diff --git a/lib/public/app.css b/lib/public/app.css index ec66c3717c..bb67bc66bd 100644 --- a/lib/public/app.css +++ b/lib/public/app.css @@ -266,6 +266,12 @@ th.text-center, td.text-center { border-color: #f5c6cb; } +.alert-warning { + color: var(--color-warning); + background-color: #ffe8c8; + border-color: #fdd69f; +} + .alert-danger hr { border-top-color: #f1b0b7; } diff --git a/lib/public/components/Filters/common/FilteringModel.js b/lib/public/components/Filters/common/FilteringModel.js index 19e59f7b65..86479ed590 100644 --- a/lib/public/components/Filters/common/FilteringModel.js +++ b/lib/public/components/Filters/common/FilteringModel.js @@ -25,11 +25,13 @@ export class FilteringModel extends Observable { * * @param {QueryRouter} router router that controls the application's page navigation * @param {Object} filters the filters with their label and model + * @param {object} warnings object reference used to define warnings. */ - constructor(router, filters) { + constructor(router, filters, warnings) { super(); this._visualChange$ = new Observable(); this._pageIdentifier = null; + this._warnings = warnings; this._router = router; this._filters = {}; @@ -151,16 +153,25 @@ export class FilteringModel extends Observable { return; } + const unknownFilters = []; + for (const [key, value] of Object.entries(filter)) { const filterModel = this._filters[key]; if (!filterModel) { + unknownFilters.push(key); continue; } filterModel.normalized = value; } + if (unknownFilters.length) { + this._warnings.set('Unknown Filters', unknownFilters.join(', ')); + } else { + this._warnings.delete('Unknown Filters'); + } + this.notify(); } diff --git a/lib/public/components/common/messages/warningComponent.js b/lib/public/components/common/messages/warningComponent.js new file mode 100644 index 0000000000..b9e3b933ad --- /dev/null +++ b/lib/public/components/common/messages/warningComponent.js @@ -0,0 +1,35 @@ +import { h } from '/js/src/index.js'; +import { iconX } from '/js/src/icons.js'; + +/** + * Component to display whenever a page has warnings. + * + * @param {OverviewPageModel} overviewModel model that controlls an overview page + * @returns {Component} the warning componen + */ +export const warningComponent = (overviewModel) => { + const { warnings } = overviewModel; + + if (!warnings.size) { + return null; + } + + return h('details.alert.alert-warning', [ + h('summary', 'Warnings'), + h('ul', warnings.entries().toArray().map(([key, message]) => + h('li.flex-row.items-center', [ + h( + '.btn.btn-pill.alert-warning.mh1', + { + onclick: () => { + warnings.delete(key); + overviewModel.notify(); + }, + }, + iconX(), + ), + h('strong.mh1', `${key}:`), + h('span', message), + ]))), + ]); +}; diff --git a/lib/public/models/OverviewModel.js b/lib/public/models/OverviewModel.js index 69ae0c3df3..d278c4d0ed 100644 --- a/lib/public/models/OverviewModel.js +++ b/lib/public/models/OverviewModel.js @@ -38,7 +38,7 @@ export class OverviewPageModel extends Observable { */ constructor() { super(); - + this._warnings = new Map(); this._sortModel = new SortModel(); this._sortModel.observe(() => { this._pagination.silentlySetCurrentPage(1); @@ -97,6 +97,7 @@ export class OverviewPageModel extends Observable { reset() { this._item$.setCurrent(RemoteData.notAsked()); this._pagination.reset(); + this._warnings.clear(); } /** @@ -249,4 +250,13 @@ export class OverviewPageModel extends Observable { hasAnyData() { return this._item$.getCurrent().match({ Success: ({ length = 0 } = {}) => length > 0, Other: () => false }); } + + /** + * Returns the warnings object + * + * @return {object} the warning model + */ + get warnings() { + return this._warnings; + } } diff --git a/lib/public/views/DataPasses/DataPassesOverviewModel.js b/lib/public/views/DataPasses/DataPassesOverviewModel.js index 3be195e0b7..c6b4e625b2 100644 --- a/lib/public/views/DataPasses/DataPassesOverviewModel.js +++ b/lib/public/views/DataPasses/DataPassesOverviewModel.js @@ -35,6 +35,7 @@ export class DataPassesOverviewModel extends OverviewPageModel { availableOptions: NON_PHYSICS_PRODUCTIONS_NAMES_WORDS.map((word) => ({ label: word.toUpperCase(), value: word })), }), }, + this._warnings, ); this._filteringModel.pageIdentifier = pageIdentifier; diff --git a/lib/public/views/DataPasses/PerLhcPeriodOverview/DataPassesPerLhcPeriodOverviewPage.js b/lib/public/views/DataPasses/PerLhcPeriodOverview/DataPassesPerLhcPeriodOverviewPage.js index e97dca2170..7cb3e5fb65 100644 --- a/lib/public/views/DataPasses/PerLhcPeriodOverview/DataPassesPerLhcPeriodOverviewPage.js +++ b/lib/public/views/DataPasses/PerLhcPeriodOverview/DataPassesPerLhcPeriodOverviewPage.js @@ -19,6 +19,7 @@ import { filtersPanelPopover } from '../../../components/Filters/common/filtersP import { estimateDisplayableRowsCount } from '../../../utilities/estimateDisplayableRowsCount.js'; import { dataPassesActiveColumns } from '../ActiveColumns/dataPassesActiveColumns.js'; import { DataPassVersionStatus } from '../../../domain/enums/DataPassVersionStatus.js'; +import { warningComponent } from '../../../components/common/messages/warningComponent.js'; const TABLEROW_HEIGHT = 42; // Estimate of the navbar and pagination elements height total; Needs to be updated in case of changes; @@ -42,24 +43,18 @@ const getRowClasses = ({ versions }) => { * @returns {Component} The overview screen */ export const DataPassesPerLhcPeriodOverviewPage = ({ dataPasses: { perLhcPeriodOverviewModel: dataPassesPerLhcPeriodOverviewModel } }) => { - dataPassesPerLhcPeriodOverviewModel.pagination.provideDefaultItemsPerPage(estimateDisplayableRowsCount( - TABLEROW_HEIGHT, - PAGE_USED_HEIGHT, - )); + const { filteringModel, sortModel, pagination, items } = dataPassesPerLhcPeriodOverviewModel; + + pagination.provideDefaultItemsPerPage(estimateDisplayableRowsCount(TABLEROW_HEIGHT, PAGE_USED_HEIGHT)); return h('', { onremove: () => dataPassesPerLhcPeriodOverviewModel.reset(), }, [ - h('.flex-row.header-container.pv2', filtersPanelPopover(dataPassesPerLhcPeriodOverviewModel.filteringModel, dataPassesActiveColumns)), + h('.flex-row.header-container.pv2', filtersPanelPopover(filteringModel, dataPassesActiveColumns)), + warningComponent(dataPassesPerLhcPeriodOverviewModel), h('.w-100.flex-column', [ - table( - dataPassesPerLhcPeriodOverviewModel.items, - dataPassesActiveColumns, - { classes: getRowClasses }, - null, - { sort: dataPassesPerLhcPeriodOverviewModel.sortModel }, - ), - paginationComponent(dataPassesPerLhcPeriodOverviewModel.pagination), + table(items, dataPassesActiveColumns, { classes: getRowClasses }, null, { sort: sortModel }), + paginationComponent(pagination), ]), ]); }; diff --git a/lib/public/views/DataPasses/PerSimulationPassOverview/DataPassesPerSimulationPassOverviewPage.js b/lib/public/views/DataPasses/PerSimulationPassOverview/DataPassesPerSimulationPassOverviewPage.js index 2473f3383d..6e11d594a8 100644 --- a/lib/public/views/DataPasses/PerSimulationPassOverview/DataPassesPerSimulationPassOverviewPage.js +++ b/lib/public/views/DataPasses/PerSimulationPassOverview/DataPassesPerSimulationPassOverviewPage.js @@ -22,6 +22,7 @@ import { breadcrumbs } from '../../../components/common/navigation/breadcrumbs.j import spinner from '../../../components/common/spinner.js'; import { tooltip } from '../../../components/common/popover/tooltip.js'; import { DataPassVersionStatus } from '../../../domain/enums/DataPassVersionStatus.js'; +import { warningComponent } from '../../../components/common/messages/warningComponent.js'; const TABLEROW_HEIGHT = 42; // Estimate of the navbar and pagination elements height total; Needs to be updated in case of changes; @@ -46,12 +47,9 @@ const getRowClasses = ({ versions }) => { */ export const DataPassesPerSimulationPassOverviewPage = ({ dataPasses: { perSimulationPassOverviewModel: dataPassesPerSimulationPassOverviewModel } }) => { - dataPassesPerSimulationPassOverviewModel.pagination.provideDefaultItemsPerPage(estimateDisplayableRowsCount( - TABLEROW_HEIGHT, - PAGE_USED_HEIGHT, - )); + const { items, simulationPass, pagination, filteringModel, sortModel } = dataPassesPerSimulationPassOverviewModel; - const { items, simulationPass, pagination } = dataPassesPerSimulationPassOverviewModel; + pagination.provideDefaultItemsPerPage(estimateDisplayableRowsCount(TABLEROW_HEIGHT, PAGE_USED_HEIGHT)); const commonTitle = h('h2#breadcrumb-header', 'Data Passes per MC'); @@ -59,7 +57,7 @@ export const DataPassesPerSimulationPassOverviewPage = ({ dataPasses: { onremove: () => dataPassesPerSimulationPassOverviewModel.reset(), }, [ h('.flex-row.items-center.g2', [ - filtersPanelPopover(dataPassesPerSimulationPassOverviewModel.filteringModel, dataPassesActiveColumns), + filtersPanelPopover(filteringModel, dataPassesActiveColumns), h( '.flex-row.g1.items-center', simulationPass.match({ @@ -70,14 +68,9 @@ export const DataPassesPerSimulationPassOverviewPage = ({ dataPasses: { }), ), ]), + warningComponent(dataPassesPerSimulationPassOverviewModel), h('.w-100.flex-column', [ - table( - items, - dataPassesActiveColumns, - { classes: getRowClasses }, - null, - { sort: dataPassesPerSimulationPassOverviewModel.sortModel }, - ), + table(items, dataPassesActiveColumns, { classes: getRowClasses }, null, { sort: sortModel }), paginationComponent(pagination), ]), ]); diff --git a/lib/public/views/Environments/Overview/EnvironmentOverviewModel.js b/lib/public/views/Environments/Overview/EnvironmentOverviewModel.js index 5e220e758a..74c5496ceb 100644 --- a/lib/public/views/Environments/Overview/EnvironmentOverviewModel.js +++ b/lib/public/views/Environments/Overview/EnvironmentOverviewModel.js @@ -48,6 +48,7 @@ export class EnvironmentOverviewModel extends OverviewPageModel { }), ids: new RawTextFilterModel(), }, + this._warnings, ); this._filteringModel.pageIdentifier = pageIdentifier; diff --git a/lib/public/views/Environments/Overview/environmentOverviewComponent.js b/lib/public/views/Environments/Overview/environmentOverviewComponent.js index 7cc60ecd22..df8f5a332d 100644 --- a/lib/public/views/Environments/Overview/environmentOverviewComponent.js +++ b/lib/public/views/Environments/Overview/environmentOverviewComponent.js @@ -17,6 +17,7 @@ import { environmentsActiveColumns } from '../ActiveColumns/environmentsActiveCo import { estimateDisplayableRowsCount } from '../../../utilities/estimateDisplayableRowsCount.js'; import { paginationComponent } from '../../../components/Pagination/paginationComponent.js'; import { filtersPanelPopover } from '../../../components/Filters/common/filtersPanelPopover.js'; +import { warningComponent } from '../../../components/common/messages/warningComponent.js'; const TABLEROW_HEIGHT = 58; // Estimate of the navbar and pagination elements height total; Needs to be updated in case of changes; @@ -30,16 +31,14 @@ const PAGE_USED_HEIGHT = 181; export const environmentOverviewComponent = (envsOverviewModel) => { const { pagination, environments } = envsOverviewModel; - pagination.provideDefaultItemsPerPage(estimateDisplayableRowsCount( - TABLEROW_HEIGHT, - PAGE_USED_HEIGHT, - )); + pagination.provideDefaultItemsPerPage(estimateDisplayableRowsCount(TABLEROW_HEIGHT, PAGE_USED_HEIGHT)); return h('', [ h( '.flex-row.header-container.g2.pv2', filtersPanelPopover(envsOverviewModel, environmentsActiveColumns), ), + warningComponent(envsOverviewModel), h('.w-100.flex-column', [ h('.header-container.pv2'), table(environments, environmentsActiveColumns, { classes: 'table-sm' }), diff --git a/lib/public/views/LhcFills/Overview/LhcFillsOverviewModel.js b/lib/public/views/LhcFills/Overview/LhcFillsOverviewModel.js index 04d746aea3..29984dd72b 100644 --- a/lib/public/views/LhcFills/Overview/LhcFillsOverviewModel.js +++ b/lib/public/views/LhcFills/Overview/LhcFillsOverviewModel.js @@ -49,6 +49,7 @@ export class LhcFillsOverviewModel extends OverviewPageModel { beamTypes: new BeamTypeFilterModel(), schemeName: new RawTextFilterModel(), }, + this._warnings, ); this._filteringModel.pageIdentifier = pageIdentifier; diff --git a/lib/public/views/LhcFills/Overview/index.js b/lib/public/views/LhcFills/Overview/index.js index a29abf5145..f790bb9957 100644 --- a/lib/public/views/LhcFills/Overview/index.js +++ b/lib/public/views/LhcFills/Overview/index.js @@ -19,6 +19,7 @@ import { estimateDisplayableRowsCount } from '../../../utilities/estimateDisplay import { paginationComponent } from '../../../components/Pagination/paginationComponent.js'; import { filtersPanelPopover } from '../../../components/Filters/common/filtersPanelPopover.js'; import { toggleFilter } from '../../../components/Filters/common/filters/toggleFilter.js'; +import { warningComponent } from '../../../components/common/messages/warningComponent.js'; const TABLEROW_HEIGHT = 53.3; // Estimate of the navbar and pagination elements height total; Needs to be updated in case of changes; @@ -41,20 +42,18 @@ export const Index = (model) => h('', { * @returns {Object} Html page */ const showLhcFillsTable = (lhcFillsOverviewModel) => { - lhcFillsOverviewModel.pagination.provideDefaultItemsPerPage(estimateDisplayableRowsCount( - TABLEROW_HEIGHT, - PAGE_USED_HEIGHT, - 1, - )); + const { items, pagination, filteringModel } = lhcFillsOverviewModel; + pagination.provideDefaultItemsPerPage(estimateDisplayableRowsCount(TABLEROW_HEIGHT, PAGE_USED_HEIGHT, 1)); return [ h('.flex-row.header-container.g2.pv2', [ filtersPanelPopover(lhcFillsOverviewModel, lhcFillsActiveColumns), - toggleFilter(lhcFillsOverviewModel.filteringModel.get('hasStableBeams'), 'STABLE BEAM ONLY'), + toggleFilter(filteringModel.get('hasStableBeams'), 'STABLE BEAM ONLY'), ]), + warningComponent(lhcFillsOverviewModel), h('.w-100.flex-column', [ - table(lhcFillsOverviewModel.items, lhcFillsActiveColumns, null, { tableClasses: '.table-sm' }), - paginationComponent(lhcFillsOverviewModel.pagination), + table(items, lhcFillsActiveColumns, null, { tableClasses: '.table-sm' }), + paginationComponent(pagination), ]), ]; }; diff --git a/lib/public/views/Logs/Overview/LogsOverviewModel.js b/lib/public/views/Logs/Overview/LogsOverviewModel.js index b3591d4e0b..b1f351b8a8 100644 --- a/lib/public/views/Logs/Overview/LogsOverviewModel.js +++ b/lib/public/views/Logs/Overview/LogsOverviewModel.js @@ -38,6 +38,7 @@ export class LogsOverviewModel extends Observable { */ constructor(model, excludeAnonymous = false, pageIdentifier) { super(); + this._warnings = new Map(); this._filteringModel = new FilteringModel( model.router, @@ -51,6 +52,7 @@ export class LogsOverviewModel extends Observable { fillNumbers: new RawTextFilterModel(), created: new TimeRangeInputModel(), }, + this._warnings, ); this._overviewSortModel = new SortModel(); @@ -175,6 +177,15 @@ export class LogsOverviewModel extends Observable { return this._pagination; } + /** + * Returns the warnings object + * + * @return {object} the warning model + */ + get warnings() { + return this._warnings; + } + /** * Apply the current filtering and update the remote data list * diff --git a/lib/public/views/Logs/Overview/index.js b/lib/public/views/Logs/Overview/index.js index 93f58c8c40..babeb820e5 100644 --- a/lib/public/views/Logs/Overview/index.js +++ b/lib/public/views/Logs/Overview/index.js @@ -19,6 +19,7 @@ import { paginationComponent } from '../../../components/Pagination/paginationCo import { frontLink } from '../../../components/common/navigation/frontLink.js'; import { filtersPanelPopover } from '../../../components/Filters/common/filtersPanelPopover.js'; import { excludeAnonymousLogAuthorToggle } from '../../../components/Filters/LogsFilter/author/authorFilter.js'; +import { warningComponent } from '../../../components/common/messages/warningComponent.js'; const TABLEROW_HEIGHT = 69; // Estimate of the navbar and pagination elements height total; Needs to be updated in case of changes; @@ -30,22 +31,22 @@ const PAGE_USED_HEIGHT = 215; * @return {Component} Returns a vnode with the table containing the logs */ const logOverviewScreen = ({ logs: { overviewModel: logsOverviewModel } }) => { - logsOverviewModel.pagination.provideDefaultItemsPerPage(estimateDisplayableRowsCount( - TABLEROW_HEIGHT, - PAGE_USED_HEIGHT, - )); + const { pagination, filteringModel, logs, overviewSortModel } = logsOverviewModel; + + pagination.provideDefaultItemsPerPage(estimateDisplayableRowsCount(TABLEROW_HEIGHT, PAGE_USED_HEIGHT)); return h('', [ h('#main-action-bar.flex-row.justify-between.header-container.pv2', [ h('.flex-row.g3', [ filtersPanelPopover(logsOverviewModel, logsActiveColumns), - excludeAnonymousLogAuthorToggle(logsOverviewModel.filteringModel.get('author')), + excludeAnonymousLogAuthorToggle(filteringModel.get('author')), ]), actionButtons(), ]), + warningComponent(logsOverviewModel), h('.w-100.flex-column', [ - table(logsOverviewModel.logs, logsActiveColumns, null, null, { sort: logsOverviewModel.overviewSortModel }), - paginationComponent(logsOverviewModel.pagination), + table(logs, logsActiveColumns, null, null, { sort: overviewSortModel }), + paginationComponent(pagination), ]), ]); }; diff --git a/lib/public/views/QcFlagTypes/Overview/QcFlagTypesOverviewModel.js b/lib/public/views/QcFlagTypes/Overview/QcFlagTypesOverviewModel.js index 060ce94c9b..21c64830f2 100644 --- a/lib/public/views/QcFlagTypes/Overview/QcFlagTypesOverviewModel.js +++ b/lib/public/views/QcFlagTypes/Overview/QcFlagTypesOverviewModel.js @@ -36,6 +36,7 @@ export class QcFlagTypesOverviewModel extends OverviewPageModel { methods: new TextTokensFilterModel(), bad: new RadioButtonFilterModel([{ label: 'Any' }, { label: 'Bad', value: true }, { label: 'Not Bad', value: false }]), }, + this._warnings, ); this._filteringModel.pageIdentifier = pageIdentifier; diff --git a/lib/public/views/QcFlagTypes/Overview/QcFlagTypesOverviewPage.js b/lib/public/views/QcFlagTypes/Overview/QcFlagTypesOverviewPage.js index 6b2a818527..0c3fb2a71e 100644 --- a/lib/public/views/QcFlagTypes/Overview/QcFlagTypesOverviewPage.js +++ b/lib/public/views/QcFlagTypes/Overview/QcFlagTypesOverviewPage.js @@ -19,6 +19,7 @@ import { qcFlagTypesActiveColumns } from '../ActiveColumns/qcFlagTypesActiveColu import { filtersPanelPopover } from '../../../components/Filters/common/filtersPanelPopover.js'; import { frontLink } from '../../../components/common/navigation/frontLink.js'; import { BkpRoles } from '../../../domain/enums/BkpRoles.js'; +import { warningComponent } from '../../../components/common/messages/warningComponent.js'; const TABLEROW_HEIGHT = 30; // Estimate of the navbar and pagination elements height total; Needs to be updated in case of changes; @@ -30,12 +31,9 @@ const PAGE_USED_HEIGHT = 215; * @return {Component} The overview page */ export const QcFlagTypesOverviewPage = ({ qcFlagTypes: { overviewModel } }) => { - overviewModel.pagination.provideDefaultItemsPerPage(estimateDisplayableRowsCount( - TABLEROW_HEIGHT, - PAGE_USED_HEIGHT, - )); + const { items: qcFlagTypes, pagination, sortModel } = overviewModel; - const { items: qcFlagTypes } = overviewModel; + pagination.provideDefaultItemsPerPage(estimateDisplayableRowsCount(TABLEROW_HEIGHT, PAGE_USED_HEIGHT)); return h('', [ h('.flex-row.justify-between.items-center.g2', [ @@ -50,15 +48,10 @@ export const QcFlagTypesOverviewPage = ({ qcFlagTypes: { overviewModel } }) => { }), ], ]), + warningComponent(overviewModel), h('.flex-column.w-100', [ - table( - qcFlagTypes, - qcFlagTypesActiveColumns, - { classes: '.table-sm' }, - null, - { sort: overviewModel.sortModel }, - ), - paginationComponent(overviewModel.pagination), + table(qcFlagTypes, qcFlagTypesActiveColumns, { classes: '.table-sm' }, null, { sort: sortModel }), + paginationComponent(pagination), ]), ]); }; diff --git a/lib/public/views/Runs/Overview/RunsOverviewModel.js b/lib/public/views/Runs/Overview/RunsOverviewModel.js index 1b276299f7..9ce38580e2 100644 --- a/lib/public/views/Runs/Overview/RunsOverviewModel.js +++ b/lib/public/views/Runs/Overview/RunsOverviewModel.js @@ -100,6 +100,7 @@ export class RunsOverviewModel extends OverviewPageModel { epn: new RadioButtonFilterModel([{ label: 'ANY' }, { label: 'ON', value: true }, { label: 'OFF', value: false }]), triggerValues: new SelectionModel({ availableOptions: TRIGGER_VALUES.map((value) => ({ label: value, value })) }), }, + this._warnings, ); this._filteringModel.pageIdentifier = pageIdentifier; diff --git a/lib/public/views/Runs/Overview/RunsOverviewPage.js b/lib/public/views/Runs/Overview/RunsOverviewPage.js index 6355872b9e..4f76d417d9 100644 --- a/lib/public/views/Runs/Overview/RunsOverviewPage.js +++ b/lib/public/views/Runs/Overview/RunsOverviewPage.js @@ -20,6 +20,7 @@ import { table } from '../../../components/common/table/table.js'; import { switchInput } from '../../../components/common/form/switchInput.js'; import { exportTriggerAndModal } from '../../../components/common/dataExport/exportTriggerAndModal.js'; import { textInputFilter } from '../../../components/Filters/common/filters/textInputFilter.js'; +import { warningComponent } from '../../../components/common/messages/warningComponent.js'; const TABLEROW_HEIGHT = 59; // Estimate of the navbar and pagination elements height total; Needs to be updated in case of changes; @@ -46,21 +47,20 @@ export const togglePhysicsOnlyFilter = (runDefinitionFilterModel) => { * @return {Component} Returns a vnode with the table containing the runs */ export const RunsOverviewPage = ({ runs: { overviewModel: runsOverviewModel }, modalModel }) => { - runsOverviewModel.pagination.provideDefaultItemsPerPage(estimateDisplayableRowsCount( - TABLEROW_HEIGHT, - PAGE_USED_HEIGHT, - )); + const { pagination, items, exportModel, filteringModel } = runsOverviewModel; + pagination.provideDefaultItemsPerPage(estimateDisplayableRowsCount(TABLEROW_HEIGHT, PAGE_USED_HEIGHT)); return h('', [ h('.flex-row.header-container.g2.pv2', [ filtersPanelPopover(runsOverviewModel, runsActiveColumns), h('.pl2#runOverviewFilter', textInputFilter(runsOverviewModel.filteringModel, 'runNumbers', 'e.g. 534454, 534455...')), - togglePhysicsOnlyFilter(runsOverviewModel.filteringModel.get('definitions')), - exportTriggerAndModal(runsOverviewModel.exportModel, modalModel), + togglePhysicsOnlyFilter(filteringModel.get('definitions')), + exportTriggerAndModal(exportModel, modalModel), ]), + warningComponent(runsOverviewModel), h('.flex-column.w-100', [ - table(runsOverviewModel.items, runsActiveColumns), - paginationComponent(runsOverviewModel.pagination), + table(items, runsActiveColumns), + paginationComponent(pagination), ]), ]); }; diff --git a/lib/public/views/Runs/RunPerDataPass/RunsPerDataPassOverviewPage.js b/lib/public/views/Runs/RunPerDataPass/RunsPerDataPassOverviewPage.js index 59f396515c..fd847389f5 100644 --- a/lib/public/views/Runs/RunPerDataPass/RunsPerDataPassOverviewPage.js +++ b/lib/public/views/Runs/RunPerDataPass/RunsPerDataPassOverviewPage.js @@ -39,6 +39,7 @@ import { getInelasticInteractionRateColumns } from '../ActiveColumns/getInelasti import { exportTriggerAndModal } from '../../../components/common/dataExport/exportTriggerAndModal.js'; import { textInputFilter } from '../../../components/Filters/common/filters/textInputFilter.js'; import { toggleFilter } from '../../../components/Filters/common/filters/toggleFilter.js'; +import { warningComponent } from '../../../components/common/messages/warningComponent.js'; const TABLEROW_HEIGHT = 59; // Estimate of the navbar and pagination elements height total; Needs to be updated in case of changes; @@ -297,6 +298,7 @@ export const RunsPerDataPassOverviewPage = ({ { alignment: 'right' }, )), ]), + warningComponent(perDataPassOverviewModel), h( '.intermediate-flex-column', { onremove: () => perDataPassOverviewModel._abortGaqFetches() }, diff --git a/lib/public/views/Runs/RunPerPeriod/RunsPerLhcPeriodOverviewPage.js b/lib/public/views/Runs/RunPerPeriod/RunsPerLhcPeriodOverviewPage.js index 1006c5f44e..cf26fe1018 100644 --- a/lib/public/views/Runs/RunPerPeriod/RunsPerLhcPeriodOverviewPage.js +++ b/lib/public/views/Runs/RunPerPeriod/RunsPerLhcPeriodOverviewPage.js @@ -29,6 +29,7 @@ import { filtersPanelPopover } from '../../../components/Filters/common/filtersP import { exportTriggerAndModal } from '../../../components/common/dataExport/exportTriggerAndModal.js'; import { textInputFilter } from '../../../components/Filters/common/filters/textInputFilter.js'; import { toggleFilter } from '../../../components/Filters/common/filters/toggleFilter.js'; +import { warningComponent } from '../../../components/common/messages/warningComponent.js'; const TABLEROW_HEIGHT = 62; // Estimate of the navbar and pagination elements height total; Needs to be updated in case of changes; @@ -50,11 +51,6 @@ const getRowClasses = (run) => isRunNotSubjectToQc(run) ? '.danger' : null; * @return {Component} The overview page */ export const RunsPerLhcPeriodOverviewPage = ({ runs: { perLhcPeriodOverviewModel }, modalModel }) => { - perLhcPeriodOverviewModel.pagination.provideDefaultItemsPerPage(estimateDisplayableRowsCount( - TABLEROW_HEIGHT, - PAGE_USED_HEIGHT, - )); - const { items: remoteRuns, lhcPeriodStatistics: remoteLhcPeriodStatistics, @@ -66,8 +62,11 @@ export const RunsPerLhcPeriodOverviewPage = ({ runs: { perLhcPeriodOverviewModel mcReproducibleAsNotBad, qcSummary: remoteQcSummary, pdpBeamTypes, + pagination, } = perLhcPeriodOverviewModel; + pagination.provideDefaultItemsPerPage(estimateDisplayableRowsCount(TABLEROW_HEIGHT, PAGE_USED_HEIGHT)); + /** * Render runs table with given detectors' active columns configuration * @@ -110,6 +109,7 @@ export const RunsPerLhcPeriodOverviewPage = ({ runs: { perLhcPeriodOverviewModel filtersPanelPopover(perLhcPeriodOverviewModel, activeColumns, { profile: 'runsPerLhcPeriod' }), h('.pl2#runOverviewFilter', textInputFilter(perLhcPeriodOverviewModel.filteringModel, 'runNumbers', 'e.g. 534454, 534455...')), h('h2.flex-row', ['Good, physics runs of ', lhcPeriodName]), + warningComponent(perLhcPeriodOverviewModel), toggleFilter(mcReproducibleAsNotBad, h('em', 'MC.R as not-bad'), 'mcReproducibleAsNotBadToggle'), exportTriggerAndModal(perLhcPeriodOverviewModel.exportModel, modalModel), ]), @@ -153,7 +153,7 @@ export const RunsPerLhcPeriodOverviewPage = ({ runs: { perLhcPeriodOverviewModel }, { panelClass: ['scroll-auto'] }, ), - paginationComponent(perLhcPeriodOverviewModel.pagination), + paginationComponent(pagination), ] }), ), ]; diff --git a/lib/public/views/Runs/RunsPerSimulationPass/RunsPerSimulationPassOverviewPage.js b/lib/public/views/Runs/RunsPerSimulationPass/RunsPerSimulationPassOverviewPage.js index 3b4ad6157f..c64fcbe6c8 100644 --- a/lib/public/views/Runs/RunsPerSimulationPass/RunsPerSimulationPassOverviewPage.js +++ b/lib/public/views/Runs/RunsPerSimulationPass/RunsPerSimulationPassOverviewPage.js @@ -29,6 +29,7 @@ import { exportTriggerAndModal } from '../../../components/common/dataExport/exp import { filtersPanelPopover } from '../../../components/Filters/common/filtersPanelPopover.js'; import { toggleFilter } from '../../../components/Filters/common/filters/toggleFilter.js'; import { textInputFilter } from '../../../components/Filters/common/filters/textInputFilter.js'; +import { warningComponent } from '../../../components/common/messages/warningComponent.js'; const TABLEROW_HEIGHT = 59; // Estimate of the navbar and pagination elements height total; Needs to be updated in case of changes; @@ -52,11 +53,6 @@ export const RunsPerSimulationPassOverviewPage = ({ dplDetectorsUserHasAccessTo: remoteDplDetectorsUserHasAccessTo, modalModel, }) => { - perSimulationPassOverviewModel.pagination.provideDefaultItemsPerPage(estimateDisplayableRowsCount( - TABLEROW_HEIGHT, - PAGE_USED_HEIGHT, - )); - const { items: remoteRuns, detectors: remoteDetectors, @@ -67,8 +63,11 @@ export const RunsPerSimulationPassOverviewPage = ({ sortModel, pdpBeamTypes, mcReproducibleAsNotBad, + pagination, } = perSimulationPassOverviewModel; + pagination.provideDefaultItemsPerPage(estimateDisplayableRowsCount(TABLEROW_HEIGHT, PAGE_USED_HEIGHT)); + const commonTitle = h('h2', 'Runs per MC'); const fullPageData = mergeRemoteData([remoteRuns, remoteSimulationPass, remoteDetectors, remoteQcSummary]); @@ -120,6 +119,7 @@ export const RunsPerSimulationPassOverviewPage = ({ }, ), ]), + warningComponent(perSimulationPassOverviewModel), h( '.intermediate-flex-column', fullPageData.match({ @@ -136,7 +136,7 @@ export const RunsPerSimulationPassOverviewPage = ({ }, { sort: sortModel }, ), - paginationComponent(perSimulationPassOverviewModel.pagination), + paginationComponent(pagination), ], Loading: () => spinner(), }), diff --git a/lib/public/views/SimulationPasses/AnchoredOverview/AnchoredSimulationPassesOverviewModel.js b/lib/public/views/SimulationPasses/AnchoredOverview/AnchoredSimulationPassesOverviewModel.js index 42d14c2a3e..e4fb264116 100644 --- a/lib/public/views/SimulationPasses/AnchoredOverview/AnchoredSimulationPassesOverviewModel.js +++ b/lib/public/views/SimulationPasses/AnchoredOverview/AnchoredSimulationPassesOverviewModel.js @@ -29,7 +29,7 @@ export class AnchoredSimulationPassesOverviewModel extends OverviewPageModel { constructor(router, pageIdentifier) { super(); - this._filteringModel = new FilteringModel(router, { names: new TextTokensFilterModel() }); + this._filteringModel = new FilteringModel(router, { names: new TextTokensFilterModel() }, this._warnings); this._filteringModel.pageIdentifier = pageIdentifier; this._filteringModel.setFilterFromURL(); diff --git a/lib/public/views/SimulationPasses/AnchoredOverview/AnchoredSimulationPassesOverviewPage.js b/lib/public/views/SimulationPasses/AnchoredOverview/AnchoredSimulationPassesOverviewPage.js index 5894ba1a05..f9f752836c 100644 --- a/lib/public/views/SimulationPasses/AnchoredOverview/AnchoredSimulationPassesOverviewPage.js +++ b/lib/public/views/SimulationPasses/AnchoredOverview/AnchoredSimulationPassesOverviewPage.js @@ -21,6 +21,7 @@ import { simulationPassesActiveColumns } from '../ActiveColumns/simulationPasses import { breadcrumbs } from '../../../components/common/navigation/breadcrumbs.js'; import spinner from '../../../components/common/spinner.js'; import { tooltip } from '../../../components/common/popover/tooltip.js'; +import { warningComponent } from '../../../components/common/messages/warningComponent.js'; const TABLEROW_HEIGHT = 42; // Estimate of the navbar and pagination elements height total; Needs to be updated in case of changes; @@ -34,13 +35,9 @@ const PAGE_USED_HEIGHT = 215; export const AnchoredSimulationPassesOverviewPage = ({ simulationPasses: { anchoredOverviewModel: anchoredSimulationPassesOverviewModel }, }) => { - anchoredSimulationPassesOverviewModel.pagination.provideDefaultItemsPerPage(estimateDisplayableRowsCount( - TABLEROW_HEIGHT, - PAGE_USED_HEIGHT, - )); - - const { items, dataPass, pagination } = anchoredSimulationPassesOverviewModel; + const { items, dataPass, pagination, sortModel } = anchoredSimulationPassesOverviewModel; + pagination.provideDefaultItemsPerPage(estimateDisplayableRowsCount(TABLEROW_HEIGHT, PAGE_USED_HEIGHT)); const commonTitle = h('h2#breadcrumb-header', { style: 'white-space: nowrap;' }, 'Anchored MC'); return h( @@ -61,13 +58,14 @@ export const AnchoredSimulationPassesOverviewPage = ({ }), ), ]), + warningComponent(anchoredSimulationPassesOverviewModel), h('.w-100.flex-column', [ table( items, simulationPassesActiveColumns, { classes: '.table-sm' }, null, - { sort: anchoredSimulationPassesOverviewModel.sortModel }, + { sort: sortModel }, ), paginationComponent(pagination), ]), diff --git a/lib/public/views/SimulationPasses/PerLhcPeriodOverview/SimulationPassesPerLhcPeriodOverviewModel.js b/lib/public/views/SimulationPasses/PerLhcPeriodOverview/SimulationPassesPerLhcPeriodOverviewModel.js index 869bf418f9..1ca1c6dc94 100644 --- a/lib/public/views/SimulationPasses/PerLhcPeriodOverview/SimulationPassesPerLhcPeriodOverviewModel.js +++ b/lib/public/views/SimulationPasses/PerLhcPeriodOverview/SimulationPassesPerLhcPeriodOverviewModel.js @@ -29,7 +29,7 @@ export class SimulationPassesPerLhcPeriodOverviewModel extends OverviewPageModel constructor(router, pageIdentifier) { super(); - this._filteringModel = new FilteringModel(router, { names: new TextTokensFilterModel() }); + this._filteringModel = new FilteringModel(router, { names: new TextTokensFilterModel() }, this._warnings); this._filteringModel.pageIdentifier = pageIdentifier; this._filteringModel.setFilterFromURL(); diff --git a/lib/public/views/SimulationPasses/PerLhcPeriodOverview/SimulationPassesPerLhcPeriodOverviewPage.js b/lib/public/views/SimulationPasses/PerLhcPeriodOverview/SimulationPassesPerLhcPeriodOverviewPage.js index 3cc12756d0..0d2961b5f3 100644 --- a/lib/public/views/SimulationPasses/PerLhcPeriodOverview/SimulationPassesPerLhcPeriodOverviewPage.js +++ b/lib/public/views/SimulationPasses/PerLhcPeriodOverview/SimulationPassesPerLhcPeriodOverviewPage.js @@ -21,6 +21,7 @@ import { simulationPassesActiveColumns } from '../ActiveColumns/simulationPasses import spinner from '../../../components/common/spinner.js'; import { tooltip } from '../../../components/common/popover/tooltip.js'; import { breadcrumbs } from '../../../components/common/navigation/breadcrumbs.js'; +import { warningComponent } from '../../../components/common/messages/warningComponent.js'; const TABLEROW_HEIGHT = 42; // Estimate of the navbar and pagination elements height total; Needs to be updated in case of changes; @@ -33,12 +34,9 @@ const PAGE_USED_HEIGHT = 215; */ export const SimulationPassesPerLhcPeriodOverviewPage = ({ simulationPasses: { perLhcPeriodOverviewModel: simulationPassesPerLhcPeriodOverviewModel } }) => { - simulationPassesPerLhcPeriodOverviewModel.pagination.provideDefaultItemsPerPage(estimateDisplayableRowsCount( - TABLEROW_HEIGHT, - PAGE_USED_HEIGHT, - )); + const { items: simulationPasses, lhcPeriod, pagination, sortModel } = simulationPassesPerLhcPeriodOverviewModel; - const { items: simulationPasses, lhcPeriod } = simulationPassesPerLhcPeriodOverviewModel; + pagination.provideDefaultItemsPerPage(estimateDisplayableRowsCount(TABLEROW_HEIGHT, PAGE_USED_HEIGHT)); const commonTitle = h('h2#breadcrumb-header', { style: 'white-space: nowrap;' }, 'Monte Carlo'); @@ -57,15 +55,10 @@ export const SimulationPassesPerLhcPeriodOverviewPage = ({ simulationPasses: { }), ), ]), + warningComponent(simulationPassesPerLhcPeriodOverviewModel), h('.w-100.flex-column', [ - table( - simulationPasses, - simulationPassesActiveColumns, - { classes: '.table-sm' }, - null, - { sort: simulationPassesPerLhcPeriodOverviewModel.sortModel }, - ), - paginationComponent(simulationPassesPerLhcPeriodOverviewModel.pagination), + table(simulationPasses, simulationPassesActiveColumns, { classes: '.table-sm' }, null, { sort: sortModel }), + paginationComponent(pagination), ]), ]); }; diff --git a/lib/public/views/lhcPeriods/Overview/LhcPeriodsOverviewModel.js b/lib/public/views/lhcPeriods/Overview/LhcPeriodsOverviewModel.js index 2d886ac3e2..fdd6cadc59 100644 --- a/lib/public/views/lhcPeriods/Overview/LhcPeriodsOverviewModel.js +++ b/lib/public/views/lhcPeriods/Overview/LhcPeriodsOverviewModel.js @@ -37,6 +37,7 @@ export class LhcPeriodsOverviewModel extends OverviewPageModel { years: new TextTokensFilterModel(), pdpBeamTypes: new TextTokensFilterModel(), }, + this._warnings, ); this._filteringModel.pageIdentifier = pageIdentifier; diff --git a/lib/public/views/lhcPeriods/Overview/LhcPeriodsOverviewPage.js b/lib/public/views/lhcPeriods/Overview/LhcPeriodsOverviewPage.js index b431c62d42..89c0def48c 100644 --- a/lib/public/views/lhcPeriods/Overview/LhcPeriodsOverviewPage.js +++ b/lib/public/views/lhcPeriods/Overview/LhcPeriodsOverviewPage.js @@ -18,6 +18,7 @@ import { lhcPeriodsActiveColumns } from '../ActiveColumns/lhcPeriodsActiveColumn import { paginationComponent } from '../../../components/Pagination/paginationComponent.js'; import { filtersPanelPopover } from '../../../components/Filters/common/filtersPanelPopover.js'; import { estimateDisplayableRowsCount } from '../../../utilities/estimateDisplayableRowsCount.js'; +import { warningComponent } from '../../../components/common/messages/warningComponent.js'; const TABLEROW_HEIGHT = 35; // Estimate of the navbar and pagination elements height total; Needs to be updated in case of changes; @@ -29,22 +30,19 @@ const PAGE_USED_HEIGHT = 215; * @returns {Component} The overview screen */ export const LhcPeriodsOverviewPage = ({ lhcPeriods: { overviewModel: lhcPeriodsOverviewModel } }) => { - lhcPeriodsOverviewModel.pagination.provideDefaultItemsPerPage(estimateDisplayableRowsCount( - TABLEROW_HEIGHT, - PAGE_USED_HEIGHT, - )); + const { sortModel, pagination, items } = lhcPeriodsOverviewModel; + + pagination.provideDefaultItemsPerPage(estimateDisplayableRowsCount(TABLEROW_HEIGHT, PAGE_USED_HEIGHT)); return h('', [ - h('.flex-row.header-container.pv2', filtersPanelPopover(lhcPeriodsOverviewModel, lhcPeriodsActiveColumns)), + h( + '.flex-row.header-container.pv2', + filtersPanelPopover(lhcPeriodsOverviewModel, lhcPeriodsActiveColumns), + ), + warningComponent(lhcPeriodsOverviewModel), h('.w-100.flex-column', [ - table( - lhcPeriodsOverviewModel.items, - lhcPeriodsActiveColumns, - { classes: '.table-sm' }, - null, - { sort: lhcPeriodsOverviewModel.sortModel }, - ), - paginationComponent(lhcPeriodsOverviewModel.pagination), + table(items, lhcPeriodsActiveColumns, { classes: '.table-sm' }, null, { sort: sortModel }), + paginationComponent(pagination), ]), ]); }; diff --git a/test/public/components/index.js b/test/public/components/index.js index 5e06743c62..700564755c 100644 --- a/test/public/components/index.js +++ b/test/public/components/index.js @@ -12,7 +12,9 @@ */ const NavBarSuite = require('./navBar.test') +const WarningSuite = require('./warnings.test') module.exports = () => { describe('Navbar component', NavBarSuite); + describe('Warning component', WarningSuite) }; diff --git a/test/public/components/warnings.test.js b/test/public/components/warnings.test.js new file mode 100644 index 0000000000..2b59055d32 --- /dev/null +++ b/test/public/components/warnings.test.js @@ -0,0 +1,48 @@ +/** + * @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, + getInnerText, + pressElement, +} = require('../defaults.js'); + +module.exports = () => { + let page; + let browser; + const navTabSelector = 'a.btn-tab[id]'; // ALI FLP doesn't have an id, nor a functional href, hence why it is excluded like this + + before(async () => { + [page, browser] = await defaultBefore(); + }); + + it('Should show warning when a filter in the url is not recognised', async () => { + await page.goto('http://localhost:4000/?page=log-overview&filter[fake]=fake', { waitUntil: 'load' }); + const warningText = await getInnerText('.alert-warning > ul'); + + expect(warningText).to.equal('Unknown Filters: fake'); + }); + + it('Should remove warnings entry after clicking the x icon', async () => { + await pressElement(page, '.alert-warning .btn', true); + const warning = await page.$('.alert-warning'); + + expect(warning).to.be.null; + }); + + after(async () => { + await defaultAfter(page, browser); + }); +};