feat: show all block parameters including advanced settings in WR UI (#SKY-6813) (#4807)
This commit is contained in:
@@ -13,6 +13,7 @@ import { DebuggerSendEmailBlockParameters } from "./DebuggerSendEmailBlockInfo";
|
||||
import { ProxyLocation } from "@/api/types";
|
||||
import { KeyValueInput } from "@/components/KeyValueInput";
|
||||
import { HelpTooltip } from "@/components/HelpTooltip";
|
||||
import { Switch } from "@/components/ui/switch";
|
||||
|
||||
function DebuggerPostRunParameters() {
|
||||
const { data: workflowRunTimeline, isLoading: workflowRunTimelineIsLoading } =
|
||||
@@ -104,6 +105,127 @@ function DebuggerPostRunParameters() {
|
||||
</div>
|
||||
</div>
|
||||
) : null}
|
||||
{activeBlock && activeBlock.block_type === WorkflowBlockTypes.Wait ? (
|
||||
<div className="rounded bg-slate-elevation2 p-6">
|
||||
<div className="space-y-4">
|
||||
<h1 className="text-sm font-bold">Wait Block Parameters</h1>
|
||||
<div className="flex flex-col gap-2">
|
||||
<div className="flex w-full items-center justify-start gap-2">
|
||||
<h1 className="text-sm">Wait Duration</h1>
|
||||
<HelpTooltip content="Seconds to wait before proceeding." />
|
||||
</div>
|
||||
<Input
|
||||
value={
|
||||
typeof activeBlock.wait_sec === "number"
|
||||
? `${activeBlock.wait_sec}s`
|
||||
: "N/A"
|
||||
}
|
||||
readOnly
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
) : null}
|
||||
{activeBlock &&
|
||||
activeBlock.block_type === WorkflowBlockTypes.HumanInteraction ? (
|
||||
<div className="rounded bg-slate-elevation2 p-6">
|
||||
<div className="space-y-4">
|
||||
<h1 className="text-sm font-bold">
|
||||
Human Interaction Block Parameters
|
||||
</h1>
|
||||
{activeBlock.instructions ? (
|
||||
<div className="flex flex-col gap-2">
|
||||
<div className="flex w-full items-center justify-start gap-2">
|
||||
<h1 className="text-sm">Instructions</h1>
|
||||
<HelpTooltip content="Instructions for the human interaction." />
|
||||
</div>
|
||||
<AutoResizingTextarea
|
||||
value={activeBlock.instructions}
|
||||
readOnly
|
||||
/>
|
||||
</div>
|
||||
) : null}
|
||||
{activeBlock.positive_descriptor ? (
|
||||
<div className="flex flex-col gap-2">
|
||||
<h1 className="text-sm">Positive Descriptor</h1>
|
||||
<Input value={activeBlock.positive_descriptor} readOnly />
|
||||
</div>
|
||||
) : null}
|
||||
{activeBlock.negative_descriptor ? (
|
||||
<div className="flex flex-col gap-2">
|
||||
<h1 className="text-sm">Negative Descriptor</h1>
|
||||
<Input value={activeBlock.negative_descriptor} readOnly />
|
||||
</div>
|
||||
) : null}
|
||||
</div>
|
||||
</div>
|
||||
) : null}
|
||||
{activeBlock &&
|
||||
activeBlock.block_type === WorkflowBlockTypes.Conditional ? (
|
||||
<div className="rounded bg-slate-elevation2 p-6">
|
||||
<div className="space-y-4">
|
||||
<h1 className="text-sm font-bold">Conditional Block Parameters</h1>
|
||||
{activeBlock.executed_branch_expression ? (
|
||||
<div className="flex flex-col gap-2">
|
||||
<div className="flex w-full items-center justify-start gap-2">
|
||||
<h1 className="text-sm">Executed Expression</h1>
|
||||
<HelpTooltip content="The branch expression that was evaluated." />
|
||||
</div>
|
||||
<AutoResizingTextarea
|
||||
value={activeBlock.executed_branch_expression}
|
||||
readOnly
|
||||
/>
|
||||
</div>
|
||||
) : null}
|
||||
{typeof activeBlock.executed_branch_result === "boolean" ? (
|
||||
<div className="flex flex-col gap-2">
|
||||
<h1 className="text-sm">Branch Result</h1>
|
||||
<div className="flex items-center gap-3">
|
||||
<Switch
|
||||
checked={activeBlock.executed_branch_result}
|
||||
disabled
|
||||
/>
|
||||
<span className="text-sm text-slate-400">
|
||||
{activeBlock.executed_branch_result ? "True" : "False"}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
) : null}
|
||||
{activeBlock.executed_branch_next_block ? (
|
||||
<div className="flex flex-col gap-2">
|
||||
<h1 className="text-sm">Next Block</h1>
|
||||
<Input
|
||||
value={activeBlock.executed_branch_next_block}
|
||||
readOnly
|
||||
/>
|
||||
</div>
|
||||
) : null}
|
||||
{activeBlock.executed_branch_id ? (
|
||||
<div className="flex flex-col gap-2">
|
||||
<h1 className="text-sm">Executed Branch ID</h1>
|
||||
<Input value={activeBlock.executed_branch_id} readOnly />
|
||||
</div>
|
||||
) : null}
|
||||
</div>
|
||||
</div>
|
||||
) : null}
|
||||
{activeBlock &&
|
||||
activeBlock.block_type === WorkflowBlockTypes.TextPrompt ? (
|
||||
<div className="rounded bg-slate-elevation2 p-6">
|
||||
<div className="space-y-4">
|
||||
<h1 className="text-sm font-bold">Text Prompt Block Parameters</h1>
|
||||
{activeBlock.prompt ? (
|
||||
<div className="flex flex-col gap-2">
|
||||
<div className="flex w-full items-center justify-start gap-2">
|
||||
<h1 className="text-sm">Prompt</h1>
|
||||
<HelpTooltip content="Instructions passed to the selected LLM." />
|
||||
</div>
|
||||
<AutoResizingTextarea value={activeBlock.prompt} readOnly />
|
||||
</div>
|
||||
) : null}
|
||||
</div>
|
||||
</div>
|
||||
) : null}
|
||||
<div className="rounded bg-slate-elevation2 p-6">
|
||||
<div className="space-y-4">
|
||||
<h1 className="text-sm font-bold">Workflow Parameters</h1>
|
||||
@@ -171,6 +293,27 @@ function DebuggerPostRunParameters() {
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
{workflowRun.browser_session_id ? (
|
||||
<div className="flex flex-col gap-2">
|
||||
<div className="flex w-full items-center justify-start gap-2">
|
||||
<h1 className="text-sm">Browser Session ID</h1>
|
||||
<HelpTooltip content="The browser session ID used for this run." />
|
||||
</div>
|
||||
<Input value={workflowRun.browser_session_id} readOnly />
|
||||
</div>
|
||||
) : null}
|
||||
{workflowRun.max_screenshot_scrolls != null ? (
|
||||
<div className="flex flex-col gap-2">
|
||||
<div className="flex w-full items-center justify-start gap-2">
|
||||
<h1 className="text-sm">Max Screenshot Scrolls</h1>
|
||||
<HelpTooltip content="Maximum number of screenshot scrolls." />
|
||||
</div>
|
||||
<Input
|
||||
value={workflowRun.max_screenshot_scrolls.toString()}
|
||||
readOnly
|
||||
/>
|
||||
</div>
|
||||
) : null}
|
||||
</div>
|
||||
</div>
|
||||
{workflowRun.task_v2 ? (
|
||||
@@ -187,10 +330,6 @@ function DebuggerPostRunParameters() {
|
||||
readOnly
|
||||
/>
|
||||
</div>
|
||||
<AutoResizingTextarea
|
||||
value={workflowRun.task_v2?.prompt ?? ""}
|
||||
readOnly
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
) : null}
|
||||
|
||||
@@ -140,6 +140,29 @@ function DebuggerTaskBlockParameters({ block }: Props) {
|
||||
</div>
|
||||
</div>
|
||||
) : null}
|
||||
|
||||
<div className="flex flex-col gap-2">
|
||||
<div className="flex w-full items-center justify-start gap-2">
|
||||
<h1 className="text-sm">Continue on Failure</h1>
|
||||
<HelpTooltip content="Whether to continue the workflow if this block fails" />
|
||||
</div>
|
||||
<div className="flex items-center gap-3">
|
||||
<Switch checked={block.continue_on_failure} disabled />
|
||||
<span className="text-sm text-slate-400">
|
||||
{block.continue_on_failure ? "Enabled" : "Disabled"}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{block.engine ? (
|
||||
<div className="flex flex-col gap-2">
|
||||
<div className="flex w-full items-center justify-start gap-2">
|
||||
<h1 className="text-sm">Engine</h1>
|
||||
<HelpTooltip content="The execution engine used for this block" />
|
||||
</div>
|
||||
<Input value={block.engine} readOnly />
|
||||
</div>
|
||||
) : null}
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { ActionsApiResponse, Status } from "@/api/types";
|
||||
import { ActionsApiResponse, RunEngine, Status } from "@/api/types";
|
||||
import { isTaskVariantBlock, WorkflowBlockType } from "./workflowTypes";
|
||||
import { ActionItem } from "../workflowRun/WorkflowRunOverview";
|
||||
|
||||
@@ -41,6 +41,7 @@ export type WorkflowRunBlock = {
|
||||
terminate_criterion: string | null;
|
||||
complete_criterion: string | null;
|
||||
include_action_history_in_verification: boolean | null;
|
||||
engine: RunEngine | null;
|
||||
actions: Array<ActionsApiResponse> | null;
|
||||
recipients?: Array<string> | null;
|
||||
attachments?: Array<string> | null;
|
||||
|
||||
@@ -2,14 +2,19 @@ import { AutoResizingTextarea } from "@/components/AutoResizingTextarea/AutoResi
|
||||
import { Input } from "@/components/ui/input";
|
||||
import { CodeEditor } from "@/routes/workflows/components/CodeEditor";
|
||||
import { WorkflowRunBlock } from "../types/workflowRunTypes";
|
||||
import { isTaskVariantBlock, WorkflowBlockTypes } from "../types/workflowTypes";
|
||||
import {
|
||||
isTaskVariantBlock,
|
||||
WorkflowBlockTypes,
|
||||
type WorkflowBlock,
|
||||
} from "../types/workflowTypes";
|
||||
import { Switch } from "@/components/ui/switch";
|
||||
|
||||
type Props = {
|
||||
block: WorkflowRunBlock;
|
||||
definitionBlock?: WorkflowBlock | null;
|
||||
};
|
||||
|
||||
function TaskBlockParameters({ block }: Props) {
|
||||
function TaskBlockParameters({ block, definitionBlock }: Props) {
|
||||
const isTaskVariant = isTaskVariantBlock(block);
|
||||
if (!isTaskVariant) {
|
||||
return null;
|
||||
@@ -32,6 +37,66 @@ function TaskBlockParameters({ block }: Props) {
|
||||
block.block_type === WorkflowBlockTypes.Task ||
|
||||
block.block_type === WorkflowBlockTypes.Navigation;
|
||||
|
||||
// Advanced settings from definition block
|
||||
const errorCodeMapping =
|
||||
definitionBlock &&
|
||||
"error_code_mapping" in definitionBlock &&
|
||||
definitionBlock.error_code_mapping
|
||||
? definitionBlock.error_code_mapping
|
||||
: null;
|
||||
|
||||
const maxRetries =
|
||||
definitionBlock && "max_retries" in definitionBlock
|
||||
? definitionBlock.max_retries
|
||||
: undefined;
|
||||
|
||||
const maxStepsPerRun =
|
||||
definitionBlock && "max_steps_per_run" in definitionBlock
|
||||
? definitionBlock.max_steps_per_run
|
||||
: undefined;
|
||||
|
||||
const totpVerificationUrl =
|
||||
definitionBlock && "totp_verification_url" in definitionBlock
|
||||
? definitionBlock.totp_verification_url
|
||||
: null;
|
||||
|
||||
const totpIdentifier =
|
||||
definitionBlock && "totp_identifier" in definitionBlock
|
||||
? definitionBlock.totp_identifier
|
||||
: null;
|
||||
|
||||
const completeOnDownload =
|
||||
definitionBlock && "complete_on_download" in definitionBlock
|
||||
? definitionBlock.complete_on_download
|
||||
: undefined;
|
||||
|
||||
const downloadSuffix =
|
||||
definitionBlock && "download_suffix" in definitionBlock
|
||||
? definitionBlock.download_suffix
|
||||
: null;
|
||||
|
||||
const disableCache =
|
||||
definitionBlock && "disable_cache" in definitionBlock
|
||||
? definitionBlock.disable_cache
|
||||
: undefined;
|
||||
|
||||
const engine =
|
||||
block.engine ??
|
||||
(definitionBlock && "engine" in definitionBlock
|
||||
? definitionBlock.engine
|
||||
: null);
|
||||
|
||||
const hasAdvancedSettings =
|
||||
errorCodeMapping !== null ||
|
||||
typeof maxRetries === "number" ||
|
||||
typeof maxStepsPerRun === "number" ||
|
||||
Boolean(totpVerificationUrl) ||
|
||||
Boolean(totpIdentifier) ||
|
||||
completeOnDownload === true ||
|
||||
Boolean(downloadSuffix) ||
|
||||
disableCache === true ||
|
||||
engine !== null;
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className="flex gap-16">
|
||||
@@ -151,6 +216,131 @@ function TaskBlockParameters({ block }: Props) {
|
||||
</div>
|
||||
</div>
|
||||
) : null}
|
||||
|
||||
<div className="flex gap-16">
|
||||
<div className="w-80">
|
||||
<h1 className="text-lg">Continue on Failure</h1>
|
||||
<h2 className="text-base text-slate-400">
|
||||
Whether to continue the workflow if this block fails
|
||||
</h2>
|
||||
</div>
|
||||
<div className="flex w-full items-center gap-3">
|
||||
<Switch checked={block.continue_on_failure} disabled />
|
||||
<span className="text-sm text-slate-400">
|
||||
{block.continue_on_failure ? "Enabled" : "Disabled"}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{hasAdvancedSettings ? (
|
||||
<>
|
||||
<h2 className="text-base font-semibold text-slate-300">
|
||||
Advanced Settings
|
||||
</h2>
|
||||
|
||||
{engine ? (
|
||||
<div className="flex gap-16">
|
||||
<div className="w-80">
|
||||
<h1 className="text-lg">Engine</h1>
|
||||
<h2 className="text-base text-slate-400">
|
||||
The execution engine used for this block
|
||||
</h2>
|
||||
</div>
|
||||
<Input value={engine} readOnly />
|
||||
</div>
|
||||
) : null}
|
||||
|
||||
{errorCodeMapping ? (
|
||||
<div className="flex gap-16">
|
||||
<div className="w-80">
|
||||
<h1 className="text-lg">Error Code Mapping</h1>
|
||||
<h2 className="text-base text-slate-400">
|
||||
Custom error codes and their descriptions
|
||||
</h2>
|
||||
</div>
|
||||
<CodeEditor
|
||||
className="w-full"
|
||||
language="json"
|
||||
value={JSON.stringify(errorCodeMapping, null, 2)}
|
||||
readOnly
|
||||
minHeight="96px"
|
||||
maxHeight="200px"
|
||||
/>
|
||||
</div>
|
||||
) : null}
|
||||
|
||||
{typeof maxRetries === "number" ? (
|
||||
<div className="flex gap-16">
|
||||
<div className="w-80">
|
||||
<h1 className="text-lg">Max Retries</h1>
|
||||
</div>
|
||||
<Input value={maxRetries.toString()} readOnly />
|
||||
</div>
|
||||
) : null}
|
||||
|
||||
{typeof maxStepsPerRun === "number" ? (
|
||||
<div className="flex gap-16">
|
||||
<div className="w-80">
|
||||
<h1 className="text-lg">Max Steps Per Run</h1>
|
||||
</div>
|
||||
<Input value={maxStepsPerRun.toString()} readOnly />
|
||||
</div>
|
||||
) : null}
|
||||
|
||||
{totpVerificationUrl ? (
|
||||
<div className="flex gap-16">
|
||||
<div className="w-80">
|
||||
<h1 className="text-lg">TOTP Verification URL</h1>
|
||||
</div>
|
||||
<Input value={totpVerificationUrl} readOnly />
|
||||
</div>
|
||||
) : null}
|
||||
|
||||
{totpIdentifier ? (
|
||||
<div className="flex gap-16">
|
||||
<div className="w-80">
|
||||
<h1 className="text-lg">TOTP Identifier</h1>
|
||||
</div>
|
||||
<Input value={totpIdentifier} readOnly />
|
||||
</div>
|
||||
) : null}
|
||||
|
||||
{completeOnDownload === true ? (
|
||||
<div className="flex gap-16">
|
||||
<div className="w-80">
|
||||
<h1 className="text-lg">Complete on Download</h1>
|
||||
</div>
|
||||
<div className="flex w-full items-center gap-3">
|
||||
<Switch checked={true} disabled />
|
||||
<span className="text-sm text-slate-400">Enabled</span>
|
||||
</div>
|
||||
</div>
|
||||
) : null}
|
||||
|
||||
{downloadSuffix ? (
|
||||
<div className="flex gap-16">
|
||||
<div className="w-80">
|
||||
<h1 className="text-lg">Download Suffix</h1>
|
||||
</div>
|
||||
<Input value={downloadSuffix} readOnly />
|
||||
</div>
|
||||
) : null}
|
||||
|
||||
{disableCache === true ? (
|
||||
<div className="flex gap-16">
|
||||
<div className="w-80">
|
||||
<h1 className="text-lg">Cache Disabled</h1>
|
||||
</div>
|
||||
<div className="flex w-full items-center gap-3">
|
||||
<Switch checked={true} disabled />
|
||||
<span className="text-sm text-slate-400">
|
||||
Cache is disabled for this block
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
) : null}
|
||||
</>
|
||||
) : null}
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -22,6 +22,12 @@ import { CodeBlockParameters } from "./blockInfo/CodeBlockParameters";
|
||||
import { TextPromptBlockParameters } from "./blockInfo/TextPromptBlockParameters";
|
||||
import { GotoUrlBlockParameters } from "./blockInfo/GotoUrlBlockParameters";
|
||||
import { FileDownloadBlockParameters } from "./blockInfo/FileDownloadBlockParameters";
|
||||
import { WaitBlockParameters } from "./blockInfo/WaitBlockParameters";
|
||||
import { HttpRequestBlockParameters } from "./blockInfo/HttpRequestBlockParameters";
|
||||
import { PrintPageBlockParameters } from "./blockInfo/PrintPageBlockParameters";
|
||||
import { HumanInteractionBlockParameters } from "./blockInfo/HumanInteractionBlockParameters";
|
||||
import { ConditionalBlockParameters } from "./blockInfo/ConditionalBlockParameters";
|
||||
import { Taskv2BlockParameters } from "./blockInfo/Taskv2BlockParameters";
|
||||
|
||||
function WorkflowPostRunParameters() {
|
||||
const { data: workflowRunTimeline, isLoading: workflowRunTimelineIsLoading } =
|
||||
@@ -86,7 +92,10 @@ function WorkflowPostRunParameters() {
|
||||
<div className="rounded bg-slate-elevation2 p-6">
|
||||
<div className="space-y-4">
|
||||
<h1 className="text-lg font-bold">Block Parameters</h1>
|
||||
<TaskBlockParameters block={activeBlock} />
|
||||
<TaskBlockParameters
|
||||
block={activeBlock}
|
||||
definitionBlock={definitionBlock}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
) : null}
|
||||
@@ -191,6 +200,142 @@ function WorkflowPostRunParameters() {
|
||||
</div>
|
||||
</div>
|
||||
) : null}
|
||||
{activeBlock && activeBlock.block_type === WorkflowBlockTypes.Wait ? (
|
||||
<div className="rounded bg-slate-elevation2 p-6">
|
||||
<div className="space-y-4">
|
||||
<h1 className="text-lg font-bold">Wait Block</h1>
|
||||
<WaitBlockParameters
|
||||
waitSec={
|
||||
activeBlock.wait_sec ??
|
||||
(isBlockOfType(definitionBlock, WorkflowBlockTypes.Wait)
|
||||
? definitionBlock.wait_sec ?? null
|
||||
: null)
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
) : null}
|
||||
{activeBlock &&
|
||||
activeBlock.block_type === WorkflowBlockTypes.HttpRequest &&
|
||||
isBlockOfType(definitionBlock, WorkflowBlockTypes.HttpRequest) ? (
|
||||
<div className="rounded bg-slate-elevation2 p-6">
|
||||
<div className="space-y-4">
|
||||
<h1 className="text-lg font-bold">HTTP Request Block</h1>
|
||||
<HttpRequestBlockParameters
|
||||
method={definitionBlock.method}
|
||||
url={definitionBlock.url}
|
||||
headers={definitionBlock.headers}
|
||||
body={definitionBlock.body}
|
||||
files={definitionBlock.files}
|
||||
timeout={definitionBlock.timeout}
|
||||
followRedirects={definitionBlock.follow_redirects}
|
||||
downloadFilename={definitionBlock.download_filename}
|
||||
saveResponseAsFile={definitionBlock.save_response_as_file}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
) : null}
|
||||
{activeBlock &&
|
||||
activeBlock.block_type === WorkflowBlockTypes.PrintPage &&
|
||||
isBlockOfType(definitionBlock, WorkflowBlockTypes.PrintPage) ? (
|
||||
<div className="rounded bg-slate-elevation2 p-6">
|
||||
<div className="space-y-4">
|
||||
<h1 className="text-lg font-bold">Print Page Block</h1>
|
||||
<PrintPageBlockParameters
|
||||
format={definitionBlock.format}
|
||||
landscape={definitionBlock.landscape}
|
||||
printBackground={definitionBlock.print_background}
|
||||
includeTimestamp={definitionBlock.include_timestamp}
|
||||
customFilename={definitionBlock.custom_filename}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
) : null}
|
||||
{activeBlock &&
|
||||
activeBlock.block_type === WorkflowBlockTypes.HumanInteraction ? (
|
||||
<div className="rounded bg-slate-elevation2 p-6">
|
||||
<div className="space-y-4">
|
||||
<h1 className="text-lg font-bold">Human Interaction Block</h1>
|
||||
<HumanInteractionBlockParameters
|
||||
instructions={
|
||||
activeBlock.instructions ??
|
||||
(isBlockOfType(
|
||||
definitionBlock,
|
||||
WorkflowBlockTypes.HumanInteraction,
|
||||
)
|
||||
? definitionBlock.instructions
|
||||
: null)
|
||||
}
|
||||
positiveDescriptor={
|
||||
activeBlock.positive_descriptor ??
|
||||
(isBlockOfType(
|
||||
definitionBlock,
|
||||
WorkflowBlockTypes.HumanInteraction,
|
||||
)
|
||||
? definitionBlock.positive_descriptor
|
||||
: null)
|
||||
}
|
||||
negativeDescriptor={
|
||||
activeBlock.negative_descriptor ??
|
||||
(isBlockOfType(
|
||||
definitionBlock,
|
||||
WorkflowBlockTypes.HumanInteraction,
|
||||
)
|
||||
? definitionBlock.negative_descriptor
|
||||
: null)
|
||||
}
|
||||
timeoutSeconds={
|
||||
isBlockOfType(
|
||||
definitionBlock,
|
||||
WorkflowBlockTypes.HumanInteraction,
|
||||
)
|
||||
? definitionBlock.timeout_seconds
|
||||
: null
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
) : null}
|
||||
{activeBlock &&
|
||||
activeBlock.block_type === WorkflowBlockTypes.Conditional ? (
|
||||
<div className="rounded bg-slate-elevation2 p-6">
|
||||
<div className="space-y-4">
|
||||
<h1 className="text-lg font-bold">Conditional Block</h1>
|
||||
<ConditionalBlockParameters
|
||||
branchConditions={
|
||||
isBlockOfType(definitionBlock, WorkflowBlockTypes.Conditional)
|
||||
? definitionBlock.branch_conditions
|
||||
: null
|
||||
}
|
||||
executedBranchId={activeBlock.executed_branch_id ?? null}
|
||||
executedBranchExpression={
|
||||
activeBlock.executed_branch_expression ?? null
|
||||
}
|
||||
executedBranchResult={activeBlock.executed_branch_result ?? null}
|
||||
executedBranchNextBlock={
|
||||
activeBlock.executed_branch_next_block ?? null
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
) : null}
|
||||
{activeBlock &&
|
||||
activeBlock.block_type === WorkflowBlockTypes.Taskv2 &&
|
||||
isBlockOfType(definitionBlock, WorkflowBlockTypes.Taskv2) ? (
|
||||
<div className="rounded bg-slate-elevation2 p-6">
|
||||
<div className="space-y-4">
|
||||
<h1 className="text-lg font-bold">Task v2 Block</h1>
|
||||
<Taskv2BlockParameters
|
||||
prompt={activeBlock.prompt ?? definitionBlock.prompt ?? ""}
|
||||
url={activeBlock.url ?? definitionBlock.url}
|
||||
maxSteps={definitionBlock.max_steps}
|
||||
totpVerificationUrl={definitionBlock.totp_verification_url}
|
||||
totpIdentifier={definitionBlock.totp_identifier}
|
||||
disableCache={definitionBlock.disable_cache}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
) : null}
|
||||
<div className="rounded bg-slate-elevation2 p-6">
|
||||
<div className="space-y-4">
|
||||
<h1 className="text-lg font-bold">Workflow Input Parameters</h1>
|
||||
@@ -252,6 +397,36 @@ function WorkflowPostRunParameters() {
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
{workflowRun.browser_session_id ? (
|
||||
<div className="flex gap-16">
|
||||
<div className="w-80">
|
||||
<h1 className="text-lg">Browser Session ID</h1>
|
||||
</div>
|
||||
<Input value={workflowRun.browser_session_id} readOnly />
|
||||
</div>
|
||||
) : null}
|
||||
{workflow?.run_with ? (
|
||||
<div className="flex gap-16">
|
||||
<div className="w-80">
|
||||
<h1 className="text-lg">Run With</h1>
|
||||
<h2 className="text-base text-slate-400">
|
||||
Execution mode for this workflow
|
||||
</h2>
|
||||
</div>
|
||||
<Input value={workflow.run_with} readOnly />
|
||||
</div>
|
||||
) : null}
|
||||
{workflowRun.max_screenshot_scrolls != null ? (
|
||||
<div className="flex gap-16">
|
||||
<div className="w-80">
|
||||
<h1 className="text-lg">Max Screenshot Scrolls</h1>
|
||||
</div>
|
||||
<Input
|
||||
value={workflowRun.max_screenshot_scrolls.toString()}
|
||||
readOnly
|
||||
/>
|
||||
</div>
|
||||
) : null}
|
||||
</div>
|
||||
</div>
|
||||
{workflowRun.task_v2 ? (
|
||||
|
||||
@@ -0,0 +1,110 @@
|
||||
import { AutoResizingTextarea } from "@/components/AutoResizingTextarea/AutoResizingTextarea";
|
||||
import { Input } from "@/components/ui/input";
|
||||
import { Switch } from "@/components/ui/switch";
|
||||
import type { BranchCondition } from "@/routes/workflows/types/workflowTypes";
|
||||
|
||||
type Props = {
|
||||
branchConditions: Array<BranchCondition> | null;
|
||||
executedBranchId: string | null;
|
||||
executedBranchExpression: string | null;
|
||||
executedBranchResult: boolean | null;
|
||||
executedBranchNextBlock: string | null;
|
||||
};
|
||||
|
||||
function ConditionalBlockParameters({
|
||||
branchConditions,
|
||||
executedBranchId,
|
||||
executedBranchExpression,
|
||||
executedBranchResult,
|
||||
executedBranchNextBlock,
|
||||
}: Props) {
|
||||
return (
|
||||
<div className="space-y-4">
|
||||
{executedBranchExpression ? (
|
||||
<div className="flex gap-16">
|
||||
<div className="w-80">
|
||||
<h1 className="text-lg">Executed Expression</h1>
|
||||
<h2 className="text-base text-slate-400">
|
||||
The branch expression that was evaluated
|
||||
</h2>
|
||||
</div>
|
||||
<AutoResizingTextarea value={executedBranchExpression} readOnly />
|
||||
</div>
|
||||
) : null}
|
||||
{typeof executedBranchResult === "boolean" ? (
|
||||
<div className="flex gap-16">
|
||||
<div className="w-80">
|
||||
<h1 className="text-lg">Branch Result</h1>
|
||||
</div>
|
||||
<div className="flex w-full items-center gap-3">
|
||||
<Switch checked={executedBranchResult} disabled />
|
||||
<span className="text-sm text-slate-400">
|
||||
{executedBranchResult ? "True" : "False"}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
) : null}
|
||||
{executedBranchNextBlock ? (
|
||||
<div className="flex gap-16">
|
||||
<div className="w-80">
|
||||
<h1 className="text-lg">Next Block</h1>
|
||||
<h2 className="text-base text-slate-400">
|
||||
The block that was executed after the condition
|
||||
</h2>
|
||||
</div>
|
||||
<Input value={executedBranchNextBlock} readOnly />
|
||||
</div>
|
||||
) : null}
|
||||
{executedBranchId ? (
|
||||
<div className="flex gap-16">
|
||||
<div className="w-80">
|
||||
<h1 className="text-lg">Executed Branch ID</h1>
|
||||
</div>
|
||||
<Input value={executedBranchId} readOnly />
|
||||
</div>
|
||||
) : null}
|
||||
{branchConditions && branchConditions.length > 0 ? (
|
||||
<div className="space-y-3">
|
||||
<h2 className="text-base font-semibold text-slate-300">
|
||||
Branch Conditions
|
||||
</h2>
|
||||
{branchConditions.map((condition) => (
|
||||
<div
|
||||
key={condition.id}
|
||||
className="space-y-2 rounded border border-slate-700/40 bg-slate-elevation3 p-3"
|
||||
>
|
||||
{condition.description ? (
|
||||
<p className="text-sm text-slate-400">
|
||||
{condition.description}
|
||||
</p>
|
||||
) : null}
|
||||
{condition.criteria?.expression ? (
|
||||
<div className="flex items-center gap-2">
|
||||
<span className="text-sm font-medium">Expression:</span>
|
||||
<code className="text-sm text-slate-300">
|
||||
{condition.criteria.expression}
|
||||
</code>
|
||||
</div>
|
||||
) : null}
|
||||
{condition.next_block_label ? (
|
||||
<div className="flex items-center gap-2">
|
||||
<span className="text-sm font-medium">Next Block:</span>
|
||||
<span className="text-sm text-slate-300">
|
||||
{condition.next_block_label}
|
||||
</span>
|
||||
</div>
|
||||
) : null}
|
||||
{condition.is_default ? (
|
||||
<span className="inline-block rounded bg-slate-700 px-2 py-0.5 text-xs">
|
||||
Default
|
||||
</span>
|
||||
) : null}
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
) : null}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export { ConditionalBlockParameters };
|
||||
@@ -0,0 +1,134 @@
|
||||
import { AutoResizingTextarea } from "@/components/AutoResizingTextarea/AutoResizingTextarea";
|
||||
import { Input } from "@/components/ui/input";
|
||||
import { Switch } from "@/components/ui/switch";
|
||||
import { CodeEditor } from "@/routes/workflows/components/CodeEditor";
|
||||
|
||||
type Props = {
|
||||
method: string;
|
||||
url: string | null;
|
||||
headers: Record<string, string> | null;
|
||||
body: Record<string, unknown> | null;
|
||||
files: Record<string, string> | null;
|
||||
timeout: number;
|
||||
followRedirects: boolean;
|
||||
downloadFilename: string | null;
|
||||
saveResponseAsFile: boolean;
|
||||
};
|
||||
|
||||
function HttpRequestBlockParameters({
|
||||
method,
|
||||
url,
|
||||
headers,
|
||||
body,
|
||||
files,
|
||||
timeout,
|
||||
followRedirects,
|
||||
downloadFilename,
|
||||
saveResponseAsFile,
|
||||
}: Props) {
|
||||
return (
|
||||
<div className="space-y-4">
|
||||
<div className="flex gap-16">
|
||||
<div className="w-80">
|
||||
<h1 className="text-lg">Method</h1>
|
||||
</div>
|
||||
<Input value={method} readOnly />
|
||||
</div>
|
||||
{url ? (
|
||||
<div className="flex gap-16">
|
||||
<div className="w-80">
|
||||
<h1 className="text-lg">URL</h1>
|
||||
</div>
|
||||
<AutoResizingTextarea value={url} readOnly />
|
||||
</div>
|
||||
) : null}
|
||||
{headers && Object.keys(headers).length > 0 ? (
|
||||
<div className="flex gap-16">
|
||||
<div className="w-80">
|
||||
<h1 className="text-lg">Headers</h1>
|
||||
</div>
|
||||
<CodeEditor
|
||||
className="w-full"
|
||||
language="json"
|
||||
value={JSON.stringify(headers, null, 2)}
|
||||
readOnly
|
||||
minHeight="96px"
|
||||
maxHeight="200px"
|
||||
/>
|
||||
</div>
|
||||
) : null}
|
||||
{body && Object.keys(body).length > 0 ? (
|
||||
<div className="flex gap-16">
|
||||
<div className="w-80">
|
||||
<h1 className="text-lg">Body</h1>
|
||||
</div>
|
||||
<CodeEditor
|
||||
className="w-full"
|
||||
language="json"
|
||||
value={JSON.stringify(body, null, 2)}
|
||||
readOnly
|
||||
minHeight="96px"
|
||||
maxHeight="200px"
|
||||
/>
|
||||
</div>
|
||||
) : null}
|
||||
{files && Object.keys(files).length > 0 ? (
|
||||
<div className="flex gap-16">
|
||||
<div className="w-80">
|
||||
<h1 className="text-lg">Files</h1>
|
||||
<h2 className="text-base text-slate-400">
|
||||
File fields and their paths/URLs
|
||||
</h2>
|
||||
</div>
|
||||
<CodeEditor
|
||||
className="w-full"
|
||||
language="json"
|
||||
value={JSON.stringify(files, null, 2)}
|
||||
readOnly
|
||||
minHeight="96px"
|
||||
maxHeight="200px"
|
||||
/>
|
||||
</div>
|
||||
) : null}
|
||||
<div className="flex gap-16">
|
||||
<div className="w-80">
|
||||
<h1 className="text-lg">Timeout</h1>
|
||||
<h2 className="text-base text-slate-400">In seconds</h2>
|
||||
</div>
|
||||
<Input value={timeout.toString()} readOnly />
|
||||
</div>
|
||||
<div className="flex gap-16">
|
||||
<div className="w-80">
|
||||
<h1 className="text-lg">Follow Redirects</h1>
|
||||
</div>
|
||||
<div className="flex w-full items-center gap-3">
|
||||
<Switch checked={followRedirects} disabled />
|
||||
<span className="text-sm text-slate-400">
|
||||
{followRedirects ? "Enabled" : "Disabled"}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
{downloadFilename ? (
|
||||
<div className="flex gap-16">
|
||||
<div className="w-80">
|
||||
<h1 className="text-lg">Download Filename</h1>
|
||||
</div>
|
||||
<Input value={downloadFilename} readOnly />
|
||||
</div>
|
||||
) : null}
|
||||
{saveResponseAsFile ? (
|
||||
<div className="flex gap-16">
|
||||
<div className="w-80">
|
||||
<h1 className="text-lg">Save Response as File</h1>
|
||||
</div>
|
||||
<div className="flex w-full items-center gap-3">
|
||||
<Switch checked={true} disabled />
|
||||
<span className="text-sm text-slate-400">Enabled</span>
|
||||
</div>
|
||||
</div>
|
||||
) : null}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export { HttpRequestBlockParameters };
|
||||
@@ -0,0 +1,59 @@
|
||||
import { AutoResizingTextarea } from "@/components/AutoResizingTextarea/AutoResizingTextarea";
|
||||
import { Input } from "@/components/ui/input";
|
||||
|
||||
type Props = {
|
||||
instructions: string | null;
|
||||
positiveDescriptor: string | null;
|
||||
negativeDescriptor: string | null;
|
||||
timeoutSeconds: number | null;
|
||||
};
|
||||
|
||||
function HumanInteractionBlockParameters({
|
||||
instructions,
|
||||
positiveDescriptor,
|
||||
negativeDescriptor,
|
||||
timeoutSeconds,
|
||||
}: Props) {
|
||||
return (
|
||||
<div className="space-y-4">
|
||||
{instructions ? (
|
||||
<div className="flex gap-16">
|
||||
<div className="w-80">
|
||||
<h1 className="text-lg">Instructions</h1>
|
||||
<h2 className="text-base text-slate-400">
|
||||
Instructions for the human interaction
|
||||
</h2>
|
||||
</div>
|
||||
<AutoResizingTextarea value={instructions} readOnly />
|
||||
</div>
|
||||
) : null}
|
||||
{positiveDescriptor ? (
|
||||
<div className="flex gap-16">
|
||||
<div className="w-80">
|
||||
<h1 className="text-lg">Positive Descriptor</h1>
|
||||
</div>
|
||||
<Input value={positiveDescriptor} readOnly />
|
||||
</div>
|
||||
) : null}
|
||||
{negativeDescriptor ? (
|
||||
<div className="flex gap-16">
|
||||
<div className="w-80">
|
||||
<h1 className="text-lg">Negative Descriptor</h1>
|
||||
</div>
|
||||
<Input value={negativeDescriptor} readOnly />
|
||||
</div>
|
||||
) : null}
|
||||
{typeof timeoutSeconds === "number" ? (
|
||||
<div className="flex gap-16">
|
||||
<div className="w-80">
|
||||
<h1 className="text-lg">Timeout</h1>
|
||||
<h2 className="text-base text-slate-400">In seconds</h2>
|
||||
</div>
|
||||
<Input value={timeoutSeconds.toString()} readOnly />
|
||||
</div>
|
||||
) : null}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export { HumanInteractionBlockParameters };
|
||||
@@ -0,0 +1,72 @@
|
||||
import { Input } from "@/components/ui/input";
|
||||
import { Switch } from "@/components/ui/switch";
|
||||
|
||||
type Props = {
|
||||
format: string;
|
||||
landscape: boolean;
|
||||
printBackground: boolean;
|
||||
includeTimestamp: boolean;
|
||||
customFilename: string | null;
|
||||
};
|
||||
|
||||
function PrintPageBlockParameters({
|
||||
format,
|
||||
landscape,
|
||||
printBackground,
|
||||
includeTimestamp,
|
||||
customFilename,
|
||||
}: Props) {
|
||||
return (
|
||||
<div className="space-y-4">
|
||||
<div className="flex gap-16">
|
||||
<div className="w-80">
|
||||
<h1 className="text-lg">Format</h1>
|
||||
</div>
|
||||
<Input value={format} readOnly />
|
||||
</div>
|
||||
<div className="flex gap-16">
|
||||
<div className="w-80">
|
||||
<h1 className="text-lg">Landscape</h1>
|
||||
</div>
|
||||
<div className="flex w-full items-center gap-3">
|
||||
<Switch checked={landscape} disabled />
|
||||
<span className="text-sm text-slate-400">
|
||||
{landscape ? "Enabled" : "Disabled"}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex gap-16">
|
||||
<div className="w-80">
|
||||
<h1 className="text-lg">Print Background</h1>
|
||||
</div>
|
||||
<div className="flex w-full items-center gap-3">
|
||||
<Switch checked={printBackground} disabled />
|
||||
<span className="text-sm text-slate-400">
|
||||
{printBackground ? "Enabled" : "Disabled"}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex gap-16">
|
||||
<div className="w-80">
|
||||
<h1 className="text-lg">Include Timestamp</h1>
|
||||
</div>
|
||||
<div className="flex w-full items-center gap-3">
|
||||
<Switch checked={includeTimestamp} disabled />
|
||||
<span className="text-sm text-slate-400">
|
||||
{includeTimestamp ? "Enabled" : "Disabled"}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
{customFilename ? (
|
||||
<div className="flex gap-16">
|
||||
<div className="w-80">
|
||||
<h1 className="text-lg">Custom Filename</h1>
|
||||
</div>
|
||||
<Input value={customFilename} readOnly />
|
||||
</div>
|
||||
) : null}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export { PrintPageBlockParameters };
|
||||
@@ -0,0 +1,82 @@
|
||||
import { AutoResizingTextarea } from "@/components/AutoResizingTextarea/AutoResizingTextarea";
|
||||
import { Input } from "@/components/ui/input";
|
||||
import { Switch } from "@/components/ui/switch";
|
||||
|
||||
type Props = {
|
||||
prompt: string;
|
||||
url: string | null;
|
||||
maxSteps: number | null;
|
||||
totpVerificationUrl: string | null;
|
||||
totpIdentifier: string | null;
|
||||
disableCache: boolean;
|
||||
};
|
||||
|
||||
function Taskv2BlockParameters({
|
||||
prompt,
|
||||
url,
|
||||
maxSteps,
|
||||
totpVerificationUrl,
|
||||
totpIdentifier,
|
||||
disableCache,
|
||||
}: Props) {
|
||||
return (
|
||||
<div className="space-y-4">
|
||||
<div className="flex gap-16">
|
||||
<div className="w-80">
|
||||
<h1 className="text-lg">Prompt</h1>
|
||||
<h2 className="text-base text-slate-400">
|
||||
The instructions for this task
|
||||
</h2>
|
||||
</div>
|
||||
<AutoResizingTextarea value={prompt} readOnly />
|
||||
</div>
|
||||
{url ? (
|
||||
<div className="flex gap-16">
|
||||
<div className="w-80">
|
||||
<h1 className="text-lg">URL</h1>
|
||||
</div>
|
||||
<Input value={url} readOnly />
|
||||
</div>
|
||||
) : null}
|
||||
{typeof maxSteps === "number" ? (
|
||||
<div className="flex gap-16">
|
||||
<div className="w-80">
|
||||
<h1 className="text-lg">Max Steps</h1>
|
||||
</div>
|
||||
<Input value={maxSteps.toString()} readOnly />
|
||||
</div>
|
||||
) : null}
|
||||
{totpVerificationUrl ? (
|
||||
<div className="flex gap-16">
|
||||
<div className="w-80">
|
||||
<h1 className="text-lg">TOTP Verification URL</h1>
|
||||
</div>
|
||||
<Input value={totpVerificationUrl} readOnly />
|
||||
</div>
|
||||
) : null}
|
||||
{totpIdentifier ? (
|
||||
<div className="flex gap-16">
|
||||
<div className="w-80">
|
||||
<h1 className="text-lg">TOTP Identifier</h1>
|
||||
</div>
|
||||
<Input value={totpIdentifier} readOnly />
|
||||
</div>
|
||||
) : null}
|
||||
{disableCache ? (
|
||||
<div className="flex gap-16">
|
||||
<div className="w-80">
|
||||
<h1 className="text-lg">Cache Disabled</h1>
|
||||
</div>
|
||||
<div className="flex w-full items-center gap-3">
|
||||
<Switch checked={true} disabled />
|
||||
<span className="text-sm text-slate-400">
|
||||
Cache is disabled for this block
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
) : null}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export { Taskv2BlockParameters };
|
||||
@@ -0,0 +1,26 @@
|
||||
import { Input } from "@/components/ui/input";
|
||||
|
||||
type Props = {
|
||||
waitSec: number | null | undefined;
|
||||
};
|
||||
|
||||
function WaitBlockParameters({ waitSec }: Props) {
|
||||
return (
|
||||
<div className="space-y-4">
|
||||
<div className="flex gap-16">
|
||||
<div className="w-80">
|
||||
<h1 className="text-lg">Wait Duration</h1>
|
||||
<h2 className="text-base text-slate-400">
|
||||
Seconds to wait before proceeding
|
||||
</h2>
|
||||
</div>
|
||||
<Input
|
||||
value={typeof waitSec === "number" ? `${waitSec}s` : "N/A"}
|
||||
readOnly
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export { WaitBlockParameters };
|
||||
Reference in New Issue
Block a user