Skip to content

Commit 235f074

Browse files
waleedlatif1icecrasher321claude
authored
feat(files): expand file editor to support more formats, add docx/xlsx preview (#3971)
* feat(files): expand file editor to support more formats, add docx/xlsx preview * lint * fix(files): narrow fileData type for closure in docx/xlsx preview effects * fix(files): address PR review — fix xlsx type, simplify error helper, tighten iframe sandbox * add mothership read externsions * fix(files): update upload test — js is now a supported extension * fix(files): deduplicate code extensions, handle dotless filenames * fix(files): lower xlsx preview row cap to 1k and type workbookRef properly Reduces XLSX_MAX_ROWS from 10,000 to 1,000 to prevent browser sluggishness on large spreadsheets. Types workbookRef with the proper xlsx.WorkBook interface instead of unknown, removing the unsafe cast. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * refactor(files): extract shared DataTable, isolate client-safe constants - Move SUPPORTED_CODE_EXTENSIONS to validation-constants.ts so client components no longer transitively import Node's `path` module - Extract shared DataTable component used by both CsvPreview and XlsxPreview, eliminating duplicated table markup Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * refactor(validation): remove Node path import, use plain string extraction Replace `import path from 'path'` with a simple `extractExtension` helper that does `fileName.slice(fileName.lastIndexOf('.') + 1)`. This removes the only Node module dependency from validation.ts, making it safe to import from client components without pulling in a Node polyfill. Deletes the unnecessary validation-constants.ts that was introduced as a workaround — the constants now live back in validation.ts where they belong. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * lint Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> --------- Co-authored-by: Vikhyath Mondreti <vikhyath@simstudio.ai> Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
1 parent ebc1948 commit 235f074

File tree

7 files changed

+373
-61
lines changed

7 files changed

+373
-61
lines changed

apps/sim/app/api/files/upload/route.test.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -458,10 +458,10 @@ describe('File Upload Security Tests', () => {
458458
expect(response.status).toBe(200)
459459
})
460460

461-
it('should reject JavaScript files', async () => {
461+
it('should reject unsupported file types', async () => {
462462
const formData = new FormData()
463-
const maliciousJs = 'alert("XSS")'
464-
const file = new File([maliciousJs], 'malicious.js', { type: 'application/javascript' })
463+
const content = 'binary data'
464+
const file = new File([content], 'archive.exe', { type: 'application/octet-stream' })
465465
formData.append('file', file)
466466
formData.append('context', 'workspace')
467467
formData.append('workspaceId', 'test-workspace-id')
@@ -475,7 +475,7 @@ describe('File Upload Security Tests', () => {
475475

476476
expect(response.status).toBe(400)
477477
const data = await response.json()
478-
expect(data.message).toContain("File type 'js' is not allowed")
478+
expect(data.message).toContain("File type 'exe' is not allowed")
479479
})
480480

481481
it('should reject files without extensions', async () => {

apps/sim/app/api/files/upload/route.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import { generateWorkspaceFileKey } from '@/lib/uploads/contexts/workspace/works
88
import { isImageFileType } from '@/lib/uploads/utils/file-utils'
99
import {
1010
SUPPORTED_AUDIO_EXTENSIONS,
11+
SUPPORTED_CODE_EXTENSIONS,
1112
SUPPORTED_DOCUMENT_EXTENSIONS,
1213
SUPPORTED_VIDEO_EXTENSIONS,
1314
validateFileType,
@@ -23,6 +24,7 @@ const IMAGE_EXTENSIONS = ['png', 'jpg', 'jpeg', 'gif', 'webp', 'svg'] as const
2324

2425
const ALLOWED_EXTENSIONS = new Set<string>([
2526
...SUPPORTED_DOCUMENT_EXTENSIONS,
27+
...SUPPORTED_CODE_EXTENSIONS,
2628
...IMAGE_EXTENSIONS,
2729
...SUPPORTED_AUDIO_EXTENSIONS,
2830
...SUPPORTED_VIDEO_EXTENSIONS,
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
import { memo } from 'react'
2+
3+
interface DataTableProps {
4+
headers: string[]
5+
rows: string[][]
6+
}
7+
8+
export const DataTable = memo(function DataTable({ headers, rows }: DataTableProps) {
9+
return (
10+
<div className='overflow-x-auto rounded-md border border-[var(--border)]'>
11+
<table className='w-full border-collapse text-[13px]'>
12+
<thead className='bg-[var(--surface-2)]'>
13+
<tr>
14+
{headers.map((header, i) => (
15+
<th
16+
key={i}
17+
className='whitespace-nowrap px-3 py-2 text-left font-semibold text-[12px] text-[var(--text-primary)]'
18+
>
19+
{String(header ?? '')}
20+
</th>
21+
))}
22+
</tr>
23+
</thead>
24+
<tbody>
25+
{rows.map((row, ri) => (
26+
<tr key={ri} className='border-[var(--border)] border-t'>
27+
{headers.map((_, ci) => (
28+
<td key={ci} className='whitespace-nowrap px-3 py-2 text-[var(--text-secondary)]'>
29+
{String(row[ci] ?? '')}
30+
</td>
31+
))}
32+
</tr>
33+
))}
34+
</tbody>
35+
</table>
36+
</div>
37+
)
38+
})

0 commit comments

Comments
 (0)