Skip to content

Commit

Permalink
Merge pull request #1387 from storybooks/151-story-hierarchy
Browse files Browse the repository at this point in the history
Story Hierarchy (UI improvements)
  • Loading branch information
shilman authored Jul 2, 2017
2 parents cf94190 + f048d32 commit b26e39b
Show file tree
Hide file tree
Showing 11 changed files with 392 additions and 277 deletions.
4 changes: 3 additions & 1 deletion lib/ui/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -28,11 +28,13 @@
"podda": "^1.2.2",
"prop-types": "^15.5.8",
"qs": "^6.4.0",
"react-icons": "^2.2.5",
"react-inspector": "^2.0.0",
"react-komposer": "^2.0.0",
"react-modal": "^1.7.6",
"react-split-pane": "^0.1.63",
"redux": "^3.6.0"
"redux": "^3.6.0",
"storybook-react-treebeard": "^1.1.6"
},
"devDependencies": {
"enzyme": "^2.8.2"
Expand Down
4 changes: 2 additions & 2 deletions lib/ui/src/modules/ui/components/left_panel/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import PropTypes from 'prop-types';
import React from 'react';
import pick from 'lodash.pick';
import Header from './header';
import Stories from './stories';
import Stories from './stories_tree';
import TextFilter from './text_filter';

const scrollStyle = {
Expand Down Expand Up @@ -48,7 +48,7 @@ LeftPanel.defaultProps = {
LeftPanel.propTypes = {
storiesHierarchy: PropTypes.shape({
namespaces: PropTypes.arrayOf(PropTypes.string),
current: PropTypes.string,
name: PropTypes.string,
map: PropTypes.object,
}),
storyFilter: PropTypes.string,
Expand Down
2 changes: 1 addition & 1 deletion lib/ui/src/modules/ui/components/left_panel/index.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { shallow } from 'enzyme';
import LeftPanel from './index';
import Header from './header';
import TextFilter from './text_filter';
import Stories from './stories';
import Stories from './stories_tree';
import { createHierarchy } from '../../libs/hierarchy';

describe('manager.ui.components.left_panel.index', () => {
Expand Down
196 changes: 0 additions & 196 deletions lib/ui/src/modules/ui/components/left_panel/stories.js

This file was deleted.

153 changes: 153 additions & 0 deletions lib/ui/src/modules/ui/components/left_panel/stories_tree/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,153 @@
import { Treebeard } from 'storybook-react-treebeard';
import PropTypes from 'prop-types';
import React from 'react';
import treeNodeTypes from './tree_node_type';
import treeDecorators from './tree_decorators';
import treeStyle from './tree_style';

const namespaceSeparator = '@';

function createNodeKey({ namespaces, type }) {
return [...namespaces, [type]].join(namespaceSeparator);
}

function getSelectedNodes(selectedHierarchy) {
return selectedHierarchy
.reduce((nodes, namespace, index) => {
const node = {};

node.type = selectedHierarchy.length - 1 === index
? treeNodeTypes.COMPONENT
: treeNodeTypes.NAMESPACE;

if (!nodes.length) {
node.namespaces = [namespace];
} else {
const lastNode = nodes[nodes.length - 1];
node.namespaces = [...lastNode.namespaces, [namespace]];
}

nodes.push(node);

return nodes;
}, [])
.reduce((nodesMap, node) => ({ ...nodesMap, [createNodeKey(node)]: true }), {});
}

class Stories extends React.Component {
constructor(...args) {
super(...args);
this.onToggle = this.onToggle.bind(this);

const { selectedHierarchy } = this.props;

this.state = {
nodes: getSelectedNodes(selectedHierarchy),
};
}

onToggle(node, toggled) {
if (node.story) {
this.fireOnKindAndStory(node.kind, node.story);
} else if (node.kind) {
this.fireOnKind(node.kind);
}

if (!node.namespaces) {
return;
}

this.setState(prevState => ({
nodes: {
...prevState.nodes,
[node.key]: toggled,
},
}));
}

fireOnKind(kind) {
const { onSelectStory } = this.props;
if (onSelectStory) onSelectStory(kind, null);
}

fireOnKindAndStory(kind, story) {
const { onSelectStory } = this.props;
if (onSelectStory) onSelectStory(kind, story);
}

mapStoriesHierarchy(storiesHierarchy) {
const treeModel = {
namespaces: storiesHierarchy.namespaces,
name: storiesHierarchy.name,
};

if (storiesHierarchy.isNamespace) {
treeModel.type = treeNodeTypes.NAMESPACE;

if (storiesHierarchy.map.size > 0) {
treeModel.children = [];

storiesHierarchy.map.forEach(childItems => {
childItems.forEach(item => {
treeModel.children.push(this.mapStoriesHierarchy(item));
});
});
}
} else {
const { selectedStory, selectedKind } = this.props;

treeModel.kind = storiesHierarchy.kind;
treeModel.type = treeNodeTypes.COMPONENT;

treeModel.children = storiesHierarchy.stories.map(story => ({
kind: storiesHierarchy.kind,
story,
name: story,
active: selectedStory === story && selectedKind === storiesHierarchy.kind,
type: treeNodeTypes.STORY,
}));
}

treeModel.key = createNodeKey(treeModel);
treeModel.toggled = this.state.nodes[treeModel.key];

return treeModel;
}

render() {
const { storiesHierarchy } = this.props;

const data = this.mapStoriesHierarchy(storiesHierarchy);
data.toggled = true;
data.name = 'stories';
data.root = true;

return (
<Treebeard
style={treeStyle}
data={data}
onToggle={this.onToggle}
decorators={treeDecorators}
/>
);
}
}

Stories.defaultProps = {
onSelectStory: null,
storiesHierarchy: null,
};

Stories.propTypes = {
storiesHierarchy: PropTypes.shape({
namespaces: PropTypes.arrayOf(PropTypes.string),
name: PropTypes.string,
map: PropTypes.object,
}),
selectedHierarchy: PropTypes.arrayOf(PropTypes.string).isRequired,
selectedKind: PropTypes.string.isRequired,
selectedStory: PropTypes.string.isRequired,
onSelectStory: PropTypes.func,
};

export default Stories;
Loading

0 comments on commit b26e39b

Please sign in to comment.