feat: rename graph titles with select-then-edit interaction

This commit is contained in:
2026-11-06 01:40:40 +08:00
parent c9ce5fc2f1
commit af9988f78d
11 changed files with 212 additions and 9 deletions
+34 -1
View File
@@ -1,6 +1,6 @@
import { test } from "node:test";
import assert from "node:assert/strict";
import { boardHref, createBoard, DEFAULT_BOARD_TITLE, loadWorkspaceHome } from "../src/lib/workspace.ts";
import { boardHref, createBoard, renameBoard, DEFAULT_BOARD_TITLE, loadWorkspaceHome } from "../src/lib/workspace.ts";
test("profile and workspace reads both start before either completes", async () => {
const calls = [];
@@ -101,3 +101,36 @@ test("graph URLs preserve workspace identity and safely encode route segments",
assert.equal(boardHref("space/a", "id?b"), "/dashboard/space%2Fa/id%3Fb");
assert.equal(boardHref("demo", "board", true), "/dashboard/demo/board?demo=1");
});
test("renaming reads the latest version and preserves description and content", async () => {
const calls = [];
const content = { schema_version: 1, preserved: { key: "value" } };
const renamed = await renameBoard(async (path, options) => {
calls.push(path);
if (!options) return { id: "board", workspace_id: "space", kind: "board", title: "Old", version: 7, description: "Keep this", content };
assert.equal(options.method, "PATCH");
assert.equal(options.headers["If-Match"], '"7"');
assert.deepEqual(JSON.parse(options.body), { title: "新名称", description: "Keep this", content });
return null;
}, "space", "board", " 新名称 ");
assert.deepEqual(calls, ["workspaces/space/materials/board", "workspaces/space/materials/board"]);
assert.equal(renamed.title, "新名称");
assert.equal(renamed.version, 8);
});
test("rename rejects empty or oversized names without any API calls", async () => {
for (const name of [" ", "字".repeat(101)]) {
await assert.rejects(renameBoard(() => assert.fail("unexpected API call"), "space", "board", name), /invalid_title/);
}
});
test("rename surfaces a version conflict without retrying or overwriting", async () => {
let patches = 0;
await assert.rejects(renameBoard(async (_path, options) => {
if (!options) return { id: "board", workspace_id: "space", kind: "board", title: "Old", version: 1 };
patches++;
throw new Error("version_conflict");
}, "space", "board", "New"), /version_conflict/);
assert.equal(patches, 1);
});