diff --git a/frontend/components/PublishingInfo/PublishingInfo.js b/frontend/components/PublishingInfo/PublishingInfo.js
index 166c23fc..298e7ef6 100644
--- a/frontend/components/PublishingInfo/PublishingInfo.js
+++ b/frontend/components/PublishingInfo/PublishingInfo.js
@@ -45,23 +45,24 @@ class PublishingInfo extends Component {
))}
}
-
- {this.props.createdBy.name}
- {' '}
- published
- {' '}
- {moment(this.props.createdAt).fromNow()}
- {this.props.createdAt !== this.props.updatedAt
- ?
- and
- {this.props.createdBy.id !== this.props.updatedBy.id &&
- ` ${this.props.updatedBy.name} `}
- modified
- {' '}
- {moment(this.props.updatedAt).fromNow()}
-
- : null}
-
+ {this.props.createdBy &&
+
+ {this.props.createdBy.name}
+ {' '}
+ published
+ {' '}
+ {moment(this.props.createdAt).fromNow()}
+ {this.props.createdAt !== this.props.updatedAt
+ ?
+ and
+ {this.props.createdBy.id !== this.props.updatedBy.id &&
+ ` ${this.props.updatedBy.name} `}
+ modified
+ {' '}
+ {moment(this.props.updatedAt).fromNow()}
+
+ : null}
+ }
);
}
diff --git a/frontend/components/SidebarHidden/SidebarHidden.js b/frontend/components/SidebarHidden/SidebarHidden.js
new file mode 100644
index 00000000..adf26b44
--- /dev/null
+++ b/frontend/components/SidebarHidden/SidebarHidden.js
@@ -0,0 +1,25 @@
+// @flow
+import { Component } from 'react';
+import { inject } from 'mobx-react';
+import UiStore from 'stores/UiStore';
+
+class SidebarHidden extends Component {
+ props: {
+ ui: UiStore,
+ children: React$Element,
+ };
+
+ componentDidMount() {
+ this.props.ui.enableEditMode();
+ }
+
+ componentWillUnmount() {
+ this.props.ui.disableEditMode();
+ }
+
+ render() {
+ return this.props.children;
+ }
+}
+
+export default inject('ui')(SidebarHidden);
diff --git a/frontend/components/SidebarHidden/index.js b/frontend/components/SidebarHidden/index.js
new file mode 100644
index 00000000..b63c0b7a
--- /dev/null
+++ b/frontend/components/SidebarHidden/index.js
@@ -0,0 +1,3 @@
+// @flow
+import SidebarHidden from './SidebarHidden';
+export default SidebarHidden;
diff --git a/frontend/index.js b/frontend/index.js
index 160ef99d..22843cda 100644
--- a/frontend/index.js
+++ b/frontend/index.js
@@ -35,6 +35,7 @@ import Error404 from 'scenes/Error404';
import ScrollToTop from 'components/ScrollToTop';
import Layout from 'components/Layout';
+import SidebarHidden from 'components/SidebarHidden';
import flatpages from 'static/flatpages';
@@ -86,11 +87,12 @@ const KeyboardShortcuts = () => (
);
const Api = () => ;
const DocumentNew = () => ;
-const DocumentNewChild = () => ;
const RedirectDocument = ({ match }: { match: Object }) => (
);
+const matchDocumentSlug = ':documentSlug([0-9a-zA-Z-]*-[a-zA-z0-9]{10,15})';
+
render(
@@ -111,26 +113,28 @@ render(
-
-
-
-
+
+
+
+
+
+
diff --git a/frontend/models/Document.js b/frontend/models/Document.js
index e19f7971..097e4563 100644
--- a/frontend/models/Document.js
+++ b/frontend/models/Document.js
@@ -15,7 +15,7 @@ const parseHeader = text => {
};
class Document {
- isSaving: boolean;
+ isSaving: boolean = false;
hasPendingChanges: boolean = false;
errors: ErrorsStore;
@@ -25,10 +25,10 @@ class Document {
createdBy: User;
html: string;
id: string;
- private: boolean;
- starred: boolean;
team: string;
- text: string;
+ private: boolean = false;
+ starred: boolean = false;
+ text: string = '';
title: string = 'Untitled document';
updatedAt: string;
updatedBy: User;
@@ -83,9 +83,9 @@ class Document {
};
@action view = async () => {
+ this.views++;
try {
await client.post('/views.create', { id: this.id });
- this.views++;
} catch (e) {
this.errors.add('Document failed to record view');
}
@@ -133,20 +133,25 @@ class Document {
}
invariant(res && res.data, 'Data should be available');
- this.hasPendingChanges = false;
+ this.updateData({
+ ...res.data,
+ hasPendingChanges: false,
+ });
} catch (e) {
this.errors.add('Document failed saving');
} finally {
this.isSaving = false;
}
+
+ return this;
};
updateData(data: Object | Document) {
- data.title = parseHeader(data.text);
+ if (data.text) data.title = parseHeader(data.text);
extendObservable(this, data);
}
- constructor(document: Document) {
+ constructor(document?: Object = {}) {
this.updateData(document);
this.errors = stores.errors;
}
diff --git a/frontend/scenes/Document/Document.js b/frontend/scenes/Document/Document.js
index f3cfa06c..c37c5172 100644
--- a/frontend/scenes/Document/Document.js
+++ b/frontend/scenes/Document/Document.js
@@ -6,6 +6,7 @@ import { observer, inject } from 'mobx-react';
import { withRouter, Prompt } from 'react-router';
import { Flex } from 'reflexbox';
+import Document from 'models/Document';
import UiStore from 'stores/UiStore';
import DocumentsStore from 'stores/DocumentsStore';
import Menu from './components/Menu';
@@ -28,15 +29,18 @@ type Props = {
history: Object,
keydown: Object,
documents: DocumentsStore,
- newChildDocument?: boolean,
+ newDocument?: boolean,
ui: UiStore,
};
-@observer class Document extends Component {
+@observer class DocumentScene extends Component {
props: Props;
-
+ state: {
+ newDocument?: Document,
+ };
state = {
isLoading: false,
+ newDocument: undefined,
};
componentDidMount() {
@@ -57,27 +61,29 @@ type Props = {
}
loadDocument = async props => {
- let document = this.document;
- if (document) {
- this.props.ui.setActiveDocument(document);
- }
-
- await this.props.documents.fetch(props.match.params.documentSlug);
- document = this.document;
-
- if (document) {
- this.props.ui.setActiveDocument(document);
- document.view();
- }
-
- if (this.props.match.params.edit) {
- this.props.ui.enableEditMode();
+ if (props.newDocument) {
+ const newDocument = new Document({
+ collection: { id: props.match.params.id },
+ });
+ this.setState({ newDocument });
} else {
- this.props.ui.disableEditMode();
+ let document = this.document;
+ if (document) {
+ this.props.ui.setActiveDocument(document);
+ }
+
+ await this.props.documents.fetch(props.match.params.documentSlug);
+ document = this.document;
+
+ if (document) {
+ this.props.ui.setActiveDocument(document);
+ document.view();
+ }
}
};
get document() {
+ if (this.state.newDocument) return this.state.newDocument;
return this.props.documents.getByUrl(
`/doc/${this.props.match.params.documentSlug}`
);
@@ -87,19 +93,17 @@ type Props = {
if (!this.document) return;
const url = `${this.document.url}/edit`;
this.props.history.push(url);
- this.props.ui.enableEditMode();
};
onSave = async (redirect: boolean = false) => {
- const document = this.document;
+ let document = this.document;
if (!document) return;
this.setState({ isLoading: true });
- await document.save();
+ document = await document.save();
this.setState({ isLoading: false });
- this.props.ui.disableEditMode();
- if (redirect) {
+ if (redirect || this.props.newDocument) {
this.props.history.push(document.url);
}
};
@@ -122,8 +126,8 @@ type Props = {
};
render() {
- const isNew = this.props.newDocument || this.props.newChildDocument;
- const isEditing = this.props.match.params.edit;
+ const isNew = this.props.newDocument;
+ const isEditing = this.props.match.params.edit || isNew;
const isFetching = !this.document;
const titleText = get(this.document, 'title', 'Loading');
@@ -217,4 +221,4 @@ const DocumentContainer = styled.div`
width: 50em;
`;
-export default withRouter(inject('ui', 'documents')(Document));
+export default withRouter(inject('ui', 'user', 'documents')(DocumentScene));
diff --git a/frontend/scenes/Document/components/Menu.js b/frontend/scenes/Document/components/Menu.js
index 76ac51a9..a5fe0976 100644
--- a/frontend/scenes/Document/components/Menu.js
+++ b/frontend/scenes/Document/components/Menu.js
@@ -16,9 +16,7 @@ type Props = {
props: Props;
onCreateDocument = () => {
- // Disabled until created a better API
- // invariant(this.props.collectionTree, 'collectionTree is not available');
- // this.props.history.push(`${this.props.collectionTree.url}/new`);
+ this.props.history.push(`${this.props.document.collection.url}/new`);
};
onCreateChild = () => {
@@ -68,7 +66,6 @@ type Props = {
-
}
{allowDelete && }
diff --git a/server/models/Document.js b/server/models/Document.js
index 206cb161..d94fe7f5 100644
--- a/server/models/Document.js
+++ b/server/models/Document.js
@@ -9,7 +9,7 @@ import { convertToMarkdown } from '../../frontend/utils/markdown';
import { truncateMarkdown } from '../utils/truncate';
import Revision from './Revision';
-const URL_REGEX = /^[a-zA-Z0-9-]*-([a-zA-Z]{10,15})$/;
+const URL_REGEX = /^[a-zA-Z0-9-]*-([a-zA-Z0-9]{10,15})$/;
slug.defaults.mode = 'rfc3986';
const slugify = text =>