@ -1,7 +1,7 @@
|
|||||||
// @flow
|
// @flow
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { observer } from 'mobx-react';
|
import { observer } from 'mobx-react';
|
||||||
import Link from 'react-router/lib/Link';
|
import { Link } from 'react-router-dom';
|
||||||
|
|
||||||
import DocumentLink from './components/DocumentLink';
|
import DocumentLink from './components/DocumentLink';
|
||||||
|
|
||||||
|
@ -3,7 +3,7 @@ import React from 'react';
|
|||||||
import { observer } from 'mobx-react';
|
import { observer } from 'mobx-react';
|
||||||
|
|
||||||
import moment from 'moment';
|
import moment from 'moment';
|
||||||
import Link from 'react-router/lib/Link';
|
import { Link } from 'react-router-dom';
|
||||||
|
|
||||||
import styles from './DocumentLink.scss';
|
import styles from './DocumentLink.scss';
|
||||||
|
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
// @flow
|
// @flow
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { toJS } from 'mobx';
|
import { toJS } from 'mobx';
|
||||||
import { Link } from 'react-router';
|
import { Link } from 'react-router-dom';
|
||||||
|
|
||||||
import styles from './DocumentPreview.scss';
|
import styles from './DocumentPreview.scss';
|
||||||
|
|
||||||
|
@ -1,31 +1,20 @@
|
|||||||
// @flow
|
// @flow
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { browserHistory } from 'react-router';
|
|
||||||
|
|
||||||
import styles from './DropdownMenu.scss';
|
import styles from './DropdownMenu.scss';
|
||||||
|
|
||||||
class MenuItem extends React.Component {
|
const MenuItem = ({
|
||||||
onClick = () => {
|
onClick,
|
||||||
if (this.props.to) {
|
children,
|
||||||
browserHistory.push(this.props.to);
|
}: {
|
||||||
} else {
|
onClick?: Function,
|
||||||
this.props.onClick();
|
children?: React.Element<any>,
|
||||||
}
|
}) => {
|
||||||
};
|
return (
|
||||||
|
<div className={styles.menuItem} onClick={onClick}>
|
||||||
render() {
|
{children}
|
||||||
return (
|
</div>
|
||||||
<div className={styles.menuItem} onClick={this.onClick}>
|
);
|
||||||
{this.props.children}
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
MenuItem.propTypes = {
|
|
||||||
onClick: React.PropTypes.func,
|
|
||||||
to: React.PropTypes.string,
|
|
||||||
children: React.PropTypes.node.isRequired,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
//
|
//
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
// @flow
|
// @flow
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { browserHistory, Link } from 'react-router';
|
import { Link, withRouter } from 'react-router-dom';
|
||||||
import Helmet from 'react-helmet';
|
import Helmet from 'react-helmet';
|
||||||
import styled from 'styled-components';
|
import styled from 'styled-components';
|
||||||
import { observer, inject } from 'mobx-react';
|
import { observer, inject } from 'mobx-react';
|
||||||
@ -9,7 +9,9 @@ import keydown from 'react-keydown';
|
|||||||
import classNames from 'classnames/bind';
|
import classNames from 'classnames/bind';
|
||||||
import searchIcon from 'assets/icons/search.svg';
|
import searchIcon from 'assets/icons/search.svg';
|
||||||
import { Flex } from 'reflexbox';
|
import { Flex } from 'reflexbox';
|
||||||
|
import { textColor } from 'styles/constants.scss';
|
||||||
import styles from './Layout.scss';
|
import styles from './Layout.scss';
|
||||||
|
|
||||||
import DropdownMenu, { MenuItem } from 'components/DropdownMenu';
|
import DropdownMenu, { MenuItem } from 'components/DropdownMenu';
|
||||||
import LoadingIndicator from 'components/LoadingIndicator';
|
import LoadingIndicator from 'components/LoadingIndicator';
|
||||||
import UserStore from 'stores/UserStore';
|
import UserStore from 'stores/UserStore';
|
||||||
@ -17,6 +19,7 @@ import UserStore from 'stores/UserStore';
|
|||||||
const cx = classNames.bind(styles);
|
const cx = classNames.bind(styles);
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
|
history: Object,
|
||||||
children?: ?React.Element<any>,
|
children?: ?React.Element<any>,
|
||||||
actions?: ?React.Element<any>,
|
actions?: ?React.Element<any>,
|
||||||
title?: ?React.Element<any>,
|
title?: ?React.Element<any>,
|
||||||
@ -36,19 +39,23 @@ type Props = {
|
|||||||
|
|
||||||
@keydown(['/', 't'])
|
@keydown(['/', 't'])
|
||||||
search() {
|
search() {
|
||||||
// if (!this.props.user) return;
|
if (!this.props.user) return;
|
||||||
_.defer(() => browserHistory.push('/search'));
|
_.defer(() => this.props.history.push('/search'));
|
||||||
}
|
}
|
||||||
|
|
||||||
@keydown(['d'])
|
@keydown(['d'])
|
||||||
dashboard() {
|
dashboard() {
|
||||||
// if (!this.props.user) return;
|
if (!this.props.user) return;
|
||||||
_.defer(() => browserHistory.push('/'));
|
_.defer(() => this.props.history.push('/'));
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const user = this.props.user;
|
const user = this.props.user;
|
||||||
|
|
||||||
|
const handleLogout = () => {
|
||||||
|
user.logout(() => this.props.history.push('/'));
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={styles.container}>
|
<div className={styles.container}>
|
||||||
<Helmet
|
<Helmet
|
||||||
@ -83,21 +90,28 @@ type Props = {
|
|||||||
<Flex>
|
<Flex>
|
||||||
{this.props.search &&
|
{this.props.search &&
|
||||||
<Flex>
|
<Flex>
|
||||||
<div
|
<Link to="/search">
|
||||||
onClick={this.search}
|
<div className={styles.search} title="Search (/)">
|
||||||
className={styles.search}
|
<img
|
||||||
title="Search (/)"
|
src={searchIcon}
|
||||||
>
|
alt="Search"
|
||||||
<img src={searchIcon} alt="Search" />
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
</Link>
|
||||||
</Flex>}
|
</Flex>}
|
||||||
<DropdownMenu label={<Avatar src={user.user.avatarUrl} />}>
|
<DropdownMenu label={<Avatar src={user.user.avatarUrl} />}>
|
||||||
<MenuItem to="/settings">Settings</MenuItem>
|
<MenuLink to="/settings">
|
||||||
<MenuItem to="/keyboard-shortcuts">
|
<MenuItem>Settings</MenuItem>
|
||||||
Keyboard shortcuts
|
</MenuLink>
|
||||||
</MenuItem>
|
<MenuLink to="/keyboard-shortcuts">
|
||||||
<MenuItem to="/developers">API</MenuItem>
|
<MenuItem>
|
||||||
<MenuItem onClick={user.logout}>Logout</MenuItem>
|
Keyboard shortcuts
|
||||||
|
</MenuItem>
|
||||||
|
</MenuLink>
|
||||||
|
<MenuLink to="/developers">
|
||||||
|
<MenuItem>API</MenuItem>
|
||||||
|
</MenuLink>
|
||||||
|
<MenuItem onClick={handleLogout}>Logout</MenuItem>
|
||||||
</DropdownMenu>
|
</DropdownMenu>
|
||||||
</Flex>}
|
</Flex>}
|
||||||
</Flex>
|
</Flex>
|
||||||
@ -118,4 +132,8 @@ const Avatar = styled.img`
|
|||||||
border-radius: 50%;
|
border-radius: 50%;
|
||||||
`;
|
`;
|
||||||
|
|
||||||
export default inject('user')(Layout);
|
const MenuLink = styled(Link)`
|
||||||
|
color: ${textColor};
|
||||||
|
`;
|
||||||
|
|
||||||
|
export default withRouter(inject('user')(Layout));
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
// @flow
|
// @flow
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { observer } from 'mobx-react';
|
import { observer } from 'mobx-react';
|
||||||
|
import { withRouter } from 'react-router-dom';
|
||||||
|
|
||||||
import { Flex } from 'reflexbox';
|
import { Flex } from 'reflexbox';
|
||||||
import Tree from 'components/Tree';
|
import Tree from 'components/Tree';
|
||||||
@ -18,6 +19,7 @@ type Props = {
|
|||||||
navigationTree: Object,
|
navigationTree: Object,
|
||||||
onNavigationUpdate: Function,
|
onNavigationUpdate: Function,
|
||||||
onNodeCollapse: Function,
|
onNodeCollapse: Function,
|
||||||
|
history: Object,
|
||||||
};
|
};
|
||||||
|
|
||||||
@observer class Sidebar extends React.Component {
|
@observer class Sidebar extends React.Component {
|
||||||
@ -47,6 +49,7 @@ type Props = {
|
|||||||
allowUpdates={this.store.isEditing}
|
allowUpdates={this.store.isEditing}
|
||||||
onChange={this.props.onNavigationUpdate}
|
onChange={this.props.onNavigationUpdate}
|
||||||
onCollapse={this.props.onNodeCollapse}
|
onCollapse={this.props.onNodeCollapse}
|
||||||
|
history={this.props.history}
|
||||||
/>
|
/>
|
||||||
</Flex>
|
</Flex>
|
||||||
<Flex auto className={styles.actions}>
|
<Flex auto className={styles.actions}>
|
||||||
@ -79,4 +82,4 @@ type Props = {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default Sidebar;
|
export default withRouter(Sidebar);
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
/* eslint-disable */
|
/* eslint-disable */
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import history from 'utils/History';
|
|
||||||
import styles from './Tree.scss';
|
import styles from './Tree.scss';
|
||||||
import classNames from 'classnames/bind';
|
import classNames from 'classnames/bind';
|
||||||
const cx = classNames.bind(styles);
|
const cx = classNames.bind(styles);
|
||||||
@ -60,6 +60,7 @@ class Node extends React.Component {
|
|||||||
paddingLeft={this.props.paddingLeft}
|
paddingLeft={this.props.paddingLeft}
|
||||||
onCollapse={this.props.onCollapse}
|
onCollapse={this.props.onCollapse}
|
||||||
onDragStart={this.props.onDragStart}
|
onDragStart={this.props.onDragStart}
|
||||||
|
history={this.props.history}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
})}
|
})}
|
||||||
@ -77,8 +78,7 @@ class Node extends React.Component {
|
|||||||
onClick = () => {
|
onClick = () => {
|
||||||
const index = this.props.index;
|
const index = this.props.index;
|
||||||
const node = index.node;
|
const node = index.node;
|
||||||
|
if (!this.isModifying()) this.props.history.push(node.url);
|
||||||
if (!this.isModifying()) history.push(node.url);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
|
@ -13,6 +13,7 @@ export default React.createClass({
|
|||||||
paddingLeft: React.PropTypes.number,
|
paddingLeft: React.PropTypes.number,
|
||||||
onCollapse: React.PropTypes.func,
|
onCollapse: React.PropTypes.func,
|
||||||
allowUpdates: React.PropTypes.bool,
|
allowUpdates: React.PropTypes.bool,
|
||||||
|
history: React.PropTypes.object,
|
||||||
},
|
},
|
||||||
|
|
||||||
getDefaultProps() {
|
getDefaultProps() {
|
||||||
@ -93,6 +94,7 @@ export default React.createClass({
|
|||||||
onDragStart={this.dragStart}
|
onDragStart={this.dragStart}
|
||||||
onCollapse={this.toggleCollapse}
|
onCollapse={this.toggleCollapse}
|
||||||
dragging={dragging && dragging.id}
|
dragging={dragging && dragging.id}
|
||||||
|
history={this.props.history}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
@ -2,10 +2,13 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { render } from 'react-dom';
|
import { render } from 'react-dom';
|
||||||
import { Provider } from 'mobx-react';
|
import { Provider } from 'mobx-react';
|
||||||
import Router from 'react-router/lib/Router';
|
import {
|
||||||
import Route from 'react-router/lib/Route';
|
BrowserRouter as Router,
|
||||||
import IndexRoute from 'react-router/lib/IndexRoute';
|
Switch,
|
||||||
import History from 'utils/History';
|
Route,
|
||||||
|
Redirect,
|
||||||
|
} from 'react-router-dom';
|
||||||
|
import { Flex } from 'reflexbox';
|
||||||
|
|
||||||
import stores from 'stores';
|
import stores from 'stores';
|
||||||
|
|
||||||
@ -34,80 +37,66 @@ if (__DEV__) {
|
|||||||
DevTools = require('mobx-react-devtools').default; // eslint-disable-line global-require
|
DevTools = require('mobx-react-devtools').default; // eslint-disable-line global-require
|
||||||
}
|
}
|
||||||
|
|
||||||
function requireAuth(nextState, replace) {
|
type AuthProps = {
|
||||||
if (!stores.user.authenticated) {
|
children?: React.Element<any>,
|
||||||
replace({
|
};
|
||||||
pathname: '/',
|
|
||||||
state: { nextPathname: nextState.location.pathname },
|
const Auth = ({ children }: AuthProps) => {
|
||||||
});
|
if (stores.user.authenticated) {
|
||||||
|
return <Flex auto>{children}</Flex>;
|
||||||
|
} else {
|
||||||
|
return <Redirect to="/" />;
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
|
const notFoundSearch = () => <Search notFound />;
|
||||||
|
const KeyboardShortcuts = () => (
|
||||||
|
<Flatpage title="Keyboard shortcuts" content={flatpages.keyboard} />
|
||||||
|
);
|
||||||
|
const Api = () => <Flatpage title="API" content={flatpages.api} />;
|
||||||
|
const DocumentEdit = () => <Document editDocument />;
|
||||||
|
const DocumentNew = () => <Document newDocument />;
|
||||||
|
const DocumentNewChild = () => <Document newChildDocument />;
|
||||||
|
|
||||||
render(
|
render(
|
||||||
<div style={{ display: 'flex', flex: 1, height: '100%' }}>
|
<div style={{ display: 'flex', flex: 1, height: '100%' }}>
|
||||||
<Provider {...stores}>
|
<Provider {...stores}>
|
||||||
<Router history={History}>
|
<Router>
|
||||||
<Route path="/">
|
<Switch>
|
||||||
<IndexRoute component={Home} />
|
<Route exact path="/" component={Home} />
|
||||||
|
|
||||||
<Route
|
<Auth>
|
||||||
path="/dashboard"
|
<Switch>
|
||||||
component={Dashboard}
|
<Route exact path="/dashboard" component={Dashboard} />
|
||||||
onEnter={requireAuth}
|
<Route exact path="/collections/:id" component={Atlas} />
|
||||||
/>
|
<Route exact path="/d/:id" component={Document} />
|
||||||
<Route
|
<Route exact path="/d/:id/edit" component={DocumentEdit} />
|
||||||
path="/collections/:id"
|
<Route
|
||||||
component={Atlas}
|
exact
|
||||||
onEnter={requireAuth}
|
path="/collections/:id/new"
|
||||||
/>
|
component={DocumentNew}
|
||||||
<Route
|
/>
|
||||||
path="/collections/:id/new"
|
<Route exact path="/d/:id/new" component={DocumentNewChild} />
|
||||||
component={Document}
|
|
||||||
onEnter={requireAuth}
|
|
||||||
newDocument
|
|
||||||
/>
|
|
||||||
<Route path="/d/:id" component={Document} onEnter={requireAuth} />
|
|
||||||
<Route
|
|
||||||
path="/d/:id/edit"
|
|
||||||
component={Document}
|
|
||||||
onEnter={requireAuth}
|
|
||||||
editDocument
|
|
||||||
/>
|
|
||||||
<Route
|
|
||||||
path="/d/:id/new"
|
|
||||||
component={Document}
|
|
||||||
onEnter={requireAuth}
|
|
||||||
newChildDocument
|
|
||||||
/>
|
|
||||||
|
|
||||||
<Route path="/search" component={Search} onEnter={requireAuth} />
|
<Route exact path="/search" component={Search} />
|
||||||
<Route path="/settings" component={Settings} onEnter={requireAuth} />
|
<Route exact path="/settings" component={Settings} />
|
||||||
|
|
||||||
<Route path="/auth/slack" component={SlackAuth} />
|
<Route exact path="/auth/slack" component={SlackAuth} />
|
||||||
<Route
|
<Route exact path="/auth/slack/commands" component={SlackAuth} />
|
||||||
path="/auth/slack/commands"
|
<Route exact path="/auth/error" component={ErrorAuth} />
|
||||||
component={SlackAuth}
|
|
||||||
apiPath="/auth.slackCommands"
|
|
||||||
/>
|
|
||||||
<Route path="/auth/error" component={ErrorAuth} />
|
|
||||||
|
|
||||||
<Flatpage
|
<Route
|
||||||
path="/keyboard-shortcuts"
|
exact
|
||||||
component={Flatpage}
|
path="/keyboard-shortcuts"
|
||||||
title="Keyboard shortcuts"
|
component={KeyboardShortcuts}
|
||||||
content={flatpages.keyboard}
|
/>
|
||||||
/>
|
<Route exact path="/developers" component={Api} />
|
||||||
|
|
||||||
<Flatpage
|
<Route path="/404" component={Error404} />
|
||||||
path="/developers"
|
<Route component={notFoundSearch} />
|
||||||
component={Flatpage}
|
</Switch>
|
||||||
title="API"
|
</Auth>
|
||||||
content={flatpages.api}
|
</Switch>
|
||||||
/>
|
|
||||||
|
|
||||||
<Route path="/404" component={Error404} />
|
|
||||||
<Route path="*" component={Search} sceneType="notFound" />
|
|
||||||
</Route>
|
|
||||||
</Router>
|
</Router>
|
||||||
</Provider>
|
</Provider>
|
||||||
{DevTools && <DevTools position={{ bottom: 0, right: 0 }} />}
|
{DevTools && <DevTools position={{ bottom: 0, right: 0 }} />}
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
// @flow
|
// @flow
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { observer } from 'mobx-react';
|
import { observer } from 'mobx-react';
|
||||||
import { browserHistory } from 'react-router';
|
|
||||||
import keydown from 'react-keydown';
|
import keydown from 'react-keydown';
|
||||||
import ReactCSSTransitionGroup from 'react-addons-css-transition-group';
|
import ReactCSSTransitionGroup from 'react-addons-css-transition-group';
|
||||||
import _ from 'lodash';
|
import _ from 'lodash';
|
||||||
@ -21,6 +20,8 @@ import styles from './Atlas.scss';
|
|||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
params: Object,
|
params: Object,
|
||||||
|
history: Object,
|
||||||
|
match: Object,
|
||||||
keydown: Object,
|
keydown: Object,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -30,11 +31,11 @@ class Atlas extends React.Component {
|
|||||||
props: Props;
|
props: Props;
|
||||||
|
|
||||||
componentDidMount = () => {
|
componentDidMount = () => {
|
||||||
const { id } = this.props.params;
|
const { id } = this.props.match.params;
|
||||||
store.fetchCollection(id, data => {
|
store.fetchCollection(id, data => {
|
||||||
// Forward directly to root document
|
// Forward directly to root document
|
||||||
if (data.type === 'atlas') {
|
if (data.type === 'atlas') {
|
||||||
browserHistory.replace(data.navigationTree.url);
|
this.props.history.replace(data.navigationTree.url);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
@ -50,7 +51,7 @@ class Atlas extends React.Component {
|
|||||||
|
|
||||||
onCreate = (event: Event) => {
|
onCreate = (event: Event) => {
|
||||||
if (event) event.preventDefault();
|
if (event) event.preventDefault();
|
||||||
store.collection && browserHistory.push(`${store.collection.url}/new`);
|
store.collection && this.props.history.push(`${store.collection.url}/new`);
|
||||||
};
|
};
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
// @flow
|
// @flow
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { observer, inject } from 'mobx-react';
|
import { observer, inject } from 'mobx-react';
|
||||||
import { withRouter } from 'react-router';
|
import { withRouter } from 'react-router-dom';
|
||||||
import { Flex } from 'reflexbox';
|
import { Flex } from 'reflexbox';
|
||||||
|
|
||||||
import DashboardStore from './DashboardStore';
|
import DashboardStore from './DashboardStore';
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
import React, { Component } from 'react';
|
import React, { Component } from 'react';
|
||||||
import get from 'lodash/get';
|
import get from 'lodash/get';
|
||||||
import { observer } from 'mobx-react';
|
import { observer } from 'mobx-react';
|
||||||
import { browserHistory, withRouter } from 'react-router';
|
import { withRouter } from 'react-router';
|
||||||
import { Flex } from 'reflexbox';
|
import { Flex } from 'reflexbox';
|
||||||
|
|
||||||
import DocumentStore from './DocumentStore';
|
import DocumentStore from './DocumentStore';
|
||||||
@ -19,10 +19,12 @@ Are you sure you want to discard them?
|
|||||||
`;
|
`;
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
route: Object,
|
match: Object,
|
||||||
router: Object,
|
history: Object,
|
||||||
params: Object,
|
|
||||||
keydown: Object,
|
keydown: Object,
|
||||||
|
editDocument?: boolean,
|
||||||
|
newChildDocument?: boolean,
|
||||||
|
editDocument?: boolean,
|
||||||
};
|
};
|
||||||
|
|
||||||
@withRouter
|
@withRouter
|
||||||
@ -33,39 +35,39 @@ class Document extends Component {
|
|||||||
|
|
||||||
constructor(props: Props) {
|
constructor(props: Props) {
|
||||||
super(props);
|
super(props);
|
||||||
this.store = new DocumentStore({});
|
this.store = new DocumentStore({ history: this.props.history });
|
||||||
}
|
}
|
||||||
|
|
||||||
componentDidMount = () => {
|
componentDidMount = () => {
|
||||||
if (this.props.route.newDocument) {
|
if (this.props.newDocument) {
|
||||||
this.store.collectionId = this.props.params.id;
|
this.store.collectionId = this.props.match.params.id;
|
||||||
this.store.newDocument = true;
|
this.store.newDocument = true;
|
||||||
} else if (this.props.route.editDocument) {
|
} else if (this.props.editDocument) {
|
||||||
this.store.documentId = this.props.params.id;
|
this.store.documentId = this.props.match.params.id;
|
||||||
this.store.fetchDocument();
|
this.store.fetchDocument();
|
||||||
} else if (this.props.route.newChildDocument) {
|
} else if (this.props.newChildDocument) {
|
||||||
this.store.documentId = this.props.params.id;
|
this.store.documentId = this.props.match.params.id;
|
||||||
this.store.newChildDocument = true;
|
this.store.newChildDocument = true;
|
||||||
this.store.fetchDocument();
|
this.store.fetchDocument();
|
||||||
} else {
|
} else {
|
||||||
this.store.documentId = this.props.params.id;
|
this.store.documentId = this.props.match.params.id;
|
||||||
this.store.newDocument = false;
|
this.store.newDocument = false;
|
||||||
this.store.fetchDocument();
|
this.store.fetchDocument();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Prevent user from accidentally leaving with unsaved changes
|
// // Prevent user from accidentally leaving with unsaved changes
|
||||||
const remove = this.props.router.setRouteLeaveHook(this.props.route, () => {
|
// const remove = this.props.router.setRouteLeaveHook(this.props.route, () => {
|
||||||
if (this.store.hasPendingChanges) {
|
// if (this.store.hasPendingChanges) {
|
||||||
return confirm(DISCARD_CHANGES);
|
// return confirm(DISCARD_CHANGES);
|
||||||
}
|
// }
|
||||||
remove();
|
// remove();
|
||||||
return null;
|
// return null;
|
||||||
});
|
// });
|
||||||
};
|
};
|
||||||
|
|
||||||
onEdit = () => {
|
onEdit = () => {
|
||||||
const url = `${this.store.document.url}/edit`;
|
const url = `${this.store.document.url}/edit`;
|
||||||
browserHistory.push(url);
|
this.props.history.push(url);
|
||||||
};
|
};
|
||||||
|
|
||||||
onSave = (options: { redirect?: boolean } = {}) => {
|
onSave = (options: { redirect?: boolean } = {}) => {
|
||||||
@ -85,20 +87,22 @@ class Document extends Component {
|
|||||||
};
|
};
|
||||||
|
|
||||||
onCancel = () => {
|
onCancel = () => {
|
||||||
browserHistory.goBack();
|
this.props.history.goBack();
|
||||||
};
|
};
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const { route } = this.props;
|
const isNew = this.props.newDocument || this.props.newChildDocument;
|
||||||
const isNew = route.newDocument || route.newChildDocument;
|
const isEditing = this.props.editDocument;
|
||||||
const isEditing = route.editDocument;
|
|
||||||
const title = (
|
const title = (
|
||||||
<Breadcrumbs
|
<Breadcrumbs
|
||||||
document={this.store.document}
|
document={this.store.document}
|
||||||
pathToDocument={this.store.pathToDocument}
|
pathToDocument={this.store.pathToDocument}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
const titleText = `${get(this.store, 'document.collection.name')} - ${get(this.store, 'document.title')}`;
|
|
||||||
|
const titleText =
|
||||||
|
this.store.document &&
|
||||||
|
`${get(this.store, 'document.collection.name')} - ${get(this.store, 'document.title')}`;
|
||||||
|
|
||||||
const actions = (
|
const actions = (
|
||||||
<Flex>
|
<Flex>
|
||||||
@ -107,7 +111,7 @@ class Document extends Component {
|
|||||||
? <SaveAction
|
? <SaveAction
|
||||||
onClick={this.onSave}
|
onClick={this.onSave}
|
||||||
disabled={this.store.isSaving}
|
disabled={this.store.isSaving}
|
||||||
isNew={isNew}
|
isNew={!!isNew}
|
||||||
/>
|
/>
|
||||||
: <a onClick={this.onEdit}>Edit</a>}
|
: <a onClick={this.onEdit}>Edit</a>}
|
||||||
</HeaderAction>
|
</HeaderAction>
|
||||||
@ -140,7 +144,7 @@ class Document extends Component {
|
|||||||
onChange={this.store.updateText}
|
onChange={this.store.updateText}
|
||||||
onSave={this.onSave}
|
onSave={this.onSave}
|
||||||
onCancel={this.onCancel}
|
onCancel={this.onCancel}
|
||||||
readOnly={!this.props.route.editDocument}
|
readOnly={!this.props.editDocument}
|
||||||
/>}
|
/>}
|
||||||
</Layout>
|
</Layout>
|
||||||
);
|
);
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
// @flow
|
// @flow
|
||||||
import { observable, action, computed, toJS } from 'mobx';
|
import { observable, action, computed, toJS } from 'mobx';
|
||||||
import { browserHistory } from 'react-router';
|
|
||||||
import get from 'lodash/get';
|
import get from 'lodash/get';
|
||||||
import invariant from 'invariant';
|
import invariant from 'invariant';
|
||||||
import { client } from 'utils/ApiClient';
|
import { client } from 'utils/ApiClient';
|
||||||
@ -23,6 +22,10 @@ const parseHeader = text => {
|
|||||||
return '';
|
return '';
|
||||||
};
|
};
|
||||||
|
|
||||||
|
type Options = {
|
||||||
|
history: Object,
|
||||||
|
};
|
||||||
|
|
||||||
class DocumentStore {
|
class DocumentStore {
|
||||||
@observable collapsedNodes: string[] = [];
|
@observable collapsedNodes: string[] = [];
|
||||||
@observable documentId = null;
|
@observable documentId = null;
|
||||||
@ -38,6 +41,8 @@ class DocumentStore {
|
|||||||
@observable isSaving: boolean = false;
|
@observable isSaving: boolean = false;
|
||||||
@observable isUploading: boolean = false;
|
@observable isUploading: boolean = false;
|
||||||
|
|
||||||
|
history: Object;
|
||||||
|
|
||||||
/* Computed */
|
/* Computed */
|
||||||
|
|
||||||
@computed get isCollection(): boolean {
|
@computed get isCollection(): boolean {
|
||||||
@ -136,7 +141,7 @@ class DocumentStore {
|
|||||||
const { url } = res.data;
|
const { url } = res.data;
|
||||||
|
|
||||||
this.hasPendingChanges = false;
|
this.hasPendingChanges = false;
|
||||||
if (redirect) browserHistory.push(url);
|
if (redirect) this.history.push(url);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error('Something went wrong');
|
console.error('Something went wrong');
|
||||||
}
|
}
|
||||||
@ -162,7 +167,7 @@ class DocumentStore {
|
|||||||
const { url } = res.data;
|
const { url } = res.data;
|
||||||
|
|
||||||
this.hasPendingChanges = false;
|
this.hasPendingChanges = false;
|
||||||
if (redirect) browserHistory.push(url);
|
if (redirect) this.history.push(url);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error('Something went wrong');
|
console.error('Something went wrong');
|
||||||
}
|
}
|
||||||
@ -174,7 +179,7 @@ class DocumentStore {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
await client.post('/documents.delete', { id: this.documentId });
|
await client.post('/documents.delete', { id: this.documentId });
|
||||||
browserHistory.push(this.document.collection.id);
|
this.history.push(this.document.collection.url);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error('Something went wrong');
|
console.error('Something went wrong');
|
||||||
}
|
}
|
||||||
@ -192,6 +197,10 @@ class DocumentStore {
|
|||||||
@action updateUploading = (uploading: boolean) => {
|
@action updateUploading = (uploading: boolean) => {
|
||||||
this.isUploading = uploading;
|
this.isUploading = uploading;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
constructor(options: Options) {
|
||||||
|
this.history = options.history;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default DocumentStore;
|
export default DocumentStore;
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
// @flow
|
// @flow
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { Link } from 'react-router';
|
import { Link } from 'react-router-dom';
|
||||||
import type { Document, NavigationNode } from 'types';
|
import type { Document, NavigationNode } from 'types';
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
|
@ -2,13 +2,14 @@
|
|||||||
import React, { Component } from 'react';
|
import React, { Component } from 'react';
|
||||||
import invariant from 'invariant';
|
import invariant from 'invariant';
|
||||||
import get from 'lodash/get';
|
import get from 'lodash/get';
|
||||||
import { browserHistory } from 'react-router';
|
import { withRouter } from 'react-router-dom';
|
||||||
import { observer } from 'mobx-react';
|
import { observer } from 'mobx-react';
|
||||||
import type { Document as DocumentType } from 'types';
|
import type { Document as DocumentType } from 'types';
|
||||||
import DropdownMenu, { MenuItem, MoreIcon } from 'components/DropdownMenu';
|
import DropdownMenu, { MenuItem, MoreIcon } from 'components/DropdownMenu';
|
||||||
import DocumentStore from '../DocumentStore';
|
import DocumentStore from '../DocumentStore';
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
|
history: Object,
|
||||||
document: DocumentType,
|
document: DocumentType,
|
||||||
collectionTree: ?Object,
|
collectionTree: ?Object,
|
||||||
store: DocumentStore,
|
store: DocumentStore,
|
||||||
@ -19,12 +20,12 @@ type Props = {
|
|||||||
|
|
||||||
onCreateDocument = () => {
|
onCreateDocument = () => {
|
||||||
invariant(this.props.collectionTree, 'collectionTree is not available');
|
invariant(this.props.collectionTree, 'collectionTree is not available');
|
||||||
browserHistory.push(`${this.props.collectionTree.url}/new`);
|
this.props.history.push(`${this.props.collectionTree.url}/new`);
|
||||||
};
|
};
|
||||||
|
|
||||||
onCreateChild = () => {
|
onCreateChild = () => {
|
||||||
invariant(this.props.document, 'Document is not available');
|
invariant(this.props.document, 'Document is not available');
|
||||||
browserHistory.push(`${this.props.document.url}/new`);
|
this.props.history.push(`${this.props.document.url}/new`);
|
||||||
};
|
};
|
||||||
|
|
||||||
onDelete = () => {
|
onDelete = () => {
|
||||||
@ -75,4 +76,4 @@ type Props = {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default Menu;
|
export default withRouter(Menu);
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
// @flow
|
// @flow
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { Link } from 'react-router';
|
import { Link } from 'react-router-dom';
|
||||||
|
|
||||||
import Layout from 'components/Layout';
|
import Layout from 'components/Layout';
|
||||||
import CenteredContent from 'components/CenteredContent';
|
import CenteredContent from 'components/CenteredContent';
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
// @flow
|
// @flow
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { Link } from 'react-router';
|
import { Link } from 'react-router-dom';
|
||||||
|
|
||||||
import Layout from 'components/Layout';
|
import Layout from 'components/Layout';
|
||||||
import CenteredContent from 'components/CenteredContent';
|
import CenteredContent from 'components/CenteredContent';
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
// @flow
|
// @flow
|
||||||
import React, { PropTypes } from 'react';
|
import React from 'react';
|
||||||
import { observer } from 'mobx-react';
|
import { observer } from 'mobx-react';
|
||||||
|
|
||||||
import Layout, { Title } from 'components/Layout';
|
import Layout, { Title } from 'components/Layout';
|
||||||
@ -8,13 +8,16 @@ import { DocumentHtml } from 'components/Document';
|
|||||||
|
|
||||||
import { convertToMarkdown } from 'utils/markdown';
|
import { convertToMarkdown } from 'utils/markdown';
|
||||||
|
|
||||||
|
type Props = {
|
||||||
|
title: string,
|
||||||
|
content: string,
|
||||||
|
};
|
||||||
|
|
||||||
@observer class Flatpage extends React.Component {
|
@observer class Flatpage extends React.Component {
|
||||||
static propTypes = {
|
props: Props;
|
||||||
route: PropTypes.object,
|
|
||||||
};
|
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const { title, content } = this.props.route;
|
const { title, content } = this.props;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Layout
|
<Layout
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
// @flow
|
// @flow
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { observer, inject } from 'mobx-react';
|
import { observer, inject } from 'mobx-react';
|
||||||
import { browserHistory } from 'react-router';
|
import { Redirect } from 'react-router';
|
||||||
|
|
||||||
import { Flex } from 'reflexbox';
|
import { Flex } from 'reflexbox';
|
||||||
import Layout from 'components/Layout';
|
import Layout from 'components/Layout';
|
||||||
@ -19,12 +19,6 @@ export default class Home extends React.Component {
|
|||||||
location: React.PropTypes.object.isRequired,
|
location: React.PropTypes.object.isRequired,
|
||||||
};
|
};
|
||||||
|
|
||||||
componentDidMount = () => {
|
|
||||||
if (this.props.user.authenticated) {
|
|
||||||
browserHistory.replace('/dashboard');
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
get notifications(): React.Element<any>[] {
|
get notifications(): React.Element<any>[] {
|
||||||
const notifications = [];
|
const notifications = [];
|
||||||
const { state } = this.props.location;
|
const { state } = this.props.location;
|
||||||
@ -46,6 +40,8 @@ export default class Home extends React.Component {
|
|||||||
return (
|
return (
|
||||||
<Flex auto>
|
<Flex auto>
|
||||||
<Layout notifications={this.notifications}>
|
<Layout notifications={this.notifications}>
|
||||||
|
{this.props.user.authenticated && <Redirect to="/dashboard" />}
|
||||||
|
|
||||||
<CenteredContent>
|
<CenteredContent>
|
||||||
{showLandingPageCopy &&
|
{showLandingPageCopy &&
|
||||||
<div className={styles.intro}>
|
<div className={styles.intro}>
|
||||||
|
@ -13,8 +13,7 @@ import CenteredContent from 'components/CenteredContent';
|
|||||||
import DocumentPreview from 'components/DocumentPreview';
|
import DocumentPreview from 'components/DocumentPreview';
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
route: Object,
|
notFound: ?boolean,
|
||||||
routeParams: Object,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
@observer class Search extends React.Component {
|
@observer class Search extends React.Component {
|
||||||
@ -26,20 +25,6 @@ type Props = {
|
|||||||
this.store = new SearchStore();
|
this.store = new SearchStore();
|
||||||
}
|
}
|
||||||
|
|
||||||
componentDidMount = () => {
|
|
||||||
const { splat } = this.props.routeParams;
|
|
||||||
if (this.viewNotFound) {
|
|
||||||
let searchTerm = _.last(splat.split('/'));
|
|
||||||
searchTerm = searchTerm.split(/[\s-]+/gi).join(' ');
|
|
||||||
this.store.search(searchTerm);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
get viewNotFound(): boolean {
|
|
||||||
const { sceneType } = this.props.route;
|
|
||||||
return sceneType === 'notFound';
|
|
||||||
}
|
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const search = _.debounce(searchTerm => {
|
const search = _.debounce(searchTerm => {
|
||||||
this.store.search(searchTerm);
|
this.store.search(searchTerm);
|
||||||
@ -54,7 +39,7 @@ type Props = {
|
|||||||
loading={this.store.isFetching}
|
loading={this.store.isFetching}
|
||||||
>
|
>
|
||||||
<CenteredContent>
|
<CenteredContent>
|
||||||
{this.viewNotFound &&
|
{this.props.notFound &&
|
||||||
<div>
|
<div>
|
||||||
<h1>Not Found</h1>
|
<h1>Not Found</h1>
|
||||||
<p>We're unable to find the page you're accessing.</p>
|
<p>We're unable to find the page you're accessing.</p>
|
||||||
|
@ -1,51 +1,65 @@
|
|||||||
// @flow
|
// @flow
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
import { Redirect } from 'react-router';
|
||||||
|
import queryString from 'query-string';
|
||||||
import { observer, inject } from 'mobx-react';
|
import { observer, inject } from 'mobx-react';
|
||||||
import { browserHistory } from 'react-router';
|
|
||||||
import { client } from 'utils/ApiClient';
|
import { client } from 'utils/ApiClient';
|
||||||
|
|
||||||
|
import UserStore from 'stores/UserStore';
|
||||||
|
|
||||||
|
type Props = {
|
||||||
|
user: UserStore,
|
||||||
|
location: Object,
|
||||||
|
};
|
||||||
|
|
||||||
@inject('user')
|
@inject('user')
|
||||||
@observer
|
@observer
|
||||||
class SlackAuth extends React.Component {
|
class SlackAuth extends React.Component {
|
||||||
static propTypes = {
|
props: Props;
|
||||||
user: React.PropTypes.object.isRequired,
|
|
||||||
location: React.PropTypes.object.isRequired,
|
|
||||||
route: React.PropTypes.object.isRequired,
|
|
||||||
};
|
|
||||||
|
|
||||||
// $FlowIssue wtf
|
state: { redirectTo: string };
|
||||||
|
|
||||||
|
// $FlowFixMe not sure why this breaks
|
||||||
componentDidMount = async () => {
|
componentDidMount = async () => {
|
||||||
const { error, code, state } = this.props.location.query;
|
const { error, code, state } = queryString.parse(
|
||||||
|
this.props.location.search
|
||||||
|
);
|
||||||
|
|
||||||
if (error) {
|
if (error) {
|
||||||
if (error === 'access_denied') {
|
if (error === 'access_denied') {
|
||||||
// User selected "Deny" access on Slack OAuth
|
// User selected "Deny" access on Slack OAuth
|
||||||
browserHistory.push('/');
|
this.setState({ redirectTo: '/dashboard' });
|
||||||
} else {
|
} else {
|
||||||
browserHistory.push('/auth/error');
|
this.setState({ redirectTo: '/auth/error' });
|
||||||
}
|
|
||||||
// $FlowIssue wtf
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.props.route.apiPath) {
|
|
||||||
try {
|
|
||||||
await client.post(this.props.route.apiPath, { code });
|
|
||||||
browserHistory.replace('/dashboard');
|
|
||||||
} catch (e) {
|
|
||||||
browserHistory.push('/auth-error');
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Regular Slack authentication
|
if (this.props.location.pathname === '/auth/slack/commands') {
|
||||||
const redirectTo = sessionStorage.getItem('redirectTo');
|
// User adding webhook integrations
|
||||||
sessionStorage.removeItem('redirectTo');
|
try {
|
||||||
|
await client.post('/auth.slackCommands', { code });
|
||||||
|
this.setState({ redirectTo: '/dashboard' });
|
||||||
|
} catch (e) {
|
||||||
|
this.setState({ redirectTo: '/auth/error' });
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Regular Slack authentication
|
||||||
|
const redirectTo = sessionStorage.getItem('redirectTo');
|
||||||
|
sessionStorage.removeItem('redirectTo');
|
||||||
|
|
||||||
this.props.user.authWithSlack(code, state, redirectTo);
|
const { success } = await this.props.user.authWithSlack(code, state);
|
||||||
|
success
|
||||||
|
? this.setState({ redirectTo: redirectTo || '/dashboard' })
|
||||||
|
: this.setState({ redirectTo: '/auth/error' });
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
return <div />;
|
return (
|
||||||
|
<div>
|
||||||
|
{this.state.redirectTo && <Redirect to={this.state.redirectTo} />}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
// @flow
|
// @flow
|
||||||
import { observable, action, computed } from 'mobx';
|
import { observable, action, computed } from 'mobx';
|
||||||
import invariant from 'invariant';
|
import invariant from 'invariant';
|
||||||
import { browserHistory } from 'react-router';
|
|
||||||
import { client } from 'utils/ApiClient';
|
import { client } from 'utils/ApiClient';
|
||||||
import type { User, Team } from 'types';
|
import type { User, Team } from 'types';
|
||||||
|
|
||||||
@ -33,10 +32,10 @@ class UserStore {
|
|||||||
|
|
||||||
/* Actions */
|
/* Actions */
|
||||||
|
|
||||||
@action logout = () => {
|
@action logout = (cb: Function) => {
|
||||||
this.user = null;
|
this.user = null;
|
||||||
this.token = null;
|
this.token = null;
|
||||||
browserHistory.push('/');
|
cb();
|
||||||
};
|
};
|
||||||
|
|
||||||
@action getOauthState = () => {
|
@action getOauthState = () => {
|
||||||
@ -45,22 +44,20 @@ class UserStore {
|
|||||||
return this.oauthState;
|
return this.oauthState;
|
||||||
};
|
};
|
||||||
|
|
||||||
@action authWithSlack = async (
|
@action authWithSlack = async (code: string, state: string) => {
|
||||||
code: string,
|
|
||||||
state: string,
|
|
||||||
redirectTo: ?string
|
|
||||||
) => {
|
|
||||||
if (state !== this.oauthState) {
|
if (state !== this.oauthState) {
|
||||||
browserHistory.push('/auth-error');
|
return {
|
||||||
return;
|
success: false,
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
let res;
|
let res;
|
||||||
try {
|
try {
|
||||||
res = await client.post('/auth.slack', { code });
|
res = await client.post('/auth.slack', { code });
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
browserHistory.push('/auth-error');
|
return {
|
||||||
return;
|
success: false,
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
invariant(
|
invariant(
|
||||||
@ -70,7 +67,10 @@ class UserStore {
|
|||||||
this.user = res.data.user;
|
this.user = res.data.user;
|
||||||
this.team = res.data.team;
|
this.team = res.data.team;
|
||||||
this.token = res.data.accessToken;
|
this.token = res.data.accessToken;
|
||||||
browserHistory.replace(redirectTo || '/');
|
|
||||||
|
return {
|
||||||
|
success: true,
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
// @flow
|
// @flow
|
||||||
import _ from 'lodash';
|
import _ from 'lodash';
|
||||||
import { browserHistory } from 'react-router';
|
|
||||||
import stores from 'stores';
|
import stores from 'stores';
|
||||||
|
|
||||||
type Options = {
|
type Options = {
|
||||||
@ -63,15 +62,15 @@ class ApiClient {
|
|||||||
return response;
|
return response;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handle 404
|
// // Handle 404
|
||||||
if (response.status === 404) {
|
// if (response.status === 404) {
|
||||||
return browserHistory.push('/404');
|
// // return browserHistory.push('/404');
|
||||||
}
|
// }
|
||||||
|
|
||||||
// Handle 401, log out user
|
// // Handle 401, log out user
|
||||||
if (response.status === 401) {
|
// if (response.status === 401) {
|
||||||
return stores.user.logout();
|
// return stores.user.logout();
|
||||||
}
|
// }
|
||||||
|
|
||||||
// Handle failed responses
|
// Handle failed responses
|
||||||
const error = {};
|
const error = {};
|
||||||
|
@ -1,4 +0,0 @@
|
|||||||
// @flow
|
|
||||||
// https://github.com/reactjs/react-router/blob/master/docs/guides/NavigatingOutsideOfComponents.md
|
|
||||||
import browserHistory from 'react-router/lib/browserHistory';
|
|
||||||
export default browserHistory;
|
|
@ -141,7 +141,7 @@
|
|||||||
"react-helmet": "3.1.0",
|
"react-helmet": "3.1.0",
|
||||||
"react-keydown": "^1.7.3",
|
"react-keydown": "^1.7.3",
|
||||||
"react-portal": "^3.1.0",
|
"react-portal": "^3.1.0",
|
||||||
"react-router": "2.8.0",
|
"react-router-dom": "^4.1.1",
|
||||||
"redis": "^2.6.2",
|
"redis": "^2.6.2",
|
||||||
"redis-lock": "^0.1.0",
|
"redis-lock": "^0.1.0",
|
||||||
"reflexbox": "^2.2.3",
|
"reflexbox": "^2.2.3",
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
/* eslint-disable */
|
||||||
var webpack = require('webpack');
|
var webpack = require('webpack');
|
||||||
var HtmlWebpackPlugin = require('html-webpack-plugin');
|
var HtmlWebpackPlugin = require('html-webpack-plugin');
|
||||||
|
|
||||||
@ -5,7 +6,7 @@ const commonWebpackConfig = require('./webpack.config');
|
|||||||
|
|
||||||
const developmentWebpackConfig = Object.assign(commonWebpackConfig, {
|
const developmentWebpackConfig = Object.assign(commonWebpackConfig, {
|
||||||
cache: true,
|
cache: true,
|
||||||
devtool: 'eval',
|
devtool: 'eval-source-map',
|
||||||
entry: [
|
entry: [
|
||||||
'babel-polyfill',
|
'babel-polyfill',
|
||||||
'babel-regenerator-runtime',
|
'babel-regenerator-runtime',
|
||||||
@ -18,11 +19,15 @@ developmentWebpackConfig.module.loaders.push({
|
|||||||
test: /\.s?css$/,
|
test: /\.s?css$/,
|
||||||
loader: 'style-loader!css-loader?modules&importLoaders=1&localIdentName=[name]__[local]___[hash:base64:5]!sass?sourceMap',
|
loader: 'style-loader!css-loader?modules&importLoaders=1&localIdentName=[name]__[local]___[hash:base64:5]!sass?sourceMap',
|
||||||
});
|
});
|
||||||
developmentWebpackConfig.plugins.push(new webpack.optimize.OccurenceOrderPlugin());
|
developmentWebpackConfig.plugins.push(
|
||||||
|
new webpack.optimize.OccurenceOrderPlugin()
|
||||||
|
);
|
||||||
developmentWebpackConfig.plugins.push(new webpack.HotModuleReplacementPlugin());
|
developmentWebpackConfig.plugins.push(new webpack.HotModuleReplacementPlugin());
|
||||||
developmentWebpackConfig.plugins.push(new webpack.NoErrorsPlugin());
|
developmentWebpackConfig.plugins.push(new webpack.NoErrorsPlugin());
|
||||||
developmentWebpackConfig.plugins.push(new HtmlWebpackPlugin({
|
developmentWebpackConfig.plugins.push(
|
||||||
title: 'Atlas',
|
new HtmlWebpackPlugin({
|
||||||
}));
|
title: 'Atlas',
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
module.exports = developmentWebpackConfig;
|
module.exports = developmentWebpackConfig;
|
||||||
|
@ -1,18 +1,15 @@
|
|||||||
|
/* eslint-disable */
|
||||||
var path = require('path');
|
var path = require('path');
|
||||||
var webpack = require('webpack');
|
var webpack = require('webpack');
|
||||||
var HtmlWebpackPlugin = require('html-webpack-plugin');
|
var HtmlWebpackPlugin = require('html-webpack-plugin');
|
||||||
var ExtractTextPlugin = require("extract-text-webpack-plugin");
|
var ExtractTextPlugin = require('extract-text-webpack-plugin');
|
||||||
|
|
||||||
commonWebpackConfig = require('./webpack.config');
|
commonWebpackConfig = require('./webpack.config');
|
||||||
|
|
||||||
productionWebpackConfig = Object.assign(commonWebpackConfig, {
|
productionWebpackConfig = Object.assign(commonWebpackConfig, {
|
||||||
cache: true,
|
cache: true,
|
||||||
devtool: 'cheap-module-source-map',
|
devtool: 'cheap-module-source-map',
|
||||||
entry: [
|
entry: ['babel-polyfill', 'babel-regenerator-runtime', './frontend/index'],
|
||||||
'babel-polyfill',
|
|
||||||
'babel-regenerator-runtime',
|
|
||||||
'./frontend/index',
|
|
||||||
],
|
|
||||||
output: {
|
output: {
|
||||||
path: path.join(__dirname, 'dist'),
|
path: path.join(__dirname, 'dist'),
|
||||||
filename: 'bundle.[hash].js',
|
filename: 'bundle.[hash].js',
|
||||||
@ -21,25 +18,34 @@ productionWebpackConfig = Object.assign(commonWebpackConfig, {
|
|||||||
});
|
});
|
||||||
productionWebpackConfig.module.loaders.push({
|
productionWebpackConfig.module.loaders.push({
|
||||||
test: /\.s?css$/,
|
test: /\.s?css$/,
|
||||||
loader: ExtractTextPlugin.extract('style-loader', 'css-loader?modules&importLoaders=1&localIdentName=[name]__[local]___[hash:base64:5]!sass?sourceMap')
|
loader: ExtractTextPlugin.extract(
|
||||||
|
'style-loader',
|
||||||
|
'css-loader?modules&importLoaders=1&localIdentName=[name]__[local]___[hash:base64:5]!sass?sourceMap'
|
||||||
|
),
|
||||||
});
|
});
|
||||||
productionWebpackConfig.plugins.push(new HtmlWebpackPlugin({
|
productionWebpackConfig.plugins.push(
|
||||||
template: 'server/static/index.html'
|
new HtmlWebpackPlugin({
|
||||||
}));
|
template: 'server/static/index.html',
|
||||||
productionWebpackConfig.plugins.push(new ExtractTextPlugin('styles.[hash].css'));
|
})
|
||||||
productionWebpackConfig.plugins.push(new webpack.optimize.OccurenceOrderPlugin());
|
);
|
||||||
|
productionWebpackConfig.plugins.push(
|
||||||
|
new ExtractTextPlugin('styles.[hash].css')
|
||||||
|
);
|
||||||
|
productionWebpackConfig.plugins.push(
|
||||||
|
new webpack.optimize.OccurenceOrderPlugin()
|
||||||
|
);
|
||||||
productionWebpackConfig.plugins.push(
|
productionWebpackConfig.plugins.push(
|
||||||
new webpack.optimize.UglifyJsPlugin({
|
new webpack.optimize.UglifyJsPlugin({
|
||||||
compress: {
|
compress: {
|
||||||
warnings: false
|
warnings: false,
|
||||||
}
|
},
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
productionWebpackConfig.plugins.push(
|
productionWebpackConfig.plugins.push(
|
||||||
new webpack.DefinePlugin({
|
new webpack.DefinePlugin({
|
||||||
'process.env': {
|
'process.env': {
|
||||||
'NODE_ENV': JSON.stringify('production')
|
NODE_ENV: JSON.stringify('production'),
|
||||||
}
|
},
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|
||||||
|
64
yarn.lock
64
yarn.lock
@ -2120,7 +2120,7 @@ decamelize@^1.0.0, decamelize@^1.1.1, decamelize@^1.1.2:
|
|||||||
version "1.2.0"
|
version "1.2.0"
|
||||||
resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290"
|
resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290"
|
||||||
|
|
||||||
deep-equal@1.0.1, deep-equal@^1.0.0, deep-equal@~1.0.0:
|
deep-equal@1.0.1, deep-equal@~1.0.0:
|
||||||
version "1.0.1"
|
version "1.0.1"
|
||||||
resolved "https://registry.yarnpkg.com/deep-equal/-/deep-equal-1.0.1.tgz#f5d260292b660e084eff4cdbc9f08ad3247448b5"
|
resolved "https://registry.yarnpkg.com/deep-equal/-/deep-equal-1.0.1.tgz#f5d260292b660e084eff4cdbc9f08ad3247448b5"
|
||||||
|
|
||||||
@ -3689,14 +3689,15 @@ history@3.0.0:
|
|||||||
query-string "^4.1.0"
|
query-string "^4.1.0"
|
||||||
warning "^2.0.0"
|
warning "^2.0.0"
|
||||||
|
|
||||||
history@^2.1.2:
|
history@^4.5.1, history@^4.6.0:
|
||||||
version "2.1.2"
|
version "4.6.1"
|
||||||
resolved "https://registry.yarnpkg.com/history/-/history-2.1.2.tgz#4aa2de897a0e4867e4539843be6ecdb2986bfdec"
|
resolved "https://registry.yarnpkg.com/history/-/history-4.6.1.tgz#911cf8eb65728555a94f2b12780a0c531a14d2fd"
|
||||||
dependencies:
|
dependencies:
|
||||||
deep-equal "^1.0.0"
|
invariant "^2.2.1"
|
||||||
invariant "^2.0.0"
|
loose-envify "^1.2.0"
|
||||||
query-string "^3.0.0"
|
resolve-pathname "^2.0.0"
|
||||||
warning "^2.0.0"
|
value-equal "^0.2.0"
|
||||||
|
warning "^3.0.0"
|
||||||
|
|
||||||
hoek@2.x.x:
|
hoek@2.x.x:
|
||||||
version "2.16.3"
|
version "2.16.3"
|
||||||
@ -5435,12 +5436,18 @@ longest@^1.0.1:
|
|||||||
version "1.0.1"
|
version "1.0.1"
|
||||||
resolved "https://registry.yarnpkg.com/longest/-/longest-1.0.1.tgz#30a0b2da38f73770e8294a0d22e6625ed77d0097"
|
resolved "https://registry.yarnpkg.com/longest/-/longest-1.0.1.tgz#30a0b2da38f73770e8294a0d22e6625ed77d0097"
|
||||||
|
|
||||||
loose-envify@^1.0.0, loose-envify@^1.1.0, loose-envify@^1.2.0:
|
loose-envify@^1.0.0, loose-envify@^1.1.0:
|
||||||
version "1.2.0"
|
version "1.2.0"
|
||||||
resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.2.0.tgz#69a65aad3de542cf4ee0f4fe74e8e33c709ccb0f"
|
resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.2.0.tgz#69a65aad3de542cf4ee0f4fe74e8e33c709ccb0f"
|
||||||
dependencies:
|
dependencies:
|
||||||
js-tokens "^1.0.1"
|
js-tokens "^1.0.1"
|
||||||
|
|
||||||
|
loose-envify@^1.2.0, loose-envify@^1.3.1:
|
||||||
|
version "1.3.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.3.1.tgz#d1a8ad33fa9ce0e713d65fdd0ac8b748d478c848"
|
||||||
|
dependencies:
|
||||||
|
js-tokens "^3.0.0"
|
||||||
|
|
||||||
loud-rejection@^1.0.0:
|
loud-rejection@^1.0.0:
|
||||||
version "1.6.0"
|
version "1.6.0"
|
||||||
resolved "https://registry.yarnpkg.com/loud-rejection/-/loud-rejection-1.6.0.tgz#5b46f80147edee578870f086d04821cf998e551f"
|
resolved "https://registry.yarnpkg.com/loud-rejection/-/loud-rejection-1.6.0.tgz#5b46f80147edee578870f086d04821cf998e551f"
|
||||||
@ -6414,7 +6421,7 @@ path-root@^0.1.1:
|
|||||||
dependencies:
|
dependencies:
|
||||||
path-root-regex "^0.1.0"
|
path-root-regex "^0.1.0"
|
||||||
|
|
||||||
path-to-regexp@^1.1.1:
|
path-to-regexp@^1.1.1, path-to-regexp@^1.5.3:
|
||||||
version "1.6.0"
|
version "1.6.0"
|
||||||
resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-1.6.0.tgz#4c59cfeab5e360a2657b180730a4bb4582ecec5b"
|
resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-1.6.0.tgz#4c59cfeab5e360a2657b180730a4bb4582ecec5b"
|
||||||
dependencies:
|
dependencies:
|
||||||
@ -6929,12 +6936,6 @@ qs@~6.4.0:
|
|||||||
version "6.4.0"
|
version "6.4.0"
|
||||||
resolved "https://registry.yarnpkg.com/qs/-/qs-6.4.0.tgz#13e26d28ad6b0ffaa91312cd3bf708ed351e7233"
|
resolved "https://registry.yarnpkg.com/qs/-/qs-6.4.0.tgz#13e26d28ad6b0ffaa91312cd3bf708ed351e7233"
|
||||||
|
|
||||||
query-string@^3.0.0:
|
|
||||||
version "3.0.3"
|
|
||||||
resolved "https://registry.yarnpkg.com/query-string/-/query-string-3.0.3.tgz#ae2e14b4d05071d4e9b9eb4873c35b0dcd42e638"
|
|
||||||
dependencies:
|
|
||||||
strict-uri-encode "^1.0.0"
|
|
||||||
|
|
||||||
query-string@^4.1.0, query-string@^4.3.4:
|
query-string@^4.1.0, query-string@^4.3.4:
|
||||||
version "4.3.4"
|
version "4.3.4"
|
||||||
resolved "https://registry.yarnpkg.com/query-string/-/query-string-4.3.4.tgz#bbb693b9ca915c232515b228b1a02b609043dbeb"
|
resolved "https://registry.yarnpkg.com/query-string/-/query-string-4.3.4.tgz#bbb693b9ca915c232515b228b1a02b609043dbeb"
|
||||||
@ -7056,14 +7057,25 @@ react-proxy@^1.1.7:
|
|||||||
lodash "^4.6.1"
|
lodash "^4.6.1"
|
||||||
react-deep-force-update "^1.0.0"
|
react-deep-force-update "^1.0.0"
|
||||||
|
|
||||||
react-router@2.8.0:
|
react-router-dom@^4.1.1:
|
||||||
version "2.8.0"
|
version "4.1.1"
|
||||||
resolved "https://registry.yarnpkg.com/react-router/-/react-router-2.8.0.tgz#cbc629fede81d96d0598c2bae1e348e7d03f6c17"
|
resolved "https://registry.yarnpkg.com/react-router-dom/-/react-router-dom-4.1.1.tgz#3021ade1f2c160af97cf94e25594c5f294583025"
|
||||||
dependencies:
|
dependencies:
|
||||||
history "^2.1.2"
|
history "^4.5.1"
|
||||||
|
loose-envify "^1.3.1"
|
||||||
|
prop-types "^15.5.4"
|
||||||
|
react-router "^4.1.1"
|
||||||
|
|
||||||
|
react-router@^4.1.1:
|
||||||
|
version "4.1.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/react-router/-/react-router-4.1.1.tgz#d448f3b7c1b429a6fbb03395099949c606b1fe95"
|
||||||
|
dependencies:
|
||||||
|
history "^4.6.0"
|
||||||
hoist-non-react-statics "^1.2.0"
|
hoist-non-react-statics "^1.2.0"
|
||||||
invariant "^2.2.1"
|
invariant "^2.2.2"
|
||||||
loose-envify "^1.2.0"
|
loose-envify "^1.3.1"
|
||||||
|
path-to-regexp "^1.5.3"
|
||||||
|
prop-types "^15.5.4"
|
||||||
warning "^3.0.0"
|
warning "^3.0.0"
|
||||||
|
|
||||||
react-side-effect@1.0.2:
|
react-side-effect@1.0.2:
|
||||||
@ -7447,6 +7459,10 @@ resolve-from@^1.0.0:
|
|||||||
version "1.0.1"
|
version "1.0.1"
|
||||||
resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-1.0.1.tgz#26cbfe935d1aeeeabb29bc3fe5aeb01e93d44226"
|
resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-1.0.1.tgz#26cbfe935d1aeeeabb29bc3fe5aeb01e93d44226"
|
||||||
|
|
||||||
|
resolve-pathname@^2.0.0:
|
||||||
|
version "2.1.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/resolve-pathname/-/resolve-pathname-2.1.0.tgz#e8358801b86b83b17560d4e3c382d7aef2100944"
|
||||||
|
|
||||||
resolve@1.1.7, resolve@1.1.x, resolve@^1.0.0, resolve@^1.1.6, resolve@^1.1.7:
|
resolve@1.1.7, resolve@1.1.x, resolve@^1.0.0, resolve@^1.1.6, resolve@^1.1.7:
|
||||||
version "1.1.7"
|
version "1.1.7"
|
||||||
resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.1.7.tgz#203114d82ad2c5ed9e8e0411b3932875e889e97b"
|
resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.1.7.tgz#203114d82ad2c5ed9e8e0411b3932875e889e97b"
|
||||||
@ -8615,6 +8631,10 @@ validator@5.2.0, validator@^5.2.0:
|
|||||||
version "5.2.0"
|
version "5.2.0"
|
||||||
resolved "https://registry.yarnpkg.com/validator/-/validator-5.2.0.tgz#e66fb3ec352348c1f7232512328738d8d66a9689"
|
resolved "https://registry.yarnpkg.com/validator/-/validator-5.2.0.tgz#e66fb3ec352348c1f7232512328738d8d66a9689"
|
||||||
|
|
||||||
|
value-equal@^0.2.0:
|
||||||
|
version "0.2.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/value-equal/-/value-equal-0.2.1.tgz#c220a304361fce6994dbbedaa3c7e1a1b895871d"
|
||||||
|
|
||||||
vary@^1.0.0, vary@~1.1.0:
|
vary@^1.0.0, vary@~1.1.0:
|
||||||
version "1.1.0"
|
version "1.1.0"
|
||||||
resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.0.tgz#e1e5affbbd16ae768dd2674394b9ad3022653140"
|
resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.0.tgz#e1e5affbbd16ae768dd2674394b9ad3022653140"
|
||||||
|
Reference in New Issue
Block a user