diff --git a/QualityControl/lib/dtos/ObjectGetDto.js b/QualityControl/lib/dtos/ObjectGetDto.js index cf29a3744..b5529c726 100644 --- a/QualityControl/lib/dtos/ObjectGetDto.js +++ b/QualityControl/lib/dtos/ObjectGetDto.js @@ -14,6 +14,7 @@ import Joi from 'joi'; import { RunNumberDto } from './filters/RunNumberDto.js'; +import { DetectorNameDto } from './filters/DetectorNameDto.js'; const periodNamePattern = /^LHC\d{1,2}[a-z0-9]+$/i; const qcVersionPattern = /^\d+\.\d+(\.\d+)?$/; @@ -26,6 +27,7 @@ const qcVersionPattern = /^\d+\.\d+(\.\d+)?$/; function createFiltersSchema(runTypes) { return Joi.object({ RunNumber: RunNumberDto.optional(), + DetectorName: DetectorNameDto.optional(), RunType: runTypes.length > 0 ? Joi.string().valid(...runTypes).optional() : Joi.string().optional(), diff --git a/QualityControl/lib/dtos/filters/DetectorNameDto.js b/QualityControl/lib/dtos/filters/DetectorNameDto.js new file mode 100644 index 000000000..454fd48fb --- /dev/null +++ b/QualityControl/lib/dtos/filters/DetectorNameDto.js @@ -0,0 +1,30 @@ +/** + * @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 Joi from 'joi'; + +/** + * Joi validation schema for QcDetectorName filter (also known as detector when fetched from BKP and used in UI) + * @type {Joi.StringSchema} + */ +export const DetectorNameDto = Joi.string() + .uppercase() + .length(3) + .pattern(/^[A-Z]{3}$/) + .messages({ + 'string.base': 'Detector name must be a string', + 'string.uppercase': 'Detector name must be uppercase', + 'string.length': 'Detector name must be exactly 3 characters', + 'string.pattern.base': 'Detector name must contain only uppercase letters (e.g., TPC, ITS)', + }); diff --git a/QualityControl/lib/services/FilterService.js b/QualityControl/lib/services/FilterService.js index 8acbba43f..446b2d760 100644 --- a/QualityControl/lib/services/FilterService.js +++ b/QualityControl/lib/services/FilterService.js @@ -82,7 +82,9 @@ export class FilterService { } try { const detectorSummaries = await this._bookkeepingService.retrieveDetectorSummaries(); - this._detectors = Object.freeze(detectorSummaries.map(({ name, type }) => Object.freeze({ name, type }))); + this._detectors = Object.freeze(detectorSummaries + .filter(({ name, type }) => name && type) + .map(({ name, type }) => Object.freeze({ name, type }))); } catch (error) { this._logger.errorMessage(`Failed to retrieve detectors: ${error?.message || error}`); } diff --git a/QualityControl/lib/services/ccdb/CcdbConstants.js b/QualityControl/lib/services/ccdb/CcdbConstants.js index 2acc54c08..cd80530d5 100644 --- a/QualityControl/lib/services/ccdb/CcdbConstants.js +++ b/QualityControl/lib/services/ccdb/CcdbConstants.js @@ -51,6 +51,7 @@ export const CcdbMetadataFields = Object.freeze({ PeriodName: 'PeriodName', PassName: 'PassName', QcVersion: 'qc_version', + DetectorName: 'qc_detector_name', }); /** diff --git a/QualityControl/public/common/filters/filter.js b/QualityControl/public/common/filters/filter.js index 6d658d9e2..dbb79c554 100644 --- a/QualityControl/public/common/filters/filter.js +++ b/QualityControl/public/common/filters/filter.js @@ -24,9 +24,9 @@ import { h, RemoteData } from '/js/src/index.js'; * @param {object} config.filterMap - Map of the current filter values. * @param {string} [config.type='text'] - The type of the filter element (e.g., 'text', 'number'). * @param {RemoteData} [config.options=RemoteData.notAsked()] - List of options for a dropdown selector (optional). - * @param {Function} config.onChangeCallback - Callback to be triggered on the change event of the filter. - * @param {Function} config.onInputCallback - Callback to be triggered on the input event. - * @param {Function} config.onEnterCallback - Callback to be triggered when the Enter key is pressed. + * @param {onchange} config.onChangeCallback - Callback to be triggered on the change event of the filter. + * @param {oninput} config.onInputCallback - Callback to be triggered on the input event. + * @param {onkeydown} config.onEnterCallback - Callback to be triggered when the Enter key is pressed. * @param {string} [config.filterType=FilterType.DROPDOWN] - The type of filter to be used. * @param {string} [config.width='.'] - The CSS class that defines the width of the filter. * @returns {vnode} - A virtual node element representing the filter element (input or dropdown). @@ -61,6 +61,81 @@ export const dynamicSelector = (config) => { }); }; +/** + * Represents options grouped for HTML . + * Keys are group labels (for the label), + * values are arrays of option values (for