import type { Profile } from "./api"; export type Workspace = { id: string; slug?: string; name: string; role?: "admin" | "editor" | "viewer" }; export type Board = { id: string; workspace_id: string; slug?: string; kind: "board"; title: string; version: number; content?: { schema_version: number }; description?: string; parent_board_id?: string; frame_id?: string; }; export function matchesRef(item: { id: string; slug?: string } | null | undefined, ref: string | undefined) { return Boolean(item && ref && (item.id === ref || item.slug === ref)); } export const DEFAULT_BOARD_TITLE = "未命名图谱"; export function boardHref(workspace: string, board: string, demo = false) { return `/dashboard/${encodeURIComponent(workspace)}/${encodeURIComponent(board)}${demo ? "?demo=1" : ""}`; } type Request = (path: string, options?: RequestInit) => Promise; export async function loadWorkspaceHome( request: Request, signal?: AbortSignal, ) { const [profile, result] = await Promise.all([ request("profile", { signal }), request("workspaces", { signal }), ]); return { profile, workspaces: Array.isArray(result) ? result : result.items || [], }; } export async function createBoard( request: Request, title: string, workspaceId: string, onWorkspaceCreated: (workspace: Workspace) => void, ) { let id = workspaceId; if (!id) { const workspace = await request("workspaces", { method: "POST", body: JSON.stringify({ name: "个人空间" }), }); id = workspace.id; onWorkspaceCreated(workspace); } const name = title.trim() || DEFAULT_BOARD_TITLE; const result = await request<{ id: string; workspace_id: string; kind: "board"; version: number; slug?: string }>("workspaces/" + id + "/materials", { method: "POST", body: JSON.stringify({ kind: "board", title: name, content: { schema_version: 1 }, }), }); return { ...result, workspace_id: result.workspace_id || id, title: name }; } export async function renameBoard(request: Request, workspaceId: string, boardId: string, title: string): Promise { const name = title.trim(); if (!name || new TextEncoder().encode(name).length > 300) throw new Error("invalid_title"); const path = `workspaces/${encodeURIComponent(workspaceId)}/materials/${encodeURIComponent(boardId)}`; const current = await request(path); if (current.kind !== "board" || !matchesRef(current, boardId) || current.workspace_id !== workspaceId) throw new Error("invalid_reference"); await request(path, { method: "PATCH", headers: { "If-Match": `"${current.version}"` }, body: JSON.stringify({ title: name, description: current.description || "", content: current.content || { schema_version: 1 } }), }); return { ...current, title: name, version: current.version + 1 }; }