Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
2893d97
test: create useCaseTests
Feb 13, 2026
6c0248f
add stableBeamsStart and stableBeamsEnd to LhcFillsFilterDto
Feb 13, 2026
b3fa2ab
filter by stableBeamsStart stableBeamsEnd in getAllLhcFillsUseCase
Feb 13, 2026
a707327
chore: uncomment tests
Feb 16, 2026
12eab62
create formats for stablebeam
Feb 16, 2026
bced169
start on lhcFillsActiveColumn
Feb 16, 2026
b6c5fe5
improve format end
Feb 16, 2026
1d68269
add two submodels to lhcOverviewmodel
Feb 16, 2026
78d1800
set activefilterColumns
Feb 16, 2026
4454965
improve both formatters
Feb 16, 2026
c621005
remove stablebeam formatters at they aren't used
Feb 16, 2026
583f41f
move filters to existing columns
Feb 16, 2026
9f2cbfa
add tests for overview
Feb 16, 2026
1b02bd3
test: fix mis-spelling issue
Feb 17, 2026
49a2053
test: fix last and final test
Feb 17, 2026
4438e9a
Merge branch 'main' into feature/O2B-1530/LHC-fills-add-SB-duration-f…
NarrowsProjects Feb 17, 2026
b5fd961
Don't unnecesarily open popover filter in test
Feb 23, 2026
6f681d6
add api tests
Feb 23, 2026
b5d7e3d
Merge branch 'main' into feature/O2B-1530/LHC-fills-add-SB-duration-f…
NarrowsProjects Feb 23, 2026
12ffaf4
fix spelling problem in test name
Feb 23, 2026
a8a4237
Update lhcFills.test.js
NarrowsProjects Feb 23, 2026
1365c7b
chore: make the 'greater than' test actually test for greater than ra…
Feb 23, 2026
050a3ea
add greater than now tests
Feb 23, 2026
f1f91e5
use valueFrom and valueTo in url construction
Feb 23, 2026
47b2198
restore lost tests
Feb 23, 2026
099e39f
add incorrect format tests
Feb 23, 2026
37aaee3
remove skips
Feb 23, 2026
d17c21d
fix test name issue
Feb 23, 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
3 changes: 3 additions & 0 deletions lib/domain/dtos/filters/LhcFillsFilterDto.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ const Joi = require('joi');
const { validateRange, RANGE_INVALID } = require('../../../utilities/rangeUtils');
const { validateBeamTypes, BEAM_TYPE_INVALID } = require('../../../utilities/beamTypeUtils');
const { validateTimeDuration } = require('../../../utilities/validateTime');
const { FromToFilterDto } = require('./FromToFilterDto.js');

exports.LhcFillsFilterDto = Joi.object({
hasStableBeams: Joi.boolean(),
Expand All @@ -23,6 +24,8 @@ exports.LhcFillsFilterDto = Joi.object({
}),
runDuration: validateTimeDuration,
beamDuration: validateTimeDuration,
stableBeamsStart: FromToFilterDto,
stableBeamsEnd: FromToFilterDto,
schemeName: Joi.string().trim().max(64),
beamTypes: Joi.string()
.trim()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ import { fillNumberFilter } from '../../../components/Filters/LhcFillsFilter/fil
import { durationFilter } from '../../../components/Filters/LhcFillsFilter/durationFilter.js';
import { beamTypeFilter } from '../../../components/Filters/LhcFillsFilter/beamTypeFilter.js';
import { schemeNameFilter } from '../../../components/Filters/LhcFillsFilter/schemeNameFilter.js';
import { timeRangeFilter } from '../../../components/Filters/common/filters/timeRangeFilter.js';

/**
* List of active columns for a lhc fills table
Expand Down Expand Up @@ -65,6 +66,14 @@ export const lhcFillsActiveColumns = {
visible: true,
size: 'w-8',
format: (timestamp) => formatTimestamp(timestamp, false),

/**
* Stable Beam start filter component
*
* @param {RunsOverviewModel} lhcFillsOverviewModel the lhcFills overview model
* @return {Component} the filter component
*/
filter: (lhcFillsOverviewModel) => timeRangeFilter(lhcFillsOverviewModel.filteringModel.get('stableBeamsStart').timeRangeInputModel),
profiles: {
lhcFill: true,
environment: true,
Expand All @@ -80,6 +89,14 @@ export const lhcFillsActiveColumns = {
visible: true,
size: 'w-8',
format: (timestamp) => formatTimestamp(timestamp, false),

/**
* Stable Beam end filter component
*
* @param {LhcFillsOverviewModel} lhcFillsOverviewModel the lhcFills overview model
* @return {Component} the filter component
*/
filter: (lhcFillsOverviewModel) => timeRangeFilter(lhcFillsOverviewModel.filteringModel.get('stableBeamsEnd').timeRangeInputModel),
profiles: {
lhcFill: true,
environment: true,
Expand Down
3 changes: 3 additions & 0 deletions lib/public/views/LhcFills/Overview/LhcFillsOverviewModel.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import { OverviewPageModel } from '../../../models/OverviewModel.js';
import { addStatisticsToLhcFill } from '../../../services/lhcFill/addStatisticsToLhcFill.js';
import { BeamTypeFilterModel } from '../../../components/Filters/LhcFillsFilter/BeamTypeFilterModel.js';
import { TextComparisonFilterModel } from '../../../components/Filters/common/filters/TextComparisonFilterModel.js';
import { TimeRangeFilterModel } from '../../../components/Filters/RunsFilter/TimeRangeFilter.js';

/**
* Model for the LHC fills overview page
Expand All @@ -39,6 +40,8 @@ export class LhcFillsOverviewModel extends OverviewPageModel {
beamDuration: new TextComparisonFilterModel(),
runDuration: new TextComparisonFilterModel(),
hasStableBeams: new StableBeamFilterModel(),
stableBeamsStart: new TimeRangeFilterModel(),
stableBeamsEnd: new TimeRangeFilterModel(),
beamTypes: new BeamTypeFilterModel(),
schemeName: new RawTextFilterModel(),
});
Expand Down
14 changes: 13 additions & 1 deletion lib/usecases/lhcFill/GetAllLhcFillsUseCase.js
Original file line number Diff line number Diff line change
Expand Up @@ -47,12 +47,24 @@ class GetAllLhcFillsUseCase {
let associatedStatisticsRequired = false;

if (filter) {
const { hasStableBeams, fillNumbers, schemeName, beamDuration, runDuration, beamTypes } = filter;
const { hasStableBeams, fillNumbers, schemeName, beamDuration, stableBeamsStart, stableBeamsEnd, runDuration, beamTypes } = filter;
if (hasStableBeams) {
// For now, if a stableBeamsStart is present, then a beam is stable
queryBuilder.where('stableBeamsStart').not().is(null);
}

if (stableBeamsStart) {
const from = stableBeamsStart.from !== undefined ? stableBeamsStart.from : 0;
const to = stableBeamsStart.to !== undefined ? stableBeamsStart.to : new Date().getTime();
queryBuilder.where('stableBeamsStart').between(from, to);
}

if (stableBeamsEnd) {
const from = stableBeamsEnd.from !== undefined ? stableBeamsEnd.from : 0;
const to = stableBeamsEnd.to !== undefined ? stableBeamsEnd.to : new Date().getTime();
queryBuilder.where('stableBeamsEnd').between(from, to);
}

if (fillNumbers) {
const fillNumberCriteria = splitStringToStringsTrimmed(fillNumbers, SEARCH_ITEMS_SEPARATOR);

Expand Down
172 changes: 172 additions & 0 deletions test/api/lhcFills.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -503,6 +503,7 @@ module.exports = () => {
});
});


it('should return 200 and an LHCFill array for runs duration filter, > 03:00:00', (done) => {
request(server)
.get('/api/lhcFills?page[offset]=0&page[limit]=15&filter[runDuration][operator]=>&filter[runDuration][limit]=03:00:00')
Expand All @@ -519,6 +520,177 @@ module.exports = () => {
done();
});
});

it('should return 400 when stableBeamEnd filter "from" is greater than the current time', (done) => {
request(server)
.get('/api/lhcFills?page[offset]=0&page[limit]=15&filter[stableBeamsEnd][from]=2647867600000')
.expect(400)
.end((err, res) => {
if (err) {
done(err);
return;
}

const { errors: [error] } = res.body;
expect(error.title).to.equal('Invalid Attribute');
expect(error.detail).to.equal('"query.filter.stableBeamsEnd.from" must be less than "now"');
done()
});
});

it('should return 400 when stableBeamStart filter "from" is greater than the current time', (done) => {
request(server)
.get('/api/lhcFills?page[offset]=0&page[limit]=15&filter[stableBeamsStart][from]=2647867600000')
.expect(400)
.end((err, res) => {
if (err) {
done(err);
return;
}

const { errors: [error] } = res.body;
expect(error.title).to.equal('Invalid Attribute');
expect(error.detail).to.equal('"query.filter.stableBeamsStart.from" must be less than "now"');
done()
});
});

it('should return 400 when stableBeamEnd filter "from" is greater than "to"', (done) => {
request(server)
.get('/api/lhcFills?page[offset]=0&page[limit]=15&filter[stableBeamsEnd][from]=1647867699999&filter[stableBeamsEnd][to]=1647867600000')
.expect(400)
.end((err, res) => {
if (err) {
done(err);
return;
}

const { errors: [error] } = res.body;
expect(error.title).to.equal('Invalid Attribute');
expect(error.detail).to.equal('"query.filter.stableBeamsEnd.to" must be greater than "ref:from"');
done()
});
});

it('should return 400 when stableBeamStart filters are strings', (done) => {
request(server)
.get('/api/lhcFills?page[offset]=0&page[limit]=15&filter[stableBeamsStart][from]=bogus&filter[stableBeamsStart][to]=bogus')
.expect(400)
.end((err, res) => {
if (err) {
done(err);
return;
}

const { errors } = res.body;

expect(errors.map(e => e.detail)).to.have.members([
'"query.filter.stableBeamsStart.from" must be a valid date',
'"query.filter.stableBeamsStart.to" must be a valid date',
]);

expect(errors.every(e => e.title === 'Invalid Attribute')).to.be.true;
done()
});
});

it('should return 400 when stableBeamEnd filters are strings', (done) => {
request(server)
.get('/api/lhcFills?page[offset]=0&page[limit]=15&filter[stableBeamsEnd][from]=bogus&filter[stableBeamsEnd][to]=bogus')
.expect(400)
.end((err, res) => {
if (err) {
done(err);
return;
}

const { errors } = res.body;

expect(errors.map(e => e.detail)).to.have.members([
'"query.filter.stableBeamsEnd.from" must be a valid date',
'"query.filter.stableBeamsEnd.to" must be a valid date',
]);

expect(errors.every(e => e.title === 'Invalid Attribute')).to.be.true;
done()
});
});

it('should return 400 when stableBeamStart filter "from" is greater than "to"', (done) => {
request(server)
.get('/api/lhcFills?page[offset]=0&page[limit]=15&filter[stableBeamsStart][from]=1647867699999&filter[stableBeamsStart][to]=1647867600000')
.expect(400)
.end((err, res) => {
if (err) {
done(err);
return;
}

const { errors: [error] } = res.body;
expect(error.title).to.equal('Invalid Attribute');
expect(error.detail).to.equal('"query.filter.stableBeamsStart.to" must be greater than "ref:from"');
done()
});
});

it('should return 200 and a LHCFill array for only "from" filters set for stableBeamStart and end', (done) => {
const fromValue = 1647867600000;

request(server)
.get(`/api/lhcFills?page[offset]=0&page[limit]=15&filter[stableBeamsStart][from]=${fromValue}&filter[stableBeamsEnd][from]=${fromValue}`)
.expect(200)
.end((err, res) => {
if (err) {
done(err);
return;
}

expect(res.body.data).to.have.lengthOf(3);
res.body.data.forEach(fill => {
expect(fill.stableBeamsStart).to.be.at.least(fromValue);
expect(fill.stableBeamsEnd).to.be.at.least(fromValue);
});

done();
});
});

it('should return 200 and a LHCFill array for only "to" filters set for stableBeamStart and end', (done) => {
const toValue = 2000000000000;

request(server)
.get(`/api/lhcFills?page[offset]=0&page[limit]=15&filter[stableBeamsStart][to]=${toValue}&filter[stableBeamsEnd][to]=${toValue}`)
.expect(200)
.end((err, res) => {
if (err) {
done(err);
return;
}

expect(res.body.data).to.have.lengthOf(4);

res.body.data.forEach(fill => {
expect(fill.stableBeamsStart).to.be.at.most(toValue);
expect(fill.stableBeamsEnd).to.be.at.most(toValue);
});
done();
});
});

it('should return 200 and a LHCFill array for stableBeamStart and end filter set', (done) => {
request(server)
.get('/api/lhcFills?page[offset]=0&page[limit]=15&filter[stableBeamsStart][from]=1647867600000&filter[stableBeamsStart][to]=1647867600001&filter[stableBeamsEnd][from]=1647961200000&filter[stableBeamsEnd][to]=1647961200001')
.expect(200)
.end((err, res) => {
if (err) {
done(err);
return;
}

expect(res.body.data).to.have.lengthOf(3);
done();
});
});

it('should return 200 and an LHCFill array for beam types filter, correct', (done) => {
request(server)
Expand Down
56 changes: 56 additions & 0 deletions test/lib/usecases/lhcFill/GetAllLhcFillsUseCase.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -317,4 +317,60 @@ module.exports = () => {

expect(lhcFills).to.be.an('array').and.lengthOf(0)
})

it('should return an array with only \'from\' values given', async () => {
getAllLhcFillsDto.query = {
filter: {
stableBeamsStart: {
from: 1647867600000,
},
stableBeamsEnd: {
from: 1647867600000,
},
},
};

const { lhcFills } = await new GetAllLhcFillsUseCase().execute(getAllLhcFillsDto);

expect(lhcFills).to.be.an('array');
expect(lhcFills).to.have.lengthOf(3);
});

it('should return an array with only \'to\' values given', async () => {
getAllLhcFillsDto.query = {
filter: {
stableBeamsStart: {
to: 2000000000000
},
stableBeamsEnd: {
to: 2000000000000
},
},
};

const { lhcFills } = await new GetAllLhcFillsUseCase().execute(getAllLhcFillsDto);

expect(lhcFills).to.be.an('array');
expect(lhcFills).to.have.lengthOf(4);
});

it('should return an array with fills on certain timestamps', async () => {
getAllLhcFillsDto.query = {
filter: {
stableBeamsStart: {
from: 1647867600000,
to: 1647867600000,
},
stableBeamsEnd: {
from: 1647961200000,
to: 1647961200000,
},
},
};

const { lhcFills } = await new GetAllLhcFillsUseCase().execute(getAllLhcFillsDto);

expect(lhcFills).to.be.an('array');
expect(lhcFills).to.have.lengthOf(3);
});
};
Loading
Loading