Skip to content

Commit

Permalink
Factorize checkboxes/radio display
Browse files Browse the repository at this point in the history
  • Loading branch information
martinboulais committed Feb 3, 2025
1 parent 2d92f12 commit df6208d
Show file tree
Hide file tree
Showing 6 changed files with 89 additions and 81 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -11,15 +11,15 @@
* or submit itself to any jurisdiction.
*/

import { checkboxes } from '../common/filters/checkboxFilter.js';
import { expandedSelectionFilter } from '../common/filters/checkboxFilter.js';

/**
* 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
*/
export const runDefinitionFilter = (runDefinitionFilterModel) => checkboxes(
export const runDefinitionFilter = (runDefinitionFilterModel) => expandedSelectionFilter(

Check warning on line 22 in lib/public/components/Filters/RunsFilter/runDefinitionFilter.js

View check run for this annotation

Codecov / codecov/patch

lib/public/components/Filters/RunsFilter/runDefinitionFilter.js#L22

Added line #L22 was not covered by tests
runDefinitionFilterModel.selectionModel,
{ selector: 'run-definition' },
);
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,12 @@
* or submit itself to any jurisdiction.
*/

import { checkboxes } from '../common/filters/checkboxFilter.js';
import { expandedSelectionFilter } from '../common/filters/checkboxFilter.js';

/**
* Renders a list of checkboxes that lets the user look for runs with specific quality
*
* @param {SelectionFilterModel} filterModel run quality filter model
* @return {Component} the filter component
*/
export const runQualitiesFilter = (filterModel) => checkboxes(filterModel.selectionModel);
export const runQualitiesFilter = (filterModel) => expandedSelectionFilter(filterModel.selectionModel);

Check warning on line 22 in lib/public/components/Filters/RunsFilter/runQualitiesFilter.js

View check run for this annotation

Codecov / codecov/patch

lib/public/components/Filters/RunsFilter/runQualitiesFilter.js#L22

Added line #L22 was not covered by tests
21 changes: 5 additions & 16 deletions lib/public/components/Filters/common/filters/checkboxFilter.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
*/

import { h } from '/js/src/index.js';
import { selectionOptions } from '../../../common/selection/selectionOptions.js';

/**
* A general component for generating checkboxes.
Expand Down Expand Up @@ -47,19 +48,7 @@ export const checkboxFilter = (name, values, isChecked, onChange, additionalProp
* @param {string} [additionalProperties.selector] input identifiers prefix
* @return {Component} filter component
*/
export const checkboxes = (selectionModel, additionalProperties = {}) => {
const { selector = 'checkboxes' } = additionalProperties;

return h('.flex-row.flex-wrap', selectionModel.options.map((option) => h('.form-check.flex-grow', [
h('input.form-check-input', {
id: `${selector}-checkbox-${option.value}`,
type: 'checkbox',
checked: selectionModel.isSelected(option),
onchange: () => selectionModel.isSelected(option) ? selectionModel.deselect(option) : selectionModel.select(option),
...additionalProperties,
}),
h('label.form-check-label', {
for: `${selector}-checkbox-${option.value}`,
}, option.label || option.value),
])));
};
export const expandedSelectionFilter = (selectionModel, additionalProperties = {}) => h(

Check warning on line 51 in lib/public/components/Filters/common/filters/checkboxFilter.js

View check run for this annotation

Codecov / codecov/patch

lib/public/components/Filters/common/filters/checkboxFilter.js#L51

Added line #L51 was not covered by tests
'.flex-row.flex-wrap.gc3',
selectionOptions(selectionModel, { selectorPrefix: additionalProperties.selector }),
);
Original file line number Diff line number Diff line change
Expand Up @@ -15,64 +15,7 @@ import { h, Observable } from '/js/src/index.js';
import spinner from '../../spinner.js';
import { cleanPrefix } from '../../../../utilities/cleanPrefix.js';
import { dropdown } from '../../popover/dropdown.js';
import { filterSelectionOptions } from '../filterSelectionOptions.js';

/**
* Display the dropdown options component containing the search input ahd the available options
*
* @param {SelectionModel} selectionModel the selection model
* @param {string} filter eventual filter used to show only a subset of options
* @param {string} selectorPrefix the prefix used to generate DOM selectors
* @return {Component} the dropdown options component
*/
const filteredDropdownOptions = (selectionModel, filter, selectorPrefix) => {
/**
* Display a given option
*
* @param {SelectionOption} option the option to display
* @param {string} [selectorPrefix] prefix used to generate DOM selectors for the component
* @return {Component} the option's view
*/
const displayOption = (option, selectorPrefix) => {
const selector = option.selector ?? option.value;

return h(
'label.dropdown-option.form-check-label.flex-row.g2.ph2.pv1',
{ key: selector },
[
h(
`input#${selectorPrefix}dropdown-option-${selector}`,
{
type: selectionModel.multiple || selectionModel.allowEmpty ? 'checkbox' : 'radio',
name: `${selectorPrefix}dropdown-option-${selectionModel.multiple ? selector : 'group'}`,
checked: selectionModel.isSelected(option),
onchange: (e) => e.target.checked ? selectionModel.select(option) : selectionModel.deselect(option),
},
),
option.label || option.value,
],
);
};

/**
* Displays the list of available options
*
* @param {SelectionOption[]} availableOptions the list of all the available options
* @return {Component} the options list
*/
const optionsList = (availableOptions) => {
if (availableOptions.length === 0) {
return h('.ph2.pv1', h('em', 'No options'));
}

return availableOptions.map((option) => displayOption(
option,
selectorPrefix,
));
};

return h('.dropdown-options', optionsList(filterSelectionOptions(selectionModel.options, filter)));
};
import { selectionOptions } from '../selectionOptions.js';

/**
* Display a selection component composed of a view of current selection plus a dropdown displaying available options
Expand Down Expand Up @@ -151,7 +94,18 @@ export const selectionDropdown = (selectionDropdownModel, configuration) => {
selectionDropdownModel.selectionModel.match({
NotAsked: () => null,
Loading: () => spinner({ size: 2, absolute: false }),
Success: (selectionModel) => filteredDropdownOptions(selectionModel, selectionDropdownModel.searchInputContent, selectorPrefix),
Success: (selectionModel) => h(

Check warning on line 97 in lib/public/components/common/selection/dropdown/selectionDropdown.js

View check run for this annotation

Codecov / codecov/patch

lib/public/components/common/selection/dropdown/selectionDropdown.js#L95-L97

Added lines #L95 - L97 were not covered by tests
'.dropdown-options',
selectionOptions(
selectionModel,
{
filter: selectionDropdownModel.searchInputContent,
placeholder: h('.ph2.pv1', h('em', 'No options')),
selectorPrefix,
labelClasses: ['dropdown-option', 'ph2', 'pv1'],
},
),
),
Failure: () => null,

Check warning on line 109 in lib/public/components/common/selection/dropdown/selectionDropdown.js

View check run for this annotation

Codecov / codecov/patch

lib/public/components/common/selection/dropdown/selectionDropdown.js#L109

Added line #L109 was not covered by tests
}),
],
Expand Down
65 changes: 65 additions & 0 deletions lib/public/components/common/selection/selectionOptions.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
/**
* @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.
*/

import { cleanPrefix } from '../../../utilities/cleanPrefix.js';
import { filterSelectionOptions } from './filterSelectionOptions.js';
import { h } from '/js/src/index.js';

/**
* Display the options of the given selection model
*
* @param {SelectionModel} selectionModel the selection model
* @param {object} [configuration] eventual configuration
* @param {string} [configuration.filter] if specified, only options with label (or value if no label) including this filter will be displayed
* @param {Component} [configuration.placeholder] if specified, this component will be returned if there is no option to display
* @param {string} [configuration.selectorPrefix] prefix to be used to construct elements selectors
* @param {string[]} [configuration.labelClasses] additional classes applied to label
* @return {Component} filter component
*/
export const selectionOptions = (selectionModel, configuration) => {
const { filter, placeholder = null, selectorPrefix, labelClasses: additionalLabelClasses = [] } = configuration || {};

Check warning on line 30 in lib/public/components/common/selection/selectionOptions.js

View check run for this annotation

Codecov / codecov/patch

lib/public/components/common/selection/selectionOptions.js#L29-L30

Added lines #L29 - L30 were not covered by tests

const options = filterSelectionOptions(selectionModel.options, filter);

Check warning on line 32 in lib/public/components/common/selection/selectionOptions.js

View check run for this annotation

Codecov / codecov/patch

lib/public/components/common/selection/selectionOptions.js#L32

Added line #L32 was not covered by tests

if (options.length === 0) {
return placeholder;

Check warning on line 35 in lib/public/components/common/selection/selectionOptions.js

View check run for this annotation

Codecov / codecov/patch

lib/public/components/common/selection/selectionOptions.js#L34-L35

Added lines #L34 - L35 were not covered by tests
}

return options.map((option) => {
const selector = option.selector ?? option.value;

Check warning on line 39 in lib/public/components/common/selection/selectionOptions.js

View check run for this annotation

Codecov / codecov/patch

lib/public/components/common/selection/selectionOptions.js#L38-L39

Added lines #L38 - L39 were not covered by tests

const uniqueSelector = `${cleanPrefix(selectorPrefix)}option-${selector}`;

Check warning on line 41 in lib/public/components/common/selection/selectionOptions.js

View check run for this annotation

Codecov / codecov/patch

lib/public/components/common/selection/selectionOptions.js#L41

Added line #L41 was not covered by tests

const labelClasses = ['form-check-label', 'flex-row', 'g2', ...additionalLabelClasses];

Check warning on line 43 in lib/public/components/common/selection/selectionOptions.js

View check run for this annotation

Codecov / codecov/patch

lib/public/components/common/selection/selectionOptions.js#L43

Added line #L43 was not covered by tests

return h(

Check warning on line 45 in lib/public/components/common/selection/selectionOptions.js

View check run for this annotation

Codecov / codecov/patch

lib/public/components/common/selection/selectionOptions.js#L45

Added line #L45 was not covered by tests
`label.${labelClasses.join('.')}`,
{ key: uniqueSelector },
[
h(
`input#${uniqueSelector}`,
{
id: uniqueSelector,
type: selectionModel.multiple || selectionModel.allowEmpty ? 'checkbox' : 'radio',
name: selectionModel.multiple || selectionModel.allowEmpty
? uniqueSelector
: `${cleanPrefix(selectorPrefix)}option-group`,

Check warning on line 56 in lib/public/components/common/selection/selectionOptions.js

View check run for this annotation

Codecov / codecov/patch

lib/public/components/common/selection/selectionOptions.js#L53-L56

Added lines #L53 - L56 were not covered by tests
checked: selectionModel.isSelected(option),
onchange: () => selectionModel.isSelected(option) ? selectionModel.deselect(option) : selectionModel.select(option),

Check warning on line 58 in lib/public/components/common/selection/selectionOptions.js

View check run for this annotation

Codecov / codecov/patch

lib/public/components/common/selection/selectionOptions.js#L58

Added line #L58 was not covered by tests
},
),
option.label || option.value,

Check warning on line 61 in lib/public/components/common/selection/selectionOptions.js

View check run for this annotation

Codecov / codecov/patch

lib/public/components/common/selection/selectionOptions.js#L61

Added line #L61 was not covered by tests
],
);
});
};
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
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 { expandedSelectionFilter } from '../../../components/Filters/common/filters/checkboxFilter.js';
import { qcFlagTypeColoredBadge } from '../../../components/qcFlags/qcFlagTypeColoredBadge.js';

/**
Expand Down Expand Up @@ -54,7 +54,7 @@ export const qcFlagTypesActiveColumns = {
name: 'Bad',
visible: true,
sortable: true,
filter: ({ isBadFilterModel }) => checkboxes(
filter: ({ isBadFilterModel }) => expandedSelectionFilter(

Check warning on line 57 in lib/public/views/QcFlagTypes/ActiveColumns/qcFlagTypesActiveColumns.js

View check run for this annotation

Codecov / codecov/patch

lib/public/views/QcFlagTypes/ActiveColumns/qcFlagTypesActiveColumns.js#L57

Added line #L57 was not covered by tests
isBadFilterModel,
{ class: 'w-75 mt1', selector: 'qc-flag-type-bad-filter' },
),
Expand Down

0 comments on commit df6208d

Please sign in to comment.