@cccsaurora/howler-ui 2.18.0-dev.716 → 2.18.0-dev.722
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/api/index.d.ts +0 -2
- package/api/index.js +2 -4
- package/api/search/facet/hit.d.ts +3 -1
- package/api/search/facet/index.d.ts +1 -3
- package/api/search/index.d.ts +1 -2
- package/api/search/index.js +1 -2
- package/commons/components/leftnav/LeftNavDrawer.js +1 -1
- package/components/app/App.js +7 -39
- package/components/app/hooks/useMatchers.js +2 -2
- package/components/app/hooks/useMatchers.test.js +22 -22
- package/components/app/hooks/useTitle.js +3 -3
- package/components/app/providers/FavouritesProvider.js +2 -2
- package/components/app/providers/HitProvider.d.ts +22 -0
- package/components/app/providers/{RecordProvider.js → HitProvider.js} +41 -41
- 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} +70 -51
- package/components/app/providers/ModalProvider.d.ts +0 -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 +14 -307
- 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 +5 -14
- package/components/elements/addons/search/phrase/Phrase.js +1 -1
- package/components/elements/display/ChipPopper.d.ts +1 -1
- package/components/elements/display/HowlerCard.js +1 -1
- package/components/elements/display/Modal.js +0 -2
- package/components/elements/display/icons/BundleButton.d.ts +6 -0
- package/components/elements/display/icons/BundleButton.js +32 -0
- package/components/elements/hit/HitActions.js +4 -4
- package/components/elements/hit/HitBanner.js +48 -28
- package/components/elements/hit/HitCard.d.ts +0 -1
- package/components/elements/hit/HitCard.js +6 -6
- 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/{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 +5 -6
- 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/outlines/DefaultOutline.js +1 -1
- package/components/elements/view/ViewTitle.d.ts +0 -1
- package/components/elements/view/ViewTitle.js +2 -9
- package/components/hooks/useHitActions.d.ts +1 -1
- package/components/hooks/useHitActions.js +4 -4
- package/components/hooks/{useRecordSelection.d.ts → useHitSelection.d.ts} +2 -2
- package/components/hooks/{useRecordSelection.js → useHitSelection.js} +33 -12
- package/components/hooks/useMyPreferences.js +1 -10
- package/components/hooks/useMySearch.js +2 -2
- package/components/hooks/useMySitemap.js +1 -4
- package/components/hooks/useMyTheme.js +2 -9
- package/components/hooks/useParamState.test.js +4 -3
- package/components/routes/action/edit/ActionEditor.js +2 -2
- package/components/routes/action/view/ActionSearch.js +1 -1
- package/components/routes/advanced/QueryBuilder.js +1 -1
- package/components/routes/advanced/QueryEditor.js +3 -3
- package/components/routes/advanced/historyCompletionProvider.js +3 -3
- package/components/routes/analytics/AnalyticDetails.js +2 -2
- package/components/routes/analytics/AnalyticSearch.js +1 -1
- package/components/routes/dossiers/DossierEditor.js +2 -2
- package/components/routes/dossiers/DossierEditor.test.js +1 -1
- package/components/routes/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/fr/bundles.md.js +1 -0
- 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 +227 -0
- package/components/{elements/record/RecordContextMenu.test.js → routes/hits/search/HitContextMenu.test.js} +39 -94
- 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 +60 -47
- 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} +8 -10
- package/components/routes/hits/view/HitViewer.js +13 -12
- package/components/routes/home/ViewCard.js +41 -47
- package/components/{elements/MarkdownEditor.js → routes/overviews/OverviewEditor.js} +3 -3
- package/components/routes/overviews/OverviewViewer.js +2 -2
- package/components/routes/views/ViewComposer.js +19 -46
- package/locales/en/translation.json +3 -88
- package/locales/fr/translation.json +3 -86
- 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 +0 -1
- package/models/entities/generated/Howler.d.ts +4 -0
- package/models/entities/generated/Rule.d.ts +10 -2
- package/models/entities/generated/Threat.d.ts +2 -2
- package/models/entities/generated/View.d.ts +0 -1
- package/package.json +1 -18
- package/plugins/clue/components/ClueTypography.js +2 -2
- package/plugins/clue/utils.d.ts +1 -2
- package/tests/server-handlers.js +1 -6
- package/tests/utils.d.ts +0 -4
- package/tests/utils.js +0 -20
- package/utils/constants.d.ts +3 -3
- package/utils/hitFunctions.d.ts +1 -2
- package/utils/hitFunctions.js +4 -4
- package/utils/viewUtils.js +0 -3
- package/api/search/case.d.ts +0 -4
- package/api/search/case.js +0 -8
- package/api/v2/case/index.d.ts +0 -8
- package/api/v2/case/index.js +0 -20
- package/api/v2/case/items.d.ts +0 -6
- package/api/v2/case/items.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 -8
- package/components/elements/hit/elements/AnalyticLink.js +0 -22
- 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 -247
- package/components/elements/record/RecordContextMenu.test.d.ts +0 -1
- 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 -22
- package/components/routes/cases/Cases.d.ts +0 -2
- package/components/routes/cases/Cases.js +0 -101
- package/components/routes/cases/constants.d.ts +0 -5
- package/components/routes/cases/constants.js +0 -5
- 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.d.ts +0 -1
- 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 -54
- package/components/routes/cases/detail/CaseDetails.d.ts +0 -6
- package/components/routes/cases/detail/CaseDetails.js +0 -61
- package/components/routes/cases/detail/CaseOverview.d.ts +0 -7
- package/components/routes/cases/detail/CaseOverview.js +0 -43
- package/components/routes/cases/detail/CaseSidebar.d.ts +0 -8
- package/components/routes/cases/detail/CaseSidebar.js +0 -50
- package/components/routes/cases/detail/CaseTask.d.ts +0 -11
- package/components/routes/cases/detail/CaseTask.js +0 -57
- 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.d.ts +0 -1
- package/components/routes/cases/detail/CaseTimeline.test.js +0 -227
- package/components/routes/cases/detail/ItemPage.d.ts +0 -6
- package/components/routes/cases/detail/ItemPage.js +0 -99
- package/components/routes/cases/detail/RelatedCasePanel.d.ts +0 -6
- package/components/routes/cases/detail/RelatedCasePanel.js +0 -31
- 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 -12
- package/components/routes/cases/detail/aggregates/CaseAggregate.js +0 -19
- package/components/routes/cases/detail/aggregates/SourceAggregate.d.ts +0 -6
- package/components/routes/cases/detail/aggregates/SourceAggregate.js +0 -30
- 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.d.ts +0 -1
- package/components/routes/cases/detail/assets/Asset.test.js +0 -72
- package/components/routes/cases/detail/sidebar/CaseFolder.d.ts +0 -14
- package/components/routes/cases/detail/sidebar/CaseFolder.js +0 -136
- package/components/routes/cases/detail/sidebar/CaseFolderContextMenu.d.ts +0 -34
- package/components/routes/cases/detail/sidebar/CaseFolderContextMenu.js +0 -105
- package/components/routes/cases/detail/sidebar/CaseFolderContextMenu.test.d.ts +0 -1
- package/components/routes/cases/detail/sidebar/CaseFolderContextMenu.test.js +0 -351
- package/components/routes/cases/detail/sidebar/types.d.ts +0 -3
- package/components/routes/cases/detail/sidebar/utils.d.ts +0 -3
- package/components/routes/cases/detail/sidebar/utils.js +0 -25
- package/components/routes/cases/hooks/useCase.d.ts +0 -13
- package/components/routes/cases/hooks/useCase.js +0 -51
- package/components/routes/cases/modals/AddToCaseModal.d.ts +0 -7
- package/components/routes/cases/modals/AddToCaseModal.js +0 -62
- 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.d.ts +0 -1
- package/components/routes/cases/modals/ResolveModal.test.js +0 -384
- 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 -43
- 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/utils/typeUtils.d.ts +0 -7
- package/utils/typeUtils.js +0 -27
- /package/components/app/providers/{RecordSearchProvider.test.d.ts → HitSearchProvider.test.d.ts} +0 -0
- /package/components/elements/hit/{related/RelatedRecords.d.ts → HitDetails.d.ts} +0 -0
- /package/components/routes/hits/search/{RecordBrowser.d.ts → HitBrowser.d.ts} +0 -0
- /package/components/{elements/ContextMenu.test.d.ts → routes/hits/search/HitContextMenu.test.d.ts} +0 -0
- /package/components/{elements/MarkdownEditor.d.ts → routes/overviews/OverviewEditor.d.ts} +0 -0
|
@@ -47,7 +47,6 @@ vi.mock('components/app/hooks/useMatchers', () => ({
|
|
|
47
47
|
getMatchingTemplate: mockGetMatchingTemplate
|
|
48
48
|
}))
|
|
49
49
|
}));
|
|
50
|
-
const mockShowModal = vi.fn();
|
|
51
50
|
const mockDispatchApi = vi.fn();
|
|
52
51
|
vi.mock('components/hooks/useMyApi', () => ({
|
|
53
52
|
default: vi.fn(() => ({
|
|
@@ -73,9 +72,6 @@ vi.mock('plugins/store', () => ({
|
|
|
73
72
|
plugins: ['plugin1']
|
|
74
73
|
}
|
|
75
74
|
}));
|
|
76
|
-
vi.mock('components/routes/cases/modals/AddToCaseModal', () => ({
|
|
77
|
-
default: () => null
|
|
78
|
-
}));
|
|
79
75
|
// Mock MUI components
|
|
80
76
|
vi.mock('@mui/material', async () => {
|
|
81
77
|
const actual = await vi.importActual('@mui/material');
|
|
@@ -95,14 +91,13 @@ vi.mock('@mui/material', async () => {
|
|
|
95
91
|
});
|
|
96
92
|
// Import component after mocks
|
|
97
93
|
import { ApiConfigContext } from '@cccsaurora/howler-ui/components/app/providers/ApiConfigProvider';
|
|
98
|
-
import {
|
|
94
|
+
import { HitContext } from '@cccsaurora/howler-ui/components/app/providers/HitProvider';
|
|
99
95
|
import { ParameterContext } from '@cccsaurora/howler-ui/components/app/providers/ParameterProvider';
|
|
100
|
-
import { RecordContext } from '@cccsaurora/howler-ui/components/app/providers/RecordProvider';
|
|
101
96
|
import i18n from '@cccsaurora/howler-ui/i18n';
|
|
102
97
|
import { I18nextProvider } from 'react-i18next';
|
|
103
98
|
import { createMockAction, createMockAnalytic, createMockHit, createMockTemplate } from '@cccsaurora/howler-ui/tests/utils';
|
|
104
99
|
import { DEFAULT_QUERY } from '@cccsaurora/howler-ui/utils/constants';
|
|
105
|
-
import
|
|
100
|
+
import HitContextMenu from './HitContextMenu';
|
|
106
101
|
const mockGetSelectedId = vi.fn(() => 'test-hit-1');
|
|
107
102
|
const mockConfig = {
|
|
108
103
|
lookups: {
|
|
@@ -110,16 +105,16 @@ const mockConfig = {
|
|
|
110
105
|
}
|
|
111
106
|
};
|
|
112
107
|
const mockApiContext = { config: mockConfig };
|
|
113
|
-
const
|
|
114
|
-
|
|
108
|
+
const mockHitContext = {
|
|
109
|
+
hits: {
|
|
115
110
|
'test-hit-1': createMockHit()
|
|
116
111
|
},
|
|
117
|
-
|
|
112
|
+
selectedHits: []
|
|
118
113
|
};
|
|
119
114
|
const mockParameterContext = { query: DEFAULT_QUERY, setQuery: vi.fn() };
|
|
120
115
|
// Test wrapper
|
|
121
116
|
const Wrapper = ({ children }) => {
|
|
122
|
-
return (_jsx(I18nextProvider, { i18n: i18n, children: _jsx(ApiConfigContext.Provider, { value: mockApiContext, children: _jsx(
|
|
117
|
+
return (_jsx(I18nextProvider, { i18n: i18n, children: _jsx(ApiConfigContext.Provider, { value: mockApiContext, children: _jsx(HitContext.Provider, { value: mockHitContext, children: _jsx(ParameterContext.Provider, { value: mockParameterContext, children: children }) }) }) }));
|
|
123
118
|
};
|
|
124
119
|
describe('HitContextMenu', () => {
|
|
125
120
|
let user;
|
|
@@ -127,11 +122,11 @@ describe('HitContextMenu', () => {
|
|
|
127
122
|
beforeEach(() => {
|
|
128
123
|
user = userEvent.setup();
|
|
129
124
|
vi.clearAllMocks();
|
|
130
|
-
|
|
131
|
-
|
|
125
|
+
mockHitContext.selectedHits.length = 0;
|
|
126
|
+
mockHitContext.hits['test-hit-1'] = createMockHit();
|
|
132
127
|
mockGetMatchingAnalytic.mockResolvedValue(createMockAnalytic());
|
|
133
128
|
mockGetMatchingTemplate.mockResolvedValue(createMockTemplate());
|
|
134
|
-
rerender = render(_jsx(Wrapper, { children: _jsx(
|
|
129
|
+
rerender = render(_jsx(Wrapper, { children: _jsx(HitContextMenu, { getSelectedId: mockGetSelectedId, children: _jsx("div", { children: "Test Content" }) }) })).rerender;
|
|
135
130
|
});
|
|
136
131
|
describe('Context Menu Initialization', () => {
|
|
137
132
|
it('should open menu on right-click', async () => {
|
|
@@ -195,13 +190,13 @@ describe('HitContextMenu', () => {
|
|
|
195
190
|
});
|
|
196
191
|
it('should disable "Open Hit" when hit is null', async () => {
|
|
197
192
|
act(() => {
|
|
198
|
-
|
|
193
|
+
mockHitContext.hits['test-hit-1'] = null;
|
|
199
194
|
const contextMenuWrapper = screen.getByText('Test Content').parentElement;
|
|
200
195
|
fireEvent.contextMenu(contextMenuWrapper);
|
|
201
196
|
});
|
|
202
197
|
await waitFor(() => {
|
|
203
198
|
const menuItems = screen.getAllByRole('menuitem');
|
|
204
|
-
const openHitItem = menuItems.find(item => item.textContent?.toLowerCase().includes('open hit'));
|
|
199
|
+
const openHitItem = menuItems.find(item => item.textContent?.toLowerCase().includes('open hit viewer'));
|
|
205
200
|
expect(openHitItem).toHaveAttribute('aria-disabled', 'true');
|
|
206
201
|
});
|
|
207
202
|
});
|
|
@@ -242,7 +237,7 @@ describe('HitContextMenu', () => {
|
|
|
242
237
|
skip_rationale: false
|
|
243
238
|
}
|
|
244
239
|
}));
|
|
245
|
-
rerender(_jsx(Wrapper, { children: _jsx(
|
|
240
|
+
rerender(_jsx(Wrapper, { children: _jsx(HitContextMenu, { getSelectedId: mockGetSelectedId, children: _jsx("div", { children: "Test Content" }) }) }));
|
|
246
241
|
act(() => {
|
|
247
242
|
const contextMenuWrapper = screen.getByText('Test Content').parentElement;
|
|
248
243
|
fireEvent.contextMenu(contextMenuWrapper);
|
|
@@ -300,7 +295,7 @@ describe('HitContextMenu', () => {
|
|
|
300
295
|
createMockAction({ action_id: 'action-2', name: 'Custom Action 2' })
|
|
301
296
|
];
|
|
302
297
|
mockDispatchApi.mockResolvedValue({ items: mockActions });
|
|
303
|
-
rerender(_jsx(Wrapper, { children: _jsx(
|
|
298
|
+
rerender(_jsx(Wrapper, { children: _jsx(HitContextMenu, { getSelectedId: mockGetSelectedId, children: _jsx("div", { children: "Test Content" }) }) }));
|
|
304
299
|
act(() => {
|
|
305
300
|
const contextMenuWrapper = screen.getByText('Test Content').parentElement;
|
|
306
301
|
fireEvent.contextMenu(contextMenuWrapper);
|
|
@@ -344,7 +339,7 @@ describe('HitContextMenu', () => {
|
|
|
344
339
|
});
|
|
345
340
|
it('should disable custom actions menu when no actions are available', async () => {
|
|
346
341
|
mockDispatchApi.mockResolvedValueOnce({ items: [] });
|
|
347
|
-
rerender(_jsx(Wrapper, { children: _jsx(
|
|
342
|
+
rerender(_jsx(Wrapper, { children: _jsx(HitContextMenu, { getSelectedId: mockGetSelectedId, children: _jsx("div", { children: "Test Content" }) }) }));
|
|
348
343
|
act(() => {
|
|
349
344
|
const contextMenuWrapper = screen.getByText('Test Content').parentElement;
|
|
350
345
|
fireEvent.contextMenu(contextMenuWrapper);
|
|
@@ -386,7 +381,7 @@ describe('HitContextMenu', () => {
|
|
|
386
381
|
skip_rationale: true
|
|
387
382
|
}
|
|
388
383
|
}));
|
|
389
|
-
rerender(_jsx(Wrapper, { children: _jsx(
|
|
384
|
+
rerender(_jsx(Wrapper, { children: _jsx(HitContextMenu, { getSelectedId: mockGetSelectedId, children: _jsx("div", { children: "Test Content" }) }) }));
|
|
390
385
|
act(() => {
|
|
391
386
|
const contextMenuWrapper = screen.getByText('Test Content').parentElement;
|
|
392
387
|
fireEvent.contextMenu(contextMenuWrapper);
|
|
@@ -454,7 +449,7 @@ describe('HitContextMenu', () => {
|
|
|
454
449
|
it('should call executeAction with action_id and hit query', async () => {
|
|
455
450
|
const mockActions = [createMockAction({ action_id: 'action-1', name: 'Custom Action' })];
|
|
456
451
|
mockDispatchApi.mockResolvedValue({ items: mockActions });
|
|
457
|
-
rerender(_jsx(Wrapper, { children: _jsx(
|
|
452
|
+
rerender(_jsx(Wrapper, { children: _jsx(HitContextMenu, { getSelectedId: mockGetSelectedId, children: _jsx("div", { children: "Test Content" }) }) }));
|
|
458
453
|
act(() => {
|
|
459
454
|
const contextMenuWrapper = screen.getByText('Test Content').parentElement;
|
|
460
455
|
fireEvent.contextMenu(contextMenuWrapper);
|
|
@@ -507,7 +502,7 @@ describe('HitContextMenu', () => {
|
|
|
507
502
|
mockGetMatchingTemplate.mockResolvedValue(createMockTemplate({
|
|
508
503
|
keys: ['howler.detection', 'event.id']
|
|
509
504
|
}));
|
|
510
|
-
rerender(_jsx(Wrapper, { children: _jsx(
|
|
505
|
+
rerender(_jsx(Wrapper, { children: _jsx(HitContextMenu, { getSelectedId: mockGetSelectedId, children: _jsx("div", { children: "Test Content" }) }) }));
|
|
511
506
|
});
|
|
512
507
|
it('should render exclusion submenu with template keys', async () => {
|
|
513
508
|
act(() => {
|
|
@@ -555,7 +550,7 @@ describe('HitContextMenu', () => {
|
|
|
555
550
|
mockGetMatchingTemplate.mockResolvedValue(createMockTemplate({
|
|
556
551
|
keys: ['howler.outline.indicators']
|
|
557
552
|
}));
|
|
558
|
-
rerender(_jsx(Wrapper, { children: _jsx(
|
|
553
|
+
rerender(_jsx(Wrapper, { children: _jsx(HitContextMenu, { getSelectedId: mockGetSelectedId, children: _jsx("div", { children: "Test Content" }) }) }));
|
|
559
554
|
act(() => {
|
|
560
555
|
const contextMenuWrapper = screen.getByText('Test Content').parentElement;
|
|
561
556
|
fireEvent.contextMenu(contextMenuWrapper);
|
|
@@ -598,7 +593,7 @@ describe('HitContextMenu', () => {
|
|
|
598
593
|
mockGetMatchingTemplate.mockResolvedValue(createMockTemplate({
|
|
599
594
|
keys: []
|
|
600
595
|
}));
|
|
601
|
-
rerender(_jsx(Wrapper, { children: _jsx(
|
|
596
|
+
rerender(_jsx(Wrapper, { children: _jsx(HitContextMenu, { getSelectedId: mockGetSelectedId, children: _jsx("div", { children: "Test Content" }) }) }));
|
|
602
597
|
act(() => {
|
|
603
598
|
const contextMenuWrapper = screen.getByText('Test Content').parentElement;
|
|
604
599
|
fireEvent.contextMenu(contextMenuWrapper);
|
|
@@ -610,7 +605,7 @@ describe('HitContextMenu', () => {
|
|
|
610
605
|
});
|
|
611
606
|
it('should skip null field values in exclusion menu', async () => {
|
|
612
607
|
act(() => {
|
|
613
|
-
|
|
608
|
+
mockHitContext.hits['test-hit-1'].event = {};
|
|
614
609
|
});
|
|
615
610
|
act(() => {
|
|
616
611
|
const contextMenuWrapper = screen.getByText('Test Content').parentElement;
|
|
@@ -633,7 +628,7 @@ describe('HitContextMenu', () => {
|
|
|
633
628
|
mockGetMatchingTemplate.mockResolvedValue(createMockTemplate({
|
|
634
629
|
keys: ['howler.detection', 'event.id']
|
|
635
630
|
}));
|
|
636
|
-
rerender(_jsx(Wrapper, { children: _jsx(
|
|
631
|
+
rerender(_jsx(Wrapper, { children: _jsx(HitContextMenu, { getSelectedId: mockGetSelectedId, children: _jsx("div", { children: "Test Content" }) }) }));
|
|
637
632
|
});
|
|
638
633
|
it('should render inclusion submenu with template keys', async () => {
|
|
639
634
|
act(() => {
|
|
@@ -681,7 +676,7 @@ describe('HitContextMenu', () => {
|
|
|
681
676
|
mockGetMatchingTemplate.mockResolvedValue(createMockTemplate({
|
|
682
677
|
keys: ['howler.outline.indicators']
|
|
683
678
|
}));
|
|
684
|
-
rerender(_jsx(Wrapper, { children: _jsx(
|
|
679
|
+
rerender(_jsx(Wrapper, { children: _jsx(HitContextMenu, { getSelectedId: mockGetSelectedId, children: _jsx("div", { children: "Test Content" }) }) }));
|
|
685
680
|
act(() => {
|
|
686
681
|
const contextMenuWrapper = screen.getByText('Test Content').parentElement;
|
|
687
682
|
fireEvent.contextMenu(contextMenuWrapper);
|
|
@@ -724,7 +719,7 @@ describe('HitContextMenu', () => {
|
|
|
724
719
|
mockGetMatchingTemplate.mockResolvedValue(createMockTemplate({
|
|
725
720
|
keys: []
|
|
726
721
|
}));
|
|
727
|
-
rerender(_jsx(Wrapper, { children: _jsx(
|
|
722
|
+
rerender(_jsx(Wrapper, { children: _jsx(HitContextMenu, { getSelectedId: mockGetSelectedId, children: _jsx("div", { children: "Test Content" }) }) }));
|
|
728
723
|
act(() => {
|
|
729
724
|
const contextMenuWrapper = screen.getByText('Test Content').parentElement;
|
|
730
725
|
fireEvent.contextMenu(contextMenuWrapper);
|
|
@@ -736,7 +731,7 @@ describe('HitContextMenu', () => {
|
|
|
736
731
|
});
|
|
737
732
|
it('should skip null field values in inclusion menu', async () => {
|
|
738
733
|
act(() => {
|
|
739
|
-
|
|
734
|
+
mockHitContext.hits['test-hit-1'].event = {};
|
|
740
735
|
});
|
|
741
736
|
act(() => {
|
|
742
737
|
const contextMenuWrapper = screen.getByText('Test Content').parentElement;
|
|
@@ -755,24 +750,24 @@ describe('HitContextMenu', () => {
|
|
|
755
750
|
});
|
|
756
751
|
});
|
|
757
752
|
describe('Multiple Hit Selection', () => {
|
|
758
|
-
it('should use
|
|
753
|
+
it('should use selectedHits when current hit is included', async () => {
|
|
759
754
|
act(() => {
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
755
|
+
mockHitContext.hits['hit-1'] = createMockHit({ howler: { id: 'hit-1' } });
|
|
756
|
+
mockHitContext.hits['hit-2'] = createMockHit({ howler: { id: 'hit-2' } });
|
|
757
|
+
mockHitContext.selectedHits.push(mockHitContext.hits['hit-1'], mockHitContext.hits['hit-2']);
|
|
763
758
|
mockGetSelectedId.mockReturnValue('hit-1');
|
|
764
759
|
});
|
|
765
760
|
const contextMenuWrapper = screen.getByText('Test Content').parentElement;
|
|
766
761
|
await user.pointer({ keys: '[MouseRight]', target: contextMenuWrapper });
|
|
767
|
-
// The component should use
|
|
762
|
+
// The component should use selectedHits for actions
|
|
768
763
|
// We can verify this indirectly through the useHitActions hook receiving the right data
|
|
769
764
|
expect(screen.getByRole('menu')).toBeInTheDocument();
|
|
770
765
|
expect(mockGetSelectedId).toHaveBeenCalled();
|
|
771
766
|
});
|
|
772
|
-
it('should use only current hit when not in
|
|
767
|
+
it('should use only current hit when not in selectedHits', async () => {
|
|
773
768
|
act(() => {
|
|
774
|
-
|
|
775
|
-
|
|
769
|
+
mockHitContext.hits['hit-1'] = createMockHit({ howler: { id: 'hit-1' } });
|
|
770
|
+
mockHitContext.selectedHits.push(mockHitContext.hits['hit-1']);
|
|
776
771
|
mockGetSelectedId.mockReturnValue('test-hit-1');
|
|
777
772
|
});
|
|
778
773
|
const contextMenuWrapper = screen.getByText('Test Content').parentElement;
|
|
@@ -791,12 +786,12 @@ describe('HitContextMenu', () => {
|
|
|
791
786
|
});
|
|
792
787
|
it('should call getMatchingAnalytic when hit has analytic', async () => {
|
|
793
788
|
await waitFor(() => {
|
|
794
|
-
expect(mockGetMatchingAnalytic).toHaveBeenCalledWith(
|
|
789
|
+
expect(mockGetMatchingAnalytic).toHaveBeenCalledWith(mockHitContext.hits['test-hit-1']);
|
|
795
790
|
});
|
|
796
791
|
});
|
|
797
792
|
it('should call getMatchingTemplate when menu opens', async () => {
|
|
798
793
|
await waitFor(() => {
|
|
799
|
-
expect(mockGetMatchingTemplate).toHaveBeenCalledWith(
|
|
794
|
+
expect(mockGetMatchingTemplate).toHaveBeenCalledWith(mockHitContext.hits['test-hit-1']);
|
|
800
795
|
});
|
|
801
796
|
});
|
|
802
797
|
it('should reset state when menu closes', async () => {
|
|
@@ -829,7 +824,7 @@ describe('HitContextMenu', () => {
|
|
|
829
824
|
describe('Edge Cases and Error Handling', () => {
|
|
830
825
|
it('should not crash when hit is null', async () => {
|
|
831
826
|
act(() => {
|
|
832
|
-
|
|
827
|
+
mockHitContext.hits = {};
|
|
833
828
|
});
|
|
834
829
|
const contextMenuWrapper = screen.getByText('Test Content').parentElement;
|
|
835
830
|
fireEvent.contextMenu(contextMenuWrapper);
|
|
@@ -840,7 +835,7 @@ describe('HitContextMenu', () => {
|
|
|
840
835
|
});
|
|
841
836
|
it('should not render exclusion menu when template is null', async () => {
|
|
842
837
|
mockGetMatchingTemplate.mockResolvedValue(null);
|
|
843
|
-
rerender(_jsx(Wrapper, { children: _jsx(
|
|
838
|
+
rerender(_jsx(Wrapper, { children: _jsx(HitContextMenu, { getSelectedId: mockGetSelectedId, children: _jsx("div", { children: "Test Content" }) }) }));
|
|
844
839
|
act(() => {
|
|
845
840
|
const contextMenuWrapper = screen.getByText('Test Content').parentElement;
|
|
846
841
|
fireEvent.contextMenu(contextMenuWrapper);
|
|
@@ -854,7 +849,7 @@ describe('HitContextMenu', () => {
|
|
|
854
849
|
});
|
|
855
850
|
it('should not render inclusion menu when template is null', async () => {
|
|
856
851
|
mockGetMatchingTemplate.mockResolvedValue(null);
|
|
857
|
-
rerender(_jsx(Wrapper, { children: _jsx(
|
|
852
|
+
rerender(_jsx(Wrapper, { children: _jsx(HitContextMenu, { getSelectedId: mockGetSelectedId, children: _jsx("div", { children: "Test Content" }) }) }));
|
|
858
853
|
act(() => {
|
|
859
854
|
const contextMenuWrapper = screen.getByText('Test Content').parentElement;
|
|
860
855
|
fireEvent.contextMenu(contextMenuWrapper);
|
|
@@ -868,7 +863,7 @@ describe('HitContextMenu', () => {
|
|
|
868
863
|
});
|
|
869
864
|
it('should handle API failure gracefully', async () => {
|
|
870
865
|
mockDispatchApi.mockResolvedValue(null);
|
|
871
|
-
rerender(_jsx(Wrapper, { children: _jsx(
|
|
866
|
+
rerender(_jsx(Wrapper, { children: _jsx(HitContextMenu, { getSelectedId: mockGetSelectedId, children: _jsx("div", { children: "Test Content" }) }) }));
|
|
872
867
|
const contextMenuWrapper = screen.getByText('Test Content').parentElement;
|
|
873
868
|
fireEvent.contextMenu(contextMenuWrapper);
|
|
874
869
|
await waitFor(() => {
|
|
@@ -879,7 +874,7 @@ describe('HitContextMenu', () => {
|
|
|
879
874
|
});
|
|
880
875
|
it('should not call getMatchingAnalytic or getMatchingTemplate when hit has no analytic', async () => {
|
|
881
876
|
act(() => {
|
|
882
|
-
|
|
877
|
+
mockHitContext.hits['test-hit-1'].howler.analytic = null;
|
|
883
878
|
});
|
|
884
879
|
const contextMenuWrapper = screen.getByText('Test Content').parentElement;
|
|
885
880
|
fireEvent.contextMenu(contextMenuWrapper);
|
|
@@ -898,54 +893,4 @@ describe('HitContextMenu', () => {
|
|
|
898
893
|
expect(mockPluginStoreExecuteFunction).toHaveBeenCalled();
|
|
899
894
|
});
|
|
900
895
|
});
|
|
901
|
-
describe('Add to Case Menu Item', () => {
|
|
902
|
-
it('should render "Add to Case" item in the menu', async () => {
|
|
903
|
-
act(() => {
|
|
904
|
-
const contextMenuWrapper = screen.getByText('Test Content').parentElement;
|
|
905
|
-
fireEvent.contextMenu(contextMenuWrapper);
|
|
906
|
-
});
|
|
907
|
-
await waitFor(() => {
|
|
908
|
-
expect(screen.getByText('Add to Case')).toBeInTheDocument();
|
|
909
|
-
});
|
|
910
|
-
});
|
|
911
|
-
it('should enable "Add to Case" when a record is present', async () => {
|
|
912
|
-
act(() => {
|
|
913
|
-
const contextMenuWrapper = screen.getByText('Test Content').parentElement;
|
|
914
|
-
fireEvent.contextMenu(contextMenuWrapper);
|
|
915
|
-
});
|
|
916
|
-
await waitFor(() => {
|
|
917
|
-
const menuItems = screen.getAllByRole('menuitem');
|
|
918
|
-
const addToCaseItem = menuItems.find(item => item.textContent?.includes('Add to Case'));
|
|
919
|
-
expect(addToCaseItem).toHaveAttribute('aria-disabled', 'false');
|
|
920
|
-
});
|
|
921
|
-
});
|
|
922
|
-
it('should disable "Add to Case" when record is null', async () => {
|
|
923
|
-
act(() => {
|
|
924
|
-
mockRecordContext.records['test-hit-1'] = null;
|
|
925
|
-
const contextMenuWrapper = screen.getByText('Test Content').parentElement;
|
|
926
|
-
fireEvent.contextMenu(contextMenuWrapper);
|
|
927
|
-
});
|
|
928
|
-
await waitFor(() => {
|
|
929
|
-
const menuItems = screen.getAllByRole('menuitem');
|
|
930
|
-
const addToCaseItem = menuItems.find(item => item.textContent?.includes('Add to Case'));
|
|
931
|
-
expect(addToCaseItem).toHaveAttribute('aria-disabled', 'true');
|
|
932
|
-
});
|
|
933
|
-
});
|
|
934
|
-
it('should call showModal with an AddToCaseModal element when clicked', async () => {
|
|
935
|
-
act(() => {
|
|
936
|
-
const contextMenuWrapper = screen.getByText('Test Content').parentElement;
|
|
937
|
-
fireEvent.contextMenu(contextMenuWrapper);
|
|
938
|
-
});
|
|
939
|
-
await waitFor(() => {
|
|
940
|
-
expect(screen.getByText('Add to Case')).toBeInTheDocument();
|
|
941
|
-
});
|
|
942
|
-
await act(async () => {
|
|
943
|
-
await user.click(screen.getByText('Add to Case'));
|
|
944
|
-
});
|
|
945
|
-
await waitFor(() => {
|
|
946
|
-
expect(mockShowModal).toHaveBeenCalledOnce();
|
|
947
|
-
expect(mockShowModal).toHaveBeenCalledWith(expect.objectContaining({ type: expect.any(Function) }));
|
|
948
|
-
});
|
|
949
|
-
});
|
|
950
|
-
});
|
|
951
896
|
});
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
export type
|
|
1
|
+
export type HitQueryProps = {
|
|
2
2
|
triggerSearch: (query: string) => void;
|
|
3
3
|
onChange?: (query: string, isDirty: boolean) => void;
|
|
4
4
|
searching?: boolean;
|
|
5
5
|
disabled?: boolean;
|
|
6
6
|
compact?: boolean;
|
|
7
7
|
};
|
|
8
|
-
declare const _default: import("react").NamedExoticComponent<
|
|
8
|
+
declare const _default: import("react").NamedExoticComponent<HitQueryProps>;
|
|
9
9
|
export default _default;
|
|
@@ -5,7 +5,7 @@ import { Badge, Box, Card, Skeleton, Tooltip, alpha, useTheme } from '@mui/mater
|
|
|
5
5
|
import { ParameterContext } from '@cccsaurora/howler-ui/components/app/providers/ParameterProvider';
|
|
6
6
|
import TuiIconButton from '@cccsaurora/howler-ui/components/elements/addons/buttons/CustomIconButton';
|
|
7
7
|
import QueryEditor from '@cccsaurora/howler-ui/components/routes/advanced/QueryEditor';
|
|
8
|
-
import {
|
|
8
|
+
import { HitSearchContext } from '@cccsaurora/howler-ui/components/app/providers/HitSearchProvider';
|
|
9
9
|
import { memo, useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
|
10
10
|
import { useTranslation } from 'react-i18next';
|
|
11
11
|
import { useLocation } from 'react-router-dom';
|
|
@@ -13,8 +13,8 @@ import { useContextSelector } from 'use-context-selector';
|
|
|
13
13
|
import { DEFAULT_QUERY } from '@cccsaurora/howler-ui/utils/constants';
|
|
14
14
|
import { sanitizeMultilineLucene } from '@cccsaurora/howler-ui/utils/stringUtils';
|
|
15
15
|
const DEFAULT_MULTILINE_HEIGHT = 250;
|
|
16
|
-
const PROMPT_CONTEXT = '
|
|
17
|
-
const
|
|
16
|
+
const PROMPT_CONTEXT = 'isHitQuery && !suggestWidgetVisible && !renameInputVisible && !inSnippetMode && !quickFixWidgetVisible';
|
|
17
|
+
const HitQuery = ({ searching = false, disabled = false, compact = false, triggerSearch, onChange }) => {
|
|
18
18
|
const { t } = useTranslation();
|
|
19
19
|
const location = useLocation();
|
|
20
20
|
const theme = useTheme();
|
|
@@ -22,7 +22,7 @@ const RecordQuery = ({ searching = false, disabled = false, compact = false, tri
|
|
|
22
22
|
const savedQuery = useContextSelector(ParameterContext, ctx => ctx.query || DEFAULT_QUERY);
|
|
23
23
|
const prevQuery = useRef(null);
|
|
24
24
|
const [query, setQuery] = useState(new URLSearchParams(window.location.search).get('query') || DEFAULT_QUERY);
|
|
25
|
-
const fzfSearch = useContextSelector(
|
|
25
|
+
const fzfSearch = useContextSelector(HitSearchContext, ctx => ctx?.fzfSearch ?? false);
|
|
26
26
|
const [loaded, setLoaded] = useState(false);
|
|
27
27
|
const [multiline, setMultiline] = useState(false);
|
|
28
28
|
const [y, setY] = useState(0);
|
|
@@ -90,7 +90,7 @@ const RecordQuery = ({ searching = false, disabled = false, compact = false, tri
|
|
|
90
90
|
window.addEventListener('mouseup', onMouseUp);
|
|
91
91
|
}, [onMouseMove, onMouseUp]);
|
|
92
92
|
const onMount = useCallback((ed) => {
|
|
93
|
-
ed.createContextKey('
|
|
93
|
+
ed.createContextKey('isHitQuery', true);
|
|
94
94
|
setLoaded(true);
|
|
95
95
|
}, []);
|
|
96
96
|
const options = useMemo(() => ({
|
|
@@ -148,4 +148,4 @@ const RecordQuery = ({ searching = false, disabled = false, compact = false, tri
|
|
|
148
148
|
zIndex: 1000
|
|
149
149
|
}, onMouseDown: onMouseDown }))] }));
|
|
150
150
|
};
|
|
151
|
-
export default memo(
|
|
151
|
+
export default memo(HitQuery);
|