@cccsaurora/howler-ui 2.19.0-cases.863 → 2.19.0-dev.1000
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/api/index.d.ts +0 -4
- package/api/index.js +2 -10
- package/api/search/facet/hit.d.ts +3 -1
- package/api/search/facet/index.d.ts +1 -3
- package/api/search/index.d.ts +1 -2
- package/api/search/index.js +1 -2
- package/commons/components/leftnav/LeftNavDrawer.js +1 -1
- package/components/app/App.d.ts +1 -0
- package/components/app/App.js +20 -42
- package/components/app/hooks/useMatchers.d.ts +1 -1
- package/components/app/hooks/useMatchers.js +11 -23
- 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/HitProvider.d.ts +22 -0
- package/components/app/providers/{RecordProvider.js → HitProvider.js} +42 -42
- package/components/app/providers/{RecordSearchProvider.d.ts → HitSearchProvider.d.ts} +6 -6
- package/components/app/providers/{RecordSearchProvider.js → HitSearchProvider.js} +17 -12
- package/components/app/providers/{RecordSearchProvider.test.js → HitSearchProvider.test.js} +71 -52
- package/components/app/providers/ModalProvider.d.ts +1 -1
- package/components/app/providers/ModalProvider.js +5 -1
- package/components/app/providers/ParameterProvider.d.ts +2 -9
- package/components/app/providers/ParameterProvider.js +240 -165
- package/components/app/providers/ParameterProvider.test.js +94 -346
- package/components/app/providers/SocketProvider.d.ts +2 -11
- package/components/app/providers/SocketProvider.js +5 -18
- package/components/app/providers/UserListProvider.js +8 -28
- package/components/elements/PluginTypography.d.ts +1 -2
- package/components/elements/PluginTypography.js +2 -3
- package/components/elements/UserList.d.ts +2 -5
- package/components/elements/UserList.js +8 -18
- package/components/elements/addons/buttons/CustomButton.test.js +106 -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.test.js +80 -0
- package/components/elements/addons/search/SearchTotal.test.js +45 -0
- package/components/elements/addons/search/phrase/Phrase.js +1 -1
- package/components/elements/display/ChipPopper.d.ts +1 -1
- package/components/elements/display/ChipPopper.js +5 -5
- package/components/elements/display/DocumentationButton.test.js +84 -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.js +55 -0
- package/components/elements/display/Image.test.js +79 -0
- package/components/elements/display/Markdown.js +9 -2
- package/components/elements/display/Modal.js +0 -2
- package/components/elements/display/QueryResultText.test.js +48 -0
- package/components/elements/display/TextDivider.test.js +43 -0
- package/components/elements/display/TypingIndicator.test.js +33 -0
- package/components/elements/display/icons/BundleButton.d.ts +6 -0
- package/components/elements/display/icons/BundleButton.js +32 -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 +0 -1
- package/components/elements/hit/HitBanner.js +49 -31
- package/components/elements/hit/HitCard.d.ts +0 -2
- package/components/elements/hit/HitCard.js +7 -7
- package/components/elements/{record/RecordComments.d.ts → hit/HitComments.d.ts} +4 -5
- package/components/elements/{record/RecordComments.js → hit/HitComments.js} +28 -29
- package/components/elements/{ObjectDetails.js → hit/HitDetails.js} +17 -17
- package/components/elements/hit/HitLabels.js +2 -2
- package/components/elements/hit/HitOutline.d.ts +0 -1
- package/components/elements/hit/HitOutline.js +3 -3
- package/components/elements/hit/{HitPreview.d.ts → HitQuickSearch.d.ts} +3 -3
- package/components/elements/hit/{HitPreview.js → HitQuickSearch.js} +4 -10
- package/components/elements/hit/HitRelated.d.ts +6 -0
- package/components/elements/hit/HitRelated.js +7 -0
- package/components/elements/hit/HitSummary.d.ts +1 -2
- package/components/elements/hit/HitSummary.js +8 -8
- package/components/elements/{record/RecordWorklog.d.ts → hit/HitWorklog.d.ts} +3 -4
- package/components/elements/{record/RecordWorklog.js → hit/HitWorklog.js} +13 -15
- package/components/elements/hit/aggregate/HitGraph.js +8 -8
- package/components/elements/hit/elements/{Assigned.d.ts → HitUsers.d.ts} +5 -2
- package/components/elements/hit/elements/HitUsers.js +33 -0
- package/components/elements/hit/outlines/DefaultOutline.js +1 -1
- package/components/elements/view/ViewTitle.d.ts +0 -1
- package/components/elements/view/ViewTitle.js +2 -9
- package/components/hooks/useHitActions.d.ts +1 -1
- package/components/hooks/useHitActions.js +4 -4
- package/components/hooks/{useRecordSelection.d.ts → useHitSelection.d.ts} +2 -2
- package/components/hooks/{useRecordSelection.js → useHitSelection.js} +33 -12
- package/components/hooks/useMyPreferences.js +3 -11
- package/components/hooks/useMySearch.js +2 -2
- package/components/hooks/useMySitemap.js +1 -4
- package/components/hooks/useMyTheme.js +2 -9
- package/components/routes/403.test.js +27 -0
- package/components/routes/404.test.js +26 -0
- package/components/routes/ErrorBoundary.test.js +43 -0
- package/components/routes/ErrorOccured.test.js +35 -0
- package/components/routes/Logout.test.js +59 -0
- package/components/routes/action/edit/ActionEditor.js +2 -2
- package/components/routes/action/view/ActionDetails.js +4 -2
- package/components/routes/action/view/ActionSearch.js +12 -7
- 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 +1 -1
- package/components/routes/dossiers/DossierEditor.js +2 -2
- package/components/routes/dossiers/DossierEditor.test.js +1 -1
- package/components/routes/dossiers/Dossiers.js +15 -11
- package/components/routes/help/ApiDocumentation.js +1 -1
- package/components/routes/help/BundleDocumentation.d.ts +3 -0
- package/components/routes/help/BundleDocumentation.js +12 -0
- package/components/routes/help/HitBannerDocumentation.js +0 -1
- package/components/routes/help/HitDocumentation.js +3 -1
- package/components/routes/help/markdown/en/bundles.md.js +1 -0
- package/components/routes/help/markdown/en/client.md.js +1 -1
- package/components/routes/help/markdown/fr/bundles.md.js +1 -0
- package/components/routes/help/markdown/fr/client.md.js +1 -1
- package/components/routes/hits/search/BundleParentMenu.d.ts +6 -0
- package/components/routes/hits/search/BundleParentMenu.js +32 -0
- package/components/routes/hits/search/BundleScroller.d.ts +2 -0
- package/components/routes/hits/search/BundleScroller.js +6 -0
- package/components/routes/hits/search/{RecordBrowser.js → HitBrowser.js} +9 -9
- package/components/{elements/record/RecordContextMenu.d.ts → routes/hits/search/HitContextMenu.d.ts} +3 -3
- package/components/routes/hits/search/HitContextMenu.js +239 -0
- package/components/{elements/record/RecordContextMenu.test.js → routes/hits/search/HitContextMenu.test.js} +43 -98
- package/components/routes/hits/search/{RecordQuery.d.ts → HitQuery.d.ts} +2 -2
- package/components/routes/hits/search/{RecordQuery.js → HitQuery.js} +6 -6
- package/components/routes/hits/search/InformationPane.d.ts +0 -1
- package/components/routes/hits/search/InformationPane.js +63 -50
- package/components/routes/hits/search/LayoutSettings.js +3 -3
- package/components/routes/hits/search/QuerySettings.js +1 -2
- package/components/routes/hits/search/QuerySettings.test.js +9 -14
- package/components/routes/hits/search/SearchPane.js +49 -26
- 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 +4 -5
- package/components/routes/hits/search/grid/EnhancedCell.d.ts +1 -2
- package/components/routes/hits/search/grid/EnhancedCell.js +2 -2
- package/components/routes/hits/search/grid/HitGrid.js +18 -20
- package/components/routes/hits/search/grid/{RecordRow.d.ts → HitRow.d.ts} +2 -3
- package/components/routes/hits/search/grid/{RecordRow.js → HitRow.js} +9 -11
- package/components/routes/hits/search/shared/CustomSpan.js +7 -7
- package/components/routes/hits/search/shared/CustomSpan.test.js +170 -0
- package/components/routes/hits/view/HitViewer.js +13 -12
- package/components/routes/home/AddNewCard.test.js +68 -0
- package/components/routes/home/ViewCard.js +41 -47
- package/components/routes/home/ViewRefresh.test.js +79 -0
- package/components/routes/overviews/OverviewCard.test.js +108 -0
- package/components/{elements/MarkdownEditor.js → routes/overviews/OverviewEditor.js} +3 -3
- package/components/routes/overviews/OverviewViewer.js +14 -10
- package/components/routes/overviews/Overviews.js +15 -11
- package/components/routes/settings/LocalSection.js +2 -1
- 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 +57 -16
- package/components/routes/templates/Templates.js +23 -6
- package/components/routes/views/ViewComposer.js +19 -46
- package/components/routes/views/Views.js +8 -4
- package/locales/en/translation.json +17 -117
- package/locales/fr/translation.json +19 -119
- package/models/WithMetadata.d.ts +1 -2
- package/models/entities/generated/{ThreatEnrichment.d.ts → Enrichment.d.ts} +1 -1
- package/models/entities/generated/Hit.d.ts +1 -1
- package/models/entities/generated/Howler.d.ts +6 -0
- package/models/entities/generated/Rule.d.ts +9 -6
- package/models/entities/generated/Threat.d.ts +2 -2
- package/models/entities/generated/UserUser.d.ts +2 -0
- package/models/entities/generated/View.d.ts +0 -1
- package/package.json +112 -132
- package/plugins/clue/components/ClueTypography.js +2 -2
- package/plugins/clue/utils.d.ts +1 -2
- 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 +1 -11
- package/tests/mocks.js +7 -12
- package/tests/server-handlers.js +1 -6
- package/tests/utils.d.ts +0 -4
- package/tests/utils.js +0 -20
- 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 +4 -4
- package/utils/constants.js +1 -6
- package/utils/hitFunctions.d.ts +1 -2
- 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.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 +0 -14
- package/utils/socketUtils.js +1 -17
- package/utils/socketUtils.test.js +16 -49
- package/utils/stringUtils.test.d.ts +1 -0
- package/utils/stringUtils.test.js +159 -0
- package/utils/utils.test.d.ts +1 -0
- package/utils/utils.test.js +292 -0
- package/utils/viewUtils.js +0 -3
- 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/api/search/case.d.ts +0 -4
- package/api/search/case.js +0 -8
- package/api/socket/index.d.ts +0 -3
- package/api/socket/index.js +0 -6
- package/api/socket/viewers.d.ts +0 -2
- package/api/socket/viewers.js +0 -8
- package/api/socket/viewers.test.js +0 -44
- package/api/v2/case/index.d.ts +0 -9
- package/api/v2/case/index.js +0 -21
- package/api/v2/case/items.d.ts +0 -6
- package/api/v2/case/items.js +0 -18
- package/api/v2/case/rules.d.ts +0 -6
- package/api/v2/case/rules.js +0 -18
- package/api/v2/index.d.ts +0 -4
- package/api/v2/index.js +0 -6
- package/api/v2/search/facet.d.ts +0 -3
- package/api/v2/search/facet.js +0 -12
- package/api/v2/search/index.d.ts +0 -5
- package/api/v2/search/index.js +0 -24
- package/components/app/providers/RecordProvider.d.ts +0 -23
- package/components/elements/ContextMenu.d.ts +0 -56
- package/components/elements/ContextMenu.js +0 -109
- package/components/elements/ContextMenu.test.js +0 -215
- package/components/elements/ObjectDetails.d.ts +0 -6
- package/components/elements/case/CaseCard.d.ts +0 -12
- package/components/elements/case/CaseCard.js +0 -42
- package/components/elements/case/CasePreview.d.ts +0 -6
- package/components/elements/case/CasePreview.js +0 -17
- package/components/elements/case/StatusIcon.d.ts +0 -5
- package/components/elements/case/StatusIcon.js +0 -13
- package/components/elements/hit/elements/AnalyticLink.d.ts +0 -9
- package/components/elements/hit/elements/AnalyticLink.js +0 -22
- package/components/elements/hit/elements/Assigned.js +0 -34
- package/components/elements/hit/elements/Assigned.test.js +0 -65
- package/components/elements/hit/related/RelatedRecords.js +0 -63
- package/components/elements/observable/ObservableCard.d.ts +0 -6
- package/components/elements/observable/ObservableCard.js +0 -22
- package/components/elements/observable/ObservablePreview.d.ts +0 -6
- package/components/elements/observable/ObservablePreview.js +0 -12
- package/components/elements/record/RecordContextMenu.js +0 -268
- package/components/elements/record/RecordRelated.d.ts +0 -7
- package/components/elements/record/RecordRelated.js +0 -34
- package/components/hooks/useRelatedRecords.d.ts +0 -13
- package/components/hooks/useRelatedRecords.js +0 -32
- package/components/routes/cases/CaseViewer.d.ts +0 -2
- package/components/routes/cases/CaseViewer.js +0 -44
- package/components/routes/cases/CaseViewer.test.js +0 -133
- package/components/routes/cases/Cases.d.ts +0 -2
- package/components/routes/cases/Cases.js +0 -148
- package/components/routes/cases/constants.d.ts +0 -6
- package/components/routes/cases/constants.js +0 -6
- package/components/routes/cases/detail/AlertPanel.d.ts +0 -6
- package/components/routes/cases/detail/AlertPanel.js +0 -33
- package/components/routes/cases/detail/CaseAssets.d.ts +0 -11
- package/components/routes/cases/detail/CaseAssets.js +0 -104
- package/components/routes/cases/detail/CaseAssets.test.js +0 -167
- package/components/routes/cases/detail/CaseDashboard.d.ts +0 -7
- package/components/routes/cases/detail/CaseDashboard.js +0 -66
- package/components/routes/cases/detail/CaseDetails.d.ts +0 -6
- package/components/routes/cases/detail/CaseDetails.js +0 -70
- package/components/routes/cases/detail/CaseOverview.d.ts +0 -7
- package/components/routes/cases/detail/CaseOverview.js +0 -43
- package/components/routes/cases/detail/CaseRules.d.ts +0 -7
- package/components/routes/cases/detail/CaseRules.js +0 -57
- package/components/routes/cases/detail/CaseRules.test.js +0 -221
- package/components/routes/cases/detail/CaseSidebar.d.ts +0 -8
- package/components/routes/cases/detail/CaseSidebar.js +0 -107
- package/components/routes/cases/detail/CaseSidebar.test.js +0 -266
- package/components/routes/cases/detail/CaseTask.d.ts +0 -11
- package/components/routes/cases/detail/CaseTask.js +0 -66
- package/components/routes/cases/detail/CaseTimeline.d.ts +0 -12
- package/components/routes/cases/detail/CaseTimeline.js +0 -106
- package/components/routes/cases/detail/CaseTimeline.test.js +0 -320
- package/components/routes/cases/detail/CreateRuleDialog.d.ts +0 -9
- package/components/routes/cases/detail/CreateRuleDialog.js +0 -163
- package/components/routes/cases/detail/CreateRuleDialog.test.js +0 -259
- package/components/routes/cases/detail/ItemPage.d.ts +0 -6
- package/components/routes/cases/detail/ItemPage.js +0 -95
- package/components/routes/cases/detail/RelatedCasePanel.d.ts +0 -6
- package/components/routes/cases/detail/RelatedCasePanel.js +0 -34
- package/components/routes/cases/detail/TaskPanel.d.ts +0 -7
- package/components/routes/cases/detail/TaskPanel.js +0 -52
- package/components/routes/cases/detail/aggregates/CaseAggregate.d.ts +0 -11
- package/components/routes/cases/detail/aggregates/CaseAggregate.js +0 -24
- package/components/routes/cases/detail/aggregates/SourceAggregate.d.ts +0 -6
- package/components/routes/cases/detail/aggregates/SourceAggregate.js +0 -26
- package/components/routes/cases/detail/assets/Asset.d.ts +0 -14
- package/components/routes/cases/detail/assets/Asset.js +0 -12
- package/components/routes/cases/detail/assets/Asset.test.js +0 -72
- package/components/routes/cases/detail/sidebar/CaseFolder.d.ts +0 -20
- package/components/routes/cases/detail/sidebar/CaseFolder.js +0 -83
- package/components/routes/cases/detail/sidebar/CaseFolder.test.js +0 -295
- package/components/routes/cases/detail/sidebar/CaseFolderContextMenu.d.ts +0 -34
- package/components/routes/cases/detail/sidebar/CaseFolderContextMenu.js +0 -103
- package/components/routes/cases/detail/sidebar/CaseFolderContextMenu.test.js +0 -363
- package/components/routes/cases/detail/sidebar/FolderEntry.d.ts +0 -25
- package/components/routes/cases/detail/sidebar/FolderEntry.js +0 -88
- package/components/routes/cases/detail/sidebar/FolderEntry.test.js +0 -206
- package/components/routes/cases/detail/sidebar/RootDropZone.d.ts +0 -5
- package/components/routes/cases/detail/sidebar/RootDropZone.js +0 -33
- package/components/routes/cases/detail/sidebar/types.d.ts +0 -9
- package/components/routes/cases/detail/sidebar/utils.d.ts +0 -3
- package/components/routes/cases/detail/sidebar/utils.js +0 -29
- package/components/routes/cases/detail/sidebar/utils.test.js +0 -82
- package/components/routes/cases/hooks/useCase.d.ts +0 -13
- package/components/routes/cases/hooks/useCase.js +0 -69
- package/components/routes/cases/hooks/useCase.test.js +0 -141
- package/components/routes/cases/modals/AddToCaseModal.d.ts +0 -7
- package/components/routes/cases/modals/AddToCaseModal.js +0 -59
- package/components/routes/cases/modals/AddToCaseModal.test.js +0 -313
- package/components/routes/cases/modals/CaseRecordRow.d.ts +0 -9
- package/components/routes/cases/modals/CaseRecordRow.js +0 -15
- package/components/routes/cases/modals/CreateCaseModal.d.ts +0 -7
- package/components/routes/cases/modals/CreateCaseModal.js +0 -55
- package/components/routes/cases/modals/CreateCaseModal.test.js +0 -358
- package/components/routes/cases/modals/RenameItemModal.d.ts +0 -9
- package/components/routes/cases/modals/RenameItemModal.js +0 -48
- package/components/routes/cases/modals/ResolveModal.d.ts +0 -7
- package/components/routes/cases/modals/ResolveModal.js +0 -115
- package/components/routes/cases/modals/ResolveModal.test.js +0 -394
- package/components/routes/cases/modals/hooks.d.ts +0 -7
- package/components/routes/cases/modals/hooks.js +0 -44
- package/components/routes/cases/modals/types.d.ts +0 -5
- package/components/routes/cases/search/CaseAssigneeFilter.d.ts +0 -6
- package/components/routes/cases/search/CaseAssigneeFilter.js +0 -33
- package/components/routes/cases/search/CaseAssigneeFilter.test.js +0 -127
- package/components/routes/cases/search/CaseDateFilter.d.ts +0 -13
- package/components/routes/cases/search/CaseDateFilter.js +0 -26
- package/components/routes/cases/search/CaseDateFilter.test.js +0 -115
- package/components/routes/cases/search/CaseStatusFilter.d.ts +0 -6
- package/components/routes/cases/search/CaseStatusFilter.js +0 -13
- package/components/routes/cases/search/CaseStatusFilter.test.js +0 -86
- package/components/routes/hits/search/shared/IndexPicker.d.ts +0 -2
- package/components/routes/hits/search/shared/IndexPicker.js +0 -20
- package/components/routes/observables/ObservableViewer.d.ts +0 -7
- package/components/routes/observables/ObservableViewer.js +0 -27
- package/models/entities/generated/AttachmentsFile.d.ts +0 -12
- package/models/entities/generated/Case.d.ts +0 -28
- package/models/entities/generated/DestinationOriginal.d.ts +0 -19
- package/models/entities/generated/EmailAttachment.d.ts +0 -8
- package/models/entities/generated/EmailParent.d.ts +0 -19
- package/models/entities/generated/Enrichments.d.ts +0 -7
- package/models/entities/generated/EnrichmentsIndicator.d.ts +0 -21
- package/models/entities/generated/HttpResponse.d.ts +0 -11
- package/models/entities/generated/Item.d.ts +0 -9
- package/models/entities/generated/Observable.d.ts +0 -85
- package/models/entities/generated/ObservableCloud.d.ts +0 -20
- package/models/entities/generated/ObservableDestination.d.ts +0 -23
- package/models/entities/generated/ObservableEmail.d.ts +0 -30
- package/models/entities/generated/ObservableFile.d.ts +0 -36
- package/models/entities/generated/ObservableHowler.d.ts +0 -42
- package/models/entities/generated/ObservableHttp.d.ts +0 -11
- package/models/entities/generated/ObservableObserver.d.ts +0 -21
- package/models/entities/generated/ObservableOrganization.d.ts +0 -7
- package/models/entities/generated/ObservableProcess.d.ts +0 -34
- package/models/entities/generated/ObservableSource.d.ts +0 -23
- package/models/entities/generated/ObservableThreat.d.ts +0 -21
- package/models/entities/generated/ObservableTls.d.ts +0 -12
- package/models/entities/generated/ObserverIngress.d.ts +0 -9
- package/models/entities/generated/Task.d.ts +0 -10
- package/models/socket/CaseUpdate.d.ts +0 -5
- package/models/socket/ViewersUpdate.d.ts +0 -4
- package/utils/typeUtils.d.ts +0 -7
- package/utils/typeUtils.js +0 -27
- /package/{api/socket/viewers.test.d.ts → components/app/providers/HitSearchProvider.test.d.ts} +0 -0
- /package/components/{app/providers/RecordSearchProvider.test.d.ts → elements/addons/buttons/CustomButton.test.d.ts} +0 -0
- /package/components/elements/{ContextMenu.test.d.ts → addons/layout/FlexOne.test.d.ts} +0 -0
- /package/components/elements/{hit/elements/Assigned.test.d.ts → addons/search/SearchPagination.test.d.ts} +0 -0
- /package/components/elements/{record/RecordContextMenu.test.d.ts → addons/search/SearchTotal.test.d.ts} +0 -0
- /package/components/{routes/cases/CaseViewer.test.d.ts → elements/display/DocumentationButton.test.d.ts} +0 -0
- /package/components/{routes/cases/detail/CaseAssets.test.d.ts → elements/display/DynamicTabs.test.d.ts} +0 -0
- /package/components/{routes/cases/detail/CaseRules.test.d.ts → elements/display/HowlerCard.test.d.ts} +0 -0
- /package/components/{routes/cases/detail/CaseSidebar.test.d.ts → elements/display/Image.test.d.ts} +0 -0
- /package/components/{routes/cases/detail/CaseTimeline.test.d.ts → elements/display/QueryResultText.test.d.ts} +0 -0
- /package/components/{routes/cases/detail/CreateRuleDialog.test.d.ts → elements/display/TextDivider.test.d.ts} +0 -0
- /package/components/{routes/cases/detail/assets/Asset.test.d.ts → elements/display/TypingIndicator.test.d.ts} +0 -0
- /package/components/elements/hit/{related/RelatedRecords.d.ts → HitDetails.d.ts} +0 -0
- /package/components/routes/{cases/detail/sidebar/CaseFolder.test.d.ts → 403.test.d.ts} +0 -0
- /package/components/routes/{cases/detail/sidebar/CaseFolderContextMenu.test.d.ts → 404.test.d.ts} +0 -0
- /package/components/routes/{cases/detail/sidebar/FolderEntry.test.d.ts → ErrorBoundary.test.d.ts} +0 -0
- /package/components/routes/{cases/detail/sidebar/utils.test.d.ts → ErrorOccured.test.d.ts} +0 -0
- /package/components/routes/{cases/hooks/useCase.test.d.ts → Logout.test.d.ts} +0 -0
- /package/components/routes/hits/search/{RecordBrowser.d.ts → HitBrowser.d.ts} +0 -0
- /package/components/routes/{cases/modals/AddToCaseModal.test.d.ts → hits/search/HitContextMenu.test.d.ts} +0 -0
- /package/components/routes/{cases/modals/CreateCaseModal.test.d.ts → hits/search/shared/CustomSpan.test.d.ts} +0 -0
- /package/components/routes/{cases/modals/ResolveModal.test.d.ts → home/AddNewCard.test.d.ts} +0 -0
- /package/components/routes/{cases/search/CaseAssigneeFilter.test.d.ts → home/ViewRefresh.test.d.ts} +0 -0
- /package/components/routes/{cases/search/CaseDateFilter.test.d.ts → overviews/OverviewCard.test.d.ts} +0 -0
- /package/components/{elements/MarkdownEditor.d.ts → routes/overviews/OverviewEditor.d.ts} +0 -0
- /package/components/routes/{cases/search/CaseStatusFilter.test.d.ts → settings/SettingsSection.test.d.ts} +0 -0
package/tests/server-handlers.js
CHANGED
|
@@ -30,12 +30,7 @@ export const MOCK_RESPONSES = {
|
|
|
30
30
|
total: 1,
|
|
31
31
|
rows: 1
|
|
32
32
|
},
|
|
33
|
-
'/api/v1/analytic': [createMockAnalytic()]
|
|
34
|
-
'/api/v2/search/hit,observable': {
|
|
35
|
-
items: [],
|
|
36
|
-
total: 0,
|
|
37
|
-
rows: 0
|
|
38
|
-
}
|
|
33
|
+
'/api/v1/analytic': [createMockAnalytic()]
|
|
39
34
|
};
|
|
40
35
|
const handlers = [
|
|
41
36
|
...Object.entries(MOCK_RESPONSES).map(([path, data]) => http.all(path, async () => HttpResponse.json({ api_response: data }))),
|
package/tests/utils.d.ts
CHANGED
|
@@ -1,20 +1,16 @@
|
|
|
1
1
|
import type { Action } from '@cccsaurora/howler-ui/models/entities/generated/Action';
|
|
2
2
|
import type { Analytic } from '@cccsaurora/howler-ui/models/entities/generated/Analytic';
|
|
3
|
-
import type { Case } from '@cccsaurora/howler-ui/models/entities/generated/Case';
|
|
4
3
|
import type { Dossier } from '@cccsaurora/howler-ui/models/entities/generated/Dossier';
|
|
5
4
|
import type { Hit } from '@cccsaurora/howler-ui/models/entities/generated/Hit';
|
|
6
|
-
import type { Observable } from '@cccsaurora/howler-ui/models/entities/generated/Observable';
|
|
7
5
|
import type { Template } from '@cccsaurora/howler-ui/models/entities/generated/Template';
|
|
8
6
|
import type { View } from '@cccsaurora/howler-ui/models/entities/generated/View';
|
|
9
7
|
type RecursivePartial<T> = {
|
|
10
8
|
[P in keyof T]?: T[P] extends (infer U)[] ? RecursivePartial<U>[] : T[P] extends object | undefined ? RecursivePartial<T[P]> : T[P];
|
|
11
9
|
};
|
|
12
10
|
export declare const createMockHit: (overrides?: RecursivePartial<Hit>) => Hit;
|
|
13
|
-
export declare const createMockObservable: (overrides?: RecursivePartial<Observable>) => Observable;
|
|
14
11
|
export declare const createMockAnalytic: (overrides?: Partial<Analytic>) => Analytic;
|
|
15
12
|
export declare const createMockTemplate: (overrides?: Partial<Template>) => Template;
|
|
16
13
|
export declare const createMockAction: (overrides?: Partial<Action>) => Action;
|
|
17
14
|
export declare const createMockView: (overrides?: Partial<View>) => View;
|
|
18
|
-
export declare const createMockCase: (overrides?: Partial<Case>) => Case;
|
|
19
15
|
export declare const createMockDossier: (overrides?: Partial<Dossier>) => Dossier;
|
|
20
16
|
export {};
|
package/tests/utils.js
CHANGED
|
@@ -1,7 +1,5 @@
|
|
|
1
1
|
// Mock data factories
|
|
2
2
|
export const createMockHit = (overrides) => ({
|
|
3
|
-
...overrides,
|
|
4
|
-
__index: 'hit',
|
|
5
3
|
howler: {
|
|
6
4
|
id: 'test-hit-1',
|
|
7
5
|
analytic: 'test-analytic',
|
|
@@ -16,17 +14,6 @@ export const createMockHit = (overrides) => ({
|
|
|
16
14
|
...overrides?.event
|
|
17
15
|
}
|
|
18
16
|
});
|
|
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
|
-
});
|
|
30
17
|
export const createMockAnalytic = (overrides) => ({
|
|
31
18
|
analytic_id: 'test-analytic-id',
|
|
32
19
|
name: 'test-analytic',
|
|
@@ -65,13 +52,6 @@ export const createMockView = (overrides) => ({
|
|
|
65
52
|
},
|
|
66
53
|
...overrides
|
|
67
54
|
});
|
|
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
|
-
});
|
|
75
55
|
// Helper function to create mock dossiers
|
|
76
56
|
export const createMockDossier = (overrides) => ({
|
|
77
57
|
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: string;
|
|
9
|
+
evidence: string;
|
|
10
|
+
hit: string;
|
|
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,7 +75,6 @@ export declare const RULE_INTERVALS: {
|
|
|
74
75
|
crontab: string;
|
|
75
76
|
}[];
|
|
76
77
|
export declare const DATE_RANGES: string[];
|
|
77
|
-
export declare const DATE_RANGE_LUCENE: Partial<Record<(typeof DATE_RANGES)[number], string>>;
|
|
78
78
|
interface LabelData {
|
|
79
79
|
icon?: ReactElement;
|
|
80
80
|
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,12 +105,6 @@ export const DATE_RANGES = [
|
|
|
104
105
|
'date.range.all',
|
|
105
106
|
'date.range.custom'
|
|
106
107
|
];
|
|
107
|
-
export const DATE_RANGE_LUCENE = {
|
|
108
|
-
'date.range.1.day': 'now-1d/d',
|
|
109
|
-
'date.range.3.day': 'now-3d/d',
|
|
110
|
-
'date.range.1.week': 'now-7d/d',
|
|
111
|
-
'date.range.1.month': 'now-1M/M'
|
|
112
|
-
};
|
|
113
108
|
export const LABEL_TYPES = {
|
|
114
109
|
insight: { icon: _jsx(PsychologyAlt, { fontSize: "small" }), color: '#FFFFFF' }, //brain icon
|
|
115
110
|
mitigation: { icon: _jsx(LocalPolice, { fontSize: "small" }), color: blue[600] }, //police badge
|
package/utils/hitFunctions.d.ts
CHANGED
|
@@ -1,3 +1,2 @@
|
|
|
1
1
|
import type { Hit } from '@cccsaurora/howler-ui/models/entities/generated/Hit';
|
|
2
|
-
|
|
3
|
-
export declare const getUserList: (record: Hit | Observable) => Set<string>;
|
|
2
|
+
export declare const getUserList: (hit: Hit) => Set<string>;
|
package/utils/hitFunctions.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
export const getUserList = (
|
|
1
|
+
export const getUserList = (hit) => {
|
|
2
2
|
const ids = new Set();
|
|
3
|
-
if (
|
|
4
|
-
|
|
5
|
-
|
|
3
|
+
if (hit) {
|
|
4
|
+
hit.howler?.log?.forEach(l => ids.add(l.user));
|
|
5
|
+
hit.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
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|