mirror of
https://github.com/outline/outline.git
synced 2026-05-07 18:41:12 -05:00
fix: 'shared with me' optimistic updates (#10547)
* optimistic state updates when documents under 'shared with me' section are created * optimistic updates for other 'shared with me' document actions * update top level document * use action decorator
This commit is contained in:
@@ -302,6 +302,7 @@ function InnerDocumentLink(
|
||||
{ publish: true }
|
||||
);
|
||||
collection?.addDocument(newDocument, node.id);
|
||||
membership?.addDocument(newDocument, node.id);
|
||||
|
||||
closeAddingNewChild();
|
||||
history.push({
|
||||
|
||||
@@ -20,9 +20,6 @@ class GroupMembership extends NavigableModel {
|
||||
@Relation(() => Group, { onDelete: "cascade" })
|
||||
group: Group;
|
||||
|
||||
/** The document ID that this membership grants the group access to. */
|
||||
documentId: string | undefined;
|
||||
|
||||
/** The document that this membership grants the group access to. */
|
||||
@Relation(() => Document, { onDelete: "cascade" })
|
||||
document: Document | undefined;
|
||||
@@ -46,7 +43,6 @@ class GroupMembership extends NavigableModel {
|
||||
permission: CollectionPermission | DocumentPermission;
|
||||
|
||||
// methods
|
||||
|
||||
/**
|
||||
* Fetches the child documents structure from the server.
|
||||
*/
|
||||
|
||||
@@ -20,9 +20,6 @@ class UserMembership extends NavigableModel {
|
||||
@observable
|
||||
permission: DocumentPermission;
|
||||
|
||||
/** The document ID that this membership grants the user access to. */
|
||||
documentId?: string;
|
||||
|
||||
/** The document that this membership grants the user access to. */
|
||||
@Relation(() => Document, { onDelete: "cascade" })
|
||||
document?: Document;
|
||||
|
||||
@@ -1,11 +1,15 @@
|
||||
import { computed, observable, runInAction } from "mobx";
|
||||
import { action, computed, observable, runInAction } from "mobx";
|
||||
import { JSONObject, type NavigationNode } from "@shared/types";
|
||||
import { client } from "~/utils/ApiClient";
|
||||
import ParanoidModel from "./ParanoidModel";
|
||||
import type Document from "../Document";
|
||||
|
||||
export default abstract class NavigableModel extends ParanoidModel {
|
||||
private isFetching = false;
|
||||
|
||||
/** The document ID associated with this model. */
|
||||
documentId?: string;
|
||||
|
||||
@observable
|
||||
node?: NavigationNode;
|
||||
|
||||
@@ -45,6 +49,13 @@ export default abstract class NavigableModel extends ParanoidModel {
|
||||
return this.node?.children;
|
||||
}
|
||||
|
||||
@action
|
||||
setDocuments(value: NavigationNode[] | undefined) {
|
||||
if (this.node && value) {
|
||||
this.node.children = value;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the document path from the original document shared with this membership.
|
||||
*/
|
||||
@@ -109,4 +120,60 @@ export default abstract class NavigableModel extends ParanoidModel {
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the document identified by the given id to the model in
|
||||
* memory. Does not add the document to the database or store.
|
||||
*
|
||||
* @param document The document to add.
|
||||
* @param parentDocumentId The id of the document to add the new document to.
|
||||
*/
|
||||
@action
|
||||
addDocument(document: Document, parentDocumentId: string) {
|
||||
if (!this.documents || !document || !parentDocumentId?.trim()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.documentId && parentDocumentId === this.documentId) {
|
||||
this.setDocuments([document.asNavigationNode, ...(this.documents ?? [])]);
|
||||
}
|
||||
|
||||
const travelNodes = (nodes: NavigationNode[]) =>
|
||||
nodes.forEach((node) => {
|
||||
if (node.id === parentDocumentId) {
|
||||
node.children = [document.asNavigationNode, ...(node.children ?? [])];
|
||||
} else {
|
||||
travelNodes(node.children);
|
||||
}
|
||||
});
|
||||
|
||||
travelNodes(this.documents);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the document identified by the given id from the model in
|
||||
* memory. Does not remove the document from the database.
|
||||
*
|
||||
* @param documentId The id of the document to remove.
|
||||
*/
|
||||
@action
|
||||
removeDocument(documentId: string) {
|
||||
if (!this.documents) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.setDocuments(
|
||||
this.documents.filter(function f(node): boolean {
|
||||
if (node.id === documentId) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (node.children) {
|
||||
node.children = node.children.filter(f);
|
||||
}
|
||||
|
||||
return true;
|
||||
})
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,7 +21,8 @@ type Props = {
|
||||
|
||||
function DocumentDelete({ document, onSubmit }: Props) {
|
||||
const { t } = useTranslation();
|
||||
const { ui, documents, collections } = useStores();
|
||||
const { ui, documents, collections, userMemberships, groupMemberships } =
|
||||
useStores();
|
||||
const history = useHistory();
|
||||
const [isDeleting, setDeleting] = React.useState(false);
|
||||
const [isArchiving, setArchiving] = React.useState(false);
|
||||
@@ -41,6 +42,13 @@ function DocumentDelete({ document, onSubmit }: Props) {
|
||||
try {
|
||||
await document.delete();
|
||||
|
||||
userMemberships
|
||||
.getByDocumentId(document.id)
|
||||
?.removeDocument(document.id);
|
||||
groupMemberships
|
||||
.getByDocumentId(document.id)
|
||||
?.removeDocument(document.id);
|
||||
|
||||
// only redirect if we're currently viewing the document that's deleted
|
||||
if (ui.activeDocumentId === document.id) {
|
||||
// If the document has a parent and it's available in the store then
|
||||
|
||||
@@ -25,7 +25,8 @@ function DocumentNew({ template }: Props) {
|
||||
const user = useCurrentUser();
|
||||
const match = useRouteMatch<{ id?: string }>();
|
||||
const { t } = useTranslation();
|
||||
const { documents, collections } = useStores();
|
||||
const { documents, collections, userMemberships, groupMemberships } =
|
||||
useStores();
|
||||
const id = match.params.id || query.get("collectionId");
|
||||
|
||||
useEffect(() => {
|
||||
@@ -55,6 +56,16 @@ function DocumentNew({ template }: Props) {
|
||||
{ publish: collection?.id || parentDocumentId ? true : undefined }
|
||||
);
|
||||
|
||||
if (parentDocumentId) {
|
||||
userMemberships
|
||||
.getByDocumentId(document.id)
|
||||
?.addDocument(document, parentDocumentId);
|
||||
|
||||
groupMemberships
|
||||
.getByDocumentId(document.id)
|
||||
?.addDocument(document, parentDocumentId);
|
||||
}
|
||||
|
||||
history.replace(
|
||||
template || !user.separateEditMode
|
||||
? documentPath(document)
|
||||
|
||||
Reference in New Issue
Block a user