Skip to content

Commit d0c0983

Browse files
committed
feat(export): added the ability to export workflow
1 parent cb4db20 commit d0c0983

File tree

8 files changed

+362
-30
lines changed

8 files changed

+362
-30
lines changed

apps/sim/app/workspace/[workspaceId]/w/components/sidebar/components/workflow-list/components/folder-item/folder-item.tsx

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import {
2020
useCanDelete,
2121
useDeleteFolder,
2222
useDuplicateFolder,
23+
useExportFolder,
2324
} from '@/app/workspace/[workspaceId]/w/hooks'
2425
import { useCreateFolder, useUpdateFolder } from '@/hooks/queries/folders'
2526
import { useCreateWorkflow } from '@/hooks/queries/workflows'
@@ -73,6 +74,12 @@ export function FolderItem({ folder, level, hoverHandlers }: FolderItemProps) {
7374
getFolderIds: () => folder.id,
7475
})
7576

77+
// Export folder hook
78+
const { isExporting, hasWorkflows, handleExportFolder } = useExportFolder({
79+
workspaceId,
80+
getFolderId: () => folder.id,
81+
})
82+
7683
// Folder expand hook - must be declared before callbacks that use expandFolder
7784
const {
7885
isExpanded,
@@ -365,13 +372,16 @@ export function FolderItem({ folder, level, hoverHandlers }: FolderItemProps) {
365372
onCreate={handleCreateWorkflowInFolder}
366373
onCreateFolder={handleCreateFolderInFolder}
367374
onDuplicate={handleDuplicateFolder}
375+
onExport={handleExportFolder}
368376
onDelete={() => setIsDeleteModalOpen(true)}
369377
showCreate={true}
370378
showCreateFolder={true}
379+
showExport={true}
371380
disableRename={!userPermissions.canEdit}
372381
disableCreate={!userPermissions.canEdit || createWorkflowMutation.isPending}
373382
disableCreateFolder={!userPermissions.canEdit || createFolderMutation.isPending}
374-
disableDuplicate={!userPermissions.canEdit}
383+
disableDuplicate={!userPermissions.canEdit || !hasWorkflows}
384+
disableExport={!userPermissions.canEdit || isExporting || !hasWorkflows}
375385
disableDelete={!userPermissions.canEdit || !canDelete}
376386
/>
377387

apps/sim/app/workspace/[workspaceId]/w/components/sidebar/components/workflow-list/workflow-list.tsx

Lines changed: 2 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@ import {
99
useDragDrop,
1010
useWorkflowSelection,
1111
} from '@/app/workspace/[workspaceId]/w/components/sidebar/hooks'
12-
import { useImportWorkflow } from '@/app/workspace/[workspaceId]/w/hooks/use-import-workflow'
1312
import { useFolders } from '@/hooks/queries/folders'
1413
import { useFolderStore } from '@/stores/folders/store'
1514
import type { FolderTreeNode } from '@/stores/folders/types'
@@ -25,24 +24,21 @@ const TREE_SPACING = {
2524
interface WorkflowListProps {
2625
regularWorkflows: WorkflowMetadata[]
2726
isLoading?: boolean
28-
isImporting: boolean
29-
setIsImporting: (value: boolean) => void
27+
handleFileChange: (event: React.ChangeEvent<HTMLInputElement>) => void
3028
fileInputRef: React.RefObject<HTMLInputElement | null>
3129
scrollContainerRef: React.RefObject<HTMLDivElement | null>
3230
}
3331

3432
/**
3533
* WorkflowList component displays workflows organized by folders with drag-and-drop support.
36-
* Uses the workflow import hook for handling JSON imports.
3734
*
3835
* @param props - Component props
3936
* @returns Workflow list with folders and drag-drop support
4037
*/
4138
export function WorkflowList({
4239
regularWorkflows,
4340
isLoading = false,
44-
isImporting,
45-
setIsImporting,
41+
handleFileChange,
4642
fileInputRef,
4743
scrollContainerRef,
4844
}: WorkflowListProps) {
@@ -65,9 +61,6 @@ export function WorkflowList({
6561
createFolderHeaderHoverHandlers,
6662
} = useDragDrop()
6763

68-
// Workflow import hook
69-
const { handleFileChange } = useImportWorkflow({ workspaceId })
70-
7164
// Set scroll container when ref changes
7265
useEffect(() => {
7366
if (scrollContainerRef.current) {

apps/sim/app/workspace/[workspaceId]/w/components/sidebar/sidebar.tsx

Lines changed: 32 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,10 @@
22

33
import { useCallback, useEffect, useMemo, useRef, useState } from 'react'
44
import { createLogger } from '@sim/logger'
5-
import { ArrowDown, Database, HelpCircle, Layout, Plus, Search, Settings } from 'lucide-react'
5+
import { Database, HelpCircle, Layout, Plus, Search, Settings } from 'lucide-react'
66
import Link from 'next/link'
77
import { useParams, usePathname, useRouter } from 'next/navigation'
8-
import { Button, FolderPlus, Library, Tooltip } from '@/components/emcn'
8+
import { Button, Download, FolderPlus, Library, Tooltip } from '@/components/emcn'
99
import { useSession } from '@/lib/auth/auth-client'
1010
import { getEnv, isTruthy } from '@/lib/core/config/env'
1111
import { useRegisterGlobalCommands } from '@/app/workspace/[workspaceId]/providers/global-commands-provider'
@@ -30,6 +30,7 @@ import {
3030
import {
3131
useDuplicateWorkspace,
3232
useExportWorkspace,
33+
useImportWorkflow,
3334
useImportWorkspace,
3435
} from '@/app/workspace/[workspaceId]/w/hooks'
3536
import { usePermissionConfig } from '@/hooks/use-permission-config'
@@ -85,9 +86,11 @@ export function Sidebar() {
8586
const isCollapsed = hasHydrated ? isCollapsedStore : false
8687
const isOnWorkflowPage = !!workflowId
8788

88-
const [isImporting, setIsImporting] = useState(false)
8989
const workspaceFileInputRef = useRef<HTMLInputElement>(null)
9090

91+
const { isImporting, handleFileChange: handleImportFileChange } = useImportWorkflow({
92+
workspaceId,
93+
})
9194
const { isImporting: isImportingWorkspace, handleImportWorkspace: importWorkspace } =
9295
useImportWorkspace()
9396
const { handleExportWorkspace: exportWorkspace } = useExportWorkspace()
@@ -565,21 +568,31 @@ export function Sidebar() {
565568
Workflows
566569
</div>
567570
<div className='flex items-center justify-center gap-[10px]'>
568-
<Tooltip.Root>
569-
<Tooltip.Trigger asChild>
570-
<Button
571-
variant='ghost'
572-
className='translate-y-[-0.25px] p-[1px]'
573-
onClick={handleImportWorkflow}
574-
disabled={isImporting || !canEdit}
575-
>
576-
<ArrowDown className='h-[14px] w-[14px]' />
577-
</Button>
578-
</Tooltip.Trigger>
579-
<Tooltip.Content>
580-
<p>{isImporting ? 'Importing workflow...' : 'Import workflow'}</p>
581-
</Tooltip.Content>
582-
</Tooltip.Root>
571+
{isImporting ? (
572+
<Button
573+
variant='ghost'
574+
className='translate-y-[-0.25px] p-[1px]'
575+
disabled={!canEdit}
576+
>
577+
<Download className='h-[14px] w-[14px]' animate />
578+
</Button>
579+
) : (
580+
<Tooltip.Root>
581+
<Tooltip.Trigger asChild>
582+
<Button
583+
variant='ghost'
584+
className='translate-y-[-0.25px] p-[1px]'
585+
onClick={handleImportWorkflow}
586+
disabled={!canEdit}
587+
>
588+
<Download className='h-[14px] w-[14px]' />
589+
</Button>
590+
</Tooltip.Trigger>
591+
<Tooltip.Content>
592+
<p>Import workflows</p>
593+
</Tooltip.Content>
594+
</Tooltip.Root>
595+
)}
583596
<Tooltip.Root>
584597
<Tooltip.Trigger asChild>
585598
<Button
@@ -622,8 +635,7 @@ export function Sidebar() {
622635
<WorkflowList
623636
regularWorkflows={regularWorkflows}
624637
isLoading={isLoading}
625-
isImporting={isImporting}
626-
setIsImporting={setIsImporting}
638+
handleFileChange={handleImportFileChange}
627639
fileInputRef={fileInputRef}
628640
scrollContainerRef={scrollContainerRef}
629641
/>

apps/sim/app/workspace/[workspaceId]/w/hooks/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ export { useDeleteWorkflow } from './use-delete-workflow'
44
export { useDuplicateFolder } from './use-duplicate-folder'
55
export { useDuplicateWorkflow } from './use-duplicate-workflow'
66
export { useDuplicateWorkspace } from './use-duplicate-workspace'
7+
export { useExportFolder } from './use-export-folder'
78
export { useExportWorkflow } from './use-export-workflow'
89
export { useExportWorkspace } from './use-export-workspace'
910
export { useImportWorkflow } from './use-import-workflow'

0 commit comments

Comments
 (0)