refactor: tooltips and placeholders (#1302)

Co-authored-by: Muhammed Salih Altun <muhammedsalihaltun@gmail.com>
This commit is contained in:
Shuchang Zheng
2024-12-02 09:19:11 -08:00
committed by GitHub
parent d18f2d41e7
commit 76f1712045
26 changed files with 270 additions and 265 deletions

View File

@@ -14,33 +14,3 @@ export const SMTP_USERNAME_AWS_KEY = "SKYVERN_SMTP_USERNAME_SES";
export const SMTP_PASSWORD_AWS_KEY = "SKYVERN_SMTP_PASSWORD_SES";
export const EMAIL_BLOCK_SENDER = "hello@skyvern.com";
export const commonHelpTooltipContent = {
maxRetries:
"Specify how many times you would like a task to retry upon failure.",
maxStepsOverride:
"Specify the maximum number of steps a task can take in total.",
completeOnDownload:
"Allow Skyvern to auto-complete the task when it downloads a file.",
fileSuffix:
"A file suffix that's automatically added to all downloaded files.",
errorCodeMapping:
"Knowing about why a task terminated can be important, specify error messages here.",
totpVerificationUrl:
"If you have an internal system for storing TOTP codes, link the endpoint here.",
totpIdentifier:
"If you are running multiple tasks or workflows at once, you will need to give the task an identifier to know that this TOTP goes with this task.",
continueOnFailure:
"Allow the workflow to continue if it encounters a failure.",
cacheActions: "Cache the actions of this task.",
} as const;
export const commonFieldPlaceholders = {
url: "https://",
navigationGoal: 'Input text into "Name" field.',
maxRetries: "Default: 3",
maxStepsOverride: "Default: 10",
downloadSuffix: "Add an ID for downloaded files",
totpVerificationUrl: "Provide your 2FA endpoint",
totpIdentifier: "Add an ID that links your TOTP to the task",
} as const;

View File

@@ -0,0 +1,125 @@
export const baseHelpTooltipContent = {
url: "The URL Skyvern is navigating to. Leave this field blank to pick up from where the last block left off.",
navigationGoal:
"Give Skyvern an objective. Make sure to include when the block is complete, when it should self-terminate, and any guardrails.",
parameters:
"Define placeholder values using the “parameters” drop down that you predefine or redefine run-to-run.",
dataExtractionGoal:
"Tell Skyvern what data you would like to scrape at the end of your run.",
dataSchema: "Specify a format for extracted data in JSON.",
maxRetries:
"Specify how many times you would like a block to retry upon failure.",
maxStepsOverride:
"Specify the maximum number of steps a block can take in total.",
completeOnDownload:
"Allow Skyvern to auto-complete the block when it downloads a file.",
fileSuffix:
"A file suffix that's automatically added to all downloaded files.",
errorCodeMapping:
"Knowing about why a block terminated can be important, specify error messages here.",
totpVerificationUrl:
"If you have an internal system for storing TOTP codes, link the endpoint here.",
totpIdentifier:
"If you are running multiple workflows at once, you will need to give the block an identifier to know that this TOTP goes with this block.",
continueOnFailure:
"Allow the workflow to continue if it encounters a failure.",
cacheActions: "Cache the actions of this block.",
} as const;
export const basePlaceholderContent = {
url: "https://",
navigationGoal: "Tell Skyvern what to do.",
dataExtractionGoal: "What data do you need to extract?",
maxRetries: "Default: 3",
maxStepsOverride: "Default: 10",
downloadSuffix: "Add an ID for downloaded files",
totpVerificationUrl: "Provide your 2FA endpoint",
totpIdentifier: "Add an ID that links your TOTP to the block",
};
export const helpTooltips = {
task: baseHelpTooltipContent,
navigation: baseHelpTooltipContent,
extraction: {
...baseHelpTooltipContent,
dataExtractionGoal:
"Tell Skyvern what data you would like to scrape. Use {{ parameter_name }} to specify parameters to use.",
},
action: {
...baseHelpTooltipContent,
navigationGoal:
"Specify a single step or action you'd like Skyvern to complete. Actions are one-off tasks like filling a field or interacting with a specific element on the page.\n\nCurrently supported actions are click, input text, upload file, and select. Use {{ parameter_name }} to specify parameters to use.",
},
fileDownload: {
...baseHelpTooltipContent,
navigationGoal:
"Give Skyvern an objective that describes how to download the file.",
},
validation: baseHelpTooltipContent,
textPrompt: {
...baseHelpTooltipContent,
prompt:
"Write a prompt you would like passed into the LLM and specify the output format, if applicable.",
},
login: baseHelpTooltipContent,
loop: {
...baseHelpTooltipContent,
loopValue:
"Define this parameterized field with a parameter key to let Skyvern know the core value you're iterating over.",
},
sendEmail: {
...baseHelpTooltipContent,
fileAttachments:
"Since we're in beta this section isn't fully customizable yet, contact us if you'd like to integrate it into your workflow.",
},
upload: {
...baseHelpTooltipContent,
path: "Since we're in beta this section isn't fully customizable yet, contact us if you'd like to integrate it into your workflow.",
},
download: {
...baseHelpTooltipContent,
url: "Since we're in beta this section isn't fully customizable yet, contact us if you'd like to integrate it into your workflow.",
},
codeBlock: baseHelpTooltipContent,
fileParser: {
...baseHelpTooltipContent,
fileUrl:
"Since we're in beta this section isn't fully customizable yet, contact us if you'd like to integrate it into your workflow.",
},
wait: {
...baseHelpTooltipContent,
waitInSeconds:
"Specify a number for how many seconds to wait. Value must be between 0 and 300 seconds.",
},
};
export const placeholders = {
task: basePlaceholderContent,
navigation: {
...basePlaceholderContent,
navigationGoal:
"Give Skyvern an objective. Make sure to include when the task is complete, when it should self-terminate, and any guardrails.",
},
extraction: {
...basePlaceholderContent,
dataExtractionGoal:
"Extract the price of the product with id {{ product_id }}",
},
action: {
...basePlaceholderContent,
navigationGoal: 'Input {{ name }} into "Name" field.',
},
fileDownload: {
navigationGoal: "Tell Skyvern which file to download.",
},
validation: basePlaceholderContent,
textPrompt: basePlaceholderContent,
login: basePlaceholderContent,
loop: basePlaceholderContent,
sendEmail: basePlaceholderContent,
upload: basePlaceholderContent,
download: basePlaceholderContent,
codeBlock: basePlaceholderContent,
fileUrl: basePlaceholderContent,
wait: basePlaceholderContent,
};

View File

@@ -21,10 +21,7 @@ import { errorMappingExampleValue } from "../types";
import { CodeEditor } from "@/routes/workflows/components/CodeEditor";
import { Switch } from "@/components/ui/switch";
import { ClickIcon } from "@/components/icons/ClickIcon";
import {
commonFieldPlaceholders,
commonHelpTooltipContent,
} from "../../constants";
import { placeholders, helpTooltips } from "../../helpContent";
const urlTooltip =
"The URL Skyvern is navigating to. Leave this field blank to pick up from where the last block left off.";
@@ -113,7 +110,7 @@ function ActionNode({ id, data }: NodeProps<ActionNode>) {
handleChange("url", event.target.value);
}}
value={inputs.url}
placeholder={commonFieldPlaceholders["url"]}
placeholder={placeholders["action"]["url"]}
className="nopan text-xs"
/>
</div>
@@ -151,12 +148,12 @@ function ActionNode({ id, data }: NodeProps<ActionNode>) {
Max Retries
</Label>
<HelpTooltip
content={commonHelpTooltipContent["maxRetries"]}
content={helpTooltips["action"]["maxRetries"]}
/>
</div>
<Input
type="number"
placeholder={commonFieldPlaceholders["maxRetries"]}
placeholder={placeholders["action"]["maxRetries"]}
className="nopan w-52 text-xs"
min="0"
value={inputs.maxRetries ?? ""}
@@ -179,7 +176,7 @@ function ActionNode({ id, data }: NodeProps<ActionNode>) {
Error Messages
</Label>
<HelpTooltip
content={commonHelpTooltipContent["errorCodeMapping"]}
content={helpTooltips["action"]["errorCodeMapping"]}
/>
</div>
<Checkbox
@@ -222,7 +219,7 @@ function ActionNode({ id, data }: NodeProps<ActionNode>) {
Continue on Failure
</Label>
<HelpTooltip
content={commonHelpTooltipContent["continueOnFailure"]}
content={helpTooltips["action"]["continueOnFailure"]}
/>
</div>
<div className="w-52">
@@ -243,7 +240,7 @@ function ActionNode({ id, data }: NodeProps<ActionNode>) {
Cache Actions
</Label>
<HelpTooltip
content={commonHelpTooltipContent["cacheActions"]}
content={helpTooltips["action"]["cacheActions"]}
/>
</div>
<div className="w-52">
@@ -265,7 +262,7 @@ function ActionNode({ id, data }: NodeProps<ActionNode>) {
Complete on Download
</Label>
<HelpTooltip
content={commonHelpTooltipContent["completeOnDownload"]}
content={helpTooltips["action"]["completeOnDownload"]}
/>
</div>
<div className="w-52">
@@ -286,12 +283,12 @@ function ActionNode({ id, data }: NodeProps<ActionNode>) {
File Suffix
</Label>
<HelpTooltip
content={commonHelpTooltipContent["fileSuffix"]}
content={helpTooltips["action"]["fileSuffix"]}
/>
</div>
<Input
type="text"
placeholder={commonFieldPlaceholders["downloadSuffix"]}
placeholder={placeholders["action"]["downloadSuffix"]}
className="nopan w-52 text-xs"
value={inputs.downloadSuffix ?? ""}
onChange={(event) => {
@@ -309,7 +306,7 @@ function ActionNode({ id, data }: NodeProps<ActionNode>) {
2FA Verification URL
</Label>
<HelpTooltip
content={commonHelpTooltipContent["totpVerificationUrl"]}
content={helpTooltips["action"]["totpVerificationUrl"]}
/>
</div>
<AutoResizingTextarea
@@ -320,7 +317,7 @@ function ActionNode({ id, data }: NodeProps<ActionNode>) {
handleChange("totpVerificationUrl", event.target.value);
}}
value={inputs.totpVerificationUrl ?? ""}
placeholder={commonFieldPlaceholders["totpVerificationUrl"]}
placeholder={placeholders["action"]["totpVerificationUrl"]}
className="nopan text-xs"
/>
</div>
@@ -330,7 +327,7 @@ function ActionNode({ id, data }: NodeProps<ActionNode>) {
2FA Identifier
</Label>
<HelpTooltip
content={commonHelpTooltipContent["totpIdentifier"]}
content={helpTooltips["action"]["totpIdentifier"]}
/>
</div>
<AutoResizingTextarea
@@ -341,7 +338,7 @@ function ActionNode({ id, data }: NodeProps<ActionNode>) {
handleChange("totpIdentifier", event.target.value);
}}
value={inputs.totpIdentifier ?? ""}
placeholder={commonFieldPlaceholders["totpIdentifier"]}
placeholder={placeholders["action"]["totpIdentifier"]}
className="nopan text-xs"
/>
</div>

View File

@@ -6,8 +6,9 @@ import { DownloadIcon } from "@radix-ui/react-icons";
import { Handle, NodeProps, Position } from "@xyflow/react";
import { EditableNodeTitle } from "../components/EditableNodeTitle";
import { NodeActionMenu } from "../NodeActionMenu";
import { helpTooltipContent, type DownloadNode } from "./types";
import type { DownloadNode } from "./types";
import { HelpTooltip } from "@/components/HelpTooltip";
import { helpTooltips } from "../../helpContent";
function DownloadNode({ id, data }: NodeProps<DownloadNode>) {
const [label, setLabel] = useNodeLabelChangeHandler({
@@ -57,7 +58,7 @@ function DownloadNode({ id, data }: NodeProps<DownloadNode>) {
<div className="space-y-2">
<div className="flex items-center gap-2">
<Label className="text-sm text-slate-400">File Path</Label>
<HelpTooltip content={helpTooltipContent["url"]} />
<HelpTooltip content={helpTooltips["download"]["url"]} />
</div>
<Input value={data.url} disabled className="nopan text-xs" />
</div>

View File

@@ -14,7 +14,3 @@ export const downloadNodeDefaultData: DownloadNodeData = {
url: SKYVERN_DOWNLOAD_DIRECTORY,
continueOnFailure: false,
} as const;
export const helpTooltipContent = {
url: "Since we're in beta this section isn't fully customizable yet, contact us if you'd like to integrate it into your workflow.",
} as const;

View File

@@ -20,17 +20,9 @@ import { dataSchemaExampleValue } from "../types";
import { CodeEditor } from "@/routes/workflows/components/CodeEditor";
import { Switch } from "@/components/ui/switch";
import type { ExtractionNode } from "./types";
import {
commonFieldPlaceholders,
commonHelpTooltipContent,
} from "../../constants";
import { ExtractIcon } from "@/components/icons/ExtractIcon";
const dataExtractionGoalTooltip =
"Tell Skyvern what data you would like to scrape. Use {{ parameter_name }} to specify parameters to use.";
const dataSchemaTooltip = "Specify a format for extracted data in JSON.";
const dataExtractionGoalPlaceholder =
"Extract the price of the product with id {{ product_id }}";
import { helpTooltips, placeholders } from "../../helpContent";
function ExtractionNode({ id, data }: NodeProps<ExtractionNode>) {
const { updateNodeData } = useReactFlow();
@@ -100,7 +92,9 @@ function ExtractionNode({ id, data }: NodeProps<ExtractionNode>) {
<Label className="text-xs text-slate-300">
Data Extraction Goal
</Label>
<HelpTooltip content={dataExtractionGoalTooltip} />
<HelpTooltip
content={helpTooltips["extraction"]["dataExtractionGoal"]}
/>
</div>
<AutoResizingTextarea
onChange={(event) => {
@@ -110,7 +104,7 @@ function ExtractionNode({ id, data }: NodeProps<ExtractionNode>) {
handleChange("dataExtractionGoal", event.target.value);
}}
value={inputs.dataExtractionGoal}
placeholder={dataExtractionGoalPlaceholder}
placeholder={placeholders["extraction"]["dataExtractionGoal"]}
className="nopan text-xs"
/>
</div>
@@ -118,7 +112,7 @@ function ExtractionNode({ id, data }: NodeProps<ExtractionNode>) {
<div className="flex gap-4">
<div className="flex gap-2">
<Label className="text-xs text-slate-300">Data Schema</Label>
<HelpTooltip content={dataSchemaTooltip} />
<HelpTooltip content={helpTooltips["extraction"]["dataSchema"]} />
</div>
<Checkbox
checked={inputs.dataSchema !== "null"}
@@ -166,12 +160,12 @@ function ExtractionNode({ id, data }: NodeProps<ExtractionNode>) {
Max Retries
</Label>
<HelpTooltip
content={commonHelpTooltipContent["maxRetries"]}
content={helpTooltips["extraction"]["maxRetries"]}
/>
</div>
<Input
type="number"
placeholder={commonFieldPlaceholders["maxRetries"]}
placeholder={placeholders["extraction"]["maxRetries"]}
className="nopan w-52 text-xs"
min="0"
value={inputs.maxRetries ?? ""}
@@ -193,12 +187,12 @@ function ExtractionNode({ id, data }: NodeProps<ExtractionNode>) {
Max Steps Override
</Label>
<HelpTooltip
content={commonHelpTooltipContent["maxStepsOverride"]}
content={helpTooltips["extraction"]["maxStepsOverride"]}
/>
</div>
<Input
type="number"
placeholder={commonFieldPlaceholders["maxStepsOverride"]}
placeholder={placeholders["extraction"]["maxStepsOverride"]}
className="nopan w-52 text-xs"
min="0"
value={inputs.maxStepsOverride ?? ""}
@@ -221,7 +215,7 @@ function ExtractionNode({ id, data }: NodeProps<ExtractionNode>) {
Continue on Failure
</Label>
<HelpTooltip
content={commonHelpTooltipContent["continueOnFailure"]}
content={helpTooltips["extraction"]["continueOnFailure"]}
/>
</div>
<div className="w-52">
@@ -242,7 +236,7 @@ function ExtractionNode({ id, data }: NodeProps<ExtractionNode>) {
Cache Actions
</Label>
<HelpTooltip
content={commonHelpTooltipContent["cacheActions"]}
content={helpTooltips["extraction"]["cacheActions"]}
/>
</div>
<div className="w-52">

View File

@@ -17,14 +17,11 @@ import { useNodeLabelChangeHandler } from "@/routes/workflows/hooks/useLabelChan
import { DownloadIcon } from "@radix-ui/react-icons";
import { Handle, NodeProps, Position, useReactFlow } from "@xyflow/react";
import { useState } from "react";
import {
commonFieldPlaceholders,
commonHelpTooltipContent,
} from "../../constants";
import { EditableNodeTitle } from "../components/EditableNodeTitle";
import { NodeActionMenu } from "../NodeActionMenu";
import { errorMappingExampleValue } from "../types";
import type { FileDownloadNode } from "./types";
import { helpTooltips, placeholders } from "../../helpContent";
const urlTooltip =
"The URL Skyvern is navigating to. Leave this field blank to pick up from where the last block left off.";
@@ -154,12 +151,12 @@ function FileDownloadNode({ id, data }: NodeProps<FileDownloadNode>) {
Max Retries
</Label>
<HelpTooltip
content={commonHelpTooltipContent["maxRetries"]}
content={helpTooltips["download"]["maxRetries"]}
/>
</div>
<Input
type="number"
placeholder={commonFieldPlaceholders["maxRetries"]}
placeholder={placeholders["download"]["maxRetries"]}
className="nopan w-52 text-xs"
min="0"
value={inputs.maxRetries ?? ""}
@@ -181,12 +178,12 @@ function FileDownloadNode({ id, data }: NodeProps<FileDownloadNode>) {
Max Steps Override
</Label>
<HelpTooltip
content={commonHelpTooltipContent["maxStepsOverride"]}
content={helpTooltips["download"]["maxStepsOverride"]}
/>
</div>
<Input
type="number"
placeholder={commonFieldPlaceholders["maxStepsOverride"]}
placeholder={placeholders["download"]["maxStepsOverride"]}
className="nopan w-52 text-xs"
min="0"
value={inputs.maxStepsOverride ?? ""}
@@ -209,7 +206,7 @@ function FileDownloadNode({ id, data }: NodeProps<FileDownloadNode>) {
Error Messages
</Label>
<HelpTooltip
content={commonHelpTooltipContent["errorCodeMapping"]}
content={helpTooltips["download"]["errorCodeMapping"]}
/>
</div>
<Checkbox
@@ -252,7 +249,7 @@ function FileDownloadNode({ id, data }: NodeProps<FileDownloadNode>) {
Continue on Failure
</Label>
<HelpTooltip
content={commonHelpTooltipContent["continueOnFailure"]}
content={helpTooltips["download"]["continueOnFailure"]}
/>
</div>
<div className="w-52">
@@ -273,7 +270,7 @@ function FileDownloadNode({ id, data }: NodeProps<FileDownloadNode>) {
Cache Actions
</Label>
<HelpTooltip
content={commonHelpTooltipContent["cacheActions"]}
content={helpTooltips["download"]["cacheActions"]}
/>
</div>
<div className="w-52">
@@ -295,12 +292,12 @@ function FileDownloadNode({ id, data }: NodeProps<FileDownloadNode>) {
File Suffix
</Label>
<HelpTooltip
content={commonHelpTooltipContent["fileSuffix"]}
content={helpTooltips["download"]["fileSuffix"]}
/>
</div>
<Input
type="text"
placeholder={commonFieldPlaceholders["downloadSuffix"]}
placeholder={placeholders["download"]["downloadSuffix"]}
className="nopan w-52 text-xs"
value={inputs.downloadSuffix ?? ""}
onChange={(event) => {
@@ -318,7 +315,7 @@ function FileDownloadNode({ id, data }: NodeProps<FileDownloadNode>) {
2FA Verification URL
</Label>
<HelpTooltip
content={commonHelpTooltipContent["totpVerificationUrl"]}
content={helpTooltips["download"]["totpVerificationUrl"]}
/>
</div>
<AutoResizingTextarea
@@ -329,7 +326,9 @@ function FileDownloadNode({ id, data }: NodeProps<FileDownloadNode>) {
handleChange("totpVerificationUrl", event.target.value);
}}
value={inputs.totpVerificationUrl ?? ""}
placeholder={commonFieldPlaceholders["totpVerificationUrl"]}
placeholder={
placeholders["download"]["totpVerificationUrl"]
}
className="nopan text-xs"
/>
</div>
@@ -339,7 +338,7 @@ function FileDownloadNode({ id, data }: NodeProps<FileDownloadNode>) {
2FA Identifier
</Label>
<HelpTooltip
content={commonHelpTooltipContent["totpIdentifier"]}
content={helpTooltips["download"]["totpIdentifier"]}
/>
</div>
<AutoResizingTextarea
@@ -350,7 +349,7 @@ function FileDownloadNode({ id, data }: NodeProps<FileDownloadNode>) {
handleChange("totpIdentifier", event.target.value);
}}
value={inputs.totpIdentifier ?? ""}
placeholder={commonFieldPlaceholders["totpIdentifier"]}
placeholder={placeholders["download"]["totpIdentifier"]}
className="nopan text-xs"
/>
</div>

View File

@@ -6,9 +6,10 @@ import { Handle, NodeProps, Position, useReactFlow } from "@xyflow/react";
import { useState } from "react";
import { EditableNodeTitle } from "../components/EditableNodeTitle";
import { NodeActionMenu } from "../NodeActionMenu";
import { helpTooltipContent, type FileParserNode } from "./types";
import { type FileParserNode } from "./types";
import { Label } from "@/components/ui/label";
import { HelpTooltip } from "@/components/HelpTooltip";
import { helpTooltips } from "../../helpContent";
function FileParserNode({ id, data }: NodeProps<FileParserNode>) {
const { updateNodeData } = useReactFlow();
@@ -62,7 +63,7 @@ function FileParserNode({ id, data }: NodeProps<FileParserNode>) {
<div className="space-y-2">
<div className="flex gap-2">
<Label className="text-xs text-slate-300">File URL</Label>
<HelpTooltip content={helpTooltipContent["fileUrl"]} />
<HelpTooltip content={helpTooltips["fileParser"]["fileUrl"]} />
</div>
<Input
value={inputs.fileUrl}

View File

@@ -13,8 +13,3 @@ export const fileParserNodeDefaultData: FileParserNodeData = {
fileUrl: "",
continueOnFailure: false,
} as const;
export const helpTooltipContent = {
fileUrl:
"Since we're in beta this section isn't fully customizable yet, contact us if you'd like to integrate it into your workflow.",
} as const;

View File

@@ -20,19 +20,9 @@ import { errorMappingExampleValue } from "../types";
import { CodeEditor } from "@/routes/workflows/components/CodeEditor";
import { Switch } from "@/components/ui/switch";
import type { LoginNode } from "./types";
import {
commonFieldPlaceholders,
commonHelpTooltipContent,
} from "../../constants";
import { LockOpen1Icon } from "@radix-ui/react-icons";
import { CredentialParameterSelector } from "./CredentialParameterSelector";
const urlTooltip =
"The URL Skyvern is navigating to. Leave this field blank to pick up from where the last block left off.";
const urlPlaceholder = "https://";
const navigationGoalTooltip =
"Give Skyvern an objective. Make sure to include when the task is complete, when it should self-terminate, and any guardrails.";
const navigationGoalPlaceholder = "Tell Skyvern what to do.";
import { helpTooltips, placeholders } from "../../helpContent";
function LoginNode({ id, data }: NodeProps<LoginNode>) {
const { updateNodeData } = useReactFlow();
@@ -103,7 +93,7 @@ function LoginNode({ id, data }: NodeProps<LoginNode>) {
<div className="space-y-2">
<div className="flex gap-2">
<Label className="text-xs text-slate-300">URL</Label>
<HelpTooltip content={urlTooltip} />
<HelpTooltip content={helpTooltips["login"]["url"]} />
</div>
<AutoResizingTextarea
onChange={(event) => {
@@ -113,14 +103,14 @@ function LoginNode({ id, data }: NodeProps<LoginNode>) {
handleChange("url", event.target.value);
}}
value={inputs.url}
placeholder={urlPlaceholder}
placeholder={placeholders["login"]["url"]}
className="nopan text-xs"
/>
</div>
<div className="space-y-2">
<div className="flex gap-2">
<Label className="text-xs text-slate-300">Login Goal</Label>
<HelpTooltip content={navigationGoalTooltip} />
<HelpTooltip content={helpTooltips["login"]["navigationGoal"]} />
</div>
<AutoResizingTextarea
onChange={(event) => {
@@ -130,7 +120,7 @@ function LoginNode({ id, data }: NodeProps<LoginNode>) {
handleChange("navigationGoal", event.target.value);
}}
value={inputs.navigationGoal}
placeholder={navigationGoalPlaceholder}
placeholder={placeholders["login"]["navigationGoal"]}
className="nopan text-xs"
/>
</div>
@@ -175,12 +165,12 @@ function LoginNode({ id, data }: NodeProps<LoginNode>) {
Max Retries
</Label>
<HelpTooltip
content={commonHelpTooltipContent["maxRetries"]}
content={helpTooltips["login"]["maxRetries"]}
/>
</div>
<Input
type="number"
placeholder={commonFieldPlaceholders["maxRetries"]}
placeholder={placeholders["login"]["maxRetries"]}
className="nopan w-52 text-xs"
min="0"
value={inputs.maxRetries ?? ""}
@@ -202,12 +192,12 @@ function LoginNode({ id, data }: NodeProps<LoginNode>) {
Max Steps Override
</Label>
<HelpTooltip
content={commonHelpTooltipContent["maxStepsOverride"]}
content={helpTooltips["login"]["maxStepsOverride"]}
/>
</div>
<Input
type="number"
placeholder={commonFieldPlaceholders["maxStepsOverride"]}
placeholder={placeholders["login"]["maxStepsOverride"]}
className="nopan w-52 text-xs"
min="0"
value={inputs.maxStepsOverride ?? ""}
@@ -230,7 +220,7 @@ function LoginNode({ id, data }: NodeProps<LoginNode>) {
Error Messages
</Label>
<HelpTooltip
content={commonHelpTooltipContent["errorCodeMapping"]}
content={helpTooltips["login"]["errorCodeMapping"]}
/>
</div>
<Checkbox
@@ -273,7 +263,7 @@ function LoginNode({ id, data }: NodeProps<LoginNode>) {
Continue on Failure
</Label>
<HelpTooltip
content={commonHelpTooltipContent["continueOnFailure"]}
content={helpTooltips["login"]["continueOnFailure"]}
/>
</div>
<div className="w-52">
@@ -294,7 +284,7 @@ function LoginNode({ id, data }: NodeProps<LoginNode>) {
Cache Actions
</Label>
<HelpTooltip
content={commonHelpTooltipContent["cacheActions"]}
content={helpTooltips["login"]["cacheActions"]}
/>
</div>
<div className="w-52">
@@ -316,7 +306,7 @@ function LoginNode({ id, data }: NodeProps<LoginNode>) {
2FA Verification URL
</Label>
<HelpTooltip
content={commonHelpTooltipContent["totpVerificationUrl"]}
content={helpTooltips["login"]["totpVerificationUrl"]}
/>
</div>
<AutoResizingTextarea
@@ -327,7 +317,7 @@ function LoginNode({ id, data }: NodeProps<LoginNode>) {
handleChange("totpVerificationUrl", event.target.value);
}}
value={inputs.totpVerificationUrl ?? ""}
placeholder={commonFieldPlaceholders["totpVerificationUrl"]}
placeholder={placeholders["login"]["totpVerificationUrl"]}
className="nopan text-xs"
/>
</div>
@@ -337,7 +327,7 @@ function LoginNode({ id, data }: NodeProps<LoginNode>) {
2FA Identifier
</Label>
<HelpTooltip
content={commonHelpTooltipContent["totpIdentifier"]}
content={helpTooltips["login"]["totpIdentifier"]}
/>
</div>
<AutoResizingTextarea
@@ -348,7 +338,7 @@ function LoginNode({ id, data }: NodeProps<LoginNode>) {
handleChange("totpIdentifier", event.target.value);
}}
value={inputs.totpIdentifier ?? ""}
placeholder={commonFieldPlaceholders["totpIdentifier"]}
placeholder={placeholders["login"]["totpIdentifier"]}
className="nopan text-xs"
/>
</div>

View File

@@ -23,8 +23,9 @@ import { useWorkflowParametersState } from "../../useWorkflowParametersState";
import { getAvailableOutputParameterKeys } from "../../workflowEditorUtils";
import { EditableNodeTitle } from "../components/EditableNodeTitle";
import { NodeActionMenu } from "../NodeActionMenu";
import { helpTooltipContent, type LoopNode } from "./types";
import type { LoopNode } from "./types";
import { HelpTooltip } from "@/components/HelpTooltip";
import { helpTooltips } from "../../helpContent";
function LoopNode({ id, data }: NodeProps<LoopNode>) {
const { updateNodeData } = useReactFlow();
@@ -111,7 +112,7 @@ function LoopNode({ id, data }: NodeProps<LoopNode>) {
<Label className="text-xs text-slate-300">
Loop Value Parameter
</Label>
<HelpTooltip content={helpTooltipContent["loopValue"]} />
<HelpTooltip content={helpTooltips["loop"]["loopValue"]} />
</div>
<Select
value={data.loopValue}

View File

@@ -17,8 +17,3 @@ export const loopNodeDefaultData: LoopNodeData = {
export function isLoopNode(node: Node): node is LoopNode {
return node.type === "loop";
}
export const helpTooltipContent = {
loopValue:
"Define this parameterized field with a parameter key to let Skyvern know the core value you're iterating over.",
} as const;

View File

@@ -20,18 +20,8 @@ import { errorMappingExampleValue } from "../types";
import { CodeEditor } from "@/routes/workflows/components/CodeEditor";
import { Switch } from "@/components/ui/switch";
import type { NavigationNode } from "./types";
import {
commonFieldPlaceholders,
commonHelpTooltipContent,
} from "../../constants";
import { RobotIcon } from "@/components/icons/RobotIcon";
const urlTooltip =
"The URL Skyvern is navigating to. Leave this field blank to pick up from where the last block left off.";
const urlPlaceholder = "https://";
const navigationGoalTooltip =
"Give Skyvern an objective. Make sure to include when the task is complete, when it should self-terminate, and any guardrails.";
const navigationGoalPlaceholder = "Tell Skyvern what to do.";
import { helpTooltips, placeholders } from "../../helpContent";
function NavigationNode({ id, data }: NodeProps<NavigationNode>) {
const { updateNodeData } = useReactFlow();
@@ -104,7 +94,7 @@ function NavigationNode({ id, data }: NodeProps<NavigationNode>) {
<div className="space-y-2">
<div className="flex gap-2">
<Label className="text-xs text-slate-300">URL</Label>
<HelpTooltip content={urlTooltip} />
<HelpTooltip content={helpTooltips["navigation"]["url"]} />
</div>
<AutoResizingTextarea
onChange={(event) => {
@@ -114,14 +104,16 @@ function NavigationNode({ id, data }: NodeProps<NavigationNode>) {
handleChange("url", event.target.value);
}}
value={inputs.url}
placeholder={urlPlaceholder}
placeholder={placeholders["navigation"]["url"]}
className="nopan text-xs"
/>
</div>
<div className="space-y-2">
<div className="flex gap-2">
<Label className="text-xs text-slate-300">Navigation Goal</Label>
<HelpTooltip content={navigationGoalTooltip} />
<HelpTooltip
content={helpTooltips["navigation"]["navigationGoal"]}
/>
</div>
<AutoResizingTextarea
onChange={(event) => {
@@ -131,7 +123,7 @@ function NavigationNode({ id, data }: NodeProps<NavigationNode>) {
handleChange("navigationGoal", event.target.value);
}}
value={inputs.navigationGoal}
placeholder={navigationGoalPlaceholder}
placeholder={placeholders["navigation"]["navigationGoal"]}
className="nopan text-xs"
/>
</div>
@@ -150,12 +142,12 @@ function NavigationNode({ id, data }: NodeProps<NavigationNode>) {
Max Retries
</Label>
<HelpTooltip
content={commonHelpTooltipContent["maxRetries"]}
content={helpTooltips["navigation"]["maxRetries"]}
/>
</div>
<Input
type="number"
placeholder={commonFieldPlaceholders["maxRetries"]}
placeholder={placeholders["navigation"]["maxRetries"]}
className="nopan w-52 text-xs"
min="0"
value={inputs.maxRetries ?? ""}
@@ -177,12 +169,12 @@ function NavigationNode({ id, data }: NodeProps<NavigationNode>) {
Max Steps Override
</Label>
<HelpTooltip
content={commonHelpTooltipContent["maxStepsOverride"]}
content={helpTooltips["navigation"]["maxStepsOverride"]}
/>
</div>
<Input
type="number"
placeholder={commonFieldPlaceholders["maxStepsOverride"]}
placeholder={placeholders["navigation"]["maxStepsOverride"]}
className="nopan w-52 text-xs"
min="0"
value={inputs.maxStepsOverride ?? ""}
@@ -205,7 +197,7 @@ function NavigationNode({ id, data }: NodeProps<NavigationNode>) {
Error Messages
</Label>
<HelpTooltip
content={commonHelpTooltipContent["errorCodeMapping"]}
content={helpTooltips["navigation"]["errorCodeMapping"]}
/>
</div>
<Checkbox
@@ -248,7 +240,7 @@ function NavigationNode({ id, data }: NodeProps<NavigationNode>) {
Continue on Failure
</Label>
<HelpTooltip
content={commonHelpTooltipContent["continueOnFailure"]}
content={helpTooltips["navigation"]["continueOnFailure"]}
/>
</div>
<div className="w-52">
@@ -269,7 +261,7 @@ function NavigationNode({ id, data }: NodeProps<NavigationNode>) {
Cache Actions
</Label>
<HelpTooltip
content={commonHelpTooltipContent["cacheActions"]}
content={helpTooltips["navigation"]["cacheActions"]}
/>
</div>
<div className="w-52">
@@ -291,7 +283,7 @@ function NavigationNode({ id, data }: NodeProps<NavigationNode>) {
Complete on Download
</Label>
<HelpTooltip
content={commonHelpTooltipContent["completeOnDownload"]}
content={helpTooltips["navigation"]["completeOnDownload"]}
/>
</div>
<div className="w-52">
@@ -312,12 +304,12 @@ function NavigationNode({ id, data }: NodeProps<NavigationNode>) {
File Suffix
</Label>
<HelpTooltip
content={commonHelpTooltipContent["fileSuffix"]}
content={helpTooltips["navigation"]["fileSuffix"]}
/>
</div>
<Input
type="text"
placeholder={commonFieldPlaceholders["downloadSuffix"]}
placeholder={placeholders["navigation"]["downloadSuffix"]}
className="nopan w-52 text-xs"
value={inputs.downloadSuffix ?? ""}
onChange={(event) => {
@@ -335,7 +327,9 @@ function NavigationNode({ id, data }: NodeProps<NavigationNode>) {
2FA Verification URL
</Label>
<HelpTooltip
content={commonHelpTooltipContent["totpVerificationUrl"]}
content={
helpTooltips["navigation"]["totpVerificationUrl"]
}
/>
</div>
<AutoResizingTextarea
@@ -346,7 +340,9 @@ function NavigationNode({ id, data }: NodeProps<NavigationNode>) {
handleChange("totpVerificationUrl", event.target.value);
}}
value={inputs.totpVerificationUrl ?? ""}
placeholder={commonFieldPlaceholders["totpVerificationUrl"]}
placeholder={
placeholders["navigation"]["totpVerificationUrl"]
}
className="nopan text-xs"
/>
</div>
@@ -356,7 +352,7 @@ function NavigationNode({ id, data }: NodeProps<NavigationNode>) {
2FA Identifier
</Label>
<HelpTooltip
content={commonHelpTooltipContent["totpIdentifier"]}
content={helpTooltips["navigation"]["totpIdentifier"]}
/>
</div>
<AutoResizingTextarea
@@ -367,7 +363,7 @@ function NavigationNode({ id, data }: NodeProps<NavigationNode>) {
handleChange("totpIdentifier", event.target.value);
}}
value={inputs.totpIdentifier ?? ""}
placeholder={commonFieldPlaceholders["totpIdentifier"]}
placeholder={placeholders["navigation"]["totpIdentifier"]}
className="nopan text-xs"
/>
</div>

View File

@@ -1,3 +1,4 @@
import { HelpTooltip } from "@/components/HelpTooltip";
import { Input } from "@/components/ui/input";
import { Label } from "@/components/ui/label";
import { Separator } from "@/components/ui/separator";
@@ -6,10 +7,10 @@ import { useNodeLabelChangeHandler } from "@/routes/workflows/hooks/useLabelChan
import { EnvelopeClosedIcon } from "@radix-ui/react-icons";
import { Handle, NodeProps, Position, useReactFlow } from "@xyflow/react";
import { useState } from "react";
import { helpTooltips } from "../../helpContent";
import { EditableNodeTitle } from "../components/EditableNodeTitle";
import { NodeActionMenu } from "../NodeActionMenu";
import { helpTooltipContent, type SendEmailNode } from "./types";
import { HelpTooltip } from "@/components/HelpTooltip";
import { type SendEmailNode } from "./types";
function SendEmailNode({ id, data }: NodeProps<SendEmailNode>) {
const { updateNodeData } = useReactFlow();
@@ -117,7 +118,9 @@ function SendEmailNode({ id, data }: NodeProps<SendEmailNode>) {
<div className="space-y-2">
<div className="flex gap-2">
<Label className="text-xs text-slate-300">File Attachments</Label>
<HelpTooltip content={helpTooltipContent["fileAttachments"]} />
<HelpTooltip
content={helpTooltips["sendEmail"]["fileAttachments"]}
/>
</div>
<Input
value={inputs.fileAttachments}

View File

@@ -37,8 +37,3 @@ export const sendEmailNodeDefaultData: SendEmailNodeData = {
smtpPasswordSecretParameterKey: SMTP_PASSWORD_PARAMETER_KEY,
continueOnFailure: false,
} as const;
export const helpTooltipContent = {
fileAttachments:
"Since we're in beta this section isn't fully customizable yet, contact us if you'd like to integrate it into your workflow.",
} as const;

View File

@@ -1,7 +1,7 @@
import { MultiSelect } from "@/components/ui/multi-select";
import { useWorkflowParametersState } from "../../useWorkflowParametersState";
import { HelpTooltip } from "@/components/HelpTooltip";
import { helpTooltipContent } from "./types";
import { helpTooltips } from "../../helpContent";
type Props = {
availableOutputParameters: Array<string>;
@@ -30,7 +30,7 @@ function ParametersMultiSelect({
<div className="space-y-2">
<header className="flex gap-2">
<h1 className="text-xs text-slate-300">Parameters</h1>
<HelpTooltip content={helpTooltipContent["parameters"]} />
<HelpTooltip content={helpTooltips["task"]["parameters"]} />
</header>
<MultiSelect
value={parameters}

View File

@@ -28,9 +28,10 @@ import { getAvailableOutputParameterKeys } from "../../workflowEditorUtils";
import { EditableNodeTitle } from "../components/EditableNodeTitle";
import { NodeActionMenu } from "../NodeActionMenu";
import { ParametersMultiSelect } from "./ParametersMultiSelect";
import { fieldPlaceholders, helpTooltipContent, type TaskNode } from "./types";
import type { TaskNode } from "./types";
import { Separator } from "@/components/ui/separator";
import { dataSchemaExampleValue, errorMappingExampleValue } from "../types";
import { helpTooltips, placeholders } from "../../helpContent";
function TaskNode({ id, data }: NodeProps<TaskNode>) {
const { updateNodeData } = useReactFlow();
@@ -113,7 +114,7 @@ function TaskNode({ id, data }: NodeProps<TaskNode>) {
<div className="space-y-2">
<div className="flex gap-2">
<Label className="text-xs text-slate-300">URL</Label>
<HelpTooltip content={helpTooltipContent["url"]} />
<HelpTooltip content={helpTooltips["task"]["url"]} />
</div>
<AutoResizingTextarea
onChange={(event) => {
@@ -123,7 +124,7 @@ function TaskNode({ id, data }: NodeProps<TaskNode>) {
handleChange("url", event.target.value);
}}
value={inputs.url}
placeholder={fieldPlaceholders["url"]}
placeholder={placeholders["task"]["url"]}
className="nopan text-xs"
/>
</div>
@@ -131,7 +132,7 @@ function TaskNode({ id, data }: NodeProps<TaskNode>) {
<div className="flex gap-2">
<Label className="text-xs text-slate-300">Goal</Label>
<HelpTooltip
content={helpTooltipContent["navigationGoal"]}
content={helpTooltips["task"]["navigationGoal"]}
/>
</div>
<AutoResizingTextarea
@@ -142,7 +143,7 @@ function TaskNode({ id, data }: NodeProps<TaskNode>) {
handleChange("navigationGoal", event.target.value);
}}
value={inputs.navigationGoal}
placeholder={fieldPlaceholders["navigationGoal"]}
placeholder={placeholders["task"]["navigationGoal"]}
className="nopan text-xs"
/>
</div>
@@ -168,7 +169,7 @@ function TaskNode({ id, data }: NodeProps<TaskNode>) {
Data Extraction Goal
</Label>
<HelpTooltip
content={helpTooltipContent["dataExtractionGoal"]}
content={helpTooltips["task"]["dataExtractionGoal"]}
/>
</div>
<AutoResizingTextarea
@@ -179,7 +180,7 @@ function TaskNode({ id, data }: NodeProps<TaskNode>) {
handleChange("dataExtractionGoal", event.target.value);
}}
value={inputs.dataExtractionGoal}
placeholder={fieldPlaceholders["dataExtractionGoal"]}
placeholder={placeholders["task"]["dataExtractionGoal"]}
className="nopan text-xs"
/>
</div>
@@ -189,7 +190,9 @@ function TaskNode({ id, data }: NodeProps<TaskNode>) {
<Label className="text-xs text-slate-300">
Data Schema
</Label>
<HelpTooltip content={helpTooltipContent["dataSchema"]} />
<HelpTooltip
content={helpTooltips["task"]["dataSchema"]}
/>
</div>
<Checkbox
checked={inputs.dataSchema !== "null"}
@@ -235,11 +238,11 @@ function TaskNode({ id, data }: NodeProps<TaskNode>) {
<Label className="text-xs font-normal text-slate-300">
Max Retries
</Label>
<HelpTooltip content={helpTooltipContent["maxRetries"]} />
<HelpTooltip content={helpTooltips["task"]["maxRetries"]} />
</div>
<Input
type="number"
placeholder={fieldPlaceholders["maxRetries"]}
placeholder={placeholders["task"]["maxRetries"]}
className="nopan w-52 text-xs"
min="0"
value={inputs.maxRetries ?? ""}
@@ -261,12 +264,12 @@ function TaskNode({ id, data }: NodeProps<TaskNode>) {
Max Steps Override
</Label>
<HelpTooltip
content={helpTooltipContent["maxStepsOverride"]}
content={helpTooltips["task"]["maxStepsOverride"]}
/>
</div>
<Input
type="number"
placeholder={fieldPlaceholders["maxStepsOverride"]}
placeholder={placeholders["task"]["maxStepsOverride"]}
className="nopan w-52 text-xs"
min="0"
value={inputs.maxStepsOverride ?? ""}
@@ -289,7 +292,7 @@ function TaskNode({ id, data }: NodeProps<TaskNode>) {
Error Messages
</Label>
<HelpTooltip
content={helpTooltipContent["errorCodeMapping"]}
content={helpTooltips["task"]["errorCodeMapping"]}
/>
</div>
<Checkbox
@@ -332,7 +335,7 @@ function TaskNode({ id, data }: NodeProps<TaskNode>) {
Continue on Failure
</Label>
<HelpTooltip
content={helpTooltipContent["continueOnFailure"]}
content={helpTooltips["task"]["continueOnFailure"]}
/>
</div>
<div className="w-52">
@@ -352,7 +355,9 @@ function TaskNode({ id, data }: NodeProps<TaskNode>) {
<Label className="text-xs font-normal text-slate-300">
Cache Actions
</Label>
<HelpTooltip content={helpTooltipContent["cacheActions"]} />
<HelpTooltip
content={helpTooltips["task"]["cacheActions"]}
/>
</div>
<div className="w-52">
<Switch
@@ -373,7 +378,7 @@ function TaskNode({ id, data }: NodeProps<TaskNode>) {
Complete on Download
</Label>
<HelpTooltip
content={helpTooltipContent["completeOnDownload"]}
content={helpTooltips["task"]["completeOnDownload"]}
/>
</div>
<div className="w-52">
@@ -393,11 +398,11 @@ function TaskNode({ id, data }: NodeProps<TaskNode>) {
<Label className="text-xs font-normal text-slate-300">
File Suffix
</Label>
<HelpTooltip content={helpTooltipContent["fileSuffix"]} />
<HelpTooltip content={helpTooltips["task"]["fileSuffix"]} />
</div>
<Input
type="text"
placeholder={fieldPlaceholders["downloadSuffix"]}
placeholder={placeholders["task"]["downloadSuffix"]}
className="nopan w-52 text-xs"
value={inputs.downloadSuffix ?? ""}
onChange={(event) => {
@@ -415,7 +420,7 @@ function TaskNode({ id, data }: NodeProps<TaskNode>) {
2FA Verification URL
</Label>
<HelpTooltip
content={helpTooltipContent["totpVerificationUrl"]}
content={helpTooltips["task"]["totpVerificationUrl"]}
/>
</div>
<AutoResizingTextarea
@@ -426,7 +431,7 @@ function TaskNode({ id, data }: NodeProps<TaskNode>) {
handleChange("totpVerificationUrl", event.target.value);
}}
value={inputs.totpVerificationUrl ?? ""}
placeholder={fieldPlaceholders["totpVerificationUrl"]}
placeholder={placeholders["task"]["totpVerificationUrl"]}
className="nopan text-xs"
/>
</div>
@@ -436,7 +441,7 @@ function TaskNode({ id, data }: NodeProps<TaskNode>) {
2FA Identifier
</Label>
<HelpTooltip
content={helpTooltipContent["totpIdentifier"]}
content={helpTooltips["task"]["totpIdentifier"]}
/>
</div>
<AutoResizingTextarea
@@ -447,7 +452,7 @@ function TaskNode({ id, data }: NodeProps<TaskNode>) {
handleChange("totpIdentifier", event.target.value);
}}
value={inputs.totpIdentifier ?? ""}
placeholder={fieldPlaceholders["totpIdentifier"]}
placeholder={placeholders["task"]["totpIdentifier"]}
className="nopan text-xs"
/>
</div>

View File

@@ -1,7 +1,7 @@
import { MultiSelect } from "@/components/ui/multi-select";
import { useWorkflowParametersState } from "../../useWorkflowParametersState";
import { HelpTooltip } from "@/components/HelpTooltip";
import { helpTooltipContent } from "./types";
import { helpTooltips } from "../../helpContent";
type Props = {
availableOutputParameters: Array<string>;
@@ -30,7 +30,7 @@ function TaskNodeParametersPanel({
<div className="space-y-2">
<header className="flex gap-2">
<h1 className="text-xs text-slate-300">Parameters</h1>
<HelpTooltip content={helpTooltipContent["parameters"]} />
<HelpTooltip content={helpTooltips["task"]["parameters"]} />
</header>
<MultiSelect
value={parameters}

View File

@@ -41,49 +41,3 @@ export const taskNodeDefaultData: TaskNodeData = {
export function isTaskNode(node: Node): node is TaskNode {
return node.type === "task";
}
export const helpTooltipContent = {
base: "Tell Skyvern what to do. This is the core of your task block, so make sure your prompt tells Skyvern when it has completed its task, any guardrails, and if there are cases where it should terminate the task early. Define placeholder values using the “parameters” drop down that you predefine or redefine run-to-run. This allows you to make a workflow generalizable to a variety of use cases that change with every run.",
extraction:
"Tell Skyvern what to extract and how it should be formatted, if applicable.",
limits:
"Give Skyvern limitations, such as number of retries on failure, the number of maximum steps, the option to download and append suffix identifiers, and return message for errors Skyvern encounters.",
totp: "Link your internal TOTP storage system to relay 2FA codes we encounter straight to Skyvern. If you have multiple tasks running simultaneously, make sure to link an identifier so Skyvern knows which TOTP URL goes with which task.",
url: "The URL Skyvern is navigating to. Leave this field blank to pick up from where the last task block left off.",
navigationGoal:
"Give Skyvern an objective. Make sure to include when the task is complete, when it should self-terminate, and any guardrails.",
parameters:
"Define placeholder values using the “parameters” drop down that you predefine or redefine run-to-run.",
dataExtractionGoal:
"Tell Skyvern what data you would like to scrape at the end of your run.",
dataSchema: "Specify a format for extracted data in JSON.",
maxRetries:
"Specify how many times you would like a task to retry upon failure.",
maxStepsOverride:
"Specify the maximum number of steps a task can take in total.",
completeOnDownload:
"Allow Skyvern to auto-complete the task when it downloads a file.",
fileSuffix:
"A file suffix that's automatically added to all downloaded files.",
errorCodeMapping:
"Knowing about why a task terminated can be important, specify error messages here.",
totpVerificationUrl:
"If you have an internal system for storing TOTP codes, link the endpoint here.",
totpIdentifier:
"If you are running multiple tasks or workflows at once, you will need to give the task an identifier to know that this TOTP goes with this task.",
continueOnFailure:
"Allow the workflow to continue if it encounters a failure.",
cacheActions: "Cache the actions of this task.",
} as const;
export const fieldPlaceholders = {
url: "https://",
navigationGoal: "Tell Skyvern what to do.",
dataExtractionGoal: "What data do you need to extract?",
maxRetries: "Default: 3",
maxStepsOverride: "Default: 10",
downloadSuffix: "Add an ID for downloaded files",
label: "Task",
totpVerificationUrl: "Provide your 2FA endpoint",
totpIdentifier: "Add an ID that links your TOTP to the task",
};

View File

@@ -1,4 +1,5 @@
import { AutoResizingTextarea } from "@/components/AutoResizingTextarea/AutoResizingTextarea";
import { HelpTooltip } from "@/components/HelpTooltip";
import { Checkbox } from "@/components/ui/checkbox";
import { Label } from "@/components/ui/label";
import { Separator } from "@/components/ui/separator";
@@ -15,13 +16,13 @@ import {
useReactFlow,
} from "@xyflow/react";
import { useState } from "react";
import { AppNode } from "..";
import { helpTooltips } from "../../helpContent";
import { getAvailableOutputParameterKeys } from "../../workflowEditorUtils";
import { EditableNodeTitle } from "../components/EditableNodeTitle";
import { NodeActionMenu } from "../NodeActionMenu";
import { helpTooltipContent, type TextPromptNode } from "./types";
import { HelpTooltip } from "@/components/HelpTooltip";
import { ParametersMultiSelect } from "../TaskNode/ParametersMultiSelect";
import { getAvailableOutputParameterKeys } from "../../workflowEditorUtils";
import { AppNode } from "..";
import { type TextPromptNode } from "./types";
function TextPromptNode({ id, data }: NodeProps<TextPromptNode>) {
const { updateNodeData } = useReactFlow();
@@ -81,7 +82,7 @@ function TextPromptNode({ id, data }: NodeProps<TextPromptNode>) {
<div className="space-y-2">
<div className="flex gap-2">
<Label className="text-xs text-slate-300">Prompt</Label>
<HelpTooltip content={helpTooltipContent["prompt"]} />
<HelpTooltip content={helpTooltips["textPrompt"]["prompt"]} />
</div>
<AutoResizingTextarea
onChange={(event) => {

View File

@@ -17,8 +17,3 @@ export const textPromptNodeDefaultData: TextPromptNodeData = {
continueOnFailure: false,
parameterKeys: [],
} as const;
export const helpTooltipContent = {
prompt:
"Write a prompt you would like passed into the LLM and specify the output format, if applicable.",
};

View File

@@ -1,13 +1,14 @@
import { HelpTooltip } from "@/components/HelpTooltip";
import { Input } from "@/components/ui/input";
import { Label } from "@/components/ui/label";
import { useDeleteNodeCallback } from "@/routes/workflows/hooks/useDeleteNodeCallback";
import { useNodeLabelChangeHandler } from "@/routes/workflows/hooks/useLabelChangeHandler";
import { UploadIcon } from "@radix-ui/react-icons";
import { Handle, NodeProps, Position } from "@xyflow/react";
import { helpTooltips } from "../../helpContent";
import { EditableNodeTitle } from "../components/EditableNodeTitle";
import { NodeActionMenu } from "../NodeActionMenu";
import { helpTooltipContent, type UploadNode } from "./types";
import { HelpTooltip } from "@/components/HelpTooltip";
import { type UploadNode } from "./types";
function UploadNode({ id, data }: NodeProps<UploadNode>) {
const deleteNodeCallback = useDeleteNodeCallback();
@@ -57,7 +58,7 @@ function UploadNode({ id, data }: NodeProps<UploadNode>) {
<div className="space-y-2">
<div className="flex items-center gap-2">
<Label className="text-sm text-slate-400">File Path</Label>
<HelpTooltip content={helpTooltipContent["path"]} />
<HelpTooltip content={helpTooltips["upload"]["path"]} />
</div>
<Input value={data.path} className="nopan text-xs" disabled />
</div>

View File

@@ -15,7 +15,3 @@ export const uploadNodeDefaultData: UploadNodeData = {
path: SKYVERN_DOWNLOAD_DIRECTORY,
continueOnFailure: false,
} as const;
export const helpTooltipContent = {
path: "Since we're in beta this section isn't fully customizable yet, contact us if you'd like to integrate it into your workflow.",
} as const;

View File

@@ -1,5 +1,5 @@
import { Handle, NodeProps, Position, useReactFlow } from "@xyflow/react";
import { helpTooltipContent, type ValidationNode } from "./types";
import type { ValidationNode } from "./types";
import { useNodeLabelChangeHandler } from "@/routes/workflows/hooks/useLabelChangeHandler";
import { useState } from "react";
import { CheckCircledIcon } from "@radix-ui/react-icons";
@@ -20,6 +20,7 @@ import {
AccordionTrigger,
} from "@/components/ui/accordion";
import { Separator } from "@/components/ui/separator";
import { helpTooltips } from "../../helpContent";
function ValidationNode({ id, data }: NodeProps<ValidationNode>) {
const { updateNodeData } = useReactFlow();
@@ -121,7 +122,7 @@ function ValidationNode({ id, data }: NodeProps<ValidationNode>) {
Error Messages
</Label>
<HelpTooltip
content={helpTooltipContent["errorCodeMapping"]}
content={helpTooltips["validation"]["errorCodeMapping"]}
/>
</div>
<Checkbox
@@ -164,7 +165,7 @@ function ValidationNode({ id, data }: NodeProps<ValidationNode>) {
Continue on Failure
</Label>
<HelpTooltip
content={helpTooltipContent["continueOnFailure"]}
content={helpTooltips["validation"]["continueOnFailure"]}
/>
</div>
<div className="w-52">

View File

@@ -20,13 +20,6 @@ export const validationNodeDefaultData: ValidationNodeData = {
parameterKeys: [],
};
export const helpTooltipContent = {
errorCodeMapping:
"Knowing about why a block terminated can be important, specify error messages here.",
continueOnFailure:
"Allow the workflow to continue if it encounters a failure.",
} as const;
export function isValidationNode(node: Node): node is ValidationNode {
return node.type === "validation";
}

View File

@@ -9,6 +9,7 @@ import { EditableNodeTitle } from "../components/EditableNodeTitle";
import { NodeActionMenu } from "../NodeActionMenu";
import type { WaitNode } from "./types";
import { HelpTooltip } from "@/components/HelpTooltip";
import { helpTooltips } from "../../helpContent";
function WaitNode({ id, data }: NodeProps<WaitNode>) {
const { updateNodeData } = useReactFlow();
@@ -72,7 +73,7 @@ function WaitNode({ id, data }: NodeProps<WaitNode>) {
<Label className="text-xs text-slate-300">
Wait Time (in seconds)
</Label>
<HelpTooltip content="Specify a number for how many seconds to wait. Value must be between 0 and 300 seconds." />
<HelpTooltip content={helpTooltips["wait"]["waitInSeconds"]} />
</div>
<Input
type="number"