Chore: Bump storybook to v6 (#28926)
* Wip * feat: get storybook and app building locally * docs: comment webpack react alias * build(grafana-ui): put back ts-loader * build: prefer storybook essentials over actions and docs. bump dark-mode * chore(storybook): migrate to latest config * build: prevent test env throwing Invalid hook call errors * chore: lodash resolves to package dependency rather than project * use decorators as variable instead of function * perf(storybook): reduce bundling time by splitting type check and compilation * refactor(storybook): use sortOrder.order param to sort intro story first * build: use yarn workspace command * refactor(storybook): use previous knobs addon registration * migrate button story to controls * build(storybook): silence warnings in console * build: bump storybook related ts packages * style: remove trailing whitespace * refactor(graphng): export interface for storybook * controls migration guide * fix typo * docs(storybook): default docs to use dark theme as per current implementation * revert(grafana-ui): put back react-is namedExport this was changed for react 17 bump but causes rollup to fail during bundling * chore: bump storybook to 6.1, enable fastRefresh, silence eslint prop-types * docs(grafana-ui): move knobs -> controls migration guide to storybook style-guide * chore(storybook): silence terminal warning about order of docs addon * Update contribute/style-guides/storybook.md Co-authored-by: achatterjee-grafana <70489351+achatterjee-grafana@users.noreply.github.com> * Apply documentation suggestions Co-authored-by: achatterjee-grafana <70489351+achatterjee-grafana@users.noreply.github.com> * chore(storybook): bump to 6.1.2 Co-authored-by: Peter Holmberg <peter.hlmbrg@gmail.com> Co-authored-by: achatterjee-grafana <70489351+achatterjee-grafana@users.noreply.github.com>
This commit is contained in:
co-authored by
achatterjee-grafana
Peter Holmberg
parent
ce39e12e00
commit
0fc8426bf1
@@ -6,7 +6,8 @@
|
||||
{
|
||||
"files": ["**/*.{test,story}.{ts,tsx}"],
|
||||
"rules": {
|
||||
"no-restricted-imports": "off"
|
||||
"no-restricted-imports": "off",
|
||||
"react/prop-types": "off"
|
||||
}
|
||||
}
|
||||
]
|
||||
|
||||
@@ -1,3 +1,8 @@
|
||||
const path = require('path');
|
||||
const TerserPlugin = require('terser-webpack-plugin');
|
||||
const OptimizeCSSAssetsPlugin = require('optimize-css-assets-webpack-plugin');
|
||||
const FilterWarningsPlugin = require('webpack-filter-warnings-plugin');
|
||||
|
||||
const stories = ['../src/**/*.story.{js,jsx,ts,tsx,mdx}'];
|
||||
|
||||
if (process.env.NODE_ENV !== 'production') {
|
||||
@@ -7,10 +12,140 @@ if (process.env.NODE_ENV !== 'production') {
|
||||
module.exports = {
|
||||
stories: stories,
|
||||
addons: [
|
||||
'@storybook/addon-docs',
|
||||
'@storybook/addon-controls',
|
||||
'@storybook/addon-knobs',
|
||||
'@storybook/addon-actions',
|
||||
'@storybook/addon-docs',
|
||||
'storybook-dark-mode/register',
|
||||
'@storybook/addon-storysource',
|
||||
],
|
||||
reactOptions: {
|
||||
fastRefresh: true,
|
||||
},
|
||||
typescript: {
|
||||
check: true,
|
||||
reactDocgen: 'react-docgen-typescript',
|
||||
reactDocgenTypescriptOptions: {
|
||||
shouldExtractLiteralValuesFromEnum: true,
|
||||
propFilter: (prop: any) => (prop.parent ? !/node_modules/.test(prop.parent.fileName) : true),
|
||||
},
|
||||
},
|
||||
webpackFinal: async (config: any, { configType }: any) => {
|
||||
const isProductionBuild = configType === 'PRODUCTION';
|
||||
config.module.rules = [
|
||||
...(config.module.rules || []),
|
||||
{
|
||||
test: /\.tsx?$/,
|
||||
use: [
|
||||
{
|
||||
loader: require.resolve('ts-loader'),
|
||||
options: {
|
||||
transpileOnly: true,
|
||||
configFile: path.resolve(__dirname, 'tsconfig.json'),
|
||||
},
|
||||
},
|
||||
{
|
||||
loader: require.resolve('react-docgen-typescript-loader'),
|
||||
options: {
|
||||
tsconfigPath: path.resolve(__dirname, 'tsconfig.json'),
|
||||
// https://github.com/styleguidist/react-docgen-typescript#parseroptions
|
||||
// @ts-ignore
|
||||
propFilter: prop => {
|
||||
if (prop.parent) {
|
||||
return !prop.parent.fileName.includes('node_modules/@types/react/');
|
||||
}
|
||||
|
||||
return true;
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
test: /\.scss$/,
|
||||
use: [
|
||||
{
|
||||
loader: 'style-loader',
|
||||
options: { injectType: 'lazyStyleTag' },
|
||||
},
|
||||
{
|
||||
loader: 'css-loader',
|
||||
options: {
|
||||
importLoaders: 2,
|
||||
},
|
||||
},
|
||||
{
|
||||
loader: 'postcss-loader',
|
||||
options: {
|
||||
sourceMap: false,
|
||||
config: { path: __dirname + '../../../../scripts/webpack/postcss.config.js' },
|
||||
},
|
||||
},
|
||||
{
|
||||
loader: 'sass-loader',
|
||||
options: {
|
||||
sourceMap: false,
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
test: require.resolve('jquery'),
|
||||
use: [
|
||||
{
|
||||
loader: 'expose-loader',
|
||||
query: 'jQuery',
|
||||
},
|
||||
{
|
||||
loader: 'expose-loader',
|
||||
query: '$',
|
||||
},
|
||||
],
|
||||
},
|
||||
];
|
||||
|
||||
config.optimization = {
|
||||
nodeEnv: 'production',
|
||||
moduleIds: 'hashed',
|
||||
runtimeChunk: 'single',
|
||||
splitChunks: {
|
||||
chunks: 'all',
|
||||
minChunks: 1,
|
||||
cacheGroups: {
|
||||
vendors: {
|
||||
test: /[\\/]node_modules[\\/].*[jt]sx?$/,
|
||||
chunks: 'initial',
|
||||
priority: -10,
|
||||
reuseExistingChunk: true,
|
||||
enforce: true,
|
||||
},
|
||||
default: {
|
||||
priority: -20,
|
||||
chunks: 'all',
|
||||
test: /.*[jt]sx?$/,
|
||||
reuseExistingChunk: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
minimize: isProductionBuild,
|
||||
minimizer: isProductionBuild
|
||||
? [
|
||||
new TerserPlugin({ cache: false, parallel: false, sourceMap: false, exclude: /monaco|bizcharts/ }),
|
||||
new OptimizeCSSAssetsPlugin({}),
|
||||
]
|
||||
: [],
|
||||
};
|
||||
|
||||
config.resolve.alias['@grafana/ui'] = path.resolve(__dirname, '..');
|
||||
|
||||
// Silence "export not found" webpack warnings with transpileOnly
|
||||
// https://github.com/TypeStrong/ts-loader#transpileonly
|
||||
config.plugins.push(
|
||||
new FilterWarningsPlugin({
|
||||
exclude: /export .* was not found in/,
|
||||
})
|
||||
);
|
||||
|
||||
return config;
|
||||
},
|
||||
};
|
||||
|
||||
@@ -15,8 +15,8 @@ import lightTheme from '../../../public/sass/grafana.light.scss';
|
||||
// @ts-ignore
|
||||
import darkTheme from '../../../public/sass/grafana.dark.scss';
|
||||
import { GrafanaLight, GrafanaDark } from './storybookTheme';
|
||||
import { configure, addDecorator, addParameters } from '@storybook/react';
|
||||
import { withKnobs } from '@storybook/addon-knobs';
|
||||
import { configure } from '@storybook/react';
|
||||
import addons from '@storybook/addons';
|
||||
|
||||
const handleThemeChange = (theme: any) => {
|
||||
if (theme !== 'light') {
|
||||
@@ -27,37 +27,36 @@ const handleThemeChange = (theme: any) => {
|
||||
lightTheme.use();
|
||||
}
|
||||
};
|
||||
addDecorator(withTheme(handleThemeChange));
|
||||
addDecorator(withKnobs);
|
||||
addDecorator(withPaddedStory);
|
||||
|
||||
addParameters({
|
||||
addons.setConfig({
|
||||
showRoots: false,
|
||||
theme: GrafanaDark,
|
||||
});
|
||||
|
||||
export const decorators = [withTheme(handleThemeChange), withPaddedStory];
|
||||
|
||||
export const parameters = {
|
||||
info: {},
|
||||
docs: {
|
||||
theme: GrafanaDark,
|
||||
},
|
||||
darkMode: {
|
||||
dark: GrafanaDark,
|
||||
light: GrafanaLight,
|
||||
},
|
||||
options: {
|
||||
theme: GrafanaDark,
|
||||
showPanel: true,
|
||||
showRoots: true,
|
||||
panelPosition: 'right',
|
||||
showNav: true,
|
||||
isFullscreen: false,
|
||||
isToolshown: true,
|
||||
storySort: (a: any, b: any) => {
|
||||
if (a[1].kind.split('/')[0] === 'Docs Overview') {
|
||||
return -1;
|
||||
} else if (b[1].kind.split('/')[0] === 'Docs Overview') {
|
||||
return 1;
|
||||
}
|
||||
return a[1].id.localeCompare(b[1].id);
|
||||
storySort: {
|
||||
method: 'alphabetical',
|
||||
// Order Docs Overview and Docs Overview/Intro story first
|
||||
order: ['Docs Overview', ['Intro']],
|
||||
},
|
||||
},
|
||||
knobs: {
|
||||
escapeHTML: false,
|
||||
},
|
||||
});
|
||||
|
||||
// @ts-ignore
|
||||
configure(require.context('../src', true, /\.story\.(js|jsx|ts|tsx|mdx)$/), module);
|
||||
};
|
||||
|
||||
@@ -1,121 +0,0 @@
|
||||
const path = require('path');
|
||||
const TerserPlugin = require('terser-webpack-plugin');
|
||||
const OptimizeCSSAssetsPlugin = require('optimize-css-assets-webpack-plugin');
|
||||
module.exports = ({ config, mode }) => {
|
||||
const isProductionBuild = mode === 'PRODUCTION';
|
||||
config.module.rules = [
|
||||
...(config.module.rules || []),
|
||||
{
|
||||
test: /\.tsx?$/,
|
||||
use: [
|
||||
{
|
||||
loader: require.resolve('ts-loader'),
|
||||
options: {
|
||||
// transpileOnly: true,
|
||||
configFile: path.resolve(__dirname, 'tsconfig.json'),
|
||||
},
|
||||
},
|
||||
{
|
||||
loader: require.resolve('react-docgen-typescript-loader'),
|
||||
options: {
|
||||
tsconfigPath: path.resolve(__dirname, 'tsconfig.json'),
|
||||
// https://github.com/styleguidist/react-docgen-typescript#parseroptions
|
||||
// @ts-ignore
|
||||
propFilter: prop => {
|
||||
if (prop.parent) {
|
||||
return !prop.parent.fileName.includes('node_modules/@types/react/');
|
||||
}
|
||||
|
||||
return true;
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
];
|
||||
|
||||
config.module.rules.push({
|
||||
test: /\.scss$/,
|
||||
use: [
|
||||
{
|
||||
loader: 'style-loader',
|
||||
options: { injectType: 'lazyStyleTag' },
|
||||
},
|
||||
{
|
||||
loader: 'css-loader',
|
||||
options: {
|
||||
importLoaders: 2,
|
||||
},
|
||||
},
|
||||
{
|
||||
loader: 'postcss-loader',
|
||||
options: {
|
||||
sourceMap: false,
|
||||
config: { path: __dirname + '../../../../scripts/webpack/postcss.config.js' },
|
||||
},
|
||||
},
|
||||
{
|
||||
loader: 'sass-loader',
|
||||
options: {
|
||||
sourceMap: false,
|
||||
},
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
config.module.rules.push({
|
||||
test: require.resolve('jquery'),
|
||||
use: [
|
||||
{
|
||||
loader: 'expose-loader',
|
||||
query: 'jQuery',
|
||||
},
|
||||
{
|
||||
loader: 'expose-loader',
|
||||
query: '$',
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
config.optimization = {
|
||||
nodeEnv: 'production',
|
||||
moduleIds: 'hashed',
|
||||
runtimeChunk: 'single',
|
||||
splitChunks: {
|
||||
chunks: 'all',
|
||||
minChunks: 1,
|
||||
cacheGroups: {
|
||||
vendors: {
|
||||
test: /[\\/]node_modules[\\/].*[jt]sx?$/,
|
||||
chunks: 'initial',
|
||||
priority: -10,
|
||||
reuseExistingChunk: true,
|
||||
enforce: true,
|
||||
},
|
||||
default: {
|
||||
priority: -20,
|
||||
chunks: 'all',
|
||||
test: /.*[jt]sx?$/,
|
||||
reuseExistingChunk: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
minimize: isProductionBuild,
|
||||
minimizer: isProductionBuild
|
||||
? [
|
||||
new TerserPlugin({ cache: false, parallel: false, sourceMap: false, exclude: /monaco|bizcharts/ }),
|
||||
new OptimizeCSSAssetsPlugin({}),
|
||||
]
|
||||
: [],
|
||||
};
|
||||
|
||||
config.resolve.extensions.push('.ts', '.tsx', '.mdx');
|
||||
config.resolve.alias = config.resolve.alias || {};
|
||||
config.resolve.alias['@grafana/ui'] = path.resolve(__dirname, '..');
|
||||
|
||||
config.stats = {
|
||||
warningsFilter: /export .* was not found in/,
|
||||
};
|
||||
|
||||
return config;
|
||||
};
|
||||
@@ -17,3 +17,7 @@ See [package source](https://github.com/grafana/grafana/tree/master/packages/gra
|
||||
## Development
|
||||
|
||||
For development purposes we suggest using `yarn link` that will create symlink to @grafana/ui lib. To do so navigate to `packages/grafana-ui` and run `yarn link`. Then, navigate to your project and run `yarn link @grafana/ui` to use the linked version of the lib. To unlink follow the same procedure, but use `yarn unlink` instead.
|
||||
|
||||
### Storybook 6.x migration
|
||||
|
||||
We've upgraded Storybook to version 6 and with that we will convert to using [controls](https://storybook.js.org/docs/react/essentials/controls) instead of knobs for manipulating components. Controls will not require as much coding as knobs do. Please refer to the [storybook style-guide](https://github.com/grafana/grafana/blob/master/contribute/style-guides/storybook.md#contrls) for further information.
|
||||
|
||||
@@ -77,13 +77,12 @@
|
||||
"@rollup/plugin-commonjs": "11.0.2",
|
||||
"@rollup/plugin-image": "2.0.4",
|
||||
"@rollup/plugin-node-resolve": "7.1.1",
|
||||
"@storybook/addon-actions": "5.3.21",
|
||||
"@storybook/addon-docs": "5.3.21",
|
||||
"@storybook/addon-info": "5.3.21",
|
||||
"@storybook/addon-knobs": "5.3.21",
|
||||
"@storybook/addon-storysource": "5.3.21",
|
||||
"@storybook/react": "5.3.21",
|
||||
"@storybook/theming": "5.3.21",
|
||||
"@storybook/addon-essentials": "6.1.2",
|
||||
"@storybook/addon-controls": "6.1.2",
|
||||
"@storybook/addon-knobs": "6.1.2",
|
||||
"@storybook/addon-storysource": "6.1.2",
|
||||
"@storybook/react": "6.1.2",
|
||||
"@storybook/theming": "6.1.2",
|
||||
"@types/classnames": "2.2.7",
|
||||
"@types/common-tags": "^1.8.0",
|
||||
"@types/d3": "5.7.2",
|
||||
@@ -101,16 +100,18 @@
|
||||
"@types/tinycolor2": "1.4.1",
|
||||
"common-tags": "^1.8.0",
|
||||
"pretty-format": "25.1.0",
|
||||
"react-docgen-typescript-loader": "3.7.1",
|
||||
"react-docgen-typescript-loader": "3.7.2",
|
||||
"react-test-renderer": "16.13.1",
|
||||
"react-is": "16.8.0",
|
||||
"rollup": "2.0.6",
|
||||
"rollup-plugin-sourcemaps": "0.5.0",
|
||||
"rollup-plugin-terser": "5.3.0",
|
||||
"rollup-plugin-typescript2": "0.26.0",
|
||||
"rollup-plugin-visualizer": "3.3.1",
|
||||
"storybook-dark-mode": "0.6.1",
|
||||
"ts-loader": "6.2.1",
|
||||
"typescript": "4.0.2"
|
||||
"storybook-dark-mode": "1.0.3",
|
||||
"ts-loader": "8.0.11",
|
||||
"typescript": "4.0.2",
|
||||
"webpack-filter-warnings-plugin": "1.2.1"
|
||||
},
|
||||
"types": "src/index.ts"
|
||||
}
|
||||
|
||||
@@ -43,7 +43,7 @@ const buildCjsPackage = ({ env }) => {
|
||||
// When 'rollup-plugin-commonjs' fails to properly convert the CommonJS modules to ES6 one has to manually name the exports
|
||||
// https://github.com/rollup/rollup-plugin-commonjs#custom-named-exports
|
||||
namedExports: {
|
||||
'../../node_modules/lodash/lodash.js': [
|
||||
'node_modules/lodash/lodash.js': [
|
||||
'flatten',
|
||||
'find',
|
||||
'upperFirst',
|
||||
@@ -82,8 +82,7 @@ const buildCjsPackage = ({ env }) => {
|
||||
'useAbsoluteLayout',
|
||||
'useFilters',
|
||||
],
|
||||
'../../node_modules/rc-tooltip/node_modules/react-is/index.js': ['isMemo'],
|
||||
'../../node_modules/rc-motion/node_modules/react-is/index.js': ['isMemo'],
|
||||
'../../node_modules/react-is/index.js': ['isMemo'],
|
||||
},
|
||||
}),
|
||||
resolve(),
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import { Meta } from '@storybook/addon-docs/blocks';
|
||||
|
||||
<Meta title="Docs Overview/Intro" parameters={{ options: { isToolshown: false }, id: 1 }} />
|
||||
|
||||
# Grafana design system
|
||||
|
||||
@@ -1,15 +1,21 @@
|
||||
import React from 'react';
|
||||
import { select, text, boolean } from '@storybook/addon-knobs';
|
||||
import { Button, ButtonVariant } from '@grafana/ui';
|
||||
import { Story } from '@storybook/react';
|
||||
import { Button, ButtonProps } from './Button';
|
||||
import { withCenteredStory, withHorizontallyCenteredStory } from '../../utils/storybook/withCenteredStory';
|
||||
import { getIconKnob } from '../../utils/storybook/knobs';
|
||||
import { iconOptions } from '../../utils/storybook/knobs';
|
||||
import mdx from './Button.mdx';
|
||||
import { ComponentSize } from '../../types/size';
|
||||
|
||||
export default {
|
||||
title: 'Buttons/Button',
|
||||
component: Button,
|
||||
decorators: [withCenteredStory, withHorizontallyCenteredStory],
|
||||
argTypes: {
|
||||
variant: { control: { type: 'select', options: ['primary', 'secondary', 'destructive', 'link'] } },
|
||||
size: { control: { type: 'select', options: ['sm', 'md', 'lg'] } },
|
||||
icon: { control: { type: 'select', options: iconOptions } },
|
||||
css: { control: { disable: true } },
|
||||
className: { control: { disable: true } },
|
||||
},
|
||||
parameters: {
|
||||
docs: {
|
||||
page: mdx,
|
||||
@@ -17,19 +23,18 @@ export default {
|
||||
},
|
||||
};
|
||||
|
||||
const variants = ['primary', 'secondary', 'destructive', 'link'];
|
||||
|
||||
const sizes = ['sm', 'md', 'lg'];
|
||||
|
||||
export const simple = () => {
|
||||
const variant = select('Variant', variants, 'primary');
|
||||
const size = select('Size', sizes, 'md');
|
||||
const buttonText = text('Text', 'Button');
|
||||
const disabled = boolean('Disabled', false);
|
||||
const icon = getIconKnob();
|
||||
export const Simple: Story<ButtonProps> = ({ disabled, icon, children, size, variant }) => {
|
||||
return (
|
||||
<Button variant={variant as ButtonVariant} size={size as ComponentSize} icon={icon} disabled={disabled}>
|
||||
{buttonText}
|
||||
<Button variant={variant} size={size} icon={icon} disabled={disabled}>
|
||||
{children}
|
||||
</Button>
|
||||
);
|
||||
};
|
||||
|
||||
Simple.args = {
|
||||
variant: 'primary',
|
||||
size: 'md',
|
||||
disabled: false,
|
||||
children: 'Button',
|
||||
icon: undefined,
|
||||
};
|
||||
|
||||
@@ -8,7 +8,7 @@ import { LegendPlacement, LegendDisplayMode } from '../Legend/Legend';
|
||||
import { GraphSeriesXY, FieldType, ArrayVector, dateTime, FieldColorModeId } from '@grafana/data';
|
||||
|
||||
export default {
|
||||
title: 'Visualizations/Graph',
|
||||
title: 'Visualizations/Graph/GraphWithLegend',
|
||||
component: GraphWithLegend,
|
||||
decorator: [withCenteredStory],
|
||||
};
|
||||
|
||||
@@ -22,7 +22,7 @@ import { useRevision } from '../uPlot/hooks';
|
||||
|
||||
const defaultFormatter = (v: any) => (v == null ? '-' : v.toFixed(1));
|
||||
|
||||
interface GraphNGProps extends Omit<PlotProps, 'data' | 'config'> {
|
||||
export interface GraphNGProps extends Omit<PlotProps, 'data' | 'config'> {
|
||||
data: DataFrame[];
|
||||
legend?: LegendOptions;
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@ import { InfoTooltip } from './InfoTooltip';
|
||||
import { Tooltip } from '../Chart/Tooltip';
|
||||
|
||||
export default {
|
||||
title: 'Overlays/Tooltip',
|
||||
title: 'Overlays/TooltipInternal',
|
||||
component: Tooltip,
|
||||
decorators: [withCenteredStory],
|
||||
};
|
||||
|
||||
@@ -3,7 +3,7 @@ import { getAvailableIcons } from '../../types';
|
||||
|
||||
const VISUAL_GROUP = 'Visual options';
|
||||
|
||||
const iconOptions = {
|
||||
export const iconOptions = {
|
||||
None: undefined,
|
||||
...getAvailableIcons().reduce<Record<string, string>>((prev, c) => {
|
||||
return {
|
||||
|
||||
Reference in New Issue
Block a user