mirror of
https://github.com/Ark0N/Codeman.git
synced 2026-10-08 08:29:42 +02:00
fix(tabs): grouped rail editing review fixes
- Pointer drag: a press released outside the rail no longer lingers. The
release is heard on window while a press is pending, a move with the
primary button up cancels it, a new press cancels any previous drag, and
an existing Escape listener is removed before another is added, so no
orphaned capture listener can swallow Escape before the terminal.
- Inline group rename: a commit by blur leaves focus where the user put it;
Enter and Escape still return focus to the header.
- A failed layout read while edits are pending keeps the held layout and the
editor and re-reads once the write settles, so a 409 is still rebased.
Dropping unsaved work now always says so in a toast.
- "Move to <group>" quotes the group name (with a matching zh-CN pattern), so
a group named "New group" or "ungrouped" no longer reads or translates like
the fixed entries.
- The group menu glyph stays visible under (hover: none).
- The sessionStorage replay copy carries { owner, baseVersion, savedAt } and is
ignored for another owner, after 60 s, or against an older layout. A move
with no anchor carries no index, so a replay keeps the row last.
- A 400 that survives the re-read is reported as "Could not save tab groups."
- closeTabRailActionMenu() no longer removes the group menu's DOM.
- Cancelling "Delete group" returns focus to the header.
- Stale comments updated.
This commit is contained in:
@@ -427,9 +427,11 @@
|
||||
const layout = normalizeLayout(layoutInput);
|
||||
const block = lineageBlock(layout, ref, parents);
|
||||
const remaining = containerRefs(layout, groupId).filter((candidate) => !block.has(refKey(candidate)));
|
||||
if (!anchor) return { groupId, index: remaining.length };
|
||||
// No anchor means "at the end", and an operation with no index keeps
|
||||
// meaning that when it is replayed onto a layout that has changed since.
|
||||
if (!anchor) return { groupId };
|
||||
const at = remaining.findIndex((candidate) => refKey(candidate) === refKey(anchor));
|
||||
if (at < 0) return { groupId, index: remaining.length };
|
||||
if (at < 0) return { groupId };
|
||||
return { groupId, index: placement === 'after' ? at + 1 : at };
|
||||
}
|
||||
|
||||
@@ -482,7 +484,7 @@
|
||||
type: 'moveRef',
|
||||
ref: { kind: source.ref.kind, id: source.ref.id },
|
||||
groupId: destination.groupId,
|
||||
index: destination.index,
|
||||
...(destination.index === undefined ? {} : { index: destination.index }),
|
||||
parents: parents || {},
|
||||
};
|
||||
return contentKey(applyOperation(layout, operation)) === contentKey(layout) ? null : operation;
|
||||
@@ -613,6 +615,7 @@
|
||||
pending = [];
|
||||
let failed = false;
|
||||
let reportedDrop = false;
|
||||
let rereadFor400 = false;
|
||||
try {
|
||||
for (let attempt = 0; attempt < maxAttempts && inFlight.length; attempt++) {
|
||||
const desired = replayOperations(authoritative, inFlight);
|
||||
@@ -633,7 +636,10 @@
|
||||
inFlight = [];
|
||||
} else if (response?.status === 409 && response.layout) {
|
||||
authoritative = normalizeLayout(response.layout);
|
||||
} else if (response?.status === 400 && options.fetchLayout) {
|
||||
} else if (response?.status === 400 && options.fetchLayout && !rereadFor400) {
|
||||
// Maybe our base was stale in a way the server reports as invalid:
|
||||
// re-read once. A 400 that survives that is a refusal, not a race.
|
||||
rereadFor400 = true;
|
||||
authoritative = normalizeLayout(await options.fetchLayout());
|
||||
if (disposed) return;
|
||||
} else {
|
||||
|
||||
Reference in New Issue
Block a user