From 344ac71501c3dc82e2853b07fbfa0ca3a609d2a4 Mon Sep 17 00:00:00 2001 From: Hakan Shehu Date: Tue, 1 Oct 2024 22:24:44 +0200 Subject: [PATCH] Fix some bugs with mutations and id generation in editor --- desktop/src/editor/extensions/id.tsx | 26 ++-- desktop/src/electron/workspace-manager.ts | 137 +++++++++++---------- server/src/mutations/node-collaborators.ts | 1 + 3 files changed, 83 insertions(+), 81 deletions(-) diff --git a/desktop/src/editor/extensions/id.tsx b/desktop/src/editor/extensions/id.tsx index d5775785..a790abe6 100644 --- a/desktop/src/editor/extensions/id.tsx +++ b/desktop/src/editor/extensions/id.tsx @@ -1,21 +1,21 @@ import { Extension } from '@tiptap/react'; import { Plugin, PluginKey } from 'prosemirror-state'; import { NeuronId } from '@/lib/id'; -import { NodeTypes } from '@/lib/constants'; +import { EditorNodeTypes } from '@/lib/constants'; const types = [ - NodeTypes.Paragraph, - NodeTypes.Heading1, - NodeTypes.Heading2, - NodeTypes.Heading3, - NodeTypes.Blockquote, - NodeTypes.BulletList, - NodeTypes.ListItem, - NodeTypes.OrderedList, - NodeTypes.TaskList, - NodeTypes.TaskItem, - NodeTypes.CodeBlock, - NodeTypes.HorizontalRule, + EditorNodeTypes.Paragraph, + EditorNodeTypes.Heading1, + EditorNodeTypes.Heading2, + EditorNodeTypes.Heading3, + EditorNodeTypes.Blockquote, + EditorNodeTypes.BulletList, + EditorNodeTypes.ListItem, + EditorNodeTypes.OrderedList, + EditorNodeTypes.TaskList, + EditorNodeTypes.TaskItem, + EditorNodeTypes.CodeBlock, + EditorNodeTypes.HorizontalRule, ]; export const IdExtension = Extension.create({ diff --git a/desktop/src/electron/workspace-manager.ts b/desktop/src/electron/workspace-manager.ts index 594213f6..2cceda4b 100644 --- a/desktop/src/electron/workspace-manager.ts +++ b/desktop/src/electron/workspace-manager.ts @@ -280,17 +280,11 @@ export class WorkspaceManager { mutation: ServerMutation, ): Promise { if (mutation.action === 'insert' && mutation.after) { - return this.syncNodeFromServer(mutation.after); + return this.createNodeFromServer(mutation.after); } else if (mutation.action === 'update' && mutation.after) { - return this.syncNodeFromServer(mutation.after); + return this.updateNodeFromServer(mutation.after); } else if (mutation.action === 'delete' && mutation.before) { - await this.database - .deleteFrom('nodes') - .where('id', '=', mutation.before.id) - .execute(); - - this.debouncedNotifyQuerySubscribers(['nodes']); - return true; + return this.deleteNodeFromServer(mutation.before); } } @@ -424,74 +418,81 @@ export class WorkspaceManager { return false; } - public async syncNodeFromServer(node: ServerNode): Promise { - try { - const existingNode = await this.database - .selectFrom('nodes') - .selectAll() - .where('id', '=', node.id) - .executeTakeFirst(); - - if (!existingNode) { - await this.database - .insertInto('nodes') - .values({ - id: node.id, - attributes: JSON.stringify(node.attributes), - state: node.state, - created_at: node.createdAt, - created_by: node.createdBy, - updated_by: node.updatedBy, - updated_at: node.updatedAt, - version_id: node.versionId, + private async createNodeFromServer(node: ServerNode): Promise { + await this.database + .insertInto('nodes') + .values({ + id: node.id, + attributes: JSON.stringify(node.attributes), + state: node.state, + created_at: node.createdAt, + created_by: node.createdBy, + updated_by: node.updatedBy, + updated_at: node.updatedAt, + version_id: node.versionId, + server_created_at: node.serverCreatedAt, + server_updated_at: node.serverUpdatedAt, + server_version_id: node.versionId, + }) + .onConflict((cb) => + cb + .doUpdateSet({ server_created_at: node.serverCreatedAt, server_updated_at: node.serverUpdatedAt, server_version_id: node.versionId, }) - .onConflict((cb) => cb.doNothing()) - .execute(); + .where('version_id', '=', node.versionId), + ) + .execute(); - this.debouncedNotifyQuerySubscribers(['nodes']); - return true; - } + this.debouncedNotifyQuerySubscribers(['nodes']); + return true; + } - if (this.shouldUpdateNodeFromServer(existingNode, node)) { - const doc = new Y.Doc({ - guid: node.id, - }); + private async updateNodeFromServer(node: ServerNode): Promise { + const existingNode = await this.database + .selectFrom('nodes') + .selectAll() + .where('id', '=', node.id) + .executeTakeFirst(); - Y.applyUpdate(doc, toUint8Array(existingNode.state)); - Y.applyUpdate(doc, toUint8Array(node.state)); - - const attributesMap = doc.getMap('attributes'); - const attributes = JSON.stringify(attributesMap.toJSON()); - const encodedState = fromUint8Array(Y.encodeStateAsUpdate(doc)); - - await this.database - .updateTable('nodes') - .set({ - attributes: attributes, - state: encodedState, - updated_at: node.updatedAt, - updated_by: node.updatedBy, - version_id: node.versionId, - server_created_at: node.serverCreatedAt, - server_updated_at: node.serverUpdatedAt, - server_version_id: node.versionId, - }) - .where('id', '=', node.id) - .execute(); - - this.debouncedNotifyQuerySubscribers(['nodes']); - return true; - } - } catch (error) { - if (error.code === 'SQLITE_CONSTRAINT_FOREIGNKEY') { - return true; - } + if (!this.shouldUpdateNodeFromServer(existingNode, node)) { + return true; } + const doc = new Y.Doc({ + guid: node.id, + }); - return false; + Y.applyUpdate(doc, toUint8Array(existingNode.state)); + Y.applyUpdate(doc, toUint8Array(node.state)); + + const attributesMap = doc.getMap('attributes'); + const attributes = JSON.stringify(attributesMap.toJSON()); + const encodedState = fromUint8Array(Y.encodeStateAsUpdate(doc)); + + await this.database + .updateTable('nodes') + .set({ + attributes: attributes, + state: encodedState, + updated_at: node.updatedAt, + updated_by: node.updatedBy, + version_id: node.versionId, + server_created_at: node.serverCreatedAt, + server_updated_at: node.serverUpdatedAt, + server_version_id: node.versionId, + }) + .where('id', '=', node.id) + .execute(); + + this.debouncedNotifyQuerySubscribers(['nodes']); + return true; + } + + private async deleteNodeFromServer(node: ServerNode): Promise { + await this.database.deleteFrom('nodes').where('id', '=', node.id).execute(); + this.debouncedNotifyQuerySubscribers(['nodes']); + return true; } public async syncNodeCollaboratorFromServer( diff --git a/server/src/mutations/node-collaborators.ts b/server/src/mutations/node-collaborators.ts index f3464513..610841c9 100644 --- a/server/src/mutations/node-collaborators.ts +++ b/server/src/mutations/node-collaborators.ts @@ -42,6 +42,7 @@ const handleCreateNodeCollaboratorMutation = async ( workspaceAccount, nodeCollaboratorData, ); + if (!canCreate) { return { status: 'error',