import { inject, Injectable } from '@angular/core'; import { Activity, ActivityGateway, CommandResult, Comment, CommentsGateway, CreateReleaseInput, Release, ReleaseBurnup, ReleasesGateway, UserDirectoryEntry, UsersGateway, } from '@task-stream/web/tracker/domain'; import { map, Observable } from 'rxjs'; import { ActivityDocument, ActivityOfDayDocument, AddCommentDocument, ArchiveReleaseDocument, CreateReleaseDocument, DeleteCommentDocument, EditCommentDocument, IssueCommentsDocument, ReactToCommentDocument, MarkDecisionDocument, ResolveThreadDocument, TurnCommentIntoIssueDocument, VotePollDocument, ClosePollDocument, PublishReleaseDocument, ReleaseBurnupDocument, ReleaseNotesDraftDocument, WriteReleaseNotesDocument, ReleasesDocument, UpcomingReleasesDocument, SearchUsersDocument, } from '../graphql/generated'; import { GraphqlOperations } from './graphql-operations'; import { toActivity, toCommandResult, toComment, toRelease } from './mappers'; @Injectable() export class GraphqlCommentsGateway extends CommentsGateway { private readonly gql = inject(GraphqlOperations); list(issueId: string): Observable { return this.gql .query(IssueCommentsDocument, { idOrKey: issueId }) .pipe(map((d) => d.issue.comments.items.map(toComment))); } add( issueId: string, body: string, replyTo: string | null = null, poll: string[] | null = null, ): Observable { return this.gql .mutate(AddCommentDocument, { issueId, body, replyTo, poll: poll?.length ? poll : null, }) .pipe(map((d) => toCommandResult(d.addComment))); } votePoll( commentId: string, option: number | null, ): Observable { return this.gql .mutate(VotePollDocument, { commentId, option }) .pipe(map((d) => toCommandResult(d.votePoll))); } closePoll(commentId: string, decide: boolean): Observable { return this.gql .mutate(ClosePollDocument, { commentId, decide }) .pipe(map((d) => toCommandResult(d.closePoll))); } react( commentId: string, emoji: string, on: boolean, ): Observable { return this.gql .mutate(ReactToCommentDocument, { commentId, emoji, on }) .pipe(map((d) => toCommandResult(d.reactToComment))); } edit(commentId: string, body: string): Observable { return this.gql .mutate(EditCommentDocument, { commentId, body }) .pipe(map((d) => toCommandResult(d.editComment))); } remove(commentId: string): Observable { return this.gql .mutate(DeleteCommentDocument, { commentId }) .pipe(map((d) => toCommandResult(d.deleteComment))); } resolveThread( commentId: string, resolved: boolean, conclusion: string | null, ): Observable { return this.gql .mutate(ResolveThreadDocument, { commentId, resolved, conclusion }) .pipe(map((d) => toCommandResult(d.resolveThread))); } turnIntoIssue( commentId: string, title: string, type: string, asSubtask: boolean, ): Observable { return this.gql .mutate(TurnCommentIntoIssueDocument, { commentId, title, type, asSubtask, }) .pipe(map((d) => toCommandResult(d.turnCommentIntoIssue))); } markDecision(commentId: string, on: boolean): Observable { return this.gql .mutate(MarkDecisionDocument, { commentId, on }) .pipe(map((d) => toCommandResult(d.markDecision))); } } @Injectable() export class GraphqlReleasesGateway extends ReleasesGateway { private readonly gql = inject(GraphqlOperations); list(projectId: string): Observable { return this.gql .query(ReleasesDocument, { idOrKey: projectId }) .pipe(map((d) => d.project.releases.map(toRelease))); } upcoming(limit: number): Observable { return this.gql .query(UpcomingReleasesDocument, { limit }) .pipe(map((d) => d.upcomingReleases.map(toRelease))); } create(input: CreateReleaseInput): Observable { return this.gql .mutate(CreateReleaseDocument, { input }) .pipe(map((d) => toCommandResult(d.createRelease))); } publish(releaseId: string, force: boolean): Observable { return this.gql .mutate(PublishReleaseDocument, { releaseId, force }) .pipe(map((d) => toCommandResult(d.publishRelease))); } archive( releaseId: string, moveTo: string | null = null, ): Observable { return this.gql .mutate(ArchiveReleaseDocument, { releaseId, moveTo }) .pipe(map((d) => toCommandResult(d.archiveRelease))); } burnup(releaseId: string): Observable { return this.gql .query(ReleaseBurnupDocument, { id: releaseId }) .pipe(map((d) => d.release.burnup)); } notesDraft(releaseId: string): Observable { return this.gql .query(ReleaseNotesDraftDocument, { id: releaseId }) .pipe(map((d) => d.release.notesDraft)); } writeNotes( releaseId: string, notes: string | null, ): Observable { return this.gql .mutate(WriteReleaseNotesDocument, { releaseId, notes }) .pipe(map((d) => toCommandResult(d.writeReleaseNotes))); } } @Injectable() export class GraphqlActivityGateway extends ActivityGateway { private readonly gql = inject(GraphqlOperations); list(projectId: string, issueId?: string): Observable { return this.gql .query(ActivityDocument, { projectId, issueId: issueId ?? null }) .pipe(map((d) => d.activity.map(toActivity))); } onDay(projectId: string, day: string): Observable { const after = `${day}T00:00:00.000Z`; const before = new Date(Date.parse(after) + 86_400_000).toISOString(); return this.gql .query(ActivityOfDayDocument, { projectId, after, before }) .pipe(map((d) => d.activity.map(toActivity))); } } @Injectable() export class GraphqlUsersGateway extends UsersGateway { private readonly gql = inject(GraphqlOperations); search(term: string): Observable { return this.gql .query(SearchUsersDocument, { search: term }) .pipe(map((d) => d.users)); } }