@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
|
@@ -13,12 +13,12 @@ import { createContext, useContextSelector } from 'use-context-selector';
|
|
|
13
13
|
import { DEFAULT_QUERY, StorageKey } from '@cccsaurora/howler-ui/utils/constants';
|
|
14
14
|
import Throttler from '@cccsaurora/howler-ui/utils/Throttler';
|
|
15
15
|
import { convertCustomDateRangeToLucene, convertDateToLucene } from '@cccsaurora/howler-ui/utils/utils';
|
|
16
|
+
import { HitContext } from './HitProvider';
|
|
16
17
|
import { ParameterContext } from './ParameterProvider';
|
|
17
|
-
import { RecordContext } from './RecordProvider';
|
|
18
18
|
import { ViewContext } from './ViewProvider';
|
|
19
|
-
export const
|
|
19
|
+
export const HitSearchContext = createContext(null);
|
|
20
20
|
const THROTTLER = new Throttler(500);
|
|
21
|
-
const
|
|
21
|
+
const HitSearchProvider = ({ children }) => {
|
|
22
22
|
const { get } = useMyLocalStorage();
|
|
23
23
|
const routeParams = useParams();
|
|
24
24
|
const location = useLocation();
|
|
@@ -33,13 +33,12 @@ const RecordSearchProvider = ({ children }) => {
|
|
|
33
33
|
const trackTotalHits = useContextSelector(ParameterContext, ctx => ctx.trackTotalHits);
|
|
34
34
|
const sort = useContextSelector(ParameterContext, ctx => ctx.sort);
|
|
35
35
|
const span = useContextSelector(ParameterContext, ctx => ctx.span);
|
|
36
|
-
const indexes = useContextSelector(ParameterContext, ctx => ctx.indexes);
|
|
37
36
|
const allFilters = useContextSelector(ParameterContext, ctx => ctx.filters);
|
|
38
37
|
const startDate = useContextSelector(ParameterContext, ctx => ctx.startDate);
|
|
39
38
|
const endDate = useContextSelector(ParameterContext, ctx => ctx.endDate);
|
|
40
39
|
const views = useContextSelector(ParameterContext, ctx => ctx.views);
|
|
41
40
|
const addView = useContextSelector(ParameterContext, ctx => ctx.addView);
|
|
42
|
-
const loadHits = useContextSelector(
|
|
41
|
+
const loadHits = useContextSelector(HitContext, ctx => ctx.loadHits);
|
|
43
42
|
const [displayType, setDisplayType] = useState(get(StorageKey.DISPLAY_TYPE) ?? 'list');
|
|
44
43
|
const [searching, setSearching] = useState(false);
|
|
45
44
|
const [error, setError] = useState(null);
|
|
@@ -48,6 +47,7 @@ const RecordSearchProvider = ({ children }) => {
|
|
|
48
47
|
'howler.id: *': new Date().toISOString()
|
|
49
48
|
});
|
|
50
49
|
const [fzfSearch, setFzfSearch] = useState(false);
|
|
50
|
+
const bundleId = useMemo(() => (location.pathname.startsWith('/bundles') ? routeParams.id : null), [location.pathname, routeParams.id]);
|
|
51
51
|
const filters = useMemo(() => allFilters.filter(filter => !filter.endsWith('*')), [allFilters]);
|
|
52
52
|
// On load check to filter out any queries older than one month
|
|
53
53
|
useEffect(() => {
|
|
@@ -70,6 +70,11 @@ const RecordSearchProvider = ({ children }) => {
|
|
|
70
70
|
else if (startDate && endDate) {
|
|
71
71
|
_filters.push(`event.created:${convertCustomDateRangeToLucene(startDate, endDate)}`);
|
|
72
72
|
}
|
|
73
|
+
// Add bundle filter
|
|
74
|
+
const bundle = location.pathname.startsWith('/bundles') && routeParams.id;
|
|
75
|
+
if (bundle) {
|
|
76
|
+
_filters.push(`howler.bundles:${bundle}`);
|
|
77
|
+
}
|
|
73
78
|
// Fetch all view queries
|
|
74
79
|
if (views.length > 0) {
|
|
75
80
|
const viewObjects = await getCurrentViews({ views });
|
|
@@ -80,7 +85,7 @@ const RecordSearchProvider = ({ children }) => {
|
|
|
80
85
|
.forEach(viewQuery => _filters.push(viewQuery));
|
|
81
86
|
}
|
|
82
87
|
return _filters;
|
|
83
|
-
}, [endDate, filters, getCurrentViews, span, startDate, views]);
|
|
88
|
+
}, [endDate, filters, getCurrentViews, location.pathname, routeParams.id, span, startDate, views]);
|
|
84
89
|
const search = useCallback(async (_query, appendResults) => {
|
|
85
90
|
THROTTLER.debounce(async () => {
|
|
86
91
|
if (_query === 'woof!') {
|
|
@@ -100,7 +105,7 @@ const RecordSearchProvider = ({ children }) => {
|
|
|
100
105
|
setSearching(true);
|
|
101
106
|
setError(null);
|
|
102
107
|
try {
|
|
103
|
-
const _response = await dispatchApi(api.
|
|
108
|
+
const _response = await dispatchApi(api.search.hit.post({
|
|
104
109
|
offset: appendResults && response ? response.rows : offset,
|
|
105
110
|
rows: pageCount,
|
|
106
111
|
query: _query || DEFAULT_QUERY,
|
|
@@ -142,7 +147,6 @@ const RecordSearchProvider = ({ children }) => {
|
|
|
142
147
|
startDate,
|
|
143
148
|
endDate,
|
|
144
149
|
filters,
|
|
145
|
-
indexes,
|
|
146
150
|
setQuery,
|
|
147
151
|
location.pathname,
|
|
148
152
|
routeParams.id,
|
|
@@ -161,15 +165,15 @@ const RecordSearchProvider = ({ children }) => {
|
|
|
161
165
|
if (span?.endsWith('custom') && (!startDate || !endDate)) {
|
|
162
166
|
return;
|
|
163
167
|
}
|
|
164
|
-
if (views.length > 0 || (query && query !== DEFAULT_QUERY) || offset > 0 || filters.length > 0) {
|
|
168
|
+
if (views.length > 0 || bundleId || (query && query !== DEFAULT_QUERY) || offset > 0 || filters.length > 0) {
|
|
165
169
|
search(query);
|
|
166
170
|
}
|
|
167
171
|
else {
|
|
168
172
|
setResponse(null);
|
|
169
173
|
}
|
|
170
174
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
171
|
-
}, [offset, pageCount, sort, span,
|
|
172
|
-
return (_jsx(
|
|
175
|
+
}, [offset, pageCount, sort, span, bundleId, location.pathname, startDate, endDate, filters, query, views]);
|
|
176
|
+
return (_jsx(HitSearchContext.Provider, { value: {
|
|
173
177
|
displayType,
|
|
174
178
|
setDisplayType,
|
|
175
179
|
search,
|
|
@@ -177,10 +181,11 @@ const RecordSearchProvider = ({ children }) => {
|
|
|
177
181
|
getFilters,
|
|
178
182
|
error,
|
|
179
183
|
response,
|
|
184
|
+
bundleId,
|
|
180
185
|
setQueryHistory,
|
|
181
186
|
queryHistory,
|
|
182
187
|
fzfSearch,
|
|
183
188
|
setFzfSearch
|
|
184
189
|
}, children: children }));
|
|
185
190
|
};
|
|
186
|
-
export default
|
|
191
|
+
export default HitSearchProvider;
|
|
@@ -5,9 +5,9 @@ import { cloneDeep } from 'lodash-es';
|
|
|
5
5
|
import { setupContextSelectorMock, setupLocalStorageMock } from '@cccsaurora/howler-ui/tests/mocks';
|
|
6
6
|
import { useContextSelector } from 'use-context-selector';
|
|
7
7
|
import { DEFAULT_QUERY, MY_LOCAL_STORAGE_PREFIX, StorageKey } from '@cccsaurora/howler-ui/utils/constants';
|
|
8
|
+
import { HitContext } from './HitProvider';
|
|
9
|
+
import HitSearchProvider, { HitSearchContext } from './HitSearchProvider';
|
|
8
10
|
import { ParameterContext } from './ParameterProvider';
|
|
9
|
-
import { RecordContext } from './RecordProvider';
|
|
10
|
-
import RecordSearchProvider, { RecordSearchContext } from './RecordSearchProvider';
|
|
11
11
|
import { ViewContext } from './ViewProvider';
|
|
12
12
|
vi.mock('api', { spy: true });
|
|
13
13
|
setupContextSelectorMock();
|
|
@@ -30,21 +30,20 @@ let mockParameterContext = {
|
|
|
30
30
|
mockParameterContext.offset = parseInt(offset);
|
|
31
31
|
},
|
|
32
32
|
views: [],
|
|
33
|
-
indexes: ['hit'],
|
|
34
33
|
addView: vi.fn()
|
|
35
34
|
};
|
|
36
35
|
const originalMockParameterContext = cloneDeep(mockParameterContext);
|
|
37
36
|
const mockHitContext = {
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
mockHitContext.
|
|
41
|
-
...mockHitContext.
|
|
37
|
+
hits: {},
|
|
38
|
+
loadHits: hits => {
|
|
39
|
+
mockHitContext.hits = {
|
|
40
|
+
...mockHitContext.hits,
|
|
42
41
|
...Object.fromEntries(hits.map(hit => [hit.howler.id, hit]))
|
|
43
42
|
};
|
|
44
43
|
}
|
|
45
44
|
};
|
|
46
45
|
const Wrapper = ({ children }) => {
|
|
47
|
-
return (_jsx(ViewContext.Provider, { value: mockViewContext, children: _jsx(ParameterContext.Provider, { value: mockParameterContext, children: _jsx(
|
|
46
|
+
return (_jsx(ViewContext.Provider, { value: mockViewContext, children: _jsx(ParameterContext.Provider, { value: mockParameterContext, children: _jsx(HitContext.Provider, { value: mockHitContext, children: _jsx(HitSearchProvider, { children: children }) }) }) }));
|
|
48
47
|
};
|
|
49
48
|
beforeEach(() => {
|
|
50
49
|
mockParameterContext = cloneDeep(originalMockParameterContext);
|
|
@@ -58,32 +57,38 @@ beforeEach(() => {
|
|
|
58
57
|
let mockSearchParams = new URLSearchParams();
|
|
59
58
|
vi.mocked(useSearchParams).mockReturnValue([mockSearchParams, mockSetParams]);
|
|
60
59
|
});
|
|
61
|
-
describe('
|
|
60
|
+
describe('HitSearchContext', () => {
|
|
62
61
|
it('should initialize with default values', async () => {
|
|
63
|
-
const hook = renderHook(() => useContextSelector(
|
|
62
|
+
const hook = renderHook(() => useContextSelector(HitSearchContext, ctx => ({
|
|
64
63
|
displayType: ctx.displayType,
|
|
65
64
|
searching: ctx.searching,
|
|
66
65
|
error: ctx.error,
|
|
67
66
|
response: ctx.response,
|
|
67
|
+
bundleId: ctx.bundleId,
|
|
68
68
|
fzfSearch: ctx.fzfSearch
|
|
69
69
|
})), { wrapper: Wrapper });
|
|
70
70
|
expect(hook.result.current.displayType).toBe('list');
|
|
71
71
|
expect(hook.result.current.searching).toBe(false);
|
|
72
72
|
expect(hook.result.current.error).toBeNull();
|
|
73
73
|
expect(hook.result.current.response).toBeNull();
|
|
74
|
+
expect(hook.result.current.bundleId).toBeNull();
|
|
74
75
|
expect(hook.result.current.fzfSearch).toBe(false);
|
|
75
76
|
});
|
|
77
|
+
it('should set bundleId when on bundles route', () => {
|
|
78
|
+
mockLocation.pathname = '/bundles/test_bundle_id';
|
|
79
|
+
mockParams.mockReturnValue({ id: 'test_bundle_id' });
|
|
80
|
+
const hook = renderHook(() => useContextSelector(HitSearchContext, ctx => ctx.bundleId), { wrapper: Wrapper });
|
|
81
|
+
expect(hook.result.current).toBe('test_bundle_id');
|
|
82
|
+
});
|
|
76
83
|
it('should initialize queryHistory from localStorage', () => {
|
|
77
84
|
const mockHistory = { 'test:query': new Date().toISOString() };
|
|
78
85
|
mockLocalStorage.setItem(`${MY_LOCAL_STORAGE_PREFIX}.${StorageKey.QUERY_HISTORY}`, JSON.stringify(mockHistory));
|
|
79
|
-
const hook = renderHook(() => useContextSelector(
|
|
80
|
-
wrapper: Wrapper
|
|
81
|
-
});
|
|
86
|
+
const hook = renderHook(() => useContextSelector(HitSearchContext, ctx => ctx.queryHistory), { wrapper: Wrapper });
|
|
82
87
|
expect(hook.result.current).toEqual(mockHistory);
|
|
83
88
|
});
|
|
84
89
|
describe('setDisplayType', () => {
|
|
85
90
|
it('should update display type', () => {
|
|
86
|
-
const hook = renderHook(() => useContextSelector(
|
|
91
|
+
const hook = renderHook(() => useContextSelector(HitSearchContext, ctx => ({
|
|
87
92
|
displayType: ctx.displayType,
|
|
88
93
|
setDisplayType: ctx.setDisplayType
|
|
89
94
|
})), { wrapper: Wrapper });
|
|
@@ -96,7 +101,7 @@ describe('RecordSearchContext', () => {
|
|
|
96
101
|
});
|
|
97
102
|
describe('setFzfSearch', () => {
|
|
98
103
|
it('should update fzfSearch state', () => {
|
|
99
|
-
const hook = renderHook(() => useContextSelector(
|
|
104
|
+
const hook = renderHook(() => useContextSelector(HitSearchContext, ctx => ({
|
|
100
105
|
fzfSearch: ctx.fzfSearch,
|
|
101
106
|
setFzfSearch: ctx.setFzfSearch
|
|
102
107
|
})), { wrapper: Wrapper });
|
|
@@ -109,7 +114,7 @@ describe('RecordSearchContext', () => {
|
|
|
109
114
|
});
|
|
110
115
|
describe('setQueryHistory', () => {
|
|
111
116
|
it('should update query history', () => {
|
|
112
|
-
const hook = renderHook(() => useContextSelector(
|
|
117
|
+
const hook = renderHook(() => useContextSelector(HitSearchContext, ctx => ({
|
|
113
118
|
queryHistory: ctx.queryHistory,
|
|
114
119
|
setQueryHistory: ctx.setQueryHistory
|
|
115
120
|
})), { wrapper: Wrapper });
|
|
@@ -122,7 +127,7 @@ describe('RecordSearchContext', () => {
|
|
|
122
127
|
});
|
|
123
128
|
describe('search', () => {
|
|
124
129
|
it('should perform a search and update response', async () => {
|
|
125
|
-
const hook = renderHook(() => useContextSelector(
|
|
130
|
+
const hook = renderHook(() => useContextSelector(HitSearchContext, ctx => ({
|
|
126
131
|
search: ctx.search,
|
|
127
132
|
searching: ctx.searching,
|
|
128
133
|
response: ctx.response,
|
|
@@ -132,13 +137,13 @@ describe('RecordSearchContext', () => {
|
|
|
132
137
|
hook.result.current.search('test query');
|
|
133
138
|
});
|
|
134
139
|
await waitFor(() => {
|
|
135
|
-
expect(hpost).toHaveBeenCalledWith('/api/
|
|
140
|
+
expect(hpost).toHaveBeenCalledWith('/api/v1/search/hit', expect.objectContaining({
|
|
136
141
|
query: expect.stringContaining('test query')
|
|
137
142
|
}));
|
|
138
143
|
});
|
|
139
144
|
});
|
|
140
145
|
it('should set searching state during search', async () => {
|
|
141
|
-
const hook = renderHook(() => useContextSelector(
|
|
146
|
+
const hook = renderHook(() => useContextSelector(HitSearchContext, ctx => ({
|
|
142
147
|
search: ctx.search,
|
|
143
148
|
searching: ctx.searching
|
|
144
149
|
})), { wrapper: Wrapper });
|
|
@@ -167,7 +172,7 @@ describe('RecordSearchContext', () => {
|
|
|
167
172
|
});
|
|
168
173
|
it('should handle search errors', async () => {
|
|
169
174
|
vi.mocked(hpost).mockRejectedValueOnce(new Error('Search failed'));
|
|
170
|
-
const hook = renderHook(() => useContextSelector(
|
|
175
|
+
const hook = renderHook(() => useContextSelector(HitSearchContext, ctx => ({
|
|
171
176
|
search: ctx.search,
|
|
172
177
|
error: ctx.error,
|
|
173
178
|
searching: ctx.searching
|
|
@@ -188,7 +193,7 @@ describe('RecordSearchContext', () => {
|
|
|
188
193
|
total: 10
|
|
189
194
|
};
|
|
190
195
|
vi.mocked(hpost).mockResolvedValueOnce(mockResponse);
|
|
191
|
-
const hook = renderHook(() => useContextSelector(
|
|
196
|
+
const hook = renderHook(() => useContextSelector(HitSearchContext, ctx => ({
|
|
192
197
|
search: ctx.search,
|
|
193
198
|
response: ctx.response
|
|
194
199
|
})), { wrapper: Wrapper });
|
|
@@ -216,13 +221,27 @@ describe('RecordSearchContext', () => {
|
|
|
216
221
|
expect(hook.result.current.response?.items.length).toBe(2);
|
|
217
222
|
});
|
|
218
223
|
});
|
|
224
|
+
it('should include bundle filter when on bundles route', async () => {
|
|
225
|
+
mockLocation.pathname = '/bundles/test_bundle_id';
|
|
226
|
+
mockParams.mockReturnValue({ id: 'test_bundle_id' });
|
|
227
|
+
const hook = renderHook(() => useContextSelector(HitSearchContext, ctx => ctx.search), { wrapper: Wrapper });
|
|
228
|
+
act(() => {
|
|
229
|
+
hook.result.current('test query');
|
|
230
|
+
});
|
|
231
|
+
await waitFor(() => {
|
|
232
|
+
expect(hpost).toHaveBeenCalledWith('/api/v1/search/hit', expect.objectContaining({
|
|
233
|
+
query: 'test query',
|
|
234
|
+
filters: ['event.created:[now-1w TO now]', 'howler.bundles:test_bundle_id']
|
|
235
|
+
}));
|
|
236
|
+
});
|
|
237
|
+
});
|
|
219
238
|
it('should apply date range filter from span', async () => {
|
|
220
|
-
const hook = renderHook(() => useContextSelector(
|
|
239
|
+
const hook = renderHook(() => useContextSelector(HitSearchContext, ctx => ctx.search), { wrapper: Wrapper });
|
|
221
240
|
act(() => {
|
|
222
241
|
hook.result.current('test query');
|
|
223
242
|
});
|
|
224
243
|
await waitFor(() => {
|
|
225
|
-
expect(hpost).toHaveBeenCalledWith('/api/
|
|
244
|
+
expect(hpost).toHaveBeenCalledWith('/api/v1/search/hit', expect.objectContaining({
|
|
226
245
|
filters: expect.arrayContaining([expect.stringContaining('event.created:')])
|
|
227
246
|
}));
|
|
228
247
|
});
|
|
@@ -231,24 +250,24 @@ describe('RecordSearchContext', () => {
|
|
|
231
250
|
mockParameterContext.span = 'date.range.custom';
|
|
232
251
|
mockParameterContext.startDate = '2025-01-01';
|
|
233
252
|
mockParameterContext.endDate = '2025-12-31';
|
|
234
|
-
const hook = renderHook(() => useContextSelector(
|
|
253
|
+
const hook = renderHook(() => useContextSelector(HitSearchContext, ctx => ctx.search), { wrapper: Wrapper });
|
|
235
254
|
act(() => {
|
|
236
255
|
hook.result.current('test query');
|
|
237
256
|
});
|
|
238
257
|
await waitFor(() => {
|
|
239
|
-
expect(hpost).toHaveBeenCalledWith('/api/
|
|
258
|
+
expect(hpost).toHaveBeenCalledWith('/api/v1/search/hit', expect.objectContaining({
|
|
240
259
|
filters: expect.arrayContaining([expect.stringContaining('event.created:')])
|
|
241
260
|
}));
|
|
242
261
|
});
|
|
243
262
|
});
|
|
244
263
|
it('should exclude filters ending with * from search', async () => {
|
|
245
264
|
mockParameterContext.filters = ['status:open', 'howler.escalation:*'];
|
|
246
|
-
const hook = renderHook(() => useContextSelector(
|
|
265
|
+
const hook = renderHook(() => useContextSelector(HitSearchContext, ctx => ctx.search), { wrapper: Wrapper });
|
|
247
266
|
act(() => {
|
|
248
267
|
hook.result.current('test query');
|
|
249
268
|
});
|
|
250
269
|
await waitFor(() => {
|
|
251
|
-
expect(hpost).toHaveBeenCalledWith('/api/
|
|
270
|
+
expect(hpost).toHaveBeenCalledWith('/api/v1/search/hit', expect.objectContaining({
|
|
252
271
|
filters: expect.not.arrayContaining([expect.stringContaining('howler.escalation:*')])
|
|
253
272
|
}));
|
|
254
273
|
});
|
|
@@ -261,7 +280,7 @@ describe('RecordSearchContext', () => {
|
|
|
261
280
|
rows: 0,
|
|
262
281
|
total: 50
|
|
263
282
|
});
|
|
264
|
-
const hook = renderHook(() => useContextSelector(
|
|
283
|
+
const hook = renderHook(() => useContextSelector(HitSearchContext, ctx => ({
|
|
265
284
|
search: ctx.search
|
|
266
285
|
})), { wrapper: Wrapper });
|
|
267
286
|
act(() => {
|
|
@@ -275,7 +294,7 @@ describe('RecordSearchContext', () => {
|
|
|
275
294
|
it('should not search when sort or span is null', async () => {
|
|
276
295
|
mockParameterContext.sort = null;
|
|
277
296
|
mockParameterContext.span = null;
|
|
278
|
-
const hook = renderHook(() => useContextSelector(
|
|
297
|
+
const hook = renderHook(() => useContextSelector(HitSearchContext, ctx => ctx.search), { wrapper: Wrapper });
|
|
279
298
|
act(() => {
|
|
280
299
|
hook.result.current('test query');
|
|
281
300
|
});
|
|
@@ -287,7 +306,7 @@ describe('RecordSearchContext', () => {
|
|
|
287
306
|
});
|
|
288
307
|
describe('automatic search on parameter changes', () => {
|
|
289
308
|
it('should trigger search when filters change', async () => {
|
|
290
|
-
const hook = renderHook(() => useContextSelector(
|
|
309
|
+
const hook = renderHook(() => useContextSelector(HitSearchContext, ctx => ({
|
|
291
310
|
response: ctx.response
|
|
292
311
|
})), { wrapper: Wrapper });
|
|
293
312
|
await waitFor(() => {
|
|
@@ -301,23 +320,23 @@ describe('RecordSearchContext', () => {
|
|
|
301
320
|
expect(hpost).toHaveBeenCalled();
|
|
302
321
|
}, { timeout: 2000 });
|
|
303
322
|
});
|
|
304
|
-
it('should not trigger search when query is DEFAULT_QUERY', async () => {
|
|
323
|
+
it('should not trigger search when query is DEFAULT_QUERY and no bundleId', async () => {
|
|
305
324
|
mockParameterContext.query = DEFAULT_QUERY;
|
|
306
|
-
renderHook(() => useContextSelector(
|
|
325
|
+
renderHook(() => useContextSelector(HitSearchContext, ctx => ctx.response), { wrapper: Wrapper });
|
|
307
326
|
await waitFor(() => {
|
|
308
327
|
expect(hpost).not.toHaveBeenCalled();
|
|
309
328
|
});
|
|
310
329
|
});
|
|
311
330
|
it('should not trigger search when span is custom but dates are missing', async () => {
|
|
312
|
-
renderHook(() => useContextSelector(
|
|
331
|
+
renderHook(() => useContextSelector(HitSearchContext, ctx => ctx.response), { wrapper: Wrapper });
|
|
313
332
|
await waitFor(() => {
|
|
314
333
|
expect(hpost).not.toHaveBeenCalled();
|
|
315
334
|
});
|
|
316
335
|
});
|
|
317
336
|
});
|
|
318
|
-
describe('
|
|
337
|
+
describe('useHitSearchContextSelector', () => {
|
|
319
338
|
it('should allow selecting specific values from context', async () => {
|
|
320
|
-
const hook = renderHook(() => useContextSelector(
|
|
339
|
+
const hook = renderHook(() => useContextSelector(HitSearchContext, ctx => ({
|
|
321
340
|
searching: ctx.searching,
|
|
322
341
|
error: ctx.error
|
|
323
342
|
})), { wrapper: Wrapper });
|
|
@@ -327,7 +346,7 @@ describe('RecordSearchContext', () => {
|
|
|
327
346
|
});
|
|
328
347
|
describe('edge cases', () => {
|
|
329
348
|
it('should handle concurrent search calls with throttling', async () => {
|
|
330
|
-
const hook = renderHook(() => useContextSelector(
|
|
349
|
+
const hook = renderHook(() => useContextSelector(HitSearchContext, ctx => ctx.search), { wrapper: Wrapper });
|
|
331
350
|
// Make multiple rapid calls
|
|
332
351
|
act(() => {
|
|
333
352
|
hook.result.current('query1');
|
|
@@ -339,8 +358,8 @@ describe('RecordSearchContext', () => {
|
|
|
339
358
|
expect(hpost).toHaveBeenCalledTimes(1);
|
|
340
359
|
}, { timeout: 2000 });
|
|
341
360
|
});
|
|
342
|
-
it('should clear response when query becomes DEFAULT_QUERY without viewId', async () => {
|
|
343
|
-
const hook = renderHook(() => useContextSelector(
|
|
361
|
+
it('should clear response when query becomes DEFAULT_QUERY without viewId or bundleId', async () => {
|
|
362
|
+
const hook = renderHook(() => useContextSelector(HitSearchContext, ctx => ctx.response), { wrapper: Wrapper });
|
|
344
363
|
await waitFor(() => {
|
|
345
364
|
expect(hook.result.current).toBeDefined();
|
|
346
365
|
}, { timeout: 2000 });
|
|
@@ -360,12 +379,12 @@ describe('RecordSearchContext', () => {
|
|
|
360
379
|
{ view_id: 'view_1', query: 'howler.status:open' },
|
|
361
380
|
{ view_id: 'view_2', query: 'howler.priority:high' }
|
|
362
381
|
]);
|
|
363
|
-
const hook = renderHook(() => useContextSelector(
|
|
382
|
+
const hook = renderHook(() => useContextSelector(HitSearchContext, ctx => ctx.search), { wrapper: Wrapper });
|
|
364
383
|
act(() => {
|
|
365
384
|
hook.result.current('test query');
|
|
366
385
|
});
|
|
367
386
|
await waitFor(() => {
|
|
368
|
-
expect(hpost).toHaveBeenCalledWith('/api/
|
|
387
|
+
expect(hpost).toHaveBeenCalledWith('/api/v1/search/hit', expect.objectContaining({
|
|
369
388
|
query: 'test query',
|
|
370
389
|
filters: expect.arrayContaining(['howler.status:open', 'howler.priority:high'])
|
|
371
390
|
}));
|
|
@@ -378,12 +397,12 @@ describe('RecordSearchContext', () => {
|
|
|
378
397
|
{ view_id: 'view_2', query: 'howler.priority:high' },
|
|
379
398
|
{ view_id: 'view_3', query: 'howler.analytic:sigma' }
|
|
380
399
|
]);
|
|
381
|
-
const hook = renderHook(() => useContextSelector(
|
|
400
|
+
const hook = renderHook(() => useContextSelector(HitSearchContext, ctx => ctx.search), { wrapper: Wrapper });
|
|
382
401
|
act(() => {
|
|
383
402
|
hook.result.current('test query');
|
|
384
403
|
});
|
|
385
404
|
await waitFor(() => {
|
|
386
|
-
expect(hpost).toHaveBeenCalledWith('/api/
|
|
405
|
+
expect(hpost).toHaveBeenCalledWith('/api/v1/search/hit', expect.objectContaining({
|
|
387
406
|
query: 'test query',
|
|
388
407
|
filters: [
|
|
389
408
|
'event.created:[now-1w TO now]',
|
|
@@ -402,7 +421,7 @@ describe('RecordSearchContext', () => {
|
|
|
402
421
|
mockParameterContext.views = [];
|
|
403
422
|
const mockSearchParams = new URLSearchParams();
|
|
404
423
|
vi.mocked(useSearchParams).mockReturnValue([mockSearchParams, mockSetParams]);
|
|
405
|
-
renderHook(() => useContextSelector(
|
|
424
|
+
renderHook(() => useContextSelector(HitSearchContext, () => { }), { wrapper: Wrapper });
|
|
406
425
|
await waitFor(() => {
|
|
407
426
|
expect(mockParameterContext.addView).toBeCalledWith('default_view_id');
|
|
408
427
|
});
|
|
@@ -414,7 +433,7 @@ describe('RecordSearchContext', () => {
|
|
|
414
433
|
const mockSearchParams = new URLSearchParams();
|
|
415
434
|
mockSearchParams.append('view', 'existing_view');
|
|
416
435
|
vi.mocked(useSearchParams).mockReturnValue([mockSearchParams, mockSetParams]);
|
|
417
|
-
renderHook(() => useContextSelector(
|
|
436
|
+
renderHook(() => useContextSelector(HitSearchContext, () => { }), { wrapper: Wrapper });
|
|
418
437
|
await waitFor(() => {
|
|
419
438
|
expect(mockParameterContext.addView).not.toBeCalled();
|
|
420
439
|
});
|
|
@@ -425,7 +444,7 @@ describe('RecordSearchContext', () => {
|
|
|
425
444
|
mockParameterContext.views = [];
|
|
426
445
|
const mockSearchParams = new URLSearchParams();
|
|
427
446
|
vi.mocked(useSearchParams).mockReturnValue([mockSearchParams, mockSetParams]);
|
|
428
|
-
renderHook(() => useContextSelector(
|
|
447
|
+
renderHook(() => useContextSelector(HitSearchContext, () => { }), { wrapper: Wrapper });
|
|
429
448
|
await waitFor(() => {
|
|
430
449
|
expect(mockSetParams).not.toHaveBeenCalled();
|
|
431
450
|
});
|
|
@@ -435,12 +454,12 @@ describe('RecordSearchContext', () => {
|
|
|
435
454
|
it('should not break when view ID does not exist', async () => {
|
|
436
455
|
mockParameterContext.views = ['non_existent_view'];
|
|
437
456
|
mockViewContext.getCurrentViews = vi.fn(() => Promise.resolve([null]));
|
|
438
|
-
const hook = renderHook(() => useContextSelector(
|
|
457
|
+
const hook = renderHook(() => useContextSelector(HitSearchContext, ctx => ctx.search), { wrapper: Wrapper });
|
|
439
458
|
act(() => {
|
|
440
459
|
hook.result.current('test query');
|
|
441
460
|
});
|
|
442
461
|
await waitFor(() => {
|
|
443
|
-
expect(hpost).toHaveBeenCalledWith('/api/
|
|
462
|
+
expect(hpost).toHaveBeenCalledWith('/api/v1/search/hit', expect.objectContaining({
|
|
444
463
|
query: expect.stringContaining('test query'),
|
|
445
464
|
filters: ['event.created:[now-1w TO now]']
|
|
446
465
|
}));
|
|
@@ -452,12 +471,12 @@ describe('RecordSearchContext', () => {
|
|
|
452
471
|
{ view_id: 'view_1', query: 'howler.status:open' },
|
|
453
472
|
{ view_id: 'view_2', query: 'howler.priority:high' }
|
|
454
473
|
]);
|
|
455
|
-
const hook = renderHook(() => useContextSelector(
|
|
474
|
+
const hook = renderHook(() => useContextSelector(HitSearchContext, ctx => ctx.search), { wrapper: Wrapper });
|
|
456
475
|
act(() => {
|
|
457
476
|
hook.result.current('test query');
|
|
458
477
|
});
|
|
459
478
|
await waitFor(() => {
|
|
460
|
-
expect(hpost).toHaveBeenCalledWith('/api/
|
|
479
|
+
expect(hpost).toHaveBeenCalledWith('/api/v1/search/hit', expect.objectContaining({
|
|
461
480
|
query: 'test query',
|
|
462
481
|
filters: ['event.created:[now-1w TO now]', 'howler.status:open', 'howler.priority:high']
|
|
463
482
|
}));
|
|
@@ -468,7 +487,7 @@ describe('RecordSearchContext', () => {
|
|
|
468
487
|
it('should not trigger search when views is empty and query is DEFAULT_QUERY', async () => {
|
|
469
488
|
mockParameterContext.query = DEFAULT_QUERY;
|
|
470
489
|
mockParameterContext.views = [];
|
|
471
|
-
renderHook(() => useContextSelector(
|
|
490
|
+
renderHook(() => useContextSelector(HitSearchContext, ctx => ctx.response), { wrapper: Wrapper });
|
|
472
491
|
await waitFor(() => {
|
|
473
492
|
expect(hpost).not.toHaveBeenCalled();
|
|
474
493
|
});
|
|
@@ -476,7 +495,7 @@ describe('RecordSearchContext', () => {
|
|
|
476
495
|
it('should trigger search when views.length > 0 even with DEFAULT_QUERY', async () => {
|
|
477
496
|
mockParameterContext.query = DEFAULT_QUERY;
|
|
478
497
|
mockParameterContext.views = ['view_1'];
|
|
479
|
-
renderHook(() => useContextSelector(
|
|
498
|
+
renderHook(() => useContextSelector(HitSearchContext, ctx => ctx.response), { wrapper: Wrapper });
|
|
480
499
|
await waitFor(() => {
|
|
481
500
|
expect(hpost).toHaveBeenCalled();
|
|
482
501
|
});
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import type { FC, PropsWithChildren } from 'react';
|
|
2
|
-
export type SearchIndex = 'hit' | 'observable' | 'case';
|
|
3
2
|
export interface ParameterContextType {
|
|
4
3
|
selected?: string;
|
|
5
4
|
query?: string;
|
|
@@ -7,7 +6,6 @@ export interface ParameterContextType {
|
|
|
7
6
|
trackTotalHits: boolean;
|
|
8
7
|
sort?: string;
|
|
9
8
|
span?: string;
|
|
10
|
-
indexes?: SearchIndex[];
|
|
11
9
|
filters?: string[];
|
|
12
10
|
startDate?: string;
|
|
13
11
|
endDate?: string;
|
|
@@ -21,16 +19,11 @@ export interface ParameterContextType {
|
|
|
21
19
|
addFilter: (filter: string) => void;
|
|
22
20
|
removeFilter: (filter: string) => void;
|
|
23
21
|
setFilter: (index: number, filter: string) => void;
|
|
24
|
-
|
|
25
|
-
addIndex: (index: SearchIndex) => void;
|
|
26
|
-
removeIndex: (index: SearchIndex) => void;
|
|
27
|
-
setIndex: (position: number, index: SearchIndex) => void;
|
|
28
|
-
setIndexes: (indexes: SearchIndex[]) => void;
|
|
29
|
-
resetIndexes: () => void;
|
|
22
|
+
clearFilters: () => void;
|
|
30
23
|
addView: (view: string) => void;
|
|
31
24
|
removeView: (view: string) => void;
|
|
32
25
|
setView: (index: number, view: string) => void;
|
|
33
|
-
|
|
26
|
+
clearViews: () => void;
|
|
34
27
|
}
|
|
35
28
|
export declare const ParameterContext: import("use-context-selector").Context<ParameterContextType>;
|
|
36
29
|
/**
|