From ca80c45eb97255ee1f8674a938110177e60af803 Mon Sep 17 00:00:00 2001 From: Martin Boulais <31805063+martinboulais@users.noreply.github.com> Date: Thu, 25 Apr 2024 08:30:55 +0200 Subject: [PATCH 1/3] [O2B-1224] Use weighted means for ALICE efficiency in statistics (#1529) * [O2B-1224] Use weighted means for ALICE efficiency in statistics * Fix --- .../adapters/LhcFillStatisticsAdapter.js | 3 + ...include-fill-without-runs-in-statistics.js | 13 +++ ...add-sb-duration-to-fill-statistics-view.js | 83 +++++++++++++++++++ lib/database/models/lhcFillStatistics.js | 4 + .../typedefs/SequelizeLhcFillStatistics.js | 1 + .../entities/statistics/LhcFillStatistics.js | 1 + .../charts/efficiencyChartComponent.js | 12 ++- 7 files changed, 113 insertions(+), 4 deletions(-) create mode 100644 lib/database/migrations/20240423072839-add-sb-duration-to-fill-statistics-view.js diff --git a/lib/database/adapters/LhcFillStatisticsAdapter.js b/lib/database/adapters/LhcFillStatisticsAdapter.js index 289a6b04cd..bb016a7e5a 100644 --- a/lib/database/adapters/LhcFillStatisticsAdapter.js +++ b/lib/database/adapters/LhcFillStatisticsAdapter.js @@ -24,6 +24,7 @@ class LhcFillStatisticsAdapter { toEntity(databaseObject) { const { fillNumber, + stableBeamsDuration, runsCoverage, efficiency, timeLossAtStart, @@ -38,6 +39,8 @@ class LhcFillStatisticsAdapter { return { fillNumber, // Convert to ms + stableBeamsDuration: stableBeamsDuration * 1000, + // Convert to ms runsCoverage: runsCoverage * 1000, efficiency: parseFloat(efficiency), // Convert to ms diff --git a/lib/database/migrations/20230901090207-include-fill-without-runs-in-statistics.js b/lib/database/migrations/20230901090207-include-fill-without-runs-in-statistics.js index eec7c9f915..fb4d537b5e 100644 --- a/lib/database/migrations/20230901090207-include-fill-without-runs-in-statistics.js +++ b/lib/database/migrations/20230901090207-include-fill-without-runs-in-statistics.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. + */ + 'use strict'; const ROLLBACK_FILL_STATISTICS_TO_PREVIOUS = ` diff --git a/lib/database/migrations/20240423072839-add-sb-duration-to-fill-statistics-view.js b/lib/database/migrations/20240423072839-add-sb-duration-to-fill-statistics-view.js new file mode 100644 index 0000000000..9af48f74c5 --- /dev/null +++ b/lib/database/migrations/20240423072839-add-sb-duration-to-fill-statistics-view.js @@ -0,0 +1,83 @@ +/** + * @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. + */ + +'use strict'; + +const UPDATE_FILL_STATISTICS_VIEW = ` +CREATE OR REPLACE VIEW fill_statistics AS +SELECT lf.fill_number, + -- Use max to comply with gruop by, but all the values are the same in the group + COALESCE(MAX(sbr.sb_duration), 0) stable_beams_duration, + SUM(sbr.sb_run_duration) runs_coverage, + SUM(COALESCE(sbr.sb_run_duration / sbr.sb_duration, 0)) efficiency, + COALESCE( + TO_SECONDS(MIN(sbr.sb_run_start)) - TO_SECONDS(MAX(sbr.sb_start)), + 0 + ) time_loss_at_start, + COALESCE( + (TO_SECONDS(MIN(sbr.sb_run_start)) - TO_SECONDS(MAX(sbr.sb_start))) / MAX(sbr.sb_duration), + 0 + ) efficiency_loss_at_start, + COALESCE(TO_SECONDS(MIN(sbr.sb_end)) - TO_SECONDS(MAX(sbr.sb_run_end)), 0) time_loss_at_end, + COALESCE( + (TO_SECONDS(MIN(sbr.sb_end)) - TO_SECONDS(MAX(sbr.sb_run_end))) / MAX(sbr.sb_duration), + 0 + ) efficiency_loss_at_end, + COALESCE(AVG(sbr.sb_run_duration), 0) mean_run_duration, + COALESCE(SUM(r.ctf_file_size), 0) total_ctf_file_size, + COALESCE(SUM(r.tf_file_size), 0) total_tf_file_size +FROM lhc_fills lf + LEFT JOIN runs r ON r.fill_number = lf.fill_number AND r.definition = 'PHYSICS' AND r.run_quality = 'good' + LEFT JOIN stable_beam_runs sbr ON sbr.run_number = r.run_number +WHERE lf.stable_beams_start IS NOT NULL +GROUP BY lf.fill_number; +`; + +const ROLLBACK_FILL_STATISTICS_TO_PREVIOUS = ` +CREATE OR REPLACE VIEW fill_statistics AS +SELECT lf.fill_number, + SUM(sbr.sb_run_duration) runs_coverage, + SUM(COALESCE(sbr.sb_run_duration / sbr.sb_duration, 0)) efficiency, + COALESCE( + TO_SECONDS(MIN(sbr.sb_run_start)) - TO_SECONDS(MAX(sbr.sb_start)), + 0 + ) time_loss_at_start, + COALESCE( + (TO_SECONDS(MIN(sbr.sb_run_start)) - TO_SECONDS(MAX(sbr.sb_start))) / MAX(sbr.sb_duration), + 0 + ) efficiency_loss_at_start, + COALESCE(TO_SECONDS(MIN(sbr.sb_end)) - TO_SECONDS(MAX(sbr.sb_run_end)), 0) time_loss_at_end, + COALESCE( + (TO_SECONDS(MIN(sbr.sb_end)) - TO_SECONDS(MAX(sbr.sb_run_end))) / MAX(sbr.sb_duration), + 0 + ) efficiency_loss_at_end, + COALESCE(AVG(sbr.sb_run_duration), 0) mean_run_duration, + COALESCE(SUM(r.ctf_file_size), 0) total_ctf_file_size, + COALESCE(SUM(r.tf_file_size), 0) total_tf_file_size +FROM lhc_fills lf + LEFT JOIN runs r ON r.fill_number = lf.fill_number AND r.definition = 'PHYSICS' AND r.run_quality = 'good' + LEFT JOIN stable_beam_runs sbr ON sbr.run_number = r.run_number +WHERE lf.stable_beams_start IS NOT NULL +GROUP BY lf.fill_number; +`; + +/** @type {import('sequelize-cli').Migration} */ +module.exports = { + up: async (queryInterface) => queryInterface.sequelize.transaction(async (transaction) => { + await queryInterface.sequelize.query(UPDATE_FILL_STATISTICS_VIEW, { transaction }); + }), + + down: async (queryInterface) => queryInterface.sequelize.transaction(async (transaction) => { + await queryInterface.sequelize.query(ROLLBACK_FILL_STATISTICS_TO_PREVIOUS, { transaction }); + }), +}; diff --git a/lib/database/models/lhcFillStatistics.js b/lib/database/models/lhcFillStatistics.js index 1f2541c519..672cf46849 100644 --- a/lib/database/models/lhcFillStatistics.js +++ b/lib/database/models/lhcFillStatistics.js @@ -20,6 +20,10 @@ module.exports = (sequelize) => { type: Sequelize.NUMBER, primaryKey: true, }, + stableBeamsDuration: { + allowNull: false, + type: Sequelize.NUMBER, + }, runsCoverage: { allowNull: false, type: Sequelize.NUMBER, diff --git a/lib/database/models/typedefs/SequelizeLhcFillStatistics.js b/lib/database/models/typedefs/SequelizeLhcFillStatistics.js index e2fba25acc..17f6698b5d 100644 --- a/lib/database/models/typedefs/SequelizeLhcFillStatistics.js +++ b/lib/database/models/typedefs/SequelizeLhcFillStatistics.js @@ -15,6 +15,7 @@ * @typedef SequelizeLhcFillStatistics * * @property {number} fillNumber the fill number to which the statistics applies to + * @property {number} stableBeamsDuration the duration of the fill stable beams * @property {number} runsCoverage total duration covered by at least one run (in seconds) * @property {string} efficiency efficiency of the fill * @property {number} timeLossAtStart duration between the start of the fill and the start of the first run (in seconds) diff --git a/lib/domain/entities/statistics/LhcFillStatistics.js b/lib/domain/entities/statistics/LhcFillStatistics.js index 827c9eeeee..0e575a919e 100644 --- a/lib/domain/entities/statistics/LhcFillStatistics.js +++ b/lib/domain/entities/statistics/LhcFillStatistics.js @@ -15,6 +15,7 @@ * @typedef LhcFillStatistics * * @property {number} fillNumber the fill number to which the statistics applies to + * @property {number} stableBeamsDuration the total stable beam duration of the fill * @property {number} runsCoverage total duration covered by at least one run (in ms) * @property {number} efficiency efficiency of the fill * @property {number} timeLossAtStart duration between the start of the fill and the start of the first run (in ms) diff --git a/lib/public/views/Statistics/charts/efficiencyChartComponent.js b/lib/public/views/Statistics/charts/efficiencyChartComponent.js index 68750d5b9c..6ff0938388 100644 --- a/lib/public/views/Statistics/charts/efficiencyChartComponent.js +++ b/lib/public/views/Statistics/charts/efficiencyChartComponent.js @@ -30,16 +30,20 @@ import { formatPercentage } from '../../../utilities/formatting/formatPercentage */ export const efficiencyChartComponent = (statistics, onPointHover, periodLabel) => { const points = []; - let efficiencySum = 0; - for (const { fillNumber, efficiency, efficiencyLossAtStart } of statistics) { + let totalRunsCoverage = 0; + let totalStableBeamDuration = 0; + for (const { fillNumber, stableBeamsDuration, runsCoverage, efficiency, efficiencyLossAtStart } of statistics) { points.push({ x: fillNumber, y: [efficiency + efficiencyLossAtStart, efficiency], }); - efficiencySum += efficiency; + + totalRunsCoverage += runsCoverage; + totalStableBeamDuration += stableBeamsDuration; } - const meanEfficiency = efficiencySum / points.length; + const meanEfficiency = totalRunsCoverage / totalStableBeamDuration; + if (points.length) { points[0].y.push(meanEfficiency); points[points.length - 1].y.push(meanEfficiency); From 1969a85e0712cec44774d7f8bb70bf4d20681d56 Mon Sep 17 00:00:00 2001 From: Martin Boulais <31805063+martinboulais@users.noreply.github.com> Date: Thu, 25 Apr 2024 11:46:37 +0200 Subject: [PATCH 2/3] [O2B-1171] Do not display missing trigger start/stop when trigger is OFF (#1476) * [O2B-1171] Do not display missing trigger start/stop when trigger is OFF * Add tests * Fix linter * Fix tests & update badly named function --- lib/database/seeders/20200713103855-runs.js | 3 +- ...{triggerValue.js => triggerValueFilter.js} | 7 ++-- lib/public/domain/enums/TriggerValue.js | 20 ++++++++++++ .../Runs/ActiveColumns/runsActiveColumns.js | 2 +- .../views/Runs/format/displayRunDuration.js | 23 +++++++------ lib/public/views/Runs/format/formatRunEnd.js | 28 ++++++++++------ .../views/Runs/format/formatRunStart.js | 32 ++++++++++++------- test/api/runs.test.js | 2 +- .../usecases/run/GetAllRunsUseCase.test.js | 2 +- test/public/runs/detail.test.js | 7 ++++ test/public/runs/overview.test.js | 15 ++++++--- 11 files changed, 96 insertions(+), 45 deletions(-) rename lib/public/components/Filters/RunsFilter/{triggerValue.js => triggerValueFilter.js} (83%) create mode 100644 lib/public/domain/enums/TriggerValue.js diff --git a/lib/database/seeders/20200713103855-runs.js b/lib/database/seeders/20200713103855-runs.js index 066376b227..ab1df22841 100644 --- a/lib/database/seeders/20200713103855-runs.js +++ b/lib/database/seeders/20200713103855-runs.js @@ -2667,8 +2667,6 @@ module.exports = { run_number: 107, time_o2_start: '2019-08-08 13:00:00', time_o2_end: '2019-08-09 14:00:00', - time_trg_start: '2019-08-08 13:00:00', - time_trg_end: '2019-08-09 14:00:00', run_type_id: 12, run_quality: 'good', n_detectors: 15, @@ -2682,6 +2680,7 @@ module.exports = { fill_number: 1, epn_topology: 'a quite long topology, which will for sure require a balloon to be displayed properly', concatenated_detectors: 'ACO, CPV, CTP, EMC, FIT, HMP, ITS, MCH, MFT, MID, PHS, TOF, TPC, TRD, ZDC', + trigger_value: 'OFF', lhc_period_id: 2, lhc_beam_mode: 'UNSTABLE BEAMS', odc_topology_full_name: 'hash', diff --git a/lib/public/components/Filters/RunsFilter/triggerValue.js b/lib/public/components/Filters/RunsFilter/triggerValueFilter.js similarity index 83% rename from lib/public/components/Filters/RunsFilter/triggerValue.js rename to lib/public/components/Filters/RunsFilter/triggerValueFilter.js index fd0217a7aa..5addab02fe 100644 --- a/lib/public/components/Filters/RunsFilter/triggerValue.js +++ b/lib/public/components/Filters/RunsFilter/triggerValueFilter.js @@ -1,13 +1,12 @@ import { checkboxFilter } from '../common/filters/checkboxFilter.js'; - -const TRIGGER_VALUES = ['OFF', 'LTU', 'CTP']; +import { TRIGGER_VALUES } from '../../../domain/enums/TriggerValue.js'; /** * Returns a panel to be used by user to filter runs by trigger value * @param {RunsOverviewModel} runModel The global model object * @return {vnode} Multiple checkboxes for a user to select the values to be filtered. */ -const triggerValue = (runModel) => checkboxFilter( +export const triggerValueFilter = (runModel) => checkboxFilter( 'triggerValue', TRIGGER_VALUES, (value) => runModel.triggerValuesFilters.has(value), @@ -20,5 +19,3 @@ const triggerValue = (runModel) => checkboxFilter( runModel.triggerValuesFilters = Array.from(runModel.triggerValuesFilters); }, ); - -export default triggerValue; diff --git a/lib/public/domain/enums/TriggerValue.js b/lib/public/domain/enums/TriggerValue.js new file mode 100644 index 0000000000..c4749b2808 --- /dev/null +++ b/lib/public/domain/enums/TriggerValue.js @@ -0,0 +1,20 @@ +/** + * @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. + */ + +export const TriggerValue = Object.freeze({ + Off: 'OFF', + CTP: 'CTP', + LTU: 'LTU', +}); + +export const TRIGGER_VALUES = Object.values(TriggerValue); diff --git a/lib/public/views/Runs/ActiveColumns/runsActiveColumns.js b/lib/public/views/Runs/ActiveColumns/runsActiveColumns.js index ffa9fc89e5..aba953c908 100644 --- a/lib/public/views/Runs/ActiveColumns/runsActiveColumns.js +++ b/lib/public/views/Runs/ActiveColumns/runsActiveColumns.js @@ -31,7 +31,7 @@ import { displayRunDuration } from '../format/displayRunDuration.js'; import fillNumbersFilter from '../../../components/Filters/RunsFilter/fillNumbers.js'; import { frontLink } from '../../../components/common/navigation/frontLink.js'; import nEpnsFilter from '../../../components/Filters/RunsFilter/nEpns.js'; -import triggerValueFilter from '../../../components/Filters/RunsFilter/triggerValue.js'; +import { triggerValueFilter } from '../../../components/Filters/RunsFilter/triggerValueFilter.js'; import lhcPeriodsFilter from '../../../components/Filters/RunsFilter/lhcPeriod.js'; import { formatRunType } from '../../../utilities/formatting/formatRunType.js'; import definitionFilter from '../../../components/Filters/RunsFilter/definitionFilter.js'; diff --git a/lib/public/views/Runs/format/displayRunDuration.js b/lib/public/views/Runs/format/displayRunDuration.js index 36fa8c2724..f330f4b523 100644 --- a/lib/public/views/Runs/format/displayRunDuration.js +++ b/lib/public/views/Runs/format/displayRunDuration.js @@ -15,16 +15,16 @@ import { h, iconWarning } from '/js/src/index.js'; import { MAX_RUN_DURATION } from '../../../services/run/constants.mjs'; import { formatRunDuration } from '../../../utilities/formatting/formatRunDuration.mjs'; import { tooltip } from '../../../components/common/popover/tooltip.js'; +import { TriggerValue } from '../../../domain/enums/TriggerValue.js'; /** * Format the duration of a given run * - * @param {Object} run for which duration must be displayed - * + * @param {Run} run for which duration must be displayed * @return {string|vnode} the formatted duration */ export const displayRunDuration = (run) => { - const { runDuration, timeTrgStart, timeTrgEnd, timeO2Start, timeO2End } = run; + const { runDuration, timeTrgStart, timeTrgEnd, timeO2Start, timeO2End, triggerValue } = run; const formattedRunDuration = formatRunDuration(run); @@ -35,15 +35,18 @@ export const displayRunDuration = (run) => { const missingTimeTrgStart = timeTrgStart === null || timeTrgStart === undefined; const missingTimeTrgEnd = timeTrgEnd === null || timeTrgEnd === undefined; + // Run has ended if (timeTrgEnd || timeO2End) { let warningPopover = null; - if (missingTimeTrgStart && missingTimeTrgEnd) { - warningPopover = 'Duration based on o2 start AND stop because of missing trigger information'; - } else if (missingTimeTrgStart) { - warningPopover = 'Duration based on o2 start because of missing trigger start information'; - } else if (missingTimeTrgEnd) { - warningPopover = 'Duration based on o2 stop because of missing trigger stop information'; + if (triggerValue !== TriggerValue.Off) { + if (missingTimeTrgStart && missingTimeTrgEnd) { + warningPopover = 'Duration based on o2 start AND stop because of missing trigger information'; + } else if (missingTimeTrgStart) { + warningPopover = 'Duration based on o2 start because of missing trigger start information'; + } else if (missingTimeTrgEnd) { + warningPopover = 'Duration based on o2 stop because of missing trigger stop information'; + } } return h('.flex-row', h( @@ -52,6 +55,8 @@ export const displayRunDuration = (run) => { )); } + // Run is either running or lost + const timeStart = missingTimeTrgStart ? timeO2Start : timeTrgStart; let classes = 'success'; diff --git a/lib/public/views/Runs/format/formatRunEnd.js b/lib/public/views/Runs/format/formatRunEnd.js index 8a96d7cd99..8fa044570a 100644 --- a/lib/public/views/Runs/format/formatRunEnd.js +++ b/lib/public/views/Runs/format/formatRunEnd.js @@ -15,6 +15,7 @@ import { formatTimestamp } from '../../../utilities/formatting/formatTimestamp.j import { iconWarning, h } from '/js/src/index.js'; import { getLocaleDateAndTime } from '../../../utilities/dateUtils.js'; import { tooltip } from '../../../components/common/popover/tooltip.js'; +import { TriggerValue } from '../../../domain/enums/TriggerValue.js'; const MISSING_TRIGGER_STOP_WARNING = 'O2 stop is displayed because trigger stop is missing'; @@ -26,20 +27,27 @@ const MISSING_TRIGGER_STOP_WARNING = 'O2 stop is displayed because trigger stop * @return {Component} the formatted end date */ export const formatRunEnd = (run, inline) => { - if (run.timeTrgEnd) { - return formatTimestamp(run.timeTrgEnd, inline); + const { timeTrgEnd, timeO2End, triggerValue } = run; + + if (timeTrgEnd || triggerValue === TriggerValue.Off) { + return formatTimestamp(timeTrgEnd || timeO2End, inline); } - if (run.timeO2End) { - const { date, time } = getLocaleDateAndTime(run.timeO2End); - const content = inline - ? h('span', [ + + if (timeO2End) { + if (inline) { + return h('span', [ h('.flex-row.items-center.g2', [ - formatTimestamp(run.timeO2End, inline), + formatTimestamp(timeO2End, inline), tooltip(iconWarning(), MISSING_TRIGGER_STOP_WARNING), ]), - ]) - : h('', h('', date), h('.flex-row.g2.items-center', [h('', time), tooltip(iconWarning(), MISSING_TRIGGER_STOP_WARNING)])); - return content; + ]); + } else { + const { date, time } = getLocaleDateAndTime(timeO2End); + return h('', [ + h('', date), + h('.flex-row.g2.items-center', [h('', time), tooltip(iconWarning(), MISSING_TRIGGER_STOP_WARNING)]), + ]); + } } return '-'; }; diff --git a/lib/public/views/Runs/format/formatRunStart.js b/lib/public/views/Runs/format/formatRunStart.js index 70fe020c8f..8b826dfe8c 100644 --- a/lib/public/views/Runs/format/formatRunStart.js +++ b/lib/public/views/Runs/format/formatRunStart.js @@ -15,8 +15,9 @@ import { formatTimestamp } from '../../../utilities/formatting/formatTimestamp.j import { iconWarning, h } from '/js/src/index.js'; import { getLocaleDateAndTime } from '../../../utilities/dateUtils.js'; import { tooltip } from '../../../components/common/popover/tooltip.js'; +import { TriggerValue } from '../../../domain/enums/TriggerValue.js'; -const MISSING_TRIGGER_STOP_WARNING = 'O2 stop is displayed because trigger stop is missing'; +const MISSING_TRIGGER_START_WARNING = 'O2 start is displayed because trigger stop is missing'; /** * Format a given run's start date @@ -26,20 +27,27 @@ const MISSING_TRIGGER_STOP_WARNING = 'O2 stop is displayed because trigger stop * @return {Component} the formatted start date */ export const formatRunStart = (run, inline) => { - if (run.timeTrgStart) { - return formatTimestamp(run.timeTrgStart, inline); + const { timeO2Start, timeTrgStart, triggerValue } = run; + + if (timeTrgStart || triggerValue === TriggerValue.Off) { + return formatTimestamp(timeTrgStart || timeO2Start, inline); } - if (run.timeO2Start) { - const { date, time } = getLocaleDateAndTime(run.timeO2Start); - const content = inline - ? h('span', [ + + if (timeO2Start) { + if (inline) { + return h('span', [ h('.flex-row.items-center.g2', [ - formatTimestamp(run.timeO2Start, inline), - tooltip(iconWarning(), MISSING_TRIGGER_STOP_WARNING), + formatTimestamp(timeO2Start, inline), + tooltip(iconWarning(), MISSING_TRIGGER_START_WARNING), ]), - ]) - : h('', h('', date), h('.flex-row.g2.items-center', [h('', time), tooltip(iconWarning(), MISSING_TRIGGER_STOP_WARNING)])); - return content; + ]); + } else { + const { date, time } = getLocaleDateAndTime(timeO2Start); + return h('', [ + h('', date), + h('.flex-row.g2.items-center', [h('', time), tooltip(iconWarning(), MISSING_TRIGGER_START_WARNING)]), + ]); + } } return '-'; }; diff --git a/test/api/runs.test.js b/test/api/runs.test.js index 0f5162d1a0..ea6a363803 100644 --- a/test/api/runs.test.js +++ b/test/api/runs.test.js @@ -390,7 +390,7 @@ module.exports = () => { const { data } = response.body; - expect(data.length).to.equal(20); + expect(data.length).to.equal(21); }); it('should filter runs on the odc topology value', async () => { diff --git a/test/lib/usecases/run/GetAllRunsUseCase.test.js b/test/lib/usecases/run/GetAllRunsUseCase.test.js index bc9620ccd8..41cde3ec78 100644 --- a/test/lib/usecases/run/GetAllRunsUseCase.test.js +++ b/test/lib/usecases/run/GetAllRunsUseCase.test.js @@ -589,7 +589,7 @@ module.exports = () => { .execute(getAllRunsDto); expect(runs).to.be.an('array'); - expect(runs).to.have.lengthOf(20); + expect(runs).to.have.lengthOf(21); }); it('should successfully return an array, only containing runs found with lhc periods filter', async () => { getAllRunsDto.query = { diff --git a/test/public/runs/detail.test.js b/test/public/runs/detail.test.js index 73593ecfc5..d147827516 100644 --- a/test/public/runs/detail.test.js +++ b/test/public/runs/detail.test.js @@ -355,6 +355,13 @@ module.exports = () => { expect(await runDurationCell.evaluate((element) => element.innerText)).to.equal('25:00:00'); }); + it('should successfully display duration without warning popover when run has trigger OFF', async () => { + await goToPage(page, 'run-detail', { queryParameters: { id: 107 } }); + const runDurationCell = await page.$('#runDurationValue'); + expect(await runDurationCell.$('.popover-trigger')).to.be.null; + expect(await runDurationCell.evaluate((element) => element.innerText)).to.equal('25:00:00'); + }); + it('should successfully display UNKNOWN without warning popover when run last for more than 48 hours', async () => { await goToPage(page, 'run-detail', { queryParameters: { id: 105 } }); const runDurationCell = await page.$('#runDurationValue'); diff --git a/test/public/runs/overview.test.js b/test/public/runs/overview.test.js index 5ec0fc83a8..3ec1a101ff 100644 --- a/test/public/runs/overview.test.js +++ b/test/public/runs/overview.test.js @@ -668,7 +668,7 @@ module.exports = () => { * @param {string[]} authorizedRunQualities the list of valid run qualities * @return {void} */ - const checkTableRunQualities = async (rows, authorizedRunQualities) => { + const checkTableTriggerValue = async (rows, authorizedRunQualities) => { for (const row of rows) { expect(await row.evaluate((rowItem) => { const rowId = rowItem.id; @@ -686,12 +686,12 @@ module.exports = () => { table = await page.$$('tbody tr'); expect(table.length).to.equal(8); - await checkTableRunQualities(table, ['OFF']); + await checkTableTriggerValue(table, ['OFF']); await page.$eval(ltuFilterSelector, (element) => element.click()); await waitForTimeout(300); table = await page.$$('tbody tr'); - await checkTableRunQualities(table, ['OFF', 'LTU']); + await checkTableTriggerValue(table, ['OFF', 'LTU']); await page.$eval(ltuFilterSelector, (element) => element.click()); await waitForTimeout(300); @@ -699,7 +699,7 @@ module.exports = () => { expect(table.length).to.equal(8); - await checkTableRunQualities(table, ['OFF']); + await checkTableTriggerValue(table, ['OFF']); }); it('should successfully filter on a list of run numbers and inform the user about it', async () => { @@ -1181,6 +1181,13 @@ module.exports = () => { expect(urlParameters).to.contain(`fillNumber=${fillNumber}`); }); + it('should successfully display duration without warning popover when run has trigger OFF', async () => { + await goToPage(page, 'run-overview'); + const runDurationCell = await page.$('#row107-runDuration'); + expect(await runDurationCell.$('.popover-trigger')).to.be.null; + expect(await runDurationCell.evaluate((element) => element.innerText)).to.equal('25:00:00'); + }); + it('should successfully display duration without warning popover when run has both trigger start and stop', async () => { await goToPage(page, 'run-overview'); const runDurationCell = await page.$('#row106-runDuration'); From 4972474cc3aecd15fe686d15cefbaa1027fb9a03 Mon Sep 17 00:00:00 2001 From: Martin Boulais <31805063+martinboulais@users.noreply.github.com> Date: Thu, 25 Apr 2024 12:37:33 +0200 Subject: [PATCH 3/3] Release 0.86.0 (#1534) --- CHANGELOG.md | 11 +++++++++++ package-lock.json | 4 ++-- package.json | 2 +- 3 files changed, 14 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3c138667e7..d0e586409f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,17 @@ All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines. +## [0.86.0](https://github.com/AliceO2Group/Bookkeeping/releases/tag/%40aliceo2%2Fbookkeeping%400.86.0) +* Notable changes for users: + * Placed RCT entry point directly in navigation bar + * Changed QC flag delete button access to admins only + * Added runs counts for simulation pass overview + * Added data passes counts for simulation pass overview + * ALICE efficiency computation now uses mean weighted by stable beam duration + * Removed missing trigger start/stop warning if trigger is OFF +* Notable change for developers: + * Run optional properties are now optional in proto file + ## [0.85.0](https://github.com/AliceO2Group/Bookkeeping/releases/tag/%40aliceo2%2Fbookkeeping%400.85.0) * Notable changes for users: * Added possibility to filter out runs that contains any of the given tags diff --git a/package-lock.json b/package-lock.json index 29ac24d283..bc897c833b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@aliceo2/bookkeeping", - "version": "0.85.0", + "version": "0.86.0", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "@aliceo2/bookkeeping", - "version": "0.85.0", + "version": "0.86.0", "bundleDependencies": [ "@aliceo2/web-ui", "@grpc/grpc-js", diff --git a/package.json b/package.json index 7e6af1f63b..f7ef4e024f 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@aliceo2/bookkeeping", - "version": "0.85.0", + "version": "0.86.0", "author": "ALICEO2", "scripts": { "coverage": "nyc npm test && npm run coverage:report",