[8.11] [Security Solution] [Elastic AI Assistant] Fix Send to Timeline ESQL action changing the ESQL bar to KQL bar (#170542) (#171471)

# Backport

This will backport the following commits from `main` to `8.11`:
- [[Security Solution] [Elastic AI Assistant] Fix Send to Timeline ESQL
action changing the ESQL bar to KQL bar
(#170542)](https://github.com/elastic/kibana/pull/170542)

<!--- Backport version: 8.9.7 -->

### Questions ?
Please refer to the [Backport tool
documentation](https://github.com/sqren/backport)

<!--BACKPORT [{"author":{"name":"Garrett
Spong","email":"spong@users.noreply.github.com"},"sourceCommit":{"committedDate":"2023-11-17T01:13:14Z","message":"[Security
Solution] [Elastic AI Assistant] Fix Send to Timeline ESQL action
changing the ESQL bar to KQL bar (#170542)\n\n## Summary\r\n\r\nIn
https://github.com/elastic/kibana/pull/169478, the `Send to
Timeline`\r\naction was fixed for `ES|QL` codeblocks, however while the
`ES|QL`\r\ntimeline tab was being selected, and the query string was
being set\r\ncorrectly, the ESQL bar would be swapped out for the KQL
bar. In the\r\ngifs below, note the right two action buttons present in
the query bar.\r\n\r\nThere is one remaining bug where refreshing the
page clears the ESQL\r\nquery and set the default query. @logeekal is
currently investigating a\r\nfix for this issue and will push to this
branch once available.\r\n\r\n#### Before\r\n<p
align=\"center\">\r\n<img
width=\"500\"\r\nsrc=\"fdc3b2a0-5b4b-4584-b304-c4d24de1917c\"\r\n/>\r\n</p>
\r\n\r\n#### After\r\n<p align=\"center\">\r\n<img
width=\"500\"\r\nsrc=\"d217b95c-2d1c-4474-ac98-180e07a86669\"\r\n/>\r\n</p>
\r\n\r\n\r\n## Test instructions\r\n\r\nEither request the assistant to
generate an ESQL query or just paste\r\nthis codeblock into the
conversation to test the action directly from\r\nthe user message. Be
sure to declare the codeblock language as `esql` or\r\ninclude one of
the [string
match\r\npatterns](https://github.com/elastic/kibana/pull/169478/files#diff-f70f0b96568e024e53bfbb62adcca72051f0a2e824d4ab22664eed0e149be248R38)\r\nabove
the code block so the action can be recognized.\r\n\r\n\r\n````\r\nBelow
is an `Elasticsearch Query Language` query:\r\n\r\n```esql\r\nFROM
logs-endpoint*\r\n| WHERE event.category == \\\"process\\\"\r\n| STATS
proc_count = COUNT(process.name) BY host.name\r\n| KEEP host.name,
proc_count\r\n```\r\n````\r\n\r\n\r\nThen verify that the query bar is
still the ESQL query bar which has the\r\n`Expand` and `ESQL Reference`
buttons to the far right.\r\n\r\n---------\r\n\r\nCo-authored-by: Jatin
Kathuria
<jatin.kathuria@elastic.co>","sha":"52fdd7f46fc6dd56d062a1ba55dd5caeae47c8f9","branchLabelMapping":{"^v8.12.0$":"main","^v(\\d+).(\\d+).\\d+$":"$1.$2"}},"sourcePullRequest":{"labels":["bug","release_note:fix","Team:
SecuritySolution","backport:prev-minor","Feature:Elastic AI
Assistant","v8.12.0","v8.11.2"],"number":170542,"url":"https://github.com/elastic/kibana/pull/170542","mergeCommit":{"message":"[Security
Solution] [Elastic AI Assistant] Fix Send to Timeline ESQL action
changing the ESQL bar to KQL bar (#170542)\n\n## Summary\r\n\r\nIn
https://github.com/elastic/kibana/pull/169478, the `Send to
Timeline`\r\naction was fixed for `ES|QL` codeblocks, however while the
`ES|QL`\r\ntimeline tab was being selected, and the query string was
being set\r\ncorrectly, the ESQL bar would be swapped out for the KQL
bar. In the\r\ngifs below, note the right two action buttons present in
the query bar.\r\n\r\nThere is one remaining bug where refreshing the
page clears the ESQL\r\nquery and set the default query. @logeekal is
currently investigating a\r\nfix for this issue and will push to this
branch once available.\r\n\r\n#### Before\r\n<p
align=\"center\">\r\n<img
width=\"500\"\r\nsrc=\"fdc3b2a0-5b4b-4584-b304-c4d24de1917c\"\r\n/>\r\n</p>
\r\n\r\n#### After\r\n<p align=\"center\">\r\n<img
width=\"500\"\r\nsrc=\"d217b95c-2d1c-4474-ac98-180e07a86669\"\r\n/>\r\n</p>
\r\n\r\n\r\n## Test instructions\r\n\r\nEither request the assistant to
generate an ESQL query or just paste\r\nthis codeblock into the
conversation to test the action directly from\r\nthe user message. Be
sure to declare the codeblock language as `esql` or\r\ninclude one of
the [string
match\r\npatterns](https://github.com/elastic/kibana/pull/169478/files#diff-f70f0b96568e024e53bfbb62adcca72051f0a2e824d4ab22664eed0e149be248R38)\r\nabove
the code block so the action can be recognized.\r\n\r\n\r\n````\r\nBelow
is an `Elasticsearch Query Language` query:\r\n\r\n```esql\r\nFROM
logs-endpoint*\r\n| WHERE event.category == \\\"process\\\"\r\n| STATS
proc_count = COUNT(process.name) BY host.name\r\n| KEEP host.name,
proc_count\r\n```\r\n````\r\n\r\n\r\nThen verify that the query bar is
still the ESQL query bar which has the\r\n`Expand` and `ESQL Reference`
buttons to the far right.\r\n\r\n---------\r\n\r\nCo-authored-by: Jatin
Kathuria
<jatin.kathuria@elastic.co>","sha":"52fdd7f46fc6dd56d062a1ba55dd5caeae47c8f9"}},"sourceBranch":"main","suggestedTargetBranches":["8.11"],"targetPullRequestStates":[{"branch":"main","label":"v8.12.0","labelRegex":"^v8.12.0$","isSourceBranch":true,"state":"MERGED","url":"https://github.com/elastic/kibana/pull/170542","number":170542,"mergeCommit":{"message":"[Security
Solution] [Elastic AI Assistant] Fix Send to Timeline ESQL action
changing the ESQL bar to KQL bar (#170542)\n\n## Summary\r\n\r\nIn
https://github.com/elastic/kibana/pull/169478, the `Send to
Timeline`\r\naction was fixed for `ES|QL` codeblocks, however while the
`ES|QL`\r\ntimeline tab was being selected, and the query string was
being set\r\ncorrectly, the ESQL bar would be swapped out for the KQL
bar. In the\r\ngifs below, note the right two action buttons present in
the query bar.\r\n\r\nThere is one remaining bug where refreshing the
page clears the ESQL\r\nquery and set the default query. @logeekal is
currently investigating a\r\nfix for this issue and will push to this
branch once available.\r\n\r\n#### Before\r\n<p
align=\"center\">\r\n<img
width=\"500\"\r\nsrc=\"fdc3b2a0-5b4b-4584-b304-c4d24de1917c\"\r\n/>\r\n</p>
\r\n\r\n#### After\r\n<p align=\"center\">\r\n<img
width=\"500\"\r\nsrc=\"d217b95c-2d1c-4474-ac98-180e07a86669\"\r\n/>\r\n</p>
\r\n\r\n\r\n## Test instructions\r\n\r\nEither request the assistant to
generate an ESQL query or just paste\r\nthis codeblock into the
conversation to test the action directly from\r\nthe user message. Be
sure to declare the codeblock language as `esql` or\r\ninclude one of
the [string
match\r\npatterns](https://github.com/elastic/kibana/pull/169478/files#diff-f70f0b96568e024e53bfbb62adcca72051f0a2e824d4ab22664eed0e149be248R38)\r\nabove
the code block so the action can be recognized.\r\n\r\n\r\n````\r\nBelow
is an `Elasticsearch Query Language` query:\r\n\r\n```esql\r\nFROM
logs-endpoint*\r\n| WHERE event.category == \\\"process\\\"\r\n| STATS
proc_count = COUNT(process.name) BY host.name\r\n| KEEP host.name,
proc_count\r\n```\r\n````\r\n\r\n\r\nThen verify that the query bar is
still the ESQL query bar which has the\r\n`Expand` and `ESQL Reference`
buttons to the far right.\r\n\r\n---------\r\n\r\nCo-authored-by: Jatin
Kathuria
<jatin.kathuria@elastic.co>","sha":"52fdd7f46fc6dd56d062a1ba55dd5caeae47c8f9"}},{"branch":"8.11","label":"v8.11.2","labelRegex":"^v(\\d+).(\\d+).\\d+$","isSourceBranch":false,"state":"NOT_CREATED"}]}]
BACKPORT-->

Co-authored-by: Garrett Spong <spong@users.noreply.github.com>
Co-authored-by: Jatin Kathuria <jatin.kathuria@elastic.co>
This commit is contained in:
Kibana Machine 2023-11-18 12:55:54 -05:00 committed by GitHub
parent a094ddd412
commit f982ca8292
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 59 additions and 17 deletions

View file

@ -5,7 +5,7 @@
* 2.0.
*/
import { EuiIcon, EuiToolTip } from '@elastic/eui';
import { EuiIcon } from '@elastic/eui';
import { analyzeMarkdown } from '@kbn/elastic-assistant';
import type { Conversation, CodeBlockDetails } from '@kbn/elastic-assistant';
import React from 'react';
@ -13,7 +13,6 @@ import React from 'react';
import type { TimelineEventsDetailsItem } from '../../common/search_strategy';
import type { Rule } from '../detection_engine/rule_management/logic';
import { SendToTimelineButton } from './send_to_timeline';
import { INVESTIGATE_IN_TIMELINE } from '../actions/add_to_timeline/constants';
export const LOCAL_STORAGE_KEY = `securityAssistant`;
@ -125,9 +124,7 @@ export const augmentMessageCodeBlocks = (
]}
keepDataView={true}
>
<EuiToolTip position="right" content={INVESTIGATE_IN_TIMELINE}>
<EuiIcon type="timeline" />
</EuiToolTip>
<EuiIcon type="timeline" />
</SendToTimelineButton>
) : null,
};

View file

@ -6,10 +6,11 @@
*/
import React, { useCallback, useMemo } from 'react';
import { EuiButton, EuiButtonEmpty } from '@elastic/eui';
import { EuiButton, EuiButtonEmpty, EuiToolTip } from '@elastic/eui';
import type { Filter } from '@kbn/es-query';
import { useDispatch } from 'react-redux';
import { useAssistantContext } from '@kbn/elastic-assistant';
import { useDeepEqualSelector } from '../../common/hooks/use_selector';
import { sourcererSelectors } from '../../common/store';
import { sourcererActions } from '../../common/store/actions';
@ -19,7 +20,10 @@ import type { TimeRange } from '../../common/store/inputs/model';
import { SourcererScopeName } from '../../common/store/sourcerer/model';
import { TimelineTabs, TimelineId } from '../../../common/types/timeline';
import { TimelineType } from '../../../common/api/timeline';
import { ACTION_INVESTIGATE_IN_TIMELINE } from '../../detections/components/alerts_table/translations';
import {
ACTION_CANNOT_INVESTIGATE_IN_TIMELINE,
ACTION_INVESTIGATE_IN_TIMELINE,
} from '../../detections/components/alerts_table/translations';
import type { DataProvider } from '../../timelines/components/timeline/data_providers/data_provider';
import { useCreateTimeline } from '../../timelines/components/timeline/properties/use_create_timeline';
import {
@ -31,6 +35,7 @@ import {
updateEqlOptions,
} from '../../timelines/store/timeline/actions';
import { useDiscoverInTimelineContext } from '../../common/components/discover_in_timeline/use_discover_in_timeline_context';
import { useShowTimeline } from '../../common/utils/timeline/use_show_timeline';
export interface SendToTimelineButtonProps {
asEmptyButton: boolean;
@ -51,7 +56,8 @@ export const SendToTimelineButton: React.FunctionComponent<SendToTimelineButtonP
...rest
}) => {
const dispatch = useDispatch();
const { showAssistantOverlay } = useAssistantContext();
const [isTimelineBottomBarVisible] = useShowTimeline();
const { discoverStateContainer } = useDiscoverInTimelineContext();
const getDataViewsSelector = useMemo(
@ -71,13 +77,15 @@ export const SendToTimelineButton: React.FunctionComponent<SendToTimelineButtonP
});
const configureAndOpenTimeline = useCallback(() => {
// Hide the assistant overlay so timeline can be seen (noop if using assistant in timeline)
showAssistantOverlay({ showOverlay: false });
if (dataProviders || filters) {
// If esql, don't reset filters or mess with dataview & time range
if (dataProviders?.[0]?.queryType === 'esql' || dataProviders?.[0]?.queryType === 'sql') {
discoverStateContainer.current?.appState.update({
query: {
query: dataProviders[0].kqlQuery,
language: 'esql',
esql: dataProviders[0].kqlQuery,
},
});
@ -200,6 +208,7 @@ export const SendToTimelineButton: React.FunctionComponent<SendToTimelineButtonP
dispatch(inputsActions.removeLinkTo([InputsModelId.timeline, InputsModelId.global]));
}
}, [
showAssistantOverlay,
dataProviders,
filters,
timeRange,
@ -211,23 +220,35 @@ export const SendToTimelineButton: React.FunctionComponent<SendToTimelineButtonP
signalIndexName,
]);
// As we work around timeline visibility issues, we will disable the button if timeline isn't available
const toolTipText = isTimelineBottomBarVisible
? ACTION_INVESTIGATE_IN_TIMELINE
: ACTION_CANNOT_INVESTIGATE_IN_TIMELINE;
const isDisabled = !isTimelineBottomBarVisible;
return asEmptyButton ? (
<EuiButtonEmpty
aria-label={ACTION_INVESTIGATE_IN_TIMELINE}
aria-label={toolTipText}
onClick={configureAndOpenTimeline}
isDisabled={isDisabled}
color="text"
flush="both"
size="xs"
>
{children}
<EuiToolTip position="right" content={toolTipText}>
<>{children}</>
</EuiToolTip>
</EuiButtonEmpty>
) : (
<EuiButton
aria-label={ACTION_INVESTIGATE_IN_TIMELINE}
aria-label={toolTipText}
isDisabled={isDisabled}
onClick={configureAndOpenTimeline}
{...rest}
>
{children}
<EuiToolTip position="right" content={toolTipText}>
<>{children}</>
</EuiToolTip>
</EuiButton>
);
};

View file

@ -134,7 +134,7 @@ export const useDiscoverInTimelineActions = (
* */
const resetDiscoverAppState = useCallback(async () => {
const defaultDiscoverAppState = await getDefaultDiscoverAppState();
discoverStateContainer.current?.appState.set(defaultDiscoverAppState);
discoverStateContainer.current?.appState.replaceUrlState(defaultDiscoverAppState);
discoverStateContainer.current?.globalState.set({
...discoverStateContainer.current?.globalState.get(),
time: defaultDiscoverTimeRange,

View file

@ -137,6 +137,13 @@ export const ACTION_INVESTIGATE_IN_TIMELINE = i18n.translate(
}
);
export const ACTION_CANNOT_INVESTIGATE_IN_TIMELINE = i18n.translate(
'xpack.securitySolution.detectionEngine.alerts.actions.cannotInvestigateInTimelineTitle',
{
defaultMessage: 'Please navigate to a page with timeline to investigate',
}
);
export const ACTION_INVESTIGATE_IN_TIMELINE_ARIA_LABEL = i18n.translate(
'xpack.securitySolution.detectionEngine.alerts.actions.investigateInTimelineAriaLabel',
{

View file

@ -238,8 +238,25 @@ export const DiscoverTabContent: FC<DiscoverTabContentProps> = ({ timelineId })
const finalAppState =
savedSearchAppState?.appState ?? discoverAppState ?? defaultDiscoverAppState;
stateContainer.appState.set(finalAppState);
await stateContainer.appState.replaceUrlState(finalAppState);
const urlAppState = stateContainer.appState.isEmptyURL()
? undefined
: stateContainer.appState.getState();
const hasESQLURlState = urlAppState?.query && 'esql' in urlAppState.query;
/*
* Url state should NOT apply if there is already a saved search being loaded
* */
const shouldApplyESQLUrlState = !savedSearchAppState?.appState && hasESQLURlState;
if (!shouldApplyESQLUrlState) {
/*
* If url state applies, it should be a no-op and there is no need to update the state container.
* Discover should automatically pick up url state
* */
stateContainer.appState.set(finalAppState);
await stateContainer.appState.replaceUrlState(finalAppState);
}
const unsubscribeState = stateContainer.appState.state$.subscribe({
next: setDiscoverAppState,