diff --git a/src/app/api/workflow/route.ts b/src/app/api/workflow/route.ts index ce2e83c8..08d994e8 100644 --- a/src/app/api/workflow/route.ts +++ b/src/app/api/workflow/route.ts @@ -141,12 +141,14 @@ export async function POST(request: NextRequest) { } } -// GET: Validate directory path +// GET: Validate directory path, or load workflow from directory export async function GET(request: NextRequest) { const directoryPath = request.nextUrl.searchParams.get("path"); + const shouldLoad = request.nextUrl.searchParams.get("load") === "true"; - logger.info('file.load', 'Directory validation request received', { + logger.info('file.load', 'Directory request received', { directoryPath, + shouldLoad, }); if (!directoryPath) { @@ -173,6 +175,54 @@ export async function GET(request: NextRequest) { try { const stats = await fs.stat(directoryPath); const isDirectory = stats.isDirectory(); + + if (!isDirectory) { + return NextResponse.json({ + success: true, + exists: true, + isDirectory: false, + }); + } + + // If load=true, find and return a workflow JSON from the directory + if (shouldLoad) { + const entries = await fs.readdir(directoryPath); + const jsonFiles = entries.filter(f => f.endsWith(".json")); + + for (const jsonFile of jsonFiles) { + try { + const filePath = path.join(directoryPath, jsonFile); + const content = await fs.readFile(filePath, "utf-8"); + const parsed = JSON.parse(content); + + if (parsed.version && parsed.nodes && parsed.edges) { + const filename = path.basename(jsonFile, ".json"); + logger.info('file.load', 'Workflow loaded from directory', { + directoryPath, + filename: jsonFile, + }); + return NextResponse.json({ + success: true, + workflow: parsed, + filename, + }); + } + } catch { + // Skip files that can't be read or parsed + continue; + } + } + + logger.warn('file.load', 'No valid workflow file found in directory', { + directoryPath, + jsonFilesChecked: jsonFiles.length, + }); + return NextResponse.json( + { success: false, error: "No workflow file found in directory" }, + { status: 404 } + ); + } + logger.info('file.load', 'Directory validation successful', { directoryPath, exists: true, diff --git a/src/components/Header.tsx b/src/components/Header.tsx index baf1ebda..9e049aa1 100644 --- a/src/components/Header.tsx +++ b/src/components/Header.tsx @@ -1,6 +1,6 @@ "use client"; -import { useState, useRef, useMemo, useCallback } from "react"; +import { useState, useMemo, useCallback } from "react"; import { useWorkflowStore, WorkflowFile } from "@/store/workflowStore"; import { useShallow } from "zustand/shallow"; import { ProjectSetupModal } from "./ProjectSetupModal"; @@ -93,7 +93,6 @@ export function Header() { const [showProjectModal, setShowProjectModal] = useState(false); const [projectModalMode, setProjectModalMode] = useState<"new" | "settings">("new"); - const fileInputRef = useRef(null); const isProjectConfigured = !!workflowName; const canSave = !!(workflowId && workflowName && saveDirectoryPath); @@ -115,31 +114,36 @@ export function Header() { setShowProjectModal(true); }; - const handleOpenFile = () => { - fileInputRef.current?.click(); - }; + const handleOpenFile = async () => { + try { + // Open native OS directory picker + const browseRes = await fetch("/api/browse-directory"); + const browseResult = await browseRes.json(); - const handleFileChange = (e: React.ChangeEvent) => { - const file = e.target.files?.[0]; - if (!file) return; - - const reader = new FileReader(); - reader.onload = async (event) => { - try { - const workflow = JSON.parse(event.target?.result as string) as WorkflowFile; - if (workflow.version && workflow.nodes && workflow.edges) { - await loadWorkflow(workflow); - } else { - alert("Invalid workflow file format"); + if (!browseResult.success || browseResult.cancelled || !browseResult.path) { + if (!browseResult.success && !browseResult.cancelled) { + alert(browseResult.error || "Failed to open directory picker"); } - } catch { - alert("Failed to parse workflow file"); + return; } - }; - reader.readAsText(file); - // Reset input so same file can be loaded again - e.target.value = ""; + const dirPath = browseResult.path; + + // Load workflow JSON from that directory + const loadRes = await fetch(`/api/workflow?path=${encodeURIComponent(dirPath)}&load=true`); + const loadResult = await loadRes.json(); + + if (!loadResult.success) { + alert(loadResult.error || "No workflow file found in directory"); + return; + } + + const workflow = loadResult.workflow as WorkflowFile; + await loadWorkflow(workflow, dirPath); + } catch (error) { + console.error("Failed to open workflow:", error); + alert("Failed to open workflow. Please try again."); + } }; const handleProjectSave = async (id: string, name: string, path: string) => { @@ -226,13 +230,6 @@ export function Header() { onSave={handleProjectSave} mode={projectModalMode} /> -