Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
95e0352
Refactor the response object of `retrieveRunStatus` and rename it to …
hehoon Dec 11, 2025
da4216c
Add panel with run information in QCG under filters
hehoon Dec 12, 2025
6c2587d
Rewrite updateRunInformation so that it doesn't rely on runNumber to …
hehoon Dec 12, 2025
e9be197
Add and use BookkeepingDto.js
hehoon Dec 12, 2025
c160e01
Remove unused variable
hehoon Dec 12, 2025
a73ae42
Use horizontal margin instead of justify center to scrolling bug
hehoon Dec 15, 2025
cf3ece5
Add typedef for RunInformation
hehoon Dec 16, 2025
c00ecc3
Rename `detectorQualities` to `detectorsQualities` and add default va…
hehoon Dec 16, 2025
c9b0c8b
Add a test to validate whether the run information endpoint returns t…
hehoon Dec 16, 2025
2c1196a
Add `statusBadgeSuccess`, `statusBadgeFail` and `statusBadge` helper …
hehoon Dec 16, 2025
c8d8cd2
Display the run detector qualities in badges on a new line beneath th…
hehoon Dec 16, 2025
8bd4032
Add tests for the run information and detector qualities displays
hehoon Dec 16, 2025
35f42ec
Merge branch 'dev' into feature/QCG/OGUI-1840/Refactor-the-response-o…
graduta Dec 17, 2025
49c4b3e
Merge branch 'feature/QCG/OGUI-1840/Refactor-the-response-object-of-r…
hehoon Dec 17, 2025
1f8e58c
Merge branch 'dev' into feature/QCG/OGUI-1842/panel-with-run-information
graduta Dec 17, 2025
3947c8e
Fix an issue with horizontal scrolling and the use of `justify-conten…
hehoon Dec 17, 2025
f0ee16c
Add components `cleanRunInformationPanel` and `detectorsQualitiesPanel`
hehoon Dec 17, 2025
924bfbb
Small changes to some jsdoc
hehoon Dec 17, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion QualityControl/public/Model.js
Original file line number Diff line number Diff line change
Expand Up @@ -169,7 +169,7 @@
this.object.objects = {}; // Remove any in-memory loaded objects
this._clearAllIntervals();
await this.filterModel.filterService.initFilterService();
this.filterModel.setFilterFromURL();
await this.filterModel.setFilterFromURL();
this.filterModel.setFilterToURL();

this.services.layout.getLayoutsByUserId(this.session.personid, RequestFields.LAYOUT_CARD);
Expand Down Expand Up @@ -276,7 +276,7 @@

/**
* Clear URL parameters and redirect to a certain page
* @param {*} pageName - name of the page to be redirected to

Check warning on line 279 in QualityControl/public/Model.js

View workflow job for this annotation

GitHub Actions / Check eslint rules on ubuntu-latest

Prefer a more specific type to `*`
* @returns {undefined}
*/
clearURL(pageName) {
Expand Down
13 changes: 13 additions & 0 deletions QualityControl/public/app.css
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,11 @@
cursor: pointer;
}

.b1 { border-style: solid; border-width: 1px; }

.b-danger { border-color: var(--color-danger); }
.b-success { border-color: var(--color-success); }

.header-layout {
&.edit {
display: flex;
Expand Down Expand Up @@ -187,3 +192,11 @@
.whitespace-nowrap {
white-space: nowrap;
}

/* This hacky workaround is required due to `justify-content: center;` being unusable thanks to a horizontal scrolling bug */
#header-detector-qualities {
&::before, &::after {
content: '';
flex: 1;
}
}
40 changes: 40 additions & 0 deletions QualityControl/public/common/badge.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
/**
* @license
* Copyright 2019-2020 CERN and copyright holders of ALICE O2.
* See http://alice-o2.web.cern.ch/copyright for details of the copyright holders.
* All rights not expressly granted are reserved.
*
* This software is distributed under the terms of the GNU General Public
* License v3 (GPL Version 3), copied verbatim in the file "COPYING".
*
* 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 { h, iconCheck, iconX } from '/js/src/index.js';

/**
* A green success badge with the tick icon
* @param {string} text - Text to display in the badge
* @returns {vnode} The badge virtual node
*/
export const statusBadgeSuccess = (text) =>
h('.badge.success.b-success.b1', h('.flex-row.g1', [text, iconCheck()]));

/**
* A red failure badge with the X icon
* @param {string} text - Text to display in the badge
* @returns {vnode} The badge virtual node
*/
export const statusBadgeFail = (text) =>
h('.badge.danger.b-danger.b1', h('.flex-row.g1', [text, iconX()]));

/**
* A status badge with dynamic color and icon depending on success or failure.
* @param {string} text - Text to display inside the badge
* @param {boolean} success - Whether the badge represents success (`true`) or failure (`false`)
* @returns {vnode} The badge virtual node
*/
export const statusBadge = (text, success) =>
success ? statusBadgeSuccess(text) : statusBadgeFail(text);
19 changes: 11 additions & 8 deletions QualityControl/public/common/filters/filterViews.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,12 @@ import { filterInput, dynamicSelector, ongoingRunsSelector } from './filter.js';
import { FilterType } from './filterTypes.js';
import { filtersConfig, runModeFilterConfig } from './filtersConfig.js';
import { runModeCheckbox } from './runMode/runModeCheckbox.js';
import { lastUpdatePanel, runStatusPanel } from './runMode/runStatusPanel.js';
import {
cleanRunInformationPanel,
detectorsQualitiesPanel,
lastUpdatePanel,
runStatusPanel,
} from './runMode/runStatusPanel.js';
import { h, iconChevronBottom, iconChevronTop } from '/js/src/index.js';

/**
Expand Down Expand Up @@ -75,6 +80,7 @@ export function filtersPanel(filterModel, viewModel) {
isVisible,
lastRefresh,
ONGOING_RUN_INTERVAL_MS: refreshRate,
runInformation,
} = filterModel;
const { fetchOngoingRuns } = filterService;
const onInputCallback = setFilterValue.bind(filterModel);
Expand All @@ -88,6 +94,7 @@ export function filtersPanel(filterModel, viewModel) {
const filtersList = isRunModeActivated
? runModeFilterConfig(filterService)
: filtersConfig(filterService);
const { detectorsQualities, ...cleanRunInformation } = runInformation;

return h(
'.w-100.flex-column.p2.g2.justify-center#filterElement',
Expand All @@ -101,15 +108,11 @@ export function filtersPanel(filterModel, viewModel) {
isRunModeActivated && runStatusPanel(runStatus),
]),
lastUpdatePanel(runStatus, lastRefresh, refreshRate),
cleanRunInformationPanel(cleanRunInformation),
detectorsQualitiesPanel(detectorsQualities),
],
);
};

/**
* Determines if runs mode is allowed based on current page and context
* @param {object} viewModel - Model that manages the state of the page
* @returns {boolean} - whether runs mode is allowed
*/
}

/**
* Button which will allow the user to update filter parameters after the input
Expand Down
58 changes: 56 additions & 2 deletions QualityControl/public/common/filters/model/FilterModel.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,15 @@ import { Observable } from '/js/src/index.js';
import { buildQueryParametersString } from '../../buildQueryParametersString.js';
import FilterService from '../../../services/Filter.service.js';
import { RunStatus } from '../../../library/runStatus.enum.js';
import { prettyFormatDate } from '../../utils.js';

const CCDB_QUERY_PARAMS = ['PeriodName', 'PassName', 'RunNumber', 'RunType'];

const RUN_INFORMATION_MAP = {
startTime: prettyFormatDate,
endTime: prettyFormatDate,
};

/**
* Model namespace that manages the filter state in the application.
*/
Expand All @@ -39,6 +46,7 @@ export default class FilterModel extends Observable {
this._runStatus = null;
this._isRunModeActivated = false;
this._lastRefresh = null;
this._runInformation = {};

this.ONGOING_RUN_INTERVAL_MS = 15000;
}
Expand All @@ -47,7 +55,7 @@ export default class FilterModel extends Observable {
* Look for parameters used for filtering in URL and apply them in the layout if it exists
* @returns {undefined}
*/
setFilterFromURL() {
async setFilterFromURL() {
const parameters = this.model.router.params;
CCDB_QUERY_PARAMS.forEach((filterKey) => {
if (parameters[filterKey]) {
Expand All @@ -64,6 +72,7 @@ export default class FilterModel extends Observable {
Other: () => null,
});

await this.updateRunInformation();
this.notify();
}

Expand Down Expand Up @@ -114,12 +123,15 @@ export default class FilterModel extends Observable {
*/
async triggerFilter(baseViewModel) {
this.setFilterToURL();
await this.updateRunInformation();

if (this.isRunModeActivated) {
this.runNumber = this._filterMap['RunNumber'];
this.runStatus = await this.filterService.getRunStatus(this.runNumber);
this.runStatus = this.runInformation.runStatus ?? RunStatus.UNKNOWN;
this.notify();
this._manageRunsModeInterval(baseViewModel, true);
}

baseViewModel.triggerFilter();
this._lastRefresh = Date.now();
this.notify();
Expand Down Expand Up @@ -150,6 +162,7 @@ export default class FilterModel extends Observable {
*/
clearFilters() {
this._filterMap = {};
this._runInformation = {};
this.setFilterToURL(true);
this.notify();
}
Expand Down Expand Up @@ -285,6 +298,19 @@ export default class FilterModel extends Observable {
}
}

/**
* Updates the `runInformation` property by fetching data from the `filterService`.
* If `this.runNumber` is defined, it asynchronously retrieves the run information
* via `filterService.getRunInformation(runNumber)` and sets it to `runInformation`,
* automatically applying any filtering and transformations defined in the setter.
* If `this.runNumber` is not defined, `runInformation` is reset to an empty object.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing @return param doc

* @returns {undefined}
*/
async updateRunInformation() {
const runNumber = this._filterMap['RunNumber'];
this.runInformation = runNumber ? await this.filterService.getRunInformation(runNumber) : {};
}

/**
* Gets the current run number.
* @returns {number} The run number.
Expand All @@ -301,6 +327,34 @@ export default class FilterModel extends Observable {
this._runNumber = value;
}

/**
* Gets the current run information.
* @returns {object} The run information.
*/
get runInformation() {
return this._runInformation;
}

/**
* Sets the run information after filtering and transforming values.
* - Filters out properties that are `null` or `undefined`.
* - Applies a transformation function from `RUN_INFORMATION_MAP` for any matching keys.
* @param {RunInformation} value - The new run information object to set.
* Keys corresponding to functions in `RUN_INFORMATION_MAP` will be transformed accordingly.
* @returns {undefined}
*/
set runInformation(value) {
const runInfo = value && typeof value === 'object' ? value : {};
const transformed = Object.entries(runInfo)
// Filters out properties that are `null` or `undefined`.
.filter(([_, v]) => v !== null && v !== undefined)
// Applies a transformation function from `RUN_INFORMATION_MAP` for any matching keys.
.map(([key, value]) =>
[key, typeof RUN_INFORMATION_MAP[key] === 'function' ? RUN_INFORMATION_MAP[key](value) : value]);

this._runInformation = Object.fromEntries(transformed);
}

/**
* Gets the current run status.
* @returns {RemoteData} The run status.
Expand Down
47 changes: 47 additions & 0 deletions QualityControl/public/common/filters/runMode/runStatusPanel.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@

import { RunStatus } from '../../../../../library/runStatus.enum.js';
import { h } from '/js/src/index.js';
import { camelToTitleCase } from '../../utils.js';
import { statusBadge } from '../../badge.js';

/**
* Creates and returns a run status panel element displaying the current run number,
Expand Down Expand Up @@ -53,3 +55,48 @@ export const lastUpdatePanel = (runStatus, lastRefresh, refreshRate = 15000) =>
),
]);
};

/**
* Renders the run information panel
* @param {object} cleanRunInformation - The `RunInformation` without `detectorsQualities`
* @returns {vnode} - virtual node element
*/
export const cleanRunInformationPanel = (cleanRunInformation) =>
cleanRunInformation && Object.keys(cleanRunInformation).length > 0 && h(
'.flex-row.g4.items-center.f7.gray-darker.text-center.ph4',
{
id: 'header-run-information',
style: 'overflow-x: auto; margin: 0 auto;',
},
Object.entries(cleanRunInformation).map(([key, value]) =>
h('.flex-row.g1', {
key: `${key}-${value}`,
style: 'flex: 0 0 auto;',
}, [
h('strong', `${camelToTitleCase(key)}:`),
h('span', `${value}`),
])),
);

/**
* Renders the detector qualities panel
* @param {DetectorQuality[]} detectorsQualities - The detector qualities of the run
* @returns {vnode} - virtual node element
*/
export const detectorsQualitiesPanel = (detectorsQualities) =>
Array.isArray(detectorsQualities) && detectorsQualities.length > 0 && h(
'.flex-row.g3.items-center.f7.gray-darker.text-center.ph3',
{
id: 'header-detector-qualities',
style: 'overflow-x: auto;',
},
detectorsQualities.map(({ id, name, quality }) =>
h(
'.flex-row.g1',
{
key: `${id}-${name}-${quality}`,
style: 'flex: 0 0 auto;',
},
statusBadge(name, quality === 'good'),
)),
);
16 changes: 13 additions & 3 deletions QualityControl/public/services/Filter.service.js
Original file line number Diff line number Diff line change
Expand Up @@ -50,12 +50,22 @@ export default class FilterService {
/**
* Method to get run status for a specific run number
* @param {number} runNumber - The run number to get status for
* @returns {RemoteData} - result within a RemoteData object
* @returns {object} - result as an object containing run information
*/
async getRunStatus(runNumber) {
async getRunInformation(runNumber) {
const parsedRunNumber = parseInt(runNumber, 10);
const { result, ok } = await this.loader.get(`/api/filter/run-status/${parsedRunNumber}`);
return ok ? result?.runStatus : RunStatus.UNKNOWN;
return ok ? result : {};
}

/**
* Method to get run status for a specific run number
* @param {number} runNumber - The run number to get status for
* @returns {RunStatus} - result as a run status
*/
async getRunStatus(runNumber) {
const { runStatus } = await this.getRunInformation(runNumber);
return runStatus ?? RunStatus.UNKNOWN;
}

/**
Expand Down
Loading
Loading