Skip to content

Commit

Permalink
🔄 synced local 'skyvern-frontend/src/' with remote 'skyvern-frontend/…
Browse files Browse the repository at this point in the history
…src/'

<!-- ELLIPSIS_HIDDEN -->

> [!IMPORTANT]
> Add new components for enhanced parameter handling in workflow nodes, replacing existing components and improving functionality across various node files.
>
>   - **Components**:
>     - Add `WorkflowBlockInput`, `WorkflowBlockInputTextarea`, and `WorkflowBlockParameterSelect` for parameter handling.
>   - **Integration**:
>     - Replace `AutoResizingTextarea` with `WorkflowBlockInputTextarea` in `ActionNode.tsx`, `ExtractionNode.tsx`, and `FileDownloadNode.tsx`.
>     - Add parameter selection in `NavigationNode.tsx` and `TaskNode.tsx` using `WorkflowBlockParameterSelect`.
>   - **State Management**:
>     - Use `useWorkflowParametersState` in `TaskNode.tsx` for managing workflow parameters.
>   - **Misc**:
>     - Add `parameterInputOptions` in `TaskNode.tsx` to combine workflow and output parameters.
>
> <sup>This description was created by </sup>[<img alt="Ellipsis" src="https://img.shields.io/badge/Ellipsis-blue?color=175173">](https://www.ellipsis.dev?ref=Skyvern-AI%2Fskyvern-cloud&utm_source=github&utm_medium=referral)<sup> for d951eeb248f89efd7c6d78de0f77c5e96cab3000. It will automatically update as commits are pushed.</sup>

<!-- ELLIPSIS_HIDDEN -->
  • Loading branch information
wintonzheng committed Dec 10, 2024
1 parent 5830758 commit 3500b2d
Show file tree
Hide file tree
Showing 10 changed files with 430 additions and 190 deletions.
22 changes: 22 additions & 0 deletions skyvern-frontend/src/components/WorkflowBlockInput.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import { PlusIcon } from "@radix-ui/react-icons";
import { cn } from "@/util/utils";
import { Input } from "./ui/input";

type Props = React.ComponentProps<typeof Input> & {
onIconClick: () => void;
};

function WorkflowBlockInput(props: Props) {
return (
<div className="relative">
<Input {...props} className={cn("pr-9", props.className)} />
<div className="absolute right-0 top-0 flex size-9 cursor-pointer items-center justify-center">
<div className="rounded p-1 hover:bg-muted" onClick={props.onIconClick}>
<PlusIcon className="size-4" />
</div>
</div>
</div>
);
}

export { WorkflowBlockInput };
25 changes: 25 additions & 0 deletions skyvern-frontend/src/components/WorkflowBlockInputTextarea.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import { PlusIcon } from "@radix-ui/react-icons";
import { cn } from "@/util/utils";
import { AutoResizingTextarea } from "./AutoResizingTextarea/AutoResizingTextarea";

type Props = React.ComponentProps<typeof AutoResizingTextarea> & {
onIconClick: () => void;
};

function WorkflowBlockInputTextarea(props: Props) {
return (
<div className="relative">
<AutoResizingTextarea
{...props}
className={cn("pr-9", props.className)}
/>
<div className="absolute right-0 top-0 flex size-9 cursor-pointer items-center justify-center">
<div className="rounded p-1 hover:bg-muted" onClick={props.onIconClick}>
<PlusIcon className="size-4" />
</div>
</div>
</div>
);
}

export { WorkflowBlockInputTextarea };
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import { AutoResizingTextarea } from "@/components/AutoResizingTextarea/AutoResizingTextarea";
import {
Accordion,
AccordionContent,
Expand All @@ -22,6 +21,8 @@ import { CodeEditor } from "@/routes/workflows/components/CodeEditor";
import { Switch } from "@/components/ui/switch";
import { ClickIcon } from "@/components/icons/ClickIcon";
import { placeholders, helpTooltips } from "../../helpContent";
import { WorkflowBlockInputTextarea } from "@/components/WorkflowBlockInputTextarea";
import { WorkflowBlockParameterSelect } from "../WorkflowBlockParameterSelect";

const urlTooltip =
"The URL Skyvern is navigating to. Leave this field blank to pick up from where the last block left off.";
Expand All @@ -31,6 +32,9 @@ const navigationGoalTooltip =
const navigationGoalPlaceholder = 'Input {{ name }} into "Name" field.';

function ActionNode({ id, data }: NodeProps<ActionNode>) {
const [parametersPanelField, setParametersPanelField] = useState<
string | null
>(null);
const { updateNodeData } = useReactFlow();
const { editable } = data;
const [label, setLabel] = useNodeLabelChangeHandler({
Expand Down Expand Up @@ -102,7 +106,10 @@ function ActionNode({ id, data }: NodeProps<ActionNode>) {
<Label className="text-xs text-slate-300">URL</Label>
<HelpTooltip content={urlTooltip} />
</div>
<AutoResizingTextarea
<WorkflowBlockInputTextarea
onIconClick={() => {
setParametersPanelField("url");
}}
onChange={(event) => {
if (!editable) {
return;
Expand All @@ -121,7 +128,10 @@ function ActionNode({ id, data }: NodeProps<ActionNode>) {
</Label>
<HelpTooltip content={navigationGoalTooltip} />
</div>
<AutoResizingTextarea
<WorkflowBlockInputTextarea
onIconClick={() => {
setParametersPanelField("navigationGoal");
}}
onChange={(event) => {
if (!editable) {
return;
Expand Down Expand Up @@ -309,11 +319,11 @@ function ActionNode({ id, data }: NodeProps<ActionNode>) {
content={helpTooltips["action"]["totpVerificationUrl"]}
/>
</div>
<AutoResizingTextarea
<WorkflowBlockInputTextarea
onIconClick={() => {
setParametersPanelField("totpVerificationUrl");
}}
onChange={(event) => {
if (!editable) {
return;
}
handleChange("totpVerificationUrl", event.target.value);
}}
value={inputs.totpVerificationUrl ?? ""}
Expand All @@ -330,7 +340,10 @@ function ActionNode({ id, data }: NodeProps<ActionNode>) {
content={helpTooltips["action"]["totpIdentifier"]}
/>
</div>
<AutoResizingTextarea
<WorkflowBlockInputTextarea
onIconClick={() => {
setParametersPanelField("totpIdentifier");
}}
onChange={(event) => {
if (!editable) {
return;
Expand All @@ -347,6 +360,25 @@ function ActionNode({ id, data }: NodeProps<ActionNode>) {
</AccordionItem>
</Accordion>
</div>
{typeof parametersPanelField === "string" && (
<WorkflowBlockParameterSelect
nodeId={id}
onClose={() => setParametersPanelField(null)}
onAdd={(parameterKey) => {
if (parametersPanelField === null || !editable) {
return;
}
if (parametersPanelField in inputs) {
const currentValue =
inputs[parametersPanelField as keyof typeof inputs];
handleChange(
parametersPanelField,
`${currentValue ?? ""}{{ ${parameterKey} }}`,
);
}
}}
/>
)}
</div>
);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import { AutoResizingTextarea } from "@/components/AutoResizingTextarea/AutoResizingTextarea";
import {
Accordion,
AccordionContent,
Expand All @@ -23,8 +22,13 @@ import type { ExtractionNode } from "./types";
import { ExtractIcon } from "@/components/icons/ExtractIcon";

import { helpTooltips, placeholders } from "../../helpContent";
import { WorkflowBlockParameterSelect } from "../WorkflowBlockParameterSelect";
import { WorkflowBlockInputTextarea } from "@/components/WorkflowBlockInputTextarea";

function ExtractionNode({ id, data }: NodeProps<ExtractionNode>) {
const [parametersPanelField, setParametersPanelField] = useState<
string | null
>(null);
const { updateNodeData } = useReactFlow();
const { editable } = data;
const [label, setLabel] = useNodeLabelChangeHandler({
Expand Down Expand Up @@ -96,7 +100,10 @@ function ExtractionNode({ id, data }: NodeProps<ExtractionNode>) {
content={helpTooltips["extraction"]["dataExtractionGoal"]}
/>
</div>
<AutoResizingTextarea
<WorkflowBlockInputTextarea
onIconClick={() => {
setParametersPanelField("dataExtractionGoal");
}}
onChange={(event) => {
if (!editable) {
return;
Expand Down Expand Up @@ -256,6 +263,25 @@ function ExtractionNode({ id, data }: NodeProps<ExtractionNode>) {
</AccordionItem>
</Accordion>
</div>
{typeof parametersPanelField === "string" && (
<WorkflowBlockParameterSelect
nodeId={id}
onClose={() => setParametersPanelField(null)}
onAdd={(parameterKey) => {
if (parametersPanelField === null || !editable) {
return;
}
if (parametersPanelField in inputs) {
const currentValue =
inputs[parametersPanelField as keyof typeof inputs];
handleChange(
parametersPanelField,
`${currentValue ?? ""}{{ ${parameterKey} }}`,
);
}
}}
/>
)}
</div>
);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import { AutoResizingTextarea } from "@/components/AutoResizingTextarea/AutoResizingTextarea";
import { HelpTooltip } from "@/components/HelpTooltip";
import {
Accordion,
Expand All @@ -22,6 +21,8 @@ import { NodeActionMenu } from "../NodeActionMenu";
import { errorMappingExampleValue } from "../types";
import type { FileDownloadNode } from "./types";
import { helpTooltips, placeholders } from "../../helpContent";
import { WorkflowBlockParameterSelect } from "../WorkflowBlockParameterSelect";
import { WorkflowBlockInputTextarea } from "@/components/WorkflowBlockInputTextarea";

const urlTooltip =
"The URL Skyvern is navigating to. Leave this field blank to pick up from where the last block left off.";
Expand All @@ -31,6 +32,9 @@ const navigationGoalTooltip =
const navigationGoalPlaceholder = "Tell Skyvern which file to download.";

function FileDownloadNode({ id, data }: NodeProps<FileDownloadNode>) {
const [parametersPanelField, setParametersPanelField] = useState<
string | null
>(null);
const { updateNodeData } = useReactFlow();
const { editable } = data;
const [label, setLabel] = useNodeLabelChangeHandler({
Expand Down Expand Up @@ -104,11 +108,11 @@ function FileDownloadNode({ id, data }: NodeProps<FileDownloadNode>) {
<Label className="text-xs text-slate-300">URL</Label>
<HelpTooltip content={urlTooltip} />
</div>
<AutoResizingTextarea
<WorkflowBlockInputTextarea
onIconClick={() => {
setParametersPanelField("url");
}}
onChange={(event) => {
if (!editable) {
return;
}
handleChange("url", event.target.value);
}}
value={inputs.url}
Expand All @@ -121,11 +125,11 @@ function FileDownloadNode({ id, data }: NodeProps<FileDownloadNode>) {
<Label className="text-xs text-slate-300">Download Goal</Label>
<HelpTooltip content={navigationGoalTooltip} />
</div>
<AutoResizingTextarea
<WorkflowBlockInputTextarea
onIconClick={() => {
setParametersPanelField("navigationGoal");
}}
onChange={(event) => {
if (!editable) {
return;
}
handleChange("navigationGoal", event.target.value);
}}
value={inputs.navigationGoal}
Expand Down Expand Up @@ -161,9 +165,6 @@ function FileDownloadNode({ id, data }: NodeProps<FileDownloadNode>) {
min="0"
value={inputs.maxRetries ?? ""}
onChange={(event) => {
if (!editable) {
return;
}
const value =
event.target.value === ""
? null
Expand All @@ -188,9 +189,6 @@ function FileDownloadNode({ id, data }: NodeProps<FileDownloadNode>) {
min="0"
value={inputs.maxStepsOverride ?? ""}
onChange={(event) => {
if (!editable) {
return;
}
const value =
event.target.value === ""
? null
Expand All @@ -213,9 +211,6 @@ function FileDownloadNode({ id, data }: NodeProps<FileDownloadNode>) {
checked={inputs.errorCodeMapping !== "null"}
disabled={!editable}
onCheckedChange={(checked) => {
if (!editable) {
return;
}
handleChange(
"errorCodeMapping",
checked
Expand All @@ -231,9 +226,6 @@ function FileDownloadNode({ id, data }: NodeProps<FileDownloadNode>) {
language="json"
value={inputs.errorCodeMapping}
onChange={(value) => {
if (!editable) {
return;
}
handleChange("errorCodeMapping", value);
}}
className="nowheel nopan"
Expand All @@ -256,9 +248,6 @@ function FileDownloadNode({ id, data }: NodeProps<FileDownloadNode>) {
<Switch
checked={inputs.continueOnFailure}
onCheckedChange={(checked) => {
if (!editable) {
return;
}
handleChange("continueOnFailure", checked);
}}
/>
Expand All @@ -277,9 +266,6 @@ function FileDownloadNode({ id, data }: NodeProps<FileDownloadNode>) {
<Switch
checked={inputs.cacheActions}
onCheckedChange={(checked) => {
if (!editable) {
return;
}
handleChange("cacheActions", checked);
}}
/>
Expand All @@ -301,9 +287,6 @@ function FileDownloadNode({ id, data }: NodeProps<FileDownloadNode>) {
className="nopan w-52 text-xs"
value={inputs.downloadSuffix ?? ""}
onChange={(event) => {
if (!editable) {
return;
}
handleChange("downloadSuffix", event.target.value);
}}
/>
Expand All @@ -318,11 +301,11 @@ function FileDownloadNode({ id, data }: NodeProps<FileDownloadNode>) {
content={helpTooltips["download"]["totpVerificationUrl"]}
/>
</div>
<AutoResizingTextarea
<WorkflowBlockInputTextarea
onIconClick={() => {
setParametersPanelField("totpVerificationUrl");
}}
onChange={(event) => {
if (!editable) {
return;
}
handleChange("totpVerificationUrl", event.target.value);
}}
value={inputs.totpVerificationUrl ?? ""}
Expand All @@ -341,11 +324,11 @@ function FileDownloadNode({ id, data }: NodeProps<FileDownloadNode>) {
content={helpTooltips["download"]["totpIdentifier"]}
/>
</div>
<AutoResizingTextarea
<WorkflowBlockInputTextarea
onIconClick={() => {
setParametersPanelField("totpIdentifier");
}}
onChange={(event) => {
if (!editable) {
return;
}
handleChange("totpIdentifier", event.target.value);
}}
value={inputs.totpIdentifier ?? ""}
Expand All @@ -358,6 +341,25 @@ function FileDownloadNode({ id, data }: NodeProps<FileDownloadNode>) {
</AccordionItem>
</Accordion>
</div>
{typeof parametersPanelField === "string" && (
<WorkflowBlockParameterSelect
nodeId={id}
onClose={() => setParametersPanelField(null)}
onAdd={(parameterKey) => {
if (parametersPanelField === null || !editable) {
return;
}
if (parametersPanelField in inputs) {
const currentValue =
inputs[parametersPanelField as keyof typeof inputs];
handleChange(
parametersPanelField,
`${currentValue ?? ""}{{ ${parameterKey} }}`,
);
}
}}
/>
)}
</div>
);
}
Expand Down
Loading

0 comments on commit 3500b2d

Please sign in to comment.