@cccsaurora/howler-ui 2.18.0 → 2.19.0-cases.1040
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 +3 -2
- package/api/analytic/index.js +4 -4
- package/api/analytic/owner.d.ts +2 -1
- package/api/analytic/owner.js +2 -2
- package/api/analytic/rules.d.ts +2 -1
- package/api/analytic/rules.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 +9 -4
- package/api/index.js +18 -10
- package/api/overview/index.d.ts +4 -3
- package/api/overview/index.js +6 -6
- package/api/search/case.d.ts +4 -0
- package/api/search/case.js +8 -0
- package/api/search/facet/hit.d.ts +1 -3
- package/api/search/facet/index.d.ts +3 -1
- package/api/search/index.d.ts +2 -1
- package/api/search/index.js +2 -1
- package/api/search/overview.d.ts +2 -2
- 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 +6 -0
- package/api/v2/case/items.js +18 -0
- package/api/v2/case/rules.d.ts +6 -0
- package/api/v2/case/rules.js +18 -0
- package/api/v2/index.d.ts +4 -0
- package/api/v2/index.js +6 -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 +5 -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/commons/components/leftnav/LeftNavDrawer.js +1 -1
- package/components/app/App.d.ts +1 -0
- package/components/app/App.js +64 -13
- package/components/app/hooks/useMatchers.d.ts +1 -1
- package/components/app/hooks/useMatchers.js +23 -11
- package/components/app/hooks/useMatchers.test.js +22 -22
- package/components/app/hooks/useTitle.js +5 -5
- package/components/app/providers/FavouritesProvider.js +2 -6
- package/components/app/providers/ModalProvider.d.ts +2 -0
- package/components/app/providers/ModalProvider.js +5 -1
- package/components/app/providers/ParameterProvider.d.ts +9 -2
- package/components/app/providers/ParameterProvider.js +165 -240
- package/components/app/providers/ParameterProvider.test.js +346 -94
- package/components/app/providers/RecordProvider.d.ts +23 -0
- package/components/app/providers/{HitProvider.js → RecordProvider.js} +42 -42
- package/components/app/providers/{HitSearchProvider.d.ts → RecordSearchProvider.d.ts} +6 -6
- package/components/app/providers/{HitSearchProvider.js → RecordSearchProvider.js} +12 -17
- 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 +18 -5
- package/components/app/providers/UserListProvider.js +28 -8
- package/components/app/providers/ViewProvider.test.js +4 -1
- package/components/elements/ContextMenu.d.ts +56 -0
- package/components/elements/ContextMenu.js +109 -0
- package/components/elements/ContextMenu.test.d.ts +1 -0
- package/components/elements/ContextMenu.test.js +215 -0
- 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/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 +18 -8
- package/components/elements/addons/buttons/CustomButton.test.d.ts +1 -0
- package/components/elements/addons/buttons/CustomButton.test.js +106 -0
- package/components/elements/addons/layout/FlexOne.test.d.ts +1 -0
- package/components/elements/addons/layout/FlexOne.test.js +30 -0
- package/components/elements/addons/lists/TuiListBase.js +4 -0
- package/components/elements/addons/lists/TuiListElement.js +6 -3
- package/components/elements/addons/lists/index.d.ts +1 -0
- package/components/elements/addons/search/SearchPagination.d.ts +2 -1
- package/components/elements/addons/search/SearchPagination.js +4 -4
- package/components/elements/addons/search/SearchPagination.test.d.ts +1 -0
- package/components/elements/addons/search/SearchPagination.test.js +80 -0
- package/components/elements/addons/search/SearchTotal.test.d.ts +1 -0
- package/components/elements/addons/search/SearchTotal.test.js +47 -0
- package/components/elements/addons/search/phrase/Phrase.js +1 -1
- package/components/elements/case/CaseCard.d.ts +12 -0
- package/components/elements/case/CaseCard.js +42 -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/ChipPopper.d.ts +1 -1
- package/components/elements/display/ChipPopper.js +5 -5
- package/components/elements/display/DocumentationButton.test.d.ts +1 -0
- package/components/elements/display/DocumentationButton.test.js +84 -0
- package/components/elements/display/DynamicTabs.test.d.ts +1 -0
- package/components/elements/display/DynamicTabs.test.js +93 -0
- package/components/elements/display/HowlerAvatar.js +2 -1
- package/components/elements/display/HowlerCard.js +1 -1
- package/components/elements/display/HowlerCard.test.d.ts +1 -0
- package/components/elements/display/HowlerCard.test.js +51 -0
- package/components/elements/display/Image.test.d.ts +1 -0
- package/components/elements/display/Image.test.js +79 -0
- package/components/elements/display/ItemManager.d.ts +2 -2
- package/components/elements/display/ItemManager.js +1 -1
- package/components/elements/display/Markdown.js +9 -2
- package/components/elements/display/Modal.js +2 -0
- package/components/elements/display/QueryResultText.test.d.ts +1 -0
- package/components/elements/display/QueryResultText.test.js +48 -0
- package/components/elements/display/TextDivider.test.d.ts +1 -0
- package/components/elements/display/TextDivider.test.js +43 -0
- package/components/elements/display/TypingIndicator.test.d.ts +1 -0
- package/components/elements/display/TypingIndicator.test.js +33 -0
- package/components/elements/display/modals/ConfirmDeleteModal.d.ts +4 -0
- package/components/elements/display/modals/ConfirmDeleteModal.js +4 -2
- package/components/elements/hit/HitActions.js +4 -4
- package/components/elements/hit/HitBanner.d.ts +1 -0
- package/components/elements/hit/HitBanner.js +34 -51
- package/components/elements/hit/HitCard.d.ts +2 -0
- package/components/elements/hit/HitCard.js +7 -7
- package/components/elements/hit/HitLabels.js +2 -2
- package/components/elements/hit/HitOutline.d.ts +1 -0
- package/components/elements/hit/HitOutline.js +3 -3
- package/components/elements/hit/{HitQuickSearch.d.ts → HitPreview.d.ts} +3 -3
- package/components/elements/hit/{HitQuickSearch.js → HitPreview.js} +10 -4
- package/components/elements/hit/HitSummary.d.ts +2 -1
- package/components/elements/hit/HitSummary.js +9 -7
- package/components/elements/hit/aggregate/HitGraph.js +8 -8
- package/components/elements/hit/elements/AnalyticLink.d.ts +9 -0
- package/components/elements/hit/elements/AnalyticLink.js +22 -0
- package/components/elements/hit/elements/Assigned.d.ts +2 -0
- package/components/elements/hit/elements/Assigned.js +21 -16
- package/components/elements/hit/elements/Assigned.test.d.ts +1 -0
- package/components/elements/hit/elements/Assigned.test.js +65 -0
- package/components/elements/hit/outlines/DefaultOutline.js +1 -1
- package/components/elements/hit/related/RelatedRecords.js +63 -0
- package/components/elements/observable/ObservableCard.d.ts +6 -0
- package/components/elements/observable/ObservableCard.js +22 -0
- package/components/elements/observable/ObservablePreview.d.ts +6 -0
- package/components/elements/observable/ObservablePreview.js +12 -0
- package/components/elements/{hit/HitComments.d.ts → record/RecordComments.d.ts} +5 -4
- package/components/elements/{hit/HitComments.js → record/RecordComments.js} +29 -28
- 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} +190 -39
- 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} +15 -13
- package/components/elements/view/ViewTitle.d.ts +1 -0
- package/components/elements/view/ViewTitle.js +9 -2
- package/components/hooks/useHitActions.d.ts +1 -1
- package/components/hooks/useHitActions.js +4 -4
- package/components/hooks/useMyApi.d.ts +1 -1
- package/components/hooks/useMyPreferences.js +12 -2
- package/components/hooks/useMySearch.js +2 -2
- package/components/hooks/useMySitemap.js +4 -1
- package/components/hooks/useMyTheme.js +9 -2
- 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/routes/403.d.ts +3 -0
- package/components/routes/403.js +10 -0
- package/components/routes/403.test.d.ts +1 -0
- package/components/routes/403.test.js +27 -0
- package/components/routes/404.test.d.ts +1 -0
- package/components/routes/404.test.js +26 -0
- package/components/routes/ErrorBoundary.test.d.ts +1 -0
- package/components/routes/ErrorBoundary.test.js +43 -0
- package/components/routes/ErrorOccured.test.d.ts +1 -0
- package/components/routes/ErrorOccured.test.js +35 -0
- package/components/routes/Logout.test.d.ts +1 -0
- package/components/routes/Logout.test.js +59 -0
- package/components/routes/action/edit/ActionEditor.js +3 -3
- package/components/routes/action/useMyActionFunctions.js +9 -3
- package/components/routes/action/view/ActionDetails.js +15 -2
- package/components/routes/action/view/ActionSearch.js +32 -20
- package/components/routes/action/view/markdown/integrations.en.md.js +1 -1
- package/components/routes/action/view/markdown/integrations.fr.md.js +1 -1
- package/components/routes/advanced/QueryBuilder.js +1 -1
- package/components/routes/advanced/QueryEditor.js +3 -3
- package/components/routes/advanced/historyCompletionProvider.js +3 -3
- package/components/routes/analytics/AnalyticDetails.js +12 -8
- package/components/routes/analytics/AnalyticSearch.js +7 -7
- 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 +133 -0
- package/components/routes/cases/Cases.d.ts +2 -0
- package/components/routes/cases/Cases.js +147 -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 +33 -0
- package/components/routes/cases/detail/CaseAssets.d.ts +11 -0
- package/components/routes/cases/detail/CaseAssets.js +104 -0
- package/components/routes/cases/detail/CaseAssets.test.d.ts +1 -0
- package/components/routes/cases/detail/CaseAssets.test.js +167 -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/CaseDetails.d.ts +6 -0
- package/components/routes/cases/detail/CaseDetails.js +70 -0
- package/components/routes/cases/detail/CaseOverview.d.ts +7 -0
- package/components/routes/cases/detail/CaseOverview.js +43 -0
- package/components/routes/cases/detail/CaseRules.d.ts +7 -0
- package/components/routes/cases/detail/CaseRules.js +57 -0
- package/components/routes/cases/detail/CaseRules.test.d.ts +1 -0
- package/components/routes/cases/detail/CaseRules.test.js +221 -0
- package/components/routes/cases/detail/CaseSidebar.d.ts +8 -0
- package/components/routes/cases/detail/CaseSidebar.js +107 -0
- package/components/routes/cases/detail/CaseSidebar.test.d.ts +1 -0
- package/components/routes/cases/detail/CaseSidebar.test.js +266 -0
- package/components/routes/cases/detail/CaseTask.d.ts +11 -0
- package/components/routes/cases/detail/CaseTask.js +66 -0
- package/components/routes/cases/detail/CaseTimeline.d.ts +12 -0
- package/components/routes/cases/detail/CaseTimeline.js +106 -0
- package/components/routes/cases/detail/CaseTimeline.test.d.ts +1 -0
- package/components/routes/cases/detail/CaseTimeline.test.js +320 -0
- package/components/routes/cases/detail/CreateRuleDialog.d.ts +9 -0
- package/components/routes/cases/detail/CreateRuleDialog.js +163 -0
- package/components/routes/cases/detail/CreateRuleDialog.test.d.ts +1 -0
- package/components/routes/cases/detail/CreateRuleDialog.test.js +259 -0
- package/components/routes/cases/detail/ItemPage.d.ts +6 -0
- package/components/routes/cases/detail/ItemPage.js +95 -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/TaskPanel.d.ts +7 -0
- package/components/routes/cases/detail/TaskPanel.js +52 -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/assets/Asset.d.ts +14 -0
- package/components/routes/cases/detail/assets/Asset.js +12 -0
- package/components/routes/cases/detail/assets/Asset.test.d.ts +1 -0
- package/components/routes/cases/detail/assets/Asset.test.js +72 -0
- package/components/routes/cases/detail/sidebar/CaseFolder.d.ts +20 -0
- package/components/routes/cases/detail/sidebar/CaseFolder.js +83 -0
- package/components/routes/cases/detail/sidebar/CaseFolder.test.d.ts +1 -0
- package/components/routes/cases/detail/sidebar/CaseFolder.test.js +295 -0
- package/components/routes/cases/detail/sidebar/CaseFolderContextMenu.d.ts +34 -0
- package/components/routes/cases/detail/sidebar/CaseFolderContextMenu.js +103 -0
- package/components/routes/cases/detail/sidebar/CaseFolderContextMenu.test.d.ts +1 -0
- package/components/routes/cases/detail/sidebar/CaseFolderContextMenu.test.js +363 -0
- package/components/routes/cases/detail/sidebar/FolderEntry.d.ts +25 -0
- package/components/routes/cases/detail/sidebar/FolderEntry.js +88 -0
- package/components/routes/cases/detail/sidebar/FolderEntry.test.d.ts +1 -0
- package/components/routes/cases/detail/sidebar/FolderEntry.test.js +206 -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 +3 -0
- package/components/routes/cases/detail/sidebar/utils.js +29 -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/hooks/useCase.d.ts +13 -0
- package/components/routes/cases/hooks/useCase.js +69 -0
- package/components/routes/cases/hooks/useCase.test.d.ts +1 -0
- package/components/routes/cases/hooks/useCase.test.js +141 -0
- package/components/routes/cases/modals/AddToCaseModal.d.ts +7 -0
- package/components/routes/cases/modals/AddToCaseModal.js +59 -0
- package/components/routes/cases/modals/AddToCaseModal.test.d.ts +1 -0
- package/components/routes/cases/modals/AddToCaseModal.test.js +313 -0
- package/components/routes/cases/modals/CaseRecordRow.d.ts +9 -0
- package/components/routes/cases/modals/CaseRecordRow.js +15 -0
- package/components/routes/cases/modals/CreateCaseModal.d.ts +7 -0
- package/components/routes/cases/modals/CreateCaseModal.js +55 -0
- package/components/routes/cases/modals/CreateCaseModal.test.d.ts +1 -0
- package/components/routes/cases/modals/CreateCaseModal.test.js +358 -0
- package/components/routes/cases/modals/RenameItemModal.d.ts +9 -0
- package/components/routes/cases/modals/RenameItemModal.js +48 -0
- package/components/routes/cases/modals/ResolveModal.d.ts +7 -0
- package/components/routes/cases/modals/ResolveModal.js +116 -0
- package/components/routes/cases/modals/ResolveModal.test.d.ts +1 -0
- package/components/routes/cases/modals/ResolveModal.test.js +454 -0
- package/components/routes/cases/modals/hooks.d.ts +7 -0
- package/components/routes/cases/modals/hooks.js +44 -0
- package/components/routes/cases/modals/types.d.ts +5 -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/dossiers/DossierEditor.js +2 -2
- package/components/routes/dossiers/DossierEditor.test.js +1 -1
- package/components/routes/dossiers/Dossiers.js +25 -19
- package/components/routes/help/ActionIntroductionDocumentation.js +1 -1
- package/components/routes/help/ApiDocumentation.js +1 -1
- package/components/routes/help/HitBannerDocumentation.js +1 -0
- package/components/routes/help/HitDocumentation.js +1 -3
- package/components/routes/help/markdown/en/client.md.js +1 -1
- package/components/routes/help/markdown/en/retention.md.js +1 -1
- package/components/routes/help/markdown/fr/client.md.js +1 -1
- package/components/routes/help/markdown/fr/retention.md.js +1 -1
- package/components/routes/hits/search/InformationPane.d.ts +1 -0
- package/components/routes/hits/search/InformationPane.js +50 -63
- package/components/routes/hits/search/LayoutSettings.js +3 -3
- package/components/routes/hits/search/QuerySettings.js +2 -1
- package/components/routes/hits/search/QuerySettings.test.js +14 -9
- package/components/routes/hits/search/{HitBrowser.js → RecordBrowser.js} +9 -9
- 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 +26 -49
- package/components/routes/hits/search/ViewLink.js +3 -3
- package/components/routes/hits/search/ViewLink.test.js +8 -8
- package/components/routes/hits/search/grid/AddColumnModal.js +5 -4
- package/components/routes/hits/search/grid/EnhancedCell.d.ts +2 -1
- package/components/routes/hits/search/grid/EnhancedCell.js +2 -2
- package/components/routes/hits/search/grid/HitGrid.js +20 -18
- package/components/routes/hits/search/grid/{HitRow.d.ts → RecordRow.d.ts} +3 -2
- package/components/routes/hits/search/grid/{HitRow.js → RecordRow.js} +10 -8
- package/components/routes/hits/search/shared/CustomSpan.js +7 -7
- package/components/routes/hits/search/shared/CustomSpan.test.d.ts +1 -0
- package/components/routes/hits/search/shared/CustomSpan.test.js +170 -0
- package/components/routes/hits/search/shared/IndexPicker.d.ts +2 -0
- package/components/routes/hits/search/shared/IndexPicker.js +20 -0
- package/components/routes/hits/view/HitViewer.js +12 -13
- package/components/routes/home/AddNewCard.js +1 -1
- package/components/routes/home/AddNewCard.test.d.ts +1 -0
- package/components/routes/home/AddNewCard.test.js +86 -0
- package/components/routes/home/ViewCard.js +47 -41
- package/components/routes/home/ViewRefresh.test.d.ts +1 -0
- package/components/routes/home/ViewRefresh.test.js +79 -0
- package/components/routes/observables/ObservableViewer.d.ts +7 -0
- package/components/routes/observables/ObservableViewer.js +27 -0
- package/components/routes/overviews/OverviewCard.test.d.ts +1 -0
- package/components/routes/overviews/OverviewCard.test.js +108 -0
- package/components/routes/overviews/OverviewViewer.js +18 -10
- package/components/routes/overviews/Overviews.js +25 -19
- package/components/routes/overviews/template/en.md.js +1 -1
- package/components/routes/overviews/template/fr.md.js +1 -1
- package/components/routes/settings/LocalSection.js +2 -1
- package/components/routes/settings/SettingsSection.test.d.ts +1 -0
- package/components/routes/settings/SettingsSection.test.js +19 -0
- package/components/routes/templates/TemplateCard.d.ts +3 -1
- package/components/routes/templates/TemplateCard.js +8 -4
- package/components/routes/templates/TemplateCard.test.d.ts +1 -0
- package/components/routes/templates/TemplateCard.test.js +115 -0
- package/components/routes/templates/TemplateViewer.js +62 -16
- package/components/routes/templates/Templates.js +35 -13
- package/components/routes/views/ViewComposer.js +46 -19
- package/components/routes/views/Views.js +21 -14
- package/locales/en/translation.json +146 -8
- package/locales/fr/translation.json +144 -8
- package/models/WithMetadata.d.ts +2 -1
- package/models/entities/generated/ApiType.d.ts +1 -1
- package/models/entities/generated/AttachmentsFile.d.ts +12 -0
- package/models/entities/generated/Case.d.ts +28 -0
- package/models/entities/generated/DestinationOriginal.d.ts +19 -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/Hit.d.ts +2 -0
- package/models/entities/generated/Howler.d.ts +1 -5
- package/models/entities/generated/HttpResponse.d.ts +11 -0
- package/models/entities/generated/Item.d.ts +9 -0
- package/models/entities/generated/Observable.d.ts +85 -0
- package/models/entities/generated/ObservableCloud.d.ts +20 -0
- package/models/entities/generated/ObservableDestination.d.ts +23 -0
- package/models/entities/generated/ObservableEmail.d.ts +30 -0
- package/models/entities/generated/ObservableFile.d.ts +36 -0
- package/models/entities/generated/ObservableHowler.d.ts +42 -0
- package/models/entities/generated/ObservableHttp.d.ts +11 -0
- package/models/entities/generated/ObservableObserver.d.ts +21 -0
- package/models/entities/generated/ObservableOrganization.d.ts +7 -0
- package/models/entities/generated/ObservableProcess.d.ts +34 -0
- package/models/entities/generated/ObservableSource.d.ts +23 -0
- package/models/entities/generated/ObservableThreat.d.ts +21 -0
- package/models/entities/generated/ObservableTls.d.ts +12 -0
- package/models/entities/generated/ObserverIngress.d.ts +9 -0
- package/models/entities/generated/Rule.d.ts +6 -9
- 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/UserUser.d.ts +2 -0
- 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 +147 -132
- package/plugins/clue/components/ClueTypography.js +2 -2
- package/plugins/clue/utils.d.ts +2 -1
- package/rest/FetchClient.test.d.ts +1 -0
- package/rest/FetchClient.test.js +81 -0
- package/setupTests.js +5 -0
- package/tests/mocks.d.ts +11 -1
- package/tests/mocks.js +12 -7
- package/tests/server-handlers.js +6 -1
- package/tests/utils.d.ts +4 -0
- package/tests/utils.js +20 -0
- package/utils/Throttler.test.d.ts +1 -0
- package/utils/Throttler.test.js +135 -0
- package/utils/actionUtils.test.d.ts +1 -0
- package/utils/actionUtils.test.js +140 -0
- package/utils/constants.d.ts +5 -3
- package/utils/constants.js +7 -0
- package/utils/hitFunctions.d.ts +2 -1
- package/utils/hitFunctions.js +4 -4
- package/utils/hitFunctions.test.d.ts +1 -0
- package/utils/hitFunctions.test.js +52 -0
- package/utils/localStorage.test.d.ts +1 -0
- package/utils/localStorage.test.js +96 -0
- package/utils/menuUtils.js +1 -1
- package/utils/menuUtils.test.d.ts +1 -0
- package/utils/menuUtils.test.js +198 -0
- package/utils/sessionStorage.test.d.ts +1 -0
- package/utils/sessionStorage.test.js +81 -0
- package/utils/socketUtils.d.ts +14 -0
- package/utils/socketUtils.js +17 -1
- package/utils/socketUtils.test.d.ts +1 -0
- package/utils/socketUtils.test.js +59 -0
- package/utils/stringUtils.test.d.ts +1 -0
- package/utils/stringUtils.test.js +159 -0
- package/utils/typeUtils.d.ts +7 -0
- package/utils/typeUtils.js +27 -0
- package/utils/utils.test.d.ts +1 -0
- package/utils/utils.test.js +292 -0
- package/utils/viewUtils.js +3 -0
- package/utils/viewUtils.test.d.ts +1 -0
- package/utils/viewUtils.test.js +45 -0
- package/utils/xsrf.test.d.ts +1 -0
- package/utils/xsrf.test.js +41 -0
- 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/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 -229
- /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/RecordSearchProvider.test.d.ts} +0 -0
- /package/components/{routes/overviews/OverviewEditor.d.ts → elements/MarkdownEditor.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/tests/utils.js
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
// Mock data factories
|
|
2
2
|
export const createMockHit = (overrides) => ({
|
|
3
|
+
...overrides,
|
|
4
|
+
__index: 'hit',
|
|
3
5
|
howler: {
|
|
4
6
|
id: 'test-hit-1',
|
|
5
7
|
analytic: 'test-analytic',
|
|
@@ -14,6 +16,17 @@ export const createMockHit = (overrides) => ({
|
|
|
14
16
|
...overrides?.event
|
|
15
17
|
}
|
|
16
18
|
});
|
|
19
|
+
export const createMockObservable = (overrides) => ({
|
|
20
|
+
...overrides,
|
|
21
|
+
__index: 'observable',
|
|
22
|
+
howler: {
|
|
23
|
+
id: 'test-observable-1',
|
|
24
|
+
analytic: 'test-analytic',
|
|
25
|
+
detection: 'Test Detection',
|
|
26
|
+
hash: '',
|
|
27
|
+
...overrides?.howler
|
|
28
|
+
}
|
|
29
|
+
});
|
|
17
30
|
export const createMockAnalytic = (overrides) => ({
|
|
18
31
|
analytic_id: 'test-analytic-id',
|
|
19
32
|
name: 'test-analytic',
|
|
@@ -52,6 +65,13 @@ export const createMockView = (overrides) => ({
|
|
|
52
65
|
},
|
|
53
66
|
...overrides
|
|
54
67
|
});
|
|
68
|
+
export const createMockCase = (overrides) => ({
|
|
69
|
+
case_id: 'test-case-id',
|
|
70
|
+
title: 'Test Case',
|
|
71
|
+
summary: 'Test case summary',
|
|
72
|
+
items: [],
|
|
73
|
+
...overrides
|
|
74
|
+
});
|
|
55
75
|
// Helper function to create mock dossiers
|
|
56
76
|
export const createMockDossier = (overrides) => ({
|
|
57
77
|
dossier_id: 'test-dossier-id',
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
/// <reference types="vitest" />
|
|
2
|
+
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
|
|
3
|
+
import Throttler from './Throttler';
|
|
4
|
+
describe('Throttler', () => {
|
|
5
|
+
beforeEach(() => {
|
|
6
|
+
vi.useFakeTimers();
|
|
7
|
+
});
|
|
8
|
+
afterEach(() => {
|
|
9
|
+
vi.useRealTimers();
|
|
10
|
+
});
|
|
11
|
+
// -------------------------------------------------------------------------
|
|
12
|
+
// throttle
|
|
13
|
+
// -------------------------------------------------------------------------
|
|
14
|
+
describe('throttle', () => {
|
|
15
|
+
it('calls fn immediately on the first invocation', () => {
|
|
16
|
+
const fn = vi.fn();
|
|
17
|
+
const t = new Throttler(100);
|
|
18
|
+
t.throttle(fn);
|
|
19
|
+
expect(fn).toHaveBeenCalledTimes(1);
|
|
20
|
+
});
|
|
21
|
+
it('suppresses subsequent calls within the throttle window', () => {
|
|
22
|
+
const fn = vi.fn();
|
|
23
|
+
const t = new Throttler(100);
|
|
24
|
+
t.throttle(fn);
|
|
25
|
+
t.throttle(fn);
|
|
26
|
+
t.throttle(fn);
|
|
27
|
+
expect(fn).toHaveBeenCalledTimes(1);
|
|
28
|
+
});
|
|
29
|
+
it('allows another call after the throttle interval expires', () => {
|
|
30
|
+
const fn = vi.fn();
|
|
31
|
+
const t = new Throttler(100);
|
|
32
|
+
t.throttle(fn);
|
|
33
|
+
vi.advanceTimersByTime(150);
|
|
34
|
+
t.throttle(fn);
|
|
35
|
+
expect(fn).toHaveBeenCalledTimes(2);
|
|
36
|
+
});
|
|
37
|
+
it('does not fire a second call if the interval has not yet elapsed', () => {
|
|
38
|
+
const fn = vi.fn();
|
|
39
|
+
const t = new Throttler(200);
|
|
40
|
+
t.throttle(fn);
|
|
41
|
+
vi.advanceTimersByTime(100);
|
|
42
|
+
t.throttle(fn);
|
|
43
|
+
expect(fn).toHaveBeenCalledTimes(1);
|
|
44
|
+
});
|
|
45
|
+
});
|
|
46
|
+
// -------------------------------------------------------------------------
|
|
47
|
+
// debounce
|
|
48
|
+
// -------------------------------------------------------------------------
|
|
49
|
+
describe('debounce', () => {
|
|
50
|
+
it('does not call fn immediately', () => {
|
|
51
|
+
const fn = vi.fn();
|
|
52
|
+
const t = new Throttler(100);
|
|
53
|
+
t.debounce(fn);
|
|
54
|
+
expect(fn).not.toHaveBeenCalled();
|
|
55
|
+
});
|
|
56
|
+
it('calls fn after the delay elapses', () => {
|
|
57
|
+
const fn = vi.fn();
|
|
58
|
+
const t = new Throttler(100);
|
|
59
|
+
t.debounce(fn);
|
|
60
|
+
vi.advanceTimersByTime(100);
|
|
61
|
+
expect(fn).toHaveBeenCalledTimes(1);
|
|
62
|
+
});
|
|
63
|
+
it('resets the delay when called again before it fires', () => {
|
|
64
|
+
const fn = vi.fn();
|
|
65
|
+
const t = new Throttler(100);
|
|
66
|
+
t.debounce(fn);
|
|
67
|
+
vi.advanceTimersByTime(80);
|
|
68
|
+
t.debounce(fn);
|
|
69
|
+
vi.advanceTimersByTime(80);
|
|
70
|
+
expect(fn).not.toHaveBeenCalled();
|
|
71
|
+
vi.advanceTimersByTime(30);
|
|
72
|
+
expect(fn).toHaveBeenCalledTimes(1);
|
|
73
|
+
});
|
|
74
|
+
it('calls fn only once after many rapid invocations', () => {
|
|
75
|
+
const fn = vi.fn();
|
|
76
|
+
const t = new Throttler(100);
|
|
77
|
+
for (let i = 0; i < 10; i++) {
|
|
78
|
+
t.debounce(fn);
|
|
79
|
+
}
|
|
80
|
+
vi.advanceTimersByTime(200);
|
|
81
|
+
expect(fn).toHaveBeenCalledTimes(1);
|
|
82
|
+
});
|
|
83
|
+
it('fires a second call correctly after the first has resolved', () => {
|
|
84
|
+
const fn = vi.fn();
|
|
85
|
+
const t = new Throttler(100);
|
|
86
|
+
t.debounce(fn);
|
|
87
|
+
vi.advanceTimersByTime(150);
|
|
88
|
+
t.debounce(fn);
|
|
89
|
+
vi.advanceTimersByTime(150);
|
|
90
|
+
expect(fn).toHaveBeenCalledTimes(2);
|
|
91
|
+
});
|
|
92
|
+
});
|
|
93
|
+
// -------------------------------------------------------------------------
|
|
94
|
+
// delayAsync
|
|
95
|
+
// -------------------------------------------------------------------------
|
|
96
|
+
describe('delayAsync', () => {
|
|
97
|
+
it('does not invoke fn before the delay', async () => {
|
|
98
|
+
const fn = vi.fn().mockResolvedValue('x');
|
|
99
|
+
const t = new Throttler(100);
|
|
100
|
+
t.delayAsync(fn);
|
|
101
|
+
expect(fn).not.toHaveBeenCalled();
|
|
102
|
+
});
|
|
103
|
+
it('resolves with the return value of fn', async () => {
|
|
104
|
+
const fn = vi.fn().mockResolvedValue('result');
|
|
105
|
+
const t = new Throttler(100);
|
|
106
|
+
const promise = t.delayAsync(fn);
|
|
107
|
+
vi.advanceTimersByTime(100);
|
|
108
|
+
await expect(promise).resolves.toBe('result');
|
|
109
|
+
});
|
|
110
|
+
it('passes variadic arguments through to fn', async () => {
|
|
111
|
+
const fn = vi.fn().mockImplementation(async (a, b) => a + b);
|
|
112
|
+
const t = new Throttler(100);
|
|
113
|
+
const promise = t.delayAsync(fn, 3, 4);
|
|
114
|
+
vi.advanceTimersByTime(100);
|
|
115
|
+
await expect(promise).resolves.toBe(7);
|
|
116
|
+
});
|
|
117
|
+
it('rejects when fn throws', async () => {
|
|
118
|
+
const fn = vi.fn().mockRejectedValue(new Error('boom'));
|
|
119
|
+
const t = new Throttler(100);
|
|
120
|
+
const promise = t.delayAsync(fn);
|
|
121
|
+
vi.advanceTimersByTime(100);
|
|
122
|
+
await expect(promise).rejects.toThrow('boom');
|
|
123
|
+
});
|
|
124
|
+
it('cancels the previous pending call when invoked again', async () => {
|
|
125
|
+
const fn = vi.fn().mockResolvedValue(42);
|
|
126
|
+
const t = new Throttler(100);
|
|
127
|
+
t.delayAsync(fn);
|
|
128
|
+
vi.advanceTimersByTime(50);
|
|
129
|
+
const second = t.delayAsync(fn);
|
|
130
|
+
vi.advanceTimersByTime(100);
|
|
131
|
+
await expect(second).resolves.toBe(42);
|
|
132
|
+
expect(fn).toHaveBeenCalledTimes(1);
|
|
133
|
+
});
|
|
134
|
+
});
|
|
135
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
import { describe, expect, it } from 'vitest';
|
|
2
|
+
import { checkArgsAreFilled, getArgsByContext, getOptionsByContext, operationReady } from './actionUtils';
|
|
3
|
+
// ---------------------------------------------------------------------------
|
|
4
|
+
// Helpers
|
|
5
|
+
// ---------------------------------------------------------------------------
|
|
6
|
+
const makeStep = (args, options = {}) => ({
|
|
7
|
+
args,
|
|
8
|
+
options,
|
|
9
|
+
validation: {}
|
|
10
|
+
});
|
|
11
|
+
const makeAction = (steps) => ({
|
|
12
|
+
id: 'test-action',
|
|
13
|
+
title: 'Test Action',
|
|
14
|
+
i18nKey: 'test.action',
|
|
15
|
+
description: { short: '', long: '' },
|
|
16
|
+
roles: [],
|
|
17
|
+
steps,
|
|
18
|
+
triggers: []
|
|
19
|
+
});
|
|
20
|
+
// ---------------------------------------------------------------------------
|
|
21
|
+
// checkArgsAreFilled
|
|
22
|
+
// ---------------------------------------------------------------------------
|
|
23
|
+
describe('checkArgsAreFilled', () => {
|
|
24
|
+
it('returns false when values is empty/falsy', () => {
|
|
25
|
+
const step = makeStep({ status: [] });
|
|
26
|
+
expect(checkArgsAreFilled(step, '')).toBe(false);
|
|
27
|
+
});
|
|
28
|
+
it('returns true when all required args are present and truthy', () => {
|
|
29
|
+
const step = makeStep({ status: [] });
|
|
30
|
+
expect(checkArgsAreFilled(step, JSON.stringify({ status: 'open' }))).toBe(true);
|
|
31
|
+
});
|
|
32
|
+
it('returns false when a required arg is missing from values', () => {
|
|
33
|
+
const step = makeStep({ status: [], assignment: [] });
|
|
34
|
+
expect(checkArgsAreFilled(step, JSON.stringify({ status: 'open' }))).toBe(false);
|
|
35
|
+
});
|
|
36
|
+
it('returns false when a required arg is present but falsy (empty string)', () => {
|
|
37
|
+
const step = makeStep({ status: [] });
|
|
38
|
+
expect(checkArgsAreFilled(step, JSON.stringify({ status: '' }))).toBe(false);
|
|
39
|
+
});
|
|
40
|
+
it('returns true when there are no required args', () => {
|
|
41
|
+
const step = makeStep({});
|
|
42
|
+
expect(checkArgsAreFilled(step, JSON.stringify({}))).toBe(true);
|
|
43
|
+
});
|
|
44
|
+
});
|
|
45
|
+
// ---------------------------------------------------------------------------
|
|
46
|
+
// getOptionsByContext
|
|
47
|
+
// ---------------------------------------------------------------------------
|
|
48
|
+
describe('getOptionsByContext', () => {
|
|
49
|
+
it('returns an empty array when the arg is not in options', () => {
|
|
50
|
+
const options = {};
|
|
51
|
+
expect(getOptionsByContext(options, 'status', '{}')).toEqual([]);
|
|
52
|
+
});
|
|
53
|
+
it('returns the full list when the arg maps to a plain array', () => {
|
|
54
|
+
const options = { status: ['open', 'in-progress', 'resolved'] };
|
|
55
|
+
expect(getOptionsByContext(options, 'status', '{}')).toEqual(['open', 'in-progress', 'resolved']);
|
|
56
|
+
});
|
|
57
|
+
it('returns options matching the current context when arg has conditional options', () => {
|
|
58
|
+
const options = {
|
|
59
|
+
assessment: {
|
|
60
|
+
'status:open': ['false_positive', 'legitimate'],
|
|
61
|
+
'status:resolved': ['correct']
|
|
62
|
+
}
|
|
63
|
+
};
|
|
64
|
+
const context = JSON.stringify({ status: 'open' });
|
|
65
|
+
expect(getOptionsByContext(options, 'assessment', context)).toEqual(['false_positive', 'legitimate']);
|
|
66
|
+
});
|
|
67
|
+
it('returns an empty array when context does not match any conditional key', () => {
|
|
68
|
+
const options = {
|
|
69
|
+
assessment: {
|
|
70
|
+
'status:open': ['false_positive']
|
|
71
|
+
}
|
|
72
|
+
};
|
|
73
|
+
const context = JSON.stringify({ status: 'resolved' });
|
|
74
|
+
expect(getOptionsByContext(options, 'assessment', context)).toEqual([]);
|
|
75
|
+
});
|
|
76
|
+
});
|
|
77
|
+
// ---------------------------------------------------------------------------
|
|
78
|
+
// getArgsByContext
|
|
79
|
+
// ---------------------------------------------------------------------------
|
|
80
|
+
describe('getArgsByContext', () => {
|
|
81
|
+
it('always returns an arg with an empty conditions array', () => {
|
|
82
|
+
const args = { status: [] };
|
|
83
|
+
expect(getArgsByContext(args, '{}')).toContain('status');
|
|
84
|
+
});
|
|
85
|
+
it('includes an arg whose condition matches the current context', () => {
|
|
86
|
+
const args = { assessment: ['status:open'] };
|
|
87
|
+
const values = JSON.stringify({ status: 'open' });
|
|
88
|
+
expect(getArgsByContext(args, values)).toContain('assessment');
|
|
89
|
+
});
|
|
90
|
+
it('excludes an arg whose condition does not match the current context', () => {
|
|
91
|
+
const args = { assessment: ['status:open'] };
|
|
92
|
+
const values = JSON.stringify({ status: 'resolved' });
|
|
93
|
+
expect(getArgsByContext(args, values)).not.toContain('assessment');
|
|
94
|
+
});
|
|
95
|
+
it('includes an arg when any one of multiple conditions matches (OR logic)', () => {
|
|
96
|
+
const args = { rationale: ['status:open', 'status:in-progress'] };
|
|
97
|
+
const values = JSON.stringify({ status: 'in-progress' });
|
|
98
|
+
expect(getArgsByContext(args, values)).toContain('rationale');
|
|
99
|
+
});
|
|
100
|
+
it('returns an empty array when no args match', () => {
|
|
101
|
+
const args = { assessment: ['status:open'] };
|
|
102
|
+
const values = JSON.stringify({ status: 'resolved' });
|
|
103
|
+
expect(getArgsByContext(args, values)).toEqual([]);
|
|
104
|
+
});
|
|
105
|
+
});
|
|
106
|
+
// ---------------------------------------------------------------------------
|
|
107
|
+
// operationReady
|
|
108
|
+
// ---------------------------------------------------------------------------
|
|
109
|
+
describe('operationReady', () => {
|
|
110
|
+
it('returns false when data is null/falsy', () => {
|
|
111
|
+
const action = makeAction([makeStep({ status: [] })]);
|
|
112
|
+
expect(operationReady(null, action)).toBe(false);
|
|
113
|
+
});
|
|
114
|
+
it('returns falsy when action is falsy', () => {
|
|
115
|
+
expect(operationReady(JSON.stringify({ status: 'open' }), null)).toBeFalsy();
|
|
116
|
+
});
|
|
117
|
+
it('returns true when all unconditional args are present', () => {
|
|
118
|
+
const action = makeAction([makeStep({ status: [] })]);
|
|
119
|
+
const data = JSON.stringify({ status: 'open' });
|
|
120
|
+
expect(operationReady(data, action)).toBe(true);
|
|
121
|
+
});
|
|
122
|
+
it('returns false when a required unconditional arg is missing', () => {
|
|
123
|
+
const action = makeAction([makeStep({ status: [], assessment: [] })]);
|
|
124
|
+
const data = JSON.stringify({ status: 'open' });
|
|
125
|
+
expect(operationReady(data, action)).toBe(false);
|
|
126
|
+
});
|
|
127
|
+
it('ignores conditional args that do not apply in the current context', () => {
|
|
128
|
+
// assessment only required when status=open; here status=resolved so assessment is not required
|
|
129
|
+
const action = makeAction([makeStep({ status: [], assessment: ['status:open'] })]);
|
|
130
|
+
const data = JSON.stringify({ status: 'resolved' });
|
|
131
|
+
expect(operationReady(data, action)).toBe(true);
|
|
132
|
+
});
|
|
133
|
+
it('merges args across multiple steps', () => {
|
|
134
|
+
const step1 = makeStep({ status: [] });
|
|
135
|
+
const step2 = makeStep({ assignment: [] });
|
|
136
|
+
const action = makeAction([step1, step2]);
|
|
137
|
+
const data = JSON.stringify({ status: 'open', assignment: 'alice' });
|
|
138
|
+
expect(operationReady(data, action)).toBe(true);
|
|
139
|
+
});
|
|
140
|
+
});
|
package/utils/constants.d.ts
CHANGED
|
@@ -5,9 +5,9 @@ export declare const VERSION: any;
|
|
|
5
5
|
export declare const MY_LOCAL_STORAGE_PREFIX = "howler.ui";
|
|
6
6
|
export declare const MY_SESSION_STORAGE_PREFIX = "howler.ui.cache";
|
|
7
7
|
export declare const ESCALATION_COLORS: {
|
|
8
|
-
alert:
|
|
9
|
-
evidence:
|
|
10
|
-
hit:
|
|
8
|
+
alert: "warning";
|
|
9
|
+
evidence: "error";
|
|
10
|
+
hit: "primary";
|
|
11
11
|
};
|
|
12
12
|
export declare const STATUS_COLORS: {
|
|
13
13
|
open: string;
|
|
@@ -49,6 +49,7 @@ export declare enum StorageKey {
|
|
|
49
49
|
COMPACT_JSON = "compact_json_view",
|
|
50
50
|
FLATTEN_JSON = "flatten_json_view",
|
|
51
51
|
FORCE_DRAWER = "force_drawer",
|
|
52
|
+
SHOW_HIT_SUMMARY_GRAPH = "show_hit_summary_graph",
|
|
52
53
|
LAST_VIEW = "last_view",
|
|
53
54
|
ONLY_RULES = "only_rules",
|
|
54
55
|
PAGE_COUNT = "page_count",
|
|
@@ -74,6 +75,7 @@ export declare const RULE_INTERVALS: {
|
|
|
74
75
|
crontab: string;
|
|
75
76
|
}[];
|
|
76
77
|
export declare const DATE_RANGES: string[];
|
|
78
|
+
export declare const DATE_RANGE_LUCENE: Partial<Record<(typeof DATE_RANGES)[number], string>>;
|
|
77
79
|
interface LabelData {
|
|
78
80
|
icon?: ReactElement;
|
|
79
81
|
color?: string;
|
package/utils/constants.js
CHANGED
|
@@ -54,6 +54,7 @@ export var StorageKey;
|
|
|
54
54
|
StorageKey["COMPACT_JSON"] = "compact_json_view";
|
|
55
55
|
StorageKey["FLATTEN_JSON"] = "flatten_json_view";
|
|
56
56
|
StorageKey["FORCE_DRAWER"] = "force_drawer";
|
|
57
|
+
StorageKey["SHOW_HIT_SUMMARY_GRAPH"] = "show_hit_summary_graph";
|
|
57
58
|
StorageKey["LAST_VIEW"] = "last_view";
|
|
58
59
|
StorageKey["ONLY_RULES"] = "only_rules";
|
|
59
60
|
StorageKey["PAGE_COUNT"] = "page_count";
|
|
@@ -104,6 +105,12 @@ export const DATE_RANGES = [
|
|
|
104
105
|
'date.range.all',
|
|
105
106
|
'date.range.custom'
|
|
106
107
|
];
|
|
108
|
+
export const DATE_RANGE_LUCENE = {
|
|
109
|
+
'date.range.1.day': 'now-1d/d',
|
|
110
|
+
'date.range.3.day': 'now-3d/d',
|
|
111
|
+
'date.range.1.week': 'now-7d/d',
|
|
112
|
+
'date.range.1.month': 'now-1M/M'
|
|
113
|
+
};
|
|
107
114
|
export const LABEL_TYPES = {
|
|
108
115
|
insight: { icon: _jsx(PsychologyAlt, { fontSize: "small" }), color: '#FFFFFF' }, //brain icon
|
|
109
116
|
mitigation: { icon: _jsx(LocalPolice, { fontSize: "small" }), color: blue[600] }, //police badge
|
package/utils/hitFunctions.d.ts
CHANGED
|
@@ -1,2 +1,3 @@
|
|
|
1
1
|
import type { Hit } from '@cccsaurora/howler-ui/models/entities/generated/Hit';
|
|
2
|
-
|
|
2
|
+
import type { Observable } from '@cccsaurora/howler-ui/models/entities/generated/Observable';
|
|
3
|
+
export declare const getUserList: (record: Hit | Observable) => Set<string>;
|
package/utils/hitFunctions.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
export const getUserList = (
|
|
1
|
+
export const getUserList = (record) => {
|
|
2
2
|
const ids = new Set();
|
|
3
|
-
if (
|
|
4
|
-
|
|
5
|
-
|
|
3
|
+
if (record) {
|
|
4
|
+
record.howler?.log?.forEach(l => ids.add(l.user));
|
|
5
|
+
record.howler?.comment?.forEach(c => ids.add(c.user), ids);
|
|
6
6
|
}
|
|
7
7
|
return ids;
|
|
8
8
|
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { describe, expect, it } from 'vitest';
|
|
2
|
+
import { getUserList } from './hitFunctions';
|
|
3
|
+
const makeHit = (howlerOverrides = {}) => ({
|
|
4
|
+
howler: {
|
|
5
|
+
log: [],
|
|
6
|
+
comment: [],
|
|
7
|
+
...howlerOverrides
|
|
8
|
+
}
|
|
9
|
+
});
|
|
10
|
+
describe('getUserList', () => {
|
|
11
|
+
it('returns an empty Set when the hit is null', () => {
|
|
12
|
+
expect(getUserList(null)).toEqual(new Set());
|
|
13
|
+
});
|
|
14
|
+
it('returns an empty Set when the hit is undefined', () => {
|
|
15
|
+
expect(getUserList(undefined)).toEqual(new Set());
|
|
16
|
+
});
|
|
17
|
+
it('returns an empty Set when both log and comment are empty', () => {
|
|
18
|
+
expect(getUserList(makeHit())).toEqual(new Set());
|
|
19
|
+
});
|
|
20
|
+
it('collects users from the log array', () => {
|
|
21
|
+
const hit = makeHit({ log: [{ user: 'alice' }, { user: 'bob' }] });
|
|
22
|
+
expect(getUserList(hit)).toEqual(new Set(['alice', 'bob']));
|
|
23
|
+
});
|
|
24
|
+
it('collects users from the comment array', () => {
|
|
25
|
+
const hit = makeHit({ comment: [{ user: 'carol' }] });
|
|
26
|
+
expect(getUserList(hit)).toEqual(new Set(['carol']));
|
|
27
|
+
});
|
|
28
|
+
it('collects users from both log and comment', () => {
|
|
29
|
+
const hit = makeHit({
|
|
30
|
+
log: [{ user: 'alice' }],
|
|
31
|
+
comment: [{ user: 'bob' }]
|
|
32
|
+
});
|
|
33
|
+
expect(getUserList(hit)).toEqual(new Set(['alice', 'bob']));
|
|
34
|
+
});
|
|
35
|
+
it('deduplicates users that appear in both arrays', () => {
|
|
36
|
+
const hit = makeHit({
|
|
37
|
+
log: [{ user: 'alice' }],
|
|
38
|
+
comment: [{ user: 'alice' }]
|
|
39
|
+
});
|
|
40
|
+
const result = getUserList(hit);
|
|
41
|
+
expect(result).toEqual(new Set(['alice']));
|
|
42
|
+
expect(result.size).toBe(1);
|
|
43
|
+
});
|
|
44
|
+
it('deduplicates users that appear multiple times in the same array', () => {
|
|
45
|
+
const hit = makeHit({ log: [{ user: 'alice' }, { user: 'alice' }] });
|
|
46
|
+
expect(getUserList(hit).size).toBe(1);
|
|
47
|
+
});
|
|
48
|
+
it('handles a hit with no howler field gracefully', () => {
|
|
49
|
+
const hit = {};
|
|
50
|
+
expect(getUserList(hit)).toEqual(new Set());
|
|
51
|
+
});
|
|
52
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
/// <reference types="vitest" />
|
|
2
|
+
import { afterEach, describe, expect, it } from 'vitest';
|
|
3
|
+
import { StorageKey } from './constants';
|
|
4
|
+
import { getStored, removeStored, saveLoginCredential, setStored } from './localStorage';
|
|
5
|
+
const PREFIX = 'howler.ui';
|
|
6
|
+
describe('localStorage utilities', () => {
|
|
7
|
+
afterEach(() => {
|
|
8
|
+
localStorage.clear();
|
|
9
|
+
});
|
|
10
|
+
// -------------------------------------------------------------------------
|
|
11
|
+
// setStored / getStored
|
|
12
|
+
// -------------------------------------------------------------------------
|
|
13
|
+
describe('setStored / getStored', () => {
|
|
14
|
+
it('stores and retrieves a string value', () => {
|
|
15
|
+
setStored(StorageKey.USERNAME, 'alice');
|
|
16
|
+
expect(getStored(StorageKey.USERNAME)).toBe('alice');
|
|
17
|
+
});
|
|
18
|
+
it('stores and retrieves an object value', () => {
|
|
19
|
+
const value = { token: 'abc', expires: 123 };
|
|
20
|
+
setStored(StorageKey.APP_TOKEN, value);
|
|
21
|
+
expect(getStored(StorageKey.APP_TOKEN)).toEqual(value);
|
|
22
|
+
});
|
|
23
|
+
it('uses the prefixed key in the underlying localStorage', () => {
|
|
24
|
+
setStored(StorageKey.USERNAME, 'bob');
|
|
25
|
+
expect(localStorage.getItem(`${PREFIX}.${StorageKey.USERNAME}`)).toBe(JSON.stringify('bob'));
|
|
26
|
+
});
|
|
27
|
+
it('returns null for a key that has not been set', () => {
|
|
28
|
+
expect(getStored(StorageKey.USERNAME)).toBeNull();
|
|
29
|
+
});
|
|
30
|
+
it('overwrites an existing value', () => {
|
|
31
|
+
setStored(StorageKey.USERNAME, 'alice');
|
|
32
|
+
setStored(StorageKey.USERNAME, 'bob');
|
|
33
|
+
expect(getStored(StorageKey.USERNAME)).toBe('bob');
|
|
34
|
+
});
|
|
35
|
+
it('stores a number value', () => {
|
|
36
|
+
setStored(StorageKey.PAGE_COUNT, 25);
|
|
37
|
+
expect(getStored(StorageKey.PAGE_COUNT)).toBe(25);
|
|
38
|
+
});
|
|
39
|
+
});
|
|
40
|
+
// -------------------------------------------------------------------------
|
|
41
|
+
// removeStored
|
|
42
|
+
// -------------------------------------------------------------------------
|
|
43
|
+
describe('removeStored', () => {
|
|
44
|
+
it('removes an existing key so it returns null on subsequent reads', () => {
|
|
45
|
+
setStored(StorageKey.USERNAME, 'alice');
|
|
46
|
+
removeStored(StorageKey.USERNAME);
|
|
47
|
+
expect(getStored(StorageKey.USERNAME)).toBeNull();
|
|
48
|
+
});
|
|
49
|
+
it('does not throw when removing a key that was never stored', () => {
|
|
50
|
+
expect(() => removeStored(StorageKey.USERNAME)).not.toThrow();
|
|
51
|
+
});
|
|
52
|
+
it('removes only the targeted key and leaves others intact', () => {
|
|
53
|
+
setStored(StorageKey.USERNAME, 'alice');
|
|
54
|
+
setStored(StorageKey.PROVIDER, 'howler');
|
|
55
|
+
removeStored(StorageKey.USERNAME);
|
|
56
|
+
expect(getStored(StorageKey.USERNAME)).toBeNull();
|
|
57
|
+
expect(getStored(StorageKey.PROVIDER)).toBe('howler');
|
|
58
|
+
});
|
|
59
|
+
});
|
|
60
|
+
// -------------------------------------------------------------------------
|
|
61
|
+
// saveLoginCredential
|
|
62
|
+
// -------------------------------------------------------------------------
|
|
63
|
+
describe('saveLoginCredential', () => {
|
|
64
|
+
it('returns true and stores app_token when app_token is present', () => {
|
|
65
|
+
const result = saveLoginCredential({ app_token: 'tok123' });
|
|
66
|
+
expect(result).toBe(true);
|
|
67
|
+
expect(getStored(StorageKey.APP_TOKEN)).toBe('tok123');
|
|
68
|
+
});
|
|
69
|
+
it('also stores refresh_token and provider when they are present', () => {
|
|
70
|
+
saveLoginCredential({ app_token: 'tok', refresh_token: 'ref', provider: 'howler' });
|
|
71
|
+
expect(getStored(StorageKey.REFRESH_TOKEN)).toBe('ref');
|
|
72
|
+
expect(getStored(StorageKey.PROVIDER)).toBe('howler');
|
|
73
|
+
});
|
|
74
|
+
it('does not store refresh_token when it is absent', () => {
|
|
75
|
+
saveLoginCredential({ app_token: 'tok' });
|
|
76
|
+
expect(getStored(StorageKey.REFRESH_TOKEN)).toBeNull();
|
|
77
|
+
});
|
|
78
|
+
it('returns false and clears stored tokens when app_token is absent', () => {
|
|
79
|
+
setStored(StorageKey.APP_TOKEN, 'old-token');
|
|
80
|
+
setStored(StorageKey.REFRESH_TOKEN, 'old-refresh');
|
|
81
|
+
const result = saveLoginCredential({});
|
|
82
|
+
expect(result).toBe(false);
|
|
83
|
+
expect(getStored(StorageKey.APP_TOKEN)).toBeNull();
|
|
84
|
+
expect(getStored(StorageKey.REFRESH_TOKEN)).toBeNull();
|
|
85
|
+
});
|
|
86
|
+
it('clears APP_TOKEN, REFRESH_TOKEN, and PROVIDER on empty credential', () => {
|
|
87
|
+
setStored(StorageKey.APP_TOKEN, 't');
|
|
88
|
+
setStored(StorageKey.REFRESH_TOKEN, 'r');
|
|
89
|
+
setStored(StorageKey.PROVIDER, 'p');
|
|
90
|
+
saveLoginCredential({});
|
|
91
|
+
expect(getStored(StorageKey.APP_TOKEN)).toBeNull();
|
|
92
|
+
expect(getStored(StorageKey.REFRESH_TOKEN)).toBeNull();
|
|
93
|
+
expect(getStored(StorageKey.PROVIDER)).toBeNull();
|
|
94
|
+
});
|
|
95
|
+
});
|
|
96
|
+
});
|
package/utils/menuUtils.js
CHANGED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|