From 2f051286960d6ef586de2e9319e5b9c769d0cafc Mon Sep 17 00:00:00 2001 From: Clint Andrew Hall Date: Thu, 12 Dec 2024 00:08:39 -0500 Subject: [PATCH] [ai][assistant] Create AI Assistant Icon, Avatar, Beacon --- .../steps/storybooks/build_and_upload.ts | 1 + .github/CODEOWNERS | 3 +- package.json | 3 +- src/dev/storybook/aliases.ts | 1 + tsconfig.base.json | 6 +- .../common}/README.md | 0 .../common}/index.ts | 0 .../common}/jest.config.js | 8 +- .../common}/kibana.jsonc | 0 .../common}/package.json | 0 .../common}/setup_tests.ts | 0 .../common}/src/index.ts | 0 .../common}/src/types/index.ts | 0 .../common}/src/utils/filter_scopes.ts | 0 .../common}/src/utils/index.ts | 0 .../common}/tsconfig.json | 5 +- x-pack/packages/ai-assistant/icon/README.md | 3 + .../icon/__stories__/avatar.stories.tsx | 34 +++++ .../icon/__stories__/beacon.stories.tsx | 25 ++++ .../icon/__stories__/icon.stories.tsx | 25 ++++ .../ai-assistant/icon/avatar.styles.ts | 22 +++ x-pack/packages/ai-assistant/icon/avatar.tsx | 33 +++++ .../ai-assistant/icon/beacon.styles.ts | 138 ++++++++++++++++++ x-pack/packages/ai-assistant/icon/beacon.tsx | 43 ++++++ x-pack/packages/ai-assistant/icon/icon.tsx | 24 +++ x-pack/packages/ai-assistant/icon/index.ts | 10 ++ .../packages/ai-assistant/icon/jest.config.js | 12 ++ .../packages/ai-assistant/icon/kibana.jsonc | 5 + .../packages/ai-assistant/icon/package.json | 6 + .../ai-assistant/icon/svg/assistant.svg | 9 ++ .../ai-assistant/icon/svg/assistant.tsx | 30 ++++ .../packages/ai-assistant/icon/tsconfig.json | 23 +++ .../kbn-ai-assistant/.storybook/main.ts | 16 ++ .../kbn-ai-assistant/.storybook/manager.ts | 20 +++ .../buttons/ask_assistant_button.stories.tsx | 51 ------- ...xpand_conversation_list_button.stories.tsx | 37 ----- .../src/buttons/new_chat_button.stories.tsx | 19 --- .../src/chat/chat_body.stories.tsx | 81 ---------- .../src/chat/chat_flyout.stories.tsx | 40 ----- .../src/chat/chat_header.stories.tsx | 41 ------ .../src/chat/chat_timeline.stories.tsx | 134 ----------------- .../src/chat/conversation_list.stories.tsx | 93 ------------ .../chat/function_list_popover.stories.tsx | 33 ----- .../chat/knowledge_base_callout.stories.tsx | 74 ---------- .../packages/kbn-ai-assistant/tsconfig.json | 3 + .../assistant/assistant_animated_icon.tsx | 3 + .../assistant_avatar/assistant_avatar.tsx | 2 +- .../assistant_avatar/assistant_avatar.tsx | 2 +- .../public/components/assistant_avatar.tsx | 1 + yarn.lock | 6 +- 50 files changed, 508 insertions(+), 617 deletions(-) rename x-pack/packages/{kbn-ai-assistant-common => ai-assistant/common}/README.md (100%) rename x-pack/packages/{kbn-ai-assistant-common => ai-assistant/common}/index.ts (100%) rename x-pack/packages/{kbn-ai-assistant-common => ai-assistant/common}/jest.config.js (66%) rename x-pack/packages/{kbn-ai-assistant-common => ai-assistant/common}/kibana.jsonc (100%) rename x-pack/packages/{kbn-ai-assistant-common => ai-assistant/common}/package.json (100%) rename x-pack/packages/{kbn-ai-assistant-common => ai-assistant/common}/setup_tests.ts (100%) rename x-pack/packages/{kbn-ai-assistant-common => ai-assistant/common}/src/index.ts (100%) rename x-pack/packages/{kbn-ai-assistant-common => ai-assistant/common}/src/types/index.ts (100%) rename x-pack/packages/{kbn-ai-assistant-common => ai-assistant/common}/src/utils/filter_scopes.ts (100%) rename x-pack/packages/{kbn-ai-assistant-common => ai-assistant/common}/src/utils/index.ts (100%) rename x-pack/packages/{kbn-ai-assistant-common => ai-assistant/common}/tsconfig.json (74%) create mode 100644 x-pack/packages/ai-assistant/icon/README.md create mode 100644 x-pack/packages/ai-assistant/icon/__stories__/avatar.stories.tsx create mode 100644 x-pack/packages/ai-assistant/icon/__stories__/beacon.stories.tsx create mode 100644 x-pack/packages/ai-assistant/icon/__stories__/icon.stories.tsx create mode 100644 x-pack/packages/ai-assistant/icon/avatar.styles.ts create mode 100644 x-pack/packages/ai-assistant/icon/avatar.tsx create mode 100644 x-pack/packages/ai-assistant/icon/beacon.styles.ts create mode 100644 x-pack/packages/ai-assistant/icon/beacon.tsx create mode 100644 x-pack/packages/ai-assistant/icon/icon.tsx create mode 100644 x-pack/packages/ai-assistant/icon/index.ts create mode 100644 x-pack/packages/ai-assistant/icon/jest.config.js create mode 100644 x-pack/packages/ai-assistant/icon/kibana.jsonc create mode 100644 x-pack/packages/ai-assistant/icon/package.json create mode 100644 x-pack/packages/ai-assistant/icon/svg/assistant.svg create mode 100644 x-pack/packages/ai-assistant/icon/svg/assistant.tsx create mode 100644 x-pack/packages/ai-assistant/icon/tsconfig.json create mode 100644 x-pack/packages/kbn-ai-assistant/.storybook/main.ts create mode 100644 x-pack/packages/kbn-ai-assistant/.storybook/manager.ts delete mode 100644 x-pack/packages/kbn-ai-assistant/src/buttons/ask_assistant_button.stories.tsx delete mode 100644 x-pack/packages/kbn-ai-assistant/src/buttons/hide_expand_conversation_list_button.stories.tsx delete mode 100644 x-pack/packages/kbn-ai-assistant/src/buttons/new_chat_button.stories.tsx delete mode 100644 x-pack/packages/kbn-ai-assistant/src/chat/chat_body.stories.tsx delete mode 100644 x-pack/packages/kbn-ai-assistant/src/chat/chat_flyout.stories.tsx delete mode 100644 x-pack/packages/kbn-ai-assistant/src/chat/chat_header.stories.tsx delete mode 100644 x-pack/packages/kbn-ai-assistant/src/chat/chat_timeline.stories.tsx delete mode 100644 x-pack/packages/kbn-ai-assistant/src/chat/conversation_list.stories.tsx delete mode 100644 x-pack/packages/kbn-ai-assistant/src/chat/function_list_popover.stories.tsx delete mode 100644 x-pack/packages/kbn-ai-assistant/src/chat/knowledge_base_callout.stories.tsx diff --git a/.buildkite/scripts/steps/storybooks/build_and_upload.ts b/.buildkite/scripts/steps/storybooks/build_and_upload.ts index 52aaa7e087a09..f8c52b2ded8cc 100644 --- a/.buildkite/scripts/steps/storybooks/build_and_upload.ts +++ b/.buildkite/scripts/steps/storybooks/build_and_upload.ts @@ -14,6 +14,7 @@ import { getKibanaDir } from '#pipeline-utils'; // TODO - how to generate this dynamically? const STORYBOOKS = [ + 'ai_assistant', 'apm', 'canvas', 'cases', diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index d3851871ebccd..d600b90342362 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -777,11 +777,12 @@ x-pack/examples/third_party_maps_source_example @elastic/kibana-presentation x-pack/examples/third_party_vis_lens_example @elastic/kibana-visualizations x-pack/examples/triggers_actions_ui_example @elastic/response-ops x-pack/examples/ui_actions_enhanced_examples @elastic/appex-sharedux +x-pack/packages/ai-assistant/common @elastic/search-kibana +x-pack/packages/ai-assistant/icon @elastic/appex-sharedux x-pack/packages/ai-infra/product-doc-artifact-builder @elastic/appex-ai-infra x-pack/packages/index-lifecycle-management/index_lifecycle_management_common_shared @elastic/kibana-management x-pack/packages/index-management/index_management_shared_types @elastic/kibana-management x-pack/packages/kbn-ai-assistant @elastic/search-kibana -x-pack/packages/kbn-ai-assistant-common @elastic/search-kibana x-pack/packages/kbn-alerting-comparators @elastic/response-ops x-pack/packages/kbn-alerting-state-types @elastic/response-ops x-pack/packages/kbn-cloud-security-posture/common @elastic/kibana-cloud-security-posture diff --git a/package.json b/package.json index 9081ece7803ee..ef6b73638be22 100644 --- a/package.json +++ b/package.json @@ -159,7 +159,8 @@ "@kbn/actions-types": "link:packages/kbn-actions-types", "@kbn/advanced-settings-plugin": "link:src/plugins/advanced_settings", "@kbn/ai-assistant": "link:x-pack/packages/kbn-ai-assistant", - "@kbn/ai-assistant-common": "link:x-pack/packages/kbn-ai-assistant-common", + "@kbn/ai-assistant-common": "link:x-pack/packages/ai-assistant/common", + "@kbn/ai-assistant-icon": "link:x-pack/packages/ai-assistant/icon", "@kbn/ai-assistant-management-plugin": "link:src/plugins/ai_assistant_management/selection", "@kbn/aiops-change-point-detection": "link:x-pack/platform/packages/private/ml/aiops_change_point_detection", "@kbn/aiops-common": "link:x-pack/platform/packages/shared/ml/aiops_common", diff --git a/src/dev/storybook/aliases.ts b/src/dev/storybook/aliases.ts index 1d3ec990948a9..ede798c0c543e 100644 --- a/src/dev/storybook/aliases.ts +++ b/src/dev/storybook/aliases.ts @@ -12,6 +12,7 @@ // If you wish for your Storybook to be built and included in CI, also add your // alias to .buildkite/scripts/steps/storybooks/build_and_upload.ts export const storybookAliases = { + ai_assistant: 'x-pack/packages/kbn-ai-assistant/.storybook', apm: 'x-pack/plugins/observability_solution/apm/.storybook', canvas: 'x-pack/plugins/canvas/storybook', cases: 'packages/kbn-cases-components/.storybook', diff --git a/tsconfig.base.json b/tsconfig.base.json index d083eb3ad4748..aec9a7b6841ef 100644 --- a/tsconfig.base.json +++ b/tsconfig.base.json @@ -16,8 +16,10 @@ "@kbn/advanced-settings-plugin/*": ["src/plugins/advanced_settings/*"], "@kbn/ai-assistant": ["x-pack/packages/kbn-ai-assistant"], "@kbn/ai-assistant/*": ["x-pack/packages/kbn-ai-assistant/*"], - "@kbn/ai-assistant-common": ["x-pack/packages/kbn-ai-assistant-common"], - "@kbn/ai-assistant-common/*": ["x-pack/packages/kbn-ai-assistant-common/*"], + "@kbn/ai-assistant-common": ["x-pack/packages/ai-assistant/common"], + "@kbn/ai-assistant-common/*": ["x-pack/packages/ai-assistant/common/*"], + "@kbn/ai-assistant-icon": ["x-pack/packages/ai-assistant/icon"], + "@kbn/ai-assistant-icon/*": ["x-pack/packages/ai-assistant/icon/*"], "@kbn/ai-assistant-management-plugin": ["src/plugins/ai_assistant_management/selection"], "@kbn/ai-assistant-management-plugin/*": ["src/plugins/ai_assistant_management/selection/*"], "@kbn/aiops-change-point-detection": ["x-pack/platform/packages/private/ml/aiops_change_point_detection"], diff --git a/x-pack/packages/kbn-ai-assistant-common/README.md b/x-pack/packages/ai-assistant/common/README.md similarity index 100% rename from x-pack/packages/kbn-ai-assistant-common/README.md rename to x-pack/packages/ai-assistant/common/README.md diff --git a/x-pack/packages/kbn-ai-assistant-common/index.ts b/x-pack/packages/ai-assistant/common/index.ts similarity index 100% rename from x-pack/packages/kbn-ai-assistant-common/index.ts rename to x-pack/packages/ai-assistant/common/index.ts diff --git a/x-pack/packages/kbn-ai-assistant-common/jest.config.js b/x-pack/packages/ai-assistant/common/jest.config.js similarity index 66% rename from x-pack/packages/kbn-ai-assistant-common/jest.config.js rename to x-pack/packages/ai-assistant/common/jest.config.js index 6682c06e5e764..e01aa78055da6 100644 --- a/x-pack/packages/kbn-ai-assistant-common/jest.config.js +++ b/x-pack/packages/ai-assistant/common/jest.config.js @@ -10,10 +10,10 @@ module.exports = { '/target/kibana-coverage/jest/x-pack/packages/kbn_ai_assistant_common_src', coverageReporters: ['text', 'html'], collectCoverageFrom: [ - '/x-pack/packages/kbn-ai-assistant-common/src/**/*.{ts,tsx}', - '!/x-pack/packages/kbn-ai-assistant-common/src/*.test.{ts,tsx}', + '/x-pack/packages/ai-assistant/common/src/**/*.{ts,tsx}', + '!/x-pack/packages/ai-assistant/common/src/*.test.{ts,tsx}', ], preset: '@kbn/test', - rootDir: '../../..', - roots: ['/x-pack/packages/kbn-ai-assistant-common'], + rootDir: '../../../..', + roots: ['/x-pack/packages/ai-assistant/common'], }; diff --git a/x-pack/packages/kbn-ai-assistant-common/kibana.jsonc b/x-pack/packages/ai-assistant/common/kibana.jsonc similarity index 100% rename from x-pack/packages/kbn-ai-assistant-common/kibana.jsonc rename to x-pack/packages/ai-assistant/common/kibana.jsonc diff --git a/x-pack/packages/kbn-ai-assistant-common/package.json b/x-pack/packages/ai-assistant/common/package.json similarity index 100% rename from x-pack/packages/kbn-ai-assistant-common/package.json rename to x-pack/packages/ai-assistant/common/package.json diff --git a/x-pack/packages/kbn-ai-assistant-common/setup_tests.ts b/x-pack/packages/ai-assistant/common/setup_tests.ts similarity index 100% rename from x-pack/packages/kbn-ai-assistant-common/setup_tests.ts rename to x-pack/packages/ai-assistant/common/setup_tests.ts diff --git a/x-pack/packages/kbn-ai-assistant-common/src/index.ts b/x-pack/packages/ai-assistant/common/src/index.ts similarity index 100% rename from x-pack/packages/kbn-ai-assistant-common/src/index.ts rename to x-pack/packages/ai-assistant/common/src/index.ts diff --git a/x-pack/packages/kbn-ai-assistant-common/src/types/index.ts b/x-pack/packages/ai-assistant/common/src/types/index.ts similarity index 100% rename from x-pack/packages/kbn-ai-assistant-common/src/types/index.ts rename to x-pack/packages/ai-assistant/common/src/types/index.ts diff --git a/x-pack/packages/kbn-ai-assistant-common/src/utils/filter_scopes.ts b/x-pack/packages/ai-assistant/common/src/utils/filter_scopes.ts similarity index 100% rename from x-pack/packages/kbn-ai-assistant-common/src/utils/filter_scopes.ts rename to x-pack/packages/ai-assistant/common/src/utils/filter_scopes.ts diff --git a/x-pack/packages/kbn-ai-assistant-common/src/utils/index.ts b/x-pack/packages/ai-assistant/common/src/utils/index.ts similarity index 100% rename from x-pack/packages/kbn-ai-assistant-common/src/utils/index.ts rename to x-pack/packages/ai-assistant/common/src/utils/index.ts diff --git a/x-pack/packages/kbn-ai-assistant-common/tsconfig.json b/x-pack/packages/ai-assistant/common/tsconfig.json similarity index 74% rename from x-pack/packages/kbn-ai-assistant-common/tsconfig.json rename to x-pack/packages/ai-assistant/common/tsconfig.json index 35c604906821d..2216eca4dd763 100644 --- a/x-pack/packages/kbn-ai-assistant-common/tsconfig.json +++ b/x-pack/packages/ai-assistant/common/tsconfig.json @@ -1,5 +1,5 @@ { - "extends": "../../../tsconfig.base.json", + "extends": "../../../../tsconfig.base.json", "compilerOptions": { "outDir": "target/types", "types": [ @@ -14,6 +14,5 @@ "exclude": [ "target/**/*" ], - "kbn_references": [ - ] + "kbn_references": [] } diff --git a/x-pack/packages/ai-assistant/icon/README.md b/x-pack/packages/ai-assistant/icon/README.md new file mode 100644 index 0000000000000..88c8421820fdc --- /dev/null +++ b/x-pack/packages/ai-assistant/icon/README.md @@ -0,0 +1,3 @@ +# @kbn/ai-assistant-icon + +Empty package generated by @kbn/generate diff --git a/x-pack/packages/ai-assistant/icon/__stories__/avatar.stories.tsx b/x-pack/packages/ai-assistant/icon/__stories__/avatar.stories.tsx new file mode 100644 index 0000000000000..829f18d138d5f --- /dev/null +++ b/x-pack/packages/ai-assistant/icon/__stories__/avatar.stories.tsx @@ -0,0 +1,34 @@ +/* + * 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 React from 'react'; +import { ComponentMeta, ComponentStory } from '@storybook/react'; + +import { AssistantAvatar as Component } from '../avatar'; + +export default { + title: 'Assistant Icon/Avatar', + component: Component, + argTypes: { + iconSize: { + control: 'select', + options: ['original', 's', 'm', 'l', 'xl', 'xxl', undefined], + defaultValue: undefined, + }, + size: { + control: 'select', + options: ['s', 'm', 'l', 'xl', undefined], + defaultValue: undefined, + }, + name: { + control: 'text', + defaultValue: 'Elastic Assistant', + }, + }, +} as ComponentMeta; + +export const Avatar: ComponentStory = (args) => ; diff --git a/x-pack/packages/ai-assistant/icon/__stories__/beacon.stories.tsx b/x-pack/packages/ai-assistant/icon/__stories__/beacon.stories.tsx new file mode 100644 index 0000000000000..b0a77f6cab3cb --- /dev/null +++ b/x-pack/packages/ai-assistant/icon/__stories__/beacon.stories.tsx @@ -0,0 +1,25 @@ +/* + * 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 React from 'react'; +import { ComponentMeta, ComponentStory } from '@storybook/react'; + +import { AssistantBeacon as Component } from '../beacon'; + +export default { + title: 'Assistant Icon/Beacon', + component: Component, + argTypes: { + size: { + control: 'select', + options: ['original', 's', 'm', 'l', 'xl', 'xxl'], + defaultValue: 'xxl', + }, + }, +} as ComponentMeta; + +export const Beacon: ComponentStory = (args) => ; diff --git a/x-pack/packages/ai-assistant/icon/__stories__/icon.stories.tsx b/x-pack/packages/ai-assistant/icon/__stories__/icon.stories.tsx new file mode 100644 index 0000000000000..e27ec513e7aa8 --- /dev/null +++ b/x-pack/packages/ai-assistant/icon/__stories__/icon.stories.tsx @@ -0,0 +1,25 @@ +/* + * 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 React from 'react'; +import { ComponentMeta, ComponentStory } from '@storybook/react'; + +import { AssistantIcon as Component } from '../icon'; + +export default { + title: 'Assistant Icon/Icon', + component: Component, + argTypes: { + size: { + control: 'select', + options: ['original', 's', 'm', 'l', 'xl', 'xxl'], + defaultValue: 'xxl', + }, + }, +} as ComponentMeta; + +export const Icon: ComponentStory = (args) => ; diff --git a/x-pack/packages/ai-assistant/icon/avatar.styles.ts b/x-pack/packages/ai-assistant/icon/avatar.styles.ts new file mode 100644 index 0000000000000..3b9d0b40ef274 --- /dev/null +++ b/x-pack/packages/ai-assistant/icon/avatar.styles.ts @@ -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 { useEuiTheme } from '@elastic/eui'; +import { css } from '@emotion/react'; + +export const useStyles = () => { + const { + euiTheme: { border, size }, + } = useEuiTheme(); + + const root = css` + border: ${border.thin}; + padding: ${size.xs}; + `; + + return { root }; +}; diff --git a/x-pack/packages/ai-assistant/icon/avatar.tsx b/x-pack/packages/ai-assistant/icon/avatar.tsx new file mode 100644 index 0000000000000..40142b8b30fa8 --- /dev/null +++ b/x-pack/packages/ai-assistant/icon/avatar.tsx @@ -0,0 +1,33 @@ +/* + * 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 React from 'react'; +import { EuiAvatar, EuiAvatarProps } from '@elastic/eui'; + +import { AssistantIcon } from './icon'; +import { useStyles } from './avatar.styles'; + +/** + * Avatar component for the AI Assistant. + */ +export type AssistantAvatarProps = Omit< + EuiAvatarProps, + 'iconType' | 'initials' | 'initialsLength' | 'imageUrl' +>; + +/** + * A `EuiAvatar` component customized for the AI Assistant. + */ +export const AssistantAvatar = ({ + css, + color = 'plain', + size = 'm', + ...props +}: AssistantAvatarProps) => { + const { root } = useStyles(); + return ; +}; diff --git a/x-pack/packages/ai-assistant/icon/beacon.styles.ts b/x-pack/packages/ai-assistant/icon/beacon.styles.ts new file mode 100644 index 0000000000000..5fff8e45f2031 --- /dev/null +++ b/x-pack/packages/ai-assistant/icon/beacon.styles.ts @@ -0,0 +1,138 @@ +/* + * 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 { useEuiTheme } from '@elastic/eui'; +import { css } from '@emotion/react'; +import { AssistantBeaconProps } from './beacon'; + +/** + * Returns contextually-relevant styles for the AI Assistant beacon. + */ +export const useStyles = ({ + backgroundColor = 'body', + size: iconSize = 'xxl', +}: AssistantBeaconProps) => { + const { + euiTheme: { colors, size }, + } = useEuiTheme(); + + const background = colors[backgroundColor]; + const rootSize = size[iconSize]; + + const root = css` + // Distance between the icon and the ring + --ring-padding: ${Math.max(parseInt(rootSize, 10) / 2, parseInt(size.m, 10))}px; + --ring-size: calc(${rootSize} + var(--ring-padding)); + + // Size of the mask that hides the ring at frame 0 + --mask-point: calc(var(--ring-size) + 1px); + + // Overall size of the icon, given the animation doubles the + // ring size at its end. + --root-size: calc(var(--ring-size) * 2); + + background-color: ${background}; + display: flex; + justify-content: center; + align-items: center; + position: relative; + width: var(--root-size); + height: var(--root-size); + + &:after { + content: ''; + position: absolute; + height: var(--mask-point); + width: var(--mask-point); + z-index: 2; + border: 2px solid ${background}; + border-radius: 50%; + } + `; + + const rings = css` + display: inline-block; + position: absolute; + height: var(--ring-size); + width: var(--ring-size); + + @keyframes outer { + 0% { + opacity: 1; + transform: scaleY(1) scaleX(1); + } + 20% { + opacity: 0.5; + } + 70% { + opacity: 0.2; + transform: scaleY(2) scaleX(2); + } + 80% { + opacity: 0; + transform: scaleY(2) scaleX(2); + } + 90% { + opacity: 0; + transform: scaleY(1) scaleX(1); + } + } + + @keyframes inner { + 0% { + opacity: 1; + transform: scaleY(1) scaleX(1); + } + 15% { + opacity: 1; + transform: scaleY(1) scaleX(1); + } + 40% { + opacity: 0.5; + } + 70% { + opacity: 0.2; + transform: scaleY(1.5) scaleX(1.5); + } + 80% { + opacity: 0; + transform: scaleY(1.5) scaleX(1.5); + } + 90% { + opacity: 0; + transform: scaleY(1) scaleX(1); + } + } + + &:before, + &:after { + content: ''; + position: absolute; + width: var(--ring-size); + height: var(--ring-size); + top: 0; + left: 0; + z-index: 0; + border: 1px solid ${colors.primary}; + border-radius: 50%; + animation: 4s cubic-bezier(0.42, 0, 0.37, 1) 0.5s infinite normal none running; + } + + &:before { + animation-name: inner; + } + + &:after { + animation-name: outer; + } + `; + + return { + root, + rings, + }; +}; diff --git a/x-pack/packages/ai-assistant/icon/beacon.tsx b/x-pack/packages/ai-assistant/icon/beacon.tsx new file mode 100644 index 0000000000000..12594d97efa35 --- /dev/null +++ b/x-pack/packages/ai-assistant/icon/beacon.tsx @@ -0,0 +1,43 @@ +/* + * 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 React from 'react'; + +import { EuiIconProps, EuiThemeComputed } from '@elastic/eui'; + +import { AssistantIcon } from './icon'; +import { useStyles } from './beacon.styles'; + +type Size = keyof EuiThemeComputed['size'] & EuiIconProps['size']; + +/** + * Parameters for the styles for the AI Assistant beacon. + */ +export interface AssistantBeaconProps { + /** + * Background color for the beacon. + */ + backgroundColor?: keyof EuiThemeComputed['colors']; + /** + * Size of the beacon. + */ + size?: Size; +} + +/** + * An AI Assistant icon with a pulsing ring around it, used in "hero" areas promoting functionality or prompting interaction. + */ +export const AssistantBeacon = ({ backgroundColor, size = 'xxl' }: AssistantBeaconProps) => { + const { root, rings } = useStyles({ backgroundColor, size }); + + return ( +
+ + +
+ ); +}; diff --git a/x-pack/packages/ai-assistant/icon/icon.tsx b/x-pack/packages/ai-assistant/icon/icon.tsx new file mode 100644 index 0000000000000..39b4d9391df29 --- /dev/null +++ b/x-pack/packages/ai-assistant/icon/icon.tsx @@ -0,0 +1,24 @@ +/* + * 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 React from 'react'; +import { EuiIcon, EuiIconProps } from '@elastic/eui'; +import { dynamic } from '@kbn/shared-ux-utility'; + +/** + * Props for the AI Assistant icon. + */ +export type AssistantIconProps = Omit; + +/** + * Default Elastic AI Assistant icon. + */ +export const AssistantIcon = ({ size = 'm', ...rest }: AssistantIconProps) => { + // TODO: can be removed once added to EUI. + const type = dynamic(() => import('./svg/assistant')); + return ; +}; diff --git a/x-pack/packages/ai-assistant/icon/index.ts b/x-pack/packages/ai-assistant/icon/index.ts new file mode 100644 index 0000000000000..4cf6a0daacab3 --- /dev/null +++ b/x-pack/packages/ai-assistant/icon/index.ts @@ -0,0 +1,10 @@ +/* + * 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. + */ + +export { AssistantAvatar, type AssistantAvatarProps } from './avatar'; +export { AssistantBeacon, type AssistantBeaconProps } from './beacon'; +export { AssistantIcon, type AssistantIconProps } from './icon'; diff --git a/x-pack/packages/ai-assistant/icon/jest.config.js b/x-pack/packages/ai-assistant/icon/jest.config.js new file mode 100644 index 0000000000000..77d4d4520e463 --- /dev/null +++ b/x-pack/packages/ai-assistant/icon/jest.config.js @@ -0,0 +1,12 @@ +/* + * 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. + */ + +module.exports = { + preset: '@kbn/test', + rootDir: '../../../..', + roots: ['/x-pack/packages/ai-assistant/icon'], +}; diff --git a/x-pack/packages/ai-assistant/icon/kibana.jsonc b/x-pack/packages/ai-assistant/icon/kibana.jsonc new file mode 100644 index 0000000000000..d38bc90dbe4d0 --- /dev/null +++ b/x-pack/packages/ai-assistant/icon/kibana.jsonc @@ -0,0 +1,5 @@ +{ + "type": "shared-common", + "id": "@kbn/ai-assistant-icon", + "owner": "@elastic/appex-sharedux" +} \ No newline at end of file diff --git a/x-pack/packages/ai-assistant/icon/package.json b/x-pack/packages/ai-assistant/icon/package.json new file mode 100644 index 0000000000000..c88a4d89d8945 --- /dev/null +++ b/x-pack/packages/ai-assistant/icon/package.json @@ -0,0 +1,6 @@ +{ + "name": "@kbn/ai-assistant-icon", + "private": true, + "version": "1.0.0", + "license": "Elastic License 2.0" +} \ No newline at end of file diff --git a/x-pack/packages/ai-assistant/icon/svg/assistant.svg b/x-pack/packages/ai-assistant/icon/svg/assistant.svg new file mode 100644 index 0000000000000..d4334388fd468 --- /dev/null +++ b/x-pack/packages/ai-assistant/icon/svg/assistant.svg @@ -0,0 +1,9 @@ + + + + + + diff --git a/x-pack/packages/ai-assistant/icon/svg/assistant.tsx b/x-pack/packages/ai-assistant/icon/svg/assistant.tsx new file mode 100644 index 0000000000000..9d47665d3e06e --- /dev/null +++ b/x-pack/packages/ai-assistant/icon/svg/assistant.tsx @@ -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 React from 'react'; + +const AssistantLogo = (props: React.SVGProps) => ( + + + + + + +); + +// eslint-disable-next-line import/no-default-export +export { AssistantLogo as default }; diff --git a/x-pack/packages/ai-assistant/icon/tsconfig.json b/x-pack/packages/ai-assistant/icon/tsconfig.json new file mode 100644 index 0000000000000..f0c3b42228b4d --- /dev/null +++ b/x-pack/packages/ai-assistant/icon/tsconfig.json @@ -0,0 +1,23 @@ +{ + "extends": "../../../../tsconfig.base.json", + "compilerOptions": { + "outDir": "target/types", + "types": [ + "jest", + "node", + "react", + "@emotion/react/types/css-prop", + "@kbn/ambient-ui-types" + ] + }, + "include": [ + "**/*.ts", + "**/*.tsx", + ], + "exclude": [ + "target/**/*" + ], + "kbn_references": [ + "@kbn/shared-ux-utility", + ] +} diff --git a/x-pack/packages/kbn-ai-assistant/.storybook/main.ts b/x-pack/packages/kbn-ai-assistant/.storybook/main.ts new file mode 100644 index 0000000000000..d612cb1a8990d --- /dev/null +++ b/x-pack/packages/kbn-ai-assistant/.storybook/main.ts @@ -0,0 +1,16 @@ +/* + * 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 { defaultConfig } from '@kbn/storybook'; + +module.exports = { + ...defaultConfig, + stories: ['../**/*.stories.tsx', '../../ai-assistant/**/*.stories.tsx'], + reactOptions: { + strictMode: true, + }, +}; diff --git a/x-pack/packages/kbn-ai-assistant/.storybook/manager.ts b/x-pack/packages/kbn-ai-assistant/.storybook/manager.ts new file mode 100644 index 0000000000000..548bd62b3779c --- /dev/null +++ b/x-pack/packages/kbn-ai-assistant/.storybook/manager.ts @@ -0,0 +1,20 @@ +/* + * 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 { addons } from '@storybook/addons'; +import { create } from '@storybook/theming'; +import { PANEL_ID } from '@storybook/addon-actions'; + +addons.setConfig({ + theme: create({ + base: 'light', + brandTitle: 'AI Assistant Storybook', + brandUrl: 'https://github.com/elastic/kibana/tree/main/x-pack/packages/kbn-ai-assistant', + }), + showPanel: true.valueOf, + selectedPanel: PANEL_ID, +}); diff --git a/x-pack/packages/kbn-ai-assistant/src/buttons/ask_assistant_button.stories.tsx b/x-pack/packages/kbn-ai-assistant/src/buttons/ask_assistant_button.stories.tsx deleted file mode 100644 index 9c0d19e3c4b75..0000000000000 --- a/x-pack/packages/kbn-ai-assistant/src/buttons/ask_assistant_button.stories.tsx +++ /dev/null @@ -1,51 +0,0 @@ -/* - * 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 React from 'react'; -import { ComponentStory } from '@storybook/react'; -import { EuiButtonSize } from '@elastic/eui'; - -import { AskAssistantButton as Component, AskAssistantButtonProps } from './ask_assistant_button'; - -export default { - component: Component, - title: 'app/Atoms/AskAiAssistantButton', - argTypes: { - size: { - options: ['xs', 's', 'm'] as EuiButtonSize[], - control: { type: 'radio' }, - }, - fill: { - control: { - type: 'boolean', - }, - }, - flush: { - control: { - type: 'boolean', - if: { arg: 'variant', eq: 'empty' }, - }, - }, - variant: { - options: ['basic', 'empty', 'iconOnly'], - control: { type: 'radio' }, - }, - }, -}; - -const Template: ComponentStory = (props: AskAssistantButtonProps) => ( - -); - -const defaultProps = { - fill: true, - size: 'm' as EuiButtonSize, - variant: 'basic' as const, -}; - -export const AskAiAssistantButton = Template.bind({}); -AskAiAssistantButton.args = defaultProps; diff --git a/x-pack/packages/kbn-ai-assistant/src/buttons/hide_expand_conversation_list_button.stories.tsx b/x-pack/packages/kbn-ai-assistant/src/buttons/hide_expand_conversation_list_button.stories.tsx deleted file mode 100644 index d49ccdfb3823d..0000000000000 --- a/x-pack/packages/kbn-ai-assistant/src/buttons/hide_expand_conversation_list_button.stories.tsx +++ /dev/null @@ -1,37 +0,0 @@ -/* - * 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 React from 'react'; -import { ComponentStory } from '@storybook/react'; - -import { - HideExpandConversationListButton as Component, - HideExpandConversationListButtonProps, -} from './hide_expand_conversation_list_button'; - -export default { - component: Component, - title: 'app/Atoms/HideExpandConversationListButton', - argTypes: { - isExpanded: { - control: { - type: 'boolean', - }, - }, - }, -}; - -const Template: ComponentStory = ( - props: HideExpandConversationListButtonProps -) => ; - -const defaultProps = { - isExpanded: true, -}; - -export const HideExpandConversationListButton = Template.bind({}); -HideExpandConversationListButton.args = defaultProps; diff --git a/x-pack/packages/kbn-ai-assistant/src/buttons/new_chat_button.stories.tsx b/x-pack/packages/kbn-ai-assistant/src/buttons/new_chat_button.stories.tsx deleted file mode 100644 index f4e0cae677ef0..0000000000000 --- a/x-pack/packages/kbn-ai-assistant/src/buttons/new_chat_button.stories.tsx +++ /dev/null @@ -1,19 +0,0 @@ -/* - * 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 { ComponentMeta, ComponentStoryObj } from '@storybook/react'; -import { NewChatButton as Component } from './new_chat_button'; - -const meta: ComponentMeta = { - component: Component, - title: 'app/Atoms/NewChatButton', -}; - -export default meta; - -export const NewChatButton: ComponentStoryObj = { - args: {}, -}; diff --git a/x-pack/packages/kbn-ai-assistant/src/chat/chat_body.stories.tsx b/x-pack/packages/kbn-ai-assistant/src/chat/chat_body.stories.tsx deleted file mode 100644 index 3809e97f059b6..0000000000000 --- a/x-pack/packages/kbn-ai-assistant/src/chat/chat_body.stories.tsx +++ /dev/null @@ -1,81 +0,0 @@ -/* - * 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 { ComponentMeta, ComponentStoryObj } from '@storybook/react'; -import React from 'react'; -import { MessageRole } from '@kbn/observability-ai-assistant-plugin/public'; -import { buildSystemMessage } from '../utils/builders'; -import { KibanaReactStorybookDecorator } from '../utils/storybook_decorator.stories'; -import { ChatBody as Component } from './chat_body'; - -const meta: ComponentMeta = { - component: Component, - title: 'app/Organisms/ChatBody', - decorators: [KibanaReactStorybookDecorator], -}; - -export default meta; -const defaultProps: ComponentStoryObj = { - args: { - initialTitle: 'My Conversation', - initialMessages: [ - buildSystemMessage(), - { - '@timestamp': new Date().toISOString(), - message: { - role: MessageRole.User, - content: `{"entries":[{"@timestamp":"2023-08-04T06:31:15.160Z","public":false,"confidence":"high","is_correction":false,"namespace":"default","text":"The user's name is Dario.","user":{"name":"elastic","id":"u_mGBROF_q5bmFCATbLXAcCwKa0k8JvONAwSruelyKA5E_0"},"ml":{"model_id":".elser_model_1"}},{"@timestamp":"2023-08-03T16:53:21.848Z","public":true,"confidence":"high","is_correction":false,"namespace":"default","text":"The RENAME command in ES|QL is used to rename a column. The syntax is 'RENAME = '. For example, 'FROM employees | KEEP first_name, last_name, still_hired | RENAME employed = still_hired' will rename the 'still_hired' column to 'employed'. If a column with the new name already exists, it will be replaced by the new column. Multiple columns can be renamed with a single RENAME command.","user":{"name":"elastic","id":"u_mGBROF_q5bmFCATbLXAcCwKa0k8JvONAwSruelyKA5E_0"},"ml":{"model_id":".elser_model_1"}},{"@timestamp":"2023-08-03T16:52:02.052Z","public":true,"confidence":"high","is_correction":false,"namespace":"default","text":"The KEEP command in ES|QL is used to specify what columns are returned and the order in which they are returned. To limit the columns that are returned, a comma-separated list of column names is used. The columns are then returned in the specified order. Wildcards can also be used to return all columns with a name that matches a pattern. For example, 'FROM employees | KEEP h*' will return all columns with a name that starts with an 'h'. The asterisk wildcard (*) by itself translates to all columns that do not match the other arguments.","user":{"name":"elastic","id":"u_mGBROF_q5bmFCATbLXAcCwKa0k8JvONAwSruelyKA5E_0"},"ml":{"model_id":".elser_model_1"}},{"@timestamp":"2023-08-03T16:55:18.984Z","public":true,"confidence":"high","is_correction":false,"namespace":"default","text":"The WHERE command in ES|QL is used to produce a table that contains all the rows from the input table for which the provided condition evaluates to true. For example, 'FROM employees | KEEP first_name, last_name, still_hired | WHERE still_hired == true' will return only the rows where 'still_hired' is true. WHERE supports various operators and functions for calculating values.","user":{"name":"elastic","id":"u_mGBROF_q5bmFCATbLXAcCwKa0k8JvONAwSruelyKA5E_0"},"ml":{"model_id":".elser_model_1"}},{"@timestamp":"2023-08-03T16:53:57.401Z","public":true,"confidence":"high","is_correction":false,"namespace":"default","text":"The SORT command in ES|QL is used to sort rows on one or more fields. The default sort order is ascending, but this can be explicitly set using ASC or DESC. For example, 'FROM employees | KEEP first_name, last_name, height | SORT height DESC' will sort the rows in descending order of height. Additional sort expressions can be provided to act as tie breakers. By default, null values are treated as being larger than any other value, meaning they are sorted last in an ascending order and first in a descending order. This can be changed by providing NULLS FIRST or NULLS LAST.","user":{"name":"elastic","id":"u_mGBROF_q5bmFCATbLXAcCwKa0k8JvONAwSruelyKA5E_0"},"ml":{"model_id":".elser_model_1"}},{"@timestamp":"2023-08-03T16:50:09.345Z","public":true,"confidence":"high","is_correction":false,"namespace":"default","text":"The EVAL command in ES|QL is used to append new columns to a table. For example, 'FROM employees | KEEP first_name, last_name, height | EVAL height_feet = height * 3.281, height_cm = height * 100' will append new columns 'height_feet' and 'height_cm' to the 'employees' table. If the specified column already exists, the existing column will be dropped, and the new column will be appended to the table. EVAL supports various functions for calculating values.","user":{"name":"elastic","id":"u_mGBROF_q5bmFCATbLXAcCwKa0k8JvONAwSruelyKA5E_0"},"ml":{"model_id":".elser_model_1"}},{"@timestamp":"2023-08-03T16:49:37.882Z","public":true,"confidence":"high","is_correction":false,"namespace":"default","text":"The ENRICH command in ES|QL is used to add data from existing indices to incoming records at query time. It requires an enrich policy to be executed, which defines a match field and a set of enrich fields. ENRICH looks for records in the enrich index based on the match field value. The matching key in the input dataset can be defined using 'ON '. If it’s not specified, the match will be performed on a field with the same name as the match field defined in the enrich policy. You can specify which attributes to be added to the result using 'WITH , ...' syntax. Attributes can also be renamed using 'WITH new_name='. By default, ENRICH will add all the enrich fields defined in the enrich policy to the result. In case of name collisions, the newly created fields will override the existing fields.","user":{"name":"elastic","id":"u_mGBROF_q5bmFCATbLXAcCwKa0k8JvONAwSruelyKA5E_0"},"ml":{"model_id":".elser_model_1"}},{"@timestamp":"2023-08-03T16:50:45.339Z","public":true,"confidence":"high","is_correction":false,"namespace":"default","text":"The GROK command in ES|QL enables you to extract structured data out of a string. GROK matches the string against patterns, based on regular expressions, and extracts the specified patterns as columns. For example, 'ROW a = "1953-01-23T12:15:00Z 127.0.0.1 some.email@foo.com 42" | GROK a "%{TIMESTAMP_ISO8601:date} %{IP:ip} %{EMAILADDRESS:email} %{NUMBER:num:int}" | KEEP date, ip, email, num' will extract the date, IP, email, and number from the string into separate columns. Refer to the grok processor documentation for the syntax of grok patterns.","user":{"name":"elastic","id":"u_mGBROF_q5bmFCATbLXAcCwKa0k8JvONAwSruelyKA5E_0"},"ml":{"model_id":".elser_model_1"}},{"@timestamp":"2023-08-03T16:44:22.647Z","public":true,"confidence":"high","is_correction":false,"namespace":"default","text":"The FROM source command in ES|QL returns a table with up to 10,000 documents from a data stream, index, or alias. Each row in the table represents a document, and each column corresponds to a field, which can be accessed by the name of that field. Date math can be used to refer to indices, aliases and data streams, which is useful for time series data. Comma-separated lists or wildcards can be used to query multiple data streams, indices, or aliases.","user":{"name":"elastic","id":"u_mGBROF_q5bmFCATbLXAcCwKa0k8JvONAwSruelyKA5E_0"},"ml":{"model_id":".elser_model_1"}},{"@timestamp":"2023-08-03T16:42:52.832Z","public":true,"confidence":"high","is_correction":false,"namespace":"default","text":"ES|QL, the Elasticsearch Query Language, is a query language designed for iterative data exploration. An ES|QL query consists of a series of commands, separated by pipes. Each query starts with a source command that produces a table, typically with data from Elasticsearch. This can be followed by one or more processing commands that modify the input table by adding, removing, or changing rows and columns. Processing commands can be chained together, with each command working on the output table of the previous command. The result of a query is the table produced by the final processing command. ES|QL can be used via the _esql endpoint, and results are returned as JSON by default. It can also be used in Kibana's Discover and Lens features for data exploration and visualization. Currently, ES|QL supports field types such as alias, boolean, date, ip, keyword family, double/float/half_float, long int/short/byte, and version.","user":{"name":"elastic","id":"u_mGBROF_q5bmFCATbLXAcCwKa0k8JvONAwSruelyKA5E_0"},"ml":{"model_id":".elser_model_1"}}]}`, - }, - }, - ], - knowledgeBase: { - status: { - loading: false, - value: { - ready: true, - enabled: true, - }, - refresh: () => {}, - }, - isInstalling: false, - install: async () => {}, - }, - connectors: { - connectors: [ - { - id: 'foo', - referencedByCount: 1, - actionTypeId: 'foo', - name: 'GPT-v8-ultra', - isPreconfigured: true, - isDeprecated: false, - isSystemAction: false, - }, - ], - loading: false, - error: undefined, - selectedConnector: 'foo', - selectConnector: () => {}, - reloadConnectors: () => {}, - }, - currentUser: { - username: 'elastic', - full_name: '', - }, - }, - render: (props) => { - return ( -
- -
- ); - }, -}; - -export const ChatBody: ComponentStoryObj = { - ...defaultProps, -}; diff --git a/x-pack/packages/kbn-ai-assistant/src/chat/chat_flyout.stories.tsx b/x-pack/packages/kbn-ai-assistant/src/chat/chat_flyout.stories.tsx deleted file mode 100644 index 72546d770e6a6..0000000000000 --- a/x-pack/packages/kbn-ai-assistant/src/chat/chat_flyout.stories.tsx +++ /dev/null @@ -1,40 +0,0 @@ -/* - * 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 { ComponentStory } from '@storybook/react'; -import React from 'react'; -import { buildSystemMessage } from '../utils/builders'; -import { KibanaReactStorybookDecorator } from '../utils/storybook_decorator.stories'; -import { ChatFlyout as Component, FlyoutPositionMode } from './chat_flyout'; - -export default { - component: Component, - title: 'app/Organisms/ChatFlyout', - decorators: [KibanaReactStorybookDecorator], -}; - -type ChatFlyoutProps = React.ComponentProps; - -const Template: ComponentStory = (props: ChatFlyoutProps) => { - return ( -
- -
- ); -}; - -const defaultProps: ChatFlyoutProps = { - isOpen: true, - initialTitle: 'How is this working', - initialMessages: [buildSystemMessage()], - initialFlyoutPositionMode: FlyoutPositionMode.OVERLAY, - onClose: () => {}, - navigateToConversation: () => {}, -}; - -export const ChatFlyout = Template.bind({}); -ChatFlyout.args = defaultProps; diff --git a/x-pack/packages/kbn-ai-assistant/src/chat/chat_header.stories.tsx b/x-pack/packages/kbn-ai-assistant/src/chat/chat_header.stories.tsx deleted file mode 100644 index 0a61e16070232..0000000000000 --- a/x-pack/packages/kbn-ai-assistant/src/chat/chat_header.stories.tsx +++ /dev/null @@ -1,41 +0,0 @@ -/* - * 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 React from 'react'; -import { ComponentMeta, ComponentStoryObj } from '@storybook/react'; -import { FindActionResult } from '@kbn/actions-plugin/server'; -import { EuiPanel } from '@elastic/eui'; -import { ChatHeader as Component } from './chat_header'; - -const meta: ComponentMeta = { - component: Component, - title: 'app/Molecules/ChatHeader', -}; - -export default meta; - -export const ChatHeaderLoaded: ComponentStoryObj = { - args: { - title: 'My conversation', - connectors: { - loading: false, - selectedConnector: 'gpt-4', - connectors: [ - { id: 'gpt-4', name: 'OpenAI GPT-4' }, - { id: 'gpt-3.5-turbo', name: 'OpenAI GPT-3.5 Turbo' }, - ] as FindActionResult[], - selectConnector: () => {}, - reloadConnectors: () => {}, - }, - }, - render: (props) => { - return ( - - - - ); - }, -}; diff --git a/x-pack/packages/kbn-ai-assistant/src/chat/chat_timeline.stories.tsx b/x-pack/packages/kbn-ai-assistant/src/chat/chat_timeline.stories.tsx deleted file mode 100644 index 7c04c3ad0bae7..0000000000000 --- a/x-pack/packages/kbn-ai-assistant/src/chat/chat_timeline.stories.tsx +++ /dev/null @@ -1,134 +0,0 @@ -/* - * 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 { EuiButton, EuiSpacer } from '@elastic/eui'; -import type { ComponentStory } from '@storybook/react'; -import React, { type ComponentProps, useState } from 'react'; -import { - MessageRole, - type ObservabilityAIAssistantChatService, -} from '@kbn/observability-ai-assistant-plugin/public'; -import { ChatState } from '@kbn/observability-ai-assistant-plugin/public'; -import { - buildAssistantMessage, - buildFunctionResponseMessage, - buildSystemMessage, - buildUserMessage, -} from '../utils/builders'; -import { ChatTimeline as Component, type ChatTimelineProps } from './chat_timeline'; - -export default { - component: Component, - title: 'app/Organisms/ChatTimeline', - parameters: { - backgrounds: { - default: 'white', - values: [{ name: 'white', value: '#fff' }], - }, - }, - argTypes: {}, -}; - -const Template: ComponentStory = (props: ChatTimelineProps) => { - const [count, setCount] = useState(props.messages.length - 1); - - return ( - <> - index <= count)} /> - - - - setCount(count >= 0 && count < props.messages.length - 1 ? count + 1 : 0)} - > - Add message - - - ); -}; - -const defaultProps: ComponentProps = { - knowledgeBase: { - status: { - loading: false, - value: { - ready: true, - enabled: true, - }, - refresh: () => {}, - }, - isInstalling: false, - installError: undefined, - install: async () => {}, - }, - chatService: { - hasRenderFunction: () => false, - } as unknown as ObservabilityAIAssistantChatService, - chatState: ChatState.Ready, - hasConnector: true, - currentUser: { - full_name: 'John Doe', - username: 'johndoe', - }, - messages: [ - buildSystemMessage(), - buildUserMessage(), - buildAssistantMessage(), - buildUserMessage({ message: { content: 'How does it work?' } }), - buildAssistantMessage({ - message: { - content: `The way functions work depends on whether we are talking about mathematical functions or programming functions. Let's explore both: - - Mathematical Functions: - In mathematics, a function maps input values to corresponding output values based on a specific rule or expression. The general process of how a mathematical function works can be summarized as follows: - Step 1: Input - You provide an input value to the function, denoted as 'x' in the notation f(x). This value represents the independent variable. - - Step 2: Processing - The function takes the input value and applies a specific rule or algorithm to it. This rule is defined by the function itself and varies depending on the function's expression. - - Step 3: Output - After processing the input, the function produces an output value, denoted as 'f(x)' or 'y'. This output represents the dependent variable and is the result of applying the function's rule to the input. - - Step 4: Uniqueness - A well-defined mathematical function ensures that each input value corresponds to exactly one output value. In other words, the function should yield the same output for the same input whenever it is called.`, - }, - }), - buildUserMessage({ - message: { content: 'Can you execute a function?' }, - }), - buildAssistantMessage({ - message: { - content: 'Sure, I can do that.', - function_call: { - name: 'a_function', - arguments: '{ "foo": "bar" }', - trigger: MessageRole.Assistant, - }, - }, - }), - buildFunctionResponseMessage({ - message: { content: '{ "message": "The arguments are wrong" }' }, - }), - buildAssistantMessage({ - message: { - content: '', - function_call: { - name: 'a_function', - arguments: '{ "bar": "foo" }', - trigger: MessageRole.Assistant, - }, - }, - }), - ], - onActionClick: async () => {}, - onEdit: async () => {}, - onFeedback: () => {}, - onRegenerate: () => {}, - onSendTelemetry: () => {}, - onStopGenerating: () => {}, -}; - -export const ChatTimeline = Template.bind({}); -ChatTimeline.args = defaultProps; diff --git a/x-pack/packages/kbn-ai-assistant/src/chat/conversation_list.stories.tsx b/x-pack/packages/kbn-ai-assistant/src/chat/conversation_list.stories.tsx deleted file mode 100644 index 7405b477647fd..0000000000000 --- a/x-pack/packages/kbn-ai-assistant/src/chat/conversation_list.stories.tsx +++ /dev/null @@ -1,93 +0,0 @@ -/* - * 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 { ComponentMeta, ComponentStoryObj } from '@storybook/react'; -import React from 'react'; -import { buildConversation } from '../utils/builders'; -import { KibanaReactStorybookDecorator } from '../utils/storybook_decorator.stories'; -import { ConversationList as Component } from './conversation_list'; - -type ConversationListProps = React.ComponentProps; - -const meta: ComponentMeta = { - component: Component, - title: 'app/Organisms/ConversationList', - decorators: [KibanaReactStorybookDecorator], -}; - -export default meta; - -const Wrapper = (props: ConversationListProps) => { - return ( -
- -
- ); -}; - -export const ConversationListLoading: ComponentStoryObj = { - args: { - conversations: { - loading: true, - error: undefined, - value: { conversations: [] }, - refresh: () => {}, - }, - isLoading: true, - }, - render: Wrapper, -}; - -export const ConversationListError: ComponentStoryObj = { - args: { - conversations: { - loading: false, - error: new Error('Failed to load conversations'), - value: { conversations: [] }, - refresh: () => {}, - }, - isLoading: false, - }, - render: Wrapper, -}; - -export const ConversationListLoaded: ComponentStoryObj = { - args: { - conversations: { - loading: false, - error: undefined, - value: { - conversations: [ - buildConversation({ - conversation: { - id: 'foo', - title: 'Why is database service responding with errors after I did rm -rf /postgres', - last_updated: '', - }, - }), - ], - }, - refresh: () => {}, - }, - selectedConversationId: '', - }, - render: Wrapper, -}; - -export const ConversationListEmpty: ComponentStoryObj = { - args: { - conversations: { - loading: false, - error: undefined, - value: { conversations: [] }, - refresh: () => {}, - }, - isLoading: false, - selectedConversationId: '', - }, - render: Wrapper, -}; diff --git a/x-pack/packages/kbn-ai-assistant/src/chat/function_list_popover.stories.tsx b/x-pack/packages/kbn-ai-assistant/src/chat/function_list_popover.stories.tsx deleted file mode 100644 index 62da0b2d14ff8..0000000000000 --- a/x-pack/packages/kbn-ai-assistant/src/chat/function_list_popover.stories.tsx +++ /dev/null @@ -1,33 +0,0 @@ -/* - * 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 { ComponentStory } from '@storybook/react'; -import React from 'react'; -import { KibanaReactStorybookDecorator } from '../utils/storybook_decorator.stories'; -import { FunctionListPopover as Component } from './function_list_popover'; - -export default { - component: Component, - title: 'app/Organisms/FunctionListPopover', - decorators: [KibanaReactStorybookDecorator], -}; - -type FunctionListPopover = React.ComponentProps; - -const Template: ComponentStory = (props: FunctionListPopover) => { - return ; -}; - -const defaultProps: FunctionListPopover = { - onSelectFunction: () => {}, - disabled: false, - mode: 'function', - selectedFunctionName: '', -}; - -export const FunctionListPopover = Template.bind({}); -FunctionListPopover.args = defaultProps; diff --git a/x-pack/packages/kbn-ai-assistant/src/chat/knowledge_base_callout.stories.tsx b/x-pack/packages/kbn-ai-assistant/src/chat/knowledge_base_callout.stories.tsx deleted file mode 100644 index 84c730129348e..0000000000000 --- a/x-pack/packages/kbn-ai-assistant/src/chat/knowledge_base_callout.stories.tsx +++ /dev/null @@ -1,74 +0,0 @@ -/* - * 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 { ComponentMeta, ComponentStoryObj } from '@storybook/react'; -import { merge } from 'lodash'; -import { KibanaReactStorybookDecorator } from '../utils/storybook_decorator.stories'; -import { KnowledgeBaseCallout as Component } from './knowledge_base_callout'; - -const meta: ComponentMeta = { - component: Component, - title: 'app/Molecules/KnowledgeBaseCallout', - decorators: [KibanaReactStorybookDecorator], -}; - -export default meta; -const defaultProps: ComponentStoryObj = { - args: { - knowledgeBase: { - status: { - loading: false, - value: { - ready: false, - enabled: true, - }, - refresh: () => {}, - }, - isInstalling: false, - installError: undefined, - install: async () => {}, - }, - }, -}; - -export const StatusError: ComponentStoryObj = merge({}, defaultProps, { - args: { knowledgeBase: { status: { loading: false, error: new Error() } } }, -}); - -export const Loading: ComponentStoryObj = merge({}, defaultProps, { - args: { knowledgeBase: { status: { loading: true } } }, -}); - -export const NotInstalled: ComponentStoryObj = merge({}, defaultProps, { - args: { knowledgeBase: { status: { loading: false, value: { ready: false, enabled: true } } } }, -}); - -export const Installing: ComponentStoryObj = merge({}, defaultProps, { - args: { - knowledgeBase: { - status: { loading: false, value: { ready: false, enabled: true } }, - isInstalling: true, - }, - }, -}); - -export const InstallError: ComponentStoryObj = merge({}, defaultProps, { - args: { - knowledgeBase: { - status: { - loading: false, - value: { ready: false, enabled: true }, - }, - isInstalling: false, - installError: new Error(), - }, - }, -}); - -export const Installed: ComponentStoryObj = merge({}, defaultProps, { - args: { knowledgeBase: { status: { loading: false, value: { ready: true, enabled: true } } } }, -}); diff --git a/x-pack/packages/kbn-ai-assistant/tsconfig.json b/x-pack/packages/kbn-ai-assistant/tsconfig.json index 5ba1b161bccba..159a38f67f426 100644 --- a/x-pack/packages/kbn-ai-assistant/tsconfig.json +++ b/x-pack/packages/kbn-ai-assistant/tsconfig.json @@ -12,6 +12,8 @@ "include": [ "**/*.ts", "**/*.tsx", + ".storybook/**/*.ts", + ".storybook/**/*.tsx", ], "exclude": [ "target/**/*" @@ -35,5 +37,6 @@ "@kbn/ml-plugin", "@kbn/share-plugin", "@kbn/ai-assistant-common", + "@kbn/storybook", ] } diff --git a/x-pack/packages/kbn-elastic-assistant/impl/assistant/assistant_animated_icon.tsx b/x-pack/packages/kbn-elastic-assistant/impl/assistant/assistant_animated_icon.tsx index f569ca1450caf..f3990dd0b7362 100644 --- a/x-pack/packages/kbn-elastic-assistant/impl/assistant/assistant_animated_icon.tsx +++ b/x-pack/packages/kbn-elastic-assistant/impl/assistant/assistant_animated_icon.tsx @@ -120,6 +120,9 @@ const AvatarWrapper = styled.span` } `; +/** + * @deprecated This component will soon be replaced by `AssistantBeacon` from `@kbn/ai-assistant-icon`. + */ export const AssistantAnimatedIcon = React.memo(() => ( diff --git a/x-pack/packages/kbn-elastic-assistant/impl/assistant/assistant_avatar/assistant_avatar.tsx b/x-pack/packages/kbn-elastic-assistant/impl/assistant/assistant_avatar/assistant_avatar.tsx index 0c66b412fc5d2..205a2c7b7bac3 100644 --- a/x-pack/packages/kbn-elastic-assistant/impl/assistant/assistant_avatar/assistant_avatar.tsx +++ b/x-pack/packages/kbn-elastic-assistant/impl/assistant/assistant_avatar/assistant_avatar.tsx @@ -27,7 +27,7 @@ export const sizeMap = { /** * Default Elastic AI Assistant logo * - * TODO: Can be removed once added to EUI + * @deprecated This component will soon be replaced by `AssistantIcon` from `@kbn/ai-assistant-icon`. */ export const AssistantAvatar = ({ className, size = 's' }: AssistantAvatarProps) => ( (