Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Story Hierarchy improved UI #1356

Merged
merged 21 commits into from
Jun 29, 2017
Merged
Show file tree
Hide file tree
Changes from 17 commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
a7a3900
Add left panel hierarchy support
Jun 21, 2017
ad32ffa
Fix a few related codebeat issues
Jun 21, 2017
6960d91
Add more tests for stories.js
Jun 21, 2017
3dbdb9e
Better UI for the hierarchy view + bugs fixes
Jun 22, 2017
6bfed5d
Merge remote-tracking branch 'origin/master' into left-panel-hierarchy
Jun 22, 2017
f27825d
Add shortcut to toggle hierarchy
Jun 23, 2017
9b00eb3
Extract hierarchy creation to the mapper
igor-dv Jun 23, 2017
06a4c54
Remove shortcuts for the hierarchy toggling + change leftPanelHierarc…
igor-dv Jun 23, 2017
c16cc2d
Rename resolveStoryHierarchyNamespace to resolveStoryHierarchy
igor-dv Jun 23, 2017
3fde529
Fix tests + Add tests for hierarchy
igor-dv Jun 23, 2017
17fb4f5
Fix the cases when the separator is not a "."
igor-dv Jun 24, 2017
87adce4
Add assertions to left_panel.test.js
igor-dv Jun 24, 2017
bbf6360
Fix warnings in stories.test.js
igor-dv Jun 25, 2017
1c33fda
Fix tests + Add tests
igor-dv Jun 25, 2017
df26718
Remove require.resolve from libs/ui webpack.config.js
igor-dv Jun 25, 2017
21d7173
Remove package-lock.json files
igor-dv Jun 25, 2017
f57a602
Merge pull request #1329 from igor-dv/left-panel-hierarchy
shilman Jun 25, 2017
dbb04c1
Repalce resolveStoryHierarchy func with hierarchySeparator
igor-dv Jun 26, 2017
279e198
Change the order of the atomic namespace
igor-dv Jun 29, 2017
43ca59b
Merge remote-tracking branch 'origin/release/3.2' into 151-story-hier…
igor-dv Jun 29, 2017
8262b7b
Revert code that was injected by aliens
igor-dv Jun 29, 2017
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -15,4 +15,3 @@ yarn.lock
/**/LICENSE
docs/public
packs/*.tgz
package-lock.json
4 changes: 1 addition & 3 deletions addons/actions/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,7 @@ npm i -D @storybook/addon-actions

Then, add following content to `.storybook/addons.js`

```
import '@storybook/addon-actions/register';
```
import '@storybook/addon-actions/register';

Import the `action` function and use it to create actions handlers. When creating action handlers, provide a **name** to make it easier to identify.

Expand Down
18 changes: 0 additions & 18 deletions addons/info/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -55,24 +55,6 @@ storiesOf('Component')

> Have a look at [this example](example/story.js) stories to learn more about the `addWithInfo` API.


To customize your defaults:

```js
// config.js
import infoAddon, { setDefaults } from '@storybook/addon-info';

// addon-info
setDefaults({
inline: true,
maxPropsIntoLine: 1,
maxPropObjectKeys: 10,
maxPropArrayLength: 10,
maxPropStringLength: 100,
});
setAddon(infoAddon);
```

## The FAQ

**Components lose their names on static build**
Expand Down
19 changes: 5 additions & 14 deletions addons/info/src/components/Story.js
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,11 @@ export default class Story extends React.Component {
_renderInline() {
return (
<div>
{this._renderInlineHeader()}
<div style={this.state.stylesheet.infoPage}>
<div style={this.state.stylesheet.infoBody}>
{this._getInfoHeader()}
</div>
</div>
<div>
{this._renderStory()}
</div>
Expand All @@ -141,19 +145,6 @@ export default class Story extends React.Component {
);
}

_renderInlineHeader() {
const infoHeader = this._getInfoHeader();

return (
infoHeader &&
<div style={this.state.stylesheet.infoPage}>
<div style={this.state.stylesheet.infoBody}>
{infoHeader}
</div>
</div>
);
}

_renderOverlay() {
const linkStyle = {
...stylesheet.link.base,
Expand Down
8 changes: 5 additions & 3 deletions app/react-native/src/server/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,14 @@ export default class Server {
this.expressApp.use(storybook(options));
this.httpServer.on('request', this.expressApp);
this.wsServer = new ws.Server({ server: this.httpServer });
this.wsServer.on('connection', (s, req) => this.handleWS(s, req));
this.wsServer.on('connection', s => this.handleWS(s));
}

handleWS(socket, req) {
handleWS(socket) {
if (this.options.manualId) {
const params = req.url ? querystring.parse(req.url.substr(1)) : {};
const params = socket.upgradeReq && socket.upgradeReq.url
? querystring.parse(socket.upgradeReq.url.substr(1))
: {};

if (params.pairedId) {
socket.pairedId = params.pairedId; // eslint-disable-line
Expand Down
4 changes: 2 additions & 2 deletions docs/pages/basics/faq/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,5 +17,5 @@ npm test -- --coverage --collectCoverageFrom='["src/**/*.{js,jsx}","!src/**/stor

Next automatically defines `React` for all of your files via a babel plugin. You must define `React` for JSX to work. You can solve this either by:

1. Adding `import React from 'react'` to your component files.
1. Adding a `.babelrc` that includes [`babel-plugin-react-require`](https://www.npmjs.com/package/babel-plugin-react-require)
1. Adding `import React from 'react'` to your component files.
2. Adding a `.babelrc` that includes [`babel-plugin-react-require`](https://www.npmjs.com/package/babel-plugin-react-require)
3 changes: 2 additions & 1 deletion examples/cra-kitchen-sink/.storybook/config.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,8 @@ setOptions({
showSearchBox: false,
downPanelInRight: true,
sortStoriesByKind: false,
})
resolveStoryHierarchy: (storyName) => storyName.split('.'),
});

setAddon(infoAddon);

Expand Down
40 changes: 40 additions & 0 deletions examples/cra-kitchen-sink/src/stories/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -153,3 +153,43 @@ storiesOf('WithEvents', module)
</WithEvents>
)
.add('Logger', () => <Logger emiter={emiter} />);

storiesOf('component.base.Link')
.addDecorator(withKnobs)
.add('first', () => <a>{text('firstLink', 'first link')}</a>)
.add('second', () => <a>{text('secondLink', 'second link')}</a>);

storiesOf('component.base.Span')
.add('first', () => <span>first span</span>)
.add('second', () => <span>second span</span>);

storiesOf('component.common.Div')
.add('first', () => <div>first div</div>)
.add('second', () => <div>second div</div>);

storiesOf('component.common.Table')
.add('first', () => <table><tr><td>first table</td></tr></table>)
.add('second', () => <table><tr><td>first table</td></tr></table>);

storiesOf('component.Button')
.add('first', () => <button>first button</button>)
.add('second', () => <button>first second</button>);

// Atomic

storiesOf('Atoms.Molecules.Cells.simple', module)
.addDecorator(withKnobs)
.add('with text', () => <Button>{text('buttonText', 'Hello Button')}</Button>)
.add('with some emoji', () => <Button>😀 😎 👍 💯</Button>);

storiesOf('Atoms.Molecules.Cells.more', module)
.add('with text2', () => <Button>Hello Button</Button>)
.add('with some emoji2', () => <Button>😀 😎 👍 💯</Button>);

storiesOf('Atoms.Molecules', module)
.add('with text', () => <Button>Hello Button</Button>)
.add('with some emoji', () => <Button>😀 😎 👍 💯</Button>);

storiesOf('Atoms.Molecules.Cells', module)
.add('with text2', () => <Button>Hello Button</Button>)
.add('with some emoji2', () => <Button>😀 😎 👍 💯</Button>);
3 changes: 1 addition & 2 deletions lib/cli/generators/REACT_NATIVE/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,7 @@ module.exports = latestVersion('@storybook/react-native').then(version => {
packageJson.devDependencies['@storybook/react-native'] = `^${version}`;

if (!packageJson.dependencies['react-dom'] && !packageJson.devDependencies['react-dom']) {
const reactVersion = packageJson.dependencies.react;
packageJson.devDependencies['react-dom'] = reactVersion;
packageJson.devDependencies['react-dom'] = '^15.5.4';
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

hmm?

}

packageJson.scripts = packageJson.scripts || {};
Expand Down
3 changes: 1 addition & 2 deletions lib/cli/generators/REACT_NATIVE_SCRIPTS/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,7 @@ module.exports = latestVersion('@storybook/react-native').then(version => {
packageJson.devDependencies['@storybook/react-native'] = `^${version}`;

if (!packageJson.dependencies['react-dom'] && !packageJson.devDependencies['react-dom']) {
const reactVersion = packageJson.dependencies.react;
packageJson.devDependencies['react-dom'] = reactVersion;
packageJson.devDependencies['react-dom'] = '^15.5.4';
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

hmm?

Copy link
Member

@igor-dv igor-dv Jun 29, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

idk what is this ¯\(ツ)/¯ ? Maybe it was somehow merged from the previous PR ?

}

packageJson.scripts = packageJson.scripts || {};
Expand Down
57 changes: 47 additions & 10 deletions lib/ui/example/client/provider.js
Original file line number Diff line number Diff line change
Expand Up @@ -78,25 +78,62 @@ export default class ReactProvider extends Provider {
this.api = api;
this.api.setOptions({
name: 'REACT-STORYBOOK',
sortStoriesByKind: true,
resolveStoryHierarchy: storyName => storyName.split('/')
});

// set stories
this.api.setStories([
this.api.setStories(this.createStories());

// listen to the story change and update the preview.
this.api.onStory((kind, story) => {
this.globalState.emit('change', kind, story);
});
}

createStories() {
return [
{
kind: 'Component 1',
kind: 'some/name/Component 1',
stories: ['State 1', 'State 2'],
},

{
kind: 'Component 2',
kind: 'some/name/Component 2',
stories: ['State a', 'State b'],
},
]);

// listen to the story change and update the preview.
this.api.onStory((kind, story) => {
this.globalState.emit('change', kind, story);
});
{
kind: 'some/name2/Component 3',
stories: ['State a', 'State b'],
},
{
kind: 'some/name2',
stories: ['State a', 'State b'],
},
{
kind: 'some/name2/Component 4',
stories: ['State a', 'State b'],
},
{
kind: 'another/name3/Component 5',
stories: ['State a', 'State b'],
},
{
kind: 'another/name3/Component 6',
stories: ['State a', 'State b'],
},
{
kind: 'Bla 1',
stories: ['State 1', 'State 2'],
},
{
kind: 'Bla 2',
stories: ['State 1', 'State 2'],
},
{
kind: 'anotherComponent in the middle',
stories: ['State a', 'State b'],
},
]
}

_handlePreviewEvents() {
Expand Down
1 change: 1 addition & 0 deletions lib/ui/src/modules/api/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ export default {
name: 'STORYBOOK',
url: 'https://github.com/storybooks/storybook',
sortStoriesByKind: false,
resolveStoryHierarchy: storyName => [storyName],
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess we'll lose a serialized function after passing through the channel.
We can consider options:

  • pass only JSON data here
  • provide this API on the manager side (it'll be available in addons.js)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think I'll just change it to be symbol/regex.
hierarchySeparator: '/' or hierarchySeparator: '.'

},
},
load({ clientStore, provider }, _actions) {
Expand Down
18 changes: 14 additions & 4 deletions lib/ui/src/modules/ui/components/left_panel/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,13 @@ const mainStyle = {
padding: '10px 0 10px 10px',
};

const storyProps = ['stories', 'selectedKind', 'selectedStory', 'onSelectStory'];
const storyProps = [
'storiesHierarchy',
'selectedKind',
'selectedHierarchy',
'selectedStory',
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Don't we need to have selectedStory and selectedKind in propTypes?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think linter cries that they are not in use in here. these props just passed further to stories.js where they are actually defined in prop types.

'onSelectStory',
];

const LeftPanel = props =>
<div style={mainStyle}>
Expand All @@ -26,12 +32,12 @@ const LeftPanel = props =>
onChange={text => props.onStoryFilter(text)}
/>
<div style={scrollStyle}>
{props.stories ? <Stories {...pick(props, storyProps)} /> : null}
{props.storiesHierarchy ? <Stories {...pick(props, storyProps)} /> : null}
</div>
</div>;

LeftPanel.defaultProps = {
stories: null,
storiesHierarchy: null,
storyFilter: null,
onStoryFilter: () => {},
openShortcutsHelp: null,
Expand All @@ -40,7 +46,11 @@ LeftPanel.defaultProps = {
};

LeftPanel.propTypes = {
stories: PropTypes.arrayOf(PropTypes.object),
storiesHierarchy: PropTypes.shape({
namespaces: PropTypes.arrayOf(PropTypes.string),
current: PropTypes.string,
map: PropTypes.object,
}),
storyFilter: PropTypes.string,
onStoryFilter: PropTypes.func,

Expand Down
14 changes: 10 additions & 4 deletions lib/ui/src/modules/ui/components/left_panel/index.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import LeftPanel from './index';
import Header from './header';
import TextFilter from './text_filter';
import Stories from './stories';
import { createHierarchy } from '../../libs/hierarchy';

describe('manager.ui.components.left_panel.index', () => {
test('should render Header and TextFilter by default', () => {
Expand All @@ -22,17 +23,22 @@ describe('manager.ui.components.left_panel.index', () => {
expect(wrap.find(Stories)).toBeEmpty();
});

test('should render stories only if stories prop exists', () => {
test('should render stories only if storiesHierarchy prop exists', () => {
const selectedKind = 'kk';
const selectedStory = 'bb';
const stories = [{ kind: 'kk', stories: ['bb'] }];
const storiesHierarchy = createHierarchy([{ kind: 'kk', stories: ['bb'] }]);
const wrap = shallow(
<LeftPanel stories={stories} selectedKind={selectedKind} selectedStory={selectedStory} />
<LeftPanel
storiesHierarchy={storiesHierarchy}
selectedKind={selectedKind}
selectedStory={selectedStory}
selectedHierarchy={['kk']}
/>
);

const header = wrap.find(Stories).first();
expect(header.props()).toMatchObject({
stories,
storiesHierarchy,
selectedKind,
selectedStory,
});
Expand Down
Loading