@cccsaurora/howler-ui 2.17.0-dev.526 → 2.17.0-dev.539

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 (143) hide show
  1. package/api/index.d.ts +0 -2
  2. package/api/index.js +2 -4
  3. package/api/search/index.d.ts +1 -2
  4. package/api/search/index.js +1 -2
  5. package/commons/components/leftnav/LeftNavDrawer.js +1 -1
  6. package/components/app/App.js +0 -14
  7. package/components/app/providers/FavouritesProvider.js +2 -2
  8. package/components/elements/PluginTypography.d.ts +1 -2
  9. package/components/elements/PluginTypography.js +2 -3
  10. package/components/elements/UserList.d.ts +2 -5
  11. package/components/elements/UserList.js +5 -14
  12. package/components/elements/addons/search/phrase/Phrase.js +1 -1
  13. package/components/elements/display/HowlerCard.js +1 -1
  14. package/components/elements/display/Modal.js +0 -1
  15. package/components/elements/display/icons/BundleButton.d.ts +6 -0
  16. package/components/elements/display/icons/BundleButton.js +32 -0
  17. package/components/elements/hit/HitBanner.js +48 -27
  18. package/components/elements/{ObjectDetails.d.ts → hit/HitDetails.d.ts} +1 -2
  19. package/components/elements/{ObjectDetails.js → hit/HitDetails.js} +17 -17
  20. package/components/elements/hit/outlines/DefaultOutline.js +1 -1
  21. package/components/elements/view/ViewTitle.js +1 -1
  22. package/components/hooks/useHitActions.d.ts +1 -1
  23. package/components/hooks/useHitActions.js +2 -2
  24. package/components/hooks/useHitSelection.js +35 -1
  25. package/components/hooks/useMyPreferences.js +1 -10
  26. package/components/hooks/useMySitemap.js +1 -4
  27. package/components/hooks/useMyTheme.js +2 -9
  28. package/components/routes/action/view/ActionSearch.js +1 -1
  29. package/components/routes/action/view/Integrations.js +9 -1
  30. package/components/routes/action/view/markdown/integrations.en.md.js +1 -0
  31. package/components/routes/action/view/markdown/integrations.fr.md.js +1 -0
  32. package/components/routes/advanced/QueryBuilder.js +1 -1
  33. package/components/routes/analytics/AnalyticDetails.js +2 -2
  34. package/components/routes/analytics/AnalyticSearch.js +1 -1
  35. package/components/routes/help/ApiDocumentation.js +1 -1
  36. package/components/routes/help/BundleDocumentation.d.ts +3 -0
  37. package/components/routes/help/BundleDocumentation.js +12 -0
  38. package/components/routes/help/HitDocumentation.js +3 -1
  39. package/components/routes/help/markdown/en/bundles.md.js +1 -0
  40. package/components/routes/help/markdown/fr/bundles.md.js +1 -0
  41. package/components/routes/hits/search/BundleParentMenu.d.ts +6 -0
  42. package/components/routes/hits/search/BundleParentMenu.js +32 -0
  43. package/components/routes/hits/search/HitContextMenu.js +27 -4
  44. package/components/routes/hits/search/HitContextMenu.test.js +140 -0
  45. package/components/routes/hits/search/InformationPane.d.ts +0 -1
  46. package/components/routes/hits/search/InformationPane.js +28 -6
  47. package/components/routes/hits/search/SearchPane.js +5 -3
  48. package/components/routes/hits/search/ViewLink.js +1 -1
  49. package/components/routes/hits/search/grid/EnhancedCell.js +1 -1
  50. package/components/routes/hits/search/shared/CustomSpan.js +6 -4
  51. package/components/routes/hits/search/shared/SearchSpan.js +4 -2
  52. package/components/routes/hits/view/HitViewer.js +4 -3
  53. package/components/routes/home/ViewCard.js +1 -1
  54. package/components/{elements/MarkdownEditor.js → routes/overviews/OverviewEditor.js} +3 -3
  55. package/components/routes/overviews/OverviewViewer.js +2 -2
  56. package/locales/en/translation.json +396 -423
  57. package/locales/fr/translation.json +421 -445
  58. package/models/entities/generated/{ThreatEnrichment.d.ts → Enrichment.d.ts} +1 -1
  59. package/models/entities/generated/Howler.d.ts +4 -0
  60. package/models/entities/generated/Rule.d.ts +10 -2
  61. package/models/entities/generated/Threat.d.ts +2 -2
  62. package/package.json +4 -17
  63. package/plugins/clue/components/ClueTypography.js +2 -2
  64. package/plugins/clue/utils.d.ts +1 -2
  65. package/utils/constants.d.ts +3 -3
  66. package/api/search/case.d.ts +0 -4
  67. package/api/search/case.js +0 -8
  68. package/api/v2/case/index.d.ts +0 -6
  69. package/api/v2/case/index.js +0 -18
  70. package/api/v2/index.d.ts +0 -4
  71. package/api/v2/index.js +0 -6
  72. package/api/v2/search/facet.d.ts +0 -3
  73. package/api/v2/search/facet.js +0 -12
  74. package/api/v2/search/index.d.ts +0 -6
  75. package/api/v2/search/index.js +0 -18
  76. package/components/elements/hit/elements/AnalyticLink.d.ts +0 -8
  77. package/components/elements/hit/elements/AnalyticLink.js +0 -22
  78. package/components/routes/cases/CaseCard.d.ts +0 -8
  79. package/components/routes/cases/CaseCard.js +0 -39
  80. package/components/routes/cases/CaseViewer.d.ts +0 -2
  81. package/components/routes/cases/CaseViewer.js +0 -24
  82. package/components/routes/cases/Cases.d.ts +0 -2
  83. package/components/routes/cases/Cases.js +0 -101
  84. package/components/routes/cases/components/StatusIcon.d.ts +0 -5
  85. package/components/routes/cases/components/StatusIcon.js +0 -13
  86. package/components/routes/cases/constants.d.ts +0 -5
  87. package/components/routes/cases/constants.js +0 -5
  88. package/components/routes/cases/detail/AlertPanel.d.ts +0 -6
  89. package/components/routes/cases/detail/AlertPanel.js +0 -32
  90. package/components/routes/cases/detail/CaseDashboard.d.ts +0 -7
  91. package/components/routes/cases/detail/CaseDashboard.js +0 -49
  92. package/components/routes/cases/detail/CaseDetails.d.ts +0 -6
  93. package/components/routes/cases/detail/CaseDetails.js +0 -61
  94. package/components/routes/cases/detail/CaseOverview.d.ts +0 -7
  95. package/components/routes/cases/detail/CaseOverview.js +0 -43
  96. package/components/routes/cases/detail/CaseSidebar.d.ts +0 -6
  97. package/components/routes/cases/detail/CaseSidebar.js +0 -36
  98. package/components/routes/cases/detail/CaseTask.d.ts +0 -11
  99. package/components/routes/cases/detail/CaseTask.js +0 -57
  100. package/components/routes/cases/detail/ItemPage.d.ts +0 -6
  101. package/components/routes/cases/detail/ItemPage.js +0 -93
  102. package/components/routes/cases/detail/RelatedCasePanel.d.ts +0 -6
  103. package/components/routes/cases/detail/RelatedCasePanel.js +0 -31
  104. package/components/routes/cases/detail/TaskPanel.d.ts +0 -7
  105. package/components/routes/cases/detail/TaskPanel.js +0 -52
  106. package/components/routes/cases/detail/aggregates/CaseAggregate.d.ts +0 -12
  107. package/components/routes/cases/detail/aggregates/CaseAggregate.js +0 -19
  108. package/components/routes/cases/detail/aggregates/SourceAggregate.d.ts +0 -6
  109. package/components/routes/cases/detail/aggregates/SourceAggregate.js +0 -27
  110. package/components/routes/cases/detail/sidebar/CaseFolder.d.ts +0 -12
  111. package/components/routes/cases/detail/sidebar/CaseFolder.js +0 -179
  112. package/components/routes/cases/detail/sidebar/types.d.ts +0 -3
  113. package/components/routes/cases/hooks/useCase.d.ts +0 -13
  114. package/components/routes/cases/hooks/useCase.js +0 -38
  115. package/components/routes/cases/modals/ResolveModal.d.ts +0 -7
  116. package/components/routes/cases/modals/ResolveModal.js +0 -59
  117. package/components/routes/observables/ObservableViewer.d.ts +0 -7
  118. package/components/routes/observables/ObservableViewer.js +0 -27
  119. package/models/entities/generated/AttachmentsFile.d.ts +0 -12
  120. package/models/entities/generated/Case.d.ts +0 -28
  121. package/models/entities/generated/DestinationOriginal.d.ts +0 -19
  122. package/models/entities/generated/EmailAttachment.d.ts +0 -8
  123. package/models/entities/generated/EmailParent.d.ts +0 -19
  124. package/models/entities/generated/Enrichments.d.ts +0 -7
  125. package/models/entities/generated/EnrichmentsIndicator.d.ts +0 -21
  126. package/models/entities/generated/HttpResponse.d.ts +0 -11
  127. package/models/entities/generated/Item.d.ts +0 -9
  128. package/models/entities/generated/Observable.d.ts +0 -84
  129. package/models/entities/generated/ObservableCloud.d.ts +0 -20
  130. package/models/entities/generated/ObservableDestination.d.ts +0 -23
  131. package/models/entities/generated/ObservableEmail.d.ts +0 -30
  132. package/models/entities/generated/ObservableFile.d.ts +0 -36
  133. package/models/entities/generated/ObservableHowler.d.ts +0 -44
  134. package/models/entities/generated/ObservableHttp.d.ts +0 -11
  135. package/models/entities/generated/ObservableObserver.d.ts +0 -21
  136. package/models/entities/generated/ObservableOrganization.d.ts +0 -7
  137. package/models/entities/generated/ObservableProcess.d.ts +0 -34
  138. package/models/entities/generated/ObservableSource.d.ts +0 -23
  139. package/models/entities/generated/ObservableThreat.d.ts +0 -21
  140. package/models/entities/generated/ObservableTls.d.ts +0 -12
  141. package/models/entities/generated/ObserverIngress.d.ts +0 -9
  142. package/models/entities/generated/Task.d.ts +0 -10
  143. /package/components/{elements/MarkdownEditor.d.ts → routes/overviews/OverviewEditor.d.ts} +0 -0
@@ -12,11 +12,13 @@ import VSBox from '@cccsaurora/howler-ui/components/elements/addons/layout/vsbox
12
12
  import VSBoxContent from '@cccsaurora/howler-ui/components/elements/addons/layout/vsbox/VSBoxContent';
13
13
  import VSBoxHeader from '@cccsaurora/howler-ui/components/elements/addons/layout/vsbox/VSBoxHeader';
14
14
  import Phrase from '@cccsaurora/howler-ui/components/elements/addons/search/phrase/Phrase';
15
+ import BundleButton from '@cccsaurora/howler-ui/components/elements/display/icons/BundleButton';
15
16
  import SocketBadge from '@cccsaurora/howler-ui/components/elements/display/icons/SocketBadge';
16
17
  import JSONViewer from '@cccsaurora/howler-ui/components/elements/display/json/JSONViewer';
17
18
  import HitActions from '@cccsaurora/howler-ui/components/elements/hit/HitActions';
18
19
  import HitBanner from '@cccsaurora/howler-ui/components/elements/hit/HitBanner';
19
20
  import HitComments from '@cccsaurora/howler-ui/components/elements/hit/HitComments';
21
+ import HitDetails from '@cccsaurora/howler-ui/components/elements/hit/HitDetails';
20
22
  import HitLabels from '@cccsaurora/howler-ui/components/elements/hit/HitLabels';
21
23
  import { HitLayout } from '@cccsaurora/howler-ui/components/elements/hit/HitLayout';
22
24
  import HitNotebooks from '@cccsaurora/howler-ui/components/elements/hit/HitNotebooks';
@@ -27,7 +29,6 @@ import HitSummary from '@cccsaurora/howler-ui/components/elements/hit/HitSummary
27
29
  import HitWorklog from '@cccsaurora/howler-ui/components/elements/hit/HitWorklog';
28
30
  import PivotLink from '@cccsaurora/howler-ui/components/elements/hit/related/PivotLink';
29
31
  import RelatedLink from '@cccsaurora/howler-ui/components/elements/hit/related/RelatedLink';
30
- import ObjectDetails from '@cccsaurora/howler-ui/components/elements/ObjectDetails';
31
32
  import useMyUserList from '@cccsaurora/howler-ui/components/hooks/useMyUserList';
32
33
  import ErrorBoundary from '@cccsaurora/howler-ui/components/routes/ErrorBoundary';
33
34
  import { uniqBy } from 'lodash-es';
@@ -41,13 +42,13 @@ import { getUserList } from '@cccsaurora/howler-ui/utils/hitFunctions';
41
42
  import { validateRegex } from '@cccsaurora/howler-ui/utils/stringUtils';
42
43
  import { tryParse } from '@cccsaurora/howler-ui/utils/utils';
43
44
  import LeadRenderer from '../view/LeadRenderer';
44
- const InformationPane = ({ onClose, selected: _selected }) => {
45
+ const InformationPane = ({ onClose }) => {
45
46
  const { t, i18n } = useTranslation();
46
47
  const theme = useTheme();
47
48
  const location = useLocation();
48
49
  const { emit, isOpen } = useContext(SocketContext);
49
50
  const { getMatchingOverview, getMatchingDossiers, getMatchingAnalytic } = useMatchers();
50
- const selected = useContextSelector(ParameterContext, ctx => ctx?.selected) ?? _selected;
51
+ const selected = useContextSelector(ParameterContext, ctx => ctx.selected);
51
52
  const pluginStore = usePluginStore();
52
53
  const getHit = useContextSelector(HitContext, ctx => ctx.getHit);
53
54
  const [userIds, setUserIds] = useState(new Set());
@@ -96,6 +97,11 @@ const InformationPane = ({ onClose, selected: _selected }) => {
96
97
  useEffect(() => {
97
98
  getMatchingOverview(hit).then(_overview => setHasOverview(!!_overview));
98
99
  }, [getMatchingOverview, hit]);
100
+ useEffect(() => {
101
+ if (tab === 'hit_aggregate' && !hit?.howler.is_bundle) {
102
+ setTab('overview');
103
+ }
104
+ }, [hit?.howler.is_bundle, tab]);
99
105
  useEffect(() => {
100
106
  if (selected && isOpen()) {
101
107
  emit({
@@ -119,13 +125,28 @@ const InformationPane = ({ onClose, selected: _selected }) => {
119
125
  }
120
126
  // eslint-disable-next-line react-hooks/exhaustive-deps
121
127
  }, [hasOverview]);
128
+ /**
129
+ * What to show as the header? If loading a skeleton, then it depends on bundle or not. Bundles don't
130
+ * show anything while normal hits do
131
+ */
132
+ const header = useMemo(() => {
133
+ if (loading && !hit?.howler?.is_bundle) {
134
+ return _jsx(Skeleton, { variant: "rounded", height: 152 });
135
+ }
136
+ else if (!!hit && !hit.howler.is_bundle) {
137
+ return _jsx(HitBanner, { layout: HitLayout.DENSE, hit: hit });
138
+ }
139
+ else {
140
+ return null;
141
+ }
142
+ }, [hit, loading]);
122
143
  const tabContent = useMemo(() => {
123
144
  if (!tab) {
124
145
  return;
125
146
  }
126
147
  return {
127
148
  overview: () => _jsx(HitOverview, { hit: hit }),
128
- details: () => _jsx(ObjectDetails, { obj: hit }),
149
+ details: () => _jsx(HitDetails, { hit: hit }),
129
150
  hit_comments: () => _jsx(HitComments, { hit: hit, users: users }),
130
151
  hit_raw: () => _jsx(JSONViewer, { data: !loading && hit, hideSearch: true, filter: filter }),
131
152
  hit_data: () => (_jsx(JSONViewer, { data: !loading && hit?.howler?.data?.map(entry => tryParse(entry)), collapse: false, hideSearch: true, filter: filter })),
@@ -143,7 +164,8 @@ const InformationPane = ({ onClose, selected: _selected }) => {
143
164
  }[tab]?.();
144
165
  }, [dossiers, filter, hit, loading, tab, users]);
145
166
  const hasError = useMemo(() => !validateRegex(filter), [filter]);
146
- return (_jsxs(VSBox, { top: 10, sx: { height: '100%', flex: 1 }, children: [_jsxs(Stack, { direction: "column", flex: 1, sx: { overflowY: 'auto', flexGrow: 1 }, position: "relative", spacing: 1, ml: 2, children: [_jsxs(Stack, { direction: "row", alignItems: "center", spacing: 0.5, flexShrink: 0, pr: 2, children: [_jsx(FlexOne, {}), onClose && !location.pathname.startsWith('/bundles') && (_jsx(TuiIconButton, { size: "small", onClick: onClose, tooltip: t('hit.panel.details.exit'), children: _jsx(Clear, {}) })), _jsx(SocketBadge, { size: "small" }), analytic && (_jsx(TuiIconButton, { size: "small", tooltip: t('hit.panel.analytic.open'), disabled: !analytic || loading, route: `/analytics/${analytic.analytic_id}`, children: _jsx(QueryStats, {}) })), !!hit && (_jsx(TuiIconButton, { tooltip: t('hit.panel.open'), href: `/hits/${selected}`, disabled: !hit || loading, size: "small", target: "_blank", children: _jsx(OpenInNew, {}) }))] }), _jsx(Box, { pr: 2, children: loading || !hit ? (_jsx(Skeleton, { variant: "rounded", height: 152 })) : (_jsx(HitBanner, { layout: HitLayout.DENSE, hit: hit })) }), !!hit &&
167
+ return (_jsxs(VSBox, { top: 10, sx: { height: '100%', flex: 1 }, children: [_jsxs(Stack, { direction: "column", flex: 1, sx: { overflowY: 'auto', flexGrow: 1 }, position: "relative", spacing: 1, ml: 2, children: [_jsxs(Stack, { direction: "row", alignItems: "center", spacing: 0.5, flexShrink: 0, pr: 2, sx: [hit?.howler?.is_bundle && { position: 'absolute', top: 1, right: 0, zIndex: 1100 }], children: [_jsx(FlexOne, {}), onClose && !location.pathname.startsWith('/bundles') && (_jsx(TuiIconButton, { size: "small", onClick: onClose, tooltip: t('hit.panel.details.exit'), children: _jsx(Clear, {}) })), _jsx(SocketBadge, { size: "small" }), analytic && (_jsx(TuiIconButton, { size: "small", tooltip: t('hit.panel.analytic.open'), disabled: !analytic || loading, route: `/analytics/${analytic.analytic_id}`, children: _jsx(QueryStats, {}) })), hit?.howler.bundles?.length > 0 && _jsx(BundleButton, { ids: hit.howler.bundles, disabled: loading }), !!hit && !hit.howler.is_bundle && (_jsx(TuiIconButton, { tooltip: t('hit.panel.open'), href: `/hits/${selected}`, disabled: !hit || loading, size: "small", target: "_blank", children: _jsx(OpenInNew, {}) }))] }), _jsx(Box, { pr: 2, children: header }), !!hit &&
168
+ !hit.howler.is_bundle &&
147
169
  (!loading ? (_jsxs(_Fragment, { children: [_jsx(HitOutline, { hit: hit, layout: HitLayout.DENSE }), _jsx(HitLabels, { hit: hit })] })) : (_jsx(Skeleton, { height: 124 }))), (hit?.howler?.links?.length > 0 ||
148
170
  analytic?.notebooks?.length > 0 ||
149
171
  dossiers.filter(_dossier => _dossier.pivots?.length > 0).length > 0) && (_jsxs(Stack, { direction: "row", spacing: 1, pr: 2, children: [analytic?.notebooks?.length > 0 && _jsx(HitNotebooks, { analytic: analytic, hit: hit }), hit?.howler?.links?.length > 0 &&
@@ -180,7 +202,7 @@ const InformationPane = ({ onClose, selected: _selected }) => {
180
202
  right: theme.spacing(-0.5)
181
203
  },
182
204
  '& > svg': { zIndex: 2 }
183
- }, badgeContent: hit?.howler.comment?.length ?? 0, children: _jsx(Comment, {}) }) }), value: "hit_comments", onClick: () => setTab('hit_comments') }), hasOverview && (_jsx(Tab, { label: t('hit.viewer.overview'), value: "overview", onClick: () => setTab('overview') })), _jsx(Tab, { label: t('hit.viewer.details'), value: "details", onClick: () => setTab('details') }), hit?.howler.dossier?.map((lead, index) => (_jsx(Tab
205
+ }, badgeContent: hit?.howler.comment?.length ?? 0, children: _jsx(Comment, {}) }) }), value: "hit_comments", onClick: () => setTab('hit_comments') }), hit?.howler?.is_bundle && (_jsx(Tab, { label: t('hit.viewer.aggregate'), value: "hit_aggregate", onClick: () => setTab('hit_aggregate') })), hasOverview && (_jsx(Tab, { label: t('hit.viewer.overview'), value: "overview", onClick: () => setTab('overview') })), _jsx(Tab, { label: t('hit.viewer.details'), value: "details", onClick: () => setTab('details') }), hit?.howler.dossier?.map((lead, index) => (_jsx(Tab
184
206
  // eslint-disable-next-line react/no-array-index-key
185
207
  , { label: _jsxs(Stack, { direction: "row", spacing: 0.5, children: [lead.icon && _jsx(Icon, { icon: lead.icon }), _jsx("span", { children: i18n.language === 'en' ? lead.label.en : lead.label.fr })] }), value: 'lead:' + index, onClick: () => setTab('lead:' + index) }, 'lead:' + index))), dossiers.flatMap((_dossier, dossierIndex) => (_dossier.leads ?? []).map((_lead, leadIndex) => (_jsx(Tab
186
208
  // eslint-disable-next-line react/no-array-index-key
@@ -1,5 +1,5 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- import { ErrorOutline, List, SavedSearch, TableChart, Terminal } from '@mui/icons-material';
2
+ import { Close, ErrorOutline, List, SavedSearch, TableChart, Terminal } from '@mui/icons-material';
3
3
  import { Box, IconButton, LinearProgress, Stack, ToggleButton, ToggleButtonGroup, Tooltip, Typography, useMediaQuery, useTheme } from '@mui/material';
4
4
  import { grey } from '@mui/material/colors';
5
5
  import AppListEmpty from '@cccsaurora/howler-ui/commons/components/display/AppListEmpty';
@@ -23,9 +23,10 @@ import useMyLocalStorage, { useMyLocalStorageItem } from '@cccsaurora/howler-ui/
23
23
  import React, { memo, useCallback, useEffect, useMemo } from 'react';
24
24
  import { isMobile } from 'react-device-detect';
25
25
  import { useTranslation } from 'react-i18next';
26
- import { Link, useLocation, useParams } from 'react-router-dom';
26
+ import { Link, useLocation, useNavigate, useParams } from 'react-router-dom';
27
27
  import { useContextSelector } from 'use-context-selector';
28
28
  import { StorageKey } from '@cccsaurora/howler-ui/utils/constants';
29
+ import BundleParentMenu from './BundleParentMenu';
29
30
  import { BundleScroller } from './BundleScroller';
30
31
  import HitContextMenu from './HitContextMenu';
31
32
  import HitQuery from './HitQuery';
@@ -78,6 +79,7 @@ const Item = memo(({ hit, onClick }) => {
78
79
  const SearchPane = () => {
79
80
  const { t } = useTranslation();
80
81
  const location = useLocation();
82
+ const navigate = useNavigate();
81
83
  const routeParams = useParams();
82
84
  const selected = useContextSelector(ParameterContext, ctx => ctx.selected);
83
85
  const setSelected = useContextSelector(ParameterContext, ctx => ctx.setSelected);
@@ -116,7 +118,7 @@ const SearchPane = () => {
116
118
  ], onClick: () => {
117
119
  clearSelectedHits(bundleHit.howler.id);
118
120
  setSelected(bundleHit.howler.id);
119
- }, children: _jsx(HitBanner, { hit: bundleHit, layout: HitLayout.DENSE, useListener: true }) }) }) }) })), _jsxs(Stack, { direction: "row", spacing: 1, alignItems: "center", children: [_jsx(Typography, { sx: { color: 'text.secondary', fontSize: '0.9em', fontStyle: 'italic', mb: 0.5 }, variant: "body2", children: t('hit.search.prompt') }), error && (_jsx(Tooltip, { title: `${t('route.advanced.error')}: ${error}`, children: _jsx(ErrorOutline, { fontSize: "small", color: "error" }) })), _jsx(FlexOne, {}), _jsx(Tooltip, { title: t('route.views.save'), children: _jsx(IconButton, { component: Link, disabled: !query, to: `/views/create?query=${query}`, children: _jsx(SavedSearch, {}) }) }), _jsx(Tooltip, { title: t('route.actions.save'), children: _jsx(IconButton, { component: Link, disabled: !query, to: `/action/execute?query=${query}`, children: _jsx(Terminal, {}) }) }), _jsxs(ToggleButtonGroup, { exclusive: true, value: displayType, onChange: (__, value) => setDisplayType(value), size: "small", children: [_jsx(ToggleButton, { value: "list", children: _jsx(List, {}) }), _jsx(ToggleButton, { value: "grid", children: _jsx(TableChart, {}) })] })] })] }), _jsxs(VSBoxHeader, { ml: -3, mr: -3, px: 2, pb: 1, sx: { zIndex: 989 }, children: [_jsxs(Stack, { sx: { pt: 1 }, children: [_jsxs(Stack, { sx: { position: 'relative', flex: 1 }, children: [_jsx(HitQuery, { searching: searching, triggerSearch: triggerSearch }), searching && (_jsx(LinearProgress, { sx: theme => ({
121
+ }, children: _jsx(HitBanner, { hit: bundleHit, layout: HitLayout.DENSE, useListener: true }) }) }) }) })), _jsxs(Stack, { direction: "row", spacing: 1, alignItems: "center", children: [_jsx(Typography, { sx: { color: 'text.secondary', fontSize: '0.9em', fontStyle: 'italic', mb: 0.5 }, variant: "body2", children: t('hit.search.prompt') }), error && (_jsx(Tooltip, { title: `${t('route.advanced.error')}: ${error}`, children: _jsx(ErrorOutline, { fontSize: "small", color: "error" }) })), _jsx(FlexOne, {}), bundleHit?.howler.bundles.length > 0 && _jsx(BundleParentMenu, { bundle: bundleHit }), bundleHit && (_jsx(Tooltip, { title: t('hit.bundle.close'), children: _jsx(IconButton, { size: "small", onClick: () => navigate('/search'), children: _jsx(Close, {}) }) })), _jsx(Tooltip, { title: t('route.views.save'), children: _jsx(IconButton, { component: Link, disabled: !query, to: `/views/create?query=${query}`, children: _jsx(SavedSearch, {}) }) }), _jsx(Tooltip, { title: t('route.actions.save'), children: _jsx(IconButton, { component: Link, disabled: !query, to: `/action/execute?query=${query}`, children: _jsx(Terminal, {}) }) }), _jsxs(ToggleButtonGroup, { exclusive: true, value: displayType, onChange: (__, value) => setDisplayType(value), size: "small", children: [_jsx(ToggleButton, { value: "list", children: _jsx(List, {}) }), _jsx(ToggleButton, { value: "grid", children: _jsx(TableChart, {}) })] })] })] }), _jsxs(VSBoxHeader, { ml: -3, mr: -3, px: 2, pb: 1, sx: { zIndex: 989 }, children: [_jsxs(Stack, { sx: { pt: 1 }, children: [_jsxs(Stack, { sx: { position: 'relative', flex: 1 }, children: [_jsx(HitQuery, { searching: searching, triggerSearch: triggerSearch }), searching && (_jsx(LinearProgress, { sx: theme => ({
120
122
  position: 'absolute',
121
123
  left: 0,
122
124
  right: 0,
@@ -47,7 +47,7 @@ const ViewLink = ({ id, viewId }) => {
47
47
  }, [query, sort, span, view]);
48
48
  const options = useMemo(() => Object.values(views).filter(_view => !!_view && !currentViews?.includes(_view.view_id)), [currentViews, views]);
49
49
  if (loading) {
50
- return _jsx(Chip, { icon: _jsx(CircularProgress, { size: 12 }) });
50
+ return _jsx(Chip, { size: "small", icon: _jsx(CircularProgress, { size: 12 }) });
51
51
  }
52
52
  if (viewId === '') {
53
53
  return (_jsx(ChipPopper, { icon: _jsx(SelectAll, {}), label: t('hit.search.view.select'), deleteIcon: _jsx(ArrowDropDown, {}), toggleOnDelete: true, slotProps: { chip: { size: 'small', color: 'warning' } }, children: _jsxs(Stack, { spacing: 1, direction: "row", children: [_jsx(Autocomplete, { fullWidth: true, size: "small", options: options, getOptionLabel: _view => t(_view.title), renderOption: ({ key, ...props }, o) => (_createElement("li", { ...props, key: key },
@@ -13,6 +13,6 @@ const EnhancedCell = ({ hit, value: rawValue, sx = {}, className, field }) => {
13
13
  return (_jsx(TableCell, { sx: { borderBottom: 'none', borderRight: 'thin solid', borderRightColor: 'divider', fontSize: '0.8rem' }, children: _jsx(Stack, { direction: "row", className: className, spacing: 0.5, sx: [
14
14
  { display: 'flex', justifyContent: 'start', width: '100%', overflow: 'hidden' },
15
15
  ...(Array.isArray(sx) ? sx : [sx])
16
- ], children: values.map((value, index) => (_jsx(PluginTypography, { context: "table", sx: { fontSize: 'inherit', textOverflow: 'ellipsis' }, value: value, field: field, obj: hit, children: value }, value + index))) }) }));
16
+ ], children: values.map((value, index) => (_jsx(PluginTypography, { context: "table", sx: { fontSize: 'inherit', textOverflow: 'ellipsis' }, value: value, field: field, hit: hit, children: value }, value + index))) }) }));
17
17
  };
18
18
  export default memo(EnhancedCell);
@@ -11,12 +11,14 @@ 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 ? dayjs(ctx.startDate) : null));
14
+ const defaultStartDate = dayjs().subtract(2, 'days');
15
+ const defaultEndDate = dayjs().subtract(1, 'day');
16
+ const startDate = useContextSelector(ParameterContext, ctx => ctx.startDate ? dayjs(ctx.startDate) : defaultStartDate);
15
17
  const setCustomSpan = useContextSelector(ParameterContext, ctx => ctx.setCustomSpan);
16
- const endDate = useContextSelector(ParameterContext, ctx => (ctx.endDate ? dayjs(ctx.endDate) : null));
18
+ const endDate = useContextSelector(ParameterContext, ctx => (ctx.endDate ? dayjs(ctx.endDate) : defaultEndDate));
17
19
  useEffect(() => {
18
- if (span?.endsWith('custom') && (!startDate || !endDate)) {
19
- setCustomSpan(dayjs().subtract(3, 'days').toISOString(), dayjs().toISOString());
20
+ if (span?.endsWith('custom')) {
21
+ setCustomSpan(startDate.format('YYYY-MM-DD HH:mm'), endDate.format('YYYY-MM-DD HH:mm'));
20
22
  }
21
23
  }, [endDate, setCustomSpan, span, startDate]);
22
24
  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;
@@ -25,8 +25,10 @@ const SearchSpan = ({ omitCustom = false, size }) => {
25
25
  const views = useContextSelector(ParameterContext, ctx => ctx.views);
26
26
  const span = useContextSelector(ParameterContext, ctx => ctx.span);
27
27
  const setSpan = useContextSelector(ParameterContext, ctx => ctx.setSpan);
28
- const startDate = useContextSelector(ParameterContext, ctx => (ctx.startDate ? dayjs(ctx.startDate) : null));
29
- const endDate = useContextSelector(ParameterContext, ctx => (ctx.endDate ? dayjs(ctx.endDate) : null));
28
+ const defaultStartDate = dayjs().subtract(2, 'days');
29
+ const defaultEndDate = dayjs().subtract(1, 'day');
30
+ const startDate = useContextSelector(ParameterContext, ctx => ctx.startDate ? dayjs(ctx.startDate) : defaultStartDate);
31
+ const endDate = useContextSelector(ParameterContext, ctx => (ctx.endDate ? dayjs(ctx.endDate) : defaultEndDate));
30
32
  const getCurrentViews = useContextSelector(ViewContext, ctx => ctx.getCurrentViews);
31
33
  useEffect(() => {
32
34
  if (location.search.includes('span')) {
@@ -7,11 +7,13 @@ import useMatchers from '@cccsaurora/howler-ui/components/app/hooks/useMatchers'
7
7
  import { HitContext } from '@cccsaurora/howler-ui/components/app/providers/HitProvider';
8
8
  import FlexOne from '@cccsaurora/howler-ui/components/elements/addons/layout/FlexOne';
9
9
  import HowlerCard from '@cccsaurora/howler-ui/components/elements/display/HowlerCard';
10
+ import BundleButton from '@cccsaurora/howler-ui/components/elements/display/icons/BundleButton';
10
11
  import SocketBadge from '@cccsaurora/howler-ui/components/elements/display/icons/SocketBadge';
11
12
  import JSONViewer from '@cccsaurora/howler-ui/components/elements/display/json/JSONViewer';
12
13
  import HitActions from '@cccsaurora/howler-ui/components/elements/hit/HitActions';
13
14
  import HitBanner from '@cccsaurora/howler-ui/components/elements/hit/HitBanner';
14
15
  import HitComments from '@cccsaurora/howler-ui/components/elements/hit/HitComments';
16
+ import HitDetails from '@cccsaurora/howler-ui/components/elements/hit/HitDetails';
15
17
  import HitLabels from '@cccsaurora/howler-ui/components/elements/hit/HitLabels';
16
18
  import { HitLayout } from '@cccsaurora/howler-ui/components/elements/hit/HitLayout';
17
19
  import HitNotebooks from '@cccsaurora/howler-ui/components/elements/hit/HitNotebooks';
@@ -21,7 +23,6 @@ import HitRelated from '@cccsaurora/howler-ui/components/elements/hit/HitRelated
21
23
  import HitWorklog from '@cccsaurora/howler-ui/components/elements/hit/HitWorklog';
22
24
  import PivotLink from '@cccsaurora/howler-ui/components/elements/hit/related/PivotLink';
23
25
  import RelatedLink from '@cccsaurora/howler-ui/components/elements/hit/related/RelatedLink';
24
- import ObjectDetails from '@cccsaurora/howler-ui/components/elements/ObjectDetails';
25
26
  import { useMyLocalStorageItem } from '@cccsaurora/howler-ui/components/hooks/useMyLocalStorage';
26
27
  import useMyUserList from '@cccsaurora/howler-ui/components/hooks/useMyUserList';
27
28
  import uniqBy from 'lodash-es/uniqBy';
@@ -96,7 +97,7 @@ const HitViewer = () => {
96
97
  }
97
98
  return {
98
99
  overview: () => _jsx(HitOverview, { hit: hit }),
99
- details: () => _jsx(ObjectDetails, { obj: hit }),
100
+ details: () => _jsx(HitDetails, { hit: hit }),
100
101
  hit_comments: () => _jsx(HitComments, { hit: hit, users: users }),
101
102
  hit_raw: () => _jsx(JSONViewer, { data: hit }),
102
103
  hit_data: () => _jsx(JSONViewer, { data: hit?.howler?.data?.map(entry => tryParse(entry)), collapse: false }),
@@ -141,7 +142,7 @@ const HitViewer = () => {
141
142
  position: 'absolute',
142
143
  top: theme.spacing(2),
143
144
  right: theme.spacing(-6)
144
- }, children: [_jsx(Tooltip, { title: t('page.hits.view.layout'), children: _jsx(IconButton, { onClick: onOrientationChange, children: _jsx(ViewAgenda, { sx: { transition: 'rotate 250ms', rotate: orientation === 'vertical' ? '90deg' : '0deg' } }) }) }), _jsx(SocketBadge, { size: "medium" }), analytic && (_jsx(Tooltip, { title: t('hit.panel.analytic.open'), children: _jsx(IconButton, { onClick: () => navigate(`/analytics/${analytic.analytic_id}`), children: _jsx(QueryStats, {}) }) }))] }))] }), _jsx(HowlerCard, { sx: [orientation === 'horizontal' && { height: '0px' }], children: _jsx(CardContent, { sx: { padding: 1, position: 'relative' }, children: _jsx(HitActions, { hit: hit, orientation: "vertical" }) }) }), _jsx(Box, { sx: { gridColumn: '1 / span 2', mb: 1 }, children: _jsxs(Tabs, { value: tab === 'overview' && !hasOverview ? 'details' : tab, sx: { display: 'flex', flexDirection: 'row', pr: 2, alignItems: 'center' }, children: [hasOverview && (_jsx(Tab, { label: t('hit.viewer.overview'), value: "overview", onClick: () => setTab('overview') })), _jsx(Tab, { label: t('hit.viewer.details'), value: "details", onClick: () => setTab('details') }), hit?.howler.dossier?.map((lead, index) => (_jsx(Tab
145
+ }, children: [_jsx(Tooltip, { title: t('page.hits.view.layout'), children: _jsx(IconButton, { onClick: onOrientationChange, children: _jsx(ViewAgenda, { sx: { transition: 'rotate 250ms', rotate: orientation === 'vertical' ? '90deg' : '0deg' } }) }) }), _jsx(SocketBadge, { size: "medium" }), analytic && (_jsx(Tooltip, { title: t('hit.panel.analytic.open'), children: _jsx(IconButton, { onClick: () => navigate(`/analytics/${analytic.analytic_id}`), children: _jsx(QueryStats, {}) }) })), hit?.howler.bundles?.length > 0 && _jsx(BundleButton, { ids: hit.howler.bundles })] }))] }), _jsx(HowlerCard, { sx: [orientation === 'horizontal' && { height: '0px' }], children: _jsx(CardContent, { sx: { padding: 1, position: 'relative' }, children: _jsx(HitActions, { hit: hit, orientation: "vertical" }) }) }), _jsx(Box, { sx: { gridColumn: '1 / span 2', mb: 1 }, children: _jsxs(Tabs, { value: tab === 'overview' && !hasOverview ? 'details' : tab, sx: { display: 'flex', flexDirection: 'row', pr: 2, alignItems: 'center' }, children: [hit?.howler?.is_bundle && (_jsx(Tab, { label: t('hit.viewer.aggregate'), value: "hit_aggregate", onClick: () => setTab('hit_aggregate') })), hasOverview && (_jsx(Tab, { label: t('hit.viewer.overview'), value: "overview", onClick: () => setTab('overview') })), _jsx(Tab, { label: t('hit.viewer.details'), value: "details", onClick: () => setTab('details') }), hit?.howler.dossier?.map((lead, index) => (_jsx(Tab
145
146
  // eslint-disable-next-line react/no-array-index-key
146
147
  , { label: _jsxs(Stack, { direction: "row", spacing: 0.5, children: [lead.icon && _jsx(Icon, { icon: lead.icon }), _jsx("span", { children: i18n.language === 'en' ? lead.label.en : lead.label.fr })] }), value: 'lead:' + index, onClick: () => setTab('lead:' + index) }, 'lead:' + index))), dossiers.flatMap((_dossier, dossierIndex) => (_dossier.leads ?? []).map((_lead, leadIndex) => (_jsx(Tab
147
148
  // eslint-disable-next-line react/no-array-index-key
@@ -39,6 +39,6 @@ const ViewCard = ({ viewId, limit }) => {
39
39
  });
40
40
  }, [dispatchApi, limit, view?.query]);
41
41
  const onClick = useCallback((query) => navigate('/hits?query=' + query), [navigate]);
42
- return (_jsx(Card, { variant: "outlined", sx: { height: '100%' }, children: _jsxs(Stack, { spacing: 1, sx: { p: 1, minHeight: 100 }, children: [_jsxs(Stack, { direction: "row", spacing: 1, alignItems: "center", children: [_jsx(Typography, { variant: "h6", children: t(view?.title) || _jsx(Skeleton, { variant: "text", height: "2em", width: "100px" }) }), _jsx(IconButton, { size: "small", onClick: () => onClick(view.query), children: _jsx(OpenInNew, { fontSize: "small" }) })] }), loading ? (_jsxs(_Fragment, { children: [_jsx(Skeleton, { height: 150, width: "100%", variant: "rounded" }), _jsx(Skeleton, { height: 160, width: "100%", variant: "rounded" }), _jsx(Skeleton, { height: 140, width: "100%", variant: "rounded" })] })) : hits.length > 0 ? (hits.map(h => (_jsx(Card, { variant: "outlined", sx: { cursor: 'pointer' }, onClick: () => navigate(`/hits/${h.howler.id}`), children: _jsx(CardContent, { children: _jsx(HitBanner, { layout: HitLayout.DENSE, hit: h }) }) }, h.howler.id)))) : (_jsx(AppListEmpty, {}))] }) }));
42
+ return (_jsx(Card, { variant: "outlined", sx: { height: '100%' }, children: _jsxs(Stack, { spacing: 1, sx: { p: 1, minHeight: 100 }, children: [_jsxs(Stack, { direction: "row", spacing: 1, alignItems: "center", children: [_jsx(Typography, { variant: "h6", children: t(view?.title) || _jsx(Skeleton, { variant: "text", height: "2em", width: "100px" }) }), _jsx(IconButton, { size: "small", onClick: () => onClick(view.query), children: _jsx(OpenInNew, { fontSize: "small" }) })] }), loading ? (_jsxs(_Fragment, { children: [_jsx(Skeleton, { height: 150, width: "100%", variant: "rounded" }), _jsx(Skeleton, { height: 160, width: "100%", variant: "rounded" }), _jsx(Skeleton, { height: 140, width: "100%", variant: "rounded" })] })) : hits.length > 0 ? (hits.map(h => (_jsx(Card, { variant: "outlined", sx: { cursor: 'pointer' }, onClick: () => navigate((h.howler.is_bundle ? '/bundles/' : '/hits/') + h.howler.id), children: _jsx(CardContent, { children: _jsx(HitBanner, { layout: HitLayout.DENSE, hit: h }) }) }, h.howler.id)))) : (_jsx(AppListEmpty, {}))] }) }));
43
43
  };
44
44
  export default ViewCard;
@@ -4,8 +4,8 @@ import { useTheme } from '@mui/material';
4
4
  import { ApiConfigContext } from '@cccsaurora/howler-ui/components/app/providers/ApiConfigProvider';
5
5
  import ThemedEditor from '@cccsaurora/howler-ui/components/elements/ThemedEditor';
6
6
  import { memo, useCallback, useContext, useEffect, useMemo } from 'react';
7
- import { conf, language } from '../routes/overviews/markdownExtendedTokenProvider';
8
- const MarkdownEditor = ({ content, setContent, onMount, fontSize = 16, height = '100%', width = '100%', editorOptions = {} }) => {
7
+ import { conf, language } from './markdownExtendedTokenProvider';
8
+ const OverviewEditor = ({ content, setContent, onMount, fontSize = 16, height = '100%', width = '100%', editorOptions = {} }) => {
9
9
  const theme = useTheme();
10
10
  const monaco = useMonaco();
11
11
  const { config } = useContext(ApiConfigContext);
@@ -53,4 +53,4 @@ const MarkdownEditor = ({ content, setContent, onMount, fontSize = 16, height =
53
53
  }), [fontSize, editorOptions]);
54
54
  return (_jsx(ThemedEditor, { height: height, width: width, theme: theme.palette.mode === 'light' ? 'howler' : 'howler-dark', value: content, onChange: value => setContent(value), beforeMount: beforeEditorMount, onMount: onMount, options: options }));
55
55
  };
56
- export default memo(MarkdownEditor);
56
+ export default memo(OverviewEditor);
@@ -15,7 +15,7 @@ import useMyTheme from '@cccsaurora/howler-ui/components/hooks/useMyTheme';
15
15
  import { useSearchParams } from 'react-router-dom';
16
16
  import hitsData from '@cccsaurora/howler-ui/utils/hit.json';
17
17
  import { sanitizeLuceneQuery } from '@cccsaurora/howler-ui/utils/stringUtils';
18
- import MarkdownEditor from '../../elements/MarkdownEditor';
18
+ import OverviewEditor from './OverviewEditor';
19
19
  import { useStartingTemplate } from './startingTemplate';
20
20
  const OverviewViewer = () => {
21
21
  const theme = useTheme();
@@ -188,7 +188,7 @@ const OverviewViewer = () => {
188
188
  right: `calc(50% + 7px - ${x}px)`,
189
189
  mr: -2.4,
190
190
  pr: 1.5
191
- }, children: _jsx(MarkdownEditor, { height: "100%", content: content, setContent: setContent }) }) }), _jsx(Box, { sx: {
191
+ }, children: _jsx(OverviewEditor, { height: "100%", content: content, setContent: setContent }) }) }), _jsx(Box, { sx: {
192
192
  position: 'absolute',
193
193
  top: 0,
194
194
  bottom: 0,