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:
Jack Westbrook
2020-11-24 10:38:41 +01:00
committed by GitHub
co-authored by achatterjee-grafana Peter Holmberg
parent ce39e12e00
commit 0fc8426bf1
18 changed files with 3703 additions and 3234 deletions
+2 -1
View File
@@ -6,7 +6,8 @@
{
"files": ["**/*.{test,story}.{ts,tsx}"],
"rules": {
"no-restricted-imports": "off"
"no-restricted-imports": "off",
"react/prop-types": "off"
}
}
]
+136 -1
View File
@@ -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;
},
};
+18 -19
View File
@@ -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;
};
+4
View File
@@ -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.
+12 -11
View File
@@ -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"
}
+2 -3
View File
@@ -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(),
+2
View File
@@ -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 {