Merge master
This commit is contained in:
@@ -1,9 +1,11 @@
|
||||
// @flow
|
||||
import React from 'react';
|
||||
import { observable } from 'mobx';
|
||||
import { observer, inject } from 'mobx-react';
|
||||
import styled from 'styled-components';
|
||||
|
||||
import DocumentsStore from 'stores/DocumentsStore';
|
||||
import Flex from 'components/Flex';
|
||||
import DocumentList from 'components/DocumentList';
|
||||
import PageTitle from 'components/PageTitle';
|
||||
import CenteredContent from 'components/CenteredContent';
|
||||
@@ -26,29 +28,33 @@ type Props = {
|
||||
|
||||
@observer class Dashboard extends React.Component {
|
||||
props: Props;
|
||||
@observable isLoaded = false;
|
||||
|
||||
componentDidMount() {
|
||||
this.props.documents.fetchAll();
|
||||
this.props.documents.fetchRecentlyViewed();
|
||||
this.loadContent();
|
||||
}
|
||||
|
||||
get showPlaceholder() {
|
||||
const { isLoaded, isFetching } = this.props.documents;
|
||||
return !isLoaded && isFetching;
|
||||
}
|
||||
loadContent = async () => {
|
||||
await Promise.all([
|
||||
this.props.documents.fetchRecentlyModified({ limit: 5 }),
|
||||
this.props.documents.fetchRecentlyViewed({ limit: 5 }),
|
||||
]);
|
||||
this.isLoaded = true;
|
||||
};
|
||||
|
||||
render() {
|
||||
return (
|
||||
<CenteredContent>
|
||||
<PageTitle title="Home" />
|
||||
<h1>Home</h1>
|
||||
<Subheading>Recently viewed</Subheading>
|
||||
{this.showPlaceholder && <ListPlaceholder />}
|
||||
<DocumentList documents={this.props.documents.recentlyViewed} />
|
||||
|
||||
<Subheading>Recently edited</Subheading>
|
||||
<DocumentList documents={this.props.documents.recentlyEdited} />
|
||||
{this.showPlaceholder && <ListPlaceholder />}
|
||||
{this.isLoaded
|
||||
? <Flex column>
|
||||
<Subheading>Recently viewed</Subheading>
|
||||
<DocumentList documents={this.props.documents.recentlyViewed} />
|
||||
<Subheading>Recently edited</Subheading>
|
||||
<DocumentList documents={this.props.documents.recentlyEdited} />
|
||||
</Flex>
|
||||
: <ListPlaceholder count={5} />}
|
||||
</CenteredContent>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@ import { observer, inject } from 'mobx-react';
|
||||
import { withRouter, Prompt } from 'react-router';
|
||||
import Flex from 'components/Flex';
|
||||
import { color, layout } from 'styles/constants';
|
||||
import { collectionUrl } from 'utils/routeHelpers';
|
||||
|
||||
import Document from 'models/Document';
|
||||
import UiStore from 'stores/UiStore';
|
||||
@@ -19,6 +20,7 @@ import LoadingIndicator from 'components/LoadingIndicator';
|
||||
import Collaborators from 'components/Collaborators';
|
||||
import CenteredContent from 'components/CenteredContent';
|
||||
import PageTitle from 'components/PageTitle';
|
||||
import Search from 'scenes/Search';
|
||||
|
||||
const DISCARD_CHANGES = `
|
||||
You have unsaved changes.
|
||||
@@ -46,6 +48,7 @@ type Props = {
|
||||
isSaving: false,
|
||||
newDocument: undefined,
|
||||
showAsSaved: false,
|
||||
notFound: false,
|
||||
};
|
||||
|
||||
componentDidMount() {
|
||||
@@ -57,6 +60,7 @@ type Props = {
|
||||
nextProps.match.params.documentSlug !==
|
||||
this.props.match.params.documentSlug
|
||||
) {
|
||||
this.setState({ notFound: false });
|
||||
this.loadDocument(nextProps);
|
||||
}
|
||||
}
|
||||
@@ -86,6 +90,9 @@ type Props = {
|
||||
if (document) {
|
||||
this.props.ui.setActiveDocument(document);
|
||||
document.view();
|
||||
} else {
|
||||
// Render 404 with search
|
||||
this.setState({ notFound: true });
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -146,7 +153,13 @@ type Props = {
|
||||
};
|
||||
|
||||
onCancel = () => {
|
||||
this.props.history.goBack();
|
||||
let url;
|
||||
if (this.document && this.document.url) {
|
||||
url = this.document.url;
|
||||
} else {
|
||||
url = collectionUrl(this.props.match.params.id);
|
||||
}
|
||||
this.props.history.push(url);
|
||||
};
|
||||
|
||||
onStartDragging = () => {
|
||||
@@ -157,6 +170,10 @@ type Props = {
|
||||
this.setState({ isDragging: false });
|
||||
};
|
||||
|
||||
renderNotFound() {
|
||||
return <Search notFound />;
|
||||
}
|
||||
|
||||
render() {
|
||||
const isNew = this.props.newDocument;
|
||||
const isEditing = !!this.props.match.params.edit || isNew;
|
||||
@@ -164,6 +181,10 @@ type Props = {
|
||||
const titleText = get(this.document, 'title', '');
|
||||
const document = this.document;
|
||||
|
||||
if (this.state.notFound) {
|
||||
return this.renderNotFound();
|
||||
}
|
||||
|
||||
return (
|
||||
<Container column auto>
|
||||
{this.state.isDragging &&
|
||||
|
||||
@@ -26,9 +26,7 @@ type Props = {
|
||||
if (state && state.nextPathname) {
|
||||
sessionStorage.removeItem('redirectTo');
|
||||
sessionStorage.setItem('redirectTo', state.nextPathname);
|
||||
notifications.push(
|
||||
<Alert key="login" info>Please login to continue</Alert>
|
||||
);
|
||||
notifications.push(<Alert key="login">Please login to continue</Alert>);
|
||||
}
|
||||
|
||||
return notifications;
|
||||
|
||||
@@ -1,48 +1,49 @@
|
||||
// @flow
|
||||
import React, { PropTypes } from 'react';
|
||||
import React from 'react';
|
||||
import { observable } from 'mobx';
|
||||
import { observer } from 'mobx-react';
|
||||
import styled from 'styled-components';
|
||||
import { color } from 'styles/constants';
|
||||
|
||||
import styles from './ApiKeyRow.scss';
|
||||
import classNames from 'classnames/bind';
|
||||
const cx = classNames.bind(styles);
|
||||
type Props = {
|
||||
id: string,
|
||||
name: ?string,
|
||||
secret: string,
|
||||
onDelete: Function,
|
||||
};
|
||||
|
||||
class ApiKeyRow extends React.Component {
|
||||
static propTypes = {
|
||||
id: PropTypes.string.isRequired,
|
||||
name: PropTypes.string.isRequired,
|
||||
secret: PropTypes.string.isRequired,
|
||||
onDelete: PropTypes.func.isRequired,
|
||||
};
|
||||
|
||||
state = {
|
||||
disabled: false,
|
||||
};
|
||||
@observer class ApiKeyRow extends React.Component {
|
||||
props: Props;
|
||||
@observable disabled: boolean;
|
||||
|
||||
onClick = () => {
|
||||
this.props.onDelete(this.props.id);
|
||||
this.setState({ disabled: true });
|
||||
this.disabled = true;
|
||||
};
|
||||
|
||||
render() {
|
||||
const { name, secret } = this.props;
|
||||
|
||||
const { disabled } = this.state;
|
||||
const { disabled } = this;
|
||||
|
||||
return (
|
||||
<tr>
|
||||
<td>{name}</td>
|
||||
<td><code>{secret}</code></td>
|
||||
<td>
|
||||
<span
|
||||
role="button"
|
||||
onClick={this.onClick}
|
||||
className={cx(styles.deleteAction, { disabled })}
|
||||
>
|
||||
Delete
|
||||
</span>
|
||||
<Action role="button" onClick={this.onClick} disabled={disabled}>
|
||||
Action
|
||||
</Action>
|
||||
</td>
|
||||
</tr>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
const Action = styled.span`
|
||||
font-size: 14px;
|
||||
color: ${color.text};
|
||||
|
||||
opacity: ${({ disabled }) => (disabled ? 0.5 : 1)};
|
||||
`;
|
||||
|
||||
export default ApiKeyRow;
|
||||
|
||||
@@ -1,10 +0,0 @@
|
||||
@import '~styles/constants.scss';
|
||||
|
||||
.deleteAction {
|
||||
font-size: 14px;
|
||||
color: $textColor;
|
||||
}
|
||||
|
||||
.disabled {
|
||||
opacity: 0.5;
|
||||
}
|
||||
Reference in New Issue
Block a user