feat: replies to comments
A comment can answer another one (replyTo), one level deep: answering a reply joins the same thread, and it must be on the same ticket. Whoever wrote the comment gets a new REPLIED notification, and the activity says "respondió a un comentario". A comment deleted while it has replies stays, without its text (deleted: true), so the thread still reads; it goes with its last reply and does not count in commentCount. The ticket page shows threads with their replies indented and a "Responder" box; REST, GraphQL and the MCP (add_comment, get_issue) take and show replyTo. Existing comments are unchanged. Docs, Word and PDF updated. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -11,6 +11,7 @@ import {
|
||||
TrackerEvent,
|
||||
withoutMentionMarkup,
|
||||
} from '@task-stream/api/tracker/domain';
|
||||
import { FindCommentsRepository } from '../ports/find-comments.repository';
|
||||
import { FindIssuesRepository } from '../ports/find-issues.repository';
|
||||
import { FindProjectsRepository } from '../ports/find-projects.repository';
|
||||
import { UserDirectory } from '../ports/user-directory';
|
||||
@@ -43,6 +44,7 @@ export class NotificationsEventHandler implements IEventHandler<TrackerEvent> {
|
||||
private readonly findIssues: FindIssuesRepository,
|
||||
private readonly findProjects: FindProjectsRepository,
|
||||
private readonly users: UserDirectory,
|
||||
private readonly findComments: FindCommentsRepository,
|
||||
) {}
|
||||
|
||||
async handle(event: TrackerEvent): Promise<void> {
|
||||
@@ -154,6 +156,16 @@ export class NotificationsEventHandler implements IEventHandler<TrackerEvent> {
|
||||
summary: `${actor} te mencionó en ${issue.key}: ${said}`,
|
||||
});
|
||||
}
|
||||
const answered = event.comment.replyTo
|
||||
? await this.findComments.findById(event.comment.replyTo)
|
||||
: null;
|
||||
if (answered && !answered.deleted) {
|
||||
drafts.push({
|
||||
userId: answered.author.id,
|
||||
kind: NotificationKind.REPLIED,
|
||||
summary: `${actor} respondió a tu comentario en ${issue.key}: ${said}`,
|
||||
});
|
||||
}
|
||||
for (const userId of [assigneeId, reporterId]) {
|
||||
if (!userId) continue;
|
||||
drafts.push({
|
||||
|
||||
Reference in New Issue
Block a user