feat: [US-035] - Export project as .vnflow file
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
parent
59cda43987
commit
78479f3234
2
prd.json
2
prd.json
|
|
@ -620,7 +620,7 @@
|
|||
"Verify in browser using dev-browser skill"
|
||||
],
|
||||
"priority": 35,
|
||||
"passes": false,
|
||||
"passes": true,
|
||||
"notes": ""
|
||||
},
|
||||
{
|
||||
|
|
|
|||
14
progress.txt
14
progress.txt
|
|
@ -506,3 +506,17 @@
|
|||
- Toast state uses object with message and type for flexibility
|
||||
- Loading spinner SVG with animate-spin class for visual feedback during save
|
||||
---
|
||||
|
||||
## 2026-01-22 - US-035
|
||||
- What was implemented: Export project as .vnflow file functionality
|
||||
- Files changed:
|
||||
- src/app/editor/[projectId]/FlowchartEditor.tsx - implemented handleExport with blob creation and download trigger, added projectName prop
|
||||
- src/app/editor/[projectId]/page.tsx - passed projectName prop to FlowchartEditor
|
||||
- **Learnings for future iterations:**
|
||||
- Use Blob with type 'application/json' for JSON file downloads
|
||||
- JSON.stringify(data, null, 2) creates pretty-printed JSON with 2-space indentation
|
||||
- URL.createObjectURL creates a temporary URL for the blob
|
||||
- Create temporary anchor element with download attribute to trigger file download
|
||||
- Remember to cleanup: remove the anchor from DOM and revoke the object URL
|
||||
- Props needed for export: pass data down from server components (e.g., projectName) to client components that need them
|
||||
---
|
||||
|
|
|
|||
|
|
@ -53,6 +53,7 @@ type ConditionEditorState = {
|
|||
|
||||
type FlowchartEditorProps = {
|
||||
projectId: string
|
||||
projectName: string
|
||||
initialData: FlowchartData
|
||||
}
|
||||
|
||||
|
|
@ -145,7 +146,7 @@ function flowchartDataEquals(a: FlowchartData, b: FlowchartData): boolean {
|
|||
}
|
||||
|
||||
// Inner component that uses useReactFlow hook
|
||||
function FlowchartEditorInner({ projectId, initialData }: FlowchartEditorProps) {
|
||||
function FlowchartEditorInner({ projectId, projectName, initialData }: FlowchartEditorProps) {
|
||||
// Define custom node types - memoized to prevent re-renders
|
||||
const nodeTypes: NodeTypes = useMemo(
|
||||
() => ({
|
||||
|
|
@ -351,8 +352,32 @@ function FlowchartEditorInner({ projectId, initialData }: FlowchartEditorProps)
|
|||
}, [isSaving, nodes, edges, projectId])
|
||||
|
||||
const handleExport = useCallback(() => {
|
||||
// TODO: Implement in US-035
|
||||
}, [])
|
||||
// Convert React Flow state to FlowchartData
|
||||
const flowchartData: FlowchartData = {
|
||||
nodes: fromReactFlowNodes(nodes),
|
||||
edges: fromReactFlowEdges(edges),
|
||||
}
|
||||
|
||||
// Create pretty-printed JSON
|
||||
const jsonContent = JSON.stringify(flowchartData, null, 2)
|
||||
|
||||
// Create blob with JSON content
|
||||
const blob = new Blob([jsonContent], { type: 'application/json' })
|
||||
|
||||
// Create download URL
|
||||
const url = URL.createObjectURL(blob)
|
||||
|
||||
// Create temporary link element and trigger download
|
||||
const link = document.createElement('a')
|
||||
link.href = url
|
||||
link.download = `${projectName}.vnflow`
|
||||
document.body.appendChild(link)
|
||||
link.click()
|
||||
|
||||
// Cleanup
|
||||
document.body.removeChild(link)
|
||||
URL.revokeObjectURL(url)
|
||||
}, [nodes, edges, projectName])
|
||||
|
||||
const handleImport = useCallback(() => {
|
||||
// TODO: Implement in US-036
|
||||
|
|
|
|||
|
|
@ -66,6 +66,7 @@ export default async function EditorPage({ params }: PageProps) {
|
|||
<div className="flex-1">
|
||||
<FlowchartEditor
|
||||
projectId={project.id}
|
||||
projectName={project.name}
|
||||
initialData={flowchartData}
|
||||
/>
|
||||
</div>
|
||||
|
|
|
|||
Loading…
Reference in New Issue