Skip to content
Open
Show file tree
Hide file tree
Changes from 39 commits
Commits
Show all changes
46 commits
Select commit Hold shift + click to select a range
057c235
[O2B-1502] Filter model setup boilerplate code.
Houwie7000 Nov 26, 2025
a7a9eda
[O2B-1502] Add filter button on LHC-fills overview page.
Houwie7000 Nov 26, 2025
2648f1c
[O2B-1502] Added stable beams only to filter
Houwie7000 Nov 26, 2025
094e6c5
[O2B-1502] Filtering with Stable Beams Only works, radioButton elemen…
Houwie7000 Nov 26, 2025
da7ff37
[O2B-1502] Doc fixes
Houwie7000 Nov 26, 2025
ee72512
[O2B-1502] Increase timeout of detailsForSimulationPass test. Local m…
Houwie7000 Nov 26, 2025
96a04c0
[O2B-1502] Potential fix for test failure.
Houwie7000 Nov 28, 2025
6fa4034
Revert "[O2B-1502] Potential fix for test failure."
Houwie7000 Dec 1, 2025
17ea048
Merge branch 'main' into feature/O2B-1502/filtering-panel-lhc-fills-f…
graduta Dec 5, 2025
695622b
[O2B-1502] Processed feedback
Houwie7000 Dec 8, 2025
87bee89
[O2B-1502] Git failed to detect rename. Ran: git mv RadioButton.js ra…
Houwie7000 Dec 8, 2025
5a18d9e
[O2B-1502] Added test import
Houwie7000 Dec 8, 2025
4c530ef
Revert "[O2B-1502] Processed feedback"
Houwie7000 Dec 10, 2025
51b50d9
[O2B-1502] Cherry pick previous feedback changes
Houwie7000 Dec 10, 2025
c0c8559
[O2B-1502] Integrated stable beam only filter into filtermodel.
Houwie7000 Dec 10, 2025
9934e56
[O2B-1502] fixed stable beam default value
Houwie7000 Dec 10, 2025
f247a6f
[O2B-1502] Fixed logic and type
Houwie7000 Dec 11, 2025
9b67281
[O2B-1502] Don't set any defaults in the filter as it will conflict w…
Houwie7000 Dec 11, 2025
ea0880f
[O2B-1502] Code cleanup
Houwie7000 Dec 11, 2025
46d4ae8
[O2B-1502] minor changes, processed feedback
Houwie7000 Dec 15, 2025
91e350c
[O2B-1502] Removed duplicate function due to override
Houwie7000 Dec 15, 2025
e95c847
[O2B-1503] Added front end fill number filter
Houwie7000 Nov 27, 2025
5077fec
[O2B-1503] fillNumbers work, todo ranges
Houwie7000 Nov 28, 2025
9130c87
[O2B-1503] ranges accepted by fill numbers filter
Houwie7000 Nov 28, 2025
0d0986e
[O2B-1503] Added/fixed test lhc-fill overview
Houwie7000 Nov 28, 2025
804cd4c
[O2B-1503] doc change
Houwie7000 Nov 28, 2025
2f5932a
[O2B-1503] JSDoc enhancements. Extracted duplicate functions to utils…
Houwie7000 Dec 15, 2025
1e3f503
[O2B-1503] placeholder text changed
Houwie7000 Dec 15, 2025
de7d95b
[O2B-1505] Added beam duration filter to frontend
Houwie7000 Nov 28, 2025
cafcba1
[O2B-1505] added simple UI test
Houwie7000 Nov 28, 2025
4c28a84
[O2B-1505] Filter+DTO work
Houwie7000 Dec 1, 2025
a34340e
[O2B-1505] Beam duration filter works, TODO testing
Houwie7000 Dec 1, 2025
9921652
[O2B-1505] tests added/improv
Houwie7000 Dec 2, 2025
1c2fffb
[O2B-1505] Fixed tests
Houwie7000 Dec 2, 2025
d40bd5c
[O2B-1505] Cleanup, remove logs, docs
Houwie7000 Dec 2, 2025
d3c1ead
[O2B-1505] Fixed test
Houwie7000 Dec 8, 2025
fe5f6c7
[O2B-1505] Doc fixes
Houwie7000 Dec 8, 2025
7628bca
[O2B-1505] remove getStableBeamsOnly
Houwie7000 Dec 8, 2025
a533088
[O2B-1505] Fixed 00:00:00 bug, added test
Houwie7000 Dec 16, 2025
fd055ca
Merge branch 'main' into feature/O2B-1503/lhcfills-fill-numbers-filter
Houwie7000 Dec 17, 2025
6a47048
[O2B-1505] Processed feedback
Houwie7000 Dec 17, 2025
8e82b34
[O2B-1503] Processed feedback, added tests
Houwie7000 Dec 18, 2025
e5bbc05
[O2B-1503] Added test for splitStringToStringsTrimmed()
Houwie7000 Dec 18, 2025
668f90e
Merge branch 'feature/O2B-1503/lhcfills-fill-numbers-filter' into fea…
Houwie7000 Dec 18, 2025
a047600
Merge branch 'main' into feature/O2B-1505/lhcfills-beam-duration-filter
Houwie7000 Dec 18, 2025
f113473
[O2B-1505] Remove old code
Houwie7000 Jan 5, 2026
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
9 changes: 9 additions & 0 deletions lib/domain/dtos/filters/LhcFillsFilterDto.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,16 @@
* or submit itself to any jurisdiction.
*/
const Joi = require('joi');
const { validateRange } = require('../../../utilities/rangeUtils');
const { validateTime } = require('../../../utilities/validateTime');

exports.LhcFillsFilterDto = Joi.object({
hasStableBeams: Joi.boolean(),
fillNumbers: Joi.string().trim().custom(validateRange).messages({
'any.invalid': '{{#message}}',
}),
beamDuration: Joi.string().trim().min(8).max(8).custom(validateTime).messages({
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could add here a pattern to match the timestamp format to clean up validate function.

'any.invalid': '{{#message}}',
}),
beamDurationOperator: Joi.string().trim().min(1).max(2),
});
30 changes: 1 addition & 29 deletions lib/domain/dtos/filters/RunFilterDto.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ const { IntegerComparisonDto, FloatComparisonDto } = require('./NumericalCompari
const { RUN_CALIBRATION_STATUS } = require('../../enums/RunCalibrationStatus.js');
const { RUN_DEFINITIONS } = require('../../enums/RunDefinition.js');
const { singleRunsCollectionCustomCheck } = require('../utils.js');
const { validateRange } = require('../../../utilities/rangeUtils.js');

const DetectorsFilterDto = Joi.object({
operator: Joi.string().valid('or', 'and', 'none').required(),
Expand All @@ -30,35 +31,6 @@ const EorReasonFilterDto = Joi.object({
description: Joi.string(),
});

/**
* Validates run numbers ranges to not exceed 100 runs
*
* @param {*} value The value to validate
* @param {*} helpers The helpers object
* @returns {Object} The value if validation passes
*/
const validateRange = (value, helpers) => {
const MAX_RANGE_SIZE = 100;

const runNumbers = value.split(',').map((runNumber) => runNumber.trim());

for (const runNumber of runNumbers) {
if (runNumber.includes('-')) {
const [start, end] = runNumber.split('-').map((n) => parseInt(n, 10));
if (Number.isNaN(start) || Number.isNaN(end) || start > end) {
return helpers.error('any.invalid', { message: `Invalid range: ${runNumber}` });
}
const rangeSize = end - start + 1;

if (rangeSize > MAX_RANGE_SIZE) {
return helpers.error('any.invalid', { message: `Given range exceeds max size of ${MAX_RANGE_SIZE} runs: ${runNumber}` });
}
}
}

return value;
};

exports.RunFilterDto = Joi.object({
runNumbers: Joi.string().trim().custom(validateRange).messages({
'any.invalid': '{{#message}}',
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
/**
* @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 { SelectionModel } from '../../common/selection/SelectionModel.js';

/**
* Stable beam filter model
* Holds true or false value
*/
export class StableBeamFilterModel extends SelectionModel {
/**
* Constructor
*/
constructor() {
super({ availableOptions: [{ value: true }, { value: false }],
defaultSelection: [{ value: false }],
multiple: false,
allowEmpty: false });
}

/**
* Returns true if the current filter is stable beams only
*
* @return {boolean} true if filter is stable beams only
*/
isStableBeamsOnly() {
return this.current;
}

/**
* Sets the current filter to stable beams only
*
* @param {boolean} value value to set this stable beams only filter with
* @return {void}
*/
setStableBeamsOnly(value) {
this.select({ value });
}

/**
* Get normalized selected option
*/
get normalized() {
return this.current;
}

/**
* Overrides SelectionModel.isEmpty to respect the fact that stable beam filter cannot be empty.
* @returns {boolean} true if the current value of the filter is false.
*/
get isEmpty() {
return this.current === false;
}

/**
* Reset the filter to default values
*
* @return {void}
*/
resetDefaults() {
if (!this.isEmpty) {
this.reset();
this.notify();
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
/**
* @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 beam duration
*
* @param {rawTextFilter} beamDurationFilterModel beamDurationFilterModel
* @param {string} beamDurationOperator beam duration operator value
* @param {(string) => undefined} beamDurationOperatorUpdate beam duration operator setter function
* @returns {Component} the text field
*/
export const beamDurationFilter = (beamDurationFilterModel, beamDurationOperator, beamDurationOperatorUpdate) => {
const amountFilter = rawTextFilter(
beamDurationFilterModel,
{ classes: ['w-100', 'beam-duration-filter'], placeholder: 'e.g 16:14:15 (HH:MM:SS)' },
);

return comparisonOperatorFilter(amountFilter, beamDurationOperator, (value) => beamDurationOperatorUpdate(value));
};
25 changes: 25 additions & 0 deletions lib/public/components/Filters/LhcFillsFilter/fillNumberFilter.js
Original file line number Diff line number Diff line change
@@ -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 fill number
*
* @param {RawTextFilterModel} filterModel the filter model
* @returns {Component} the text field
*/
export const fillNumberFilter = (filterModel) => rawTextFilter(
filterModel,
{ classes: ['w-100', 'fill-numbers-filter'], placeholder: 'e.g. 11392, 11383, 7625' },
);
49 changes: 49 additions & 0 deletions lib/public/components/Filters/LhcFillsFilter/stableBeamFilter.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
/**
* @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 { h } from '/js/src/index.js';
import { switchInput } from '../../common/form/switchInput.js';
import { radioButton } from '../../common/form/inputs/radioButton.js';

/**
* Display a toggle switch or radio buttons to filter stable beams only
*
* @param {StableBeamFilterModel} stableBeamFilterModel the stableBeamFilterModel
* @param {boolean} radioButtonMode define whether or not to return radio buttons or a switch.
* @returns {Component} the toggle switch
*/
export const toggleStableBeamOnlyFilter = (stableBeamFilterModel, radioButtonMode = false) => {
const name = 'stableBeamsOnlyRadio';
const labelOff = 'OFF';
const labelOn = 'ON';
if (radioButtonMode) {
return h('.form-group-header.flex-row.w-100', [
radioButton({
label: labelOff,
isChecked: !stableBeamFilterModel.isStableBeamsOnly(),
action: () => stableBeamFilterModel.setStableBeamsOnly(false),
name: name,
}),
radioButton({
label: labelOn,
isChecked: stableBeamFilterModel.isStableBeamsOnly(),
action: () => stableBeamFilterModel.setStableBeamsOnly(true),
name: name,
}),
]);
} else {
return switchInput(stableBeamFilterModel.isStableBeamsOnly(), (newState) => {
stableBeamFilterModel.setStableBeamsOnly(newState);
}, { labelAfter: 'STABLE BEAM ONLY' });
}
};
48 changes: 23 additions & 25 deletions lib/public/components/Filters/RunsFilter/dcs.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
* or submit itself to any jurisdiction.
*/

import { radioButton } from '../../common/form/inputs/radioButton.js';
import { h } from '/js/src/index.js';

/**
Expand All @@ -20,33 +21,30 @@ import { h } from '/js/src/index.js';
*/
const dcsOperationRadioButtons = (runModel) => {
const state = runModel.getDcsFilterOperation();
const name = 'dcsFilterRadio';
const labelAny = 'ANY';
const labelOff = 'OFF';
const labelOn = 'ON';
return h('.form-group-header.flex-row.w-100', [
radioButton('ANY', state === '', () => runModel.removeDcs()),
radioButton('OFF', state === false, () => runModel.setDcsFilterOperation(false)),
radioButton('ON', state === true, () => runModel.setDcsFilterOperation(true)),
radioButton({
label: labelAny,
isChecked: state === '',
action: () => runModel.removeDcs(),
name,
}),
radioButton({
label: labelOff,
isChecked: state === false,
action: () => runModel.setDcsFilterOperation(false),
name,
}),
radioButton({
label: labelOn,
isChecked: state === true,
action: () => runModel.setDcsFilterOperation(true),
name,
}),
]);
};

/**
* Build a radio button with its configuration and actions
* @param {string} label - label to be displayed to the user for radio button
* @param {boolean} isChecked - is radio button selected or not
* @param {Function} action - action to be followed on user click
* @return {vnode} - radio button with label associated
*/
const radioButton = (label, isChecked, action) => h('.w-33.form-check', [
h('input.form-check-input', {
onchange: action,
type: 'radio',
id: `dcsFilterRadio${label}`,
name: 'dcsFilterRadio',
value: label,
checked: isChecked,
}, ''),
h('label.form-check-label', {
style: 'cursor: pointer;',
for: `dcsFilterRadio${label}`,
}, label),
]);

export default dcsOperationRadioButtons;
48 changes: 23 additions & 25 deletions lib/public/components/Filters/RunsFilter/ddflp.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
* or submit itself to any jurisdiction.
*/

import { radioButton } from '../../common/form/inputs/radioButton.js';
import { h } from '/js/src/index.js';

/**
Expand All @@ -20,33 +21,30 @@ import { h } from '/js/src/index.js';
*/
const ddflpOperationRadioButtons = (runModel) => {
const state = runModel.getDdflpFilterOperation();
const name = 'ddFlpFilterRadio';
const labelAny = 'ANY';
const labelOff = 'OFF';
const labelOn = 'ON';
return h('.form-group-header.flex-row.w-100', [
radioButton('ANY', state === '', () => runModel.removeDdflp()),
radioButton('OFF', state === false, () => runModel.setDdflpFilterOperation(false)),
radioButton('ON', state === true, () => runModel.setDdflpFilterOperation(true)),
radioButton({
label: labelAny,
isChecked: state === '',
action: () => runModel.removeDdflp(),
name,
}),
radioButton({
label: labelOff,
isChecked: state === false,
action: () => runModel.setDdflpFilterOperation(false),
name,
}),
radioButton({
label: labelOn,
isChecked: state === true,
action: () => runModel.setDdflpFilterOperation(true),
name,
}),
]);
};

/**
* Build a radio button with its configuration and actions
* @param {string} label - label to be displayed to the user for radio button
* @param {boolean} isChecked - is radio button selected or not
* @param {Function} action - action to be followed on user click
* @return {vnode} - radio button with label associated
*/
const radioButton = (label, isChecked, action) => h('.w-33.form-check', [
h('input.form-check-input', {
onchange: action,
type: 'radio',
id: `ddFlpFilterRadio${label}`,
name: 'ddFlpFilterRadio',
value: label,
checked: isChecked,
}, ''),
h('label.form-check-label', {
style: 'cursor: pointer;',
for: `ddFlpFilterRadio${label}`,
}, label),
]);

export default ddflpOperationRadioButtons;
Loading
Loading