@cccsaurora/howler-ui 2.18.0-dev.700 → 2.18.0-dev.704

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 (246) 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 +7 -34
  7. package/components/app/hooks/useMatchers.js +2 -2
  8. package/components/app/hooks/useMatchers.test.js +22 -22
  9. package/components/app/hooks/useTitle.js +3 -3
  10. package/components/app/providers/FavouritesProvider.js +2 -2
  11. package/components/app/providers/HitProvider.d.ts +22 -0
  12. package/components/app/providers/{RecordProvider.js → HitProvider.js} +41 -41
  13. package/components/app/providers/{RecordSearchProvider.d.ts → HitSearchProvider.d.ts} +6 -6
  14. package/components/app/providers/{RecordSearchProvider.js → HitSearchProvider.js} +17 -12
  15. package/components/app/providers/{RecordSearchProvider.test.js → HitSearchProvider.test.js} +70 -51
  16. package/components/app/providers/ModalProvider.d.ts +0 -1
  17. package/components/app/providers/ParameterProvider.d.ts +2 -9
  18. package/components/app/providers/ParameterProvider.js +240 -165
  19. package/components/app/providers/ParameterProvider.test.js +14 -307
  20. package/components/elements/PluginTypography.d.ts +1 -2
  21. package/components/elements/PluginTypography.js +2 -3
  22. package/components/elements/UserList.d.ts +2 -5
  23. package/components/elements/UserList.js +5 -14
  24. package/components/elements/addons/search/phrase/Phrase.js +1 -1
  25. package/components/elements/display/ChipPopper.d.ts +1 -1
  26. package/components/elements/display/HowlerCard.js +1 -1
  27. package/components/elements/display/Modal.js +0 -2
  28. package/components/elements/display/icons/BundleButton.d.ts +6 -0
  29. package/components/elements/display/icons/BundleButton.js +32 -0
  30. package/components/elements/hit/HitActions.js +4 -4
  31. package/components/elements/hit/HitBanner.js +48 -28
  32. package/components/elements/hit/HitCard.js +5 -5
  33. package/components/elements/{record/RecordComments.d.ts → hit/HitComments.d.ts} +4 -5
  34. package/components/elements/{record/RecordComments.js → hit/HitComments.js} +28 -29
  35. package/components/elements/{ObjectDetails.js → hit/HitDetails.js} +17 -17
  36. package/components/elements/hit/HitLabels.js +2 -2
  37. package/components/elements/hit/{HitPreview.d.ts → HitQuickSearch.d.ts} +3 -3
  38. package/components/elements/hit/{HitPreview.js → HitQuickSearch.js} +4 -10
  39. package/components/elements/hit/HitRelated.d.ts +6 -0
  40. package/components/elements/hit/HitRelated.js +7 -0
  41. package/components/elements/hit/HitSummary.d.ts +1 -2
  42. package/components/elements/hit/HitSummary.js +5 -6
  43. package/components/elements/{record/RecordWorklog.d.ts → hit/HitWorklog.d.ts} +3 -4
  44. package/components/elements/{record/RecordWorklog.js → hit/HitWorklog.js} +13 -15
  45. package/components/elements/hit/aggregate/HitGraph.js +8 -8
  46. package/components/elements/hit/outlines/DefaultOutline.js +1 -1
  47. package/components/elements/view/ViewTitle.d.ts +0 -1
  48. package/components/elements/view/ViewTitle.js +2 -9
  49. package/components/hooks/useHitActions.d.ts +1 -1
  50. package/components/hooks/useHitActions.js +4 -4
  51. package/components/hooks/{useRecordSelection.d.ts → useHitSelection.d.ts} +2 -2
  52. package/components/hooks/{useRecordSelection.js → useHitSelection.js} +33 -12
  53. package/components/hooks/useMyPreferences.js +1 -10
  54. package/components/hooks/useMySearch.js +2 -2
  55. package/components/hooks/useMySitemap.js +1 -4
  56. package/components/hooks/useMyTheme.js +2 -9
  57. package/components/hooks/useParamState.test.js +4 -3
  58. package/components/routes/action/edit/ActionEditor.js +2 -2
  59. package/components/routes/action/view/ActionSearch.js +1 -1
  60. package/components/routes/advanced/QueryBuilder.js +1 -1
  61. package/components/routes/advanced/QueryEditor.js +3 -3
  62. package/components/routes/advanced/historyCompletionProvider.js +3 -3
  63. package/components/routes/analytics/AnalyticDetails.js +2 -2
  64. package/components/routes/analytics/AnalyticSearch.js +1 -1
  65. package/components/routes/dossiers/DossierEditor.js +2 -2
  66. package/components/routes/dossiers/DossierEditor.test.js +1 -1
  67. package/components/routes/help/ApiDocumentation.js +1 -1
  68. package/components/routes/help/BundleDocumentation.d.ts +3 -0
  69. package/components/routes/help/BundleDocumentation.js +12 -0
  70. package/components/routes/help/HitBannerDocumentation.js +0 -1
  71. package/components/routes/help/HitDocumentation.js +3 -1
  72. package/components/routes/help/markdown/en/bundles.md.js +1 -0
  73. package/components/routes/help/markdown/fr/bundles.md.js +1 -0
  74. package/components/routes/hits/search/BundleParentMenu.d.ts +6 -0
  75. package/components/routes/hits/search/BundleParentMenu.js +32 -0
  76. package/components/routes/hits/search/BundleScroller.d.ts +2 -0
  77. package/components/routes/hits/search/BundleScroller.js +6 -0
  78. package/components/routes/hits/search/{RecordBrowser.js → HitBrowser.js} +9 -9
  79. package/components/{elements/record/RecordContextMenu.d.ts → routes/hits/search/HitContextMenu.d.ts} +3 -3
  80. package/components/routes/hits/search/HitContextMenu.js +227 -0
  81. package/components/{elements/record/RecordContextMenu.test.js → routes/hits/search/HitContextMenu.test.js} +39 -94
  82. package/components/routes/hits/search/{RecordQuery.d.ts → HitQuery.d.ts} +2 -2
  83. package/components/routes/hits/search/{RecordQuery.js → HitQuery.js} +6 -6
  84. package/components/routes/hits/search/InformationPane.d.ts +0 -1
  85. package/components/routes/hits/search/InformationPane.js +60 -47
  86. package/components/routes/hits/search/LayoutSettings.js +3 -3
  87. package/components/routes/hits/search/QuerySettings.js +1 -2
  88. package/components/routes/hits/search/QuerySettings.test.js +9 -14
  89. package/components/routes/hits/search/SearchPane.js +49 -26
  90. package/components/routes/hits/search/ViewLink.js +3 -3
  91. package/components/routes/hits/search/ViewLink.test.js +8 -8
  92. package/components/routes/hits/search/grid/AddColumnModal.js +4 -5
  93. package/components/routes/hits/search/grid/EnhancedCell.d.ts +1 -2
  94. package/components/routes/hits/search/grid/EnhancedCell.js +2 -2
  95. package/components/routes/hits/search/grid/HitGrid.js +18 -20
  96. package/components/routes/hits/search/grid/{RecordRow.d.ts → HitRow.d.ts} +2 -3
  97. package/components/routes/hits/search/grid/{RecordRow.js → HitRow.js} +8 -10
  98. package/components/routes/hits/view/HitViewer.js +13 -12
  99. package/components/routes/home/ViewCard.js +41 -47
  100. package/components/{elements/MarkdownEditor.js → routes/overviews/OverviewEditor.js} +3 -3
  101. package/components/routes/overviews/OverviewViewer.js +2 -2
  102. package/components/routes/views/ViewComposer.js +19 -46
  103. package/locales/en/translation.json +3 -80
  104. package/locales/fr/translation.json +3 -78
  105. package/models/WithMetadata.d.ts +1 -2
  106. package/models/entities/generated/{ThreatEnrichment.d.ts → Enrichment.d.ts} +1 -1
  107. package/models/entities/generated/Hit.d.ts +0 -1
  108. package/models/entities/generated/Howler.d.ts +4 -0
  109. package/models/entities/generated/Rule.d.ts +10 -2
  110. package/models/entities/generated/Threat.d.ts +2 -2
  111. package/models/entities/generated/View.d.ts +0 -1
  112. package/package.json +106 -123
  113. package/plugins/clue/components/ClueTypography.js +2 -2
  114. package/plugins/clue/helpers.js +1 -1
  115. package/plugins/clue/utils.d.ts +1 -2
  116. package/tests/server-handlers.js +1 -6
  117. package/tests/utils.d.ts +0 -4
  118. package/tests/utils.js +0 -20
  119. package/utils/constants.d.ts +3 -3
  120. package/utils/hitFunctions.d.ts +1 -2
  121. package/utils/hitFunctions.js +4 -4
  122. package/utils/viewUtils.js +0 -3
  123. package/api/search/case.d.ts +0 -4
  124. package/api/search/case.js +0 -8
  125. package/api/v2/case/index.d.ts +0 -8
  126. package/api/v2/case/index.js +0 -20
  127. package/api/v2/case/items.d.ts +0 -6
  128. package/api/v2/case/items.js +0 -18
  129. package/api/v2/index.d.ts +0 -4
  130. package/api/v2/index.js +0 -6
  131. package/api/v2/search/facet.d.ts +0 -3
  132. package/api/v2/search/facet.js +0 -12
  133. package/api/v2/search/index.d.ts +0 -5
  134. package/api/v2/search/index.js +0 -24
  135. package/components/app/providers/RecordProvider.d.ts +0 -23
  136. package/components/elements/ContextMenu.d.ts +0 -56
  137. package/components/elements/ContextMenu.js +0 -109
  138. package/components/elements/ContextMenu.test.js +0 -215
  139. package/components/elements/ObjectDetails.d.ts +0 -6
  140. package/components/elements/case/CaseCard.d.ts +0 -12
  141. package/components/elements/case/CaseCard.js +0 -42
  142. package/components/elements/case/CasePreview.d.ts +0 -6
  143. package/components/elements/case/CasePreview.js +0 -17
  144. package/components/elements/case/StatusIcon.d.ts +0 -5
  145. package/components/elements/case/StatusIcon.js +0 -13
  146. package/components/elements/hit/elements/AnalyticLink.d.ts +0 -8
  147. package/components/elements/hit/elements/AnalyticLink.js +0 -22
  148. package/components/elements/hit/related/RelatedRecords.js +0 -63
  149. package/components/elements/observable/ObservableCard.d.ts +0 -6
  150. package/components/elements/observable/ObservableCard.js +0 -23
  151. package/components/elements/observable/ObservablePreview.d.ts +0 -6
  152. package/components/elements/observable/ObservablePreview.js +0 -12
  153. package/components/elements/record/RecordContextMenu.js +0 -247
  154. package/components/elements/record/RecordContextMenu.test.d.ts +0 -1
  155. package/components/elements/record/RecordRelated.d.ts +0 -7
  156. package/components/elements/record/RecordRelated.js +0 -34
  157. package/components/hooks/useRelatedRecords.d.ts +0 -13
  158. package/components/hooks/useRelatedRecords.js +0 -32
  159. package/components/routes/cases/CaseViewer.d.ts +0 -2
  160. package/components/routes/cases/CaseViewer.js +0 -22
  161. package/components/routes/cases/Cases.d.ts +0 -2
  162. package/components/routes/cases/Cases.js +0 -101
  163. package/components/routes/cases/constants.d.ts +0 -5
  164. package/components/routes/cases/constants.js +0 -5
  165. package/components/routes/cases/detail/AlertPanel.d.ts +0 -6
  166. package/components/routes/cases/detail/AlertPanel.js +0 -33
  167. package/components/routes/cases/detail/CaseAssets.d.ts +0 -12
  168. package/components/routes/cases/detail/CaseAssets.js +0 -104
  169. package/components/routes/cases/detail/CaseAssets.test.d.ts +0 -1
  170. package/components/routes/cases/detail/CaseAssets.test.js +0 -167
  171. package/components/routes/cases/detail/CaseDashboard.d.ts +0 -7
  172. package/components/routes/cases/detail/CaseDashboard.js +0 -54
  173. package/components/routes/cases/detail/CaseDetails.d.ts +0 -6
  174. package/components/routes/cases/detail/CaseDetails.js +0 -61
  175. package/components/routes/cases/detail/CaseOverview.d.ts +0 -7
  176. package/components/routes/cases/detail/CaseOverview.js +0 -43
  177. package/components/routes/cases/detail/CaseSidebar.d.ts +0 -8
  178. package/components/routes/cases/detail/CaseSidebar.js +0 -61
  179. package/components/routes/cases/detail/CaseTask.d.ts +0 -11
  180. package/components/routes/cases/detail/CaseTask.js +0 -57
  181. package/components/routes/cases/detail/ItemPage.d.ts +0 -6
  182. package/components/routes/cases/detail/ItemPage.js +0 -99
  183. package/components/routes/cases/detail/RelatedCasePanel.d.ts +0 -6
  184. package/components/routes/cases/detail/RelatedCasePanel.js +0 -31
  185. package/components/routes/cases/detail/TaskPanel.d.ts +0 -7
  186. package/components/routes/cases/detail/TaskPanel.js +0 -52
  187. package/components/routes/cases/detail/aggregates/CaseAggregate.d.ts +0 -12
  188. package/components/routes/cases/detail/aggregates/CaseAggregate.js +0 -19
  189. package/components/routes/cases/detail/aggregates/SourceAggregate.d.ts +0 -6
  190. package/components/routes/cases/detail/aggregates/SourceAggregate.js +0 -30
  191. package/components/routes/cases/detail/assets/Asset.d.ts +0 -14
  192. package/components/routes/cases/detail/assets/Asset.js +0 -12
  193. package/components/routes/cases/detail/assets/Asset.test.d.ts +0 -1
  194. package/components/routes/cases/detail/assets/Asset.test.js +0 -72
  195. package/components/routes/cases/detail/sidebar/CaseFolder.d.ts +0 -14
  196. package/components/routes/cases/detail/sidebar/CaseFolder.js +0 -133
  197. package/components/routes/cases/detail/sidebar/CaseFolderContextMenu.d.ts +0 -34
  198. package/components/routes/cases/detail/sidebar/CaseFolderContextMenu.js +0 -105
  199. package/components/routes/cases/detail/sidebar/CaseFolderContextMenu.test.d.ts +0 -1
  200. package/components/routes/cases/detail/sidebar/CaseFolderContextMenu.test.js +0 -351
  201. package/components/routes/cases/detail/sidebar/types.d.ts +0 -3
  202. package/components/routes/cases/detail/sidebar/utils.d.ts +0 -3
  203. package/components/routes/cases/detail/sidebar/utils.js +0 -25
  204. package/components/routes/cases/hooks/useCase.d.ts +0 -13
  205. package/components/routes/cases/hooks/useCase.js +0 -51
  206. package/components/routes/cases/modals/AddToCaseModal.d.ts +0 -7
  207. package/components/routes/cases/modals/AddToCaseModal.js +0 -62
  208. package/components/routes/cases/modals/RenameItemModal.d.ts +0 -9
  209. package/components/routes/cases/modals/RenameItemModal.js +0 -48
  210. package/components/routes/cases/modals/ResolveModal.d.ts +0 -7
  211. package/components/routes/cases/modals/ResolveModal.js +0 -62
  212. package/components/routes/hits/search/shared/IndexPicker.d.ts +0 -2
  213. package/components/routes/hits/search/shared/IndexPicker.js +0 -20
  214. package/components/routes/observables/ObservableViewer.d.ts +0 -7
  215. package/components/routes/observables/ObservableViewer.js +0 -27
  216. package/models/entities/generated/AttachmentsFile.d.ts +0 -12
  217. package/models/entities/generated/Case.d.ts +0 -28
  218. package/models/entities/generated/DestinationOriginal.d.ts +0 -19
  219. package/models/entities/generated/EmailAttachment.d.ts +0 -8
  220. package/models/entities/generated/EmailParent.d.ts +0 -19
  221. package/models/entities/generated/Enrichments.d.ts +0 -7
  222. package/models/entities/generated/EnrichmentsIndicator.d.ts +0 -21
  223. package/models/entities/generated/HttpResponse.d.ts +0 -11
  224. package/models/entities/generated/Item.d.ts +0 -9
  225. package/models/entities/generated/Observable.d.ts +0 -85
  226. package/models/entities/generated/ObservableCloud.d.ts +0 -20
  227. package/models/entities/generated/ObservableDestination.d.ts +0 -23
  228. package/models/entities/generated/ObservableEmail.d.ts +0 -30
  229. package/models/entities/generated/ObservableFile.d.ts +0 -36
  230. package/models/entities/generated/ObservableHowler.d.ts +0 -43
  231. package/models/entities/generated/ObservableHttp.d.ts +0 -11
  232. package/models/entities/generated/ObservableObserver.d.ts +0 -21
  233. package/models/entities/generated/ObservableOrganization.d.ts +0 -7
  234. package/models/entities/generated/ObservableProcess.d.ts +0 -34
  235. package/models/entities/generated/ObservableSource.d.ts +0 -23
  236. package/models/entities/generated/ObservableThreat.d.ts +0 -21
  237. package/models/entities/generated/ObservableTls.d.ts +0 -12
  238. package/models/entities/generated/ObserverIngress.d.ts +0 -9
  239. package/models/entities/generated/Task.d.ts +0 -10
  240. package/utils/typeUtils.d.ts +0 -7
  241. package/utils/typeUtils.js +0 -27
  242. /package/components/app/providers/{RecordSearchProvider.test.d.ts → HitSearchProvider.test.d.ts} +0 -0
  243. /package/components/elements/hit/{related/RelatedRecords.d.ts → HitDetails.d.ts} +0 -0
  244. /package/components/routes/hits/search/{RecordBrowser.d.ts → HitBrowser.d.ts} +0 -0
  245. /package/components/{elements/ContextMenu.test.d.ts → routes/hits/search/HitContextMenu.test.d.ts} +0 -0
  246. /package/components/{elements/MarkdownEditor.d.ts → routes/overviews/OverviewEditor.d.ts} +0 -0
package/api/v2/index.d.ts DELETED
@@ -1,4 +0,0 @@
1
- import * as case_ from '@cccsaurora/howler-ui/api/v2/case';
2
- import * as search from '@cccsaurora/howler-ui/api/v2/search';
3
- export declare const uri: () => string;
4
- export { case_ as case, search };
package/api/v2/index.js DELETED
@@ -1,6 +0,0 @@
1
- import * as case_ from '@cccsaurora/howler-ui/api/v2/case';
2
- import * as search from '@cccsaurora/howler-ui/api/v2/search';
3
- export const uri = () => {
4
- return '/api/v2';
5
- };
6
- export { case_ as case, search };
@@ -1,3 +0,0 @@
1
- import type { HowlerFacetSearchRequest, HowlerFacetSearchResponse } from '@cccsaurora/howler-ui/api/search/facet';
2
- export declare const uri: (indexes: string[]) => string;
3
- export declare const post: (indexes: string | string[], request?: HowlerFacetSearchRequest) => Promise<HowlerFacetSearchResponse>;
@@ -1,12 +0,0 @@
1
- // eslint-disable-next-line import/no-cycle
2
- import { hpost, joinAllUri } from '@cccsaurora/howler-ui/api';
3
- import { uri as parentUri } from '@cccsaurora/howler-ui/api/v2';
4
- export const uri = (indexes) => {
5
- return joinAllUri(parentUri(), 'search', 'facet', indexes.join(','));
6
- };
7
- export const post = (indexes, request) => {
8
- if (typeof indexes === 'string') {
9
- indexes = indexes.split(',');
10
- }
11
- return hpost(uri(indexes), { ...(request || {}), query: request?.query || 'howler.id:*' });
12
- };
@@ -1,5 +0,0 @@
1
- import type { HowlerSearchRequest, HowlerSearchResponse } from '@cccsaurora/howler-ui/api/search';
2
- import * as facet from './facet';
3
- export declare const uri: (indexes: string[]) => string;
4
- export declare const post: <T = any>(indexes: string | string[], request?: HowlerSearchRequest) => Promise<HowlerSearchResponse<T>>;
5
- export { facet };
@@ -1,24 +0,0 @@
1
- // eslint-disable-next-line import/no-cycle
2
- import { hpost, joinAllUri } from '@cccsaurora/howler-ui/api';
3
- import { uri as parentUri } from '@cccsaurora/howler-ui/api/v2';
4
- import { identity, isNil } from 'lodash-es';
5
- import * as facet from './facet';
6
- export const uri = (indexes) => {
7
- return joinAllUri(parentUri(), 'search', indexes.join(','));
8
- };
9
- export const post = (indexes, request) => {
10
- if (isNil(indexes)) {
11
- throw new Error('Indexes cannot be null or undefined.');
12
- }
13
- if (typeof indexes === 'string') {
14
- indexes = indexes.split(',').filter(identity);
15
- }
16
- if (indexes.some(index => !['hit', 'observable', 'case'].includes(index))) {
17
- throw new Error('Only hit, case, and observable indexes should be used currently.');
18
- }
19
- if (indexes.length < 1) {
20
- throw new Error('indexes must have length of at least 1.');
21
- }
22
- return hpost(uri(indexes), { ...(request || {}), query: request?.query || 'howler.id:*' });
23
- };
24
- export { facet };
@@ -1,23 +0,0 @@
1
- import type { Hit } from '@cccsaurora/howler-ui/models/entities/generated/Hit';
2
- import type { Observable } from '@cccsaurora/howler-ui/models/entities/generated/Observable';
3
- import type { WithMetadata } from '@cccsaurora/howler-ui/models/WithMetadata';
4
- import type { FC, PropsWithChildren } from 'react';
5
- export interface RecordContextType {
6
- records: {
7
- [index: string]: Hit | Observable;
8
- };
9
- selectedRecords: (Hit | Observable)[];
10
- addRecordToSelection: (id: string) => void;
11
- removeRecordFromSelection: (id: string) => void;
12
- clearSelectedRecords: (except?: string) => void;
13
- loadRecords: (hits: (Hit | Observable)[]) => void;
14
- updateRecord: (newHit: Hit | Observable) => void;
15
- getRecord: (id: string, force?: boolean) => Promise<WithMetadata<Hit | Observable>>;
16
- }
17
- export declare const RecordContext: import("use-context-selector").Context<RecordContextType>;
18
- /**
19
- * Central repository for storing individual hit data across the application. Allows efficient retrieval of hits across componenents.
20
- */
21
- declare const RecordProvider: FC<PropsWithChildren>;
22
- export declare const useHitContextSelector: <Selected>(selector: (value: RecordContextType) => Selected) => Selected;
23
- export default RecordProvider;
@@ -1,56 +0,0 @@
1
- import { type SxProps } from '@mui/material';
2
- import type { ElementType, FC, MouseEventHandler, PropsWithChildren, ReactNode } from 'react';
3
- export type ContextMenuDivider = {
4
- kind: 'divider';
5
- id: string;
6
- sx?: SxProps;
7
- };
8
- export type ContextMenuLeafItem = {
9
- kind: 'item';
10
- id: string;
11
- icon?: ReactNode;
12
- label: ReactNode;
13
- disabled?: boolean;
14
- onClick?: () => void;
15
- /** When provided the item renders as a router Link instead of a button. */
16
- to?: string;
17
- };
18
- export type ContextMenuSubItem = {
19
- key: string;
20
- label: ReactNode;
21
- disabled?: boolean;
22
- onClick?: () => void;
23
- };
24
- export type ContextMenuSubmenuItem = {
25
- kind: 'submenu';
26
- /**
27
- * Identifier for this submenu. Used to derive:
28
- * - the MenuItem's DOM id (`${id}-menu-item`)
29
- * - the submenu Paper's DOM id (`${id}-submenu`)
30
- */
31
- id: string;
32
- icon?: ReactNode;
33
- label: ReactNode;
34
- disabled?: boolean;
35
- items: ContextMenuSubItem[];
36
- };
37
- export type ContextMenuEntry = ContextMenuDivider | ContextMenuLeafItem | ContextMenuSubmenuItem;
38
- interface ContextMenuProps {
39
- items: ContextMenuEntry[];
40
- /** Called after the menu opens, with the triggering event. */
41
- onOpen?: MouseEventHandler<HTMLElement>;
42
- /** Called when the menu closes. */
43
- onClose?: () => void;
44
- /** Wraps children + menu in this element. Defaults to Box. */
45
- Component?: ElementType;
46
- /** id applied to the wrapper element */
47
- id?: string;
48
- }
49
- /**
50
- * Generic context menu component that renders a MUI Menu from a declarative
51
- * items structure supporting leaf items, dividers, and single-level submenus.
52
- *
53
- * Submenus appear on hover and are positioned to avoid screen overflow.
54
- */
55
- declare const ContextMenu: FC<PropsWithChildren<ContextMenuProps>>;
56
- export default ContextMenu;
@@ -1,109 +0,0 @@
1
- import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- import { KeyboardArrowRight } from '@mui/icons-material';
3
- import { Box, Divider, Fade, ListItemIcon, ListItemText, Menu, MenuItem, MenuList, Paper, useTheme } from '@mui/material';
4
- import { useCallback, useEffect, useState } from 'react';
5
- import { Link } from 'react-router-dom';
6
- /**
7
- * The margin at the bottom of the screen by which a submenu should be inverted.
8
- * If hovering within this many pixels of the bottom, the submenu renders upward.
9
- */
10
- const CONTEXTMENU_MARGIN = 350;
11
- /**
12
- * Generic context menu component that renders a MUI Menu from a declarative
13
- * items structure supporting leaf items, dividers, and single-level submenus.
14
- *
15
- * Submenus appear on hover and are positioned to avoid screen overflow.
16
- */
17
- const ContextMenu = ({ items, onOpen, onClose, Component = Box, id, children }) => {
18
- const theme = useTheme();
19
- const [show, setShow] = useState({});
20
- const [anchorEl, setAnchorEl] = useState(null);
21
- const [transformProps, setTransformProps] = useState({});
22
- const handleClose = useCallback(() => {
23
- setAnchorEl(null);
24
- onClose?.();
25
- }, [onClose]);
26
- const handleContextMenu = useCallback(event => {
27
- if (anchorEl) {
28
- event.preventDefault();
29
- handleClose();
30
- return;
31
- }
32
- event.preventDefault();
33
- if (window.innerHeight - event.clientY < 300) {
34
- setTransformProps({
35
- position: 'fixed',
36
- bottom: `${window.innerHeight - event.clientY}px !important`,
37
- top: 'unset !important',
38
- left: `${event.clientX}px !important`
39
- });
40
- }
41
- else {
42
- setTransformProps({
43
- position: 'fixed',
44
- top: `${event.clientY}px !important`,
45
- left: `${event.clientX}px !important`
46
- });
47
- }
48
- setAnchorEl(event.target);
49
- onOpen?.(event);
50
- }, [anchorEl, handleClose, onOpen]);
51
- /**
52
- * Calculates positioning styles for a submenu based on the parent element's
53
- * position relative to the viewport bottom.
54
- */
55
- const calculateSubMenuStyles = useCallback((parent) => {
56
- const baseStyles = { position: 'absolute', maxHeight: '300px', overflow: 'auto' };
57
- const defaultStyles = { ...baseStyles, top: 0, left: '100%' };
58
- if (!parent) {
59
- return defaultStyles;
60
- }
61
- const parentBounds = parent.getBoundingClientRect();
62
- if (window.innerHeight - parentBounds.y < CONTEXTMENU_MARGIN) {
63
- return { ...baseStyles, bottom: 0, left: '100%' };
64
- }
65
- return defaultStyles;
66
- }, []);
67
- // Reset submenu visibility whenever the menu is closed
68
- useEffect(() => {
69
- if (!anchorEl) {
70
- setShow({});
71
- }
72
- }, [anchorEl]);
73
- return (_jsxs(Component, { id: id, onContextMenu: handleContextMenu, children: [children, _jsx(Menu, { id: "record-menu", open: !!anchorEl, anchorEl: anchorEl, onClose: handleClose, slotProps: {
74
- paper: {
75
- sx: {
76
- ...transformProps,
77
- overflow: 'visible !important'
78
- },
79
- elevation: 2
80
- }
81
- }, MenuListProps: {
82
- dense: true,
83
- sx: {
84
- minWidth: '250px',
85
- paddingY: '0 !important',
86
- '& > :first-child': {
87
- borderTopLeftRadius: theme.shape.borderRadius,
88
- borderTopRightRadius: theme.shape.borderRadius
89
- },
90
- '& > :last-child': {
91
- borderBottomLeftRadius: theme.shape.borderRadius,
92
- borderBottomRightRadius: theme.shape.borderRadius
93
- }
94
- }
95
- }, anchorOrigin: { vertical: 'top', horizontal: 'left' }, onClick: handleClose, children: items.map(entry => {
96
- if (entry.kind === 'divider') {
97
- return _jsx(Divider, { sx: { my: '0 !important' } }, entry.id);
98
- }
99
- if (entry.kind === 'item') {
100
- if (entry.to) {
101
- return (_jsxs(MenuItem, { component: Link, to: entry.to, disabled: entry.disabled, children: [entry.icon && _jsx(ListItemIcon, { children: entry.icon }), _jsx(ListItemText, { children: entry.label })] }, entry.id));
102
- }
103
- return (_jsxs(MenuItem, { disabled: entry.disabled, onClick: entry.onClick, children: [entry.icon && _jsx(ListItemIcon, { children: entry.icon }), _jsx(ListItemText, { children: entry.label })] }, entry.id));
104
- }
105
- const { id: entryId, icon, label, disabled, items: subItems } = entry;
106
- return (_jsxs(MenuItem, { id: `${entryId}-menu-item`, sx: { position: 'relative' }, onMouseEnter: ev => setShow(_show => ({ ..._show, [entryId]: ev.target })), onMouseLeave: () => setShow(_show => ({ ..._show, [entryId]: null })), disabled: disabled, children: [icon && _jsx(ListItemIcon, { children: icon }), _jsx(ListItemText, { sx: { flex: 1 }, children: label }), !disabled && _jsx(KeyboardArrowRight, { fontSize: "small", sx: { color: 'text.secondary', mr: -1 } }), _jsx(Fade, { in: !!show[entryId], unmountOnExit: true, children: _jsx(Paper, { id: `${entryId}-submenu`, sx: calculateSubMenuStyles(show[entryId]), elevation: 2, children: _jsx(MenuList, { sx: { p: 0, borderTopLeftRadius: 0 }, dense: true, role: "group", children: subItems.map(subItem => (_jsx(MenuItem, { onClick: subItem.onClick, disabled: subItem.disabled, children: _jsx(ListItemText, { children: subItem.label }) }, subItem.key))) }) }) })] }, entryId));
107
- }) })] }));
108
- };
109
- export default ContextMenu;
@@ -1,215 +0,0 @@
1
- import { jsx as _jsx, Fragment as _Fragment } from "react/jsx-runtime";
2
- import { fireEvent, render, screen, waitFor } from '@testing-library/react';
3
- import { omit } from 'lodash-es';
4
- import { act } from 'react';
5
- import { vi } from 'vitest';
6
- // Mock react-router-dom Link
7
- vi.mock('react-router-dom', () => ({
8
- Link: ({ to, children, ...props }) => (_jsx("a", { href: to, ...props, children: children }))
9
- }));
10
- // Stub MUI components to simple HTML equivalents
11
- vi.mock('@mui/material', async () => {
12
- const actual = await vi.importActual('@mui/material');
13
- return {
14
- ...actual,
15
- useTheme: () => ({ shape: { borderRadius: 4 } }),
16
- Menu: ({ children, open, onClose, ...props }) => open ? (_jsx("div", { role: "menu", onClick: onClose, ...omit(props, ['sx', 'slotProps', 'MenuListProps', 'anchorOrigin', 'anchorEl']), children: children })) : null,
17
- MenuItem: ({ children, onClick, disabled, component, to, id, onMouseEnter, onMouseLeave, ...props }) => {
18
- const Component = component || 'div';
19
- return (_jsx(Component, { role: "menuitem", onClick: onClick, "aria-disabled": disabled, href: to, id: id, onMouseEnter: onMouseEnter, onMouseLeave: onMouseLeave, ...omit(props, ['sx']), children: children }));
20
- },
21
- Fade: ({ children, in: inProp }) => (inProp ? _jsx(_Fragment, { children: children }) : null),
22
- ListItemIcon: ({ children }) => _jsx("div", { children: children }),
23
- ListItemText: ({ children }) => _jsx("div", { children: children }),
24
- Divider: () => _jsx("hr", {}),
25
- Paper: ({ children, id, ...props }) => (_jsx("div", { id: id, ...omit(props, ['sx', 'elevation']), children: children })),
26
- MenuList: ({ children, ...props }) => (_jsx("div", { role: "group", ...omit(props, ['sx', 'dense']), children: children })),
27
- Box: ({ children, id, onContextMenu, ...props }) => (_jsx("div", { id: id, onContextMenu: onContextMenu, ...omit(props, ['sx']), children: children }))
28
- };
29
- });
30
- import ContextMenu, {} from './ContextMenu';
31
- const renderMenu = (items, opts = {}) => {
32
- const { autoOpen = true, onOpen = vi.fn(), onClose = vi.fn() } = opts;
33
- const utils = render(_jsx(ContextMenu, { items: items, onOpen: onOpen, onClose: onClose, id: "test-menu", children: _jsx("div", { id: "trigger", children: "trigger" }) }));
34
- const openMenu = () => act(() => {
35
- fireEvent.contextMenu(screen.getByTestId('trigger'));
36
- });
37
- if (autoOpen) {
38
- openMenu();
39
- }
40
- return { ...utils, onOpen, onClose, openMenu };
41
- };
42
- describe('ContextMenu', () => {
43
- describe('Visibility', () => {
44
- it('renders nothing before right-click', () => {
45
- const { container } = renderMenu([], { autoOpen: false });
46
- expect(container.querySelector('[role="menu"]')).toBeNull();
47
- });
48
- it('renders the menu after right-click', () => {
49
- renderMenu([]);
50
- expect(screen.getByRole('menu')).toBeInTheDocument();
51
- });
52
- it('calls onClose when the menu is clicked', () => {
53
- const { onClose } = renderMenu([]);
54
- fireEvent.click(screen.getByRole('menu'));
55
- expect(onClose).toHaveBeenCalledTimes(1);
56
- });
57
- it('closes on a second right-click (toggle)', () => {
58
- const { openMenu } = renderMenu([]);
59
- expect(screen.getByRole('menu')).toBeInTheDocument();
60
- openMenu();
61
- expect(screen.queryByRole('menu')).not.toBeInTheDocument();
62
- });
63
- it('calls onOpen when right-clicked', () => {
64
- const onOpen = vi.fn();
65
- renderMenu([], { onOpen });
66
- expect(onOpen).toHaveBeenCalledTimes(1);
67
- });
68
- it('calls onClose when closed via toggle right-click', () => {
69
- const onClose = vi.fn();
70
- const { openMenu } = renderMenu([], { onClose });
71
- openMenu();
72
- expect(onClose).toHaveBeenCalledTimes(1);
73
- });
74
- });
75
- describe('Leaf items', () => {
76
- it('renders a plain button item', () => {
77
- const onClick = vi.fn();
78
- renderMenu([{ kind: 'item', id: 'action-1', label: 'Do something', onClick }]);
79
- const item = screen.getByRole('menuitem');
80
- expect(item).toHaveTextContent('Do something');
81
- });
82
- it('calls onClick when a plain item is clicked', () => {
83
- const onClick = vi.fn();
84
- renderMenu([{ kind: 'item', id: 'action-1', label: 'Do something', onClick }]);
85
- fireEvent.click(screen.getByRole('menuitem'));
86
- expect(onClick).toHaveBeenCalledTimes(1);
87
- });
88
- it('renders a link item with correct href', () => {
89
- renderMenu([{ kind: 'item', id: 'link-1', label: 'Go somewhere', to: '/some/path' }]);
90
- const link = screen.getByRole('menuitem');
91
- expect(link).toHaveAttribute('href', '/some/path');
92
- });
93
- it('marks a disabled item with aria-disabled', () => {
94
- renderMenu([{ kind: 'item', id: 'action-1', label: 'Disabled', disabled: true }]);
95
- expect(screen.getByRole('menuitem')).toHaveAttribute('aria-disabled', 'true');
96
- });
97
- it('renders an icon alongside the label when provided', () => {
98
- renderMenu([{ kind: 'item', id: 'icon-item', label: 'With icon', icon: _jsx("span", { id: "test-icon" }) }]);
99
- expect(screen.getByTestId('test-icon')).toBeInTheDocument();
100
- expect(screen.getByRole('menuitem')).toHaveTextContent('With icon');
101
- });
102
- });
103
- describe('Dividers', () => {
104
- it('renders a divider between items', () => {
105
- renderMenu([
106
- { kind: 'item', id: 'item-a', label: 'A' },
107
- { kind: 'divider', id: 'sep' },
108
- { kind: 'item', id: 'item-b', label: 'B' }
109
- ]);
110
- expect(screen.getByRole('separator')).toBeInTheDocument();
111
- expect(screen.getAllByRole('menuitem')).toHaveLength(2);
112
- });
113
- });
114
- describe('Submenu items', () => {
115
- const subItems = [
116
- { key: 'sub-a', label: 'Sub A', onClick: vi.fn() },
117
- { key: 'sub-b', label: 'Sub B', onClick: vi.fn() }
118
- ];
119
- const submenuEntry = {
120
- kind: 'submenu',
121
- id: 'my-submenu',
122
- label: 'Parent',
123
- items: subItems
124
- };
125
- it('renders the parent submenu item', () => {
126
- renderMenu([submenuEntry]);
127
- expect(screen.getByText('Parent')).toBeInTheDocument();
128
- });
129
- it('does not show submenu content before hovering', () => {
130
- renderMenu([submenuEntry]);
131
- expect(screen.queryByText('Sub A')).not.toBeInTheDocument();
132
- });
133
- it('shows submenu content on mouse enter', async () => {
134
- renderMenu([submenuEntry]);
135
- const parent = screen.getByRole('menuitem');
136
- act(() => {
137
- fireEvent.mouseEnter(parent);
138
- });
139
- await waitFor(() => {
140
- expect(screen.getByText('Sub A')).toBeInTheDocument();
141
- expect(screen.getByText('Sub B')).toBeInTheDocument();
142
- });
143
- });
144
- it('hides submenu after mouse leave', async () => {
145
- renderMenu([submenuEntry]);
146
- const parent = screen.getByRole('menuitem');
147
- act(() => {
148
- fireEvent.mouseEnter(parent);
149
- });
150
- await waitFor(() => {
151
- expect(screen.getByText('Sub A')).toBeInTheDocument();
152
- });
153
- act(() => {
154
- fireEvent.mouseLeave(parent);
155
- });
156
- await waitFor(() => {
157
- expect(screen.queryByText('Sub A')).not.toBeInTheDocument();
158
- });
159
- });
160
- it('calls the sub-item onClick when a sub-item is clicked', async () => {
161
- const onClick = vi.fn();
162
- renderMenu([
163
- {
164
- kind: 'submenu',
165
- id: 'actions',
166
- label: 'Actions',
167
- items: [{ key: 'do-it', label: 'Do it', onClick }]
168
- }
169
- ]);
170
- const parent = screen.getByRole('menuitem');
171
- act(() => {
172
- fireEvent.mouseEnter(parent);
173
- });
174
- await waitFor(() => {
175
- expect(screen.getByText('Do it')).toBeInTheDocument();
176
- });
177
- fireEvent.click(screen.getByText('Do it'));
178
- expect(onClick).toHaveBeenCalledTimes(1);
179
- });
180
- it('marks a disabled submenu parent with aria-disabled', () => {
181
- renderMenu([{ ...submenuEntry, disabled: true }]);
182
- expect(screen.getByRole('menuitem')).toHaveAttribute('aria-disabled', 'true');
183
- });
184
- it('does not show expand arrow when submenu is disabled', () => {
185
- renderMenu([{ ...submenuEntry, disabled: true }]);
186
- // The KeyboardArrowRight icon only renders when !disabled
187
- expect(screen.queryByTestId('KeyboardArrowRightIcon')).not.toBeInTheDocument();
188
- });
189
- it('assigns correct DOM ids to submenu parent and panel', async () => {
190
- renderMenu([submenuEntry]);
191
- expect(document.getElementById('my-submenu-menu-item')).not.toBeNull();
192
- const parent = screen.getByRole('menuitem');
193
- act(() => {
194
- fireEvent.mouseEnter(parent);
195
- });
196
- await waitFor(() => {
197
- expect(document.getElementById('my-submenu-submenu')).not.toBeNull();
198
- });
199
- });
200
- });
201
- describe('Mixed item list', () => {
202
- it('renders items in order', () => {
203
- renderMenu([
204
- { kind: 'item', id: 'first', label: 'First' },
205
- { kind: 'divider', id: 'div-1' },
206
- { kind: 'submenu', id: 'third', label: 'Third', items: [] },
207
- { kind: 'item', id: 'fourth', label: 'Fourth' }
208
- ]);
209
- const items = screen.getAllByRole('menuitem');
210
- expect(items[0]).toHaveTextContent('First');
211
- expect(items[1]).toHaveTextContent('Third');
212
- expect(items[2]).toHaveTextContent('Fourth');
213
- });
214
- });
215
- });
@@ -1,6 +0,0 @@
1
- import type { Hit } from '@cccsaurora/howler-ui/models/entities/generated/Hit';
2
- import type { Observable } from '@cccsaurora/howler-ui/models/entities/generated/Observable';
3
- declare const _default: import("react").NamedExoticComponent<{
4
- obj: Hit | Observable;
5
- }>;
6
- export default _default;
@@ -1,12 +0,0 @@
1
- import { type CardProps } from '@mui/material';
2
- import type { Case } from '@cccsaurora/howler-ui/models/entities/generated/Case';
3
- import { type FC } from 'react';
4
- declare const CaseCard: FC<{
5
- case?: Case;
6
- caseId?: string;
7
- className?: string;
8
- slotProps?: {
9
- card?: CardProps;
10
- };
11
- }>;
12
- export default CaseCard;
@@ -1,42 +0,0 @@
1
- import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
- import { CheckCircleOutline, HourglassBottom, RadioButtonUnchecked, UpdateOutlined } from '@mui/icons-material';
3
- import { Card, Chip, Divider, Grid, Skeleton, Stack, Tooltip, Typography, useTheme } from '@mui/material';
4
- import api from '@cccsaurora/howler-ui/api';
5
- import StatusIcon from '@cccsaurora/howler-ui/components/elements/case/StatusIcon';
6
- import HowlerAvatar from '@cccsaurora/howler-ui/components/elements/display/HowlerAvatar';
7
- import PluginChip from '@cccsaurora/howler-ui/components/elements/PluginChip';
8
- import useMyApi from '@cccsaurora/howler-ui/components/hooks/useMyApi';
9
- import dayjs from 'dayjs';
10
- import { countBy } from 'lodash-es';
11
- import { useEffect, useState } from 'react';
12
- import { useTranslation } from 'react-i18next';
13
- import { twitterShort } from '@cccsaurora/howler-ui/utils/utils';
14
- const STATUS_COLORS = {
15
- resolved: 'success'
16
- };
17
- const CaseCard = ({ case: providedCase, caseId, className, slotProps }) => {
18
- const { t } = useTranslation();
19
- const { dispatchApi } = useMyApi();
20
- const theme = useTheme();
21
- const [_case, setCase] = useState(providedCase);
22
- useEffect(() => {
23
- if (providedCase) {
24
- setCase(providedCase);
25
- }
26
- }, [providedCase]);
27
- useEffect(() => {
28
- if (caseId) {
29
- dispatchApi(api.v2.case.get(caseId), { throwError: false }).then(setCase);
30
- }
31
- }, [caseId, dispatchApi]);
32
- if (!_case) {
33
- return _jsx(Skeleton, { variant: "rounded", height: 250, sx: { mb: 1 }, className: className });
34
- }
35
- return (_jsx(Card, { variant: "outlined", ...slotProps?.card, sx: [
36
- { p: 1, mb: 1, borderColor: theme.palette[STATUS_COLORS[_case.status]]?.main },
37
- ...(Array.isArray(slotProps?.card?.sx) ? slotProps.card.sx : slotProps?.card?.sx ? [slotProps.card.sx] : [])
38
- ], className: className, children: _jsx(Stack, { direction: "row", alignItems: "start", spacing: 1, children: _jsxs(Stack, { sx: { flex: 1 }, spacing: 1, children: [_jsxs(Stack, { direction: "row", spacing: 1, alignItems: "center", children: [_jsx(Typography, { variant: "h6", display: "flex", alignItems: "start", children: _case.title }), _jsx(StatusIcon, { status: _case.status }), _jsx("div", { style: { flex: 1 } }), _case.start && _case.end && (_jsx(Tooltip, { title: dayjs(_case.updated).toString(), children: _jsx(Chip, { icon: _jsx(HourglassBottom, { fontSize: "small" }), size: "small", label: twitterShort(_case.start) + ' - ' + twitterShort(_case.end) }) })), _jsx(Tooltip, { title: dayjs(_case.updated).toString(), children: _jsx(Chip, { icon: _jsx(UpdateOutlined, { fontSize: "small" }), size: "small", label: twitterShort(_case.updated) }) })] }), _jsx(Typography, { variant: "caption", color: "textSecondary", children: _case.summary.trim().split('\n')[0] }), _case.participants?.length > 0 && (_jsxs(_Fragment, { children: [_jsx(Divider, { flexItem: true }), _jsx(Stack, { direction: "row", spacing: 1, children: _case.participants?.map(participant => (_jsx(HowlerAvatar, { sx: { height: '20px', width: '20px' }, userId: participant }, participant))) })] })), _jsx(Divider, { flexItem: true }), _jsxs(Grid, { container: true, spacing: 1, children: [_case.targets?.map(indicator => (_jsx(Grid, { item: true, children: _jsx(PluginChip, { size: "small", color: "primary", context: "casecard", variant: "outlined", value: indicator, label: indicator }) }, indicator))), _case.targets?.length > 0 && (_case.indicators?.length > 0 || _case.threats?.length > 0) && (_jsx(Grid, { item: true, children: _jsx(Divider, { orientation: "vertical" }) })), _case.indicators?.map(indicator => (_jsx(Grid, { item: true, children: _jsx(PluginChip, { variant: "outlined", context: "casecard", value: indicator, label: indicator }) }, indicator))), _case.indicators?.length > 0 && _case.threats?.length > 0 && (_jsx(Grid, { item: true, children: _jsx(Divider, { orientation: "vertical" }) })), _case.threats?.map(indicator => (_jsx(Grid, { item: true, children: _jsx(PluginChip, { size: "small", color: "warning", variant: "outlined", context: "casecard", value: indicator, label: indicator }) }, indicator)))] }), _case.tasks?.length > 0 && (_jsxs(_Fragment, { children: [_jsx(Divider, { flexItem: true }), _jsxs(Stack, { spacing: 0.5, alignItems: "start", children: [_case.tasks.some(task => task.complete) && (_jsx(Chip, { size: "small", color: "success", icon: _jsx(CheckCircleOutline, {}), label: `${countBy(_case.tasks, task => task.complete).true} ${t('complete')}` })), _case.tasks
39
- .filter(task => !task.complete)
40
- .map(task => (_jsx(Chip, { icon: _jsx(RadioButtonUnchecked, {}), label: task.summary }, task.id)))] })] }))] }) }) }, _case.case_id));
41
- };
42
- export default CaseCard;
@@ -1,6 +0,0 @@
1
- import type { Case } from '@cccsaurora/howler-ui/models/entities/generated/Case';
2
- type PreviewProps = {
3
- case: Case;
4
- };
5
- declare const _default: import("react").NamedExoticComponent<PreviewProps>;
6
- export default _default;
@@ -1,17 +0,0 @@
1
- import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- import { CheckCircleOutline, HourglassBottom, RadioButtonUnchecked, UpdateOutlined } from '@mui/icons-material';
3
- import { Chip, Stack, Tooltip, Typography, useTheme } from '@mui/material';
4
- import dayjs from 'dayjs';
5
- import { countBy } from 'lodash-es';
6
- import { memo } from 'react';
7
- import { useTranslation } from 'react-i18next';
8
- import { twitterShort } from '@cccsaurora/howler-ui/utils/utils';
9
- import HowlerAvatar from '../display/HowlerAvatar';
10
- import StatusIcon from './StatusIcon';
11
- const CasePreview = ({ case: _case }) => {
12
- const { t } = useTranslation();
13
- const theme = useTheme();
14
- const taskCounts = countBy(_case.tasks, task => task.complete);
15
- return (_jsxs(Stack, { flex: 1, spacing: 1, sx: { overflow: 'hidden', borderBottom: `thin solid ${theme.palette.divider}`, pb: 1, mb: 0 }, children: [_jsxs(Stack, { direction: "row", spacing: 1, children: [_jsxs(Stack, { spacing: 1, children: [_jsx(Typography, { variant: "body1", fontWeight: "bold", children: _case.title }), _jsx(Typography, { variant: "caption", color: "textSecondary", children: _case.summary.trim().split('\n')[0] })] }), _jsx(StatusIcon, { status: _case.status }), _jsx("div", { style: { flex: 1 } }), _jsxs(Stack, { spacing: 1, alignItems: "end", children: [_case.start && _case.end && (_jsx(Tooltip, { title: dayjs(_case.updated).toString(), children: _jsx(Chip, { icon: _jsx(HourglassBottom, { fontSize: "small" }), size: "small", label: twitterShort(_case.start) + ' - ' + twitterShort(_case.end) }) })), _jsx(Tooltip, { title: dayjs(_case.updated).toString(), children: _jsx(Chip, { icon: _jsx(UpdateOutlined, { fontSize: "small" }), size: "small", label: twitterShort(_case.updated) }) })] })] }), _jsxs(Stack, { direction: "row", spacing: 1, children: [_case.participants?.length > 0 && (_jsx(Stack, { direction: "row", spacing: 1, children: _case.participants?.map(participant => (_jsx(HowlerAvatar, { sx: { height: '24px', width: '24px' }, userId: participant }, participant))) })), _jsx(Chip, { color: "success", icon: _jsx(CheckCircleOutline, {}), label: `${taskCounts.true ?? 0} ${t('complete')}` }), _jsx(Chip, { icon: _jsx(RadioButtonUnchecked, {}), label: `${taskCounts.false ?? 0} ${t('incomplete')}` })] })] }));
16
- };
17
- export default memo(CasePreview);
@@ -1,5 +0,0 @@
1
- import type { FC } from 'react';
2
- declare const StatusIcon: FC<{
3
- status: string;
4
- }>;
5
- export default StatusIcon;
@@ -1,13 +0,0 @@
1
- import { jsx as _jsx } from "react/jsx-runtime";
2
- import { Check, HourglassBottom, Pause, Troubleshoot } from '@mui/icons-material';
3
- import { Tooltip } from '@mui/material';
4
- import { useTranslation } from 'react-i18next';
5
- const StatusIcon = ({ status }) => {
6
- const { t } = useTranslation();
7
- return (_jsx(Tooltip, { title: t(`page.cases.status.${status}`), children: {
8
- 'in-progress': _jsx(HourglassBottom, { color: "warning" }),
9
- 'on-hold': _jsx(Pause, { color: "disabled" }),
10
- resolved: _jsx(Check, { color: "success" })
11
- }[status] ?? _jsx(Troubleshoot, { color: "primary" }) }));
12
- };
13
- export default StatusIcon;
@@ -1,8 +0,0 @@
1
- import type { Hit } from '@cccsaurora/howler-ui/models/entities/generated/Hit';
2
- import { type FC } from 'react';
3
- declare const AnalyticLink: FC<{
4
- hit: Hit;
5
- compressed?: boolean;
6
- alignSelf?: string;
7
- }>;
8
- export default AnalyticLink;
@@ -1,22 +0,0 @@
1
- import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- import { Typography } from '@mui/material';
3
- import useMatchers from '@cccsaurora/howler-ui/components/app/hooks/useMatchers';
4
- import { useEffect, useState } from 'react';
5
- import { Link } from 'react-router-dom';
6
- const AnalyticLink = ({ hit, compressed, alignSelf = 'start' }) => {
7
- const { getMatchingAnalytic } = useMatchers();
8
- const [analyticId, setAnalyticId] = useState();
9
- useEffect(() => {
10
- if (!hit?.howler.analytic) {
11
- return;
12
- }
13
- getMatchingAnalytic(hit).then(analytic => setAnalyticId(analytic?.analytic_id));
14
- // eslint-disable-next-line react-hooks/exhaustive-deps
15
- }, [hit?.howler.analytic]);
16
- return (_jsxs(Typography, { variant: compressed ? 'body1' : 'h6', fontWeight: compressed && 'bold', sx: { alignSelf, '& a': { color: 'text.primary' } }, children: [analyticId ? (_jsx(Link, { to: `/analytics/${analyticId}`, onAuxClick: e => {
17
- e.stopPropagation();
18
- }, onClick: e => {
19
- e.stopPropagation();
20
- }, children: hit.howler.analytic })) : (hit.howler.analytic), hit.howler.detection && ': ', hit.howler.detection] }));
21
- };
22
- export default AnalyticLink;