From e6e92f0bb38139a889028febc4819f34e9f040a8 Mon Sep 17 00:00:00 2001 From: Ainur <59531286+yagudin10@users.noreply.github.com> Date: Tue, 16 Sep 2025 16:51:38 +0300 Subject: [PATCH] dbeaver/pro#5614 api for expert settings props (#3727) --- .../OSGI-INF/l10n/bundle.properties | 8 +- .../OSGI-INF/l10n/bundle_fr.properties | 2 + .../OSGI-INF/l10n/bundle_ru.properties | 5 ++ .../OSGI-INF/l10n/bundle_vi.properties | 4 + .../OSGI-INF/l10n/bundle_zh.properties | 3 + .../model/WebConnectionConfig.java | 24 +++-- .../cloudbeaver/model/WebConnectionInfo.java | 11 +++ .../model/WebExpertSettingsProperties.java | 87 +++++++++++++++++++ .../OSGI-INF/l10n/bundle.properties | 2 +- .../OSGI-INF/l10n/bundle_ru.properties | 2 +- .../schema/service.core.graphqls | 19 ++-- .../model/WebDatabaseDriverInfo.java | 4 + .../ObjectPropertyInfoForm/RenderField.tsx | 7 +- .../src/DBDriverExpertSettingsResource.ts | 57 ++++++++++++ .../core-connections/src/DBDriverResource.ts | 4 + webapp/packages/core-connections/src/index.ts | 1 + .../core-connections/src/locales/de.ts | 4 - .../core-connections/src/locales/en.ts | 6 -- .../core-connections/src/locales/fr.ts | 6 -- .../core-connections/src/locales/it.ts | 6 -- .../core-connections/src/locales/ru.ts | 6 -- .../core-connections/src/locales/vi.ts | 4 - .../core-connections/src/locales/zh.ts | 6 -- .../packages/core-connections/src/module.ts | 3 + .../src/getObjectPropertyValueType.ts | 2 +- .../connections/getDriverExpertProperties.gql | 7 ++ .../DatabaseConnectionCustomOptions.gql | 6 +- .../Options/AdvancedPropertiesForm.tsx | 77 ++-------------- .../Options/ConnectionFormOptionsPart.ts | 26 ++++-- .../Options/IConnectionConfig.ts | 6 +- .../Options/getConnectionFormOptionsPart.ts | 3 + 31 files changed, 264 insertions(+), 144 deletions(-) create mode 100644 server/bundles/io.cloudbeaver.model/OSGI-INF/l10n/bundle_fr.properties create mode 100644 server/bundles/io.cloudbeaver.model/OSGI-INF/l10n/bundle_ru.properties create mode 100644 server/bundles/io.cloudbeaver.model/OSGI-INF/l10n/bundle_vi.properties create mode 100644 server/bundles/io.cloudbeaver.model/OSGI-INF/l10n/bundle_zh.properties create mode 100644 server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/model/WebExpertSettingsProperties.java create mode 100644 webapp/packages/core-connections/src/DBDriverExpertSettingsResource.ts create mode 100644 webapp/packages/core-sdk/src/queries/connections/getDriverExpertProperties.gql diff --git a/server/bundles/io.cloudbeaver.model/OSGI-INF/l10n/bundle.properties b/server/bundles/io.cloudbeaver.model/OSGI-INF/l10n/bundle.properties index f4e51c2924..bcfc808dd6 100644 --- a/server/bundles/io.cloudbeaver.model/OSGI-INF/l10n/bundle.properties +++ b/server/bundles/io.cloudbeaver.model/OSGI-INF/l10n/bundle.properties @@ -10,4 +10,10 @@ meta.io.cloudbeaver.model.app.ServletSystemInformationCollector.deploymentType.n meta.io.cloudbeaver.model.app.ServletSystemInformationCollector.smDbUrl.name=Security manager database URL meta.io.cloudbeaver.model.app.ServletSystemInformationCollector.smDbDriverName.name=Security manager database driver name meta.io.cloudbeaver.model.app.ServletSystemInformationCollector.smDbProductName.name=Security manager database product name -meta.io.cloudbeaver.model.app.ServletSystemInformationCollector.smDbProductVersion.name=Security manager database product version \ No newline at end of file +meta.io.cloudbeaver.model.app.ServletSystemInformationCollector.smDbProductVersion.name=Security manager database product version + +meta.io.cloudbeaver.model.WebExpertSettingsProperties.readOnly.name = Read-only connection +meta.io.cloudbeaver.model.WebExpertSettingsProperties.autoCommit.name = Auto-commit +meta.io.cloudbeaver.model.WebExpertSettingsProperties.keepAliveInterval.name = Keep-alive interval (seconds) +meta.io.cloudbeaver.model.WebExpertSettingsProperties.defaultSchema.name = Default schema +meta.io.cloudbeaver.model.WebExpertSettingsProperties.defaultCatalog.name = Default catalog \ No newline at end of file diff --git a/server/bundles/io.cloudbeaver.model/OSGI-INF/l10n/bundle_fr.properties b/server/bundles/io.cloudbeaver.model/OSGI-INF/l10n/bundle_fr.properties new file mode 100644 index 0000000000..c03222eb0b --- /dev/null +++ b/server/bundles/io.cloudbeaver.model/OSGI-INF/l10n/bundle_fr.properties @@ -0,0 +1,2 @@ +meta.io.cloudbeaver.model.WebExpertSettingsProperties.keepAliveInterval.name = Garder actif (en secondes) +meta.io.cloudbeaver.model.WebExpertSettingsProperties.keepAliveInterval.description = Pas de déconnexion automatique \ No newline at end of file diff --git a/server/bundles/io.cloudbeaver.model/OSGI-INF/l10n/bundle_ru.properties b/server/bundles/io.cloudbeaver.model/OSGI-INF/l10n/bundle_ru.properties new file mode 100644 index 0000000000..08a1d65e20 --- /dev/null +++ b/server/bundles/io.cloudbeaver.model/OSGI-INF/l10n/bundle_ru.properties @@ -0,0 +1,5 @@ +meta.io.cloudbeaver.model.WebExpertSettingsProperties.readOnly.name = Только для чтения +meta.io.cloudbeaver.model.WebExpertSettingsProperties.autoCommit.name = Авто-коммит +meta.io.cloudbeaver.model.WebExpertSettingsProperties.keepAliveInterval.name = Интервал Keep-alive (в секундах) +meta.io.cloudbeaver.model.WebExpertSettingsProperties.defaultSchema.name = Схема по умолчанию +meta.io.cloudbeaver.model.WebExpertSettingsProperties.defaultCatalog.name = Каталог по умолчанию \ No newline at end of file diff --git a/server/bundles/io.cloudbeaver.model/OSGI-INF/l10n/bundle_vi.properties b/server/bundles/io.cloudbeaver.model/OSGI-INF/l10n/bundle_vi.properties new file mode 100644 index 0000000000..f60d3e3372 --- /dev/null +++ b/server/bundles/io.cloudbeaver.model/OSGI-INF/l10n/bundle_vi.properties @@ -0,0 +1,4 @@ +meta.io.cloudbeaver.model.WebExpertSettingsProperties.readOnly.name = Kết nối chỉ đọc +meta.io.cloudbeaver.model.WebExpertSettingsProperties.autoCommit.name = Tự động commit +meta.io.cloudbeaver.model.WebExpertSettingsProperties.keepAliveInterval.name = Giữ kết nối (tính bằng giây) +meta.io.cloudbeaver.model.WebExpertSettingsProperties.keepAliveInterval.description = Không tự động ngắt kết nối \ No newline at end of file diff --git a/server/bundles/io.cloudbeaver.model/OSGI-INF/l10n/bundle_zh.properties b/server/bundles/io.cloudbeaver.model/OSGI-INF/l10n/bundle_zh.properties new file mode 100644 index 0000000000..662a0c1b41 --- /dev/null +++ b/server/bundles/io.cloudbeaver.model/OSGI-INF/l10n/bundle_zh.properties @@ -0,0 +1,3 @@ +meta.io.cloudbeaver.model.WebExpertSettingsProperties.autoCommit.name = 自动提交 +meta.io.cloudbeaver.model.WebExpertSettingsProperties.keepAliveInterval.name = 保持连接 (秒) +meta.io.cloudbeaver.model.WebExpertSettingsProperties.keepAliveInterval.description = 无自动断开连接 \ No newline at end of file diff --git a/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/model/WebConnectionConfig.java b/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/model/WebConnectionConfig.java index ba0030f7c7..d2787d958d 100644 --- a/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/model/WebConnectionConfig.java +++ b/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/model/WebConnectionConfig.java @@ -56,6 +56,7 @@ public class WebConnectionConfig { private boolean saveCredentials; private boolean sharedCredentials; private Map mainPropertyValues; + private Map expertSettingsValues; private Map providerProperties; private Map externalParameters; private List networkHandlersConfig; @@ -72,7 +73,6 @@ public class WebConnectionConfig { if (!CommonUtils.isEmpty(params)) { connectionId = JSONUtils.getString(params, "connectionId"); driverId = JSONUtils.getString(params, "driverId"); - readOnly = JSONUtils.getBoolean(params, "readOnly"); host = JSONUtils.getString(params, "host"); port = JSONUtils.getString(params, "port"); @@ -80,9 +80,6 @@ public class WebConnectionConfig { databaseName = JSONUtils.getString(params, "databaseName"); url = JSONUtils.getString(params, "url"); - keepAliveInterval = JSONUtils.getInteger(params, "keepAliveInterval", -1); - defaultAutoCommit = JSONUtils.getBoolean(params, "autocommit", true); - name = JSONUtils.getString(params, "name"); description = JSONUtils.getString(params, "description"); folder = JSONUtils.getString(params, "folder"); @@ -99,8 +96,18 @@ public class WebConnectionConfig { mainPropertyValues = JSONUtils.getObjectOrNull(params, "mainPropertyValues"); providerProperties = JSONUtils.getObjectOrNull(params, "providerProperties"); - defaultCatalogName = JSONUtils.getString(params, "defaultCatalogName"); - defaultSchemaName = JSONUtils.getString(params, "defaultSchemaName"); + + expertSettingsValues = JSONUtils.getObjectOrNull(params, "expertSettingsValues"); + keepAliveInterval = JSONUtils.getInteger( + expertSettingsValues != null ? expertSettingsValues : params, WebExpertSettingsProperties.PROP_KEEP_ALIVE_INTERVAL, -1); + readOnly = JSONUtils.getBoolean( + expertSettingsValues != null ? expertSettingsValues : params, WebExpertSettingsProperties.PROP_READ_ONLY); + defaultAutoCommit = JSONUtils.getBoolean( + expertSettingsValues != null ? expertSettingsValues : params, WebExpertSettingsProperties.PROP_AUTO_COMMIT, true); + defaultCatalogName = JSONUtils.getString( + expertSettingsValues != null ? expertSettingsValues : params, WebExpertSettingsProperties.PROP_DEFAULT_CATALOG); + defaultSchemaName = JSONUtils.getString( + expertSettingsValues != null ? expertSettingsValues : params, WebExpertSettingsProperties.PROP_DEFAULT_SCHEMA); String configType = JSONUtils.getString(params, "configurationType"); configurationType = configType == null ? null : DBPDriverConfigurationType.valueOf(configType); @@ -221,6 +228,11 @@ public class WebConnectionConfig { return mainPropertyValues; } + @Property + public Map getExpertSettingsValues() { + return expertSettingsValues; + } + @Property public Map getProviderProperties() { return providerProperties; 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 999b592db9..a49b1f16b5 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 @@ -417,6 +417,17 @@ public class WebConnectionInfo { return mainProperties; } + @Property + public Map getExpertSettingsValues() { + Map expertSettings = new LinkedHashMap<>(); + expertSettings.put(WebExpertSettingsProperties.PROP_AUTO_COMMIT, isAutocommit()); + expertSettings.put(WebExpertSettingsProperties.PROP_KEEP_ALIVE_INTERVAL, getKeepAliveInterval()); + expertSettings.put(WebExpertSettingsProperties.PROP_READ_ONLY, isReadOnly()); + expertSettings.put(WebExpertSettingsProperties.PROP_DEFAULT_CATALOG, getDefaultCatalogName()); + expertSettings.put(WebExpertSettingsProperties.PROP_DEFAULT_SCHEMA, getDefaultSchemaName()); + return expertSettings; + } + @Property public Map getProviderProperties() { return dataSourceContainer.getConnectionConfiguration().getProviderProperties(); diff --git a/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/model/WebExpertSettingsProperties.java b/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/model/WebExpertSettingsProperties.java new file mode 100644 index 0000000000..800d0f349a --- /dev/null +++ b/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/model/WebExpertSettingsProperties.java @@ -0,0 +1,87 @@ +package io.cloudbeaver.model; + +import org.jkiss.code.NotNull; +import org.jkiss.dbeaver.model.DBPObject; +import org.jkiss.dbeaver.model.connection.DBPDriver; +import org.jkiss.dbeaver.model.connection.DBPDriverConstants; +import org.jkiss.dbeaver.model.meta.IPropertyValueValidator; +import org.jkiss.dbeaver.model.meta.Property; +import org.jkiss.utils.CommonUtils; + +/** + * Web expert settings properties. Class for returning filtered expert settings properties in web interface. + */ +public class WebExpertSettingsProperties implements DBPObject { + public static final String PROP_READ_ONLY = "readOnly"; + public static final String PROP_AUTO_COMMIT = "autocommit"; + public static final String PROP_KEEP_ALIVE_INTERVAL = "keepAliveInterval"; + public static final String PROP_DEFAULT_CATALOG = "defaultCatalogName"; + public static final String PROP_DEFAULT_SCHEMA = "defaultSchemaName"; + + private final DBPDriver driver; + + public WebExpertSettingsProperties(@NotNull DBPDriver driver) { + this.driver = driver; + } + + @Property(order = 1, id = PROP_KEEP_ALIVE_INTERVAL, visibleIf = KeepAliveIntervalFieldValidator.class) + public int getKeepAliveInterval() { + return 0; + } + + @Property(order = 2, id = PROP_AUTO_COMMIT, visibleIf = AutoCommitFieldValidator.class) + public boolean isAutoCommit() { + return true; + } + + @Property(order = 3, id = PROP_READ_ONLY, visibleIf = ReadOnlyFieldValidator.class) + public boolean isReadOnly() { + return false; + } + + @Property(order = 4, id = PROP_DEFAULT_CATALOG, visibleIf = DefaultCatalogFieldVisibleValidator.class) + public String getDefaultCatalog() { + return null; + } + + @Property(order = 5, id = PROP_DEFAULT_SCHEMA, visibleIf = DefaultSchemaFieldVisibleValidator.class) + public String getDefaultSchema() { + return null; + } + + + public static class KeepAliveIntervalFieldValidator implements IPropertyValueValidator { + @Override + public boolean isValidValue(WebExpertSettingsProperties object, Object value) throws IllegalArgumentException { + return CommonUtils.toBoolean(!object.driver.isEmbedded(), true); + } + } + + public static class AutoCommitFieldValidator implements IPropertyValueValidator { + @Override + public boolean isValidValue(WebExpertSettingsProperties object, Object value) throws IllegalArgumentException { + return CommonUtils.toBoolean(object.driver.getDriverParameter(DBPDriverConstants.PARAM_SUPPORTS_TRANSACTIONS), true); + } + } + + public static class ReadOnlyFieldValidator implements IPropertyValueValidator { + @Override + public boolean isValidValue(WebExpertSettingsProperties object, Object value) throws IllegalArgumentException { + return CommonUtils.toBoolean(object.driver.getDriverParameter(DBPDriverConstants.PARAM_SUPPORTS_READ_ONLY_MODE), true); + } + } + + public static class DefaultCatalogFieldVisibleValidator implements IPropertyValueValidator { + @Override + public boolean isValidValue(WebExpertSettingsProperties object, Object value) throws IllegalArgumentException { + return CommonUtils.toBoolean(object.driver.getDriverParameter(DBPDriverConstants.PARAM_SUPPORTS_CATALOG_SELECTION), true); + } + } + + public static class DefaultSchemaFieldVisibleValidator implements IPropertyValueValidator { + @Override + public boolean isValidValue(WebExpertSettingsProperties object, Object value) throws IllegalArgumentException { + return CommonUtils.toBoolean(object.driver.getDriverParameter(DBPDriverConstants.PARAM_SUPPORTS_SCHEMA_SELECTION), true); + } + } +} diff --git a/server/bundles/io.cloudbeaver.server/OSGI-INF/l10n/bundle.properties b/server/bundles/io.cloudbeaver.server/OSGI-INF/l10n/bundle.properties index 6cf1ed3703..3d208419e0 100644 --- a/server/bundles/io.cloudbeaver.server/OSGI-INF/l10n/bundle.properties +++ b/server/bundles/io.cloudbeaver.server/OSGI-INF/l10n/bundle.properties @@ -1,2 +1,2 @@ log.api.graphql.debug = Log GraphQL requests to console -log.api.graphql.debug.description = Enable detailed logging of GraphQL queries in the server log, including all provided variables \ No newline at end of file +log.api.graphql.debug.description = Enable detailed logging of GraphQL queries in the server log, including all provided variables diff --git a/server/bundles/io.cloudbeaver.server/OSGI-INF/l10n/bundle_ru.properties b/server/bundles/io.cloudbeaver.server/OSGI-INF/l10n/bundle_ru.properties index c73f9b478b..ddb9a9c941 100644 --- a/server/bundles/io.cloudbeaver.server/OSGI-INF/l10n/bundle_ru.properties +++ b/server/bundles/io.cloudbeaver.server/OSGI-INF/l10n/bundle_ru.properties @@ -1,2 +1,2 @@ log.api.graphql.debug =Логировать GraphQL-запросы в консоль -log.api.graphql.debug.description = Включите подробное логирование запросов GraphQL в журнале сервера, включая все предоставленные переменные \ No newline at end of file +log.api.graphql.debug.description = Включите подробное логирование запросов GraphQL в журнале сервера, включая все предоставленные переменные diff --git a/server/bundles/io.cloudbeaver.server/schema/service.core.graphqls b/server/bundles/io.cloudbeaver.server/schema/service.core.graphqls index 0d7cdbbf43..42066205ea 100644 --- a/server/bundles/io.cloudbeaver.server/schema/service.core.graphqls +++ b/server/bundles/io.cloudbeaver.server/schema/service.core.graphqls @@ -351,6 +351,9 @@ type DriverInfo { """ providerProperties: [ObjectPropertyInfo!]! + "Expert driver settings properties. Returns properties (like keep-alive interval) that are not often used and can be hidden in UI" + expertSettingsProperties: [ObjectPropertyInfo!]! @since(version: "25.2.1") + "False for drivers which do not support authentication." anonymousAccess: Boolean "Default auth model that is used for this driver (see authModels)" @@ -486,6 +489,9 @@ type ConnectionInfo { "Main connection properties. Contains host, port, database, server name fields" mainPropertyValues: Object @since(version: "24.1.2") + "Expert connection settings. Contains expert settings properties (like keep-alive interval or auto-commit) that are not often used" + expertSettingsValues: Object @since(version: "25.2.1") + "Connection keep-alive interval in seconds" keepAliveInterval: Int! "Defines if the connection is in auto-commit mode" @@ -672,6 +678,9 @@ input ConnectionConfig { "Host, port, serverName, databaseName are also stored in mainPropertyValues for custom pages" mainPropertyValues: Object @since(version: "24.1.2") + "Keep-alive, auto-commit, read-only and other expert settings are stored in expertSettingsValues" + expertSettingsValues: Object @since(version: "25.2.1") + "Sets connection URL jdbc:{driver}://{host}[:{port}]/[{database}]" url: String @@ -679,13 +688,13 @@ input ConnectionConfig { properties: Object "Set keep-alive interval" - keepAliveInterval: Int + keepAliveInterval: Int @deprecated(reason: "25.2.1 use expertPropertyValues instead") "Sets auto-commit connection state" - autocommit: Boolean + autocommit: Boolean @deprecated(reason: "25.2.1 use expertPropertyValues instead") "Sets read-only connection state" - readOnly: Boolean + readOnly: Boolean @deprecated(reason: "25.2.1 use expertPropertyValues instead") # User credentials @@ -721,9 +730,9 @@ input ConnectionConfig { "Configuration type (MANUAL, URL)" configurationType: DriverConfigurationType "Sets catalog name for the connection" - defaultCatalogName: String @since(version: "25.0.5") + defaultCatalogName: String @since(version: "25.0.5") @deprecated(reason: "25.2.1 use expertPropertyValues instead") "Sets schema name for the connection" - defaultSchemaName: String @since(version: "25.0.5") + defaultSchemaName: String @since(version: "25.0.5") @deprecated(reason: "25.2.1 use expertPropertyValues instead") } #################################################### 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 fc798da397..096afc7d6c 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 @@ -257,6 +257,10 @@ public class WebDatabaseDriverInfo { .toArray(WebPropertyInfo[]::new); } + public WebPropertyInfo[] getExpertSettingsProperties() { + return WebServiceUtils.getObjectFilteredProperties(webSession, new WebExpertSettingsProperties(driver), null); + } + @Property public boolean isEnabled() { return WebServiceUtils.isDriverEnabled(driver); diff --git a/webapp/packages/core-blocks/src/ObjectPropertyInfo/ObjectPropertyInfoForm/RenderField.tsx b/webapp/packages/core-blocks/src/ObjectPropertyInfo/ObjectPropertyInfoForm/RenderField.tsx index 41d95737d4..4c25c45bd0 100644 --- a/webapp/packages/core-blocks/src/ObjectPropertyInfo/ObjectPropertyInfoForm/RenderField.tsx +++ b/webapp/packages/core-blocks/src/ObjectPropertyInfo/ObjectPropertyInfoForm/RenderField.tsx @@ -87,6 +87,7 @@ export const RenderField = observer(function RenderField({ const required = property.required && !readonly; const value = getObjectPropertyValue(property); const defaultValue = getObjectPropertyDefaultValue(property); + const hint = property.hint === property.displayName ? undefined : property.hint; if (controlType === 'link') { return ( @@ -178,7 +179,7 @@ export const RenderField = observer(function RenderField({ title={property.description} disabled={disabled} readOnly={readonly} - description={property.hint} + description={hint} className={className} > {property.displayName ?? ''} @@ -253,7 +254,7 @@ export const RenderField = observer(function RenderField({ state={state} defaultState={defaultState || { [property.id!]: defaultValue }} autoHide={autoHide} - description={property.hint} + description={hint} placeholder={passwordSavedMessage} readOnly={readonly || disabled} autoComplete={RESERVED_KEYWORDS.includes(autofillToken) ? autofillToken : `${autofillToken} ${property.id}`} @@ -275,7 +276,7 @@ export const RenderField = observer(function RenderField({ name={property.id!} value={value} defaultValue={defaultValue} - description={property.hint} + description={hint} placeholder={passwordSavedMessage} readOnly={readonly || disabled} autoComplete={RESERVED_KEYWORDS.includes(autofillToken) ? autofillToken : `${autofillToken} ${property.id}`} diff --git a/webapp/packages/core-connections/src/DBDriverExpertSettingsResource.ts b/webapp/packages/core-connections/src/DBDriverExpertSettingsResource.ts new file mode 100644 index 0000000000..cbb9231f7b --- /dev/null +++ b/webapp/packages/core-connections/src/DBDriverExpertSettingsResource.ts @@ -0,0 +1,57 @@ +/* + * CloudBeaver - Cloud Database Manager + * Copyright (C) 2020-2025 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 { CachedMapResource, isResourceAlias, ResourceKeyUtils, type ResourceKey } from '@cloudbeaver/core-resource'; +import { GraphQLService } from '@cloudbeaver/core-sdk'; +import { injectable } from '@cloudbeaver/core-di'; +import { SessionDataResource } from '@cloudbeaver/core-root'; + +import { DBDriverResource, type DriverPropertyInfo } from './DBDriverResource.js'; + +@injectable(() => [GraphQLService, DBDriverResource, SessionDataResource]) +export class DBDriverExpertSettingsResource extends CachedMapResource { + constructor( + private readonly graphQLService: GraphQLService, + private readonly dbDriverResource: DBDriverResource, + private readonly sessionDataResource: SessionDataResource, + ) { + super(); + + this.sessionDataResource.outdateResource(this); + this.sync(this.dbDriverResource); + this.dbDriverResource.onItemDelete.addHandler(this.delete.bind(this)); + } + + protected async loader(originalKey: ResourceKey): Promise> { + if (isResourceAlias(originalKey)) { + throw new Error('Aliases not supported by this resource.'); + } + + const values: DriverPropertyInfo[][] = []; + + await ResourceKeyUtils.forEachAsync(originalKey, async key => { + const { drivers } = await this.graphQLService.sdk.getDriverExpertProperties({ driverId: key }); + + if (drivers.length === 0) { + throw new Error('Driver not found'); + } + + const driver = drivers[0]!; + + values.push(driver.expertSettingsProperties); + }); + + this.set(ResourceKeyUtils.toList(originalKey), values); + + return this.data; + } + + protected validateKey(key: string): boolean { + return typeof key === 'string'; + } +} diff --git a/webapp/packages/core-connections/src/DBDriverResource.ts b/webapp/packages/core-connections/src/DBDriverResource.ts index 6e56f5de07..d013a7935c 100644 --- a/webapp/packages/core-connections/src/DBDriverResource.ts +++ b/webapp/packages/core-connections/src/DBDriverResource.ts @@ -16,6 +16,7 @@ import { type DatabaseDriverFragment, DriverConfigurationType, type DriverListQueryVariables, + type DriverPropertyInfoFragment, GraphQLService, } from '@cloudbeaver/core-sdk'; import { isArraysEqual } from '@cloudbeaver/core-utils'; @@ -27,6 +28,8 @@ export const NEW_DRIVER_SYMBOL = Symbol('new-driver'); export type NewDBDriver = DBDriver & { [NEW_DRIVER_SYMBOL]: boolean; timestamp: number }; export type DBDriverResourceIncludes = Omit; +export type DriverPropertyInfo = DriverPropertyInfoFragment; + @injectable(() => [ServerConfigResource, GraphQLService, WorkspaceConfigEventHandler, AppAuthService]) export class DBDriverResource extends CachedMapResource { get enabledDrivers() { @@ -41,6 +44,7 @@ export class DBDriverResource extends CachedMapResource {}, diff --git a/webapp/packages/core-connections/src/index.ts b/webapp/packages/core-connections/src/index.ts index 2b10645eb9..3fb8a5cf2a 100644 --- a/webapp/packages/core-connections/src/index.ts +++ b/webapp/packages/core-connections/src/index.ts @@ -63,5 +63,6 @@ export * from './useConnectionInfo.js'; export * from './useDBDriver.js'; export * from './USER_NAME_PROPERTY_ID.js'; export * from './parseConnectionKey.js'; +export * from './DBDriverExpertSettingsResource.js'; export { manifest as coreConnectionsManifest } from './manifest.js'; diff --git a/webapp/packages/core-connections/src/locales/de.ts b/webapp/packages/core-connections/src/locales/de.ts index edc829508c..eeed1fdf8a 100644 --- a/webapp/packages/core-connections/src/locales/de.ts +++ b/webapp/packages/core-connections/src/locales/de.ts @@ -27,7 +27,6 @@ export default [ ['connections_connection_edit_search', 'Suchen'], ['connections_connection_edit_search_hosts', 'Hostnamen'], ['connections_connection_expert_settings', 'Expert settings'], - ['connections_connection_read_only', 'Read-only connection'], ['connections_connection_address', 'Adresse'], ['connections_connection_folder', 'Ordner'], ['connections_connection_name', 'Verbindungsname'], @@ -45,9 +44,6 @@ export default [ ['connections_network_handler_ssh_tunnel_auth_type', 'Authentifizierungsmethode'], ['connections_network_handler_ssh_tunnel_advanced_settings', 'Erweiterte Einstellungen'], ['connections_not_found', 'Es wurden keine Datenbankverbindungen gefunden'], - ['connections_connection_autocommit', 'Auto commit'], - ['connections_connection_default_catalog', 'Default catalog'], - ['connections_connection_default_schema', 'Default schema'], ['core_connections_settings_disable', 'Disable'], ['core_connections_settings_disable_description', 'Disable the ability to create new connections'], diff --git a/webapp/packages/core-connections/src/locales/en.ts b/webapp/packages/core-connections/src/locales/en.ts index 2298a4161c..ac255bbaf6 100644 --- a/webapp/packages/core-connections/src/locales/en.ts +++ b/webapp/packages/core-connections/src/locales/en.ts @@ -52,12 +52,6 @@ export default [ ['connections_connection_create_fail', 'Fail to create connection'], ['connections_connection_save_fail', 'Fail to save connection'], ['connections_connection_expert_settings', 'Expert settings'], - ['connections_connection_keep_alive', 'Keep alive (in seconds)'], - ['connections_connection_read_only', 'Read-only connection'], - ['connections_connection_autocommit', 'Auto commit'], - ['connections_connection_default_catalog', 'Default catalog'], - ['connections_connection_default_schema', 'Default schema'], - ['connections_connection_keep_alive_tooltip', 'No auto disconnect'], ['connections_network_handler_test', 'Test Tunnel'], ['connections_network_handler_test_fail', 'Tunnel test failed'], ['connections_network_handler_test_success', 'Tunnel test success'], diff --git a/webapp/packages/core-connections/src/locales/fr.ts b/webapp/packages/core-connections/src/locales/fr.ts index 929224dfda..e5dea8a7a2 100644 --- a/webapp/packages/core-connections/src/locales/fr.ts +++ b/webapp/packages/core-connections/src/locales/fr.ts @@ -49,7 +49,6 @@ export default [ ['connections_connection_configuration', 'Configuration'], ['connections_connection_host', 'Hôte'], ['connections_connection_port', 'Port'], - ['connections_connection_read_only', 'Read-only connection'], ['core_connections_connection_create_success', 'Connection was created'], ['core_connections_connection_update_success', 'Connection was updated'], ['connections_connection_test', 'Tester'], @@ -58,11 +57,6 @@ export default [ ['connections_connection_create_fail', 'Échec de la création de la connexion'], ['connections_connection_save_fail', 'Échec de la sauvegarde de la connexion'], ['connections_connection_expert_settings', 'Expert settings'], - ['connections_connection_keep_alive', 'Garder actif (en secondes)'], - ['connections_connection_autocommit', 'Auto commit'], - ['connections_connection_default_catalog', 'Default catalog'], - ['connections_connection_default_schema', 'Default schema'], - ['connections_connection_keep_alive_tooltip', 'Pas de déconnexion automatique'], ['connections_network_handler_test', 'Tester le tunnel'], ['connections_network_handler_test_fail', 'Échec du test du tunnel'], ['connections_network_handler_test_success', 'Test du tunnel réussi'], diff --git a/webapp/packages/core-connections/src/locales/it.ts b/webapp/packages/core-connections/src/locales/it.ts index 77006e3e02..b8b6453320 100644 --- a/webapp/packages/core-connections/src/locales/it.ts +++ b/webapp/packages/core-connections/src/locales/it.ts @@ -50,12 +50,6 @@ export default [ ['connections_connection_create_fail', 'Errore di creazione connessione'], ['connections_connection_save_fail', 'Errore di salvataggio connessione'], ['connections_connection_expert_settings', 'Expert settings'], - ['connections_connection_keep_alive', 'Keep alive (in seconds)'], - ['connections_connection_autocommit', 'Auto commit'], - ['connections_connection_default_catalog', 'Default catalog'], - ['connections_connection_default_schema', 'Default schema'], - ['connections_connection_keep_alive_tooltip', 'No auto disconnect'], - ['connections_connection_read_only', 'Read-only connection'], ['connections_network_handler_test', 'Prova il Tunnel'], ['connections_network_handler_test_fail', 'Prova del Tunnel fallita'], ['connections_network_handler_test_success', 'Prova del Tunnel terminata con successo'], diff --git a/webapp/packages/core-connections/src/locales/ru.ts b/webapp/packages/core-connections/src/locales/ru.ts index 2ff170e8b4..d2168a5068 100644 --- a/webapp/packages/core-connections/src/locales/ru.ts +++ b/webapp/packages/core-connections/src/locales/ru.ts @@ -61,12 +61,6 @@ export default [ ['connections_connection_create_fail', 'Не удалось создать подключение'], ['connections_connection_save_fail', 'Не удалось сохранить подключение'], ['connections_connection_expert_settings', 'Продвинутые настройки'], - ['connections_connection_keep_alive', 'Поддерживать соединение (в секундах)'], - ['connections_connection_autocommit', 'Авто коммит'], - ['connections_connection_default_catalog', 'Каталог по умолчанию'], - ['connections_connection_default_schema', 'Схема по умолчанию'], - ['connections_connection_keep_alive_tooltip', 'Не отключать соединение'], - ['connections_connection_read_only', 'Разрешить только чтение'], ['connections_network_handler_test', 'Проверить подключение'], ['connections_network_handler_test_fail', 'Не удалось установить соединение'], ['connections_network_handler_test_success', 'Соединение установлено'], diff --git a/webapp/packages/core-connections/src/locales/vi.ts b/webapp/packages/core-connections/src/locales/vi.ts index 93f5690fee..321705cae2 100644 --- a/webapp/packages/core-connections/src/locales/vi.ts +++ b/webapp/packages/core-connections/src/locales/vi.ts @@ -66,10 +66,6 @@ export default [ ['connections_connection_create_fail', 'Tạo kết nối thất bại'], ['connections_connection_save_fail', 'Lưu kết nối thất bại'], ['connections_connection_expert_settings', 'Cài đặt nâng cao'], - ['connections_connection_keep_alive', 'Giữ kết nối (tính bằng giây)'], - ['connections_connection_read_only', 'Kết nối chỉ đọc'], - ['connections_connection_autocommit', 'Tự động commit'], - ['connections_connection_keep_alive_tooltip', 'Không tự động ngắt kết nối'], ['connections_network_handler_test', 'Kiểm tra Tunnel'], ['connections_network_handler_test_fail', 'Kiểm tra tunnel thất bại'], ['connections_network_handler_test_success', 'Kiểm tra tunnel thành công'], diff --git a/webapp/packages/core-connections/src/locales/zh.ts b/webapp/packages/core-connections/src/locales/zh.ts index 7f40e9b912..b6aab8dd04 100644 --- a/webapp/packages/core-connections/src/locales/zh.ts +++ b/webapp/packages/core-connections/src/locales/zh.ts @@ -44,12 +44,6 @@ export default [ ['connections_connection_create_fail', '无法创建连接'], ['connections_connection_save_fail', '无法保存连接'], ['connections_connection_expert_settings', '专业设置'], - ['connections_connection_keep_alive', '保持连接 (秒)'], - ['connections_connection_autocommit', '自动提交'], - ['connections_connection_default_catalog', 'Default catalog'], - ['connections_connection_default_schema', 'Default schema'], - ['connections_connection_keep_alive_tooltip', '无自动断开连接'], - ['connections_connection_read_only', 'Read-only connection'], ['connections_network_handler_test', '测试隧道'], ['connections_network_handler_test_fail', '隧道测试失败'], ['connections_network_handler_test_success', '隧道测试成功'], diff --git a/webapp/packages/core-connections/src/module.ts b/webapp/packages/core-connections/src/module.ts index 65b18d43db..991dbcaf8a 100644 --- a/webapp/packages/core-connections/src/module.ts +++ b/webapp/packages/core-connections/src/module.ts @@ -32,6 +32,7 @@ import { ConnectionExecutionContextService } from './ConnectionExecutionContext/ import { ConnectionFolderEventHandler } from './ConnectionFolderEventHandler.js'; import { ConnectionExecutionContextResource } from './ConnectionExecutionContext/ConnectionExecutionContextResource.js'; import { ConnectionDialectResource } from './ConnectionDialectResource.js'; +import { DBDriverExpertSettingsResource } from './DBDriverExpertSettingsResource.js'; ModuleRegistry.add({ name: '@cloudbeaver/core-connections', @@ -57,10 +58,12 @@ ModuleRegistry.add({ .addSingleton(Dependency, proxy(ConnectionInfoCustomOptionsResource)) .addSingleton(Dependency, proxy(ConnectionFolderResource)) .addSingleton(Dependency, proxy(ConnectionExecutionContextResource)) + .addSingleton(Dependency, proxy(DBDriverExpertSettingsResource)) .addSingleton(ConnectionDialectResource) .addSingleton(NetworkHandlerResource) .addSingleton(NavNodeExtensionsService) .addSingleton(DBDriverResource) + .addSingleton(DBDriverExpertSettingsResource) .addSingleton(DatabaseAuthModelsResource) .addSingleton(ContainerResource) .addSingleton(ConnectionToolsResource) diff --git a/webapp/packages/core-sdk/src/getObjectPropertyValueType.ts b/webapp/packages/core-sdk/src/getObjectPropertyValueType.ts index 2de6a3cd70..3289ab6d9f 100644 --- a/webapp/packages/core-sdk/src/getObjectPropertyValueType.ts +++ b/webapp/packages/core-sdk/src/getObjectPropertyValueType.ts @@ -16,7 +16,7 @@ export function getObjectPropertyValueType(property: ObjectPropertyInfo): Object return 'password'; } - if (dataType === 'integer') { + if (dataType === 'integer' || dataType === 'int') { return 'number'; } diff --git a/webapp/packages/core-sdk/src/queries/connections/getDriverExpertProperties.gql b/webapp/packages/core-sdk/src/queries/connections/getDriverExpertProperties.gql new file mode 100644 index 0000000000..c77c0eef63 --- /dev/null +++ b/webapp/packages/core-sdk/src/queries/connections/getDriverExpertProperties.gql @@ -0,0 +1,7 @@ +query getDriverExpertProperties($driverId: ID) { + drivers: driverList(id: $driverId) { + expertSettingsProperties { + ...DriverPropertyInfo + } + } +} diff --git a/webapp/packages/core-sdk/src/queries/fragments/DatabaseConnectionCustomOptions.gql b/webapp/packages/core-sdk/src/queries/fragments/DatabaseConnectionCustomOptions.gql index 40fa317af8..a7c3ecf159 100644 --- a/webapp/packages/core-sdk/src/queries/fragments/DatabaseConnectionCustomOptions.gql +++ b/webapp/packages/core-sdk/src/queries/fragments/DatabaseConnectionCustomOptions.gql @@ -12,10 +12,6 @@ fragment DatabaseConnectionCustomOptions on ConnectionInfo { description folder driverId - keepAliveInterval - autocommit - defaultCatalogName - defaultSchemaName - readOnly mainPropertyValues + expertSettingsValues } diff --git a/webapp/packages/plugin-connections/src/ConnectionForm/Options/AdvancedPropertiesForm.tsx b/webapp/packages/plugin-connections/src/ConnectionForm/Options/AdvancedPropertiesForm.tsx index df18e6c9dd..c1ab3a2689 100644 --- a/webapp/packages/plugin-connections/src/ConnectionForm/Options/AdvancedPropertiesForm.tsx +++ b/webapp/packages/plugin-connections/src/ConnectionForm/Options/AdvancedPropertiesForm.tsx @@ -7,17 +7,9 @@ */ import { observer } from 'mobx-react-lite'; -import { Container, Expandable, FieldCheckbox, Flex, Group, InputField, useTranslate } from '@cloudbeaver/core-blocks'; +import { Container, Expandable, Group, ObjectPropertyInfoForm, useResource, useTranslate } from '@cloudbeaver/core-blocks'; import type { ConnectionConfig } from '@cloudbeaver/core-sdk'; - -const MAX_KEEP_ALIVE_INTERVAL = 32767; -const DEFAULT_CONFIG: ConnectionConfig = { - keepAliveInterval: 0, - autocommit: true, - defaultCatalogName: '', - defaultSchemaName: '', - readOnly: false, -}; +import { DBDriverExpertSettingsResource } from '@cloudbeaver/core-connections'; interface Props { config: ConnectionConfig; @@ -27,70 +19,17 @@ interface Props { export const AdvancedPropertiesForm = observer(function AdvancedPropertiesForm({ config, disabled, readonly }) { const translate = useTranslate(); + const properties = useResource(AdvancedPropertiesForm, DBDriverExpertSettingsResource, config.driverId ?? null); + + if (!properties.data?.length) { + return null; + } return ( - - {translate('connections_connection_keep_alive')} - - - - {translate('connections_connection_autocommit')} - - - - {translate('connections_connection_read_only')} - - - - - {translate('connections_connection_default_catalog')} - - - - {translate('connections_connection_default_schema')} - - + diff --git a/webapp/packages/plugin-connections/src/ConnectionForm/Options/ConnectionFormOptionsPart.ts b/webapp/packages/plugin-connections/src/ConnectionForm/Options/ConnectionFormOptionsPart.ts index aa37be1975..dfcb202dea 100644 --- a/webapp/packages/plugin-connections/src/ConnectionForm/Options/ConnectionFormOptionsPart.ts +++ b/webapp/packages/plugin-connections/src/ConnectionForm/Options/ConnectionFormOptionsPart.ts @@ -16,6 +16,7 @@ import { ConnectionInfoResource, createConnectionParam, DatabaseAuthModelsResource, + DBDriverExpertSettingsResource, DBDriverResource, type ConnectionInfoAuthProperties, type DBDriver, @@ -45,9 +46,9 @@ const defaultStateGetter = (connectionId?: string, credentials?: Record 0) { this.state.mainPropertyValues = prepareDynamicProperties(driver.mainProperties, this.state.mainPropertyValues!, this.state.configurationType); } + + if (expertSettings.length > 0) { + this.state.expertSettingsValues = prepareDynamicProperties(expertSettings, this.state.expertSettingsValues!); + } } private async getConnectionAuthModelProperties(authModelId: string, connectionInfo?: ConnectionInfoAuthProperties): Promise { diff --git a/webapp/packages/plugin-connections/src/ConnectionForm/Options/IConnectionConfig.ts b/webapp/packages/plugin-connections/src/ConnectionForm/Options/IConnectionConfig.ts index 8b0b7dfc32..4ea42307b1 100644 --- a/webapp/packages/plugin-connections/src/ConnectionForm/Options/IConnectionConfig.ts +++ b/webapp/packages/plugin-connections/src/ConnectionForm/Options/IConnectionConfig.ts @@ -13,7 +13,6 @@ export const CONNECTION_PROPERTIES_SCHEMA = schema.record(schema.string(), schem export const CONNECTION_CONFIG_SCHEMA = schema.object({ authModelId: schema.string().optional(), - autocommit: schema.boolean().optional(), configurationType: schema.enum([DriverConfigurationType.Manual, DriverConfigurationType.Url]).optional(), connectionId: schema.string().optional(), credentials: schema.record(schema.string(), schema.any()).optional(), @@ -23,16 +22,13 @@ export const CONNECTION_CONFIG_SCHEMA = schema.object({ driverId: schema.string().optional(), folder: schema.string().optional(), host: schema.string().optional(), - keepAliveInterval: schema.number().optional(), - defaultCatalogName: schema.string().optional(), - defaultSchemaName: schema.string().optional(), mainPropertyValues: schema.record(schema.string(), schema.any()).optional(), + expertSettingsValues: schema.record(schema.string(), schema.any()).optional(), name: schema.string().optional(), networkHandlersConfig: schema.array(CONNECTION_NETWORK_HANDLER_SCHEMA).optional(), port: schema.string().optional(), properties: CONNECTION_PROPERTIES_SCHEMA.optional(), providerProperties: schema.record(schema.string(), schema.any()).optional(), - readOnly: schema.boolean().optional(), saveCredentials: schema.boolean().optional(), selectedSecretId: schema.string().optional(), serverName: schema.string().optional(), diff --git a/webapp/packages/plugin-connections/src/ConnectionForm/Options/getConnectionFormOptionsPart.ts b/webapp/packages/plugin-connections/src/ConnectionForm/Options/getConnectionFormOptionsPart.ts index d57342623f..074964aa1b 100644 --- a/webapp/packages/plugin-connections/src/ConnectionForm/Options/getConnectionFormOptionsPart.ts +++ b/webapp/packages/plugin-connections/src/ConnectionForm/Options/getConnectionFormOptionsPart.ts @@ -14,6 +14,7 @@ import { ConnectionInfoProviderPropertiesResource, ConnectionInfoResource, DatabaseAuthModelsResource, + DBDriverExpertSettingsResource, DBDriverResource, } from '@cloudbeaver/core-connections'; import { ProjectInfoResource } from '@cloudbeaver/core-projects'; @@ -37,6 +38,7 @@ export function getConnectionFormOptionsPart(formState: IFormState