mirror of
https://github.com/dograh-hq/dograh.git
synced 2026-06-07 07:55:16 +02:00
fix: fix circuit breaker failure recording
fix: fix circuit breaker failure recording chore: provide advanced configuration option in UI for campaigns
This commit is contained in:
parent
628132f29b
commit
3ea235a666
17 changed files with 448 additions and 58 deletions
|
|
@ -46,6 +46,15 @@ export interface CampaignAdvancedSettingsProps {
|
|||
onScheduleTimezoneChange: (value: ITimezoneOption | string) => void;
|
||||
timeSlots: TimeSlot[];
|
||||
onTimeSlotsChange: (value: TimeSlot[]) => void;
|
||||
// Circuit breaker config
|
||||
circuitBreakerEnabled: boolean;
|
||||
onCircuitBreakerEnabledChange: (value: boolean) => void;
|
||||
circuitBreakerFailureThreshold: string;
|
||||
onCircuitBreakerFailureThresholdChange: (value: string) => void;
|
||||
circuitBreakerWindowSeconds: string;
|
||||
onCircuitBreakerWindowSecondsChange: (value: string) => void;
|
||||
circuitBreakerMinCalls: string;
|
||||
onCircuitBreakerMinCallsChange: (value: string) => void;
|
||||
}
|
||||
|
||||
/** Extract the string timezone value from ITimezoneOption | string */
|
||||
|
|
@ -101,6 +110,10 @@ export default function CampaignAdvancedSettings({
|
|||
retryOnVoicemail, onRetryOnVoicemailChange,
|
||||
scheduleEnabled, onScheduleEnabledChange, scheduleTimezone, onScheduleTimezoneChange,
|
||||
timeSlots, onTimeSlotsChange,
|
||||
circuitBreakerEnabled, onCircuitBreakerEnabledChange,
|
||||
circuitBreakerFailureThreshold, onCircuitBreakerFailureThresholdChange,
|
||||
circuitBreakerWindowSeconds, onCircuitBreakerWindowSecondsChange,
|
||||
circuitBreakerMinCalls, onCircuitBreakerMinCallsChange,
|
||||
}: CampaignAdvancedSettingsProps) {
|
||||
const timezoneSelectId = useId();
|
||||
|
||||
|
|
@ -295,6 +308,68 @@ export default function CampaignAdvancedSettings({
|
|||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<Separator />
|
||||
|
||||
{/* Circuit Breaker */}
|
||||
<div className="space-y-4">
|
||||
<div className="flex items-center justify-between">
|
||||
<div>
|
||||
<Label htmlFor="circuit-breaker-enabled">Circuit Breaker</Label>
|
||||
<p className="text-sm text-muted-foreground">
|
||||
Auto-pause campaign on high failure rates
|
||||
</p>
|
||||
</div>
|
||||
<Switch
|
||||
id="circuit-breaker-enabled"
|
||||
checked={circuitBreakerEnabled}
|
||||
onCheckedChange={onCircuitBreakerEnabledChange}
|
||||
/>
|
||||
</div>
|
||||
|
||||
{circuitBreakerEnabled && (
|
||||
<div className="space-y-4 pl-4 border-l-2 border-muted">
|
||||
<div className="space-y-2">
|
||||
<Label htmlFor="cb-failure-threshold">Failure Threshold (%)</Label>
|
||||
<Input
|
||||
id="cb-failure-threshold"
|
||||
type="number"
|
||||
value={circuitBreakerFailureThreshold}
|
||||
onChange={(e) => onCircuitBreakerFailureThresholdChange(e.target.value)}
|
||||
min={1}
|
||||
max={100}
|
||||
/>
|
||||
<p className="text-sm text-muted-foreground">
|
||||
Pause when failure rate exceeds this percentage
|
||||
</p>
|
||||
</div>
|
||||
<div className="grid grid-cols-2 gap-4">
|
||||
<div className="space-y-2">
|
||||
<Label htmlFor="cb-window">Window (seconds)</Label>
|
||||
<Input
|
||||
id="cb-window"
|
||||
type="number"
|
||||
value={circuitBreakerWindowSeconds}
|
||||
onChange={(e) => onCircuitBreakerWindowSecondsChange(e.target.value)}
|
||||
min={30}
|
||||
max={600}
|
||||
/>
|
||||
</div>
|
||||
<div className="space-y-2">
|
||||
<Label htmlFor="cb-min-calls">Min Calls in Window</Label>
|
||||
<Input
|
||||
id="cb-min-calls"
|
||||
type="number"
|
||||
value={circuitBreakerMinCalls}
|
||||
onChange={(e) => onCircuitBreakerMinCallsChange(e.target.value)}
|
||||
min={1}
|
||||
max={100}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,8 +8,8 @@ import { toast } from 'sonner';
|
|||
|
||||
import {
|
||||
getCampaignApiV1CampaignCampaignIdGet,
|
||||
getCampaignLimitsApiV1OrganizationsCampaignLimitsGet,
|
||||
updateCampaignApiV1CampaignCampaignIdPatch,
|
||||
getCampaignDefaultsApiV1OrganizationsCampaignDefaultsGet,
|
||||
updateCampaignApiV1CampaignCampaignIdPatch
|
||||
} from '@/client/sdk.gen';
|
||||
import type { CampaignResponse } from '@/client/types.gen';
|
||||
import { Button } from '@/components/ui/button';
|
||||
|
|
@ -55,6 +55,11 @@ export default function EditCampaignPage() {
|
|||
const [timeSlots, setTimeSlots] = useState<TimeSlot[]>([
|
||||
{ day_of_week: 0, start_time: '09:00', end_time: '17:00' },
|
||||
]);
|
||||
// Circuit breaker config state
|
||||
const [circuitBreakerEnabled, setCircuitBreakerEnabled] = useState(true);
|
||||
const [circuitBreakerFailureThreshold, setCircuitBreakerFailureThreshold] = useState<string>('50');
|
||||
const [circuitBreakerWindowSeconds, setCircuitBreakerWindowSeconds] = useState<string>('120');
|
||||
const [circuitBreakerMinCalls, setCircuitBreakerMinCalls] = useState<string>('5');
|
||||
|
||||
// Redirect if not authenticated
|
||||
useEffect(() => {
|
||||
|
|
@ -104,6 +109,15 @@ export default function EditCampaignPage() {
|
|||
setTimeSlots(c.schedule_config.slots.map(s => ({ ...s })));
|
||||
}
|
||||
}
|
||||
|
||||
// Circuit breaker config
|
||||
const cb = (c as unknown as { circuit_breaker?: { enabled: boolean; failure_threshold: number; window_seconds: number; min_calls_in_window: number } }).circuit_breaker;
|
||||
if (cb) {
|
||||
setCircuitBreakerEnabled(cb.enabled);
|
||||
setCircuitBreakerFailureThreshold(String(Math.round(cb.failure_threshold * 100)));
|
||||
setCircuitBreakerWindowSeconds(String(cb.window_seconds));
|
||||
setCircuitBreakerMinCalls(String(cb.min_calls_in_window));
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Failed to fetch campaign:', error);
|
||||
|
|
@ -115,11 +129,11 @@ export default function EditCampaignPage() {
|
|||
}, [user, getAccessToken, campaignId, router]);
|
||||
|
||||
// Fetch campaign limits
|
||||
const fetchCampaignLimits = useCallback(async () => {
|
||||
const fetchCampaignDefaults = useCallback(async () => {
|
||||
if (!user) return;
|
||||
try {
|
||||
const accessToken = await getAccessToken();
|
||||
const response = await getCampaignLimitsApiV1OrganizationsCampaignLimitsGet({
|
||||
const response = await getCampaignDefaultsApiV1OrganizationsCampaignDefaultsGet({
|
||||
headers: { 'Authorization': `Bearer ${accessToken}` },
|
||||
});
|
||||
|
||||
|
|
@ -136,9 +150,9 @@ export default function EditCampaignPage() {
|
|||
useEffect(() => {
|
||||
if (user) {
|
||||
fetchCampaign();
|
||||
fetchCampaignLimits();
|
||||
fetchCampaignDefaults();
|
||||
}
|
||||
}, [fetchCampaign, fetchCampaignLimits, user]);
|
||||
}, [fetchCampaign, fetchCampaignDefaults, user]);
|
||||
|
||||
// Effective concurrency limit
|
||||
const effectiveLimit = fromNumbersCount > 0
|
||||
|
|
@ -213,6 +227,14 @@ export default function EditCampaignPage() {
|
|||
slots: [{ day_of_week: 0, start_time: '09:00', end_time: '17:00' }],
|
||||
};
|
||||
|
||||
const circuitBreakerConfig = {
|
||||
enabled: circuitBreakerEnabled,
|
||||
failure_threshold: (parseInt(circuitBreakerFailureThreshold) || 50) / 100,
|
||||
window_seconds: parseInt(circuitBreakerWindowSeconds) || 120,
|
||||
min_calls_in_window: parseInt(circuitBreakerMinCalls) || 5,
|
||||
};
|
||||
|
||||
|
||||
const response = await updateCampaignApiV1CampaignCampaignIdPatch({
|
||||
path: { campaign_id: campaignId },
|
||||
body: {
|
||||
|
|
@ -220,6 +242,7 @@ export default function EditCampaignPage() {
|
|||
retry_config: retryConfig,
|
||||
max_concurrency: maxConcurrencyValue,
|
||||
schedule_config: scheduleConfig,
|
||||
circuit_breaker: circuitBreakerConfig,
|
||||
},
|
||||
headers: { 'Authorization': `Bearer ${accessToken}` },
|
||||
});
|
||||
|
|
@ -332,6 +355,14 @@ export default function EditCampaignPage() {
|
|||
onScheduleTimezoneChange={setScheduleTimezone}
|
||||
timeSlots={timeSlots}
|
||||
onTimeSlotsChange={setTimeSlots}
|
||||
circuitBreakerEnabled={circuitBreakerEnabled}
|
||||
onCircuitBreakerEnabledChange={setCircuitBreakerEnabled}
|
||||
circuitBreakerFailureThreshold={circuitBreakerFailureThreshold}
|
||||
onCircuitBreakerFailureThresholdChange={setCircuitBreakerFailureThreshold}
|
||||
circuitBreakerWindowSeconds={circuitBreakerWindowSeconds}
|
||||
onCircuitBreakerWindowSecondsChange={setCircuitBreakerWindowSeconds}
|
||||
circuitBreakerMinCalls={circuitBreakerMinCalls}
|
||||
onCircuitBreakerMinCallsChange={setCircuitBreakerMinCalls}
|
||||
/>
|
||||
|
||||
{submitError && (
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ import { toast } from 'sonner';
|
|||
|
||||
import {
|
||||
createCampaignApiV1CampaignCreatePost,
|
||||
getCampaignLimitsApiV1OrganizationsCampaignLimitsGet,
|
||||
getCampaignDefaultsApiV1OrganizationsCampaignDefaultsGet,
|
||||
getWorkflowsSummaryApiV1WorkflowSummaryGet
|
||||
} from '@/client/sdk.gen';
|
||||
import type { WorkflowSummaryResponse } from '@/client/types.gen';
|
||||
|
|
@ -72,6 +72,11 @@ export default function NewCampaignPage() {
|
|||
const [timeSlots, setTimeSlots] = useState<TimeSlot[]>([
|
||||
{ day_of_week: 0, start_time: '09:00', end_time: '17:00' },
|
||||
]);
|
||||
// Circuit breaker config state
|
||||
const [circuitBreakerEnabled, setCircuitBreakerEnabled] = useState(true);
|
||||
const [circuitBreakerFailureThreshold, setCircuitBreakerFailureThreshold] = useState<string>('50');
|
||||
const [circuitBreakerWindowSeconds, setCircuitBreakerWindowSeconds] = useState<string>('120');
|
||||
const [circuitBreakerMinCalls, setCircuitBreakerMinCalls] = useState<string>('5');
|
||||
|
||||
// Redirect if not authenticated
|
||||
useEffect(() => {
|
||||
|
|
@ -104,11 +109,11 @@ export default function NewCampaignPage() {
|
|||
}, [user, getAccessToken]);
|
||||
|
||||
// Fetch campaign limits
|
||||
const fetchCampaignLimits = useCallback(async () => {
|
||||
const fetchCampaignDefaults = useCallback(async () => {
|
||||
if (!user) return;
|
||||
try {
|
||||
const accessToken = await getAccessToken();
|
||||
const response = await getCampaignLimitsApiV1OrganizationsCampaignLimitsGet({
|
||||
const response = await getCampaignDefaultsApiV1OrganizationsCampaignDefaultsGet({
|
||||
headers: {
|
||||
'Authorization': `Bearer ${accessToken}`,
|
||||
}
|
||||
|
|
@ -117,14 +122,56 @@ export default function NewCampaignPage() {
|
|||
if (response.data) {
|
||||
setOrgConcurrentLimit(response.data.concurrent_call_limit);
|
||||
setFromNumbersCount(response.data.from_numbers_count);
|
||||
// Initialize retry config from defaults
|
||||
const retryConfig = response.data.default_retry_config;
|
||||
setRetryEnabled(retryConfig.enabled);
|
||||
setMaxRetries(String(retryConfig.max_retries));
|
||||
setRetryDelaySeconds(String(retryConfig.retry_delay_seconds));
|
||||
setRetryOnBusy(retryConfig.retry_on_busy);
|
||||
setRetryOnNoAnswer(retryConfig.retry_on_no_answer);
|
||||
setRetryOnVoicemail(retryConfig.retry_on_voicemail);
|
||||
|
||||
const last = (response.data as { last_campaign_settings?: {
|
||||
retry_config?: { enabled: boolean; max_retries: number; retry_delay_seconds: number; retry_on_busy: boolean; retry_on_no_answer: boolean; retry_on_voicemail: boolean };
|
||||
max_concurrency?: number | null;
|
||||
schedule_config?: { enabled: boolean; timezone: string; slots: TimeSlot[] } | null;
|
||||
circuit_breaker?: { enabled: boolean; failure_threshold: number; window_seconds: number; min_calls_in_window: number } | null;
|
||||
} | null }).last_campaign_settings;
|
||||
|
||||
if (last) {
|
||||
// Pre-populate from last campaign
|
||||
if (last.retry_config) {
|
||||
setRetryEnabled(last.retry_config.enabled);
|
||||
setMaxRetries(String(last.retry_config.max_retries));
|
||||
setRetryDelaySeconds(String(last.retry_config.retry_delay_seconds));
|
||||
setRetryOnBusy(last.retry_config.retry_on_busy);
|
||||
setRetryOnNoAnswer(last.retry_config.retry_on_no_answer);
|
||||
setRetryOnVoicemail(last.retry_config.retry_on_voicemail);
|
||||
} else {
|
||||
const retryConfig = response.data.default_retry_config;
|
||||
setRetryEnabled(retryConfig.enabled);
|
||||
setMaxRetries(String(retryConfig.max_retries));
|
||||
setRetryDelaySeconds(String(retryConfig.retry_delay_seconds));
|
||||
setRetryOnBusy(retryConfig.retry_on_busy);
|
||||
setRetryOnNoAnswer(retryConfig.retry_on_no_answer);
|
||||
setRetryOnVoicemail(retryConfig.retry_on_voicemail);
|
||||
}
|
||||
if (last.max_concurrency) {
|
||||
setMaxConcurrency(String(last.max_concurrency));
|
||||
}
|
||||
if (last.schedule_config) {
|
||||
setScheduleEnabled(last.schedule_config.enabled);
|
||||
setScheduleTimezone(last.schedule_config.timezone);
|
||||
setTimeSlots(last.schedule_config.slots);
|
||||
}
|
||||
if (last.circuit_breaker) {
|
||||
setCircuitBreakerEnabled(last.circuit_breaker.enabled);
|
||||
setCircuitBreakerFailureThreshold(String(Math.round(last.circuit_breaker.failure_threshold * 100)));
|
||||
setCircuitBreakerWindowSeconds(String(last.circuit_breaker.window_seconds));
|
||||
setCircuitBreakerMinCalls(String(last.circuit_breaker.min_calls_in_window));
|
||||
}
|
||||
} else {
|
||||
// No previous campaign — use defaults
|
||||
const retryConfig = response.data.default_retry_config;
|
||||
setRetryEnabled(retryConfig.enabled);
|
||||
setMaxRetries(String(retryConfig.max_retries));
|
||||
setRetryDelaySeconds(String(retryConfig.retry_delay_seconds));
|
||||
setRetryOnBusy(retryConfig.retry_on_busy);
|
||||
setRetryOnNoAnswer(retryConfig.retry_on_no_answer);
|
||||
setRetryOnVoicemail(retryConfig.retry_on_voicemail);
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Failed to fetch campaign limits:', error);
|
||||
|
|
@ -135,9 +182,9 @@ export default function NewCampaignPage() {
|
|||
useEffect(() => {
|
||||
if (user) {
|
||||
fetchWorkflows();
|
||||
fetchCampaignLimits();
|
||||
fetchCampaignDefaults();
|
||||
}
|
||||
}, [fetchWorkflows, fetchCampaignLimits, user]);
|
||||
}, [fetchWorkflows, fetchCampaignDefaults, user]);
|
||||
|
||||
// Effective concurrency limit considering both org limit and available CLIs
|
||||
const effectiveLimit = fromNumbersCount > 0
|
||||
|
|
@ -195,6 +242,15 @@ export default function NewCampaignPage() {
|
|||
}
|
||||
: undefined;
|
||||
|
||||
// Build circuit_breaker config
|
||||
const circuitBreakerConfig = {
|
||||
enabled: circuitBreakerEnabled,
|
||||
failure_threshold: (parseInt(circuitBreakerFailureThreshold) || 50) / 100,
|
||||
window_seconds: parseInt(circuitBreakerWindowSeconds) || 120,
|
||||
min_calls_in_window: parseInt(circuitBreakerMinCalls) || 5,
|
||||
};
|
||||
|
||||
|
||||
const response = await createCampaignApiV1CampaignCreatePost({
|
||||
body: {
|
||||
name: campaignName,
|
||||
|
|
@ -204,6 +260,7 @@ export default function NewCampaignPage() {
|
|||
retry_config: retryConfig,
|
||||
max_concurrency: maxConcurrencyValue,
|
||||
schedule_config: scheduleConfig,
|
||||
circuit_breaker: circuitBreakerConfig,
|
||||
},
|
||||
headers: {
|
||||
'Authorization': `Bearer ${accessToken}`,
|
||||
|
|
@ -401,6 +458,14 @@ export default function NewCampaignPage() {
|
|||
onScheduleTimezoneChange={setScheduleTimezone}
|
||||
timeSlots={timeSlots}
|
||||
onTimeSlotsChange={setTimeSlots}
|
||||
circuitBreakerEnabled={circuitBreakerEnabled}
|
||||
onCircuitBreakerEnabledChange={setCircuitBreakerEnabled}
|
||||
circuitBreakerFailureThreshold={circuitBreakerFailureThreshold}
|
||||
onCircuitBreakerFailureThresholdChange={setCircuitBreakerFailureThreshold}
|
||||
circuitBreakerWindowSeconds={circuitBreakerWindowSeconds}
|
||||
onCircuitBreakerWindowSecondsChange={setCircuitBreakerWindowSeconds}
|
||||
circuitBreakerMinCalls={circuitBreakerMinCalls}
|
||||
onCircuitBreakerMinCallsChange={setCircuitBreakerMinCalls}
|
||||
/>
|
||||
</CollapsibleContent>
|
||||
</Collapsible>
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ interface DocumentUploadProps {
|
|||
onUploadSuccess: () => void;
|
||||
}
|
||||
|
||||
const MAX_FILE_SIZE = 100 * 1024 * 1024; // 100MB
|
||||
const MAX_FILE_SIZE = 5 * 1024 * 1024; // 5MB
|
||||
const ACCEPTED_FILE_TYPES = ['.pdf', '.docx', '.doc', '.txt'];
|
||||
|
||||
export default function DocumentUpload({ onUploadSuccess }: DocumentUploadProps) {
|
||||
|
|
@ -36,7 +36,7 @@ export default function DocumentUpload({ onUploadSuccess }: DocumentUploadProps)
|
|||
|
||||
// Validate file size
|
||||
if (file.size > MAX_FILE_SIZE) {
|
||||
toast.error('File size must be less than 100MB');
|
||||
toast.error('File size must be less than 5MB');
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
@ -44,7 +44,13 @@ export default function DocumentUpload({ onUploadSuccess }: DocumentUploadProps)
|
|||
};
|
||||
|
||||
const uploadFile = async (file: File) => {
|
||||
if (!validateFile(file)) return;
|
||||
if (!validateFile(file)) {
|
||||
// Reset file input so the same file can be re-selected
|
||||
if (fileInputRef.current) {
|
||||
fileInputRef.current.value = '';
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
setUploading(true);
|
||||
setUploadProgress(0);
|
||||
|
|
@ -182,7 +188,7 @@ export default function DocumentUpload({ onUploadSuccess }: DocumentUploadProps)
|
|||
or click to browse
|
||||
</p>
|
||||
<p className="text-xs text-muted-foreground">
|
||||
Supported formats: {ACCEPTED_FILE_TYPES.join(', ')} (Max 100MB)
|
||||
Supported formats: {ACCEPTED_FILE_TYPES.join(', ')} (Max 5MB)
|
||||
</p>
|
||||
</div>
|
||||
|
||||
|
|
|
|||
File diff suppressed because one or more lines are too long
|
|
@ -82,10 +82,11 @@ export type AuthUserResponse = {
|
|||
|
||||
export type CallType = 'inbound' | 'outbound';
|
||||
|
||||
export type CampaignLimitsResponse = {
|
||||
export type CampaignDefaultsResponse = {
|
||||
concurrent_call_limit: number;
|
||||
from_numbers_count: number;
|
||||
default_retry_config: RetryConfigResponse;
|
||||
last_campaign_settings?: LastCampaignSettingsResponse | null;
|
||||
};
|
||||
|
||||
export type CampaignProgressResponse = {
|
||||
|
|
@ -120,6 +121,7 @@ export type CampaignResponse = {
|
|||
retry_config: RetryConfigResponse;
|
||||
max_concurrency?: number | null;
|
||||
schedule_config?: ScheduleConfigResponse | null;
|
||||
circuit_breaker?: CircuitBreakerConfigResponse | null;
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
@ -192,6 +194,20 @@ export type ChunkSearchResponseSchema = {
|
|||
total_results: number;
|
||||
};
|
||||
|
||||
export type CircuitBreakerConfigRequest = {
|
||||
enabled?: boolean;
|
||||
failure_threshold?: number;
|
||||
window_seconds?: number;
|
||||
min_calls_in_window?: number;
|
||||
};
|
||||
|
||||
export type CircuitBreakerConfigResponse = {
|
||||
enabled: boolean;
|
||||
failure_threshold: number;
|
||||
window_seconds: number;
|
||||
min_calls_in_window: number;
|
||||
};
|
||||
|
||||
/**
|
||||
* Request schema for Cloudonix configuration.
|
||||
*/
|
||||
|
|
@ -241,6 +257,7 @@ export type CreateCampaignRequest = {
|
|||
retry_config?: RetryConfigRequest | null;
|
||||
max_concurrency?: number | null;
|
||||
schedule_config?: ScheduleConfigRequest | null;
|
||||
circuit_breaker?: CircuitBreakerConfigRequest | null;
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
@ -715,6 +732,13 @@ export type IntegrationResponse = {
|
|||
|
||||
export type ItemKind = 'node' | 'edge' | 'workflow';
|
||||
|
||||
export type LastCampaignSettingsResponse = {
|
||||
retry_config?: RetryConfigResponse | null;
|
||||
max_concurrency?: number | null;
|
||||
schedule_config?: ScheduleConfigResponse | null;
|
||||
circuit_breaker?: CircuitBreakerConfigResponse | null;
|
||||
};
|
||||
|
||||
export type LoadTestStatsResponse = {
|
||||
total: number;
|
||||
pending: number;
|
||||
|
|
@ -949,7 +973,7 @@ export type ToolResponse = {
|
|||
*/
|
||||
export type TransferCallConfig = {
|
||||
/**
|
||||
* Phone number to transfer the call to (E.164 format, e.g., +1234567890)
|
||||
* Phone number or SIP endpoint to transfer the call to (E.164 format e.g., +1234567890, or SIP endpoint e.g., PJSIP/1234)
|
||||
*/
|
||||
destination: string;
|
||||
/**
|
||||
|
|
@ -1058,6 +1082,7 @@ export type UpdateCampaignRequest = {
|
|||
retry_config?: RetryConfigRequest | null;
|
||||
max_concurrency?: number | null;
|
||||
schedule_config?: ScheduleConfigRequest | null;
|
||||
circuit_breaker?: CircuitBreakerConfigRequest | null;
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
@ -1574,6 +1599,35 @@ export type HandleCloudonixStatusCallbackApiV1TelephonyCloudonixStatusCallbackWo
|
|||
200: unknown;
|
||||
};
|
||||
|
||||
export type HandleCloudonixAmdCallbackApiV1TelephonyCloudonixAmdCallbackWorkflowRunIdPostData = {
|
||||
body?: never;
|
||||
path: {
|
||||
workflow_run_id: number;
|
||||
};
|
||||
query?: never;
|
||||
url: '/api/v1/telephony/cloudonix/amd-callback/{workflow_run_id}';
|
||||
};
|
||||
|
||||
export type HandleCloudonixAmdCallbackApiV1TelephonyCloudonixAmdCallbackWorkflowRunIdPostErrors = {
|
||||
/**
|
||||
* Not found
|
||||
*/
|
||||
404: unknown;
|
||||
/**
|
||||
* Validation Error
|
||||
*/
|
||||
422: HttpValidationError;
|
||||
};
|
||||
|
||||
export type HandleCloudonixAmdCallbackApiV1TelephonyCloudonixAmdCallbackWorkflowRunIdPostError = HandleCloudonixAmdCallbackApiV1TelephonyCloudonixAmdCallbackWorkflowRunIdPostErrors[keyof HandleCloudonixAmdCallbackApiV1TelephonyCloudonixAmdCallbackWorkflowRunIdPostErrors];
|
||||
|
||||
export type HandleCloudonixAmdCallbackApiV1TelephonyCloudonixAmdCallbackWorkflowRunIdPostResponses = {
|
||||
/**
|
||||
* Successful Response
|
||||
*/
|
||||
200: unknown;
|
||||
};
|
||||
|
||||
export type HandleVobizHangupCallbackByWorkflowApiV1TelephonyVobizHangupCallbackWorkflowWorkflowIdPostData = {
|
||||
body?: never;
|
||||
headers?: {
|
||||
|
|
@ -3593,7 +3647,7 @@ export type SaveTelephonyConfigurationApiV1OrganizationsTelephonyConfigPostRespo
|
|||
200: unknown;
|
||||
};
|
||||
|
||||
export type GetCampaignLimitsApiV1OrganizationsCampaignLimitsGetData = {
|
||||
export type GetCampaignDefaultsApiV1OrganizationsCampaignDefaultsGetData = {
|
||||
body?: never;
|
||||
headers?: {
|
||||
authorization?: string | null;
|
||||
|
|
@ -3601,10 +3655,10 @@ export type GetCampaignLimitsApiV1OrganizationsCampaignLimitsGetData = {
|
|||
};
|
||||
path?: never;
|
||||
query?: never;
|
||||
url: '/api/v1/organizations/campaign-limits';
|
||||
url: '/api/v1/organizations/campaign-defaults';
|
||||
};
|
||||
|
||||
export type GetCampaignLimitsApiV1OrganizationsCampaignLimitsGetErrors = {
|
||||
export type GetCampaignDefaultsApiV1OrganizationsCampaignDefaultsGetErrors = {
|
||||
/**
|
||||
* Not found
|
||||
*/
|
||||
|
|
@ -3615,16 +3669,16 @@ export type GetCampaignLimitsApiV1OrganizationsCampaignLimitsGetErrors = {
|
|||
422: HttpValidationError;
|
||||
};
|
||||
|
||||
export type GetCampaignLimitsApiV1OrganizationsCampaignLimitsGetError = GetCampaignLimitsApiV1OrganizationsCampaignLimitsGetErrors[keyof GetCampaignLimitsApiV1OrganizationsCampaignLimitsGetErrors];
|
||||
export type GetCampaignDefaultsApiV1OrganizationsCampaignDefaultsGetError = GetCampaignDefaultsApiV1OrganizationsCampaignDefaultsGetErrors[keyof GetCampaignDefaultsApiV1OrganizationsCampaignDefaultsGetErrors];
|
||||
|
||||
export type GetCampaignLimitsApiV1OrganizationsCampaignLimitsGetResponses = {
|
||||
export type GetCampaignDefaultsApiV1OrganizationsCampaignDefaultsGetResponses = {
|
||||
/**
|
||||
* Successful Response
|
||||
*/
|
||||
200: CampaignLimitsResponse;
|
||||
200: CampaignDefaultsResponse;
|
||||
};
|
||||
|
||||
export type GetCampaignLimitsApiV1OrganizationsCampaignLimitsGetResponse = GetCampaignLimitsApiV1OrganizationsCampaignLimitsGetResponses[keyof GetCampaignLimitsApiV1OrganizationsCampaignLimitsGetResponses];
|
||||
export type GetCampaignDefaultsApiV1OrganizationsCampaignDefaultsGetResponse = GetCampaignDefaultsApiV1OrganizationsCampaignDefaultsGetResponses[keyof GetCampaignDefaultsApiV1OrganizationsCampaignDefaultsGetResponses];
|
||||
|
||||
export type GetSignedUrlApiV1S3SignedUrlGetData = {
|
||||
body?: never;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue