11import { AuditAction , AuditResourceType , recordAudit } from '@sim/audit'
22import { db } from '@sim/db'
3- import { workflow , workflowFolder } from '@sim/db/schema'
3+ import { folder as folderTable , workflow } from '@sim/db/schema'
44import { createLogger } from '@sim/logger'
55import { FolderLockedError } from '@sim/platform-authz/workflow'
66import { generateId } from '@sim/utils/id'
@@ -12,6 +12,7 @@ import { getSession } from '@/lib/auth'
1212import { generateRequestId } from '@/lib/core/utils/request'
1313import { withRouteHandler } from '@/lib/core/utils/with-route-handler'
1414import type { DbOrTx } from '@/lib/db/types'
15+ import { deduplicateFolderName } from '@/lib/folders/naming'
1516import { toFolderApi } from '@/lib/folders/queries'
1617import { duplicateWorkflow } from '@/lib/workflows/persistence/duplicate'
1718import { getUserEntityPermissions } from '@/lib/workspaces/permissions/utils'
@@ -40,8 +41,14 @@ export const POST = withRouteHandler(
4041
4142 const sourceFolder = await db
4243 . select ( )
43- . from ( workflowFolder )
44- . where ( and ( eq ( workflowFolder . id , sourceFolderId ) , isNull ( workflowFolder . archivedAt ) ) )
44+ . from ( folderTable )
45+ . where (
46+ and (
47+ eq ( folderTable . id , sourceFolderId ) ,
48+ isNull ( folderTable . deletedAt ) ,
49+ eq ( folderTable . resourceType , 'workflow' )
50+ )
51+ )
4552 . then ( ( rows ) => rows [ 0 ] )
4653
4754 if ( ! sourceFolder ) {
@@ -70,17 +77,23 @@ export const POST = withRouteHandler(
7077 await assertTargetParentFolderMutable ( tx , targetParentId , targetWorkspaceId , sourceFolderId )
7178
7279 const folderParentCondition = targetParentId
73- ? eq ( workflowFolder . parentId , targetParentId )
74- : isNull ( workflowFolder . parentId )
80+ ? eq ( folderTable . parentId , targetParentId )
81+ : isNull ( folderTable . parentId )
7582 const workflowParentCondition = targetParentId
7683 ? eq ( workflow . folderId , targetParentId )
7784 : isNull ( workflow . folderId )
7885
7986 const [ [ folderResult ] , [ workflowResult ] ] = await Promise . all ( [
8087 tx
81- . select ( { minSortOrder : min ( workflowFolder . sortOrder ) } )
82- . from ( workflowFolder )
83- . where ( and ( eq ( workflowFolder . workspaceId , targetWorkspaceId ) , folderParentCondition ) ) ,
88+ . select ( { minSortOrder : min ( folderTable . sortOrder ) } )
89+ . from ( folderTable )
90+ . where (
91+ and (
92+ eq ( folderTable . workspaceId , targetWorkspaceId ) ,
93+ eq ( folderTable . resourceType , 'workflow' ) ,
94+ folderParentCondition
95+ )
96+ ) ,
8497 tx
8598 . select ( { minSortOrder : min ( workflow . sortOrder ) } )
8699 . from ( workflow )
@@ -102,15 +115,14 @@ export const POST = withRouteHandler(
102115 name
103116 )
104117
105- await tx . insert ( workflowFolder ) . values ( {
118+ await tx . insert ( folderTable ) . values ( {
106119 id : newFolderId ,
120+ resourceType : 'workflow' ,
107121 userId : session . user . id ,
108122 workspaceId : targetWorkspaceId ,
109123 name : deduplicatedName ,
110- color : sourceFolder . color ,
111124 parentId : targetParentId ,
112125 sortOrder,
113- isExpanded : false ,
114126 locked : false ,
115127 createdAt : now ,
116128 updatedAt : now ,
@@ -169,8 +181,8 @@ export const POST = withRouteHandler(
169181
170182 const duplicatedFolder = await db
171183 . select ( )
172- . from ( workflowFolder )
173- . where ( eq ( workflowFolder . id , newFolderId ) )
184+ . from ( folderTable )
185+ . where ( and ( eq ( folderTable . id , newFolderId ) , eq ( folderTable . resourceType , 'workflow' ) ) )
174186 . then ( ( rows ) => rows [ 0 ] )
175187
176188 return NextResponse . json ( { folder : toFolderApi ( duplicatedFolder ) } , { status : 201 } )
@@ -230,14 +242,14 @@ async function assertTargetParentFolderMutable(
230242 visited . add ( currentFolderId )
231243 const [ folder ] = await tx
232244 . select ( {
233- id : workflowFolder . id ,
234- parentId : workflowFolder . parentId ,
235- workspaceId : workflowFolder . workspaceId ,
236- locked : workflowFolder . locked ,
237- archivedAt : workflowFolder . archivedAt ,
245+ id : folderTable . id ,
246+ parentId : folderTable . parentId ,
247+ workspaceId : folderTable . workspaceId ,
248+ locked : folderTable . locked ,
249+ archivedAt : folderTable . deletedAt ,
238250 } )
239- . from ( workflowFolder )
240- . where ( eq ( workflowFolder . id , currentFolderId ) )
251+ . from ( folderTable )
252+ . where ( and ( eq ( folderTable . id , currentFolderId ) , eq ( folderTable . resourceType , 'workflow' ) ) )
241253 . limit ( 1 )
242254
243255 if ( ! folder || folder . workspaceId !== targetWorkspaceId || folder . archivedAt ) {
@@ -254,37 +266,6 @@ async function assertTargetParentFolderMutable(
254266 }
255267}
256268
257- async function deduplicateFolderName (
258- tx : DbOrTx ,
259- workspaceId : string ,
260- parentId : string | null ,
261- requestedName : string
262- ) : Promise < string > {
263- const parentCondition = parentId
264- ? eq ( workflowFolder . parentId , parentId )
265- : isNull ( workflowFolder . parentId )
266- const siblingRows = await tx
267- . select ( { name : workflowFolder . name } )
268- . from ( workflowFolder )
269- . where (
270- and (
271- eq ( workflowFolder . workspaceId , workspaceId ) ,
272- parentCondition ,
273- isNull ( workflowFolder . archivedAt )
274- )
275- )
276- const siblingNames = new Set ( siblingRows . map ( ( row ) => row . name ) )
277- if ( ! siblingNames . has ( requestedName ) ) return requestedName
278-
279- let suffix = 1
280- let candidate = `${ requestedName } (${ suffix } )`
281- while ( siblingNames . has ( candidate ) ) {
282- suffix += 1
283- candidate = `${ requestedName } (${ suffix } )`
284- }
285- return candidate
286- }
287-
288269async function duplicateFolderStructure (
289270 tx : DbOrTx ,
290271 sourceFolderId : string ,
@@ -297,28 +278,28 @@ async function duplicateFolderStructure(
297278) : Promise < void > {
298279 const childFolders = await tx
299280 . select ( )
300- . from ( workflowFolder )
281+ . from ( folderTable )
301282 . where (
302283 and (
303- eq ( workflowFolder . parentId , sourceFolderId ) ,
304- eq ( workflowFolder . workspaceId , sourceWorkspaceId ) ,
305- isNull ( workflowFolder . archivedAt )
284+ eq ( folderTable . parentId , sourceFolderId ) ,
285+ eq ( folderTable . workspaceId , sourceWorkspaceId ) ,
286+ eq ( folderTable . resourceType , 'workflow' ) ,
287+ isNull ( folderTable . deletedAt )
306288 )
307289 )
308290
309291 for ( const childFolder of childFolders ) {
310292 const newChildFolderId = generateId ( )
311293 folderMapping . set ( childFolder . id , newChildFolderId )
312294
313- await tx . insert ( workflowFolder ) . values ( {
295+ await tx . insert ( folderTable ) . values ( {
314296 id : newChildFolderId ,
297+ resourceType : 'workflow' ,
315298 userId,
316299 workspaceId : targetWorkspaceId ,
317300 name : childFolder . name ,
318- color : childFolder . color ,
319301 parentId : newParentFolderId ,
320302 sortOrder : childFolder . sortOrder ,
321- isExpanded : false ,
322303 locked : false ,
323304 createdAt : timestamp ,
324305 updatedAt : timestamp ,
0 commit comments