diff --git a/app/components/Sidebar/components/DocumentLink.tsx b/app/components/Sidebar/components/DocumentLink.tsx index 3106d6fed1..2c23d03f50 100644 --- a/app/components/Sidebar/components/DocumentLink.tsx +++ b/app/components/Sidebar/components/DocumentLink.tsx @@ -302,6 +302,7 @@ function InnerDocumentLink( { publish: true } ); collection?.addDocument(newDocument, node.id); + membership?.addDocument(newDocument, node.id); closeAddingNewChild(); history.push({ diff --git a/app/models/GroupMembership.ts b/app/models/GroupMembership.ts index 3d9b14cc31..389f6e9405 100644 --- a/app/models/GroupMembership.ts +++ b/app/models/GroupMembership.ts @@ -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. */ diff --git a/app/models/UserMembership.ts b/app/models/UserMembership.ts index 0ab32181e6..832c4e8e52 100644 --- a/app/models/UserMembership.ts +++ b/app/models/UserMembership.ts @@ -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; diff --git a/app/models/base/NavigableModel.ts b/app/models/base/NavigableModel.ts index 1244c74cd6..259097b28c 100644 --- a/app/models/base/NavigableModel.ts +++ b/app/models/base/NavigableModel.ts @@ -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; + }) + ); + } } diff --git a/app/scenes/DocumentDelete.tsx b/app/scenes/DocumentDelete.tsx index f5a75cc599..e0e899cb41 100644 --- a/app/scenes/DocumentDelete.tsx +++ b/app/scenes/DocumentDelete.tsx @@ -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 diff --git a/app/scenes/DocumentNew.tsx b/app/scenes/DocumentNew.tsx index debc416d89..04669154d8 100644 --- a/app/scenes/DocumentNew.tsx +++ b/app/scenes/DocumentNew.tsx @@ -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)