Files
task-stream/libs/web/tracker/infrastructure/src/lib/adapters/graphql-sprints.gateway.ts
Josep Piguillem 50d3ffd1dd 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>
2026-10-08 14:59:01 +02:00

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)));
}
}