feat: add cmdk dependency and enhance canvas node creation with edge splitting functionality

- Introduced the cmdk package for improved command palette capabilities.
- Enhanced the canvas placement context to support creating nodes with edge splitting, allowing for more dynamic node interactions.
- Updated the canvas inner component to utilize optimistic updates for node creation, improving user experience during interactions.
- Refactored node handling logic to incorporate new mutation types and streamline data management.
This commit is contained in:
Matthias
2026-03-27 23:40:31 +01:00
parent 4e84e7f76f
commit 6e866f2df6
15 changed files with 1037 additions and 112 deletions

View File

@@ -1,5 +1,7 @@
import { mutation } from "./_generated/server";
import { mutation, query } from "./_generated/server";
import { v } from "convex/values";
import { requireAuth } from "./helpers";
import type { Id } from "./_generated/dataModel";
export const generateUploadUrl = mutation({
args: {},
@@ -8,3 +10,41 @@ export const generateUploadUrl = mutation({
return await ctx.storage.generateUploadUrl();
},
});
/**
* Signierte URLs für alle Storage-Assets eines Canvas (gebündelt).
* `nodes.list` liefert keine URLs mehr, damit Node-Liste schnell bleibt.
*/
export const batchGetUrlsForCanvas = query({
args: { canvasId: v.id("canvases") },
handler: async (ctx, { canvasId }) => {
const user = await requireAuth(ctx);
const canvas = await ctx.db.get(canvasId);
if (!canvas || canvas.ownerId !== user.userId) {
throw new Error("Canvas not found");
}
const nodes = await ctx.db
.query("nodes")
.withIndex("by_canvas", (q) => q.eq("canvasId", canvasId))
.collect();
const ids = new Set<Id<"_storage">>();
for (const node of nodes) {
const data = node.data as Record<string, unknown> | undefined;
const sid = data?.storageId;
if (typeof sid === "string" && sid.length > 0) {
ids.add(sid as Id<"_storage">);
}
}
const entries = await Promise.all(
[...ids].map(
async (id) =>
[id, (await ctx.storage.getUrl(id)) ?? undefined] as const,
),
);
return Object.fromEntries(entries) as Record<string, string | undefined>;
},
});