From 8ec11aad750d2c48c311a7f66ad322da4082b2a0 Mon Sep 17 00:00:00 2001 From: NarrowsProjects Date: Wed, 29 Apr 2026 14:09:08 +0200 Subject: [PATCH 1/8] chore: add a url parameter to setFilterFromUrl --- .../Filters/common/FilteringModel.js | 32 +++++++++++++++++-- .../views/DataPasses/DataPassesModel.js | 4 +-- .../DataPasses/DataPassesOverviewModel.js | 2 +- .../views/Environments/EnvironmentModel.js | 2 +- .../Overview/EnvironmentOverviewModel.js | 2 +- lib/public/views/LhcFills/LhcFills.js | 2 +- .../Overview/LhcFillsOverviewModel.js | 2 +- lib/public/views/Logs/LogsModel.js | 2 +- .../views/Logs/Overview/LogsOverviewModel.js | 2 +- .../Overview/QcFlagTypesOverviewModel.js | 2 +- .../views/QcFlagTypes/QcFlagTypesModel.js | 2 +- .../views/Runs/Overview/RunsOverviewModel.js | 2 +- lib/public/views/Runs/RunsModel.js | 8 ++--- .../AnchoredSimulationPassesOverviewModel.js | 2 +- ...mulationPassesPerLhcPeriodOverviewModel.js | 2 +- .../SimulationPasses/SimulationPassesModel.js | 4 +-- .../views/lhcPeriods/LhcPeriodsModel.js | 2 +- .../Overview/LhcPeriodsOverviewModel.js | 2 +- 18 files changed, 52 insertions(+), 24 deletions(-) diff --git a/lib/public/components/Filters/common/FilteringModel.js b/lib/public/components/Filters/common/FilteringModel.js index 9cb4fd1d90..5b8b6b6aa3 100644 --- a/lib/public/components/Filters/common/FilteringModel.js +++ b/lib/public/components/Filters/common/FilteringModel.js @@ -14,7 +14,7 @@ import { expandQueryLikeNestedKey } from '../../../utilities/expandNestedKey.js'; import { SelectionModel } from '../../common/selection/SelectionModel.js'; import { FilterModel } from './FilterModel.js'; -import { buildUrl, Observable } from '/js/src/index.js'; +import { buildUrl, Observable, parseUrlParameters } from '/js/src/index.js'; /** * Model representing a filtering system, including filter inputs visibility, filters values and so on @@ -137,13 +137,37 @@ export class FilteringModel extends Observable { this.notify(); } + /** + * Compute seach parameters based a url or router + * + * @param {string|null} [url=null] the url that is to be parsed + * @returns {object} the serach parameters object + */ + _computeParameters(url = null) { + let params = {}; + + if (url) { + try { + params = parseUrlParameters(new URL(url).searchParams); + } catch (e) { + this._warnings.set('Unparseable URL', `URL could not be parsed. URL: ${url}`); + this.notify(); + } + } else { + params = this._router.params; + } + + return params; + } + /** * Look for parameters used for filtering in URL and apply them in the layout if it exists * * @param {boolean} notify if observers should be notified after setting the filters + * @param {string|null} [url=null] the url that is to be parsed into active filters * @returns {undefined} */ - setFilterFromURL(notify = false) { + setFilterFromURL(url = null, notify = false) { const { params: { page = '', filter } } = this._router; if (this._pageIdentifier === page) { @@ -186,6 +210,10 @@ export class FilteringModel extends Observable { } } + if (url) { + this._router.go(buildUrl('?', params), false, true); + } + if (notify) { this.notify(); } diff --git a/lib/public/views/DataPasses/DataPassesModel.js b/lib/public/views/DataPasses/DataPassesModel.js index 42fed10c3a..0ac1551358 100644 --- a/lib/public/views/DataPasses/DataPassesModel.js +++ b/lib/public/views/DataPasses/DataPassesModel.js @@ -40,7 +40,7 @@ export class DataPassesModel extends Observable { * @returns {void} */ loadPerLhcPeriodOverview({ lhcPeriodId }) { - this._perLhcPeriodOverviewModel.setFilterFromURL(false); + this._perLhcPeriodOverviewModel.setFilterFromUrl(null, false); this._perLhcPeriodOverviewModel.load({ lhcPeriodId }); } @@ -69,7 +69,7 @@ export class DataPassesModel extends Observable { */ loadPerSimulationPassOverview({ simulationPassId }) { this._perSimulationPassOverviewModel.simulationPassId = parseInt(simulationPassId, 10); - this._perSimulationPassOverviewModel.setFilterFromURL(false); + this._perSimulationPassOverviewModel.setFilterFromUrl(null, false); this._perSimulationPassOverviewModel.load(); } diff --git a/lib/public/views/DataPasses/DataPassesOverviewModel.js b/lib/public/views/DataPasses/DataPassesOverviewModel.js index 2834e1db1d..c7a690f6a0 100644 --- a/lib/public/views/DataPasses/DataPassesOverviewModel.js +++ b/lib/public/views/DataPasses/DataPassesOverviewModel.js @@ -61,7 +61,7 @@ export class DataPassesOverviewModel extends OverviewPageModel { * @param {boolean} notify if the FilteringModel should notify it's observers after finishing setting the filters */ setFilterFromURL(notify) { - this._filteringModel.setFilterFromURL(notify); + this._filteringModelsetFilterFromURL(null, notify); } /** diff --git a/lib/public/views/Environments/EnvironmentModel.js b/lib/public/views/Environments/EnvironmentModel.js index 1cc7fa484d..0e765df8fa 100644 --- a/lib/public/views/Environments/EnvironmentModel.js +++ b/lib/public/views/Environments/EnvironmentModel.js @@ -42,7 +42,7 @@ export class EnvironmentModel extends Observable { */ loadOverview() { if (!this._overviewModel.pagination.isInfiniteScrollEnabled) { - this._overviewModel.setFilterFromURL(false); + this._overviewModel.setFilterFromUrl(null, false); this._overviewModel.load(); } } diff --git a/lib/public/views/Environments/Overview/EnvironmentOverviewModel.js b/lib/public/views/Environments/Overview/EnvironmentOverviewModel.js index 5d6eb72cb3..1daa0025aa 100644 --- a/lib/public/views/Environments/Overview/EnvironmentOverviewModel.js +++ b/lib/public/views/Environments/Overview/EnvironmentOverviewModel.js @@ -76,7 +76,7 @@ export class EnvironmentOverviewModel extends OverviewPageModel { * @param {boolean} notify if the FilteringModel should notify it's observers after finishing setting the filters */ setFilterFromURL(notify) { - this._filteringModel.setFilterFromURL(notify); + this._filteringModelsetFilterFromURL(null, notify); } /** diff --git a/lib/public/views/LhcFills/LhcFills.js b/lib/public/views/LhcFills/LhcFills.js index a4343be26a..ea92a4ae03 100644 --- a/lib/public/views/LhcFills/LhcFills.js +++ b/lib/public/views/LhcFills/LhcFills.js @@ -42,7 +42,7 @@ export default class LhcFills extends Observable { * @returns {void} */ loadOverview() { - this._overviewModel.setFilterFromURL(false); + this._overviewModel.setFilterFromUrl(null, false); this._overviewModel.load(); } diff --git a/lib/public/views/LhcFills/Overview/LhcFillsOverviewModel.js b/lib/public/views/LhcFills/Overview/LhcFillsOverviewModel.js index 567182d3c5..8886126f36 100644 --- a/lib/public/views/LhcFills/Overview/LhcFillsOverviewModel.js +++ b/lib/public/views/LhcFills/Overview/LhcFillsOverviewModel.js @@ -80,7 +80,7 @@ export class LhcFillsOverviewModel extends OverviewPageModel { * @param {boolean} notify if the FilteringModel should notify it's observers after finishing setting the filters */ setFilterFromURL(notify) { - this._filteringModel.setFilterFromURL(notify); + this._filteringModelsetFilterFromURL(null, notify); } /** diff --git a/lib/public/views/Logs/LogsModel.js b/lib/public/views/Logs/LogsModel.js index 7822fa4d79..67c3d9062f 100644 --- a/lib/public/views/Logs/LogsModel.js +++ b/lib/public/views/Logs/LogsModel.js @@ -55,7 +55,7 @@ export class LogsModel extends Observable { */ loadOverview() { if (!this._overviewModel.pagination.isInfiniteScrollEnabled) { - this._overviewModel.setFilterFromURL(false); + this._overviewModel.setFilterFromUrl(null, false); this._overviewModel.fetchLogs(); } } diff --git a/lib/public/views/Logs/Overview/LogsOverviewModel.js b/lib/public/views/Logs/Overview/LogsOverviewModel.js index f6fcb01638..f1a89ebb0d 100644 --- a/lib/public/views/Logs/Overview/LogsOverviewModel.js +++ b/lib/public/views/Logs/Overview/LogsOverviewModel.js @@ -86,7 +86,7 @@ export class LogsOverviewModel extends Observable { * @param {boolean} notify if the FilteringModel should notify it's observers after finishing setting the filters */ setFilterFromURL(notify) { - this._filteringModel.setFilterFromURL(notify); + this._filteringModelsetFilterFromURL(null, notify); } /** diff --git a/lib/public/views/QcFlagTypes/Overview/QcFlagTypesOverviewModel.js b/lib/public/views/QcFlagTypes/Overview/QcFlagTypesOverviewModel.js index a87baedaa5..b5e37a298c 100644 --- a/lib/public/views/QcFlagTypes/Overview/QcFlagTypesOverviewModel.js +++ b/lib/public/views/QcFlagTypes/Overview/QcFlagTypesOverviewModel.js @@ -61,7 +61,7 @@ export class QcFlagTypesOverviewModel extends OverviewPageModel { * @param {boolean} notify if the FilteringModel should notify it's observers after finishing setting the filters */ setFilterFromURL(notify) { - this._filteringModel.setFilterFromURL(notify); + this._filteringModelsetFilterFromURL(null, notify); } /** diff --git a/lib/public/views/QcFlagTypes/QcFlagTypesModel.js b/lib/public/views/QcFlagTypes/QcFlagTypesModel.js index 9fe8118a76..554cd61edf 100644 --- a/lib/public/views/QcFlagTypes/QcFlagTypesModel.js +++ b/lib/public/views/QcFlagTypes/QcFlagTypesModel.js @@ -38,7 +38,7 @@ export class QcFlagTypesModel extends Observable { * @return {void} */ loadOverview() { - this._overviewModel.setFilterFromURL(false); + this._overviewModel.setFilterFromUrl(null, false); this._overviewModel.load(); } diff --git a/lib/public/views/Runs/Overview/RunsOverviewModel.js b/lib/public/views/Runs/Overview/RunsOverviewModel.js index 1b15fff0dc..7a4b7c36ac 100644 --- a/lib/public/views/Runs/Overview/RunsOverviewModel.js +++ b/lib/public/views/Runs/Overview/RunsOverviewModel.js @@ -168,7 +168,7 @@ export class RunsOverviewModel extends OverviewPageModel { * @param {boolean} notify if the FilteringModel should notify it's observers after finishing setting the filters */ setFilterFromURL(notify) { - this._filteringModel.setFilterFromURL(notify); + this._filteringModelsetFilterFromURL(null, notify); } /** diff --git a/lib/public/views/Runs/RunsModel.js b/lib/public/views/Runs/RunsModel.js index 007a456368..799c7b355d 100644 --- a/lib/public/views/Runs/RunsModel.js +++ b/lib/public/views/Runs/RunsModel.js @@ -48,7 +48,7 @@ export class RunsModel extends Observable { */ loadOverview() { if (! this._overviewModel.pagination.isInfiniteScrollEnabled) { - this._overviewModel.setFilterFromURL(false); + this._overviewModel.setFilterFromUrl(null, false); this._overviewModel.load(); } } @@ -94,7 +94,7 @@ export class RunsModel extends Observable { this._perLhcPeriodOverviewModel.tabbedPanelModel.currentPanelKey = panel; if (!this._perLhcPeriodOverviewModel.pagination.isInfiniteScrollEnabled) { this._perLhcPeriodOverviewModel.lhcPeriodId = lhcPeriodId; - this._perLhcPeriodOverviewModel.setFilterFromURL(false); + this._perLhcPeriodOverviewModel.setFilterFromUrl(null, false); this._perLhcPeriodOverviewModel.load(); } } @@ -122,7 +122,7 @@ export class RunsModel extends Observable { * so the pagination trigger will not refresh the data. * Thus, we need to trigger the load here. */ - this._perDataPassOverviewModel.setFilterFromURL(false); + this._perDataPassOverviewModel.setFilterFromUrl(null, false); this._perDataPassOverviewModel.load(); } } @@ -151,7 +151,7 @@ export class RunsModel extends Observable { * so the pagination trigger will not refresh the data. * Thus, we need to trigger the load here. */ - this._perSimulationPassOverviewModel.setFilterFromURL(false); + this._perSimulationPassOverviewModel.setFilterFromUrl(null, false); this._perSimulationPassOverviewModel.load(); } } diff --git a/lib/public/views/SimulationPasses/AnchoredOverview/AnchoredSimulationPassesOverviewModel.js b/lib/public/views/SimulationPasses/AnchoredOverview/AnchoredSimulationPassesOverviewModel.js index 810789c17f..6d6a80ff76 100644 --- a/lib/public/views/SimulationPasses/AnchoredOverview/AnchoredSimulationPassesOverviewModel.js +++ b/lib/public/views/SimulationPasses/AnchoredOverview/AnchoredSimulationPassesOverviewModel.js @@ -48,7 +48,7 @@ export class AnchoredSimulationPassesOverviewModel extends OverviewPageModel { * @param {boolean} notify if the FilteringModel should notify it's observers after finishing setting the filters */ setFilterFromURL(notify) { - this._filteringModel.setFilterFromURL(notify); + this._filteringModelsetFilterFromURL(null, notify); } /** diff --git a/lib/public/views/SimulationPasses/PerLhcPeriodOverview/SimulationPassesPerLhcPeriodOverviewModel.js b/lib/public/views/SimulationPasses/PerLhcPeriodOverview/SimulationPassesPerLhcPeriodOverviewModel.js index ffc2eb5e02..cfff1e3d23 100644 --- a/lib/public/views/SimulationPasses/PerLhcPeriodOverview/SimulationPassesPerLhcPeriodOverviewModel.js +++ b/lib/public/views/SimulationPasses/PerLhcPeriodOverview/SimulationPassesPerLhcPeriodOverviewModel.js @@ -64,7 +64,7 @@ export class SimulationPassesPerLhcPeriodOverviewModel extends OverviewPageModel * @param {boolean} notify if the FilteringModel should notify it's observers after finishing setting the filters */ setFilterFromURL(notify) { - this._filteringModel.setFilterFromURL(notify); + this._filteringModelsetFilterFromURL(null, notify); } /** diff --git a/lib/public/views/SimulationPasses/SimulationPassesModel.js b/lib/public/views/SimulationPasses/SimulationPassesModel.js index 8ba624efd8..5a0a9a7d17 100644 --- a/lib/public/views/SimulationPasses/SimulationPassesModel.js +++ b/lib/public/views/SimulationPasses/SimulationPassesModel.js @@ -42,7 +42,7 @@ export class SimulationPassesModel extends Observable { loadPerLhcPeriodOverview({ lhcPeriodId }) { if (!this._perLhcPeriodOverviewModel.pagination.isInfiniteScrollEnabled) { this._perLhcPeriodOverviewModel.lhcPeriodId = lhcPeriodId; - this._perLhcPeriodOverviewModel.setFilterFromURL(false); + this._perLhcPeriodOverviewModel.setFilterFromUrl(null, false); this._perLhcPeriodOverviewModel.load(); } } @@ -72,7 +72,7 @@ export class SimulationPassesModel extends Observable { */ loadAnchoredOverview({ dataPassId }) { this._anchoredOverviewModel.dataPassId = dataPassId; - this._anchoredOverviewModel.setFilterFromURL(false); + this._anchoredOverviewModel.setFilterFromUrl(null, false); this._anchoredOverviewModel.load(); } diff --git a/lib/public/views/lhcPeriods/LhcPeriodsModel.js b/lib/public/views/lhcPeriods/LhcPeriodsModel.js index 74df7b9dc7..a7e7da7385 100644 --- a/lib/public/views/lhcPeriods/LhcPeriodsModel.js +++ b/lib/public/views/lhcPeriods/LhcPeriodsModel.js @@ -35,7 +35,7 @@ export class LhcPeriodsModel extends Observable { * @returns {void} */ loadOverview() { - this._overviewModel.setFilterFromURL(false); + this._overviewModel.setFilterFromUrl(null, false); this._overviewModel.load(); } diff --git a/lib/public/views/lhcPeriods/Overview/LhcPeriodsOverviewModel.js b/lib/public/views/lhcPeriods/Overview/LhcPeriodsOverviewModel.js index f517fe02e7..f29e39ad5a 100644 --- a/lib/public/views/lhcPeriods/Overview/LhcPeriodsOverviewModel.js +++ b/lib/public/views/lhcPeriods/Overview/LhcPeriodsOverviewModel.js @@ -61,7 +61,7 @@ export class LhcPeriodsOverviewModel extends OverviewPageModel { * @param {boolean} notify if the FilteringModel should notify it's observers after finishing setting the filters */ setFilterFromURL(notify) { - this._filteringModel.setFilterFromURL(notify); + this._filteringModelsetFilterFromURL(null, notify); } /** From cd0654893d0a6f0526526a1381fe4130d6cdb11d Mon Sep 17 00:00:00 2001 From: NarrowsProjects Date: Wed, 29 Apr 2026 16:55:21 +0200 Subject: [PATCH 2/8] feat: create dropdown options --- .../Filters/common/filtersPanelPopover.js | 98 ++++++++++++++++--- 1 file changed, 86 insertions(+), 12 deletions(-) diff --git a/lib/public/components/Filters/common/filtersPanelPopover.js b/lib/public/components/Filters/common/filtersPanelPopover.js index 1d729eb93e..8aaa90df20 100644 --- a/lib/public/components/Filters/common/filtersPanelPopover.js +++ b/lib/public/components/Filters/common/filtersPanelPopover.js @@ -10,7 +10,8 @@ * granted to it by virtue of its status as an Intergovernmental Organization * or submit itself to any jurisdiction. */ -import { h, info, popover, PopoverAnchors, PopoverTriggerPreConfiguration } from '/js/src/index.js'; +import { h, info, popover, PopoverAnchors, PopoverTriggerPreConfiguration, DropdownComponent, CopyToClipboardComponent } from '/js/src/index.js'; +import { iconCaretBottom } from '/js/src/icons.js'; import { profiles } from '../../common/table/profiles.js'; import { applyProfile } from '../../../utilities/applyProfile.js'; import { tooltip } from '../../common/popover/tooltip.js'; @@ -35,25 +36,34 @@ import { tooltip } from '../../common/popover/tooltip.js'; * * @return {Component} the button component */ -const filtersToggleTrigger = () => h('button#openFilterToggle.btn.btn.btn-primary', 'Filters'); +const filtersToggleTrigger = () => h('button#openFilterToggle.btn.btn.btn-primary.first-item', 'Filters'); /** - * Create main header of the filters panel - * @param {FilteringModel} filteringModel filtering model - * @returns {Component} main panel header + * Button component that resets all filters upon click + * + * @param {FilteringModel|OverviewPageModel} filteringModel the FilteringModel + * @returns {Component} the reset button component */ -const filtersToggleContentHeader = (filteringModel) => h('.flex-row.justify-between', [ - h('.f4', 'Filters'), - h( +const resetFiltersButton = (filteringModel) => h( 'button#reset-filters.btn.btn-danger', { + disabled: !filteringModel.isAnyFilterActive(), onclick: () => filteringModel.resetFiltering ? filteringModel.resetFiltering(true, true) : filteringModel.reset(true, true), - disabled: !filteringModel.isAnyFilterActive(), }, 'Reset all filters', - ), + ); + + +/** + * Create main header of the filters panel + * @param {FilteringModel} filteringModel filtering model + * @returns {Component} main panel header + */ +const filtersToggleContentHeader = (filteringModel) => h('.flex-row.justify-between', [ + h('.f4', 'Filters'), + resetFiltersButton(filteringModel), ]); /** @@ -114,9 +124,9 @@ const filtersToggleContent = ( * @param {FiltersConfiguration} filtersConfiguration filters configuration * @param {object} [configuration] optional configuration * @param {string} [configuration.profile] specify for which profile filtering should be enabled - * @return {Component} the filter component + * @return {Component} the filter button component */ -export const filtersPanelPopover = (filteringModel, filtersConfiguration, configuration) => popover( +const filtersPanelButton = (filteringModel, filtersConfiguration, configuration) => popover( filtersToggleTrigger(), filtersToggleContent(filteringModel, filtersConfiguration, configuration), { @@ -124,3 +134,67 @@ export const filtersPanelPopover = (filteringModel, filtersConfiguration, config anchor: PopoverAnchors.RIGHT_START, }, ); + +/** + * A button component that lets the user copy the url if there are active filters. + * + * @param {boolean} activeFilters if false, will disable the button + * @returns {Component} the copy button component + */ +const copyButtonOption = (activeFilters) => h( + '', + { style: activeFilters ? {} : { opacity: 0.5, pointerEvents: 'none' } }, + h(CopyToClipboardComponent, { value: location.href, id: "filter" }, 'Copy Active Filters'), +) + +/** + * A button component that lets the user paste the first entry of their clipboard as a filter url. + * + * @param {FilteringModel|OverviewPageModel} filteringModel the FilteringModel + * @returns {Component} the paste button component + */ +const pasteButtonOption = (filteringModel) => { + const clipboardSupported = navigator?.clipboard && window.isSecureContext; + + // Sometimes, the overview model is passed to filterPanelPopover instead of the filteringmodel (e.g. envirionments) + if (filteringModel.filteringModel) { + filteringModel = filteringModel.filteringModel; + } + + return h('.btn.btn-primary', { onclick: async () => { + const url = await navigator.clipboard.readText(); + filteringModel.setFilterFromURL(url); + + }, disabled: !clipboardSupported}, 'Paste filters'); +} + +/** + * Return component composed of the filter popover button and a dropdown trigger + * + * @param {FilteringModel} filteringModel the filtering model + * @param {FiltersConfiguration} filtersConfiguration filters configuration + * @param {object} [configuration] optional configuration + * @param {string} [configuration.profile] specify for which profile filtering should be enabled + * @return {Component} the filter component + */ +export const filtersPanelPopover = (filteringModel, filtersConfiguration, configuration) => { + const hasActiveFilters = filteringModel.isAnyFilterActive(); + + return h( + '.flex-row.items-center.btn-group', + [ + filtersPanelButton(filteringModel, filtersConfiguration, configuration), + DropdownComponent( + h('.btn.btn-group-item.last-item', iconCaretBottom()), + h( + '.flex-column.p2.g2', + [ + copyButtonOption(hasActiveFilters), + pasteButtonOption(filteringModel), + resetFiltersButton(filteringModel), + ], + ), + ), + ], + ); +} From acef2bf92da758e7a4217dfb03c9cc8cf4cbca1c Mon Sep 17 00:00:00 2001 From: NarrowsProjects Date: Wed, 29 Apr 2026 17:18:41 +0200 Subject: [PATCH 3/8] fix linting issues --- .../Filters/common/FilteringModel.js | 11 ++--- .../Filters/common/filtersPanelPopover.js | 47 +++++++++---------- 2 files changed, 27 insertions(+), 31 deletions(-) diff --git a/lib/public/components/Filters/common/FilteringModel.js b/lib/public/components/Filters/common/FilteringModel.js index 5b8b6b6aa3..5ce15214d4 100644 --- a/lib/public/components/Filters/common/FilteringModel.js +++ b/lib/public/components/Filters/common/FilteringModel.js @@ -144,20 +144,17 @@ export class FilteringModel extends Observable { * @returns {object} the serach parameters object */ _computeParameters(url = null) { - let params = {}; - if (url) { try { - params = parseUrlParameters(new URL(url).searchParams); - } catch (e) { + return parseUrlParameters(new URL(url).searchParams); + } catch { this._warnings.set('Unparseable URL', `URL could not be parsed. URL: ${url}`); this.notify(); + return {}; } - } else { - params = this._router.params; } - return params; + return this._router.params; } /** diff --git a/lib/public/components/Filters/common/filtersPanelPopover.js b/lib/public/components/Filters/common/filtersPanelPopover.js index 8aaa90df20..db75241844 100644 --- a/lib/public/components/Filters/common/filtersPanelPopover.js +++ b/lib/public/components/Filters/common/filtersPanelPopover.js @@ -45,16 +45,15 @@ const filtersToggleTrigger = () => h('button#openFilterToggle.btn.btn.btn-primar * @returns {Component} the reset button component */ const resetFiltersButton = (filteringModel) => h( - 'button#reset-filters.btn.btn-danger', - { - disabled: !filteringModel.isAnyFilterActive(), - onclick: () => filteringModel.resetFiltering - ? filteringModel.resetFiltering(true, true) - : filteringModel.reset(true, true), - }, - 'Reset all filters', - ); - + 'button#reset-filters.btn.btn-danger', + { + disabled: !filteringModel.isAnyFilterActive(), + onclick: () => filteringModel.resetFiltering + ? filteringModel.resetFiltering(true, true) + : filteringModel.reset(true, true), + }, + 'Reset all filters', +); /** * Create main header of the filters panel @@ -144,29 +143,29 @@ const filtersPanelButton = (filteringModel, filtersConfiguration, configuration) const copyButtonOption = (activeFilters) => h( '', { style: activeFilters ? {} : { opacity: 0.5, pointerEvents: 'none' } }, - h(CopyToClipboardComponent, { value: location.href, id: "filter" }, 'Copy Active Filters'), -) + h(CopyToClipboardComponent, { value: location.href, id: 'filter' }, 'Copy Active Filters'), +); /** * A button component that lets the user paste the first entry of their clipboard as a filter url. * - * @param {FilteringModel|OverviewPageModel} filteringModel the FilteringModel + * @param {FilteringModel|OverviewPageModel} model the FilteringModel * @returns {Component} the paste button component */ -const pasteButtonOption = (filteringModel) => { +const pasteButtonOption = (model) => { const clipboardSupported = navigator?.clipboard && window.isSecureContext; // Sometimes, the overview model is passed to filterPanelPopover instead of the filteringmodel (e.g. envirionments) - if (filteringModel.filteringModel) { - filteringModel = filteringModel.filteringModel; - } + const { filteringModel = model } = model; - return h('.btn.btn-primary', { onclick: async () => { - const url = await navigator.clipboard.readText(); - filteringModel.setFilterFromURL(url); - - }, disabled: !clipboardSupported}, 'Paste filters'); -} + return h('.btn.btn-primary', { + onclick: async () => { + const url = await navigator.clipboard.readText(); + filteringModel.setFilterFromURL(url); + }, + disabled: !clipboardSupported, + }, 'Paste filters'); +}; /** * Return component composed of the filter popover button and a dropdown trigger @@ -197,4 +196,4 @@ export const filtersPanelPopover = (filteringModel, filtersConfiguration, config ), ], ); -} +}; From 52cc7499f76d835f9342f4690e734363197bc7ff Mon Sep 17 00:00:00 2001 From: NarrowsProjects Date: Thu, 30 Apr 2026 09:56:19 +0200 Subject: [PATCH 4/8] chore: add tests for new buttons --- .../Filters/common/filtersPanelPopover.js | 1 + .../components/filtersPopoverPanel.test.js | 86 +++++++++++++++++++ test/public/components/index.js | 2 + 3 files changed, 89 insertions(+) create mode 100644 test/public/components/filtersPopoverPanel.test.js diff --git a/lib/public/components/Filters/common/filtersPanelPopover.js b/lib/public/components/Filters/common/filtersPanelPopover.js index db75241844..8f0ca39a4b 100644 --- a/lib/public/components/Filters/common/filtersPanelPopover.js +++ b/lib/public/components/Filters/common/filtersPanelPopover.js @@ -164,6 +164,7 @@ const pasteButtonOption = (model) => { filteringModel.setFilterFromURL(url); }, disabled: !clipboardSupported, + id: 'paste-filter', }, 'Paste filters'); }; diff --git a/test/public/components/filtersPopoverPanel.test.js b/test/public/components/filtersPopoverPanel.test.js new file mode 100644 index 0000000000..7e6d7e0011 --- /dev/null +++ b/test/public/components/filtersPopoverPanel.test.js @@ -0,0 +1,86 @@ +/** + * @license + * Copyright CERN and copyright holders of ALICE O2. 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-o2.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. + */ + +const { expect } = require('chai'); +const { defaultBefore, defaultAfter, pressElement, takeScreenshot, expectInputValue } = require('../defaults.js'); + +module.exports = () => { + let page; + let browser; + let context; + let url; + + before(async () => { + [page, browser, url] = await defaultBefore(page, browser); + context = browser.defaultBrowserContext(); + context.overridePermissions(url, ['clipboard-read', 'clipboard-write', 'clipboard-sanitized-write']); + }); + + it('Should copy url when clicking filer copy button', async () => { + const url = 'http://localhost:4000/?page=lhc-period-overview&filter[names][]=name&filter[years][]=100&filter[pdpBeamTypes][]=PbPb'; + await page.goto(url, { waitUntil: 'load' }); + await takeScreenshot(page, 'test'); + await pressElement(page, '#copy-filter', true); + + const clipboardContents = await page.evaluate(async () => decodeURI(await navigator.clipboard.readText())); + expect(clipboardContents).to.equal(url); + }); + + it('Should set filters when pressing paste active filters button', async () => { + const url = 'http://localhost:4000/?page=lhc-period-overview&filter[names][]=name&filter[years][]=100&filter[pdpBeamTypes][]=PbPb'; + + await page.evaluate(async (url) => await navigator.clipboard.writeText(url), url); + await pressElement(page, '#paste-filter', true); + + const actualUrl = page.url(); + expect(actualUrl).to.equal(url); + + await expectInputValue(page, 'div.flex-row.items-baseline:nth-of-type(1) input[type=text]', 'name'); + await expectInputValue(page, 'div.flex-row.items-baseline:nth-of-type(2) input[type=text]', '100'); + await expectInputValue(page, 'div.flex-row.items-baseline:nth-of-type(3) input[type=text]', 'PbPb'); + }); + + it('Should set filters when pressing paste active filters button', async () => { + const url = 'http://localhost:4000/?page=lhc-period-overview&filter[names][]=name&filter[years][]=100&filter[pdpBeamTypes][]=PbPb'; + + await page.evaluate(async (url) => await navigator.clipboard.writeText(url), url); + await pressElement(page, '#paste-filter', true); + + const actualUrl = page.url(); + expect(actualUrl).to.equal(url); + + await expectInputValue(page, 'div.flex-row.items-baseline:nth-of-type(1) input[type=text]', 'name'); + await expectInputValue(page, 'div.flex-row.items-baseline:nth-of-type(2) input[type=text]', '100'); + await expectInputValue(page, 'div.flex-row.items-baseline:nth-of-type(3) input[type=text]', 'PbPb'); + }); + + it('Should reset filters when pressing the reset all filters button', async () => { + const url = 'http://localhost:4000/?page=lhc-period-overview&filter[names][]=name&filter[years][]=100&filter[pdpBeamTypes][]=PbPb'; + + await page.goto(url, { waitUntil: 'load' }); + + await page.evaluate(async (url) => await navigator.clipboard.writeText(url), url); + await pressElement(page, '.dropdown #reset-filters', true); + + const actualUrl = page.url(); + expect(actualUrl).to.equal('http://localhost:4000/?page=lhc-period-overview'); + + await expectInputValue(page, '.name-filter input', ''); + await expectInputValue(page, '.year-filter input', ''); + await expectInputValue(page, '.pdpBeamTypes-filter input', ''); + }); + + after(async () => { + await defaultAfter(page, browser); + }); +}; diff --git a/test/public/components/index.js b/test/public/components/index.js index 700564755c..794ae79252 100644 --- a/test/public/components/index.js +++ b/test/public/components/index.js @@ -13,8 +13,10 @@ const NavBarSuite = require('./navBar.test') const WarningSuite = require('./warnings.test') +const FiltersPanelSuite = require('./filtersPopoverPanel.test') module.exports = () => { describe('Navbar component', NavBarSuite); describe('Warning component', WarningSuite) + describe('FiltersPanelPopover component', FiltersPanelSuite) }; From 3c542a492cc52a25b70207389650237aa21eb5e9 Mon Sep 17 00:00:00 2001 From: NarrowsProjects Date: Mon, 25 May 2026 13:50:41 +0200 Subject: [PATCH 5/8] feat: add filter restoration button --- .../Filters/common/FilteringModel.js | 16 ++++++++++++++++ .../Filters/common/filtersPanelPopover.js | 19 ++++++++++++++++++- 2 files changed, 34 insertions(+), 1 deletion(-) diff --git a/lib/public/components/Filters/common/FilteringModel.js b/lib/public/components/Filters/common/FilteringModel.js index 5ce15214d4..9cec2592a3 100644 --- a/lib/public/components/Filters/common/FilteringModel.js +++ b/lib/public/components/Filters/common/FilteringModel.js @@ -37,6 +37,7 @@ export class FilteringModel extends Observable { this._filters = {}; this._filterModels = []; Object.entries(filters).forEach(([key, model]) => this.put(key, model)); + this.previousUrl = ''; } /** @@ -58,6 +59,12 @@ export class FilteringModel extends Observable { * @return {void} */ reset(notify = false, clearUrl = false) { + if (!this.isAnyFilterActive()) { + return; + } + + this.previousUrl = location.href; + for (const model of this._filterModels) { model.reset(); } @@ -137,6 +144,15 @@ export class FilteringModel extends Observable { this.notify(); } + /** + * Will restore filters to the state before it was reset. + * @returns {undefined} + */ + restoreFilters() { + this.setFilterFromURL(this.previousUrl); + this.previousUrl = ''; + } + /** * Compute seach parameters based a url or router * diff --git a/lib/public/components/Filters/common/filtersPanelPopover.js b/lib/public/components/Filters/common/filtersPanelPopover.js index 8f0ca39a4b..063df33ae0 100644 --- a/lib/public/components/Filters/common/filtersPanelPopover.js +++ b/lib/public/components/Filters/common/filtersPanelPopover.js @@ -158,7 +158,7 @@ const pasteButtonOption = (model) => { // Sometimes, the overview model is passed to filterPanelPopover instead of the filteringmodel (e.g. envirionments) const { filteringModel = model } = model; - return h('.btn.btn-primary', { + return h('button.btn.btn-primary', { onclick: async () => { const url = await navigator.clipboard.readText(); filteringModel.setFilterFromURL(url); @@ -168,6 +168,22 @@ const pasteButtonOption = (model) => { }, 'Paste filters'); }; +/** + * A button component that lets the user paste the first entry of their clipboard as a filter url. + * + * @param {FilteringModel|OverviewPageModel} model the FilteringModel + * @returns {Component} the paste button component + */ +const restoreFiltersButton = (model) => { + const { filteringModel = model } = model; + + return h('button.btn.btn-primary', { + onclick: async () => filteringModel.restoreFilters(), + disabled: !filteringModel.previousUrl, + id: 'restore-filters', + }, 'Restore Filters'); +}; + /** * Return component composed of the filter popover button and a dropdown trigger * @@ -192,6 +208,7 @@ export const filtersPanelPopover = (filteringModel, filtersConfiguration, config copyButtonOption(hasActiveFilters), pasteButtonOption(filteringModel), resetFiltersButton(filteringModel), + restoreFiltersButton(filteringModel), ], ), ), From e9d594537c9923a6f630a4d81fb28cce4cb85f1b Mon Sep 17 00:00:00 2001 From: NarrowsProjects Date: Wed, 17 Jun 2026 11:35:59 +0200 Subject: [PATCH 6/8] chore: remove restoreFilters --- .../components/Filters/common/FilteringModel.js | 12 ------------ .../Filters/common/filtersPanelPopover.js | 17 ----------------- 2 files changed, 29 deletions(-) diff --git a/lib/public/components/Filters/common/FilteringModel.js b/lib/public/components/Filters/common/FilteringModel.js index 9cec2592a3..0164540af1 100644 --- a/lib/public/components/Filters/common/FilteringModel.js +++ b/lib/public/components/Filters/common/FilteringModel.js @@ -37,7 +37,6 @@ export class FilteringModel extends Observable { this._filters = {}; this._filterModels = []; Object.entries(filters).forEach(([key, model]) => this.put(key, model)); - this.previousUrl = ''; } /** @@ -63,8 +62,6 @@ export class FilteringModel extends Observable { return; } - this.previousUrl = location.href; - for (const model of this._filterModels) { model.reset(); } @@ -144,15 +141,6 @@ export class FilteringModel extends Observable { this.notify(); } - /** - * Will restore filters to the state before it was reset. - * @returns {undefined} - */ - restoreFilters() { - this.setFilterFromURL(this.previousUrl); - this.previousUrl = ''; - } - /** * Compute seach parameters based a url or router * diff --git a/lib/public/components/Filters/common/filtersPanelPopover.js b/lib/public/components/Filters/common/filtersPanelPopover.js index 063df33ae0..99a750e1e5 100644 --- a/lib/public/components/Filters/common/filtersPanelPopover.js +++ b/lib/public/components/Filters/common/filtersPanelPopover.js @@ -168,22 +168,6 @@ const pasteButtonOption = (model) => { }, 'Paste filters'); }; -/** - * A button component that lets the user paste the first entry of their clipboard as a filter url. - * - * @param {FilteringModel|OverviewPageModel} model the FilteringModel - * @returns {Component} the paste button component - */ -const restoreFiltersButton = (model) => { - const { filteringModel = model } = model; - - return h('button.btn.btn-primary', { - onclick: async () => filteringModel.restoreFilters(), - disabled: !filteringModel.previousUrl, - id: 'restore-filters', - }, 'Restore Filters'); -}; - /** * Return component composed of the filter popover button and a dropdown trigger * @@ -208,7 +192,6 @@ export const filtersPanelPopover = (filteringModel, filtersConfiguration, config copyButtonOption(hasActiveFilters), pasteButtonOption(filteringModel), resetFiltersButton(filteringModel), - restoreFiltersButton(filteringModel), ], ), ), From 6c1b59e111f42ec55604e344bdb94c8be6d9ed03 Mon Sep 17 00:00:00 2001 From: NarrowsProjects Date: Wed, 17 Jun 2026 12:39:00 +0200 Subject: [PATCH 7/8] chore: pass url to setFiltersFromUrl --- lib/public/components/Filters/common/FilteringModel.js | 3 ++- .../components/Filters/common/filtersPanelPopover.js | 2 +- lib/public/views/DataPasses/DataPassesModel.js | 4 ++-- lib/public/views/DataPasses/DataPassesOverviewModel.js | 2 +- lib/public/views/Environments/EnvironmentModel.js | 2 +- .../Environments/Overview/EnvironmentOverviewModel.js | 2 +- lib/public/views/LhcFills/LhcFills.js | 2 +- .../views/LhcFills/Overview/LhcFillsOverviewModel.js | 2 +- lib/public/views/Logs/LogsModel.js | 2 +- lib/public/views/Logs/Overview/LogsOverviewModel.js | 2 +- .../QcFlagTypes/Overview/QcFlagTypesOverviewModel.js | 2 +- lib/public/views/QcFlagTypes/QcFlagTypesModel.js | 2 +- lib/public/views/Runs/Overview/RunsOverviewModel.js | 2 +- lib/public/views/Runs/RunsModel.js | 8 ++++---- .../AnchoredSimulationPassesOverviewModel.js | 2 +- .../SimulationPassesPerLhcPeriodOverviewModel.js | 2 +- .../views/SimulationPasses/SimulationPassesModel.js | 4 ++-- lib/public/views/lhcPeriods/LhcPeriodsModel.js | 2 +- .../views/lhcPeriods/Overview/LhcPeriodsOverviewModel.js | 2 +- 19 files changed, 25 insertions(+), 24 deletions(-) diff --git a/lib/public/components/Filters/common/FilteringModel.js b/lib/public/components/Filters/common/FilteringModel.js index 0164540af1..ed543247bc 100644 --- a/lib/public/components/Filters/common/FilteringModel.js +++ b/lib/public/components/Filters/common/FilteringModel.js @@ -169,7 +169,8 @@ export class FilteringModel extends Observable { * @returns {undefined} */ setFilterFromURL(url = null, notify = false) { - const { params: { page = '', filter } } = this._router; + const params = this._computeParameters(url); + const { page, filter } = params; if (this._pageIdentifier === page) { if (!filter) { diff --git a/lib/public/components/Filters/common/filtersPanelPopover.js b/lib/public/components/Filters/common/filtersPanelPopover.js index 99a750e1e5..ee5a370fdf 100644 --- a/lib/public/components/Filters/common/filtersPanelPopover.js +++ b/lib/public/components/Filters/common/filtersPanelPopover.js @@ -161,7 +161,7 @@ const pasteButtonOption = (model) => { return h('button.btn.btn-primary', { onclick: async () => { const url = await navigator.clipboard.readText(); - filteringModel.setFilterFromURL(url); + filteringModel.setFilterFromURL(url, true); }, disabled: !clipboardSupported, id: 'paste-filter', diff --git a/lib/public/views/DataPasses/DataPassesModel.js b/lib/public/views/DataPasses/DataPassesModel.js index 0ac1551358..42fed10c3a 100644 --- a/lib/public/views/DataPasses/DataPassesModel.js +++ b/lib/public/views/DataPasses/DataPassesModel.js @@ -40,7 +40,7 @@ export class DataPassesModel extends Observable { * @returns {void} */ loadPerLhcPeriodOverview({ lhcPeriodId }) { - this._perLhcPeriodOverviewModel.setFilterFromUrl(null, false); + this._perLhcPeriodOverviewModel.setFilterFromURL(false); this._perLhcPeriodOverviewModel.load({ lhcPeriodId }); } @@ -69,7 +69,7 @@ export class DataPassesModel extends Observable { */ loadPerSimulationPassOverview({ simulationPassId }) { this._perSimulationPassOverviewModel.simulationPassId = parseInt(simulationPassId, 10); - this._perSimulationPassOverviewModel.setFilterFromUrl(null, false); + this._perSimulationPassOverviewModel.setFilterFromURL(false); this._perSimulationPassOverviewModel.load(); } diff --git a/lib/public/views/DataPasses/DataPassesOverviewModel.js b/lib/public/views/DataPasses/DataPassesOverviewModel.js index c7a690f6a0..ca6c058220 100644 --- a/lib/public/views/DataPasses/DataPassesOverviewModel.js +++ b/lib/public/views/DataPasses/DataPassesOverviewModel.js @@ -61,7 +61,7 @@ export class DataPassesOverviewModel extends OverviewPageModel { * @param {boolean} notify if the FilteringModel should notify it's observers after finishing setting the filters */ setFilterFromURL(notify) { - this._filteringModelsetFilterFromURL(null, notify); + this._filteringModel.setFilterFromURL(null, notify); } /** diff --git a/lib/public/views/Environments/EnvironmentModel.js b/lib/public/views/Environments/EnvironmentModel.js index 0e765df8fa..1cc7fa484d 100644 --- a/lib/public/views/Environments/EnvironmentModel.js +++ b/lib/public/views/Environments/EnvironmentModel.js @@ -42,7 +42,7 @@ export class EnvironmentModel extends Observable { */ loadOverview() { if (!this._overviewModel.pagination.isInfiniteScrollEnabled) { - this._overviewModel.setFilterFromUrl(null, false); + this._overviewModel.setFilterFromURL(false); this._overviewModel.load(); } } diff --git a/lib/public/views/Environments/Overview/EnvironmentOverviewModel.js b/lib/public/views/Environments/Overview/EnvironmentOverviewModel.js index 1daa0025aa..49a06d8758 100644 --- a/lib/public/views/Environments/Overview/EnvironmentOverviewModel.js +++ b/lib/public/views/Environments/Overview/EnvironmentOverviewModel.js @@ -76,7 +76,7 @@ export class EnvironmentOverviewModel extends OverviewPageModel { * @param {boolean} notify if the FilteringModel should notify it's observers after finishing setting the filters */ setFilterFromURL(notify) { - this._filteringModelsetFilterFromURL(null, notify); + this._filteringModel.setFilterFromURL(null, notify); } /** diff --git a/lib/public/views/LhcFills/LhcFills.js b/lib/public/views/LhcFills/LhcFills.js index ea92a4ae03..a4343be26a 100644 --- a/lib/public/views/LhcFills/LhcFills.js +++ b/lib/public/views/LhcFills/LhcFills.js @@ -42,7 +42,7 @@ export default class LhcFills extends Observable { * @returns {void} */ loadOverview() { - this._overviewModel.setFilterFromUrl(null, false); + this._overviewModel.setFilterFromURL(false); this._overviewModel.load(); } diff --git a/lib/public/views/LhcFills/Overview/LhcFillsOverviewModel.js b/lib/public/views/LhcFills/Overview/LhcFillsOverviewModel.js index 8886126f36..b09fe7f00f 100644 --- a/lib/public/views/LhcFills/Overview/LhcFillsOverviewModel.js +++ b/lib/public/views/LhcFills/Overview/LhcFillsOverviewModel.js @@ -80,7 +80,7 @@ export class LhcFillsOverviewModel extends OverviewPageModel { * @param {boolean} notify if the FilteringModel should notify it's observers after finishing setting the filters */ setFilterFromURL(notify) { - this._filteringModelsetFilterFromURL(null, notify); + this._filteringModel.setFilterFromURL(null, notify); } /** diff --git a/lib/public/views/Logs/LogsModel.js b/lib/public/views/Logs/LogsModel.js index 67c3d9062f..7822fa4d79 100644 --- a/lib/public/views/Logs/LogsModel.js +++ b/lib/public/views/Logs/LogsModel.js @@ -55,7 +55,7 @@ export class LogsModel extends Observable { */ loadOverview() { if (!this._overviewModel.pagination.isInfiniteScrollEnabled) { - this._overviewModel.setFilterFromUrl(null, false); + this._overviewModel.setFilterFromURL(false); this._overviewModel.fetchLogs(); } } diff --git a/lib/public/views/Logs/Overview/LogsOverviewModel.js b/lib/public/views/Logs/Overview/LogsOverviewModel.js index f1a89ebb0d..4f73a8cf98 100644 --- a/lib/public/views/Logs/Overview/LogsOverviewModel.js +++ b/lib/public/views/Logs/Overview/LogsOverviewModel.js @@ -86,7 +86,7 @@ export class LogsOverviewModel extends Observable { * @param {boolean} notify if the FilteringModel should notify it's observers after finishing setting the filters */ setFilterFromURL(notify) { - this._filteringModelsetFilterFromURL(null, notify); + this._filteringModel.setFilterFromURL(null, notify); } /** diff --git a/lib/public/views/QcFlagTypes/Overview/QcFlagTypesOverviewModel.js b/lib/public/views/QcFlagTypes/Overview/QcFlagTypesOverviewModel.js index b5e37a298c..2e25d7b67b 100644 --- a/lib/public/views/QcFlagTypes/Overview/QcFlagTypesOverviewModel.js +++ b/lib/public/views/QcFlagTypes/Overview/QcFlagTypesOverviewModel.js @@ -61,7 +61,7 @@ export class QcFlagTypesOverviewModel extends OverviewPageModel { * @param {boolean} notify if the FilteringModel should notify it's observers after finishing setting the filters */ setFilterFromURL(notify) { - this._filteringModelsetFilterFromURL(null, notify); + this._filteringModel.setFilterFromURL(null, notify); } /** diff --git a/lib/public/views/QcFlagTypes/QcFlagTypesModel.js b/lib/public/views/QcFlagTypes/QcFlagTypesModel.js index 554cd61edf..9fe8118a76 100644 --- a/lib/public/views/QcFlagTypes/QcFlagTypesModel.js +++ b/lib/public/views/QcFlagTypes/QcFlagTypesModel.js @@ -38,7 +38,7 @@ export class QcFlagTypesModel extends Observable { * @return {void} */ loadOverview() { - this._overviewModel.setFilterFromUrl(null, false); + this._overviewModel.setFilterFromURL(false); this._overviewModel.load(); } diff --git a/lib/public/views/Runs/Overview/RunsOverviewModel.js b/lib/public/views/Runs/Overview/RunsOverviewModel.js index 7a4b7c36ac..482e9a40d5 100644 --- a/lib/public/views/Runs/Overview/RunsOverviewModel.js +++ b/lib/public/views/Runs/Overview/RunsOverviewModel.js @@ -168,7 +168,7 @@ export class RunsOverviewModel extends OverviewPageModel { * @param {boolean} notify if the FilteringModel should notify it's observers after finishing setting the filters */ setFilterFromURL(notify) { - this._filteringModelsetFilterFromURL(null, notify); + this._filteringModel.setFilterFromURL(null, notify); } /** diff --git a/lib/public/views/Runs/RunsModel.js b/lib/public/views/Runs/RunsModel.js index 799c7b355d..007a456368 100644 --- a/lib/public/views/Runs/RunsModel.js +++ b/lib/public/views/Runs/RunsModel.js @@ -48,7 +48,7 @@ export class RunsModel extends Observable { */ loadOverview() { if (! this._overviewModel.pagination.isInfiniteScrollEnabled) { - this._overviewModel.setFilterFromUrl(null, false); + this._overviewModel.setFilterFromURL(false); this._overviewModel.load(); } } @@ -94,7 +94,7 @@ export class RunsModel extends Observable { this._perLhcPeriodOverviewModel.tabbedPanelModel.currentPanelKey = panel; if (!this._perLhcPeriodOverviewModel.pagination.isInfiniteScrollEnabled) { this._perLhcPeriodOverviewModel.lhcPeriodId = lhcPeriodId; - this._perLhcPeriodOverviewModel.setFilterFromUrl(null, false); + this._perLhcPeriodOverviewModel.setFilterFromURL(false); this._perLhcPeriodOverviewModel.load(); } } @@ -122,7 +122,7 @@ export class RunsModel extends Observable { * so the pagination trigger will not refresh the data. * Thus, we need to trigger the load here. */ - this._perDataPassOverviewModel.setFilterFromUrl(null, false); + this._perDataPassOverviewModel.setFilterFromURL(false); this._perDataPassOverviewModel.load(); } } @@ -151,7 +151,7 @@ export class RunsModel extends Observable { * so the pagination trigger will not refresh the data. * Thus, we need to trigger the load here. */ - this._perSimulationPassOverviewModel.setFilterFromUrl(null, false); + this._perSimulationPassOverviewModel.setFilterFromURL(false); this._perSimulationPassOverviewModel.load(); } } diff --git a/lib/public/views/SimulationPasses/AnchoredOverview/AnchoredSimulationPassesOverviewModel.js b/lib/public/views/SimulationPasses/AnchoredOverview/AnchoredSimulationPassesOverviewModel.js index 6d6a80ff76..20fc3b725f 100644 --- a/lib/public/views/SimulationPasses/AnchoredOverview/AnchoredSimulationPassesOverviewModel.js +++ b/lib/public/views/SimulationPasses/AnchoredOverview/AnchoredSimulationPassesOverviewModel.js @@ -48,7 +48,7 @@ export class AnchoredSimulationPassesOverviewModel extends OverviewPageModel { * @param {boolean} notify if the FilteringModel should notify it's observers after finishing setting the filters */ setFilterFromURL(notify) { - this._filteringModelsetFilterFromURL(null, notify); + this._filteringModel.setFilterFromURL(null, notify); } /** diff --git a/lib/public/views/SimulationPasses/PerLhcPeriodOverview/SimulationPassesPerLhcPeriodOverviewModel.js b/lib/public/views/SimulationPasses/PerLhcPeriodOverview/SimulationPassesPerLhcPeriodOverviewModel.js index cfff1e3d23..ac2bd40ce8 100644 --- a/lib/public/views/SimulationPasses/PerLhcPeriodOverview/SimulationPassesPerLhcPeriodOverviewModel.js +++ b/lib/public/views/SimulationPasses/PerLhcPeriodOverview/SimulationPassesPerLhcPeriodOverviewModel.js @@ -64,7 +64,7 @@ export class SimulationPassesPerLhcPeriodOverviewModel extends OverviewPageModel * @param {boolean} notify if the FilteringModel should notify it's observers after finishing setting the filters */ setFilterFromURL(notify) { - this._filteringModelsetFilterFromURL(null, notify); + this._filteringModel.setFilterFromURL(null, notify); } /** diff --git a/lib/public/views/SimulationPasses/SimulationPassesModel.js b/lib/public/views/SimulationPasses/SimulationPassesModel.js index 5a0a9a7d17..8ba624efd8 100644 --- a/lib/public/views/SimulationPasses/SimulationPassesModel.js +++ b/lib/public/views/SimulationPasses/SimulationPassesModel.js @@ -42,7 +42,7 @@ export class SimulationPassesModel extends Observable { loadPerLhcPeriodOverview({ lhcPeriodId }) { if (!this._perLhcPeriodOverviewModel.pagination.isInfiniteScrollEnabled) { this._perLhcPeriodOverviewModel.lhcPeriodId = lhcPeriodId; - this._perLhcPeriodOverviewModel.setFilterFromUrl(null, false); + this._perLhcPeriodOverviewModel.setFilterFromURL(false); this._perLhcPeriodOverviewModel.load(); } } @@ -72,7 +72,7 @@ export class SimulationPassesModel extends Observable { */ loadAnchoredOverview({ dataPassId }) { this._anchoredOverviewModel.dataPassId = dataPassId; - this._anchoredOverviewModel.setFilterFromUrl(null, false); + this._anchoredOverviewModel.setFilterFromURL(false); this._anchoredOverviewModel.load(); } diff --git a/lib/public/views/lhcPeriods/LhcPeriodsModel.js b/lib/public/views/lhcPeriods/LhcPeriodsModel.js index a7e7da7385..74df7b9dc7 100644 --- a/lib/public/views/lhcPeriods/LhcPeriodsModel.js +++ b/lib/public/views/lhcPeriods/LhcPeriodsModel.js @@ -35,7 +35,7 @@ export class LhcPeriodsModel extends Observable { * @returns {void} */ loadOverview() { - this._overviewModel.setFilterFromUrl(null, false); + this._overviewModel.setFilterFromURL(false); this._overviewModel.load(); } diff --git a/lib/public/views/lhcPeriods/Overview/LhcPeriodsOverviewModel.js b/lib/public/views/lhcPeriods/Overview/LhcPeriodsOverviewModel.js index f29e39ad5a..3d2f4dad19 100644 --- a/lib/public/views/lhcPeriods/Overview/LhcPeriodsOverviewModel.js +++ b/lib/public/views/lhcPeriods/Overview/LhcPeriodsOverviewModel.js @@ -61,7 +61,7 @@ export class LhcPeriodsOverviewModel extends OverviewPageModel { * @param {boolean} notify if the FilteringModel should notify it's observers after finishing setting the filters */ setFilterFromURL(notify) { - this._filteringModelsetFilterFromURL(null, notify); + this._filteringModel.setFilterFromURL(null, notify); } /** From 5abae211ad0101deefcdef1531edfd366f8d5b33 Mon Sep 17 00:00:00 2001 From: NarrowsProjects Date: Wed, 17 Jun 2026 12:56:51 +0200 Subject: [PATCH 8/8] chore: switch url and notify arguments --- lib/public/components/Filters/common/FilteringModel.js | 2 +- lib/public/components/Filters/common/filtersPanelPopover.js | 2 +- lib/public/views/DataPasses/DataPassesOverviewModel.js | 2 +- .../views/Environments/Overview/EnvironmentOverviewModel.js | 2 +- lib/public/views/LhcFills/Overview/LhcFillsOverviewModel.js | 2 +- lib/public/views/Logs/Overview/LogsOverviewModel.js | 2 +- .../views/QcFlagTypes/Overview/QcFlagTypesOverviewModel.js | 2 +- lib/public/views/Runs/Overview/RunsOverviewModel.js | 2 +- .../AnchoredOverview/AnchoredSimulationPassesOverviewModel.js | 2 +- .../SimulationPassesPerLhcPeriodOverviewModel.js | 2 +- lib/public/views/lhcPeriods/Overview/LhcPeriodsOverviewModel.js | 2 +- 11 files changed, 11 insertions(+), 11 deletions(-) diff --git a/lib/public/components/Filters/common/FilteringModel.js b/lib/public/components/Filters/common/FilteringModel.js index ed543247bc..7cf22e9065 100644 --- a/lib/public/components/Filters/common/FilteringModel.js +++ b/lib/public/components/Filters/common/FilteringModel.js @@ -168,7 +168,7 @@ export class FilteringModel extends Observable { * @param {string|null} [url=null] the url that is to be parsed into active filters * @returns {undefined} */ - setFilterFromURL(url = null, notify = false) { + setFilterFromURL(notify = false, url = null) { const params = this._computeParameters(url); const { page, filter } = params; diff --git a/lib/public/components/Filters/common/filtersPanelPopover.js b/lib/public/components/Filters/common/filtersPanelPopover.js index ee5a370fdf..7146d1add7 100644 --- a/lib/public/components/Filters/common/filtersPanelPopover.js +++ b/lib/public/components/Filters/common/filtersPanelPopover.js @@ -161,7 +161,7 @@ const pasteButtonOption = (model) => { return h('button.btn.btn-primary', { onclick: async () => { const url = await navigator.clipboard.readText(); - filteringModel.setFilterFromURL(url, true); + filteringModel.setFilterFromURL(true, url); }, disabled: !clipboardSupported, id: 'paste-filter', diff --git a/lib/public/views/DataPasses/DataPassesOverviewModel.js b/lib/public/views/DataPasses/DataPassesOverviewModel.js index ca6c058220..2834e1db1d 100644 --- a/lib/public/views/DataPasses/DataPassesOverviewModel.js +++ b/lib/public/views/DataPasses/DataPassesOverviewModel.js @@ -61,7 +61,7 @@ export class DataPassesOverviewModel extends OverviewPageModel { * @param {boolean} notify if the FilteringModel should notify it's observers after finishing setting the filters */ setFilterFromURL(notify) { - this._filteringModel.setFilterFromURL(null, notify); + this._filteringModel.setFilterFromURL(notify); } /** diff --git a/lib/public/views/Environments/Overview/EnvironmentOverviewModel.js b/lib/public/views/Environments/Overview/EnvironmentOverviewModel.js index 49a06d8758..5d6eb72cb3 100644 --- a/lib/public/views/Environments/Overview/EnvironmentOverviewModel.js +++ b/lib/public/views/Environments/Overview/EnvironmentOverviewModel.js @@ -76,7 +76,7 @@ export class EnvironmentOverviewModel extends OverviewPageModel { * @param {boolean} notify if the FilteringModel should notify it's observers after finishing setting the filters */ setFilterFromURL(notify) { - this._filteringModel.setFilterFromURL(null, notify); + this._filteringModel.setFilterFromURL(notify); } /** diff --git a/lib/public/views/LhcFills/Overview/LhcFillsOverviewModel.js b/lib/public/views/LhcFills/Overview/LhcFillsOverviewModel.js index b09fe7f00f..567182d3c5 100644 --- a/lib/public/views/LhcFills/Overview/LhcFillsOverviewModel.js +++ b/lib/public/views/LhcFills/Overview/LhcFillsOverviewModel.js @@ -80,7 +80,7 @@ export class LhcFillsOverviewModel extends OverviewPageModel { * @param {boolean} notify if the FilteringModel should notify it's observers after finishing setting the filters */ setFilterFromURL(notify) { - this._filteringModel.setFilterFromURL(null, notify); + this._filteringModel.setFilterFromURL(notify); } /** diff --git a/lib/public/views/Logs/Overview/LogsOverviewModel.js b/lib/public/views/Logs/Overview/LogsOverviewModel.js index 4f73a8cf98..f6fcb01638 100644 --- a/lib/public/views/Logs/Overview/LogsOverviewModel.js +++ b/lib/public/views/Logs/Overview/LogsOverviewModel.js @@ -86,7 +86,7 @@ export class LogsOverviewModel extends Observable { * @param {boolean} notify if the FilteringModel should notify it's observers after finishing setting the filters */ setFilterFromURL(notify) { - this._filteringModel.setFilterFromURL(null, notify); + this._filteringModel.setFilterFromURL(notify); } /** diff --git a/lib/public/views/QcFlagTypes/Overview/QcFlagTypesOverviewModel.js b/lib/public/views/QcFlagTypes/Overview/QcFlagTypesOverviewModel.js index 2e25d7b67b..a87baedaa5 100644 --- a/lib/public/views/QcFlagTypes/Overview/QcFlagTypesOverviewModel.js +++ b/lib/public/views/QcFlagTypes/Overview/QcFlagTypesOverviewModel.js @@ -61,7 +61,7 @@ export class QcFlagTypesOverviewModel extends OverviewPageModel { * @param {boolean} notify if the FilteringModel should notify it's observers after finishing setting the filters */ setFilterFromURL(notify) { - this._filteringModel.setFilterFromURL(null, notify); + this._filteringModel.setFilterFromURL(notify); } /** diff --git a/lib/public/views/Runs/Overview/RunsOverviewModel.js b/lib/public/views/Runs/Overview/RunsOverviewModel.js index 482e9a40d5..1b15fff0dc 100644 --- a/lib/public/views/Runs/Overview/RunsOverviewModel.js +++ b/lib/public/views/Runs/Overview/RunsOverviewModel.js @@ -168,7 +168,7 @@ export class RunsOverviewModel extends OverviewPageModel { * @param {boolean} notify if the FilteringModel should notify it's observers after finishing setting the filters */ setFilterFromURL(notify) { - this._filteringModel.setFilterFromURL(null, notify); + this._filteringModel.setFilterFromURL(notify); } /** diff --git a/lib/public/views/SimulationPasses/AnchoredOverview/AnchoredSimulationPassesOverviewModel.js b/lib/public/views/SimulationPasses/AnchoredOverview/AnchoredSimulationPassesOverviewModel.js index 20fc3b725f..810789c17f 100644 --- a/lib/public/views/SimulationPasses/AnchoredOverview/AnchoredSimulationPassesOverviewModel.js +++ b/lib/public/views/SimulationPasses/AnchoredOverview/AnchoredSimulationPassesOverviewModel.js @@ -48,7 +48,7 @@ export class AnchoredSimulationPassesOverviewModel extends OverviewPageModel { * @param {boolean} notify if the FilteringModel should notify it's observers after finishing setting the filters */ setFilterFromURL(notify) { - this._filteringModel.setFilterFromURL(null, notify); + this._filteringModel.setFilterFromURL(notify); } /** diff --git a/lib/public/views/SimulationPasses/PerLhcPeriodOverview/SimulationPassesPerLhcPeriodOverviewModel.js b/lib/public/views/SimulationPasses/PerLhcPeriodOverview/SimulationPassesPerLhcPeriodOverviewModel.js index ac2bd40ce8..ffc2eb5e02 100644 --- a/lib/public/views/SimulationPasses/PerLhcPeriodOverview/SimulationPassesPerLhcPeriodOverviewModel.js +++ b/lib/public/views/SimulationPasses/PerLhcPeriodOverview/SimulationPassesPerLhcPeriodOverviewModel.js @@ -64,7 +64,7 @@ export class SimulationPassesPerLhcPeriodOverviewModel extends OverviewPageModel * @param {boolean} notify if the FilteringModel should notify it's observers after finishing setting the filters */ setFilterFromURL(notify) { - this._filteringModel.setFilterFromURL(null, notify); + this._filteringModel.setFilterFromURL(notify); } /** diff --git a/lib/public/views/lhcPeriods/Overview/LhcPeriodsOverviewModel.js b/lib/public/views/lhcPeriods/Overview/LhcPeriodsOverviewModel.js index 3d2f4dad19..f517fe02e7 100644 --- a/lib/public/views/lhcPeriods/Overview/LhcPeriodsOverviewModel.js +++ b/lib/public/views/lhcPeriods/Overview/LhcPeriodsOverviewModel.js @@ -61,7 +61,7 @@ export class LhcPeriodsOverviewModel extends OverviewPageModel { * @param {boolean} notify if the FilteringModel should notify it's observers after finishing setting the filters */ setFilterFromURL(notify) { - this._filteringModel.setFilterFromURL(null, notify); + this._filteringModel.setFilterFromURL(notify); } /**