mirror of
https://github.com/dograh-hq/dograh.git
synced 2026-06-19 08:28:10 +02:00
feat: add redial option in campaigns
This commit is contained in:
parent
79116e6af2
commit
7fab959e26
14 changed files with 998 additions and 58 deletions
|
|
@ -1,7 +1,7 @@
|
|||
"use client";
|
||||
|
||||
import { format } from 'date-fns';
|
||||
import { ArrowLeft, CalendarIcon, Check, Clock, Download, Pause, Pencil, Play, RefreshCw, X } from 'lucide-react';
|
||||
import { ArrowLeft, CalendarIcon, Check, Clock, Download, Pause, Pencil, Phone, Play, RefreshCw, X } from 'lucide-react';
|
||||
import { useParams, useRouter, useSearchParams } from 'next/navigation';
|
||||
import { useCallback, useEffect, useState } from 'react';
|
||||
import { toast } from 'sonner';
|
||||
|
|
@ -11,6 +11,7 @@ import {
|
|||
getCampaignApiV1CampaignCampaignIdGet,
|
||||
getCampaignSourceDownloadUrlApiV1CampaignCampaignIdSourceDownloadUrlGet,
|
||||
pauseCampaignApiV1CampaignCampaignIdPausePost,
|
||||
redialCampaignApiV1CampaignCampaignIdRedialPost,
|
||||
resumeCampaignApiV1CampaignCampaignIdResumePost,
|
||||
startCampaignApiV1CampaignCampaignIdStartPost,
|
||||
} from '@/client/sdk.gen';
|
||||
|
|
@ -19,6 +20,8 @@ import { Badge } from '@/components/ui/badge';
|
|||
import { Button } from '@/components/ui/button';
|
||||
import { Calendar } from '@/components/ui/calendar';
|
||||
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card';
|
||||
import { Checkbox } from '@/components/ui/checkbox';
|
||||
import { Dialog, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle } from '@/components/ui/dialog';
|
||||
import { Input } from '@/components/ui/input';
|
||||
import { Label } from '@/components/ui/label';
|
||||
import { Popover, PopoverContent, PopoverTrigger } from '@/components/ui/popover';
|
||||
|
|
@ -55,6 +58,14 @@ export default function CampaignDetailPage() {
|
|||
const [reportEndTime, setReportEndTime] = useState('23:59');
|
||||
const [isReportPopoverOpen, setIsReportPopoverOpen] = useState(false);
|
||||
|
||||
// Redial dialog state
|
||||
const [isRedialDialogOpen, setIsRedialDialogOpen] = useState(false);
|
||||
const [redialName, setRedialName] = useState('');
|
||||
const [redialOnVoicemail, setRedialOnVoicemail] = useState(true);
|
||||
const [redialOnNoAnswer, setRedialOnNoAnswer] = useState(true);
|
||||
const [redialOnBusy, setRedialOnBusy] = useState(true);
|
||||
const [isRedialing, setIsRedialing] = useState(false);
|
||||
|
||||
// Fetch campaign details
|
||||
const fetchCampaign = useCallback(async () => {
|
||||
if (!user) return;
|
||||
|
|
@ -258,6 +269,62 @@ export default function CampaignDetailPage() {
|
|||
}
|
||||
};
|
||||
|
||||
// Open redial dialog with default name
|
||||
const openRedialDialog = () => {
|
||||
if (!campaign) return;
|
||||
setRedialName(`${campaign.name} (Redial)`);
|
||||
setRedialOnVoicemail(true);
|
||||
setRedialOnNoAnswer(true);
|
||||
setRedialOnBusy(true);
|
||||
setIsRedialDialogOpen(true);
|
||||
};
|
||||
|
||||
// Handle redial campaign
|
||||
const handleRedial = async () => {
|
||||
if (!user || !campaign) return;
|
||||
if (!redialOnVoicemail && !redialOnNoAnswer && !redialOnBusy) {
|
||||
toast.error('Select at least one reason to redial');
|
||||
return;
|
||||
}
|
||||
setIsRedialing(true);
|
||||
try {
|
||||
const accessToken = await getAccessToken();
|
||||
const response = await redialCampaignApiV1CampaignCampaignIdRedialPost({
|
||||
path: {
|
||||
campaign_id: campaignId,
|
||||
},
|
||||
body: {
|
||||
name: redialName || null,
|
||||
retry_on_voicemail: redialOnVoicemail,
|
||||
retry_on_no_answer: redialOnNoAnswer,
|
||||
retry_on_busy: redialOnBusy,
|
||||
},
|
||||
headers: {
|
||||
'Authorization': `Bearer ${accessToken}`,
|
||||
}
|
||||
});
|
||||
|
||||
if (response.data) {
|
||||
toast.success('Redial campaign created');
|
||||
setIsRedialDialogOpen(false);
|
||||
router.push(`/campaigns/${response.data.id}`);
|
||||
} else if (response.error) {
|
||||
let errorMsg = 'Failed to create redial campaign';
|
||||
if (typeof response.error === 'string') {
|
||||
errorMsg = response.error;
|
||||
} else if (response.error && typeof response.error === 'object') {
|
||||
errorMsg = (response.error as unknown as { detail?: string }).detail || JSON.stringify(response.error);
|
||||
}
|
||||
toast.error(errorMsg);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Failed to redial campaign:', error);
|
||||
toast.error('Failed to create redial campaign');
|
||||
} finally {
|
||||
setIsRedialing(false);
|
||||
}
|
||||
};
|
||||
|
||||
// Handle pause campaign
|
||||
const handlePause = async () => {
|
||||
if (!user) return;
|
||||
|
|
@ -356,6 +423,16 @@ export default function CampaignDetailPage() {
|
|||
</Button>
|
||||
</div>
|
||||
);
|
||||
case 'completed':
|
||||
if (campaign.redialed_campaign_id) {
|
||||
return null;
|
||||
}
|
||||
return (
|
||||
<Button onClick={openRedialDialog}>
|
||||
<Phone className="h-4 w-4 mr-2" />
|
||||
Redial Campaign
|
||||
</Button>
|
||||
);
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
|
|
@ -541,6 +618,38 @@ export default function CampaignDetailPage() {
|
|||
<dt className="text-sm font-medium">State</dt>
|
||||
<dd className="mt-1 capitalize">{campaign.state}</dd>
|
||||
</div>
|
||||
<div>
|
||||
<dt className="text-sm font-medium">Progress</dt>
|
||||
<dd className="mt-1">
|
||||
{campaign.executed_count} / {campaign.total_queued_count}
|
||||
</dd>
|
||||
</div>
|
||||
{campaign.parent_campaign_id && (
|
||||
<div>
|
||||
<dt className="text-sm font-medium">Redial Of</dt>
|
||||
<dd className="mt-1">
|
||||
<button
|
||||
onClick={() => router.push(`/campaigns/${campaign.parent_campaign_id}`)}
|
||||
className="text-blue-600 hover:text-blue-800 hover:underline"
|
||||
>
|
||||
Campaign #{campaign.parent_campaign_id}
|
||||
</button>
|
||||
</dd>
|
||||
</div>
|
||||
)}
|
||||
{campaign.redialed_campaign_id && (
|
||||
<div>
|
||||
<dt className="text-sm font-medium">Redialed As</dt>
|
||||
<dd className="mt-1">
|
||||
<button
|
||||
onClick={() => router.push(`/campaigns/${campaign.redialed_campaign_id}`)}
|
||||
className="text-blue-600 hover:text-blue-800 hover:underline"
|
||||
>
|
||||
Campaign #{campaign.redialed_campaign_id}
|
||||
</button>
|
||||
</dd>
|
||||
</div>
|
||||
)}
|
||||
{campaign.started_at && (
|
||||
<div>
|
||||
<dt className="text-sm font-medium">Started At</dt>
|
||||
|
|
@ -678,6 +787,75 @@ export default function CampaignDetailPage() {
|
|||
workflowId={campaign.workflow_id}
|
||||
searchParams={searchParams}
|
||||
/>
|
||||
|
||||
<Dialog open={isRedialDialogOpen} onOpenChange={setIsRedialDialogOpen}>
|
||||
<DialogContent>
|
||||
<DialogHeader>
|
||||
<DialogTitle>Redial Campaign</DialogTitle>
|
||||
<DialogDescription>
|
||||
Creates a new campaign that re-dials unique subscribers whose
|
||||
last call ended with one of the selected outcomes. Subscribers
|
||||
who were successfully reached on a retry are skipped.
|
||||
</DialogDescription>
|
||||
</DialogHeader>
|
||||
<div className="space-y-4 py-2">
|
||||
<div className="space-y-1.5">
|
||||
<Label htmlFor="redial-name">Name</Label>
|
||||
<Input
|
||||
id="redial-name"
|
||||
value={redialName}
|
||||
onChange={(e) => setRedialName(e.target.value)}
|
||||
placeholder="Campaign name"
|
||||
/>
|
||||
</div>
|
||||
<div className="space-y-3">
|
||||
<Label>Redial when last call was</Label>
|
||||
<div className="flex items-center gap-2">
|
||||
<Checkbox
|
||||
id="redial-voicemail"
|
||||
checked={redialOnVoicemail}
|
||||
onCheckedChange={(v) => setRedialOnVoicemail(v === true)}
|
||||
/>
|
||||
<Label htmlFor="redial-voicemail" className="font-normal">
|
||||
Voicemail
|
||||
</Label>
|
||||
</div>
|
||||
<div className="flex items-center gap-2">
|
||||
<Checkbox
|
||||
id="redial-no-answer"
|
||||
checked={redialOnNoAnswer}
|
||||
onCheckedChange={(v) => setRedialOnNoAnswer(v === true)}
|
||||
/>
|
||||
<Label htmlFor="redial-no-answer" className="font-normal">
|
||||
No Answer
|
||||
</Label>
|
||||
</div>
|
||||
<div className="flex items-center gap-2">
|
||||
<Checkbox
|
||||
id="redial-busy"
|
||||
checked={redialOnBusy}
|
||||
onCheckedChange={(v) => setRedialOnBusy(v === true)}
|
||||
/>
|
||||
<Label htmlFor="redial-busy" className="font-normal">
|
||||
Busy
|
||||
</Label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<DialogFooter>
|
||||
<Button
|
||||
variant="outline"
|
||||
onClick={() => setIsRedialDialogOpen(false)}
|
||||
disabled={isRedialing}
|
||||
>
|
||||
Cancel
|
||||
</Button>
|
||||
<Button onClick={handleRedial} disabled={isRedialing}>
|
||||
{isRedialing ? 'Creating...' : 'Create Redial Campaign'}
|
||||
</Button>
|
||||
</DialogFooter>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -129,6 +129,7 @@ export default function CampaignsPage() {
|
|||
<TableHead>Name</TableHead>
|
||||
<TableHead>Workflow</TableHead>
|
||||
<TableHead>State</TableHead>
|
||||
<TableHead>Progress</TableHead>
|
||||
<TableHead>Created</TableHead>
|
||||
<TableHead className="text-right">Action</TableHead>
|
||||
</TableRow>
|
||||
|
|
@ -148,6 +149,9 @@ export default function CampaignsPage() {
|
|||
{campaign.state}
|
||||
</Badge>
|
||||
</TableCell>
|
||||
<TableCell>
|
||||
{campaign.executed_count} / {campaign.total_queued_count}
|
||||
</TableCell>
|
||||
<TableCell>{formatDate(campaign.created_at)}</TableCell>
|
||||
<TableCell className="text-right">
|
||||
<Button
|
||||
|
|
|
|||
|
|
@ -1,20 +1,24 @@
|
|||
"use client";
|
||||
|
||||
import { ArrowLeft, BookA, Brain, ExternalLink, Loader2, Mic, Pause, PhoneOff, Play, Rocket, Settings, Trash2Icon, Upload, Variable, X } from "lucide-react";
|
||||
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 Link from "next/link";
|
||||
import { useParams, useRouter } from "next/navigation";
|
||||
import { useEffect, useMemo, useRef, useState } from "react";
|
||||
import { toast } from "sonner";
|
||||
|
||||
import { getAmbientNoiseUploadUrlApiV1WorkflowAmbientNoiseUploadUrlPost, getWorkflowApiV1WorkflowFetchWorkflowIdGet } from "@/client/sdk.gen";
|
||||
import { downloadWorkflowReportApiV1WorkflowWorkflowIdReportGet, getAmbientNoiseUploadUrlApiV1WorkflowAmbientNoiseUploadUrlPost, getWorkflowApiV1WorkflowFetchWorkflowIdGet } from "@/client/sdk.gen";
|
||||
import type { WorkflowResponse } from "@/client/types.gen";
|
||||
import { FlowEdge, FlowNode } from "@/components/flow/types";
|
||||
import { LLMConfigSelector } from "@/components/LLMConfigSelector";
|
||||
import { ServiceConfigurationForm } from "@/components/ServiceConfigurationForm";
|
||||
import SpinLoader from "@/components/SpinLoader";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { Calendar } from "@/components/ui/calendar";
|
||||
import { Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle } from "@/components/ui/card";
|
||||
import { Input } from "@/components/ui/input";
|
||||
import { Label } from "@/components/ui/label";
|
||||
import { Popover, PopoverContent, PopoverTrigger } from "@/components/ui/popover";
|
||||
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select";
|
||||
import { Separator } from "@/components/ui/separator";
|
||||
import { Switch } from "@/components/ui/switch";
|
||||
|
|
@ -76,8 +80,166 @@ const NAV_ITEMS = [
|
|||
{ id: "voicemail", label: "Voicemail Detection", icon: PhoneOff },
|
||||
{ id: "recordings", label: "Recordings", icon: Mic },
|
||||
{ id: "deployment", label: "Deployment", icon: Rocket },
|
||||
{ id: "report", label: "Report", icon: FileDown },
|
||||
];
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Section: Report
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
function ReportSection({ workflowId }: { workflowId: number }) {
|
||||
const [startDate, setStartDate] = useState<Date | undefined>(undefined);
|
||||
const [startTime, setStartTime] = useState("00:00");
|
||||
const [endDate, setEndDate] = useState<Date | undefined>(undefined);
|
||||
const [endTime, setEndTime] = useState("23:59");
|
||||
const [isPopoverOpen, setIsPopoverOpen] = useState(false);
|
||||
const [isDownloading, setIsDownloading] = useState(false);
|
||||
|
||||
const buildDateTime = (date: Date | undefined, time: string): string | undefined => {
|
||||
if (!date) return undefined;
|
||||
const [hours, minutes] = time.split(":").map(Number);
|
||||
const combined = new Date(date);
|
||||
combined.setHours(hours, minutes, 0, 0);
|
||||
return combined.toISOString();
|
||||
};
|
||||
|
||||
const handleDownload = async () => {
|
||||
setIsDownloading(true);
|
||||
setIsPopoverOpen(false);
|
||||
try {
|
||||
const response = await downloadWorkflowReportApiV1WorkflowWorkflowIdReportGet({
|
||||
path: { workflow_id: workflowId },
|
||||
query: {
|
||||
start_date: buildDateTime(startDate, startTime),
|
||||
end_date: buildDateTime(endDate, endTime),
|
||||
},
|
||||
parseAs: "blob",
|
||||
});
|
||||
|
||||
if (response.data) {
|
||||
const blob = response.data as Blob;
|
||||
const url = window.URL.createObjectURL(blob);
|
||||
const a = document.createElement("a");
|
||||
a.href = url;
|
||||
a.download = `workflow_${workflowId}_report.csv`;
|
||||
document.body.appendChild(a);
|
||||
a.click();
|
||||
a.remove();
|
||||
window.URL.revokeObjectURL(url);
|
||||
} else {
|
||||
toast.error("Failed to download report");
|
||||
}
|
||||
} catch (err) {
|
||||
logger.error(`Failed to download workflow report: ${err}`);
|
||||
toast.error("Failed to download report");
|
||||
} finally {
|
||||
setIsDownloading(false);
|
||||
}
|
||||
};
|
||||
|
||||
const handleClear = () => {
|
||||
setStartDate(undefined);
|
||||
setStartTime("00:00");
|
||||
setEndDate(undefined);
|
||||
setEndTime("23:59");
|
||||
};
|
||||
|
||||
return (
|
||||
<Card id="report">
|
||||
<CardHeader>
|
||||
<CardTitle className="flex items-center gap-2 text-base">
|
||||
<FileDown className="h-4 w-4" />
|
||||
Report
|
||||
</CardTitle>
|
||||
<CardDescription>
|
||||
Download a CSV report of completed runs for this agent, optionally filtered by date range.
|
||||
</CardDescription>
|
||||
</CardHeader>
|
||||
<CardFooter className="border-t pt-6">
|
||||
<Popover open={isPopoverOpen} onOpenChange={setIsPopoverOpen}>
|
||||
<PopoverTrigger asChild>
|
||||
<Button variant="outline" disabled={isDownloading}>
|
||||
<Download className="h-4 w-4 mr-2" />
|
||||
Download Report
|
||||
</Button>
|
||||
</PopoverTrigger>
|
||||
<PopoverContent className="w-auto p-4" align="start">
|
||||
<div className="space-y-4">
|
||||
<div className="text-sm font-medium">Filter by date range</div>
|
||||
<div className="grid gap-3">
|
||||
<div className="space-y-1.5">
|
||||
<Label className="text-xs">From</Label>
|
||||
<div className="flex gap-2">
|
||||
<Popover>
|
||||
<PopoverTrigger asChild>
|
||||
<Button variant="outline" size="sm" className="w-[140px] justify-start text-left font-normal">
|
||||
<CalendarIcon className="mr-2 h-3.5 w-3.5" />
|
||||
{startDate ? format(startDate, "MMM dd, yyyy") : "Start date"}
|
||||
</Button>
|
||||
</PopoverTrigger>
|
||||
<PopoverContent className="w-auto p-0" align="start">
|
||||
<Calendar
|
||||
mode="single"
|
||||
selected={startDate}
|
||||
onSelect={setStartDate}
|
||||
disabled={(date) => (endDate ? date > endDate : false)}
|
||||
/>
|
||||
</PopoverContent>
|
||||
</Popover>
|
||||
<Input
|
||||
type="time"
|
||||
value={startTime}
|
||||
onChange={(e) => setStartTime(e.target.value)}
|
||||
className="w-[100px] h-8 text-xs"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div className="space-y-1.5">
|
||||
<Label className="text-xs">To</Label>
|
||||
<div className="flex gap-2">
|
||||
<Popover>
|
||||
<PopoverTrigger asChild>
|
||||
<Button variant="outline" size="sm" className="w-[140px] justify-start text-left font-normal">
|
||||
<CalendarIcon className="mr-2 h-3.5 w-3.5" />
|
||||
{endDate ? format(endDate, "MMM dd, yyyy") : "End date"}
|
||||
</Button>
|
||||
</PopoverTrigger>
|
||||
<PopoverContent className="w-auto p-0" align="start">
|
||||
<Calendar
|
||||
mode="single"
|
||||
selected={endDate}
|
||||
onSelect={setEndDate}
|
||||
disabled={(date) => (startDate ? date < startDate : false)}
|
||||
/>
|
||||
</PopoverContent>
|
||||
</Popover>
|
||||
<Input
|
||||
type="time"
|
||||
value={endTime}
|
||||
onChange={(e) => setEndTime(e.target.value)}
|
||||
className="w-[100px] h-8 text-xs"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<Separator />
|
||||
<div className="flex justify-between">
|
||||
<Button variant="ghost" size="sm" onClick={handleClear}>
|
||||
Clear
|
||||
</Button>
|
||||
<Button size="sm" onClick={handleDownload} disabled={isDownloading}>
|
||||
<Download className="h-3.5 w-3.5 mr-1.5" />
|
||||
{startDate || endDate ? "Download Filtered" : "Download All"}
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</PopoverContent>
|
||||
</Popover>
|
||||
</CardFooter>
|
||||
</Card>
|
||||
);
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Section: General
|
||||
// ---------------------------------------------------------------------------
|
||||
|
|
@ -1098,6 +1260,9 @@ function WorkflowSettingsInner({
|
|||
</Button>
|
||||
</CardFooter>
|
||||
</Card>
|
||||
|
||||
{/* Report */}
|
||||
<ReportSection workflowId={workflowId} />
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
|
|
|
|||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
|
@ -467,6 +467,22 @@ export type CampaignResponse = {
|
|||
max_concurrency?: number | null;
|
||||
schedule_config?: ScheduleConfigResponse | null;
|
||||
circuit_breaker?: CircuitBreakerConfigResponse | null;
|
||||
/**
|
||||
* Executed Count
|
||||
*/
|
||||
executed_count?: number;
|
||||
/**
|
||||
* Total Queued Count
|
||||
*/
|
||||
total_queued_count?: number;
|
||||
/**
|
||||
* Parent Campaign Id
|
||||
*/
|
||||
parent_campaign_id?: number | null;
|
||||
/**
|
||||
* Redialed Campaign Id
|
||||
*/
|
||||
redialed_campaign_id?: number | null;
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
@ -2282,6 +2298,31 @@ export type RecordingUploadResponseSchema = {
|
|||
storage_key: string;
|
||||
};
|
||||
|
||||
/**
|
||||
* RedialCampaignRequest
|
||||
*/
|
||||
export type RedialCampaignRequest = {
|
||||
/**
|
||||
* Name
|
||||
*
|
||||
* Name for the redial campaign
|
||||
*/
|
||||
name?: string | null;
|
||||
/**
|
||||
* Retry On Voicemail
|
||||
*/
|
||||
retry_on_voicemail?: boolean;
|
||||
/**
|
||||
* Retry On No Answer
|
||||
*/
|
||||
retry_on_no_answer?: boolean;
|
||||
/**
|
||||
* Retry On Busy
|
||||
*/
|
||||
retry_on_busy?: boolean;
|
||||
retry_config?: RetryConfigRequest | null;
|
||||
};
|
||||
|
||||
/**
|
||||
* RetryConfigRequest
|
||||
*/
|
||||
|
|
@ -3267,6 +3308,10 @@ export type UserResponse = {
|
|||
* Organization Id
|
||||
*/
|
||||
organization_id?: number | null;
|
||||
/**
|
||||
* Provider Id
|
||||
*/
|
||||
provider_id?: string | null;
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
@ -5195,6 +5240,61 @@ export type GetWorkflowRunApiV1WorkflowWorkflowIdRunsRunIdGetResponses = {
|
|||
|
||||
export type GetWorkflowRunApiV1WorkflowWorkflowIdRunsRunIdGetResponse = GetWorkflowRunApiV1WorkflowWorkflowIdRunsRunIdGetResponses[keyof GetWorkflowRunApiV1WorkflowWorkflowIdRunsRunIdGetResponses];
|
||||
|
||||
export type DownloadWorkflowReportApiV1WorkflowWorkflowIdReportGetData = {
|
||||
body?: never;
|
||||
headers?: {
|
||||
/**
|
||||
* Authorization
|
||||
*/
|
||||
authorization?: string | null;
|
||||
/**
|
||||
* X-Api-Key
|
||||
*/
|
||||
'X-API-Key'?: string | null;
|
||||
};
|
||||
path: {
|
||||
/**
|
||||
* Workflow Id
|
||||
*/
|
||||
workflow_id: number;
|
||||
};
|
||||
query?: {
|
||||
/**
|
||||
* Start Date
|
||||
*
|
||||
* Filter runs created on or after this datetime (ISO 8601)
|
||||
*/
|
||||
start_date?: string | null;
|
||||
/**
|
||||
* End Date
|
||||
*
|
||||
* Filter runs created on or before this datetime (ISO 8601)
|
||||
*/
|
||||
end_date?: string | null;
|
||||
};
|
||||
url: '/api/v1/workflow/{workflow_id}/report';
|
||||
};
|
||||
|
||||
export type DownloadWorkflowReportApiV1WorkflowWorkflowIdReportGetErrors = {
|
||||
/**
|
||||
* Not found
|
||||
*/
|
||||
404: unknown;
|
||||
/**
|
||||
* Validation Error
|
||||
*/
|
||||
422: HttpValidationError;
|
||||
};
|
||||
|
||||
export type DownloadWorkflowReportApiV1WorkflowWorkflowIdReportGetError = DownloadWorkflowReportApiV1WorkflowWorkflowIdReportGetErrors[keyof DownloadWorkflowReportApiV1WorkflowWorkflowIdReportGetErrors];
|
||||
|
||||
export type DownloadWorkflowReportApiV1WorkflowWorkflowIdReportGetResponses = {
|
||||
/**
|
||||
* Successful Response
|
||||
*/
|
||||
200: unknown;
|
||||
};
|
||||
|
||||
export type GetWorkflowTemplatesApiV1WorkflowTemplatesGetData = {
|
||||
body?: never;
|
||||
path?: never;
|
||||
|
|
@ -6041,6 +6141,50 @@ export type GetCampaignRunsApiV1CampaignCampaignIdRunsGetResponses = {
|
|||
|
||||
export type GetCampaignRunsApiV1CampaignCampaignIdRunsGetResponse = GetCampaignRunsApiV1CampaignCampaignIdRunsGetResponses[keyof GetCampaignRunsApiV1CampaignCampaignIdRunsGetResponses];
|
||||
|
||||
export type RedialCampaignApiV1CampaignCampaignIdRedialPostData = {
|
||||
body: RedialCampaignRequest;
|
||||
headers?: {
|
||||
/**
|
||||
* Authorization
|
||||
*/
|
||||
authorization?: string | null;
|
||||
/**
|
||||
* X-Api-Key
|
||||
*/
|
||||
'X-API-Key'?: string | null;
|
||||
};
|
||||
path: {
|
||||
/**
|
||||
* Campaign Id
|
||||
*/
|
||||
campaign_id: number;
|
||||
};
|
||||
query?: never;
|
||||
url: '/api/v1/campaign/{campaign_id}/redial';
|
||||
};
|
||||
|
||||
export type RedialCampaignApiV1CampaignCampaignIdRedialPostErrors = {
|
||||
/**
|
||||
* Not found
|
||||
*/
|
||||
404: unknown;
|
||||
/**
|
||||
* Validation Error
|
||||
*/
|
||||
422: HttpValidationError;
|
||||
};
|
||||
|
||||
export type RedialCampaignApiV1CampaignCampaignIdRedialPostError = RedialCampaignApiV1CampaignCampaignIdRedialPostErrors[keyof RedialCampaignApiV1CampaignCampaignIdRedialPostErrors];
|
||||
|
||||
export type RedialCampaignApiV1CampaignCampaignIdRedialPostResponses = {
|
||||
/**
|
||||
* Successful Response
|
||||
*/
|
||||
200: CampaignResponse;
|
||||
};
|
||||
|
||||
export type RedialCampaignApiV1CampaignCampaignIdRedialPostResponse = RedialCampaignApiV1CampaignCampaignIdRedialPostResponses[keyof RedialCampaignApiV1CampaignCampaignIdRedialPostResponses];
|
||||
|
||||
export type ResumeCampaignApiV1CampaignCampaignIdResumePostData = {
|
||||
body?: never;
|
||||
headers?: {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue