From 0f1b313272ea66e9acd29cec6d39af5b696b1a50 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=9B=B7=E7=94=B5=E8=8A=BD=E8=A1=A3?= Date: Thu, 16 Apr 2026 22:06:39 -0400 Subject: [PATCH] refactor(execution): split ApprovalInspector 346-line god-component Decompose monolithic src/renderer/components/execution/ApprovalInspector.tsx into src/renderer/components/execution/approval-inspector/: - ApprovalInspector.tsx (168 lines, orchestrator only) - ApprovalSummary.tsx, ProposedHireCard.tsx, ApprovalDocumentsPanel.tsx - DeliverableReviewPanel.tsx, SchedulePicker.tsx, DecisionForm.tsx - TypeBadge.tsx, useApprovalPayload.ts, index.ts (barrel) Hoist JSON.parse out of JSX IIFE into useApprovalPayload hook with typed return. Replace roll-your-own role=radio spans with native input[type=radio]. Extract getTypeBadgeClass switch into TypeBadge component. Update execution.tsx barrel to re-export from new path. Business logic preserved: approval decision flow, schedule validation, deliverable review, document editing, delete confirmation. --- src/renderer/components/execution.tsx | 2 +- .../execution/ApprovalInspector.tsx | 346 ------------------ .../ApprovalDocumentsPanel.tsx | 138 +++++++ .../approval-inspector/ApprovalInspector.tsx | 168 +++++++++ .../approval-inspector/ApprovalSummary.tsx | 52 +++ .../approval-inspector/DecisionForm.tsx | 79 ++++ .../DeliverableReviewPanel.tsx | 112 ++++++ .../approval-inspector/ProposedHireCard.tsx | 93 +++++ .../approval-inspector/SchedulePicker.tsx | 77 ++++ .../approval-inspector/TypeBadge.tsx | 16 + .../execution/approval-inspector/index.ts | 1 + .../approval-inspector/useApprovalPayload.ts | 26 ++ 12 files changed, 763 insertions(+), 347 deletions(-) delete mode 100644 src/renderer/components/execution/ApprovalInspector.tsx create mode 100644 src/renderer/components/execution/approval-inspector/ApprovalDocumentsPanel.tsx create mode 100644 src/renderer/components/execution/approval-inspector/ApprovalInspector.tsx create mode 100644 src/renderer/components/execution/approval-inspector/ApprovalSummary.tsx create mode 100644 src/renderer/components/execution/approval-inspector/DecisionForm.tsx create mode 100644 src/renderer/components/execution/approval-inspector/DeliverableReviewPanel.tsx create mode 100644 src/renderer/components/execution/approval-inspector/ProposedHireCard.tsx create mode 100644 src/renderer/components/execution/approval-inspector/SchedulePicker.tsx create mode 100644 src/renderer/components/execution/approval-inspector/TypeBadge.tsx create mode 100644 src/renderer/components/execution/approval-inspector/index.ts create mode 100644 src/renderer/components/execution/approval-inspector/useApprovalPayload.ts diff --git a/src/renderer/components/execution.tsx b/src/renderer/components/execution.tsx index f613a716..f56aa33d 100644 --- a/src/renderer/components/execution.tsx +++ b/src/renderer/components/execution.tsx @@ -3,7 +3,7 @@ export { TaskQueue } from "./execution/TaskQueue" export { TaskInspector } from "./execution/TaskInspector" export { TaskCreator } from "./execution/TaskCreator" export { ApprovalList } from "./execution/ApprovalList" -export { ApprovalInspector } from "./execution/ApprovalInspector" +export { ApprovalInspector } from "./execution/approval-inspector" export { ActivityList } from "./execution/ActivityList" export { CostList } from "./execution/CostList" export { BudgetSummary } from "./execution/BudgetSummary" diff --git a/src/renderer/components/execution/ApprovalInspector.tsx b/src/renderer/components/execution/ApprovalInspector.tsx deleted file mode 100644 index 713ce2fc..00000000 --- a/src/renderer/components/execution/ApprovalInspector.tsx +++ /dev/null @@ -1,346 +0,0 @@ -import { useMemo, useState } from "react" -import { Briefcase, CheckCircle, Clock, ClockCounterClockwise, Robot, Trash, XCircle } from "@phosphor-icons/react" -import { CaretDown, CaretUp } from "@phosphor-icons/react" -import type { AgentRecord, ApprovalRecord, DocumentRecord, TaskRecord } from "@shared/types" -import { extractApprovalDocumentReferences, type ApprovalDocumentReference } from "@shared/approval-documents" -import { useT } from "../../i18n" -import { formatMoney, formatTime } from "../../lib/formatters" -import { unwrap } from "../../lib/desktop" -import { ActionButton, ConfirmDialog, InlineNotice, Input, StatusPill, TextArea } from "../ui" -import { describeActionError, parseApprovalPayloadJson } from "./execution-utils" -import { SocialDraftPreview } from "./SocialDraftPreview" -import { useAppStore } from "../../state/store" - -function getTypeBadgeClass(type: string): string { - if (type === "hire_agent") return "bg-accent text-primary" - if (type === "approve_ceo_strategy") return "bg-warning-muted text-warning" - if (type === "secret_access") return "bg-destructive-muted text-destructive" - if (type === "social_post") return "bg-accent text-primary" - if (type === "deliverable_review") return "bg-accent text-primary" - return "bg-muted text-muted-foreground" -} - -function ApprovalDocumentEditor({ - companyId, - document, - fallback, -}: { - companyId: string - document: DocumentRecord - fallback?: ApprovalDocumentReference -}) { - const addToast = useAppStore((s) => s.addToast) - const [title, setTitle] = useState(document.title) - const [content, setContent] = useState(document.content ?? "") - const [saving, setSaving] = useState(false) - const [saveError, setSaveError] = useState(null) - - async function handleSave() { - if (!title.trim()) { - setSaveError("Document title is required.") - return - } - setSaving(true) - setSaveError(null) - try { - unwrap(await window.agentCompany.saveDocument({ - id: document.id, - companyId, - type: document.type, - title: title.trim(), - content, - authorAgentId: document.authorAgentId ?? null, - reviewerAgentId: document.reviewerAgentId ?? null, - projectId: document.projectId ?? null, - goalId: document.goalId ?? null, - parentDocId: document.parentDocId ?? null, - version: document.version, - status: document.status, - tagsJson: document.tagsJson, - })) - addToast(`Saved document: ${title.trim()}`, "success") - } catch (error) { - setSaveError(describeActionError(error)) - } finally { - setSaving(false) - } - } - - return ( -
-
-
-
{fallback?.title ?? document.title}
-
{(fallback?.type ?? document.type).replaceAll("_", " ")} · v{document.version} · {document.status}
-
- void handleSave()} loading={saving} /> -
- {saveError ? : null} - -