From 1f6de13232dd1fbc6d1dcbd887ce66cdc0496544 Mon Sep 17 00:00:00 2001 From: Michael Olorunnisola Date: Mon, 6 Mar 2023 14:08:28 -0500 Subject: [PATCH] [Security Solution][Investigations] - 8.7 minor fixes (#152284) ## Summary This PR includes minor fixes for the following items by commit **[Timeline ui alignment fix]** https://github.com/elastic/kibana/issues/149017 - https://github.com/elastic/kibana/pull/152284/commits/01281497dcad8f09f22db2c25155b586e02b2532 **[Saving empty eql query]** https://github.com/elastic/kibana/issues/148950** - https://github.com/elastic/kibana/pull/152284/commits/b9715cb5e5d75fe12ed0af1672d22370cec9207d **[Re-add alert count to top n]** https://github.com/elastic/kibana/issues/148631 - https://github.com/elastic/kibana/pull/152284/commits/4c8d1e6021b37ad90bd34aa7cb25527a7a60cd21 --- .../cypress/e2e/timelines/creation.cy.ts | 65 +++++++++++++++++++ .../cypress/screens/create_new_rule.ts | 2 + .../alerts_histogram_panel/index.tsx | 3 +- .../timeline/eql_tab_content/index.tsx | 3 +- .../timeline/query_bar/eql/index.tsx | 5 +- 5 files changed, 74 insertions(+), 4 deletions(-) diff --git a/x-pack/plugins/security_solution/cypress/e2e/timelines/creation.cy.ts b/x-pack/plugins/security_solution/cypress/e2e/timelines/creation.cy.ts index 62d8fdb8f1b41..81e74661d1839 100644 --- a/x-pack/plugins/security_solution/cypress/e2e/timelines/creation.cy.ts +++ b/x-pack/plugins/security_solution/cypress/e2e/timelines/creation.cy.ts @@ -22,6 +22,7 @@ import { TIMELINE_TAB_CONTENT_GRAPHS_NOTES, EDIT_TIMELINE_BTN, EDIT_TIMELINE_TOOLTIP, + TIMELINE_CORRELATION_INPUT, } from '../../screens/timeline'; import { createTimelineTemplate } from '../../tasks/api_calls/timelines'; @@ -41,9 +42,11 @@ import { goToQueryTab, pinFirstEvent, populateTimeline, + waitForTimelineChanges, } from '../../tasks/timeline'; import { OVERVIEW_URL, TIMELINE_TEMPLATES_URL } from '../../urls/navigation'; +import { EQL_QUERY_VALIDATION_ERROR } from '../../screens/create_new_rule'; describe('Create a timeline from a template', () => { before(() => { @@ -154,5 +157,67 @@ describe('Timelines', (): void => { .then(parseInt) .should('be.gt', 0); }); + + // Skipped in this PR until the underlying re-renders are fixed: https://github.com/elastic/kibana/pull/152284 + describe.skip('correlation tab', () => { + it('should update timeline after adding eql', () => { + cy.intercept('PATCH', '/api/timeline').as('updateTimeline'); + const eql = 'any where process.name == "zsh"'; + addEqlToTimeline(eql); + + cy.wait('@updateTimeline', { timeout: 10000 }).its('response.statusCode').should('eq', 200); + + cy.get(`${TIMELINE_TAB_CONTENT_EQL} ${SERVER_SIDE_EVENT_COUNT}`) + .invoke('text') + .then(parseInt) + .should('be.gt', 0); + }); + + describe.skip('updates', () => { + const eql = 'any where process.name == "zsh"'; + beforeEach(() => { + cy.intercept('PATCH', '/api/timeline').as('updateTimeline'); + addEqlToTimeline(eql); + // TODO: It may need a further refactor to handle the frequency with which react calls this api + // Since it's based on real time text changes...and real time query validation + // there's almost no guarantee on the number of calls, so a cypress.wait may actually be more appropriate + cy.wait('@updateTimeline'); + cy.wait('@updateTimeline'); + cy.reload(); + cy.get(TIMELINE_CORRELATION_INPUT).should('be.visible'); + cy.get(TIMELINE_CORRELATION_INPUT).should('have.text', eql); + }); + + it('should update timeline after removing eql', () => { + cy.intercept('PATCH', '/api/timeline').as('updateTimeline'); + cy.get(TIMELINE_CORRELATION_INPUT).should('be.visible'); + waitForTimelineChanges(); + cy.get(TIMELINE_CORRELATION_INPUT).type('{selectAll} {del}').clear(); + // TODO: It may need a further refactor to handle the frequency with which react calls this api + // Since it's based on real time text changes...and real time query validation + // there's almost no guarantee on the number of calls, so a cypress.wait may actually be more appropriate + cy.wait('@updateTimeline'); + cy.wait('@updateTimeline'); + cy.wait('@updateTimeline'); + cy.wait('@updateTimeline'); + waitForTimelineChanges(); + cy.reload(); + cy.get(TIMELINE_CORRELATION_INPUT).should('be.visible'); + + cy.get(TIMELINE_CORRELATION_INPUT).should('have.text', ''); + }); + + it('should NOT update timeline after adding wrong eql', () => { + cy.intercept('PATCH', '/api/timeline').as('updateTimeline'); + const nonFunctionalEql = 'this is not valid eql'; + addEqlToTimeline(nonFunctionalEql); + cy.get(EQL_QUERY_VALIDATION_ERROR).should('be.visible'); + cy.reload(); + cy.get(TIMELINE_CORRELATION_INPUT).should('be.visible'); + + cy.get(TIMELINE_CORRELATION_INPUT).should('have.text', eql); + }); + }); + }); }); }); diff --git a/x-pack/plugins/security_solution/cypress/screens/create_new_rule.ts b/x-pack/plugins/security_solution/cypress/screens/create_new_rule.ts index 80b53926ed720..61677bbd73b78 100644 --- a/x-pack/plugins/security_solution/cypress/screens/create_new_rule.ts +++ b/x-pack/plugins/security_solution/cypress/screens/create_new_rule.ts @@ -89,6 +89,8 @@ export const EQL_QUERY_INPUT = '[data-test-subj="eqlQueryBarTextInput"]'; export const EQL_QUERY_VALIDATION_SPINNER = '[data-test-subj="eql-validation-loading"]'; +export const EQL_QUERY_VALIDATION_ERROR = '[data-test-subj="eql-validation-errors-popover-button"]'; + export const IMPORT_QUERY_FROM_SAVED_TIMELINE_LINK = '[data-test-subj="importQueryFromSavedTimeline"]'; diff --git a/x-pack/plugins/security_solution/public/detections/components/alerts_kpis/alerts_histogram_panel/index.tsx b/x-pack/plugins/security_solution/public/detections/components/alerts_kpis/alerts_histogram_panel/index.tsx index 8c5760c20a70b..3c20f5603a0ee 100644 --- a/x-pack/plugins/security_solution/public/detections/components/alerts_kpis/alerts_histogram_panel/index.tsx +++ b/x-pack/plugins/security_solution/public/detections/components/alerts_kpis/alerts_histogram_panel/index.tsx @@ -391,7 +391,7 @@ export const AlertsHistogramPanel = memo( alignHeader={alignHeader} id={uniqueQueryId} inspectTitle={inspectTitle} - outerDirection="row" + outerDirection="column" title={titleText} titleSize={titleSize} toggleStatus={showHistogram} @@ -399,7 +399,6 @@ export const AlertsHistogramPanel = memo( showInspectButton={isChartEmbeddablesEnabled ? false : chartOptionsContextMenu == null} subtitle={!isInitialLoading && showTotalAlertsCount && totalAlerts} isInspectDisabled={isInspectDisabled} - hideSubtitle > diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/eql_tab_content/index.tsx b/x-pack/plugins/security_solution/public/timelines/components/timeline/eql_tab_content/index.tsx index 87bd628ca48c6..8bcf48b869f3d 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/timeline/eql_tab_content/index.tsx +++ b/x-pack/plugins/security_solution/public/timelines/components/timeline/eql_tab_content/index.tsx @@ -69,11 +69,12 @@ const StyledEuiFlyoutHeader = styled(EuiFlyoutHeader)` box-shadow: none; display: flex; flex-direction: column; + margin-top: ${({ theme }) => theme.eui.euiSizeM} padding: 0; &.euiFlyoutHeader { ${({ theme }) => - `padding: 0 ${theme.eui.euiSizeS} ${theme.eui.euiSizeS} ${theme.eui.euiSizeS};`} + `padding: 0 ${theme.eui.euiSizeM} ${theme.eui.euiSizeS} ${theme.eui.euiSizeS};`} } `; diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/query_bar/eql/index.tsx b/x-pack/plugins/security_solution/public/timelines/components/timeline/query_bar/eql/index.tsx index 56969a288102c..f4b21265a7906 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/timeline/query_bar/eql/index.tsx +++ b/x-pack/plugins/security_solution/public/timelines/components/timeline/query_bar/eql/index.tsx @@ -107,6 +107,8 @@ export const EqlQueryBarTimeline = memo(({ timelineId }: { timelineId: string }) watch: ['eqlQueryBar'], }); + const prevEqlQuery = useRef(''); + const optionsData = useMemo( () => isEmpty(indexPattern.fields) @@ -156,10 +158,11 @@ export const EqlQueryBarTimeline = memo(({ timelineId }: { timelineId: string }) useEffect(() => { if ( formEqlQueryBar != null && - !isEmpty(formEqlQueryBar.query.query) && + prevEqlQuery.current !== formEqlQueryBar.query.query && isQueryBarValid && !isQueryBarValidating ) { + prevEqlQuery.current = formEqlQueryBar.query.query; dispatch( timelineActions.updateEqlOptions({ id: timelineId,