From 75cd203f2f1617770c6162997e0d0edf6b60af1a Mon Sep 17 00:00:00 2001 From: Martin Boulais <31805063+martinboulais@users.noreply.github.com> Date: Sun, 29 Dec 2024 21:13:00 +0100 Subject: [PATCH] [O2B-532] Improve runs overview run definition filter --- .../RunsFilter/RunDefinitionFilterModel.js | 109 ++++++++++++++++++ ...nitionFilter.js => runDefinitionFilter.js} | 17 ++- .../Runs/ActiveColumns/runsActiveColumns.js | 11 +- .../views/Runs/Overview/RunsOverviewModel.js | 63 +--------- .../views/Runs/Overview/RunsOverviewPage.js | 14 +-- 5 files changed, 135 insertions(+), 79 deletions(-) create mode 100644 lib/public/components/Filters/RunsFilter/RunDefinitionFilterModel.js rename lib/public/components/Filters/RunsFilter/{definitionFilter.js => runDefinitionFilter.js} (59%) diff --git a/lib/public/components/Filters/RunsFilter/RunDefinitionFilterModel.js b/lib/public/components/Filters/RunsFilter/RunDefinitionFilterModel.js new file mode 100644 index 0000000000..dd5ee54cf9 --- /dev/null +++ b/lib/public/components/Filters/RunsFilter/RunDefinitionFilterModel.js @@ -0,0 +1,109 @@ +import { RunDefinition } from '../../../domain/enums/RunDefinition.js'; +import { FilterModel } from '../common/FilterModel.js'; + +/** + * Run definition filter model + */ +export class RunDefinitionFilterModel extends FilterModel { + /** + * Constructor + */ + constructor() { + super(); + this._definitions = []; + } + + // eslint-disable-next-line valid-jsdoc + /** + * @inheritDoc + */ + reset() { + this._definitions = []; + } + + // eslint-disable-next-line valid-jsdoc + /** + * @inheritDoc + */ + get isEmpty() { + return this._definitions.length === 0; + } + + // eslint-disable-next-line valid-jsdoc + /** + * @inheritDoc + */ + get normalized() { + return this._definitions.join(','); + } + + /** + * States if the given definition is currently in the run definition filter + * + * @param {string} definition the run definition to look for + * @return {boolean} true if the definition is included in the filter + */ + isDefinitionInFilter(definition) { + return this._definitions.includes(definition); + } + + /** + * Add a given definition in the current run definition filter if it is not already present + * + * @param {string} definition the run definition to add + * @return {void} + */ + addDefinition(definition) { + if (!this.isDefinitionInFilter(definition)) { + this._definitions.push(definition); + this.notify(); + } + } + + /** + * Remove a given definition from the current run definition filter if it is in it (else do nothing) + * + * @param {string} definition the definition to add + * @return {void} + */ + removeDefinition(definition) { + const originalLength = this._definitions._definitions; + this._definitions = this._definitions.filter((existingDefinition) => definition !== existingDefinition); + if (this._definitions.length !== originalLength) { + this.notify(); + } + } + + /** + * Sets the current filter to physics only + * + * @return {void} + */ + setPhysicsOnly() { + if (!this.isPhysicsOnly()) { + this._definitions = [RunDefinition.Physics]; + this.notify(); + } + } + + /** + * Returns true if the current filter is physics only + * + * @return {boolean} true if filter is physics only + */ + isPhysicsOnly() { + return this._definitions.length === 1 && this._definitions[0] === RunDefinition.Physics; + } + + /** + * Empty the current filter + * + * @return {void} + */ + setEmpty() { + if (!this.isEmpty) { + this.reset(); + this.notify(); + } + } +} diff --git a/lib/public/components/Filters/RunsFilter/definitionFilter.js b/lib/public/components/Filters/RunsFilter/runDefinitionFilter.js similarity index 59% rename from lib/public/components/Filters/RunsFilter/definitionFilter.js rename to lib/public/components/Filters/RunsFilter/runDefinitionFilter.js index f0ec8f01f5..79e4f9e3f6 100644 --- a/lib/public/components/Filters/RunsFilter/definitionFilter.js +++ b/lib/public/components/Filters/RunsFilter/runDefinitionFilter.js @@ -15,17 +15,16 @@ import { checkboxFilter } from '../common/filters/checkboxFilter.js'; import { RUN_DEFINITIONS } from '../../../domain/enums/RunDefinition.js'; /** - * Returns the definition filter component - * @param {RunsOverviewModel} runModel The run model - * @return {vnode} A list of checkboxes that lets the user look for runs with specific definition + * Renders a list of checkboxes that lets the user look for runs with specific definition + * + * @param {RunDefinitionFilterModel} runDefinitionFilterModel run definition filter model + * @return {Component} the filter */ -const definitionFilter = (runModel) => checkboxFilter( +export const runDefinitionFilter = (runDefinitionFilterModel) => checkboxFilter( 'runDefinition', RUN_DEFINITIONS, - (runQuality) => runModel.isDefinitionInFilter(runQuality), + (runDefinition) => runDefinitionFilterModel.isDefinitionInFilter(runDefinition), (e, definition) => e.target.checked - ? runModel.addDefinitionFilter(definition) - : runModel.removeDefinitionFilter(definition), + ? runDefinitionFilterModel.addDefinition(definition) + : runDefinitionFilterModel.removeDefinition(definition), ); - -export default definitionFilter; diff --git a/lib/public/views/Runs/ActiveColumns/runsActiveColumns.js b/lib/public/views/Runs/ActiveColumns/runsActiveColumns.js index e63251955f..c25c661122 100644 --- a/lib/public/views/Runs/ActiveColumns/runsActiveColumns.js +++ b/lib/public/views/Runs/ActiveColumns/runsActiveColumns.js @@ -31,7 +31,7 @@ import nEpnsFilter from '../../../components/Filters/RunsFilter/nEpns.js'; import { triggerValueFilter } from '../../../components/Filters/RunsFilter/triggerValueFilter.js'; import lhcPeriodsFilter from '../../../components/Filters/RunsFilter/lhcPeriod.js'; import { formatRunType } from '../../../utilities/formatting/formatRunType.js'; -import definitionFilter from '../../../components/Filters/RunsFilter/definitionFilter.js'; +import { runDefinitionFilter } from '../../../components/Filters/RunsFilter/runDefinitionFilter.js'; import { profiles } from '../../../components/common/table/profiles.js'; import { formatDuration } from '../../../utilities/formatting/formatDuration.mjs'; import { formatRunStart } from '../format/formatRunStart.js'; @@ -326,7 +326,14 @@ export const runsActiveColumns = { } return h('.flex-column.items-start', lines); }, - filter: definitionFilter, + + /** + * Run definition filter component + * + * @param {RunsOverviewModel} runsOverviewModel the runs overview model + * @return {Component} the filter component + */ + filter: (runsOverviewModel) => runDefinitionFilter(runsOverviewModel.filteringModel.get('definitions')), }, runDuration: { name: 'Duration', diff --git a/lib/public/views/Runs/Overview/RunsOverviewModel.js b/lib/public/views/Runs/Overview/RunsOverviewModel.js index 0e3f8b6631..2ad4076d3a 100644 --- a/lib/public/views/Runs/Overview/RunsOverviewModel.js +++ b/lib/public/views/Runs/Overview/RunsOverviewModel.js @@ -29,6 +29,7 @@ import { FilteringModel } from '../../../components/Filters/common/FilteringMode import { buildUrl } from '../../../utilities/fetch/buildUrl.js'; import { TimeRangeFilterModel } from '../../../components/Filters/RunsFilter/TimeRangeFilter.js'; import { RawTextFilterModel } from '../../../components/Filters/common/filters/RawTextFilterModel.js'; +import { RunDefinitionFilterModel } from '../../../components/Filters/RunsFilter/RunDefinitionFilterModel.js'; /** * Model representing handlers for runs page @@ -53,6 +54,7 @@ export class RunsOverviewModel extends OverviewPageModel { ]), o2start: new TimeRangeFilterModel(), o2end: new TimeRangeFilterModel(), + definitions: new RunDefinitionFilterModel(), runTypes: new RunTypesFilterModel(), eorReason: new EorReasonFilterModel(), magnets: new MagnetsFilteringModel(), @@ -160,8 +162,6 @@ export class RunsOverviewModel extends OverviewPageModel { resetFiltering(fetch = true) { this._filteringModel.reset(); - this._runDefinitionFilter = []; - this._fillNumbersFilter = ''; this._runDurationFilter = null; @@ -199,7 +199,6 @@ export class RunsOverviewModel extends OverviewPageModel { */ isAnyFilterActive() { return this._filteringModel.isAnyFilterActive() - || this._runDefinitionFilter.length > 0 || this._fillNumbersFilter !== '' || this._runDurationFilter !== null || this._lhcPeriodsFilter !== null @@ -247,61 +246,6 @@ export class RunsOverviewModel extends OverviewPageModel { this.notify(); } - /** - * States if the given definition is currently in the run definition filter, and it's the only one - * - * @param {string} definition the run definition to look for - * @return {boolean} true if the definition is the only one currently applied - */ - isDefinitionOnlyOneInFilter(definition) { - return this._runDefinitionFilter.length === 1 && this._runDefinitionFilter[0] === definition; - } - - /** - * States if the given definition is currently in the run definition filter - * - * @param {string} definition the run definition to look for - * @return {boolean} true if the definition is included in the filter - */ - isDefinitionInFilter(definition) { - return this._runDefinitionFilter.includes(definition); - } - - /** - * Add a given definition in the current run definition filter if it is not already present, then refresh runs list - * - * @param {string} definition the run definition to add - * @return {void} - */ - addDefinitionFilter(definition) { - if (!this.isDefinitionInFilter(definition)) { - this._runDefinitionFilter.push(definition); - this._applyFilters(); - } - } - - /** - * Remove a given definition from the current run definition filter if it is in it (else do nothing) then refresh runs list - * - * @param {string} definition the definition to add - * @return {void} - */ - removeDefinitionFilter(definition) { - this._runDefinitionFilter = this._runDefinitionFilter.filter((existingDefinition) => definition !== existingDefinition); - this._applyFilters(); - } - - /** - * Set the list of definition to be used as the current run definition filter - * - * @param {string[]} definitions the new definition filter - * @return {void} - */ - setDefinitionFilter(definitions) { - this._runDefinitionFilter = [...definitions]; - this._applyFilters(); - } - /** * Return the currently applied fill number filter * @@ -631,9 +575,6 @@ export class RunsOverviewModel extends OverviewPageModel { ...this.runFilterValues && { 'filter[runNumbers]': this.runFilterValues, }, - ...this._runDefinitionFilter.length > 0 && { - 'filter[definitions]': this._runDefinitionFilter.join(','), - }, ...this._fillNumbersFilter && { 'filter[fillNumbers]': this._fillNumbersFilter, }, diff --git a/lib/public/views/Runs/Overview/RunsOverviewPage.js b/lib/public/views/Runs/Overview/RunsOverviewPage.js index 24ff126331..495853fbda 100644 --- a/lib/public/views/Runs/Overview/RunsOverviewPage.js +++ b/lib/public/views/Runs/Overview/RunsOverviewPage.js @@ -20,7 +20,6 @@ import { runsActiveColumns } from '../ActiveColumns/runsActiveColumns.js'; import { table } from '../../../components/common/table/table.js'; import { runNumberFilter } from '../../../components/Filters/RunsFilter/runNumberFilter.js'; import { switchInput } from '../../../components/common/form/switchInput.js'; -import { RunDefinition } from '../../../domain/enums/RunDefinition.js'; const TABLEROW_HEIGHT = 59; // Estimate of the navbar and pagination elements height total; Needs to be updated in case of changes; @@ -29,14 +28,15 @@ const PAGE_USED_HEIGHT = 215; /** * Display a toggle switch to display physics runs only * - * @param {RunsOverviewModel} runsOverviewModel the model of the runs overview + * @param {RunDefinitionFilterModel} runDefinitionFilterModel the run definition filter model * @returns {Component} the toggle switch */ -export const togglePhysicsOnlyFilter = (runsOverviewModel) => { - const isPhysicsOnly = runsOverviewModel.isDefinitionOnlyOneInFilter(RunDefinition.Physics); +export const togglePhysicsOnlyFilter = (runDefinitionFilterModel) => { + const isPhysicsOnly = runDefinitionFilterModel.isPhysicsOnly(); const onChange = isPhysicsOnly - ? () => runsOverviewModel.setDefinitionFilter([]) - : () => runsOverviewModel.setDefinitionFilter([RunDefinition.Physics]); + ? () => runDefinitionFilterModel.setEmpty() + : () => runDefinitionFilterModel.setPhysicsOnly(); + return switchInput(isPhysicsOnly, onChange, { labelAfter: 'PHYSICS ONLY' }); }; @@ -55,7 +55,7 @@ export const RunsOverviewPage = ({ runs: { overviewModel: runsOverviewModel }, m h('.flex-row.header-container.g2.pv2', [ filtersPanelPopover(runsOverviewModel, runsActiveColumns), h('.pl2#runOverviewFilter', runNumberFilter(runsOverviewModel.filteringModel.get('runNumber'))), - togglePhysicsOnlyFilter(runsOverviewModel), + togglePhysicsOnlyFilter(runsOverviewModel.filteringModel.get('definitions')), exportRunsTriggerAndModal(runsOverviewModel, modalModel), ]), h('.flex-column.w-100', [