mirror of
https://github.com/dograh-hq/dograh.git
synced 2026-07-01 08:59:46 +02:00
feat: support inbound vonage calls (#480)
* feat: support inbound vonage calls * fix: drift check * feat: add warning with missing signature secret * docs: vonage inbound steps * chore: upgrade pipecat submodule
This commit is contained in:
parent
f190a0dd9a
commit
d9800fddd6
18 changed files with 687 additions and 83 deletions
4
ui/package-lock.json
generated
4
ui/package-lock.json
generated
|
|
@ -1,12 +1,12 @@
|
|||
{
|
||||
"name": "ui",
|
||||
"version": "1.35.0",
|
||||
"version": "1.39.0",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "ui",
|
||||
"version": "1.35.0",
|
||||
"version": "1.39.0",
|
||||
"dependencies": {
|
||||
"@dagrejs/dagre": "^1.1.4",
|
||||
"@radix-ui/react-alert-dialog": "^1.1.15",
|
||||
|
|
|
|||
|
|
@ -53,6 +53,7 @@ export default function TelephonyConfigurationsPage() {
|
|||
const { user, getAccessToken, loading: authLoading } = useAuth();
|
||||
const {
|
||||
telnyxMissingWebhookPublicKeyCount,
|
||||
vonageMissingSignatureSecretCount,
|
||||
refresh: refreshWarnings,
|
||||
} = useTelephonyConfigWarnings();
|
||||
const [items, setItems] = useState<TelephonyConfigurationListItem[]>([]);
|
||||
|
|
@ -82,9 +83,9 @@ export default function TelephonyConfigurationsPage() {
|
|||
}
|
||||
}, [authLoading, user, getAccessToken]);
|
||||
|
||||
// After a save (create/update), the backing config may have flipped between
|
||||
// missing/present webhook_public_key — refresh the cached warning state so
|
||||
// the page banner and nav badge update without a manual reload.
|
||||
// After a save (create/update), webhook-verification warning state may have
|
||||
// changed — refresh the cached warning state so the page banner and nav badge
|
||||
// update without a manual reload.
|
||||
const onSaved = useCallback(async () => {
|
||||
await fetchItems();
|
||||
await refreshWarnings();
|
||||
|
|
@ -194,6 +195,26 @@ export default function TelephonyConfigurationsPage() {
|
|||
</div>
|
||||
)}
|
||||
|
||||
{vonageMissingSignatureSecretCount > 0 && (
|
||||
<div className="mb-6 rounded-md border border-amber-300 bg-amber-50 p-4 text-amber-900 dark:border-amber-800 dark:bg-amber-950 dark:text-amber-200">
|
||||
<div className="flex items-start gap-3">
|
||||
<AlertTriangle className="h-5 w-5 shrink-0 mt-0.5" />
|
||||
<div className="space-y-1 text-sm">
|
||||
<p className="font-medium">Signature secret not configured</p>
|
||||
<p>
|
||||
{vonageMissingSignatureSecretCount === 1
|
||||
? "1 Vonage configuration is"
|
||||
: `${vonageMissingSignatureSecretCount} Vonage configurations are`}{" "}
|
||||
missing a signature secret. Without it, Vonage signed webhooks
|
||||
are rejected, so inbound calls and call status updates will not
|
||||
work. Copy the signature secret from your Vonage account and
|
||||
paste it into the affected Vonage configuration below.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{loading ? (
|
||||
<div className="grid gap-3">
|
||||
<Skeleton className="h-24 w-full" />
|
||||
|
|
|
|||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
|
@ -5323,6 +5323,10 @@ export type TelephonyConfigWarningsResponse = {
|
|||
* Telnyx Missing Webhook Public Key Count
|
||||
*/
|
||||
telnyx_missing_webhook_public_key_count: number;
|
||||
/**
|
||||
* Vonage Missing Signature Secret Count
|
||||
*/
|
||||
vonage_missing_signature_secret_count: number;
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
@ -6427,6 +6431,12 @@ export type VonageConfigurationRequest = {
|
|||
* Private key for JWT generation
|
||||
*/
|
||||
private_key: string;
|
||||
/**
|
||||
* Signature Secret
|
||||
*
|
||||
* Vonage signature secret used to verify signed webhooks
|
||||
*/
|
||||
signature_secret?: string | null;
|
||||
/**
|
||||
* From Numbers
|
||||
*
|
||||
|
|
@ -6461,6 +6471,10 @@ export type VonageConfigurationResponse = {
|
|||
* Private Key
|
||||
*/
|
||||
private_key: string;
|
||||
/**
|
||||
* Signature Secret
|
||||
*/
|
||||
signature_secret?: string | null;
|
||||
/**
|
||||
* From Numbers
|
||||
*/
|
||||
|
|
@ -7553,6 +7567,27 @@ export type HandleVonageEventsApiV1TelephonyVonageEventsWorkflowRunIdPostRespons
|
|||
200: unknown;
|
||||
};
|
||||
|
||||
export type HandleVonageEventsWithoutRunApiV1TelephonyVonageEventsPostData = {
|
||||
body?: never;
|
||||
path?: never;
|
||||
query?: never;
|
||||
url: '/api/v1/telephony/vonage/events';
|
||||
};
|
||||
|
||||
export type HandleVonageEventsWithoutRunApiV1TelephonyVonageEventsPostErrors = {
|
||||
/**
|
||||
* Not found
|
||||
*/
|
||||
404: unknown;
|
||||
};
|
||||
|
||||
export type HandleVonageEventsWithoutRunApiV1TelephonyVonageEventsPostResponses = {
|
||||
/**
|
||||
* Successful Response
|
||||
*/
|
||||
200: unknown;
|
||||
};
|
||||
|
||||
export type ImpersonateApiV1SuperuserImpersonatePostData = {
|
||||
body: ImpersonateRequest;
|
||||
headers?: {
|
||||
|
|
|
|||
|
|
@ -167,8 +167,13 @@ export function AppSidebar() {
|
|||
const { provider, getSelectedTeam, logout, user } = useAuth();
|
||||
const { config } = useAppConfig();
|
||||
const { openHireExpert } = useLeadForms();
|
||||
const { telnyxMissingWebhookPublicKeyCount } = useTelephonyConfigWarnings();
|
||||
const hasTelephonyWarning = telnyxMissingWebhookPublicKeyCount > 0;
|
||||
const {
|
||||
telnyxMissingWebhookPublicKeyCount,
|
||||
vonageMissingSignatureSecretCount,
|
||||
} = useTelephonyConfigWarnings();
|
||||
const hasTelephonyWarning =
|
||||
telnyxMissingWebhookPublicKeyCount > 0 ||
|
||||
vonageMissingSignatureSecretCount > 0;
|
||||
const isCollapsed = !isMobile && state === "collapsed";
|
||||
|
||||
// Get selected team for Stack auth (cast to Team type from Stack)
|
||||
|
|
|
|||
|
|
@ -7,12 +7,14 @@ import { useAuth } from '@/lib/auth';
|
|||
|
||||
interface TelephonyConfigWarningsContextType {
|
||||
telnyxMissingWebhookPublicKeyCount: number;
|
||||
vonageMissingSignatureSecretCount: number;
|
||||
refresh: () => Promise<void>;
|
||||
loading: boolean;
|
||||
}
|
||||
|
||||
const TelephonyConfigWarningsContext = createContext<TelephonyConfigWarningsContextType>({
|
||||
telnyxMissingWebhookPublicKeyCount: 0,
|
||||
vonageMissingSignatureSecretCount: 0,
|
||||
refresh: async () => { },
|
||||
loading: false,
|
||||
});
|
||||
|
|
@ -23,7 +25,8 @@ const TelephonyConfigWarningsContext = createContext<TelephonyConfigWarningsCont
|
|||
// change. Page-level callers invalidate via refresh() after a save.
|
||||
export function TelephonyConfigWarningsProvider({ children }: { children: ReactNode }) {
|
||||
const auth = useAuth();
|
||||
const [count, setCount] = useState(0);
|
||||
const [telnyxCount, setTelnyxCount] = useState(0);
|
||||
const [vonageCount, setVonageCount] = useState(0);
|
||||
const [loading, setLoading] = useState(false);
|
||||
const hasFetched = useRef(false);
|
||||
|
||||
|
|
@ -31,9 +34,11 @@ export function TelephonyConfigWarningsProvider({ children }: { children: ReactN
|
|||
setLoading(true);
|
||||
try {
|
||||
const res = await getTelephonyConfigWarningsApiV1OrganizationsTelephonyConfigWarningsGet();
|
||||
setCount(res.data?.telnyx_missing_webhook_public_key_count ?? 0);
|
||||
setTelnyxCount(res.data?.telnyx_missing_webhook_public_key_count ?? 0);
|
||||
setVonageCount(res.data?.vonage_missing_signature_secret_count ?? 0);
|
||||
} catch {
|
||||
setCount(0);
|
||||
setTelnyxCount(0);
|
||||
setVonageCount(0);
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
|
|
@ -53,7 +58,8 @@ export function TelephonyConfigWarningsProvider({ children }: { children: ReactN
|
|||
return (
|
||||
<TelephonyConfigWarningsContext.Provider
|
||||
value={{
|
||||
telnyxMissingWebhookPublicKeyCount: count,
|
||||
telnyxMissingWebhookPublicKeyCount: telnyxCount,
|
||||
vonageMissingSignatureSecretCount: vonageCount,
|
||||
refresh,
|
||||
loading,
|
||||
}}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue