From a22860a05c95f64d73f4e03677ba1634924ea1e9 Mon Sep 17 00:00:00 2001 From: Sebastien Ponce Date: Wed, 27 Sep 2023 10:47:58 +0200 Subject: [PATCH] Allowed to specify "no-cache" for file loading This is actually useful in case of automatic file reload when cycling on live events. Without it, new events are not loaded as the cache enters the game. This included extending the file-loader API to allow any options to be passed when loading a file. --- .../src/assets/files/lhcb/events.json | 2 +- .../file-explorer.component.html | 2 +- .../file-explorer.component.test.ts | 10 +++-- .../file-explorer/file-explorer.component.ts | 17 ++++++-- .../cycle-events/cycle-events.component.ts | 2 +- ...ent-data-explorer-dialog.component.test.ts | 16 ++++++-- .../event-data-explorer-dialog.component.ts | 19 ++++++--- .../lib/services/file-loader.service.ts | 40 ++++++++++++------- 8 files changed, 77 insertions(+), 31 deletions(-) diff --git a/packages/phoenix-ng/projects/phoenix-app/src/assets/files/lhcb/events.json b/packages/phoenix-ng/projects/phoenix-app/src/assets/files/lhcb/events.json index 1f9588bda..16bd9dd7d 100644 --- a/packages/phoenix-ng/projects/phoenix-app/src/assets/files/lhcb/events.json +++ b/packages/phoenix-ng/projects/phoenix-app/src/assets/files/lhcb/events.json @@ -1,5 +1,5 @@ [ - {"name":"Live events.json", "url":"https:\/\/lhcb-media.web.cern.ch\/lhcb-media\/EventDisplay\/liveEvents.json.zip"}, + {"name":"Live events.json", "url":"https:\/\/lhcb-media.web.cern.ch\/lhcb-media\/EventDisplay\/liveEvents.json.zip", "nocache":"true"}, {"name":"2023/FirstCollisions2023.json", "url":"\/assets\/files\/lhcb\/FirstCollisions2023.json.zip"}, {"name":"2023/First 2400 bunches.json", "url":"\/assets\/files\/lhcb\/EventData_Run263132.json.zip"}, {"name":"2022/Simulation_Proton-Proton.json", "url":"\/assets\/files\/lhcb\/MC_ProtonCollisions.json.zip"}, diff --git a/packages/phoenix-ng/projects/phoenix-ui-components/lib/components/file-explorer/file-explorer.component.html b/packages/phoenix-ng/projects/phoenix-ui-components/lib/components/file-explorer/file-explorer.component.html index 594da9e51..16853b8ac 100644 --- a/packages/phoenix-ng/projects/phoenix-ui-components/lib/components/file-explorer/file-explorer.component.html +++ b/packages/phoenix-ng/projects/phoenix-ui-components/lib/components/file-explorer/file-explorer.component.html @@ -5,7 +5,7 @@ mat-button mat-stroked-button class="tree-node-button" - (click)="onSelect(node.url)" + (click)="onSelect(node.url, node.nocache)" > diff --git a/packages/phoenix-ng/projects/phoenix-ui-components/lib/components/file-explorer/file-explorer.component.test.ts b/packages/phoenix-ng/projects/phoenix-ui-components/lib/components/file-explorer/file-explorer.component.test.ts index 84ca534bf..3849c62f0 100644 --- a/packages/phoenix-ng/projects/phoenix-ui-components/lib/components/file-explorer/file-explorer.component.test.ts +++ b/packages/phoenix-ng/projects/phoenix-ui-components/lib/components/file-explorer/file-explorer.component.test.ts @@ -1,7 +1,11 @@ import { CdkTreeModule } from '@angular/cdk/tree'; import { ComponentFixture, TestBed } from '@angular/core/testing'; -import { FileExplorerComponent, FileNode } from './file-explorer.component'; +import { + FileExplorerComponent, + FileNode, + FileEvent, +} from './file-explorer.component'; const getMockFileNode = () => { const rootNode = new FileNode('RootNode'); @@ -57,9 +61,9 @@ describe('FileExplorerComponent', () => { it('should emit onFileSelect event on selection of file', () => { jest.spyOn(component.onFileSelect, 'emit'); - component.onSelect('http://example.com/file.json'); + component.onSelect('http://example.com/file.json', true); expect(component.onFileSelect.emit).toHaveBeenCalledWith( - 'http://example.com/file.json' + new FileEvent('http://example.com/file.json', true) ); }); diff --git a/packages/phoenix-ng/projects/phoenix-ui-components/lib/components/file-explorer/file-explorer.component.ts b/packages/phoenix-ng/projects/phoenix-ui-components/lib/components/file-explorer/file-explorer.component.ts index 59ed1b892..945106372 100644 --- a/packages/phoenix-ng/projects/phoenix-ui-components/lib/components/file-explorer/file-explorer.component.ts +++ b/packages/phoenix-ng/projects/phoenix-ui-components/lib/components/file-explorer/file-explorer.component.ts @@ -12,10 +12,20 @@ import { MatTreeNestedDataSource } from '@angular/material/tree'; export class FileNode { name: string; url: string; + nocache: boolean; children: { [key: string]: FileNode }; constructor(name?: string) { this.name = name; + this.nocache = false; + } +} +export class FileEvent { + url: string; + nocache: boolean; + constructor(url: string, nocache: boolean) { + this.url = url; + this.nocache = nocache; } } @@ -26,7 +36,8 @@ export class FileNode { }) export class FileExplorerComponent implements OnChanges { @Input() rootFileNode: FileNode; - @Output() onFileSelect: EventEmitter = new EventEmitter(); + @Output() onFileSelect: EventEmitter = + new EventEmitter(); treeControl = new NestedTreeControl( this.getSortedChildren.bind(this) @@ -44,8 +55,8 @@ export class FileExplorerComponent implements OnChanges { hasChildren = (_: number, node: FileNode) => !!node.children && Object.keys(node.children).length > 0; - onSelect(url: string) { - this.onFileSelect.emit(url); + onSelect(url: string, nocache: boolean) { + this.onFileSelect.emit(new FileEvent(url, nocache)); } /** diff --git a/packages/phoenix-ng/projects/phoenix-ui-components/lib/components/ui-menu/cycle-events/cycle-events.component.ts b/packages/phoenix-ng/projects/phoenix-ui-components/lib/components/ui-menu/cycle-events/cycle-events.component.ts index 5fc9d76b2..09f069707 100644 --- a/packages/phoenix-ng/projects/phoenix-ui-components/lib/components/ui-menu/cycle-events/cycle-events.component.ts +++ b/packages/phoenix-ng/projects/phoenix-ui-components/lib/components/ui-menu/cycle-events/cycle-events.component.ts @@ -60,7 +60,7 @@ export class CycleEventsComponent implements OnInit { // special value -1 is used to denote wrapping of the current set of events if (index == -1) { if (this.reloading) { - // reload the current events + // reload the current events, ignoring caches this.fileLoader.reloadLastEvents(this.eventDisplay); } // put back index to 0 to start with first event anyway diff --git a/packages/phoenix-ng/projects/phoenix-ui-components/lib/components/ui-menu/event-data-explorer/event-data-explorer-dialog/event-data-explorer-dialog.component.test.ts b/packages/phoenix-ng/projects/phoenix-ui-components/lib/components/ui-menu/event-data-explorer/event-data-explorer-dialog/event-data-explorer-dialog.component.test.ts index c0e214d45..e0cce6906 100644 --- a/packages/phoenix-ng/projects/phoenix-ui-components/lib/components/ui-menu/event-data-explorer/event-data-explorer-dialog/event-data-explorer-dialog.component.test.ts +++ b/packages/phoenix-ng/projects/phoenix-ui-components/lib/components/ui-menu/event-data-explorer/event-data-explorer-dialog/event-data-explorer-dialog.component.test.ts @@ -2,7 +2,10 @@ import { ComponentFixture, TestBed } from '@angular/core/testing'; import { MatDialogRef, MAT_DIALOG_DATA } from '@angular/material/dialog'; import { BrowserAnimationsModule } from '@angular/platform-browser/animations'; import { EventDisplayService } from '../../../../services/event-display.service'; -import { FileNode } from '../../../file-explorer/file-explorer.component'; +import { + FileNode, + FileEvent, +} from '../../../file-explorer/file-explorer.component'; import { FileLoaderService } from '../../../../services/file-loader.service'; import { PhoenixUIModule } from '../../../phoenix-ui.module'; import { EventDataExplorerDialogData } from '../event-data-explorer.component'; @@ -37,14 +40,17 @@ describe.skip('EventDataExplorerDialogComponent', () => { { name: 'event_data/test.json', url: 'https://example.com/event_data/test.json', + nocache: false, }, { name: 'event_data/test.xml', url: 'https://example.com/event_data/test.xml', + nocache: true, }, { name: 'config_data/test.json', url: 'https://example.com/config_data/test.json', + nocache: false, }, ]; @@ -108,7 +114,9 @@ describe.skip('EventDataExplorerDialogComponent', () => { ); jest.spyOn(FileLoaderService.prototype, 'loadEvent'); - component.loadEvent('https://example.com/event_data/test.json'); + component.loadEvent( + new FileEvent('https://example.com/event_data/test.json', false) + ); expect(mockFileLoaderService.loadEvent).toHaveBeenCalled(); }); @@ -125,7 +133,9 @@ describe.skip('EventDataExplorerDialogComponent', () => { return true; } ); - component.loadConfig('https://example.com/config_data/test.json'); + component.loadConfig( + new FileEvent('https://example.com/config_data/test.json', false) + ); expect(mockStateManager.loadStateFromJSON).toHaveBeenCalledWith({}); }); }); diff --git a/packages/phoenix-ng/projects/phoenix-ui-components/lib/components/ui-menu/event-data-explorer/event-data-explorer-dialog/event-data-explorer-dialog.component.ts b/packages/phoenix-ng/projects/phoenix-ui-components/lib/components/ui-menu/event-data-explorer/event-data-explorer-dialog/event-data-explorer-dialog.component.ts index b34282dbf..c86f71e82 100644 --- a/packages/phoenix-ng/projects/phoenix-ui-components/lib/components/ui-menu/event-data-explorer/event-data-explorer-dialog/event-data-explorer-dialog.component.ts +++ b/packages/phoenix-ng/projects/phoenix-ui-components/lib/components/ui-menu/event-data-explorer/event-data-explorer-dialog/event-data-explorer-dialog.component.ts @@ -1,7 +1,10 @@ import { Component, Inject } from '@angular/core'; import { MatDialogRef, MAT_DIALOG_DATA } from '@angular/material/dialog'; import { EventDisplayService } from '../../../../services/event-display.service'; -import { FileNode } from '../../../file-explorer/file-explorer.component'; +import { + FileNode, + FileEvent, +} from '../../../file-explorer/file-explorer.component'; import { FileLoaderService } from '../../../../services/file-loader.service'; import { EventDataExplorerDialogData } from '../event-data-explorer.component'; @@ -10,6 +13,7 @@ const supportFileTypes = ['json', 'xml']; export type FileResponse = { name: string; url: string; + nocache: boolean; }; @Component({ @@ -56,17 +60,21 @@ export class EventDataExplorerDialogComponent { ); } - loadEvent(file: string) { + loadEvent(file: FileEvent) { this.loading = true; - this.error = this.fileLoader.loadEvent(file, this.eventDisplay); + this.error = this.fileLoader.loadEvent( + file.url, + this.eventDisplay, + file.nocache ? { cache: 'no-cache' } : {} + ); this.loading = false; if (!this.error) this.onClose(); } - loadConfig(file: string) { + loadConfig(file: FileEvent) { this.loading = true; this.error = this.fileLoader.makeRequest( - `${this.dialogData.apiURL}?type=config&f=${file}`, + `${this.dialogData.apiURL}?type=config&f=${file.url}`, 'text', (config) => { const stateManager = this.eventDisplay.getStateManager(); @@ -94,6 +102,7 @@ export class EventDataExplorerDialogComponent { }); fileNode.url = filePath.url; + fileNode.nocache = filePath.nocache; fileNode = rootNode; } diff --git a/packages/phoenix-ng/projects/phoenix-ui-components/lib/services/file-loader.service.ts b/packages/phoenix-ng/projects/phoenix-ui-components/lib/services/file-loader.service.ts index 64913fcf5..1a937e18f 100644 --- a/packages/phoenix-ng/projects/phoenix-ui-components/lib/services/file-loader.service.ts +++ b/packages/phoenix-ng/projects/phoenix-ui-components/lib/services/file-loader.service.ts @@ -11,6 +11,7 @@ import { JiveXMLLoader } from 'phoenix-event-display'; }) export class FileLoaderService { private lastEventsURL: string = ''; + private lastEventsOptions: boolean = false; async unzip(data: ArrayBuffer) { const archive = new JSZip(); @@ -34,9 +35,10 @@ export class FileLoaderService { makeRequest( urlPath: string, responseType: 'json' | 'text' | 'blob', - onData: (data: any) => void + onData: (data: any) => void, + options: any = {} ) { - fetch(urlPath) + fetch(urlPath, options) .then((res) => res[responseType]()) .then((data) => { if (responseType === 'blob') { @@ -66,25 +68,35 @@ export class FileLoaderService { eventDisplay.buildEventDataFromJSON(processedEventData); } - loadEvent(file: string, eventDisplay: EventDisplayService) { + loadEvent( + file: string, + eventDisplay: EventDisplayService, + options: any = {} + ) { this.lastEventsURL = file; + this.lastEventsOptions = options; const isZip = file.split('.').pop() === 'zip'; const rawfile = isZip ? file.substring(0, file.length - 4) : file; - return this.makeRequest(file, isZip ? 'blob' : 'text', (eventData) => { - switch (rawfile.split('.').pop()) { - case 'xml': - this.loadJiveXMLEvent(eventData, eventDisplay); - break; - case 'json': - this.loadJSONEvent(eventData, eventDisplay); - break; - } - }); + return this.makeRequest( + file, + isZip ? 'blob' : 'text', + (eventData) => { + switch (rawfile.split('.').pop()) { + case 'xml': + this.loadJiveXMLEvent(eventData, eventDisplay); + break; + case 'json': + this.loadJSONEvent(eventData, eventDisplay); + break; + } + }, + options + ); } reloadLastEvents(eventDisplay: EventDisplayService) { if (this.lastEventsURL.length > 0) { - this.loadEvent(this.lastEventsURL, eventDisplay); + this.loadEvent(this.lastEventsURL, eventDisplay, this.lastEventsOptions); } } }