feat: draft sprint UX — sidebar section, status badges, start-sprint warning - #460
Conversation
…s badges - Implemented collapsible section for planned sprints in the app sidebar. - Added SprintStatusBadge component to display sprint status. - Enhanced interaction layout to handle starting sprints with warnings for active sprints. - Updated various components to support new sprint status features and localization.
There was a problem hiding this comment.
ℹ️ Clean, well-structured UI feature — one minor suggestion inline, nothing blocking.
Reviewed changes — Single commit (1aaf510) touching 28 files in apps/web, all frontend sprint-interactions UI:
- Sidebar draft-sprints section (
app-sidebar.tsx) — New collapsible "Draft Sprints" group with per-project localStorage collapse state, defaulting to expanded and mirroring the existingcompletedSprintsCollapsedpattern. SprintStatusBadge(new component) — Color-coded, localized status badge reused across the list-group header, sprint detail header, and move-sprint modal.- Start-sprint warning — The Start Sprint modal now shows a non-blocking amber warning naming an already-active sprint, threaded through
list-view.tsx→list-group.tsx→start-sprint-modal.tsxviaotherActiveSprint. handleStartSprintextraction (interaction-layout.tsx) — Behavior-preserving refactor of the inline start handler; still gated at the call site bycontext === "backlog" && canCreate.- Planned-sprint hint (
properties-panel.tsx/option-list-button.tsx/types.ts) — Planned sprints show a muted "(not started)" hint via the new optionalSelectOption.hint; renders only in the dropdown list. - Sprint detail header (
$sprintId.tsx) — Status badge now shows for all viewers; edit/complete buttons remain gated bycanManageSprints; move-sprint modal swaps raw capitalized text for the badge. - i18n —
plannedSprints,sprintNotStarted,alreadyActiveWarningadded andstatusPlannedrenamed "Planned"→"Draft" consistently across all 9 locales.
I traced the otherActiveSprint wiring end-to-end: ListGroup has no other callers, the modal is only reachable for a planned sprint's start button, and the gate/passthrough logic preserves the prior behavior. No correctness or behavior regressions found.
DeepSeek Flash (free via Pullfrog for OSS) | 𝕏
- Introduced SprintFormModal for handling sprint creation and editing. - Updated StartSprintModal to utilize SprintFormModal for starting sprints. - Refactored InteractionLayout, ListGroup, and ListView components to use SprintFormPayload type. - Enhanced internationalization by adding "startSprint" translations in multiple languages. - Improved SprintPage component to manage sprint state and modal visibility more effectively.
There was a problem hiding this comment.
✅ No new issues found.
Reviewed changes — Commit 2022ba09 (delta vs the prior pullfrog review at 1aaf510), which refactors the sprint management modals:
- Extracted
SprintFormModal(new component) — a sharedmode="start"|"edit"dialog that supersedes both the standalone Start Sprint dialog and the sprint detail page's inline edit modal. - New "Start sprint" action on the sprint detail header for
plannedsprints — wired toStartSprintModal, reusing theotherActiveSprintwarning (now computed page-level fromallSprints) and the existingupdateSprintmutation carryingstatus: "active". - Edit dialog now uses
SprintFormModal mode="edit"— the delete action and stacked delete-confirm overlay are retained;suppressEscape={deleteConfirmOpen}plus the page-level Escape handler correctly close only the topmost dialog. - Shared
SprintFormPayloadtype — replaces three duplicated inlineonSubmitpayload shapes acrossinteraction-layout,list-view,list-group, andstart-sprint-modal. - Localization —
editSprintModal/editSprint/startSprintkeys added; verified theeditSprintModalandstartSprintModalkey sets are byte-identical across all 9 locales.
I re-verified the load-bearing details rather than trusting the diff: UpdateSprintPayload.status is typed SprintStatus so the injected "active" compiles; the delete-confirm overlay and its Esc/backdrop handling remain fully intact; date-range validation, the edit-mode empty-name disable, and the start-mode name fallback are all preserved. StartSprintModal delegating to SprintFormModal keeps behavior identical to the prior inline implementation. Prior review feedback (the .find() warning edge case) was already resolved. No regressions or new issues found.
DeepSeek Flash (free via Pullfrog for OSS) | 𝕏
There was a problem hiding this comment.
✅ No new issues found.
Reviewed changes — Commit 711c1b25 (delta vs the prior pullfrog review at 2022ba09), which adds error handling for the start-sprint flow and completes i18n:
- Inline start-sprint error handling (
list-group.tsx) — NewstartSprintErrorstate; the modal'sonSubmitwrapsonStartSprintin try/catch, setslayout.startSprintModal.erroron failure, and re-throws. The error is cleared each time the Start button is reopened. - Same handling on the sprint detail page (
$sprintId.tsx) — The header "Start sprint" button now routes throughupdateSprintMutation.mutateAsyncwith an equivalent try/catch +startSprintErrorre-throw. errorMessageprop threading (start-sprint-modal.tsx) — New optionalerrorMessageforwarded toSprintFormModal, whosehandleSubmitalready swallows caller errors (comment: "caller surfaces failures viaerrorMessage") and keeps the dialog open — so the failure text renders below the fields and the modal doesn't close on a failed start.- i18n —
startSprintModal.error(plus the already-reviewedalreadyActiveWarning) added in all 9 locales.
I verified the load-bearing details rather than trusting the diff: the t("layout.startSprintModal.error") key referenced by both callers exists, and I confirmed the startSprintModal and sprintDetail.editSprintModal key sets are byte-identical across all 9 locales (en, es, fr, ja, ko, pt-BR, ru, vi, zh-CN). On a failed start, updateSprintMutation's onError also fires setEditError, but that slot belongs to the (closed) edit modal and is cleared on the next edit-open, so it's harmless. The dialog staying open on failure with the error visible is the intended trade-off. No regressions found.
DeepSeek Flash (free via Pullfrog for OSS) | 𝕏

Summary
Improves sprint lifecycle UX so a newly created sprint is easy to find and understand instead of silently disappearing until it's started (see #456, where a "missing" sprint was reported as a bug).
SprintStatusBadgecomponent gives Draft/Active/Completed a consistent look across the backlog column headers, the sprint detail page header, and the Complete Sprint modal's destination-sprint list.Notes
planned) — only the label shown to users was renamed to "Draft" for clarity. No API or database migration involved.Closes #456.