Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[ORCT-192] update legacy endpoint to handle migrated flags #233

Merged
Show file tree
Hide file tree
Changes from 29 commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
e5588f0
update get_run_det_data function
xsalonx Sep 28, 2023
1c6c914
adjust forntend to new api
xsalonx Sep 28, 2023
4f06acd
refactor flags view
xsalonx Sep 28, 2023
0c07959
refactor
xsalonx Sep 28, 2023
6334293
amend escaping
xsalonx Sep 28, 2023
b3c70d5
verification display amendment
xsalonx Sep 28, 2023
f409f9a
remove dead code
xsalonx Oct 5, 2023
029df9c
Merge branch 'master' into improvement/ORCT-192/update-legacy-endpoin…
xsalonx Oct 5, 2023
cd25622
structurize flags summary
xsalonx Oct 5, 2023
b4a80ae
return correct timestamps for entire qcf's
xsalonx Oct 5, 2023
d377c9b
add timestamp for flags_view
xsalonx Oct 5, 2023
c7660d0
add color for good
xsalonx Oct 5, 2023
c1f8d30
handle no qc data
xsalonx Oct 5, 2023
693a783
display no qc data
xsalonx Oct 5, 2023
a9bdf43
differentiate between synchronous and asynchronus flags
xsalonx Oct 5, 2023
dc3cc47
Merge branch 'master' into improvement/ORCT-192/update-legacy-endpoin…
xsalonx Oct 9, 2023
3278fef
refactor
xsalonx Oct 9, 2023
2ce9228
Merge branch 'master' into improvement/ORCT-192/update-legacy-endpoin…
xsalonx Oct 10, 2023
bf73d13
replace shortcuts
xsalonx Oct 10, 2023
89b001e
remove problematic data
xsalonx Oct 10, 2023
d37a4d4
amend invalid date
xsalonx Oct 10, 2023
e94f90e
apply the same formatting for verification time:
xsalonx Oct 10, 2023
fd752e2
use css instead of text objects
xsalonx Oct 10, 2023
31ce9d4
css
xsalonx Oct 10, 2023
bdb8310
refactor
xsalonx Oct 10, 2023
e6eca24
refactor
xsalonx Oct 10, 2023
72fd3e1
refactor
xsalonx Oct 10, 2023
f427ff9
simplify method and add docs
xsalonx Oct 10, 2023
eb69693
Merge branch 'master' into improvement/ORCT-192/update-legacy-endpoin…
xsalonx Oct 11, 2023
cb7abb0
refactor ternary operator
xsalonx Oct 11, 2023
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
1 change: 1 addition & 0 deletions app/config/rct-data/quality/flagReasonColors.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ const flagReasonColors = {
neutral: '277DA1',
bad: '922C40',
limitedAcceptance: 'DC9750',
good: '2C9240',
};

module.exports = flagReasonColors;
15 changes: 0 additions & 15 deletions app/lib/database/procedures/flags.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,20 +31,6 @@ const flag_insert = (query) => `
$do$;
`;

const flag_update = (query) => {
return 'NOT IMPLEMENTED PLEASE REMOVE OLD FLAG INSTANCE';
`
DO
$do$
BEGIN
INSERT INTO quality_control_flags (data_pass_id, run_number, detector_id, flag_type_id,
time_start, time_end, comment, added_by, addition_time, last_modified_by, last_modification_time)
VALUES(pass_id, ${query.run_number}, det_id, flag_id,
${query.time_start}, ${query.time_end}, '${query.comment}', '${query.added_by}', now(), null, null);
END
$do$;
`;
}
const flag_delete = (query) => `
DO
$do$
Expand All @@ -67,6 +53,5 @@ $do$;
module.exports = {
flag_insert,
flag_delete,
flag_update,
verification_insert
};
59 changes: 36 additions & 23 deletions app/lib/database/views/flags_view.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,35 +12,50 @@
* or submit itself to any jurisdiction.
*/

const flags_view = (query) => {
rn = query.run_numbers;
let rn_sql = "";
if (typeof(rn) === 'object') {
rn_sql = rn.join(",");
} else if (typeof(rn) === 'string') {
rn_sql = rn
} else {
throw `run_numbers seems to be incorrect ${rn}`
/**
* Build part of sql where clause like 'FIELD_NAME in (...DATA...)';
* @param {Array<String>|String} data - data to be used to build logical clause
* @param {String} fieldName - field name in database
* @param {Boolean} isString - if true values from data are wrapped with single quote
* @returns {String|undefined} - logical clause
*/
const dataFieldToSQLBelongsLogicalClause = (data, fieldName, isString) => {
if (!data) {
return undefined;

Check warning on line 24 in app/lib/database/views/flags_view.js

View check run for this annotation

Codecov / codecov/patch

app/lib/database/views/flags_view.js#L24

Added line #L24 was not covered by tests
}

let det_sql = "";
if (query.detector) {
det_sql = `AND ds.name = '${query.detector}'`
if (!Array.isArray(data)) {
data = [data];
}
const rightOperand = (isString ? data.map((value) => `'${value}'`) : data).join(',');
return rightOperand ? `${fieldName} in (${rightOperand})` : undefined;
}

/**
* Build sql query to fetch quality control flags for
* one data pass and (if provided) given runs and detector subsystems
* @param {Object} query containing data_pass_name (single name), run_numbers (list), detector (list)
* @returns {String} sql query
*/
const flags_view = (query) => {
martinboulais marked this conversation as resolved.
Show resolved Hide resolved
run_selection_sql = dataFieldToSQLBelongsLogicalClause(query.run_numbers, 'r.run_number')
detector_selection_sql = dataFieldToSQLBelongsLogicalClause(query.detector, 'ds.name', true)

const data_pass_sql = `dp.name = '${query.data_pass_name}'`;
const whereClause = [data_pass_sql, run_selection_sql, detector_selection_sql]
.filter(_ => _)
.join(' AND ');

return `
SELECT
qcf.id,
qcf.time_start,
qcf.time_end,
qcf.id,
qcf.entire,
EXTRACT(EPOCH FROM COALESCE(qcf.time_start, r.time_trg_start, r.time_o2_start)) * 1000 as time_start,
EXTRACT(EPOCH FROM COALESCE(qcf.time_end, r.time_trg_end, r.time_o2_end)) * 1000 as time_end,
ftd.name as flag_reason,
qcf.comment,
r.run_number,
ds.name as detector,
array_agg(v.verified_by) as by,
array_agg(v.created_at) as ver_time

get_verifications(qcf.id) as verifications

FROM quality_control_flags AS qcf
INNER JOIN data_passes as dp
Expand All @@ -54,9 +69,7 @@
LEFT OUTER JOIN verifications as v
ON qcf.id = v.qcf_id

WHERE r.run_number in (${rn_sql}) AND
dp.name = '${query.data_pass_name}'
${det_sql}
WHERE ${whereClause}
GROUP BY qcf.id, qcf.time_start, qcf.time_end, ftd.name, qcf.comment, r.run_number, ds.name

`;
Expand Down
10 changes: 5 additions & 5 deletions app/lib/database/views/runs_views.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,14 @@
* or submit itself to any jurisdiction.
*/
const config = require('../../config/configProvider.js');
const run_detectors_field_in_sql_query = config.rctData.detectors
.map(d => `(SELECT get_run_det_data(r.run_number, '${d.toUpperCase()}')) as ${d.toUpperCase()}_detector`)
const run_detectors_field_in_sql_query_factory = (dataPassName = null) => config.rctData.detectors
.map(d => `(SELECT get_run_det_data(r.run_number, '${d.toUpperCase()}', '${dataPassName}')) as ${d.toUpperCase()}_detector`)
.join(',\n')


const queryForRunsFields = `
--p.name,
r.run_number,
r.run_number,
extract( epoch from r.time_o2_start ) * 1000 as time_o2_start,
extract( epoch from r.time_o2_end ) * 1000 as time_o2_end,
extract( epoch from r.time_trg_start ) * 1000 as time_trg_start,
Expand All @@ -34,7 +34,7 @@ const queryForRunsFields = `
const runs_per_period_view = (query) => `
SELECT
${queryForRunsFields},
${run_detectors_field_in_sql_query}
${run_detectors_field_in_sql_query_factory()}
FROM runs AS r
INNER JOIN periods AS p
ON p.id = r.period_id
Expand All @@ -49,7 +49,7 @@ const runs_per_period_view = (query) => `
const runs_per_data_pass_view = (query) => `
SELECT
${queryForRunsFields},
${run_detectors_field_in_sql_query}
${run_detectors_field_in_sql_query_factory(query.index)}
FROM data_passes AS dp
INNER JOIN data_passes_runs AS dpr
ON dp.id=dpr.data_pass_id
Expand Down
11 changes: 8 additions & 3 deletions app/public/components/detectors/detectorIcon.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,12 @@
export default function detectorIcon(navigation, item, index, detectorName, timeBased = false, qualityChangePossible = false) {
const runDetectorId = `${index}-${item.run_number}-${detectorName}`;
const runBasedQcModalId = `${runDetectorId}-qc-modal`;
const runDetectorQuality = item[`${detectorName.toLowerCase()}_detector`];
const runDetectorQualityControlFlag = item[`${detectorName.toLowerCase()}_detector`];

Check warning on line 22 in app/public/components/detectors/detectorIcon.js

View check run for this annotation

Codecov / codecov/patch

app/public/components/detectors/detectorIcon.js#L22

Added line #L22 was not covered by tests

const { qcf, qcf_bkp } = runDetectorQualityControlFlag;
const quality = qcf?.quality || qcf_bkp?.quality;
const qcFromBookkeeping = ! qcf?.quality && qcf_bkp?.quality;

Check warning on line 26 in app/public/components/detectors/detectorIcon.js

View check run for this annotation

Codecov / codecov/patch

app/public/components/detectors/detectorIcon.js#L24-L26

Added lines #L24 - L26 were not covered by tests

return [
qualityChangePossible
? h('.modal', { id: runBasedQcModalId },
Expand All @@ -30,14 +35,14 @@
}, item, index, detectorName, runDetectorId, timeBased)))
: '',

h(`button.btn.pointer.run-quality.${runDetectorQuality}`, {
h(`button.btn.pointer.run-quality.${quality ?? 'no-data'}`, {
id: runDetectorId,
onclick: () => {
if (qualityChangePossible) {
showModal(runBasedQcModalId);
}
},
},
runDetectorQuality),
quality ?? '.', h('sub', qcFromBookkeeping ? 'sync' : '')),
];
}
17 changes: 7 additions & 10 deletions app/public/components/flags/flagsVisualization.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,23 +15,17 @@
import { h } from '/js/src/index.js';
import flagVisualization from './flagVisualization.js';
import { RCT } from '../../config.js';
import { dateFormatter } from '../../utils/dataProcessing/dataProcessingUtils.js';
const { flagReasonColors } = RCT.quality;

function filterDistinct(a) {
return a.filter((value, index, array) => array.indexOf(value) === index);
}

const dateFormatter = (sec) => {
const cestOffset = 2 * 60 * 60 * 1000;
const localOffset = new Date().getTimezoneOffset() * 60 * 1000;
const d = new Date(Number(sec) + cestOffset + localOffset);
const dateString = d.toLocaleDateString();
const timeString = d.toLocaleTimeString();
return h('', h('.skinny', dateString), timeString);
};

export default function flagsVisualization(runData, flagsData) {
const { time_start, time_end } = runData;
const { time_o2_start, time_o2_end, time_trg_start, time_trg_end } = runData;
const time_start = time_trg_start ?? time_o2_start;
const time_end = time_trg_end ?? time_o2_end;

Check warning on line 28 in app/public/components/flags/flagsVisualization.js

View check run for this annotation

Codecov / codecov/patch

app/public/components/flags/flagsVisualization.js#L26-L28

Added lines #L26 - L28 were not covered by tests

const distinctFlagReasons = filterDistinct(flagsData.map((flag) => flag.flag_reason.replace(/\s+/g, '')));

Expand All @@ -43,7 +37,10 @@
const flagColor = (flagReason) => {
switch (flagReason) {
case 'LimitedAcceptance':
case 'Mixed':
return flagReasonColors.limitedAcceptance;
case 'Good':
return flagReasonColors.good;

Check warning on line 43 in app/public/components/flags/flagsVisualization.js

View check run for this annotation

Codecov / codecov/patch

app/public/components/flags/flagsVisualization.js#L43

Added line #L43 was not covered by tests
case 'Notbad':
return flagReasonColors.neutral;
case 'CertifiedbyExpert':
Expand Down
10 changes: 10 additions & 0 deletions app/public/styles/rct/custom/components/run-quality.css
Original file line number Diff line number Diff line change
Expand Up @@ -21,3 +21,13 @@
background-color: var(--red) !important;
color: var(--white);
}

.rct .run-quality.mixed {
background-color: var(--orange) !important;
color: var(--white);
}

.rct .run-quality.no-data {
background-color: var(--dark-blue) !important;
color: var(--white);
}
8 changes: 6 additions & 2 deletions app/public/styles/rct/custom/tables/flags.css
Original file line number Diff line number Diff line change
Expand Up @@ -63,8 +63,12 @@
}

/* Verification time */
.rct .flags-table .flags-ver_time-cell,
.rct .flags-table .flags-ver_time-header {
.rct .flags-table .flags-verification_time-cell,
.rct .flags-table .flags-verification_time-header {
martinboulais marked this conversation as resolved.
Show resolved Hide resolved
min-width: 10em;
text-align: left;
}

.verification-border {
border-bottom: solid;
}
7 changes: 6 additions & 1 deletion app/public/views/flags/Flags.js
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,12 @@ export default class Flags extends Observable {

getFlags(runNumber, detector) {
const allFlags = this.getAllFlags();
const flags = Array.isArray(allFlags) ? allFlags : [];
const flags = !Array.isArray(allFlags) ? [] : allFlags.map((flag) => {
const { verifications } = flag;
flag.verification_time = verifications?.map(({ verification_time }) => verification_time);
flag.by = verifications?.map(({ by }) => by);
return flag;
});
return flags.filter((e) => e.detector === detector && e.run_number.toString() === runNumber.toString());
}
}
2 changes: 1 addition & 1 deletion app/public/views/flags/table/fields.js
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ const fields = [
display: true,
},
{
name: 'ver_time',
name: 'verification_time',
display: true,
},
];
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ export default function qcTypeSelection(navigation, close, item, index, detector
? h('.flex-wrap.justify-center.items-center.p-1rem.p-bottom-0',
h('button.btn.btn-primary', {
onclick: () => navigation.router.go(flagsUrl),
}, 'Time based quality'))
}, 'Quality Control Flags'))
: '',
]);
}
2 changes: 1 addition & 1 deletion app/public/views/runs/runsPerDataPass/table/row.js
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ export default function row(
const detectorCells = visibleFields.filter((field) =>
shouldDisplayDetectorField(field.name, model.parent.userPreferences.detectorList)).map((field) =>
h(`td.${pageName}-detector-cell.text-ellipsis`,
item[field.name]
item[field.name] && (item[field.name]?.qcf_bkp || item[field.name]?.qcf)
? detectorIcon(model.navigation, item, index, detectors.getDetectorName(field.name), true, true)
: ''));

Expand Down
2 changes: 1 addition & 1 deletion app/public/views/userView/data/headersSpecials.js
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ const flagFields = {
flag_reason: 'Reason',
comment: 'Comment',
by: 'Verified by',
ver_time: 'Verification time',
verification_time: 'Verification time',
};

const headersSpecials = {
Expand Down
16 changes: 7 additions & 9 deletions app/public/views/userView/data/pagesCellsSpecials.js
Original file line number Diff line number Diff line change
Expand Up @@ -109,15 +109,13 @@ pagesCellsSpecials[PN.runsPerPeriod] = {
pagesCellsSpecials[PN.flags] = {
time_start: (item) => dateFormatter(item.time_start),
time_end: (item) => dateFormatter(item.time_end),
ver_time: (item) => item.ver_time.isEmpty
? 'unverified'
: item.ver_time.map((e) => {
if (!e) {
return 'unverified';
}
const date = new Date(e);
return dateFormatter(date.getTime());
}),
by: (item) => ! item.verifications?.length ?
'unverified'
: item.verifications.map(({ by: verifier }) => h('.verification-border', h('', verifier, h('.skinny.hidden', '.')))),
verification_time: (item) => ! item.verifications?.length ?
'unverified'
: item.verifications.map(({ verification_time }) =>
h('.verification-border', dateFormatter(new Date(verification_time).getTime()))),
};

pagesCellsSpecials[PN.runsPerDataPass] = pagesCellsSpecials[PN.runsPerPeriod];
Expand Down
58 changes: 49 additions & 9 deletions database/stored-sql-functionalities/functions/get_run_det_data.sql
Original file line number Diff line number Diff line change
@@ -1,17 +1,57 @@
CREATE or REPLACE FUNCTION get_run_det_data(
_run_number bigint,
_detector_name varchar
_detector_name varchar,
_data_pass_name varchar
)
returns varchar

returns json
LANGUAGE plpgsql
AS $body$
DECLARE ret varchar:= null;
DECLARE ret json:= null;

BEGIN
SELECT rd.quality INTO ret -- TODO
FROM runs_detectors AS rd
INNER JOIN detectors_subsystems AS ds
ON rd.detector_id = ds.id
WHERE rd.run_number = _run_number AND ds.name = _detector_name;
return ret::varchar;

raise notice 'data: % % %', _data_pass_name, _run_number, _detector_name;

SELECT json_build_object(
'qcf', qcf,
'qcf_bkp', qcf_bkp
) INTO ret FROM (SELECT

(SELECT json_build_object(
'id', qcf.id,
'quality', lower(ftd.name)
)
FROM
quality_control_flags AS qcf
INNER JOIN flag_types_dictionary AS ftd
ON ftd.id = qcf.flag_type_id
INNER JOIN data_passes as dp
ON dp.id = qcf.data_pass_id
INNER JOIN detectors_subsystems as ds
ON ds.id = qcf.detector_id
WHERE
dp.name = _data_pass_name AND
ds.name = _detector_name AND
qcf.run_number = _run_number
ORDER BY qcf.updated_at DESC
LIMIT 1
) as qcf
,

(SELECT json_build_object(
'quality', rd.quality
)
FROM runs_detectors AS rd
INNER JOIN detectors_subsystems AS ds
ON rd.detector_id = ds.id
WHERE
rd.run_number = _run_number AND
ds.name = _detector_name
) as qcf_bkp

) as subq;

return ret;
END;
$body$;
Loading