From d513387b2efda8a67fad45242597b843556410b6 Mon Sep 17 00:00:00 2001 From: xsalonx Date: Mon, 4 Aug 2025 12:48:10 +0200 Subject: [PATCH 01/19] A --- .../views/Runs/Overview/RunsWithQcModel.js | 16 ++++++++++++++++ .../RunsPerDataPassOverviewModel.js | 10 ++-------- .../RunsPerSimulationPassOverviewPage.js | 4 ++++ 3 files changed, 22 insertions(+), 8 deletions(-) diff --git a/lib/public/views/Runs/Overview/RunsWithQcModel.js b/lib/public/views/Runs/Overview/RunsWithQcModel.js index 4dff88c1f1..f1933bf6e9 100644 --- a/lib/public/views/Runs/Overview/RunsWithQcModel.js +++ b/lib/public/views/Runs/Overview/RunsWithQcModel.js @@ -11,6 +11,7 @@ * or submit itself to any jurisdiction. */ +import { NumericalComparisonFilterModel } from '../../../components/Filters/common/filters/NumericalComparisonFilterModel.js'; import { RunsOverviewModel } from './RunsOverviewModel.js'; /** @@ -32,4 +33,19 @@ export class RunsWithQcModel extends RunsOverviewModel { freezeFirstColumn: true, }); } + + /** + * Register not-bad fraction detectors filtering model + * @param {ObservableData>} detectors$ detectors remote data observable + */ + registerDetectorsNotBadFractionFilterModels(detectors$) { + detectors$.observe((observableData) => observableData.getCurrent().apply({ + Success: (detectors) => detectors.forEach(({ id }) => { + this._filteringModel.put(`detectorsQc[_${id}][notBadFraction]`, new NumericalComparisonFilterModel({ + scale: 0.01, + integer: false, + })); + }), + })); + } } diff --git a/lib/public/views/Runs/RunPerDataPass/RunsPerDataPassOverviewModel.js b/lib/public/views/Runs/RunPerDataPass/RunsPerDataPassOverviewModel.js index fdc2ee2f31..6a9e944dda 100644 --- a/lib/public/views/Runs/RunPerDataPass/RunsPerDataPassOverviewModel.js +++ b/lib/public/views/Runs/RunPerDataPass/RunsPerDataPassOverviewModel.js @@ -35,14 +35,8 @@ export class RunsPerDataPassOverviewModel extends FixedPdpBeamTypeRunsOverviewMo super(model); this._detectors$ = detectorsProvider.qc$; this._detectors$.bubbleTo(this); - this._detectors$.observe((observableData) => observableData.getCurrent().apply({ - Success: (detectors) => detectors.forEach(({ id }) => { - this._filteringModel.put(`detectorsQc[_${id}][notBadFraction]`, new NumericalComparisonFilterModel({ - scale: 0.01, - integer: false, - })); - }), - })); + this.registerDetectorsNotBadFractionFilterModels(this._detectors$); + this._dataPass = new ObservableData(RemoteData.notAsked()); this._dataPass.bubbleTo(this); this._qcSummary$ = new ObservableData(RemoteData.notAsked()); diff --git a/lib/public/views/Runs/RunsPerSimulationPass/RunsPerSimulationPassOverviewPage.js b/lib/public/views/Runs/RunsPerSimulationPass/RunsPerSimulationPassOverviewPage.js index 1cf1287076..5bc0983c43 100644 --- a/lib/public/views/Runs/RunsPerSimulationPass/RunsPerSimulationPassOverviewPage.js +++ b/lib/public/views/Runs/RunsPerSimulationPass/RunsPerSimulationPassOverviewPage.js @@ -28,6 +28,8 @@ import { PdpBeamType } from '../../../domain/enums/PdpBeamType.js'; import { frontLink } from '../../../components/common/navigation/frontLink.js'; import { mergeRemoteData } from '../../../utilities/mergeRemoteData.js'; import errorAlert from '../../../components/common/errorAlert.js'; +import { filtersPanelPopover } from '../../../components/Filters/common/filtersPanelPopover.js'; +import { runNumbersFilter } from '../../../components/Filters/RunsFilter/runNumbersFilter.js'; const TABLEROW_HEIGHT = 59; // Estimate of the navbar and pagination elements height total; Needs to be updated in case of changes; @@ -90,6 +92,8 @@ export const RunsPerSimulationPassOverviewPage = ({ return [ h('.flex-row.justify-between.items-center.g2', [ + filtersPanelPopover(perSimulationPassOverviewModel.filteringModel, activeColumns, { profile: 'runsPerSimulationPass' }), + h('.pl2#runOverviewFilter', runNumbersFilter(perSimulationPassOverviewModel.filteringModel.get('runNumbers'))), h( '.flex-row.g1.items-center', breadcrumbs([commonTitle, h('h2#breadcrumb-simulation-pass-name', simulationPass.name)]), From 7fe72193d822ac7910457dde7aeaad0e0aa5b322 Mon Sep 17 00:00:00 2001 From: xsalonx Date: Tue, 5 Aug 2025 14:27:57 +0200 Subject: [PATCH 02/19] refactor --- .../views/Runs/Overview/RunsWithQcModel.js | 43 +++++++++++++++++++ .../RunsPerDataPassOverviewModel.js | 37 ---------------- .../RunsPerSimulationPassOverviewModel.js | 17 +------- .../RunsPerSimulationPassOverviewPage.js | 2 +- 4 files changed, 46 insertions(+), 53 deletions(-) diff --git a/lib/public/views/Runs/Overview/RunsWithQcModel.js b/lib/public/views/Runs/Overview/RunsWithQcModel.js index f1933bf6e9..2814c4b81a 100644 --- a/lib/public/views/Runs/Overview/RunsWithQcModel.js +++ b/lib/public/views/Runs/Overview/RunsWithQcModel.js @@ -12,6 +12,7 @@ */ import { NumericalComparisonFilterModel } from '../../../components/Filters/common/filters/NumericalComparisonFilterModel.js'; +import { RunDetectorsSelectionModel } from '../RunDetectorsSelectionModel.js'; import { RunsOverviewModel } from './RunsOverviewModel.js'; /** @@ -27,6 +28,11 @@ export class RunsWithQcModel extends RunsOverviewModel { constructor(model) { super(model); + this._mcReproducibleAsNotBad = false; + + this._runDetectorsSelectionModel = new RunDetectorsSelectionModel(); + this._runDetectorsSelectionModel.bubbleTo(this); + this.patchDisplayOptions({ horizontalScrollEnabled: true, verticalScrollEnabled: true, @@ -34,6 +40,43 @@ export class RunsWithQcModel extends RunsOverviewModel { }); } + /** + * Set mcReproducibleAsNotBad + * + * @param {boolean} mcReproducibleAsNotBad new value + * @return {void} + */ + setMcReproducibleAsNotBad(mcReproducibleAsNotBad) { + this._mcReproducibleAsNotBad = mcReproducibleAsNotBad; + this.load(); + } + + /** + * Get mcReproducibleAsNotBad + * + * @return {boolean} mcReproducibleAsNotBad + */ + get mcReproducibleAsNotBad() { + return this._mcReproducibleAsNotBad; + } + + /** + * Returns the run detectors selection model + * + * @return {RunDetectorsSelectionModel} selection model + */ + get runDetectorsSelectionModel() { + return this._runDetectorsSelectionModel; + } + + /** + * @inheritdoc + */ + async load() { + this._runDetectorsSelectionModel.reset(); + super.load(); + } + /** * Register not-bad fraction detectors filtering model * @param {ObservableData>} detectors$ detectors remote data observable diff --git a/lib/public/views/Runs/RunPerDataPass/RunsPerDataPassOverviewModel.js b/lib/public/views/Runs/RunPerDataPass/RunsPerDataPassOverviewModel.js index 6a9e944dda..e187f0d006 100644 --- a/lib/public/views/Runs/RunPerDataPass/RunsPerDataPassOverviewModel.js +++ b/lib/public/views/Runs/RunPerDataPass/RunsPerDataPassOverviewModel.js @@ -20,7 +20,6 @@ import { jsonPatch } from '../../../utilities/fetch/jsonPatch.js'; import { jsonPut } from '../../../utilities/fetch/jsonPut.js'; import { SkimmingStage } from '../../../domain/enums/SkimmingStage.js'; import { NumericalComparisonFilterModel } from '../../../components/Filters/common/filters/NumericalComparisonFilterModel.js'; -import { RunDetectorsSelectionModel } from '../RunDetectorsSelectionModel.js'; import { jsonFetch } from '../../../utilities/fetch/jsonFetch.js'; /** @@ -44,8 +43,6 @@ export class RunsPerDataPassOverviewModel extends FixedPdpBeamTypeRunsOverviewMo this._gaqSummary$ = new ObservableData(RemoteData.notAsked()); this._gaqSummary$.bubbleTo(this); - this._mcReproducibleAsNotBad = false; - this._markAsSkimmableRequestResult$ = new ObservableData(RemoteData.notAsked()); this._markAsSkimmableRequestResult$.bubbleTo(this); @@ -57,9 +54,6 @@ export class RunsPerDataPassOverviewModel extends FixedPdpBeamTypeRunsOverviewMo integer: false, })); - this._runDetectorsSelectionModel = new RunDetectorsSelectionModel(); - this._runDetectorsSelectionModel.bubbleTo(this); - this._freezeOrUnfreezeActionState$ = new ObservableData(RemoteData.notAsked()); this._freezeOrUnfreezeActionState$.bubbleTo(this); @@ -110,8 +104,6 @@ export class RunsPerDataPassOverviewModel extends FixedPdpBeamTypeRunsOverviewMo return; } - this._runDetectorsSelectionModel.reset(); - this._fetchQcSummary(); this._fetchGaqSummary(); await this._fetchDataPass(); @@ -308,35 +300,6 @@ export class RunsPerDataPassOverviewModel extends FixedPdpBeamTypeRunsOverviewMo return this._dataPassId; } - /** - * Set mcReproducibleAsNotBad - * - * @param {boolean} mcReproducibleAsNotBad new value - * @return {void} - */ - setMcReproducibleAsNotBad(mcReproducibleAsNotBad) { - this._mcReproducibleAsNotBad = mcReproducibleAsNotBad; - this.load(); - } - - /** - * Get mcReproducibleAsNotBad - * - * @return {boolean} mcReproducibleAsNotBad - */ - get mcReproducibleAsNotBad() { - return this._mcReproducibleAsNotBad; - } - - /** - * Returns the run detectors selection model - * - * @return {RunDetectorsSelectionModel} selection model - */ - get runDetectorsSelectionModel() { - return this._runDetectorsSelectionModel; - } - /** * Fetch data pass data which runs are fetched * @return {Promise} promise diff --git a/lib/public/views/Runs/RunsPerSimulationPass/RunsPerSimulationPassOverviewModel.js b/lib/public/views/Runs/RunsPerSimulationPass/RunsPerSimulationPassOverviewModel.js index 38ab7edad1..84926159ef 100644 --- a/lib/public/views/Runs/RunsPerSimulationPass/RunsPerSimulationPassOverviewModel.js +++ b/lib/public/views/Runs/RunsPerSimulationPass/RunsPerSimulationPassOverviewModel.js @@ -15,7 +15,6 @@ import { RunsWithQcModel } from '../Overview/RunsWithQcModel.js'; import { ObservableData } from '../../../utilities/ObservableData.js'; import { getRemoteData } from '../../../utilities/fetch/getRemoteData.js'; import { detectorsProvider } from '../../../services/detectors/detectorsProvider.js'; -import { RunDetectorsSelectionModel } from '../RunDetectorsSelectionModel.js'; /** * Runs Per Simulation Pass overview model @@ -29,13 +28,12 @@ export class RunsPerSimulationPassOverviewModel extends RunsWithQcModel { super(model); this._detectors$ = detectorsProvider.qc$; this._detectors$.bubbleTo(this); + this.registerDetectorsNotBadFractionFilterModels(this._detectors$); + this._simulationPass$ = new ObservableData(RemoteData.notAsked()); this._simulationPass$.bubbleTo(this); this._qcSummary$ = new ObservableData(RemoteData.NotAsked()); this._qcSummary$.bubbleTo(this); - - this._runDetectorsSelectionModel = new RunDetectorsSelectionModel(); - this._runDetectorsSelectionModel.bubbleTo(this); } /** @@ -70,8 +68,6 @@ export class RunsPerSimulationPassOverviewModel extends RunsWithQcModel { * @inheritdoc */ async load() { - this._runDetectorsSelectionModel.reset(); - this._fetchQcSummary(); this._fetchSimulationPass(); super.load(); @@ -129,13 +125,4 @@ export class RunsPerSimulationPassOverviewModel extends RunsWithQcModel { get qcSummary() { return this._qcSummary$.getCurrent(); } - - /** - * Returns the run detectors selection model - * - * @return {RunDetectorsSelectionModel} selection model - */ - get runDetectorsSelectionModel() { - return this._runDetectorsSelectionModel; - } } diff --git a/lib/public/views/Runs/RunsPerSimulationPass/RunsPerSimulationPassOverviewPage.js b/lib/public/views/Runs/RunsPerSimulationPass/RunsPerSimulationPassOverviewPage.js index 5bc0983c43..37e11db467 100644 --- a/lib/public/views/Runs/RunsPerSimulationPass/RunsPerSimulationPassOverviewPage.js +++ b/lib/public/views/Runs/RunsPerSimulationPass/RunsPerSimulationPassOverviewPage.js @@ -92,7 +92,7 @@ export const RunsPerSimulationPassOverviewPage = ({ return [ h('.flex-row.justify-between.items-center.g2', [ - filtersPanelPopover(perSimulationPassOverviewModel.filteringModel, activeColumns, { profile: 'runsPerSimulationPass' }), + filtersPanelPopover(perSimulationPassOverviewModel, activeColumns, { profile: 'runsPerSimulationPass' }), h('.pl2#runOverviewFilter', runNumbersFilter(perSimulationPassOverviewModel.filteringModel.get('runNumbers'))), h( '.flex-row.g1.items-center', From 9a594b15014e6147a182c2ff8fbc22040bc25a51 Mon Sep 17 00:00:00 2001 From: xsalonx Date: Tue, 5 Aug 2025 14:30:23 +0200 Subject: [PATCH 03/19] cleanup --- .../views/Runs/Overview/FixedPdpBeamTypeRunsOverviewModel.js | 1 + .../views/Runs/RunPerDataPass/RunsPerDataPassOverviewModel.js | 2 ++ .../RunsPerSimulationPass/RunsPerSimulationPassOverviewModel.js | 2 ++ 3 files changed, 5 insertions(+) diff --git a/lib/public/views/Runs/Overview/FixedPdpBeamTypeRunsOverviewModel.js b/lib/public/views/Runs/Overview/FixedPdpBeamTypeRunsOverviewModel.js index 5fe3215406..590f456d00 100644 --- a/lib/public/views/Runs/Overview/FixedPdpBeamTypeRunsOverviewModel.js +++ b/lib/public/views/Runs/Overview/FixedPdpBeamTypeRunsOverviewModel.js @@ -26,6 +26,7 @@ export class FixedPdpBeamTypeRunsOverviewModel extends RunsWithQcModel { */ constructor(model) { super(model); + this._pdpBeamType = null; } diff --git a/lib/public/views/Runs/RunPerDataPass/RunsPerDataPassOverviewModel.js b/lib/public/views/Runs/RunPerDataPass/RunsPerDataPassOverviewModel.js index e187f0d006..7bf90b185d 100644 --- a/lib/public/views/Runs/RunPerDataPass/RunsPerDataPassOverviewModel.js +++ b/lib/public/views/Runs/RunPerDataPass/RunsPerDataPassOverviewModel.js @@ -38,8 +38,10 @@ export class RunsPerDataPassOverviewModel extends FixedPdpBeamTypeRunsOverviewMo this._dataPass = new ObservableData(RemoteData.notAsked()); this._dataPass.bubbleTo(this); + this._qcSummary$ = new ObservableData(RemoteData.notAsked()); this._qcSummary$.bubbleTo(this); + this._gaqSummary$ = new ObservableData(RemoteData.notAsked()); this._gaqSummary$.bubbleTo(this); diff --git a/lib/public/views/Runs/RunsPerSimulationPass/RunsPerSimulationPassOverviewModel.js b/lib/public/views/Runs/RunsPerSimulationPass/RunsPerSimulationPassOverviewModel.js index 84926159ef..3fc5bdc10d 100644 --- a/lib/public/views/Runs/RunsPerSimulationPass/RunsPerSimulationPassOverviewModel.js +++ b/lib/public/views/Runs/RunsPerSimulationPass/RunsPerSimulationPassOverviewModel.js @@ -26,12 +26,14 @@ export class RunsPerSimulationPassOverviewModel extends RunsWithQcModel { */ constructor(model) { super(model); + this._detectors$ = detectorsProvider.qc$; this._detectors$.bubbleTo(this); this.registerDetectorsNotBadFractionFilterModels(this._detectors$); this._simulationPass$ = new ObservableData(RemoteData.notAsked()); this._simulationPass$.bubbleTo(this); + this._qcSummary$ = new ObservableData(RemoteData.NotAsked()); this._qcSummary$.bubbleTo(this); } From dd78bec003dcab8f0c9d1b5cea61d61a290bf6db Mon Sep 17 00:00:00 2001 From: xsalonx Date: Tue, 5 Aug 2025 14:41:49 +0200 Subject: [PATCH 04/19] WIP --- .../views/Runs/Overview/RunsWithQcModel.js | 13 +++++++++ .../RunsPerDataPassOverviewModel.js | 3 -- .../RunsPerDataPassOverviewPage.js | 14 +--------- .../RunsPerSimulationPassOverviewModel.js | 5 +++- .../RunsPerSimulationPassOverviewPage.js | 6 ++++ .../Runs/mcReproducibleAsNotBadToggle.js | 28 +++++++++++++++++++ 6 files changed, 52 insertions(+), 17 deletions(-) create mode 100644 lib/public/views/Runs/mcReproducibleAsNotBadToggle.js diff --git a/lib/public/views/Runs/Overview/RunsWithQcModel.js b/lib/public/views/Runs/Overview/RunsWithQcModel.js index 2814c4b81a..9ac799563b 100644 --- a/lib/public/views/Runs/Overview/RunsWithQcModel.js +++ b/lib/public/views/Runs/Overview/RunsWithQcModel.js @@ -11,6 +11,7 @@ * or submit itself to any jurisdiction. */ +import { buildUrl } from '/js/src/index.js'; import { NumericalComparisonFilterModel } from '../../../components/Filters/common/filters/NumericalComparisonFilterModel.js'; import { RunDetectorsSelectionModel } from '../RunDetectorsSelectionModel.js'; import { RunsOverviewModel } from './RunsOverviewModel.js'; @@ -40,6 +41,18 @@ export class RunsWithQcModel extends RunsOverviewModel { }); } + /** + * @inheritdoc + */ + getRootEndpoint() { + const filter = {}; + filter.detectorsQc = { + mcReproducibleAsNotBad: this._mcReproducibleAsNotBad, + }; + + return buildUrl(super.getRootEndpoint(), { filter }); + } + /** * Set mcReproducibleAsNotBad * diff --git a/lib/public/views/Runs/RunPerDataPass/RunsPerDataPassOverviewModel.js b/lib/public/views/Runs/RunPerDataPass/RunsPerDataPassOverviewModel.js index 7bf90b185d..5c061ac857 100644 --- a/lib/public/views/Runs/RunPerDataPass/RunsPerDataPassOverviewModel.js +++ b/lib/public/views/Runs/RunPerDataPass/RunsPerDataPassOverviewModel.js @@ -127,9 +127,6 @@ export class RunsPerDataPassOverviewModel extends FixedPdpBeamTypeRunsOverviewMo mcReproducibleAsNotBad: this._mcReproducibleAsNotBad, }; } - filter.detectorsQc = { - mcReproducibleAsNotBad: this._mcReproducibleAsNotBad, - }; return buildUrl(super.getRootEndpoint(), { filter }); } diff --git a/lib/public/views/Runs/RunPerDataPass/RunsPerDataPassOverviewPage.js b/lib/public/views/Runs/RunPerDataPass/RunsPerDataPassOverviewPage.js index 15f58fd57e..7aaead3fba 100644 --- a/lib/public/views/Runs/RunPerDataPass/RunsPerDataPassOverviewPage.js +++ b/lib/public/views/Runs/RunPerDataPass/RunsPerDataPassOverviewPage.js @@ -39,6 +39,7 @@ import { mergeRemoteData } from '../../../utilities/mergeRemoteData.js'; import { numericalComparisonFilter } from '../../../components/Filters/common/filters/numericalComparisonFilter.js'; import { iconCaretBottom } from '/js/src/icons.js'; import { BkpRoles } from '../../../domain/enums/BkpRoles.js'; +import { mcReproducibleAsNotBadToggle } from '../mcReproducibleAsNotBadToggle.js'; const TABLEROW_HEIGHT = 59; // Estimate of the navbar and pagination elements height total; Needs to be updated in case of changes; @@ -52,19 +53,6 @@ const PAGE_USED_HEIGHT = 215; */ const getRowClasses = (run) => isRunNotSubjectToQc(run) ? '.danger' : null; -/** - * Display a toggle switch to change interpretation of MC.Reproducible flag type from bad to not-bad - * - * @param {boolean} value current value - * @param {function} onChange to be called when switching - * @returns {Component} the toggle switch - */ -const mcReproducibleAsNotBadToggle = (value, onChange) => h('#mcReproducibleAsNotBadToggle', switchInput( - value, - onChange, - { labelAfter: h('em', 'MC.R as not-bad') }, -)); - /** * Render (if applies to type of current data pass) button to mark current data pass as skimmable, * if it's skimmable already, badge with this information is rendered instead diff --git a/lib/public/views/Runs/RunsPerSimulationPass/RunsPerSimulationPassOverviewModel.js b/lib/public/views/Runs/RunsPerSimulationPass/RunsPerSimulationPassOverviewModel.js index 3fc5bdc10d..1ac4463884 100644 --- a/lib/public/views/Runs/RunsPerSimulationPass/RunsPerSimulationPassOverviewModel.js +++ b/lib/public/views/Runs/RunsPerSimulationPass/RunsPerSimulationPassOverviewModel.js @@ -59,7 +59,10 @@ export class RunsPerSimulationPassOverviewModel extends RunsWithQcModel { async _fetchQcSummary() { this._qcSummary$.setCurrent(RemoteData.loading()); try { - const { data: qcSummary } = await getRemoteData(buildUrl('/api/qcFlags/summary', { simulationPassId: this._simulationPassId })); + const { data: qcSummary } = await getRemoteData(buildUrl('/api/qcFlags/summary', { + simulationPassId: this._simulationPassId, + mcReproducibleAsNotBad: this._mcReproducibleAsNotBad, + })); this._qcSummary$.setCurrent(RemoteData.success(qcSummary)); } catch (error) { this._qcSummary$.setCurrent(RemoteData.failure(error)); diff --git a/lib/public/views/Runs/RunsPerSimulationPass/RunsPerSimulationPassOverviewPage.js b/lib/public/views/Runs/RunsPerSimulationPass/RunsPerSimulationPassOverviewPage.js index 37e11db467..be05790f24 100644 --- a/lib/public/views/Runs/RunsPerSimulationPass/RunsPerSimulationPassOverviewPage.js +++ b/lib/public/views/Runs/RunsPerSimulationPass/RunsPerSimulationPassOverviewPage.js @@ -30,6 +30,7 @@ import { mergeRemoteData } from '../../../utilities/mergeRemoteData.js'; import errorAlert from '../../../components/common/errorAlert.js'; import { filtersPanelPopover } from '../../../components/Filters/common/filtersPanelPopover.js'; import { runNumbersFilter } from '../../../components/Filters/RunsFilter/runNumbersFilter.js'; +import { mcReproducibleAsNotBadToggle } from '../mcReproducibleAsNotBadToggle.js'; const TABLEROW_HEIGHT = 59; // Estimate of the navbar and pagination elements height total; Needs to be updated in case of changes; @@ -66,6 +67,7 @@ export const RunsPerSimulationPassOverviewPage = ({ qcSummary: remoteQcSummary, displayOptions, sortModel, + mcReproducibleAsNotBad, } = perSimulationPassOverviewModel; const commonTitle = h('h2', 'Runs per MC'); @@ -98,6 +100,10 @@ export const RunsPerSimulationPassOverviewPage = ({ '.flex-row.g1.items-center', breadcrumbs([commonTitle, h('h2#breadcrumb-simulation-pass-name', simulationPass.name)]), ), + mcReproducibleAsNotBadToggle( + mcReproducibleAsNotBad, + () => perSimulationPassOverviewModel.setMcReproducibleAsNotBad(!mcReproducibleAsNotBad), + ), h('.mlauto', qcSummaryLegendTooltip()), exportRunsTriggerAndModal(perSimulationPassOverviewModel, modalModel, { autoMarginLeft: false }), frontLink( diff --git a/lib/public/views/Runs/mcReproducibleAsNotBadToggle.js b/lib/public/views/Runs/mcReproducibleAsNotBadToggle.js new file mode 100644 index 0000000000..636ed0f245 --- /dev/null +++ b/lib/public/views/Runs/mcReproducibleAsNotBadToggle.js @@ -0,0 +1,28 @@ +/** + * @license + * Copyright CERN and copyright holders of ALICE O2. This software is + * distributed under the terms of the GNU General Public License v3 (GPL + * Version 3), copied verbatim in the file "COPYING". + * + * See http://alice-o2.web.cern.ch/license for full licensing information. + * + * In applying this license CERN does not waive the privileges and immunities + * granted to it by virtue of its status as an Intergovernmental Organization + * or submit itself to any jurisdiction. + */ + +import { switchInput } from '../../components/common/form/switchInput.js'; +import { h } from '/js/src/index.js'; + +/** + * Display a toggle switch to change interpretation of MC.Reproducible flag type from bad to not-bad + * + * @param {boolean} value current value + * @param {function} onChange to be called when switching + * @returns {Component} the toggle switch + */ +export const mcReproducibleAsNotBadToggle = (value, onChange) => h('#mcReproducibleAsNotBadToggle', switchInput( + value, + onChange, + { labelAfter: h('em', 'MC.R as not-bad') }, +)); From 867bf0b4997200941711a756c8da1c4ef4876612 Mon Sep 17 00:00:00 2001 From: xsalonx Date: Tue, 5 Aug 2025 14:59:47 +0200 Subject: [PATCH 05/19] add test --- .../runs/runsPerSimulationPass.overview.test.js | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/test/public/runs/runsPerSimulationPass.overview.test.js b/test/public/runs/runsPerSimulationPass.overview.test.js index adb30973f3..514a7aa9c3 100644 --- a/test/public/runs/runsPerSimulationPass.overview.test.js +++ b/test/public/runs/runsPerSimulationPass.overview.test.js @@ -190,6 +190,20 @@ module.exports = () => { await waitForNavigation(page, () => page.goBack()); }); + + it('should successfully apply detectors notBadFraction filters', async () => { + await pressElement(page, '#openFilterToggle', true); + + await page.waitForSelector('#detectorsQc-for-1-notBadFraction-operator'); + await page.select('#detectorsQc-for-1-notBadFraction-operator', '<='); + await fillInput(page, '#detectorsQc-for-1-notBadFraction-operand', '90', ['change']); + await expectColumnValues(page, 'runNumber', ['106']); + + await pressElement(page, '#openFilterToggle', true); + await pressElement(page, '#reset-filters', true); + await expectColumnValues(page, 'runNumber', ['107', '106', '105']); + }); + it('should successfully export runs', async () => { const EXPORT_RUNS_TRIGGER_SELECTOR = '#export-runs-trigger'; From 9446537dedaefd265dc1241d0ef7a923e2e2f2ca Mon Sep 17 00:00:00 2001 From: xsalonx Date: Tue, 5 Aug 2025 15:08:52 +0200 Subject: [PATCH 06/19] add naviagtion util --- package.json | 2 +- ...aPassesUtilities.js => navigationUtils.js} | 20 +++++++++++++++++++ .../runs/runsPerDataPass.overview.test.js | 2 +- .../runsPerSimulationPass.overview.test.js | 4 ++++ 4 files changed, 26 insertions(+), 2 deletions(-) rename test/public/runs/{dataPassesUtilities.js => navigationUtils.js} (51%) diff --git a/package.json b/package.json index 24c63bfa1e..ef35a82d9c 100644 --- a/package.json +++ b/package.json @@ -10,7 +10,7 @@ "sequelize": "sequelize-cli", "start:dev": "nodemon --ignore 'lib/public/**/*.js' lib/main.js", "start:prod": "node lib/main.js", - "test": "mocha --exit --timeout 0", + "test": "mocha --exit --timeout 0 --grep 'Runs Per Simulation Pass Overview Page'", "test:subset": "nyc -- mocha --exit --timeout 0 test/scripts/test-${TEST_TYPE}.js && nyc report --report-dir=/usr/src/app/coverage/${TEST_TYPE} --reporter=json", "test:subset-local": "mocha --exit --timeout 0 --reporter test/scripts/parallel-local/custom-mocha-reporter.js test/scripts/test-${TEST_TYPE}.js", "docker-run": "docker compose -f docker-compose.yml -f docker-compose.dev.yml up --build", diff --git a/test/public/runs/dataPassesUtilities.js b/test/public/runs/navigationUtils.js similarity index 51% rename from test/public/runs/dataPassesUtilities.js rename to test/public/runs/navigationUtils.js index 2b97b2f0d4..d68c3ba25e 100644 --- a/test/public/runs/dataPassesUtilities.js +++ b/test/public/runs/navigationUtils.js @@ -19,3 +19,23 @@ exports.navigateToRunsPerDataPass = async (page, lhcPeriodId, dataPassId, expect expectUrlParams(page, { page: 'runs-per-data-pass', dataPassId, pdpBeamType }); await waitForTableLength(page, expectedRowsCount); }; + +/** + * Navigate to Runs per Simulation Pass page + * + * @param {Puppeteer.Page} page page + * @param {number} lhcPeriodId id of lhc period on LHC Period overview page + * @param {number} simulationPassId id of data pass on Data Passes per LHC Period page + * @param {number} expectedRowsCount expected number of rows on runs per data pass page + * @return {Promise} promise + */ +exports.navigateToRunsPerSimulationPass = async (page, lhcPeriodId, simulationPassId, expectedRowsCount) => { + await waitForNavigation(page, () => pressElement(page, 'a#lhc-period-overview', true)); + const pdpBeamType = await getInnerText(await page.waitForSelector(`#row${lhcPeriodId}-beamTypes`)); + await waitForNavigation(page, () => pressElement(page, `#row${lhcPeriodId}-associatedDataPasses a`, true)); + expectUrlParams(page, { page: 'simulation-passes-per-lhc-period-overview', lhcPeriodId }); + await page.waitForSelector('th#description'); + await waitForNavigation(page, () => pressElement(page, `#row${simulationPassId}-associatedRuns a`, true)); + expectUrlParams(page, { page: 'runs-per-simulation-pass', dataPassId: simulationPassId, pdpBeamType }); + await waitForTableLength(page, expectedRowsCount); +}; diff --git a/test/public/runs/runsPerDataPass.overview.test.js b/test/public/runs/runsPerDataPass.overview.test.js index 1656ee6a20..fabec158d9 100644 --- a/test/public/runs/runsPerDataPass.overview.test.js +++ b/test/public/runs/runsPerDataPass.overview.test.js @@ -39,7 +39,7 @@ const { const { resetDatabaseContent } = require('../../utilities/resetDatabaseContent.js'); const DataPassRepository = require('../../../lib/database/repositories/DataPassRepository.js'); const { BkpRoles } = require('../../../lib/domain/enums/BkpRoles.js'); -const { navigateToRunsPerDataPass } = require('./dataPassesUtilities.js'); +const { navigateToRunsPerDataPass } = require('./navigationUtils.js'); const { expect } = chai; diff --git a/test/public/runs/runsPerSimulationPass.overview.test.js b/test/public/runs/runsPerSimulationPass.overview.test.js index 514a7aa9c3..de2e2e2316 100644 --- a/test/public/runs/runsPerSimulationPass.overview.test.js +++ b/test/public/runs/runsPerSimulationPass.overview.test.js @@ -30,11 +30,13 @@ const { expectUrlParams, testTableSortingByColumn, waitForTableLength, + expectColumnValues, } = require('../defaults.js'); const { expect } = chai; const { qcFlagService } = require('../../../lib/server/services/qualityControlFlag/QcFlagService'); const { resetDatabaseContent } = require('../../utilities/resetDatabaseContent.js'); +const { navigateToRunsPerSimulationPass } = require('./navigationUtils.js'); const DETECTORS = [ 'CPV', @@ -192,6 +194,7 @@ module.exports = () => { it('should successfully apply detectors notBadFraction filters', async () => { + await navigateToRunsPerSimulationPass(page, 2, 1, 3); await pressElement(page, '#openFilterToggle', true); await page.waitForSelector('#detectorsQc-for-1-notBadFraction-operator'); @@ -202,6 +205,7 @@ module.exports = () => { await pressElement(page, '#openFilterToggle', true); await pressElement(page, '#reset-filters', true); await expectColumnValues(page, 'runNumber', ['107', '106', '105']); + await navigateToRunsPerSimulationPass(page, 1, 2, 3); }); it('should successfully export runs', async () => { From 0e19fe62386fb2493dacea584f9f59f2732de995 Mon Sep 17 00:00:00 2001 From: xsalonx Date: Tue, 5 Aug 2025 15:16:17 +0200 Subject: [PATCH 07/19] fix navigatin --- .../simulationPassesActiveColumns.js | 4 ++++ test/public/qcFlags/detailsForDataPass.test.js | 2 +- test/public/runs/navigationUtils.js | 15 ++++++++++++++- 3 files changed, 19 insertions(+), 2 deletions(-) diff --git a/lib/public/views/SimulationPasses/ActiveColumns/simulationPassesActiveColumns.js b/lib/public/views/SimulationPasses/ActiveColumns/simulationPassesActiveColumns.js index 32fcee388a..05b796bcf8 100644 --- a/lib/public/views/SimulationPasses/ActiveColumns/simulationPassesActiveColumns.js +++ b/lib/public/views/SimulationPasses/ActiveColumns/simulationPassesActiveColumns.js @@ -23,6 +23,10 @@ import { badge } from '../../../components/common/badge.js'; * List of active columns for a generic simulation passes table */ export const simulationPassesActiveColumns = { + id: { + visible: false, + }, + name: { name: 'Name', visible: true, diff --git a/test/public/qcFlags/detailsForDataPass.test.js b/test/public/qcFlags/detailsForDataPass.test.js index 15d72d9dc4..d1536b9fbc 100644 --- a/test/public/qcFlags/detailsForDataPass.test.js +++ b/test/public/qcFlags/detailsForDataPass.test.js @@ -27,7 +27,7 @@ const { waitForTableLength, } = require('../defaults.js'); const { resetDatabaseContent } = require('../../utilities/resetDatabaseContent.js'); -const { navigateToRunsPerDataPass } = require('../runs/dataPassesUtilities.js'); +const { navigateToRunsPerDataPass } = require('../runs/navigationUtils.js'); const { expect } = chai; diff --git a/test/public/runs/navigationUtils.js b/test/public/runs/navigationUtils.js index d68c3ba25e..26689e9e32 100644 --- a/test/public/runs/navigationUtils.js +++ b/test/public/runs/navigationUtils.js @@ -1,3 +1,16 @@ +/** + * @license + * Copyright CERN and copyright holders of ALICE O2. This software is + * distributed under the terms of the GNU General Public License v3 (GPL + * Version 3), copied verbatim in the file "COPYING". + * + * See http://alice-o2.web.cern.ch/license for full licensing information. + * + * In applying this license CERN does not waive the privileges and immunities + * granted to it by virtue of its status as an Intergovernmental Organization + * or submit itself to any jurisdiction. + */ + const { waitForNavigation, pressElement, getInnerText, expectUrlParams, waitForTableLength } = require('../defaults.js'); /** @@ -32,7 +45,7 @@ exports.navigateToRunsPerDataPass = async (page, lhcPeriodId, dataPassId, expect exports.navigateToRunsPerSimulationPass = async (page, lhcPeriodId, simulationPassId, expectedRowsCount) => { await waitForNavigation(page, () => pressElement(page, 'a#lhc-period-overview', true)); const pdpBeamType = await getInnerText(await page.waitForSelector(`#row${lhcPeriodId}-beamTypes`)); - await waitForNavigation(page, () => pressElement(page, `#row${lhcPeriodId}-associatedDataPasses a`, true)); + await waitForNavigation(page, () => pressElement(page, `#row${lhcPeriodId}-associatedSimulationPasses a`, true)); expectUrlParams(page, { page: 'simulation-passes-per-lhc-period-overview', lhcPeriodId }); await page.waitForSelector('th#description'); await waitForNavigation(page, () => pressElement(page, `#row${simulationPassId}-associatedRuns a`, true)); From 2a061ed38e079c3465862e8f53e5b14ff21e93d5 Mon Sep 17 00:00:00 2001 From: xsalonx Date: Tue, 5 Aug 2025 15:20:49 +0200 Subject: [PATCH 08/19] fix, cleanup --- package.json | 2 +- test/public/runs/navigationUtils.js | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/package.json b/package.json index ef35a82d9c..24c63bfa1e 100644 --- a/package.json +++ b/package.json @@ -10,7 +10,7 @@ "sequelize": "sequelize-cli", "start:dev": "nodemon --ignore 'lib/public/**/*.js' lib/main.js", "start:prod": "node lib/main.js", - "test": "mocha --exit --timeout 0 --grep 'Runs Per Simulation Pass Overview Page'", + "test": "mocha --exit --timeout 0", "test:subset": "nyc -- mocha --exit --timeout 0 test/scripts/test-${TEST_TYPE}.js && nyc report --report-dir=/usr/src/app/coverage/${TEST_TYPE} --reporter=json", "test:subset-local": "mocha --exit --timeout 0 --reporter test/scripts/parallel-local/custom-mocha-reporter.js test/scripts/test-${TEST_TYPE}.js", "docker-run": "docker compose -f docker-compose.yml -f docker-compose.dev.yml up --build", diff --git a/test/public/runs/navigationUtils.js b/test/public/runs/navigationUtils.js index 26689e9e32..652f460481 100644 --- a/test/public/runs/navigationUtils.js +++ b/test/public/runs/navigationUtils.js @@ -44,11 +44,10 @@ exports.navigateToRunsPerDataPass = async (page, lhcPeriodId, dataPassId, expect */ exports.navigateToRunsPerSimulationPass = async (page, lhcPeriodId, simulationPassId, expectedRowsCount) => { await waitForNavigation(page, () => pressElement(page, 'a#lhc-period-overview', true)); - const pdpBeamType = await getInnerText(await page.waitForSelector(`#row${lhcPeriodId}-beamTypes`)); await waitForNavigation(page, () => pressElement(page, `#row${lhcPeriodId}-associatedSimulationPasses a`, true)); expectUrlParams(page, { page: 'simulation-passes-per-lhc-period-overview', lhcPeriodId }); await page.waitForSelector('th#description'); await waitForNavigation(page, () => pressElement(page, `#row${simulationPassId}-associatedRuns a`, true)); - expectUrlParams(page, { page: 'runs-per-simulation-pass', dataPassId: simulationPassId, pdpBeamType }); + expectUrlParams(page, { page: 'runs-per-simulation-pass', simulationPassId }); await waitForTableLength(page, expectedRowsCount); }; From f6b1572e68946998392ad58ec83b7b4727e75a90 Mon Sep 17 00:00:00 2001 From: xsalonx Date: Tue, 5 Aug 2025 15:29:07 +0200 Subject: [PATCH 09/19] fix resetting on leaving page --- .../RunsPerSimulationPassOverviewPage.js | 117 +++++++++--------- 1 file changed, 61 insertions(+), 56 deletions(-) diff --git a/lib/public/views/Runs/RunsPerSimulationPass/RunsPerSimulationPassOverviewPage.js b/lib/public/views/Runs/RunsPerSimulationPass/RunsPerSimulationPassOverviewPage.js index be05790f24..4782d486e9 100644 --- a/lib/public/views/Runs/RunsPerSimulationPass/RunsPerSimulationPassOverviewPage.js +++ b/lib/public/views/Runs/RunsPerSimulationPass/RunsPerSimulationPassOverviewPage.js @@ -72,68 +72,73 @@ export const RunsPerSimulationPassOverviewPage = ({ const commonTitle = h('h2', 'Runs per MC'); - return h('.intermediate-flex-column', mergeRemoteData([remoteSimulationPass, remoteRuns, remoteDetectors, remoteQcSummary]).match({ - NotAsked: () => null, - Failure: (errors) => errorAlert(errors), - Success: ([simulationPass, runs, detectors, qcSummary]) => { - const activeColumns = { - ...runsActiveColumns, - ...runs.some((run) => run.pdpBeamType === PdpBeamType.LEAD_LEAD) ? inelasticInteractionRateActiveColumnsForPbPb : {}, - ...runs.some((run) => run.pdpBeamType === PdpBeamType.PROTON_PROTON) ? inelasticInteractionRateActiveColumnsForProtonProton : {}, - ...createRunDetectorsAsyncQcActiveColumns( - perSimulationPassOverviewModel.runDetectorsSelectionModel, - detectors, - remoteDplDetectorsUserHasAccessTo, - { simulationPass }, - { - profile: 'runsPerSimulationPass', - qcSummary, - }, - ), - }; - - return [ - h('.flex-row.justify-between.items-center.g2', [ - filtersPanelPopover(perSimulationPassOverviewModel, activeColumns, { profile: 'runsPerSimulationPass' }), - h('.pl2#runOverviewFilter', runNumbersFilter(perSimulationPassOverviewModel.filteringModel.get('runNumbers'))), - h( - '.flex-row.g1.items-center', - breadcrumbs([commonTitle, h('h2#breadcrumb-simulation-pass-name', simulationPass.name)]), - ), - mcReproducibleAsNotBadToggle( - mcReproducibleAsNotBad, - () => perSimulationPassOverviewModel.setMcReproducibleAsNotBad(!mcReproducibleAsNotBad), + return h( + '.intermediate-flex-column', + { onremove: () => perSimulationPassOverviewModel.reset(false) }, + mergeRemoteData([remoteSimulationPass, remoteRuns, remoteDetectors, remoteQcSummary]).match({ + NotAsked: () => null, + Failure: (errors) => errorAlert(errors), + Success: ([simulationPass, runs, detectors, qcSummary]) => { + const activeColumns = { + ...runsActiveColumns, + ...runs.some((run) => run.pdpBeamType === PdpBeamType.LEAD_LEAD) ? inelasticInteractionRateActiveColumnsForPbPb : {}, + ...runs.some((run) => run.pdpBeamType === PdpBeamType.PROTON_PROTON) + ? inelasticInteractionRateActiveColumnsForProtonProton : {}, + ...createRunDetectorsAsyncQcActiveColumns( + perSimulationPassOverviewModel.runDetectorsSelectionModel, + detectors, + remoteDplDetectorsUserHasAccessTo, + { simulationPass }, + { + profile: 'runsPerSimulationPass', + qcSummary, + }, ), - h('.mlauto', qcSummaryLegendTooltip()), - exportRunsTriggerAndModal(perSimulationPassOverviewModel, modalModel, { autoMarginLeft: false }), - frontLink( + }; + + return [ + h('.flex-row.justify-between.items-center.g2', [ + filtersPanelPopover(perSimulationPassOverviewModel, activeColumns, { profile: 'runsPerSimulationPass' }), + h('.pl2#runOverviewFilter', runNumbersFilter(perSimulationPassOverviewModel.filteringModel.get('runNumbers'))), h( - 'button.btn.btn-primary.w-100.h2}#set-qc-flags-trigger', + '.flex-row.g1.items-center', + breadcrumbs([commonTitle, h('h2#breadcrumb-simulation-pass-name', simulationPass.name)]), + ), + mcReproducibleAsNotBadToggle( + mcReproducibleAsNotBad, + () => perSimulationPassOverviewModel.setMcReproducibleAsNotBad(!mcReproducibleAsNotBad), + ), + h('.mlauto', qcSummaryLegendTooltip()), + exportRunsTriggerAndModal(perSimulationPassOverviewModel, modalModel, { autoMarginLeft: false }), + frontLink( + h( + 'button.btn.btn-primary.w-100.h2}#set-qc-flags-trigger', + { + disabled: perSimulationPassOverviewModel.runDetectorsSelectionModel.selectedQueryString.length < 1, + }, + 'Set QC Flags', + ), + 'qc-flag-creation-for-simulation-pass', { - disabled: perSimulationPassOverviewModel.runDetectorsSelectionModel.selectedQueryString.length < 1, + runNumberDetectorsMap: perSimulationPassOverviewModel.runDetectorsSelectionModel.selectedQueryString, + simulationPassId, }, - 'Set QC Flags', ), - 'qc-flag-creation-for-simulation-pass', + ]), + table( + runs, + activeColumns, + { classes: getRowClasses }, { - runNumberDetectorsMap: perSimulationPassOverviewModel.runDetectorsSelectionModel.selectedQueryString, - simulationPassId, + profile: 'runsPerSimulationPass', + ...displayOptions, }, + { sort: sortModel }, ), - ]), - table( - runs, - activeColumns, - { classes: getRowClasses }, - { - profile: 'runsPerSimulationPass', - ...displayOptions, - }, - { sort: sortModel }, - ), - paginationComponent(perSimulationPassOverviewModel.pagination), - ]; - }, - Loading: () => spinner(), - })); + paginationComponent(perSimulationPassOverviewModel.pagination), + ]; + }, + Loading: () => spinner(), + }), + ); }; From 85f6b82dbb56fc727bdc64cf937a312d4098c9ad Mon Sep 17 00:00:00 2001 From: xsalonx Date: Tue, 5 Aug 2025 15:58:39 +0200 Subject: [PATCH 10/19] refactor, use lhcPeriodId --- .../RunsPerLhcPeriodOverviewModel.js | 69 +++++++++++++------ .../RunsPerLhcPeriodOverviewPage.js | 53 ++++++++------ lib/public/views/Runs/RunsModel.js | 6 +- .../ActiveColumns/lhcPeriodsActiveColumns.js | 4 +- 4 files changed, 84 insertions(+), 48 deletions(-) diff --git a/lib/public/views/Runs/RunPerPeriod/RunsPerLhcPeriodOverviewModel.js b/lib/public/views/Runs/RunPerPeriod/RunsPerLhcPeriodOverviewModel.js index 898fd3f97c..43e43aa64a 100644 --- a/lib/public/views/Runs/RunPerPeriod/RunsPerLhcPeriodOverviewModel.js +++ b/lib/public/views/Runs/RunPerPeriod/RunsPerLhcPeriodOverviewModel.js @@ -15,6 +15,7 @@ import { TabbedPanelModel } from '../../../components/TabbedPanel/TabbedPanelMod import { detectorsProvider } from '../../../services/detectors/detectorsProvider.js'; import { RunsWithQcModel } from '../Overview/RunsWithQcModel.js'; import { jsonFetch } from '../../../utilities/fetch/jsonFetch.js'; +import { ObservableData } from '../../../utilities/ObservableData.js'; export const RUNS_PER_LHC_PERIOD_PANELS_KEYS = { DETECTOR_QUALITIES: 'detectorQualities', @@ -34,18 +35,49 @@ export class RunsPerLhcPeriodOverviewModel extends RunsWithQcModel { super(model); this._detectors$ = detectorsProvider.physical$; this._detectors$.bubbleTo(this); + this.registerDetectorsNotBadFractionFilterModels(this._detectors$); + + this._lhcPeriodId = null; + this._lhcPeriod$ = new ObservableData(RemoteData.notAsked()); + this._lhcPeriod$.bubbleTo(this); this._tabbedPanelModel = new RunsPerLhcPeriodTabbedPanelModel(); this._tabbedPanelModel.bubbleTo(this); } + /** + * Fetch LHC period data which runs are fetched + * @return {Promise} promise + */ + async _fetchLhcPeriod() { + this._lhcPeriod$.setCurrent(RemoteData.loading()); + try { + const { data: [lhcPeriod] } = await jsonFetch(`/api/lhcPeriodsStatistics?filter[ids][]=${this._lhcPeriodId}`); + this._lhcPeriod$.setCurrent(RemoteData.success(lhcPeriod)); + } catch (error) { + this._lhcPeriod$.setCurrent(RemoteData.failure(error)); + } + } + + /** + * @inheritdoc + */ + async load() { + if (!this._lhcPeriodId) { + return; + } + + await this._fetchLhcPeriod(); + super.load(); + } + /** * @inheritdoc */ getRootEndpoint() { return buildUrl(super.getRootEndpoint(), { filter: { - lhcPeriods: this._lhcPeriodName, + lhcPeriodIds: [this._lhcPeriodId], runQualities: 'good', definitions: 'PHYSICS', }, @@ -53,20 +85,20 @@ export class RunsPerLhcPeriodOverviewModel extends RunsWithQcModel { } /** - * Get name of current lhc period which runs are fetched + * Get LHC period which runs are fetched */ - get lhcPeriodName() { - return this._lhcPeriodName; + get lhcPeriod() { + return this._lhcPeriod$.getCurrent(); } /** - * Set name of current lhc period which runs are fetched + * Set id of current LHC period which runs are fetched * - * @param {string} lhcPeriodName name of LHC period + * @param {string} lhcPeriodId id of a LHC period */ - set lhcPeriodName(lhcPeriodName) { - this._lhcPeriodName = lhcPeriodName; - this._tabbedPanelModel.lhcPeriodName = lhcPeriodName; + set lhcPeriodId(lhcPeriodId) { + this._lhcPeriodId = lhcPeriodId; + this._tabbedPanelModel.lhcPeriodId = lhcPeriodId; } /** @@ -119,17 +151,12 @@ class RunsPerLhcPeriodTabbedPanelModel extends TabbedPanelModel { * @return {Promise} resolved once data are fetched */ async _fetchSynchronousQcSummary() { - if (this._lhcPeriodName) { + if (this._lhcPeriodId) { this.currentPanelData = RemoteData.loading(); this.notify(); try { - const { data: [lhcPeriod] } = await jsonFetch(`/api/lhcPeriodsStatistics?filter[names][]=${this._lhcPeriodName}`); - if (!lhcPeriod) { - this.currentPanelData = RemoteData.failure([{ title: `Cannot find LHC period with name '${this._lhcPeriodName}'` }]); - } else { - const { data: qcSummary } = await jsonFetch(`/api/qcFlags/summary?lhcPeriodId=${lhcPeriod.id}`); - this.currentPanelData = RemoteData.success(qcSummary); - } + const { data: qcSummary } = await jsonFetch(`/api/qcFlags/summary?lhcPeriodId=${this._lhcPeriodId}`); + this.currentPanelData = RemoteData.success(qcSummary); } catch (errors) { this.currentPanelData = RemoteData.failure(errors); } @@ -138,12 +165,12 @@ class RunsPerLhcPeriodTabbedPanelModel extends TabbedPanelModel { } /** - * Set LHC period name + * Set LHC period id * - * @param {string} lhcPeriodName name of LHC period + * @param {string} lhcPeriodId id of LHC period */ - set lhcPeriodName(lhcPeriodName) { - this._lhcPeriodName = lhcPeriodName; + set lhcPeriodId(lhcPeriodId) { + this._lhcPeriodId = lhcPeriodId; this._fetchCurrentPanelData(); } } diff --git a/lib/public/views/Runs/RunPerPeriod/RunsPerLhcPeriodOverviewPage.js b/lib/public/views/Runs/RunPerPeriod/RunsPerLhcPeriodOverviewPage.js index 1ae252ab85..6d301c29b4 100644 --- a/lib/public/views/Runs/RunPerPeriod/RunsPerLhcPeriodOverviewPage.js +++ b/lib/public/views/Runs/RunPerPeriod/RunsPerLhcPeriodOverviewPage.js @@ -25,6 +25,8 @@ import { runDetectorsSyncQcActiveColumns } from '../ActiveColumns/runDetectorsSy import { tabbedPanelComponent } from '../../../components/TabbedPanel/tabbedPanelComponent.js'; import { RUNS_PER_LHC_PERIOD_PANELS_KEYS } from './RunsPerLhcPeriodOverviewModel.js'; import { PdpBeamType } from '../../../domain/enums/PdpBeamType.js'; +import { filtersPanelPopover } from '../../../components/Filters/common/filtersPanelPopover.js'; +import { runNumbersFilter } from '../../../components/Filters/RunsFilter/runNumbersFilter.js'; const TABLEROW_HEIGHT = 62; // Estimate of the navbar and pagination elements height total; Needs to be updated in case of changes; @@ -54,7 +56,7 @@ export const RunsPerLhcPeriodOverviewPage = ({ runs: { perLhcPeriodOverviewModel const { items: remoteRuns, detectors: remoteDetectors, - lhcPeriodName, + lhcPeriod, displayOptions, sortModel, tabbedPanelModel, @@ -103,25 +105,31 @@ export const RunsPerLhcPeriodOverviewPage = ({ runs: { perLhcPeriodOverviewModel { sort: sortModel }, ); - return h('.intermediate-flex-column', [ - h('.flex-row.justify-between.g2', [ - h('h2', `Good, physics runs of ${lhcPeriodName}`), - exportRunsTriggerAndModal(perLhcPeriodOverviewModel, modalModel), - ]), - ...tabbedPanelComponent( - tabbedPanelModel, - { - [RUNS_PER_LHC_PERIOD_PANELS_KEYS.DETECTOR_QUALITIES]: 'Qualities of detectors', - [RUNS_PER_LHC_PERIOD_PANELS_KEYS.SYNCHRONOUS_FLAGS]: 'Synchronous QC flags', - }, - { - [RUNS_PER_LHC_PERIOD_PANELS_KEYS.DETECTOR_QUALITIES]: + return h( + '.intermediate-flex-column', + { onremove: () => perLhcPeriodOverviewModel.reset(false) }, + [ + h('.flex-row.justify-between.g2', [ + filtersPanelPopover(perLhcPeriodOverviewModel, activeColumns, { profile: 'runsPerLhcPeriod' }), + h('.pl2#runOverviewFilter', runNumbersFilter(perLhcPeriodOverviewModel.filteringModel.get('runNumbers'))), + h('h2', `Good, physics runs of ${lhcPeriod.match({ Success: ({ lhcPeriod: { name } }) => name, Other: () => null })}`), + + exportRunsTriggerAndModal(perLhcPeriodOverviewModel, modalModel), + ]), + ...tabbedPanelComponent( + tabbedPanelModel, + { + [RUNS_PER_LHC_PERIOD_PANELS_KEYS.DETECTOR_QUALITIES]: 'Qualities of detectors', + [RUNS_PER_LHC_PERIOD_PANELS_KEYS.SYNCHRONOUS_FLAGS]: 'Synchronous QC flags', + }, + { + [RUNS_PER_LHC_PERIOD_PANELS_KEYS.DETECTOR_QUALITIES]: () => getTableWithGivenDetectorsColumns(runDetectorsQualitiesActiveColumns( remoteDetectors.match({ Success: (payload) => payload, Other: () => [] }), { profiles: 'runsPerLhcPeriod' }, )), - [RUNS_PER_LHC_PERIOD_PANELS_KEYS.SYNCHRONOUS_FLAGS]: + [RUNS_PER_LHC_PERIOD_PANELS_KEYS.SYNCHRONOUS_FLAGS]: (remoteSynchronousQcSummary) => getTableWithGivenDetectorsColumns(runDetectorsSyncQcActiveColumns( remoteDetectors.match({ Success: (payload) => payload, Other: () => [] }), { @@ -129,11 +137,12 @@ export const RunsPerLhcPeriodOverviewPage = ({ runs: { perLhcPeriodOverviewModel qcSummary: remoteSynchronousQcSummary.match({ Success: (qcSummary) => qcSummary, Other: () => null }), }, )), - }, - { - panelClass: ['scroll-auto'], - }, - ), - paginationComponent(perLhcPeriodOverviewModel.pagination), - ]); + }, + { + panelClass: ['scroll-auto'], + }, + ), + paginationComponent(perLhcPeriodOverviewModel.pagination), + ], + ); }; diff --git a/lib/public/views/Runs/RunsModel.js b/lib/public/views/Runs/RunsModel.js index 88aec1ca89..8298ee2857 100644 --- a/lib/public/views/Runs/RunsModel.js +++ b/lib/public/views/Runs/RunsModel.js @@ -85,14 +85,14 @@ export class RunsModel extends Observable { /** * Load runs overview data * @param {object} params the parameters for the model - * @param {string} [params.lhcPeriodName] the name of the LHC period to display + * @param {string} [params.lhcPeriodId] the id of the LHC period to display * @param {string} [params.panel] the key of the panel to display * @return {void} */ - loadPerLhcPeriodOverview({ lhcPeriodName, panel }) { + loadPerLhcPeriodOverview({ lhcPeriodId, panel }) { this._perLhcPeriodOverviewModel.tabbedPanelModel.currentPanelKey = panel; if (!this._perLhcPeriodOverviewModel.pagination.isInfiniteScrollEnabled) { - this._perLhcPeriodOverviewModel.lhcPeriodName = lhcPeriodName; + this._perLhcPeriodOverviewModel.lhcPeriodId = lhcPeriodId; this._perLhcPeriodOverviewModel.load(); } } diff --git a/lib/public/views/lhcPeriods/ActiveColumns/lhcPeriodsActiveColumns.js b/lib/public/views/lhcPeriods/ActiveColumns/lhcPeriodsActiveColumns.js index 125cb30c2c..8d1eeeb19a 100644 --- a/lib/public/views/lhcPeriods/ActiveColumns/lhcPeriodsActiveColumns.js +++ b/lib/public/views/lhcPeriods/ActiveColumns/lhcPeriodsActiveColumns.js @@ -40,13 +40,13 @@ export const lhcPeriodsActiveColumns = { associatedRuns: { name: 'Runs', visible: true, - format: (_, { name, runsCount }) => + format: (_, { id, runsCount }) => runsCount === 0 ? 'No runs' : frontLink( badge(runsCount), 'runs-per-lhc-period', - { lhcPeriodName: name }, + { lhcPeriodId: id }, ), classes: 'w-10', }, From f080a078e7e7582b72d7a332b21b8ccd20c98e0c Mon Sep 17 00:00:00 2001 From: xsalonx Date: Tue, 5 Aug 2025 16:37:00 +0200 Subject: [PATCH 11/19] cleanup --- .../RunsPerLhcPeriodOverviewModel.js | 2 +- .../RunsPerLhcPeriodOverviewPage.js | 74 +++++++++---------- 2 files changed, 38 insertions(+), 38 deletions(-) diff --git a/lib/public/views/Runs/RunPerPeriod/RunsPerLhcPeriodOverviewModel.js b/lib/public/views/Runs/RunPerPeriod/RunsPerLhcPeriodOverviewModel.js index 43e43aa64a..c335caae8f 100644 --- a/lib/public/views/Runs/RunPerPeriod/RunsPerLhcPeriodOverviewModel.js +++ b/lib/public/views/Runs/RunPerPeriod/RunsPerLhcPeriodOverviewModel.js @@ -171,6 +171,6 @@ class RunsPerLhcPeriodTabbedPanelModel extends TabbedPanelModel { */ set lhcPeriodId(lhcPeriodId) { this._lhcPeriodId = lhcPeriodId; - this._fetchCurrentPanelData(); + this.currentPanelData = null; } } diff --git a/lib/public/views/Runs/RunPerPeriod/RunsPerLhcPeriodOverviewPage.js b/lib/public/views/Runs/RunPerPeriod/RunsPerLhcPeriodOverviewPage.js index 6d301c29b4..7c7b4968d4 100644 --- a/lib/public/views/Runs/RunPerPeriod/RunsPerLhcPeriodOverviewPage.js +++ b/lib/public/views/Runs/RunPerPeriod/RunsPerLhcPeriodOverviewPage.js @@ -27,6 +27,9 @@ import { RUNS_PER_LHC_PERIOD_PANELS_KEYS } from './RunsPerLhcPeriodOverviewModel import { PdpBeamType } from '../../../domain/enums/PdpBeamType.js'; import { filtersPanelPopover } from '../../../components/Filters/common/filtersPanelPopover.js'; import { runNumbersFilter } from '../../../components/Filters/RunsFilter/runNumbersFilter.js'; +import { mergeRemoteData } from '../../../utilities/mergeRemoteData.js'; +import errorAlert from '../../../components/common/errorAlert.js'; +import spinner from '../../../components/common/spinner.js'; const TABLEROW_HEIGHT = 62; // Estimate of the navbar and pagination elements height total; Needs to be updated in case of changes; @@ -56,7 +59,7 @@ export const RunsPerLhcPeriodOverviewPage = ({ runs: { perLhcPeriodOverviewModel const { items: remoteRuns, detectors: remoteDetectors, - lhcPeriod, + lhcPeriod: remoteLhcPeriod, displayOptions, sortModel, tabbedPanelModel, @@ -89,9 +92,8 @@ export const RunsPerLhcPeriodOverviewPage = ({ runs: { perLhcPeriodOverviewModel /* * Columns depends on detectors' list, it's not useful to render the table when detectors are missing - * TODO replace by RemoteData merging */ - remoteDetectors.match({ Success: () => remoteRuns, Other: () => remoteDetectors }), + remoteRuns, { ...activeColumns, ...detectorsActiveColumns, @@ -108,41 +110,39 @@ export const RunsPerLhcPeriodOverviewPage = ({ runs: { perLhcPeriodOverviewModel return h( '.intermediate-flex-column', { onremove: () => perLhcPeriodOverviewModel.reset(false) }, - [ - h('.flex-row.justify-between.g2', [ - filtersPanelPopover(perLhcPeriodOverviewModel, activeColumns, { profile: 'runsPerLhcPeriod' }), - h('.pl2#runOverviewFilter', runNumbersFilter(perLhcPeriodOverviewModel.filteringModel.get('runNumbers'))), - h('h2', `Good, physics runs of ${lhcPeriod.match({ Success: ({ lhcPeriod: { name } }) => name, Other: () => null })}`), + mergeRemoteData([remoteLhcPeriod, remoteRuns, remoteDetectors]).match({ + NotAsked: () => null, + Failure: (errors) => errorAlert(errors), + Loading: () => spinner(), + Success: ([lhcPeriod, _, detectors]) => [ + h('.flex-row.justify-between.items-center.g2', [ + filtersPanelPopover(perLhcPeriodOverviewModel, activeColumns, { profile: 'runsPerLhcPeriod' }), + h('.pl2#runOverviewFilter', runNumbersFilter(perLhcPeriodOverviewModel.filteringModel.get('runNumbers'))), + h('h2', `Good, physics runs of ${lhcPeriod.lhcPeriod.name}`), - exportRunsTriggerAndModal(perLhcPeriodOverviewModel, modalModel), - ]), - ...tabbedPanelComponent( - tabbedPanelModel, - { - [RUNS_PER_LHC_PERIOD_PANELS_KEYS.DETECTOR_QUALITIES]: 'Qualities of detectors', - [RUNS_PER_LHC_PERIOD_PANELS_KEYS.SYNCHRONOUS_FLAGS]: 'Synchronous QC flags', - }, - { - [RUNS_PER_LHC_PERIOD_PANELS_KEYS.DETECTOR_QUALITIES]: - () => getTableWithGivenDetectorsColumns(runDetectorsQualitiesActiveColumns( - remoteDetectors.match({ Success: (payload) => payload, Other: () => [] }), - { profiles: 'runsPerLhcPeriod' }, - )), + exportRunsTriggerAndModal(perLhcPeriodOverviewModel, modalModel), + ]), + ...tabbedPanelComponent( + tabbedPanelModel, + { + [RUNS_PER_LHC_PERIOD_PANELS_KEYS.DETECTOR_QUALITIES]: 'Qualities of detectors', + [RUNS_PER_LHC_PERIOD_PANELS_KEYS.SYNCHRONOUS_FLAGS]: 'Synchronous QC flags', + }, + { + [RUNS_PER_LHC_PERIOD_PANELS_KEYS.DETECTOR_QUALITIES]: + () => getTableWithGivenDetectorsColumns(runDetectorsQualitiesActiveColumns(detectors, { profiles: 'runsPerLhcPeriod' })), + + [RUNS_PER_LHC_PERIOD_PANELS_KEYS.SYNCHRONOUS_FLAGS]: + (remoteSynchronousQcSummary) => getTableWithGivenDetectorsColumns(runDetectorsSyncQcActiveColumns(detectors, { + profiles: 'runsPerLhcPeriod', + qcSummary: remoteSynchronousQcSummary.match({ Success: (qcSummary) => qcSummary, Other: () => null }), + })), + }, + { panelClass: ['scroll-auto'] }, + ), + paginationComponent(perLhcPeriodOverviewModel.pagination), + ], + }), - [RUNS_PER_LHC_PERIOD_PANELS_KEYS.SYNCHRONOUS_FLAGS]: - (remoteSynchronousQcSummary) => getTableWithGivenDetectorsColumns(runDetectorsSyncQcActiveColumns( - remoteDetectors.match({ Success: (payload) => payload, Other: () => [] }), - { - profiles: 'runsPerLhcPeriod', - qcSummary: remoteSynchronousQcSummary.match({ Success: (qcSummary) => qcSummary, Other: () => null }), - }, - )), - }, - { - panelClass: ['scroll-auto'], - }, - ), - paginationComponent(perLhcPeriodOverviewModel.pagination), - ], ); }; From 86ffd637f177acd96c79edf5acb310e4841199a2 Mon Sep 17 00:00:00 2001 From: xsalonx Date: Tue, 5 Aug 2025 16:41:39 +0200 Subject: [PATCH 12/19] refactor --- .../RunsPerLhcPeriodOverviewPage.js | 31 ++++++++----------- 1 file changed, 13 insertions(+), 18 deletions(-) diff --git a/lib/public/views/Runs/RunPerPeriod/RunsPerLhcPeriodOverviewPage.js b/lib/public/views/Runs/RunPerPeriod/RunsPerLhcPeriodOverviewPage.js index 7c7b4968d4..6fe006d5ee 100644 --- a/lib/public/views/Runs/RunPerPeriod/RunsPerLhcPeriodOverviewPage.js +++ b/lib/public/views/Runs/RunPerPeriod/RunsPerLhcPeriodOverviewPage.js @@ -66,28 +66,17 @@ export const RunsPerLhcPeriodOverviewPage = ({ runs: { perLhcPeriodOverviewModel } = perLhcPeriodOverviewModel; const activeColumns = { - ...runsActiveColumns, - ...remoteRuns.match({ - Success: (runs) => runs.some((run) => run.pdpBeamType === PdpBeamType.LEAD_LEAD) - ? inelasticInteractionRateActiveColumnsForPbPb - : {}, - Other: () => {}, - }), - ...remoteRuns.match({ - Success: (runs) => runs.some((run) => run.pdpBeamType === PdpBeamType.PROTON_PROTON) - ? inelasticInteractionRateActiveColumnsForProtonProton - : {}, - Other: () => {}, - }), + }; /** * Render runs table with given detectors' active columns configuration * + * @param {Run[]} runs runs * @param {object} detectorsActiveColumns active columns * @return {Component} table with pagination */ - const getTableWithGivenDetectorsColumns = (detectorsActiveColumns) => + const getTableWithGivenDetectorsColumns = (runs, detectorsActiveColumns) => table( /* @@ -95,7 +84,10 @@ export const RunsPerLhcPeriodOverviewPage = ({ runs: { perLhcPeriodOverviewModel */ remoteRuns, { - ...activeColumns, + ...runsActiveColumns, + ...runs.some((run) => run.pdpBeamType === PdpBeamType.LEAD_LEAD) ? inelasticInteractionRateActiveColumnsForPbPb : {}, + ...runs.some((run) => run.pdpBeamType === PdpBeamType.PROTON_PROTON) + ? inelasticInteractionRateActiveColumnsForProtonProton : {}, ...detectorsActiveColumns, }, { classes: getRowClasses }, @@ -114,7 +106,7 @@ export const RunsPerLhcPeriodOverviewPage = ({ runs: { perLhcPeriodOverviewModel NotAsked: () => null, Failure: (errors) => errorAlert(errors), Loading: () => spinner(), - Success: ([lhcPeriod, _, detectors]) => [ + Success: ([lhcPeriod, runs, detectors]) => [ h('.flex-row.justify-between.items-center.g2', [ filtersPanelPopover(perLhcPeriodOverviewModel, activeColumns, { profile: 'runsPerLhcPeriod' }), h('.pl2#runOverviewFilter', runNumbersFilter(perLhcPeriodOverviewModel.filteringModel.get('runNumbers'))), @@ -130,10 +122,13 @@ export const RunsPerLhcPeriodOverviewPage = ({ runs: { perLhcPeriodOverviewModel }, { [RUNS_PER_LHC_PERIOD_PANELS_KEYS.DETECTOR_QUALITIES]: - () => getTableWithGivenDetectorsColumns(runDetectorsQualitiesActiveColumns(detectors, { profiles: 'runsPerLhcPeriod' })), + () => getTableWithGivenDetectorsColumns( + runs, + runDetectorsQualitiesActiveColumns(detectors, { profiles: 'runsPerLhcPeriod' }), + ), [RUNS_PER_LHC_PERIOD_PANELS_KEYS.SYNCHRONOUS_FLAGS]: - (remoteSynchronousQcSummary) => getTableWithGivenDetectorsColumns(runDetectorsSyncQcActiveColumns(detectors, { + (remoteSynchronousQcSummary) => getTableWithGivenDetectorsColumns(runs, runDetectorsSyncQcActiveColumns(detectors, { profiles: 'runsPerLhcPeriod', qcSummary: remoteSynchronousQcSummary.match({ Success: (qcSummary) => qcSummary, Other: () => null }), })), From 1399681e37d99f47a9af965e2b92cd45ae9ca80d Mon Sep 17 00:00:00 2001 From: xsalonx Date: Tue, 5 Aug 2025 16:52:59 +0200 Subject: [PATCH 13/19] fix --- .../views/Runs/RunPerPeriod/RunsPerLhcPeriodOverviewModel.js | 2 +- .../views/Runs/RunPerPeriod/RunsPerLhcPeriodOverviewPage.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/public/views/Runs/RunPerPeriod/RunsPerLhcPeriodOverviewModel.js b/lib/public/views/Runs/RunPerPeriod/RunsPerLhcPeriodOverviewModel.js index c335caae8f..43e43aa64a 100644 --- a/lib/public/views/Runs/RunPerPeriod/RunsPerLhcPeriodOverviewModel.js +++ b/lib/public/views/Runs/RunPerPeriod/RunsPerLhcPeriodOverviewModel.js @@ -171,6 +171,6 @@ class RunsPerLhcPeriodTabbedPanelModel extends TabbedPanelModel { */ set lhcPeriodId(lhcPeriodId) { this._lhcPeriodId = lhcPeriodId; - this.currentPanelData = null; + this._fetchCurrentPanelData(); } } diff --git a/lib/public/views/Runs/RunPerPeriod/RunsPerLhcPeriodOverviewPage.js b/lib/public/views/Runs/RunPerPeriod/RunsPerLhcPeriodOverviewPage.js index 6fe006d5ee..d786774773 100644 --- a/lib/public/views/Runs/RunPerPeriod/RunsPerLhcPeriodOverviewPage.js +++ b/lib/public/views/Runs/RunPerPeriod/RunsPerLhcPeriodOverviewPage.js @@ -130,7 +130,7 @@ export const RunsPerLhcPeriodOverviewPage = ({ runs: { perLhcPeriodOverviewModel [RUNS_PER_LHC_PERIOD_PANELS_KEYS.SYNCHRONOUS_FLAGS]: (remoteSynchronousQcSummary) => getTableWithGivenDetectorsColumns(runs, runDetectorsSyncQcActiveColumns(detectors, { profiles: 'runsPerLhcPeriod', - qcSummary: remoteSynchronousQcSummary.match({ Success: (qcSummary) => qcSummary, Other: () => null }), + qcSummary: remoteSynchronousQcSummary?.match({ Success: (qcSummary) => qcSummary, Other: () => null }), })), }, { panelClass: ['scroll-auto'] }, From d1932bee33c963bf8b2155c6a009e1b7eab75574 Mon Sep 17 00:00:00 2001 From: xsalonx Date: Tue, 5 Aug 2025 16:58:30 +0200 Subject: [PATCH 14/19] a --- .../RunsPerLhcPeriodOverviewPage.js | 76 ++++++++++--------- 1 file changed, 39 insertions(+), 37 deletions(-) diff --git a/lib/public/views/Runs/RunPerPeriod/RunsPerLhcPeriodOverviewPage.js b/lib/public/views/Runs/RunPerPeriod/RunsPerLhcPeriodOverviewPage.js index d786774773..fb6aa33c9e 100644 --- a/lib/public/views/Runs/RunPerPeriod/RunsPerLhcPeriodOverviewPage.js +++ b/lib/public/views/Runs/RunPerPeriod/RunsPerLhcPeriodOverviewPage.js @@ -65,18 +65,14 @@ export const RunsPerLhcPeriodOverviewPage = ({ runs: { perLhcPeriodOverviewModel tabbedPanelModel, } = perLhcPeriodOverviewModel; - const activeColumns = { - - }; - /** * Render runs table with given detectors' active columns configuration * - * @param {Run[]} runs runs - * @param {object} detectorsActiveColumns active columns + * @param {object} activeColumns common acctivte column + * @param {object} detectorsActiveColumns detectors specific columns * @return {Component} table with pagination */ - const getTableWithGivenDetectorsColumns = (runs, detectorsActiveColumns) => + const getTableWithGivenDetectorsColumns = (activeColumns, detectorsActiveColumns) => table( /* @@ -84,10 +80,7 @@ export const RunsPerLhcPeriodOverviewPage = ({ runs: { perLhcPeriodOverviewModel */ remoteRuns, { - ...runsActiveColumns, - ...runs.some((run) => run.pdpBeamType === PdpBeamType.LEAD_LEAD) ? inelasticInteractionRateActiveColumnsForPbPb : {}, - ...runs.some((run) => run.pdpBeamType === PdpBeamType.PROTON_PROTON) - ? inelasticInteractionRateActiveColumnsForProtonProton : {}, + ...activeColumns, ...detectorsActiveColumns, }, { classes: getRowClasses }, @@ -106,37 +99,46 @@ export const RunsPerLhcPeriodOverviewPage = ({ runs: { perLhcPeriodOverviewModel NotAsked: () => null, Failure: (errors) => errorAlert(errors), Loading: () => spinner(), - Success: ([lhcPeriod, runs, detectors]) => [ - h('.flex-row.justify-between.items-center.g2', [ - filtersPanelPopover(perLhcPeriodOverviewModel, activeColumns, { profile: 'runsPerLhcPeriod' }), - h('.pl2#runOverviewFilter', runNumbersFilter(perLhcPeriodOverviewModel.filteringModel.get('runNumbers'))), - h('h2', `Good, physics runs of ${lhcPeriod.lhcPeriod.name}`), + Success: ([lhcPeriod, runs, detectors]) => { + const activeColumns = { + ...runsActiveColumns, + ...runs.some((run) => run.pdpBeamType === PdpBeamType.LEAD_LEAD) ? inelasticInteractionRateActiveColumnsForPbPb : {}, + ...runs.some((run) => run.pdpBeamType === PdpBeamType.PROTON_PROTON) + ? inelasticInteractionRateActiveColumnsForProtonProton : {}, + }; - exportRunsTriggerAndModal(perLhcPeriodOverviewModel, modalModel), - ]), - ...tabbedPanelComponent( - tabbedPanelModel, - { - [RUNS_PER_LHC_PERIOD_PANELS_KEYS.DETECTOR_QUALITIES]: 'Qualities of detectors', - [RUNS_PER_LHC_PERIOD_PANELS_KEYS.SYNCHRONOUS_FLAGS]: 'Synchronous QC flags', - }, - { - [RUNS_PER_LHC_PERIOD_PANELS_KEYS.DETECTOR_QUALITIES]: + return [ + h('.flex-row.justify-between.items-center.g2', [ + filtersPanelPopover(perLhcPeriodOverviewModel, activeColumns, { profile: 'runsPerLhcPeriod' }), + h('.pl2#runOverviewFilter', runNumbersFilter(perLhcPeriodOverviewModel.filteringModel.get('runNumbers'))), + h('h2', `Good, physics runs of ${lhcPeriod.lhcPeriod.name}`), + + exportRunsTriggerAndModal(perLhcPeriodOverviewModel, modalModel), + ]), + ...tabbedPanelComponent( + tabbedPanelModel, + { + [RUNS_PER_LHC_PERIOD_PANELS_KEYS.DETECTOR_QUALITIES]: 'Qualities of detectors', + [RUNS_PER_LHC_PERIOD_PANELS_KEYS.SYNCHRONOUS_FLAGS]: 'Synchronous QC flags', + }, + { + [RUNS_PER_LHC_PERIOD_PANELS_KEYS.DETECTOR_QUALITIES]: () => getTableWithGivenDetectorsColumns( - runs, + activeColumns, runDetectorsQualitiesActiveColumns(detectors, { profiles: 'runsPerLhcPeriod' }), ), - [RUNS_PER_LHC_PERIOD_PANELS_KEYS.SYNCHRONOUS_FLAGS]: - (remoteSynchronousQcSummary) => getTableWithGivenDetectorsColumns(runs, runDetectorsSyncQcActiveColumns(detectors, { - profiles: 'runsPerLhcPeriod', - qcSummary: remoteSynchronousQcSummary?.match({ Success: (qcSummary) => qcSummary, Other: () => null }), - })), - }, - { panelClass: ['scroll-auto'] }, - ), - paginationComponent(perLhcPeriodOverviewModel.pagination), - ], + [RUNS_PER_LHC_PERIOD_PANELS_KEYS.SYNCHRONOUS_FLAGS]: (remoteSynchronousQcSummary) => + getTableWithGivenDetectorsColumns(activeColumns, runDetectorsSyncQcActiveColumns(detectors, { + profiles: 'runsPerLhcPeriod', + qcSummary: remoteSynchronousQcSummary?.match({ Success: (qcSummary) => qcSummary, Other: () => null }), + })), + }, + { panelClass: ['scroll-auto'] }, + ), + paginationComponent(perLhcPeriodOverviewModel.pagination), + ]; + }, }), ); From 38910eccf48da04c779e99a071fb29e59a7435c7 Mon Sep 17 00:00:00 2001 From: xsalonx Date: Wed, 6 Aug 2025 13:00:34 +0200 Subject: [PATCH 15/19] a --- .../RunsPerLhcPeriodOverviewModel.js | 30 +++++++++++++++++-- .../RunsPerLhcPeriodOverviewPage.js | 7 ++++- .../runs/runsPerLhcPeriod.overview.test.js | 16 +++++++++- 3 files changed, 49 insertions(+), 4 deletions(-) diff --git a/lib/public/views/Runs/RunPerPeriod/RunsPerLhcPeriodOverviewModel.js b/lib/public/views/Runs/RunPerPeriod/RunsPerLhcPeriodOverviewModel.js index 43e43aa64a..bc416086b5 100644 --- a/lib/public/views/Runs/RunPerPeriod/RunsPerLhcPeriodOverviewModel.js +++ b/lib/public/views/Runs/RunPerPeriod/RunsPerLhcPeriodOverviewModel.js @@ -101,6 +101,16 @@ export class RunsPerLhcPeriodOverviewModel extends RunsWithQcModel { this._tabbedPanelModel.lhcPeriodId = lhcPeriodId; } + /** + * Set mcReproducibleAsNotBad flag + * + * @param {boolean} mcReproducibleAsNotBad new value + */ + setMcReproducibleAsNotBad(mcReproducibleAsNotBad) { + super.setMcReproducibleAsNotBad(mcReproducibleAsNotBad); + this._tabbedPanelModel.mcReproducibleAsNotBad = mcReproducibleAsNotBad; + } + /** * Get all detectors * @@ -155,7 +165,13 @@ class RunsPerLhcPeriodTabbedPanelModel extends TabbedPanelModel { this.currentPanelData = RemoteData.loading(); this.notify(); try { - const { data: qcSummary } = await jsonFetch(`/api/qcFlags/summary?lhcPeriodId=${this._lhcPeriodId}`); + const { data: qcSummary } = await jsonFetch(buildUrl( + '/api/qcFlags/summary', + { + lhcPeriodId: this._lhcPeriodId, + mcReproducibleAsNotBad: this._mcReproducibleAsNotBad, + }, + )); this.currentPanelData = RemoteData.success(qcSummary); } catch (errors) { this.currentPanelData = RemoteData.failure(errors); @@ -167,10 +183,20 @@ class RunsPerLhcPeriodTabbedPanelModel extends TabbedPanelModel { /** * Set LHC period id * - * @param {string} lhcPeriodId id of LHC period + * @param {id} lhcPeriodId id of LHC period */ set lhcPeriodId(lhcPeriodId) { this._lhcPeriodId = lhcPeriodId; this._fetchCurrentPanelData(); } + + /** + * Set mcReproducibleAsNotBad flag + * + * @param {boolean} mcReproducibleAsNotBad new value + */ + set mcReproducibleAsNotBad(mcReproducibleAsNotBad) { + this._mcReproducibleAsNotBad = mcReproducibleAsNotBad; + this._fetchCurrentPanelData(); + } } diff --git a/lib/public/views/Runs/RunPerPeriod/RunsPerLhcPeriodOverviewPage.js b/lib/public/views/Runs/RunPerPeriod/RunsPerLhcPeriodOverviewPage.js index fb6aa33c9e..f724e28753 100644 --- a/lib/public/views/Runs/RunPerPeriod/RunsPerLhcPeriodOverviewPage.js +++ b/lib/public/views/Runs/RunPerPeriod/RunsPerLhcPeriodOverviewPage.js @@ -30,6 +30,7 @@ import { runNumbersFilter } from '../../../components/Filters/RunsFilter/runNumb import { mergeRemoteData } from '../../../utilities/mergeRemoteData.js'; import errorAlert from '../../../components/common/errorAlert.js'; import spinner from '../../../components/common/spinner.js'; +import { mcReproducibleAsNotBadToggle } from '../mcReproducibleAsNotBadToggle.js'; const TABLEROW_HEIGHT = 62; // Estimate of the navbar and pagination elements height total; Needs to be updated in case of changes; @@ -63,6 +64,7 @@ export const RunsPerLhcPeriodOverviewPage = ({ runs: { perLhcPeriodOverviewModel displayOptions, sortModel, tabbedPanelModel, + mcReproducibleAsNotBad, } = perLhcPeriodOverviewModel; /** @@ -112,7 +114,10 @@ export const RunsPerLhcPeriodOverviewPage = ({ runs: { perLhcPeriodOverviewModel filtersPanelPopover(perLhcPeriodOverviewModel, activeColumns, { profile: 'runsPerLhcPeriod' }), h('.pl2#runOverviewFilter', runNumbersFilter(perLhcPeriodOverviewModel.filteringModel.get('runNumbers'))), h('h2', `Good, physics runs of ${lhcPeriod.lhcPeriod.name}`), - + mcReproducibleAsNotBadToggle( + mcReproducibleAsNotBad, + () => perLhcPeriodOverviewModel.setMcReproducibleAsNotBad(!mcReproducibleAsNotBad), + ), exportRunsTriggerAndModal(perLhcPeriodOverviewModel, modalModel), ]), ...tabbedPanelComponent( diff --git a/test/public/runs/runsPerLhcPeriod.overview.test.js b/test/public/runs/runsPerLhcPeriod.overview.test.js index 7e23ba1fcf..1d629acffd 100644 --- a/test/public/runs/runsPerLhcPeriod.overview.test.js +++ b/test/public/runs/runsPerLhcPeriod.overview.test.js @@ -73,7 +73,7 @@ module.exports = () => { }); it('loads the page successfully', async () => { - const response = await goToPage(page, 'runs-per-lhc-period', { queryParameters: { lhcPeriodName: 'LHC22a' } }); + const response = await goToPage(page, 'runs-per-lhc-period', { queryParameters: { lhcPeriodId: 1 } }); expect(response.status()).to.equal(200); @@ -236,5 +236,19 @@ module.exports = () => { const expectedRunNumber = await getInnerText(await page.waitForSelector('tbody tr:first-of-type a')); await waitForNavigation(page, () => pressElement(page, 'tbody tr:first-of-type a')); expectUrlParams(page, { page: 'run-detail', runNumber: expectedRunNumber }); + await page.goBack() + }); + + it('should successfully apply detectors notBadFraction filters', async () => { + await pressElement(page, '#openFilterToggle', true); + + await page.waitForSelector('#inelasticInteractionRateAvg-operator'); + await page.select('#inelasticInteractionRateAvg-operator', '<='); + await fillInput(page, '#inelasticInteractionRateAvg-operand', '100000', ['change']); + await expectColumnValues(page, 'runNumber', ['56', '54']); + + await pressElement(page, '#openFilterToggle', true); + await pressElement(page, '#reset-filters', true); + await expectColumnValues(page, 'runNumber', ['105', '56', '54', '49']); }); }; From b24e06a7d6551619f78a2bad88bc919f594806e4 Mon Sep 17 00:00:00 2001 From: xsalonx Date: Wed, 6 Aug 2025 14:50:00 +0200 Subject: [PATCH 16/19] test fixes --- test/public/defaults.js | 6 +++--- test/public/runs/runsPerLhcPeriod.overview.test.js | 7 ++++--- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/test/public/defaults.js b/test/public/defaults.js index 877b77134f..645db75124 100644 --- a/test/public/defaults.js +++ b/test/public/defaults.js @@ -773,15 +773,15 @@ module.exports.testTableSortingByColumn = async (page, columnId) => { const notOrderData = await getColumnCellsInnerTexts(page, columnId); // Sort in ASCENDING manner - await this.pressElement(page, `th#${columnId}`); + await this.pressElement(page, `th#${columnId}`, true); this.expectColumnValues(page, columnId, [...notOrderData].sort()); // Sort in DESCENDING manner - await this.pressElement(page, `th#${columnId}`); + await this.pressElement(page, `th#${columnId}`, true); this.expectColumnValues(page, columnId, [...notOrderData].sort().reverse()); // Revoke sorting - await this.pressElement(page, `th#${columnId}`); + await this.pressElement(page, `th#${columnId}`, true); this.expectColumnValues(page, columnId, notOrderData); }; diff --git a/test/public/runs/runsPerLhcPeriod.overview.test.js b/test/public/runs/runsPerLhcPeriod.overview.test.js index 1d629acffd..54f20be24f 100644 --- a/test/public/runs/runsPerLhcPeriod.overview.test.js +++ b/test/public/runs/runsPerLhcPeriod.overview.test.js @@ -29,6 +29,7 @@ const { getInnerText, expectUrlParams, fillInput, + expectColumnValues, } = require('../defaults.js'); const { RUN_QUALITIES, RunQualities } = require('../../../lib/domain/enums/RunQualities.js'); const { resetDatabaseContent } = require('../../utilities/resetDatabaseContent.js'); @@ -152,9 +153,9 @@ module.exports = () => { await page.waitForSelector(`${amountSelectorId} .dropup-menu`); const amountItems5 = `${amountSelectorId} .dropup-menu .menu-item:first-child`; - await pressElement(page, amountItems5); - await expectInnerText(page, '.dropup button', 'Rows per page: 5 '); + await pressElement(page, amountItems5, true); await waitForTableLength(page, 4); + await expectInnerText(page, '.dropup button', 'Rows per page: 5 '); // Expect the custom per page input to have red border and text color if wrong value typed await fillInput(page, `${amountSelectorId} input[type=number]`, '1111'); @@ -190,7 +191,7 @@ module.exports = () => { const targetFileName = 'runs.json'; // First export - await pressElement(page, EXPORT_RUNS_TRIGGER_SELECTOR); + await pressElement(page, EXPORT_RUNS_TRIGGER_SELECTOR, true); await page.waitForSelector('select.form-control', { timeout: 200 }); await page.select('select.form-control', 'runQuality', 'runNumber', 'definition', 'lhcPeriod'); await expectInnerText(page, '#send:enabled', 'Export'); From 5562e5c77495031c18086fd64d338dae5ddecf1d Mon Sep 17 00:00:00 2001 From: xsalonx Date: Tue, 12 Aug 2025 12:34:49 +0200 Subject: [PATCH 17/19] remove artifcat --- .../views/Runs/RunPerPeriod/RunsPerLhcPeriodOverviewModel.js | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/public/views/Runs/RunPerPeriod/RunsPerLhcPeriodOverviewModel.js b/lib/public/views/Runs/RunPerPeriod/RunsPerLhcPeriodOverviewModel.js index bc416086b5..e1b9c01338 100644 --- a/lib/public/views/Runs/RunPerPeriod/RunsPerLhcPeriodOverviewModel.js +++ b/lib/public/views/Runs/RunPerPeriod/RunsPerLhcPeriodOverviewModel.js @@ -35,7 +35,6 @@ export class RunsPerLhcPeriodOverviewModel extends RunsWithQcModel { super(model); this._detectors$ = detectorsProvider.physical$; this._detectors$.bubbleTo(this); - this.registerDetectorsNotBadFractionFilterModels(this._detectors$); this._lhcPeriodId = null; this._lhcPeriod$ = new ObservableData(RemoteData.notAsked()); From f9eed0e9928b85c0f880e7775adcbc5d46c09f53 Mon Sep 17 00:00:00 2001 From: xsalonx Date: Tue, 12 Aug 2025 14:04:00 +0200 Subject: [PATCH 18/19] rename lhcPeriod to lhPeriodStatistics --- .../RunsPerLhcPeriodOverviewModel.js | 16 ++++++++-------- .../RunPerPeriod/RunsPerLhcPeriodOverviewPage.js | 8 ++++---- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/lib/public/views/Runs/RunPerPeriod/RunsPerLhcPeriodOverviewModel.js b/lib/public/views/Runs/RunPerPeriod/RunsPerLhcPeriodOverviewModel.js index e1b9c01338..e9cae75b0d 100644 --- a/lib/public/views/Runs/RunPerPeriod/RunsPerLhcPeriodOverviewModel.js +++ b/lib/public/views/Runs/RunPerPeriod/RunsPerLhcPeriodOverviewModel.js @@ -37,8 +37,8 @@ export class RunsPerLhcPeriodOverviewModel extends RunsWithQcModel { this._detectors$.bubbleTo(this); this._lhcPeriodId = null; - this._lhcPeriod$ = new ObservableData(RemoteData.notAsked()); - this._lhcPeriod$.bubbleTo(this); + this._lhcPeriodStatistics$ = new ObservableData(RemoteData.notAsked()); + this._lhcPeriodStatistics$.bubbleTo(this); this._tabbedPanelModel = new RunsPerLhcPeriodTabbedPanelModel(); this._tabbedPanelModel.bubbleTo(this); @@ -49,12 +49,12 @@ export class RunsPerLhcPeriodOverviewModel extends RunsWithQcModel { * @return {Promise} promise */ async _fetchLhcPeriod() { - this._lhcPeriod$.setCurrent(RemoteData.loading()); + this._lhcPeriodStatistics$.setCurrent(RemoteData.loading()); try { - const { data: [lhcPeriod] } = await jsonFetch(`/api/lhcPeriodsStatistics?filter[ids][]=${this._lhcPeriodId}`); - this._lhcPeriod$.setCurrent(RemoteData.success(lhcPeriod)); + const { data: [lhcPeriodStatistics] } = await jsonFetch(`/api/lhcPeriodsStatistics?filter[ids][]=${this._lhcPeriodId}`); + this._lhcPeriodStatistics$.setCurrent(RemoteData.success(lhcPeriodStatistics)); } catch (error) { - this._lhcPeriod$.setCurrent(RemoteData.failure(error)); + this._lhcPeriodStatistics$.setCurrent(RemoteData.failure(error)); } } @@ -86,8 +86,8 @@ export class RunsPerLhcPeriodOverviewModel extends RunsWithQcModel { /** * Get LHC period which runs are fetched */ - get lhcPeriod() { - return this._lhcPeriod$.getCurrent(); + get lhcPeriodStatistics() { + return this._lhcPeriodStatistics$.getCurrent(); } /** diff --git a/lib/public/views/Runs/RunPerPeriod/RunsPerLhcPeriodOverviewPage.js b/lib/public/views/Runs/RunPerPeriod/RunsPerLhcPeriodOverviewPage.js index f724e28753..c90731f93b 100644 --- a/lib/public/views/Runs/RunPerPeriod/RunsPerLhcPeriodOverviewPage.js +++ b/lib/public/views/Runs/RunPerPeriod/RunsPerLhcPeriodOverviewPage.js @@ -60,7 +60,7 @@ export const RunsPerLhcPeriodOverviewPage = ({ runs: { perLhcPeriodOverviewModel const { items: remoteRuns, detectors: remoteDetectors, - lhcPeriod: remoteLhcPeriod, + lhcPeriodStatistics: remoteLhcPeriodStatistics, displayOptions, sortModel, tabbedPanelModel, @@ -97,11 +97,11 @@ export const RunsPerLhcPeriodOverviewPage = ({ runs: { perLhcPeriodOverviewModel return h( '.intermediate-flex-column', { onremove: () => perLhcPeriodOverviewModel.reset(false) }, - mergeRemoteData([remoteLhcPeriod, remoteRuns, remoteDetectors]).match({ + mergeRemoteData([remoteLhcPeriodStatistics, remoteRuns, remoteDetectors]).match({ NotAsked: () => null, Failure: (errors) => errorAlert(errors), Loading: () => spinner(), - Success: ([lhcPeriod, runs, detectors]) => { + Success: ([lhcPeriodStatistics, runs, detectors]) => { const activeColumns = { ...runsActiveColumns, ...runs.some((run) => run.pdpBeamType === PdpBeamType.LEAD_LEAD) ? inelasticInteractionRateActiveColumnsForPbPb : {}, @@ -113,7 +113,7 @@ export const RunsPerLhcPeriodOverviewPage = ({ runs: { perLhcPeriodOverviewModel h('.flex-row.justify-between.items-center.g2', [ filtersPanelPopover(perLhcPeriodOverviewModel, activeColumns, { profile: 'runsPerLhcPeriod' }), h('.pl2#runOverviewFilter', runNumbersFilter(perLhcPeriodOverviewModel.filteringModel.get('runNumbers'))), - h('h2', `Good, physics runs of ${lhcPeriod.lhcPeriod.name}`), + h('h2', `Good, physics runs of ${lhcPeriodStatistics.lhcPeriod.name}`), mcReproducibleAsNotBadToggle( mcReproducibleAsNotBad, () => perLhcPeriodOverviewModel.setMcReproducibleAsNotBad(!mcReproducibleAsNotBad), From c6b68d0f4af30658a39147b8f0d15d39f6c25b62 Mon Sep 17 00:00:00 2001 From: xsalonx Date: Wed, 20 Aug 2025 15:21:07 +0200 Subject: [PATCH 19/19] fix test --- test/public/runs/runsPerLhcPeriod.overview.test.js | 1 + 1 file changed, 1 insertion(+) diff --git a/test/public/runs/runsPerLhcPeriod.overview.test.js b/test/public/runs/runsPerLhcPeriod.overview.test.js index 6cc1f4e99e..86a422c7a9 100644 --- a/test/public/runs/runsPerLhcPeriod.overview.test.js +++ b/test/public/runs/runsPerLhcPeriod.overview.test.js @@ -193,6 +193,7 @@ module.exports = () => { // First export await pressElement(page, EXPORT_RUNS_TRIGGER_SELECTOR, true); await page.waitForSelector('select.form-control', { timeout: 200 }); + await page.waitForSelector('option[value=runNumber]', { timeout: 200 }); await page.select('select.form-control', 'runQuality', 'runNumber', 'definition', 'lhcPeriod'); await expectInnerText(page, '#send:enabled', 'Export');