From 96013b699519be18c903e2d36cafcdf2f1ceaa03 Mon Sep 17 00:00:00 2001 From: Roman Korvatskyi Date: Mon, 7 Sep 2026 18:02:32 +0200 Subject: [PATCH] feat(board): CU-86ajn8n1y reapply activity/staleness indicator row on TicketCard Revert of the landed revert (0e703611, #2101) - restores #1696 adapted to the current main (Pragmatic DnD, strict ESLint, touch mode, prettier). Ships for testing together with the FE reapply branch (hotfix/reapply-tickets-board-staleness) and BE reapply #2099. Co-Authored-By: Claude Fable 5 --- .../src/components/features/board/index.ts | 2 + .../components/features/board/ticket-card.tsx | 33 ++++++++++++++- .../src/components/features/board/types.ts | 20 +++++++++ .../src/stories/TicketCard.stories.tsx | 41 ++++++++++++++++++- 4 files changed, 93 insertions(+), 3 deletions(-) diff --git a/openframe-frontend-core/src/components/features/board/index.ts b/openframe-frontend-core/src/components/features/board/index.ts index c3be134a7..6a85380a6 100644 --- a/openframe-frontend-core/src/components/features/board/index.ts +++ b/openframe-frontend-core/src/components/features/board/index.ts @@ -21,6 +21,8 @@ export type { BoardColumnDef, BoardPriority, BoardTicket, + BoardTicketActivity, + BoardTicketActivityKind, BoardTicketAssignee, BoardTicketPendingApproval, } from './types'; diff --git a/openframe-frontend-core/src/components/features/board/ticket-card.tsx b/openframe-frontend-core/src/components/features/board/ticket-card.tsx index 3960e37fe..d0cf19fbc 100644 --- a/openframe-frontend-core/src/components/features/board/ticket-card.tsx +++ b/openframe-frontend-core/src/components/features/board/ticket-card.tsx @@ -21,7 +21,14 @@ import { cn } from '../../../utils/cn'; import { formatTicketRelativeTime, formatTicketFullTimestamp } from '../../../utils/date-utils'; import { holdMoveDragEffect } from '../../../utils/drag-effect'; import { getReadableTextColor } from '../../../utils/ods-color-utils'; -import { LaptopIcon, Flag02Icon, MessagesIcon, UserCheckIcon } from '../../icons-v2-generated'; +import { + ClockIcon, + DotsLoaderIcon, + LaptopIcon, + Flag02Icon, + MessagesIcon, + UserCheckIcon, +} from '../../icons-v2-generated'; import { DeletedUserAvatar } from '../../ui/deleted-user-avatar'; import { SquareAvatar } from '../../ui/square-avatar'; import { Tag } from '../../ui/tag'; @@ -30,7 +37,7 @@ import { BoardTicketApproval } from './board-ticket-approval'; import { useBoardLift, useDropAim } from './drop-aim'; import { DROP_LINE_ATTRIBUTE } from './lane-geometry'; import { useIsLanding } from './pending-move'; -import type { BoardPriority, BoardTicket } from './types'; +import type { BoardPriority, BoardTicket, BoardTicketActivityKind } from './types'; import { TICKET_ID_ATTRIBUTE } from './use-lane-scroll-anchor'; const PRIORITY_COLOR_CLASS: Record = { @@ -50,6 +57,13 @@ export const DRAG_PREVIEW_OPACITY = 0.9; const MAX_VISIBLE_TAGS = 2; const MAX_VISIBLE_ASSIGNEES = 3; +const ACTIVITY_DEFAULT_LABEL: Record = { + 'ai-working': 'AI assistant is working', + 'user-typing': 'User typing', + 'waiting-external': 'Waiting for client response', + stale: 'No activity', +}; + /** Shared card shell (border / padding / bg). Same footprint for the draggable * board card and the static {@link TicketCardView}. */ const TICKET_CARD_SHELL = @@ -158,6 +172,21 @@ export function TicketCardBody({ ticket, columnColor, renderAssignSlot, onApprov Escalated by User )} + {ticket.activity && ( +
+ {ticket.activity.kind === 'stale' ? ( + + ) : ( + + )} + {ticket.activity.label ?? ACTIVITY_DEFAULT_LABEL[ticket.activity.kind]} +
+ )} {showNewMessage && ( { + const activities: { kind: BoardTicketActivityKind; label?: string }[] = [ + { kind: 'ai-working' }, + { kind: 'user-typing' }, + { kind: 'waiting-external' }, + { kind: 'stale', label: 'No activity for 2 hours' }, + ]; + return ( +
+ {activities.map(activity => ( + + ))} +
+ ); + }, +}; + /** * Pending CLIENT approval — collapsed grey "Pending client approval" row with a * loader glyph. Expand it to reach the shared approve/reject affordance.