@cccsaurora/howler-ui 2.17.0-dev.516 → 2.17.0-dev.518
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/hit/HitBanner.js +1 -1
- package/components/routes/cases/detail/CaseTask.d.ts +4 -3
- package/components/routes/cases/detail/CaseTask.js +34 -30
- package/components/routes/cases/detail/RelatedCasePanel.js +1 -1
- package/components/routes/cases/detail/TaskPanel.js +41 -12
- package/locales/en/translation.json +2 -2
- package/locales/fr/translation.json +1 -0
- package/package.json +1 -1
|
@@ -109,6 +109,6 @@ const HitBanner = ({ hit, layout = HitLayout.NORMAL, showAssigned = true }) => {
|
|
|
109
109
|
width: theme.spacing(3)
|
|
110
110
|
}
|
|
111
111
|
}
|
|
112
|
-
], children: [_jsx(HitTimestamp, { hit: hit, layout: layout }), showAssigned && _jsx(Assigned, { hit: hit, layout: layout }), _jsxs(Stack, { direction: "row", spacing: layout !== HitLayout.COMFY ? 0.5 : 1, children: [_jsx(EscalationChip, { hit: hit, layout: layout }), ['in-progress', 'on-hold'].includes(hit.howler.status) && (_jsx(Chip, { sx: { width: 'fit-content', display: 'inline-flex' }, label: hit.howler.status, size: layout !== HitLayout.COMFY ? 'small' : 'medium', color: "primary" })), hit.howler.related && (_jsx(Chip, { size: layout !== HitLayout.COMFY ? 'small' : 'medium', label: t('hit.header.related', { count: hit.howler.related.length }) }))
|
|
112
|
+
], children: [_jsx(HitTimestamp, { hit: hit, layout: layout }), showAssigned && _jsx(Assigned, { hit: hit, layout: layout }), _jsxs(Stack, { direction: "row", spacing: layout !== HitLayout.COMFY ? 0.5 : 1, children: [_jsx(EscalationChip, { hit: hit, layout: layout }), ['in-progress', 'on-hold'].includes(hit.howler.status) && (_jsx(Chip, { sx: { width: 'fit-content', display: 'inline-flex' }, label: hit.howler.status, size: layout !== HitLayout.COMFY ? 'small' : 'medium', color: "primary" }))] }), hit.howler.related && (_jsx(Chip, { size: layout !== HitLayout.COMFY ? 'small' : 'medium', label: t('hit.header.related', { count: hit.howler.related.length }) })), howlerPluginStore.plugins.flatMap(plugin => pluginStore.executeFunction(`${plugin}.status`, { hit, layout }))] })] }));
|
|
113
113
|
};
|
|
114
114
|
export default HitBanner;
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import type { Task } from '@cccsaurora/howler-ui/models/entities/generated/Task';
|
|
2
2
|
import { type FC } from 'react';
|
|
3
3
|
declare const CaseTask: FC<{
|
|
4
|
-
task
|
|
4
|
+
task?: Task;
|
|
5
5
|
paths: string[];
|
|
6
|
-
onDelete
|
|
7
|
-
onEdit: (task
|
|
6
|
+
onDelete?: () => Promise<void>;
|
|
7
|
+
onEdit: (task?: Partial<Task>) => Promise<void>;
|
|
8
8
|
loading?: boolean;
|
|
9
|
+
newTask?: boolean;
|
|
9
10
|
}>;
|
|
10
11
|
export default CaseTask;
|
|
@@ -2,45 +2,49 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
|
2
2
|
import { Check, Close, Delete, Edit } from '@mui/icons-material';
|
|
3
3
|
import { Autocomplete, Card, Checkbox, Chip, IconButton, LinearProgress, Stack, TextField, Tooltip, Typography } from '@mui/material';
|
|
4
4
|
import UserList from '@cccsaurora/howler-ui/components/elements/UserList';
|
|
5
|
-
import { useState } from 'react';
|
|
5
|
+
import { useEffect, useState } from 'react';
|
|
6
6
|
import { useTranslation } from 'react-i18next';
|
|
7
7
|
import { Link } from 'react-router-dom';
|
|
8
|
-
const CaseTask = ({ task, onEdit, onDelete, paths }) => {
|
|
8
|
+
const CaseTask = ({ task, onEdit, onDelete, paths, newTask = false }) => {
|
|
9
9
|
const { t } = useTranslation();
|
|
10
|
-
const [editing, setEditing] = useState(false);
|
|
11
10
|
const [loading, setLoading] = useState(false);
|
|
12
|
-
const [
|
|
13
|
-
const [
|
|
14
|
-
const
|
|
15
|
-
const
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
assignment
|
|
19
|
-
});
|
|
20
|
-
setLoading(false);
|
|
21
|
-
};
|
|
11
|
+
const [editing, setEditing] = useState(newTask);
|
|
12
|
+
const [summary, setSummary] = useState(task?.summary || '');
|
|
13
|
+
const [path, setPath] = useState(task?.path ?? null);
|
|
14
|
+
const [assignment, setAssignment] = useState(task?.assignment);
|
|
15
|
+
const [complete, setComplete] = useState(task?.complete ?? false);
|
|
16
|
+
const dirty = summary !== task?.summary || path !== task?.path || complete !== task?.complete || assignment !== task?.assignment;
|
|
22
17
|
const onSubmit = async () => {
|
|
23
|
-
if (dirty) {
|
|
18
|
+
if (dirty && editing) {
|
|
24
19
|
setLoading(true);
|
|
25
|
-
await onEdit({ summary, path: !path ? null : path });
|
|
20
|
+
await onEdit({ summary, path: !path ? null : path, assignment, complete });
|
|
26
21
|
setLoading(false);
|
|
27
22
|
}
|
|
28
23
|
};
|
|
29
|
-
|
|
30
|
-
|
|
24
|
+
useEffect(() => {
|
|
25
|
+
if (!editing && task?.assignment !== assignment) {
|
|
26
|
+
setLoading(true);
|
|
27
|
+
onEdit({ assignment }).finally(() => setLoading(false));
|
|
28
|
+
}
|
|
29
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
30
|
+
}, [assignment]);
|
|
31
|
+
useEffect(() => {
|
|
32
|
+
if (!editing && task?.complete !== complete) {
|
|
33
|
+
setLoading(true);
|
|
34
|
+
onEdit({ complete }).finally(() => setLoading(false));
|
|
35
|
+
}
|
|
36
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
37
|
+
}, [complete]);
|
|
38
|
+
return (_jsxs(Card, { sx: { pl: 0.5, pr: 1, py: 0.5, position: 'relative' }, children: [_jsxs(Stack, { direction: "row", alignItems: "center", spacing: 1, children: [_jsx(Checkbox, { disabled: loading, color: "success", checked: complete, size: "small", onChange: (_ev, _complete) => setComplete(_complete) }), editing ? (_jsx(TextField, { disabled: loading, value: summary, onChange: e => setSummary(e.target.value), size: "small", fullWidth: true, sx: { minWidth: '40%' } })) : (_jsx(Typography, { sx: [complete && { textDecoration: 'line-through' }], children: task?.summary || summary })), !editing && path && _jsx(Chip, { clickable: true, component: Link, to: path, label: path }), editing && (_jsx(Autocomplete, { disabled: loading, value: path, options: paths, onChange: (_ev, value) => setPath(value), fullWidth: true, renderInput: params => _jsx(TextField, { ...params, size: "small" }) })), _jsx(UserList, { disabled: loading, userIds: [assignment], onChange: ([_assigment]) => setAssignment(_assigment), i18nLabel: "route.cases.task.set.assignment", avatarHeight: 24 }), _jsx("div", { style: { flex: 1 } }), editing && (_jsx(Tooltip, { title: t('route.cases.task.delete'), children: _jsx(IconButton, { size: "small", color: "error", onClick: () => {
|
|
31
39
|
setLoading(true);
|
|
32
|
-
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
setEditing(
|
|
40
|
-
|
|
41
|
-
}
|
|
42
|
-
setEditing(false);
|
|
43
|
-
onSubmit();
|
|
44
|
-
}, disabled: (!dirty && editing) || loading, children: editing ? _jsx(Check, { fontSize: "small" }) : _jsx(Edit, { fontSize: "small" }) }) }), editing && (_jsx(Tooltip, { title: t('route.cases.task.edit.cancel'), children: _jsx(IconButton, { size: "small", onClick: () => setEditing(false), disabled: loading, children: _jsx(Close, { fontSize: "small" }) }) }))] }), loading && _jsx(LinearProgress, { sx: { left: 0, bottom: 0, right: 0, position: 'absolute' } })] }, task.id));
|
|
40
|
+
onDelete().then(() => setLoading(false));
|
|
41
|
+
}, disabled: loading, children: _jsx(Delete, { fontSize: "small" }) }) })), _jsx(Tooltip, { title: t(editing ? 'route.cases.task.edit.save' : 'route.cases.task.edit'), children: _jsx("span", { children: _jsx(IconButton, { size: "small", color: editing ? 'success' : 'default', onClick: async () => {
|
|
42
|
+
if (!editing) {
|
|
43
|
+
setEditing(true);
|
|
44
|
+
return;
|
|
45
|
+
}
|
|
46
|
+
await onSubmit();
|
|
47
|
+
setEditing(false);
|
|
48
|
+
}, disabled: (!dirty && editing) || loading || !summary, children: editing ? _jsx(Check, { fontSize: "small" }) : _jsx(Edit, { fontSize: "small" }) }) }) }), editing && (_jsx(Tooltip, { title: t('route.cases.task.edit.cancel'), children: _jsx(IconButton, { size: "small", onClick: () => setEditing(false), disabled: loading, children: _jsx(Close, { fontSize: "small" }) }) }))] }), loading && _jsx(LinearProgress, { sx: { left: 0, bottom: 0, right: 0, position: 'absolute' } })] }));
|
|
45
49
|
};
|
|
46
50
|
export default CaseTask;
|
|
@@ -13,7 +13,7 @@ const RelatedCasePanel = ({ case: _case }) => {
|
|
|
13
13
|
if (!_case) {
|
|
14
14
|
return _jsx(Skeleton, { height: 240 });
|
|
15
15
|
}
|
|
16
|
-
return (_jsxs(Stack, { spacing: 1, children: [_jsxs(Stack, { direction: "row", children: [_jsx(Typography, { flex: 1, variant: "h4", children: t('page.cases.dashboard.
|
|
16
|
+
return (_jsxs(Stack, { spacing: 1, children: [_jsxs(Stack, { direction: "row", children: [_jsx(Typography, { flex: 1, variant: "h4", children: t('page.cases.dashboard.cases') }), _jsx(Pagination, { count: casePages.length, page: casePage, onChange: (_, page) => setCasePage(page) })] }), _jsx(Divider, {}), casePages[casePage - 1]?.map(item => (_jsxs(Box, { position: "relative", children: [_jsx(CaseCard, { caseId: item.id }), _jsx(Box, { component: Link, to: item.path, sx: {
|
|
17
17
|
position: 'absolute',
|
|
18
18
|
top: 0,
|
|
19
19
|
left: 0,
|
|
@@ -1,23 +1,52 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { Add } from '@mui/icons-material';
|
|
2
3
|
import { Divider, Skeleton, Stack, Typography } from '@mui/material';
|
|
3
|
-
import {} from 'react';
|
|
4
|
+
import { useState } from 'react';
|
|
4
5
|
import { useTranslation } from 'react-i18next';
|
|
5
6
|
import CaseTask from './CaseTask';
|
|
6
7
|
const TaskPanel = ({ case: _case, updateCase }) => {
|
|
7
8
|
const { t } = useTranslation();
|
|
9
|
+
const [addingTask, setAddingTask] = useState(false);
|
|
10
|
+
const onEdit = (task) => async (newTask) => {
|
|
11
|
+
if (task) {
|
|
12
|
+
await updateCase({
|
|
13
|
+
tasks: _case.tasks.map(_task => {
|
|
14
|
+
if (_task.id !== task.id) {
|
|
15
|
+
return _task;
|
|
16
|
+
}
|
|
17
|
+
return {
|
|
18
|
+
..._task,
|
|
19
|
+
...newTask
|
|
20
|
+
};
|
|
21
|
+
})
|
|
22
|
+
});
|
|
23
|
+
}
|
|
24
|
+
else {
|
|
25
|
+
await updateCase({
|
|
26
|
+
tasks: [..._case.tasks, newTask]
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
};
|
|
8
30
|
if (!_case) {
|
|
9
31
|
return _jsx(Skeleton, { height: 240 });
|
|
10
32
|
}
|
|
11
|
-
return (_jsxs(Stack, { spacing: 1, children: [_jsx(Typography, { flex: 1, variant: "h4", children: t('page.cases.dashboard.tasks') }), _jsx(Divider, {}), _case.tasks.map(task => (_jsx(CaseTask, { task: task, paths: _case.items.map(item => item.path), onEdit:
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
33
|
+
return (_jsxs(Stack, { spacing: 1, children: [_jsx(Typography, { flex: 1, variant: "h4", children: t('page.cases.dashboard.tasks') }), _jsx(Divider, {}), _case.tasks.map(task => (_jsx(CaseTask, { task: task, paths: _case.items.map(item => item.path), onEdit: onEdit(task), onDelete: () => updateCase({ tasks: _case.tasks.filter(_task => _task.id !== task.id) }) }, task.id))), addingTask && (_jsx(CaseTask, { newTask: true, paths: _case.items.map(item => item.path), onEdit: async (task) => {
|
|
34
|
+
await onEdit()(task);
|
|
35
|
+
setAddingTask(false);
|
|
36
|
+
}, onDelete: async () => setAddingTask(false) })), _jsxs(Stack, { onClick: () => setAddingTask(true), direction: "row", spacing: 2, sx: theme => ({
|
|
37
|
+
borderStyle: 'dashed',
|
|
38
|
+
borderColor: theme.palette.text.secondary,
|
|
39
|
+
borderWidth: '0.15rem',
|
|
40
|
+
borderRadius: '0.15rem',
|
|
41
|
+
opacity: 0.3,
|
|
42
|
+
justifyContent: 'center',
|
|
43
|
+
alignItems: 'center',
|
|
44
|
+
padding: 1,
|
|
45
|
+
transition: theme.transitions.create('opacity'),
|
|
46
|
+
'&:hover': {
|
|
47
|
+
opacity: 1,
|
|
48
|
+
cursor: 'pointer'
|
|
49
|
+
}
|
|
50
|
+
}), children: [_jsx(Add, {}), _jsx(Typography, { children: t('page.cases.dashboard.tasks.add') })] })] }));
|
|
22
51
|
};
|
|
23
52
|
export default TaskPanel;
|
|
@@ -114,7 +114,6 @@
|
|
|
114
114
|
"help.hit.banner.description": "See the below hit banner example for the hit keys necessary to properly populate it. If you have any additional questions, ask in the HOWLER support channel.",
|
|
115
115
|
"help.hit.banner.json": "Here is the hit data used to populate this banner:",
|
|
116
116
|
"help.hit.banner.title": "Populating the Hit Banner",
|
|
117
|
-
"help.hit.bundle.title": "Hit Bundles",
|
|
118
117
|
"help.hit.labels.title": "Hit Labels",
|
|
119
118
|
"help.hit.links.title": "Hit Links",
|
|
120
119
|
"help.hit.schema.description.missing": "No description provided.",
|
|
@@ -168,6 +167,7 @@
|
|
|
168
167
|
"hit.header.escalation": "Escalation Level: ",
|
|
169
168
|
"hit.header.indicators": "Indicators",
|
|
170
169
|
"hit.header.rationale": "Rationale",
|
|
170
|
+
"hit.header.related": "{{count}} related records",
|
|
171
171
|
"hit.header.scrutiny": "Scrutiny: ",
|
|
172
172
|
"hit.header.status": "Status: ",
|
|
173
173
|
"hit.header.summary": "Summary",
|
|
@@ -336,6 +336,7 @@
|
|
|
336
336
|
"page.cases.created": "Created",
|
|
337
337
|
"page.cases.dashboard": "Dashboard",
|
|
338
338
|
"page.cases.dashboard.alerts": "Alerts",
|
|
339
|
+
"page.cases.dashboard.cases": "Related Cases",
|
|
339
340
|
"page.cases.dashboard.duration": "Duration",
|
|
340
341
|
"page.cases.dashboard.indicators": "Indicators",
|
|
341
342
|
"page.cases.dashboard.target": "Targets",
|
|
@@ -618,7 +619,6 @@
|
|
|
618
619
|
"route.help.views": "Views",
|
|
619
620
|
"route.history": "History mode: See all previous queries",
|
|
620
621
|
"route.hits": "Alerts",
|
|
621
|
-
"route.hits.bundle": "View Bundle",
|
|
622
622
|
"route.hits.view": "View Hit",
|
|
623
623
|
"route.home": "User Dashboard",
|
|
624
624
|
"route.home.add": "Add New Panel",
|
|
@@ -340,6 +340,7 @@
|
|
|
340
340
|
"page.cases.created": "Créé",
|
|
341
341
|
"page.cases.dashboard": "Tableau de bord",
|
|
342
342
|
"page.cases.dashboard.alerts": "Alertes",
|
|
343
|
+
"page.cases.dashboard.cases": "Cas connexes",
|
|
343
344
|
"page.cases.dashboard.duration": "Durée",
|
|
344
345
|
"page.cases.dashboard.indicators": "Indicateurs",
|
|
345
346
|
"page.cases.dashboard.target": "Cibles",
|