Skip to content

Commit 9525ac0

Browse files
committed
fix(files): revert broken ref opt, clean 409 on restore, null parentId on orphaned restore
- files.tsx: revert the activeDropTargetId ref optimization — the ref doesn't trigger re-renders so the drop-target highlight never updated during drag; activeDropTargetId is back in state and in the rowDragDropConfig deps - restore/route.ts: catch Postgres 23505 unique-constraint violation and return a clean 409 instead of leaking the raw error as 400 - restoreWorkspaceFileFolder: check if the parent folder is still archived before restoring; if it is, restore to root (parentId: null) so the folder is never orphaned under an archived parent
1 parent 13c4f18 commit 9525ac0

3 files changed

Lines changed: 29 additions & 14 deletions

File tree

apps/sim/app/api/workspaces/[id]/files/folders/[folderId]/restore/route.ts

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { AuditAction, AuditResourceType, recordAudit } from '@sim/audit'
22
import { createLogger } from '@sim/logger'
3-
import { toError } from '@sim/utils/errors'
3+
import { getPostgresErrorCode, toError } from '@sim/utils/errors'
44
import { type NextRequest, NextResponse } from 'next/server'
55
import { restoreWorkspaceFileFolderContract } from '@/lib/api/contracts/workspace-file-folders'
66
import { parseRequest } from '@/lib/api/server'
@@ -55,13 +55,13 @@ export const POST = withRouteHandler(
5555
return NextResponse.json({ success: true, folder })
5656
} catch (error) {
5757
logger.error('Failed to restore workspace file folder:', error)
58-
return NextResponse.json(
59-
{
60-
success: false,
61-
error: toError(error).message,
62-
},
63-
{ status: 400 }
64-
)
58+
if (getPostgresErrorCode(error) === '23505') {
59+
return NextResponse.json(
60+
{ success: false, error: 'A folder with this name already exists in this location' },
61+
{ status: 409 }
62+
)
63+
}
64+
return NextResponse.json({ success: false, error: toError(error).message }, { status: 400 })
6565
}
6666
}
6767
)

apps/sim/app/workspace/[workspaceId]/files/files.tsx

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -243,10 +243,6 @@ export function Files() {
243243
const [saveStatus, setSaveStatus] = useState<SaveStatus>('idle')
244244
const [selectedRowIds, setSelectedRowIds] = useState<Set<string>>(() => new Set())
245245
const [activeDropTargetId, setActiveDropTargetId] = useState<string | null>(null)
246-
const activeDropTargetIdRef = useRef(activeDropTargetId)
247-
useEffect(() => {
248-
activeDropTargetIdRef.current = activeDropTargetId
249-
}, [activeDropTargetId])
250246
const [draggedRowIds, setDraggedRowIds] = useState<Set<string>>(() => new Set())
251247
const [previewMode, setPreviewMode] = useState<PreviewMode>(() => {
252248
if (isNewFile) return 'editor'
@@ -683,7 +679,7 @@ export function Files() {
683679

684680
const rowDragDropConfig = useMemo<RowDragDropConfig>(
685681
() => ({
686-
activeDropTargetId: activeDropTargetIdRef.current,
682+
activeDropTargetId,
687683
draggedRowIds,
688684
isAnyDragActive: draggedRowIds.size > 0,
689685
isRowDraggable: (rowId) => canEdit && listRename.editingId !== rowId,
@@ -817,6 +813,7 @@ export function Files() {
817813
},
818814
}),
819815
[
816+
activeDropTargetId,
820817
draggedRowIds,
821818
canEdit,
822819
listRename.editingId,

apps/sim/lib/uploads/contexts/workspace/workspace-file-folder-manager.ts

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -914,9 +914,27 @@ export async function restoreWorkspaceFileFolder(
914914
if (!raw) throw new Error('Folder not found')
915915
if (!raw.deletedAt) throw new Error('Folder is not archived')
916916

917+
// If the parent folder is still archived, restore to root so the folder
918+
// doesn't become an orphan (hidden under an archived parent).
919+
let resolvedParentId = raw.parentId
920+
if (resolvedParentId) {
921+
const parent = await db
922+
.select({ deletedAt: workspaceFileFolder.deletedAt })
923+
.from(workspaceFileFolder)
924+
.where(
925+
and(
926+
eq(workspaceFileFolder.id, resolvedParentId),
927+
eq(workspaceFileFolder.workspaceId, workspaceId)
928+
)
929+
)
930+
.limit(1)
931+
.then((rows) => rows[0] ?? null)
932+
if (!parent || parent.deletedAt) resolvedParentId = null
933+
}
934+
917935
const [restored] = await db
918936
.update(workspaceFileFolder)
919-
.set({ deletedAt: null, updatedAt: new Date() })
937+
.set({ deletedAt: null, parentId: resolvedParentId, updatedAt: new Date() })
920938
.where(
921939
and(eq(workspaceFileFolder.id, folderId), eq(workspaceFileFolder.workspaceId, workspaceId))
922940
)

0 commit comments

Comments
 (0)