- Updated the build script in `build-release.ts` to set `NODE_ENV` and `VITE_USER_NODE_ENV` to production, ensuring proper environment configuration. - Refined the styling of various components including `approvals-view.tsx`, `dashboard/view.tsx`, `tasks-view.tsx`, and others to improve visual consistency with rounded borders and adjusted background colors. - Enhanced the `PendingApprovalRow` and `PoliciesPanel` components for better user interaction and layout.
Unified · Split
| @@ -5,7 +5,7 @@ · 4 unmodified lines | |||
| 5 | "scripts": { | 5 | "scripts": { |
| 6 | "with-env": "bun run --env-file=../../../.env --", | 6 | "with-env": "bun run --env-file=../../../.env --", |
| 7 | "dev": "bun with-env vite dev --port 4312", | 7 | "dev": "bun with-env vite dev --port 4312", |
| 8 | "build": "bun with-env vite build", | 8 | "build": "NODE_ENV=production bun with-env vite build --mode production", |
| 9 | "start": "bun with-env env PORT=5312 HOSTNAME=127.0.0.1 node dist/server/server.mjs", | 9 | "start": "bun with-env env PORT=5312 HOSTNAME=127.0.0.1 node dist/server/server.mjs", |
| 10 | "lint": "eslint", | 10 | "lint": "eslint", |
| 11 | "typecheck": "bunx --package @typescript/native-preview tsgo --noEmit -p tsconfig.json", | 11 | "typecheck": "bunx --package @typescript/native-preview tsgo --noEmit -p tsconfig.json", |
| @@ -67,7 +67,7 @@ function ApprovalCard({ · 66 unmodified lines | |||
| 67 | ); | 67 | ); |
| 68 | 68 | ||
| 69 | return ( | 69 | return ( |
| 70 | <Card className="bg-card border-border border-l-2 border-l-terminal-amber glow-amber"> | 70 | <Card className="rounded-none bg-card/40 border-border/50 border-l-2 border-l-terminal-amber glow-amber"> |
| 71 | <CardContent className="p-4 space-y-3"> | 71 | <CardContent className="p-4 space-y-3"> |
| 72 | {/* Header */} | 72 | {/* Header */} |
| 73 | <div className="flex items-start justify-between gap-3"> | 73 | <div className="flex items-start justify-between gap-3"> |
| @@ -180,7 +180,7 @@ export function ApprovalsView() { · 106 unmodified lines | |||
| 180 | ))} | 180 | ))} |
| 181 | </div> | 181 | </div> |
| 182 | ) : count === 0 ? ( | 182 | ) : count === 0 ? ( |
| 183 | <Card className="bg-card border-border flex-1"> | 183 | <Card className="rounded-none bg-card/40 border-border/50 flex-1"> |
| 184 | <CardContent className="flex flex-col items-center justify-center py-20 gap-3"> | 184 | <CardContent className="flex flex-col items-center justify-center py-20 gap-3"> |
| 185 | <div className="h-12 w-12 rounded-full bg-terminal-green/10 flex items-center justify-center"> | 185 | <div className="h-12 w-12 rounded-full bg-terminal-green/10 flex items-center justify-center"> |
| 186 | <CheckCircle2 className="h-6 w-6 text-terminal-green/60" /> | 186 | <CheckCircle2 className="h-6 w-6 text-terminal-green/60" /> |
| @@ -11,7 +11,7 @@ function PendingApprovalRow({ approval }: { approval: PendingApprovalRecord }) { · 10 unmodified lines | |||
| 11 | return ( | 11 | return ( |
| 12 | <button | 12 | <button |
| 13 | onClick={() => navigate("/approvals")} | 13 | onClick={() => navigate("/approvals")} |
| 14 | className="w-full flex items-center gap-3 px-3 py-2.5 rounded-md hover:bg-accent/50 transition-colors text-left group" | 14 | className="group flex w-full items-center gap-3 px-3 py-2.5 text-left transition-colors hover:bg-accent/20" |
| 15 | > | 15 | > |
| 16 | <div className="h-2 w-2 rounded-full bg-terminal-amber pulse-dot shrink-0" /> | 16 | <div className="h-2 w-2 rounded-full bg-terminal-amber pulse-dot shrink-0" /> |
| 17 | <div className="flex-1 min-w-0"> | 17 | <div className="flex-1 min-w-0"> |
| @@ -33,7 +33,7 @@ export function DashboardPendingApprovalsCard({ · 15 unmodified lines | |||
| 33 | const navigate = useNavigate(); | 33 | const navigate = useNavigate(); |
| 34 | 34 | ||
| 35 | return ( | 35 | return ( |
| 36 | <Card className="bg-card border-border"> | 36 | <Card className="rounded-none border-border/50 bg-card/40"> |
| 37 | <CardHeader className="pb-3"> | 37 | <CardHeader className="pb-3"> |
| 38 | <div className="flex items-center justify-between"> | 38 | <div className="flex items-center justify-between"> |
| 39 | <CardTitle className="text-sm font-medium flex items-center gap-2"> | 39 | <CardTitle className="text-sm font-medium flex items-center gap-2"> |
| @@ -63,7 +63,7 @@ export function DashboardPendingApprovalsCard({ · 23 unmodified lines | |||
| 63 | No pending approvals | 63 | No pending approvals |
| 64 | </div> | 64 | </div> |
| 65 | ) : ( | 65 | ) : ( |
| 66 | <div className="space-y-0.5"> | 66 | <div className="divide-y divide-border/30"> |
| 67 | {approvals.map((approval) => ( | 67 | {approvals.map((approval) => ( |
| 68 | <PendingApprovalRow key={approval.id} approval={approval} /> | 68 | <PendingApprovalRow key={approval.id} approval={approval} /> |
| 69 | ))} | 69 | ))} |
| @@ -46,7 +46,7 @@ export function DashboardView() { · 45 unmodified lines | |||
| 46 | /> | 46 | /> |
| 47 | )} | 47 | )} |
| 48 | 48 | ||
| 49 | <Card id="mcp-setup" className="bg-card border-border min-h-0 flex flex-col"> | 49 | <Card id="mcp-setup" className="rounded-none bg-card/40 border-border/50 min-h-0 flex flex-col"> |
| 50 | <CardHeader className="pb-3"> | 50 | <CardHeader className="pb-3"> |
| 51 | <CardTitle className="text-sm font-medium flex items-center gap-2"> | 51 | <CardTitle className="text-sm font-medium flex items-center gap-2"> |
| 52 | <Server className="h-4 w-4 text-primary" /> | 52 | <Server className="h-4 w-4 text-primary" /> |
| @@ -77,7 +77,7 @@ export function TasksView() { · 76 unmodified lines | |||
| 77 | 77 | ||
| 78 | <div className="flex min-h-0 flex-1 flex-col"> | 78 | <div className="flex min-h-0 flex-1 flex-col"> |
| 79 | <div className="grid h-full min-h-0 gap-6 lg:grid-cols-[minmax(360px,440px)_1fr]"> | 79 | <div className="grid h-full min-h-0 gap-6 lg:grid-cols-[minmax(360px,440px)_1fr]"> |
| 80 | <Card className="bg-card border-border min-h-0 flex flex-col"> | 80 | <Card className="rounded-none bg-card/40 border-border/50 min-h-0 flex flex-col"> |
| 81 | <CardHeader className="pb-3"> | 81 | <CardHeader className="pb-3"> |
| 82 | <CardTitle className="text-sm font-medium flex items-center gap-2"> | 82 | <CardTitle className="text-sm font-medium flex items-center gap-2"> |
| 83 | Task History | 83 | Task History |
| @@ -126,7 +126,7 @@ export function TasksView() { · 42 unmodified lines | |||
| 126 | onClose={() => selectTask(null)} | 126 | onClose={() => selectTask(null)} |
| 127 | /> | 127 | /> |
| 128 | ) : ( | 128 | ) : ( |
| 129 | <Card className="bg-card border-border h-full"> | 129 | <Card className="rounded-none bg-card/40 border-border/50 h-full"> |
| 130 | <CardContent className="flex items-center justify-center py-24"> | 130 | <CardContent className="flex items-center justify-center py-24"> |
| 131 | <p className="text-sm text-muted-foreground"> | 131 | <p className="text-sm text-muted-foreground"> |
| 132 | Select a task to view logs, output, and approval actions | 132 | Select a task to view logs, output, and approval actions |
| @@ -92,7 +92,7 @@ export function CredentialsPanel({ · 91 unmodified lines | |||
| 92 | }, [credentials]); | 92 | }, [credentials]); |
| 93 | 93 | ||
| 94 | return ( | 94 | return ( |
| 95 | <section className="mx-auto flex h-full min-h-0 w-full max-w-6xl flex-col border border-border/50 bg-card/40"> | 95 | <section className="mx-auto flex h-full min-h-0 w-full max-w-6xl flex-col rounded-none border border-border/50 bg-card/30"> |
| 96 | <div className="flex items-center justify-between border-b border-border/40 px-4 py-3 sm:px-5"> | 96 | <div className="flex items-center justify-between border-b border-border/40 px-4 py-3 sm:px-5"> |
| 97 | <div className="flex items-center gap-2"> | 97 | <div className="flex items-center gap-2"> |
| 98 | <div className="flex h-7 w-7 items-center justify-center border border-border/60 bg-background/80"> | 98 | <div className="flex h-7 w-7 items-center justify-center border border-border/60 bg-background/80"> |
| @@ -140,6 +140,7 @@ export function CredentialsPanel({ · 41 unmodified lines | |||
| 140 | <div | 140 | <div |
| 141 | key={connection.key} | 141 | key={connection.key} |
| 142 | className="group flex items-center gap-3 border border-border/50 bg-background/70 px-3 py-2.5 transition-colors hover:border-border hover:bg-accent/20" | 142 | className="group flex items-center gap-3 border border-border/50 bg-background/70 px-3 py-2.5 transition-colors hover:border-border hover:bg-accent/20" |
| 143 | style={{ boxShadow: "inset 2px 0 0 0 color-mix(in oklch, var(--border) 70%, transparent)" }} | ||
| 143 | > | 144 | > |
| 144 | <div className="flex h-8 w-8 shrink-0 items-center justify-center border border-border/60 bg-muted/50 overflow-hidden"> | 145 | <div className="flex h-8 w-8 shrink-0 items-center justify-center border border-border/60 bg-muted/50 overflow-hidden"> |
| 145 | {firstSource ? ( | 146 | {firstSource ? ( |
| @@ -336,17 +336,29 @@ export function ToolExplorer({ · 335 unmodified lines | |||
| 336 | }, [maybeLoadToolDetails, setFocusedSourceName]); | 336 | }, [maybeLoadToolDetails, setFocusedSourceName]); |
| 337 | 337 | ||
| 338 | const handleSourceClick = useCallback((sourceName: string) => { | 338 | const handleSourceClick = useCallback((sourceName: string) => { |
| 339 | const key = `source:${sourceName}`; | ||
| 340 | const wasFocused = focusedSourceName === sourceName; | ||
| 339 | const source = sourceByName.get(sourceName); | 341 | const source = sourceByName.get(sourceName); |
| 342 | |||
| 343 | if (wasFocused) { | ||
| 344 | setSourceFocusState(null, null); | ||
| 345 | setExpandedKeys((prev) => { | ||
| 346 | const next = new Set(prev); | ||
| 347 | next.delete(key); | ||
| 348 | return next; | ||
| 349 | }); | ||
| 350 | return; | ||
| 351 | } | ||
| 352 | |||
| 340 | setSourceFocusState(sourceName, source ?? null); | 353 | setSourceFocusState(sourceName, source ?? null); |
| 341 | // Ensure the source group is expanded | 354 | // Ensure the source group is expanded |
| 342 | setExpandedKeys((prev) => { | 355 | setExpandedKeys((prev) => { |
| 343 | const key = `source:${sourceName}`; | ||
| 344 | if (prev.has(key)) return prev; | 356 | if (prev.has(key)) return prev; |
| 345 | const next = new Set(prev); | 357 | const next = new Set(prev); |
| 346 | next.add(key); | 358 | next.add(key); |
| 347 | return next; | 359 | return next; |
| 348 | }); | 360 | }); |
| 349 | }, [sourceByName]); | 361 | }, [focusedSourceName, setSourceFocusState, sourceByName]); |
| 350 | 362 | ||
| 351 | const handleAddSource = useCallback(() => { | 363 | const handleAddSource = useCallback(() => { |
| 352 | setSourceFocusState(null, null); | 364 | setSourceFocusState(null, null); |
| @@ -748,7 +748,7 @@ function PolicyCard({ · 747 unmodified lines | |||
| 748 | const [showTools, setShowTools] = useState(false); | 748 | const [showTools, setShowTools] = useState(false); |
| 749 | 749 | ||
| 750 | return ( | 750 | return ( |
| 751 | <div className="group relative rounded-lg border border-border/60 bg-card hover:border-border transition-colors"> | 751 | <div className="group relative rounded-none border border-border/60 bg-card/60 hover:border-border transition-colors"> |
| 752 | <div className="px-3.5 py-2.5"> | 752 | <div className="px-3.5 py-2.5"> |
| 753 | {/* Header row */} | 753 | {/* Header row */} |
| 754 | <div className="flex items-start gap-2.5"> | 754 | <div className="flex items-start gap-2.5"> |
| @@ -1321,7 +1321,7 @@ export function PoliciesPanel({ · 566 unmodified lines | |||
| 1321 | ))} | 1321 | ))} |
| 1322 | </div> | 1322 | </div> |
| 1323 | ) : policies.length === 0 ? ( | 1323 | ) : policies.length === 0 ? ( |
| 1324 | <div className="rounded-lg border border-dashed border-border/50 py-10 flex flex-col items-center gap-2.5"> | 1324 | <div className="rounded-none border border-dashed border-border/50 py-10 flex flex-col items-center gap-2.5"> |
| 1325 | <Shield className="h-8 w-8 text-muted-foreground/30" /> | 1325 | <Shield className="h-8 w-8 text-muted-foreground/30" /> |
| 1326 | <div className="text-center"> | 1326 | <div className="text-center"> |
| 1327 | <p className="text-xs text-muted-foreground">No tool policies configured</p> | 1327 | <p className="text-xs text-muted-foreground">No tool policies configured</p> |
| @@ -1377,7 +1377,7 @@ export function PoliciesPanel({ · 49 unmodified lines | |||
| 1377 | 1377 | ||
| 1378 | <Separator className="bg-border/40" /> | 1378 | <Separator className="bg-border/40" /> |
| 1379 | 1379 | ||
| 1380 | <details className="group rounded-lg border border-border/60 bg-card/40"> | 1380 | <details className="group rounded-none border border-border/60 bg-card/30"> |
| 1381 | <summary className="flex cursor-pointer list-none items-center justify-between gap-3 px-3 py-2.5"> | 1381 | <summary className="flex cursor-pointer list-none items-center justify-between gap-3 px-3 py-2.5"> |
| 1382 | <div> | 1382 | <div> |
| 1383 | <h4 className="text-sm font-medium">Policy Set Manager</h4> | 1383 | <h4 className="text-sm font-medium">Policy Set Manager</h4> |
| @@ -1391,12 +1391,12 @@ export function PoliciesPanel({ · 7 unmodified lines | |||
| 1391 | 1391 | ||
| 1392 | <div className="px-3 pb-3"> | 1392 | <div className="px-3 pb-3"> |
| 1393 | {!canManageRoles ? ( | 1393 | {!canManageRoles ? ( |
| 1394 | <div className="rounded-lg border border-dashed border-border/50 p-4 text-xs text-muted-foreground"> | 1394 | <div className="rounded-none border border-dashed border-border/50 p-4 text-xs text-muted-foreground"> |
| 1395 | Organization owner/admin role required to manage tool policy sets. | 1395 | Organization owner/admin role required to manage tool policy sets. |
| 1396 | </div> | 1396 | </div> |
| 1397 | ) : ( | 1397 | ) : ( |
| 1398 | <div className="grid grid-cols-1 gap-4 lg:grid-cols-[280px_1fr]"> | 1398 | <div className="grid grid-cols-1 gap-4 lg:grid-cols-[280px_1fr]"> |
| 1399 | <div className="space-y-3 rounded-lg border border-border/60 bg-card p-3"> | 1399 | <div className="space-y-3 rounded-none border border-border/60 bg-card/50 p-3"> |
| 1400 | <Label className="text-xs text-muted-foreground">Create policy set</Label> | 1400 | <Label className="text-xs text-muted-foreground">Create policy set</Label> |
| 1401 | <Input | 1401 | <Input |
| 1402 | value={roleForm.name} | 1402 | value={roleForm.name} |
| @@ -1455,7 +1455,7 @@ export function PoliciesPanel({ · 52 unmodified lines | |||
| 1455 | </div> | 1455 | </div> |
| 1456 | </div> | 1456 | </div> |
| 1457 | 1457 | ||
| 1458 | <div className="space-y-4 rounded-lg border border-border/60 bg-card p-4"> | 1458 | <div className="space-y-4 rounded-none border border-border/60 bg-card/50 p-4"> |
| 1459 | {!selectedRole ? ( | 1459 | {!selectedRole ? ( |
| 1460 | <p className="text-xs text-muted-foreground">Select a policy set to manage its rules and assignments.</p> | 1460 | <p className="text-xs text-muted-foreground">Select a policy set to manage its rules and assignments.</p> |
| 1461 | ) : ( | 1461 | ) : ( |
| @@ -447,9 +447,11 @@ async function buildWebArtifact(rootDir: string, releaseDir: string, checksums: · 446 unmodified lines | |||
| 447 | EXECUTOR_WEB_CONVEX_SITE_URL: "http://127.0.0.1:5411", | 447 | EXECUTOR_WEB_CONVEX_SITE_URL: "http://127.0.0.1:5411", |
| 448 | VITE_CONVEX_URL: "http://127.0.0.1:5410", | 448 | VITE_CONVEX_URL: "http://127.0.0.1:5410", |
| 449 | VITE_CONVEX_SITE_URL: "http://127.0.0.1:5411", | 449 | VITE_CONVEX_SITE_URL: "http://127.0.0.1:5411", |
| 450 | NODE_ENV: "production", | ||
| 451 | VITE_USER_NODE_ENV: "production", | ||
| 450 | }; | 452 | }; |
| 451 | 453 | ||
| 452 | await runCommand(["bunx", "vite", "build"], { | 454 | await runCommand(["bunx", "vite", "build", "--mode", "production"], { |
| 453 | cwd: webAppDir, | 455 | cwd: webAppDir, |
| 454 | env: webBuildEnv, | 456 | env: webBuildEnv, |
| 455 | }); | 457 | }); |