@cccsaurora/howler-ui 2.13.0-dev.169 → 2.13.0-dev.173

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.
Files changed (42) hide show
  1. package/commons/components/notification/elements/item/NotificationItemDate.js +2 -2
  2. package/components/app/drawers/ApiKeyDrawer.js +4 -4
  3. package/components/app/hooks/useMatchers.js +29 -4
  4. package/components/app/hooks/useMatchers.test.js +3 -3
  5. package/components/elements/hit/aggregate/HitGraph.d.ts +1 -1
  6. package/components/elements/hit/aggregate/HitGraph.js +7 -7
  7. package/components/elements/hit/elements/HitTimestamp.js +8 -8
  8. package/components/hooks/useMyChart.d.ts +1 -1
  9. package/components/hooks/useMyChart.js +1 -1
  10. package/components/routes/advanced/QueryBuilder.js +3 -3
  11. package/components/routes/analytics/AnalyticOverview.d.ts +1 -1
  12. package/components/routes/analytics/AnalyticOverview.js +1 -1
  13. package/components/routes/analytics/AnalyticOverviews.d.ts +1 -1
  14. package/components/routes/analytics/AnalyticOverviews.js +1 -1
  15. package/components/routes/analytics/AnalyticTemplates.d.ts +1 -1
  16. package/components/routes/analytics/AnalyticTemplates.js +1 -1
  17. package/components/routes/analytics/RuleView.d.ts +1 -1
  18. package/components/routes/analytics/RuleView.js +1 -1
  19. package/components/routes/analytics/TriageSettings.d.ts +1 -1
  20. package/components/routes/analytics/TriageSettings.js +1 -1
  21. package/components/routes/analytics/widgets/Assessment.d.ts +1 -1
  22. package/components/routes/analytics/widgets/Assessment.js +1 -1
  23. package/components/routes/analytics/widgets/Created.d.ts +1 -1
  24. package/components/routes/analytics/widgets/Created.js +1 -1
  25. package/components/routes/analytics/widgets/Detection.d.ts +1 -1
  26. package/components/routes/analytics/widgets/Detection.js +1 -1
  27. package/components/routes/analytics/widgets/Escalation.d.ts +1 -1
  28. package/components/routes/analytics/widgets/Escalation.js +1 -1
  29. package/components/routes/analytics/widgets/Stacked.d.ts +1 -1
  30. package/components/routes/analytics/widgets/Stacked.js +1 -1
  31. package/components/routes/analytics/widgets/Status.d.ts +1 -1
  32. package/components/routes/analytics/widgets/Status.js +1 -1
  33. package/components/routes/help/TemplateDocumentation.js +5 -5
  34. package/components/routes/hits/search/HitBrowser.js +2 -2
  35. package/components/routes/hits/search/InformationPane.js +16 -6
  36. package/components/routes/hits/search/shared/CustomSpan.js +6 -6
  37. package/components/routes/home/index.js +4 -4
  38. package/components/routes/settings/SecuritySection.js +2 -2
  39. package/index.js +7 -0
  40. package/package.json +103 -103
  41. package/utils/constants.js +2 -2
  42. package/utils/utils.js +3 -3
@@ -1,10 +1,10 @@
1
1
  import { Fragment as _Fragment, jsx as _jsx } from "react/jsx-runtime";
2
2
  import { Typography } from '@mui/material';
3
3
  import {} from '@cccsaurora/howler-ui/commons/components/notification';
4
- import moment from 'moment';
4
+ import dayjs from 'dayjs';
5
5
  import { memo } from 'react';
6
6
  import { useTranslation } from 'react-i18next';
7
7
  export const NotificationItemDate = memo(({ date_published = null }) => {
8
8
  const { i18n } = useTranslation(['notification']);
9
- return !date_published ? null : (_jsx(Typography, { lineHeight: "revert", display: "block", variant: "caption", color: "textSecondary", children: _jsx(_Fragment, { children: moment(date_published).locale(i18n.language).fromNow() }) }));
9
+ return !date_published ? null : (_jsx(Typography, { lineHeight: "revert", display: "block", variant: "caption", color: "textSecondary", children: _jsx(_Fragment, { children: dayjs(date_published).locale(i18n.language).fromNow() }) }));
10
10
  });
@@ -1,12 +1,12 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
2
  import { Alert, AlertTitle, Button, Checkbox, Divider, FormControl, FormControlLabel, FormGroup, FormLabel, Stack, TextField, Typography } from '@mui/material';
3
3
  import { LocalizationProvider, StaticDateTimePicker } from '@mui/x-date-pickers';
4
- import { AdapterMoment } from '@mui/x-date-pickers/AdapterMoment';
4
+ import { AdapterDayjs } from '@mui/x-date-pickers/AdapterDayjs';
5
5
  import api from '@cccsaurora/howler-ui/api';
6
6
  import useMyApi from '@cccsaurora/howler-ui/components/hooks/useMyApi';
7
7
  import useMySnackbar from '@cccsaurora/howler-ui/components/hooks/useMySnackbar';
8
+ import dayjs from 'dayjs';
8
9
  import {} from '@cccsaurora/howler-ui/models/entities/generated/ApiType';
9
- import moment from 'moment';
10
10
  import { useCallback, useContext, useEffect, useMemo, useState } from 'react';
11
11
  import { Trans, useTranslation } from 'react-i18next';
12
12
  import { ApiConfigContext } from '../providers/ApiConfigProvider';
@@ -30,7 +30,7 @@ const ApiKeyDrawer = ({ onCreated }) => {
30
30
  if (!amount || !unit) {
31
31
  return null;
32
32
  }
33
- return moment().add(amount, unit);
33
+ return dayjs().add(amount, unit);
34
34
  }, [amount, unit]);
35
35
  const updatePrivs = useCallback((priv) => (ev) => {
36
36
  if (ev.target.checked) {
@@ -62,6 +62,6 @@ const ApiKeyDrawer = ({ onCreated }) => {
62
62
  useEffect(() => {
63
63
  setExpiryDate(maxDate);
64
64
  }, [maxDate]);
65
- return (_jsx(LocalizationProvider, { dateAdapter: AdapterMoment, children: _jsxs(Stack, { direction: "column", spacing: 2, sx: { mt: 2 }, children: [_jsx(Typography, { sx: { maxWidth: '500px' }, children: _jsx(Trans, { i18nKey: "app.drawer.user.apikey.description" }) }), amount && unit && moment.duration(amount, unit).asSeconds() < moment.duration(7, 'days').asSeconds() && (_jsxs(Alert, { severity: "warning", variant: "outlined", sx: { maxWidth: '500px' }, children: [_jsx(AlertTitle, { children: t('app.drawer.user.apikey.limit.title') }), t('app.drawer.user.apikey.limit.description'), " (", maxDate?.format('MMM D HH:mm:ss'), ")"] })), _jsx(TextField, { label: t('app.drawer.user.apikey.field.name'), required: true, fullWidth: true, value: keyName, onChange: onChange }), _jsxs(FormControl, { required: true, children: [_jsx(FormLabel, { component: "legend", children: t('app.drawer.user.apikey.permissions') }), _jsxs(FormGroup, { sx: { display: 'grid', gridTemplateColumns: '1fr 1fr' }, children: [_jsx(FormControlLabel, { control: _jsx(Checkbox, { onChange: updatePrivs('R') }), label: t('@cccsaurora/howler-ui/apikey.read') }), _jsx(FormControlLabel, { control: _jsx(Checkbox, { onChange: updatePrivs('W') }), label: t('@cccsaurora/howler-ui/apikey.write') }), _jsx(FormControlLabel, { disabled: privs.includes('E'), control: _jsx(Checkbox, { onChange: updatePrivs('I') }), label: t('@cccsaurora/howler-ui/apikey.impersonate') }), config.configuration.auth.allow_extended_apikeys && (_jsx(FormControlLabel, { disabled: privs.includes('I'), control: _jsx(Checkbox, { onChange: updatePrivs('E') }), label: t('@cccsaurora/howler-ui/apikey.extended') }))] })] }), _jsxs(FormControl, { required: !!maxDate, children: [_jsx(FormLabel, { children: t('app.drawer.user.apikey.expiry.date') }), _jsx(StaticDateTimePicker, { orientation: "landscape", ampm: false, value: expiryDate, onChange: newValue => setExpiryDate(newValue), disablePast: true, maxDate: maxDate, maxTime: maxDate, sx: { backgroundColor: 'transparent', '& > div:first-of-type': { maxWidth: '300px' } } })] }), _jsx(Button, { onClick: onSubmit, disabled: !keyName || (!privs.includes('R') && !privs.includes('W')) || (maxDate && !expiryDate), variant: "outlined", children: _jsx(Trans, { i18nKey: "button.create" }) }), createdKey && (_jsxs(_Fragment, { children: [_jsx(Divider, { orientation: "horizontal" }), _jsxs(Stack, { direction: "row", spacing: 1, alignItems: "stretch", children: [_jsx(TextField, { size: "small", value: createdKey, inputProps: { readOnly: true }, fullWidth: true }), _jsx(Button, { variant: "outlined", onClick: onCopy, disabled: !createdKey, children: _jsx(Trans, { i18nKey: "button.copy" }) })] })] }))] }) }));
65
+ return (_jsx(LocalizationProvider, { dateAdapter: AdapterDayjs, children: _jsxs(Stack, { direction: "column", spacing: 2, sx: { mt: 2 }, children: [_jsx(Typography, { sx: { maxWidth: '500px' }, children: _jsx(Trans, { i18nKey: "app.drawer.user.apikey.description" }) }), amount && unit && dayjs.duration(amount, unit).asSeconds() < dayjs.duration(7, 'days').asSeconds() && (_jsxs(Alert, { severity: "warning", variant: "outlined", sx: { maxWidth: '500px' }, children: [_jsx(AlertTitle, { children: t('app.drawer.user.apikey.limit.title') }), t('app.drawer.user.apikey.limit.description'), " (", maxDate?.format('MMM D HH:mm:ss'), ")"] })), _jsx(TextField, { label: t('app.drawer.user.apikey.field.name'), required: true, fullWidth: true, value: keyName, onChange: onChange }), _jsxs(FormControl, { required: true, children: [_jsx(FormLabel, { component: "legend", children: t('app.drawer.user.apikey.permissions') }), _jsxs(FormGroup, { sx: { display: 'grid', gridTemplateColumns: '1fr 1fr' }, children: [_jsx(FormControlLabel, { control: _jsx(Checkbox, { onChange: updatePrivs('R') }), label: t('@cccsaurora/howler-ui/apikey.read') }), _jsx(FormControlLabel, { control: _jsx(Checkbox, { onChange: updatePrivs('W') }), label: t('@cccsaurora/howler-ui/apikey.write') }), _jsx(FormControlLabel, { disabled: privs.includes('E'), control: _jsx(Checkbox, { onChange: updatePrivs('I') }), label: t('@cccsaurora/howler-ui/apikey.impersonate') }), config.configuration.auth.allow_extended_apikeys && (_jsx(FormControlLabel, { disabled: privs.includes('I'), control: _jsx(Checkbox, { onChange: updatePrivs('E') }), label: t('@cccsaurora/howler-ui/apikey.extended') }))] })] }), _jsxs(FormControl, { required: !!maxDate, children: [_jsx(FormLabel, { children: t('app.drawer.user.apikey.expiry.date') }), _jsx(StaticDateTimePicker, { orientation: "landscape", ampm: false, value: expiryDate, onChange: newValue => setExpiryDate(newValue), disablePast: true, maxDate: maxDate, maxTime: maxDate, sx: { backgroundColor: 'transparent', '& > div:first-of-type': { maxWidth: '300px' } } })] }), _jsx(Button, { onClick: onSubmit, disabled: !keyName || (!privs.includes('R') && !privs.includes('W')) || (maxDate && !expiryDate), variant: "outlined", children: _jsx(Trans, { i18nKey: "button.create" }) }), createdKey && (_jsxs(_Fragment, { children: [_jsx(Divider, { orientation: "horizontal" }), _jsxs(Stack, { direction: "row", spacing: 1, alignItems: "stretch", children: [_jsx(TextField, { size: "small", value: createdKey, inputProps: { readOnly: true }, fullWidth: true }), _jsx(Button, { variant: "outlined", onClick: onCopy, disabled: !createdKey, children: _jsx(Trans, { i18nKey: "button.copy" }) })] })] }))] }) }));
66
66
  };
67
67
  export default ApiKeyDrawer;
@@ -1,3 +1,4 @@
1
+ /* eslint-disable no-console */
1
2
  import { has } from 'lodash-es';
2
3
  import { useCallback } from 'react';
3
4
  import { useContextSelector } from 'use-context-selector';
@@ -13,7 +14,13 @@ const useMatchers = () => {
13
14
  }
14
15
  // This is a fallback in case metadata is not included. In most cases templates are shown, the template metadata
15
16
  // should also exist
16
- return (await getHit(hit.howler.id, true)).__template;
17
+ try {
18
+ return (await getHit(hit.howler.id, true)).__template;
19
+ }
20
+ catch (e) {
21
+ console.warn(e);
22
+ return null;
23
+ }
17
24
  }, [getHit]);
18
25
  const getMatchingOverview = useCallback(async (hit) => {
19
26
  if (!hit) {
@@ -24,7 +31,13 @@ const useMatchers = () => {
24
31
  }
25
32
  // This is a fallback in case metadata is not included. In most cases templates are shown, the template metadata
26
33
  // should also exist
27
- return (await getHit(hit.howler.id, true)).__overview;
34
+ try {
35
+ return (await getHit(hit.howler.id, true)).__overview;
36
+ }
37
+ catch (e) {
38
+ console.warn(e);
39
+ return null;
40
+ }
28
41
  }, [getHit]);
29
42
  const getMatchingDossiers = useCallback(async (hit) => {
30
43
  if (!hit) {
@@ -35,7 +48,13 @@ const useMatchers = () => {
35
48
  }
36
49
  // This is a fallback in case metadata is not included. In most cases templates are shown, the template metadata
37
50
  // should also exist
38
- return (await getHit(hit.howler.id, true)).__dossiers;
51
+ try {
52
+ return (await getHit(hit.howler.id, true)).__dossiers ?? [];
53
+ }
54
+ catch (e) {
55
+ console.warn(e);
56
+ return [];
57
+ }
39
58
  }, [getHit]);
40
59
  const getMatchingAnalytic = useCallback(async (hit) => {
41
60
  if (!hit) {
@@ -45,7 +64,13 @@ const useMatchers = () => {
45
64
  return hit.__analytic;
46
65
  }
47
66
  // This is a fallback in case metadata is not included.
48
- return (await getHit(hit.howler.id, true)).__analytic;
67
+ try {
68
+ return (await getHit(hit.howler.id, true)).__analytic;
69
+ }
70
+ catch (e) {
71
+ console.warn(e);
72
+ return null;
73
+ }
49
74
  }, [getHit]);
50
75
  return {
51
76
  getMatchingDossiers,
@@ -86,7 +86,7 @@ describe('useMatchers', () => {
86
86
  has.mockReturnValue(false);
87
87
  mockGetHit.mockRejectedValue(new Error('Failed to fetch hit'));
88
88
  const { result } = renderHook(() => useMatchers());
89
- await expect(result.current.getMatchingTemplate(mockHit)).rejects.toThrow('Failed to fetch hit');
89
+ await expect(result.current.getMatchingTemplate(mockHit)).resolves.toBeNull();
90
90
  expect(mockGetHit).toHaveBeenCalledWith('test-hit-id', true);
91
91
  });
92
92
  });
@@ -124,7 +124,7 @@ describe('useMatchers', () => {
124
124
  has.mockReturnValue(false);
125
125
  mockGetHit.mockRejectedValue(new Error('Failed to fetch hit'));
126
126
  const { result } = renderHook(() => useMatchers());
127
- await expect(result.current.getMatchingOverview(mockHit)).rejects.toThrow('Failed to fetch hit');
127
+ await expect(result.current.getMatchingOverview(mockHit)).resolves.toBeNull();
128
128
  expect(mockGetHit).toHaveBeenCalledWith('test-hit-id', true);
129
129
  });
130
130
  });
@@ -162,7 +162,7 @@ describe('useMatchers', () => {
162
162
  has.mockReturnValue(false);
163
163
  mockGetHit.mockRejectedValue(new Error('Failed to fetch hit'));
164
164
  const { result } = renderHook(() => useMatchers());
165
- await expect(result.current.getMatchingDossiers(mockHit)).rejects.toThrow('Failed to fetch hit');
165
+ await expect(result.current.getMatchingDossiers(mockHit)).resolves.toEqual([]);
166
166
  expect(mockGetHit).toHaveBeenCalledWith('test-hit-id', true);
167
167
  });
168
168
  });
@@ -1,4 +1,4 @@
1
- import 'chartjs-adapter-moment';
1
+ import 'chartjs-adapter-dayjs';
2
2
  import type { FC } from 'react';
3
3
  declare const HitGraph: FC<{
4
4
  query: string;
@@ -2,15 +2,15 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { CenterFocusWeak, Refresh } from '@mui/icons-material';
3
3
  import { Alert, AlertTitle, Autocomplete, Box, Button, CircularProgress, IconButton, Stack, TextField, Tooltip, alpha, useTheme } from '@mui/material';
4
4
  import api from '@cccsaurora/howler-ui/api';
5
- import 'chartjs-adapter-moment';
5
+ import 'chartjs-adapter-dayjs';
6
6
  import { ApiConfigContext } from '@cccsaurora/howler-ui/components/app/providers/ApiConfigProvider';
7
7
  import { HitContext } from '@cccsaurora/howler-ui/components/app/providers/HitProvider';
8
8
  import { HitSearchContext } from '@cccsaurora/howler-ui/components/app/providers/HitSearchProvider';
9
9
  import { ParameterContext } from '@cccsaurora/howler-ui/components/app/providers/ParameterProvider';
10
10
  import useMyApi from '@cccsaurora/howler-ui/components/hooks/useMyApi';
11
11
  import useMyChart from '@cccsaurora/howler-ui/components/hooks/useMyChart';
12
+ import dayjs from 'dayjs';
12
13
  import { capitalize } from 'lodash-es';
13
- import moment from 'moment';
14
14
  import { useCallback, useContext, useEffect, useMemo, useRef, useState } from 'react';
15
15
  import { Scatter } from 'react-chartjs-2';
16
16
  import { useTranslation } from 'react-i18next';
@@ -96,10 +96,10 @@ const HitGraph = ({ query }) => {
96
96
  return {
97
97
  label: `${label} (${category.total})`,
98
98
  data: category.items.map(hit => {
99
- const createdMoment = moment(hit.event?.created ?? hit.timestamp);
99
+ const createdDate = dayjs(hit.event?.created ?? hit.timestamp);
100
100
  return {
101
- x: createdMoment.clone().hour(0).minute(0).second(0).toISOString(),
102
- y: createdMoment.hour() + createdMoment.minute() / 60 + createdMoment.second() / 3600,
101
+ x: createdDate.clone().hour(0).minute(0).second(0).toISOString(),
102
+ y: createdDate.hour() + createdDate.minute() / 60 + createdDate.second() / 3600,
103
103
  hit,
104
104
  label
105
105
  };
@@ -157,7 +157,7 @@ const HitGraph = ({ query }) => {
157
157
  tooltip: {
158
158
  callbacks: {
159
159
  title: entries => `${entries.length} ${t('hits')}`,
160
- label: entry => `${entry.raw.hit.howler.analytic}: ${entry.raw.hit.howler.detection} (${moment(entry.raw.hit.event.created).format('MMM D HH:mm:ss')})`,
160
+ label: entry => `${entry.raw.hit.howler.analytic}: ${entry.raw.hit.howler.detection} (${dayjs(entry.raw.hit.event.created).format('MMM D HH:mm:ss')})`,
161
161
  afterLabel: entry => `${entry.raw.hit.howler.outline.threat} ${entry.raw.hit.howler.outline.target}`
162
162
  }
163
163
  },
@@ -183,7 +183,7 @@ const HitGraph = ({ query }) => {
183
183
  ticks: {
184
184
  callback: (value) => {
185
185
  const [hour, minute] = [Math.floor(value), Math.floor((value - Math.floor(value)) * 60)];
186
- return moment().hour(hour).minute(minute).format('HH:mm');
186
+ return dayjs().hour(hour).minute(minute).format('HH:mm');
187
187
  }
188
188
  }
189
189
  }
@@ -1,7 +1,7 @@
1
1
  import { jsx as _jsx } from "react/jsx-runtime";
2
2
  import { Chip, Tooltip } from '@mui/material';
3
3
  import { ApiConfigContext } from '@cccsaurora/howler-ui/components/app/providers/ApiConfigProvider';
4
- import moment from 'moment';
4
+ import dayjs from 'dayjs';
5
5
  import { useContext, useMemo } from 'react';
6
6
  import { useTranslation } from 'react-i18next';
7
7
  import { formatDate } from '@cccsaurora/howler-ui/utils/utils';
@@ -14,31 +14,31 @@ const TIMESTAMP_MESSAGES = {
14
14
  const HitTimestamp = ({ hit, layout }) => {
15
15
  const { t } = useTranslation();
16
16
  const { config } = useContext(ApiConfigContext);
17
- const threshold = useMemo(() => moment().subtract(config.configuration.system.retention?.limit_amount ?? 350, config.configuration.system.retention?.limit_unit ?? 'days'), [config.configuration.system.retention?.limit_amount, config.configuration.system.retention?.limit_unit]);
17
+ const threshold = useMemo(() => dayjs().subtract(config.configuration.system.retention?.limit_amount ?? 350, config.configuration.system.retention?.limit_unit ?? 'days'), [config.configuration.system.retention?.limit_amount, config.configuration.system.retention?.limit_unit]);
18
18
  const timestamp = useMemo(() => {
19
19
  const validFieldValues = [hit.howler?.expiry, hit.event?.created, hit.timestamp];
20
20
  const earliestDate = validFieldValues
21
21
  .filter(entry => !!entry)
22
22
  .reduce((earliest, current) => {
23
- return moment(earliest).isBefore(current) ? earliest : current;
23
+ return dayjs(earliest).isBefore(current) ? earliest : current;
24
24
  });
25
25
  return earliestDate;
26
26
  }, [hit]);
27
27
  const color = useMemo(() => {
28
- if (moment(timestamp).isBefore(threshold.clone().add(2, 'weeks'))) {
28
+ if (dayjs(timestamp).isBefore(threshold.clone().add(2, 'weeks'))) {
29
29
  return 'error';
30
30
  }
31
- if (moment(timestamp).isBefore(threshold.clone().add(1, 'months'))) {
31
+ if (dayjs(timestamp).isBefore(threshold.clone().add(1, 'months'))) {
32
32
  return 'warning';
33
33
  }
34
34
  return 'default';
35
35
  }, [threshold, timestamp]);
36
36
  const duration = useMemo(() => {
37
- if (moment(timestamp).isBefore(threshold)) {
37
+ if (dayjs(timestamp).isBefore(threshold)) {
38
38
  return t('retention.imminent');
39
39
  }
40
- const diff = moment(timestamp).diff(threshold, 'seconds');
41
- const _duration = moment.duration(diff, 'seconds');
40
+ const diff = dayjs(timestamp).diff(threshold, 'seconds');
41
+ const _duration = dayjs.duration(diff, 'seconds');
42
42
  return _duration.humanize();
43
43
  }, [t, threshold, timestamp]);
44
44
  return (_jsx(Tooltip, { title: t(TIMESTAMP_MESSAGES[color], {
@@ -1,4 +1,4 @@
1
- import 'chartjs-adapter-moment';
1
+ import 'chartjs-adapter-dayjs';
2
2
  declare const useMyChart: () => {
3
3
  line: (titleKey: string, subtitleKey?: string) => {
4
4
  responsive: boolean;
@@ -1,6 +1,6 @@
1
1
  import { useTheme } from '@mui/material';
2
2
  import { ArcElement, BarElement, CategoryScale, Chart as ChartJS, Filler, Legend, LinearScale, LineElement, PointElement, SubTitle, TimeScale, Title, Tooltip } from 'chart.js';
3
- import 'chartjs-adapter-moment';
3
+ import 'chartjs-adapter-dayjs';
4
4
  import zoomPlugin from 'chartjs-plugin-zoom';
5
5
  import { useCallback } from 'react';
6
6
  import { useTranslation } from 'react-i18next';
@@ -13,7 +13,7 @@ import CustomButton from '@cccsaurora/howler-ui/components/elements/addons/butto
13
13
  import FlexOne from '@cccsaurora/howler-ui/components/elements/addons/layout/FlexOne';
14
14
  import JSONViewer from '@cccsaurora/howler-ui/components/elements/display/json/JSONViewer';
15
15
  import useMySnackbar from '@cccsaurora/howler-ui/components/hooks/useMySnackbar';
16
- import moment from 'moment';
16
+ import dayjs from 'dayjs';
17
17
  import { useCallback, useContext, useEffect, useMemo, useRef, useState } from 'react';
18
18
  import { useTranslation } from 'react-i18next';
19
19
  import { Link } from 'react-router-dom';
@@ -41,8 +41,8 @@ description: A basic example of using sigma rule notation to query howler
41
41
  references:
42
42
  - https://github.com/SigmaHQ/sigma
43
43
  author: You
44
- date: ${moment().format('YYYY/MM/DD')}
45
- modified: ${moment().format('YYYY/MM/DD')}
44
+ date: ${dayjs().format('YYYY/MM/DD')}
45
+ modified: ${dayjs().format('YYYY/MM/DD')}
46
46
  tags:
47
47
  - attack.command_and_control
48
48
  logsource:
@@ -1,4 +1,4 @@
1
- import 'chartjs-adapter-moment';
1
+ import 'chartjs-adapter-dayjs';
2
2
  import type { Analytic } from '@cccsaurora/howler-ui/models/entities/generated/Analytic';
3
3
  import type { FC } from 'react';
4
4
  declare const AnalyticOverview: FC<{
@@ -2,7 +2,7 @@ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-run
2
2
  import { Check, Edit } from '@mui/icons-material';
3
3
  import { Alert, AlertTitle, Box, Card, CardContent, CircularProgress, Divider, IconButton, Skeleton, Stack, TextField, Typography, useMediaQuery, useTheme } from '@mui/material';
4
4
  import api from '@cccsaurora/howler-ui/api';
5
- import 'chartjs-adapter-moment';
5
+ import 'chartjs-adapter-dayjs';
6
6
  import Markdown from '@cccsaurora/howler-ui/components/elements/display/Markdown';
7
7
  import useMyApi from '@cccsaurora/howler-ui/components/hooks/useMyApi';
8
8
  import useMySnackbar from '@cccsaurora/howler-ui/components/hooks/useMySnackbar';
@@ -1,4 +1,4 @@
1
- import 'chartjs-adapter-moment';
1
+ import 'chartjs-adapter-dayjs';
2
2
  import type { Analytic } from '@cccsaurora/howler-ui/models/entities/generated/Analytic';
3
3
  import { type FC } from 'react';
4
4
  declare const AnalyticOverviews: FC<{
@@ -1,7 +1,7 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { Article } from '@mui/icons-material';
3
3
  import { Box, Fab, Skeleton, Stack, Typography, useMediaQuery } from '@mui/material';
4
- import 'chartjs-adapter-moment';
4
+ import 'chartjs-adapter-dayjs';
5
5
  import AppListEmpty from '@cccsaurora/howler-ui/commons/components/display/AppListEmpty';
6
6
  import { OverviewContext } from '@cccsaurora/howler-ui/components/app/providers/OverviewProvider';
7
7
  import { useContext, useEffect, useMemo, useState } from 'react';
@@ -1,4 +1,4 @@
1
- import 'chartjs-adapter-moment';
1
+ import 'chartjs-adapter-dayjs';
2
2
  import type { Analytic } from '@cccsaurora/howler-ui/models/entities/generated/Analytic';
3
3
  import { type FC } from 'react';
4
4
  declare const AnalyticTemplates: FC<{
@@ -2,7 +2,7 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { Article } from '@mui/icons-material';
3
3
  import { Box, Fab, Skeleton, Stack, Typography, useMediaQuery } from '@mui/material';
4
4
  import api from '@cccsaurora/howler-ui/api';
5
- import 'chartjs-adapter-moment';
5
+ import 'chartjs-adapter-dayjs';
6
6
  import AppListEmpty from '@cccsaurora/howler-ui/commons/components/display/AppListEmpty';
7
7
  import useMyApi from '@cccsaurora/howler-ui/components/hooks/useMyApi';
8
8
  import { useEffect, useState } from 'react';
@@ -1,4 +1,4 @@
1
- import 'chartjs-adapter-moment';
1
+ import 'chartjs-adapter-dayjs';
2
2
  import type { Analytic } from '@cccsaurora/howler-ui/models/entities/generated/Analytic';
3
3
  import type { FC } from 'react';
4
4
  declare const RuleView: FC<{
@@ -2,7 +2,7 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { Check, Edit } from '@mui/icons-material';
3
3
  import { Box, CircularProgress, IconButton, Stack, Typography, useTheme } from '@mui/material';
4
4
  import api from '@cccsaurora/howler-ui/api';
5
- import 'chartjs-adapter-moment';
5
+ import 'chartjs-adapter-dayjs';
6
6
  import useMyApi from '@cccsaurora/howler-ui/components/hooks/useMyApi';
7
7
  import useMySnackbar from '@cccsaurora/howler-ui/components/hooks/useMySnackbar';
8
8
  import { useCallback, useState } from 'react';
@@ -1,4 +1,4 @@
1
- import 'chartjs-adapter-moment';
1
+ import 'chartjs-adapter-dayjs';
2
2
  import type { Analytic } from '@cccsaurora/howler-ui/models/entities/generated/Analytic';
3
3
  import type { FC } from 'react';
4
4
  declare const TriageSettings: FC<{
@@ -1,7 +1,7 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { Checkbox, Divider, Grid, Paper, Stack, Table, TableBody, TableCell, TableContainer, TableHead, TableRow, Tooltip, Typography } from '@mui/material';
3
3
  import api from '@cccsaurora/howler-ui/api';
4
- import 'chartjs-adapter-moment';
4
+ import 'chartjs-adapter-dayjs';
5
5
  import { ApiConfigContext } from '@cccsaurora/howler-ui/components/app/providers/ApiConfigProvider';
6
6
  import EditRow from '@cccsaurora/howler-ui/components/elements/EditRow';
7
7
  import useMyApi from '@cccsaurora/howler-ui/components/hooks/useMyApi';
@@ -1,4 +1,4 @@
1
- import 'chartjs-adapter-moment';
1
+ import 'chartjs-adapter-dayjs';
2
2
  import type { Analytic } from '@cccsaurora/howler-ui/models/entities/generated/Analytic';
3
3
  declare const Assessment: import("react").ForwardRefExoticComponent<{
4
4
  analytic: Analytic;
@@ -1,7 +1,7 @@
1
1
  import { jsx as _jsx } from "react/jsx-runtime";
2
2
  import { Box, Skeleton, Typography } from '@mui/material';
3
3
  import api from '@cccsaurora/howler-ui/api';
4
- import 'chartjs-adapter-moment';
4
+ import 'chartjs-adapter-dayjs';
5
5
  import useMyChart from '@cccsaurora/howler-ui/components/hooks/useMyChart';
6
6
  import { forwardRef, useEffect, useState } from 'react';
7
7
  import { Bar } from 'react-chartjs-2';
@@ -1,4 +1,4 @@
1
- import 'chartjs-adapter-moment';
1
+ import 'chartjs-adapter-dayjs';
2
2
  import type { Analytic } from '@cccsaurora/howler-ui/models/entities/generated/Analytic';
3
3
  declare const Created: import("react").ForwardRefExoticComponent<{
4
4
  analytic: Analytic;
@@ -1,7 +1,7 @@
1
1
  import { jsx as _jsx } from "react/jsx-runtime";
2
2
  import { Skeleton } from '@mui/material';
3
3
  import api from '@cccsaurora/howler-ui/api';
4
- import 'chartjs-adapter-moment';
4
+ import 'chartjs-adapter-dayjs';
5
5
  import useMyChart from '@cccsaurora/howler-ui/components/hooks/useMyChart';
6
6
  import { forwardRef, useEffect, useState } from 'react';
7
7
  import { Line } from 'react-chartjs-2';
@@ -1,4 +1,4 @@
1
- import 'chartjs-adapter-moment';
1
+ import 'chartjs-adapter-dayjs';
2
2
  import type { Analytic } from '@cccsaurora/howler-ui/models/entities/generated/Analytic';
3
3
  declare const Detection: import("react").ForwardRefExoticComponent<{
4
4
  analytic: Analytic;
@@ -1,5 +1,5 @@
1
1
  import { jsx as _jsx } from "react/jsx-runtime";
2
- import 'chartjs-adapter-moment';
2
+ import 'chartjs-adapter-dayjs';
3
3
  import { forwardRef } from 'react';
4
4
  import { stringToColor } from '@cccsaurora/howler-ui/utils/utils';
5
5
  import Stacked from './Stacked';
@@ -1,4 +1,4 @@
1
- import 'chartjs-adapter-moment';
1
+ import 'chartjs-adapter-dayjs';
2
2
  import type { Analytic } from '@cccsaurora/howler-ui/models/entities/generated/Analytic';
3
3
  declare const Escalation: import("react").ForwardRefExoticComponent<{
4
4
  analytic: Analytic;
@@ -1,7 +1,7 @@
1
1
  import { jsx as _jsx } from "react/jsx-runtime";
2
2
  import { Skeleton, useTheme } from '@mui/material';
3
3
  import api from '@cccsaurora/howler-ui/api';
4
- import 'chartjs-adapter-moment';
4
+ import 'chartjs-adapter-dayjs';
5
5
  import useMyChart from '@cccsaurora/howler-ui/components/hooks/useMyChart';
6
6
  import { forwardRef, useEffect, useMemo, useState } from 'react';
7
7
  import { Doughnut } from 'react-chartjs-2';
@@ -1,4 +1,4 @@
1
- import 'chartjs-adapter-moment';
1
+ import 'chartjs-adapter-dayjs';
2
2
  import type { Analytic } from '@cccsaurora/howler-ui/models/entities/generated/Analytic';
3
3
  declare const Stacked: import("react").ForwardRefExoticComponent<{
4
4
  analytic: Analytic;
@@ -1,7 +1,7 @@
1
1
  import { jsx as _jsx } from "react/jsx-runtime";
2
2
  import { Skeleton } from '@mui/material';
3
3
  import api from '@cccsaurora/howler-ui/api';
4
- import 'chartjs-adapter-moment';
4
+ import 'chartjs-adapter-dayjs';
5
5
  import useMyChart from '@cccsaurora/howler-ui/components/hooks/useMyChart';
6
6
  import sum from 'lodash-es/sum';
7
7
  import { forwardRef, useCallback, useEffect, useMemo, useState } from 'react';
@@ -1,4 +1,4 @@
1
- import 'chartjs-adapter-moment';
1
+ import 'chartjs-adapter-dayjs';
2
2
  import type { Analytic } from '@cccsaurora/howler-ui/models/entities/generated/Analytic';
3
3
  declare const Status: import("react").ForwardRefExoticComponent<{
4
4
  analytic: Analytic;
@@ -1,6 +1,6 @@
1
1
  import { jsx as _jsx } from "react/jsx-runtime";
2
2
  import { useTheme } from '@mui/material';
3
- import 'chartjs-adapter-moment';
3
+ import 'chartjs-adapter-dayjs';
4
4
  import { forwardRef } from 'react';
5
5
  import { STATUS_COLORS } from '@cccsaurora/howler-ui/utils/constants';
6
6
  import Stacked from './Stacked';
@@ -5,7 +5,7 @@ import Markdown from '@cccsaurora/howler-ui/components/elements/display/Markdown
5
5
  import { HitLayout } from '@cccsaurora/howler-ui/components/elements/hit/HitLayout';
6
6
  import DefaultOutline from '@cccsaurora/howler-ui/components/elements/hit/outlines/DefaultOutline';
7
7
  import { useScrollRestoration } from '@cccsaurora/howler-ui/components/hooks/useScrollRestoration';
8
- import moment from 'moment';
8
+ import dayjs from 'dayjs';
9
9
  import { useMemo } from 'react';
10
10
  import { useTranslation } from 'react-i18next';
11
11
  import TEMPLATES_EN from './markdown/en/templates.md';
@@ -14,8 +14,8 @@ const ALERTS = [
14
14
  {
15
15
  howler: { id: 'hit1', analytic: 'Cat Checker', detection: 'Listening for Meows' },
16
16
  event: {
17
- start: moment().subtract(4, 'hour').toString(),
18
- end: moment().subtract(3, 'hour').toString(),
17
+ start: dayjs().subtract(4, 'hour').toString(),
18
+ end: dayjs().subtract(3, 'hour').toString(),
19
19
  kind: 'Loud meow',
20
20
  outcome: 'Food provided'
21
21
  }
@@ -23,8 +23,8 @@ const ALERTS = [
23
23
  {
24
24
  howler: { id: 'hit2', analytic: 'Cat Checker', detection: 'Looking for paw prints' },
25
25
  event: {
26
- start: moment().subtract(6, 'hour').toString(),
27
- end: moment().subtract(5, 'hour').toString(),
26
+ start: dayjs().subtract(6, 'hour').toString(),
27
+ end: dayjs().subtract(5, 'hour').toString(),
28
28
  provider: "The neighbour's cat (probably)",
29
29
  reason: 'There was some fish we forgot to put away in the kitchen'
30
30
  }
@@ -10,8 +10,8 @@ import FlexPort from '@cccsaurora/howler-ui/components/elements/addons/layout/Fl
10
10
  import HitSummary from '@cccsaurora/howler-ui/components/elements/hit/HitSummary';
11
11
  import { useMyLocalStorageItem } from '@cccsaurora/howler-ui/components/hooks/useMyLocalStorage';
12
12
  import ErrorBoundary from '@cccsaurora/howler-ui/components/routes/ErrorBoundary';
13
+ import dayjs from 'dayjs';
13
14
  import { has, isNull } from 'lodash-es';
14
- import moment from 'moment';
15
15
  import { memo, useCallback, useEffect, useMemo, useState } from 'react';
16
16
  import { Trans, useTranslation } from 'react-i18next';
17
17
  import { useLocation, useParams, useSearchParams } from 'react-router-dom';
@@ -88,7 +88,7 @@ const HitBrowser = () => {
88
88
  useEffect(() => {
89
89
  // On load check to filter out any queries older than one month
90
90
  setQueryHistory(_queryHistory => {
91
- const filterQueryTime = moment().subtract(1, 'month').toISOString();
91
+ const filterQueryTime = dayjs().subtract(1, 'month').toISOString();
92
92
  return Object.fromEntries(Object.entries(_queryHistory).filter(([_, value]) => value > filterQueryTime));
93
93
  });
94
94
  }, [setQueryHistory]);
@@ -56,16 +56,15 @@ const InformationPane = ({ onClose }) => {
56
56
  const [hasOverview, setHasOverview] = useState(false);
57
57
  const [tab, setTab] = useState('overview');
58
58
  const [loading, setLoading] = useState(false);
59
- const [dossiers, setDossiers] = useState([]);
60
59
  const [filter, setFilter] = useState('');
60
+ // In order to properly check for dossiers, we split dossiers into two
61
+ const [_dossiers, setDossiers] = useState(null);
62
+ const dossiers = useMemo(() => _dossiers ?? [], [_dossiers]);
61
63
  const users = useMyUserList(userIds);
62
64
  const hit = useContextSelector(HitContext, ctx => ctx.hits[selected]);
63
65
  howlerPluginStore.plugins.forEach(plugin => {
64
66
  pluginStore.executeFunction(`${plugin}.on`, 'viewing');
65
67
  });
66
- useEffect(() => {
67
- getMatchingOverview(hit).then(_overview => setHasOverview(!!_overview));
68
- }, [getMatchingOverview, hit]);
69
68
  useEffect(() => {
70
69
  if (!selected) {
71
70
  return;
@@ -76,10 +75,21 @@ const InformationPane = ({ onClose }) => {
76
75
  return;
77
76
  }
78
77
  setUserIds(getUserList(hit));
79
- getMatchingAnalytic(hit).then(setAnalytic);
80
- getMatchingDossiers(hit).then(setDossiers);
81
78
  // eslint-disable-next-line react-hooks/exhaustive-deps
82
79
  }, [getHit, selected]);
80
+ useEffect(() => {
81
+ if (hit && !analytic) {
82
+ getMatchingAnalytic(hit).then(setAnalytic);
83
+ }
84
+ }, [analytic, getMatchingAnalytic, hit]);
85
+ useEffect(() => {
86
+ if (hit && !_dossiers) {
87
+ getMatchingDossiers(hit).then(setDossiers);
88
+ }
89
+ }, [_dossiers, getMatchingDossiers, hit]);
90
+ useEffect(() => {
91
+ getMatchingOverview(hit).then(_overview => setHasOverview(!!_overview));
92
+ }, [getMatchingOverview, hit]);
83
93
  useEffect(() => {
84
94
  if (tab === 'hit_aggregate' && !hit?.howler.is_bundle) {
85
95
  setTab('overview');
@@ -1,24 +1,24 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { Stack } from '@mui/material';
3
3
  import { LocalizationProvider } from '@mui/x-date-pickers';
4
- import { AdapterMoment } from '@mui/x-date-pickers/AdapterMoment';
4
+ import { AdapterDayjs } from '@mui/x-date-pickers/AdapterDayjs';
5
5
  import { DateTimePicker } from '@mui/x-date-pickers/DateTimePicker';
6
6
  import { ParameterContext } from '@cccsaurora/howler-ui/components/app/providers/ParameterProvider';
7
- import moment from 'moment';
7
+ import dayjs from 'dayjs';
8
8
  import { memo, useEffect } from 'react';
9
9
  import { useTranslation } from 'react-i18next';
10
10
  import { useContextSelector } from 'use-context-selector';
11
11
  const CustomSpan = () => {
12
12
  const { t } = useTranslation();
13
13
  const span = useContextSelector(ParameterContext, ctx => ctx.span);
14
- const startDate = useContextSelector(ParameterContext, ctx => (ctx.startDate ? moment(ctx.startDate) : null));
14
+ const startDate = useContextSelector(ParameterContext, ctx => (ctx.startDate ? dayjs(ctx.startDate) : null));
15
15
  const setCustomSpan = useContextSelector(ParameterContext, ctx => ctx.setCustomSpan);
16
- const endDate = useContextSelector(ParameterContext, ctx => (ctx.endDate ? moment(ctx.endDate) : null));
16
+ const endDate = useContextSelector(ParameterContext, ctx => (ctx.endDate ? dayjs(ctx.endDate) : null));
17
17
  useEffect(() => {
18
18
  if (span?.endsWith('custom') && (!startDate || !endDate)) {
19
- setCustomSpan(moment().subtract(3, 'days').toISOString(), moment().toISOString());
19
+ setCustomSpan(dayjs().subtract(3, 'days').toISOString(), dayjs().toISOString());
20
20
  }
21
21
  }, [endDate, setCustomSpan, span, startDate]);
22
- return span?.endsWith('custom') ? (_jsx(LocalizationProvider, { dateAdapter: AdapterMoment, children: _jsxs(Stack, { direction: "row", spacing: 1, useFlexGap: true, flexWrap: "wrap", children: [_jsx(DateTimePicker, { sx: { minWidth: '175px', flexGrow: 1, marginTop: 1 }, slotProps: { textField: { size: 'small' } }, label: t('date.select.start'), value: startDate ? moment(startDate) : moment().subtract(1, 'days'), maxDate: endDate, onChange: (newStartDate) => setCustomSpan(newStartDate.toISOString(), endDate.toISOString()), ampm: false, disableFuture: true }), _jsx(DateTimePicker, { sx: { minWidth: '175px', flexGrow: 1, marginTop: 1 }, slotProps: { textField: { size: 'small' } }, label: t('date.select.end'), value: endDate, minDate: startDate, onChange: (newEndDate) => setCustomSpan(startDate.toISOString(), newEndDate.toISOString()), ampm: false, disableFuture: true })] }) })) : null;
22
+ return span?.endsWith('custom') ? (_jsx(LocalizationProvider, { dateAdapter: AdapterDayjs, children: _jsxs(Stack, { direction: "row", spacing: 1, useFlexGap: true, flexWrap: "wrap", children: [_jsx(DateTimePicker, { sx: { minWidth: '175px', flexGrow: 1, marginTop: 1 }, slotProps: { textField: { size: 'small' } }, label: t('date.select.start'), value: startDate ? dayjs(startDate) : dayjs().subtract(1, 'days'), maxDate: endDate, onChange: (newStartDate) => setCustomSpan(newStartDate.toISOString(), endDate.toISOString()), ampm: false, disableFuture: true }), _jsx(DateTimePicker, { sx: { minWidth: '175px', flexGrow: 1, marginTop: 1 }, slotProps: { textField: { size: 'small' } }, label: t('date.select.end'), value: endDate, minDate: startDate, onChange: (newEndDate) => setCustomSpan(startDate.toISOString(), newEndDate.toISOString()), ampm: false, disableFuture: true })] }) })) : null;
23
23
  };
24
24
  export default memo(CustomSpan);
@@ -10,8 +10,8 @@ import PageCenter from '@cccsaurora/howler-ui/commons/components/pages/PageCente
10
10
  import CustomButton from '@cccsaurora/howler-ui/components/elements/addons/buttons/CustomButton';
11
11
  import { useMyLocalStorageItem } from '@cccsaurora/howler-ui/components/hooks/useMyLocalStorage';
12
12
  import useMyUserFunctions from '@cccsaurora/howler-ui/components/hooks/useMyUserFunctions';
13
+ import dayjs from 'dayjs';
13
14
  import isEqual from 'lodash-es/isEqual';
14
- import moment from 'moment';
15
15
  import { useCallback, useEffect, useMemo, useState } from 'react';
16
16
  import { useTranslation } from 'react-i18next';
17
17
  import { Link } from 'react-router-dom';
@@ -26,7 +26,7 @@ const Home = () => {
26
26
  const { user, setUser } = useAppUser();
27
27
  const { setDashboard } = useMyUserFunctions();
28
28
  const sensors = useSensors(useSensor(PointerSensor), useSensor(KeyboardSensor, { coordinateGetter: sortableKeyboardCoordinates }));
29
- const [lastViewed, setLastViewed] = useMyLocalStorageItem(StorageKey.LAST_VIEW, moment().utc().format(LUCENE_DATE_FMT));
29
+ const [lastViewed, setLastViewed] = useMyLocalStorageItem(StorageKey.LAST_VIEW, dayjs().utc().format(LUCENE_DATE_FMT));
30
30
  const [loading, setLoading] = useState(false);
31
31
  const [isEditing, setIsEditing] = useState(false);
32
32
  const [updatedHitTotal, setUpdatedHitTotal] = useState(0);
@@ -81,8 +81,8 @@ const Home = () => {
81
81
  })
82
82
  .then(result => setUpdatedHitTotal(result.total));
83
83
  }, [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(moment().utc().format(LUCENE_DATE_FMT)), children: _jsx(OpenInNew, {}) }), _jsx(IconButton, { color: "info", onClick: () => {
85
- setLastViewed(moment().utc().format(LUCENE_DATE_FMT));
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
+ setLastViewed(dayjs().utc().format(LUCENE_DATE_FMT));
86
86
  setUpdatedHitTotal(0);
87
87
  }, 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: [
88
88
  theme => ({
@@ -3,7 +3,7 @@ import { Add } from '@mui/icons-material';
3
3
  import { Chip, Grid, IconButton, TableCell, TableRow } from '@mui/material';
4
4
  import { ApiConfigContext } from '@cccsaurora/howler-ui/components/app/providers/ApiConfigProvider';
5
5
  import useMyLocalStorage from '@cccsaurora/howler-ui/components/hooks/useMyLocalStorage';
6
- import moment from 'moment';
6
+ import dayjs from 'dayjs';
7
7
  import howlerPluginStore from '@cccsaurora/howler-ui/plugins/store';
8
8
  import { useContext, useMemo } from 'react';
9
9
  import { Trans, useTranslation } from 'react-i18next';
@@ -26,6 +26,6 @@ const SecuritySection = ({ user, editPassword, addApiKey, removeApiKey, editQuot
26
26
  return (_jsxs(SettingsSection, { title: t('page.settings.security.title'), colSpan: 3, children: [!isOAuth && editPassword && (_jsx(EditRow, { titleKey: "page.settings.security.table.password", value: "\u25CF\u25CF\u25CF\u25CF\u25CF\u25CF\u25CF\u25CF\u25CF\u25CF\u25CF", onEdit: editPassword, type: "password" })), config?.configuration.auth.allow_apikeys && (_jsxs(TableRow, { sx: { cursor: 'pointer' }, children: [_jsx(TableCell, { style: { whiteSpace: 'nowrap' }, children: t('page.settings.security.table.apikeys') }), _jsx(TableCell, { width: "100%", children: _jsxs(Grid, { container: true, spacing: 1, children: [user?.apikeys?.map(apiKey => (_jsx(Grid, { item: true, children: _jsx(Chip, { label: apiKey[0].toLocaleLowerCase() +
27
27
  (apiKey[1].length > 0
28
28
  ? ` (${apiKey[1].map(permission => t(APIKEY_LABELS[permission])).join(', ')})`
29
- : ''), style: { backgroundColor: moment.utc(apiKey[2]).isBefore(moment().utc()) ? 'orange' : 'default' }, onDelete: removeApiKey ? () => removeApiKey(apiKey) : null }) }, apiKey[0]))), user?.apikeys?.length < 1 && (_jsx(Grid, { item: true, children: _jsx(Trans, { i18nKey: "none" }) }))] }) }), _jsx(TableCell, { align: "right", children: addApiKey && (_jsx(IconButton, { onClick: addApiKey, children: _jsx(Add, { fontSize: "small" }) })) })] })), _jsx(EditRow, { titleKey: "page.settings.security.table.apiquota", descriptionKey: "page.settings.security.table.apiquota.description", value: user?.api_quota, validate: value => value && /^[0-9]*$/m.test(value.toString()), type: "number", onEdit: editQuota }), howlerPluginStore.plugins.map(plugin => pluginStore.executeFunction(`${plugin}.settings`, 'security'))] }));
29
+ : ''), style: { backgroundColor: dayjs.utc(apiKey[2]).isBefore(dayjs().utc()) ? 'orange' : 'default' }, onDelete: removeApiKey ? () => removeApiKey(apiKey) : null }) }, apiKey[0]))), user?.apikeys?.length < 1 && (_jsx(Grid, { item: true, children: _jsx(Trans, { i18nKey: "none" }) }))] }) }), _jsx(TableCell, { align: "right", children: addApiKey && (_jsx(IconButton, { onClick: addApiKey, children: _jsx(Add, { fontSize: "small" }) })) })] })), _jsx(EditRow, { titleKey: "page.settings.security.table.apiquota", descriptionKey: "page.settings.security.table.apiquota.description", value: user?.api_quota, validate: value => value && /^[0-9]*$/m.test(value.toString()), type: "number", onEdit: editQuota }), howlerPluginStore.plugins.map(plugin => pluginStore.executeFunction(`${plugin}.settings`, 'security'))] }));
30
30
  };
31
31
  export default SecuritySection;
package/index.js CHANGED
@@ -1,10 +1,17 @@
1
1
  import { jsx as _jsx } from "react/jsx-runtime";
2
2
  import '@fontsource/roboto';
3
3
  import App from '@cccsaurora/howler-ui/components/app/App';
4
+ import dayjs from 'dayjs';
5
+ import duration from 'dayjs/plugin/duration';
6
+ import relativeTime from 'dayjs/plugin/relativeTime';
7
+ import utc from 'dayjs/plugin/utc';
4
8
  import '@cccsaurora/howler-ui/i18n';
5
9
  import 'index.css';
6
10
  // import howlerPluginStore from '@cccsaurora/howler-ui/plugins/store';
7
11
  import * as ReactDOM from 'react-dom/client';
12
+ dayjs.extend(utc);
13
+ dayjs.extend(duration);
14
+ dayjs.extend(relativeTime);
8
15
  // This is where you can inject UI plugins to modify Howler's interface.
9
16
  // howlerPluginStore.install(new ExamplePlugin());
10
17
  ReactDOM.createRoot(document.getElementById('root')).render(_jsx(App, {}));
package/package.json CHANGED
@@ -31,10 +31,11 @@
31
31
  "axios-retry": "^3.9.1",
32
32
  "borealis-ui": "0.11.0",
33
33
  "chart.js": "^4.5.0",
34
- "chartjs-adapter-moment": "^1.0.1",
34
+ "chartjs-adapter-dayjs": "^1.0.0",
35
35
  "chartjs-plugin-zoom": "^2.2.0",
36
36
  "clsx": "^2.1.1",
37
37
  "csstype": "^3.1.3",
38
+ "dayjs": "^1.11.13",
38
39
  "dompurify": "^3.2.6",
39
40
  "express": "^4.21.2",
40
41
  "flat": "^6.0.1",
@@ -47,7 +48,6 @@
47
48
  "lodash-es": "^4.17.21",
48
49
  "md5": "^2.3.0",
49
50
  "mermaid": "^11.10.0",
50
- "moment": "^2.30.1",
51
51
  "monaco-editor": "^0.49.0",
52
52
  "notistack": "^3.0.2",
53
53
  "react": "^18.3.1",
@@ -96,163 +96,163 @@
96
96
  "internal-slot": "1.0.7"
97
97
  },
98
98
  "type": "module",
99
- "version": "2.13.0-dev.169",
99
+ "version": "2.13.0-dev.173",
100
100
  "exports": {
101
101
  "./i18n": "./i18n.js",
102
102
  "./index.css": "./index.css",
103
+ "./utils/*": "./utils/*.js",
104
+ "./utils/*.json": "./utils/*.json",
105
+ "./locales/*.json": "./locales/*.json",
106
+ "./commons/*": "./commons/*.js",
103
107
  "./api/*": "./api/*.js",
104
108
  "./api": "./api/index.js",
105
- "./commons/*": "./commons/*.js",
106
109
  "./tests/*": "./tests/*.js",
107
- "./rest/*": "./rest/*.js",
108
- "./rest": "./rest/index.js",
109
- "./locales/*.json": "./locales/*.json",
110
+ "./plugins/*": "./plugins/*.js",
110
111
  "./branding/*": "./branding/*.js",
111
112
  "./components/*": "./components/*.js",
113
+ "./rest/*": "./rest/*.js",
114
+ "./rest": "./rest/index.js",
112
115
  "./models/*": "./models/*.js",
113
- "./utils/*": "./utils/*.js",
114
- "./utils/*.json": "./utils/*.json",
115
- "./plugins/*": "./plugins/*.js",
116
- "./api/analytic/*": "./api/analytic/*.js",
117
- "./api/analytic": "./api/analytic/index.js",
118
- "./api/configs/*": "./api/configs/*.js",
119
- "./api/configs": "./api/configs/index.js",
120
- "./api/dossier/*": "./api/dossier/*.js",
121
- "./api/dossier": "./api/dossier/index.js",
122
- "./api/user/*": "./api/user/*.js",
123
- "./api/user": "./api/user/index.js",
124
- "./api/notebook/*": "./api/notebook/*.js",
125
- "./api/notebook": "./api/notebook/index.js",
116
+ "./locales/fr/*.json": "./locales/fr/*.json",
117
+ "./locales/en/*.json": "./locales/en/*.json",
118
+ "./locales/fr/help/*.json": "./locales/fr/help/*.json",
119
+ "./locales/en/help/*.json": "./locales/en/help/*.json",
120
+ "./commons/components/*": "./commons/components/*.js",
121
+ "./commons/components/utils/*": "./commons/components/utils/*.js",
122
+ "./commons/components/topnav/*": "./commons/components/topnav/*.js",
123
+ "./commons/components/app/*": "./commons/components/app/*.js",
124
+ "./commons/components/display/*": "./commons/components/display/*.js",
125
+ "./commons/components/breadcrumbs/*": "./commons/components/breadcrumbs/*.js",
126
+ "./commons/components/search/*": "./commons/components/search/*.js",
127
+ "./commons/components/pages/*": "./commons/components/pages/*.js",
128
+ "./commons/components/notification/*": "./commons/components/notification/*.js",
129
+ "./commons/components/notification": "./commons/components/notification/index.js",
130
+ "./commons/components/leftnav/*": "./commons/components/leftnav/*.js",
131
+ "./commons/components/utils/hooks/*": "./commons/components/utils/hooks/*.js",
132
+ "./commons/components/app/providers/*": "./commons/components/app/providers/*.js",
133
+ "./commons/components/app/hooks/*": "./commons/components/app/hooks/*.js",
134
+ "./commons/components/app/hooks": "./commons/components/app/hooks/index.js",
135
+ "./commons/components/display/hooks/*": "./commons/components/display/hooks/*.js",
136
+ "./commons/components/pages/hooks/*": "./commons/components/pages/hooks/*.js",
137
+ "./commons/components/notification/elements/*": "./commons/components/notification/elements/*.js",
138
+ "./commons/components/notification/elements/item/*": "./commons/components/notification/elements/item/*.js",
139
+ "./api/template/*": "./api/template/*.js",
140
+ "./api/template": "./api/template/index.js",
126
141
  "./api/action/*": "./api/action/*.js",
127
142
  "./api/action": "./api/action/index.js",
143
+ "./api/user/*": "./api/user/*.js",
144
+ "./api/user": "./api/user/index.js",
145
+ "./api/hit/*": "./api/hit/*.js",
146
+ "./api/hit": "./api/hit/index.js",
147
+ "./api/configs/*": "./api/configs/*.js",
148
+ "./api/configs": "./api/configs/index.js",
128
149
  "./api/auth/*": "./api/auth/*.js",
129
150
  "./api/auth": "./api/auth/index.js",
130
151
  "./api/search/*": "./api/search/*.js",
131
152
  "./api/search": "./api/search/index.js",
153
+ "./api/analytic/*": "./api/analytic/*.js",
154
+ "./api/analytic": "./api/analytic/index.js",
155
+ "./api/notebook/*": "./api/notebook/*.js",
156
+ "./api/notebook": "./api/notebook/index.js",
132
157
  "./api/view/*": "./api/view/*.js",
133
158
  "./api/view": "./api/view/index.js",
159
+ "./api/dossier/*": "./api/dossier/*.js",
160
+ "./api/dossier": "./api/dossier/index.js",
134
161
  "./api/overview/*": "./api/overview/*.js",
135
162
  "./api/overview": "./api/overview/index.js",
136
- "./api/hit/*": "./api/hit/*.js",
137
- "./api/hit": "./api/hit/index.js",
138
- "./api/template/*": "./api/template/*.js",
139
- "./api/template": "./api/template/index.js",
140
- "./api/analytic/notebooks/*": "./api/analytic/notebooks/*.js",
141
- "./api/analytic/notebooks": "./api/analytic/notebooks/index.js",
142
- "./api/analytic/comments/*": "./api/analytic/comments/*.js",
143
- "./api/analytic/comments": "./api/analytic/comments/index.js",
144
163
  "./api/user/avatar/*": "./api/user/avatar/*.js",
145
164
  "./api/user/avatar": "./api/user/avatar/index.js",
146
- "./api/search/fields/*": "./api/search/fields/*.js",
147
- "./api/search/fields": "./api/search/fields/index.js",
148
- "./api/search/sigma/*": "./api/search/sigma/*.js",
149
- "./api/search/histogram/*": "./api/search/histogram/*.js",
150
- "./api/search/histogram": "./api/search/histogram/index.js",
165
+ "./api/hit/comments/*": "./api/hit/comments/*.js",
166
+ "./api/hit/comments": "./api/hit/comments/index.js",
151
167
  "./api/search/grouped/*": "./api/search/grouped/*.js",
152
168
  "./api/search/grouped": "./api/search/grouped/index.js",
153
- "./api/search/count/*": "./api/search/count/*.js",
154
- "./api/search/count": "./api/search/count/index.js",
169
+ "./api/search/fields/*": "./api/search/fields/*.js",
170
+ "./api/search/fields": "./api/search/fields/index.js",
155
171
  "./api/search/eql/*": "./api/search/eql/*.js",
156
172
  "./api/search/facet/*": "./api/search/facet/*.js",
157
173
  "./api/search/facet": "./api/search/facet/index.js",
158
- "./api/hit/comments/*": "./api/hit/comments/*.js",
159
- "./api/hit/comments": "./api/hit/comments/index.js",
160
- "./commons/components/*": "./commons/components/*.js",
161
- "./commons/components/breadcrumbs/*": "./commons/components/breadcrumbs/*.js",
162
- "./commons/components/app/*": "./commons/components/app/*.js",
163
- "./commons/components/notification/*": "./commons/components/notification/*.js",
164
- "./commons/components/notification": "./commons/components/notification/index.js",
165
- "./commons/components/topnav/*": "./commons/components/topnav/*.js",
166
- "./commons/components/pages/*": "./commons/components/pages/*.js",
167
- "./commons/components/display/*": "./commons/components/display/*.js",
168
- "./commons/components/utils/*": "./commons/components/utils/*.js",
169
- "./commons/components/leftnav/*": "./commons/components/leftnav/*.js",
170
- "./commons/components/search/*": "./commons/components/search/*.js",
171
- "./commons/components/app/hooks/*": "./commons/components/app/hooks/*.js",
172
- "./commons/components/app/hooks": "./commons/components/app/hooks/index.js",
173
- "./commons/components/app/providers/*": "./commons/components/app/providers/*.js",
174
- "./commons/components/notification/elements/*": "./commons/components/notification/elements/*.js",
175
- "./commons/components/notification/elements/item/*": "./commons/components/notification/elements/item/*.js",
176
- "./commons/components/pages/hooks/*": "./commons/components/pages/hooks/*.js",
177
- "./commons/components/display/hooks/*": "./commons/components/display/hooks/*.js",
178
- "./commons/components/utils/hooks/*": "./commons/components/utils/hooks/*.js",
179
- "./locales/en/*.json": "./locales/en/*.json",
180
- "./locales/fr/*.json": "./locales/fr/*.json",
181
- "./locales/en/help/*.json": "./locales/en/help/*.json",
182
- "./locales/fr/help/*.json": "./locales/fr/help/*.json",
174
+ "./api/search/count/*": "./api/search/count/*.js",
175
+ "./api/search/count": "./api/search/count/index.js",
176
+ "./api/search/histogram/*": "./api/search/histogram/*.js",
177
+ "./api/search/histogram": "./api/search/histogram/index.js",
178
+ "./api/search/sigma/*": "./api/search/sigma/*.js",
179
+ "./api/analytic/notebooks/*": "./api/analytic/notebooks/*.js",
180
+ "./api/analytic/notebooks": "./api/analytic/notebooks/index.js",
181
+ "./api/analytic/comments/*": "./api/analytic/comments/*.js",
182
+ "./api/analytic/comments": "./api/analytic/comments/index.js",
183
+ "./plugins/borealis/*": "./plugins/borealis/*.js",
184
+ "./plugins/borealis": "./plugins/borealis/index.js",
185
+ "./plugins/borealis/locales/*": "./plugins/borealis/locales/*.js",
186
+ "./plugins/borealis/components/*": "./plugins/borealis/components/*.js",
183
187
  "./components/app/*": "./components/app/*.js",
184
- "./components/hooks/*": "./components/hooks/*.js",
185
188
  "./components/elements/*": "./components/elements/*.js",
186
189
  "./components/routes/*": "./components/routes/*.js",
187
190
  "./components/logins/*": "./components/logins/*.js",
191
+ "./components/hooks/*": "./components/hooks/*.js",
192
+ "./components/app/providers/*": "./components/app/providers/*.js",
188
193
  "./components/app/hooks/*": "./components/app/hooks/*.js",
189
194
  "./components/app/drawers/*": "./components/app/drawers/*.js",
190
- "./components/app/providers/*": "./components/app/providers/*.js",
191
- "./components/elements/addons/*": "./components/elements/addons/*.js",
192
195
  "./components/elements/display/*": "./components/elements/display/*.js",
193
- "./components/elements/view/*": "./components/elements/view/*.js",
194
196
  "./components/elements/hit/*": "./components/elements/hit/*.js",
195
- "./components/elements/addons/lists/*": "./components/elements/addons/lists/*.js",
196
- "./components/elements/addons/lists": "./components/elements/addons/lists/index.js",
197
+ "./components/elements/view/*": "./components/elements/view/*.js",
198
+ "./components/elements/addons/*": "./components/elements/addons/*.js",
199
+ "./components/elements/display/markdownPlugins/*.md": "./components/elements/display/markdownPlugins/*.md.js",
200
+ "./components/elements/display/modals/*": "./components/elements/display/modals/*.js",
201
+ "./components/elements/display/features/*": "./components/elements/display/features/*.js",
202
+ "./components/elements/display/icons/*": "./components/elements/display/icons/*.js",
203
+ "./components/elements/display/json/*": "./components/elements/display/json/*.js",
204
+ "./components/elements/display/handlebars/*": "./components/elements/display/handlebars/*.js",
205
+ "./components/elements/display/icons/svg/*": "./components/elements/display/icons/svg/*.js",
206
+ "./components/elements/hit/elements/*": "./components/elements/hit/elements/*.js",
207
+ "./components/elements/hit/outlines/*": "./components/elements/hit/outlines/*.js",
208
+ "./components/elements/hit/related/*": "./components/elements/hit/related/*.js",
209
+ "./components/elements/hit/aggregate/*": "./components/elements/hit/aggregate/*.js",
210
+ "./components/elements/hit/actions/*": "./components/elements/hit/actions/*.js",
211
+ "./components/elements/hit/outlines/al/*": "./components/elements/hit/outlines/al/*.js",
197
212
  "./components/elements/addons/buttons/*": "./components/elements/addons/buttons/*.js",
198
213
  "./components/elements/addons/buttons": "./components/elements/addons/buttons/index.js",
199
214
  "./components/elements/addons/layout/*": "./components/elements/addons/layout/*.js",
200
215
  "./components/elements/addons/search/*": "./components/elements/addons/search/*.js",
201
- "./components/elements/addons/lists/hooks/*": "./components/elements/addons/lists/hooks/*.js",
202
- "./components/elements/addons/lists/table/*": "./components/elements/addons/lists/table/*.js",
203
- "./components/elements/addons/lists/table": "./components/elements/addons/lists/table/index.js",
216
+ "./components/elements/addons/lists/*": "./components/elements/addons/lists/*.js",
217
+ "./components/elements/addons/lists": "./components/elements/addons/lists/index.js",
204
218
  "./components/elements/addons/layout/vsbox/*": "./components/elements/addons/layout/vsbox/*.js",
205
219
  "./components/elements/addons/search/phrase/*": "./components/elements/addons/search/phrase/*.js",
206
220
  "./components/elements/addons/search/phrase": "./components/elements/addons/search/phrase/index.js",
207
221
  "./components/elements/addons/search/phrase/word/*": "./components/elements/addons/search/phrase/word/*.js",
208
222
  "./components/elements/addons/search/phrase/word/consumers/*": "./components/elements/addons/search/phrase/word/consumers/*.js",
209
- "./components/elements/display/features/*": "./components/elements/display/features/*.js",
210
- "./components/elements/display/markdownPlugins/*.md": "./components/elements/display/markdownPlugins/*.md.js",
211
- "./components/elements/display/icons/*": "./components/elements/display/icons/*.js",
212
- "./components/elements/display/handlebars/*": "./components/elements/display/handlebars/*.js",
213
- "./components/elements/display/modals/*": "./components/elements/display/modals/*.js",
214
- "./components/elements/display/json/*": "./components/elements/display/json/*.js",
215
- "./components/elements/display/icons/svg/*": "./components/elements/display/icons/svg/*.js",
216
- "./components/elements/hit/related/*": "./components/elements/hit/related/*.js",
217
- "./components/elements/hit/aggregate/*": "./components/elements/hit/aggregate/*.js",
218
- "./components/elements/hit/elements/*": "./components/elements/hit/elements/*.js",
219
- "./components/elements/hit/actions/*": "./components/elements/hit/actions/*.js",
220
- "./components/elements/hit/outlines/*": "./components/elements/hit/outlines/*.js",
221
- "./components/elements/hit/outlines/al/*": "./components/elements/hit/outlines/al/*.js",
222
- "./components/routes/home/*": "./components/routes/home/*.js",
223
- "./components/routes/home": "./components/routes/home/index.js",
223
+ "./components/elements/addons/lists/hooks/*": "./components/elements/addons/lists/hooks/*.js",
224
+ "./components/elements/addons/lists/table/*": "./components/elements/addons/lists/table/*.js",
225
+ "./components/elements/addons/lists/table": "./components/elements/addons/lists/table/index.js",
224
226
  "./components/routes/views/*": "./components/routes/views/*.js",
225
- "./components/routes/hits/*": "./components/routes/hits/*.js",
226
- "./components/routes/advanced/*": "./components/routes/advanced/*.js",
227
- "./components/routes/admin/*": "./components/routes/admin/*.js",
228
227
  "./components/routes/dossiers/*": "./components/routes/dossiers/*.js",
229
- "./components/routes/templates/*": "./components/routes/templates/*.js",
230
228
  "./components/routes/action/*": "./components/routes/action/*.js",
229
+ "./components/routes/admin/*": "./components/routes/admin/*.js",
230
+ "./components/routes/hits/*": "./components/routes/hits/*.js",
231
231
  "./components/routes/settings/*": "./components/routes/settings/*.js",
232
+ "./components/routes/home/*": "./components/routes/home/*.js",
233
+ "./components/routes/home": "./components/routes/home/index.js",
232
234
  "./components/routes/overviews/*": "./components/routes/overviews/*.js",
233
- "./components/routes/help/*": "./components/routes/help/*.js",
235
+ "./components/routes/advanced/*": "./components/routes/advanced/*.js",
234
236
  "./components/routes/analytics/*": "./components/routes/analytics/*.js",
237
+ "./components/routes/templates/*": "./components/routes/templates/*.js",
238
+ "./components/routes/help/*": "./components/routes/help/*.js",
239
+ "./components/routes/action/shared/*": "./components/routes/action/shared/*.js",
240
+ "./components/routes/action/view/*": "./components/routes/action/view/*.js",
241
+ "./components/routes/action/edit/*": "./components/routes/action/edit/*.js",
242
+ "./components/routes/admin/users/*": "./components/routes/admin/users/*.js",
235
243
  "./components/routes/hits/search/*": "./components/routes/hits/search/*.js",
236
244
  "./components/routes/hits/view/*": "./components/routes/hits/view/*.js",
237
- "./components/routes/hits/search/grid/*": "./components/routes/hits/search/grid/*.js",
238
245
  "./components/routes/hits/search/shared/*": "./components/routes/hits/search/shared/*.js",
239
- "./components/routes/admin/users/*": "./components/routes/admin/users/*.js",
240
- "./components/routes/action/edit/*": "./components/routes/action/edit/*.js",
241
- "./components/routes/action/shared/*": "./components/routes/action/shared/*.js",
242
- "./components/routes/action/view/*": "./components/routes/action/view/*.js",
246
+ "./components/routes/hits/search/grid/*": "./components/routes/hits/search/grid/*.js",
247
+ "./components/routes/analytics/widgets/*": "./components/routes/analytics/widgets/*.js",
243
248
  "./components/routes/help/markdown/*.md": "./components/routes/help/markdown/*.md.js",
244
249
  "./components/routes/help/components/*": "./components/routes/help/components/*.js",
245
- "./components/routes/help/markdown/en/*.md": "./components/routes/help/markdown/en/*.md.js",
246
250
  "./components/routes/help/markdown/fr/*.md": "./components/routes/help/markdown/fr/*.md.js",
247
- "./components/routes/analytics/widgets/*": "./components/routes/analytics/widgets/*.js",
248
- "./components/logins/hooks/*": "./components/logins/hooks/*.js",
251
+ "./components/routes/help/markdown/en/*.md": "./components/routes/help/markdown/en/*.md.js",
249
252
  "./components/logins/auth/*": "./components/logins/auth/*.js",
250
- "./models/socket/*": "./models/socket/*.js",
253
+ "./components/logins/hooks/*": "./components/logins/hooks/*.js",
251
254
  "./models/entities/*": "./models/entities/*.js",
252
- "./models/entities/generated/*": "./models/entities/generated/*.js",
253
- "./plugins/borealis/*": "./plugins/borealis/*.js",
254
- "./plugins/borealis": "./plugins/borealis/index.js",
255
- "./plugins/borealis/locales/*": "./plugins/borealis/locales/*.js",
256
- "./plugins/borealis/components/*": "./plugins/borealis/components/*.js"
255
+ "./models/socket/*": "./models/socket/*.js",
256
+ "./models/entities/generated/*": "./models/entities/generated/*.js"
257
257
  }
258
258
  }
@@ -1,7 +1,7 @@
1
1
  import { jsx as _jsx } from "react/jsx-runtime";
2
2
  import { LocalPolice, MoodBad, NewReleases, PsychologyAlt, Star, Timeline } from '@mui/icons-material';
3
3
  import { blue, grey, indigo, orange, pink, red, teal, yellow } from '@mui/material/colors';
4
- import moment from 'moment';
4
+ import dayjs from 'dayjs';
5
5
  export const HOWLER_API = import.meta.env.VITE_API;
6
6
  export const LOCAL = HOWLER_API === 'MOCK';
7
7
  export const VERSION = import.meta.env.VITE_VERSION;
@@ -66,7 +66,7 @@ export var StorageKey;
66
66
  export const MOCK_SEARCH_QUERY_STORE = `${MY_LOCAL_STORAGE_PREFIX}.${StorageKey.MOCK_SEARCH_QUERY_STORE}`;
67
67
  export const MOCK_FAVOURITES_STORE = `${MY_LOCAL_STORAGE_PREFIX}.${StorageKey.MOCK_FAVOURITES_STORE}`;
68
68
  export const VALID_ACTION_TRIGGERS = ['create', 'promote', 'demote'];
69
- const CURRENT_TIME = moment();
69
+ const CURRENT_TIME = dayjs();
70
70
  export const minutes = [CURRENT_TIME.get('minute'), CURRENT_TIME.add(30, 'minute').get('minute')].sort();
71
71
  export const hours = [
72
72
  CURRENT_TIME.get('hour'),
package/utils/utils.js CHANGED
@@ -1,7 +1,7 @@
1
1
  import * as colors from '@mui/material/colors';
2
+ import dayjs from 'dayjs';
2
3
  import { flatten, unflatten } from 'flat';
3
4
  import { isArray, isEmpty, isNil, isObject, isPlainObject } from 'lodash-es';
4
- import moment from 'moment';
5
5
  export const bytesToSize = (bytes) => {
6
6
  const sizes = ['B', 'KB', 'MB', 'GB', 'TB'];
7
7
  if (bytes === 0 || bytes === null)
@@ -39,7 +39,7 @@ export const formatDate = (date) => {
39
39
  if (!date) {
40
40
  return '?';
41
41
  }
42
- return moment(date).utc().format(DATE_FORMAT);
42
+ return dayjs(date).utc().format(DATE_FORMAT);
43
43
  };
44
44
  export const compareTimestamp = (a, b) => {
45
45
  return (new Date(a).getTime() - new Date(b).getTime()) / 1000;
@@ -48,7 +48,7 @@ export const twitterShort = (date) => {
48
48
  if (!date || date === '?') {
49
49
  return '?';
50
50
  }
51
- return moment(date).fromNow();
51
+ return dayjs(date).fromNow();
52
52
  };
53
53
  export const hashCode = (s) => s.split('').reduce((a, b) => ((a << 5) - a + b.charCodeAt(0)) | 0, 0);
54
54
  export const stringToColor = (string) => {