Tickets get a start date next to their due date, both editable on the ticket page. The Hoja de ruta tab lays the epics out over the months as bars filled with their progress, with sprints and releases as landmarks and a line for today. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
67 lines
2.4 KiB
TypeScript
67 lines
2.4 KiB
TypeScript
import { EventsHandler, IEventHandler } from '@nestjs/cqrs';
|
|
import {
|
|
DEFAULT_PROJECT_SETTINGS,
|
|
IssueCreatedEvent,
|
|
implicitRank,
|
|
ProjectWorkflow,
|
|
} from '@task-stream/api/tracker/domain';
|
|
import { FindProjectsRepository } from '../ports/find-projects.repository';
|
|
import { FindReleasesRepository } from '../ports/find-releases.repository';
|
|
import { UpsertMaterializedIssueRepository } from '../ports/upsert-materialized-issue.repository';
|
|
import { UserDirectory } from '../ports/user-directory';
|
|
import { ReadModelNotifier, versionOf } from './read-model-notifier';
|
|
|
|
@EventsHandler(IssueCreatedEvent)
|
|
export class IssueCreatedEventHandler
|
|
implements IEventHandler<IssueCreatedEvent>
|
|
{
|
|
constructor(
|
|
private readonly upsertMaterializedIssueRepository: UpsertMaterializedIssueRepository,
|
|
private readonly findReleases: FindReleasesRepository,
|
|
private readonly findProjects: FindProjectsRepository,
|
|
private readonly users: UserDirectory,
|
|
private readonly notifier: ReadModelNotifier,
|
|
) {}
|
|
|
|
async handle(event: IssueCreatedEvent) {
|
|
const { issue } = event;
|
|
const users = await this.users.refs([issue.reporterId, issue.assigneeId]);
|
|
const project = await this.findProjects.findById(issue.projectId);
|
|
const workflow = new ProjectWorkflow(
|
|
project?.settings ?? DEFAULT_PROJECT_SETTINGS,
|
|
);
|
|
const release = issue.releaseId
|
|
? await this.findReleases.findById(issue.releaseId)
|
|
: null;
|
|
await this.upsertMaterializedIssueRepository.upsert({
|
|
id: issue.id,
|
|
projectId: issue.projectId,
|
|
projectKey: issue.key.slice(0, issue.key.lastIndexOf('-')),
|
|
number: issue.number,
|
|
key: issue.key,
|
|
type: issue.type,
|
|
area: issue.area,
|
|
title: issue.title,
|
|
description: issue.description,
|
|
status: issue.status,
|
|
statusCategory: workflow.categoryOf(issue.status),
|
|
priority: issue.priority,
|
|
reporter: users.of(issue.reporterId),
|
|
assignee: users.ofNullable(issue.assigneeId),
|
|
release: release ? { id: release.id, name: release.name } : null,
|
|
parent: null,
|
|
sprint: null,
|
|
rank: implicitRank(issue.number),
|
|
labels: issue.labels,
|
|
figmaUrl: issue.figmaUrl,
|
|
storyPoints: issue.storyPoints,
|
|
startDate: issue.startDate ?? null,
|
|
dueDate: issue.dueDate,
|
|
createdAt: issue.createdAt,
|
|
updatedAt: issue.updatedAt,
|
|
version: versionOf(event),
|
|
});
|
|
await this.notifier.issue(issue.id, event);
|
|
}
|
|
}
|