first commit
This commit is contained in:
@@ -0,0 +1,155 @@
|
||||
import {
|
||||
CommentAddedEvent,
|
||||
CommentDeletedEvent,
|
||||
CommentEditedEvent,
|
||||
IssueAssignedEvent,
|
||||
IssueCreatedEvent,
|
||||
IssueLinkedEvent,
|
||||
IssueLinkType,
|
||||
IssueReleaseChangedEvent,
|
||||
IssueStatus,
|
||||
IssueStatusChangedEvent,
|
||||
IssueType,
|
||||
IssueUnlinkedEvent,
|
||||
IssueUpdatedEvent,
|
||||
ProjectCreatedEvent,
|
||||
ProjectMemberAddedEvent,
|
||||
ProjectMemberRemovedEvent,
|
||||
ProjectMemberRoleChangedEvent,
|
||||
ProjectRole,
|
||||
ProjectUpdatedEvent,
|
||||
ReleaseArchivedEvent,
|
||||
ReleaseCreatedEvent,
|
||||
ReleaseShippedEvent,
|
||||
ReleaseUpdatedEvent,
|
||||
TrackerEvent,
|
||||
} from '@task-stream/api/tracker/domain';
|
||||
|
||||
export interface SummaryContext {
|
||||
actor: string;
|
||||
user: (id: string | null) => string;
|
||||
issueKey: string;
|
||||
projectKey: string;
|
||||
releaseName: string;
|
||||
}
|
||||
|
||||
/* The activity feed is read by people: Spanish, with the same labels as the web app. */
|
||||
|
||||
const STATUS: Record<IssueStatus, string> = {
|
||||
[IssueStatus.BACKLOG]: 'Backlog',
|
||||
[IssueStatus.TODO]: 'Por hacer',
|
||||
[IssueStatus.IN_PROGRESS]: 'En curso',
|
||||
[IssueStatus.IN_REVIEW]: 'En revisión',
|
||||
[IssueStatus.READY_FOR_QA]: 'Listo para QA',
|
||||
[IssueStatus.IN_QA]: 'En QA',
|
||||
[IssueStatus.QA_FAILED]: 'QA fallido',
|
||||
[IssueStatus.DONE]: 'Hecho',
|
||||
[IssueStatus.CANCELLED]: 'Cancelado',
|
||||
};
|
||||
|
||||
const TYPE: Record<IssueType, string> = {
|
||||
[IssueType.BUG]: 'bug',
|
||||
[IssueType.FEATURE]: 'feature',
|
||||
[IssueType.UI_CHANGE]: 'cambio de UI',
|
||||
[IssueType.TASK]: 'tarea',
|
||||
[IssueType.QA]: 'QA',
|
||||
};
|
||||
|
||||
const LINK: Record<IssueLinkType, string> = {
|
||||
[IssueLinkType.BLOCKS]: 'bloquea a',
|
||||
[IssueLinkType.DEPENDS_ON]: 'depende de',
|
||||
[IssueLinkType.TESTS]: 'prueba',
|
||||
[IssueLinkType.DUPLICATES]: 'duplica a',
|
||||
[IssueLinkType.RELATES_TO]: 'está relacionado con',
|
||||
};
|
||||
|
||||
const ROLE: Record<ProjectRole, string> = {
|
||||
[ProjectRole.OWNER]: 'propietario',
|
||||
[ProjectRole.ADMIN]: 'admin',
|
||||
[ProjectRole.MEMBER]: 'miembro',
|
||||
[ProjectRole.VIEWER]: 'lector',
|
||||
};
|
||||
|
||||
const FIELD: Record<string, string> = {
|
||||
title: 'el título',
|
||||
description: 'la descripción',
|
||||
type: 'el tipo',
|
||||
area: 'el área',
|
||||
priority: 'la prioridad',
|
||||
labels: 'las etiquetas',
|
||||
figmaUrl: 'el enlace de Figma',
|
||||
storyPoints: 'los puntos',
|
||||
dueDate: 'la fecha límite',
|
||||
};
|
||||
|
||||
const list = (items: string[]) =>
|
||||
items.length <= 1
|
||||
? items.join('')
|
||||
: `${items.slice(0, -1).join(', ')} y ${items[items.length - 1]}`;
|
||||
|
||||
/** One human-readable line per event, for the project activity feed. */
|
||||
export function describeEvent(
|
||||
event: TrackerEvent,
|
||||
ctx: SummaryContext,
|
||||
): string {
|
||||
const { actor, issueKey } = ctx;
|
||||
|
||||
if (event instanceof ProjectCreatedEvent)
|
||||
return `${actor} creó el proyecto ${event.project.key}`;
|
||||
if (event instanceof ProjectUpdatedEvent)
|
||||
return `${actor} actualizó el proyecto ${ctx.projectKey}`;
|
||||
if (event instanceof ProjectMemberAddedEvent) {
|
||||
return `${actor} añadió a ${ctx.user(event.userId)} como ${ROLE[event.role]}`;
|
||||
}
|
||||
if (event instanceof ProjectMemberRemovedEvent) {
|
||||
return event.userId === event.actorId
|
||||
? `${actor} salió del proyecto`
|
||||
: `${actor} quitó a ${ctx.user(event.userId)} del proyecto`;
|
||||
}
|
||||
if (event instanceof ProjectMemberRoleChangedEvent) {
|
||||
return `${actor} cambió el rol de ${ctx.user(event.userId)} a ${ROLE[event.role]}`;
|
||||
}
|
||||
|
||||
if (event instanceof IssueCreatedEvent) {
|
||||
return `${actor} creó ${event.issue.key} (${TYPE[event.issue.type]}): ${event.issue.title}`;
|
||||
}
|
||||
if (event instanceof IssueUpdatedEvent) {
|
||||
return `${actor} cambió ${list(Object.keys(event.changes).map((f) => FIELD[f] ?? f))} de ${issueKey}`;
|
||||
}
|
||||
if (event instanceof IssueStatusChangedEvent) {
|
||||
return `${actor} movió ${issueKey} de ${STATUS[event.from]} a ${STATUS[event.to]}${event.reason ? `: ${event.reason}` : ''}`;
|
||||
}
|
||||
if (event instanceof IssueAssignedEvent) {
|
||||
return event.assigneeId
|
||||
? `${actor} asignó ${issueKey} a ${ctx.user(event.assigneeId)}`
|
||||
: `${actor} dejó ${issueKey} sin asignar`;
|
||||
}
|
||||
if (event instanceof IssueLinkedEvent) {
|
||||
return `${actor} indicó que ${issueKey} ${LINK[event.link.type]} ${event.link.targetKey}`;
|
||||
}
|
||||
if (event instanceof IssueUnlinkedEvent) {
|
||||
return `${actor} quitó la relación entre ${issueKey} y ${event.link.targetKey}`;
|
||||
}
|
||||
if (event instanceof IssueReleaseChangedEvent) {
|
||||
return event.releaseId
|
||||
? `${actor} metió ${issueKey} en la release ${ctx.releaseName}`
|
||||
: `${actor} sacó ${issueKey} de su release`;
|
||||
}
|
||||
|
||||
if (event instanceof CommentAddedEvent)
|
||||
return `${actor} comentó en ${issueKey}`;
|
||||
if (event instanceof CommentEditedEvent)
|
||||
return `${actor} editó un comentario en ${issueKey}`;
|
||||
if (event instanceof CommentDeletedEvent)
|
||||
return `${actor} borró un comentario en ${issueKey}`;
|
||||
|
||||
if (event instanceof ReleaseCreatedEvent)
|
||||
return `${actor} creó la release ${event.release.name}`;
|
||||
if (event instanceof ReleaseUpdatedEvent)
|
||||
return `${actor} actualizó la release ${ctx.releaseName}`;
|
||||
if (event instanceof ReleaseShippedEvent)
|
||||
return `${actor} publicó la release ${ctx.releaseName} 🚀`;
|
||||
if (event instanceof ReleaseArchivedEvent)
|
||||
return `${actor} archivó la release ${ctx.releaseName}`;
|
||||
return `${actor}: ${event.constructor.name}`;
|
||||
}
|
||||
Reference in New Issue
Block a user