Add proxy location to workflow run screen (#1158)

This commit is contained in:
Shuchang Zheng
2024-11-07 09:44:48 -08:00
committed by GitHub
parent 45477ab327
commit a6d6965f4b
2 changed files with 133 additions and 45 deletions

View File

@@ -12,6 +12,8 @@ export const ArtifactType = {
HTMLScrape: "html_scrape", HTMLScrape: "html_scrape",
} as const; } as const;
export type ArtifactType = (typeof ArtifactType)[keyof typeof ArtifactType];
export const Status = { export const Status = {
Created: "created", Created: "created",
Running: "running", Running: "running",
@@ -25,7 +27,16 @@ export const Status = {
export type Status = (typeof Status)[keyof typeof Status]; export type Status = (typeof Status)[keyof typeof Status];
export type ArtifactType = (typeof ArtifactType)[keyof typeof ArtifactType]; export const ProxyLocation = {
Residential: "RESIDENTIAL",
ResidentialIE: "RESIDENTIAL_IE",
ResidentialES: "RESIDENTIAL_ES",
ResidentialIN: "RESIDENTIAL_IN",
ResidentialJP: "RESIDENTIAL_JP",
None: "NONE",
} as const;
export type ProxyLocation = (typeof ProxyLocation)[keyof typeof ProxyLocation];
export type ArtifactApiResponse = { export type ArtifactApiResponse = {
created_at: string; created_at: string;
@@ -90,7 +101,7 @@ export type CreateTaskRequest = {
navigation_payload: Record<string, unknown> | string | null; navigation_payload: Record<string, unknown> | string | null;
extracted_information_schema: Record<string, unknown> | string | null; extracted_information_schema: Record<string, unknown> | string | null;
error_code_mapping: Record<string, string> | null; error_code_mapping: Record<string, string> | null;
proxy_location: string | null; proxy_location: ProxyLocation | null;
totp_verification_url: string | null; totp_verification_url: string | null;
totp_identifier: string | null; totp_identifier: string | null;
}; };
@@ -184,7 +195,7 @@ export type WorkflowApiResponse = {
parameters: Array<WorkflowParameter>; parameters: Array<WorkflowParameter>;
blocks: Array<WorkflowBlock>; blocks: Array<WorkflowBlock>;
}; };
proxy_location: string; proxy_location: ProxyLocation | null;
webhook_callback_url: string; webhook_callback_url: string;
created_at: string; created_at: string;
modified_at: string; modified_at: string;
@@ -248,7 +259,7 @@ export type WorkflowRunApiResponse = {
workflow_run_id: string; workflow_run_id: string;
workflow_id: string; workflow_id: string;
status: Status; status: Status;
proxy_location: string; proxy_location: ProxyLocation | null;
webhook_callback_url: string; webhook_callback_url: string;
created_at: string; created_at: string;
modified_at: string; modified_at: string;
@@ -258,7 +269,7 @@ export type WorkflowRunStatusApiResponse = {
workflow_id: string; workflow_id: string;
workflow_run_id: string; workflow_run_id: string;
status: Status; status: Status;
proxy_location: string; proxy_location: ProxyLocation | null;
webhook_callback_url: string | null; webhook_callback_url: string | null;
created_at: string; created_at: string;
modified_at: string; modified_at: string;

View File

@@ -23,6 +23,14 @@ import { copyText } from "@/util/copyText";
import { WorkflowParameter } from "./types/workflowTypes"; import { WorkflowParameter } from "./types/workflowTypes";
import { Input } from "@/components/ui/input"; import { Input } from "@/components/ui/input";
import { z } from "zod"; import { z } from "zod";
import { ProxyLocation } from "@/api/types";
import {
Select,
SelectContent,
SelectItem,
SelectTrigger,
SelectValue,
} from "@/components/ui/select";
type Props = { type Props = {
workflowParameters: Array<WorkflowParameter>; workflowParameters: Array<WorkflowParameter>;
@@ -60,38 +68,61 @@ function parseValuesForWorkflowRun(
); );
} }
type RunWorkflowRequestBody = {
data: Record<string, unknown>; // workflow parameters and values
proxy_location: ProxyLocation | null;
webhook_callback_url?: string | null;
};
function getRunWorkflowRequestBody(
values: RunWorkflowFormType,
workflowParameters: Array<WorkflowParameter>,
): RunWorkflowRequestBody {
const { webhookCallbackUrl, proxyLocation, ...parameters } = values;
const parsedParameters = parseValuesForWorkflowRun(
parameters,
workflowParameters,
);
const body: RunWorkflowRequestBody = {
data: parsedParameters,
proxy_location: proxyLocation,
};
if (webhookCallbackUrl) {
body.webhook_callback_url = webhookCallbackUrl;
}
return body;
}
type RunWorkflowFormType = Record<string, unknown> & {
webhookCallbackUrl: string | null;
proxyLocation: ProxyLocation | null;
};
function RunWorkflowForm({ workflowParameters, initialValues }: Props) { 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<Record<string, unknown>>({ const form = useForm<RunWorkflowFormType>({
defaultValues: { ...initialValues, webhookCallbackUrl: null }, defaultValues: {
...initialValues,
webhookCallbackUrl: null,
proxyLocation: ProxyLocation.Residential,
},
}); });
const apiCredential = useApiCredential(); const apiCredential = useApiCredential();
const runWorkflowMutation = useMutation({ const runWorkflowMutation = useMutation({
mutationFn: async (values: Record<string, unknown>) => { mutationFn: async (values: RunWorkflowFormType) => {
const client = await getClient(credentialGetter); const client = await getClient(credentialGetter);
const body = getRunWorkflowRequestBody(values, workflowParameters);
const { webhookCallbackUrl, ...parameters } = values; return client.post<
RunWorkflowRequestBody,
const body: { { data: { workflow_run_id: string } }
data: Record<string, unknown>; >(`/workflows/${workflowPermanentId}/run`, body);
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 } }>(
`/workflows/${workflowPermanentId}/run`,
body,
);
}, },
onSuccess: (response) => { onSuccess: (response) => {
toast({ toast({
@@ -123,8 +154,8 @@ function RunWorkflowForm({ workflowParameters, initialValues }: Props) {
}, },
}); });
function onSubmit(values: Record<string, unknown>) { function onSubmit(values: RunWorkflowFormType) {
const { webhookCallbackUrl, ...parameters } = values; const { webhookCallbackUrl, proxyLocation, ...parameters } = values;
const parsedParameters = parseValuesForWorkflowRun( const parsedParameters = parseValuesForWorkflowRun(
parameters, parameters,
workflowParameters, workflowParameters,
@@ -132,6 +163,7 @@ function RunWorkflowForm({ workflowParameters, initialValues }: Props) {
runWorkflowMutation.mutate({ runWorkflowMutation.mutate({
...parsedParameters, ...parsedParameters,
webhookCallbackUrl, webhookCallbackUrl,
proxyLocation,
}); });
} }
@@ -216,7 +248,7 @@ function RunWorkflowForm({ workflowParameters, initialValues }: Props) {
<FormField <FormField
key="webhookCallbackUrl" key="webhookCallbackUrl"
control={form.control} control={form.control}
name={"webhookCallbackUrl"} name="webhookCallbackUrl"
rules={{ rules={{
validate: (value) => { validate: (value) => {
if (value === null) { if (value === null) {
@@ -264,6 +296,62 @@ function RunWorkflowForm({ workflowParameters, initialValues }: Props) {
); );
}} }}
/> />
<FormField
key="proxyLocation"
control={form.control}
name="proxyLocation"
render={({ field }) => {
return (
<FormItem>
<div className="flex gap-16">
<FormLabel>
<div className="w-72">
<div className="flex items-center gap-2 text-lg">
Proxy Location
</div>
<h2 className="text-sm text-slate-400">
Route Skyvern through one of our available proxies.
</h2>
</div>
</FormLabel>
<div className="w-full space-y-2">
<FormControl>
<Select
value={field.value ?? ""}
onValueChange={field.onChange}
>
<SelectTrigger className="w-48">
<SelectValue placeholder="Proxy Location" />
</SelectTrigger>
<SelectContent>
<SelectItem value={ProxyLocation.Residential}>
Residential
</SelectItem>
<SelectItem value={ProxyLocation.ResidentialES}>
Residential (Spain)
</SelectItem>
<SelectItem value={ProxyLocation.ResidentialIE}>
Residential (Ireland)
</SelectItem>
<SelectItem value={ProxyLocation.ResidentialIN}>
Residential (India)
</SelectItem>
<SelectItem value={ProxyLocation.ResidentialJP}>
Residential (Japan)
</SelectItem>
<SelectItem value={ProxyLocation.None}>
None
</SelectItem>
</SelectContent>
</Select>
</FormControl>
<FormMessage />
</div>
</div>
</FormItem>
);
}}
/>
</div> </div>
<div className="flex justify-end gap-2"> <div className="flex justify-end gap-2">
@@ -272,22 +360,10 @@ function RunWorkflowForm({ workflowParameters, initialValues }: Props) {
variant="secondary" variant="secondary"
onClick={() => { onClick={() => {
const values = form.getValues(); const values = form.getValues();
const { webhookCallbackUrl, ...parameters } = values; const body = getRunWorkflowRequestBody(
const parsedParameters = parseValuesForWorkflowRun( values,
parameters,
workflowParameters, workflowParameters,
); );
const body: {
data: Record<string, unknown>;
proxy_location: string;
webhook_callback_url?: string;
} = {
data: parsedParameters,
proxy_location: "RESIDENTIAL",
};
if (webhookCallbackUrl) {
body.webhook_callback_url = webhookCallbackUrl as string;
}
const curl = fetchToCurl({ const curl = fetchToCurl({
method: "POST", method: "POST",
@@ -298,6 +374,7 @@ function RunWorkflowForm({ workflowParameters, initialValues }: Props) {
"x-api-key": apiCredential ?? "<your-api-key>", "x-api-key": apiCredential ?? "<your-api-key>",
}, },
}); });
copyText(curl).then(() => { copyText(curl).then(() => {
toast({ toast({
variant: "success", variant: "success",