mirror of
				https://github.com/Unleash/unleash.git
				synced 2025-10-27 11:02:16 +01:00 
			
		
		
		
	Merge branch 'master' into greenkeeper/style-loader-0.22.0
This commit is contained in:
		
						commit
						505c1d59ae
					
				@ -15,5 +15,11 @@
 | 
			
		||||
                "printWidth": 120
 | 
			
		||||
            }
 | 
			
		||||
        ]
 | 
			
		||||
    },
 | 
			
		||||
    "overrides": [
 | 
			
		||||
        {
 | 
			
		||||
            "files": ["**/__tests__/*"],
 | 
			
		||||
            "env": { "jest": true }
 | 
			
		||||
        }
 | 
			
		||||
    ]
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -10,6 +10,9 @@ The latest version of this document is always available in
 | 
			
		||||
 | 
			
		||||
## [Unrelesed]
 | 
			
		||||
 | 
			
		||||
## [3.1.0]
 | 
			
		||||
- fix(react-router): Upgrade to react-router v4.
 | 
			
		||||
 | 
			
		||||
## [3.0.1]
 | 
			
		||||
- fix(feature): Create feature form inside a Card to align UI
 | 
			
		||||
- feat(archive): Improve archive view, UI, search, toggle details
 | 
			
		||||
 | 
			
		||||
@ -50,8 +50,7 @@
 | 
			
		||||
    "react-mdl": "^1.11.0",
 | 
			
		||||
    "react-modal": "^3.1.13",
 | 
			
		||||
    "react-redux": "^5.0.6",
 | 
			
		||||
    "react-router": "^3.0.0",
 | 
			
		||||
    "react-router-scroll": "^0.4.1",
 | 
			
		||||
    "react-router-dom": "^4.3.1",
 | 
			
		||||
    "redux": "^3.6.0",
 | 
			
		||||
    "redux-thunk": "^2.1.0",
 | 
			
		||||
    "whatwg-fetch": "^2.0.0"
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										3
									
								
								frontend/src/__mocks__/react-mdl.js
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										3
									
								
								frontend/src/__mocks__/react-mdl.js
									
									
									
									
										vendored
									
									
								
							@ -5,6 +5,7 @@ module.exports = {
 | 
			
		||||
    CardText: 'react-mdl-CardText',
 | 
			
		||||
    CardMenu: 'react-mdl-CardMenu',
 | 
			
		||||
    DataTable: 'react-mdl-DataTable',
 | 
			
		||||
    Drawer: 'react-mdl-Drawer',
 | 
			
		||||
    Cell: 'react-mdl-Cell',
 | 
			
		||||
    Chip: 'react-mdl-Chip',
 | 
			
		||||
    Grid: 'react-mdl-Grid',
 | 
			
		||||
@ -16,12 +17,14 @@ module.exports = {
 | 
			
		||||
    ListItemAction: 'react-mdl-ListItemAction',
 | 
			
		||||
    Menu: 'react-mdl-Menu',
 | 
			
		||||
    MenuItem: 'react-mdl-MenuItem',
 | 
			
		||||
    Navigation: 'react-mdl-Navigation',
 | 
			
		||||
    ProgressBar: 'react-mdl-ProgressBar',
 | 
			
		||||
    Switch: 'react-mdl-Switch',
 | 
			
		||||
    Tab: 'react-mdl-Tab',
 | 
			
		||||
    Tabs: 'react-mdl-Tabs',
 | 
			
		||||
    TableHeader: 'react-mdl-TableHeader',
 | 
			
		||||
    Textfield: 'react-mdl-Textfield',
 | 
			
		||||
    FooterDropDownSection: 'react-mdl-FooterDropDownSection',
 | 
			
		||||
    FooterSection: 'react-mdl-FooterSection',
 | 
			
		||||
    FooterLinkList: 'react-mdl-FooterLinkList',
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
@ -1,5 +0,0 @@
 | 
			
		||||
{
 | 
			
		||||
    "env": {
 | 
			
		||||
        "jest": true
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -1,5 +0,0 @@
 | 
			
		||||
{
 | 
			
		||||
    "env": {
 | 
			
		||||
        "jest": true
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -1,43 +1,23 @@
 | 
			
		||||
import React, { Component } from 'react';
 | 
			
		||||
import PropTypes from 'prop-types';
 | 
			
		||||
import {
 | 
			
		||||
    Layout,
 | 
			
		||||
    Drawer,
 | 
			
		||||
    Header,
 | 
			
		||||
    Navigation,
 | 
			
		||||
    Content,
 | 
			
		||||
    Footer,
 | 
			
		||||
    FooterSection,
 | 
			
		||||
    FooterDropDownSection,
 | 
			
		||||
    FooterLinkList,
 | 
			
		||||
    Grid,
 | 
			
		||||
    Cell,
 | 
			
		||||
    Icon,
 | 
			
		||||
} from 'react-mdl';
 | 
			
		||||
import { Link } from 'react-router';
 | 
			
		||||
import { Layout, Header, Navigation, Content, Footer, Grid, Cell } from 'react-mdl';
 | 
			
		||||
import { Route, Redirect, Switch } from 'react-router-dom';
 | 
			
		||||
import styles from './styles.scss';
 | 
			
		||||
import ErrorContainer from './error/error-container';
 | 
			
		||||
 | 
			
		||||
import AuthenticationContainer from './user/authentication-container';
 | 
			
		||||
import ShowUserContainer from './user/show-user-container';
 | 
			
		||||
import ShowApiDetailsContainer from './api/show-api-details-container';
 | 
			
		||||
import { ScrollContainer } from 'react-router-scroll';
 | 
			
		||||
 | 
			
		||||
function replace(input, params) {
 | 
			
		||||
    if (!params) {
 | 
			
		||||
        return input;
 | 
			
		||||
    }
 | 
			
		||||
    Object.keys(params).forEach(key => {
 | 
			
		||||
        input = input.replace(`:${key}`, params[key]);
 | 
			
		||||
    });
 | 
			
		||||
    return input;
 | 
			
		||||
}
 | 
			
		||||
import Features from '../page/features';
 | 
			
		||||
import { DrawerMenu } from './menu/drawer';
 | 
			
		||||
import { FooterMenu } from './menu/footer';
 | 
			
		||||
import Breadcrum from './menu/breadcrumb';
 | 
			
		||||
import { routes } from './menu/routes';
 | 
			
		||||
 | 
			
		||||
export default class App extends Component {
 | 
			
		||||
    static propTypes = {
 | 
			
		||||
        location: PropTypes.object.isRequired,
 | 
			
		||||
        params: PropTypes.object.isRequired,
 | 
			
		||||
        routes: PropTypes.array.isRequired,
 | 
			
		||||
        match: PropTypes.object.isRequired,
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    static contextTypes = {
 | 
			
		||||
@ -58,152 +38,38 @@ export default class App extends Component {
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    getSections() {
 | 
			
		||||
        const { routes, params } = this.props;
 | 
			
		||||
        const unique = {};
 | 
			
		||||
        const result = routes
 | 
			
		||||
            .splice(1)
 | 
			
		||||
            .map(routeEntry => ({
 | 
			
		||||
                name: replace(routeEntry.pageTitle, params),
 | 
			
		||||
                link: replace(routeEntry.link || routeEntry.path, params),
 | 
			
		||||
            }))
 | 
			
		||||
            .filter(entry => {
 | 
			
		||||
                if (!unique[entry.link]) {
 | 
			
		||||
                    unique[entry.link] = true;
 | 
			
		||||
                    return true;
 | 
			
		||||
                }
 | 
			
		||||
                return false;
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
        // mutate document.title:
 | 
			
		||||
        document.title = result
 | 
			
		||||
            .map(e => e.name)
 | 
			
		||||
            .reverse()
 | 
			
		||||
            .concat('Unleash')
 | 
			
		||||
            .join(' – ');
 | 
			
		||||
 | 
			
		||||
        return result;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    getTitleWithLinks() {
 | 
			
		||||
        const result = this.getSections();
 | 
			
		||||
        return (
 | 
			
		||||
            <span>
 | 
			
		||||
                {result.map((entry, index) => (
 | 
			
		||||
                    <span key={entry.link + index} className={index > 0 ? 'mdl-layout--large-screen-only' : ''}>
 | 
			
		||||
                        {index > 0 ? ' › ' : null}
 | 
			
		||||
                        <Link
 | 
			
		||||
                            className={[styles.headerTitleLink, 'mdl-color-text--primary-contrast'].join(' ')}
 | 
			
		||||
                            to={entry.link}
 | 
			
		||||
                        >
 | 
			
		||||
                            {entry.name}
 | 
			
		||||
                        </Link>
 | 
			
		||||
                    </span>
 | 
			
		||||
                ))}
 | 
			
		||||
            </span>
 | 
			
		||||
        );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    render() {
 | 
			
		||||
        const shouldUpdateScroll = (prevRouterProps, { location }) => {
 | 
			
		||||
            if (prevRouterProps && location.pathname !== prevRouterProps.location.pathname) {
 | 
			
		||||
                return location.action === 'POP';
 | 
			
		||||
            } else {
 | 
			
		||||
                return [0, 0];
 | 
			
		||||
            }
 | 
			
		||||
        };
 | 
			
		||||
        const createListItem = (path, caption, icon, isDrawerNavigation = false) => {
 | 
			
		||||
            const linkColor =
 | 
			
		||||
                isDrawerNavigation && this.context.router.isActive(path)
 | 
			
		||||
                    ? 'mdl-color-text--black'
 | 
			
		||||
                    : 'mdl-color-text--grey-900';
 | 
			
		||||
            const iconColor =
 | 
			
		||||
                isDrawerNavigation && this.context.router.isActive(path)
 | 
			
		||||
                    ? 'mdl-color-text--black'
 | 
			
		||||
                    : 'mdl-color-text--grey-600';
 | 
			
		||||
            const renderIcon = (
 | 
			
		||||
                <Icon
 | 
			
		||||
                    name={icon}
 | 
			
		||||
                    className={isDrawerNavigation ? [styles.navigationIcon, iconColor].join(' ') : undefined}
 | 
			
		||||
                />
 | 
			
		||||
            );
 | 
			
		||||
            return (
 | 
			
		||||
                <Link
 | 
			
		||||
                    to={path}
 | 
			
		||||
                    className={isDrawerNavigation ? [styles.navigationLink, linkColor].join(' ') : undefined}
 | 
			
		||||
                >
 | 
			
		||||
                    {icon && renderIcon}
 | 
			
		||||
                    {caption}
 | 
			
		||||
                </Link>
 | 
			
		||||
            );
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        return (
 | 
			
		||||
            <div className={styles.container}>
 | 
			
		||||
                <AuthenticationContainer />
 | 
			
		||||
                <Layout fixedHeader>
 | 
			
		||||
                    <Header title={this.getTitleWithLinks()}>
 | 
			
		||||
                    <Header title={<Route path="/:path" component={Breadcrum} />}>
 | 
			
		||||
                        <Navigation>
 | 
			
		||||
                            <ShowUserContainer />
 | 
			
		||||
                        </Navigation>
 | 
			
		||||
                    </Header>
 | 
			
		||||
                    <Drawer className="mdl-color--white">
 | 
			
		||||
                        <span className={[styles.drawerTitle, 'mdl-layout-title'].join(' ')}>
 | 
			
		||||
                            <img src="public/logo.png" width="32" height="32" className={styles.drawerTitleLogo} />
 | 
			
		||||
                            <span className={styles.drawerTitleText}>Unleash</span>
 | 
			
		||||
                        </span>
 | 
			
		||||
                        <hr />
 | 
			
		||||
                        <Navigation className={styles.navigation}>
 | 
			
		||||
                            {createListItem('/features', 'Feature Toggles', 'list', true)}
 | 
			
		||||
                            {createListItem('/strategies', 'Strategies', 'extension', true)}
 | 
			
		||||
                            {createListItem('/history', 'Event History', 'history', true)}
 | 
			
		||||
                            {createListItem('/archive', 'Archived Toggles', 'archive', true)}
 | 
			
		||||
                            {createListItem('/applications', 'Applications', 'apps', true)}
 | 
			
		||||
                            {createListItem('logout', 'Sign out', 'exit_to_app', true)}
 | 
			
		||||
                        </Navigation>
 | 
			
		||||
                        <hr />
 | 
			
		||||
                        <Navigation className={styles.navigation}>
 | 
			
		||||
                            <a
 | 
			
		||||
                                href="https://github.com/Unleash"
 | 
			
		||||
                                target="_blank"
 | 
			
		||||
                                className={[styles.navigationLink, 'mdl-color-text--grey-900'].join(' ')}
 | 
			
		||||
                            >
 | 
			
		||||
                                <i className={['material-icons', styles.navigationIcon, styles.iconGitHub].join(' ')} />GitHub
 | 
			
		||||
                            </a>
 | 
			
		||||
                        </Navigation>
 | 
			
		||||
                    </Drawer>
 | 
			
		||||
                    <ScrollContainer scrollKey="container" shouldUpdateScroll={shouldUpdateScroll}>
 | 
			
		||||
                    <DrawerMenu />
 | 
			
		||||
                    <Content className="mdl-color--grey-50">
 | 
			
		||||
                        <Grid noSpacing className={styles.content}>
 | 
			
		||||
                            <Cell col={12}>
 | 
			
		||||
                                    {this.props.children}
 | 
			
		||||
                                <Switch>
 | 
			
		||||
                                    <Route
 | 
			
		||||
                                        exact
 | 
			
		||||
                                        path="/"
 | 
			
		||||
                                        render={() => <Redirect to="/features" component={Features} />}
 | 
			
		||||
                                    />
 | 
			
		||||
                                    {routes.map(route => (
 | 
			
		||||
                                        <Route key={route.path} path={route.path} component={route.component} />
 | 
			
		||||
                                    ))}
 | 
			
		||||
                                </Switch>
 | 
			
		||||
                                <ErrorContainer />
 | 
			
		||||
                            </Cell>
 | 
			
		||||
                        </Grid>
 | 
			
		||||
                        <Footer size="mega">
 | 
			
		||||
                                <FooterSection type="middle">
 | 
			
		||||
                                    <FooterDropDownSection title="Menu">
 | 
			
		||||
                                        <FooterLinkList>
 | 
			
		||||
                                            {createListItem('/features', 'Feature Toggles', '')}
 | 
			
		||||
                                            {createListItem('/strategies', 'Strategies', '')}
 | 
			
		||||
                                            {createListItem('/history', 'Event History', '')}
 | 
			
		||||
                                            {createListItem('/archive', 'Archived Toggles', '')}
 | 
			
		||||
                                            {createListItem('/applications', 'Applications', '')}
 | 
			
		||||
                                            {createListItem('/logout', 'Sign out', '')}
 | 
			
		||||
                                        </FooterLinkList>
 | 
			
		||||
                                    </FooterDropDownSection>
 | 
			
		||||
                                    <FooterDropDownSection title="Clients">
 | 
			
		||||
                                        <FooterLinkList>
 | 
			
		||||
                                            <a href="https://github.com/Unleash/unleash-client-node/">Node.js</a>
 | 
			
		||||
                                            <a href="https://github.com/Unleash/unleash-client-java/">Java</a>
 | 
			
		||||
                                            <a href="https://github.com/Unleash/unleash-client-go/">Go</a>
 | 
			
		||||
                                        </FooterLinkList>
 | 
			
		||||
                                    </FooterDropDownSection>
 | 
			
		||||
                                </FooterSection>
 | 
			
		||||
                            <FooterMenu />
 | 
			
		||||
                            <ShowApiDetailsContainer />
 | 
			
		||||
                        </Footer>
 | 
			
		||||
                    </Content>
 | 
			
		||||
                    </ScrollContainer>
 | 
			
		||||
                </Layout>
 | 
			
		||||
            </div>
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
@ -1,5 +0,0 @@
 | 
			
		||||
{
 | 
			
		||||
    "env": {
 | 
			
		||||
        "jest": true
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -2,7 +2,7 @@
 | 
			
		||||
import React, { Component, PureComponent } from 'react';
 | 
			
		||||
import PropTypes from 'prop-types';
 | 
			
		||||
 | 
			
		||||
import { Link } from 'react-router';
 | 
			
		||||
import { Link } from 'react-router-dom';
 | 
			
		||||
import {
 | 
			
		||||
    Grid,
 | 
			
		||||
    Cell,
 | 
			
		||||
 | 
			
		||||
@ -1,5 +0,0 @@
 | 
			
		||||
{
 | 
			
		||||
    "env": {
 | 
			
		||||
        "jest": true
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -1,5 +0,0 @@
 | 
			
		||||
{
 | 
			
		||||
    "env": {
 | 
			
		||||
        "jest": true
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -1,6 +1,6 @@
 | 
			
		||||
import React from 'react';
 | 
			
		||||
import PropTypes from 'prop-types';
 | 
			
		||||
import { Link } from 'react-router';
 | 
			
		||||
import { Link } from 'react-router-dom';
 | 
			
		||||
import { List, ListItem, ListItemContent, Button, Icon, Switch, MenuItem } from 'react-mdl';
 | 
			
		||||
import styles from './common.scss';
 | 
			
		||||
 | 
			
		||||
@ -11,10 +11,10 @@ export const shorten = (str, len = 50) => (str && str.length > len ? `${str.subs
 | 
			
		||||
export const AppsLinkList = ({ apps }) => (
 | 
			
		||||
    <List>
 | 
			
		||||
        {apps.length > 0 &&
 | 
			
		||||
            apps.map(({ appName, description = '-', icon = 'apps' }) => (
 | 
			
		||||
            apps.map(({ appName, description = '-', icon }) => (
 | 
			
		||||
                <ListItem twoLine key={appName}>
 | 
			
		||||
                    <span className="mdl-list__item-primary-content" style={{ minWidth: 0 }}>
 | 
			
		||||
                        <Icon name={icon} className="mdl-list__item-avatar" />
 | 
			
		||||
                        <Icon name={icon || 'apps'} className="mdl-list__item-avatar" />
 | 
			
		||||
                        <Link to={`/applications/${appName}`} className={[styles.listLink, styles.truncate].join(' ')}>
 | 
			
		||||
                            {appName}
 | 
			
		||||
                            <span className={['mdl-list__item-sub-title', styles.truncate].join(' ')}>
 | 
			
		||||
 | 
			
		||||
@ -1,5 +0,0 @@
 | 
			
		||||
{
 | 
			
		||||
    "env": {
 | 
			
		||||
        "jest": true
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -32,8 +32,8 @@ exports[`renders correctly with one feature 1`] = `
 | 
			
		||||
  >
 | 
			
		||||
    <a
 | 
			
		||||
      className="listLink truncate"
 | 
			
		||||
      href="/features/strategies/Another"
 | 
			
		||||
      onClick={[Function]}
 | 
			
		||||
      style={Object {}}
 | 
			
		||||
    >
 | 
			
		||||
      Another
 | 
			
		||||
      <span
 | 
			
		||||
 | 
			
		||||
@ -1,4 +1,5 @@
 | 
			
		||||
import React from 'react';
 | 
			
		||||
import { MemoryRouter } from 'react-router-dom';
 | 
			
		||||
 | 
			
		||||
import Feature from './../feature-list-item-component';
 | 
			
		||||
import renderer from 'react-test-renderer';
 | 
			
		||||
@ -23,6 +24,7 @@ test('renders correctly with one feature', () => {
 | 
			
		||||
    const featureMetrics = { lastHour: {}, lastMinute: {}, seenApps: {} };
 | 
			
		||||
    const settings = { sort: 'name' };
 | 
			
		||||
    const tree = renderer.create(
 | 
			
		||||
        <MemoryRouter>
 | 
			
		||||
            <Feature
 | 
			
		||||
                key={0}
 | 
			
		||||
                settings={settings}
 | 
			
		||||
@ -31,6 +33,7 @@ test('renders correctly with one feature', () => {
 | 
			
		||||
                feature={feature}
 | 
			
		||||
                toggleFeature={jest.fn()}
 | 
			
		||||
            />
 | 
			
		||||
        </MemoryRouter>
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    expect(tree).toMatchSnapshot();
 | 
			
		||||
 | 
			
		||||
@ -1,6 +1,6 @@
 | 
			
		||||
import React from 'react';
 | 
			
		||||
import PropTypes from 'prop-types';
 | 
			
		||||
import { Link } from 'react-router';
 | 
			
		||||
import { Link } from 'react-router-dom';
 | 
			
		||||
import { Switch, Chip, ListItem, ListItemAction, Icon } from 'react-mdl';
 | 
			
		||||
import Progress from './progress';
 | 
			
		||||
import { calc, styles as commonStyles } from '../common';
 | 
			
		||||
 | 
			
		||||
@ -1,5 +1,4 @@
 | 
			
		||||
import { connect } from 'react-redux';
 | 
			
		||||
import { hashHistory } from 'react-router';
 | 
			
		||||
import { createFeatureToggles, validateName } from './../../../store/feature-actions';
 | 
			
		||||
import { createMapper, createActions } from './../../input-helpers';
 | 
			
		||||
import AddFeatureComponent from './form-add-feature-component';
 | 
			
		||||
@ -17,7 +16,7 @@ const mapStateToProps = createMapper({
 | 
			
		||||
        return { name };
 | 
			
		||||
    },
 | 
			
		||||
});
 | 
			
		||||
const prepare = (methods, dispatch) => {
 | 
			
		||||
const prepare = (methods, dispatch, ownProps) => {
 | 
			
		||||
    methods.onSubmit = input => e => {
 | 
			
		||||
        e.preventDefault();
 | 
			
		||||
 | 
			
		||||
@ -31,13 +30,13 @@ const prepare = (methods, dispatch) => {
 | 
			
		||||
 | 
			
		||||
        createFeatureToggles(input)(dispatch)
 | 
			
		||||
            .then(() => methods.clear())
 | 
			
		||||
            .then(() => hashHistory.push(`/features/strategies/${input.name}`));
 | 
			
		||||
            .then(() => ownProps.history.push(`/features/strategies/${input.name}`));
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    methods.onCancel = evt => {
 | 
			
		||||
        evt.preventDefault();
 | 
			
		||||
        methods.clear();
 | 
			
		||||
        hashHistory.push('/features');
 | 
			
		||||
        ownProps.history.push('/features');
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    methods.addStrategy = v => {
 | 
			
		||||
 | 
			
		||||
@ -1,5 +1,4 @@
 | 
			
		||||
import { connect } from 'react-redux';
 | 
			
		||||
import { hashHistory } from 'react-router';
 | 
			
		||||
 | 
			
		||||
import { requestUpdateFeatureToggle } from '../../../store/feature-actions';
 | 
			
		||||
import { createMapper, createActions } from '../../input-helpers';
 | 
			
		||||
@ -25,7 +24,7 @@ const mapStateToProps = createMapper({
 | 
			
		||||
    },
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
const prepare = (methods, dispatch) => {
 | 
			
		||||
const prepare = (methods, dispatch, ownProps) => {
 | 
			
		||||
    methods.onSubmit = (input, features) => e => {
 | 
			
		||||
        e.preventDefault();
 | 
			
		||||
 | 
			
		||||
@ -42,13 +41,13 @@ const prepare = (methods, dispatch) => {
 | 
			
		||||
        // TODO: should add error handling
 | 
			
		||||
        requestUpdateFeatureToggle(input)(dispatch)
 | 
			
		||||
            .then(() => methods.clear())
 | 
			
		||||
            .then(() => hashHistory.push(`/features`));
 | 
			
		||||
            .then(() => ownProps.history.push(`/features`));
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    methods.onCancel = evt => {
 | 
			
		||||
        evt.preventDefault();
 | 
			
		||||
        methods.clear();
 | 
			
		||||
        hashHistory.push(`/features`);
 | 
			
		||||
        ownProps.history.push(`/features`);
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    methods.addStrategy = v => {
 | 
			
		||||
 | 
			
		||||
@ -1,7 +1,6 @@
 | 
			
		||||
import { connect } from 'react-redux';
 | 
			
		||||
import { createMapper, createActions } from '../../input-helpers';
 | 
			
		||||
import ViewFeatureToggleComponent from './form-view-feature-component';
 | 
			
		||||
import { hashHistory } from 'react-router';
 | 
			
		||||
 | 
			
		||||
const ID = 'view-feature-toggle';
 | 
			
		||||
function getId(props) {
 | 
			
		||||
@ -27,7 +26,7 @@ const prepare = methods => {
 | 
			
		||||
    methods.onCancel = evt => {
 | 
			
		||||
        evt.preventDefault();
 | 
			
		||||
        methods.clear();
 | 
			
		||||
        hashHistory.push(`/archive`);
 | 
			
		||||
        this.props.history.push(`/archive`);
 | 
			
		||||
    };
 | 
			
		||||
    return methods;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
@ -24,7 +24,7 @@ class StrategiesList extends React.Component {
 | 
			
		||||
        const blocks = configuredStrategies.map((strategy, i) => (
 | 
			
		||||
            <ConfigureStrategy
 | 
			
		||||
                index={i}
 | 
			
		||||
                key={strategy.id}
 | 
			
		||||
                key={`${strategy.id}-${i}`}
 | 
			
		||||
                strategy={strategy}
 | 
			
		||||
                moveStrategy={moveStrategy}
 | 
			
		||||
                removeStrategy={removeStrategy ? removeStrategy.bind(null, i) : null}
 | 
			
		||||
 | 
			
		||||
@ -2,7 +2,7 @@ import React from 'react';
 | 
			
		||||
import PropTypes from 'prop-types';
 | 
			
		||||
import { Textfield, Button, Card, CardTitle, CardText, CardActions, CardMenu, IconButton, Icon } from 'react-mdl';
 | 
			
		||||
import { DragSource, DropTarget } from 'react-dnd';
 | 
			
		||||
import { Link } from 'react-router';
 | 
			
		||||
import { Link } from 'react-router-dom';
 | 
			
		||||
import StrategyInputPercentage from './strategy-input-percentage';
 | 
			
		||||
import StrategyInputList from './strategy-input-list';
 | 
			
		||||
import styles from './strategy.scss';
 | 
			
		||||
 | 
			
		||||
@ -1,7 +1,7 @@
 | 
			
		||||
import React from 'react';
 | 
			
		||||
import PropTypes from 'prop-types';
 | 
			
		||||
import Feature from './feature-list-item-component';
 | 
			
		||||
import { hashHistory, Link } from 'react-router';
 | 
			
		||||
import { Link } from 'react-router-dom';
 | 
			
		||||
import { Icon, FABButton, Textfield, Menu, MenuItem, Card, CardActions, List } from 'react-mdl';
 | 
			
		||||
import { MenuItemWithIcon, DropdownButton, styles as commonStyles } from '../common';
 | 
			
		||||
import styles from './feature.scss';
 | 
			
		||||
@ -18,6 +18,7 @@ export default class FeatureListComponent extends React.Component {
 | 
			
		||||
        updateSetting: PropTypes.func.isRequired,
 | 
			
		||||
        toggleFeature: PropTypes.func,
 | 
			
		||||
        settings: PropTypes.object,
 | 
			
		||||
        history: PropTypes.object.isRequired,
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    static contextTypes = {
 | 
			
		||||
@ -27,7 +28,7 @@ export default class FeatureListComponent extends React.Component {
 | 
			
		||||
    componentDidMount() {
 | 
			
		||||
        if (this.props.logout) {
 | 
			
		||||
            this.props.logoutUser();
 | 
			
		||||
            hashHistory.push(`/`);
 | 
			
		||||
            this.props.history.push(`/`);
 | 
			
		||||
        }
 | 
			
		||||
        if (this.props.fetchFeatureToggles) {
 | 
			
		||||
            this.props.fetchFeatureToggles();
 | 
			
		||||
 | 
			
		||||
@ -2,7 +2,7 @@ import React from 'react';
 | 
			
		||||
import PropTypes from 'prop-types';
 | 
			
		||||
import { Grid, Cell, Icon, Chip, ChipContact } from 'react-mdl';
 | 
			
		||||
import Progress from './progress';
 | 
			
		||||
import { Link } from 'react-router';
 | 
			
		||||
import { Link } from 'react-router-dom';
 | 
			
		||||
import { AppsLinkList, calc } from '../common';
 | 
			
		||||
import { formatFullDateTimeWithLocale } from '../common/util';
 | 
			
		||||
import styles from './metrics.scss';
 | 
			
		||||
 | 
			
		||||
@ -1,7 +1,7 @@
 | 
			
		||||
import React from 'react';
 | 
			
		||||
import PropTypes from 'prop-types';
 | 
			
		||||
import { Tabs, Tab, ProgressBar, Button, Card, CardText, CardTitle, CardActions, Textfield, Switch } from 'react-mdl';
 | 
			
		||||
import { hashHistory, Link } from 'react-router';
 | 
			
		||||
import { Link } from 'react-router-dom';
 | 
			
		||||
 | 
			
		||||
import HistoryComponent from '../history/history-list-toggle-container';
 | 
			
		||||
import MetricComponent from './metric-container';
 | 
			
		||||
@ -33,6 +33,7 @@ export default class ViewFeatureToggleComponent extends React.Component {
 | 
			
		||||
        fetchFeatureToggles: PropTypes.func,
 | 
			
		||||
        editFeatureToggle: PropTypes.func,
 | 
			
		||||
        featureToggle: PropTypes.object,
 | 
			
		||||
        history: PropTypes.object.isRequired,
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    componentWillMount() {
 | 
			
		||||
@ -52,7 +53,9 @@ export default class ViewFeatureToggleComponent extends React.Component {
 | 
			
		||||
            return <HistoryComponent toggleName={featureToggleName} />;
 | 
			
		||||
        } else if (TABS[activeTab] === TABS.strategies) {
 | 
			
		||||
            if (this.isFeatureView) {
 | 
			
		||||
                return <EditFeatureToggle featureToggle={featureToggle} features={features} />;
 | 
			
		||||
                return (
 | 
			
		||||
                    <EditFeatureToggle featureToggle={featureToggle} features={features} history={this.props.history} />
 | 
			
		||||
                );
 | 
			
		||||
            }
 | 
			
		||||
            return <ViewFeatureToggle featureToggle={featureToggle} />;
 | 
			
		||||
        } else {
 | 
			
		||||
@ -62,7 +65,7 @@ export default class ViewFeatureToggleComponent extends React.Component {
 | 
			
		||||
 | 
			
		||||
    goToTab(tabName, featureToggleName) {
 | 
			
		||||
        let view = this.props.fetchFeatureToggles ? 'features' : 'archive';
 | 
			
		||||
        hashHistory.push(`/${view}/${tabName}/${featureToggleName}`);
 | 
			
		||||
        this.props.history.push(`/${view}/${tabName}/${featureToggleName}`);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    render() {
 | 
			
		||||
@ -105,12 +108,12 @@ export default class ViewFeatureToggleComponent extends React.Component {
 | 
			
		||||
                window.confirm('Are you sure you want to remove this toggle?')
 | 
			
		||||
            ) {
 | 
			
		||||
                removeFeatureToggle(featureToggle.name);
 | 
			
		||||
                hashHistory.push('/features');
 | 
			
		||||
                this.props.history.push('/features');
 | 
			
		||||
            }
 | 
			
		||||
        };
 | 
			
		||||
        const reviveToggle = () => {
 | 
			
		||||
            revive(featureToggle.name);
 | 
			
		||||
            hashHistory.push('/features');
 | 
			
		||||
            this.props.history.push('/features');
 | 
			
		||||
        };
 | 
			
		||||
        const updateFeatureToggle = () => {
 | 
			
		||||
            let feature = { ...featureToggle };
 | 
			
		||||
 | 
			
		||||
@ -0,0 +1,49 @@
 | 
			
		||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
 | 
			
		||||
 | 
			
		||||
exports[`breadcrumb for /features 1`] = `
 | 
			
		||||
<span
 | 
			
		||||
  className="mdl-layout--large-screen-only"
 | 
			
		||||
>
 | 
			
		||||
  <span
 | 
			
		||||
    className="headerTitleLink mdl-color-text--primary-contrast"
 | 
			
		||||
  >
 | 
			
		||||
    Feature Toggles
 | 
			
		||||
  </span>
 | 
			
		||||
</span>
 | 
			
		||||
`;
 | 
			
		||||
 | 
			
		||||
exports[`breadcrumb for /features/view/Demo 1`] = `
 | 
			
		||||
<span>
 | 
			
		||||
  <a
 | 
			
		||||
    className="headerTitleLink mdl-color-text--primary-contrast"
 | 
			
		||||
    href="/features"
 | 
			
		||||
    onClick={[Function]}
 | 
			
		||||
  >
 | 
			
		||||
    Feature Toggles
 | 
			
		||||
  </a>
 | 
			
		||||
  <span
 | 
			
		||||
    className="mdl-layout--large-screen-only"
 | 
			
		||||
  >
 | 
			
		||||
    <span>
 | 
			
		||||
       › 
 | 
			
		||||
    </span>
 | 
			
		||||
    <span
 | 
			
		||||
      className="headerTitleLink mdl-color-text--primary-contrast"
 | 
			
		||||
    >
 | 
			
		||||
      Demo
 | 
			
		||||
    </span>
 | 
			
		||||
  </span>
 | 
			
		||||
</span>
 | 
			
		||||
`;
 | 
			
		||||
 | 
			
		||||
exports[`breadcrumb for /strategies 1`] = `
 | 
			
		||||
<span
 | 
			
		||||
  className="mdl-layout--large-screen-only"
 | 
			
		||||
>
 | 
			
		||||
  <span
 | 
			
		||||
    className="headerTitleLink mdl-color-text--primary-contrast"
 | 
			
		||||
  >
 | 
			
		||||
    Strategies
 | 
			
		||||
  </span>
 | 
			
		||||
</span>
 | 
			
		||||
`;
 | 
			
		||||
@ -0,0 +1,253 @@
 | 
			
		||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
 | 
			
		||||
 | 
			
		||||
exports[`should render DrawerMenu 1`] = `
 | 
			
		||||
<react-mdl-Drawer
 | 
			
		||||
  className="mdl-color--white"
 | 
			
		||||
>
 | 
			
		||||
  <span
 | 
			
		||||
    className="drawerTitle mdl-layout-title"
 | 
			
		||||
  >
 | 
			
		||||
    <img
 | 
			
		||||
      className="drawerTitleLogo"
 | 
			
		||||
      height="32"
 | 
			
		||||
      src="public/logo.png"
 | 
			
		||||
      width="32"
 | 
			
		||||
    />
 | 
			
		||||
    <span
 | 
			
		||||
      className="drawerTitleText"
 | 
			
		||||
    >
 | 
			
		||||
      Unleash
 | 
			
		||||
    </span>
 | 
			
		||||
  </span>
 | 
			
		||||
  <hr />
 | 
			
		||||
  <react-mdl-Navigation
 | 
			
		||||
    className="navigation"
 | 
			
		||||
  >
 | 
			
		||||
    <a
 | 
			
		||||
      aria-current={null}
 | 
			
		||||
      className="navigationLink mdl-color-text--grey-600"
 | 
			
		||||
      href="/features"
 | 
			
		||||
      onClick={[Function]}
 | 
			
		||||
      style={undefined}
 | 
			
		||||
    >
 | 
			
		||||
      <react-mdl-Icon
 | 
			
		||||
        className="navigationIcon"
 | 
			
		||||
        name="list"
 | 
			
		||||
      />
 | 
			
		||||
       
 | 
			
		||||
      Feature Toggles
 | 
			
		||||
    </a>
 | 
			
		||||
    <a
 | 
			
		||||
      aria-current={null}
 | 
			
		||||
      className="navigationLink mdl-color-text--grey-600"
 | 
			
		||||
      href="/strategies"
 | 
			
		||||
      onClick={[Function]}
 | 
			
		||||
      style={undefined}
 | 
			
		||||
    >
 | 
			
		||||
      <react-mdl-Icon
 | 
			
		||||
        className="navigationIcon"
 | 
			
		||||
        name="extension"
 | 
			
		||||
      />
 | 
			
		||||
       
 | 
			
		||||
      Strategies
 | 
			
		||||
    </a>
 | 
			
		||||
    <a
 | 
			
		||||
      aria-current={null}
 | 
			
		||||
      className="navigationLink mdl-color-text--grey-600"
 | 
			
		||||
      href="/history"
 | 
			
		||||
      onClick={[Function]}
 | 
			
		||||
      style={undefined}
 | 
			
		||||
    >
 | 
			
		||||
      <react-mdl-Icon
 | 
			
		||||
        className="navigationIcon"
 | 
			
		||||
        name="history"
 | 
			
		||||
      />
 | 
			
		||||
       
 | 
			
		||||
      Event History
 | 
			
		||||
    </a>
 | 
			
		||||
    <a
 | 
			
		||||
      aria-current={null}
 | 
			
		||||
      className="navigationLink mdl-color-text--grey-600"
 | 
			
		||||
      href="/archive"
 | 
			
		||||
      onClick={[Function]}
 | 
			
		||||
      style={undefined}
 | 
			
		||||
    >
 | 
			
		||||
      <react-mdl-Icon
 | 
			
		||||
        className="navigationIcon"
 | 
			
		||||
        name="archive"
 | 
			
		||||
      />
 | 
			
		||||
       
 | 
			
		||||
      Archived Toggles
 | 
			
		||||
    </a>
 | 
			
		||||
    <a
 | 
			
		||||
      aria-current={null}
 | 
			
		||||
      className="navigationLink mdl-color-text--grey-600"
 | 
			
		||||
      href="/applications"
 | 
			
		||||
      onClick={[Function]}
 | 
			
		||||
      style={undefined}
 | 
			
		||||
    >
 | 
			
		||||
      <react-mdl-Icon
 | 
			
		||||
        className="navigationIcon"
 | 
			
		||||
        name="apps"
 | 
			
		||||
      />
 | 
			
		||||
       
 | 
			
		||||
      Applications
 | 
			
		||||
    </a>
 | 
			
		||||
    <a
 | 
			
		||||
      aria-current={null}
 | 
			
		||||
      className="navigationLink mdl-color-text--grey-600"
 | 
			
		||||
      href="/logout"
 | 
			
		||||
      onClick={[Function]}
 | 
			
		||||
      style={undefined}
 | 
			
		||||
    >
 | 
			
		||||
      <react-mdl-Icon
 | 
			
		||||
        className="navigationIcon"
 | 
			
		||||
        name="exit_to_app"
 | 
			
		||||
      />
 | 
			
		||||
       
 | 
			
		||||
      Sign out
 | 
			
		||||
    </a>
 | 
			
		||||
  </react-mdl-Navigation>
 | 
			
		||||
  <hr />
 | 
			
		||||
  <react-mdl-Navigation
 | 
			
		||||
    className="navigation"
 | 
			
		||||
  >
 | 
			
		||||
    <a
 | 
			
		||||
      className="navigationLink mdl-color-text--grey-900"
 | 
			
		||||
      href="https://github.com/Unleash"
 | 
			
		||||
      target="_blank"
 | 
			
		||||
    >
 | 
			
		||||
      <i
 | 
			
		||||
        className="material-icons navigationIcon iconGitHub"
 | 
			
		||||
      />
 | 
			
		||||
      GitHub
 | 
			
		||||
    </a>
 | 
			
		||||
  </react-mdl-Navigation>
 | 
			
		||||
</react-mdl-Drawer>
 | 
			
		||||
`;
 | 
			
		||||
 | 
			
		||||
exports[`should render DrawerMenu with "features" selected 1`] = `
 | 
			
		||||
<react-mdl-Drawer
 | 
			
		||||
  className="mdl-color--white"
 | 
			
		||||
>
 | 
			
		||||
  <span
 | 
			
		||||
    className="drawerTitle mdl-layout-title"
 | 
			
		||||
  >
 | 
			
		||||
    <img
 | 
			
		||||
      className="drawerTitleLogo"
 | 
			
		||||
      height="32"
 | 
			
		||||
      src="public/logo.png"
 | 
			
		||||
      width="32"
 | 
			
		||||
    />
 | 
			
		||||
    <span
 | 
			
		||||
      className="drawerTitleText"
 | 
			
		||||
    >
 | 
			
		||||
      Unleash
 | 
			
		||||
    </span>
 | 
			
		||||
  </span>
 | 
			
		||||
  <hr />
 | 
			
		||||
  <react-mdl-Navigation
 | 
			
		||||
    className="navigation"
 | 
			
		||||
  >
 | 
			
		||||
    <a
 | 
			
		||||
      aria-current="page"
 | 
			
		||||
      className="navigationLink mdl-color-text--grey-600 navigationLink mdl-color-text--black"
 | 
			
		||||
      href="/features"
 | 
			
		||||
      onClick={[Function]}
 | 
			
		||||
      style={Object {}}
 | 
			
		||||
    >
 | 
			
		||||
      <react-mdl-Icon
 | 
			
		||||
        className="navigationIcon"
 | 
			
		||||
        name="list"
 | 
			
		||||
      />
 | 
			
		||||
       
 | 
			
		||||
      Feature Toggles
 | 
			
		||||
    </a>
 | 
			
		||||
    <a
 | 
			
		||||
      aria-current={null}
 | 
			
		||||
      className="navigationLink mdl-color-text--grey-600"
 | 
			
		||||
      href="/strategies"
 | 
			
		||||
      onClick={[Function]}
 | 
			
		||||
      style={undefined}
 | 
			
		||||
    >
 | 
			
		||||
      <react-mdl-Icon
 | 
			
		||||
        className="navigationIcon"
 | 
			
		||||
        name="extension"
 | 
			
		||||
      />
 | 
			
		||||
       
 | 
			
		||||
      Strategies
 | 
			
		||||
    </a>
 | 
			
		||||
    <a
 | 
			
		||||
      aria-current={null}
 | 
			
		||||
      className="navigationLink mdl-color-text--grey-600"
 | 
			
		||||
      href="/history"
 | 
			
		||||
      onClick={[Function]}
 | 
			
		||||
      style={undefined}
 | 
			
		||||
    >
 | 
			
		||||
      <react-mdl-Icon
 | 
			
		||||
        className="navigationIcon"
 | 
			
		||||
        name="history"
 | 
			
		||||
      />
 | 
			
		||||
       
 | 
			
		||||
      Event History
 | 
			
		||||
    </a>
 | 
			
		||||
    <a
 | 
			
		||||
      aria-current={null}
 | 
			
		||||
      className="navigationLink mdl-color-text--grey-600"
 | 
			
		||||
      href="/archive"
 | 
			
		||||
      onClick={[Function]}
 | 
			
		||||
      style={undefined}
 | 
			
		||||
    >
 | 
			
		||||
      <react-mdl-Icon
 | 
			
		||||
        className="navigationIcon"
 | 
			
		||||
        name="archive"
 | 
			
		||||
      />
 | 
			
		||||
       
 | 
			
		||||
      Archived Toggles
 | 
			
		||||
    </a>
 | 
			
		||||
    <a
 | 
			
		||||
      aria-current={null}
 | 
			
		||||
      className="navigationLink mdl-color-text--grey-600"
 | 
			
		||||
      href="/applications"
 | 
			
		||||
      onClick={[Function]}
 | 
			
		||||
      style={undefined}
 | 
			
		||||
    >
 | 
			
		||||
      <react-mdl-Icon
 | 
			
		||||
        className="navigationIcon"
 | 
			
		||||
        name="apps"
 | 
			
		||||
      />
 | 
			
		||||
       
 | 
			
		||||
      Applications
 | 
			
		||||
    </a>
 | 
			
		||||
    <a
 | 
			
		||||
      aria-current={null}
 | 
			
		||||
      className="navigationLink mdl-color-text--grey-600"
 | 
			
		||||
      href="/logout"
 | 
			
		||||
      onClick={[Function]}
 | 
			
		||||
      style={undefined}
 | 
			
		||||
    >
 | 
			
		||||
      <react-mdl-Icon
 | 
			
		||||
        className="navigationIcon"
 | 
			
		||||
        name="exit_to_app"
 | 
			
		||||
      />
 | 
			
		||||
       
 | 
			
		||||
      Sign out
 | 
			
		||||
    </a>
 | 
			
		||||
  </react-mdl-Navigation>
 | 
			
		||||
  <hr />
 | 
			
		||||
  <react-mdl-Navigation
 | 
			
		||||
    className="navigation"
 | 
			
		||||
  >
 | 
			
		||||
    <a
 | 
			
		||||
      className="navigationLink mdl-color-text--grey-900"
 | 
			
		||||
      href="https://github.com/Unleash"
 | 
			
		||||
      target="_blank"
 | 
			
		||||
    >
 | 
			
		||||
      <i
 | 
			
		||||
        className="material-icons navigationIcon iconGitHub"
 | 
			
		||||
      />
 | 
			
		||||
      GitHub
 | 
			
		||||
    </a>
 | 
			
		||||
  </react-mdl-Navigation>
 | 
			
		||||
</react-mdl-Drawer>
 | 
			
		||||
`;
 | 
			
		||||
@ -0,0 +1,177 @@
 | 
			
		||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
 | 
			
		||||
 | 
			
		||||
exports[`should render DrawerMenu 1`] = `
 | 
			
		||||
<react-mdl-FooterSection
 | 
			
		||||
  type="middle"
 | 
			
		||||
>
 | 
			
		||||
  <react-mdl-FooterDropDownSection
 | 
			
		||||
    title="Menu"
 | 
			
		||||
  >
 | 
			
		||||
    <react-mdl-FooterLinkList>
 | 
			
		||||
      <a
 | 
			
		||||
        aria-current={null}
 | 
			
		||||
        className={undefined}
 | 
			
		||||
        href="/features"
 | 
			
		||||
        onClick={[Function]}
 | 
			
		||||
        style={undefined}
 | 
			
		||||
      >
 | 
			
		||||
        Feature Toggles
 | 
			
		||||
      </a>
 | 
			
		||||
      <a
 | 
			
		||||
        aria-current={null}
 | 
			
		||||
        className={undefined}
 | 
			
		||||
        href="/strategies"
 | 
			
		||||
        onClick={[Function]}
 | 
			
		||||
        style={undefined}
 | 
			
		||||
      >
 | 
			
		||||
        Strategies
 | 
			
		||||
      </a>
 | 
			
		||||
      <a
 | 
			
		||||
        aria-current={null}
 | 
			
		||||
        className={undefined}
 | 
			
		||||
        href="/history"
 | 
			
		||||
        onClick={[Function]}
 | 
			
		||||
        style={undefined}
 | 
			
		||||
      >
 | 
			
		||||
        Event History
 | 
			
		||||
      </a>
 | 
			
		||||
      <a
 | 
			
		||||
        aria-current={null}
 | 
			
		||||
        className={undefined}
 | 
			
		||||
        href="/archive"
 | 
			
		||||
        onClick={[Function]}
 | 
			
		||||
        style={undefined}
 | 
			
		||||
      >
 | 
			
		||||
        Archived Toggles
 | 
			
		||||
      </a>
 | 
			
		||||
      <a
 | 
			
		||||
        aria-current={null}
 | 
			
		||||
        className={undefined}
 | 
			
		||||
        href="/applications"
 | 
			
		||||
        onClick={[Function]}
 | 
			
		||||
        style={undefined}
 | 
			
		||||
      >
 | 
			
		||||
        Applications
 | 
			
		||||
      </a>
 | 
			
		||||
      <a
 | 
			
		||||
        aria-current={null}
 | 
			
		||||
        className={undefined}
 | 
			
		||||
        href="/logout"
 | 
			
		||||
        onClick={[Function]}
 | 
			
		||||
        style={undefined}
 | 
			
		||||
      >
 | 
			
		||||
        Sign out
 | 
			
		||||
      </a>
 | 
			
		||||
    </react-mdl-FooterLinkList>
 | 
			
		||||
  </react-mdl-FooterDropDownSection>
 | 
			
		||||
  <react-mdl-FooterDropDownSection
 | 
			
		||||
    title="Clients"
 | 
			
		||||
  >
 | 
			
		||||
    <react-mdl-FooterLinkList>
 | 
			
		||||
      <a
 | 
			
		||||
        href="https://github.com/Unleash/unleash-client-node/"
 | 
			
		||||
      >
 | 
			
		||||
        Node.js
 | 
			
		||||
      </a>
 | 
			
		||||
      <a
 | 
			
		||||
        href="https://github.com/Unleash/unleash-client-java/"
 | 
			
		||||
      >
 | 
			
		||||
        Java
 | 
			
		||||
      </a>
 | 
			
		||||
      <a
 | 
			
		||||
        href="https://github.com/Unleash/unleash-client-go/"
 | 
			
		||||
      >
 | 
			
		||||
        Go
 | 
			
		||||
      </a>
 | 
			
		||||
    </react-mdl-FooterLinkList>
 | 
			
		||||
  </react-mdl-FooterDropDownSection>
 | 
			
		||||
</react-mdl-FooterSection>
 | 
			
		||||
`;
 | 
			
		||||
 | 
			
		||||
exports[`should render DrawerMenu with "features" selected 1`] = `
 | 
			
		||||
<react-mdl-FooterSection
 | 
			
		||||
  type="middle"
 | 
			
		||||
>
 | 
			
		||||
  <react-mdl-FooterDropDownSection
 | 
			
		||||
    title="Menu"
 | 
			
		||||
  >
 | 
			
		||||
    <react-mdl-FooterLinkList>
 | 
			
		||||
      <a
 | 
			
		||||
        aria-current="page"
 | 
			
		||||
        className="active"
 | 
			
		||||
        href="/features"
 | 
			
		||||
        onClick={[Function]}
 | 
			
		||||
        style={Object {}}
 | 
			
		||||
      >
 | 
			
		||||
        Feature Toggles
 | 
			
		||||
      </a>
 | 
			
		||||
      <a
 | 
			
		||||
        aria-current={null}
 | 
			
		||||
        className={undefined}
 | 
			
		||||
        href="/strategies"
 | 
			
		||||
        onClick={[Function]}
 | 
			
		||||
        style={undefined}
 | 
			
		||||
      >
 | 
			
		||||
        Strategies
 | 
			
		||||
      </a>
 | 
			
		||||
      <a
 | 
			
		||||
        aria-current={null}
 | 
			
		||||
        className={undefined}
 | 
			
		||||
        href="/history"
 | 
			
		||||
        onClick={[Function]}
 | 
			
		||||
        style={undefined}
 | 
			
		||||
      >
 | 
			
		||||
        Event History
 | 
			
		||||
      </a>
 | 
			
		||||
      <a
 | 
			
		||||
        aria-current={null}
 | 
			
		||||
        className={undefined}
 | 
			
		||||
        href="/archive"
 | 
			
		||||
        onClick={[Function]}
 | 
			
		||||
        style={undefined}
 | 
			
		||||
      >
 | 
			
		||||
        Archived Toggles
 | 
			
		||||
      </a>
 | 
			
		||||
      <a
 | 
			
		||||
        aria-current={null}
 | 
			
		||||
        className={undefined}
 | 
			
		||||
        href="/applications"
 | 
			
		||||
        onClick={[Function]}
 | 
			
		||||
        style={undefined}
 | 
			
		||||
      >
 | 
			
		||||
        Applications
 | 
			
		||||
      </a>
 | 
			
		||||
      <a
 | 
			
		||||
        aria-current={null}
 | 
			
		||||
        className={undefined}
 | 
			
		||||
        href="/logout"
 | 
			
		||||
        onClick={[Function]}
 | 
			
		||||
        style={undefined}
 | 
			
		||||
      >
 | 
			
		||||
        Sign out
 | 
			
		||||
      </a>
 | 
			
		||||
    </react-mdl-FooterLinkList>
 | 
			
		||||
  </react-mdl-FooterDropDownSection>
 | 
			
		||||
  <react-mdl-FooterDropDownSection
 | 
			
		||||
    title="Clients"
 | 
			
		||||
  >
 | 
			
		||||
    <react-mdl-FooterLinkList>
 | 
			
		||||
      <a
 | 
			
		||||
        href="https://github.com/Unleash/unleash-client-node/"
 | 
			
		||||
      >
 | 
			
		||||
        Node.js
 | 
			
		||||
      </a>
 | 
			
		||||
      <a
 | 
			
		||||
        href="https://github.com/Unleash/unleash-client-java/"
 | 
			
		||||
      >
 | 
			
		||||
        Java
 | 
			
		||||
      </a>
 | 
			
		||||
      <a
 | 
			
		||||
        href="https://github.com/Unleash/unleash-client-go/"
 | 
			
		||||
      >
 | 
			
		||||
        Go
 | 
			
		||||
      </a>
 | 
			
		||||
    </react-mdl-FooterLinkList>
 | 
			
		||||
  </react-mdl-FooterDropDownSection>
 | 
			
		||||
</react-mdl-FooterSection>
 | 
			
		||||
`;
 | 
			
		||||
@ -0,0 +1,125 @@
 | 
			
		||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
 | 
			
		||||
 | 
			
		||||
exports[`returns all baseRoutes 1`] = `
 | 
			
		||||
Array [
 | 
			
		||||
  Object {
 | 
			
		||||
    "component": [Function],
 | 
			
		||||
    "icon": "list",
 | 
			
		||||
    "path": "/features",
 | 
			
		||||
    "title": "Feature Toggles",
 | 
			
		||||
  },
 | 
			
		||||
  Object {
 | 
			
		||||
    "component": [Function],
 | 
			
		||||
    "icon": "extension",
 | 
			
		||||
    "path": "/strategies",
 | 
			
		||||
    "title": "Strategies",
 | 
			
		||||
  },
 | 
			
		||||
  Object {
 | 
			
		||||
    "component": [Function],
 | 
			
		||||
    "icon": "history",
 | 
			
		||||
    "path": "/history",
 | 
			
		||||
    "title": "Event History",
 | 
			
		||||
  },
 | 
			
		||||
  Object {
 | 
			
		||||
    "component": [Function],
 | 
			
		||||
    "icon": "archive",
 | 
			
		||||
    "path": "/archive",
 | 
			
		||||
    "title": "Archived Toggles",
 | 
			
		||||
  },
 | 
			
		||||
  Object {
 | 
			
		||||
    "component": [Function],
 | 
			
		||||
    "icon": "apps",
 | 
			
		||||
    "path": "/applications",
 | 
			
		||||
    "title": "Applications",
 | 
			
		||||
  },
 | 
			
		||||
  Object {
 | 
			
		||||
    "component": [Function],
 | 
			
		||||
    "icon": "exit_to_app",
 | 
			
		||||
    "path": "/logout",
 | 
			
		||||
    "title": "Sign out",
 | 
			
		||||
  },
 | 
			
		||||
]
 | 
			
		||||
`;
 | 
			
		||||
 | 
			
		||||
exports[`returns all defined routes 1`] = `
 | 
			
		||||
Array [
 | 
			
		||||
  Object {
 | 
			
		||||
    "component": [Function],
 | 
			
		||||
    "parent": "/features",
 | 
			
		||||
    "path": "/features/create",
 | 
			
		||||
    "title": "Create",
 | 
			
		||||
  },
 | 
			
		||||
  Object {
 | 
			
		||||
    "component": [Function],
 | 
			
		||||
    "parent": "/features",
 | 
			
		||||
    "path": "/features/:activeTab/:name",
 | 
			
		||||
    "title": ":name",
 | 
			
		||||
  },
 | 
			
		||||
  Object {
 | 
			
		||||
    "component": [Function],
 | 
			
		||||
    "icon": "list",
 | 
			
		||||
    "path": "/features",
 | 
			
		||||
    "title": "Feature Toggles",
 | 
			
		||||
  },
 | 
			
		||||
  Object {
 | 
			
		||||
    "component": [Function],
 | 
			
		||||
    "parent": "/strategies",
 | 
			
		||||
    "path": "/strategies/create",
 | 
			
		||||
    "title": "Create",
 | 
			
		||||
  },
 | 
			
		||||
  Object {
 | 
			
		||||
    "component": [Function],
 | 
			
		||||
    "parent": "/strategies",
 | 
			
		||||
    "path": "/strategies/:activeTab/:strategyName",
 | 
			
		||||
    "title": ":strategyName",
 | 
			
		||||
  },
 | 
			
		||||
  Object {
 | 
			
		||||
    "component": [Function],
 | 
			
		||||
    "icon": "extension",
 | 
			
		||||
    "path": "/strategies",
 | 
			
		||||
    "title": "Strategies",
 | 
			
		||||
  },
 | 
			
		||||
  Object {
 | 
			
		||||
    "component": [Function],
 | 
			
		||||
    "parent": "/history",
 | 
			
		||||
    "path": "/history/:toggleName",
 | 
			
		||||
    "title": ":toggleName",
 | 
			
		||||
  },
 | 
			
		||||
  Object {
 | 
			
		||||
    "component": [Function],
 | 
			
		||||
    "icon": "history",
 | 
			
		||||
    "path": "/history",
 | 
			
		||||
    "title": "Event History",
 | 
			
		||||
  },
 | 
			
		||||
  Object {
 | 
			
		||||
    "component": [Function],
 | 
			
		||||
    "parent": "/archive",
 | 
			
		||||
    "path": "/archive/:activeTab/:name",
 | 
			
		||||
    "title": ":name",
 | 
			
		||||
  },
 | 
			
		||||
  Object {
 | 
			
		||||
    "component": [Function],
 | 
			
		||||
    "icon": "archive",
 | 
			
		||||
    "path": "/archive",
 | 
			
		||||
    "title": "Archived Toggles",
 | 
			
		||||
  },
 | 
			
		||||
  Object {
 | 
			
		||||
    "component": [Function],
 | 
			
		||||
    "parent": "/applications",
 | 
			
		||||
    "path": "/applications/:name",
 | 
			
		||||
    "title": ":name",
 | 
			
		||||
  },
 | 
			
		||||
  Object {
 | 
			
		||||
    "component": [Function],
 | 
			
		||||
    "icon": "apps",
 | 
			
		||||
    "path": "/applications",
 | 
			
		||||
    "title": "Applications",
 | 
			
		||||
  },
 | 
			
		||||
  Object {
 | 
			
		||||
    "component": [Function],
 | 
			
		||||
    "icon": "exit_to_app",
 | 
			
		||||
    "path": "/logout",
 | 
			
		||||
    "title": "Sign out",
 | 
			
		||||
  },
 | 
			
		||||
]
 | 
			
		||||
`;
 | 
			
		||||
							
								
								
									
										37
									
								
								frontend/src/component/menu/__tests__/breadcrumb-test.jsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										37
									
								
								frontend/src/component/menu/__tests__/breadcrumb-test.jsx
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,37 @@
 | 
			
		||||
import React from 'react';
 | 
			
		||||
import renderer from 'react-test-renderer';
 | 
			
		||||
import { MemoryRouter } from 'react-router-dom';
 | 
			
		||||
 | 
			
		||||
import Breadcrumb from '../breadcrumb';
 | 
			
		||||
 | 
			
		||||
jest.mock('react-mdl');
 | 
			
		||||
 | 
			
		||||
test('breadcrumb for /features', () => {
 | 
			
		||||
    const tree = renderer.create(
 | 
			
		||||
        <MemoryRouter initialEntries={['/features']}>
 | 
			
		||||
            <Breadcrumb />
 | 
			
		||||
        </MemoryRouter>
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    expect(tree).toMatchSnapshot();
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
test('breadcrumb for /features/view/Demo', () => {
 | 
			
		||||
    const tree = renderer.create(
 | 
			
		||||
        <MemoryRouter initialEntries={['/features/view/Demo']}>
 | 
			
		||||
            <Breadcrumb />
 | 
			
		||||
        </MemoryRouter>
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    expect(tree).toMatchSnapshot();
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
test('breadcrumb for /strategies', () => {
 | 
			
		||||
    const tree = renderer.create(
 | 
			
		||||
        <MemoryRouter initialEntries={['/strategies']}>
 | 
			
		||||
            <Breadcrumb />
 | 
			
		||||
        </MemoryRouter>
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    expect(tree).toMatchSnapshot();
 | 
			
		||||
});
 | 
			
		||||
							
								
								
									
										27
									
								
								frontend/src/component/menu/__tests__/drawer-test.jsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										27
									
								
								frontend/src/component/menu/__tests__/drawer-test.jsx
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,27 @@
 | 
			
		||||
import React from 'react';
 | 
			
		||||
import renderer from 'react-test-renderer';
 | 
			
		||||
import { MemoryRouter } from 'react-router-dom';
 | 
			
		||||
 | 
			
		||||
import { DrawerMenu } from '../drawer';
 | 
			
		||||
 | 
			
		||||
jest.mock('react-mdl');
 | 
			
		||||
 | 
			
		||||
test('should render DrawerMenu', () => {
 | 
			
		||||
    const tree = renderer.create(
 | 
			
		||||
        <MemoryRouter>
 | 
			
		||||
            <DrawerMenu />
 | 
			
		||||
        </MemoryRouter>
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    expect(tree).toMatchSnapshot();
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
test('should render DrawerMenu with "features" selected', () => {
 | 
			
		||||
    const tree = renderer.create(
 | 
			
		||||
        <MemoryRouter initialEntries={['/features']}>
 | 
			
		||||
            <DrawerMenu />
 | 
			
		||||
        </MemoryRouter>
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    expect(tree).toMatchSnapshot();
 | 
			
		||||
});
 | 
			
		||||
							
								
								
									
										27
									
								
								frontend/src/component/menu/__tests__/footer-test.jsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										27
									
								
								frontend/src/component/menu/__tests__/footer-test.jsx
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,27 @@
 | 
			
		||||
import React from 'react';
 | 
			
		||||
import renderer from 'react-test-renderer';
 | 
			
		||||
import { MemoryRouter } from 'react-router-dom';
 | 
			
		||||
 | 
			
		||||
import { FooterMenu } from '../footer';
 | 
			
		||||
 | 
			
		||||
jest.mock('react-mdl');
 | 
			
		||||
 | 
			
		||||
test('should render DrawerMenu', () => {
 | 
			
		||||
    const tree = renderer.create(
 | 
			
		||||
        <MemoryRouter>
 | 
			
		||||
            <FooterMenu />
 | 
			
		||||
        </MemoryRouter>
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    expect(tree).toMatchSnapshot();
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
test('should render DrawerMenu with "features" selected', () => {
 | 
			
		||||
    const tree = renderer.create(
 | 
			
		||||
        <MemoryRouter initialEntries={['/features']}>
 | 
			
		||||
            <FooterMenu />
 | 
			
		||||
        </MemoryRouter>
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    expect(tree).toMatchSnapshot();
 | 
			
		||||
});
 | 
			
		||||
							
								
								
									
										16
									
								
								frontend/src/component/menu/__tests__/routes-test.jsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										16
									
								
								frontend/src/component/menu/__tests__/routes-test.jsx
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,16 @@
 | 
			
		||||
import { routes, baseRoutes, getRoute } from '../routes';
 | 
			
		||||
 | 
			
		||||
test('returns all defined routes', () => {
 | 
			
		||||
    expect(routes.length).toEqual(13);
 | 
			
		||||
    expect(routes).toMatchSnapshot();
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
test('returns all baseRoutes', () => {
 | 
			
		||||
    expect(baseRoutes.length).toEqual(6);
 | 
			
		||||
    expect(baseRoutes).toMatchSnapshot();
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
test('getRoute() returns named route', () => {
 | 
			
		||||
    const featuresRoute = getRoute('/features');
 | 
			
		||||
    expect(featuresRoute.path).toEqual('/features');
 | 
			
		||||
});
 | 
			
		||||
							
								
								
									
										69
									
								
								frontend/src/component/menu/breadcrumb.jsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										69
									
								
								frontend/src/component/menu/breadcrumb.jsx
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,69 @@
 | 
			
		||||
import React from 'react';
 | 
			
		||||
import { Link, Route, Switch } from 'react-router-dom';
 | 
			
		||||
 | 
			
		||||
import { routes, getRoute } from './routes';
 | 
			
		||||
 | 
			
		||||
import styles from '../styles.scss';
 | 
			
		||||
 | 
			
		||||
const renderDoubleBread = (currentTitle, parentRoute) => {
 | 
			
		||||
    document.title = `${currentTitle} -  ${parentRoute.title} - Unleash`;
 | 
			
		||||
    return (
 | 
			
		||||
        <span>
 | 
			
		||||
            <Link
 | 
			
		||||
                className={[styles.headerTitleLink, 'mdl-color-text--primary-contrast'].join(' ')}
 | 
			
		||||
                to={parentRoute.path}
 | 
			
		||||
            >
 | 
			
		||||
                {parentRoute.title}
 | 
			
		||||
            </Link>
 | 
			
		||||
            <span className="mdl-layout--large-screen-only">
 | 
			
		||||
                <span> › </span>
 | 
			
		||||
                <span className={[styles.headerTitleLink, 'mdl-color-text--primary-contrast'].join(' ')}>
 | 
			
		||||
                    {currentTitle}
 | 
			
		||||
                </span>
 | 
			
		||||
            </span>
 | 
			
		||||
        </span>
 | 
			
		||||
    );
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const renderBread = route => {
 | 
			
		||||
    document.title = `${route.title} - Unleash`;
 | 
			
		||||
    return (
 | 
			
		||||
        <span className="mdl-layout--large-screen-only">
 | 
			
		||||
            <span className={[styles.headerTitleLink, 'mdl-color-text--primary-contrast'].join(' ')}>
 | 
			
		||||
                {route.title}
 | 
			
		||||
            </span>
 | 
			
		||||
        </span>
 | 
			
		||||
    );
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const renderRoute = (params, route) => {
 | 
			
		||||
    if (!route) {
 | 
			
		||||
        return null;
 | 
			
		||||
    }
 | 
			
		||||
    const title = route.title.startsWith(':') ? params[route.title.substring(1)] : route.title;
 | 
			
		||||
    return route.parent ? renderDoubleBread(title, getRoute(route.parent)) : renderBread(route);
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
    Render the breadcrumb.
 | 
			
		||||
 | 
			
		||||
    We only support two levels.
 | 
			
		||||
 | 
			
		||||
    Examples:
 | 
			
		||||
     - Features
 | 
			
		||||
     - Features > Create
 | 
			
		||||
     - Features > SomeToggle
 | 
			
		||||
 */
 | 
			
		||||
const Breadcrumb = () => (
 | 
			
		||||
    <Switch>
 | 
			
		||||
        {routes.map(route => (
 | 
			
		||||
            <Route
 | 
			
		||||
                key={route.path}
 | 
			
		||||
                path={route.path}
 | 
			
		||||
                render={({ match: { params } } = this.props) => renderRoute(params, route)}
 | 
			
		||||
            />
 | 
			
		||||
        ))}
 | 
			
		||||
    </Switch>
 | 
			
		||||
);
 | 
			
		||||
 | 
			
		||||
export default Breadcrumb;
 | 
			
		||||
							
								
								
									
										38
									
								
								frontend/src/component/menu/drawer.jsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										38
									
								
								frontend/src/component/menu/drawer.jsx
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,38 @@
 | 
			
		||||
import React from 'react';
 | 
			
		||||
import { Drawer, Icon, Navigation } from 'react-mdl';
 | 
			
		||||
import { NavLink } from 'react-router-dom';
 | 
			
		||||
import styles from '../styles.scss';
 | 
			
		||||
 | 
			
		||||
import { baseRoutes as routes } from './routes';
 | 
			
		||||
 | 
			
		||||
export const DrawerMenu = () => (
 | 
			
		||||
    <Drawer className="mdl-color--white">
 | 
			
		||||
        <span className={[styles.drawerTitle, 'mdl-layout-title'].join(' ')}>
 | 
			
		||||
            <img src="public/logo.png" width="32" height="32" className={styles.drawerTitleLogo} />
 | 
			
		||||
            <span className={styles.drawerTitleText}>Unleash</span>
 | 
			
		||||
        </span>
 | 
			
		||||
        <hr />
 | 
			
		||||
        <Navigation className={styles.navigation}>
 | 
			
		||||
            {routes.map(item => (
 | 
			
		||||
                <NavLink
 | 
			
		||||
                    key={item.path}
 | 
			
		||||
                    to={item.path}
 | 
			
		||||
                    className={[styles.navigationLink, 'mdl-color-text--grey-600'].join(' ')}
 | 
			
		||||
                    activeClassName={[styles.navigationLink, 'mdl-color-text--black'].join(' ')}
 | 
			
		||||
                >
 | 
			
		||||
                    <Icon name={item.icon} className={styles.navigationIcon} /> {item.title}
 | 
			
		||||
                </NavLink>
 | 
			
		||||
            ))}
 | 
			
		||||
        </Navigation>
 | 
			
		||||
        <hr />
 | 
			
		||||
        <Navigation className={styles.navigation}>
 | 
			
		||||
            <a
 | 
			
		||||
                href="https://github.com/Unleash"
 | 
			
		||||
                target="_blank"
 | 
			
		||||
                className={[styles.navigationLink, 'mdl-color-text--grey-900'].join(' ')}
 | 
			
		||||
            >
 | 
			
		||||
                <i className={['material-icons', styles.navigationIcon, styles.iconGitHub].join(' ')} />GitHub
 | 
			
		||||
            </a>
 | 
			
		||||
        </Navigation>
 | 
			
		||||
    </Drawer>
 | 
			
		||||
);
 | 
			
		||||
							
								
								
									
										26
									
								
								frontend/src/component/menu/footer.jsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										26
									
								
								frontend/src/component/menu/footer.jsx
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,26 @@
 | 
			
		||||
import React from 'react';
 | 
			
		||||
import { FooterDropDownSection, FooterLinkList, FooterSection } from 'react-mdl';
 | 
			
		||||
import { NavLink } from 'react-router-dom';
 | 
			
		||||
 | 
			
		||||
import { baseRoutes as routes } from './routes';
 | 
			
		||||
 | 
			
		||||
export const FooterMenu = () => (
 | 
			
		||||
    <FooterSection type="middle">
 | 
			
		||||
        <FooterDropDownSection title="Menu">
 | 
			
		||||
            <FooterLinkList>
 | 
			
		||||
                {routes.map(item => (
 | 
			
		||||
                    <NavLink key={item.path} to={item.path}>
 | 
			
		||||
                        {item.title}
 | 
			
		||||
                    </NavLink>
 | 
			
		||||
                ))}
 | 
			
		||||
            </FooterLinkList>
 | 
			
		||||
        </FooterDropDownSection>
 | 
			
		||||
        <FooterDropDownSection title="Clients">
 | 
			
		||||
            <FooterLinkList>
 | 
			
		||||
                <a href="https://github.com/Unleash/unleash-client-node/">Node.js</a>
 | 
			
		||||
                <a href="https://github.com/Unleash/unleash-client-java/">Java</a>
 | 
			
		||||
                <a href="https://github.com/Unleash/unleash-client-go/">Go</a>
 | 
			
		||||
            </FooterLinkList>
 | 
			
		||||
        </FooterDropDownSection>
 | 
			
		||||
    </FooterSection>
 | 
			
		||||
);
 | 
			
		||||
							
								
								
									
										48
									
								
								frontend/src/component/menu/routes.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										48
									
								
								frontend/src/component/menu/routes.js
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,48 @@
 | 
			
		||||
import CreateFeatureToggle from '../../page/features/create';
 | 
			
		||||
import ViewFeatureToggle from '../../page/features/show';
 | 
			
		||||
import Features from '../../page/features';
 | 
			
		||||
import CreateStrategies from '../../page/strategies/create';
 | 
			
		||||
import StrategyView from '../../page/strategies/show';
 | 
			
		||||
import Strategies from '../../page/strategies';
 | 
			
		||||
import HistoryPage from '../../page/history';
 | 
			
		||||
import HistoryTogglePage from '../../page/history/toggle';
 | 
			
		||||
import ShowArchive from '../../page/archive/show';
 | 
			
		||||
import Archive from '../../page/archive';
 | 
			
		||||
import Applications from '../../page/applications';
 | 
			
		||||
import ApplicationView from '../../page/applications/view';
 | 
			
		||||
import LogoutFeatures from '../../page/user/logout';
 | 
			
		||||
 | 
			
		||||
export const routes = [
 | 
			
		||||
    // Features
 | 
			
		||||
    { path: '/features/create', parent: '/features', title: 'Create', component: CreateFeatureToggle },
 | 
			
		||||
    { path: '/features/:activeTab/:name', parent: '/features', title: ':name', component: ViewFeatureToggle },
 | 
			
		||||
    { path: '/features', title: 'Feature Toggles', icon: 'list', component: Features },
 | 
			
		||||
 | 
			
		||||
    // Strategies
 | 
			
		||||
    { path: '/strategies/create', title: 'Create', parent: '/strategies', component: CreateStrategies },
 | 
			
		||||
    {
 | 
			
		||||
        path: '/strategies/:activeTab/:strategyName',
 | 
			
		||||
        title: ':strategyName',
 | 
			
		||||
        parent: '/strategies',
 | 
			
		||||
        component: StrategyView,
 | 
			
		||||
    },
 | 
			
		||||
    { path: '/strategies', title: 'Strategies', icon: 'extension', component: Strategies },
 | 
			
		||||
 | 
			
		||||
    // History
 | 
			
		||||
    { path: '/history/:toggleName', title: ':toggleName', parent: '/history', component: HistoryTogglePage },
 | 
			
		||||
    { path: '/history', title: 'Event History', icon: 'history', component: HistoryPage },
 | 
			
		||||
 | 
			
		||||
    // Archive
 | 
			
		||||
    { path: '/archive/:activeTab/:name', title: ':name', parent: '/archive', component: ShowArchive },
 | 
			
		||||
    { path: '/archive', title: 'Archived Toggles', icon: 'archive', component: Archive },
 | 
			
		||||
 | 
			
		||||
    // Applications
 | 
			
		||||
    { path: '/applications/:name', title: ':name', parent: '/applications', component: ApplicationView },
 | 
			
		||||
    { path: '/applications', title: 'Applications', icon: 'apps', component: Applications },
 | 
			
		||||
 | 
			
		||||
    { path: '/logout', title: 'Sign out', icon: 'exit_to_app', component: LogoutFeatures },
 | 
			
		||||
];
 | 
			
		||||
 | 
			
		||||
export const getRoute = path => routes.find(route => route.path === path);
 | 
			
		||||
 | 
			
		||||
export const baseRoutes = routes.filter(route => !route.parent);
 | 
			
		||||
							
								
								
									
										21
									
								
								frontend/src/component/scroll-to-top.jsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										21
									
								
								frontend/src/component/scroll-to-top.jsx
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,21 @@
 | 
			
		||||
import { Component } from 'react';
 | 
			
		||||
import { withRouter } from 'react-router-dom';
 | 
			
		||||
import PropTypes from 'prop-types';
 | 
			
		||||
 | 
			
		||||
class ScrollToTop extends Component {
 | 
			
		||||
    static propTypes = {
 | 
			
		||||
        location: PropTypes.object.isRequired,
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    componentDidUpdate(prevProps) {
 | 
			
		||||
        if (this.props.location !== prevProps.location) {
 | 
			
		||||
            window.scrollTo(0, 0);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    render() {
 | 
			
		||||
        return this.props.children;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export default withRouter(ScrollToTop);
 | 
			
		||||
@ -1,5 +1,4 @@
 | 
			
		||||
import { connect } from 'react-redux';
 | 
			
		||||
import { hashHistory } from 'react-router';
 | 
			
		||||
import { createMapper, createActions } from '../input-helpers';
 | 
			
		||||
import { updateStrategy } from '../../store/strategy/actions';
 | 
			
		||||
 | 
			
		||||
@ -41,7 +40,7 @@ const prepare = (methods, dispatch) => {
 | 
			
		||||
            parameters,
 | 
			
		||||
        })(dispatch)
 | 
			
		||||
            .then(() => methods.clear())
 | 
			
		||||
            .then(() => hashHistory.push(`/strategies/view/${input.name}`));
 | 
			
		||||
            .then(() => this.props.history.push(`/strategies/view/${input.name}`));
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    methods.onCancel = e => {
 | 
			
		||||
 | 
			
		||||
@ -1,6 +1,6 @@
 | 
			
		||||
import React, { Component } from 'react';
 | 
			
		||||
import PropTypes from 'prop-types';
 | 
			
		||||
import { Link } from 'react-router';
 | 
			
		||||
import { Link } from 'react-router-dom';
 | 
			
		||||
 | 
			
		||||
import { List, ListItem, ListItemContent, IconButton, Grid, Cell } from 'react-mdl';
 | 
			
		||||
import { HeaderTitle } from '../common';
 | 
			
		||||
 | 
			
		||||
@ -1,6 +1,5 @@
 | 
			
		||||
import React, { Component } from 'react';
 | 
			
		||||
import PropTypes from 'prop-types';
 | 
			
		||||
import { hashHistory } from 'react-router';
 | 
			
		||||
import { Tabs, Tab, ProgressBar, Grid, Cell } from 'react-mdl';
 | 
			
		||||
import ShowStrategy from './show-strategy-component';
 | 
			
		||||
import EditStrategy from './edit-container';
 | 
			
		||||
@ -21,6 +20,7 @@ export default class StrategyDetails extends Component {
 | 
			
		||||
        fetchStrategies: PropTypes.func.isRequired,
 | 
			
		||||
        fetchApplications: PropTypes.func.isRequired,
 | 
			
		||||
        fetchFeatureToggles: PropTypes.func.isRequired,
 | 
			
		||||
        history: PropTypes.object.isRequired,
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    componentDidMount() {
 | 
			
		||||
@ -50,7 +50,7 @@ export default class StrategyDetails extends Component {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    goToTab(tabName) {
 | 
			
		||||
        hashHistory.push(`/strategies/${tabName}/${this.props.strategyName}`);
 | 
			
		||||
        this.props.history.push(`/strategies/${tabName}/${this.props.strategyName}`);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    render() {
 | 
			
		||||
 | 
			
		||||
@ -1,6 +1,5 @@
 | 
			
		||||
import React from 'react';
 | 
			
		||||
import PropTypes from 'prop-types';
 | 
			
		||||
import { hashHistory } from 'react-router';
 | 
			
		||||
import { CardActions, Button, Textfield } from 'react-mdl';
 | 
			
		||||
 | 
			
		||||
class SimpleAuthenticationComponent extends React.Component {
 | 
			
		||||
@ -16,12 +15,7 @@ class SimpleAuthenticationComponent extends React.Component {
 | 
			
		||||
        const user = { email };
 | 
			
		||||
        const path = evt.target.action;
 | 
			
		||||
 | 
			
		||||
        this.props
 | 
			
		||||
            .unsecureLogin(path, user)
 | 
			
		||||
            .then(this.props.fetchFeatureToggles)
 | 
			
		||||
            .then(() => {
 | 
			
		||||
                hashHistory.push('/features');
 | 
			
		||||
            });
 | 
			
		||||
        this.props.unsecureLogin(path, user).then(this.props.fetchFeatureToggles);
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    render() {
 | 
			
		||||
 | 
			
		||||
@ -4,8 +4,7 @@ import 'react-mdl/extra/material.js';
 | 
			
		||||
 | 
			
		||||
import React from 'react';
 | 
			
		||||
import ReactDOM from 'react-dom';
 | 
			
		||||
import { applyRouterMiddleware, Router, Route, IndexRedirect, hashHistory } from 'react-router';
 | 
			
		||||
import { useScroll } from 'react-router-scroll';
 | 
			
		||||
import { HashRouter, Route } from 'react-router-dom';
 | 
			
		||||
import { Provider } from 'react-redux';
 | 
			
		||||
import thunkMiddleware from 'redux-thunk';
 | 
			
		||||
import { createStore, applyMiddleware, compose } from 'redux';
 | 
			
		||||
@ -13,20 +12,7 @@ import { createStore, applyMiddleware, compose } from 'redux';
 | 
			
		||||
import store from './store';
 | 
			
		||||
import MetricsPoller from './metrics-poller';
 | 
			
		||||
import App from './component/app';
 | 
			
		||||
 | 
			
		||||
import Features from './page/features';
 | 
			
		||||
import CreateFeatureToggle from './page/features/create';
 | 
			
		||||
import ViewFeatureToggle from './page/features/show';
 | 
			
		||||
import Strategies from './page/strategies';
 | 
			
		||||
import StrategyView from './page/strategies/show';
 | 
			
		||||
import CreateStrategies from './page/strategies/create';
 | 
			
		||||
import HistoryPage from './page/history';
 | 
			
		||||
import HistoryTogglePage from './page/history/toggle';
 | 
			
		||||
import Archive from './page/archive';
 | 
			
		||||
import ShowArchive from './page/archive/show';
 | 
			
		||||
import Applications from './page/applications';
 | 
			
		||||
import ApplicationView from './page/applications/view';
 | 
			
		||||
import LogoutFeatures from './page/user/logout';
 | 
			
		||||
import ScrollToTop from './component/scroll-to-top';
 | 
			
		||||
 | 
			
		||||
let composeEnhancers;
 | 
			
		||||
 | 
			
		||||
@ -40,48 +26,13 @@ const unleashStore = createStore(store, composeEnhancers(applyMiddleware(thunkMi
 | 
			
		||||
const metricsPoller = new MetricsPoller(unleashStore);
 | 
			
		||||
metricsPoller.start();
 | 
			
		||||
 | 
			
		||||
// "pageTitle" and "link" attributes are for internal usage only
 | 
			
		||||
 | 
			
		||||
ReactDOM.render(
 | 
			
		||||
    <Provider store={unleashStore}>
 | 
			
		||||
        <Router history={hashHistory} render={applyRouterMiddleware(useScroll())}>
 | 
			
		||||
            <Route path="/" component={App}>
 | 
			
		||||
                <IndexRedirect to="/features" />
 | 
			
		||||
 | 
			
		||||
                <Route pageTitle="Feature Toggles" link="/features">
 | 
			
		||||
                    <Route pageTitle="Feature toggles" path="/features" component={Features} />
 | 
			
		||||
                    <Route pageTitle="New" path="/features/create" component={CreateFeatureToggle} />
 | 
			
		||||
                    <Route pageTitle=":name" path="/features/:activeTab/:name" component={ViewFeatureToggle} />
 | 
			
		||||
                </Route>
 | 
			
		||||
 | 
			
		||||
                <Route pageTitle="Strategies" link="/strategies">
 | 
			
		||||
                    <Route pageTitle="Strategies" path="/strategies" component={Strategies} />
 | 
			
		||||
                    <Route pageTitle="New" path="/strategies/create" component={CreateStrategies} />
 | 
			
		||||
                    <Route
 | 
			
		||||
                        pageTitle=":strategyName"
 | 
			
		||||
                        path="/strategies/:activeTab/:strategyName"
 | 
			
		||||
                        component={StrategyView}
 | 
			
		||||
                    />
 | 
			
		||||
                </Route>
 | 
			
		||||
 | 
			
		||||
                <Route pageTitle="Event History" link="/history">
 | 
			
		||||
                    <Route pageTitle="Event history" path="/history" component={HistoryPage} />
 | 
			
		||||
                    <Route pageTitle=":toggleName" path="/history/:toggleName" component={HistoryTogglePage} />
 | 
			
		||||
                </Route>
 | 
			
		||||
                <Route pageTitle="Archived Toggles" link="/archive">
 | 
			
		||||
                    <Route pageTitle="Archived Toggles" path="/archive" component={Archive} />
 | 
			
		||||
                    <Route pageTitle=":name" path="/archive/:activeTab/:name" component={ShowArchive} />
 | 
			
		||||
                </Route>
 | 
			
		||||
 | 
			
		||||
                <Route pageTitle="Applications" link="/applications">
 | 
			
		||||
                    <Route pageTitle="Applications" path="/applications" component={Applications} />
 | 
			
		||||
                    <Route pageTitle=":name" path="/applications/:name" component={ApplicationView} />
 | 
			
		||||
                </Route>
 | 
			
		||||
                <Route pageTitle="Logout" link="/logout">
 | 
			
		||||
                    <Route pageTitle="Logout" path="/logout" component={LogoutFeatures} />
 | 
			
		||||
                </Route>
 | 
			
		||||
            </Route>
 | 
			
		||||
        </Router>
 | 
			
		||||
        <HashRouter>
 | 
			
		||||
            <ScrollToTop>
 | 
			
		||||
                <Route path="/" component={App} />
 | 
			
		||||
            </ScrollToTop>
 | 
			
		||||
        </HashRouter>
 | 
			
		||||
    </Provider>,
 | 
			
		||||
    document.getElementById('app')
 | 
			
		||||
);
 | 
			
		||||
 | 
			
		||||
@ -2,10 +2,10 @@ import React from 'react';
 | 
			
		||||
import PropTypes from 'prop-types';
 | 
			
		||||
import ApplicationEditComponent from '../../component/application/application-edit-container';
 | 
			
		||||
 | 
			
		||||
const render = ({ params }) => <ApplicationEditComponent appName={params.name} />;
 | 
			
		||||
const render = ({ match: { params } }) => <ApplicationEditComponent appName={params.name} />;
 | 
			
		||||
 | 
			
		||||
render.propTypes = {
 | 
			
		||||
    params: PropTypes.object.isRequired,
 | 
			
		||||
    match: PropTypes.object.isRequired,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export default render;
 | 
			
		||||
 | 
			
		||||
@ -2,9 +2,10 @@ import React from 'react';
 | 
			
		||||
import Archive from '../../component/archive/archive-list-container';
 | 
			
		||||
import PropTypes from 'prop-types';
 | 
			
		||||
 | 
			
		||||
const render = ({ params }) => <Archive name={params.name} />;
 | 
			
		||||
const render = ({ match: { params }, history }) => <Archive name={params.name} history={history} />;
 | 
			
		||||
render.propTypes = {
 | 
			
		||||
    params: PropTypes.object,
 | 
			
		||||
    match: PropTypes.object,
 | 
			
		||||
    history: PropTypes.object,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export default render;
 | 
			
		||||
 | 
			
		||||
@ -4,11 +4,18 @@ import ViewFeatureToggle from './../../component/archive/view-container';
 | 
			
		||||
 | 
			
		||||
export default class Features extends PureComponent {
 | 
			
		||||
    static propTypes = {
 | 
			
		||||
        params: PropTypes.object.isRequired,
 | 
			
		||||
        match: PropTypes.object.isRequired,
 | 
			
		||||
        history: PropTypes.object.isRequired,
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    render() {
 | 
			
		||||
        const { params } = this.props;
 | 
			
		||||
        return <ViewFeatureToggle featureToggleName={params.name} activeTab={params.activeTab} />;
 | 
			
		||||
        const { match, history } = this.props;
 | 
			
		||||
        return (
 | 
			
		||||
            <ViewFeatureToggle
 | 
			
		||||
                history={history}
 | 
			
		||||
                featureToggleName={match.params.name}
 | 
			
		||||
                activeTab={match.params.activeTab}
 | 
			
		||||
            />
 | 
			
		||||
        );
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -1,6 +1,11 @@
 | 
			
		||||
import React from 'react';
 | 
			
		||||
import AddFeatureToggleForm from '../../component/feature/form/form-add-feature-container';
 | 
			
		||||
import PropTypes from 'prop-types';
 | 
			
		||||
 | 
			
		||||
const render = () => <AddFeatureToggleForm title="Create feature toggle" />;
 | 
			
		||||
const render = ({ history }) => <AddFeatureToggleForm title="Create feature toggle" history={history} />;
 | 
			
		||||
 | 
			
		||||
render.propTypes = {
 | 
			
		||||
    history: PropTypes.object.isRequired,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export default render;
 | 
			
		||||
 | 
			
		||||
@ -1,6 +1,11 @@
 | 
			
		||||
import React from 'react';
 | 
			
		||||
import FeatureListContainer from './../../component/feature/list-container';
 | 
			
		||||
import PropTypes from 'prop-types';
 | 
			
		||||
 | 
			
		||||
const render = () => <FeatureListContainer />;
 | 
			
		||||
const render = ({ history }) => <FeatureListContainer history={history} />;
 | 
			
		||||
 | 
			
		||||
render.propTypes = {
 | 
			
		||||
    history: PropTypes.object.isRequired,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export default render;
 | 
			
		||||
 | 
			
		||||
@ -4,11 +4,12 @@ import ViewFeatureToggle from './../../component/feature/view-container';
 | 
			
		||||
 | 
			
		||||
export default class Features extends PureComponent {
 | 
			
		||||
    static propTypes = {
 | 
			
		||||
        params: PropTypes.object.isRequired,
 | 
			
		||||
        match: PropTypes.object.isRequired,
 | 
			
		||||
        history: PropTypes.object.isRequired,
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    render() {
 | 
			
		||||
        const { params } = this.props;
 | 
			
		||||
        return <ViewFeatureToggle featureToggleName={params.name} activeTab={params.activeTab} />;
 | 
			
		||||
        const { match: { params }, history } = this.props;
 | 
			
		||||
        return <ViewFeatureToggle featureToggleName={params.name} activeTab={params.activeTab} history={history} />;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -2,10 +2,10 @@ import React from 'react';
 | 
			
		||||
import PropTypes from 'prop-types';
 | 
			
		||||
import HistoryListToggle from '../../component/history/history-list-toggle-container';
 | 
			
		||||
 | 
			
		||||
const render = ({ params }) => <HistoryListToggle toggleName={params.toggleName} />;
 | 
			
		||||
const render = ({ match: { params } }) => <HistoryListToggle toggleName={params.toggleName} />;
 | 
			
		||||
 | 
			
		||||
render.propTypes = {
 | 
			
		||||
    params: PropTypes.object.isRequired,
 | 
			
		||||
    match: PropTypes.object.isRequired,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export default render;
 | 
			
		||||
 | 
			
		||||
@ -2,10 +2,12 @@ import React from 'react';
 | 
			
		||||
import PropTypes from 'prop-types';
 | 
			
		||||
import ShowStrategy from '../../component/strategies/strategy-details-container';
 | 
			
		||||
 | 
			
		||||
const render = ({ params }) => <ShowStrategy strategyName={params.strategyName} activeTab={params.activeTab} />;
 | 
			
		||||
const render = ({ match: { params } }) => (
 | 
			
		||||
    <ShowStrategy strategyName={params.strategyName} activeTab={params.activeTab} />
 | 
			
		||||
);
 | 
			
		||||
 | 
			
		||||
render.propTypes = {
 | 
			
		||||
    params: PropTypes.object.isRequired,
 | 
			
		||||
    match: PropTypes.object.isRequired,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export default render;
 | 
			
		||||
 | 
			
		||||
@ -1,6 +1,11 @@
 | 
			
		||||
import React from 'react';
 | 
			
		||||
import FeatureListContainer from './../../component/feature/list-container';
 | 
			
		||||
import PropTypes from 'prop-types';
 | 
			
		||||
 | 
			
		||||
const render = () => <FeatureListContainer logout />;
 | 
			
		||||
const render = ({ history }) => <FeatureListContainer logout history={history} />;
 | 
			
		||||
 | 
			
		||||
render.propTypes = {
 | 
			
		||||
    history: PropTypes.object.isRequired,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export default render;
 | 
			
		||||
 | 
			
		||||
@ -1,5 +0,0 @@
 | 
			
		||||
{
 | 
			
		||||
    "env": {
 | 
			
		||||
        "jest": true
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -1732,14 +1732,6 @@ create-hmac@^1.1.0, create-hmac@^1.1.2, create-hmac@^1.1.4:
 | 
			
		||||
    safe-buffer "^5.0.1"
 | 
			
		||||
    sha.js "^2.4.8"
 | 
			
		||||
 | 
			
		||||
create-react-class@^15.5.1:
 | 
			
		||||
  version "15.6.3"
 | 
			
		||||
  resolved "https://registry.yarnpkg.com/create-react-class/-/create-react-class-15.6.3.tgz#2d73237fb3f970ae6ebe011a9e66f46dbca80036"
 | 
			
		||||
  dependencies:
 | 
			
		||||
    fbjs "^0.8.9"
 | 
			
		||||
    loose-envify "^1.3.1"
 | 
			
		||||
    object-assign "^4.1.1"
 | 
			
		||||
 | 
			
		||||
cross-spawn@^3.0.0:
 | 
			
		||||
  version "3.0.1"
 | 
			
		||||
  resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-3.0.1.tgz#1256037ecb9f0c5f79e3d6ef135e30770184b982"
 | 
			
		||||
@ -2030,10 +2022,6 @@ doctrine@^2.1.0:
 | 
			
		||||
  dependencies:
 | 
			
		||||
    esutils "^2.0.2"
 | 
			
		||||
 | 
			
		||||
dom-helpers@^3.2.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.1.0:
 | 
			
		||||
  version "0.1.0"
 | 
			
		||||
  resolved "https://registry.yarnpkg.com/dom-serializer/-/dom-serializer-0.1.0.tgz#073c697546ce0780ce23be4a28e293e40bc30c82"
 | 
			
		||||
@ -2674,7 +2662,7 @@ fbjs@^0.8.1:
 | 
			
		||||
    setimmediate "^1.0.5"
 | 
			
		||||
    ua-parser-js "^0.7.18"
 | 
			
		||||
 | 
			
		||||
fbjs@^0.8.16, fbjs@^0.8.9:
 | 
			
		||||
fbjs@^0.8.16:
 | 
			
		||||
  version "0.8.16"
 | 
			
		||||
  resolved "https://registry.yarnpkg.com/fbjs/-/fbjs-0.8.16.tgz#5e67432f550dc41b572bf55847b8aca64e5337db"
 | 
			
		||||
  dependencies:
 | 
			
		||||
@ -3188,13 +3176,14 @@ hawk@~6.0.2:
 | 
			
		||||
    hoek "4.x.x"
 | 
			
		||||
    sntp "2.x.x"
 | 
			
		||||
 | 
			
		||||
history@^3.0.0:
 | 
			
		||||
  version "3.3.0"
 | 
			
		||||
  resolved "https://registry.yarnpkg.com/history/-/history-3.3.0.tgz#fcedcce8f12975371545d735461033579a6dae9c"
 | 
			
		||||
history@^4.7.2:
 | 
			
		||||
  version "4.7.2"
 | 
			
		||||
  resolved "https://registry.yarnpkg.com/history/-/history-4.7.2.tgz#22b5c7f31633c5b8021c7f4a8a954ac139ee8d5b"
 | 
			
		||||
  dependencies:
 | 
			
		||||
    invariant "^2.2.1"
 | 
			
		||||
    loose-envify "^1.2.0"
 | 
			
		||||
    query-string "^4.2.2"
 | 
			
		||||
    resolve-pathname "^2.2.0"
 | 
			
		||||
    value-equal "^0.4.0"
 | 
			
		||||
    warning "^3.0.0"
 | 
			
		||||
 | 
			
		||||
hmac-drbg@^1.0.0:
 | 
			
		||||
@ -3213,10 +3202,6 @@ hoek@4.x.x:
 | 
			
		||||
  version "4.2.0"
 | 
			
		||||
  resolved "https://registry.yarnpkg.com/hoek/-/hoek-4.2.0.tgz#72d9d0754f7fe25ca2d01ad8f8f9a9449a89526d"
 | 
			
		||||
 | 
			
		||||
hoist-non-react-statics@^1.2.0:
 | 
			
		||||
  version "1.2.0"
 | 
			
		||||
  resolved "https://registry.yarnpkg.com/hoist-non-react-statics/-/hoist-non-react-statics-1.2.0.tgz#aa448cf0986d55cc40773b17174b7dd066cb7cfb"
 | 
			
		||||
 | 
			
		||||
hoist-non-react-statics@^2.2.1:
 | 
			
		||||
  version "2.3.1"
 | 
			
		||||
  resolved "https://registry.yarnpkg.com/hoist-non-react-statics/-/hoist-non-react-statics-2.3.1.tgz#343db84c6018c650778898240135a1420ee22ce0"
 | 
			
		||||
@ -3699,6 +3684,10 @@ is-wsl@^1.1.0:
 | 
			
		||||
  version "1.1.0"
 | 
			
		||||
  resolved "https://registry.yarnpkg.com/is-wsl/-/is-wsl-1.1.0.tgz#1f16e4aa22b04d1336b66188a66af3c600c3a66d"
 | 
			
		||||
 | 
			
		||||
isarray@0.0.1:
 | 
			
		||||
  version "0.0.1"
 | 
			
		||||
  resolved "https://registry.yarnpkg.com/isarray/-/isarray-0.0.1.tgz#8a18acfca9a8f4177e09abfc6038939b05d1eedf"
 | 
			
		||||
 | 
			
		||||
isarray@1.0.0, isarray@^1.0.0, isarray@~1.0.0:
 | 
			
		||||
  version "1.0.0"
 | 
			
		||||
  resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11"
 | 
			
		||||
@ -5062,6 +5051,12 @@ path-to-regexp@0.1.7:
 | 
			
		||||
  version "0.1.7"
 | 
			
		||||
  resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-0.1.7.tgz#df604178005f522f15eb4490e7247a1bfaa67f8c"
 | 
			
		||||
 | 
			
		||||
path-to-regexp@^1.7.0:
 | 
			
		||||
  version "1.7.0"
 | 
			
		||||
  resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-1.7.0.tgz#59fde0f435badacba103a84e9d3bc64e96b9937d"
 | 
			
		||||
  dependencies:
 | 
			
		||||
    isarray "0.0.1"
 | 
			
		||||
 | 
			
		||||
path-to-regexp@^2.1.0:
 | 
			
		||||
  version "2.1.0"
 | 
			
		||||
  resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-2.1.0.tgz#7e30f9f5b134bd6a28ffc2e3ef1e47075ac5259b"
 | 
			
		||||
@ -5238,7 +5233,7 @@ promise@^7.1.1:
 | 
			
		||||
  dependencies:
 | 
			
		||||
    asap "~2.0.3"
 | 
			
		||||
 | 
			
		||||
prop-types@^15.5.0, prop-types@^15.5.10, prop-types@^15.5.4, prop-types@^15.5.6, prop-types@^15.5.7, prop-types@^15.6.0:
 | 
			
		||||
prop-types@^15.5.0, prop-types@^15.5.10, prop-types@^15.5.4, prop-types@^15.5.7, prop-types@^15.6.0:
 | 
			
		||||
  version "15.6.0"
 | 
			
		||||
  resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.6.0.tgz#ceaf083022fc46b4a35f69e13ef75aed0d639856"
 | 
			
		||||
  dependencies:
 | 
			
		||||
@ -5246,7 +5241,7 @@ prop-types@^15.5.0, prop-types@^15.5.10, prop-types@^15.5.4, prop-types@^15.5.6,
 | 
			
		||||
    loose-envify "^1.3.1"
 | 
			
		||||
    object-assign "^4.1.1"
 | 
			
		||||
 | 
			
		||||
prop-types@^15.6.2:
 | 
			
		||||
prop-types@^15.6.1, prop-types@^15.6.2:
 | 
			
		||||
  version "15.6.2"
 | 
			
		||||
  resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.6.2.tgz#05d5ca77b4453e985d60fc7ff8c859094a497102"
 | 
			
		||||
  dependencies:
 | 
			
		||||
@ -5302,13 +5297,6 @@ qs@~6.4.0:
 | 
			
		||||
  version "6.4.0"
 | 
			
		||||
  resolved "https://registry.yarnpkg.com/qs/-/qs-6.4.0.tgz#13e26d28ad6b0ffaa91312cd3bf708ed351e7233"
 | 
			
		||||
 | 
			
		||||
query-string@^4.2.2:
 | 
			
		||||
  version "4.3.4"
 | 
			
		||||
  resolved "https://registry.yarnpkg.com/query-string/-/query-string-4.3.4.tgz#bbb693b9ca915c232515b228b1a02b609043dbeb"
 | 
			
		||||
  dependencies:
 | 
			
		||||
    object-assign "^4.1.0"
 | 
			
		||||
    strict-uri-encode "^1.0.0"
 | 
			
		||||
 | 
			
		||||
querystring-es3@^0.2.0:
 | 
			
		||||
  version "0.2.1"
 | 
			
		||||
  resolved "https://registry.yarnpkg.com/querystring-es3/-/querystring-es3-0.2.1.tgz#9ec61f79049875707d69414596fd907a4d711e73"
 | 
			
		||||
@ -5465,25 +5453,28 @@ react-redux@^5.0.6:
 | 
			
		||||
    loose-envify "^1.1.0"
 | 
			
		||||
    prop-types "^15.5.10"
 | 
			
		||||
 | 
			
		||||
react-router-scroll@^0.4.1:
 | 
			
		||||
  version "0.4.4"
 | 
			
		||||
  resolved "https://registry.yarnpkg.com/react-router-scroll/-/react-router-scroll-0.4.4.tgz#4d7b71c75b45ff296e4adca1e029a86e898a155d"
 | 
			
		||||
react-router-dom@^4.3.1:
 | 
			
		||||
  version "4.3.1"
 | 
			
		||||
  resolved "https://registry.yarnpkg.com/react-router-dom/-/react-router-dom-4.3.1.tgz#4c2619fc24c4fa87c9fd18f4fb4a43fe63fbd5c6"
 | 
			
		||||
  dependencies:
 | 
			
		||||
    prop-types "^15.6.0"
 | 
			
		||||
    scroll-behavior "^0.9.5"
 | 
			
		||||
    warning "^3.0.0"
 | 
			
		||||
    history "^4.7.2"
 | 
			
		||||
    invariant "^2.2.4"
 | 
			
		||||
    loose-envify "^1.3.1"
 | 
			
		||||
    prop-types "^15.6.1"
 | 
			
		||||
    react-router "^4.3.1"
 | 
			
		||||
    warning "^4.0.1"
 | 
			
		||||
 | 
			
		||||
react-router@^3.0.0:
 | 
			
		||||
  version "3.2.0"
 | 
			
		||||
  resolved "https://registry.yarnpkg.com/react-router/-/react-router-3.2.0.tgz#62b6279d589b70b34e265113e4c0a9261a02ed36"
 | 
			
		||||
react-router@^4.3.1:
 | 
			
		||||
  version "4.3.1"
 | 
			
		||||
  resolved "https://registry.yarnpkg.com/react-router/-/react-router-4.3.1.tgz#aada4aef14c809cb2e686b05cee4742234506c4e"
 | 
			
		||||
  dependencies:
 | 
			
		||||
    create-react-class "^15.5.1"
 | 
			
		||||
    history "^3.0.0"
 | 
			
		||||
    hoist-non-react-statics "^1.2.0"
 | 
			
		||||
    invariant "^2.2.1"
 | 
			
		||||
    loose-envify "^1.2.0"
 | 
			
		||||
    prop-types "^15.5.6"
 | 
			
		||||
    warning "^3.0.0"
 | 
			
		||||
    history "^4.7.2"
 | 
			
		||||
    hoist-non-react-statics "^2.5.0"
 | 
			
		||||
    invariant "^2.2.4"
 | 
			
		||||
    loose-envify "^1.3.1"
 | 
			
		||||
    path-to-regexp "^1.7.0"
 | 
			
		||||
    prop-types "^15.6.1"
 | 
			
		||||
    warning "^4.0.1"
 | 
			
		||||
 | 
			
		||||
react-test-renderer@^16.0.0-0, react-test-renderer@^16.2.0:
 | 
			
		||||
  version "16.2.0"
 | 
			
		||||
@ -5852,6 +5843,10 @@ resolve-from@^3.0.0:
 | 
			
		||||
  version "3.0.0"
 | 
			
		||||
  resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-3.0.0.tgz#b22c7af7d9d6881bc8b6e653335eebcb0a188748"
 | 
			
		||||
 | 
			
		||||
resolve-pathname@^2.2.0:
 | 
			
		||||
  version "2.2.0"
 | 
			
		||||
  resolved "https://registry.yarnpkg.com/resolve-pathname/-/resolve-pathname-2.2.0.tgz#7e9ae21ed815fd63ab189adeee64dc831eefa879"
 | 
			
		||||
 | 
			
		||||
resolve-url@^0.2.1:
 | 
			
		||||
  version "0.2.1"
 | 
			
		||||
  resolved "https://registry.yarnpkg.com/resolve-url/-/resolve-url-0.2.1.tgz#2c637fe77c893afd2a663fe21aa9080068e2052a"
 | 
			
		||||
@ -5967,13 +5962,6 @@ schema-utils@^0.4.5:
 | 
			
		||||
    ajv "^6.1.0"
 | 
			
		||||
    ajv-keywords "^3.1.0"
 | 
			
		||||
 | 
			
		||||
scroll-behavior@^0.9.5:
 | 
			
		||||
  version "0.9.9"
 | 
			
		||||
  resolved "https://registry.yarnpkg.com/scroll-behavior/-/scroll-behavior-0.9.9.tgz#ebfe0658455b82ad885b66195215416674dacce2"
 | 
			
		||||
  dependencies:
 | 
			
		||||
    dom-helpers "^3.2.1"
 | 
			
		||||
    invariant "^2.2.2"
 | 
			
		||||
 | 
			
		||||
scss-tokenizer@^0.2.3:
 | 
			
		||||
  version "0.2.3"
 | 
			
		||||
  resolved "https://registry.yarnpkg.com/scss-tokenizer/-/scss-tokenizer-0.2.3.tgz#8eb06db9a9723333824d3f5530641149847ce5d1"
 | 
			
		||||
@ -6351,10 +6339,6 @@ stream-http@^2.7.2:
 | 
			
		||||
    to-arraybuffer "^1.0.0"
 | 
			
		||||
    xtend "^4.0.0"
 | 
			
		||||
 | 
			
		||||
strict-uri-encode@^1.0.0:
 | 
			
		||||
  version "1.1.0"
 | 
			
		||||
  resolved "https://registry.yarnpkg.com/strict-uri-encode/-/strict-uri-encode-1.1.0.tgz#279b225df1d582b1f54e65addd4352e18faa0713"
 | 
			
		||||
 | 
			
		||||
string-length@^2.0.0:
 | 
			
		||||
  version "2.0.0"
 | 
			
		||||
  resolved "https://registry.yarnpkg.com/string-length/-/string-length-2.0.0.tgz#d40dbb686a3ace960c1cffca562bf2c45f8363ed"
 | 
			
		||||
@ -6795,6 +6779,10 @@ validate-npm-package-license@^3.0.1:
 | 
			
		||||
    spdx-correct "~1.0.0"
 | 
			
		||||
    spdx-expression-parse "~1.0.0"
 | 
			
		||||
 | 
			
		||||
value-equal@^0.4.0:
 | 
			
		||||
  version "0.4.0"
 | 
			
		||||
  resolved "https://registry.yarnpkg.com/value-equal/-/value-equal-0.4.0.tgz#c5bdd2f54ee093c04839d71ce2e4758a6890abc7"
 | 
			
		||||
 | 
			
		||||
vary@~1.1.2:
 | 
			
		||||
  version "1.1.2"
 | 
			
		||||
  resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc"
 | 
			
		||||
@ -6831,6 +6819,12 @@ warning@^3.0.0:
 | 
			
		||||
  dependencies:
 | 
			
		||||
    loose-envify "^1.0.0"
 | 
			
		||||
 | 
			
		||||
warning@^4.0.1:
 | 
			
		||||
  version "4.0.1"
 | 
			
		||||
  resolved "https://registry.yarnpkg.com/warning/-/warning-4.0.1.tgz#66ce376b7fbfe8a887c22bdf0e7349d73d397745"
 | 
			
		||||
  dependencies:
 | 
			
		||||
    loose-envify "^1.0.0"
 | 
			
		||||
 | 
			
		||||
watch@~0.18.0:
 | 
			
		||||
  version "0.18.0"
 | 
			
		||||
  resolved "https://registry.yarnpkg.com/watch/-/watch-0.18.0.tgz#28095476c6df7c90c963138990c0a5423eb4b986"
 | 
			
		||||
 | 
			
		||||
		Loading…
	
		Reference in New Issue
	
	Block a user