@cccsaurora/howler-ui 2.18.0-dev.739 → 2.18.0-dev.748
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} +20 -23
- package/components/app/providers/{HitSearchProvider.test.js → RecordSearchProvider.test.js} +68 -65
- 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/{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,
|
|
@@ -122,12 +117,14 @@ const HitSearchProvider = ({ children }) => {
|
|
|
122
117
|
setResponse(_response);
|
|
123
118
|
}
|
|
124
119
|
else {
|
|
125
|
-
setResponse(_existingResponse =>
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
120
|
+
setResponse(_existingResponse => _existingResponse
|
|
121
|
+
? {
|
|
122
|
+
..._response,
|
|
123
|
+
offset: _existingResponse.offset,
|
|
124
|
+
rows: Math.min(_existingResponse.rows + _response.rows, _response.total),
|
|
125
|
+
items: [..._existingResponse.items, ..._response.items]
|
|
126
|
+
}
|
|
127
|
+
: _response);
|
|
131
128
|
}
|
|
132
129
|
}
|
|
133
130
|
catch (e) {
|
|
@@ -147,6 +144,7 @@ const HitSearchProvider = ({ children }) => {
|
|
|
147
144
|
startDate,
|
|
148
145
|
endDate,
|
|
149
146
|
filters,
|
|
147
|
+
indexes,
|
|
150
148
|
setQuery,
|
|
151
149
|
location.pathname,
|
|
152
150
|
routeParams.id,
|
|
@@ -165,15 +163,15 @@ const HitSearchProvider = ({ children }) => {
|
|
|
165
163
|
if (span?.endsWith('custom') && (!startDate || !endDate)) {
|
|
166
164
|
return;
|
|
167
165
|
}
|
|
168
|
-
if (views.length > 0 ||
|
|
166
|
+
if (views.length > 0 || (query && query !== DEFAULT_QUERY) || offset > 0 || filters.length > 0) {
|
|
169
167
|
search(query);
|
|
170
168
|
}
|
|
171
169
|
else {
|
|
172
170
|
setResponse(null);
|
|
173
171
|
}
|
|
174
172
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
175
|
-
}, [offset, pageCount, sort, span,
|
|
176
|
-
return (_jsx(
|
|
173
|
+
}, [offset, pageCount, sort, span, indexes, location.pathname, startDate, endDate, filters, query, views]);
|
|
174
|
+
return (_jsx(RecordSearchContext.Provider, { value: {
|
|
177
175
|
displayType,
|
|
178
176
|
setDisplayType,
|
|
179
177
|
search,
|
|
@@ -181,11 +179,10 @@ const HitSearchProvider = ({ children }) => {
|
|
|
181
179
|
getFilters,
|
|
182
180
|
error,
|
|
183
181
|
response,
|
|
184
|
-
bundleId,
|
|
185
182
|
setQueryHistory,
|
|
186
183
|
queryHistory,
|
|
187
184
|
fzfSearch,
|
|
188
185
|
setFzfSearch
|
|
189
186
|
}, children: children }));
|
|
190
187
|
};
|
|
191
|
-
export default
|
|
188
|
+
export default RecordSearchProvider;
|