@cccsaurora/howler-ui 2.19.0-cases.863 → 2.19.0-dev.1023

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 (435) hide show
  1. package/api/action/index.d.ts +5 -4
  2. package/api/action/index.js +8 -8
  3. package/api/analytic/index.d.ts +3 -2
  4. package/api/analytic/index.js +4 -4
  5. package/api/analytic/owner.d.ts +2 -1
  6. package/api/analytic/owner.js +2 -2
  7. package/api/analytic/rules.d.ts +2 -1
  8. package/api/analytic/rules.js +2 -2
  9. package/api/dossier/index.d.ts +4 -3
  10. package/api/dossier/index.js +6 -6
  11. package/api/hit/index.d.ts +3 -2
  12. package/api/hit/index.js +4 -4
  13. package/api/hit/labels.d.ts +3 -2
  14. package/api/hit/labels.js +4 -4
  15. package/api/hit/overwrite.d.ts +2 -1
  16. package/api/hit/overwrite.js +2 -2
  17. package/api/hit/transition.d.ts +2 -1
  18. package/api/hit/transition.js +2 -2
  19. package/api/index.d.ts +5 -8
  20. package/api/index.js +10 -18
  21. package/api/overview/index.d.ts +4 -3
  22. package/api/overview/index.js +6 -6
  23. package/api/search/facet/hit.d.ts +3 -1
  24. package/api/search/facet/index.d.ts +1 -3
  25. package/api/search/index.d.ts +1 -2
  26. package/api/search/index.js +1 -2
  27. package/api/search/overview.d.ts +2 -2
  28. package/api/template/index.d.ts +4 -3
  29. package/api/template/index.js +6 -6
  30. package/api/user/index.d.ts +2 -1
  31. package/api/user/index.js +2 -2
  32. package/api/view/index.d.ts +4 -3
  33. package/api/view/index.js +6 -6
  34. package/commons/components/leftnav/LeftNavDrawer.js +1 -1
  35. package/components/app/App.d.ts +1 -0
  36. package/components/app/App.js +20 -42
  37. package/components/app/hooks/useMatchers.d.ts +1 -1
  38. package/components/app/hooks/useMatchers.js +11 -23
  39. package/components/app/hooks/useMatchers.test.js +22 -22
  40. package/components/app/hooks/useTitle.js +5 -5
  41. package/components/app/providers/FavouritesProvider.js +2 -6
  42. package/components/app/providers/HitProvider.d.ts +22 -0
  43. package/components/app/providers/{RecordProvider.js → HitProvider.js} +42 -42
  44. package/components/app/providers/{RecordSearchProvider.d.ts → HitSearchProvider.d.ts} +6 -6
  45. package/components/app/providers/{RecordSearchProvider.js → HitSearchProvider.js} +17 -12
  46. package/components/app/providers/{RecordSearchProvider.test.js → HitSearchProvider.test.js} +71 -52
  47. package/components/app/providers/ModalProvider.d.ts +1 -1
  48. package/components/app/providers/ModalProvider.js +5 -1
  49. package/components/app/providers/ParameterProvider.d.ts +2 -9
  50. package/components/app/providers/ParameterProvider.js +240 -165
  51. package/components/app/providers/ParameterProvider.test.js +94 -346
  52. package/components/app/providers/SearchResponseProvider.d.ts +21 -0
  53. package/components/app/providers/SearchResponseProvider.js +81 -0
  54. package/components/app/providers/SearchResponseProvider.test.js +406 -0
  55. package/components/app/providers/SocketProvider.d.ts +2 -11
  56. package/components/app/providers/SocketProvider.js +5 -18
  57. package/components/app/providers/UserListProvider.js +8 -28
  58. package/components/app/providers/ViewProvider.test.js +4 -1
  59. package/components/elements/PluginTypography.d.ts +1 -2
  60. package/components/elements/PluginTypography.js +2 -3
  61. package/components/elements/UserList.d.ts +2 -5
  62. package/components/elements/UserList.js +8 -18
  63. package/components/elements/addons/buttons/CustomButton.test.js +106 -0
  64. package/components/elements/addons/layout/FlexOne.test.js +30 -0
  65. package/components/elements/addons/lists/TuiListBase.js +4 -0
  66. package/components/elements/addons/lists/TuiListElement.js +6 -3
  67. package/components/elements/addons/lists/index.d.ts +1 -0
  68. package/components/elements/addons/search/SearchPagination.d.ts +2 -1
  69. package/components/elements/addons/search/SearchPagination.js +4 -4
  70. package/components/elements/addons/search/SearchPagination.test.js +80 -0
  71. package/components/elements/addons/search/SearchTotal.test.js +47 -0
  72. package/components/elements/addons/search/phrase/Phrase.js +1 -1
  73. package/components/elements/display/ChipPopper.d.ts +1 -1
  74. package/components/elements/display/ChipPopper.js +5 -5
  75. package/components/elements/display/DocumentationButton.test.js +84 -0
  76. package/components/elements/display/DynamicTabs.test.js +93 -0
  77. package/components/elements/display/HowlerAvatar.js +2 -1
  78. package/components/elements/display/HowlerCard.js +1 -1
  79. package/components/elements/display/HowlerCard.test.js +55 -0
  80. package/components/elements/display/Image.test.js +79 -0
  81. package/components/elements/display/ItemManager.d.ts +2 -2
  82. package/components/elements/display/ItemManager.js +1 -1
  83. package/components/elements/display/Markdown.js +9 -2
  84. package/components/elements/display/Modal.js +0 -2
  85. package/components/elements/display/QueryResultText.test.js +48 -0
  86. package/components/elements/display/TextDivider.test.js +43 -0
  87. package/components/elements/display/TypingIndicator.test.js +33 -0
  88. package/components/elements/display/icons/BundleButton.d.ts +6 -0
  89. package/components/elements/display/icons/BundleButton.js +32 -0
  90. package/components/elements/display/modals/ConfirmDeleteModal.d.ts +4 -0
  91. package/components/elements/display/modals/ConfirmDeleteModal.js +4 -2
  92. package/components/elements/hit/HitActions.js +4 -4
  93. package/components/elements/hit/HitBanner.d.ts +0 -1
  94. package/components/elements/hit/HitBanner.js +49 -31
  95. package/components/elements/hit/HitCard.d.ts +0 -2
  96. package/components/elements/hit/HitCard.js +7 -7
  97. package/components/elements/{record/RecordComments.d.ts → hit/HitComments.d.ts} +4 -5
  98. package/components/elements/{record/RecordComments.js → hit/HitComments.js} +28 -29
  99. package/components/elements/{ObjectDetails.js → hit/HitDetails.js} +17 -17
  100. package/components/elements/hit/HitLabels.js +2 -2
  101. package/components/elements/hit/HitOutline.d.ts +0 -1
  102. package/components/elements/hit/HitOutline.js +3 -3
  103. package/components/elements/hit/{HitPreview.d.ts → HitQuickSearch.d.ts} +3 -3
  104. package/components/elements/hit/{HitPreview.js → HitQuickSearch.js} +4 -10
  105. package/components/elements/hit/HitRelated.d.ts +6 -0
  106. package/components/elements/hit/HitRelated.js +7 -0
  107. package/components/elements/hit/HitSummary.d.ts +1 -2
  108. package/components/elements/hit/HitSummary.js +8 -8
  109. package/components/elements/{record/RecordWorklog.d.ts → hit/HitWorklog.d.ts} +3 -4
  110. package/components/elements/{record/RecordWorklog.js → hit/HitWorklog.js} +13 -15
  111. package/components/elements/hit/aggregate/HitGraph.js +8 -8
  112. package/components/elements/hit/elements/{Assigned.d.ts → HitUsers.d.ts} +5 -2
  113. package/components/elements/hit/elements/HitUsers.js +33 -0
  114. package/components/elements/hit/outlines/DefaultOutline.js +1 -1
  115. package/components/elements/view/ViewTitle.d.ts +0 -1
  116. package/components/elements/view/ViewTitle.js +2 -9
  117. package/components/hooks/useHitActions.d.ts +1 -1
  118. package/components/hooks/useHitActions.js +4 -4
  119. package/components/hooks/{useRecordSelection.d.ts → useHitSelection.d.ts} +2 -2
  120. package/components/hooks/{useRecordSelection.js → useHitSelection.js} +33 -12
  121. package/components/hooks/useMyApi.d.ts +1 -1
  122. package/components/hooks/useMyPreferences.js +3 -11
  123. package/components/hooks/useMySearch.js +2 -2
  124. package/components/hooks/useMySitemap.js +1 -4
  125. package/components/hooks/useMyTheme.js +2 -9
  126. package/components/routes/403.test.js +27 -0
  127. package/components/routes/404.test.js +26 -0
  128. package/components/routes/ErrorBoundary.test.js +43 -0
  129. package/components/routes/ErrorOccured.test.js +35 -0
  130. package/components/routes/Logout.test.js +59 -0
  131. package/components/routes/action/edit/ActionEditor.js +2 -2
  132. package/components/routes/action/useMyActionFunctions.js +5 -2
  133. package/components/routes/action/view/ActionDetails.js +10 -2
  134. package/components/routes/action/view/ActionSearch.js +30 -19
  135. package/components/routes/advanced/QueryBuilder.js +1 -1
  136. package/components/routes/advanced/QueryEditor.js +3 -3
  137. package/components/routes/advanced/historyCompletionProvider.js +3 -3
  138. package/components/routes/analytics/AnalyticDetails.js +12 -8
  139. package/components/routes/analytics/AnalyticSearch.js +7 -7
  140. package/components/routes/dossiers/DossierEditor.js +2 -2
  141. package/components/routes/dossiers/DossierEditor.test.js +1 -1
  142. package/components/routes/dossiers/Dossiers.js +25 -19
  143. package/components/routes/help/ApiDocumentation.js +1 -1
  144. package/components/routes/help/BundleDocumentation.d.ts +3 -0
  145. package/components/routes/help/BundleDocumentation.js +12 -0
  146. package/components/routes/help/HitBannerDocumentation.js +0 -1
  147. package/components/routes/help/HitDocumentation.js +3 -1
  148. package/components/routes/help/markdown/en/bundles.md.js +1 -0
  149. package/components/routes/help/markdown/en/client.md.js +1 -1
  150. package/components/routes/help/markdown/fr/bundles.md.js +1 -0
  151. package/components/routes/help/markdown/fr/client.md.js +1 -1
  152. package/components/routes/hits/search/BundleParentMenu.d.ts +6 -0
  153. package/components/routes/hits/search/BundleParentMenu.js +32 -0
  154. package/components/routes/hits/search/BundleScroller.d.ts +2 -0
  155. package/components/routes/hits/search/BundleScroller.js +6 -0
  156. package/components/routes/hits/search/{RecordBrowser.js → HitBrowser.js} +9 -9
  157. package/components/{elements/record/RecordContextMenu.d.ts → routes/hits/search/HitContextMenu.d.ts} +3 -3
  158. package/components/routes/hits/search/HitContextMenu.js +239 -0
  159. package/components/{elements/record/RecordContextMenu.test.js → routes/hits/search/HitContextMenu.test.js} +43 -98
  160. package/components/routes/hits/search/{RecordQuery.d.ts → HitQuery.d.ts} +2 -2
  161. package/components/routes/hits/search/{RecordQuery.js → HitQuery.js} +6 -6
  162. package/components/routes/hits/search/InformationPane.d.ts +0 -1
  163. package/components/routes/hits/search/InformationPane.js +63 -50
  164. package/components/routes/hits/search/LayoutSettings.js +3 -3
  165. package/components/routes/hits/search/QuerySettings.js +1 -2
  166. package/components/routes/hits/search/QuerySettings.test.js +9 -14
  167. package/components/routes/hits/search/SearchPane.js +49 -26
  168. package/components/routes/hits/search/ViewLink.js +3 -3
  169. package/components/routes/hits/search/ViewLink.test.js +8 -8
  170. package/components/routes/hits/search/grid/AddColumnModal.js +4 -5
  171. package/components/routes/hits/search/grid/EnhancedCell.d.ts +1 -2
  172. package/components/routes/hits/search/grid/EnhancedCell.js +2 -2
  173. package/components/routes/hits/search/grid/HitGrid.js +18 -20
  174. package/components/routes/hits/search/grid/{RecordRow.d.ts → HitRow.d.ts} +2 -3
  175. package/components/routes/hits/search/grid/{RecordRow.js → HitRow.js} +9 -11
  176. package/components/routes/hits/search/shared/CustomSpan.js +7 -7
  177. package/components/routes/hits/search/shared/CustomSpan.test.js +170 -0
  178. package/components/routes/hits/view/HitViewer.js +13 -12
  179. package/components/routes/home/AddNewCard.test.js +86 -0
  180. package/components/routes/home/ViewCard.js +41 -47
  181. package/components/routes/home/ViewRefresh.test.js +79 -0
  182. package/components/routes/overviews/OverviewCard.test.js +108 -0
  183. package/components/{elements/MarkdownEditor.js → routes/overviews/OverviewEditor.js} +3 -3
  184. package/components/routes/overviews/OverviewViewer.js +18 -10
  185. package/components/routes/overviews/Overviews.js +25 -19
  186. package/components/routes/settings/LocalSection.js +2 -1
  187. package/components/routes/settings/SettingsSection.test.d.ts +1 -0
  188. package/components/routes/settings/SettingsSection.test.js +19 -0
  189. package/components/routes/templates/TemplateCard.d.ts +3 -1
  190. package/components/routes/templates/TemplateCard.js +8 -4
  191. package/components/routes/templates/TemplateCard.test.d.ts +1 -0
  192. package/components/routes/templates/TemplateCard.test.js +115 -0
  193. package/components/routes/templates/TemplateViewer.js +62 -16
  194. package/components/routes/templates/Templates.js +35 -13
  195. package/components/routes/views/ViewComposer.js +19 -46
  196. package/components/routes/views/Views.js +21 -14
  197. package/locales/en/translation.json +21 -118
  198. package/locales/fr/translation.json +23 -120
  199. package/models/WithMetadata.d.ts +1 -2
  200. package/models/entities/generated/{ThreatEnrichment.d.ts → Enrichment.d.ts} +1 -1
  201. package/models/entities/generated/Hit.d.ts +1 -1
  202. package/models/entities/generated/Howler.d.ts +6 -0
  203. package/models/entities/generated/Rule.d.ts +9 -6
  204. package/models/entities/generated/Threat.d.ts +2 -2
  205. package/models/entities/generated/UserUser.d.ts +2 -0
  206. package/models/entities/generated/View.d.ts +0 -1
  207. package/package.json +125 -145
  208. package/plugins/clue/components/ClueTypography.js +2 -2
  209. package/plugins/clue/utils.d.ts +1 -2
  210. package/rest/FetchClient.test.d.ts +1 -0
  211. package/rest/FetchClient.test.js +81 -0
  212. package/setupTests.js +5 -0
  213. package/tests/mocks.d.ts +1 -11
  214. package/tests/mocks.js +7 -12
  215. package/tests/server-handlers.js +1 -6
  216. package/tests/utils.d.ts +0 -4
  217. package/tests/utils.js +0 -20
  218. package/utils/Throttler.test.d.ts +1 -0
  219. package/utils/Throttler.test.js +135 -0
  220. package/utils/actionUtils.test.d.ts +1 -0
  221. package/utils/actionUtils.test.js +140 -0
  222. package/utils/constants.d.ts +4 -4
  223. package/utils/constants.js +1 -6
  224. package/utils/hitFunctions.d.ts +1 -2
  225. package/utils/hitFunctions.js +4 -4
  226. package/utils/hitFunctions.test.d.ts +1 -0
  227. package/utils/hitFunctions.test.js +52 -0
  228. package/utils/localStorage.test.d.ts +1 -0
  229. package/utils/localStorage.test.js +96 -0
  230. package/utils/menuUtils.test.d.ts +1 -0
  231. package/utils/menuUtils.test.js +198 -0
  232. package/utils/sessionStorage.test.d.ts +1 -0
  233. package/utils/sessionStorage.test.js +81 -0
  234. package/utils/socketUtils.d.ts +0 -14
  235. package/utils/socketUtils.js +1 -17
  236. package/utils/socketUtils.test.js +16 -49
  237. package/utils/stringUtils.test.d.ts +1 -0
  238. package/utils/stringUtils.test.js +159 -0
  239. package/utils/utils.test.d.ts +1 -0
  240. package/utils/utils.test.js +292 -0
  241. package/utils/viewUtils.js +0 -3
  242. package/utils/viewUtils.test.d.ts +1 -0
  243. package/utils/viewUtils.test.js +45 -0
  244. package/utils/xsrf.test.d.ts +1 -0
  245. package/utils/xsrf.test.js +41 -0
  246. package/api/search/case.d.ts +0 -4
  247. package/api/search/case.js +0 -8
  248. package/api/socket/index.d.ts +0 -3
  249. package/api/socket/index.js +0 -6
  250. package/api/socket/viewers.d.ts +0 -2
  251. package/api/socket/viewers.js +0 -8
  252. package/api/socket/viewers.test.js +0 -44
  253. package/api/v2/case/index.d.ts +0 -9
  254. package/api/v2/case/index.js +0 -21
  255. package/api/v2/case/items.d.ts +0 -6
  256. package/api/v2/case/items.js +0 -18
  257. package/api/v2/case/rules.d.ts +0 -6
  258. package/api/v2/case/rules.js +0 -18
  259. package/api/v2/index.d.ts +0 -4
  260. package/api/v2/index.js +0 -6
  261. package/api/v2/search/facet.d.ts +0 -3
  262. package/api/v2/search/facet.js +0 -12
  263. package/api/v2/search/index.d.ts +0 -5
  264. package/api/v2/search/index.js +0 -24
  265. package/components/app/providers/RecordProvider.d.ts +0 -23
  266. package/components/elements/ContextMenu.d.ts +0 -56
  267. package/components/elements/ContextMenu.js +0 -109
  268. package/components/elements/ContextMenu.test.js +0 -215
  269. package/components/elements/ObjectDetails.d.ts +0 -6
  270. package/components/elements/case/CaseCard.d.ts +0 -12
  271. package/components/elements/case/CaseCard.js +0 -42
  272. package/components/elements/case/CasePreview.d.ts +0 -6
  273. package/components/elements/case/CasePreview.js +0 -17
  274. package/components/elements/case/StatusIcon.d.ts +0 -5
  275. package/components/elements/case/StatusIcon.js +0 -13
  276. package/components/elements/hit/elements/AnalyticLink.d.ts +0 -9
  277. package/components/elements/hit/elements/AnalyticLink.js +0 -22
  278. package/components/elements/hit/elements/Assigned.js +0 -34
  279. package/components/elements/hit/elements/Assigned.test.js +0 -65
  280. package/components/elements/hit/related/RelatedRecords.js +0 -63
  281. package/components/elements/observable/ObservableCard.d.ts +0 -6
  282. package/components/elements/observable/ObservableCard.js +0 -22
  283. package/components/elements/observable/ObservablePreview.d.ts +0 -6
  284. package/components/elements/observable/ObservablePreview.js +0 -12
  285. package/components/elements/record/RecordContextMenu.js +0 -268
  286. package/components/elements/record/RecordRelated.d.ts +0 -7
  287. package/components/elements/record/RecordRelated.js +0 -34
  288. package/components/hooks/useRelatedRecords.d.ts +0 -13
  289. package/components/hooks/useRelatedRecords.js +0 -32
  290. package/components/routes/cases/CaseViewer.d.ts +0 -2
  291. package/components/routes/cases/CaseViewer.js +0 -44
  292. package/components/routes/cases/CaseViewer.test.js +0 -133
  293. package/components/routes/cases/Cases.d.ts +0 -2
  294. package/components/routes/cases/Cases.js +0 -148
  295. package/components/routes/cases/constants.d.ts +0 -6
  296. package/components/routes/cases/constants.js +0 -6
  297. package/components/routes/cases/detail/AlertPanel.d.ts +0 -6
  298. package/components/routes/cases/detail/AlertPanel.js +0 -33
  299. package/components/routes/cases/detail/CaseAssets.d.ts +0 -11
  300. package/components/routes/cases/detail/CaseAssets.js +0 -104
  301. package/components/routes/cases/detail/CaseAssets.test.js +0 -167
  302. package/components/routes/cases/detail/CaseDashboard.d.ts +0 -7
  303. package/components/routes/cases/detail/CaseDashboard.js +0 -66
  304. package/components/routes/cases/detail/CaseDetails.d.ts +0 -6
  305. package/components/routes/cases/detail/CaseDetails.js +0 -70
  306. package/components/routes/cases/detail/CaseOverview.d.ts +0 -7
  307. package/components/routes/cases/detail/CaseOverview.js +0 -43
  308. package/components/routes/cases/detail/CaseRules.d.ts +0 -7
  309. package/components/routes/cases/detail/CaseRules.js +0 -57
  310. package/components/routes/cases/detail/CaseRules.test.js +0 -221
  311. package/components/routes/cases/detail/CaseSidebar.d.ts +0 -8
  312. package/components/routes/cases/detail/CaseSidebar.js +0 -107
  313. package/components/routes/cases/detail/CaseSidebar.test.js +0 -266
  314. package/components/routes/cases/detail/CaseTask.d.ts +0 -11
  315. package/components/routes/cases/detail/CaseTask.js +0 -66
  316. package/components/routes/cases/detail/CaseTimeline.d.ts +0 -12
  317. package/components/routes/cases/detail/CaseTimeline.js +0 -106
  318. package/components/routes/cases/detail/CaseTimeline.test.js +0 -320
  319. package/components/routes/cases/detail/CreateRuleDialog.d.ts +0 -9
  320. package/components/routes/cases/detail/CreateRuleDialog.js +0 -163
  321. package/components/routes/cases/detail/CreateRuleDialog.test.js +0 -259
  322. package/components/routes/cases/detail/ItemPage.d.ts +0 -6
  323. package/components/routes/cases/detail/ItemPage.js +0 -95
  324. package/components/routes/cases/detail/RelatedCasePanel.d.ts +0 -6
  325. package/components/routes/cases/detail/RelatedCasePanel.js +0 -34
  326. package/components/routes/cases/detail/TaskPanel.d.ts +0 -7
  327. package/components/routes/cases/detail/TaskPanel.js +0 -52
  328. package/components/routes/cases/detail/aggregates/CaseAggregate.d.ts +0 -11
  329. package/components/routes/cases/detail/aggregates/CaseAggregate.js +0 -24
  330. package/components/routes/cases/detail/aggregates/SourceAggregate.d.ts +0 -6
  331. package/components/routes/cases/detail/aggregates/SourceAggregate.js +0 -26
  332. package/components/routes/cases/detail/assets/Asset.d.ts +0 -14
  333. package/components/routes/cases/detail/assets/Asset.js +0 -12
  334. package/components/routes/cases/detail/assets/Asset.test.js +0 -72
  335. package/components/routes/cases/detail/sidebar/CaseFolder.d.ts +0 -20
  336. package/components/routes/cases/detail/sidebar/CaseFolder.js +0 -83
  337. package/components/routes/cases/detail/sidebar/CaseFolder.test.js +0 -295
  338. package/components/routes/cases/detail/sidebar/CaseFolderContextMenu.d.ts +0 -34
  339. package/components/routes/cases/detail/sidebar/CaseFolderContextMenu.js +0 -103
  340. package/components/routes/cases/detail/sidebar/CaseFolderContextMenu.test.js +0 -363
  341. package/components/routes/cases/detail/sidebar/FolderEntry.d.ts +0 -25
  342. package/components/routes/cases/detail/sidebar/FolderEntry.js +0 -88
  343. package/components/routes/cases/detail/sidebar/FolderEntry.test.js +0 -206
  344. package/components/routes/cases/detail/sidebar/RootDropZone.d.ts +0 -5
  345. package/components/routes/cases/detail/sidebar/RootDropZone.js +0 -33
  346. package/components/routes/cases/detail/sidebar/types.d.ts +0 -9
  347. package/components/routes/cases/detail/sidebar/utils.d.ts +0 -3
  348. package/components/routes/cases/detail/sidebar/utils.js +0 -29
  349. package/components/routes/cases/detail/sidebar/utils.test.js +0 -82
  350. package/components/routes/cases/hooks/useCase.d.ts +0 -13
  351. package/components/routes/cases/hooks/useCase.js +0 -69
  352. package/components/routes/cases/hooks/useCase.test.js +0 -141
  353. package/components/routes/cases/modals/AddToCaseModal.d.ts +0 -7
  354. package/components/routes/cases/modals/AddToCaseModal.js +0 -59
  355. package/components/routes/cases/modals/AddToCaseModal.test.js +0 -313
  356. package/components/routes/cases/modals/CaseRecordRow.d.ts +0 -9
  357. package/components/routes/cases/modals/CaseRecordRow.js +0 -15
  358. package/components/routes/cases/modals/CreateCaseModal.d.ts +0 -7
  359. package/components/routes/cases/modals/CreateCaseModal.js +0 -55
  360. package/components/routes/cases/modals/CreateCaseModal.test.js +0 -358
  361. package/components/routes/cases/modals/RenameItemModal.d.ts +0 -9
  362. package/components/routes/cases/modals/RenameItemModal.js +0 -48
  363. package/components/routes/cases/modals/ResolveModal.d.ts +0 -7
  364. package/components/routes/cases/modals/ResolveModal.js +0 -115
  365. package/components/routes/cases/modals/ResolveModal.test.js +0 -394
  366. package/components/routes/cases/modals/hooks.d.ts +0 -7
  367. package/components/routes/cases/modals/hooks.js +0 -44
  368. package/components/routes/cases/modals/types.d.ts +0 -5
  369. package/components/routes/cases/search/CaseAssigneeFilter.d.ts +0 -6
  370. package/components/routes/cases/search/CaseAssigneeFilter.js +0 -33
  371. package/components/routes/cases/search/CaseAssigneeFilter.test.js +0 -127
  372. package/components/routes/cases/search/CaseDateFilter.d.ts +0 -13
  373. package/components/routes/cases/search/CaseDateFilter.js +0 -26
  374. package/components/routes/cases/search/CaseDateFilter.test.js +0 -115
  375. package/components/routes/cases/search/CaseStatusFilter.d.ts +0 -6
  376. package/components/routes/cases/search/CaseStatusFilter.js +0 -13
  377. package/components/routes/cases/search/CaseStatusFilter.test.js +0 -86
  378. package/components/routes/hits/search/shared/IndexPicker.d.ts +0 -2
  379. package/components/routes/hits/search/shared/IndexPicker.js +0 -20
  380. package/components/routes/observables/ObservableViewer.d.ts +0 -7
  381. package/components/routes/observables/ObservableViewer.js +0 -27
  382. package/models/entities/generated/AttachmentsFile.d.ts +0 -12
  383. package/models/entities/generated/Case.d.ts +0 -28
  384. package/models/entities/generated/DestinationOriginal.d.ts +0 -19
  385. package/models/entities/generated/EmailAttachment.d.ts +0 -8
  386. package/models/entities/generated/EmailParent.d.ts +0 -19
  387. package/models/entities/generated/Enrichments.d.ts +0 -7
  388. package/models/entities/generated/EnrichmentsIndicator.d.ts +0 -21
  389. package/models/entities/generated/HttpResponse.d.ts +0 -11
  390. package/models/entities/generated/Item.d.ts +0 -9
  391. package/models/entities/generated/Observable.d.ts +0 -85
  392. package/models/entities/generated/ObservableCloud.d.ts +0 -20
  393. package/models/entities/generated/ObservableDestination.d.ts +0 -23
  394. package/models/entities/generated/ObservableEmail.d.ts +0 -30
  395. package/models/entities/generated/ObservableFile.d.ts +0 -36
  396. package/models/entities/generated/ObservableHowler.d.ts +0 -42
  397. package/models/entities/generated/ObservableHttp.d.ts +0 -11
  398. package/models/entities/generated/ObservableObserver.d.ts +0 -21
  399. package/models/entities/generated/ObservableOrganization.d.ts +0 -7
  400. package/models/entities/generated/ObservableProcess.d.ts +0 -34
  401. package/models/entities/generated/ObservableSource.d.ts +0 -23
  402. package/models/entities/generated/ObservableThreat.d.ts +0 -21
  403. package/models/entities/generated/ObservableTls.d.ts +0 -12
  404. package/models/entities/generated/ObserverIngress.d.ts +0 -9
  405. package/models/entities/generated/Task.d.ts +0 -10
  406. package/models/socket/CaseUpdate.d.ts +0 -5
  407. package/models/socket/ViewersUpdate.d.ts +0 -4
  408. package/utils/typeUtils.d.ts +0 -7
  409. package/utils/typeUtils.js +0 -27
  410. /package/{api/socket/viewers.test.d.ts → components/app/providers/HitSearchProvider.test.d.ts} +0 -0
  411. /package/components/app/providers/{RecordSearchProvider.test.d.ts → SearchResponseProvider.test.d.ts} +0 -0
  412. /package/components/elements/{ContextMenu.test.d.ts → addons/buttons/CustomButton.test.d.ts} +0 -0
  413. /package/components/elements/{hit/elements/Assigned.test.d.ts → addons/layout/FlexOne.test.d.ts} +0 -0
  414. /package/components/elements/{record/RecordContextMenu.test.d.ts → addons/search/SearchPagination.test.d.ts} +0 -0
  415. /package/components/{routes/cases/CaseViewer.test.d.ts → elements/addons/search/SearchTotal.test.d.ts} +0 -0
  416. /package/components/{routes/cases/detail/CaseAssets.test.d.ts → elements/display/DocumentationButton.test.d.ts} +0 -0
  417. /package/components/{routes/cases/detail/CaseRules.test.d.ts → elements/display/DynamicTabs.test.d.ts} +0 -0
  418. /package/components/{routes/cases/detail/CaseSidebar.test.d.ts → elements/display/HowlerCard.test.d.ts} +0 -0
  419. /package/components/{routes/cases/detail/CaseTimeline.test.d.ts → elements/display/Image.test.d.ts} +0 -0
  420. /package/components/{routes/cases/detail/CreateRuleDialog.test.d.ts → elements/display/QueryResultText.test.d.ts} +0 -0
  421. /package/components/{routes/cases/detail/assets/Asset.test.d.ts → elements/display/TextDivider.test.d.ts} +0 -0
  422. /package/components/{routes/cases/detail/sidebar/CaseFolder.test.d.ts → elements/display/TypingIndicator.test.d.ts} +0 -0
  423. /package/components/elements/hit/{related/RelatedRecords.d.ts → HitDetails.d.ts} +0 -0
  424. /package/components/routes/{cases/detail/sidebar/CaseFolderContextMenu.test.d.ts → 403.test.d.ts} +0 -0
  425. /package/components/routes/{cases/detail/sidebar/FolderEntry.test.d.ts → 404.test.d.ts} +0 -0
  426. /package/components/routes/{cases/detail/sidebar/utils.test.d.ts → ErrorBoundary.test.d.ts} +0 -0
  427. /package/components/routes/{cases/hooks/useCase.test.d.ts → ErrorOccured.test.d.ts} +0 -0
  428. /package/components/routes/{cases/modals/AddToCaseModal.test.d.ts → Logout.test.d.ts} +0 -0
  429. /package/components/routes/hits/search/{RecordBrowser.d.ts → HitBrowser.d.ts} +0 -0
  430. /package/components/routes/{cases/modals/CreateCaseModal.test.d.ts → hits/search/HitContextMenu.test.d.ts} +0 -0
  431. /package/components/routes/{cases/modals/ResolveModal.test.d.ts → hits/search/shared/CustomSpan.test.d.ts} +0 -0
  432. /package/components/routes/{cases/search/CaseAssigneeFilter.test.d.ts → home/AddNewCard.test.d.ts} +0 -0
  433. /package/components/routes/{cases/search/CaseDateFilter.test.d.ts → home/ViewRefresh.test.d.ts} +0 -0
  434. /package/components/routes/{cases/search/CaseStatusFilter.test.d.ts → overviews/OverviewCard.test.d.ts} +0 -0
  435. /package/components/{elements/MarkdownEditor.d.ts → routes/overviews/OverviewEditor.d.ts} +0 -0
@@ -0,0 +1,21 @@
1
+ import type { HowlerSearchRequest, HowlerSearchResponse } from '@cccsaurora/howler-ui/api/search';
2
+ import type { DispatchApiConfig } from '@cccsaurora/howler-ui/components/hooks/useMyApi';
3
+ import { type PropsWithChildren } from 'react';
4
+ export type SearchResponseState<T> = HowlerSearchResponse<T> & {
5
+ removeCount: number;
6
+ };
7
+ export type SearchResponseContextType<T> = {
8
+ push: (item: T) => void;
9
+ remove: (id: string) => void;
10
+ replace: (id: string, item: T) => void;
11
+ request: (endpoint: (request: HowlerSearchRequest) => Promise<HowlerSearchResponse<T>>, requestData: HowlerSearchRequest, config?: DispatchApiConfig) => Promise<HowlerSearchResponse<T>>;
12
+ getSearchRequestData: (requestData: Partial<HowlerSearchRequest>) => Partial<HowlerSearchRequest>;
13
+ response: SearchResponseState<T> | null;
14
+ };
15
+ export declare const SearchResponseContext: import("react").Context<SearchResponseContextType<any>>;
16
+ type SearchResponseProviderProps<T> = PropsWithChildren<{
17
+ idField: string;
18
+ initialResponse?: SearchResponseState<T>;
19
+ }>;
20
+ declare const SearchResponseProvider: <T>({ children, idField: idField, initialResponse }: SearchResponseProviderProps<T>) => import("react/jsx-runtime").JSX.Element;
21
+ export default SearchResponseProvider;
@@ -0,0 +1,81 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import useMyApi from '@cccsaurora/howler-ui/components/hooks/useMyApi';
3
+ import { createContext, useCallback, useState } from 'react';
4
+ export const SearchResponseContext = createContext(null);
5
+ const SearchResponseProvider = ({ children, idField: idField, initialResponse = null }) => {
6
+ const { dispatchApi } = useMyApi();
7
+ const [response, setResponse] = useState(initialResponse);
8
+ const request = useCallback(async (endpoint, requestData, config) => {
9
+ const _response = await dispatchApi(endpoint(requestData), config);
10
+ setResponse(_prevResponse => ({
11
+ ..._response,
12
+ removeCount: _response.offset <= _prevResponse?.offset ? 0 : (_prevResponse?.removeCount ?? 0)
13
+ }));
14
+ return _response;
15
+ }, [dispatchApi]);
16
+ const getSearchRequestData = useCallback((requestData) => {
17
+ const modifiedRequest = { ...requestData };
18
+ if (response?.removeCount) {
19
+ if (response.offset < modifiedRequest.offset) {
20
+ modifiedRequest.offset = Math.max(0, modifiedRequest.offset - response.removeCount);
21
+ }
22
+ }
23
+ return modifiedRequest;
24
+ }, [response]);
25
+ const push = useCallback((item) => {
26
+ setResponse(_response => {
27
+ if (_response === null) {
28
+ return _response;
29
+ }
30
+ const filteredItems = _response.items.filter(v => v[idField] !== item[idField]);
31
+ const itemExists = filteredItems.length < _response.items.length;
32
+ filteredItems.push(item);
33
+ return {
34
+ items: filteredItems.length <= _response.rows ? filteredItems : _response.items,
35
+ offset: _response.offset,
36
+ rows: _response.rows,
37
+ total: itemExists ? _response.total : _response.total + 1,
38
+ removeCount: itemExists ? _response.removeCount : Math.max(_response.removeCount - 1, 0)
39
+ };
40
+ });
41
+ }, [idField]);
42
+ const replace = useCallback((id, item) => {
43
+ if (item[idField] !== undefined && id !== item[idField]) {
44
+ throw new Error('Item id is defined but id does not match the id provided to replace function');
45
+ }
46
+ const newItem = {
47
+ ...item,
48
+ [idField]: item[idField] !== undefined ? item[idField] : id
49
+ };
50
+ setResponse(_response => {
51
+ if (_response === null) {
52
+ return _response;
53
+ }
54
+ return {
55
+ items: _response.items.map(v => (v[idField] === id ? newItem : v)),
56
+ offset: _response.offset,
57
+ rows: _response.rows,
58
+ total: _response.total,
59
+ removeCount: _response.removeCount
60
+ };
61
+ });
62
+ }, [idField]);
63
+ const remove = useCallback((id) => {
64
+ setResponse(_response => {
65
+ if (_response === null) {
66
+ return _response;
67
+ }
68
+ const filteredItems = _response.items.filter(v => v[idField] !== id);
69
+ const itemExists = filteredItems.length < _response.items.length;
70
+ return {
71
+ items: filteredItems,
72
+ offset: _response.offset,
73
+ rows: _response.rows,
74
+ total: itemExists ? _response.total - 1 : _response.total,
75
+ removeCount: itemExists ? _response.removeCount + 1 : _response.removeCount
76
+ };
77
+ });
78
+ }, [idField]);
79
+ return (_jsx(SearchResponseContext.Provider, { value: { push, remove, replace, request, getSearchRequestData, response }, children: children }));
80
+ };
81
+ export default SearchResponseProvider;
@@ -0,0 +1,406 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { act, renderHook } from '@testing-library/react';
3
+ import { useContext } from 'react';
4
+ import SearchResponseProvider, { SearchResponseContext } from './SearchResponseProvider';
5
+ const TEST_PAGE_SIZE = 25;
6
+ const TEST_TOTAL_COUNT = 100;
7
+ const makeWrapper = (initialResponse) => {
8
+ const Wrapper = ({ children }) => (_jsx(SearchResponseProvider, { idField: "id", initialResponse: initialResponse, children: children }));
9
+ return Wrapper;
10
+ };
11
+ const renderProvider = (initialResponse) => {
12
+ return renderHook(() => useContext(SearchResponseContext), {
13
+ wrapper: makeWrapper(initialResponse)
14
+ });
15
+ };
16
+ describe('push', () => {
17
+ it("should add an item to the response if it doesn't exist", () => {
18
+ const hook = renderProvider({
19
+ items: [{ id: '0', name: 'existing' }],
20
+ offset: 0,
21
+ rows: TEST_PAGE_SIZE,
22
+ total: TEST_TOTAL_COUNT,
23
+ removeCount: 0
24
+ });
25
+ act(() => {
26
+ hook.result.current.push({ id: '1', name: 'test' });
27
+ });
28
+ expect(hook.result.current.response).toEqual({
29
+ items: [
30
+ { id: '0', name: 'existing' },
31
+ { id: '1', name: 'test' }
32
+ ],
33
+ offset: 0,
34
+ rows: TEST_PAGE_SIZE,
35
+ total: TEST_TOTAL_COUNT + 1,
36
+ removeCount: 0
37
+ });
38
+ });
39
+ it('should replace an item in the response if it already exists', () => {
40
+ const hook = renderProvider({
41
+ items: [{ id: '0', name: 'old' }],
42
+ offset: 0,
43
+ rows: TEST_PAGE_SIZE,
44
+ total: TEST_TOTAL_COUNT,
45
+ removeCount: 0
46
+ });
47
+ act(() => {
48
+ hook.result.current.push({ id: '0', name: 'new' });
49
+ });
50
+ expect(hook.result.current.response).toEqual({
51
+ items: [{ id: '0', name: 'new' }],
52
+ offset: 0,
53
+ rows: TEST_PAGE_SIZE,
54
+ total: TEST_TOTAL_COUNT,
55
+ removeCount: 0
56
+ });
57
+ });
58
+ it('should update total but not add item if the response has the maximum number of items', () => {
59
+ const items = Array.from({ length: TEST_PAGE_SIZE }, (_, i) => ({ id: i.toString(), name: `item${i}` }));
60
+ const newItem = { id: TEST_PAGE_SIZE.toString(), name: 'test' };
61
+ const hook = renderProvider({
62
+ items,
63
+ offset: 0,
64
+ rows: TEST_PAGE_SIZE,
65
+ total: TEST_TOTAL_COUNT,
66
+ removeCount: 0
67
+ });
68
+ act(() => {
69
+ hook.result.current.push(newItem);
70
+ });
71
+ expect(hook.result.current.response?.items).not.toContainEqual(newItem);
72
+ expect(hook.result.current.response).toEqual({
73
+ items,
74
+ offset: 0,
75
+ rows: TEST_PAGE_SIZE,
76
+ total: TEST_TOTAL_COUNT + 1,
77
+ removeCount: 0
78
+ });
79
+ });
80
+ it('should decrement removeCount if the item does not exist already', () => {
81
+ const hook = renderProvider({
82
+ items: [{ id: '0', name: 'existing' }],
83
+ offset: 0,
84
+ rows: TEST_PAGE_SIZE,
85
+ total: TEST_TOTAL_COUNT,
86
+ removeCount: 1
87
+ });
88
+ act(() => {
89
+ hook.result.current.push({ id: '1', name: 'test' });
90
+ });
91
+ expect(hook.result.current.response).not.toBeNull();
92
+ expect(hook.result.current.response.removeCount).toBe(0);
93
+ });
94
+ it('should not decrement removeCount if the item already exists', () => {
95
+ const hook = renderProvider({
96
+ items: [{ id: '0', name: 'existing' }],
97
+ offset: 0,
98
+ rows: TEST_PAGE_SIZE,
99
+ total: TEST_TOTAL_COUNT,
100
+ removeCount: 1
101
+ });
102
+ act(() => {
103
+ hook.result.current.push({ id: '0', name: 'new' });
104
+ });
105
+ expect(hook.result.current.response).not.toBeNull();
106
+ expect(hook.result.current.response.removeCount).toBe(1);
107
+ });
108
+ it('should keep response null if it is uninitiated', () => {
109
+ const hook = renderProvider();
110
+ act(() => {
111
+ hook.result.current.push({ id: '0', name: 'test' });
112
+ });
113
+ expect(hook.result.current.response).toBeNull();
114
+ });
115
+ });
116
+ describe('remove', () => {
117
+ it('should remove an item from the response if it exists', () => {
118
+ const hook = renderProvider({
119
+ items: [
120
+ { id: '0', name: 'item0' },
121
+ { id: '1', name: 'item1' }
122
+ ],
123
+ offset: 0,
124
+ rows: TEST_PAGE_SIZE,
125
+ total: TEST_TOTAL_COUNT,
126
+ removeCount: 0
127
+ });
128
+ act(() => {
129
+ hook.result.current.remove('0');
130
+ });
131
+ expect(hook.result.current.response).toEqual({
132
+ items: [{ id: '1', name: 'item1' }],
133
+ offset: 0,
134
+ rows: TEST_PAGE_SIZE,
135
+ total: TEST_TOTAL_COUNT - 1,
136
+ removeCount: 1
137
+ });
138
+ });
139
+ it('should ignore the remove if the item does not exist', () => {
140
+ const hook = renderProvider({
141
+ items: [{ id: '0', name: 'item' }],
142
+ offset: 0,
143
+ rows: TEST_PAGE_SIZE,
144
+ total: TEST_TOTAL_COUNT,
145
+ removeCount: 0
146
+ });
147
+ act(() => {
148
+ hook.result.current.remove('1');
149
+ });
150
+ expect(hook.result.current.response).toEqual({
151
+ items: [{ id: '0', name: 'item' }],
152
+ offset: 0,
153
+ rows: TEST_PAGE_SIZE,
154
+ total: TEST_TOTAL_COUNT,
155
+ removeCount: 0
156
+ });
157
+ });
158
+ it('should keep response null if it is uninitiated', () => {
159
+ const hook = renderProvider();
160
+ act(() => {
161
+ hook.result.current.remove('0');
162
+ });
163
+ expect(hook.result.current.response).toBeNull();
164
+ });
165
+ });
166
+ describe('replace', () => {
167
+ it('should replace an item in the response if it exists', () => {
168
+ const hook = renderProvider({
169
+ items: [{ id: '0', name: 'old' }],
170
+ offset: 0,
171
+ rows: TEST_PAGE_SIZE,
172
+ total: TEST_TOTAL_COUNT,
173
+ removeCount: 0
174
+ });
175
+ act(() => {
176
+ hook.result.current.replace('0', { id: undefined, name: 'new' });
177
+ });
178
+ expect(hook.result.current.response).toEqual({
179
+ items: [{ id: '0', name: 'new' }],
180
+ offset: 0,
181
+ rows: TEST_PAGE_SIZE,
182
+ total: TEST_TOTAL_COUNT,
183
+ removeCount: 0
184
+ });
185
+ });
186
+ it('should ignore the replace if the item does not exist', () => {
187
+ const hook = renderProvider({
188
+ items: [{ id: '0', name: 'item' }],
189
+ offset: 0,
190
+ rows: TEST_PAGE_SIZE,
191
+ total: TEST_TOTAL_COUNT,
192
+ removeCount: 0
193
+ });
194
+ act(() => {
195
+ hook.result.current.replace('1', { id: undefined, name: 'new' });
196
+ });
197
+ expect(hook.result.current.response).not.toContainEqual({ id: '1', name: 'new' });
198
+ expect(hook.result.current.response).toEqual({
199
+ items: [{ id: '0', name: 'item' }],
200
+ offset: 0,
201
+ rows: TEST_PAGE_SIZE,
202
+ total: TEST_TOTAL_COUNT,
203
+ removeCount: 0
204
+ });
205
+ });
206
+ it('should keep response null if it is uninitiated', () => {
207
+ const hook = renderProvider();
208
+ act(() => {
209
+ hook.result.current.replace('0', { id: '0', name: 'new' });
210
+ });
211
+ expect(hook.result.current.response).toBeNull();
212
+ });
213
+ it('should throw error if item id does not match the id provided', () => {
214
+ const hook = renderProvider({
215
+ items: [{ id: '0', name: 'old' }],
216
+ offset: 0,
217
+ rows: TEST_PAGE_SIZE,
218
+ total: TEST_TOTAL_COUNT,
219
+ removeCount: 0
220
+ });
221
+ expect(() => act(() => {
222
+ hook.result.current.replace('0', { id: '1', name: 'new' });
223
+ })).toThrow(/id does not match/);
224
+ });
225
+ });
226
+ describe('request', () => {
227
+ const apiSearchMock = vi.fn();
228
+ beforeEach(() => {
229
+ apiSearchMock.mockReset();
230
+ });
231
+ it('should update the response with the result of the request', async () => {
232
+ const hook = renderProvider({
233
+ items: [{ id: '0', name: 'item' }],
234
+ offset: 0,
235
+ rows: TEST_PAGE_SIZE,
236
+ total: TEST_TOTAL_COUNT,
237
+ removeCount: 0
238
+ });
239
+ const request = {
240
+ query: 'test',
241
+ rows: TEST_PAGE_SIZE,
242
+ offset: 0
243
+ };
244
+ apiSearchMock.mockResolvedValue({
245
+ items: [{ id: '1', name: 'new' }],
246
+ offset: request.offset,
247
+ rows: TEST_PAGE_SIZE,
248
+ total: TEST_TOTAL_COUNT
249
+ });
250
+ await act(async () => {
251
+ await hook.result.current.request(apiSearchMock, request);
252
+ });
253
+ expect(apiSearchMock).toHaveBeenCalledWith(request);
254
+ expect(hook.result.current.response).toEqual({
255
+ items: [{ id: '1', name: 'new' }],
256
+ offset: request.offset,
257
+ rows: TEST_PAGE_SIZE,
258
+ total: TEST_TOTAL_COUNT,
259
+ removeCount: 0
260
+ });
261
+ });
262
+ it.for([
263
+ { description: 'before', offset: 0 },
264
+ { description: 'the same as', offset: TEST_PAGE_SIZE }
265
+ ])('should reset removeCount if the offset is $description the current offset', async ({ offset }) => {
266
+ const hook = renderProvider({
267
+ items: [{ id: '0', name: 'item' }],
268
+ offset: TEST_PAGE_SIZE,
269
+ rows: TEST_PAGE_SIZE,
270
+ total: TEST_TOTAL_COUNT,
271
+ removeCount: 5
272
+ });
273
+ const request = {
274
+ query: 'test',
275
+ rows: TEST_PAGE_SIZE,
276
+ offset: offset
277
+ };
278
+ apiSearchMock.mockResolvedValue({
279
+ items: [{ id: '1', name: 'new' }],
280
+ offset: request.offset,
281
+ rows: TEST_PAGE_SIZE,
282
+ total: TEST_TOTAL_COUNT
283
+ });
284
+ await act(async () => {
285
+ await hook.result.current.request(apiSearchMock, request);
286
+ });
287
+ expect(apiSearchMock).toHaveBeenCalledWith(request);
288
+ expect(hook.result.current.response).toEqual({
289
+ items: [{ id: '1', name: 'new' }],
290
+ offset: request.offset,
291
+ rows: TEST_PAGE_SIZE,
292
+ total: TEST_TOTAL_COUNT,
293
+ removeCount: 0
294
+ });
295
+ });
296
+ it('should not reset removeCount if the offset is after the current offset', async () => {
297
+ const hook = renderProvider({
298
+ items: [{ id: '0', name: 'item' }],
299
+ offset: TEST_PAGE_SIZE,
300
+ rows: TEST_PAGE_SIZE,
301
+ total: TEST_TOTAL_COUNT,
302
+ removeCount: 5
303
+ });
304
+ const request = {
305
+ query: 'test',
306
+ rows: TEST_PAGE_SIZE,
307
+ offset: TEST_PAGE_SIZE * 2
308
+ };
309
+ apiSearchMock.mockResolvedValue({
310
+ items: [{ id: '1', name: 'new' }],
311
+ offset: request.offset,
312
+ rows: TEST_PAGE_SIZE,
313
+ total: TEST_TOTAL_COUNT
314
+ });
315
+ await act(async () => {
316
+ await hook.result.current.request(apiSearchMock, request);
317
+ });
318
+ expect(apiSearchMock).toHaveBeenCalledWith(request);
319
+ expect(hook.result.current.response).toEqual({
320
+ items: [{ id: '1', name: 'new' }],
321
+ offset: request.offset,
322
+ rows: TEST_PAGE_SIZE,
323
+ total: TEST_TOTAL_COUNT,
324
+ removeCount: 5
325
+ });
326
+ });
327
+ it('should keep response undefined if the request fails', async () => {
328
+ const hook = renderProvider();
329
+ const request = {
330
+ query: 'test',
331
+ rows: TEST_PAGE_SIZE,
332
+ offset: 0
333
+ };
334
+ apiSearchMock.mockRejectedValue(new Error('Request failed'));
335
+ await act(async () => {
336
+ await hook.result.current.request(apiSearchMock, request).catch(() => { });
337
+ });
338
+ expect(apiSearchMock).toHaveBeenCalledWith(request);
339
+ expect(hook.result.current.response).toBeNull();
340
+ });
341
+ it('should keep response unchanged if the request fails', async () => {
342
+ const initialResponse = {
343
+ items: [{ id: '0', name: 'item' }],
344
+ offset: 0,
345
+ rows: TEST_PAGE_SIZE,
346
+ total: TEST_TOTAL_COUNT,
347
+ removeCount: 5
348
+ };
349
+ const hook = renderProvider(initialResponse);
350
+ const request = {
351
+ query: 'test',
352
+ rows: TEST_PAGE_SIZE,
353
+ offset: 0
354
+ };
355
+ apiSearchMock.mockRejectedValue(new Error('Request failed'));
356
+ await act(async () => {
357
+ await hook.result.current.request(apiSearchMock, request).catch(() => { });
358
+ });
359
+ expect(apiSearchMock).toHaveBeenCalledWith(request);
360
+ expect(hook.result.current.response).toEqual(initialResponse);
361
+ });
362
+ it('should throw an error if the request throws an error', async () => {
363
+ const hook = renderProvider();
364
+ const request = {
365
+ query: 'test',
366
+ rows: TEST_PAGE_SIZE,
367
+ offset: 0
368
+ };
369
+ apiSearchMock.mockRejectedValue(new Error('Request failed'));
370
+ await expect(act(async () => {
371
+ await hook.result.current.request(apiSearchMock, request);
372
+ })).rejects.toThrow('Request failed');
373
+ });
374
+ });
375
+ describe('getSearchRequestData', () => {
376
+ it.for([
377
+ { description: 'no remove count', removeCount: 0 },
378
+ { description: 'with remove count', removeCount: 5 }
379
+ ])('should modify offset if it is provided - $description', ({ removeCount }) => {
380
+ const hook = renderProvider({
381
+ items: [],
382
+ offset: 0,
383
+ rows: TEST_PAGE_SIZE,
384
+ total: TEST_TOTAL_COUNT,
385
+ removeCount: removeCount
386
+ });
387
+ const modifiedRequest = hook.result.current.getSearchRequestData({ offset: TEST_PAGE_SIZE });
388
+ expect(modifiedRequest.offset).toBe(TEST_PAGE_SIZE - removeCount);
389
+ });
390
+ it('should not modify offset if it is not provided', () => {
391
+ const hook = renderProvider({
392
+ items: [],
393
+ offset: 0,
394
+ rows: TEST_PAGE_SIZE,
395
+ total: TEST_TOTAL_COUNT,
396
+ removeCount: 5
397
+ });
398
+ const modifiedRequest = hook.result.current.getSearchRequestData({ query: 'value' });
399
+ expect(modifiedRequest.offset).not.toBeDefined();
400
+ });
401
+ it('should not modify offset if response is uninitialised', () => {
402
+ const hook = renderProvider();
403
+ const modifiedRequest = hook.result.current.getSearchRequestData({ offset: TEST_PAGE_SIZE });
404
+ expect(modifiedRequest.offset).toBe(TEST_PAGE_SIZE);
405
+ });
406
+ });
@@ -48,18 +48,9 @@ interface SocketContextType {
48
48
  */
49
49
  reconnect: () => void;
50
50
  /**
51
- * Helper to tell if the socket is open
51
+ * Helper function to tell if the socket is open
52
52
  */
53
- open: boolean;
54
- /**
55
- * A map of entity IDs to their current viewers.
56
- */
57
- viewers: Record<string, string[]>;
58
- /**
59
- * Fetch the current viewers for an entity via REST, then keep in sync via socket.
60
- * @param entityId The entity ID to fetch viewers for
61
- */
62
- fetchViewers: (entityId: string) => Promise<void>;
53
+ isOpen: () => boolean;
63
54
  }
64
55
  export declare const SocketContext: import("react").Context<SocketContextType>;
65
56
  declare const SocketProvider: React.FC<PropsWithChildren>;
@@ -1,12 +1,11 @@
1
1
  import { jsx as _jsx } from "react/jsx-runtime";
2
2
  /* eslint-disable no-console */
3
3
  import api from '@cccsaurora/howler-ui/api';
4
- import useMyApi from '@cccsaurora/howler-ui/components/hooks/useMyApi';
5
4
  import useMyLocalStorage from '@cccsaurora/howler-ui/components/hooks/useMyLocalStorage';
6
- import { createContext, useCallback, useEffect, useMemo, useRef, useState } from 'react';
5
+ import { createContext, useCallback, useEffect, useRef, useState } from 'react';
7
6
  import { StorageKey } from '@cccsaurora/howler-ui/utils/constants';
8
7
  import { getStored, setAxiosCache, setStored } from '@cccsaurora/howler-ui/utils/sessionStorage';
9
- import { isHitUpdate, isViewersUpdate } from '@cccsaurora/howler-ui/utils/socketUtils';
8
+ import { isHitUpdate } from '@cccsaurora/howler-ui/utils/socketUtils';
10
9
  /**
11
10
  * Enum to help track the status of the Websocket, since the corresponding websocket enums are directly on the object
12
11
  */
@@ -20,7 +19,6 @@ export var Status;
20
19
  export const SocketContext = createContext(null);
21
20
  const SocketProvider = ({ children }) => {
22
21
  const { get } = useMyLocalStorage();
23
- const { dispatchApi } = useMyApi();
24
22
  // In order to persist the connection through state changes, we use a ref
25
23
  const socket = useRef();
26
24
  // Due to react setState race conditions, listeners are also stored in a ref
@@ -33,8 +31,6 @@ const SocketProvider = ({ children }) => {
33
31
  const [retry, setRetry] = useState(true);
34
32
  // Track the number of failed attempts when connecting to the server
35
33
  const [failedAttempts, setFailedAttempts] = useState(0);
36
- // Track active viewers per entity ID
37
- const [viewers, setViewers] = useState({});
38
34
  const onClose = useCallback(e => {
39
35
  // https://www.rfc-editor.org/rfc/rfc6455:
40
36
  // 1006 is a reserved value and MUST NOT be set as a status code in a
@@ -187,7 +183,7 @@ const SocketProvider = ({ children }) => {
187
183
  const addListener = useCallback((key, callback) => {
188
184
  // If a listener with the same key already exists, remove it.
189
185
  if (listeners.current[key]) {
190
- socket.current?.removeEventListener('message', listeners.current[key]);
186
+ socket.current?.removeEventListener('message', listeners[key]);
191
187
  }
192
188
  // We wrap the callback so that all the listeners don't need to JSON.parse the data
193
189
  const wrapped = ev => {
@@ -204,9 +200,6 @@ const SocketProvider = ({ children }) => {
204
200
  api_status_code: parsedData.status
205
201
  });
206
202
  }
207
- if (isViewersUpdate(parsedData)) {
208
- setViewers(prev => ({ ...prev, [parsedData.id]: parsedData.viewers }));
209
- }
210
203
  callback(parsedData);
211
204
  };
212
205
  socket.current?.addEventListener('message', wrapped);
@@ -226,14 +219,8 @@ const SocketProvider = ({ children }) => {
226
219
  }
227
220
  socket.current?.send(data);
228
221
  }, [status]);
229
- const open = useMemo(() => status === Status.OPEN, [status]);
222
+ const isOpen = useCallback(() => status === Status.OPEN, [status]);
230
223
  const reconnect = useCallback(() => setRetry(true), []);
231
- const fetchViewers = useCallback(async (entityId) => {
232
- const result = await dispatchApi(api.socket.viewers.get(entityId), { throwError: false });
233
- if (result) {
234
- setViewers(prev => ({ ...prev, [entityId]: result }));
235
- }
236
- }, [dispatchApi]);
237
- return (_jsx(SocketContext.Provider, { value: { addListener, removeListener, emit, status, reconnect, open, viewers, fetchViewers }, children: children }));
224
+ return (_jsx(SocketContext.Provider, { value: { addListener, removeListener, emit, status, reconnect, isOpen }, children: children }));
238
225
  };
239
226
  export default SocketProvider;
@@ -1,15 +1,11 @@
1
1
  import { jsx as _jsx } from "react/jsx-runtime";
2
2
  import api from '@cccsaurora/howler-ui/api';
3
3
  import useMyApi from '@cccsaurora/howler-ui/components/hooks/useMyApi';
4
- import { createContext, useCallback, useEffect, useRef, useState } from 'react';
4
+ import { createContext, useCallback, useState } from 'react';
5
5
  export const UserListContext = createContext(null);
6
6
  const UserListProvider = ({ children }) => {
7
7
  const { dispatchApi } = useMyApi();
8
8
  const [users, setUsers] = useState({});
9
- const usersRef = useRef(users);
10
- usersRef.current = users;
11
- const pendingIds = useRef(new Set());
12
- const debounceTimer = useRef(null);
13
9
  const searchUsers = useCallback(async (query) => {
14
10
  const newUsers = (await dispatchApi(api.search.user.post({ query, rows: 1000 }), {
15
11
  throwError: false,
@@ -21,30 +17,14 @@ const UserListProvider = ({ children }) => {
21
17
  ...newUsers
22
18
  }));
23
19
  }, [dispatchApi]);
24
- const fetchUsers = useCallback((ids) => {
25
- const nextIds = new Set(ids);
26
- nextIds.delete('Unknown');
27
- nextIds.forEach(id => pendingIds.current.add(id));
28
- if (debounceTimer.current) {
29
- clearTimeout(debounceTimer.current);
20
+ const fetchUsers = useCallback(async (ids) => {
21
+ ids.delete('Unknown');
22
+ const idsToGet = Array.from(ids.values()).filter(id => !Object.keys(users).includes(id));
23
+ if (idsToGet.length <= 0) {
24
+ return;
30
25
  }
31
- debounceTimer.current = setTimeout(async () => {
32
- const idsToGet = Array.from(pendingIds.current).filter(id => !Object.keys(usersRef.current).includes(id));
33
- pendingIds.current = new Set();
34
- debounceTimer.current = null;
35
- if (idsToGet.length <= 0) {
36
- return;
37
- }
38
- await searchUsers(`id:${idsToGet.join(' OR ')}`);
39
- }, 200);
40
- }, [searchUsers]);
41
- useEffect(() => {
42
- return () => {
43
- if (debounceTimer.current) {
44
- clearTimeout(debounceTimer.current);
45
- }
46
- };
47
- }, []);
26
+ await searchUsers(`id:${[...idsToGet].join(' OR ')}`);
27
+ }, [searchUsers, users]);
48
28
  return _jsx(UserListContext.Provider, { value: { users, fetchUsers, searchUsers }, children: children });
49
29
  };
50
30
  export default UserListProvider;
@@ -151,7 +151,10 @@ describe('ViewContext', () => {
151
151
  it('should allow users to edit views', async () => {
152
152
  const result = await act(async () => hook.result.current('example_view_id', { query: DEFAULT_QUERY }));
153
153
  expect(hput).toHaveBeenCalledOnce();
154
- expect(hput).toBeCalledWith('/api/v1/view/example_view_id', { query: DEFAULT_QUERY });
154
+ const [url, body, ...rest] = vi.mocked(hput).mock.calls[0];
155
+ expect(url).toBe('/api/v1/view/example_view_id');
156
+ expect(body).toEqual({ query: DEFAULT_QUERY });
157
+ expect(rest.every(v => v === undefined)).toBe(true);
155
158
  expect(result).toEqual(MOCK_RESPONSES['/api/v1/view/example_view_id']);
156
159
  });
157
160
  });
@@ -1,11 +1,10 @@
1
1
  import { type TypographyProps } from '@mui/material';
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
  export type PluginTypographyProps = TypographyProps & {
5
4
  value: string;
6
5
  context: string;
7
6
  field?: string;
8
- obj?: Hit | Observable;
7
+ hit?: Hit;
9
8
  };
10
9
  declare const _default: import("react").NamedExoticComponent<PluginTypographyProps>;
11
10
  export default _default;