Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,12 @@
* 2.0.
*/

import React, { Dispatch, SetStateAction } from 'react';
import React, { Dispatch, SetStateAction, useMemo } from 'react';
import { EuiFlexGroup, EuiFlexItem, EuiPanel, EuiText } from '@elastic/eui';
import { css } from '@emotion/react';
import { PromptResponse } from '@kbn/elastic-assistant-common';
import { AssistantBeacon } from '@kbn/ai-assistant-icon';
import { useVerticalBreakpoint } from './use_vertical_breakpoint';
import { useAssistantContext } from '../../..';
import { StarterPrompts } from './starter_prompts';
import { SystemPrompt } from '../prompt_editor/system_prompt';
Expand Down Expand Up @@ -39,12 +40,15 @@ export const EmptyConvo: React.FC<Props> = ({
setUserPrompt,
}) => {
const { assistantAvailability } = useAssistantContext();
const breakpoint = useVerticalBreakpoint();
const compressed = useMemo(() => breakpoint !== 'tall', [breakpoint]);
return (
<EuiFlexGroup
alignItems="center"
justifyContent="spaceBetween"
data-test-subj="emptyConvo"
direction="column"
gutterSize={compressed ? 'm' : 'l'}
>
<EuiFlexItem grow={false}>
<EuiPanel
Expand All @@ -54,12 +58,17 @@ export const EmptyConvo: React.FC<Props> = ({
text-align: center;
`}
>
<EuiFlexGroup alignItems="center" justifyContent="center" direction="column">
<EuiFlexGroup
alignItems="center"
justifyContent="center"
direction="column"
gutterSize={compressed ? 'm' : 'l'}
>
<EuiFlexItem grow={false}>
<AssistantBeacon backgroundColor="emptyShade" size="xl" />
<AssistantBeacon backgroundColor="emptyShade" size={compressed ? 'm' : 'xl'} />
</EuiFlexItem>
<EuiFlexItem grow={false}>
<EuiText>
<EuiText size={compressed ? 'xs' : 'relative'}>
<h3>{i18n.EMPTY_SCREEN_TITLE}</h3>
<p>{i18n.EMPTY_SCREEN_DESCRIPTION}</p>
</EuiText>
Expand All @@ -71,17 +80,22 @@ export const EmptyConvo: React.FC<Props> = ({
isSettingsModalVisible={isSettingsModalVisible}
onSystemPromptSelectionChange={setCurrentSystemPromptId}
setIsSettingsModalVisible={setIsSettingsModalVisible}
compressed={compressed}
/>
</EuiFlexItem>
<EuiFlexItem grow={false}>
<SetupKnowledgeBaseButton />
<SetupKnowledgeBaseButton {...(compressed ? { display: 'mini' } : {})} />
</EuiFlexItem>
</EuiFlexGroup>
</EuiPanel>
</EuiFlexItem>
{assistantAvailability.isStarterPromptsEnabled && (
<EuiFlexItem grow={false} css={starterPromptWrapperClassName}>
<StarterPrompts connectorId={connectorId} setUserPrompt={setUserPrompt} />
<StarterPrompts
compressed={compressed}
connectorId={connectorId}
setUserPrompt={setUserPrompt}
/>
</EuiFlexItem>
)}
</EuiFlexGroup>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,21 +6,14 @@
*/

import React, { useMemo, useCallback } from 'react';
import {
EuiFlexGroup,
EuiFlexItem,
EuiIcon,
EuiPanel,
EuiSpacer,
EuiText,
EuiTitle,
} from '@elastic/eui';
import { EuiFlexGroup, EuiFlexItem, EuiIcon, EuiPanel, EuiSpacer, EuiText } from '@elastic/eui';
import { css } from '@emotion/css';
import { PromptItemArray } from '@kbn/elastic-assistant-common/impl/schemas/security_ai_prompts/common_attributes.gen';
import { useAssistantContext, useFindPrompts } from '../../..';

interface Props {
connectorId?: string;
compressed?: boolean;
setUserPrompt: React.Dispatch<React.SetStateAction<string | null>>;
}
const starterPromptClassName = css`
Expand Down Expand Up @@ -65,7 +58,11 @@ export const promptGroups = [
},
];

export const StarterPrompts: React.FC<Props> = ({ connectorId, setUserPrompt }) => {
export const StarterPrompts: React.FC<Props> = ({
compressed = false,
connectorId,
setUserPrompt,
}) => {
const {
assistantAvailability: { isAssistantEnabled },
assistantTelemetry,
Expand Down Expand Up @@ -116,20 +113,20 @@ export const StarterPrompts: React.FC<Props> = ({ connectorId, setUserPrompt })
{fetchedPromptGroups.map(({ description, title, icon, prompt }) => (
<EuiFlexItem key={prompt} className={starterPromptClassName}>
<EuiPanel
paddingSize="m"
paddingSize={compressed ? 's' : 'm'}
hasShadow={false}
hasBorder
data-test-subj={prompt}
onClick={() => onSelectPrompt(prompt, title)}
className={starterPromptInnerClassName}
>
<EuiSpacer size="s" />
<EuiIcon type={icon} size="xl" />
<EuiIcon type={icon} size={compressed ? 'm' : 'xl'} />
<EuiSpacer size="s" />
<EuiTitle size="xs">
<h2>{title}</h2>
</EuiTitle>
<EuiText size="s">{description}</EuiText>
<EuiText size={compressed ? 'xs' : 's'}>
<h3>{title}</h3>
<p>{description}</p>
</EuiText>
</EuiPanel>
</EuiFlexItem>
))}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
/*
* 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 { act, renderHook } from '@testing-library/react';
import { useVerticalBreakpoint } from './use_vertical_breakpoint';

describe('useVerticalBreakpoint', () => {
beforeEach(() => {
jest.useFakeTimers();
});

afterEach(() => {
jest.useRealTimers();
});

function setWindowHeight(height: number) {
Object.defineProperty(window, 'innerHeight', {
writable: true,
configurable: true,
value: height,
});
window.dispatchEvent(new Event('resize'));
}

it('returns "short" for height < 600', () => {
setWindowHeight(500);
const { result } = renderHook(() => useVerticalBreakpoint());
expect(result.current).toBe('short');
});

it('returns "medium" for 600 <= height < 1100', () => {
setWindowHeight(800);
const { result } = renderHook(() => useVerticalBreakpoint());
expect(result.current).toBe('medium');
});

it('returns "tall" for height >= 1100', () => {
setWindowHeight(1200);
const { result } = renderHook(() => useVerticalBreakpoint());
expect(result.current).toBe('tall');
});

it('updates value on window resize once debounced', () => {
setWindowHeight(1200);
const { result } = renderHook(() => useVerticalBreakpoint());
expect(result.current).toBe('tall');
setWindowHeight(500);
expect(result.current).toBe('tall');
act(() => {
jest.advanceTimersByTime(100); // debounce
});
expect(result.current).toBe('short');
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
/*
* 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 { useEffect } from 'react';
import useRafState from 'react-use/lib/useRafState';

export type VerticalBreakpoint = 'short' | 'medium' | 'tall';

export function useVerticalBreakpoint(): VerticalBreakpoint {
const [height, setHeight] = useRafState(() => window.innerHeight);

useEffect(() => {
const handleResize = () => {
const newHeight = window.innerHeight;
setHeight((prev) => (prev !== newHeight ? newHeight : prev));
};
window.addEventListener('resize', handleResize, { passive: true });
return () => {
window.removeEventListener('resize', handleResize);
};
}, [setHeight]);

if (height < 600) return 'short';
if (height < 1100) return 'medium';
return 'tall';
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ interface Props {
allSystemPrompts: PromptResponse[];
currentSystemPromptId: string | undefined;
isSettingsModalVisible: boolean;
compressed?: boolean;
onSystemPromptSelectionChange: (systemPromptId: string | undefined) => void;
setIsSettingsModalVisible: React.Dispatch<React.SetStateAction<boolean>>;
}
Expand All @@ -21,6 +22,7 @@ const SystemPromptComponent: React.FC<Props> = ({
allSystemPrompts,
currentSystemPromptId,
isSettingsModalVisible,
compressed = false,
onSystemPromptSelectionChange,
setIsSettingsModalVisible,
}) => {
Expand All @@ -43,6 +45,7 @@ const SystemPromptComponent: React.FC<Props> = ({
data-test-subj="systemPrompt"
isClearable={true}
isSettingsModalVisible={isSettingsModalVisible}
compressed={compressed}
onSystemPromptSelectionChange={onSystemPromptSelectionChange}
selectedPrompt={selectedPrompt}
setIsSettingsModalVisible={setIsSettingsModalVisible}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,7 @@ const SelectSystemPromptComponent: React.FC<Props> = ({
prepend={!isSettingsModalVisible ? PROMPT_CONTEXT_SELECTOR_PREFIX : undefined}
css={css`
padding-right: 56px !important;
${compressed ? 'font-size: 0.9rem;' : ''}
`}
/>
</EuiFormRow>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,10 +37,10 @@ export const EMPTY_SCREEN_TITLE = i18n.translate(
);

export const EMPTY_SCREEN_DESCRIPTION = i18n.translate(
'xpack.elasticAssistant.assistant.emptyScreen.description',
'xpack.elasticAssistant.assistant.emptyScreen.descriptionV2',
{
defaultMessage:
'Ask me anything from "Summarize this alert" to "Help me build a query" using the following system prompt:',
'Ask me anything in the chat box, or choose one of the prompts below to jump right in.',
}
);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16174,7 +16174,6 @@
"xpack.elasticAssistant.assistant.deleteConversationModal.deleteButtonText": "Supprimer",
"xpack.elasticAssistant.assistant.deleteConversationModal.deleteConversationTitle": "Supprimer cette conversation",
"xpack.elasticAssistant.assistant.disclaimer": "Les réponses des systèmes d'IA ne sont pas toujours tout à fait exactes, même si elles peuvent sembler convaincantes. Pour en savoir plus sur la fonctionnalité d'assistant et son utilisation, consultez la documentation.",
"xpack.elasticAssistant.assistant.emptyScreen.description": "Demandez-moi tout ce que vous voulez, de \"Résumez cette alerte\" à \"Aidez-moi à construire une requête\" en utilisant l'invite suivante du système :",
"xpack.elasticAssistant.assistant.emptyScreen.title": "Comment puis-je vous aider ?",
"xpack.elasticAssistant.assistant.firstPromptEditor.addNewSystemPrompt": "Ajouter une nouvelle invite système...",
"xpack.elasticAssistant.assistant.firstPromptEditor.clearSystemPrompt": "Effacer une invite système",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16151,7 +16151,6 @@
"xpack.elasticAssistant.assistant.deleteConversationModal.deleteButtonText": "削除",
"xpack.elasticAssistant.assistant.deleteConversationModal.deleteConversationTitle": "この会話を削除",
"xpack.elasticAssistant.assistant.disclaimer": "AIシステムからの応答は、納得できるように思われる場合であっても、必ずしも完全に正確であるとは限りません。アシスタント機能とその使用方法の詳細については、ドキュメントを参照してください。",
"xpack.elasticAssistant.assistant.emptyScreen.description": "次のシステムプロンプトを使用して、「このアラートを要約してください」から「クエリの作成を手伝ってください」まで、何でも依頼してください。",
"xpack.elasticAssistant.assistant.emptyScreen.title": "お手伝いできることはありますか?",
"xpack.elasticAssistant.assistant.firstPromptEditor.addNewSystemPrompt": "新しいシステムプロンプトを追加...",
"xpack.elasticAssistant.assistant.firstPromptEditor.clearSystemPrompt": "システムプロンプトを消去",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16191,7 +16191,6 @@
"xpack.elasticAssistant.assistant.deleteConversationModal.deleteButtonText": "删除",
"xpack.elasticAssistant.assistant.deleteConversationModal.deleteConversationTitle": "删除此对话",
"xpack.elasticAssistant.assistant.disclaimer": "虽然来自 AI 系统的响应不可能始终完全准确,但它们似乎令人信服。有关辅助功能及其用法的详细信息,请参阅文档。",
"xpack.elasticAssistant.assistant.emptyScreen.description": "使用以下系统提示向我提出任何要求,从“汇总此告警”到“帮助我构建查询”:",
"xpack.elasticAssistant.assistant.emptyScreen.title": "我如何帮助您?",
"xpack.elasticAssistant.assistant.firstPromptEditor.addNewSystemPrompt": "添加新系统提示……",
"xpack.elasticAssistant.assistant.firstPromptEditor.clearSystemPrompt": "清除系统提示",
Expand Down