feat: epics, subtasks and checklists
Tickets can hang from another one of the same project, three levels deep at most (epic → ticket → subtask). The ticket page lists its subtasks with their progress, creates new ones and moves the ticket under an epic; a new Épicas tab shows every epic and how far it has got. Each ticket also gets a checklist for the small steps that don't deserve a ticket. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -5,6 +5,7 @@ import {
|
||||
ChangeStatusInput,
|
||||
CommandResult,
|
||||
CreateIssueInput,
|
||||
Epic,
|
||||
Issue,
|
||||
IssuePage,
|
||||
IssuesGateway,
|
||||
@@ -15,18 +16,24 @@ import {
|
||||
} from '@task-stream/web/tracker/domain';
|
||||
import { map, Observable } from 'rxjs';
|
||||
import {
|
||||
AddChecklistItemDocument,
|
||||
AssignIssueDocument,
|
||||
BoardDocument,
|
||||
ChangeIssueStatusDocument,
|
||||
CreateIssueDocument,
|
||||
EpicsDocument,
|
||||
IssueChildrenDocument,
|
||||
IssueDocument,
|
||||
LinkIssuesDocument,
|
||||
MyIssuesDocument,
|
||||
RemoveChecklistItemDocument,
|
||||
SearchIssuesDocument,
|
||||
SetIssueParentDocument,
|
||||
SetIssueReleaseDocument,
|
||||
UnlinkIssuesDocument,
|
||||
UnwatchIssueDocument,
|
||||
WatchIssueDocument,
|
||||
UpdateChecklistItemDocument,
|
||||
UpdateIssueDocument,
|
||||
} from '../graphql/generated';
|
||||
import { GraphqlOperations } from './graphql-operations';
|
||||
@@ -131,6 +138,61 @@ export class GraphqlIssuesGateway extends IssuesGateway {
|
||||
.pipe(map((d) => toCommandResult(d.unwatchIssue)));
|
||||
}
|
||||
|
||||
children(projectId: string, issueId: string): Observable<IssueSummary[]> {
|
||||
return this.gql
|
||||
.query(IssueChildrenDocument, {
|
||||
filter: { projectId, parentId: issueId },
|
||||
})
|
||||
.pipe(map((d) => d.issues.items.map(toIssueSummary)));
|
||||
}
|
||||
|
||||
setParent(
|
||||
issueId: string,
|
||||
parentId: string | null,
|
||||
): Observable<CommandResult> {
|
||||
return this.gql
|
||||
.mutate(SetIssueParentDocument, { issueId, parentId })
|
||||
.pipe(map((d) => toCommandResult(d.setIssueParent)));
|
||||
}
|
||||
|
||||
epics(projectId: string): Observable<Epic[]> {
|
||||
return this.gql.query(EpicsDocument, { projectId }).pipe(
|
||||
map((d) =>
|
||||
d.epics.map((epic) => ({
|
||||
issue: toIssueSummary(epic.issue),
|
||||
progress: { ...epic.progress },
|
||||
})),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
addChecklistItem(issueId: string, text: string): Observable<CommandResult> {
|
||||
return this.gql
|
||||
.mutate(AddChecklistItemDocument, { input: { issueId, text } })
|
||||
.pipe(map((d) => toCommandResult(d.addChecklistItem)));
|
||||
}
|
||||
|
||||
updateChecklistItem(
|
||||
issueId: string,
|
||||
itemId: string,
|
||||
changes: { text?: string; done?: boolean },
|
||||
): Observable<CommandResult> {
|
||||
return this.gql
|
||||
.mutate(UpdateChecklistItemDocument, {
|
||||
input: { issueId, itemId, ...changes },
|
||||
})
|
||||
.pipe(map((d) => toCommandResult(d.updateChecklistItem)));
|
||||
}
|
||||
|
||||
removeChecklistItem(
|
||||
issueId: string,
|
||||
itemId: string,
|
||||
): Observable<CommandResult> {
|
||||
return this.gql
|
||||
.mutate(RemoveChecklistItemDocument, { issueId, itemId })
|
||||
.pipe(map((d) => toCommandResult(d.removeChecklistItem)));
|
||||
}
|
||||
|
||||
setRelease(
|
||||
issueId: string,
|
||||
releaseId: string | null,
|
||||
|
||||
Reference in New Issue
Block a user