From da14be3443d542babe71b77cdd50acebb516b66e 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, 28 May 2026 22:41:09 -0400 Subject: [PATCH] Add approval detail review and fix the declined-row icon --- .../src/renderer/src/pages/ApprovalsPage.tsx | 81 +++++++++++++++++-- 1 file changed, 75 insertions(+), 6 deletions(-) diff --git a/AgentCompany-New/src/renderer/src/pages/ApprovalsPage.tsx b/AgentCompany-New/src/renderer/src/pages/ApprovalsPage.tsx index 859470b2..e6926112 100644 --- a/AgentCompany-New/src/renderer/src/pages/ApprovalsPage.tsx +++ b/AgentCompany-New/src/renderer/src/pages/ApprovalsPage.tsx @@ -1,5 +1,5 @@ import { useMemo, useState } from "react"; -import { Avatar, Button, Icon, Pill } from "../shared/ui"; +import { Avatar, Button, Icon, IconButton, Pill } from "../shared/ui"; import { TopbarActions } from "../shared/TopbarActions"; import type { AgentRecord, @@ -30,6 +30,7 @@ export function ApprovalsPage({ snapshot, actions }: PageProps) { const orgId = activeOrgId(snapshot); const employee = requireActiveEmployee(snapshot); const [filter, setFilter] = useState("all"); + const [editingId, setEditingId] = useState(null); const approvals = useMemo(() => snapshot.approvals.filter((item) => item.orgId === orgId), [snapshot.approvals, orgId]); const employees = snapshot.employees.filter((item) => item.orgId === orgId); @@ -43,13 +44,17 @@ export function ApprovalsPage({ snapshot, actions }: PageProps) { const declined7d = weeklyDecided.filter((approval) => approval.state === APPROVAL_STATE.DECLINED).length; const medianTime = computeMedianMinutes(weeklyDecided); - const decide = (approval: ApprovalRecord, state: "approved" | "declined") => + const editing = editingId ? approvals.find((approval) => approval.id === editingId) ?? null : null; + + const decide = (approval: ApprovalRecord, state: "approved" | "declined") => { + setEditingId(null); void actions.run(() => window.agentCompany.decideApproval({ orgId, approvalId: approval.id, state, decidedByEmployeeId: employee.id, })); + }; const approveAllLowRisk = () => { const lows = filteredPending.filter((approval) => approval.risk === RISK_LEVEL.LOW); @@ -83,6 +88,7 @@ export function ApprovalsPage({ snapshot, actions }: PageProps) { isBot={approval.requestedByType === "agent"} onApprove={() => decide(approval, "approved")} onDecline={() => decide(approval, "declined")} + onEdit={() => setEditingId(approval.id)} /> ))} @@ -102,10 +108,70 @@ export function ApprovalsPage({ snapshot, actions }: PageProps) { )} + + setEditingId(null)} + onApprove={() => editing && decide(editing, "approved")} + onDecline={() => editing && decide(editing, "declined")} + /> ); } +function ApprovalDetailDialog({ + approval, + requester, + onClose, + onApprove, + onDecline, +}: { + approval: ApprovalRecord | null; + requester: string; + onClose: () => void; + onApprove: () => void; + onDecline: () => void; +}) { + if (!approval) return null; + const tone = RISK_TONES[approval.risk]; + if (!tone) throw new Error("Approval risk tone is missing."); + return ( +
+
event.stopPropagation()}> +
+

{approval.title}

+ +
+
+ {tone.label} + ยท + {approval.kind} +
+

+ {approval.details} +

+
+ Requested by + {requester} + {approval.sourceEntityType && (<>Source{humanizeKind(approval.sourceEntityType)})} + Requested + {formatRelative(approval.createdAt)} +
+
+ + +
+
+
+ ); +} + +function humanizeKind(value: string): string { + const spaced = value.replace(/_/g, " "); + return spaced.charAt(0).toUpperCase() + spaced.slice(1); +} + function RiskMenu({ filter, onChange }: { filter: RiskFilter; onChange: (next: RiskFilter) => void }) { return (