diff --git a/apps/rowboat/app/projects/[projectId]/workflow/workflow_editor.tsx b/apps/rowboat/app/projects/[projectId]/workflow/workflow_editor.tsx index 6b90242e..30598d1c 100644 --- a/apps/rowboat/app/projects/[projectId]/workflow/workflow_editor.tsx +++ b/apps/rowboat/app/projects/[projectId]/workflow/workflow_editor.tsx @@ -23,7 +23,7 @@ import { Copilot } from "../copilot/app"; import { publishWorkflow, renameWorkflow, saveWorkflow } from "../../../actions/workflow_actions"; import { PublishedBadge } from "./published_badge"; import { BackIcon, HamburgerIcon, WorkflowIcon } from "../../../lib/components/icons"; -import { CopyIcon, ImportIcon, Layers2Icon, RadioIcon, RedoIcon, ServerIcon, Sparkles, UndoIcon, RocketIcon, PenLine, AlertTriangle } from "lucide-react"; +import { CopyIcon, ImportIcon, Layers2Icon, RadioIcon, RedoIcon, ServerIcon, Sparkles, UndoIcon, RocketIcon, PenLine, AlertTriangle, DownloadIcon } from "lucide-react"; import { EntityList } from "./entity_list"; import { ProductTour } from "@/components/common/product-tour"; import { ModelsResponse } from "@/app/lib/types/billing_types"; @@ -765,14 +765,19 @@ export function WorkflowEditor({ dispatch({ type: "set_published_workflow_id", workflowId: state.present.workflow._id }); } - function handleCopyJSON() { + // Remove handleCopyJSON and add handleDownloadJSON + function handleDownloadJSON() { const { _id, projectId, ...workflow } = state.present.workflow; const json = JSON.stringify(workflow, null, 2); - navigator.clipboard.writeText(json); - setShowCopySuccess(true); - setTimeout(() => { - setShowCopySuccess(false); - }, 1500); + const blob = new Blob([json], { type: 'application/json' }); + const url = window.URL.createObjectURL(blob); + const a = document.createElement('a'); + a.href = url; + a.download = `${state.present.workflow.name || 'workflow'}.json`; + document.body.appendChild(a); + a.click(); + window.URL.revokeObjectURL(url); + document.body.removeChild(a); } const processQueue = useCallback(async (state: State, dispatch: React.Dispatch) => { @@ -840,59 +845,59 @@ export function WorkflowEditor({ Draft } + {/* Download JSON icon button, with tooltip, to the left of the menu */} + + + + + +
+ + + +
+
+ { + if (key === 'switch') { + handleShowSelector(); + } + if (key === 'clone') { + handleCloneVersion(state.present.workflow._id); + } + }} + > + } + className="gap-x-2" + > + View versions + + + } + className="gap-x-2" + > + Clone this version + + +
- - -
- - - -
-
- { - if (key === 'switch') { - handleShowSelector(); - } - if (key === 'clone') { - handleCloneVersion(state.present.workflow._id); - } - if (key === 'clipboard') { - handleCopyJSON(); - } - }} - > - } - className="gap-x-2" - > - View versions - - - } - className="gap-x-2" - > - Clone this version - - - } - className="gap-x-2" - > - Export as JSON - - -
{showCopySuccess &&
Copied to clipboard
@@ -922,18 +927,6 @@ export function WorkflowEditor({ {showCopilot ? "Hide Copilot" : "Copilot"}
} - {!isLive &&
- {state.present.saving &&
- -
Saving...
-
} - {!state.present.saving && !state.present.pendingChanges && state.present.workflow &&
- Updated -
} - {!state.present.saving && state.present.pendingChanges && state.present.workflow &&
- Unsaved changes -
} -
} {!isLive && <>