Add webhook callback url in run workflow form (#1035)
This commit is contained in:
@@ -5,6 +5,7 @@ import {
|
|||||||
FormField,
|
FormField,
|
||||||
FormItem,
|
FormItem,
|
||||||
FormLabel,
|
FormLabel,
|
||||||
|
FormMessage,
|
||||||
} from "@/components/ui/form";
|
} from "@/components/ui/form";
|
||||||
import { useCredentialGetter } from "@/hooks/useCredentialGetter";
|
import { useCredentialGetter } from "@/hooks/useCredentialGetter";
|
||||||
import { useMutation, useQueryClient } from "@tanstack/react-query";
|
import { useMutation, useQueryClient } from "@tanstack/react-query";
|
||||||
@@ -20,6 +21,8 @@ import { apiBaseUrl } from "@/util/env";
|
|||||||
import { useApiCredential } from "@/hooks/useApiCredential";
|
import { useApiCredential } from "@/hooks/useApiCredential";
|
||||||
import { copyText } from "@/util/copyText";
|
import { copyText } from "@/util/copyText";
|
||||||
import { WorkflowParameter } from "./types/workflowTypes";
|
import { WorkflowParameter } from "./types/workflowTypes";
|
||||||
|
import { Input } from "@/components/ui/input";
|
||||||
|
import { z } from "zod";
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
workflowParameters: Array<WorkflowParameter>;
|
workflowParameters: Array<WorkflowParameter>;
|
||||||
@@ -61,20 +64,33 @@ function RunWorkflowForm({ workflowParameters, initialValues }: Props) {
|
|||||||
const { workflowPermanentId } = useParams();
|
const { workflowPermanentId } = useParams();
|
||||||
const credentialGetter = useCredentialGetter();
|
const credentialGetter = useCredentialGetter();
|
||||||
const queryClient = useQueryClient();
|
const queryClient = useQueryClient();
|
||||||
const form = useForm({
|
const form = useForm<Record<string, unknown>>({
|
||||||
defaultValues: initialValues,
|
defaultValues: { ...initialValues, webhookCallbackUrl: null },
|
||||||
});
|
});
|
||||||
const apiCredential = useApiCredential();
|
const apiCredential = useApiCredential();
|
||||||
|
|
||||||
const runWorkflowMutation = useMutation({
|
const runWorkflowMutation = useMutation({
|
||||||
mutationFn: async (values: Record<string, unknown>) => {
|
mutationFn: async (values: Record<string, unknown>) => {
|
||||||
const client = await getClient(credentialGetter);
|
const client = await getClient(credentialGetter);
|
||||||
|
|
||||||
|
const { webhookCallbackUrl, ...parameters } = values;
|
||||||
|
|
||||||
|
const body: {
|
||||||
|
data: Record<string, unknown>;
|
||||||
|
proxy_location: string;
|
||||||
|
webhook_callback_url?: string;
|
||||||
|
} = {
|
||||||
|
data: parameters,
|
||||||
|
proxy_location: "RESIDENTIAL",
|
||||||
|
};
|
||||||
|
|
||||||
|
if (webhookCallbackUrl) {
|
||||||
|
body.webhook_callback_url = webhookCallbackUrl as string;
|
||||||
|
}
|
||||||
|
|
||||||
return client.post<unknown, { data: { workflow_run_id: string } }>(
|
return client.post<unknown, { data: { workflow_run_id: string } }>(
|
||||||
`/workflows/${workflowPermanentId}/run`,
|
`/workflows/${workflowPermanentId}/run`,
|
||||||
{
|
body,
|
||||||
data: values,
|
|
||||||
proxy_location: "RESIDENTIAL",
|
|
||||||
},
|
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
onSuccess: (response) => {
|
onSuccess: (response) => {
|
||||||
@@ -114,75 +130,135 @@ function RunWorkflowForm({ workflowParameters, initialValues }: Props) {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<Form {...form}>
|
<Form {...form}>
|
||||||
<form
|
<form onSubmit={form.handleSubmit(onSubmit)} className="space-y-8">
|
||||||
onSubmit={form.handleSubmit(onSubmit)}
|
<div className="space-y-8 rounded-lg bg-slate-elevation3 px-6 py-5">
|
||||||
className="space-y-8 rounded-lg bg-slate-elevation3 px-6 py-5"
|
<header>
|
||||||
>
|
<h1 className="text-lg">Workflow Parameters</h1>
|
||||||
{workflowParameters?.map((parameter) => {
|
</header>
|
||||||
return (
|
{workflowParameters?.map((parameter) => {
|
||||||
<FormField
|
return (
|
||||||
key={parameter.key}
|
<FormField
|
||||||
control={form.control}
|
key={parameter.key}
|
||||||
name={parameter.key}
|
control={form.control}
|
||||||
rules={{
|
name={parameter.key}
|
||||||
validate: (value) => {
|
rules={{
|
||||||
if (
|
validate: (value) => {
|
||||||
parameter.workflow_parameter_type === "json" &&
|
if (
|
||||||
typeof value === "string"
|
parameter.workflow_parameter_type === "json" &&
|
||||||
) {
|
typeof value === "string"
|
||||||
try {
|
) {
|
||||||
JSON.parse(value);
|
try {
|
||||||
return true;
|
JSON.parse(value);
|
||||||
} catch (e) {
|
return true;
|
||||||
return "Invalid JSON";
|
} catch (e) {
|
||||||
|
return "Invalid JSON";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
if (value === null) {
|
||||||
if (value === null) {
|
return "This field is required";
|
||||||
return "This field is required";
|
}
|
||||||
}
|
},
|
||||||
},
|
}}
|
||||||
}}
|
render={({ field }) => {
|
||||||
render={({ field }) => {
|
return (
|
||||||
return (
|
<FormItem>
|
||||||
<FormItem>
|
<div className="flex gap-16">
|
||||||
<div className="flex gap-16">
|
<FormLabel>
|
||||||
<FormLabel>
|
<div className="w-72">
|
||||||
<div className="w-72">
|
<div className="flex items-center gap-2 text-lg">
|
||||||
<div className="flex items-center gap-2 text-lg">
|
{parameter.key}
|
||||||
{parameter.key}
|
<span className="text-sm text-slate-400">
|
||||||
<span className="text-sm text-slate-400">
|
{parameter.workflow_parameter_type}
|
||||||
{parameter.workflow_parameter_type}
|
</span>
|
||||||
</span>
|
</div>
|
||||||
|
<h2 className="text-sm text-slate-400">
|
||||||
|
{parameter.description}
|
||||||
|
</h2>
|
||||||
</div>
|
</div>
|
||||||
<h2 className="text-sm text-slate-400">
|
</FormLabel>
|
||||||
{parameter.description}
|
<div className="w-full space-y-2">
|
||||||
</h2>
|
<FormControl>
|
||||||
|
<WorkflowParameterInput
|
||||||
|
type={parameter.workflow_parameter_type}
|
||||||
|
value={field.value}
|
||||||
|
onChange={field.onChange}
|
||||||
|
/>
|
||||||
|
</FormControl>
|
||||||
|
{form.formState.errors[parameter.key] && (
|
||||||
|
<div className="text-destructive">
|
||||||
|
{form.formState.errors[parameter.key]?.message}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
</FormLabel>
|
|
||||||
<div className="w-full space-y-2">
|
|
||||||
<FormControl>
|
|
||||||
<WorkflowParameterInput
|
|
||||||
type={parameter.workflow_parameter_type}
|
|
||||||
value={field.value}
|
|
||||||
onChange={field.onChange}
|
|
||||||
/>
|
|
||||||
</FormControl>
|
|
||||||
{form.formState.errors[parameter.key] && (
|
|
||||||
<div className="text-destructive">
|
|
||||||
{form.formState.errors[parameter.key]?.message}
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</div>
|
</div>
|
||||||
|
</FormItem>
|
||||||
|
);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
{workflowParameters.length === 0 && (
|
||||||
|
<div>No workflow parameters for this workflow.</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="space-y-8 rounded-lg bg-slate-elevation3 px-6 py-5">
|
||||||
|
<header>
|
||||||
|
<h1 className="text-lg">Advanced Settings</h1>
|
||||||
|
</header>
|
||||||
|
<FormField
|
||||||
|
key="webhookCallbackUrl"
|
||||||
|
control={form.control}
|
||||||
|
name={"webhookCallbackUrl"}
|
||||||
|
rules={{
|
||||||
|
validate: (value) => {
|
||||||
|
if (value === null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (typeof value !== "string") {
|
||||||
|
return "Invalid URL";
|
||||||
|
}
|
||||||
|
const urlSchema = z.string().url({ message: "Invalid URL" });
|
||||||
|
const { success } = urlSchema.safeParse(value);
|
||||||
|
if (!success) {
|
||||||
|
return "Invalid URL";
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
render={({ field }) => {
|
||||||
|
return (
|
||||||
|
<FormItem>
|
||||||
|
<div className="flex gap-16">
|
||||||
|
<FormLabel>
|
||||||
|
<div className="w-72">
|
||||||
|
<div className="flex items-center gap-2 text-lg">
|
||||||
|
Webhook Callback URL
|
||||||
|
</div>
|
||||||
|
<h2 className="text-sm text-slate-400">
|
||||||
|
The URL of a webhook endpoint to send the details of
|
||||||
|
the workflow result.
|
||||||
|
</h2>
|
||||||
|
</div>
|
||||||
|
</FormLabel>
|
||||||
|
<div className="w-full space-y-2">
|
||||||
|
<FormControl>
|
||||||
|
<Input
|
||||||
|
{...field}
|
||||||
|
placeholder="https://"
|
||||||
|
value={
|
||||||
|
field.value === null ? "" : (field.value as string)
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
</FormControl>
|
||||||
|
<FormMessage />
|
||||||
</div>
|
</div>
|
||||||
</FormItem>
|
</div>
|
||||||
);
|
</FormItem>
|
||||||
}}
|
);
|
||||||
/>
|
}}
|
||||||
);
|
/>
|
||||||
})}
|
</div>
|
||||||
{workflowParameters.length === 0 && (
|
|
||||||
<div>No workflow parameters for this workflow.</div>
|
|
||||||
)}
|
|
||||||
<div className="flex justify-end gap-2">
|
<div className="flex justify-end gap-2">
|
||||||
<Button
|
<Button
|
||||||
type="button"
|
type="button"
|
||||||
|
|||||||
Reference in New Issue
Block a user