diff --git a/frontend/models/Collection.js b/frontend/models/Collection.js index 13d8e5e8b..80d0ba393 100644 --- a/frontend/models/Collection.js +++ b/frontend/models/Collection.js @@ -93,7 +93,7 @@ class Collection extends BaseModel { } }; - updateData(data: Object = {}) { + @action updateData(data: Object = {}) { this.data = data; extendObservable(this, data); } @@ -107,6 +107,14 @@ class Collection extends BaseModel { this.on('documents.delete', (data: { collectionId: string }) => { if (data.collectionId === this.id) this.fetch(); }); + this.on( + 'collections.update', + (data: { id: string, collection: Collection }) => { + // FIXME: calling this.updateData won't update the + // UI. Some mobx issue + if (data.id === this.id) this.fetch(); + } + ); } } diff --git a/frontend/models/Document.js b/frontend/models/Document.js index ea39c2f62..eade37798 100644 --- a/frontend/models/Document.js +++ b/frontend/models/Document.js @@ -160,6 +160,11 @@ class Document extends BaseModel { this.updateData(res.data); this.hasPendingChanges = false; }); + + this.emit('collections.update', { + id: this.collection.id, + collection: this.collection, + }); } catch (e) { this.errors.add('Document failed saving'); } finally { diff --git a/frontend/scenes/Document/Document.js b/frontend/scenes/Document/Document.js index 4bc09784a..b64c0023f 100644 --- a/frontend/scenes/Document/Document.js +++ b/frontend/scenes/Document/Document.js @@ -6,7 +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 { collectionUrl, updateDocumentUrl } from 'utils/routeHelpers'; import Document from 'models/Document'; import UiStore from 'stores/UiStore'; @@ -90,6 +90,11 @@ type Props = { if (document) { this.props.ui.setActiveDocument(document); document.view(); + + // Update url to match the current one + this.props.history.replace( + updateDocumentUrl(this.props.match.url, document.url) + ); } else { // Render 404 with search this.setState({ notFound: true }); diff --git a/frontend/stores/DocumentsStore.js b/frontend/stores/DocumentsStore.js index 7ccedcad5..cfbb70f99 100644 --- a/frontend/stores/DocumentsStore.js +++ b/frontend/stores/DocumentsStore.js @@ -138,8 +138,11 @@ class DocumentsStore extends BaseStore { return this.data.get(id); }; + /** + * Match documents by the url ID as the title slug can change + */ getByUrl = (url: string): ?Document => { - return _.find(this.data.values(), { url }); + return _.find(this.data.values(), doc => url.endsWith(doc.urlId)); }; constructor(options: Options) { diff --git a/frontend/utils/routeHelpers.js b/frontend/utils/routeHelpers.js index ce11b20f3..2a273bd51 100644 --- a/frontend/utils/routeHelpers.js +++ b/frontend/utils/routeHelpers.js @@ -38,3 +38,13 @@ export function searchUrl(query?: string): string { export function notFoundUrl(): string { return '/404'; } + +/** + * Replace full url's document part with the new one in case + * the document slug has been updated + */ +export function updateDocumentUrl(oldUrl: string, newUrl: string): string { + // Update url to match the current one + const urlParts = oldUrl.split('/'); + return [newUrl, urlParts.slice(3)].join('/'); +} diff --git a/server/api/documents.js b/server/api/documents.js index 178e590aa..a179f9830 100644 --- a/server/api/documents.js +++ b/server/api/documents.js @@ -211,6 +211,8 @@ router.post('documents.create', auth(), async ctx => { await ownerCollection.addDocumentToStructure(document, index); } + document.collection = ownerCollection; + ctx.body = { data: await presentDocument(ctx, document), }; @@ -280,6 +282,8 @@ router.post('documents.move', auth(), async ctx => { await collection.addDocumentToStructure(document, index); } + document.collection = collection; + ctx.body = { data: await presentDocument(ctx, document), }; diff --git a/server/presenters/document.js b/server/presenters/document.js index 0ca0ea186..5927a83d9 100644 --- a/server/presenters/document.js +++ b/server/presenters/document.js @@ -17,6 +17,7 @@ async function present(ctx: Object, document: Document, options: ?Options) { const data = { id: document.id, url: document.getUrl(), + urlId: document.urlId, private: document.private, title: document.title, text: document.text,