feat: add agents management and enhance inspector with typed forms

- Introduced a new "Agents" section in the app sidebar for better navigation.
- Enhanced the Inspector component to support typed forms for various node types, improving user experience when configuring nodes.
- Created a new NodeForm component to handle specific forms for different node types, including Trigger, Build, Test, Eval, Policy, Approval, Deploy, Promote, and Rollback.
- Updated the API layer to manage agents, including listing, creating, deleting, and testing agent authentication.
- Modified the node catalog to include new node types and their respective configurations.
- Adjusted the Next.js configuration and Nginx settings to reflect changes in API endpoint ports.
This commit is contained in:
patel-lyzr
2026-05-13 22:15:08 +05:30
parent 64a857d1b7
commit 0a1874e736
21 changed files with 3175 additions and 117 deletions
+66 -16
View File
@@ -1,7 +1,7 @@
"use client";
import { useEffect, useState } from "react";
import { Trash2 } from "lucide-react";
import { ChevronDown, ChevronRight, Trash2 } from "lucide-react";
import { Button } from "@/components/ui/button";
import { Input } from "@/components/ui/input";
import { Label } from "@/components/ui/label";
@@ -9,6 +9,7 @@ import { Textarea } from "@/components/ui/textarea";
import { Badge } from "@/components/ui/badge";
import { lookup } from "@/lib/node-catalog";
import type { PipelineNode } from "@/lib/pipeline-graph";
import { NodeForm, hasTypedForm } from "./node-form";
interface InspectorProps {
node: PipelineNode | null;
@@ -21,14 +22,22 @@ export function Inspector({ node, onChange, onDelete, onClose }: InspectorProps)
const [name, setName] = useState("");
const [paramsText, setParamsText] = useState("{}");
const [paramsErr, setParamsErr] = useState<string | null>(null);
const [showJSON, setShowJSON] = useState(false);
useEffect(() => {
if (!node) return;
setName(node.name);
setParamsText(JSON.stringify(node.parameters ?? {}, null, 2));
setParamsErr(null);
setShowJSON(false);
}, [node?.id]); // eslint-disable-line react-hooks/exhaustive-deps
// Keep the JSON textarea in sync when typed-form edits change parameters.
useEffect(() => {
if (!node) return;
setParamsText(JSON.stringify(node.parameters ?? {}, null, 2));
}, [node?.parameters]); // eslint-disable-line react-hooks/exhaustive-deps
if (!node) {
return (
<aside className="w-80 shrink-0 border-l bg-muted/20 p-4 text-sm text-muted-foreground">
@@ -38,6 +47,7 @@ export function Inspector({ node, onChange, onDelete, onClose }: InspectorProps)
}
const entry = lookup(node.type);
const typed = hasTypedForm(node.type);
function commitName(next: string) {
if (!node) return;
@@ -89,21 +99,61 @@ export function Inspector({ node, onChange, onDelete, onClose }: InspectorProps)
</p>
</div>
<div className="space-y-1.5">
<Label htmlFor="node-params">Parameters (JSON)</Label>
<Textarea
id="node-params"
value={paramsText}
onChange={(e) => setParamsText(e.target.value)}
onBlur={() => commitParams(paramsText)}
rows={14}
spellCheck={false}
className="text-xs"
/>
{paramsErr && (
<p className="text-[11px] text-destructive">{paramsErr}</p>
)}
</div>
{typed ? (
<div className="space-y-3 rounded-md border bg-background p-3">
<NodeForm node={node} onChange={onChange} />
</div>
) : (
<div className="space-y-1.5">
<Label htmlFor="node-params">Parameters (JSON)</Label>
<Textarea
id="node-params"
value={paramsText}
onChange={(e) => setParamsText(e.target.value)}
onBlur={() => commitParams(paramsText)}
rows={14}
spellCheck={false}
className="text-xs"
/>
{paramsErr && (
<p className="text-[11px] text-destructive">{paramsErr}</p>
)}
</div>
)}
{typed && (
<div className="rounded-md border bg-background">
<button
type="button"
className="flex w-full items-center justify-between gap-2 px-3 py-2 text-xs font-medium hover:bg-accent"
onClick={() => setShowJSON((v) => !v)}
>
<span className="flex items-center gap-1 text-muted-foreground">
{showJSON ? (
<ChevronDown className="size-3.5" />
) : (
<ChevronRight className="size-3.5" />
)}
Raw JSON
</span>
</button>
{showJSON && (
<div className="border-t p-2">
<Textarea
value={paramsText}
onChange={(e) => setParamsText(e.target.value)}
onBlur={() => commitParams(paramsText)}
rows={10}
spellCheck={false}
className="text-[11px]"
/>
{paramsErr && (
<p className="mt-1 text-[11px] text-destructive">{paramsErr}</p>
)}
</div>
)}
</div>
)}
{entry && (
<div className="rounded-md border bg-background p-2 text-[11px] text-muted-foreground">