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>
85 lines
2.3 KiB
TypeScript
85 lines
2.3 KiB
TypeScript
import { inject, Injectable } from '@angular/core';
|
|
import {
|
|
CommandResult,
|
|
CreateSprintInput,
|
|
Sprint,
|
|
SprintBurndown,
|
|
SprintsGateway,
|
|
UpdateSprintInput,
|
|
} from '@task-stream/web/tracker/domain';
|
|
import { map, Observable } from 'rxjs';
|
|
import {
|
|
CloseSprintDocument,
|
|
CreateSprintDocument,
|
|
DeleteSprintDocument,
|
|
SetIssueSprintDocument,
|
|
SprintBurndownDocument,
|
|
SprintsDocument,
|
|
StartSprintDocument,
|
|
UpdateSprintDocument,
|
|
} from '../graphql/generated';
|
|
import { GraphqlOperations } from './graphql-operations';
|
|
import { toCommandResult } from './mappers';
|
|
|
|
@Injectable()
|
|
export class GraphqlSprintsGateway extends SprintsGateway {
|
|
private readonly gql = inject(GraphqlOperations);
|
|
|
|
list(projectId: string): Observable<Sprint[]> {
|
|
return this.gql
|
|
.query(SprintsDocument, { projectId })
|
|
.pipe(map((d) => d.sprints as Sprint[]));
|
|
}
|
|
|
|
burndown(sprintId: string): Observable<SprintBurndown> {
|
|
return this.gql
|
|
.query(SprintBurndownDocument, { id: sprintId })
|
|
.pipe(map((d) => d.sprint.burndown));
|
|
}
|
|
|
|
create(input: CreateSprintInput): Observable<CommandResult> {
|
|
return this.gql
|
|
.mutate(CreateSprintDocument, { input })
|
|
.pipe(map((d) => toCommandResult(d.createSprint)));
|
|
}
|
|
|
|
update(input: UpdateSprintInput): Observable<CommandResult> {
|
|
return this.gql
|
|
.mutate(UpdateSprintDocument, { input })
|
|
.pipe(map((d) => toCommandResult(d.updateSprint)));
|
|
}
|
|
|
|
start(sprintId: string): Observable<CommandResult> {
|
|
return this.gql
|
|
.mutate(StartSprintDocument, { sprintId })
|
|
.pipe(map((d) => toCommandResult(d.startSprint)));
|
|
}
|
|
|
|
close(
|
|
sprintId: string,
|
|
carryOverTo: string | null,
|
|
): Observable<CommandResult> {
|
|
return this.gql
|
|
.mutate(CloseSprintDocument, {
|
|
sprintId,
|
|
carryOverToSprintId: carryOverTo,
|
|
})
|
|
.pipe(map((d) => toCommandResult(d.closeSprint)));
|
|
}
|
|
|
|
remove(sprintId: string): Observable<CommandResult> {
|
|
return this.gql
|
|
.mutate(DeleteSprintDocument, { sprintId })
|
|
.pipe(map((d) => toCommandResult(d.deleteSprint)));
|
|
}
|
|
|
|
setIssueSprint(
|
|
issueId: string,
|
|
sprintId: string | null,
|
|
): Observable<CommandResult> {
|
|
return this.gql
|
|
.mutate(SetIssueSprintDocument, { issueId, sprintId })
|
|
.pipe(map((d) => toCommandResult(d.setIssueSprint)));
|
|
}
|
|
}
|