feat(PBI-79): pendingSprintDraft session-only + concept-entry + leave-guard
Scope-aanpassing uit plan-revisie: drafts persisten niet meer server-side.
Wijzigingen:
- stores/user-settings/store.ts:
- hydrate() strip nu workflow.pendingSprintDraft uit serverstate
(legacy DB-entries blijven harmless aanwezig maar worden niet
gehydreerd → effectief unreachable voor de UI).
- setPendingSprintDraft / clearPendingSprintDraft worden lokale-only;
geen import van sprint-draft-actions, geen server-roundtrip.
- upsertPbiIntent / upsertStoryOverride blijven via setPendingSprintDraft
routeren → ook session-only.
- components/shared/sprint-switcher.tsx: leest draft-goal uit user-settings
store en toont '⚙ Concept — [goal]' als niet-selecteerbare entry
bovenaan de dropdown zolang er een draft loopt.
- components/backlog/sprint-draft-leave-guard.tsx (nieuw): registreert
een beforeunload-listener zolang er een draft is. Browser-refresh,
tab-close en back-navigatie tonen daarmee de standaard confirm. In-app
route-changes blijven via de banner-Annuleren-knop lopen.
- app/(app)/products/[id]/page.tsx: SprintDraftLeaveGuard gemount naast
de banner.
- Tests: user-settings store-tests aangepast (geen server-call assert
meer, hydrate strip-assert toegevoegd; upsert-tests seed nu via
setPendingSprintDraft i.p.v. legacy hydrate).
setPendingSprintDraftAction + clearPendingSprintDraftAction blijven bestaan
voor eventuele toekomstige opruim-flows, maar worden niet meer aangeroepen
vanuit de UI.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
e4252cad3e
commit
2a4ee6aded
5 changed files with 114 additions and 97 deletions
|
|
@ -18,6 +18,7 @@ import {
|
|||
switchActiveSprintAction,
|
||||
} from '@/actions/active-sprint'
|
||||
import { useProductWorkspaceStore } from '@/stores/product-workspace/store'
|
||||
import { useUserSettingsStore } from '@/stores/user-settings/store'
|
||||
import type { SprintStatusApi } from '@/lib/task-status'
|
||||
import { debugProps } from '@/lib/debug'
|
||||
|
||||
|
|
@ -49,6 +50,13 @@ export function SprintSwitcher({
|
|||
const [showClosed, setShowClosed] = useState(false)
|
||||
const buildingSet = new Set(buildingSprintIds)
|
||||
|
||||
// PBI-79: zolang er een sprint-draft loopt tonen we 'Concept — [goal]'
|
||||
// bovenaan de dropdown. De draft staat alleen in deze session-store; bij
|
||||
// page-refresh/leave is hij weg.
|
||||
const draftGoal = useUserSettingsStore(
|
||||
(s) => s.entities.settings.workflow?.pendingSprintDraft?.[productId]?.goal ?? null,
|
||||
)
|
||||
|
||||
const visibleSprints = sprints.filter(s => {
|
||||
if (showClosed) return true
|
||||
if (s.id === activeSprint?.id) return true
|
||||
|
|
@ -161,6 +169,19 @@ export function SprintSwitcher({
|
|||
Toon afgeronde sprints
|
||||
</button>
|
||||
<DropdownMenuSeparator />
|
||||
{draftGoal && (
|
||||
<>
|
||||
<DropdownMenuItem
|
||||
disabled
|
||||
className="italic text-tertiary opacity-90 cursor-default"
|
||||
data-debug-id="sprint-switcher__concept"
|
||||
>
|
||||
<span className="shrink-0">⚙ Concept —</span>
|
||||
<span className="truncate">{draftGoal}</span>
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuSeparator />
|
||||
</>
|
||||
)}
|
||||
<DropdownMenuItem
|
||||
onClick={handleClearActiveSprint}
|
||||
disabled={!activeSprint || isPending}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue