@cccsaurora/howler-ui 3.1.0-dev.1649 → 3.1.0-dev.1656
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.
|
@@ -14,7 +14,7 @@ import useMyApi from '@cccsaurora/howler-ui/components/hooks/useMyApi';
|
|
|
14
14
|
import useMyActionFunctions from '@cccsaurora/howler-ui/components/routes/action/useMyActionFunctions';
|
|
15
15
|
import AddRecordToCaseModal from '@cccsaurora/howler-ui/components/routes/cases/modals/AddRecordToCaseModal';
|
|
16
16
|
import CreateCaseModal from '@cccsaurora/howler-ui/components/routes/cases/modals/CreateCaseModal';
|
|
17
|
-
import { capitalize, get, groupBy, isEmpty, toString } from 'lodash-es';
|
|
17
|
+
import { capitalize, get, groupBy, isEmpty, toString, uniq } from 'lodash-es';
|
|
18
18
|
import howlerPluginStore from '@cccsaurora/howler-ui/plugins/store';
|
|
19
19
|
import React, { useCallback, useContext, useEffect, useMemo, useState } from 'react';
|
|
20
20
|
import { useTranslation } from 'react-i18next';
|
|
@@ -188,14 +188,18 @@ const RecordContextMenu = ({ children, getSelectedId, Component }) => {
|
|
|
188
188
|
onClick: () => executeAction(action.action_id, `howler.id:(${records.map(r => r.howler.id).join(' OR ')})`)
|
|
189
189
|
}))
|
|
190
190
|
});
|
|
191
|
-
|
|
191
|
+
const filterKeys = uniq([
|
|
192
|
+
...(template?.keys ?? []),
|
|
193
|
+
...Object.keys(record.howler.outline ?? {}).map(key => `howler.outline.${key}`)
|
|
194
|
+
]);
|
|
195
|
+
if (!isEmpty(filterKeys) && setQuery) {
|
|
192
196
|
result.push({ kind: 'divider', id: 'filter-divider' });
|
|
193
197
|
result.push({
|
|
194
198
|
kind: 'submenu',
|
|
195
199
|
id: 'excludes',
|
|
196
200
|
icon: _jsx(RemoveCircleOutline, {}),
|
|
197
201
|
label: t('hit.panel.exclude'),
|
|
198
|
-
items:
|
|
202
|
+
items: filterKeys.flatMap(key => {
|
|
199
203
|
let newQuery = '';
|
|
200
204
|
if (query !== DEFAULT_QUERY) {
|
|
201
205
|
newQuery = `(${query}) AND `;
|
|
@@ -225,7 +229,7 @@ const RecordContextMenu = ({ children, getSelectedId, Component }) => {
|
|
|
225
229
|
id: 'includes',
|
|
226
230
|
icon: _jsx(AddCircleOutline, {}),
|
|
227
231
|
label: t('hit.panel.include'),
|
|
228
|
-
items:
|
|
232
|
+
items: filterKeys.flatMap(key => {
|
|
229
233
|
let newQuery = `(${query}) AND `;
|
|
230
234
|
const value = get(record, key);
|
|
231
235
|
if (!value) {
|
|
@@ -648,7 +648,7 @@ describe('HitContextMenu', () => {
|
|
|
648
648
|
expect(mockParameterContext.setQuery).toHaveBeenCalledWith('(howler.status:open) AND -howler.detection:"Test Detection"');
|
|
649
649
|
});
|
|
650
650
|
});
|
|
651
|
-
it('should
|
|
651
|
+
it('should render outline fields in the exclusion menu when template has no keys', async () => {
|
|
652
652
|
mockGetMatchingTemplate.mockResolvedValue(createMockTemplate({
|
|
653
653
|
keys: []
|
|
654
654
|
}));
|
|
@@ -660,7 +660,13 @@ describe('HitContextMenu', () => {
|
|
|
660
660
|
await waitFor(() => {
|
|
661
661
|
expect(screen.getByRole('menu')).toBeInTheDocument();
|
|
662
662
|
});
|
|
663
|
-
expect(screen.
|
|
663
|
+
expect(screen.getByText('Exclude By')).toBeInTheDocument();
|
|
664
|
+
act(() => {
|
|
665
|
+
fireEvent.mouseEnter(screen.getByText('Exclude By'));
|
|
666
|
+
});
|
|
667
|
+
await waitFor(() => {
|
|
668
|
+
expect(screen.getByTestId('excludes-submenu').textContent).toContain('howler.outline.indicators');
|
|
669
|
+
});
|
|
664
670
|
});
|
|
665
671
|
it('should skip null field values in exclusion menu', async () => {
|
|
666
672
|
act(() => {
|
|
@@ -777,7 +783,7 @@ describe('HitContextMenu', () => {
|
|
|
777
783
|
expect(mockParameterContext.setQuery).toHaveBeenCalledWith('(howler.status:open) AND howler.detection:"Test Detection"');
|
|
778
784
|
});
|
|
779
785
|
});
|
|
780
|
-
it('should
|
|
786
|
+
it('should render outline fields in the inclusion menu when template has no keys', async () => {
|
|
781
787
|
mockGetMatchingTemplate.mockResolvedValue(createMockTemplate({
|
|
782
788
|
keys: []
|
|
783
789
|
}));
|
|
@@ -789,7 +795,16 @@ describe('HitContextMenu', () => {
|
|
|
789
795
|
await waitFor(() => {
|
|
790
796
|
expect(screen.getByRole('menu')).toBeInTheDocument();
|
|
791
797
|
});
|
|
792
|
-
|
|
798
|
+
act(() => {
|
|
799
|
+
fireEvent.mouseEnter(screen.getByText('Include By'));
|
|
800
|
+
});
|
|
801
|
+
await waitFor(() => {
|
|
802
|
+
expect(screen.getByTestId('includes-submenu').textContent).toContain('howler.outline.indicators');
|
|
803
|
+
});
|
|
804
|
+
await act(async () => {
|
|
805
|
+
await user.click(screen.getByText('howler.outline.indicators'));
|
|
806
|
+
});
|
|
807
|
+
expect(mockParameterContext.setQuery).toHaveBeenCalledWith(expect.stringContaining('howler.outline.indicators:("a" OR "b" OR "c")'));
|
|
793
808
|
});
|
|
794
809
|
it('should skip null field values in inclusion menu', async () => {
|
|
795
810
|
act(() => {
|
|
@@ -895,7 +910,7 @@ describe('HitContextMenu', () => {
|
|
|
895
910
|
});
|
|
896
911
|
expect(screen.queryByRole('menu')).toBeInTheDocument();
|
|
897
912
|
});
|
|
898
|
-
it('should
|
|
913
|
+
it('should render exclusion menu for outline fields when template is null', async () => {
|
|
899
914
|
mockGetMatchingTemplate.mockResolvedValue(null);
|
|
900
915
|
rerender(_jsx(Wrapper, { children: _jsx(RecordContextMenu, { getSelectedId: mockGetSelectedId, children: _jsx("div", { children: "Test Content" }) }) }));
|
|
901
916
|
act(() => {
|
|
@@ -905,11 +920,9 @@ describe('HitContextMenu', () => {
|
|
|
905
920
|
await waitFor(() => {
|
|
906
921
|
expect(screen.getByRole('menu')).toBeInTheDocument();
|
|
907
922
|
});
|
|
908
|
-
|
|
909
|
-
expect(screen.queryByText('Exclude By')).toBeNull();
|
|
910
|
-
});
|
|
923
|
+
expect(screen.getByText('Exclude By')).toBeInTheDocument();
|
|
911
924
|
});
|
|
912
|
-
it('should
|
|
925
|
+
it('should render inclusion menu for outline fields when template is null', async () => {
|
|
913
926
|
mockGetMatchingTemplate.mockResolvedValue(null);
|
|
914
927
|
rerender(_jsx(Wrapper, { children: _jsx(RecordContextMenu, { getSelectedId: mockGetSelectedId, children: _jsx("div", { children: "Test Content" }) }) }));
|
|
915
928
|
act(() => {
|
|
@@ -919,9 +932,7 @@ describe('HitContextMenu', () => {
|
|
|
919
932
|
await waitFor(() => {
|
|
920
933
|
expect(screen.getByRole('menu')).toBeInTheDocument();
|
|
921
934
|
});
|
|
922
|
-
|
|
923
|
-
expect(screen.queryByText('Include By')).toBeNull();
|
|
924
|
-
});
|
|
935
|
+
expect(screen.getByText('Include By')).toBeInTheDocument();
|
|
925
936
|
});
|
|
926
937
|
it('should handle API failure gracefully', async () => {
|
|
927
938
|
mockDispatchApi.mockResolvedValue(null);
|