From db20421eca8319fcd373ff9ac23bfe0a61d7f4c0 Mon Sep 17 00:00:00 2001 From: waleed Date: Tue, 30 Jun 2026 17:12:35 -0700 Subject: [PATCH] fix(input-format): file-field mode toggle uses canonical arrow icon on the label row The file field's mode switch was a right-aligned 'Enter JSON manually' text link on its own row, causing awkward spacing above the control. Replace it with the canonical sub-block mode toggle: a compact left-right arrows (ArrowLeftRight) icon button with a tooltip, placed on the 'Value' label row (label left, toggle right), matching the Files subblock header. Removes the extra row and aligns spacing. --- .../components/starter/input-format.tsx | 162 +++++++++++------- 1 file changed, 98 insertions(+), 64 deletions(-) diff --git a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/editor/components/sub-block/components/starter/input-format.tsx b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/editor/components/sub-block/components/starter/input-format.tsx index 06b0b586ba8..25324d61f91 100644 --- a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/editor/components/sub-block/components/starter/input-format.tsx +++ b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/editor/components/sub-block/components/starter/input-format.tsx @@ -15,9 +15,10 @@ import { Input, Label, languages, + Tooltip, } from '@sim/emcn' import { Trash } from '@sim/emcn/icons' -import { Plus } from 'lucide-react' +import { ArrowLeftRight, Plus } from 'lucide-react' import Editor from 'react-simple-code-editor' import { createDefaultInputFormatField, @@ -141,6 +142,59 @@ export function FieldFormat({ const renderFieldLabel = (label: string) => + /** + * Resolves the current editor mode for a file field. The uploader is only + * offered when it can represent the stored value losslessly (empty or all + * run-ready); mixed/legacy values force JSON mode so the uploader can't drop + * entries it cannot show on save. + */ + const getFileFieldMode = (field: Field): { mode: 'upload' | 'json'; canUseUploader: boolean } => { + const canUseUploader = defaultFileFieldMode(field.value) === 'upload' + return { + mode: canUseUploader ? (fileFieldModes[field.id] ?? 'upload') : 'json', + canUseUploader, + } + } + + /** + * Renders the ⇄ toggle that switches a file field between the uploader and the + * raw JSON editor. Matches the canonical sub-block mode toggle. Hidden when the + * value can't be safely represented by the uploader. + */ + const renderFileModeToggle = (field: Field) => { + const { mode, canUseUploader } = getFileFieldMode(field) + if (!canUseUploader) return null + const label = mode === 'upload' ? 'Switch to JSON' : 'Switch to file uploader' + return ( + + + + + +

{label}

+
+
+ ) + } + /** * Adds a new field to the list */ @@ -493,52 +547,28 @@ export function FieldFormat({ } if (isFileFieldType(field.type)) { - // The uploader is only offered when it can represent the stored value - // losslessly (empty or all run-ready). For mixed/legacy values it would - // drop the entries it can't show on save, so we force JSON mode and hide - // the toggle until the value is cleared or made fully run-ready. - const canUseUploader = defaultFileFieldMode(field.value) === 'upload' - const mode = canUseUploader ? (fileFieldModes[field.id] ?? 'upload') : 'json' - - const modeToggle = canUseUploader ? ( -
- -
- ) : null + // The mode toggle lives on the "Value" label row (see the field header); + // this only renders the active control. Mode derivation is shared via + // getFileFieldMode so the two stay in sync. + const { mode } = getFileFieldMode(field) if (mode === 'upload') { const currentFiles = parseInputFormatFiles(field.value) return ( -
- {modeToggle} - - updateField( - field.id, - 'value', - serializeInputFormatFiles(controlValueToFiles(next, currentFiles)) - ) - } - /> -
+ + updateField( + field.id, + 'value', + serializeInputFormatFiles(controlValueToFiles(next, currentFiles)) + ) + } + /> ) } @@ -556,26 +586,23 @@ export function FieldFormat({ )) return ( -
- {modeToggle} - - {renderLineNumbers()} - - - { - '[\n {\n "data": "",\n "type": "file",\n "name": "document.pdf",\n "mime": "application/pdf"\n }\n]' - } - - - - -
+ + {renderLineNumbers()} + + + { + '[\n {\n "data": "",\n "type": "file",\n "name": "document.pdf",\n "mime": "application/pdf"\n }\n]' + } + + + + ) } @@ -709,7 +736,14 @@ export function FieldFormat({ {showValue && (
- {renderFieldLabel('Value')} + {isFileFieldType(field.type) ? ( +
+ {renderFieldLabel('Value')} + {renderFileModeToggle(field)} +
+ ) : ( + renderFieldLabel('Value') + )}
{renderValueInput(field)}
)}