From 186a565bee4183ad8617aeaf5de3a7911a1758e2 Mon Sep 17 00:00:00 2001 From: Hammer Date: Wed, 28 Jan 2026 23:46:57 +0000 Subject: [PATCH] feat: copyable task IDs on cards and detail panel --- frontend/src/components/TaskCard.tsx | 32 +++++++++++++++++++ frontend/src/components/TaskDetailPanel.tsx | 35 ++++++++++++++++++--- 2 files changed, 63 insertions(+), 4 deletions(-) diff --git a/frontend/src/components/TaskCard.tsx b/frontend/src/components/TaskCard.tsx index 77500d8..a2eca34 100644 --- a/frontend/src/components/TaskCard.tsx +++ b/frontend/src/components/TaskCard.tsx @@ -1,3 +1,4 @@ +import { useState } from "react"; import type { Task, TaskStatus, TaskPriority } from "../lib/types"; const priorityColors: Record = { @@ -65,8 +66,18 @@ export function TaskCard({ isActive, onClick, }: TaskCardProps) { + const [idCopied, setIdCopied] = useState(false); const actions = statusActions[task.status] || []; const noteCount = task.progressNotes?.length || 0; + const shortId = task.id.slice(0, 8); + + const handleCopyId = (e: React.MouseEvent) => { + e.stopPropagation(); + navigator.clipboard.writeText(task.id).then(() => { + setIdCopied(true); + setTimeout(() => setIdCopied(false), 1500); + }); + }; return (
+ { + e.stopPropagation(); + navigator.clipboard.writeText(task.id); + }} + > + {task.id.slice(0, 8)} + {task.priority} @@ -106,6 +127,17 @@ export function TaskCard({ 💬 {noteCount} )} +
{task.description && ( diff --git a/frontend/src/components/TaskDetailPanel.tsx b/frontend/src/components/TaskDetailPanel.tsx index d52ed99..2821eb0 100644 --- a/frontend/src/components/TaskDetailPanel.tsx +++ b/frontend/src/components/TaskDetailPanel.tsx @@ -118,6 +118,35 @@ function ElapsedTimer({ since }: { since: string }) { ); } +function CopyableId({ id }: { id: string }) { + const [copied, setCopied] = useState(false); + + const handleCopy = () => { + navigator.clipboard.writeText(id).then(() => { + setCopied(true); + setTimeout(() => setCopied(false), 2000); + }); + }; + + return ( +
+ ID: + {id} + +
+ ); +} + interface TaskDetailPanelProps { task: Task; onClose: () => void; @@ -278,10 +307,8 @@ export function TaskDetailPanel({ task, onClose, onStatusChange, hasToken }: Tas
)} - {/* Task ID */} -
-

ID: {task.id}

-
+ {/* Task ID - click to copy */} + );