diff --git a/lib/public/domain/enums/DetectorOrders.js b/lib/public/domain/enums/DetectorOrders.js new file mode 100644 index 0000000000..e4b95b318b --- /dev/null +++ b/lib/public/domain/enums/DetectorOrders.js @@ -0,0 +1,35 @@ +/** + * @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 { DetectorType } from './DetectorTypes.js'; + +export const DetectorOrders = Object.freeze({ + DEFAULT: { + [DetectorType.OTHER]: 0, + [DetectorType.VIRTUAL]: 1, + [DetectorType.PHYSICAL]: 2, + [DetectorType.AOT_GLO]: 3, + [DetectorType.AOT_EVENT]: 4, + [DetectorType.MUON_GLO]: 5, + [DetectorType.QC_ONLY]: 6, + }, + RCT: { + [DetectorType.OTHER]: 0, + [DetectorType.AOT_GLO]: 1, + [DetectorType.AOT_EVENT]: 2, + [DetectorType.MUON_GLO]: 3, + [DetectorType.VIRTUAL]: 4, + [DetectorType.PHYSICAL]: 5, + [DetectorType.QC_ONLY]: 6, + }, +}); diff --git a/lib/public/services/detectors/detectorsProvider.js b/lib/public/services/detectors/detectorsProvider.js index 3825835d66..9c02ea7957 100644 --- a/lib/public/services/detectors/detectorsProvider.js +++ b/lib/public/services/detectors/detectorsProvider.js @@ -15,6 +15,7 @@ import { switchCase } from '/js/src/index.js'; import { getRemoteData } from '../../utilities/fetch/getRemoteData.js'; import { ObservableData } from '../../utilities/ObservableData.js'; import { DetectorType, DATA_TAKING_DETECTOR_TYPES, QC_DETECTORS } from '../../domain/enums/DetectorTypes.js'; +import { DetectorOrders } from '../../domain/enums/DetectorOrders.js'; import { NonPhysicalDetector } from '../../domain/enums/detectorsNames.mjs'; @@ -44,9 +45,12 @@ const getQcDetectorsFromAllDetectors = (allDetectors) => allDetectors export class DetectorsProvider extends RemoteDataProvider { /** * Constructor + * + * @param {DetectorOrders} detectorOrder the order to base sorting on, default is DetectorOrders.DEFAULT */ - constructor() { + constructor(detectorOrder = DetectorOrders.DEFAULT) { super(); + this._detectorOrder = detectorOrder; this._physical$ = ObservableData.builder() .source(this._items$) .apply((remoteDetectors) => remoteDetectors.apply({ @@ -74,15 +78,7 @@ export class DetectorsProvider extends RemoteDataProvider { */ async getRemoteData() { const { data: detectors } = await getRemoteData('/api/detectors'); - const typeToOrderingKey = (type) => switchCase(type, { - [DetectorType.OTHER]: 0, - [DetectorType.VIRTUAL]: 1, - [DetectorType.PHYSICAL]: 2, - [DetectorType.AOT_GLO]: 3, - [DetectorType.AOT_EVENT]: 4, - [DetectorType.MUON_GLO]: 5, - [DetectorType.QC_ONLY]: 6, - }); + const typeToOrderingKey = (type) => switchCase(type, this._detectorOrder); const orderingKey = (detector1, detector2) => { const specialPair = ['ZDC', 'TST']; @@ -161,3 +157,4 @@ export class DetectorsProvider extends RemoteDataProvider { } export const detectorsProvider = new DetectorsProvider(); +export const rctDetectorsProvider = new DetectorsProvider(DetectorOrders.RCT); diff --git a/lib/public/views/Runs/RunPerDataPass/RunsPerDataPassOverviewModel.js b/lib/public/views/Runs/RunPerDataPass/RunsPerDataPassOverviewModel.js index 0aca49d627..4e602e4ef1 100644 --- a/lib/public/views/Runs/RunPerDataPass/RunsPerDataPassOverviewModel.js +++ b/lib/public/views/Runs/RunPerDataPass/RunsPerDataPassOverviewModel.js @@ -14,7 +14,7 @@ import { buildUrl, RemoteData } from '/js/src/index.js'; import { ObservableData } from '../../../utilities/ObservableData.js'; import { getRemoteDataSlice } from '../../../utilities/fetch/getRemoteDataSlice.js'; import { getRemoteData } from '../../../utilities/fetch/getRemoteData.js'; -import { detectorsProvider } from '../../../services/detectors/detectorsProvider.js'; +import { rctDetectorsProvider } from '../../../services/detectors/detectorsProvider.js'; import { FixedPdpBeamTypeRunsOverviewModel } from '../Overview/FixedPdpBeamTypeRunsOverviewModel.js'; import { jsonPatch } from '../../../utilities/fetch/jsonPatch.js'; import { jsonPut } from '../../../utilities/fetch/jsonPut.js'; @@ -43,7 +43,7 @@ export class RunsPerDataPassOverviewModel extends FixedPdpBeamTypeRunsOverviewMo this._detectors$ = ObservableData .builder() - .sources([detectorsProvider.qc$, this._dataPass$]) + .sources([rctDetectorsProvider.qc$, this._dataPass$]) .apply((remoteDataList) => mergeRemoteData(remoteDataList) .apply({ Success: ([detectors, dataPass]) => ALL_CPASS_PRODUCTIONS_REGEX.test(dataPass.name) ? detectors.filter(({ name, type }) => type !== DetectorType.AOT_GLO || DETECTOR_NAMES_NOT_IN_CPASSES.includes(name)) diff --git a/lib/public/views/Runs/RunPerPeriod/RunsPerLhcPeriodOverviewModel.js b/lib/public/views/Runs/RunPerPeriod/RunsPerLhcPeriodOverviewModel.js index b361522b8b..a2f5ebd2e5 100644 --- a/lib/public/views/Runs/RunPerPeriod/RunsPerLhcPeriodOverviewModel.js +++ b/lib/public/views/Runs/RunPerPeriod/RunsPerLhcPeriodOverviewModel.js @@ -12,7 +12,7 @@ */ import { buildUrl, RemoteData } from '/js/src/index.js'; import { TabbedPanelModel } from '../../../components/TabbedPanel/TabbedPanelModel.js'; -import { detectorsProvider } from '../../../services/detectors/detectorsProvider.js'; +import { rctDetectorsProvider } from '../../../services/detectors/detectorsProvider.js'; import { jsonFetch } from '../../../utilities/fetch/jsonFetch.js'; import { DetectorType } from '../../../domain/enums/DetectorTypes.js'; import { ObservableData } from '../../../utilities/ObservableData.js'; @@ -38,11 +38,11 @@ export class RunsPerLhcPeriodOverviewModel extends FixedPdpBeamTypeRunsOverviewM this._lhcPeriodId = null; this._lhcPeriodStatistics$ = new ObservableData(RemoteData.notAsked()); - this._onlineDetectors$ = detectorsProvider.physical$; + this._onlineDetectors$ = rctDetectorsProvider.physical$; this._syncDetectors$ = ObservableData .builder() - .source(detectorsProvider.qc$) + .source(rctDetectorsProvider.qc$) .apply((remoteDetectors) => remoteDetectors.apply({ Success: (detectors) => detectors.filter(({ type }) => [DetectorType.PHYSICAL, DetectorType.MUON_GLO].includes(type)), diff --git a/lib/public/views/Runs/RunsPerSimulationPass/RunsPerSimulationPassOverviewModel.js b/lib/public/views/Runs/RunsPerSimulationPass/RunsPerSimulationPassOverviewModel.js index 9b8b982d4b..3eb0a38303 100644 --- a/lib/public/views/Runs/RunsPerSimulationPass/RunsPerSimulationPassOverviewModel.js +++ b/lib/public/views/Runs/RunsPerSimulationPass/RunsPerSimulationPassOverviewModel.js @@ -13,7 +13,7 @@ import { buildUrl, RemoteData } from '/js/src/index.js'; import { ObservableData } from '../../../utilities/ObservableData.js'; import { getRemoteData } from '../../../utilities/fetch/getRemoteData.js'; -import { detectorsProvider } from '../../../services/detectors/detectorsProvider.js'; +import { rctDetectorsProvider } from '../../../services/detectors/detectorsProvider.js'; import { FixedPdpBeamTypeRunsOverviewModel } from '../Overview/FixedPdpBeamTypeRunsOverviewModel.js'; /** @@ -29,7 +29,7 @@ export class RunsPerSimulationPassOverviewModel extends FixedPdpBeamTypeRunsOver this._simulationPass$ = new ObservableData(RemoteData.notAsked()); - this._detectors$ = detectorsProvider.qc$; + this._detectors$ = rctDetectorsProvider.qc$; this.registerObervablesQcSummaryDependesOn([this._detectors$]); this.registerDetectorsNotBadFractionFilterModels(this._detectors$); diff --git a/test/public/runs/runsPerDataPass.overview.test.js b/test/public/runs/runsPerDataPass.overview.test.js index f45d004e55..9d210e25ed 100644 --- a/test/public/runs/runsPerDataPass.overview.test.js +++ b/test/public/runs/runsPerDataPass.overview.test.js @@ -152,6 +152,17 @@ module.exports = () => { .to.be.equal('Missing 3 verifications'); }); + it('should display detector columns in RCT order (AOT/MUON after physical)', async () => { + const headers = await page.$$eval( + 'table thead th', + (ths) => ths.map((th) => th.id).filter(Boolean), + ); + + // see DetectorOrders.RCT in detectorsProvider.js + expect(headers.indexOf('VTX')).to.be.greaterThan(headers.indexOf('ZDC')); + expect(headers.indexOf('MUD')).to.be.greaterThan(headers.indexOf('ZDC')); + }); + it('should ignore QC flags created by services in QC summaries of AOT and MUON ', async () => { await navigateToRunsPerDataPass(page, 2, 1, 3); // apass await expectInnerText(page, '#row106-VTX-text', '100'); @@ -394,10 +405,10 @@ module.exports = () => { const exportContent = fs.readFileSync(path.resolve(downloadPath, targetFileName)).toString(); expect(exportContent.trim()).to.be.eql([ - 'runNumber;VTX;CPV', + 'runNumber;CPV;VTX', '108;"";""', - '107;"";"Good (from: 1565290800000 to: 1565359260000) | Limited Acceptance MC Reproducible (from: 1565269140000 to: 1565290800000)"', - '106;"Good (from: 1565269200000 to: 1565304200000) | Good (from: 1565324200000 to: 1565359200000)";"Limited Acceptance MC Reproducible (from: 1565304200000 to: 1565324200000) | Limited acceptance (from: 1565329200000 to: 1565334200000) | Bad (from: 1565339200000 to: 1565344200000)"', + '107;"Good (from: 1565290800000 to: 1565359260000) | Limited Acceptance MC Reproducible (from: 1565269140000 to: 1565290800000)";""', + '106;"Limited Acceptance MC Reproducible (from: 1565304200000 to: 1565324200000) | Limited acceptance (from: 1565329200000 to: 1565334200000) | Bad (from: 1565339200000 to: 1565344200000)";"Good (from: 1565269200000 to: 1565304200000) | Good (from: 1565324200000 to: 1565359200000)"', ].join('\r\n')); fs.unlinkSync(path.resolve(downloadPath, targetFileName)); }); diff --git a/test/public/runs/runsPerLhcPeriod.overview.test.js b/test/public/runs/runsPerLhcPeriod.overview.test.js index f38dc635a9..023ab4921e 100644 --- a/test/public/runs/runsPerLhcPeriod.overview.test.js +++ b/test/public/runs/runsPerLhcPeriod.overview.test.js @@ -130,6 +130,17 @@ module.exports = () => { await expectInnerText(page, '#row56-FT0', '83'); }); + it('should display detector columns in RCT order (AOT/MUON after physical) for synchronous flags', async () => { + // Note test starts already on synchronous flags tab + const headers = await page.$$eval( + 'table thead th', + (ths) => ths.map((th) => th.id).filter(Boolean), + ); + + // see DetectorOrders.RCT in detectorsProvider.js + expect(headers.indexOf('MUD')).to.be.greaterThan(headers.indexOf('ZDC')); + }); + it('should successfully sort by runNumber in ascending and descending manners', async () => { await testTableSortingByColumn(page, 'runNumber'); }); diff --git a/test/public/runs/runsPerSimulationPass.overview.test.js b/test/public/runs/runsPerSimulationPass.overview.test.js index b7b1c725fd..afa3dab09c 100644 --- a/test/public/runs/runsPerSimulationPass.overview.test.js +++ b/test/public/runs/runsPerSimulationPass.overview.test.js @@ -137,6 +137,17 @@ module.exports = () => { await qcFlagService.delete(tmpQcFlag.id); }); + it('should display detector columns in RCT order (AOT/MUON after physical)', async () => { + const headers = await page.$$eval( + 'table thead th', + (ths) => ths.map((th) => th.id).filter(Boolean), + ); + + // see DetectorOrders.RCT in detectorsProvider.js + expect(headers.indexOf('VTX')).to.be.greaterThan(headers.indexOf('ZDC')); + expect(headers.indexOf('MUD')).to.be.greaterThan(headers.indexOf('ZDC')); + }); + it('should successfully sort by runNumber in ascending and descending manners', async () => { await testTableSortingByColumn(page, 'runNumber'); });