mirror of
https://github.com/tiennm99/goclaw.git
synced 2026-10-13 08:15:29 +00:00
feat(teams): show the full task UUID in the task detail dialog with one-click copy (#1560)
The short identifier (T-015-cc8e) carries only the last four hex chars of the UUID, while every agent-facing surface — the team_tasks tool (get / retry / cancel / comment) and the teams.tasks.* RPCs — takes the full UUID. A human looking at the dashboard therefore had no way to name a task to the lead in chat. Show the UUID next to the identifier and status badges, copy it to the clipboard on click, with a short "copied" confirmation. Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
1 parent
0fef6ff596
commit
d98ea89e3b
7 files changed
+58
-6
No files matched your search
@@ -16,6 +16,11 @@ All notable changes to GoClaw are documented here. For full documentation, see [
|
||||
|
||||
### Added
|
||||
|
||||
- **Task detail dialog shows the full task UUID with one-click copy** — the
|
||||
short identifier (`T-015-cc8e`) carries only the last four hex characters of
|
||||
the UUID, while the agent-facing `team_tasks` tool and RPCs take the full
|
||||
UUID, so a human had no way to name a task to the lead from the dashboard.
|
||||
|
||||
- **Behavior UX sidecar delivery overrides** — Adds sidecar-generated Quick
|
||||
Acknowledgement and Intermediate Replies with provider/model, timeout, token,
|
||||
and char caps. Effective config resolves Channel > Agent > Workspace, with
|
||||
|
||||
@@ -117,7 +117,9 @@
|
||||
"followupCountMax": "Reminders sent: {{count}}/{{max}}",
|
||||
"followupNext": "Next reminder:",
|
||||
"followupDone": "All reminders sent",
|
||||
"download": "Download"
|
||||
"download": "Download",
|
||||
"copyId": "Copy task ID",
|
||||
"copied": "Copied"
|
||||
},
|
||||
"delete": "Delete",
|
||||
"deleteConfirm": "Delete this task? This cannot be undone.",
|
||||
|
||||
@@ -117,7 +117,9 @@
|
||||
"followupCountMax": "알림 발송: {{count}}/{{max}}회",
|
||||
"followupNext": "다음 알림:",
|
||||
"followupDone": "모든 알림 발송됨",
|
||||
"download": "다운로드"
|
||||
"download": "다운로드",
|
||||
"copyId": "작업 ID 복사",
|
||||
"copied": "복사됨"
|
||||
},
|
||||
"delete": "삭제",
|
||||
"deleteConfirm": "이 태스크를 삭제하시겠습니까? 취소할 수 없습니다.",
|
||||
|
||||
@@ -117,7 +117,9 @@
|
||||
"followupCountMax": "Отправлено напоминаний: {{count}}/{{max}}",
|
||||
"followupNext": "Следующее напоминание:",
|
||||
"followupDone": "Все напоминания отправлены",
|
||||
"download": "Скачать"
|
||||
"download": "Скачать",
|
||||
"copyId": "Скопировать ID задачи",
|
||||
"copied": "Скопировано"
|
||||
},
|
||||
"delete": "Удалить",
|
||||
"deleteConfirm": "Удалить эту задачу? Это действие нельзя отменить.",
|
||||
|
||||
@@ -117,7 +117,9 @@
|
||||
"followupCountMax": "Đã nhắc: {{count}}/{{max}} lần",
|
||||
"followupNext": "Nhắc tiếp:",
|
||||
"followupDone": "Đã nhắc hết",
|
||||
"download": "Tải xuống"
|
||||
"download": "Tải xuống",
|
||||
"copyId": "Sao chép ID tác vụ",
|
||||
"copied": "Đã sao chép"
|
||||
},
|
||||
"delete": "Xoá",
|
||||
"deleteConfirm": "Xoá task này? Không thể hoàn tác.",
|
||||
|
||||
@@ -117,7 +117,9 @@
|
||||
"followupCountMax": "已提醒:{{count}}/{{max}} 次",
|
||||
"followupNext": "下次提醒:",
|
||||
"followupDone": "已全部提醒",
|
||||
"download": "下载"
|
||||
"download": "下载",
|
||||
"copyId": "复制任务 ID",
|
||||
"copied": "已复制"
|
||||
},
|
||||
"delete": "删除",
|
||||
"deleteConfirm": "删除此任务?此操作无法撤消。",
|
||||
|
||||
@@ -7,7 +7,7 @@ import { Button } from "@/components/ui/button";
|
||||
import { Separator } from "@/components/ui/separator";
|
||||
import { ConfirmDialog } from "@/components/shared/confirm-dialog";
|
||||
import {
|
||||
Trash2, ArrowUp, ArrowDown, ArrowRight, AlertTriangle,
|
||||
Trash2, ArrowUp, ArrowDown, ArrowRight, AlertTriangle, Copy, Check,
|
||||
} from "lucide-react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { formatDate } from "@/lib/format";
|
||||
@@ -41,6 +41,42 @@ function priorityLabel(priority?: number) {
|
||||
return priority != null ? (PRIORITY_CONFIG[priority]?.label ?? String(priority)) : "\u2014";
|
||||
}
|
||||
|
||||
/* ── Task UUID with copy ──────────────────────────────────────── */
|
||||
|
||||
// The short identifier (T-015-cc8e) carries only the last four hex chars of
|
||||
// the UUID, while every agent-facing tool (team_tasks get/retry/cancel, comments)
|
||||
// takes the full UUID. Show it in full and make it one click to copy so a
|
||||
// human can hand the exact task to the lead in chat.
|
||||
function TaskIdCopy({ id, label, copiedLabel }: { id: string; label: string; copiedLabel: string }) {
|
||||
const [copied, setCopied] = useState(false);
|
||||
useEffect(() => {
|
||||
if (!copied) return;
|
||||
const timer = setTimeout(() => setCopied(false), 1500);
|
||||
return () => clearTimeout(timer);
|
||||
}, [copied]);
|
||||
|
||||
const copy = async () => {
|
||||
try {
|
||||
await navigator.clipboard.writeText(id);
|
||||
setCopied(true);
|
||||
} catch { /* clipboard unavailable (insecure context) — the text is still selectable */ }
|
||||
};
|
||||
|
||||
return (
|
||||
<button
|
||||
type="button"
|
||||
onClick={copy}
|
||||
title={copied ? copiedLabel : label}
|
||||
className="inline-flex items-center gap-1 rounded px-1 font-mono text-[11px] text-muted-foreground hover:bg-accent hover:text-foreground select-all"
|
||||
>
|
||||
<span className="truncate max-w-[16rem] sm:max-w-none">{id}</span>
|
||||
{copied
|
||||
? <Check className="h-3 w-3 shrink-0 text-green-600" />
|
||||
: <Copy className="h-3 w-3 shrink-0" />}
|
||||
</button>
|
||||
);
|
||||
}
|
||||
|
||||
/* ── Metadata item ────────────────────────────────────────────── */
|
||||
|
||||
function MetaItem({ label, children }: { label: string; children: React.ReactNode }) {
|
||||
@@ -129,6 +165,7 @@ export function TaskDetailDialog({
|
||||
<Badge variant={taskStatusBadgeVariant(task.status)} className="text-xs">
|
||||
{task.status.replace(/_/g, " ")}
|
||||
</Badge>
|
||||
<TaskIdCopy id={task.id} label={t("tasks.detail.copyId")} copiedLabel={t("tasks.detail.copied")} />
|
||||
</div>
|
||||
<DialogTitle className="text-base sm:text-lg">{task.subject}</DialogTitle>
|
||||
</DialogHeader>
|
||||
|
||||
Reference in new issue
Block a user