@cccsaurora/howler-ui 2.19.0-dev.999 → 2.20.0-dev.1352

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 (653) 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 +5 -5
  4. package/api/analytic/index.js +5 -6
  5. package/api/analytic/owner.d.ts +2 -1
  6. package/api/analytic/owner.js +2 -2
  7. package/api/dossier/index.d.ts +4 -3
  8. package/api/dossier/index.js +6 -6
  9. package/api/hit/index.d.ts +3 -2
  10. package/api/hit/index.js +4 -4
  11. package/api/hit/labels.d.ts +3 -2
  12. package/api/hit/labels.js +4 -4
  13. package/api/hit/overwrite.d.ts +2 -1
  14. package/api/hit/overwrite.js +2 -2
  15. package/api/hit/transition.d.ts +2 -1
  16. package/api/hit/transition.js +2 -2
  17. package/api/index.d.ts +10 -5
  18. package/api/index.js +18 -10
  19. package/api/overview/index.d.ts +4 -3
  20. package/api/overview/index.js +6 -6
  21. package/api/search/action.js +1 -1
  22. package/api/search/analytic.js +1 -1
  23. package/api/search/case.d.ts +4 -0
  24. package/api/search/case.js +8 -0
  25. package/api/search/count/hit.js +1 -1
  26. package/api/search/dossier.js +1 -1
  27. package/api/search/eql/hit.js +1 -1
  28. package/api/search/explain/hit.js +1 -1
  29. package/api/search/facet/hit.d.ts +1 -3
  30. package/api/search/facet/hit.js +1 -1
  31. package/api/search/facet/index.d.ts +3 -1
  32. package/api/search/grouped/hit.js +1 -1
  33. package/api/search/grouped/user.js +1 -1
  34. package/api/search/histogram/hit.js +1 -1
  35. package/api/search/hit.js +1 -1
  36. package/api/search/index.d.ts +3 -1
  37. package/api/search/index.js +2 -1
  38. package/api/search/overview.d.ts +2 -2
  39. package/api/search/overview.js +1 -1
  40. package/api/search/sigma/hit.js +1 -1
  41. package/api/search/template.js +1 -1
  42. package/api/search/user.js +1 -1
  43. package/api/search/view.js +1 -1
  44. package/api/socket/index.d.ts +3 -0
  45. package/api/socket/index.js +6 -0
  46. package/api/socket/viewers.d.ts +2 -0
  47. package/api/socket/viewers.js +8 -0
  48. package/api/socket/viewers.test.js +44 -0
  49. package/api/template/index.d.ts +4 -3
  50. package/api/template/index.js +6 -6
  51. package/api/user/index.d.ts +2 -1
  52. package/api/user/index.js +2 -2
  53. package/api/v2/case/index.d.ts +9 -0
  54. package/api/v2/case/index.js +21 -0
  55. package/api/v2/case/items.d.ts +9 -0
  56. package/api/v2/case/items.js +19 -0
  57. package/api/v2/case/rules.d.ts +6 -0
  58. package/api/v2/case/rules.js +18 -0
  59. package/api/v2/fuzzy.d.ts +17 -0
  60. package/api/v2/fuzzy.js +11 -0
  61. package/api/v2/index.d.ts +5 -0
  62. package/api/v2/index.js +7 -0
  63. package/api/v2/search/facet.d.ts +3 -0
  64. package/api/v2/search/facet.js +12 -0
  65. package/api/v2/search/index.d.ts +6 -0
  66. package/api/v2/search/index.js +24 -0
  67. package/api/view/index.d.ts +4 -3
  68. package/api/view/index.js +6 -6
  69. package/branding/AppBrand.d.ts +2 -2
  70. package/commons/components/app/AppSkeleton.js +1 -1
  71. package/commons/components/app/hooks/useAppConfigs.d.ts +2 -2
  72. package/commons/components/app/hooks/useAppSitemap.d.ts +5 -2
  73. package/commons/components/breadcrumbs/BreadcrumbIcon.js +1 -1
  74. package/commons/components/breadcrumbs/Breadcrumbs.d.ts +3 -2
  75. package/commons/components/display/AppToc.d.ts +2 -1
  76. package/commons/components/display/AppToc.js +1 -1
  77. package/commons/components/display/hooks/useAppColor.d.ts +1 -1
  78. package/commons/components/leftnav/LeftNavDrawer.d.ts +2 -1
  79. package/commons/components/leftnav/LeftNavDrawer.js +1 -1
  80. package/commons/components/leftnav/LeftNavGroup.d.ts +2 -1
  81. package/commons/components/leftnav/LeftNavItem.d.ts +2 -1
  82. package/commons/components/leftnav/LeftNavItem.js +1 -1
  83. package/commons/components/notification/Notification.js +1 -1
  84. package/commons/components/notification/elements/NotificationHeader.js +1 -1
  85. package/commons/components/notification/elements/NotificationItems.js +1 -1
  86. package/commons/components/notification/elements/item/NotificationItemAuthor.js +1 -1
  87. package/commons/components/pages/PageCenter.d.ts +2 -1
  88. package/commons/components/pages/PageContent.d.ts +2 -1
  89. package/commons/components/pages/PageFullScreen.d.ts +2 -1
  90. package/commons/components/search/AppSearch.js +1 -1
  91. package/commons/components/search/AppSearchInput.d.ts +2 -1
  92. package/commons/components/search/AppSearchResult.d.ts +2 -1
  93. package/commons/components/topnav/AppBar.d.ts +2 -1
  94. package/commons/components/topnav/AppName.d.ts +3 -2
  95. package/commons/components/topnav/AppSwitcher.d.ts +2 -1
  96. package/commons/components/topnav/ThemeSelection.d.ts +2 -1
  97. package/commons/components/topnav/ThemeSelection.js +1 -1
  98. package/commons/components/topnav/UserProfile.d.ts +2 -1
  99. package/commons/components/topnav/UserProfile.js +1 -1
  100. package/commons/components/utils/hooks/useThemeBuilder.d.ts +1 -1
  101. package/components/app/App.js +52 -12
  102. package/components/app/drawers/ApiKeyDrawer.js +1 -1
  103. package/components/app/hooks/useMatchers.d.ts +1 -1
  104. package/components/app/hooks/useMatchers.js +27 -15
  105. package/components/app/hooks/useMatchers.test.js +22 -22
  106. package/components/app/hooks/useTitle.js +6 -6
  107. package/components/app/providers/AnalyticProvider.js +1 -1
  108. package/components/app/providers/AvatarProvider.js +1 -1
  109. package/components/app/providers/FavouritesProvider.js +3 -3
  110. package/components/app/providers/GridColumnsProvider.d.ts +52 -0
  111. package/components/app/providers/GridColumnsProvider.js +177 -0
  112. package/components/app/providers/GridColumnsProvider.test.js +255 -0
  113. package/components/app/providers/ModalProvider.d.ts +1 -0
  114. package/components/app/providers/OverviewProvider.js +1 -1
  115. package/components/app/providers/ParameterProvider.d.ts +25 -3
  116. package/components/app/providers/ParameterProvider.js +163 -226
  117. package/components/app/providers/ParameterProvider.test.js +358 -94
  118. package/components/app/providers/RecordProvider.d.ts +23 -0
  119. package/components/app/providers/{HitProvider.js → RecordProvider.js} +47 -43
  120. package/components/app/providers/{HitSearchProvider.d.ts → RecordSearchProvider.d.ts} +6 -6
  121. package/components/app/providers/{HitSearchProvider.js → RecordSearchProvider.js} +24 -37
  122. package/components/app/providers/{HitSearchProvider.test.js → RecordSearchProvider.test.js} +52 -71
  123. package/components/app/providers/SearchResponseProvider.d.ts +21 -0
  124. package/components/app/providers/SearchResponseProvider.js +81 -0
  125. package/components/app/providers/SearchResponseProvider.test.d.ts +1 -0
  126. package/components/app/providers/SearchResponseProvider.test.js +406 -0
  127. package/components/app/providers/SocketProvider.d.ts +11 -2
  128. package/components/app/providers/SocketProvider.js +21 -8
  129. package/components/app/providers/UserListProvider.js +28 -8
  130. package/components/app/providers/UserListProvider.test.d.ts +1 -0
  131. package/components/app/providers/UserListProvider.test.js +150 -0
  132. package/components/app/providers/ViewProvider.js +3 -3
  133. package/components/app/providers/ViewProvider.test.js +4 -1
  134. package/components/elements/Comment.js +2 -2
  135. package/components/elements/ContextMenu.d.ts +56 -0
  136. package/components/elements/ContextMenu.js +113 -0
  137. package/components/elements/ContextMenu.test.d.ts +1 -0
  138. package/components/elements/ContextMenu.test.js +215 -0
  139. package/components/elements/EditRow.js +4 -4
  140. package/components/{routes/overviews/OverviewEditor.js → elements/MarkdownEditor.js} +3 -3
  141. package/components/elements/ObjectDetails.d.ts +6 -0
  142. package/components/elements/{hit/HitDetails.js → ObjectDetails.js} +17 -17
  143. package/components/elements/PluginChip.d.ts +1 -1
  144. package/components/elements/PluginChip.js +0 -1
  145. package/components/elements/PluginTypography.d.ts +2 -1
  146. package/components/elements/PluginTypography.js +3 -2
  147. package/components/elements/UserList.d.ts +5 -2
  148. package/components/elements/UserList.js +34 -17
  149. package/components/elements/UserList.test.d.ts +1 -0
  150. package/components/elements/UserList.test.js +122 -0
  151. package/components/elements/addons/buttons/CustomIconButton.test.d.ts +1 -0
  152. package/components/elements/addons/buttons/CustomIconButton.test.js +81 -0
  153. package/components/elements/addons/buttons/index.d.ts +1 -1
  154. package/components/elements/addons/layout/FlexOne.d.ts +3 -2
  155. package/components/elements/addons/layout/FlexPort.d.ts +2 -1
  156. package/components/elements/addons/layout/FlexVertical.d.ts +2 -1
  157. package/components/elements/addons/layout/FlexVertical.test.d.ts +1 -0
  158. package/components/elements/addons/layout/FlexVertical.test.js +32 -0
  159. package/components/elements/addons/layout/vsbox/VSBoxContent.test.d.ts +1 -0
  160. package/components/elements/addons/layout/vsbox/VSBoxContent.test.js +26 -0
  161. package/components/elements/addons/layout/vsbox/VSBoxElement.d.ts +2 -1
  162. package/components/elements/addons/lists/TuiList.d.ts +2 -1
  163. package/components/elements/addons/lists/TuiListBase.d.ts +2 -1
  164. package/components/elements/addons/lists/TuiListElement.d.ts +3 -2
  165. package/components/elements/addons/lists/TuiListElement.js +0 -1
  166. package/components/elements/addons/lists/TuiListMenu.d.ts +2 -1
  167. package/components/elements/addons/lists/TuiListMenu.js +1 -1
  168. package/components/elements/addons/lists/table/TuiTableHeader.d.ts +3 -2
  169. package/components/elements/addons/lists/table/index.d.ts +1 -1
  170. package/components/elements/addons/search/SearchPagination.d.ts +2 -1
  171. package/components/elements/addons/search/SearchPagination.js +4 -4
  172. package/components/elements/addons/search/SearchTotal.js +1 -1
  173. package/components/elements/addons/search/SearchTotal.test.js +5 -3
  174. package/components/elements/addons/search/phrase/Phrase.js +1 -1
  175. package/components/elements/addons/search/phrase/WordLexer.test.d.ts +1 -0
  176. package/components/elements/addons/search/phrase/WordLexer.test.js +55 -0
  177. package/components/elements/case/CaseCard.d.ts +12 -0
  178. package/components/elements/case/CaseCard.js +43 -0
  179. package/components/elements/case/CasePreview.d.ts +6 -0
  180. package/components/elements/case/CasePreview.js +17 -0
  181. package/components/elements/case/StatusIcon.d.ts +5 -0
  182. package/components/elements/case/StatusIcon.js +13 -0
  183. package/components/elements/display/ActionButton.js +1 -1
  184. package/components/elements/display/ChipPopper.d.ts +1 -1
  185. package/components/elements/display/ChipPopper.js +7 -6
  186. package/components/elements/display/Classification.js +1 -1
  187. package/components/elements/display/ClassificationChip.d.ts +14 -0
  188. package/components/elements/display/ClassificationChip.js +36 -0
  189. package/components/elements/display/HandlebarsMarkdown.js +38 -3
  190. package/components/elements/display/HowlerAvatar.js +2 -2
  191. package/components/elements/display/HowlerCard.js +1 -1
  192. package/components/elements/display/HowlerCard.test.js +5 -9
  193. package/components/elements/display/Image.js +3 -3
  194. package/components/elements/display/ItemManager.d.ts +2 -2
  195. package/components/elements/display/ItemManager.js +3 -3
  196. package/components/elements/display/Markdown.js +2 -2
  197. package/components/elements/display/Modal.js +2 -0
  198. package/components/elements/display/QueryResultText.d.ts +1 -0
  199. package/components/elements/display/QueryResultText.js +2 -2
  200. package/components/elements/display/handlebars/helpers.d.ts +4 -0
  201. package/components/elements/display/handlebars/helpers.js +134 -35
  202. package/components/elements/display/json/JSONViewer.js +2 -2
  203. package/components/elements/display/modals/RationaleModal.js +2 -2
  204. package/components/elements/display/modals/RationaleModal.test.js +1 -1
  205. package/components/elements/event/EventCard.d.ts +6 -0
  206. package/components/elements/event/EventCard.js +22 -0
  207. package/components/elements/event/EventPreview.d.ts +6 -0
  208. package/components/elements/event/EventPreview.js +12 -0
  209. package/components/elements/hit/HitActions.d.ts +1 -1
  210. package/components/elements/hit/HitActions.js +5 -5
  211. package/components/elements/hit/HitBanner.d.ts +1 -0
  212. package/components/elements/hit/HitBanner.js +32 -50
  213. package/components/elements/hit/HitCard.d.ts +4 -0
  214. package/components/elements/hit/HitCard.js +7 -7
  215. package/components/elements/hit/HitLabels.js +3 -3
  216. package/components/elements/hit/HitLabels.test.d.ts +1 -0
  217. package/components/elements/hit/HitLabels.test.js +77 -0
  218. package/components/elements/hit/HitLinks.d.ts +5 -4
  219. package/components/elements/hit/HitLinks.js +28 -10
  220. package/components/elements/hit/HitNotebooks.js +32 -31
  221. package/components/elements/hit/HitOutline.d.ts +1 -0
  222. package/components/elements/hit/HitOutline.js +4 -4
  223. package/components/elements/hit/HitOverview.js +2 -2
  224. package/components/elements/hit/{HitQuickSearch.d.ts → HitPreview.d.ts} +3 -3
  225. package/components/elements/hit/{HitQuickSearch.js → HitPreview.js} +11 -5
  226. package/components/elements/hit/HitSummary.d.ts +2 -1
  227. package/components/elements/hit/HitSummary.js +8 -7
  228. package/components/elements/hit/NotebookTooltip.d.ts +3 -0
  229. package/components/elements/hit/NotebookTooltip.js +8 -0
  230. package/components/elements/hit/PivotTooltip.d.ts +7 -0
  231. package/components/elements/hit/PivotTooltip.js +9 -0
  232. package/components/elements/hit/RelatedLinkTooltip.d.ts +6 -0
  233. package/components/elements/hit/RelatedLinkTooltip.js +8 -0
  234. package/components/elements/hit/ResolvePivotUrl.d.ts +4 -0
  235. package/components/elements/hit/ResolvePivotUrl.js +22 -0
  236. package/components/elements/hit/actions/ButtonActions.js +1 -3
  237. package/components/elements/hit/aggregate/HitGraph.js +9 -9
  238. package/components/elements/hit/elements/AnalyticLink.d.ts +9 -0
  239. package/components/elements/hit/elements/AnalyticLink.js +22 -0
  240. package/components/elements/hit/elements/{HitUsers.d.ts → Assigned.d.ts} +2 -4
  241. package/components/elements/hit/elements/Assigned.js +35 -0
  242. package/components/elements/hit/elements/Assigned.test.d.ts +1 -0
  243. package/components/elements/hit/elements/Assigned.test.js +65 -0
  244. package/components/{routes/hits/search → elements/hit}/grid/AddColumnModal.js +6 -5
  245. package/components/{routes/hits/search → elements/hit}/grid/ColumnHeader.d.ts +2 -1
  246. package/components/{routes/hits/search → elements/hit}/grid/ColumnHeader.js +3 -3
  247. package/components/{routes/hits/search → elements/hit}/grid/EnhancedCell.d.ts +2 -1
  248. package/components/{routes/hits/search → elements/hit}/grid/EnhancedCell.js +2 -2
  249. package/components/{routes/hits/search/grid/HitRow.d.ts → elements/hit/grid/RecordRow.d.ts} +4 -3
  250. package/components/{routes/hits/search/grid/HitRow.js → elements/hit/grid/RecordRow.js} +12 -10
  251. package/components/elements/hit/grid/RecordTable.d.ts +13 -0
  252. package/components/elements/hit/grid/RecordTable.js +84 -0
  253. package/components/elements/hit/outlines/DefaultOutline.js +2 -4
  254. package/components/elements/hit/related/PivotLink.d.ts +3 -0
  255. package/components/elements/hit/related/PivotLink.js +6 -3
  256. package/components/elements/hit/related/RelatedLink.d.ts +1 -0
  257. package/components/elements/hit/related/RelatedLink.js +18 -15
  258. package/components/elements/hit/related/RelatedRecords.js +63 -0
  259. package/components/elements/{hit/HitComments.d.ts → record/RecordComments.d.ts} +5 -4
  260. package/components/elements/{hit/HitComments.js → record/RecordComments.js} +33 -34
  261. package/components/{routes/hits/search/HitContextMenu.d.ts → elements/record/RecordContextMenu.d.ts} +3 -3
  262. package/components/elements/record/RecordContextMenu.js +268 -0
  263. package/components/elements/record/RecordContextMenu.test.d.ts +1 -0
  264. package/components/{routes/hits/search/HitContextMenu.test.js → elements/record/RecordContextMenu.test.js} +143 -49
  265. package/components/elements/record/RecordRelated.d.ts +7 -0
  266. package/components/elements/record/RecordRelated.js +34 -0
  267. package/components/elements/{hit/HitWorklog.d.ts → record/RecordWorklog.d.ts} +4 -3
  268. package/components/elements/{hit/HitWorklog.js → record/RecordWorklog.js} +16 -14
  269. package/components/elements/search/FuzzySearchBar.d.ts +7 -0
  270. package/components/elements/search/FuzzySearchBar.js +33 -0
  271. package/components/elements/search/FuzzySearchBar.test.d.ts +1 -0
  272. package/components/elements/search/FuzzySearchBar.test.js +87 -0
  273. package/components/elements/view/LayoutToggle.d.ts +8 -0
  274. package/components/elements/view/LayoutToggle.js +12 -0
  275. package/components/elements/view/ViewTitle.d.ts +4 -0
  276. package/components/elements/view/ViewTitle.js +13 -3
  277. package/components/hooks/useHitActions.d.ts +1 -1
  278. package/components/hooks/useHitActions.js +5 -5
  279. package/components/hooks/useLocalStorage.js +1 -1
  280. package/components/hooks/useLocalStorageItem.test.js +2 -2
  281. package/components/hooks/useMyApi.d.ts +1 -1
  282. package/components/hooks/useMyChart.d.ts +23 -23
  283. package/components/hooks/useMyPreferences.js +10 -1
  284. package/components/hooks/useMySearch.js +2 -2
  285. package/components/hooks/useMySitemap.js +3 -1
  286. package/components/hooks/useMySnackbar.js +1 -1
  287. package/components/hooks/useMyTheme.js +9 -2
  288. package/components/hooks/useMyTheme.test.d.ts +1 -0
  289. package/components/hooks/useMyTheme.test.js +35 -0
  290. package/components/hooks/useMyUserFunctions.d.ts +21 -21
  291. package/components/hooks/{useHitSelection.d.ts → useRecordSelection.d.ts} +2 -2
  292. package/components/hooks/{useHitSelection.js → useRecordSelection.js} +12 -33
  293. package/components/hooks/useRelatedRecords.d.ts +13 -0
  294. package/components/hooks/useRelatedRecords.js +32 -0
  295. package/components/logins/Login.js +1 -1
  296. package/components/logins/auth/OAuthLogin.js +1 -1
  297. package/components/logins/hooks/useLogin.js +2 -2
  298. package/components/routes/ErrorBoundary.d.ts +2 -13
  299. package/components/routes/ErrorBoundary.js +12 -1
  300. package/components/routes/ErrorBoundary.test.js +27 -4
  301. package/components/routes/action/edit/ActionEditor.js +6 -6
  302. package/components/routes/action/shared/OperationEntry.js +1 -1
  303. package/components/routes/action/shared/OperationStep.js +1 -1
  304. package/components/routes/action/useMyActionFunctions.js +6 -3
  305. package/components/routes/action/view/ActionDetails.js +9 -3
  306. package/components/routes/action/view/ActionSearch.js +25 -19
  307. package/components/routes/admin/users/UserEditor.js +1 -1
  308. package/components/routes/admin/users/UserSearch.js +5 -5
  309. package/components/routes/advanced/QueryBuilder.js +6 -29
  310. package/components/routes/advanced/QueryEditor.js +3 -3
  311. package/components/routes/advanced/eqlTokenProvider.test.d.ts +1 -0
  312. package/components/routes/advanced/eqlTokenProvider.test.js +34 -0
  313. package/components/routes/advanced/historyCompletionProvider.js +3 -3
  314. package/components/routes/advanced/luceneCompletionProvider.js +1 -1
  315. package/components/routes/advanced/luceneTokenProvider.test.d.ts +1 -0
  316. package/components/routes/advanced/luceneTokenProvider.test.js +34 -0
  317. package/components/routes/analytics/AnalyticComments.js +3 -5
  318. package/components/routes/analytics/AnalyticDetails.js +8 -56
  319. package/components/routes/analytics/AnalyticHitComments.js +1 -1
  320. package/components/routes/analytics/AnalyticHitComments.test.js +1 -1
  321. package/components/routes/analytics/AnalyticOverview.js +2 -2
  322. package/components/routes/analytics/AnalyticOverviews.js +1 -1
  323. package/components/routes/analytics/AnalyticSearch.js +16 -25
  324. package/components/routes/analytics/AnalyticTemplates.js +1 -1
  325. package/components/routes/analytics/TriageSettings.js +2 -2
  326. package/components/routes/analytics/widgets/Assessment.js +1 -1
  327. package/components/routes/analytics/widgets/Created.js +1 -1
  328. package/components/routes/analytics/widgets/Escalation.js +1 -1
  329. package/components/routes/analytics/widgets/Stacked.js +1 -1
  330. package/components/routes/cases/CaseViewer.d.ts +2 -0
  331. package/components/routes/cases/CaseViewer.js +44 -0
  332. package/components/routes/cases/CaseViewer.test.d.ts +1 -0
  333. package/components/routes/cases/CaseViewer.test.js +156 -0
  334. package/components/routes/cases/Cases.d.ts +2 -0
  335. package/components/routes/cases/Cases.js +140 -0
  336. package/components/routes/cases/constants.d.ts +6 -0
  337. package/components/routes/cases/constants.js +6 -0
  338. package/components/routes/cases/detail/AlertPanel.d.ts +6 -0
  339. package/components/routes/cases/detail/AlertPanel.js +34 -0
  340. package/components/routes/cases/detail/AlertPanel.test.d.ts +1 -0
  341. package/components/routes/cases/detail/AlertPanel.test.js +107 -0
  342. package/components/routes/cases/detail/CaseDashboard.d.ts +7 -0
  343. package/components/routes/cases/detail/CaseDashboard.js +66 -0
  344. package/components/routes/cases/detail/CaseDashboard.test.d.ts +1 -0
  345. package/components/routes/cases/detail/CaseDashboard.test.js +218 -0
  346. package/components/routes/cases/detail/CaseDetails.d.ts +6 -0
  347. package/components/routes/cases/detail/CaseDetails.js +79 -0
  348. package/components/routes/cases/detail/CaseDetails.test.d.ts +1 -0
  349. package/components/routes/cases/detail/CaseDetails.test.js +145 -0
  350. package/components/routes/cases/detail/CaseObservables.d.ts +6 -0
  351. package/components/routes/cases/detail/CaseObservables.js +127 -0
  352. package/components/routes/cases/detail/CaseObservables.test.d.ts +1 -0
  353. package/components/routes/cases/detail/CaseObservables.test.js +167 -0
  354. package/components/routes/cases/detail/CaseOverview.d.ts +7 -0
  355. package/components/routes/cases/detail/CaseOverview.js +40 -0
  356. package/components/routes/cases/detail/CaseRules.d.ts +7 -0
  357. package/components/routes/cases/detail/CaseRules.js +55 -0
  358. package/components/routes/cases/detail/CaseRules.test.d.ts +1 -0
  359. package/components/routes/cases/detail/CaseRules.test.js +238 -0
  360. package/components/routes/cases/detail/CaseSearch.d.ts +3 -0
  361. package/components/routes/cases/detail/CaseSearch.js +78 -0
  362. package/components/routes/cases/detail/CaseSearch.test.d.ts +1 -0
  363. package/components/routes/cases/detail/CaseSearch.test.js +154 -0
  364. package/components/routes/cases/detail/CaseSidebar.d.ts +8 -0
  365. package/components/routes/cases/detail/CaseSidebar.js +147 -0
  366. package/components/routes/cases/detail/CaseSidebar.test.d.ts +1 -0
  367. package/components/routes/cases/detail/CaseSidebar.test.js +155 -0
  368. package/components/routes/cases/detail/CaseTask.d.ts +14 -0
  369. package/components/routes/cases/detail/CaseTask.js +71 -0
  370. package/components/routes/cases/detail/CaseTask.test.d.ts +1 -0
  371. package/components/routes/cases/detail/CaseTask.test.js +143 -0
  372. package/components/routes/cases/detail/CaseTimeline.d.ts +12 -0
  373. package/components/routes/cases/detail/CaseTimeline.js +120 -0
  374. package/components/routes/cases/detail/CaseTimeline.test.d.ts +1 -0
  375. package/components/routes/cases/detail/CaseTimeline.test.js +319 -0
  376. package/components/routes/cases/detail/CreateRuleDialog.d.ts +9 -0
  377. package/components/routes/cases/detail/CreateRuleDialog.js +145 -0
  378. package/components/routes/cases/detail/CreateRuleDialog.test.d.ts +1 -0
  379. package/components/routes/cases/detail/CreateRuleDialog.test.js +218 -0
  380. package/components/routes/cases/detail/ItemPage.d.ts +6 -0
  381. package/components/routes/cases/detail/ItemPage.js +100 -0
  382. package/components/routes/cases/detail/ItemPage.test.d.ts +1 -0
  383. package/components/routes/cases/detail/ItemPage.test.js +238 -0
  384. package/components/routes/cases/detail/MarkdownPage.d.ts +8 -0
  385. package/components/routes/cases/detail/MarkdownPage.js +63 -0
  386. package/components/routes/cases/detail/MarkdownPage.test.d.ts +1 -0
  387. package/components/routes/cases/detail/MarkdownPage.test.js +116 -0
  388. package/components/routes/cases/detail/RelatedCasePanel.d.ts +6 -0
  389. package/components/routes/cases/detail/RelatedCasePanel.js +34 -0
  390. package/components/routes/cases/detail/RelatedCasePanel.test.d.ts +1 -0
  391. package/components/routes/cases/detail/RelatedCasePanel.test.js +115 -0
  392. package/components/routes/cases/detail/TaskPanel.d.ts +7 -0
  393. package/components/routes/cases/detail/TaskPanel.js +95 -0
  394. package/components/routes/cases/detail/TaskPanel.test.d.ts +1 -0
  395. package/components/routes/cases/detail/TaskPanel.test.js +145 -0
  396. package/components/routes/cases/detail/aggregates/CaseAggregate.d.ts +11 -0
  397. package/components/routes/cases/detail/aggregates/CaseAggregate.js +24 -0
  398. package/components/routes/cases/detail/aggregates/SourceAggregate.d.ts +6 -0
  399. package/components/routes/cases/detail/aggregates/SourceAggregate.js +26 -0
  400. package/components/routes/cases/detail/observables/Observable.d.ts +8 -0
  401. package/components/routes/cases/detail/observables/Observable.js +14 -0
  402. package/components/routes/cases/detail/observables/Observable.test.d.ts +1 -0
  403. package/components/routes/cases/detail/observables/Observable.test.js +80 -0
  404. package/components/routes/cases/detail/observables/ObservableTable.d.ts +7 -0
  405. package/components/routes/cases/detail/observables/ObservableTable.js +61 -0
  406. package/components/routes/cases/detail/observables/ObservableTable.test.d.ts +1 -0
  407. package/components/routes/cases/detail/observables/ObservableTable.test.js +97 -0
  408. package/components/routes/cases/detail/sidebar/CaseFolder.d.ts +22 -0
  409. package/components/routes/cases/detail/sidebar/CaseFolder.js +105 -0
  410. package/components/routes/cases/detail/sidebar/CaseFolder.test.d.ts +1 -0
  411. package/components/routes/cases/detail/sidebar/CaseFolder.test.js +98 -0
  412. package/components/routes/cases/detail/sidebar/CaseFolderContextMenu.d.ts +32 -0
  413. package/components/routes/cases/detail/sidebar/CaseFolderContextMenu.js +99 -0
  414. package/components/routes/cases/detail/sidebar/CaseFolderContextMenu.test.d.ts +1 -0
  415. package/components/routes/cases/detail/sidebar/CaseFolderContextMenu.test.js +117 -0
  416. package/components/routes/cases/detail/sidebar/FolderEntry.d.ts +25 -0
  417. package/components/routes/cases/detail/sidebar/FolderEntry.js +89 -0
  418. package/components/routes/cases/detail/sidebar/FolderEntry.test.d.ts +1 -0
  419. package/components/routes/cases/detail/sidebar/FolderEntry.test.js +81 -0
  420. package/components/routes/cases/detail/sidebar/RootDropZone.d.ts +5 -0
  421. package/components/routes/cases/detail/sidebar/RootDropZone.js +33 -0
  422. package/components/routes/cases/detail/sidebar/types.d.ts +9 -0
  423. package/components/routes/cases/detail/sidebar/utils.d.ts +10 -0
  424. package/components/routes/cases/detail/sidebar/utils.js +51 -0
  425. package/components/routes/cases/detail/sidebar/utils.test.d.ts +1 -0
  426. package/components/routes/cases/detail/sidebar/utils.test.js +82 -0
  427. package/components/routes/cases/detail/types.d.ts +22 -0
  428. package/components/routes/cases/detail/utils.d.ts +28 -0
  429. package/components/routes/cases/detail/utils.js +117 -0
  430. package/components/routes/cases/detail/utils.test.d.ts +1 -0
  431. package/components/routes/cases/detail/utils.test.js +166 -0
  432. package/components/routes/cases/hooks/useCase.d.ts +13 -0
  433. package/components/routes/cases/hooks/useCase.js +67 -0
  434. package/components/routes/cases/hooks/useCase.test.d.ts +1 -0
  435. package/components/routes/cases/hooks/useCase.test.js +170 -0
  436. package/components/routes/cases/modals/AddRecordToCaseModal.d.ts +7 -0
  437. package/components/routes/cases/modals/AddRecordToCaseModal.js +57 -0
  438. package/components/routes/cases/modals/AddRecordToCaseModal.test.d.ts +1 -0
  439. package/components/routes/cases/modals/AddRecordToCaseModal.test.js +309 -0
  440. package/components/routes/cases/modals/AddToCaseModal.d.ts +9 -0
  441. package/components/routes/cases/modals/AddToCaseModal.js +72 -0
  442. package/components/routes/cases/modals/CaseRecordRow.d.ts +9 -0
  443. package/components/routes/cases/modals/CaseRecordRow.js +14 -0
  444. package/components/routes/cases/modals/CreateCaseModal.d.ts +7 -0
  445. package/components/routes/cases/modals/CreateCaseModal.js +53 -0
  446. package/components/routes/cases/modals/CreateCaseModal.test.d.ts +1 -0
  447. package/components/routes/cases/modals/CreateCaseModal.test.js +319 -0
  448. package/components/routes/cases/modals/RenameItemModal.d.ts +9 -0
  449. package/components/routes/cases/modals/RenameItemModal.js +44 -0
  450. package/components/routes/cases/modals/ResolveModal.d.ts +7 -0
  451. package/components/routes/cases/modals/ResolveModal.js +120 -0
  452. package/components/routes/cases/modals/ResolveModal.test.d.ts +1 -0
  453. package/components/routes/cases/modals/ResolveModal.test.js +520 -0
  454. package/components/routes/cases/modals/hooks.d.ts +7 -0
  455. package/components/routes/cases/modals/hooks.js +40 -0
  456. package/components/routes/cases/modals/types.d.ts +13 -0
  457. package/components/routes/cases/search/CaseAssigneeFilter.d.ts +6 -0
  458. package/components/routes/cases/search/CaseAssigneeFilter.js +33 -0
  459. package/components/routes/cases/search/CaseAssigneeFilter.test.d.ts +1 -0
  460. package/components/routes/cases/search/CaseAssigneeFilter.test.js +127 -0
  461. package/components/routes/cases/search/CaseDateFilter.d.ts +13 -0
  462. package/components/routes/cases/search/CaseDateFilter.js +26 -0
  463. package/components/routes/cases/search/CaseDateFilter.test.d.ts +1 -0
  464. package/components/routes/cases/search/CaseDateFilter.test.js +115 -0
  465. package/components/routes/cases/search/CaseStatusFilter.d.ts +6 -0
  466. package/components/routes/cases/search/CaseStatusFilter.js +13 -0
  467. package/components/routes/cases/search/CaseStatusFilter.test.d.ts +1 -0
  468. package/components/routes/cases/search/CaseStatusFilter.test.js +86 -0
  469. package/components/routes/cases/utils.d.ts +3 -0
  470. package/components/routes/cases/utils.js +21 -0
  471. package/components/routes/dossiers/DossierEditor.js +4 -4
  472. package/components/routes/dossiers/DossierEditor.test.js +2 -2
  473. package/components/routes/dossiers/Dossiers.js +16 -14
  474. package/components/routes/dossiers/PivotForm.js +2 -4
  475. package/components/routes/events/EventViewer.d.ts +7 -0
  476. package/components/routes/events/EventViewer.js +24 -0
  477. package/components/routes/help/ApiDocumentation.js +2 -2
  478. package/components/routes/help/HitBannerDocumentation.js +2 -1
  479. package/components/routes/help/HitDocumentation.js +1 -3
  480. package/components/routes/help/HitSchemaDocumentation.js +1 -1
  481. package/components/routes/help/OverviewDocumentation.d.ts +1 -1
  482. package/components/routes/help/OverviewDocumentation.js +0 -1
  483. package/components/routes/help/RetentionDocumentation.js +2 -2
  484. package/components/routes/help/SearchDocumentation.js +1 -1
  485. package/components/routes/help/markdown/en/client.md.js +1 -1
  486. package/components/routes/help/markdown/fr/client.md.js +1 -1
  487. package/components/routes/hits/search/InformationPane.d.ts +1 -0
  488. package/components/routes/hits/search/InformationPane.js +52 -65
  489. package/components/routes/hits/search/QuerySettings.js +2 -1
  490. package/components/routes/hits/search/QuerySettings.test.js +19 -17
  491. package/components/routes/hits/search/{HitBrowser.js → RecordBrowser.js} +13 -12
  492. package/components/routes/hits/search/{HitQuery.d.ts → RecordQuery.d.ts} +2 -2
  493. package/components/routes/hits/search/{HitQuery.js → RecordQuery.js} +6 -6
  494. package/components/routes/hits/search/SearchPane.js +28 -50
  495. package/components/routes/hits/search/ViewLink.js +7 -6
  496. package/components/routes/hits/search/ViewLink.test.js +8 -9
  497. package/components/routes/hits/search/grid/RecordGrid.d.ts +3 -0
  498. package/components/routes/hits/search/grid/RecordGrid.js +64 -0
  499. package/components/routes/hits/search/shared/CustomSort.js +1 -1
  500. package/components/routes/hits/search/shared/CustomSpan.test.js +3 -4
  501. package/components/routes/hits/search/shared/HitFilter.d.ts +1 -1
  502. package/components/routes/hits/search/shared/HitSort.d.ts +1 -1
  503. package/components/routes/hits/search/shared/HitSort.js +2 -1
  504. package/components/routes/hits/search/shared/IndexPicker.d.ts +8 -0
  505. package/components/routes/hits/search/shared/IndexPicker.js +21 -0
  506. package/components/routes/hits/search/shared/LayoutSettings.js +25 -0
  507. package/components/routes/hits/search/shared/SearchActionMenu.d.ts +4 -0
  508. package/components/routes/hits/search/shared/SearchActionMenu.js +11 -0
  509. package/components/routes/hits/search/shared/SearchSpan.d.ts +1 -1
  510. package/components/routes/hits/search/shared/SearchSpan.js +1 -1
  511. package/components/routes/hits/view/HitViewer.js +16 -17
  512. package/components/routes/home/AddNewCard.js +2 -2
  513. package/components/routes/home/AddNewCard.test.js +20 -2
  514. package/components/routes/home/AnalyticCard.js +1 -1
  515. package/components/routes/home/EntryWrapper.js +1 -1
  516. package/components/routes/home/HomeSettings.js +1 -1
  517. package/components/routes/home/HomeSettings.test.d.ts +1 -0
  518. package/components/routes/home/HomeSettings.test.js +44 -0
  519. package/components/routes/home/ViewCard.js +52 -46
  520. package/components/routes/home/ViewRefresh.test.js +1 -1
  521. package/components/routes/home/index.js +2 -2
  522. package/components/routes/overviews/OverviewCard.js +1 -1
  523. package/components/routes/overviews/OverviewViewer.js +13 -10
  524. package/components/routes/overviews/Overviews.js +16 -14
  525. package/components/routes/overviews/markdownExtendedTokenProvider.js +15 -15
  526. package/components/routes/overviews/markdownExtendedTokenProvider.test.d.ts +1 -0
  527. package/components/routes/overviews/markdownExtendedTokenProvider.test.js +50 -0
  528. package/components/routes/settings/ProfileSection.js +2 -2
  529. package/components/routes/templates/TemplateEditor.d.ts +3 -2
  530. package/components/routes/templates/TemplateEditor.js +1 -1
  531. package/components/routes/templates/TemplateViewer.js +10 -5
  532. package/components/routes/templates/Templates.js +19 -14
  533. package/components/routes/views/ViewComposer.js +78 -26
  534. package/components/routes/views/Views.js +17 -14
  535. package/i18n.js +1 -1
  536. package/index.css +4 -0
  537. package/index.d.ts +1 -1
  538. package/index.js +1 -1
  539. package/locales/en/translation.json +188 -34
  540. package/locales/fr/translation.json +186 -32
  541. package/models/WithMetadata.d.ts +2 -1
  542. package/models/entities/generated/Analytic.d.ts +0 -3
  543. package/models/entities/generated/ApiType.d.ts +3 -1
  544. package/models/entities/generated/AttachmentsFile.d.ts +12 -0
  545. package/models/entities/generated/Case.d.ts +29 -0
  546. package/models/entities/generated/Column.d.ts +7 -0
  547. package/models/entities/generated/DestinationOriginal.d.ts +19 -0
  548. package/models/entities/generated/ECSEvent.d.ts +31 -0
  549. package/models/entities/generated/EmailAttachment.d.ts +8 -0
  550. package/models/entities/generated/EmailParent.d.ts +19 -0
  551. package/models/entities/generated/Enrichments.d.ts +7 -0
  552. package/models/entities/generated/EnrichmentsIndicator.d.ts +21 -0
  553. package/models/entities/generated/Event.d.ts +80 -26
  554. package/models/entities/generated/EventCloud.d.ts +20 -0
  555. package/models/entities/generated/EventDestination.d.ts +23 -0
  556. package/models/entities/generated/EventEmail.d.ts +30 -0
  557. package/models/entities/generated/EventFile.d.ts +36 -0
  558. package/models/entities/generated/EventHowler.d.ts +42 -0
  559. package/models/entities/generated/EventHttp.d.ts +11 -0
  560. package/models/entities/generated/EventObserver.d.ts +21 -0
  561. package/models/entities/generated/EventOrganization.d.ts +7 -0
  562. package/models/entities/generated/EventProcess.d.ts +34 -0
  563. package/models/entities/generated/EventSource.d.ts +23 -0
  564. package/models/entities/generated/EventThreat.d.ts +21 -0
  565. package/models/entities/generated/EventTls.d.ts +12 -0
  566. package/models/entities/generated/Hit.d.ts +3 -2
  567. package/models/entities/generated/Host.d.ts +1 -0
  568. package/models/entities/generated/Howler.d.ts +1 -6
  569. package/models/entities/generated/HttpResponse.d.ts +11 -0
  570. package/models/entities/generated/Item.d.ts +12 -0
  571. package/models/entities/generated/ObserverIngress.d.ts +9 -0
  572. package/models/entities/generated/Rule.d.ts +8 -9
  573. package/models/entities/generated/Settings.d.ts +4 -0
  574. package/models/entities/generated/Task.d.ts +10 -0
  575. package/models/entities/generated/Threat.d.ts +2 -2
  576. package/models/entities/generated/{Enrichment.d.ts → ThreatEnrichment.d.ts} +1 -1
  577. package/models/entities/generated/View.d.ts +1 -0
  578. package/models/socket/CaseUpdate.d.ts +5 -0
  579. package/models/socket/ViewersUpdate.d.ts +4 -0
  580. package/package.json +156 -137
  581. package/plugins/clue/components/ClueLeadForm.js +1 -1
  582. package/plugins/clue/components/CluePivotForm.js +2 -2
  583. package/plugins/clue/components/ClueTypography.js +2 -2
  584. package/plugins/clue/helpers.js +4 -4
  585. package/plugins/clue/index.d.ts +3 -2
  586. package/plugins/clue/index.js +0 -1
  587. package/plugins/clue/utils.d.ts +2 -1
  588. package/rest/AxiosClient.test.d.ts +1 -0
  589. package/rest/AxiosClient.test.js +185 -0
  590. package/tests/mocks.d.ts +11 -1
  591. package/tests/mocks.js +12 -7
  592. package/tests/server-handlers.js +11 -1
  593. package/tests/utils.d.ts +4 -0
  594. package/tests/utils.js +21 -0
  595. package/utils/Throttler.test.js +2 -2
  596. package/utils/actionUtils.d.ts +3 -3
  597. package/utils/classificationParser.d.ts +195 -0
  598. package/utils/classificationParser.js +680 -0
  599. package/utils/constants.d.ts +4 -3
  600. package/utils/constants.js +6 -0
  601. package/utils/localStorage.js +1 -1
  602. package/utils/menuUtils.js +0 -4
  603. package/utils/recordFunctions.d.ts +3 -0
  604. package/utils/recordFunctions.js +8 -0
  605. package/utils/recordFunctions.test.d.ts +1 -0
  606. package/utils/{hitFunctions.test.js → recordFunctions.test.js} +1 -1
  607. package/utils/socketUtils.d.ts +14 -0
  608. package/utils/socketUtils.js +17 -1
  609. package/utils/socketUtils.test.js +49 -16
  610. package/utils/stringUtils.d.ts +1 -0
  611. package/utils/stringUtils.js +7 -0
  612. package/utils/stringUtils.test.js +22 -2
  613. package/utils/typeUtils.d.ts +7 -0
  614. package/utils/typeUtils.js +27 -0
  615. package/utils/utils.d.ts +1 -1
  616. package/utils/utils.js +2 -2
  617. package/utils/utils.test.js +119 -2
  618. package/utils/viewUtils.js +3 -0
  619. package/utils/xsrf.js +1 -1
  620. package/api/analytic/rules.d.ts +0 -3
  621. package/api/analytic/rules.js +0 -8
  622. package/components/app/providers/HitProvider.d.ts +0 -22
  623. package/components/elements/display/icons/BundleButton.d.ts +0 -6
  624. package/components/elements/display/icons/BundleButton.js +0 -32
  625. package/components/elements/hit/HitRelated.d.ts +0 -6
  626. package/components/elements/hit/HitRelated.js +0 -7
  627. package/components/elements/hit/elements/HitUsers.js +0 -33
  628. package/components/routes/advanced/RuleModal.d.ts +0 -7
  629. package/components/routes/advanced/RuleModal.js +0 -83
  630. package/components/routes/analytics/RuleView.d.ts +0 -8
  631. package/components/routes/analytics/RuleView.js +0 -48
  632. package/components/routes/help/BundleDocumentation.d.ts +0 -3
  633. package/components/routes/help/BundleDocumentation.js +0 -12
  634. package/components/routes/help/markdown/en/bundles.md.js +0 -1
  635. package/components/routes/help/markdown/fr/bundles.md.js +0 -1
  636. package/components/routes/hits/search/BundleParentMenu.d.ts +0 -6
  637. package/components/routes/hits/search/BundleParentMenu.js +0 -32
  638. package/components/routes/hits/search/BundleScroller.d.ts +0 -2
  639. package/components/routes/hits/search/BundleScroller.js +0 -6
  640. package/components/routes/hits/search/HitContextMenu.js +0 -239
  641. package/components/routes/hits/search/LayoutSettings.js +0 -24
  642. package/components/routes/hits/search/grid/HitGrid.d.ts +0 -3
  643. package/components/routes/hits/search/grid/HitGrid.js +0 -132
  644. package/utils/hitFunctions.d.ts +0 -2
  645. package/utils/hitFunctions.js +0 -8
  646. /package/{components/app/providers/HitSearchProvider.test.d.ts → api/socket/viewers.test.d.ts} +0 -0
  647. /package/components/{routes/hits/search/HitContextMenu.test.d.ts → app/providers/GridColumnsProvider.test.d.ts} +0 -0
  648. /package/{utils/hitFunctions.test.d.ts → components/app/providers/RecordSearchProvider.test.d.ts} +0 -0
  649. /package/components/{routes/overviews/OverviewEditor.d.ts → elements/MarkdownEditor.d.ts} +0 -0
  650. /package/components/{routes/hits/search → elements/hit}/grid/AddColumnModal.d.ts +0 -0
  651. /package/components/elements/hit/{HitDetails.d.ts → related/RelatedRecords.d.ts} +0 -0
  652. /package/components/routes/hits/search/{HitBrowser.d.ts → RecordBrowser.d.ts} +0 -0
  653. /package/components/routes/hits/search/{LayoutSettings.d.ts → shared/LayoutSettings.d.ts} +0 -0
@@ -1,23 +1,18 @@
1
1
  import { jsx as _jsx } from "react/jsx-runtime";
2
2
  import { act, renderHook, waitFor } from '@testing-library/react';
3
+ import { setupReactRouterMock } from '@cccsaurora/howler-ui/tests/mocks';
3
4
  import { useContextSelector } from 'use-context-selector';
4
5
  import { DEFAULT_QUERY } from '@cccsaurora/howler-ui/utils/constants';
5
6
  import ParameterProvider, { ParameterContext } from './ParameterProvider';
6
7
  // Mock dependencies
7
- const mockSetParams = vi.fn();
8
- const mockLocation = { pathname: '/hits', search: '' };
9
- const mockParams = { id: undefined };
10
- let mockSearchParams = new URLSearchParams();
11
- vi.mock('react-router-dom', () => ({
12
- useLocation: vi.fn(() => mockLocation),
13
- useParams: vi.fn(() => mockParams),
14
- useSearchParams: vi.fn(() => [mockSearchParams, mockSetParams])
15
- }));
8
+ const { mockParams, mockLocation, mockSetParams, mockSearchParams } = setupReactRouterMock();
16
9
  const Wrapper = ({ children }) => {
17
10
  return _jsx(ParameterProvider, { children: children });
18
11
  };
19
12
  beforeEach(() => {
20
- mockSearchParams = new URLSearchParams();
13
+ for (const key of [...mockSearchParams.keys()]) {
14
+ mockSearchParams.delete(key);
15
+ }
21
16
  mockSetParams.mockClear();
22
17
  mockLocation.pathname = '/hits';
23
18
  mockLocation.search = '';
@@ -39,15 +34,13 @@ describe('ParameterContext', () => {
39
34
  expect(hook.result.current.trackTotalHits).toBe(false);
40
35
  });
41
36
  it('should initialize with values from URL params', async () => {
42
- mockSearchParams = new URLSearchParams({
43
- query: 'test query',
44
- sort: 'test.field asc',
45
- span: 'date.range.1.week',
46
- offset: '25',
47
- selected: 'test_id',
48
- filter: 'status:open',
49
- track_total_hits: 'true'
50
- });
37
+ mockSearchParams.set('query', 'test query');
38
+ mockSearchParams.set('sort', 'test.field asc');
39
+ mockSearchParams.set('span', 'date.range.1.week');
40
+ mockSearchParams.set('offset', '25');
41
+ mockSearchParams.set('selected', 'test_id');
42
+ mockSearchParams.set('filter', 'status:open');
43
+ mockSearchParams.set('track_total_hits', 'true');
51
44
  const hook = renderHook(() => useContextSelector(ParameterContext, ctx => ({
52
45
  query: ctx.query,
53
46
  sort: ctx.sort,
@@ -66,11 +59,9 @@ describe('ParameterContext', () => {
66
59
  expect(hook.result.current.trackTotalHits).toBe(true);
67
60
  });
68
61
  it('should handle custom date span with start and end dates', async () => {
69
- mockSearchParams = new URLSearchParams({
70
- span: 'date.range.custom',
71
- start_date: '2025-01-01',
72
- end_date: '2025-12-31'
73
- });
62
+ mockSearchParams.set('span', 'date.range.custom');
63
+ mockSearchParams.set('start_date', '2025-01-01');
64
+ mockSearchParams.set('end_date', '2025-12-31');
74
65
  const hook = renderHook(() => useContextSelector(ParameterContext, ctx => ({
75
66
  span: ctx.span,
76
67
  startDate: ctx.startDate,
@@ -94,7 +85,7 @@ describe('ParameterContext', () => {
94
85
  });
95
86
  });
96
87
  it('should not update if the value is the same', async () => {
97
- mockSearchParams = new URLSearchParams({ query: 'existing query' });
88
+ mockSearchParams.set('query', 'existing query');
98
89
  const hook = renderHook(() => useContextSelector(ParameterContext, ctx => ({
99
90
  query: ctx.query,
100
91
  setQuery: ctx.setQuery
@@ -134,11 +125,9 @@ describe('ParameterContext', () => {
134
125
  });
135
126
  });
136
127
  it('should clear startDate and endDate when span does not end with custom', async () => {
137
- mockSearchParams = new URLSearchParams({
138
- span: 'date.range.custom',
139
- start_date: '2025-01-01',
140
- end_date: '2025-12-31'
141
- });
128
+ mockSearchParams.set('span', 'date.range.custom');
129
+ mockSearchParams.set('start_date', '2025-01-01');
130
+ mockSearchParams.set('end_date', '2025-12-31');
142
131
  const hook = renderHook(() => useContextSelector(ParameterContext, ctx => ({
143
132
  span: ctx.span,
144
133
  startDate: ctx.startDate,
@@ -161,19 +150,17 @@ describe('ParameterContext', () => {
161
150
  expect(hook.result.current).toEqual([]);
162
151
  });
163
152
  it('should initialize with single filter from URL', async () => {
164
- mockSearchParams = new URLSearchParams({ filter: 'status:open' });
153
+ mockSearchParams.set('filter', 'status:open');
165
154
  const hook = renderHook(() => useContextSelector(ParameterContext, ctx => ctx.filters), { wrapper: Wrapper });
166
155
  expect(hook.result.current).toEqual(['status:open']);
167
156
  });
168
157
  it('should initialize with multiple filters from URL', async () => {
169
- mockSearchParams = new URLSearchParams();
170
158
  mockSearchParams.append('filter', 'howler.escalation:hit');
171
159
  mockSearchParams.append('filter', 'howler.assignment:someuser');
172
160
  const hook = renderHook(() => useContextSelector(ParameterContext, ctx => ctx.filters), { wrapper: Wrapper });
173
161
  expect(hook.result.current).toEqual(['howler.escalation:hit', 'howler.assignment:someuser']);
174
162
  });
175
163
  it('should preserve filter order from URL', async () => {
176
- mockSearchParams = new URLSearchParams();
177
164
  mockSearchParams.append('filter', 'c');
178
165
  mockSearchParams.append('filter', 'a');
179
166
  mockSearchParams.append('filter', 'b');
@@ -181,7 +168,6 @@ describe('ParameterContext', () => {
181
168
  expect(hook.result.current).toEqual(['c', 'a', 'b']);
182
169
  });
183
170
  it('should deduplicate multiple empty filter params to single empty string', async () => {
184
- mockSearchParams = new URLSearchParams();
185
171
  mockSearchParams.append('filter', '');
186
172
  mockSearchParams.append('filter', '');
187
173
  mockSearchParams.append('filter', '');
@@ -202,7 +188,7 @@ describe('ParameterContext', () => {
202
188
  });
203
189
  });
204
190
  it('should append filter to existing filters', async () => {
205
- mockSearchParams = new URLSearchParams({ filter: 'existing:filter' });
191
+ mockSearchParams.set('filter', 'existing:filter');
206
192
  const hook = renderHook(() => useContextSelector(ParameterContext, ctx => ({
207
193
  filters: ctx.filters,
208
194
  addFilter: ctx.addFilter
@@ -215,7 +201,7 @@ describe('ParameterContext', () => {
215
201
  });
216
202
  });
217
203
  it('should not add duplicate filters', async () => {
218
- mockSearchParams = new URLSearchParams({ filter: 'status:open' });
204
+ mockSearchParams.set('filter', 'status:open');
219
205
  const hook = renderHook(() => useContextSelector(ParameterContext, ctx => ({
220
206
  filters: ctx.filters,
221
207
  addFilter: ctx.addFilter
@@ -231,7 +217,6 @@ describe('ParameterContext', () => {
231
217
  });
232
218
  describe('removeFilter', () => {
233
219
  it('should remove first matching filter', async () => {
234
- mockSearchParams = new URLSearchParams();
235
220
  mockSearchParams.append('filter', 'filter1');
236
221
  mockSearchParams.append('filter', 'filter2');
237
222
  mockSearchParams.append('filter', 'filter3');
@@ -247,7 +232,7 @@ describe('ParameterContext', () => {
247
232
  });
248
233
  });
249
234
  it('should do nothing when removing nonexistent filter', async () => {
250
- mockSearchParams = new URLSearchParams({ filter: 'existing' });
235
+ mockSearchParams.set('filter', 'existing');
251
236
  const hook = renderHook(() => useContextSelector(ParameterContext, ctx => ({
252
237
  filters: ctx.filters,
253
238
  removeFilter: ctx.removeFilter
@@ -272,17 +257,16 @@ describe('ParameterContext', () => {
272
257
  });
273
258
  });
274
259
  });
275
- describe('clearFilters', () => {
260
+ describe('resetFilters', () => {
276
261
  it('should clear all filters', async () => {
277
- mockSearchParams = new URLSearchParams();
278
262
  mockSearchParams.append('filter', 'filter1');
279
263
  mockSearchParams.append('filter', 'filter2');
280
264
  const hook = renderHook(() => useContextSelector(ParameterContext, ctx => ({
281
265
  filters: ctx.filters,
282
- clearFilters: ctx.clearFilters
266
+ resetFilters: ctx.resetFilters
283
267
  })), { wrapper: Wrapper });
284
268
  await act(async () => {
285
- hook.result.current.clearFilters();
269
+ hook.result.current.resetFilters();
286
270
  });
287
271
  await waitFor(() => {
288
272
  expect(hook.result.current.filters).toEqual([]);
@@ -291,10 +275,10 @@ describe('ParameterContext', () => {
291
275
  it('should be no-op when already empty', async () => {
292
276
  const hook = renderHook(() => useContextSelector(ParameterContext, ctx => ({
293
277
  filters: ctx.filters,
294
- clearFilters: ctx.clearFilters
278
+ resetFilters: ctx.resetFilters
295
279
  })), { wrapper: Wrapper });
296
280
  await act(async () => {
297
- hook.result.current.clearFilters();
281
+ hook.result.current.resetFilters();
298
282
  });
299
283
  await waitFor(() => {
300
284
  expect(hook.result.current.filters).toEqual([]);
@@ -303,7 +287,6 @@ describe('ParameterContext', () => {
303
287
  });
304
288
  describe('setFilter', () => {
305
289
  it('should update filter at specified index', async () => {
306
- mockSearchParams = new URLSearchParams();
307
290
  mockSearchParams.append('filter', 'filter1');
308
291
  mockSearchParams.append('filter', 'filter2');
309
292
  mockSearchParams.append('filter', 'filter3');
@@ -319,7 +302,6 @@ describe('ParameterContext', () => {
319
302
  });
320
303
  });
321
304
  it('should update filter at index 0', async () => {
322
- mockSearchParams = new URLSearchParams();
323
305
  mockSearchParams.append('filter', 'old:filter');
324
306
  mockSearchParams.append('filter', 'filter2');
325
307
  const hook = renderHook(() => useContextSelector(ParameterContext, ctx => ({
@@ -334,7 +316,6 @@ describe('ParameterContext', () => {
334
316
  });
335
317
  });
336
318
  it('should update filter at last index', async () => {
337
- mockSearchParams = new URLSearchParams();
338
319
  mockSearchParams.append('filter', 'filter1');
339
320
  mockSearchParams.append('filter', 'old:last');
340
321
  const hook = renderHook(() => useContextSelector(ParameterContext, ctx => ({
@@ -349,7 +330,7 @@ describe('ParameterContext', () => {
349
330
  });
350
331
  });
351
332
  it('should do nothing when index is out of bounds', async () => {
352
- mockSearchParams = new URLSearchParams({ filter: 'existing' });
333
+ mockSearchParams.set('filter', 'existing');
353
334
  const hook = renderHook(() => useContextSelector(ParameterContext, ctx => ({
354
335
  filters: ctx.filters,
355
336
  setFilter: ctx.setFilter
@@ -362,7 +343,7 @@ describe('ParameterContext', () => {
362
343
  });
363
344
  });
364
345
  it('should do nothing when index is negative', async () => {
365
- mockSearchParams = new URLSearchParams({ filter: 'existing' });
346
+ mockSearchParams.set('filter', 'existing');
366
347
  const hook = renderHook(() => useContextSelector(ParameterContext, ctx => ({
367
348
  filters: ctx.filters,
368
349
  setFilter: ctx.setFilter
@@ -387,7 +368,6 @@ describe('ParameterContext', () => {
387
368
  });
388
369
  });
389
370
  it('should sync updated filter to URL', async () => {
390
- mockSearchParams = new URLSearchParams();
391
371
  mockSearchParams.append('filter', 'filter1');
392
372
  mockSearchParams.append('filter', 'filter2');
393
373
  const hook = renderHook(() => useContextSelector(ParameterContext, ctx => ({
@@ -437,14 +417,13 @@ describe('ParameterContext', () => {
437
417
  });
438
418
  });
439
419
  it('should remove all filter params when filters is empty', async () => {
440
- mockSearchParams = new URLSearchParams();
441
420
  mockSearchParams.append('filter', 'filter1');
442
421
  mockSearchParams.append('filter', 'filter2');
443
422
  const hook = renderHook(() => useContextSelector(ParameterContext, ctx => ({
444
- clearFilters: ctx.clearFilters
423
+ resetFilters: ctx.resetFilters
445
424
  })), { wrapper: Wrapper });
446
425
  await act(async () => {
447
- hook.result.current.clearFilters();
426
+ hook.result.current.resetFilters();
448
427
  });
449
428
  await waitFor(() => {
450
429
  expect(mockSetParams).toHaveBeenCalled();
@@ -567,11 +546,11 @@ describe('ParameterContext', () => {
567
546
  });
568
547
  });
569
548
  it('should read changes from URL params', async () => {
570
- mockSearchParams = new URLSearchParams({ query: 'initial query' });
549
+ mockSearchParams.set('query', 'initial query');
571
550
  const hook = renderHook(() => useContextSelector(ParameterContext, ctx => ctx.query), { wrapper: Wrapper });
572
551
  expect(hook.result.current).toBe('initial query');
573
552
  // Simulate URL change
574
- mockSearchParams = new URLSearchParams({ query: 'updated query' });
553
+ mockSearchParams.set('query', 'updated query');
575
554
  mockLocation.search = '?query=updated%20query';
576
555
  hook.rerender();
577
556
  await waitFor(() => {
@@ -589,24 +568,34 @@ describe('ParameterContext', () => {
589
568
  it('should handle selected parameter in bundle when it matches bundle id', async () => {
590
569
  mockLocation.pathname = '/bundles/bundle_123';
591
570
  mockParams.id = 'bundle_123';
592
- mockSearchParams = new URLSearchParams({ selected: 'bundle_123' });
571
+ mockSearchParams.set('selected', 'bundle_123');
593
572
  const hook = renderHook(() => useContextSelector(ParameterContext, ctx => ctx.selected), { wrapper: Wrapper });
594
573
  expect(hook.result.current).toBe('bundle_123');
595
574
  });
596
575
  it('should handle selected parameter in bundle when it differs from bundle id', async () => {
597
576
  mockLocation.pathname = '/bundles/bundle_123';
598
577
  mockParams.id = 'bundle_123';
599
- mockSearchParams = new URLSearchParams({ selected: 'different_hit_id' });
578
+ mockSearchParams.set('selected', 'different_hit_id');
600
579
  const hook = renderHook(() => useContextSelector(ParameterContext, ctx => ctx.selected), { wrapper: Wrapper });
601
580
  expect(hook.result.current).toBe('different_hit_id');
602
581
  });
582
+ it('should not sync query when default query differs from global default', async () => {
583
+ const CustomDefaultWrapper = ({ children }) => {
584
+ return _jsx(ParameterProvider, { defaults: { query: '' }, children: children });
585
+ };
586
+ const hook = renderHook(() => useContextSelector(ParameterContext, ctx => ctx.query), {
587
+ wrapper: CustomDefaultWrapper
588
+ });
589
+ expect(hook.result.current).toBe('');
590
+ await waitFor(() => {
591
+ expect(mockSetParams).not.toHaveBeenCalled();
592
+ });
593
+ });
603
594
  });
604
595
  describe('useParameterContextSelector', () => {
605
596
  it('should allow selecting specific values from context', async () => {
606
- mockSearchParams = new URLSearchParams({
607
- query: 'test query',
608
- sort: 'test.field asc'
609
- });
597
+ mockSearchParams.set('query', 'test query');
598
+ mockSearchParams.set('sort', 'test.field asc');
610
599
  const hook = renderHook(() => useContextSelector(ParameterContext, ctx => ({
611
600
  query: ctx.query,
612
601
  sort: ctx.sort
@@ -617,17 +606,17 @@ describe('ParameterContext', () => {
617
606
  });
618
607
  describe('edge cases', () => {
619
608
  it('should handle offset of 0 in URL params', async () => {
620
- mockSearchParams = new URLSearchParams({ offset: '0' });
609
+ mockSearchParams.set('offset', '0');
621
610
  const hook = renderHook(() => useContextSelector(ParameterContext, ctx => ctx.offset), { wrapper: Wrapper });
622
611
  expect(hook.result.current).toBe(0);
623
612
  });
624
613
  it('should handle trackTotalHits with various values', async () => {
625
- mockSearchParams = new URLSearchParams({ track_total_hits: 'false' });
614
+ mockSearchParams.set('track_total_hits', 'false');
626
615
  let hook = renderHook(() => useContextSelector(ParameterContext, ctx => ctx.trackTotalHits), {
627
616
  wrapper: Wrapper
628
617
  });
629
618
  expect(hook.result.current).toBe(false);
630
- mockSearchParams = new URLSearchParams({ track_total_hits: 'true' });
619
+ mockSearchParams.set('track_total_hits', 'true');
631
620
  hook = renderHook(() => useContextSelector(ParameterContext, ctx => ctx.trackTotalHits), { wrapper: Wrapper });
632
621
  expect(hook.result.current).toBe(true);
633
622
  });
@@ -645,11 +634,9 @@ describe('ParameterContext', () => {
645
634
  expect(hook.result.current.endDate).toBeNull();
646
635
  });
647
636
  it('should fallback to default values when URL params are cleared', async () => {
648
- mockSearchParams = new URLSearchParams({
649
- query: 'custom query',
650
- sort: 'custom.sort asc',
651
- span: 'date.range.1.week'
652
- });
637
+ mockSearchParams.set('query', 'custom query');
638
+ mockSearchParams.set('sort', 'custom.sort asc');
639
+ mockSearchParams.set('span', 'date.range.1.week');
653
640
  mockLocation.search = mockSearchParams.toString();
654
641
  const hook = renderHook(() => useContextSelector(ParameterContext, ctx => ({
655
642
  query: ctx.query,
@@ -658,7 +645,9 @@ describe('ParameterContext', () => {
658
645
  })), { wrapper: Wrapper });
659
646
  expect(hook.result.current.query).toBe('custom query');
660
647
  // Simulate clearing URL params
661
- mockSearchParams = new URLSearchParams();
648
+ for (const key of [...mockSearchParams.keys()]) {
649
+ mockSearchParams.delete(key);
650
+ }
662
651
  mockLocation.search = '';
663
652
  hook.rerender();
664
653
  await waitFor(() => {
@@ -686,6 +675,7 @@ describe('ParameterContext', () => {
686
675
  hook.result.current.setSpan('date.range.1.week');
687
676
  hook.result.current.addFilter('status:resolved');
688
677
  });
678
+ hook.rerender();
689
679
  await waitFor(() => {
690
680
  expect(hook.result.current.query).toBe('multi query');
691
681
  expect(hook.result.current.sort).toBe('multi.sort desc');
@@ -706,25 +696,308 @@ describe('ParameterContext', () => {
706
696
  });
707
697
  });
708
698
  });
699
+ describe('indexes (multi-index support)', () => {
700
+ it('should initialize with default ["hit"] when no index params are present', async () => {
701
+ const hook = renderHook(() => useContextSelector(ParameterContext, ctx => ctx.indexes), { wrapper: Wrapper });
702
+ expect(hook.result.current).toEqual(['hit']);
703
+ });
704
+ it('should initialize with single index from URL', async () => {
705
+ mockSearchParams.set('index', 'event');
706
+ const hook = renderHook(() => useContextSelector(ParameterContext, ctx => ctx.indexes), { wrapper: Wrapper });
707
+ expect(hook.result.current).toEqual(['event']);
708
+ });
709
+ it('should initialize with multiple indexes from URL', async () => {
710
+ mockSearchParams.append('index', 'hit');
711
+ mockSearchParams.append('index', 'event');
712
+ const hook = renderHook(() => useContextSelector(ParameterContext, ctx => ctx.indexes), { wrapper: Wrapper });
713
+ expect(hook.result.current).toEqual(['hit', 'event']);
714
+ });
715
+ it('should deduplicate repeated index values from URL', async () => {
716
+ mockSearchParams.append('index', 'hit');
717
+ mockSearchParams.append('index', 'hit');
718
+ const hook = renderHook(() => useContextSelector(ParameterContext, ctx => ctx.indexes), { wrapper: Wrapper });
719
+ expect(hook.result.current).toEqual(['hit']);
720
+ });
721
+ describe('addIndex', () => {
722
+ it('should add an index to the default array', async () => {
723
+ const hook = renderHook(() => useContextSelector(ParameterContext, ctx => ({
724
+ indexes: ctx.indexes,
725
+ addIndex: ctx.addIndex
726
+ })), { wrapper: Wrapper });
727
+ await act(async () => {
728
+ hook.result.current.addIndex('event');
729
+ });
730
+ await waitFor(() => {
731
+ expect(hook.result.current.indexes).toEqual(['hit', 'event']);
732
+ });
733
+ });
734
+ it('should not add a duplicate index', async () => {
735
+ const hook = renderHook(() => useContextSelector(ParameterContext, ctx => ({
736
+ indexes: ctx.indexes,
737
+ addIndex: ctx.addIndex
738
+ })), { wrapper: Wrapper });
739
+ await act(async () => {
740
+ hook.result.current.addIndex('hit');
741
+ });
742
+ await waitFor(() => {
743
+ expect(hook.result.current.indexes).toEqual(['hit']);
744
+ });
745
+ });
746
+ });
747
+ describe('removeIndex', () => {
748
+ it('should remove an index from the list', async () => {
749
+ mockSearchParams.append('index', 'hit');
750
+ mockSearchParams.append('index', 'event');
751
+ const hook = renderHook(() => useContextSelector(ParameterContext, ctx => ({
752
+ indexes: ctx.indexes,
753
+ removeIndex: ctx.removeIndex
754
+ })), { wrapper: Wrapper });
755
+ await act(async () => {
756
+ hook.result.current.removeIndex('hit');
757
+ });
758
+ await waitFor(() => {
759
+ expect(hook.result.current.indexes).toEqual(['event']);
760
+ });
761
+ });
762
+ it('should do nothing when removing a nonexistent index', async () => {
763
+ const hook = renderHook(() => useContextSelector(ParameterContext, ctx => ({
764
+ indexes: ctx.indexes,
765
+ removeIndex: ctx.removeIndex
766
+ })), { wrapper: Wrapper });
767
+ await act(async () => {
768
+ hook.result.current.removeIndex('event');
769
+ });
770
+ await waitFor(() => {
771
+ expect(hook.result.current.indexes).toEqual(['hit']);
772
+ });
773
+ });
774
+ it('should handle removing from empty array', async () => {
775
+ mockSearchParams.append('index', 'hit');
776
+ const hook = renderHook(() => useContextSelector(ParameterContext, ctx => ({
777
+ indexes: ctx.indexes,
778
+ removeIndex: ctx.removeIndex
779
+ })), { wrapper: Wrapper });
780
+ await act(async () => {
781
+ hook.result.current.removeIndex('hit');
782
+ });
783
+ await waitFor(() => {
784
+ expect(hook.result.current.indexes).toEqual([]);
785
+ });
786
+ });
787
+ });
788
+ describe('setIndex', () => {
789
+ it('should update the index at the specified position', async () => {
790
+ mockSearchParams.append('index', 'hit');
791
+ mockSearchParams.append('index', 'event');
792
+ const hook = renderHook(() => useContextSelector(ParameterContext, ctx => ({
793
+ indexes: ctx.indexes,
794
+ setIndex: ctx.setIndex
795
+ })), { wrapper: Wrapper });
796
+ await act(async () => {
797
+ hook.result.current.setIndex(0, 'event');
798
+ });
799
+ await waitFor(() => {
800
+ expect(hook.result.current.indexes).toEqual(['event', 'event']);
801
+ });
802
+ });
803
+ it('should do nothing when index is out of bounds', async () => {
804
+ const hook = renderHook(() => useContextSelector(ParameterContext, ctx => ({
805
+ indexes: ctx.indexes,
806
+ setIndex: ctx.setIndex
807
+ })), { wrapper: Wrapper });
808
+ await act(async () => {
809
+ hook.result.current.setIndex(5, 'event');
810
+ });
811
+ await waitFor(() => {
812
+ expect(hook.result.current.indexes).toEqual(['hit']);
813
+ });
814
+ });
815
+ it('should do nothing when position is negative', async () => {
816
+ const hook = renderHook(() => useContextSelector(ParameterContext, ctx => ({
817
+ indexes: ctx.indexes,
818
+ setIndex: ctx.setIndex
819
+ })), { wrapper: Wrapper });
820
+ await act(async () => {
821
+ hook.result.current.setIndex(-1, 'event');
822
+ });
823
+ await waitFor(() => {
824
+ expect(hook.result.current.indexes).toEqual(['hit']);
825
+ });
826
+ });
827
+ });
828
+ describe('setIndexes', () => {
829
+ it('should replace all indexes with the provided list', async () => {
830
+ const hook = renderHook(() => useContextSelector(ParameterContext, ctx => ({
831
+ indexes: ctx.indexes,
832
+ setIndexes: ctx.setIndexes
833
+ })), { wrapper: Wrapper });
834
+ await act(async () => {
835
+ hook.result.current.setIndexes(['event']);
836
+ });
837
+ await waitFor(() => {
838
+ expect(hook.result.current.indexes).toEqual(['event']);
839
+ });
840
+ });
841
+ it('should deduplicate values when setting all indexes', async () => {
842
+ const hook = renderHook(() => useContextSelector(ParameterContext, ctx => ({
843
+ indexes: ctx.indexes,
844
+ setIndexes: ctx.setIndexes
845
+ })), { wrapper: Wrapper });
846
+ await act(async () => {
847
+ hook.result.current.setIndexes(['hit', 'hit', 'event']);
848
+ });
849
+ await waitFor(() => {
850
+ expect(hook.result.current.indexes).toEqual(['hit', 'event']);
851
+ });
852
+ });
853
+ it('should set to empty array', async () => {
854
+ const hook = renderHook(() => useContextSelector(ParameterContext, ctx => ({
855
+ indexes: ctx.indexes,
856
+ setIndexes: ctx.setIndexes
857
+ })), { wrapper: Wrapper });
858
+ await act(async () => {
859
+ hook.result.current.setIndexes([]);
860
+ });
861
+ await waitFor(() => {
862
+ expect(hook.result.current.indexes).toEqual([]);
863
+ });
864
+ });
865
+ });
866
+ describe('resetIndexes', () => {
867
+ it('should reset indexes to default ["hit"]', async () => {
868
+ mockSearchParams.append('index', 'hit');
869
+ mockSearchParams.append('index', 'event');
870
+ const hook = renderHook(() => useContextSelector(ParameterContext, ctx => ({
871
+ indexes: ctx.indexes,
872
+ resetIndexes: ctx.resetIndexes
873
+ })), { wrapper: Wrapper });
874
+ await act(async () => {
875
+ hook.result.current.resetIndexes();
876
+ });
877
+ await waitFor(() => {
878
+ expect(hook.result.current.indexes).toEqual(['hit']);
879
+ });
880
+ });
881
+ it('should reset to default even when called on empty array', async () => {
882
+ mockSearchParams.append('index', 'hit');
883
+ const hook = renderHook(() => useContextSelector(ParameterContext, ctx => ({
884
+ indexes: ctx.indexes,
885
+ removeIndex: ctx.removeIndex,
886
+ resetIndexes: ctx.resetIndexes
887
+ })), { wrapper: Wrapper });
888
+ // First empty it
889
+ await act(async () => {
890
+ hook.result.current.removeIndex('hit');
891
+ });
892
+ await waitFor(() => {
893
+ expect(hook.result.current.indexes).toEqual([]);
894
+ });
895
+ // Resetting always returns to default ['hit']
896
+ await act(async () => {
897
+ hook.result.current.resetIndexes();
898
+ });
899
+ await waitFor(() => {
900
+ expect(hook.result.current.indexes).toEqual(['hit']);
901
+ });
902
+ });
903
+ });
904
+ describe('URL synchronization', () => {
905
+ it('should not write the default ["hit"] index to the URL', async () => {
906
+ renderHook(() => useContextSelector(ParameterContext, ctx => ctx.indexes), { wrapper: Wrapper });
907
+ // Allow any effects to flush
908
+ await waitFor(() => {
909
+ // If setParams was called, the URL must not contain ?index=hit
910
+ if (mockSetParams.mock.calls.length > 0) {
911
+ const call = mockSetParams.mock.calls[mockSetParams.mock.calls.length - 1];
912
+ const urlParams = typeof call[0] === 'function' ? call[0](mockSearchParams) : call[0];
913
+ expect(urlParams.getAll('index')).toEqual([]);
914
+ }
915
+ else {
916
+ // setParams not called at all is also fine
917
+ expect(true).toBe(true);
918
+ }
919
+ });
920
+ });
921
+ it('should write a non-default index to the URL', async () => {
922
+ const hook = renderHook(() => useContextSelector(ParameterContext, ctx => ({
923
+ addIndex: ctx.addIndex,
924
+ resetIndexes: ctx.resetIndexes
925
+ })), { wrapper: Wrapper });
926
+ await act(async () => {
927
+ hook.result.current.resetIndexes();
928
+ hook.result.current.addIndex('event');
929
+ });
930
+ await waitFor(() => {
931
+ expect(mockSetParams).toHaveBeenCalled();
932
+ const call = mockSetParams.mock.calls[mockSetParams.mock.calls.length - 1];
933
+ const urlParams = typeof call[0] === 'function' ? call[0](mockSearchParams) : call[0];
934
+ expect(urlParams.getAll('index')).toEqual(['hit', 'event']);
935
+ });
936
+ });
937
+ it('should sync multiple indexes to URL as multiple index params', async () => {
938
+ const hook = renderHook(() => useContextSelector(ParameterContext, ctx => ({
939
+ addIndex: ctx.addIndex
940
+ })), { wrapper: Wrapper });
941
+ await act(async () => {
942
+ hook.result.current.addIndex('event');
943
+ });
944
+ await waitFor(() => {
945
+ expect(mockSetParams).toHaveBeenCalled();
946
+ const call = mockSetParams.mock.calls[mockSetParams.mock.calls.length - 1];
947
+ const urlParams = typeof call[0] === 'function' ? call[0](mockSearchParams) : call[0];
948
+ expect(urlParams.getAll('index')).toEqual(['hit', 'event']);
949
+ });
950
+ });
951
+ it('should remove all index params from URL when state resets to default', async () => {
952
+ mockSearchParams.append('index', 'hit');
953
+ mockSearchParams.append('index', 'event');
954
+ const hook = renderHook(() => useContextSelector(ParameterContext, ctx => ({
955
+ resetIndexes: ctx.resetIndexes
956
+ })), { wrapper: Wrapper });
957
+ await act(async () => {
958
+ hook.result.current.resetIndexes();
959
+ });
960
+ await waitFor(() => {
961
+ expect(mockSetParams).toHaveBeenCalled();
962
+ const call = mockSetParams.mock.calls[mockSetParams.mock.calls.length - 1];
963
+ const urlParams = typeof call[0] === 'function' ? call[0](mockSearchParams) : call[0];
964
+ expect(urlParams.getAll('index')).toEqual([]);
965
+ });
966
+ });
967
+ it('should remove index param from URL when state returns to default', async () => {
968
+ mockSearchParams.set('index', 'event');
969
+ const hook = renderHook(() => useContextSelector(ParameterContext, ctx => ({
970
+ setIndexes: ctx.setIndexes
971
+ })), { wrapper: Wrapper });
972
+ await act(async () => {
973
+ hook.result.current.setIndexes(['hit']);
974
+ });
975
+ await waitFor(() => {
976
+ expect(mockSetParams).toHaveBeenCalled();
977
+ const call = mockSetParams.mock.calls[mockSetParams.mock.calls.length - 1];
978
+ const urlParams = typeof call[0] === 'function' ? call[0](mockSearchParams) : call[0];
979
+ expect(urlParams.getAll('index')).toEqual([]);
980
+ });
981
+ });
982
+ });
983
+ });
709
984
  describe('views (multi-view support)', () => {
710
985
  it('should initialize with empty array when no view params present', async () => {
711
986
  const hook = renderHook(() => useContextSelector(ParameterContext, ctx => ctx.views), { wrapper: Wrapper });
712
987
  expect(hook.result.current).toEqual([]);
713
988
  });
714
989
  it('should initialize with single view from URL', async () => {
715
- mockSearchParams = new URLSearchParams({ view: 'view_1' });
990
+ mockSearchParams.set('view', 'view_1');
716
991
  const hook = renderHook(() => useContextSelector(ParameterContext, ctx => ctx.views), { wrapper: Wrapper });
717
992
  expect(hook.result.current).toEqual(['view_1']);
718
993
  });
719
994
  it('should initialize with multiple views from URL', async () => {
720
- mockSearchParams = new URLSearchParams();
721
995
  mockSearchParams.append('view', 'view_1');
722
996
  mockSearchParams.append('view', 'view_2');
723
997
  const hook = renderHook(() => useContextSelector(ParameterContext, ctx => ctx.views), { wrapper: Wrapper });
724
998
  expect(hook.result.current).toEqual(['view_1', 'view_2']);
725
999
  });
726
1000
  it('should preserve view order from URL', async () => {
727
- mockSearchParams = new URLSearchParams();
728
1001
  mockSearchParams.append('view', 'view_c');
729
1002
  mockSearchParams.append('view', 'view_a');
730
1003
  mockSearchParams.append('view', 'view_b');
@@ -732,7 +1005,6 @@ describe('ParameterContext', () => {
732
1005
  expect(hook.result.current).toEqual(['view_c', 'view_a', 'view_b']);
733
1006
  });
734
1007
  it('should deduplicate multiple empty view params to single empty string', async () => {
735
- mockSearchParams = new URLSearchParams();
736
1008
  mockSearchParams.append('view', '');
737
1009
  mockSearchParams.append('view', '');
738
1010
  mockSearchParams.append('view', '');
@@ -753,7 +1025,7 @@ describe('ParameterContext', () => {
753
1025
  });
754
1026
  });
755
1027
  it('should append view to existing views', async () => {
756
- mockSearchParams = new URLSearchParams({ view: 'existing_view' });
1028
+ mockSearchParams.set('view', 'existing_view');
757
1029
  const hook = renderHook(() => useContextSelector(ParameterContext, ctx => ({
758
1030
  views: ctx.views,
759
1031
  addView: ctx.addView
@@ -766,7 +1038,7 @@ describe('ParameterContext', () => {
766
1038
  });
767
1039
  });
768
1040
  it('should not add duplicate views', async () => {
769
- mockSearchParams = new URLSearchParams({ view: 'view_1' });
1041
+ mockSearchParams.set('view', 'view_1');
770
1042
  const hook = renderHook(() => useContextSelector(ParameterContext, ctx => ({
771
1043
  views: ctx.views,
772
1044
  addView: ctx.addView
@@ -782,7 +1054,6 @@ describe('ParameterContext', () => {
782
1054
  });
783
1055
  describe('removeView', () => {
784
1056
  it('should remove first matching view', async () => {
785
- mockSearchParams = new URLSearchParams();
786
1057
  mockSearchParams.append('view', 'view_1');
787
1058
  mockSearchParams.append('view', 'view_2');
788
1059
  mockSearchParams.append('view', 'view_3');
@@ -798,7 +1069,6 @@ describe('ParameterContext', () => {
798
1069
  });
799
1070
  });
800
1071
  it('should remove only first occurrence of duplicate views', async () => {
801
- mockSearchParams = new URLSearchParams();
802
1072
  mockSearchParams.append('view', 'dup');
803
1073
  mockSearchParams.append('view', 'dup');
804
1074
  mockSearchParams.append('view', 'other');
@@ -814,7 +1084,7 @@ describe('ParameterContext', () => {
814
1084
  });
815
1085
  });
816
1086
  it('should do nothing when removing nonexistent view', async () => {
817
- mockSearchParams = new URLSearchParams({ view: 'existing' });
1087
+ mockSearchParams.set('view', 'existing');
818
1088
  const hook = renderHook(() => useContextSelector(ParameterContext, ctx => ({
819
1089
  views: ctx.views,
820
1090
  removeView: ctx.removeView
@@ -839,17 +1109,16 @@ describe('ParameterContext', () => {
839
1109
  });
840
1110
  });
841
1111
  });
842
- describe('clearViews', () => {
1112
+ describe('resetViews', () => {
843
1113
  it('should clear all views', async () => {
844
- mockSearchParams = new URLSearchParams();
845
1114
  mockSearchParams.append('view', 'view_1');
846
1115
  mockSearchParams.append('view', 'view_2');
847
1116
  const hook = renderHook(() => useContextSelector(ParameterContext, ctx => ({
848
1117
  views: ctx.views,
849
- clearViews: ctx.clearViews
1118
+ resetViews: ctx.resetViews
850
1119
  })), { wrapper: Wrapper });
851
1120
  await act(async () => {
852
- hook.result.current.clearViews();
1121
+ hook.result.current.resetViews();
853
1122
  });
854
1123
  await waitFor(() => {
855
1124
  expect(hook.result.current.views).toEqual([]);
@@ -858,10 +1127,10 @@ describe('ParameterContext', () => {
858
1127
  it('should be no-op when already empty', async () => {
859
1128
  const hook = renderHook(() => useContextSelector(ParameterContext, ctx => ({
860
1129
  views: ctx.views,
861
- clearViews: ctx.clearViews
1130
+ resetViews: ctx.resetViews
862
1131
  })), { wrapper: Wrapper });
863
1132
  await act(async () => {
864
- hook.result.current.clearViews();
1133
+ hook.result.current.resetViews();
865
1134
  });
866
1135
  await waitFor(() => {
867
1136
  expect(hook.result.current.views).toEqual([]);
@@ -870,7 +1139,6 @@ describe('ParameterContext', () => {
870
1139
  });
871
1140
  describe('setView', () => {
872
1141
  it('should update view at specified index', async () => {
873
- mockSearchParams = new URLSearchParams();
874
1142
  mockSearchParams.append('view', 'view_1');
875
1143
  mockSearchParams.append('view', 'view_2');
876
1144
  mockSearchParams.append('view', 'view_3');
@@ -886,7 +1154,6 @@ describe('ParameterContext', () => {
886
1154
  });
887
1155
  });
888
1156
  it('should update view at index 0', async () => {
889
- mockSearchParams = new URLSearchParams();
890
1157
  mockSearchParams.append('view', 'old_view');
891
1158
  mockSearchParams.append('view', 'view_2');
892
1159
  const hook = renderHook(() => useContextSelector(ParameterContext, ctx => ({
@@ -901,7 +1168,6 @@ describe('ParameterContext', () => {
901
1168
  });
902
1169
  });
903
1170
  it('should update view at last index', async () => {
904
- mockSearchParams = new URLSearchParams();
905
1171
  mockSearchParams.append('view', 'view_1');
906
1172
  mockSearchParams.append('view', 'old_last');
907
1173
  const hook = renderHook(() => useContextSelector(ParameterContext, ctx => ({
@@ -916,7 +1182,7 @@ describe('ParameterContext', () => {
916
1182
  });
917
1183
  });
918
1184
  it('should do nothing when index is out of bounds', async () => {
919
- mockSearchParams = new URLSearchParams({ view: 'existing' });
1185
+ mockSearchParams.set('view', 'existing');
920
1186
  const hook = renderHook(() => useContextSelector(ParameterContext, ctx => ({
921
1187
  views: ctx.views,
922
1188
  setView: ctx.setView
@@ -929,7 +1195,7 @@ describe('ParameterContext', () => {
929
1195
  });
930
1196
  });
931
1197
  it('should do nothing when index is negative', async () => {
932
- mockSearchParams = new URLSearchParams({ view: 'existing' });
1198
+ mockSearchParams.set('view', 'existing');
933
1199
  const hook = renderHook(() => useContextSelector(ParameterContext, ctx => ({
934
1200
  views: ctx.views,
935
1201
  setView: ctx.setView
@@ -954,7 +1220,6 @@ describe('ParameterContext', () => {
954
1220
  });
955
1221
  });
956
1222
  it('should sync updated view to URL', async () => {
957
- mockSearchParams = new URLSearchParams();
958
1223
  mockSearchParams.append('view', 'view_1');
959
1224
  mockSearchParams.append('view', 'view_2');
960
1225
  const hook = renderHook(() => useContextSelector(ParameterContext, ctx => ({
@@ -1004,14 +1269,13 @@ describe('ParameterContext', () => {
1004
1269
  });
1005
1270
  });
1006
1271
  it('should remove all view params when views is empty', async () => {
1007
- mockSearchParams = new URLSearchParams();
1008
1272
  mockSearchParams.append('view', 'view_1');
1009
1273
  mockSearchParams.append('view', 'view_2');
1010
1274
  const hook = renderHook(() => useContextSelector(ParameterContext, ctx => ({
1011
- clearViews: ctx.clearViews
1275
+ resetViews: ctx.resetViews
1012
1276
  })), { wrapper: Wrapper });
1013
1277
  await act(async () => {
1014
- hook.result.current.clearViews();
1278
+ hook.result.current.resetViews();
1015
1279
  });
1016
1280
  await waitFor(() => {
1017
1281
  expect(mockSetParams).toHaveBeenCalled();