From 98e3701d88a070b035945d39d76ecb259b9be4aa Mon Sep 17 00:00:00 2001 From: Jasper Houweling Date: Wed, 10 Dec 2025 11:09:16 +0100 Subject: [PATCH 1/5] [O2B-1509] Filtering by scheme name possible --- lib/domain/dtos/filters/LhcFillsFilterDto.js | 1 + .../LhcFillsFilter/schemeNameFilter.js | 25 +++++++++++++++++++ .../ActiveColumns/lhcFillsActiveColumns.js | 2 ++ .../Overview/LhcFillsOverviewModel.js | 1 + lib/usecases/lhcFill/GetAllLhcFillsUseCase.js | 7 +++++- 5 files changed, 35 insertions(+), 1 deletion(-) create mode 100644 lib/public/components/Filters/LhcFillsFilter/schemeNameFilter.js diff --git a/lib/domain/dtos/filters/LhcFillsFilterDto.js b/lib/domain/dtos/filters/LhcFillsFilterDto.js index 2942844758..b21ae09255 100644 --- a/lib/domain/dtos/filters/LhcFillsFilterDto.js +++ b/lib/domain/dtos/filters/LhcFillsFilterDto.js @@ -28,4 +28,5 @@ exports.LhcFillsFilterDto = Joi.object({ }), runDurationOperator: Joi.string().trim().min(1).max(2), beamsType: Joi.string(), + schemeName: Joi.string().trim(), }); diff --git a/lib/public/components/Filters/LhcFillsFilter/schemeNameFilter.js b/lib/public/components/Filters/LhcFillsFilter/schemeNameFilter.js new file mode 100644 index 0000000000..a4b8dfb643 --- /dev/null +++ b/lib/public/components/Filters/LhcFillsFilter/schemeNameFilter.js @@ -0,0 +1,25 @@ +/** + * @license + * Copyright CERN and copyright holders of ALICE Trg. 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-Trg.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 { rawTextFilter } from '../common/filters/rawTextFilter.js'; + +/** + * Component to filter LHC-fills by scheme name + * + * @param {RawTextFilterModel} filterModel the filter model + * @returns {Component} the text field + */ +export const schemeNameFilter = (filterModel) => rawTextFilter( + filterModel, + { classes: ['w-100', 'scheme-name-filter'], placeholder: 'e.g. Single_12b_8_1024_8_2018' }, +); diff --git a/lib/public/views/LhcFills/ActiveColumns/lhcFillsActiveColumns.js b/lib/public/views/LhcFills/ActiveColumns/lhcFillsActiveColumns.js index 897b407d13..6ad8935c48 100644 --- a/lib/public/views/LhcFills/ActiveColumns/lhcFillsActiveColumns.js +++ b/lib/public/views/LhcFills/ActiveColumns/lhcFillsActiveColumns.js @@ -28,6 +28,7 @@ import { fillNumberFilter } from '../../../components/Filters/LhcFillsFilter/fil import { beamDurationFilter } from '../../../components/Filters/LhcFillsFilter/beamDurationFilter.js'; import { runDurationFilter } from '../../../components/Filters/LhcFillsFilter/runDurationFilter.js'; import { beamsTypeFilter } from '../../../components/Filters/LhcFillsFilter/beamsTypeFilter.js'; +import { schemeNameFilter } from '../../../components/Filters/LhcFillsFilter/schemeNameFilter.js'; /** * List of active columns for a lhc fills table @@ -184,6 +185,7 @@ export const lhcFillsActiveColumns = { visible: true, size: 'w-10', format: (value) => value ? value : '-', + filter: (lhcFillModel) => schemeNameFilter(lhcFillModel.filteringModel.get('schemeName')), balloon: true, }, runs: { diff --git a/lib/public/views/LhcFills/Overview/LhcFillsOverviewModel.js b/lib/public/views/LhcFills/Overview/LhcFillsOverviewModel.js index 5689428c96..a3eeccc8d9 100644 --- a/lib/public/views/LhcFills/Overview/LhcFillsOverviewModel.js +++ b/lib/public/views/LhcFills/Overview/LhcFillsOverviewModel.js @@ -44,6 +44,7 @@ export class LhcFillsOverviewModel extends OverviewPageModel { runDuration: new RawTextFilterModel(), hasStableBeams: new StableBeamFilterModel(), beamsType: new BeamsTypeFilterModel(), + schemeName: new RawTextFilterModel(), }); this._beamDurationOperator = defaultBeamDurationOperator; diff --git a/lib/usecases/lhcFill/GetAllLhcFillsUseCase.js b/lib/usecases/lhcFill/GetAllLhcFillsUseCase.js index 958f07cbe2..abd78bcd0e 100644 --- a/lib/usecases/lhcFill/GetAllLhcFillsUseCase.js +++ b/lib/usecases/lhcFill/GetAllLhcFillsUseCase.js @@ -47,7 +47,7 @@ class GetAllLhcFillsUseCase { let associatedStatisticsRequired = false; if (filter) { - const { hasStableBeams, fillNumbers, beamDurationOperator, beamDuration, runDurationOperator, runDuration, beamsType } = filter; + const { hasStableBeams, fillNumbers, schemeName, beamDurationOperator, beamDuration, runDurationOperator, runDuration, beamsType } = filter; if (hasStableBeams) { // For now, if a stableBeamsStart is present, then a beam is stable queryBuilder.where('stableBeamsStart').not().is(null); @@ -64,6 +64,11 @@ class GetAllLhcFillsUseCase { } } + // Scheme name filter + if (schemeName) { + queryBuilder.where('filling_scheme_name').substring(schemeName); + } + // Run duration filter and corresponding operator. if (runDuration !== null && runDuration !== undefined && runDurationOperator) { associatedStatisticsRequired = true; From b239d29aad41c569ed57c1ffe3ac52bedc5f1f31 Mon Sep 17 00:00:00 2001 From: Jasper Houweling Date: Wed, 10 Dec 2025 12:25:30 +0100 Subject: [PATCH 2/5] [O2B-1509] Added tests, fixed existing tests --- .../lhcFill/GetAllLhcFillsUseCase.test.js | 34 ++++++++++++++++--- test/public/index.js | 28 +++++++-------- test/public/lhcFills/overview.test.js | 5 ++- 3 files changed, 47 insertions(+), 20 deletions(-) diff --git a/test/lib/usecases/lhcFill/GetAllLhcFillsUseCase.test.js b/test/lib/usecases/lhcFill/GetAllLhcFillsUseCase.test.js index c9284001f5..492864ed64 100644 --- a/test/lib/usecases/lhcFill/GetAllLhcFillsUseCase.test.js +++ b/test/lib/usecases/lhcFill/GetAllLhcFillsUseCase.test.js @@ -44,7 +44,7 @@ module.exports = () => { // Fill number filter tests it('should only contain specified fill number', async () => { - getAllLhcFillsDto.query = { filter: { hasStableBeams: true, fillNumbers: '6' } }; + getAllLhcFillsDto.query = { filter: { beamsMode: BeamModes.STABLE_BEAMS, fillNumbers: '6' } }; const { lhcFills } = await new GetAllLhcFillsUseCase().execute(getAllLhcFillsDto); expect(lhcFills).to.be.an('array').and.lengthOf(1) @@ -54,7 +54,7 @@ module.exports = () => { }) it('should only contain specified fill numbers', async () => { - getAllLhcFillsDto.query = { filter: { hasStableBeams: true, fillNumbers: '6,3' } }; + getAllLhcFillsDto.query = { filter: { beamsMode: BeamModes.STABLE_BEAMS, fillNumbers: '6,3' } }; const { lhcFills } = await new GetAllLhcFillsUseCase().execute(getAllLhcFillsDto); @@ -66,7 +66,7 @@ module.exports = () => { }) it('should only contain specified fill numbers, range', async () => { - getAllLhcFillsDto.query = { filter: { hasStableBeams: true, fillNumbers: '1-3,6' } }; + getAllLhcFillsDto.query = { filter: { beamsMode: BeamModes.STABLE_BEAMS, fillNumbers: '1-3,6' } }; const { lhcFills } = await new GetAllLhcFillsUseCase().execute(getAllLhcFillsDto); @@ -78,7 +78,7 @@ module.exports = () => { }) it('should only contain specified fill numbers, whitespace', async () => { - getAllLhcFillsDto.query = { filter: { hasStableBeams: true, fillNumbers: ' 6 , 3 ' } }; + getAllLhcFillsDto.query = { filter: { beamsMode: BeamModes.STABLE_BEAMS, fillNumbers: ' 6 , 3 ' } }; const { lhcFills } = await new GetAllLhcFillsUseCase().execute(getAllLhcFillsDto); @@ -90,7 +90,7 @@ module.exports = () => { }) it('should only contain specified fill numbers, comma misplacement', async () => { - getAllLhcFillsDto.query = { filter: { hasStableBeams: true, fillNumbers: ',6,3,' } }; + getAllLhcFillsDto.query = { filter: { beamsMode: BeamModes.STABLE_BEAMS, fillNumbers: ',6,3,' } }; const { lhcFills } = await new GetAllLhcFillsUseCase().execute(getAllLhcFillsDto); @@ -101,6 +101,30 @@ module.exports = () => { }); }) + it('should only contain matching scheme name, one precise', async () => { + getAllLhcFillsDto.query = { filter: { beamsMode: BeamModes.STABLE_BEAMS, schemeName: 'schemename' } }; + const { lhcFills } = await new GetAllLhcFillsUseCase().execute(getAllLhcFillsDto); + + + expect(lhcFills).to.be.an('array').and.lengthOf(3) + + lhcFills.forEach((lhcFill) => { + expect(lhcFill.fillingSchemeName).to.equal('schemename') + }); + }) + + it('should only contain matching scheme name, one partial', async () => { + getAllLhcFillsDto.query = { filter: { schemeName: '25ns_2352b_2340_2004_2133' } }; + const { lhcFills } = await new GetAllLhcFillsUseCase().execute(getAllLhcFillsDto); + + + expect(lhcFills).to.be.an('array').and.lengthOf(1) + + lhcFills.forEach((lhcFill) => { + expect(lhcFill.fillingSchemeName).to.equal('25ns_2352b_2340_2004_2133_108bpi_24inj') + }); + }) + // Beam duration filter tests it('should only contain specified stable beam durations, < 12:00:00', async () => { getAllLhcFillsDto.query = { filter: { beamDuration: '43200', beamDurationOperator: '<' } }; diff --git a/test/public/index.js b/test/public/index.js index ca57751ba9..62c9f54e62 100644 --- a/test/public/index.js +++ b/test/public/index.js @@ -28,19 +28,19 @@ const QcFlagTypesSuite = require('./qcFlagTypes'); const QcFlagsSuite = require('./qcFlags'); module.exports = () => { - describe('LhcPeriods', LhcPeriodsSuite); + // describe('LhcPeriods', LhcPeriodsSuite); describe('LhcFills', LhcFillsSuite); - describe('Logs', LogsSuite); - describe('Envs', EnvsSuite); - describe('Runs', RunsSuite); - describe('Tags', TagsSuite); - describe('Flps', FlpsSuite); - describe('Home', HomeSuite); - describe('About', AboutSuite); - describe('EosReport', EosReportSuite); - describe('DataPasses', DataPassesSuite); - describe('SimulationPasses', SimulationPassesSuite); - describe('QcFlagTypes', QcFlagTypesSuite); - describe('QcFlags', QcFlagsSuite); - describe('Error', ErrorSuite); + // describe('Logs', LogsSuite); + // describe('Envs', EnvsSuite); + // describe('Runs', RunsSuite); + // describe('Tags', TagsSuite); + // describe('Flps', FlpsSuite); + // describe('Home', HomeSuite); + // describe('About', AboutSuite); + // describe('EosReport', EosReportSuite); + // describe('DataPasses', DataPassesSuite); + // describe('SimulationPasses', SimulationPassesSuite); + // describe('QcFlagTypes', QcFlagTypesSuite); + // describe('QcFlags', QcFlagsSuite); + // describe('Error', ErrorSuite); }; diff --git a/test/public/lhcFills/overview.test.js b/test/public/lhcFills/overview.test.js index adea7f85fa..39db64559a 100644 --- a/test/public/lhcFills/overview.test.js +++ b/test/public/lhcFills/overview.test.js @@ -255,6 +255,7 @@ module.exports = () => { const meanRunDurationExpect = { selector: 'tbody tr:nth-child(1) td:nth-child(6)', value: '01:40:00' }; const totalRunsDurationExpect = { selector: 'tbody tr:nth-child(1) td:nth-child(7)', value: '05:00:00' }; const efficiencyExpect = { selector: 'tbody tr:nth-child(1) td:nth-child(8)', value: '41.67%' }; + const schemeNameExpect = { selector: '#row6-fillingSchemeName > div:nth-child(1) > div:nth-child(1)', value: 'Single_12b_8_1024_8_2018'}; await goToPage(page, 'lhc-fill-overview'); @@ -264,6 +265,7 @@ module.exports = () => { await expectInnerText(page, meanRunDurationExpect.selector, meanRunDurationExpect.value); await expectInnerText(page, totalRunsDurationExpect.selector, totalRunsDurationExpect.value); await expectInnerText(page, efficiencyExpect.selector, efficiencyExpect.value); + await expectInnerText(page, schemeNameExpect.selector, schemeNameExpect.value); }); it('should successfully display filter elements', async () => { @@ -274,7 +276,7 @@ module.exports = () => { const filterRunDurationExpect = {selector: 'div.flex-row:nth-child(4) > div:nth-child(1)', value: 'Total runs duration'} const filterRunDurationPlaceholderExpect = {selector: '.run-duration-filter', value: 'e.g 16:14:15 (HH:MM:SS)'} const filterBeamTypeExpect = {selector: 'div.flex-row:nth-child(5) > div:nth-child(1)', value: 'Beam Type'} - + const filterSchemeNamePlaceholderExpect = {selector: '.scheme-name-filter', value: 'e.g. Single_12b_8_1024_8_2018'} await goToPage(page, 'lhc-fill-overview'); // Open the filtering panel @@ -286,6 +288,7 @@ module.exports = () => { await expectInnerText(page, filterRunDurationExpect.selector, filterRunDurationExpect.value); await expectAttributeValue(page, filterRunDurationPlaceholderExpect.selector, 'placeholder', filterRunDurationPlaceholderExpect.value); await expectInnerText(page, filterBeamTypeExpect.selector, filterBeamTypeExpect.value); + await expectAttributeValue(page, filterSchemeNamePlaceholderExpect.selector, 'placeholder', filterSchemeNamePlaceholderExpect.value); }); it('should successfully un-apply Stable Beam filter menu', async () => { From 690dbdba8448fe2f6cacde729f9b2454ecc1093f Mon Sep 17 00:00:00 2001 From: Jasper Houweling Date: Tue, 16 Dec 2025 10:46:32 +0100 Subject: [PATCH 3/5] [O2B-1509] Linting --- lib/usecases/lhcFill/GetAllLhcFillsUseCase.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/usecases/lhcFill/GetAllLhcFillsUseCase.js b/lib/usecases/lhcFill/GetAllLhcFillsUseCase.js index abd78bcd0e..753f4afa35 100644 --- a/lib/usecases/lhcFill/GetAllLhcFillsUseCase.js +++ b/lib/usecases/lhcFill/GetAllLhcFillsUseCase.js @@ -47,7 +47,8 @@ class GetAllLhcFillsUseCase { let associatedStatisticsRequired = false; if (filter) { - const { hasStableBeams, fillNumbers, schemeName, beamDurationOperator, beamDuration, runDurationOperator, runDuration, beamsType } = filter; + const { hasStableBeams, fillNumbers, schemeName, beamDurationOperator, + beamDuration, runDurationOperator, runDuration, beamsType } = filter; if (hasStableBeams) { // For now, if a stableBeamsStart is present, then a beam is stable queryBuilder.where('stableBeamsStart').not().is(null); From 4a7fbdf9ffa0831b88b310d36f2f16a5aeb0af08 Mon Sep 17 00:00:00 2001 From: Jasper Houweling Date: Tue, 16 Dec 2025 13:51:00 +0100 Subject: [PATCH 4/5] [O2B-1509] Undo bad test parameter --- .../usecases/lhcFill/GetAllLhcFillsUseCase.test.js | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/test/lib/usecases/lhcFill/GetAllLhcFillsUseCase.test.js b/test/lib/usecases/lhcFill/GetAllLhcFillsUseCase.test.js index 492864ed64..883c77e07f 100644 --- a/test/lib/usecases/lhcFill/GetAllLhcFillsUseCase.test.js +++ b/test/lib/usecases/lhcFill/GetAllLhcFillsUseCase.test.js @@ -44,7 +44,7 @@ module.exports = () => { // Fill number filter tests it('should only contain specified fill number', async () => { - getAllLhcFillsDto.query = { filter: { beamsMode: BeamModes.STABLE_BEAMS, fillNumbers: '6' } }; + getAllLhcFillsDto.query = { filter: { hasStableBeams: true, fillNumbers: '6' } }; const { lhcFills } = await new GetAllLhcFillsUseCase().execute(getAllLhcFillsDto); expect(lhcFills).to.be.an('array').and.lengthOf(1) @@ -54,7 +54,7 @@ module.exports = () => { }) it('should only contain specified fill numbers', async () => { - getAllLhcFillsDto.query = { filter: { beamsMode: BeamModes.STABLE_BEAMS, fillNumbers: '6,3' } }; + getAllLhcFillsDto.query = { filter: { hasStableBeams: true, fillNumbers: '6,3' } }; const { lhcFills } = await new GetAllLhcFillsUseCase().execute(getAllLhcFillsDto); @@ -66,7 +66,7 @@ module.exports = () => { }) it('should only contain specified fill numbers, range', async () => { - getAllLhcFillsDto.query = { filter: { beamsMode: BeamModes.STABLE_BEAMS, fillNumbers: '1-3,6' } }; + getAllLhcFillsDto.query = { filter: { bhasStableBeams: true, fillNumbers: '1-3,6' } }; const { lhcFills } = await new GetAllLhcFillsUseCase().execute(getAllLhcFillsDto); @@ -78,7 +78,7 @@ module.exports = () => { }) it('should only contain specified fill numbers, whitespace', async () => { - getAllLhcFillsDto.query = { filter: { beamsMode: BeamModes.STABLE_BEAMS, fillNumbers: ' 6 , 3 ' } }; + getAllLhcFillsDto.query = { filter: { hasStableBeams: true, fillNumbers: ' 6 , 3 ' } }; const { lhcFills } = await new GetAllLhcFillsUseCase().execute(getAllLhcFillsDto); @@ -90,7 +90,7 @@ module.exports = () => { }) it('should only contain specified fill numbers, comma misplacement', async () => { - getAllLhcFillsDto.query = { filter: { beamsMode: BeamModes.STABLE_BEAMS, fillNumbers: ',6,3,' } }; + getAllLhcFillsDto.query = { filter: { hasStableBeams: true, fillNumbers: ',6,3,' } }; const { lhcFills } = await new GetAllLhcFillsUseCase().execute(getAllLhcFillsDto); @@ -102,7 +102,7 @@ module.exports = () => { }) it('should only contain matching scheme name, one precise', async () => { - getAllLhcFillsDto.query = { filter: { beamsMode: BeamModes.STABLE_BEAMS, schemeName: 'schemename' } }; + getAllLhcFillsDto.query = { filter: { hasStableBeams: true, schemeName: 'schemename' } }; const { lhcFills } = await new GetAllLhcFillsUseCase().execute(getAllLhcFillsDto); From 8d5afe3c8efee9778d33a844932cc046c8b76f83 Mon Sep 17 00:00:00 2001 From: Jasper Houweling Date: Tue, 16 Dec 2025 13:55:18 +0100 Subject: [PATCH 5/5] [O2B-1509] Undo wrongfully staged changes --- test/public/index.js | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/test/public/index.js b/test/public/index.js index 62c9f54e62..ca57751ba9 100644 --- a/test/public/index.js +++ b/test/public/index.js @@ -28,19 +28,19 @@ const QcFlagTypesSuite = require('./qcFlagTypes'); const QcFlagsSuite = require('./qcFlags'); module.exports = () => { - // describe('LhcPeriods', LhcPeriodsSuite); + describe('LhcPeriods', LhcPeriodsSuite); describe('LhcFills', LhcFillsSuite); - // describe('Logs', LogsSuite); - // describe('Envs', EnvsSuite); - // describe('Runs', RunsSuite); - // describe('Tags', TagsSuite); - // describe('Flps', FlpsSuite); - // describe('Home', HomeSuite); - // describe('About', AboutSuite); - // describe('EosReport', EosReportSuite); - // describe('DataPasses', DataPassesSuite); - // describe('SimulationPasses', SimulationPassesSuite); - // describe('QcFlagTypes', QcFlagTypesSuite); - // describe('QcFlags', QcFlagsSuite); - // describe('Error', ErrorSuite); + describe('Logs', LogsSuite); + describe('Envs', EnvsSuite); + describe('Runs', RunsSuite); + describe('Tags', TagsSuite); + describe('Flps', FlpsSuite); + describe('Home', HomeSuite); + describe('About', AboutSuite); + describe('EosReport', EosReportSuite); + describe('DataPasses', DataPassesSuite); + describe('SimulationPasses', SimulationPassesSuite); + describe('QcFlagTypes', QcFlagTypesSuite); + describe('QcFlags', QcFlagsSuite); + describe('Error', ErrorSuite); };