agent-ecosystem/src/shared/utils/taskChangeSince.ts
iliya 92968b45ad refactor(graph): simplify comment particle rendering with dedicated bubble function
- Replaced inline drawing logic for task comments with a new `drawCommentBubble` function to enhance readability and maintainability.
- The new function encapsulates the drawing of a speech-bubble icon, including the rounded rectangle body, tail, and inner dots to suggest text.
2026-03-30 20:02:05 +03:00

51 lines
1.6 KiB
TypeScript

const TASK_SINCE_GRACE_MS = 2 * 60 * 1000;
type TaskChangeIntervalLike = {
startedAt?: string | null;
};
type TaskChangeHistoryEventLike = {
timestamp?: string | null;
};
export interface TaskChangeSinceLike<
TInterval extends TaskChangeIntervalLike = TaskChangeIntervalLike,
THistoryEvent extends TaskChangeHistoryEventLike = TaskChangeHistoryEventLike,
> {
createdAt?: string | null;
workIntervals?: TInterval[] | null;
historyEvents?: THistoryEvent[] | null;
}
export function deriveTaskSince<
TInterval extends TaskChangeIntervalLike,
THistoryEvent extends TaskChangeHistoryEventLike,
>(task: TaskChangeSinceLike<TInterval, THistoryEvent> | null | undefined): string | undefined {
if (!task) return undefined;
const sources: string[] = [];
if (typeof task.createdAt === 'string' && task.createdAt.length > 0) {
sources.push(task.createdAt);
}
if (Array.isArray(task.workIntervals)) {
for (const interval of task.workIntervals) {
if (typeof interval?.startedAt === 'string' && interval.startedAt.length > 0) {
sources.push(interval.startedAt);
}
}
}
if (Array.isArray(task.historyEvents)) {
for (const event of task.historyEvents) {
if (typeof event?.timestamp === 'string' && event.timestamp.length > 0) {
sources.push(event.timestamp);
}
}
}
if (sources.length === 0) return undefined;
const [first, ...rest] = sources;
const earliest = rest.reduce((a, b) => (a < b ? a : b), first);
const date = new Date(earliest);
date.setTime(date.getTime() - TASK_SINCE_GRACE_MS);
return date.toISOString();
}