Files
task-stream/libs/api/tracker/application/src/lib/queries/get-activity.query-handler.ts
Josep Piguillem d66b1f3ece feat: a day of the activity map opens what happened, ticket by ticket
On the project dashboard, a day with activity can be picked on the map:
a side panel lists that day's moves grouped by ticket (each key opens
it), with the time of each, and the project's own (sprints, releases,
members) apart.

The activity feed takes an `after` date (GraphQL, REST), so with
`before` it reads a window such as a day; the MCP's
get_project_activity takes a `day`.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-16 20:42:30 +02:00

42 lines
1.6 KiB
TypeScript

import { NotFoundError } from '@task-stream/api/shared/domain';
import { FindIssuesRepository } from '../ports/find-issues.repository';
import { IQueryHandler, QueryHandler } from '@nestjs/cqrs';
import { ActivityReadModel } from '@task-stream/api/tracker/domain';
import { FindActivityRepository } from '../ports/find-activity.repository';
import { ReadAccess } from './read-access';
import { GetActivityQuery } from './get-activity.query';
@QueryHandler(GetActivityQuery)
export class GetActivityQueryHandler
implements IQueryHandler<GetActivityQuery, ActivityReadModel[]>
{
constructor(
private readonly findActivity: FindActivityRepository,
private readonly access: ReadAccess,
private readonly findIssues: FindIssuesRepository,
) {}
async execute(query: GetActivityQuery): Promise<ActivityReadModel[]> {
// A ticket's history goes with the ticket; the project's feed is for
// whoever sees the whole project (not a guest).
if (query.issueId) {
const issue = this.access.assertFound(
await this.findIssues.findById(query.issueId),
'Issue',
query.issueId,
);
if (issue.projectId !== query.projectId)
throw new NotFoundError('Issue', query.issueId);
await this.access.assertCanViewIssue(issue, query.viewerId);
} else
await this.access.assertSeesWholeProject(query.projectId, query.viewerId);
return this.findActivity.find({
projectId: query.projectId,
issueId: query.issueId,
limit: Math.min(query.limit, 200),
before: query.before,
after: query.after,
});
}
}