@cccsaurora/howler-ui 2.18.0-dev.732 → 2.18.0-dev.736
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/facet/hit.d.ts +1 -3
- package/api/search/facet/index.d.ts +3 -1
- package/api/search/index.d.ts +2 -1
- package/api/search/index.js +2 -1
- package/api/v2/case/index.d.ts +8 -0
- package/api/v2/case/index.js +20 -0
- package/api/v2/case/items.d.ts +6 -0
- package/api/v2/case/items.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 +39 -7
- package/components/app/hooks/useMatchers.d.ts +1 -1
- package/components/app/hooks/useMatchers.js +23 -11
- 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/ModalProvider.d.ts +1 -0
- package/components/app/providers/ParameterProvider.d.ts +9 -2
- package/components/app/providers/ParameterProvider.js +165 -240
- package/components/app/providers/ParameterProvider.test.js +346 -94
- package/components/app/providers/RecordProvider.d.ts +23 -0
- package/components/app/providers/{HitProvider.js → RecordProvider.js} +41 -41
- package/components/app/providers/{HitSearchProvider.d.ts → RecordSearchProvider.d.ts} +6 -6
- package/components/app/providers/{HitSearchProvider.js → RecordSearchProvider.js} +12 -17
- package/components/app/providers/{HitSearchProvider.test.js → RecordSearchProvider.test.js} +51 -70
- package/components/app/providers/UserListProvider.js +28 -8
- package/components/elements/ContextMenu.d.ts +56 -0
- package/components/elements/ContextMenu.js +109 -0
- package/components/elements/ContextMenu.test.js +215 -0
- 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 +18 -8
- package/components/elements/addons/search/phrase/Phrase.js +1 -1
- package/components/elements/case/CaseCard.d.ts +12 -0
- package/components/elements/case/CaseCard.js +42 -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 -1
- package/components/elements/display/HowlerCard.js +1 -1
- package/components/elements/display/Modal.js +2 -0
- package/components/elements/hit/HitActions.js +4 -4
- package/components/elements/hit/HitBanner.d.ts +1 -0
- package/components/elements/hit/HitBanner.js +29 -49
- package/components/elements/hit/HitCard.d.ts +2 -0
- package/components/elements/hit/HitCard.js +7 -7
- package/components/elements/hit/HitLabels.js +2 -2
- package/components/elements/hit/HitOutline.d.ts +1 -0
- package/components/elements/hit/HitOutline.js +3 -3
- 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/HitSummary.d.ts +2 -1
- package/components/elements/hit/HitSummary.js +6 -5
- package/components/elements/hit/aggregate/HitGraph.js +8 -8
- package/components/elements/hit/elements/AnalyticLink.d.ts +9 -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 +6 -0
- package/components/elements/observable/ObservableCard.js +22 -0
- package/components/elements/observable/ObservablePreview.d.ts +6 -0
- package/components/elements/observable/ObservablePreview.js +12 -0
- package/components/elements/{hit/HitComments.d.ts → record/RecordComments.d.ts} +5 -4
- package/components/elements/{hit/HitComments.js → record/RecordComments.js} +29 -28
- package/components/{routes/hits/search/HitContextMenu.d.ts → elements/record/RecordContextMenu.d.ts} +3 -3
- package/components/elements/record/RecordContextMenu.js +247 -0
- package/components/elements/record/RecordContextMenu.test.d.ts +1 -0
- package/components/{routes/hits/search/HitContextMenu.test.js → elements/record/RecordContextMenu.test.js} +94 -39
- package/components/elements/record/RecordRelated.d.ts +7 -0
- package/components/elements/record/RecordRelated.js +34 -0
- package/components/elements/{hit/HitWorklog.d.ts → record/RecordWorklog.d.ts} +4 -3
- package/components/elements/{hit/HitWorklog.js → record/RecordWorklog.js} +15 -13
- package/components/elements/view/ViewTitle.d.ts +1 -0
- package/components/elements/view/ViewTitle.js +9 -2
- package/components/hooks/useHitActions.d.ts +1 -1
- package/components/hooks/useHitActions.js +4 -4
- 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/useParamState.test.js +3 -4
- package/components/hooks/{useHitSelection.d.ts → useRecordSelection.d.ts} +2 -2
- package/components/hooks/{useHitSelection.js → useRecordSelection.js} +12 -33
- package/components/hooks/useRelatedRecords.d.ts +13 -0
- package/components/hooks/useRelatedRecords.js +32 -0
- 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/cases/CaseViewer.d.ts +2 -0
- package/components/routes/cases/CaseViewer.js +22 -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 +33 -0
- package/components/routes/cases/detail/CaseAssets.d.ts +11 -0
- package/components/routes/cases/detail/CaseAssets.js +104 -0
- package/components/routes/cases/detail/CaseAssets.test.d.ts +1 -0
- package/components/routes/cases/detail/CaseAssets.test.js +167 -0
- package/components/routes/cases/detail/CaseDashboard.d.ts +7 -0
- package/components/routes/cases/detail/CaseDashboard.js +66 -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 +8 -0
- package/components/routes/cases/detail/CaseSidebar.js +107 -0
- package/components/routes/cases/detail/CaseSidebar.test.d.ts +1 -0
- package/components/routes/cases/detail/CaseSidebar.test.js +246 -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/CaseTimeline.d.ts +12 -0
- package/components/routes/cases/detail/CaseTimeline.js +106 -0
- package/components/routes/cases/detail/CaseTimeline.test.d.ts +1 -0
- package/components/routes/cases/detail/CaseTimeline.test.js +227 -0
- package/components/routes/cases/detail/ItemPage.d.ts +6 -0
- package/components/routes/cases/detail/ItemPage.js +99 -0
- package/components/routes/cases/detail/RelatedCasePanel.d.ts +6 -0
- package/components/routes/cases/detail/RelatedCasePanel.js +34 -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 +11 -0
- package/components/routes/cases/detail/aggregates/CaseAggregate.js +24 -0
- package/components/routes/cases/detail/aggregates/SourceAggregate.d.ts +6 -0
- package/components/routes/cases/detail/aggregates/SourceAggregate.js +26 -0
- package/components/routes/cases/detail/assets/Asset.d.ts +14 -0
- package/components/routes/cases/detail/assets/Asset.js +12 -0
- package/components/routes/cases/detail/assets/Asset.test.d.ts +1 -0
- package/components/routes/cases/detail/assets/Asset.test.js +72 -0
- package/components/routes/cases/detail/sidebar/CaseFolder.d.ts +20 -0
- package/components/routes/cases/detail/sidebar/CaseFolder.js +83 -0
- package/components/routes/cases/detail/sidebar/CaseFolder.test.d.ts +1 -0
- package/components/routes/cases/detail/sidebar/CaseFolder.test.js +295 -0
- package/components/routes/cases/detail/sidebar/CaseFolderContextMenu.d.ts +34 -0
- package/components/routes/cases/detail/sidebar/CaseFolderContextMenu.js +103 -0
- package/components/routes/cases/detail/sidebar/CaseFolderContextMenu.test.d.ts +1 -0
- package/components/routes/cases/detail/sidebar/CaseFolderContextMenu.test.js +363 -0
- package/components/routes/cases/detail/sidebar/FolderEntry.d.ts +25 -0
- package/components/routes/cases/detail/sidebar/FolderEntry.js +88 -0
- package/components/routes/cases/detail/sidebar/FolderEntry.test.d.ts +1 -0
- package/components/routes/cases/detail/sidebar/FolderEntry.test.js +206 -0
- package/components/routes/cases/detail/sidebar/RootDropZone.d.ts +5 -0
- package/components/routes/cases/detail/sidebar/RootDropZone.js +33 -0
- package/components/routes/cases/detail/sidebar/types.d.ts +9 -0
- package/components/routes/cases/detail/sidebar/utils.d.ts +3 -0
- package/components/routes/cases/detail/sidebar/utils.js +29 -0
- package/components/routes/cases/detail/sidebar/utils.test.d.ts +1 -0
- package/components/routes/cases/detail/sidebar/utils.test.js +82 -0
- package/components/routes/cases/hooks/useCase.d.ts +13 -0
- package/components/routes/cases/hooks/useCase.js +51 -0
- package/components/routes/cases/modals/AddToCaseModal.d.ts +7 -0
- package/components/routes/cases/modals/AddToCaseModal.js +62 -0
- package/components/routes/cases/modals/RenameItemModal.d.ts +9 -0
- package/components/routes/cases/modals/RenameItemModal.js +48 -0
- package/components/routes/cases/modals/ResolveModal.d.ts +7 -0
- package/components/routes/cases/modals/ResolveModal.js +115 -0
- package/components/routes/cases/modals/ResolveModal.test.d.ts +1 -0
- package/components/routes/cases/modals/ResolveModal.test.js +384 -0
- 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/HitBannerDocumentation.js +1 -0
- package/components/routes/help/HitDocumentation.js +1 -3
- package/components/routes/hits/search/InformationPane.d.ts +1 -0
- package/components/routes/hits/search/InformationPane.js +47 -60
- package/components/routes/hits/search/LayoutSettings.js +3 -3
- package/components/routes/hits/search/QuerySettings.js +2 -1
- package/components/routes/hits/search/QuerySettings.test.js +14 -9
- package/components/routes/hits/search/{HitBrowser.js → RecordBrowser.js} +9 -9
- package/components/routes/hits/search/{HitQuery.d.ts → RecordQuery.d.ts} +2 -2
- package/components/routes/hits/search/{HitQuery.js → RecordQuery.js} +6 -6
- package/components/routes/hits/search/SearchPane.js +26 -49
- 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 +5 -4
- package/components/routes/hits/search/grid/EnhancedCell.d.ts +2 -1
- package/components/routes/hits/search/grid/EnhancedCell.js +2 -2
- package/components/routes/hits/search/grid/HitGrid.js +20 -18
- package/components/routes/hits/search/grid/{HitRow.d.ts → RecordRow.d.ts} +3 -2
- package/components/routes/hits/search/grid/{HitRow.js → RecordRow.js} +10 -8
- 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 +12 -13
- package/components/routes/home/ViewCard.js +47 -41
- 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/components/routes/views/ViewComposer.js +46 -19
- package/locales/en/translation.json +89 -3
- package/locales/fr/translation.json +87 -3
- 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/Hit.d.ts +1 -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 +85 -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 +43 -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/models/entities/generated/View.d.ts +1 -0
- package/package.json +114 -97
- package/plugins/clue/components/ClueTypography.js +2 -2
- package/plugins/clue/utils.d.ts +2 -1
- package/tests/mocks.d.ts +11 -1
- package/tests/mocks.js +12 -7
- package/tests/server-handlers.js +6 -1
- package/tests/utils.d.ts +4 -0
- package/tests/utils.js +20 -0
- package/utils/constants.d.ts +3 -3
- package/utils/hitFunctions.d.ts +2 -1
- package/utils/hitFunctions.js +4 -4
- package/utils/typeUtils.d.ts +7 -0
- package/utils/typeUtils.js +27 -0
- package/utils/viewUtils.js +3 -0
- package/components/app/providers/HitProvider.d.ts +0 -22
- package/components/elements/display/icons/BundleButton.d.ts +0 -6
- package/components/elements/display/icons/BundleButton.js +0 -32
- package/components/elements/hit/HitRelated.d.ts +0 -6
- package/components/elements/hit/HitRelated.js +0 -7
- 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/hits/search/BundleScroller.d.ts +0 -2
- package/components/routes/hits/search/BundleScroller.js +0 -6
- package/components/routes/hits/search/HitContextMenu.js +0 -227
- /package/components/app/providers/{HitSearchProvider.test.d.ts → RecordSearchProvider.test.d.ts} +0 -0
- /package/components/{routes/hits/search/HitContextMenu.test.d.ts → elements/ContextMenu.test.d.ts} +0 -0
- /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/components/routes/hits/search/{HitBrowser.d.ts → RecordBrowser.d.ts} +0 -0
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import type { Hit } from '@cccsaurora/howler-ui/models/entities/generated/Hit';
|
|
2
|
+
import type { Observable } from '@cccsaurora/howler-ui/models/entities/generated/Observable';
|
|
3
|
+
import type { WithMetadata } from '@cccsaurora/howler-ui/models/WithMetadata';
|
|
4
|
+
import type { FC, PropsWithChildren } from 'react';
|
|
5
|
+
export interface RecordContextType {
|
|
6
|
+
records: {
|
|
7
|
+
[index: string]: Hit | Observable;
|
|
8
|
+
};
|
|
9
|
+
selectedRecords: (Hit | Observable)[];
|
|
10
|
+
addRecordToSelection: (id: string) => void;
|
|
11
|
+
removeRecordFromSelection: (id: string) => void;
|
|
12
|
+
clearSelectedRecords: (except?: string) => void;
|
|
13
|
+
loadRecords: (hits: (Hit | Observable)[]) => void;
|
|
14
|
+
updateRecord: (newHit: Hit | Observable) => void;
|
|
15
|
+
getRecord: (id: string, force?: boolean) => Promise<WithMetadata<Hit | Observable>>;
|
|
16
|
+
}
|
|
17
|
+
export declare const RecordContext: import("use-context-selector").Context<RecordContextType>;
|
|
18
|
+
/**
|
|
19
|
+
* Central repository for storing individual hit data across the application. Allows efficient retrieval of hits across componenents.
|
|
20
|
+
*/
|
|
21
|
+
declare const RecordProvider: FC<PropsWithChildren>;
|
|
22
|
+
export declare const useHitContextSelector: <Selected>(selector: (value: RecordContextType) => Selected) => Selected;
|
|
23
|
+
export default RecordProvider;
|
|
@@ -5,25 +5,25 @@ import { uniq } from 'lodash-es';
|
|
|
5
5
|
import { useCallback, useContext, useEffect, useMemo, useRef, useState } from 'react';
|
|
6
6
|
import { createContext, useContextSelector } from 'use-context-selector';
|
|
7
7
|
import { SocketContext } from './SocketProvider';
|
|
8
|
-
export const
|
|
8
|
+
export const RecordContext = createContext(null);
|
|
9
9
|
/**
|
|
10
10
|
* Central repository for storing individual hit data across the application. Allows efficient retrieval of hits across componenents.
|
|
11
11
|
*/
|
|
12
|
-
const
|
|
12
|
+
const RecordProvider = ({ children }) => {
|
|
13
13
|
const { dispatchApi } = useMyApi();
|
|
14
14
|
const { addListener, removeListener } = useContext(SocketContext);
|
|
15
15
|
/**
|
|
16
16
|
* The most immediate of two levels of caching, this ref stores the raw promises for each hit.
|
|
17
17
|
* Rapidly updates, good for uses in-context where parallel updates my be occurring, i.e.
|
|
18
|
-
* when two cards request the same hit that's missing from the store. Used in
|
|
18
|
+
* when two cards request the same hit that's missing from the store. Used in getRecord for this reason.
|
|
19
19
|
*/
|
|
20
|
-
const
|
|
20
|
+
const recordRequests = useRef({});
|
|
21
21
|
/**
|
|
22
22
|
* The "Authoritative" store of hits. Changes here will trigger rerenders, and essentially
|
|
23
23
|
* caches the result of the above promises. Slower to update, so used outside of the hitcontext
|
|
24
24
|
* where parallel requests aren't an issue.
|
|
25
25
|
*/
|
|
26
|
-
const [
|
|
26
|
+
const [records, setRecords] = useState({});
|
|
27
27
|
const [selectedHitIds, setSelectedHitIds] = useState([]);
|
|
28
28
|
// The central location where we propagate any changes from hits made via websockets into the repository. We just save every update,
|
|
29
29
|
// instead of caching it across many components inconsistently as before.
|
|
@@ -31,8 +31,8 @@ const HitProvider = ({ children }) => {
|
|
|
31
31
|
if (data.hit) {
|
|
32
32
|
// eslint-disable-next-line no-console
|
|
33
33
|
console.debug('Received websocket update for hit', data.hit.howler.id);
|
|
34
|
-
|
|
35
|
-
|
|
34
|
+
recordRequests.current[data.hit.howler.id] = Promise.resolve(data.hit);
|
|
35
|
+
setRecords(_hits => ({
|
|
36
36
|
..._hits,
|
|
37
37
|
[data.hit.howler.id]: {
|
|
38
38
|
..._hits[data.hit.howler.id],
|
|
@@ -46,68 +46,68 @@ const HitProvider = ({ children }) => {
|
|
|
46
46
|
return () => removeListener('hits');
|
|
47
47
|
}, [addListener, handler, removeListener]);
|
|
48
48
|
/**
|
|
49
|
-
* A method to retrieve a
|
|
49
|
+
* A method to retrieve a record from the context. It first checks the hit state,
|
|
50
50
|
* then checks for ongoing requests, then finally executes a new request if necessary.
|
|
51
51
|
*/
|
|
52
|
-
const
|
|
53
|
-
if (!
|
|
54
|
-
|
|
55
|
-
const
|
|
56
|
-
|
|
52
|
+
const getRecord = useCallback(async (id, force = false) => {
|
|
53
|
+
if (!recordRequests.current[id] || force) {
|
|
54
|
+
recordRequests.current[id] = dispatchApi(api.hit.get(id, ['template', 'dossiers', 'analytic', 'overview']));
|
|
55
|
+
const newRecord = await recordRequests.current[id];
|
|
56
|
+
setRecords(_records => ({ ..._records, [id]: newRecord }));
|
|
57
57
|
}
|
|
58
|
-
return
|
|
58
|
+
return recordRequests.current[id];
|
|
59
59
|
}, [dispatchApi]);
|
|
60
60
|
/**
|
|
61
61
|
* Update a hit in the context locally
|
|
62
62
|
*/
|
|
63
|
-
const
|
|
64
|
-
|
|
65
|
-
|
|
63
|
+
const updateRecord = useCallback((newHit) => {
|
|
64
|
+
recordRequests.current[newHit.howler.id] = Promise.resolve(newHit);
|
|
65
|
+
setRecords(_hits => ({ ..._hits, [newHit.howler.id]: newHit }));
|
|
66
66
|
}, []);
|
|
67
67
|
/**
|
|
68
68
|
* Add a large number of hits to the cache. Used for results of searches.
|
|
69
69
|
*/
|
|
70
|
-
const
|
|
70
|
+
const loadRecords = useCallback((newHits) => {
|
|
71
71
|
const mappedHits = newHits.map(hit => [hit.howler.id, hit]);
|
|
72
72
|
mappedHits.forEach(([id, hit]) => {
|
|
73
|
-
|
|
73
|
+
recordRequests.current[id] = Promise.resolve(hit);
|
|
74
74
|
});
|
|
75
|
-
|
|
75
|
+
setRecords(_hits => ({ ..._hits, ...Object.fromEntries(mappedHits) }));
|
|
76
76
|
}, []);
|
|
77
|
-
const
|
|
77
|
+
const addRecordToSelection = useCallback((id) => {
|
|
78
78
|
setSelectedHitIds(_selected => uniq([..._selected, id]));
|
|
79
79
|
}, []);
|
|
80
|
-
const
|
|
80
|
+
const removeRecordFromSelection = useCallback((id) => {
|
|
81
81
|
setSelectedHitIds(_selected => _selected.filter(_id => _id !== id));
|
|
82
82
|
}, []);
|
|
83
|
-
const
|
|
83
|
+
const clearSelectedRecords = useCallback((except) => {
|
|
84
84
|
setSelectedHitIds(!!except ? [except] : []);
|
|
85
85
|
}, []);
|
|
86
|
-
const
|
|
86
|
+
const selectedRecords = useMemo(() => selectedHitIds.map(id => records[id]).filter(hit => !!hit), [records, selectedHitIds]);
|
|
87
87
|
useEffect(() => {
|
|
88
88
|
selectedHitIds.forEach(id => {
|
|
89
|
-
if (!
|
|
90
|
-
|
|
89
|
+
if (!recordRequests.current[id]) {
|
|
90
|
+
getRecord(id);
|
|
91
91
|
}
|
|
92
92
|
});
|
|
93
|
-
}, [
|
|
93
|
+
}, [getRecord, selectedHitIds]);
|
|
94
94
|
useEffect(() => {
|
|
95
|
-
Object.entries(
|
|
96
|
-
|
|
95
|
+
Object.entries(records).forEach(([id, hit]) => {
|
|
96
|
+
recordRequests.current[id] = Promise.resolve(hit);
|
|
97
97
|
});
|
|
98
|
-
}, [
|
|
99
|
-
return (_jsx(
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
98
|
+
}, [records]);
|
|
99
|
+
return (_jsx(RecordContext.Provider, { value: {
|
|
100
|
+
records,
|
|
101
|
+
getRecord,
|
|
102
|
+
updateRecord,
|
|
103
|
+
selectedRecords,
|
|
104
|
+
addRecordToSelection,
|
|
105
|
+
removeRecordFromSelection,
|
|
106
|
+
clearSelectedRecords,
|
|
107
|
+
loadRecords
|
|
108
108
|
}, children: children }));
|
|
109
109
|
};
|
|
110
110
|
export const useHitContextSelector = (selector) => {
|
|
111
|
-
return useContextSelector(
|
|
111
|
+
return useContextSelector(RecordContext, selector);
|
|
112
112
|
};
|
|
113
|
-
export default
|
|
113
|
+
export default RecordProvider;
|
|
@@ -1,17 +1,17 @@
|
|
|
1
1
|
import type { HowlerSearchResponse } from '@cccsaurora/howler-ui/api/search';
|
|
2
2
|
import { useMyLocalStorageItem } from '@cccsaurora/howler-ui/components/hooks/useMyLocalStorage';
|
|
3
3
|
import type { Hit } from '@cccsaurora/howler-ui/models/entities/generated/Hit';
|
|
4
|
+
import type { Observable } from '@cccsaurora/howler-ui/models/entities/generated/Observable';
|
|
4
5
|
import type { WithMetadata } from '@cccsaurora/howler-ui/models/WithMetadata';
|
|
5
6
|
import { type Dispatch, type FC, type PropsWithChildren, type SetStateAction } from 'react';
|
|
6
7
|
export interface QueryEntry {
|
|
7
8
|
[query: string]: string;
|
|
8
9
|
}
|
|
9
|
-
export interface
|
|
10
|
+
export interface RecordSearchContextType {
|
|
10
11
|
displayType: 'list' | 'grid';
|
|
11
12
|
searching: boolean;
|
|
12
13
|
error: string | null;
|
|
13
|
-
response: HowlerSearchResponse<WithMetadata<Hit>> | null;
|
|
14
|
-
bundleId: string | null;
|
|
14
|
+
response: HowlerSearchResponse<WithMetadata<Hit | Observable>> | null;
|
|
15
15
|
fzfSearch: boolean;
|
|
16
16
|
setDisplayType: (type: 'list' | 'grid') => void;
|
|
17
17
|
setFzfSearch: Dispatch<SetStateAction<boolean>>;
|
|
@@ -20,6 +20,6 @@ export interface HitSearchContextType {
|
|
|
20
20
|
queryHistory: QueryEntry;
|
|
21
21
|
setQueryHistory: ReturnType<typeof useMyLocalStorageItem>[1];
|
|
22
22
|
}
|
|
23
|
-
export declare const
|
|
24
|
-
declare const
|
|
25
|
-
export default
|
|
23
|
+
export declare const RecordSearchContext: import("use-context-selector").Context<RecordSearchContextType>;
|
|
24
|
+
declare const RecordSearchProvider: FC<PropsWithChildren>;
|
|
25
|
+
export default RecordSearchProvider;
|
|
@@ -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';
|
|
17
16
|
import { ParameterContext } from './ParameterProvider';
|
|
17
|
+
import { RecordContext } from './RecordProvider';
|
|
18
18
|
import { ViewContext } from './ViewProvider';
|
|
19
|
-
export const
|
|
19
|
+
export const RecordSearchContext = createContext(null);
|
|
20
20
|
const THROTTLER = new Throttler(500);
|
|
21
|
-
const
|
|
21
|
+
const RecordSearchProvider = ({ children }) => {
|
|
22
22
|
const { get } = useMyLocalStorage();
|
|
23
23
|
const routeParams = useParams();
|
|
24
24
|
const location = useLocation();
|
|
@@ -33,12 +33,13 @@ 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);
|
|
39
40
|
const views = useContextSelector(ParameterContext, ctx => ctx.views);
|
|
40
41
|
const addView = useContextSelector(ParameterContext, ctx => ctx.addView);
|
|
41
|
-
const loadHits = useContextSelector(
|
|
42
|
+
const loadHits = useContextSelector(RecordContext, ctx => ctx.loadRecords);
|
|
42
43
|
const [displayType, setDisplayType] = useState(get(StorageKey.DISPLAY_TYPE) ?? 'list');
|
|
43
44
|
const [searching, setSearching] = useState(false);
|
|
44
45
|
const [error, setError] = useState(null);
|
|
@@ -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,15 +161,15 @@ 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,
|
|
176
|
-
return (_jsx(
|
|
171
|
+
}, [offset, pageCount, sort, span, indexes, location.pathname, startDate, endDate, filters, query, views]);
|
|
172
|
+
return (_jsx(RecordSearchContext.Provider, { value: {
|
|
177
173
|
displayType,
|
|
178
174
|
setDisplayType,
|
|
179
175
|
search,
|
|
@@ -181,11 +177,10 @@ const HitSearchProvider = ({ children }) => {
|
|
|
181
177
|
getFilters,
|
|
182
178
|
error,
|
|
183
179
|
response,
|
|
184
|
-
bundleId,
|
|
185
180
|
setQueryHistory,
|
|
186
181
|
queryHistory,
|
|
187
182
|
fzfSearch,
|
|
188
183
|
setFzfSearch
|
|
189
184
|
}, children: children }));
|
|
190
185
|
};
|
|
191
|
-
export default
|
|
186
|
+
export default RecordSearchProvider;
|