From 487745a667bb5c051b356b617c4bf747860334df Mon Sep 17 00:00:00 2001 From: Taylor Ho Date: Wed, 12 Aug 2026 02:27:55 -0700 Subject: [PATCH] Refine workflow inspector hierarchy Signed-off-by: Taylor Ho --- .../workflows/ui/WorkflowFormBuilder.tsx | 137 ++++++++++---- .../workflows/ui/WorkflowStepCard.tsx | 174 ++++++++++-------- desktop/tests/e2e/workflows.spec.ts | 50 +++-- 3 files changed, 229 insertions(+), 132 deletions(-) diff --git a/desktop/src/features/workflows/ui/WorkflowFormBuilder.tsx b/desktop/src/features/workflows/ui/WorkflowFormBuilder.tsx index c6f5c0de5..7db923907 100644 --- a/desktop/src/features/workflows/ui/WorkflowFormBuilder.tsx +++ b/desktop/src/features/workflows/ui/WorkflowFormBuilder.tsx @@ -1,4 +1,4 @@ -import { Plus, Trash2, X, Zap } from "lucide-react"; +import { Check, ChevronDown, Plus, Trash2, X, Zap } from "lucide-react"; import { AnimatePresence, motion, useReducedMotion } from "motion/react"; import * as React from "react"; import { createPortal } from "react-dom"; @@ -9,15 +9,13 @@ import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, - DropdownMenuLabel, - DropdownMenuSeparator, DropdownMenuTrigger, } from "@/shared/ui/dropdown-menu"; import { Input } from "@/shared/ui/input"; import { Switch } from "@/shared/ui/switch"; import { Textarea } from "@/shared/ui/textarea"; import { WorkflowStepCard } from "./WorkflowStepCard"; -import { FieldLabel, FormSelect } from "./workflowFormPrimitives"; +import { FieldLabel } from "./workflowFormPrimitives"; import { DEFAULT_FORM_STATE, ACTION_LABELS, @@ -32,7 +30,6 @@ import type { ActionType, StepFormState, TriggerConfig, - TriggerType, WorkflowFormState, } from "./workflowFormTypes"; @@ -166,6 +163,52 @@ const inspectorContentVariants = { }), }; +function InspectorTypeMenu({ + ariaLabel, + disabled, + labels, + onChange, + options, + value, +}: { + ariaLabel: string; + disabled?: boolean; + labels: Record; + onChange: (value: T) => void; + options: readonly T[]; + value: T; +}) { + return ( + + + + + + {options.map((option) => ( + onChange(option)}> + + {labels[option]} + + ))} + + + ); +} + function WorkflowNode({ description, disabled, @@ -177,6 +220,7 @@ function WorkflowNode({ onRemove, selected, showTitle = true, + subtitle, title, }: { description: string; @@ -189,6 +233,7 @@ function WorkflowNode({ onRemove?: () => void; selected: boolean; showTitle?: boolean; + subtitle?: string; title: string; }) { const isNumbered = number !== undefined; @@ -223,10 +268,15 @@ function WorkflowNode({ {showTitle ? ( - + {title} ) : null} + {subtitle ? ( + + {subtitle} + + ) : null} {description} @@ -265,8 +315,6 @@ function WorkflowNode({ - Add action - {ACTION_TYPES.map((action) => ( {formState.steps.map((step, index) => { - const nodeTitle = - step.name?.trim() || ACTION_LABELS[step.action]; + const stepName = step.name?.trim(); + const actionLabel = ACTION_LABELS[step.action]; + const nodeTitle = stepName || actionLabel; return ( ); @@ -531,14 +581,36 @@ export function WorkflowFormBuilder({ ? "Trigger" : `Step ${selectedNode.index + 1}`}

-

- {selectedNode.type === "trigger" - ? TRIGGER_LABELS[formState.trigger.on] - : selectedStep?.name?.trim() || - (selectedStep - ? ACTION_LABELS[selectedStep.action] - : "Step")} -

+ {selectedNode.type === "trigger" ? ( + + updateFormState({ + ...formState, + trigger: { on: triggerType }, + }) + } + options={TRIGGER_TYPES} + value={formState.trigger.on} + /> + ) : selectedStep ? ( + { + const next = { ...selectedStep, action }; + if (action === "call_webhook" && !next.method) { + next.method = "POST"; + } + updateStep(selectedNode.index, next); + }} + options={ACTION_TYPES} + value={selectedStep.action} + /> + ) : null}
{selectedNode.type === "step" && selectedStep ? ( @@ -592,27 +664,14 @@ export function WorkflowFormBuilder({ > {selectedNode.type === "trigger" ? (
-
- - Event - - - updateFormState({ - ...formState, - trigger: { on: value as TriggerType }, - }) - } - value={formState.trigger.on} - > - {TRIGGER_TYPES.map((type) => ( - - ))} - +
+

+ Trigger settings +

+

+ Configure when this event should start the + workflow. +

diff --git a/desktop/src/features/workflows/ui/WorkflowStepCard.tsx b/desktop/src/features/workflows/ui/WorkflowStepCard.tsx index 5aeaa64cb..bd32555b9 100644 --- a/desktop/src/features/workflows/ui/WorkflowStepCard.tsx +++ b/desktop/src/features/workflows/ui/WorkflowStepCard.tsx @@ -5,13 +5,8 @@ import { Button } from "@/shared/ui/button"; import { Input } from "@/shared/ui/input"; import { Textarea } from "@/shared/ui/textarea"; import { FieldLabel, FormSelect } from "./workflowFormPrimitives"; -import { ACTION_LABELS, ACTION_TYPES } from "./workflowFormTypes"; import { WorkflowWebhookHeadersEditor } from "./WorkflowWebhookHeadersEditor"; -import type { - ActionType, - StepFormState, - TriggerType, -} from "./workflowFormTypes"; +import type { StepFormState, TriggerType } from "./workflowFormTypes"; function BackendSupportHint({ action }: { action: StepFormState["action"] }) { switch (action) { @@ -150,9 +145,9 @@ function StepConfigFields({ ); case "call_webhook": return ( -
+
- URL + Endpoint URL
- - Method (optional) - + HTTP method
- Body (optional) + + Request body (optional) +