@cccsaurora/howler-ui 2.19.0-dev.920 → 2.19.0-dev.922
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/elements/hit/HitSummary.js +3 -2
- package/components/routes/settings/LocalSection.js +2 -1
- 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 +8 -2
- package/locales/fr/translation.json +8 -2
- package/package.json +1 -1
- package/utils/constants.d.ts +1 -0
- package/utils/constants.js +1 -0
|
@@ -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,4 +1,4 @@
|
|
|
1
|
-
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
1
|
+
import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
import { Analytics, InfoOutlined } from '@mui/icons-material';
|
|
3
3
|
import { Alert, AlertTitle, Autocomplete, Box, Button, Chip, CircularProgress, Divider, Fade, Grid, LinearProgress, Stack, TextField, Tooltip, Typography } from '@mui/material';
|
|
4
4
|
import api from '@cccsaurora/howler-ui/api';
|
|
@@ -23,6 +23,7 @@ const HitSummary = ({ response, onStart, onComplete }) => {
|
|
|
23
23
|
const { hitFields } = useContext(FieldContext);
|
|
24
24
|
const { showErrorMessage } = useMySnackbar();
|
|
25
25
|
const pageCount = useMyLocalStorageItem(StorageKey.PAGE_COUNT, 25)[0];
|
|
26
|
+
const [showHitSummaryGraph] = useMyLocalStorageItem(StorageKey.SHOW_HIT_SUMMARY_GRAPH, true);
|
|
26
27
|
const { getMatchingTemplate } = useMatchers();
|
|
27
28
|
const searching = useContextSelector(HitSearchContext, ctx => ctx.searching);
|
|
28
29
|
const error = useContextSelector(HitSearchContext, ctx => ctx.error);
|
|
@@ -130,7 +131,7 @@ const HitSummary = ({ response, onStart, onComplete }) => {
|
|
|
130
131
|
performAggregation();
|
|
131
132
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
132
133
|
}, [query, views, searching, error]);
|
|
133
|
-
return (_jsxs(Stack, { sx: { mx: 2, height: '100%' }, spacing: 1, children: [_jsx(Typography, { variant: "h6", children: t('hit.summary.aggregate.title') }), _jsx(Divider, { flexItem: true }), _jsx(HitGraph, {}), _jsx(Divider, { flexItem: true }), _jsxs(Stack, { sx: { overflow: 'auto', marginTop: '0 !important' }, pt: 1, spacing: 1, children: [_jsxs(Stack, { direction: "row", spacing: 2, mb: 2, alignItems: "stretch", children: [_jsx(Autocomplete, { fullWidth: true, multiple: true, sx: { minWidth: '175px' }, size: "small", value: customKeys, options: hitFields.map(_field => _field.key), renderInput: _params => _jsx(TextField, { ..._params, label: t('hit.summary.adhoc') }), onChange: (_, value) => setCustomKeys(value) }), _jsx(Button, { variant: "outlined", startIcon: loading ? _jsx(CircularProgress, { size: 20, sx: { ml: 1 } }) : _jsx(Analytics, { sx: { ml: 1 } }), disabled: loading, onClick: () => performAggregation(), children: t('button.aggregate') })] }), isEmpty(aggregateResults) && (_jsxs(Alert, { severity: "info", variant: "outlined", children: [_jsx(AlertTitle, { children: t('hit.summary.aggregate.nokeys.title') }), t('hit.summary.aggregate.nokeys.description')] })), loading && _jsx(LinearProgress, { sx: { minHeight: '4px' } }), Object.keys(aggregateResults)
|
|
134
|
+
return (_jsxs(Stack, { sx: { mx: 2, height: '100%' }, spacing: 1, children: [_jsx(Typography, { variant: "h6", children: t('hit.summary.aggregate.title') }), _jsx(Divider, { flexItem: true }), showHitSummaryGraph && (_jsxs(_Fragment, { children: [_jsx(HitGraph, {}), _jsx(Divider, { flexItem: true })] })), _jsxs(Stack, { sx: { overflow: 'auto', marginTop: '0 !important' }, pt: 1, spacing: 1, children: [_jsxs(Stack, { direction: "row", spacing: 2, mb: 2, alignItems: "stretch", children: [_jsx(Autocomplete, { fullWidth: true, multiple: true, sx: { minWidth: '175px' }, size: "small", value: customKeys, options: hitFields.map(_field => _field.key), renderInput: _params => _jsx(TextField, { ..._params, label: t('hit.summary.adhoc') }), onChange: (_, value) => setCustomKeys(value) }), _jsx(Button, { variant: "outlined", startIcon: loading ? _jsx(CircularProgress, { size: 20, sx: { ml: 1 } }) : _jsx(Analytics, { sx: { ml: 1 } }), disabled: loading, onClick: () => performAggregation(), children: t('button.aggregate') })] }), isEmpty(aggregateResults) && (_jsxs(Alert, { severity: "info", variant: "outlined", children: [_jsx(AlertTitle, { children: t('hit.summary.aggregate.nokeys.title') }), t('hit.summary.aggregate.nokeys.description')] })), loading && _jsx(LinearProgress, { sx: { minHeight: '4px' } }), Object.keys(aggregateResults)
|
|
134
135
|
.filter(key => !isEmpty(aggregateResults[key]))
|
|
135
136
|
.flatMap(key => [
|
|
136
137
|
_jsx(Fade, { in: true, children: _jsxs(Stack, { direction: "row", alignItems: "center", spacing: 1, children: [_jsx(Typography, { variant: "body1", children: key }, key + '-title'), keyCounts[key]?.count < 0 ? (_jsxs(Typography, { variant: "caption", color: "text.secondary", children: ["(", t('hit.summary.adhoc.custom'), ")"] })) : (_jsxs(Typography, { variant: "caption", color: "text.secondary", children: ["(", keyCounts[key]?.count ?? '?', " ", t('references'), ")"] })), _jsx(Tooltip, { title: _jsxs(Stack, { children: [_jsx(Typography, { variant: "caption", children: t('hit.summary.aggregate.sources') }), keyCounts[key]?.sources.map(source => (_jsx(Typography, { variant: "caption", children: source }, source))) ?? '?'] }), children: _jsx(InfoOutlined, { fontSize: "inherit" }) })] }) }, key + '-refs'),
|
|
@@ -17,11 +17,12 @@ const LocalSection = () => {
|
|
|
17
17
|
const [compactJson, setCompactJson] = useMyLocalStorageItem(StorageKey.COMPACT_JSON, true);
|
|
18
18
|
const [flattenJson, setFlattenJson] = useMyLocalStorageItem(StorageKey.FLATTEN_JSON, false);
|
|
19
19
|
const [forceDrawer, setForceDrawer] = useMyLocalStorageItem(StorageKey.FORCE_DRAWER, false);
|
|
20
|
+
const [showHitSummaryGraph, setShowHitSummaryGraph] = useMyLocalStorageItem(StorageKey.SHOW_HIT_SUMMARY_GRAPH, true);
|
|
20
21
|
const [hitLayout, setHitLayout] = useMyLocalStorageItem(StorageKey.HIT_LAYOUT, false);
|
|
21
22
|
const [displayType, setDisplayType] = useMyLocalStorageItem(StorageKey.DISPLAY_TYPE, 'list');
|
|
22
23
|
const [pageCount, setPageCount] = useMyLocalStorageItem(StorageKey.PAGE_COUNT, 25);
|
|
23
24
|
const [searchWidth, setSearchWidth] = useMyLocalStorageItem(StorageKey.SEARCH_PANE_WIDTH, null);
|
|
24
25
|
const [templateFieldCount, setTemplateFieldCount] = useMyLocalStorageItem(StorageKey.TEMPLATE_FIELD_COUNT, null);
|
|
25
|
-
return (_jsxs(SettingsSection, { title: t('page.settings.local.title'), colSpan: 3, children: [_jsx(EditRow, { titleKey: "page.settings.local.compact.json", descriptionKey: "page.settings.local.compact.json.description", value: compactJson, type: "checkbox", onEdit: async (value) => setCompactJson(JSON.parse(value)) }), _jsx(EditRow, { titleKey: "page.settings.local.flatten.json", descriptionKey: "page.settings.local.flatten.json.description", value: flattenJson, type: "checkbox", onEdit: async (value) => setFlattenJson(JSON.parse(value)) }), _jsx(EditRow, { titleKey: "page.settings.local.details.drawer", descriptionKey: "page.settings.local.details.drawer.description", value: forceDrawer, type: "checkbox", onEdit: async (value) => setForceDrawer(JSON.parse(value)) }), _jsx(EditRow, { titleKey: "page.settings.local.search.width", descriptionKey: "page.settings.local.search.width.description", value: searchWidth, type: "range", min: 400, max: Math.floor(window.innerWidth / 100) * 100, optional: true, onEdit: async (value) => setSearchWidth(value ? parseInt(value) : null) }), _jsxs(TableRow, { children: [_jsx(TableCell, { sx: CELL_SX, style: { whiteSpace: 'nowrap' }, children: t('page.settings.local.hits.layout') }), _jsx(TableCell, { sx: CELL_SX, colSpan: 2, align: "right", children: _jsxs(ToggleButtonGroup, { size: "small", value: hitLayout, exclusive: true, onChange: (_, value) => setHitLayout(value), children: [_jsx(ToggleButton, { value: HitLayout.DENSE, children: _jsxs(Stack, { direction: "row", spacing: 0.5, children: [_jsx(ViewCompact, {}), _jsx("span", { children: t('page.settings.local.hits.layout.dense') })] }) }), _jsx(ToggleButton, { value: HitLayout.NORMAL, children: _jsxs(Stack, { direction: "row", spacing: 0.5, children: [_jsx(ViewModule, {}), _jsx("span", { children: t('page.settings.local.hits.layout.normal') })] }) }), _jsx(ToggleButton, { value: HitLayout.COMFY, children: _jsxs(Stack, { direction: "row", spacing: 0.5, children: [_jsx(ViewComfy, {}), _jsx("span", { children: t('page.settings.local.hits.layout.comfy') })] }) })] }) })] }), _jsx(TableRow, { children: _jsx(TableCell, { colSpan: 3, sx: { paddingTop: '0 !important' }, children: _jsx(Typography, { variant: "caption", color: "text.secondary", children: t('page.settings.local.hits.layout.description') }) }) }), _jsx(EditRow, { titleKey: "page.settings.local.hits.field_count", descriptionKey: "page.settings.local.hits.field_count.description", value: templateFieldCount, type: "range", min: 0, step: 1, max: 15, optional: true, onEdit: async (value) => setTemplateFieldCount(value ? parseInt(value) : null), valueLabelFormat: val => val.toString() }), _jsxs(TableRow, { children: [_jsx(TableCell, { sx: CELL_SX, style: { whiteSpace: 'nowrap' }, children: t('page.settings.local.hits.display_type') }), _jsx(TableCell, { sx: CELL_SX, colSpan: 2, align: "right", children: _jsxs(ToggleButtonGroup, { size: "small", value: displayType, exclusive: true, onChange: (_, value) => setDisplayType(value), children: [_jsx(ToggleButton, { value: "list", children: _jsxs(Stack, { direction: "row", spacing: 0.5, children: [_jsx(List, {}), _jsx("span", { children: t('page.settings.local.hits.display_type.list') })] }) }), _jsx(ToggleButton, { value: "grid", children: _jsxs(Stack, { direction: "row", spacing: 0.5, children: [_jsx(TableChart, {}), _jsx("span", { children: t('page.settings.local.hits.display_type.grid') })] }) })] }) })] }), _jsx(TableRow, { children: _jsx(TableCell, { colSpan: 3, sx: { paddingTop: '0 !important' }, children: _jsx(Typography, { variant: "caption", color: "text.secondary", children: t('page.settings.local.hits.display_type.description') }) }) }), _jsxs(TableRow, { children: [_jsx(TableCell, { sx: CELL_SX, style: { whiteSpace: 'nowrap' }, children: t('page.settings.local.results.count') }), _jsx(TableCell, { sx: CELL_SX, colSpan: 2, align: "right", children: _jsxs(Select, { size: "small", sx: { minWidth: '75px', textAlign: 'left' }, value: pageCount, onChange: event => setPageCount(typeof event.target.value === 'string' ? parseInt(event.target.value) : event.target.value), children: [_jsx(MenuItem, { value: 5, children: "5" }), _jsx(MenuItem, { value: 10, children: "10" }), _jsx(MenuItem, { value: 25, children: "25" }), _jsx(MenuItem, { value: 50, children: "50" }), _jsx(MenuItem, { value: 75, children: "75" }), _jsx(MenuItem, { value: 100, children: "100" }), _jsx(MenuItem, { value: 150, children: "150" }), _jsx(MenuItem, { value: 250, children: "250" })] }) })] }), _jsx(TableRow, { children: _jsx(TableCell, { colSpan: 3, sx: { paddingTop: '0 !important' }, children: _jsx(Typography, { variant: "caption", color: "text.secondary", children: t('page.settings.local.results.count.description') }) }) }), howlerPluginStore.plugins.map(plugin => pluginStore.executeFunction(`${plugin}.settings`, 'local'))] }));
|
|
26
|
+
return (_jsxs(SettingsSection, { title: t('page.settings.local.title'), colSpan: 3, children: [_jsx(EditRow, { titleKey: "page.settings.local.compact.json", descriptionKey: "page.settings.local.compact.json.description", value: compactJson, type: "checkbox", onEdit: async (value) => setCompactJson(JSON.parse(value)) }), _jsx(EditRow, { titleKey: "page.settings.local.flatten.json", descriptionKey: "page.settings.local.flatten.json.description", value: flattenJson, type: "checkbox", onEdit: async (value) => setFlattenJson(JSON.parse(value)) }), _jsx(EditRow, { titleKey: "page.settings.local.details.drawer", descriptionKey: "page.settings.local.details.drawer.description", value: forceDrawer, type: "checkbox", onEdit: async (value) => setForceDrawer(JSON.parse(value)) }), _jsx(EditRow, { titleKey: "page.settings.local.show.hit.summary.graph", descriptionKey: "page.settings.local.show.hit.summary.graph.description", value: showHitSummaryGraph, type: "checkbox", onEdit: async (value) => setShowHitSummaryGraph(JSON.parse(value)) }), _jsx(EditRow, { titleKey: "page.settings.local.search.width", descriptionKey: "page.settings.local.search.width.description", value: searchWidth, type: "range", min: 400, max: Math.floor(window.innerWidth / 100) * 100, optional: true, onEdit: async (value) => setSearchWidth(value ? parseInt(value) : null) }), _jsxs(TableRow, { children: [_jsx(TableCell, { sx: CELL_SX, style: { whiteSpace: 'nowrap' }, children: t('page.settings.local.hits.layout') }), _jsx(TableCell, { sx: CELL_SX, colSpan: 2, align: "right", children: _jsxs(ToggleButtonGroup, { size: "small", value: hitLayout, exclusive: true, onChange: (_, value) => setHitLayout(value), children: [_jsx(ToggleButton, { value: HitLayout.DENSE, children: _jsxs(Stack, { direction: "row", spacing: 0.5, children: [_jsx(ViewCompact, {}), _jsx("span", { children: t('page.settings.local.hits.layout.dense') })] }) }), _jsx(ToggleButton, { value: HitLayout.NORMAL, children: _jsxs(Stack, { direction: "row", spacing: 0.5, children: [_jsx(ViewModule, {}), _jsx("span", { children: t('page.settings.local.hits.layout.normal') })] }) }), _jsx(ToggleButton, { value: HitLayout.COMFY, children: _jsxs(Stack, { direction: "row", spacing: 0.5, children: [_jsx(ViewComfy, {}), _jsx("span", { children: t('page.settings.local.hits.layout.comfy') })] }) })] }) })] }), _jsx(TableRow, { children: _jsx(TableCell, { colSpan: 3, sx: { paddingTop: '0 !important' }, children: _jsx(Typography, { variant: "caption", color: "text.secondary", children: t('page.settings.local.hits.layout.description') }) }) }), _jsx(EditRow, { titleKey: "page.settings.local.hits.field_count", descriptionKey: "page.settings.local.hits.field_count.description", value: templateFieldCount, type: "range", min: 0, step: 1, max: 15, optional: true, onEdit: async (value) => setTemplateFieldCount(value ? parseInt(value) : null), valueLabelFormat: val => val.toString() }), _jsxs(TableRow, { children: [_jsx(TableCell, { sx: CELL_SX, style: { whiteSpace: 'nowrap' }, children: t('page.settings.local.hits.display_type') }), _jsx(TableCell, { sx: CELL_SX, colSpan: 2, align: "right", children: _jsxs(ToggleButtonGroup, { size: "small", value: displayType, exclusive: true, onChange: (_, value) => setDisplayType(value), children: [_jsx(ToggleButton, { value: "list", children: _jsxs(Stack, { direction: "row", spacing: 0.5, children: [_jsx(List, {}), _jsx("span", { children: t('page.settings.local.hits.display_type.list') })] }) }), _jsx(ToggleButton, { value: "grid", children: _jsxs(Stack, { direction: "row", spacing: 0.5, children: [_jsx(TableChart, {}), _jsx("span", { children: t('page.settings.local.hits.display_type.grid') })] }) })] }) })] }), _jsx(TableRow, { children: _jsx(TableCell, { colSpan: 3, sx: { paddingTop: '0 !important' }, children: _jsx(Typography, { variant: "caption", color: "text.secondary", children: t('page.settings.local.hits.display_type.description') }) }) }), _jsxs(TableRow, { children: [_jsx(TableCell, { sx: CELL_SX, style: { whiteSpace: 'nowrap' }, children: t('page.settings.local.results.count') }), _jsx(TableCell, { sx: CELL_SX, colSpan: 2, align: "right", children: _jsxs(Select, { size: "small", sx: { minWidth: '75px', textAlign: 'left' }, value: pageCount, onChange: event => setPageCount(typeof event.target.value === 'string' ? parseInt(event.target.value) : event.target.value), children: [_jsx(MenuItem, { value: 5, children: "5" }), _jsx(MenuItem, { value: 10, children: "10" }), _jsx(MenuItem, { value: 25, children: "25" }), _jsx(MenuItem, { value: 50, children: "50" }), _jsx(MenuItem, { value: 75, children: "75" }), _jsx(MenuItem, { value: 100, children: "100" }), _jsx(MenuItem, { value: 150, children: "150" }), _jsx(MenuItem, { value: 250, children: "250" })] }) })] }), _jsx(TableRow, { children: _jsx(TableCell, { colSpan: 3, sx: { paddingTop: '0 !important' }, children: _jsx(Typography, { variant: "caption", color: "text.secondary", children: t('page.settings.local.results.count.description') }) }) }), howlerPluginStore.plugins.map(plugin => pluginStore.executeFunction(`${plugin}.settings`, 'local'))] }));
|
|
26
27
|
};
|
|
27
28
|
export default LocalSection;
|
|
@@ -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, {}) }));
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
{
|
|
2
2
|
"*": "All values",
|
|
3
|
+
"actions.error": "Action \"{{action}}\" had error(s): {{messages}}",
|
|
3
4
|
"actions.running": "Action \"{{action}}\" is executing.",
|
|
4
|
-
"actions.succeeded": "Action \"{{action}}\" completed successfully.",
|
|
5
5
|
"actions.skipped": "Action \"{{action}}\" was skipped: {{messages}}",
|
|
6
|
-
"actions.
|
|
6
|
+
"actions.succeeded": "Action \"{{action}}\" completed successfully.",
|
|
7
7
|
"add": "Add",
|
|
8
8
|
"adminmenu": "Admin menu",
|
|
9
9
|
"adminmenu.config": "Configuration",
|
|
@@ -386,6 +386,8 @@
|
|
|
386
386
|
"page.settings.local.results.count.description": "How many results should we show per page when showing search results?",
|
|
387
387
|
"page.settings.local.search.width": "Maximum Results Width",
|
|
388
388
|
"page.settings.local.search.width.description": "The maximum size (in pixels) the results column in the search page.",
|
|
389
|
+
"page.settings.local.show.hit.summary.graph": "Show the Hit Summary Graph in Hit Search",
|
|
390
|
+
"page.settings.local.show.hit.summary.graph.description": "Shows the Hit Summary Graph in the Hit Search",
|
|
389
391
|
"page.settings.local.title": "UI Preferences",
|
|
390
392
|
"page.settings.profile.table.email": "Email",
|
|
391
393
|
"page.settings.profile.table.groups": "Groups",
|
|
@@ -670,6 +672,10 @@
|
|
|
670
672
|
"route.templates.manager.personal": "Personal",
|
|
671
673
|
"route.templates.manager.readonly": "Built-in",
|
|
672
674
|
"route.templates.manager.search": "Search Templates",
|
|
675
|
+
"route.templates.manager.error.message": "Invalid Detection",
|
|
676
|
+
"route.templates.manager.error.action": "Click to open quick fix options",
|
|
677
|
+
"route.templates.manager.error.modal.title": "Template detection no longer exists",
|
|
678
|
+
"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
679
|
"route.templates.personal": "Personal",
|
|
674
680
|
"route.templates.prompt": "Activate autocomplete using [ctrl + space].",
|
|
675
681
|
"route.templates.readonly.warning": "This is a built-in template, and cannot be edited. To make changes to it, contact",
|
|
@@ -2,10 +2,10 @@
|
|
|
2
2
|
"*": "Toutes les valeurs",
|
|
3
3
|
"Protected B": "Protégé B",
|
|
4
4
|
"Unclassified//Official Use Only": "Non classé//Réservé à des fins officielles",
|
|
5
|
+
"actions.error": "Action \"{{action}}\" a rencontré une ou des erreur(s): {{messages}}",
|
|
5
6
|
"actions.running": "Action \"{{action}}\" s'exécute.",
|
|
6
|
-
"actions.succeeded": "Action \"{{action}}\" achevé avec succès.",
|
|
7
7
|
"actions.skipped": "Action \"{{action}}\" a été ignorée: {{messages}}",
|
|
8
|
-
"actions.
|
|
8
|
+
"actions.succeeded": "Action \"{{action}}\" achevé avec succès.",
|
|
9
9
|
"add": "Ajouter",
|
|
10
10
|
"adminmenu": "Menu d'administration",
|
|
11
11
|
"adminmenu.config": "Configuration",
|
|
@@ -391,6 +391,8 @@
|
|
|
391
391
|
"page.settings.local.results.count.description": "Combien de résultats devons-nous afficher par page lors de l'affichage des résultats de recherche ?",
|
|
392
392
|
"page.settings.local.search.width": "Largeur maximale des résultats",
|
|
393
393
|
"page.settings.local.search.width.description": "Taille maximale (en pixels) de la colonne des résultats dans la page de recherche.",
|
|
394
|
+
"page.settings.local.show.hit.summary.graph": "Afficher le graphique du résumé des résultats dans le volet Résumé des résultats",
|
|
395
|
+
"page.settings.local.show.hit.summary.graph.description": "Affiche le graphique du résumé des résultats dans le volet Résumé des résultats",
|
|
394
396
|
"page.settings.local.title": "Préférences de l'interface utilisateur",
|
|
395
397
|
"page.settings.profile.table.email": "Courriel",
|
|
396
398
|
"page.settings.profile.table.groups": "Groupes",
|
|
@@ -674,6 +676,10 @@
|
|
|
674
676
|
"route.templates.manager.personal": "Personnel",
|
|
675
677
|
"route.templates.manager.readonly": "Intégré",
|
|
676
678
|
"route.templates.manager.search": "Rechercher les modèles",
|
|
679
|
+
"route.templates.manager.error.message": "Détection non valide",
|
|
680
|
+
"route.templates.manager.error.action": "Cliquez ici pour afficher les options de correction rapide",
|
|
681
|
+
"route.templates.manager.error.modal.title": "La détection du modèle n'existe plus",
|
|
682
|
+
"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
683
|
"route.templates.personal": "Personnel",
|
|
678
684
|
"route.templates.prompt": "Activer l'autocomplétion en utilisant [ctrl + espace].",
|
|
679
685
|
"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
package/utils/constants.d.ts
CHANGED
|
@@ -49,6 +49,7 @@ export declare enum StorageKey {
|
|
|
49
49
|
COMPACT_JSON = "compact_json_view",
|
|
50
50
|
FLATTEN_JSON = "flatten_json_view",
|
|
51
51
|
FORCE_DRAWER = "force_drawer",
|
|
52
|
+
SHOW_HIT_SUMMARY_GRAPH = "show_hit_summary_graph",
|
|
52
53
|
LAST_VIEW = "last_view",
|
|
53
54
|
ONLY_RULES = "only_rules",
|
|
54
55
|
PAGE_COUNT = "page_count",
|
package/utils/constants.js
CHANGED
|
@@ -54,6 +54,7 @@ export var StorageKey;
|
|
|
54
54
|
StorageKey["COMPACT_JSON"] = "compact_json_view";
|
|
55
55
|
StorageKey["FLATTEN_JSON"] = "flatten_json_view";
|
|
56
56
|
StorageKey["FORCE_DRAWER"] = "force_drawer";
|
|
57
|
+
StorageKey["SHOW_HIT_SUMMARY_GRAPH"] = "show_hit_summary_graph";
|
|
57
58
|
StorageKey["LAST_VIEW"] = "last_view";
|
|
58
59
|
StorageKey["ONLY_RULES"] = "only_rules";
|
|
59
60
|
StorageKey["PAGE_COUNT"] = "page_count";
|