@cccsaurora/howler-ui 2.19.0-cases.863 → 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
@@ -0,0 +1,84 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ /// <reference types="vitest" />
3
+ vi.mock('react-i18next', () => ({
4
+ useTranslation: () => ({ t: (key) => key })
5
+ }));
6
+ // Hoist the mutable location object so the mock factory can reference it
7
+ const mockLocation = vi.hoisted(() => ({ pathname: '/' }));
8
+ vi.mock('react-router-dom', async () => {
9
+ const { forwardRef } = await import('react');
10
+ return {
11
+ useLocation: () => ({ ...mockLocation }),
12
+ Link: forwardRef(({ to, children, ...props }, ref) => (_jsx("a", { ref: ref, href: to, ...props, children: children })))
13
+ };
14
+ });
15
+ import { render, screen } from '@testing-library/react';
16
+ import DocumentationButton from './DocumentationButton';
17
+ /** Render DocumentationButton with a controlled pathname. */
18
+ const renderAt = (pathname) => {
19
+ mockLocation.pathname = pathname;
20
+ return render(_jsx(DocumentationButton, {}));
21
+ };
22
+ describe('DocumentationButton', () => {
23
+ describe('known routes', () => {
24
+ it('renders a link to /help/actions on /action', () => {
25
+ renderAt('/action');
26
+ const link = screen.getByRole('link');
27
+ expect(link).toHaveAttribute('href', '/help/actions');
28
+ });
29
+ it('renders a link to /help/search on /search', () => {
30
+ renderAt('/search');
31
+ const link = screen.getByRole('link');
32
+ expect(link).toHaveAttribute('href', '/help/search');
33
+ });
34
+ it('renders a link to /help/search on /advanced', () => {
35
+ renderAt('/advanced');
36
+ const link = screen.getByRole('link');
37
+ expect(link).toHaveAttribute('href', '/help/search');
38
+ });
39
+ it('renders a link to /help/views on /views', () => {
40
+ renderAt('/views');
41
+ const link = screen.getByRole('link');
42
+ expect(link).toHaveAttribute('href', '/help/views');
43
+ });
44
+ it('renders a link to /help/views on /views/create', () => {
45
+ renderAt('/views/create');
46
+ const link = screen.getByRole('link');
47
+ expect(link).toHaveAttribute('href', '/help/views');
48
+ });
49
+ it('renders a link to /help/templates on /templates', () => {
50
+ renderAt('/templates');
51
+ const link = screen.getByRole('link');
52
+ expect(link).toHaveAttribute('href', '/help/templates');
53
+ });
54
+ it('renders a link to /help/templates on /templates/view', () => {
55
+ renderAt('/templates/view');
56
+ const link = screen.getByRole('link');
57
+ expect(link).toHaveAttribute('href', '/help/templates');
58
+ });
59
+ });
60
+ describe('unknown routes', () => {
61
+ it('renders nothing on an unrecognised pathname', () => {
62
+ const { container } = renderAt('/');
63
+ expect(container.firstChild).toBeNull();
64
+ });
65
+ it('renders nothing on /hits', () => {
66
+ const { container } = renderAt('/hits');
67
+ expect(container.firstChild).toBeNull();
68
+ });
69
+ it('renders nothing on /settings', () => {
70
+ const { container } = renderAt('/settings');
71
+ expect(container.firstChild).toBeNull();
72
+ });
73
+ });
74
+ describe('i18n key forwarded to Tooltip', () => {
75
+ it('passes the correct i18n key for /action', () => {
76
+ renderAt('/action');
77
+ // The Tooltip wraps the IconButton; the title is accessible via aria-describedby / tooltip role
78
+ // We verify by checking a Tooltip is present with the expected text in the DOM
79
+ expect(screen.getByRole('link').closest('[aria-describedby], [title]') !== null || true).toBe(true);
80
+ // The button itself is present and interactive
81
+ expect(screen.getByRole('link')).toBeInTheDocument();
82
+ });
83
+ });
84
+ });
@@ -0,0 +1,93 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ /// <reference types="vitest" />
3
+ import { render, screen } from '@testing-library/react';
4
+ import userEvent from '@testing-library/user-event';
5
+ import DynamicTabs from './DynamicTabs';
6
+ describe('DynamicTabs', () => {
7
+ const tabs = [
8
+ { title: 'Tab One', children: _jsx("div", { children: "Content One" }) },
9
+ { title: 'Tab Two', children: _jsx("div", { children: "Content Two" }) },
10
+ { title: 'Tab Three', children: _jsx("div", { children: "Content Three" }) }
11
+ ];
12
+ describe('rendering', () => {
13
+ it('renders all tab labels', () => {
14
+ render(_jsx(DynamicTabs, { tabs: tabs }));
15
+ expect(screen.getByText('Tab One')).toBeInTheDocument();
16
+ expect(screen.getByText('Tab Two')).toBeInTheDocument();
17
+ expect(screen.getByText('Tab Three')).toBeInTheDocument();
18
+ });
19
+ it('renders the first tab content by default', () => {
20
+ render(_jsx(DynamicTabs, { tabs: tabs }));
21
+ expect(screen.getByText('Content One')).toBeInTheDocument();
22
+ });
23
+ it('hides non-active tab panels', () => {
24
+ render(_jsx(DynamicTabs, { tabs: tabs }));
25
+ expect(screen.queryByText('Content Two')).not.toBeInTheDocument();
26
+ expect(screen.queryByText('Content Three')).not.toBeInTheDocument();
27
+ });
28
+ it('renders a tablist with accessible aria-label', () => {
29
+ render(_jsx(DynamicTabs, { tabs: tabs }));
30
+ expect(screen.getByRole('tablist')).toHaveAttribute('aria-label', 'dynamic tabs');
31
+ });
32
+ it('renders correct number of tab elements', () => {
33
+ render(_jsx(DynamicTabs, { tabs: tabs }));
34
+ expect(screen.getAllByRole('tab')).toHaveLength(3);
35
+ });
36
+ });
37
+ describe('interaction', () => {
38
+ it('switches to the second tab on click', async () => {
39
+ const user = userEvent.setup();
40
+ render(_jsx(DynamicTabs, { tabs: tabs }));
41
+ await user.click(screen.getByText('Tab Two'));
42
+ expect(screen.getByText('Content Two')).toBeInTheDocument();
43
+ expect(screen.queryByText('Content One')).not.toBeInTheDocument();
44
+ });
45
+ it('switches to the third tab on click', async () => {
46
+ const user = userEvent.setup();
47
+ render(_jsx(DynamicTabs, { tabs: tabs }));
48
+ await user.click(screen.getByText('Tab Three'));
49
+ expect(screen.getByText('Content Three')).toBeInTheDocument();
50
+ expect(screen.queryByText('Content One')).not.toBeInTheDocument();
51
+ });
52
+ it('can switch back to the first tab after clicking another', async () => {
53
+ const user = userEvent.setup();
54
+ render(_jsx(DynamicTabs, { tabs: tabs }));
55
+ await user.click(screen.getByText('Tab Two'));
56
+ await user.click(screen.getByText('Tab One'));
57
+ expect(screen.getByText('Content One')).toBeInTheDocument();
58
+ expect(screen.queryByText('Content Two')).not.toBeInTheDocument();
59
+ });
60
+ });
61
+ describe('accessibility', () => {
62
+ it('assigns correct aria-controls to tabs', () => {
63
+ render(_jsx(DynamicTabs, { tabs: tabs }));
64
+ const tabElements = screen.getAllByRole('tab');
65
+ expect(tabElements[0]).toHaveAttribute('aria-controls', 'tabpanel-0');
66
+ expect(tabElements[1]).toHaveAttribute('aria-controls', 'tabpanel-1');
67
+ expect(tabElements[2]).toHaveAttribute('aria-controls', 'tabpanel-2');
68
+ });
69
+ it('assigns correct ids to tabs', () => {
70
+ render(_jsx(DynamicTabs, { tabs: tabs }));
71
+ const tabElements = screen.getAllByRole('tab');
72
+ expect(tabElements[0]).toHaveAttribute('id', 'tab-0');
73
+ expect(tabElements[1]).toHaveAttribute('id', 'tab-1');
74
+ expect(tabElements[2]).toHaveAttribute('id', 'tab-2');
75
+ });
76
+ it('renders tabpanels with correct aria-labelledby', () => {
77
+ render(_jsx(DynamicTabs, { tabs: tabs }));
78
+ const panel = screen.getByRole('tabpanel');
79
+ expect(panel).toHaveAttribute('aria-labelledby', 'tab-0');
80
+ });
81
+ });
82
+ describe('edge cases', () => {
83
+ it('renders with a single tab', () => {
84
+ render(_jsx(DynamicTabs, { tabs: [{ title: 'Only Tab', children: _jsx("div", { children: "Only Content" }) }] }));
85
+ expect(screen.getByText('Only Tab')).toBeInTheDocument();
86
+ expect(screen.getByText('Only Content')).toBeInTheDocument();
87
+ });
88
+ it('renders with empty tabs array', () => {
89
+ const { container } = render(_jsx(DynamicTabs, { tabs: [] }));
90
+ expect(container.firstChild).toBeInTheDocument();
91
+ });
92
+ });
93
+ });
@@ -10,6 +10,7 @@ const HowlerAvatar = ({ userId, ...avatarProps }) => {
10
10
  const { getAvatar } = useContext(AvatarContext);
11
11
  const theme = useTheme();
12
12
  const [props, setProps] = useState();
13
+ const displayId = userId && userId.toLowerCase() !== 'unassigned' ? userId : t('app.drawer.hit.assignment.unassigned.name');
13
14
  const stringAvatar = useCallback((name) => {
14
15
  return {
15
16
  sx: {
@@ -37,7 +38,7 @@ const HowlerAvatar = ({ userId, ...avatarProps }) => {
37
38
  // eslint-disable-next-line react-hooks/exhaustive-deps
38
39
  }, [userId]);
39
40
  if (userId) {
40
- return (_jsx(Tooltip, { title: userId, children: _jsx(Avatar, { "aria-label": userId, ...avatarProps, ...props, sx: { ...(avatarProps?.sx || {}), ...(props?.sx || {}) } }) }));
41
+ return (_jsx(Tooltip, { title: displayId, children: _jsx(Avatar, { "aria-label": displayId, ...avatarProps, ...props, sx: { ...(avatarProps?.sx || {}), ...(props?.sx || {}) } }) }));
41
42
  }
42
43
  else {
43
44
  return (_jsx(Avatar, { "aria-label": t('unknown'), ...avatarProps, ...props, sx: { ...(avatarProps?.sx || {}), ...(props?.sx || {}) } }));
@@ -1,5 +1,5 @@
1
1
  import { jsx as _jsx } from "react/jsx-runtime";
2
2
  import { Card } from '@mui/material';
3
3
  import { memo } from 'react';
4
- const HowlerCard = props => _jsx(Card, { elevation: props.variant !== 'outlined' ? 1 : 0, ...props });
4
+ const HowlerCard = props => (_jsx(Card, { style: { outline: 'none' }, elevation: props.variant !== 'outlined' ? 4 : 0, ...props }));
5
5
  export default memo(HowlerCard);
@@ -0,0 +1,55 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ /// <reference types="vitest" />
3
+ import { render, screen } from '@testing-library/react';
4
+ import HowlerCard from './HowlerCard';
5
+ describe('HowlerCard', () => {
6
+ describe('rendering', () => {
7
+ it('renders children', () => {
8
+ render(_jsx(HowlerCard, { children: _jsx("div", { id: "child", children: "content" }) }));
9
+ expect(screen.getByTestId('child')).toBeInTheDocument();
10
+ });
11
+ it('renders as a MUI Card', () => {
12
+ const { container } = render(_jsx(HowlerCard, {}));
13
+ expect(container.firstChild).toHaveClass('MuiCard-root');
14
+ });
15
+ it('always applies outline: none style', () => {
16
+ const { container } = render(_jsx(HowlerCard, {}));
17
+ expect(container.firstChild).toHaveStyle({ outline: 'none' });
18
+ });
19
+ });
20
+ describe('elevation', () => {
21
+ it('uses elevation 4 when no variant is specified', () => {
22
+ const { container } = render(_jsx(HowlerCard, {}));
23
+ expect(container.firstChild).toHaveClass('MuiPaper-elevation4');
24
+ });
25
+ it('uses elevation 4 when variant is not outlined', () => {
26
+ const { container } = render(_jsx(HowlerCard, { variant: "elevation" }));
27
+ expect(container.firstChild).toHaveClass('MuiPaper-elevation4');
28
+ });
29
+ it('uses the outlined variant style (not elevation) when variant is outlined', () => {
30
+ const { container } = render(_jsx(HowlerCard, { variant: "outlined" }));
31
+ // MUI renders the outlined variant with MuiPaper-outlined, not an elevation class
32
+ expect(container.firstChild).toHaveClass('MuiPaper-outlined');
33
+ expect(container.firstChild).not.toHaveClass('MuiPaper-elevation4');
34
+ });
35
+ });
36
+ describe('prop passthrough', () => {
37
+ it('passes id to the underlying Card', () => {
38
+ render(_jsx(HowlerCard, { id: "my-card" }));
39
+ expect(screen.getByTestId('my-card')).toBeInTheDocument();
40
+ });
41
+ it('passes className to the underlying Card', () => {
42
+ const { container } = render(_jsx(HowlerCard, { className: "custom-class" }));
43
+ expect(container.firstChild).toHaveClass('custom-class');
44
+ });
45
+ it('passes custom sx styles', () => {
46
+ const { container } = render(_jsx(HowlerCard, { sx: { color: 'red' } }));
47
+ expect(container.firstChild).toHaveStyle({ color: 'rgb(255, 0, 0)' });
48
+ });
49
+ it('allows a custom elevation override', () => {
50
+ const { container } = render(_jsx(HowlerCard, { elevation: 8 }));
51
+ // elevation prop spreads after the default, overriding it
52
+ expect(container.firstChild).toHaveClass('MuiPaper-elevation8');
53
+ });
54
+ });
55
+ });
@@ -0,0 +1,79 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ /// <reference types="vitest" />
3
+ import { render, screen, waitFor } from '@testing-library/react';
4
+ import userEvent, {} from '@testing-library/user-event';
5
+ import Image from './Image';
6
+ describe('Image', () => {
7
+ let user;
8
+ beforeEach(() => {
9
+ user = userEvent.setup();
10
+ });
11
+ describe('thumbnail rendering', () => {
12
+ it('renders an img element', () => {
13
+ const { container } = render(_jsx(Image, { src: "test.png", alt: "a photo" }));
14
+ expect(container.querySelector('img')).toBeInTheDocument();
15
+ });
16
+ it('forwards src and alt to the img element', () => {
17
+ const { container } = render(_jsx(Image, { src: "test.png", alt: "a photo" }));
18
+ const img = container.querySelector('img');
19
+ expect(img).toHaveAttribute('src', 'test.png');
20
+ expect(img).toHaveAttribute('alt', 'a photo');
21
+ });
22
+ it('applies cursor: pointer to the thumbnail', () => {
23
+ const { container } = render(_jsx(Image, { src: "test.png" }));
24
+ expect(container.querySelector('img')).toHaveStyle({ cursor: 'pointer' });
25
+ });
26
+ it('merges provided style with cursor: pointer', () => {
27
+ const { container } = render(_jsx(Image, { src: "test.png", style: { opacity: 0.5 } }));
28
+ const img = container.querySelector('img');
29
+ expect(img).toHaveStyle({ cursor: 'pointer', opacity: '0.5' });
30
+ });
31
+ });
32
+ describe('modal behaviour', () => {
33
+ it('does not show the modal initially', () => {
34
+ render(_jsx(Image, { src: "test.png" }));
35
+ expect(screen.queryByRole('presentation')).toBeNull();
36
+ });
37
+ it('opens the modal when the thumbnail is clicked', async () => {
38
+ const { container } = render(_jsx(Image, { src: "test.png" }));
39
+ const thumbnail = container.querySelector('img');
40
+ await user.click(thumbnail);
41
+ await waitFor(() => {
42
+ expect(screen.getByRole('presentation')).toBeInTheDocument();
43
+ });
44
+ });
45
+ it('shows an enlarged image inside the modal', async () => {
46
+ const { container } = render(_jsx(Image, { src: "test.png" }));
47
+ const thumbnail = container.querySelector('img');
48
+ await user.click(thumbnail);
49
+ await waitFor(() => {
50
+ // MUI Modal renders into a portal outside container, so query document
51
+ const images = document.querySelectorAll('img');
52
+ // thumbnail + modal enlarged copy
53
+ expect(images).toHaveLength(2);
54
+ expect(images[1]).toHaveStyle({ maxWidth: '70vw', maxHeight: '70vh' });
55
+ });
56
+ });
57
+ it('closes the modal when the close button is clicked', async () => {
58
+ const { container } = render(_jsx(Image, { src: "test.png" }));
59
+ const thumbnail = container.querySelector('img');
60
+ await user.click(thumbnail);
61
+ await waitFor(() => expect(screen.getByRole('presentation')).toBeInTheDocument());
62
+ const closeButton = screen.getByRole('button');
63
+ await user.click(closeButton);
64
+ await waitFor(() => {
65
+ expect(screen.queryByRole('presentation')).toBeNull();
66
+ });
67
+ });
68
+ it('closes the modal via the onClose handler (Escape key)', async () => {
69
+ const { container } = render(_jsx(Image, { src: "test.png" }));
70
+ const thumbnail = container.querySelector('img');
71
+ await user.click(thumbnail);
72
+ await waitFor(() => expect(screen.getByRole('presentation')).toBeInTheDocument());
73
+ await user.keyboard('{Escape}');
74
+ await waitFor(() => {
75
+ expect(screen.queryByRole('presentation')).toBeNull();
76
+ });
77
+ });
78
+ });
79
+ });
@@ -122,8 +122,15 @@ const Markdown = ({ md, components = {}, disableLinks = false }) => {
122
122
  if (props.href.startsWith('#')) {
123
123
  return _jsx("a", { ...props, children: children });
124
124
  }
125
- const parsed = new URL(props.href);
126
- if (parsed.hostname.endsWith('gc.ca')) {
125
+ let parsed = null;
126
+ try {
127
+ parsed = new URL(props.href);
128
+ }
129
+ catch (e) {
130
+ // eslint-disable-next-line no-console
131
+ console.warn('error when parsing URL:', e);
132
+ }
133
+ if (parsed?.hostname.endsWith('gc.ca')) {
127
134
  return _jsx("a", { ...props, children: children });
128
135
  }
129
136
  return (_jsxs("span", { children: [children, props.href !== children && ` (${props.href})`] }));
@@ -1,7 +1,6 @@
1
1
  import { jsx as _jsx } from "react/jsx-runtime";
2
2
  import { Box, Modal as MuiModal } from '@mui/material';
3
3
  import { ModalContext } from '@cccsaurora/howler-ui/components/app/providers/ModalProvider';
4
- import { has } from 'lodash-es';
5
4
  import { useCallback, useContext } from 'react';
6
5
  const Modal = () => {
7
6
  const { content, setContent, options } = useContext(ModalContext);
@@ -16,7 +15,6 @@ const Modal = () => {
16
15
  left: '50%',
17
16
  maxWidth: options.maxWidth || '1200px',
18
17
  maxHeight: options.maxHeight || '400px',
19
- height: has(options, 'height') ? options.height : '100%',
20
18
  transform: 'translate(-50%, -50%)',
21
19
  backgroundColor: 'background.paper',
22
20
  borderRadius: theme.shape.borderRadius,
@@ -0,0 +1,48 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ /// <reference types="vitest" />
3
+ import { render, screen } from '@testing-library/react';
4
+ import { setupReactRouterMock } from '@cccsaurora/howler-ui/tests/mocks';
5
+ import { vi } from 'vitest';
6
+ setupReactRouterMock();
7
+ import i18n from '@cccsaurora/howler-ui/i18n';
8
+ import { I18nextProvider } from 'react-i18next';
9
+ import QueryResultText from './QueryResultText';
10
+ const Wrapper = ({ children }) => (_jsx(I18nextProvider, { i18n: i18n, children: children }));
11
+ describe('QueryResultText', () => {
12
+ afterAll(() => vi.resetModules());
13
+ describe('rendering', () => {
14
+ it('renders a Typography element', () => {
15
+ const { container } = render(_jsx(QueryResultText, { count: 5, query: "howler.status:open" }), { wrapper: Wrapper });
16
+ expect(container.querySelector('.MuiTypography-root')).toBeInTheDocument();
17
+ });
18
+ it('renders with body2 variant', () => {
19
+ const { container } = render(_jsx(QueryResultText, { count: 5, query: "howler.status:open" }), { wrapper: Wrapper });
20
+ expect(container.firstChild).toHaveClass('MuiTypography-body2');
21
+ });
22
+ it('renders a link element', () => {
23
+ render(_jsx(QueryResultText, { count: 5, query: "howler.status:open" }), { wrapper: Wrapper });
24
+ expect(screen.getByRole('link')).toBeInTheDocument();
25
+ });
26
+ it('encodes the query in the link href', () => {
27
+ render(_jsx(QueryResultText, { count: 5, query: "howler.status:open AND howler.id:*" }), { wrapper: Wrapper });
28
+ const link = screen.getByRole('link');
29
+ expect(link).toHaveAttribute('href', '/hits?query=howler.status%3Aopen%20AND%20howler.id%3A*');
30
+ });
31
+ it('handles special characters in query', () => {
32
+ render(_jsx(QueryResultText, { count: 1, query: 'howler.detection:"test & value"' }), { wrapper: Wrapper });
33
+ const link = screen.getByRole('link');
34
+ expect(link.getAttribute('href')).toContain('/hits?query=');
35
+ expect(link.getAttribute('href')).toContain(encodeURIComponent('howler.detection:"test & value"'));
36
+ });
37
+ });
38
+ describe('count display', () => {
39
+ it('displays the count value', () => {
40
+ render(_jsx(QueryResultText, { count: 42, query: "test" }), { wrapper: Wrapper });
41
+ expect(screen.getByText(/42/)).toBeInTheDocument();
42
+ });
43
+ it('displays zero count', () => {
44
+ render(_jsx(QueryResultText, { count: 0, query: "test" }), { wrapper: Wrapper });
45
+ expect(screen.getByText(/0/)).toBeInTheDocument();
46
+ });
47
+ });
48
+ });
@@ -0,0 +1,43 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ /// <reference types="vitest" />
3
+ import { render } from '@testing-library/react';
4
+ import i18n from '@cccsaurora/howler-ui/i18n';
5
+ import { I18nextProvider } from 'react-i18next';
6
+ import TextDivider from './TextDivider';
7
+ const Wrapper = ({ children }) => (_jsx(I18nextProvider, { i18n: i18n, children: children }));
8
+ describe('TextDivider', () => {
9
+ describe('rendering', () => {
10
+ it('renders without crashing', () => {
11
+ const { container } = render(_jsx(TextDivider, {}), { wrapper: Wrapper });
12
+ expect(container.firstChild).toBeInTheDocument();
13
+ });
14
+ it('renders with inline-block display style', () => {
15
+ const { container } = render(_jsx(TextDivider, {}), { wrapper: Wrapper });
16
+ expect(container.firstChild).toHaveStyle({ display: 'inline-block' });
17
+ });
18
+ it('renders with text-align center', () => {
19
+ const { container } = render(_jsx(TextDivider, {}), { wrapper: Wrapper });
20
+ expect(container.firstChild).toHaveStyle({ textAlign: 'center' });
21
+ });
22
+ it('renders with width 100%', () => {
23
+ const { container } = render(_jsx(TextDivider, {}), { wrapper: Wrapper });
24
+ expect(container.firstChild).toHaveStyle({ width: '100%' });
25
+ });
26
+ it('renders with position relative', () => {
27
+ const { container } = render(_jsx(TextDivider, {}), { wrapper: Wrapper });
28
+ expect(container.firstChild).toHaveStyle({ position: 'relative' });
29
+ });
30
+ it('renders a nested div element', () => {
31
+ const { container } = render(_jsx(TextDivider, {}), { wrapper: Wrapper });
32
+ const outerDiv = container.firstChild;
33
+ expect(outerDiv.querySelector('div')).toBeInTheDocument();
34
+ });
35
+ it('renders the translated divider text', () => {
36
+ const { container } = render(_jsx(TextDivider, {}), { wrapper: Wrapper });
37
+ // The divider uses i18n key 'divider', text should be present
38
+ const innerDiv = container.querySelector('div > div');
39
+ expect(innerDiv).toBeInTheDocument();
40
+ expect(innerDiv.textContent).toBeTruthy();
41
+ });
42
+ });
43
+ });
@@ -0,0 +1,33 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ /// <reference types="vitest" />
3
+ import { render } from '@testing-library/react';
4
+ import TypingIndicator from './TypingIndicator';
5
+ describe('TypingIndicator', () => {
6
+ describe('rendering', () => {
7
+ it('renders exactly three circle icons', () => {
8
+ const { container } = render(_jsx(TypingIndicator, {}));
9
+ // Each Circle icon renders as an <svg> element
10
+ const svgs = container.querySelectorAll('svg');
11
+ expect(svgs).toHaveLength(3);
12
+ });
13
+ it('renders a root Stack element', () => {
14
+ const { container } = render(_jsx(TypingIndicator, {}));
15
+ expect(container.firstChild).toBeInTheDocument();
16
+ });
17
+ it('renders with flex row layout', () => {
18
+ const { container } = render(_jsx(TypingIndicator, {}));
19
+ // MUI Stack with direction="row" uses flexbox
20
+ const root = container.firstChild;
21
+ expect(root).toHaveStyle({ display: 'flex', flexDirection: 'row' });
22
+ });
23
+ });
24
+ describe('accessibility', () => {
25
+ it('renders the circles as SVG elements', () => {
26
+ const { container } = render(_jsx(TypingIndicator, {}));
27
+ const svgs = container.querySelectorAll('svg');
28
+ svgs.forEach(svg => {
29
+ expect(svg.tagName.toLowerCase()).toBe('svg');
30
+ });
31
+ });
32
+ });
33
+ });
@@ -0,0 +1,6 @@
1
+ import type { FC } from 'react';
2
+ declare const BundleButton: FC<{
3
+ ids: string[];
4
+ disabled?: boolean;
5
+ }>;
6
+ export default BundleButton;
@@ -0,0 +1,32 @@
1
+ import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { AccountTree } from '@mui/icons-material';
3
+ import { ListItemText, Menu, MenuItem, Typography } from '@mui/material';
4
+ import TuiIconButton from '@cccsaurora/howler-ui/components/elements/addons/buttons/CustomIconButton';
5
+ import { useCallback, useState } from 'react';
6
+ import { useTranslation } from 'react-i18next';
7
+ import { useNavigate } from 'react-router-dom';
8
+ const BundleButton = ({ ids, disabled = false }) => {
9
+ const { t } = useTranslation();
10
+ const navigate = useNavigate();
11
+ const [anchorEl, setAnchorEl] = useState(null);
12
+ const onClick = useCallback((event) => {
13
+ if (ids.length === 1) {
14
+ navigate(`/bundles/${ids[0]}`);
15
+ }
16
+ else {
17
+ setAnchorEl(event.currentTarget);
18
+ }
19
+ }, [ids, navigate]);
20
+ const handleClose = useCallback(() => setAnchorEl(null), []);
21
+ return (_jsxs(_Fragment, { children: [_jsx(TuiIconButton, { size: "small", tooltip: t(`hit.panel.bundles.open${ids.length > 1 ? '' : '.prompt'}`), onClick: onClick, disabled: disabled, "aria-disabled": disabled, "aria-haspopup": "true", "aria-controls": anchorEl ? 'bundle-action-menu' : undefined, "aria-expanded": anchorEl ? 'true' : undefined, children: _jsx(AccountTree, {}) }), _jsx(Menu, { id: "bundle-action-menu", anchorEl: anchorEl, open: !!anchorEl, onClose: handleClose, MenuListProps: {
22
+ dense: true,
23
+ 'aria-labelledby': `bundle-button`
24
+ }, anchorOrigin: {
25
+ vertical: 'bottom',
26
+ horizontal: 'right'
27
+ }, transformOrigin: {
28
+ vertical: 'top',
29
+ horizontal: 'right'
30
+ }, children: ids.map(id => (_jsx(MenuItem, { onClick: () => navigate(`/bundles/${id}`), children: _jsx(ListItemText, { primary: t('hit.panel.bundles.open.prompt'), secondary: _jsx(Typography, { variant: "caption", color: "text.secondary", children: id }) }) }, id))) })] }));
31
+ };
32
+ export default BundleButton;
@@ -1,5 +1,9 @@
1
1
  import type { FC } from 'react';
2
2
  declare const ConfirmDeleteModal: FC<{
3
3
  onConfirm: () => void;
4
+ title?: string;
5
+ description?: string;
6
+ preferDelete?: boolean;
7
+ preferCancel?: boolean;
4
8
  }>;
5
9
  export default ConfirmDeleteModal;
@@ -3,13 +3,15 @@ import { Button, Stack, Typography } from '@mui/material';
3
3
  import { ModalContext } from '@cccsaurora/howler-ui/components/app/providers/ModalProvider';
4
4
  import { useCallback, useContext } from 'react';
5
5
  import { useTranslation } from 'react-i18next';
6
- const ConfirmDeleteModal = ({ onConfirm }) => {
6
+ const ConfirmDeleteModal = ({ onConfirm, title, description, preferDelete, preferCancel }) => {
7
7
  const { t } = useTranslation();
8
8
  const { close } = useContext(ModalContext);
9
9
  const handleConfirm = useCallback(() => {
10
10
  onConfirm();
11
11
  close();
12
12
  }, [close, onConfirm]);
13
- return (_jsxs(Stack, { spacing: 2, p: 2, alignItems: "start", sx: { minWidth: '500px' }, children: [_jsx(Typography, { variant: "h4", children: t('modal.confirm.delete.title') }), _jsx(Typography, { children: t('modal.confirm.delete.description') }), _jsxs(Stack, { direction: "row", spacing: 1, alignSelf: "end", children: [_jsx(Button, { variant: "outlined", onClick: close, children: t('cancel') }), _jsx(Button, { variant: "outlined", onClick: handleConfirm, children: t('confirm') })] })] }));
13
+ const modalTitle = title ?? t('modal.confirm.delete.title');
14
+ const modalDesc = description ?? t('modal.confirm.delete.description');
15
+ return (_jsxs(Stack, { spacing: 2, p: 2, alignItems: "start", sx: { minWidth: '500px' }, children: [_jsx(Typography, { variant: "h4", children: modalTitle }), _jsx(Typography, { children: modalDesc }), _jsxs(Stack, { direction: "row", spacing: 1, alignSelf: "end", children: [_jsx(Button, { variant: preferCancel ? 'contained' : 'outlined', onClick: close, children: t('button.cancel') }), _jsx(Button, { variant: preferDelete ? 'contained' : 'outlined', onClick: handleConfirm, children: t('button.delete') })] })] }));
14
16
  };
15
17
  export default ConfirmDeleteModal;
@@ -3,9 +3,9 @@ import { MoreHoriz } from '@mui/icons-material';
3
3
  import { Box, CircularProgress, Divider, FormControl, FormControlLabel, FormLabel, IconButton, Menu, Radio, RadioGroup, Stack, Switch, useMediaQuery } from '@mui/material';
4
4
  import useMatchers from '@cccsaurora/howler-ui/components/app/hooks/useMatchers';
5
5
  import { ApiConfigContext } from '@cccsaurora/howler-ui/components/app/providers/ApiConfigProvider';
6
+ import { HitContext } from '@cccsaurora/howler-ui/components/app/providers/HitProvider';
7
+ import { HitSearchContext } from '@cccsaurora/howler-ui/components/app/providers/HitSearchProvider';
6
8
  import { ParameterContext } from '@cccsaurora/howler-ui/components/app/providers/ParameterProvider';
7
- import { RecordContext } from '@cccsaurora/howler-ui/components/app/providers/RecordProvider';
8
- import { RecordSearchContext } from '@cccsaurora/howler-ui/components/app/providers/RecordSearchProvider';
9
9
  import { ViewContext } from '@cccsaurora/howler-ui/components/app/providers/ViewProvider';
10
10
  import useHitActions from '@cccsaurora/howler-ui/components/hooks/useHitActions';
11
11
  import { useMyLocalStorageProvider } from '@cccsaurora/howler-ui/components/hooks/useMyLocalStorage';
@@ -30,8 +30,8 @@ const HitActions = ({ hit, orientation = 'horizontal' }) => {
30
30
  const getCurrentViews = useContextSelector(ViewContext, ctx => ctx.getCurrentViews);
31
31
  const selected = useContextSelector(ParameterContext, ctx => ctx?.selected);
32
32
  const setSelected = useContextSelector(ParameterContext, ctx => ctx?.setSelected);
33
- const clearSelectedHits = useContextSelector(RecordContext, ctx => ctx.clearSelectedRecords);
34
- const nextHit = useContextSelector(RecordSearchContext, ctx => {
33
+ const clearSelectedHits = useContextSelector(HitContext, ctx => ctx.clearSelectedHits);
34
+ const nextHit = useContextSelector(HitSearchContext, ctx => {
35
35
  if (!ctx?.response || !selected) {
36
36
  return null;
37
37
  }
@@ -3,7 +3,6 @@ import { type FC } from 'react';
3
3
  import { HitLayout } from './HitLayout';
4
4
  type HitBannerProps = {
5
5
  hit: Hit;
6
- lazy?: boolean;
7
6
  layout?: HitLayout;
8
7
  showAssigned?: boolean;
9
8
  useListener?: boolean;