refs #13535 Merge branch '13535-tree-component' into 13610-projects-hierarchy
authorDaniel Kos <daniel.kos@contractors.roche.com>
Tue, 12 Jun 2018 19:38:39 +0000 (21:38 +0200)
committerDaniel Kos <daniel.kos@contractors.roche.com>
Tue, 12 Jun 2018 19:38:39 +0000 (21:38 +0200)
# Conflicts:
# package.json
# src/components/tree/tree.tsx
# src/index.tsx
# src/models/project.ts
# src/store/project-action.ts
# src/store/project-reducer.ts
# src/views/workbench/workbench.test.tsx
# src/views/workbench/workbench.tsx
# tslint.json
# yarn.lock

Arvados-DCO-1.1-Signed-off-by: Daniel Kos <daniel.kos@contractors.roche.com>

19 files changed:
package.json
public/index.html
src/components/project-list/project-list.tsx
src/components/project-tree/project-tree.test.tsx [new file with mode: 0644]
src/components/project-tree/project-tree.tsx [new file with mode: 0644]
src/components/tree/tree.test.tsx [new file with mode: 0644]
src/components/tree/tree.tsx
src/index.tsx
src/models/project.ts
src/store/project-action.ts [new file with mode: 0644]
src/store/project-reducer.ts [new file with mode: 0644]
src/store/project/project-action.ts
src/store/project/project-reducer.ts
src/views/workbench/workbench.test.tsx
src/views/workbench/workbench.tsx
tsconfig.json
tsconfig.test.json
tslint.json
yarn.lock

index ac890d8d89460f5e42f70ab33b4f43c8f67c67da..399750a3d77c8ca005d95bf8c8e1f02a2fe063d3 100644 (file)
@@ -5,6 +5,7 @@
   "dependencies": {
     "@material-ui/core": "1.2.0",
     "@material-ui/icons": "^1.1.0",
+    "lodash": "4.17.10",
     "axios": "0.18.0",
     "react": "16.4.0",
     "react-dom": "16.4.0",
@@ -25,6 +26,8 @@
     "lint": "tslint src/** -t verbose"
   },
   "devDependencies": {
+    "@types/enzyme": "^3.1.10",
+    "@types/enzyme-adapter-react-16": "^1.0.2",
     "@types/jest": "23.0.0",
     "@types/node": "10.3.0",
     "@types/react": "16.3.16",
@@ -34,6 +37,8 @@
     "@types/react-router-dom": "4.2.7",
     "@types/react-router-redux": "5.0.15",
     "@types/redux-devtools": "3.0.44",
+    "enzyme": "^3.3.0",
+    "enzyme-adapter-react-16": "^1.1.1",
     "jest-localstorage-mock": "2.2.0",
     "redux-devtools": "3.4.1",
     "typescript": "2.9.1"
index f6111b91895db5aad0429e757fb378ec2ba66c3a..a8d655e5872080571e26bf3f5a830046b3ffcffe 100644 (file)
@@ -10,6 +10,7 @@
     -->
     <link rel="manifest" href="%PUBLIC_URL%/manifest.json">
     <link rel="shortcut icon" href="%PUBLIC_URL%/favicon.ico">
+    <link href="//netdna.bootstrapcdn.com/font-awesome/3.2.1/css/font-awesome.css" rel="stylesheet">
     <!--
       Notice the use of %PUBLIC_URL% in the tags above.
       It will be replaced with the URL of the `public` folder during the build.
@@ -20,6 +21,8 @@
       Learn how to configure a non-root public URL by running `npm run build`.
     -->
     <title>Arvados Workbench 2</title>
+    <script>FontAwesomeConfig = { autoReplaceSvg: 'nest' }</script>
+    <script defer src="https://use.fontawesome.com/releases/v5.0.13/js/all.js" integrity="sha384-xymdQtn1n3lH2wcu0qhcdaOpQwyoarkgLVxC/wZ5q7h9gHtxICrpcaSUfygqZGOe" crossorigin="anonymous"></script>
   </head>
   <body>
     <noscript>
index 3526da391cd6d2585140b9c993d31029f676a674..ec16a677f45a83926f7ec79d15c17913ba10d10a 100644 (file)
@@ -4,9 +4,8 @@
 
 import * as React from 'react';
 import { Theme } from "@material-ui/core";
-import { StyleRulesCallback, WithStyles } from "@material-ui/core/styles";
+import { StyleRulesCallback, WithStyles, withStyles } from "@material-ui/core/styles";
 import Paper from "@material-ui/core/Paper/Paper";
-import withStyles from "@material-ui/core/es/styles/withStyles";
 import Table from "@material-ui/core/Table/Table";
 import TableHead from "@material-ui/core/TableHead/TableHead";
 import TableRow from "@material-ui/core/TableRow/TableRow";
diff --git a/src/components/project-tree/project-tree.test.tsx b/src/components/project-tree/project-tree.test.tsx
new file mode 100644 (file)
index 0000000..03bf44f
--- /dev/null
@@ -0,0 +1,92 @@
+// Copyright (C) The Arvados Authors. All rights reserved.
+//
+// SPDX-License-Identifier: AGPL-3.0
+
+import * as React from 'react';
+import * as ReactDOM from 'react-dom';
+import { shallow, mount, render } from 'enzyme';
+import * as Enzyme from 'enzyme';
+import * as Adapter from 'enzyme-adapter-react-16';
+import ListItemIcon from '@material-ui/core/ListItemIcon';
+import { Collapse } from '@material-ui/core';
+
+import ProjectTree from './project-tree';
+import { TreeItem } from '../tree/tree';
+import { Project } from '../../models/project';
+Enzyme.configure({ adapter: new Adapter() });
+
+describe("ProjectTree component", () => {
+
+    it("checks is there ListItemIcon in the ProjectTree component", () => {
+        const project: TreeItem<Project> = {
+            data: {
+                name: "sample name",
+                createdAt: "2018-06-12",
+                icon: <i className="fas fa-th" />
+            },
+            id: "3",
+            open: true,
+            active: true
+        }
+        const wrapper = mount(<ProjectTree projects={[project]} toggleProjectTreeItem={() => { }} />);
+
+        expect(wrapper.find(ListItemIcon).length).toEqual(1);
+    });
+
+    it("checks are there two ListItemIcon's in the ProjectTree component", () => {
+        const project: Array<TreeItem<Project>> = [
+            {
+                data: {
+                    name: "sample name",
+                    createdAt: "2018-06-12",
+                    icon: <i className="fas fa-th" />
+                },
+                id: "3",
+                open: false,
+                active: true
+            },
+            {
+                data: {
+                    name: "sample name",
+                    createdAt: "2018-06-12",
+                    icon: <i className="fas fa-th" />
+                },
+                id: "3",
+                open: false,
+                active: true
+            }
+        ]
+        const wrapper = mount(<ProjectTree projects={project} toggleProjectTreeItem={() => { }} />);
+
+        expect(wrapper.find(ListItemIcon).length).toEqual(2);
+    });
+
+    it("check ProjectTree, when open is changed", () => {
+        const project: TreeItem<Project> = {
+            data: {
+                name: "sample name",
+                createdAt: "2018-06-12",
+                icon: <i className="fas fa-th" />
+            },
+            id: "3",
+            open: true,
+            active: true,
+            items: [
+                {
+                    data: {
+                        name: "sample name",
+                        createdAt: "2018-06-12",
+                        icon: <i className="fas fa-th" />
+                    },
+                    id: "4",
+                    open: false,
+                    active: true
+                }
+            ]
+        }
+        const wrapper = mount(<ProjectTree projects={[project]} toggleProjectTreeItem={() => { }} />);
+        wrapper.setState({open: true });
+
+        expect(wrapper.find(Collapse).length).toEqual(1);
+    });
+});
diff --git a/src/components/project-tree/project-tree.tsx b/src/components/project-tree/project-tree.tsx
new file mode 100644 (file)
index 0000000..310dced
--- /dev/null
@@ -0,0 +1,60 @@
+// Copyright (C) The Arvados Authors. All rights reserved.
+//
+// SPDX-License-Identifier: AGPL-3.0
+
+import * as React from 'react';
+import { ReactElement } from 'react';
+import { StyleRulesCallback, Theme, WithStyles, withStyles } from '@material-ui/core/styles';
+import ListItemText from "@material-ui/core/ListItemText/ListItemText";
+import ListItemIcon from '@material-ui/core/ListItemIcon';
+import Typography from '@material-ui/core/Typography';
+
+import Tree, { TreeItem } from '../tree/tree';
+import { Project } from '../../models/project';
+
+type CssRules = 'active' | 'listItemText' | 'row' | 'treeContainer';
+
+const styles: StyleRulesCallback<CssRules> = (theme: Theme) => ({
+    active: {
+        color: '#4285F6',
+    },
+    listItemText: {
+        padding: '0px',
+    },
+    row: {
+        display: 'flex',
+        alignItems: 'center',
+        marginLeft: '20px',
+    },
+    treeContainer: {
+        position: 'absolute',
+        overflowX: 'visible',
+        marginTop: '80px',
+        minWidth: '240px',
+        whiteSpace: 'nowrap',
+    }
+});
+
+export interface WorkbenchProps {
+    projects: Array<TreeItem<Project>>;
+    toggleProjectTreeItem: (id: string) => any;
+}
+
+class ProjectTree<T> extends React.Component<WorkbenchProps & WithStyles<CssRules>> {
+    render(): ReactElement<any> {
+        const {classes, projects} = this.props;
+        const {active, listItemText, row, treeContainer} = classes;
+        return (
+            <div className={treeContainer}>
+                <Tree items={projects}
+                    toggleItem={this.props.toggleProjectTreeItem}
+                    render={(project: TreeItem<Project>) => <span className={row}>
+                        <ListItemIcon className={project.active ? active : ''}>{project.data.icon}</ListItemIcon>
+                        <ListItemText className={listItemText} primary={<Typography className={project.active ? active : ''}>{project.data.name}</Typography>} />
+                    </span>} />
+            </div>
+        );
+    }
+}
+
+export default withStyles(styles)(ProjectTree)
\ No newline at end of file
diff --git a/src/components/tree/tree.test.tsx b/src/components/tree/tree.test.tsx
new file mode 100644 (file)
index 0000000..6a5f410
--- /dev/null
@@ -0,0 +1,3 @@
+// Copyright (C) The Arvados Authors. All rights reserved.
+//
+// SPDX-License-Identifier: AGPL-3.0
index 12369d57e12b1415624839a8244dbe95bb7442d6..fdde3c16a6c08023a127d98f4f166ac40e63b025 100644 (file)
@@ -5,23 +5,71 @@
 import * as React from 'react';
 import List from "@material-ui/core/List/List";
 import ListItem from "@material-ui/core/ListItem/ListItem";
+import { StyleRulesCallback, Theme, withStyles, WithStyles } from '@material-ui/core/styles';
 import { ReactElement } from "react";
+import Collapse from "@material-ui/core/Collapse/Collapse";
+
+type CssRules = 'list' | 'activeArrow' | 'arrow' | 'arrowRotate';
+
+const styles: StyleRulesCallback<CssRules> = (theme: Theme) => ({
+    list: {
+        paddingBottom: '3px', 
+        paddingTop: '3px',
+    },
+    activeArrow: {
+        color: '#4285F6', 
+        position: 'absolute',
+    },
+    arrow: {
+        position: 'absolute',
+    },
+    arrowRotate: {
+        transform: 'rotate(-90deg)',
+    }
+});
+
+export interface TreeItem<T> {
+    data: T;
+    id: string;
+    open: boolean;
+    active: boolean;
+    items?: Array<TreeItem<T>>;
+}
 
 interface TreeProps<T> {
-    items: T[],
-    render: (item: T) => ReactElement<{}>
+    items?: Array<TreeItem<T>>;
+    render: (item: TreeItem<T>) => ReactElement<{}>;
+    toggleItem: (id: string) => any;
+    level?: number;
 }
 
-class Tree<T> extends React.Component<TreeProps<T>, {}> {
-    render() {
-        return <List>
-            {this.props.items && this.props.items.map((it: T, idx: number) =>
-                <ListItem key={`item/${idx}`} button>
-                    {this.props.render(it)}
+class Tree<T> extends React.Component<TreeProps<T> & WithStyles<CssRules>, {}> {
+    renderArrow (items: Array<TreeItem<T>> | undefined, arrowClass: string, isOpen: boolean){
+        return items && items.length > 0 ? <i className={`${arrowClass} ${isOpen ? "fas fa-caret-down" : `fas fa-caret-down ${this.props.classes.arrowRotate}`}`} /> : ''
+    }
+    render(): ReactElement<any> {
+        const level = this.props.level ? this.props.level : 0;
+        const {classes, render, toggleItem, items} = this.props;
+        const {list, arrow, activeArrow, arrowRotate} = classes;
+        return <List component="div" className={list}>
+            {items && items.map((it: TreeItem<T>, idx: number) =>
+             <div key={`item/${level}/${idx}`}>      
+                <ListItem button onClick={() => toggleItem(it.id)} className={list} style={{paddingLeft: (level + 1) * 20}}>  
+                    {it.active ? this.renderArrow(it.items, activeArrow, it.open) : this.renderArrow(it.items, arrow, it.open)}
+                    {render(it)}
                 </ListItem>
-            )}
+                {it.items && it.items.length > 0 &&
+                <Collapse in={it.open} timeout="auto" unmountOnExit>
+                    <StyledTree 
+                        items={it.items}
+                        render={render}
+                        toggleItem={toggleItem}
+                        level={level + 1}/>
+                </Collapse>}
+             </div>)}
         </List>
     }
 }
 
-export default Tree;
+const StyledTree = withStyles(styles)(Tree);
+export default StyledTree
index 0cb67f1d82771a985d0b0637078c7d8dbb62463d..173296817b317294d0fe75f8907c0468dd388835 100644 (file)
@@ -15,8 +15,26 @@ import { ConnectedRouter } from "react-router-redux";
 import ApiToken from "./components/api-token/api-token";
 import authActions from "./store/auth/auth-action";
 import { projectService } from "./services/services";
+import { TreeItem } from "./components/tree/tree";
+import { Project } from "./models/project";
 
+function buildProjectTree(tree: any[], level = 0): Array<TreeItem<Project>> {
+    const projects = tree.map((t, idx) => ({
+        id: `l${level}i${idx}${t[0]}`,
+        open: false,
+        active: false,
+        data: {
+            name: t[0],
+            icon: level === 0 ? <i className="fas fa-th"/> : <i className="fas fa-folder"/>,
+            createdAt: '2018-05-05',
+        },
+        items: t.length > 1 ? buildProjectTree(t[1], level + 1) : []
+    }));
+    return projects;
+}
 const history = createBrowserHistory();
+const projects = buildProjectTree(sampleProjects);
+
 const store = configureStore({
     projects: [
     ],
@@ -31,6 +49,7 @@ const store = configureStore({
 store.dispatch(authActions.INIT());
 store.dispatch<any>(projectService.getProjectList());
 
+
 const App = () =>
     <Provider store={store}>
         <ConnectedRouter history={history}>
index 83862c94001a575f55136faa8b1d93653a44f415..f4faf7d64e14acddce651b3bc64b71a2d47ba78c 100644 (file)
@@ -8,5 +8,6 @@ export interface Project {
     modifiedAt: string;
     uuid: string;
     ownerUuid: string;
-    href: string
+    href: string;
+    icon?: any;
 }
diff --git a/src/store/project-action.ts b/src/store/project-action.ts
new file mode 100644 (file)
index 0000000..7cd3bac
--- /dev/null
@@ -0,0 +1,14 @@
+// Copyright (C) The Arvados Authors. All rights reserved.
+//
+// SPDX-License-Identifier: AGPL-3.0
+
+import { ActionType, createStandardAction } from "typesafe-actions";
+import { Project } from "../models/project";
+
+export const actions = {
+    createProject: createStandardAction('@@project/create')<Project>(),
+    removeProject: createStandardAction('@@project/remove')<string>(),
+    toggleProjectTreeItem: createStandardAction('@@project/toggleTreeItem')<string>()
+};
+
+export type ProjectAction = ActionType<typeof actions>;
diff --git a/src/store/project-reducer.ts b/src/store/project-reducer.ts
new file mode 100644 (file)
index 0000000..42442ba
--- /dev/null
@@ -0,0 +1,57 @@
+// Copyright (C) The Arvados Authors. All rights reserved.
+//
+// SPDX-License-Identifier: AGPL-3.0
+
+import { getType } from "typesafe-actions";
+import { Project } from "../models/project";
+import { actions, ProjectAction } from "./project-action";
+import { TreeItem } from "../components/tree/tree";
+import * as _ from 'lodash';
+
+type ProjectState = Array<TreeItem<Project>>;
+
+function findTreeItem<T>(tree: Array<TreeItem<T>>, itemId: string): TreeItem<T> | undefined {
+    let item;
+    for (const t of tree) {
+        item = t.id === itemId
+            ? t
+            : findTreeItem(t.items ? t.items : [], itemId);
+        if (item) {
+            break;
+        }
+    }
+    return item;
+}
+
+function resetTreeActivity<T>(tree: Array<TreeItem<T>>): boolean | undefined {
+    let item;
+    for (const leaf of tree) {
+        item = leaf.active === true
+            ? leaf.active = false
+            : resetTreeActivity(leaf.items ? leaf.items : []);
+    }
+    return item;
+}
+
+const projectsReducer = (state: ProjectState = [], action: ProjectAction) => {
+    switch (action.type) {
+        case getType(actions.createProject): {
+            return [...state, action.payload];
+        }
+        case getType(actions.toggleProjectTreeItem): {
+            const tree = _.cloneDeep(state);
+            const itemId = action.payload;
+            resetTreeActivity(tree);
+            const item = findTreeItem(tree, itemId);
+            if (item) {
+                item.open = !item.open;
+                item.active = true;
+            }
+            return tree;
+        }
+        default:
+            return state;
+    }
+};
+
+export default projectsReducer;
index c88edb60df8d0c764563ee48c027289859214567..2101619515a0c197855425667b28910581165df7 100644 (file)
@@ -9,7 +9,8 @@ const actions = unionize({
     CREATE_PROJECT: ofType<Project>(),
     REMOVE_PROJECT: ofType<string>(),
     PROJECTS_REQUEST: {},
-    PROJECTS_SUCCESS: ofType<Project[]>()
+    PROJECTS_SUCCESS: ofType<Project[]>(),
+    TOGGLE_PROJECT_TREE_ITEM: ofType<string>()
 }, {
     tag: 'type',
     value: 'payload'
index 477cb1e4688e309e243d78cece928313f6215146..458177c0431c9d240ec0b08664014615ea095b36 100644 (file)
@@ -4,8 +4,33 @@
 
 import { Project } from "../../models/project";
 import actions, { ProjectAction } from "./project-action";
+import { TreeItem } from "../../components/tree/tree";
+import * as _ from "lodash";
 
-export type ProjectState = Project[];
+export type ProjectState = Array<TreeItem<Project>>;
+
+function findTreeItem<T>(tree: Array<TreeItem<T>>, itemId: string): TreeItem<T> | undefined {
+    let item;
+    for (const t of tree) {
+        item = t.id === itemId
+            ? t
+            : findTreeItem(t.items ? t.items : [], itemId);
+        if (item) {
+            break;
+        }
+    }
+    return item;
+}
+
+function resetTreeActivity<T>(tree: Array<TreeItem<T>>): boolean | undefined {
+    let item;
+    for (const leaf of tree) {
+        item = leaf.active === true
+            ? leaf.active = false
+            : resetTreeActivity(leaf.items ? leaf.items : []);
+    }
+    return item;
+}
 
 const projectsReducer = (state: ProjectState = [], action: ProjectAction) => {
     return actions.match(action, {
@@ -15,6 +40,16 @@ const projectsReducer = (state: ProjectState = [], action: ProjectAction) => {
         PROJECTS_SUCCESS: projects => {
             return projects;
         },
+        TOGGLE_PROJECT_TREE_ITEM: itemId => {
+            const tree = _.cloneDeep(state);
+            resetTreeActivity(tree);
+            const item = findTreeItem(tree, itemId);
+            if (item) {
+                item.open = !item.open;
+                item.active = true;
+            }
+            return tree;
+        },
         default: () => state
     });
 };
index fc89609acc43b45767fcebb0cec2f0518953423f..7b9b74d095c65a8a1ad760a2c4c87f360cb13836 100644 (file)
@@ -8,10 +8,19 @@ import Workbench from '../../views/workbench/workbench';
 import { Provider } from "react-redux";
 import configureStore from "../../store/store";
 import createBrowserHistory from "history/createBrowserHistory";
+import { ConnectedRouter } from "react-router-redux";
+
+const history = createBrowserHistory();
 
 it('renders without crashing', () => {
     const div = document.createElement('div');
     const store = configureStore({ projects: [], router: { location: null }, auth: {} }, createBrowserHistory());
-    ReactDOM.render(<Provider store={store}><Workbench/></Provider>, div);
+    ReactDOM.render(
+        <Provider store={store}>
+            <ConnectedRouter history={history}>
+                <Workbench/>
+            </ConnectedRouter>
+        </Provider>,
+    div);
     ReactDOM.unmountComponentAtNode(div);
 });
index 8c3145b823e1950a58aa2bca49129ab23c0e8023..7cccfe3034698057db006cde792dc0e4d201a915 100644 (file)
@@ -25,6 +25,9 @@ import { User } from "../../models/user";
 import Grid from "@material-ui/core/Grid/Grid";
 import { RootState } from "../../store/store";
 
+import { actions as projectActions } from "../../store/project-action";
+import ProjectTree, { WorkbenchProps } from '../../components/project-tree/project-tree';
+
 const drawerWidth = 240;
 
 type CssRules = 'root' | 'appBar' | 'drawerPaper' | 'content' | 'toolbar';
@@ -154,9 +157,9 @@ class Workbench extends React.Component<WorkbenchProps, WorkbenchState> {
                         paper: classes.drawerPaper,
                     }}>
                     <div className={classes.toolbar}/>
-                    <Tree items={this.props.projects} render={(p: Project) =>
-                        <Link to={`/project/${p.name}`}>{p.name}</Link>
-                    }/>
+                           <ProjectTree
+                        projects={this.props.projects}
+                        toggleProjectTreeItem={this.props.toggleProjectTreeItem}/>
                 </Drawer>}
                 <main className={classes.content}>
                     <div className={classes.toolbar}/>
@@ -173,7 +176,9 @@ export default connect<WorkbenchDataProps>(
     (state: RootState) => ({
         projects: state.projects,
         user: state.auth.user
-    })
+    }){
+        toggleProjectTreeItem: (id: string) => projectActions.toggleProjectTreeItem(id)
+    }
 )(
     withStyles(styles)(Workbench)
 );
index 98d5d9151c7b8f706dcfd3944f0bdee6a573f2c8..af933d9fa9a09755a64da1f8f3f8c4c5b54c1d68 100644 (file)
@@ -31,6 +31,7 @@
     "acceptance-tests",
     "webpack",
     "jest",
-    "src/setupTests.ts"
+    "src/setupTests.ts",
+    "**/*.test.tsx"
   ]
 }
index 65ffdd493929cf996f7f185609fb9f3f7f14184b..2c7b284162f4cafdbef8875c7ae7cb517c8e7abd 100644 (file)
@@ -3,4 +3,4 @@
   "compilerOptions": {
     "module": "commonjs"
   }
-}
\ No newline at end of file
+}
index ccb194f75b7577c150c09125d6b0d8ef6b0edc0d..1b26ab5f0f629330f31409d8b463422f1ee668d1 100644 (file)
@@ -10,7 +10,8 @@
     "jsx-boolean-value": false,
     "jsx-no-lambda": false,
     "no-debugger": false,
-    "no-console": false
+    "no-console": false,
+    "no-shadowed-variable": false
   },
   "linterOptions": {
     "exclude": [
index 7b9820bb5807c253e3aa0f5c2c5539f9d0053d6d..f3950fae03611dd1acd889ff4423ffb71c7c9dd0 100644 (file)
--- a/yarn.lock
+++ b/yarn.lock
   dependencies:
     recompose "^0.26.0 || ^0.27.0"
 
+"@types/cheerio@*":
+  version "0.22.7"
+  resolved "https://registry.yarnpkg.com/@types/cheerio/-/cheerio-0.22.7.tgz#4a92eafedfb2b9f4437d3a4410006d81114c66ce"
+
+"@types/enzyme-adapter-react-16@^1.0.2":
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/@types/enzyme-adapter-react-16/-/enzyme-adapter-react-16-1.0.2.tgz#15ae37c64d6221a6f4b3a4aacc357cf773859de4"
+  dependencies:
+    "@types/enzyme" "*"
+
+"@types/enzyme@*", "@types/enzyme@^3.1.10":
+  version "3.1.10"
+  resolved "https://registry.yarnpkg.com/@types/enzyme/-/enzyme-3.1.10.tgz#28108a9864e65699751469551a803a35d2e26160"
+  dependencies:
+    "@types/cheerio" "*"
+    "@types/react" "*"
+
 "@types/history@*":
   version "4.6.2"
   resolved "https://registry.yarnpkg.com/@types/history/-/history-4.6.2.tgz#12cfaba693ba20f114ed5765467ff25fdf67ddb0"
     csstype "^2.0.0"
     indefinite-observable "^1.0.1"
 
+"@types/lodash@4.14.109":
+  version "4.14.109"
+  resolved "https://registry.yarnpkg.com/@types/lodash/-/lodash-4.14.109.tgz#b1c4442239730bf35cabaf493c772b18c045886d"
+
 "@types/node@*", "@types/node@10.3.0":
   version "10.3.0"
   resolved "https://registry.yarnpkg.com/@types/node/-/node-10.3.0.tgz#078516315a84d56216b5d4fed8f75d59d3b16cac"
@@ -1464,6 +1485,17 @@ chardet@^0.4.0:
   version "0.4.2"
   resolved "https://registry.yarnpkg.com/chardet/-/chardet-0.4.2.tgz#b5473b33dc97c424e5d98dc87d55d4d8a29c8bf2"
 
+cheerio@^1.0.0-rc.2:
+  version "1.0.0-rc.2"
+  resolved "https://registry.yarnpkg.com/cheerio/-/cheerio-1.0.0-rc.2.tgz#4b9f53a81b27e4d5dac31c0ffd0cfa03cc6830db"
+  dependencies:
+    css-select "~1.2.0"
+    dom-serializer "~0.1.0"
+    entities "~1.1.1"
+    htmlparser2 "^3.9.1"
+    lodash "^4.15.0"
+    parse5 "^3.0.1"
+
 chokidar@^1.6.0, chokidar@^1.7.0:
   version "1.7.0"
   resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-1.7.0.tgz#798e689778151c8076b4b360e5edd28cda2bb468"
@@ -1632,6 +1664,10 @@ colormin@^1.0.5:
     css-color-names "0.0.4"
     has "^1.0.1"
 
+colors@0.5.x:
+  version "0.5.1"
+  resolved "https://registry.yarnpkg.com/colors/-/colors-0.5.1.tgz#7d0023eaeb154e8ee9fce75dcb923d0ed1667774"
+
 colors@~1.1.2:
   version "1.1.2"
   resolved "https://registry.yarnpkg.com/colors/-/colors-1.1.2.tgz#168a4701756b6a7f51a12ce0c97bfa28c084ed63"
@@ -1882,7 +1918,7 @@ css-loader@0.28.7:
     postcss-value-parser "^3.3.0"
     source-list-map "^2.0.0"
 
-css-select@^1.1.0:
+css-select@^1.1.0, css-select@~1.2.0:
   version "1.2.0"
   resolved "https://registry.yarnpkg.com/css-select/-/css-select-1.2.0.tgz#2b3a110539c5355f1cd8d314623e870b121ec858"
   dependencies:
@@ -2168,6 +2204,10 @@ diffie-hellman@^5.0.0:
     miller-rabin "^4.0.0"
     randombytes "^2.0.0"
 
+discontinuous-range@1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/discontinuous-range/-/discontinuous-range-1.0.0.tgz#e38331f0844bba49b9a9cb71c771585aab1bc65a"
+
 dns-equal@^1.0.0:
   version "1.0.0"
   resolved "https://registry.yarnpkg.com/dns-equal/-/dns-equal-1.0.0.tgz#b39e7f1da6eb0a75ba9c17324b34753c47e0654d"
@@ -2195,7 +2235,7 @@ dom-helpers@^3.2.1, dom-helpers@^3.3.1:
   version "3.3.1"
   resolved "https://registry.yarnpkg.com/dom-helpers/-/dom-helpers-3.3.1.tgz#fc1a4e15ffdf60ddde03a480a9c0fece821dd4a6"
 
-dom-serializer@0:
+dom-serializer@0, dom-serializer@~0.1.0:
   version "0.1.0"
   resolved "https://registry.yarnpkg.com/dom-serializer/-/dom-serializer-0.1.0.tgz#073c697546ce0780ce23be4a28e293e40bc30c82"
   dependencies:
@@ -2216,7 +2256,7 @@ domain-browser@^1.1.1:
   version "1.2.0"
   resolved "https://registry.yarnpkg.com/domain-browser/-/domain-browser-1.2.0.tgz#3d31f50191a6749dd1375a7f522e823d42e54eda"
 
-domelementtype@1:
+domelementtype@1, domelementtype@^1.3.0:
   version "1.3.0"
   resolved "https://registry.yarnpkg.com/domelementtype/-/domelementtype-1.3.0.tgz#b17aed82e8ab59e52dd9c19b1756e0fc187204c2"
 
@@ -2236,6 +2276,12 @@ domhandler@2.1:
   dependencies:
     domelementtype "1"
 
+domhandler@^2.3.0:
+  version "2.4.2"
+  resolved "https://registry.yarnpkg.com/domhandler/-/domhandler-2.4.2.tgz#8805097e933d65e85546f726d60f5eb88b44f803"
+  dependencies:
+    domelementtype "1"
+
 domutils@1.1:
   version "1.1.6"
   resolved "https://registry.yarnpkg.com/domutils/-/domutils-1.1.6.tgz#bddc3de099b9a2efacc51c623f28f416ecc57485"
@@ -2249,6 +2295,13 @@ domutils@1.5.1:
     dom-serializer "0"
     domelementtype "1"
 
+domutils@^1.5.1:
+  version "1.7.0"
+  resolved "https://registry.yarnpkg.com/domutils/-/domutils-1.7.0.tgz#56ea341e834e06e6748af7a1cb25da67ea9f8c2a"
+  dependencies:
+    dom-serializer "0"
+    domelementtype "1"
+
 dot-prop@^4.1.0:
   version "4.2.0"
   resolved "https://registry.yarnpkg.com/dot-prop/-/dot-prop-4.2.0.tgz#1f19e0c2e1aa0e32797c49799f2837ac6af69c57"
@@ -2335,10 +2388,51 @@ enhanced-resolve@^3.0.0, enhanced-resolve@^3.4.0:
     object-assign "^4.0.1"
     tapable "^0.2.7"
 
-entities@~1.1.1:
+entities@^1.1.1, entities@~1.1.1:
   version "1.1.1"
   resolved "https://registry.yarnpkg.com/entities/-/entities-1.1.1.tgz#6e5c2d0a5621b5dadaecef80b90edfb5cd7772f0"
 
+enzyme-adapter-react-16@^1.1.1:
+  version "1.1.1"
+  resolved "https://registry.yarnpkg.com/enzyme-adapter-react-16/-/enzyme-adapter-react-16-1.1.1.tgz#a8f4278b47e082fbca14f5bfb1ee50ee650717b4"
+  dependencies:
+    enzyme-adapter-utils "^1.3.0"
+    lodash "^4.17.4"
+    object.assign "^4.0.4"
+    object.values "^1.0.4"
+    prop-types "^15.6.0"
+    react-reconciler "^0.7.0"
+    react-test-renderer "^16.0.0-0"
+
+enzyme-adapter-utils@^1.3.0:
+  version "1.3.0"
+  resolved "https://registry.yarnpkg.com/enzyme-adapter-utils/-/enzyme-adapter-utils-1.3.0.tgz#d6c85756826c257a8544d362cc7a67e97ea698c7"
+  dependencies:
+    lodash "^4.17.4"
+    object.assign "^4.0.4"
+    prop-types "^15.6.0"
+
+enzyme@^3.3.0:
+  version "3.3.0"
+  resolved "https://registry.yarnpkg.com/enzyme/-/enzyme-3.3.0.tgz#0971abd167f2d4bf3f5bd508229e1c4b6dc50479"
+  dependencies:
+    cheerio "^1.0.0-rc.2"
+    function.prototype.name "^1.0.3"
+    has "^1.0.1"
+    is-boolean-object "^1.0.0"
+    is-callable "^1.1.3"
+    is-number-object "^1.0.3"
+    is-string "^1.0.4"
+    is-subset "^0.1.1"
+    lodash "^4.17.4"
+    object-inspect "^1.5.0"
+    object-is "^1.0.1"
+    object.assign "^4.1.0"
+    object.entries "^1.0.4"
+    object.values "^1.0.4"
+    raf "^3.4.0"
+    rst-selector-parser "^2.2.3"
+
 errno@^0.1.3, errno@~0.1.7:
   version "0.1.7"
   resolved "https://registry.yarnpkg.com/errno/-/errno-0.1.7.tgz#4684d71779ad39af177e3f007996f7c67c852618"
@@ -2937,6 +3031,14 @@ function-bind@^1.1.1:
   version "1.1.1"
   resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d"
 
+function.prototype.name@^1.0.3:
+  version "1.1.0"
+  resolved "https://registry.yarnpkg.com/function.prototype.name/-/function.prototype.name-1.1.0.tgz#8bd763cc0af860a859cc5d49384d74b932cd2327"
+  dependencies:
+    define-properties "^1.1.2"
+    function-bind "^1.1.1"
+    is-callable "^1.1.3"
+
 gauge@~2.7.3:
   version "2.7.4"
   resolved "https://registry.yarnpkg.com/gauge/-/gauge-2.7.4.tgz#2c03405c7538c39d7eb37b317022e325fb018bf7"
@@ -3138,6 +3240,10 @@ has-flag@^3.0.0:
   version "3.0.0"
   resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd"
 
+has-symbols@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.0.tgz#ba1a8f1af2a0fc39650f5c850367704122063b44"
+
 has-unicode@^2.0.0:
   version "2.0.1"
   resolved "https://registry.yarnpkg.com/has-unicode/-/has-unicode-2.0.1.tgz#e0e6fe6a28cf51138855e086d1691e771de2a8b9"
@@ -3278,6 +3384,17 @@ html-webpack-plugin@2.29.0:
     pretty-error "^2.0.2"
     toposort "^1.0.0"
 
+htmlparser2@^3.9.1:
+  version "3.9.2"
+  resolved "https://registry.yarnpkg.com/htmlparser2/-/htmlparser2-3.9.2.tgz#1bdf87acca0f3f9e53fa4fcceb0f4b4cbb00b338"
+  dependencies:
+    domelementtype "^1.3.0"
+    domhandler "^2.3.0"
+    domutils "^1.5.1"
+    entities "^1.1.1"
+    inherits "^2.0.1"
+    readable-stream "^2.0.2"
+
 htmlparser2@~3.3.0:
   version "3.3.0"
   resolved "https://registry.yarnpkg.com/htmlparser2/-/htmlparser2-3.3.0.tgz#cc70d05a59f6542e43f0e685c982e14c924a9efe"
@@ -3514,6 +3631,10 @@ is-binary-path@^1.0.0:
   dependencies:
     binary-extensions "^1.0.0"
 
+is-boolean-object@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/is-boolean-object/-/is-boolean-object-1.0.0.tgz#98f8b28030684219a95f375cfbd88ce3405dff93"
+
 is-buffer@^1.1.5:
   version "1.1.6"
   resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-1.1.6.tgz#efaa2ea9daa0d7ab2ea13a97b2b8ad51fefbe8be"
@@ -3655,6 +3776,10 @@ is-npm@^1.0.0:
   version "1.0.0"
   resolved "https://registry.yarnpkg.com/is-npm/-/is-npm-1.0.0.tgz#f2fb63a65e4905b406c86072765a1a4dc793b9f4"
 
+is-number-object@^1.0.3:
+  version "1.0.3"
+  resolved "https://registry.yarnpkg.com/is-number-object/-/is-number-object-1.0.3.tgz#f265ab89a9f445034ef6aff15a8f00b00f551799"
+
 is-number@^2.1.0:
   version "2.1.0"
   resolved "https://registry.yarnpkg.com/is-number/-/is-number-2.1.0.tgz#01fcbbb393463a548f2f466cce16dece49db908f"
@@ -3741,6 +3866,14 @@ is-stream@^1.0.0, is-stream@^1.0.1, is-stream@^1.1.0:
   version "1.1.0"
   resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-1.1.0.tgz#12d4a3dd4e68e0b79ceb8dbc84173ae80d91ca44"
 
+is-string@^1.0.4:
+  version "1.0.4"
+  resolved "https://registry.yarnpkg.com/is-string/-/is-string-1.0.4.tgz#cc3a9b69857d621e963725a24caeec873b826e64"
+
+is-subset@^0.1.1:
+  version "0.1.1"
+  resolved "https://registry.yarnpkg.com/is-subset/-/is-subset-0.1.1.tgz#8a59117d932de1de00f245fcdd39ce43f1e939a6"
+
 is-svg@^2.0.0:
   version "2.1.0"
   resolved "https://registry.yarnpkg.com/is-svg/-/is-svg-2.1.0.tgz#cf61090da0d9efbcab8722deba6f032208dbb0e9"
@@ -4470,6 +4603,10 @@ lodash.endswith@^4.2.1:
   version "4.2.1"
   resolved "https://registry.yarnpkg.com/lodash.endswith/-/lodash.endswith-4.2.1.tgz#fed59ac1738ed3e236edd7064ec456448b37bc09"
 
+lodash.flattendeep@^4.4.0:
+  version "4.4.0"
+  resolved "https://registry.yarnpkg.com/lodash.flattendeep/-/lodash.flattendeep-4.4.0.tgz#fb030917f86a3134e5bc9bec0d69e0013ddfedb2"
+
 lodash.isfunction@^3.0.8:
   version "3.0.9"
   resolved "https://registry.yarnpkg.com/lodash.isfunction/-/lodash.isfunction-3.0.9.tgz#06de25df4db327ac931981d1bdb067e5af68d051"
@@ -4507,7 +4644,7 @@ lodash.uniq@^4.5.0:
   version "4.5.0"
   resolved "https://registry.yarnpkg.com/lodash.uniq/-/lodash.uniq-4.5.0.tgz#d0225373aeb652adc1bc82e4945339a842754773"
 
-"lodash@>=3.5 <5", lodash@^4.13.1, lodash@^4.17.10, lodash@^4.17.2, lodash@^4.17.3, lodash@^4.17.4, lodash@^4.17.5, lodash@^4.2.0, lodash@^4.2.1, lodash@^4.3.0:
+lodash@4.17.10, "lodash@>=3.5 <5", lodash@^4.13.1, lodash@^4.15.0, lodash@^4.17.10, lodash@^4.17.2, lodash@^4.17.3, lodash@^4.17.4, lodash@^4.17.5, lodash@^4.2.0, lodash@^4.2.1, lodash@^4.3.0:
   version "4.17.10"
   resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.10.tgz#1b7793cf7259ea38fb3661d4d38b3260af8ae4e7"
 
@@ -4841,6 +4978,15 @@ natural-compare@^1.4.0:
   version "1.4.0"
   resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7"
 
+nearley@^2.7.10:
+  version "2.13.0"
+  resolved "https://registry.yarnpkg.com/nearley/-/nearley-2.13.0.tgz#6e7b0f4e68bfc3e74c99eaef2eda39e513143439"
+  dependencies:
+    nomnom "~1.6.2"
+    railroad-diagrams "^1.0.0"
+    randexp "0.4.6"
+    semver "^5.4.1"
+
 needle@^2.2.0:
   version "2.2.1"
   resolved "https://registry.yarnpkg.com/needle/-/needle-2.2.1.tgz#b5e325bd3aae8c2678902fa296f729455d1d3a7d"
@@ -4934,6 +5080,13 @@ node-pre-gyp@^0.10.0:
     semver "^5.3.0"
     tar "^4"
 
+nomnom@~1.6.2:
+  version "1.6.2"
+  resolved "https://registry.yarnpkg.com/nomnom/-/nomnom-1.6.2.tgz#84a66a260174408fc5b77a18f888eccc44fb6971"
+  dependencies:
+    colors "0.5.x"
+    underscore "~1.4.4"
+
 nopt@^4.0.1:
   version "4.0.1"
   resolved "https://registry.yarnpkg.com/nopt/-/nopt-4.0.1.tgz#d0d4685afd5415193c8c7505602d0d17cd64474d"
@@ -5033,7 +5186,15 @@ object-copy@^0.1.0:
     define-property "^0.2.5"
     kind-of "^3.0.3"
 
-object-keys@^1.0.8:
+object-inspect@^1.5.0:
+  version "1.6.0"
+  resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.6.0.tgz#c70b6cbf72f274aab4c34c0c82f5167bf82cf15b"
+
+object-is@^1.0.1:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/object-is/-/object-is-1.0.1.tgz#0aa60ec9989a0b3ed795cf4d06f62cf1ad6539b6"
+
+object-keys@^1.0.11, object-keys@^1.0.8:
   version "1.0.11"
   resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-1.0.11.tgz#c54601778ad560f1142ce0e01bcca8b56d13426d"
 
@@ -5043,6 +5204,24 @@ object-visit@^1.0.0:
   dependencies:
     isobject "^3.0.0"
 
+object.assign@^4.0.4, object.assign@^4.1.0:
+  version "4.1.0"
+  resolved "https://registry.yarnpkg.com/object.assign/-/object.assign-4.1.0.tgz#968bf1100d7956bb3ca086f006f846b3bc4008da"
+  dependencies:
+    define-properties "^1.1.2"
+    function-bind "^1.1.1"
+    has-symbols "^1.0.0"
+    object-keys "^1.0.11"
+
+object.entries@^1.0.4:
+  version "1.0.4"
+  resolved "https://registry.yarnpkg.com/object.entries/-/object.entries-1.0.4.tgz#1bf9a4dd2288f5b33f3a993d257661f05d161a5f"
+  dependencies:
+    define-properties "^1.1.2"
+    es-abstract "^1.6.1"
+    function-bind "^1.1.0"
+    has "^1.0.1"
+
 object.getownpropertydescriptors@^2.0.3:
   version "2.0.3"
   resolved "https://registry.yarnpkg.com/object.getownpropertydescriptors/-/object.getownpropertydescriptors-2.0.3.tgz#8758c846f5b407adab0f236e0986f14b051caa16"
@@ -5063,6 +5242,15 @@ object.pick@^1.3.0:
   dependencies:
     isobject "^3.0.1"
 
+object.values@^1.0.4:
+  version "1.0.4"
+  resolved "https://registry.yarnpkg.com/object.values/-/object.values-1.0.4.tgz#e524da09b4f66ff05df457546ec72ac99f13069a"
+  dependencies:
+    define-properties "^1.1.2"
+    es-abstract "^1.6.1"
+    function-bind "^1.1.0"
+    has "^1.0.1"
+
 obuf@^1.0.0, obuf@^1.1.1:
   version "1.1.2"
   resolved "https://registry.yarnpkg.com/obuf/-/obuf-1.1.2.tgz#09bea3343d41859ebd446292d11c9d4db619084e"
@@ -5242,6 +5430,12 @@ parse5@4.0.0:
   version "4.0.0"
   resolved "https://registry.yarnpkg.com/parse5/-/parse5-4.0.0.tgz#6d78656e3da8d78b4ec0b906f7c08ef1dfe3f608"
 
+parse5@^3.0.1:
+  version "3.0.3"
+  resolved "https://registry.yarnpkg.com/parse5/-/parse5-3.0.3.tgz#042f792ffdd36851551cf4e9e066b3874ab45b5c"
+  dependencies:
+    "@types/node" "*"
+
 parseurl@~1.3.2:
   version "1.3.2"
   resolved "https://registry.yarnpkg.com/parseurl/-/parseurl-1.3.2.tgz#fc289d4ed8993119460c156253262cdc8de65bf3"
@@ -5802,7 +5996,7 @@ querystringify@^2.0.0:
   version "2.0.0"
   resolved "https://registry.yarnpkg.com/querystringify/-/querystringify-2.0.0.tgz#fa3ed6e68eb15159457c89b37bc6472833195755"
 
-raf@3.4.0:
+raf@3.4.0, raf@^3.4.0:
   version "3.4.0"
   resolved "https://registry.yarnpkg.com/raf/-/raf-3.4.0.tgz#a28876881b4bc2ca9117d4138163ddb80f781575"
   dependencies:
@@ -5814,6 +6008,17 @@ rafl@~1.2.1:
   dependencies:
     global "~4.3.0"
 
+railroad-diagrams@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/railroad-diagrams/-/railroad-diagrams-1.0.0.tgz#eb7e6267548ddedfb899c1b90e57374559cddb7e"
+
+randexp@0.4.6:
+  version "0.4.6"
+  resolved "https://registry.yarnpkg.com/randexp/-/randexp-0.4.6.tgz#e986ad5e5e31dae13ddd6f7b3019aa7c87f60ca3"
+  dependencies:
+    discontinuous-range "1.0.0"
+    ret "~0.1.10"
+
 randomatic@^3.0.0:
   version "3.0.0"
   resolved "https://registry.yarnpkg.com/randomatic/-/randomatic-3.0.0.tgz#d35490030eb4f7578de292ce6dfb04a91a128923"
@@ -5901,6 +6106,10 @@ react-event-listener@^0.6.0:
     prop-types "^15.6.0"
     warning "^3.0.0"
 
+react-is@^16.4.0:
+  version "16.4.0"
+  resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.4.0.tgz#cc9fdc855ac34d2e7d9d2eb7059bbc240d35ffcf"
+
 react-jss@^8.1.0:
   version "8.4.0"
   resolved "https://registry.yarnpkg.com/react-jss/-/react-jss-8.4.0.tgz#7cb43d85dea56afafc8f0fd072ae27fcc0518950"
@@ -5922,6 +6131,15 @@ react-popper@^0.10.0:
     popper.js "^1.14.1"
     prop-types "^15.6.1"
 
+react-reconciler@^0.7.0:
+  version "0.7.0"
+  resolved "https://registry.yarnpkg.com/react-reconciler/-/react-reconciler-0.7.0.tgz#9614894103e5f138deeeb5eabaf3ee80eb1d026d"
+  dependencies:
+    fbjs "^0.8.16"
+    loose-envify "^1.1.0"
+    object-assign "^4.1.1"
+    prop-types "^15.6.0"
+
 react-redux@5.0.7:
   version "5.0.7"
   resolved "https://registry.yarnpkg.com/react-redux/-/react-redux-5.0.7.tgz#0dc1076d9afb4670f993ffaef44b8f8c1155a4c8"
@@ -6008,6 +6226,24 @@ react-scripts-ts@2.16.0:
   optionalDependencies:
     fsevents "^1.1.3"
 
+react-scrollbar-size@^2.0.2:
+  version "2.1.0"
+  resolved "https://registry.yarnpkg.com/react-scrollbar-size/-/react-scrollbar-size-2.1.0.tgz#105e797135cab92b1f9e16f00071db7f29f80754"
+  dependencies:
+    babel-runtime "^6.26.0"
+    prop-types "^15.6.0"
+    react-event-listener "^0.5.1"
+    stifle "^1.0.2"
+
+react-test-renderer@^16.0.0-0:
+  version "16.4.0"
+  resolved "https://registry.yarnpkg.com/react-test-renderer/-/react-test-renderer-16.4.0.tgz#0dbe0e24263e94e1830c7afb1f403707fad313a3"
+  dependencies:
+    fbjs "^0.8.16"
+    object-assign "^4.1.1"
+    prop-types "^15.6.0"
+    react-is "^16.4.0"
+
 react-transition-group@^2.2.1:
   version "2.3.1"
   resolved "https://registry.yarnpkg.com/react-transition-group/-/react-transition-group-2.3.1.tgz#31d611b33e143a5e0f2d94c348e026a0f3b474b6"
@@ -6390,6 +6626,13 @@ ripemd160@^2.0.0, ripemd160@^2.0.1:
     hash-base "^3.0.0"
     inherits "^2.0.1"
 
+rst-selector-parser@^2.2.3:
+  version "2.2.3"
+  resolved "https://registry.yarnpkg.com/rst-selector-parser/-/rst-selector-parser-2.2.3.tgz#81b230ea2fcc6066c89e3472de794285d9b03d91"
+  dependencies:
+    lodash.flattendeep "^4.4.0"
+    nearley "^2.7.10"
+
 rsvp@^3.3.3:
   version "3.6.2"
   resolved "https://registry.yarnpkg.com/rsvp/-/rsvp-3.6.2.tgz#2e96491599a96cde1b515d5674a8f7a91452926a"
@@ -7319,6 +7562,10 @@ uglifyjs-webpack-plugin@^1.1.8:
     webpack-sources "^1.1.0"
     worker-farm "^1.5.2"
 
+underscore@~1.4.4:
+  version "1.4.4"
+  resolved "https://registry.yarnpkg.com/underscore/-/underscore-1.4.4.tgz#61a6a32010622afa07963bf325203cf12239d604"
+
 union-value@^1.0.0:
   version "1.0.0"
   resolved "https://registry.yarnpkg.com/union-value/-/union-value-1.0.0.tgz#5c71c34cb5bad5dcebe3ea0cd08207ba5aa1aea4"