@cccsaurora/howler-ui 2.19.0-cases.1065 → 2.19.0-cases.1097

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.
Files changed (92) hide show
  1. package/api/v2/search/index.d.ts +2 -1
  2. package/api/v2/search/index.js +2 -2
  3. package/components/app/providers/ParameterProvider.d.ts +1 -1
  4. package/components/app/providers/ParameterProvider.test.js +25 -25
  5. package/components/app/providers/RecordProvider.d.ts +6 -6
  6. package/components/app/providers/RecordProvider.js +5 -1
  7. package/components/app/providers/RecordSearchProvider.d.ts +2 -2
  8. package/components/elements/ObjectDetails.d.ts +2 -2
  9. package/components/elements/PluginTypography.d.ts +2 -2
  10. package/components/elements/event/EventCard.d.ts +6 -0
  11. package/components/elements/{observable/ObservableCard.js → event/EventCard.js} +7 -7
  12. package/components/elements/{observable/ObservablePreview.d.ts → event/EventPreview.d.ts} +2 -2
  13. package/components/elements/event/EventPreview.js +12 -0
  14. package/components/elements/hit/HitCard.d.ts +2 -0
  15. package/components/elements/hit/HitCard.js +2 -2
  16. package/components/elements/hit/HitSummary.d.ts +2 -2
  17. package/components/elements/hit/related/RelatedRecords.js +4 -4
  18. package/components/elements/record/RecordComments.d.ts +2 -2
  19. package/components/elements/record/RecordRelated.d.ts +2 -2
  20. package/components/elements/record/RecordRelated.js +4 -4
  21. package/components/elements/record/RecordWorklog.d.ts +2 -2
  22. package/components/hooks/useRelatedRecords.d.ts +3 -3
  23. package/components/hooks/useRelatedRecords.js +2 -2
  24. package/components/routes/cases/detail/AlertPanel.test.d.ts +1 -0
  25. package/components/routes/cases/detail/AlertPanel.test.js +110 -0
  26. package/components/routes/cases/detail/CaseAssets.d.ts +2 -2
  27. package/components/routes/cases/detail/CaseAssets.js +2 -2
  28. package/components/routes/cases/detail/CaseAssets.test.js +4 -4
  29. package/components/routes/cases/detail/CaseDashboard.js +2 -2
  30. package/components/routes/cases/detail/CaseDashboard.test.d.ts +1 -0
  31. package/components/routes/cases/detail/CaseDashboard.test.js +218 -0
  32. package/components/routes/cases/detail/CaseRules.test.js +2 -2
  33. package/components/routes/cases/detail/CaseTimeline.js +5 -5
  34. package/components/routes/cases/detail/CaseTimeline.test.js +7 -7
  35. package/components/routes/cases/detail/CreateRuleDialog.js +4 -4
  36. package/components/routes/cases/detail/CreateRuleDialog.test.js +5 -5
  37. package/components/routes/cases/detail/ItemPage.js +1 -1
  38. package/components/routes/cases/detail/aggregates/CaseAggregate.d.ts +2 -2
  39. package/components/routes/cases/detail/assets/Asset.d.ts +1 -1
  40. package/components/routes/cases/detail/assets/Asset.test.js +2 -2
  41. package/components/routes/cases/detail/sidebar/CaseFolderContextMenu.d.ts +1 -1
  42. package/components/routes/cases/detail/sidebar/CaseFolderContextMenu.js +3 -3
  43. package/components/routes/cases/detail/sidebar/CaseFolderContextMenu.test.js +8 -8
  44. package/components/routes/cases/detail/sidebar/FolderEntry.js +1 -1
  45. package/components/routes/cases/modals/AddToCaseModal.d.ts +2 -2
  46. package/components/routes/cases/modals/AddToCaseModal.test.js +11 -11
  47. package/components/routes/cases/modals/CaseRecordRow.js +1 -1
  48. package/components/routes/cases/modals/CreateCaseModal.d.ts +2 -2
  49. package/components/routes/cases/modals/CreateCaseModal.test.js +14 -14
  50. package/components/routes/cases/modals/hooks.d.ts +3 -3
  51. package/components/routes/cases/modals/hooks.js +1 -1
  52. package/components/routes/cases/modals/types.d.ts +4 -1
  53. package/components/routes/events/EventViewer.d.ts +7 -0
  54. package/components/routes/events/EventViewer.js +27 -0
  55. package/components/routes/hits/search/SearchPane.js +3 -3
  56. package/components/routes/hits/search/grid/EnhancedCell.d.ts +2 -2
  57. package/components/routes/hits/search/grid/RecordRow.d.ts +3 -3
  58. package/components/routes/hits/search/grid/RecordRow.js +2 -2
  59. package/components/routes/hits/search/shared/IndexPicker.js +1 -1
  60. package/components/routes/home/ViewCard.js +4 -4
  61. package/components/routes/views/ViewComposer.js +2 -2
  62. package/locales/en/translation.json +4 -4
  63. package/locales/fr/translation.json +4 -4
  64. package/models/entities/generated/ECSEvent.d.ts +31 -0
  65. package/models/entities/generated/Event.d.ts +80 -26
  66. package/models/entities/generated/{ObservableCloud.d.ts → EventCloud.d.ts} +1 -1
  67. package/models/entities/generated/{ObservableDestination.d.ts → EventDestination.d.ts} +1 -1
  68. package/models/entities/generated/{ObservableEmail.d.ts → EventEmail.d.ts} +1 -1
  69. package/models/entities/generated/{ObservableFile.d.ts → EventFile.d.ts} +1 -1
  70. package/models/entities/generated/{ObservableHowler.d.ts → EventHowler.d.ts} +1 -1
  71. package/models/entities/generated/{ObservableHttp.d.ts → EventHttp.d.ts} +1 -1
  72. package/models/entities/generated/{ObservableObserver.d.ts → EventObserver.d.ts} +1 -1
  73. package/models/entities/generated/{ObservableOrganization.d.ts → EventOrganization.d.ts} +1 -1
  74. package/models/entities/generated/{ObservableProcess.d.ts → EventProcess.d.ts} +1 -1
  75. package/models/entities/generated/{ObservableSource.d.ts → EventSource.d.ts} +1 -1
  76. package/models/entities/generated/{ObservableThreat.d.ts → EventThreat.d.ts} +1 -1
  77. package/models/entities/generated/{ObservableTls.d.ts → EventTls.d.ts} +1 -1
  78. package/models/entities/generated/Hit.d.ts +2 -2
  79. package/models/entities/generated/Rule.d.ts +1 -1
  80. package/package.json +3 -3
  81. package/plugins/clue/utils.d.ts +2 -2
  82. package/tests/server-handlers.js +1 -1
  83. package/tests/utils.d.ts +2 -2
  84. package/tests/utils.js +3 -3
  85. package/utils/hitFunctions.d.ts +2 -2
  86. package/utils/typeUtils.d.ts +2 -2
  87. package/utils/typeUtils.js +2 -2
  88. package/components/elements/observable/ObservableCard.d.ts +0 -6
  89. package/components/elements/observable/ObservablePreview.js +0 -12
  90. package/components/routes/observables/ObservableViewer.d.ts +0 -7
  91. package/components/routes/observables/ObservableViewer.js +0 -27
  92. package/models/entities/generated/Observable.d.ts +0 -85
@@ -49,13 +49,13 @@ describe('Asset', () => {
49
49
  const _case = createMockCase({
50
50
  items: [
51
51
  { path: 'alerts/my-analytic (hit-001)', type: 'hit', value: 'hit-001' },
52
- { path: 'observables/obs-002', type: 'observable', value: 'obs-002' },
52
+ { path: 'events/obs-002', type: 'event', value: 'obs-002' },
53
53
  { path: 'alerts/other-analytic (hit-003)', type: 'hit', value: 'hit-003' }
54
54
  ]
55
55
  });
56
56
  render(_jsx(MemoryRouter, { children: _jsx(Asset, { asset: makeAsset({ seenIn: ['hit-001', 'obs-002', 'hit-003'] }), case: _case }) }));
57
57
  expect(screen.getByText('alerts/my-analytic (hit-001)')).toBeTruthy();
58
- expect(screen.getByText('observables/obs-002')).toBeTruthy();
58
+ expect(screen.getByText('events/obs-002')).toBeTruthy();
59
59
  expect(screen.getByText('alerts/other-analytic (hit-003)')).toBeTruthy();
60
60
  });
61
61
  it('links each chip to /cases/:case_id/:path', () => {
@@ -10,7 +10,7 @@ export declare const collectAllLeaves: (tree: Tree) => Item[];
10
10
  * Returns the URL to open for a given leaf item, or null if no URL applies.
11
11
  * - reference: the item's value (an external URL)
12
12
  * - hit: /hits/<id>
13
- * - observable: /observables/<id>
13
+ * - event: /events/<id>
14
14
  * - case: /cases/<id>
15
15
  * - table / lead: null (no dedicated detail page)
16
16
  */
@@ -21,7 +21,7 @@ export const collectAllLeaves = (tree) => {
21
21
  * Returns the URL to open for a given leaf item, or null if no URL applies.
22
22
  * - reference: the item's value (an external URL)
23
23
  * - hit: /hits/<id>
24
- * - observable: /observables/<id>
24
+ * - event: /events/<id>
25
25
  * - case: /cases/<id>
26
26
  * - table / lead: null (no dedicated detail page)
27
27
  */
@@ -33,8 +33,8 @@ export const getOpenUrl = (leaf) => {
33
33
  if (type === 'hit') {
34
34
  return leaf.value ? `/hits/${leaf.value}` : null;
35
35
  }
36
- if (type === 'observable') {
37
- return leaf.value ? `/observables/${leaf.value}` : null;
36
+ if (type === 'event') {
37
+ return leaf.value ? `/events/${leaf.value}` : null;
38
38
  }
39
39
  if (type === 'case') {
40
40
  return leaf.value ? `/cases/${leaf.value}` : null;
@@ -54,7 +54,7 @@ import CaseFolderContextMenu, { collectAllLeaves, getOpenUrl } from './CaseFolde
54
54
  const mockCase = { case_id: 'case-1', title: 'Test Case', items: [] };
55
55
  const hitLeaf = { type: 'hit', value: 'hit-123', path: 'folder/hit-item' };
56
56
  const referenceLeaf = { type: 'reference', value: 'https://example.com', path: 'folder/ref-item' };
57
- const observableLeaf = { type: 'observable', value: 'obs-456', path: 'folder/obs-item' };
57
+ const eventLeaf = { type: 'event', value: 'obs-456', path: 'folder/event-item' };
58
58
  const caseLeaf = { type: 'case', value: 'nested-case-id', path: 'folder/case-item' };
59
59
  const tableLeaf = { type: 'table', value: 'table-789', path: 'folder/table-item' };
60
60
  const leadLeaf = { type: 'lead', value: 'lead-999', path: 'folder/lead-item' };
@@ -119,8 +119,8 @@ describe('getOpenUrl', () => {
119
119
  it('returns /hits/<id> for a hit item', () => {
120
120
  expect(getOpenUrl(hitLeaf)).toBe('/hits/hit-123');
121
121
  });
122
- it('returns /observables/<id> for an observable item', () => {
123
- expect(getOpenUrl(observableLeaf)).toBe('/observables/obs-456');
122
+ it('returns /events/<id> for an event item', () => {
123
+ expect(getOpenUrl(eventLeaf)).toBe('/events/obs-456');
124
124
  });
125
125
  it('returns /cases/<id> for a case item', () => {
126
126
  expect(getOpenUrl(caseLeaf)).toBe('/cases/nested-case-id');
@@ -159,8 +159,8 @@ describe('CaseFolderContextMenu', () => {
159
159
  expect(screen.getByTestId('open-item')).toBeInTheDocument();
160
160
  expect(screen.getByTestId('remove-item')).toBeInTheDocument();
161
161
  });
162
- it('shows "Open item" and "Remove item" for an observable leaf', () => {
163
- renderMenu({ leaf: observableLeaf });
162
+ it('shows "Open item" and "Remove item" for an event leaf', () => {
163
+ renderMenu({ leaf: eventLeaf });
164
164
  expect(screen.getByTestId('open-item')).toBeInTheDocument();
165
165
  expect(screen.getByTestId('remove-item')).toBeInTheDocument();
166
166
  });
@@ -219,12 +219,12 @@ describe('CaseFolderContextMenu', () => {
219
219
  });
220
220
  expect(window.open).toHaveBeenCalledWith('https://example.com', '_blank', 'noopener noreferrer');
221
221
  });
222
- it('calls window.open with the observable URL', () => {
223
- renderMenu({ leaf: observableLeaf });
222
+ it('calls window.open with the event URL', () => {
223
+ renderMenu({ leaf: eventLeaf });
224
224
  act(() => {
225
225
  fireEvent.click(screen.getByTestId('open-item'));
226
226
  });
227
- expect(window.open).toHaveBeenCalledWith('/observables/obs-456', '_blank', 'noopener noreferrer');
227
+ expect(window.open).toHaveBeenCalledWith('/events/obs-456', '_blank', 'noopener noreferrer');
228
228
  });
229
229
  it('calls window.open with the case URL', () => {
230
230
  renderMenu({ leaf: caseLeaf });
@@ -9,7 +9,7 @@ import { Link, useLocation } from 'react-router-dom';
9
9
  const ICON_FOR_TYPE = {
10
10
  folder: Folder,
11
11
  case: BookRounded,
12
- observable: Visibility,
12
+ event: Visibility,
13
13
  hit: CheckCircle,
14
14
  table: TableChart,
15
15
  lead: Lightbulb,
@@ -1,7 +1,7 @@
1
+ import type { Event } from '@cccsaurora/howler-ui/models/entities/generated/Event';
1
2
  import type { Hit } from '@cccsaurora/howler-ui/models/entities/generated/Hit';
2
- import type { Observable } from '@cccsaurora/howler-ui/models/entities/generated/Observable';
3
3
  import { type FC } from 'react';
4
4
  declare const AddToCaseModal: FC<{
5
- records: (Hit | Observable)[];
5
+ records: (Hit | Event)[];
6
6
  }>;
7
7
  export default AddToCaseModal;
@@ -5,7 +5,7 @@ import userEvent, {} from '@testing-library/user-event';
5
5
  import { ModalContext } from '@cccsaurora/howler-ui/components/app/providers/ModalProvider';
6
6
  import i18n from '@cccsaurora/howler-ui/i18n';
7
7
  import { I18nextProvider } from 'react-i18next';
8
- import { createMockCase, createMockHit, createMockObservable } from '@cccsaurora/howler-ui/tests/utils';
8
+ import { createMockCase, createMockEvent, createMockHit } from '@cccsaurora/howler-ui/tests/utils';
9
9
  import { beforeEach, describe, expect, it, vi } from 'vitest';
10
10
  import AddToCaseModal from './AddToCaseModal';
11
11
  // ---------------------------------------------------------------------------
@@ -49,7 +49,7 @@ const MOCK_HIT_1 = createMockHit({
49
49
  const MOCK_HIT_2 = createMockHit({
50
50
  howler: { id: 'hit-002', analytic: 'AnalyticTwo', status: 'open' }
51
51
  });
52
- const MOCK_OBSERVABLE = createMockObservable({
52
+ const MOCK_EVENT = createMockEvent({
53
53
  howler: { id: 'obs-001' }
54
54
  });
55
55
  // ---------------------------------------------------------------------------
@@ -114,12 +114,12 @@ describe('AddToCaseModal', () => {
114
114
  const titleInput = screen.getByPlaceholderText(i18n.t('modal.cases.add_to_case.title'));
115
115
  expect(titleInput).toHaveValue(`${MOCK_HIT_1.howler.analytic} (${MOCK_HIT_1.howler.id})`);
116
116
  });
117
- it('pre-populates title for an observable with Observable and id', async () => {
118
- renderModal([MOCK_OBSERVABLE]);
117
+ it('pre-populates title for an event with Event and id', async () => {
118
+ renderModal([MOCK_EVENT]);
119
119
  await waitFor(() => expect(mockDispatchApi).toHaveBeenCalled());
120
120
  await selectCase(user, 'Case Alpha');
121
121
  const titleInput = screen.getByPlaceholderText(i18n.t('modal.cases.add_to_case.title'));
122
- expect(titleInput).toHaveValue(`Observable (${MOCK_OBSERVABLE.howler.id})`);
122
+ expect(titleInput).toHaveValue(`Event (${MOCK_EVENT.howler.id})`);
123
123
  });
124
124
  it('title input is editable', async () => {
125
125
  renderModal([MOCK_HIT_1]);
@@ -161,13 +161,13 @@ describe('AddToCaseModal', () => {
161
161
  expect(titleInputs[0]).toHaveValue('Edited');
162
162
  expect(titleInputs[1]).toHaveValue(`${MOCK_HIT_2.howler.analytic} (${MOCK_HIT_2.howler.id})`);
163
163
  });
164
- it('mixed hit and observable records each get correct default titles', async () => {
165
- renderModal([MOCK_HIT_1, MOCK_OBSERVABLE]);
164
+ it('mixed hit and event records each get correct default titles', async () => {
165
+ renderModal([MOCK_HIT_1, MOCK_EVENT]);
166
166
  await waitFor(() => expect(mockDispatchApi).toHaveBeenCalled());
167
167
  await selectCase(user, 'Case Alpha');
168
168
  const titleInputs = screen.getAllByPlaceholderText(i18n.t('modal.cases.add_to_case.title'));
169
169
  expect(titleInputs[0]).toHaveValue(`${MOCK_HIT_1.howler.analytic} (${MOCK_HIT_1.howler.id})`);
170
- expect(titleInputs[1]).toHaveValue(`Observable (${MOCK_OBSERVABLE.howler.id})`);
170
+ expect(titleInputs[1]).toHaveValue(`Event (${MOCK_EVENT.howler.id})`);
171
171
  });
172
172
  });
173
173
  // -------------------------------------------------------------------------
@@ -260,14 +260,14 @@ describe('AddToCaseModal', () => {
260
260
  path: `investigations/${MOCK_HIT_1.howler.analytic} (${MOCK_HIT_1.howler.id})`
261
261
  }));
262
262
  });
263
- it('uses observable __index for observable records', async () => {
263
+ it('uses event __index for event records', async () => {
264
264
  const api = (await import('api')).default;
265
- renderModal([MOCK_OBSERVABLE]);
265
+ renderModal([MOCK_EVENT]);
266
266
  await waitFor(() => expect(mockDispatchApi).toHaveBeenCalled());
267
267
  await selectCase(user, 'Case Alpha');
268
268
  await user.click(screen.getByRole('button', { name: i18n.t('confirm') }));
269
269
  await waitFor(() => expect(mockClose).toHaveBeenCalled());
270
- expect(api.v2.case.items.post).toHaveBeenCalledWith('case-a', expect.objectContaining({ type: 'observable' }));
270
+ expect(api.v2.case.items.post).toHaveBeenCalledWith('case-a', expect.objectContaining({ type: 'event' }));
271
271
  });
272
272
  });
273
273
  // -------------------------------------------------------------------------
@@ -10,6 +10,6 @@ const CaseRecordRow = ({ entry, folderOptions = [], onTitleChange, onPathChange
10
10
  const { record, path, title } = entry;
11
11
  const fullPath = path ? `${path}/${title}` : title;
12
12
  const pathError = path.startsWith('/') || path.endsWith('/');
13
- return (_jsxs(Accordion, { variant: "outlined", defaultExpanded: true, sx: { flexShrink: 0 }, children: [_jsx(AccordionSummary, { expandIcon: _jsx(KeyboardArrowDown, {}), sx: { px: 1, minHeight: '48px !important', '& > *': { margin: '0 !important' } }, children: _jsxs(Stack, { direction: "row", alignItems: "center", spacing: 1, width: "100%", children: [_jsx(Typography, { variant: "body2", fontWeight: 500, sx: { flex: 1, overflow: 'hidden', textOverflow: 'ellipsis' }, children: isHit(record) ? record.howler.analytic : 'Observable' }), isHit(record) && _jsx(EscalationChip, { hit: record, layout: HitLayout.DENSE }), isHit(record) && _jsx(Chip, { label: record.howler.status, size: "small", color: "primary", sx: { flexShrink: 0 } }), _jsx(Typography, { variant: "caption", color: "textSecondary", sx: { flexShrink: 0 }, children: record.howler.id })] }) }), _jsx(AccordionDetails, { children: _jsxs(Stack, { spacing: 1, children: [_jsx(Autocomplete, { freeSolo: true, disablePortal: true, options: folderOptions, value: path, onInputChange: (_ev, newVal) => onPathChange(newVal), renderInput: params => (_jsx(TextField, { ...params, size: "small", placeholder: t('modal.cases.add_to_case.select_path'), fullWidth: true, error: pathError, helperText: pathError ? t('modal.cases.add_to_case.path_invalid') : undefined })) }), _jsx(TextField, { size: "small", fullWidth: true, placeholder: t('modal.cases.add_to_case.title'), value: title, onChange: ev => onTitleChange(ev.target.value) }), title && (_jsx(Typography, { variant: "caption", color: "textSecondary", children: t('modal.cases.add_to_case.full_path', { path: fullPath }) }))] }) })] }));
13
+ return (_jsxs(Accordion, { variant: "outlined", defaultExpanded: true, sx: { flexShrink: 0 }, children: [_jsx(AccordionSummary, { expandIcon: _jsx(KeyboardArrowDown, {}), sx: { px: 1, minHeight: '48px !important', '& > *': { margin: '0 !important' } }, children: _jsxs(Stack, { direction: "row", alignItems: "center", spacing: 1, width: "100%", children: [_jsx(Typography, { variant: "body2", fontWeight: 500, sx: { flex: 1, overflow: 'hidden', textOverflow: 'ellipsis' }, children: isHit(record) ? record.howler.analytic : 'Event' }), isHit(record) && _jsx(EscalationChip, { hit: record, layout: HitLayout.DENSE }), isHit(record) && _jsx(Chip, { label: record.howler.status, size: "small", color: "primary", sx: { flexShrink: 0 } }), _jsx(Typography, { variant: "caption", color: "textSecondary", sx: { flexShrink: 0 }, children: record.howler.id })] }) }), _jsx(AccordionDetails, { children: _jsxs(Stack, { spacing: 1, children: [_jsx(Autocomplete, { freeSolo: true, disablePortal: true, options: folderOptions, value: path, onInputChange: (_ev, newVal) => onPathChange(newVal), renderInput: params => (_jsx(TextField, { ...params, size: "small", placeholder: t('modal.cases.add_to_case.select_path'), fullWidth: true, error: pathError, helperText: pathError ? t('modal.cases.add_to_case.path_invalid') : undefined })) }), _jsx(TextField, { size: "small", fullWidth: true, placeholder: t('modal.cases.add_to_case.title'), value: title, onChange: ev => onTitleChange(ev.target.value) }), title && (_jsx(Typography, { variant: "caption", color: "textSecondary", children: t('modal.cases.add_to_case.full_path', { path: fullPath }) }))] }) })] }));
14
14
  };
15
15
  export default CaseRecordRow;
@@ -1,7 +1,7 @@
1
+ import type { Event } from '@cccsaurora/howler-ui/models/entities/generated/Event';
1
2
  import type { Hit } from '@cccsaurora/howler-ui/models/entities/generated/Hit';
2
- import type { Observable } from '@cccsaurora/howler-ui/models/entities/generated/Observable';
3
3
  import { type FC } from 'react';
4
4
  declare const CreateCaseModal: FC<{
5
- records: (Hit | Observable)[];
5
+ records: (Hit | Event)[];
6
6
  }>;
7
7
  export default CreateCaseModal;
@@ -6,7 +6,7 @@ import { ApiConfigContext } from '@cccsaurora/howler-ui/components/app/providers
6
6
  import { ModalContext } from '@cccsaurora/howler-ui/components/app/providers/ModalProvider';
7
7
  import i18n from '@cccsaurora/howler-ui/i18n';
8
8
  import { I18nextProvider } from 'react-i18next';
9
- import { createMockHit, createMockObservable } from '@cccsaurora/howler-ui/tests/utils';
9
+ import { createMockEvent, createMockHit } from '@cccsaurora/howler-ui/tests/utils';
10
10
  import { beforeEach, describe, expect, it, vi } from 'vitest';
11
11
  import CreateCaseModal from './CreateCaseModal';
12
12
  // ---------------------------------------------------------------------------
@@ -48,7 +48,7 @@ const MOCK_HIT_1 = createMockHit({
48
48
  const MOCK_HIT_2 = createMockHit({
49
49
  howler: { id: 'hit-002', analytic: 'AnalyticTwo', status: 'open' }
50
50
  });
51
- const MOCK_OBSERVABLE = createMockObservable({
51
+ const MOCK_EVENT = createMockEvent({
52
52
  howler: { id: 'obs-001' }
53
53
  });
54
54
  const MOCK_CONFIG = {
@@ -115,19 +115,19 @@ describe('CreateCaseModal', () => {
115
115
  expect(screen.getByText(MOCK_HIT_1.howler.analytic)).toBeInTheDocument();
116
116
  expect(screen.getByText(MOCK_HIT_2.howler.analytic)).toBeInTheDocument();
117
117
  });
118
- it('renders a row for an observable record', () => {
119
- renderModal([MOCK_OBSERVABLE]);
120
- expect(screen.getByText('Observable')).toBeInTheDocument();
118
+ it('renders a row for an event record', () => {
119
+ renderModal([MOCK_EVENT]);
120
+ expect(screen.getByText('Event')).toBeInTheDocument();
121
121
  });
122
122
  it('pre-populates the title for a hit with analytic and id', () => {
123
123
  renderModal([MOCK_HIT_1]);
124
124
  const titleInputs = screen.getAllByPlaceholderText(i18n.t('modal.cases.add_to_case.title'));
125
125
  expect(titleInputs[0]).toHaveValue(`${MOCK_HIT_1.howler.analytic} (${MOCK_HIT_1.howler.id})`);
126
126
  });
127
- it('pre-populates the title for an observable with Observable and id', () => {
128
- renderModal([MOCK_OBSERVABLE]);
127
+ it('pre-populates the title for an event with Event and id', () => {
128
+ renderModal([MOCK_EVENT]);
129
129
  const titleInput = screen.getByPlaceholderText(i18n.t('modal.cases.add_to_case.title'));
130
- expect(titleInput).toHaveValue(`Observable (${MOCK_OBSERVABLE.howler.id})`);
130
+ expect(titleInput).toHaveValue(`Event (${MOCK_EVENT.howler.id})`);
131
131
  });
132
132
  it('shows the alert placement section label when there are records', () => {
133
133
  renderModal([MOCK_HIT_1]);
@@ -302,14 +302,14 @@ describe('CreateCaseModal', () => {
302
302
  path: `investigations/${MOCK_HIT_1.howler.analytic} (${MOCK_HIT_1.howler.id})`
303
303
  }));
304
304
  });
305
- it('uses observable __index for observable records', async () => {
305
+ it('uses event __index for event records', async () => {
306
306
  const api = (await import('api')).default;
307
307
  mockDispatchApi.mockResolvedValue({ case_id: 'new-case-id' });
308
- renderModal([MOCK_OBSERVABLE]);
308
+ renderModal([MOCK_EVENT]);
309
309
  await fillCaseMetadata(user);
310
310
  await user.click(screen.getByRole('button', { name: i18n.t('confirm') }));
311
311
  await waitFor(() => expect(mockClose).toHaveBeenCalled());
312
- expect(api.v2.case.items.post).toHaveBeenCalledWith('new-case-id', expect.objectContaining({ type: 'observable' }));
312
+ expect(api.v2.case.items.post).toHaveBeenCalledWith('new-case-id', expect.objectContaining({ type: 'event' }));
313
313
  });
314
314
  it('does not call items.post when there are no records', async () => {
315
315
  const api = (await import('api')).default;
@@ -348,11 +348,11 @@ describe('CreateCaseModal', () => {
348
348
  expect(titleInputs[0]).toHaveValue('Edited Title');
349
349
  expect(titleInputs[1]).toHaveValue(`${MOCK_HIT_2.howler.analytic} (${MOCK_HIT_2.howler.id})`);
350
350
  });
351
- it('mixed hit and observable records each get correct default titles', () => {
352
- renderModal([MOCK_HIT_1, MOCK_OBSERVABLE]);
351
+ it('mixed hit and event records each get correct default titles', () => {
352
+ renderModal([MOCK_HIT_1, MOCK_EVENT]);
353
353
  const titleInputs = screen.getAllByPlaceholderText(i18n.t('modal.cases.add_to_case.title'));
354
354
  expect(titleInputs[0]).toHaveValue(`${MOCK_HIT_1.howler.analytic} (${MOCK_HIT_1.howler.id})`);
355
- expect(titleInputs[1]).toHaveValue(`Observable (${MOCK_OBSERVABLE.howler.id})`);
355
+ expect(titleInputs[1]).toHaveValue(`Event (${MOCK_EVENT.howler.id})`);
356
356
  });
357
357
  });
358
358
  });
@@ -1,7 +1,7 @@
1
1
  import type { Case } from '@cccsaurora/howler-ui/models/entities/generated/Case';
2
+ import type { Event } from '@cccsaurora/howler-ui/models/entities/generated/Event';
2
3
  import type { Hit } from '@cccsaurora/howler-ui/models/entities/generated/Hit';
3
- import type { Observable } from '@cccsaurora/howler-ui/models/entities/generated/Observable';
4
4
  import type { RecordEntry } from './types';
5
- export declare const defaultTitle: (record: Hit | Observable) => string;
5
+ export declare const defaultTitle: (record: Hit | Event) => string;
6
6
  export declare const useFolderOptions: (selectedCase: Case | null) => string[];
7
- export declare const useRecordEntries: (records: (Hit | Observable)[]) => readonly [RecordEntry[], (index: number, field: "title" | "path", value: string) => void];
7
+ export declare const useRecordEntries: (records: (Hit | Event)[]) => readonly [RecordEntry[], (index: number, field: "title" | "path", value: string) => void];
@@ -3,7 +3,7 @@ export const defaultTitle = (record) => {
3
3
  if (record.__index === 'hit') {
4
4
  return `${record.howler.analytic} (${record.howler.id})`;
5
5
  }
6
- return `Observable (${record.howler.id})`;
6
+ return `Event (${record.howler.id})`;
7
7
  };
8
8
  export const useFolderOptions = (selectedCase) => {
9
9
  return useMemo(() => {
@@ -1,5 +1,8 @@
1
+ import type { Event } from 'models/entities/generated/Event';
2
+ import type { Hit } from 'models/entities/generated/Hit';
3
+
1
4
  export interface RecordEntry {
2
- record: Hit | Observable;
5
+ record: Hit | Event;
3
6
  path: string;
4
7
  title: string;
5
8
  }
@@ -0,0 +1,7 @@
1
+ import type { Event } from '@cccsaurora/howler-ui/models/entities/generated/Event';
2
+ import { type FC } from 'react';
3
+ declare const EventViewer: FC<{
4
+ event?: Event;
5
+ eventId?: string;
6
+ }>;
7
+ export default EventViewer;
@@ -0,0 +1,27 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { Box, Skeleton } from '@mui/material';
3
+ import api from '@cccsaurora/howler-ui/api';
4
+ import ObjectDetails from '@cccsaurora/howler-ui/components/elements/ObjectDetails';
5
+ import useMyApi from '@cccsaurora/howler-ui/components/hooks/useMyApi';
6
+ import { useEffect, useState } from 'react';
7
+ const EventViewer = ({ event: provided, eventId }) => {
8
+ const { dispatchApi } = useMyApi();
9
+ const [event, setEvent] = useState(null);
10
+ useEffect(() => {
11
+ if (provided) {
12
+ setEvent(provided);
13
+ }
14
+ }, [provided]);
15
+ useEffect(() => {
16
+ if (eventId) {
17
+ dispatchApi(api.v2.search.post('event', { query: `howler.id:${eventId}`, rows: 1 }), {
18
+ throwError: false
19
+ }).then(res => setEvent(res.items[0]));
20
+ }
21
+ }, [dispatchApi, eventId]);
22
+ if (!event) {
23
+ return;
24
+ }
25
+ return _jsx(Box, { p: 1, children: event ? _jsx(ObjectDetails, { obj: event }) : _jsx(Skeleton, { height: 120 }) });
26
+ };
27
+ export default EventViewer;
@@ -14,9 +14,9 @@ import VSBoxContent from '@cccsaurora/howler-ui/components/elements/addons/layou
14
14
  import VSBoxHeader from '@cccsaurora/howler-ui/components/elements/addons/layout/vsbox/VSBoxHeader';
15
15
  import SearchPagination from '@cccsaurora/howler-ui/components/elements/addons/search/SearchPagination';
16
16
  import SearchTotal from '@cccsaurora/howler-ui/components/elements/addons/search/SearchTotal';
17
+ import EventCard from '@cccsaurora/howler-ui/components/elements/event/EventCard';
17
18
  import HitCard from '@cccsaurora/howler-ui/components/elements/hit/HitCard';
18
19
  import { HitLayout } from '@cccsaurora/howler-ui/components/elements/hit/HitLayout';
19
- import ObservableCard from '@cccsaurora/howler-ui/components/elements/observable/ObservableCard';
20
20
  import RecordContextMenu from '@cccsaurora/howler-ui/components/elements/record/RecordContextMenu';
21
21
  import { useMyLocalStorageItem } from '@cccsaurora/howler-ui/components/hooks/useMyLocalStorage';
22
22
  import useRecordSelection from '@cccsaurora/howler-ui/components/hooks/useRecordSelection';
@@ -26,7 +26,7 @@ import { useTranslation } from 'react-i18next';
26
26
  import { Link } from 'react-router-dom';
27
27
  import { useContextSelector } from 'use-context-selector';
28
28
  import { StorageKey } from '@cccsaurora/howler-ui/utils/constants';
29
- import { isHit, isObservable } from '@cccsaurora/howler-ui/utils/typeUtils';
29
+ import { isEvent, isHit } from '@cccsaurora/howler-ui/utils/typeUtils';
30
30
  import LayoutSettings from './LayoutSettings';
31
31
  import QuerySettings from './QuerySettings';
32
32
  import RecordQuery from './RecordQuery';
@@ -73,7 +73,7 @@ const Item = memo(({ record, onClick }) => {
73
73
  boxShadow: `0px 0px 5px 2px ${theme.palette.primary.main}`
74
74
  }
75
75
  }
76
- ], children: [isHit(record) && _jsx(HitCard, { id: record.howler.id, layout: layout }), isObservable(record) && _jsx(ObservableCard, { id: record.howler.id, observable: record })] }));
76
+ ], children: [isHit(record) && _jsx(HitCard, { id: record.howler.id, layout: layout }), isEvent(record) && _jsx(EventCard, { id: record.howler.id, event: record })] }));
77
77
  });
78
78
  const SearchPane = () => {
79
79
  const { t } = useTranslation();
@@ -1,8 +1,8 @@
1
1
  import { type SxProps } from '@mui/material';
2
+ import type { Event } from '@cccsaurora/howler-ui/models/entities/generated/Event';
2
3
  import type { Hit } from '@cccsaurora/howler-ui/models/entities/generated/Hit';
3
- import type { Observable } from '@cccsaurora/howler-ui/models/entities/generated/Observable';
4
4
  declare const _default: import("react").NamedExoticComponent<{
5
- record: Hit | Observable;
5
+ record: Hit | Event;
6
6
  value: string;
7
7
  sx?: SxProps;
8
8
  className: string;
@@ -1,11 +1,11 @@
1
+ import type { Event } from '@cccsaurora/howler-ui/models/entities/generated/Event';
1
2
  import type { Hit } from '@cccsaurora/howler-ui/models/entities/generated/Hit';
2
- import type { Observable } from '@cccsaurora/howler-ui/models/entities/generated/Observable';
3
3
  declare const _default: import("react").NamedExoticComponent<{
4
- record: Hit | Observable;
4
+ record: Hit | Event;
5
5
  analyticIds: Record<string, string>;
6
6
  columns: string[];
7
7
  columnWidths: Record<string, string>;
8
8
  collapseMainColumn: boolean;
9
- onClick: (e: React.MouseEvent<HTMLDivElement>, record: Hit | Observable) => void;
9
+ onClick: (e: React.MouseEvent<HTMLDivElement>, record: Hit | Event) => void;
10
10
  }>;
11
11
  export default _default;
@@ -3,11 +3,11 @@ import { KeyboardArrowUp } from '@mui/icons-material';
3
3
  import { Box, Collapse, IconButton, lighten, Stack, TableCell, TableRow, Typography, useTheme } from '@mui/material';
4
4
  import { ParameterContext } from '@cccsaurora/howler-ui/components/app/providers/ParameterProvider';
5
5
  import { RecordContext } from '@cccsaurora/howler-ui/components/app/providers/RecordProvider';
6
+ import EventCard from '@cccsaurora/howler-ui/components/elements/event/EventCard';
6
7
  import Assigned from '@cccsaurora/howler-ui/components/elements/hit/elements/Assigned';
7
8
  import EscalationChip from '@cccsaurora/howler-ui/components/elements/hit/elements/EscalationChip';
8
9
  import HitCard from '@cccsaurora/howler-ui/components/elements/hit/HitCard';
9
10
  import { HitLayout } from '@cccsaurora/howler-ui/components/elements/hit/HitLayout';
10
- import ObservableCard from '@cccsaurora/howler-ui/components/elements/observable/ObservableCard';
11
11
  import { get } from 'lodash-es';
12
12
  import { memo, useState } from 'react';
13
13
  import { useTranslation } from 'react-i18next';
@@ -47,6 +47,6 @@ const RecordRow = ({ record, analyticIds, columns, columnWidths, collapseMainCol
47
47
  e.preventDefault();
48
48
  e.stopPropagation();
49
49
  setExpandRow(_expanded => !_expanded);
50
- }, children: _jsx(KeyboardArrowUp, {}) }), _jsx(Collapse, { in: !collapseMainColumn, orientation: "horizontal", unmountOnExit: true, children: _jsxs(Stack, { direction: "row", spacing: 1, flexWrap: "nowrap", children: [isHit(record) && _jsx(EscalationChip, { hit: record, layout: HitLayout.DENSE, hideLabel: true }), _jsxs(Typography, { sx: { textWrap: 'nowrap', whiteSpace: 'nowrap', fontSize: 'inherit' }, children: [analyticIds[record.howler.analytic] ? (_jsx(Link, { to: `/analytics/${analyticIds[record.howler.analytic]}`, onClick: e => e.stopPropagation(), children: record.howler.analytic })) : (record.howler.analytic), record.howler.detection && ': ', record.howler.detection] }), isHit(record) && record.howler.assignment !== 'unassigned' && (_jsx(Assigned, { hit: record, layout: HitLayout.DENSE, hideLabel: true }))] }) })] }) }), columns.map(col => (_jsx(EnhancedCell, { record: record, className: `col-${col.replaceAll('.', '-')}`, value: get(record, col) ?? t('none'), sx: columnWidths[col] ? { width: columnWidths[col] } : { width: '220px', maxWidth: '300px' }, field: col }, col)))] }, record.howler.id), _jsx(TableRow, { onClick: ev => onClick(ev, record), children: _jsx(TableCell, { colSpan: columns.length + 2, style: { paddingBottom: 0, paddingTop: 0 }, children: _jsx(Collapse, { in: expandRow, unmountOnExit: true, children: _jsx(Box, { width: "100%", maxWidth: "1200px", margin: 1, children: isHit(record) ? (_jsx(HitCard, { id: record.howler.id, layout: HitLayout.NORMAL })) : (_jsx(ObservableCard, { id: record.howler.id, observable: record })) }) }) }) })] }));
50
+ }, children: _jsx(KeyboardArrowUp, {}) }), _jsx(Collapse, { in: !collapseMainColumn, orientation: "horizontal", unmountOnExit: true, children: _jsxs(Stack, { direction: "row", spacing: 1, flexWrap: "nowrap", children: [isHit(record) && _jsx(EscalationChip, { hit: record, layout: HitLayout.DENSE, hideLabel: true }), _jsxs(Typography, { sx: { textWrap: 'nowrap', whiteSpace: 'nowrap', fontSize: 'inherit' }, children: [analyticIds[record.howler.analytic] ? (_jsx(Link, { to: `/analytics/${analyticIds[record.howler.analytic]}`, onClick: e => e.stopPropagation(), children: record.howler.analytic })) : (record.howler.analytic), record.howler.detection && ': ', record.howler.detection] }), isHit(record) && record.howler.assignment !== 'unassigned' && (_jsx(Assigned, { hit: record, layout: HitLayout.DENSE, hideLabel: true }))] }) })] }) }), columns.map(col => (_jsx(EnhancedCell, { record: record, className: `col-${col.replaceAll('.', '-')}`, value: get(record, col) ?? t('none'), sx: columnWidths[col] ? { width: columnWidths[col] } : { width: '220px', maxWidth: '300px' }, field: col }, col)))] }, record.howler.id), _jsx(TableRow, { onClick: ev => onClick(ev, record), children: _jsx(TableCell, { colSpan: columns.length + 2, style: { paddingBottom: 0, paddingTop: 0 }, children: _jsx(Collapse, { in: expandRow, unmountOnExit: true, children: _jsx(Box, { width: "100%", maxWidth: "1200px", margin: 1, children: isHit(record) ? (_jsx(HitCard, { id: record.howler.id, layout: HitLayout.NORMAL })) : (_jsx(EventCard, { id: record.howler.id, event: record })) }) }) }) })] }));
51
51
  };
52
52
  export default memo(RecordRow);
@@ -8,7 +8,7 @@ import { useTranslation } from 'react-i18next';
8
8
  import { useContextSelector } from 'use-context-selector';
9
9
  const FILTER_OPTIONS = [
10
10
  { label: 'hit.search.index.hit', value: 'hit' },
11
- { label: 'hit.search.index.observable', value: 'observable' }
11
+ { label: 'hit.search.index.event', value: 'event' }
12
12
  ];
13
13
  const IndexPicker = () => {
14
14
  const { t } = useTranslation();
@@ -5,16 +5,16 @@ import api from '@cccsaurora/howler-ui/api';
5
5
  import AppListEmpty from '@cccsaurora/howler-ui/commons/components/display/AppListEmpty';
6
6
  import { useRecordContextSelector } from '@cccsaurora/howler-ui/components/app/providers/RecordProvider';
7
7
  import { ViewContext } from '@cccsaurora/howler-ui/components/app/providers/ViewProvider';
8
+ import EventCard from '@cccsaurora/howler-ui/components/elements/event/EventCard';
8
9
  import HitBanner from '@cccsaurora/howler-ui/components/elements/hit/HitBanner';
9
10
  import { HitLayout } from '@cccsaurora/howler-ui/components/elements/hit/HitLayout';
10
- import ObservableCard from '@cccsaurora/howler-ui/components/elements/observable/ObservableCard';
11
11
  import RecordContextMenu from '@cccsaurora/howler-ui/components/elements/record/RecordContextMenu';
12
12
  import useMyApi from '@cccsaurora/howler-ui/components/hooks/useMyApi';
13
13
  import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
14
14
  import { useTranslation } from 'react-i18next';
15
15
  import { Link, useNavigate } from 'react-router-dom';
16
16
  import { useContextSelector } from 'use-context-selector';
17
- import { isObservable } from '@cccsaurora/howler-ui/utils/typeUtils';
17
+ import { isEvent } from '@cccsaurora/howler-ui/utils/typeUtils';
18
18
  import { buildViewUrl } from '@cccsaurora/howler-ui/utils/viewUtils';
19
19
  // Custom hook to select records by IDs with proper memoization
20
20
  const useSelectRecordsByIds = (recordIds) => {
@@ -49,7 +49,7 @@ const createRecordSignature = (record) => {
49
49
  if (!record) {
50
50
  return '';
51
51
  }
52
- if (isObservable(record)) {
52
+ if (isEvent(record)) {
53
53
  return record.howler?.id;
54
54
  }
55
55
  return `${record.howler?.id}:${normalize(record.howler?.status)}:${normalize(record.howler?.assignment)}:${normalize(record.howler?.assessment)}`;
@@ -157,6 +157,6 @@ const ViewCard = ({ viewId, limit, refreshTick, onRefreshComplete }) => {
157
157
  }
158
158
  return selectedElement.id;
159
159
  }, []);
160
- return (_jsx(Card, { variant: "outlined", sx: { height: '100%' }, children: _jsxs(Stack, { spacing: 1, sx: { p: 1, minHeight: 100 }, children: [_jsxs(Stack, { direction: "row", spacing: 1, alignItems: "center", children: [_jsx(Typography, { variant: "h6", children: t(view?.title) || _jsx(Skeleton, { variant: "text", height: "2em", width: "100px" }) }), _jsx(IconButton, { size: "small", component: Link, disabled: !view, to: view ? buildViewUrl(view) : '', onClick: () => onClick(view.query), children: _jsx(OpenInNew, { fontSize: "small" }) })] }), loading ? (_jsxs(_Fragment, { children: [_jsx(Skeleton, { height: 150, width: "100%", variant: "rounded" }), _jsx(Skeleton, { height: 160, width: "100%", variant: "rounded" }), _jsx(Skeleton, { height: 140, width: "100%", variant: "rounded" })] })) : records.length > 0 ? (_jsx(RecordContextMenu, { getSelectedId: getSelectedId, children: records.map((r) => (_jsx(Card, { id: r.howler.id, variant: "outlined", sx: { cursor: 'pointer' }, onClick: () => navigate(`/hits/${r.howler.id}`), children: _jsx(CardContent, { children: r.__index == 'hit' ? (_jsx(HitBanner, { layout: HitLayout.DENSE, hit: r })) : (_jsx(ObservableCard, { observable: r })) }) }, r.howler.id))) })) : (_jsx(AppListEmpty, {}))] }) }));
160
+ return (_jsx(Card, { variant: "outlined", sx: { height: '100%' }, children: _jsxs(Stack, { spacing: 1, sx: { p: 1, minHeight: 100 }, children: [_jsxs(Stack, { direction: "row", spacing: 1, alignItems: "center", children: [_jsx(Typography, { variant: "h6", children: t(view?.title) || _jsx(Skeleton, { variant: "text", height: "2em", width: "100px" }) }), _jsx(IconButton, { size: "small", component: Link, disabled: !view, to: view ? buildViewUrl(view) : '', onClick: () => onClick(view.query), children: _jsx(OpenInNew, { fontSize: "small" }) })] }), loading ? (_jsxs(_Fragment, { children: [_jsx(Skeleton, { height: 150, width: "100%", variant: "rounded" }), _jsx(Skeleton, { height: 160, width: "100%", variant: "rounded" }), _jsx(Skeleton, { height: 140, width: "100%", variant: "rounded" })] })) : records.length > 0 ? (_jsx(RecordContextMenu, { getSelectedId: getSelectedId, children: records.map((r) => (_jsx(Card, { id: r.howler.id, variant: "outlined", sx: { cursor: 'pointer' }, onClick: () => navigate(`/hits/${r.howler.id}`), children: _jsx(CardContent, { children: r.__index == 'hit' ? (_jsx(HitBanner, { layout: HitLayout.DENSE, hit: r })) : (_jsx(EventCard, { event: r })) }) }, r.howler.id))) })) : (_jsx(AppListEmpty, {}))] }) }));
161
161
  };
162
162
  export default ViewCard;
@@ -16,9 +16,9 @@ import VSBox from '@cccsaurora/howler-ui/components/elements/addons/layout/vsbox
16
16
  import VSBoxContent from '@cccsaurora/howler-ui/components/elements/addons/layout/vsbox/VSBoxContent';
17
17
  import VSBoxHeader from '@cccsaurora/howler-ui/components/elements/addons/layout/vsbox/VSBoxHeader';
18
18
  import SearchTotal from '@cccsaurora/howler-ui/components/elements/addons/search/SearchTotal';
19
+ import EventCard from '@cccsaurora/howler-ui/components/elements/event/EventCard';
19
20
  import HitCard from '@cccsaurora/howler-ui/components/elements/hit/HitCard';
20
21
  import { HitLayout } from '@cccsaurora/howler-ui/components/elements/hit/HitLayout';
21
- import ObservableCard from '@cccsaurora/howler-ui/components/elements/observable/ObservableCard';
22
22
  import useMyApi from '@cccsaurora/howler-ui/components/hooks/useMyApi';
23
23
  import { useMyLocalStorageItem } from '@cccsaurora/howler-ui/components/hooks/useMyLocalStorage';
24
24
  import useMySnackbar from '@cccsaurora/howler-ui/components/hooks/useMySnackbar';
@@ -199,6 +199,6 @@ const ViewComposer = () => {
199
199
  fontSize: '0.9em',
200
200
  fontStyle: 'italic',
201
201
  mb: 0.5
202
- }), variant: "body2", children: t('hit.search.prompt') }), _jsx(RecordQuery, { triggerSearch: search, searching: searching, onChange: (_query, isDirty) => setIsSearchDirty(isDirty) }), _jsxs(Stack, { direction: "row", spacing: 1, children: [_jsx(IndexPicker, {}), _jsx(HitSort, {}), _jsx(SearchSpan, { omitCustom: true }), _jsx("div", { style: { flex: 1 } }), _jsxs(Stack, { spacing: 1, direction: "row", alignItems: "center", sx: { flex: '0 !important', minWidth: '300px' }, children: [_jsx(Typography, { component: "span", children: t('view.settings.advance_on_triage') }), _jsx(Tooltip, { title: t('view.settings.advance_on_triage.description'), children: _jsx(HelpOutline, { sx: { fontSize: '16px' } }) }), _jsx(Checkbox, { size: "small", checked: advanceOnTriage, onChange: (_event, checked) => setAdvanceOnTriage(checked) })] })] }), response?.total ? (_jsx(SearchTotal, { total: response.total, pageLength: response.items.length, offset: response.offset, sx: theme => ({ color: theme.palette.text.secondary, fontSize: '0.9em', fontStyle: 'italic' }) })) : null, _jsx(LinearProgress, { sx: [!searching && { opacity: 0 }] })] }) }), _jsx(VSBoxContent, { children: _jsxs(Stack, { spacing: 1, children: [!response?.total && _jsx(AppListEmpty, {}), response?.items.map(record => record.__index === 'hit' ? (_jsx(HitCard, { id: record.howler.id, layout: HitLayout.DENSE }, record.howler.id)) : (_jsx(ObservableCard, { observable: record }, record.howler.id)))] }) })] }) }) }) }));
202
+ }), variant: "body2", children: t('hit.search.prompt') }), _jsx(RecordQuery, { triggerSearch: search, searching: searching, onChange: (_query, isDirty) => setIsSearchDirty(isDirty) }), _jsxs(Stack, { direction: "row", spacing: 1, children: [_jsx(IndexPicker, {}), _jsx(HitSort, {}), _jsx(SearchSpan, { omitCustom: true }), _jsx("div", { style: { flex: 1 } }), _jsxs(Stack, { spacing: 1, direction: "row", alignItems: "center", sx: { flex: '0 !important', minWidth: '300px' }, children: [_jsx(Typography, { component: "span", children: t('view.settings.advance_on_triage') }), _jsx(Tooltip, { title: t('view.settings.advance_on_triage.description'), children: _jsx(HelpOutline, { sx: { fontSize: '16px' } }) }), _jsx(Checkbox, { size: "small", checked: advanceOnTriage, onChange: (_event, checked) => setAdvanceOnTriage(checked) })] })] }), response?.total ? (_jsx(SearchTotal, { total: response.total, pageLength: response.items.length, offset: response.offset, sx: theme => ({ color: theme.palette.text.secondary, fontSize: '0.9em', fontStyle: 'italic' }) })) : null, _jsx(LinearProgress, { sx: [!searching && { opacity: 0 }] })] }) }), _jsx(VSBoxContent, { children: _jsxs(Stack, { spacing: 1, children: [!response?.total && _jsx(AppListEmpty, {}), response?.items.map(record => record.__index === 'hit' ? (_jsx(HitCard, { id: record.howler.id, layout: HitLayout.DENSE }, record.howler.id)) : (_jsx(EventCard, { event: record }, record.howler.id)))] }) })] }) }) }) }));
203
203
  };
204
204
  export default ViewComposer;
@@ -188,7 +188,7 @@
188
188
  "hit.header.threat": "Threat",
189
189
  "hit.header.view.case": "View case {{id}}",
190
190
  "hit.header.view.hit": "View hit {{id}}",
191
- "hit.header.view.observable": "View observable {{id}}",
191
+ "hit.header.view.event": "View event {{id}}",
192
192
  "hit.header.votes": "Votes: ",
193
193
  "hit.howler.related": "{{count}} related records",
194
194
  "hit.label": "Labels",
@@ -233,7 +233,7 @@
233
233
  "hit.related.tab.case": "Cases",
234
234
  "hit.related.tab.hit": "Hits",
235
235
  "hit.related.tab.links": "Links",
236
- "hit.related.tab.observable": "Observables",
236
+ "hit.related.tab.event": "Events",
237
237
  "hit.search.aggregate.button": "Create Summary",
238
238
  "hit.search.button": "Perform search",
239
239
  "hit.search.custom": "Custom Sort",
@@ -244,7 +244,7 @@
244
244
  "hit.search.filter.values": "Values",
245
245
  "hit.search.index": "Indexes",
246
246
  "hit.search.index.hit": "Hits",
247
- "hit.search.index.observable": "Observables",
247
+ "hit.search.index.event": "Events",
248
248
  "hit.search.invalid": "Invalid Query",
249
249
  "hit.search.keyboard": "Keyboard shortcuts",
250
250
  "hit.search.keyboard.no_shortcuts": "No shortcuts",
@@ -368,7 +368,7 @@
368
368
  "no.data": "No Data",
369
369
  "none": "None",
370
370
  "normal": "Normal Priority",
371
- "observable.open": "Open Observable",
371
+ "event.open": "Open Event",
372
372
  "on": "on",
373
373
  "open": "Open",
374
374
  "operations.add_label": "Add Label",
@@ -188,7 +188,7 @@
188
188
  "hit.header.threat": "Menace",
189
189
  "hit.header.view.case": "Voir le cas {{id}}",
190
190
  "hit.header.view.hit": "Voir l'alerte {{id}}",
191
- "hit.header.view.observable": "Voir l'observable {{id}}",
191
+ "hit.header.view.event": "Voir l'événement {{id}}",
192
192
  "hit.header.votes": "Votes: ",
193
193
  "hit.howler.related": "{{count}} enregistrements associés",
194
194
  "hit.label": "Étiquettes",
@@ -233,7 +233,7 @@
233
233
  "hit.related.tab.case": "Cas",
234
234
  "hit.related.tab.hit": "Alertes",
235
235
  "hit.related.tab.links": "Liens",
236
- "hit.related.tab.observable": "Observables",
236
+ "hit.related.tab.event": "Événements",
237
237
  "hit.search.aggregate.button": "Créer un sommaire",
238
238
  "hit.search.button": "Effectuer une recherche",
239
239
  "hit.search.custom": "Triage personnalisé",
@@ -244,7 +244,7 @@
244
244
  "hit.search.filter.values": "Valeurs",
245
245
  "hit.search.index": "Indexes",
246
246
  "hit.search.index.hit": "Hits",
247
- "hit.search.index.observable": "Observables",
247
+ "hit.search.index.event": "Événements",
248
248
  "hit.search.invalid": "Requête invalide",
249
249
  "hit.search.keyboard": "Raccourcis clavier",
250
250
  "hit.search.keyboard.no_shortcuts": "Pas de raccourcis",
@@ -368,7 +368,7 @@
368
368
  "no.data": "Aucune donnée",
369
369
  "none": "Rien",
370
370
  "normal": "Priorité normale",
371
- "observable.open": "Ouvrir observable",
371
+ "event.open": "Ouvrir événement",
372
372
  "on": "sur",
373
373
  "open": "Ouvert",
374
374
  "operations.add_label": "Ajouter un label",