diff --git a/desktop/src/features/workflows/ui/WorkflowActionsMenu.tsx b/desktop/src/features/workflows/ui/WorkflowActionsMenu.tsx
new file mode 100644
index 000000000..92cf3de28
--- /dev/null
+++ b/desktop/src/features/workflows/ui/WorkflowActionsMenu.tsx
@@ -0,0 +1,97 @@
+import {
+ Copy,
+ MoreHorizontal,
+ Pencil,
+ Play,
+ Power,
+ PowerOff,
+ Trash2,
+} from "lucide-react";
+
+import { Button } from "@/shared/ui/button";
+import {
+ DropdownMenu,
+ DropdownMenuCheckboxItem,
+ DropdownMenuContent,
+ DropdownMenuItem,
+ DropdownMenuSeparator,
+ DropdownMenuTrigger,
+} from "@/shared/ui/dropdown-menu";
+import { Switch } from "@/shared/ui/switch";
+
+type WorkflowActionsMenuProps = {
+ isEnabled: boolean;
+ isTogglingEnabled?: boolean;
+ onDelete: () => void;
+ onDuplicate: () => void;
+ onEdit: () => void;
+ onToggleEnabled: () => void;
+ onTrigger: () => void;
+};
+
+export function WorkflowActionsMenu({
+ isEnabled,
+ isTogglingEnabled = false,
+ onDelete,
+ onDuplicate,
+ onEdit,
+ onToggleEnabled,
+ onTrigger,
+}: WorkflowActionsMenuProps) {
+ return (
+
+
+
+
+
+
+
+ Trigger
+
+
+
+ Edit
+
+
+
+ Duplicate
+
+ {
+ if (checked !== isEnabled) onToggleEnabled();
+ }}
+ onSelect={(event) => event.preventDefault()}
+ >
+ {isEnabled ? (
+
+ ) : (
+
+ )}
+ Enable
+
+
+
+
+
+ Delete
+
+
+
+ );
+}
diff --git a/desktop/src/features/workflows/ui/WorkflowCard.tsx b/desktop/src/features/workflows/ui/WorkflowCard.tsx
index ce90c7229..ecc9350ce 100644
--- a/desktop/src/features/workflows/ui/WorkflowCard.tsx
+++ b/desktop/src/features/workflows/ui/WorkflowCard.tsx
@@ -2,20 +2,13 @@ import {
ArrowRight,
CalendarClock,
CircleCheckBig,
- Copy,
GitPullRequest,
Hash,
MessageCircle,
MessageSquare,
- MoreHorizontal,
- Pencil,
- Play,
- Power,
- PowerOff,
Send,
SmilePlus,
Timer,
- Trash2,
Webhook,
Zap,
} from "lucide-react";
@@ -27,16 +20,7 @@ import type { Workflow } from "@/shared/api/types";
import { cn } from "@/shared/lib/cn";
import { emojiDisplayName } from "@/shared/lib/emojiName";
import { rewriteRelayUrl } from "@/shared/lib/mediaUrl";
-import { Button } from "@/shared/ui/button";
-import {
- DropdownMenu,
- DropdownMenuCheckboxItem,
- DropdownMenuContent,
- DropdownMenuItem,
- DropdownMenuSeparator,
- DropdownMenuTrigger,
-} from "@/shared/ui/dropdown-menu";
-import { Switch } from "@/shared/ui/switch";
+import { WorkflowActionsMenu } from "./WorkflowActionsMenu";
import {
getWorkflowCardLabel,
getWorkflowDisplayStatus,
@@ -355,62 +339,15 @@ export function WorkflowCard({
-
-
-
-
-
- onTrigger(workflow.id)}>
-
- Trigger
-
- onEdit(workflow)}>
-
- Edit
-
- onDuplicate(workflow)}>
-
- Duplicate
-
- {
- if (checked !== isEnabled) onToggleEnabled(workflow);
- }}
- onSelect={(event) => event.preventDefault()}
- >
- {isEnabled ? (
-
- ) : (
-
- )}
- Enable
-
-
-
- onDelete(workflow)}
- >
-
- Delete
-
-
-
+
onDelete(workflow)}
+ onDuplicate={() => onDuplicate(workflow)}
+ onEdit={() => onEdit(workflow)}
+ onToggleEnabled={() => onToggleEnabled(workflow)}
+ onTrigger={() => onTrigger(workflow.id)}
+ />
diff --git a/desktop/src/features/workflows/ui/WorkflowDialog.tsx b/desktop/src/features/workflows/ui/WorkflowDialog.tsx
index 99bf2a0b3..c22527ec9 100644
--- a/desktop/src/features/workflows/ui/WorkflowDialog.tsx
+++ b/desktop/src/features/workflows/ui/WorkflowDialog.tsx
@@ -32,12 +32,14 @@ import {
} from "@/shared/ui/dialog";
import { Input } from "@/shared/ui/input";
import { ChannelCombobox } from "./ChannelCombobox";
+import { WorkflowActionsMenu } from "./WorkflowActionsMenu";
import {
WorkflowFormBuilder,
type WorkflowEditorMode,
type WorkflowFormBuilderHandle,
} from "./WorkflowFormBuilder";
import { WorkflowWebhookSecretDialog } from "./WorkflowWebhookSecretDialog";
+import { getWorkflowEnabled } from "./workflowDefinition";
import type { WorkflowEditorPane } from "./workflowEditorPane";
import {
DEFAULT_FORM_STATE,
@@ -50,8 +52,12 @@ type DialogMode = "create" | "edit" | "duplicate";
type WorkflowDialogProps = {
channels: Channel[];
mode: DialogMode;
+ onDeleteWorkflow: (workflow: Workflow) => void;
+ onDuplicateWorkflow: (workflowId: string) => void;
+ onEditWorkflow: (workflowId: string) => void;
onEditorPaneChange: (pane: WorkflowEditorPane) => void;
onOpenChange: (open: boolean) => void;
+ onTriggerWorkflow: (workflowId: string) => void;
open: boolean;
pane: WorkflowEditorPane;
workflow?: Workflow | null;
@@ -112,6 +118,24 @@ function yamlWithWorkflowName(yaml: string, name: string): string | null {
return document.toString();
}
+function yamlWithWorkflowEnabled(
+ yaml: string,
+ enabled: boolean,
+): string | null {
+ if (!yaml.trim()) {
+ return formStateToYaml({ ...DEFAULT_FORM_STATE, enabled });
+ }
+
+ const document = parseDocument(yaml);
+ if (document.errors.length > 0 || !isMap(document.contents)) return null;
+ if (enabled) {
+ document.delete("enabled");
+ } else {
+ document.set("enabled", false);
+ }
+ return document.toString();
+}
+
function WorkflowNameEditor({
disabled,
generating,
@@ -214,8 +238,12 @@ function WorkflowNameEditor({
export function WorkflowDialog({
channels,
mode,
+ onDeleteWorkflow,
+ onDuplicateWorkflow,
+ onEditWorkflow,
onEditorPaneChange,
onOpenChange,
+ onTriggerWorkflow,
open,
pane,
workflow,
@@ -419,6 +447,11 @@ export function WorkflowDialog({
const workflowName = visibleWorkflowName(yamlDefinition, workflow?.name);
const canEditWorkflowName =
!yamlDefinition.trim() || yamlToFormState(yamlDefinition).ok;
+ const workflowEnabled = parsedDefinition?.ok
+ ? parsedDefinition.state.enabled
+ : workflow
+ ? getWorkflowEnabled(workflow.definition)
+ : true;
const handleWorkflowNameCommit = React.useCallback(
(name: string) => {
const nextYaml = yamlWithWorkflowName(yamlDefinitionRef.current, name);
@@ -430,6 +463,16 @@ export function WorkflowDialog({
},
[mutation.reset],
);
+ const handleToggleWorkflowEnabled = React.useCallback(() => {
+ const nextYaml = yamlWithWorkflowEnabled(
+ yamlDefinitionRef.current,
+ !workflowEnabled,
+ );
+ if (nextYaml === null) return;
+ mutation.reset();
+ yamlDefinitionRef.current = nextYaml;
+ setYamlDefinition(nextYaml);
+ }, [mutation.reset, workflowEnabled]);
const showChannelSelector = mode !== "edit";
@@ -465,7 +508,9 @@ export function WorkflowDialog({
/>
+ {mode === "edit" && workflow ? (
+ onDeleteWorkflow(workflow)}
+ onDuplicate={() => onDuplicateWorkflow(workflow.id)}
+ onEdit={() => onEditWorkflow(workflow.id)}
+ onToggleEnabled={handleToggleWorkflowEnabled}
+ onTrigger={() => onTriggerWorkflow(workflow.id)}
+ />
+ ) : null}