From cfc261d64608142b236293a0e9d3ffc36836b002 Mon Sep 17 00:00:00 2001 From: Siddharth Ganesan Date: Wed, 9 Jul 2025 11:37:08 -0700 Subject: [PATCH] Move upload button --- .../import-controls/import-controls.tsx | 340 ------------------ .../components/control-bar/control-bar.tsx | 4 +- .../components/create-menu/create-menu.tsx | 76 +++- .../create-menu/import-controls.tsx | 285 +++++++++++++++ 4 files changed, 360 insertions(+), 345 deletions(-) delete mode 100644 apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/control-bar/components/import-controls/import-controls.tsx create mode 100644 apps/sim/app/workspace/[workspaceId]/w/components/sidebar/components/create-menu/import-controls.tsx diff --git a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/control-bar/components/import-controls/import-controls.tsx b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/control-bar/components/import-controls/import-controls.tsx deleted file mode 100644 index bcef770a41..0000000000 --- a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/control-bar/components/import-controls/import-controls.tsx +++ /dev/null @@ -1,340 +0,0 @@ -'use client' - -import { useRef, useState } from 'react' -import { AlertCircle, CheckCircle, FileText, Plus, Upload } from 'lucide-react' -import { useParams, useRouter } from 'next/navigation' -import { Alert, AlertDescription } from '@/components/ui/alert' -import { Button } from '@/components/ui/button' -import { - Dialog, - DialogContent, - DialogDescription, - DialogFooter, - DialogHeader, - DialogTitle, -} from '@/components/ui/dialog' -import { - DropdownMenu, - DropdownMenuContent, - DropdownMenuItem, - DropdownMenuTrigger, -} from '@/components/ui/dropdown-menu' -import { Textarea } from '@/components/ui/textarea' -import { Tooltip, TooltipContent, TooltipTrigger } from '@/components/ui/tooltip' -import { createLogger } from '@/lib/logs/console-logger' -import { useCollaborativeWorkflow } from '@/hooks/use-collaborative-workflow' -import { useWorkflowRegistry } from '@/stores/workflows/registry/store' -import { useSubBlockStore } from '@/stores/workflows/subblock/store' -import { importWorkflowFromYaml, parseWorkflowYaml } from '@/stores/workflows/yaml/importer' - -const logger = createLogger('ImportControls') - -interface ImportControlsProps { - disabled?: boolean -} - -export function ImportControls({ disabled = false }: ImportControlsProps) { - const [isImporting, setIsImporting] = useState(false) - const [showYamlDialog, setShowYamlDialog] = useState(false) - const [yamlContent, setYamlContent] = useState('') - const [importResult, setImportResult] = useState<{ - success: boolean - errors: string[] - warnings: string[] - summary?: string - } | null>(null) - - const fileInputRef = useRef(null) - const router = useRouter() - const params = useParams() - const workspaceId = params.workspaceId as string - - // Stores and hooks - const { createWorkflow } = useWorkflowRegistry() - const { collaborativeAddBlock, collaborativeAddEdge, collaborativeSetSubblockValue } = - useCollaborativeWorkflow() - const subBlockStore = useSubBlockStore() - - const handleFileUpload = async (event: React.ChangeEvent) => { - const file = event.target.files?.[0] - if (!file) return - - try { - const content = await file.text() - setYamlContent(content) - setShowYamlDialog(true) - } catch (error) { - logger.error('Failed to read file:', error) - setImportResult({ - success: false, - errors: [ - `Failed to read file: ${error instanceof Error ? error.message : 'Unknown error'}`, - ], - warnings: [], - }) - } - - // Reset file input - if (fileInputRef.current) { - fileInputRef.current.value = '' - } - } - - const handleYamlImport = async () => { - if (!yamlContent.trim()) { - setImportResult({ - success: false, - errors: ['YAML content is required'], - warnings: [], - }) - return - } - - setIsImporting(true) - setImportResult(null) - - try { - // First validate the YAML without importing - const { data: yamlWorkflow, errors: parseErrors } = parseWorkflowYaml(yamlContent) - - if (!yamlWorkflow || parseErrors.length > 0) { - setImportResult({ - success: false, - errors: parseErrors, - warnings: [], - }) - return - } - - // Create a new workflow - - const newWorkflowId = await createWorkflow({ - name: `Imported Workflow - ${new Date().toLocaleString()}`, - description: 'Workflow imported from YAML', - workspaceId, - }) - - // Import the YAML into the new workflow BEFORE navigation (creates complete state and saves directly to DB) - // This avoids timing issues with workflow reload during navigation - const result = await importWorkflowFromYaml( - yamlContent, - { - addBlock: collaborativeAddBlock, - addEdge: collaborativeAddEdge, - applyAutoLayout: () => { - // Trigger auto layout - window.dispatchEvent(new CustomEvent('trigger-auto-layout')) - }, - setSubBlockValue: (blockId: string, subBlockId: string, value: any) => { - // Use the collaborative function - the same one called when users type into fields - collaborativeSetSubblockValue(blockId, subBlockId, value) - }, - getExistingBlocks: () => { - // For a new workflow, we'll get the starter block from the server - return {} - }, - }, - newWorkflowId - ) // Pass the new workflow ID to import into - - // Navigate to the new workflow AFTER import is complete - if (result.success) { - logger.info('Navigating to imported workflow') - router.push(`/workspace/${workspaceId}/w/${newWorkflowId}`) - } - - setImportResult(result) - - if (result.success) { - setYamlContent('') - setShowYamlDialog(false) - logger.info('YAML import completed successfully') - } - } catch (error) { - logger.error('Failed to import YAML workflow:', error) - setImportResult({ - success: false, - errors: [`Import failed: ${error instanceof Error ? error.message : 'Unknown error'}`], - warnings: [], - }) - } finally { - setIsImporting(false) - } - } - - const handleOpenYamlDialog = () => { - setYamlContent('') - setImportResult(null) - setShowYamlDialog(true) - } - - const isDisabled = disabled || isImporting - - return ( - <> - - - - - {isDisabled ? ( -
- -
- ) : ( - - )} -
- - fileInputRef.current?.click()} - disabled={isDisabled} - className='flex cursor-pointer items-center gap-2' - > - -
- Upload YAML File - - Import from .yaml or .yml file - -
-
- - - -
- Paste YAML - Import from YAML text -
-
-
-
-
- - {isDisabled - ? isImporting - ? 'Importing workflow...' - : 'Cannot import workflow' - : 'Import Workflow from YAML'} - -
- - {/* Hidden file input */} - - - {/* YAML Import Dialog */} - - - - Import Workflow from YAML - - Paste your workflow YAML content below. This will create a new workflow with the - blocks and connections defined in the YAML. - - - -
-