Canvas: Preview tab
Change-Id: I8a66cd977db5864828ad7ba9025270d624143091
diff --git a/apps/canvas/front/src/App.tsx b/apps/canvas/front/src/App.tsx
index 711b076..5100576 100644
--- a/apps/canvas/front/src/App.tsx
+++ b/apps/canvas/front/src/App.tsx
@@ -10,6 +10,7 @@
import { ChatManager } from "./components/ChatManager";
import { useAgents } from "./lib/state";
import { Bot } from "lucide-react";
+import { Preview } from "./components/preview";
export default function App() {
return (
@@ -30,6 +31,7 @@
<div className="flex justify-between border-b">
<TabsList className="!rounded-none">
<TabsTrigger value="build">Build</TabsTrigger>
+ <TabsTrigger value="preview">Preview</TabsTrigger>
<TabsTrigger value="monitoring">Monitoring</TabsTrigger>
<TabsTrigger value="config">Config</TabsTrigger>
<TabsTrigger value="integrations">Integrations</TabsTrigger>
@@ -51,6 +53,9 @@
<TabsContent value="build" className="!mt-0 flex-1 min-h-0">
<Build />
</TabsContent>
+ <TabsContent value="preview" className="!mt-0 flex-1 min-h-0">
+ <Preview />
+ </TabsContent>
<TabsContent value="config" className="!mt-0 flex-1 min-h-0">
<Config />
</TabsContent>
diff --git a/apps/canvas/front/src/components/preview.tsx b/apps/canvas/front/src/components/preview.tsx
new file mode 100644
index 0000000..f5ae9cf
--- /dev/null
+++ b/apps/canvas/front/src/components/preview.tsx
@@ -0,0 +1,64 @@
+import { useMemo, useState } from "react";
+import { useEnv, useLeadAgent } from "@/lib/state";
+import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "./ui/select";
+import { Button } from "./ui/button";
+import { RefreshCw } from "lucide-react";
+import { Agent } from "@/Agent";
+import { ResizableHandle, ResizablePanel, ResizablePanelGroup } from "@/components/ui/resizable";
+
+export function Preview() {
+ const leadAgent = useLeadAgent();
+ if (leadAgent == null) {
+ return <PreviewImpl />;
+ }
+ return (
+ <ResizablePanelGroup direction="horizontal" className="h-full">
+ <ResizablePanel defaultSize={25}>
+ <div className="p-4 h-full">
+ {leadAgent ? <Agent agent={leadAgent} /> : <div>No agent available</div>}
+ </div>
+ </ResizablePanel>
+ <ResizableHandle withHandle />
+ <ResizablePanel>
+ <PreviewImpl />
+ </ResizablePanel>
+ </ResizablePanelGroup>
+ );
+}
+
+function PreviewImpl() {
+ const env = useEnv();
+ const httpsAccess = useMemo(() => env.access.filter((a) => a.type === "https"), [env]);
+ const [selectedUrl, setSelectedUrl] = useState<string | null>(null);
+ const [refreshKey, setRefreshKey] = useState(0);
+ return (
+ <div className="w-full h-full flex flex-col">
+ <div className="p-4 border-b flex items-center gap-2">
+ <Select onValueChange={setSelectedUrl}>
+ <SelectTrigger className="w-[300px]">
+ <SelectValue placeholder="Select a gateway" />
+ </SelectTrigger>
+ <SelectContent>
+ {httpsAccess.map((a) => (
+ <SelectItem key={a.address} value={a.address}>
+ {a.address}
+ </SelectItem>
+ ))}
+ </SelectContent>
+ </Select>
+ <Button variant="outline" size="icon" onClick={() => setRefreshKey((prev) => prev + 1)}>
+ <RefreshCw className="h-4 w-4" />
+ </Button>
+ </div>
+ <div className="flex-1">
+ {selectedUrl ? (
+ <iframe key={refreshKey} src={selectedUrl} className="w-full h-full border-0" />
+ ) : (
+ <div className="flex items-center justify-center h-full">
+ <p>Select a gateway to preview</p>
+ </div>
+ )}
+ </div>
+ </div>
+ );
+}