From 3c99026328a6303657d2c4c3e91d31d1b8f00b79 Mon Sep 17 00:00:00 2001 From: yyh Date: Thu, 30 Apr 2026 13:13:55 +0800 Subject: [PATCH] fix: preserve select migration behavior --- .../base/__tests__/base-field.spec.tsx | 19 ++++++++++++++ .../base/form/components/base/base-field.tsx | 25 ++++++++++++++++--- .../field/__tests__/select.spec.tsx | 16 ++++++++++++ .../__tests__/index.spec.tsx | 3 ++- .../field/input-type-select/trigger.tsx | 11 ++++---- .../base/form/components/field/select.tsx | 14 +++++++++-- 6 files changed, 75 insertions(+), 13 deletions(-) diff --git a/web/app/components/base/form/components/base/__tests__/base-field.spec.tsx b/web/app/components/base/form/components/base/__tests__/base-field.spec.tsx index a5a84b8738..a4d1323e6a 100644 --- a/web/app/components/base/form/components/base/__tests__/base-field.spec.tsx +++ b/web/app/components/base/form/components/base/__tests__/base-field.spec.tsx @@ -118,6 +118,25 @@ describe('BaseField', () => { expect(screen.queryByText('Beta')).not.toBeInTheDocument() }) + it('should not render current select value when it is filtered out by show_on conditions', () => { + renderBaseField({ + formSchema: { + type: FormTypeEnum.select, + name: 'mode', + label: 'Mode', + required: false, + options: [ + { label: 'Alpha', value: 'alpha' }, + { label: 'Beta', value: 'beta', show_on: [{ variable: 'enabled', value: 'yes' }] }, + ], + }, + defaultValues: { mode: 'beta', enabled: 'no' }, + }) + + expect(screen.getByRole('combobox', { name: 'Mode' })).not.toHaveTextContent('beta') + expect(screen.getByRole('combobox', { name: 'Mode' })).toHaveTextContent('common.placeholder.input') + }) + it('should render dynamic select loading state', () => { mockDynamicOptions.mockReturnValue({ data: undefined, diff --git a/web/app/components/base/form/components/base/base-field.tsx b/web/app/components/base/form/components/base/base-field.tsx index a4159cbc6f..a256bccd8b 100644 --- a/web/app/components/base/form/components/base/base-field.tsx +++ b/web/app/components/base/form/components/base/base-field.tsx @@ -51,6 +51,19 @@ const getTranslatedContent = ({ content, render }: { return '' } +type SelectOption = { + label: string + value: string +} + +const getSingleSelectValue = (value: unknown, options: SelectOption[]) => { + return options.find(option => option.value === value)?.value ?? null +} + +const getSingleSelectLabel = (value: unknown, options: SelectOption[], placeholder: string | undefined) => { + return options.find(option => option.value === value)?.label ?? placeholder +} + const VALIDATE_STATUS_STYLE_MAP: Record = { [FormItemValidateStatusEnum.Error]: { componentClassName: 'border-components-input-border-destructive focus:border-components-input-border-destructive', @@ -267,7 +280,7 @@ const BaseField = ({ : ( { if (next == null) @@ -348,7 +363,9 @@ const BaseField = ({ }} > - + + {nextValue => getSingleSelectLabel(nextValue, dynamicOptions, dynamicPlaceholder)} + {dynamicNoticeTitle && ( diff --git a/web/app/components/base/form/components/field/__tests__/select.spec.tsx b/web/app/components/base/form/components/field/__tests__/select.spec.tsx index aec6c6fd56..45cc87d157 100644 --- a/web/app/components/base/form/components/field/__tests__/select.spec.tsx +++ b/web/app/components/base/form/components/field/__tests__/select.spec.tsx @@ -33,6 +33,22 @@ describe('SelectField', () => { expect(screen.getByRole('combobox', { name: 'Mode' })).toHaveTextContent('Alpha') }) + it('should render the option label when selected value is an empty string', () => { + mockField.state.value = '' + + render( + , + ) + + expect(screen.getByRole('combobox', { name: 'Mode' })).toHaveTextContent('No default selected') + }) + it('should update value when users select another option', async () => { const user = userEvent.setup() render( diff --git a/web/app/components/base/form/components/field/input-type-select/__tests__/index.spec.tsx b/web/app/components/base/form/components/field/input-type-select/__tests__/index.spec.tsx index e5e4e9dc9a..4efe5e1257 100644 --- a/web/app/components/base/form/components/field/input-type-select/__tests__/index.spec.tsx +++ b/web/app/components/base/form/components/field/input-type-select/__tests__/index.spec.tsx @@ -21,10 +21,11 @@ describe('InputTypeSelectField', () => { }) it('should render label and selected option', () => { - render() + const { container } = render() expect(screen.getByText('Input type')).toBeInTheDocument() expect(screen.getByText('appDebug.variableConfig.text-input')).toBeInTheDocument() + expect(container.querySelector('[role="combobox"] span > div')).not.toBeInTheDocument() }) it('should update value when users choose another input type', async () => { diff --git a/web/app/components/base/form/components/field/input-type-select/trigger.tsx b/web/app/components/base/form/components/field/input-type-select/trigger.tsx index bf67a3d775..e66bf8efda 100644 --- a/web/app/components/base/form/components/field/input-type-select/trigger.tsx +++ b/web/app/components/base/form/components/field/input-type-select/trigger.tsx @@ -1,7 +1,6 @@ import type { FileTypeSelectOption } from './types' import * as React from 'react' import { useTranslation } from 'react-i18next' -import Badge from '@/app/components/base/badge' type TriggerProps = { option: FileTypeSelectOption | undefined @@ -16,13 +15,13 @@ const Trigger = ({ return {t('placeholder.select', { ns: 'common' })} return ( -
+ <> {option.label} -
- -
-
+ + {option.type} + + ) } diff --git a/web/app/components/base/form/components/field/select.tsx b/web/app/components/base/form/components/field/select.tsx index 2ed52eefec..a8b49a2691 100644 --- a/web/app/components/base/form/components/field/select.tsx +++ b/web/app/components/base/form/components/field/select.tsx @@ -18,6 +18,14 @@ export type Option = { value: string } +const getSelectedValue = (value: string | undefined, options: Option[]) => { + return options.some(option => option.value === value) ? value : null +} + +const getDisplayLabel = (value: string | null, options: Option[], placeholder: string) => { + return options.find(option => option.value === value)?.label ?? placeholder +} + type SelectFieldPopupProps = { className?: string title?: string @@ -58,7 +66,7 @@ const SelectField = ({ />