feat: agent stream for cloudonix OPBX (#261)

* feat: agent stream for cloudonix OPBX

* feat: make cloudonix app name optional

* feat: create application while configuring telephony config

* fix: get telephony configuration from stamped workflow run

* fix: fix vobiz hangup URL
This commit is contained in:
Abhishek 2026-05-02 15:53:58 +05:30 committed by GitHub
parent 5cfdbeff02
commit 7fd3b96470
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
48 changed files with 1529 additions and 545 deletions

View file

@ -42,6 +42,7 @@ const edgeTypes = {
interface RenderWorkflowProps {
initialWorkflowName: string;
workflowId: number;
workflowUuid?: string;
initialFlow?: {
nodes: FlowNode[];
edges: FlowEdge[];
@ -58,7 +59,7 @@ interface RenderWorkflowProps {
user: { id: string; email?: string };
}
function RenderWorkflow({ initialWorkflowName, workflowId, initialFlow, initialTemplateContextVariables, initialWorkflowConfigurations, initialVersionNumber, initialVersionStatus, user }: RenderWorkflowProps) {
function RenderWorkflow({ initialWorkflowName, workflowId, workflowUuid, initialFlow, initialTemplateContextVariables, initialWorkflowConfigurations, initialVersionNumber, initialVersionStatus, user }: RenderWorkflowProps) {
const router = useRouter();
const [isPhoneCallDialogOpen, setIsPhoneCallDialogOpen] = useState(false);
const [isVersionPanelOpen, setIsVersionPanelOpen] = useState(false);
@ -303,6 +304,7 @@ function RenderWorkflow({ initialWorkflowName, workflowId, initialFlow, initialT
rfInstance={rfInstance}
onRun={onRun}
workflowId={workflowId}
workflowUuid={workflowUuid}
saveWorkflow={guardedSaveWorkflow}
user={user}
onPhoneCallClick={() => setIsPhoneCallDialogOpen(true)}

View file

@ -1,7 +1,7 @@
"use client";
import { ReactFlowInstance } from "@xyflow/react";
import { AlertCircle, ArrowLeft, ChevronDown, Copy, Download, Eye, History, LoaderCircle, Menu, MoreVertical, Phone, Rocket } from "lucide-react";
import { AlertCircle, ArrowLeft, ChevronDown, Clipboard, Copy, Download, Eye, History, LoaderCircle, Menu, MoreVertical, Phone, Rocket } from "lucide-react";
import { useRouter } from "next/navigation";
import posthog from "posthog-js";
import { useState } from "react";
@ -37,6 +37,7 @@ interface WorkflowEditorHeaderProps {
rfInstance: React.RefObject<ReactFlowInstance<FlowNode, FlowEdge> | null>;
onRun: (mode: string) => Promise<void>;
workflowId: number;
workflowUuid?: string;
saveWorkflow: (updateWorkflowDefinition?: boolean) => Promise<void>;
user: { id: string; email?: string };
onPhoneCallClick: () => void;
@ -63,6 +64,7 @@ export const WorkflowEditorHeader = ({
hasDraft,
onPublished,
workflowId,
workflowUuid,
}: WorkflowEditorHeaderProps) => {
const router = useRouter();
const { toggleSidebar } = useSidebar();
@ -123,6 +125,19 @@ export const WorkflowEditorHeader = ({
}
};
const handleCopyAgentUuid = async () => {
if (!workflowUuid) {
toast.error("Agent UUID not available");
return;
}
try {
await navigator.clipboard.writeText(workflowUuid);
toast.success("Agent UUID copied");
} catch {
toast.error("Failed to copy Agent UUID");
}
};
const handleDownloadWorkflow = () => {
if (!rfInstance.current) return;
@ -380,6 +395,14 @@ export const WorkflowEditorHeader = ({
<Download className="w-4 h-4 mr-2" />
Download Workflow
</DropdownMenuItem>
<DropdownMenuItem
onClick={handleCopyAgentUuid}
disabled={!workflowUuid}
className="text-white hover:bg-[#2a2a2a] cursor-pointer"
>
<Clipboard className="w-4 h-4 mr-2" />
Copy Agent UUID
</DropdownMenuItem>
</DropdownMenuContent>
</DropdownMenu>

View file

@ -81,6 +81,7 @@ export default function WorkflowDetailPage() {
<RenderWorkflow
initialWorkflowName={workflow.name}
workflowId={workflow.id}
workflowUuid={workflow.workflow_uuid ?? undefined}
initialFlow={{
nodes: workflow.workflow_definition.nodes as FlowNode[],
edges: workflow.workflow_definition.edges as FlowEdge[],

View file

@ -1,7 +1,7 @@
"use client";
import { format } from "date-fns";
import { ArrowLeft, BookA, Brain, CalendarIcon, Download, ExternalLink, FileDown, Loader2, Mic, Pause, PhoneOff, Play, Rocket, Settings, Trash2Icon, Upload, Variable, X } from "lucide-react";
import { ArrowLeft, BookA, Brain, CalendarIcon, Clipboard, Download, ExternalLink, FileDown, Fingerprint, Loader2, Mic, Pause, PhoneOff, Play, Rocket, Settings, Trash2Icon, Upload, Variable, X } from "lucide-react";
import Link from "next/link";
import { useParams, useRouter } from "next/navigation";
import { useEffect, useMemo, useRef, useState } from "react";
@ -81,6 +81,7 @@ const NAV_ITEMS = [
{ id: "recordings", label: "Recordings", icon: Mic },
{ id: "deployment", label: "Deployment", icon: Rocket },
{ id: "report", label: "Report", icon: FileDown },
{ id: "identity", label: "Agent UUID", icon: Fingerprint },
];
// ---------------------------------------------------------------------------
@ -992,6 +993,53 @@ function VoicemailSection({
);
}
// ---------------------------------------------------------------------------
// Section: Agent UUID
// ---------------------------------------------------------------------------
function AgentUuidSection({ workflowUuid }: { workflowUuid: string }) {
const handleCopy = async () => {
try {
await navigator.clipboard.writeText(workflowUuid);
toast.success("Agent UUID copied");
} catch {
toast.error("Failed to copy Agent UUID");
}
};
return (
<Card id="identity">
<CardHeader>
<CardTitle className="flex items-center gap-2 text-base">
<Fingerprint className="h-4 w-4" />
Agent UUID
</CardTitle>
<CardDescription>
Stable identifier for this agent. Used in agent-stream URLs and
other integrations where a numeric workflow ID isn&apos;t portable.
</CardDescription>
</CardHeader>
<CardContent>
<button
type="button"
onClick={handleCopy}
title="Click to copy"
className="group flex w-full items-center gap-2 rounded-md border bg-muted/20 p-2 text-left font-mono text-xs transition-colors hover:bg-muted/40"
>
<code className="flex-1 truncate">{workflowUuid}</code>
<Clipboard className="h-3.5 w-3.5 shrink-0 text-muted-foreground transition-colors group-hover:text-foreground" />
</button>
</CardContent>
<CardFooter className="border-t pt-6">
<Button variant="outline" size="sm" onClick={handleCopy}>
<Clipboard className="h-3.5 w-3.5 mr-2" />
Copy UUID
</Button>
</CardFooter>
</Card>
);
}
// ---------------------------------------------------------------------------
// Main Page
// ---------------------------------------------------------------------------
@ -1263,6 +1311,11 @@ function WorkflowSettingsInner({
{/* Report */}
<ReportSection workflowId={workflowId} />
{/* Agent UUID */}
{workflow.workflow_uuid && (
<AgentUuidSection workflowUuid={workflow.workflow_uuid} />
)}
</>
)}
</div>