Greeting and summary of the day, the coming week, the latest across my projects, who is online now, the week in numbers (mine and the team's, with a streak), sprints under way, «Retomar», project cards with their activity, what to pick up when nothing is mine and first steps for newcomers. REST (GET /api/me/home), GraphQL (myHome) and MCP (get_my_week). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
167 lines
4.7 KiB
TypeScript
167 lines
4.7 KiB
TypeScript
import { inject, Injectable } from '@angular/core';
|
|
import {
|
|
CommandResult,
|
|
CreateProjectInput,
|
|
MemberInput,
|
|
Project,
|
|
ProjectAnalytics,
|
|
ProjectInsights,
|
|
PortfolioProject,
|
|
Home,
|
|
ProjectSettings,
|
|
ProjectsGateway,
|
|
ProjectStats,
|
|
UpdateProjectInput,
|
|
} from '@task-stream/web/tracker/domain';
|
|
import { map, Observable } from 'rxjs';
|
|
import {
|
|
AddProjectMemberDocument,
|
|
ChangeProjectMemberRoleDocument,
|
|
CreateProjectDocument,
|
|
DeleteProjectDocument,
|
|
ArchiveProjectDocument,
|
|
UnarchiveProjectDocument,
|
|
MyProjectsDocument,
|
|
ProjectAnalyticsDocument,
|
|
ProjectInsightsDocument,
|
|
PortfolioDocument,
|
|
MyHomeDocument,
|
|
ProjectDocument,
|
|
ProjectStatsDocument,
|
|
PublicProjectsDocument,
|
|
RemoveProjectMemberDocument,
|
|
UpdateProjectDocument,
|
|
UpdateProjectSettingsDocument,
|
|
} from '../graphql/generated';
|
|
import { GraphqlOperations } from './graphql-operations';
|
|
import {
|
|
toCommandResult,
|
|
toIssueSummary,
|
|
toProject,
|
|
toSettingsInput,
|
|
toStats,
|
|
} from './mappers';
|
|
|
|
@Injectable()
|
|
export class GraphqlProjectsGateway extends ProjectsGateway {
|
|
private readonly gql = inject(GraphqlOperations);
|
|
|
|
myProjects(): Observable<Project[]> {
|
|
return this.gql
|
|
.query(MyProjectsDocument)
|
|
.pipe(map((d) => d.myProjects.map(toProject)));
|
|
}
|
|
|
|
publicProjects(): Observable<Project[]> {
|
|
return this.gql
|
|
.query(PublicProjectsDocument)
|
|
.pipe(map((d) => d.publicProjects.map(toProject)));
|
|
}
|
|
|
|
project(idOrKey: string): Observable<Project> {
|
|
return this.gql
|
|
.query(ProjectDocument, { idOrKey })
|
|
.pipe(map((d) => toProject(d.project)));
|
|
}
|
|
|
|
stats(projectId: string): Observable<ProjectStats> {
|
|
return this.gql
|
|
.query(ProjectStatsDocument, { idOrKey: projectId })
|
|
.pipe(map((d) => toStats(d.project.stats)));
|
|
}
|
|
|
|
myHome(): Observable<Home> {
|
|
return this.gql
|
|
.query(MyHomeDocument, {})
|
|
.pipe(map((d) => d.myHome as Home));
|
|
}
|
|
|
|
portfolio(): Observable<PortfolioProject[]> {
|
|
return this.gql.query(PortfolioDocument, {}).pipe(
|
|
map((d) =>
|
|
d.portfolio.map((p) => ({
|
|
...(p as unknown as PortfolioProject),
|
|
epics: p.epics.map((e) => ({
|
|
issue: toIssueSummary(e.issue),
|
|
progress: { ...e.progress },
|
|
links: [],
|
|
})),
|
|
})),
|
|
),
|
|
);
|
|
}
|
|
|
|
insights(
|
|
projectId: string,
|
|
since: string | null,
|
|
): Observable<ProjectInsights> {
|
|
return this.gql
|
|
.query(ProjectInsightsDocument, { idOrKey: projectId, since })
|
|
.pipe(map((d) => d.project.insights as ProjectInsights));
|
|
}
|
|
|
|
analytics(projectId: string, days: number): Observable<ProjectAnalytics> {
|
|
return this.gql
|
|
.query(ProjectAnalyticsDocument, { idOrKey: projectId, days })
|
|
.pipe(map((d) => d.project.analytics));
|
|
}
|
|
|
|
updateSettings(
|
|
projectId: string,
|
|
settings: ProjectSettings,
|
|
): Observable<CommandResult> {
|
|
return this.gql
|
|
.mutate(UpdateProjectSettingsDocument, {
|
|
projectId,
|
|
settings: toSettingsInput(settings),
|
|
})
|
|
.pipe(map((d) => toCommandResult(d.updateProjectSettings)));
|
|
}
|
|
|
|
create(input: CreateProjectInput): Observable<CommandResult> {
|
|
return this.gql
|
|
.mutate(CreateProjectDocument, { input })
|
|
.pipe(map((d) => toCommandResult(d.createProject)));
|
|
}
|
|
|
|
update(input: UpdateProjectInput): Observable<CommandResult> {
|
|
return this.gql
|
|
.mutate(UpdateProjectDocument, { input })
|
|
.pipe(map((d) => toCommandResult(d.updateProject)));
|
|
}
|
|
|
|
setArchived(projectId: string, archived: boolean): Observable<CommandResult> {
|
|
return archived
|
|
? this.gql
|
|
.mutate(ArchiveProjectDocument, { projectId })
|
|
.pipe(map((d) => toCommandResult(d.archiveProject)))
|
|
: this.gql
|
|
.mutate(UnarchiveProjectDocument, { projectId })
|
|
.pipe(map((d) => toCommandResult(d.unarchiveProject)));
|
|
}
|
|
|
|
delete(projectId: string, confirmKey: string): Observable<CommandResult> {
|
|
return this.gql
|
|
.mutate(DeleteProjectDocument, { projectId, confirmKey })
|
|
.pipe(map((d) => toCommandResult(d.deleteProject)));
|
|
}
|
|
|
|
addMember(input: MemberInput): Observable<CommandResult> {
|
|
return this.gql
|
|
.mutate(AddProjectMemberDocument, { input: input as never })
|
|
.pipe(map((d) => toCommandResult(d.addProjectMember)));
|
|
}
|
|
|
|
changeMemberRole(input: MemberInput): Observable<CommandResult> {
|
|
return this.gql
|
|
.mutate(ChangeProjectMemberRoleDocument, { input: input as never })
|
|
.pipe(map((d) => toCommandResult(d.changeProjectMemberRole)));
|
|
}
|
|
|
|
removeMember(projectId: string, userId: string): Observable<CommandResult> {
|
|
return this.gql
|
|
.mutate(RemoveProjectMemberDocument, { projectId, userId })
|
|
.pipe(map((d) => toCommandResult(d.removeProjectMember)));
|
|
}
|
|
}
|