diff --git a/.buildkite/scripts/steps/storybooks/build_and_upload.js b/.buildkite/scripts/steps/storybooks/build_and_upload.js index 9d72f518837e..c1032575ae4a 100644 --- a/.buildkite/scripts/steps/storybooks/build_and_upload.js +++ b/.buildkite/scripts/steps/storybooks/build_and_upload.js @@ -13,6 +13,7 @@ const STORYBOOKS = [ 'dashboard_enhanced', 'data_enhanced', 'embeddable', + 'fleet', 'infra', 'security_solution', 'ui_actions_enhanced', diff --git a/src/dev/storybook/aliases.ts b/src/dev/storybook/aliases.ts index 9395c5fdf883..a61a2618d642 100644 --- a/src/dev/storybook/aliases.ts +++ b/src/dev/storybook/aliases.ts @@ -24,6 +24,7 @@ export const storybookAliases = { expression_reveal_image: 'src/plugins/expression_reveal_image/.storybook', expression_shape: 'src/plugins/expression_shape/.storybook', expression_tagcloud: 'src/plugins/chart_expressions/expression_tagcloud/.storybook', + fleet: 'x-pack/plugins/fleet/storybook', infra: 'x-pack/plugins/infra/.storybook', security_solution: 'x-pack/plugins/security_solution/.storybook', ui_actions_enhanced: 'x-pack/plugins/ui_actions_enhanced/.storybook', diff --git a/x-pack/plugins/fleet/public/applications/integrations/sections/epm/components/assets_facet_group.stories.tsx b/x-pack/plugins/fleet/public/applications/integrations/sections/epm/components/assets_facet_group.stories.tsx new file mode 100644 index 000000000000..d98f2b2408d5 --- /dev/null +++ b/x-pack/plugins/fleet/public/applications/integrations/sections/epm/components/assets_facet_group.stories.tsx @@ -0,0 +1,55 @@ +/* + * 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 { AssetsFacetGroup as Component } from './assets_facet_group'; + +export default { + component: Component, + title: 'Sections/EPM/Assets Facet Group', +}; + +interface Args { + width: number; +} + +const args: Args = { + width: 250, +}; + +export const AssetsFacetGroup = ({ width }: Args) => { + return ( +
+ +
+ ); +}; + +AssetsFacetGroup.args = args; diff --git a/x-pack/plugins/fleet/public/applications/integrations/sections/epm/components/package_card.stories.tsx b/x-pack/plugins/fleet/public/applications/integrations/sections/epm/components/package_card.stories.tsx new file mode 100644 index 000000000000..e8814b8b8c87 --- /dev/null +++ b/x-pack/plugins/fleet/public/applications/integrations/sections/epm/components/package_card.stories.tsx @@ -0,0 +1,79 @@ +/* + * 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 type { SavedObject } from 'src/core/public'; + +import type { Installation } from '../../../../../../common'; + +import type { PackageCardProps } from './package_card'; +import { PackageCard } from './package_card'; + +export default { + title: 'Sections/EPM/Package Card', + description: 'A card representing a package available in Fleet', +}; + +type Args = Omit & { width: number }; + +const args: Args = { + width: 250, + title: 'Title', + description: 'Description', + name: 'beats', + release: 'ga', + id: 'id', + version: '1.0.0', + download: '/', + path: 'path', +}; + +const argTypes = { + release: { + control: { + type: 'radio', + options: ['ga', 'beta', 'experimental'], + }, + }, +}; + +export const NotInstalled = ({ width, ...props }: Args) => ( +
+ +
+); + +export const Installed = ({ width, ...props }: Args) => { + const savedObject: SavedObject = { + id: props.id, + type: props.type || '', + attributes: { + name: props.name, + version: props.version, + install_version: props.version, + es_index_patterns: {}, + installed_kibana: [], + installed_es: [], + install_status: 'installed', + install_source: 'registry', + install_started_at: '2020-01-01T00:00:00.000Z', + }, + references: [], + }; + + return ( +
+ +
+ ); +}; + +NotInstalled.args = args; +NotInstalled.argTypes = argTypes; +Installed.args = args; +Installed.argTypes = argTypes; diff --git a/x-pack/plugins/fleet/public/applications/integrations/sections/epm/components/package_card.tsx b/x-pack/plugins/fleet/public/applications/integrations/sections/epm/components/package_card.tsx index c12e67fdb571..c2d6d0f1e028 100644 --- a/x-pack/plugins/fleet/public/applications/integrations/sections/epm/components/package_card.tsx +++ b/x-pack/plugins/fleet/public/applications/integrations/sections/epm/components/package_card.tsx @@ -15,7 +15,7 @@ import { PackageIcon } from '../../../components'; import { RELEASE_BADGE_LABEL, RELEASE_BADGE_DESCRIPTION } from './release_badge'; -type PackageCardProps = PackageListItem; +export type PackageCardProps = PackageListItem; // adding the `href` causes EuiCard to use a `a` instead of a `button` // `a` tags use `euiLinkColor` which results in blueish Badge text diff --git a/x-pack/plugins/fleet/public/applications/integrations/sections/epm/components/package_list_grid.stories.tsx b/x-pack/plugins/fleet/public/applications/integrations/sections/epm/components/package_list_grid.stories.tsx new file mode 100644 index 000000000000..d84e286b6f56 --- /dev/null +++ b/x-pack/plugins/fleet/public/applications/integrations/sections/epm/components/package_list_grid.stories.tsx @@ -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 React from 'react'; + +import { action } from '@storybook/addon-actions'; + +import type { SavedObject } from 'src/core/public'; + +import type { Installation } from '../../../../../../common'; + +import type { ListProps } from './package_list_grid'; +import { PackageListGrid } from './package_list_grid'; + +export default { + component: PackageListGrid, + title: 'Sections/EPM/Package List Grid', +}; + +type Args = Pick; + +const args: Args = { + title: 'Installed integrations', + isLoading: false, + showMissingIntegrationMessage: false, +}; + +const savedObject: SavedObject = { + id: 'id', + type: 'integration', + attributes: { + name: 'savedObject', + version: '1.2.3', + install_version: '1.2.3', + es_index_patterns: {}, + installed_kibana: [], + installed_es: [], + install_status: 'installed', + install_source: 'registry', + install_started_at: '2020-01-01T00:00:00.000Z', + }, + references: [], +}; + +export const EmptyList = (props: Args) => ( + +); + +export const List = (props: Args) => ( + +); + +EmptyList.args = args; +List.args = args; diff --git a/x-pack/plugins/fleet/public/applications/integrations/sections/epm/components/package_list_grid.tsx b/x-pack/plugins/fleet/public/applications/integrations/sections/epm/components/package_list_grid.tsx index 6bbd479c5c2b..db63c5c7dd83 100644 --- a/x-pack/plugins/fleet/public/applications/integrations/sections/epm/components/package_list_grid.tsx +++ b/x-pack/plugins/fleet/public/applications/integrations/sections/epm/components/package_list_grid.tsx @@ -28,7 +28,7 @@ import { useLocalSearch, searchIdField } from '../../../hooks'; import { PackageCard } from './package_card'; -interface ListProps { +export interface ListProps { isLoading?: boolean; controls?: ReactNode; title: string; diff --git a/x-pack/plugins/fleet/public/applications/integrations/sections/epm/components/requirements.stories.tsx b/x-pack/plugins/fleet/public/applications/integrations/sections/epm/components/requirements.stories.tsx new file mode 100644 index 000000000000..205d739d4869 --- /dev/null +++ b/x-pack/plugins/fleet/public/applications/integrations/sections/epm/components/requirements.stories.tsx @@ -0,0 +1,39 @@ +/* + * 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 { Requirements as Component } from './requirements'; + +export default { + component: Component, + title: 'Sections/EPM/Requirements', +}; + +interface Args { + width: number; +} + +const args: Args = { + width: 250, +}; + +export const Requirements = ({ width }: Args) => { + return ( +
+ +
+ ); +}; + +Requirements.args = args; diff --git a/x-pack/plugins/fleet/storybook/decorator.tsx b/x-pack/plugins/fleet/storybook/decorator.tsx new file mode 100644 index 000000000000..499b01c2bfba --- /dev/null +++ b/x-pack/plugins/fleet/storybook/decorator.tsx @@ -0,0 +1,79 @@ +/* + * 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 { of } from 'rxjs'; +import type { DecoratorFn } from '@storybook/react'; +import { action } from '@storybook/addon-actions'; +import { createMemoryHistory } from 'history'; + +import { I18nProvider } from '@kbn/i18n/react'; + +import { ScopedHistory } from '../../../../src/core/public'; +import { IntegrationsAppContext } from '../public/applications/integrations/app'; +import type { FleetConfigType, FleetStartServices } from '../public/plugin'; + +// TODO: clintandrewhall - this is not ideal, or complete. The root context of Fleet applications +// requires full start contracts of its dependencies. As a result, we have to mock all of those contracts +// with Storybook equivalents. This is a temporary solution, and should be replaced with a more complete +// mock later, (or, ideally, Fleet starts to use a service abstraction). +// +// Expect this to grow as components that are given Stories need access to mocked services. +export const contextDecorator: DecoratorFn = (story: Function) => { + const basepath = '/'; + const memoryHistory = createMemoryHistory({ initialEntries: [basepath] }); + const history = new ScopedHistory(memoryHistory, basepath); + + const startServices = { + application: { + currentAppId$: of('home'), + navigateToUrl: (url: string) => action(`Navigate to: ${url}`), + getUrlForApp: (url: string) => url, + }, + http: { + basePath: { + prepend: () => basepath, + }, + }, + notifications: {}, + history, + uiSettings: { + get$: (key: string) => { + switch (key) { + case 'theme:darkMode': + return of(false); + default: + return of(); + } + }, + }, + i18n: { + Context: I18nProvider, + }, + } as unknown as FleetStartServices; + + const config = { + enabled: true, + agents: { + enabled: true, + elasticsearch: {}, + }, + } as unknown as FleetConfigType; + + const extensions = {}; + + const kibanaVersion = '1.2.3'; + + return ( + + {story()} + + ); +}; diff --git a/x-pack/plugins/fleet/storybook/main.ts b/x-pack/plugins/fleet/storybook/main.ts new file mode 100644 index 000000000000..2cf4124c6178 --- /dev/null +++ b/x-pack/plugins/fleet/storybook/main.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 type { Configuration } from 'webpack'; +import { defaultConfig, WebpackConfig } from '@kbn/storybook'; + +module.exports = { + ...defaultConfig, + addons: ['@storybook/addon-essentials'], + babel: () => ({ + presets: [require.resolve('@kbn/babel-preset/webpack_preset')], + }), + webpackFinal: (config: Configuration) => { + return WebpackConfig({ config }); + }, +}; diff --git a/x-pack/plugins/fleet/storybook/manager.ts b/x-pack/plugins/fleet/storybook/manager.ts new file mode 100644 index 000000000000..471a735ed370 --- /dev/null +++ b/x-pack/plugins/fleet/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: 'Kibana Fleet Storybook', + brandUrl: 'https://github.com/elastic/kibana/tree/master/x-pack/plugins/fleet', + }), + showPanel: true.valueOf, + selectedPanel: PANEL_ID, +}); diff --git a/x-pack/plugins/fleet/storybook/preview.tsx b/x-pack/plugins/fleet/storybook/preview.tsx new file mode 100644 index 000000000000..a50ff2faaff5 --- /dev/null +++ b/x-pack/plugins/fleet/storybook/preview.tsx @@ -0,0 +1,28 @@ +/* + * 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 { addDecorator } from '@storybook/react'; +import { Title, Subtitle, Description, Primary, Stories } from '@storybook/addon-docs/blocks'; + +import { contextDecorator } from './decorator'; + +addDecorator(contextDecorator); + +export const parameters = { + docs: { + page: () => ( + <> + + <Subtitle /> + <Description /> + <Primary /> + <Stories /> + </> + ), + }, +}; diff --git a/x-pack/plugins/fleet/tsconfig.json b/x-pack/plugins/fleet/tsconfig.json index 5002bf289387..a9dd66ce503a 100644 --- a/x-pack/plugins/fleet/tsconfig.json +++ b/x-pack/plugins/fleet/tsconfig.json @@ -14,6 +14,7 @@ "server/**/*.json", "scripts/**/*", "package.json", + "storybook/**/*", "../../../typings/**/*" ], "references": [