Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions lib/domain/dtos/filters/LhcFillsFilterDto.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,10 @@ exports.LhcFillsFilterDto = Joi.object({
fillNumbers: Joi.string().trim().custom(validateRange).messages({
'any.invalid': '{{#message}}',
}),
runDuration: Joi.string().trim().min(8).max(8).custom(validateTime).messages({
'any.invalid': '{{#message}}',
}),
runDurationOperator: Joi.string().trim().min(1).max(2),
beamDuration: {
limit: Joi.string().trim().min(8).max(8).custom(validateTime).messages({
'any.invalid': '{{#message}}',
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
/**
* @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 { comparisonOperatorFilter } from '../common/filters/comparisonOperatorFilter.js';
import { rawTextFilter } from '../common/filters/rawTextFilter.js';

/**
* Component to filter LHC-fills by run duration
*
* @param {TextComparisonFilterModel} runDurationFilterModel runDurationFilterModel
* @returns {Component} the text field
*/
export const runDurationFilter = (runDurationFilterModel) => {
const amountFilter = rawTextFilter(
runDurationFilterModel.operandInputModel,
{ classes: ['w-100', 'run-duration-filter'], placeholder: 'e.g 16:14:15 (HH:MM:SS)' },
);

return comparisonOperatorFilter(amountFilter, runDurationFilterModel.operatorSelectionModel.value, (value) =>
runDurationFilterModel.operatorSelectionModel.select(value));
};
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import { frontLink } from '../../../components/common/navigation/frontLink.js';
import { toggleStableBeamOnlyFilter } from '../../../components/Filters/LhcFillsFilter/stableBeamFilter.js';
import { fillNumberFilter } from '../../../components/Filters/LhcFillsFilter/fillNumberFilter.js';
import { beamDurationFilter } from '../../../components/Filters/LhcFillsFilter/beamDurationFilter.js';
import { runDurationFilter } from '../../../components/Filters/LhcFillsFilter/runDurationFilter.js';

/**
* List of active columns for a lhc fills table
Expand Down Expand Up @@ -141,6 +142,7 @@ export const lhcFillsActiveColumns = {
visible: true,
size: 'w-8',
format: (duration) => formatDuration(duration),
filter: (lhcFillModel) => runDurationFilter(lhcFillModel.filteringModel.get('runDuration')),
},
efficiency: {
name: 'Fill Efficiency',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ export class LhcFillsOverviewModel extends OverviewPageModel {
this._filteringModel = new FilteringModel({
fillNumbers: new RawTextFilterModel(),
beamDuration: new TextComparisonFilterModel(),
runDuration: new TextComparisonFilterModel(),
hasStableBeams: new StableBeamFilterModel(),
});

Expand Down
18 changes: 17 additions & 1 deletion lib/usecases/lhcFill/GetAllLhcFillsUseCase.js
Original file line number Diff line number Diff line change
Expand Up @@ -44,8 +44,10 @@ class GetAllLhcFillsUseCase {

const queryBuilder = new QueryBuilder();

let associatedStatisticsRequired = false;

if (filter) {
const { hasStableBeams, fillNumbers, beamDuration } = filter;
const { hasStableBeams, fillNumbers, beamDuration, runDurationOperator, runDuration } = filter;
if (hasStableBeams) {
// For now, if a stableBeamsStart is present, then a beam is stable
queryBuilder.where('stableBeamsStart').not().is(null);
Expand All @@ -62,6 +64,15 @@ class GetAllLhcFillsUseCase {
: queryBuilder.where('fillNumber').oneOf(...finalFillnumberList);
}
}

// Run duration filter and corresponding operator.
if (runDuration !== null && runDuration !== undefined && runDurationOperator) {
associatedStatisticsRequired = true;
// 00:00:00 aka 0 value is saved in the DB as null
runDuration === 0 ? queryBuilder.whereAssociation('statistics', 'runsCoverage').applyOperator(runDurationOperator, null)
: queryBuilder.whereAssociation('statistics', 'runsCoverage').applyOperator(runDurationOperator, runDuration);
}

// Beam duration filter, limit and corresponding operator.
if (beamDuration?.limit !== undefined && beamDuration?.operator) {
const beamDurationLimit = Number(beamDuration.limit) === 0 ? null : beamDuration.limit;
Expand All @@ -75,6 +86,11 @@ class GetAllLhcFillsUseCase {
where: { definition: RunDefinition.PHYSICS },
required: false,
});
queryBuilder.include({
association: 'statistics',
required: associatedStatisticsRequired,
});

queryBuilder.orderBy('fillNumber', 'desc');
queryBuilder.limit(limit);
queryBuilder.offset(offset);
Expand Down
62 changes: 61 additions & 1 deletion test/lib/usecases/lhcFill/GetAllLhcFillsUseCase.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,6 @@ module.exports = () => {
})

// Beam duration filter tests

it('should only contain specified stable beam durations, < 12:00:00', async () => {
getAllLhcFillsDto.query = { filter: { beamDuration: {limit: '43200', operator: '<'} } };
const { lhcFills } = await new GetAllLhcFillsUseCase().execute(getAllLhcFillsDto);
Expand Down Expand Up @@ -160,4 +159,65 @@ module.exports = () => {
expect(lhcFill.stableBeamsDuration).equals(null)
});
})

it('should only contain specified total run duration, > 04:00:00', async () => {
getAllLhcFillsDto.query = { filter: { runDuration: '14400', runDurationOperator: '>' } };
const { lhcFills } = await new GetAllLhcFillsUseCase().execute(getAllLhcFillsDto)

expect(lhcFills).to.be.an('array').and.lengthOf(1)
lhcFills.forEach((lhcFill) => {
expect(lhcFill.statistics.runsCoverage).greaterThan(14400)
});
})

it('should only contain specified total run duration, >= 05:00:00', async () => {
getAllLhcFillsDto.query = { filter: { runDuration: '18000', runDurationOperator: '>=' } };
const { lhcFills } = await new GetAllLhcFillsUseCase().execute(getAllLhcFillsDto)

expect(lhcFills).to.be.an('array').and.lengthOf(1)
lhcFills.forEach((lhcFill) => {
expect(lhcFill.statistics.runsCoverage).greaterThan(18000)
});
})

it('should only contain specified total run duration, = 05:00:00', async () => {
getAllLhcFillsDto.query = { filter: { runDuration: '18000', runDurationOperator: '=' } };
const { lhcFills } = await new GetAllLhcFillsUseCase().execute(getAllLhcFillsDto)

expect(lhcFills).to.be.an('array').and.lengthOf(1)
lhcFills.forEach((lhcFill) => {
expect(lhcFill.statistics.runsCoverage).greaterThan(18000)
});
})

it('should only contain specified total run duration, = 00:00:00', async () => {
// Tests the usecase's ability to replace the request for 0 to a request for null.
getAllLhcFillsDto.query = { filter: { runDuration: 0, runDurationOperator: '=' } };
const { lhcFills } = await new GetAllLhcFillsUseCase().execute(getAllLhcFillsDto)

expect(lhcFills).to.be.an('array').and.lengthOf(4)
lhcFills.forEach((lhcFill) => {
expect(lhcFill.statistics.runsCoverage).equals(0)
});
})

it('should only contain specified total run duration, <= 05:00:00', async () => {
getAllLhcFillsDto.query = { filter: { runDuration: '18000', runDurationOperator: '<=' } };
const { lhcFills } = await new GetAllLhcFillsUseCase().execute(getAllLhcFillsDto)

expect(lhcFills).to.be.an('array').and.lengthOf(1)
lhcFills.forEach((lhcFill) => {
expect(lhcFill.statistics.runsCoverage).greaterThan(18000)
});
})

it('should only contain specified total run duration, < 06:30:59', async () => {
getAllLhcFillsDto.query = { filter: { runDuration: '23459', runDurationOperator: '<' } };
const { lhcFills } = await new GetAllLhcFillsUseCase().execute(getAllLhcFillsDto)

expect(lhcFills).to.be.an('array').and.lengthOf(1)
lhcFills.forEach((lhcFill) => {
expect(lhcFill.statistics.runsCoverage).greaterThan(23459)
});
})
};
6 changes: 5 additions & 1 deletion test/public/lhcFills/overview.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -270,7 +270,9 @@ module.exports = () => {
const filterSBExpect = { selector: '.stableBeams-filter .w-30', value: 'Stable Beams Only' };
const filterFillNRExpect = {selector: 'div.items-baseline:nth-child(1) > div:nth-child(1)', value: 'Fill #'}
const filterSBDurationExpect = {selector: 'div.items-baseline:nth-child(3) > div:nth-child(1)', value: 'SB Duration'}
const filterSBDurationPlaceholderExpect = {selector: 'input.w-100:nth-child(2)', value: 'e.g 16:14:15 (HH:MM:SS)'}
const filterSBDurationPlaceholderExpect = {selector: '.beam-duration-filter', value: 'e.g 16:14:15 (HH:MM:SS)'}
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)'}


await goToPage(page, 'lhc-fill-overview');
Expand All @@ -280,6 +282,8 @@ module.exports = () => {
await expectInnerText(page, filterFillNRExpect.selector, filterFillNRExpect.value);
await expectInnerText(page, filterSBDurationExpect.selector, filterSBDurationExpect.value);
await expectAttributeValue(page, filterSBDurationPlaceholderExpect.selector, 'placeholder', filterSBDurationPlaceholderExpect.value);
await expectInnerText(page, filterRunDurationExpect.selector, filterRunDurationExpect.value);
await expectAttributeValue(page, filterRunDurationPlaceholderExpect.selector, 'placeholder', filterRunDurationPlaceholderExpect.value);
});

it('should successfully un-apply Stable Beam filter menu', async () => {
Expand Down
Loading