Skip to content

Commit f2a477a

Browse files
authored
[O2B-1352] Comments in popover of QC summary (#1984)
* cherry-pick * test * cleanup * fix * a * cleanup * rename * fix * fix
1 parent 303d356 commit f2a477a

9 files changed

Lines changed: 703 additions & 18 deletions

File tree

lib/domain/entities/QcFlagType.js

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,3 +30,10 @@
3030
* @property {QcFlagVerification[]} verifications
3131
* @property {User} lastUpdatedBy
3232
*/
33+
34+
/**
35+
* @typedef MinifiedQcFlagType
36+
*
37+
* @property {string} name
38+
* @property {string} color as hex
39+
*/

lib/domain/entities/QcSummary.js

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,19 @@
1+
/**
2+
* @typedef MinifiedQcSummaryFlag
3+
*
4+
* @property {number} id - QC flag identifier
5+
* @property {string} comment - QC flag comment
6+
* @property {MinifiedQcFlagType} flagType - flag type
7+
*/
8+
19
/**
210
* @typedef RunDetectorQcSummary
311
*
412
* @property {number} badEffectiveRunCoverage - fraction of run's data, marked explicitly with bad QC flag
513
* @property {number} explicitlyNotBadEffectiveRunCoverage - fraction of run's data, marked explicitly with good QC flag
614
* @property {boolean} mcReproducible - if true states that some Limited Acceptance MC Reproducible flag was assigned
715
* @property {number} missingVerificationsCount - number of QC flags that are unverified and have not been discarded
16+
* @property {MinifiedQcSummaryFlag[]} minifiedFlags - flag with only necessary properties for QC summary display
817
*/
918

1019
/**

lib/domain/enums/QcSummaryProperties.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,5 +16,6 @@ exports.QcSummarProperties = {
1616
EXPLICITELY_NOT_BAD_EFFECTIVE_RUN_COVERAGE: 'explicitlyNotBadEffectiveRunCoverage',
1717
MISSING_VERIFICATIONS: 'missingVerificationsCount',
1818
MC_REPRODUCIBLE: 'mcReproducible',
19+
MINIFIED_FLAGS: 'minifiedFlags',
1920
UNDEFINED_QUALITY_PERIODS_COUNT: 'undefinedQualityPeriodsCount',
2021
};

lib/public/components/common/popover/overflowBalloon.js

Lines changed: 30 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -31,19 +31,22 @@ const doesElementOverflow = (element) => {
3131
/**
3232
* Return a component containing the given content, with a popover displayed on hover if the content overflow from its parent
3333
*
34-
* @param {Component} content the content of the component to create
35-
* @param {Object|null} [options=null] a restricted set of popover options
34+
* @param {Component} trigger baloon trigger
35+
* @param {Component} content baloon content
36+
* @param {object} [options] a restricted set of popover options
3637
* @param {boolean} [options.stretch=false] if true, the balloon will be displayed when hovering the element in which this component is displayed
37-
* @return {vnode} the component
38+
* @param {function<triggerNode, boolean>} [options.showCondition=(()=>true)] content show condition
39+
* @param {number} [options.anchor=PopoverAnchors.TOP_MIDDLE] popover anchor
40+
* @return {Component} the component
3841
*/
39-
export const overflowBalloon = (content, options = null) => {
40-
const { stretch = false } = options || {};
42+
export const balloon = (trigger, content, options = null) => {
43+
const { stretch = false, showCondition = null, anchor = PopoverAnchors.TOP_MIDDLE } = options || {};
4144

4245
return popover(
43-
h('.w-wrapped', content),
46+
trigger,
4447
content,
4548
{
46-
anchor: PopoverAnchors.TOP_MIDDLE,
49+
anchor,
4750
popoverClass: ['p2'],
4851

4952
/**
@@ -96,8 +99,27 @@ export const overflowBalloon = (content, options = null) => {
9699
* @returns {boolean} true if visible, false otherwise
97100
*/
98101
showCondition: function () {
99-
return doesElementOverflow(this.triggerNode.querySelector('.w-wrapped'));
102+
return showCondition
103+
? showCondition(this.triggerNode)
104+
: true;
100105
},
101106
},
102107
);
103108
};
109+
110+
/**
111+
* Return a component containing the given content, with a popover displayed on hover if the content overflow from its parent
112+
*
113+
* @param {Component} content the content of the component to create
114+
* @param {object} [options] a restricted set of popover options
115+
* @param {boolean} [options.stretch=false] if true, the balloon will be displayed when hovering the element in which this component is displayed
116+
* @return {Component} the component
117+
*/
118+
export const overflowBalloon = (content, options = null) => balloon(
119+
h('.w-wrapped', content),
120+
content,
121+
{
122+
showCondition: (triggerNode) => doesElementOverflow(triggerNode.querySelector('.w-wrapped')),
123+
...options,
124+
},
125+
);

lib/public/views/Runs/ActiveColumns/getQcSummaryDisplay.js

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,11 +11,19 @@
1111
* or submit itself to any jurisdiction.
1212
*/
1313

14-
import { h, iconWarning, iconBolt } from '/js/src/index.js';
14+
import {
15+
h,
16+
iconWarning,
17+
iconBolt,
18+
PopoverAnchors,
19+
PopoverTriggerPreConfiguration,
20+
} from '/js/src/index.js';
1521
import { formatFloat } from '../../../utilities/formatting/formatFloat.js';
1622
import { QcSummaryColors } from '../../../components/qcFlags/qcSummaryColors.js';
1723
import { tooltip } from '../../../components/common/popover/tooltip.js';
1824
import { getContrastColor } from '../../../components/common/colors.js';
25+
import { balloon } from '../../../components/common/popover/overflowBalloon.js';
26+
import { qcFlagTypeColoredBadge } from '../../../components/qcFlags/qcFlagTypeColoredBadge.js';
1927

2028
const FULL_COVERAGE = 1;
2129

@@ -31,6 +39,7 @@ export const getQcSummaryDisplay = (summary) => {
3139
explicitlyNotBadEffectiveRunCoverage,
3240
missingVerificationsCount,
3341
mcReproducible,
42+
minifiedFlags = [],
3443
} = summary;
3544

3645
const missingVerificationDisplay = missingVerificationsCount
@@ -102,5 +111,25 @@ export const getQcSummaryDisplay = (summary) => {
102111
);
103112
}
104113

114+
if (minifiedFlags.length > 0) {
115+
const commentsContent = h(
116+
'.p2.flex-column.g2',
117+
minifiedFlags.map(({ id, comment, flagType }) => h('.flex-column.g1', { key: id }, [
118+
h('.f7.gray.flex-row.g1', [`Flag ${id}`, qcFlagTypeColoredBadge(flagType)]),
119+
h('.f6', { style: { whiteSpace: 'pre-wrap' } }, comment),
120+
h('.section-divider'),
121+
])),
122+
);
123+
124+
qcSummaryDisplay = balloon(
125+
qcSummaryDisplay,
126+
commentsContent,
127+
{
128+
...PopoverTriggerPreConfiguration.hover,
129+
anchor: PopoverAnchors.BOTTOM_MIDDLE,
130+
},
131+
);
132+
}
133+
105134
return qcSummaryDisplay;
106135
};

lib/server/services/qualityControlFlag/QcFlagSummaryService.js

Lines changed: 47 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -166,17 +166,44 @@ class QcFlagSummaryService {
166166
? Math.min(1, Math.max(0, parseFloat(effectiveRunCoverageString)))
167167
: null;
168168

169+
const flagIds = (summaryDb.get('flagIds')?.split(',') ?? [])
170+
.map((id) => parseInt(id, 10))
171+
.filter(Number.isFinite)
172+
.sort((a, b) => a - b);
173+
169174
return {
170175
runNumber: summaryDb.runNumber,
171176
detectorId: summaryDb.detectorId,
172177
effectiveRunCoverage,
173178
bad: Boolean(summaryDb.get('bad')),
174-
flagIds: (summaryDb.get('flagIds')?.split(',') ?? []).map((id) => parseInt(id, 10)),
179+
flagIds,
175180
mcReproducible: Boolean(summaryDb.get('mcReproducible')),
176181
};
177182
});
178183

179184
const allFlagsIds = new Set(runDetectorSummaryList.flatMap(({ flagIds }) => flagIds));
185+
186+
const miniCommentedFlagByFlagId = new Map();
187+
if (allFlagsIds.size > 0) {
188+
const flagsWithComments = await QcFlagRepository.findAll({
189+
attributes: ['id', 'comment'],
190+
where: { id: { [Op.in]: [...allFlagsIds] } },
191+
include: [{ association: 'flagType' }],
192+
});
193+
194+
for (const { id, comment, flagType: { name, color } } of flagsWithComments) {
195+
if (comment?.trim()) {
196+
miniCommentedFlagByFlagId.set(id, { comment, flagType: { name, color } });
197+
}
198+
}
199+
}
200+
201+
for (const summaryUnit of runDetectorSummaryList) {
202+
summaryUnit.minifiedFlags = summaryUnit.flagIds
203+
.map((id) => ({ id, ...miniCommentedFlagByFlagId.get(id) }))
204+
.filter(({ comment }) => Boolean(comment));
205+
}
206+
180207
const notVerifiedFlagsIds = new Set((await QcFlagRepository.findAll({
181208
attributes: ['id'],
182209
include: [{ association: 'verifications', required: false, attributes: [] }],
@@ -194,21 +221,39 @@ class QcFlagSummaryService {
194221
runNumber,
195222
detectorId,
196223
flagIds,
224+
minifiedFlags,
197225
} = runDetectorSummaryForFlagTypesClass;
198226
const missingVerificationsCount = flagIds.filter((id) => notVerifiedFlagsIds.has(id)).length;
199227

200228
if (!summary[runNumber]) {
201229
summary[runNumber] = {};
202230
}
203231
if (!summary[runNumber][detectorId]) {
204-
summary[runNumber][detectorId] = { [QcSummarProperties.MC_REPRODUCIBLE]: false };
232+
summary[runNumber][detectorId] = {
233+
[QcSummarProperties.MC_REPRODUCIBLE]: false,
234+
[QcSummarProperties.MINIFIED_FLAGS]: [],
235+
};
205236
}
206237

207238
const runDetectorSummary = summary[runNumber][detectorId];
208239

209240
runDetectorSummary[QcSummarProperties.MISSING_VERIFICATIONS] =
210241
(runDetectorSummary[QcSummarProperties.MISSING_VERIFICATIONS] ?? 0) + missingVerificationsCount;
211242

243+
if (!runDetectorSummary[QcSummarProperties.MINIFIED_FLAGS]) {
244+
runDetectorSummary[QcSummarProperties.MINIFIED_FLAGS] = [];
245+
}
246+
if (minifiedFlags.length > 0) {
247+
const existingFlagComments = runDetectorSummary[QcSummarProperties.MINIFIED_FLAGS];
248+
const existingIds = new Set(existingFlagComments.map(({ id }) => id));
249+
for (const miniCommentedFlagByFlagId of minifiedFlags) {
250+
if (!existingIds.has(miniCommentedFlagByFlagId.id)) {
251+
existingFlagComments.push(miniCommentedFlagByFlagId);
252+
existingIds.add(miniCommentedFlagByFlagId.id);
253+
}
254+
}
255+
}
256+
212257
QcFlagSummaryService.mergeIntoSummaryUnit(runDetectorSummary, runDetectorSummaryForFlagTypesClass);
213258
}
214259

0 commit comments

Comments
 (0)