diff --git a/lib/public/components/Filters/QcFlagTypesFilter/bad.js b/lib/public/components/Filters/QcFlagTypesFilter/bad.js new file mode 100644 index 0000000000..7378d18d0d --- /dev/null +++ b/lib/public/components/Filters/QcFlagTypesFilter/bad.js @@ -0,0 +1,36 @@ +/** + * @license + * Copyright CERN and copyright holders of ALICE Trg. 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-Trg.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. + */ + +import { radioButton } from '../../common/form/inputs/radioButton.js'; +import { h } from '/js/src/index.js'; + +/** + * Radiobutton filter for the qcFlag 'bad' filter + * @param {SelectionModel} selectionModel the a selectionmodel + * @return {vnode} A number of radiobuttons corresponding with the selection options + */ +const badFilterRadioButtons = (selectionModel) => { + const name = 'badFilterRadio'; + return h( + '.form-group-header.flex-row.w-100', + selectionModel.options.map((option) => { + const { label } = option; + const action = () => selectionModel.select(option); + const isChecked = selectionModel.isSelected(option); + + return radioButton({ label, isChecked, action, name }); + }), + ); +}; + +export default badFilterRadioButtons; diff --git a/lib/public/components/common/selection/SelectionModel.js b/lib/public/components/common/selection/SelectionModel.js index 8b28aa28d1..18bbaf56eb 100644 --- a/lib/public/components/common/selection/SelectionModel.js +++ b/lib/public/components/common/selection/SelectionModel.js @@ -331,4 +331,16 @@ export class SelectionModel extends Observable { get optionsSelectedByDefault() { return this._defaultSelection; } + + /** + * Returns the normalized value of the selection + * + * @return {string|boolean|number} the normalized value + * @abstract + */ + get normalized() { + return (this._allowEmpty || this._multiple) + ? this._selectedOptions.join() + : this.current; + } } diff --git a/lib/public/views/QcFlagTypes/ActiveColumns/qcFlagTypesActiveColumns.js b/lib/public/views/QcFlagTypes/ActiveColumns/qcFlagTypesActiveColumns.js index 7f4ae8aa69..9bed5b35a6 100644 --- a/lib/public/views/QcFlagTypes/ActiveColumns/qcFlagTypesActiveColumns.js +++ b/lib/public/views/QcFlagTypes/ActiveColumns/qcFlagTypesActiveColumns.js @@ -14,8 +14,8 @@ import { h } from '/js/src/index.js'; import { formatTimestamp } from '../../../utilities/formatting/formatTimestamp.js'; import { textFilter } from '../../../components/Filters/common/filters/textFilter.js'; -import { checkboxes } from '../../../components/Filters/common/filters/checkboxFilter.js'; import { qcFlagTypeColoredBadge } from '../../../components/qcFlags/qcFlagTypeColoredBadge.js'; +import badFilterRadioButtons from '../../../components/Filters/QcFlagTypesFilter/bad.js'; /** * List of active columns for a QC Flag Types table @@ -30,8 +30,8 @@ export const qcFlagTypesActiveColumns = { name: { name: 'Name', visible: true, - filter: ({ namesFilterModel }) => textFilter( - namesFilterModel, + filter: ({ filteringModel }) => textFilter( + filteringModel.get('names'), { class: 'w-75 mt1', placeholder: 'e.g. BadPID, ...' }, ), classes: 'f6', @@ -43,8 +43,8 @@ export const qcFlagTypesActiveColumns = { name: 'Method', visible: true, sortable: true, - filter: ({ methodsFilterModel }) => textFilter( - methodsFilterModel, + filter: ({ filteringModel }) => textFilter( + filteringModel.get('methods'), { class: 'w-75 mt1', placeholder: 'e.g. Bad PID, ...' }, ), classes: 'f6', @@ -54,10 +54,7 @@ export const qcFlagTypesActiveColumns = { name: 'Bad', visible: true, sortable: true, - filter: ({ isBadFilterModel }) => checkboxes( - isBadFilterModel, - { class: 'w-75 mt1', selector: 'qc-flag-type-bad-filter' }, - ), + filter: ({ filteringModel }) => badFilterRadioButtons(filteringModel.get('bad')), classes: 'f6 w-5', format: (bad) => bad ? h('.danger', 'Yes') : h('.success', 'No'), }, diff --git a/lib/public/views/QcFlagTypes/Overview/QcFlagTypesOverviewModel.js b/lib/public/views/QcFlagTypes/Overview/QcFlagTypesOverviewModel.js index 6c80ada996..cc4ced6716 100644 --- a/lib/public/views/QcFlagTypes/Overview/QcFlagTypesOverviewModel.js +++ b/lib/public/views/QcFlagTypes/Overview/QcFlagTypesOverviewModel.js @@ -15,6 +15,7 @@ import { TextTokensFilterModel } from '../../../components/Filters/common/filter import { OverviewPageModel } from '../../../models/OverviewModel.js'; import { SelectionModel } from '../../../components/common/selection/SelectionModel.js'; import { buildUrl } from '/js/src/index.js'; +import { FilteringModel } from '../../../components/Filters/common/FilteringModel.js'; /** * QcFlagTypesOverviewModel @@ -26,73 +27,39 @@ export class QcFlagTypesOverviewModel extends OverviewPageModel { constructor() { super(); - this._namesFilterModel = new TextTokensFilterModel(); - this._registerFilter(this._namesFilterModel); - this._methodsFilterModel = new TextTokensFilterModel(); - this._registerFilter(this._methodsFilterModel); - this._isBadFilterModel = - new SelectionModel({ availableOptions: [{ label: 'Bad', value: true }, { label: 'Not Bad', value: false }] }); - this._registerFilter(this._isBadFilterModel); - } - - /** - * @inheritdoc - */ - getRootEndpoint() { - const params = {}; - if (this.isAnyFilterActive()) { - params.filter = { - names: this._namesFilterModel.normalized, - methods: this._methodsFilterModel.normalized, - bad: this._isBadFilterModel.selected.length === 2 - ? undefined - : this._isBadFilterModel.selected[0], - }; - } - - return buildUrl('/api/qcFlagTypes', params); - } + this._filteringModel = new FilteringModel({ + names: new TextTokensFilterModel(), + methods: new TextTokensFilterModel(), + bad: new SelectionModel({ + availableOptions: [{ label: 'Any' }, { label: 'Bad', value: true }, { label: 'Not Bad', value: false }], + defaultSelection: [{ label: 'Any' }], + allowEmpty: false, + multiple: false, + }), + }); - /** - * Get names filter model - * - * @return {TextTokensFilterModel} names filter model - */ - get namesFilterModel() { - return this._namesFilterModel; - } + this._filteringModel.observe(() => { + this._pagination.silentlySetCurrentPage(1); + this.load(); + }); - /** - * Get methods filter model - * - * @return {TextTokensFilterModel} methods filter model - */ - get methodsFilterModel() { - return this._methodsFilterModel; + this._filteringModel.visualChange$.bubbleTo(this); } /** - * Returns filter model for filtering bad and not bad flags - * - * @return {TextTokensFilterModel} filter model for filtering bad and not bad flags + * @inheritdoc */ - get isBadFilterModel() { - return this._isBadFilterModel; + getRootEndpoint() { + return buildUrl('/api/qcFlagTypes', { filter: this._filteringModel.normalized }); } /** - * Register a new filter model + * Return the model managing all filters * - * @param {FilterModel} filterModel the filter model to register - * @return {void} - * @private + * @return {FilteringModel} the filtering model */ - _registerFilter(filterModel) { - filterModel.visualChange$.bubbleTo(this); - filterModel.observe(() => { - this._pagination.silentlySetCurrentPage(1); - this.load(); - }); + get filteringModel() { + return this._filteringModel; } /** @@ -101,7 +68,7 @@ export class QcFlagTypesOverviewModel extends OverviewPageModel { * @return {boolean} true if any filter is active */ isAnyFilterActive() { - return !this._namesFilterModel.isEmpty || !this._methodsFilterModel.isEmpty || this._isBadFilterModel.selected.length; + return this._filteringModel.isAnyFilterActive(); } /** @@ -110,9 +77,7 @@ export class QcFlagTypesOverviewModel extends OverviewPageModel { * @returns {void} */ reset() { - this._methodsFilterModel.reset(); - this._namesFilterModel.reset(); - this._isBadFilterModel.reset(); + this._filteringModel.reset(); super.reset(); } } diff --git a/test/public/qcFlagTypes/overview.test.js b/test/public/qcFlagTypes/overview.test.js index 0bf4d519cc..77b4fe656b 100644 --- a/test/public/qcFlagTypes/overview.test.js +++ b/test/public/qcFlagTypes/overview.test.js @@ -112,7 +112,7 @@ module.exports = () => { it('should successfully apply QC flag type bad filter', async () => { await waitForTableLength(page, 7); - await pressElement(page, '.bad-filter input[type=checkbox]', true); + await pressElement(page, '#badFilterRadioBad', true); await checkColumnValuesWithRegex(page, 'bad', '^Yes$'); await pressElement(page, '#reset-filters', true);