feat: adding Storybook to Superset (#10383)

* Storybook added!

* starting to configure junk....

* Storybook works!!!

* Now with theme!

* apache boilerplate

* more apache comments

* lots o' knobs for the Button.... taking stock of the codebase

* more classes, but killing the knob for now.

* nixing unused module

* linting

* fresh package-lock

* now with tooltip!

* adding path and zlip because the linter told me to

* upgrading storybook packages from devdeps

* linting

* removing cruft

* killing an annoying (and old?) lint issue

* lint fix, take 2.

* removing zlib/path

* package lock reset from master

* re-adding new packages for this here PR

* nixing console log, simplifying

* nixing comment TODOs (done enough!)

* basic docs.
This commit is contained in:
Evan Rusackas 2020-07-22 10:21:25 -07:00 committed by GitHub
parent 961108625e
commit ca71d4d6ee
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 6663 additions and 239 deletions

View File

@ -703,6 +703,17 @@ npm run cypress open
See [`superset-frontend/cypress_build.sh`](https://github.com/apache/incubator-superset/blob/master/superset-frontend/cypress_build.sh).
### Storybook
Superset includes a [Storybook](https://storybook.js.org/) to preview the layout/styling of various Superset components, and variations thereof. To open and view the Storybook:
```bash
cd superset-frontend
npm run storybool
```
When contributing new React components to Superset, please try to add a Story alongside the component's `jsx/tsx` file.
## Translating
We use [Babel](http://babel.pocoo.org/en/latest/) to translate Superset.

View File

@ -0,0 +1,41 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
const path = require('path');
// Suerset's webpack.config.js
const customConfig = require('../webpack.config.js');
module.exports = {
stories: ['../src/components/**/*.stories.jsx'],
addons: [
'@storybook/addon-actions',
'@storybook/addon-links',
'@storybook/preset-typescript',
'storybook-addon-jsx',
'@storybook/addon-knobs/register',
],
webpackFinal: config => ({
...config,
module: {
...config.module,
rules: customConfig.module.rules,
},
plugins: [...config.plugins, ...customConfig.plugins],
}),
};

View File

@ -0,0 +1,32 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
import React from 'react';
import { addDecorator } from '@storybook/react';
import { jsxDecorator } from 'storybook-addon-jsx';
import { supersetTheme, ThemeProvider } from '@superset-ui/style';
import '../src/theme.ts';
const themeDecorator = storyFn => (
<ThemeProvider theme={supersetTheme}>{storyFn()}</ThemeProvider>
);
addDecorator(jsxDecorator);
addDecorator(themeDecorator);

File diff suppressed because it is too large Load Diff

View File

@ -23,7 +23,9 @@
"lint-fix": "eslint --fix --ignore-path=.eslintignore --ext .js,.jsx,.ts,tsx . && npm run clean-css && npm run type",
"clean-css": "prettier --write '{src,stylesheets}/**/*.{css,less,sass,scss}'",
"check-translation": "prettier --check ../superset/translations/**/LC_MESSAGES/*.json",
"clean-translation": "prettier --write ../superset/translations/**/LC_MESSAGES/*.json"
"clean-translation": "prettier --write ../superset/translations/**/LC_MESSAGES/*.json",
"storybook": "NODE_ENV=development BABEL_ENV=development start-storybook -p 6006",
"build-storybook": "build-storybook"
},
"repository": {
"type": "git",
@ -59,6 +61,8 @@
"@babel/runtime-corejs3": "^7.8.4",
"@data-ui/sparkline": "^0.0.54",
"@emotion/core": "^10.0.28",
"@storybook/addon-actions": "^5.3.19",
"@storybook/addon-knobs": "^5.3.19",
"@superset-ui/chart": "^0.14.9",
"@superset-ui/chart-composition": "^0.14.9",
"@superset-ui/chart-controls": "^0.14.9",
@ -204,6 +208,10 @@
"@emotion/babel-preset-css-prop": "^10.0.27",
"@hot-loader/react-dom": "^16.13.0",
"@istanbuljs/nyc-config-typescript": "^1.0.1",
"@storybook/addon-links": "^5.3.19",
"@storybook/addons": "^5.3.19",
"@storybook/preset-typescript": "^3.0.0",
"@storybook/react": "^5.3.19",
"@svgr/webpack": "^5.4.0",
"@types/classnames": "^2.2.9",
"@types/dom-to-image": "^2.6.0",
@ -262,6 +270,7 @@
"sinon": "^9.0.2",
"source-map-support": "^0.5.16",
"speed-measure-webpack-plugin": "^1.2.3",
"storybook-addon-jsx": "^7.3.3",
"style-loader": "^1.0.0",
"terser-webpack-plugin": "^1.1.0",
"thread-loader": "^1.2.0",

View File

@ -21,6 +21,7 @@ import { shallow } from 'enzyme';
import ResizableHandle from 'src/dashboard/components/resizable/ResizableHandle';
/* eslint-disable react/jsx-pascal-case */
describe('ResizableHandle', () => {
it('should render a right resize handle', () => {
const wrapper = shallow(<ResizableHandle.right />);
@ -41,3 +42,4 @@ describe('ResizableHandle', () => {
).toHaveLength(1);
});
});
/* eslint-enable react/jsx-pascal-case */

View File

@ -0,0 +1,140 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
import React from 'react';
import { action } from '@storybook/addon-actions';
import { withKnobs, boolean, select, text } from '@storybook/addon-knobs';
import Button from './index';
export default {
title: 'Button',
component: Button,
decorators: [withKnobs],
};
const bsStyleKnob = {
label: 'Types',
options: {
Primary: 'primary',
Secondary: 'secondary',
Danger: 'danger',
Warning: 'warning',
Success: 'success',
Link: 'link',
Default: 'default',
None: null,
},
defaultValue: null,
// groupId: 'ButtonType',
};
const bsSizeKnob = {
label: 'Sizes',
options: {
XS: 'xsmall',
S: 'small',
M: 'medium',
L: 'large',
None: null,
},
defaultValue: null,
};
// TODO remove the use of these in the codebase where they're not necessary
// const classKnob = {
// label: 'Known Classes',
// options: {
// Refresh: 'refresh-btn',
// Primary: 'btn-primary',
// Reset: 'reset',
// Fetch: 'fetch',
// Query: 'query',
// saveBtn: 'save-btn',
// MR3: 'm-r-3',
// cancelQuery: 'cancelQuery',
// toggleSave: 'toggleSave',
// toggleSchedule: 'toggleSchedule',
// autocomplete: 'autocomplete',
// OK: 'ok',
// None: null,
// },
// defaultValue: null,
// };
const typeKnob = {
label: 'Type',
options: {
Submit: 'submit',
Button: 'button',
None: null,
},
defaultValue: null,
};
const targetKnob = {
label: 'Target',
options: {
Blank: '_blank',
None: null,
},
defaultValue: null,
};
const hrefKnob = {
label: 'HREF',
options: {
Superset: 'http://https://superset.incubator.apache.org/',
None: null,
},
defaultValue: null,
};
export const SupersetButton = () => (
<Button
disabled={boolean('Disabled', false)}
bsStyle={select(
bsStyleKnob.label,
bsStyleKnob.options,
bsStyleKnob.defaultValue,
bsStyleKnob.groupId,
)}
bsSize={select(
bsSizeKnob.label,
bsSizeKnob.options,
bsSizeKnob.defaultValue,
bsSizeKnob.groupId,
)}
onClick={action('clicked')}
type={select(
typeKnob.label,
typeKnob.options,
typeKnob.defaultValue,
typeKnob.groupId,
)}
target={select(
targetKnob.label,
targetKnob.options,
targetKnob.defaultValue,
targetKnob.groupId,
)}
href={select(
hrefKnob.label,
hrefKnob.options,
hrefKnob.defaultValue,
hrefKnob.groupId,
)}
tooltip={boolean('Tooltip', false) === true ? 'This is a tooltip!' : null}
>
{text('Label', 'Button!')}
</Button>
);

View File

@ -258,7 +258,11 @@ const config = {
test: /\.jsx?$/,
// include source code for plugins, but exclude node_modules within them
exclude: [/superset-ui.*\/node_modules\//],
include: [new RegExp(`${APP_DIR}/src`), /superset-ui.*\/src/],
include: [
new RegExp(`${APP_DIR}/src`),
/superset-ui.*\/src/,
new RegExp(`${APP_DIR}/.storybook`),
],
use: [babelLoader],
},
{