From e2fe3992e33a8546cf54a25de19700c9e517d6db Mon Sep 17 00:00:00 2001 From: Mike S Date: Fri, 27 Feb 2026 11:23:03 +0000 Subject: [PATCH] feat(kan-6): add empty board prompt with Ask Navi suggestion --- src/components/KanbanBoard.tsx | 41 ++++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/src/components/KanbanBoard.tsx b/src/components/KanbanBoard.tsx index 2e2b2c0..a9d96fc 100644 --- a/src/components/KanbanBoard.tsx +++ b/src/components/KanbanBoard.tsx @@ -451,6 +451,7 @@ const [rightWidth, setRightWidth] = useState(402); const [workingByTask, setWorkingByTask] = useState>({}); const [doneConfirm, setDoneConfirm] = useState<{ taskId: number; fromStatus: string; incomplete: number } | null>(null); const [prdEditor, setPrdEditor] = useState<{ taskId: number; title: string; content: string; version: number } | null>(null); + const [isAskingNavi, setIsAskingNavi] = useState(false); const load = useCallback(async () => { const response = await fetch('/api/tasks', { cache: 'no-store' }); @@ -560,6 +561,7 @@ const [rightWidth, setRightWidth] = useState(402); }), [tasks, filters]); const grouped = useMemo(() => STATUS_COLUMNS.map((col) => ({ col, items: filteredTasks.filter((t) => t.status === col) })), [filteredTasks]); + const inProgressTaskCount = useMemo(() => tasks.filter((task) => task.status === 'in_progress').length, [tasks]); const hasActiveFilters = filters.search !== '' || filters.priority !== 'All' || filters.goal !== 'All' || filters.agent !== 'All' || filters.tags !== ''; const hiddenCount = tasks.length - filteredTasks.length; @@ -743,6 +745,27 @@ const [rightWidth, setRightWidth] = useState(402); const toggleColumnCollapsed = (column: string) => setCollapsedColumns((prev) => ({ ...prev, [column]: !prev[column] })); const startWipEdit = (column: string) => { setEditingWipColumn(column); const current = wipLimits[column]; setEditingWipValue(current && current > 0 ? String(current) : ''); }; const saveWipLimit = (column: string) => { const parsed = Number(editingWipValue); setWipLimits((prev) => ({ ...prev, [column]: Number.isFinite(parsed) && parsed > 0 ? parsed : null })); setEditingWipColumn(null); }; + const askNaviForNextTask = async () => { + setErrorMessage(null); + setIsAskingNavi(true); + try { + const response = await fetch('/api/openclaw/chat/send', { + method: 'POST', + headers: { 'content-type': 'application/json' }, + body: JSON.stringify({ + message: 'What should I work on next? Check the backlog and recommend the highest priority task.', + }), + }); + + if (!response.ok) { + setErrorMessage("Failed to ask Navi what's next"); + } + } catch { + setErrorMessage("Failed to ask Navi what's next"); + } finally { + setIsAskingNavi(false); + } + }; return (
@@ -915,6 +938,24 @@ const [rightWidth, setRightWidth] = useState(402); ); })} + {col === 'in_progress' && inProgressTaskCount === 0 && ( +
+
+

+ No tasks in progress. Pick one from backlog or ask Navi for suggestions! +

+ +
+
+ )} {provided.placeholder}
)}