A chapter with an order of its own

A chapter orders its own notes now, chosen in the same dialog as its name,
mark and colour -- one decision about one thing. The notebook's setting
governs the notebook's own list; a chapter is a place someone made and
filled, so a reference chapter can stay alphabetical while the notebook
around it stays as it was arranged. It starts hand-made, and a chapter put
in one of the other orders loses its lines and its handles exactly as the
notebook does: neither means anything against an order the app is choosing.

A line still would not go under another line, and the comparator was only
half of it. The write was then thrown away by the "did anything change?"
test, which sorted the separators before comparing them -- to ignore the
other chapters' lines riding along in the same field -- and a sorted
comparison cannot see a sequence. Two lines in one gap carry the same
position, so swapping them changes nothing else. It compares this list's own
lines, in order.

An open chapter swelled while rearranging: the strips at the two ends of its
list stood open for the whole of the mode, adding half a finger of empty
space inside every chapter. They are thin now, and only there while
something is actually being carried -- which is also why the suite presses
first and aims afterwards.

Server: sort_mode on chapters, validated against the same five modes as a
notebook's, and set outside the COALESCE so null means the hand-made order
rather than "leave it alone".

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
marcandClaude Opus 5 committed 2026-08-17 16:45:05 +02:00
1 parent ea1bca5d25
commit 3b7958b713
11 files changed
+354 -94

No files matched your search

+40
View File
@@ -303,6 +303,46 @@ try {
await p.waitForTimeout(800);
check((await p.locator("[data-separator]").count()) === 1, "and back on the way in");
/* ── one line under another ──
* Two lines in the same gap carry the same position, so swapping them changes
* nothing but their sequence. The write was computed correctly and then thrown
* away by a "did anything change?" test that sorted before comparing — and a
* sorted comparison cannot see a sequence. The line sprang back every time. */
await p.locator("[data-add-separator]").click();
await p.waitForTimeout(1800);
const lines = () =>
p.locator("[data-separator]").evaluateAll((els) => els.map((e) => e.innerText.trim()));
check((await p.locator("[data-separator]").count()) === 2, "a second line can be drawn");
// First bring them together, so what follows is the case that was broken:
// two lines in one gap, where only their sequence tells them apart.
await drag(p.locator("[data-separator]").first(), p.locator("[data-separator]").nth(1));
const lineOrder = await lines();
await drag(p.locator("[data-separator]").first(), p.locator("[data-separator]").nth(1));
const swapped = await lines();
check(
swapped[0] === lineOrder[1] && swapped[1] === lineOrder[0],
"a line dropped on another in the same gap goes under it",
`${lineOrder.join(" | ")} → ${swapped.join(" | ")}`
);
// And it was written, not only drawn.
await p.reload({ waitUntil: "networkidle" });
await p.waitForTimeout(2500);
await p.locator("button").filter({ hasText: "Ordnung" }).first().click();
await p.waitForTimeout(1800);
check(
(await lines()).join(" | ") === swapped.join(" | "),
"and stays under it after a reload",
(await lines()).join(" | ")
);
// Back to one line, so what follows reads the notebook it expects.
await p.locator("[data-separator]").first().click({ button: "right" });
await p.waitForTimeout(600);
await p.getByText("Remove separator").click();
await p.waitForTimeout(600);
await p.getByRole("button", { name: "Remove", exact: true }).click();
await p.waitForTimeout(2000);
check((await p.locator("[data-separator]").count()) === 1, "and one of them can be taken away again");
/* ── a new note goes on top, and takes nothing with it ──
*
* It used to be given no position at all and left to the tie-break, which put