From f1f804f344c104131e9a8bae217d330d4ce642a4 Mon Sep 17 00:00:00 2001 From: Amardeepsingh Siglani Date: Fri, 10 Jan 2025 13:23:52 -0800 Subject: [PATCH] [Backport 2.17] Backport missing commits to 2.17 for bug fixes (#1242) * feat: update category (#1169) (#1170) (cherry picked from commit 8865ff1f4fce4ae184889bf3c7fb7ef04c4455fc) Signed-off-by: SuZhou-Joe Signed-off-by: github-actions[bot] Co-authored-by: github-actions[bot] * Bug fixes for threat intel, duplicate findings, and breadcrumbs path (#1176) (#1177) * fix spacing for threat intel * fix alienvault source details page crash * fix threat intel findings widget view view all url crash * fix security analtyics breadcrumbs link path crash * fix duplicate findings --------- (cherry picked from commit 0ce91fbe36e316516022e31baa5a77f4336f0f50) Signed-off-by: Joanne Wang Signed-off-by: github-actions[bot] Co-authored-by: github-actions[bot] * Fit and Finish UX Fixes (#1174) (#1178) * add plus sign to create detector button * change getting started to get started * run yarn test:jest -u * move tabs to top * remove duplicate code * change total active alerts to total active threat alerts * Add period to end of correlate events content * fix spacing and padding * make search and filters compressed * make search and filter compressed pt 2 * move refresh and actions next to search bar * move bulk delete to left of search bar * fix spacing for detector details view * change content panel from h2 to h3 * remove empty hover state * fix sizing for empty widget * fix heading spacing * change getting started to get started pt2 * run yarn test:jest -u * add helper function for empty prompt and change to p instead of span --------- (cherry picked from commit 9c0c2f422e2766890657ad451ec8bf75fa88cb20) Signed-off-by: Joanne Wang Signed-off-by: github-actions[bot] Co-authored-by: github-actions[bot] * [Fit&Finish] Security analytics overview page (#1175) (#1179) * fit&finish * add width for recent threat alerts card * fix typo --------- (cherry picked from commit 076d1efc8941d2af51f229014e65885788e0c2a8) Signed-off-by: Hailong Cui Signed-off-by: github-actions[bot] Co-authored-by: github-actions[bot] * avoid showing unuseful error toast when ds is not yet selected (#1186) (#1187) (cherry picked from commit e4fdd2545a6f9c14e34b33c8950717d3b047d868) Signed-off-by: Amardeepsingh Siglani Signed-off-by: github-actions[bot] Co-authored-by: github-actions[bot] * fix: Update getting started cards content and visual design (#1188) (#1189) (cherry picked from commit 2b33ca28223dae9419167b8e524da0f17828526b) Signed-off-by: Viraj Sanghvi Signed-off-by: github-actions[bot] Co-authored-by: github-actions[bot] * testing default ds switch changes (#1199) (#1201) (cherry picked from commit 5d3801a6c16640d3b0f5785ec8d2e1e8db43ff93) Signed-off-by: Riya Saxena Signed-off-by: github-actions[bot] Co-authored-by: github-actions[bot] * make dataSource default cluster for threat alerts card (#1200) (#1203) (cherry picked from commit 48669ca25184f734db933b2e9671b0ad6e3af242) Signed-off-by: Joanne Wang Signed-off-by: github-actions[bot] Co-authored-by: github-actions[bot] * Fix data source picker for threat alerts card (#1206) (#1207) * Fix data source picker for threat alerts card * remove unused import * fix get alerts loop --------- (cherry picked from commit b2eb62c96e4a4be0b6c8a5450e810d2437fd737f) Signed-off-by: Joanne Wang Signed-off-by: github-actions[bot] Co-authored-by: github-actions[bot] * do not decode ds id from url; update global state on ds change (#1216) (#1217) (cherry picked from commit ad76b7bfacd90eaeb95ea8ee674eaf3a1af4746d) Signed-off-by: Amardeepsingh Siglani Signed-off-by: github-actions[bot] Co-authored-by: github-actions[bot] --------- Signed-off-by: SuZhou-Joe Signed-off-by: github-actions[bot] Signed-off-by: Joanne Wang Signed-off-by: Hailong Cui Signed-off-by: Amardeepsingh Siglani Signed-off-by: Viraj Sanghvi Signed-off-by: Riya Saxena Co-authored-by: opensearch-trigger-bot[bot] <98922864+opensearch-trigger-bot[bot]@users.noreply.github.com> Co-authored-by: github-actions[bot] --- .../components/ContentPanel/ContentPanel.tsx | 7 +- .../__snapshots__/ContentPanel.test.tsx.snap | 6 +- .../DataSourceThreatAlertsCard.tsx | 16 +- .../ThreatIntelAlertsTable.tsx | 8 +- .../pages/Alerts/containers/Alerts/Alerts.tsx | 149 +- .../Alerts/__snapshots__/Alerts.test.tsx.snap | 2144 ++++++++++------- .../containers/CorrelationRules.tsx | 3 +- .../containers/CorrelationsContainer.tsx | 12 +- .../containers/CreateDetector.tsx | 2 +- .../DetectorBasicDetailsView.test.tsx.snap | 12 +- .../DetectorRulesView.test.tsx.snap | 57 +- .../FieldMappingsView.test.tsx.snap | 12 +- .../UpdateDetectorRules.test.tsx.snap | 12 +- .../AlertTriggersView.test.tsx.snap | 10 +- .../containers/Detector/DetectorDetails.tsx | 4 +- .../DetectorDetails.test.tsx.snap | 82 +- .../DetectorDetailsView.tsx | 1 - .../DetectorDetailsView.test.tsx.snap | 74 +- .../containers/Detectors/Detectors.tsx | 115 +- .../__snapshots__/Detectors.test.tsx.snap | 695 ++++-- .../FindingsTable/FindingsTable.tsx | 4 + .../ThreatIntelFindingsTable.tsx | 8 +- .../Findings/containers/Findings/Findings.tsx | 126 +- public/pages/LogTypes/utils/helpers.tsx | 3 + public/pages/Main/Main.tsx | 37 +- .../components/Widgets/RecentAlertsWidget.tsx | 37 +- .../Widgets/RecentFindingsWidget.tsx | 37 +- .../RecentThreatIntelFindingsWidget.tsx | 56 +- .../Overview/components/Widgets/Summary.tsx | 11 +- .../components/Widgets/TopRulesWidget.tsx | 19 +- .../Overview/containers/Overview/Overview.tsx | 18 +- public/pages/Overview/utils/constants.ts | 91 +- .../__snapshots__/RulesTable.test.tsx.snap | 20 +- public/pages/Rules/containers/Rules/Rules.tsx | 12 +- public/pages/Rules/utils/helpers.tsx | 4 + .../ThreatIntelSourceDetails.tsx | 13 +- .../ThreatIntelSourcesList.tsx | 7 +- public/plugin.ts | 63 +- public/security_analytics_app.tsx | 146 +- public/services/AlertsService.ts | 3 +- public/services/DetectorService.ts | 6 +- public/services/utils/constants.ts | 4 +- public/store/AlertsStore.ts | 36 +- public/store/FindingsStore.ts | 4 + public/store/LogTypeStore.ts | 114 +- public/utils/constants.ts | 13 +- public/utils/helpers.tsx | 23 + types/Alert.ts | 4 +- 48 files changed, 2520 insertions(+), 1820 deletions(-) diff --git a/public/components/ContentPanel/ContentPanel.tsx b/public/components/ContentPanel/ContentPanel.tsx index edb92e293..3433bf1aa 100644 --- a/public/components/ContentPanel/ContentPanel.tsx +++ b/public/components/ContentPanel/ContentPanel.tsx @@ -48,15 +48,12 @@ const ContentPanel = ({ hideHeaderBorder = false, className = '', }: ContentPanelProps): JSX.Element => ( - + {typeof title === 'string' ? ( -

{title}

+

{title}

) : ( title diff --git a/public/components/ContentPanel/__snapshots__/ContentPanel.test.tsx.snap b/public/components/ContentPanel/__snapshots__/ContentPanel.test.tsx.snap index 38b86519a..abd12b5c4 100644 --- a/public/components/ContentPanel/__snapshots__/ContentPanel.test.tsx.snap +++ b/public/components/ContentPanel/__snapshots__/ContentPanel.test.tsx.snap @@ -3,7 +3,7 @@ exports[` spec renders the component 1`] = `
spec renders the component 1`] = `
-

+

Testing -

+
= ( }, [getDataSourceMenu]); const notifications = getNotifications(); const [loading, setLoading] = useState(false); - const [dataSource, setDataSource] = useState({ - label: 'Local cluster', - id: '', - }); + const [dataSource, setDataSource] = useState(); const [alerts, setAlerts] = useState([]); const getAlerts = async () => { try { - const detectorsRes = await detectorService.getDetectors(); + const detectorsRes = await detectorService.getDetectors(dataSource); if (detectorsRes.ok) { const detectors: any = {}; const detectorIds = detectorsRes.response.hits.hits.map((hit: any) => { @@ -72,16 +69,15 @@ export const DataSourceThreatAlertsCard: React.FC = ( }); let alerts: any[] = []; - const abortController = new AbortController(); for (let id of detectorIds) { - const alertsRes = await DataStore.alerts.getAlertsByDetector( + const alertsRes = await DataStore.alerts.getAlertsForThreatAlertsCard( id, detectors[id].name, - abortController.signal, undefined, undefined, - 25 + 25, + dataSource ); alerts = alerts.concat(alertsRes); } @@ -106,7 +102,7 @@ export const DataSourceThreatAlertsCard: React.FC = ( const onDataSourceSelected = useCallback( (options: any[]) => { - if (dataSource?.id !== undefined && dataSource?.id !== options[0]?.id) { + if (dataSource?.id === undefined || dataSource?.id !== options[0]?.id) { setDataSource(options[0]); } }, diff --git a/public/pages/Alerts/components/ThreatIntelAlertsTable/ThreatIntelAlertsTable.tsx b/public/pages/Alerts/components/ThreatIntelAlertsTable/ThreatIntelAlertsTable.tsx index bf90db806..6aceb98ec 100644 --- a/public/pages/Alerts/components/ThreatIntelAlertsTable/ThreatIntelAlertsTable.tsx +++ b/public/pages/Alerts/components/ThreatIntelAlertsTable/ThreatIntelAlertsTable.tsx @@ -126,6 +126,12 @@ export const ThreatIntelAlertsTable: React.FC = ({ }, ]; + const search = { + box: { + compressed: true, + }, + }; + return ( <> = ({ items={alerts} itemId={(item) => `${item.id}`} pagination - search + search={search} selection={itemSelection} isSelectable={true} /> diff --git a/public/pages/Alerts/containers/Alerts/Alerts.tsx b/public/pages/Alerts/containers/Alerts/Alerts.tsx index 9bcb18500..df6fb3dd5 100644 --- a/public/pages/Alerts/containers/Alerts/Alerts.tsx +++ b/public/pages/Alerts/containers/Alerts/Alerts.tsx @@ -938,12 +938,14 @@ export class Alerts extends Component { box: { placeholder: 'Search alerts', schema: true, + compressed: true, }, filters: [ { type: 'field_value_selection', field: 'severity', name: 'Alert severity', + compressed: true, options: Array.from(severities).map((severity) => ({ value: severity, name: parseAlertSeverityToOption(severity)?.label || severity, @@ -954,6 +956,7 @@ export class Alerts extends Component { type: 'field_value_selection', field: 'state', name: 'Status', + compressed: true, options: Array.from(statuses).map((status) => ({ value: status, name: capitalizeFirstLetter(status) || status, @@ -967,12 +970,14 @@ export class Alerts extends Component { box: { placeholder: 'Search alerts', schema: true, + compressed: true, }, filters: [ { type: 'field_value_selection', field: 'severity', name: 'Alert severity', + compressed: true, options: Array.from(corrSeverities).map((severity) => ({ value: severity, name: parseAlertSeverityToOption(severity)?.label || severity, @@ -983,6 +988,7 @@ export class Alerts extends Component { type: 'field_value_selection', field: 'state', name: 'Status', + compressed: true, options: Array.from(corrStatuses).map((status) => ({ value: status, name: capitalizeFirstLetter(status) || status, @@ -1018,18 +1024,22 @@ export class Alerts extends Component { content: ( <> - `${item.id}`} - isSelectable={true} - pagination - search={search} - sorting={sorting} - selection={selection} - loading={loading} - message={widgetEmptyMessage} - /> + {this.getAlertsGraph(alerts, loading)} + + + `${item.id}`} + isSelectable={true} + pagination + search={search} + sorting={sorting} + selection={selection} + loading={loading} + message={widgetEmptyMessage} + /> + ), }, @@ -1039,11 +1049,15 @@ export class Alerts extends Component { content: ( <> - + {this.getAlertsGraph(alerts, loading)} + + + + ), }, @@ -1060,18 +1074,22 @@ export class Alerts extends Component { content: ( <> - `${item.id}`} - isSelectable={true} - pagination - search={correlationSearch} - sorting={sorting} - selection={correlationSelection} - loading={loading} - message={widgetEmptyCorrelationMessage} - /> + {this.getAlertsGraph(alerts, loading)} + + + `${item.id}`} + isSelectable={true} + pagination + search={correlationSearch} + sorting={sorting} + selection={correlationSelection} + loading={loading} + message={widgetEmptyCorrelationMessage} + /> + ), }, @@ -1109,7 +1127,7 @@ export class Alerts extends Component { onAcknowledge={this.onAcknowledgeCorrelationAlert} /> )} - + { {datePicker} - - - - - {this.createGroupByControl()} - - - {!alerts || alerts.length === 0 ? ( -

No alerts

} - body={ -

- - Adjust the time range to see more results or create alert triggers in your{' '} - detectors to - generate alerts. - -

- } - /> - ) : ( - - )} -
-
-
- + this.setState({ selectedTabId: id as AlertTabId })} + initialSelectedTab={tabs.find(({ id }) => id === selectedTabId) ?? tabs[0]} + />
+
+ + ); + } + + private getAlertsGraph(alerts: any[], loading: boolean) { + return ( + + + {this.createGroupByControl()} - - this.setState({ selectedTabId: id as AlertTabId })} - initialSelectedTab={tabs.find(({ id }) => id === selectedTabId) ?? tabs[0]} + {!alerts || alerts.length === 0 ? ( + +

No alerts

+ + } + body={ +

+ + Adjust the time range to see more results or create alert triggers in your{' '} + detectors to + generate alerts. + +

+ } /> -
+ ) : ( + + )}
- +
); } } diff --git a/public/pages/Alerts/containers/Alerts/__snapshots__/Alerts.test.tsx.snap b/public/pages/Alerts/containers/Alerts/__snapshots__/Alerts.test.tsx.snap index 0f21fe9cb..2899073d5 100644 --- a/public/pages/Alerts/containers/Alerts/__snapshots__/Alerts.test.tsx.snap +++ b/public/pages/Alerts/containers/Alerts/__snapshots__/Alerts.test.tsx.snap @@ -209,9 +209,10 @@ exports[` spec renders the component 1`] = ` >
spec renders the component 1`] = `
- -
-
@@ -832,43 +826,235 @@ exports[` spec renders the component 1`] = `
- -
- -
- + + + + + + + + + + + + + + Adjust the time range to see more results or create alert triggers in your + + + detectors + + to generate alerts. + +

+ } + title={ + +

+ No alerts +

+
+ } + /> +
+
+
+ + + Acknowledge + , + ] } + title="Alerts" > -
+ selection={ + Object { + "onSelectionChange": [Function], + "selectable": [Function], + "selectableMessage": [Function], + } + } + sorting={ + Object { + "sort": Object { + "direction": "dsc", + "field": "start_time", + }, + } + } + tableLayout="fixed" + /> + + , + "id": "detection-rules", + "name": "Detection rules", + } + } + onTabClick={[Function]} + size="s" + tabs={ + Array [ + Object { + "content": + + -
- -
spec renders the component 1`] = ` } prepend="Group by" value="status" - > - + + + + + + - -
- - - -
- - - - -
- - - - - -
-
-
-
-
-
-
-
-
-
+ detectors + + to generate alerts. + +

+ } + title={ + +

+ No alerts +

+
+ } + /> +
-
-
- -
+ + + Acknowledge + , + ] + } + title="Alerts" > - - - Adjust the time range to see more results or create alert triggers in your - - - detectors - - to generate alerts. - -

+ -

- No alerts -

- + isSelectable={true} + itemId={[Function]} + items={Array []} + loading={true} + pagination={true} + responsive={true} + search={ + Object { + "box": Object { + "compressed": true, + "placeholder": "Search alerts", + "schema": true, + }, + "filters": Array [ + Object { + "compressed": true, + "field": "severity", + "multiSelect": "or", + "name": "Alert severity", + "options": Array [], + "type": "field_value_selection", + }, + Object { + "compressed": true, + "field": "state", + "multiSelect": "or", + "name": "Status", + "options": Array [], + "type": "field_value_selection", + }, + ], + } + } + selection={ + Object { + "onSelectionChange": [Function], + "selectable": [Function], + "selectableMessage": [Function], + } + } + sorting={ + Object { + "sort": Object { + "direction": "dsc", + "field": "start_time", + }, + } } + tableLayout="fixed" + /> +
+ , + "id": "detection-rules", + "name": "Detection rules", + }, + Object { + "content": + + + -
- - -
+ + + + + + + Adjust the time range to see more results or create alert triggers in your + + + detectors + + to generate alerts. + +

+ } + title={ +

No alerts

-
-
-
- + } + /> + + + + + + Acknowledge + , + ] + } + title="Alerts" + > + + + , + "id": "threat-intel", + "name": "Threat intel", + }, + Object { + "content": + + + + + - - -
- - -
-

- -

- Adjust the time range to see more results or create alert triggers in your - - - - detectors - - - to generate alerts. -
- -

-
-
- - -
- -
- -
- -
- - -
- -
- - -
- - Acknowledge - , - ] - } - title="Alerts" - > - -
- -
- -
- -
-

- Alerts -

-
-
-
-
- -
- -
- -
- + + + + + + - - - - - - -
-
-
-
-
-
-
-
- -
-
-
- - + to generate alerts. + +

+ } + title={ + +

+ No alerts +

+
+ } /> - + + + + + Acknowledge + , + ] + } + title="Alerts" + > + - , - "id": "detection-rules", - "name": "Detection rules", - } - } - onTabClick={[Function]} - size="s" - tabs={ - Array [ - Object { - "content": - - - , - "id": "detection-rules", - "name": "Detection rules", - }, - Object { - "content": - - - , - "id": "threat-intel", - "name": "Threat intel", - }, + "compressed": true, + "field": "state", + "multiSelect": "or", + "name": "Status", + "options": Array [], + "type": "field_value_selection", + }, + ], + } + } + selection={ + Object { + "onSelectionChange": [Function], + "selectable": [Function], + "selectableMessage": [Function], + } + } + sorting={ + Object { + "sort": Object { + "direction": "dsc", + "field": "start_time", + }, + } + } + tableLayout="fixed" + /> + + , + "id": "correlations", + "name": +
- - - , - "id": "correlations", - "name": + + Correlations + + +
+
, + }, + ] + } + > +
+ +
+ + + + + + + + + +
+
+
+ +
+ + +
-
- +
-
- - - - +
+ + + +
+ + + +
+ + + + +
+ + + + + +
+
+
+
+
+
+
+
+ +
+ +
+ + +
- - - + +
+

+ No alerts +

+
+
+ + + + +
+ + +
+

+ +

+ Adjust the time range to see more results or create alert triggers in your + + + + detectors + + + to generate alerts. +
+ +

+
+
+ + +
+ +
+
+
+ +
+
+ +
+ + + Acknowledge + , + ] + } + title="Alerts" + > + +
+ +
+ +
+ +
+

+ Alerts +

+
+
+
+
+ - + + +
- - - - - + +
+ +
+
- + + +
+
- -
- spec renders the component 1`] = ` search={ Object { "box": Object { + "compressed": true, "placeholder": "Search alerts", "schema": true, }, "filters": Array [ Object { + "compressed": true, "field": "severity", "multiSelect": "or", "name": "Alert severity", @@ -1870,6 +2219,7 @@ exports[` spec renders the component 1`] = ` "type": "field_value_selection", }, Object { + "compressed": true, "field": "state", "multiSelect": "or", "name": "Status", @@ -1900,6 +2250,7 @@ exports[` spec renders the component 1`] = ` spec renders the component 1`] = ` filters={ Array [ Object { + "compressed": true, "field": "severity", "multiSelect": "or", "name": "Alert severity", @@ -1933,6 +2285,7 @@ exports[` spec renders the component 1`] = ` "type": "field_value_selection", }, Object { + "compressed": true, "field": "state", "multiSelect": "or", "name": "Status", @@ -1959,6 +2312,7 @@ exports[` spec renders the component 1`] = ` className="euiFlexItem euiSearchBar__searchHolder" > spec renders the component 1`] = ` > spec renders the component 1`] = ` placeholder="Search alerts" >
spec renders the component 1`] = ` > spec renders the component 1`] = ` /> @@ -2011,7 +2365,7 @@ exports[` spec renders the component 1`] = ` className="euiFormControlLayoutIcons" > spec renders the component 1`] = `
- -
+ +
- - +
+
diff --git a/public/pages/Correlations/containers/CorrelationRules.tsx b/public/pages/Correlations/containers/CorrelationRules.tsx index b50e435bf..63e9c28d9 100644 --- a/public/pages/Correlations/containers/CorrelationRules.tsx +++ b/public/pages/Correlations/containers/CorrelationRules.tsx @@ -109,7 +109,7 @@ export const CorrelationRules: React.FC = (props: Correla return ( <> {isDeleteModalVisible && deleteModal ? deleteModal : null} - + @@ -120,7 +120,6 @@ export const CorrelationRules: React.FC = (props: Correla {createRuleAction} - diff --git a/public/pages/Correlations/containers/CorrelationsContainer.tsx b/public/pages/Correlations/containers/CorrelationsContainer.tsx index a5ff8eb4a..87e691c34 100644 --- a/public/pages/Correlations/containers/CorrelationsContainer.tsx +++ b/public/pages/Correlations/containers/CorrelationsContainer.tsx @@ -454,7 +454,11 @@ export class Correlations extends React.ComponentNo correlations found } - body={

There are no correlated findings in the system.

} + body={ + +

There are no correlated findings in the system.

+
+ } actions={[ Create correlation rule @@ -548,7 +552,7 @@ export class Correlations extends React.Component ) : null} - +
- Reset filters + + Reset filters +
diff --git a/public/pages/CreateDetector/containers/CreateDetector.tsx b/public/pages/CreateDetector/containers/CreateDetector.tsx index c029da6af..ffc7d344a 100644 --- a/public/pages/CreateDetector/containers/CreateDetector.tsx +++ b/public/pages/CreateDetector/containers/CreateDetector.tsx @@ -386,7 +386,7 @@ export default class CreateDetector extends Component

Create detector

- + {this.getStepContent()} diff --git a/public/pages/Detectors/components/DetectorBasicDetailsView/__snapshots__/DetectorBasicDetailsView.test.tsx.snap b/public/pages/Detectors/components/DetectorBasicDetailsView/__snapshots__/DetectorBasicDetailsView.test.tsx.snap index 5c7e3e9ec..dfe1ee3b8 100644 --- a/public/pages/Detectors/components/DetectorBasicDetailsView/__snapshots__/DetectorBasicDetailsView.test.tsx.snap +++ b/public/pages/Detectors/components/DetectorBasicDetailsView/__snapshots__/DetectorBasicDetailsView.test.tsx.snap @@ -7,7 +7,7 @@ Object {
-

+

Detector details -

+
-

+

Detector details -

+
spec renders the component 1`] = ` className="" style={ Object { - "paddingLeft": "0px", - "paddingRight": "0px", + "padding": "16px", } } > @@ -224,8 +223,7 @@ exports[` spec renders the component 1`] = ` className="euiPanel euiPanel--paddingMedium euiPanel--borderRadiusMedium euiPanel--plain euiPanel--hasShadow" style={ Object { - "paddingLeft": "0px", - "paddingRight": "0px", + "padding": "16px", } } > @@ -256,9 +254,9 @@ exports[` spec renders the component 1`] = `
-

+

Active rules (2) -

+
@@ -424,11 +422,13 @@ exports[` spec renders the component 1`] = ` search={ Object { "box": Object { + "compressed": true, "placeholder": "Search rules", "schema": true, }, "filters": Array [ Object { + "compressed": true, "field": "category", "multiSelect": "or", "name": "Log type", @@ -436,6 +436,7 @@ exports[` spec renders the component 1`] = ` "type": "field_value_selection", }, Object { + "compressed": true, "field": "level", "multiSelect": "or", "name": "Rule severity", @@ -489,6 +490,7 @@ exports[` spec renders the component 1`] = ` "type": "field_value_selection", }, Object { + "compressed": true, "field": "source", "multiSelect": "or", "name": "Source", @@ -512,6 +514,7 @@ exports[` spec renders the component 1`] = ` spec renders the component 1`] = ` filters={ Array [ Object { + "compressed": true, "field": "category", "multiSelect": "or", "name": "Log type", @@ -545,6 +549,7 @@ exports[` spec renders the component 1`] = ` "type": "field_value_selection", }, Object { + "compressed": true, "field": "level", "multiSelect": "or", "name": "Rule severity", @@ -598,6 +603,7 @@ exports[` spec renders the component 1`] = ` "type": "field_value_selection", }, Object { + "compressed": true, "field": "source", "multiSelect": "or", "name": "Source", @@ -631,6 +637,7 @@ exports[` spec renders the component 1`] = ` className="euiFlexItem euiSearchBar__searchHolder" > spec renders the component 1`] = ` > spec renders the component 1`] = ` placeholder="Search rules" >
spec renders the component 1`] = ` > spec renders the component 1`] = ` /> @@ -683,7 +690,7 @@ exports[` spec renders the component 1`] = ` className="euiFormControlLayoutIcons" > spec renders the component 1`] = `
diff --git a/public/pages/Detectors/containers/Detector/DetectorDetails.tsx b/public/pages/Detectors/containers/Detector/DetectorDetails.tsx index c079f427d..307a025b4 100644 --- a/public/pages/Detectors/containers/Detector/DetectorDetails.tsx +++ b/public/pages/Detectors/containers/Detector/DetectorDetails.tsx @@ -514,10 +514,10 @@ export class DetectorDetails extends React.Component - + {this.renderTabs()} - + {selectedTabContent} ); diff --git a/public/pages/Detectors/containers/Detector/__snapshots__/DetectorDetails.test.tsx.snap b/public/pages/Detectors/containers/Detector/__snapshots__/DetectorDetails.test.tsx.snap index 868286b83..64ec5f51a 100644 --- a/public/pages/Detectors/containers/Detector/__snapshots__/DetectorDetails.test.tsx.snap +++ b/public/pages/Detectors/containers/Detector/__snapshots__/DetectorDetails.test.tsx.snap @@ -545,10 +545,10 @@ exports[` spec renders the component 1`] = `
@@ -622,10 +622,10 @@ exports[` spec renders the component 1`] = `
spec renders the component 1`] = ` className="" style={ Object { - "paddingLeft": "0px", - "paddingRight": "0px", + "padding": "16px", } } > @@ -1505,8 +1504,7 @@ exports[` spec renders the component 1`] = ` className="euiPanel euiPanel--paddingMedium euiPanel--borderRadiusMedium euiPanel--plain euiPanel--hasShadow" style={ Object { - "paddingLeft": "0px", - "paddingRight": "0px", + "padding": "16px", } } > @@ -1537,9 +1535,9 @@ exports[` spec renders the component 1`] = `
-

+

Detector details -

+
@@ -2330,13 +2328,6 @@ exports[` spec renders the component 1`] = ` className="euiSpacer euiSpacer--m" />
- -
- spec renders the component 1`] = ` className="" style={ Object { - "paddingLeft": "0px", - "paddingRight": "0px", + "padding": "16px", } } > @@ -2789,8 +2779,7 @@ exports[` spec renders the component 1`] = ` className="euiPanel euiPanel--paddingMedium euiPanel--borderRadiusMedium euiPanel--plain euiPanel--hasShadow" style={ Object { - "paddingLeft": "0px", - "paddingRight": "0px", + "padding": "16px", } } > @@ -2821,9 +2810,9 @@ exports[` spec renders the component 1`] = `
-

+

Active rules (2) -

+
@@ -2989,11 +2978,13 @@ exports[` spec renders the component 1`] = ` search={ Object { "box": Object { + "compressed": true, "placeholder": "Search rules", "schema": true, }, "filters": Array [ Object { + "compressed": true, "field": "category", "multiSelect": "or", "name": "Log type", @@ -3001,6 +2992,7 @@ exports[` spec renders the component 1`] = ` "type": "field_value_selection", }, Object { + "compressed": true, "field": "level", "multiSelect": "or", "name": "Rule severity", @@ -3054,6 +3046,7 @@ exports[` spec renders the component 1`] = ` "type": "field_value_selection", }, Object { + "compressed": true, "field": "source", "multiSelect": "or", "name": "Source", @@ -3077,6 +3070,7 @@ exports[` spec renders the component 1`] = ` spec renders the component 1`] = ` filters={ Array [ Object { + "compressed": true, "field": "category", "multiSelect": "or", "name": "Log type", @@ -3110,6 +3105,7 @@ exports[` spec renders the component 1`] = ` "type": "field_value_selection", }, Object { + "compressed": true, "field": "level", "multiSelect": "or", "name": "Rule severity", @@ -3163,6 +3159,7 @@ exports[` spec renders the component 1`] = ` "type": "field_value_selection", }, Object { + "compressed": true, "field": "source", "multiSelect": "or", "name": "Source", @@ -3196,6 +3193,7 @@ exports[` spec renders the component 1`] = ` className="euiFlexItem euiSearchBar__searchHolder" > spec renders the component 1`] = ` > spec renders the component 1`] = ` placeholder="Search rules" >
spec renders the component 1`] = ` > spec renders the component 1`] = ` /> @@ -3248,7 +3246,7 @@ exports[` spec renders the component 1`] = ` className="euiFormControlLayoutIcons" > spec renders the component 1`] = `
@@ -1252,13 +1250,6 @@ exports[` spec renders the component 1`] = ` className="euiSpacer euiSpacer--m" /> - -
- spec renders the component 1`] = ` className="" style={ Object { - "paddingLeft": "0px", - "paddingRight": "0px", + "padding": "16px", } } > @@ -1486,8 +1476,7 @@ exports[` spec renders the component 1`] = ` className="euiPanel euiPanel--paddingMedium euiPanel--borderRadiusMedium euiPanel--plain euiPanel--hasShadow" style={ Object { - "paddingLeft": "0px", - "paddingRight": "0px", + "padding": "16px", } } > @@ -1518,9 +1507,9 @@ exports[` spec renders the component 1`] = `
-

+

Active rules (2) -

+
@@ -1686,11 +1675,13 @@ exports[` spec renders the component 1`] = ` search={ Object { "box": Object { + "compressed": true, "placeholder": "Search rules", "schema": true, }, "filters": Array [ Object { + "compressed": true, "field": "category", "multiSelect": "or", "name": "Log type", @@ -1698,6 +1689,7 @@ exports[` spec renders the component 1`] = ` "type": "field_value_selection", }, Object { + "compressed": true, "field": "level", "multiSelect": "or", "name": "Rule severity", @@ -1751,6 +1743,7 @@ exports[` spec renders the component 1`] = ` "type": "field_value_selection", }, Object { + "compressed": true, "field": "source", "multiSelect": "or", "name": "Source", @@ -1774,6 +1767,7 @@ exports[` spec renders the component 1`] = ` spec renders the component 1`] = ` filters={ Array [ Object { + "compressed": true, "field": "category", "multiSelect": "or", "name": "Log type", @@ -1807,6 +1802,7 @@ exports[` spec renders the component 1`] = ` "type": "field_value_selection", }, Object { + "compressed": true, "field": "level", "multiSelect": "or", "name": "Rule severity", @@ -1860,6 +1856,7 @@ exports[` spec renders the component 1`] = ` "type": "field_value_selection", }, Object { + "compressed": true, "field": "source", "multiSelect": "or", "name": "Source", @@ -1893,6 +1890,7 @@ exports[` spec renders the component 1`] = ` className="euiFlexItem euiSearchBar__searchHolder" > spec renders the component 1`] = ` > spec renders the component 1`] = ` placeholder="Search rules" >
spec renders the component 1`] = ` > spec renders the component 1`] = ` /> @@ -1945,7 +1943,7 @@ exports[` spec renders the component 1`] = ` className="euiFormControlLayoutIcons" > spec renders the component 1`] = `
- - -
- - Actions - - } - closePopover={[Function]} - data-test-subj="detectorsActionsPopover" - display="inlineBlock" - hasArrow={true} - id="detectorsActionsPopover" - isOpen={false} - ownFocus={true} - panelPaddingSize="none" - > -
-
- - - - - - - -
-
-
-
-
-
spec renders the component 1`] = ` data-test-subj="detectorsCreateButton" fill={true} href="#/create-detector" + iconGap="s" + iconSide="left" + iconType="plus" > spec renders the component 1`] = ` element="a" fill={true} href="#/create-detector" + iconGap="s" + iconSide="left" + iconType="plus" isDisabled={false} rel="noreferrer" size="s" @@ -375,8 +142,9 @@ exports[` spec renders the component 1`] = ` > spec renders the component 1`] = ` } > + + EuiIconMock + @@ -405,13 +181,6 @@ exports[` spec renders the component 1`] = `
- -
-
@@ -689,12 +458,14 @@ exports[` spec renders the component 1`] = ` search={ Object { "box": Object { + "compressed": true, "incremental": true, "placeholder": "Search threat detectors", "schema": true, }, "filters": Array [ Object { + "compressed": true, "field": "status", "multiSelect": "or", "name": "Status", @@ -707,6 +478,7 @@ exports[` spec renders the component 1`] = ` "type": "field_value_selection", }, Object { + "compressed": true, "field": "logType", "multiSelect": "or", "name": "Log type", @@ -714,6 +486,55 @@ exports[` spec renders the component 1`] = ` "type": "field_value_selection", }, ], + "toolsLeft": Array [ + + Delete detectors + , + ], + "toolsRight": Array [ + + Refresh + , + + Actions + + } + closePopover={[Function]} + data-test-subj="detectorsActionsPopover" + display="inlineBlock" + hasArrow={true} + id="detectorsActionsPopover" + isOpen={false} + ownFocus={true} + panelPaddingSize="none" + > + + , + ], } } selection={ @@ -735,6 +556,7 @@ exports[` spec renders the component 1`] = ` spec renders the component 1`] = ` filters={ Array [ Object { + "compressed": true, "field": "status", "multiSelect": "or", "name": "Status", @@ -774,6 +597,7 @@ exports[` spec renders the component 1`] = ` "type": "field_value_selection", }, Object { + "compressed": true, "field": "logType", "multiSelect": "or", "name": "Log type", @@ -783,6 +607,59 @@ exports[` spec renders the component 1`] = ` ] } onChange={[Function]} + toolsLeft={ + Array [ + + Delete detectors + , + ] + } + toolsRight={ + Array [ + + Refresh + , + + Actions + + } + closePopover={[Function]} + data-test-subj="detectorsActionsPopover" + display="inlineBlock" + hasArrow={true} + id="detectorsActionsPopover" + isOpen={false} + ownFocus={true} + panelPaddingSize="none" + > + + , + ] + } > spec renders the component 1`] = `
+ +
+ + + + + + + +
+
spec renders the component 1`] = ` className="euiFlexItem euiSearchBar__searchHolder" > spec renders the component 1`] = ` > spec renders the component 1`] = ` placeholder="Search threat detectors" >
spec renders the component 1`] = ` > spec renders the component 1`] = ` /> @@ -852,7 +812,7 @@ exports[` spec renders the component 1`] = ` className="euiFormControlLayoutIcons" > spec renders the component 1`] = `
+ +
+ + + + + + + +
+
+ +
+ + Actions + + } + closePopover={[Function]} + data-test-subj="detectorsActionsPopover" + display="inlineBlock" + hasArrow={true} + id="detectorsActionsPopover" + isOpen={false} + ownFocus={true} + panelPaddingSize="none" + > +
+
+ + + + + + + +
+
+
+
+
diff --git a/public/pages/Findings/components/FindingsTable/FindingsTable.tsx b/public/pages/Findings/components/FindingsTable/FindingsTable.tsx index 1a66a1c2d..005e32663 100644 --- a/public/pages/Findings/components/FindingsTable/FindingsTable.tsx +++ b/public/pages/Findings/components/FindingsTable/FindingsTable.tsx @@ -271,12 +271,14 @@ export default class FindingsTable extends Component { const name = parseAlertSeverityToOption(severity)?.label || capitalizeFirstLetter(severity); @@ -288,6 +290,7 @@ export default class FindingsTable extends Component ({ value: type, name: formatRuleType(type), @@ -298,6 +301,7 @@ export default class FindingsTable extends Component = }, ]; - return ; + const search = { + box: { + compressed: true, + }, + }; + + return ; }; diff --git a/public/pages/Findings/containers/Findings/Findings.tsx b/public/pages/Findings/containers/Findings/Findings.tsx index c25d5c424..aeebd7d3e 100644 --- a/public/pages/Findings/containers/Findings/Findings.tsx +++ b/public/pages/Findings/containers/Findings/Findings.tsx @@ -564,22 +564,26 @@ class Findings extends Component { ), content: ( <> - - + + {this.getFindingsGraph(findings, loading)} + + + + ), }, @@ -595,10 +599,14 @@ class Findings extends Component { ), content: ( <> - - + + {this.getFindingsGraph(findings, loading)} + + + + ), }, @@ -617,7 +625,7 @@ class Findings extends Component { ); return ( - + {
{datePicker} - - - - - - {this.createGroupByControl()} - - - {!findings || findings.length === 0 ? ( - -

No findings

- - } - body={ - - {this.state.findingStateByTabId[this.state.selectedTabId].emptyPromptBody} - - } - /> - ) : ( - - )} -
-
-
- - -
- - id === selectedTabId) ?? tabs[0]} - onTabClick={(tab) => { - this.setState({ selectedTabId: tab.id as FindingTabId }); - }} - /> - + id === selectedTabId) ?? tabs[0]} + onTabClick={(tab) => { + this.setState({ selectedTabId: tab.id as FindingTabId }); + }} + /> ); } + + private getFindingsGraph(findings: ThreatIntelFinding[] | FindingItemType[], loading: boolean) { + return ( + + + {this.createGroupByControl()} + + {!findings || findings.length === 0 ? ( + +

No findings

+ + } + body={ + + {this.state.findingStateByTabId[this.state.selectedTabId].emptyPromptBody} + + } + /> + ) : ( + + )} +
+
+
+ ); + } } export default withRouter(Findings); diff --git a/public/pages/LogTypes/utils/helpers.tsx b/public/pages/LogTypes/utils/helpers.tsx index 85f1e084d..6545eda1e 100644 --- a/public/pages/LogTypes/utils/helpers.tsx +++ b/public/pages/LogTypes/utils/helpers.tsx @@ -65,12 +65,14 @@ export const getLogTypesTableSearchConfig = (): Search => { box: { placeholder: 'Search log types', schema: true, + compressed: true, }, filters: [ { type: 'field_value_selection', field: 'category', name: 'Category', + compressed: true, multiSelect: 'or', options: logTypeCategories.map((category) => ({ value: category, @@ -80,6 +82,7 @@ export const getLogTypesTableSearchConfig = (): Search => { type: 'field_value_selection', field: 'source', name: 'Source', + compressed: true, multiSelect: 'or', options: ruleSource.map((source: string) => ({ value: source, diff --git a/public/pages/Main/Main.tsx b/public/pages/Main/Main.tsx index e3a548dc8..fc56a0fd7 100644 --- a/public/pages/Main/Main.tsx +++ b/public/pages/Main/Main.tsx @@ -25,6 +25,7 @@ import { DATE_TIME_FILTER_KEY, ROUTES, dataSourceObservable, + OS_NOTIFICATION_PLUGIN, } from '../../utils/constants'; import { CoreServicesConsumer } from '../../components/core_services'; import Findings from '../Findings'; @@ -66,9 +67,15 @@ import { ThreatIntelOverview } from '../ThreatIntel/containers/Overview/ThreatIn import { AddThreatIntelSource } from '../ThreatIntel/containers/AddThreatIntelSource/AddThreatIntelSource'; import { ThreatIntelScanConfigForm } from '../ThreatIntel/containers/ScanConfiguration/ThreatIntelScanConfigForm'; import { ThreatIntelSource } from '../ThreatIntel/containers/ThreatIntelSource/ThreatIntelSource'; -import queryString from 'query-string'; -import { dataSourceFilterFn } from '../../utils/helpers'; +import { parse } from 'query-string'; +import { + dataSourceFilterFn, + getPlugins, + setIsNotificationPluginInstalled, +} from '../../utils/helpers'; import { GettingStartedContent } from '../Overview/components/GettingStarted/GettingStartedContent'; +import { BrowserServices } from '../../models/interfaces'; +import { CHANNEL_TYPES } from '../CreateDetector/components/ConfigureAlerts/utils/constants'; enum Navigation { SecurityAnalytics = 'Security Analytics', @@ -108,6 +115,7 @@ interface MainProps extends RouteComponentProps { setActionMenu: AppMountParameters['setHeaderActionMenu']; multiDataSourceEnabled: boolean; dataSourceManagement?: DataSourceManagementPluginSetup; + services: BrowserServices; } interface MainState { @@ -150,16 +158,12 @@ export default class Main extends Component { const { dataSourceId: parsedDataSourceId, dataSourceLabel: parsedDataSourceLabel, - } = queryString.parse(this.props.location.search) as { + } = parse(this.props.location.search, { decode: false }) as { dataSourceId: string; dataSourceLabel: string; }; dataSourceId = parsedDataSourceId; dataSourceLabel = parsedDataSourceLabel || ''; - - if (dataSourceId) { - dataSourceObservable.next({ id: dataSourceId, label: dataSourceLabel }); - } } this.state = { @@ -267,6 +271,7 @@ export default class Main extends Component { onDataSourceSelected = (sources: DataSourceOption[]) => { const { selectedDataSource: dataSource, dataSourceLoading } = this.state; + const { services } = this.props; if ( sources[0] && (dataSource?.id !== sources[0].id || dataSource?.label !== sources[0].label) @@ -275,11 +280,21 @@ export default class Main extends Component { this.setState({ selectedDataSource: { ...sources[0] }, }); + dataSourceObservable.next(dataSourceInfo.activeDataSource); + + services.notificationsService.getServerFeatures().then((response) => { + if (response.ok) { + CHANNEL_TYPES.splice(0, CHANNEL_TYPES.length, ...response.response); + } + }); + + getPlugins(services.opensearchService).then((plugins): void => { + setIsNotificationPluginInstalled(plugins.includes(OS_NOTIFICATION_PLUGIN)); + }); + + DataStore.logTypes.getLogTypes(); } - dataSourceObservable.next({ - id: this.state.selectedDataSource.id, - label: this.state.selectedDataSource.label, - }); + if (dataSourceLoading) { this.setState({ dataSourceLoading: false }); } diff --git a/public/pages/Overview/components/Widgets/RecentAlertsWidget.tsx b/public/pages/Overview/components/Widgets/RecentAlertsWidget.tsx index d961ce94f..6ea5e8646 100644 --- a/public/pages/Overview/components/Widgets/RecentAlertsWidget.tsx +++ b/public/pages/Overview/components/Widgets/RecentAlertsWidget.tsx @@ -3,12 +3,12 @@ * SPDX-License-Identifier: Apache-2.0 */ -import { EuiBasicTableColumn, EuiSmallButton, EuiEmptyPrompt, EuiText } from '@elastic/eui'; +import { EuiBasicTableColumn, EuiSmallButton } from '@elastic/eui'; import { ROUTES, SortDirection } from '../../../../utils/constants'; import React, { useEffect, useState } from 'react'; import { TableWidget } from './TableWidget'; import { WidgetContainer } from './WidgetContainer'; -import { getAlertSeverityBadge, renderTime } from '../../../../utils/helpers'; +import { getAlertSeverityBadge, getEuiEmptyPrompt, renderTime } from '../../../../utils/helpers'; import { OverviewAlertItem } from '../../../../../types'; const columns: EuiBasicTableColumn[] = [ @@ -44,9 +44,6 @@ export const RecentAlertsWidget: React.FC = ({ loading = false, }) => { const [alertItems, setAlertItems] = useState([]); - const [widgetEmptyMessage, setwidgetEmptyMessage] = useState( - undefined - ); useEffect(() => { items.sort((a, b) => { @@ -55,18 +52,6 @@ export const RecentAlertsWidget: React.FC = ({ return timeB - timeA; }); setAlertItems(items.slice(0, 20)); - setwidgetEmptyMessage( - items.length > 0 ? undefined : ( - - No recent alerts.Adjust the time range to - see more results. - - } - /> - ) - ); }, [items]); const actions = React.useMemo( @@ -76,14 +61,16 @@ export const RecentAlertsWidget: React.FC = ({ return ( - + {alertItems.length === 0 ? ( + getEuiEmptyPrompt('No recent alerts.') + ) : ( + + )} ); }; diff --git a/public/pages/Overview/components/Widgets/RecentFindingsWidget.tsx b/public/pages/Overview/components/Widgets/RecentFindingsWidget.tsx index a0dcf8fca..96edb94b0 100644 --- a/public/pages/Overview/components/Widgets/RecentFindingsWidget.tsx +++ b/public/pages/Overview/components/Widgets/RecentFindingsWidget.tsx @@ -3,12 +3,12 @@ * SPDX-License-Identifier: Apache-2.0 */ -import { EuiBasicTableColumn, EuiSmallButton, EuiEmptyPrompt, EuiText } from '@elastic/eui'; +import { EuiBasicTableColumn, EuiSmallButton } from '@elastic/eui'; import { FINDINGS_NAV_ID, ROUTES, SortDirection } from '../../../../utils/constants'; import React, { useEffect, useState } from 'react'; import { TableWidget } from './TableWidget'; import { WidgetContainer } from './WidgetContainer'; -import { renderTime, getSeverityBadge } from '../../../../utils/helpers'; +import { renderTime, getSeverityBadge, getEuiEmptyPrompt } from '../../../../utils/helpers'; import { OverviewFindingItem } from '../../../../../types'; import { getApplication, getUseUpdatedUx } from '../../../../services/utils/constants'; @@ -53,27 +53,12 @@ export const RecentFindingsWidget: React.FC = ({ loading = false, }) => { const [findingItems, setFindingItems] = useState([]); - const [widgetEmptyMessage, setWidgetEmptyMessage] = useState( - undefined - ); useEffect(() => { items.sort((a, b) => { return b.time - a.time; }); setFindingItems(items.slice(0, 20)); - setWidgetEmptyMessage( - items.length > 0 ? undefined : ( - - No recent findings.Adjust the time range to - see more results. - - } - /> - ) - ); }, [items]); const actions = React.useMemo(() => { @@ -83,14 +68,16 @@ export const RecentFindingsWidget: React.FC = ({ return ( - + {findingItems.length === 0 ? ( + getEuiEmptyPrompt('No recent findings.') + ) : ( + + )} ); }; diff --git a/public/pages/Overview/components/Widgets/RecentThreatIntelFindingsWidget.tsx b/public/pages/Overview/components/Widgets/RecentThreatIntelFindingsWidget.tsx index c4e48b664..a6e100e3d 100644 --- a/public/pages/Overview/components/Widgets/RecentThreatIntelFindingsWidget.tsx +++ b/public/pages/Overview/components/Widgets/RecentThreatIntelFindingsWidget.tsx @@ -3,7 +3,7 @@ * SPDX-License-Identifier: Apache-2.0 */ -import { EuiBasicTableColumn, EuiSmallButton, EuiEmptyPrompt, EuiText } from '@elastic/eui'; +import { EuiBasicTableColumn, EuiSmallButton } from '@elastic/eui'; import { DEFAULT_EMPTY_DATA, FINDINGS_NAV_ID, @@ -14,9 +14,9 @@ import { import React, { useEffect, useState } from 'react'; import { TableWidget } from './TableWidget'; import { WidgetContainer } from './WidgetContainer'; -import { renderTime } from '../../../../utils/helpers'; +import { getEuiEmptyPrompt, renderTime } from '../../../../utils/helpers'; import { ThreatIntelFinding } from '../../../../../types'; -import { getApplication } from '../../../../services/utils/constants'; +import { getApplication, getUseUpdatedUx } from '../../../../services/utils/constants'; import { IocLabel, ThreatIntelIocType } from '../../../../../common/constants'; const columns: EuiBasicTableColumn[] = [ @@ -55,51 +55,37 @@ export const RecentThreatIntelFindingsWidget: React.FC { const [findingItems, setFindingItems] = useState([]); - const [widgetEmptyMessage, setWidgetEmptyMessage] = useState( - undefined - ); useEffect(() => { items.sort((a, b) => { return b.timestamp - a.timestamp; }); setFindingItems(items.slice(0, 20)); - setWidgetEmptyMessage( - items.length > 0 ? undefined : ( - - No recent findings.Adjust the time range to - see more results. - - } - /> - ) - ); }, [items]); - const threatIntelFindingsUrl = `${getApplication().getUrlForApp(FINDINGS_NAV_ID, { - path: `#${ROUTES.FINDINGS}`, - })}?detectionType=${FindingTabId.ThreatIntel}`; - const actions = React.useMemo( - () => [ - getApplication().navigateToUrl(threatIntelFindingsUrl)}> + const actions = React.useMemo(() => { + const baseUrl = getUseUpdatedUx() ? getApplication().getUrlForApp(FINDINGS_NAV_ID) : ''; + return [ + View all , - ], - [] - ); + ]; + }, []); return ( - + {findingItems.length === 0 ? ( + getEuiEmptyPrompt('No recent findings.') + ) : ( + + )} ); }; diff --git a/public/pages/Overview/components/Widgets/Summary.tsx b/public/pages/Overview/components/Widgets/Summary.tsx index 0270e47c3..910aa555b 100644 --- a/public/pages/Overview/components/Widgets/Summary.tsx +++ b/public/pages/Overview/components/Widgets/Summary.tsx @@ -170,12 +170,16 @@ export const Summary: React.FC = ({ {activeAlerts === 0 && totalFindings === 0 ? (

No alerts and findings found

} + title={ + +

No alerts and findings found

+
+ } body={ <>

- Adjust the time range to see more results or create a
+ Adjust the time range to see more results or create a
detector to generate findings.

@@ -183,6 +187,9 @@ export const Summary: React.FC = ({ href={`#${ROUTES.DETECTORS_CREATE}`} fill={true} data-test-subj={'detectorsCreateButton'} + iconType="plus" + iconSide="left" + iconGap="s" > Create a detector
diff --git a/public/pages/Overview/components/Widgets/TopRulesWidget.tsx b/public/pages/Overview/components/Widgets/TopRulesWidget.tsx index 29bb45a1d..b6ef0a512 100644 --- a/public/pages/Overview/components/Widgets/TopRulesWidget.tsx +++ b/public/pages/Overview/components/Widgets/TopRulesWidget.tsx @@ -3,12 +3,11 @@ * SPDX-License-Identifier: Apache-2.0 */ -import { renderVisualization } from '../../../../utils/helpers'; +import { getEuiEmptyPrompt, renderVisualization } from '../../../../utils/helpers'; import React, { useEffect } from 'react'; import { WidgetContainer } from './WidgetContainer'; import { getTopRulesVisualizationSpec } from '../../utils/helpers'; import { ChartContainer } from '../../../../components/Charts/ChartContainer'; -import { EuiEmptyPrompt, EuiText } from '@elastic/eui'; import { OverviewFindingItem } from '../../../../../types'; export interface TopRulesWidgetProps { @@ -37,21 +36,9 @@ export const TopRulesWidget: React.FC = ({ findings, loadin return ( {findings.length === 0 ? ( - -

- - No findings with detection rules.Adjust - the time range to see more results. - -

-
- } - /> + getEuiEmptyPrompt('No findings with detection rules.') ) : ( - + )} ); diff --git a/public/pages/Overview/containers/Overview/Overview.tsx b/public/pages/Overview/containers/Overview/Overview.tsx index 9c99c28bc..398fe6951 100644 --- a/public/pages/Overview/containers/Overview/Overview.tsx +++ b/public/pages/Overview/containers/Overview/Overview.tsx @@ -39,8 +39,10 @@ import { OverviewProps, OverviewState, OverviewViewModel } from '../../../../../ import { setBreadcrumbs } from '../../../../utils/helpers'; import { PageHeader } from '../../../../components/PageHeader/PageHeader'; import { getOverviewStatsProps, getOverviewsCardsProps } from '../../utils/constants'; -import { getUseUpdatedUx } from '../../../../services/utils/constants'; +import { getChrome, getUseUpdatedUx } from '../../../../services/utils/constants'; import { RecentThreatIntelFindingsWidget } from '../../components/Widgets/RecentThreatIntelFindingsWidget'; +import { useObservable } from 'react-use'; +import { SECURITY_ANALYTICS_USE_CASE_ID } from '../../../../../../../src/core/public'; export const Overview: React.FC = (props) => { const { @@ -101,15 +103,17 @@ export const Overview: React.FC = (props) => { () => new OverviewViewModelActor(saContext?.services, context?.notifications!), [saContext?.services, context] ); + const currentNavGroup = useObservable(getChrome().navGroup.getCurrentNavGroup$()); + const isSecurityAnalyticsUseCase = currentNavGroup?.id === SECURITY_ANALYTICS_USE_CASE_ID; useEffect(() => { - setBreadcrumbs([BREADCRUMBS.OVERVIEW]); + setBreadcrumbs(isSecurityAnalyticsUseCase ? [ BREADCRUMBS.OVERVIEW] : [{...BREADCRUMBS.OVERVIEW, text: 'Security Analytics overview'}]); overviewViewModelActor.registerRefreshHandler(updateState, true /* allowPartialResults */); overviewViewModelActor.registerRefreshHandler( onLoadingComplete, false /* allowPartialResults */ ); - }, []); + }, [isSecurityAnalyticsUseCase]); useEffect(() => { const abortController = new AbortController(); @@ -216,6 +220,9 @@ export const Overview: React.FC = (props) => { href={`#${ROUTES.DETECTORS_CREATE}`} fill={true} data-test-subj={'detectorsCreateButton'} + iconType="plus" + iconSide="left" + iconGap="s" > Create detector @@ -240,7 +247,7 @@ export const Overview: React.FC = (props) => { }; return ( - + = (props) => { {datePicker} {createDetectorAction} - {getUseUpdatedUx() && ( @@ -267,7 +273,7 @@ export const Overview: React.FC = (props) => { {getOverviewsCardsProps().map((p, idx) => ( - + ))} diff --git a/public/pages/Overview/utils/constants.ts b/public/pages/Overview/utils/constants.ts index f3e51317e..071e6e595 100644 --- a/public/pages/Overview/utils/constants.ts +++ b/public/pages/Overview/utils/constants.ts @@ -3,12 +3,11 @@ * SPDX-License-Identifier: Apache-2.0 */ -import { EuiCardProps, EuiStatProps } from '@elastic/eui'; +import { EuiCardProps, EuiStatProps, EuiIcon, EuiTextColor } from '@elastic/eui'; +import React from 'react'; import { - CORRELATIONS_RULE_NAV_ID, DETECTORS_NAV_ID, - GETTING_STARTED_NAV_ID, - THREAT_ALERTS_NAV_ID, + GET_STARTED_NAV_ID, THREAT_INTEL_NAV_ID, } from '../../../utils/constants'; import { getApplication } from '../../../services/utils/constants'; @@ -22,70 +21,44 @@ export const moreLink = 'https://opensearch.org/docs/latest/security-analytics/' export const getOverviewsCardsProps = (): EuiCardProps[] => [ { - title: 'Configure Security Analytics', - description: 'Set up tools and components to get started.', - selectable: { - onClick: () => { - getApplication().navigateToApp(GETTING_STARTED_NAV_ID); - }, - children: 'Getting started guide', - isDisabled: false, + icon: React.createElement(EuiIcon, { type: 'rocket', size: "l", color: "primary" }), + title: '', + description: 'Configure Security Analytics tools and components to get started.', + onClick: () => { + getApplication().navigateToApp(GET_STARTED_NAV_ID); }, + footer: React.createElement(EuiTextColor, { color: 'subdued' }, 'Get started guide'), + className: 'usecaseOverviewGettingStartedCard', }, { - title: 'Uncover security findings', - description: 'Identify security threats in your log data with detection rules.', - selectable: { - onClick: () => { - getApplication().navigateToApp(DETECTORS_NAV_ID); - }, - children: 'Threat detectors', - isDisabled: false, - }, - }, - { - title: 'Discover insights', - description: 'Explore data to uncover insights.', - selectable: { - onClick: () => { - getApplication().navigateToApp('discover'); - }, - children: 'Discover', - isDisabled: false, + icon: React.createElement(EuiIcon, { type: 'compass', size: "l", color: "primary" }), + title: '', + description: 'Explore data to uncover and discover insights.', + onClick: () => { + getApplication().navigateToApp('discover'); }, + footer: React.createElement(EuiTextColor, { color: 'subdued' }, 'Discover'), + className: 'usecaseOverviewGettingStartedCard', }, { - title: 'Get notified', - description: 'Receive timely notifications with detector-driven alerts.', - selectable: { - onClick: () => { - getApplication().navigateToApp(THREAT_ALERTS_NAV_ID); - }, - children: 'Threat alerts', - isDisabled: false, - }, - }, - { - title: 'Correlate events', - description: 'Detect multi-system threats with correlation rule builder', - selectable: { - onClick: () => { - getApplication().navigateToApp(CORRELATIONS_RULE_NAV_ID); - }, - children: 'Correlation rules', - isDisabled: false, + icon: React.createElement(EuiIcon, { type: 'pulse', size: "l", color: "primary" }), + title: '', + description: 'Identify security threats in your log data with detection rules.', + onClick: () => { + getApplication().navigateToApp(DETECTORS_NAV_ID); }, + footer: React.createElement(EuiTextColor, { color: 'subdued' }, 'Threat detection'), + className: 'usecaseOverviewGettingStartedCard', }, { - title: 'Scan your logs', - description: 'Identify malicious actors from known indicators of compromise.', - selectable: { - onClick: () => { - getApplication().navigateToApp(THREAT_INTEL_NAV_ID); - }, - children: ' Threat intelligence', - isDisabled: false, + icon: React.createElement(EuiIcon, { type: 'radar', size: "l", color: "primary" }), + title: '', + description: 'Scan your log data for malicious actors from known indicators of compromise.', + onClick: () => { + getApplication().navigateToApp(THREAT_INTEL_NAV_ID); }, + footer: React.createElement(EuiTextColor, { color: 'subdued' }, 'Threat intelligence'), + className: 'usecaseOverviewGettingStartedCard', }, ]; @@ -98,7 +71,7 @@ export const getOverviewStatsProps = ({ return [ { title: alerts, - description: 'Total active alerts', + description: 'Total active threat alerts', }, { title: correlations, diff --git a/public/pages/Rules/components/RulesTable/__snapshots__/RulesTable.test.tsx.snap b/public/pages/Rules/components/RulesTable/__snapshots__/RulesTable.test.tsx.snap index 09d948c0f..b32277ed8 100644 --- a/public/pages/Rules/components/RulesTable/__snapshots__/RulesTable.test.tsx.snap +++ b/public/pages/Rules/components/RulesTable/__snapshots__/RulesTable.test.tsx.snap @@ -13,14 +13,14 @@ Object { class="euiFlexItem euiSearchBar__searchHolder" >
+ } + /> + ); +} + export function initializeServices(coreStart: CoreStart, indexPattern: CoreIndexPatternsService) { const { http, savedObjects } = coreStart; diff --git a/types/Alert.ts b/types/Alert.ts index 2d3b56ef5..5e600c57e 100644 --- a/types/Alert.ts +++ b/types/Alert.ts @@ -53,6 +53,7 @@ export type GetAlertsParams = { startIndex?: number; startTime?: number; endTime?: number; + dataSource?: any; } & ( | { detector_id: string; @@ -105,11 +106,10 @@ export interface CorrelationAlertItem { acknowledged_time: string | null; } -export interface CorrelationAlertTableItem extends CorrelationAlertItem{ +export interface CorrelationAlertTableItem extends CorrelationAlertItem { correlation_rule_categories: string[]; } - export interface AlertResponse extends AlertItem { version: number; schema_version: number;