@cccsaurora/howler-ui 3.1.0-dev.1493 → 3.1.0-dev.1607
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/execute.d.ts +1 -1
- package/api/action/index.d.ts +10 -6
- package/api/action/index.js +5 -9
- package/api/action/operations.js +2 -2
- package/api/analytic/comments/index.d.ts +4 -6
- package/api/analytic/comments/react.d.ts +2 -2
- package/api/analytic/favourite.d.ts +2 -4
- package/api/analytic/index.d.ts +7 -4
- package/api/analytic/index.js +2 -2
- package/api/analytic/notebooks/index.d.ts +2 -4
- package/api/analytic/owner.d.ts +1 -1
- package/api/auth/apikey.d.ts +2 -2
- package/api/auth/login.d.ts +2 -2
- package/api/configs/index.d.ts +1 -1
- package/api/dossier.d.ts +16 -0
- package/api/{dossier/index.js → dossier.js} +6 -4
- package/api/help.d.ts +2 -2
- package/api/hit/assign.d.ts +6 -2
- package/api/hit/comments/index.d.ts +4 -6
- package/api/hit/comments/react.d.ts +2 -2
- package/api/hit/index.d.ts +3 -8
- package/api/hit/labels.d.ts +2 -2
- package/api/hit/overwrite.d.ts +1 -1
- package/api/hit/transition.d.ts +1 -1
- package/api/index.d.ts +6 -6
- package/api/index.js +7 -6
- package/api/notebook/environments.d.ts +1 -1
- package/api/notebook/index.d.ts +1 -1
- package/api/overview/index.d.ts +4 -4
- package/api/search/action.d.ts +1 -1
- package/api/search/analytic.d.ts +1 -1
- package/api/search/case.d.ts +1 -1
- package/api/search/count/hit.d.ts +1 -1
- package/api/search/dossier.d.ts +1 -1
- package/api/search/eql/hit.d.ts +1 -1
- package/api/search/explain/hit.d.ts +1 -1
- package/api/search/facet/hit.d.ts +1 -1
- package/api/search/fields/hit.js +1 -2
- package/api/search/fields/user.js +2 -4
- package/api/search/grouped/hit.d.ts +1 -1
- package/api/search/grouped/user.js +3 -0
- package/api/search/histogram/hit.d.ts +1 -1
- package/api/search/hit.d.ts +1 -1
- package/api/search/overview.d.ts +1 -1
- package/api/search/sigma/hit.d.ts +1 -1
- package/api/search/template.d.ts +1 -1
- package/api/search/user.d.ts +30 -2
- package/api/search/user.js +3 -0
- package/api/search/view.d.ts +1 -1
- package/api/socket/viewers.d.ts +1 -1
- package/api/socket/viewers.js +1 -1
- package/api/template/index.d.ts +3 -3
- package/api/template/index.js +2 -2
- package/api/user/avatar/index.d.ts +1 -1
- package/api/user/groups.d.ts +1 -1
- package/api/user/index.d.ts +2 -2
- package/api/user/whoami.d.ts +1 -1
- package/api/utils/createPermissionsApi.d.ts +10 -0
- package/api/utils/createPermissionsApi.js +10 -0
- package/api/v2/case/index.d.ts +4 -4
- package/api/v2/case/items.d.ts +3 -3
- package/api/v2/case/rules.d.ts +3 -3
- package/api/v2/fuzzy.d.ts +1 -1
- package/api/v2/search/facet.d.ts +1 -1
- package/api/v2/search/index.d.ts +1 -1
- package/api/view/favourite.d.ts +2 -4
- package/api/view/index.d.ts +9 -5
- package/api/view/index.js +3 -1
- package/branding/AppBrand.d.ts +2 -2
- package/branding/AppBrand.js +4 -6
- package/components/app/App.js +248 -51
- package/components/app/AppContainer.js +1 -1
- package/components/app/drawers/ApiKeyDrawer.js +13 -5
- package/components/app/drawers/AssignUserDrawer.js +11 -4
- package/components/app/hooks/useMatchers.d.ts +3 -3
- package/components/app/hooks/useMatchers.js +12 -12
- package/components/app/hooks/useMatchers.test.js +15 -14
- package/components/app/hooks/useTitle.js +8 -7
- package/components/app/providers/AnalyticProvider.d.ts +1 -1
- package/components/app/providers/AnalyticProvider.js +7 -4
- package/components/app/providers/ApiConfigProvider.d.ts +2 -1
- package/components/app/providers/ApiConfigProvider.js +12 -10
- package/components/app/providers/AppDrawerProvider.js +2 -2
- package/components/app/providers/AvatarProvider.js +18 -11
- package/components/app/providers/FavouritesProvider.js +56 -86
- package/components/app/providers/FieldProvider.js +1 -1
- package/components/app/providers/GridColumnsProvider.d.ts +1 -1
- package/components/app/providers/GridColumnsProvider.js +17 -4
- package/components/app/providers/GridColumnsProvider.test.js +2 -1
- package/components/app/providers/LocalStorageProvider.d.ts +2 -2
- package/components/app/providers/LocalStorageProvider.js +4 -3
- package/components/app/providers/ModalProvider.js +8 -1
- package/components/app/providers/OverviewProvider.js +10 -2
- package/components/app/providers/ParameterProvider.d.ts +7 -7
- package/components/app/providers/ParameterProvider.js +42 -5
- package/components/app/providers/ParameterProvider.test.js +1 -0
- package/components/app/providers/RecordProvider.js +7 -1
- package/components/app/providers/RecordSearchProvider.d.ts +1 -2
- package/components/app/providers/RecordSearchProvider.js +32 -23
- package/components/app/providers/RecordSearchProvider.test.js +2 -1
- package/components/app/providers/SearchResponseProvider.d.ts +9 -6
- package/components/app/providers/SearchResponseProvider.js +37 -19
- package/components/app/providers/SearchResponseProvider.test.js +37 -11
- package/components/app/providers/SocketProvider.js +6 -4
- package/components/app/providers/UserListProvider.d.ts +1 -1
- package/components/app/providers/ViewProvider.d.ts +2 -2
- package/components/app/providers/ViewProvider.js +22 -12
- package/components/app/providers/ViewProvider.test.js +2 -2
- package/components/app/providers/contextUtils.d.ts +1 -0
- package/components/app/providers/contextUtils.js +3 -0
- package/components/elements/Comment.d.ts +1 -1
- package/components/elements/Comment.js +11 -9
- package/components/elements/ContextMenu.js +1 -1
- package/components/elements/ContextMenu.test.js +2 -2
- package/components/elements/EditRow.d.ts +9 -4
- package/components/elements/EditRow.js +5 -4
- package/components/elements/MarkdownEditor.js +1 -1
- package/components/elements/MembershipManagement.test.js +178 -0
- package/components/elements/ObjectDetails.js +6 -6
- package/components/elements/ThemedEditor.js +17 -17
- package/components/elements/UserList.d.ts +2 -0
- package/components/elements/UserList.js +26 -18
- package/components/elements/UserList.test.js +24 -1
- package/components/elements/addons/buttons/CustomButton.d.ts +1 -1
- package/components/elements/addons/buttons/CustomButton.js +2 -2
- package/components/elements/addons/buttons/CustomIconButton.d.ts +1 -1
- package/components/elements/addons/buttons/CustomIconButton.js +3 -3
- package/components/elements/addons/buttons/index.d.ts +1 -1
- package/components/elements/addons/layout/FlexOne.d.ts +2 -2
- package/components/elements/addons/layout/FlexOne.test.js +1 -0
- package/components/elements/addons/layout/FlexPort.d.ts +1 -1
- package/components/elements/addons/layout/FlexPort.js +9 -2
- package/components/elements/addons/layout/FlexVertical.d.ts +2 -2
- package/components/elements/addons/layout/FlexVertical.js +1 -1
- package/components/elements/addons/layout/vsbox/VSBox.d.ts +2 -2
- package/components/elements/addons/layout/vsbox/VSBox.js +5 -4
- package/components/elements/addons/layout/vsbox/VSBoxElement.d.ts +1 -1
- package/components/elements/addons/layout/vsbox/VSBoxHeader.js +4 -3
- package/components/elements/addons/lists/TuiList.d.ts +2 -2
- package/components/elements/addons/lists/TuiList.js +1 -1
- package/components/elements/addons/lists/TuiListBase.d.ts +2 -2
- package/components/elements/addons/lists/TuiListBase.js +4 -4
- package/components/elements/addons/lists/TuiListElement.d.ts +2 -2
- package/components/elements/addons/lists/TuiListElement.js +2 -2
- package/components/elements/addons/lists/TuiListMenu.d.ts +13 -37
- package/components/elements/addons/lists/TuiListMenu.js +8 -8
- package/components/elements/addons/lists/TuiListProvider.d.ts +2 -2
- package/components/elements/addons/lists/TuiListProvider.js +4 -4
- package/components/elements/addons/lists/hooks/useTuiListKeyboard.js +1 -1
- package/components/elements/addons/lists/table/TuiTable.d.ts +1 -1
- package/components/elements/addons/lists/table/TuiTable.js +1 -1
- package/components/elements/addons/lists/table/TuiTableBody.d.ts +1 -1
- package/components/elements/addons/lists/table/TuiTableBody.js +1 -1
- package/components/elements/addons/lists/table/TuiTableHead.d.ts +1 -1
- package/components/elements/addons/lists/table/TuiTableHead.js +1 -1
- package/components/elements/addons/lists/table/TuiTableHeader.d.ts +1 -1
- package/components/elements/addons/lists/table/TuiTableLayout.js +1 -1
- package/components/elements/addons/search/SearchPagination.d.ts +1 -1
- package/components/elements/addons/search/SearchPagination.test.js +1 -1
- package/components/elements/addons/search/SearchTotal.d.ts +1 -1
- package/components/elements/addons/search/phrase/Phrase.d.ts +2 -2
- package/components/elements/addons/search/phrase/Phrase.js +7 -7
- package/components/elements/addons/search/phrase/PhraseConsumer.d.ts +2 -2
- package/components/elements/addons/search/phrase/PhraseLexer.d.ts +1 -1
- package/components/elements/addons/search/phrase/PhraseLexer.js +6 -6
- package/components/elements/addons/search/phrase/WordLexer.test.js +1 -0
- package/components/elements/addons/search/phrase/index.d.ts +2 -2
- package/components/elements/addons/search/phrase/index.js +3 -2
- package/components/elements/addons/search/phrase/word/consumers/WhitespaceConsumer.d.ts +1 -1
- package/components/elements/addons/search/phrase/word/consumers/WhitespaceConsumer.js +1 -1
- package/components/elements/addons/search/phrase/word/consumers/WordConsumer.d.ts +1 -1
- package/components/elements/case/CaseCard.js +10 -4
- package/components/elements/case/CasePreview.js +1 -1
- package/components/elements/display/ActionButton.js +3 -1
- package/components/elements/display/ChipPopper.js +1 -1
- package/components/elements/display/ChipPopper.test.js +1 -0
- package/components/elements/display/Classification.js +6 -5
- package/components/elements/display/ClassificationChip.d.ts +2 -4
- package/components/elements/display/ClassificationChip.js +5 -3
- package/components/elements/display/DocumentationButton.js +1 -1
- package/components/elements/display/DocumentationButton.test.js +1 -1
- package/components/elements/display/HandlebarsMarkdown.js +2 -2
- package/components/elements/display/HowlerAvatar.d.ts +1 -0
- package/components/elements/display/HowlerAvatar.js +5 -4
- package/components/elements/display/HowlerAvatarHeader.js +2 -2
- package/components/elements/display/Image.test.js +1 -0
- package/components/elements/display/ItemManager.d.ts +6 -6
- package/components/elements/display/ItemManager.js +1 -1
- package/components/elements/display/Markdown.js +9 -3
- package/components/elements/display/Modal.js +3 -3
- package/components/elements/display/QueryResultText.js +1 -1
- package/components/elements/display/TextDivider.test.js +1 -0
- package/components/elements/display/TypingIndicator.d.ts +1 -1
- package/components/elements/display/UserPageWrapper.js +2 -2
- package/components/elements/display/handlebars/helpers.js +1 -1
- package/components/elements/display/json/JSONViewer.js +2 -2
- package/components/elements/display/markdownPlugins/tabs.js +4 -0
- package/components/elements/display/modals/CreateActionModal.js +1 -1
- package/components/elements/display/modals/RationaleModal.js +1 -2
- package/components/elements/display/modals/RationaleModal.test.js +9 -5
- package/components/elements/event/EventPreview.js +1 -1
- package/components/elements/hit/HitActions.js +5 -7
- package/components/elements/hit/HitBanner.js +4 -16
- package/components/elements/hit/HitBanner.test.js +11 -20
- package/components/elements/hit/HitLabels.js +23 -13
- package/components/elements/hit/HitLinks.js +4 -4
- package/components/elements/hit/HitNotebooks.js +28 -10
- package/components/elements/hit/HitOutline.js +9 -15
- package/components/elements/hit/HitOutline.test.js +5 -5
- package/components/elements/hit/HitOverview.js +3 -3
- package/components/elements/hit/HitPreview.d.ts +1 -1
- package/components/elements/hit/HitPreview.js +6 -7
- package/components/elements/hit/HitSummary.js +8 -8
- package/components/elements/hit/PivotTooltip.js +1 -1
- package/components/elements/hit/actions/ButtonActions.js +2 -2
- package/components/elements/hit/actions/DropdownActions.js +4 -4
- package/components/elements/hit/aggregate/HitGraph.js +28 -11
- package/components/elements/hit/elements/AnalyticLink.js +2 -2
- package/components/elements/hit/elements/AnalyticLink.test.js +1 -1
- package/components/elements/hit/elements/Assigned.js +1 -1
- package/components/elements/hit/elements/Assigned.test.js +1 -1
- package/components/elements/hit/elements/EscalationChip.js +2 -2
- package/components/elements/hit/elements/HitTimestamp.js +2 -2
- package/components/elements/hit/grid/AddColumnModal.js +2 -2
- package/components/elements/hit/grid/ColumnHeader.js +1 -1
- package/components/elements/hit/grid/RecordRow.js +1 -1
- package/components/elements/hit/grid/RecordTable.d.ts +4 -3
- package/components/elements/hit/grid/RecordTable.js +6 -6
- package/components/elements/hit/related/PivotLink.js +2 -2
- package/components/elements/hit/related/RelatedIcon.js +2 -2
- package/components/elements/hit/related/RelatedLink.js +1 -1
- package/components/elements/hit/related/RelatedRecords.js +1 -1
- package/components/elements/membership/Members.d.ts +6 -0
- package/components/elements/membership/Members.js +14 -0
- package/components/elements/membership/MembershipManagement.d.ts +9 -0
- package/components/elements/membership/MembershipManagement.js +119 -0
- package/components/elements/membership/types.d.ts +7 -0
- package/components/elements/membership/utils.d.ts +2 -0
- package/components/elements/membership/utils.js +6 -0
- package/components/elements/record/RecordComments.js +16 -10
- package/components/elements/record/RecordContextMenu.d.ts +2 -2
- package/components/elements/record/RecordContextMenu.js +11 -5
- package/components/elements/record/RecordContextMenu.test.js +14 -6
- package/components/elements/record/RecordRelated.js +2 -2
- package/components/elements/search/FuzzySearchBar.js +1 -1
- package/components/elements/view/LayoutToggle.d.ts +1 -1
- package/components/elements/view/ViewTitle.js +3 -4
- package/components/hooks/useHitActions.d.ts +1 -1
- package/components/hooks/useHitActions.js +25 -15
- package/components/hooks/useLocalStorage.d.ts +1 -1
- package/components/hooks/useLocalStorage.js +1 -1
- package/components/hooks/useLocalStorageItem.d.ts +11 -1
- package/components/hooks/useLocalStorageItem.js +7 -5
- package/components/hooks/useLocalStorageItem.test.js +23 -0
- package/components/hooks/useMyAccessibility.d.ts +7 -0
- package/components/hooks/useMyAccessibility.js +21 -0
- package/components/hooks/useMyApi.d.ts +1 -1
- package/components/hooks/useMyApi.js +4 -4
- package/components/hooks/useMyChart.d.ts +46 -48
- package/components/hooks/useMyChart.js +30 -9
- package/components/hooks/useMyCookies.d.ts +3 -0
- package/components/hooks/useMyCookies.js +8 -0
- package/components/hooks/useMyLocalStorage.d.ts +8 -2
- package/components/hooks/useMyLocalStorage.js +1 -1
- package/components/hooks/useMyPreferences.d.ts +1 -1
- package/components/hooks/useMyPreferences.js +93 -127
- package/components/hooks/useMyRouter.d.ts +2 -0
- package/components/hooks/useMyRouter.js +24 -0
- package/components/hooks/useMySearch.d.ts +1 -1
- package/components/hooks/useMySearch.js +17 -7
- package/components/hooks/useMySnackbar.js +1 -1
- package/components/hooks/useMyTheme.d.ts +1 -1
- package/components/hooks/useMyTheme.js +13 -8
- package/components/hooks/useMyTheme.test.js +11 -6
- package/components/hooks/useMyUser.d.ts +1 -1
- package/components/hooks/useMyUser.js +6 -5
- package/components/hooks/useMyUserFunctions.d.ts +2 -2
- package/components/hooks/useMyUserFunctions.js +14 -10
- package/components/hooks/useMyUserList.d.ts +1 -1
- package/components/hooks/useMyUtils.js +1 -1
- package/components/hooks/useParamState.js +5 -3
- package/components/hooks/useParamState.test.js +1 -1
- package/components/hooks/useRecordSelection.d.ts +4 -3
- package/components/hooks/useRecordSelection.js +5 -5
- package/components/hooks/useScrollRestoration.js +3 -3
- package/components/logins/Login.d.ts +1 -1
- package/components/logins/Login.js +4 -6
- package/components/logins/auth/OAuthLogin.js +1 -1
- package/components/logins/auth/UserPassLogin.d.ts +1 -1
- package/components/logins/hooks/useLogin.js +10 -6
- package/components/routes/403.js +1 -1
- package/components/routes/403.test.js +7 -3
- package/components/routes/404.js +1 -1
- package/components/routes/404.test.js +7 -3
- package/components/routes/ErrorBoundary.d.ts +2 -2
- package/components/routes/ErrorBoundary.js +2 -2
- package/components/routes/ErrorBoundary.test.js +1 -4
- package/components/routes/ErrorOccured.js +1 -1
- package/components/routes/ErrorOccured.test.js +7 -3
- package/components/routes/Logout.js +3 -4
- package/components/routes/Logout.test.js +12 -11
- package/components/routes/action/edit/ActionEditor.js +38 -30
- package/components/routes/action/shared/ActionReportDisplay.js +1 -1
- package/components/routes/action/shared/OperationEntry.js +2 -2
- package/components/routes/action/shared/OperationStep.js +12 -10
- package/components/routes/action/useMyActionFunctions.d.ts +3 -3
- package/components/routes/action/useMyActionFunctions.js +13 -13
- package/components/routes/action/view/ActionDetails.d.ts +1 -1
- package/components/routes/action/view/ActionDetails.js +46 -26
- package/components/routes/action/view/ActionSearch.js +11 -10
- package/components/routes/action/view/Integrations.js +2 -2
- package/components/routes/action/view/markdown/integrations.en.md.js +1 -1
- package/components/routes/action/view/markdown/integrations.fr.md.js +1 -1
- package/components/routes/admin/users/UserEditor.js +21 -8
- package/components/routes/admin/users/UserSearch.js +10 -9
- package/components/routes/advanced/QueryBuilder.js +17 -11
- package/components/routes/advanced/luceneCompletionProvider.js +42 -21
- package/components/routes/analytics/AnalyticComments.js +19 -14
- package/components/routes/analytics/AnalyticDetails.d.ts +1 -1
- package/components/routes/analytics/AnalyticDetails.js +20 -16
- package/components/routes/analytics/AnalyticHitComments.js +13 -6
- package/components/routes/analytics/AnalyticHitComments.test.js +5 -4
- package/components/routes/analytics/AnalyticNotebooks.js +5 -5
- package/components/routes/analytics/AnalyticOverview.js +28 -15
- package/components/routes/analytics/AnalyticOverviews.js +2 -2
- package/components/routes/analytics/AnalyticSearch.js +11 -10
- package/components/routes/analytics/AnalyticTemplates.js +3 -3
- package/components/routes/analytics/TriageSettings.d.ts +1 -1
- package/components/routes/analytics/TriageSettings.js +1 -1
- package/components/routes/analytics/widgets/Assessment.js +1 -1
- package/components/routes/analytics/widgets/Created.js +9 -9
- package/components/routes/analytics/widgets/Escalation.js +3 -3
- package/components/routes/analytics/widgets/Stacked.js +5 -5
- package/components/routes/analytics/widgets/Status.js +2 -2
- package/components/routes/cases/CaseViewer.js +1 -1
- package/components/routes/cases/CaseViewer.test.js +2 -2
- package/components/routes/cases/Cases.d.ts +1 -1
- package/components/routes/cases/Cases.js +8 -7
- package/components/routes/cases/constants.d.ts +3 -3
- package/components/routes/cases/detail/AlertPanel.js +1 -1
- package/components/routes/cases/detail/AlertPanel.test.js +4 -6
- package/components/routes/cases/detail/CaseDashboard.js +8 -4
- package/components/routes/cases/detail/CaseDashboard.test.js +2 -2
- package/components/routes/cases/detail/CaseDetails.js +7 -2
- package/components/routes/cases/detail/CaseDetails.test.js +1 -1
- package/components/routes/cases/detail/CaseObservables.js +5 -4
- package/components/routes/cases/detail/CaseObservables.test.js +1 -1
- package/components/routes/cases/detail/CaseOverview.js +2 -2
- package/components/routes/cases/detail/CaseRules.js +10 -6
- package/components/routes/cases/detail/CaseRules.test.js +2 -2
- package/components/routes/cases/detail/CaseSearch.js +5 -5
- package/components/routes/cases/detail/CaseSearch.test.js +2 -2
- package/components/routes/cases/detail/CaseSidebar.js +12 -7
- package/components/routes/cases/detail/CaseSidebar.test.js +5 -6
- package/components/routes/cases/detail/CaseTask.js +27 -15
- package/components/routes/cases/detail/CaseTask.test.js +8 -1
- package/components/routes/cases/detail/CaseTimeline.js +8 -8
- package/components/routes/cases/detail/CaseTimeline.test.js +6 -6
- package/components/routes/cases/detail/CreateRuleDialog.js +4 -4
- package/components/routes/cases/detail/CreateRuleDialog.test.js +2 -2
- package/components/routes/cases/detail/ItemPage.js +3 -3
- package/components/routes/cases/detail/MarkdownPage.test.js +0 -4
- package/components/routes/cases/detail/RelatedCasePanel.js +1 -1
- package/components/routes/cases/detail/RelatedCasePanel.test.js +4 -6
- package/components/routes/cases/detail/TaskPanel.js +8 -8
- package/components/routes/cases/detail/TaskPanel.test.js +3 -3
- package/components/routes/cases/detail/aggregates/CaseAggregate.js +1 -1
- package/components/routes/cases/detail/aggregates/SourceAggregate.js +3 -3
- package/components/routes/cases/detail/observables/Observable.js +4 -5
- package/components/routes/cases/detail/observables/Observable.test.js +1 -1
- package/components/routes/cases/detail/observables/ObservableTable.js +3 -3
- package/components/routes/cases/detail/observables/ObservableTable.test.js +1 -1
- package/components/routes/cases/detail/sidebar/CaseFolder.js +24 -20
- package/components/routes/cases/detail/sidebar/CaseFolder.test.js +1 -1
- package/components/routes/cases/detail/sidebar/CaseFolderContextMenu.js +4 -2
- package/components/routes/cases/detail/sidebar/CaseFolderContextMenu.test.js +3 -2
- package/components/routes/cases/detail/sidebar/FolderEntry.js +3 -3
- package/components/routes/cases/detail/sidebar/FolderEntry.test.js +3 -3
- package/components/routes/cases/detail/sidebar/types.d.ts +1 -1
- package/components/routes/cases/detail/sidebar/utils.js +1 -1
- package/components/routes/cases/detail/sidebar/utils.test.js +8 -8
- package/components/routes/cases/detail/utils.d.ts +1 -1
- package/components/routes/cases/detail/utils.js +3 -2
- package/components/routes/cases/hooks/useCase.js +14 -2
- package/components/routes/cases/modals/AddRecordToCaseModal.test.js +1 -1
- package/components/routes/cases/modals/AddToCaseModal.d.ts +1 -1
- package/components/routes/cases/modals/AddToCaseModal.js +2 -2
- package/components/routes/cases/modals/CreateCaseModal.test.js +1 -1
- package/components/routes/cases/modals/ResolveModal.js +8 -5
- package/components/routes/cases/modals/ResolveModal.test.js +5 -5
- package/components/routes/cases/modals/hooks.js +1 -2
- package/components/routes/cases/modals/types.d.ts +1 -1
- package/components/routes/cases/search/CaseAssigneeFilter.js +1 -1
- package/components/routes/cases/search/CaseAssigneeFilter.test.js +8 -3
- package/components/routes/cases/search/CaseStatusFilter.test.js +1 -0
- package/components/routes/cases/utils.d.ts +0 -1
- package/components/routes/cases/utils.js +4 -13
- package/components/routes/dossiers/DossierCard.js +3 -3
- package/components/routes/dossiers/DossierCard.test.js +6 -6
- package/components/routes/dossiers/DossierEditor.js +61 -25
- package/components/routes/dossiers/DossierEditor.test.js +16 -9
- package/components/routes/dossiers/Dossiers.d.ts +1 -1
- package/components/routes/dossiers/Dossiers.js +6 -5
- package/components/routes/dossiers/LeadEditor.d.ts +1 -1
- package/components/routes/dossiers/LeadEditor.js +2 -2
- package/components/routes/dossiers/LeadForm.js +2 -2
- package/components/routes/dossiers/PivotForm.d.ts +1 -1
- package/components/routes/dossiers/PivotForm.js +10 -9
- package/components/routes/events/EventViewer.js +1 -1
- package/components/routes/help/ActionDocumentation.js +2 -2
- package/components/routes/help/ActionIntroductionDocumentation.js +2 -2
- package/components/routes/help/ApiDocumentation.js +3 -4
- package/components/routes/help/AuthDocumentation.js +1 -1
- package/components/routes/help/ClientDocumentation.js +1 -1
- package/components/routes/help/Help.d.ts +1 -1
- package/components/routes/help/Help.js +5 -4
- package/components/routes/help/HitDocumentation.js +3 -3
- package/components/routes/help/HitLabelsDocumentation.js +12 -12
- package/components/routes/help/HitLinksDocumentation.js +2 -2
- package/components/routes/help/HitSchemaDocumentation.js +14 -8
- package/components/routes/help/NotebookDocumentation.js +1 -1
- package/components/routes/help/OverviewDocumentation.js +1 -1
- package/components/routes/help/RetentionDocumentation.js +3 -3
- package/components/routes/help/SearchDocumentation.js +6 -4
- package/components/routes/help/TemplateDocumentation.js +2 -2
- package/components/routes/help/ViewDocumentation.js +1 -1
- package/components/routes/help/markdown/en/views.md.js +1 -1
- package/components/routes/help/markdown/fr/views.md.js +1 -1
- package/components/routes/hits/search/InformationPane.js +8 -8
- package/components/routes/hits/search/QuerySettings.js +1 -1
- package/components/routes/hits/search/QuerySettings.test.js +8 -4
- package/components/routes/hits/search/RecordBrowser.js +12 -9
- package/components/routes/hits/search/RecordQuery.js +13 -10
- package/components/routes/hits/search/SearchPane.js +2 -3
- package/components/routes/hits/search/ViewLink.js +4 -4
- package/components/routes/hits/search/ViewLink.test.js +1 -0
- package/components/routes/hits/search/grid/RecordGrid.js +1 -1
- package/components/routes/hits/search/shared/CustomSort.js +3 -2
- package/components/routes/hits/search/shared/CustomSpan.js +9 -1
- package/components/routes/hits/search/shared/HitFilter.js +8 -3
- package/components/routes/hits/search/shared/HitSort.js +8 -6
- package/components/routes/hits/search/shared/IndexPicker.js +1 -1
- package/components/routes/hits/search/shared/LayoutSettings.js +1 -1
- package/components/routes/hits/search/shared/SearchActionMenu.d.ts +1 -1
- package/components/routes/hits/search/shared/SearchActionMenu.js +1 -1
- package/components/routes/hits/search/shared/SearchSpan.js +1 -1
- package/components/routes/hits/view/HitViewer.js +21 -11
- package/components/routes/hits/view/HitViewer.test.js +2 -2
- package/components/routes/home/AddNewCard.d.ts +2 -1
- package/components/routes/home/AddNewCard.js +7 -4
- package/components/routes/home/AnalyticCard.js +3 -3
- package/components/routes/home/EntryWrapper.js +1 -1
- package/components/routes/home/ViewCard.js +11 -7
- package/components/routes/home/ViewCard.test.js +3 -6
- package/components/routes/home/index.js +20 -17
- package/components/routes/overviews/OverviewCard.js +6 -2
- package/components/routes/overviews/OverviewViewer.d.ts +1 -1
- package/components/routes/overviews/OverviewViewer.js +48 -39
- package/components/routes/overviews/Overviews.d.ts +1 -1
- package/components/routes/overviews/Overviews.js +7 -6
- package/components/routes/overviews/markdownExtendedTokenProvider.test.js +1 -0
- package/components/routes/overviews/startingTemplate.js +1 -1
- package/components/routes/settings/ProfileSection.d.ts +1 -1
- package/components/routes/settings/ProfileSection.js +2 -2
- package/components/routes/settings/SecuritySection.d.ts +1 -1
- package/components/routes/settings/SecuritySection.js +2 -2
- package/components/routes/settings/Settings.js +6 -6
- package/components/routes/templates/TemplateCard.js +1 -1
- package/components/routes/templates/TemplateEditor.d.ts +1 -1
- package/components/routes/templates/TemplateEditor.js +3 -3
- package/components/routes/templates/TemplateViewer.d.ts +1 -1
- package/components/routes/templates/TemplateViewer.js +54 -52
- package/components/routes/templates/Templates.d.ts +1 -1
- package/components/routes/templates/Templates.js +10 -9
- package/components/routes/views/ViewComposer.js +38 -30
- package/components/routes/views/Views.d.ts +2 -1
- package/components/routes/views/Views.js +20 -14
- package/i18n.js +4 -0
- package/locales/en/translation.json +10 -0
- package/locales/fr/translation.json +10 -0
- package/models/entities/HowlerUser.d.ts +1 -1
- package/models/entities/generated/Action.d.ts +3 -1
- package/models/entities/generated/ApiType.d.ts +2 -3
- package/models/entities/generated/Dossier.d.ts +2 -0
- package/models/entities/generated/HowlerDossier.d.ts +2 -0
- package/models/entities/generated/Item.d.ts +2 -2
- package/models/entities/generated/Settings.d.ts +1 -1
- package/models/entities/generated/View.d.ts +2 -0
- package/package.json +102 -118
- package/plugins/HowlerPlugin.d.ts +9 -50
- package/plugins/HowlerPlugin.js +7 -113
- package/plugins/clue/Provider.js +2 -2
- package/plugins/clue/components/ClueLeadForm.js +2 -2
- package/plugins/clue/components/CluePivot.js +6 -7
- package/plugins/clue/components/CluePivotForm.js +26 -15
- package/plugins/clue/components/ClueTypography.js +2 -2
- package/plugins/clue/helpers.js +5 -5
- package/plugins/clue/index.d.ts +2 -2
- package/plugins/clue/index.js +1 -1
- package/plugins/clue/setup.js +1 -1
- package/plugins/clue/utils.d.ts +1 -1
- package/plugins/store.d.ts +26 -43
- package/plugins/store.js +2 -15
- package/rest/AxiosClient.js +3 -3
- package/rest/FetchClient.d.ts +1 -1
- package/rest/FetchClient.js +8 -5
- package/rest/FetchClient.test.js +7 -4
- package/rest/index.d.ts +4 -3
- package/setupTests.d.ts +3 -0
- package/tests/MockLocalStorage.js +2 -1
- package/tests/mocks.d.ts +2 -2
- package/tests/mocks.js +3 -3
- package/tests/server-handlers.js +1 -1
- package/utils/Throttler.js +1 -1
- package/utils/actionUtils.d.ts +1 -1
- package/utils/actionUtils.js +10 -6
- package/utils/classificationParser.js +56 -63
- package/utils/constants.d.ts +0 -17
- package/utils/constants.js +1 -18
- package/utils/exampleHit.d.ts +2 -0
- package/utils/exampleHit.js +18 -0
- package/utils/localStorage.d.ts +2 -2
- package/utils/localStorage.js +1 -1
- package/utils/menuUtils.d.ts +3 -89
- package/utils/menuUtils.js +66 -227
- package/utils/menuUtils.test.js +45 -181
- package/utils/sessionStorage.js +1 -1
- package/utils/sessionStorage.test.js +1 -0
- package/utils/stringUtils.d.ts +1 -1
- package/utils/utils.d.ts +30 -6
- package/utils/utils.js +66 -9
- package/utils/utils.test.js +1 -0
- package/utils/xsrf.d.ts +1 -1
- package/utils/xsrf.js +5 -10
- package/api/dossier/hit.d.ts +0 -2
- package/api/dossier/hit.js +0 -7
- package/api/dossier/index.d.ts +0 -9
- package/commons/components/app/AppConfigs.d.ts +0 -137
- package/commons/components/app/AppConstants.d.ts +0 -10
- package/commons/components/app/AppConstants.js +0 -10
- package/commons/components/app/AppContexts.d.ts +0 -105
- package/commons/components/app/AppContexts.js +0 -21
- package/commons/components/app/AppDefaults.d.ts +0 -6
- package/commons/components/app/AppDefaults.js +0 -40
- package/commons/components/app/AppNotificationService.d.ts +0 -6
- package/commons/components/app/AppNotificationService.js +0 -1
- package/commons/components/app/AppProvider.d.ts +0 -15
- package/commons/components/app/AppProvider.js +0 -41
- package/commons/components/app/AppSearchService.d.ts +0 -21
- package/commons/components/app/AppSearchService.js +0 -1
- package/commons/components/app/AppSkeleton.d.ts +0 -5
- package/commons/components/app/AppSkeleton.js +0 -152
- package/commons/components/app/AppUserService.d.ts +0 -17
- package/commons/components/app/AppUserService.js +0 -1
- package/commons/components/app/hooks/index.d.ts +0 -18
- package/commons/components/app/hooks/index.js +0 -18
- package/commons/components/app/hooks/useApp.d.ts +0 -1
- package/commons/components/app/hooks/useApp.js +0 -5
- package/commons/components/app/hooks/useAppBanner.d.ts +0 -1
- package/commons/components/app/hooks/useAppBanner.js +0 -6
- package/commons/components/app/hooks/useAppBar.d.ts +0 -1
- package/commons/components/app/hooks/useAppBar.js +0 -5
- package/commons/components/app/hooks/useAppBarHeight.d.ts +0 -2
- package/commons/components/app/hooks/useAppBarHeight.js +0 -22
- package/commons/components/app/hooks/useAppBarScrollTrigger.d.ts +0 -1
- package/commons/components/app/hooks/useAppBarScrollTrigger.js +0 -7
- package/commons/components/app/hooks/useAppBreadcrumbs.d.ts +0 -1
- package/commons/components/app/hooks/useAppBreadcrumbs.js +0 -5
- package/commons/components/app/hooks/useAppConfigs.d.ts +0 -59
- package/commons/components/app/hooks/useAppConfigs.js +0 -44
- package/commons/components/app/hooks/useAppLanguage.d.ts +0 -6
- package/commons/components/app/hooks/useAppLanguage.js +0 -17
- package/commons/components/app/hooks/useAppLayout.d.ts +0 -1
- package/commons/components/app/hooks/useAppLayout.js +0 -5
- package/commons/components/app/hooks/useAppLeftNav.d.ts +0 -1
- package/commons/components/app/hooks/useAppLeftNav.js +0 -5
- package/commons/components/app/hooks/useAppLogo.d.ts +0 -1
- package/commons/components/app/hooks/useAppLogo.js +0 -8
- package/commons/components/app/hooks/useAppNotification.d.ts +0 -1
- package/commons/components/app/hooks/useAppNotification.js +0 -5
- package/commons/components/app/hooks/useAppQuickSearch.d.ts +0 -1
- package/commons/components/app/hooks/useAppQuickSearch.js +0 -5
- package/commons/components/app/hooks/useAppSearchService.d.ts +0 -2
- package/commons/components/app/hooks/useAppSearchService.js +0 -5
- package/commons/components/app/hooks/useAppSitemap.d.ts +0 -16
- package/commons/components/app/hooks/useAppSitemap.js +0 -70
- package/commons/components/app/hooks/useAppSwitcher.d.ts +0 -1
- package/commons/components/app/hooks/useAppSwitcher.js +0 -5
- package/commons/components/app/hooks/useAppTheme.d.ts +0 -8
- package/commons/components/app/hooks/useAppTheme.js +0 -12
- package/commons/components/app/hooks/useAppUser.d.ts +0 -2
- package/commons/components/app/hooks/useAppUser.js +0 -5
- package/commons/components/app/providers/AppBarProvider.d.ts +0 -10
- package/commons/components/app/providers/AppBarProvider.js +0 -24
- package/commons/components/app/providers/AppBreadcrumbsProvider.d.ts +0 -6
- package/commons/components/app/providers/AppBreadcrumbsProvider.js +0 -43
- package/commons/components/app/providers/AppLayoutProvider.d.ts +0 -6
- package/commons/components/app/providers/AppLayoutProvider.js +0 -73
- package/commons/components/app/providers/AppLeftNavProvider.d.ts +0 -6
- package/commons/components/app/providers/AppLeftNavProvider.js +0 -22
- package/commons/components/app/providers/AppNotificationProvider.d.ts +0 -6
- package/commons/components/app/providers/AppNotificationProvider.js +0 -31
- package/commons/components/app/providers/AppQuickSearchProvider.d.ts +0 -8
- package/commons/components/app/providers/AppQuickSearchProvider.js +0 -19
- package/commons/components/app/providers/AppSearchServiceProvider.d.ts +0 -6
- package/commons/components/app/providers/AppSearchServiceProvider.js +0 -46
- package/commons/components/app/providers/AppSnackbarProvider.d.ts +0 -3
- package/commons/components/app/providers/AppSnackbarProvider.js +0 -15
- package/commons/components/app/providers/AppSwitcherProvider.d.ts +0 -6
- package/commons/components/app/providers/AppSwitcherProvider.js +0 -10
- package/commons/components/app/providers/AppUserProvider.d.ts +0 -8
- package/commons/components/app/providers/AppUserProvider.js +0 -12
- package/commons/components/breadcrumbs/BreadcrumbIcon.d.ts +0 -6
- package/commons/components/breadcrumbs/BreadcrumbIcon.js +0 -9
- package/commons/components/breadcrumbs/BreadcrumbLastItem.d.ts +0 -7
- package/commons/components/breadcrumbs/BreadcrumbLastItem.js +0 -19
- package/commons/components/breadcrumbs/BreadcrumbLinkItem.d.ts +0 -7
- package/commons/components/breadcrumbs/BreadcrumbLinkItem.js +0 -20
- package/commons/components/breadcrumbs/BreadcrumbList.d.ts +0 -11
- package/commons/components/breadcrumbs/BreadcrumbList.js +0 -44
- package/commons/components/breadcrumbs/Breadcrumbs.d.ts +0 -5
- package/commons/components/breadcrumbs/Breadcrumbs.js +0 -31
- package/commons/components/display/AppAvatar.d.ts +0 -8
- package/commons/components/display/AppAvatar.js +0 -18
- package/commons/components/display/AppInfoPanel.d.ts +0 -5
- package/commons/components/display/AppInfoPanel.js +0 -17
- package/commons/components/display/AppListEmpty.d.ts +0 -2
- package/commons/components/display/AppListEmpty.js +0 -5
- package/commons/components/display/AppToc.d.ts +0 -20
- package/commons/components/display/AppToc.js +0 -98
- package/commons/components/display/hooks/useAppColor.d.ts +0 -5
- package/commons/components/display/hooks/useAppColor.js +0 -10
- package/commons/components/leftnav/LeftNavDrawer.d.ts +0 -3
- package/commons/components/leftnav/LeftNavDrawer.js +0 -99
- package/commons/components/leftnav/LeftNavGroup.d.ts +0 -8
- package/commons/components/leftnav/LeftNavGroup.js +0 -55
- package/commons/components/leftnav/LeftNavItem.d.ts +0 -11
- package/commons/components/leftnav/LeftNavItem.js +0 -29
- package/commons/components/notification/FeedModels.d.ts +0 -64
- package/commons/components/notification/FeedModels.js +0 -94
- package/commons/components/notification/Notification.d.ts +0 -10
- package/commons/components/notification/Notification.js +0 -95
- package/commons/components/notification/elements/NotificationCloseButton.d.ts +0 -3
- package/commons/components/notification/elements/NotificationCloseButton.js +0 -6
- package/commons/components/notification/elements/NotificationContainer.d.ts +0 -16
- package/commons/components/notification/elements/NotificationContainer.js +0 -29
- package/commons/components/notification/elements/NotificationEndOfPage.d.ts +0 -5
- package/commons/components/notification/elements/NotificationEndOfPage.js +0 -36
- package/commons/components/notification/elements/NotificationError.d.ts +0 -2
- package/commons/components/notification/elements/NotificationError.js +0 -10
- package/commons/components/notification/elements/NotificationHeader.d.ts +0 -8
- package/commons/components/notification/elements/NotificationHeader.js +0 -18
- package/commons/components/notification/elements/NotificationItems.d.ts +0 -12
- package/commons/components/notification/elements/NotificationItems.js +0 -12
- package/commons/components/notification/elements/NotificationSkeleton.d.ts +0 -2
- package/commons/components/notification/elements/NotificationSkeleton.js +0 -12
- package/commons/components/notification/elements/NotificationTopNavButton.d.ts +0 -9
- package/commons/components/notification/elements/NotificationTopNavButton.js +0 -9
- package/commons/components/notification/elements/item/NotificationItem.d.ts +0 -5
- package/commons/components/notification/elements/item/NotificationItem.js +0 -25
- package/commons/components/notification/elements/item/NotificationItemAuthor.d.ts +0 -5
- package/commons/components/notification/elements/item/NotificationItemAuthor.js +0 -31
- package/commons/components/notification/elements/item/NotificationItemContent.d.ts +0 -3
- package/commons/components/notification/elements/item/NotificationItemContent.js +0 -9
- package/commons/components/notification/elements/item/NotificationItemDate.d.ts +0 -3
- package/commons/components/notification/elements/item/NotificationItemDate.js +0 -10
- package/commons/components/notification/elements/item/NotificationItemImage.d.ts +0 -4
- package/commons/components/notification/elements/item/NotificationItemImage.js +0 -8
- package/commons/components/notification/elements/item/NotificationItemTag.d.ts +0 -4
- package/commons/components/notification/elements/item/NotificationItemTag.js +0 -12
- package/commons/components/notification/elements/item/NotificationItemTitle.d.ts +0 -3
- package/commons/components/notification/elements/item/NotificationItemTitle.js +0 -15
- package/commons/components/notification/index.d.ts +0 -2
- package/commons/components/notification/index.js +0 -2
- package/commons/components/pages/PageCardCentered.d.ts +0 -5
- package/commons/components/pages/PageCardCentered.js +0 -30
- package/commons/components/pages/PageCenter.d.ts +0 -9
- package/commons/components/pages/PageCenter.js +0 -20
- package/commons/components/pages/PageContent.d.ts +0 -8
- package/commons/components/pages/PageContent.js +0 -8
- package/commons/components/pages/PageFullScreen.d.ts +0 -11
- package/commons/components/pages/PageFullScreen.js +0 -40
- package/commons/components/pages/PageFullWidth.d.ts +0 -11
- package/commons/components/pages/PageFullWidth.js +0 -7
- package/commons/components/pages/PageHeader.d.ts +0 -23
- package/commons/components/pages/PageHeader.js +0 -27
- package/commons/components/pages/hooks/usePageProps.d.ts +0 -24
- package/commons/components/pages/hooks/usePageProps.js +0 -19
- package/commons/components/search/AppSearch.d.ts +0 -1
- package/commons/components/search/AppSearch.js +0 -135
- package/commons/components/search/AppSearchInput.d.ts +0 -12
- package/commons/components/search/AppSearchInput.js +0 -35
- package/commons/components/search/AppSearchResult.d.ts +0 -5
- package/commons/components/search/AppSearchResult.js +0 -28
- package/commons/components/topnav/AppBar.d.ts +0 -6
- package/commons/components/topnav/AppBar.js +0 -80
- package/commons/components/topnav/AppName.d.ts +0 -5
- package/commons/components/topnav/AppName.js +0 -31
- package/commons/components/topnav/AppSwitcher.d.ts +0 -3
- package/commons/components/topnav/AppSwitcher.js +0 -44
- package/commons/components/topnav/Notifications.d.ts +0 -2
- package/commons/components/topnav/Notifications.js +0 -8
- package/commons/components/topnav/ThemeSelection.d.ts +0 -3
- package/commons/components/topnav/ThemeSelection.js +0 -33
- package/commons/components/topnav/ThemeSelectionIcon.d.ts +0 -2
- package/commons/components/topnav/ThemeSelectionIcon.js +0 -16
- package/commons/components/topnav/UserProfile.d.ts +0 -6
- package/commons/components/topnav/UserProfile.js +0 -71
- package/commons/components/utils/hooks/useClipboard.d.ts +0 -3
- package/commons/components/utils/hooks/useClipboard.js +0 -29
- package/commons/components/utils/hooks/useEnv.d.ts +0 -1
- package/commons/components/utils/hooks/useEnv.js +0 -11
- package/commons/components/utils/hooks/useFullscreenStatus.d.ts +0 -2
- package/commons/components/utils/hooks/useFullscreenStatus.js +0 -41
- package/commons/components/utils/hooks/useGravatar.d.ts +0 -2
- package/commons/components/utils/hooks/useGravatar.js +0 -9
- package/commons/components/utils/hooks/useLocalStorage.d.ts +0 -12
- package/commons/components/utils/hooks/useLocalStorage.js +0 -52
- package/commons/components/utils/hooks/useLocalStorageItem.d.ts +0 -14
- package/commons/components/utils/hooks/useLocalStorageItem.js +0 -39
- package/commons/components/utils/hooks/useThemeBuilder.d.ts +0 -7
- package/commons/components/utils/hooks/useThemeBuilder.js +0 -48
- package/commons/components/utils/keyboard.d.ts +0 -30
- package/commons/components/utils/keyboard.js +0 -50
- package/components/hooks/useMySitemap.d.ts +0 -3
- package/components/hooks/useMySitemap.js +0 -219
- /package/{commons/components/app/AppConfigs.js → components/elements/MembershipManagement.test.d.ts} +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
2
|
import { act, fireEvent, render, screen, waitFor } from '@testing-library/react';
|
|
3
|
-
import { MemoryRouter } from 'react-router
|
|
3
|
+
import { MemoryRouter } from 'react-router';
|
|
4
4
|
import { setupReactRouterMock } from '@cccsaurora/howler-ui/tests/mocks';
|
|
5
5
|
import { createMockCase } from '@cccsaurora/howler-ui/tests/utils';
|
|
6
6
|
import { beforeEach, describe, expect, it, vi } from 'vitest';
|
|
@@ -120,6 +120,13 @@ describe('CaseTask', () => {
|
|
|
120
120
|
expect(screen.getByText('Hit One')).toBeInTheDocument();
|
|
121
121
|
});
|
|
122
122
|
});
|
|
123
|
+
describe('missing callbacks', () => {
|
|
124
|
+
it('does not expose editing controls without an edit callback', () => {
|
|
125
|
+
const { container } = render(_jsx(MemoryRouter, { children: _jsx(CaseTask, { case: testCase, task: mkTask() }) }));
|
|
126
|
+
expect(getEditButton(container)).not.toBeInTheDocument();
|
|
127
|
+
expect(screen.getByRole('checkbox')).toBeDisabled();
|
|
128
|
+
});
|
|
129
|
+
});
|
|
123
130
|
describe('auto-update effects', () => {
|
|
124
131
|
it('auto-calls onEdit when complete is toggled while not editing', async () => {
|
|
125
132
|
const { mockOnEdit } = renderTask(mkTask({ complete: false }));
|
|
@@ -13,10 +13,10 @@ import dayjs from 'dayjs';
|
|
|
13
13
|
import { capitalize } from 'lodash-es';
|
|
14
14
|
import { memo, useContext, useEffect, useMemo, useState } from 'react';
|
|
15
15
|
import { useTranslation } from 'react-i18next';
|
|
16
|
-
import { Link, useOutletContext } from 'react-router
|
|
16
|
+
import { Link, useOutletContext } from 'react-router';
|
|
17
17
|
import { useContextSelector } from 'use-context-selector';
|
|
18
|
-
import { ESCALATION_COLORS } from '@cccsaurora/howler-ui/utils/constants';
|
|
19
18
|
import { isHit } from '@cccsaurora/howler-ui/utils/typeUtils';
|
|
19
|
+
import { getEscalationColor } from '@cccsaurora/howler-ui/utils/utils';
|
|
20
20
|
import useCase from '../hooks/useCase';
|
|
21
21
|
import { buildPathFromID } from '../utils';
|
|
22
22
|
// builds the additional filters for the lucene query
|
|
@@ -49,10 +49,10 @@ const CaseTimeline = ({ case: providedCase, caseId }) => {
|
|
|
49
49
|
const [selectedMitres, setSelectedMitres] = useState([]);
|
|
50
50
|
const [selectedEscalations, setSelectedEscalations] = useState(['evidence']);
|
|
51
51
|
const ids = useMemo(() => (_case?.items ?? [])
|
|
52
|
-
.filter(item => ['hit', 'event'].includes(item.type))
|
|
52
|
+
.filter(item => item.type && ['hit', 'event'].includes(item.type))
|
|
53
53
|
.map(item => item.value)
|
|
54
|
-
.filter(
|
|
55
|
-
const getItemId = (value) => _case.items
|
|
54
|
+
.filter((value) => !!value), [_case]);
|
|
55
|
+
const getItemId = (value) => _case.items?.find(item => item.value === value)?.id;
|
|
56
56
|
useEffect(() => {
|
|
57
57
|
if (ids.length < 1) {
|
|
58
58
|
return;
|
|
@@ -67,12 +67,12 @@ const CaseTimeline = ({ case: providedCase, caseId }) => {
|
|
|
67
67
|
setEscalationOptions(Object.keys(result['howler.escalation'] ?? {}));
|
|
68
68
|
const tactics = Object.keys(result['threat.tactic.id'] ?? {}).map(tactic => ({
|
|
69
69
|
id: tactic,
|
|
70
|
-
name: config.lookups?.tactics?.[tactic]
|
|
70
|
+
name: config.lookups?.tactics?.[tactic]?.name ?? tactic,
|
|
71
71
|
kind: 'tactic'
|
|
72
72
|
}));
|
|
73
73
|
const techniques = Object.keys(result['threat.technique.id'] ?? {}).map(technique => ({
|
|
74
74
|
id: technique,
|
|
75
|
-
name: config.lookups?.techniques?.[technique]
|
|
75
|
+
name: config.lookups?.techniques?.[technique]?.name ?? technique,
|
|
76
76
|
kind: 'technique'
|
|
77
77
|
}));
|
|
78
78
|
setMitreOptions([...tactics, ...techniques]);
|
|
@@ -102,7 +102,7 @@ const CaseTimeline = ({ case: providedCase, caseId }) => {
|
|
|
102
102
|
if (!_case) {
|
|
103
103
|
return null;
|
|
104
104
|
}
|
|
105
|
-
return (_jsxs(Stack, { spacing: 0, sx: { height: '100%' }, children: [_jsxs(Stack, { direction: "row", spacing: 1, alignItems: "center", flexWrap: "wrap", sx: { p: 1, gap: 1 }, children: [_jsx(Tooltip, { title: t('page.cases.timeline.filter.label'), children: _jsx(FilterList, { fontSize: "small", color: "action" }) }), _jsx(Autocomplete, { multiple: true, size: "small", options: mitreOptions, value: selectedMitres, onChange: (_e, values) => setSelectedMitres(values), getOptionLabel: opt => `${opt.id} - ${opt.name}`, isOptionEqualToValue: (opt, val) => opt.id === val.id, groupBy: opt => capitalize(opt.kind), renderTags: (value, getTagProps) => value.map((opt, index) => (_createElement(Chip, { ...getTagProps({ index }), key: opt.id, size: "small", label: opt.id, color: "primary" }))), renderInput: params => (_jsx(TextField, { ...params, label: t('page.cases.timeline.filter.mitre'), sx: { minWidth: 260 } })), noOptionsText: t('page.cases.timeline.filter.mitre.empty') }), _jsx(Autocomplete, { multiple: true, size: "small", options: escalationOptions, value: selectedEscalations, onChange: (_e, value) => setSelectedEscalations(value), getOptionLabel: opt => t(`howler.escalation.${opt}`, opt), renderTags: (value, getTagProps) => value.map((opt, index) => (_createElement(Chip, { ...getTagProps({ index }), key: opt, size: "small", label: opt, color:
|
|
105
|
+
return (_jsxs(Stack, { spacing: 0, sx: { height: '100%' }, children: [_jsxs(Stack, { direction: "row", spacing: 1, alignItems: "center", flexWrap: "wrap", sx: { p: 1, gap: 1 }, children: [_jsx(Tooltip, { title: t('page.cases.timeline.filter.label'), children: _jsx(FilterList, { fontSize: "small", color: "action" }) }), _jsx(Autocomplete, { multiple: true, size: "small", options: mitreOptions, value: selectedMitres, onChange: (_e, values) => setSelectedMitres(values), getOptionLabel: opt => `${opt.id} - ${opt.name}`, isOptionEqualToValue: (opt, val) => opt.id === val.id, groupBy: opt => capitalize(opt.kind), renderTags: (value, getTagProps) => value.map((opt, index) => (_createElement(Chip, { ...getTagProps({ index }), key: opt.id, size: "small", label: opt.id, color: "primary" }))), renderInput: params => (_jsx(TextField, { ...params, label: t('page.cases.timeline.filter.mitre'), sx: { minWidth: 260 } })), noOptionsText: t('page.cases.timeline.filter.mitre.empty') }), _jsx(Autocomplete, { multiple: true, size: "small", options: escalationOptions, value: selectedEscalations, onChange: (_e, value) => setSelectedEscalations(value), getOptionLabel: opt => t(`howler.escalation.${opt}`, opt), renderTags: (value, getTagProps) => value.map((opt, index) => (_createElement(Chip, { ...getTagProps({ index }), key: opt, size: "small", label: opt, color: getEscalationColor(opt) }))), renderInput: params => (_jsx(TextField, { ...params, label: t('page.cases.timeline.filter.escalation'), sx: { minWidth: 220 } })), noOptionsText: t('page.cases.timeline.filter.escalation.empty') })] }), _jsx(Divider, {}), loading ? (_jsx(Stack, { spacing: 2, sx: { px: 2, py: 1 }, children: [0, 1, 2].map(i => (_jsxs(Stack, { direction: "row", width: "100%", spacing: 1, children: [_jsx(Skeleton, { variant: "text", width: 120, height: 24 }), _jsx(Skeleton, { variant: "rounded", height: 120, sx: { flex: 1 } })] }, i))) })) : displayedEntries.length === 0 ? (_jsx(Box, { sx: { pt: 4, textAlign: 'center' }, children: _jsx(Typography, { color: "textSecondary", children: t('page.cases.timeline.empty') }) })) : (_jsx(Stack, { component: "ol", spacing: 0, sx: { px: 2, py: 1, listStyle: 'none', m: 0, overflow: 'auto' }, children: displayedEntries.map(entry => (_jsxs(Stack, { component: "li", spacing: 1, sx: { pb: 1 }, children: [_jsxs(Stack, { direction: "row", spacing: 2, alignItems: "flex-start", children: [_jsxs(Stack, { spacing: 0.5, alignItems: "end", children: [_jsx(Typography, { variant: "caption", color: "text.secondary", sx: { whiteSpace: 'nowrap' }, children: dayjs(entry.event?.created ?? entry.timestamp).format('YYYY-MM-DD HH:mm:ss') }), entry.threat?.technique?.id && (_jsx(Tooltip, { title: `${entry.threat.technique.id}: ${config.lookups?.techniques?.[entry.threat.technique.id]?.name ?? t('unknown')}`, children: _jsx(Typography, { component: config.lookups?.techniques?.[entry.threat.technique.id]?.url ? 'a' : 'span', href: config.lookups?.techniques?.[entry.threat.technique.id]?.url, variant: "caption", color: "text.secondary", sx: { whiteSpace: 'nowrap' }, children: entry.threat.technique.id }) })), entry.threat?.tactic?.id && (_jsx(Tooltip, { title: `${entry.threat.tactic.id}: ${config.lookups?.tactics?.[entry.threat.tactic.id]?.name ?? t('unknown')}`, children: _jsx(Typography, { component: config.lookups?.tactics?.[entry.threat.tactic.id]?.url ? 'a' : 'span', href: config.lookups?.tactics?.[entry.threat.tactic.id]?.url, variant: "caption", color: "text.secondary", sx: { whiteSpace: 'nowrap' }, children: entry.threat.tactic.id }) }))] }), _jsxs(Box, { sx: { flex: 1, minWidth: 0, textDecoration: 'none', position: 'relative' }, children: [isHit(entry) ? (_jsx(HitCard, { id: entry.howler.id, hit: entry, layout: HitLayout.DENSE, readOnly: true })) : (_jsx(EventCard, { id: entry.howler.id, event: entry })), _jsx(Box, { component: Link, to: `/cases/${_case.case_id}/${buildPathFromID(_case, getItemId(entry.howler.id) ?? entry.howler.id)}`, sx: theme => ({
|
|
106
106
|
position: 'absolute',
|
|
107
107
|
top: 0,
|
|
108
108
|
left: 0,
|
|
@@ -5,7 +5,7 @@ import userEvent from '@testing-library/user-event';
|
|
|
5
5
|
import { ApiConfigContext } from '@cccsaurora/howler-ui/components/app/providers/ApiConfigProvider';
|
|
6
6
|
import { RecordContext } from '@cccsaurora/howler-ui/components/app/providers/RecordProvider';
|
|
7
7
|
import { createElement } from 'react';
|
|
8
|
-
import { MemoryRouter } from 'react-router
|
|
8
|
+
import { MemoryRouter } from 'react-router';
|
|
9
9
|
import { createMockEvent, createMockHit } from '@cccsaurora/howler-ui/tests/utils';
|
|
10
10
|
import { beforeEach, describe, expect, it, vi } from 'vitest';
|
|
11
11
|
import { buildFilters } from './CaseTimeline';
|
|
@@ -61,8 +61,8 @@ vi.mock('components/hooks/useMyApi', () => ({
|
|
|
61
61
|
vi.mock('../hooks/useCase', () => ({
|
|
62
62
|
default: ({ case: c }) => ({ case: c, update: vi.fn(), loading: false, missing: false })
|
|
63
63
|
}));
|
|
64
|
-
vi.mock('react-router
|
|
65
|
-
const actual = await vi.importActual('react-router
|
|
64
|
+
vi.mock('react-router', async () => {
|
|
65
|
+
const actual = await vi.importActual('react-router');
|
|
66
66
|
return { ...actual, useOutletContext: () => undefined };
|
|
67
67
|
});
|
|
68
68
|
// Stub card components — their internals are irrelevant to timeline tests
|
|
@@ -100,7 +100,7 @@ const mockCase = {
|
|
|
100
100
|
{ type: 'event', value: 'obs-1', path: 'events/obs-1' }
|
|
101
101
|
]
|
|
102
102
|
};
|
|
103
|
-
const Wrapper = ({ children }) => (_jsx(ApiConfigContext.Provider, { value: { config: mockConfig, setConfig: vi.fn() }, children: _jsx(RecordContext.Provider, { value: { records: {}, loadRecords: mockLoadRecords }, children: _jsx(MemoryRouter, { initialEntries: ['/cases/case-001/timeline'], children: children }) }) }));
|
|
103
|
+
const Wrapper = ({ children }) => (_jsx(ApiConfigContext.Provider, { value: { loaded: false, config: mockConfig, setConfig: vi.fn() }, children: _jsx(RecordContext.Provider, { value: { records: {}, loadRecords: mockLoadRecords }, children: _jsx(MemoryRouter, { initialEntries: ['/cases/case-001/timeline'], children: children }) }) }));
|
|
104
104
|
const mockConfigWithUrls = {
|
|
105
105
|
lookups: {
|
|
106
106
|
tactics: { TA0001: { key: 'TA0001', name: 'Initial Access', url: 'https://attack.mitre.org/tactics/TA0001' } },
|
|
@@ -109,7 +109,7 @@ const mockConfigWithUrls = {
|
|
|
109
109
|
}
|
|
110
110
|
}
|
|
111
111
|
};
|
|
112
|
-
const WrapperWithUrl = ({ children }) => (_jsx(ApiConfigContext.Provider, { value: { config: mockConfigWithUrls, setConfig: vi.fn() }, children: _jsx(RecordContext.Provider, { value: { records: {}, loadRecords: mockLoadRecords }, children: _jsx(MemoryRouter, { initialEntries: ['/cases/case-001/timeline'], children: children }) }) }));
|
|
112
|
+
const WrapperWithUrl = ({ children }) => (_jsx(ApiConfigContext.Provider, { value: { loaded: false, config: mockConfigWithUrls, setConfig: vi.fn() }, children: _jsx(RecordContext.Provider, { value: { records: {}, loadRecords: mockLoadRecords }, children: _jsx(MemoryRouter, { initialEntries: ['/cases/case-001/timeline'], children: children }) }) }));
|
|
113
113
|
const CaseTimeline = (await import('./CaseTimeline')).default;
|
|
114
114
|
// Reusable mock response factories
|
|
115
115
|
const mockFacetResponse = {
|
|
@@ -223,7 +223,7 @@ describe('CaseTimeline component', () => {
|
|
|
223
223
|
expect(JSON.stringify(searchCallArg)).toContain('obs-1');
|
|
224
224
|
});
|
|
225
225
|
it('renders nothing when _case is not yet available', () => {
|
|
226
|
-
const emptyCaseWrapper = ({ children }) => createElement(ApiConfigContext.Provider, { value: { config: mockConfig, setConfig: vi.fn() }, children: null }, createElement(RecordContext.Provider, { value: { records: {}, loadRecords: mockLoadRecords }, children: null }, createElement(MemoryRouter, null, children)));
|
|
226
|
+
const emptyCaseWrapper = ({ children }) => createElement(ApiConfigContext.Provider, { value: { loaded: true, config: mockConfig, setConfig: vi.fn() }, children: null }, createElement(RecordContext.Provider, { value: { records: {}, loadRecords: mockLoadRecords }, children: null }, createElement(MemoryRouter, null, children)));
|
|
227
227
|
const { container } = render(_jsx(CaseTimeline, {}), { wrapper: emptyCaseWrapper });
|
|
228
228
|
expect(container.firstChild).toBeNull();
|
|
229
229
|
});
|
|
@@ -44,7 +44,7 @@ const CreateRuleDialog = ({ open, onClose, onSubmit }) => {
|
|
|
44
44
|
const [expireAfterResolved, setExpireAfterResolved] = useState(false);
|
|
45
45
|
const [loading, setLoading] = useState(false);
|
|
46
46
|
const [searching, setSearching] = useState(false);
|
|
47
|
-
const [response, setResponse] = useState(
|
|
47
|
+
const [response, setResponse] = useState();
|
|
48
48
|
const handleOpen = useCallback(() => {
|
|
49
49
|
setQuery('');
|
|
50
50
|
setDestination('');
|
|
@@ -52,7 +52,7 @@ const CreateRuleDialog = ({ open, onClose, onSubmit }) => {
|
|
|
52
52
|
setTimeframeDays(DEFAULT_TIMEFRAME_DAYS);
|
|
53
53
|
setHasExpiry(true);
|
|
54
54
|
setExpireAfterResolved(false);
|
|
55
|
-
setResponse(
|
|
55
|
+
setResponse(undefined);
|
|
56
56
|
}, []);
|
|
57
57
|
const handleSearch = useCallback(async () => {
|
|
58
58
|
setSearching(true);
|
|
@@ -70,7 +70,7 @@ const CreateRuleDialog = ({ open, onClose, onSubmit }) => {
|
|
|
70
70
|
}, [dispatchApi, query]);
|
|
71
71
|
const handleQueryChange = useCallback((q) => {
|
|
72
72
|
setQuery(q);
|
|
73
|
-
setResponse(
|
|
73
|
+
setResponse(undefined);
|
|
74
74
|
}, []);
|
|
75
75
|
const handleSubmit = useCallback(async () => {
|
|
76
76
|
if (!query.trim() || !destination.trim()) {
|
|
@@ -81,7 +81,7 @@ const CreateRuleDialog = ({ open, onClose, onSubmit }) => {
|
|
|
81
81
|
await onSubmit({
|
|
82
82
|
query: query.trim(),
|
|
83
83
|
destination: destination.trim(),
|
|
84
|
-
timeframe: hasExpiry ? timeframeDays :
|
|
84
|
+
timeframe: hasExpiry ? timeframeDays : undefined,
|
|
85
85
|
expire_after_resolved: hasExpiry ? expireAfterResolved : false,
|
|
86
86
|
indexes
|
|
87
87
|
});
|
|
@@ -143,7 +143,7 @@ describe('CreateRuleDialog', () => {
|
|
|
143
143
|
}));
|
|
144
144
|
});
|
|
145
145
|
});
|
|
146
|
-
it('
|
|
146
|
+
it('sets timeframe to undefined when no expiry is checked', async () => {
|
|
147
147
|
const user = userEvent.setup();
|
|
148
148
|
const onSubmit = vi.fn().mockResolvedValue(undefined);
|
|
149
149
|
mockDispatchApi.mockResolvedValueOnce({ items: [], total: 1, offset: 0, rows: 0 });
|
|
@@ -158,7 +158,7 @@ describe('CreateRuleDialog', () => {
|
|
|
158
158
|
expect(onSubmit).toHaveBeenCalledWith(expect.objectContaining({
|
|
159
159
|
query: 'event.kind:alert',
|
|
160
160
|
destination: 'alerts/incoming',
|
|
161
|
-
timeframe:
|
|
161
|
+
timeframe: undefined
|
|
162
162
|
}));
|
|
163
163
|
});
|
|
164
164
|
});
|
|
@@ -4,7 +4,7 @@ import useMyApi from '@cccsaurora/howler-ui/components/hooks/useMyApi';
|
|
|
4
4
|
import NotFoundPage from '@cccsaurora/howler-ui/components/routes/404';
|
|
5
5
|
import InformationPane from '@cccsaurora/howler-ui/components/routes/hits/search/InformationPane';
|
|
6
6
|
import { useEffect, useMemo, useState } from 'react';
|
|
7
|
-
import { useOutletContext, useParams } from 'react-router
|
|
7
|
+
import { useOutletContext, useParams } from 'react-router';
|
|
8
8
|
import useCase from '../hooks/useCase';
|
|
9
9
|
import { buildPathFromID } from '../utils';
|
|
10
10
|
import CaseDashboard from './CaseDashboard';
|
|
@@ -36,8 +36,8 @@ const ItemPage = ({ case: providedCase }) => {
|
|
|
36
36
|
let remainingPath = normalizedSubPath;
|
|
37
37
|
while (currentCase && remainingPath) {
|
|
38
38
|
const currentRemainingPath = remainingPath;
|
|
39
|
-
const matchedNestedCase = currentCase
|
|
40
|
-
.filter(Boolean)
|
|
39
|
+
const matchedNestedCase = currentCase
|
|
40
|
+
.items.filter(Boolean)
|
|
41
41
|
.find(_item => _item.type === 'case' && currentRemainingPath.startsWith(`${_item.name}/`));
|
|
42
42
|
if (!matchedNestedCase) {
|
|
43
43
|
break;
|
|
@@ -32,7 +32,6 @@ describe('MarkdownPage', () => {
|
|
|
32
32
|
vi.clearAllMocks();
|
|
33
33
|
markdownItem = {
|
|
34
34
|
id: 'item-1',
|
|
35
|
-
parent: null,
|
|
36
35
|
type: 'markdown',
|
|
37
36
|
name: 'Analyst Notes',
|
|
38
37
|
value: 'Initial markdown value',
|
|
@@ -44,7 +43,6 @@ describe('MarkdownPage', () => {
|
|
|
44
43
|
markdownItem,
|
|
45
44
|
{
|
|
46
45
|
id: 'item-2',
|
|
47
|
-
parent: null,
|
|
48
46
|
type: 'markdown',
|
|
49
47
|
name: 'Other Item',
|
|
50
48
|
value: 'Keep this value'
|
|
@@ -93,7 +91,6 @@ describe('MarkdownPage', () => {
|
|
|
93
91
|
items: [
|
|
94
92
|
{
|
|
95
93
|
id: 'item-1',
|
|
96
|
-
parent: null,
|
|
97
94
|
type: 'markdown',
|
|
98
95
|
name: 'Analyst Notes',
|
|
99
96
|
value: 'Persisted value',
|
|
@@ -101,7 +98,6 @@ describe('MarkdownPage', () => {
|
|
|
101
98
|
},
|
|
102
99
|
{
|
|
103
100
|
id: 'item-2',
|
|
104
|
-
parent: null,
|
|
105
101
|
type: 'markdown',
|
|
106
102
|
name: 'Other Item',
|
|
107
103
|
value: 'Keep this value'
|
|
@@ -3,7 +3,7 @@ import { Box, Divider, Pagination, Skeleton, Stack, Typography, useTheme } from
|
|
|
3
3
|
import { chunk, uniq } from 'lodash-es';
|
|
4
4
|
import { useMemo, useState } from 'react';
|
|
5
5
|
import { useTranslation } from 'react-i18next';
|
|
6
|
-
import { Link } from 'react-router
|
|
6
|
+
import { Link } from 'react-router';
|
|
7
7
|
import CaseCard from '../../../elements/case/CaseCard';
|
|
8
8
|
const RelatedCasePanel = ({ case: _case }) => {
|
|
9
9
|
const { t } = useTranslation();
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
2
|
import { fireEvent, render, screen } from '@testing-library/react';
|
|
3
|
-
import { MemoryRouter } from 'react-router
|
|
3
|
+
import { MemoryRouter } from 'react-router';
|
|
4
4
|
import { createMockCase } from '@cccsaurora/howler-ui/tests/utils';
|
|
5
5
|
import { beforeEach, describe, expect, it, vi } from 'vitest';
|
|
6
6
|
// ---------------------------------------------------------------------------
|
|
@@ -15,8 +15,8 @@ vi.mock('react-i18next', () => ({
|
|
|
15
15
|
t: (key) => key
|
|
16
16
|
})
|
|
17
17
|
}));
|
|
18
|
-
vi.mock('react-router
|
|
19
|
-
const actual = await vi.importActual('react-router
|
|
18
|
+
vi.mock('react-router', async () => {
|
|
19
|
+
const actual = await vi.importActual('react-router');
|
|
20
20
|
return {
|
|
21
21
|
...actual,
|
|
22
22
|
Link: ({ to, children, ...props }) => (_jsx("a", { href: to, ...props, children: children }))
|
|
@@ -41,9 +41,7 @@ const renderPanel = (caseValue) => {
|
|
|
41
41
|
const makeCaseItem = (value, id = value) => ({
|
|
42
42
|
type: 'case',
|
|
43
43
|
value,
|
|
44
|
-
id
|
|
45
|
-
name: null,
|
|
46
|
-
parent: null
|
|
44
|
+
id
|
|
47
45
|
});
|
|
48
46
|
// ---------------------------------------------------------------------------
|
|
49
47
|
// Setup
|
|
@@ -5,7 +5,7 @@ import api from '@cccsaurora/howler-ui/api';
|
|
|
5
5
|
import useMyApi from '@cccsaurora/howler-ui/components/hooks/useMyApi';
|
|
6
6
|
import { useEffect, useMemo, useState } from 'react';
|
|
7
7
|
import { useTranslation } from 'react-i18next';
|
|
8
|
-
import { Link } from 'react-router
|
|
8
|
+
import { Link } from 'react-router';
|
|
9
9
|
import CaseTask from './CaseTask';
|
|
10
10
|
/** Maximum number of child cases auto-loaded for task aggregation. */
|
|
11
11
|
const MAX_CHILD_CASES = 10;
|
|
@@ -27,7 +27,7 @@ const TaskPanel = ({ case: _case, updateCase }) => {
|
|
|
27
27
|
}
|
|
28
28
|
let cancelled = false;
|
|
29
29
|
void dispatchApi(api.v2.search.post('case', { query: `case_id:(${childCaseItems.map(item => item.value).join(' OR ')})` }), { throwError: false })
|
|
30
|
-
.then(results => results
|
|
30
|
+
.then(results => results?.items ?? [])
|
|
31
31
|
.then(results => {
|
|
32
32
|
if (!cancelled) {
|
|
33
33
|
setChildCases(results);
|
|
@@ -46,10 +46,10 @@ const TaskPanel = ({ case: _case, updateCase }) => {
|
|
|
46
46
|
const childCaseOptions = useMemo(() => childCases.map(c => c.case_id), [childCases]);
|
|
47
47
|
// Child cases whose tasks are currently visible
|
|
48
48
|
const visibleChildCases = useMemo(() => (showChildTasks ? childCases.filter(c => (selectedChildIds ?? []).includes(c.case_id)) : []), [showChildTasks, childCases, selectedChildIds]);
|
|
49
|
-
const onEdit = (task) => async (newTask) => {
|
|
49
|
+
const onEdit = (task) => async (newTask = {}) => {
|
|
50
50
|
if (task) {
|
|
51
51
|
await updateCase({
|
|
52
|
-
tasks: _case.tasks.map(_task => {
|
|
52
|
+
tasks: (_case.tasks ?? []).map(_task => {
|
|
53
53
|
if (_task.id !== task.id) {
|
|
54
54
|
return _task;
|
|
55
55
|
}
|
|
@@ -62,7 +62,7 @@ const TaskPanel = ({ case: _case, updateCase }) => {
|
|
|
62
62
|
}
|
|
63
63
|
else {
|
|
64
64
|
await updateCase({
|
|
65
|
-
tasks: [..._case.tasks, newTask]
|
|
65
|
+
tasks: [...(_case.tasks ?? []), newTask]
|
|
66
66
|
});
|
|
67
67
|
}
|
|
68
68
|
};
|
|
@@ -73,8 +73,8 @@ const TaskPanel = ({ case: _case, updateCase }) => {
|
|
|
73
73
|
return (_jsxs(Stack, { spacing: 1, children: [_jsxs(Stack, { direction: "row", alignItems: "center", spacing: 1, children: [_jsx(Typography, { flex: 1, variant: "h4", children: t('page.cases.dashboard.tasks') }), hasChildCases && (_jsxs(_Fragment, { children: [_jsx(Autocomplete, { multiple: true, size: "small", disableCloseOnSelect: true, options: childCaseOptions, value: selectedChildIds ?? [], onChange: (_ev, val) => setSelectedChildIds(val), getOptionLabel: id => childCases.find(c => c.case_id === id)?.title ?? id, renderTags: (vals, getTagProps) => vals.map((id, index) => {
|
|
74
74
|
const { key, ...tagProps } = getTagProps({ index });
|
|
75
75
|
return (_jsx(Chip, { ...tagProps, size: "small", label: childCases.find(c => c.case_id === id)?.title ?? id }, key));
|
|
76
|
-
}), renderInput: params => (_jsx(TextField, { ...params, size: "small", placeholder: selectedChildIds?.length === 0 ? t('page.cases.dashboard.tasks.filter_cases') : '', sx: { minWidth: 180 } })), sx: { minWidth: 180 } }), _jsx(Tooltip, { title: t(showChildTasks ? 'page.cases.dashboard.tasks.hide_child' : 'page.cases.dashboard.tasks.show_child'), children: _jsx(Chip, { size: "small", variant: showChildTasks ? 'filled' : 'outlined', label: t('page.cases.dashboard.tasks.child_cases'), icon: showChildTasks ? _jsx(ExpandLess, { fontSize: "small" }) : _jsx(ExpandMore, { fontSize: "small" }), onClick: () => setShowChildTasks(v => !v), clickable: true }) })] }))] }), _jsx(Divider, {}), _case.tasks.map(task => (_jsx(CaseTask, { task: task, case: _case, onEdit: onEdit(task), onDelete: () => updateCase({ tasks: _case.tasks.filter(_task => _task.id !== task.id) }) }, task.id))), addingTask && (_jsx(CaseTask, { newTask: true, case: _case, onEdit: async (task) => {
|
|
77
|
-
await onEdit()(task);
|
|
76
|
+
}), renderInput: params => (_jsx(TextField, { ...params, size: "small", placeholder: selectedChildIds?.length === 0 ? t('page.cases.dashboard.tasks.filter_cases') : '', sx: { minWidth: 180 } })), sx: { minWidth: 180 } }), _jsx(Tooltip, { title: t(showChildTasks ? 'page.cases.dashboard.tasks.hide_child' : 'page.cases.dashboard.tasks.show_child'), children: _jsx(Chip, { size: "small", variant: showChildTasks ? 'filled' : 'outlined', label: t('page.cases.dashboard.tasks.child_cases'), icon: showChildTasks ? _jsx(ExpandLess, { fontSize: "small" }) : _jsx(ExpandMore, { fontSize: "small" }), onClick: () => setShowChildTasks(v => !v), clickable: true }) })] }))] }), _jsx(Divider, {}), (_case.tasks ?? []).map(task => (_jsx(CaseTask, { task: task, case: _case, onEdit: onEdit(task), onDelete: () => updateCase({ tasks: (_case.tasks ?? []).filter(_task => _task.id !== task.id) }) }, task.id))), addingTask && (_jsx(CaseTask, { newTask: true, case: _case, onEdit: async (task) => {
|
|
77
|
+
await onEdit()(task ?? {});
|
|
78
78
|
setAddingTask(false);
|
|
79
79
|
}, onDelete: async () => setAddingTask(false) })), _jsxs(Stack, { onClick: () => setAddingTask(true), direction: "row", spacing: 2, sx: theme => ({
|
|
80
80
|
borderStyle: 'dashed',
|
|
@@ -90,6 +90,6 @@ const TaskPanel = ({ case: _case, updateCase }) => {
|
|
|
90
90
|
opacity: 1,
|
|
91
91
|
cursor: 'pointer'
|
|
92
92
|
}
|
|
93
|
-
}), children: [_jsx(Add, {}), _jsx(Typography, { children: t('page.cases.dashboard.tasks.add') })] }), visibleChildCases.map(child => (_jsxs(Stack, { spacing: 1, children: [_jsx(Divider, { children: _jsx(Chip, { component: Link, to: `/cases/${child.case_id}`, clickable: true, size: "small", label: child.title, variant: "outlined" }) }), child.tasks.length === 0 ? (_jsx(Typography, { variant: "caption", color: "textSecondary", sx: { pl: 1 }, children: t('page.cases.dashboard.tasks.child.empty') })) : (child.tasks.map(task => _jsx(CaseTask, { task: task, case: child, readOnly: true }, task.id)))] }, child.case_id)))] }));
|
|
93
|
+
}), children: [_jsx(Add, {}), _jsx(Typography, { children: t('page.cases.dashboard.tasks.add') })] }), visibleChildCases.map(child => (_jsxs(Stack, { spacing: 1, children: [_jsx(Divider, { children: _jsx(Chip, { component: Link, to: `/cases/${child.case_id}`, clickable: true, size: "small", label: child.title, variant: "outlined" }) }), (child.tasks ?? []).length === 0 ? (_jsx(Typography, { variant: "caption", color: "textSecondary", sx: { pl: 1 }, children: t('page.cases.dashboard.tasks.child.empty') })) : ((child.tasks ?? []).map(task => _jsx(CaseTask, { task: task, case: child, readOnly: true }, task.id)))] }, child.case_id)))] }));
|
|
94
94
|
};
|
|
95
95
|
export default TaskPanel;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
2
|
import { act, fireEvent, render, screen, waitFor } from '@testing-library/react';
|
|
3
|
-
import { MemoryRouter } from 'react-router
|
|
3
|
+
import { MemoryRouter } from 'react-router';
|
|
4
4
|
import { createMockCase } from '@cccsaurora/howler-ui/tests/utils';
|
|
5
5
|
import { beforeEach, describe, expect, it, vi } from 'vitest';
|
|
6
6
|
const mockDispatchApi = vi.hoisted(() => vi.fn());
|
|
@@ -19,8 +19,8 @@ vi.mock('api', () => ({
|
|
|
19
19
|
}
|
|
20
20
|
}
|
|
21
21
|
}));
|
|
22
|
-
vi.mock('react-router
|
|
23
|
-
const actual = await vi.importActual('react-router
|
|
22
|
+
vi.mock('react-router', async () => {
|
|
23
|
+
const actual = await vi.importActual('react-router');
|
|
24
24
|
return {
|
|
25
25
|
...actual,
|
|
26
26
|
Link: ({ to, children, ...props }) => (_jsx("a", { href: to, ...props, children: children }))
|
|
@@ -19,6 +19,6 @@ const CaseAggregate = ({ icon, iconColor, field, records, title, subtitle }) =>
|
|
|
19
19
|
.flat()
|
|
20
20
|
.filter(Boolean))
|
|
21
21
|
: [];
|
|
22
|
-
return (_jsx(Card, { sx: { height: '100%' }, children: _jsx(CardContent, { children: _jsxs(Stack, { alignItems: "center", spacing: 1, children: [_jsxs(Stack, { direction: "row", alignItems: "center", spacing: 1, children: [icon && _jsx(Icon, { fontSize: "96px", icon: icon, color: iconColor || theme.palette.grey[700] }), _jsx(NoMaxWidthTooltip, { title: !isEmpty(values) && (_jsx(Stack, { spacing: 0.5, children: uniq(values).map(value => (_jsx("span", { children: value }, value))) })), children: _jsxs(Typography, { variant: "h3", children: [values.length, !isEmpty(values) && !!title && ' - ', title] }) })] }), _jsx(Typography, { color: "textSecondary", children: subtitle })] }) }) }));
|
|
22
|
+
return (_jsx(Card, { sx: { height: '100%' }, children: _jsx(CardContent, { children: _jsxs(Stack, { alignItems: "center", spacing: 1, children: [_jsxs(Stack, { direction: "row", alignItems: "center", spacing: 1, children: [icon && _jsx(Icon, { fontSize: "96px", icon: icon, color: iconColor || theme.palette.grey[700] }), _jsx(NoMaxWidthTooltip, { title: !isEmpty(values) && (_jsx(Stack, { spacing: 0.5, children: uniq(values).map(value => (_jsx("span", { children: String(value) }, String(value)))) })), children: _jsxs(Typography, { variant: "h3", children: [values.length, !isEmpty(values) && !!title && ' - ', title] }) })] }), _jsx(Typography, { color: "textSecondary", children: subtitle })] }) }) }));
|
|
23
23
|
};
|
|
24
24
|
export default memo(CaseAggregate);
|
|
@@ -12,15 +12,15 @@ const SourceAggregate = ({ case: providedCase }) => {
|
|
|
12
12
|
if (!_case) {
|
|
13
13
|
return [];
|
|
14
14
|
}
|
|
15
|
-
const hitIds = _case.items
|
|
15
|
+
const hitIds = (_case.items ?? [])
|
|
16
16
|
.filter(item => item.type === 'hit')
|
|
17
17
|
.map(item => item.value)
|
|
18
|
-
.filter(value => !!value);
|
|
18
|
+
.filter((value) => !!value);
|
|
19
19
|
return uniq(hitIds.map(id => records[id]?.howler?.analytic).filter(analytic => !!analytic));
|
|
20
20
|
}, [_case, records]);
|
|
21
21
|
if (!_case) {
|
|
22
22
|
return _jsx(Skeleton, { height: 12, variant: "rounded" });
|
|
23
23
|
}
|
|
24
|
-
return (_jsx(Grid, { container: true, spacing: 1, children: analytics.map(_analytic => (_jsx(Grid, {
|
|
24
|
+
return (_jsx(Grid, { container: true, spacing: 1, children: analytics.map(_analytic => (_jsx(Grid, { children: _jsx(Chip, { size: "small", label: _analytic }) }, _analytic))) }));
|
|
25
25
|
};
|
|
26
26
|
export default SourceAggregate;
|
|
@@ -1,14 +1,13 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
import { Card, CardContent, Chip, Stack, Typography } from '@mui/material';
|
|
3
3
|
import { useTranslation } from 'react-i18next';
|
|
4
|
-
import { Link } from 'react-router
|
|
4
|
+
import { Link } from 'react-router';
|
|
5
|
+
import { buildPathFromID } from '../../utils';
|
|
5
6
|
const Observable = ({ observable, case: _case }) => {
|
|
6
7
|
const { t } = useTranslation();
|
|
7
8
|
return (_jsx(Card, { sx: { height: '100%' }, children: _jsx(CardContent, { children: _jsxs(Stack, { spacing: 1, children: [_jsxs(Stack, { direction: "row", alignItems: "center", spacing: 1, children: [_jsx(Chip, { size: "small", label: t(`page.cases.observables.type.${observable.type}`), color: "primary", variant: "outlined" }), _jsx(Typography, { variant: "body2", sx: { wordBreak: 'break-all', fontFamily: 'monospace' }, children: observable.value })] }), (observable.sources?.length ?? 0) > 0 && (_jsxs(Stack, { spacing: 0.5, children: [_jsx(Typography, { variant: "caption", color: "text.secondary", children: t('page.cases.observables.seen_in') }), _jsx(Stack, { direction: "row", flexWrap: "wrap", gap: 0.5, children: observable.sources?.map(source => {
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
}
|
|
11
|
-
return (_jsx(Chip, { clickable: true, size: "small", label: source.label ?? source.id, variant: "outlined", component: Link, to: `/cases/${_case.case_id}/${source.path}` }, source.id));
|
|
9
|
+
const entry = _case.items.find(item => item.value === source.id);
|
|
10
|
+
return (_jsx(Chip, { clickable: true, size: "small", label: entry.name, variant: "outlined", component: Link, to: `/cases/${_case.case_id}/${buildPathFromID(_case, entry.id)}` }, source.id));
|
|
12
11
|
}) })] }))] }) }) }));
|
|
13
12
|
};
|
|
14
13
|
export default Observable;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
2
|
/// <reference types="vitest" />
|
|
3
3
|
import { render, screen } from '@testing-library/react';
|
|
4
|
-
import { MemoryRouter } from 'react-router
|
|
4
|
+
import { MemoryRouter } from 'react-router';
|
|
5
5
|
import { createMockCase } from '@cccsaurora/howler-ui/tests/utils';
|
|
6
6
|
import { describe, expect, it } from 'vitest';
|
|
7
7
|
import Observable from './Observable';
|
|
@@ -4,8 +4,8 @@ import ChipPopper from '@cccsaurora/howler-ui/components/elements/display/ChipPo
|
|
|
4
4
|
import PluginTypography from '@cccsaurora/howler-ui/components/elements/PluginTypography';
|
|
5
5
|
import { memo, useMemo, useState } from 'react';
|
|
6
6
|
import { useTranslation } from 'react-i18next';
|
|
7
|
-
import { Link } from 'react-router
|
|
8
|
-
import {
|
|
7
|
+
import { Link } from 'react-router';
|
|
8
|
+
import { getEscalationColor } from '@cccsaurora/howler-ui/utils/utils';
|
|
9
9
|
const ROLE_COLORS = {
|
|
10
10
|
threat: 'error',
|
|
11
11
|
target: 'warning',
|
|
@@ -55,7 +55,7 @@ const ObservableTable = ({ observables, case: _case }) => {
|
|
|
55
55
|
const sources = observable.sources ?? [];
|
|
56
56
|
const escalations = [...new Set(sources.map(s => s.escalation).filter(Boolean))];
|
|
57
57
|
const linkedSources = sources.filter(source => source.path);
|
|
58
|
-
return (_jsxs(TableRow, { children: [_jsx(TableCell, { children: _jsx(Chip, { size: "small", label: t(`page.cases.observables.type.${observable.type}`), color: "primary", variant: "outlined" }) }), _jsx(TableCell, { sx: { maxWidth: 300 }, children: _jsx(PluginTypography, { value: observable.value, context: "table", variant: "body2", sx: { fontFamily: 'monospace', wordBreak: 'break-all' } }) }), _jsx(TableCell, { children: observable.role && (_jsx(Chip, { size: "small", label: t(`page.cases.observables.role.${observable.role}`), color: ROLE_COLORS[observable.role], variant: "outlined" })) }), _jsx(TableCell, { align: "right", children: _jsx(Typography, { variant: "body2", children: sources.length }) }), _jsx(TableCell, { children: linkedSources.length === 0 ? null : linkedSources.length === 1 ? (_jsx(Chip, { clickable: true, size: "small", label: linkedSources[0].label ?? linkedSources[0].path, variant: "outlined", component: Link, to: `/cases/${_case.case_id}/${linkedSources[0].path}` })) : (_jsx(ChipPopper, { label: `${linkedSources[0].label ?? linkedSources[0].path} (+${linkedSources.length - 1})`, slotProps: { chip: { size: 'small', variant: 'outlined' } }, children: _jsx(Stack, { gap: 0.5, children: linkedSources.map(source => (_jsx(Chip, { clickable: true, size: "small", label: source.label ?? source.path, variant: "outlined", component: Link, to: `/cases/${_case.case_id}/${source.path}` }, source.id))) }) })) }), _jsx(TableCell, { children: _jsx(Stack, { direction: "row", flexWrap: "wrap", gap: 0.5, children: escalations.map(esc => (_jsx(Chip, { size: "small", label: esc, color:
|
|
58
|
+
return (_jsxs(TableRow, { children: [_jsx(TableCell, { children: _jsx(Chip, { size: "small", label: t(`page.cases.observables.type.${observable.type}`), color: "primary", variant: "outlined" }) }), _jsx(TableCell, { sx: { maxWidth: 300 }, children: _jsx(PluginTypography, { value: observable.value, context: "table", variant: "body2", sx: { fontFamily: 'monospace', wordBreak: 'break-all' } }) }), _jsx(TableCell, { children: observable.role && (_jsx(Chip, { size: "small", label: t(`page.cases.observables.role.${observable.role}`), color: ROLE_COLORS[observable.role], variant: "outlined" })) }), _jsx(TableCell, { align: "right", children: _jsx(Typography, { variant: "body2", children: sources.length }) }), _jsx(TableCell, { children: linkedSources.length === 0 ? null : linkedSources.length === 1 ? (_jsx(Chip, { clickable: true, size: "small", label: linkedSources[0].label ?? linkedSources[0].path, variant: "outlined", component: Link, to: `/cases/${_case.case_id}/${linkedSources[0].path}` })) : (_jsx(ChipPopper, { label: `${linkedSources[0].label ?? linkedSources[0].path} (+${linkedSources.length - 1})`, slotProps: { chip: { size: 'small', variant: 'outlined' } }, children: _jsx(Stack, { gap: 0.5, children: linkedSources.map(source => (_jsx(Chip, { clickable: true, size: "small", label: source.label ?? source.path, variant: "outlined", component: Link, to: `/cases/${_case.case_id}/${source.path}` }, source.id))) }) })) }), _jsx(TableCell, { children: _jsx(Stack, { direction: "row", flexWrap: "wrap", gap: 0.5, children: escalations.map(esc => (_jsx(Chip, { size: "small", label: esc, color: getEscalationColor(esc) }, esc))) }) })] }, `${observable.type}:${observable.value}`));
|
|
59
59
|
}) })] }) }));
|
|
60
60
|
};
|
|
61
61
|
export default memo(ObservableTable);
|
|
@@ -2,7 +2,7 @@ import { jsx as _jsx } from "react/jsx-runtime";
|
|
|
2
2
|
import { render, screen, within } from '@testing-library/react';
|
|
3
3
|
import userEvent from '@testing-library/user-event';
|
|
4
4
|
import { createElement } from 'react';
|
|
5
|
-
import { MemoryRouter } from 'react-router
|
|
5
|
+
import { MemoryRouter } from 'react-router';
|
|
6
6
|
import { createMockCase } from '@cccsaurora/howler-ui/tests/utils';
|
|
7
7
|
import { describe, expect, it, vi } from 'vitest';
|
|
8
8
|
import ObservableTable from './ObservableTable';
|
|
@@ -4,9 +4,9 @@ import api from '@cccsaurora/howler-ui/api';
|
|
|
4
4
|
import { RecordContext } from '@cccsaurora/howler-ui/components/app/providers/RecordProvider';
|
|
5
5
|
import useMyApi from '@cccsaurora/howler-ui/components/hooks/useMyApi';
|
|
6
6
|
import { useCallback, useEffect, useMemo, useState } from 'react';
|
|
7
|
-
import { useParams } from 'react-router
|
|
7
|
+
import { useParams } from 'react-router';
|
|
8
8
|
import { useContextSelector } from 'use-context-selector';
|
|
9
|
-
import {
|
|
9
|
+
import { getEscalationColor, notNil } from '@cccsaurora/howler-ui/utils/utils';
|
|
10
10
|
import { buildPathFromID } from '../../utils';
|
|
11
11
|
import CaseFolderContextMenu from './CaseFolderContextMenu';
|
|
12
12
|
import FolderEntry from './FolderEntry';
|
|
@@ -32,37 +32,41 @@ const CaseFolder = ({ case: _case, folder, name, step = -1, parentCaseNames = []
|
|
|
32
32
|
const tree = useMemo(() => folder || buildTree(_case?.items), [folder, _case?.items]);
|
|
33
33
|
const rootCaseId = params.id;
|
|
34
34
|
// Returns the MUI colour token for the item's escalation, or undefined if none.
|
|
35
|
-
const
|
|
35
|
+
const getItemEscalationColor = (itemType, leaf) => {
|
|
36
36
|
if (itemType === 'hit' && leaf.value) {
|
|
37
|
-
const color =
|
|
38
|
-
if (color)
|
|
37
|
+
const color = getEscalationColor(records[leaf.value]?.howler?.escalation, 'inherit');
|
|
38
|
+
if (color) {
|
|
39
39
|
return color;
|
|
40
|
+
}
|
|
40
41
|
}
|
|
41
42
|
if (itemType === 'case' && leaf.value) {
|
|
42
|
-
const color =
|
|
43
|
-
if (color)
|
|
43
|
+
const color = getEscalationColor(caseStates[leaf.value]?.data?.escalation, 'inherit');
|
|
44
|
+
if (color) {
|
|
44
45
|
return color;
|
|
46
|
+
}
|
|
45
47
|
}
|
|
46
|
-
return
|
|
48
|
+
return 'inherit';
|
|
47
49
|
};
|
|
48
50
|
const toggleCase = useCallback((item) => {
|
|
49
51
|
const prev = caseStates[item.value] ?? { open: false, loading: false, data: null };
|
|
50
52
|
const shouldOpen = !prev.open;
|
|
51
53
|
const shouldFetch = shouldOpen && !!item.value && !prev.data && !prev.loading;
|
|
52
54
|
setCaseStates(current => ({ ...current, [item.value]: { ...prev, open: shouldOpen, loading: shouldFetch } }));
|
|
53
|
-
if (!shouldFetch)
|
|
55
|
+
if (!shouldFetch) {
|
|
54
56
|
return;
|
|
57
|
+
}
|
|
55
58
|
void dispatchApi(api.v2.case.get(item.value), { throwError: false })
|
|
56
59
|
.then(caseResponse => {
|
|
57
|
-
if (!caseResponse)
|
|
60
|
+
if (!caseResponse) {
|
|
58
61
|
return;
|
|
62
|
+
}
|
|
59
63
|
setCaseStates(current => ({ ...current, [item.value]: { ...current[item.value], data: caseResponse } }));
|
|
60
64
|
})
|
|
61
65
|
.finally(() => {
|
|
62
66
|
setCaseStates(current => ({ ...current, [item.value]: { ...current[item.value], loading: false } }));
|
|
63
67
|
});
|
|
64
68
|
}, [caseStates, dispatchApi]);
|
|
65
|
-
return (_jsxs(Stack, { sx: { overflow: 'visible' }, children: [name && (_jsx(CaseFolderContextMenu, { case: _case, item: folder.item, onUpdate: onItemUpdated, children: _jsx(Box, { sx: {
|
|
69
|
+
return (_jsxs(Stack, { sx: { overflow: 'visible' }, children: [name && folder?.item && (_jsx(CaseFolderContextMenu, { case: _case, item: folder.item, onUpdate: onItemUpdated, children: _jsx(Box, { sx: {
|
|
66
70
|
transition: theme.transitions.create('background', { duration: 100 }),
|
|
67
71
|
background: 'transparent',
|
|
68
72
|
'&:hover': { background: theme.palette.grey[800] }
|
|
@@ -76,30 +80,30 @@ const CaseFolder = ({ case: _case, folder, name, step = -1, parentCaseNames = []
|
|
|
76
80
|
const nestedCase = nodeState?.data ?? null;
|
|
77
81
|
const fullItemPath = [...parentCaseNames, leaf.name].filter(Boolean).join('/');
|
|
78
82
|
const itemTo = `/cases/${rootCaseId}${fullItemPath ? `/${fullItemPath}` : ''}`;
|
|
79
|
-
const escalationColor =
|
|
80
|
-
const
|
|
81
|
-
const leafColor = escalationColor ? `${escalationColor}.light` : 'text.secondary';
|
|
83
|
+
const escalationColor = getItemEscalationColor(itemType, leaf);
|
|
84
|
+
const leafColor = escalationColor !== 'inherit' ? `${escalationColor}.light` : 'text.secondary';
|
|
82
85
|
return (_jsx(CaseFolderContextMenu, { case: _case, item: leaf, onUpdate: onItemUpdated, children: _jsxs(Stack, { children: [_jsx(Box, { sx: {
|
|
83
86
|
transition: theme.transitions.create('background', { duration: 100 }),
|
|
84
87
|
background: 'transparent',
|
|
85
88
|
'&:hover': { background: theme.palette.grey[800] }
|
|
86
|
-
}, children: _jsx(FolderEntry, { caseId: _case.case_id === rootCaseId ? rootCaseId : null, indent: step * 1.5 + 1, label: leaf.name ?? leaf.value ?? '', iconColor:
|
|
89
|
+
}, children: _jsx(FolderEntry, { caseId: _case.case_id === rootCaseId ? rootCaseId : null, indent: step * 1.5 + 1, label: leaf.name ?? leaf.value ?? '', iconColor: escalationColor, labelColor: leafColor, chevronOpen: isCaseOpen, to: itemTo, onClick: () => toggleCase(leaf), entry: leaf }) }), isCaseOpen && isCaseLoading && (_jsx(Stack, { pl: step * 1.5 + 4, py: 0.25, children: _jsx(Skeleton, { width: 140, height: 16 }) })), isCaseOpen && nestedCase && (_jsx(CaseFolder, { case: nestedCase, step: step + 1, parentCaseNames: [...parentCaseNames, leaf.name].filter(notNil), onItemUpdated: onItemUpdated, collapseKey: collapseKey }))] }) }, `${_case?.case_id}-${leaf.id}-${leaf.value}`));
|
|
87
90
|
}), Object.entries(tree.folders ?? {}).map(([folderName, subfolder]) => {
|
|
88
|
-
return (_jsx(CaseFolder, { name: folderName, case: _case, folder: subfolder, step: step + 1, parentCaseNames: parentCaseNames, onItemUpdated: onItemUpdated, collapseKey: collapseKey }, subfolder.item
|
|
91
|
+
return (_jsx(CaseFolder, { name: folderName, case: _case, folder: subfolder, step: step + 1, parentCaseNames: parentCaseNames, onItemUpdated: onItemUpdated, collapseKey: collapseKey }, subfolder.item?.id ?? folderName));
|
|
89
92
|
}), tree.leaves
|
|
90
93
|
?.filter(leaf => leaf.type?.toLowerCase() !== 'case')
|
|
91
94
|
.map(leaf => {
|
|
92
95
|
const itemType = leaf.type?.toLowerCase();
|
|
93
96
|
const fullItemPath = [...parentCaseNames, buildPathFromID(_case, leaf.id)].filter(Boolean).join('/');
|
|
94
|
-
const itemTo = itemType !== 'reference'
|
|
95
|
-
|
|
96
|
-
|
|
97
|
+
const itemTo = itemType !== 'reference'
|
|
98
|
+
? `/cases/${rootCaseId}${fullItemPath ? `/${fullItemPath}` : ''}`
|
|
99
|
+
: (leaf.value ?? '');
|
|
100
|
+
const escalationColor = getItemEscalationColor(itemType, leaf);
|
|
97
101
|
const leafColor = escalationColor ? `${escalationColor}.light` : 'text.secondary';
|
|
98
102
|
return (_jsx(CaseFolderContextMenu, { case: _case, item: leaf, onUpdate: onItemUpdated, children: _jsx(Box, { sx: {
|
|
99
103
|
transition: theme.transitions.create('background', { duration: 100 }),
|
|
100
104
|
background: 'transparent',
|
|
101
105
|
'&:hover': { background: theme.palette.grey[800] }
|
|
102
|
-
}, children: _jsx(FolderEntry, { caseId: _case.case_id === rootCaseId ? rootCaseId : null, indent: step * 1.5 + 1, label: leaf.name ?? leaf.value ?? '', iconColor:
|
|
106
|
+
}, children: _jsx(FolderEntry, { caseId: _case.case_id === rootCaseId ? rootCaseId : null, indent: step * 1.5 + 1, label: leaf.name ?? leaf.value ?? '', iconColor: escalationColor, labelColor: leafColor, to: itemTo, entry: leaf }) }) }, `${_case?.case_id}-${leaf.id}-${leaf.value}`));
|
|
103
107
|
})] }))] }));
|
|
104
108
|
};
|
|
105
109
|
export default CaseFolder;
|
|
@@ -37,7 +37,7 @@ const mockRecords = vi.hoisted(() => ({ current: {} }));
|
|
|
37
37
|
vi.mock('components/app/providers/RecordProvider', async () => ({
|
|
38
38
|
RecordContext: createContext({ records: mockRecords.current })
|
|
39
39
|
}));
|
|
40
|
-
import { MemoryRouter, useParams } from 'react-router
|
|
40
|
+
import { MemoryRouter, useParams } from 'react-router';
|
|
41
41
|
import CaseFolder from './CaseFolder';
|
|
42
42
|
const makeCase = (id, items = []) => ({
|
|
43
43
|
__index: 'case',
|
|
@@ -81,8 +81,10 @@ const CaseFolderContextMenu = ({ case: _case, item, onUpdate, children }) => {
|
|
|
81
81
|
id: 'remove-item',
|
|
82
82
|
label: isFolder ? t('page.cases.sidebar.folder.remove') : t('page.cases.sidebar.item.remove'),
|
|
83
83
|
icon: _jsx(Delete, { fontSize: "small" }),
|
|
84
|
-
onClick: () => {
|
|
85
|
-
|
|
84
|
+
onClick: async () => {
|
|
85
|
+
const caseId = _case.case_id;
|
|
86
|
+
const itemId = item.id;
|
|
87
|
+
if (!caseId || !itemId) {
|
|
86
88
|
return;
|
|
87
89
|
}
|
|
88
90
|
void dispatchApi(api.v2.case.items.del(_case.case_id, [item.id], isFolder), { throwError: false }).then(updatedCase => {
|