Skip to content
Open
Show file tree
Hide file tree
Changes from 8 commits
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
9d6f065
feat: add setFilterFromURL function to filteringModel
Apr 24, 2026
f6a0212
feat: mundane implementations of setFilterFromURL in OverviewModels
Apr 25, 2026
4058609
feat: implement setfilterFromURL for all runsOverview models
Apr 25, 2026
e253ed6
test: add tests for urlToFilter
Apr 27, 2026
72af509
undo faulty textFilter -> textInputFilter conversion
Apr 27, 2026
571ca62
fix eslint issues
Apr 27, 2026
4e22d71
feat: create filterLogger
May 20, 2026
d23795c
feat: add logs to all filterable overview endpoints
May 20, 2026
192fddd
fix: remove async from setFilterFromURL and improve readability
May 27, 2026
ceb2ced
chore: remove unneeded variable
May 27, 2026
ae2acca
chore: fix fillter getter from request
May 27, 2026
94a9057
chore: initialize FilterLogger with parenthesis
May 27, 2026
ee0dda9
test: uncomment a test suite
May 27, 2026
83c28cb
undo a textInputFilter migration
May 27, 2026
7df8afe
chore: undo filterlogger
May 27, 2026
7bcf905
feat: use replace history instead of pushHistory in FilteringModel
May 27, 2026
09483c4
chore: rename documentation to be more consistent with the rest of th…
May 27, 2026
cc6dc57
feat: reset filters if no filters are present in url
May 27, 2026
ba1ce7d
add test
May 27, 2026
9699f37
fix linting issues
May 27, 2026
7939594
uncomment test suites
May 27, 2026
a806dde
feat: update setFilterFromURL to receive a notify argument
May 28, 2026
19ae3f2
only notify once for rundefinitions filter
May 28, 2026
6b520a6
feat: attempt to fully move filter from url setting to RunModel
May 28, 2026
781bece
feat: addSetFilterFromURL functions to all overview models
May 28, 2026
b817c87
feat: call setFilterFromURL fromLogsModel
May 28, 2026
0401062
feat: move all setFilterFromURL calls entity model files
May 28, 2026
e88a2de
improve selectionModel normalize setter for allowing a different order
May 28, 2026
a092efd
textFilterModel migration.
May 28, 2026
c405d9f
feat: add isInactive getter to FilterModel and SelectionModel
Apr 30, 2026
1a3cbe4
feat: implement isInactive for ToggleFilterModel and MultiComposition…
Apr 30, 2026
0cc8d6a
feat: allow the stable beams only toggle to be toggled and untoggled …
May 28, 2026
87a5941
linter fixes
May 28, 2026
bb85b17
test: change input event type for textFilter in tests to input
Jun 1, 2026
0c42d0d
feat: improve NumvericalComparisonFilterModel setter.
Jun 3, 2026
b422ff3
test: extend filteringmodel tests
Jun 3, 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
24 changes: 24 additions & 0 deletions lib/public/components/Filters/common/FilteringModel.js
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,30 @@ export class FilteringModel extends Observable {
this.notify();
}

/**
* Look for parameters used for filtering in URL and apply them in the layout if it exists
* @returns {undefined}
*/
async setFilterFromURL() {
Comment thread
graduta marked this conversation as resolved.
Outdated
const { params: { page = '', filter = {} } } = this._router;

if (!(this._pageIdentifier === page)) {
Comment thread
graduta marked this conversation as resolved.
Outdated
return;
}

for (const [key, value] of Object.entries(filter)) {
const filterModel = this._filters[key];
Comment thread
graduta marked this conversation as resolved.
Outdated

if (!filterModel) {
continue;
}

filterModel.normalized = value;
}

this.notify();
}

/**
* Add new filter
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import { h } from '/js/src/index.js';
*/
export const eorReasonFilterComponent = (eorReasonFilterModel, eorReasonTypes) => {
const eorReasonsCategories = [...new Set(eorReasonTypes.map(({ category }) => category))];
const { category: currentCategory, title: currentTitle } = eorReasonFilterModel;

return [
h('.flex-row', [
Expand All @@ -36,7 +37,7 @@ export const eorReasonFilterComponent = (eorReasonFilterModel, eorReasonTypes) =
h('option', { selected: eorReasonFilterModel.category === '', value: '' }, '-'),
eorReasonsCategories.map((category, index) => h(
`option#eorCategory${index}`,
{ key: category, value: category },
{ key: category, value: category, selected: category === currentCategory },
category,
)),
],
Expand All @@ -54,7 +55,7 @@ export const eorReasonFilterComponent = (eorReasonFilterModel, eorReasonTypes) =
.filter((reason) => reason.category === eorReasonFilterModel.category)
.map(({ title }, index) => h(
`option#eorTitle${index}`,
{ key: title, value: title },
{ key: title, value: title, selected: title === currentTitle },
title || '(empty)',
)),
],
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ import { h } from '/js/src/index.js';
import { formatDataPassName } from '../format/formatDataPassName.js';
import { formatDataPassStatusHistory } from '../format/formatStatusHistory.js';
import { checkboxes } from '../../../components/Filters/common/filters/checkboxFilter.js';
import { textInputFilter } from '../../../components/Filters/common/filters/textInputFilter.js';
import { textFilter } from '../../../components/Filters/common/filters/textFilter.js';

/**
* List of active columns for a generic data passes table
Expand All @@ -35,7 +35,7 @@ export const dataPassesActiveColumns = {
visible: true,
sortable: true,
format: (_, dataPass) => formatDataPassName(dataPass),
filter: (filteringModel) => textInputFilter(filteringModel, 'names', 'e.g. LHC22a_apass1, ...', 'w-75'),
filter: (filteringModel) => textFilter(filteringModel.get('names'), { class: 'w-75 mt1', placeholder: 'e.g. LHC22a, lhc23b, ...' }),
balloon: true,
classes: 'w-20',
},
Expand Down
1 change: 1 addition & 0 deletions lib/public/views/DataPasses/DataPassesOverviewModel.js
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ export class DataPassesOverviewModel extends OverviewPageModel {
);

this._filteringModel.pageIdentifier = pageIdentifier;
this._filteringModel.setFilterFromURL();
this._filteringModel.visualChange$.bubbleTo(this);
this._filteringModel.observe(() => {
this._pagination.currentPage = 1;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,10 +51,10 @@ export class EnvironmentOverviewModel extends OverviewPageModel {
);

this._filteringModel.pageIdentifier = pageIdentifier;
this._filteringModel.setFilterFromURL();
this._filteringModel.observe(() => this._applyFilters(true));
this._filteringModel.visualChange$?.bubbleTo(this);

this.reset(false);
const updateDebounceTime = () => {
this._debouncedLoad = debounce(this.load.bind(this), model.inputDebounceTime);
};
Expand Down Expand Up @@ -92,7 +92,7 @@ export class EnvironmentOverviewModel extends OverviewPageModel {
/**
* Reset all filtering models
* @param {boolean} fetch Whether to refetch all data after filters have been reset
* @param {boolean} [clearUrl=false] if true filters will be removed from the url
* @param {boolean} resetUrl Whether to remove all the active filters from the urls
* @return {void}
*/
resetFiltering(fetch = true, clearUrl = false) {
Comment thread
graduta marked this conversation as resolved.
Expand Down
8 changes: 2 additions & 6 deletions lib/public/views/LhcFills/Overview/LhcFillsOverviewModel.js
Original file line number Diff line number Diff line change
Expand Up @@ -52,10 +52,9 @@ export class LhcFillsOverviewModel extends OverviewPageModel {
);

this._filteringModel.pageIdentifier = pageIdentifier;
this._filteringModel.setFilterFromURL();
this._filteringModel.observe(() => this._applyFilters());
this._filteringModel.visualChange$.bubbleTo(this);

this.reset(false);
}

/**
Expand All @@ -72,10 +71,7 @@ export class LhcFillsOverviewModel extends OverviewPageModel {
* @inheritDoc
*/
getRootEndpoint() {
const params = {
filter: this.filteringModel.normalized,
};
return buildUrl('/api/lhcFills', params);
return buildUrl('/api/lhcFills', { filter: this.filteringModel.normalized });
}

/**
Expand Down
26 changes: 13 additions & 13 deletions lib/public/views/Logs/Overview/LogsOverviewModel.js
Original file line number Diff line number Diff line change
Expand Up @@ -53,30 +53,30 @@ export class LogsOverviewModel extends Observable {
},
);

this._filteringModel.pageIdentifier = pageIdentifier;
this._overviewSortModel = new SortModel();
this._pagination = new PaginationModel();
const updateDebounceTime = () => {
this._debouncedFetchAllLogs = debounce(this.fetchLogs.bind(this), model.inputDebounceTime);
};

updateDebounceTime();
model.appConfiguration$.observe(() => updateDebounceTime());

// Filters
this.filteringModel.pageIdentifier = pageIdentifier;
excludeAnonymous && this._filteringModel.get('author').update('!Anonymous');
this._filteringModel.setFilterFromURL();
this._filteringModel.observe(() => this._applyFilters());
this._filteringModel.visualChange$.bubbleTo(this);

// Sub-models
this._overviewSortModel = new SortModel();
this._overviewSortModel.observe(() => this._applyFilters(true));
this._overviewSortModel.visualChange$.bubbleTo(this);

this._pagination = new PaginationModel();
this._pagination.observe(() => this.fetchLogs());
this._pagination.itemsPerPageSelector$.observe(() => this.notify());

this._logs = RemoteData.NotAsked();

const updateDebounceTime = () => {
this._debouncedFetchAllLogs = debounce(this.fetchLogs.bind(this), model.inputDebounceTime);
};
model.appConfiguration$.observe(() => updateDebounceTime());
updateDebounceTime();

excludeAnonymous && this._filteringModel.get('author').update('!Anonymous');

this.reset(false);
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ export class QcFlagTypesOverviewModel extends OverviewPageModel {
);

this._filteringModel.pageIdentifier = pageIdentifier;
this._filteringModel.setFilterFromURL();
this._filteringModel.observe(() => {
this._pagination.silentlySetCurrentPage(1);
this.load();
Expand Down
1 change: 0 additions & 1 deletion lib/public/views/Runs/Overview/RunsOverviewModel.js
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,6 @@ export class RunsOverviewModel extends OverviewPageModel {
this._filteringModel.observe(() => this._applyFilters(true));
this._filteringModel.visualChange$.bubbleTo(this);

this.reset(false);
const updateDebounceTime = () => {
this._debouncedLoad = debounce(this.load.bind(this), model.inputDebounceTime);
};
Expand Down
29 changes: 24 additions & 5 deletions lib/public/views/Runs/Overview/RunsWithQcModel.js
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,10 @@ export class RunsWithQcModel extends RunsOverviewModel {
constructor(model, pageIdentifier) {
super(model, pageIdentifier);

this._detectorsNotBadFractionRegistered = false;
this._detectorsForQcFlagRegistered = false;
this._qcSummaryObservableRegistered = false;
Comment thread
graduta marked this conversation as resolved.
Outdated

this._observablesQcFlagsSummaryDependsOn$ = null;
// This filter instance will be added as a sub-filter for a MultiCompositionFilter and a GaqFilter later.
this._mcReproducibleAsNotBad = new ToggleFilterModel();
Expand Down Expand Up @@ -145,9 +149,17 @@ export class RunsWithQcModel extends RunsOverviewModel {
Success: (detectors) => detectors.forEach(({ id }) =>
detectorsQcNotBadFraction.putFilter(`_${id}`, new NumericalComparisonFilterModel({ scale: 0.01, integer: false }))),
});

if (current?.isSuccess() && !this._detectorsNotBadFractionRegistered) {
this.filteringModel.setFilterFromURL();
this._detectorsNotBadFractionRegistered = true;
}
};
detectors$.observe(callback);
callback(detectors$);

if (!this._detectorsNotBadFractionRegistered) {
detectors$.observe(callback.bind(this));
callback(detectors$);
}
}

/**
Expand All @@ -161,6 +173,7 @@ export class RunsWithQcModel extends RunsOverviewModel {
const current = observableData.getCurrent();
current?.apply({
Success: (detectors) => {
this._detectorsForQcFlagRegistered = true;
this._exportModel.setDataExportConfiguration({
...baseDataExportConfiguration,
...qcFlagsExportConfigurationFactory(detectors),
Expand All @@ -169,9 +182,11 @@ export class RunsWithQcModel extends RunsOverviewModel {
Other: () => null,
});
};
detectors$.observe(callback);
// Also trigger immediately if detectors are already loaded
callback(detectors$);

if (!this._detectorsForQcFlagRegistered) {
detectors$.observe(callback.bind(this));
callback(detectors$);
}
}

/**
Expand All @@ -180,6 +195,10 @@ export class RunsWithQcModel extends RunsOverviewModel {
* @param {ObservableData<RemoteData<Detector>>} detectors$ observable data which QC flags fetching operation success depends on
*/
registerObservablesQcSummaryDependsOn(detectors$) {
if (detectors$ === this._observablesQcFlagsSummaryDependsOn$) {
return;
}

this._observablesQcFlagsSummaryDependsOn$ = detectors$;
const callback = (observableData) => {
const current = observableData.getCurrent();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,9 @@ export class RunsPerDataPassOverviewModel extends FixedPdpBeamTypeRunsOverviewMo
}))
.build();

this._filteringModel.put('gaq', new GaqFilterModel(this._mcReproducibleAsNotBad));
this._filteringModel.setFilterFromURL();

this._detectors$.bubbleTo(this);

this._markAsSkimmableRequestResult$ = new ObservableData(RemoteData.notAsked());
Expand All @@ -66,8 +69,6 @@ export class RunsPerDataPassOverviewModel extends FixedPdpBeamTypeRunsOverviewMo
this._skimmableRuns$ = new ObservableData(RemoteData.notAsked());
this._skimmableRuns$.bubbleTo(this);

this._filteringModel.put('gaq', new GaqFilterModel(this._mcReproducibleAsNotBad));

this._freezeOrUnfreezeActionState$ = new ObservableData(RemoteData.notAsked());
this._freezeOrUnfreezeActionState$.bubbleTo(this);

Expand Down Expand Up @@ -149,8 +150,8 @@ export class RunsPerDataPassOverviewModel extends FixedPdpBeamTypeRunsOverviewMo
/**
* @inheritdoc
*/
resetFiltering(fetch = true, clearUrl = false) {
super.resetFiltering(fetch, clearUrl);
resetFiltering(fetch = true, resetUrl = false) {
super.resetFiltering(fetch, resetUrl);
}

/**
Expand Down Expand Up @@ -272,7 +273,7 @@ export class RunsPerDataPassOverviewModel extends FixedPdpBeamTypeRunsOverviewMo
* @param {number} dataPassId id of Data Pass
*/
set dataPassId(dataPassId) {
if (dataPassId !== this._dataPassId) {
if (this._dataPassId && dataPassId !== this._dataPassId) {
Comment thread
graduta marked this conversation as resolved.
this.reset(false);
}
this._dataPassId = dataPassId;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ export class RunsPerLhcPeriodOverviewModel extends FixedPdpBeamTypeRunsOverviewM

this._tabbedPanelModel = new RunsPerLhcPeriodTabbedPanelModel(this._qcSummary$);
this._tabbedPanelModel.bubbleTo(this);
this._filteringModel.setFilterFromURL();
}

/**
Expand Down Expand Up @@ -96,13 +97,8 @@ export class RunsPerLhcPeriodOverviewModel extends FixedPdpBeamTypeRunsOverviewM
* @inheritdoc
*/
getRootEndpoint() {
return buildUrl(super.getRootEndpoint(), {
filter: {
lhcPeriodIds: [this._lhcPeriodId],
runQualities: 'good',
definitions: 'PHYSICS',
},
});
const filter = { lhcPeriodIds: [this._lhcPeriodId], runQualities: 'good', definitions: 'PHYSICS' };
return buildUrl(super.getRootEndpoint(), { filter });
}

/**
Expand Down Expand Up @@ -152,7 +148,7 @@ export class RunsPerLhcPeriodOverviewModel extends FixedPdpBeamTypeRunsOverviewM
* @param {string} lhcPeriodId id of a LHC period
*/
set lhcPeriodId(lhcPeriodId) {
if (lhcPeriodId !== this._lhcPeriodId) {
if (this._lhcPeriodId && lhcPeriodId !== this._lhcPeriodId) {
Comment thread
graduta marked this conversation as resolved.
this.reset(false);
}
this._lhcPeriodId = lhcPeriodId;
Expand Down
6 changes: 6 additions & 0 deletions lib/public/views/Runs/RunsModel.js
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,12 @@ export class RunsModel extends Observable {
loadOverview() {
if (! this._overviewModel.pagination.isInfiniteScrollEnabled) {
this._overviewModel.load();

/**
* This is done outside the constructor because the child classes need to set their filters after their filters are ready setting up.
* Putting it in the constructor would cause duplicate api calls
*/
this._overviewModel.filteringModel.setFilterFromURL();
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ export class RunsPerSimulationPassOverviewModel extends FixedPdpBeamTypeRunsOver

this._detectors$.bubbleTo(this);
this._simulationPass$.bubbleTo(this);
this._filteringModel.setFilterFromURL();
}

/**
Expand Down Expand Up @@ -75,21 +76,16 @@ export class RunsPerSimulationPassOverviewModel extends FixedPdpBeamTypeRunsOver
* @inheritdoc
*/
getRootEndpoint() {
const params = {
filter: {
simulationPassIds: [this._simulationPassId],
},
};

return buildUrl(super.getRootEndpoint(), params);
const filter = { simulationPassIds: [this._simulationPassId] };
return buildUrl(super.getRootEndpoint(), { filter });
}

/**
* Set id of current simulation pass which runs are fetched
* @param {number} simulationPassId simulation pass id
*/
set simulationPassId(simulationPassId) {
if (simulationPassId !== this._simulationPassId) {
if (this._simulationPassId && simulationPassId !== this._simulationPassId) {
Comment thread
graduta marked this conversation as resolved.
this.reset(false);
}
this._simulationPassId = simulationPassId;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ export class AnchoredSimulationPassesOverviewModel extends OverviewPageModel {
this._filteringModel = new FilteringModel(router, { names: new TextTokensFilterModel() });

this._filteringModel.pageIdentifier = pageIdentifier;
this._filteringModel.setFilterFromURL();
this._filteringModel.observe(() => {
this._pagination.silentlySetCurrentPage(1);
this.load();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ export class SimulationPassesPerLhcPeriodOverviewModel extends OverviewPageModel
this._filteringModel = new FilteringModel(router, { names: new TextTokensFilterModel() });

this._filteringModel.pageIdentifier = pageIdentifier;
this._filteringModel.setFilterFromURL();
this._filteringModel.visualChange$.bubbleTo(this);
this._filteringModel.observe(() => {
this._pagination.silentlySetCurrentPage(1);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ export class LhcPeriodsOverviewModel extends OverviewPageModel {
);

this._filteringModel.pageIdentifier = pageIdentifier;
this._filteringModel.setFilterFromURL();
this._filteringModel.visualChange$.bubbleTo(this);
this._filteringModel.observe(() => {
this._pagination.silentlySetCurrentPage(1);
Expand Down
Loading
Loading