diff --git a/config/sample-databases/DefaultConfiguration/cloudbeaver.conf b/config/sample-databases/DefaultConfiguration/cloudbeaver.conf index 168e296f93..e4f986e684 100644 --- a/config/sample-databases/DefaultConfiguration/cloudbeaver.conf +++ b/config/sample-databases/DefaultConfiguration/cloudbeaver.conf @@ -38,6 +38,7 @@ anonymousAccessEnabled: true, anonymousUserRole: "user", supportsCustomConnections: false, + showReadOnlyConnectionInfo: false, forwardProxy: false, diff --git a/config/sample-databases/SQLiteConfiguration/cloudbeaver.conf b/config/sample-databases/SQLiteConfiguration/cloudbeaver.conf index a1f14be291..5dbc3c8d71 100644 --- a/config/sample-databases/SQLiteConfiguration/cloudbeaver.conf +++ b/config/sample-databases/SQLiteConfiguration/cloudbeaver.conf @@ -38,6 +38,7 @@ anonymousAccessEnabled: true, anonymousUserRole: "user", supportsCustomConnections: false, + showReadOnlyConnectionInfo: false, forwardProxy: false, diff --git a/deploy/docker/Dockerfile b/deploy/docker/Dockerfile index 5e32885cae..8a041b51ed 100644 --- a/deploy/docker/Dockerfile +++ b/deploy/docker/Dockerfile @@ -1,5 +1,4 @@ -ARG ARCH=amd64 -FROM ${ARCH}/eclipse-temurin:17.0.4.1_1-jre-focal +FROM eclipse-temurin:17.0.4.1_1-jre-focal COPY cloudbeaver /opt/cloudbeaver diff --git a/server/bundles/io.cloudbeaver.model/META-INF/MANIFEST.MF b/server/bundles/io.cloudbeaver.model/META-INF/MANIFEST.MF index a99f1bcca3..7ae78071a0 100644 --- a/server/bundles/io.cloudbeaver.model/META-INF/MANIFEST.MF +++ b/server/bundles/io.cloudbeaver.model/META-INF/MANIFEST.MF @@ -3,12 +3,13 @@ Bundle-ManifestVersion: 2 Bundle-Vendor: %Bundle-Vendor Bundle-Name: %Bundle-Name Bundle-SymbolicName: io.cloudbeaver.model;singleton:=true -Bundle-Version: 1.0.16.qualifier -Bundle-Release-Date: 20221107 +Bundle-Version: 1.0.17.qualifier +Bundle-Release-Date: 20221121 Bundle-RequiredExecutionEnvironment: JavaSE-11 Bundle-ActivationPolicy: lazy Bundle-ClassPath: . Require-Bundle: org.jkiss.dbeaver.model;visibility:=reexport, + org.jkiss.dbeaver.model.sm;visibility:=reexport, org.jkiss.dbeaver.registry;visibility:=reexport, org.jkiss.dbeaver.net.ssh, org.jkiss.bundle.graphql.java;visibility:=reexport, diff --git a/server/bundles/io.cloudbeaver.model/plugin.xml b/server/bundles/io.cloudbeaver.model/plugin.xml index 96847f47d7..ec0dd5a019 100644 --- a/server/bundles/io.cloudbeaver.model/plugin.xml +++ b/server/bundles/io.cloudbeaver.model/plugin.xml @@ -7,4 +7,6 @@ + + diff --git a/server/bundles/io.cloudbeaver.model/pom.xml b/server/bundles/io.cloudbeaver.model/pom.xml index 6c58cc5d6c..61c409252c 100644 --- a/server/bundles/io.cloudbeaver.model/pom.xml +++ b/server/bundles/io.cloudbeaver.model/pom.xml @@ -10,7 +10,7 @@ ../ io.cloudbeaver.model - 1.0.16-SNAPSHOT + 1.0.17-SNAPSHOT eclipse-plugin diff --git a/server/bundles/io.cloudbeaver.service.auth/schema/io.cloudbeaver.userProfile.exsd b/server/bundles/io.cloudbeaver.model/schema/io.cloudbeaver.metaParameters.exsd similarity index 85% rename from server/bundles/io.cloudbeaver.service.auth/schema/io.cloudbeaver.userProfile.exsd rename to server/bundles/io.cloudbeaver.model/schema/io.cloudbeaver.metaParameters.exsd index 5901571b6a..fe9b6f92fb 100644 --- a/server/bundles/io.cloudbeaver.service.auth/schema/io.cloudbeaver.userProfile.exsd +++ b/server/bundles/io.cloudbeaver.model/schema/io.cloudbeaver.metaParameters.exsd @@ -2,7 +2,7 @@ - + diff --git a/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/WebDataSourceRegistryProxy.java b/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/WebDataSourceRegistryProxy.java index 7c781afdd2..eacb137ba4 100644 --- a/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/WebDataSourceRegistryProxy.java +++ b/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/WebDataSourceRegistryProxy.java @@ -1,3 +1,20 @@ +/* + * DBeaver - Universal Database Manager + * Copyright (C) 2010-2022 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 org.jkiss.code.NotNull; 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 3f24947c00..dbfe02cb02 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 @@ -17,11 +17,14 @@ package io.cloudbeaver.model; import io.cloudbeaver.WebProjectImpl; +import io.cloudbeaver.model.app.BaseWebAppConfiguration; import io.cloudbeaver.model.session.WebSession; import io.cloudbeaver.service.security.SMUtils; import io.cloudbeaver.service.sql.WebDataFormat; import io.cloudbeaver.utils.CBModelConstants; +import io.cloudbeaver.utils.WebAppUtils; import io.cloudbeaver.utils.WebCommonUtils; +import org.jkiss.dbeaver.DBException; import org.jkiss.dbeaver.model.DBPDataSource; import org.jkiss.dbeaver.model.DBPDataSourceContainer; import org.jkiss.dbeaver.model.DBPDataSourceFolder; @@ -38,10 +41,7 @@ import org.jkiss.dbeaver.model.rm.RMProjectPermission; import org.jkiss.dbeaver.runtime.DBWorkbench; import org.jkiss.utils.CommonUtils; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; -import java.util.Map; +import java.util.*; import java.util.stream.Collectors; /** @@ -49,6 +49,7 @@ import java.util.stream.Collectors; */ public class WebConnectionInfo { + private static final String SECURED_VALUE = "********"; private final WebSession session; private final DBPDataSourceContainer dataSourceContainer; private WebServerError connectError; @@ -99,12 +100,18 @@ public class WebConnectionInfo { @Property public String getHost() { - return dataSourceContainer.getConnectionConfiguration().getHostName(); + if (canViewReadOnlyConnections()) { + return dataSourceContainer.getConnectionConfiguration().getHostName(); + } + return SECURED_VALUE; } @Property public String getPort() { - return dataSourceContainer.getConnectionConfiguration().getHostPort(); + if (canViewReadOnlyConnections()) { + return dataSourceContainer.getConnectionConfiguration().getHostPort(); + } + return SECURED_VALUE; } @Property @@ -114,17 +121,26 @@ public class WebConnectionInfo { @Property public String getDatabaseName() { - return dataSourceContainer.getConnectionConfiguration().getDatabaseName(); + if (canViewReadOnlyConnections()) { + return dataSourceContainer.getConnectionConfiguration().getDatabaseName(); + } + return SECURED_VALUE; } @Property public String getUrl() { - return dataSourceContainer.getConnectionConfiguration().getUrl(); + if (canViewReadOnlyConnections()) { + return dataSourceContainer.getConnectionConfiguration().getUrl(); + } + return SECURED_VALUE; } @Property public Map getProperties() { - return dataSourceContainer.getConnectionConfiguration().getProperties(); + if (canViewReadOnlyConnections()) { + return dataSourceContainer.getConnectionConfiguration().getProperties(); + } + return Collections.emptyMap(); } @Property @@ -157,6 +173,16 @@ public class WebConnectionInfo { return dataSourceContainer.isSavePassword(); } + @Property + public boolean isCredentialsSaved() throws DBException { + return dataSourceContainer.isCredentialsSaved(); + } + + @Property + public boolean isSharedCredentials() { + return dataSourceContainer.isSharedCredentials(); + } + @Property public String getFolder() { DBPDataSourceFolder folder = dataSourceContainer.getFolder(); @@ -265,9 +291,9 @@ public class WebConnectionInfo { } @Property - public boolean isAuthNeeded() { + public boolean isAuthNeeded() throws DBException { return !dataSourceContainer.isConnected() && - !dataSourceContainer.isSavePassword() && + !dataSourceContainer.isCredentialsSaved() && !dataSourceContainer.getDriver().isAnonymousAccess(); } @@ -301,8 +327,11 @@ public class WebConnectionInfo { @Property public List getNetworkHandlersConfig() { - return dataSourceContainer.getConnectionConfiguration().getHandlers().stream() - .map(WebNetworkHandlerConfig::new).collect(Collectors.toList()); + if (canViewReadOnlyConnections()) { + return dataSourceContainer.getConnectionConfiguration().getHandlers().stream() + .map(WebNetworkHandlerConfig::new).collect(Collectors.toList()); + } + return Collections.emptyList(); } @Property @@ -341,7 +370,7 @@ public class WebConnectionInfo { @Property public boolean isCanViewSettings() { - return true; + return canViewReadOnlyConnections(); } @Property @@ -371,4 +400,13 @@ public class WebConnectionInfo { } return SMUtils.hasProjectPermission(session, ((WebProjectImpl) project).getRmProject(), projectPermission); } + + private boolean canViewReadOnlyConnections() { + if (isCanEdit()) { + return true; + } + BaseWebAppConfiguration appConfig = (BaseWebAppConfiguration) WebAppUtils.getWebApplication().getAppConfiguration(); + return appConfig.isShowReadOnlyConnectionInfo(); + + } } diff --git a/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/model/app/BaseWebAppConfiguration.java b/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/model/app/BaseWebAppConfiguration.java index 82a17315e5..7d02c127f5 100644 --- a/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/model/app/BaseWebAppConfiguration.java +++ b/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/model/app/BaseWebAppConfiguration.java @@ -31,6 +31,7 @@ public abstract class BaseWebAppConfiguration implements WebAppConfiguration { protected final Map plugins; protected String defaultUserTeam; protected boolean resourceManagerEnabled; + protected boolean showReadOnlyConnectionInfo; protected String[] enabledFeatures; public BaseWebAppConfiguration() { @@ -38,6 +39,7 @@ public abstract class BaseWebAppConfiguration implements WebAppConfiguration { this.defaultUserTeam = DEFAULT_APP_ANONYMOUS_TEAM_NAME; this.resourceManagerEnabled = true; this.enabledFeatures = null; + this.showReadOnlyConnectionInfo = false; } public BaseWebAppConfiguration(BaseWebAppConfiguration src) { @@ -45,6 +47,7 @@ public abstract class BaseWebAppConfiguration implements WebAppConfiguration { this.defaultUserTeam = src.defaultUserTeam; this.resourceManagerEnabled = src.resourceManagerEnabled; this.enabledFeatures = src.enabledFeatures; + this.showReadOnlyConnectionInfo = src.showReadOnlyConnectionInfo; } @Override @@ -98,4 +101,8 @@ public abstract class BaseWebAppConfiguration implements WebAppConfiguration { public void setEnabledFeatures(String[] enabledFeatures) { this.enabledFeatures = enabledFeatures; } + + public boolean isShowReadOnlyConnectionInfo() { + return showReadOnlyConnectionInfo; + } } 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 bf7ebc726f..048bf5a3b8 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 @@ -34,7 +34,6 @@ import org.jkiss.dbeaver.model.app.DBPWorkspace; import org.jkiss.dbeaver.model.auth.SMCredentialsProvider; import org.jkiss.dbeaver.model.data.json.JSONUtils; import org.jkiss.dbeaver.model.impl.app.ApplicationRegistry; -import org.jkiss.dbeaver.model.impl.app.LocalSecretController; import org.jkiss.dbeaver.model.rm.RMController; import org.jkiss.dbeaver.model.rm.RMProject; import org.jkiss.dbeaver.model.secret.DBSSecretController; @@ -140,9 +139,14 @@ public abstract class BaseWebApplication extends BaseApplicationImpl implements ); } + /** + * There is no secret controller in base web app. + * Method returns VoidSecretController instance. + * Advanced apps may implement it differently. + */ @Override public DBSSecretController getSecretController(@NotNull SMCredentialsProvider credentialsProvider) throws DBException { - return new LocalSecretController("user/" + credentialsProvider.getActiveUserCredentials().getUserId()); + return VoidSecretController.INSTANCE; } protected Map getServerConfigProps(Map configProps) { diff --git a/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/model/app/VoidSecretController.java b/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/model/app/VoidSecretController.java new file mode 100644 index 0000000000..12bbb9b255 --- /dev/null +++ b/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/model/app/VoidSecretController.java @@ -0,0 +1,50 @@ +/* + * DBeaver - Universal Database Manager + * Copyright (C) 2010-2022 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.model.app; + +import org.jkiss.code.NotNull; +import org.jkiss.code.Nullable; +import org.jkiss.dbeaver.DBException; +import org.jkiss.dbeaver.model.secret.DBSSecretController; + +/** + * Void secret controller. + */ +public class VoidSecretController implements DBSSecretController { + + public static final VoidSecretController INSTANCE = new VoidSecretController(); + + public VoidSecretController() { + + } + + @Nullable + @Override + public String getSecretValue(@NotNull String secretId) { + return null; + } + + @Override + public void setSecretValue(@NotNull String secretId, @Nullable String secretValue) throws DBException { + throw new DBException("Secret controller is read-only"); + } + + @Override + public void flushChanges() { + } + +} \ No newline at end of file diff --git a/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/model/rm/RMUtils.java b/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/model/rm/RMUtils.java index 4060ef878b..5b53c616e9 100644 --- a/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/model/rm/RMUtils.java +++ b/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/model/rm/RMUtils.java @@ -3,10 +3,12 @@ package io.cloudbeaver.model.rm; import io.cloudbeaver.DBWConstants; import io.cloudbeaver.model.app.BaseWebApplication; import org.jkiss.code.NotNull; +import org.jkiss.dbeaver.DBException; import org.jkiss.dbeaver.model.rm.RMProject; import org.jkiss.dbeaver.model.rm.RMProjectPermission; import org.jkiss.dbeaver.model.rm.RMProjectType; import org.jkiss.dbeaver.runtime.DBWorkbench; +import org.jkiss.utils.CommonUtils; import java.nio.file.Path; import java.util.Objects; @@ -46,18 +48,25 @@ public class RMUtils { * @return path to the project based on the name of projects and prefixes that it contains */ @NotNull - public static Path getProjectPathByName(@NotNull String projectId) { - if (!projectId.contains("_") || projectId.startsWith("_")) { - return getRootPath().resolve(BaseWebApplication.getInstance().getDefaultProjectName()); + public static Path getProjectPathByName(@NotNull String projectId) throws DBException { + int divPos = projectId.indexOf("_"); + if (divPos <= 0) { + throw new DBException("Bad project ID"); } - String prefix = projectId.substring(0, projectId.indexOf("_")); + + String prefix = projectId.substring(0, divPos); + String projectName = projectId.substring(divPos + 1); switch (RMProjectType.getByPrefix(prefix)) { case GLOBAL: - return getRootPath().resolve(BaseWebApplication.getInstance().getDefaultProjectName()); + String defaultProjectName = BaseWebApplication.getInstance().getDefaultProjectName(); + if (CommonUtils.isEmpty(defaultProjectName)) { + throw new DBException("Global projects are not supported"); + } + return getRootPath().resolve(defaultProjectName); case SHARED: - return getSharedProjectsPath().resolve(projectId); + return getSharedProjectsPath().resolve(projectName); default: - return getUserProjectsPath().resolve(projectId); + return getUserProjectsPath().resolve(projectName); } } 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 5fa715498e..6463d8ccd0 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 @@ -155,6 +155,7 @@ public class LocalResourceController implements RMController { if (userProject != null) { projects.add(0, userProject); } + projects.sort(Comparator.comparing(RMProject::getDisplayName)); return projects.toArray(new RMProject[0]); } @@ -172,7 +173,6 @@ public class LocalResourceController implements RMController { RMProjectType.SHARED, true) ) .filter(Objects::nonNull) - .sorted(Comparator.comparing(RMProject::getDisplayName)) .collect(Collectors.toList()); } diff --git a/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/model/session/WebUserContext.java b/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/model/session/WebUserContext.java index 7338aa2ba4..0269f7248e 100644 --- a/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/model/session/WebUserContext.java +++ b/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/model/session/WebUserContext.java @@ -23,11 +23,13 @@ import io.cloudbeaver.model.user.WebUser; import org.jkiss.code.NotNull; import org.jkiss.code.Nullable; import org.jkiss.dbeaver.DBException; +import org.jkiss.dbeaver.Log; import org.jkiss.dbeaver.model.auth.SMAuthInfo; import org.jkiss.dbeaver.model.auth.SMAuthStatus; import org.jkiss.dbeaver.model.auth.SMCredentials; import org.jkiss.dbeaver.model.auth.SMCredentialsProvider; import org.jkiss.dbeaver.model.exec.DBCException; +import org.jkiss.dbeaver.model.secret.DBSSecretController; import org.jkiss.dbeaver.model.security.SMAdminController; import org.jkiss.dbeaver.model.security.SMController; import org.jkiss.utils.CommonUtils; @@ -40,6 +42,8 @@ import java.util.Set; * Contains user state and services based on available permissions */ public class WebUserContext implements SMCredentialsProvider { + private static final Log log = Log.getLog(WebUserContext.class); + private final WebApplication application; private WebUser user; @@ -50,6 +54,7 @@ public class WebUserContext implements SMCredentialsProvider { private SMController securityController; private SMAdminController adminSecurityController; + private DBSSecretController secretController; public WebUserContext(WebApplication application) throws DBException { this.application = application; @@ -64,7 +69,7 @@ public class WebUserContext implements SMCredentialsProvider { * @throws DBException - if user already authorized and new token come from another user */ public synchronized boolean refresh(SMAuthInfo smAuthInfo) throws DBException { - if (smAuthInfo.getAuthStatus() != SMAuthStatus.SUCCESS) { + if (smAuthInfo.getAuthStatus() != SMAuthStatus.SUCCESS || smAuthInfo.getSmAuthToken() == null) { throw new DBCException("Authorization did not complete successfully"); } var isNonAnonymousUserAuthorized = isAuthorizedInSecurityManager() && getUser() != null; @@ -85,6 +90,7 @@ public class WebUserContext implements SMCredentialsProvider { this.userPermissions = authPermissions.getPermissions(); this.securityController = application.createSecurityController(this); this.adminSecurityController = application.getAdminSecurityController(this); + this.secretController = application.getSecretController(this); if (isSessionChanged) { this.smSessionId = smAuthInfo.getAuthPermissions().getSessionId(); setUser(authPermissions.getUserId() == null ? null : new WebUser(securityController.getCurrentUser())); @@ -114,12 +120,14 @@ public class WebUserContext implements SMCredentialsProvider { this.securityController.logout(); } } catch (Exception e) { + log.error("Error logging out user", e); } this.userPermissions = getDefaultPermissions(); this.smCredentials = null; this.user = null; this.securityController = application.createSecurityController(this); this.adminSecurityController = null; + this.secretController = application.getSecretController(this); } @NotNull @@ -172,6 +180,10 @@ public class WebUserContext implements SMCredentialsProvider { } } + public DBSSecretController getSecretController() { + return secretController; + } + public synchronized String getSmSessionId() { return smSessionId; } diff --git a/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/registry/WebAuthProviderDescriptor.java b/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/registry/WebAuthProviderDescriptor.java index a6c46bebc1..087dfda5b0 100644 --- a/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/registry/WebAuthProviderDescriptor.java +++ b/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/registry/WebAuthProviderDescriptor.java @@ -46,7 +46,7 @@ public class WebAuthProviderDescriptor extends AbstractDescriptor { private final IConfigurationElement cfg; private final ObjectType implType; - private final Map> metaProperties = new HashMap<>(); + private final Map> metaParameters = new HashMap<>(); private SMAuthProvider instance; private final DBPImage icon; private final Map configurationParameters = new LinkedHashMap<>(); @@ -76,13 +76,13 @@ public class WebAuthProviderDescriptor extends AbstractDescriptor { for (IConfigurationElement credElement : cfg.getChildren("credentials")) { credentialProfiles.add(new SMAuthCredentialsProfile(credElement)); } - for (IConfigurationElement mpElement : cfg.getChildren("metaProperties")) { + for (IConfigurationElement mpElement : cfg.getChildren("metaParameters")) { SMSubjectType subjectType = CommonUtils.valueOf(SMSubjectType.class, mpElement.getAttribute("type"), SMSubjectType.user); List metaProps = new ArrayList<>(); for (IConfigurationElement propGroup : ArrayUtils.safeArray(mpElement.getChildren(PropertyDescriptor.TAG_PROPERTY_GROUP))) { metaProps.addAll(PropertyDescriptor.extractProperties(propGroup)); } - metaProperties.put(subjectType, metaProps); + metaParameters.put(subjectType, metaProps); } String rfList = cfg.getAttribute("requiredFeatures"); @@ -182,8 +182,8 @@ public class WebAuthProviderDescriptor extends AbstractDescriptor { } @Nullable - public List getMetaProperties(SMSubjectType subjectType) { - return metaProperties.get(subjectType); + public List getMetaParameters(SMSubjectType subjectType) { + return metaParameters.get(subjectType); } } diff --git a/server/bundles/io.cloudbeaver.service.auth/src/io/cloudbeaver/registry/WebUserProfileRegistry.java b/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/registry/WebMetaParametersRegistry.java similarity index 57% rename from server/bundles/io.cloudbeaver.service.auth/src/io/cloudbeaver/registry/WebUserProfileRegistry.java rename to server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/registry/WebMetaParametersRegistry.java index 796f62b3e2..c8f11f6211 100644 --- a/server/bundles/io.cloudbeaver.service.auth/src/io/cloudbeaver/registry/WebUserProfileRegistry.java +++ b/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/registry/WebMetaParametersRegistry.java @@ -27,36 +27,47 @@ import org.jkiss.utils.ArrayUtils; import java.util.ArrayList; import java.util.List; -public class WebUserProfileRegistry { +public class WebMetaParametersRegistry { - private static final Log log = Log.getLog(WebUserProfileRegistry.class); + private static final Log log = Log.getLog(WebMetaParametersRegistry.class); - public static final String EXTENSION_ID = "io.cloudbeaver.userProfile"; //$NON-NLS-1$ + public static final String EXTENSION_ID = "io.cloudbeaver.metaParameters"; //$NON-NLS-1$ - private static WebUserProfileRegistry instance = null; - private final List properties = new ArrayList<>(); + private static WebMetaParametersRegistry instance = null; + private final List userParameters = new ArrayList<>(); + private final List teamParameters = new ArrayList<>(); - public synchronized static WebUserProfileRegistry getInstance() { + public synchronized static WebMetaParametersRegistry getInstance() { if (instance == null) { - instance = new WebUserProfileRegistry(); + instance = new WebMetaParametersRegistry(); instance.loadExtensions(Platform.getExtensionRegistry()); } return instance; } - private WebUserProfileRegistry() { + private WebMetaParametersRegistry() { } - public List getProperties() { - return properties; + public List getUserParameters() { + return userParameters; + } + + public List getTeamParameters() { + return teamParameters; } private void loadExtensions(IExtensionRegistry registry) { IConfigurationElement[] extConfigs = registry.getConfigurationElementsFor(EXTENSION_ID); for (IConfigurationElement ext : extConfigs) { - if (ext.getName().equals("userProfileProperties")) { + if (ext.getName().equals("metaParameters")) { + boolean isUser = "user".equals(ext.getAttribute("type")); for (IConfigurationElement propGroup : ArrayUtils.safeArray(ext.getChildren(PropertyDescriptor.TAG_PROPERTY_GROUP))) { - properties.addAll(PropertyDescriptor.extractProperties(propGroup)); + List props = PropertyDescriptor.extractProperties(propGroup); + if (isUser) { + userParameters.addAll(props); + } else { + teamParameters.addAll(props); + } } } } diff --git a/server/bundles/io.cloudbeaver.product.ce/META-INF/MANIFEST.MF b/server/bundles/io.cloudbeaver.product.ce/META-INF/MANIFEST.MF index ebc2d9d70b..6e07c156a7 100644 --- a/server/bundles/io.cloudbeaver.product.ce/META-INF/MANIFEST.MF +++ b/server/bundles/io.cloudbeaver.product.ce/META-INF/MANIFEST.MF @@ -3,8 +3,8 @@ Bundle-ManifestVersion: 2 Bundle-Vendor: %Bundle-Vendor Bundle-Name: %Bundle-Name Bundle-SymbolicName: io.cloudbeaver.product.ce;singleton:=true -Bundle-Version: 22.2.4.qualifier -Bundle-Release-Date: 20221107 +Bundle-Version: 22.2.5.qualifier +Bundle-Release-Date: 20221121 Bundle-RequiredExecutionEnvironment: JavaSE-11 Bundle-ActivationPolicy: lazy Bundle-ClassPath: . diff --git a/server/bundles/io.cloudbeaver.product.ce/pom.xml b/server/bundles/io.cloudbeaver.product.ce/pom.xml index 6cc9f578ef..5585e89770 100644 --- a/server/bundles/io.cloudbeaver.product.ce/pom.xml +++ b/server/bundles/io.cloudbeaver.product.ce/pom.xml @@ -10,7 +10,7 @@ ../ io.cloudbeaver.product.ce - 22.2.4-SNAPSHOT + 22.2.5-SNAPSHOT eclipse-plugin diff --git a/server/bundles/io.cloudbeaver.resources.drivers.base/META-INF/MANIFEST.MF b/server/bundles/io.cloudbeaver.resources.drivers.base/META-INF/MANIFEST.MF index b63393ed03..b955039986 100644 --- a/server/bundles/io.cloudbeaver.resources.drivers.base/META-INF/MANIFEST.MF +++ b/server/bundles/io.cloudbeaver.resources.drivers.base/META-INF/MANIFEST.MF @@ -2,8 +2,8 @@ Manifest-Version: 1.0 Bundle-ManifestVersion: 2 Bundle-Name: Base JDBC drivers Bundle-SymbolicName: io.cloudbeaver.resources.drivers.base;singleton:=true -Bundle-Version: 1.0.61.qualifier -Bundle-Release-Date: 20221107 +Bundle-Version: 1.0.62.qualifier +Bundle-Release-Date: 20221121 Bundle-Vendor: DBeaver Corp Bundle-ActivationPolicy: lazy Automatic-Module-Name: io.cloudbeaver.resources.drivers.base diff --git a/server/bundles/io.cloudbeaver.resources.drivers.base/pom.xml b/server/bundles/io.cloudbeaver.resources.drivers.base/pom.xml index a1ac12206d..d769225d92 100644 --- a/server/bundles/io.cloudbeaver.resources.drivers.base/pom.xml +++ b/server/bundles/io.cloudbeaver.resources.drivers.base/pom.xml @@ -9,6 +9,6 @@ ../ io.cloudbeaver.resources.drivers.base - 1.0.61-SNAPSHOT + 1.0.62-SNAPSHOT eclipse-plugin diff --git a/server/bundles/io.cloudbeaver.server/META-INF/MANIFEST.MF b/server/bundles/io.cloudbeaver.server/META-INF/MANIFEST.MF index 79ca58304c..2586cb7ef5 100644 --- a/server/bundles/io.cloudbeaver.server/META-INF/MANIFEST.MF +++ b/server/bundles/io.cloudbeaver.server/META-INF/MANIFEST.MF @@ -3,8 +3,8 @@ Bundle-ManifestVersion: 2 Bundle-Vendor: %Bundle-Vendor Bundle-Name: %Bundle-Name Bundle-SymbolicName: io.cloudbeaver.server;singleton:=true -Bundle-Version: 22.2.4.qualifier -Bundle-Release-Date: 20221107 +Bundle-Version: 22.2.5.qualifier +Bundle-Release-Date: 20221121 Bundle-RequiredExecutionEnvironment: JavaSE-11 Bundle-ActivationPolicy: lazy Bundle-Activator: io.cloudbeaver.server.CBPlatformActivator diff --git a/server/bundles/io.cloudbeaver.server/pom.xml b/server/bundles/io.cloudbeaver.server/pom.xml index dac95913a5..41606d0cda 100644 --- a/server/bundles/io.cloudbeaver.server/pom.xml +++ b/server/bundles/io.cloudbeaver.server/pom.xml @@ -10,7 +10,7 @@ ../ io.cloudbeaver.server - 22.2.4-SNAPSHOT + 22.2.5-SNAPSHOT eclipse-plugin diff --git a/server/bundles/io.cloudbeaver.server/schema/service.core.graphqls b/server/bundles/io.cloudbeaver.server/schema/service.core.graphqls index 8dcec45ed7..bd2c65cb57 100644 --- a/server/bundles/io.cloudbeaver.server/schema/service.core.graphqls +++ b/server/bundles/io.cloudbeaver.server/schema/service.core.graphqls @@ -301,8 +301,19 @@ type ConnectionInfo { connected: Boolean! provided: Boolean! readOnly: Boolean! + # Forces connection URL use, host/port/database parameters will be ignored useUrl: Boolean! + + # Forces credentials save. This flag doesn't work in shared projects. saveCredentials: Boolean! + # Shared credentials - the same for all users, stored in secure storage. + sharedCredentials: Boolean! + # Determines that credentials were saved for current user. + # This field read is slow, it should be read only when it really needed + credentialsSaved: Boolean! + # Determines that additional credentials are needed to connect + # This field read is slow, it should be read only when it really needed + authNeeded: Boolean! folder: ID nodePath: String @@ -314,7 +325,6 @@ type ConnectionInfo { origin: ObjectOrigin! - authNeeded: Boolean! authModel: ID authProperties: [ObjectPropertyInfo!]! @@ -453,6 +463,7 @@ input ConnectionConfig { # User credentials saveCredentials: Boolean + sharedCredentials: Boolean authModelId: ID credentials: Object @@ -558,7 +569,8 @@ extend type Mutation { testNetworkHandler( config: NetworkHandlerConfigInput! ): NetworkEndpointInfo! # Initiate existing connection - initConnection( id: ID!, projectId: ID, credentials: Object, networkCredentials: [NetworkHandlerConfigInput!], saveCredentials: Boolean ): ConnectionInfo! + initConnection( id: ID!, projectId: ID, credentials: Object, networkCredentials: [NetworkHandlerConfigInput!], + saveCredentials:Boolean, sharedCredentials: Boolean ): ConnectionInfo! # Disconnect from database closeConnection( id: ID!, projectId: ID ): ConnectionInfo! 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 6f2a43060c..893cdc96b1 100644 --- a/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/WebServiceUtils.java +++ b/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/WebServiceUtils.java @@ -140,7 +140,13 @@ public class WebServiceUtils extends WebCommonUtils { //navSettings.setShowSystemObjects(false); ((DataSourceDescriptor)newDataSource).setNavigatorSettings(navSettings); - saveAuthProperties(newDataSource, newDataSource.getConnectionConfiguration(), config.getCredentials(), config.isSaveCredentials()); + saveAuthProperties( + newDataSource, + newDataSource.getConnectionConfiguration(), + config.getCredentials(), + config.isSaveCredentials(), + config.isSharedCredentials() + ); return newDataSource; @@ -245,9 +251,11 @@ public class WebServiceUtils extends WebCommonUtils { @NotNull DBPDataSourceContainer dataSourceContainer, @NotNull DBPConnectionConfiguration configuration, @Nullable Map authProperties, - boolean saveCredentials) - { + boolean saveCredentials, + boolean sharedCredentials + ) { dataSourceContainer.setSavePassword(saveCredentials); + dataSourceContainer.setSharedCredentials(sharedCredentials); if (!saveCredentials) { // Reset credentials if (authProperties == null) { @@ -293,7 +301,13 @@ public class WebServiceUtils extends WebCommonUtils { dataSource.setFolder(null); } getGlobalDataSourceRegistry().getAllFolders().clear(); - saveAuthProperties(dataSource, dataSource.getConnectionConfiguration(), config.getCredentials(), config.isSaveCredentials()); + saveAuthProperties( + dataSource, + dataSource.getConnectionConfiguration(), + config.getCredentials(), + config.isSaveCredentials(), + config.isSharedCredentials() + ); } public static DBNBrowseSettings parseNavigatorSettings(Map settingsMap) { diff --git a/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/model/WebConnectionConfig.java b/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/model/WebConnectionConfig.java index b74bee9cf2..8b8b8bd962 100644 --- a/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/model/WebConnectionConfig.java +++ b/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/model/WebConnectionConfig.java @@ -53,6 +53,7 @@ public class WebConnectionConfig { private String authModelId; private Map credentials; private boolean saveCredentials; + private boolean sharedCredentials; private Map providerProperties; private List networkHandlersConfig; private DBPDriverConfigurationType configurationType; @@ -90,6 +91,7 @@ public class WebConnectionConfig { authModelId = JSONUtils.getString(params, "authModelId"); credentials = JSONUtils.getObjectOrNull(params, "credentials"); saveCredentials = JSONUtils.getBoolean(params, "saveCredentials"); + sharedCredentials = JSONUtils.getBoolean(params, "sharedCredentials"); providerProperties = JSONUtils.getObjectOrNull(params, "providerProperties"); @@ -207,6 +209,11 @@ public class WebConnectionConfig { return saveCredentials; } + @Property + public boolean isSharedCredentials() { + return sharedCredentials; + } + public void setSaveCredentials(boolean saveCredentials) { this.saveCredentials = saveCredentials; } diff --git a/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/server/CBApplication.java b/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/server/CBApplication.java index e44699337e..3ab312a6fa 100644 --- a/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/server/CBApplication.java +++ b/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/server/CBApplication.java @@ -930,23 +930,25 @@ public class CBApplication extends BaseWebApplication implements WebAuthApplicat rootConfig.put("app", appConfigProperties); copyConfigValue( - oldAppConfig, appConfigProperties, "anonymousAccessEnabled", appConfig.isAnonymousAccessEnabled()); + oldAppConfig, appConfigProperties, "anonymousAccessEnabled", appConfig.isAnonymousAccessEnabled()); copyConfigValue( - oldAppConfig, appConfigProperties, "supportsCustomConnections", appConfig.isSupportsCustomConnections()); + oldAppConfig, appConfigProperties, "supportsCustomConnections", appConfig.isSupportsCustomConnections()); copyConfigValue( - oldAppConfig, appConfigProperties, "publicCredentialsSaveEnabled", appConfig.isPublicCredentialsSaveEnabled()); + oldAppConfig, appConfigProperties, "publicCredentialsSaveEnabled", appConfig.isPublicCredentialsSaveEnabled()); copyConfigValue( - oldAppConfig, appConfigProperties, "adminCredentialsSaveEnabled", appConfig.isAdminCredentialsSaveEnabled()); + oldAppConfig, appConfigProperties, "adminCredentialsSaveEnabled", appConfig.isAdminCredentialsSaveEnabled()); copyConfigValue( - oldAppConfig, appConfigProperties, "enableReverseProxyAuth", appConfig.isEnabledReverseProxyAuth()); + oldAppConfig, appConfigProperties, "enableReverseProxyAuth", appConfig.isEnabledReverseProxyAuth()); copyConfigValue( - oldAppConfig, appConfigProperties, "forwardProxy", appConfig.isEnabledForwardProxy()); + oldAppConfig, appConfigProperties, "forwardProxy", appConfig.isEnabledForwardProxy()); copyConfigValue( - oldAppConfig, appConfigProperties, "linkExternalCredentialsWithUser", appConfig.isLinkExternalCredentialsWithUser()); + oldAppConfig, appConfigProperties, "linkExternalCredentialsWithUser", appConfig.isLinkExternalCredentialsWithUser()); copyConfigValue( - oldAppConfig, appConfigProperties, "redirectOnFederatedAuth", appConfig.isRedirectOnFederatedAuth()); + oldAppConfig, appConfigProperties, "redirectOnFederatedAuth", appConfig.isRedirectOnFederatedAuth()); copyConfigValue( - oldAppConfig, appConfigProperties, CBConstants.PARAM_RESOURCE_MANAGER_ENABLED, appConfig.isResourceManagerEnabled()); + oldAppConfig, appConfigProperties, CBConstants.PARAM_RESOURCE_MANAGER_ENABLED, appConfig.isResourceManagerEnabled()); + copyConfigValue( + oldAppConfig, appConfigProperties, CBConstants.PARAM_SHOW_READ_ONLY_CONN_INFO, appConfig.isShowReadOnlyConnectionInfo()); Map resourceQuotas = new LinkedHashMap<>(); Map originResourceQuotas = JSONUtils.getObject(oldAppConfig, CBConstants.PARAM_RESOURCE_QUOTAS); diff --git a/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/server/CBConstants.java b/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/server/CBConstants.java index 5b2e04a638..b774d61635 100644 --- a/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/server/CBConstants.java +++ b/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/server/CBConstants.java @@ -39,6 +39,7 @@ public class CBConstants { public static final String PARAM_STATIC_CONTENT = "staticContent"; public static final String PARAM_RESOURCE_QUOTAS = "resourceQuotas"; public static final String PARAM_RESOURCE_MANAGER_ENABLED = "resourceManagerEnabled"; + public static final String PARAM_SHOW_READ_ONLY_CONN_INFO = "showReadOnlyConnectionInfo"; public static final String PARAM_AUTH_PROVIDERS = "authConfiguration"; public static final String PARAM_DB_CONFIGURATION = "database"; diff --git a/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/core/DBWServiceCore.java b/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/core/DBWServiceCore.java index 666d0f33a9..53e4022dc5 100644 --- a/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/core/DBWServiceCore.java +++ b/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/core/DBWServiceCore.java @@ -113,13 +113,16 @@ public interface DBWServiceCore extends DBWService { @NotNull String connectionId, @NotNull Map authProperties, @Nullable List networkCredentials, - @Nullable Boolean saveCredentials) throws DBWebException; + @Nullable Boolean saveCredentials, + @Nullable Boolean sharedCredentials + ) throws DBWebException; @WebProjectAction(requireProjectPermissions = {RMConstants.PERMISSION_PROJECT_DATASOURCES_EDIT}) WebConnectionInfo createConnection( @NotNull WebSession webSession, @Nullable @WebObjectId String projectId, - @NotNull WebConnectionConfig connectionConfig) throws DBWebException; + @NotNull WebConnectionConfig connectionConfig + ) throws DBWebException; @WebProjectAction(requireProjectPermissions = {RMConstants.PERMISSION_PROJECT_DATASOURCES_EDIT}) WebConnectionInfo updateConnection( diff --git a/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/core/WebServiceBindingCore.java b/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/core/WebServiceBindingCore.java index 7dba9a5676..5e079c041d 100644 --- a/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/core/WebServiceBindingCore.java +++ b/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/core/WebServiceBindingCore.java @@ -134,7 +134,9 @@ public class WebServiceBindingCore extends WebServiceBindingBase env.getArgument("id"), env.getArgument("credentials"), nhc, - env.getArgument("saveCredentials")); + env.getArgument("saveCredentials"), + env.getArgument("sharedCredentials") + ); } ) .dataFetcher("testConnection", env -> getService(env).testConnection( diff --git a/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/core/impl/WebServiceCore.java b/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/core/impl/WebServiceCore.java index 0d90d902c9..729fdebd75 100644 --- a/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/core/impl/WebServiceCore.java +++ b/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/core/impl/WebServiceCore.java @@ -19,6 +19,7 @@ package io.cloudbeaver.service.core.impl; import io.cloudbeaver.DBWConstants; import io.cloudbeaver.DBWebException; +import io.cloudbeaver.WebProjectImpl; import io.cloudbeaver.WebServiceUtils; import io.cloudbeaver.events.CBEvent; import io.cloudbeaver.events.CBEventConstants; @@ -154,7 +155,7 @@ public class WebServiceCore implements DBWServiceCore { getTemplateConnectionsFromProject(webSession, project, result); } } else { - DBPProject project = webSession.getProjectById(projectId); + DBPProject project = getProjectById(webSession, projectId); getTemplateConnectionsFromProject(webSession, project, result); } webSession.filterAccessibleConnections(result); @@ -189,7 +190,7 @@ public class WebServiceCore implements DBWServiceCore { WebConnectionFolderInfo folderInfo = WebConnectionFolderUtils.getFolderInfo(webSession, projectId, id); return Collections.singletonList(folderInfo); } - DBPProject project = webSession.getProjectById(projectId); + DBPProject project = getProjectById(webSession, projectId); return getConnectionFoldersFromProject(webSession, project); } @@ -308,8 +309,9 @@ public class WebServiceCore implements DBWServiceCore { @NotNull String connectionId, @NotNull Map authProperties, @Nullable List networkCredentials, - @Nullable Boolean saveCredentials) throws DBWebException - { + @Nullable Boolean saveCredentials, + @Nullable Boolean sharedCredentials + ) throws DBWebException { WebConnectionInfo connectionInfo = webSession.getWebConnectionInfo(projectId, connectionId); connectionInfo.setSavedCredentials(authProperties, networkCredentials); @@ -349,7 +351,9 @@ public class WebServiceCore implements DBWServiceCore { dataSourceContainer, dataSourceContainer.getConnectionConfiguration(), authProperties, - true); + true, + sharedCredentials == null ? false : sharedCredentials + ); WebDataSourceUtils.saveCredentialsInDataSource(connectionInfo, dataSourceContainer, dataSourceContainer.getConnectionConfiguration()); saveConfig[0] = true; @@ -371,7 +375,7 @@ public class WebServiceCore implements DBWServiceCore { @Nullable String projectId, @NotNull WebConnectionConfig connectionConfig ) throws DBWebException { - var project = webSession.getProjectById(projectId); + var project = getProjectById(webSession, projectId); var rmProject = project.getRmProject(); if (rmProject.getType() == RMProjectType.USER && !webSession.hasPermission(DBWConstants.PERMISSION_ADMIN) @@ -380,7 +384,7 @@ public class WebServiceCore implements DBWServiceCore { throw new DBWebException("New connection create is restricted by server configuration"); } webSession.addInfoMessage("Create new connection"); - DBPDataSourceRegistry sessionRegistry = webSession.getProjectById(projectId).getDataSourceRegistry(); + DBPDataSourceRegistry sessionRegistry = project.getDataSourceRegistry(); // we don't need to save credentials for templates if (connectionConfig.isTemplate()) { @@ -404,7 +408,7 @@ public class WebServiceCore implements DBWServiceCore { webSession.addConnection(connectionInfo); webSession.addInfoMessage("New connection was created - " + WebServiceUtils.getConnectionContainerInfo(newDataSource)); WebAppUtils.addDataSourceUpdatedEvent( - webSession.getProjectById(projectId), + project, connectionInfo.getId(), CBEventConstants.EventType.TYPE_CREATE ); @@ -421,7 +425,7 @@ public class WebServiceCore implements DBWServiceCore { // if (!CBApplication.getInstance().getAppConfiguration().isSupportsCustomConnections()) { // throw new DBWebException("Connection edit is restricted by server configuration"); // } - DBPDataSourceRegistry sessionRegistry = webSession.getProjectById(projectId).getDataSourceRegistry(); + DBPDataSourceRegistry sessionRegistry = getProjectById(webSession, projectId).getDataSourceRegistry(); WebConnectionInfo connectionInfo = webSession.getWebConnectionInfo(projectId, config.getConnectionId()); DBPDataSourceContainer dataSource = connectionInfo.getDataSourceContainer(); @@ -437,7 +441,13 @@ public class WebServiceCore implements DBWServiceCore { dataSource.setFolder(config.getFolder() != null ? sessionRegistry.getFolder(config.getFolder()) : null); WebServiceUtils.setConnectionConfiguration(dataSource.getDriver(), dataSource.getConnectionConfiguration(), config); - WebServiceUtils.saveAuthProperties(dataSource, dataSource.getConnectionConfiguration(), config.getCredentials(), config.isSaveCredentials()); + WebServiceUtils.saveAuthProperties( + dataSource, + dataSource.getConnectionConfiguration(), + config.getCredentials(), + config.isSaveCredentials(), + config.isSharedCredentials() + ); try { sessionRegistry.updateDataSource(dataSource); @@ -446,21 +456,22 @@ public class WebServiceCore implements DBWServiceCore { throw new DBWebException("Failed to update connection", e); } WebAppUtils.addDataSourceUpdatedEvent( - webSession.getProjectById(projectId), connectionInfo.getId(), CBEventConstants.EventType.TYPE_UPDATE); + getProjectById(webSession, projectId), connectionInfo.getId(), CBEventConstants.EventType.TYPE_UPDATE); return connectionInfo; } @Override public boolean deleteConnection( - @NotNull WebSession webSession, @Nullable String projectId, @NotNull String connectionId) throws DBWebException { + @NotNull WebSession webSession, @Nullable String projectId, @NotNull String connectionId + ) throws DBWebException { WebConnectionInfo connectionInfo = webSession.getWebConnectionInfo(projectId, connectionId); - if (connectionInfo.getDataSourceContainer().getProject() != webSession.getProjectById(projectId)) { + if (connectionInfo.getDataSourceContainer().getProject() != getProjectById(webSession, projectId)) { throw new DBWebException("Global connection '" + connectionInfo.getName() + "' configuration cannot be deleted"); } webSession.addInfoMessage("Delete connection - " + WebServiceUtils.getConnectionContainerInfo(connectionInfo.getDataSourceContainer())); closeAndDeleteConnection(webSession, projectId, connectionId, true); - WebAppUtils.addDataSourceUpdatedEvent(webSession.getProjectById(projectId), connectionId, CBEventConstants.EventType.TYPE_DELETE); + WebAppUtils.addDataSourceUpdatedEvent(getProjectById(webSession, projectId), connectionId, CBEventConstants.EventType.TYPE_DELETE); return true; } @@ -471,7 +482,7 @@ public class WebServiceCore implements DBWServiceCore { @NotNull String templateId, @Nullable String connectionName) throws DBWebException { - DBPDataSourceRegistry templateRegistry = webSession.getProjectById(projectId).getDataSourceRegistry(); + DBPDataSourceRegistry templateRegistry = getProjectById(webSession, projectId).getDataSourceRegistry(); DBPDataSourceContainer dataSourceTemplate = templateRegistry.getDataSource(templateId); if (dataSourceTemplate == null) { throw new DBWebException("Template data source '" + templateId + "' not found"); @@ -507,7 +518,7 @@ public class WebServiceCore implements DBWServiceCore { @NotNull WebConnectionConfig config) throws DBWebException { try { DBNModel navigatorModel = webSession.getNavigatorModel(); - DBPDataSourceRegistry dataSourceRegistry = webSession.getProjectById(projectId).getDataSourceRegistry(); + DBPDataSourceRegistry dataSourceRegistry = getProjectById(webSession, projectId).getDataSourceRegistry(); DBNNode srcNode = navigatorModel.getNodeByPath(webSession.getProgressMonitor(), nodePath); if (srcNode == null) { @@ -537,7 +548,7 @@ public class WebServiceCore implements DBWServiceCore { dataSourceRegistry.checkForErrors(); webSession.addConnection(connectionInfo); WebAppUtils.addDataSourceUpdatedEvent( - webSession.getProjectById(projectId), connectionInfo.getId(), CBEventConstants.EventType.TYPE_CREATE); + getProjectById(webSession, projectId), connectionInfo.getId(), CBEventConstants.EventType.TYPE_CREATE); return connectionInfo; } catch (DBException e) { throw new DBWebException("Error copying connection", e); @@ -555,12 +566,30 @@ public class WebServiceCore implements DBWServiceCore { DBPDataSourceContainer dataSource = WebDataSourceUtils.getLocalOrGlobalDataSource( CBApplication.getInstance(), webSession, projectId, connectionId); - DBPDataSourceRegistry sessionRegistry = webSession.getProjectById(projectId).getDataSourceRegistry(); + WebProjectImpl project = getProjectById(webSession, projectId); + DBPDataSourceRegistry sessionRegistry = project.getDataSourceRegistry(); DBPDataSourceContainer testDataSource; if (dataSource != null) { + try { + // Check that creds are saved to trigger secrets resolve + dataSource.isCredentialsSaved(); + } catch (DBException e) { + throw new DBWebException("Can't determine whether datasource credentials are saved", e); + } + testDataSource = dataSource.createCopy(dataSource.getRegistry()); - WebServiceUtils.setConnectionConfiguration(testDataSource.getDriver(), testDataSource.getConnectionConfiguration(), connectionConfig); - WebServiceUtils.saveAuthProperties(testDataSource, testDataSource.getConnectionConfiguration(), connectionConfig.getCredentials(), true); + WebServiceUtils.setConnectionConfiguration( + testDataSource.getDriver(), + testDataSource.getConnectionConfiguration(), + connectionConfig + ); + WebServiceUtils.saveAuthProperties( + testDataSource, + testDataSource.getConnectionConfiguration(), + connectionConfig.getCredentials(), + true, + false + ); } else { testDataSource = WebServiceUtils.createConnectionFromConfig(connectionConfig, sessionRegistry); } @@ -664,7 +693,7 @@ public class WebServiceCore implements DBWServiceCore { //new DisconnectJob(connectionInfo.getDataSource()).schedule(); } if (forceDelete) { - DBPDataSourceRegistry registry = webSession.getProjectById(projectId).getDataSourceRegistry(); + DBPDataSourceRegistry registry = getProjectById(webSession, projectId).getDataSourceRegistry(); registry.removeDataSource(dataSourceContainer); try { registry.checkForErrors(); @@ -712,12 +741,13 @@ public class WebServiceCore implements DBWServiceCore { if (parentPath != null) { parentNode = WebConnectionFolderUtils.getFolderInfo(session, projectId, parentPath); } - DBPDataSourceRegistry sessionRegistry = session.getProjectById(projectId).getDataSourceRegistry(); + WebProjectImpl project = getProjectById(session, projectId); + DBPDataSourceRegistry sessionRegistry = project.getDataSourceRegistry(); DBPDataSourceFolder newFolder = WebServiceUtils.createFolder(parentNode, folderName, sessionRegistry); WebConnectionFolderInfo folderInfo = new WebConnectionFolderInfo(session, newFolder); WebServiceUtils.updateConfigAndRefreshDatabases(session, projectId); WebAppUtils.addDataSourceUpdatedEvent( - session.getProjectById(projectId), folderInfo.getId(), CBEventConstants.EventType.TYPE_CREATE); + project, folderInfo.getId(), CBEventConstants.EventType.TYPE_CREATE); return folderInfo; } catch (DBException e) { throw new DBWebException(e.getMessage(), e); @@ -736,7 +766,7 @@ public class WebServiceCore implements DBWServiceCore { folderInfo.getDataSourceFolder().setName(newName); WebServiceUtils.updateConfigAndRefreshDatabases(session, projectId); WebAppUtils.addDataSourceUpdatedEvent( - session.getProjectById(projectId), folderInfo.getId(), CBEventConstants.EventType.TYPE_UPDATE); + getProjectById(session, projectId), folderInfo.getId(), CBEventConstants.EventType.TYPE_UPDATE); return folderInfo; } @@ -747,15 +777,16 @@ public class WebServiceCore implements DBWServiceCore { try { WebConnectionFolderInfo folderInfo = WebConnectionFolderUtils.getFolderInfo(session, projectId, folderPath); DBPDataSourceFolder folder = folderInfo.getDataSourceFolder(); - if (folder.getDataSourceRegistry().getProject() != session.getProjectById(projectId)) { + WebProjectImpl project = getProjectById(session, projectId); + if (folder.getDataSourceRegistry().getProject() != project) { throw new DBWebException("Global folder '" + folderInfo.getId() + "' cannot be deleted"); } session.addInfoMessage("Delete folder"); - DBPDataSourceRegistry sessionRegistry = session.getProjectById(projectId).getDataSourceRegistry(); + DBPDataSourceRegistry sessionRegistry = project.getDataSourceRegistry(); sessionRegistry.removeFolder(folderInfo.getDataSourceFolder(), false); WebServiceUtils.updateConfigAndRefreshDatabases(session, projectId); WebAppUtils.addDataSourceUpdatedEvent( - session.getProjectById(projectId), folderInfo.getId(), CBEventConstants.EventType.TYPE_DELETE); + project, folderInfo.getId(), CBEventConstants.EventType.TYPE_DELETE); } catch (DBException e) { throw new DBWebException(e.getMessage(), e); } @@ -771,7 +802,7 @@ public class WebServiceCore implements DBWServiceCore { dataSourceDescriptor.setNavigatorSettings(settings); dataSourceDescriptor.persistConfiguration(); WebAppUtils.addDataSourceUpdatedEvent( - webSession.getProjectById(projectId), id, CBEventConstants.EventType.TYPE_UPDATE); + getProjectById(webSession, projectId), id, CBEventConstants.EventType.TYPE_UPDATE); return connectionInfo; } @@ -785,4 +816,11 @@ public class WebServiceCore implements DBWServiceCore { return webSession.asyncTaskCancel(taskId); } + private WebProjectImpl getProjectById(WebSession webSession, String projectId) throws DBWebException { + WebProjectImpl project = webSession.getProjectById(projectId); + if (project == null) { + throw new DBWebException("Project '" + projectId + "' not found"); + } + return project; + } } diff --git a/server/bundles/io.cloudbeaver.service.admin/META-INF/MANIFEST.MF b/server/bundles/io.cloudbeaver.service.admin/META-INF/MANIFEST.MF index 65b18a9ac7..d14f9379a9 100644 --- a/server/bundles/io.cloudbeaver.service.admin/META-INF/MANIFEST.MF +++ b/server/bundles/io.cloudbeaver.service.admin/META-INF/MANIFEST.MF @@ -3,8 +3,8 @@ Bundle-ManifestVersion: 2 Bundle-Vendor: %Bundle-Vendor Bundle-Name: %Bundle-Name Bundle-SymbolicName: io.cloudbeaver.service.admin;singleton:=true -Bundle-Version: 1.0.60.qualifier -Bundle-Release-Date: 20221107 +Bundle-Version: 1.0.61.qualifier +Bundle-Release-Date: 20221121 Bundle-RequiredExecutionEnvironment: JavaSE-11 Bundle-ActivationPolicy: lazy Bundle-ClassPath: . diff --git a/server/bundles/io.cloudbeaver.service.admin/pom.xml b/server/bundles/io.cloudbeaver.service.admin/pom.xml index ffa69eea79..f51281ec97 100644 --- a/server/bundles/io.cloudbeaver.service.admin/pom.xml +++ b/server/bundles/io.cloudbeaver.service.admin/pom.xml @@ -10,7 +10,7 @@ ../ io.cloudbeaver.service.admin - 1.0.60-SNAPSHOT + 1.0.61-SNAPSHOT eclipse-plugin diff --git a/server/bundles/io.cloudbeaver.service.admin/schema/service.admin.graphqls b/server/bundles/io.cloudbeaver.service.admin/schema/service.admin.graphqls index 895c8168f2..2b463c236d 100644 --- a/server/bundles/io.cloudbeaver.service.admin/schema/service.admin.graphqls +++ b/server/bundles/io.cloudbeaver.service.admin/schema/service.admin.graphqls @@ -50,6 +50,8 @@ type AdminTeamInfo { teamName: String description: String + metaParameters: Object! + grantedUsers: [ID!]! grantedConnections: [AdminConnectionGrantInfo!]! @@ -120,6 +122,7 @@ extend type Query { listTeams(teamId: ID): [AdminTeamInfo!]! listPermissions: [AdminPermissionInfo!]! listAuthRoles: [String!]! + listTeamMetaParameters: [ObjectPropertyInfo!]! createUser(userId: ID!, enabled: Boolean!, authRole: String): AdminUserInfo! deleteUser(userId: ID!): Boolean @@ -179,6 +182,8 @@ extend type Query { setUserMetaParameterValues(userId: ID!, parameters: Object!): Boolean! + setTeamMetaParameterValues(teamId: ID!, parameters: Object!): Boolean! + #### Global configuration configureServer(configuration: ServerConfigInput!): Boolean! diff --git a/server/bundles/io.cloudbeaver.service.admin/src/io/cloudbeaver/service/admin/AdminTeamInfo.java b/server/bundles/io.cloudbeaver.service.admin/src/io/cloudbeaver/service/admin/AdminTeamInfo.java index 5826d36239..37ea11b0e3 100644 --- a/server/bundles/io.cloudbeaver.service.admin/src/io/cloudbeaver/service/admin/AdminTeamInfo.java +++ b/server/bundles/io.cloudbeaver.service.admin/src/io/cloudbeaver/service/admin/AdminTeamInfo.java @@ -25,6 +25,7 @@ import org.jkiss.dbeaver.model.security.user.SMTeam; import java.util.ArrayList; import java.util.List; +import java.util.Map; /** * Web team info @@ -45,14 +46,22 @@ public class AdminTeamInfo { return team.getTeamId(); } + @Property public String getTeamName() { return team.getName(); } + @Property public String getDescription() { return team.getDescription(); } + @Property + public Map getMetaParameters() { + return team.getMetaParameters(); + } + + @Property public List getTeamPermissions() { return teamPermissions; } diff --git a/server/bundles/io.cloudbeaver.service.admin/src/io/cloudbeaver/service/admin/DBWServiceAdmin.java b/server/bundles/io.cloudbeaver.service.admin/src/io/cloudbeaver/service/admin/DBWServiceAdmin.java index 315990ac04..9a183de67b 100644 --- a/server/bundles/io.cloudbeaver.service.admin/src/io/cloudbeaver/service/admin/DBWServiceAdmin.java +++ b/server/bundles/io.cloudbeaver.service.admin/src/io/cloudbeaver/service/admin/DBWServiceAdmin.java @@ -50,6 +50,9 @@ public interface DBWServiceAdmin extends DBWService { @NotNull List listPermissions(@NotNull WebSession webSession) throws DBWebException; + @WebAction() + WebPropertyInfo[] listTeamMetaParameters(@NotNull WebSession webSession); + @WebAction(requirePermissions = DBWConstants.PERMISSION_ADMIN) @NotNull AdminUserInfo createUser( @@ -164,6 +167,8 @@ public interface DBWServiceAdmin extends DBWService { @WebAction(requirePermissions = DBWConstants.PERMISSION_ADMIN) Boolean setUserMetaParameterValues(WebSession webSession, String userId, Map parameters) throws DBWebException; @WebAction(requirePermissions = DBWConstants.PERMISSION_ADMIN) + Boolean setTeamMetaParameterValues(WebSession webSession, String teamId, Map parameters) throws DBWebException; + @WebAction(requirePermissions = DBWConstants.PERMISSION_ADMIN) Boolean enableUser(WebSession webSession, String userId, Boolean enabled) throws DBWebException; @WebAction(requirePermissions = DBWConstants.PERMISSION_ADMIN) diff --git a/server/bundles/io.cloudbeaver.service.admin/src/io/cloudbeaver/service/admin/WebServiceBindingAdmin.java b/server/bundles/io.cloudbeaver.service.admin/src/io/cloudbeaver/service/admin/WebServiceBindingAdmin.java index ee6f46afce..3a0dabe8f7 100644 --- a/server/bundles/io.cloudbeaver.service.admin/src/io/cloudbeaver/service/admin/WebServiceBindingAdmin.java +++ b/server/bundles/io.cloudbeaver.service.admin/src/io/cloudbeaver/service/admin/WebServiceBindingAdmin.java @@ -50,6 +50,8 @@ public class WebServiceBindingAdmin extends WebServiceBindingBase getService(env).listPermissions(getWebSession(env))) .dataFetcher("listAuthRoles", env -> getService(env).listAuthRoles()) + .dataFetcher("listTeamMetaParameters", + env -> getService(env).listTeamMetaParameters(getWebSession(env))) .dataFetcher("createUser", env -> getService(env).createUser( getWebSession(env), @@ -143,6 +145,11 @@ public class WebServiceBindingAdmin extends WebServiceBindingBase getService(env).setTeamMetaParameterValues( + getWebSession(env), + env.getArgument("teamId"), + env.getArgument("parameters"))) .dataFetcher("configureServer", env -> getService(env).configureServer(getWebSession(env), env.getArgument("configuration"))) diff --git a/server/bundles/io.cloudbeaver.service.admin/src/io/cloudbeaver/service/admin/impl/WebServiceAdmin.java b/server/bundles/io.cloudbeaver.service.admin/src/io/cloudbeaver/service/admin/impl/WebServiceAdmin.java index 5215b35597..85ef850d9a 100644 --- a/server/bundles/io.cloudbeaver.service.admin/src/io/cloudbeaver/service/admin/impl/WebServiceAdmin.java +++ b/server/bundles/io.cloudbeaver.service.admin/src/io/cloudbeaver/service/admin/impl/WebServiceAdmin.java @@ -41,10 +41,8 @@ import org.jkiss.dbeaver.model.DBPDataSourceContainer; import org.jkiss.dbeaver.model.app.DBPDataSourceRegistry; import org.jkiss.dbeaver.model.app.DBPProject; import org.jkiss.dbeaver.model.navigator.DBNBrowseSettings; -import org.jkiss.dbeaver.model.security.SMAuthProviderCustomConfiguration; -import org.jkiss.dbeaver.model.security.SMConstants; -import org.jkiss.dbeaver.model.security.SMDataSourceGrant; -import org.jkiss.dbeaver.model.security.SMObjects; +import org.jkiss.dbeaver.model.preferences.DBPPropertyDescriptor; +import org.jkiss.dbeaver.model.security.*; import org.jkiss.dbeaver.model.security.user.SMTeam; import org.jkiss.dbeaver.model.security.user.SMUser; import org.jkiss.utils.CommonUtils; @@ -113,6 +111,25 @@ public class WebServiceAdmin implements DBWServiceAdmin { } } + @Override + public WebPropertyInfo[] listTeamMetaParameters(@NotNull WebSession webSession) { + // First add user profile properties + List props = new ArrayList<>( + WebMetaParametersRegistry.getInstance().getTeamParameters()); + + // Add metas from enabled auth providers + for (WebAuthProviderDescriptor ap : WebServiceUtils.getEnabledAuthProviders()) { + List metaProps = ap.getMetaParameters(SMSubjectType.team); + if (!CommonUtils.isEmpty(metaProps)) { + props.addAll(metaProps); + } + } + + return props.stream() + .map(p -> new WebPropertyInfo(webSession, p, null)) + .toArray(WebPropertyInfo[]::new); + } + @NotNull @Override public AdminUserInfo createUser( @@ -657,6 +674,16 @@ public class WebServiceAdmin implements DBWServiceAdmin { } } + @Override + public Boolean setTeamMetaParameterValues(WebSession webSession, String teamId, Map parameters) throws DBWebException { + try { + webSession.getAdminSecurityController().setSubjectMetas(teamId, parameters); + return true; + } catch (DBException e) { + throw new DBWebException("Error changing team '" + teamId + "' meta parameters", e); + } + } + private DBPDataSourceRegistry getDataSourceRegistry(WebSession session, String projectId) throws DBWebException { WebProjectImpl project = session.getProjectById(projectId); if (project == null) { diff --git a/server/bundles/io.cloudbeaver.service.auth/META-INF/MANIFEST.MF b/server/bundles/io.cloudbeaver.service.auth/META-INF/MANIFEST.MF index a18830d881..67540cbcc3 100644 --- a/server/bundles/io.cloudbeaver.service.auth/META-INF/MANIFEST.MF +++ b/server/bundles/io.cloudbeaver.service.auth/META-INF/MANIFEST.MF @@ -3,8 +3,8 @@ Bundle-ManifestVersion: 2 Bundle-Vendor: %Bundle-Vendor Bundle-Name: %Bundle-Name Bundle-SymbolicName: io.cloudbeaver.service.auth;singleton:=true -Bundle-Version: 1.0.60.qualifier -Bundle-Release-Date: 20221107 +Bundle-Version: 1.0.61.qualifier +Bundle-Release-Date: 20221121 Bundle-RequiredExecutionEnvironment: JavaSE-11 Bundle-ActivationPolicy: lazy Bundle-ClassPath: . diff --git a/server/bundles/io.cloudbeaver.service.auth/plugin.xml b/server/bundles/io.cloudbeaver.service.auth/plugin.xml index 3cbc26b47e..36baf6d3c9 100644 --- a/server/bundles/io.cloudbeaver.service.auth/plugin.xml +++ b/server/bundles/io.cloudbeaver.service.auth/plugin.xml @@ -3,21 +3,18 @@ - - - - - + + - + diff --git a/server/bundles/io.cloudbeaver.service.auth/pom.xml b/server/bundles/io.cloudbeaver.service.auth/pom.xml index f504ffa82e..2a4519ab39 100644 --- a/server/bundles/io.cloudbeaver.service.auth/pom.xml +++ b/server/bundles/io.cloudbeaver.service.auth/pom.xml @@ -10,7 +10,7 @@ ../ io.cloudbeaver.service.auth - 1.0.60-SNAPSHOT + 1.0.61-SNAPSHOT eclipse-plugin diff --git a/server/bundles/io.cloudbeaver.service.auth/schema/service.auth.graphqls b/server/bundles/io.cloudbeaver.service.auth/schema/service.auth.graphqls index a48c41491d..e72b4b0d88 100644 --- a/server/bundles/io.cloudbeaver.service.auth/schema/service.auth.graphqls +++ b/server/bundles/io.cloudbeaver.service.auth/schema/service.auth.graphqls @@ -109,16 +109,19 @@ type UserInfo { # Human readable display name. It is taken from the first auth provider which was used for user login. displayName: String + # User auth role ID. Optional. + authRole: ID + # All authentication tokens used during current session authTokens: [UserAuthToken!]! linkedAuthProviders: [String!]! # User profile properties map metaParameters: Object! - - # USer configuiraiton parameters + # User configuration parameters configurationParameters: Object! + } extend type Query { diff --git a/server/bundles/io.cloudbeaver.service.auth/src/io/cloudbeaver/service/auth/WebUserInfo.java b/server/bundles/io.cloudbeaver.service.auth/src/io/cloudbeaver/service/auth/WebUserInfo.java index 7a78e7d5e0..dd2d72482b 100644 --- a/server/bundles/io.cloudbeaver.service.auth/src/io/cloudbeaver/service/auth/WebUserInfo.java +++ b/server/bundles/io.cloudbeaver.service.auth/src/io/cloudbeaver/service/auth/WebUserInfo.java @@ -54,6 +54,11 @@ public class WebUserInfo { return user == null ? null : user.getDisplayName(); } + @Property + public String getAuthRole() { + return user == null ? null : user.getAuthRole(); + } + @Property public List getAuthTokens() { return session.getAllAuthInfo().stream() diff --git a/server/bundles/io.cloudbeaver.service.auth/src/io/cloudbeaver/service/auth/impl/WebServiceAuthImpl.java b/server/bundles/io.cloudbeaver.service.auth/src/io/cloudbeaver/service/auth/impl/WebServiceAuthImpl.java index 7d31bb5268..949ba5fb1e 100644 --- a/server/bundles/io.cloudbeaver.service.auth/src/io/cloudbeaver/service/auth/impl/WebServiceAuthImpl.java +++ b/server/bundles/io.cloudbeaver.service.auth/src/io/cloudbeaver/service/auth/impl/WebServiceAuthImpl.java @@ -27,7 +27,7 @@ import io.cloudbeaver.model.user.WebAuthProviderInfo; import io.cloudbeaver.model.user.WebUser; import io.cloudbeaver.registry.WebAuthProviderDescriptor; import io.cloudbeaver.registry.WebAuthProviderRegistry; -import io.cloudbeaver.registry.WebUserProfileRegistry; +import io.cloudbeaver.registry.WebMetaParametersRegistry; import io.cloudbeaver.server.CBApplication; import io.cloudbeaver.service.auth.DBWServiceAuth; import io.cloudbeaver.service.auth.WebAuthStatus; @@ -191,14 +191,13 @@ public class WebServiceAuthImpl implements DBWServiceAuth { @Override public WebPropertyInfo[] listUserProfileProperties(@NotNull WebSession webSession) { - List props = new ArrayList<>(); - // First add user profile properties - props.addAll(WebUserProfileRegistry.getInstance().getProperties()); + List props = new ArrayList<>( + WebMetaParametersRegistry.getInstance().getUserParameters()); // Add metas from enabled auth providers for (WebAuthProviderDescriptor ap : WebServiceUtils.getEnabledAuthProviders()) { - List metaProps = ap.getMetaProperties(SMSubjectType.user); + List metaProps = ap.getMetaParameters(SMSubjectType.user); if (!CommonUtils.isEmpty(metaProps)) { props.addAll(metaProps); } diff --git a/server/bundles/io.cloudbeaver.service.data.transfer/META-INF/MANIFEST.MF b/server/bundles/io.cloudbeaver.service.data.transfer/META-INF/MANIFEST.MF index 0eec3eed42..3a9279df38 100644 --- a/server/bundles/io.cloudbeaver.service.data.transfer/META-INF/MANIFEST.MF +++ b/server/bundles/io.cloudbeaver.service.data.transfer/META-INF/MANIFEST.MF @@ -3,8 +3,8 @@ Bundle-ManifestVersion: 2 Bundle-Vendor: %Bundle-Vendor Bundle-Name: %Bundle-Name Bundle-SymbolicName: io.cloudbeaver.service.data.transfer;singleton:=true -Bundle-Version: 1.0.61.qualifier -Bundle-Release-Date: 20221107 +Bundle-Version: 1.0.62.qualifier +Bundle-Release-Date: 20221121 Bundle-RequiredExecutionEnvironment: JavaSE-11 Bundle-ActivationPolicy: lazy Bundle-ClassPath: . diff --git a/server/bundles/io.cloudbeaver.service.data.transfer/pom.xml b/server/bundles/io.cloudbeaver.service.data.transfer/pom.xml index ac3dc1ca6f..b202ef5d4a 100644 --- a/server/bundles/io.cloudbeaver.service.data.transfer/pom.xml +++ b/server/bundles/io.cloudbeaver.service.data.transfer/pom.xml @@ -10,7 +10,7 @@ ../ io.cloudbeaver.service.data.transfer - 1.0.61-SNAPSHOT + 1.0.62-SNAPSHOT eclipse-plugin diff --git a/server/bundles/io.cloudbeaver.service.metadata/META-INF/MANIFEST.MF b/server/bundles/io.cloudbeaver.service.metadata/META-INF/MANIFEST.MF index f03b7b608c..7ab5ae4367 100644 --- a/server/bundles/io.cloudbeaver.service.metadata/META-INF/MANIFEST.MF +++ b/server/bundles/io.cloudbeaver.service.metadata/META-INF/MANIFEST.MF @@ -3,8 +3,8 @@ Bundle-ManifestVersion: 2 Bundle-Vendor: %Bundle-Vendor Bundle-Name: %Bundle-Name Bundle-SymbolicName: io.cloudbeaver.service.metadata;singleton:=true -Bundle-Version: 1.0.64.qualifier -Bundle-Release-Date: 20221107 +Bundle-Version: 1.0.65.qualifier +Bundle-Release-Date: 20221121 Bundle-RequiredExecutionEnvironment: JavaSE-11 Bundle-ActivationPolicy: lazy Bundle-ClassPath: . diff --git a/server/bundles/io.cloudbeaver.service.metadata/pom.xml b/server/bundles/io.cloudbeaver.service.metadata/pom.xml index a43ef7d2fc..8c30f4afa3 100644 --- a/server/bundles/io.cloudbeaver.service.metadata/pom.xml +++ b/server/bundles/io.cloudbeaver.service.metadata/pom.xml @@ -10,7 +10,7 @@ ../ io.cloudbeaver.service.metadata - 1.0.64-SNAPSHOT + 1.0.65-SNAPSHOT eclipse-plugin diff --git a/server/bundles/io.cloudbeaver.service.rm/META-INF/MANIFEST.MF b/server/bundles/io.cloudbeaver.service.rm/META-INF/MANIFEST.MF index b5a0da7371..2ed0469f67 100644 --- a/server/bundles/io.cloudbeaver.service.rm/META-INF/MANIFEST.MF +++ b/server/bundles/io.cloudbeaver.service.rm/META-INF/MANIFEST.MF @@ -3,8 +3,8 @@ Bundle-ManifestVersion: 2 Bundle-Vendor: %Bundle-Vendor Bundle-Name: %Bundle-Name Bundle-SymbolicName: io.cloudbeaver.service.rm;singleton:=true -Bundle-Version: 1.0.13.qualifier -Bundle-Release-Date: 20221107 +Bundle-Version: 1.0.14.qualifier +Bundle-Release-Date: 20221121 Bundle-RequiredExecutionEnvironment: JavaSE-11 Bundle-ActivationPolicy: lazy Bundle-ClassPath: . diff --git a/server/bundles/io.cloudbeaver.service.rm/pom.xml b/server/bundles/io.cloudbeaver.service.rm/pom.xml index f5cbb99cf8..05a756657f 100644 --- a/server/bundles/io.cloudbeaver.service.rm/pom.xml +++ b/server/bundles/io.cloudbeaver.service.rm/pom.xml @@ -10,7 +10,7 @@ ../ io.cloudbeaver.service.rm - 1.0.13-SNAPSHOT + 1.0.14-SNAPSHOT eclipse-plugin diff --git a/server/bundles/io.cloudbeaver.service.security/META-INF/MANIFEST.MF b/server/bundles/io.cloudbeaver.service.security/META-INF/MANIFEST.MF index 52c7a00a45..94b0ef1a6b 100644 --- a/server/bundles/io.cloudbeaver.service.security/META-INF/MANIFEST.MF +++ b/server/bundles/io.cloudbeaver.service.security/META-INF/MANIFEST.MF @@ -3,8 +3,8 @@ Bundle-ManifestVersion: 2 Bundle-Vendor: DBeaver Security Sevice Bundle-Vendor: DBeaver Corp Bundle-SymbolicName: io.cloudbeaver.service.security;singleton:=true -Bundle-Version: 1.0.16.qualifier -Bundle-Release-Date: 20221107 +Bundle-Version: 1.0.17.qualifier +Bundle-Release-Date: 20221121 Bundle-RequiredExecutionEnvironment: JavaSE-11 Bundle-ActivationPolicy: lazy Bundle-ClassPath: . diff --git a/server/bundles/io.cloudbeaver.service.security/pom.xml b/server/bundles/io.cloudbeaver.service.security/pom.xml index 01024811b9..0a9e8d2473 100644 --- a/server/bundles/io.cloudbeaver.service.security/pom.xml +++ b/server/bundles/io.cloudbeaver.service.security/pom.xml @@ -10,7 +10,7 @@ ../ io.cloudbeaver.service.security - 1.0.16-SNAPSHOT + 1.0.17-SNAPSHOT eclipse-plugin diff --git a/server/bundles/io.cloudbeaver.service.security/src/io/cloudbeaver/service/security/CBEmbeddedSecurityController.java b/server/bundles/io.cloudbeaver.service.security/src/io/cloudbeaver/service/security/CBEmbeddedSecurityController.java index 29aa81d210..28d736399b 100644 --- a/server/bundles/io.cloudbeaver.service.security/src/io/cloudbeaver/service/security/CBEmbeddedSecurityController.java +++ b/server/bundles/io.cloudbeaver.service.security/src/io/cloudbeaver/service/security/CBEmbeddedSecurityController.java @@ -44,11 +44,11 @@ import org.jkiss.dbeaver.model.impl.jdbc.JDBCUtils; import org.jkiss.dbeaver.model.impl.jdbc.exec.JDBCTransaction; import org.jkiss.dbeaver.model.runtime.DBRProgressMonitor; import org.jkiss.dbeaver.model.runtime.LoggingProgressMonitor; -import org.jkiss.dbeaver.model.security.*; import org.jkiss.dbeaver.model.security.exception.SMAccessTokenExpiredException; import org.jkiss.dbeaver.model.security.exception.SMException; import org.jkiss.dbeaver.model.security.exception.SMRefreshTokenExpiredException; import org.jkiss.dbeaver.model.security.user.*; +import org.jkiss.dbeaver.model.security.*; import org.jkiss.dbeaver.runtime.DBWorkbench; import org.jkiss.utils.ArrayUtils; import org.jkiss.utils.CommonUtils; diff --git a/server/bundles/io.cloudbeaver.service.security/src/io/cloudbeaver/service/security/internal/AuthAttemptSessionInfo.java b/server/bundles/io.cloudbeaver.service.security/src/io/cloudbeaver/service/security/internal/AuthAttemptSessionInfo.java index 7c5aee36e3..28c972bdeb 100644 --- a/server/bundles/io.cloudbeaver.service.security/src/io/cloudbeaver/service/security/internal/AuthAttemptSessionInfo.java +++ b/server/bundles/io.cloudbeaver.service.security/src/io/cloudbeaver/service/security/internal/AuthAttemptSessionInfo.java @@ -19,7 +19,7 @@ package io.cloudbeaver.service.security.internal; import org.jkiss.code.NotNull; import org.jkiss.code.Nullable; -import org.jkiss.dbeaver.model.security.SMSessionType; +import org.jkiss.dbeaver.model.auth.SMSessionType; import java.util.Map; diff --git a/server/features/io.cloudbeaver.ce.drivers.feature/feature.xml b/server/features/io.cloudbeaver.ce.drivers.feature/feature.xml index d41f5e13ca..1035557792 100644 --- a/server/features/io.cloudbeaver.ce.drivers.feature/feature.xml +++ b/server/features/io.cloudbeaver.ce.drivers.feature/feature.xml @@ -2,7 +2,7 @@ diff --git a/server/features/io.cloudbeaver.ce.drivers.feature/pom.xml b/server/features/io.cloudbeaver.ce.drivers.feature/pom.xml index 211797eea3..add5768e85 100644 --- a/server/features/io.cloudbeaver.ce.drivers.feature/pom.xml +++ b/server/features/io.cloudbeaver.ce.drivers.feature/pom.xml @@ -9,6 +9,6 @@ ../ io.cloudbeaver.ce.drivers.feature - 1.0.84-SNAPSHOT + 1.0.85-SNAPSHOT eclipse-feature diff --git a/server/features/io.cloudbeaver.product.ce.feature/feature.xml b/server/features/io.cloudbeaver.product.ce.feature/feature.xml index 924d9f6c24..615ebb2801 100644 --- a/server/features/io.cloudbeaver.product.ce.feature/feature.xml +++ b/server/features/io.cloudbeaver.product.ce.feature/feature.xml @@ -2,7 +2,7 @@ diff --git a/server/features/io.cloudbeaver.product.ce.feature/pom.xml b/server/features/io.cloudbeaver.product.ce.feature/pom.xml index c4c4f9c632..abb26cd816 100644 --- a/server/features/io.cloudbeaver.product.ce.feature/pom.xml +++ b/server/features/io.cloudbeaver.product.ce.feature/pom.xml @@ -10,7 +10,7 @@ ../ io.cloudbeaver.product.ce.feature - 22.2.4-SNAPSHOT + 22.2.5-SNAPSHOT eclipse-feature diff --git a/server/features/io.cloudbeaver.server.feature/feature.xml b/server/features/io.cloudbeaver.server.feature/feature.xml index 0d8902748d..1cef19e74e 100644 --- a/server/features/io.cloudbeaver.server.feature/feature.xml +++ b/server/features/io.cloudbeaver.server.feature/feature.xml @@ -2,7 +2,7 @@ diff --git a/server/features/io.cloudbeaver.server.feature/pom.xml b/server/features/io.cloudbeaver.server.feature/pom.xml index 40f70144e4..9082c6882a 100644 --- a/server/features/io.cloudbeaver.server.feature/pom.xml +++ b/server/features/io.cloudbeaver.server.feature/pom.xml @@ -10,6 +10,6 @@ ../ io.cloudbeaver.server.feature - 22.2.4-SNAPSHOT + 22.2.5-SNAPSHOT eclipse-feature diff --git a/server/features/io.cloudbeaver.ws.feature/feature.xml b/server/features/io.cloudbeaver.ws.feature/feature.xml index 98f48d9187..b7f614877d 100644 --- a/server/features/io.cloudbeaver.ws.feature/feature.xml +++ b/server/features/io.cloudbeaver.ws.feature/feature.xml @@ -2,7 +2,7 @@ diff --git a/server/features/io.cloudbeaver.ws.feature/pom.xml b/server/features/io.cloudbeaver.ws.feature/pom.xml index f17ca57b58..67ffaf8b42 100644 --- a/server/features/io.cloudbeaver.ws.feature/pom.xml +++ b/server/features/io.cloudbeaver.ws.feature/pom.xml @@ -10,6 +10,6 @@ ../ io.cloudbeaver.ws.feature - 1.0.14-SNAPSHOT + 1.0.15-SNAPSHOT eclipse-feature diff --git a/server/pom.xml b/server/pom.xml index fdea75709d..9ca92c06ea 100644 --- a/server/pom.xml +++ b/server/pom.xml @@ -19,7 +19,7 @@ CloudBeaver CE - 22.2.4 + 22.2.5 diff --git a/server/product/web-server/CloudbeaverServer.product b/server/product/web-server/CloudbeaverServer.product index de9cef9eaf..040040199b 100644 --- a/server/product/web-server/CloudbeaverServer.product +++ b/server/product/web-server/CloudbeaverServer.product @@ -2,7 +2,7 @@ diff --git a/server/product/web-server/CloudbeaverServer.product.launch b/server/product/web-server/CloudbeaverServer.product.launch index 4ebc339734..640feb6e01 100644 --- a/server/product/web-server/CloudbeaverServer.product.launch +++ b/server/product/web-server/CloudbeaverServer.product.launch @@ -33,7 +33,6 @@ - diff --git a/server/product/web-server/pom.xml b/server/product/web-server/pom.xml index af56b09f4c..ad0ecb96e6 100644 --- a/server/product/web-server/pom.xml +++ b/server/product/web-server/pom.xml @@ -9,7 +9,7 @@ 1.0.0-SNAPSHOT ../../ - 22.2.4-SNAPSHOT + 22.2.5-SNAPSHOT web-server eclipse-repository Cloudbeaver Server Product diff --git a/webapp/packages/core-authentication/src/TeamMetaParametersResource.ts b/webapp/packages/core-authentication/src/TeamMetaParametersResource.ts new file mode 100644 index 0000000000..f5026e9f29 --- /dev/null +++ b/webapp/packages/core-authentication/src/TeamMetaParametersResource.ts @@ -0,0 +1,30 @@ +/* + * CloudBeaver - Cloud Database Manager + * Copyright (C) 2020-2022 DBeaver Corp and others + * + * Licensed under the Apache License, Version 2.0. + * you may not use this file except in compliance with the License. + */ + +import { injectable } from '@cloudbeaver/core-di'; +import { SessionResource } from '@cloudbeaver/core-root'; +import { CachedDataResource, GraphQLService, ObjectPropertyInfo } from '@cloudbeaver/core-sdk'; + +export type TeamMetaParameter = ObjectPropertyInfo; + +@injectable() +export class TeamMetaParametersResource extends CachedDataResource { + constructor( + private readonly graphQLService: GraphQLService, + sessionResource: SessionResource, + ) { + super([]); + + this.sync(sessionResource, () => { }, () => { }); + } + + protected async loader(): Promise { + const { parameters } = await this.graphQLService.sdk.getTeamMetaParameters(); + return parameters; + } +} diff --git a/webapp/packages/core-authentication/src/TeamsResource.ts b/webapp/packages/core-authentication/src/TeamsResource.ts index 47cc793a75..ba3c8bb42d 100644 --- a/webapp/packages/core-authentication/src/TeamsResource.ts +++ b/webapp/packages/core-authentication/src/TeamsResource.ts @@ -16,17 +16,20 @@ import { ResourceKeyUtils, AdminTeamInfoFragment, AdminConnectionGrantInfo, - CachedMapAllKey + CachedMapAllKey, + GetTeamsListQueryVariables } from '@cloudbeaver/core-sdk'; import { isArraysEqual } from '@cloudbeaver/core-utils'; const NEW_TEAM_SYMBOL = Symbol('new-team'); export type TeamInfo = AdminTeamInfoFragment; + +type TeamResourceIncludes = Omit; type NewTeam = TeamInfo & { [NEW_TEAM_SYMBOL]: boolean; timestamp: number }; @injectable() -export class TeamsResource extends CachedMapResource { +export class TeamsResource extends CachedMapResource { constructor(private readonly graphQLService: GraphQLService) { super(); } @@ -41,8 +44,20 @@ export class TeamsResource extends CachedMapResource { return this.data; } - async createTeam(teamInfo: TeamInfo): Promise { - const response = await this.graphQLService.sdk.createTeam(teamInfo); + async createTeam({ + teamId, + teamPermissions, + teamName, + description, + metaParameters, + }: TeamInfo): Promise { + const response = await this.graphQLService.sdk.createTeam({ + teamId, + teamName, + description, + ...this.getDefaultIncludes(), + ...this.getIncludesMap(teamId), + }); const newTeam: NewTeam = { ...response.team, @@ -52,19 +67,35 @@ export class TeamsResource extends CachedMapResource { this.updateTeams(newTeam); - await this.setSubjectPermissions(newTeam.teamId, teamInfo.teamPermissions); + await this.setMetaParameters(newTeam.teamId, metaParameters); + await this.setSubjectPermissions(newTeam.teamId, teamPermissions); - return this.get(teamInfo.teamId)!; + return this.get(teamId)!; } - async updateTeam(teamInfo: TeamInfo): Promise { - const { team } = await this.graphQLService.sdk.updateTeam(teamInfo); + async updateTeam({ + teamId, + teamPermissions, + teamName, + description, + metaParameters, + }: TeamInfo): Promise { + const { team } = await this.graphQLService.sdk.updateTeam({ + teamId, + teamName, + description, + ...this.getDefaultIncludes(), + ...this.getIncludesMap(teamId), + }); this.updateTeams(team); - await this.setSubjectPermissions(team.teamId, teamInfo.teamPermissions); + await this.setMetaParameters(team.teamId, metaParameters); + await this.setSubjectPermissions(team.teamId, teamPermissions); - return this.get(teamInfo.teamId)!; + this.markOutdated(team.teamId); + + return this.get(teamId)!; } async deleteTeam(key: ResourceKey): Promise> { @@ -103,11 +134,15 @@ export class TeamsResource extends CachedMapResource { team.teamPermissions = newPermissions.map(permission => permission.id); } else { // TODO: update permissions for team instead - await this.loader(subjectId); + await this.loader(subjectId, []); } } - protected async loader(key: ResourceKey): Promise> { + async setMetaParameters(teamId: string, parameters: Record): Promise { + await this.graphQLService.sdk.saveTeamMetaParameters({ teamId, parameters }); + } + + protected async loader(key: ResourceKey, includes: string[] | undefined): Promise> { const all = ResourceKeyUtils.includes(key, CachedMapAllKey); await ResourceKeyUtils.forEachAsync(all ? CachedMapAllKey : key, async key => { @@ -115,9 +150,12 @@ export class TeamsResource extends CachedMapResource { const { teams } = await this.graphQLService.sdk.getTeamsList({ teamId, + ...this.getDefaultIncludes(), + ...this.getIncludesMap(teamId, includes), }); if (all) { + this.resetIncludes(); this.data.clear(); } @@ -141,6 +179,12 @@ export class TeamsResource extends CachedMapResource { return key; } + + private getDefaultIncludes(): TeamResourceIncludes { + return { + includeMetaParameters: false, + }; + } } function isNewTeam(team: TeamInfo | NewTeam): team is NewTeam { diff --git a/webapp/packages/core-authentication/src/index.ts b/webapp/packages/core-authentication/src/index.ts index a82c6a1b40..70c9325069 100644 --- a/webapp/packages/core-authentication/src/index.ts +++ b/webapp/packages/core-authentication/src/index.ts @@ -16,3 +16,4 @@ export * from './UserDataService'; export * from './UserInfoResource'; export * from './UserMetaParametersResource'; export * from './UsersResource'; +export * from './TeamMetaParametersResource'; \ No newline at end of file diff --git a/webapp/packages/core-authentication/src/manifest.ts b/webapp/packages/core-authentication/src/manifest.ts index e07c765bb2..4f08e36cb3 100644 --- a/webapp/packages/core-authentication/src/manifest.ts +++ b/webapp/packages/core-authentication/src/manifest.ts @@ -16,6 +16,7 @@ import { AuthProviderService } from './AuthProviderService'; import { AuthProvidersResource } from './AuthProvidersResource'; import { AuthRolesResource } from './AuthRolesResource'; import { AuthSettingsService } from './AuthSettingsService'; +import { TeamMetaParametersResource } from './TeamMetaParametersResource'; import { TeamsManagerService } from './TeamsManagerService'; import { TeamsResource } from './TeamsResource'; import { UserConfigurationBootstrap } from './UserConfigurationBootstrap'; @@ -45,5 +46,6 @@ export const manifest: PluginManifest = { UserMetaParametersResource, UserConfigurationBootstrap, AuthRolesResource, + TeamMetaParametersResource, ], }; diff --git a/webapp/packages/core-connections/src/ConnectionInfoResource.ts b/webapp/packages/core-connections/src/ConnectionInfoResource.ts index e3285e142c..6417a32c37 100644 --- a/webapp/packages/core-connections/src/ConnectionInfoResource.ts +++ b/webapp/packages/core-connections/src/ConnectionInfoResource.ts @@ -38,7 +38,7 @@ import type { IConnectionInfoParams } from './IConnectionsResource'; export type Connection = DatabaseConnection & { authProperties?: UserConnectionAuthPropertiesFragment[]; }; -export type ConnectionInitConfig = Omit; +export type ConnectionInitConfig = Omit; export type ConnectionInfoIncludes = Omit; export const NEW_CONNECTION_SYMBOL = Symbol('new-connection'); @@ -477,6 +477,8 @@ export class ConnectionInfoResource customIncludeOriginDetails: false, includeAuthProperties: false, includeOrigin: true, + includeAuthNeeded: false, + includeCredentialsSaved: false, }; } } diff --git a/webapp/packages/core-connections/src/locales/en.ts b/webapp/packages/core-connections/src/locales/en.ts index 27e791be66..0035a8f19d 100644 --- a/webapp/packages/core-connections/src/locales/en.ts +++ b/webapp/packages/core-connections/src/locales/en.ts @@ -23,6 +23,8 @@ export default [ ['connections_connection_create_custom', 'Custom'], ['connections_connection_create_search_database', 'Search'], ['connections_connection_edit_save_credentials', 'Save credentials'], + ['connections_connection_share_credentials', 'Share credentials'], + ['connections_connection_share_credentials_tooltip', 'Share credentials across all users'], ['connections_connection_credentials_provisioning', 'Authentication credentials'], ['connections_connection_credentials_provisioning_description', 'You need to fill in or confirm the credentials to test this connection'], ['connections_connection_edit_authentication', 'Authentication'], diff --git a/webapp/packages/core-connections/src/locales/it.ts b/webapp/packages/core-connections/src/locales/it.ts index f878fabe07..5685f268e4 100644 --- a/webapp/packages/core-connections/src/locales/it.ts +++ b/webapp/packages/core-connections/src/locales/it.ts @@ -21,6 +21,8 @@ export default [ ['connections_connection_create_custom', 'Custom'], ['connections_connection_create_search_database', 'Cerca'], ['connections_connection_edit_save_credentials', 'Salva le credenziali'], + ['connections_connection_share_credentials', 'Share credentials'], + ['connections_connection_share_credentials_tooltip', 'Share credentials across all users'], ['connections_connection_credentials_provisioning', 'Credenziali di autenticazione'], ['connections_connection_credentials_provisioning_description', 'Devi compilare o confermare le credenziali per provare questa connessione'], ['connections_connection_edit_authentication', 'Autenticazione'], diff --git a/webapp/packages/core-connections/src/locales/ru.ts b/webapp/packages/core-connections/src/locales/ru.ts index b5bd3acfee..deff940ef9 100644 --- a/webapp/packages/core-connections/src/locales/ru.ts +++ b/webapp/packages/core-connections/src/locales/ru.ts @@ -20,6 +20,8 @@ export default [ ['connections_connection_create_custom', 'Настроить'], ['connections_connection_create_search_database', 'Найти'], ['connections_connection_edit_save_credentials', ' Запомнить данные'], + ['connections_connection_share_credentials', 'Запомнить данные для всех пользователей'], + ['connections_connection_share_credentials_tooltip', 'Запомнить данные для всех пользователей'], ['connections_connection_credentials_provisioning', 'Аутентификационные данные'], ['connections_connection_credentials_provisioning_description', 'Чтобы проверить подключение, необходимо заполнить или подтвердить данные доступа'], ['connections_connection_edit_authentication', 'Авторизация'], diff --git a/webapp/packages/core-connections/src/locales/zh.ts b/webapp/packages/core-connections/src/locales/zh.ts index 20137d2810..8bec724a43 100644 --- a/webapp/packages/core-connections/src/locales/zh.ts +++ b/webapp/packages/core-connections/src/locales/zh.ts @@ -22,6 +22,8 @@ export default [ ['connections_connection_create_custom', '自定义'], ['connections_connection_create_search_database', '搜索'], ['connections_connection_edit_save_credentials', '保存凭据'], + ['connections_connection_share_credentials', 'Share credentials'], + ['connections_connection_share_credentials_tooltip', 'Share credentials across all users'], ['connections_connection_credentials_provisioning', '认证凭据'], ['connections_connection_credentials_provisioning_description', '您却要填写或确认凭据以测试此连接。'], ['connections_connection_edit_authentication', '认证'], diff --git a/webapp/packages/core-navigation-tree/src/NodesManager/NavNodeManagerService.ts b/webapp/packages/core-navigation-tree/src/NodesManager/NavNodeManagerService.ts index 5b97895e29..06b397d508 100644 --- a/webapp/packages/core-navigation-tree/src/NodesManager/NavNodeManagerService.ts +++ b/webapp/packages/core-navigation-tree/src/NodesManager/NavNodeManagerService.ts @@ -174,6 +174,10 @@ export class NavNodeManagerService extends Bootstrap { } async canOpen(nodeId: string, parentId: string, folderId?: string): Promise { + if (!this.navTree.has(nodeId)) { + return false; + } + const contexts = await this.navigator.execute({ type: NavigationType.canOpen, nodeId, diff --git a/webapp/packages/core-sdk/src/queries/authentication/teams/createTeam.gql b/webapp/packages/core-sdk/src/queries/authentication/teams/createTeam.gql index 6617ea956f..7654ea781e 100644 --- a/webapp/packages/core-sdk/src/queries/authentication/teams/createTeam.gql +++ b/webapp/packages/core-sdk/src/queries/authentication/teams/createTeam.gql @@ -1,4 +1,4 @@ -query createTeam($teamId: ID!, $teamName: String, $description: String ) { +query createTeam($teamId: ID!, $teamName: String, $description: String, $includeMetaParameters: Boolean!) { team: createTeam(teamId: $teamId, teamName: $teamName, description: $description) { ...AdminTeamInfo } diff --git a/webapp/packages/core-sdk/src/queries/authentication/teams/getTeamMetaParameters.gql b/webapp/packages/core-sdk/src/queries/authentication/teams/getTeamMetaParameters.gql new file mode 100644 index 0000000000..7e96985156 --- /dev/null +++ b/webapp/packages/core-sdk/src/queries/authentication/teams/getTeamMetaParameters.gql @@ -0,0 +1,5 @@ +query getTeamMetaParameters { + parameters: listTeamMetaParameters { + ...ObjectPropertyInfo + } +} \ No newline at end of file diff --git a/webapp/packages/core-sdk/src/queries/authentication/teams/getTeamsList.gql b/webapp/packages/core-sdk/src/queries/authentication/teams/getTeamsList.gql index a7f4901739..fbbb425072 100644 --- a/webapp/packages/core-sdk/src/queries/authentication/teams/getTeamsList.gql +++ b/webapp/packages/core-sdk/src/queries/authentication/teams/getTeamsList.gql @@ -1,4 +1,4 @@ -query getTeamsList($teamId: ID) { +query getTeamsList($teamId: ID, $includeMetaParameters: Boolean!) { teams: listTeams(teamId: $teamId) { ...AdminTeamInfo } diff --git a/webapp/packages/core-sdk/src/queries/authentication/teams/saveTeamMetaParameters.gql b/webapp/packages/core-sdk/src/queries/authentication/teams/saveTeamMetaParameters.gql new file mode 100644 index 0000000000..453fabd09b --- /dev/null +++ b/webapp/packages/core-sdk/src/queries/authentication/teams/saveTeamMetaParameters.gql @@ -0,0 +1,9 @@ +query saveTeamMetaParameters( + $teamId: ID! + $parameters: Object! +) { + setTeamMetaParameterValues( + teamId: $teamId, + parameters: $parameters + ) +} \ No newline at end of file diff --git a/webapp/packages/core-sdk/src/queries/authentication/teams/updateTeam.gql b/webapp/packages/core-sdk/src/queries/authentication/teams/updateTeam.gql index 5b7d115b79..20bafa082b 100644 --- a/webapp/packages/core-sdk/src/queries/authentication/teams/updateTeam.gql +++ b/webapp/packages/core-sdk/src/queries/authentication/teams/updateTeam.gql @@ -1,4 +1,4 @@ -query updateTeam($teamId: ID!, $teamName: String, $description: String ) { +query updateTeam($teamId: ID!, $teamName: String, $description: String, $includeMetaParameters: Boolean!) { team: updateTeam(teamId: $teamId, teamName: $teamName, description: $description) { ...AdminTeamInfo } diff --git a/webapp/packages/core-sdk/src/queries/connections/closeConnection.gql b/webapp/packages/core-sdk/src/queries/connections/closeConnection.gql index 0b40e19671..35b789d377 100644 --- a/webapp/packages/core-sdk/src/queries/connections/closeConnection.gql +++ b/webapp/packages/core-sdk/src/queries/connections/closeConnection.gql @@ -6,6 +6,8 @@ mutation closeConnection( $customIncludeOriginDetails: Boolean! $includeAuthProperties: Boolean! $customIncludeNetworkHandlerCredentials: Boolean! + $includeCredentialsSaved: Boolean! + $includeAuthNeeded: Boolean! ) { connection: closeConnection(projectId: $projectId, id: $connectionId) { ...DatabaseConnection diff --git a/webapp/packages/core-sdk/src/queries/connections/createConnection.gql b/webapp/packages/core-sdk/src/queries/connections/createConnection.gql index 87bfa093a7..2f61a9a484 100644 --- a/webapp/packages/core-sdk/src/queries/connections/createConnection.gql +++ b/webapp/packages/core-sdk/src/queries/connections/createConnection.gql @@ -6,6 +6,8 @@ mutation createConnection( $customIncludeOriginDetails: Boolean! $includeAuthProperties: Boolean! $customIncludeNetworkHandlerCredentials: Boolean! + $includeCredentialsSaved: Boolean! + $includeAuthNeeded: Boolean! ) { connection: createConnection(projectId: $projectId, config: $config) { ...DatabaseConnection diff --git a/webapp/packages/core-sdk/src/queries/connections/createConnectionFromNode.gql b/webapp/packages/core-sdk/src/queries/connections/createConnectionFromNode.gql index 17d337815c..50e0d25d2a 100644 --- a/webapp/packages/core-sdk/src/queries/connections/createConnectionFromNode.gql +++ b/webapp/packages/core-sdk/src/queries/connections/createConnectionFromNode.gql @@ -7,6 +7,8 @@ mutation createConnectionFromNode( $customIncludeOriginDetails: Boolean! $includeAuthProperties: Boolean! $customIncludeNetworkHandlerCredentials: Boolean! + $includeCredentialsSaved: Boolean! + $includeAuthNeeded: Boolean! ) { connection: copyConnectionFromNode(projectId: $projectId, nodePath: $nodePath, config: $config) { ...DatabaseConnection diff --git a/webapp/packages/core-sdk/src/queries/connections/createConnectionFromTemplate.gql b/webapp/packages/core-sdk/src/queries/connections/createConnectionFromTemplate.gql index d51a37e04d..1eaa1dd014 100644 --- a/webapp/packages/core-sdk/src/queries/connections/createConnectionFromTemplate.gql +++ b/webapp/packages/core-sdk/src/queries/connections/createConnectionFromTemplate.gql @@ -7,6 +7,8 @@ mutation createConnectionFromTemplate( $customIncludeOriginDetails: Boolean! $includeAuthProperties: Boolean! $customIncludeNetworkHandlerCredentials: Boolean! + $includeCredentialsSaved: Boolean! + $includeAuthNeeded: Boolean! ) { connection: createConnectionFromTemplate(projectId: $projectId, templateId: $templateId, connectionName: $connectionName) { ...DatabaseConnection diff --git a/webapp/packages/core-sdk/src/queries/connections/getTemplateConnections.gql b/webapp/packages/core-sdk/src/queries/connections/getTemplateConnections.gql index b4ab50313f..9450f1c217 100644 --- a/webapp/packages/core-sdk/src/queries/connections/getTemplateConnections.gql +++ b/webapp/packages/core-sdk/src/queries/connections/getTemplateConnections.gql @@ -4,6 +4,8 @@ query getTemplateConnections( $customIncludeOriginDetails: Boolean! $includeAuthProperties: Boolean! $customIncludeNetworkHandlerCredentials: Boolean! + $includeCredentialsSaved: Boolean! + $includeAuthNeeded: Boolean! ) { connections: templateConnections(projectId: $projectId) { ...DatabaseConnection diff --git a/webapp/packages/core-sdk/src/queries/connections/getUserConnections.gql b/webapp/packages/core-sdk/src/queries/connections/getUserConnections.gql index 0cfb807cec..3f86591350 100644 --- a/webapp/packages/core-sdk/src/queries/connections/getUserConnections.gql +++ b/webapp/packages/core-sdk/src/queries/connections/getUserConnections.gql @@ -5,6 +5,8 @@ query getUserConnections( $customIncludeOriginDetails: Boolean! $includeAuthProperties: Boolean! $customIncludeNetworkHandlerCredentials: Boolean! + $includeCredentialsSaved: Boolean! + $includeAuthNeeded: Boolean! ) { connections: userConnections(projectId: $projectId, id: $connectionId) { ...DatabaseConnection diff --git a/webapp/packages/core-sdk/src/queries/connections/initConnection.gql b/webapp/packages/core-sdk/src/queries/connections/initConnection.gql index 56f36a51d9..5502749450 100644 --- a/webapp/packages/core-sdk/src/queries/connections/initConnection.gql +++ b/webapp/packages/core-sdk/src/queries/connections/initConnection.gql @@ -4,18 +4,22 @@ mutation initConnection( $credentials: Object $networkCredentials: [NetworkHandlerConfigInput!] $saveCredentials: Boolean + $sharedCredentials: Boolean $includeOrigin: Boolean! $customIncludeOriginDetails: Boolean! $includeAuthProperties: Boolean! $customIncludeNetworkHandlerCredentials: Boolean! + $includeCredentialsSaved: Boolean! + $includeAuthNeeded: Boolean! ) { connection: initConnection( projectId: $projectId id: $connectionId credentials: $credentials networkCredentials: $networkCredentials - saveCredentials: $saveCredentials + saveCredentials: $saveCredentials, + sharedCredentials: $sharedCredentials, ) { ...DatabaseConnection } diff --git a/webapp/packages/core-sdk/src/queries/connections/setConnectionNavigatorSettings.gql b/webapp/packages/core-sdk/src/queries/connections/setConnectionNavigatorSettings.gql index 1ec0646fce..e3fe0f7c06 100644 --- a/webapp/packages/core-sdk/src/queries/connections/setConnectionNavigatorSettings.gql +++ b/webapp/packages/core-sdk/src/queries/connections/setConnectionNavigatorSettings.gql @@ -7,6 +7,8 @@ mutation setConnectionNavigatorSettings( $customIncludeOriginDetails: Boolean! $includeAuthProperties: Boolean! $customIncludeNetworkHandlerCredentials: Boolean! + $includeCredentialsSaved: Boolean! + $includeAuthNeeded: Boolean! ) { connection: setConnectionNavigatorSettings(projectId: $projectId, id: $connectionId, settings: $settings) { ...DatabaseConnection diff --git a/webapp/packages/core-sdk/src/queries/connections/updateConnection.gql b/webapp/packages/core-sdk/src/queries/connections/updateConnection.gql index 177de578c4..6051ed6f99 100644 --- a/webapp/packages/core-sdk/src/queries/connections/updateConnection.gql +++ b/webapp/packages/core-sdk/src/queries/connections/updateConnection.gql @@ -6,6 +6,8 @@ mutation updateConnection( $customIncludeOriginDetails: Boolean! $includeAuthProperties: Boolean! $customIncludeNetworkHandlerCredentials: Boolean! + $includeCredentialsSaved: Boolean! + $includeAuthNeeded: Boolean! ) { connection: updateConnection(projectId: $projectId, config: $config) { ...DatabaseConnection diff --git a/webapp/packages/core-sdk/src/queries/fragments/AdminTeamInfo.gql b/webapp/packages/core-sdk/src/queries/fragments/AdminTeamInfo.gql index d30dfb554d..29bfda19d0 100644 --- a/webapp/packages/core-sdk/src/queries/fragments/AdminTeamInfo.gql +++ b/webapp/packages/core-sdk/src/queries/fragments/AdminTeamInfo.gql @@ -3,4 +3,5 @@ fragment AdminTeamInfo on AdminTeamInfo { teamName description teamPermissions + metaParameters @include(if: $includeMetaParameters) } \ No newline at end of file diff --git a/webapp/packages/core-sdk/src/queries/fragments/DatabaseConnection.gql b/webapp/packages/core-sdk/src/queries/fragments/DatabaseConnection.gql index 15874115cc..94e7796646 100644 --- a/webapp/packages/core-sdk/src/queries/fragments/DatabaseConnection.gql +++ b/webapp/packages/core-sdk/src/queries/fragments/DatabaseConnection.gql @@ -10,7 +10,10 @@ fragment DatabaseConnection on ConnectionInfo { provided useUrl readOnly + saveCredentials + credentialsSaved @include(if: $includeCredentialsSaved) + sharedCredentials folder nodePath @@ -33,7 +36,7 @@ fragment DatabaseConnection on ConnectionInfo { ...ObjectOriginInfo } - authNeeded + authNeeded @include(if: $includeAuthNeeded) authModel authProperties @include(if: $includeAuthProperties) { diff --git a/webapp/packages/core-sdk/src/queries/fragments/ObjectPropertyInfo.gql b/webapp/packages/core-sdk/src/queries/fragments/ObjectPropertyInfo.gql new file mode 100644 index 0000000000..e097d362b5 --- /dev/null +++ b/webapp/packages/core-sdk/src/queries/fragments/ObjectPropertyInfo.gql @@ -0,0 +1,13 @@ +fragment ObjectPropertyInfo on ObjectPropertyInfo { + id + displayName + description + category + dataType + value + validValues + defaultValue + length + features + order +} \ No newline at end of file diff --git a/webapp/packages/core-sdk/src/sdk.ts b/webapp/packages/core-sdk/src/sdk.ts index 46fa5b8b2d..2e239a7657 100644 --- a/webapp/packages/core-sdk/src/sdk.ts +++ b/webapp/packages/core-sdk/src/sdk.ts @@ -75,6 +75,7 @@ export interface AdminTeamInfo { description?: Maybe; grantedConnections: Array; grantedUsers: Array; + metaParameters: Scalars['Object']; teamId: Scalars['ID']; teamName?: Maybe; teamPermissions: Array; @@ -194,6 +195,7 @@ export interface ConnectionConfig { readOnly?: InputMaybe; saveCredentials?: InputMaybe; serverName?: InputMaybe; + sharedCredentials?: InputMaybe; template?: InputMaybe; templateId?: InputMaybe; url?: InputMaybe; @@ -219,6 +221,7 @@ export interface ConnectionInfo { connectTime?: Maybe; connected: Scalars['Boolean']; connectionError?: Maybe; + credentialsSaved: Scalars['Boolean']; databaseName?: Maybe; description?: Maybe; driverId: Scalars['ID']; @@ -241,6 +244,7 @@ export interface ConnectionInfo { saveCredentials: Scalars['Boolean']; serverName?: Maybe; serverVersion?: Maybe; + sharedCredentials: Scalars['Boolean']; supportedDataFormats: Array; template: Scalars['Boolean']; url?: Maybe; @@ -542,6 +546,7 @@ export interface MutationInitConnectionArgs { networkCredentials?: InputMaybe>; projectId?: InputMaybe; saveCredentials?: InputMaybe; + sharedCredentials?: InputMaybe; } @@ -918,6 +923,7 @@ export interface Query { listFeatureSets: Array; listPermissions: Array; listProjects: Array; + listTeamMetaParameters: Array; listTeams: Array; listUserProfileProperties: Array; listUsers: Array; @@ -949,6 +955,7 @@ export interface Query { setDefaultNavigatorSettings: Scalars['Boolean']; setSubjectConnectionAccess?: Maybe; setSubjectPermissions: Array; + setTeamMetaParameterValues: Scalars['Boolean']; setUserAuthRole?: Maybe; setUserCredentials?: Maybe; setUserMetaParameterValues: Scalars['Boolean']; @@ -1246,6 +1253,12 @@ export interface QuerySetSubjectPermissionsArgs { } +export interface QuerySetTeamMetaParameterValuesArgs { + parameters: Scalars['Object']; + teamId: Scalars['ID']; +} + + export interface QuerySetUserAuthRoleArgs { authRole?: InputMaybe; userId: Scalars['ID']; @@ -1608,6 +1621,7 @@ export interface UserAuthToken { } export interface UserInfo { + authRole?: Maybe; authTokens: Array; configurationParameters: Scalars['Object']; displayName?: Maybe; @@ -1757,10 +1771,11 @@ export type CreateTeamQueryVariables = Exact<{ teamId: Scalars['ID']; teamName?: InputMaybe; description?: InputMaybe; + includeMetaParameters: Scalars['Boolean']; }>; -export type CreateTeamQuery = { team: { teamId: string, teamName?: string, description?: string, teamPermissions: Array } }; +export type CreateTeamQuery = { team: { teamId: string, teamName?: string, description?: string, teamPermissions: Array, metaParameters?: any } }; export type DeleteTeamQueryVariables = Exact<{ teamId: Scalars['ID']; @@ -1776,21 +1791,36 @@ export type GetTeamGrantedUsersQueryVariables = Exact<{ export type GetTeamGrantedUsersQuery = { team: Array<{ grantedUsers: Array }> }; +export type GetTeamMetaParametersQueryVariables = Exact<{ [key: string]: never; }>; + + +export type GetTeamMetaParametersQuery = { parameters: Array<{ id?: string, displayName?: string, description?: string, category?: string, dataType?: string, value?: any, validValues?: Array, defaultValue?: any, length: ObjectPropertyLength, features: Array, order: number }> }; + export type GetTeamsListQueryVariables = Exact<{ teamId?: InputMaybe; + includeMetaParameters: Scalars['Boolean']; }>; -export type GetTeamsListQuery = { teams: Array<{ teamId: string, teamName?: string, description?: string, teamPermissions: Array }> }; +export type GetTeamsListQuery = { teams: Array<{ teamId: string, teamName?: string, description?: string, teamPermissions: Array, metaParameters?: any }> }; + +export type SaveTeamMetaParametersQueryVariables = Exact<{ + teamId: Scalars['ID']; + parameters: Scalars['Object']; +}>; + + +export type SaveTeamMetaParametersQuery = { setTeamMetaParameterValues: boolean }; export type UpdateTeamQueryVariables = Exact<{ teamId: Scalars['ID']; teamName?: InputMaybe; description?: InputMaybe; + includeMetaParameters: Scalars['Boolean']; }>; -export type UpdateTeamQuery = { team: { teamId: string, teamName?: string, description?: string, teamPermissions: Array } }; +export type UpdateTeamQuery = { team: { teamId: string, teamName?: string, description?: string, teamPermissions: Array, metaParameters?: any } }; export type CreateUserQueryVariables = Exact<{ userId: Scalars['ID']; @@ -1954,10 +1984,12 @@ export type CloseConnectionMutationVariables = Exact<{ customIncludeOriginDetails: Scalars['Boolean']; includeAuthProperties: Scalars['Boolean']; customIncludeNetworkHandlerCredentials: Scalars['Boolean']; + includeCredentialsSaved: Scalars['Boolean']; + includeAuthNeeded: Scalars['Boolean']; }>; -export type CloseConnectionMutation = { connection: { id: string, projectId: string, name: string, description?: string, driverId: string, template: boolean, connected: boolean, provided: boolean, useUrl: boolean, readOnly: boolean, saveCredentials: boolean, folder?: string, nodePath?: string, host?: string, port?: string, serverName?: string, databaseName?: string, url?: string, properties?: any, providerProperties: any, requiredAuth?: string, features: Array, supportedDataFormats: Array, configurationType?: DriverConfigurationType, authNeeded: boolean, authModel?: string, canViewSettings: boolean, canEdit: boolean, canDelete: boolean, origin?: { type: string, subType?: string, displayName: string, icon?: string, details?: Array<{ id?: string, displayName?: string, description?: string, category?: string, dataType?: string, defaultValue?: any, validValues?: Array, value?: any, length: ObjectPropertyLength, features: Array, order: number }> }, authProperties?: Array<{ id?: string, displayName?: string, description?: string, category?: string, dataType?: string, value?: any, validValues?: Array, defaultValue?: any, length: ObjectPropertyLength, features: Array, order: number }>, networkHandlersConfig: Array<{ id: string, enabled: boolean, authType: NetworkHandlerAuthType, userName?: string, password?: string, key?: string, savePassword: boolean, properties?: any }>, navigatorSettings: { showSystemObjects: boolean, showUtilityObjects: boolean, showOnlyEntities: boolean, mergeEntities: boolean, hideFolders: boolean, hideSchemas: boolean, hideVirtualModel: boolean } } }; +export type CloseConnectionMutation = { connection: { id: string, projectId: string, name: string, description?: string, driverId: string, template: boolean, connected: boolean, provided: boolean, useUrl: boolean, readOnly: boolean, saveCredentials: boolean, credentialsSaved?: boolean, sharedCredentials: boolean, folder?: string, nodePath?: string, host?: string, port?: string, serverName?: string, databaseName?: string, url?: string, properties?: any, providerProperties: any, requiredAuth?: string, features: Array, supportedDataFormats: Array, configurationType?: DriverConfigurationType, authNeeded?: boolean, authModel?: string, canViewSettings: boolean, canEdit: boolean, canDelete: boolean, origin?: { type: string, subType?: string, displayName: string, icon?: string, details?: Array<{ id?: string, displayName?: string, description?: string, category?: string, dataType?: string, defaultValue?: any, validValues?: Array, value?: any, length: ObjectPropertyLength, features: Array, order: number }> }, authProperties?: Array<{ id?: string, displayName?: string, description?: string, category?: string, dataType?: string, value?: any, validValues?: Array, defaultValue?: any, length: ObjectPropertyLength, features: Array, order: number }>, networkHandlersConfig: Array<{ id: string, enabled: boolean, authType: NetworkHandlerAuthType, userName?: string, password?: string, key?: string, savePassword: boolean, properties?: any }>, navigatorSettings: { showSystemObjects: boolean, showUtilityObjects: boolean, showOnlyEntities: boolean, mergeEntities: boolean, hideFolders: boolean, hideSchemas: boolean, hideVirtualModel: boolean } } }; export type CreateConnectionMutationVariables = Exact<{ projectId: Scalars['ID']; @@ -1966,10 +1998,12 @@ export type CreateConnectionMutationVariables = Exact<{ customIncludeOriginDetails: Scalars['Boolean']; includeAuthProperties: Scalars['Boolean']; customIncludeNetworkHandlerCredentials: Scalars['Boolean']; + includeCredentialsSaved: Scalars['Boolean']; + includeAuthNeeded: Scalars['Boolean']; }>; -export type CreateConnectionMutation = { connection: { id: string, projectId: string, name: string, description?: string, driverId: string, template: boolean, connected: boolean, provided: boolean, useUrl: boolean, readOnly: boolean, saveCredentials: boolean, folder?: string, nodePath?: string, host?: string, port?: string, serverName?: string, databaseName?: string, url?: string, properties?: any, providerProperties: any, requiredAuth?: string, features: Array, supportedDataFormats: Array, configurationType?: DriverConfigurationType, authNeeded: boolean, authModel?: string, canViewSettings: boolean, canEdit: boolean, canDelete: boolean, origin?: { type: string, subType?: string, displayName: string, icon?: string, details?: Array<{ id?: string, displayName?: string, description?: string, category?: string, dataType?: string, defaultValue?: any, validValues?: Array, value?: any, length: ObjectPropertyLength, features: Array, order: number }> }, authProperties?: Array<{ id?: string, displayName?: string, description?: string, category?: string, dataType?: string, value?: any, validValues?: Array, defaultValue?: any, length: ObjectPropertyLength, features: Array, order: number }>, networkHandlersConfig: Array<{ id: string, enabled: boolean, authType: NetworkHandlerAuthType, userName?: string, password?: string, key?: string, savePassword: boolean, properties?: any }>, navigatorSettings: { showSystemObjects: boolean, showUtilityObjects: boolean, showOnlyEntities: boolean, mergeEntities: boolean, hideFolders: boolean, hideSchemas: boolean, hideVirtualModel: boolean } } }; +export type CreateConnectionMutation = { connection: { id: string, projectId: string, name: string, description?: string, driverId: string, template: boolean, connected: boolean, provided: boolean, useUrl: boolean, readOnly: boolean, saveCredentials: boolean, credentialsSaved?: boolean, sharedCredentials: boolean, folder?: string, nodePath?: string, host?: string, port?: string, serverName?: string, databaseName?: string, url?: string, properties?: any, providerProperties: any, requiredAuth?: string, features: Array, supportedDataFormats: Array, configurationType?: DriverConfigurationType, authNeeded?: boolean, authModel?: string, canViewSettings: boolean, canEdit: boolean, canDelete: boolean, origin?: { type: string, subType?: string, displayName: string, icon?: string, details?: Array<{ id?: string, displayName?: string, description?: string, category?: string, dataType?: string, defaultValue?: any, validValues?: Array, value?: any, length: ObjectPropertyLength, features: Array, order: number }> }, authProperties?: Array<{ id?: string, displayName?: string, description?: string, category?: string, dataType?: string, value?: any, validValues?: Array, defaultValue?: any, length: ObjectPropertyLength, features: Array, order: number }>, networkHandlersConfig: Array<{ id: string, enabled: boolean, authType: NetworkHandlerAuthType, userName?: string, password?: string, key?: string, savePassword: boolean, properties?: any }>, navigatorSettings: { showSystemObjects: boolean, showUtilityObjects: boolean, showOnlyEntities: boolean, mergeEntities: boolean, hideFolders: boolean, hideSchemas: boolean, hideVirtualModel: boolean } } }; export type CreateConnectionFolderMutationVariables = Exact<{ projectId: Scalars['ID']; @@ -1988,10 +2022,12 @@ export type CreateConnectionFromNodeMutationVariables = Exact<{ customIncludeOriginDetails: Scalars['Boolean']; includeAuthProperties: Scalars['Boolean']; customIncludeNetworkHandlerCredentials: Scalars['Boolean']; + includeCredentialsSaved: Scalars['Boolean']; + includeAuthNeeded: Scalars['Boolean']; }>; -export type CreateConnectionFromNodeMutation = { connection: { id: string, projectId: string, name: string, description?: string, driverId: string, template: boolean, connected: boolean, provided: boolean, useUrl: boolean, readOnly: boolean, saveCredentials: boolean, folder?: string, nodePath?: string, host?: string, port?: string, serverName?: string, databaseName?: string, url?: string, properties?: any, providerProperties: any, requiredAuth?: string, features: Array, supportedDataFormats: Array, configurationType?: DriverConfigurationType, authNeeded: boolean, authModel?: string, canViewSettings: boolean, canEdit: boolean, canDelete: boolean, origin?: { type: string, subType?: string, displayName: string, icon?: string, details?: Array<{ id?: string, displayName?: string, description?: string, category?: string, dataType?: string, defaultValue?: any, validValues?: Array, value?: any, length: ObjectPropertyLength, features: Array, order: number }> }, authProperties?: Array<{ id?: string, displayName?: string, description?: string, category?: string, dataType?: string, value?: any, validValues?: Array, defaultValue?: any, length: ObjectPropertyLength, features: Array, order: number }>, networkHandlersConfig: Array<{ id: string, enabled: boolean, authType: NetworkHandlerAuthType, userName?: string, password?: string, key?: string, savePassword: boolean, properties?: any }>, navigatorSettings: { showSystemObjects: boolean, showUtilityObjects: boolean, showOnlyEntities: boolean, mergeEntities: boolean, hideFolders: boolean, hideSchemas: boolean, hideVirtualModel: boolean } } }; +export type CreateConnectionFromNodeMutation = { connection: { id: string, projectId: string, name: string, description?: string, driverId: string, template: boolean, connected: boolean, provided: boolean, useUrl: boolean, readOnly: boolean, saveCredentials: boolean, credentialsSaved?: boolean, sharedCredentials: boolean, folder?: string, nodePath?: string, host?: string, port?: string, serverName?: string, databaseName?: string, url?: string, properties?: any, providerProperties: any, requiredAuth?: string, features: Array, supportedDataFormats: Array, configurationType?: DriverConfigurationType, authNeeded?: boolean, authModel?: string, canViewSettings: boolean, canEdit: boolean, canDelete: boolean, origin?: { type: string, subType?: string, displayName: string, icon?: string, details?: Array<{ id?: string, displayName?: string, description?: string, category?: string, dataType?: string, defaultValue?: any, validValues?: Array, value?: any, length: ObjectPropertyLength, features: Array, order: number }> }, authProperties?: Array<{ id?: string, displayName?: string, description?: string, category?: string, dataType?: string, value?: any, validValues?: Array, defaultValue?: any, length: ObjectPropertyLength, features: Array, order: number }>, networkHandlersConfig: Array<{ id: string, enabled: boolean, authType: NetworkHandlerAuthType, userName?: string, password?: string, key?: string, savePassword: boolean, properties?: any }>, navigatorSettings: { showSystemObjects: boolean, showUtilityObjects: boolean, showOnlyEntities: boolean, mergeEntities: boolean, hideFolders: boolean, hideSchemas: boolean, hideVirtualModel: boolean } } }; export type CreateConnectionFromTemplateMutationVariables = Exact<{ projectId: Scalars['ID']; @@ -2001,10 +2037,12 @@ export type CreateConnectionFromTemplateMutationVariables = Exact<{ customIncludeOriginDetails: Scalars['Boolean']; includeAuthProperties: Scalars['Boolean']; customIncludeNetworkHandlerCredentials: Scalars['Boolean']; + includeCredentialsSaved: Scalars['Boolean']; + includeAuthNeeded: Scalars['Boolean']; }>; -export type CreateConnectionFromTemplateMutation = { connection: { id: string, projectId: string, name: string, description?: string, driverId: string, template: boolean, connected: boolean, provided: boolean, useUrl: boolean, readOnly: boolean, saveCredentials: boolean, folder?: string, nodePath?: string, host?: string, port?: string, serverName?: string, databaseName?: string, url?: string, properties?: any, providerProperties: any, requiredAuth?: string, features: Array, supportedDataFormats: Array, configurationType?: DriverConfigurationType, authNeeded: boolean, authModel?: string, canViewSettings: boolean, canEdit: boolean, canDelete: boolean, origin?: { type: string, subType?: string, displayName: string, icon?: string, details?: Array<{ id?: string, displayName?: string, description?: string, category?: string, dataType?: string, defaultValue?: any, validValues?: Array, value?: any, length: ObjectPropertyLength, features: Array, order: number }> }, authProperties?: Array<{ id?: string, displayName?: string, description?: string, category?: string, dataType?: string, value?: any, validValues?: Array, defaultValue?: any, length: ObjectPropertyLength, features: Array, order: number }>, networkHandlersConfig: Array<{ id: string, enabled: boolean, authType: NetworkHandlerAuthType, userName?: string, password?: string, key?: string, savePassword: boolean, properties?: any }>, navigatorSettings: { showSystemObjects: boolean, showUtilityObjects: boolean, showOnlyEntities: boolean, mergeEntities: boolean, hideFolders: boolean, hideSchemas: boolean, hideVirtualModel: boolean } } }; +export type CreateConnectionFromTemplateMutation = { connection: { id: string, projectId: string, name: string, description?: string, driverId: string, template: boolean, connected: boolean, provided: boolean, useUrl: boolean, readOnly: boolean, saveCredentials: boolean, credentialsSaved?: boolean, sharedCredentials: boolean, folder?: string, nodePath?: string, host?: string, port?: string, serverName?: string, databaseName?: string, url?: string, properties?: any, providerProperties: any, requiredAuth?: string, features: Array, supportedDataFormats: Array, configurationType?: DriverConfigurationType, authNeeded?: boolean, authModel?: string, canViewSettings: boolean, canEdit: boolean, canDelete: boolean, origin?: { type: string, subType?: string, displayName: string, icon?: string, details?: Array<{ id?: string, displayName?: string, description?: string, category?: string, dataType?: string, defaultValue?: any, validValues?: Array, value?: any, length: ObjectPropertyLength, features: Array, order: number }> }, authProperties?: Array<{ id?: string, displayName?: string, description?: string, category?: string, dataType?: string, value?: any, validValues?: Array, defaultValue?: any, length: ObjectPropertyLength, features: Array, order: number }>, networkHandlersConfig: Array<{ id: string, enabled: boolean, authType: NetworkHandlerAuthType, userName?: string, password?: string, key?: string, savePassword: boolean, properties?: any }>, navigatorSettings: { showSystemObjects: boolean, showUtilityObjects: boolean, showOnlyEntities: boolean, mergeEntities: boolean, hideFolders: boolean, hideSchemas: boolean, hideVirtualModel: boolean } } }; export type DeleteConnectionMutationVariables = Exact<{ projectId: Scalars['ID']; @@ -2090,10 +2128,12 @@ export type GetTemplateConnectionsQueryVariables = Exact<{ customIncludeOriginDetails: Scalars['Boolean']; includeAuthProperties: Scalars['Boolean']; customIncludeNetworkHandlerCredentials: Scalars['Boolean']; + includeCredentialsSaved: Scalars['Boolean']; + includeAuthNeeded: Scalars['Boolean']; }>; -export type GetTemplateConnectionsQuery = { connections: Array<{ id: string, projectId: string, name: string, description?: string, driverId: string, template: boolean, connected: boolean, provided: boolean, useUrl: boolean, readOnly: boolean, saveCredentials: boolean, folder?: string, nodePath?: string, host?: string, port?: string, serverName?: string, databaseName?: string, url?: string, properties?: any, providerProperties: any, requiredAuth?: string, features: Array, supportedDataFormats: Array, configurationType?: DriverConfigurationType, authNeeded: boolean, authModel?: string, canViewSettings: boolean, canEdit: boolean, canDelete: boolean, origin?: { type: string, subType?: string, displayName: string, icon?: string, details?: Array<{ id?: string, displayName?: string, description?: string, category?: string, dataType?: string, defaultValue?: any, validValues?: Array, value?: any, length: ObjectPropertyLength, features: Array, order: number }> }, authProperties?: Array<{ id?: string, displayName?: string, description?: string, category?: string, dataType?: string, value?: any, validValues?: Array, defaultValue?: any, length: ObjectPropertyLength, features: Array, order: number }>, networkHandlersConfig: Array<{ id: string, enabled: boolean, authType: NetworkHandlerAuthType, userName?: string, password?: string, key?: string, savePassword: boolean, properties?: any }>, navigatorSettings: { showSystemObjects: boolean, showUtilityObjects: boolean, showOnlyEntities: boolean, mergeEntities: boolean, hideFolders: boolean, hideSchemas: boolean, hideVirtualModel: boolean } }> }; +export type GetTemplateConnectionsQuery = { connections: Array<{ id: string, projectId: string, name: string, description?: string, driverId: string, template: boolean, connected: boolean, provided: boolean, useUrl: boolean, readOnly: boolean, saveCredentials: boolean, credentialsSaved?: boolean, sharedCredentials: boolean, folder?: string, nodePath?: string, host?: string, port?: string, serverName?: string, databaseName?: string, url?: string, properties?: any, providerProperties: any, requiredAuth?: string, features: Array, supportedDataFormats: Array, configurationType?: DriverConfigurationType, authNeeded?: boolean, authModel?: string, canViewSettings: boolean, canEdit: boolean, canDelete: boolean, origin?: { type: string, subType?: string, displayName: string, icon?: string, details?: Array<{ id?: string, displayName?: string, description?: string, category?: string, dataType?: string, defaultValue?: any, validValues?: Array, value?: any, length: ObjectPropertyLength, features: Array, order: number }> }, authProperties?: Array<{ id?: string, displayName?: string, description?: string, category?: string, dataType?: string, value?: any, validValues?: Array, defaultValue?: any, length: ObjectPropertyLength, features: Array, order: number }>, networkHandlersConfig: Array<{ id: string, enabled: boolean, authType: NetworkHandlerAuthType, userName?: string, password?: string, key?: string, savePassword: boolean, properties?: any }>, navigatorSettings: { showSystemObjects: boolean, showUtilityObjects: boolean, showOnlyEntities: boolean, mergeEntities: boolean, hideFolders: boolean, hideSchemas: boolean, hideVirtualModel: boolean } }> }; export type GetUserConnectionsQueryVariables = Exact<{ projectId?: InputMaybe; @@ -2102,10 +2142,12 @@ export type GetUserConnectionsQueryVariables = Exact<{ customIncludeOriginDetails: Scalars['Boolean']; includeAuthProperties: Scalars['Boolean']; customIncludeNetworkHandlerCredentials: Scalars['Boolean']; + includeCredentialsSaved: Scalars['Boolean']; + includeAuthNeeded: Scalars['Boolean']; }>; -export type GetUserConnectionsQuery = { connections: Array<{ id: string, projectId: string, name: string, description?: string, driverId: string, template: boolean, connected: boolean, provided: boolean, useUrl: boolean, readOnly: boolean, saveCredentials: boolean, folder?: string, nodePath?: string, host?: string, port?: string, serverName?: string, databaseName?: string, url?: string, properties?: any, providerProperties: any, requiredAuth?: string, features: Array, supportedDataFormats: Array, configurationType?: DriverConfigurationType, authNeeded: boolean, authModel?: string, canViewSettings: boolean, canEdit: boolean, canDelete: boolean, origin?: { type: string, subType?: string, displayName: string, icon?: string, details?: Array<{ id?: string, displayName?: string, description?: string, category?: string, dataType?: string, defaultValue?: any, validValues?: Array, value?: any, length: ObjectPropertyLength, features: Array, order: number }> }, authProperties?: Array<{ id?: string, displayName?: string, description?: string, category?: string, dataType?: string, value?: any, validValues?: Array, defaultValue?: any, length: ObjectPropertyLength, features: Array, order: number }>, networkHandlersConfig: Array<{ id: string, enabled: boolean, authType: NetworkHandlerAuthType, userName?: string, password?: string, key?: string, savePassword: boolean, properties?: any }>, navigatorSettings: { showSystemObjects: boolean, showUtilityObjects: boolean, showOnlyEntities: boolean, mergeEntities: boolean, hideFolders: boolean, hideSchemas: boolean, hideVirtualModel: boolean } }> }; +export type GetUserConnectionsQuery = { connections: Array<{ id: string, projectId: string, name: string, description?: string, driverId: string, template: boolean, connected: boolean, provided: boolean, useUrl: boolean, readOnly: boolean, saveCredentials: boolean, credentialsSaved?: boolean, sharedCredentials: boolean, folder?: string, nodePath?: string, host?: string, port?: string, serverName?: string, databaseName?: string, url?: string, properties?: any, providerProperties: any, requiredAuth?: string, features: Array, supportedDataFormats: Array, configurationType?: DriverConfigurationType, authNeeded?: boolean, authModel?: string, canViewSettings: boolean, canEdit: boolean, canDelete: boolean, origin?: { type: string, subType?: string, displayName: string, icon?: string, details?: Array<{ id?: string, displayName?: string, description?: string, category?: string, dataType?: string, defaultValue?: any, validValues?: Array, value?: any, length: ObjectPropertyLength, features: Array, order: number }> }, authProperties?: Array<{ id?: string, displayName?: string, description?: string, category?: string, dataType?: string, value?: any, validValues?: Array, defaultValue?: any, length: ObjectPropertyLength, features: Array, order: number }>, networkHandlersConfig: Array<{ id: string, enabled: boolean, authType: NetworkHandlerAuthType, userName?: string, password?: string, key?: string, savePassword: boolean, properties?: any }>, navigatorSettings: { showSystemObjects: boolean, showUtilityObjects: boolean, showOnlyEntities: boolean, mergeEntities: boolean, hideFolders: boolean, hideSchemas: boolean, hideVirtualModel: boolean } }> }; export type InitConnectionMutationVariables = Exact<{ projectId: Scalars['ID']; @@ -2113,14 +2155,17 @@ export type InitConnectionMutationVariables = Exact<{ credentials?: InputMaybe; networkCredentials?: InputMaybe | NetworkHandlerConfigInput>; saveCredentials?: InputMaybe; + sharedCredentials?: InputMaybe; includeOrigin: Scalars['Boolean']; customIncludeOriginDetails: Scalars['Boolean']; includeAuthProperties: Scalars['Boolean']; customIncludeNetworkHandlerCredentials: Scalars['Boolean']; + includeCredentialsSaved: Scalars['Boolean']; + includeAuthNeeded: Scalars['Boolean']; }>; -export type InitConnectionMutation = { connection: { id: string, projectId: string, name: string, description?: string, driverId: string, template: boolean, connected: boolean, provided: boolean, useUrl: boolean, readOnly: boolean, saveCredentials: boolean, folder?: string, nodePath?: string, host?: string, port?: string, serverName?: string, databaseName?: string, url?: string, properties?: any, providerProperties: any, requiredAuth?: string, features: Array, supportedDataFormats: Array, configurationType?: DriverConfigurationType, authNeeded: boolean, authModel?: string, canViewSettings: boolean, canEdit: boolean, canDelete: boolean, origin?: { type: string, subType?: string, displayName: string, icon?: string, details?: Array<{ id?: string, displayName?: string, description?: string, category?: string, dataType?: string, defaultValue?: any, validValues?: Array, value?: any, length: ObjectPropertyLength, features: Array, order: number }> }, authProperties?: Array<{ id?: string, displayName?: string, description?: string, category?: string, dataType?: string, value?: any, validValues?: Array, defaultValue?: any, length: ObjectPropertyLength, features: Array, order: number }>, networkHandlersConfig: Array<{ id: string, enabled: boolean, authType: NetworkHandlerAuthType, userName?: string, password?: string, key?: string, savePassword: boolean, properties?: any }>, navigatorSettings: { showSystemObjects: boolean, showUtilityObjects: boolean, showOnlyEntities: boolean, mergeEntities: boolean, hideFolders: boolean, hideSchemas: boolean, hideVirtualModel: boolean } } }; +export type InitConnectionMutation = { connection: { id: string, projectId: string, name: string, description?: string, driverId: string, template: boolean, connected: boolean, provided: boolean, useUrl: boolean, readOnly: boolean, saveCredentials: boolean, credentialsSaved?: boolean, sharedCredentials: boolean, folder?: string, nodePath?: string, host?: string, port?: string, serverName?: string, databaseName?: string, url?: string, properties?: any, providerProperties: any, requiredAuth?: string, features: Array, supportedDataFormats: Array, configurationType?: DriverConfigurationType, authNeeded?: boolean, authModel?: string, canViewSettings: boolean, canEdit: boolean, canDelete: boolean, origin?: { type: string, subType?: string, displayName: string, icon?: string, details?: Array<{ id?: string, displayName?: string, description?: string, category?: string, dataType?: string, defaultValue?: any, validValues?: Array, value?: any, length: ObjectPropertyLength, features: Array, order: number }> }, authProperties?: Array<{ id?: string, displayName?: string, description?: string, category?: string, dataType?: string, value?: any, validValues?: Array, defaultValue?: any, length: ObjectPropertyLength, features: Array, order: number }>, networkHandlersConfig: Array<{ id: string, enabled: boolean, authType: NetworkHandlerAuthType, userName?: string, password?: string, key?: string, savePassword: boolean, properties?: any }>, navigatorSettings: { showSystemObjects: boolean, showUtilityObjects: boolean, showOnlyEntities: boolean, mergeEntities: boolean, hideFolders: boolean, hideSchemas: boolean, hideVirtualModel: boolean } } }; export type RefreshSessionConnectionsMutationVariables = Exact<{ [key: string]: never; }>; @@ -2135,10 +2180,12 @@ export type SetConnectionNavigatorSettingsMutationVariables = Exact<{ customIncludeOriginDetails: Scalars['Boolean']; includeAuthProperties: Scalars['Boolean']; customIncludeNetworkHandlerCredentials: Scalars['Boolean']; + includeCredentialsSaved: Scalars['Boolean']; + includeAuthNeeded: Scalars['Boolean']; }>; -export type SetConnectionNavigatorSettingsMutation = { connection: { id: string, projectId: string, name: string, description?: string, driverId: string, template: boolean, connected: boolean, provided: boolean, useUrl: boolean, readOnly: boolean, saveCredentials: boolean, folder?: string, nodePath?: string, host?: string, port?: string, serverName?: string, databaseName?: string, url?: string, properties?: any, providerProperties: any, requiredAuth?: string, features: Array, supportedDataFormats: Array, configurationType?: DriverConfigurationType, authNeeded: boolean, authModel?: string, canViewSettings: boolean, canEdit: boolean, canDelete: boolean, origin?: { type: string, subType?: string, displayName: string, icon?: string, details?: Array<{ id?: string, displayName?: string, description?: string, category?: string, dataType?: string, defaultValue?: any, validValues?: Array, value?: any, length: ObjectPropertyLength, features: Array, order: number }> }, authProperties?: Array<{ id?: string, displayName?: string, description?: string, category?: string, dataType?: string, value?: any, validValues?: Array, defaultValue?: any, length: ObjectPropertyLength, features: Array, order: number }>, networkHandlersConfig: Array<{ id: string, enabled: boolean, authType: NetworkHandlerAuthType, userName?: string, password?: string, key?: string, savePassword: boolean, properties?: any }>, navigatorSettings: { showSystemObjects: boolean, showUtilityObjects: boolean, showOnlyEntities: boolean, mergeEntities: boolean, hideFolders: boolean, hideSchemas: boolean, hideVirtualModel: boolean } } }; +export type SetConnectionNavigatorSettingsMutation = { connection: { id: string, projectId: string, name: string, description?: string, driverId: string, template: boolean, connected: boolean, provided: boolean, useUrl: boolean, readOnly: boolean, saveCredentials: boolean, credentialsSaved?: boolean, sharedCredentials: boolean, folder?: string, nodePath?: string, host?: string, port?: string, serverName?: string, databaseName?: string, url?: string, properties?: any, providerProperties: any, requiredAuth?: string, features: Array, supportedDataFormats: Array, configurationType?: DriverConfigurationType, authNeeded?: boolean, authModel?: string, canViewSettings: boolean, canEdit: boolean, canDelete: boolean, origin?: { type: string, subType?: string, displayName: string, icon?: string, details?: Array<{ id?: string, displayName?: string, description?: string, category?: string, dataType?: string, defaultValue?: any, validValues?: Array, value?: any, length: ObjectPropertyLength, features: Array, order: number }> }, authProperties?: Array<{ id?: string, displayName?: string, description?: string, category?: string, dataType?: string, value?: any, validValues?: Array, defaultValue?: any, length: ObjectPropertyLength, features: Array, order: number }>, networkHandlersConfig: Array<{ id: string, enabled: boolean, authType: NetworkHandlerAuthType, userName?: string, password?: string, key?: string, savePassword: boolean, properties?: any }>, navigatorSettings: { showSystemObjects: boolean, showUtilityObjects: boolean, showOnlyEntities: boolean, mergeEntities: boolean, hideFolders: boolean, hideSchemas: boolean, hideVirtualModel: boolean } } }; export type TestConnectionMutationVariables = Exact<{ projectId: Scalars['ID']; @@ -2162,10 +2209,12 @@ export type UpdateConnectionMutationVariables = Exact<{ customIncludeOriginDetails: Scalars['Boolean']; includeAuthProperties: Scalars['Boolean']; customIncludeNetworkHandlerCredentials: Scalars['Boolean']; + includeCredentialsSaved: Scalars['Boolean']; + includeAuthNeeded: Scalars['Boolean']; }>; -export type UpdateConnectionMutation = { connection: { id: string, projectId: string, name: string, description?: string, driverId: string, template: boolean, connected: boolean, provided: boolean, useUrl: boolean, readOnly: boolean, saveCredentials: boolean, folder?: string, nodePath?: string, host?: string, port?: string, serverName?: string, databaseName?: string, url?: string, properties?: any, providerProperties: any, requiredAuth?: string, features: Array, supportedDataFormats: Array, configurationType?: DriverConfigurationType, authNeeded: boolean, authModel?: string, canViewSettings: boolean, canEdit: boolean, canDelete: boolean, origin?: { type: string, subType?: string, displayName: string, icon?: string, details?: Array<{ id?: string, displayName?: string, description?: string, category?: string, dataType?: string, defaultValue?: any, validValues?: Array, value?: any, length: ObjectPropertyLength, features: Array, order: number }> }, authProperties?: Array<{ id?: string, displayName?: string, description?: string, category?: string, dataType?: string, value?: any, validValues?: Array, defaultValue?: any, length: ObjectPropertyLength, features: Array, order: number }>, networkHandlersConfig: Array<{ id: string, enabled: boolean, authType: NetworkHandlerAuthType, userName?: string, password?: string, key?: string, savePassword: boolean, properties?: any }>, navigatorSettings: { showSystemObjects: boolean, showUtilityObjects: boolean, showOnlyEntities: boolean, mergeEntities: boolean, hideFolders: boolean, hideSchemas: boolean, hideVirtualModel: boolean } } }; +export type UpdateConnectionMutation = { connection: { id: string, projectId: string, name: string, description?: string, driverId: string, template: boolean, connected: boolean, provided: boolean, useUrl: boolean, readOnly: boolean, saveCredentials: boolean, credentialsSaved?: boolean, sharedCredentials: boolean, folder?: string, nodePath?: string, host?: string, port?: string, serverName?: string, databaseName?: string, url?: string, properties?: any, providerProperties: any, requiredAuth?: string, features: Array, supportedDataFormats: Array, configurationType?: DriverConfigurationType, authNeeded?: boolean, authModel?: string, canViewSettings: boolean, canEdit: boolean, canDelete: boolean, origin?: { type: string, subType?: string, displayName: string, icon?: string, details?: Array<{ id?: string, displayName?: string, description?: string, category?: string, dataType?: string, defaultValue?: any, validValues?: Array, value?: any, length: ObjectPropertyLength, features: Array, order: number }> }, authProperties?: Array<{ id?: string, displayName?: string, description?: string, category?: string, dataType?: string, value?: any, validValues?: Array, defaultValue?: any, length: ObjectPropertyLength, features: Array, order: number }>, networkHandlersConfig: Array<{ id: string, enabled: boolean, authType: NetworkHandlerAuthType, userName?: string, password?: string, key?: string, savePassword: boolean, properties?: any }>, navigatorSettings: { showSystemObjects: boolean, showUtilityObjects: boolean, showOnlyEntities: boolean, mergeEntities: boolean, hideFolders: boolean, hideSchemas: boolean, hideVirtualModel: boolean } } }; export type ExportDataFromContainerQueryVariables = Exact<{ projectId: Scalars['ID']; @@ -2219,7 +2268,7 @@ export type AdminObjectGrantInfoFragment = { subjectId: string, subjectType: Adm export type AdminPermissionInfoFragment = { id: string, label?: string, description?: string, category?: string }; -export type AdminTeamInfoFragment = { teamId: string, teamName?: string, description?: string, teamPermissions: Array }; +export type AdminTeamInfoFragment = { teamId: string, teamName?: string, description?: string, teamPermissions: Array, metaParameters?: any }; export type AdminUserInfoFragment = { userId: string, grantedTeams: Array, linkedAuthProviders: Array, metaParameters?: any, enabled: boolean, authRole?: string, origins: Array<{ type: string, subType?: string, displayName: string, icon?: string, details?: Array<{ id?: string, displayName?: string, description?: string, category?: string, dataType?: string, defaultValue?: any, validValues?: Array, value?: any, length: ObjectPropertyLength, features: Array, order: number }> }> }; @@ -2237,7 +2286,7 @@ export type AuthTokenFragment = { authProvider: string, authConfiguration?: stri export type ConnectionFolderInfoFragment = { id: string, projectId: string, description?: string }; -export type DatabaseConnectionFragment = { id: string, projectId: string, name: string, description?: string, driverId: string, template: boolean, connected: boolean, provided: boolean, useUrl: boolean, readOnly: boolean, saveCredentials: boolean, folder?: string, nodePath?: string, host?: string, port?: string, serverName?: string, databaseName?: string, url?: string, properties?: any, providerProperties: any, requiredAuth?: string, features: Array, supportedDataFormats: Array, configurationType?: DriverConfigurationType, authNeeded: boolean, authModel?: string, canViewSettings: boolean, canEdit: boolean, canDelete: boolean, origin?: { type: string, subType?: string, displayName: string, icon?: string, details?: Array<{ id?: string, displayName?: string, description?: string, category?: string, dataType?: string, defaultValue?: any, validValues?: Array, value?: any, length: ObjectPropertyLength, features: Array, order: number }> }, authProperties?: Array<{ id?: string, displayName?: string, description?: string, category?: string, dataType?: string, value?: any, validValues?: Array, defaultValue?: any, length: ObjectPropertyLength, features: Array, order: number }>, networkHandlersConfig: Array<{ id: string, enabled: boolean, authType: NetworkHandlerAuthType, userName?: string, password?: string, key?: string, savePassword: boolean, properties?: any }>, navigatorSettings: { showSystemObjects: boolean, showUtilityObjects: boolean, showOnlyEntities: boolean, mergeEntities: boolean, hideFolders: boolean, hideSchemas: boolean, hideVirtualModel: boolean } }; +export type DatabaseConnectionFragment = { id: string, projectId: string, name: string, description?: string, driverId: string, template: boolean, connected: boolean, provided: boolean, useUrl: boolean, readOnly: boolean, saveCredentials: boolean, credentialsSaved?: boolean, sharedCredentials: boolean, folder?: string, nodePath?: string, host?: string, port?: string, serverName?: string, databaseName?: string, url?: string, properties?: any, providerProperties: any, requiredAuth?: string, features: Array, supportedDataFormats: Array, configurationType?: DriverConfigurationType, authNeeded?: boolean, authModel?: string, canViewSettings: boolean, canEdit: boolean, canDelete: boolean, origin?: { type: string, subType?: string, displayName: string, icon?: string, details?: Array<{ id?: string, displayName?: string, description?: string, category?: string, dataType?: string, defaultValue?: any, validValues?: Array, value?: any, length: ObjectPropertyLength, features: Array, order: number }> }, authProperties?: Array<{ id?: string, displayName?: string, description?: string, category?: string, dataType?: string, value?: any, validValues?: Array, defaultValue?: any, length: ObjectPropertyLength, features: Array, order: number }>, networkHandlersConfig: Array<{ id: string, enabled: boolean, authType: NetworkHandlerAuthType, userName?: string, password?: string, key?: string, savePassword: boolean, properties?: any }>, navigatorSettings: { showSystemObjects: boolean, showUtilityObjects: boolean, showOnlyEntities: boolean, mergeEntities: boolean, hideFolders: boolean, hideSchemas: boolean, hideVirtualModel: boolean } }; export type DatabaseDriverFragment = { id: string, name?: string, icon?: string, description?: string, defaultPort?: string, defaultDatabase?: string, defaultServer?: string, defaultUser?: string, sampleURL?: string, embedded?: boolean, enabled: boolean, requiresServerName?: boolean, anonymousAccess?: boolean, promotedScore?: number, defaultAuthModel: string, applicableAuthModels: Array, applicableNetworkHandlers: Array, configurationTypes: Array, driverParameters?: any, providerProperties?: Array<{ id?: string, displayName?: string, description?: string, category?: string, dataType?: string, defaultValue?: any, validValues?: Array, length: ObjectPropertyLength, features: Array, order: number }>, driverProperties?: Array<{ id?: string, displayName?: string, description?: string, category?: string, dataType?: string, defaultValue?: any, validValues?: Array }> }; @@ -2251,6 +2300,8 @@ export type NavNodePropertiesFragment = { id?: string, category?: string, dataTy export type ObjectOriginInfoFragment = { type: string, subType?: string, displayName: string, icon?: string, details?: Array<{ id?: string, displayName?: string, description?: string, category?: string, dataType?: string, defaultValue?: any, validValues?: Array, value?: any, length: ObjectPropertyLength, features: Array, order: number }> }; +export type ObjectPropertyInfoFragment = { id?: string, displayName?: string, description?: string, category?: string, dataType?: string, value?: any, validValues?: Array, defaultValue?: any, length: ObjectPropertyLength, features: Array, order: number }; + export type SqlScriptInfoFragment = { queries: Array<{ start: number, end: number }> }; export type SessionStateFragment = { createTime: string, lastAccessTime: string, cacheExpired: boolean, locale: string, actionParameters?: any, valid: boolean, remainingTime: number }; @@ -2748,6 +2799,7 @@ export const AdminTeamInfoFragmentDoc = ` teamName description teamPermissions + metaParameters @include(if: $includeMetaParameters) } `; export const ObjectOriginInfoFragmentDoc = ` @@ -2912,6 +2964,8 @@ export const DatabaseConnectionFragmentDoc = ` useUrl readOnly saveCredentials + credentialsSaved @include(if: $includeCredentialsSaved) + sharedCredentials folder nodePath host @@ -2928,7 +2982,7 @@ export const DatabaseConnectionFragmentDoc = ` origin @include(if: $includeOrigin) { ...ObjectOriginInfo } - authNeeded + authNeeded @include(if: $includeAuthNeeded) authModel authProperties @include(if: $includeAuthProperties) { ...UserConnectionAuthProperties @@ -3051,6 +3105,21 @@ export const NavNodeInfoFragmentDoc = ` } } ${NavNodePropertiesFragmentDoc}`; +export const ObjectPropertyInfoFragmentDoc = ` + fragment ObjectPropertyInfo on ObjectPropertyInfo { + id + displayName + description + category + dataType + value + validValues + defaultValue + length + features + order +} + `; export const SqlScriptInfoFragmentDoc = ` fragment SQLScriptInfo on SQLScriptInfo { queries { @@ -3249,7 +3318,7 @@ export const SaveUserMetaParametersDocument = ` } `; export const CreateTeamDocument = ` - query createTeam($teamId: ID!, $teamName: String, $description: String) { + query createTeam($teamId: ID!, $teamName: String, $description: String, $includeMetaParameters: Boolean!) { team: createTeam( teamId: $teamId teamName: $teamName @@ -3271,15 +3340,27 @@ export const GetTeamGrantedUsersDocument = ` } } `; +export const GetTeamMetaParametersDocument = ` + query getTeamMetaParameters { + parameters: listTeamMetaParameters { + ...ObjectPropertyInfo + } +} + ${ObjectPropertyInfoFragmentDoc}`; export const GetTeamsListDocument = ` - query getTeamsList($teamId: ID) { + query getTeamsList($teamId: ID, $includeMetaParameters: Boolean!) { teams: listTeams(teamId: $teamId) { ...AdminTeamInfo } } ${AdminTeamInfoFragmentDoc}`; +export const SaveTeamMetaParametersDocument = ` + query saveTeamMetaParameters($teamId: ID!, $parameters: Object!) { + setTeamMetaParameterValues(teamId: $teamId, parameters: $parameters) +} + `; export const UpdateTeamDocument = ` - query updateTeam($teamId: ID!, $teamName: String, $description: String) { + query updateTeam($teamId: ID!, $teamName: String, $description: String, $includeMetaParameters: Boolean!) { team: updateTeam( teamId: $teamId teamName: $teamName @@ -3431,14 +3512,14 @@ export const SetSubjectConnectionAccessDocument = ` } `; export const CloseConnectionDocument = ` - mutation closeConnection($projectId: ID!, $connectionId: ID!, $includeOrigin: Boolean!, $customIncludeOriginDetails: Boolean!, $includeAuthProperties: Boolean!, $customIncludeNetworkHandlerCredentials: Boolean!) { + mutation closeConnection($projectId: ID!, $connectionId: ID!, $includeOrigin: Boolean!, $customIncludeOriginDetails: Boolean!, $includeAuthProperties: Boolean!, $customIncludeNetworkHandlerCredentials: Boolean!, $includeCredentialsSaved: Boolean!, $includeAuthNeeded: Boolean!) { connection: closeConnection(projectId: $projectId, id: $connectionId) { ...DatabaseConnection } } ${DatabaseConnectionFragmentDoc}`; export const CreateConnectionDocument = ` - mutation createConnection($projectId: ID!, $config: ConnectionConfig!, $includeOrigin: Boolean!, $customIncludeOriginDetails: Boolean!, $includeAuthProperties: Boolean!, $customIncludeNetworkHandlerCredentials: Boolean!) { + mutation createConnection($projectId: ID!, $config: ConnectionConfig!, $includeOrigin: Boolean!, $customIncludeOriginDetails: Boolean!, $includeAuthProperties: Boolean!, $customIncludeNetworkHandlerCredentials: Boolean!, $includeCredentialsSaved: Boolean!, $includeAuthNeeded: Boolean!) { connection: createConnection(projectId: $projectId, config: $config) { ...DatabaseConnection } @@ -3456,7 +3537,7 @@ export const CreateConnectionFolderDocument = ` } ${ConnectionFolderInfoFragmentDoc}`; export const CreateConnectionFromNodeDocument = ` - mutation createConnectionFromNode($projectId: ID!, $nodePath: String!, $config: ConnectionConfig, $includeOrigin: Boolean!, $customIncludeOriginDetails: Boolean!, $includeAuthProperties: Boolean!, $customIncludeNetworkHandlerCredentials: Boolean!) { + mutation createConnectionFromNode($projectId: ID!, $nodePath: String!, $config: ConnectionConfig, $includeOrigin: Boolean!, $customIncludeOriginDetails: Boolean!, $includeAuthProperties: Boolean!, $customIncludeNetworkHandlerCredentials: Boolean!, $includeCredentialsSaved: Boolean!, $includeAuthNeeded: Boolean!) { connection: copyConnectionFromNode( projectId: $projectId nodePath: $nodePath @@ -3467,7 +3548,7 @@ export const CreateConnectionFromNodeDocument = ` } ${DatabaseConnectionFragmentDoc}`; export const CreateConnectionFromTemplateDocument = ` - mutation createConnectionFromTemplate($projectId: ID!, $templateId: ID!, $connectionName: String!, $includeOrigin: Boolean!, $customIncludeOriginDetails: Boolean!, $includeAuthProperties: Boolean!, $customIncludeNetworkHandlerCredentials: Boolean!) { + mutation createConnectionFromTemplate($projectId: ID!, $templateId: ID!, $connectionName: String!, $includeOrigin: Boolean!, $customIncludeOriginDetails: Boolean!, $includeAuthProperties: Boolean!, $customIncludeNetworkHandlerCredentials: Boolean!, $includeCredentialsSaved: Boolean!, $includeAuthNeeded: Boolean!) { connection: createConnectionFromTemplate( projectId: $projectId templateId: $templateId @@ -3569,27 +3650,28 @@ export const GetConnectionFoldersDocument = ` } ${ConnectionFolderInfoFragmentDoc}`; export const GetTemplateConnectionsDocument = ` - query getTemplateConnections($projectId: ID, $includeOrigin: Boolean!, $customIncludeOriginDetails: Boolean!, $includeAuthProperties: Boolean!, $customIncludeNetworkHandlerCredentials: Boolean!) { + query getTemplateConnections($projectId: ID, $includeOrigin: Boolean!, $customIncludeOriginDetails: Boolean!, $includeAuthProperties: Boolean!, $customIncludeNetworkHandlerCredentials: Boolean!, $includeCredentialsSaved: Boolean!, $includeAuthNeeded: Boolean!) { connections: templateConnections(projectId: $projectId) { ...DatabaseConnection } } ${DatabaseConnectionFragmentDoc}`; export const GetUserConnectionsDocument = ` - query getUserConnections($projectId: ID, $connectionId: ID, $includeOrigin: Boolean!, $customIncludeOriginDetails: Boolean!, $includeAuthProperties: Boolean!, $customIncludeNetworkHandlerCredentials: Boolean!) { + query getUserConnections($projectId: ID, $connectionId: ID, $includeOrigin: Boolean!, $customIncludeOriginDetails: Boolean!, $includeAuthProperties: Boolean!, $customIncludeNetworkHandlerCredentials: Boolean!, $includeCredentialsSaved: Boolean!, $includeAuthNeeded: Boolean!) { connections: userConnections(projectId: $projectId, id: $connectionId) { ...DatabaseConnection } } ${DatabaseConnectionFragmentDoc}`; export const InitConnectionDocument = ` - mutation initConnection($projectId: ID!, $connectionId: ID!, $credentials: Object, $networkCredentials: [NetworkHandlerConfigInput!], $saveCredentials: Boolean, $includeOrigin: Boolean!, $customIncludeOriginDetails: Boolean!, $includeAuthProperties: Boolean!, $customIncludeNetworkHandlerCredentials: Boolean!) { + mutation initConnection($projectId: ID!, $connectionId: ID!, $credentials: Object, $networkCredentials: [NetworkHandlerConfigInput!], $saveCredentials: Boolean, $sharedCredentials: Boolean, $includeOrigin: Boolean!, $customIncludeOriginDetails: Boolean!, $includeAuthProperties: Boolean!, $customIncludeNetworkHandlerCredentials: Boolean!, $includeCredentialsSaved: Boolean!, $includeAuthNeeded: Boolean!) { connection: initConnection( projectId: $projectId id: $connectionId credentials: $credentials networkCredentials: $networkCredentials saveCredentials: $saveCredentials + sharedCredentials: $sharedCredentials ) { ...DatabaseConnection } @@ -3601,7 +3683,7 @@ export const RefreshSessionConnectionsDocument = ` } `; export const SetConnectionNavigatorSettingsDocument = ` - mutation setConnectionNavigatorSettings($projectId: ID!, $connectionId: ID!, $settings: NavigatorSettingsInput!, $includeOrigin: Boolean!, $customIncludeOriginDetails: Boolean!, $includeAuthProperties: Boolean!, $customIncludeNetworkHandlerCredentials: Boolean!) { + mutation setConnectionNavigatorSettings($projectId: ID!, $connectionId: ID!, $settings: NavigatorSettingsInput!, $includeOrigin: Boolean!, $customIncludeOriginDetails: Boolean!, $includeAuthProperties: Boolean!, $customIncludeNetworkHandlerCredentials: Boolean!, $includeCredentialsSaved: Boolean!, $includeAuthNeeded: Boolean!) { connection: setConnectionNavigatorSettings( projectId: $projectId id: $connectionId @@ -3636,7 +3718,7 @@ export const TestNetworkHandlerDocument = ` } `; export const UpdateConnectionDocument = ` - mutation updateConnection($projectId: ID!, $config: ConnectionConfig!, $includeOrigin: Boolean!, $customIncludeOriginDetails: Boolean!, $includeAuthProperties: Boolean!, $customIncludeNetworkHandlerCredentials: Boolean!) { + mutation updateConnection($projectId: ID!, $config: ConnectionConfig!, $includeOrigin: Boolean!, $customIncludeOriginDetails: Boolean!, $includeAuthProperties: Boolean!, $customIncludeNetworkHandlerCredentials: Boolean!, $includeCredentialsSaved: Boolean!, $includeAuthNeeded: Boolean!) { connection: updateConnection(projectId: $projectId, config: $config) { ...DatabaseConnection } @@ -4441,9 +4523,15 @@ export function getSdk(client: GraphQLClient, withWrapper: SdkFunctionWrapper = getTeamGrantedUsers(variables: GetTeamGrantedUsersQueryVariables, requestHeaders?: Dom.RequestInit["headers"]): Promise { return withWrapper((wrappedRequestHeaders) => client.request(GetTeamGrantedUsersDocument, variables, {...requestHeaders, ...wrappedRequestHeaders}), 'getTeamGrantedUsers', 'query'); }, - getTeamsList(variables?: GetTeamsListQueryVariables, requestHeaders?: Dom.RequestInit["headers"]): Promise { + getTeamMetaParameters(variables?: GetTeamMetaParametersQueryVariables, requestHeaders?: Dom.RequestInit["headers"]): Promise { + return withWrapper((wrappedRequestHeaders) => client.request(GetTeamMetaParametersDocument, variables, {...requestHeaders, ...wrappedRequestHeaders}), 'getTeamMetaParameters', 'query'); + }, + getTeamsList(variables: GetTeamsListQueryVariables, requestHeaders?: Dom.RequestInit["headers"]): Promise { return withWrapper((wrappedRequestHeaders) => client.request(GetTeamsListDocument, variables, {...requestHeaders, ...wrappedRequestHeaders}), 'getTeamsList', 'query'); }, + saveTeamMetaParameters(variables: SaveTeamMetaParametersQueryVariables, requestHeaders?: Dom.RequestInit["headers"]): Promise { + return withWrapper((wrappedRequestHeaders) => client.request(SaveTeamMetaParametersDocument, variables, {...requestHeaders, ...wrappedRequestHeaders}), 'saveTeamMetaParameters', 'query'); + }, updateTeam(variables: UpdateTeamQueryVariables, requestHeaders?: Dom.RequestInit["headers"]): Promise { return withWrapper((wrappedRequestHeaders) => client.request(UpdateTeamDocument, variables, {...requestHeaders, ...wrappedRequestHeaders}), 'updateTeam', 'query'); }, diff --git a/webapp/packages/plugin-authentication-administration/src/Administration/Users/Teams/Contexts/teamContext.ts b/webapp/packages/plugin-authentication-administration/src/Administration/Users/Teams/Contexts/teamContext.ts index f5648ed9f6..48c269653d 100644 --- a/webapp/packages/plugin-authentication-administration/src/Administration/Users/Teams/Contexts/teamContext.ts +++ b/webapp/packages/plugin-authentication-administration/src/Administration/Users/Teams/Contexts/teamContext.ts @@ -12,5 +12,6 @@ export function teamContext(): TeamInfo { return { teamId: '', teamPermissions: [], + metaParameters: {}, }; } diff --git a/webapp/packages/plugin-authentication-administration/src/Administration/Users/Teams/ITeamFormProps.ts b/webapp/packages/plugin-authentication-administration/src/Administration/Users/Teams/ITeamFormProps.ts index 291a5d2f96..4a0cd269ad 100644 --- a/webapp/packages/plugin-authentication-administration/src/Administration/Users/Teams/ITeamFormProps.ts +++ b/webapp/packages/plugin-authentication-administration/src/Administration/Users/Teams/ITeamFormProps.ts @@ -6,9 +6,8 @@ * you may not use this file except in compliance with the License. */ -import type { TeamInfo } from '@cloudbeaver/core-authentication'; +import type { TeamInfo, TeamsResource } from '@cloudbeaver/core-authentication'; import type { IExecutorHandlersCollection } from '@cloudbeaver/core-executor'; -import type { CachedMapResource } from '@cloudbeaver/core-sdk'; import type { MetadataMap } from '@cloudbeaver/core-utils'; export type TeamFormMode = 'edit' | 'create'; @@ -25,7 +24,7 @@ export interface ITeamFormState { readonly loading: boolean; readonly submittingTask: IExecutorHandlersCollection; - readonly resource: CachedMapResource; + readonly resource: TeamsResource; readonly load: () => Promise; readonly loadTeamInfo: () => Promise; diff --git a/webapp/packages/plugin-authentication-administration/src/Administration/Users/Teams/Options/TeamOptions.tsx b/webapp/packages/plugin-authentication-administration/src/Administration/Users/Teams/Options/TeamOptions.tsx index ee8ac23060..419fa8a9f8 100644 --- a/webapp/packages/plugin-authentication-administration/src/Administration/Users/Teams/Options/TeamOptions.tsx +++ b/webapp/packages/plugin-authentication-administration/src/Administration/Users/Teams/Options/TeamOptions.tsx @@ -10,7 +10,8 @@ import { observer } from 'mobx-react-lite'; import { useRef } from 'react'; import styled, { css } from 'reshadow'; -import { BASE_CONTAINERS_STYLES, ColoredContainer, Group, InputField, SubmittingForm, Textarea, useTranslate, useStyles, useDataResource } from '@cloudbeaver/core-blocks'; +import { TeamMetaParametersResource } from '@cloudbeaver/core-authentication'; +import { BASE_CONTAINERS_STYLES, ColoredContainer, Group, InputField, SubmittingForm, Textarea, useTranslate, useStyles, useDataResource, Loader, GroupTitle, ObjectPropertyInfoForm } from '@cloudbeaver/core-blocks'; import { ServerConfigResource } from '@cloudbeaver/core-root'; import type { TabContainerPanelComponent } from '@cloudbeaver/core-ui'; @@ -31,6 +32,7 @@ export const TeamOptions: TabContainerPanelComponent = observer( const translate = useTranslate(); const serverConfigResource = useDataResource(TeamOptions, ServerConfigResource, undefined); + const teamMetaParameters = useDataResource(TeamOptions, TeamMetaParametersResource, undefined); const style = useStyles(BASE_CONTAINERS_STYLES, styles); const edit = state.mode === 'edit'; @@ -72,6 +74,20 @@ export const TeamOptions: TabContainerPanelComponent = observer( {!serverConfigResource.data?.distributed && } + + {() => teamMetaParameters.data.length > 0 && styled(style)( + + {translate('authentication_team_meta_parameters')} + + + )} + ); diff --git a/webapp/packages/plugin-authentication-administration/src/Administration/Users/Teams/Options/TeamOptionsTabService.ts b/webapp/packages/plugin-authentication-administration/src/Administration/Users/Teams/Options/TeamOptionsTabService.ts index c6614172f9..8888bb8fa6 100644 --- a/webapp/packages/plugin-authentication-administration/src/Administration/Users/Teams/Options/TeamOptionsTabService.ts +++ b/webapp/packages/plugin-authentication-administration/src/Administration/Users/Teams/Options/TeamOptionsTabService.ts @@ -73,6 +73,10 @@ export class TeamOptionsTabService extends Bootstrap { config.description = state.config.description; } + if (state.config.metaParameters) { + config.metaParameters = state.config.metaParameters; + } + config.teamPermissions = [...state.config.teamPermissions]; } @@ -115,6 +119,7 @@ export class TeamOptionsTabService extends Bootstrap { status.info(team.teamId); } else { const team = await this.teamResource.updateTeam(config); + status.info('administration_teams_team_info_updated'); status.info(team.teamId); } @@ -142,12 +147,19 @@ export class TeamOptionsTabService extends Bootstrap { if (state.info.teamId) { state.config.teamId = state.info.teamId; } + if (state.info.teamName) { state.config.teamName = state.info.teamName; } + if (state.info.description) { state.config.description = state.info.description; } + + if (state.info.metaParameters) { + state.config.metaParameters = state.info.metaParameters; + } + state.config.teamPermissions = [...state.info.teamPermissions]; } } diff --git a/webapp/packages/plugin-authentication-administration/src/Administration/Users/Teams/TeamFormState.ts b/webapp/packages/plugin-authentication-administration/src/Administration/Users/Teams/TeamFormState.ts index 5caff777aa..234b4efda1 100644 --- a/webapp/packages/plugin-authentication-administration/src/Administration/Users/Teams/TeamFormState.ts +++ b/webapp/packages/plugin-authentication-administration/src/Administration/Users/Teams/TeamFormState.ts @@ -8,9 +8,8 @@ import { computed, makeObservable, observable } from 'mobx'; -import type { TeamInfo } from '@cloudbeaver/core-authentication'; +import type { TeamInfo, TeamsResource } from '@cloudbeaver/core-authentication'; import { Executor, IExecutionContextProvider, IExecutor } from '@cloudbeaver/core-executor'; -import type { CachedMapResource } from '@cloudbeaver/core-sdk'; import { MetadataMap } from '@cloudbeaver/core-utils'; import { teamFormConfigureContext } from './Contexts/teamFormConfigureContext'; @@ -44,7 +43,7 @@ export class TeamFormState implements ITeamFormState { return false; } - readonly resource: CachedMapResource; + readonly resource: TeamsResource; readonly service: TeamFormService; readonly submittingTask: IExecutor; @@ -55,12 +54,13 @@ export class TeamFormState implements ITeamFormState { constructor( service: TeamFormService, - resource: CachedMapResource + resource: TeamsResource ) { this.resource = resource; this.config = { teamId: '', teamPermissions: [], + metaParameters: {}, }; this.stateInfo = null; @@ -156,6 +156,6 @@ export class TeamFormState implements ITeamFormState { return; } - await this.resource.load(data.config.teamId); + await this.resource.load(data.config.teamId, ['includeMetaParameters']); } } diff --git a/webapp/packages/plugin-authentication-administration/src/Administration/Users/Teams/TeamsTable/TeamEdit.tsx b/webapp/packages/plugin-authentication-administration/src/Administration/Users/Teams/TeamsTable/TeamEdit.tsx index b07650a3fa..8155d57dac 100644 --- a/webapp/packages/plugin-authentication-administration/src/Administration/Users/Teams/TeamsTable/TeamEdit.tsx +++ b/webapp/packages/plugin-authentication-administration/src/Administration/Users/Teams/TeamsTable/TeamEdit.tsx @@ -59,7 +59,7 @@ export const TeamEdit = observer(function TeamEdit({ data.config.teamId = item; return styled(useStyles(styles))( - + , + resource: TeamsResource, configure?: (state: ITeamFormState) => any ): ITeamFormState { const service = useService(TeamFormService); diff --git a/webapp/packages/plugin-authentication/src/locales/en.ts b/webapp/packages/plugin-authentication/src/locales/en.ts index af8b302370..0b7cc179f0 100644 --- a/webapp/packages/plugin-authentication/src/locales/en.ts +++ b/webapp/packages/plugin-authentication/src/locales/en.ts @@ -16,6 +16,7 @@ export default [ ['authentication_user_role', 'Role'], ['authentication_user_credentials', 'Credentials'], ['authentication_user_meta_parameters', 'Parameters'], + ['authentication_team_meta_parameters', 'Parameters'], ['authentication_user_password', 'User password'], ['authentication_user_password_repeat', 'Repeat password'], ['authentication_user_team', 'User team'], diff --git a/webapp/packages/plugin-authentication/src/locales/it.ts b/webapp/packages/plugin-authentication/src/locales/it.ts index 03f7e1ba26..f60e06745e 100644 --- a/webapp/packages/plugin-authentication/src/locales/it.ts +++ b/webapp/packages/plugin-authentication/src/locales/it.ts @@ -10,6 +10,7 @@ export default [ ['authentication_user_role', 'Role'], ['authentication_user_credentials', 'Credenziali'], ['authentication_user_meta_parameters', 'Parameters'], + ['authentication_team_meta_parameters', 'Parameters'], ['authentication_user_password', 'Password utente'], ['authentication_user_password_repeat', 'Ripeti password'], ['authentication_user_status', 'User status'], diff --git a/webapp/packages/plugin-authentication/src/locales/ru.ts b/webapp/packages/plugin-authentication/src/locales/ru.ts index 744f305656..e2269f862b 100644 --- a/webapp/packages/plugin-authentication/src/locales/ru.ts +++ b/webapp/packages/plugin-authentication/src/locales/ru.ts @@ -16,6 +16,7 @@ export default [ ['authentication_user_role', 'Роль'], ['authentication_user_credentials', 'Учетные данные'], ['authentication_user_meta_parameters', 'Параметры'], + ['authentication_team_meta_parameters', 'Параметры'], ['authentication_user_password', 'Пароль'], ['authentication_user_password_repeat', 'Повторите пароль'], ['authentication_user_team', 'Команда'], diff --git a/webapp/packages/plugin-authentication/src/locales/zh.ts b/webapp/packages/plugin-authentication/src/locales/zh.ts index 9a00a5c34a..d6e29002ef 100644 --- a/webapp/packages/plugin-authentication/src/locales/zh.ts +++ b/webapp/packages/plugin-authentication/src/locales/zh.ts @@ -16,6 +16,7 @@ export default [ ['authentication_user_role', 'Role'], ['authentication_user_credentials', '凭据'], ['authentication_user_meta_parameters', '参数'], + ['authentication_team_meta_parameters', '参数'], ['authentication_user_password', '用户密码'], ['authentication_user_password_repeat', '重复密码'], ['authentication_user_status', 'User status'], diff --git a/webapp/packages/plugin-connection-template/src/TemplateConnectionsResource.ts b/webapp/packages/plugin-connection-template/src/TemplateConnectionsResource.ts index d10945afa8..072d540cd1 100644 --- a/webapp/packages/plugin-connection-template/src/TemplateConnectionsResource.ts +++ b/webapp/packages/plugin-connection-template/src/TemplateConnectionsResource.ts @@ -37,6 +37,8 @@ export class TemplateConnectionsResource extends CachedDataResource handler.enabled && !handler.savePassword) diff --git a/webapp/packages/plugin-connections/src/ConnectionForm/Options/ConnectionOptionsTabService.ts b/webapp/packages/plugin-connections/src/ConnectionForm/Options/ConnectionOptionsTabService.ts index e78065de6a..39cc47b293 100644 --- a/webapp/packages/plugin-connections/src/ConnectionForm/Options/ConnectionOptionsTabService.ts +++ b/webapp/packages/plugin-connections/src/ConnectionForm/Options/ConnectionOptionsTabService.ts @@ -216,7 +216,8 @@ export class ConnectionOptionsTabService extends Bootstrap { state.config.authModelId = state.info.authModel; - state.config.saveCredentials = state.info.saveCredentials; + state.config.saveCredentials = state.info.credentialsSaved; + state.config.sharedCredentials = state.info.sharedCredentials; if (state.info.authProperties) { for (const property of state.info.authProperties) { @@ -234,7 +235,7 @@ export class ConnectionOptionsTabService extends Bootstrap { private configure(data: IConnectionFormState, contexts: IExecutionContextProvider) { const configuration = contexts.getContext(connectionFormConfigureContext); - configuration.include('includeAuthProperties'); + configuration.include('includeAuthProperties', 'includeCredentialsSaved'); } private async prepareConfig( @@ -293,6 +294,7 @@ export class ConnectionOptionsTabService extends Bootstrap { if ((state.config.authModelId || driver.defaultAuthModel) && !driver.anonymousAccess) { tempConfig.authModelId = state.config.authModelId || driver.defaultAuthModel; tempConfig.saveCredentials = state.config.saveCredentials; + tempConfig.sharedCredentials = state.config.sharedCredentials; const properties = await this.getConnectionAuthModelProperties(tempConfig.authModelId, state.info); @@ -377,7 +379,8 @@ export class ConnectionOptionsTabService extends Bootstrap { || (config.databaseName !== undefined && !isValuesEqual(config.databaseName, data.info.databaseName, '')) || config.credentials !== undefined || (config.authModelId !== undefined && !isValuesEqual(config.authModelId, data.info.authModel, '')) - || (config.saveCredentials !== undefined && config.saveCredentials !== data.info.saveCredentials) + || (config.saveCredentials !== undefined && config.saveCredentials !== data.info.credentialsSaved) + || (config.sharedCredentials !== undefined && config.sharedCredentials !== data.info.sharedCredentials) || ( config.providerProperties !== undefined && !isObjectPropertyInfoStateEqual( diff --git a/webapp/packages/plugin-connections/src/ConnectionForm/Options/Options.tsx b/webapp/packages/plugin-connections/src/ConnectionForm/Options/Options.tsx index 02129dcfc8..7b55c08e2c 100644 --- a/webapp/packages/plugin-connections/src/ConnectionForm/Options/Options.tsx +++ b/webapp/packages/plugin-connections/src/ConnectionForm/Options/Options.tsx @@ -32,9 +32,11 @@ import { FormFieldDescription, useTranslate, usePermission, + useDataResource, } from '@cloudbeaver/core-blocks'; import { DatabaseAuthModelsResource, DBDriverResource, isLocalConnection } from '@cloudbeaver/core-connections'; import { useService } from '@cloudbeaver/core-di'; +import { ServerConfigResource } from '@cloudbeaver/core-root'; import { CachedMapEmptyKey, DriverConfigurationType, resourceKeyList } from '@cloudbeaver/core-sdk'; import type { TabContainerPanelComponent } from '@cloudbeaver/core-ui'; import { useAuthenticationAction } from '@cloudbeaver/core-ui'; @@ -74,6 +76,7 @@ const driverConfiguration: IDriverConfiguration[] = [ export const Options: TabContainerPanelComponent = observer(function Options({ state, }) { + const serverConfigResource = useDataResource(Options, ServerConfigResource, undefined); const connectionOptionsTabService = useService(ConnectionOptionsTabService); const service = useService(ConnectionFormService); const formRef = useRef(null); @@ -140,6 +143,16 @@ export const Options: TabContainerPanelComponent = observe if (config.template) { config.folder = undefined; } + + if (name === 'sharedCredentials' && value) { + config.saveCredentials = true; + + for (const handler of config.networkHandlersConfig ?? []) { + if (!handler.savePassword) { + handler.savePassword = true; + } + } + } } const { data: applicableAuthModels } = useMapResource( @@ -378,14 +391,29 @@ export const Options: TabContainerPanelComponent = observe /> {credentialsSavingEnabled && ( - - {translate('connections_connection_edit_save_credentials')} - + + + {translate('connections_connection_edit_save_credentials')} + + {serverConfigResource.data?.distributed && connectionOptionsTabService.isProjectShared(state) && ( + + {translate('connections_connection_share_credentials')} + + )} + )} )} diff --git a/webapp/packages/plugin-connections/src/ConnectionForm/SSH/SSH.tsx b/webapp/packages/plugin-connections/src/ConnectionForm/SSH/SSH.tsx index b908384ff1..fe15c62bb0 100644 --- a/webapp/packages/plugin-connections/src/ConnectionForm/SSH/SSH.tsx +++ b/webapp/packages/plugin-connections/src/ConnectionForm/SSH/SSH.tsx @@ -216,7 +216,7 @@ export const SSH: TabContainerPanelComponent = observer(function SSH({ id={SSH_TUNNEL_ID + ' savePassword'} name="savePassword" state={handlerState} - disabled={disabled || !enabled || readonly} + disabled={disabled || !enabled || readonly || formState.config.sharedCredentials} > {translate('connections_connection_edit_save_credentials')} diff --git a/webapp/packages/plugin-connections/src/DatabaseAuthDialog/DBAuthDialogController.ts b/webapp/packages/plugin-connections/src/DatabaseAuthDialog/DBAuthDialogController.ts index 4172ae2eee..44f4031745 100644 --- a/webapp/packages/plugin-connections/src/DatabaseAuthDialog/DBAuthDialogController.ts +++ b/webapp/packages/plugin-connections/src/DatabaseAuthDialog/DBAuthDialogController.ts @@ -107,7 +107,9 @@ export class DBAuthDialogController implements IInitializableController, IDestru private async loadAuthModel() { try { - const connection = await this.connectionInfoResource.load(this.connectionKey, ['includeAuthProperties', 'customIncludeNetworkHandlerCredentials']); + const connection = await this.connectionInfoResource.load(this.connectionKey, [ + 'includeAuthProperties', 'customIncludeNetworkHandlerCredentials', 'includeAuthNeeded', + ]); if (connection.authNeeded) { const property = connection.authProperties.find(property => property.id === USER_NAME_PROPERTY_ID);