From 0bc47a997dd9ab19da89ff9b1e2eb5abaabcaa0f Mon Sep 17 00:00:00 2001 From: adonis <513554676@qq.com> Date: Thu, 19 Mar 2026 23:54:08 +0800 Subject: [PATCH] feat(ext): rerun tasks from history --- .../src/components/HistoryDetail.tsx | 27 ++++++++++- .../extension/src/components/HistoryList.tsx | 47 +++++++++++++++---- .../src/entrypoints/sidepanel/App.tsx | 33 +++++++++---- 3 files changed, 87 insertions(+), 20 deletions(-) diff --git a/packages/extension/src/components/HistoryDetail.tsx b/packages/extension/src/components/HistoryDetail.tsx index 2f07966..9fe2d59 100644 --- a/packages/extension/src/components/HistoryDetail.tsx +++ b/packages/extension/src/components/HistoryDetail.tsx @@ -1,4 +1,4 @@ -import { ArrowLeft } from 'lucide-react' +import { ArrowLeft, RotateCcw } from 'lucide-react' import { useEffect, useState } from 'react' import { Button } from '@/components/ui/button' @@ -6,7 +6,17 @@ import { type SessionRecord, getSession } from '@/lib/db' import { EventCard } from './cards' -export function HistoryDetail({ sessionId, onBack }: { sessionId: string; onBack: () => void }) { +export function HistoryDetail({ + sessionId, + onBack, + onRerun, + rerunDisabled = false, +}: { + sessionId: string + onBack: () => void + onRerun: (task: string) => void + rerunDisabled?: boolean +}) { const [session, setSession] = useState(null) useEffect(() => { @@ -37,6 +47,19 @@ export function HistoryDetail({ sessionId, onBack }: { sessionId: string; onBack
{session.task}
+
+ +
{/* Events (read-only) */} diff --git a/packages/extension/src/components/HistoryList.tsx b/packages/extension/src/components/HistoryList.tsx index c13bae2..096ac0f 100644 --- a/packages/extension/src/components/HistoryList.tsx +++ b/packages/extension/src/components/HistoryList.tsx @@ -1,4 +1,4 @@ -import { ArrowLeft, CheckCircle, Trash2, XCircle } from 'lucide-react' +import { ArrowLeft, CheckCircle, RotateCcw, Trash2, XCircle } from 'lucide-react' import { useCallback, useEffect, useState } from 'react' import { Button } from '@/components/ui/button' @@ -18,9 +18,13 @@ function timeAgo(ts: number): string { export function HistoryList({ onSelect, onBack, + onRerun, + rerunDisabled = false, }: { onSelect: (id: string) => void onBack: () => void + onRerun: (task: string) => void + rerunDisabled?: boolean }) { const [sessions, setSessions] = useState([]) const [loading, setLoading] = useState(true) @@ -41,6 +45,11 @@ export function HistoryList({ setSessions((prev) => prev.filter((s) => s.id !== id)) } + const handleRerun = (e: React.MouseEvent, task: string) => { + e.stopPropagation() + onRerun(task) + } + return (
{/* Header */} @@ -85,7 +94,12 @@ export function HistoryList({ role="button" tabIndex={0} onClick={() => onSelect(session.id)} - onKeyDown={(e) => e.key === 'Enter' && onSelect(session.id)} + onKeyDown={(e) => { + if (e.target !== e.currentTarget) return + if (e.key !== 'Enter' && e.key !== ' ') return + e.preventDefault() + onSelect(session.id) + }} className="w-full text-left px-3 py-2.5 border-b hover:bg-muted/50 transition-colors cursor-pointer flex items-start gap-2 group" > {/* Status icon */} @@ -103,14 +117,27 @@ export function HistoryList({

- {/* Delete */} - +
+ + +
))} diff --git a/packages/extension/src/entrypoints/sidepanel/App.tsx b/packages/extension/src/entrypoints/sidepanel/App.tsx index db02f53..9835460 100644 --- a/packages/extension/src/entrypoints/sidepanel/App.tsx +++ b/packages/extension/src/entrypoints/sidepanel/App.tsx @@ -56,19 +56,27 @@ export default function App() { } }, [history, activity]) - const handleSubmit = useCallback( - (e?: React.SyntheticEvent) => { - e?.preventDefault() - if (!inputValue.trim() || status === 'running') return + const runTask = useCallback( + (task: string) => { + const normalizedTask = task.trim() + if (!normalizedTask || status === 'running') return - const taskToExecute = inputValue.trim() setInputValue('') + setView({ name: 'chat' }) - execute(taskToExecute).catch((error) => { + execute(normalizedTask).catch((error) => { console.error('[SidePanel] Failed to execute task:', error) }) }, - [inputValue, status, execute] + [execute, status] + ) + + const handleSubmit = useCallback( + (e?: React.SyntheticEvent) => { + e?.preventDefault() + runTask(inputValue) + }, + [inputValue, runTask] ) const handleStop = useCallback(() => { @@ -103,12 +111,21 @@ export default function App() { setView({ name: 'history-detail', sessionId: id })} onBack={() => setView({ name: 'chat' })} + onRerun={runTask} + rerunDisabled={status === 'running'} /> ) } if (view.name === 'history-detail') { - return setView({ name: 'history' })} /> + return ( + setView({ name: 'history' })} + onRerun={runTask} + rerunDisabled={status === 'running'} + /> + ) } // --- Chat view ---