Spaces:
Runtime error
Runtime error
nyk commited on
feat: add awaiting_owner task status detection (#428)
Browse filesAdd awaiting_owner column to task board with keyword-based detection
for tasks requiring human action. Tasks matching keywords like
"waiting for", "needs human", "approval needed" are automatically
placed in a dedicated column with orange styling.
Supersedes #397
- messages/ar.json +1 -0
- messages/de.json +1 -0
- messages/en.json +1 -0
- messages/es.json +1 -0
- messages/fr.json +1 -0
- messages/ja.json +1 -0
- messages/ko.json +1 -0
- messages/pt.json +1 -0
- messages/ru.json +1 -0
- messages/zh.json +1 -0
- src/components/panels/task-board-panel.tsx +27 -3
- src/store/index.ts +1 -1
messages/ar.json
CHANGED
|
@@ -593,6 +593,7 @@
|
|
| 593 |
"columnAriaLabel": "عمود {title}، {count} مهمة",
|
| 594 |
"colInbox": "البريد الوارد",
|
| 595 |
"colAssigned": "مُخصّص",
|
|
|
|
| 596 |
"colInProgress": "قيد التنفيذ",
|
| 597 |
"colReview": "المراجعة",
|
| 598 |
"colQualityReview": "مراجعة الجودة",
|
|
|
|
| 593 |
"columnAriaLabel": "عمود {title}، {count} مهمة",
|
| 594 |
"colInbox": "البريد الوارد",
|
| 595 |
"colAssigned": "مُخصّص",
|
| 596 |
+
"colAwaitingOwner": "بانتظار المالك",
|
| 597 |
"colInProgress": "قيد التنفيذ",
|
| 598 |
"colReview": "المراجعة",
|
| 599 |
"colQualityReview": "مراجعة الجودة",
|
messages/de.json
CHANGED
|
@@ -593,6 +593,7 @@
|
|
| 593 |
"columnAriaLabel": "Spalte {title}, {count} Aufgaben",
|
| 594 |
"colInbox": "Posteingang",
|
| 595 |
"colAssigned": "Zugewiesen",
|
|
|
|
| 596 |
"colInProgress": "In Bearbeitung",
|
| 597 |
"colReview": "Überprüfung",
|
| 598 |
"colQualityReview": "Qualitätsprüfung",
|
|
|
|
| 593 |
"columnAriaLabel": "Spalte {title}, {count} Aufgaben",
|
| 594 |
"colInbox": "Posteingang",
|
| 595 |
"colAssigned": "Zugewiesen",
|
| 596 |
+
"colAwaitingOwner": "Wartet auf Besitzer",
|
| 597 |
"colInProgress": "In Bearbeitung",
|
| 598 |
"colReview": "Überprüfung",
|
| 599 |
"colQualityReview": "Qualitätsprüfung",
|
messages/en.json
CHANGED
|
@@ -742,6 +742,7 @@
|
|
| 742 |
"columnAriaLabel": "{title} column, {count} tasks",
|
| 743 |
"colInbox": "Inbox",
|
| 744 |
"colAssigned": "Assigned",
|
|
|
|
| 745 |
"colInProgress": "In Progress",
|
| 746 |
"colReview": "Review",
|
| 747 |
"colQualityReview": "Quality Review",
|
|
|
|
| 742 |
"columnAriaLabel": "{title} column, {count} tasks",
|
| 743 |
"colInbox": "Inbox",
|
| 744 |
"colAssigned": "Assigned",
|
| 745 |
+
"colAwaitingOwner": "Awaiting Owner",
|
| 746 |
"colInProgress": "In Progress",
|
| 747 |
"colReview": "Review",
|
| 748 |
"colQualityReview": "Quality Review",
|
messages/es.json
CHANGED
|
@@ -593,6 +593,7 @@
|
|
| 593 |
"columnAriaLabel": "Columna {title}, {count} tareas",
|
| 594 |
"colInbox": "Bandeja de entrada",
|
| 595 |
"colAssigned": "Asignado",
|
|
|
|
| 596 |
"colInProgress": "En progreso",
|
| 597 |
"colReview": "Revisión",
|
| 598 |
"colQualityReview": "Revisión de calidad",
|
|
|
|
| 593 |
"columnAriaLabel": "Columna {title}, {count} tareas",
|
| 594 |
"colInbox": "Bandeja de entrada",
|
| 595 |
"colAssigned": "Asignado",
|
| 596 |
+
"colAwaitingOwner": "Esperando al propietario",
|
| 597 |
"colInProgress": "En progreso",
|
| 598 |
"colReview": "Revisión",
|
| 599 |
"colQualityReview": "Revisión de calidad",
|
messages/fr.json
CHANGED
|
@@ -593,6 +593,7 @@
|
|
| 593 |
"columnAriaLabel": "Colonne {title}, {count} tâches",
|
| 594 |
"colInbox": "Boîte de réception",
|
| 595 |
"colAssigned": "Assigné",
|
|
|
|
| 596 |
"colInProgress": "En cours",
|
| 597 |
"colReview": "Révision",
|
| 598 |
"colQualityReview": "Révision qualité",
|
|
|
|
| 593 |
"columnAriaLabel": "Colonne {title}, {count} tâches",
|
| 594 |
"colInbox": "Boîte de réception",
|
| 595 |
"colAssigned": "Assigné",
|
| 596 |
+
"colAwaitingOwner": "En attente du propriétaire",
|
| 597 |
"colInProgress": "En cours",
|
| 598 |
"colReview": "Révision",
|
| 599 |
"colQualityReview": "Révision qualité",
|
messages/ja.json
CHANGED
|
@@ -593,6 +593,7 @@
|
|
| 593 |
"columnAriaLabel": "{title}列、{count}件のタスク",
|
| 594 |
"colInbox": "受信トレイ",
|
| 595 |
"colAssigned": "割り当て済み",
|
|
|
|
| 596 |
"colInProgress": "進行中",
|
| 597 |
"colReview": "レビュー",
|
| 598 |
"colQualityReview": "品質レビュー",
|
|
|
|
| 593 |
"columnAriaLabel": "{title}列、{count}件のタスク",
|
| 594 |
"colInbox": "受信トレイ",
|
| 595 |
"colAssigned": "割り当て済み",
|
| 596 |
+
"colAwaitingOwner": "オーナー待ち",
|
| 597 |
"colInProgress": "進行中",
|
| 598 |
"colReview": "レビュー",
|
| 599 |
"colQualityReview": "品質レビュー",
|
messages/ko.json
CHANGED
|
@@ -593,6 +593,7 @@
|
|
| 593 |
"columnAriaLabel": "{title} 열, {count}개 작업",
|
| 594 |
"colInbox": "받은 편지함",
|
| 595 |
"colAssigned": "할당됨",
|
|
|
|
| 596 |
"colInProgress": "진행 중",
|
| 597 |
"colReview": "검토",
|
| 598 |
"colQualityReview": "품질 검토",
|
|
|
|
| 593 |
"columnAriaLabel": "{title} 열, {count}개 작업",
|
| 594 |
"colInbox": "받은 편지함",
|
| 595 |
"colAssigned": "할당됨",
|
| 596 |
+
"colAwaitingOwner": "소유자 대기 중",
|
| 597 |
"colInProgress": "진행 중",
|
| 598 |
"colReview": "검토",
|
| 599 |
"colQualityReview": "품질 검토",
|
messages/pt.json
CHANGED
|
@@ -593,6 +593,7 @@
|
|
| 593 |
"columnAriaLabel": "Coluna {title}, {count} tarefas",
|
| 594 |
"colInbox": "Caixa de entrada",
|
| 595 |
"colAssigned": "Atribuído",
|
|
|
|
| 596 |
"colInProgress": "Em andamento",
|
| 597 |
"colReview": "Revisão",
|
| 598 |
"colQualityReview": "Revisão de qualidade",
|
|
|
|
| 593 |
"columnAriaLabel": "Coluna {title}, {count} tarefas",
|
| 594 |
"colInbox": "Caixa de entrada",
|
| 595 |
"colAssigned": "Atribuído",
|
| 596 |
+
"colAwaitingOwner": "Aguardando proprietário",
|
| 597 |
"colInProgress": "Em andamento",
|
| 598 |
"colReview": "Revisão",
|
| 599 |
"colQualityReview": "Revisão de qualidade",
|
messages/ru.json
CHANGED
|
@@ -593,6 +593,7 @@
|
|
| 593 |
"columnAriaLabel": "Колонка {title}, {count} задач",
|
| 594 |
"colInbox": "Входящие",
|
| 595 |
"colAssigned": "Назначено",
|
|
|
|
| 596 |
"colInProgress": "В работе",
|
| 597 |
"colReview": "На проверке",
|
| 598 |
"colQualityReview": "Контроль качества",
|
|
|
|
| 593 |
"columnAriaLabel": "Колонка {title}, {count} задач",
|
| 594 |
"colInbox": "Входящие",
|
| 595 |
"colAssigned": "Назначено",
|
| 596 |
+
"colAwaitingOwner": "Ожидает владельца",
|
| 597 |
"colInProgress": "В работе",
|
| 598 |
"colReview": "На проверке",
|
| 599 |
"colQualityReview": "Контроль качества",
|
messages/zh.json
CHANGED
|
@@ -831,6 +831,7 @@
|
|
| 831 |
"columnAriaLabel": "{title} 列,{count} 个任务",
|
| 832 |
"colInbox": "收件箱",
|
| 833 |
"colAssigned": "已分配",
|
|
|
|
| 834 |
"colInProgress": "进行中",
|
| 835 |
"colReview": "审查",
|
| 836 |
"colQualityReview": "质量审查",
|
|
|
|
| 831 |
"columnAriaLabel": "{title} 列,{count} 个任务",
|
| 832 |
"colInbox": "收件箱",
|
| 833 |
"colAssigned": "已分配",
|
| 834 |
+
"colAwaitingOwner": "等待所有者",
|
| 835 |
"colInProgress": "进行中",
|
| 836 |
"colReview": "审查",
|
| 837 |
"colQualityReview": "质量审查",
|
src/components/panels/task-board-panel.tsx
CHANGED
|
@@ -22,7 +22,7 @@ interface Task {
|
|
| 22 |
id: number
|
| 23 |
title: string
|
| 24 |
description?: string
|
| 25 |
-
status: 'inbox' | 'assigned' | 'in_progress' | 'review' | 'quality_review' | 'done'
|
| 26 |
priority: 'low' | 'medium' | 'high' | 'critical' | 'urgent'
|
| 27 |
assigned_to?: string
|
| 28 |
created_by: string
|
|
@@ -89,12 +89,27 @@ interface MentionOption {
|
|
| 89 |
const STATUS_COLUMN_KEYS = [
|
| 90 |
{ key: 'inbox', titleKey: 'colInbox', color: 'bg-secondary text-foreground' },
|
| 91 |
{ key: 'assigned', titleKey: 'colAssigned', color: 'bg-blue-500/20 text-blue-400' },
|
|
|
|
| 92 |
{ key: 'in_progress', titleKey: 'colInProgress', color: 'bg-yellow-500/20 text-yellow-400' },
|
| 93 |
{ key: 'review', titleKey: 'colReview', color: 'bg-purple-500/20 text-purple-400' },
|
| 94 |
{ key: 'quality_review', titleKey: 'colQualityReview', color: 'bg-indigo-500/20 text-indigo-400' },
|
| 95 |
{ key: 'done', titleKey: 'colDone', color: 'bg-green-500/20 text-green-400' },
|
| 96 |
]
|
| 97 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 98 |
/** Build a human-readable label for a session key like "agent:nefes:telegram-group-123" */
|
| 99 |
function formatSessionLabel(s: { key: string; channel?: string; kind?: string; label?: string }): string {
|
| 100 |
if (s.label) return s.label
|
|
@@ -535,9 +550,12 @@ export function TaskBoardPanel() {
|
|
| 535 |
// Poll as SSE fallback — pauses when SSE is delivering events
|
| 536 |
useSmartPoll(fetchData, 30000, { pauseWhenSseConnected: true })
|
| 537 |
|
| 538 |
-
// Group tasks by status
|
| 539 |
const tasksByStatus = statusColumns.reduce((acc, column) => {
|
| 540 |
-
acc[column.key] = tasks.filter(task =>
|
|
|
|
|
|
|
|
|
|
| 541 |
return acc
|
| 542 |
}, {} as Record<string, Task[]>)
|
| 543 |
|
|
@@ -1017,6 +1035,11 @@ export function TaskBoardPanel() {
|
|
| 1017 |
Aegis
|
| 1018 |
</span>
|
| 1019 |
)}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1020 |
</div>
|
| 1021 |
</div>
|
| 1022 |
</div>
|
|
@@ -1820,6 +1843,7 @@ function ClaudeCodeTasksSection() {
|
|
| 1820 |
s === 'completed' ? 'text-green-400' :
|
| 1821 |
s === 'in_progress' ? 'text-blue-400' :
|
| 1822 |
s === 'blocked' ? 'text-red-400' :
|
|
|
|
| 1823 |
'text-muted-foreground'
|
| 1824 |
|
| 1825 |
return (
|
|
|
|
| 22 |
id: number
|
| 23 |
title: string
|
| 24 |
description?: string
|
| 25 |
+
status: 'inbox' | 'assigned' | 'in_progress' | 'review' | 'quality_review' | 'done' | 'awaiting_owner'
|
| 26 |
priority: 'low' | 'medium' | 'high' | 'critical' | 'urgent'
|
| 27 |
assigned_to?: string
|
| 28 |
created_by: string
|
|
|
|
| 89 |
const STATUS_COLUMN_KEYS = [
|
| 90 |
{ key: 'inbox', titleKey: 'colInbox', color: 'bg-secondary text-foreground' },
|
| 91 |
{ key: 'assigned', titleKey: 'colAssigned', color: 'bg-blue-500/20 text-blue-400' },
|
| 92 |
+
{ key: 'awaiting_owner', titleKey: 'colAwaitingOwner', color: 'bg-orange-500/20 text-orange-400' },
|
| 93 |
{ key: 'in_progress', titleKey: 'colInProgress', color: 'bg-yellow-500/20 text-yellow-400' },
|
| 94 |
{ key: 'review', titleKey: 'colReview', color: 'bg-purple-500/20 text-purple-400' },
|
| 95 |
{ key: 'quality_review', titleKey: 'colQualityReview', color: 'bg-indigo-500/20 text-indigo-400' },
|
| 96 |
{ key: 'done', titleKey: 'colDone', color: 'bg-green-500/20 text-green-400' },
|
| 97 |
]
|
| 98 |
|
| 99 |
+
const AWAITING_OWNER_KEYWORDS = [
|
| 100 |
+
'waiting for', 'waiting on', 'needs human', 'manual action',
|
| 101 |
+
'account creation', 'browser login', 'approval needed',
|
| 102 |
+
'owner action', 'human required', 'blocked on owner',
|
| 103 |
+
'awaiting owner', 'awaiting human', 'needs owner',
|
| 104 |
+
]
|
| 105 |
+
|
| 106 |
+
function detectAwaitingOwner(task: Task): boolean {
|
| 107 |
+
if (task.status === 'awaiting_owner') return true
|
| 108 |
+
if (task.status !== 'assigned' && task.status !== 'in_progress') return false
|
| 109 |
+
const text = `${task.title} ${task.description || ''}`.toLowerCase()
|
| 110 |
+
return AWAITING_OWNER_KEYWORDS.some(kw => text.includes(kw))
|
| 111 |
+
}
|
| 112 |
+
|
| 113 |
/** Build a human-readable label for a session key like "agent:nefes:telegram-group-123" */
|
| 114 |
function formatSessionLabel(s: { key: string; channel?: string; kind?: string; label?: string }): string {
|
| 115 |
if (s.label) return s.label
|
|
|
|
| 550 |
// Poll as SSE fallback — pauses when SSE is delivering events
|
| 551 |
useSmartPoll(fetchData, 30000, { pauseWhenSseConnected: true })
|
| 552 |
|
| 553 |
+
// Group tasks by status, overriding for awaiting_owner detection
|
| 554 |
const tasksByStatus = statusColumns.reduce((acc, column) => {
|
| 555 |
+
acc[column.key] = tasks.filter(task => {
|
| 556 |
+
const effectiveStatus = detectAwaitingOwner(task) ? 'awaiting_owner' : task.status
|
| 557 |
+
return effectiveStatus === column.key
|
| 558 |
+
})
|
| 559 |
return acc
|
| 560 |
}, {} as Record<string, Task[]>)
|
| 561 |
|
|
|
|
| 1035 |
Aegis
|
| 1036 |
</span>
|
| 1037 |
)}
|
| 1038 |
+
{detectAwaitingOwner(task) && (
|
| 1039 |
+
<span className="text-[10px] px-1.5 py-0.5 rounded bg-orange-500/20 text-orange-400 border border-orange-500/30 font-mono">
|
| 1040 |
+
{t('colAwaitingOwner')}
|
| 1041 |
+
</span>
|
| 1042 |
+
)}
|
| 1043 |
</div>
|
| 1044 |
</div>
|
| 1045 |
</div>
|
|
|
|
| 1843 |
s === 'completed' ? 'text-green-400' :
|
| 1844 |
s === 'in_progress' ? 'text-blue-400' :
|
| 1845 |
s === 'blocked' ? 'text-red-400' :
|
| 1846 |
+
s === 'awaiting_owner' ? 'text-orange-400' :
|
| 1847 |
'text-muted-foreground'
|
| 1848 |
|
| 1849 |
return (
|
src/store/index.ts
CHANGED
|
@@ -100,7 +100,7 @@ export interface Task {
|
|
| 100 |
id: number
|
| 101 |
title: string
|
| 102 |
description?: string
|
| 103 |
-
status: 'inbox' | 'assigned' | 'in_progress' | 'review' | 'quality_review' | 'done'
|
| 104 |
priority: 'low' | 'medium' | 'high' | 'critical' | 'urgent'
|
| 105 |
project_id?: number
|
| 106 |
project_ticket_no?: number
|
|
|
|
| 100 |
id: number
|
| 101 |
title: string
|
| 102 |
description?: string
|
| 103 |
+
status: 'inbox' | 'assigned' | 'in_progress' | 'review' | 'quality_review' | 'done' | 'awaiting_owner'
|
| 104 |
priority: 'low' | 'medium' | 'high' | 'critical' | 'urgent'
|
| 105 |
project_id?: number
|
| 106 |
project_ticket_no?: number
|