From 6f7bf8df429783e86d92ef1abaa790fd699a3e24 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Padez?= Date: Fri, 24 Jul 2026 14:39:09 +0000 Subject: [PATCH] remove the Automation page MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Deletes the Automation and NewAutomation screens, their /automation and /new-automation routes, the Dashboard barrel exports, the dock item (+ default dock path), and the page-title rule. TaskRunnerModal is kept — the file browser still uses it to run tasks on files. Co-Authored-By: Claude Opus 4.8 --- src/apps/officer-web/App.tsx | 2 - .../Dashboard/Automation/AutomationDetail.tsx | 232 ------------------ .../Dashboard/Automation/AutomationList.tsx | 202 --------------- .../Screens/Dashboard/Automation/CLAUDE.md | 49 ---- .../Screens/Dashboard/Automation/index.tsx | 53 ---- .../Screens/Dashboard/Layout/Dock.tsx | 5 +- .../Screens/Dashboard/NewAutomation/index.tsx | 37 --- .../officer-web/Screens/Dashboard/index.tsx | 2 - src/apps/officer-web/state/usePageTitle.ts | 1 - 9 files changed, 2 insertions(+), 581 deletions(-) delete mode 100644 src/apps/officer-web/Screens/Dashboard/Automation/AutomationDetail.tsx delete mode 100644 src/apps/officer-web/Screens/Dashboard/Automation/AutomationList.tsx delete mode 100644 src/apps/officer-web/Screens/Dashboard/Automation/CLAUDE.md delete mode 100644 src/apps/officer-web/Screens/Dashboard/Automation/index.tsx delete mode 100644 src/apps/officer-web/Screens/Dashboard/NewAutomation/index.tsx diff --git a/src/apps/officer-web/App.tsx b/src/apps/officer-web/App.tsx index 2528980f..64439afa 100644 --- a/src/apps/officer-web/App.tsx +++ b/src/apps/officer-web/App.tsx @@ -50,8 +50,6 @@ export function App() { /> } /> } /> - } /> - } /> } /> } /> } /> diff --git a/src/apps/officer-web/Screens/Dashboard/Automation/AutomationDetail.tsx b/src/apps/officer-web/Screens/Dashboard/Automation/AutomationDetail.tsx deleted file mode 100644 index e6ba8d25..00000000 --- a/src/apps/officer-web/Screens/Dashboard/Automation/AutomationDetail.tsx +++ /dev/null @@ -1,232 +0,0 @@ -import { useState, useEffect } from 'react'; -import { useQuery, useQueryClient } from '@tanstack/react-query'; -import { toast } from 'sonner'; -import ReactMarkdown from 'react-markdown'; -import remarkGfm from 'remark-gfm'; -import rehypeRaw from 'rehype-raw'; -import { Play, Trash2, Terminal, Bot, Workflow } from 'lucide-react'; -import { Button } from '@/components/ui/button'; -import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogDescription } from '@/components/ui/dialog'; -import { useClient } from 'hooks/useClient'; -import { usePanelChannel } from 'hooks/usePanelChannel'; -import { Card } from '@/components/Card'; -import { TaskRunnerModal } from 'officerdev'; -import type { TaskSummary } from 'officerdev'; - -type TaskDetail = { - dirName: string; - name: string; - description: string; - mode: string; - language: string | null; - body: string | null; - inputs: Record | null; - config: { steps?: Array<{ task: string; foreach?: string }> } | null; - version: number | null; -}; - -const modeLabels: Record = { - script: { label: 'Script', icon: Terminal, color: 'bg-emerald-500/10 text-emerald-600' }, - agentic: { label: 'Agentic', icon: Bot, color: 'bg-violet-500/10 text-violet-600' }, - pipeline: { label: 'Pipeline', icon: Workflow, color: 'bg-amber-500/10 text-amber-600' }, -}; - -export const AutomationDetail = () => { - const client = useClient(); - const qc = useQueryClient(); - const [selected, setSelected] = usePanelChannel('automation:selected-task', null); - const [deleteConfirm, setDeleteConfirm] = useState(false); - const [runTask, setRunTask] = useState(null); - - // Reset delete confirm when selection changes - useEffect(() => { - setDeleteConfirm(false); - }, [selected?.dirName]); - - const { data: detail } = useQuery({ - queryKey: ['tasks', selected?.dirName], - queryFn: () => client.get(`/tasks/${selected!.dirName}`), - enabled: !!selected?.dirName, - }); - - const handleDelete = async () => { - if (!selected) return; - try { - await client.delete(`/tasks/${selected.dirName}`); - await qc.invalidateQueries({ queryKey: ['tasks'] }); - setDeleteConfirm(false); - setSelected(null); - toast.success('Automation deleted'); - } catch { - toast.error('Failed to delete automation'); - } - }; - - if (!selected) { - return ( -
-

Select an automation to view details

-
- ); - } - - const mode = modeLabels[selected.mode] ?? modeLabels.agentic!; - const ModeIcon = mode.icon; - - const hasSteps = detail?.config?.steps && detail.config.steps.length > 0; - const hasInputs = detail?.inputs && Object.keys(detail.inputs).length > 0; - - return ( - <> - - {/* Header */} -
- - {detail?.name ?? selected.name} - - - - {mode.label} - - - -
- - {/* Content */} -
- {/* Description */} - {detail?.description && ( -

{detail.description}

- )} - - {/* Meta badges */} -
- {detail?.language && ( - - {detail.language} - - )} - {detail?.version && ( - - v{detail.version} - - )} -
- - {/* Pipeline steps */} - {hasSteps && ( -
-

- Pipeline Steps -

-
- {detail!.config!.steps!.map((step, i) => ( -
- - {i + 1} - - {step.task} - {step.foreach && ( - - (foreach: {step.foreach}) - - )} -
- ))} -
-
- )} - - {/* Inputs */} - {hasInputs && ( -
-

- Inputs -

-
- {Object.entries(detail!.inputs!).map(([key, def]) => { - const d = def as { type?: string; description?: string; default?: string }; - return ( -
- {key} - {d.type && ( - {d.type} - )} - {d.description && ( - - {d.description} - - )} -
- ); - })} -
-
- )} - - {/* Body (agent instructions) */} - {detail?.body ? ( -
- - {detail.body} - -
- ) : detail && !hasSteps ? ( -

No instructions

- ) : null} -
-
- - {/* Delete confirmation */} - - - - Delete Automation - - Are you sure you want to delete "{selected.name}"? This cannot be undone. - - -
- - -
-
-
- - {/* Run modal */} - {runTask && ( - { - if (!open) setRunTask(null); - }} - task={runTask} - /> - )} - - ); -}; diff --git a/src/apps/officer-web/Screens/Dashboard/Automation/AutomationList.tsx b/src/apps/officer-web/Screens/Dashboard/Automation/AutomationList.tsx deleted file mode 100644 index b0a69b8b..00000000 --- a/src/apps/officer-web/Screens/Dashboard/Automation/AutomationList.tsx +++ /dev/null @@ -1,202 +0,0 @@ -import { useState } from 'react'; -import { useQuery, useQueryClient } from '@tanstack/react-query'; -import { toast } from 'sonner'; -import { Plus, Search, Play, Terminal, Bot, Workflow } from 'lucide-react'; -import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogDescription } from '@/components/ui/dialog'; -import { Button } from '@/components/ui/button'; -import { useClient } from 'hooks/useClient'; -import { usePanelChannel } from 'hooks/usePanelChannel'; -import { TaskRunnerModal } from 'officerdev'; -import type { TaskSummary } from 'officerdev'; - -const modeIcons = { - script: Terminal, - agentic: Bot, - pipeline: Workflow, -} as const; - -const modeColors = { - script: 'bg-emerald-500/10 text-emerald-600', - agentic: 'bg-violet-500/10 text-violet-600', - pipeline: 'bg-amber-500/10 text-amber-600', -} as const; - -export const AutomationList = () => { - const client = useClient(); - const qc = useQueryClient(); - const [selected, setSelected] = usePanelChannel('automation:selected-task', null); - const [search, setSearch] = useState(''); - const [showCreate, setShowCreate] = useState(false); - const [createName, setCreateName] = useState(''); - const [createDesc, setCreateDesc] = useState(''); - const [creating, setCreating] = useState(false); - const [runTask, setRunTask] = useState(null); - - const { data: tasks = [] } = useQuery({ - queryKey: ['tasks'], - queryFn: () => client.get('/tasks'), - staleTime: 60_000, - }); - - const q = search.toLowerCase(); - const filtered = search - ? tasks.filter((t) => t.name.toLowerCase().includes(q) || t.description?.toLowerCase().includes(q)) - : tasks; - - const handleCreate = async () => { - const name = createName.trim(); - if (!name) return; - setCreating(true); - try { - await client.post('/tasks', { name, description: createDesc.trim() || undefined }); - await qc.invalidateQueries({ queryKey: ['tasks'] }); - setShowCreate(false); - setCreateName(''); - setCreateDesc(''); - toast.success('Automation created'); - } catch { - toast.error('Failed to create automation'); - } finally { - setCreating(false); - } - }; - - return ( - <> -
- {/* Header */} -
- Automations - -
- - {/* Search */} -
-
- - setSearch(ev.target.value)} - placeholder="Search..." - className="w-full rounded border border-duck-dark/15 dark:border-foreground/15 bg-background/80 pl-7 pr-2 py-1.5 text-sm text-duck-dark dark:text-foreground placeholder:text-duck-dark/30 dark:placeholder:text-foreground/30 focus:outline-none focus:ring-1 focus:ring-duck-teal/30" - /> -
-
- - {/* Task list */} -
-
- {filtered.map((task) => { - const ModeIcon = modeIcons[task.mode] ?? Bot; - const modeColor = modeColors[task.mode] ?? modeColors.agentic; - const isSelected = selected?.dirName === task.dirName; - return ( -
- - -
- ); - })} - {tasks.length === 0 && ( -

- No automations yet -

- )} - {tasks.length > 0 && filtered.length === 0 && ( -

- No matches -

- )} -
-
-
- - {/* Create dialog */} - - - - Create Automation - Give your automation a name and optional description. - -
{ ev.preventDefault(); handleCreate(); }} - className="flex flex-col gap-3 mt-1" - > -
- - setCreateName(ev.target.value)} - placeholder="e.g. Batch Resize Images" - autoFocus - className="rounded border border-duck-dark/20 dark:border-foreground/20 bg-background px-3 py-2 text-sm text-duck-dark dark:text-foreground placeholder:text-duck-dark/30 dark:placeholder:text-foreground/30 focus:outline-none focus:ring-1 focus:ring-duck-teal/30" - /> -
-
- -