@cccsaurora/howler-ui 2.15.0-dev.323 → 2.15.0-dev.327
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/components/elements/display/Classification.js +3 -3
- package/components/elements/display/modals/RationaleModal.d.ts +2 -0
- package/components/elements/display/modals/RationaleModal.js +44 -7
- package/components/hooks/useHitActions.js +1 -1
- package/locales/en/translation.json +2 -0
- package/locales/fr/translation.json +2 -0
- package/package.json +1 -1
|
@@ -10,12 +10,12 @@ const Classification = () => {
|
|
|
10
10
|
const isSm = useMediaQuery(theme.breakpoints.down('md'));
|
|
11
11
|
const label = useMemo(() => {
|
|
12
12
|
if (isSm) {
|
|
13
|
-
return config.c12nDef?.
|
|
13
|
+
return config.c12nDef?.RESTRICTED?.replace(/[a-z]/g, '').replace(/ /g, '') ?? '???';
|
|
14
14
|
}
|
|
15
15
|
else {
|
|
16
|
-
return config.c12nDef?.
|
|
16
|
+
return config.c12nDef?.RESTRICTED ?? 'Unknown';
|
|
17
17
|
}
|
|
18
|
-
}, [config.c12nDef?.
|
|
18
|
+
}, [config.c12nDef?.RESTRICTED, isSm]);
|
|
19
19
|
const color = useMemo(() => config.c12nDef?.levels_styles_map?.[label.replace(/\/\/.+/, '')]?.color ?? 'default', [config.c12nDef?.levels_styles_map, label]);
|
|
20
20
|
return _jsx(Chip, { label: t(label), color: color, sx: { mr: 1, fontSize: '.9rem', p: 2, textTransform: 'uppercase' } });
|
|
21
21
|
};
|
|
@@ -1,13 +1,37 @@
|
|
|
1
|
-
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
import { Button, Stack, TextField, Typography } from '@mui/material';
|
|
1
|
+
import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { Autocomplete, Button, CircularProgress, ListItemText, Stack, TextField, Typography } from '@mui/material';
|
|
3
|
+
import api from '@cccsaurora/howler-ui/api';
|
|
4
|
+
import { useAppUser } from '@cccsaurora/howler-ui/commons/components/app/hooks/useAppUser';
|
|
3
5
|
import { parseEvent } from '@cccsaurora/howler-ui/commons/components/utils/keyboard';
|
|
4
6
|
import { ModalContext } from '@cccsaurora/howler-ui/components/app/providers/ModalProvider';
|
|
5
|
-
import
|
|
7
|
+
import useMyApi from '@cccsaurora/howler-ui/components/hooks/useMyApi';
|
|
8
|
+
import { isEqual } from 'lodash-es';
|
|
9
|
+
import flatten from 'lodash-es/flatten';
|
|
10
|
+
import isString from 'lodash-es/isString';
|
|
11
|
+
import uniqBy from 'lodash-es/uniqBy';
|
|
12
|
+
import { useCallback, useContext, useEffect, useMemo, useState } from 'react';
|
|
6
13
|
import { useTranslation } from 'react-i18next';
|
|
7
|
-
|
|
14
|
+
import { sanitizeLuceneQuery } from '@cccsaurora/howler-ui/utils/stringUtils';
|
|
15
|
+
const RationaleModal = ({ hits, onSubmit }) => {
|
|
8
16
|
const { t } = useTranslation();
|
|
17
|
+
const { dispatchApi } = useMyApi();
|
|
9
18
|
const { close } = useContext(ModalContext);
|
|
19
|
+
const { user } = useAppUser();
|
|
20
|
+
const [loading, setLoading] = useState(false);
|
|
10
21
|
const [rationale, setRationale] = useState('');
|
|
22
|
+
const [suggestedRationales, setSuggestedRationales] = useState([]);
|
|
23
|
+
const queries = useMemo(() => [
|
|
24
|
+
{
|
|
25
|
+
type: 'analytic',
|
|
26
|
+
query: hits
|
|
27
|
+
.map(hit => `(howler.rationale:* AND howler.analytic:"${sanitizeLuceneQuery(hit.howler.analytic)}")`)
|
|
28
|
+
.join(' OR ')
|
|
29
|
+
},
|
|
30
|
+
{
|
|
31
|
+
type: 'assignment',
|
|
32
|
+
query: `howler.rationale:* AND howler.assignment:${user.username} AND howler.timestamp:[now-14d TO now]`
|
|
33
|
+
}
|
|
34
|
+
], [hits, user.username]);
|
|
11
35
|
const handleSubmit = useCallback(() => {
|
|
12
36
|
onSubmit(rationale);
|
|
13
37
|
close();
|
|
@@ -21,8 +45,21 @@ const RationaleModal = ({ onSubmit }) => {
|
|
|
21
45
|
close();
|
|
22
46
|
}
|
|
23
47
|
}, [close, handleSubmit]);
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
48
|
+
useEffect(() => {
|
|
49
|
+
(async () => {
|
|
50
|
+
setLoading(true);
|
|
51
|
+
// TODO: Eventually switch a a facet call once the elasticsearch refactor is complete
|
|
52
|
+
const results = flatten(await Promise.all(queries.map(async ({ query, type }) => {
|
|
53
|
+
const result = await dispatchApi(api.search.hit.post({ query, rows: 250, fl: 'howler.rationale,howler.assignment' }), { throwError: false });
|
|
54
|
+
return uniqBy((result?.items ?? []).map(_hit => ({ rationale: _hit.howler.rationale, type })), 'rationale');
|
|
55
|
+
})));
|
|
56
|
+
setSuggestedRationales(results);
|
|
57
|
+
setLoading(false);
|
|
58
|
+
})();
|
|
59
|
+
}, [dispatchApi, queries]);
|
|
60
|
+
return (_jsxs(Stack, { spacing: 2, p: 2, alignItems: "start", sx: { minWidth: '500px' }, children: [_jsx(Typography, { variant: "h4", children: t('modal.rationale.title') }), _jsx(Typography, { children: t('modal.rationale.description') }), _jsx(Autocomplete, { loading: loading, loadingText: t('loading'), freeSolo: true, value: rationale, onChange: (_, newValue) => setRationale(isString(newValue) ? newValue : (newValue?.rationale ?? '')), options: suggestedRationales, getOptionLabel: suggestion => (isString(suggestion) ? suggestion : suggestion.rationale), isOptionEqualToValue: (option, value) => isString(value) ? option.rationale === value : isEqual(option, value), fullWidth: true, disablePortal: true, renderInput: params => (_jsx(TextField, { ...params, label: t('modal.rationale.label'), onChange: e => setRationale(e.target.value), onKeyDown: handleKeydown, InputProps: {
|
|
61
|
+
...params.InputProps,
|
|
62
|
+
endAdornment: (_jsxs(_Fragment, { children: [loading ? _jsx(CircularProgress, { color: "inherit", size: 20 }) : null, params.InputProps.endAdornment] }))
|
|
63
|
+
} })), renderOption: (props, option) => (_jsx(ListItemText, { ...props, sx: { flexDirection: 'column', alignItems: 'start !important' }, primary: option.rationale, secondary: t(`modal.rationale.type.${option.type}`) })) }), _jsxs(Stack, { direction: "row", spacing: 1, alignSelf: "end", children: [_jsx(Button, { variant: "outlined", onClick: close, children: t('cancel') }), _jsx(Button, { variant: "outlined", onClick: handleSubmit, children: t('submit') })] })] }));
|
|
27
64
|
};
|
|
28
65
|
export default RationaleModal;
|
|
@@ -94,7 +94,7 @@ const useHitActions = (_hits) => {
|
|
|
94
94
|
const rationale = skipRationale
|
|
95
95
|
? t('rationale.default', { assessment })
|
|
96
96
|
: await new Promise(res => {
|
|
97
|
-
showModal(_jsx(RationaleModal, { onSubmit: _rationale => {
|
|
97
|
+
showModal(_jsx(RationaleModal, { hits: hits, onSubmit: _rationale => {
|
|
98
98
|
res(_rationale);
|
|
99
99
|
} }));
|
|
100
100
|
});
|
|
@@ -306,6 +306,8 @@
|
|
|
306
306
|
"modal.rationale.title": "Add Rationale",
|
|
307
307
|
"modal.rationale.description": "Provide a rationale that succinctly explains to other analysts why you are confident in this assessment.",
|
|
308
308
|
"modal.rationale.label": "Rationale",
|
|
309
|
+
"modal.rationale.type.analytic": "This rationale was used when assessing alerts with the same analytic name.",
|
|
310
|
+
"modal.rationale.type.assignment": "This is a rationale you have recently used when assessing an alert.",
|
|
309
311
|
"none": "None",
|
|
310
312
|
"no.data": "No Data",
|
|
311
313
|
"on": "on",
|
|
@@ -308,6 +308,8 @@
|
|
|
308
308
|
"modal.rationale.title": "Ajouter une justification",
|
|
309
309
|
"modal.rationale.description": "Fournissez une justification qui explique succinctement aux autres analystes les raisons pour lesquelles vous êtes confiant dans cette évaluation.",
|
|
310
310
|
"modal.rationale.label": "Justification",
|
|
311
|
+
"modal.rationale.type.analytic": "Cette justification a été utilisée lors de l'évaluation des alertes avec le même nom d'analyse.",
|
|
312
|
+
"modal.rationale.type.assignment": "Il s'agit d'une justification que vous avez récemment utilisée lors de l'évaluation d'une alerte.",
|
|
311
313
|
"none": "Rien",
|
|
312
314
|
"no.data": "Aucune donnée",
|
|
313
315
|
"on": "sur",
|