Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
21 changes: 21 additions & 0 deletions lib/database/seeders/20240404100811-qc-flags.js
Original file line number Diff line number Diff line change
Expand Up @@ -281,6 +281,21 @@ module.exports = {
created_at: '2024-08-12 12:00:10',
updated_at: '2024-08-12 12:00:10',
},
{
id: 103,
deleted: true,
from: null,
to: '2019-08-08 20:50:00',
comment: 'deleted flag',

run_number: 56,
flag_type_id: 13, // Bad
created_by_id: 2,
detector_id: 7, // FT0

created_at: '2024-08-12 12:00:15',
updated_at: '2024-08-12 12:00:15',
},

// Run : 56, ITS
{
Expand Down Expand Up @@ -394,6 +409,12 @@ module.exports = {
from: '2019-08-08 20:50:00',
to: null,
},
{
id: 103,
flag_id: 103,
from: null,
to: '2019-08-08 20:50:00',
},

// Run : 56, ITS
{
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
/**
* @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 { h } from '/js/src/index.js';
import { qcFlagsActiveColumns } from './qcFlagsActiveColumns.js';
import { formatQcFlagStart } from '../format/formatQcFlagStart.js';
import { formatQcFlagEnd } from '../format/formatQcFlagEnd.js';
import { formatQcFlagCreatedBy } from '../format/formatQcFlagCreatedBy.js';
import { formatTimestamp } from '../../../utilities/formatting/formatTimestamp.js';

/**
* Active columns configuration for synchronous QC flags table
*/
export const synchronousQcFlagsActiveColumns = {
id: {
name: 'Id',
visible: false,
},
flagType: {
...qcFlagsActiveColumns.flagType,
classes: 'w-15',
},
from: {
name: 'From/To',
visible: true,
format: (_, qcFlag) => h('', [
h('.flex-row', ['From: ', formatQcFlagStart(qcFlag, true)]),
h('.flex-row', ['To: ', formatQcFlagEnd(qcFlag, true)]),
]),
classes: 'w-15',
},
comment: {
...qcFlagsActiveColumns.comment,
balloon: true,
},
deleted: {
name: 'Deleted',
visible: true,
classes: 'w-5',
format: (deleted) => deleted ? h('.danger', 'Yes') : 'No',
},
createdBy: {
name: 'Created',
visible: true,
balloon: true,
format: (_, qcFlag) => h('', [
h('.flex-row', ['By: ', formatQcFlagCreatedBy(qcFlag)]),
h('.flex-row', ['At: ', formatTimestamp(qcFlag.createdAt)]),
]),
},
};
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ import { h } from '/js/src/index.js';
import { estimateDisplayableRowsCount } from '../../../utilities/estimateDisplayableRowsCount.js';
import { table } from '../../../components/common/table/table.js';
import { paginationComponent } from '../../../components/Pagination/paginationComponent.js';
import { qcFlagsActiveColumns } from '../ActiveColumns/qcFlagsActiveColumns.js';
import { synchronousQcFlagsActiveColumns } from '../ActiveColumns/synchronousQcFlagsActiveColumns.js';
import { qcFlagsBreadcrumbs } from '../../../components/qcFlags/qcFlagsBreadcrumbs.js';
import { mergeRemoteData } from '../../../utilities/mergeRemoteData.js';
import errorAlert from '../../../components/common/errorAlert.js';
Expand Down Expand Up @@ -46,16 +46,6 @@ export const SynchronousQcFlagsOverviewPage = ({ qcFlags: { synchronousOverviewM
PAGE_USED_HEIGHT,
));

const activeColumns = {
qcFlagId: {
name: 'Id',
visible: false,
classes: 'w-5',
},
...qcFlagsActiveColumns,
};
delete activeColumns.verified;

return h(
'',
{ onremove: () => synchronousOverviewModel.reset() },
Expand All @@ -70,8 +60,8 @@ export const SynchronousQcFlagsOverviewPage = ({ qcFlags: { synchronousOverviewM
h('.w-100.flex-column', [
table(
qcFlags,
activeColumns,
{ classes: '.table-sm' },
synchronousQcFlagsActiveColumns,
{ classes: '.table-sm.f6' },
null,
{ sort: sortModel },
),
Expand Down
5 changes: 3 additions & 2 deletions lib/public/views/QcFlags/format/formatQcFlagEnd.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,12 @@ import { formatTimestamp } from '../../../utilities/formatting/formatTimestamp.j
* Format QC flag `to` timestamp
*
* @param {QcFlag} qcFlag QC flag
* @param {boolean} inline if true, date and time are on a single line
* @return {Component} formatted `to` timestamp
*/
export const formatQcFlagEnd = ({ from, to }) => {
export const formatQcFlagEnd = ({ from, to }, inline = false) => {
if (to) {
return formatTimestamp(to, false);
return formatTimestamp(to, inline);
} else {
return from
? 'Until run end'
Expand Down
5 changes: 3 additions & 2 deletions lib/public/views/QcFlags/format/formatQcFlagStart.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,12 @@ import { formatTimestamp } from '../../../utilities/formatting/formatTimestamp.j
* Format QC flag `from` timestamp
*
* @param {QcFlag} qcFlag QC flag
* @param {boolean} inline if true, date and time are on a single line
* @return {Component} formatted `from` timestamp
*/
export const formatQcFlagStart = ({ from, to }) => {
export const formatQcFlagStart = ({ from, to }, inline = false) => {
if (from) {
return formatTimestamp(from, false);
return formatTimestamp(from, inline);
} else {
return to
? 'Since run start'
Expand Down
10 changes: 5 additions & 5 deletions test/api/qcFlags.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -743,20 +743,20 @@ module.exports = () => {
const response = await request(server).get(`/api/qcFlags/synchronous?runNumber=${runNumber}&detectorId=${detectorId}`);
expect(response.status).to.be.equal(200);
const { data: flags, meta } = response.body;
expect(meta).to.be.eql({ page: { totalCount: 2, pageCount: 1 } });
expect(flags.map(({ id }) => id)).to.have.all.ordered.members([101, 100]);
expect(meta).to.be.eql({ page: { totalCount: 3, pageCount: 1 } });
expect(flags.map(({ id }) => id)).to.have.all.ordered.members([103, 101, 100]);
});

it('should successfully fetch synchronous flags with pagination', async () => {
const runNumber = 56;
const detectorId = 7;
{
const response = await request(server)
.get(`/api/qcFlags/synchronous?runNumber=${runNumber}&detectorId=${detectorId}&page[limit]=1&page[offset]=1`);
.get(`/api/qcFlags/synchronous?runNumber=${runNumber}&detectorId=${detectorId}&page[limit]=1&page[offset]=2`);

expect(response.status).to.be.equal(200);
const { data: flags, meta } = response.body;
expect(meta).to.be.eql({ page: { totalCount: 2, pageCount: 2 } });
expect(meta).to.be.eql({ page: { totalCount: 3, pageCount: 3 } });
expect(flags).to.be.lengthOf(1);
const [flag] = flags;
expect(flag.id).to.be.equal(100);
Expand All @@ -770,7 +770,7 @@ module.exports = () => {
{
const response = await request(server)
.get(`/api/qcFlags/synchronous?runNumber=${runNumber}&detectorId=${detectorId}&filter[createdBy][names]=Jan%20Jansen&filter[createdBy][operator]=or`);
expect(response.body.data).to.be.lengthOf(2);
expect(response.body.data).to.be.lengthOf(3);
}

{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -142,15 +142,15 @@ module.exports = () => {
const detectorId = 7;
{
const { rows: flags, count } = await qcFlagService.getAllSynchronousPerRunAndDetector({ runNumber, detectorId });
expect(count).to.be.equal(2);
expect(flags.map(({ id }) => id)).to.have.all.ordered.members([101, 100]);
expect(count).to.be.equal(3);
expect(flags.map(({ id }) => id)).to.have.all.ordered.members([103, 101, 100]);
}
{
const { rows: flags, count } = await qcFlagService.getAllSynchronousPerRunAndDetector(
{ runNumber, detectorId },
{ limit: 1, offset: 1 },
{ limit: 1, offset: 2 },
);
expect(count).to.be.equal(2);
expect(count).to.be.equal(3);
expect(flags).to.be.lengthOf(1);
const [flag] = flags;
expect(flag.id).to.be.equal(100);
Expand Down Expand Up @@ -2124,10 +2124,10 @@ module.exports = () => {
});
});

it('should successfult fiter sync flags by created by name', async () => {
it('should successfully filter sync flags by created by name', async () => {
{
const { rows } = await qcFlagService.getAllSynchronousPerRunAndDetector({ runNumber: 56, detectorId: 7 }, {}, { createdBy: { names: ['Jan Jansen'], operator: 'or' }});
expect(rows).to.be.lengthOf(2);
expect(rows).to.be.lengthOf(3);
}

{
Expand All @@ -2136,7 +2136,7 @@ module.exports = () => {
}
});

it('should successfult fiter data pass flags by created by name', async () => {
it('should successfully filter data pass flags by created by name', async () => {
{
const { rows } = await qcFlagService.getAllPerDataPassAndRunAndDetector({ dataPassId: 1, runNumber: 107, detectorId: 1 }, {}, { createdBy: { names: ['John Doe'], operator: 'or' }});
expect(rows).to.be.lengthOf(2);
Expand All @@ -2148,7 +2148,7 @@ module.exports = () => {
}
});

it('should successfult fiter simulation pass flags by created by name', async () => {
it('should successfully filter simulation pass flags by created by name', async () => {
{
const { rows } = await qcFlagService.getAllPerSimulationPassAndRunAndDetector({ simulationPassId: 1, runNumber: 106, detectorId: 1 }, {}, { createdBy: { names: ['Jan Jansen'], operator: 'or' }});
expect(rows).to.be.lengthOf(2);
Expand Down
50 changes: 42 additions & 8 deletions test/public/qcFlags/synchronousOverview.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ const {
expectUrlParams,
waitForNavigation,
getColumnCellsInnerTexts,
getPopoverContent,
} = require('../defaults.js');

const { expect } = chai;
Expand Down Expand Up @@ -59,14 +60,21 @@ module.exports = () => {

it('shows correct datatypes in respective columns', async () => {
// eslint-disable-next-line require-jsdoc
const validateDate = (date) => date === '-' || !isNaN(dateAndTime.parse(date, 'DD/MM/YYYY hh:mm:ss'));
const validateDate = (date) => date === '-' || !isNaN(dateAndTime.parse(date, 'DD/MM/YYYY, hh:mm:ss'));
const tableDataValidators = {
flagType: (flagType) => flagType && flagType !== '-',
createdBy: (userName) => userName && userName !== '-',
from: (timestamp) => timestamp === 'Whole run coverage' || timestamp === 'Since run start' || validateDate(timestamp),
to: (timestamp) => timestamp === 'Whole run coverage' || timestamp === 'Until run end' || validateDate(timestamp),
createdAt: validateDate,
updatedAt: validateDate,
from: (cellContent) => {
const match = cellContent.match(/^From:\s*(.+)\nTo:\s*(.+)$/);
if (!match) return false;
const [, from, to] = match;
return (['Whole run coverage', 'Since run start'].includes(from) || validateDate(from))
&& (['Whole run coverage', 'Until run end'].includes(to) || validateDate(to));
},
deleted: (value) => value === 'Yes' || value === 'No',
createdBy: (cellContent) => {
const match = cellContent.match(/^By:\s*(.+)\nAt:\s*(.+)$/);
return match && match[1] !== '-' && validateDate(match[2]);
},
};

await validateTableData(page, new Map(Object.entries(tableDataValidators)));
Expand All @@ -76,8 +84,34 @@ module.exports = () => {

it('Should display the correct items counter at the bottom of the page', async () => {
await expectInnerText(page, '#firstRowIndex', '1');
await expectInnerText(page, '#lastRowIndex', '2');
await expectInnerText(page, '#totalRowsCount', '2');
await expectInnerText(page, '#lastRowIndex', '3');
await expectInnerText(page, '#totalRowsCount', '3');
});

it('should display Comment tooltip with full information', async () => {
let popoverTrigger = await page.$(`#row100-comment .popover-trigger`);
expect(popoverTrigger).to.not.be.null;

const popoverContent = await getPopoverContent(popoverTrigger);
expect(popoverContent).to.equal('first part good');
});

it('should display CreatedBy tooltip with full information', async () => {
let popoverTrigger = await page.$(`#row100-createdBy .popover-trigger`);
expect(popoverTrigger).to.not.be.null;

const popoverContent = await getPopoverContent(popoverTrigger);
expect(popoverContent).to.equal('By: Jan JansenAt: 12/08/2024, 12:00:00');
});

it('should display correct Deleted text colour', async () => {
const deletedCell = await page.$('#row103-deleted-text:nth-child(1)');

const deletedCellText = await page.evaluate(cell => cell.textContent.trim(), deletedCell);
expect(deletedCellText).to.equal('Yes');

const deletedCellFirstChildClass = await page.evaluate(cell => cell.firstElementChild.className, deletedCell);
expect(deletedCellFirstChildClass).to.include('danger');
});

it('can navigate to run details page from breadcrumbs link', async () => {
Expand Down