Skip to content

Commit 05149f7

Browse files
committed
refactor(sidebar): moved logic into hooks
1 parent a7f3ff3 commit 05149f7

File tree

7 files changed

+656
-516
lines changed

7 files changed

+656
-516
lines changed

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,9 @@ import type { WorkflowMetadata } from '@/stores/workflows/registry/types'
1212
import { useSubBlockStore } from '@/stores/workflows/subblock/store'
1313
import { useWorkflowStore } from '@/stores/workflows/workflow/store'
1414
import type { WorkflowState } from '@/stores/workflows/workflow/types'
15+
import { useDragDrop } from '../../hooks/use-drag-drop'
1516
import { FolderItem } from './components/folder-item/folder-item'
1617
import { WorkflowItem } from './components/workflow-item/workflow-item'
17-
import { useDragDrop } from './utils/use-drag-drop'
1818

1919
const logger = createLogger('WorkflowList')
2020

apps/sim/app/workspace/[workspaceId]/w/components/sidebar/components-new/workflow-list/utils/use-drag-drop.ts renamed to apps/sim/app/workspace/[workspaceId]/w/components/sidebar/hooks/use-drag-drop.ts

File renamed without changes.
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
import { useCallback, useState } from 'react'
2+
import { createLogger } from '@/lib/logs/console/logger'
3+
import { generateFolderName } from '@/lib/naming'
4+
import { useFolderStore } from '@/stores/folders/store'
5+
6+
const logger = createLogger('useFolderOperations')
7+
8+
interface UseFolderOperationsProps {
9+
workspaceId: string
10+
}
11+
12+
/**
13+
* Custom hook to manage folder operations including creating folders.
14+
* Handles folder name generation and state management.
15+
*
16+
* @param props - Configuration object containing workspaceId
17+
* @returns Folder operations state and handlers
18+
*/
19+
export function useFolderOperations({ workspaceId }: UseFolderOperationsProps) {
20+
const { createFolder } = useFolderStore()
21+
const [isCreatingFolder, setIsCreatingFolder] = useState(false)
22+
23+
/**
24+
* Create folder handler - creates folder with auto-generated name
25+
*/
26+
const handleCreateFolder = useCallback(async () => {
27+
if (isCreatingFolder || !workspaceId) {
28+
logger.info('Folder creation already in progress or no workspaceId available')
29+
return
30+
}
31+
32+
try {
33+
setIsCreatingFolder(true)
34+
const folderName = await generateFolderName(workspaceId)
35+
await createFolder({ name: folderName, workspaceId })
36+
logger.info(`Created folder: ${folderName}`)
37+
} catch (error) {
38+
logger.error('Failed to create folder:', { error })
39+
} finally {
40+
setIsCreatingFolder(false)
41+
}
42+
}, [createFolder, workspaceId, isCreatingFolder])
43+
44+
return {
45+
// State
46+
isCreatingFolder,
47+
48+
// Operations
49+
handleCreateFolder,
50+
}
51+
}
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
import { useCallback, useEffect, useState } from 'react'
2+
import { useSidebarStore } from '@/stores/sidebar/store'
3+
4+
/**
5+
* Constants for sidebar sizing
6+
*/
7+
const MIN_WIDTH = 232
8+
const MAX_WIDTH = 400
9+
10+
/**
11+
* Custom hook to handle sidebar resize functionality.
12+
* Manages mouse events for resizing and enforces min/max width constraints.
13+
*
14+
* @returns Resize state and handlers
15+
*/
16+
export function useSidebarResize() {
17+
const { setSidebarWidth } = useSidebarStore()
18+
const [isResizing, setIsResizing] = useState(false)
19+
20+
/**
21+
* Handles mouse down on resize handle
22+
*/
23+
const handleMouseDown = useCallback(() => {
24+
setIsResizing(true)
25+
}, [])
26+
27+
/**
28+
* Setup resize event listeners and body styles when resizing
29+
* Cleanup is handled automatically by the effect's return function
30+
*/
31+
useEffect(() => {
32+
if (!isResizing) return
33+
34+
const handleMouseMove = (e: MouseEvent) => {
35+
const newWidth = e.clientX
36+
if (newWidth >= MIN_WIDTH && newWidth <= MAX_WIDTH) {
37+
setSidebarWidth(newWidth)
38+
}
39+
}
40+
41+
const handleMouseUp = () => {
42+
setIsResizing(false)
43+
}
44+
45+
document.addEventListener('mousemove', handleMouseMove)
46+
document.addEventListener('mouseup', handleMouseUp)
47+
document.body.style.cursor = 'ew-resize'
48+
document.body.style.userSelect = 'none'
49+
50+
return () => {
51+
document.removeEventListener('mousemove', handleMouseMove)
52+
document.removeEventListener('mouseup', handleMouseUp)
53+
document.body.style.cursor = ''
54+
document.body.style.userSelect = ''
55+
}
56+
}, [isResizing, setSidebarWidth])
57+
58+
return {
59+
isResizing,
60+
handleMouseDown,
61+
}
62+
}
Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
import { useCallback, useEffect, useState } from 'react'
2+
import { useRouter } from 'next/navigation'
3+
import { createLogger } from '@/lib/logs/console/logger'
4+
import { useWorkflowDiffStore } from '@/stores/workflow-diff/store'
5+
import { useWorkflowRegistry } from '@/stores/workflows/registry/store'
6+
7+
const logger = createLogger('useWorkflowOperations')
8+
9+
interface UseWorkflowOperationsProps {
10+
workspaceId: string
11+
isWorkspaceValid: (workspaceId: string) => Promise<boolean>
12+
onWorkspaceInvalid: () => void
13+
}
14+
15+
/**
16+
* Custom hook to manage workflow operations including creating and loading workflows.
17+
* Handles workflow state management and navigation.
18+
*
19+
* @param props - Configuration object containing workspaceId and validation handlers
20+
* @returns Workflow operations state and handlers
21+
*/
22+
export function useWorkflowOperations({
23+
workspaceId,
24+
isWorkspaceValid,
25+
onWorkspaceInvalid,
26+
}: UseWorkflowOperationsProps) {
27+
const router = useRouter()
28+
const {
29+
workflows,
30+
isLoading: workflowsLoading,
31+
loadWorkflows,
32+
createWorkflow,
33+
} = useWorkflowRegistry()
34+
const [isCreatingWorkflow, setIsCreatingWorkflow] = useState(false)
35+
36+
/**
37+
* Filter and sort workflows for the current workspace
38+
*/
39+
const regularWorkflows = Object.values(workflows)
40+
.filter((workflow) => workflow.workspaceId === workspaceId)
41+
.sort((a, b) => {
42+
// Sort by creation date (newest first) for stable ordering
43+
return b.createdAt.getTime() - a.createdAt.getTime()
44+
})
45+
46+
/**
47+
* Create workflow handler - creates workflow and navigates to it
48+
*/
49+
const handleCreateWorkflow = useCallback(async () => {
50+
if (isCreatingWorkflow) {
51+
logger.info('Workflow creation already in progress, ignoring request')
52+
return
53+
}
54+
55+
try {
56+
setIsCreatingWorkflow(true)
57+
58+
// Clear workflow diff store when creating a new workflow
59+
const { clearDiff } = useWorkflowDiffStore.getState()
60+
clearDiff()
61+
62+
const workflowId = await createWorkflow({
63+
workspaceId: workspaceId || undefined,
64+
})
65+
66+
// Navigate to the newly created workflow
67+
if (workflowId) {
68+
router.push(`/workspace/${workspaceId}/w/${workflowId}`)
69+
}
70+
} catch (error) {
71+
logger.error('Error creating workflow:', error)
72+
} finally {
73+
setIsCreatingWorkflow(false)
74+
}
75+
}, [isCreatingWorkflow, createWorkflow, workspaceId, router])
76+
77+
/**
78+
* Load workflows for the current workspace when workspaceId changes
79+
*/
80+
useEffect(() => {
81+
if (workspaceId) {
82+
// Validate workspace exists before loading workflows
83+
isWorkspaceValid(workspaceId).then((valid) => {
84+
if (valid) {
85+
loadWorkflows(workspaceId)
86+
} else {
87+
logger.warn(`Workspace ${workspaceId} no longer exists, triggering workspace refresh`)
88+
onWorkspaceInvalid()
89+
}
90+
})
91+
}
92+
}, [workspaceId, loadWorkflows, isWorkspaceValid, onWorkspaceInvalid])
93+
94+
return {
95+
// State
96+
workflows,
97+
regularWorkflows,
98+
workflowsLoading,
99+
isCreatingWorkflow,
100+
101+
// Operations
102+
handleCreateWorkflow,
103+
loadWorkflows,
104+
}
105+
}

0 commit comments

Comments
 (0)