diff --git a/.github/workflows/backend-build.yml b/.github/workflows/backend-build.yml index 7b1dcb97b5..987763d5a6 100644 --- a/.github/workflows/backend-build.yml +++ b/.github/workflows/backend-build.yml @@ -32,6 +32,17 @@ jobs: sudo chmod 777 ../ shell: bash + - name: Determine branches + id: determine-branch + run: | + echo "pr_branch=${{ github.head_ref }}" >> $GITHUB_ENV + echo "base_branch=${{ github.event.pull_request.base.ref }}" >> $GITHUB_ENV + + - name: Clone dbeaver/dbeaver + id: clone-repo + run: | + git clone -b ${{ env.pr_branch }} https://github.com/dbeaver/dbeaver.git ../dbeaver || git clone -b ${{ env.base_branch }} https://github.com/dbeaver/dbeaver.git ../dbeaver + - name: Run build script run: ./build-backend.sh shell: bash diff --git a/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/model/WebConnectionInfo.java b/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/model/WebConnectionInfo.java index ed9cc7bf7a..9c4984db7e 100644 --- a/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/model/WebConnectionInfo.java +++ b/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/model/WebConnectionInfo.java @@ -384,6 +384,16 @@ public class WebConnectionInfo { } } + @Property + public Map getMainPropertyValues() { + Map mainProperties = new LinkedHashMap<>(); + mainProperties.put(DBConstants.PROP_HOST, getHost()); + mainProperties.put(DBConstants.PROP_PORT, getPort()); + mainProperties.put(DBConstants.PROP_DATABASE, getDatabaseName()); + mainProperties.put(DBConstants.PROP_SERVER, getServerName()); + return mainProperties; + } + @Property public Map getProviderProperties() { return dataSourceContainer.getConnectionConfiguration().getProviderProperties(); diff --git a/server/bundles/io.cloudbeaver.server/schema/service.core.graphqls b/server/bundles/io.cloudbeaver.server/schema/service.core.graphqls index 94998e62f9..66e49b6a85 100644 --- a/server/bundles/io.cloudbeaver.server/schema/service.core.graphqls +++ b/server/bundles/io.cloudbeaver.server/schema/service.core.graphqls @@ -229,6 +229,7 @@ type DriverInfo { enabled: Boolean! requiresServerName: Boolean requiresDatabaseName: Boolean + useCustomPage: Boolean! @since(version: "24.1.2") # if host, port, database, server name fields are custom licenseRequired: Boolean license: String @@ -248,6 +249,10 @@ type DriverInfo { # Driver parameters (map name->value) driverParameters: Object! + # Main driver properties + # Contains info about main fields (host, port, database, server name) + mainProperties: [ObjectPropertyInfo!]! @since(version: "24.1.2") + # Additional driver provider properties # These properties can be configured by user on main connection page # to provide important connection settings @@ -340,6 +345,8 @@ type ConnectionInfo { databaseName: String url: String + mainPropertyValues: Object @since(version: "24.1.2") + keepAliveInterval: Int! autocommit: Boolean @@ -499,6 +506,10 @@ input ConnectionConfig { port: String serverName: String databaseName: String + + # Host, port, serverName, databaseName are also stored in mainPropertyValues for custom pages + mainPropertyValues: Object @since(version: "24.1.2") + # Connection url jdbc:{driver}://{host}[:{port}]/[{database}] url: String # Properties diff --git a/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/WebServiceUtils.java b/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/WebServiceUtils.java index 31710ece35..f87931b036 100644 --- a/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/WebServiceUtils.java +++ b/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/WebServiceUtils.java @@ -33,6 +33,7 @@ import io.cloudbeaver.utils.WebDataSourceUtils; import org.jkiss.code.NotNull; import org.jkiss.code.Nullable; import org.jkiss.dbeaver.Log; +import org.jkiss.dbeaver.model.DBConstants; import org.jkiss.dbeaver.model.DBPDataSourceContainer; import org.jkiss.dbeaver.model.access.DBAAuthCredentials; import org.jkiss.dbeaver.model.app.DBPDataSourceRegistry; @@ -150,22 +151,7 @@ public class WebServiceUtils extends WebCommonUtils { } public static void setConnectionConfiguration(DBPDriver driver, DBPConnectionConfiguration dsConfig, WebConnectionConfig config) { - if (!CommonUtils.isEmpty(config.getUrl())) { - dsConfig.setUrl(config.getUrl()); - } else { - if (config.getHost() != null) { - dsConfig.setHostName(config.getHost()); - } - if (config.getPort() != null) { - dsConfig.setHostPort(config.getPort()); - } - if (config.getDatabaseName() != null) { - dsConfig.setDatabaseName(config.getDatabaseName()); - } - if (config.getServerName() != null) { - dsConfig.setServerName(config.getServerName()); - } - } + setMainProperties(dsConfig, config); if (config.getProperties() != null) { Map newProps = new LinkedHashMap<>(); for (Map.Entry pe : config.getProperties().entrySet()) { @@ -222,6 +208,37 @@ public class WebServiceUtils extends WebCommonUtils { } } + private static void setMainProperties(DBPConnectionConfiguration dsConfig, WebConnectionConfig config) { + if (CommonUtils.isNotEmpty(config.getUrl())) { + dsConfig.setUrl(config.getUrl()); + return; + } + if (config.getMainPropertyValues() != null) { + for (Map.Entry e : config.getMainPropertyValues().entrySet()) { + switch (e.getKey()) { + case DBConstants.PROP_HOST -> dsConfig.setHostName(CommonUtils.toString(e.getValue())); + case DBConstants.PROP_PORT -> dsConfig.setHostPort(CommonUtils.toString(e.getValue())); + case DBConstants.PROP_DATABASE -> dsConfig.setDatabaseName(CommonUtils.toString(e.getValue())); + case DBConstants.PROP_SERVER -> dsConfig.setServerName(CommonUtils.toString(e.getValue())); + default -> throw new IllegalStateException("Unexpected value: " + e.getKey()); + } + } + return; + } + if (config.getHost() != null) { + dsConfig.setHostName(config.getHost()); + } + if (config.getPort() != null) { + dsConfig.setHostPort(config.getPort()); + } + if (config.getDatabaseName() != null) { + dsConfig.setDatabaseName(config.getDatabaseName()); + } + if (config.getServerName() != null) { + dsConfig.setServerName(config.getServerName()); + } + } + public static void saveAuthProperties( @NotNull DBPDataSourceContainer dataSourceContainer, @NotNull DBPConnectionConfiguration configuration, diff --git a/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/model/WebConnectionConfig.java b/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/model/WebConnectionConfig.java index b51390e9c5..73d0197ea3 100644 --- a/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/model/WebConnectionConfig.java +++ b/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/model/WebConnectionConfig.java @@ -57,6 +57,7 @@ public class WebConnectionConfig { private Map credentials; private boolean saveCredentials; private boolean sharedCredentials; + private Map mainPropertyValues; private Map providerProperties; private List networkHandlersConfig; private DBPDriverConfigurationType configurationType; @@ -102,6 +103,7 @@ public class WebConnectionConfig { saveCredentials = JSONUtils.getBoolean(params, "saveCredentials"); sharedCredentials = JSONUtils.getBoolean(params, "sharedCredentials"); + mainPropertyValues = JSONUtils.getObjectOrNull(params, "mainPropertyValues"); providerProperties = JSONUtils.getObjectOrNull(params, "providerProperties"); String configType = JSONUtils.getString(params, "configurationType"); @@ -227,6 +229,11 @@ public class WebConnectionConfig { this.saveCredentials = saveCredentials; } + @Property + public Map getMainPropertyValues() { + return mainPropertyValues; + } + @Property public Map getProviderProperties() { return providerProperties; diff --git a/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/model/WebDatabaseDriverInfo.java b/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/model/WebDatabaseDriverInfo.java index 61f0a8e970..f9e207bbcb 100644 --- a/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/model/WebDatabaseDriverInfo.java +++ b/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/model/WebDatabaseDriverInfo.java @@ -36,9 +36,11 @@ import org.jkiss.dbeaver.registry.DataSourceProviderRegistry; import org.jkiss.dbeaver.registry.network.NetworkHandlerDescriptor; import org.jkiss.dbeaver.registry.network.NetworkHandlerRegistry; import org.jkiss.dbeaver.runtime.properties.PropertySourceCustom; +import org.jkiss.utils.ArrayUtils; import org.jkiss.utils.CommonUtils; import java.util.Arrays; +import java.util.LinkedHashMap; import java.util.Map; /** @@ -233,6 +235,22 @@ public class WebDatabaseDriverInfo { return AuthModelDatabaseNative.ID; } + @Property + public WebPropertyInfo[] getMainProperties() { + DBPPropertyDescriptor[] properties = driver.getMainPropertyDescriptors(); + // set default values to main properties + Map defaultValues = new LinkedHashMap<>(); + defaultValues.put(DBConstants.PROP_HOST, getDefaultHost()); + defaultValues.put(DBConstants.PROP_PORT, getDefaultPort()); + defaultValues.put(DBConstants.PROP_DATABASE, getDefaultDatabase()); + defaultValues.put(DBConstants.PROP_SERVER, getDefaultServer()); + PropertySourceCustom propertySource = new PropertySourceCustom(properties, defaultValues); + + return Arrays.stream(properties) + .map(p -> new WebPropertyInfo(webSession, p, propertySource)) + .toArray(WebPropertyInfo[]::new); + } + @Property public WebPropertyInfo[] getProviderProperties() { return Arrays.stream(driver.getProviderPropertyDescriptors()) @@ -276,4 +294,9 @@ public class WebDatabaseDriverInfo { .map(dbpDriverLibrary -> new WebDriverLibraryInfo(webSession, dbpDriverLibrary)) .toArray(WebDriverLibraryInfo[]::new); } + + @Property + public boolean getUseCustomPage() { + return !ArrayUtils.isEmpty(driver.getMainPropertyDescriptors()); + } } diff --git a/webapp/packages/core-blocks/src/ObjectPropertyInfo/ObjectPropertyInfoForm/RenderField.tsx b/webapp/packages/core-blocks/src/ObjectPropertyInfo/ObjectPropertyInfoForm/RenderField.tsx index 20f73297ca..0d82228881 100644 --- a/webapp/packages/core-blocks/src/ObjectPropertyInfo/ObjectPropertyInfoForm/RenderField.tsx +++ b/webapp/packages/core-blocks/src/ObjectPropertyInfo/ObjectPropertyInfoForm/RenderField.tsx @@ -7,7 +7,7 @@ */ import { observer } from 'mobx-react-lite'; -import { getObjectPropertyType, type ObjectPropertyInfo, type ObjectPropertyType } from '@cloudbeaver/core-sdk'; +import { getObjectPropertyType, getObjectPropertyValueType, type ObjectPropertyInfo, type ObjectPropertyType } from '@cloudbeaver/core-sdk'; import { removeMetadataFromDataURL } from '@cloudbeaver/core-utils'; import { FieldCheckbox } from '../../FormControls/Checkboxes/FieldCheckbox'; @@ -70,7 +70,8 @@ export const RenderField = observer(function RenderField({ const translate = useTranslate(); const controlType = getObjectPropertyType(property); - const password = property.features.includes('password'); + const type = getObjectPropertyValueType(property); + const isPassword = type === 'password'; const required = property.required && !readOnly; const value = getValue(property.value, controlType); @@ -172,7 +173,7 @@ export const RenderField = observer(function RenderField({ ); } - const passwordSaved = showRememberTip && ((password && !!property.value) || saved); + const passwordSaved = showRememberTip && ((isPassword && !!property.value) || saved); const passwordSavedMessage = passwordSaved ? translate('core_blocks_object_property_info_password_saved') : undefined; if (controlType === 'file' && state) { @@ -233,8 +234,8 @@ export const RenderField = observer(function RenderField({ return ( (function RenderField({ return ( { const { Options } = await import('./Options'); return { default: Options }; }); +const MAIN_PROPERTY_DATABASE_KEY = 'database'; +const MAIN_PROPERTY_HOST_KEY = 'host'; +const MAIN_PROPERTY_PORT_KEY = 'port'; +const MAIN_PROPERTY_SERVER_KEY = 'server'; + @injectable() export class ConnectionOptionsTabService extends Bootstrap { constructor( - private readonly serverConfigResource: ServerConfigResource, private readonly projectInfoResource: ProjectInfoResource, private readonly connectionFormService: ConnectionFormService, private readonly dbDriverResource: DBDriverResource, @@ -174,10 +178,7 @@ export class ConnectionOptionsTabService extends Bootstrap { const driver = await this.dbDriverResource.load(state.config.driverId, ['includeProviderProperties']); state.config.authModelId = driver?.defaultAuthModel; - - state.config.configurationType = driver?.configurationTypes.includes(DriverConfigurationType.Manual) - ? DriverConfigurationType.Manual - : DriverConfigurationType.Url; + state.config.configurationType = getDefaultConfigurationType(driver); state.config.host = driver?.defaultServer || 'localhost'; state.config.port = driver?.defaultPort; @@ -205,6 +206,10 @@ export class ConnectionOptionsTabService extends Bootstrap { state.config.providerProperties = {}; } + if (!state.config.mainPropertyValues || updated) { + state.config.mainPropertyValues = {}; + } + if (!state.info) { await this.setDefaults(state); return; @@ -218,10 +223,11 @@ export class ConnectionOptionsTabService extends Bootstrap { state.config.template = state.info.template; state.config.driverId = state.info.driverId; - state.config.host = state.info.host; - state.config.port = state.info.port; - state.config.serverName = state.info.serverName; - state.config.databaseName = state.info.databaseName; + state.config.host = state.info.mainPropertyValues[MAIN_PROPERTY_HOST_KEY]; + state.config.port = state.info.mainPropertyValues[MAIN_PROPERTY_PORT_KEY]; + state.config.serverName = state.info.mainPropertyValues[MAIN_PROPERTY_SERVER_KEY]; + state.config.databaseName = state.info.mainPropertyValues[MAIN_PROPERTY_DATABASE_KEY]; + state.config.url = state.info.url; state.config.folder = state.info.folder; @@ -243,6 +249,10 @@ export class ConnectionOptionsTabService extends Bootstrap { if (state.info.providerProperties) { state.config.providerProperties = { ...state.info.providerProperties }; } + + if (state.info.mainPropertyValues) { + state.config.mainPropertyValues = { ...state.info.mainPropertyValues }; + } } private configure(data: IConnectionFormState, contexts: IExecutionContextProvider) { @@ -251,19 +261,6 @@ export class ConnectionOptionsTabService extends Bootstrap { configuration.include('includeOrigin', 'includeAuthProperties', 'includeCredentialsSaved', 'customIncludeOptions'); } - private getTrimmedPropertiesConfig(authProperties: ObjectPropertyInfo[], credentials: Record): Record { - const trimmedProperties: Record = toJS(credentials); - for (const property of authProperties) { - const value = credentials?.[property.id!]; - - if (typeof value === 'string' && value) { - trimmedProperties[property.id!] = value?.trim(); - } - } - - return trimmedProperties; - } - private async prepareConfig({ state }: IConnectionFormSubmitData, contexts: IExecutionContextProvider) { const config = contexts.getContext(connectionConfigContext); const credentialsState = contexts.getContext(connectionCredentialsStateContext); @@ -272,7 +269,7 @@ export class ConnectionOptionsTabService extends Bootstrap { return; } - const driver = await this.dbDriverResource.load(state.config.driverId, ['includeProviderProperties']); + const driver = await this.dbDriverResource.load(state.config.driverId, ['includeProviderProperties', 'includeMainProperties']); const tempConfig = toJS(config); if (state.mode === 'edit') { @@ -280,7 +277,6 @@ export class ConnectionOptionsTabService extends Bootstrap { } tempConfig.configurationType = state.config.configurationType; - tempConfig.name = state.config.name?.trim(); if (tempConfig.name && state.mode === 'create') { @@ -291,11 +287,8 @@ export class ConnectionOptionsTabService extends Bootstrap { } tempConfig.description = state.config.description?.trim(); - tempConfig.template = state.config.template; - tempConfig.driverId = state.config.driverId; - tempConfig.keepAliveInterval = Number(state.config.keepAliveInterval); tempConfig.autocommit = state.config.autocommit; @@ -305,15 +298,21 @@ export class ConnectionOptionsTabService extends Bootstrap { if (tempConfig.configurationType === DriverConfigurationType.Url) { tempConfig.url = state.config.url?.trim(); - } else { + } + + tempConfig.mainPropertyValues = toJS(state.config.mainPropertyValues); + + if (tempConfig.configurationType === DriverConfigurationType.Manual && !driver.useCustomPage) { + tempConfig.mainPropertyValues[MAIN_PROPERTY_DATABASE_KEY] = state.config.databaseName?.trim(); + if (!driver.embedded) { - tempConfig.host = state.config.host?.trim(); - tempConfig.port = state.config.port?.trim(); + tempConfig.mainPropertyValues[MAIN_PROPERTY_HOST_KEY] = state.config.host?.trim(); + tempConfig.mainPropertyValues[MAIN_PROPERTY_PORT_KEY] = state.config.port?.trim(); } + if (driver.requiresServerName) { - tempConfig.serverName = state.config.serverName?.trim(); + tempConfig.mainPropertyValues[MAIN_PROPERTY_SERVER_KEY] = state.config.serverName?.trim(); } - tempConfig.databaseName = state.config.databaseName?.trim(); } if ((state.config.authModelId || driver.defaultAuthModel) && !driver.anonymousAccess) { @@ -324,7 +323,7 @@ export class ConnectionOptionsTabService extends Bootstrap { const properties = await this.getConnectionAuthModelProperties(tempConfig.authModelId, state.info); if (this.isCredentialsChanged(properties, state.config.credentials)) { - tempConfig.credentials = this.getTrimmedPropertiesConfig(properties, { ...state.config.credentials }); + tempConfig.credentials = this.prepareDynamicProperties(properties, toJS(state.config.credentials)); } if (!tempConfig.saveCredentials) { @@ -333,32 +332,19 @@ export class ConnectionOptionsTabService extends Bootstrap { } if (driver.providerProperties.length > 0) { - const providerProperties: Record = { ...state.config.providerProperties }; + tempConfig.providerProperties = this.prepareDynamicProperties( + driver.providerProperties, + toJS(state.config.providerProperties), + tempConfig.configurationType, + ); + } - for (const providerProperty of driver.providerProperties) { - if (!providerProperty.id) { - continue; - } - - const supported = providerProperty.supportedConfigurationTypes?.some(t => t === tempConfig.configurationType); - - if (!supported) { - delete providerProperties[providerProperty.id]; - } else { - const isDefault = isNotNullDefined(providerProperty.defaultValue); - if (!(providerProperty.id in providerProperties) && isDefault) { - providerProperties[providerProperty.id] = providerProperty.defaultValue; - } - } - } - - tempConfig.providerProperties = providerProperties; - - for (const key of Object.keys(tempConfig.providerProperties)) { - if (typeof tempConfig.providerProperties[key] === 'string') { - tempConfig.providerProperties[key] = tempConfig.providerProperties[key]?.trim(); - } - } + if (driver.useCustomPage && driver.mainProperties.length > 0) { + tempConfig.mainPropertyValues = this.prepareDynamicProperties( + driver.mainProperties, + tempConfig.mainPropertyValues, + tempConfig.configurationType, + ); } runInAction(() => { @@ -366,11 +352,44 @@ export class ConnectionOptionsTabService extends Bootstrap { }); } + private prepareDynamicProperties( + propertiesInfo: ObjectPropertyInfo[], + properties: Record, + configurationType?: DriverConfigurationType, + ) { + const result: Record = { ...properties }; + + for (const propertyInfo of propertiesInfo) { + if (!propertyInfo.id) { + continue; + } + + const supported = configurationType === undefined || propertyInfo.supportedConfigurationTypes?.some(type => type === configurationType); + + if (!supported) { + delete result[propertyInfo.id]; + } else { + const isDefault = isNotNullDefined(propertyInfo.defaultValue); + if (!(propertyInfo.id in result) && isDefault) { + result[propertyInfo.id] = propertyInfo.defaultValue; + } + } + } + + for (const key of Object.keys(result)) { + if (typeof result[key] === 'string') { + result[key] = result[key]?.trim(); + } + } + + return result; + } + private async formAuthState(data: IConnectionFormState, contexts: IExecutionContextProvider) { const config = contexts.getContext(connectionConfigContext); const stateContext = contexts.getContext(formStateContext); - const driver = await this.dbDriverResource.load(config.driverId!, ['includeProviderProperties']); + const driver = await this.dbDriverResource.load(config.driverId!, ['includeProviderProperties', 'includeMainProperties']); const authModel = await this.databaseAuthModelsResource.load(config.authModelId ?? data.info?.authModel ?? driver.defaultAuthModel); const providerId = authModel.requiredAuth ?? data.info?.requiredAuth ?? AUTH_PROVIDER_LOCAL_ID; @@ -394,7 +413,7 @@ export class ConnectionOptionsTabService extends Bootstrap { const config = contexts.getContext(connectionConfigContext); const stateContext = contexts.getContext(formStateContext); - const driver = await this.dbDriverResource.load(data.config.driverId!, ['includeProviderProperties']); + const driver = await this.dbDriverResource.load(data.config.driverId!, ['includeProviderProperties', 'includeMainProperties']); if ( !isValuesEqual(config.name, data.info.name, '') || @@ -414,6 +433,8 @@ export class ConnectionOptionsTabService extends Bootstrap { (config.sharedCredentials !== undefined && config.sharedCredentials !== data.info.sharedCredentials) || (config.providerProperties !== undefined && !isObjectPropertyInfoStateEqual(driver.providerProperties, config.providerProperties, data.info.providerProperties)) || + (config.mainPropertyValues !== undefined && + !isObjectPropertyInfoStateEqual(driver.mainProperties, config.mainPropertyValues, data.info.mainPropertyValues)) || (config.keepAliveInterval !== undefined && !isValuesEqual(config.keepAliveInterval, data.info.keepAliveInterval)) || (config.autocommit !== undefined && !isValuesEqual(config.autocommit, data.info.autocommit)) ) { diff --git a/webapp/packages/plugin-connections/src/ConnectionForm/Options/Options.tsx b/webapp/packages/plugin-connections/src/ConnectionForm/Options/Options.tsx index c27a632847..f50955f7e4 100644 --- a/webapp/packages/plugin-connections/src/ConnectionForm/Options/Options.tsx +++ b/webapp/packages/plugin-connections/src/ConnectionForm/Options/Options.tsx @@ -21,6 +21,7 @@ import { GroupTitle, InputField, Link, + ObjectPropertyInfoForm, Radio, RadioGroup, s, @@ -31,11 +32,12 @@ import { useS, useTranslate, } from '@cloudbeaver/core-blocks'; -import { DatabaseAuthModelsResource, DBDriverResource, isLocalConnection } from '@cloudbeaver/core-connections'; +import { DatabaseAuthModelsResource, DBDriver, DBDriverResource, isLocalConnection } from '@cloudbeaver/core-connections'; import { useService } from '@cloudbeaver/core-di'; import { ServerConfigResource } from '@cloudbeaver/core-root'; import { DriverConfigurationType } from '@cloudbeaver/core-sdk'; import { type TabContainerPanelComponent, TabsContext, useAuthenticationAction } from '@cloudbeaver/core-ui'; +import { EMPTY_ARRAY } from '@cloudbeaver/core-utils'; import { ProjectSelect } from '@cloudbeaver/plugin-projects'; import { ConnectionAuthModelCredentialsForm } from '../ConnectionAuthModelCredentials/ConnectionAuthModelCredentialsForm'; @@ -57,16 +59,19 @@ interface IDriverConfiguration { value: DriverConfigurationType; description?: string; icon?: string; + isVisible: (driver: DBDriver) => boolean; } const driverConfiguration: IDriverConfiguration[] = [ { name: 'Manual', value: DriverConfigurationType.Manual, + isVisible: driver => driver.configurationTypes.includes(DriverConfigurationType.Manual), }, { name: 'URL', value: DriverConfigurationType.Url, + isVisible: driver => driver.configurationTypes.includes(DriverConfigurationType.Url), }, ]; @@ -90,7 +95,7 @@ export const Options: TabContainerPanelComponent = observe const driverMap = useResource( Options, DBDriverResource, - { key: config.driverId || null, includes: ['includeProviderProperties'] as const }, + { key: config.driverId || null, includes: ['includeProviderProperties', 'includeMainProperties'] as const }, { onData: data => { optionsHook.setDefaults(data); @@ -99,7 +104,7 @@ export const Options: TabContainerPanelComponent = observe ); const driver = driverMap.data; - const configurationTypes = driverConfiguration.filter(conf => driver?.configurationTypes.includes(conf.value)); + const configurationTypes = driverConfiguration.filter(configuration => driver && configuration.isVisible(driver)); function handleFormChange(value?: unknown, name?: string) { if (name !== 'name' && optionsHook.isNameAutoFill()) { @@ -142,7 +147,6 @@ export const Options: TabContainerPanelComponent = observe providerId: authModel?.requiredAuth ?? info?.requiredAuth ?? AUTH_PROVIDER_LOCAL_ID, }); - const isURLConfiguration = config.configurationType === DriverConfigurationType.Url; const edit = state.mode === 'edit'; const originLocal = !info || isLocalConnection(info); @@ -185,44 +189,28 @@ export const Options: TabContainerPanelComponent = observe {translate('connections_connection_driver')} {configurationTypes.length > 1 && ( - <> - {/* conf.value} - valueSelector={conf => conf.name} - titleSelector={conf => conf.description} - readOnly={readonly || configurationTypes.length < 2} - disabled={disabled} - tiny - fill - > - {translate('connections_connection_configuration')} - */} - - - - {driverConfiguration.map(conf => ( - - {conf.name} - - ))} - - - - + + + + {configurationTypes.map(conf => ( + + {conf.name} + + ))} + + + )} - {isURLConfiguration ? ( + {config.configurationType === DriverConfigurationType.Url && ( = observe > {translate('customConnection_url_JDBC')} - ) : ( - )} + + {config.configurationType === DriverConfigurationType.Manual && + (driver?.useCustomPage ? ( + + ) : ( + + ))} diff --git a/webapp/packages/plugin-connections/src/ConnectionForm/Options/ProviderPropertiesForm.tsx b/webapp/packages/plugin-connections/src/ConnectionForm/Options/ProviderPropertiesForm.tsx index b9f1cc17de..38551732b7 100644 --- a/webapp/packages/plugin-connections/src/ConnectionForm/Options/ProviderPropertiesForm.tsx +++ b/webapp/packages/plugin-connections/src/ConnectionForm/Options/ProviderPropertiesForm.tsx @@ -16,13 +16,13 @@ import { useObjectPropertyCategories, useTranslate, } from '@cloudbeaver/core-blocks'; -import { type ConnectionConfig, type DriverProviderPropertyInfoFragment, getObjectPropertyType } from '@cloudbeaver/core-sdk'; +import { type ConnectionConfig, type DriverPropertyInfoFragment, getObjectPropertyType } from '@cloudbeaver/core-sdk'; -type DriverProviderPropertyInfo = DriverProviderPropertyInfoFragment; +type DriverPropertyInfo = DriverPropertyInfoFragment; interface Props { config: ConnectionConfig; - properties: DriverProviderPropertyInfo[]; + properties: DriverPropertyInfo[]; disabled?: boolean; readonly?: boolean; } @@ -93,6 +93,6 @@ export const ProviderPropertiesForm = observer(function ProviderPropertie ); }); -function isOnlyBooleans(properties: DriverProviderPropertyInfo[], category?: string): boolean { +function isOnlyBooleans(properties: DriverPropertyInfo[], category?: string): boolean { return properties.filter(property => !category || property.category === category).every(property => property.dataType === 'Boolean'); } diff --git a/webapp/packages/plugin-connections/src/ConnectionForm/Options/getDefaultConfigurationType.ts b/webapp/packages/plugin-connections/src/ConnectionForm/Options/getDefaultConfigurationType.ts new file mode 100644 index 0000000000..b25fc1519f --- /dev/null +++ b/webapp/packages/plugin-connections/src/ConnectionForm/Options/getDefaultConfigurationType.ts @@ -0,0 +1,18 @@ +/* + * CloudBeaver - Cloud Database Manager + * Copyright (C) 2020-2024 DBeaver Corp and others + * + * Licensed under the Apache License, Version 2.0. + * you may not use this file except in compliance with the License. + */ +import type { DBDriver } from '@cloudbeaver/core-connections'; +import { DriverConfigurationType } from '@cloudbeaver/core-sdk'; + +export function getDefaultConfigurationType(driver: DBDriver | undefined) { + if (!driver) { + return DriverConfigurationType.Url; + } + + const supportManual = driver.configurationTypes.includes(DriverConfigurationType.Manual); + return supportManual ? DriverConfigurationType.Manual : DriverConfigurationType.Url; +} diff --git a/webapp/packages/plugin-connections/src/ConnectionForm/Options/useOptions.ts b/webapp/packages/plugin-connections/src/ConnectionForm/Options/useOptions.ts index cfaa66f6ea..473de8dce7 100644 --- a/webapp/packages/plugin-connections/src/ConnectionForm/Options/useOptions.ts +++ b/webapp/packages/plugin-connections/src/ConnectionForm/Options/useOptions.ts @@ -10,10 +10,11 @@ import { runInAction } from 'mobx'; import { useObjectRef } from '@cloudbeaver/core-blocks'; import { DBDriver, DBDriverResource, isJDBCConnection } from '@cloudbeaver/core-connections'; import { useService } from '@cloudbeaver/core-di'; -import { DatabaseAuthModel, DriverConfigurationType } from '@cloudbeaver/core-sdk'; +import type { DatabaseAuthModel } from '@cloudbeaver/core-sdk'; import type { IConnectionFormState } from '../IConnectionFormProps'; import { getConnectionName } from './getConnectionName'; +import { getDefaultConfigurationType } from './getDefaultConfigurationType'; export function useOptions(state: IConnectionFormState) { const dbDriverResource = useService(DBDriverResource); @@ -71,9 +72,7 @@ export function useOptions(state: IConnectionFormState) { refObject.prevDriverId = driver?.id || null; if (!config.configurationType || !driver?.configurationTypes.includes(config.configurationType)) { - config.configurationType = driver?.configurationTypes.includes(DriverConfigurationType.Manual) - ? DriverConfigurationType.Manual - : DriverConfigurationType.Url; + state.config.configurationType = getDefaultConfigurationType(driver); } if ((!prevDriver && config.host === undefined) || config.host === prevDriver?.defaultServer) {