From 8dbbce91c1e8c5bd86df2892be1d60b4d0178f34 Mon Sep 17 00:00:00 2001 From: NarrowsProjects Date: Thu, 30 Apr 2026 12:28:32 +0200 Subject: [PATCH 1/6] create: activeFilterIndicator --- lib/public/app.css | 27 +++++++++++++++++++ .../Filters/common/filtersPanelPopover.js | 16 +++++++++++ 2 files changed, 43 insertions(+) diff --git a/lib/public/app.css b/lib/public/app.css index bb67bc66bd..e33f0cdf52 100644 --- a/lib/public/app.css +++ b/lib/public/app.css @@ -718,6 +718,33 @@ label { opacity: 0.5; } +.active-filters-indicator { + border-radius: .25rem; + padding: var(--space-xs) var(--space-s) var(--space-xs) var(--space-s); + margin: 0 0 0 var(--space-s); +} + +.inactive { + opacity: 0.5; + pointer-events: none; +} + +.pulse-green { + animation: pulseGreen 2s infinite; +} + +@keyframes pulseGreen { + 0% { + box-shadow: 0 0 0px rgba(102, 255, 7, 0.6); + } + 50% { + box-shadow: 0 0 10px rgba(102, 255, 7, 0.9); + } + 100% { + box-shadow: 0 0 0px rgba(102, 255, 7, 0.6); + } +} + /** * Breakpoints : * small : x < 600 (default styles) diff --git a/lib/public/components/Filters/common/filtersPanelPopover.js b/lib/public/components/Filters/common/filtersPanelPopover.js index 171dda6e8d..4a916a46eb 100644 --- a/lib/public/components/Filters/common/filtersPanelPopover.js +++ b/lib/public/components/Filters/common/filtersPanelPopover.js @@ -168,6 +168,21 @@ const pasteButtonOption = (model) => { }, 'Paste filters'); }; +/** + * A indicates if any filters are currently active on the page + * + * @param {boolean} activeFilters if true, component will turn green and glow + * @returns {Component} the active filters indicator + */ +const activeFilterIndicator = (activeFilters) => { + const innerText = `Filters ${activeFilters ? 'Active' : 'Inactive'}`; + + let element = '.active-filters-indicator.b1'; + element += activeFilters ? '.pulse-green.b-success.success' : '.inactive'; + + return h(element, innerText); +}; + /** * Return component composed of the filter popover button and a dropdown trigger * @@ -195,6 +210,7 @@ export const filtersPanelPopover = (filteringModel, filtersConfiguration, config ], ), ), + activeFilterIndicator(hasActiveFilters), ], ); }; From c70e064d71e3ad4985bc15dee22f816bfd5c277a Mon Sep 17 00:00:00 2001 From: NarrowsProjects Date: Mon, 18 May 2026 12:30:44 +0200 Subject: [PATCH 2/6] feat: add filter clear button to the right side --- lib/public/app.css | 19 ++++++++++ .../Filters/common/filtersPanelPopover.js | 38 ++++++++++++------- 2 files changed, 43 insertions(+), 14 deletions(-) diff --git a/lib/public/app.css b/lib/public/app.css index e33f0cdf52..77f2215862 100644 --- a/lib/public/app.css +++ b/lib/public/app.css @@ -724,6 +724,25 @@ label { margin: 0 0 0 var(--space-s); } +.active-filters-indicator:has(+ .clear-filter-icon) { + border-right: 0; + border-radius: .25rem 0 0 .25rem +} + +.clear-filter-icon { + background-color: white; + border-radius: 0 .25rem .25rem 0; + color: var(--color-danger); + padding: var(--space-xs); + font-weight: 700; + cursor: pointer; +} + +.clear-filter-icon:hover { + background-color: var(--color-danger); + color: white; +} + .inactive { opacity: 0.5; pointer-events: none; diff --git a/lib/public/components/Filters/common/filtersPanelPopover.js b/lib/public/components/Filters/common/filtersPanelPopover.js index 4a916a46eb..b81cfaaa80 100644 --- a/lib/public/components/Filters/common/filtersPanelPopover.js +++ b/lib/public/components/Filters/common/filtersPanelPopover.js @@ -11,7 +11,7 @@ * or submit itself to any jurisdiction. */ import { h, info, popover, PopoverAnchors, PopoverTriggerPreConfiguration, DropdownComponent, CopyToClipboardComponent } from '/js/src/index.js'; -import { iconCaretBottom } from '/js/src/icons.js'; +import { iconCaretBottom, iconX } 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'; @@ -42,18 +42,21 @@ const filtersToggleTrigger = () => h('button#openFilterToggle.btn.btn.btn-primar * Button component that resets all filters upon click * * @param {FilteringModel|OverviewPageModel} filteringModel the FilteringModel + * @param {bool} [filteringModel=false] if the component is rendered as a regular button with text or as a component with an 'X' icon * @returns {Component} the reset button component */ -const resetFiltersButton = (filteringModel) => h( - 'button#reset-filters.btn.btn-danger', - { +const resetFiltersButton = (filteringModel, isIcon = false) => { + const attributes = { disabled: !filteringModel.isAnyFilterActive(), onclick: () => filteringModel.resetFiltering ? filteringModel.resetFiltering(true, true) : filteringModel.reset(true, true), - }, - 'Reset all filters', -); + }; + + return isIcon + ? h('.clear-filter-icon.b1.b-danger.btn-group-item.last-item', attributes, 'X') + : h('button#reset-filters.btn.btn-danger', attributes, 'Reset all filters'); +} /** * Create main header of the filters panel @@ -171,16 +174,23 @@ const pasteButtonOption = (model) => { /** * A indicates if any filters are currently active on the page * - * @param {boolean} activeFilters if true, component will turn green and glow + * @param {FilteringModel} filteringModel the filtering model * @returns {Component} the active filters indicator */ -const activeFilterIndicator = (activeFilters) => { - const innerText = `Filters ${activeFilters ? 'Active' : 'Inactive'}`; +const activeFilterIndicator = (filteringModel) => { + const hasActiveFilters = filteringModel.isAnyFilterActive() + const innerText = `Filters ${hasActiveFilters ? 'Active' : 'Inactive'}`; + + let indicator = '.active-filters-indicator.b1'; + indicator += hasActiveFilters ? '.b-success.success.pulse-green' : '.inactive'; - let element = '.active-filters-indicator.b1'; - element += activeFilters ? '.pulse-green.b-success.success' : '.inactive'; + const children = [h(indicator, innerText)]; - return h(element, innerText); + if (hasActiveFilters) { + children.push(resetFiltersButton(filteringModel, true)) + } + + return h('.flex-row.items-center', children); }; /** @@ -210,7 +220,7 @@ export const filtersPanelPopover = (filteringModel, filtersConfiguration, config ], ), ), - activeFilterIndicator(hasActiveFilters), + activeFilterIndicator(filteringModel), ], ); }; From 505156db96957b324a4d3ad951c39bbe85adea55 Mon Sep 17 00:00:00 2001 From: NarrowsProjects Date: Wed, 27 May 2026 16:24:04 +0200 Subject: [PATCH 3/6] improve pulse color seperation --- lib/public/app.css | 30 ++++++++++++++----- .../Filters/common/filtersPanelPopover.js | 4 +-- 2 files changed, 25 insertions(+), 9 deletions(-) diff --git a/lib/public/app.css b/lib/public/app.css index 77f2215862..11c643f80d 100644 --- a/lib/public/app.css +++ b/lib/public/app.css @@ -719,6 +719,9 @@ label { } .active-filters-indicator { + position: relative; + z-index: 10; + background-color: white; border-radius: .25rem; padding: var(--space-xs) var(--space-s) var(--space-xs) var(--space-s); margin: 0 0 0 var(--space-s); @@ -733,12 +736,19 @@ label { background-color: white; border-radius: 0 .25rem .25rem 0; color: var(--color-danger); - padding: var(--space-xs); font-weight: 700; cursor: pointer; } -.clear-filter-icon:hover { +.clear-filter-icon > * { + padding: var(--space-xs); + background-color: white; + position: relative; + border-radius: 0 .25rem .25rem 0; + z-index: 10; +} + +.clear-filter-icon > *:hover { background-color: var(--color-danger); color: white; } @@ -749,18 +759,24 @@ label { } .pulse-green { - animation: pulseGreen 2s infinite; + --pulse-color: 102, 255, 7; + animation: pulse 2s infinite; +} + +.pulse-red { + --pulse-color: 206, 42, 42; + animation: pulse 2s infinite; } -@keyframes pulseGreen { +@keyframes pulse { 0% { - box-shadow: 0 0 0px rgba(102, 255, 7, 0.6); + box-shadow: 0 0 0px rgba(var(--pulse-color), 0.6); } 50% { - box-shadow: 0 0 10px rgba(102, 255, 7, 0.9); + box-shadow: 0 0 10px rgba(var(--pulse-color), 0.9); } 100% { - box-shadow: 0 0 0px rgba(102, 255, 7, 0.6); + box-shadow: 0 0 0px rgba(var(--pulse-color), 0.6); } } diff --git a/lib/public/components/Filters/common/filtersPanelPopover.js b/lib/public/components/Filters/common/filtersPanelPopover.js index b81cfaaa80..30df9db94c 100644 --- a/lib/public/components/Filters/common/filtersPanelPopover.js +++ b/lib/public/components/Filters/common/filtersPanelPopover.js @@ -54,7 +54,7 @@ const resetFiltersButton = (filteringModel, isIcon = false) => { }; return isIcon - ? h('.clear-filter-icon.b1.b-danger.btn-group-item.last-item', attributes, 'X') + ? h('.clear-filter-icon.b1.b-danger.btn-group-item.last-item.pulse-red', attributes, [h('', 'X')]) : h('button#reset-filters.btn.btn-danger', attributes, 'Reset all filters'); } @@ -184,7 +184,7 @@ const activeFilterIndicator = (filteringModel) => { let indicator = '.active-filters-indicator.b1'; indicator += hasActiveFilters ? '.b-success.success.pulse-green' : '.inactive'; - const children = [h(indicator, innerText)]; + const children = [h(indicator, h('', innerText))]; if (hasActiveFilters) { children.push(resetFiltersButton(filteringModel, true)) From 8170a80941889eb1a52d359ce198c977874d6222 Mon Sep 17 00:00:00 2001 From: NarrowsProjects Date: Thu, 18 Jun 2026 12:22:51 +0200 Subject: [PATCH 4/6] refactor: improve style readability --- lib/public/app.css | 10 +++++----- .../Filters/common/filtersPanelPopover.js | 14 +++++++------- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/lib/public/app.css b/lib/public/app.css index 11c643f80d..0e88f93174 100644 --- a/lib/public/app.css +++ b/lib/public/app.css @@ -727,28 +727,28 @@ label { margin: 0 0 0 var(--space-s); } -.active-filters-indicator:has(+ .clear-filter-icon) { +.active-filters-indicator:has(+ .clear-filter-icon-container) { border-right: 0; border-radius: .25rem 0 0 .25rem } -.clear-filter-icon { +.clear-filter-icon-container { background-color: white; border-radius: 0 .25rem .25rem 0; - color: var(--color-danger); font-weight: 700; cursor: pointer; } -.clear-filter-icon > * { +.clear-filter-icon { padding: var(--space-xs); background-color: white; + color: var(--color-danger); position: relative; border-radius: 0 .25rem .25rem 0; z-index: 10; } -.clear-filter-icon > *:hover { +.clear-filter-icon:hover { background-color: var(--color-danger); color: white; } diff --git a/lib/public/components/Filters/common/filtersPanelPopover.js b/lib/public/components/Filters/common/filtersPanelPopover.js index 30df9db94c..775c48c933 100644 --- a/lib/public/components/Filters/common/filtersPanelPopover.js +++ b/lib/public/components/Filters/common/filtersPanelPopover.js @@ -11,7 +11,7 @@ * or submit itself to any jurisdiction. */ import { h, info, popover, PopoverAnchors, PopoverTriggerPreConfiguration, DropdownComponent, CopyToClipboardComponent } from '/js/src/index.js'; -import { iconCaretBottom, iconX } from '/js/src/icons.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'; @@ -54,9 +54,9 @@ const resetFiltersButton = (filteringModel, isIcon = false) => { }; return isIcon - ? h('.clear-filter-icon.b1.b-danger.btn-group-item.last-item.pulse-red', attributes, [h('', 'X')]) + ? h('.clear-filter-icon-container.btn-group-item.last-item.pulse-red', attributes, h('.clear-filter-icon.b1.b-danger', 'X')) : h('button#reset-filters.btn.btn-danger', attributes, 'Reset all filters'); -} +}; /** * Create main header of the filters panel @@ -178,18 +178,18 @@ const pasteButtonOption = (model) => { * @returns {Component} the active filters indicator */ const activeFilterIndicator = (filteringModel) => { - const hasActiveFilters = filteringModel.isAnyFilterActive() + const hasActiveFilters = filteringModel.isAnyFilterActive(); const innerText = `Filters ${hasActiveFilters ? 'Active' : 'Inactive'}`; let indicator = '.active-filters-indicator.b1'; indicator += hasActiveFilters ? '.b-success.success.pulse-green' : '.inactive'; - const children = [h(indicator, h('', innerText))]; + const children = [h(indicator, innerText)]; if (hasActiveFilters) { - children.push(resetFiltersButton(filteringModel, true)) + children.push(resetFiltersButton(filteringModel, true)); } - + return h('.flex-row.items-center', children); }; From f257e4980f169f99567cc9096041bab294c6abf8 Mon Sep 17 00:00:00 2001 From: NarrowsProjects Date: Thu, 18 Jun 2026 12:37:52 +0200 Subject: [PATCH 5/6] fix issue of mcReproducible always being active --- .../components/Filters/common/filtersPanelPopover.js | 7 +++++-- lib/public/views/Runs/Overview/RunsWithQcModel.js | 2 +- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/lib/public/components/Filters/common/filtersPanelPopover.js b/lib/public/components/Filters/common/filtersPanelPopover.js index 775c48c933..1cc666215c 100644 --- a/lib/public/components/Filters/common/filtersPanelPopover.js +++ b/lib/public/components/Filters/common/filtersPanelPopover.js @@ -174,10 +174,13 @@ const pasteButtonOption = (model) => { /** * A indicates if any filters are currently active on the page * - * @param {FilteringModel} filteringModel the filtering model + * @param {FilteringModel} model the filtering model * @returns {Component} the active filters indicator */ -const activeFilterIndicator = (filteringModel) => { +const activeFilterIndicator = (model) => { + // Sometimes, the overview model is passed to filterPanelPopover instead of the filteringmodel (e.g. envirionments) + const { filteringModel = model } = model; + const hasActiveFilters = filteringModel.isAnyFilterActive(); const innerText = `Filters ${hasActiveFilters ? 'Active' : 'Inactive'}`; diff --git a/lib/public/views/Runs/Overview/RunsWithQcModel.js b/lib/public/views/Runs/Overview/RunsWithQcModel.js index cc1687cf30..e9ec4f36c5 100644 --- a/lib/public/views/Runs/Overview/RunsWithQcModel.js +++ b/lib/public/views/Runs/Overview/RunsWithQcModel.js @@ -78,7 +78,7 @@ export class RunsWithQcModel extends RunsOverviewModel { this._observablesQcFlagsSummaryDependsOn$ = null; // This filter instance will be added as a sub-filter for a MultiCompositionFilter and a GaqFilter later. - this._mcReproducibleAsNotBad = new ToggleFilterModel(); + this._mcReproducibleAsNotBad = new ToggleFilterModel(false, true); this._runDetectorsSelectionModel = new RunDetectorsSelectionModel(); this._runDetectorsSelectionModel.bubbleTo(this); From c8a1e4044e024edfc13d3cde139b116c1671b9c0 Mon Sep 17 00:00:00 2001 From: NarrowsProjects Date: Thu, 18 Jun 2026 13:23:29 +0200 Subject: [PATCH 6/6] fix documentation for resetbutton --- lib/public/components/Filters/common/filtersPanelPopover.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/public/components/Filters/common/filtersPanelPopover.js b/lib/public/components/Filters/common/filtersPanelPopover.js index 1cc666215c..648427db34 100644 --- a/lib/public/components/Filters/common/filtersPanelPopover.js +++ b/lib/public/components/Filters/common/filtersPanelPopover.js @@ -42,7 +42,7 @@ const filtersToggleTrigger = () => h('button#openFilterToggle.btn.btn.btn-primar * Button component that resets all filters upon click * * @param {FilteringModel|OverviewPageModel} filteringModel the FilteringModel - * @param {bool} [filteringModel=false] if the component is rendered as a regular button with text or as a component with an 'X' icon + * @param {bool} [isIcon=false] if the component is rendered as a regular button with text or as a component with an 'X' icon * @returns {Component} the reset button component */ const resetFiltersButton = (filteringModel, isIcon = false) => {