mirror of
https://github.com/elastic/kibana.git
synced 2025-04-23 09:19:04 -04:00
[fleet] Introduce Storybook to Fleet (#112611)
Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com>
This commit is contained in:
parent
322c5e26f0
commit
b1d6779d43
13 changed files with 463 additions and 2 deletions
|
@ -13,6 +13,7 @@ const STORYBOOKS = [
|
|||
'dashboard_enhanced',
|
||||
'data_enhanced',
|
||||
'embeddable',
|
||||
'fleet',
|
||||
'infra',
|
||||
'security_solution',
|
||||
'ui_actions_enhanced',
|
||||
|
|
|
@ -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',
|
||||
|
|
|
@ -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 (
|
||||
<div style={{ width }}>
|
||||
<Component
|
||||
assets={{
|
||||
kibana: {
|
||||
dashboard: [],
|
||||
visualization: [],
|
||||
index_pattern: [],
|
||||
search: [],
|
||||
map: [],
|
||||
lens: [],
|
||||
security_rule: [],
|
||||
ml_module: [],
|
||||
},
|
||||
elasticsearch: {
|
||||
component_template: [],
|
||||
data_stream_ilm_policy: [],
|
||||
data_stream: [],
|
||||
ilm_policy: [],
|
||||
index_template: [],
|
||||
ingest_pipeline: [],
|
||||
transform: [],
|
||||
},
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
AssetsFacetGroup.args = args;
|
|
@ -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<PackageCardProps, 'status'> & { 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) => (
|
||||
<div style={{ width }}>
|
||||
<PackageCard {...props} status="not_installed" />
|
||||
</div>
|
||||
);
|
||||
|
||||
export const Installed = ({ width, ...props }: Args) => {
|
||||
const savedObject: SavedObject<Installation> = {
|
||||
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 (
|
||||
<div style={{ width }}>
|
||||
<PackageCard {...props} status="installed" savedObject={savedObject} />
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
NotInstalled.args = args;
|
||||
NotInstalled.argTypes = argTypes;
|
||||
Installed.args = args;
|
||||
Installed.argTypes = argTypes;
|
|
@ -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
|
||||
|
|
|
@ -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<ListProps, 'title' | 'isLoading' | 'showMissingIntegrationMessage'>;
|
||||
|
||||
const args: Args = {
|
||||
title: 'Installed integrations',
|
||||
isLoading: false,
|
||||
showMissingIntegrationMessage: false,
|
||||
};
|
||||
|
||||
const savedObject: SavedObject<Installation> = {
|
||||
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) => (
|
||||
<PackageListGrid
|
||||
list={[]}
|
||||
onSearchChange={action('onSearchChange')}
|
||||
setSelectedCategory={action('setSelectedCategory')}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
|
||||
export const List = (props: Args) => (
|
||||
<PackageListGrid
|
||||
list={[
|
||||
{
|
||||
title: 'Package One',
|
||||
description: 'Not Installed Description',
|
||||
name: 'beats',
|
||||
release: 'ga',
|
||||
id: 'id',
|
||||
version: '1.0.0',
|
||||
download: '/',
|
||||
path: 'path',
|
||||
status: 'not_installed',
|
||||
},
|
||||
{
|
||||
title: 'Package Two',
|
||||
description: 'Not Installed Description',
|
||||
name: 'aws',
|
||||
release: 'beta',
|
||||
id: 'id',
|
||||
version: '1.0.0',
|
||||
download: '/',
|
||||
path: 'path',
|
||||
status: 'not_installed',
|
||||
},
|
||||
{
|
||||
title: 'Package Three',
|
||||
description: 'Not Installed Description',
|
||||
name: 'azure',
|
||||
release: 'experimental',
|
||||
id: 'id',
|
||||
version: '1.0.0',
|
||||
download: '/',
|
||||
path: 'path',
|
||||
status: 'not_installed',
|
||||
},
|
||||
{
|
||||
title: 'Package Four',
|
||||
description: 'Installed Description',
|
||||
name: 'elastic',
|
||||
release: 'ga',
|
||||
id: 'id',
|
||||
version: '1.0.0',
|
||||
download: '/',
|
||||
path: 'path',
|
||||
status: 'installed',
|
||||
savedObject,
|
||||
},
|
||||
{
|
||||
title: 'Package Five',
|
||||
description: 'Installed Description',
|
||||
name: 'unknown',
|
||||
release: 'beta',
|
||||
id: 'id',
|
||||
version: '1.0.0',
|
||||
download: '/',
|
||||
path: 'path',
|
||||
status: 'installed',
|
||||
savedObject,
|
||||
},
|
||||
{
|
||||
title: 'Package Six',
|
||||
description: 'Installed Description',
|
||||
name: 'kibana',
|
||||
release: 'experimental',
|
||||
id: 'id',
|
||||
version: '1.0.0',
|
||||
download: '/',
|
||||
path: 'path',
|
||||
status: 'installed',
|
||||
savedObject,
|
||||
},
|
||||
]}
|
||||
onSearchChange={action('onSearchChange')}
|
||||
setSelectedCategory={action('setSelectedCategory')}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
|
||||
EmptyList.args = args;
|
||||
List.args = args;
|
|
@ -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;
|
||||
|
|
|
@ -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 (
|
||||
<div style={{ width }}>
|
||||
<Component
|
||||
requirements={{
|
||||
kibana: {
|
||||
version: '1.2.3',
|
||||
},
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
Requirements.args = args;
|
79
x-pack/plugins/fleet/storybook/decorator.tsx
Normal file
79
x-pack/plugins/fleet/storybook/decorator.tsx
Normal file
|
@ -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 (
|
||||
<IntegrationsAppContext
|
||||
{...{ kibanaVersion, basepath, config, history, startServices, extensions }}
|
||||
>
|
||||
{story()}
|
||||
</IntegrationsAppContext>
|
||||
);
|
||||
};
|
20
x-pack/plugins/fleet/storybook/main.ts
Normal file
20
x-pack/plugins/fleet/storybook/main.ts
Normal file
|
@ -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 });
|
||||
},
|
||||
};
|
20
x-pack/plugins/fleet/storybook/manager.ts
Normal file
20
x-pack/plugins/fleet/storybook/manager.ts
Normal file
|
@ -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,
|
||||
});
|
28
x-pack/plugins/fleet/storybook/preview.tsx
Normal file
28
x-pack/plugins/fleet/storybook/preview.tsx
Normal file
|
@ -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: () => (
|
||||
<>
|
||||
<Title />
|
||||
<Subtitle />
|
||||
<Description />
|
||||
<Primary />
|
||||
<Stories />
|
||||
</>
|
||||
),
|
||||
},
|
||||
};
|
|
@ -14,6 +14,7 @@
|
|||
"server/**/*.json",
|
||||
"scripts/**/*",
|
||||
"package.json",
|
||||
"storybook/**/*",
|
||||
"../../../typings/**/*"
|
||||
],
|
||||
"references": [
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue