Skip to content

Commit 7f490d5

Browse files
committed
fix(input-format): require file key, keep mixed/partial values in JSON mode
Addresses review round 2 (Greptile P1 + Cursor): - parseInputFormatFiles now requires a non-empty key (the uploader always sets one); an external/signed URL with no recoverable key no longer opens uploader mode or reaches workflowInput.files only to be rejected. - defaultFileFieldMode uses the uploader only when EVERY entry is run-ready; a mixed array with any legacy/partial entry stays in JSON mode so the uploader can't drop the entries it can't represent on the next save.
1 parent 8812340 commit 7f490d5

4 files changed

Lines changed: 21 additions & 3 deletions

File tree

apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/editor/components/sub-block/components/starter/input-format-files.test.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,4 +105,8 @@ describe('defaultFileFieldMode', () => {
105105
expect(defaultFileFieldMode('[{"data":"<base64>","name":"x.pdf"}]')).toBe('json')
106106
expect(defaultFileFieldMode('{"csv":"a,b,c"}')).toBe('json')
107107
})
108+
109+
it.concurrent('uses json when only some entries are run-ready (no silent drop)', () => {
110+
expect(defaultFileFieldMode(JSON.stringify([file, { name: 'legacy-only' }]))).toBe('json')
111+
})
108112
})

apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/editor/components/sub-block/components/starter/input-format-files.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,5 +67,9 @@ export function defaultFileFieldMode(value: string | undefined): 'upload' | 'jso
6767
return 'json'
6868
}
6969
if (!Array.isArray(parsed)) return 'json'
70-
return parsed.length === 0 || parseInputFormatFiles(parsed).length > 0 ? 'upload' : 'json'
70+
if (parsed.length === 0) return 'upload'
71+
// Only use the uploader when EVERY entry is run-ready; if any entry is legacy
72+
// or partial, stay in JSON mode so the uploader can't drop the entries it
73+
// cannot represent when the field is next saved.
74+
return parseInputFormatFiles(parsed).length === parsed.length ? 'upload' : 'json'
7175
}

apps/sim/lib/workflows/input-format.test.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -299,6 +299,12 @@ describe('parseInputFormatFiles', () => {
299299
)
300300
).toEqual([])
301301
})
302+
303+
it.concurrent('rejects files without a usable key', () => {
304+
const { key, ...noKey } = file
305+
expect(parseInputFormatFiles(JSON.stringify([noKey]))).toEqual([])
306+
expect(parseInputFormatFiles(JSON.stringify([{ ...file, key: '' }]))).toEqual([])
307+
})
302308
})
303309

304310
describe('collectInputFormatFiles', () => {

apps/sim/lib/workflows/input-format.ts

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -85,12 +85,16 @@ export function parseInputFormatFiles(value: unknown): InputFormatFile[] {
8585
if (file === null || typeof file !== 'object') return false
8686
const f = file as InputFormatFile
8787
// Require the full run-ready shape the executor's normalizeStartFile needs,
88-
// so a partial object never opens in uploader mode or reaches the files
89-
// channel only to be rejected (which would silently drop every file).
88+
// including a usable `key` (the uploader always sets one), so a partial
89+
// object or an external/signed URL never opens in uploader mode or reaches
90+
// the files channel only to be rejected — which would silently drop every
91+
// file. Anything short of this falls back to the JSON editor.
9092
return (
9193
typeof f.id === 'string' &&
9294
typeof f.name === 'string' &&
9395
typeof f.url === 'string' &&
96+
typeof f.key === 'string' &&
97+
f.key.length > 0 &&
9498
typeof f.size === 'number' &&
9599
Number.isFinite(f.size) &&
96100
typeof f.type === 'string'

0 commit comments

Comments
 (0)