[Security Solution] Elastic Security Assistant fixes (#159054)

- Changes the `New chat` button text from `New chat` to `Chat`, because a new chat context is not created if an existing chat is in progress
- Updates the Data Quality dashboard user prompt to remove references to API requests
- Fixes an issue where user prompts were not filtered by category
This commit is contained in:
Andrew Macri 2023-06-05 15:06:18 -06:00 committed by GitHub
parent 419cd20b4e
commit 0fda51d5cd
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
10 changed files with 68 additions and 18 deletions

View file

@ -77,8 +77,7 @@ export const PromptContextSelector: React.FC<Props> = React.memo(
return (
<span className={contentClassName}>
<EuiHighlight search={searchValue}>{label}</EuiHighlight>
&nbsp;
<span>{`(${value?.category})`}</span>
<span>{` / (${value?.category})`}</span>
</span>
);
};

View file

@ -5,7 +5,7 @@
* 2.0.
*/
import React, { useCallback, useState } from 'react';
import React, { useCallback, useMemo, useState } from 'react';
import { EuiFlexGroup, EuiFlexItem, EuiBadge, EuiPopover } from '@elastic/eui';
// eslint-disable-next-line @kbn/eslint/module_migration
import styled from 'styled-components';
@ -33,7 +33,7 @@ interface QuickPromptsProps {
* and localstorage for storing new and edited prompts.
*/
export const QuickPrompts: React.FC<QuickPromptsProps> = React.memo(({ setInput }) => {
const { basePromptContexts, baseQuickPrompts, nameSpace } = useAssistantContext();
const { basePromptContexts, baseQuickPrompts, nameSpace, promptContexts } = useAssistantContext();
// Local storage for all quick prompts, prefixed by assistant nameSpace
const [localStorageQuickPrompts, setLocalStorageQuickPrompts] = useLocalStorage(
@ -42,6 +42,20 @@ export const QuickPrompts: React.FC<QuickPromptsProps> = React.memo(({ setInput
);
const [quickPrompts, setQuickPrompts] = useState(localStorageQuickPrompts ?? []);
const contextFilteredQuickPrompts = useMemo(() => {
const registeredPromptContextTitles = Object.values(promptContexts).map((pc) => pc.category);
return quickPrompts.filter((quickPrompt) => {
// Return quick prompt as match if it has no categories, otherwise ensure category exists in registered prompt contexts
if (quickPrompt.categories == null || quickPrompt.categories.length === 0) {
return true;
} else {
return quickPrompt.categories.some((category) => {
return registeredPromptContextTitles.includes(category);
});
}
});
}, [quickPrompts, promptContexts]);
// Overflow state
const [isOverflowPopoverOpen, setIsOverflowPopoverOpen] = useState(false);
const toggleOverflowPopover = useCallback(
@ -67,7 +81,7 @@ export const QuickPrompts: React.FC<QuickPromptsProps> = React.memo(({ setInput
);
return (
<QuickPromptsFlexGroup gutterSize="s" alignItems="center">
{quickPrompts.slice(0, COUNT_BEFORE_OVERFLOW).map((badge, index) => (
{contextFilteredQuickPrompts.slice(0, COUNT_BEFORE_OVERFLOW).map((badge, index) => (
<EuiFlexItem key={index} grow={false}>
<EuiBadge
color={badge.color}
@ -78,7 +92,7 @@ export const QuickPrompts: React.FC<QuickPromptsProps> = React.memo(({ setInput
</EuiBadge>
</EuiFlexItem>
))}
{quickPrompts.length > COUNT_BEFORE_OVERFLOW && (
{contextFilteredQuickPrompts.length > COUNT_BEFORE_OVERFLOW && (
<EuiFlexItem grow={false}>
<EuiPopover
button={
@ -94,7 +108,7 @@ export const QuickPrompts: React.FC<QuickPromptsProps> = React.memo(({ setInput
anchorPosition="rightUp"
>
<EuiFlexGroup direction="column" gutterSize="s">
{quickPrompts.slice(COUNT_BEFORE_OVERFLOW).map((badge, index) => (
{contextFilteredQuickPrompts.slice(COUNT_BEFORE_OVERFLOW).map((badge, index) => (
<EuiFlexItem key={index} grow={false}>
<EuiBadge
color={badge.color}

View file

@ -43,7 +43,7 @@ describe('NewChat', () => {
const newChatButton = screen.getByTestId('newChat');
expect(newChatButton.textContent).toContain('New chat');
expect(newChatButton.textContent).toContain('Chat');
});
it('renders custom children', () => {

View file

@ -8,5 +8,5 @@
import { i18n } from '@kbn/i18n';
export const NEW_CHAT = i18n.translate('xpack.elasticAssistant.assistant.newChat.newChatButton', {
defaultMessage: 'New chat',
defaultMessage: 'Chat',
});

View file

@ -36,7 +36,7 @@ describe('NewChatById', () => {
const newChatButton = screen.getByTestId('newChatById');
expect(newChatButton.textContent).toContain('New chat');
expect(newChatButton.textContent).toContain('Chat');
});
it('renders custom children', async () => {

View file

@ -10,6 +10,6 @@ import { i18n } from '@kbn/i18n';
export const NEW_CHAT = i18n.translate(
'xpack.elasticAssistant.assistant.newChatById.newChatByIdButton',
{
defaultMessage: 'New chat',
defaultMessage: 'Chat',
}
);

View file

@ -87,7 +87,8 @@ export const DATA_QUALITY_SUBTITLE: string = i18n.translate(
export const DATA_QUALITY_SUGGESTED_USER_PROMPT = i18n.translate(
'securitySolutionPackages.ecsDataQualityDashboard.dataQualitySuggestedUserPrompt',
{
defaultMessage: 'Explain how to fix issues step by step, and provide API calls.',
defaultMessage:
'Explain the results above, and describe some options to fix incompatibilities.',
}
);

View file

@ -10,7 +10,10 @@ export { DataQualityPanel } from './impl/data_quality';
export { getIlmPhaseDescription } from './impl/data_quality/helpers';
export {
DATA_QUALITY_PROMPT_CONTEXT_PILL,
DATA_QUALITY_PROMPT_CONTEXT_PILL_TOOLTIP,
DATA_QUALITY_SUBTITLE,
DATA_QUALITY_SUGGESTED_USER_PROMPT,
ILM_PHASE,
INDEX_LIFECYCLE_MANAGEMENT_PHASES,
SELECT_ONE_OR_MORE_ILM_PHASES,

View file

@ -7,13 +7,15 @@
import type { PromptContext, PromptContextTemplate } from '@kbn/elastic-assistant';
import { USER_PROMPTS } from '@kbn/elastic-assistant';
import * as i18n from '../../../common/components/event_details/translations';
import * as i18nDataQuality from '@kbn/ecs-data-quality-dashboard';
import * as i18nEventDetails from '../../../common/components/event_details/translations';
import * as i18nDetections from '../../../detections/pages/detection_engine/rules/translations';
import { SUMMARY_VIEW } from '../../../common/components/event_details/translations';
import * as i18n from './translations';
export const PROMPT_CONTEXT_ALERT_CATEGORY = 'alert';
export const PROMPT_CONTEXT_EVENT_CATEGORY = 'event';
export const PROMPT_CONTEXT_DETECTION_RULES_CATEGORY = 'detection-rules';
export const DATA_QUALITY_DASHBOARD_CATEGORY = 'data-quality-dashboard';
/**
* Global list of PromptContexts intended to be used throughout Security Solution.
@ -28,8 +30,8 @@ export const PROMPT_CONTEXTS: Record<PromptContext['category'], PromptContextTem
PROMPT_CONTEXT_ALERT_CATEGORY: {
category: PROMPT_CONTEXT_ALERT_CATEGORY,
suggestedUserPrompt: USER_PROMPTS.EXPLAIN_THEN_SUMMARIZE_SUGGEST_INVESTIGATION_GUIDE_NON_I18N,
description: i18n.ALERT_SUMMARY_CONTEXT_DESCRIPTION(SUMMARY_VIEW),
tooltip: i18n.ALERT_SUMMARY_VIEW_CONTEXT_TOOLTIP,
description: i18nEventDetails.ALERT_SUMMARY_CONTEXT_DESCRIPTION(i18n.VIEW),
tooltip: i18nEventDetails.ALERT_SUMMARY_VIEW_CONTEXT_TOOLTIP,
},
/**
* Event summary view context, made available from Timeline events
@ -37,8 +39,17 @@ export const PROMPT_CONTEXTS: Record<PromptContext['category'], PromptContextTem
PROMPT_CONTEXT_EVENT_CATEGORY: {
category: PROMPT_CONTEXT_EVENT_CATEGORY,
suggestedUserPrompt: USER_PROMPTS.EXPLAIN_THEN_SUMMARIZE_SUGGEST_INVESTIGATION_GUIDE_NON_I18N,
description: i18n.EVENT_SUMMARY_CONTEXT_DESCRIPTION('view'),
tooltip: i18n.EVENT_SUMMARY_VIEW_CONTEXT_TOOLTIP,
description: i18nEventDetails.EVENT_SUMMARY_CONTEXT_DESCRIPTION(i18n.VIEW),
tooltip: i18nEventDetails.EVENT_SUMMARY_VIEW_CONTEXT_TOOLTIP,
},
/**
* Data Quality dashboard context, made available on the Data Quality dashboard
*/
DATA_QUALITY_DASHBOARD_CATEGORY: {
category: DATA_QUALITY_DASHBOARD_CATEGORY,
suggestedUserPrompt: i18nDataQuality.DATA_QUALITY_SUGGESTED_USER_PROMPT,
description: i18nDataQuality.DATA_QUALITY_PROMPT_CONTEXT_PILL(i18n.INDEX),
tooltip: i18nDataQuality.DATA_QUALITY_PROMPT_CONTEXT_PILL_TOOLTIP,
},
/**
* Detection Rules context, made available on the Rule Management page when rules are selected

View file

@ -0,0 +1,22 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/
import { i18n } from '@kbn/i18n';
export const VIEW = i18n.translate(
'xpack.securitySolution.assistant.content.promptContexts.viewTitle',
{
defaultMessage: 'view',
}
);
export const INDEX = i18n.translate(
'xpack.securitySolution.assistant.content.promptContexts.indexTitle',
{
defaultMessage: 'index',
}
);