diff --git a/lib/public/views/Runs/ActiveColumns/runDetectorsQualitiesActiveColumns.js b/lib/public/views/Runs/ActiveColumns/runDetectorsQualitiesActiveColumns.js deleted file mode 100644 index 32c777b15d..0000000000 --- a/lib/public/views/Runs/ActiveColumns/runDetectorsQualitiesActiveColumns.js +++ /dev/null @@ -1,39 +0,0 @@ -/** - * @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 { formatDetectorQuality } from '../format/formatDetectorQuality.js'; - -/** - * Factory for detectors' qualities related active columns configuration - * - * @param {Detector[]|DplDetector[]} detectors detectors list - * @param {object} [options] additional options - * @param {object|string|string[]} [options.profiles] profiles to which the column is restricted to - * @return {object} active columns configuration - */ -export const runDetectorsQualitiesActiveColumns = ( - detectors, - { profiles } = {}, -) => Object.fromEntries(detectors?.map(({ name: detectorName }) => [ - detectorName, { - name: detectorName.toUpperCase(), - visible: true, - format: (_, run) => { - const detectorWasActiveDuringRun = run.detectorsQualities.find(({ name }) => name === detectorName); - - return detectorWasActiveDuringRun - ? formatDetectorQuality(detectorWasActiveDuringRun.quality) - : null; - }, - profiles, - }, -]) ?? []); diff --git a/lib/public/views/Runs/ActiveColumns/runDetectorsSyncQcActiveColumns.js b/lib/public/views/Runs/ActiveColumns/runDetectorsQualitiesAndSyncQcActiveColumns.js similarity index 53% rename from lib/public/views/Runs/ActiveColumns/runDetectorsSyncQcActiveColumns.js rename to lib/public/views/Runs/ActiveColumns/runDetectorsQualitiesAndSyncQcActiveColumns.js index 41cf85c7e9..45edb61819 100644 --- a/lib/public/views/Runs/ActiveColumns/runDetectorsSyncQcActiveColumns.js +++ b/lib/public/views/Runs/ActiveColumns/runDetectorsQualitiesAndSyncQcActiveColumns.js @@ -11,12 +11,14 @@ * or submit itself to any jurisdiction. */ import { h, iconBan } from '/js/src/index.js'; +import { formatDetectorQuality } from '../format/formatDetectorQuality.js'; import { getQcSummaryDisplay } from './getQcSummaryDisplay.js'; import { qcFlagOverviewPanelLink } from '../../../components/qcFlags/qcFlagOverviewPanelLink.js'; import { DetectorType } from '../../../domain/enums/DetectorTypes.js'; /** - * Factory for detectors related active columns for synchronous QC flags configuration + * Factory for detectors related active columns configuration displaying, in a single column per detector, both the detector's + * online quality and its synchronous QC flags summary, one under the other * * @param {Detector[]} detectors detectors list * @param {object} [options] additional options @@ -24,7 +26,7 @@ import { DetectorType } from '../../../domain/enums/DetectorTypes.js'; * @param {QcSummary} [options.qcSummary] QC summary of synchronous QC flags for given LHC period * @return {object} active columns configuration */ -export const runDetectorsSyncQcActiveColumns = ( +export const runDetectorsQualitiesAndSyncQcActiveColumns = ( detectors, { profiles, qcSummary } = {}, ) => Object.fromEntries(detectors?.map(({ name: detectorName, id: detectorId, type: detectorType }) => [ @@ -32,18 +34,24 @@ export const runDetectorsSyncQcActiveColumns = ( name: detectorName.toUpperCase(), visible: true, format: (_, { runNumber, detectorsQualities }) => { - const detectorWasActiveDuringRun = Boolean(detectorsQualities.find(({ name }) => name === detectorName)); - if (detectorType === DetectorType.PHYSICAL && !detectorWasActiveDuringRun) { - return null; + const detectorWasActiveDuringRun = detectorsQualities.find(({ name }) => name === detectorName); + + const qualityDisplay = detectorWasActiveDuringRun + ? formatDetectorQuality(detectorWasActiveDuringRun.quality) + : null; + + let syncQcDisplay = null; + if (!(detectorType === DetectorType.PHYSICAL && !detectorWasActiveDuringRun)) { + const runDetectorSummary = qcSummary?.[runNumber]?.[detectorId]; + syncQcDisplay = runDetectorSummary + ? qcFlagOverviewPanelLink( + getQcSummaryDisplay({ ...runDetectorSummary, missingVerificationsCount: 0 }), // Ignore verifications + { runNumber, dplDetectorId: detectorId }, + ) + : h('m2.badge.gray', iconBan()); } - const runDetectorSummary = qcSummary?.[runNumber]?.[detectorId]; - return runDetectorSummary - ? qcFlagOverviewPanelLink( - getQcSummaryDisplay({ ...runDetectorSummary, missingVerificationsCount: 0 }), // Ignore verifications - { runNumber, dplDetectorId: detectorId }, - ) - : h('m2.badge.gray', iconBan()); + return qualityDisplay || syncQcDisplay ? h('.flex-column.g1', [qualityDisplay, syncQcDisplay]) : null; }, profiles, }, diff --git a/lib/public/views/Runs/RunPerPeriod/RunsPerLhcPeriodOverviewModel.js b/lib/public/views/Runs/RunPerPeriod/RunsPerLhcPeriodOverviewModel.js index 2ae78a395c..c009f2acd8 100644 --- a/lib/public/views/Runs/RunPerPeriod/RunsPerLhcPeriodOverviewModel.js +++ b/lib/public/views/Runs/RunPerPeriod/RunsPerLhcPeriodOverviewModel.js @@ -11,18 +11,12 @@ * or submit itself to any jurisdiction. */ import { buildUrl, RemoteData } from '/js/src/index.js'; -import { TabbedPanelModel } from '../../../components/TabbedPanel/TabbedPanelModel.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'; import { FixedPdpBeamTypeRunsOverviewModel } from '../Overview/FixedPdpBeamTypeRunsOverviewModel.js'; -export const RUNS_PER_LHC_PERIOD_PANELS_KEYS = { - DETECTOR_QUALITIES: 'detectorQualities', - SYNCHRONOUS_FLAGS: 'synchronousFlags', -}; - /** * Runs Per LHC Period overview model */ @@ -39,8 +33,6 @@ export class RunsPerLhcPeriodOverviewModel extends FixedPdpBeamTypeRunsOverviewM this._lhcPeriodId = null; this._lhcPeriodStatistics$ = new ObservableData(RemoteData.notAsked()); - this._onlineDetectors$ = rctDetectorsProvider.physical$; - this._syncDetectors$ = ObservableData .builder() .source(rctDetectorsProvider.qc$) @@ -51,11 +43,7 @@ export class RunsPerLhcPeriodOverviewModel extends FixedPdpBeamTypeRunsOverviewM .build(); this._syncDetectors$.bubbleTo(this); - this._onlineDetectors$.bubbleTo(this); this._lhcPeriodStatistics$.bubbleTo(this); - - this._tabbedPanelModel = new RunsPerLhcPeriodTabbedPanelModel(this._qcSummary$); - this._tabbedPanelModel.bubbleTo(this); } /** @@ -107,15 +95,6 @@ export class RunsPerLhcPeriodOverviewModel extends FixedPdpBeamTypeRunsOverviewM return this._lhcPeriodStatistics$.getCurrent(); } - /** - * Get all detectors - * - * @return {RemoteData} detectors - */ - get onlineDetectors() { - return this._onlineDetectors$.getCurrent(); - } - /** * Get all detectors for synchronous QC flags * @@ -132,15 +111,6 @@ export class RunsPerLhcPeriodOverviewModel extends FixedPdpBeamTypeRunsOverviewM return this._syncDetectors$.getCurrent(); } - /** - * Returns the model for the tabbed component - * - * @return {RunsPerLhcPeriodTabbedPanelModel} the tabbed component model - */ - get tabbedPanelModel() { - return this._tabbedPanelModel; - } - /** * Set id of current LHC period which runs are fetched * @@ -160,15 +130,3 @@ export class RunsPerLhcPeriodOverviewModel extends FixedPdpBeamTypeRunsOverviewM return { lhcPeriodId: this._lhcPeriodId }; } } - -/** - * RunsPerLhcPeriodTabbedPanelModel - */ -class RunsPerLhcPeriodTabbedPanelModel extends TabbedPanelModel { - /** - * Constructor - */ - constructor() { - super(Object.values(RUNS_PER_LHC_PERIOD_PANELS_KEYS)); - } -} diff --git a/lib/public/views/Runs/RunPerPeriod/RunsPerLhcPeriodOverviewPage.js b/lib/public/views/Runs/RunPerPeriod/RunsPerLhcPeriodOverviewPage.js index 4a08a95565..8c7b14c7e5 100644 --- a/lib/public/views/Runs/RunPerPeriod/RunsPerLhcPeriodOverviewPage.js +++ b/lib/public/views/Runs/RunPerPeriod/RunsPerLhcPeriodOverviewPage.js @@ -16,11 +16,8 @@ import { table } from '../../../components/common/table/table.js'; import { paginationComponent } from '../../../components/Pagination/paginationComponent.js'; import { estimateDisplayableRowsCount } from '../../../utilities/estimateDisplayableRowsCount.js'; import { runsActiveColumns } from '../ActiveColumns/runsActiveColumns.js'; -import { runDetectorsQualitiesActiveColumns } from '../ActiveColumns/runDetectorsQualitiesActiveColumns.js'; import { isRunNotSubjectToQc } from '../../../components/qcFlags/isRunNotSubjectToQc.js'; -import { runDetectorsSyncQcActiveColumns } from '../ActiveColumns/runDetectorsSyncQcActiveColumns.js'; -import { tabbedPanelComponent } from '../../../components/TabbedPanel/tabbedPanelComponent.js'; -import { RUNS_PER_LHC_PERIOD_PANELS_KEYS } from './RunsPerLhcPeriodOverviewModel.js'; +import { runDetectorsQualitiesAndSyncQcActiveColumns } from '../ActiveColumns/runDetectorsQualitiesAndSyncQcActiveColumns.js'; import { mergeRemoteData } from '../../../utilities/mergeRemoteData.js'; import errorAlert from '../../../components/common/errorAlert.js'; import spinner from '../../../components/common/spinner.js'; @@ -54,11 +51,9 @@ export const RunsPerLhcPeriodOverviewPage = ({ runs: { perLhcPeriodOverviewModel const { items: remoteRuns, lhcPeriodStatistics: remoteLhcPeriodStatistics, - onlineDetectors: remoteOnlineDetectors, syncDetectors: remoteSyncDetectors, displayOptions, sortModel, - tabbedPanelModel, mcReproducibleAsNotBad, qcSummary: remoteQcSummary, pdpBeamTypes, @@ -70,11 +65,11 @@ export const RunsPerLhcPeriodOverviewPage = ({ runs: { perLhcPeriodOverviewModel /** * Render runs table with given detectors' active columns configuration * - * @param {object} activeColumns common acctivte column - * @param {object} detectorsActiveColumns detectors specific columns + * @param {object} activeColumns common active columns + * @param {object} detectorsColumns detectors specific columns, displaying quality and synchronous QC flags summary * @return {Component} table with pagination */ - const getTableWithGivenDetectorsColumns = (activeColumns, detectorsActiveColumns) => + const getTableWithGivenDetectorsColumns = (activeColumns, detectorsColumns) => table( /* @@ -83,7 +78,7 @@ export const RunsPerLhcPeriodOverviewPage = ({ runs: { perLhcPeriodOverviewModel remoteRuns, { ...activeColumns, - ...detectorsActiveColumns, + ...detectorsColumns, }, { classes: getRowClasses }, { @@ -114,45 +109,24 @@ export const RunsPerLhcPeriodOverviewPage = ({ runs: { perLhcPeriodOverviewModel exportTriggerAndModal(perLhcPeriodOverviewModel.exportModel, modalModel), ]), h( - '.intermediate-flex-column', + '.flex-column.w-100', remoteRuns.match({ NotAsked: () => null, Failure: (errors) => errorAlert(errors), Loading: () => spinner(), Success: () => [ - ...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]: () => remoteOnlineDetectors.match({ - Success: (onlineDetectors) => getTableWithGivenDetectorsColumns( - activeColumns, - runDetectorsQualitiesActiveColumns(onlineDetectors, { profiles: 'runsPerLhcPeriod' }), - ), - NotAsked: () => null, - Failure: (errors) => errorAlert(errors), - Loading: () => spinner(), + mergeRemoteData([remoteSyncDetectors, remoteQcSummary]).match({ + Success: ([syncDetectors, synchronousQcSummary]) => getTableWithGivenDetectorsColumns( + activeColumns, + runDetectorsQualitiesAndSyncQcActiveColumns(syncDetectors, { + profiles: 'runsPerLhcPeriod', + qcSummary: synchronousQcSummary, }), - - [RUNS_PER_LHC_PERIOD_PANELS_KEYS.SYNCHRONOUS_FLAGS]: () => - mergeRemoteData([remoteQcSummary, remoteSyncDetectors]).match({ - Success: ([synchronousQcSummary, syncDetectors]) => getTableWithGivenDetectorsColumns( - activeColumns, - runDetectorsSyncQcActiveColumns(syncDetectors, { - profiles: 'runsPerLhcPeriod', - qcSummary: synchronousQcSummary, - }), - ), - NotAsked: () => null, - Failure: (errors) => errorAlert(errors), - Loading: () => spinner(), - }), - }, - { panelClass: ['scroll-auto'] }, - ), + ), + NotAsked: () => null, + Failure: (errors) => errorAlert(errors), + Loading: () => spinner(), + }), paginationComponent(pagination), ] }), ), diff --git a/lib/public/views/Runs/RunsModel.js b/lib/public/views/Runs/RunsModel.js index 007a456368..a509c9fd92 100644 --- a/lib/public/views/Runs/RunsModel.js +++ b/lib/public/views/Runs/RunsModel.js @@ -87,11 +87,9 @@ export class RunsModel extends Observable { * Load runs overview data * @param {object} params the parameters for the model * @param {string} params.lhcPeriodId id of the LHC period to display - * @param {string} params.panel key of the panel to display * @return {void} */ - loadPerLhcPeriodOverview({ lhcPeriodId, panel }) { - this._perLhcPeriodOverviewModel.tabbedPanelModel.currentPanelKey = panel; + loadPerLhcPeriodOverview({ lhcPeriodId }) { if (!this._perLhcPeriodOverviewModel.pagination.isInfiniteScrollEnabled) { this._perLhcPeriodOverviewModel.lhcPeriodId = lhcPeriodId; this._perLhcPeriodOverviewModel.setFilterFromURL(false); diff --git a/test/public/runs/navigationUtils.js b/test/public/runs/navigationUtils.js index 4cbb35a08c..c728991911 100644 --- a/test/public/runs/navigationUtils.js +++ b/test/public/runs/navigationUtils.js @@ -32,11 +32,10 @@ exports.navigateToRunsOverview = async (page) => { * @param {number} expectedRowsCount expected number of rows on runs per data pass page * @return {Promise} promise */ -exports.navigateToRunsPerLhcPeriod = async (page, lhcPeriodId, expectedRowsCount, tabPanel='detectorQualities') => { +exports.navigateToRunsPerLhcPeriod = async (page, lhcPeriodId, expectedRowsCount) => { await waitForNavigation(page, () => pressElement(page, 'a#lhc-period-overview', true)); await waitForNavigation(page, () => pressElement(page, `#row${lhcPeriodId}-associatedRuns a`, true)); - await pressElement(page, `#${tabPanel}-tab`, true); - expectUrlParams(page, { page: 'runs-per-lhc-period', lhcPeriodId, panel: tabPanel }, ['pdpBeamType']); + expectUrlParams(page, { page: 'runs-per-lhc-period', lhcPeriodId }, ['pdpBeamType']); await waitForTableLength(page, expectedRowsCount); }; diff --git a/test/public/runs/runsPerLhcPeriod.overview.test.js b/test/public/runs/runsPerLhcPeriod.overview.test.js index 77d1ec4a24..f52e2b8086 100644 --- a/test/public/runs/runsPerLhcPeriod.overview.test.js +++ b/test/public/runs/runsPerLhcPeriod.overview.test.js @@ -106,34 +106,25 @@ module.exports = () => { inelasticInteractionRateAtEnd: (value) => value === '-' || !isNaN(Number(value.replace(/,/g, ''))), }; - // By default current tab is 'detectorsQualities' - const tableDataValidatorsWithDetectorQualities = { - ...tableDataValidators, - ...Object.fromEntries(DETECTORS.map((detectorName) => [detectorName, (quality) => expect(quality).oneOf([...RUN_QUALITIES, ''])])), + // Detector columns now combine, in a single cell, both the detector's quality and its synchronous QC flags summary + const combinedDetectorCellValidator = (cellText) => { + const lines = cellText.split('\n').map((line) => line.trim()).filter(Boolean); + return lines.length <= 2 && lines.every((line) => RUN_QUALITIES.includes(line) || !isNaN(Number(line))); }; - await waitForTableLength(page, 4); - await validateTableData(page, new Map(Object.entries(tableDataValidatorsWithDetectorQualities))); - - await waitForNavigation(page, () => pressElement(page, '#synchronousFlags-tab')); - - await page.waitForSelector('tbody tr:not(.loading-row)'); - - const tableDataValidatorsWithQualityFromSynchronousFlags = { + const tableDataValidatorsWithDetectorColumns = { ...tableDataValidators, - ...Object.fromEntries(DETECTORS.map((detectorName) => [ - detectorName, - (notBadDataFraction) => !notBadDataFraction || !isNaN(Number(notBadDataFraction)), - ])), + ...Object.fromEntries(DETECTORS.map((detectorName) => [detectorName, combinedDetectorCellValidator])), }; await waitForTableLength(page, 4); - await validateTableData(page, new Map(Object.entries(tableDataValidatorsWithQualityFromSynchronousFlags))); - await expectInnerText(page, '#row56-FT0', '83'); + await validateTableData(page, new Map(Object.entries(tableDataValidatorsWithDetectorColumns))); + + const ft0CellText = await getInnerText(await page.waitForSelector('#row56-FT0')); + expect(ft0CellText).to.include('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),