@cccsaurora/howler-ui 2.13.1 → 2.13.2
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/app/providers/HitSearchProvider.js +2 -3
- package/components/app/providers/ViewProvider.d.ts +4 -1
- package/components/app/providers/ViewProvider.js +8 -6
- package/components/app/providers/ViewProvider.test.js +8 -2
- package/components/elements/hit/HitBanner.js +1 -1
- package/components/elements/hit/aggregate/HitGraph.js +3 -2
- package/components/routes/hits/search/shared/HitSort.js +1 -1
- package/components/routes/hits/search/shared/SearchSpan.js +1 -1
- package/components/routes/hits/view/HitViewer.js +1 -1
- package/components/routes/home/AddNewCard.js +3 -2
- package/components/routes/home/index.js +36 -35
- package/package.json +1 -1
|
@@ -78,7 +78,7 @@ const HitSearchProvider = ({ children }) => {
|
|
|
78
78
|
fullQuery = `(howler.bundles:${bundle}) AND (${fullQuery})`;
|
|
79
79
|
}
|
|
80
80
|
else if (viewId) {
|
|
81
|
-
fullQuery = `(${(await getCurrentView())?.query || 'howler.id:*'}) AND (${fullQuery})`;
|
|
81
|
+
fullQuery = `(${(await getCurrentView({ viewId }))?.query || 'howler.id:*'}) AND (${fullQuery})`;
|
|
82
82
|
}
|
|
83
83
|
const _response = await dispatchApi(api.search.hit.post({
|
|
84
84
|
offset: appendResults ? response.rows : offset,
|
|
@@ -132,7 +132,6 @@ const HitSearchProvider = ({ children }) => {
|
|
|
132
132
|
trackTotalHits,
|
|
133
133
|
loadHits,
|
|
134
134
|
getCurrentView,
|
|
135
|
-
defaultView,
|
|
136
135
|
setOffset
|
|
137
136
|
]);
|
|
138
137
|
// We only run this when ancillary properties (i.e. filters, sorting) change
|
|
@@ -147,7 +146,7 @@ const HitSearchProvider = ({ children }) => {
|
|
|
147
146
|
setResponse(null);
|
|
148
147
|
}
|
|
149
148
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
150
|
-
}, [filter, offset, pageCount, sort, span, bundleId, location.pathname, startDate, endDate]);
|
|
149
|
+
}, [filter, offset, pageCount, sort, span, bundleId, location.pathname, startDate, endDate, viewId]);
|
|
151
150
|
return (_jsx(HitSearchContext.Provider, { value: {
|
|
152
151
|
layout,
|
|
153
152
|
displayType,
|
|
@@ -12,7 +12,10 @@ export interface ViewContextType {
|
|
|
12
12
|
addView: (v: View) => Promise<View>;
|
|
13
13
|
editView: (id: string, newView: Partial<Omit<View, 'view_id' | 'owner'>>) => Promise<View>;
|
|
14
14
|
removeView: (id: string) => Promise<void>;
|
|
15
|
-
getCurrentView: (
|
|
15
|
+
getCurrentView: (config?: {
|
|
16
|
+
viewId?: string;
|
|
17
|
+
lazy?: boolean;
|
|
18
|
+
}) => Promise<View>;
|
|
16
19
|
}
|
|
17
20
|
export declare const ViewContext: import("use-context-selector").Context<ViewContextType>;
|
|
18
21
|
declare const ViewProvider: FC<PropsWithChildren>;
|
|
@@ -59,15 +59,17 @@ const ViewProvider = ({ children }) => {
|
|
|
59
59
|
}
|
|
60
60
|
})();
|
|
61
61
|
}, [defaultView, fetchViews, setDefaultView, views]);
|
|
62
|
-
const getCurrentView = useCallback(async (lazy = false) => {
|
|
63
|
-
|
|
64
|
-
|
|
62
|
+
const getCurrentView = useCallback(async ({ viewId, lazy = false } = {}) => {
|
|
63
|
+
if (!viewId) {
|
|
64
|
+
viewId = location.pathname.startsWith('/views') ? routeParams.id : defaultView;
|
|
65
|
+
}
|
|
66
|
+
if (!viewId) {
|
|
65
67
|
return null;
|
|
66
68
|
}
|
|
67
|
-
if (!has(views,
|
|
68
|
-
return (await fetchViews([
|
|
69
|
+
if (!has(views, viewId) && !lazy) {
|
|
70
|
+
return (await fetchViews([viewId]))[0];
|
|
69
71
|
}
|
|
70
|
-
return views[
|
|
72
|
+
return views[viewId];
|
|
71
73
|
}, [defaultView, fetchViews, location.pathname, routeParams.id, views]);
|
|
72
74
|
const editView = useCallback(async (id, partialView) => {
|
|
73
75
|
const result = await dispatchApi(api.view.put(id, partialView));
|
|
@@ -117,17 +117,23 @@ describe('ViewContext', () => {
|
|
|
117
117
|
});
|
|
118
118
|
describe('getCurrentView', () => {
|
|
119
119
|
let hook;
|
|
120
|
-
|
|
120
|
+
beforeEach(async () => {
|
|
121
121
|
hook = await act(async () => {
|
|
122
122
|
return renderHook(() => useContextSelector(ViewContext, ctx => ctx.getCurrentView), { wrapper: Wrapper });
|
|
123
123
|
});
|
|
124
124
|
});
|
|
125
125
|
it('should allow the user to fetch their current view based on the location', async () => {
|
|
126
126
|
// lazy load should return nothing
|
|
127
|
-
await expect(hook.result.current(true)).resolves.toBeFalsy();
|
|
127
|
+
await expect(hook.result.current({ lazy: true })).resolves.toBeFalsy();
|
|
128
128
|
const result = await act(async () => hook.result.current());
|
|
129
129
|
expect(result).toEqual(MOCK_RESPONSES['/api/v1/search/view'].items[0]);
|
|
130
130
|
});
|
|
131
|
+
it('should allow the user to fetch their current view based on the view ID', async () => {
|
|
132
|
+
// lazy load should return nothing
|
|
133
|
+
await expect(hook.result.current({ lazy: true })).resolves.toBeFalsy();
|
|
134
|
+
const result = await act(async () => hook.result.current({ viewId: 'searched_view_id' }));
|
|
135
|
+
expect(result).toEqual(MOCK_RESPONSES['/api/v1/search/view'].items[0]);
|
|
136
|
+
});
|
|
131
137
|
});
|
|
132
138
|
describe('editView', () => {
|
|
133
139
|
let hook;
|
|
@@ -29,7 +29,7 @@ const HitBanner = ({ hit, layout = HitLayout.NORMAL, showAssigned = true }) => {
|
|
|
29
29
|
if (!hit?.howler.analytic) {
|
|
30
30
|
return;
|
|
31
31
|
}
|
|
32
|
-
getMatchingAnalytic(hit).then(analytic => setAnalyticId(analytic
|
|
32
|
+
getMatchingAnalytic(hit).then(analytic => setAnalyticId(analytic?.analytic_id));
|
|
33
33
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
34
34
|
}, [hit?.howler.analytic]);
|
|
35
35
|
const providerColor = useMemo(() => PROVIDER_COLORS[hit.event?.provider ?? 'unknown'] ?? stringToColor(hit.event.provider), [hit.event?.provider]);
|
|
@@ -42,6 +42,7 @@ const HitGraph = ({ query }) => {
|
|
|
42
42
|
const removeHitFromSelection = useContextSelector(HitContext, ctx => ctx.removeHitFromSelection);
|
|
43
43
|
const viewId = useContextSelector(HitSearchContext, ctx => ctx.viewId);
|
|
44
44
|
const error = useContextSelector(HitSearchContext, ctx => ctx.error);
|
|
45
|
+
const response = useContextSelector(HitSearchContext, ctx => ctx.response);
|
|
45
46
|
const chartRef = useRef();
|
|
46
47
|
const [loading, setLoading] = useState(false);
|
|
47
48
|
const [filterField, setFilterField] = useState(FILTER_FIELDS[0]);
|
|
@@ -113,12 +114,12 @@ const HitGraph = ({ query }) => {
|
|
|
113
114
|
}
|
|
114
115
|
}, [dispatchApi, endDate, escalationFilter, filterField, override, query, span, startDate]);
|
|
115
116
|
useEffect(() => {
|
|
116
|
-
if ((!query && !viewId) || error) {
|
|
117
|
+
if ((!query && !viewId) || error || !response) {
|
|
117
118
|
return;
|
|
118
119
|
}
|
|
119
120
|
performQuery();
|
|
120
121
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
121
|
-
}, [query, viewId, error, span]);
|
|
122
|
+
}, [query, viewId, error, span, response]);
|
|
122
123
|
const options = useMemo(() => {
|
|
123
124
|
const parentOptions = scatter('hit.summary.title', 'hit.summary.subtitle');
|
|
124
125
|
return {
|
|
@@ -53,7 +53,7 @@ const HitSort = ({ size = 'small' }) => {
|
|
|
53
53
|
return;
|
|
54
54
|
}
|
|
55
55
|
(async () => {
|
|
56
|
-
const selectedView = await getCurrentView(true);
|
|
56
|
+
const selectedView = await getCurrentView({ lazy: true });
|
|
57
57
|
if (selectedView?.sort && !location.search.includes('sort')) {
|
|
58
58
|
setSavedSort(selectedView.sort);
|
|
59
59
|
}
|
|
@@ -104,7 +104,7 @@ const HitViewer = () => {
|
|
|
104
104
|
hit_worklog: () => _jsx(HitWorklog, { hit: hit, users: users }),
|
|
105
105
|
hit_related: () => _jsx(HitRelated, { hit: hit }),
|
|
106
106
|
...Object.fromEntries(hit?.howler.dossier?.map((lead, index) => ['lead:' + index, () => _jsx(LeadRenderer, { lead: lead })]) ?? []),
|
|
107
|
-
...Object.fromEntries(dossiers.flatMap((_dossier, dossierIndex) => _dossier.leads
|
|
107
|
+
...Object.fromEntries(dossiers.flatMap((_dossier, dossierIndex) => (_dossier.leads ?? []).map((_lead, leadIndex) => [
|
|
108
108
|
`external-lead:${dossierIndex}:${leadIndex}`,
|
|
109
109
|
() => _jsx(LeadRenderer, { lead: _lead, hit: hit })
|
|
110
110
|
])))
|
|
@@ -15,7 +15,7 @@ const TYPES = {
|
|
|
15
15
|
const VISUALIZATIONS = ['assessment', 'created', 'escalation', 'status', 'detection'];
|
|
16
16
|
const AddNewCard = ({ dashboard, addCard }) => {
|
|
17
17
|
const { t } = useTranslation();
|
|
18
|
-
const views = useContextSelector(ViewContext, ctx => ctx.views ??
|
|
18
|
+
const views = useContextSelector(ViewContext, ctx => ctx.views ?? {});
|
|
19
19
|
const fetchViews = useContextSelector(ViewContext, ctx => ctx.fetchViews);
|
|
20
20
|
const [selectedType, setSelectedType] = useState('');
|
|
21
21
|
const [analytics, setAnalytics] = useState([]);
|
|
@@ -58,7 +58,8 @@ const AddNewCard = ({ dashboard, addCard }) => {
|
|
|
58
58
|
}, [fetchViews]);
|
|
59
59
|
return (_jsx(Grid, { item: true, xs: 12, md: 6, children: _jsxs(Card, { variant: "outlined", sx: { height: '100%' }, children: [_jsx(CardHeader, { title: t('route.home.add'), subheader: _jsx(Typography, { variant: "body2", color: "text.secondary", children: t('route.home.add.description') }) }), _jsx(CardContent, { children: _jsxs(Stack, { spacing: 1, children: [_jsxs(FormControl, { sx: theme => ({ mt: `${theme.spacing(2)} !important` }), children: [_jsx(InputLabel, { children: t('route.home.add.type') }), _jsx(Select, { value: selectedType, onChange: event => setSelectedType(event.target.value), label: t('route.home.add.type'), children: Object.keys(TYPES).map(type => (_jsx(MenuItem, { value: type, children: _jsxs(Stack, { children: [_jsx(Typography, { variant: "body1", children: t(`route.home.add.type.${type}`) }), _jsx(Typography, { variant: "caption", color: "text.secondary", children: t(`route.home.add.type.${type}.description`) })] }) }, type))) })] }), selectedType && _jsx(Divider, { flexItem: true }), selectedType === 'analytic' && (_jsxs(_Fragment, { children: [_jsx(Typography, { variant: "body1", children: t('route.home.add.analytic.title') }), _jsx(Typography, { variant: "caption", color: "text.secondary", children: t('route.home.add.analytic.description') }), _jsx(Autocomplete, { sx: { pt: 1 }, onChange: (__, opt) => setConfig('analyticId', opt.analytic_id), options: analytics, filterOptions: (options, state) => options.filter(opt => opt.name.toLowerCase().includes(state.inputValue.toLowerCase()) ||
|
|
60
60
|
opt.description?.split('\n')[0]?.toLowerCase().includes(state.inputValue.toLowerCase())), renderOption: (props, option) => (_createElement("li", { ...props, key: option.analytic_id },
|
|
61
|
-
_jsxs(Stack, { children: [_jsx(Typography, { variant: "body1", children: option.name }), _jsx(Typography, { variant: "caption", color: "text.secondary", children: option.description?.split('\n')[0] })] }))), getOptionLabel: option => option.name, renderInput: params => _jsx(TextField, { ...params, label: t('route.home.add.analytic') }) }), _jsxs(FormControl, { sx: theme => ({ mt: `${theme.spacing(2)} !important` }), children: [_jsx(InputLabel, { children: t('route.home.add.visualization') }), _jsx(Select, { value: config.type ?? '', onChange: event => setConfig('type', event.target.value), label: t('route.home.add.visualization'), children: VISUALIZATIONS.map(viz => (_jsx(MenuItem, { value: viz, children: _jsxs(Stack, { children: [_jsx(Typography, { variant: "body1", children: t(`route.home.add.visualization.${viz}`) }), _jsx(Typography, { variant: "caption", color: "text.secondary", children: t(`route.home.add.visualization.${viz}.description`) })] }) }, viz))) })] })] })), selectedType === 'view' && (_jsxs(_Fragment, { children: [_jsx(Autocomplete, { sx: { pt: 1 }, onChange: (__, opt) => setConfig('viewId', opt.view_id), onOpen: onViewOpen, onClose: () => setViewOpen(false), open: viewOpen, loading: viewLoading, options: Object.values(views), filterOptions: (options, state) => options.filter(opt =>
|
|
61
|
+
_jsxs(Stack, { children: [_jsx(Typography, { variant: "body1", children: option.name }), _jsx(Typography, { variant: "caption", color: "text.secondary", children: option.description?.split('\n')[0] })] }))), getOptionLabel: option => option.name, renderInput: params => _jsx(TextField, { ...params, label: t('route.home.add.analytic') }) }), _jsxs(FormControl, { sx: theme => ({ mt: `${theme.spacing(2)} !important` }), children: [_jsx(InputLabel, { children: t('route.home.add.visualization') }), _jsx(Select, { value: config.type ?? '', onChange: event => setConfig('type', event.target.value), label: t('route.home.add.visualization'), children: VISUALIZATIONS.map(viz => (_jsx(MenuItem, { value: viz, children: _jsxs(Stack, { children: [_jsx(Typography, { variant: "body1", children: t(`route.home.add.visualization.${viz}`) }), _jsx(Typography, { variant: "caption", color: "text.secondary", children: t(`route.home.add.visualization.${viz}.description`) })] }) }, viz))) })] })] })), selectedType === 'view' && (_jsxs(_Fragment, { children: [_jsx(Autocomplete, { sx: { pt: 1 }, onChange: (__, opt) => setConfig('viewId', opt.view_id), onOpen: onViewOpen, onClose: () => setViewOpen(false), open: viewOpen, loading: viewLoading, options: Object.values(views), filterOptions: (options, state) => options.filter(opt => !!opt &&
|
|
62
|
+
!dashboard?.find(entry => entry.type === 'view' && JSON.parse(entry.config).viewId === opt.view_id) &&
|
|
62
63
|
(opt.title.toLowerCase().includes(state.inputValue.toLowerCase()) ||
|
|
63
64
|
opt.query.toLowerCase().includes(state.inputValue.toLowerCase()))), renderOption: (props, option) => (_createElement("li", { ...props, key: option.view_id },
|
|
64
65
|
_jsxs(Stack, { children: [_jsx(Typography, { variant: "body1", children: t(option.title) }), _jsx(Typography, { variant: "caption", color: "text.secondary", children: option.query })] }))), getOptionLabel: option => t(option.title), renderInput: params => _jsx(TextField, { ...params, label: t('route.home.add.view') }) }), _jsx(Typography, { variant: "body1", sx: { pt: 1 }, children: t('route.home.add.limit') }), _jsx(Typography, { variant: "caption", color: "text.secondary", children: t('route.home.add.limit.description') }), _jsx(Box, { sx: { px: 0.5 }, children: _jsx(Slider, { value: config.limit ?? 3, valueLabelDisplay: "auto", onChange: (_, value) => setConfig('limit', value), min: 1, max: 10, step: 1, marks: true }) })] })), _jsx(Stack, { direction: "row", justifyContent: "end", children: _jsx(CustomButton, { variant: "outlined", size: "small", color: "primary", startIcon: _jsx(Check, {}), disabled: !selectedType || TYPES[selectedType]?.filter(field => !config[field])?.length > 0, onClick: _addCard, children: t('create') }) })] }) })] }) }));
|
|
@@ -16,6 +16,7 @@ import { useCallback, useEffect, useMemo, useState } from 'react';
|
|
|
16
16
|
import { useTranslation } from 'react-i18next';
|
|
17
17
|
import { Link } from 'react-router-dom';
|
|
18
18
|
import { StorageKey } from '@cccsaurora/howler-ui/utils/constants';
|
|
19
|
+
import ErrorBoundary from '../ErrorBoundary';
|
|
19
20
|
import AddNewCard from './AddNewCard';
|
|
20
21
|
import AnalyticCard, {} from './AnalyticCard';
|
|
21
22
|
import EntryWrapper from './EntryWrapper';
|
|
@@ -81,41 +82,41 @@ const Home = () => {
|
|
|
81
82
|
})
|
|
82
83
|
.then(result => setUpdatedHitTotal(result.total));
|
|
83
84
|
}, [updateQuery]);
|
|
84
|
-
return (_jsx(PageCenter, { maxWidth: "1800px", textAlign: "left", height: "100%", children: _jsxs(Stack, { direction: "column", spacing: 1, sx: { height: '100%' }, children: [_jsxs(Stack, { direction: "row", justifyContent: "end", spacing: 1, children: [isEditing && (_jsx(CustomButton, { variant: "outlined", size: "small", color: "error", startIcon: _jsx(Cancel, {}), onClick: discardChanges, children: t('cancel') })), _jsx(CustomButton, { variant: "outlined", size: "small", disabled: isEditing && isEqual(dashboard, user.dashboard), color: isEditing ? 'success' : 'primary', startIcon: isEditing ? loading ? _jsx(CircularProgress, { size: 20 }) : _jsx(Check, {}) : _jsx(Edit, {}), onClick: () => (!isEditing ? setIsEditing(true) : saveChanges()), children: t(isEditing ? 'save' : 'edit') })] }), updatedHitTotal > 0 && (_jsxs(Alert, { severity: "info", variant: "outlined", action: _jsxs(Stack, { spacing: 1, direction: "row", children: [_jsx(IconButton, { color: "info", component: Link, to: `/hits?query=${encodeURIComponent(updateQuery)}`, onClick: () => setLastViewed(dayjs().utc().format(LUCENE_DATE_FMT)), children: _jsx(OpenInNew, {}) }), _jsx(IconButton, { color: "info", onClick: () => {
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
}
|
|
97
|
-
], children: [(dashboard ?? []).map(entry => {
|
|
98
|
-
if (entry.type === 'view') {
|
|
99
|
-
const settings = JSON.parse(entry.config);
|
|
100
|
-
return (_jsx(EntryWrapper, { editing: isEditing, id: settings.viewId, onDelete: () => setLocalDashboard((dashboard ?? []).filter(_entry => _entry.entry_id !== getIdFromEntry(entry))), children: _jsx(ViewCard, { ...settings }, entry.config) }, entry.entry_id));
|
|
85
|
+
return (_jsx(PageCenter, { maxWidth: "1800px", textAlign: "left", height: "100%", children: _jsx(ErrorBoundary, { children: _jsxs(Stack, { direction: "column", spacing: 1, sx: { height: '100%' }, children: [_jsxs(Stack, { direction: "row", justifyContent: "end", spacing: 1, children: [isEditing && (_jsx(CustomButton, { variant: "outlined", size: "small", color: "error", startIcon: _jsx(Cancel, {}), onClick: discardChanges, children: t('cancel') })), _jsx(CustomButton, { variant: "outlined", size: "small", disabled: isEditing && isEqual(dashboard, user.dashboard), color: isEditing ? 'success' : 'primary', startIcon: isEditing ? loading ? _jsx(CircularProgress, { size: 20 }) : _jsx(Check, {}) : _jsx(Edit, {}), onClick: () => (!isEditing ? setIsEditing(true) : saveChanges()), children: t(isEditing ? 'save' : 'edit') })] }), updatedHitTotal > 0 && (_jsxs(Alert, { severity: "info", variant: "outlined", action: _jsxs(Stack, { spacing: 1, direction: "row", children: [_jsx(IconButton, { color: "info", component: Link, to: `/hits?query=${encodeURIComponent(updateQuery)}`, onClick: () => setLastViewed(dayjs().utc().format(LUCENE_DATE_FMT)), children: _jsx(OpenInNew, {}) }), _jsx(IconButton, { color: "info", onClick: () => {
|
|
86
|
+
setLastViewed(dayjs().utc().format(LUCENE_DATE_FMT));
|
|
87
|
+
setUpdatedHitTotal(0);
|
|
88
|
+
}, children: _jsx(Close, {}) })] }), children: [_jsx(AlertTitle, { children: t('route.home.alert.updated.title') }), t('route.home.alert.updated.description', { count: updatedHitTotal })] })), _jsx(DndContext, { sensors: sensors, collisionDetection: closestCenter, onDragEnd: handleDragEnd, children: _jsx(SortableContext, { items: (dashboard ?? []).map(entry => getIdFromEntry(entry)), children: _jsxs(Grid, { container: true, spacing: 1, alignItems: "stretch", sx: [
|
|
89
|
+
theme => ({
|
|
90
|
+
marginLeft: `${theme.spacing(-1)} !important`
|
|
91
|
+
}),
|
|
92
|
+
!dashboard?.length &&
|
|
93
|
+
!isEditing && {
|
|
94
|
+
height: '100%',
|
|
95
|
+
display: 'flex',
|
|
96
|
+
alignItems: 'center'
|
|
101
97
|
}
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
98
|
+
], children: [(dashboard ?? []).map(entry => {
|
|
99
|
+
if (entry.type === 'view') {
|
|
100
|
+
const settings = JSON.parse(entry.config);
|
|
101
|
+
return (_jsx(EntryWrapper, { editing: isEditing, id: settings.viewId, onDelete: () => setLocalDashboard((dashboard ?? []).filter(_entry => _entry.entry_id !== getIdFromEntry(entry))), children: _jsx(ViewCard, { ...settings }, entry.config) }, entry.entry_id));
|
|
102
|
+
}
|
|
103
|
+
else if (entry.type === 'analytic') {
|
|
104
|
+
const settings = JSON.parse(entry.config);
|
|
105
|
+
return (_jsx(EntryWrapper, { editing: isEditing, id: getIdFromEntry(entry), onDelete: () => setLocalDashboard((dashboard ?? []).filter(_entry => _entry.entry_id !== getIdFromEntry(entry))), children: _jsx(AnalyticCard, { ...settings }, entry.config) }, entry.entry_id));
|
|
106
|
+
}
|
|
107
|
+
else {
|
|
108
|
+
return null;
|
|
109
|
+
}
|
|
110
|
+
}), isEditing && (_jsx(AddNewCard, { dashboard: dashboard, addCard: newCard => setStateDashboard(_dashboard => [...(_dashboard ?? []), newCard]) })), !dashboard?.length && !isEditing && (_jsx(Grid, { item: true, xs: 12, children: _jsxs(Stack, { direction: "column", spacing: 2, sx: theme => ({
|
|
111
|
+
height: '60vh',
|
|
112
|
+
borderStyle: 'dashed',
|
|
113
|
+
borderColor: theme.palette.text.secondary,
|
|
114
|
+
borderWidth: '1rem',
|
|
115
|
+
borderRadius: '1rem',
|
|
116
|
+
opacity: 0.3,
|
|
117
|
+
justifyContent: 'center',
|
|
118
|
+
alignItems: 'center',
|
|
119
|
+
padding: 3
|
|
120
|
+
}), children: [_jsx(Typography, { variant: "h1", sx: { display: 'flex', alignItems: 'center' }, children: _jsxs(Stack, { direction: "row", spacing: 2.5, children: [_jsx(AppBrand, { application: "howler", variant: "logo", size: "large" }), _jsx("span", { children: t('route.home.title') })] }) }), _jsx(Typography, { variant: "h4", sx: { textAlign: 'center' }, children: t('route.home.description') })] }) }))] }) }) })] }) }) }));
|
|
120
121
|
};
|
|
121
122
|
export default Home;
|