@cccsaurora/howler-ui 2.19.0-cases.863 → 2.19.0-dev.1023
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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 +5 -8
- package/api/index.js +10 -18
- package/api/overview/index.d.ts +4 -3
- package/api/overview/index.js +6 -6
- 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/api/search/overview.d.ts +2 -2
- 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/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 +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/SearchResponseProvider.d.ts +21 -0
- package/components/app/providers/SearchResponseProvider.js +81 -0
- package/components/app/providers/SearchResponseProvider.test.js +406 -0
- 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/app/providers/ViewProvider.test.js +4 -1
- 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.d.ts +2 -1
- package/components/elements/addons/search/SearchPagination.js +4 -4
- package/components/elements/addons/search/SearchPagination.test.js +80 -0
- package/components/elements/addons/search/SearchTotal.test.js +47 -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/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 +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/useMyApi.d.ts +1 -1
- 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/useMyActionFunctions.js +5 -2
- package/components/routes/action/view/ActionDetails.js +10 -2
- package/components/routes/action/view/ActionSearch.js +30 -19
- 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/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/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 +86 -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 +18 -10
- package/components/routes/overviews/Overviews.js +25 -19
- 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 +19 -46
- package/components/routes/views/Views.js +21 -14
- package/locales/en/translation.json +21 -118
- package/locales/fr/translation.json +23 -120
- 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 +125 -145
- 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 → SearchResponseProvider.test.d.ts} +0 -0
- /package/components/elements/{ContextMenu.test.d.ts → addons/buttons/CustomButton.test.d.ts} +0 -0
- /package/components/elements/{hit/elements/Assigned.test.d.ts → addons/layout/FlexOne.test.d.ts} +0 -0
- /package/components/elements/{record/RecordContextMenu.test.d.ts → addons/search/SearchPagination.test.d.ts} +0 -0
- /package/components/{routes/cases/CaseViewer.test.d.ts → elements/addons/search/SearchTotal.test.d.ts} +0 -0
- /package/components/{routes/cases/detail/CaseAssets.test.d.ts → elements/display/DocumentationButton.test.d.ts} +0 -0
- /package/components/{routes/cases/detail/CaseRules.test.d.ts → elements/display/DynamicTabs.test.d.ts} +0 -0
- /package/components/{routes/cases/detail/CaseSidebar.test.d.ts → elements/display/HowlerCard.test.d.ts} +0 -0
- /package/components/{routes/cases/detail/CaseTimeline.test.d.ts → elements/display/Image.test.d.ts} +0 -0
- /package/components/{routes/cases/detail/CreateRuleDialog.test.d.ts → elements/display/QueryResultText.test.d.ts} +0 -0
- /package/components/{routes/cases/detail/assets/Asset.test.d.ts → elements/display/TextDivider.test.d.ts} +0 -0
- /package/components/{routes/cases/detail/sidebar/CaseFolder.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/CaseFolderContextMenu.test.d.ts → 403.test.d.ts} +0 -0
- /package/components/routes/{cases/detail/sidebar/FolderEntry.test.d.ts → 404.test.d.ts} +0 -0
- /package/components/routes/{cases/detail/sidebar/utils.test.d.ts → ErrorBoundary.test.d.ts} +0 -0
- /package/components/routes/{cases/hooks/useCase.test.d.ts → ErrorOccured.test.d.ts} +0 -0
- /package/components/routes/{cases/modals/AddToCaseModal.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/CreateCaseModal.test.d.ts → hits/search/HitContextMenu.test.d.ts} +0 -0
- /package/components/routes/{cases/modals/ResolveModal.test.d.ts → hits/search/shared/CustomSpan.test.d.ts} +0 -0
- /package/components/routes/{cases/search/CaseAssigneeFilter.test.d.ts → home/AddNewCard.test.d.ts} +0 -0
- /package/components/routes/{cases/search/CaseDateFilter.test.d.ts → home/ViewRefresh.test.d.ts} +0 -0
- /package/components/routes/{cases/search/CaseStatusFilter.test.d.ts → overviews/OverviewCard.test.d.ts} +0 -0
- /package/components/{elements/MarkdownEditor.d.ts → routes/overviews/OverviewEditor.d.ts} +0 -0
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
/// <reference types="vitest" />
|
|
3
|
+
import { render, screen } from '@testing-library/react';
|
|
4
|
+
import i18n from '@cccsaurora/howler-ui/i18n';
|
|
5
|
+
import { I18nextProvider } from 'react-i18next';
|
|
6
|
+
import { describe, expect, it, vi } from 'vitest';
|
|
7
|
+
import ErrorOccured from './ErrorOccured';
|
|
8
|
+
vi.mock('commons/components/pages/PageCenter', () => ({
|
|
9
|
+
default: ({ children }) => _jsx("div", { id: "page-center", children: children })
|
|
10
|
+
}));
|
|
11
|
+
const mockExecuteFunction = vi.fn(() => null);
|
|
12
|
+
vi.mock('react-pluggable', () => ({
|
|
13
|
+
usePluginStore: () => ({
|
|
14
|
+
executeFunction: mockExecuteFunction
|
|
15
|
+
})
|
|
16
|
+
}));
|
|
17
|
+
vi.mock('plugins/store', () => ({
|
|
18
|
+
default: { plugins: ['TestPlugin'] }
|
|
19
|
+
}));
|
|
20
|
+
const Wrapper = ({ children }) => (_jsx(I18nextProvider, { i18n: i18n, children: children }));
|
|
21
|
+
describe('ErrorOccured', () => {
|
|
22
|
+
it('should render the error title and description', () => {
|
|
23
|
+
render(_jsx(ErrorOccured, {}), { wrapper: Wrapper });
|
|
24
|
+
expect(screen.getByText('Application Stopped Working')).toBeInTheDocument();
|
|
25
|
+
expect(screen.getByText('The application stopped working suddenly. If the problem persists please reach out on teams.')).toBeInTheDocument();
|
|
26
|
+
});
|
|
27
|
+
it('should render inside PageCenter', () => {
|
|
28
|
+
render(_jsx(ErrorOccured, {}), { wrapper: Wrapper });
|
|
29
|
+
expect(screen.getByTestId('page-center')).toBeInTheDocument();
|
|
30
|
+
});
|
|
31
|
+
it('should execute plugin support functions', () => {
|
|
32
|
+
render(_jsx(ErrorOccured, {}), { wrapper: Wrapper });
|
|
33
|
+
expect(mockExecuteFunction).toHaveBeenCalledWith('TestPlugin.support');
|
|
34
|
+
});
|
|
35
|
+
});
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
/// <reference types="vitest" />
|
|
3
|
+
import { render, screen } from '@testing-library/react';
|
|
4
|
+
import i18n from '@cccsaurora/howler-ui/i18n';
|
|
5
|
+
import { I18nextProvider } from 'react-i18next';
|
|
6
|
+
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
|
|
7
|
+
import Logout from './Logout';
|
|
8
|
+
const mockHideMenus = vi.fn();
|
|
9
|
+
const mockClear = vi.fn();
|
|
10
|
+
vi.mock('commons/components/app/hooks', () => ({
|
|
11
|
+
useAppBanner: () => _jsx("div", { "data-testid": "app-banner", children: "Banner" }),
|
|
12
|
+
useAppLayout: () => ({
|
|
13
|
+
hideMenus: mockHideMenus
|
|
14
|
+
})
|
|
15
|
+
}));
|
|
16
|
+
vi.mock('components/hooks/useMyLocalStorage', () => ({
|
|
17
|
+
default: () => ({
|
|
18
|
+
clear: mockClear
|
|
19
|
+
})
|
|
20
|
+
}));
|
|
21
|
+
vi.mock('commons/components/pages/PageCardCentered', () => ({
|
|
22
|
+
default: ({ children }) => _jsx("div", { children: children })
|
|
23
|
+
}));
|
|
24
|
+
const Wrapper = ({ children }) => (_jsx(I18nextProvider, { i18n: i18n, children: children }));
|
|
25
|
+
describe('Logout', () => {
|
|
26
|
+
const originalLocation = window.location;
|
|
27
|
+
beforeEach(() => {
|
|
28
|
+
vi.useFakeTimers();
|
|
29
|
+
// Mock window.location.replace
|
|
30
|
+
Object.defineProperty(window, 'location', {
|
|
31
|
+
value: { ...originalLocation, replace: vi.fn() },
|
|
32
|
+
writable: true
|
|
33
|
+
});
|
|
34
|
+
});
|
|
35
|
+
afterEach(() => {
|
|
36
|
+
vi.useRealTimers();
|
|
37
|
+
Object.defineProperty(window, 'location', { value: originalLocation, writable: true });
|
|
38
|
+
vi.clearAllMocks();
|
|
39
|
+
});
|
|
40
|
+
it('should render the logout message', () => {
|
|
41
|
+
render(_jsx(Logout, {}), { wrapper: Wrapper });
|
|
42
|
+
expect(screen.getByText(/Logging out current user/)).toBeInTheDocument();
|
|
43
|
+
});
|
|
44
|
+
it('should render the app banner', () => {
|
|
45
|
+
render(_jsx(Logout, {}), { wrapper: Wrapper });
|
|
46
|
+
expect(screen.getByText('Banner')).toBeInTheDocument();
|
|
47
|
+
});
|
|
48
|
+
it('should hide menus on mount', () => {
|
|
49
|
+
render(_jsx(Logout, {}), { wrapper: Wrapper });
|
|
50
|
+
expect(mockHideMenus).toHaveBeenCalled();
|
|
51
|
+
});
|
|
52
|
+
it('should clear localStorage and redirect after 2 seconds', () => {
|
|
53
|
+
render(_jsx(Logout, {}), { wrapper: Wrapper });
|
|
54
|
+
expect(mockClear).not.toHaveBeenCalled();
|
|
55
|
+
vi.advanceTimersByTime(2000);
|
|
56
|
+
expect(mockClear).toHaveBeenCalled();
|
|
57
|
+
expect(window.location.replace).toHaveBeenCalledWith('/');
|
|
58
|
+
});
|
|
59
|
+
});
|
|
@@ -7,7 +7,7 @@ import PageCenter from '@cccsaurora/howler-ui/commons/components/pages/PageCente
|
|
|
7
7
|
import { FieldContext } from '@cccsaurora/howler-ui/components/app/providers/FieldProvider';
|
|
8
8
|
import SocketBadge from '@cccsaurora/howler-ui/components/elements/display/icons/SocketBadge';
|
|
9
9
|
import useMyApi from '@cccsaurora/howler-ui/components/hooks/useMyApi';
|
|
10
|
-
import
|
|
10
|
+
import HitQuery from '@cccsaurora/howler-ui/components/routes/hits/search/HitQuery';
|
|
11
11
|
import { difference, uniq } from 'lodash-es';
|
|
12
12
|
import howlerPluginStore from '@cccsaurora/howler-ui/plugins/store';
|
|
13
13
|
import { useCallback, useContext, useEffect, useMemo, useState } from 'react';
|
|
@@ -102,7 +102,7 @@ const ActionEditor = () => {
|
|
|
102
102
|
: disabled && userOperations.length > 0
|
|
103
103
|
? t('route.actions.trigger.disabled.explanation')
|
|
104
104
|
: null, children: component }, trigger));
|
|
105
|
-
}) }) }), _jsxs(Stack, { direction: "row", justifyContent: "space-between", alignItems: "end", sx: { mb: -1 }, children: [_jsx(Typography, { sx: theme => ({ color: theme.palette.text.disabled, fontStyle: 'italic', mb: 0.5 }), variant: "body2", children: t('hit.search.prompt') }), _jsx(SocketBadge, { size: "small" })] }), _jsx(
|
|
105
|
+
}) }) }), _jsxs(Stack, { direction: "row", justifyContent: "space-between", alignItems: "end", sx: { mb: -1 }, children: [_jsx(Typography, { sx: theme => ({ color: theme.palette.text.disabled, fontStyle: 'italic', mb: 0.5 }), variant: "body2", children: t('hit.search.prompt') }), _jsx(SocketBadge, { size: "small" })] }), _jsx(HitQuery, { triggerSearch: onSearch }), response ? (_jsx(QueryResultText, { count: response.total, query: responseQuery })) : (_jsx(Typography, { sx: theme => ({
|
|
106
106
|
color: theme.palette.text.secondary,
|
|
107
107
|
fontSize: '0.9em',
|
|
108
108
|
fontStyle: 'italic',
|
|
@@ -163,8 +163,11 @@ const useMyActionFunctions = () => {
|
|
|
163
163
|
deleteAction: useCallback(async (actionId) => {
|
|
164
164
|
setLoading(true);
|
|
165
165
|
try {
|
|
166
|
-
|
|
167
|
-
|
|
166
|
+
const detailedActionView = location.pathname.endsWith(actionId);
|
|
167
|
+
await dispatchApi(api.action.del(actionId, detailedActionView ? 'wait_for' : undefined), {
|
|
168
|
+
throwError: true
|
|
169
|
+
});
|
|
170
|
+
if (detailedActionView) {
|
|
168
171
|
navigate('/action');
|
|
169
172
|
}
|
|
170
173
|
}
|
|
@@ -4,13 +4,15 @@ import { Button, Checkbox, FormControlLabel, FormGroup, IconButton, LinearProgre
|
|
|
4
4
|
import api from '@cccsaurora/howler-ui/api';
|
|
5
5
|
import { useAppUser } from '@cccsaurora/howler-ui/commons/components/app/hooks';
|
|
6
6
|
import PageCenter from '@cccsaurora/howler-ui/commons/components/pages/PageCenter';
|
|
7
|
+
import { ModalContext } from '@cccsaurora/howler-ui/components/app/providers/ModalProvider';
|
|
7
8
|
import FlexOne from '@cccsaurora/howler-ui/components/elements/addons/layout/FlexOne';
|
|
8
9
|
import Phrase from '@cccsaurora/howler-ui/components/elements/addons/search/phrase/Phrase';
|
|
9
10
|
import HowlerAvatar from '@cccsaurora/howler-ui/components/elements/display/HowlerAvatar';
|
|
10
11
|
import useMyApi from '@cccsaurora/howler-ui/components/hooks/useMyApi';
|
|
12
|
+
import useMySnackbar from '@cccsaurora/howler-ui/components/hooks/useMySnackbar';
|
|
11
13
|
import OperationEntry from '@cccsaurora/howler-ui/components/routes/action/shared/OperationEntry';
|
|
12
14
|
import howlerPluginStore from '@cccsaurora/howler-ui/plugins/store';
|
|
13
|
-
import { useCallback, useEffect, useState } from 'react';
|
|
15
|
+
import { useCallback, useContext, useEffect, useState } from 'react';
|
|
14
16
|
import { useTranslation } from 'react-i18next';
|
|
15
17
|
import { usePluginStore } from 'react-pluggable';
|
|
16
18
|
import { Link, useParams } from 'react-router-dom';
|
|
@@ -26,6 +28,8 @@ const ActionDetails = () => {
|
|
|
26
28
|
const { response, onSearch, loading, setLoading, executeAction, deleteAction, progress, report } = useMyActionFunctions();
|
|
27
29
|
const [operations, setOperations] = useState([]);
|
|
28
30
|
const [action, setAction] = useState();
|
|
31
|
+
const { withConfirmDeleteModal } = useContext(ModalContext);
|
|
32
|
+
const { showSuccessMessage } = useMySnackbar();
|
|
29
33
|
const onTriggerChange = useCallback(async (e) => {
|
|
30
34
|
let newTriggers = action.triggers ?? [];
|
|
31
35
|
if (e.target.checked && !newTriggers.includes(e.target.name)) {
|
|
@@ -45,6 +49,10 @@ const ActionDetails = () => {
|
|
|
45
49
|
setLoading(false);
|
|
46
50
|
}
|
|
47
51
|
}, [action, dispatchApi, setLoading]);
|
|
52
|
+
const onDelete = useCallback(() => withConfirmDeleteModal(async () => {
|
|
53
|
+
await deleteAction(action?.action_id);
|
|
54
|
+
showSuccessMessage(t('route.actions.manager.delete.success'));
|
|
55
|
+
}), [withConfirmDeleteModal, deleteAction, action?.action_id, showSuccessMessage, t]);
|
|
48
56
|
useEffect(() => {
|
|
49
57
|
setLoading(true);
|
|
50
58
|
Promise.all([
|
|
@@ -63,7 +71,7 @@ const ActionDetails = () => {
|
|
|
63
71
|
user.roles.includes('admin') ||
|
|
64
72
|
user.roles.includes('actionrunner_basic') ||
|
|
65
73
|
user.roles.includes('actionrunner_advanced');
|
|
66
|
-
return (_jsx(PageCenter, { maxWidth: "1500px", textAlign: "left", height: "100%", children: _jsxs(Stack, { spacing: 1, children: [_jsxs(Stack, { direction: "row", justifyContent: "space-between", children: [_jsx(Typography, { variant: "h5", children: action?.name }), action?.owner_id && _jsx(HowlerAvatar, { sx: { width: 32, height: 32 }, userId: action.owner_id })] }), _jsx(Phrase, { fullWidth: true, value: action?.query, disabled: true, size: "small", onChange: () => { }, startAdornment: _jsx(IconButton, { onClick: () => onSearch(action?.query), children: _jsx(Search, { fontSize: "small" }) }) }), _jsxs(Stack, { direction: "row", alignItems: "center", spacing: 1, children: [response && _jsx(QueryResultText, { count: response.total, query: action?.query }), _jsx(FlexOne, {}), ((action?.owner_id === user.username && editRoles) || user.roles?.includes('admin')) && (_jsx(Button, { startIcon: _jsx(Delete, {}), size: "small", variant: "outlined", color: "error", onClick:
|
|
74
|
+
return (_jsx(PageCenter, { maxWidth: "1500px", textAlign: "left", height: "100%", children: _jsxs(Stack, { spacing: 1, children: [_jsxs(Stack, { direction: "row", justifyContent: "space-between", children: [_jsx(Typography, { variant: "h5", children: action?.name }), action?.owner_id && _jsx(HowlerAvatar, { sx: { width: 32, height: 32 }, userId: action.owner_id })] }), _jsx(Phrase, { fullWidth: true, value: action?.query, disabled: true, size: "small", onChange: () => { }, startAdornment: _jsx(IconButton, { onClick: () => onSearch(action?.query), children: _jsx(Search, { fontSize: "small" }) }) }), _jsxs(Stack, { direction: "row", alignItems: "center", spacing: 1, children: [response && _jsx(QueryResultText, { count: response.total, query: action?.query }), _jsx(FlexOne, {}), ((action?.owner_id === user.username && editRoles) || user.roles?.includes('admin')) && (_jsx(Button, { startIcon: _jsx(Delete, {}), size: "small", variant: "outlined", color: "error", onClick: onDelete, children: t('button.delete') })), execRoles && (_jsx(Button, { startIcon: _jsx(PlayCircleOutline, {}), size: "small", variant: "outlined", color: "success", onClick: () => executeAction(action?.action_id), children: t('route.actions.execute') })), ((action?.owner_id === user.username && editRoles) || user.roles?.includes('admin')) && (_jsx(Button, { startIcon: _jsx(Edit, {}), size: "small", variant: "outlined", component: Link, to: `/action/${params.id}/edit`, children: t('route.actions.edit') }))] }), user.roles.includes('automation_advanced') && (_jsx(FormGroup, { children: _jsx(Stack, { direction: "row", spacing: 1, children: action?.operations
|
|
67
75
|
?.map(a => (operations ?? []).find(_action => _action.id === a.operation_id)?.triggers ?? [])
|
|
68
76
|
.reduce((acc, triggers) => acc.filter(_t => triggers.includes(_t)))
|
|
69
77
|
.map(trigger => (_jsx(FormControlLabel, { control: _jsx(Checkbox, { name: trigger, onChange: onTriggerChange, checked: action?.triggers?.includes(trigger) ?? false }), label: t(`route.actions.trigger.${trigger}`) }, trigger))) }) })), loading &&
|
|
@@ -3,13 +3,15 @@ import { Delete, Engineering, Terminal } from '@mui/icons-material';
|
|
|
3
3
|
import { Autocomplete, Card, CardContent, CardHeader, Chip, Grid, IconButton, Stack, TextField, Tooltip, Typography } from '@mui/material';
|
|
4
4
|
import api from '@cccsaurora/howler-ui/api';
|
|
5
5
|
import { useAppUser } from '@cccsaurora/howler-ui/commons/components/app/hooks';
|
|
6
|
+
import { ModalContext } from '@cccsaurora/howler-ui/components/app/providers/ModalProvider';
|
|
7
|
+
import SearchResponseProvider, { SearchResponseContext } from '@cccsaurora/howler-ui/components/app/providers/SearchResponseProvider';
|
|
6
8
|
import FlexOne from '@cccsaurora/howler-ui/components/elements/addons/layout/FlexOne';
|
|
7
9
|
import { TuiListProvider } from '@cccsaurora/howler-ui/components/elements/addons/lists';
|
|
8
10
|
import { TuiListMethodContext } from '@cccsaurora/howler-ui/components/elements/addons/lists/TuiListProvider';
|
|
9
11
|
import HowlerAvatar from '@cccsaurora/howler-ui/components/elements/display/HowlerAvatar';
|
|
10
12
|
import ItemManager from '@cccsaurora/howler-ui/components/elements/display/ItemManager';
|
|
11
|
-
import useMyApi from '@cccsaurora/howler-ui/components/hooks/useMyApi';
|
|
12
13
|
import { useMyLocalStorageItem } from '@cccsaurora/howler-ui/components/hooks/useMyLocalStorage';
|
|
14
|
+
import useMySnackbar from '@cccsaurora/howler-ui/components/hooks/useMySnackbar';
|
|
13
15
|
import { useCallback, useContext, useEffect, useState } from 'react';
|
|
14
16
|
import { Trans, useTranslation } from 'react-i18next';
|
|
15
17
|
import { useNavigate, useSearchParams } from 'react-router-dom';
|
|
@@ -20,16 +22,17 @@ const ActionSearch = () => {
|
|
|
20
22
|
const navigate = useNavigate();
|
|
21
23
|
const { t } = useTranslation();
|
|
22
24
|
const { user } = useAppUser();
|
|
23
|
-
const { dispatchApi } = useMyApi();
|
|
24
25
|
const { load } = useContext(TuiListMethodContext);
|
|
26
|
+
const { withConfirmDeleteModal } = useContext(ModalContext);
|
|
27
|
+
const { showSuccessMessage } = useMySnackbar();
|
|
25
28
|
const [searchParams, setSearchParams] = useSearchParams();
|
|
26
29
|
const { deleteAction } = useMyActionFunctions();
|
|
27
30
|
const pageCount = useMyLocalStorageItem(StorageKey.PAGE_COUNT, 25)[0];
|
|
31
|
+
const { response, request, remove, getSearchRequestData } = useContext(SearchResponseContext);
|
|
28
32
|
const [searching, setSearching] = useState(false);
|
|
29
33
|
const [hasError, setHasError] = useState(false);
|
|
30
34
|
const [phrase, setPhrase] = useState(searchParams.get('phrase') || '');
|
|
31
35
|
const [offset, setOffset] = useState(parseInt(searchParams.get('offset')) || 0);
|
|
32
|
-
const [response, setResponse] = useState(null);
|
|
33
36
|
const [searchModifiers, setSearchModifiers] = useState([]);
|
|
34
37
|
// Search Handler.
|
|
35
38
|
const onSearch = useCallback(async () => {
|
|
@@ -48,13 +51,11 @@ const ActionSearch = () => {
|
|
|
48
51
|
if (searchModifiers.length > 0) {
|
|
49
52
|
query = `(${query}) AND (triggers:(${searchModifiers.join(' OR ')}))`;
|
|
50
53
|
}
|
|
51
|
-
|
|
54
|
+
await request(api.search.action.post, {
|
|
52
55
|
query,
|
|
53
56
|
rows: pageCount,
|
|
54
57
|
offset
|
|
55
|
-
})
|
|
56
|
-
setResponse(_response);
|
|
57
|
-
load(_response.items.map(u => ({ id: u.action_id, item: u })));
|
|
58
|
+
});
|
|
58
59
|
}
|
|
59
60
|
catch (e) {
|
|
60
61
|
setHasError(true);
|
|
@@ -62,14 +63,29 @@ const ActionSearch = () => {
|
|
|
62
63
|
finally {
|
|
63
64
|
setSearching(false);
|
|
64
65
|
}
|
|
65
|
-
}, [
|
|
66
|
+
}, [phrase, setSearchParams, searchParams, searchModifiers, request, pageCount, offset]);
|
|
67
|
+
useEffect(() => {
|
|
68
|
+
if (response) {
|
|
69
|
+
load(response.items.map((item) => ({ id: item.action_id, item: item })));
|
|
70
|
+
}
|
|
71
|
+
}, [response, load]);
|
|
66
72
|
const onPageChange = useCallback((_offset) => {
|
|
67
73
|
if (_offset !== offset) {
|
|
68
|
-
|
|
74
|
+
const modifiedRequest = getSearchRequestData({ offset: _offset });
|
|
75
|
+
searchParams.set('offset', modifiedRequest.offset.toString());
|
|
69
76
|
setSearchParams(searchParams, { replace: true });
|
|
70
|
-
setOffset(
|
|
77
|
+
setOffset(modifiedRequest.offset);
|
|
71
78
|
}
|
|
72
|
-
}, [offset, searchParams, setSearchParams]);
|
|
79
|
+
}, [offset, searchParams, setSearchParams, getSearchRequestData]);
|
|
80
|
+
const onDelete = useCallback((e, actionId) => {
|
|
81
|
+
e.preventDefault();
|
|
82
|
+
e.stopPropagation();
|
|
83
|
+
withConfirmDeleteModal(async () => {
|
|
84
|
+
await deleteAction(actionId);
|
|
85
|
+
remove(actionId);
|
|
86
|
+
showSuccessMessage(t('route.actions.manager.delete.success'));
|
|
87
|
+
});
|
|
88
|
+
}, [deleteAction, remove, withConfirmDeleteModal, showSuccessMessage, t]);
|
|
73
89
|
// Effect to initialize list of users.
|
|
74
90
|
useEffect(() => {
|
|
75
91
|
onSearch();
|
|
@@ -105,16 +121,11 @@ const ActionSearch = () => {
|
|
|
105
121
|
transitionProperty: 'border-color',
|
|
106
122
|
cursor: 'pointer',
|
|
107
123
|
mt: 1
|
|
108
|
-
}, children: [_jsx(CardHeader, { title: _jsxs(Stack, { direction: "row", spacing: 1, alignItems: "center", children: [_jsx(Typography, { variant: "h5", children: item.item.name }), item.item.triggers.length > 0 && (_jsx(Tooltip, { title: _jsx(Trans, { i18nKey: "route.actions.trigger.description", values: { triggers: item.item.triggers.join(', ') }, components: { bold: _jsx("strong", {}) } }), children: _jsx(Engineering, {}) })), _jsx(FlexOne, {}), ((item.item.owner_id === user.username && editRoles) || user.roles?.includes('admin')) && (_jsx(IconButton, { size: "small", onClick:
|
|
109
|
-
|
|
110
|
-
e.stopPropagation();
|
|
111
|
-
await deleteAction(item.item.action_id);
|
|
112
|
-
onSearch();
|
|
113
|
-
}, children: _jsx(Delete, {}) })), _jsx(HowlerAvatar, { sx: { width: 24, height: 24, marginRight: '8px !important' }, userId: item.item.owner_id })] }), subheader: item.item.query }), _jsx(CardContent, { sx: { paddingTop: 0 }, children: _jsx(Grid, { container: true, spacing: 1, children: item.item.operations.map(d => (_jsx(Grid, { item: true, children: _jsx(Chip, { label: t(`operations.${d.operation_id}`) }) }, d.operation_id))) }) })] }, item.item.name));
|
|
114
|
-
}, [deleteAction, editRoles, navigate, onSearch, t, user.roles, user.username]);
|
|
124
|
+
}, children: [_jsx(CardHeader, { title: _jsxs(Stack, { direction: "row", spacing: 1, alignItems: "center", children: [_jsx(Typography, { variant: "h5", children: item.item.name }), item.item.triggers.length > 0 && (_jsx(Tooltip, { title: _jsx(Trans, { i18nKey: "route.actions.trigger.description", values: { triggers: item.item.triggers.join(', ') }, components: { bold: _jsx("strong", {}) } }), children: _jsx(Engineering, {}) })), _jsx(FlexOne, {}), ((item.item.owner_id === user.username && editRoles) || user.roles?.includes('admin')) && (_jsx(IconButton, { size: "small", onClick: e => onDelete(e, item.item.action_id), children: _jsx(Delete, {}) })), _jsx(HowlerAvatar, { sx: { width: 24, height: 24, marginRight: '8px !important' }, userId: item.item.owner_id })] }), subheader: item.item.query }), _jsx(CardContent, { sx: { paddingTop: 0 }, children: _jsx(Grid, { container: true, spacing: 1, children: item.item.operations.map(d => (_jsx(Grid, { item: true, children: _jsx(Chip, { size: "small", label: t(`operations.${d.operation_id}`) }) }, d.operation_id))) }) })] }, item.item.name));
|
|
125
|
+
}, [editRoles, navigate, onDelete, t, user.roles, user.username]);
|
|
115
126
|
return (_jsx(ItemManager, { onSearch: onSearch, onCreate: editRoles ? () => navigate('/action/execute') : undefined, onPageChange: onPageChange, phrase: phrase, setPhrase: setPhrase, hasError: hasError, searching: searching, aboveSearch: _jsx(Typography, { sx: theme => ({ fontStyle: 'italic', color: theme.palette.text.disabled, mb: 0.5 }), variant: "body2", children: t('route.actions.search.prompt') }), searchFilters: _jsx(Autocomplete, { multiple: true, size: "small", value: searchModifiers, onChange: (__, values) => setSearchModifiers(values), getOptionLabel: trigger => t(`route.actions.trigger.${trigger}`), options: VALID_ACTION_TRIGGERS, renderInput: params => (_jsx(TextField, { ...params, sx: { maxWidth: '500px' }, label: t('route.actions.trigger') })) }), renderer: renderer, response: response, createPrompt: "route.actions.create", searchPrompt: "route.actions.search", createIcon: _jsx(Terminal, { sx: { mr: 1 } }) }));
|
|
116
127
|
};
|
|
117
128
|
const ActionSearchProvider = () => {
|
|
118
|
-
return (_jsx(TuiListProvider, { children: _jsx(ActionSearch, {}) }));
|
|
129
|
+
return (_jsx(TuiListProvider, { children: _jsx(SearchResponseProvider, { idField: "action_id", children: _jsx(ActionSearch, {}) }) }));
|
|
119
130
|
};
|
|
120
131
|
export default ActionSearchProvider;
|
|
@@ -233,7 +233,7 @@ const QueryBuilder = () => {
|
|
|
233
233
|
height: '100%',
|
|
234
234
|
'& .MuiFormControl-root': { height: '100%', '& > div': { height: '100%' } }
|
|
235
235
|
}
|
|
236
|
-
], slotProps: { paper: { sx: { minWidth: '600px' } } } }), _jsx(Card, { variant: "outlined", sx: { flex: 1, maxWidth: '350px', minWidth: '210px' }, children: _jsxs(Stack, { spacing: 0.5, sx: { px: 1, alignItems: 'start' }, children: [_jsxs(Typography, { variant: "caption", color: "text.secondary", sx: { whiteSpace: 'nowrap' }, children: [t('route.advanced.rows'), ": ", STEPS[rows]] }), _jsx(Slider, { size: "small", valueLabelDisplay: "off", value: rows, onChange: (_, value) => setRows(value), min: 0, max: 9, step: 1, marks: true, track: false, sx: { py: 0.5 } })] }) })] }), type === 'lucene' && (_jsx(Autocomplete, { size: "small", getOptionLabel: opt => t(`route.advanced.query.type.${opt}`), options: LUCENE_QUERY_OPTIONS, value: queryType, onChange: (_event, value) => setQueryType(value), renderInput: params => (_jsx(TextField, { ...params, label: t('route.advanced.query.lucene.type'), sx: { minWidth: '230px' } })), renderOption: (props, option) => (_jsx(ListItemText, { ...props, sx: { flexDirection: 'column', alignItems: 'start !important' }, primary: t(`route.advanced.query.type.${option}`), secondary: t(`route.advanced.query.type.${option}.description`) })) })), queryType === 'groupby' && (_jsx(Autocomplete, { size: "small", options: fieldOptions, value: groupByField, onChange: (__, value) => setGroupByField(value), renderInput: params => _jsx(TextField, { ...params, label: t('route.advanced.pivot.field') }), sx: { minWidth: '200px', '& label': { zIndex: 1200 } }, onKeyDown: onKeyDown, PopperComponent: CustomPopper })), allFields && queryType !== 'facet' ? (_jsx(FormControlLabel, { control: _jsx(Checkbox, { size: "small", checked: allFields, onChange: (__, checked) => setAllFields(checked) }), label: t('route.advanced.fields.all'), sx: { '& > span': { color: 'text.secondary' }, alignSelf: 'start' } })) : (_jsx(Autocomplete, { fullWidth: true, renderTags: values => values.length <= 3 ? (_jsx(Stack, { direction: "row", spacing: 0.5, children: values.map(_value => (_jsx(Chip, { label: _value }, _value))) })) : (_jsx(Tooltip, { title: _jsx(Stack, { spacing: 1, children: values.map(_value => (_jsx("span", { children: _value }, _value))) }), children: _jsx(Chip, { label: values.length }) })), multiple: true, size: "small", options: fieldOptions, value: fields, onChange: (__, values) => (values.length > 0 ? setFields(values) : setAllFields(true)), renderInput: params => _jsx(TextField, { ...params, label: t('route.advanced.fields') }), sx: { maxWidth: '500px', width: '20vw', minWidth: '200px', '& label': { zIndex: 1200 } }, onKeyDown: onKeyDown, PopperComponent: CustomPopper })), _jsx(FlexOne, {}), type === 'lucene' &&
|
|
236
|
+
], slotProps: { paper: { sx: { minWidth: '600px' } } } }), _jsx(Card, { variant: "outlined", sx: { flex: 1, maxWidth: '350px', minWidth: '210px' }, children: _jsxs(Stack, { spacing: 0.5, sx: { px: 1, alignItems: 'start' }, children: [_jsxs(Typography, { variant: "caption", color: "text.secondary", sx: { whiteSpace: 'nowrap' }, children: [t('route.advanced.rows'), ": ", STEPS[rows]] }), _jsx(Slider, { size: "small", valueLabelDisplay: "off", value: rows, onChange: (_, value) => setRows(value), min: 0, max: 9, step: 1, marks: true, track: false, sx: { py: 0.5 } })] }) })] }), type === 'lucene' && (_jsx(Autocomplete, { size: "small", getOptionLabel: opt => t(`route.advanced.query.type.${opt}`), options: LUCENE_QUERY_OPTIONS, value: queryType, onChange: (_event, value) => setQueryType(value), renderInput: params => (_jsx(TextField, { ...params, label: t('route.advanced.query.lucene.type'), sx: { minWidth: '230px' } })), renderOption: (props, option) => (_jsx(ListItemText, { ...props, sx: { flexDirection: 'column', alignItems: 'start !important' }, primary: t(`route.advanced.query.type.${option}`), secondary: t(`route.advanced.query.type.${option}.description`) })) })), queryType === 'groupby' && (_jsx(Autocomplete, { size: "small", options: fieldOptions, value: groupByField, onChange: (__, value) => setGroupByField(value), renderInput: params => _jsx(TextField, { ...params, label: t('route.advanced.pivot.field') }), sx: { minWidth: '200px', '& label': { zIndex: 1200 } }, onKeyDown: onKeyDown, PopperComponent: CustomPopper })), allFields && queryType !== 'facet' ? (_jsx(FormControlLabel, { control: _jsx(Checkbox, { size: "small", checked: allFields, onChange: (__, checked) => setAllFields(checked) }), label: t('route.advanced.fields.all'), sx: { '& > span': { color: 'text.secondary' }, alignSelf: 'start' } })) : (_jsx(Autocomplete, { fullWidth: true, renderTags: values => values.length <= 3 ? (_jsx(Stack, { direction: "row", spacing: 0.5, children: values.map(_value => (_jsx(Chip, { size: "small", label: _value }, _value))) })) : (_jsx(Tooltip, { title: _jsx(Stack, { spacing: 1, children: values.map(_value => (_jsx("span", { children: _value }, _value))) }), children: _jsx(Chip, { size: "small", label: values.length }) })), multiple: true, size: "small", options: fieldOptions, value: fields, onChange: (__, values) => (values.length > 0 ? setFields(values) : setAllFields(true)), renderInput: params => _jsx(TextField, { ...params, label: t('route.advanced.fields') }), sx: { maxWidth: '500px', width: '20vw', minWidth: '200px', '& label': { zIndex: 1200 } }, onKeyDown: onKeyDown, PopperComponent: CustomPopper })), _jsx(FlexOne, {}), type === 'lucene' &&
|
|
237
237
|
(smallButtons ? (_jsx(Tooltip, { title: t('route.advanced.open'), children: _jsx(IconButton, { color: "primary", sx: { alignSelf: 'center' }, component: Link, disabled: !response, to: `/hits?query=${sanitizeMultilineLucene(query).replaceAll('\n', ' ').trim()}`, children: _jsx(OpenInNew, { fontSize: "small" }) }) })) : (_jsx(CustomButton, { size: "small", variant: "outlined", startIcon: _jsx(OpenInNew, {}), component: Link, disabled: !response, ...{ to: `/hits?query=${sanitizeMultilineLucene(query).replaceAll('\n', ' ').trim()}` }, children: t('route.advanced.open') }))), smallButtons ? (_jsx(Tooltip, { title: response ? t('route.advanced.create.rule') : t('route.advanced.create.rule.disabled'), children: _jsx(IconButton, { size: "small", sx: { alignSelf: 'center' }, color: "info", onClick: onCreateRule, disabled: !response, children: _jsx(SsidChart, {}) }) })) : (_jsx(CustomButton, { size: "small", variant: "outlined", color: "info", startIcon: _jsx(SsidChart, {}), onClick: onCreateRule, disabled: !response, ...{ to: `/hits?query=${sanitizeMultilineLucene(query).replaceAll('\n', ' ').trim()}` }, tooltip: !response && t('route.advanced.create.rule.disabled'), children: t('route.advanced.create.rule') }))] }), _jsxs(Box, { width: "100%", height: "calc(100vh - 112px)", sx: { position: 'relative', overflow: 'hidden', borderTop: `thin solid ${theme.palette.divider}` }, children: [_jsx(Box, { sx: {
|
|
238
238
|
position: 'absolute',
|
|
239
239
|
top: 0,
|
|
@@ -2,7 +2,7 @@ import { jsx as _jsx } from "react/jsx-runtime";
|
|
|
2
2
|
import { useMonaco } from '@monaco-editor/react';
|
|
3
3
|
import { Box, useTheme } from '@mui/material';
|
|
4
4
|
import { ApiConfigContext } from '@cccsaurora/howler-ui/components/app/providers/ApiConfigProvider';
|
|
5
|
-
import {
|
|
5
|
+
import { HitSearchContext } from '@cccsaurora/howler-ui/components/app/providers/HitSearchProvider';
|
|
6
6
|
import ThemedEditor from '@cccsaurora/howler-ui/components/elements/ThemedEditor';
|
|
7
7
|
import { memo, useCallback, useContext, useEffect, useMemo } from 'react';
|
|
8
8
|
import { useContextSelector } from 'use-context-selector';
|
|
@@ -20,8 +20,8 @@ const QueryEditor = ({ query, setQuery, onMount, language = 'lucene', fontSize =
|
|
|
20
20
|
const yamlCompletion = useYamlCompletionProvider();
|
|
21
21
|
const eqlCompletion = useEQLCompletionProvider();
|
|
22
22
|
const historyCompletion = useHistoryCompletionProvider();
|
|
23
|
-
const fzfSearch = useContextSelector(
|
|
24
|
-
const setFzfSearch = useContextSelector(
|
|
23
|
+
const fzfSearch = useContextSelector(HitSearchContext, ctx => ctx?.fzfSearch ?? false);
|
|
24
|
+
const setFzfSearch = useContextSelector(HitSearchContext, ctx => ctx?.setFzfSearch);
|
|
25
25
|
const beforeEditorMount = useCallback((_monaco) => {
|
|
26
26
|
_monaco.languages.register({ id: 'lucene' });
|
|
27
27
|
_monaco.languages.register({ id: 'eql' });
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
import { useMonaco } from '@monaco-editor/react';
|
|
2
|
-
import {
|
|
2
|
+
import { HitSearchContext } from '@cccsaurora/howler-ui/components/app/providers/HitSearchProvider';
|
|
3
3
|
import Fuse from 'fuse.js';
|
|
4
4
|
import { useMemo } from 'react';
|
|
5
5
|
import { useContextSelector } from 'use-context-selector';
|
|
6
6
|
import { twitterShort } from '@cccsaurora/howler-ui/utils/utils';
|
|
7
7
|
const useHistoryCompletionProvider = () => {
|
|
8
8
|
const monaco = useMonaco();
|
|
9
|
-
const fzfSearch = useContextSelector(
|
|
10
|
-
const queryHistory = useContextSelector(
|
|
9
|
+
const fzfSearch = useContextSelector(HitSearchContext, ctx => ctx?.fzfSearch);
|
|
10
|
+
const queryHistory = useContextSelector(HitSearchContext, ctx => ctx?.queryHistory ?? {});
|
|
11
11
|
// Using fuse for fuzzy searching
|
|
12
12
|
const fuse = useMemo(() => new Fuse(Object.keys(queryHistory), { keys: ['key'], threshold: 0.4 }), [queryHistory]);
|
|
13
13
|
return {
|
|
@@ -5,6 +5,7 @@ import api from '@cccsaurora/howler-ui/api';
|
|
|
5
5
|
import { useAppUser } from '@cccsaurora/howler-ui/commons/components/app/hooks';
|
|
6
6
|
import PageCenter from '@cccsaurora/howler-ui/commons/components/pages/PageCenter';
|
|
7
7
|
import { ApiConfigContext } from '@cccsaurora/howler-ui/components/app/providers/ApiConfigProvider';
|
|
8
|
+
import { ModalContext } from '@cccsaurora/howler-ui/components/app/providers/ModalProvider';
|
|
8
9
|
import { UserListContext } from '@cccsaurora/howler-ui/components/app/providers/UserListProvider';
|
|
9
10
|
import UserList from '@cccsaurora/howler-ui/components/elements/UserList';
|
|
10
11
|
import HowlerAvatar from '@cccsaurora/howler-ui/components/elements/display/HowlerAvatar';
|
|
@@ -31,6 +32,7 @@ const AnalyticDetails = () => {
|
|
|
31
32
|
const { dispatchApi } = useMyApi();
|
|
32
33
|
const theme = useTheme();
|
|
33
34
|
const { showSuccessMessage } = useMySnackbar();
|
|
35
|
+
const { withConfirmDeleteModal } = useContext(ModalContext);
|
|
34
36
|
const { users, searchUsers } = useContext(UserListContext);
|
|
35
37
|
const { config } = useContext(ApiConfigContext);
|
|
36
38
|
const [analytic, setAnalytic] = useState(null);
|
|
@@ -51,18 +53,20 @@ const AnalyticDetails = () => {
|
|
|
51
53
|
_setFilter(detection);
|
|
52
54
|
}
|
|
53
55
|
}, [filter]);
|
|
54
|
-
const onOwnerChange = useCallback(async (
|
|
56
|
+
const onOwnerChange = useCallback(async (ownerId) => {
|
|
55
57
|
const result = await dispatchApi(api.analytic.owner.post(analytic.analytic_id, { username: ownerId }), {
|
|
56
58
|
throwError: true,
|
|
57
59
|
showError: true
|
|
58
60
|
});
|
|
59
61
|
setAnalytic(result);
|
|
60
62
|
}, [analytic?.analytic_id, dispatchApi]);
|
|
61
|
-
const onDelete = useCallback(
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
63
|
+
const onDelete = useCallback(() => {
|
|
64
|
+
withConfirmDeleteModal(async () => {
|
|
65
|
+
await dispatchApi(api.analytic.del(analytic?.analytic_id, 'wait_for'));
|
|
66
|
+
showSuccessMessage(t('route.analytics.deleted'));
|
|
67
|
+
navigate('/analytics');
|
|
68
|
+
});
|
|
69
|
+
}, [analytic?.analytic_id, dispatchApi, navigate, withConfirmDeleteModal, showSuccessMessage, t]);
|
|
66
70
|
const onEdit = useCallback(async () => {
|
|
67
71
|
if (editingInterval) {
|
|
68
72
|
setIntervalLoading(true);
|
|
@@ -108,14 +112,14 @@ const AnalyticDetails = () => {
|
|
|
108
112
|
marginTop: '0 !important',
|
|
109
113
|
marginLeft: `${theme.spacing(-1)} !important`,
|
|
110
114
|
marginRight: `${theme.spacing(-1)} !important`
|
|
111
|
-
},
|
|
115
|
+
}, userId: analytic?.owner, onChange: onOwnerChange, i18nLabel: "route.analytics.set.owner" })) : (_jsx(HowlerAvatar, { userId: analytic?.owner })), _jsx(Stack, { children: users[analytic?.owner] ? (_jsxs(_Fragment, { children: [_jsx(Typography, { variant: "body1", children: users[analytic?.owner].name }), _jsx(Typography, { component: "a", href: `mailto:${users[analytic?.owner].email}`, variant: "caption", color: "text.secondary", children: users[analytic?.owner].email })] })) : (_jsxs(_Fragment, { children: [_jsx(Skeleton, { variant: "text", width: "70px" }), _jsx(Skeleton, { variant: "text", width: "60px" })] })) })] })] }), filteredContributors.length > 0 && (_jsxs(Stack, { spacing: 1, children: [_jsx(Typography, { variant: "body1", color: "text.secondary", children: t('route.analytics.contributors') }), _jsx(Stack, { direction: "row", alignItems: "center", spacing: 1, children: filteredContributors.map(_user => (_jsx(HowlerAvatar, { userId: _user }, _user))) })] })), analytic?.rule_crontab && (_jsxs(Stack, { direction: "row", spacing: 1, children: [_jsxs(Stack, { spacing: 1, justifyContent: "space-between", children: [_jsx(Typography, { variant: "body1", color: "text.secondary", children: t('rule.interval') }), editingInterval ? (_jsxs(FormControl, { sx: { minWidth: '200px' }, children: [_jsx(InputLabel, { children: t('rule.interval') }), _jsx(Select, { size: "small", label: t('rule.interval'), onChange: event => setCrontab(event.target.value), value: crontab, children: RULE_INTERVALS.map(interval => (_jsx(MenuItem, { value: interval.crontab, children: t(interval.key) }, interval.key))) })] })) : (_jsx("code", { style: {
|
|
112
116
|
backgroundColor: theme.palette.background.paper,
|
|
113
117
|
padding: theme.spacing(0.5),
|
|
114
118
|
alignSelf: 'start',
|
|
115
119
|
borderRadius: theme.shape.borderRadius,
|
|
116
120
|
border: `thin solid ${theme.palette.divider}`,
|
|
117
121
|
width: '100%'
|
|
118
|
-
}, children: analytic.rule_crontab }))] }), (analytic?.owner === user.username || user.roles.includes('admin')) && (_jsx(Tooltip, { title: editingInterval ? t('rule.interval.save') : t('rule.interval.edit'), children: _jsx(IconButton, { disabled: intervalLoading, sx: { alignSelf: 'end' }, onClick: onEdit, children: intervalLoading ? _jsx(CircularProgress, { size: 20 }) : editingInterval ? _jsx(Check, {}) : _jsx(Edit, {}) }) }))] }))] }), _jsxs(Grid, { container: true, children: [_jsx(Grid, { item: true, xs: 12, md: 9, children: _jsxs(Tabs, { value: tab, onChange: (_, _tab) => setTab(_tab), children: [_jsx(Tab, { label: t('route.analytics.tab.overview'), value: "overview" }), _jsx(Tab, { label: t('route.analytics.tab.comments'), value: "comments" }), _jsx(Tab, { label: t('route.analytics.tab.hit_comments'), value: "hit_comments" }), _jsx(Tab, { label: t('route.analytics.tab.templates'), value: "templates" }), _jsx(Tab, { label: t('route.analytics.tab.overviews'), value: "overviews" }), analytic?.rule && _jsx(Tab, { label: t('route.analytics.tab.rule'), value: "rule" }), config?.configuration.features.notebook && (_jsx(Tab, { label: t('route.analytics.tab.notebooks'), value: "notebooks" })), _jsx(Tab, { label: t('route.analytics.tab.triage'), value: "triage" })] }) }), ['comments', 'hit_comments'].includes(tab) && (_jsx(Grid, { item: true, xs: 12, md: 3, children: _jsx(Autocomplete, { options: analytic?.detections ?? [], renderInput: param => _jsx(TextField, { ...param, label:
|
|
122
|
+
}, children: analytic.rule_crontab }))] }), (analytic?.owner === user.username || user.roles.includes('admin')) && (_jsx(Tooltip, { title: editingInterval ? t('rule.interval.save') : t('rule.interval.edit'), children: _jsx(IconButton, { disabled: intervalLoading, sx: { alignSelf: 'end' }, onClick: onEdit, children: intervalLoading ? _jsx(CircularProgress, { size: 20 }) : editingInterval ? _jsx(Check, {}) : _jsx(Edit, {}) }) }))] }))] }), _jsxs(Grid, { container: true, children: [_jsx(Grid, { item: true, xs: 12, md: 9, children: _jsxs(Tabs, { value: tab, onChange: (_, _tab) => setTab(_tab), children: [_jsx(Tab, { label: t('route.analytics.tab.overview'), value: "overview" }), _jsx(Tab, { label: t('route.analytics.tab.comments'), value: "comments" }), _jsx(Tab, { label: t('route.analytics.tab.hit_comments'), value: "hit_comments" }), _jsx(Tab, { label: t('route.analytics.tab.templates'), value: "templates" }), _jsx(Tab, { label: t('route.analytics.tab.overviews'), value: "overviews" }), analytic?.rule && _jsx(Tab, { label: t('route.analytics.tab.rule'), value: "rule" }), config?.configuration.features.notebook && (_jsx(Tab, { label: t('route.analytics.tab.notebooks'), value: "notebooks" })), _jsx(Tab, { label: t('route.analytics.tab.triage'), value: "triage" })] }) }), ['comments', 'hit_comments'].includes(tab) && (_jsx(Grid, { item: true, xs: 12, md: 3, children: _jsx(Autocomplete, { options: analytic?.detections ?? [], renderInput: param => _jsx(TextField, { ...param, label: t('route.analytics.dropdown.detection') }), value: filter, onChange: (_, v) => setFilter(v) }) }))] }), {
|
|
119
123
|
comments: _jsx(AnalyticComments, { analytic: analytic, setAnalytic: setAnalytic }),
|
|
120
124
|
hit_comments: _jsx(AnalyticHitComments, { analytic: analytic }),
|
|
121
125
|
overview: _jsx(AnalyticOverview, { analytic: analytic, setAnalytic: setAnalytic }),
|
|
@@ -4,6 +4,7 @@ import { AvatarGroup, Card, CardContent, CardHeader, Chip, Divider, Grid, IconBu
|
|
|
4
4
|
import api from '@cccsaurora/howler-ui/api';
|
|
5
5
|
import { useAppUser } from '@cccsaurora/howler-ui/commons/components/app/hooks';
|
|
6
6
|
import useLocalStorageItem from '@cccsaurora/howler-ui/commons/components/utils/hooks/useLocalStorageItem';
|
|
7
|
+
import SearchResponseProvider, { SearchResponseContext } from '@cccsaurora/howler-ui/components/app/providers/SearchResponseProvider';
|
|
7
8
|
import FlexOne from '@cccsaurora/howler-ui/components/elements/addons/layout/FlexOne';
|
|
8
9
|
import { TuiListProvider } from '@cccsaurora/howler-ui/components/elements/addons/lists';
|
|
9
10
|
import { TuiListMethodContext } from '@cccsaurora/howler-ui/components/elements/addons/lists/TuiListProvider';
|
|
@@ -25,12 +26,12 @@ const AnalyticSearchBase = () => {
|
|
|
25
26
|
const [searchParams, setSearchParams] = useSearchParams();
|
|
26
27
|
const pageCount = useMyLocalStorageItem(StorageKey.PAGE_COUNT, 25)[0];
|
|
27
28
|
const appUser = useAppUser();
|
|
29
|
+
const { response, request } = useContext(SearchResponseContext);
|
|
28
30
|
const [onlyRules, setOnlyRules] = useLocalStorageItem(StorageKey.ONLY_RULES, 0);
|
|
29
31
|
const [searching, setSearching] = useState(false);
|
|
30
32
|
const [hasError, setHasError] = useState(false);
|
|
31
33
|
const [phrase, setPhrase] = useState(searchParams.get('phrase') || '');
|
|
32
34
|
const [offset, setOffset] = useState(parseInt(searchParams.get('offset')) || 0);
|
|
33
|
-
const [response, setResponse] = useState(null);
|
|
34
35
|
const addFavourite = useCallback(async (analytic) => {
|
|
35
36
|
await dispatchApi(api.analytic.favourite.post(analytic.analytic_id));
|
|
36
37
|
appUser.setUser({
|
|
@@ -58,13 +59,12 @@ const AnalyticSearchBase = () => {
|
|
|
58
59
|
setSearchParams(searchParams, { replace: true });
|
|
59
60
|
try {
|
|
60
61
|
const sanitizedPhrase = sanitizeLuceneQuery(phrase);
|
|
61
|
-
const _response = await
|
|
62
|
+
const _response = await request(api.search.analytic.post, {
|
|
62
63
|
query: `name:*${sanitizedPhrase}* OR detections:*${sanitizedPhrase}*` +
|
|
63
64
|
(onlyRules > 0 ? ' AND _exists_:rule_type' : onlyRules < 0 ? ' AND -_exists_:rule_type' : ''),
|
|
64
65
|
rows: pageCount,
|
|
65
66
|
offset
|
|
66
|
-
})
|
|
67
|
-
setResponse(_response);
|
|
67
|
+
});
|
|
68
68
|
load(_response.items.map(u => ({ id: u.analytic_id, item: u })));
|
|
69
69
|
}
|
|
70
70
|
catch (e) {
|
|
@@ -73,7 +73,7 @@ const AnalyticSearchBase = () => {
|
|
|
73
73
|
finally {
|
|
74
74
|
setSearching(false);
|
|
75
75
|
}
|
|
76
|
-
}, [
|
|
76
|
+
}, [request, load, offset, onlyRules, pageCount, phrase, searchParams, setSearchParams]);
|
|
77
77
|
const onPageChange = useCallback((_offset) => {
|
|
78
78
|
if (_offset !== offset) {
|
|
79
79
|
searchParams.set('offset', _offset.toString());
|
|
@@ -128,11 +128,11 @@ const AnalyticSearchBase = () => {
|
|
|
128
128
|
padding: theme.spacing(0.5),
|
|
129
129
|
borderRadius: theme.shape.borderRadius,
|
|
130
130
|
border: `thin solid ${theme.palette.divider}`
|
|
131
|
-
}, children: item.item.rule_type })] })), _jsx(FlexOne, {}), _jsxs(Stack, { direction: "row", spacing: 1, sx: { mt: 1 }, children: [item.item.owner && _jsx(HowlerAvatar, { sx: { width: 24, height: 24 }, userId: item.item.owner }), filteredContributors.length > 0 && _jsx(Divider, { orientation: "vertical", flexItem: true }), _jsx(AvatarGroup, { children: filteredContributors.map(contributor => (_jsx(HowlerAvatar, { sx: { width: 24, height: 24 }, userId: contributor }, contributor))) })] }), _jsx(Tooltip, { title: t('button.pin'), children: _jsx(IconButton, { size: "small", onClick: e => onFavourite(e, item.item), children: appUser.user?.favourite_analytics?.includes(item.item.analytic_id) ? _jsx(Star, {}) : _jsx(StarBorder, {}) }) })] }) }), item.item.detections?.length > 0 && (_jsx(CardContent, { sx: { paddingTop: 0 }, children: _jsxs(Grid, { container: true, spacing: 0.5, sx: { marginTop: `${theme.spacing(-0.5)} !important` }, children: [item.item.detections.slice(0, 5).map(d => (_jsx(Grid, { item: true, children: _jsx(Chip, { variant: "outlined", label: d }) }, d))), item.item.detections.length > 5 && (_jsx(Grid, { item: true, children: _jsx(Tooltip, { title: _jsx(Stack, { children: item.item.detections.slice(5).map(d => (_jsx("span", { children: d }, d))) }), children: _jsx(Chip, { variant: "outlined", label: `+ ${item.item.detections.length - 5}` }) }) }))] }) }))] }, item.item.name));
|
|
131
|
+
}, children: item.item.rule_type })] })), _jsx(FlexOne, {}), _jsxs(Stack, { direction: "row", spacing: 1, sx: { mt: 1 }, children: [item.item.owner && _jsx(HowlerAvatar, { sx: { width: 24, height: 24 }, userId: item.item.owner }), filteredContributors.length > 0 && _jsx(Divider, { orientation: "vertical", flexItem: true }), _jsx(AvatarGroup, { children: filteredContributors.map(contributor => (_jsx(HowlerAvatar, { sx: { width: 24, height: 24 }, userId: contributor }, contributor))) })] }), _jsx(Tooltip, { title: t('button.pin'), children: _jsx(IconButton, { size: "small", onClick: e => onFavourite(e, item.item), children: appUser.user?.favourite_analytics?.includes(item.item.analytic_id) ? _jsx(Star, {}) : _jsx(StarBorder, {}) }) })] }) }), item.item.detections?.length > 0 && (_jsx(CardContent, { sx: { paddingTop: 0 }, children: _jsxs(Grid, { container: true, spacing: 0.5, sx: { marginTop: `${theme.spacing(-0.5)} !important` }, children: [item.item.detections.slice(0, 5).map(d => (_jsx(Grid, { item: true, children: _jsx(Chip, { size: "small", variant: "outlined", label: d }) }, d))), item.item.detections.length > 5 && (_jsx(Grid, { item: true, children: _jsx(Tooltip, { title: _jsx(Stack, { children: item.item.detections.slice(5).map(d => (_jsx("span", { children: d }, d))) }), children: _jsx(Chip, { size: "small", variant: "outlined", label: `+ ${item.item.detections.length - 5}` }) }) }))] }) }))] }, item.item.name));
|
|
132
132
|
}, [appUser.user?.favourite_analytics, navigate, onFavourite, t, theme]);
|
|
133
133
|
return (_jsx(ItemManager, { onSearch: onSearch, onPageChange: onPageChange, phrase: phrase, setPhrase: setPhrase, hasError: hasError, searching: searching, searchAdornment: _jsx(InputAdornment, { position: "end", children: _jsx(Tooltip, { title: t(`route.analytics.search.filter.rules.${onlyRules < 0 ? 'hide' : onlyRules > 0 ? 'show' : 'toggle'}`), children: _jsx(IconButton, { onClick: () => setOnlyRules((((onlyRules + 2) % 3) - 1)), children: _jsx(SsidChart, { color: onlyRules < 0 ? 'error' : onlyRules > 0 ? 'info' : 'inherit', sx: { transition: theme.transitions.create(['color']) } }) }) }) }), aboveSearch: _jsx(Typography, { sx: { fontStyle: 'italic', color: theme.palette.text.disabled, mb: 0.5 }, variant: "body2", children: t('route.analytics.search.prompt') }), renderer: renderer, response: response, searchPrompt: "route.analytics.manager.search" }));
|
|
134
134
|
};
|
|
135
135
|
const AnalyticSearch = () => {
|
|
136
|
-
return (_jsx(TuiListProvider, { children: _jsx(AnalyticSearchBase, {}) }));
|
|
136
|
+
return (_jsx(TuiListProvider, { children: _jsx(SearchResponseProvider, { idField: "analytic_id", children: _jsx(AnalyticSearchBase, {}) }) }));
|
|
137
137
|
};
|
|
138
138
|
export default AnalyticSearch;
|
|
@@ -13,7 +13,7 @@ import { useTranslation } from 'react-i18next';
|
|
|
13
13
|
import { useNavigate, useParams, useSearchParams } from 'react-router-dom';
|
|
14
14
|
import { useContextSelector } from 'use-context-selector';
|
|
15
15
|
import QueryResultText from '../../elements/display/QueryResultText';
|
|
16
|
-
import
|
|
16
|
+
import HitQuery from '../hits/search/HitQuery';
|
|
17
17
|
import LeadForm from './LeadForm';
|
|
18
18
|
import PivotForm from './PivotForm';
|
|
19
19
|
const DossierEditor = () => {
|
|
@@ -188,6 +188,6 @@ const DossierEditor = () => {
|
|
|
188
188
|
fontSize: '0.9em',
|
|
189
189
|
fontStyle: 'italic',
|
|
190
190
|
mb: 0.5
|
|
191
|
-
}), variant: "body2", children: t('hit.search.prompt') }), _jsx(
|
|
191
|
+
}), variant: "body2", children: t('hit.search.prompt') }), _jsx(HitQuery, { disabled: !dossier || loading, onChange: (_val, isDirty) => setSearchDirty(isDirty), triggerSearch: query => setDossier(_dossier => ({ ..._dossier, query })) }), searchTotal >= 0 && _jsx(QueryResultText, { count: searchTotal, query: dossier.query })] }) }), _jsxs(Tabs, { value: tab, onChange: (_ev, value) => setTab(value), children: [_jsx(Tab, { label: t('route.dossiers.manager.tabs.leads'), value: "leads" }), _jsx(Tab, { label: t('route.dossiers.manager.tabs.pivots'), value: "pivots" })] }), tab === 'leads' && _jsx(LeadForm, { dossier: dossier, setDossier: setDossier, loading: loading }), tab === 'pivots' && _jsx(PivotForm, { dossier: dossier, setDossier: setDossier, loading: loading })] })] }) }));
|
|
192
192
|
};
|
|
193
193
|
export default memo(DossierEditor);
|
|
@@ -61,7 +61,7 @@ vi.mock('commons/components/pages/PageCenter', () => ({
|
|
|
61
61
|
vi.mock('../../elements/display/QueryResultText', () => ({
|
|
62
62
|
default: ({ count, query }) => (_jsxs("div", { id: "query-result-text", children: [count, " ", ' results for ', " ", query] }))
|
|
63
63
|
}));
|
|
64
|
-
vi.mock('../hits/search/
|
|
64
|
+
vi.mock('../hits/search/HitQuery', () => ({
|
|
65
65
|
default: ({ onChange, triggerSearch, disabled }) => {
|
|
66
66
|
return (_jsxs("div", { id: "hit-query", children: [_jsx("input", { id: "query-input", disabled: disabled, onChange: e => {
|
|
67
67
|
onChange?.(e.target.value, false);
|