From d513387b2efda8a67fad45242597b843556410b6 Mon Sep 17 00:00:00 2001 From: xsalonx Date: Mon, 4 Aug 2025 12:48:10 +0200 Subject: [PATCH 1/9] 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 2/9] 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 3/9] 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 4/9] 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 5/9] 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 6/9] 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 7/9] 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 8/9] 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 9/9] 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(), + }), + ); };