@cccsaurora/howler-ui 2.19.0-dev.916 → 2.19.0-dev.921
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/addons/lists/TuiListBase.js +4 -0
- package/components/elements/addons/lists/TuiListElement.js +6 -3
- package/components/elements/addons/lists/index.d.ts +1 -0
- package/components/elements/display/modals/ConfirmDeleteModal.d.ts +4 -0
- package/components/elements/display/modals/ConfirmDeleteModal.js +4 -2
- package/components/routes/templates/TemplateCard.d.ts +3 -1
- package/components/routes/templates/TemplateCard.js +8 -4
- package/components/routes/templates/Templates.js +23 -6
- package/locales/en/translation.json +4 -0
- package/locales/fr/translation.json +4 -0
- package/package.json +3 -3
|
@@ -30,6 +30,10 @@ const TuiListBaseRoot = styled('div')(({ theme }) => ({
|
|
|
30
30
|
display: 'flex',
|
|
31
31
|
backgroundColor: emphasize(theme.palette.background.default, 0.04)
|
|
32
32
|
}
|
|
33
|
+
},
|
|
34
|
+
'.elementDisabled': {
|
|
35
|
+
color: theme.palette.text.disabled,
|
|
36
|
+
cursor: 'default'
|
|
33
37
|
}
|
|
34
38
|
}));
|
|
35
39
|
const TuiListBase = ({ keyboard = false, onSelect, children }) => {
|
|
@@ -5,11 +5,14 @@ import VSBoxElement from '../layout/vsbox/VSBoxElement';
|
|
|
5
5
|
const TuiListElement = ({ position, item, onSelect: onClick, children }) => {
|
|
6
6
|
const elementEl = useRef();
|
|
7
7
|
const onItemClick = useCallback(_event => {
|
|
8
|
-
if (onClick) {
|
|
8
|
+
if (onClick && !item.disabled) {
|
|
9
9
|
onClick(item, position);
|
|
10
10
|
}
|
|
11
11
|
}, [onClick, item, position]);
|
|
12
12
|
const classRenderer = useCallback(() => {
|
|
13
|
+
if (item.disabled) {
|
|
14
|
+
return 'elementDisabled';
|
|
15
|
+
}
|
|
13
16
|
const _classes = ['elementHover'];
|
|
14
17
|
if (item.cursor) {
|
|
15
18
|
_classes.push('elementFocus');
|
|
@@ -18,7 +21,7 @@ const TuiListElement = ({ position, item, onSelect: onClick, children }) => {
|
|
|
18
21
|
_classes.push('elementSelected');
|
|
19
22
|
}
|
|
20
23
|
return _classes.join(' ');
|
|
21
|
-
}, [item.cursor, item.selected]);
|
|
22
|
-
return (_jsx(VSBoxElement, { focus: !!item.cursor, children: _jsx("div", { ref: elementEl, "data-tuilist-index": position, "data-tuilist-id": item.id, "data-tuilist-focus": !!item.cursor, "data-tuilist-selected": !!item.selected, onClick: onItemClick, children: children({ item, position }, classRenderer) }) }));
|
|
24
|
+
}, [item.cursor, item.selected, item.disabled]);
|
|
25
|
+
return (_jsx(VSBoxElement, { focus: !!item.cursor, children: _jsx("div", { ref: elementEl, "data-tuilist-index": position, "data-tuilist-id": item.id, "data-tuilist-focus": !!item.cursor, "data-tuilist-selected": !!item.selected, "aria-disabled": item.disabled, onClick: onItemClick, children: children({ item, position }, classRenderer) }) }));
|
|
23
26
|
};
|
|
24
27
|
export default memo(TuiListElement);
|
|
@@ -3,13 +3,15 @@ import { Button, Stack, Typography } from '@mui/material';
|
|
|
3
3
|
import { ModalContext } from '@cccsaurora/howler-ui/components/app/providers/ModalProvider';
|
|
4
4
|
import { useCallback, useContext } from 'react';
|
|
5
5
|
import { useTranslation } from 'react-i18next';
|
|
6
|
-
const ConfirmDeleteModal = ({ onConfirm }) => {
|
|
6
|
+
const ConfirmDeleteModal = ({ onConfirm, title, description, preferDelete, preferCancel }) => {
|
|
7
7
|
const { t } = useTranslation();
|
|
8
8
|
const { close } = useContext(ModalContext);
|
|
9
9
|
const handleConfirm = useCallback(() => {
|
|
10
10
|
onConfirm();
|
|
11
11
|
close();
|
|
12
12
|
}, [close, onConfirm]);
|
|
13
|
-
|
|
13
|
+
const modalTitle = title ?? t('modal.confirm.delete.title');
|
|
14
|
+
const modalDesc = description ?? t('modal.confirm.delete.description');
|
|
15
|
+
return (_jsxs(Stack, { spacing: 2, p: 2, alignItems: "start", sx: { minWidth: '500px' }, children: [_jsx(Typography, { variant: "h4", children: modalTitle }), _jsx(Typography, { children: modalDesc }), _jsxs(Stack, { direction: "row", spacing: 1, alignSelf: "end", children: [_jsx(Button, { variant: preferCancel ? 'contained' : 'outlined', onClick: close, children: t('button.cancel') }), _jsx(Button, { variant: preferDelete ? 'contained' : 'outlined', onClick: handleConfirm, children: t('button.delete') })] })] }));
|
|
14
16
|
};
|
|
15
17
|
export default ConfirmDeleteModal;
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import type { Template } from '@cccsaurora/howler-ui/models/entities/generated/Template';
|
|
2
|
-
import type
|
|
2
|
+
import { type FC } from 'react';
|
|
3
3
|
declare const TemplateCard: FC<{
|
|
4
4
|
template: Template;
|
|
5
|
+
onRemove?: (templateId: string) => void;
|
|
6
|
+
error?: boolean;
|
|
5
7
|
className?: string;
|
|
6
8
|
}>;
|
|
7
9
|
export default TemplateCard;
|
|
@@ -1,13 +1,17 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
import { Language, Lock, Person } from '@mui/icons-material';
|
|
3
|
-
import { Card, Divider, Stack, Tooltip, Typography } from '@mui/material';
|
|
2
|
+
import { Language, Lock, Person, ReportProblem } from '@mui/icons-material';
|
|
3
|
+
import { Button, Card, Divider, Stack, Tooltip, Typography } from '@mui/material';
|
|
4
|
+
import { ModalContext } from '@cccsaurora/howler-ui/components/app/providers/ModalProvider';
|
|
5
|
+
import ConfirmDeleteModal from '@cccsaurora/howler-ui/components/elements/display/modals/ConfirmDeleteModal';
|
|
6
|
+
import { useContext } from 'react';
|
|
4
7
|
import { useTranslation } from 'react-i18next';
|
|
5
|
-
const TemplateCard = ({ template, className }) => {
|
|
8
|
+
const TemplateCard = ({ template, onRemove, error, className }) => {
|
|
6
9
|
const { t } = useTranslation();
|
|
10
|
+
const { showModal } = useContext(ModalContext);
|
|
7
11
|
return (_jsx(Card, { variant: "outlined", sx: { p: 1, mb: 1 }, className: className, children: _jsxs(Stack, { direction: "row", spacing: 1, children: [_jsx(Tooltip, { title: t(`route.templates.manager.${template.type}`), children: {
|
|
8
12
|
readonly: _jsx(Lock, {}),
|
|
9
13
|
global: _jsx(Language, {}),
|
|
10
14
|
personal: _jsx(Person, {})
|
|
11
|
-
}[template.type] }), _jsx(Divider, { orientation: "vertical", flexItem: true }), _jsxs(Stack, { children: [_jsxs(Typography, { variant: "body1", children: [t(template.analytic), " - ", t(template.detection ?? 'all')] }), template.keys.map(key => (_jsx(Typography, { variant: "caption", sx: { ml: 1 }, children: _jsx("code", { children: key }) }, template.template_id + key)))] })] }) }, template.template_id));
|
|
15
|
+
}[template.type] }), _jsx(Divider, { orientation: "vertical", flexItem: true }), _jsxs(Stack, { children: [_jsxs(Typography, { variant: "body1", children: [t(template.analytic), " - ", t(template.detection ?? 'all')] }), template.keys.map(key => (_jsx(Typography, { variant: "caption", sx: { ml: 1 }, children: _jsx("code", { children: key }) }, template.template_id + key)))] }), error && (_jsx(Stack, { direction: "row", justifyContent: "end", width: "100%", children: _jsx(Stack, { children: _jsx(Tooltip, { title: t('route.templates.manager.error.action'), children: _jsx(Button, { startIcon: _jsx(ReportProblem, {}), color: "warning", onClick: () => showModal(_jsx(ConfirmDeleteModal, { onConfirm: () => onRemove?.(template.template_id), title: t('route.templates.manager.error.modal.title'), description: t('route.templates.manager.error.modal.description'), preferDelete: true })), children: t('route.templates.manager.error.message') }) }) }) }))] }) }, template.template_id));
|
|
12
16
|
};
|
|
13
17
|
export default TemplateCard;
|
|
@@ -3,6 +3,7 @@ import { Article } from '@mui/icons-material';
|
|
|
3
3
|
import { Stack, ToggleButton, ToggleButtonGroup, Typography } from '@mui/material';
|
|
4
4
|
import api from '@cccsaurora/howler-ui/api';
|
|
5
5
|
import { useAppUser } from '@cccsaurora/howler-ui/commons/components/app/hooks';
|
|
6
|
+
import { AnalyticContext } from '@cccsaurora/howler-ui/components/app/providers/AnalyticProvider';
|
|
6
7
|
import { TuiListProvider } from '@cccsaurora/howler-ui/components/elements/addons/lists';
|
|
7
8
|
import { TuiListMethodContext } from '@cccsaurora/howler-ui/components/elements/addons/lists/TuiListProvider';
|
|
8
9
|
import ItemManager from '@cccsaurora/howler-ui/components/elements/display/ItemManager';
|
|
@@ -19,8 +20,9 @@ const TemplatesBase = () => {
|
|
|
19
20
|
const navigate = useNavigate();
|
|
20
21
|
const { dispatchApi } = useMyApi();
|
|
21
22
|
const [searchParams, setSearchParams] = useSearchParams();
|
|
22
|
-
const { load } = useContext(TuiListMethodContext);
|
|
23
|
+
const { load, remove } = useContext(TuiListMethodContext);
|
|
23
24
|
const pageCount = useMyLocalStorageItem(StorageKey.PAGE_COUNT, 25)[0];
|
|
25
|
+
const { analytics } = useContext(AnalyticContext);
|
|
24
26
|
const [phrase, setPhrase] = useState('');
|
|
25
27
|
const [offset, setOffset] = useState(parseInt(searchParams.get('offset')) || 0);
|
|
26
28
|
const [response, setResponse] = useState(null);
|
|
@@ -57,17 +59,22 @@ const TemplatesBase = () => {
|
|
|
57
59
|
}, [phrase, setSearchParams, searchParams, user.username, types, dispatchApi, pageCount, offset]);
|
|
58
60
|
// Load the items into list when response changes.
|
|
59
61
|
// This hook should only trigger when the 'response' changes.
|
|
62
|
+
// or if the analytic list changes to refresh the disabled state
|
|
60
63
|
useEffect(() => {
|
|
61
64
|
if (response) {
|
|
62
65
|
load(response.items.map((item) => ({
|
|
63
66
|
id: item.template_id,
|
|
64
67
|
item,
|
|
65
68
|
selected: false,
|
|
66
|
-
cursor: false
|
|
69
|
+
cursor: false,
|
|
70
|
+
disabled: item.detection &&
|
|
71
|
+
!analytics
|
|
72
|
+
.find(v => v.name === item.analytic)
|
|
73
|
+
?.detections?.map((s) => s.toLowerCase())
|
|
74
|
+
?.includes(item.detection?.toLowerCase())
|
|
67
75
|
})));
|
|
68
76
|
}
|
|
69
|
-
|
|
70
|
-
}, [response, load]);
|
|
77
|
+
}, [response, load, analytics]);
|
|
71
78
|
const onPageChange = useCallback((_offset) => {
|
|
72
79
|
if (_offset !== offset) {
|
|
73
80
|
searchParams.set('offset', _offset.toString());
|
|
@@ -96,12 +103,22 @@ const TemplatesBase = () => {
|
|
|
96
103
|
}
|
|
97
104
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
98
105
|
}, [offset]);
|
|
99
|
-
const
|
|
106
|
+
const removeTemplate = useCallback(async (templateId) => {
|
|
107
|
+
await dispatchApi(api.template.del(templateId), {
|
|
108
|
+
logError: false,
|
|
109
|
+
showError: true,
|
|
110
|
+
throwError: false
|
|
111
|
+
});
|
|
112
|
+
remove(templateId);
|
|
113
|
+
}, [dispatchApi, remove]);
|
|
114
|
+
const renderer = useCallback((item, error, className) => (_jsx(TemplateCard, { template: item, error: error, onRemove: removeTemplate, className: className })), [removeTemplate]);
|
|
100
115
|
return (_jsx(ItemManager, { onSearch: onSearch, onPageChange: onPageChange, phrase: phrase, setPhrase: setPhrase, hasError: hasError, searching: searching, searchFilters: _jsx(Stack, { direction: "row", spacing: 1, alignItems: "center", children: _jsxs(ToggleButtonGroup, { sx: { display: 'grid', gridTemplateColumns: '1fr 1fr', alignSelf: 'start' }, size: "small", value: types, onChange: (__, _types) => {
|
|
101
116
|
if (_types) {
|
|
102
117
|
setTypes(_types.length < 2 ? _types : []);
|
|
103
118
|
}
|
|
104
|
-
}, children: [_jsx(ToggleButton, { value: "personal", "aria-label": "personal", children: t('route.templates.manager.personal') }), _jsx(ToggleButton, { value: "global", "aria-label": "global", children: t('route.templates.manager.global') })] }) }), aboveSearch: _jsx(Typography, { sx: theme => ({ fontStyle: 'italic', color: theme.palette.text.disabled, mb: 0.5 }), variant: "body2", children: t('route.templates.search.prompt') }), renderer: ({ item }, classRenderer) => renderer(item.item, classRenderer()), response: response, onSelect: (item) =>
|
|
119
|
+
}, children: [_jsx(ToggleButton, { value: "personal", "aria-label": "personal", children: t('route.templates.manager.personal') }), _jsx(ToggleButton, { value: "global", "aria-label": "global", children: t('route.templates.manager.global') })] }) }), aboveSearch: _jsx(Typography, { sx: theme => ({ fontStyle: 'italic', color: theme.palette.text.disabled, mb: 0.5 }), variant: "body2", children: t('route.templates.search.prompt') }), renderer: ({ item }, classRenderer) => renderer(item.item, !!item.disabled, classRenderer()), response: response, onSelect: (item) => {
|
|
120
|
+
navigate(`/templates/view?type=${item.item.type}&analytic=${item.item.analytic}${item.item.detection ? '&detection=' + item.item.detection : ''}`);
|
|
121
|
+
}, onCreate: () => navigate('/templates/view'), createPrompt: "route.templates.create", searchPrompt: "route.templates.manager.search", createIcon: _jsx(Article, { sx: { mr: 1 } }) }));
|
|
105
122
|
};
|
|
106
123
|
const Templates = () => {
|
|
107
124
|
return (_jsx(TuiListProvider, { children: _jsx(TemplatesBase, {}) }));
|
|
@@ -670,6 +670,10 @@
|
|
|
670
670
|
"route.templates.manager.personal": "Personal",
|
|
671
671
|
"route.templates.manager.readonly": "Built-in",
|
|
672
672
|
"route.templates.manager.search": "Search Templates",
|
|
673
|
+
"route.templates.manager.error.message": "Invalid Detection",
|
|
674
|
+
"route.templates.manager.error.action": "Click to open quick fix options",
|
|
675
|
+
"route.templates.manager.error.modal.title": "Template detection no longer exists",
|
|
676
|
+
"route.templates.manager.error.modal.description": "The template fields are read only and will not be used. Do you want to remove the template?",
|
|
673
677
|
"route.templates.personal": "Personal",
|
|
674
678
|
"route.templates.prompt": "Activate autocomplete using [ctrl + space].",
|
|
675
679
|
"route.templates.readonly.warning": "This is a built-in template, and cannot be edited. To make changes to it, contact",
|
|
@@ -674,6 +674,10 @@
|
|
|
674
674
|
"route.templates.manager.personal": "Personnel",
|
|
675
675
|
"route.templates.manager.readonly": "Intégré",
|
|
676
676
|
"route.templates.manager.search": "Rechercher les modèles",
|
|
677
|
+
"route.templates.manager.error.message": "Détection non valide",
|
|
678
|
+
"route.templates.manager.error.action": "Cliquez ici pour afficher les options de correction rapide",
|
|
679
|
+
"route.templates.manager.error.modal.title": "La détection du modèle n'existe plus",
|
|
680
|
+
"route.templates.manager.error.modal.description": "Les clés du modèle sont en lecture seule et ne seront pas utilisées. Voulez-vous supprimer le modèle ?",
|
|
677
681
|
"route.templates.personal": "Personnel",
|
|
678
682
|
"route.templates.prompt": "Activer l'autocomplétion en utilisant [ctrl + espace].",
|
|
679
683
|
"route.templates.readonly.warning": "Il s'agit d'un modèle intégré qui ne peut pas être modifié. Pour le modifier, veuillez contacter",
|
package/package.json
CHANGED
|
@@ -28,13 +28,13 @@
|
|
|
28
28
|
"@monaco-editor/react": "^4.7.0",
|
|
29
29
|
"ajv": "^8.20.0",
|
|
30
30
|
"ajv-i18n": "^4.2.0",
|
|
31
|
-
"axios": "^1.16.
|
|
31
|
+
"axios": "^1.16.1",
|
|
32
32
|
"axios-retry": "^3.9.1",
|
|
33
33
|
"chart.js": "^4.5.1",
|
|
34
34
|
"chartjs-adapter-dayjs-4": "^1.0.4",
|
|
35
35
|
"chartjs-plugin-zoom": "^2.2.0",
|
|
36
36
|
"dayjs": "^1.11.20",
|
|
37
|
-
"dompurify": "^3.4.
|
|
37
|
+
"dompurify": "^3.4.5",
|
|
38
38
|
"flat": "^6.0.1",
|
|
39
39
|
"fuse.js": "^7.3.0",
|
|
40
40
|
"handlebars": "^4.7.9",
|
|
@@ -96,7 +96,7 @@
|
|
|
96
96
|
"internal-slot": "1.0.7"
|
|
97
97
|
},
|
|
98
98
|
"type": "module",
|
|
99
|
-
"version": "2.19.0-dev.
|
|
99
|
+
"version": "2.19.0-dev.921",
|
|
100
100
|
"exports": {
|
|
101
101
|
"./i18n": "./i18n.js",
|
|
102
102
|
"./index.css": "./index.css",
|