@cccsaurora/howler-ui 2.17.0-dev.600 → 2.17.1-dev.627
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/api/index.d.ts +0 -2
- package/api/index.js +2 -4
- package/api/search/index.d.ts +1 -2
- package/api/search/index.js +1 -2
- package/commons/components/leftnav/LeftNavDrawer.js +1 -1
- package/components/app/App.js +0 -14
- package/components/app/providers/FavouritesProvider.js +2 -2
- package/components/app/providers/HitSearchProvider.d.ts +1 -0
- package/components/app/providers/HitSearchProvider.js +11 -6
- package/components/app/providers/HitSearchProvider.test.js +32 -11
- package/components/app/providers/LocalStorageProvider.js +1 -1
- package/components/app/providers/ParameterProvider.d.ts +2 -9
- package/components/app/providers/ParameterProvider.js +240 -165
- package/components/app/providers/ParameterProvider.test.js +14 -307
- package/components/elements/EditRow.d.ts +4 -1
- package/components/elements/EditRow.js +4 -4
- package/components/elements/PluginTypography.d.ts +1 -2
- package/components/elements/PluginTypography.js +2 -3
- package/components/elements/UserList.d.ts +2 -5
- package/components/elements/UserList.js +5 -14
- package/components/elements/addons/search/phrase/Phrase.js +1 -1
- package/components/elements/display/ChipPopper.d.ts +1 -1
- package/components/elements/display/ChipPopper.js +1 -1
- package/components/elements/display/HowlerCard.js +1 -1
- package/components/elements/display/Modal.js +0 -1
- package/components/elements/display/icons/BundleButton.d.ts +6 -0
- package/components/elements/display/icons/BundleButton.js +32 -0
- package/components/elements/hit/HitBanner.js +48 -28
- package/components/elements/hit/HitCard.js +1 -1
- package/components/elements/{ObjectDetails.js → hit/HitDetails.js} +17 -17
- package/components/elements/hit/HitOutline.js +7 -3
- package/components/elements/hit/{HitPreview.d.ts → HitQuickSearch.d.ts} +3 -3
- package/components/elements/hit/{HitPreview.js → HitQuickSearch.js} +4 -10
- package/components/elements/hit/HitRelated.d.ts +1 -1
- package/components/elements/hit/HitRelated.js +3 -30
- package/components/elements/hit/outlines/DefaultOutline.js +1 -1
- package/components/elements/hit/related/PivotLink.js +1 -1
- package/components/elements/hit/related/RelatedLink.d.ts +1 -0
- package/components/elements/hit/related/RelatedLink.js +2 -2
- 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 +24 -3
- package/components/hooks/useLocalStorage.d.ts +13 -0
- package/components/hooks/useLocalStorage.js +53 -0
- package/components/hooks/useLocalStorageItem.d.ts +18 -0
- package/components/hooks/useLocalStorageItem.js +78 -0
- package/components/hooks/useLocalStorageItem.test.d.ts +1 -0
- package/components/hooks/useLocalStorageItem.test.js +144 -0
- package/components/hooks/useMyLocalStorage.js +2 -2
- package/components/hooks/useMyPreferences.js +1 -10
- package/components/hooks/useMySearch.js +2 -2
- package/components/hooks/useMySitemap.js +1 -4
- package/components/hooks/useMyTheme.js +2 -9
- package/components/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/help/ApiDocumentation.js +1 -1
- package/components/routes/help/BundleDocumentation.d.ts +3 -0
- package/components/routes/help/BundleDocumentation.js +12 -0
- package/components/routes/help/HitDocumentation.js +3 -1
- package/components/routes/help/markdown/en/bundles.md.js +1 -0
- package/components/routes/help/markdown/fr/bundles.md.js +1 -0
- package/components/routes/hits/search/BundleParentMenu.d.ts +6 -0
- package/components/routes/hits/search/BundleParentMenu.js +32 -0
- package/components/routes/hits/search/HitContextMenu.js +2 -3
- package/components/routes/hits/search/InformationPane.d.ts +0 -1
- package/components/routes/hits/search/InformationPane.js +28 -6
- package/components/routes/hits/search/LayoutSettings.d.ts +3 -0
- package/components/routes/hits/search/LayoutSettings.js +18 -0
- package/components/routes/hits/search/QuerySettings.js +1 -2
- package/components/routes/hits/search/QuerySettings.test.js +9 -14
- package/components/routes/hits/search/SearchPane.js +37 -13
- package/components/routes/hits/search/ViewLink.js +1 -1
- package/components/routes/hits/search/grid/EnhancedCell.js +1 -1
- package/components/routes/hits/view/HitViewer.js +4 -3
- package/components/routes/home/AnalyticCard.d.ts +2 -3
- package/components/routes/home/AnalyticCard.js +2 -2
- package/components/routes/home/ViewCard.js +1 -1
- package/components/routes/home/ViewRefresh.d.ts +23 -0
- package/components/routes/home/ViewRefresh.js +67 -0
- package/components/routes/home/index.js +9 -46
- package/components/{elements/MarkdownEditor.js → routes/overviews/OverviewEditor.js} +3 -3
- package/components/routes/overviews/OverviewViewer.js +2 -2
- package/components/routes/settings/LocalSection.js +2 -1
- package/locales/en/translation.json +6 -42
- package/locales/fr/translation.json +4 -35
- package/models/WithMetadata.d.ts +1 -2
- package/models/entities/generated/{ThreatEnrichment.d.ts → Enrichment.d.ts} +1 -1
- package/models/entities/generated/Howler.d.ts +4 -0
- package/models/entities/generated/Rule.d.ts +10 -2
- package/models/entities/generated/Threat.d.ts +2 -2
- package/package.json +1 -16
- package/plugins/clue/components/ClueTypography.js +2 -2
- package/plugins/clue/utils.d.ts +1 -2
- package/utils/constants.d.ts +4 -3
- package/utils/constants.js +1 -0
- package/api/search/case.d.ts +0 -4
- package/api/search/case.js +0 -8
- package/api/v2/case/index.d.ts +0 -6
- package/api/v2/case/index.js +0 -18
- package/api/v2/index.d.ts +0 -4
- package/api/v2/index.js +0 -6
- package/api/v2/search/facet.d.ts +0 -3
- package/api/v2/search/facet.js +0 -12
- package/api/v2/search/index.d.ts +0 -5
- package/api/v2/search/index.js +0 -24
- package/components/elements/ObjectDetails.d.ts +0 -6
- package/components/elements/case/CaseCard.d.ts +0 -8
- package/components/elements/case/CaseCard.js +0 -39
- package/components/elements/case/CasePreview.d.ts +0 -6
- package/components/elements/case/CasePreview.js +0 -17
- package/components/elements/case/StatusIcon.d.ts +0 -5
- package/components/elements/case/StatusIcon.js +0 -13
- package/components/elements/hit/elements/AnalyticLink.d.ts +0 -8
- package/components/elements/hit/elements/AnalyticLink.js +0 -22
- package/components/elements/hit/related/RelatedRecords.js +0 -63
- package/components/elements/observable/ObservableCard.d.ts +0 -5
- package/components/elements/observable/ObservableCard.js +0 -7
- package/components/elements/observable/ObservablePreview.d.ts +0 -6
- package/components/elements/observable/ObservablePreview.js +0 -12
- package/components/hooks/useRelatedRecords.d.ts +0 -13
- package/components/hooks/useRelatedRecords.js +0 -32
- package/components/routes/cases/CaseViewer.d.ts +0 -2
- package/components/routes/cases/CaseViewer.js +0 -24
- package/components/routes/cases/Cases.d.ts +0 -2
- package/components/routes/cases/Cases.js +0 -101
- package/components/routes/cases/constants.d.ts +0 -5
- package/components/routes/cases/constants.js +0 -5
- package/components/routes/cases/detail/AlertPanel.d.ts +0 -6
- package/components/routes/cases/detail/AlertPanel.js +0 -32
- package/components/routes/cases/detail/CaseDashboard.d.ts +0 -7
- package/components/routes/cases/detail/CaseDashboard.js +0 -49
- package/components/routes/cases/detail/CaseDetails.d.ts +0 -6
- package/components/routes/cases/detail/CaseDetails.js +0 -61
- package/components/routes/cases/detail/CaseOverview.d.ts +0 -7
- package/components/routes/cases/detail/CaseOverview.js +0 -43
- package/components/routes/cases/detail/CaseSidebar.d.ts +0 -6
- package/components/routes/cases/detail/CaseSidebar.js +0 -36
- package/components/routes/cases/detail/CaseTask.d.ts +0 -11
- package/components/routes/cases/detail/CaseTask.js +0 -57
- package/components/routes/cases/detail/ItemPage.d.ts +0 -6
- package/components/routes/cases/detail/ItemPage.js +0 -93
- package/components/routes/cases/detail/RelatedCasePanel.d.ts +0 -6
- package/components/routes/cases/detail/RelatedCasePanel.js +0 -31
- package/components/routes/cases/detail/TaskPanel.d.ts +0 -7
- package/components/routes/cases/detail/TaskPanel.js +0 -52
- package/components/routes/cases/detail/aggregates/CaseAggregate.d.ts +0 -12
- package/components/routes/cases/detail/aggregates/CaseAggregate.js +0 -19
- package/components/routes/cases/detail/aggregates/SourceAggregate.d.ts +0 -6
- package/components/routes/cases/detail/aggregates/SourceAggregate.js +0 -27
- package/components/routes/cases/detail/sidebar/CaseFolder.d.ts +0 -12
- package/components/routes/cases/detail/sidebar/CaseFolder.js +0 -179
- package/components/routes/cases/detail/sidebar/types.d.ts +0 -3
- package/components/routes/cases/hooks/useCase.d.ts +0 -13
- package/components/routes/cases/hooks/useCase.js +0 -38
- package/components/routes/cases/modals/ResolveModal.d.ts +0 -7
- package/components/routes/cases/modals/ResolveModal.js +0 -59
- package/components/routes/hits/search/shared/IndexPicker.d.ts +0 -2
- package/components/routes/hits/search/shared/IndexPicker.js +0 -20
- package/components/routes/observables/ObservableViewer.d.ts +0 -7
- package/components/routes/observables/ObservableViewer.js +0 -27
- package/models/entities/generated/AttachmentsFile.d.ts +0 -12
- package/models/entities/generated/Case.d.ts +0 -28
- package/models/entities/generated/DestinationOriginal.d.ts +0 -19
- package/models/entities/generated/EmailAttachment.d.ts +0 -8
- package/models/entities/generated/EmailParent.d.ts +0 -19
- package/models/entities/generated/Enrichments.d.ts +0 -7
- package/models/entities/generated/EnrichmentsIndicator.d.ts +0 -21
- package/models/entities/generated/HttpResponse.d.ts +0 -11
- package/models/entities/generated/Item.d.ts +0 -9
- package/models/entities/generated/Observable.d.ts +0 -84
- package/models/entities/generated/ObservableCloud.d.ts +0 -20
- package/models/entities/generated/ObservableDestination.d.ts +0 -23
- package/models/entities/generated/ObservableEmail.d.ts +0 -30
- package/models/entities/generated/ObservableFile.d.ts +0 -36
- package/models/entities/generated/ObservableHowler.d.ts +0 -44
- package/models/entities/generated/ObservableHttp.d.ts +0 -11
- package/models/entities/generated/ObservableObserver.d.ts +0 -21
- package/models/entities/generated/ObservableOrganization.d.ts +0 -7
- package/models/entities/generated/ObservableProcess.d.ts +0 -34
- package/models/entities/generated/ObservableSource.d.ts +0 -23
- package/models/entities/generated/ObservableThreat.d.ts +0 -21
- package/models/entities/generated/ObservableTls.d.ts +0 -12
- package/models/entities/generated/ObserverIngress.d.ts +0 -9
- package/models/entities/generated/Task.d.ts +0 -10
- package/utils/typeUtils.d.ts +0 -7
- package/utils/typeUtils.js +0 -18
- /package/components/elements/hit/{related/RelatedRecords.d.ts → HitDetails.d.ts} +0 -0
- /package/components/{elements/MarkdownEditor.d.ts → routes/overviews/OverviewEditor.d.ts} +0 -0
|
@@ -272,17 +272,17 @@ describe('ParameterContext', () => {
|
|
|
272
272
|
});
|
|
273
273
|
});
|
|
274
274
|
});
|
|
275
|
-
describe('
|
|
275
|
+
describe('clearFilters', () => {
|
|
276
276
|
it('should clear all filters', async () => {
|
|
277
277
|
mockSearchParams = new URLSearchParams();
|
|
278
278
|
mockSearchParams.append('filter', 'filter1');
|
|
279
279
|
mockSearchParams.append('filter', 'filter2');
|
|
280
280
|
const hook = renderHook(() => useContextSelector(ParameterContext, ctx => ({
|
|
281
281
|
filters: ctx.filters,
|
|
282
|
-
|
|
282
|
+
clearFilters: ctx.clearFilters
|
|
283
283
|
})), { wrapper: Wrapper });
|
|
284
284
|
await act(async () => {
|
|
285
|
-
hook.result.current.
|
|
285
|
+
hook.result.current.clearFilters();
|
|
286
286
|
});
|
|
287
287
|
await waitFor(() => {
|
|
288
288
|
expect(hook.result.current.filters).toEqual([]);
|
|
@@ -291,10 +291,10 @@ describe('ParameterContext', () => {
|
|
|
291
291
|
it('should be no-op when already empty', async () => {
|
|
292
292
|
const hook = renderHook(() => useContextSelector(ParameterContext, ctx => ({
|
|
293
293
|
filters: ctx.filters,
|
|
294
|
-
|
|
294
|
+
clearFilters: ctx.clearFilters
|
|
295
295
|
})), { wrapper: Wrapper });
|
|
296
296
|
await act(async () => {
|
|
297
|
-
hook.result.current.
|
|
297
|
+
hook.result.current.clearFilters();
|
|
298
298
|
});
|
|
299
299
|
await waitFor(() => {
|
|
300
300
|
expect(hook.result.current.filters).toEqual([]);
|
|
@@ -441,10 +441,10 @@ describe('ParameterContext', () => {
|
|
|
441
441
|
mockSearchParams.append('filter', 'filter1');
|
|
442
442
|
mockSearchParams.append('filter', 'filter2');
|
|
443
443
|
const hook = renderHook(() => useContextSelector(ParameterContext, ctx => ({
|
|
444
|
-
|
|
444
|
+
clearFilters: ctx.clearFilters
|
|
445
445
|
})), { wrapper: Wrapper });
|
|
446
446
|
await act(async () => {
|
|
447
|
-
hook.result.current.
|
|
447
|
+
hook.result.current.clearFilters();
|
|
448
448
|
});
|
|
449
449
|
await waitFor(() => {
|
|
450
450
|
expect(mockSetParams).toHaveBeenCalled();
|
|
@@ -706,299 +706,6 @@ describe('ParameterContext', () => {
|
|
|
706
706
|
});
|
|
707
707
|
});
|
|
708
708
|
});
|
|
709
|
-
describe('indexes (multi-index support)', () => {
|
|
710
|
-
it('should initialize with default ["hit"] when no index params are present', async () => {
|
|
711
|
-
const hook = renderHook(() => useContextSelector(ParameterContext, ctx => ctx.indexes), { wrapper: Wrapper });
|
|
712
|
-
expect(hook.result.current).toEqual(['hit']);
|
|
713
|
-
});
|
|
714
|
-
it('should initialize with single index from URL', async () => {
|
|
715
|
-
mockSearchParams = new URLSearchParams({ index: 'observable' });
|
|
716
|
-
const hook = renderHook(() => useContextSelector(ParameterContext, ctx => ctx.indexes), { wrapper: Wrapper });
|
|
717
|
-
expect(hook.result.current).toEqual(['observable']);
|
|
718
|
-
});
|
|
719
|
-
it('should initialize with multiple indexes from URL', async () => {
|
|
720
|
-
mockSearchParams = new URLSearchParams();
|
|
721
|
-
mockSearchParams.append('index', 'hit');
|
|
722
|
-
mockSearchParams.append('index', 'observable');
|
|
723
|
-
const hook = renderHook(() => useContextSelector(ParameterContext, ctx => ctx.indexes), { wrapper: Wrapper });
|
|
724
|
-
expect(hook.result.current).toEqual(['hit', 'observable']);
|
|
725
|
-
});
|
|
726
|
-
it('should deduplicate repeated index values from URL', async () => {
|
|
727
|
-
mockSearchParams = new URLSearchParams();
|
|
728
|
-
mockSearchParams.append('index', 'hit');
|
|
729
|
-
mockSearchParams.append('index', 'hit');
|
|
730
|
-
const hook = renderHook(() => useContextSelector(ParameterContext, ctx => ctx.indexes), { wrapper: Wrapper });
|
|
731
|
-
expect(hook.result.current).toEqual(['hit']);
|
|
732
|
-
});
|
|
733
|
-
describe('addIndex', () => {
|
|
734
|
-
it('should add an index to the default array', async () => {
|
|
735
|
-
const hook = renderHook(() => useContextSelector(ParameterContext, ctx => ({
|
|
736
|
-
indexes: ctx.indexes,
|
|
737
|
-
addIndex: ctx.addIndex
|
|
738
|
-
})), { wrapper: Wrapper });
|
|
739
|
-
await act(async () => {
|
|
740
|
-
hook.result.current.addIndex('observable');
|
|
741
|
-
});
|
|
742
|
-
await waitFor(() => {
|
|
743
|
-
expect(hook.result.current.indexes).toEqual(['hit', 'observable']);
|
|
744
|
-
});
|
|
745
|
-
});
|
|
746
|
-
it('should not add a duplicate index', async () => {
|
|
747
|
-
const hook = renderHook(() => useContextSelector(ParameterContext, ctx => ({
|
|
748
|
-
indexes: ctx.indexes,
|
|
749
|
-
addIndex: ctx.addIndex
|
|
750
|
-
})), { wrapper: Wrapper });
|
|
751
|
-
await act(async () => {
|
|
752
|
-
hook.result.current.addIndex('hit');
|
|
753
|
-
});
|
|
754
|
-
await waitFor(() => {
|
|
755
|
-
expect(hook.result.current.indexes).toEqual(['hit']);
|
|
756
|
-
});
|
|
757
|
-
});
|
|
758
|
-
});
|
|
759
|
-
describe('removeIndex', () => {
|
|
760
|
-
it('should remove an index from the list', async () => {
|
|
761
|
-
mockSearchParams = new URLSearchParams();
|
|
762
|
-
mockSearchParams.append('index', 'hit');
|
|
763
|
-
mockSearchParams.append('index', 'observable');
|
|
764
|
-
const hook = renderHook(() => useContextSelector(ParameterContext, ctx => ({
|
|
765
|
-
indexes: ctx.indexes,
|
|
766
|
-
removeIndex: ctx.removeIndex
|
|
767
|
-
})), { wrapper: Wrapper });
|
|
768
|
-
await act(async () => {
|
|
769
|
-
hook.result.current.removeIndex('hit');
|
|
770
|
-
});
|
|
771
|
-
await waitFor(() => {
|
|
772
|
-
expect(hook.result.current.indexes).toEqual(['observable']);
|
|
773
|
-
});
|
|
774
|
-
});
|
|
775
|
-
it('should do nothing when removing a nonexistent index', async () => {
|
|
776
|
-
const hook = renderHook(() => useContextSelector(ParameterContext, ctx => ({
|
|
777
|
-
indexes: ctx.indexes,
|
|
778
|
-
removeIndex: ctx.removeIndex
|
|
779
|
-
})), { wrapper: Wrapper });
|
|
780
|
-
await act(async () => {
|
|
781
|
-
hook.result.current.removeIndex('observable');
|
|
782
|
-
});
|
|
783
|
-
await waitFor(() => {
|
|
784
|
-
expect(hook.result.current.indexes).toEqual(['hit']);
|
|
785
|
-
});
|
|
786
|
-
});
|
|
787
|
-
it('should handle removing from empty array', async () => {
|
|
788
|
-
mockSearchParams = new URLSearchParams();
|
|
789
|
-
mockSearchParams.append('index', 'hit');
|
|
790
|
-
const hook = renderHook(() => useContextSelector(ParameterContext, ctx => ({
|
|
791
|
-
indexes: ctx.indexes,
|
|
792
|
-
removeIndex: ctx.removeIndex
|
|
793
|
-
})), { wrapper: Wrapper });
|
|
794
|
-
await act(async () => {
|
|
795
|
-
hook.result.current.removeIndex('hit');
|
|
796
|
-
});
|
|
797
|
-
await waitFor(() => {
|
|
798
|
-
expect(hook.result.current.indexes).toEqual([]);
|
|
799
|
-
});
|
|
800
|
-
});
|
|
801
|
-
});
|
|
802
|
-
describe('setIndex', () => {
|
|
803
|
-
it('should update the index at the specified position', async () => {
|
|
804
|
-
mockSearchParams = new URLSearchParams();
|
|
805
|
-
mockSearchParams.append('index', 'hit');
|
|
806
|
-
mockSearchParams.append('index', 'observable');
|
|
807
|
-
const hook = renderHook(() => useContextSelector(ParameterContext, ctx => ({
|
|
808
|
-
indexes: ctx.indexes,
|
|
809
|
-
setIndex: ctx.setIndex
|
|
810
|
-
})), { wrapper: Wrapper });
|
|
811
|
-
await act(async () => {
|
|
812
|
-
hook.result.current.setIndex(0, 'observable');
|
|
813
|
-
});
|
|
814
|
-
await waitFor(() => {
|
|
815
|
-
expect(hook.result.current.indexes).toEqual(['observable', 'observable']);
|
|
816
|
-
});
|
|
817
|
-
});
|
|
818
|
-
it('should do nothing when index is out of bounds', async () => {
|
|
819
|
-
const hook = renderHook(() => useContextSelector(ParameterContext, ctx => ({
|
|
820
|
-
indexes: ctx.indexes,
|
|
821
|
-
setIndex: ctx.setIndex
|
|
822
|
-
})), { wrapper: Wrapper });
|
|
823
|
-
await act(async () => {
|
|
824
|
-
hook.result.current.setIndex(5, 'observable');
|
|
825
|
-
});
|
|
826
|
-
await waitFor(() => {
|
|
827
|
-
expect(hook.result.current.indexes).toEqual(['hit']);
|
|
828
|
-
});
|
|
829
|
-
});
|
|
830
|
-
it('should do nothing when position is negative', async () => {
|
|
831
|
-
const hook = renderHook(() => useContextSelector(ParameterContext, ctx => ({
|
|
832
|
-
indexes: ctx.indexes,
|
|
833
|
-
setIndex: ctx.setIndex
|
|
834
|
-
})), { wrapper: Wrapper });
|
|
835
|
-
await act(async () => {
|
|
836
|
-
hook.result.current.setIndex(-1, 'observable');
|
|
837
|
-
});
|
|
838
|
-
await waitFor(() => {
|
|
839
|
-
expect(hook.result.current.indexes).toEqual(['hit']);
|
|
840
|
-
});
|
|
841
|
-
});
|
|
842
|
-
});
|
|
843
|
-
describe('setIndexes', () => {
|
|
844
|
-
it('should replace all indexes with the provided list', async () => {
|
|
845
|
-
const hook = renderHook(() => useContextSelector(ParameterContext, ctx => ({
|
|
846
|
-
indexes: ctx.indexes,
|
|
847
|
-
setIndexes: ctx.setIndexes
|
|
848
|
-
})), { wrapper: Wrapper });
|
|
849
|
-
await act(async () => {
|
|
850
|
-
hook.result.current.setIndexes(['observable']);
|
|
851
|
-
});
|
|
852
|
-
await waitFor(() => {
|
|
853
|
-
expect(hook.result.current.indexes).toEqual(['observable']);
|
|
854
|
-
});
|
|
855
|
-
});
|
|
856
|
-
it('should deduplicate values when setting all indexes', async () => {
|
|
857
|
-
const hook = renderHook(() => useContextSelector(ParameterContext, ctx => ({
|
|
858
|
-
indexes: ctx.indexes,
|
|
859
|
-
setIndexes: ctx.setIndexes
|
|
860
|
-
})), { wrapper: Wrapper });
|
|
861
|
-
await act(async () => {
|
|
862
|
-
hook.result.current.setIndexes(['hit', 'hit', 'observable']);
|
|
863
|
-
});
|
|
864
|
-
await waitFor(() => {
|
|
865
|
-
expect(hook.result.current.indexes).toEqual(['hit', 'observable']);
|
|
866
|
-
});
|
|
867
|
-
});
|
|
868
|
-
it('should set to empty array', async () => {
|
|
869
|
-
const hook = renderHook(() => useContextSelector(ParameterContext, ctx => ({
|
|
870
|
-
indexes: ctx.indexes,
|
|
871
|
-
setIndexes: ctx.setIndexes
|
|
872
|
-
})), { wrapper: Wrapper });
|
|
873
|
-
await act(async () => {
|
|
874
|
-
hook.result.current.setIndexes([]);
|
|
875
|
-
});
|
|
876
|
-
await waitFor(() => {
|
|
877
|
-
expect(hook.result.current.indexes).toEqual([]);
|
|
878
|
-
});
|
|
879
|
-
});
|
|
880
|
-
});
|
|
881
|
-
describe('resetIndexes', () => {
|
|
882
|
-
it('should reset indexes to default ["hit"]', async () => {
|
|
883
|
-
mockSearchParams = new URLSearchParams();
|
|
884
|
-
mockSearchParams.append('index', 'hit');
|
|
885
|
-
mockSearchParams.append('index', 'observable');
|
|
886
|
-
const hook = renderHook(() => useContextSelector(ParameterContext, ctx => ({
|
|
887
|
-
indexes: ctx.indexes,
|
|
888
|
-
resetIndexes: ctx.resetIndexes
|
|
889
|
-
})), { wrapper: Wrapper });
|
|
890
|
-
await act(async () => {
|
|
891
|
-
hook.result.current.resetIndexes();
|
|
892
|
-
});
|
|
893
|
-
await waitFor(() => {
|
|
894
|
-
expect(hook.result.current.indexes).toEqual(['hit']);
|
|
895
|
-
});
|
|
896
|
-
});
|
|
897
|
-
it('should reset to default even when called on empty array', async () => {
|
|
898
|
-
mockSearchParams = new URLSearchParams();
|
|
899
|
-
mockSearchParams.append('index', 'hit');
|
|
900
|
-
const hook = renderHook(() => useContextSelector(ParameterContext, ctx => ({
|
|
901
|
-
indexes: ctx.indexes,
|
|
902
|
-
removeIndex: ctx.removeIndex,
|
|
903
|
-
resetIndexes: ctx.resetIndexes
|
|
904
|
-
})), { wrapper: Wrapper });
|
|
905
|
-
// First empty it
|
|
906
|
-
await act(async () => {
|
|
907
|
-
hook.result.current.removeIndex('hit');
|
|
908
|
-
});
|
|
909
|
-
await waitFor(() => {
|
|
910
|
-
expect(hook.result.current.indexes).toEqual([]);
|
|
911
|
-
});
|
|
912
|
-
// Resetting always returns to default ['hit']
|
|
913
|
-
await act(async () => {
|
|
914
|
-
hook.result.current.resetIndexes();
|
|
915
|
-
});
|
|
916
|
-
await waitFor(() => {
|
|
917
|
-
expect(hook.result.current.indexes).toEqual(['hit']);
|
|
918
|
-
});
|
|
919
|
-
});
|
|
920
|
-
});
|
|
921
|
-
describe('URL synchronization', () => {
|
|
922
|
-
it('should not write the default ["hit"] index to the URL', async () => {
|
|
923
|
-
renderHook(() => useContextSelector(ParameterContext, ctx => ctx.indexes), { wrapper: Wrapper });
|
|
924
|
-
// Allow any effects to flush
|
|
925
|
-
await waitFor(() => {
|
|
926
|
-
// If setParams was called, the URL must not contain ?index=hit
|
|
927
|
-
if (mockSetParams.mock.calls.length > 0) {
|
|
928
|
-
const call = mockSetParams.mock.calls[mockSetParams.mock.calls.length - 1];
|
|
929
|
-
const urlParams = typeof call[0] === 'function' ? call[0](mockSearchParams) : call[0];
|
|
930
|
-
expect(urlParams.getAll('index')).toEqual([]);
|
|
931
|
-
}
|
|
932
|
-
else {
|
|
933
|
-
// setParams not called at all is also fine
|
|
934
|
-
expect(true).toBe(true);
|
|
935
|
-
}
|
|
936
|
-
});
|
|
937
|
-
});
|
|
938
|
-
it('should write a non-default index to the URL', async () => {
|
|
939
|
-
const hook = renderHook(() => useContextSelector(ParameterContext, ctx => ({
|
|
940
|
-
addIndex: ctx.addIndex,
|
|
941
|
-
resetIndexes: ctx.resetIndexes
|
|
942
|
-
})), { wrapper: Wrapper });
|
|
943
|
-
await act(async () => {
|
|
944
|
-
hook.result.current.resetIndexes();
|
|
945
|
-
hook.result.current.addIndex('observable');
|
|
946
|
-
});
|
|
947
|
-
await waitFor(() => {
|
|
948
|
-
expect(mockSetParams).toHaveBeenCalled();
|
|
949
|
-
const call = mockSetParams.mock.calls[mockSetParams.mock.calls.length - 1];
|
|
950
|
-
const urlParams = typeof call[0] === 'function' ? call[0](mockSearchParams) : call[0];
|
|
951
|
-
expect(urlParams.getAll('index')).toEqual(['hit', 'observable']);
|
|
952
|
-
});
|
|
953
|
-
});
|
|
954
|
-
it('should sync multiple indexes to URL as multiple index params', async () => {
|
|
955
|
-
const hook = renderHook(() => useContextSelector(ParameterContext, ctx => ({
|
|
956
|
-
addIndex: ctx.addIndex
|
|
957
|
-
})), { wrapper: Wrapper });
|
|
958
|
-
await act(async () => {
|
|
959
|
-
hook.result.current.addIndex('observable');
|
|
960
|
-
});
|
|
961
|
-
await waitFor(() => {
|
|
962
|
-
expect(mockSetParams).toHaveBeenCalled();
|
|
963
|
-
const call = mockSetParams.mock.calls[mockSetParams.mock.calls.length - 1];
|
|
964
|
-
const urlParams = typeof call[0] === 'function' ? call[0](mockSearchParams) : call[0];
|
|
965
|
-
expect(urlParams.getAll('index')).toEqual(['hit', 'observable']);
|
|
966
|
-
});
|
|
967
|
-
});
|
|
968
|
-
it('should remove all index params from URL when state resets to default', async () => {
|
|
969
|
-
mockSearchParams = new URLSearchParams();
|
|
970
|
-
mockSearchParams.append('index', 'hit');
|
|
971
|
-
mockSearchParams.append('index', 'observable');
|
|
972
|
-
const hook = renderHook(() => useContextSelector(ParameterContext, ctx => ({
|
|
973
|
-
resetIndexes: ctx.resetIndexes
|
|
974
|
-
})), { wrapper: Wrapper });
|
|
975
|
-
await act(async () => {
|
|
976
|
-
hook.result.current.resetIndexes();
|
|
977
|
-
});
|
|
978
|
-
await waitFor(() => {
|
|
979
|
-
expect(mockSetParams).toHaveBeenCalled();
|
|
980
|
-
const call = mockSetParams.mock.calls[mockSetParams.mock.calls.length - 1];
|
|
981
|
-
const urlParams = typeof call[0] === 'function' ? call[0](mockSearchParams) : call[0];
|
|
982
|
-
expect(urlParams.getAll('index')).toEqual([]);
|
|
983
|
-
});
|
|
984
|
-
});
|
|
985
|
-
it('should remove index param from URL when state returns to default', async () => {
|
|
986
|
-
mockSearchParams = new URLSearchParams({ index: 'observable' });
|
|
987
|
-
const hook = renderHook(() => useContextSelector(ParameterContext, ctx => ({
|
|
988
|
-
setIndexes: ctx.setIndexes
|
|
989
|
-
})), { wrapper: Wrapper });
|
|
990
|
-
await act(async () => {
|
|
991
|
-
hook.result.current.setIndexes(['hit']);
|
|
992
|
-
});
|
|
993
|
-
await waitFor(() => {
|
|
994
|
-
expect(mockSetParams).toHaveBeenCalled();
|
|
995
|
-
const call = mockSetParams.mock.calls[mockSetParams.mock.calls.length - 1];
|
|
996
|
-
const urlParams = typeof call[0] === 'function' ? call[0](mockSearchParams) : call[0];
|
|
997
|
-
expect(urlParams.getAll('index')).toEqual([]);
|
|
998
|
-
});
|
|
999
|
-
});
|
|
1000
|
-
});
|
|
1001
|
-
});
|
|
1002
709
|
describe('views (multi-view support)', () => {
|
|
1003
710
|
it('should initialize with empty array when no view params present', async () => {
|
|
1004
711
|
const hook = renderHook(() => useContextSelector(ParameterContext, ctx => ctx.views), { wrapper: Wrapper });
|
|
@@ -1132,17 +839,17 @@ describe('ParameterContext', () => {
|
|
|
1132
839
|
});
|
|
1133
840
|
});
|
|
1134
841
|
});
|
|
1135
|
-
describe('
|
|
842
|
+
describe('clearViews', () => {
|
|
1136
843
|
it('should clear all views', async () => {
|
|
1137
844
|
mockSearchParams = new URLSearchParams();
|
|
1138
845
|
mockSearchParams.append('view', 'view_1');
|
|
1139
846
|
mockSearchParams.append('view', 'view_2');
|
|
1140
847
|
const hook = renderHook(() => useContextSelector(ParameterContext, ctx => ({
|
|
1141
848
|
views: ctx.views,
|
|
1142
|
-
|
|
849
|
+
clearViews: ctx.clearViews
|
|
1143
850
|
})), { wrapper: Wrapper });
|
|
1144
851
|
await act(async () => {
|
|
1145
|
-
hook.result.current.
|
|
852
|
+
hook.result.current.clearViews();
|
|
1146
853
|
});
|
|
1147
854
|
await waitFor(() => {
|
|
1148
855
|
expect(hook.result.current.views).toEqual([]);
|
|
@@ -1151,10 +858,10 @@ describe('ParameterContext', () => {
|
|
|
1151
858
|
it('should be no-op when already empty', async () => {
|
|
1152
859
|
const hook = renderHook(() => useContextSelector(ParameterContext, ctx => ({
|
|
1153
860
|
views: ctx.views,
|
|
1154
|
-
|
|
861
|
+
clearViews: ctx.clearViews
|
|
1155
862
|
})), { wrapper: Wrapper });
|
|
1156
863
|
await act(async () => {
|
|
1157
|
-
hook.result.current.
|
|
864
|
+
hook.result.current.clearViews();
|
|
1158
865
|
});
|
|
1159
866
|
await waitFor(() => {
|
|
1160
867
|
expect(hook.result.current.views).toEqual([]);
|
|
@@ -1301,10 +1008,10 @@ describe('ParameterContext', () => {
|
|
|
1301
1008
|
mockSearchParams.append('view', 'view_1');
|
|
1302
1009
|
mockSearchParams.append('view', 'view_2');
|
|
1303
1010
|
const hook = renderHook(() => useContextSelector(ParameterContext, ctx => ({
|
|
1304
|
-
|
|
1011
|
+
clearViews: ctx.clearViews
|
|
1305
1012
|
})), { wrapper: Wrapper });
|
|
1306
1013
|
await act(async () => {
|
|
1307
|
-
hook.result.current.
|
|
1014
|
+
hook.result.current.clearViews();
|
|
1308
1015
|
});
|
|
1309
1016
|
await waitFor(() => {
|
|
1310
1017
|
expect(mockSetParams).toHaveBeenCalled();
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { type SliderProps } from '@mui/material';
|
|
1
2
|
type EditRowTypes<T extends string | number | boolean> = {
|
|
2
3
|
titleKey: string;
|
|
3
4
|
descriptionKey?: string;
|
|
@@ -8,7 +9,9 @@ type EditRowTypes<T extends string | number | boolean> = {
|
|
|
8
9
|
type?: 'password' | 'number' | 'text' | 'checkbox' | 'range';
|
|
9
10
|
min?: number;
|
|
10
11
|
max?: number;
|
|
12
|
+
step?: number;
|
|
11
13
|
optional?: boolean;
|
|
14
|
+
valueLabelFormat?: SliderProps['valueLabelFormat'];
|
|
12
15
|
};
|
|
13
|
-
declare const EditRow: <T extends string | number | boolean>({ titleKey, descriptionKey, value, onEdit, validate, failOnValidate, type, min, max, optional }: EditRowTypes<T>) => import("react/jsx-runtime").JSX.Element;
|
|
16
|
+
declare const EditRow: <T extends string | number | boolean>({ titleKey, descriptionKey, value, onEdit, validate, failOnValidate, type, min, max, step, valueLabelFormat, optional }: EditRowTypes<T>) => import("react/jsx-runtime").JSX.Element;
|
|
14
17
|
export default EditRow;
|
|
@@ -2,10 +2,10 @@ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-run
|
|
|
2
2
|
import { Check, Close, Delete, Edit } from '@mui/icons-material';
|
|
3
3
|
import { Box, Checkbox, CircularProgress, IconButton, Slider, Stack, TableCell, TableRow, TextField, Typography } from '@mui/material';
|
|
4
4
|
import useMySnackbar from '@cccsaurora/howler-ui/components/hooks/useMySnackbar';
|
|
5
|
-
import { isNull, isUndefined } from 'lodash-es';
|
|
5
|
+
import { isNil, isNull, isUndefined } from 'lodash-es';
|
|
6
6
|
import { useCallback, useEffect, useMemo, useState } from 'react';
|
|
7
7
|
import { useTranslation } from 'react-i18next';
|
|
8
|
-
const EditRow = ({ titleKey, descriptionKey, value, onEdit, validate, failOnValidate = false, type = 'text', min, max, optional }) => {
|
|
8
|
+
const EditRow = ({ titleKey, descriptionKey, value, onEdit, validate, failOnValidate = false, type = 'text', min, max, step, valueLabelFormat, optional }) => {
|
|
9
9
|
const { t } = useTranslation();
|
|
10
10
|
const { showErrorMessage } = useMySnackbar();
|
|
11
11
|
const [editing, setEditing] = useState(false);
|
|
@@ -102,7 +102,7 @@ const EditRow = ({ titleKey, descriptionKey, value, onEdit, validate, failOnVali
|
|
|
102
102
|
}
|
|
103
103
|
}, children: [!['checkbox', 'range'].includes(type) && (_jsx(TextField, { size: "small", value: editValue, onChange: ev => onChange(ev.target.value), onKeyDown: checkForActions, fullWidth: true, label: type === 'password' ? t('password') : null, type: type, error: error, sx: { '& input': { fontSize: '13.5px !important' } }, InputProps: {
|
|
104
104
|
endAdornment: loading && _jsx(CircularProgress, { size: 24 })
|
|
105
|
-
} })), type === 'checkbox' && (_jsx(Checkbox, { sx: { marginRight: 'auto' }, value: editValue, onChange: ev => onChange(ev.target.checked) })), type === 'range' && (_jsx(Slider, { min: min ?? 0, max: max ?? 100, step: Math.pow(10, Math.floor(Math.log10(max ?? 100) - Math.log10(Math.max(min ?? 0, 1)) / 2)), onChange: (__, val) => onChange(val), value: editValue, valueLabelDisplay: "auto", valueLabelFormat: val => `${val}px` })), type === 'password' && (_jsx(TextField, { size: "small", value: confirmPassword, onChange: ev => {
|
|
105
|
+
} })), type === 'checkbox' && (_jsx(Checkbox, { sx: { marginRight: 'auto' }, value: editValue, onChange: ev => onChange(ev.target.checked) })), type === 'range' && (_jsx(Slider, { min: min ?? 0, max: max ?? 100, step: step ?? Math.pow(10, Math.floor(Math.log10(max ?? 100) - Math.log10(Math.max(min ?? 0, 1)) / 2)), onChange: (__, val) => onChange(val), value: editValue, valueLabelDisplay: "auto", valueLabelFormat: valueLabelFormat ?? (val => `${val}px`) })), type === 'password' && (_jsx(TextField, { size: "small", value: confirmPassword, onChange: ev => {
|
|
106
106
|
setConfirmPassword(ev.target.value);
|
|
107
107
|
setError(false);
|
|
108
108
|
}, onKeyDown: checkForActions, fullWidth: true, label: t('password.confirm'), type: "password", error: error, sx: { '& input': { fontSize: '13.5px !important' } }, InputProps: {
|
|
@@ -110,6 +110,6 @@ const EditRow = ({ titleKey, descriptionKey, value, onEdit, validate, failOnVali
|
|
|
110
110
|
} }))] }), _jsx(IconButton, { onClick: onSubmit, disabled: loading, children: _jsx(Check, { fontSize: "small" }) }), _jsx(IconButton, { onClick: () => setEditing(false), disabled: loading, children: _jsx(Close, { fontSize: "small" }) }), optional && (_jsx(IconButton, { onClick: () => {
|
|
111
111
|
setEditing(false);
|
|
112
112
|
onEdit(null);
|
|
113
|
-
}, disabled: loading, children: _jsx(Delete, { fontSize: "small" }) }))] }) })) : (
|
|
113
|
+
}, disabled: loading, children: _jsx(Delete, { fontSize: "small" }) }))] }) })) : (_jsx(TableCell, { sx: cellSx, width: "100%", children: type === 'checkbox' ? (_jsx(Checkbox, { onChange: ev => onChange(ev.target.checked), checked: value.toString() === 'true' })) : type === 'range' && !isNil(value) ? ((valueLabelFormat ?? (val => `${val}px`))(value)) : ((value ?? t('none'))) })), onEdit && !editing && type !== 'checkbox' && (_jsx(TableCell, { sx: cellSx, align: "right", children: _jsx(IconButton, { onClick: () => setEditing(true), children: _jsx(Edit, { fontSize: "small" }) }) }))] }), descriptionKey && (_jsx(TableRow, { children: _jsx(TableCell, { colSpan: 3, sx: { paddingTop: '0 !important' }, children: _jsx(Typography, { variant: "caption", color: "text.secondary", children: t(descriptionKey) }) }) }))] }));
|
|
114
114
|
};
|
|
115
115
|
export default EditRow;
|
|
@@ -1,11 +1,10 @@
|
|
|
1
1
|
import { type TypographyProps } from '@mui/material';
|
|
2
2
|
import type { Hit } from '@cccsaurora/howler-ui/models/entities/generated/Hit';
|
|
3
|
-
import type { Observable } from '@cccsaurora/howler-ui/models/entities/generated/Observable';
|
|
4
3
|
export type PluginTypographyProps = TypographyProps & {
|
|
5
4
|
value: string;
|
|
6
5
|
context: string;
|
|
7
6
|
field?: string;
|
|
8
|
-
|
|
7
|
+
hit?: Hit;
|
|
9
8
|
};
|
|
10
9
|
declare const _default: import("react").NamedExoticComponent<PluginTypographyProps>;
|
|
11
10
|
export default _default;
|
|
@@ -3,7 +3,7 @@ import { Typography } from '@mui/material';
|
|
|
3
3
|
import howlerPluginStore from '@cccsaurora/howler-ui/plugins/store';
|
|
4
4
|
import { memo } from 'react';
|
|
5
5
|
import { usePluginStore } from 'react-pluggable';
|
|
6
|
-
const PluginTypography = ({ children, value, context, field,
|
|
6
|
+
const PluginTypography = ({ children, value, context, field, hit, ...props }) => {
|
|
7
7
|
const pluginStore = usePluginStore();
|
|
8
8
|
for (const plugin of howlerPluginStore.plugins) {
|
|
9
9
|
const component = pluginStore.executeFunction(`${plugin}.typography`, {
|
|
@@ -11,8 +11,7 @@ const PluginTypography = ({ children, value, context, field, obj, ...props }) =>
|
|
|
11
11
|
value,
|
|
12
12
|
context,
|
|
13
13
|
field,
|
|
14
|
-
hit
|
|
15
|
-
obj,
|
|
14
|
+
hit,
|
|
16
15
|
...props
|
|
17
16
|
});
|
|
18
17
|
if (component) {
|
|
@@ -2,11 +2,8 @@ import type { SxProps, Theme } from '@mui/material';
|
|
|
2
2
|
import type { FC } from 'react';
|
|
3
3
|
declare const UserList: FC<{
|
|
4
4
|
buttonSx?: SxProps<Theme>;
|
|
5
|
-
|
|
6
|
-
onChange: (
|
|
5
|
+
userId: string;
|
|
6
|
+
onChange: (userId: string) => void;
|
|
7
7
|
i18nLabel: string;
|
|
8
|
-
avatarHeight?: number;
|
|
9
|
-
disabled?: boolean;
|
|
10
|
-
multiple?: boolean;
|
|
11
8
|
}>;
|
|
12
9
|
export default UserList;
|
|
@@ -1,20 +1,18 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
|
-
import {
|
|
3
|
-
import { Autocomplete, AvatarGroup, Box, IconButton, Popover, Stack, TextField, Typography } from '@mui/material';
|
|
2
|
+
import { Autocomplete, Box, IconButton, Popover, TextField, Typography } from '@mui/material';
|
|
4
3
|
import { UserListContext } from '@cccsaurora/howler-ui/components/app/providers/UserListProvider';
|
|
5
|
-
import { uniq } from 'lodash-es';
|
|
6
4
|
import { useContext, useEffect, useMemo, useState } from 'react';
|
|
7
5
|
import { useTranslation } from 'react-i18next';
|
|
8
6
|
import HowlerAvatar from './display/HowlerAvatar';
|
|
9
|
-
const UserList = ({ buttonSx = {},
|
|
7
|
+
const UserList = ({ buttonSx = {}, userId, onChange, i18nLabel }) => {
|
|
10
8
|
const { t } = useTranslation();
|
|
11
9
|
const [anchorEl, setAnchorEl] = useState(null);
|
|
12
10
|
const { users, searchUsers } = useContext(UserListContext);
|
|
13
|
-
const
|
|
11
|
+
const userIds = useMemo(() => Object.keys(users), [users]);
|
|
14
12
|
useEffect(() => {
|
|
15
13
|
searchUsers('uname:*');
|
|
16
14
|
}, [searchUsers]);
|
|
17
|
-
return (_jsxs(_Fragment, { children: [
|
|
15
|
+
return (_jsxs(_Fragment, { children: [_jsx(IconButton, { sx: buttonSx, onClick: e => setAnchorEl(e.currentTarget), children: _jsx(HowlerAvatar, { userId: userId }) }), _jsx(Popover, { open: !!anchorEl, onClose: () => setAnchorEl(null), anchorEl: anchorEl, anchorOrigin: { vertical: 'bottom', horizontal: 'left' }, children: _jsx(Box, { sx: { p: 2 }, children: _jsx(Autocomplete, { sx: { minWidth: '300px' }, options: userIds, renderInput: params => _jsx(TextField, { ...params, label: t(i18nLabel), size: "small" }), renderOption: (props, _userId) => {
|
|
18
16
|
const user = users[_userId];
|
|
19
17
|
return (_jsx("li", { ...props, children: _jsxs(Box, { sx: {
|
|
20
18
|
display: 'grid',
|
|
@@ -23,13 +21,6 @@ const UserList = ({ buttonSx = {}, userIds, onChange, i18nLabel, avatarHeight =
|
|
|
23
21
|
gridTemplateAreas: `"profile name"\n"profile email"`,
|
|
24
22
|
columnGap: 1.5
|
|
25
23
|
}, children: [_jsx(HowlerAvatar, { sx: { gridArea: 'profile', alignSelf: 'center', height: '32px', width: '32px' }, userId: user.username }), _jsx(Typography, { sx: { gridArea: 'name' }, variant: "body1", children: user.name }), _jsx(Typography, { sx: { gridArea: 'email' }, variant: "caption", children: user.email })] }) }));
|
|
26
|
-
}, value:
|
|
27
|
-
if (multiple) {
|
|
28
|
-
onChange(Array.isArray(options) ? options : [options]);
|
|
29
|
-
}
|
|
30
|
-
else {
|
|
31
|
-
onChange([Array.isArray(options) ? (options[0] ?? null) : options]);
|
|
32
|
-
}
|
|
33
|
-
} }) }) })] }));
|
|
24
|
+
}, value: userId, onChange: (__, option) => onChange(option) }) }) })] }));
|
|
34
25
|
};
|
|
35
26
|
export default UserList;
|
|
@@ -80,7 +80,7 @@ const Phrase = ({ value = '', variant = 'outlined', suggestions = [], lexer, sug
|
|
|
80
80
|
onSelectCapture: _onSelectCapture,
|
|
81
81
|
startAdornment: startAdornment && _jsx(InputAdornment, { position: "start", children: startAdornment }),
|
|
82
82
|
endAdornment: endAdornment && _jsx(InputAdornment, { position: "end", children: endAdornment })
|
|
83
|
-
} }), _jsx(Popper, { anchorEl: containerRef.current, style: { width: '100%', zIndex: 100 }, open: optionsOpen && (options.length > 0 || (debug && analysisRef.current?.tokens.length > 0)), disablePortal: true, children: _jsx(Paper, { elevation:
|
|
83
|
+
} }), _jsx(Popper, { anchorEl: containerRef.current, style: { width: '100%', zIndex: 100 }, open: optionsOpen && (options.length > 0 || (debug && analysisRef.current?.tokens.length > 0)), disablePortal: true, children: _jsx(Paper, { elevation: 2, sx: { maxHeight: 200, overflow: 'auto', borderTopRightRadius: 0, borderTopLeftRadius: 0 }, children: _jsx(MenuList, { ref: menuRef, onKeyDown: _onMenuKeyDown, sx: {
|
|
84
84
|
'&:focus': {
|
|
85
85
|
outline: 'none'
|
|
86
86
|
}
|
|
@@ -15,8 +15,8 @@ interface ChipPopperProps {
|
|
|
15
15
|
onToggle?: (show: boolean) => void;
|
|
16
16
|
onDelete?: (event?: any) => void;
|
|
17
17
|
toggleOnDelete?: boolean;
|
|
18
|
-
disablePortal?: boolean;
|
|
19
18
|
closeOnClick?: boolean;
|
|
19
|
+
disablePortal?: boolean;
|
|
20
20
|
}
|
|
21
21
|
declare const _default: import("react").NamedExoticComponent<ChipPopperProps>;
|
|
22
22
|
export default _default;
|
|
@@ -21,7 +21,7 @@ const ChipPopper = ({ icon, deleteIcon, label, children, minWidth, placement = '
|
|
|
21
21
|
...(Array.isArray(slotProps.chip?.sx) ? slotProps.chip.sx : [slotProps.chip?.sx])
|
|
22
22
|
], ...(slotProps.chip ?? {}) }), _jsx(Popper, { placement: placement, anchorEl: anchorEl.current, disablePortal: disablePortal, open: true, sx: {
|
|
23
23
|
minWidth: Math.max(typeof minWidth === 'number' ? minWidth : parseInt(minWidth?.replace('px', '')) || 0, anchorEl.current?.clientWidth || 0),
|
|
24
|
-
zIndex:
|
|
24
|
+
zIndex: 1000
|
|
25
25
|
}, children: _jsx(Collapse, { in: show, unmountOnExit: true, onClick: () => {
|
|
26
26
|
if (closeOnClick) {
|
|
27
27
|
handleToggle(false);
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
2
|
import { Card } from '@mui/material';
|
|
3
3
|
import { memo } from 'react';
|
|
4
|
-
const HowlerCard = props => _jsx(Card, { elevation: props.variant !== 'outlined' ?
|
|
4
|
+
const HowlerCard = props => (_jsx(Card, { style: { outline: 'none' }, elevation: props.variant !== 'outlined' ? 4 : 0, ...props }));
|
|
5
5
|
export default memo(HowlerCard);
|
|
@@ -15,7 +15,6 @@ const Modal = () => {
|
|
|
15
15
|
left: '50%',
|
|
16
16
|
maxWidth: options.maxWidth || '1200px',
|
|
17
17
|
maxHeight: options.maxHeight || '400px',
|
|
18
|
-
height: '100%',
|
|
19
18
|
transform: 'translate(-50%, -50%)',
|
|
20
19
|
backgroundColor: 'background.paper',
|
|
21
20
|
borderRadius: theme.shape.borderRadius,
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { AccountTree } from '@mui/icons-material';
|
|
3
|
+
import { ListItemText, Menu, MenuItem, Typography } from '@mui/material';
|
|
4
|
+
import TuiIconButton from '@cccsaurora/howler-ui/components/elements/addons/buttons/CustomIconButton';
|
|
5
|
+
import { useCallback, useState } from 'react';
|
|
6
|
+
import { useTranslation } from 'react-i18next';
|
|
7
|
+
import { useNavigate } from 'react-router-dom';
|
|
8
|
+
const BundleButton = ({ ids, disabled = false }) => {
|
|
9
|
+
const { t } = useTranslation();
|
|
10
|
+
const navigate = useNavigate();
|
|
11
|
+
const [anchorEl, setAnchorEl] = useState(null);
|
|
12
|
+
const onClick = useCallback((event) => {
|
|
13
|
+
if (ids.length === 1) {
|
|
14
|
+
navigate(`/bundles/${ids[0]}`);
|
|
15
|
+
}
|
|
16
|
+
else {
|
|
17
|
+
setAnchorEl(event.currentTarget);
|
|
18
|
+
}
|
|
19
|
+
}, [ids, navigate]);
|
|
20
|
+
const handleClose = useCallback(() => setAnchorEl(null), []);
|
|
21
|
+
return (_jsxs(_Fragment, { children: [_jsx(TuiIconButton, { size: "small", tooltip: t(`hit.panel.bundles.open${ids.length > 1 ? '' : '.prompt'}`), onClick: onClick, disabled: disabled, "aria-disabled": disabled, "aria-haspopup": "true", "aria-controls": anchorEl ? 'bundle-action-menu' : undefined, "aria-expanded": anchorEl ? 'true' : undefined, children: _jsx(AccountTree, {}) }), _jsx(Menu, { id: "bundle-action-menu", anchorEl: anchorEl, open: !!anchorEl, onClose: handleClose, MenuListProps: {
|
|
22
|
+
dense: true,
|
|
23
|
+
'aria-labelledby': `bundle-button`
|
|
24
|
+
}, anchorOrigin: {
|
|
25
|
+
vertical: 'bottom',
|
|
26
|
+
horizontal: 'right'
|
|
27
|
+
}, transformOrigin: {
|
|
28
|
+
vertical: 'top',
|
|
29
|
+
horizontal: 'right'
|
|
30
|
+
}, children: ids.map(id => (_jsx(MenuItem, { onClick: () => navigate(`/bundles/${id}`), children: _jsx(ListItemText, { primary: t('hit.panel.bundles.open.prompt'), secondary: _jsx(Typography, { variant: "caption", color: "text.secondary", children: id }) }) }, id))) })] }));
|
|
31
|
+
};
|
|
32
|
+
export default BundleButton;
|