@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.
- package/api/action/index.d.ts +5 -4
- package/api/action/index.js +8 -8
- package/api/analytic/index.d.ts +5 -5
- package/api/analytic/index.js +5 -6
- package/api/analytic/owner.d.ts +2 -1
- package/api/analytic/owner.js +2 -2
- package/api/dossier/index.d.ts +4 -3
- package/api/dossier/index.js +6 -6
- package/api/hit/index.d.ts +3 -2
- package/api/hit/index.js +4 -4
- package/api/hit/labels.d.ts +3 -2
- package/api/hit/labels.js +4 -4
- package/api/hit/overwrite.d.ts +2 -1
- package/api/hit/overwrite.js +2 -2
- package/api/hit/transition.d.ts +2 -1
- package/api/hit/transition.js +2 -2
- package/api/index.d.ts +10 -5
- package/api/index.js +18 -10
- package/api/overview/index.d.ts +4 -3
- package/api/overview/index.js +6 -6
- package/api/search/action.js +1 -1
- package/api/search/analytic.js +1 -1
- package/api/search/case.d.ts +4 -0
- package/api/search/case.js +8 -0
- package/api/search/count/hit.js +1 -1
- package/api/search/dossier.js +1 -1
- package/api/search/eql/hit.js +1 -1
- package/api/search/explain/hit.js +1 -1
- package/api/search/facet/hit.d.ts +1 -3
- package/api/search/facet/hit.js +1 -1
- package/api/search/facet/index.d.ts +3 -1
- package/api/search/grouped/hit.js +1 -1
- package/api/search/grouped/user.js +1 -1
- package/api/search/histogram/hit.js +1 -1
- package/api/search/hit.js +1 -1
- package/api/search/index.d.ts +3 -1
- package/api/search/index.js +2 -1
- package/api/search/overview.d.ts +2 -2
- package/api/search/overview.js +1 -1
- package/api/search/sigma/hit.js +1 -1
- package/api/search/template.js +1 -1
- package/api/search/user.js +1 -1
- package/api/search/view.js +1 -1
- package/api/socket/index.d.ts +3 -0
- package/api/socket/index.js +6 -0
- package/api/socket/viewers.d.ts +2 -0
- package/api/socket/viewers.js +8 -0
- package/api/socket/viewers.test.js +44 -0
- package/api/template/index.d.ts +4 -3
- package/api/template/index.js +6 -6
- package/api/user/index.d.ts +2 -1
- package/api/user/index.js +2 -2
- package/api/v2/case/index.d.ts +9 -0
- package/api/v2/case/index.js +21 -0
- package/api/v2/case/items.d.ts +9 -0
- package/api/v2/case/items.js +19 -0
- package/api/v2/case/rules.d.ts +6 -0
- package/api/v2/case/rules.js +18 -0
- package/api/v2/fuzzy.d.ts +17 -0
- package/api/v2/fuzzy.js +11 -0
- package/api/v2/index.d.ts +5 -0
- package/api/v2/index.js +7 -0
- package/api/v2/search/facet.d.ts +3 -0
- package/api/v2/search/facet.js +12 -0
- package/api/v2/search/index.d.ts +6 -0
- package/api/v2/search/index.js +24 -0
- package/api/view/index.d.ts +4 -3
- package/api/view/index.js +6 -6
- package/branding/AppBrand.d.ts +2 -2
- package/commons/components/app/AppSkeleton.js +1 -1
- package/commons/components/app/hooks/useAppConfigs.d.ts +2 -2
- package/commons/components/app/hooks/useAppSitemap.d.ts +5 -2
- package/commons/components/breadcrumbs/BreadcrumbIcon.js +1 -1
- package/commons/components/breadcrumbs/Breadcrumbs.d.ts +3 -2
- package/commons/components/display/AppToc.d.ts +2 -1
- package/commons/components/display/AppToc.js +1 -1
- package/commons/components/display/hooks/useAppColor.d.ts +1 -1
- package/commons/components/leftnav/LeftNavDrawer.d.ts +2 -1
- package/commons/components/leftnav/LeftNavDrawer.js +1 -1
- package/commons/components/leftnav/LeftNavGroup.d.ts +2 -1
- package/commons/components/leftnav/LeftNavItem.d.ts +2 -1
- package/commons/components/leftnav/LeftNavItem.js +1 -1
- package/commons/components/notification/Notification.js +1 -1
- package/commons/components/notification/elements/NotificationHeader.js +1 -1
- package/commons/components/notification/elements/NotificationItems.js +1 -1
- package/commons/components/notification/elements/item/NotificationItemAuthor.js +1 -1
- package/commons/components/pages/PageCenter.d.ts +2 -1
- package/commons/components/pages/PageContent.d.ts +2 -1
- package/commons/components/pages/PageFullScreen.d.ts +2 -1
- package/commons/components/search/AppSearch.js +1 -1
- package/commons/components/search/AppSearchInput.d.ts +2 -1
- package/commons/components/search/AppSearchResult.d.ts +2 -1
- package/commons/components/topnav/AppBar.d.ts +2 -1
- package/commons/components/topnav/AppName.d.ts +3 -2
- package/commons/components/topnav/AppSwitcher.d.ts +2 -1
- package/commons/components/topnav/ThemeSelection.d.ts +2 -1
- package/commons/components/topnav/ThemeSelection.js +1 -1
- package/commons/components/topnav/UserProfile.d.ts +2 -1
- package/commons/components/topnav/UserProfile.js +1 -1
- package/commons/components/utils/hooks/useThemeBuilder.d.ts +1 -1
- package/components/app/App.js +52 -12
- package/components/app/drawers/ApiKeyDrawer.js +1 -1
- package/components/app/hooks/useMatchers.d.ts +1 -1
- package/components/app/hooks/useMatchers.js +27 -15
- package/components/app/hooks/useMatchers.test.js +22 -22
- package/components/app/hooks/useTitle.js +6 -6
- package/components/app/providers/AnalyticProvider.js +1 -1
- package/components/app/providers/AvatarProvider.js +1 -1
- package/components/app/providers/FavouritesProvider.js +3 -3
- package/components/app/providers/GridColumnsProvider.d.ts +52 -0
- package/components/app/providers/GridColumnsProvider.js +177 -0
- package/components/app/providers/GridColumnsProvider.test.js +255 -0
- package/components/app/providers/ModalProvider.d.ts +1 -0
- package/components/app/providers/OverviewProvider.js +1 -1
- package/components/app/providers/ParameterProvider.d.ts +25 -3
- package/components/app/providers/ParameterProvider.js +163 -226
- package/components/app/providers/ParameterProvider.test.js +358 -94
- package/components/app/providers/RecordProvider.d.ts +23 -0
- package/components/app/providers/{HitProvider.js → RecordProvider.js} +47 -43
- package/components/app/providers/{HitSearchProvider.d.ts → RecordSearchProvider.d.ts} +6 -6
- package/components/app/providers/{HitSearchProvider.js → RecordSearchProvider.js} +24 -37
- package/components/app/providers/{HitSearchProvider.test.js → RecordSearchProvider.test.js} +52 -71
- package/components/app/providers/SearchResponseProvider.d.ts +21 -0
- package/components/app/providers/SearchResponseProvider.js +81 -0
- package/components/app/providers/SearchResponseProvider.test.d.ts +1 -0
- package/components/app/providers/SearchResponseProvider.test.js +406 -0
- package/components/app/providers/SocketProvider.d.ts +11 -2
- package/components/app/providers/SocketProvider.js +21 -8
- package/components/app/providers/UserListProvider.js +28 -8
- package/components/app/providers/UserListProvider.test.d.ts +1 -0
- package/components/app/providers/UserListProvider.test.js +150 -0
- package/components/app/providers/ViewProvider.js +3 -3
- package/components/app/providers/ViewProvider.test.js +4 -1
- package/components/elements/Comment.js +2 -2
- package/components/elements/ContextMenu.d.ts +56 -0
- package/components/elements/ContextMenu.js +113 -0
- package/components/elements/ContextMenu.test.d.ts +1 -0
- package/components/elements/ContextMenu.test.js +215 -0
- package/components/elements/EditRow.js +4 -4
- package/components/{routes/overviews/OverviewEditor.js → elements/MarkdownEditor.js} +3 -3
- package/components/elements/ObjectDetails.d.ts +6 -0
- package/components/elements/{hit/HitDetails.js → ObjectDetails.js} +17 -17
- package/components/elements/PluginChip.d.ts +1 -1
- package/components/elements/PluginChip.js +0 -1
- package/components/elements/PluginTypography.d.ts +2 -1
- package/components/elements/PluginTypography.js +3 -2
- package/components/elements/UserList.d.ts +5 -2
- package/components/elements/UserList.js +34 -17
- package/components/elements/UserList.test.d.ts +1 -0
- package/components/elements/UserList.test.js +122 -0
- package/components/elements/addons/buttons/CustomIconButton.test.d.ts +1 -0
- package/components/elements/addons/buttons/CustomIconButton.test.js +81 -0
- package/components/elements/addons/buttons/index.d.ts +1 -1
- package/components/elements/addons/layout/FlexOne.d.ts +3 -2
- package/components/elements/addons/layout/FlexPort.d.ts +2 -1
- package/components/elements/addons/layout/FlexVertical.d.ts +2 -1
- package/components/elements/addons/layout/FlexVertical.test.d.ts +1 -0
- package/components/elements/addons/layout/FlexVertical.test.js +32 -0
- package/components/elements/addons/layout/vsbox/VSBoxContent.test.d.ts +1 -0
- package/components/elements/addons/layout/vsbox/VSBoxContent.test.js +26 -0
- package/components/elements/addons/layout/vsbox/VSBoxElement.d.ts +2 -1
- package/components/elements/addons/lists/TuiList.d.ts +2 -1
- package/components/elements/addons/lists/TuiListBase.d.ts +2 -1
- package/components/elements/addons/lists/TuiListElement.d.ts +3 -2
- package/components/elements/addons/lists/TuiListElement.js +0 -1
- package/components/elements/addons/lists/TuiListMenu.d.ts +2 -1
- package/components/elements/addons/lists/TuiListMenu.js +1 -1
- package/components/elements/addons/lists/table/TuiTableHeader.d.ts +3 -2
- package/components/elements/addons/lists/table/index.d.ts +1 -1
- package/components/elements/addons/search/SearchPagination.d.ts +2 -1
- package/components/elements/addons/search/SearchPagination.js +4 -4
- package/components/elements/addons/search/SearchTotal.js +1 -1
- package/components/elements/addons/search/SearchTotal.test.js +5 -3
- package/components/elements/addons/search/phrase/Phrase.js +1 -1
- package/components/elements/addons/search/phrase/WordLexer.test.d.ts +1 -0
- package/components/elements/addons/search/phrase/WordLexer.test.js +55 -0
- package/components/elements/case/CaseCard.d.ts +12 -0
- package/components/elements/case/CaseCard.js +43 -0
- package/components/elements/case/CasePreview.d.ts +6 -0
- package/components/elements/case/CasePreview.js +17 -0
- package/components/elements/case/StatusIcon.d.ts +5 -0
- package/components/elements/case/StatusIcon.js +13 -0
- package/components/elements/display/ActionButton.js +1 -1
- package/components/elements/display/ChipPopper.d.ts +1 -1
- package/components/elements/display/ChipPopper.js +7 -6
- package/components/elements/display/Classification.js +1 -1
- package/components/elements/display/ClassificationChip.d.ts +14 -0
- package/components/elements/display/ClassificationChip.js +36 -0
- package/components/elements/display/HandlebarsMarkdown.js +38 -3
- package/components/elements/display/HowlerAvatar.js +2 -2
- package/components/elements/display/HowlerCard.js +1 -1
- package/components/elements/display/HowlerCard.test.js +5 -9
- package/components/elements/display/Image.js +3 -3
- package/components/elements/display/ItemManager.d.ts +2 -2
- package/components/elements/display/ItemManager.js +3 -3
- package/components/elements/display/Markdown.js +2 -2
- package/components/elements/display/Modal.js +2 -0
- package/components/elements/display/QueryResultText.d.ts +1 -0
- package/components/elements/display/QueryResultText.js +2 -2
- package/components/elements/display/handlebars/helpers.d.ts +4 -0
- package/components/elements/display/handlebars/helpers.js +134 -35
- package/components/elements/display/json/JSONViewer.js +2 -2
- package/components/elements/display/modals/RationaleModal.js +2 -2
- package/components/elements/display/modals/RationaleModal.test.js +1 -1
- package/components/elements/event/EventCard.d.ts +6 -0
- package/components/elements/event/EventCard.js +22 -0
- package/components/elements/event/EventPreview.d.ts +6 -0
- package/components/elements/event/EventPreview.js +12 -0
- package/components/elements/hit/HitActions.d.ts +1 -1
- package/components/elements/hit/HitActions.js +5 -5
- package/components/elements/hit/HitBanner.d.ts +1 -0
- package/components/elements/hit/HitBanner.js +32 -50
- package/components/elements/hit/HitCard.d.ts +4 -0
- package/components/elements/hit/HitCard.js +7 -7
- package/components/elements/hit/HitLabels.js +3 -3
- package/components/elements/hit/HitLabels.test.d.ts +1 -0
- package/components/elements/hit/HitLabels.test.js +77 -0
- package/components/elements/hit/HitLinks.d.ts +5 -4
- package/components/elements/hit/HitLinks.js +28 -10
- package/components/elements/hit/HitNotebooks.js +32 -31
- package/components/elements/hit/HitOutline.d.ts +1 -0
- package/components/elements/hit/HitOutline.js +4 -4
- package/components/elements/hit/HitOverview.js +2 -2
- package/components/elements/hit/{HitQuickSearch.d.ts → HitPreview.d.ts} +3 -3
- package/components/elements/hit/{HitQuickSearch.js → HitPreview.js} +11 -5
- package/components/elements/hit/HitSummary.d.ts +2 -1
- package/components/elements/hit/HitSummary.js +8 -7
- package/components/elements/hit/NotebookTooltip.d.ts +3 -0
- package/components/elements/hit/NotebookTooltip.js +8 -0
- package/components/elements/hit/PivotTooltip.d.ts +7 -0
- package/components/elements/hit/PivotTooltip.js +9 -0
- package/components/elements/hit/RelatedLinkTooltip.d.ts +6 -0
- package/components/elements/hit/RelatedLinkTooltip.js +8 -0
- package/components/elements/hit/ResolvePivotUrl.d.ts +4 -0
- package/components/elements/hit/ResolvePivotUrl.js +22 -0
- package/components/elements/hit/actions/ButtonActions.js +1 -3
- package/components/elements/hit/aggregate/HitGraph.js +9 -9
- package/components/elements/hit/elements/AnalyticLink.d.ts +9 -0
- package/components/elements/hit/elements/AnalyticLink.js +22 -0
- package/components/elements/hit/elements/{HitUsers.d.ts → Assigned.d.ts} +2 -4
- package/components/elements/hit/elements/Assigned.js +35 -0
- package/components/elements/hit/elements/Assigned.test.d.ts +1 -0
- package/components/elements/hit/elements/Assigned.test.js +65 -0
- package/components/{routes/hits/search → elements/hit}/grid/AddColumnModal.js +6 -5
- package/components/{routes/hits/search → elements/hit}/grid/ColumnHeader.d.ts +2 -1
- package/components/{routes/hits/search → elements/hit}/grid/ColumnHeader.js +3 -3
- package/components/{routes/hits/search → elements/hit}/grid/EnhancedCell.d.ts +2 -1
- package/components/{routes/hits/search → elements/hit}/grid/EnhancedCell.js +2 -2
- package/components/{routes/hits/search/grid/HitRow.d.ts → elements/hit/grid/RecordRow.d.ts} +4 -3
- package/components/{routes/hits/search/grid/HitRow.js → elements/hit/grid/RecordRow.js} +12 -10
- package/components/elements/hit/grid/RecordTable.d.ts +13 -0
- package/components/elements/hit/grid/RecordTable.js +84 -0
- package/components/elements/hit/outlines/DefaultOutline.js +2 -4
- package/components/elements/hit/related/PivotLink.d.ts +3 -0
- package/components/elements/hit/related/PivotLink.js +6 -3
- package/components/elements/hit/related/RelatedLink.d.ts +1 -0
- package/components/elements/hit/related/RelatedLink.js +18 -15
- package/components/elements/hit/related/RelatedRecords.js +63 -0
- package/components/elements/{hit/HitComments.d.ts → record/RecordComments.d.ts} +5 -4
- package/components/elements/{hit/HitComments.js → record/RecordComments.js} +33 -34
- package/components/{routes/hits/search/HitContextMenu.d.ts → elements/record/RecordContextMenu.d.ts} +3 -3
- package/components/elements/record/RecordContextMenu.js +268 -0
- package/components/elements/record/RecordContextMenu.test.d.ts +1 -0
- package/components/{routes/hits/search/HitContextMenu.test.js → elements/record/RecordContextMenu.test.js} +143 -49
- package/components/elements/record/RecordRelated.d.ts +7 -0
- package/components/elements/record/RecordRelated.js +34 -0
- package/components/elements/{hit/HitWorklog.d.ts → record/RecordWorklog.d.ts} +4 -3
- package/components/elements/{hit/HitWorklog.js → record/RecordWorklog.js} +16 -14
- package/components/elements/search/FuzzySearchBar.d.ts +7 -0
- package/components/elements/search/FuzzySearchBar.js +33 -0
- package/components/elements/search/FuzzySearchBar.test.d.ts +1 -0
- package/components/elements/search/FuzzySearchBar.test.js +87 -0
- package/components/elements/view/LayoutToggle.d.ts +8 -0
- package/components/elements/view/LayoutToggle.js +12 -0
- package/components/elements/view/ViewTitle.d.ts +4 -0
- package/components/elements/view/ViewTitle.js +13 -3
- package/components/hooks/useHitActions.d.ts +1 -1
- package/components/hooks/useHitActions.js +5 -5
- package/components/hooks/useLocalStorage.js +1 -1
- package/components/hooks/useLocalStorageItem.test.js +2 -2
- package/components/hooks/useMyApi.d.ts +1 -1
- package/components/hooks/useMyChart.d.ts +23 -23
- package/components/hooks/useMyPreferences.js +10 -1
- package/components/hooks/useMySearch.js +2 -2
- package/components/hooks/useMySitemap.js +3 -1
- package/components/hooks/useMySnackbar.js +1 -1
- package/components/hooks/useMyTheme.js +9 -2
- package/components/hooks/useMyTheme.test.d.ts +1 -0
- package/components/hooks/useMyTheme.test.js +35 -0
- package/components/hooks/useMyUserFunctions.d.ts +21 -21
- package/components/hooks/{useHitSelection.d.ts → useRecordSelection.d.ts} +2 -2
- package/components/hooks/{useHitSelection.js → useRecordSelection.js} +12 -33
- package/components/hooks/useRelatedRecords.d.ts +13 -0
- package/components/hooks/useRelatedRecords.js +32 -0
- package/components/logins/Login.js +1 -1
- package/components/logins/auth/OAuthLogin.js +1 -1
- package/components/logins/hooks/useLogin.js +2 -2
- package/components/routes/ErrorBoundary.d.ts +2 -13
- package/components/routes/ErrorBoundary.js +12 -1
- package/components/routes/ErrorBoundary.test.js +27 -4
- package/components/routes/action/edit/ActionEditor.js +6 -6
- package/components/routes/action/shared/OperationEntry.js +1 -1
- package/components/routes/action/shared/OperationStep.js +1 -1
- package/components/routes/action/useMyActionFunctions.js +6 -3
- package/components/routes/action/view/ActionDetails.js +9 -3
- package/components/routes/action/view/ActionSearch.js +25 -19
- package/components/routes/admin/users/UserEditor.js +1 -1
- package/components/routes/admin/users/UserSearch.js +5 -5
- package/components/routes/advanced/QueryBuilder.js +6 -29
- package/components/routes/advanced/QueryEditor.js +3 -3
- package/components/routes/advanced/eqlTokenProvider.test.d.ts +1 -0
- package/components/routes/advanced/eqlTokenProvider.test.js +34 -0
- package/components/routes/advanced/historyCompletionProvider.js +3 -3
- package/components/routes/advanced/luceneCompletionProvider.js +1 -1
- package/components/routes/advanced/luceneTokenProvider.test.d.ts +1 -0
- package/components/routes/advanced/luceneTokenProvider.test.js +34 -0
- package/components/routes/analytics/AnalyticComments.js +3 -5
- package/components/routes/analytics/AnalyticDetails.js +8 -56
- package/components/routes/analytics/AnalyticHitComments.js +1 -1
- package/components/routes/analytics/AnalyticHitComments.test.js +1 -1
- package/components/routes/analytics/AnalyticOverview.js +2 -2
- package/components/routes/analytics/AnalyticOverviews.js +1 -1
- package/components/routes/analytics/AnalyticSearch.js +16 -25
- package/components/routes/analytics/AnalyticTemplates.js +1 -1
- package/components/routes/analytics/TriageSettings.js +2 -2
- package/components/routes/analytics/widgets/Assessment.js +1 -1
- package/components/routes/analytics/widgets/Created.js +1 -1
- package/components/routes/analytics/widgets/Escalation.js +1 -1
- package/components/routes/analytics/widgets/Stacked.js +1 -1
- package/components/routes/cases/CaseViewer.d.ts +2 -0
- package/components/routes/cases/CaseViewer.js +44 -0
- package/components/routes/cases/CaseViewer.test.d.ts +1 -0
- package/components/routes/cases/CaseViewer.test.js +156 -0
- package/components/routes/cases/Cases.d.ts +2 -0
- package/components/routes/cases/Cases.js +140 -0
- package/components/routes/cases/constants.d.ts +6 -0
- package/components/routes/cases/constants.js +6 -0
- package/components/routes/cases/detail/AlertPanel.d.ts +6 -0
- package/components/routes/cases/detail/AlertPanel.js +34 -0
- package/components/routes/cases/detail/AlertPanel.test.d.ts +1 -0
- package/components/routes/cases/detail/AlertPanel.test.js +107 -0
- package/components/routes/cases/detail/CaseDashboard.d.ts +7 -0
- package/components/routes/cases/detail/CaseDashboard.js +66 -0
- package/components/routes/cases/detail/CaseDashboard.test.d.ts +1 -0
- package/components/routes/cases/detail/CaseDashboard.test.js +218 -0
- package/components/routes/cases/detail/CaseDetails.d.ts +6 -0
- package/components/routes/cases/detail/CaseDetails.js +79 -0
- package/components/routes/cases/detail/CaseDetails.test.d.ts +1 -0
- package/components/routes/cases/detail/CaseDetails.test.js +145 -0
- package/components/routes/cases/detail/CaseObservables.d.ts +6 -0
- package/components/routes/cases/detail/CaseObservables.js +127 -0
- package/components/routes/cases/detail/CaseObservables.test.d.ts +1 -0
- package/components/routes/cases/detail/CaseObservables.test.js +167 -0
- package/components/routes/cases/detail/CaseOverview.d.ts +7 -0
- package/components/routes/cases/detail/CaseOverview.js +40 -0
- package/components/routes/cases/detail/CaseRules.d.ts +7 -0
- package/components/routes/cases/detail/CaseRules.js +55 -0
- package/components/routes/cases/detail/CaseRules.test.d.ts +1 -0
- package/components/routes/cases/detail/CaseRules.test.js +238 -0
- package/components/routes/cases/detail/CaseSearch.d.ts +3 -0
- package/components/routes/cases/detail/CaseSearch.js +78 -0
- package/components/routes/cases/detail/CaseSearch.test.d.ts +1 -0
- package/components/routes/cases/detail/CaseSearch.test.js +154 -0
- package/components/routes/cases/detail/CaseSidebar.d.ts +8 -0
- package/components/routes/cases/detail/CaseSidebar.js +147 -0
- package/components/routes/cases/detail/CaseSidebar.test.d.ts +1 -0
- package/components/routes/cases/detail/CaseSidebar.test.js +155 -0
- package/components/routes/cases/detail/CaseTask.d.ts +14 -0
- package/components/routes/cases/detail/CaseTask.js +71 -0
- package/components/routes/cases/detail/CaseTask.test.d.ts +1 -0
- package/components/routes/cases/detail/CaseTask.test.js +143 -0
- package/components/routes/cases/detail/CaseTimeline.d.ts +12 -0
- package/components/routes/cases/detail/CaseTimeline.js +120 -0
- package/components/routes/cases/detail/CaseTimeline.test.d.ts +1 -0
- package/components/routes/cases/detail/CaseTimeline.test.js +319 -0
- package/components/routes/cases/detail/CreateRuleDialog.d.ts +9 -0
- package/components/routes/cases/detail/CreateRuleDialog.js +145 -0
- package/components/routes/cases/detail/CreateRuleDialog.test.d.ts +1 -0
- package/components/routes/cases/detail/CreateRuleDialog.test.js +218 -0
- package/components/routes/cases/detail/ItemPage.d.ts +6 -0
- package/components/routes/cases/detail/ItemPage.js +100 -0
- package/components/routes/cases/detail/ItemPage.test.d.ts +1 -0
- package/components/routes/cases/detail/ItemPage.test.js +238 -0
- package/components/routes/cases/detail/MarkdownPage.d.ts +8 -0
- package/components/routes/cases/detail/MarkdownPage.js +63 -0
- package/components/routes/cases/detail/MarkdownPage.test.d.ts +1 -0
- package/components/routes/cases/detail/MarkdownPage.test.js +116 -0
- package/components/routes/cases/detail/RelatedCasePanel.d.ts +6 -0
- package/components/routes/cases/detail/RelatedCasePanel.js +34 -0
- package/components/routes/cases/detail/RelatedCasePanel.test.d.ts +1 -0
- package/components/routes/cases/detail/RelatedCasePanel.test.js +115 -0
- package/components/routes/cases/detail/TaskPanel.d.ts +7 -0
- package/components/routes/cases/detail/TaskPanel.js +95 -0
- package/components/routes/cases/detail/TaskPanel.test.d.ts +1 -0
- package/components/routes/cases/detail/TaskPanel.test.js +145 -0
- package/components/routes/cases/detail/aggregates/CaseAggregate.d.ts +11 -0
- package/components/routes/cases/detail/aggregates/CaseAggregate.js +24 -0
- package/components/routes/cases/detail/aggregates/SourceAggregate.d.ts +6 -0
- package/components/routes/cases/detail/aggregates/SourceAggregate.js +26 -0
- package/components/routes/cases/detail/observables/Observable.d.ts +8 -0
- package/components/routes/cases/detail/observables/Observable.js +14 -0
- package/components/routes/cases/detail/observables/Observable.test.d.ts +1 -0
- package/components/routes/cases/detail/observables/Observable.test.js +80 -0
- package/components/routes/cases/detail/observables/ObservableTable.d.ts +7 -0
- package/components/routes/cases/detail/observables/ObservableTable.js +61 -0
- package/components/routes/cases/detail/observables/ObservableTable.test.d.ts +1 -0
- package/components/routes/cases/detail/observables/ObservableTable.test.js +97 -0
- package/components/routes/cases/detail/sidebar/CaseFolder.d.ts +22 -0
- package/components/routes/cases/detail/sidebar/CaseFolder.js +105 -0
- package/components/routes/cases/detail/sidebar/CaseFolder.test.d.ts +1 -0
- package/components/routes/cases/detail/sidebar/CaseFolder.test.js +98 -0
- package/components/routes/cases/detail/sidebar/CaseFolderContextMenu.d.ts +32 -0
- package/components/routes/cases/detail/sidebar/CaseFolderContextMenu.js +99 -0
- package/components/routes/cases/detail/sidebar/CaseFolderContextMenu.test.d.ts +1 -0
- package/components/routes/cases/detail/sidebar/CaseFolderContextMenu.test.js +117 -0
- package/components/routes/cases/detail/sidebar/FolderEntry.d.ts +25 -0
- package/components/routes/cases/detail/sidebar/FolderEntry.js +89 -0
- package/components/routes/cases/detail/sidebar/FolderEntry.test.d.ts +1 -0
- package/components/routes/cases/detail/sidebar/FolderEntry.test.js +81 -0
- package/components/routes/cases/detail/sidebar/RootDropZone.d.ts +5 -0
- package/components/routes/cases/detail/sidebar/RootDropZone.js +33 -0
- package/components/routes/cases/detail/sidebar/types.d.ts +9 -0
- package/components/routes/cases/detail/sidebar/utils.d.ts +10 -0
- package/components/routes/cases/detail/sidebar/utils.js +51 -0
- package/components/routes/cases/detail/sidebar/utils.test.d.ts +1 -0
- package/components/routes/cases/detail/sidebar/utils.test.js +82 -0
- package/components/routes/cases/detail/types.d.ts +22 -0
- package/components/routes/cases/detail/utils.d.ts +28 -0
- package/components/routes/cases/detail/utils.js +117 -0
- package/components/routes/cases/detail/utils.test.d.ts +1 -0
- package/components/routes/cases/detail/utils.test.js +166 -0
- package/components/routes/cases/hooks/useCase.d.ts +13 -0
- package/components/routes/cases/hooks/useCase.js +67 -0
- package/components/routes/cases/hooks/useCase.test.d.ts +1 -0
- package/components/routes/cases/hooks/useCase.test.js +170 -0
- package/components/routes/cases/modals/AddRecordToCaseModal.d.ts +7 -0
- package/components/routes/cases/modals/AddRecordToCaseModal.js +57 -0
- package/components/routes/cases/modals/AddRecordToCaseModal.test.d.ts +1 -0
- package/components/routes/cases/modals/AddRecordToCaseModal.test.js +309 -0
- package/components/routes/cases/modals/AddToCaseModal.d.ts +9 -0
- package/components/routes/cases/modals/AddToCaseModal.js +72 -0
- package/components/routes/cases/modals/CaseRecordRow.d.ts +9 -0
- package/components/routes/cases/modals/CaseRecordRow.js +14 -0
- package/components/routes/cases/modals/CreateCaseModal.d.ts +7 -0
- package/components/routes/cases/modals/CreateCaseModal.js +53 -0
- package/components/routes/cases/modals/CreateCaseModal.test.d.ts +1 -0
- package/components/routes/cases/modals/CreateCaseModal.test.js +319 -0
- package/components/routes/cases/modals/RenameItemModal.d.ts +9 -0
- package/components/routes/cases/modals/RenameItemModal.js +44 -0
- package/components/routes/cases/modals/ResolveModal.d.ts +7 -0
- package/components/routes/cases/modals/ResolveModal.js +120 -0
- package/components/routes/cases/modals/ResolveModal.test.d.ts +1 -0
- package/components/routes/cases/modals/ResolveModal.test.js +520 -0
- package/components/routes/cases/modals/hooks.d.ts +7 -0
- package/components/routes/cases/modals/hooks.js +40 -0
- package/components/routes/cases/modals/types.d.ts +13 -0
- package/components/routes/cases/search/CaseAssigneeFilter.d.ts +6 -0
- package/components/routes/cases/search/CaseAssigneeFilter.js +33 -0
- package/components/routes/cases/search/CaseAssigneeFilter.test.d.ts +1 -0
- package/components/routes/cases/search/CaseAssigneeFilter.test.js +127 -0
- package/components/routes/cases/search/CaseDateFilter.d.ts +13 -0
- package/components/routes/cases/search/CaseDateFilter.js +26 -0
- package/components/routes/cases/search/CaseDateFilter.test.d.ts +1 -0
- package/components/routes/cases/search/CaseDateFilter.test.js +115 -0
- package/components/routes/cases/search/CaseStatusFilter.d.ts +6 -0
- package/components/routes/cases/search/CaseStatusFilter.js +13 -0
- package/components/routes/cases/search/CaseStatusFilter.test.d.ts +1 -0
- package/components/routes/cases/search/CaseStatusFilter.test.js +86 -0
- package/components/routes/cases/utils.d.ts +3 -0
- package/components/routes/cases/utils.js +21 -0
- package/components/routes/dossiers/DossierEditor.js +4 -4
- package/components/routes/dossiers/DossierEditor.test.js +2 -2
- package/components/routes/dossiers/Dossiers.js +16 -14
- package/components/routes/dossiers/PivotForm.js +2 -4
- package/components/routes/events/EventViewer.d.ts +7 -0
- package/components/routes/events/EventViewer.js +24 -0
- package/components/routes/help/ApiDocumentation.js +2 -2
- package/components/routes/help/HitBannerDocumentation.js +2 -1
- package/components/routes/help/HitDocumentation.js +1 -3
- package/components/routes/help/HitSchemaDocumentation.js +1 -1
- package/components/routes/help/OverviewDocumentation.d.ts +1 -1
- package/components/routes/help/OverviewDocumentation.js +0 -1
- package/components/routes/help/RetentionDocumentation.js +2 -2
- package/components/routes/help/SearchDocumentation.js +1 -1
- package/components/routes/help/markdown/en/client.md.js +1 -1
- package/components/routes/help/markdown/fr/client.md.js +1 -1
- package/components/routes/hits/search/InformationPane.d.ts +1 -0
- package/components/routes/hits/search/InformationPane.js +52 -65
- package/components/routes/hits/search/QuerySettings.js +2 -1
- package/components/routes/hits/search/QuerySettings.test.js +19 -17
- package/components/routes/hits/search/{HitBrowser.js → RecordBrowser.js} +13 -12
- package/components/routes/hits/search/{HitQuery.d.ts → RecordQuery.d.ts} +2 -2
- package/components/routes/hits/search/{HitQuery.js → RecordQuery.js} +6 -6
- package/components/routes/hits/search/SearchPane.js +28 -50
- package/components/routes/hits/search/ViewLink.js +7 -6
- package/components/routes/hits/search/ViewLink.test.js +8 -9
- package/components/routes/hits/search/grid/RecordGrid.d.ts +3 -0
- package/components/routes/hits/search/grid/RecordGrid.js +64 -0
- package/components/routes/hits/search/shared/CustomSort.js +1 -1
- package/components/routes/hits/search/shared/CustomSpan.test.js +3 -4
- package/components/routes/hits/search/shared/HitFilter.d.ts +1 -1
- package/components/routes/hits/search/shared/HitSort.d.ts +1 -1
- package/components/routes/hits/search/shared/HitSort.js +2 -1
- package/components/routes/hits/search/shared/IndexPicker.d.ts +8 -0
- package/components/routes/hits/search/shared/IndexPicker.js +21 -0
- package/components/routes/hits/search/shared/LayoutSettings.js +25 -0
- package/components/routes/hits/search/shared/SearchActionMenu.d.ts +4 -0
- package/components/routes/hits/search/shared/SearchActionMenu.js +11 -0
- package/components/routes/hits/search/shared/SearchSpan.d.ts +1 -1
- package/components/routes/hits/search/shared/SearchSpan.js +1 -1
- package/components/routes/hits/view/HitViewer.js +16 -17
- package/components/routes/home/AddNewCard.js +2 -2
- package/components/routes/home/AddNewCard.test.js +20 -2
- package/components/routes/home/AnalyticCard.js +1 -1
- package/components/routes/home/EntryWrapper.js +1 -1
- package/components/routes/home/HomeSettings.js +1 -1
- package/components/routes/home/HomeSettings.test.d.ts +1 -0
- package/components/routes/home/HomeSettings.test.js +44 -0
- package/components/routes/home/ViewCard.js +52 -46
- package/components/routes/home/ViewRefresh.test.js +1 -1
- package/components/routes/home/index.js +2 -2
- package/components/routes/overviews/OverviewCard.js +1 -1
- package/components/routes/overviews/OverviewViewer.js +13 -10
- package/components/routes/overviews/Overviews.js +16 -14
- package/components/routes/overviews/markdownExtendedTokenProvider.js +15 -15
- package/components/routes/overviews/markdownExtendedTokenProvider.test.d.ts +1 -0
- package/components/routes/overviews/markdownExtendedTokenProvider.test.js +50 -0
- package/components/routes/settings/ProfileSection.js +2 -2
- package/components/routes/templates/TemplateEditor.d.ts +3 -2
- package/components/routes/templates/TemplateEditor.js +1 -1
- package/components/routes/templates/TemplateViewer.js +10 -5
- package/components/routes/templates/Templates.js +19 -14
- package/components/routes/views/ViewComposer.js +78 -26
- package/components/routes/views/Views.js +17 -14
- package/i18n.js +1 -1
- package/index.css +4 -0
- package/index.d.ts +1 -1
- package/index.js +1 -1
- package/locales/en/translation.json +188 -34
- package/locales/fr/translation.json +186 -32
- package/models/WithMetadata.d.ts +2 -1
- package/models/entities/generated/Analytic.d.ts +0 -3
- package/models/entities/generated/ApiType.d.ts +3 -1
- package/models/entities/generated/AttachmentsFile.d.ts +12 -0
- package/models/entities/generated/Case.d.ts +29 -0
- package/models/entities/generated/Column.d.ts +7 -0
- package/models/entities/generated/DestinationOriginal.d.ts +19 -0
- package/models/entities/generated/ECSEvent.d.ts +31 -0
- package/models/entities/generated/EmailAttachment.d.ts +8 -0
- package/models/entities/generated/EmailParent.d.ts +19 -0
- package/models/entities/generated/Enrichments.d.ts +7 -0
- package/models/entities/generated/EnrichmentsIndicator.d.ts +21 -0
- package/models/entities/generated/Event.d.ts +80 -26
- package/models/entities/generated/EventCloud.d.ts +20 -0
- package/models/entities/generated/EventDestination.d.ts +23 -0
- package/models/entities/generated/EventEmail.d.ts +30 -0
- package/models/entities/generated/EventFile.d.ts +36 -0
- package/models/entities/generated/EventHowler.d.ts +42 -0
- package/models/entities/generated/EventHttp.d.ts +11 -0
- package/models/entities/generated/EventObserver.d.ts +21 -0
- package/models/entities/generated/EventOrganization.d.ts +7 -0
- package/models/entities/generated/EventProcess.d.ts +34 -0
- package/models/entities/generated/EventSource.d.ts +23 -0
- package/models/entities/generated/EventThreat.d.ts +21 -0
- package/models/entities/generated/EventTls.d.ts +12 -0
- package/models/entities/generated/Hit.d.ts +3 -2
- package/models/entities/generated/Host.d.ts +1 -0
- package/models/entities/generated/Howler.d.ts +1 -6
- package/models/entities/generated/HttpResponse.d.ts +11 -0
- package/models/entities/generated/Item.d.ts +12 -0
- package/models/entities/generated/ObserverIngress.d.ts +9 -0
- package/models/entities/generated/Rule.d.ts +8 -9
- package/models/entities/generated/Settings.d.ts +4 -0
- package/models/entities/generated/Task.d.ts +10 -0
- package/models/entities/generated/Threat.d.ts +2 -2
- package/models/entities/generated/{Enrichment.d.ts → ThreatEnrichment.d.ts} +1 -1
- package/models/entities/generated/View.d.ts +1 -0
- package/models/socket/CaseUpdate.d.ts +5 -0
- package/models/socket/ViewersUpdate.d.ts +4 -0
- package/package.json +156 -137
- package/plugins/clue/components/ClueLeadForm.js +1 -1
- package/plugins/clue/components/CluePivotForm.js +2 -2
- package/plugins/clue/components/ClueTypography.js +2 -2
- package/plugins/clue/helpers.js +4 -4
- package/plugins/clue/index.d.ts +3 -2
- package/plugins/clue/index.js +0 -1
- package/plugins/clue/utils.d.ts +2 -1
- package/rest/AxiosClient.test.d.ts +1 -0
- package/rest/AxiosClient.test.js +185 -0
- package/tests/mocks.d.ts +11 -1
- package/tests/mocks.js +12 -7
- package/tests/server-handlers.js +11 -1
- package/tests/utils.d.ts +4 -0
- package/tests/utils.js +21 -0
- package/utils/Throttler.test.js +2 -2
- package/utils/actionUtils.d.ts +3 -3
- package/utils/classificationParser.d.ts +195 -0
- package/utils/classificationParser.js +680 -0
- package/utils/constants.d.ts +4 -3
- package/utils/constants.js +6 -0
- package/utils/localStorage.js +1 -1
- package/utils/menuUtils.js +0 -4
- package/utils/recordFunctions.d.ts +3 -0
- package/utils/recordFunctions.js +8 -0
- package/utils/recordFunctions.test.d.ts +1 -0
- package/utils/{hitFunctions.test.js → recordFunctions.test.js} +1 -1
- package/utils/socketUtils.d.ts +14 -0
- package/utils/socketUtils.js +17 -1
- package/utils/socketUtils.test.js +49 -16
- package/utils/stringUtils.d.ts +1 -0
- package/utils/stringUtils.js +7 -0
- package/utils/stringUtils.test.js +22 -2
- package/utils/typeUtils.d.ts +7 -0
- package/utils/typeUtils.js +27 -0
- package/utils/utils.d.ts +1 -1
- package/utils/utils.js +2 -2
- package/utils/utils.test.js +119 -2
- package/utils/viewUtils.js +3 -0
- package/utils/xsrf.js +1 -1
- package/api/analytic/rules.d.ts +0 -3
- package/api/analytic/rules.js +0 -8
- package/components/app/providers/HitProvider.d.ts +0 -22
- package/components/elements/display/icons/BundleButton.d.ts +0 -6
- package/components/elements/display/icons/BundleButton.js +0 -32
- package/components/elements/hit/HitRelated.d.ts +0 -6
- package/components/elements/hit/HitRelated.js +0 -7
- package/components/elements/hit/elements/HitUsers.js +0 -33
- package/components/routes/advanced/RuleModal.d.ts +0 -7
- package/components/routes/advanced/RuleModal.js +0 -83
- package/components/routes/analytics/RuleView.d.ts +0 -8
- package/components/routes/analytics/RuleView.js +0 -48
- package/components/routes/help/BundleDocumentation.d.ts +0 -3
- package/components/routes/help/BundleDocumentation.js +0 -12
- package/components/routes/help/markdown/en/bundles.md.js +0 -1
- package/components/routes/help/markdown/fr/bundles.md.js +0 -1
- package/components/routes/hits/search/BundleParentMenu.d.ts +0 -6
- package/components/routes/hits/search/BundleParentMenu.js +0 -32
- package/components/routes/hits/search/BundleScroller.d.ts +0 -2
- package/components/routes/hits/search/BundleScroller.js +0 -6
- package/components/routes/hits/search/HitContextMenu.js +0 -239
- package/components/routes/hits/search/LayoutSettings.js +0 -24
- package/components/routes/hits/search/grid/HitGrid.d.ts +0 -3
- package/components/routes/hits/search/grid/HitGrid.js +0 -132
- package/utils/hitFunctions.d.ts +0 -2
- package/utils/hitFunctions.js +0 -8
- /package/{components/app/providers/HitSearchProvider.test.d.ts → api/socket/viewers.test.d.ts} +0 -0
- /package/components/{routes/hits/search/HitContextMenu.test.d.ts → app/providers/GridColumnsProvider.test.d.ts} +0 -0
- /package/{utils/hitFunctions.test.d.ts → components/app/providers/RecordSearchProvider.test.d.ts} +0 -0
- /package/components/{routes/overviews/OverviewEditor.d.ts → elements/MarkdownEditor.d.ts} +0 -0
- /package/components/{routes/hits/search → elements/hit}/grid/AddColumnModal.d.ts +0 -0
- /package/components/elements/hit/{HitDetails.d.ts → related/RelatedRecords.d.ts} +0 -0
- /package/components/routes/hits/search/{HitBrowser.d.ts → RecordBrowser.d.ts} +0 -0
- /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 =
|
|
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
|
-
|
|
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
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
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
|
|
70
|
-
|
|
71
|
-
|
|
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
|
|
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
|
|
138
|
-
|
|
139
|
-
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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('
|
|
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
|
-
|
|
266
|
+
resetFilters: ctx.resetFilters
|
|
283
267
|
})), { wrapper: Wrapper });
|
|
284
268
|
await act(async () => {
|
|
285
|
-
hook.result.current.
|
|
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
|
-
|
|
278
|
+
resetFilters: ctx.resetFilters
|
|
295
279
|
})), { wrapper: Wrapper });
|
|
296
280
|
await act(async () => {
|
|
297
|
-
hook.result.current.
|
|
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
|
|
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
|
|
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
|
-
|
|
423
|
+
resetFilters: ctx.resetFilters
|
|
445
424
|
})), { wrapper: Wrapper });
|
|
446
425
|
await act(async () => {
|
|
447
|
-
hook.result.current.
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
607
|
-
|
|
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
|
|
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
|
|
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
|
|
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
|
|
649
|
-
|
|
650
|
-
|
|
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
|
-
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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('
|
|
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
|
-
|
|
1118
|
+
resetViews: ctx.resetViews
|
|
850
1119
|
})), { wrapper: Wrapper });
|
|
851
1120
|
await act(async () => {
|
|
852
|
-
hook.result.current.
|
|
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
|
-
|
|
1130
|
+
resetViews: ctx.resetViews
|
|
862
1131
|
})), { wrapper: Wrapper });
|
|
863
1132
|
await act(async () => {
|
|
864
|
-
hook.result.current.
|
|
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
|
|
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
|
|
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
|
-
|
|
1275
|
+
resetViews: ctx.resetViews
|
|
1012
1276
|
})), { wrapper: Wrapper });
|
|
1013
1277
|
await act(async () => {
|
|
1014
|
-
hook.result.current.
|
|
1278
|
+
hook.result.current.resetViews();
|
|
1015
1279
|
});
|
|
1016
1280
|
await waitFor(() => {
|
|
1017
1281
|
expect(mockSetParams).toHaveBeenCalled();
|