Skip to content

Commit 5eb7b88

Browse files
authored
fix(folders): modified folder deletion to delete subfolders & workflows in it instead of moving to root (#508)
* modified folder deletion to delete subfolders & workflows in it instead of moving to root * added additional testing utils * ack PR comments
1 parent f4cbf5d commit 5eb7b88

File tree

9 files changed

+1375
-76
lines changed

9 files changed

+1375
-76
lines changed

apps/sim/app/api/__test-utils__/utils.ts

Lines changed: 396 additions & 0 deletions
Large diffs are not rendered by default.

apps/sim/app/api/folders/[id]/route.test.ts

Lines changed: 414 additions & 0 deletions
Large diffs are not rendered by default.

apps/sim/app/api/folders/[id]/route.ts

Lines changed: 50 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ export async function PUT(request: NextRequest, { params }: { params: Promise<{
6868
}
6969
}
7070

71-
// DELETE - Delete a folder
71+
// DELETE - Delete a folder and all its contents
7272
export async function DELETE(
7373
request: NextRequest,
7474
{ params }: { params: Promise<{ id: string }> }
@@ -80,8 +80,6 @@ export async function DELETE(
8080
}
8181

8282
const { id } = await params
83-
const { searchParams } = new URL(request.url)
84-
const moveWorkflowsTo = searchParams.get('moveWorkflowsTo') // Optional: move workflows to another folder
8583

8684
// Verify the folder exists and belongs to the user
8785
const existingFolder = await db
@@ -94,64 +92,68 @@ export async function DELETE(
9492
return NextResponse.json({ error: 'Folder not found' }, { status: 404 })
9593
}
9694

97-
// Check if folder has child folders
98-
const childFolders = await db
99-
.select({ id: workflowFolder.id })
100-
.from(workflowFolder)
101-
.where(eq(workflowFolder.parentId, id))
102-
103-
// Check if folder has workflows
104-
const workflowsInFolder = await db
105-
.select({ id: workflow.id })
106-
.from(workflow)
107-
.where(eq(workflow.folderId, id))
108-
109-
// Handle child folders - move them to parent or root
110-
if (childFolders.length > 0) {
111-
await db
112-
.update(workflowFolder)
113-
.set({
114-
parentId: existingFolder.parentId, // Move to the parent of the deleted folder
115-
updatedAt: new Date(),
116-
})
117-
.where(eq(workflowFolder.parentId, id))
118-
}
119-
120-
// Handle workflows in the folder
121-
if (workflowsInFolder.length > 0) {
122-
const newFolderId = moveWorkflowsTo || null // Move to specified folder or root
123-
await db
124-
.update(workflow)
125-
.set({
126-
folderId: newFolderId,
127-
updatedAt: new Date(),
128-
})
129-
.where(eq(workflow.folderId, id))
130-
}
95+
// Recursively delete folder and all its contents
96+
const deletionStats = await deleteFolderRecursively(id, session.user.id)
13197

132-
// Delete the folder
133-
await db.delete(workflowFolder).where(eq(workflowFolder.id, id))
134-
135-
logger.info('Deleted folder:', {
98+
logger.info('Deleted folder and all contents:', {
13699
id,
137-
childFoldersCount: childFolders.length,
138-
workflowsCount: workflowsInFolder.length,
139-
movedWorkflowsTo: moveWorkflowsTo,
100+
deletionStats,
140101
})
141102

142103
return NextResponse.json({
143104
success: true,
144-
movedItems: {
145-
childFolders: childFolders.length,
146-
workflows: workflowsInFolder.length,
147-
},
105+
deletedItems: deletionStats,
148106
})
149107
} catch (error) {
150108
logger.error('Error deleting folder:', { error })
151109
return NextResponse.json({ error: 'Internal server error' }, { status: 500 })
152110
}
153111
}
154112

113+
// Helper function to recursively delete a folder and all its contents
114+
async function deleteFolderRecursively(
115+
folderId: string,
116+
userId: string
117+
): Promise<{ folders: number; workflows: number }> {
118+
const stats = { folders: 0, workflows: 0 }
119+
120+
// Get all child folders first
121+
const childFolders = await db
122+
.select({ id: workflowFolder.id })
123+
.from(workflowFolder)
124+
.where(and(eq(workflowFolder.parentId, folderId), eq(workflowFolder.userId, userId)))
125+
126+
// Recursively delete child folders
127+
for (const childFolder of childFolders) {
128+
const childStats = await deleteFolderRecursively(childFolder.id, userId)
129+
stats.folders += childStats.folders
130+
stats.workflows += childStats.workflows
131+
}
132+
133+
// Delete all workflows in this folder
134+
const workflowsInFolder = await db
135+
.select({ id: workflow.id })
136+
.from(workflow)
137+
.where(and(eq(workflow.folderId, folderId), eq(workflow.userId, userId)))
138+
139+
if (workflowsInFolder.length > 0) {
140+
await db
141+
.delete(workflow)
142+
.where(and(eq(workflow.folderId, folderId), eq(workflow.userId, userId)))
143+
144+
stats.workflows += workflowsInFolder.length
145+
}
146+
147+
// Delete this folder
148+
await db
149+
.delete(workflowFolder)
150+
.where(and(eq(workflowFolder.id, folderId), eq(workflowFolder.userId, userId)))
151+
152+
stats.folders += 1
153+
154+
return stats
155+
}
156+
155157
// Helper function to check for circular references
156158
async function checkForCircularReference(folderId: string, parentId: string): Promise<boolean> {
157159
let currentParentId: string | null = parentId

0 commit comments

Comments
 (0)