fix: Improved handling of simultaneous edits

This commit is contained in:
Tom Moor
2020-06-02 23:16:15 -07:00
parent 05e24df226
commit 33815639f2
3 changed files with 58 additions and 29 deletions

View File

@ -128,22 +128,6 @@ class SocketProvider extends React.Component<Props> {
}); });
} }
} }
// TODO: Move this to the document scene once data loading
// has been refactored to be friendlier there.
if (
auth.user &&
documentId === ui.activeDocumentId &&
document.updatedBy.id !== auth.user.id
) {
ui.showToast(`Document updated by ${document.updatedBy.name}`, {
timeout: 30 * 1000,
action: {
text: 'Refresh',
onClick: () => window.location.reload(),
},
});
}
} }
} }

View File

@ -10,7 +10,12 @@ import Revision from 'models/Revision';
import User from 'models/User'; import User from 'models/User';
import DocumentsStore from 'stores/DocumentsStore'; import DocumentsStore from 'stores/DocumentsStore';
type SaveOptions = { publish?: boolean, done?: boolean, autosave?: boolean }; type SaveOptions = {
publish?: boolean,
done?: boolean,
autosave?: boolean,
lastRevision?: number,
};
export default class Document extends BaseModel { export default class Document extends BaseModel {
@observable isSaving: boolean = false; @observable isSaving: boolean = false;
@ -185,7 +190,7 @@ export default class Document extends BaseModel {
id: this.id, id: this.id,
title: this.title, title: this.title,
text: this.text, text: this.text,
lastRevision: this.revision, lastRevision: options.lastRevision,
...options, ...options,
}); });
} finally { } finally {

View File

@ -14,6 +14,7 @@ import {
documentMoveUrl, documentMoveUrl,
documentHistoryUrl, documentHistoryUrl,
documentEditUrl, documentEditUrl,
documentUrl,
} from 'utils/routeHelpers'; } from 'utils/routeHelpers';
import { emojiToUrl } from 'utils/emoji'; import { emojiToUrl } from 'utils/emoji';
@ -74,11 +75,13 @@ class DocumentScene extends React.Component<Props> {
@observable isDirty: boolean = false; @observable isDirty: boolean = false;
@observable isEmpty: boolean = true; @observable isEmpty: boolean = true;
@observable moveModalOpen: boolean = false; @observable moveModalOpen: boolean = false;
@observable lastRevision: number;
@observable title: string; @observable title: string;
constructor(props) { constructor(props) {
super(); super();
this.title = props.document.title; this.title = props.document.title;
this.lastRevision = props.document.revision;
this.loadEditor(); this.loadEditor();
} }
@ -86,6 +89,29 @@ class DocumentScene extends React.Component<Props> {
this.updateIsDirty(); this.updateIsDirty();
} }
componentDidUpdate(prevProps) {
const { auth, document } = this.props;
if (this.props.readOnly) {
this.lastRevision = document.revision;
} else if (prevProps.document.revision !== this.lastRevision) {
if (auth.user && document.updatedBy.id !== auth.user.id) {
this.props.ui.showToast(
`Document updated by ${document.updatedBy.name}`,
{
timeout: 30 * 1000,
action: {
text: 'Reload',
onClick: () => {
window.location.href = documentUrl(document);
},
},
}
);
}
}
}
@keydown('m') @keydown('m')
goToMove(ev) { goToMove(ev) {
if (!this.props.readOnly) return; if (!this.props.readOnly) return;
@ -174,7 +200,11 @@ class DocumentScene extends React.Component<Props> {
handleOpenMoveModal = () => (this.moveModalOpen = true); handleOpenMoveModal = () => (this.moveModalOpen = true);
onSave = async ( onSave = async (
options: { done?: boolean, publish?: boolean, autosave?: boolean } = {} options: {
done?: boolean,
publish?: boolean,
autosave?: boolean,
} = {}
) => { ) => {
const { document } = this.props; const { document } = this.props;
@ -202,17 +232,27 @@ class DocumentScene extends React.Component<Props> {
let isNew = !document.id; let isNew = !document.id;
this.isSaving = true; this.isSaving = true;
this.isPublishing = !!options.publish; this.isPublishing = !!options.publish;
const savedDocument = await document.save(options);
this.isDirty = false;
this.isSaving = false;
this.isPublishing = false;
if (options.done) { try {
this.props.history.push(savedDocument.url); const savedDocument = await document.save({
this.props.ui.setActiveDocument(savedDocument); ...options,
} else if (isNew) { lastRevision: this.lastRevision,
this.props.history.push(documentEditUrl(savedDocument)); });
this.props.ui.setActiveDocument(savedDocument); this.isDirty = false;
this.lastRevision = savedDocument.revision;
if (options.done) {
this.props.history.push(savedDocument.url);
this.props.ui.setActiveDocument(savedDocument);
} else if (isNew) {
this.props.history.push(documentEditUrl(savedDocument));
this.props.ui.setActiveDocument(savedDocument);
}
} catch (err) {
this.props.ui.showToast(err.message);
} finally {
this.isSaving = false;
this.isPublishing = false;
} }
}; };