Skip to content

Commit

Permalink
[O2B-1241] RCT Runs overviews filtering (#1559)
Browse files Browse the repository at this point in the history
* add filter

* WIP

* fix

* enable some fiters

* add test WIP

* add test WIP

* add columns

* fix

* duration

* tests

* cleanup; remove spurios test

* cleanup; remove spurios test

* add tset

* test

* test WIP

* docs

* test

* fix tesT

* refactor

* docs

* docs

* handle test case

* a

* cleanup

* docs

* rename

* Simplify expectColumnValue

* Handle no-data row in expectColumnValue

* rename

* ref

* fix

---------

Co-authored-by: martinboulais <[email protected]>
  • Loading branch information
xsalonx and martinboulais authored May 27, 2024
1 parent 6c0e243 commit 5d7e456
Show file tree
Hide file tree
Showing 7 changed files with 138 additions and 16 deletions.
27 changes: 21 additions & 6 deletions lib/public/components/Filters/common/filtersPanelPopover.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ import { popover } from '../../common/popover/popover.js';
import { PopoverTriggerPreConfiguration } from '../../common/popover/popoverPreConfigurations.js';
import { PopoverAnchors } from '../../common/popover/PopoverEngine.js';
import { h } from '/js/src/index.js';
import { profiles } from '../../common/table/profiles.js';
import { applyProfile } from '../../../utilities/applyProfile.js';

/**
* Return the filters panel popover trigger
Expand All @@ -29,10 +31,15 @@ const filtersToggleTrigger = () => h('button#openFilterToggle.btn.btn.btn-primar
*
* @param {object} filteringModel the filtering model
* @param {object} columns the list of columns containing filters
*
* @param {object} [configuration] additional configuration
* @param {string} [configuration.profile = profiles.none] profile which filters should be rendered @see Column
* @return {Component} the filters panel
*/
const filtersToggleContent = (filteringModel, columns) => h('.w-l.scroll-y.flex-column.p3.g3', [
const filtersToggleContent = (
filteringModel,
columns,
{ profile: appliedProfile = profiles.none } = {},
) => h('.w-l.scroll-y.flex-column.p3.g3', [
h('.flex-row.justify-between', [
h('.f4', 'Filters'),
h(
Expand All @@ -46,7 +53,13 @@ const filtersToggleContent = (filteringModel, columns) => h('.w-l.scroll-y.flex-
]),
h('.flex-column.g2', [
Object.entries(columns)
.filter(([_, column]) => column.filter)
.filter(([_, column]) => {
let columnProfiles = column.profiles ?? [profiles.none];
if (typeof columnProfiles === 'string') {
columnProfiles = [columnProfiles];
}
return applyProfile(column, appliedProfile, columnProfiles)?.filter;
})
.map(([columnKey, column]) => [
h(`.flex-row.items-baseline.${columnKey}-filter`, [
h('.w-30.f5', column.name),
Expand All @@ -57,15 +70,17 @@ const filtersToggleContent = (filteringModel, columns) => h('.w-l.scroll-y.flex-
]);

/**
* Return component composed by the filtering popover and its button trigger
* Return component composed of the filtering popover and its button trigger
*
* @param {object} filterModel the filter model
* @param {object} activeColumns the list of active columns containing the filtering 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 = (filterModel, activeColumns) => popover(
export const filtersPanelPopover = (filterModel, activeColumns, configuration) => popover(
filtersToggleTrigger(),
filtersToggleContent(filterModel, activeColumns),
filtersToggleContent(filterModel, activeColumns, configuration),
{
...PopoverTriggerPreConfiguration.click,
anchor: PopoverAnchors.RIGHT_START,
Expand Down
2 changes: 1 addition & 1 deletion lib/public/components/common/table/noDataRow.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,4 @@ import { h } from '/js/src/index.js';
* @param {number} colspan the amount of columns the row must span on
* @return {Component} the no-data row
*/
export const noDataRow = (colspan) => h('tr', h('td', { colSpan: colspan }, h('.text-center', h('em', 'No data'))));
export const noDataRow = (colspan) => h('tr.empty-row', h('td', { colSpan: colspan }, h('.text-center', h('em', 'No data'))));
2 changes: 1 addition & 1 deletion lib/public/components/common/table/table.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ import { remoteDataTableBody } from './remoteDataTableBody.js';
* @property {string|Object} [information] extra information given to the header of the column
* @property {boolean} [visible] false to hide the column
* @property {string|Symbol|Array|Object} [profiles] may be one of the following (note that if the table has no explicit profile, it will be
* assigned {@see profiles.none} profile automatically):
* assigned @see profiles.none profile automatically):
* - If this is a string or a symbol, the column will be displayed only if the table's profile is the specified profile
* - If this is an array, the column will be displayed only if the table's profile is one of the specified profiles
* - If this is an Object:
Expand Down
22 changes: 19 additions & 3 deletions lib/public/views/Runs/ActiveColumns/runsActiveColumns.js
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,12 @@ export const runsActiveColumns = {
detectors: {
name: 'Detectors',
visible: true,
profiles: [profiles.none, 'lhcFill', 'home'],
profiles: {
[profiles.none]: null,
lhcFill: null,
home: null,
runsPerDataPass: { visible: false },
},
size: 'w-15 f6',
format: (_, run) => formatRunDetectorsInline(run.detectorsQualities, run.nDetectors),
filter: detectorsFilterComponent,
Expand All @@ -114,7 +119,12 @@ export const runsActiveColumns = {
tags: {
name: 'Tags',
visible: true,
profiles: [profiles.none, 'lhcFill', 'environment'],
profiles: {
[profiles.none]: null,
lhcFill: null,
environment: null,
runsPerDataPass: { visible: false },
},
classes: 'w-5 f6',
format: (tags) => formatTagsList(tags),
exportFormat: (tags) => tags?.length ? tags.map(({ text }) => text).join('-') : '-',
Expand Down Expand Up @@ -282,7 +292,13 @@ export const runsActiveColumns = {
name: 'Duration',
visible: true,
classes: 'w-7 f6',
profiles: [profiles.none, 'lhcFill', 'environment', 'home'],
profiles: {
[profiles.none]: null,
lhcFill: null,
environment: null,
home: null,
runsPerDataPass: { visible: false },
},
noEllipsis: true,
format: (_duration, run) => displayRunDuration(run),
exportFormat: (_duration, run) => formatRunDuration(run),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ import { breadcrumbs } from '../../../components/common/navigation/breadcrumbs.j
import { createRunDetectorsAsyncQcActiveColumns } from '../ActiveColumns/runDetectorsAsyncQcActiveColumns.js';
import { inelasticInteractionRateActiveColumnsForPbPb } from '../ActiveColumns/inelasticInteractionRateActiveColumnsForPbPb.js';
import { inelasticInteractionRateActiveColumnsForProtonProton } from '../ActiveColumns/inelasticInteractionRateActiveColumnsForProtonProton.js';
import { filtersPanelPopover } from '../../../components/Filters/common/filtersPanelPopover.js';
import runNumberFilter from '../../../components/Filters/RunsFilter/runNumber.js';
import { qcSummaryLegendTooltip } from '../../../components/qcFlags/qcSummaryLegendTooltip.js';

const TABLEROW_HEIGHT = 59;
Expand Down Expand Up @@ -83,6 +85,8 @@ export const RunsPerDataPassOverviewPage = ({ runs: { perDataPassOverviewModel }

return h('', [
h('.flex-row.justify-between.items-center.g2', [
filtersPanelPopover(perDataPassOverviewModel, runsActiveColumns, { profile: 'runsPerDataPass' }),
h('.pl2#runOverviewFilter', runNumberFilter(perDataPassOverviewModel)),
h(
'.flex-row.g1.items-center',
remoteDataPass.match({
Expand Down
14 changes: 9 additions & 5 deletions test/public/defaults.js
Original file line number Diff line number Diff line change
Expand Up @@ -510,11 +510,15 @@ module.exports.checkMismatchingUrlParam = async (page, expectedUrlParameters) =>
* @return {Promise<void>} resolve once column values were checked
*/
module.exports.expectColumnValues = async (page, columnId, expectedInnerTextValues) => {
await page.waitForFunction((columnId, expectedInnerTextValues) => {
// Browser context, be careful when modifying
const names = [...document.querySelectorAll(`table tbody .column-${columnId}`)].map(({ innerText }) => innerText);
return JSON.stringify(names) === JSON.stringify(expectedInnerTextValues);
}, { timeout: 1500 }, columnId, expectedInnerTextValues);
const size = expectedInnerTextValues.length;

await page.waitForFunction(
(size) => document.querySelectorAll('tbody tr:not(.loading-row):not(.empty-row)').length === size,
{ timeout: 500 },
size,
);

expect(await this.getColumnCellsInnerTexts(page, columnId)).to.have.all.ordered.members(expectedInnerTextValues);
};

/**
Expand Down
83 changes: 83 additions & 0 deletions test/public/runs/runsPerDataPass.overview.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ const {
pressElement,
goToPage,
reloadPage,
expectColumnValues,
fillInput,
validateTableData,
expectLink,
validateDate,
Expand Down Expand Up @@ -257,4 +259,85 @@ module.exports = () => {
]);
fs.unlinkSync(path.resolve(downloadPath, targetFileName));
});

// Filters
it('should successfuly apply runNumber filter', async () => {
await goToPage(page, 'runs-per-data-pass', { queryParameters: { dataPassId: 1 } });
await pressElement(page, '#openFilterToggle');

await fillInput(page, '.runNumber-filter input[type=text]', '108,107');
await expectColumnValues(page, 'runNumber', ['108', '107']);

await pressElement(page, '#reset-filters');
await expectColumnValues(page, 'runNumber', ['108', '107', '106']);
});

it('should successfuly apply detectors filter', async () => {
await goToPage(page, 'runs-per-data-pass', { queryParameters: { dataPassId: 2 } });
await pressElement(page, '#openFilterToggle');

await pressElement(page, '.detectors-filter .dropdown-trigger');
await pressElement(page, '#detector-filter-dropdown-option-CPV');
await expectColumnValues(page, 'runNumber', ['2', '1']);

await pressElement(page, '#reset-filters');
await expectColumnValues(page, 'runNumber', ['55', '2', '1']);
});

it('should successfuly apply tags filter', async () => {
await goToPage(page, 'runs-per-data-pass', { queryParameters: { dataPassId: 1 } });
await pressElement(page, '#openFilterToggle');

await pressElement(page, '.tags-filter .dropdown-trigger');
await pressElement(page, '#tag-dropdown-option-FOOD');
await pressElement(page, '#tag-dropdown-option-RUN');
await expectColumnValues(page, 'runNumber', ['106']);

await pressElement(page, '#reset-filters');
await expectColumnValues(page, 'runNumber', ['108', '107', '106']);
});

it('should successfuly apply timeStart filter', async () => {
await goToPage(page, 'runs-per-data-pass', { queryParameters: { dataPassId: 2 } });
await pressElement(page, '#openFilterToggle');

await fillInput(page, '.timeO2Start-filter input[type=date]', '2021-01-01');
await expectColumnValues(page, 'runNumber', ['1']);

await pressElement(page, '#reset-filters');
await expectColumnValues(page, 'runNumber', ['55', '2', '1']);
});

it('should successfuly apply timeEnd filter', async () => {
await goToPage(page, 'runs-per-data-pass', { queryParameters: { dataPassId: 2 } });
await pressElement(page, '#openFilterToggle');

await fillInput(page, '.timeO2End-filter input[type=date]', '2021-01-01');
await expectColumnValues(page, 'runNumber', ['1']);

await pressElement(page, '#reset-filters');
await expectColumnValues(page, 'runNumber', ['55', '2', '1']);
});

it('should successfuly apply duration filter', async () => {
await goToPage(page, 'runs-per-data-pass', { queryParameters: { dataPassId: 2 } });
await pressElement(page, '#openFilterToggle');

await page.select('.runDuration-filter select', '>=');

/**
* Invokation of page.select and fillInput in case of amountFilter results in two concurrent,
* async actions whereas a result of only one of them is saved into model.
* Therefore additional action is invoked in between
*/
await page.select('.runDuration-filter select', '>=');
await pressElement(page, '#openFilterToggle');
await pressElement(page, '#openFilterToggle');
await fillInput(page, '.runDuration-filter input[type=number]', '10');

await expectColumnValues(page, 'runNumber', ['55', '1']);

await pressElement(page, '#reset-filters');
await expectColumnValues(page, 'runNumber', ['55', '2', '1']);
});
};

0 comments on commit 5d7e456

Please sign in to comment.