Skip to content

Commit

Permalink
[ai][assistant] Create AI Assistant Icon, Avatar, Beacon
Browse files Browse the repository at this point in the history
  • Loading branch information
clintandrewhall committed Dec 12, 2024
1 parent 7b9dd35 commit 2f05128
Show file tree
Hide file tree
Showing 50 changed files with 508 additions and 617 deletions.
1 change: 1 addition & 0 deletions .buildkite/scripts/steps/storybooks/build_and_upload.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import { getKibanaDir } from '#pipeline-utils';

// TODO - how to generate this dynamically?
const STORYBOOKS = [
'ai_assistant',
'apm',
'canvas',
'cases',
Expand Down
3 changes: 2 additions & 1 deletion .github/CODEOWNERS
Validating CODEOWNERS rules …
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
1 change: 1 addition & 0 deletions src/dev/storybook/aliases.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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',
Expand Down
6 changes: 4 additions & 2 deletions tsconfig.base.json
Original file line number Diff line number Diff line change
Expand Up @@ -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"],
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,10 @@ module.exports = {
'<rootDir>/target/kibana-coverage/jest/x-pack/packages/kbn_ai_assistant_common_src',
coverageReporters: ['text', 'html'],
collectCoverageFrom: [
'<rootDir>/x-pack/packages/kbn-ai-assistant-common/src/**/*.{ts,tsx}',
'!<rootDir>/x-pack/packages/kbn-ai-assistant-common/src/*.test.{ts,tsx}',
'<rootDir>/x-pack/packages/ai-assistant/common/src/**/*.{ts,tsx}',
'!<rootDir>/x-pack/packages/ai-assistant/common/src/*.test.{ts,tsx}',
],
preset: '@kbn/test',
rootDir: '../../..',
roots: ['<rootDir>/x-pack/packages/kbn-ai-assistant-common'],
rootDir: '../../../..',
roots: ['<rootDir>/x-pack/packages/ai-assistant/common'],
};
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"extends": "../../../tsconfig.base.json",
"extends": "../../../../tsconfig.base.json",
"compilerOptions": {
"outDir": "target/types",
"types": [
Expand All @@ -14,6 +14,5 @@
"exclude": [
"target/**/*"
],
"kbn_references": [
]
"kbn_references": []
}
3 changes: 3 additions & 0 deletions x-pack/packages/ai-assistant/icon/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# @kbn/ai-assistant-icon

Empty package generated by @kbn/generate
34 changes: 34 additions & 0 deletions x-pack/packages/ai-assistant/icon/__stories__/avatar.stories.tsx
Original file line number Diff line number Diff line change
@@ -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<typeof Component>;

export const Avatar: ComponentStory<typeof Component> = (args) => <Component {...args} />;
25 changes: 25 additions & 0 deletions x-pack/packages/ai-assistant/icon/__stories__/beacon.stories.tsx
Original file line number Diff line number Diff line change
@@ -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<typeof Component>;

export const Beacon: ComponentStory<typeof Component> = (args) => <Component {...args} />;
25 changes: 25 additions & 0 deletions x-pack/packages/ai-assistant/icon/__stories__/icon.stories.tsx
Original file line number Diff line number Diff line change
@@ -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<typeof Component>;

export const Icon: ComponentStory<typeof Component> = (args) => <Component {...args} />;
22 changes: 22 additions & 0 deletions x-pack/packages/ai-assistant/icon/avatar.styles.ts
Original file line number Diff line number Diff line change
@@ -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 };
};
33 changes: 33 additions & 0 deletions x-pack/packages/ai-assistant/icon/avatar.tsx
Original file line number Diff line number Diff line change
@@ -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 <EuiAvatar {...{ ...props, color, size }} css={[root, css]} iconType={AssistantIcon} />;
};
138 changes: 138 additions & 0 deletions x-pack/packages/ai-assistant/icon/beacon.styles.ts
Original file line number Diff line number Diff line change
@@ -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,
};
};
Loading

0 comments on commit 2f05128

Please sign in to comment.