Skip to content

Commit b987ce6

Browse files
committed
cleanup unnused code
1 parent 4cb15cc commit b987ce6

4 files changed

Lines changed: 129 additions & 71 deletions

File tree

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

Lines changed: 20 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -254,7 +254,6 @@ export function Files() {
254254
fileIds: string[]
255255
folderIds: string[]
256256
name: string
257-
isFolder?: boolean
258257
} | null>(null)
259258

260259
const listRename = useInlineRename({
@@ -884,7 +883,6 @@ export function Files() {
884883
folders.find((folder) => folder.id === selectedFolderIds[0])?.name ??
885884
'selected item')
886885
: `${selectedFileIds.length + selectedFolderIds.length} selected items`,
887-
isFolder: selectedFolderIds.length > 0,
888886
})
889887
setShowDeleteConfirm(true)
890888
}, [selectedFileIds, selectedFolderIds, files, folders])
@@ -1123,7 +1121,7 @@ export function Files() {
11231121
setDeleteTarget(
11241122
item.kind === 'file'
11251123
? { fileIds: [item.file.id], folderIds: [], name: item.file.name }
1126-
: { fileIds: [], folderIds: [item.folder.id], name: item.folder.name, isFolder: true }
1124+
: { fileIds: [], folderIds: [item.folder.id], name: item.folder.name }
11271125
)
11281126
setShowDeleteConfirm(true)
11291127
closeContextMenu()
@@ -1648,7 +1646,8 @@ export function Files() {
16481646
open={showDeleteConfirm}
16491647
onOpenChange={setShowDeleteConfirm}
16501648
fileName={deleteTarget?.name}
1651-
isFolder={deleteTarget?.isFolder}
1649+
fileCount={deleteTarget?.fileIds.length ?? 0}
1650+
folderCount={deleteTarget?.folderIds.length ?? 0}
16521651
onDelete={handleDelete}
16531652
isPending={deleteFile.isPending || bulkArchiveItems.isPending}
16541653
/>
@@ -1733,7 +1732,8 @@ export function Files() {
17331732
open={showDeleteConfirm}
17341733
onOpenChange={setShowDeleteConfirm}
17351734
fileName={deleteTarget?.name}
1736-
isFolder={deleteTarget?.isFolder}
1735+
fileCount={deleteTarget?.fileIds.length ?? 0}
1736+
folderCount={deleteTarget?.folderIds.length ?? 0}
17371737
onDelete={handleDelete}
17381738
isPending={deleteFile.isPending || bulkArchiveItems.isPending}
17391739
/>
@@ -1855,7 +1855,8 @@ interface DeleteConfirmModalProps {
18551855
open: boolean
18561856
onOpenChange: (open: boolean) => void
18571857
fileName?: string
1858-
isFolder?: boolean
1858+
fileCount: number
1859+
folderCount: number
18591860
onDelete: () => void
18601861
isPending: boolean
18611862
}
@@ -1864,21 +1865,29 @@ const DeleteConfirmModal = memo(function DeleteConfirmModal({
18641865
open,
18651866
onOpenChange,
18661867
fileName,
1867-
isFolder = false,
1868+
fileCount,
1869+
folderCount,
18681870
onDelete,
18691871
isPending,
18701872
}: DeleteConfirmModalProps) {
1873+
const totalCount = fileCount + folderCount
1874+
const hasFolders = folderCount > 0
1875+
const title = totalCount > 1 ? 'Delete Items' : hasFolders ? 'Delete Folder' : 'Delete File'
1876+
const consequence = hasFolders
1877+
? totalCount > 1
1878+
? 'This will also delete files and folders inside any selected folders.'
1879+
: 'This will also delete files and folders inside it.'
1880+
: 'You can restore it from Recently Deleted in Settings.'
1881+
18711882
return (
18721883
<Modal open={open} onOpenChange={onOpenChange}>
18731884
<ModalContent size='sm'>
1874-
<ModalHeader>{isFolder ? 'Delete Folder' : 'Delete File'}</ModalHeader>
1885+
<ModalHeader>{title}</ModalHeader>
18751886
<ModalBody>
18761887
<p className='text-[var(--text-secondary)]'>
18771888
Are you sure you want to delete{' '}
18781889
<span className='font-medium text-[var(--text-primary)]'>{fileName}</span>?{' '}
1879-
{isFolder
1880-
? 'This will also delete files and folders inside it.'
1881-
: 'You can restore it from Recently Deleted in Settings.'}
1890+
{consequence}
18821891
</p>
18831892
</ModalBody>
18841893
<ModalFooter>

apps/sim/hooks/queries/workspace-file-folders.ts

Lines changed: 0 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@ import { requestJson } from '@/lib/api/client/request'
33
import {
44
bulkArchiveWorkspaceFileItemsContract,
55
createWorkspaceFileFolderContract,
6-
deleteWorkspaceFileFolderContract,
76
listWorkspaceFileFoldersContract,
87
moveWorkspaceFileItemsContract,
98
updateWorkspaceFileFolderContract,
@@ -96,20 +95,6 @@ export function useUpdateWorkspaceFileFolder() {
9695
})
9796
}
9897

99-
export function useDeleteWorkspaceFileFolder() {
100-
const queryClient = useQueryClient()
101-
return useMutation({
102-
mutationFn: async (variables: { workspaceId: string; folderId: string }) => {
103-
return requestJson(deleteWorkspaceFileFolderContract, {
104-
params: { id: variables.workspaceId, folderId: variables.folderId },
105-
})
106-
},
107-
onSettled: (_data, _error, variables) => {
108-
invalidateWorkspaceFileBrowsers(queryClient, variables.workspaceId)
109-
},
110-
})
111-
}
112-
11398
export function useMoveWorkspaceFileItems() {
11499
const queryClient = useQueryClient()
115100
return useMutation({

apps/sim/lib/uploads/client/download.ts

Lines changed: 0 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -24,14 +24,3 @@ export async function triggerFileDownload(record: WorkspaceFileRecord): Promise<
2424
document.body.removeChild(a)
2525
URL.revokeObjectURL(objectUrl)
2626
}
27-
28-
export function triggerBlobDownload(blob: Blob, fileName: string): void {
29-
const objectUrl = URL.createObjectURL(blob)
30-
const a = document.createElement('a')
31-
a.href = objectUrl
32-
a.download = fileName
33-
document.body.appendChild(a)
34-
a.click()
35-
document.body.removeChild(a)
36-
URL.revokeObjectURL(objectUrl)
37-
}

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

Lines changed: 109 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import { workspaceFileFolder, workspaceFiles } from '@sim/db/schema'
33
import { createLogger } from '@sim/logger'
44
import { getPostgresErrorCode } from '@sim/utils/errors'
55
import { generateId } from '@sim/utils/id'
6-
import { and, asc, eq, inArray, isNull, min, sql } from 'drizzle-orm'
6+
import { and, asc, eq, inArray, isNull, min, type SQL, sql } from 'drizzle-orm'
77

88
const logger = createLogger('WorkspaceFileFolders')
99

@@ -50,6 +50,10 @@ interface RawWorkspaceFileFolder {
5050
updatedAt: Date
5151
}
5252

53+
interface WorkspaceFileFolderLockTx {
54+
execute(query: SQL): Promise<unknown>
55+
}
56+
5357
export interface WorkspaceFileArchiveResult {
5458
folders: number
5559
files: number
@@ -82,6 +86,15 @@ function fileFolderCondition(folderId?: string | null) {
8286
return normalized ? eq(workspaceFiles.folderId, normalized) : isNull(workspaceFiles.folderId)
8387
}
8488

89+
async function acquireWorkspaceFileFolderMutationLock(
90+
tx: WorkspaceFileFolderLockTx,
91+
workspaceId: string
92+
) {
93+
await tx.execute(
94+
sql`SELECT pg_advisory_xact_lock(hashtextextended(${`workspace_file_folders:${workspaceId}`}, 0))`
95+
)
96+
}
97+
8598
export function buildWorkspaceFileFolderPathMap(
8699
folders: Array<Pick<RawWorkspaceFileFolder, 'id' | 'name' | 'parentId'>>
87100
): Map<string, string> {
@@ -300,34 +313,38 @@ export async function createWorkspaceFileFolder(params: {
300313
parentId?: string | null
301314
sortOrder?: number
302315
}): Promise<WorkspaceFileFolderRecord> {
303-
const parentId = await assertWorkspaceFileFolderTarget(params.workspaceId, params.parentId)
304316
const name = normalizeWorkspaceFileItemName(params.name, 'Folder')
305317

306-
if (await workspaceFileFolderExists(params.workspaceId, name, parentId)) {
307-
throw new WorkspaceFileFolderConflictError(name)
308-
}
318+
const folder = await db.transaction(async (tx) => {
319+
await acquireWorkspaceFileFolderMutationLock(tx, params.workspaceId)
309320

310-
const id = generateId()
311-
let folder: RawWorkspaceFileFolder
312-
try {
313-
const [inserted] = await db
314-
.insert(workspaceFileFolder)
315-
.values({
316-
id,
317-
name,
318-
userId: params.userId,
319-
workspaceId: params.workspaceId,
320-
parentId,
321-
sortOrder: params.sortOrder ?? (await nextFolderSortOrder(params.workspaceId, parentId)),
322-
})
323-
.returning()
324-
folder = inserted
325-
} catch (error) {
326-
if (getPostgresErrorCode(error) === '23505') {
321+
const parentId = await assertWorkspaceFileFolderTarget(params.workspaceId, params.parentId)
322+
323+
if (await workspaceFileFolderExists(params.workspaceId, name, parentId)) {
327324
throw new WorkspaceFileFolderConflictError(name)
328325
}
329-
throw error
330-
}
326+
327+
const id = generateId()
328+
try {
329+
const [inserted] = await tx
330+
.insert(workspaceFileFolder)
331+
.values({
332+
id,
333+
name,
334+
userId: params.userId,
335+
workspaceId: params.workspaceId,
336+
parentId,
337+
sortOrder: params.sortOrder ?? (await nextFolderSortOrder(params.workspaceId, parentId)),
338+
})
339+
.returning()
340+
return inserted
341+
} catch (error) {
342+
if (getPostgresErrorCode(error) === '23505') {
343+
throw new WorkspaceFileFolderConflictError(name)
344+
}
345+
throw error
346+
}
347+
})
331348

332349
return mapFolderWithPath(params.workspaceId, folder)
333350
}
@@ -407,6 +424,31 @@ async function getDescendantFolderIds(
407424
return descendants
408425
}
409426

427+
function collectDescendantFolderIds(
428+
folders: Array<Pick<WorkspaceFileFolderRecord, 'id' | 'parentId'>>,
429+
folderId: string
430+
): string[] {
431+
const childrenByParent = new Map<string, string[]>()
432+
433+
for (const folder of folders) {
434+
if (!folder.parentId) continue
435+
const children = childrenByParent.get(folder.parentId) ?? []
436+
children.push(folder.id)
437+
childrenByParent.set(folder.parentId, children)
438+
}
439+
440+
const descendants: string[] = []
441+
const visit = (id: string) => {
442+
for (const childId of childrenByParent.get(id) ?? []) {
443+
descendants.push(childId)
444+
visit(childId)
445+
}
446+
}
447+
visit(folderId)
448+
449+
return descendants
450+
}
451+
410452
export async function updateWorkspaceFileFolder(params: {
411453
workspaceId: string
412454
folderId: string
@@ -611,13 +653,33 @@ export async function archiveWorkspaceFileFolderRecursive(
611653
workspaceId: string,
612654
folderId: string
613655
): Promise<WorkspaceFileArchiveResult> {
614-
const folder = await getWorkspaceFileFolder(workspaceId, folderId)
615-
if (!folder) throw new Error('Folder not found')
616-
617656
const now = new Date()
618-
const folderIds = [folderId, ...(await getDescendantFolderIds(workspaceId, folderId))]
619657

620658
return db.transaction(async (tx) => {
659+
await acquireWorkspaceFileFolderMutationLock(tx, workspaceId)
660+
661+
const [folder] = await tx
662+
.select({ id: workspaceFileFolder.id })
663+
.from(workspaceFileFolder)
664+
.where(
665+
and(
666+
eq(workspaceFileFolder.id, folderId),
667+
eq(workspaceFileFolder.workspaceId, workspaceId),
668+
isNull(workspaceFileFolder.deletedAt)
669+
)
670+
)
671+
.limit(1)
672+
673+
if (!folder) throw new Error('Folder not found')
674+
675+
const activeFolders = await tx
676+
.select({ id: workspaceFileFolder.id, parentId: workspaceFileFolder.parentId })
677+
.from(workspaceFileFolder)
678+
.where(
679+
and(eq(workspaceFileFolder.workspaceId, workspaceId), isNull(workspaceFileFolder.deletedAt))
680+
)
681+
const folderIds = [folderId, ...collectDescendantFolderIds(activeFolders, folderId)]
682+
621683
const archivedFiles = await tx
622684
.update(workspaceFiles)
623685
.set({ deletedAt: now, updatedAt: now })
@@ -662,14 +724,27 @@ export async function bulkArchiveWorkspaceFileItems(params: {
662724
const now = new Date()
663725
const explicitFileIds = Array.from(new Set(params.fileIds ?? []))
664726
const explicitFolderIds = Array.from(new Set(params.folderIds ?? []))
665-
const descendantFolderIds = (
666-
await Promise.all(
667-
explicitFolderIds.map((folderId) => getDescendantFolderIds(params.workspaceId, folderId))
668-
)
669-
).flat()
670-
const allFolderIds = Array.from(new Set([...explicitFolderIds, ...descendantFolderIds]))
671727

672728
return db.transaction(async (tx) => {
729+
await acquireWorkspaceFileFolderMutationLock(tx, params.workspaceId)
730+
731+
const activeFolders =
732+
explicitFolderIds.length > 0
733+
? await tx
734+
.select({ id: workspaceFileFolder.id, parentId: workspaceFileFolder.parentId })
735+
.from(workspaceFileFolder)
736+
.where(
737+
and(
738+
eq(workspaceFileFolder.workspaceId, params.workspaceId),
739+
isNull(workspaceFileFolder.deletedAt)
740+
)
741+
)
742+
: []
743+
const descendantFolderIds = explicitFolderIds.flatMap((folderId) =>
744+
collectDescendantFolderIds(activeFolders, folderId)
745+
)
746+
const allFolderIds = Array.from(new Set([...explicitFolderIds, ...descendantFolderIds]))
747+
673748
const archivedExplicitFiles =
674749
explicitFileIds.length > 0
675750
? await tx

0 commit comments

Comments
 (0)