Skip to content

Commit 02f381d

Browse files
feat(pptx): replace viewer with custom preview (#4536)
* feat(pptx): replace viewer with custom preview * address comments * address comments * address bugbot * address comment * rm bun lock * resolve conflict * update credit comment * address comments * rm bun lock * resolve conflict * make previews consistent for zoom and scroll * zoom fix
1 parent c7130c6 commit 02f381d

58 files changed

Lines changed: 22737 additions & 482 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

apps/sim/app/(auth)/signup/signup-form.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -271,7 +271,7 @@ function SignupFormContent({ githubAvailable, googleAvailable, isProduction }: S
271271
...(token ? { 'x-captcha-response': token } : {}),
272272
},
273273
onError: (ctx) => {
274-
logger.error('Signup error:', ctx.error)
274+
logger.warn('Signup error:', ctx.error)
275275
const errorMessage: string[] = ['Failed to create account']
276276

277277
let errorCode = 'unknown'

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

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,7 @@ vi.mock('@/app/api/files/authorization', () => ({
6969
vi.mock('@/lib/uploads', () => ({
7070
getStorageProvider: mockGetStorageProvider,
7171
isUsingCloudStorage: mockIsUsingCloudStorage,
72+
StorageService: storageServiceMock,
7273
}))
7374

7475
vi.mock('@/lib/file-parsers', () => ({
@@ -172,6 +173,7 @@ describe('File Parse API Route', () => {
172173

173174
permissionsMockFns.mockGetUserEntityPermissions.mockResolvedValue({ canView: true })
174175
storageServiceMockFns.mockHasCloudStorage.mockReturnValue(true)
176+
storageServiceMockFns.mockDownloadFile.mockResolvedValue(Buffer.from('test file content'))
175177
mockIsSupportedFileType.mockReturnValue(true)
176178
mockParseFile.mockResolvedValue({
177179
content: 'parsed content',
@@ -245,6 +247,48 @@ describe('File Parse API Route', () => {
245247
}
246248
})
247249

250+
it('should keep known binary extensions as binary even when the bytes are valid UTF-8', async () => {
251+
setupFileApiMocks({
252+
cloudEnabled: true,
253+
storageProvider: 's3',
254+
authenticated: true,
255+
})
256+
mockIsSupportedFileType.mockReturnValue(false)
257+
storageServiceMockFns.mockDownloadFile.mockResolvedValue(Buffer.from('valid utf8 bytes'))
258+
259+
const req = createMockRequest('POST', {
260+
filePath: '/api/files/serve/execution/workspace-1/workflow-1/execution-1/image.png',
261+
})
262+
263+
const response = await POST(req)
264+
const data = await response.json()
265+
266+
expect(response.status).toBe(200)
267+
expect(data.success).toBe(true)
268+
expect(data.output.content).toBe('[Binary PNG file - 16 bytes]')
269+
})
270+
271+
it('should parse unknown extensions as text when the bytes look like UTF-8 text', async () => {
272+
setupFileApiMocks({
273+
cloudEnabled: true,
274+
storageProvider: 's3',
275+
authenticated: true,
276+
})
277+
mockIsSupportedFileType.mockReturnValue(false)
278+
storageServiceMockFns.mockDownloadFile.mockResolvedValue(Buffer.from('plain text content'))
279+
280+
const req = createMockRequest('POST', {
281+
filePath: '/api/files/serve/execution/workspace-1/workflow-1/execution-1/readme.customtext',
282+
})
283+
284+
const response = await POST(req)
285+
const data = await response.json()
286+
287+
expect(response.status).toBe(200)
288+
expect(data.success).toBe(true)
289+
expect(data.output.content).toBe('plain text content')
290+
})
291+
248292
it('should handle multiple files', async () => {
249293
setupFileApiMocks({
250294
cloudEnabled: false,

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

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { Buffer } from 'buffer'
1+
import { Buffer, isUtf8 } from 'buffer'
22
import { createHash } from 'crypto'
33
import fsPromises, { readFile } from 'fs/promises'
44
import path from 'path'
@@ -39,6 +39,11 @@ const logger = createLogger('FilesParseAPI')
3939

4040
const MAX_DOWNLOAD_SIZE_BYTES = 100 * 1024 * 1024 // 100 MB
4141
const DOWNLOAD_TIMEOUT_MS = 30000 // 30 seconds
42+
const BINARY_EXTENSIONS = new Set<string>(binaryExtensionsList)
43+
44+
function isLikelyTextBuffer(fileBuffer: Buffer): boolean {
45+
return isUtf8(fileBuffer) && !fileBuffer.includes(0)
46+
}
4247

4348
interface ExecutionContext {
4449
workspaceId: string
@@ -863,10 +868,11 @@ function handleGenericBuffer(
863868
extension: string,
864869
fileType?: string
865870
): ParseResult {
866-
const isBinary = binaryExtensionsList.includes(extension)
867-
const content = isBinary
868-
? `[Binary ${extension.toUpperCase()} file - ${fileBuffer.length} bytes]`
869-
: fileBuffer.toString('utf-8')
871+
const normalizedExtension = extension.toLowerCase()
872+
const content =
873+
!BINARY_EXTENSIONS.has(normalizedExtension) && isLikelyTextBuffer(fileBuffer)
874+
? fileBuffer.toString('utf-8')
875+
: `[Binary ${normalizedExtension.toUpperCase()} file - ${fileBuffer.length} bytes]`
870876

871877
return {
872878
success: true,

0 commit comments

Comments
 (0)