mirror of
https://github.com/dograh-hq/dograh.git
synced 2026-07-04 10:52:17 +02:00
feat: add template variable rendering for transfer call destination
This commit is contained in:
parent
65d46bc313
commit
9966940624
8 changed files with 279 additions and 142 deletions
|
|
@ -238,7 +238,7 @@ export default function TelephonyConfigurationsPage() {
|
|||
<div className="grid gap-3">
|
||||
{items.map((item) => (
|
||||
<Card key={item.id}>
|
||||
<CardContent className="flex items-center gap-4 py-4">
|
||||
<CardContent className="flex flex-col gap-4 py-4 sm:flex-row sm:items-center">
|
||||
<Link
|
||||
href={`/telephony-configurations/${item.id}`}
|
||||
className="flex flex-1 items-center gap-4 min-w-0"
|
||||
|
|
@ -276,7 +276,7 @@ export default function TelephonyConfigurationsPage() {
|
|||
</button>
|
||||
</div>
|
||||
</Link>
|
||||
<div className="flex items-center gap-1">
|
||||
<div className="flex w-full flex-wrap items-center justify-end gap-1 sm:w-auto sm:flex-nowrap">
|
||||
{!item.is_default_outbound && (
|
||||
<Button
|
||||
variant="ghost"
|
||||
|
|
@ -303,13 +303,15 @@ export default function TelephonyConfigurationsPage() {
|
|||
>
|
||||
<Trash2 className="h-4 w-4 text-destructive" />
|
||||
</Button>
|
||||
<Link
|
||||
href={`/telephony-configurations/${item.id}`}
|
||||
className="text-muted-foreground"
|
||||
aria-label="View phone numbers"
|
||||
>
|
||||
<ChevronRight className="h-5 w-5" />
|
||||
</Link>
|
||||
<Button variant="outline" size="sm" asChild>
|
||||
<Link
|
||||
href={`/telephony-configurations/${item.id}`}
|
||||
aria-label={`Manage phone numbers for ${item.name}`}
|
||||
>
|
||||
Manage Phone Numbers
|
||||
<ChevronRight className="h-4 w-4" />
|
||||
</Link>
|
||||
</Button>
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
|
|
|
|||
|
|
@ -1,7 +1,5 @@
|
|||
"use client";
|
||||
|
||||
import {useState } from "react";
|
||||
|
||||
import type { RecordingResponseSchema } from "@/client/types.gen";
|
||||
import { RecordingSelect, StaticTextWarning } from "@/components/flow/TextOrAudioInput";
|
||||
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card";
|
||||
|
|
@ -47,40 +45,6 @@ export function TransferCallToolConfig({
|
|||
timeout,
|
||||
onTimeoutChange,
|
||||
}: TransferCallToolConfigProps) {
|
||||
const [sipMode, setSipMode] = useState(() => /^(PJSIP|SIP)\//i.test(destination));
|
||||
|
||||
// Validation patterns
|
||||
const isValidPhoneNumber = (phone: string): boolean => {
|
||||
const e164Pattern = /^\+[1-9]\d{1,14}$/;
|
||||
return e164Pattern.test(phone);
|
||||
};
|
||||
|
||||
const isValidSipEndpoint = (endpoint: string): boolean => {
|
||||
const sipPattern = /^(PJSIP|SIP)\/[\w\-\.@]+$/i;
|
||||
return sipPattern.test(endpoint);
|
||||
};
|
||||
|
||||
const getValidationError = (): string | null => {
|
||||
if (!destination) return null;
|
||||
|
||||
if (sipMode) {
|
||||
return isValidSipEndpoint(destination)
|
||||
? null
|
||||
: "Please enter a valid SIP endpoint (e.g., PJSIP/1234 or SIP/extension@domain.com)";
|
||||
} else {
|
||||
return isValidPhoneNumber(destination)
|
||||
? null
|
||||
: "Please enter a valid phone number in E.164 format (e.g., +1234567890)";
|
||||
}
|
||||
};
|
||||
|
||||
const destinationError = getValidationError();
|
||||
|
||||
const handleSipModeToggle = () => {
|
||||
setSipMode(!sipMode);
|
||||
onDestinationChange(""); // Clear destination when switching modes
|
||||
};
|
||||
|
||||
return (
|
||||
<Card>
|
||||
<CardHeader>
|
||||
|
|
@ -117,30 +81,23 @@ export function TransferCallToolConfig({
|
|||
|
||||
<div className="grid gap-2 pt-4 border-t">
|
||||
<Label>Transfer Destination</Label>
|
||||
<Label className="text-xs text-muted-foreground">
|
||||
{sipMode
|
||||
? "SIP endpoint to transfer the call to (e.g., PJSIP/1234 or SIP/extension@domain.com)"
|
||||
: "Phone number to transfer the call to (E.164 format with country code)"
|
||||
}
|
||||
</Label>
|
||||
<div className="text-xs text-muted-foreground space-y-1">
|
||||
<p>Enter one of these destination formats:</p>
|
||||
<ul className="list-disc pl-4 space-y-1">
|
||||
<li>SIP endpoint, e.g. PJSIP/1234</li>
|
||||
<li>E.164 phone number, e.g. +1234567890</li>
|
||||
<li>
|
||||
Template variable, e.g. {"{{initial_context.transfer_destination}}"}
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<Input
|
||||
value={destination}
|
||||
onChange={(e) => onDestinationChange(e.target.value)}
|
||||
placeholder={sipMode ? "PJSIP/1234 or SIP/extension@domain.com" : "+1234567890"}
|
||||
className={destinationError ? "border-red-500 focus:border-red-500" : ""}
|
||||
placeholder={
|
||||
"+1234567890, PJSIP/1234, or {{initial_context.transfer_destination}}"
|
||||
}
|
||||
/>
|
||||
{destinationError && (
|
||||
<Label className="text-xs text-red-500">
|
||||
{destinationError}
|
||||
</Label>
|
||||
)}
|
||||
<button
|
||||
type="button"
|
||||
className="text-xs text-muted-foreground hover:text-foreground underline w-fit"
|
||||
onClick={handleSipModeToggle}
|
||||
>
|
||||
{sipMode ? "Use phone number instead" : "Use SIP endpoint instead"}
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div className="grid gap-4 pt-4 border-t">
|
||||
|
|
|
|||
|
|
@ -290,18 +290,14 @@ export default function ToolDetailPage() {
|
|||
const handleSave = async () => {
|
||||
if (!tool) return;
|
||||
|
||||
const normalizedTransferDestination = transferDestination.trim();
|
||||
|
||||
// Validation based on tool type
|
||||
if (tool.category === "calculator") {
|
||||
// No validation needed for built-in tools
|
||||
} else if (tool.category === "transfer_call") {
|
||||
// Validate destination for Transfer Call tools (supports both E.164 and SIP endpoints)
|
||||
const e164Pattern = /^\+[1-9]\d{1,14}$/;
|
||||
const sipPattern = /^(PJSIP|SIP)\/[\w\-\.@]+$/i;
|
||||
const isValidE164 = e164Pattern.test(transferDestination);
|
||||
const isValidSip = sipPattern.test(transferDestination);
|
||||
|
||||
if (!transferDestination || (!isValidE164 && !isValidSip)) {
|
||||
setError("Please enter a valid phone number (E.164 format) or SIP endpoint (e.g., PJSIP/1234)");
|
||||
if (!normalizedTransferDestination) {
|
||||
setError("Please enter a transfer destination");
|
||||
return;
|
||||
}
|
||||
} else if (tool.category === "mcp") {
|
||||
|
|
@ -382,7 +378,7 @@ export default function ToolDetailPage() {
|
|||
schema_version: 1,
|
||||
type: "transfer_call",
|
||||
config: {
|
||||
destination: transferDestination,
|
||||
destination: normalizedTransferDestination,
|
||||
messageType: transferMessageType,
|
||||
customMessage: transferMessageType === "custom" ? customMessage : undefined,
|
||||
audioRecordingId: transferMessageType === "audio" ? transferAudioRecordingId || undefined : undefined,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue