Move download workflow JSON cta outside menu

This commit is contained in:
akhisud3195 2025-07-11 19:32:17 +05:30
parent 61b811bd35
commit 45c9379451

View file

@ -23,7 +23,7 @@ import { Copilot } from "../copilot/app";
import { publishWorkflow, renameWorkflow, saveWorkflow } from "../../../actions/workflow_actions"; import { publishWorkflow, renameWorkflow, saveWorkflow } from "../../../actions/workflow_actions";
import { PublishedBadge } from "./published_badge"; import { PublishedBadge } from "./published_badge";
import { BackIcon, HamburgerIcon, WorkflowIcon } from "../../../lib/components/icons"; 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 { EntityList } from "./entity_list";
import { ProductTour } from "@/components/common/product-tour"; import { ProductTour } from "@/components/common/product-tour";
import { ModelsResponse } from "@/app/lib/types/billing_types"; 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 }); 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 { _id, projectId, ...workflow } = state.present.workflow;
const json = JSON.stringify(workflow, null, 2); const json = JSON.stringify(workflow, null, 2);
navigator.clipboard.writeText(json); const blob = new Blob([json], { type: 'application/json' });
setShowCopySuccess(true); const url = window.URL.createObjectURL(blob);
setTimeout(() => { const a = document.createElement('a');
setShowCopySuccess(false); a.href = url;
}, 1500); 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<Action>) => { const processQueue = useCallback(async (state: State, dispatch: React.Dispatch<Action>) => {
@ -840,7 +845,17 @@ export function WorkflowEditor({
<PenLine size={16} /> <PenLine size={16} />
Draft Draft
</div>} </div>}
</div> {/* Download JSON icon button, with tooltip, to the left of the menu */}
<Tooltip content="Download Assistant JSON">
<button
onClick={handleDownloadJSON}
className="p-1.5 text-indigo-600 hover:text-indigo-700 dark:text-indigo-400 dark:hover:text-indigo-300 transition-colors"
aria-label="Download JSON"
type="button"
>
<DownloadIcon size={20} />
</button>
</Tooltip>
<Dropdown> <Dropdown>
<DropdownTrigger> <DropdownTrigger>
<div> <div>
@ -863,9 +878,6 @@ export function WorkflowEditor({
if (key === 'clone') { if (key === 'clone') {
handleCloneVersion(state.present.workflow._id); handleCloneVersion(state.present.workflow._id);
} }
if (key === 'clipboard') {
handleCopyJSON();
}
}} }}
> >
<DropdownItem <DropdownItem
@ -883,17 +895,10 @@ export function WorkflowEditor({
> >
Clone this version Clone this version
</DropdownItem> </DropdownItem>
<DropdownItem
key="clipboard"
startContent={<div className="text-gray-500"><CopyIcon size={16} /></div>}
className="gap-x-2"
>
Export as JSON
</DropdownItem>
</DropdownMenu> </DropdownMenu>
</Dropdown> </Dropdown>
</div> </div>
</div>
{showCopySuccess && <div className="flex items-center gap-2"> {showCopySuccess && <div className="flex items-center gap-2">
<div className="text-green-500">Copied to clipboard</div> <div className="text-green-500">Copied to clipboard</div>
</div>} </div>}
@ -922,18 +927,6 @@ export function WorkflowEditor({
{showCopilot ? "Hide Copilot" : "Copilot"} {showCopilot ? "Hide Copilot" : "Copilot"}
</Button> </Button>
</div>} </div>}
{!isLive && <div className="text-xs text-gray-400">
{state.present.saving && <div className="flex items-center gap-1">
<Spinner size="sm" />
<div>Saving...</div>
</div>}
{!state.present.saving && !state.present.pendingChanges && state.present.workflow && <div>
Updated <RelativeTime date={new Date(state.present.lastUpdatedAt)} />
</div>}
{!state.present.saving && state.present.pendingChanges && state.present.workflow && <div>
Unsaved changes
</div>}
</div>}
{!isLive && <> {!isLive && <>
<button <button
className="p-1 text-gray-400 hover:text-black hover:cursor-pointer" className="p-1 text-gray-400 hover:text-black hover:cursor-pointer"