diff --git a/config/sample-databases/DefaultConfiguration/GlobalConfiguration/.dbeaver/data-sources.json b/config/GlobalConfiguration/.dbeaver/data-sources.json similarity index 100% rename from config/sample-databases/DefaultConfiguration/GlobalConfiguration/.dbeaver/data-sources.json rename to config/GlobalConfiguration/.dbeaver/data-sources.json diff --git a/config/sample-databases/DefaultConfiguration/GlobalConfiguration/.dbeaver/provided-connections.json b/config/GlobalConfiguration/.dbeaver/provided-connections.json similarity index 100% rename from config/sample-databases/DefaultConfiguration/GlobalConfiguration/.dbeaver/provided-connections.json rename to config/GlobalConfiguration/.dbeaver/provided-connections.json diff --git a/config/sample-databases/DefaultConfiguration/cloudbeaver.conf b/config/core/cloudbeaver.conf similarity index 100% rename from config/sample-databases/DefaultConfiguration/cloudbeaver.conf rename to config/core/cloudbeaver.conf diff --git a/config/sample-databases/README.md b/config/sample-databases/README.md deleted file mode 100644 index a6fe87c936..0000000000 --- a/config/sample-databases/README.md +++ /dev/null @@ -1,3 +0,0 @@ -### Sample databases - -Provides access to locally deployed SQLite sample database diff --git a/config/sample-databases/SQLiteConfiguration/GlobalConfiguration/.dbeaver/data-sources.json b/config/sample-databases/SQLiteConfiguration/GlobalConfiguration/.dbeaver/data-sources.json deleted file mode 100644 index 27dbbe907a..0000000000 --- a/config/sample-databases/SQLiteConfiguration/GlobalConfiguration/.dbeaver/data-sources.json +++ /dev/null @@ -1,39 +0,0 @@ -{ - "folders": {}, - "connections": { - "sqlite_xerial-sample-database": { - "provider": "generic", - "driver": "sqlite_jdbc", - "name": "SQLite - Chinook (Sample)", - "save-password": true, - "navigator-show-only-entities": false, - "navigator-hide-folders": false, - "read-only": false, - "template": false, - "configuration": { - "database": "${application.path}/../samples/db/Chinook.sqlitedb", - "type": "dev", - "auth-model": "native" - } - }, - "postgresql-template-1": { - "provider": "postgresql", - "driver": "postgres-jdbc", - "name": "PostgreSQL (Template)", - "save-password": false, - "show-system-objects": false, - "read-only": true, - "template": true, - "configuration": { - "host": "localhost", - "port": "5432", - "database": "postgres", - "url": "jdbc:postgresql://localhost:5432/postgres", - "type": "dev", - "provider-properties": { - "@dbeaver-show-non-default-db@": "false" - } - } - } - } -} diff --git a/config/sample-databases/SQLiteConfiguration/GlobalConfiguration/.dbeaver/provided-connections.json b/config/sample-databases/SQLiteConfiguration/GlobalConfiguration/.dbeaver/provided-connections.json deleted file mode 100644 index edc5802a0a..0000000000 --- a/config/sample-databases/SQLiteConfiguration/GlobalConfiguration/.dbeaver/provided-connections.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "folders": {}, - "connections": {} -} diff --git a/config/sample-databases/SQLiteConfiguration/cloudbeaver.conf b/config/sample-databases/SQLiteConfiguration/cloudbeaver.conf deleted file mode 100644 index da744d4914..0000000000 --- a/config/sample-databases/SQLiteConfiguration/cloudbeaver.conf +++ /dev/null @@ -1,99 +0,0 @@ -{ - server: { - serverPort: "${CLOUDBEAVER_SERVICE_PORT:8978}", - - workspaceLocation: "${CLOUDBEAVER_WORKSPACE_LOCATION:workspace}", - contentRoot: "web", - driversLocation: "drivers", - - rootURI: "${CLOUDBEAVER_ROOT_URI:/}", - serviceURI: "/api/", - - productSettings: { - # Global properties - core.theming.theme: 'light', - core.localization.localization: 'en', - plugin.sql-editor.autoSave: true, - plugin.sql-editor.disabled: false, - # max size of the file that can be uploaded to the editor (in kilobytes) - plugin.sql-editor.maxFileSize: 10240, - plugin.log-viewer.disabled: false, - plugin.log-viewer.logBatchSize: 1000, - plugin.log-viewer.maxLogRecords: 2000, - sql.proposals.insert.table.alias: PLAIN - }, - - expireSessionAfterPeriod: "${CLOUDBEAVER_EXPIRE_SESSION_AFTER_PERIOD:1800000}", - - develMode: "${CLOUDBEAVER_DEVEL_MODE:false}", - - enableSecurityManager: false, - - database: { - driver: "${CLOUDBEAVER_DB_DRIVER:h2_embedded_v2}", - url: "${CLOUDBEAVER_DB_URL:jdbc:h2:${workspace}/.data/cb.h2v2.dat}", - schema: "${CLOUDBEAVER_DB_SCHEMA:''}", - user: "${CLOUDBEAVER_DB_USER:''}", - password: "${CLOUDBEAVER_DB_PASSWORD:''}", - initialDataConfiguration: "${CLOUDBEAVER_DB_INITIAL_DATA:conf/initial-data.conf}", - pool: { - minIdleConnections: "${CLOUDBEAVER_DB_MIN_IDLE_CONNECTIONS:4}", - maxIdleConnections: "${CLOUDBEAVER_DB_MAX_IDLE_CONNECTIONS:10}", - maxConnections: "${CLOUDBEAVER_DB_MAX_CONNECTIONS:100}", - validationQuery: "${CLOUDBEAVER_DB_VALIDATION_QUERY:SELECT 1}" - }, - backupEnabled: "${CLOUDBEAVER_DB_BACKUP_ENABLED:true}" - }, - sm: { - enableBruteForceProtection: "${CLOUDBEAVER_BRUTE_FORCE_PROTECTION_ENABLED:true}", - maxFailedLogin: "${CLOUDBEAVER_MAX_FAILED_LOGINS:10}", - minimumLoginTimeout: "${CLOUDBEAVER_MINIMUM_LOGIN_TIMEOUT:1}", - blockLoginPeriod: "${CLOUDBEAVER_BLOCK_PERIOD:300}", - passwordPolicy: { - minLength: "${CLOUDBEAVER_POLICY_MIN_LENGTH:8}", - requireMixedCase: "${CLOUDBEAVER_POLICY_REQUIRE_MIXED_CASE:true}", - minNumberCount: "${CLOUDBEAVER_POLICY_MIN_NUMBER_COUNT:1}", - minSymbolCount: "${CLOUDBEAVER_POLICY_MIN_SYMBOL_COUNT:0}" - } - } - - }, - app: { - anonymousAccessEnabled: "${CLOUDBEAVER_APP_ANONYMOUS_ACCESS_ENABLED:true}", - anonymousUserRole: user, - grantConnectionsAccessToAnonymousTeam: "${CLOUDBEAVER_APP_GRANT_CONNECTIONS_ACCESS_TO_ANONYMOUS_TEAM:false}", - supportsCustomConnections: "${CLOUDBEAVER_APP_SUPPORTS_CUSTOM_CONNECTIONS:false}", - showReadOnlyConnectionInfo: "${CLOUDBEAVER_APP_READ_ONLY_CONNECTION_INFO:false}", - systemVariablesResolvingEnabled: "${CLOUDBEAVER_SYSTEM_VARIABLES_RESOLVING_ENABLED:false}", - - forwardProxy: "${CLOUDBEAVER_APP_FORWARD_PROXY:false}", - - publicCredentialsSaveEnabled: "${CLOUDBEAVER_APP_PUBLIC_CREDENTIALS_SAVE_ENABLED:true}", - adminCredentialsSaveEnabled: "${CLOUDBEAVER_APP_ADMIN_CREDENTIALS_SAVE_ENABLED:true}", - - resourceManagerEnabled: "${CLOUDBEAVER_APP_RESOURCE_MANAGER_ENABLED:true}", - - resourceQuotas: { - dataExportFileSizeLimit: "${CLOUDBEAVER_RESOURCE_QUOTA_DATA_EXPORT_FILE_SIZE_LIMIT:10000000}", - resourceManagerFileSizeLimit: "${CLOUDBEAVER_RESOURCE_QUOTA_RESOURCE_MANAGER_FILE_SIZE_LIMIT:500000}", - sqlMaxRunningQueries: "${CLOUDBEAVER_RESOURCE_QUOTA_SQL_MAX_RUNNING_QUERIES:100}", - sqlResultSetRowsLimit: "${CLOUDBEAVER_RESOURCE_QUOTA_SQL_RESULT_SET_ROWS_LIMIT:100000}", - sqlTextPreviewMaxLength: "${CLOUDBEAVER_RESOURCE_QUOTA_SQL_TEXT_PREVIEW_MAX_LENGTH:4096}", - sqlBinaryPreviewMaxLength: "${CLOUDBEAVER_RESOURCE_QUOTA_SQL_BINARY_PREVIEW_MAX_LENGTH:261120}" - }, - enabledAuthProviders: [ - "local" - ], - - disabledDrivers: [ - "h2:h2_embedded", - "h2:h2_embedded_v2", - "clickhouse:yandex_clickhouse" - ], - disabledBetaFeatures: [ - - ] - - } - -} diff --git a/config/sample-databases/db/Chinook.sqlitedb b/config/sample-databases/db/Chinook.sqlitedb deleted file mode 100644 index 7eb421570e..0000000000 Binary files a/config/sample-databases/db/Chinook.sqlitedb and /dev/null differ diff --git a/config/sample-databases/db/README b/config/sample-databases/db/README deleted file mode 100644 index 0882204624..0000000000 --- a/config/sample-databases/db/README +++ /dev/null @@ -1,6 +0,0 @@ - Chinook Database - Version 1.3 - Script: Chinook_Sqlite.sql - Description: Creates and populates the Chinook database. - DB Server: Sqlite - Author: Luis Rocha - License: http://www.codeplex.com/ChinookDatabase/license diff --git a/deploy/build-backend.sh b/deploy/build-backend.sh index 051ed0a798..5b1b55d45f 100755 --- a/deploy/build-backend.sh +++ b/deploy/build-backend.sh @@ -2,12 +2,6 @@ set -Eeo pipefail set +u -# #command line arguments -# CONFIGURATION_PATH=${1-"../config/sample-databases/DefaultConfiguration"} -# SAMPLE_DATABASE_PATH=${2-""} - -# echo $CONFIGURATION_PATH -# echo $SAMPLE_DATABASE_PATH echo "Clone and build Cloudbeaver" rm -rf ./drivers @@ -43,20 +37,8 @@ cp -rp ../server/product/web-server/target/products/io.cloudbeaver.product/all/a cp -p ./scripts/* ./cloudbeaver mkdir cloudbeaver/samples -if [[ -z $SAMPLE_DATABASE_PATH ]]; then - SAMPLE_DATABASE_PATH="" -else - mkdir cloudbeaver/samples/db - cp -rp "${SAMPLE_DATABASE_PATH}" cloudbeaver/samples/ -fi - -if [[ -z "$CONFIGURATION_PATH" ]]; then - CONFIGURATION_PATH="../config/sample-databases/DefaultConfiguration" -fi - cp -rp ../config/core/* cloudbeaver/conf -cp -rp "${CONFIGURATION_PATH}"/GlobalConfiguration/.dbeaver/data-sources.json cloudbeaver/conf/initial-data-sources.conf -cp -p "${CONFIGURATION_PATH}"/*.conf cloudbeaver/conf/ +cp -rp ../config/GlobalConfiguration/.dbeaver/data-sources.json cloudbeaver/conf/initial-data-sources.conf mv drivers cloudbeaver echo "End of backend build" \ No newline at end of file diff --git a/deploy/build-sqlite.bat b/deploy/build-sqlite.bat deleted file mode 100644 index 16e1c95963..0000000000 --- a/deploy/build-sqlite.bat +++ /dev/null @@ -1 +0,0 @@ -@call build.bat ..\config\sample-databases\SQLiteConfiguration ..\config\sample-databases\db diff --git a/deploy/build-sqlite.sh b/deploy/build-sqlite.sh deleted file mode 100755 index 1a8212fef0..0000000000 --- a/deploy/build-sqlite.sh +++ /dev/null @@ -1,9 +0,0 @@ -#!/bin/bash -set -Eeuo pipefail - -#command line arguments -CONFIGURATION_PATH='../config/sample-databases/SQLiteConfiguration' -SAMPLE_DATABASE_PATH='../config/sample-databases/db' - -source build-backend.sh -source build-frontend.sh \ No newline at end of file diff --git a/deploy/build.bat b/deploy/build.bat index e5a90eb1df..27bc96826e 100644 --- a/deploy/build.bat +++ b/deploy/build.bat @@ -1,11 +1,6 @@ @echo off rem command line arguments -SET CONFIGURATION_PATH=%1 -SET SAMPLE_DATABASE_PATH=%2 - -IF "%CONFIGURATION_PATH%"=="" SET CONFIGURATION_PATH="..\config\sample-databases\DefaultConfiguration" -echo "Configuration path=%CONFIGURATION_PATH%" echo Clone and build Cloudbeaver @@ -40,13 +35,9 @@ xcopy /E /Q ..\server\product\web-server\target\products\io.cloudbeaver.product\ copy scripts\* cloudbeaver >NUL mkdir cloudbeaver\samples -IF NOT "%SAMPLE_DATABASE_PATH%"=="" ( - mkdir cloudbeaver\samples\db - xcopy /E /Q %SAMPLE_DATABASE_PATH% cloudbeaver\samples\db >NUL -) + copy ..\config\core\* cloudbeaver\conf >NUL -copy %CONFIGURATION_PATH%\GlobalConfiguration\.dbeaver\data-sources.json cloudbeaver\conf\initial-data-sources.conf >NUL -copy %CONFIGURATION_PATH%\*.conf cloudbeaver\conf >NUL +copy ..\config\DefaultConfiguration\GlobalConfiguration\.dbeaver\data-sources.json cloudbeaver\conf\initial-data-sources.conf >NUL move drivers cloudbeaver >NUL diff --git a/deploy/build.sh b/deploy/build.sh index 04efba9759..c3e481a4eb 100755 --- a/deploy/build.sh +++ b/deploy/build.sh @@ -1,9 +1,5 @@ #!/bin/bash set -Eeuo pipefail -#command line arguments -CONFIGURATION_PATH="../config/sample-databases/DefaultConfiguration" -SAMPLE_DATABASE_PATH="" - source build-backend.sh source build-frontend.sh \ No newline at end of file diff --git a/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/BaseWebProjectImpl.java b/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/BaseWebProjectImpl.java index d5c4690cd6..fb066b6719 100644 --- a/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/BaseWebProjectImpl.java +++ b/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/BaseWebProjectImpl.java @@ -38,21 +38,18 @@ public abstract class BaseWebProjectImpl extends BaseProjectImpl implements RMCo @NotNull private final Path path; @NotNull - protected final DataSourceFilter dataSourceFilter; private final RMController resourceController; public BaseWebProjectImpl( @NotNull DBPWorkspace workspace, @NotNull RMController resourceController, @NotNull SMSessionContext sessionContext, - @NotNull RMProject project, - @NotNull DataSourceFilter dataSourceFilter + @NotNull RMProject project ) { super(workspace, sessionContext); this.resourceController = resourceController; this.path = RMUtils.getProjectPath(project); this.project = project; - this.dataSourceFilter = dataSourceFilter; } @NotNull @@ -104,11 +101,6 @@ public boolean isUseSecretStorage() { return false; } - @NotNull - public RMProject getRmProject() { - return this.project; - } - /** * Method for Bulk Update of resources properties paths * diff --git a/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/WebProjectImpl.java b/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/WebProjectImpl.java index 8cce6d1332..00a4c64136 100644 --- a/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/WebProjectImpl.java +++ b/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/WebProjectImpl.java @@ -33,16 +33,15 @@ public abstract class WebProjectImpl extends BaseWebProjectImpl { private static final Log log = Log.getLog(WebProjectImpl.class); @NotNull - private final DBPPreferenceStore preferenceStore; + protected final DBPPreferenceStore preferenceStore; public WebProjectImpl( @NotNull DBPWorkspace workspace, @NotNull RMController resourceController, @NotNull SMSessionContext sessionContext, @NotNull RMProject project, - @NotNull DataSourceFilter dataSourceFilter, @NotNull DBPPreferenceStore preferenceStore ) { - super(workspace, resourceController, sessionContext, project, dataSourceFilter); + super(workspace, resourceController, sessionContext, project); this.preferenceStore = preferenceStore; } @@ -82,8 +81,13 @@ public DBTTaskManager getTaskManager() { protected DBPDataSourceRegistry createDataSourceRegistry() { return new WebDataSourceRegistryProxy( new DataSourceRegistryRM(this, getResourceController(), preferenceStore), - dataSourceFilter + getDataSourceFilter() ); } + @NotNull + public DataSourceFilter getDataSourceFilter() { + return (ds) -> true; + } + } diff --git a/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/WebSessionGlobalProjectImpl.java b/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/WebSessionGlobalProjectImpl.java new file mode 100644 index 0000000000..66f48d8d03 --- /dev/null +++ b/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/WebSessionGlobalProjectImpl.java @@ -0,0 +1,118 @@ +/* + * DBeaver - Universal Database Manager + * Copyright (C) 2010-2024 DBeaver Corp and others + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.cloudbeaver; + +import io.cloudbeaver.model.session.WebSession; +import org.jkiss.code.NotNull; +import org.jkiss.dbeaver.DBException; +import org.jkiss.dbeaver.Log; +import org.jkiss.dbeaver.model.DBPDataSourceContainer; +import org.jkiss.dbeaver.model.DBPEvent; +import org.jkiss.dbeaver.model.rm.RMProject; +import org.jkiss.dbeaver.model.security.SMObjectType; +import org.jkiss.dbeaver.model.security.user.SMObjectPermissions; + +import java.util.Collections; +import java.util.Set; +import java.util.stream.Collectors; + +/** + * Global project. + * Connections there can be not accessible. + */ +public class WebSessionGlobalProjectImpl extends WebSessionProjectImpl { + private static final Log log = Log.getLog(WebSessionGlobalProjectImpl.class); + private Set accessibleConnectionIds = Collections.emptySet(); + + public WebSessionGlobalProjectImpl(@NotNull WebSession webSession, @NotNull RMProject project) { + super(webSession, project); + } + + /** + * Update info about accessible connections from a database. + */ + public synchronized void refreshAccessibleConnectionIds() { + this.accessibleConnectionIds = readAccessibleConnectionIds(); + } + + @NotNull + private Set readAccessibleConnectionIds() { + try { + return webSession.getSecurityController() + .getAllAvailableObjectsPermissions(SMObjectType.datasource) + .stream() + .map(SMObjectPermissions::getObjectId) + .collect(Collectors.toSet()); + } catch (DBException e) { + webSession.addSessionError(e); + log.error("Error reading connection grants", e); + return Collections.emptySet(); + } + } + + /** + * Checks if connection is accessible for current user. + */ + public boolean isDataSourceAccessible(@NotNull DBPDataSourceContainer dataSource) { + return dataSource.isExternallyProvided() || + dataSource.isTemporary() || + webSession.hasPermission(DBWConstants.PERMISSION_ADMIN) || + accessibleConnectionIds.contains(dataSource.getId()); + } + + /** + * Adds a connection if it became accessible. + * The method is processed when connection permissions were updated. + */ + public synchronized void addAccessibleConnectionToCache(@NotNull String dsId) { + if (!getRMProject().isGlobal()) { + return; + } + this.accessibleConnectionIds.add(dsId); + var registry = getDataSourceRegistry(); + var dataSource = registry.getDataSource(dsId); + if (dataSource != null) { + addConnection(dataSource); + // reflect changes is navigator model + registry.notifyDataSourceListeners(new DBPEvent(DBPEvent.Action.OBJECT_ADD, dataSource, true)); + } + } + + /** + * Removes a connection if it became not accessible. + * The method is processed when connection permissions were updated. + */ + public synchronized void removeAccessibleConnectionFromCache(@NotNull String dsId) { + if (!getRMProject().isGlobal()) { + return; + } + var registry = getDataSourceRegistry(); + var dataSource = registry.getDataSource(dsId); + if (dataSource != null) { + this.accessibleConnectionIds.remove(dsId); + removeConnection(dataSource); + // reflect changes is navigator model + registry.notifyDataSourceListeners(new DBPEvent(DBPEvent.Action.OBJECT_REMOVE, dataSource)); + dataSource.dispose(); + } + } + + @NotNull + public DataSourceFilter getDataSourceFilter() { + return this::isDataSourceAccessible; + } +} diff --git a/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/WebSessionProjectImpl.java b/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/WebSessionProjectImpl.java index 980f0a93a7..5dacda453f 100644 --- a/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/WebSessionProjectImpl.java +++ b/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/WebSessionProjectImpl.java @@ -16,27 +16,39 @@ */ package io.cloudbeaver; +import io.cloudbeaver.model.WebConnectionInfo; import io.cloudbeaver.model.session.WebSession; +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.DBPDataSourceContainer; +import org.jkiss.dbeaver.model.app.DBPDataSourceRegistry; +import org.jkiss.dbeaver.model.app.DBPDataSourceRegistryCache; import org.jkiss.dbeaver.model.navigator.DBNModel; import org.jkiss.dbeaver.model.rm.RMProject; +import org.jkiss.dbeaver.model.websocket.event.WSEventType; +import org.jkiss.dbeaver.registry.DataSourceDescriptor; +import org.jkiss.dbeaver.runtime.jobs.DisconnectJob; -public class WebSessionProjectImpl extends WebProjectImpl { +import java.util.*; +import java.util.stream.Collectors; - private final WebSession webSession; +public class WebSessionProjectImpl extends WebProjectImpl { + private static final Log log = Log.getLog(WebSessionProjectImpl.class); + protected final WebSession webSession; + private final Map connections = new HashMap<>(); + private boolean registryIsLoaded = false; public WebSessionProjectImpl( @NotNull WebSession webSession, - @NotNull RMProject project, - @NotNull DataSourceFilter dataSourceFilter + @NotNull RMProject project ) { super( webSession.getWorkspace(), webSession.getRmController(), webSession.getSessionContext(), project, - dataSourceFilter, webSession.getUserPreferenceStore() ); this.webSession = webSession; @@ -47,4 +59,156 @@ public WebSessionProjectImpl( public DBNModel getNavigatorModel() { return webSession.getNavigatorModel(); } + + @NotNull + @Override + protected DBPDataSourceRegistry createDataSourceRegistry() { + DBPDataSourceRegistry dataSourceRegistry = super.createDataSourceRegistry(); + dataSourceRegistry.setAuthCredentialsProvider(webSession); + return dataSourceRegistry; + } + + private synchronized void addDataSourcesToCache() { + if (registryIsLoaded) { + return; + } + getDataSourceRegistry().getDataSources().forEach(this::addConnection); + Throwable lastError = getDataSourceRegistry().getLastError(); + if (lastError != null) { + webSession.addSessionError(lastError); + log.error("Error refreshing connections from project '" + getId() + "'", lastError); + } + registryIsLoaded = true; + } + + @Override + public void dispose() { + super.dispose(); + Map conCopy; + synchronized (this.connections) { + conCopy = new HashMap<>(this.connections); + this.connections.clear(); + } + + for (WebConnectionInfo connectionInfo : conCopy.values()) { + if (connectionInfo.isConnected()) { + new DisconnectJob(connectionInfo.getDataSourceContainer()).schedule(); + } + } + } + + + /** + * Returns web connection info from cache (if exists). + */ + @Nullable + public WebConnectionInfo findWebConnectionInfo(@NotNull String connectionId) { + synchronized (connections) { + return connections.get(connectionId); + } + } + + /** + * Returns web connection info from cache, adds it to cache if not present. + * Throws exception if connection is not found. + */ + @NotNull + public WebConnectionInfo getWebConnectionInfo(@NotNull String connectionId) throws DBWebException { + WebConnectionInfo connectionInfo = findWebConnectionInfo(connectionId); + if (connectionInfo != null) { + return connectionInfo; + } + DBPDataSourceContainer dataSource = getDataSourceRegistry().getDataSource(connectionId); + if (dataSource != null) { + return addConnection(dataSource); + } + throw new DBWebException("Connection '%s' not found".formatted(connectionId)); + } + + /** + * Adds connection to project cache. + */ + @NotNull + public synchronized WebConnectionInfo addConnection(@NotNull DBPDataSourceContainer dataSourceContainer) { + WebConnectionInfo connection = new WebConnectionInfo(webSession, dataSourceContainer); + synchronized (connections) { + connections.put(dataSourceContainer.getId(), connection); + } + return connection; + } + + /** + * Removes connection from project cache. + */ + public void removeConnection(@NotNull DBPDataSourceContainer dataSourceContainer) { + WebConnectionInfo webConnectionInfo = connections.get(dataSourceContainer.getId()); + if (webConnectionInfo != null) { + webConnectionInfo.clearCache(); + synchronized (connections) { + connections.remove(dataSourceContainer.getId()); + } + } + } + + /** + * Loads connection from registry if they are not loaded. + * + * @return connections from cache. + */ + public List getConnections() { + if (!registryIsLoaded) { + addDataSourcesToCache(); + registryIsLoaded = true; + } + synchronized (connections) { + return new ArrayList<>(connections.values()); + } + } + + /** + * updates data sources based on event in web session + * + * @param dataSourceIds list of updated connections + * @param type type of event + */ + public synchronized boolean updateProjectDataSources(@NotNull List dataSourceIds, @NotNull WSEventType type) { + var sendDataSourceUpdatedEvent = false; + DBPDataSourceRegistry registry = getDataSourceRegistry(); + // save old connections + var oldDataSources = dataSourceIds.stream() + .map(registry::getDataSource) + .filter(Objects::nonNull) + .collect(Collectors.toMap( + DBPDataSourceContainer::getId, + ds -> new DataSourceDescriptor((DataSourceDescriptor) ds, ds.getRegistry()) + )); + if (type == WSEventType.DATASOURCE_CREATED || type == WSEventType.DATASOURCE_UPDATED) { + registry.refreshConfig(dataSourceIds); + } + for (String dsId : dataSourceIds) { + DataSourceDescriptor ds = (DataSourceDescriptor) registry.getDataSource(dsId); + if (ds == null) { + continue; + } + switch (type) { + case DATASOURCE_CREATED -> { + addConnection(ds); + sendDataSourceUpdatedEvent = true; + } + case DATASOURCE_UPDATED -> // if settings were changed we need to send event + sendDataSourceUpdatedEvent |= !ds.equalSettings(oldDataSources.get(dsId)); + case DATASOURCE_DELETED -> { + WebDataSourceUtils.disconnectDataSource(webSession, ds); + if (registry instanceof DBPDataSourceRegistryCache dsrc) { + dsrc.removeDataSourceFromList(ds); + } + removeConnection(ds); + sendDataSourceUpdatedEvent = true; + } + default -> { + } + } + } + return sendDataSourceUpdatedEvent; + } } 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 9c5e42c945..85f9d249d3 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 @@ -445,10 +445,10 @@ public String getRequiredAuth() { private boolean hasProjectPermission(RMProjectPermission projectPermission) { DBPProject project = dataSourceContainer.getProject(); - if (!(project instanceof WebProjectImpl)) { + if (!(project instanceof WebProjectImpl webProject)) { return false; } - return SMUtils.hasProjectPermission(session, ((WebProjectImpl) project).getRmProject(), projectPermission); + return SMUtils.hasProjectPermission(session, webProject.getRMProject(), projectPermission); } private boolean canViewReadOnlyConnections() { diff --git a/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/model/WebProjectInfo.java b/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/model/WebProjectInfo.java index 2a3ceed1a9..292ef8601d 100644 --- a/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/model/WebProjectInfo.java +++ b/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/model/WebProjectInfo.java @@ -53,11 +53,13 @@ public String getId() { } @Property - public boolean isGlobal() { return project.getRmProject().isGlobal(); } + public boolean isGlobal() { + return project.getRMProject().isGlobal(); + } @Property public boolean isShared() { - return project.getRmProject().isShared(); + return project.getRMProject().isShared(); } @Property @@ -72,7 +74,7 @@ public String getDescription() { @Property public boolean isCanEditDataSources() { - if (project.getRmProject().getType() == RMProjectType.USER && !customPrivateConnectionsEnabled) { + if (project.getRMProject().getType() == RMProjectType.USER && !customPrivateConnectionsEnabled) { return false; } return hasDataSourcePermission(RMProjectPermission.DATA_SOURCES_EDIT); @@ -94,12 +96,12 @@ public boolean isCanViewResources() { } private boolean hasDataSourcePermission(RMProjectPermission permission) { - return SMUtils.hasProjectPermission(session, project.getRmProject(), permission); + return SMUtils.hasProjectPermission(session, project.getRMProject(), permission); } @Property public RMResourceType[] getResourceTypes() { - RMResourceType[] resourceTypes = project.getRmProject().getResourceTypes(); + RMResourceType[] resourceTypes = project.getRMProject().getResourceTypes(); if(resourceTypes == null) { return ArrayUtils.toArray(RMResourceType.class, new ArrayList<>()); diff --git a/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/model/app/BaseWebApplication.java b/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/model/app/BaseWebApplication.java index 0517fef9b1..9483767290 100644 --- a/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/model/app/BaseWebApplication.java +++ b/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/model/app/BaseWebApplication.java @@ -16,11 +16,7 @@ */ package io.cloudbeaver.model.app; -import io.cloudbeaver.DataSourceFilter; -import io.cloudbeaver.WebProjectImpl; -import io.cloudbeaver.WebSessionProjectImpl; import io.cloudbeaver.model.log.SLF4JLogHandler; -import io.cloudbeaver.model.session.WebSession; import org.eclipse.core.runtime.Platform; import org.eclipse.equinox.app.IApplicationContext; import org.jkiss.code.NotNull; @@ -36,7 +32,6 @@ import org.jkiss.dbeaver.model.impl.app.BaseApplicationImpl; import org.jkiss.dbeaver.model.impl.app.BaseWorkspaceImpl; import org.jkiss.dbeaver.model.rm.RMController; -import org.jkiss.dbeaver.model.rm.RMProject; import org.jkiss.dbeaver.model.secret.DBSSecretController; import org.jkiss.dbeaver.model.websocket.event.WSEventController; import org.jkiss.dbeaver.runtime.IVariableResolver; @@ -160,19 +155,6 @@ private Path getCustomConfigPath(Path configPath, String fileName) { return Files.exists(customConfigPath) ? customConfigPath : configPath.resolve(fileName); } - @Override - public WebProjectImpl createProjectImpl( - @NotNull WebSession webSession, - @NotNull RMProject project, - @NotNull DataSourceFilter dataSourceFilter - ) { - return new WebSessionProjectImpl( - webSession, - project, - dataSourceFilter - ); - } - /** * There is no secret controller in base web app. * Method returns VoidSecretController instance. diff --git a/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/model/app/WebApplication.java b/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/model/app/WebApplication.java index 6e5a2ccf49..ae1ec9333a 100644 --- a/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/model/app/WebApplication.java +++ b/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/model/app/WebApplication.java @@ -16,9 +16,6 @@ */ package io.cloudbeaver.model.app; -import io.cloudbeaver.DataSourceFilter; -import io.cloudbeaver.WebProjectImpl; -import io.cloudbeaver.model.session.WebSession; import org.jkiss.code.NotNull; import org.jkiss.dbeaver.DBException; import org.jkiss.dbeaver.model.DBFileController; @@ -27,7 +24,6 @@ import org.jkiss.dbeaver.model.auth.SMCredentialsProvider; import org.jkiss.dbeaver.model.auth.SMSessionContext; import org.jkiss.dbeaver.model.rm.RMController; -import org.jkiss.dbeaver.model.rm.RMProject; import org.jkiss.dbeaver.model.secret.DBSSecretController; import org.jkiss.dbeaver.model.security.SMAdminController; import org.jkiss.dbeaver.model.security.SMController; @@ -58,12 +54,6 @@ default boolean isInitializationMode() { boolean isMultiNode(); - WebProjectImpl createProjectImpl( - @NotNull WebSession webSession, - @NotNull RMProject project, - @NotNull DataSourceFilter dataSourceFilter - ); - SMController createSecurityController(@NotNull SMCredentialsProvider credentialsProvider) throws DBException; SMAdminController getAdminSecurityController(@NotNull SMCredentialsProvider credentialsProvider) throws DBException; diff --git a/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/model/rm/local/LocalResourceController.java b/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/model/rm/local/LocalResourceController.java index 4718c448c2..21657250bc 100644 --- a/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/model/rm/local/LocalResourceController.java +++ b/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/model/rm/local/LocalResourceController.java @@ -1291,8 +1291,7 @@ public InternalWebProjectImpl(SessionContextImpl sessionContext, RMProject rmPro LocalResourceController.this.workspace, LocalResourceController.this, sessionContext, - rmProject, - (container) -> true); + rmProject); } @NotNull diff --git a/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/model/session/BaseWebSession.java b/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/model/session/BaseWebSession.java index 8d516be802..9cad92722f 100644 --- a/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/model/session/BaseWebSession.java +++ b/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/model/session/BaseWebSession.java @@ -72,6 +72,7 @@ protected WebUserContext createUserContext() throws DBException { return new WebUserContext(this.application, this.workspace); } + @NotNull public WebSessionWorkspace getWorkspace() { return workspace; } diff --git a/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/model/session/WebSession.java b/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/model/session/WebSession.java index 716dd7386f..0650ecd72b 100644 --- a/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/model/session/WebSession.java +++ b/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/model/session/WebSession.java @@ -19,10 +19,8 @@ import com.google.gson.Gson; import com.google.gson.GsonBuilder; import com.google.gson.InstanceCreator; -import io.cloudbeaver.DBWConstants; -import io.cloudbeaver.DBWebException; -import io.cloudbeaver.DataSourceFilter; -import io.cloudbeaver.WebProjectImpl; +import com.google.gson.Strictness; +import io.cloudbeaver.*; import io.cloudbeaver.model.WebAsyncTaskInfo; import io.cloudbeaver.model.WebConnectionInfo; import io.cloudbeaver.model.WebServerMessage; @@ -32,7 +30,6 @@ import io.cloudbeaver.service.DBWSessionHandler; import io.cloudbeaver.service.sql.WebSQLConstants; import io.cloudbeaver.utils.CBModelConstants; -import io.cloudbeaver.utils.WebAppUtils; import io.cloudbeaver.utils.WebDataSourceUtils; import org.eclipse.core.runtime.IAdaptable; import org.eclipse.core.runtime.IStatus; @@ -43,12 +40,8 @@ import org.jkiss.dbeaver.Log; import org.jkiss.dbeaver.model.DBFileController; import org.jkiss.dbeaver.model.DBPDataSourceContainer; -import org.jkiss.dbeaver.model.DBPEvent; import org.jkiss.dbeaver.model.access.DBAAuthCredentials; import org.jkiss.dbeaver.model.access.DBACredentialsProvider; -import org.jkiss.dbeaver.model.app.DBPDataSourceRegistry; -import org.jkiss.dbeaver.model.app.DBPDataSourceRegistryCache; -import org.jkiss.dbeaver.model.app.DBPProject; import org.jkiss.dbeaver.model.auth.*; import org.jkiss.dbeaver.model.connection.DBPConnectionConfiguration; import org.jkiss.dbeaver.model.exec.DBCException; @@ -68,15 +61,11 @@ import org.jkiss.dbeaver.model.security.SMAdminController; import org.jkiss.dbeaver.model.security.SMConstants; import org.jkiss.dbeaver.model.security.SMController; -import org.jkiss.dbeaver.model.security.SMObjectType; -import org.jkiss.dbeaver.model.security.user.SMObjectPermissions; import org.jkiss.dbeaver.model.sql.DBQuotaException; import org.jkiss.dbeaver.model.websocket.event.MessageType; import org.jkiss.dbeaver.model.websocket.event.WSEventType; import org.jkiss.dbeaver.model.websocket.event.WSSessionLogUpdatedEvent; -import org.jkiss.dbeaver.registry.DataSourceDescriptor; import org.jkiss.dbeaver.runtime.DBWorkbench; -import org.jkiss.dbeaver.runtime.jobs.DisconnectJob; import org.jkiss.utils.CommonUtils; import java.lang.reflect.InvocationTargetException; @@ -106,12 +95,10 @@ public class WebSession extends BaseWebSession private String lastRemoteAddr; private String lastRemoteUserAgent; - private Set accessibleConnectionIds = Collections.emptySet(); - private String locale; private boolean cacheExpired; - private final Map connections = new HashMap<>(); + private WebSessionGlobalProjectImpl globalProject; private final List sessionMessages = new ArrayList<>(); private final Map asyncTasks = new HashMap<>(); @@ -166,8 +153,8 @@ public SMSessionPrincipal getSessionPrincipal() { } } - @NotNull - public DBPProject getSingletonProject() { + @Nullable + public WebSessionProjectImpl getSingletonProject() { return getWorkspace().getActiveProject(); } @@ -264,69 +251,6 @@ public synchronized void refreshUserData() { initNavigatorModel(); } - /** - * updates data sources based on event in web session - * - * @param project project of connection - * @param dataSourceIds list of updated connections - * @param type type of event - */ - public synchronized boolean updateProjectDataSources( - DBPProject project, - List dataSourceIds, - WSEventType type - ) { - var sendDataSourceUpdatedEvent = false; - DBPDataSourceRegistry registry = project.getDataSourceRegistry(); - // save old connections - var oldDataSources = dataSourceIds.stream() - .map(registry::getDataSource) - .filter(Objects::nonNull) - .collect(Collectors.toMap( - DBPDataSourceContainer::getId, - ds -> new DataSourceDescriptor((DataSourceDescriptor) ds, ds.getRegistry()) - )); - if (type == WSEventType.DATASOURCE_CREATED || type == WSEventType.DATASOURCE_UPDATED) { - registry.refreshConfig(dataSourceIds); - } - for (String dsId : dataSourceIds) { - DataSourceDescriptor ds = (DataSourceDescriptor) registry.getDataSource(dsId); - if (ds == null) { - continue; - } - switch (type) { - case DATASOURCE_CREATED -> { - WebConnectionInfo connectionInfo = new WebConnectionInfo(this, ds); - this.connections.put(getConnectionId(ds), connectionInfo); - sendDataSourceUpdatedEvent = true; - } - case DATASOURCE_UPDATED -> // if settings were changed we need to send event - sendDataSourceUpdatedEvent |= !ds.equalSettings(oldDataSources.get(dsId)); - case DATASOURCE_DELETED -> { - WebDataSourceUtils.disconnectDataSource(this, ds); - if (registry instanceof DBPDataSourceRegistryCache dsrc) { - dsrc.removeDataSourceFromList(ds); - } - this.connections.remove(getConnectionId(ds)); - sendDataSourceUpdatedEvent = true; - } - default -> { - } - } - } - return sendDataSourceUpdatedEvent; - } - - @NotNull - private String getConnectionId(@NotNull DBPDataSourceContainer container) { - return getConnectionId(container.getProject().getId(), container.getId()); - } - - @NotNull - private String getConnectionId(@NotNull String projectId, @NotNull String dsId) { - return projectId + ":" + dsId; - } - // Note: for admin use only public synchronized void resetUserState() throws DBException { clearAuthTokens(); @@ -347,7 +271,7 @@ private void initNavigatorModel() { this.navigatorModel.dispose(); this.navigatorModel = null; } - this.connections.clear(); + this.globalProject = null; loadProjects(); @@ -367,7 +291,6 @@ private void loadProjects() { // No anonymous mode in distributed apps return; } - refreshAccessibleConnectionIds(); try { RMController controller = getRmController(); RMProject[] rmProjects = controller.listAccessibleProjects(); @@ -387,57 +310,30 @@ private void loadProjects() { } } - public WebProjectImpl createWebProject(RMProject project) { - // Do not filter data sources from user project - DataSourceFilter filter = project.getType() == RMProjectType.GLOBAL - ? this::isDataSourceAccessible - : x -> true; - WebProjectImpl sessionProject = application.createProjectImpl(this, project, filter); + private WebSessionProjectImpl createWebProject(RMProject project) { + WebSessionProjectImpl sessionProject; + if (project.isGlobal()) { + sessionProject = createGlobalProject(project); + } else { + sessionProject = new WebSessionProjectImpl(this, project); + } // do not load data sources for anonymous project if (project.getType() == RMProjectType.USER && userContext.getUser() == null) { sessionProject.setInMemory(true); } - DBPDataSourceRegistry dataSourceRegistry = sessionProject.getDataSourceRegistry(); - dataSourceRegistry.setAuthCredentialsProvider(this); addSessionProject(sessionProject); if (!project.isShared() || application.isConfigurationMode()) { getWorkspace().setActiveProject(sessionProject); } - for (DBPDataSourceContainer ds : dataSourceRegistry.getDataSources()) { - addConnection(new WebConnectionInfo(this, ds)); - } - Throwable lastError = dataSourceRegistry.getLastError(); - if (lastError != null) { - addSessionError(lastError); - log.error("Error refreshing connections from project '" + project.getId() + "'", lastError); - } return sessionProject; } - public void filterAccessibleConnections(List connections) { - connections.removeIf(c -> !isDataSourceAccessible(c.getDataSourceContainer())); - } - - private boolean isDataSourceAccessible(DBPDataSourceContainer dataSource) { - return dataSource.isExternallyProvided() || - dataSource.isTemporary() || - this.hasPermission(DBWConstants.PERMISSION_ADMIN) || - accessibleConnectionIds.contains(dataSource.getId()); - } - - @NotNull - protected Set readAccessibleConnectionIds() { - try { - return getSecurityController() - .getAllAvailableObjectsPermissions(SMObjectType.datasource) - .stream() - .map(SMObjectPermissions::getObjectId) - .collect(Collectors.toSet()); - } catch (DBException e) { - addSessionError(e); - log.error("Error reading connection grants", e); - return Collections.emptySet(); - } + private WebSessionProjectImpl createGlobalProject(RMProject project) { + WebSessionProjectImpl sessionProject; + this.globalProject = new WebSessionGlobalProjectImpl(this, project); + globalProject.refreshAccessibleConnectionIds(); + sessionProject = globalProject; + return sessionProject; } private void resetSessionCache() throws DBCException { @@ -455,17 +351,7 @@ private void resetSessionCache() throws DBCException { } private void resetNavigationModel() { - Map conCopy; - synchronized (this.connections) { - conCopy = new HashMap<>(this.connections); - this.connections.clear(); - } - - for (WebConnectionInfo connectionInfo : conCopy.values()) { - if (connectionInfo.isConnected()) { - new DisconnectJob(connectionInfo.getDataSourceContainer()).schedule(); - } - } + getWorkspace().getProjects().forEach(WebSessionProjectImpl::dispose); if (this.navigatorModel != null) { this.navigatorModel.dispose(); @@ -479,7 +365,9 @@ private synchronized void refreshSessionAuth() { authAsAnonymousUser(); } else if (getUserId() != null) { userContext.refreshPermissions(); - refreshAccessibleConnectionIds(); + if (globalProject != null) { + globalProject.refreshAccessibleConnectionIds(); + } } } catch (Exception e) { @@ -488,32 +376,6 @@ private synchronized void refreshSessionAuth() { } } - protected synchronized void refreshAccessibleConnectionIds() { - this.accessibleConnectionIds = readAccessibleConnectionIds(); - } - - public synchronized void addAccessibleConnectionToCache(@NotNull String dsId) { - this.accessibleConnectionIds.add(dsId); - var registry = getProjectById(WebAppUtils.getGlobalProjectId()).getDataSourceRegistry(); - var dataSource = registry.getDataSource(dsId); - if (dataSource != null) { - connections.put(getConnectionId(dataSource), new WebConnectionInfo(this, dataSource)); - // reflect changes is navigator model - registry.notifyDataSourceListeners(new DBPEvent(DBPEvent.Action.OBJECT_ADD, dataSource, true)); - } - } - - public synchronized void removeAccessibleConnectionFromCache(@NotNull String dsId) { - var registry = getProjectById(WebAppUtils.getGlobalProjectId()).getDataSourceRegistry(); - var dataSource = registry.getDataSource(dsId); - if (dataSource != null) { - this.accessibleConnectionIds.remove(dsId); - connections.remove(getConnectionId(dataSource)); - // reflect changes is navigator model - registry.notifyDataSourceListeners(new DBPEvent(DBPEvent.Action.OBJECT_REMOVE, dataSource)); - dataSource.dispose(); - } - } private synchronized void authAsAnonymousUser() throws DBException { if (!application.getAppConfiguration().isAnonymousAccessEnabled()) { @@ -578,69 +440,6 @@ public synchronized void updateSessionParameters(WebHttpRequestInfo requestInfo) this.cacheExpired = false; } - @Association - public List getConnections() { - synchronized (connections) { - return new ArrayList<>(connections.values()); - } - } - - @NotNull - public WebConnectionInfo getWebConnectionInfo(@Nullable String projectId, String connectionID) throws DBWebException { - WebConnectionInfo connectionInfo = null; - synchronized (connections) { - if (projectId != null) { - connectionInfo = connections.get(getConnectionId(projectId, connectionID)); - } else { - addWarningMessage("Project id is not defined in request. Try to find it from connection cache"); - for (Map.Entry entry : connections.entrySet()) { - String k = entry.getKey(); - WebConnectionInfo v = entry.getValue(); - if (k.contains(connectionID)) { - connectionInfo = v; - break; - } - } - } - } - if (connectionInfo == null) { - WebProjectImpl project = getProjectById(projectId); - if (project == null) { - throw new DBWebException("Project '" + projectId + "' not found in web workspace"); - } - DBPDataSourceContainer dataSource = project.getDataSourceRegistry().getDataSource(connectionID); - if (dataSource != null) { - connectionInfo = new WebConnectionInfo(this, dataSource); - synchronized (connections) { - connections.put(getConnectionId(dataSource), connectionInfo); - } - } else { - throw new DBWebException("Connection '" + connectionID + "' not found"); - } - } - return connectionInfo; - } - - @Nullable - public WebConnectionInfo findWebConnectionInfo(String projectId, String connectionId) { - synchronized (connections) { - return connections.get(getConnectionId(projectId, connectionId)); - } - } - - public void addConnection(WebConnectionInfo connectionInfo) { - synchronized (connections) { - connections.put(getConnectionId(connectionInfo.getDataSourceContainer()), connectionInfo); - } - } - - public void removeConnection(WebConnectionInfo connectionInfo) { - connectionInfo.clearCache(); - synchronized (connections) { - connections.remove(getConnectionId(connectionInfo.getDataSourceContainer())); - } - } - @Override public void close() { try { @@ -824,7 +623,7 @@ public T getAttribute(String name) { synchronized (attributes) { Object value = attributes.get(name); if (value instanceof PersistentAttribute persistentAttribute) { - value = persistentAttribute.getValue(); + value = persistentAttribute.value(); } return (T) value; } @@ -840,7 +639,7 @@ public T getAttribute(String name, Function creator, Function di synchronized (attributes) { Object value = attributes.get(name); if (value instanceof PersistentAttribute persistentAttribute) { - value = persistentAttribute.getValue(); + value = persistentAttribute.value(); } if (value == null) { value = creator.apply(null); @@ -983,9 +782,12 @@ public boolean provideAuthParameters( } configuration.setRuntimeAttribute(RUNTIME_PARAM_AUTH_INFOS, getAllAuthInfo()); - WebConnectionInfo webConnectionInfo = findWebConnectionInfo(dataSourceContainer.getProject().getId(), dataSourceContainer.getId()); - if (webConnectionInfo != null) { - WebDataSourceUtils.saveCredentialsInDataSource(webConnectionInfo, dataSourceContainer, configuration); + WebSessionProjectImpl project = getProjectById(dataSourceContainer.getProject().getId()); + if (project != null) { + WebConnectionInfo webConnectionInfo = project.findWebConnectionInfo(dataSourceContainer.getId()); + if (webConnectionInfo != null) { + WebDataSourceUtils.saveCredentialsInDataSource(webConnectionInfo, dataSourceContainer, configuration); + } } // uncommented because we had the problem with non-native auth models @@ -994,7 +796,7 @@ public boolean provideAuthParameters( InstanceCreator credTypeAdapter = type -> credentials; Gson credGson = new GsonBuilder() - .setLenient() + .setStrictness(Strictness.LENIENT) .registerTypeAdapter(credentials.getClass(), credTypeAdapter) .create(); @@ -1076,12 +878,17 @@ public void refreshSMSession() throws DBException { } @Nullable - public WebProjectImpl getProjectById(@Nullable String projectId) { + public WebSessionProjectImpl getProjectById(@Nullable String projectId) { return getWorkspace().getProjectById(projectId); } - public WebProjectImpl getAccessibleProjectById(@Nullable String projectId) throws DBWebException { - WebProjectImpl project = null; + /** + * Returns project info from session cache. + * + * @throws DBWebException if project with provided id is not found. + */ + public WebSessionProjectImpl getAccessibleProjectById(@Nullable String projectId) throws DBWebException { + WebSessionProjectImpl project = null; if (projectId != null) { project = getWorkspace().getProjectById(projectId); } @@ -1091,18 +898,24 @@ public WebProjectImpl getAccessibleProjectById(@Nullable String projectId) throw return project; } - public List getAccessibleProjects() { + public List getAccessibleProjects() { return getWorkspace().getProjects(); } - public void addSessionProject(@NotNull WebProjectImpl project) { + /** + * Adds project to session cache and navigator tree. + */ + public void addSessionProject(@NotNull WebSessionProjectImpl project) { getWorkspace().addProject(project); if (navigatorModel != null) { navigatorModel.getRoot().addProject(project, false); } } - public void deleteSessionProject(@Nullable WebProjectImpl project) { + /** + * Removes project from session cache and navigator tree. + */ + public void deleteSessionProject(@Nullable WebSessionProjectImpl project) { if (project != null) { project.dispose(); } @@ -1127,10 +940,6 @@ public void removeSessionProject(@Nullable String projectId) throws DBException return; } deleteSessionProject(project); - var projectConnections = project.getDataSourceRegistry().getDataSources(); - for (DBPDataSourceContainer c : projectConnections) { - removeConnection(new WebConnectionInfo(this, c)); - } } @NotNull @@ -1147,6 +956,11 @@ public DBPPreferenceStore getUserPreferenceStore() { return getUserContext().getPreferenceStore(); } + @Nullable + public WebSessionGlobalProjectImpl getGlobalProject() { + return globalProject; + } + private class SessionProgressMonitor extends BaseProgressMonitor { @Override public void beginTask(String name, int totalWork) { @@ -1181,15 +995,6 @@ public void subTask(String name) { } } - private static class PersistentAttribute { - private final Object value; - - public PersistentAttribute(Object value) { - this.value = value; - } - - public Object getValue() { - return value; - } + private record PersistentAttribute(Object value) { } } diff --git a/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/model/session/WebSessionWorkspace.java b/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/model/session/WebSessionWorkspace.java index f24bf8c90a..87581c2634 100644 --- a/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/model/session/WebSessionWorkspace.java +++ b/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/model/session/WebSessionWorkspace.java @@ -16,13 +16,12 @@ */ package io.cloudbeaver.model.session; -import io.cloudbeaver.WebProjectImpl; +import io.cloudbeaver.WebSessionProjectImpl; import org.jkiss.code.NotNull; import org.jkiss.code.Nullable; import org.jkiss.dbeaver.model.DBPAdaptable; import org.jkiss.dbeaver.model.DBPImage; import org.jkiss.dbeaver.model.app.DBPPlatform; -import org.jkiss.dbeaver.model.app.DBPProject; import org.jkiss.dbeaver.model.app.DBPWorkspace; import org.jkiss.dbeaver.model.impl.auth.SessionContextImpl; import org.jkiss.dbeaver.model.rm.RMUtils; @@ -40,8 +39,8 @@ public class WebSessionWorkspace implements DBPWorkspace { private final BaseWebSession session; private final SessionContextImpl workspaceAuthContext; - private final List accessibleProjects = new ArrayList<>(); - private WebProjectImpl activeProject; + private final List accessibleProjects = new ArrayList<>(); + private WebSessionProjectImpl activeProject; public WebSessionWorkspace(BaseWebSession session) { this.session = session; @@ -83,20 +82,20 @@ public Path getMetadataFolder() { @NotNull @Override - public List getProjects() { + public List getProjects() { return accessibleProjects; } @Nullable @Override - public DBPProject getActiveProject() { + public WebSessionProjectImpl getActiveProject() { return activeProject; } @Nullable @Override - public WebProjectImpl getProject(@NotNull String projectName) { - for (WebProjectImpl project : accessibleProjects) { + public WebSessionProjectImpl getProject(@NotNull String projectName) { + for (WebSessionProjectImpl project : accessibleProjects) { if (project.getName().equals(projectName)) { return project; } @@ -106,11 +105,11 @@ public WebProjectImpl getProject(@NotNull String projectName) { @Nullable @Override - public WebProjectImpl getProjectById(@NotNull String projectId) { + public WebSessionProjectImpl getProjectById(@NotNull String projectId) { if (projectId == null) { return activeProject; } - for (WebProjectImpl project : accessibleProjects) { + for (WebSessionProjectImpl project : accessibleProjects) { if (project.getId().equals(projectId)) { return project; } @@ -139,21 +138,21 @@ public DBPImage getResourceIcon(DBPAdaptable resourceAdapter) { return null; } - public void setActiveProject(DBPProject activeProject) { - this.activeProject = (WebProjectImpl) activeProject; + public void setActiveProject(WebSessionProjectImpl activeProject) { + this.activeProject = activeProject; } - void addProject(WebProjectImpl project) { + void addProject(WebSessionProjectImpl project) { accessibleProjects.add(project); } - void removeProject(WebProjectImpl project) { + void removeProject(WebSessionProjectImpl project) { accessibleProjects.remove(project); } void clearProjects() { if (!this.accessibleProjects.isEmpty()) { - for (WebProjectImpl project : accessibleProjects) { + for (WebSessionProjectImpl project : accessibleProjects) { project.dispose(); } this.activeProject = null; diff --git a/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/utils/WebDataSourceUtils.java b/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/utils/WebDataSourceUtils.java index 0848b7206b..72c8775cd1 100644 --- a/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/utils/WebDataSourceUtils.java +++ b/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/utils/WebDataSourceUtils.java @@ -18,10 +18,9 @@ import io.cloudbeaver.DBWConstants; import io.cloudbeaver.DBWebException; -import io.cloudbeaver.WebProjectImpl; +import io.cloudbeaver.WebSessionProjectImpl; import io.cloudbeaver.model.WebConnectionInfo; import io.cloudbeaver.model.WebNetworkHandlerConfigInput; -import io.cloudbeaver.model.app.WebApplication; import io.cloudbeaver.model.session.WebSession; import org.jkiss.code.NotNull; import org.jkiss.code.Nullable; @@ -38,6 +37,7 @@ import java.util.List; import java.util.Map; +import java.util.Optional; public class WebDataSourceUtils { @@ -114,18 +114,22 @@ private static void setSecureProperties(DBWHandlerConfiguration handlerConfig, W @Nullable public static DBPDataSourceContainer getLocalOrGlobalDataSource( - WebApplication application, WebSession webSession, @Nullable String projectId, String connectionId + WebSession webSession, @Nullable String projectId, String connectionId ) throws DBWebException { DBPDataSourceContainer dataSource = null; if (!CommonUtils.isEmpty(connectionId)) { - WebProjectImpl project = webSession.getProjectById(projectId); + WebSessionProjectImpl project = webSession.getProjectById(projectId); if (project == null) { throw new DBWebException("Project '" + projectId + "' not found"); } dataSource = project.getDataSourceRegistry().getDataSource(connectionId); - if (dataSource == null && (webSession.hasPermission(DBWConstants.PERMISSION_ADMIN) || application.isConfigurationMode())) { + if (dataSource == null && + (webSession.hasPermission(DBWConstants.PERMISSION_ADMIN) || webSession.getApplication().isConfigurationMode())) { // If called for new connection in admin mode then this connection may absent in session registry yet - dataSource = getGlobalDataSourceRegistry().getDataSource(connectionId); + project = webSession.getGlobalProject(); + if (project != null) { + dataSource = project.getDataSourceRegistry().getDataSource(connectionId); + } } } return dataSource; @@ -162,4 +166,28 @@ public static boolean disconnectDataSource(@NotNull WebSession webSession, @NotN } return false; } + + /** + * The method that seeks for web connection in session cache by connection id. + * Mostly used when project id is not defined. + */ + @NotNull + public static WebConnectionInfo getWebConnectionInfo( + @NotNull WebSession webSession, + @Nullable String projectId, + @NotNull String connectionId + ) throws DBWebException { + if (projectId == null) { + webSession.addWarningMessage("Project id is not defined in request. Try to find it from connection cache"); + // try to find connection in all accessible projects + Optional optional = webSession.getAccessibleProjects().stream() + .flatMap(p -> p.getConnections().stream()) // get connection cache from web projects + .filter(e -> e.getId().contains(connectionId)) + .findFirst(); + if (optional.isPresent()) { + return optional.get(); + } + } + return webSession.getAccessibleProjectById(projectId).getWebConnectionInfo(connectionId); + } } 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 4c60dd58d8..e1ddccf294 100644 --- a/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/WebServiceUtils.java +++ b/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/WebServiceUtils.java @@ -30,7 +30,6 @@ import io.cloudbeaver.server.CBApplication; import io.cloudbeaver.server.CBPlatform; import io.cloudbeaver.service.navigator.WebPropertyFilter; -import io.cloudbeaver.utils.WebAppUtils; import io.cloudbeaver.utils.WebCommonUtils; import io.cloudbeaver.utils.WebDataSourceUtils; import org.jkiss.code.NotNull; @@ -98,10 +97,6 @@ public static DBPDataSourceRegistry getGlobalDataSourceRegistry() throws DBWebEx return WebDataSourceUtils.getGlobalDataSourceRegistry(); } - public static DBPDataSourceRegistry getGlobalRegistry(WebSession session) { - return session.getProjectById(WebAppUtils.getGlobalProjectId()).getDataSourceRegistry(); - } - public static InputStream openStaticResource(String path) { return WebServiceUtils.class.getClassLoader().getResourceAsStream(path); } diff --git a/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/server/events/WSDataSourceUpdatedEventHandlerImpl.java b/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/server/events/WSDataSourceUpdatedEventHandlerImpl.java index 81d54ab417..21928f0203 100644 --- a/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/server/events/WSDataSourceUpdatedEventHandlerImpl.java +++ b/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/server/events/WSDataSourceUpdatedEventHandlerImpl.java @@ -16,7 +16,7 @@ */ package io.cloudbeaver.server.events; -import io.cloudbeaver.WebProjectImpl; +import io.cloudbeaver.WebSessionProjectImpl; import io.cloudbeaver.model.session.BaseWebSession; import io.cloudbeaver.model.session.WebSession; import org.jkiss.code.NotNull; @@ -34,15 +34,13 @@ public class WSDataSourceUpdatedEventHandlerImpl extends WSAbstractProjectEventH @Override protected void updateSessionData(@NotNull BaseWebSession activeUserSession, @NotNull WSDataSourceEvent event) { var sendEvent = true; - if (activeUserSession instanceof WebSession) { - var webSession = (WebSession) activeUserSession; - WebProjectImpl project = webSession.getProjectById(event.getProjectId()); + if (activeUserSession instanceof WebSession webSession) { + WebSessionProjectImpl project = webSession.getProjectById(event.getProjectId()); if (project == null) { log.debug("Project " + event.getProjectId() + " is not found in session " + webSession.getSessionId()); return; } - sendEvent = webSession.updateProjectDataSources( - project, + sendEvent = project.updateProjectDataSources( event.getDataSourceIds(), WSEventType.valueById(event.getId()) ); diff --git a/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/server/events/WSObjectPermissionUpdatedEventHandler.java b/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/server/events/WSObjectPermissionUpdatedEventHandler.java index 0968876b3e..ebc1dfd6e1 100644 --- a/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/server/events/WSObjectPermissionUpdatedEventHandler.java +++ b/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/server/events/WSObjectPermissionUpdatedEventHandler.java @@ -16,6 +16,7 @@ */ package io.cloudbeaver.server.events; +import io.cloudbeaver.WebSessionGlobalProjectImpl; import io.cloudbeaver.model.session.BaseWebSession; import io.cloudbeaver.model.session.WebSession; import io.cloudbeaver.utils.WebAppUtils; @@ -74,34 +75,34 @@ protected void updateSessionData(@NotNull BaseWebSession activeUserSession, @Not var webSession = (WebSession) activeUserSession; var dataSources = List.of(objectId); - var project = webSession.getProjectById(WebAppUtils.getGlobalProjectId()); + WebSessionGlobalProjectImpl project = webSession.getGlobalProject(); if (project == null) { log.error("Project " + WebAppUtils.getGlobalProjectId() + " is not found in session " + activeUserSession.getSessionId()); return; } if (WSEventType.OBJECT_PERMISSIONS_UPDATED.getEventId().equals(event.getId())) { - isAccessibleNow = webSession.findWebConnectionInfo(project.getId(), objectId) != null; + isAccessibleNow = project.findWebConnectionInfo(objectId) != null; if (isAccessibleNow) { return; } - webSession.addAccessibleConnectionToCache(objectId); + project.addAccessibleConnectionToCache(objectId); webSession.addSessionEvent( WSDataSourceEvent.create( event.getSessionId(), event.getUserId(), - WebAppUtils.getGlobalProjectId(), + project.getId(), dataSources, WSDataSourceProperty.CONFIGURATION ) ); } else if (WSEventType.OBJECT_PERMISSIONS_DELETED.getEventId().equals(event.getId())) { - webSession.removeAccessibleConnectionFromCache(objectId); + project.removeAccessibleConnectionFromCache(objectId); webSession.addSessionEvent( WSDataSourceEvent.delete( event.getSessionId(), event.getUserId(), - WebAppUtils.getGlobalProjectId(), + project.getId(), dataSources, WSDataSourceProperty.CONFIGURATION ) diff --git a/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/server/events/WSRmResourceUpdatedEventHandlerImpl.java b/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/server/events/WSRmResourceUpdatedEventHandlerImpl.java index 48dccc7e55..3466b93b0d 100644 --- a/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/server/events/WSRmResourceUpdatedEventHandlerImpl.java +++ b/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/server/events/WSRmResourceUpdatedEventHandlerImpl.java @@ -53,13 +53,13 @@ private void acceptChangesInNavigatorTree(WSEventType eventType, String resource if (eventType == WSEventType.RM_RESOURCE_CREATED) { RMEventManager.fireEvent( new RMEvent(RMEvent.Action.RESOURCE_ADD, - project.getRmProject(), + project.getRMProject(), resourcePath) ); } else if (eventType == WSEventType.RM_RESOURCE_DELETED) { RMEventManager.fireEvent( new RMEvent(RMEvent.Action.RESOURCE_DELETE, - project.getRmProject(), + project.getRMProject(), resourcePath) ); } diff --git a/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/server/events/WSUserSecretEventHandlerImpl.java b/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/server/events/WSUserSecretEventHandlerImpl.java index ade211b040..438a1ef858 100644 --- a/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/server/events/WSUserSecretEventHandlerImpl.java +++ b/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/server/events/WSUserSecretEventHandlerImpl.java @@ -16,6 +16,7 @@ */ package io.cloudbeaver.server.events; +import io.cloudbeaver.WebSessionProjectImpl; import io.cloudbeaver.model.session.BaseWebSession; import io.cloudbeaver.model.session.WebSession; import org.jkiss.code.NotNull; @@ -36,11 +37,16 @@ public class WSUserSecretEventHandlerImpl extends WSDefaultEventHandler getUserConnections( return Collections.singletonList(connectionInfo); } } - var stream = webSession.getConnections().stream(); + var stream = webSession.getAccessibleProjects().stream(); if (projectId != null) { - stream = stream.filter(c -> c.getProjectId().equals(projectId)); + stream = stream.filter(c -> c.getId().equals(projectId)); } if (projectIds != null) { - stream = stream.filter(c -> projectIds.contains(c.getProjectId())); + stream = stream.filter(c -> projectIds.contains(c.getId())); } Set applicableDrivers = WebServiceUtils.getApplicableDriversIds(); - return stream.filter(c -> applicableDrivers.contains(c.getDataSourceContainer().getDriver().getId())) + return stream + .flatMap(p -> p.getConnections().stream()) + .filter(c -> applicableDrivers.contains(c.getDataSourceContainer().getDriver().getId())) .toList(); } @@ -153,27 +152,30 @@ public List getTemplateDataSources() throws DBWebException public List getTemplateConnections( @NotNull WebSession webSession, @Nullable String projectId ) throws DBWebException { + if (webSession.getApplication().isDistributed()) { + return List.of(); + } List result = new ArrayList<>(); if (projectId == null) { - for (DBPProject project : webSession.getAccessibleProjects()) { + for (WebSessionProjectImpl project : webSession.getAccessibleProjects()) { getTemplateConnectionsFromProject(webSession, project, result); } } else { - DBPProject project = getProjectById(webSession, projectId); + WebSessionProjectImpl project = getProjectById(webSession, projectId); getTemplateConnectionsFromProject(webSession, project, result); } - webSession.filterAccessibleConnections(result); return result; } private void getTemplateConnectionsFromProject( @NotNull WebSession webSession, - @NotNull DBPProject project, + @NotNull WebSessionProjectImpl project, List result ) { DBPDataSourceRegistry registry = project.getDataSourceRegistry(); for (DBPDataSourceContainer ds : registry.getDataSources()) { if (ds.isTemplate() && + project.getDataSourceFilter().filter(ds) && CBPlatform.getInstance().getApplicableDrivers().contains(ds.getDriver())) { result.add(new WebConnectionInfo(webSession, ds)); } @@ -316,9 +318,11 @@ public boolean changeSessionLanguage(@NotNull WebSession webSession, String loca @Override public WebConnectionInfo getConnectionState( - WebSession webSession, @Nullable String projectId, String connectionId + @NotNull WebSession webSession, + @Nullable String projectId, + @NotNull String connectionId ) throws DBWebException { - return webSession.getWebConnectionInfo(projectId, connectionId); + return WebDataSourceUtils.getWebConnectionInfo(webSession, projectId, connectionId); } @@ -333,7 +337,7 @@ public WebConnectionInfo initConnection( @Nullable Boolean sharedCredentials, @Nullable String selectedSecretId ) throws DBWebException { - WebConnectionInfo connectionInfo = webSession.getWebConnectionInfo(projectId, connectionId); + WebConnectionInfo connectionInfo = WebDataSourceUtils.getWebConnectionInfo(webSession, projectId, connectionId); connectionInfo.setSavedCredentials(authProperties, networkCredentials); var dataSourceContainer = (DataSourceDescriptor) connectionInfo.getDataSourceContainer(); @@ -429,8 +433,8 @@ public WebConnectionInfo createConnection( @Nullable String projectId, @NotNull WebConnectionConfig connectionConfig ) throws DBWebException { - var project = getProjectById(webSession, projectId); - var rmProject = project.getRmProject(); + WebSessionProjectImpl project = getProjectById(webSession, projectId); + var rmProject = project.getRMProject(); if (rmProject.getType() == RMProjectType.USER && !webSession.hasPermission(DBWConstants.PERMISSION_ADMIN) && !CBApplication.getInstance().getAppConfiguration().isSupportsCustomConnections() @@ -459,8 +463,7 @@ public WebConnectionInfo createConnection( throw new DBWebException("Failed to create connection", e); } - WebConnectionInfo connectionInfo = new WebConnectionInfo(webSession, newDataSource); - webSession.addConnection(connectionInfo); + WebConnectionInfo connectionInfo = project.addConnection(newDataSource); webSession.addInfoMessage("New connection was created - " + WebServiceUtils.getConnectionContainerInfo( newDataSource)); WebEventUtils.addDataSourceUpdatedEvent( @@ -484,9 +487,8 @@ public WebConnectionInfo updateConnection( // if (!CBApplication.getInstance().getAppConfiguration().isSupportsCustomConnections()) { // throw new DBWebException("Connection edit is restricted by server configuration"); // } - DBPDataSourceRegistry sessionRegistry = getProjectById(webSession, projectId).getDataSourceRegistry(); - WebConnectionInfo connectionInfo = webSession.getWebConnectionInfo(projectId, config.getConnectionId()); + WebConnectionInfo connectionInfo = WebDataSourceUtils.getWebConnectionInfo(webSession, projectId, config.getConnectionId()); DBPDataSourceContainer dataSource = connectionInfo.getDataSourceContainer(); webSession.addInfoMessage("Update connection - " + WebServiceUtils.getConnectionContainerInfo(dataSource)); var oldDataSource = new DataSourceDescriptor((DataSourceDescriptor) dataSource, dataSource.getRegistry()); @@ -499,6 +501,8 @@ public WebConnectionInfo updateConnection( dataSource.setDescription(config.getDescription()); } + WebSessionProjectImpl project = getProjectById(webSession, projectId); + DBPDataSourceRegistry sessionRegistry = project.getDataSourceRegistry(); dataSource.setFolder(config.getFolder() != null ? sessionRegistry.getFolder(config.getFolder()) : null); if (config.isDefaultAutoCommit() != null) { dataSource.setDefaultAutoCommit(config.isDefaultAutoCommit()); @@ -575,7 +579,7 @@ private WSDataSourceProperty getDatasourceEventProperty( public boolean deleteConnection( @NotNull WebSession webSession, @Nullable String projectId, @NotNull String connectionId ) throws DBWebException { - WebConnectionInfo connectionInfo = webSession.getWebConnectionInfo(projectId, connectionId); + WebConnectionInfo connectionInfo = WebDataSourceUtils.getWebConnectionInfo(webSession, projectId, connectionId); if (connectionInfo.getDataSourceContainer().getProject() != getProjectById(webSession, projectId)) { throw new DBWebException("Global connection '" + connectionInfo.getName() + "' configuration cannot be deleted"); } @@ -599,7 +603,8 @@ public WebConnectionInfo createConnectionFromTemplate( @NotNull String templateId, @Nullable String connectionName ) throws DBWebException { - DBPDataSourceRegistry templateRegistry = getProjectById(webSession, projectId).getDataSourceRegistry(); + WebSessionProjectImpl project = getProjectById(webSession, projectId); + DBPDataSourceRegistry templateRegistry = project.getDataSourceRegistry(); DBPDataSourceContainer dataSourceTemplate = templateRegistry.getDataSource(templateId); if (dataSourceTemplate == null) { throw new DBWebException("Template data source '" + templateId + "' not found"); @@ -622,9 +627,7 @@ public WebConnectionInfo createConnectionFromTemplate( throw new DBWebException(e.getMessage(), e); } - WebConnectionInfo connectionInfo = new WebConnectionInfo(webSession, newDataSource); - webSession.addConnection(connectionInfo); - return connectionInfo; + return project.addConnection(newDataSource); } @Override @@ -636,7 +639,8 @@ public WebConnectionInfo copyConnectionFromNode( ) throws DBWebException { try { DBNModel navigatorModel = webSession.getNavigatorModel(); - DBPDataSourceRegistry dataSourceRegistry = getProjectById(webSession, projectId).getDataSourceRegistry(); + WebSessionProjectImpl project = getProjectById(webSession, projectId); + DBPDataSourceRegistry dataSourceRegistry = project.getDataSourceRegistry(); DBNNode srcNode = navigatorModel.getNodeByPath(webSession.getProgressMonitor(), nodePath); if (srcNode == null) { @@ -662,9 +666,8 @@ public WebConnectionInfo copyConnectionFromNode( dataSourceRegistry.addDataSource(newDataSource); - WebConnectionInfo connectionInfo = new WebConnectionInfo(webSession, newDataSource); dataSourceRegistry.checkForErrors(); - webSession.addConnection(connectionInfo); + WebConnectionInfo connectionInfo = project.addConnection(newDataSource); WebEventUtils.addDataSourceUpdatedEvent( webSession.getProjectById(projectId), webSession, @@ -687,7 +690,7 @@ public WebConnectionInfo testConnection( connectionConfig.setSaveCredentials(true); // It is used in createConnectionFromConfig DataSourceDescriptor dataSource = (DataSourceDescriptor) WebDataSourceUtils.getLocalOrGlobalDataSource( - CBApplication.getInstance(), webSession, projectId, connectionId); + webSession, projectId, connectionId); WebProjectImpl project = getProjectById(webSession, projectId); DBPDataSourceRegistry sessionRegistry = project.getDataSourceRegistry(); @@ -823,12 +826,13 @@ private WebConnectionInfo closeAndDeleteConnection( @NotNull String connectionId, boolean forceDelete ) throws DBWebException { - WebConnectionInfo connectionInfo = webSession.getWebConnectionInfo(projectId, connectionId); + WebSessionProjectImpl project = getProjectById(webSession, projectId); + WebConnectionInfo connectionInfo = project.getWebConnectionInfo(connectionId); DBPDataSourceContainer dataSourceContainer = connectionInfo.getDataSourceContainer(); boolean disconnected = WebDataSourceUtils.disconnectDataSource(webSession, dataSourceContainer); if (forceDelete) { - DBPDataSourceRegistry registry = getProjectById(webSession, projectId).getDataSourceRegistry(); + DBPDataSourceRegistry registry = project.getDataSourceRegistry(); registry.removeDataSource(dataSourceContainer); try { registry.checkForErrors(); @@ -840,7 +844,7 @@ private WebConnectionInfo closeAndDeleteConnection( } throw new DBWebException("Failed to delete connection", e); } - webSession.removeConnection(connectionInfo); + project.removeConnection(dataSourceContainer); } else { // Just reset saved credentials connectionInfo.clearCache(); @@ -954,7 +958,7 @@ public boolean deleteConnectionFolder( public WebConnectionInfo setConnectionNavigatorSettings( WebSession webSession, @Nullable String projectId, String id, DBNBrowseSettings settings ) throws DBWebException { - WebConnectionInfo connectionInfo = webSession.getWebConnectionInfo(projectId, id); + WebConnectionInfo connectionInfo = WebDataSourceUtils.getWebConnectionInfo(webSession, projectId, id); DataSourceDescriptor dataSourceDescriptor = ((DataSourceDescriptor) connectionInfo.getDataSourceContainer()); dataSourceDescriptor.setNavigatorSettings(settings); dataSourceDescriptor.persistConfiguration(); @@ -983,8 +987,8 @@ public WebProductSettings getProductSettings(@NotNull WebSession webSession) { return new WebProductSettings(webSession, ProductSettingsRegistry.getInstance().getSettings()); } - private WebProjectImpl getProjectById(WebSession webSession, String projectId) throws DBWebException { - WebProjectImpl project = webSession.getProjectById(projectId); + private WebSessionProjectImpl getProjectById(WebSession webSession, String projectId) throws DBWebException { + WebSessionProjectImpl project = webSession.getProjectById(projectId); if (project == null) { throw new DBWebException("Project '" + projectId + "' not found"); } diff --git a/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/navigator/WebNavigatorNodeInfo.java b/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/navigator/WebNavigatorNodeInfo.java index 6e31e3113e..511b0743f6 100644 --- a/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/navigator/WebNavigatorNodeInfo.java +++ b/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/navigator/WebNavigatorNodeInfo.java @@ -259,7 +259,7 @@ private boolean hasNodePermission(RMProjectPermission permission) { if (project == null) { return false; } - RMProject rmProject = project.getRmProject(); + RMProject rmProject = project.getRMProject(); return SMUtils.hasProjectPermission(session, rmProject, permission); } diff --git a/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/navigator/impl/WebServiceNavigator.java b/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/navigator/impl/WebServiceNavigator.java index 96690ea4de..89c0b08d44 100644 --- a/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/navigator/impl/WebServiceNavigator.java +++ b/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/navigator/impl/WebServiceNavigator.java @@ -230,7 +230,7 @@ public boolean setNavigatorNodeFilter( filter.setEnabled(true); if (node instanceof DBNDatabaseNode dbNode) { dbNode.setNodeFilter(dbNode.getItemsMeta(), filter, true); - if (hasNodeEditPermission(webSession, node, ((WebProjectImpl) node.getOwnerProject()).getRmProject())) { + if (hasNodeEditPermission(webSession, node, ((WebProjectImpl) node.getOwnerProject()).getRMProject())) { // Save settings dbNode.getDataSourceContainer().persistConfiguration(); } @@ -571,7 +571,7 @@ public int deleteNodes( private void checkProjectEditAccess(DBNNode node, WebSession session) throws DBException { BaseWebProjectImpl project = (BaseWebProjectImpl) node.getOwnerProject(); - if (project == null || !hasNodeEditPermission(session, node, project.getRmProject())) { + if (project == null || !hasNodeEditPermission(session, node, project.getRMProject())) { throw new DBException("Access denied"); } } diff --git a/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/sql/impl/WebServiceSQL.java b/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/sql/impl/WebServiceSQL.java index cc52563e20..88fece2598 100644 --- a/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/sql/impl/WebServiceSQL.java +++ b/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/sql/impl/WebServiceSQL.java @@ -84,7 +84,7 @@ public WebSQLContextInfo[] listContexts( WebConnectionInfo webConnection = WebServiceBindingBase.getWebConnection(session, projectId, connectionId); conToRead.add(webConnection); } else { - conToRead.addAll(session.getConnections()); + conToRead.addAll(session.getAccessibleProjects().stream().flatMap(p -> p.getConnections().stream()).toList()); } List contexts = new ArrayList<>(); diff --git a/server/bundles/io.cloudbeaver.service.auth/src/io/cloudbeaver/service/auth/local/LocalSessionHandler.java b/server/bundles/io.cloudbeaver.service.auth/src/io/cloudbeaver/service/auth/local/LocalSessionHandler.java index 6707fe84ec..c2261f8e5f 100644 --- a/server/bundles/io.cloudbeaver.service.auth/src/io/cloudbeaver/service/auth/local/LocalSessionHandler.java +++ b/server/bundles/io.cloudbeaver.service.auth/src/io/cloudbeaver/service/auth/local/LocalSessionHandler.java @@ -54,10 +54,9 @@ protected void openDatabaseConsole(WebSession webSession, CBServerAction action) String connectionId = action.getParameter(LocalServletHandler.PARAM_CONNECTION_ID); String connectionName = action.getParameter(LocalServletHandler.PARAM_CONNECTION_NAME); String connectionURL = action.getParameter(LocalServletHandler.PARAM_CONNECTION_URL); - Stream stream = webSession.getConnections().stream(); - if (projectId != null) { - stream = stream.filter(c -> c.getProjectId().equals(projectId)); - } + Stream stream = webSession.getAccessibleProjects().stream() + .filter(c -> projectId == null || c.getId().equals(projectId)) + .flatMap(p -> p.getConnections().stream()); if (connectionId != null) { stream = stream.filter(c -> c.getId().equals(connectionId)); } else if (connectionName != null) { diff --git a/server/bundles/io.cloudbeaver.service.data.transfer/src/io/cloudbeaver/service/data/transfer/impl/WebDataTransferImportServlet.java b/server/bundles/io.cloudbeaver.service.data.transfer/src/io/cloudbeaver/service/data/transfer/impl/WebDataTransferImportServlet.java index c0f575abb5..f645d07404 100644 --- a/server/bundles/io.cloudbeaver.service.data.transfer/src/io/cloudbeaver/service/data/transfer/impl/WebDataTransferImportServlet.java +++ b/server/bundles/io.cloudbeaver.service.data.transfer/src/io/cloudbeaver/service/data/transfer/impl/WebDataTransferImportServlet.java @@ -88,7 +88,7 @@ protected void processServiceRequest( throw new IllegalArgumentException("Missing required parameters"); } - WebConnectionInfo webConnectionInfo = session.getWebConnectionInfo(projectId, connectionId); + WebConnectionInfo webConnectionInfo = session.getAccessibleProjectById(projectId).getWebConnectionInfo(connectionId); WebSQLProcessor processor = WebServiceBindingSQL.getSQLProcessor(webConnectionInfo); WebSQLContextInfo webSQLContextInfo = processor.getContext(contextId); diff --git a/webapp/packages/plugin-connection-custom/src/DriverSelector/DriverSelectorDialog.tsx b/webapp/packages/plugin-connection-custom/src/DriverSelector/DriverSelectorDialog.tsx index fa161c1baf..668ceeea1c 100644 --- a/webapp/packages/plugin-connection-custom/src/DriverSelector/DriverSelectorDialog.tsx +++ b/webapp/packages/plugin-connection-custom/src/DriverSelector/DriverSelectorDialog.tsx @@ -31,7 +31,7 @@ export const DriverSelectorDialog: DialogComponent = observer(function Dri return ( - + diff --git a/webapp/packages/plugin-connection-custom/src/locales/en.ts b/webapp/packages/plugin-connection-custom/src/locales/en.ts index 101224f2a2..3c03aca9cf 100644 --- a/webapp/packages/plugin-connection-custom/src/locales/en.ts +++ b/webapp/packages/plugin-connection-custom/src/locales/en.ts @@ -1,21 +1,8 @@ -export default [ - ['customConnection_connectionType_custom', 'Parameters'], - ['customConnection_connectionType_url', 'URL'], - ['customConnection_main', 'Main'], - ['customConnection_properties', 'Driver Properties'], - ['customConnection_custom_name', 'Name'], - ['customConnection_custom_host', 'Host'], - ['customConnection_custom_obligatory', '(obligatory)'], - ['customConnection_custom_port', 'Port'], - ['customConnection_custom_server_name', 'Server name'], - ['customConnection_custom_database', 'Database'], - ['customConnection_custom_server', 'Server'], - ['customConnection_url_JDBC', 'JDBC URL'], - ['customConnection_folder', 'Folder'], - ['customConnection_userName', 'User name'], - ['customConnection_Password', 'Password'], - ['customConnection_test', 'Test Connection'], - ['customConnection_create', 'Create'], - ['customConnection_create_error', 'Сreate connection error'], - ['plugin_connection_custom_action_custom_label', 'New Connection'], -]; +/* + * 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. + */ +export default [['plugin_connection_custom_action_custom_label', 'New Connection']]; diff --git a/webapp/packages/plugin-connection-custom/src/locales/fr.ts b/webapp/packages/plugin-connection-custom/src/locales/fr.ts index 45855a2b3c..4c0f72d04d 100644 --- a/webapp/packages/plugin-connection-custom/src/locales/fr.ts +++ b/webapp/packages/plugin-connection-custom/src/locales/fr.ts @@ -5,24 +5,4 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ -export default [ - ['customConnection_connectionType_custom', 'Paramètres'], - ['customConnection_connectionType_url', 'URL'], - ['customConnection_main', 'Principal'], - ['customConnection_properties', 'Propriétés du pilote'], - ['customConnection_custom_name', 'Nom'], - ['customConnection_custom_host', 'Hôte'], - ['customConnection_custom_obligatory', '(obligatoire)'], - ['customConnection_custom_port', 'Port'], - ['customConnection_custom_server_name', 'Nom du serveur'], - ['customConnection_custom_database', 'Base de données'], - ['customConnection_custom_server', 'Serveur'], - ['customConnection_url_JDBC', 'URL JDBC'], - ['customConnection_folder', 'Dossier'], - ['customConnection_userName', "Nom d'utilisateur"], - ['customConnection_Password', 'Mot de passe'], - ['customConnection_test', 'Tester la connexion'], - ['customConnection_create', 'Créer'], - ['customConnection_create_error', 'Erreur de création de la connexion'], - ['plugin_connection_custom_action_custom_label', 'Nouvelle connexion'], -]; +export default [['plugin_connection_custom_action_custom_label', 'Nouvelle connexion']]; diff --git a/webapp/packages/plugin-connection-custom/src/locales/it.ts b/webapp/packages/plugin-connection-custom/src/locales/it.ts index 631852b9f7..3c03aca9cf 100644 --- a/webapp/packages/plugin-connection-custom/src/locales/it.ts +++ b/webapp/packages/plugin-connection-custom/src/locales/it.ts @@ -1,21 +1,8 @@ -export default [ - ['customConnection_connectionType_custom', 'Parametri'], - ['customConnection_connectionType_url', 'URL'], - ['customConnection_main', 'Main'], - ['customConnection_properties', 'Proprietà del driver'], - ['customConnection_custom_name', 'Nome'], - ['customConnection_custom_host', 'Host'], - ['customConnection_custom_obligatory', '(obbligatorio)'], - ['customConnection_custom_port', 'Porta'], - ['customConnection_custom_server_name', 'Server name'], - ['customConnection_custom_database', 'Database'], - ['customConnection_custom_server', 'Server'], - ['customConnection_url_JDBC', 'JDBC URL'], - ['customConnection_folder', 'Folder'], - ['customConnection_userName', 'User name'], - ['customConnection_Password', 'Password'], - ['customConnection_test', 'Prova la connessione'], - ['customConnection_create', 'Crea'], - ['customConnection_create_error', 'Errore di creazione connessione'], - ['plugin_connection_custom_action_custom_label', 'New Connection'], -]; +/* + * 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. + */ +export default [['plugin_connection_custom_action_custom_label', 'New Connection']]; diff --git a/webapp/packages/plugin-connection-custom/src/locales/ru.ts b/webapp/packages/plugin-connection-custom/src/locales/ru.ts index ea21af31b7..4d4f153ef8 100644 --- a/webapp/packages/plugin-connection-custom/src/locales/ru.ts +++ b/webapp/packages/plugin-connection-custom/src/locales/ru.ts @@ -1,21 +1,8 @@ -export default [ - ['customConnection_connectionType_custom', 'Параметры'], - ['customConnection_connectionType_url', 'URL'], - ['customConnection_main', 'Главное'], - ['customConnection_properties', 'Параметры драйвера'], - ['customConnection_custom_name', 'Имя'], - ['customConnection_custom_host', 'Хост'], - ['customConnection_custom_obligatory', '(обязательное)'], - ['customConnection_custom_port', 'Порт'], - ['customConnection_custom_server_name', 'Имя сервера'], - ['customConnection_custom_database', 'База'], - ['customConnection_custom_server', 'Сервер'], - ['customConnection_url_JDBC', 'JDBC URL'], - ['customConnection_folder', 'Папка'], - ['customConnection_userName', 'Пользователь'], - ['customConnection_Password', 'Пароль'], - ['customConnection_test', 'Проверить'], - ['customConnection_create', 'Создать'], - ['customConnection_create_error', 'Ошибка при создании подключения'], - ['plugin_connection_custom_action_custom_label', 'Новое подключение'], -]; +/* + * 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. + */ +export default [['plugin_connection_custom_action_custom_label', 'Новое подключение']]; diff --git a/webapp/packages/plugin-connection-custom/src/locales/zh.ts b/webapp/packages/plugin-connection-custom/src/locales/zh.ts index 9d0096646e..0de6a0635e 100644 --- a/webapp/packages/plugin-connection-custom/src/locales/zh.ts +++ b/webapp/packages/plugin-connection-custom/src/locales/zh.ts @@ -5,24 +5,4 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ -export default [ - ['customConnection_connectionType_custom', '参数'], - ['customConnection_connectionType_url', 'URL'], - ['customConnection_main', '主要'], - ['customConnection_properties', '驱动属性'], - ['customConnection_custom_name', '名称'], - ['customConnection_custom_host', '主机'], - ['customConnection_custom_obligatory', '(强制性的)'], - ['customConnection_custom_port', '端口'], - ['customConnection_custom_server_name', '服务器名称'], - ['customConnection_custom_database', '数据库'], - ['customConnection_custom_server', '服务器'], - ['customConnection_url_JDBC', 'JDBC URL'], - ['customConnection_folder', '文件夹'], - ['customConnection_userName', '用户名称'], - ['customConnection_Password', '密码'], - ['customConnection_test', '测试连接'], - ['customConnection_create', '创建'], - ['customConnection_create_error', '创建连接失败'], - ['plugin_connection_custom_action_custom_label', '新建连接'], -]; +export default [['plugin_connection_custom_action_custom_label', '新建连接']]; diff --git a/webapp/packages/plugin-connection-search/src/Search/ConnectionSearchService.ts b/webapp/packages/plugin-connection-search/src/Search/ConnectionSearchService.ts index 4836716cd1..ab3ce752a7 100644 --- a/webapp/packages/plugin-connection-search/src/Search/ConnectionSearchService.ts +++ b/webapp/packages/plugin-connection-search/src/Search/ConnectionSearchService.ts @@ -128,8 +128,8 @@ export class ConnectionSearchService { } const result = await this.commonDialogService.open(ConfirmationDialog, { - title: 'connections_public_connection_edit_cancel_title', - message: 'connections_public_connection_edit_cancel_message', + title: 'plugin_connections_connection_edit_cancel_title', + message: 'plugin_connections_connection_edit_cancel_message', confirmActionText: 'ui_processing_ok', }); diff --git a/webapp/packages/plugin-connection-template/src/ConnectionDialog/ConnectionDialog.tsx b/webapp/packages/plugin-connection-template/src/ConnectionDialog/ConnectionDialog.tsx index 67467a826f..91cb00ceb3 100644 --- a/webapp/packages/plugin-connection-template/src/ConnectionDialog/ConnectionDialog.tsx +++ b/webapp/packages/plugin-connection-template/src/ConnectionDialog/ConnectionDialog.tsx @@ -43,7 +43,7 @@ export const ConnectionDialog: DialogComponent = observer(function C return ( = observer(function C {dialog.step === ConnectionStep.ConnectionTemplateSelect && } {dialog.step === ConnectionStep.Connection && (!dialog.authModelId ? ( -
- {dialog.processing && translate('basicConnection_connectionDialog_connecting_message')} -
+
{dialog.processing && translate('plugin_connection_template_connecting_message')}
) : (
(function ConnectionDialogF {translate('ui_stepper_back')} ); diff --git a/webapp/packages/plugin-connection-template/src/locales/en.ts b/webapp/packages/plugin-connection-template/src/locales/en.ts index 4e2b491465..cdd315dbc1 100644 --- a/webapp/packages/plugin-connection-template/src/locales/en.ts +++ b/webapp/packages/plugin-connection-template/src/locales/en.ts @@ -1,13 +1,13 @@ +/* + * 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. + */ export default [ - ['basicConnection_connectionDialog_newConnection', 'New connection'], - ['basicConnection_connectionDialog_title', 'Connect to Database'], - ['basicConnection_connectionDialog_listTitle', 'Database:'], - ['basicConnection_connectionDialog_username', 'Database Username:'], - ['basicConnection_connectionDialog_usernamePlaceholder', 'user'], - ['basicConnection_connectionDialog_password', 'Database User Password:'], - ['basicConnection_connectionDialog_passwordPlaceholder', 'password'], - ['basicConnection_connectionDialog_connecting', 'Connecting...'], - ['basicConnection_connectionDialog_connecting_message', 'Connecting to database...'], + ['plugin_connection_template_connecting', 'Connecting...'], + ['plugin_connection_template_connecting_message', 'Connecting to database...'], ['plugin_connection_template_connect_success', 'Connection is established'], ['plugin_connection_template_action_connection_template_label', 'From a Template'], ]; diff --git a/webapp/packages/plugin-connection-template/src/locales/fr.ts b/webapp/packages/plugin-connection-template/src/locales/fr.ts index 5dfbf166cc..e8009b5044 100644 --- a/webapp/packages/plugin-connection-template/src/locales/fr.ts +++ b/webapp/packages/plugin-connection-template/src/locales/fr.ts @@ -6,15 +6,8 @@ * you may not use this file except in compliance with the License. */ export default [ - ['basicConnection_connectionDialog_newConnection', 'Nouvelle connexion'], - ['basicConnection_connectionDialog_title', 'Se connecter à la base de données'], - ['basicConnection_connectionDialog_listTitle', 'Base de données :'], - ['basicConnection_connectionDialog_username', "Nom d'utilisateur de la base de données :"], - ['basicConnection_connectionDialog_usernamePlaceholder', 'utilisateur'], - ['basicConnection_connectionDialog_password', "Mot de passe de l'utilisateur de la base de données :"], - ['basicConnection_connectionDialog_passwordPlaceholder', 'mot de passe'], - ['basicConnection_connectionDialog_connecting', 'Connexion en cours...'], - ['basicConnection_connectionDialog_connecting_message', 'Connexion à la base de données en cours...'], + ['plugin_connection_template_connecting', 'Connexion en cours...'], + ['plugin_connection_template_connecting_message', 'Connexion à la base de données en cours...'], ['plugin_connection_template_connect_success', 'Connexion établie'], ['plugin_connection_template_action_connection_template_label', "À partir d'un modèle"], ]; diff --git a/webapp/packages/plugin-connection-template/src/locales/it.ts b/webapp/packages/plugin-connection-template/src/locales/it.ts index f1737ef804..4b29b98428 100644 --- a/webapp/packages/plugin-connection-template/src/locales/it.ts +++ b/webapp/packages/plugin-connection-template/src/locales/it.ts @@ -1,13 +1,13 @@ +/* + * 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. + */ export default [ - ['basicConnection_connectionDialog_newConnection', 'Nuova connessione'], - ['basicConnection_connectionDialog_title', 'Collegati al database'], - ['basicConnection_connectionDialog_listTitle', 'Database:'], - ['basicConnection_connectionDialog_username', 'Database Username:'], - ['basicConnection_connectionDialog_usernamePlaceholder', 'utente'], - ['basicConnection_connectionDialog_password', 'Password Utente del Database:'], - ['basicConnection_connectionDialog_passwordPlaceholder', 'password'], - ['basicConnection_connectionDialog_connecting', 'Collegamento...'], - ['basicConnection_connectionDialog_connecting_message', 'Collegamento al database...'], + ['plugin_connection_template_connecting', 'Collegamento...'], + ['plugin_connection_template_connecting_message', 'Collegamento al database...'], ['plugin_connection_template_connect_success', 'Connection is established'], ['plugin_connection_template_action_connection_template_label', 'Dal Template'], ]; diff --git a/webapp/packages/plugin-connection-template/src/locales/ru.ts b/webapp/packages/plugin-connection-template/src/locales/ru.ts index 6ea4d10b1a..7c4300da47 100644 --- a/webapp/packages/plugin-connection-template/src/locales/ru.ts +++ b/webapp/packages/plugin-connection-template/src/locales/ru.ts @@ -1,13 +1,13 @@ +/* + * 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. + */ export default [ - ['basicConnection_connectionDialog_newConnection', 'Новое подключение'], - ['basicConnection_connectionDialog_title', 'Подключение к базе данных'], - ['basicConnection_connectionDialog_listTitle', 'Базы данных:'], - ['basicConnection_connectionDialog_username', 'Имя пользователя:'], - ['basicConnection_connectionDialog_usernamePlaceholder', 'user'], - ['basicConnection_connectionDialog_password', 'Пароль пользователя:'], - ['basicConnection_connectionDialog_passwordPlaceholder', 'password'], - ['basicConnection_connectionDialog_connecting', 'Подключение...'], - ['basicConnection_connectionDialog_connecting_message', 'Подключение к базе...'], + ['plugin_connection_template_connecting', 'Подключение...'], + ['plugin_connection_template_connecting_message', 'Подключение к базе...'], ['plugin_connection_template_connect_success', 'Подключение установлено'], ['plugin_connection_template_action_connection_template_label', 'Из шаблона'], ]; diff --git a/webapp/packages/plugin-connection-template/src/locales/zh.ts b/webapp/packages/plugin-connection-template/src/locales/zh.ts index c9b0b566d4..6b4d9ee3ce 100644 --- a/webapp/packages/plugin-connection-template/src/locales/zh.ts +++ b/webapp/packages/plugin-connection-template/src/locales/zh.ts @@ -6,15 +6,8 @@ * you may not use this file except in compliance with the License. */ export default [ - ['basicConnection_connectionDialog_newConnection', '新连接'], - ['basicConnection_connectionDialog_title', '连接数据库'], - ['basicConnection_connectionDialog_listTitle', '数据库:'], - ['basicConnection_connectionDialog_username', '用户库用户名:'], - ['basicConnection_connectionDialog_usernamePlaceholder', '用户'], - ['basicConnection_connectionDialog_password', '数据库用户密码:'], - ['basicConnection_connectionDialog_passwordPlaceholder', '密码'], - ['basicConnection_connectionDialog_connecting', '连接中...'], - ['basicConnection_connectionDialog_connecting_message', '连接数据库...'], + ['plugin_connection_template_connecting', '连接中...'], + ['plugin_connection_template_connecting_message', '连接数据库...'], ['plugin_connection_template_connect_success', '已建立连接'], ['plugin_connection_template_action_connection_template_label', '从模板创建'], ]; diff --git a/webapp/packages/plugin-connections-administration/src/locales/en.ts b/webapp/packages/plugin-connections-administration/src/locales/en.ts index 521fb71806..3718ace448 100644 --- a/webapp/packages/plugin-connections-administration/src/locales/en.ts +++ b/webapp/packages/plugin-connections-administration/src/locales/en.ts @@ -6,11 +6,11 @@ * you may not use this file except in compliance with the License. */ export default [ - ['connections_public_connection_edit_menu_item_title', 'Edit Connection'], - ['connections_public_connection_edit_cancel_title', 'Cancel confirmation'], - ['connections_public_connection_edit_reconnect_title', 'Connection updated'], - ['connections_public_connection_edit_reconnect_message', 'Connection has been updated. Do you want to reconnect?'], - ['connections_public_connection_edit_reconnect_failed', 'Failed to reconnect'], + ['plugin_connections_connection_edit_menu_item_title', 'Edit Connection'], + ['plugin_connections_connection_edit_cancel_title', 'Cancel confirmation'], + ['plugin_connections_connection_edit_reconnect_title', 'Connection updated'], + ['plugin_connections_connection_edit_reconnect_message', 'Connection has been updated. Do you want to reconnect?'], + ['plugin_connections_connection_edit_reconnect_failed', 'Failed to reconnect'], ['connections_administration_deactivate_message', "Your connection's settings will be lost. Do you want to continue?"], [ diff --git a/webapp/packages/plugin-connections-administration/src/locales/fr.ts b/webapp/packages/plugin-connections-administration/src/locales/fr.ts index ea916df5d3..a70584acef 100644 --- a/webapp/packages/plugin-connections-administration/src/locales/fr.ts +++ b/webapp/packages/plugin-connections-administration/src/locales/fr.ts @@ -6,11 +6,11 @@ * you may not use this file except in compliance with the License. */ export default [ - ['connections_public_connection_edit_menu_item_title', 'Modifier la connexion'], - ['connections_public_connection_edit_cancel_title', "Confirmation d'annulation"], - ['connections_public_connection_edit_reconnect_title', 'Connexion mise à jour'], - ['connections_public_connection_edit_reconnect_message', 'La connexion a été mise à jour. Voulez-vous vous reconnecter ?'], - ['connections_public_connection_edit_reconnect_failed', 'Échec de la reconnexion'], + ['plugin_connections_connection_edit_menu_item_title', 'Modifier la connexion'], + ['plugin_connections_connection_edit_cancel_title', "Confirmation d'annulation"], + ['plugin_connections_connection_edit_reconnect_title', 'Connexion mise à jour'], + ['plugin_connections_connection_edit_reconnect_message', 'La connexion a été mise à jour. Voulez-vous vous reconnecter ?'], + ['plugin_connections_connection_edit_reconnect_failed', 'Échec de la reconnexion'], ['connections_administration_deactivate_message', 'Les paramètres de votre connexion seront perdus. Voulez-vous continuer ?'], [ diff --git a/webapp/packages/plugin-connections-administration/src/locales/it.ts b/webapp/packages/plugin-connections-administration/src/locales/it.ts index c3761b511e..c1eea9c399 100644 --- a/webapp/packages/plugin-connections-administration/src/locales/it.ts +++ b/webapp/packages/plugin-connections-administration/src/locales/it.ts @@ -6,8 +6,8 @@ * you may not use this file except in compliance with the License. */ export default [ - ['connections_public_connection_edit_menu_item_title', 'Modifica Connessione'], - ['connections_public_connection_edit_cancel_title', "Conferma l'annullamento"], + ['plugin_connections_connection_edit_menu_item_title', 'Modifica Connessione'], + ['plugin_connections_connection_edit_cancel_title', "Conferma l'annullamento"], [ 'templates_administration_info_message', 'The templates enable administrators to define various reusable connection parameters, subsequently allowing users to create multiple connections based on these templates.', diff --git a/webapp/packages/plugin-connections-administration/src/locales/ru.ts b/webapp/packages/plugin-connections-administration/src/locales/ru.ts index cf9559fa5f..3ffea2835b 100644 --- a/webapp/packages/plugin-connections-administration/src/locales/ru.ts +++ b/webapp/packages/plugin-connections-administration/src/locales/ru.ts @@ -6,11 +6,11 @@ * you may not use this file except in compliance with the License. */ export default [ - ['connections_public_connection_edit_menu_item_title', 'Изменить подключение'], - ['connections_public_connection_edit_cancel_title', 'Отмена редактирования'], - ['connections_public_connection_edit_reconnect_title', 'Подключение обновлено'], - ['connections_public_connection_edit_reconnect_message', 'Подключение было обновлено. Вы хотите переподключиться?'], - ['connections_public_connection_edit_reconnect_failed', 'Не удалось переподключиться'], + ['plugin_connections_connection_edit_menu_item_title', 'Изменить подключение'], + ['plugin_connections_connection_edit_cancel_title', 'Отмена редактирования'], + ['plugin_connections_connection_edit_reconnect_title', 'Подключение обновлено'], + ['plugin_connections_connection_edit_reconnect_message', 'Подключение было обновлено. Вы хотите переподключиться?'], + ['plugin_connections_connection_edit_reconnect_failed', 'Не удалось переподключиться'], ['connections_administration_deactivate_message', 'Настройки вашего подключения будут потеряны. Вы хотите продолжить?'], [ diff --git a/webapp/packages/plugin-connections-administration/src/locales/zh.ts b/webapp/packages/plugin-connections-administration/src/locales/zh.ts index 9535cafc9b..149fe0a2b0 100644 --- a/webapp/packages/plugin-connections-administration/src/locales/zh.ts +++ b/webapp/packages/plugin-connections-administration/src/locales/zh.ts @@ -6,16 +6,13 @@ * you may not use this file except in compliance with the License. */ export default [ - ['connections_public_connection_edit_menu_item_title', '编辑连接'], - ['connections_public_connection_edit_cancel_title', '取消确认'], - ['connections_public_connection_edit_reconnect_title', '连接已更新'], - ['connections_public_connection_edit_reconnect_message', '连接已更新。您想重新连接吗?'], - ['connections_public_connection_edit_reconnect_failed', '重新连接失败'], + ['plugin_connections_connection_edit_menu_item_title', '编辑连接'], + ['plugin_connections_connection_edit_cancel_title', '取消确认'], + ['plugin_connections_connection_edit_reconnect_title', '连接已更新'], + ['plugin_connections_connection_edit_reconnect_message', '连接已更新。您想重新连接吗?'], + ['plugin_connections_connection_edit_reconnect_failed', '重新连接失败'], ['connections_administration_deactivate_message', '您的连接设置将丢失。您要继续吗?'], - [ - 'templates_administration_info_message', - '管理员可在数据库连接模板中定义各种可重用的连接参数,之后用户可基于这些模板创建多个数据库连接。', - ], + ['templates_administration_info_message', '管理员可在数据库连接模板中定义各种可重用的连接参数,之后用户可基于这些模板创建多个数据库连接。'], ['connections_administration_connection_create_error', 'Failed to create connection'], ]; diff --git a/webapp/packages/plugin-connections/src/ConnectionForm/DriverProperties/ConnectionDriverPropertiesTabService.ts b/webapp/packages/plugin-connections/src/ConnectionForm/DriverProperties/ConnectionDriverPropertiesTabService.ts index 6a275f786e..dd932d3f43 100644 --- a/webapp/packages/plugin-connections/src/ConnectionForm/DriverProperties/ConnectionDriverPropertiesTabService.ts +++ b/webapp/packages/plugin-connections/src/ConnectionForm/DriverProperties/ConnectionDriverPropertiesTabService.ts @@ -35,8 +35,8 @@ export class ConnectionDriverPropertiesTabService extends Bootstrap { override register(): void { this.connectionFormService.tabsContainer.add({ key: 'driver_properties', - name: 'customConnection_properties', - title: 'customConnection_properties', + name: 'plugin_connections_connection_form_part_properties', + title: 'plugin_connections_connection_form_part_properties', order: 2, panel: () => DriverPropertiesLoader, isDisabled: (tabId, props) => { diff --git a/webapp/packages/plugin-connections/src/ConnectionForm/Options/ConnectionOptionsTabService.ts b/webapp/packages/plugin-connections/src/ConnectionForm/Options/ConnectionOptionsTabService.ts index 294fae54ad..47e1cf91f6 100644 --- a/webapp/packages/plugin-connections/src/ConnectionForm/Options/ConnectionOptionsTabService.ts +++ b/webapp/packages/plugin-connections/src/ConnectionForm/Options/ConnectionOptionsTabService.ts @@ -64,7 +64,7 @@ export class ConnectionOptionsTabService extends Bootstrap { override register(): void { this.connectionFormService.tabsContainer.add({ key: 'options', - name: 'customConnection_main', + name: 'plugin_connections_connection_form_part_main', order: 1, panel: () => Options, }); @@ -382,7 +382,7 @@ export class ConnectionOptionsTabService extends Bootstrap { if (!this.userInfoResource.hasToken(providerId)) { const provider = await this.authProvidersResource.load(providerId); - const message = this.localizationService.translate('connections_public_connection_cloud_auth_required', undefined, { + const message = this.localizationService.translate('plugin_connections_connection_cloud_auth_required', undefined, { providerLabel: provider.label, }); stateContext.setInfo(message); diff --git a/webapp/packages/plugin-connections/src/ConnectionForm/Options/Options.tsx b/webapp/packages/plugin-connections/src/ConnectionForm/Options/Options.tsx index ae9c2f4be4..d95cd5fa7f 100644 --- a/webapp/packages/plugin-connections/src/ConnectionForm/Options/Options.tsx +++ b/webapp/packages/plugin-connections/src/ConnectionForm/Options/Options.tsx @@ -220,7 +220,7 @@ export const Options: TabContainerPanelComponent = observe readOnly={readonly} autoComplete={`section-${config.driverId || 'driver'} section-jdbc`} > - {translate('customConnection_url_JDBC')} + {translate('plugin_connections_connection_form_part_main_url_jdbc')} )} @@ -269,7 +269,7 @@ export const Options: TabContainerPanelComponent = observe tiny fill > - {translate('customConnection_folder')} + {translate('plugin_connections_connection_form_part_main_folder')} )} diff --git a/webapp/packages/plugin-connections/src/ConnectionForm/Options/ParametersForm.tsx b/webapp/packages/plugin-connections/src/ConnectionForm/Options/ParametersForm.tsx index 951388baf2..a83cbc8810 100644 --- a/webapp/packages/plugin-connections/src/ConnectionForm/Options/ParametersForm.tsx +++ b/webapp/packages/plugin-connections/src/ConnectionForm/Options/ParametersForm.tsx @@ -27,19 +27,19 @@ export const ParametersForm = observer(function ParametersForm({ config, {!embedded && ( - {translate('customConnection_custom_host')} + {translate('plugin_connections_connection_form_part_main_custom_host')} - {translate('customConnection_custom_port')} + {translate('plugin_connections_connection_form_part_main_custom_port')} )} - {translate('customConnection_custom_database')} + {translate('plugin_connections_connection_form_part_main_custom_database')} {requiresServerName && ( - {translate('customConnection_custom_server_name')} + {translate('plugin_connections_connection_form_part_main_custom_server_name')} )} diff --git a/webapp/packages/plugin-connections/src/ConnectionForm/OriginInfo/OriginInfo.tsx b/webapp/packages/plugin-connections/src/ConnectionForm/OriginInfo/OriginInfo.tsx index 190ea70392..faa3a65aee 100644 --- a/webapp/packages/plugin-connections/src/ConnectionForm/OriginInfo/OriginInfo.tsx +++ b/webapp/packages/plugin-connections/src/ConnectionForm/OriginInfo/OriginInfo.tsx @@ -96,7 +96,7 @@ export const OriginInfo: TabContainerPanelComponent = obse return ( - {translate('connections_public_connection_cloud_auth_required', undefined, { + {translate('plugin_connections_connection_cloud_auth_required', undefined, { providerLabel: providerLoader.data?.label, })} diff --git a/webapp/packages/plugin-connections/src/ConnectionForm/SSH/ConnectionSSHTabService.ts b/webapp/packages/plugin-connections/src/ConnectionForm/SSH/ConnectionSSHTabService.ts index a1ac615e61..1aaab6c0e4 100644 --- a/webapp/packages/plugin-connections/src/ConnectionForm/SSH/ConnectionSSHTabService.ts +++ b/webapp/packages/plugin-connections/src/ConnectionForm/SSH/ConnectionSSHTabService.ts @@ -46,7 +46,7 @@ export class ConnectionSSHTabService extends Bootstrap { override register(): void { this.connectionFormService.tabsContainer.add({ key: 'ssh', - name: 'customConnection_main', + name: 'plugin_connections_connection_form_part_main', order: 3, tab: () => SSHTab, panel: () => SSHPanel, diff --git a/webapp/packages/plugin-connections/src/ConnectionForm/SSL/SSL.tsx b/webapp/packages/plugin-connections/src/ConnectionForm/SSL/SSL.tsx index be86d56881..65698f3066 100644 --- a/webapp/packages/plugin-connections/src/ConnectionForm/SSL/SSL.tsx +++ b/webapp/packages/plugin-connections/src/ConnectionForm/SSL/SSL.tsx @@ -68,7 +68,7 @@ export const SSL: TabContainerPanelComponent = observer(function SSL({ st mod={['primary']} disabled={disabled || readonly} > - {translate('connections_public_connection_ssl_enable')} + {translate('plugin_connections_connection_ssl_enable')} {isUncategorizedExists && ( 0) { this.notificationService.logError({ - title: 'connections_public_connection_folder_move_failed', - message: this.localizationService.translate('connections_public_connection_folder_move_duplication', undefined, { + title: 'plugin_connections_connection_folder_move_failed', + message: this.localizationService.translate('plugin_connections_connection_folder_move_duplication', undefined, { name: folderDuplicates.map(node => `"${node.name}"`).join(', '), }), }); @@ -233,7 +233,7 @@ export class ConnectionFoldersBootstrap extends Bootstrap { this.connectionInfoResource.markOutdated(resourceKeyList(connections)); } catch (exception: any) { - this.notificationService.logException(exception, 'connections_public_connection_folder_move_failed'); + this.notificationService.logException(exception, 'plugin_connections_connection_folder_move_failed'); } } } diff --git a/webapp/packages/plugin-connections/src/PluginConnectionsSettingsService.ts b/webapp/packages/plugin-connections/src/PluginConnectionsSettingsService.ts index d9ef4cec64..83d7b4d3f2 100644 --- a/webapp/packages/plugin-connections/src/PluginConnectionsSettingsService.ts +++ b/webapp/packages/plugin-connections/src/PluginConnectionsSettingsService.ts @@ -41,8 +41,8 @@ export class PluginConnectionsSettingsService extends Dependency { // access: { // scope: ['server'], // }, - // name: 'settings_connections_hide_connections_view_name', - // description: 'settings_connections_hide_connections_view_description', + // name: 'plugin_connections_settings_hide_connections_view_name', + // description: 'plugin_connections_settings_hide_connections_view_description', // group: CONNECTIONS_SETTINGS_GROUP, // }, // ]); diff --git a/webapp/packages/plugin-connections/src/PublicConnectionForm/PublicConnectionFormService.ts b/webapp/packages/plugin-connections/src/PublicConnectionForm/PublicConnectionFormService.ts index c325cde384..28b52abf78 100644 --- a/webapp/packages/plugin-connections/src/PublicConnectionForm/PublicConnectionFormService.ts +++ b/webapp/packages/plugin-connections/src/PublicConnectionForm/PublicConnectionFormService.ts @@ -190,8 +190,8 @@ export class PublicConnectionFormService { } const result = await this.commonDialogService.open(ConfirmationDialog, { - title: 'connections_public_connection_edit_cancel_title', - message: 'connections_public_connection_edit_cancel_message', + title: 'plugin_connections_connection_edit_cancel_title', + message: 'plugin_connections_connection_edit_cancel_message', confirmActionText: 'ui_processing_ok', }); @@ -200,8 +200,8 @@ export class PublicConnectionFormService { private async tryReconnect(connectionKey: IConnectionInfoParams) { const result = await this.commonDialogService.open(ConfirmationDialog, { - title: 'connections_public_connection_edit_reconnect_title', - message: 'connections_public_connection_edit_reconnect_message', + title: 'plugin_connections_connection_edit_reconnect_title', + message: 'plugin_connections_connection_edit_reconnect_message', confirmActionText: 'ui_reconnect', }); @@ -213,7 +213,7 @@ export class PublicConnectionFormService { await this.connectionInfoResource.close(connectionKey); await this.connectionsManagerService.requireConnection(connectionKey); } catch (exception: any) { - this.notificationService.logException(exception, 'connections_public_connection_edit_reconnect_failed'); + this.notificationService.logException(exception, 'plugin_connections_connection_edit_reconnect_failed'); } } diff --git a/webapp/packages/plugin-connections/src/locales/en.ts b/webapp/packages/plugin-connections/src/locales/en.ts index 3935d3b310..8c55100259 100644 --- a/webapp/packages/plugin-connections/src/locales/en.ts +++ b/webapp/packages/plugin-connections/src/locales/en.ts @@ -6,27 +6,37 @@ * you may not use this file except in compliance with the License. */ export default [ - ['connections_public_connection_edit_menu_item_title', 'Edit Connection'], - ['connections_public_connection_edit_cancel_title', 'Cancel confirmation'], - ['connections_public_connection_edit_cancel_message', "You're going to cancel connection changes. Unsaved changes will be lost. Are you sure?"], - ['connections_public_connection_edit_reconnect_title', 'Connection updated'], - ['connections_public_connection_edit_reconnect_message', 'Connection has been updated. Do you want to reconnect?'], - ['connections_public_connection_edit_reconnect_failed', 'Failed to reconnect'], - ['connections_public_connection_folder_move_failed', 'Failed to move to folder'], - ['connections_public_connection_folder_move_duplication', 'Target folder or selected folders contains folder with the same name ({arg:name})'], - ['connections_public_connection_cloud_auth_required', 'You need to sign in with "{arg:providerLabel}" credentials to work with this connection.'], + ['plugin_connections_new_connection_dialog_title', 'New connection'], + ['plugin_connections_connection_form_part_main', 'Main'], + ['plugin_connections_connection_form_part_properties', 'Driver Properties'], + ['plugin_connections_connection_form_part_main_custom_host', 'Host'], + ['plugin_connections_connection_form_part_main_custom_port', 'Port'], + ['plugin_connections_connection_form_part_main_custom_server_name', 'Server name'], + ['plugin_connections_connection_form_part_main_custom_database', 'Database'], + ['plugin_connections_connection_form_part_main_url_jdbc', 'JDBC URL'], + ['plugin_connections_connection_form_part_main_folder', 'Folder'], + + ['plugin_connections_connection_edit_menu_item_title', 'Edit Connection'], + ['plugin_connections_connection_edit_cancel_title', 'Cancel confirmation'], + ['plugin_connections_connection_edit_cancel_message', "You're going to cancel connection changes. Unsaved changes will be lost. Are you sure?"], + ['plugin_connections_connection_edit_reconnect_title', 'Connection updated'], + ['plugin_connections_connection_edit_reconnect_message', 'Connection has been updated. Do you want to reconnect?'], + ['plugin_connections_connection_edit_reconnect_failed', 'Failed to reconnect'], + ['plugin_connections_connection_folder_move_failed', 'Failed to move to folder'], + ['plugin_connections_connection_folder_move_duplication', 'Target folder or selected folders contains folder with the same name ({arg:name})'], + ['plugin_connections_connection_cloud_auth_required', 'You need to sign in with "{arg:providerLabel}" credentials to work with this connection.'], ['plugin_connections_connection_form_project_invalid', 'You have no access to create connections in selected project'], ['plugin_connections_connection_form_host_configuration_invalid', 'Host configuration is not supported'], ['plugin_connections_connection_form_name_invalid', "Field 'Connection name' can't be empty"], ['plugin_connections_connection_form_host_invalid', "Field 'Host' can't be empty"], - ['connections_public_connection_folder_delete_confirmation', 'You\'re going to delete "{arg:name}". Connections won\'t be deleted. Are you sure?'], + ['plugin_connections_connection_folder_delete_confirmation', 'You\'re going to delete "{arg:name}". Connections won\'t be deleted. Are you sure?'], ['plugin_connections_menu_connections_label', 'Connection'], ['plugin_connections_action_disconnect_all_label', 'Disconnect All'], - ['settings_connections', 'Connections'], - ['settings_connections_hide_connections_view_name', 'Hide connections'], - ['settings_connections_hide_connections_view_description', 'Connections will be hidden for all users except administrators'], + ['plugin_connections_settings', 'Connections'], + ['plugin_connections_settings_hide_connections_view_name', 'Hide connections'], + ['plugin_connections_settings_hide_connections_view_description', 'Connections will be hidden for all users except administrators'], - ['connections_public_connection_ssl_enable', 'Enable SSL'], + ['plugin_connections_connection_ssl_enable', 'Enable SSL'], ['plugin_connections_connection_form_shared_credentials_manage_info', 'You can manage credentials in the '], ['plugin_connections_connection_form_shared_credentials_manage_info_tab_link', 'Credentials tab'], diff --git a/webapp/packages/plugin-connections/src/locales/fr.ts b/webapp/packages/plugin-connections/src/locales/fr.ts index 517a392ba6..89b98319ce 100644 --- a/webapp/packages/plugin-connections/src/locales/fr.ts +++ b/webapp/packages/plugin-connections/src/locales/fr.ts @@ -6,22 +6,32 @@ * you may not use this file except in compliance with the License. */ export default [ - ['connections_public_connection_edit_menu_item_title', 'Modifier la connexion'], - ['connections_public_connection_edit_cancel_title', "Confirmation d'annulation"], + ['plugin_connections_connection_form_part_main', 'Principal'], + ['plugin_connections_connection_form_part_properties', 'Propriétés du pilote'], + ['plugin_connections_connection_form_part_main_custom_host', 'Hôte'], + ['plugin_connections_connection_form_part_main_custom_port', 'Port'], + ['plugin_connections_connection_form_part_main_custom_server_name', 'Nom du serveur'], + ['plugin_connections_connection_form_part_main_custom_database', 'Base de données'], + ['plugin_connections_connection_form_part_main_url_jdbc', 'URL JDBC'], + ['plugin_connections_connection_form_part_main_folder', 'Dossier'], + ['plugin_connections_new_connection_dialog_title', 'Nouvelle connexion'], + + ['plugin_connections_connection_edit_menu_item_title', 'Modifier la connexion'], + ['plugin_connections_connection_edit_cancel_title', "Confirmation d'annulation"], [ - 'connections_public_connection_edit_cancel_message', + 'plugin_connections_connection_edit_cancel_message', 'Vous allez annuler les modifications de la connexion. Les modifications non enregistrées seront perdues. Êtes-vous sûr ?', ], - ['connections_public_connection_edit_reconnect_title', 'Connexion mise à jour'], - ['connections_public_connection_edit_reconnect_message', 'La connexion a été mise à jour. Voulez-vous vous reconnecter ?'], - ['connections_public_connection_edit_reconnect_failed', 'Échec de la reconnexion'], - ['connections_public_connection_folder_move_failed', 'Échec du déplacement vers le dossier'], + ['plugin_connections_connection_edit_reconnect_title', 'Connexion mise à jour'], + ['plugin_connections_connection_edit_reconnect_message', 'La connexion a été mise à jour. Voulez-vous vous reconnecter ?'], + ['plugin_connections_connection_edit_reconnect_failed', 'Échec de la reconnexion'], + ['plugin_connections_connection_folder_move_failed', 'Échec du déplacement vers le dossier'], [ - 'connections_public_connection_folder_move_duplication', + 'plugin_connections_connection_folder_move_duplication', 'Le dossier cible ou les dossiers sélectionnés contiennent un dossier portant le même nom ({arg:name})', ], [ - 'connections_public_connection_cloud_auth_required', + 'plugin_connections_connection_cloud_auth_required', 'Vous devez vous connecter avec les identifiants "{arg:providerLabel}" pour travailler avec cette connexion.', ], ['plugin_connections_connection_form_project_invalid', "Vous n'avez pas accès à la création de connexions dans le projet sélectionné"], @@ -29,16 +39,16 @@ export default [ ['plugin_connections_connection_form_name_invalid', 'Le champ "Nom de la connexion" ne peut pas être vide'], ['plugin_connections_connection_form_host_invalid', 'Le champ "Hôte" ne peut pas être vide'], [ - 'connections_public_connection_folder_delete_confirmation', + 'plugin_connections_connection_folder_delete_confirmation', 'Vous allez supprimer "{arg:name}". Les connexions ne seront pas supprimées. Êtes-vous sûr ?', ], ['plugin_connections_menu_connections_label', 'Connexion'], ['plugin_connections_action_disconnect_all_label', 'Déconnecter tout'], - ['settings_connections', 'Connexions'], - ['settings_connections_hide_connections_view_name', 'Hide connections'], - ['settings_connections_hide_connections_view_description', 'Connections will be hidden for all users except administrators'], + ['plugin_connections_settings', 'Connexions'], + ['plugin_connections_settings_hide_connections_view_name', 'Hide connections'], + ['plugin_connections_settings_hide_connections_view_description', 'Connections will be hidden for all users except administrators'], - ['connections_public_connection_ssl_enable', 'Activer SSL'], + ['plugin_connections_connection_ssl_enable', 'Activer SSL'], ['plugin_connections_connection_form_shared_credentials_manage_info', "Vous pouvez gérer les identifiants dans l'onglet "], ['plugin_connections_connection_form_shared_credentials_manage_info_tab_link', 'Onglet Identifiants'], diff --git a/webapp/packages/plugin-connections/src/locales/it.ts b/webapp/packages/plugin-connections/src/locales/it.ts index aab2d88d4e..986ec92b9b 100644 --- a/webapp/packages/plugin-connections/src/locales/it.ts +++ b/webapp/packages/plugin-connections/src/locales/it.ts @@ -6,29 +6,39 @@ * you may not use this file except in compliance with the License. */ export default [ - ['connections_public_connection_edit_menu_item_title', 'Modifica Connessione'], - ['connections_public_connection_edit_cancel_title', "Conferma l'annullamento"], + ['plugin_connections_connection_form_part_main', 'Main'], + ['plugin_connections_connection_form_part_properties', 'Proprietà del driver'], + ['plugin_connections_connection_form_part_main_custom_host', 'Host'], + ['plugin_connections_connection_form_part_main_custom_port', 'Porta'], + ['plugin_connections_connection_form_part_main_custom_server_name', 'Server name'], + ['plugin_connections_connection_form_part_main_custom_database', 'Database'], + ['plugin_connections_connection_form_part_main_url_jdbc', 'JDBC URL'], + ['plugin_connections_connection_form_part_main_folder', 'Folder'], + ['plugin_connections_new_connection_dialog_title', 'Nuova connessione'], + + ['plugin_connections_connection_edit_menu_item_title', 'Modifica Connessione'], + ['plugin_connections_connection_edit_cancel_title', "Conferma l'annullamento"], [ - 'connections_public_connection_edit_cancel_message', + 'plugin_connections_connection_edit_cancel_message', 'Stai per annullare le modifiche alla connessione. Modifiche non salvate saranno perse. Sei sicuro?', ], - ['connections_public_connection_edit_reconnect_title', 'Connection updated'], - ['connections_public_connection_edit_reconnect_message', 'Connection has been updated. Do you want to reconnect?'], - ['connections_public_connection_edit_reconnect_failed', 'Failed to reconnect'], - ['connections_public_connection_folder_move_failed', 'Failed to move to folder'], - ['connections_public_connection_folder_move_duplication', 'Target folder or selected folders contains folder with the same name ({arg:name})'], + ['plugin_connections_connection_edit_reconnect_title', 'Connection updated'], + ['plugin_connections_connection_edit_reconnect_message', 'Connection has been updated. Do you want to reconnect?'], + ['plugin_connections_connection_edit_reconnect_failed', 'Failed to reconnect'], + ['plugin_connections_connection_folder_move_failed', 'Failed to move to folder'], + ['plugin_connections_connection_folder_move_duplication', 'Target folder or selected folders contains folder with the same name ({arg:name})'], ['plugin_connections_connection_form_project_invalid', 'You have no access to create connections in selected project'], ['plugin_connections_connection_form_host_configuration_invalid', 'Host configuration is not supported'], ['plugin_connections_connection_form_name_invalid', "Field 'Connection name' can't be empty"], ['plugin_connections_connection_form_host_invalid', "Field 'Host' can't be empty"], - ['connections_public_connection_folder_delete_confirmation', 'You\'re going to delete "{arg:name}". Connections won\'t be deleted. Are you sure?'], + ['plugin_connections_connection_folder_delete_confirmation', 'You\'re going to delete "{arg:name}". Connections won\'t be deleted. Are you sure?'], ['plugin_connections_menu_connections_label', 'Connessione'], ['plugin_connections_action_disconnect_all_label', 'Scollegati da tutto'], - ['settings_connections', 'Connections'], - ['settings_connections_hide_connections_view_name', 'Hide connections'], - ['settings_connections_hide_connections_view_description', 'Connections will be hidden for all users except administrators'], + ['plugin_connections_settings', 'Connections'], + ['plugin_connections_settings_hide_connections_view_name', 'Hide connections'], + ['plugin_connections_settings_hide_connections_view_description', 'Connections will be hidden for all users except administrators'], - ['connections_public_connection_ssl_enable', 'Enable SSL'], + ['plugin_connections_connection_ssl_enable', 'Enable SSL'], ['plugin_connections_connection_form_shared_credentials_manage_info', 'You can manage credentials in the '], ['plugin_connections_connection_form_shared_credentials_manage_info_tab_link', 'Credentials tab'], diff --git a/webapp/packages/plugin-connections/src/locales/ru.ts b/webapp/packages/plugin-connections/src/locales/ru.ts index 0e420e9687..9b810049bf 100644 --- a/webapp/packages/plugin-connections/src/locales/ru.ts +++ b/webapp/packages/plugin-connections/src/locales/ru.ts @@ -6,27 +6,37 @@ * you may not use this file except in compliance with the License. */ export default [ - ['connections_public_connection_edit_menu_item_title', 'Изменить подключение'], - ['connections_public_connection_edit_cancel_title', 'Отмена редактирования'], - ['connections_public_connection_edit_cancel_message', 'Вы собираетесь закрыть редактор, несохраненные изменения не будут применены. Вы уверены?'], - ['connections_public_connection_edit_reconnect_title', 'Подключение обновлено'], - ['connections_public_connection_edit_reconnect_message', 'Подключение было обновлено. Вы хотите переподключиться?'], - ['connections_public_connection_edit_reconnect_failed', 'Не удалось переподключиться'], - ['connections_public_connection_folder_move_failed', 'Ошибка перемещения в папку'], - ['connections_public_connection_folder_move_duplication', 'Выбранные папки или папка назначения содержит папки с таким же названием ({arg:name})'], - ['connections_public_connection_cloud_auth_required', 'Вы должны подключиться через "{arg:providerLabel}", чтобы работать с этим соединением.'], + ['plugin_connections_connection_form_part_main', 'Главное'], + ['plugin_connections_connection_form_part_properties', 'Параметры драйвера'], + ['plugin_connections_connection_form_part_main_custom_host', 'Хост'], + ['plugin_connections_connection_form_part_main_custom_port', 'Порт'], + ['plugin_connections_connection_form_part_main_custom_server_name', 'Имя сервера'], + ['plugin_connections_connection_form_part_main_custom_database', 'База'], + ['plugin_connections_connection_form_part_main_url_jdbc', 'JDBC URL'], + ['plugin_connections_connection_form_part_main_folder', 'Папка'], + ['plugin_connections_new_connection_dialog_title', 'Новое подключение'], + + ['plugin_connections_connection_edit_menu_item_title', 'Изменить подключение'], + ['plugin_connections_connection_edit_cancel_title', 'Отмена редактирования'], + ['plugin_connections_connection_edit_cancel_message', 'Вы собираетесь закрыть редактор, несохраненные изменения не будут применены. Вы уверены?'], + ['plugin_connections_connection_edit_reconnect_title', 'Подключение обновлено'], + ['plugin_connections_connection_edit_reconnect_message', 'Подключение было обновлено. Вы хотите переподключиться?'], + ['plugin_connections_connection_edit_reconnect_failed', 'Не удалось переподключиться'], + ['plugin_connections_connection_folder_move_failed', 'Ошибка перемещения в папку'], + ['plugin_connections_connection_folder_move_duplication', 'Выбранные папки или папка назначения содержит папки с таким же названием ({arg:name})'], + ['plugin_connections_connection_cloud_auth_required', 'Вы должны подключиться через "{arg:providerLabel}", чтобы работать с этим соединением.'], ['plugin_connections_connection_form_project_invalid', 'У вас нет разрешения создавать коннекшены в выбранном проекте'], ['plugin_connections_connection_form_host_configuration_invalid', 'Конфигурация хоста не поддерживается'], ['plugin_connections_connection_form_name_invalid', "Поле 'Название подключения' не может быть пустым"], ['plugin_connections_connection_form_host_invalid', "Поле 'Хост' не может быть пустым"], - ['connections_public_connection_folder_delete_confirmation', 'Вы удаляете "{arg:name}". Подключения не будут удалены. Вы уверены?'], + ['plugin_connections_connection_folder_delete_confirmation', 'Вы удаляете "{arg:name}". Подключения не будут удалены. Вы уверены?'], ['plugin_connections_menu_connections_label', 'Подключение'], ['plugin_connections_action_disconnect_all_label', 'Отключить все'], - ['settings_connections', 'Подключения'], - ['settings_connections_hide_connections_view_name', 'Скрыть подключения'], - ['settings_connections_hide_connections_view_description', 'Подключения будут скрыты для всех пользователей, кроме администраторов'], + ['plugin_connections_settings', 'Подключения'], + ['plugin_connections_settings_hide_connections_view_name', 'Скрыть подключения'], + ['plugin_connections_settings_hide_connections_view_description', 'Подключения будут скрыты для всех пользователей, кроме администраторов'], - ['connections_public_connection_ssl_enable', 'Включить SSL'], + ['plugin_connections_connection_ssl_enable', 'Включить SSL'], ['plugin_connections_connection_form_shared_credentials_manage_info', 'Вы можете указать учетные данные в '], ['plugin_connections_connection_form_shared_credentials_manage_info_tab_link', 'во вкладке "Учетные данные"'], diff --git a/webapp/packages/plugin-connections/src/locales/zh.ts b/webapp/packages/plugin-connections/src/locales/zh.ts index 4d77c92380..ae9b7f3715 100644 --- a/webapp/packages/plugin-connections/src/locales/zh.ts +++ b/webapp/packages/plugin-connections/src/locales/zh.ts @@ -6,26 +6,36 @@ * you may not use this file except in compliance with the License. */ export default [ - ['connections_public_connection_edit_menu_item_title', '编辑连接'], - ['connections_public_connection_edit_cancel_title', '取消确认'], - ['connections_public_connection_edit_cancel_message', '您将取消连接更改。未保存的更改将丢失。您确定吗?'], - ['connections_public_connection_edit_reconnect_title', '连接已更新'], - ['connections_public_connection_edit_reconnect_message', '连接已更新。您想重新连接吗?'], - ['connections_public_connection_edit_reconnect_failed', '重新连接失败'], - ['connections_public_connection_folder_move_failed', '移动到文件夹失败'], - ['connections_public_connection_folder_move_duplication', '目标文件夹或所选文件夹包含同名文件夹 ({arg:name})'], + ['plugin_connections_connection_form_part_main', '主要'], + ['plugin_connections_connection_form_part_properties', '驱动属性'], + ['plugin_connections_connection_form_part_main_custom_host', '主机'], + ['plugin_connections_connection_form_part_main_custom_port', '端口'], + ['plugin_connections_connection_form_part_main_custom_server_name', '服务器名称'], + ['plugin_connections_connection_form_part_main_custom_database', '数据库'], + ['plugin_connections_connection_form_part_main_url_jdbc', 'JDBC URL'], + ['plugin_connections_connection_form_part_main_folder', '文件夹'], + ['plugin_connections_new_connection_dialog_title', '新连接'], + + ['plugin_connections_connection_edit_menu_item_title', '编辑连接'], + ['plugin_connections_connection_edit_cancel_title', '取消确认'], + ['plugin_connections_connection_edit_cancel_message', '您将取消连接更改。未保存的更改将丢失。您确定吗?'], + ['plugin_connections_connection_edit_reconnect_title', '连接已更新'], + ['plugin_connections_connection_edit_reconnect_message', '连接已更新。您想重新连接吗?'], + ['plugin_connections_connection_edit_reconnect_failed', '重新连接失败'], + ['plugin_connections_connection_folder_move_failed', '移动到文件夹失败'], + ['plugin_connections_connection_folder_move_duplication', '目标文件夹或所选文件夹包含同名文件夹 ({arg:name})'], ['plugin_connections_connection_form_project_invalid', '您无权在所选项目中创建连接'], ['plugin_connections_connection_form_host_configuration_invalid', '不支持主机配置'], ['plugin_connections_connection_form_name_invalid', "字段 '连接名称' 不可为空"], ['plugin_connections_connection_form_host_invalid', "字段 '主机' 不可为空"], - ['connections_public_connection_folder_delete_confirmation', '即将删除 "{arg:name}". 连接并不会删除,是否确定?'], + ['plugin_connections_connection_folder_delete_confirmation', '即将删除 "{arg:name}". 连接并不会删除,是否确定?'], ['plugin_connections_menu_connections_label', '连接'], ['plugin_connections_action_disconnect_all_label', '断开所有连接'], - ['settings_connections', '连接'], - ['settings_connections_hide_connections_view_name', 'Hide connections'], - ['settings_connections_hide_connections_view_description', 'Connections will be hidden for all users except administrators'], + ['plugin_connections_settings', '连接'], + ['plugin_connections_settings_hide_connections_view_name', 'Hide connections'], + ['plugin_connections_settings_hide_connections_view_description', 'Connections will be hidden for all users except administrators'], - ['connections_public_connection_ssl_enable', '启用 SSL'], + ['plugin_connections_connection_ssl_enable', '启用 SSL'], ['plugin_connections_connection_form_shared_credentials_manage_info', '您可在此管理凭证 '], ['plugin_connections_connection_form_shared_credentials_manage_info_tab_link', '凭证页签'], diff --git a/webapp/packages/plugin-user-profile/src/UserProfileForm/UserProfileFormPanel.tsx b/webapp/packages/plugin-user-profile/src/UserProfileForm/UserProfileFormPanel.tsx index 3df6297562..6831c578d3 100644 --- a/webapp/packages/plugin-user-profile/src/UserProfileForm/UserProfileFormPanel.tsx +++ b/webapp/packages/plugin-user-profile/src/UserProfileForm/UserProfileFormPanel.tsx @@ -41,8 +41,8 @@ export const UserProfileFormPanel: TabContainerPanelComponent = observer(functio if (state.isChanged && !context.force) { const result = await commonDialogService.open(ConfirmationDialog, { - title: 'connections_public_connection_edit_cancel_title', - message: 'connections_public_connection_edit_cancel_message', + title: 'plugin_connections_connection_edit_cancel_title', + message: 'plugin_connections_connection_edit_cancel_message', confirmActionText: 'ui_processing_ok', });