@cccsaurora/howler-ui 2.19.0-cases.862 → 2.19.0-dev.1000

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 (397) hide show
  1. package/api/index.d.ts +0 -4
  2. package/api/index.js +2 -10
  3. package/api/search/facet/hit.d.ts +3 -1
  4. package/api/search/facet/index.d.ts +1 -3
  5. package/api/search/index.d.ts +1 -2
  6. package/api/search/index.js +1 -2
  7. package/commons/components/leftnav/LeftNavDrawer.js +1 -1
  8. package/components/app/App.d.ts +1 -0
  9. package/components/app/App.js +20 -42
  10. package/components/app/hooks/useMatchers.d.ts +1 -1
  11. package/components/app/hooks/useMatchers.js +11 -23
  12. package/components/app/hooks/useMatchers.test.js +22 -22
  13. package/components/app/hooks/useTitle.js +5 -5
  14. package/components/app/providers/FavouritesProvider.js +2 -6
  15. package/components/app/providers/HitProvider.d.ts +22 -0
  16. package/components/app/providers/{RecordProvider.js → HitProvider.js} +42 -42
  17. package/components/app/providers/{RecordSearchProvider.d.ts → HitSearchProvider.d.ts} +6 -6
  18. package/components/app/providers/{RecordSearchProvider.js → HitSearchProvider.js} +17 -12
  19. package/components/app/providers/{RecordSearchProvider.test.js → HitSearchProvider.test.js} +71 -52
  20. package/components/app/providers/ModalProvider.d.ts +1 -1
  21. package/components/app/providers/ModalProvider.js +5 -1
  22. package/components/app/providers/ParameterProvider.d.ts +2 -9
  23. package/components/app/providers/ParameterProvider.js +240 -165
  24. package/components/app/providers/ParameterProvider.test.js +94 -346
  25. package/components/app/providers/SocketProvider.d.ts +2 -11
  26. package/components/app/providers/SocketProvider.js +5 -18
  27. package/components/app/providers/UserListProvider.js +8 -28
  28. package/components/elements/PluginTypography.d.ts +1 -2
  29. package/components/elements/PluginTypography.js +2 -3
  30. package/components/elements/UserList.d.ts +2 -5
  31. package/components/elements/UserList.js +8 -18
  32. package/components/elements/addons/buttons/CustomButton.test.js +106 -0
  33. package/components/elements/addons/layout/FlexOne.test.js +30 -0
  34. package/components/elements/addons/lists/TuiListBase.js +4 -0
  35. package/components/elements/addons/lists/TuiListElement.js +6 -3
  36. package/components/elements/addons/lists/index.d.ts +1 -0
  37. package/components/elements/addons/search/SearchPagination.test.js +80 -0
  38. package/components/elements/addons/search/SearchTotal.test.js +45 -0
  39. package/components/elements/addons/search/phrase/Phrase.js +1 -1
  40. package/components/elements/display/ChipPopper.d.ts +1 -1
  41. package/components/elements/display/ChipPopper.js +5 -5
  42. package/components/elements/display/DocumentationButton.test.js +84 -0
  43. package/components/elements/display/DynamicTabs.test.js +93 -0
  44. package/components/elements/display/HowlerAvatar.js +2 -1
  45. package/components/elements/display/HowlerCard.js +1 -1
  46. package/components/elements/display/HowlerCard.test.js +55 -0
  47. package/components/elements/display/Image.test.js +79 -0
  48. package/components/elements/display/Markdown.js +9 -2
  49. package/components/elements/display/Modal.js +0 -2
  50. package/components/elements/display/QueryResultText.test.js +48 -0
  51. package/components/elements/display/TextDivider.test.js +43 -0
  52. package/components/elements/display/TypingIndicator.test.js +33 -0
  53. package/components/elements/display/icons/BundleButton.d.ts +6 -0
  54. package/components/elements/display/icons/BundleButton.js +32 -0
  55. package/components/elements/display/modals/ConfirmDeleteModal.d.ts +4 -0
  56. package/components/elements/display/modals/ConfirmDeleteModal.js +4 -2
  57. package/components/elements/hit/HitActions.js +4 -4
  58. package/components/elements/hit/HitBanner.d.ts +0 -1
  59. package/components/elements/hit/HitBanner.js +49 -31
  60. package/components/elements/hit/HitCard.d.ts +0 -2
  61. package/components/elements/hit/HitCard.js +7 -7
  62. package/components/elements/{record/RecordComments.d.ts → hit/HitComments.d.ts} +4 -5
  63. package/components/elements/{record/RecordComments.js → hit/HitComments.js} +28 -29
  64. package/components/elements/{ObjectDetails.js → hit/HitDetails.js} +17 -17
  65. package/components/elements/hit/HitLabels.js +2 -2
  66. package/components/elements/hit/HitOutline.d.ts +0 -1
  67. package/components/elements/hit/HitOutline.js +3 -3
  68. package/components/elements/hit/{HitPreview.d.ts → HitQuickSearch.d.ts} +3 -3
  69. package/components/elements/hit/{HitPreview.js → HitQuickSearch.js} +4 -10
  70. package/components/elements/hit/HitRelated.d.ts +6 -0
  71. package/components/elements/hit/HitRelated.js +7 -0
  72. package/components/elements/hit/HitSummary.d.ts +1 -2
  73. package/components/elements/hit/HitSummary.js +8 -8
  74. package/components/elements/{record/RecordWorklog.d.ts → hit/HitWorklog.d.ts} +3 -4
  75. package/components/elements/{record/RecordWorklog.js → hit/HitWorklog.js} +13 -15
  76. package/components/elements/hit/aggregate/HitGraph.js +8 -8
  77. package/components/elements/hit/elements/{Assigned.d.ts → HitUsers.d.ts} +5 -2
  78. package/components/elements/hit/elements/HitUsers.js +33 -0
  79. package/components/elements/hit/outlines/DefaultOutline.js +1 -1
  80. package/components/elements/view/ViewTitle.d.ts +0 -1
  81. package/components/elements/view/ViewTitle.js +2 -9
  82. package/components/hooks/useHitActions.d.ts +1 -1
  83. package/components/hooks/useHitActions.js +4 -4
  84. package/components/hooks/{useRecordSelection.d.ts → useHitSelection.d.ts} +2 -2
  85. package/components/hooks/{useRecordSelection.js → useHitSelection.js} +33 -12
  86. package/components/hooks/useMyPreferences.js +3 -11
  87. package/components/hooks/useMySearch.js +2 -2
  88. package/components/hooks/useMySitemap.js +1 -4
  89. package/components/hooks/useMyTheme.js +2 -9
  90. package/components/routes/403.test.js +27 -0
  91. package/components/routes/404.test.js +26 -0
  92. package/components/routes/ErrorBoundary.test.js +43 -0
  93. package/components/routes/ErrorOccured.test.js +35 -0
  94. package/components/routes/Logout.test.js +59 -0
  95. package/components/routes/action/edit/ActionEditor.js +2 -2
  96. package/components/routes/action/view/ActionDetails.js +4 -2
  97. package/components/routes/action/view/ActionSearch.js +12 -7
  98. package/components/routes/advanced/QueryBuilder.js +1 -1
  99. package/components/routes/advanced/QueryEditor.js +3 -3
  100. package/components/routes/advanced/historyCompletionProvider.js +3 -3
  101. package/components/routes/analytics/AnalyticDetails.js +12 -8
  102. package/components/routes/analytics/AnalyticSearch.js +1 -1
  103. package/components/routes/dossiers/DossierEditor.js +2 -2
  104. package/components/routes/dossiers/DossierEditor.test.js +1 -1
  105. package/components/routes/dossiers/Dossiers.js +15 -11
  106. package/components/routes/help/ApiDocumentation.js +1 -1
  107. package/components/routes/help/BundleDocumentation.d.ts +3 -0
  108. package/components/routes/help/BundleDocumentation.js +12 -0
  109. package/components/routes/help/HitBannerDocumentation.js +0 -1
  110. package/components/routes/help/HitDocumentation.js +3 -1
  111. package/components/routes/help/markdown/en/bundles.md.js +1 -0
  112. package/components/routes/help/markdown/en/client.md.js +1 -1
  113. package/components/routes/help/markdown/fr/bundles.md.js +1 -0
  114. package/components/routes/help/markdown/fr/client.md.js +1 -1
  115. package/components/routes/hits/search/BundleParentMenu.d.ts +6 -0
  116. package/components/routes/hits/search/BundleParentMenu.js +32 -0
  117. package/components/routes/hits/search/BundleScroller.d.ts +2 -0
  118. package/components/routes/hits/search/BundleScroller.js +6 -0
  119. package/components/routes/hits/search/{RecordBrowser.js → HitBrowser.js} +9 -9
  120. package/components/{elements/record/RecordContextMenu.d.ts → routes/hits/search/HitContextMenu.d.ts} +3 -3
  121. package/components/routes/hits/search/HitContextMenu.js +239 -0
  122. package/components/{elements/record/RecordContextMenu.test.js → routes/hits/search/HitContextMenu.test.js} +43 -98
  123. package/components/routes/hits/search/{RecordQuery.d.ts → HitQuery.d.ts} +2 -2
  124. package/components/routes/hits/search/{RecordQuery.js → HitQuery.js} +6 -6
  125. package/components/routes/hits/search/InformationPane.d.ts +0 -1
  126. package/components/routes/hits/search/InformationPane.js +63 -50
  127. package/components/routes/hits/search/LayoutSettings.js +3 -3
  128. package/components/routes/hits/search/QuerySettings.js +1 -2
  129. package/components/routes/hits/search/QuerySettings.test.js +9 -14
  130. package/components/routes/hits/search/SearchPane.js +49 -26
  131. package/components/routes/hits/search/ViewLink.js +3 -3
  132. package/components/routes/hits/search/ViewLink.test.js +8 -8
  133. package/components/routes/hits/search/grid/AddColumnModal.js +4 -5
  134. package/components/routes/hits/search/grid/EnhancedCell.d.ts +1 -2
  135. package/components/routes/hits/search/grid/EnhancedCell.js +2 -2
  136. package/components/routes/hits/search/grid/HitGrid.js +18 -20
  137. package/components/routes/hits/search/grid/{RecordRow.d.ts → HitRow.d.ts} +2 -3
  138. package/components/routes/hits/search/grid/{RecordRow.js → HitRow.js} +9 -11
  139. package/components/routes/hits/search/shared/CustomSpan.js +7 -7
  140. package/components/routes/hits/search/shared/CustomSpan.test.js +170 -0
  141. package/components/routes/hits/view/HitViewer.js +13 -12
  142. package/components/routes/home/AddNewCard.test.js +68 -0
  143. package/components/routes/home/ViewCard.js +41 -47
  144. package/components/routes/home/ViewRefresh.test.js +79 -0
  145. package/components/routes/overviews/OverviewCard.test.js +108 -0
  146. package/components/{elements/MarkdownEditor.js → routes/overviews/OverviewEditor.js} +3 -3
  147. package/components/routes/overviews/OverviewViewer.js +14 -10
  148. package/components/routes/overviews/Overviews.js +15 -11
  149. package/components/routes/settings/LocalSection.js +2 -1
  150. package/components/routes/settings/SettingsSection.test.js +19 -0
  151. package/components/routes/templates/TemplateCard.d.ts +3 -1
  152. package/components/routes/templates/TemplateCard.js +8 -4
  153. package/components/routes/templates/TemplateCard.test.d.ts +1 -0
  154. package/components/routes/templates/TemplateCard.test.js +115 -0
  155. package/components/routes/templates/TemplateViewer.js +57 -16
  156. package/components/routes/templates/Templates.js +23 -6
  157. package/components/routes/views/ViewComposer.js +19 -46
  158. package/components/routes/views/Views.js +8 -4
  159. package/locales/en/translation.json +17 -117
  160. package/locales/fr/translation.json +19 -119
  161. package/models/WithMetadata.d.ts +1 -2
  162. package/models/entities/generated/{ThreatEnrichment.d.ts → Enrichment.d.ts} +1 -1
  163. package/models/entities/generated/Hit.d.ts +1 -1
  164. package/models/entities/generated/Howler.d.ts +6 -0
  165. package/models/entities/generated/Rule.d.ts +9 -6
  166. package/models/entities/generated/Threat.d.ts +2 -2
  167. package/models/entities/generated/UserUser.d.ts +2 -0
  168. package/models/entities/generated/View.d.ts +0 -1
  169. package/package.json +112 -132
  170. package/plugins/clue/components/ClueTypography.js +2 -2
  171. package/plugins/clue/utils.d.ts +1 -2
  172. package/rest/FetchClient.test.d.ts +1 -0
  173. package/rest/FetchClient.test.js +81 -0
  174. package/setupTests.js +5 -0
  175. package/tests/mocks.d.ts +1 -11
  176. package/tests/mocks.js +7 -12
  177. package/tests/server-handlers.js +1 -6
  178. package/tests/utils.d.ts +0 -4
  179. package/tests/utils.js +0 -20
  180. package/utils/Throttler.test.d.ts +1 -0
  181. package/utils/Throttler.test.js +135 -0
  182. package/utils/actionUtils.test.d.ts +1 -0
  183. package/utils/actionUtils.test.js +140 -0
  184. package/utils/constants.d.ts +4 -4
  185. package/utils/constants.js +1 -6
  186. package/utils/hitFunctions.d.ts +1 -2
  187. package/utils/hitFunctions.js +4 -4
  188. package/utils/hitFunctions.test.d.ts +1 -0
  189. package/utils/hitFunctions.test.js +52 -0
  190. package/utils/localStorage.test.d.ts +1 -0
  191. package/utils/localStorage.test.js +96 -0
  192. package/utils/menuUtils.test.d.ts +1 -0
  193. package/utils/menuUtils.test.js +198 -0
  194. package/utils/sessionStorage.test.d.ts +1 -0
  195. package/utils/sessionStorage.test.js +81 -0
  196. package/utils/socketUtils.d.ts +0 -14
  197. package/utils/socketUtils.js +1 -17
  198. package/utils/socketUtils.test.js +16 -49
  199. package/utils/stringUtils.test.d.ts +1 -0
  200. package/utils/stringUtils.test.js +159 -0
  201. package/utils/utils.test.d.ts +1 -0
  202. package/utils/utils.test.js +292 -0
  203. package/utils/viewUtils.js +0 -3
  204. package/utils/viewUtils.test.d.ts +1 -0
  205. package/utils/viewUtils.test.js +45 -0
  206. package/utils/xsrf.test.d.ts +1 -0
  207. package/utils/xsrf.test.js +41 -0
  208. package/api/search/case.d.ts +0 -4
  209. package/api/search/case.js +0 -8
  210. package/api/socket/index.d.ts +0 -3
  211. package/api/socket/index.js +0 -6
  212. package/api/socket/viewers.d.ts +0 -2
  213. package/api/socket/viewers.js +0 -8
  214. package/api/socket/viewers.test.js +0 -44
  215. package/api/v2/case/index.d.ts +0 -9
  216. package/api/v2/case/index.js +0 -21
  217. package/api/v2/case/items.d.ts +0 -6
  218. package/api/v2/case/items.js +0 -18
  219. package/api/v2/case/rules.d.ts +0 -6
  220. package/api/v2/case/rules.js +0 -18
  221. package/api/v2/index.d.ts +0 -4
  222. package/api/v2/index.js +0 -6
  223. package/api/v2/search/facet.d.ts +0 -3
  224. package/api/v2/search/facet.js +0 -12
  225. package/api/v2/search/index.d.ts +0 -5
  226. package/api/v2/search/index.js +0 -24
  227. package/components/app/providers/RecordProvider.d.ts +0 -23
  228. package/components/elements/ContextMenu.d.ts +0 -56
  229. package/components/elements/ContextMenu.js +0 -109
  230. package/components/elements/ContextMenu.test.js +0 -215
  231. package/components/elements/ObjectDetails.d.ts +0 -6
  232. package/components/elements/case/CaseCard.d.ts +0 -12
  233. package/components/elements/case/CaseCard.js +0 -42
  234. package/components/elements/case/CasePreview.d.ts +0 -6
  235. package/components/elements/case/CasePreview.js +0 -17
  236. package/components/elements/case/StatusIcon.d.ts +0 -5
  237. package/components/elements/case/StatusIcon.js +0 -13
  238. package/components/elements/hit/elements/AnalyticLink.d.ts +0 -9
  239. package/components/elements/hit/elements/AnalyticLink.js +0 -22
  240. package/components/elements/hit/elements/Assigned.js +0 -34
  241. package/components/elements/hit/elements/Assigned.test.js +0 -65
  242. package/components/elements/hit/related/RelatedRecords.js +0 -63
  243. package/components/elements/observable/ObservableCard.d.ts +0 -6
  244. package/components/elements/observable/ObservableCard.js +0 -22
  245. package/components/elements/observable/ObservablePreview.d.ts +0 -6
  246. package/components/elements/observable/ObservablePreview.js +0 -12
  247. package/components/elements/record/RecordContextMenu.js +0 -268
  248. package/components/elements/record/RecordRelated.d.ts +0 -7
  249. package/components/elements/record/RecordRelated.js +0 -34
  250. package/components/hooks/useRelatedRecords.d.ts +0 -13
  251. package/components/hooks/useRelatedRecords.js +0 -32
  252. package/components/routes/cases/CaseViewer.d.ts +0 -2
  253. package/components/routes/cases/CaseViewer.js +0 -44
  254. package/components/routes/cases/CaseViewer.test.js +0 -133
  255. package/components/routes/cases/Cases.d.ts +0 -2
  256. package/components/routes/cases/Cases.js +0 -148
  257. package/components/routes/cases/constants.d.ts +0 -6
  258. package/components/routes/cases/constants.js +0 -6
  259. package/components/routes/cases/detail/AlertPanel.d.ts +0 -6
  260. package/components/routes/cases/detail/AlertPanel.js +0 -33
  261. package/components/routes/cases/detail/CaseAssets.d.ts +0 -11
  262. package/components/routes/cases/detail/CaseAssets.js +0 -104
  263. package/components/routes/cases/detail/CaseAssets.test.js +0 -167
  264. package/components/routes/cases/detail/CaseDashboard.d.ts +0 -7
  265. package/components/routes/cases/detail/CaseDashboard.js +0 -66
  266. package/components/routes/cases/detail/CaseDetails.d.ts +0 -6
  267. package/components/routes/cases/detail/CaseDetails.js +0 -70
  268. package/components/routes/cases/detail/CaseOverview.d.ts +0 -7
  269. package/components/routes/cases/detail/CaseOverview.js +0 -43
  270. package/components/routes/cases/detail/CaseRules.d.ts +0 -7
  271. package/components/routes/cases/detail/CaseRules.js +0 -57
  272. package/components/routes/cases/detail/CaseRules.test.js +0 -221
  273. package/components/routes/cases/detail/CaseSidebar.d.ts +0 -8
  274. package/components/routes/cases/detail/CaseSidebar.js +0 -107
  275. package/components/routes/cases/detail/CaseSidebar.test.js +0 -266
  276. package/components/routes/cases/detail/CaseTask.d.ts +0 -11
  277. package/components/routes/cases/detail/CaseTask.js +0 -66
  278. package/components/routes/cases/detail/CaseTimeline.d.ts +0 -12
  279. package/components/routes/cases/detail/CaseTimeline.js +0 -106
  280. package/components/routes/cases/detail/CaseTimeline.test.js +0 -320
  281. package/components/routes/cases/detail/CreateRuleDialog.d.ts +0 -9
  282. package/components/routes/cases/detail/CreateRuleDialog.js +0 -163
  283. package/components/routes/cases/detail/CreateRuleDialog.test.js +0 -259
  284. package/components/routes/cases/detail/ItemPage.d.ts +0 -6
  285. package/components/routes/cases/detail/ItemPage.js +0 -95
  286. package/components/routes/cases/detail/RelatedCasePanel.d.ts +0 -6
  287. package/components/routes/cases/detail/RelatedCasePanel.js +0 -34
  288. package/components/routes/cases/detail/TaskPanel.d.ts +0 -7
  289. package/components/routes/cases/detail/TaskPanel.js +0 -52
  290. package/components/routes/cases/detail/aggregates/CaseAggregate.d.ts +0 -11
  291. package/components/routes/cases/detail/aggregates/CaseAggregate.js +0 -24
  292. package/components/routes/cases/detail/aggregates/SourceAggregate.d.ts +0 -6
  293. package/components/routes/cases/detail/aggregates/SourceAggregate.js +0 -26
  294. package/components/routes/cases/detail/assets/Asset.d.ts +0 -14
  295. package/components/routes/cases/detail/assets/Asset.js +0 -12
  296. package/components/routes/cases/detail/assets/Asset.test.js +0 -72
  297. package/components/routes/cases/detail/sidebar/CaseFolder.d.ts +0 -20
  298. package/components/routes/cases/detail/sidebar/CaseFolder.js +0 -83
  299. package/components/routes/cases/detail/sidebar/CaseFolder.test.js +0 -295
  300. package/components/routes/cases/detail/sidebar/CaseFolderContextMenu.d.ts +0 -34
  301. package/components/routes/cases/detail/sidebar/CaseFolderContextMenu.js +0 -103
  302. package/components/routes/cases/detail/sidebar/CaseFolderContextMenu.test.js +0 -363
  303. package/components/routes/cases/detail/sidebar/FolderEntry.d.ts +0 -25
  304. package/components/routes/cases/detail/sidebar/FolderEntry.js +0 -88
  305. package/components/routes/cases/detail/sidebar/FolderEntry.test.js +0 -206
  306. package/components/routes/cases/detail/sidebar/RootDropZone.d.ts +0 -5
  307. package/components/routes/cases/detail/sidebar/RootDropZone.js +0 -33
  308. package/components/routes/cases/detail/sidebar/types.d.ts +0 -9
  309. package/components/routes/cases/detail/sidebar/utils.d.ts +0 -3
  310. package/components/routes/cases/detail/sidebar/utils.js +0 -29
  311. package/components/routes/cases/detail/sidebar/utils.test.js +0 -82
  312. package/components/routes/cases/hooks/useCase.d.ts +0 -13
  313. package/components/routes/cases/hooks/useCase.js +0 -69
  314. package/components/routes/cases/hooks/useCase.test.js +0 -141
  315. package/components/routes/cases/modals/AddToCaseModal.d.ts +0 -7
  316. package/components/routes/cases/modals/AddToCaseModal.js +0 -59
  317. package/components/routes/cases/modals/AddToCaseModal.test.js +0 -313
  318. package/components/routes/cases/modals/CaseRecordRow.d.ts +0 -9
  319. package/components/routes/cases/modals/CaseRecordRow.js +0 -15
  320. package/components/routes/cases/modals/CreateCaseModal.d.ts +0 -7
  321. package/components/routes/cases/modals/CreateCaseModal.js +0 -55
  322. package/components/routes/cases/modals/CreateCaseModal.test.js +0 -358
  323. package/components/routes/cases/modals/RenameItemModal.d.ts +0 -9
  324. package/components/routes/cases/modals/RenameItemModal.js +0 -48
  325. package/components/routes/cases/modals/ResolveModal.d.ts +0 -7
  326. package/components/routes/cases/modals/ResolveModal.js +0 -115
  327. package/components/routes/cases/modals/ResolveModal.test.js +0 -394
  328. package/components/routes/cases/modals/hooks.d.ts +0 -7
  329. package/components/routes/cases/modals/hooks.js +0 -44
  330. package/components/routes/cases/modals/types.d.ts +0 -5
  331. package/components/routes/cases/search/CaseAssigneeFilter.d.ts +0 -6
  332. package/components/routes/cases/search/CaseAssigneeFilter.js +0 -33
  333. package/components/routes/cases/search/CaseAssigneeFilter.test.js +0 -127
  334. package/components/routes/cases/search/CaseDateFilter.d.ts +0 -13
  335. package/components/routes/cases/search/CaseDateFilter.js +0 -26
  336. package/components/routes/cases/search/CaseDateFilter.test.js +0 -115
  337. package/components/routes/cases/search/CaseStatusFilter.d.ts +0 -6
  338. package/components/routes/cases/search/CaseStatusFilter.js +0 -13
  339. package/components/routes/cases/search/CaseStatusFilter.test.js +0 -86
  340. package/components/routes/hits/search/shared/IndexPicker.d.ts +0 -2
  341. package/components/routes/hits/search/shared/IndexPicker.js +0 -20
  342. package/components/routes/observables/ObservableViewer.d.ts +0 -7
  343. package/components/routes/observables/ObservableViewer.js +0 -27
  344. package/models/entities/generated/AttachmentsFile.d.ts +0 -12
  345. package/models/entities/generated/Case.d.ts +0 -28
  346. package/models/entities/generated/DestinationOriginal.d.ts +0 -19
  347. package/models/entities/generated/EmailAttachment.d.ts +0 -8
  348. package/models/entities/generated/EmailParent.d.ts +0 -19
  349. package/models/entities/generated/Enrichments.d.ts +0 -7
  350. package/models/entities/generated/EnrichmentsIndicator.d.ts +0 -21
  351. package/models/entities/generated/HttpResponse.d.ts +0 -11
  352. package/models/entities/generated/Item.d.ts +0 -9
  353. package/models/entities/generated/Observable.d.ts +0 -85
  354. package/models/entities/generated/ObservableCloud.d.ts +0 -20
  355. package/models/entities/generated/ObservableDestination.d.ts +0 -23
  356. package/models/entities/generated/ObservableEmail.d.ts +0 -30
  357. package/models/entities/generated/ObservableFile.d.ts +0 -36
  358. package/models/entities/generated/ObservableHowler.d.ts +0 -42
  359. package/models/entities/generated/ObservableHttp.d.ts +0 -11
  360. package/models/entities/generated/ObservableObserver.d.ts +0 -21
  361. package/models/entities/generated/ObservableOrganization.d.ts +0 -7
  362. package/models/entities/generated/ObservableProcess.d.ts +0 -34
  363. package/models/entities/generated/ObservableSource.d.ts +0 -23
  364. package/models/entities/generated/ObservableThreat.d.ts +0 -21
  365. package/models/entities/generated/ObservableTls.d.ts +0 -12
  366. package/models/entities/generated/ObserverIngress.d.ts +0 -9
  367. package/models/entities/generated/Task.d.ts +0 -10
  368. package/models/socket/CaseUpdate.d.ts +0 -5
  369. package/models/socket/ViewersUpdate.d.ts +0 -4
  370. package/utils/typeUtils.d.ts +0 -7
  371. package/utils/typeUtils.js +0 -27
  372. /package/{api/socket/viewers.test.d.ts → components/app/providers/HitSearchProvider.test.d.ts} +0 -0
  373. /package/components/{app/providers/RecordSearchProvider.test.d.ts → elements/addons/buttons/CustomButton.test.d.ts} +0 -0
  374. /package/components/elements/{ContextMenu.test.d.ts → addons/layout/FlexOne.test.d.ts} +0 -0
  375. /package/components/elements/{hit/elements/Assigned.test.d.ts → addons/search/SearchPagination.test.d.ts} +0 -0
  376. /package/components/elements/{record/RecordContextMenu.test.d.ts → addons/search/SearchTotal.test.d.ts} +0 -0
  377. /package/components/{routes/cases/CaseViewer.test.d.ts → elements/display/DocumentationButton.test.d.ts} +0 -0
  378. /package/components/{routes/cases/detail/CaseAssets.test.d.ts → elements/display/DynamicTabs.test.d.ts} +0 -0
  379. /package/components/{routes/cases/detail/CaseRules.test.d.ts → elements/display/HowlerCard.test.d.ts} +0 -0
  380. /package/components/{routes/cases/detail/CaseSidebar.test.d.ts → elements/display/Image.test.d.ts} +0 -0
  381. /package/components/{routes/cases/detail/CaseTimeline.test.d.ts → elements/display/QueryResultText.test.d.ts} +0 -0
  382. /package/components/{routes/cases/detail/CreateRuleDialog.test.d.ts → elements/display/TextDivider.test.d.ts} +0 -0
  383. /package/components/{routes/cases/detail/assets/Asset.test.d.ts → elements/display/TypingIndicator.test.d.ts} +0 -0
  384. /package/components/elements/hit/{related/RelatedRecords.d.ts → HitDetails.d.ts} +0 -0
  385. /package/components/routes/{cases/detail/sidebar/CaseFolder.test.d.ts → 403.test.d.ts} +0 -0
  386. /package/components/routes/{cases/detail/sidebar/CaseFolderContextMenu.test.d.ts → 404.test.d.ts} +0 -0
  387. /package/components/routes/{cases/detail/sidebar/FolderEntry.test.d.ts → ErrorBoundary.test.d.ts} +0 -0
  388. /package/components/routes/{cases/detail/sidebar/utils.test.d.ts → ErrorOccured.test.d.ts} +0 -0
  389. /package/components/routes/{cases/hooks/useCase.test.d.ts → Logout.test.d.ts} +0 -0
  390. /package/components/routes/hits/search/{RecordBrowser.d.ts → HitBrowser.d.ts} +0 -0
  391. /package/components/routes/{cases/modals/AddToCaseModal.test.d.ts → hits/search/HitContextMenu.test.d.ts} +0 -0
  392. /package/components/routes/{cases/modals/CreateCaseModal.test.d.ts → hits/search/shared/CustomSpan.test.d.ts} +0 -0
  393. /package/components/routes/{cases/modals/ResolveModal.test.d.ts → home/AddNewCard.test.d.ts} +0 -0
  394. /package/components/routes/{cases/search/CaseAssigneeFilter.test.d.ts → home/ViewRefresh.test.d.ts} +0 -0
  395. /package/components/routes/{cases/search/CaseDateFilter.test.d.ts → overviews/OverviewCard.test.d.ts} +0 -0
  396. /package/components/{elements/MarkdownEditor.d.ts → routes/overviews/OverviewEditor.d.ts} +0 -0
  397. /package/components/routes/{cases/search/CaseStatusFilter.test.d.ts → settings/SettingsSection.test.d.ts} +0 -0
@@ -1,11 +1,11 @@
1
- import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
1
+ import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { Analytics, InfoOutlined } from '@mui/icons-material';
3
3
  import { Alert, AlertTitle, Autocomplete, Box, Button, Chip, CircularProgress, Divider, Fade, Grid, LinearProgress, Stack, TextField, Tooltip, Typography } from '@mui/material';
4
4
  import api from '@cccsaurora/howler-ui/api';
5
5
  import useMatchers from '@cccsaurora/howler-ui/components/app/hooks/useMatchers';
6
6
  import { FieldContext } from '@cccsaurora/howler-ui/components/app/providers/FieldProvider';
7
+ import { HitSearchContext } from '@cccsaurora/howler-ui/components/app/providers/HitSearchProvider';
7
8
  import { ParameterContext } from '@cccsaurora/howler-ui/components/app/providers/ParameterProvider';
8
- import { RecordSearchContext } from '@cccsaurora/howler-ui/components/app/providers/RecordSearchProvider';
9
9
  import useMyApi from '@cccsaurora/howler-ui/components/hooks/useMyApi';
10
10
  import { useMyLocalStorageItem } from '@cccsaurora/howler-ui/components/hooks/useMyLocalStorage';
11
11
  import useMySnackbar from '@cccsaurora/howler-ui/components/hooks/useMySnackbar';
@@ -14,7 +14,6 @@ import { memo, useCallback, useContext, useEffect, useState } from 'react';
14
14
  import { useTranslation } from 'react-i18next';
15
15
  import { useContextSelector } from 'use-context-selector';
16
16
  import { StorageKey } from '@cccsaurora/howler-ui/utils/constants';
17
- import { isHit } from '@cccsaurora/howler-ui/utils/typeUtils';
18
17
  import { getTimeRange } from '@cccsaurora/howler-ui/utils/utils';
19
18
  import PluginChip from '../PluginChip';
20
19
  import HitGraph from './aggregate/HitGraph';
@@ -24,10 +23,11 @@ const HitSummary = ({ response, onStart, onComplete }) => {
24
23
  const { hitFields } = useContext(FieldContext);
25
24
  const { showErrorMessage } = useMySnackbar();
26
25
  const pageCount = useMyLocalStorageItem(StorageKey.PAGE_COUNT, 25)[0];
26
+ const [showHitSummaryGraph] = useMyLocalStorageItem(StorageKey.SHOW_HIT_SUMMARY_GRAPH, true);
27
27
  const { getMatchingTemplate } = useMatchers();
28
- const searching = useContextSelector(RecordSearchContext, ctx => ctx.searching);
29
- const error = useContextSelector(RecordSearchContext, ctx => ctx.error);
30
- const getFilters = useContextSelector(RecordSearchContext, ctx => ctx.getFilters);
28
+ const searching = useContextSelector(HitSearchContext, ctx => ctx.searching);
29
+ const error = useContextSelector(HitSearchContext, ctx => ctx.error);
30
+ const getFilters = useContextSelector(HitSearchContext, ctx => ctx.getFilters);
31
31
  const query = useContextSelector(ParameterContext, ctx => ctx.query);
32
32
  const setQuery = useContextSelector(ParameterContext, ctx => ctx.setQuery);
33
33
  const views = useContextSelector(ParameterContext, ctx => ctx.views);
@@ -41,7 +41,7 @@ const HitSummary = ({ response, onStart, onComplete }) => {
41
41
  }
42
42
  try {
43
43
  // Get a list of every key in every template of the hits we're searching
44
- const rawCounts = await Promise.all((response?.items ?? []).filter(isHit).map(async (h) => {
44
+ const rawCounts = await Promise.all((response?.items ?? []).map(async (h) => {
45
45
  const matchingTemplate = await getMatchingTemplate(h);
46
46
  return (matchingTemplate?.keys ?? [])
47
47
  .filter(key => !['howler.id', 'howler.hash'].includes(key))
@@ -131,7 +131,7 @@ const HitSummary = ({ response, onStart, onComplete }) => {
131
131
  performAggregation();
132
132
  // eslint-disable-next-line react-hooks/exhaustive-deps
133
133
  }, [query, views, searching, error]);
134
- return (_jsxs(Stack, { sx: { mx: 2, height: '100%' }, spacing: 1, children: [_jsx(Typography, { variant: "h6", children: t('hit.summary.aggregate.title') }), _jsx(Divider, { flexItem: true }), _jsx(HitGraph, {}), _jsx(Divider, { flexItem: true }), _jsxs(Stack, { sx: { overflow: 'auto', marginTop: '0 !important' }, pt: 1, spacing: 1, children: [_jsxs(Stack, { direction: "row", spacing: 2, mb: 2, alignItems: "stretch", children: [_jsx(Autocomplete, { fullWidth: true, multiple: true, sx: { minWidth: '175px' }, size: "small", value: customKeys, options: hitFields.map(_field => _field.key), renderInput: _params => _jsx(TextField, { ..._params, label: t('hit.summary.adhoc') }), onChange: (_, value) => setCustomKeys(value) }), _jsx(Button, { variant: "outlined", startIcon: loading ? _jsx(CircularProgress, { size: 20, sx: { ml: 1 } }) : _jsx(Analytics, { sx: { ml: 1 } }), disabled: loading, onClick: () => performAggregation(), children: t('button.aggregate') })] }), isEmpty(aggregateResults) && (_jsxs(Alert, { severity: "info", variant: "outlined", children: [_jsx(AlertTitle, { children: t('hit.summary.aggregate.nokeys.title') }), t('hit.summary.aggregate.nokeys.description')] })), loading && _jsx(LinearProgress, { sx: { minHeight: '4px' } }), Object.keys(aggregateResults)
134
+ return (_jsxs(Stack, { sx: { mx: 2, height: '100%' }, spacing: 1, children: [_jsx(Typography, { variant: "h6", children: t('hit.summary.aggregate.title') }), _jsx(Divider, { flexItem: true }), showHitSummaryGraph && (_jsxs(_Fragment, { children: [_jsx(HitGraph, {}), _jsx(Divider, { flexItem: true })] })), _jsxs(Stack, { sx: { overflow: 'auto', marginTop: '0 !important' }, pt: 1, spacing: 1, children: [_jsxs(Stack, { direction: "row", spacing: 2, mb: 2, alignItems: "stretch", children: [_jsx(Autocomplete, { fullWidth: true, multiple: true, sx: { minWidth: '175px' }, size: "small", value: customKeys, options: hitFields.map(_field => _field.key), renderInput: _params => _jsx(TextField, { ..._params, label: t('hit.summary.adhoc') }), onChange: (_, value) => setCustomKeys(value) }), _jsx(Button, { variant: "outlined", startIcon: loading ? _jsx(CircularProgress, { size: 20, sx: { ml: 1 } }) : _jsx(Analytics, { sx: { ml: 1 } }), disabled: loading, onClick: () => performAggregation(), children: t('button.aggregate') })] }), isEmpty(aggregateResults) && (_jsxs(Alert, { severity: "info", variant: "outlined", children: [_jsx(AlertTitle, { children: t('hit.summary.aggregate.nokeys.title') }), t('hit.summary.aggregate.nokeys.description')] })), loading && _jsx(LinearProgress, { sx: { minHeight: '4px' } }), Object.keys(aggregateResults)
135
135
  .filter(key => !isEmpty(aggregateResults[key]))
136
136
  .flatMap(key => [
137
137
  _jsx(Fade, { in: true, children: _jsxs(Stack, { direction: "row", alignItems: "center", spacing: 1, children: [_jsx(Typography, { variant: "body1", children: key }, key + '-title'), keyCounts[key]?.count < 0 ? (_jsxs(Typography, { variant: "caption", color: "text.secondary", children: ["(", t('hit.summary.adhoc.custom'), ")"] })) : (_jsxs(Typography, { variant: "caption", color: "text.secondary", children: ["(", keyCounts[key]?.count ?? '?', " ", t('references'), ")"] })), _jsx(Tooltip, { title: _jsxs(Stack, { children: [_jsx(Typography, { variant: "caption", children: t('hit.summary.aggregate.sources') }), keyCounts[key]?.sources.map(source => (_jsx(Typography, { variant: "caption", children: source }, source))) ?? '?'] }), children: _jsx(InfoOutlined, { fontSize: "inherit" }) })] }) }, key + '-refs'),
@@ -1,11 +1,10 @@
1
1
  import type { HowlerUser } from '@cccsaurora/howler-ui/models/entities/HowlerUser';
2
2
  import type { Hit } from '@cccsaurora/howler-ui/models/entities/generated/Hit';
3
- import type { Observable } from '@cccsaurora/howler-ui/models/entities/generated/Observable';
4
3
  import type { FC } from 'react';
5
- declare const RecordWorklog: FC<{
6
- record: Hit | Observable;
4
+ declare const HitWorklog: FC<{
5
+ hit: Hit;
7
6
  users: {
8
7
  [id: string]: HowlerUser;
9
8
  };
10
9
  }>;
11
- export default RecordWorklog;
10
+ export default HitWorklog;
@@ -10,7 +10,7 @@ import { compareTimestamp, twitterShort } from '@cccsaurora/howler-ui/utils/util
10
10
  import HowlerAvatar from '../display/HowlerAvatar';
11
11
  import HowlerCard from '../display/HowlerCard';
12
12
  import Markdown from '../display/Markdown';
13
- const RecordWorklog = ({ record, users }) => {
13
+ const HitWorklog = ({ hit, users }) => {
14
14
  const theme = useTheme();
15
15
  const { shiftColor } = useMyUtils();
16
16
  const { t } = useTranslation();
@@ -23,15 +23,15 @@ const RecordWorklog = ({ record, users }) => {
23
23
  */
24
24
  const worklogGroups = useMemo(() => {
25
25
  let setInitialVersion = false;
26
- return (record?.howler?.log || [])
26
+ return (hit?.howler?.log || [])
27
27
  .slice()
28
28
  .sort((a, b) => compareTimestamp(b.timestamp, a.timestamp))
29
29
  .reduce((acc, l) => {
30
- if (!initialVersions[record.howler.id] && !setInitialVersion) {
30
+ if (!initialVersions[hit.howler.id] && !setInitialVersion) {
31
31
  setInitialVersion = true;
32
32
  setInitialVersions({
33
33
  ...initialVersions,
34
- [record.howler.id]: l.previous_version
34
+ [hit.howler.id]: l.previous_version
35
35
  });
36
36
  }
37
37
  // Initialize the worklog card groups
@@ -42,9 +42,9 @@ const RecordWorklog = ({ record, users }) => {
42
42
  const currArr = acc[acc.length - 1];
43
43
  if (
44
44
  // Does this log version match the saved version?
45
- l.previous_version === initialVersions[record.howler.id] &&
45
+ l.previous_version === initialVersions[hit.howler.id] &&
46
46
  // Does the previous entry not match?
47
- currArr[currArr.length - 1].previous_version !== initialVersions[record.howler.id]) {
47
+ currArr[currArr.length - 1].previous_version !== initialVersions[hit.howler.id]) {
48
48
  // If so, we've figured out where the new logs should start, so we start a new card.
49
49
  acc.push([l]);
50
50
  return acc;
@@ -59,14 +59,14 @@ const RecordWorklog = ({ record, users }) => {
59
59
  }, []);
60
60
  },
61
61
  // eslint-disable-next-line react-hooks/exhaustive-deps
62
- [record?.howler?.log]);
62
+ [hit?.howler?.log]);
63
63
  useEffect(() => {
64
64
  // On unmount, mark the latest entry version as the last seen version.
65
65
  return () => {
66
- if (record?.howler.id) {
66
+ if (hit?.howler.id) {
67
67
  setInitialVersions({
68
68
  ...initialVersions,
69
- [record.howler.id]: worklogGroups[0][0]?.previous_version ?? initialVersions[record.howler.id]
69
+ [hit.howler.id]: worklogGroups[0][0]?.previous_version ?? initialVersions[hit.howler.id]
70
70
  });
71
71
  }
72
72
  };
@@ -77,9 +77,7 @@ const RecordWorklog = ({ record, users }) => {
77
77
  if (worklogGroups.length > 0) {
78
78
  return worklogGroups.flatMap((ls, index) => {
79
79
  const result = [];
80
- if (index > 0 &&
81
- initialVersions[record.howler.id] &&
82
- ls[0].previous_version === initialVersions[record.howler.id]) {
80
+ if (index > 0 && initialVersions[hit.howler.id] && ls[0].previous_version === initialVersions[hit.howler.id]) {
83
81
  result.push(_jsx(Divider, { children: _jsxs(Stack, { direction: "row", children: [_jsx(KeyboardArrowUp, { sx: { color: 'text.secondary' }, fontSize: "small" }), _jsx(Typography, { variant: "caption", color: "text.secondary", children: t('hit.worklog.new') }), _jsx(KeyboardArrowUp, { sx: { color: 'text.secondary' }, fontSize: "small" })] }) }, "new"));
84
82
  }
85
83
  result.push(_jsxs(HowlerCard, { elevation: 4, children: [_jsx(CardHeader, { avatar: _jsx(HowlerAvatar, { userId: ls[0].user }), title: users[ls[0].user]?.name ?? ls[0].user, subheader: _jsx(Tooltip, { title: new Date(ls[0].timestamp).toLocaleString(), children: _jsx(Typography, { variant: "caption", children: twitterShort(ls[0].timestamp) }) }) }), _jsx(CardContent, { children: _jsx(Stack, { spacing: 1, divider: _jsx(Divider, { orientation: "horizontal" }), children: ls.map(l => (_jsxs(Typography, { variant: "body2", color: "text.secondary", component: "div", position: "relative", children: [l.explanation ? (_jsx(Markdown, { md: l.explanation.trim() })) : (_jsxs(_Fragment, { children: [_jsxs("span", { children: [t('hit.worklog.updated'), "\u00A0"] }), _jsx("code", { children: l.key }), _jsx("span", { children: ":\u00A0" }), {
@@ -90,10 +88,10 @@ const RecordWorklog = ({ record, users }) => {
90
88
  return result;
91
89
  });
92
90
  }
93
- else if (!record?.howler) {
91
+ else if (!hit?.howler) {
94
92
  return (_jsxs(_Fragment, { children: [_jsx(Skeleton, { width: "100%", height: 200, variant: "rounded" }), _jsx(Skeleton, { width: "100%", height: 220, variant: "rounded" }), _jsx(Skeleton, { width: "100%", height: 150, variant: "rounded" })] }));
95
93
  }
96
- }, [worklogGroups, record.howler, initialVersions, users, t, shiftColor, theme.palette.text.primary]);
94
+ }, [worklogGroups, hit.howler, initialVersions, users, t, shiftColor, theme.palette.text.primary]);
97
95
  return (_jsx(Stack, { sx: { p: 2 }, spacing: 1, children: worklogEls }));
98
96
  };
99
- export default RecordWorklog;
97
+ export default HitWorklog;
@@ -4,9 +4,9 @@ import { Alert, AlertTitle, Autocomplete, Box, Button, CircularProgress, IconBut
4
4
  import api from '@cccsaurora/howler-ui/api';
5
5
  import 'chartjs-adapter-dayjs-4';
6
6
  import { ApiConfigContext } from '@cccsaurora/howler-ui/components/app/providers/ApiConfigProvider';
7
+ import { HitContext } from '@cccsaurora/howler-ui/components/app/providers/HitProvider';
8
+ import { HitSearchContext } from '@cccsaurora/howler-ui/components/app/providers/HitSearchProvider';
7
9
  import { ParameterContext } from '@cccsaurora/howler-ui/components/app/providers/ParameterProvider';
8
- import { RecordContext } from '@cccsaurora/howler-ui/components/app/providers/RecordProvider';
9
- import { RecordSearchContext } from '@cccsaurora/howler-ui/components/app/providers/RecordSearchProvider';
10
10
  import useMyApi from '@cccsaurora/howler-ui/components/hooks/useMyApi';
11
11
  import useMyChart from '@cccsaurora/howler-ui/components/hooks/useMyChart';
12
12
  import dayjs from 'dayjs';
@@ -38,12 +38,12 @@ const HitGraph = () => {
38
38
  const setQuery = useContextSelector(ParameterContext, ctx => ctx.setQuery);
39
39
  const span = useContextSelector(ParameterContext, ctx => ctx.span);
40
40
  const views = useContextSelector(ParameterContext, ctx => ctx.views);
41
- const selectedHits = useContextSelector(RecordContext, ctx => ctx.selectedRecords);
42
- const addHitToSelection = useContextSelector(RecordContext, ctx => ctx.addRecordToSelection);
43
- const removeHitFromSelection = useContextSelector(RecordContext, ctx => ctx.removeRecordFromSelection);
44
- const error = useContextSelector(RecordSearchContext, ctx => ctx.error);
45
- const response = useContextSelector(RecordSearchContext, ctx => ctx.response);
46
- const getFilters = useContextSelector(RecordSearchContext, ctx => ctx.getFilters);
41
+ const selectedHits = useContextSelector(HitContext, ctx => ctx.selectedHits);
42
+ const addHitToSelection = useContextSelector(HitContext, ctx => ctx.addHitToSelection);
43
+ const removeHitFromSelection = useContextSelector(HitContext, ctx => ctx.removeHitFromSelection);
44
+ const error = useContextSelector(HitSearchContext, ctx => ctx.error);
45
+ const response = useContextSelector(HitSearchContext, ctx => ctx.response);
46
+ const getFilters = useContextSelector(HitSearchContext, ctx => ctx.getFilters);
47
47
  const chartRef = useRef();
48
48
  const [loading, setLoading] = useState(false);
49
49
  const [filterField, setFilterField] = useState(FILTER_FIELDS[0]);
@@ -1,9 +1,12 @@
1
1
  import type { Hit } from '@cccsaurora/howler-ui/models/entities/generated/Hit';
2
2
  import type { FC } from 'react';
3
3
  import { HitLayout } from '../HitLayout';
4
- declare const Assigned: FC<{
4
+ type AssignedProps = FC<{
5
5
  hit: Hit;
6
6
  layout: HitLayout;
7
7
  hideLabel?: boolean;
8
+ showAssigned?: boolean;
9
+ showAssessor?: boolean;
8
10
  }>;
9
- export default Assigned;
11
+ declare const HitUsers: AssignedProps;
12
+ export default HitUsers;
@@ -0,0 +1,33 @@
1
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
+ import { avatarClasses, AvatarGroup, Chip, Divider, Stack, Typography } from '@mui/material';
3
+ import { useAppUser } from '@cccsaurora/howler-ui/commons/components/app/hooks';
4
+ import HowlerAvatar from '@cccsaurora/howler-ui/components/elements/display/HowlerAvatar';
5
+ import { useTranslation } from 'react-i18next';
6
+ import { HitLayout } from '../HitLayout';
7
+ const AvatarChip = ({ userId, noUser, placeholder, layout, hideLabel }) => {
8
+ const userAvatar = (_jsx(HowlerAvatar, { userId: userId, sx: { height: layout !== HitLayout.COMFY ? 24 : 32, width: layout !== HitLayout.COMFY ? 24 : 32 } }));
9
+ return hideLabel ? (userAvatar) : (_jsx(Chip, { variant: "outlined", sx: {
10
+ width: 'fit-content',
11
+ '& .MuiChip-icon': {
12
+ marginLeft: 0
13
+ }
14
+ }, icon: userAvatar, label: userId && userId !== noUser ? userId : placeholder, size: layout !== HitLayout.COMFY ? 'small' : 'medium' }));
15
+ };
16
+ const HitUsers = ({ hit, layout, hideLabel = false, showAssigned = false, showAssessor = false }) => {
17
+ const { t } = useTranslation();
18
+ const { user } = useAppUser();
19
+ const assessorVisible = showAssessor || hit.howler.assessment != null;
20
+ const assigneeVisible = !hit.howler.assessor && (showAssigned || hit.howler.assignment !== 'unassigned');
21
+ return (_jsxs(Stack, { direction: hideLabel ? 'row' : 'column', spacing: 0.5, alignItems: "flex-start", children: [_jsxs(Stack, { display: "grid", gridTemplateColumns: "repeat(2, 1fr)", alignItems: "center", columnGap: 0.5, rowGap: 0.25, children: [assigneeVisible && (_jsxs(_Fragment, { children: [!hideLabel && _jsxs(Typography, { variant: "caption", children: [t('app.drawer.hit.assignment.assignee'), ":"] }), _jsx(AvatarChip, { userId: hit?.howler.assignment, noUser: "unassigned", placeholder: t('app.drawer.hit.assignment.unassigned.name'), layout: layout, hideLabel: hideLabel })] })), assessorVisible && (_jsxs(_Fragment, { children: [!hideLabel && _jsxs(Typography, { variant: "caption", children: [t('app.drawer.hit.assessment.assessor'), ":"] }), _jsx(AvatarChip, { userId: hit.howler.assessor, noUser: "unknown", placeholder: t('app.drawer.hit.assessment.unknown.name'), layout: layout, hideLabel: hideLabel })] }))] }), hit.howler.viewers?.length > 0 && hideLabel && _jsx(Divider, { orientation: "vertical", flexItem: true, variant: "middle" }), _jsx(AvatarGroup, { max: 3, sx: { [`.${avatarClasses.root}`]: { border: 0, marginLeft: 0.5 } }, componentsProps: {
22
+ additionalAvatar: {
23
+ sx: {
24
+ height: layout !== HitLayout.COMFY ? 24 : 32,
25
+ width: layout !== HitLayout.COMFY ? 24 : 32,
26
+ fontSize: '12px'
27
+ }
28
+ }
29
+ }, children: [...new Set(hit?.howler.viewers)]
30
+ .filter(viewer => viewer !== user.username)
31
+ .map(viewer => (_jsx(HowlerAvatar, { userId: viewer, sx: { height: layout !== HitLayout.COMFY ? 24 : 32, width: layout !== HitLayout.COMFY ? 24 : 32 } }, viewer))) })] }));
32
+ };
33
+ export default HitUsers;
@@ -41,7 +41,7 @@ const DefaultOutline = ({ hit, fields, template, layout = HitLayout.NORMAL, read
41
41
  if (!displayedData) {
42
42
  return null;
43
43
  }
44
- return (_jsxs(React.Fragment, { children: [_jsx(Tooltip, { title: (config.indexes.hit[field]?.description ?? t('none')).split('\n')[0], children: _jsxs(Typography, { variant: layout !== HitLayout.COMFY ? 'caption' : 'body1', fontWeight: "bold", children: [field, ":"] }) }), _jsx(PluginTypography, { context: "outline", variant: layout !== HitLayout.COMFY ? 'caption' : 'body1', whiteSpace: "normal", sx: { width: '100%', wordBreak: 'break-all' }, value: displayedData, field: field, obj: hit, children: displayedData })] }, field));
44
+ return (_jsxs(React.Fragment, { children: [_jsx(Tooltip, { title: (config.indexes.hit[field]?.description ?? t('none')).split('\n')[0], children: _jsxs(Typography, { variant: layout !== HitLayout.COMFY ? 'caption' : 'body1', fontWeight: "bold", children: [field, ":"] }) }), _jsx(PluginTypography, { context: "outline", variant: layout !== HitLayout.COMFY ? 'caption' : 'body1', whiteSpace: "normal", sx: { width: '100%', wordBreak: 'break-all' }, value: displayedData, field: field, hit: hit, children: displayedData })] }, field));
45
45
  })] }));
46
46
  };
47
47
  export default memo(DefaultOutline);
@@ -3,7 +3,6 @@ interface ViewTitleProps {
3
3
  title?: string;
4
4
  type?: string;
5
5
  query?: string;
6
- indexes?: string[];
7
6
  sort?: string;
8
7
  span?: string;
9
8
  }
@@ -4,7 +4,7 @@ import { Chip, Stack, Tooltip, Typography } from '@mui/material';
4
4
  import { useMemo } from 'react';
5
5
  import { useTranslation } from 'react-i18next';
6
6
  import { convertLuceneToDate } from '@cccsaurora/howler-ui/utils/utils';
7
- export const ViewTitle = ({ title, type, query, sort, span, indexes }) => {
7
+ export const ViewTitle = ({ title, type, query, sort, span }) => {
8
8
  const { t } = useTranslation();
9
9
  const spanLabel = useMemo(() => {
10
10
  if (!span) {
@@ -17,16 +17,9 @@ export const ViewTitle = ({ title, type, query, sort, span, indexes }) => {
17
17
  return t(span);
18
18
  }
19
19
  }, [span, t]);
20
- const indexLabel = useMemo(() => {
21
- if (!indexes || indexes.length === 0) {
22
- return '';
23
- }
24
- else
25
- return `(${indexes.join(', ')})`;
26
- }, [indexes]);
27
20
  return (_jsxs(Stack, { children: [_jsxs(Stack, { direction: "row", alignItems: "start", spacing: 1, children: [_jsx(Tooltip, { title: t(`route.views.manager.${type}`), children: {
28
21
  readonly: _jsx(Lock, { fontSize: "small" }),
29
22
  global: _jsx(Language, { fontSize: "small" }),
30
23
  personal: _jsx(Person, { fontSize: "small" })
31
- }[type] }), _jsx(Typography, { variant: "body1", children: t(title) })] }), _jsx(Typography, { variant: "caption", children: _jsx("code", { children: query }) }), (sort || span || indexLabel) && (_jsxs(Stack, { direction: "row", sx: { mt: 1 }, spacing: 1, children: [sort?.split(',').map(_sort => (_jsx(Chip, { size: "small", label: _sort.split(' ')[0], icon: _sort.endsWith('desc') ? _jsx(ArrowDownward, {}) : _jsx(ArrowUpward, {}) }, _sort.split(' ')[0]))), spanLabel && _jsx(Chip, { label: spanLabel }), indexLabel && _jsx(Chip, { label: indexLabel })] }))] }));
24
+ }[type] }), _jsx(Typography, { variant: "body1", children: t(title) })] }), _jsx(Typography, { variant: "caption", children: _jsx("code", { children: query }) }), (sort || span) && (_jsxs(Stack, { direction: "row", sx: { mt: 1 }, spacing: 1, children: [sort?.split(',').map(_sort => (_jsx(Chip, { size: "small", label: _sort.split(' ')[0], icon: _sort.endsWith('desc') ? _jsx(ArrowDownward, {}) : _jsx(ArrowUpward, {}) }, _sort.split(' ')[0]))), spanLabel && _jsx(Chip, { size: "small", label: spanLabel })] }))] }));
32
25
  };
@@ -7,7 +7,7 @@ declare const useHitActions: (_hits: Hit | Hit[]) => {
7
7
  canAssess: boolean;
8
8
  loading: boolean;
9
9
  manage: (transition: string) => Promise<void>;
10
- assess: (assessment: string, skipRationale?: boolean, providedRationale?: any) => Promise<void>;
10
+ assess: (assessment: string, skipRationale?: boolean) => Promise<void>;
11
11
  vote: (v: string) => Promise<void>;
12
12
  selectedVote: string;
13
13
  };
@@ -4,8 +4,8 @@ import { useAppUser } from '@cccsaurora/howler-ui/commons/components/app/hooks';
4
4
  import AssignUserDrawer from '@cccsaurora/howler-ui/components/app/drawers/AssignUserDrawer';
5
5
  import { ApiConfigContext } from '@cccsaurora/howler-ui/components/app/providers/ApiConfigProvider';
6
6
  import { AppDrawerContext } from '@cccsaurora/howler-ui/components/app/providers/AppDrawerProvider';
7
+ import { HitContext } from '@cccsaurora/howler-ui/components/app/providers/HitProvider';
7
8
  import { ModalContext } from '@cccsaurora/howler-ui/components/app/providers/ModalProvider';
8
- import { RecordContext } from '@cccsaurora/howler-ui/components/app/providers/RecordProvider';
9
9
  import RationaleModal from '@cccsaurora/howler-ui/components/elements/display/modals/RationaleModal';
10
10
  import { useCallback, useContext, useMemo, useState } from 'react';
11
11
  import { useTranslation } from 'react-i18next';
@@ -31,7 +31,7 @@ const useHitActions = (_hits) => {
31
31
  const { showModal } = useContext(ModalContext);
32
32
  const { showWarningMessage } = useMySnackbar();
33
33
  const { dispatchApi } = useMyApi();
34
- const updateHit = useContextSelector(RecordContext, ctx => ctx.updateRecord);
34
+ const updateHit = useContextSelector(HitContext, ctx => ctx.updateHit);
35
35
  const [loading, setLoading] = useState(false);
36
36
  const hits = useMemo(() => (Array.isArray(_hits) ? _hits : [_hits]).filter(_hit => !!_hit), [_hits]);
37
37
  const canVote = useMemo(() => hits.every(hit => hit?.howler.assignment !== user.username || hit?.howler.status === 'in-progress'), [hits, user.username]);
@@ -90,9 +90,9 @@ const useHitActions = (_hits) => {
90
90
  }
91
91
  }
92
92
  }, [dispatchApi, hits, selectedVote, updateHit, user.email]);
93
- const assess = useCallback(async (assessment, skipRationale = false, providedRationale = null) => {
93
+ const assess = useCallback(async (assessment, skipRationale = false) => {
94
94
  const rationale = skipRationale
95
- ? (providedRationale ?? t('rationale.default', { assessment }))
95
+ ? t('rationale.default', { assessment })
96
96
  : await new Promise(res => {
97
97
  showModal(_jsx(RationaleModal, { hits: hits, onSubmit: _rationale => {
98
98
  res(_rationale);
@@ -1,8 +1,8 @@
1
1
  import type { Hit } from '@cccsaurora/howler-ui/models/entities/generated/Hit';
2
2
  import type React from 'react';
3
- declare const useRecordSelection: () => {
3
+ declare const useHitSelection: () => {
4
4
  lastSelected: string;
5
5
  setLastSelected: React.Dispatch<React.SetStateAction<string>>;
6
6
  onClick: (e: React.MouseEvent<HTMLDivElement>, hit: Hit) => void;
7
7
  };
8
- export default useRecordSelection;
8
+ export default useHitSelection;
@@ -1,14 +1,20 @@
1
+ import { useAppBreadcrumbs } from '@cccsaurora/howler-ui/commons/components/app/hooks';
2
+ import { HitContext } from '@cccsaurora/howler-ui/components/app/providers/HitProvider';
3
+ import { HitSearchContext } from '@cccsaurora/howler-ui/components/app/providers/HitSearchProvider';
1
4
  import { ParameterContext } from '@cccsaurora/howler-ui/components/app/providers/ParameterProvider';
2
- import { RecordContext } from '@cccsaurora/howler-ui/components/app/providers/RecordProvider';
3
- import { RecordSearchContext } from '@cccsaurora/howler-ui/components/app/providers/RecordSearchProvider';
5
+ import useMySitemap from '@cccsaurora/howler-ui/components/hooks/useMySitemap';
4
6
  import { useCallback, useState } from 'react';
7
+ import { useNavigate } from 'react-router-dom';
5
8
  import { useContextSelector } from 'use-context-selector';
6
- const useRecordSelection = () => {
7
- const response = useContextSelector(RecordSearchContext, ctx => ctx.response);
8
- const selectedHits = useContextSelector(RecordContext, ctx => ctx.selectedRecords);
9
- const addHitToSelection = useContextSelector(RecordContext, ctx => ctx.addRecordToSelection);
10
- const removeHitFromSelection = useContextSelector(RecordContext, ctx => ctx.removeRecordFromSelection);
11
- const clearSelectedHits = useContextSelector(RecordContext, ctx => ctx.clearSelectedRecords);
9
+ const useHitSelection = () => {
10
+ const navigate = useNavigate();
11
+ const { setItems } = useAppBreadcrumbs();
12
+ const { routes } = useMySitemap();
13
+ const response = useContextSelector(HitSearchContext, ctx => ctx.response);
14
+ const selectedHits = useContextSelector(HitContext, ctx => ctx.selectedHits);
15
+ const addHitToSelection = useContextSelector(HitContext, ctx => ctx.addHitToSelection);
16
+ const removeHitFromSelection = useContextSelector(HitContext, ctx => ctx.removeHitFromSelection);
17
+ const clearSelectedHits = useContextSelector(HitContext, ctx => ctx.clearSelectedHits);
12
18
  const setSelected = useContextSelector(ParameterContext, ctx => ctx.setSelected);
13
19
  const [lastSelected, setLastSelected] = useState(null);
14
20
  const onClick = useCallback((e, hit) => {
@@ -41,17 +47,32 @@ const useRecordSelection = () => {
41
47
  e.stopPropagation();
42
48
  return;
43
49
  }
44
- clearSelectedHits(hit.howler.id);
45
- setSelected(hit.howler.id);
50
+ if (hit.howler.is_bundle) {
51
+ const searchRoute = routes.find(_route => _route.path.startsWith(location.pathname.replace(/^(\/.*)\/.+/, '$1')));
52
+ const newBreadcrumb = {
53
+ ...searchRoute,
54
+ path: location.pathname + location.search
55
+ };
56
+ setItems([{ route: newBreadcrumb, matcher: null }]);
57
+ navigate(`/bundles/${hit.howler.id}?span=date.range.all&query=howler.id%3A*&offset=0`);
58
+ clearSelectedHits(hit.howler.id);
59
+ }
60
+ else {
61
+ clearSelectedHits(hit.howler.id);
62
+ setSelected(hit.howler.id);
63
+ }
46
64
  }, [
47
65
  addHitToSelection,
48
66
  clearSelectedHits,
49
67
  lastSelected,
68
+ navigate,
50
69
  removeHitFromSelection,
51
- response?.items,
70
+ response,
71
+ routes,
52
72
  selectedHits,
73
+ setItems,
53
74
  setSelected
54
75
  ]);
55
76
  return { lastSelected, setLastSelected, onClick };
56
77
  };
57
- export default useRecordSelection;
78
+ export default useHitSelection;
@@ -1,5 +1,5 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- import { Api, Article, Book, BookRounded, Code, Dashboard, Description, ExitToApp, FormatListBulleted, Help, HelpCenter, Key, ManageSearch, QueryStats, SavedSearch, Search, Settings, SettingsSuggest, Shield, Storage, SupervisorAccount, Terminal, Topic } from '@mui/icons-material';
2
+ import { Api, Article, Book, Code, Dashboard, Description, ExitToApp, FormatListBulleted, Help, HelpCenter, Key, ManageSearch, QueryStats, SavedSearch, Search, Settings, SettingsSuggest, Shield, Storage, SupervisorAccount, Terminal, Topic } from '@mui/icons-material';
3
3
  import { Stack } from '@mui/material';
4
4
  import { AppBrand } from '@cccsaurora/howler-ui/branding/AppBrand';
5
5
  import { AppBarContext } from '@cccsaurora/howler-ui/components/app/providers/AppBarProvider';
@@ -24,15 +24,6 @@ const useMyPreferences = () => {
24
24
  icon: _jsx(Dashboard, {})
25
25
  }
26
26
  },
27
- {
28
- type: 'item',
29
- element: {
30
- id: 'cases',
31
- i18nKey: 'route.cases',
32
- route: '/cases',
33
- icon: _jsx(BookRounded, {})
34
- }
35
- },
36
27
  {
37
28
  type: 'group',
38
29
  element: {
@@ -285,7 +276,8 @@ const useMyPreferences = () => {
285
276
  rightBeforeSearch: (_jsxs(Stack, { direction: "row", spacing: 1, alignItems: "center", pr: 1, children: [rightItems.map(item => (_jsx(Fragment, { children: item.component }, item.id))), _jsx(Classification, {})] }))
286
277
  },
287
278
  leftnav: {
288
- elements: MENU_ITEMS
279
+ elements: MENU_ITEMS,
280
+ width: 280
289
281
  }
290
282
  }), [USER_MENU_ITEMS, ADMIN_MENU_ITEMS, MENU_ITEMS, leftItems, rightItems]);
291
283
  };
@@ -1,7 +1,7 @@
1
1
  import { jsx as _jsx } from "react/jsx-runtime";
2
2
  import { Alert, Box, Typography } from '@mui/material';
3
3
  import api from '@cccsaurora/howler-ui/api';
4
- import HitPreview from '@cccsaurora/howler-ui/components/elements/hit/HitPreview';
4
+ import HitQuickSearch from '@cccsaurora/howler-ui/components/elements/hit/HitQuickSearch';
5
5
  import { useMemo } from 'react';
6
6
  import { useTranslation } from 'react-i18next';
7
7
  import { Link, useNavigate } from 'react-router-dom';
@@ -40,7 +40,7 @@ const useMySearch = () => {
40
40
  },
41
41
  headerRenderer: (state) => (state.result?.error || !state.items) && (_jsx(Box, { sx: { p: 1, pb: 0, textAlign: 'center' }, children: state.result?.error ? (_jsx(Alert, { severity: "error", color: "error", children: t('hit.search.invalid') })) : ((!state.items || state.items.length === 0) && (_jsx(Typography, { sx: { mb: -1, color: 'text.secondary' }, children: t('hit.quicksearch') }))) })),
42
42
  itemRenderer: (item, options) => {
43
- return (_jsx(Link, { to: `/hits/${item.id}`, style: { flex: 1, textDecoration: 'none', color: 'inherit', overflow: 'hidden' }, children: _jsx(HitPreview, { hit: item.item, options: options }) }));
43
+ return (_jsx(Link, { to: `/hits/${item.id}`, style: { flex: 1, textDecoration: 'none', color: 'inherit', overflow: 'hidden' }, children: _jsx(HitQuickSearch, { hit: item.item, options: options }) }));
44
44
  }
45
45
  }), [navigate, pageCount, t]);
46
46
  };
@@ -1,5 +1,5 @@
1
1
  import { jsx as _jsx } from "react/jsx-runtime";
2
- import { Article, Book, BookRounded, Code, CreateNewFolder, Dashboard, Description, Edit, EditNote, FormatListBulleted, Help, Info, Key, Person, PersonSearch, QueryStats, SavedSearch, Search, Settings, SettingsSuggest, Shield, Storage, Terminal, Topic, Work } from '@mui/icons-material';
2
+ import { Article, Book, Code, CreateNewFolder, Dashboard, Description, Edit, EditNote, FormatListBulleted, Help, Info, Key, Person, PersonSearch, QueryStats, SavedSearch, Search, Settings, SettingsSuggest, Shield, Storage, Terminal, Topic, Work } from '@mui/icons-material';
3
3
  import howlerPluginStore from '@cccsaurora/howler-ui/plugins/store';
4
4
  import { useMemo } from 'react';
5
5
  import { useTranslation } from 'react-i18next';
@@ -24,9 +24,6 @@ const useMySitemap = () => {
24
24
  return useMemo(() => ({
25
25
  routes: [
26
26
  { path: '/', title: t('route.home'), isRoot: true, icon: _jsx(Dashboard, {}) },
27
- { path: '/cases', title: t('route.cases'), isRoot: true, icon: _jsx(BookRounded, {}) },
28
- { path: '/cases/:id', title: t('route.cases.view'), breadcrumbs: ['/cases'] },
29
- { path: '/cases/:id/*', title: t('route.cases.view'), isLeaf: true, breadcrumbs: ['/cases'] },
30
27
  { path: '/admin/users', title: t('route.admin.user.search'), isRoot: true, icon: _jsx(PersonSearch, {}) },
31
28
  {
32
29
  path: '/admin/users/:id',
@@ -1,16 +1,9 @@
1
1
  const DEFAULT_THEME = {
2
- components: {
3
- MuiChip: {
4
- defaultProps: {
5
- size: 'small'
6
- }
7
- }
8
- },
9
2
  palette: {
10
3
  dark: {
11
4
  background: {
12
- default: '#181818',
13
- paper: '#181818'
5
+ default: '#202020',
6
+ paper: '#202020'
14
7
  },
15
8
  primary: {
16
9
  main: '#7DA1DB'
@@ -0,0 +1,27 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ /// <reference types="vitest" />
3
+ import { render, screen } from '@testing-library/react';
4
+ import i18n from '@cccsaurora/howler-ui/i18n';
5
+ import { I18nextProvider } from 'react-i18next';
6
+ import { describe, expect, it, vi } from 'vitest';
7
+ import PermissionDeniedPage from './403';
8
+ vi.mock('commons/components/pages/PageCenter', () => ({
9
+ default: ({ children }) => _jsx("div", { id: "page-center", children: children })
10
+ }));
11
+ const Wrapper = ({ children }) => (_jsx(I18nextProvider, { i18n: i18n, children: children }));
12
+ describe('PermissionDeniedPage (403)', () => {
13
+ it('should render the 403 title and description', () => {
14
+ render(_jsx(PermissionDeniedPage, {}), { wrapper: Wrapper });
15
+ expect(screen.getByText('403: Access Forbidden')).toBeInTheDocument();
16
+ expect(screen.getByText('You do not have permission to access this page.')).toBeInTheDocument();
17
+ });
18
+ it('should render inside PageCenter', () => {
19
+ render(_jsx(PermissionDeniedPage, {}), { wrapper: Wrapper });
20
+ expect(screen.getByTestId('page-center')).toBeInTheDocument();
21
+ });
22
+ it('should render the PersonOff icon', () => {
23
+ render(_jsx(PermissionDeniedPage, {}), { wrapper: Wrapper });
24
+ // MUI SVG icons have data-testid attribute
25
+ expect(document.querySelector('[data-testid="PersonOffIcon"]')).toBeInTheDocument();
26
+ });
27
+ });
@@ -0,0 +1,26 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ /// <reference types="vitest" />
3
+ import { render, screen } from '@testing-library/react';
4
+ import i18n from '@cccsaurora/howler-ui/i18n';
5
+ import { I18nextProvider } from 'react-i18next';
6
+ import { describe, expect, it, vi } from 'vitest';
7
+ import NotFoundPage from './404';
8
+ vi.mock('commons/components/pages/PageCenter', () => ({
9
+ default: ({ children }) => _jsx("div", { id: "page-center", children: children })
10
+ }));
11
+ const Wrapper = ({ children }) => (_jsx(I18nextProvider, { i18n: i18n, children: children }));
12
+ describe('NotFoundPage (404)', () => {
13
+ it('should render the 404 title and description', () => {
14
+ render(_jsx(NotFoundPage, {}), { wrapper: Wrapper });
15
+ expect(screen.getByText('404: Not found')).toBeInTheDocument();
16
+ expect(screen.getByText('The page you are looking for cannot be found...')).toBeInTheDocument();
17
+ });
18
+ it('should render inside PageCenter', () => {
19
+ render(_jsx(NotFoundPage, {}), { wrapper: Wrapper });
20
+ expect(screen.getByTestId('page-center')).toBeInTheDocument();
21
+ });
22
+ it('should render the LinkOff icon', () => {
23
+ render(_jsx(NotFoundPage, {}), { wrapper: Wrapper });
24
+ expect(document.querySelector('[data-testid="LinkOffIcon"]')).toBeInTheDocument();
25
+ });
26
+ });
@@ -0,0 +1,43 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ /// <reference types="vitest" />
3
+ import { render, screen } from '@testing-library/react';
4
+ import i18n from '@cccsaurora/howler-ui/i18n';
5
+ import { I18nextProvider } from 'react-i18next';
6
+ import { describe, expect, it, vi } from 'vitest';
7
+ import ErrorBoundary from './ErrorBoundary';
8
+ vi.mock('commons/components/pages/PageCenter', () => ({
9
+ default: ({ children }) => _jsx("div", { id: "page-center", children: children })
10
+ }));
11
+ vi.mock('react-pluggable', () => ({
12
+ usePluginStore: () => ({
13
+ executeFunction: vi.fn(() => null)
14
+ })
15
+ }));
16
+ vi.mock('plugins/store', () => ({
17
+ default: { plugins: [] }
18
+ }));
19
+ const Wrapper = ({ children }) => (_jsx(I18nextProvider, { i18n: i18n, children: children }));
20
+ const ThrowingComponent = ({ error }) => {
21
+ throw error;
22
+ };
23
+ describe('ErrorBoundary', () => {
24
+ it('should render children when no error occurs', () => {
25
+ render(_jsx(ErrorBoundary, { children: _jsx("div", { children: "Child content" }) }), { wrapper: Wrapper });
26
+ expect(screen.getByText('Child content')).toBeInTheDocument();
27
+ });
28
+ it('should render error UI when a child throws', () => {
29
+ const consoleSpy = vi.spyOn(console, 'error').mockImplementation(() => { });
30
+ const testError = new Error('Test error message');
31
+ testError.stack = 'Error: Test error message\n at TestComponent';
32
+ render(_jsx(ErrorBoundary, { children: _jsx(ThrowingComponent, { error: testError }) }), { wrapper: Wrapper });
33
+ expect(screen.getByText('Test error message')).toBeInTheDocument();
34
+ consoleSpy.mockRestore();
35
+ });
36
+ it('should display the error page title when an error occurs', () => {
37
+ const consoleSpy = vi.spyOn(console, 'error').mockImplementation(() => { });
38
+ const testError = new Error('Something went wrong');
39
+ render(_jsx(ErrorBoundary, { children: _jsx(ThrowingComponent, { error: testError }) }), { wrapper: Wrapper });
40
+ expect(screen.getByText('Application Stopped Working')).toBeInTheDocument();
41
+ consoleSpy.mockRestore();
42
+ });
43
+ });