From 27791ac12111cb4b2989fd19bf46f980a24080b3 Mon Sep 17 00:00:00 2001 From: Joel Date: Mon, 20 Apr 2026 08:53:18 +0800 Subject: [PATCH] chore: file type not show hidden --- .../__tests__/form-fields.spec.tsx | 21 +++++++---- .../__tests__/index-logic.spec.tsx | 4 +- .../config-modal/__tests__/utils.spec.ts | 20 ++++++++++ .../config-var/config-modal/form-fields.tsx | 37 ++++++++++--------- .../config-var/config-modal/utils.ts | 35 ++++++++++-------- 5 files changed, 77 insertions(+), 40 deletions(-) diff --git a/web/app/components/app/configuration/config-var/config-modal/__tests__/form-fields.spec.tsx b/web/app/components/app/configuration/config-var/config-modal/__tests__/form-fields.spec.tsx index 1ce6a4d0e5..91fc828c2f 100644 --- a/web/app/components/app/configuration/config-var/config-modal/__tests__/form-fields.spec.tsx +++ b/web/app/components/app/configuration/config-var/config-modal/__tests__/form-fields.spec.tsx @@ -166,6 +166,12 @@ describe('ConfigModalFormFields', () => { }) it('should wire file, json schema, and visibility controls', () => { + const textInputProps = createBaseProps() + const textInputView = render() + expect(screen.getByText('variableConfig.hidden')).toBeInTheDocument() + expect(screen.getByText('variableConfig.hiddenDescription')).toBeInTheDocument() + textInputView.unmount() + const singleFileProps = createBaseProps() singleFileProps.tempPayload = { ...singleFileProps.tempPayload, @@ -174,20 +180,20 @@ describe('ConfigModalFormFields', () => { allowed_file_extensions: [], allowed_file_upload_methods: ['remote_url'], } - render() - expect(screen.getByText('variableConfig.hidden')).toBeInTheDocument() - expect(screen.getByText('variableConfig.hiddenDescription')).toBeInTheDocument() + const singleFileView = render() + expect(screen.queryByText('variableConfig.hidden')).not.toBeInTheDocument() + expect(screen.queryByText('variableConfig.hiddenDescription')).not.toBeInTheDocument() fireEvent.click(screen.getByText('single-file-setting')) fireEvent.click(screen.getByText('upload-file')) - fireEvent.click(screen.getAllByText('unchecked')[0]) - fireEvent.click(screen.getAllByText('unchecked')[1]) + fireEvent.click(screen.getByText('unchecked')) expect(singleFileProps.onFilePayloadChange).toHaveBeenCalledWith({ number_limits: 1 }) expect(singleFileProps.payloadChangeHandlers.default).toHaveBeenCalledWith(expect.objectContaining({ fileId: 'file-1', })) expect(singleFileProps.payloadChangeHandlers.required).toHaveBeenCalledWith(true) - expect(singleFileProps.payloadChangeHandlers.hide).toHaveBeenCalledWith(true) + expect(singleFileProps.payloadChangeHandlers.hide).not.toHaveBeenCalled() + singleFileView.unmount() const multiFileProps = createBaseProps() multiFileProps.tempPayload = { @@ -198,8 +204,9 @@ describe('ConfigModalFormFields', () => { allowed_file_upload_methods: ['remote_url'], } render() + expect(screen.queryByText('variableConfig.hidden')).not.toBeInTheDocument() fireEvent.click(screen.getByText('multi-file-setting')) - fireEvent.click(screen.getAllByText('upload-file')[1]) + fireEvent.click(screen.getByText('upload-file')) expect(multiFileProps.onFilePayloadChange).toHaveBeenCalledWith({ number_limits: 3 }) expect(multiFileProps.payloadChangeHandlers.default).toHaveBeenCalledWith([ expect.objectContaining({ fileId: 'file-1' }), diff --git a/web/app/components/app/configuration/config-var/config-modal/__tests__/index-logic.spec.tsx b/web/app/components/app/configuration/config-var/config-modal/__tests__/index-logic.spec.tsx index 4888d284d2..fccd48725e 100644 --- a/web/app/components/app/configuration/config-var/config-modal/__tests__/index-logic.spec.tsx +++ b/web/app/components/app/configuration/config-var/config-modal/__tests__/index-logic.spec.tsx @@ -25,6 +25,7 @@ vi.mock('../form-fields', () => ({ return (
{String(props.tempPayload.type)}
+
{String(props.tempPayload.hide)}
{String(props.tempPayload.label ?? '')}
{String(props.tempPayload.json_schema ?? '')}
{String(props.tempPayload.default ?? '')}
@@ -115,7 +116,7 @@ describe('ConfigModal logic', () => { }) it('should derive payload fields from mocked form-field callbacks', async () => { - renderConfigModal() + renderConfigModal(createPayload({ hide: true })) fireEvent.click(screen.getByTestId('valid-key-blur')) await waitFor(() => { @@ -138,6 +139,7 @@ describe('ConfigModal logic', () => { fireEvent.click(screen.getByTestId('type-change')) await waitFor(() => { expect(screen.getByTestId('payload-type')).toHaveTextContent(InputVarType.singleFile) + expect(screen.getByTestId('payload-hide')).toHaveTextContent('false') }) fireEvent.click(screen.getByTestId('file-payload-change')) diff --git a/web/app/components/app/configuration/config-var/config-modal/__tests__/utils.spec.ts b/web/app/components/app/configuration/config-var/config-modal/__tests__/utils.spec.ts index 1c00e1c5b2..2317868004 100644 --- a/web/app/components/app/configuration/config-var/config-modal/__tests__/utils.spec.ts +++ b/web/app/components/app/configuration/config-var/config-modal/__tests__/utils.spec.ts @@ -49,11 +49,13 @@ describe('config-modal utils', () => { const payload = createInputVar({ type: InputVarType.textInput, default: 'hello', + hide: true, }) const nextPayload = createPayloadForType(payload, InputVarType.multiFiles) expect(nextPayload.type).toBe(InputVarType.multiFiles) + expect(nextPayload.hide).toBe(false) expect(nextPayload.max_length).toBe(DEFAULT_FILE_UPLOAD_SETTING.max_length) expect(nextPayload.allowed_file_types).toEqual(DEFAULT_FILE_UPLOAD_SETTING.allowed_file_types) expect(nextPayload.default).toBe('hello') @@ -249,6 +251,24 @@ describe('config-modal utils', () => { }) }) + it('should force file inputs to stay visible when saving', () => { + const result = validateConfigModalPayload({ + tempPayload: createInputVar({ + type: InputVarType.singleFile, + hide: true, + allowed_file_types: [SupportUploadFileTypes.document], + allowed_file_extensions: [], + }), + payload: createInputVar(), + checkVariableName: () => true, + t, + }) + + expect(result.payloadToSave).toEqual(expect.objectContaining({ + hide: false, + })) + }) + it('should stop validation when the variable name checker rejects the payload', () => { const result = validateConfigModalPayload({ tempPayload: createInputVar({ diff --git a/web/app/components/app/configuration/config-var/config-modal/form-fields.tsx b/web/app/components/app/configuration/config-var/config-modal/form-fields.tsx index 1aa12320aa..de0a96ce02 100644 --- a/web/app/components/app/configuration/config-var/config-modal/form-fields.tsx +++ b/web/app/components/app/configuration/config-var/config-modal/form-fields.tsx @@ -68,6 +68,7 @@ const ConfigModalFormFields: FC = ({ t, }) => { const { type, label, variable } = tempPayload + const isFileInput = [InputVarType.singleFile, InputVarType.multiFiles].includes(type) return (
@@ -174,7 +175,7 @@ const ConfigModalFormFields: FC = ({ )} - {[InputVarType.singleFile, InputVarType.multiFiles].includes(type) && ( + {isFileInput && ( <> = ({ )}
- onPayloadChange('required')(!tempPayload.required)} /> + onPayloadChange('required')(!tempPayload.required)} /> {t('variableConfig.required', { ns: 'appDebug' })}
-
- onPayloadChange('hide')(!tempPayload.hide)} /> -
- {t('variableConfig.hidden', { ns: 'appDebug' })} - - -
- -
-
- - {t('variableConfig.hiddenDescription', { ns: 'appDebug' })} - -
+ {!isFileInput && ( +
+ onPayloadChange('hide')(!tempPayload.hide)} /> +
+ {t('variableConfig.hidden', { ns: 'appDebug' })} + + +
+ +
+
+ + {t('variableConfig.hiddenDescription', { ns: 'appDebug' })} + +
+
-
+ )}
) } diff --git a/web/app/components/app/configuration/config-var/config-modal/utils.ts b/web/app/components/app/configuration/config-var/config-modal/utils.ts index fdc0ac3501..e24e4b6593 100644 --- a/web/app/components/app/configuration/config-var/config-modal/utils.ts +++ b/web/app/components/app/configuration/config-var/config-modal/utils.ts @@ -88,7 +88,9 @@ export const createPayloadForType = (payload: InputVar, type: InputVarType) => { draft.default = undefined if ([InputVarType.singleFile, InputVarType.multiFiles].includes(type)) { - (Object.keys(DEFAULT_FILE_UPLOAD_SETTING) as Array).forEach((key) => { + draft.hide = false + const fileUploadSettingKeys = Object.keys(DEFAULT_FILE_UPLOAD_SETTING) as Array + fileUploadSettingKeys.forEach((key) => { if (key !== 'max_length') draft[key] = DEFAULT_FILE_UPLOAD_SETTING[key] as never }) @@ -158,38 +160,41 @@ export const validateConfigModalPayload = ({ checkVariableName, t, }: ValidateConfigModalPayloadOptions): ValidateConfigModalPayloadResult => { + const normalizedTempPayload = [InputVarType.singleFile, InputVarType.multiFiles].includes(tempPayload.type) + ? { ...tempPayload, hide: false } + : tempPayload const jsonSchemaValue = tempPayload.json_schema const schemaEmpty = isJsonSchemaEmpty(jsonSchemaValue) const normalizedJsonSchema = schemaEmpty ? undefined : jsonSchemaValue - const payloadToSave = tempPayload.type === InputVarType.jsonObject && schemaEmpty - ? { ...tempPayload, json_schema: undefined } - : tempPayload + const payloadToSave = normalizedTempPayload.type === InputVarType.jsonObject && schemaEmpty + ? { ...normalizedTempPayload, json_schema: undefined } + : normalizedTempPayload - const moreInfo = tempPayload.variable === payload?.variable + const moreInfo = normalizedTempPayload.variable === payload?.variable ? undefined : { type: ChangeType.changeVarName, - payload: { beforeKey: payload?.variable || '', afterKey: tempPayload.variable }, + payload: { beforeKey: payload?.variable || '', afterKey: normalizedTempPayload.variable }, } - if (!checkVariableName(tempPayload.variable)) + if (!checkVariableName(normalizedTempPayload.variable)) return {} - if (!tempPayload.label) { + if (!normalizedTempPayload.label) { return { errorMessage: t('variableConfig.errorMsg.labelNameRequired', { ns: 'appDebug' }), } } - if (tempPayload.type === InputVarType.select) { - if (!tempPayload.options?.length) { + if (normalizedTempPayload.type === InputVarType.select) { + if (!normalizedTempPayload.options?.length) { return { errorMessage: t('variableConfig.errorMsg.atLeastOneOption', { ns: 'appDebug' }), } } const duplicated = new Set() - const hasRepeatedItem = tempPayload.options.some((option) => { + const hasRepeatedItem = normalizedTempPayload.options.some((option) => { if (duplicated.has(option)) return true @@ -204,8 +209,8 @@ export const validateConfigModalPayload = ({ } } - if ([InputVarType.singleFile, InputVarType.multiFiles].includes(tempPayload.type)) { - if (!tempPayload.allowed_file_types?.length) { + if ([InputVarType.singleFile, InputVarType.multiFiles].includes(normalizedTempPayload.type)) { + if (!normalizedTempPayload.allowed_file_types?.length) { return { errorMessage: t('errorMsg.fieldRequired', { ns: 'workflow', @@ -214,7 +219,7 @@ export const validateConfigModalPayload = ({ } } - if (tempPayload.allowed_file_types.includes(SupportUploadFileTypes.custom) && !tempPayload.allowed_file_extensions?.length) { + if (normalizedTempPayload.allowed_file_types.includes(SupportUploadFileTypes.custom) && !normalizedTempPayload.allowed_file_extensions?.length) { return { errorMessage: t('errorMsg.fieldRequired', { ns: 'workflow', @@ -224,7 +229,7 @@ export const validateConfigModalPayload = ({ } } - if (tempPayload.type === InputVarType.jsonObject && !schemaEmpty && typeof normalizedJsonSchema === 'string') { + if (normalizedTempPayload.type === InputVarType.jsonObject && !schemaEmpty && typeof normalizedJsonSchema === 'string') { try { const schema = JSON.parse(normalizedJsonSchema) if (schema?.type !== 'object') {