Skip to content

Commit 8fa13aa

Browse files
icecrasher321waleedlatif1
authored andcommitted
perf improvements
1 parent f36d0de commit 8fa13aa

4 files changed

Lines changed: 113 additions & 6 deletions

File tree

apps/sim/app/api/workspaces/[id]/files/download/route.ts

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,12 @@ import {
1010
listWorkspaceFileFolders,
1111
listWorkspaceFiles,
1212
} from '@/lib/uploads/contexts/workspace'
13+
import { formatFileSize } from '@/lib/uploads/utils/file-utils'
1314
import { verifyWorkspaceMembership } from '@/app/api/workflows/utils'
1415

1516
const logger = createLogger('WorkspaceFilesDownloadAPI')
17+
const MAX_ZIP_DOWNLOAD_FILES = 100
18+
const MAX_ZIP_DOWNLOAD_BYTES = 250 * 1024 * 1024
1619

1720
function safeZipPath(path: string): string {
1821
return path
@@ -76,6 +79,25 @@ export const GET = withRouteHandler(
7679
return NextResponse.json({ error: 'No files selected for download' }, { status: 400 })
7780
}
7881

82+
if (filesToZip.length > MAX_ZIP_DOWNLOAD_FILES) {
83+
return NextResponse.json(
84+
{
85+
error: `Too many files selected for download. Select ${MAX_ZIP_DOWNLOAD_FILES} or fewer files.`,
86+
},
87+
{ status: 413 }
88+
)
89+
}
90+
91+
const totalBytes = filesToZip.reduce((sum, file) => sum + file.size, 0)
92+
if (totalBytes > MAX_ZIP_DOWNLOAD_BYTES) {
93+
return NextResponse.json(
94+
{
95+
error: `Selected files total ${formatFileSize(totalBytes)}, which exceeds the ${formatFileSize(MAX_ZIP_DOWNLOAD_BYTES)} download limit.`,
96+
},
97+
{ status: 413 }
98+
)
99+
}
100+
79101
const zip = new JSZip()
80102
const usedPaths = new Set<string>()
81103
for (const file of filesToZip) {

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

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -414,6 +414,14 @@ export function Files() {
414414
owner: ownerCell(file.uploadedBy, members),
415415
updated: timeCell(file.updatedAt),
416416
},
417+
sortValues: {
418+
name: file.name,
419+
size: file.size,
420+
type: formatFileType(file.type, file.name),
421+
created: new Date(file.uploadedAt).getTime(),
422+
updated: new Date(file.updatedAt).getTime(),
423+
owner: members?.find((m) => m.userId === file.uploadedBy)?.name ?? '',
424+
},
417425
}
418426
return row
419427
})

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

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -217,6 +217,37 @@ async function mapFolderWithPath(
217217
return mapFolder(folder, new Map([[folder.id, path]]))
218218
}
219219

220+
export async function getWorkspaceFileFolderPath(
221+
workspaceId: string,
222+
folderId: string,
223+
options?: { includeDeleted?: boolean }
224+
): Promise<string | null> {
225+
const folder = await getRawWorkspaceFileFolder(workspaceId, folderId, options)
226+
return folder ? buildWorkspaceFileFolderPath(workspaceId, folder, options) : null
227+
}
228+
229+
export async function findWorkspaceFileFolderIdByPath(
230+
workspaceId: string,
231+
pathSegments: string[]
232+
): Promise<string | null> {
233+
let parentId: string | null = null
234+
235+
for (const rawSegment of pathSegments) {
236+
let name: string
237+
try {
238+
name = normalizeWorkspaceFileItemName(rawSegment, 'Folder')
239+
} catch {
240+
return null
241+
}
242+
243+
const folder = await findRawWorkspaceFileFolderByName(workspaceId, name, parentId)
244+
if (!folder) return null
245+
parentId = folder.id
246+
}
247+
248+
return parentId
249+
}
250+
220251
export async function listWorkspaceFileFolders(
221252
workspaceId: string,
222253
options?: { scope?: WorkspaceFileFolderScope }

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

Lines changed: 52 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,8 @@ import {
3333
assertWorkspaceFileFolderTarget,
3434
buildWorkspaceFileFolderPathMap,
3535
fileNameExistsInWorkspaceFolder,
36+
findWorkspaceFileFolderIdByPath,
37+
getWorkspaceFileFolderPath,
3638
listWorkspaceFileFolders,
3739
normalizeWorkspaceFileItemName,
3840
} from './workspace-file-folder-manager'
@@ -565,6 +567,24 @@ function mapWorkspaceFileRecord(
565567
}
566568
}
567569

570+
async function mapSingleWorkspaceFileRecord(
571+
file: typeof workspaceFiles.$inferSelect,
572+
workspaceId: string
573+
): Promise<WorkspaceFileRecord> {
574+
if (!file.folderId) {
575+
return mapWorkspaceFileRecord(file, workspaceId, new Map())
576+
}
577+
578+
const folderPath = await getWorkspaceFileFolderPath(workspaceId, file.folderId, {
579+
includeDeleted: true,
580+
})
581+
return mapWorkspaceFileRecord(
582+
file,
583+
workspaceId,
584+
folderPath ? new Map([[file.folderId, folderPath]]) : new Map()
585+
)
586+
}
587+
568588
/**
569589
* Look up a single active workspace file by its original name.
570590
* Returns the record if found, or null if no matching file exists.
@@ -592,9 +612,7 @@ export async function getWorkspaceFileByName(
592612

593613
if (files.length === 0) return null
594614

595-
const folders = await listWorkspaceFileFolders(workspaceId, { scope: 'all' })
596-
const folderPaths = buildWorkspaceFileFolderPathMap(folders)
597-
return mapWorkspaceFileRecord(files[0], workspaceId, folderPaths)
615+
return mapSingleWorkspaceFileRecord(files[0], workspaceId)
598616
}
599617

600618
/**
@@ -728,13 +746,43 @@ export function findWorkspaceFileRecord(
728746
return files.find((file) => normalizeVfsSegment(file.name) === segmentKey) ?? null
729747
}
730748

749+
async function getWorkspaceFileByExactReference(
750+
workspaceId: string,
751+
fileReference: string
752+
): Promise<WorkspaceFileRecord | null> {
753+
const segments = fileReference
754+
.split('/')
755+
.map((segment) => segment.trim())
756+
.filter(Boolean)
757+
758+
if (segments.length === 0) return null
759+
if (segments.length === 1) {
760+
return getWorkspaceFileByName(workspaceId, segments[0], { folderId: null })
761+
}
762+
763+
const folderId = await findWorkspaceFileFolderIdByPath(workspaceId, segments.slice(0, -1))
764+
return folderId ? getWorkspaceFileByName(workspaceId, segments.at(-1) ?? '', { folderId }) : null
765+
}
766+
731767
/**
732768
* Resolve a workspace file record from either its id or a VFS/name reference.
733769
*/
734770
export async function resolveWorkspaceFileReference(
735771
workspaceId: string,
736772
fileReference: string
737773
): Promise<WorkspaceFileRecord | null> {
774+
const normalizedReference = normalizeWorkspaceFileReference(fileReference)
775+
if (normalizedReference.startsWith('wf_')) {
776+
const file = await getWorkspaceFile(workspaceId, normalizedReference)
777+
if (file) return file
778+
}
779+
780+
const exactReferenceFile = await getWorkspaceFileByExactReference(
781+
workspaceId,
782+
normalizedReference
783+
)
784+
if (exactReferenceFile) return exactReferenceFile
785+
738786
const files = await listWorkspaceFiles(workspaceId)
739787
return findWorkspaceFileRecord(files, fileReference)
740788
}
@@ -770,9 +818,7 @@ export async function getWorkspaceFile(
770818

771819
if (files.length === 0) return null
772820

773-
const folders = await listWorkspaceFileFolders(workspaceId, { scope: 'all' })
774-
const folderPaths = buildWorkspaceFileFolderPathMap(folders)
775-
return mapWorkspaceFileRecord(files[0], workspaceId, folderPaths)
821+
return mapSingleWorkspaceFileRecord(files[0], workspaceId)
776822
} catch (error) {
777823
logger.error(`Failed to get workspace file ${fileId}:`, error)
778824
return null

0 commit comments

Comments
 (0)