@cccsaurora/howler-ui 2.17.0-dev.564 → 2.17.0-dev.617
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 +2 -0
- package/api/index.js +4 -2
- package/api/search/case.d.ts +4 -0
- package/api/search/case.js +8 -0
- package/api/search/index.d.ts +2 -1
- package/api/search/index.js +2 -1
- package/api/v2/case/index.d.ts +6 -0
- package/api/v2/case/index.js +18 -0
- package/api/v2/index.d.ts +4 -0
- package/api/v2/index.js +6 -0
- package/api/v2/search/facet.d.ts +3 -0
- package/api/v2/search/facet.js +12 -0
- package/api/v2/search/index.d.ts +5 -0
- package/api/v2/search/index.js +24 -0
- package/commons/components/leftnav/LeftNavDrawer.js +1 -1
- package/components/app/App.js +14 -0
- package/components/app/providers/FavouritesProvider.js +2 -2
- package/components/app/providers/HitSearchProvider.d.ts +0 -1
- package/components/app/providers/HitSearchProvider.js +6 -11
- package/components/app/providers/HitSearchProvider.test.js +11 -32
- package/components/app/providers/ParameterProvider.d.ts +9 -2
- package/components/app/providers/ParameterProvider.js +165 -240
- package/components/app/providers/ParameterProvider.test.js +307 -14
- package/components/{routes/overviews/OverviewEditor.js → elements/MarkdownEditor.js} +3 -3
- package/components/elements/ObjectDetails.d.ts +6 -0
- package/components/elements/{hit/HitDetails.js → ObjectDetails.js} +17 -17
- package/components/elements/PluginTypography.d.ts +2 -1
- package/components/elements/PluginTypography.js +3 -2
- package/components/elements/UserList.d.ts +5 -2
- package/components/elements/UserList.js +14 -5
- package/components/elements/addons/search/phrase/Phrase.js +1 -1
- package/components/elements/case/CaseCard.d.ts +8 -0
- package/components/elements/case/CaseCard.js +39 -0
- package/components/elements/case/CasePreview.d.ts +6 -0
- package/components/elements/case/CasePreview.js +17 -0
- package/components/elements/case/StatusIcon.d.ts +5 -0
- package/components/elements/case/StatusIcon.js +13 -0
- package/components/elements/display/ChipPopper.d.ts +1 -0
- package/components/elements/display/ChipPopper.js +2 -2
- package/components/elements/display/HowlerCard.js +1 -1
- package/components/elements/display/Modal.js +1 -0
- package/components/elements/hit/HitBanner.js +28 -48
- package/components/elements/hit/HitCard.js +1 -1
- package/components/elements/hit/{HitQuickSearch.d.ts → HitPreview.d.ts} +3 -3
- package/components/elements/hit/{HitQuickSearch.js → HitPreview.js} +10 -4
- package/components/elements/hit/HitRelated.d.ts +1 -1
- package/components/elements/hit/HitRelated.js +30 -3
- package/components/elements/hit/elements/AnalyticLink.d.ts +8 -0
- package/components/elements/hit/elements/AnalyticLink.js +22 -0
- package/components/elements/hit/outlines/DefaultOutline.js +1 -1
- package/components/elements/hit/related/RelatedRecords.js +63 -0
- package/components/elements/observable/ObservableCard.d.ts +5 -0
- package/components/elements/observable/ObservableCard.js +7 -0
- package/components/elements/observable/ObservablePreview.d.ts +6 -0
- package/components/elements/observable/ObservablePreview.js +12 -0
- package/components/elements/view/ViewTitle.js +1 -1
- package/components/hooks/useHitActions.d.ts +1 -1
- package/components/hooks/useHitActions.js +2 -2
- package/components/hooks/useHitSelection.js +3 -24
- package/components/hooks/useMyPreferences.js +10 -1
- package/components/hooks/useMySearch.js +2 -2
- package/components/hooks/useMySitemap.js +4 -1
- package/components/hooks/useMyTheme.js +9 -2
- package/components/hooks/useRelatedRecords.d.ts +13 -0
- package/components/hooks/useRelatedRecords.js +32 -0
- package/components/routes/action/view/ActionSearch.js +1 -1
- package/components/routes/advanced/QueryBuilder.js +1 -1
- package/components/routes/analytics/AnalyticDetails.js +2 -2
- package/components/routes/analytics/AnalyticSearch.js +1 -1
- package/components/routes/cases/CaseViewer.d.ts +2 -0
- package/components/routes/cases/CaseViewer.js +24 -0
- package/components/routes/cases/Cases.d.ts +2 -0
- package/components/routes/cases/Cases.js +101 -0
- package/components/routes/cases/constants.d.ts +5 -0
- package/components/routes/cases/constants.js +5 -0
- package/components/routes/cases/detail/AlertPanel.d.ts +6 -0
- package/components/routes/cases/detail/AlertPanel.js +32 -0
- package/components/routes/cases/detail/CaseDashboard.d.ts +7 -0
- package/components/routes/cases/detail/CaseDashboard.js +49 -0
- package/components/routes/cases/detail/CaseDetails.d.ts +6 -0
- package/components/routes/cases/detail/CaseDetails.js +61 -0
- package/components/routes/cases/detail/CaseOverview.d.ts +7 -0
- package/components/routes/cases/detail/CaseOverview.js +43 -0
- package/components/routes/cases/detail/CaseSidebar.d.ts +6 -0
- package/components/routes/cases/detail/CaseSidebar.js +36 -0
- package/components/routes/cases/detail/CaseTask.d.ts +11 -0
- package/components/routes/cases/detail/CaseTask.js +57 -0
- package/components/routes/cases/detail/ItemPage.d.ts +6 -0
- package/components/routes/cases/detail/ItemPage.js +93 -0
- package/components/routes/cases/detail/RelatedCasePanel.d.ts +6 -0
- package/components/routes/cases/detail/RelatedCasePanel.js +31 -0
- package/components/routes/cases/detail/TaskPanel.d.ts +7 -0
- package/components/routes/cases/detail/TaskPanel.js +52 -0
- package/components/routes/cases/detail/aggregates/CaseAggregate.d.ts +12 -0
- package/components/routes/cases/detail/aggregates/CaseAggregate.js +19 -0
- package/components/routes/cases/detail/aggregates/SourceAggregate.d.ts +6 -0
- package/components/routes/cases/detail/aggregates/SourceAggregate.js +27 -0
- package/components/routes/cases/detail/sidebar/CaseFolder.d.ts +13 -0
- package/components/routes/cases/detail/sidebar/CaseFolder.js +134 -0
- package/components/routes/cases/detail/sidebar/types.d.ts +3 -0
- package/components/routes/cases/detail/sidebar/utils.d.ts +3 -0
- package/components/routes/cases/detail/sidebar/utils.js +25 -0
- package/components/routes/cases/hooks/useCase.d.ts +13 -0
- package/components/routes/cases/hooks/useCase.js +38 -0
- package/components/routes/cases/modals/ResolveModal.d.ts +7 -0
- package/components/routes/cases/modals/ResolveModal.js +59 -0
- package/components/routes/help/ApiDocumentation.js +1 -1
- package/components/routes/help/HitDocumentation.js +1 -3
- package/components/routes/hits/search/HitContextMenu.js +3 -2
- package/components/routes/hits/search/InformationPane.d.ts +1 -0
- package/components/routes/hits/search/InformationPane.js +6 -28
- package/components/routes/hits/search/QuerySettings.js +2 -1
- package/components/routes/hits/search/QuerySettings.test.js +14 -9
- package/components/routes/hits/search/SearchPane.js +7 -32
- package/components/routes/hits/search/ViewLink.js +1 -1
- package/components/routes/hits/search/grid/EnhancedCell.js +1 -1
- package/components/routes/hits/search/shared/IndexPicker.d.ts +2 -0
- package/components/routes/hits/search/shared/IndexPicker.js +20 -0
- package/components/routes/hits/view/HitViewer.js +3 -4
- package/components/routes/home/ViewCard.js +1 -1
- package/components/routes/observables/ObservableViewer.d.ts +7 -0
- package/components/routes/observables/ObservableViewer.js +27 -0
- package/components/routes/overviews/OverviewViewer.js +2 -2
- package/locales/en/translation.json +437 -398
- package/locales/fr/translation.json +442 -408
- package/models/WithMetadata.d.ts +2 -1
- package/models/entities/generated/AttachmentsFile.d.ts +12 -0
- package/models/entities/generated/Case.d.ts +28 -0
- package/models/entities/generated/DestinationOriginal.d.ts +19 -0
- package/models/entities/generated/EmailAttachment.d.ts +8 -0
- package/models/entities/generated/EmailParent.d.ts +19 -0
- package/models/entities/generated/Enrichments.d.ts +7 -0
- package/models/entities/generated/EnrichmentsIndicator.d.ts +21 -0
- package/models/entities/generated/Howler.d.ts +0 -4
- package/models/entities/generated/HttpResponse.d.ts +11 -0
- package/models/entities/generated/Item.d.ts +9 -0
- package/models/entities/generated/Observable.d.ts +84 -0
- package/models/entities/generated/ObservableCloud.d.ts +20 -0
- package/models/entities/generated/ObservableDestination.d.ts +23 -0
- package/models/entities/generated/ObservableEmail.d.ts +30 -0
- package/models/entities/generated/ObservableFile.d.ts +36 -0
- package/models/entities/generated/ObservableHowler.d.ts +44 -0
- package/models/entities/generated/ObservableHttp.d.ts +11 -0
- package/models/entities/generated/ObservableObserver.d.ts +21 -0
- package/models/entities/generated/ObservableOrganization.d.ts +7 -0
- package/models/entities/generated/ObservableProcess.d.ts +34 -0
- package/models/entities/generated/ObservableSource.d.ts +23 -0
- package/models/entities/generated/ObservableThreat.d.ts +21 -0
- package/models/entities/generated/ObservableTls.d.ts +12 -0
- package/models/entities/generated/ObserverIngress.d.ts +9 -0
- package/models/entities/generated/Rule.d.ts +2 -10
- package/models/entities/generated/Task.d.ts +10 -0
- package/models/entities/generated/Threat.d.ts +2 -2
- package/models/entities/generated/{Enrichment.d.ts → ThreatEnrichment.d.ts} +1 -1
- package/package.json +16 -1
- package/plugins/clue/components/ClueTypography.js +2 -2
- package/plugins/clue/utils.d.ts +2 -1
- package/utils/constants.d.ts +3 -3
- package/utils/typeUtils.d.ts +7 -0
- package/utils/typeUtils.js +18 -0
- package/components/elements/display/icons/BundleButton.d.ts +0 -6
- package/components/elements/display/icons/BundleButton.js +0 -32
- package/components/routes/help/BundleDocumentation.d.ts +0 -3
- package/components/routes/help/BundleDocumentation.js +0 -12
- package/components/routes/help/markdown/en/bundles.md.js +0 -1
- package/components/routes/help/markdown/fr/bundles.md.js +0 -1
- package/components/routes/hits/search/BundleParentMenu.d.ts +0 -6
- package/components/routes/hits/search/BundleParentMenu.js +0 -32
- /package/components/{routes/overviews/OverviewEditor.d.ts → elements/MarkdownEditor.d.ts} +0 -0
- /package/components/elements/hit/{HitDetails.d.ts → related/RelatedRecords.d.ts} +0 -0
package/api/index.d.ts
CHANGED
|
@@ -10,6 +10,7 @@ import * as overview from '@cccsaurora/howler-ui/api/overview';
|
|
|
10
10
|
import * as search from '@cccsaurora/howler-ui/api/search';
|
|
11
11
|
import * as template from '@cccsaurora/howler-ui/api/template';
|
|
12
12
|
import * as user from '@cccsaurora/howler-ui/api/user';
|
|
13
|
+
import * as v2 from '@cccsaurora/howler-ui/api/v2';
|
|
13
14
|
import * as view from '@cccsaurora/howler-ui/api/view';
|
|
14
15
|
/**
|
|
15
16
|
* Defining the default export exposing all children routes of '/api/v1/'.
|
|
@@ -28,6 +29,7 @@ declare const api: {
|
|
|
28
29
|
user: typeof user;
|
|
29
30
|
view: typeof view;
|
|
30
31
|
notebook: typeof notebook;
|
|
32
|
+
v2: typeof v2;
|
|
31
33
|
};
|
|
32
34
|
/**
|
|
33
35
|
* The specification interface of an Howler HTTP response.
|
package/api/index.js
CHANGED
|
@@ -10,6 +10,7 @@ import * as overview from '@cccsaurora/howler-ui/api/overview';
|
|
|
10
10
|
import * as search from '@cccsaurora/howler-ui/api/search';
|
|
11
11
|
import * as template from '@cccsaurora/howler-ui/api/template';
|
|
12
12
|
import * as user from '@cccsaurora/howler-ui/api/user';
|
|
13
|
+
import * as v2 from '@cccsaurora/howler-ui/api/v2';
|
|
13
14
|
import * as view from '@cccsaurora/howler-ui/api/view';
|
|
14
15
|
import AxiosClient from '@cccsaurora/howler-ui/rest/AxiosClient';
|
|
15
16
|
import urlJoin from 'url-join';
|
|
@@ -38,7 +39,8 @@ const api = {
|
|
|
38
39
|
template,
|
|
39
40
|
user,
|
|
40
41
|
view,
|
|
41
|
-
notebook
|
|
42
|
+
notebook,
|
|
43
|
+
v2
|
|
42
44
|
};
|
|
43
45
|
/**
|
|
44
46
|
* The base section of the Howler API uri.
|
|
@@ -57,7 +59,7 @@ export const uri = () => {
|
|
|
57
59
|
* @returns `string` - properly formatted howler uri.
|
|
58
60
|
*/
|
|
59
61
|
const format = (_uri) => {
|
|
60
|
-
return _uri.startsWith(
|
|
62
|
+
return _uri.startsWith('/api') ? _uri : `${uri()}/${_uri.replace(/\/$/, '')}`;
|
|
61
63
|
};
|
|
62
64
|
/**
|
|
63
65
|
* Append series of search parameters to the specified uri.
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { HowlerSearchRequest, HowlerSearchResponse } from '@cccsaurora/howler-ui/api/search';
|
|
2
|
+
import type { Case } from '@cccsaurora/howler-ui/models/entities/generated/Case';
|
|
3
|
+
export declare const uri: () => string;
|
|
4
|
+
export declare const post: (request?: HowlerSearchRequest) => Promise<HowlerSearchResponse<Case>>;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { hpost, joinUri } from '@cccsaurora/howler-ui/api';
|
|
2
|
+
import { uri as parentUri } from '@cccsaurora/howler-ui/api/search';
|
|
3
|
+
export const uri = () => {
|
|
4
|
+
return joinUri(parentUri(), 'case');
|
|
5
|
+
};
|
|
6
|
+
export const post = (request) => {
|
|
7
|
+
return hpost(uri(), { ...(request || {}), query: request?.query || 'case_id:*' });
|
|
8
|
+
};
|
package/api/search/index.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import * as action from '@cccsaurora/howler-ui/api/search/action';
|
|
2
2
|
import * as analytic from '@cccsaurora/howler-ui/api/search/analytic';
|
|
3
|
+
import * as case_ from '@cccsaurora/howler-ui/api/search/case';
|
|
3
4
|
import * as count from '@cccsaurora/howler-ui/api/search/count';
|
|
4
5
|
import * as dossier from '@cccsaurora/howler-ui/api/search/dossier';
|
|
5
6
|
import * as facet from '@cccsaurora/howler-ui/api/search/facet';
|
|
@@ -60,4 +61,4 @@ export type HowlerExplainSearchResponse = {
|
|
|
60
61
|
explanation: string;
|
|
61
62
|
}[];
|
|
62
63
|
};
|
|
63
|
-
export { action, analytic, count, dossier, facet, fields, grouped, histogram, hit, overview, template, user, view };
|
|
64
|
+
export { action, analytic, case_ as case, count, dossier, facet, fields, grouped, histogram, hit, overview, template, user, view };
|
package/api/search/index.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { joinUri, uri as parentUri } from '@cccsaurora/howler-ui/api';
|
|
2
2
|
import * as action from '@cccsaurora/howler-ui/api/search/action';
|
|
3
3
|
import * as analytic from '@cccsaurora/howler-ui/api/search/analytic';
|
|
4
|
+
import * as case_ from '@cccsaurora/howler-ui/api/search/case';
|
|
4
5
|
import * as count from '@cccsaurora/howler-ui/api/search/count';
|
|
5
6
|
import * as dossier from '@cccsaurora/howler-ui/api/search/dossier';
|
|
6
7
|
import * as facet from '@cccsaurora/howler-ui/api/search/facet';
|
|
@@ -15,4 +16,4 @@ import * as view from '@cccsaurora/howler-ui/api/search/view';
|
|
|
15
16
|
export const uri = () => {
|
|
16
17
|
return joinUri(parentUri(), 'search');
|
|
17
18
|
};
|
|
18
|
-
export { action, analytic, count, dossier, facet, fields, grouped, histogram, hit, overview, template, user, view };
|
|
19
|
+
export { action, analytic, case_ as case, count, dossier, facet, fields, grouped, histogram, hit, overview, template, user, view };
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { Case } from '@cccsaurora/howler-ui/models/entities/generated/Case';
|
|
2
|
+
export declare const uri: (id?: string) => string;
|
|
3
|
+
export declare const get: (id: string) => Promise<Case>;
|
|
4
|
+
export declare const post: (newData: Partial<Case>) => Promise<Case>;
|
|
5
|
+
export declare const put: (id: string, _case: Partial<Case>) => Promise<Case>;
|
|
6
|
+
export declare const del: (id: string) => Promise<void>;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
// eslint-disable-next-line import/no-cycle
|
|
2
|
+
import { hdelete, hget, hpost, hput, joinAllUri, joinUri } from '@cccsaurora/howler-ui/api';
|
|
3
|
+
import { uri as parentUri } from '@cccsaurora/howler-ui/api/v2';
|
|
4
|
+
export const uri = (id) => {
|
|
5
|
+
return id ? joinAllUri(parentUri(), 'case', id) : joinUri(parentUri(), 'case');
|
|
6
|
+
};
|
|
7
|
+
export const get = (id) => {
|
|
8
|
+
return hget(uri(id));
|
|
9
|
+
};
|
|
10
|
+
export const post = (newData) => {
|
|
11
|
+
return hpost(uri(), newData);
|
|
12
|
+
};
|
|
13
|
+
export const put = (id, _case) => {
|
|
14
|
+
return hput(uri(id), _case);
|
|
15
|
+
};
|
|
16
|
+
export const del = (id) => {
|
|
17
|
+
return hdelete(uri(id));
|
|
18
|
+
};
|
package/api/v2/index.js
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import type { HowlerFacetSearchRequest, HowlerFacetSearchResponse } from '@cccsaurora/howler-ui/api/search/facet';
|
|
2
|
+
export declare const uri: (indexes: string[]) => string;
|
|
3
|
+
export declare const post: (indexes: string | string[], request?: HowlerFacetSearchRequest) => Promise<HowlerFacetSearchResponse>;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
// eslint-disable-next-line import/no-cycle
|
|
2
|
+
import { hpost, joinAllUri } from '@cccsaurora/howler-ui/api';
|
|
3
|
+
import { uri as parentUri } from '@cccsaurora/howler-ui/api/v2';
|
|
4
|
+
export const uri = (indexes) => {
|
|
5
|
+
return joinAllUri(parentUri(), 'search', 'facet', indexes.join(','));
|
|
6
|
+
};
|
|
7
|
+
export const post = (indexes, request) => {
|
|
8
|
+
if (typeof indexes === 'string') {
|
|
9
|
+
indexes = indexes.split(',');
|
|
10
|
+
}
|
|
11
|
+
return hpost(uri(indexes), { ...(request || {}), query: request?.query || 'howler.id:*' });
|
|
12
|
+
};
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { HowlerSearchRequest, HowlerSearchResponse } from '@cccsaurora/howler-ui/api/search';
|
|
2
|
+
import * as facet from './facet';
|
|
3
|
+
export declare const uri: (indexes: string[]) => string;
|
|
4
|
+
export declare const post: <T = any>(indexes: string | string[], request?: HowlerSearchRequest) => Promise<HowlerSearchResponse<T>>;
|
|
5
|
+
export { facet };
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
// eslint-disable-next-line import/no-cycle
|
|
2
|
+
import { hpost, joinAllUri } from '@cccsaurora/howler-ui/api';
|
|
3
|
+
import { uri as parentUri } from '@cccsaurora/howler-ui/api/v2';
|
|
4
|
+
import { identity, isNil } from 'lodash-es';
|
|
5
|
+
import * as facet from './facet';
|
|
6
|
+
export const uri = (indexes) => {
|
|
7
|
+
return joinAllUri(parentUri(), 'search', indexes.join(','));
|
|
8
|
+
};
|
|
9
|
+
export const post = (indexes, request) => {
|
|
10
|
+
if (isNil(indexes)) {
|
|
11
|
+
throw new Error('Indexes cannot be null or undefined.');
|
|
12
|
+
}
|
|
13
|
+
if (typeof indexes === 'string') {
|
|
14
|
+
indexes = indexes.split(',').filter(identity);
|
|
15
|
+
}
|
|
16
|
+
if (indexes.some(index => !['hit', 'observable', 'case'].includes(index))) {
|
|
17
|
+
throw new Error('Only hit, case and observable indexes should be used currently.');
|
|
18
|
+
}
|
|
19
|
+
if (indexes.length < 1) {
|
|
20
|
+
throw new Error('indexes must have length of at least 1.');
|
|
21
|
+
}
|
|
22
|
+
return hpost(uri(indexes), { ...(request || {}), query: request?.query || 'howler.id:*' });
|
|
23
|
+
};
|
|
24
|
+
export { facet };
|
|
@@ -75,7 +75,7 @@ const LeftNavDrawer = () => {
|
|
|
75
75
|
}
|
|
76
76
|
}, children: _jsx(AppName, {}) }), !isTopLayout && _jsx(Divider, {})] }));
|
|
77
77
|
const hide = (_jsx(List, { disablePadding: true, children: _jsxs(ListItemButton, { onClick: leftnav.toggle, children: [_jsx(ListItemIcon, { children: leftnav.open ? _jsx(ChevronLeftIcon, {}) : _jsx(ChevronRightIcon, {}) }), _jsx(ListItemText, { primary: t('drawer.collapse') })] }, "chevron") }));
|
|
78
|
-
return (_jsx(ClickAwayListener, { mouseEvent: "onMouseDown", touchEvent: "onTouchStart", onClickAway: onCloseDrawerIfOpen, children: _jsxs(StyledDrawer, {
|
|
78
|
+
return (_jsx(ClickAwayListener, { mouseEvent: "onMouseDown", touchEvent: "onTouchStart", onClickAway: onCloseDrawerIfOpen, children: _jsxs(StyledDrawer, { variant: "permanent", style: { height: '100%' }, width: preferences.leftnav.width, open: leftnav.open, children: [leftnav.open ? (header) : (_jsx(Tooltip, { title: preferences.appName, "aria-label": preferences.appName, placement: "right", children: header })), _jsx(List, { disablePadding: true, children: leftnav.elements.map((e, i) => {
|
|
79
79
|
if (e.type === 'item') {
|
|
80
80
|
const item = e.element;
|
|
81
81
|
return _jsx(LeftNavItem, { item: item, onClick: isSmDown && onCloseDrawerIfOpen }, item.id);
|
package/components/app/App.js
CHANGED
|
@@ -25,6 +25,8 @@ import UserSearchProvider from '@cccsaurora/howler-ui/components/routes/admin/us
|
|
|
25
25
|
import QueryBuilder from '@cccsaurora/howler-ui/components/routes/advanced/QueryBuilder';
|
|
26
26
|
import AnalyticDetails from '@cccsaurora/howler-ui/components/routes/analytics/AnalyticDetails';
|
|
27
27
|
import AnalyticSearch from '@cccsaurora/howler-ui/components/routes/analytics/AnalyticSearch';
|
|
28
|
+
import CaseViewer from '@cccsaurora/howler-ui/components/routes/cases/CaseViewer';
|
|
29
|
+
import Cases from '@cccsaurora/howler-ui/components/routes/cases/Cases';
|
|
28
30
|
import DossierEditor from '@cccsaurora/howler-ui/components/routes/dossiers/DossierEditor';
|
|
29
31
|
import Dossiers from '@cccsaurora/howler-ui/components/routes/dossiers/Dossiers';
|
|
30
32
|
import ActionDocumentation from '@cccsaurora/howler-ui/components/routes/help/ActionDocumentation';
|
|
@@ -185,6 +187,18 @@ const router = createBrowserRouter([
|
|
|
185
187
|
path: 'bundles/:id',
|
|
186
188
|
element: _jsx(HitBrowser, {})
|
|
187
189
|
},
|
|
190
|
+
{
|
|
191
|
+
path: 'cases',
|
|
192
|
+
element: _jsx(Cases, {})
|
|
193
|
+
},
|
|
194
|
+
{
|
|
195
|
+
path: 'cases/:id',
|
|
196
|
+
element: _jsx(CaseViewer, {})
|
|
197
|
+
},
|
|
198
|
+
{
|
|
199
|
+
path: 'cases/:id/*',
|
|
200
|
+
element: _jsx(CaseViewer, {})
|
|
201
|
+
},
|
|
188
202
|
{
|
|
189
203
|
path: 'templates',
|
|
190
204
|
element: _jsx(Templates, {})
|
|
@@ -120,11 +120,11 @@ const FavouriteProvider = ({ children }) => {
|
|
|
120
120
|
(async () => {
|
|
121
121
|
const analyticElement = processAnalyticElement();
|
|
122
122
|
if (analyticElement) {
|
|
123
|
-
newElements.splice(
|
|
123
|
+
newElements.splice(2, 0, analyticElement);
|
|
124
124
|
}
|
|
125
125
|
const viewElement = await processViewElement();
|
|
126
126
|
if (viewElement) {
|
|
127
|
-
newElements.splice(
|
|
127
|
+
newElements.splice(2, 0, viewElement);
|
|
128
128
|
}
|
|
129
129
|
leftNav.setElements(newElements);
|
|
130
130
|
})();
|
|
@@ -11,7 +11,6 @@ export interface HitSearchContextType {
|
|
|
11
11
|
searching: boolean;
|
|
12
12
|
error: string | null;
|
|
13
13
|
response: HowlerSearchResponse<WithMetadata<Hit>> | null;
|
|
14
|
-
bundleId: string | null;
|
|
15
14
|
fzfSearch: boolean;
|
|
16
15
|
setDisplayType: (type: 'list' | 'grid') => void;
|
|
17
16
|
setFzfSearch: Dispatch<SetStateAction<boolean>>;
|
|
@@ -33,6 +33,7 @@ const HitSearchProvider = ({ 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);
|
|
36
37
|
const allFilters = useContextSelector(ParameterContext, ctx => ctx.filters);
|
|
37
38
|
const startDate = useContextSelector(ParameterContext, ctx => ctx.startDate);
|
|
38
39
|
const endDate = useContextSelector(ParameterContext, ctx => ctx.endDate);
|
|
@@ -47,7 +48,6 @@ const HitSearchProvider = ({ children }) => {
|
|
|
47
48
|
'howler.id: *': new Date().toISOString()
|
|
48
49
|
});
|
|
49
50
|
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,11 +70,6 @@ const HitSearchProvider = ({ 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
|
-
}
|
|
78
73
|
// Fetch all view queries
|
|
79
74
|
if (views.length > 0) {
|
|
80
75
|
const viewObjects = await getCurrentViews({ views });
|
|
@@ -85,7 +80,7 @@ const HitSearchProvider = ({ children }) => {
|
|
|
85
80
|
.forEach(viewQuery => _filters.push(viewQuery));
|
|
86
81
|
}
|
|
87
82
|
return _filters;
|
|
88
|
-
}, [endDate, filters, getCurrentViews,
|
|
83
|
+
}, [endDate, filters, getCurrentViews, span, startDate, views]);
|
|
89
84
|
const search = useCallback(async (_query, appendResults) => {
|
|
90
85
|
THROTTLER.debounce(async () => {
|
|
91
86
|
if (_query === 'woof!') {
|
|
@@ -105,7 +100,7 @@ const HitSearchProvider = ({ children }) => {
|
|
|
105
100
|
setSearching(true);
|
|
106
101
|
setError(null);
|
|
107
102
|
try {
|
|
108
|
-
const _response = await dispatchApi(api.search.
|
|
103
|
+
const _response = await dispatchApi(api.v2.search.post(indexes, {
|
|
109
104
|
offset: appendResults && response ? response.rows : offset,
|
|
110
105
|
rows: pageCount,
|
|
111
106
|
query: _query || DEFAULT_QUERY,
|
|
@@ -147,6 +142,7 @@ const HitSearchProvider = ({ children }) => {
|
|
|
147
142
|
startDate,
|
|
148
143
|
endDate,
|
|
149
144
|
filters,
|
|
145
|
+
indexes,
|
|
150
146
|
setQuery,
|
|
151
147
|
location.pathname,
|
|
152
148
|
routeParams.id,
|
|
@@ -165,14 +161,14 @@ const HitSearchProvider = ({ children }) => {
|
|
|
165
161
|
if (span?.endsWith('custom') && (!startDate || !endDate)) {
|
|
166
162
|
return;
|
|
167
163
|
}
|
|
168
|
-
if (views.length > 0 ||
|
|
164
|
+
if (views.length > 0 || (query && query !== DEFAULT_QUERY) || offset > 0 || filters.length > 0) {
|
|
169
165
|
search(query);
|
|
170
166
|
}
|
|
171
167
|
else {
|
|
172
168
|
setResponse(null);
|
|
173
169
|
}
|
|
174
170
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
175
|
-
}, [offset, pageCount, sort, span,
|
|
171
|
+
}, [offset, pageCount, sort, span, indexes, location.pathname, startDate, endDate, filters, query, views]);
|
|
176
172
|
return (_jsx(HitSearchContext.Provider, { value: {
|
|
177
173
|
displayType,
|
|
178
174
|
setDisplayType,
|
|
@@ -181,7 +177,6 @@ const HitSearchProvider = ({ children }) => {
|
|
|
181
177
|
getFilters,
|
|
182
178
|
error,
|
|
183
179
|
response,
|
|
184
|
-
bundleId,
|
|
185
180
|
setQueryHistory,
|
|
186
181
|
queryHistory,
|
|
187
182
|
fzfSearch,
|
|
@@ -30,6 +30,7 @@ let mockParameterContext = {
|
|
|
30
30
|
mockParameterContext.offset = parseInt(offset);
|
|
31
31
|
},
|
|
32
32
|
views: [],
|
|
33
|
+
indexes: ['hit'],
|
|
33
34
|
addView: vi.fn()
|
|
34
35
|
};
|
|
35
36
|
const originalMockParameterContext = cloneDeep(mockParameterContext);
|
|
@@ -64,22 +65,14 @@ describe('HitSearchContext', () => {
|
|
|
64
65
|
searching: ctx.searching,
|
|
65
66
|
error: ctx.error,
|
|
66
67
|
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();
|
|
75
74
|
expect(hook.result.current.fzfSearch).toBe(false);
|
|
76
75
|
});
|
|
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
|
-
});
|
|
83
76
|
it('should initialize queryHistory from localStorage', () => {
|
|
84
77
|
const mockHistory = { 'test:query': new Date().toISOString() };
|
|
85
78
|
mockLocalStorage.setItem(`${MY_LOCAL_STORAGE_PREFIX}.${StorageKey.QUERY_HISTORY}`, JSON.stringify(mockHistory));
|
|
@@ -137,7 +130,7 @@ describe('HitSearchContext', () => {
|
|
|
137
130
|
hook.result.current.search('test query');
|
|
138
131
|
});
|
|
139
132
|
await waitFor(() => {
|
|
140
|
-
expect(hpost).toHaveBeenCalledWith('/api/
|
|
133
|
+
expect(hpost).toHaveBeenCalledWith('/api/v2/search/hit', expect.objectContaining({
|
|
141
134
|
query: expect.stringContaining('test query')
|
|
142
135
|
}));
|
|
143
136
|
});
|
|
@@ -221,27 +214,13 @@ describe('HitSearchContext', () => {
|
|
|
221
214
|
expect(hook.result.current.response?.items.length).toBe(2);
|
|
222
215
|
});
|
|
223
216
|
});
|
|
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
|
-
});
|
|
238
217
|
it('should apply date range filter from span', async () => {
|
|
239
218
|
const hook = renderHook(() => useContextSelector(HitSearchContext, ctx => ctx.search), { wrapper: Wrapper });
|
|
240
219
|
act(() => {
|
|
241
220
|
hook.result.current('test query');
|
|
242
221
|
});
|
|
243
222
|
await waitFor(() => {
|
|
244
|
-
expect(hpost).toHaveBeenCalledWith('/api/
|
|
223
|
+
expect(hpost).toHaveBeenCalledWith('/api/v2/search/hit', expect.objectContaining({
|
|
245
224
|
filters: expect.arrayContaining([expect.stringContaining('event.created:')])
|
|
246
225
|
}));
|
|
247
226
|
});
|
|
@@ -255,7 +234,7 @@ describe('HitSearchContext', () => {
|
|
|
255
234
|
hook.result.current('test query');
|
|
256
235
|
});
|
|
257
236
|
await waitFor(() => {
|
|
258
|
-
expect(hpost).toHaveBeenCalledWith('/api/
|
|
237
|
+
expect(hpost).toHaveBeenCalledWith('/api/v2/search/hit', expect.objectContaining({
|
|
259
238
|
filters: expect.arrayContaining([expect.stringContaining('event.created:')])
|
|
260
239
|
}));
|
|
261
240
|
});
|
|
@@ -267,7 +246,7 @@ describe('HitSearchContext', () => {
|
|
|
267
246
|
hook.result.current('test query');
|
|
268
247
|
});
|
|
269
248
|
await waitFor(() => {
|
|
270
|
-
expect(hpost).toHaveBeenCalledWith('/api/
|
|
249
|
+
expect(hpost).toHaveBeenCalledWith('/api/v2/search/hit', expect.objectContaining({
|
|
271
250
|
filters: expect.not.arrayContaining([expect.stringContaining('howler.escalation:*')])
|
|
272
251
|
}));
|
|
273
252
|
});
|
|
@@ -320,7 +299,7 @@ describe('HitSearchContext', () => {
|
|
|
320
299
|
expect(hpost).toHaveBeenCalled();
|
|
321
300
|
}, { timeout: 2000 });
|
|
322
301
|
});
|
|
323
|
-
it('should not trigger search when query is DEFAULT_QUERY
|
|
302
|
+
it('should not trigger search when query is DEFAULT_QUERY', async () => {
|
|
324
303
|
mockParameterContext.query = DEFAULT_QUERY;
|
|
325
304
|
renderHook(() => useContextSelector(HitSearchContext, ctx => ctx.response), { wrapper: Wrapper });
|
|
326
305
|
await waitFor(() => {
|
|
@@ -358,7 +337,7 @@ describe('HitSearchContext', () => {
|
|
|
358
337
|
expect(hpost).toHaveBeenCalledTimes(1);
|
|
359
338
|
}, { timeout: 2000 });
|
|
360
339
|
});
|
|
361
|
-
it('should clear response when query becomes DEFAULT_QUERY without viewId
|
|
340
|
+
it('should clear response when query becomes DEFAULT_QUERY without viewId', async () => {
|
|
362
341
|
const hook = renderHook(() => useContextSelector(HitSearchContext, ctx => ctx.response), { wrapper: Wrapper });
|
|
363
342
|
await waitFor(() => {
|
|
364
343
|
expect(hook.result.current).toBeDefined();
|
|
@@ -384,7 +363,7 @@ describe('HitSearchContext', () => {
|
|
|
384
363
|
hook.result.current('test query');
|
|
385
364
|
});
|
|
386
365
|
await waitFor(() => {
|
|
387
|
-
expect(hpost).toHaveBeenCalledWith('/api/
|
|
366
|
+
expect(hpost).toHaveBeenCalledWith('/api/v2/search/hit', expect.objectContaining({
|
|
388
367
|
query: 'test query',
|
|
389
368
|
filters: expect.arrayContaining(['howler.status:open', 'howler.priority:high'])
|
|
390
369
|
}));
|
|
@@ -402,7 +381,7 @@ describe('HitSearchContext', () => {
|
|
|
402
381
|
hook.result.current('test query');
|
|
403
382
|
});
|
|
404
383
|
await waitFor(() => {
|
|
405
|
-
expect(hpost).toHaveBeenCalledWith('/api/
|
|
384
|
+
expect(hpost).toHaveBeenCalledWith('/api/v2/search/hit', expect.objectContaining({
|
|
406
385
|
query: 'test query',
|
|
407
386
|
filters: [
|
|
408
387
|
'event.created:[now-1w TO now]',
|
|
@@ -459,7 +438,7 @@ describe('HitSearchContext', () => {
|
|
|
459
438
|
hook.result.current('test query');
|
|
460
439
|
});
|
|
461
440
|
await waitFor(() => {
|
|
462
|
-
expect(hpost).toHaveBeenCalledWith('/api/
|
|
441
|
+
expect(hpost).toHaveBeenCalledWith('/api/v2/search/hit', expect.objectContaining({
|
|
463
442
|
query: expect.stringContaining('test query'),
|
|
464
443
|
filters: ['event.created:[now-1w TO now]']
|
|
465
444
|
}));
|
|
@@ -476,7 +455,7 @@ describe('HitSearchContext', () => {
|
|
|
476
455
|
hook.result.current('test query');
|
|
477
456
|
});
|
|
478
457
|
await waitFor(() => {
|
|
479
|
-
expect(hpost).toHaveBeenCalledWith('/api/
|
|
458
|
+
expect(hpost).toHaveBeenCalledWith('/api/v2/search/hit', expect.objectContaining({
|
|
480
459
|
query: 'test query',
|
|
481
460
|
filters: ['event.created:[now-1w TO now]', 'howler.status:open', 'howler.priority:high']
|
|
482
461
|
}));
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { FC, PropsWithChildren } from 'react';
|
|
2
|
+
export type SearchIndex = 'hit' | 'observable' | 'case';
|
|
2
3
|
export interface ParameterContextType {
|
|
3
4
|
selected?: string;
|
|
4
5
|
query?: string;
|
|
@@ -6,6 +7,7 @@ export interface ParameterContextType {
|
|
|
6
7
|
trackTotalHits: boolean;
|
|
7
8
|
sort?: string;
|
|
8
9
|
span?: string;
|
|
10
|
+
indexes?: SearchIndex[];
|
|
9
11
|
filters?: string[];
|
|
10
12
|
startDate?: string;
|
|
11
13
|
endDate?: string;
|
|
@@ -19,11 +21,16 @@ export interface ParameterContextType {
|
|
|
19
21
|
addFilter: (filter: string) => void;
|
|
20
22
|
removeFilter: (filter: string) => void;
|
|
21
23
|
setFilter: (index: number, filter: string) => void;
|
|
22
|
-
|
|
24
|
+
resetFilters: () => void;
|
|
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;
|
|
23
30
|
addView: (view: string) => void;
|
|
24
31
|
removeView: (view: string) => void;
|
|
25
32
|
setView: (index: number, view: string) => void;
|
|
26
|
-
|
|
33
|
+
resetViews: () => void;
|
|
27
34
|
}
|
|
28
35
|
export declare const ParameterContext: import("use-context-selector").Context<ParameterContextType>;
|
|
29
36
|
/**
|