feat: sprints with burndown and carry-over

Plan sprints with dates and a goal, run one at a time per project, and
put tickets in them from the ticket page. The Sprints tab follows the one
under way with its progress and a burndown in tickets or points against
the ideal line. Closing a sprint sends what was left to the next one or
back to the backlog; the board can be filtered by sprint.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-08 14:59:01 +02:00
parent d2e31789a7
commit 50d3ffd1dd
104 changed files with 7209 additions and 33 deletions

View File

@@ -6,6 +6,8 @@ import {
Comment,
Epic,
SavedFilter,
Sprint,
SprintBurndown,
SavedFilterCriteria,
CommandResult,
Issue,
@@ -32,6 +34,8 @@ import {
MyIssuesFilter,
UpdateIssueInput,
UpdateProjectInput,
CreateSprintInput,
UpdateSprintInput,
} from '../models/inputs';
/*
@@ -173,6 +177,25 @@ export abstract class ReleasesGateway {
abstract burnup(releaseId: string): Observable<ReleaseBurnup>;
}
export abstract class SprintsGateway {
/** With their progress: under way, planned, then closed. */
abstract list(projectId: string): Observable<Sprint[]>;
abstract burndown(sprintId: string): Observable<SprintBurndown>;
abstract create(input: CreateSprintInput): Observable<CommandResult>;
abstract update(input: UpdateSprintInput): Observable<CommandResult>;
abstract start(sprintId: string): Observable<CommandResult>;
/** Unfinished tickets go to `carryOverTo` (null: the backlog). */
abstract close(
sprintId: string,
carryOverTo: string | null,
): Observable<CommandResult>;
abstract remove(sprintId: string): Observable<CommandResult>;
abstract setIssueSprint(
issueId: string,
sprintId: string | null,
): Observable<CommandResult>;
}
export abstract class ActivityGateway {
abstract list(projectId: string, issueId?: string): Observable<Activity[]>;
}
@@ -219,6 +242,8 @@ export abstract class TrackerRealtimeGateway {
abstract commentChanges(issueId: string): Observable<CommentChanged>;
abstract activity(projectId: string): Observable<Activity>;
abstract releaseChanges(projectId: string): Observable<Release>;
/** Something about a sprint of the project changed (or it was deleted). */
abstract sprintChanges(projectId: string): Observable<{ sprintId: string }>;
abstract projectChanges(projectId: string): Observable<ProjectChanged>;
abstract myProjectsChanges(): Observable<ProjectChanged>;
abstract notifications(): Observable<Notification>;