( folderName: string, workflows: WorkflowExportData[], folders: FolderExportData[] )
| 283 | * @param folders - Subfolders within the exported folder (parentId should be null for direct children) |
| 284 | */ |
| 285 | export async function exportFolderToZip( |
| 286 | folderName: string, |
| 287 | workflows: WorkflowExportData[], |
| 288 | folders: FolderExportData[] |
| 289 | ): Promise<Blob> { |
| 290 | const JSZip = await getJSZip() |
| 291 | const zip = new JSZip() |
| 292 | const foldersMap = new Map(folders.map((f) => [f.id, f])) |
| 293 | |
| 294 | const metadata = { |
| 295 | folder: { |
| 296 | name: folderName, |
| 297 | exportedAt: new Date().toISOString(), |
| 298 | }, |
| 299 | folders: folders.map((f) => ({ id: f.id, name: f.name, parentId: f.parentId })), |
| 300 | } |
| 301 | |
| 302 | zip.file('_folder.json', JSON.stringify(metadata, null, 2)) |
| 303 | |
| 304 | for (const workflow of workflows) { |
| 305 | try { |
| 306 | const workflowState = { |
| 307 | ...workflow.state, |
| 308 | metadata: { |
| 309 | name: workflow.workflow.name, |
| 310 | description: workflow.workflow.description, |
| 311 | exportedAt: new Date().toISOString(), |
| 312 | }, |
| 313 | variables: workflow.variables, |
| 314 | } |
| 315 | |
| 316 | const exportState = sanitizeForExport(workflowState) |
| 317 | const sanitizedName = sanitizePathSegment(workflow.workflow.name) |
| 318 | const filename = `${sanitizedName}-${workflow.workflow.id}.json` |
| 319 | |
| 320 | const folderPath = buildFolderPath(workflow.workflow.folderId, foldersMap) |
| 321 | const fullPath = folderPath ? `${folderPath}/${filename}` : filename |
| 322 | |
| 323 | zip.file(fullPath, JSON.stringify(exportState, null, 2)) |
| 324 | } catch (error) { |
| 325 | logger.error(`Failed to export workflow ${workflow.workflow.id}:`, error) |
| 326 | } |
| 327 | } |
| 328 | |
| 329 | return await zip.generateAsync({ type: 'blob' }) |
| 330 | } |
| 331 | |
| 332 | export interface ImportedWorkflow { |
| 333 | content: string |
no test coverage detected