Skip to content

Commit 6aad77e

Browse files
committed
fix(skills): track a sentinel consumed while the guard is released
release() intentionally leaves the seeded history entry in place, but it also drops the popstate listener — so Back during the released window (an optimistic delete's round-trip) consumed that entry with nothing to record it. hasSentinelRef stayed true, and a failed delete's rearm() then skipped re-seeding, leaving the surface with no Back confirm despite unsaved edits. The released branch now keeps a bookkeeping-only popstate listener that clears the ref, so rearm() seeds a fresh entry when the old one is gone.
1 parent ee80756 commit 6aad77e

1 file changed

Lines changed: 12 additions & 2 deletions

File tree

apps/sim/app/workspace/[workspaceId]/components/credential-detail/hooks/use-unsaved-changes-guard.ts

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,8 +30,18 @@ export function useUnsavedChangesGuard({ isDirty, backHref }: UseUnsavedChangesG
3030
const hasSentinelRef = useRef(false)
3131

3232
useEffect(() => {
33-
// The caller is navigating away — popping the seeded entry would cancel it.
34-
if (isReleased) return
33+
// The caller is navigating away — popping the seeded entry would cancel it. But
34+
// Back during that window consumes the entry with no listener left to re-push
35+
// it, so track that: a later rearm() must seed a fresh one rather than trust a
36+
// stale ref and leave the surface unguarded.
37+
if (isReleased) {
38+
if (!hasSentinelRef.current) return
39+
const handleSentinelConsumed = () => {
40+
hasSentinelRef.current = false
41+
}
42+
window.addEventListener('popstate', handleSentinelConsumed)
43+
return () => window.removeEventListener('popstate', handleSentinelConsumed)
44+
}
3545
if (!isDirty) {
3646
// Clean again while still mounted (saved/reverted): pop the seeded entry so
3747
// it can't pile up across edit/save cycles. This runs in the effect body,

0 commit comments

Comments
 (0)