diff --git a/lib/domain/dtos/filters/LhcFillsFilterDto.js b/lib/domain/dtos/filters/LhcFillsFilterDto.js index ee53e64bf2..7513ee900a 100644 --- a/lib/domain/dtos/filters/LhcFillsFilterDto.js +++ b/lib/domain/dtos/filters/LhcFillsFilterDto.js @@ -23,4 +23,5 @@ exports.LhcFillsFilterDto = Joi.object({ runDuration: validateTimeDuration, beamDuration: validateTimeDuration, beamType: 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..7b644f382a --- /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'], 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 83cddcbe6e..941b37bf5d 100644 --- a/lib/public/views/LhcFills/ActiveColumns/lhcFillsActiveColumns.js +++ b/lib/public/views/LhcFills/ActiveColumns/lhcFillsActiveColumns.js @@ -27,6 +27,7 @@ import { toggleStableBeamOnlyFilter } from '../../../components/Filters/LhcFills import { fillNumberFilter } from '../../../components/Filters/LhcFillsFilter/fillNumberFilter.js'; import { durationFilter } from '../../../components/Filters/LhcFillsFilter/durationFilter.js'; import { beamTypeFilter } from '../../../components/Filters/LhcFillsFilter/beamTypeFilter.js'; +import { schemeNameFilter } from '../../../components/Filters/LhcFillsFilter/schemeNameFilter.js'; /** * List of active columns for a lhc fills table @@ -175,6 +176,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 e37e619076..246aa752b9 100644 --- a/lib/public/views/LhcFills/Overview/LhcFillsOverviewModel.js +++ b/lib/public/views/LhcFills/Overview/LhcFillsOverviewModel.js @@ -40,6 +40,7 @@ export class LhcFillsOverviewModel extends OverviewPageModel { runDuration: new TextComparisonFilterModel(), hasStableBeams: new StableBeamFilterModel(), beamType: new BeamTypeFilterModel(), + schemeName: new RawTextFilterModel(), }); this._filteringModel.observe(() => this._applyFilters()); diff --git a/lib/usecases/lhcFill/GetAllLhcFillsUseCase.js b/lib/usecases/lhcFill/GetAllLhcFillsUseCase.js index f7419a8669..bc7f77c2e2 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, beamDuration, runDuration, beamType } = filter; + const { hasStableBeams, fillNumbers, schemeName, beamDuration, runDuration, beamType } = filter; if (hasStableBeams) { // For now, if a stableBeamsStart is present, then a beam is stable queryBuilder.where('stableBeamsStart').not().is(null); @@ -65,6 +65,10 @@ class GetAllLhcFillsUseCase { } } + if (schemeName) { + queryBuilder.where('filling_scheme_name').substring(schemeName); + } + if (runDuration?.limit !== undefined && runDuration?.operator) { associatedStatisticsRequired = true; // 00:00:00 aka 0 value is saved in the DB as null (bookkeeping.fill_statistics.runs_coverage) @@ -81,7 +85,6 @@ class GetAllLhcFillsUseCase { } } - // Beam duration filter, limit and corresponding operator. if (beamDuration?.limit !== undefined && beamDuration?.operator) { queryBuilder.where('stableBeamsDuration').applyOperator(beamDuration.operator, beamDuration.limit); } diff --git a/test/api/lhcFills.test.js b/test/api/lhcFills.test.js index 85adfc612f..196d053bec 100644 --- a/test/api/lhcFills.test.js +++ b/test/api/lhcFills.test.js @@ -604,6 +604,7 @@ module.exports = () => { }); }); }); + describe('POST /api/lhcFills', () => { it('should return 201 if valid data is provided', async () => { const response = await request(server) diff --git a/test/lib/usecases/lhcFill/GetAllLhcFillsUseCase.test.js b/test/lib/usecases/lhcFill/GetAllLhcFillsUseCase.test.js index 7a2d1cfeb4..8bbcfa3fae 100644 --- a/test/lib/usecases/lhcFill/GetAllLhcFillsUseCase.test.js +++ b/test/lib/usecases/lhcFill/GetAllLhcFillsUseCase.test.js @@ -101,6 +101,28 @@ module.exports = () => { }); }) + it('should only contain matching scheme name, one precise', async () => { + getAllLhcFillsDto.query = { filter: { hasStableBeams: true, 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: {limit: '43200', operator: '<'} } }; diff --git a/test/public/lhcFills/overview.test.js b/test/public/lhcFills/overview.test.js index 29f98e13c4..2d1f72bb28 100644 --- a/test/public/lhcFills/overview.test.js +++ b/test/public/lhcFills/overview.test.js @@ -256,6 +256,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'); @@ -265,6 +266,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 () => { @@ -276,7 +278,7 @@ module.exports = () => { const filterRunDurationPlaceholderExpect = {selector: '#run-duration-filter-operand', value: 'e.g 16:14:15 (HH:MM:SS)'}; const filterSBDurationOperatorExpect = { value: true }; const filterBeamTypeExpect = {selector: 'div.flex-row:nth-child(5) > div:nth-child(1)', value: 'Beam Type'} - + const filterSchemeNamePlaceholderExpect = {selector: '.fillingSchemeName-filter input', value: 'e.g. Single_12b_8_1024_8_2018'} await goToPage(page, 'lhc-fill-overview'); // Open the filtering panel @@ -290,6 +292,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 () => { @@ -350,4 +353,14 @@ module.exports = () => { await pressElement(page, filterBeamTypePb_Pb); await waitForTableLength(page, 2); }); + + it('should successfully apply scheme name filter', async () => { + const filterSchemeNameInputField= '.fillingSchemeName-filter input'; + await goToPage(page, 'lhc-fill-overview'); + await waitForTableLength(page, 5); + + await openFilteringPanel(page); + await fillInput(page, filterSchemeNameInputField, 'Single_12b_8_1024_8_2018', ['change']); + await waitForTableLength(page, 1); + }); };