diff --git a/webapp/packages/core-blocks/src/FormControls/Combobox.tsx b/webapp/packages/core-blocks/src/FormControls/Combobox.tsx index 71982ebe72..c075253b74 100644 --- a/webapp/packages/core-blocks/src/FormControls/Combobox.tsx +++ b/webapp/packages/core-blocks/src/FormControls/Combobox.tsx @@ -16,6 +16,7 @@ import { useStyles } from '@cloudbeaver/core-theming'; import { filterLayoutFakeProps } from '../Containers/filterLayoutFakeProps'; import type { ILayoutSizeProps } from '../Containers/ILayoutSizeProps'; +import { getComputed } from '../getComputed'; import { Icon } from '../Icon'; import { IconOrImage } from '../IconOrImage'; import { baseFormControlStyles, baseValidFormControlStyles } from './baseFormControlStyles'; @@ -132,6 +133,7 @@ type BaseProps = Omit, valueSelector: (item: TValue) => string; titleSelector?: (item: TValue) => string | undefined; iconSelector?: (item: TValue) => string | React.ReactElement | undefined; + isDisabled?: (item: TValue) => boolean; onSwitch?: (state: boolean) => void; }; @@ -173,6 +175,7 @@ export const Combobox: ComboboxType = observer(function Combobox({ valueSelector = v => v, iconSelector, titleSelector, + isDisabled, onChange = () => { }, onSelect, onSwitch, @@ -194,6 +197,19 @@ export const Combobox: ComboboxType = observer(function Combobox({ } const [searchValue, setSearchValue] = useState(null); + + const filteredItems = getComputed(() => { + const result = items.filter( + item => !searchValue || valueSelector(item).toUpperCase().includes(searchValue.toUpperCase()) + ); + + if (isDisabled) { + return result.sort((a, b) => Number(isDisabled(a)) - Number(isDisabled(b))); + } + + return result; + }); + let value: string | number | readonly string[] | undefined = controlledValue ?? defaultValue ?? undefined; if (state && name !== undefined && name in state) { @@ -208,10 +224,6 @@ export const Combobox: ComboboxType = observer(function Combobox({ inputValue = searchValue; } - const filteredItems = items.filter( - item => !searchValue || valueSelector(item).toUpperCase().includes(searchValue.toUpperCase()) - ); - function handleClick() { if (!searchable) { if (menu.visible) { @@ -362,6 +374,7 @@ export const Combobox: ComboboxType = observer(function Combobox({ : (filteredItems.map((item, index) => { const icon = iconSelector?.(item); const title = titleSelector?.(item); + const disabled = isDisabled?.(item); return ( handleSelect(event.currentTarget.id)} > {iconSelector && ( diff --git a/webapp/packages/plugin-administration/src/ConfigurationWizard/ServerConfiguration/ServerConfigurationDriversForm.tsx b/webapp/packages/plugin-administration/src/ConfigurationWizard/ServerConfiguration/ServerConfigurationDriversForm.tsx index b29d084fea..ad7473b5b4 100644 --- a/webapp/packages/plugin-administration/src/ConfigurationWizard/ServerConfiguration/ServerConfigurationDriversForm.tsx +++ b/webapp/packages/plugin-administration/src/ConfigurationWizard/ServerConfiguration/ServerConfigurationDriversForm.tsx @@ -35,9 +35,7 @@ export const ServerConfigurationDriversForm = observer(function ServerCon const translate = useTranslate(); const driversResource = useMapResource(ServerConfigurationDriversForm, DBDriverResource, CachedMapAllKey); - const drivers = driversResource.resource.values - .filter(driver => !serverConfig.disabledDrivers?.includes(driver.id)) - .sort(driversResource.resource.compare); + const drivers = driversResource.resource.values.slice().sort(driversResource.resource.compare); const tags: ITag[] = driversResource.resource.get(resourceKeyList(serverConfig.disabledDrivers || [])) .filter(Boolean) @@ -72,6 +70,7 @@ export const ServerConfigurationDriversForm = observer(function ServerCon keySelector={item => item.id} valueSelector={value => value.name || value.id} iconSelector={value => value.icon} + isDisabled={item => serverConfig.disabledDrivers?.includes(item.id) ?? false} items={drivers} placeholder={translate('administration_disabled_drivers_search_placeholder')} searchable