feat: add custom value support for s3 region (#15968)

### What problem does this PR solve?
Allow S3-compatible data source region fields to accept custom values
while preserving search-and-select behavior.

### Type of change
- [x] New Feature (non-breaking change which adds functionality)
This commit is contained in:
buua436
2026-06-15 11:40:28 +08:00
committed by GitHub
parent eb6ea284a8
commit 400dfd50d8
3 changed files with 35 additions and 1 deletions

View File

@@ -69,6 +69,7 @@ export interface FormFieldConfig {
required?: boolean;
placeholder?: string;
options?: { label: string; value: string }[];
allowCustomValue?: boolean;
defaultValue?: any;
validation?: {
pattern?: RegExp;
@@ -456,6 +457,7 @@ export const RenderField = ({
triggerClassName="!shrink"
{...finalFieldProps}
options={field.options}
allowCustomValue={field.allowCustomValue}
disabled={field.disabled}
/>
);

View File

@@ -47,6 +47,7 @@ export type SelectWithSearchFlagProps = {
disabled?: boolean;
placeholder?: string;
emptyData?: string;
allowCustomValue?: boolean;
testId?: string;
optionTestIdPrefix?: string;
};
@@ -88,6 +89,7 @@ export const SelectWithSearch = forwardRef<
disabled = false,
placeholder = t('common.selectPlaceholder'),
emptyData = t('common.noDataFound'),
allowCustomValue = false,
testId,
optionTestIdPrefix,
},
@@ -96,6 +98,7 @@ export const SelectWithSearch = forwardRef<
const id = useId();
const [open, setOpen] = useState<boolean>(false);
const [value, setValue] = useState<string>('');
const [searchValue, setSearchValue] = useState<string>('');
const selectLabel = useMemo(() => {
if (options.every((x) => x.options === undefined)) {
@@ -120,6 +123,9 @@ export const SelectWithSearch = forwardRef<
}, [options, value]);
const showSearch = useMemo(() => {
if (allowCustomValue) {
return true;
}
if (Array.isArray(options) && options.length > 5) {
return true;
}
@@ -130,7 +136,21 @@ export const SelectWithSearch = forwardRef<
return optionsNum > 5;
}
return false;
}, [options]);
}, [allowCustomValue, options]);
const hasCustomSearchValue = useMemo(() => {
const customValue = searchValue.trim();
if (!allowCustomValue || !customValue) {
return false;
}
const values = options.flatMap((option) =>
option.options
? option.options.map((item) => item.value)
: option.value,
);
return !values.includes(customValue);
}, [allowCustomValue, options, searchValue]);
const handleSelect = useCallback(
(val: string) => {
@@ -207,12 +227,23 @@ export const SelectWithSearch = forwardRef<
<CommandInput
placeholder={t('common.search') + '...'}
className=" placeholder:text-text-disabled"
value={searchValue}
onValueChange={setSearchValue}
/>
)}
<CommandList className="mt-2 outline-none">
<CommandEmpty>
<div dangerouslySetInnerHTML={{ __html: emptyData }}></div>
</CommandEmpty>
{hasCustomSearchValue && (
<CommandItem
value={searchValue.trim()}
onSelect={handleSelect}
className="mb-1 min-h-10"
>
<span className="leading-none">{searchValue.trim()}</span>
</CommandItem>
)}
{options.map((group, groupIndex) => {
if (group.options) {
return (

View File

@@ -19,6 +19,7 @@ export const S3Constant = (t: TFunction) => [
type: FormFieldType.Select,
required: false,
options: awsRegionOptions,
allowCustomValue: true,
customValidate: (val: string, formValues: any) => {
const credentials = formValues?.config?.credentials || {};
const bucketType = formValues?.config?.bucket_type || 's3';