fix(dashboard): clarify Kanban Ready vs assignment

Ready column help and fallbacks now describe dependency-ready work; show a
badge on unassigned ready cards and fix the stale unassigned tooltip. Align
localized Ready help strings with the new semantics.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Austin Pickett 2026-05-15 22:40:21 -04:00
parent c7db6a5800
commit 63503ebb14
18 changed files with 40 additions and 17 deletions

View file

@ -68,7 +68,7 @@
const FALLBACK_COLUMN_HELP = { const FALLBACK_COLUMN_HELP = {
triage: "Raw ideas — a specifier will flesh out the spec", triage: "Raw ideas — a specifier will flesh out the spec",
todo: "Waiting on dependencies or unassigned", todo: "Waiting on dependencies or unassigned",
ready: "Assigned and waiting for a dispatcher tick", ready: "Dependencies satisfied; assign a profile to dispatch",
running: "Claimed by a worker — in-flight", running: "Claimed by a worker — in-flight",
blocked: "Worker asked for human input", blocked: "Worker asked for human input",
done: "Completed", done: "Completed",
@ -2048,6 +2048,7 @@
}; };
const progress = t.progress; const progress = t.progress;
const needsAssignee = t.status === "ready" && !t.assignee;
return h("div", { return h("div", {
ref: cardRef, ref: cardRef,
@ -2118,6 +2119,13 @@
title: `${progress.done} of ${progress.total} child tasks done`, title: `${progress.done} of ${progress.total} child tasks done`,
}, `${progress.done}/${progress.total}`) }, `${progress.done}/${progress.total}`)
: null, : null,
needsAssignee
? h(Badge, {
variant: "outline",
className: "hermes-kanban-needs-assignee",
title: tx(i18n, "needsAssigneeHint", "Dependencies are satisfied, but the dispatcher skips this task until you assign a profile."),
}, tx(i18n, "needsAssignee", "Needs assignee"))
: null,
), ),
h("div", { className: "hermes-kanban-card-title" }, h("div", { className: "hermes-kanban-card-title" },
t.title || tx(i18n, "untitled", "(untitled)")), t.title || tx(i18n, "untitled", "(untitled)")),
@ -2126,7 +2134,9 @@
? h("span", { className: "hermes-kanban-assignee", ? h("span", { className: "hermes-kanban-assignee",
title: `Assigned to Hermes profile @${t.assignee}` }, "@", t.assignee) title: `Assigned to Hermes profile @${t.assignee}` }, "@", t.assignee)
: h("span", { className: "hermes-kanban-unassigned", : h("span", { className: "hermes-kanban-unassigned",
title: "No profile assigned. The dispatcher will pick one from available profiles when the task is Ready." }, title: needsAssignee
? tx(i18n, "needsAssigneeHint", "Dependencies are satisfied, but the dispatcher skips this task until you assign a profile.")
: "No profile assigned." },
tx(i18n, "unassigned", "unassigned")), tx(i18n, "unassigned", "unassigned")),
t.comment_count > 0 t.comment_count > 0
? h("span", { className: "hermes-kanban-count", ? h("span", { className: "hermes-kanban-count",

View file

@ -280,6 +280,14 @@
padding: 0.05rem 0.3rem !important; padding: 0.05rem 0.3rem !important;
} }
.hermes-kanban-needs-assignee {
font-size: 0.6rem !important;
padding: 0.05rem 0.3rem !important;
background: color-mix(in srgb, var(--color-warning, #d4b348) 16%, transparent);
border-color: color-mix(in srgb, var(--color-warning, #d4b348) 45%, var(--color-border));
color: var(--color-foreground);
}
.hermes-kanban-assignee { .hermes-kanban-assignee {
font-weight: 500; font-weight: 500;
color: color-mix(in srgb, var(--color-foreground) 80%, var(--color-muted-foreground)); color: color-mix(in srgb, var(--color-foreground) 80%, var(--color-muted-foreground));

View file

@ -663,7 +663,7 @@ export const af: Translations = {
columnHelp: { columnHelp: {
triage: "Rou idees — 'n spesifiseerder sal die spesifikasie uitwerk", triage: "Rou idees — 'n spesifiseerder sal die spesifikasie uitwerk",
todo: "Wag op afhanklikhede of nie toegewys nie", todo: "Wag op afhanklikhede of nie toegewys nie",
ready: "Toegewys en wag vir 'n versender-tik", ready: "Afhanklikhede is bevredig; wys 'n profiel toe om te versend",
running: "Deur 'n werker geëis — in vlug", running: "Deur 'n werker geëis — in vlug",
blocked: "Werker het mensinvoer aangevra", blocked: "Werker het mensinvoer aangevra",
done: "Voltooi", done: "Voltooi",

View file

@ -662,7 +662,7 @@ export const de: Translations = {
columnHelp: { columnHelp: {
triage: "Rohe Ideen — ein Specifier wird die Spezifikation ausarbeiten", triage: "Rohe Ideen — ein Specifier wird die Spezifikation ausarbeiten",
todo: "Wartet auf Abhängigkeiten oder ist nicht zugewiesen", todo: "Wartet auf Abhängigkeiten oder ist nicht zugewiesen",
ready: "Zugewiesen und wartet auf einen Dispatcher-Tick", ready: "Abhängigkeiten erfüllt; Profil zum Dispatch zuweisen",
running: "Von einem Worker übernommen — in Bearbeitung", running: "Von einem Worker übernommen — in Bearbeitung",
blocked: "Worker hat um menschliche Eingabe gebeten", blocked: "Worker hat um menschliche Eingabe gebeten",
done: "Abgeschlossen", done: "Abgeschlossen",

View file

@ -574,6 +574,9 @@ export const en: Translations = {
createTask: "Create task in this column", createTask: "Create task in this column",
noTasks: "— no tasks —", noTasks: "— no tasks —",
unassigned: "unassigned", unassigned: "unassigned",
needsAssignee: "Needs assignee",
needsAssigneeHint:
"Dependencies are satisfied, but the dispatcher skips this task until you assign a profile.",
untitled: "(untitled)", untitled: "(untitled)",
loadingDetail: "Loading…", loadingDetail: "Loading…",
addComment: "Add a comment… (Enter to submit)", addComment: "Add a comment… (Enter to submit)",
@ -664,7 +667,7 @@ export const en: Translations = {
columnHelp: { columnHelp: {
triage: "Raw ideas — a specifier will flesh out the spec", triage: "Raw ideas — a specifier will flesh out the spec",
todo: "Waiting on dependencies or unassigned", todo: "Waiting on dependencies or unassigned",
ready: "Assigned and waiting for a dispatcher tick", ready: "Dependencies satisfied; assign a profile to dispatch",
running: "Claimed by a worker — in-flight", running: "Claimed by a worker — in-flight",
blocked: "Worker asked for human input", blocked: "Worker asked for human input",
done: "Completed", done: "Completed",

View file

@ -662,7 +662,7 @@ export const es: Translations = {
columnHelp: { columnHelp: {
triage: "Ideas en bruto — un specifier desarrollará la especificación", triage: "Ideas en bruto — un specifier desarrollará la especificación",
todo: "Esperando dependencias o sin asignar", todo: "Esperando dependencias o sin asignar",
ready: "Asignado y esperando un tick del dispatcher", ready: "Dependencias satisfechas; asigna un perfil para despachar",
running: "Reclamado por un worker — en ejecución", running: "Reclamado por un worker — en ejecución",
blocked: "El worker pidió intervención humana", blocked: "El worker pidió intervención humana",
done: "Completado", done: "Completado",

View file

@ -662,7 +662,7 @@ export const fr: Translations = {
columnHelp: { columnHelp: {
triage: "Idées brutes — un specifier rédigera la spécification", triage: "Idées brutes — un specifier rédigera la spécification",
todo: "En attente de dépendances ou non assigné", todo: "En attente de dépendances ou non assigné",
ready: "Assigné et en attente d'un tick du dispatcher", ready: "Dépendances satisfaites ; assignez un profil pour dispatch",
running: "Réclamé par un worker — en cours d'exécution", running: "Réclamé par un worker — en cours d'exécution",
blocked: "Le worker a demandé une intervention humaine", blocked: "Le worker a demandé une intervention humaine",
done: "Terminé", done: "Terminé",

View file

@ -663,7 +663,7 @@ export const ga: Translations = {
columnHelp: { columnHelp: {
triage: "Smaointe amha — déanfaidh specifier an spec a chur i bhfeidhm", triage: "Smaointe amha — déanfaidh specifier an spec a chur i bhfeidhm",
todo: "Ag fanacht ar spleáchais nó gan sannadh", todo: "Ag fanacht ar spleáchais nó gan sannadh",
ready: "Sannta agus ag fanacht ar thic an dispatcher", ready: "Tá na spleáchais sásaithe; sann próifíl le dispatch a dhéanamh",
running: "Éilithe ag worker — ar siúl", running: "Éilithe ag worker — ar siúl",
blocked: "D'iarr an worker ionchur duine", blocked: "D'iarr an worker ionchur duine",
done: "Críochnaithe", done: "Críochnaithe",

View file

@ -663,7 +663,7 @@ export const hu: Translations = {
columnHelp: { columnHelp: {
triage: "Nyers ötletek — egy specifier kidolgozza a specifikációt", triage: "Nyers ötletek — egy specifier kidolgozza a specifikációt",
todo: "Függőségekre vár vagy nincs felelőse", todo: "Függőségekre vár vagy nincs felelőse",
ready: "Kiosztva, dispatcher tickre vár", ready: "A függőségek teljesültek; rendelj hozzá profilt az indításhoz",
running: "Worker felvette — folyamatban", running: "Worker felvette — folyamatban",
blocked: "A worker emberi beavatkozást kért", blocked: "A worker emberi beavatkozást kért",
done: "Befejezve", done: "Befejezve",

View file

@ -662,7 +662,7 @@ export const it: Translations = {
columnHelp: { columnHelp: {
triage: "Idee grezze — un specifier elaborerà la specifica", triage: "Idee grezze — un specifier elaborerà la specifica",
todo: "In attesa di dipendenze o non assegnato", todo: "In attesa di dipendenze o non assegnato",
ready: "Assegnato e in attesa di un tick del dispatcher", ready: "Dipendenze soddisfatte; assegna un profilo per il dispatch",
running: "Preso in carico da un worker — in esecuzione", running: "Preso in carico da un worker — in esecuzione",
blocked: "Il worker ha richiesto input umano", blocked: "Il worker ha richiesto input umano",
done: "Completato", done: "Completato",

View file

@ -663,7 +663,7 @@ export const ja: Translations = {
columnHelp: { columnHelp: {
triage: "未整理のアイデア — スペシファイアが仕様を肉付けします", triage: "未整理のアイデア — スペシファイアが仕様を肉付けします",
todo: "依存関係の待機中、または未割り当て", todo: "依存関係の待機中、または未割り当て",
ready: "割り当て済み、ディスパッチャーのティック待ち", ready: "依存関係は満たされています。ディスパッチするにはプロファイルを割り当ててください",
running: "ワーカーが取得中 — 実行中", running: "ワーカーが取得中 — 実行中",
blocked: "ワーカーが人間の入力を求めています", blocked: "ワーカーが人間の入力を求めています",
done: "完了", done: "完了",

View file

@ -663,7 +663,7 @@ export const ko: Translations = {
columnHelp: { columnHelp: {
triage: "원시 아이디어 — 스페시파이어가 사양을 구체화합니다", triage: "원시 아이디어 — 스페시파이어가 사양을 구체화합니다",
todo: "종속성 대기 중 또는 미지정", todo: "종속성 대기 중 또는 미지정",
ready: "지정되었으며 디스패처 틱 대기 중", ready: "종속성이 충족됨; 디스패치하려면 프로필을 지정하세요",
running: "워커가 점유 중 — 실행 중", running: "워커가 점유 중 — 실행 중",
blocked: "워커가 사람의 입력을 요청함", blocked: "워커가 사람의 입력을 요청함",
done: "완료됨", done: "완료됨",

View file

@ -663,7 +663,7 @@ export const pt: Translations = {
columnHelp: { columnHelp: {
triage: "Ideias em bruto — um specifier vai detalhar a especificação", triage: "Ideias em bruto — um specifier vai detalhar a especificação",
todo: "À espera de dependências ou sem atribuição", todo: "À espera de dependências ou sem atribuição",
ready: "Atribuído e à espera de um tick do dispatcher", ready: "Dependências satisfeitas; atribua um perfil para despachar",
running: "Reivindicado por um worker — em execução", running: "Reivindicado por um worker — em execução",
blocked: "O worker pediu intervenção humana", blocked: "O worker pediu intervenção humana",
done: "Concluído", done: "Concluído",

View file

@ -663,7 +663,7 @@ export const ru: Translations = {
columnHelp: { columnHelp: {
triage: "Сырые идеи — specifier подготовит спецификацию", triage: "Сырые идеи — specifier подготовит спецификацию",
todo: "Ожидает зависимостей или без исполнителя", todo: "Ожидает зависимостей или без исполнителя",
ready: "Назначено и ждёт тика диспетчера", ready: "Зависимости выполнены; назначьте профиль для диспетчеризации",
running: "Взято воркером — выполняется", running: "Взято воркером — выполняется",
blocked: "Воркер запросил вмешательство человека", blocked: "Воркер запросил вмешательство человека",
done: "Завершено", done: "Завершено",

View file

@ -663,7 +663,7 @@ export const tr: Translations = {
columnHelp: { columnHelp: {
triage: "Ham fikirler — bir specifier şartnameyi detaylandıracak", triage: "Ham fikirler — bir specifier şartnameyi detaylandıracak",
todo: "Bağımlılıklar bekleniyor veya atanmamış", todo: "Bağımlılıklar bekleniyor veya atanmamış",
ready: "Atanmış ve dispatcher tick'i bekleniyor", ready: "Bağımlılıklar karşılandı; dispatch için bir profil atayın",
running: "Bir worker tarafından alındı — yürütülüyor", running: "Bir worker tarafından alındı — yürütülüyor",
blocked: "Worker insan girdisi istedi", blocked: "Worker insan girdisi istedi",
done: "Tamamlandı", done: "Tamamlandı",

View file

@ -586,6 +586,8 @@ export interface Translations {
createTask: string; createTask: string;
noTasks: string; noTasks: string;
unassigned: string; unassigned: string;
needsAssignee?: string;
needsAssigneeHint?: string;
untitled: string; untitled: string;
loadingDetail: string; loadingDetail: string;
addComment: string; addComment: string;

View file

@ -663,7 +663,7 @@ export const zhHant: Translations = {
columnHelp: { columnHelp: {
triage: "原始想法 — 規格制定者將完善規格", triage: "原始想法 — 規格制定者將完善規格",
todo: "等待相依項目或尚未指派", todo: "等待相依項目或尚未指派",
ready: "已指派,等待排程器輪詢", ready: "相依項目已滿足;指派設定檔以便排程",
running: "已被工作者領取 — 執行中", running: "已被工作者領取 — 執行中",
blocked: "工作者請求人工輸入", blocked: "工作者請求人工輸入",
done: "已完成", done: "已完成",

View file

@ -659,7 +659,7 @@ export const zh: Translations = {
columnHelp: { columnHelp: {
triage: "原始想法 — 规范制定者将完善规格", triage: "原始想法 — 规范制定者将完善规格",
todo: "等待依赖项或未分配", todo: "等待依赖项或未分配",
ready: "已分配,等待调度器轮询", ready: "依赖项已满足;分配一个配置文件以便调度",
running: "已被工作者认领 — 执行中", running: "已被工作者认领 — 执行中",
blocked: "工作者请求人工输入", blocked: "工作者请求人工输入",
done: "已完成", done: "已完成",