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:
@@ -181,6 +181,41 @@ export class ChangeIssueStatusInput {
|
||||
reason?: string | null;
|
||||
}
|
||||
|
||||
const DAY = /^\d{4}-\d{2}-\d{2}$/;
|
||||
|
||||
@InputType()
|
||||
export class CreateSprintInput {
|
||||
@Field(() => ID) @IsUUID() projectId!: string;
|
||||
@Field() @IsString() @MinLength(1) @MaxLength(80) name!: string;
|
||||
@Field(() => String, { nullable: true })
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
@MaxLength(500)
|
||||
goal?: string | null;
|
||||
@Field({ description: 'YYYY-MM-DD' }) @Matches(DAY) startDate!: string;
|
||||
@Field({ description: 'YYYY-MM-DD, included' })
|
||||
@Matches(DAY)
|
||||
endDate!: string;
|
||||
}
|
||||
|
||||
@InputType()
|
||||
export class UpdateSprintInput {
|
||||
@Field(() => ID) @IsUUID() sprintId!: string;
|
||||
@Field({ nullable: true })
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
@MinLength(1)
|
||||
@MaxLength(80)
|
||||
name?: string;
|
||||
@Field(() => String, { nullable: true })
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
@MaxLength(500)
|
||||
goal?: string | null;
|
||||
@Field({ nullable: true }) @IsOptional() @Matches(DAY) startDate?: string;
|
||||
@Field({ nullable: true }) @IsOptional() @Matches(DAY) endDate?: string;
|
||||
}
|
||||
|
||||
@InputType()
|
||||
export class SavedFilterCriteriaInput {
|
||||
@Field(() => [String], { nullable: true })
|
||||
@@ -320,6 +355,14 @@ export class IssueFilterInput {
|
||||
@IsOptional()
|
||||
@IsUUID()
|
||||
parentId?: string;
|
||||
@Field(() => ID, { nullable: true })
|
||||
@IsOptional()
|
||||
@IsUUID()
|
||||
sprintId?: string;
|
||||
@Field({ nullable: true, description: 'Only tickets in no sprint' })
|
||||
@IsOptional()
|
||||
@IsBoolean()
|
||||
noSprint?: boolean;
|
||||
@Field(() => IssueSort, { nullable: true, defaultValue: IssueSort.RECENT })
|
||||
@IsOptional()
|
||||
@IsEnum(IssueSort)
|
||||
|
||||
Reference in New Issue
Block a user