mirror of
https://github.com/PerpetualSoftware/pad.git
synced 2026-10-03 12:10:31 +00:00
fix(web): make itemMatchesRef workspace-aware in ItemDetail (IDEA-2135) (#1008)
The no-{#key} switch-boundary predicate compared only ref/slug identity,
never workspace. On a reused embedded ItemDetail instance, navigating
ws1?item=TASK-1 -> ws2?item=TASK-1 (both workspaces owning TASK-1) kept
the predicate true across the switch, leaving collabKey pinned to ws1's
item.id and rawMode carried over until ws2's loadData resolved.
Stamp the wsSlug each item is loaded under (loadedItemWsSlug, lock-stepped
with item adoption inside the myItemGen===itemGen gate) and fold
loadedItemWsSlug === wsSlug into itemMatchesRef. scrollReady, collabKey,
resolvedIdentity, and the rawMode-reset gate all derive from it, so they
tighten together and stay consistent. Single-workspace usage is unchanged
(the arm is always true there).
TASK-2283.
Claude-Session: https://claude.ai/code/session_01EZ6yr6pAUFb1uffan912ra
This commit is contained in:
@@ -178,6 +178,16 @@
|
||||
(onNavigateAway ?? ((u: string) => goto(u, { replaceState: true })))(url);
|
||||
|
||||
let item = $state<Item | null>(null);
|
||||
// The wsSlug the currently-held `item` was actually loaded under. Stamped
|
||||
// lock-stepped with every `item` adoption in loadData, so it can never
|
||||
// disagree with `item`'s workspace. Folded into `itemMatchesRef` below so the
|
||||
// switch boundary is workspace-aware: on a REUSED (no-{#key}) ItemDetail
|
||||
// instance, a cross-workspace nav that preserves `?item=<ref>` for a ref both
|
||||
// workspaces own (ws1?item=TASK-1 → ws2?item=TASK-1) would otherwise keep the
|
||||
// predicate true across the switch — leaving `collabKey` pinned to ws1's
|
||||
// item.id and rawMode carried over until ws2's load resolves (IDEA-2135).
|
||||
// In single-workspace usage this always equals `wsSlug` → byte-identical.
|
||||
let loadedItemWsSlug = $state('');
|
||||
let collection = $state<Collection | null>(null);
|
||||
let loading = $state(true);
|
||||
let error = $state('');
|
||||
@@ -376,8 +386,15 @@
|
||||
// stale provider for the previous item tears down the instant `ref`
|
||||
// changes — before the new fetch resolves — instead of lingering with a
|
||||
// destroyed editor (PLAN-2105 / TASK-2112 switch-safety; Codex).
|
||||
// The workspace arm (`loadedItemWsSlug === wsSlug`) makes the switch boundary
|
||||
// workspace-aware (IDEA-2135): a reused instance navigating ws1→ws2 with the
|
||||
// same `?item=<ref>`, where both workspaces own that ref, flips the predicate
|
||||
// false the instant `wsSlug` changes — before ws2's load resolves — so
|
||||
// `collabKey`/`scrollReady`/`resolvedIdentity` and the rawMode-reset gate all
|
||||
// tighten together instead of lingering on the previous workspace's item.
|
||||
let itemMatchesRef = $derived(
|
||||
item !== null &&
|
||||
loadedItemWsSlug === wsSlug &&
|
||||
(item.id === itemSlug ||
|
||||
item.slug === itemSlug ||
|
||||
`${item.collection_prefix}-${item.item_number}` === itemSlug),
|
||||
@@ -1404,7 +1421,15 @@
|
||||
// Gate the ITEM snapshot on itemGen too: a newer item write (e.g. the
|
||||
// migration refetch) that bumped itemGen but not loadGeneration must
|
||||
// not be reverted by this in-flight load (round 9).
|
||||
if (myItemGen === itemGen) item = withInflightTags(itemData);
|
||||
// Stamp the workspace this item was loaded under in lockstep with the
|
||||
// item adoption (IDEA-2135) — same gate, so `loadedItemWsSlug` and
|
||||
// `item` can never disagree about which workspace `item` belongs to.
|
||||
// `reqWsSlug` (captured at load start) is authoritative here: `myGen`
|
||||
// was already checked above, so no newer load has moved `wsSlug` on.
|
||||
if (myItemGen === itemGen) {
|
||||
item = withInflightTags(itemData);
|
||||
loadedItemWsSlug = reqWsSlug;
|
||||
}
|
||||
// Cross-collection `?item=` safety (PLAN-2105 / TASK-2112). The
|
||||
// Promise.all above optimistically fetched the collection by the
|
||||
// route's `collSlug` — correct for the common (row-click) case,
|
||||
|
||||
Reference in New Issue
Block a user