mirror of
https://github.com/colanode/colanode.git
synced 2025-12-16 19:57:46 +01:00
Fix some mutations
This commit is contained in:
@@ -1,5 +1,3 @@
|
|||||||
import { merge } from 'lodash-es';
|
|
||||||
|
|
||||||
import { WorkspaceMutationHandlerBase } from '@colanode/client/handlers/mutations/workspace-mutation-handler-base';
|
import { WorkspaceMutationHandlerBase } from '@colanode/client/handlers/mutations/workspace-mutation-handler-base';
|
||||||
import { MutationHandler } from '@colanode/client/lib/types';
|
import { MutationHandler } from '@colanode/client/lib/types';
|
||||||
import {
|
import {
|
||||||
@@ -15,8 +13,8 @@ export class NodeUpdateMutationHandler
|
|||||||
input: NodeUpdateMutationInput
|
input: NodeUpdateMutationInput
|
||||||
): Promise<NodeUpdateMutationOutput> {
|
): Promise<NodeUpdateMutationOutput> {
|
||||||
const workspace = this.getWorkspace(input.userId);
|
const workspace = this.getWorkspace(input.userId);
|
||||||
await workspace.nodes.updateNode(input.nodeId, (attributes) => {
|
await workspace.nodes.updateNode(input.nodeId, () => {
|
||||||
return merge(attributes, input.attributes);
|
return input.attributes;
|
||||||
});
|
});
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ export type NodeUpdateMutationInput = {
|
|||||||
type: 'node.update';
|
type: 'node.update';
|
||||||
userId: string;
|
userId: string;
|
||||||
nodeId: string;
|
nodeId: string;
|
||||||
attributes: Partial<NodeAttributes>;
|
attributes: NodeAttributes;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type NodeUpdateMutationOutput = {
|
export type NodeUpdateMutationOutput = {
|
||||||
|
|||||||
@@ -52,11 +52,16 @@ export class YDoc {
|
|||||||
schema: z.ZodSchema,
|
schema: z.ZodSchema,
|
||||||
object: z.infer<typeof schema>
|
object: z.infer<typeof schema>
|
||||||
): Uint8Array | null {
|
): Uint8Array | null {
|
||||||
if (!schema.safeParse(object).success) {
|
const normalizedObject = this.normalizeForUpdate(object);
|
||||||
throw new Error('Invalid object', schema.safeParse(object).error);
|
|
||||||
|
const parseResult = schema.safeParse(normalizedObject);
|
||||||
|
if (!parseResult.success) {
|
||||||
|
throw new Error(`Invalid object: ${parseResult.error.message}`, {
|
||||||
|
cause: parseResult.error,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
const objectSchema = this.extractType(schema, object);
|
const objectSchema = this.extractType(schema, normalizedObject);
|
||||||
if (!(objectSchema instanceof z.ZodObject)) {
|
if (!(objectSchema instanceof z.ZodObject)) {
|
||||||
throw new Error('Schema must be a ZodObject');
|
throw new Error('Schema must be a ZodObject');
|
||||||
}
|
}
|
||||||
@@ -70,7 +75,7 @@ export class YDoc {
|
|||||||
|
|
||||||
const objectMap = this.doc.getMap('object');
|
const objectMap = this.doc.getMap('object');
|
||||||
this.doc.transact(() => {
|
this.doc.transact(() => {
|
||||||
this.applyObjectChanges(objectSchema, object, objectMap);
|
this.applyObjectChanges(objectSchema, normalizedObject, objectMap);
|
||||||
|
|
||||||
const parseResult = schema.safeParse(objectMap.toJSON());
|
const parseResult = schema.safeParse(objectMap.toJSON());
|
||||||
if (!parseResult.success) {
|
if (!parseResult.success) {
|
||||||
@@ -469,4 +474,26 @@ export class YDoc {
|
|||||||
|
|
||||||
return schema;
|
return schema;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private normalizeForUpdate(object: any): any {
|
||||||
|
if (object === null || object === undefined) {
|
||||||
|
return object;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Array.isArray(object)) {
|
||||||
|
return object.map((item) => this.normalizeForUpdate(item));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeof object === 'object') {
|
||||||
|
const normalized: any = {};
|
||||||
|
for (const [key, value] of Object.entries(object)) {
|
||||||
|
if (value !== undefined) {
|
||||||
|
normalized[key] = this.normalizeForUpdate(value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return normalized;
|
||||||
|
}
|
||||||
|
|
||||||
|
return object;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -83,22 +83,24 @@ export const SelectFieldOptions = ({
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!fieldDraft.options) {
|
const existingOptions = fieldDraft.options ?? {};
|
||||||
fieldDraft.options = {};
|
const maxIndex = Object.values(existingOptions)
|
||||||
}
|
|
||||||
|
|
||||||
const maxIndex = Object.values(fieldDraft.options)
|
|
||||||
.map((selectOption) => selectOption.index)
|
.map((selectOption) => selectOption.index)
|
||||||
.sort((a, b) => -compareString(a, b))[0];
|
.sort((a, b) => -compareString(a, b))[0];
|
||||||
|
|
||||||
const index = generateFractionalIndex(maxIndex, null);
|
const index = generateFractionalIndex(maxIndex, null);
|
||||||
|
|
||||||
fieldDraft.options[selectOptionId] = {
|
const updatedOptions = {
|
||||||
name: name,
|
...existingOptions,
|
||||||
id: selectOptionId,
|
[selectOptionId]: {
|
||||||
color: color,
|
name: name,
|
||||||
index: index,
|
id: selectOptionId,
|
||||||
|
color: color,
|
||||||
|
index: index,
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
fieldDraft.options = updatedOptions;
|
||||||
});
|
});
|
||||||
|
|
||||||
return selectOptionId;
|
return selectOptionId;
|
||||||
@@ -113,6 +115,7 @@ export const SelectFieldOptions = ({
|
|||||||
onSelect(selectOptionId);
|
onSelect(selectOptionId);
|
||||||
},
|
},
|
||||||
onError: (error) => {
|
onError: (error) => {
|
||||||
|
console.log('error', error);
|
||||||
toast.error(error.message as string);
|
toast.error(error.message as string);
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import { createCollection } from '@tanstack/react-db';
|
import { createCollection } from '@tanstack/react-db';
|
||||||
|
import { cloneDeep } from 'lodash-es';
|
||||||
|
|
||||||
import { LocalNode } from '@colanode/client/types';
|
import { LocalNode } from '@colanode/client/types';
|
||||||
|
|
||||||
@@ -49,38 +50,33 @@ export const createNodesCollection = (userId: string) => {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
onInsert: async ({ transaction }) => {
|
onInsert: async ({ transaction }) => {
|
||||||
transaction.mutations.forEach(async (mutation) => {
|
for (const mutation of transaction.mutations) {
|
||||||
await window.colanode.executeMutation({
|
await window.colanode.executeMutation({
|
||||||
type: 'node.create',
|
type: 'node.create',
|
||||||
userId,
|
userId,
|
||||||
node: mutation.modified,
|
node: mutation.modified,
|
||||||
});
|
});
|
||||||
});
|
}
|
||||||
},
|
},
|
||||||
onUpdate: async ({ transaction }) => {
|
onUpdate: async ({ transaction }) => {
|
||||||
transaction.mutations.forEach(async (mutation) => {
|
for (const mutation of transaction.mutations) {
|
||||||
console.log('onUpdate', mutation);
|
const attributes = cloneDeep(mutation.modified.attributes);
|
||||||
const attributes = mutation.changes.attributes;
|
|
||||||
if (!attributes) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
await window.colanode.executeMutation({
|
await window.colanode.executeMutation({
|
||||||
type: 'node.update',
|
type: 'node.update',
|
||||||
userId,
|
userId,
|
||||||
nodeId: mutation.key,
|
nodeId: mutation.key,
|
||||||
attributes,
|
attributes,
|
||||||
});
|
});
|
||||||
});
|
}
|
||||||
},
|
},
|
||||||
onDelete: async ({ transaction }) => {
|
onDelete: async ({ transaction }) => {
|
||||||
transaction.mutations.forEach(async (mutation) => {
|
for (const mutation of transaction.mutations) {
|
||||||
await window.colanode.executeMutation({
|
await window.colanode.executeMutation({
|
||||||
type: 'node.delete',
|
type: 'node.delete',
|
||||||
userId,
|
userId,
|
||||||
nodeId: mutation.key,
|
nodeId: mutation.key,
|
||||||
});
|
});
|
||||||
});
|
}
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user