Add proxy location to task form advanced settings (#1171)
This commit is contained in:
41
skyvern-frontend/src/components/ProxySelector.tsx
Normal file
41
skyvern-frontend/src/components/ProxySelector.tsx
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
import { ProxyLocation } from "@/api/types";
|
||||||
|
import {
|
||||||
|
Select,
|
||||||
|
SelectContent,
|
||||||
|
SelectItem,
|
||||||
|
SelectTrigger,
|
||||||
|
SelectValue,
|
||||||
|
} from "./ui/select";
|
||||||
|
|
||||||
|
type Props = {
|
||||||
|
value: ProxyLocation | null;
|
||||||
|
onChange: (value: ProxyLocation) => void;
|
||||||
|
};
|
||||||
|
|
||||||
|
function ProxySelector({ value, onChange }: Props) {
|
||||||
|
return (
|
||||||
|
<Select value={value ?? ""} onValueChange={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>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export { ProxySelector };
|
||||||
@@ -1,5 +1,9 @@
|
|||||||
import { getClient } from "@/api/AxiosClient";
|
import { getClient } from "@/api/AxiosClient";
|
||||||
import { CreateTaskRequest, OrganizationApiResponse } from "@/api/types";
|
import {
|
||||||
|
CreateTaskRequest,
|
||||||
|
OrganizationApiResponse,
|
||||||
|
ProxyLocation,
|
||||||
|
} from "@/api/types";
|
||||||
import { AutoResizingTextarea } from "@/components/AutoResizingTextarea/AutoResizingTextarea";
|
import { AutoResizingTextarea } from "@/components/AutoResizingTextarea/AutoResizingTextarea";
|
||||||
import { Button } from "@/components/ui/button";
|
import { Button } from "@/components/ui/button";
|
||||||
import {
|
import {
|
||||||
@@ -33,6 +37,7 @@ import {
|
|||||||
createNewTaskFormSchema,
|
createNewTaskFormSchema,
|
||||||
CreateNewTaskFormValues,
|
CreateNewTaskFormValues,
|
||||||
} from "./taskFormTypes";
|
} from "./taskFormTypes";
|
||||||
|
import { ProxySelector } from "@/components/ProxySelector";
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
initialValues: CreateNewTaskFormValues;
|
initialValues: CreateNewTaskFormValues;
|
||||||
@@ -70,7 +75,7 @@ function createTaskRequestObject(
|
|||||||
webhook_callback_url: transform(formValues.webhookCallbackUrl),
|
webhook_callback_url: transform(formValues.webhookCallbackUrl),
|
||||||
navigation_goal: transform(formValues.navigationGoal),
|
navigation_goal: transform(formValues.navigationGoal),
|
||||||
data_extraction_goal: transform(formValues.dataExtractionGoal),
|
data_extraction_goal: transform(formValues.dataExtractionGoal),
|
||||||
proxy_location: "RESIDENTIAL",
|
proxy_location: formValues.proxyLocation ?? ProxyLocation.Residential,
|
||||||
navigation_payload: transform(formValues.navigationPayload),
|
navigation_payload: transform(formValues.navigationPayload),
|
||||||
extracted_information_schema: extractedInformationSchema,
|
extracted_information_schema: extractedInformationSchema,
|
||||||
totp_verification_url: transform(formValues.totpVerificationUrl),
|
totp_verification_url: transform(formValues.totpVerificationUrl),
|
||||||
@@ -105,10 +110,10 @@ function CreateNewTaskForm({ initialValues }: Props) {
|
|||||||
|
|
||||||
const form = useForm<CreateNewTaskFormValues>({
|
const form = useForm<CreateNewTaskFormValues>({
|
||||||
resolver: zodResolver(createNewTaskFormSchema),
|
resolver: zodResolver(createNewTaskFormSchema),
|
||||||
defaultValues: initialValues,
|
defaultValues: {
|
||||||
values: {
|
|
||||||
...initialValues,
|
...initialValues,
|
||||||
maxStepsOverride: null,
|
maxStepsOverride: initialValues.maxStepsOverride ?? null,
|
||||||
|
proxyLocation: initialValues.proxyLocation ?? ProxyLocation.Residential,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
const { errors } = useFormState({ control: form.control });
|
const { errors } = useFormState({ control: form.control });
|
||||||
@@ -486,6 +491,38 @@ function CreateNewTaskForm({ initialValues }: Props) {
|
|||||||
</FormItem>
|
</FormItem>
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
|
<FormField
|
||||||
|
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>
|
||||||
|
<ProxySelector
|
||||||
|
value={field.value}
|
||||||
|
onChange={field.onChange}
|
||||||
|
/>
|
||||||
|
</FormControl>
|
||||||
|
<FormMessage />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</FormItem>
|
||||||
|
);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
<Separator />
|
<Separator />
|
||||||
<FormField
|
<FormField
|
||||||
control={form.control}
|
control={form.control}
|
||||||
|
|||||||
@@ -60,6 +60,7 @@ function CreateNewTaskFormPage() {
|
|||||||
totpIdentifier: null,
|
totpIdentifier: null,
|
||||||
totpVerificationUrl: null,
|
totpVerificationUrl: null,
|
||||||
webhookCallbackUrl: null,
|
webhookCallbackUrl: null,
|
||||||
|
proxyLocation: null,
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -31,7 +31,8 @@ import { stringify as convertToYAML } from "yaml";
|
|||||||
import { MAX_STEPS_DEFAULT } from "../constants";
|
import { MAX_STEPS_DEFAULT } from "../constants";
|
||||||
import { TaskFormSection } from "./TaskFormSection";
|
import { TaskFormSection } from "./TaskFormSection";
|
||||||
import { savedTaskFormSchema, SavedTaskFormValues } from "./taskFormTypes";
|
import { savedTaskFormSchema, SavedTaskFormValues } from "./taskFormTypes";
|
||||||
import { OrganizationApiResponse } from "@/api/types";
|
import { OrganizationApiResponse, ProxyLocation } from "@/api/types";
|
||||||
|
import { ProxySelector } from "@/components/ProxySelector";
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
initialValues: SavedTaskFormValues;
|
initialValues: SavedTaskFormValues;
|
||||||
@@ -157,10 +158,10 @@ function SavedTaskForm({ initialValues }: Props) {
|
|||||||
|
|
||||||
const form = useForm<SavedTaskFormValues>({
|
const form = useForm<SavedTaskFormValues>({
|
||||||
resolver: zodResolver(savedTaskFormSchema),
|
resolver: zodResolver(savedTaskFormSchema),
|
||||||
defaultValues: initialValues,
|
defaultValues: {
|
||||||
values: {
|
|
||||||
...initialValues,
|
...initialValues,
|
||||||
maxStepsOverride: initialValues.maxStepsOverride ?? null,
|
maxStepsOverride: initialValues.maxStepsOverride ?? null,
|
||||||
|
proxyLocation: initialValues.proxyLocation ?? ProxyLocation.Residential,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -662,6 +663,38 @@ function SavedTaskForm({ initialValues }: Props) {
|
|||||||
</FormItem>
|
</FormItem>
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
|
<FormField
|
||||||
|
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>
|
||||||
|
<ProxySelector
|
||||||
|
value={field.value}
|
||||||
|
onChange={field.onChange}
|
||||||
|
/>
|
||||||
|
</FormControl>
|
||||||
|
<FormMessage />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</FormItem>
|
||||||
|
);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
<Separator />
|
<Separator />
|
||||||
<FormField
|
<FormField
|
||||||
control={form.control}
|
control={form.control}
|
||||||
|
|||||||
@@ -42,6 +42,7 @@ function RetryTask() {
|
|||||||
errorCodeMapping: task.request.error_code_mapping
|
errorCodeMapping: task.request.error_code_mapping
|
||||||
? JSON.stringify(task.request.error_code_mapping, null, 2)
|
? JSON.stringify(task.request.error_code_mapping, null, 2)
|
||||||
: "",
|
: "",
|
||||||
|
proxyLocation: task.request.proxy_location,
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import { ProxyLocation } from "@/api/types";
|
||||||
import { z } from "zod";
|
import { z } from "zod";
|
||||||
|
|
||||||
const createNewTaskFormSchemaBase = z.object({
|
const createNewTaskFormSchemaBase = z.object({
|
||||||
@@ -13,12 +14,12 @@ const createNewTaskFormSchemaBase = z.object({
|
|||||||
totpVerificationUrl: z.string().or(z.null()),
|
totpVerificationUrl: z.string().or(z.null()),
|
||||||
totpIdentifier: z.string().or(z.null()),
|
totpIdentifier: z.string().or(z.null()),
|
||||||
errorCodeMapping: z.string().or(z.null()),
|
errorCodeMapping: z.string().or(z.null()),
|
||||||
|
proxyLocation: z.nativeEnum(ProxyLocation).or(z.null()),
|
||||||
});
|
});
|
||||||
|
|
||||||
const savedTaskFormSchemaBase = createNewTaskFormSchemaBase.extend({
|
const savedTaskFormSchemaBase = createNewTaskFormSchemaBase.extend({
|
||||||
title: z.string().min(1, "Title is required"),
|
title: z.string().min(1, "Title is required"),
|
||||||
description: z.string(),
|
description: z.string(),
|
||||||
proxyLocation: z.string().or(z.null()),
|
|
||||||
});
|
});
|
||||||
|
|
||||||
function refineTaskFormValues(
|
function refineTaskFormValues(
|
||||||
|
|||||||
@@ -24,13 +24,7 @@ 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 { ProxyLocation } from "@/api/types";
|
||||||
import {
|
import { ProxySelector } from "@/components/ProxySelector";
|
||||||
Select,
|
|
||||||
SelectContent,
|
|
||||||
SelectItem,
|
|
||||||
SelectTrigger,
|
|
||||||
SelectValue,
|
|
||||||
} from "@/components/ui/select";
|
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
workflowParameters: Array<WorkflowParameter>;
|
workflowParameters: Array<WorkflowParameter>;
|
||||||
@@ -316,34 +310,10 @@ function RunWorkflowForm({ workflowParameters, initialValues }: Props) {
|
|||||||
</FormLabel>
|
</FormLabel>
|
||||||
<div className="w-full space-y-2">
|
<div className="w-full space-y-2">
|
||||||
<FormControl>
|
<FormControl>
|
||||||
<Select
|
<ProxySelector
|
||||||
value={field.value ?? ""}
|
value={field.value}
|
||||||
onValueChange={field.onChange}
|
onChange={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>
|
</FormControl>
|
||||||
<FormMessage />
|
<FormMessage />
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
Reference in New Issue
Block a user