diff --git a/README.md b/README.md index 1de038c49b..3e42e01cbb 100644 --- a/README.md +++ b/README.md @@ -22,6 +22,12 @@ You can see live demo of CloudBeaver here: https://demo.cloudbeaver.io ## Changelog +### CloudBeaver 22.2.2 - 2022-10-10 +- Administrators now: + - have permission to create connections in both projects, Shared and Private, when it’s restricted for other users, + - can enable a reverse proxy for user authentication in the Administration. +- Different bugs have been fixed. + ### CloudBeaver 22.2.1 - 2022-09-26 - Connection: diff --git a/config/core/initial-data.conf b/config/core/initial-data.conf index 2ba3e63ffc..a33187160f 100644 --- a/config/core/initial-data.conf +++ b/config/core/initial-data.conf @@ -1,13 +1,13 @@ { - roles: [ + teams: [ { - roleId: "admin", + teamId: "admin", name: "Admin", description: "Administrative access. Has all permissions.", permissions: [ "public", "admin" ] }, { - roleId: "user", + teamId: "user", name: "User", description: "Standard user", permissions: [ "public" ] diff --git a/deploy/docker/Dockerfile b/deploy/docker/Dockerfile index e85d0ec846..4123d7015b 100644 --- a/deploy/docker/Dockerfile +++ b/deploy/docker/Dockerfile @@ -1,4 +1,4 @@ -FROM eclipse-temurin:11.0.14.1_1-jre-focal +FROM eclipse-temurin:17.0.4.1_1-jre #adoptopenjdk/openjdk11:jdk-11.0.12_7-ubuntu-slim COPY cloudbeaver /opt/cloudbeaver 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 455aad7bd3..82a17315e5 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 @@ -26,30 +26,30 @@ import java.util.LinkedHashMap; import java.util.Map; public abstract class BaseWebAppConfiguration implements WebAppConfiguration { - public static final String DEFAULT_APP_ANONYMOUS_ROLE_NAME = "user"; + public static final String DEFAULT_APP_ANONYMOUS_TEAM_NAME = "user"; protected final Map plugins; - protected String defaultUserRole; + protected String defaultUserTeam; protected boolean resourceManagerEnabled; protected String[] enabledFeatures; public BaseWebAppConfiguration() { this.plugins = new LinkedHashMap<>(); - this.defaultUserRole = DEFAULT_APP_ANONYMOUS_ROLE_NAME; + this.defaultUserTeam = DEFAULT_APP_ANONYMOUS_TEAM_NAME; this.resourceManagerEnabled = true; this.enabledFeatures = null; } public BaseWebAppConfiguration(BaseWebAppConfiguration src) { this.plugins = new LinkedHashMap<>(src.plugins); - this.defaultUserRole = src.defaultUserRole; + this.defaultUserTeam = src.defaultUserTeam; this.resourceManagerEnabled = src.resourceManagerEnabled; this.enabledFeatures = src.enabledFeatures; } @Override - public String getDefaultUserRole() { - return defaultUserRole; + public String getDefaultUserTeam() { + return defaultUserTeam; } @Override diff --git a/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/model/app/WebAppConfiguration.java b/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/model/app/WebAppConfiguration.java index 9949b47619..236e470c6d 100644 --- a/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/model/app/WebAppConfiguration.java +++ b/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/model/app/WebAppConfiguration.java @@ -24,13 +24,13 @@ import java.util.Map; * Application configuration */ public interface WebAppConfiguration { - String getAnonymousUserRole(); + String getAnonymousUserTeam(); boolean isAnonymousAccessEnabled(); T getResourceQuota(String quotaId); - String getDefaultUserRole(); + String getDefaultUserTeam(); T getPluginOption(@NotNull String pluginId, @NotNull String option); 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 079be1b693..918414cf82 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 @@ -167,6 +167,7 @@ public class LocalResourceController implements RMController { RMProjectType.SHARED, true) ) .filter(Objects::nonNull) + .sorted(Comparator.comparing(RMProject::getDisplayName)) .collect(Collectors.toList()); } @@ -364,6 +365,7 @@ public class LocalResourceController implements RMController { ) throws IOException { try (Stream files = Files.list(folderPath)) { return files.filter(path -> !path.getFileName().toString().startsWith(".")) // skip hidden files + .sorted(Comparator.comparing(path -> path.getFileName().toString(), String.CASE_INSENSITIVE_ORDER)) .map((Path path) -> makeResourceFromPath(projectId, path, readProperties, readHistory, recursive)) .filter(Objects::nonNull) .toArray(RMResource[]::new); diff --git a/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/model/session/WebSession.java b/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/model/session/WebSession.java index 2c955fe363..99f2d8d325 100644 --- a/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/model/session/WebSession.java +++ b/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/model/session/WebSession.java @@ -410,7 +410,7 @@ public class WebSession extends AbstractSessionPersistent private Set readAccessibleConnectionIds() { WebUser user = getUser(); String subjectId = user == null ? - application.getAppConfiguration().getAnonymousUserRole() : user.getUserId(); + application.getAppConfiguration().getAnonymousUserTeam() : user.getUserId(); try { return getSecurityController() diff --git a/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/model/session/WebSessionAuthProcessor.java b/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/model/session/WebSessionAuthProcessor.java index 17c8634da0..c3abd76796 100644 --- a/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/model/session/WebSessionAuthProcessor.java +++ b/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/model/session/WebSessionAuthProcessor.java @@ -161,7 +161,7 @@ public class WebSessionAuthProcessor { providerConfig, userCredentials); - if (!configMode && securityController.getUserPermissions(userId).isEmpty()) { + if (!configMode && securityController.getUserPermissions(userId, authInfo.getAuthRole()).isEmpty()) { throw new DBWebException("Access denied (no permissions)"); } if (!configMode && !securityController.getUserById(userId).isEnabled()) { diff --git a/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/model/user/WebUser.java b/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/model/user/WebUser.java index 16ae555488..5516cddb32 100644 --- a/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/model/user/WebUser.java +++ b/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/model/user/WebUser.java @@ -17,38 +17,26 @@ package io.cloudbeaver.model.user; import org.jkiss.code.NotNull; -import org.jkiss.dbeaver.model.security.user.SMRole; import org.jkiss.dbeaver.model.security.user.SMUser; -import java.util.*; +import java.util.Collections; +import java.util.Map; /** * Web user. */ public class WebUser { @NotNull - private final String userId; + private final SMUser user; private String displayName; - private final Map metaParameters = new LinkedHashMap<>(); - private final Map configurationParameters = new LinkedHashMap<>(); - - private boolean enabled; - - private SMRole[] roles = null; - - private String activeAuthModel; - private final Map> authCredentials = new HashMap<>(); - public WebUser(@NotNull SMUser smUser) { - this.userId = smUser.getUserId(); - this.metaParameters.putAll(smUser.getMetaParameters()); - this.enabled = smUser.isEnabled(); + this.user = smUser; } @NotNull public String getUserId() { - return userId; + return user.getUserId(); } /** @@ -63,61 +51,41 @@ public class WebUser { } public boolean getEnabled() { - return enabled; + return user.isEnabled(); } public void setEnabled(boolean enabled) { - this.enabled = enabled; - } - - public String[] getGrantedRoles() { - return Arrays.stream(roles).map(SMRole::getRoleId).toArray(String[]::new); - } - - public boolean hasRole(String roleId) { - return Arrays.stream(roles).anyMatch(r -> r.getRoleId().equals(roleId)); + user.enableUser(enabled); } public Map getMetaParameters() { - return Collections.unmodifiableMap(metaParameters); - } - - public String getMetaParameter(String name) { - return metaParameters.get(name); + return Collections.unmodifiableMap(user.getMetaParameters()); } public void setMetaParameter(String name, String value) { - metaParameters.put(name, value); - } - - public void removeMetaParameter(String name) { - metaParameters.remove(name); + user.setMetaParameter(name, value); } public Map getConfigurationParameters() { - return Collections.unmodifiableMap(configurationParameters); + return Collections.emptyMap(); } - public SMRole[] getRoles() { - return roles; - } - - public void setRoles(SMRole[] roles) { - this.roles = roles; + public String[] getTeams() { + return user.getUserTeams(); } @Override public int hashCode() { - return userId.hashCode(); + return user.getUserId().hashCode(); } @Override public boolean equals(Object obj) { - return obj instanceof WebUser && ((WebUser) obj).userId.equals(this.userId); + return obj instanceof WebUser && ((WebUser) obj).user.getUserId().equals(this.user.getUserId()); } @Override public String toString() { - return userId; + return user.getUserId(); } } diff --git a/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/server/CBAppConfig.java b/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/server/CBAppConfig.java index 8fd830c197..32028cfbcb 100644 --- a/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/server/CBAppConfig.java +++ b/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/server/CBAppConfig.java @@ -50,7 +50,9 @@ public class CBAppConfig extends BaseAuthWebAppConfiguration implements WebAuthC private boolean redirectOnFederatedAuth; private boolean anonymousAccessEnabled; + @Deprecated private String anonymousUserRole; + private String anonymousUserTeam; private String[] enabledDrivers; private String[] disabledDrivers; @@ -61,7 +63,8 @@ public class CBAppConfig extends BaseAuthWebAppConfiguration implements WebAuthC public CBAppConfig() { super(); this.anonymousAccessEnabled = false; - this.anonymousUserRole = DEFAULT_APP_ANONYMOUS_ROLE_NAME; + this.anonymousUserRole = DEFAULT_APP_ANONYMOUS_TEAM_NAME; + this.anonymousUserTeam = DEFAULT_APP_ANONYMOUS_TEAM_NAME; this.supportsCustomConnections = true; this.supportsConnectionBrowser = false; this.supportsUserWorkspaces = false; @@ -81,6 +84,7 @@ public class CBAppConfig extends BaseAuthWebAppConfiguration implements WebAuthC super(src); this.anonymousAccessEnabled = src.anonymousAccessEnabled; this.anonymousUserRole = src.anonymousUserRole; + this.anonymousUserTeam = src.anonymousUserTeam; this.supportsCustomConnections = src.supportsCustomConnections; this.supportsConnectionBrowser = src.supportsConnectionBrowser; this.supportsUserWorkspaces = src.supportsUserWorkspaces; @@ -102,8 +106,8 @@ public class CBAppConfig extends BaseAuthWebAppConfiguration implements WebAuthC } @Override - public String getAnonymousUserRole() { - return anonymousUserRole; + public String getAnonymousUserTeam() { + return CommonUtils.notNull(anonymousUserTeam, anonymousUserRole); } public void setAnonymousAccessEnabled(boolean anonymousAccessEnabled) { 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 73567df73a..7d4ff0593d 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 @@ -820,15 +820,15 @@ public class CBApplication extends BaseWebApplication implements WebAuthApplicat private void grantAnonymousAccessToConnections(CBAppConfig appConfig, String adminName) { try { - String anonymousRoleId = appConfig.getAnonymousUserRole(); + String anonymousTeamId = appConfig.getAnonymousUserTeam(); var securityController = getSecurityController(); for (DBPDataSourceContainer ds : WebServiceUtils.getGlobalDataSourceRegistry().getDataSources()) { - var datasourcePermissions = securityController.getObjectPermissions(anonymousRoleId, ds.getId(), SMObjects.DATASOURCE); + var datasourcePermissions = securityController.getObjectPermissions(anonymousTeamId, ds.getId(), SMObjects.DATASOURCE); if (CommonUtils.isEmpty(datasourcePermissions.getPermissions())) { securityController.setObjectPermissions( Set.of(ds.getId()), SMObjects.DATASOURCE, - Set.of(anonymousRoleId), + Set.of(anonymousTeamId), Set.of(SMConstants.DATA_SOURCE_ACCESS_PERMISSION), adminName ); 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 145aadf9c7..5b2e04a638 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 @@ -58,7 +58,7 @@ public class CBConstants { public static final String DEFAULT_WORKSPACE_LOCATION = DEFAULT_DEPLOY_LOCATION + "/workspace"; public static final String DEFAULT_PRODUCT_CONFIGURATION = "conf/product.conf"; public static final String DEFAULT_ADMIN_NAME = "cbadmin"; - public static final String DEFAULT_ADMIN_ROLE = "admin"; + public static final String DEFAULT_ADMIN_TEAM = "admin"; // Default max idle time (10 minutes) public static final long MAX_SESSION_IDLE_TIME = 10 * 60 * 1000; 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 e3e372f44b..9d9bb052bc 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 @@ -364,6 +364,10 @@ public class WebServiceCore implements DBWServiceCore { webSession.addInfoMessage("Create new connection"); DBPDataSourceRegistry sessionRegistry = webSession.getProjectById(projectId).getDataSourceRegistry(); + // we don't need to save credentials for templates + if (connectionConfig.isTemplate()) { + connectionConfig.setSaveCredentials(false); + } DBPDataSourceContainer newDataSource = WebServiceUtils.createConnectionFromConfig(connectionConfig, sessionRegistry); if (CommonUtils.isEmpty(newDataSource.getName())) { newDataSource.setName(CommonUtils.notNull(connectionConfig.getName(), "NewConnection")); diff --git a/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/navigator/WebNavigatorNodeInfo.java b/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/navigator/WebNavigatorNodeInfo.java index fb3761ba94..297486ec98 100644 --- a/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/navigator/WebNavigatorNodeInfo.java +++ b/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/navigator/WebNavigatorNodeInfo.java @@ -82,7 +82,8 @@ public class WebNavigatorNodeInfo { @Property public String getProjectId() { - return node.getOwnerProject().getId(); + DBPProject ownerProject = node.getOwnerProject(); + return ownerProject == null ? null : ownerProject.getId(); } @Property 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 d7f3029352..8c09fe4183 100644 --- a/server/bundles/io.cloudbeaver.service.admin/schema/service.admin.graphqls +++ b/server/bundles/io.cloudbeaver.service.admin/schema/service.admin.graphqls @@ -1,7 +1,7 @@ enum AdminSubjectType { user, - role + team } type AdminConnectionGrantInfo { @@ -35,7 +35,7 @@ type AdminUserInfo { metaParameters: Object! configurationParameters: Object! - grantedRoles: [ID!]! + grantedTeams: [ID!]! grantedConnections: [AdminConnectionGrantInfo!]! origins: [ObjectOrigin!]! @@ -44,15 +44,15 @@ type AdminUserInfo { enabled: Boolean! } -type AdminRoleInfo { - roleId: ID! - roleName: String +type AdminTeamInfo { + teamId: ID! + teamName: String description: String grantedUsers: [ID!]! grantedConnections: [AdminConnectionGrantInfo!]! - rolePermissions: [ID!]! + teamPermissions: [ID!]! } type AdminPermissionInfo { @@ -113,23 +113,23 @@ input ServerConfigInput { extend type Query { - #### Users and roles + #### Users and teams listUsers(userId: ID): [AdminUserInfo!]! - listRoles(roleId: ID): [AdminRoleInfo!]! + listTeams(teamId: ID): [AdminTeamInfo!]! listPermissions: [AdminPermissionInfo!]! createUser(userId: ID!, enabled: Boolean!): AdminUserInfo! deleteUser(userId: ID!): Boolean - createRole(roleId: ID!, roleName: String, description: String): AdminRoleInfo! - updateRole(roleId: ID!, roleName: String, description: String): AdminRoleInfo! - deleteRole(roleId: ID!): Boolean + createTeam(teamId: ID!, teamName: String, description: String): AdminTeamInfo! + updateTeam(teamId: ID!, teamName: String, description: String): AdminTeamInfo! + deleteTeam(teamId: ID!): Boolean - grantUserRole(userId: ID!, roleId: ID!): Boolean - revokeUserRole(userId: ID!, roleId: ID!): Boolean + grantUserTeam(userId: ID!, teamId: ID!): Boolean + revokeUserTeam(userId: ID!, teamId: ID!): Boolean - setSubjectPermissions(roleId: ID!, permissions: [ID!]!): [AdminPermissionInfo!]! + setSubjectPermissions(subjectId: ID!, permissions: [ID!]!): [AdminPermissionInfo!]! setUserCredentials(userId: ID!, providerId: ID!, credentials: Object!): Boolean diff --git a/server/bundles/io.cloudbeaver.service.admin/src/io/cloudbeaver/service/admin/AdminRoleInfo.java b/server/bundles/io.cloudbeaver.service.admin/src/io/cloudbeaver/service/admin/AdminTeamInfo.java similarity index 66% rename from server/bundles/io.cloudbeaver.service.admin/src/io/cloudbeaver/service/admin/AdminRoleInfo.java rename to server/bundles/io.cloudbeaver.service.admin/src/io/cloudbeaver/service/admin/AdminTeamInfo.java index d0061830d3..5826d36239 100644 --- a/server/bundles/io.cloudbeaver.service.admin/src/io/cloudbeaver/service/admin/AdminRoleInfo.java +++ b/server/bundles/io.cloudbeaver.service.admin/src/io/cloudbeaver/service/admin/AdminTeamInfo.java @@ -21,54 +21,54 @@ import org.jkiss.dbeaver.DBException; import org.jkiss.dbeaver.model.meta.Property; import org.jkiss.dbeaver.model.security.SMDataSourceGrant; import org.jkiss.dbeaver.model.security.SMObjects; -import org.jkiss.dbeaver.model.security.user.SMRole; +import org.jkiss.dbeaver.model.security.user.SMTeam; import java.util.ArrayList; import java.util.List; /** - * Web role info + * Web team info */ -public class AdminRoleInfo { +public class AdminTeamInfo { private final WebSession session; - private final SMRole role; - private List rolePermissions; + private final SMTeam team; + private List teamPermissions; - public AdminRoleInfo(WebSession session, SMRole role) { - this.role = role; + public AdminTeamInfo(WebSession session, SMTeam team) { + this.team = team; this.session = session; - this.rolePermissions = new ArrayList<>(role.getPermissions()); + this.teamPermissions = new ArrayList<>(team.getPermissions()); } - public String getRoleId() { - return role.getRoleId(); + public String getTeamId() { + return team.getTeamId(); } - public String getRoleName() { - return role.getName(); + public String getTeamName() { + return team.getName(); } public String getDescription() { - return role.getDescription(); + return team.getDescription(); } - public List getRolePermissions() { - return rolePermissions; + public List getTeamPermissions() { + return teamPermissions; } - public void setRolePermissions(List rolePermissions) { - this.rolePermissions = rolePermissions; + public void setTeamPermissions(List teamPermissions) { + this.teamPermissions = teamPermissions; } @Property public SMDataSourceGrant[] getGrantedConnections() throws DBException { return session.getAdminSecurityController() - .getSubjectObjectPermissionGrants(getRoleId(), SMObjects.DATASOURCE) + .getSubjectObjectPermissionGrants(getTeamId(), SMObjects.DATASOURCE) .stream() .map(objectPermission -> new SMDataSourceGrant( objectPermission.getObjectPermissions().getObjectId(), - getRoleId(), + getTeamId(), objectPermission.getSubjectType() )) .toArray(SMDataSourceGrant[]::new); @@ -76,7 +76,7 @@ public class AdminRoleInfo { @Property public String[] getGrantedUsers() throws DBException { - return session.getAdminSecurityController().getRoleSubjects(getRoleId()); + return session.getAdminSecurityController().getTeamMembers(getTeamId()); } } diff --git a/server/bundles/io.cloudbeaver.service.admin/src/io/cloudbeaver/service/admin/AdminUserInfo.java b/server/bundles/io.cloudbeaver.service.admin/src/io/cloudbeaver/service/admin/AdminUserInfo.java index 60621101b9..c542cbed51 100644 --- a/server/bundles/io.cloudbeaver.service.admin/src/io/cloudbeaver/service/admin/AdminUserInfo.java +++ b/server/bundles/io.cloudbeaver.service.admin/src/io/cloudbeaver/service/admin/AdminUserInfo.java @@ -25,7 +25,6 @@ import org.jkiss.dbeaver.Log; import org.jkiss.dbeaver.model.meta.Property; import org.jkiss.dbeaver.model.security.SMDataSourceGrant; import org.jkiss.dbeaver.model.security.SMObjects; -import org.jkiss.dbeaver.model.security.user.SMRole; import org.jkiss.dbeaver.registry.auth.AuthProviderDescriptor; import org.jkiss.dbeaver.registry.auth.AuthProviderRegistry; @@ -71,12 +70,8 @@ public class AdminUserInfo { } @Property - public String[] getGrantedRoles() throws DBException { - if (user.getRoles() == null) { - SMRole[] userRoles = session.getSecurityController().getUserRoles(getUserId()); - user.setRoles(userRoles); - } - return user.getGrantedRoles(); + public String[] getGrantedTeams() { + return user.getTeams(); } @Property 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 357bf83552..b9c79e360a 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 @@ -45,7 +45,7 @@ public interface DBWServiceAdmin extends DBWService { @WebAction(requirePermissions = DBWConstants.PERMISSION_ADMIN) @NotNull - List listRoles(@NotNull WebSession webSession, @Nullable String roleName) throws DBWebException; + List listTeams(@NotNull WebSession webSession, @Nullable String teamName) throws DBWebException; @WebAction(requirePermissions = DBWConstants.PERMISSION_ADMIN) @NotNull @@ -60,23 +60,23 @@ public interface DBWServiceAdmin extends DBWService { @WebAction(requirePermissions = DBWConstants.PERMISSION_ADMIN) @NotNull - AdminRoleInfo createRole(@NotNull WebSession webSession, String roleId, String roleName, String description) throws DBWebException; + AdminTeamInfo createTeam(@NotNull WebSession webSession, String teamId, String teamName, String description) throws DBWebException; @WebAction(requirePermissions = DBWConstants.PERMISSION_ADMIN) @NotNull - AdminRoleInfo updateRole(@NotNull WebSession webSession, String roleId, String roleName, String description) throws DBWebException; + AdminTeamInfo updateTeam(@NotNull WebSession webSession, String teamId, String teamName, String description) throws DBWebException; @WebAction(requirePermissions = DBWConstants.PERMISSION_ADMIN) - boolean deleteRole(@NotNull WebSession webSession, String roleId) throws DBWebException; + boolean deleteTeam(@NotNull WebSession webSession, String teamId) throws DBWebException; @WebAction(requirePermissions = DBWConstants.PERMISSION_ADMIN) - boolean grantUserRole(@NotNull WebSession webSession, String user, String role) throws DBWebException; + boolean grantUserTeam(@NotNull WebSession webSession, String user, String team) throws DBWebException; @WebAction(requirePermissions = DBWConstants.PERMISSION_ADMIN) - boolean revokeUserRole(@NotNull WebSession webSession, String user, String role) throws DBWebException; + boolean revokeUserTeam(@NotNull WebSession webSession, String user, String team) throws DBWebException; @WebAction(requirePermissions = DBWConstants.PERMISSION_ADMIN) - List setSubjectPermissions(@NotNull WebSession webSession, String roleID, List permissions) throws DBWebException; + List setSubjectPermissions(@NotNull WebSession webSession, String subjectID, List permissions) throws DBWebException; @WebAction(requirePermissions = DBWConstants.PERMISSION_ADMIN) boolean setUserCredentials(@NotNull WebSession webSession, @NotNull String userID, @NotNull String providerId, @NotNull Map credentials) throws DBWebException; 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 e0a8bef7b6..a3cb6190b3 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 @@ -45,35 +45,35 @@ public class WebServiceBindingAdmin extends WebServiceBindingBase getService(env).listUsers(getWebSession(env), env.getArgument("userId"))) - .dataFetcher("listRoles", - env -> getService(env).listRoles(getWebSession(env), env.getArgument("roleId"))) + .dataFetcher("listTeams", + env -> getService(env).listTeams(getWebSession(env), env.getArgument("teamId"))) .dataFetcher("listPermissions", env -> getService(env).listPermissions(getWebSession(env))) .dataFetcher("createUser", env -> getService(env).createUser(getWebSession(env), env.getArgument("userId"), env.getArgument("enabled"))) .dataFetcher("deleteUser", env -> getService(env).deleteUser(getWebSession(env), env.getArgument("userId"))) - .dataFetcher("createRole", - env -> getService(env).createRole( + .dataFetcher("createTeam", + env -> getService(env).createTeam( getWebSession(env), - env.getArgument("roleId"), - env.getArgument("roleName"), + env.getArgument("teamId"), + env.getArgument("teamName"), env.getArgument("description"))) - .dataFetcher("updateRole", - env -> getService(env).updateRole( + .dataFetcher("updateTeam", + env -> getService(env).updateTeam( getWebSession(env), - env.getArgument("roleId"), - env.getArgument("roleName"), + env.getArgument("teamId"), + env.getArgument("teamName"), env.getArgument("description"))) - .dataFetcher("deleteRole", - env -> getService(env).deleteRole(getWebSession(env), env.getArgument("roleId"))) + .dataFetcher("deleteTeam", + env -> getService(env).deleteTeam(getWebSession(env), env.getArgument("teamId"))) - .dataFetcher("grantUserRole", - env -> getService(env).grantUserRole(getWebSession(env), env.getArgument("userId"), env.getArgument("roleId"))) - .dataFetcher("revokeUserRole", - env -> getService(env).revokeUserRole(getWebSession(env), env.getArgument("userId"), env.getArgument("roleId"))) + .dataFetcher("grantUserTeam", + env -> getService(env).grantUserTeam(getWebSession(env), env.getArgument("userId"), env.getArgument("teamId"))) + .dataFetcher("revokeUserTeam", + env -> getService(env).revokeUserTeam(getWebSession(env), env.getArgument("userId"), env.getArgument("teamId"))) .dataFetcher("setSubjectPermissions", - env -> getService(env).setSubjectPermissions(getWebSession(env), env.getArgument("roleId"), env.getArgument("permissions"))) + env -> getService(env).setSubjectPermissions(getWebSession(env), env.getArgument("subjectId"), env.getArgument("permissions"))) .dataFetcher("setUserCredentials", env -> getService(env).setUserCredentials(getWebSession(env), env.getArgument("userId"), env.getArgument("providerId"), env.getArgument("credentials"))) .dataFetcher("enableUser", 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 795fb7d469..50efb32b68 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 @@ -53,7 +53,7 @@ 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.security.user.SMRole; +import org.jkiss.dbeaver.model.security.user.SMTeam; import org.jkiss.dbeaver.model.security.user.SMUser; import org.jkiss.dbeaver.registry.DataSourceDescriptor; import org.jkiss.dbeaver.registry.auth.AuthProviderDescriptor; @@ -95,22 +95,22 @@ public class WebServiceAdmin implements DBWServiceAdmin { @NotNull @Override - public List listRoles(@NotNull WebSession webSession, String roleId) throws DBWebException { + public List listTeams(@NotNull WebSession webSession, String teamName) throws DBWebException { try { - List roles = new ArrayList<>(); - if (CommonUtils.isEmpty(roleId)) { - for (SMRole role : webSession.getAdminSecurityController().readAllRoles()) { - roles.add(new AdminRoleInfo(webSession, role)); + List teams = new ArrayList<>(); + if (CommonUtils.isEmpty(teamName)) { + for (SMTeam team : webSession.getAdminSecurityController().readAllTeams()) { + teams.add(new AdminTeamInfo(webSession, team)); } } else { - SMRole role = webSession.getAdminSecurityController().findRole(roleId); - if (role != null) { - roles.add(new AdminRoleInfo(webSession, role)); + SMTeam team = webSession.getAdminSecurityController().findTeam(teamName); + if (team != null) { + teams.add(new AdminTeamInfo(webSession, team)); } } - return roles; + return teams; } catch (Exception e) { - throw new DBWebException("Error reading roles", e); + throw new DBWebException("Error reading teams", e); } } @@ -158,126 +158,126 @@ public class WebServiceAdmin implements DBWServiceAdmin { @NotNull @Override - public AdminRoleInfo createRole(@NotNull WebSession webSession, String roleId, String roleName, String description) throws DBWebException { - if (roleId.isEmpty()) { - throw new DBWebException("Empty role ID"); + public AdminTeamInfo createTeam(@NotNull WebSession webSession, String teamId, String teamName, String description) throws DBWebException { + if (teamId.isEmpty()) { + throw new DBWebException("Empty team ID"); } - webSession.addInfoMessage("Create new role - " + roleId); + webSession.addInfoMessage("Create new team - " + teamId); try { - webSession.getAdminSecurityController().createRole(roleId, roleName, description, webSession.getUser().getUserId()); - SMRole newRole = webSession.getAdminSecurityController().findRole(roleId); - return new AdminRoleInfo(webSession, newRole); + webSession.getAdminSecurityController().createTeam(teamId, teamName, description, webSession.getUser().getUserId()); + SMTeam newTeam = webSession.getAdminSecurityController().findTeam(teamId); + return new AdminTeamInfo(webSession, newTeam); } catch (Exception e) { - throw new DBWebException("Error creating new role", e); + throw new DBWebException("Error creating new team", e); } } @NotNull @Override - public AdminRoleInfo updateRole(@NotNull WebSession webSession, String roleId, String roleName, String description) throws DBWebException { - if (roleId.isEmpty()) { - throw new DBWebException("Empty role ID"); + public AdminTeamInfo updateTeam(@NotNull WebSession webSession, String teamId, String teamName, String description) throws DBWebException { + if (teamId.isEmpty()) { + throw new DBWebException("Empty team ID"); } - webSession.addInfoMessage("Update role - " + roleId); + webSession.addInfoMessage("Update team - " + teamId); try { - webSession.getAdminSecurityController().updateRole(roleId, roleName, description); - SMRole newRole = webSession.getAdminSecurityController().findRole(roleId); - return new AdminRoleInfo(webSession, newRole); + webSession.getAdminSecurityController().updateTeam(teamId, teamName, description); + SMTeam newTeam = webSession.getAdminSecurityController().findTeam(teamId); + return new AdminTeamInfo(webSession, newTeam); } catch (Exception e) { - throw new DBWebException("Error updating role " + roleId, e); + throw new DBWebException("Error updating team " + teamId, e); } } @Override - public boolean deleteRole(@NotNull WebSession webSession, String roleId) throws DBWebException { + public boolean deleteTeam(@NotNull WebSession webSession, String teamId) throws DBWebException { try { - webSession.addInfoMessage("Delete role - " + roleId); + webSession.addInfoMessage("Delete team - " + teamId); var adminSecurityController = webSession.getAdminSecurityController(); - SMRole[] userRoles = adminSecurityController.getUserRoles(webSession.getUser().getUserId()); - if (Arrays.stream(userRoles).anyMatch(DBRole -> DBRole.getRoleId().equals(roleId))) { - throw new DBWebException("You can not delete your own role"); + SMTeam[] userTeams = adminSecurityController.getUserTeams(webSession.getUser().getUserId()); + if (Arrays.stream(userTeams).anyMatch(team -> team.getTeamId().equals(teamId))) { + throw new DBWebException("You can not delete your own team"); } - adminSecurityController.deleteRole(roleId); + adminSecurityController.deleteTeam(teamId); return true; } catch (Exception e) { - throw new DBWebException("Error deleting role", e); + throw new DBWebException("Error deleting team", e); } } @Override - public boolean grantUserRole(@NotNull WebSession webSession, String user, String role) throws DBWebException { + public boolean grantUserTeam(@NotNull WebSession webSession, String user, String team) throws DBWebException { WebUser grantor = webSession.getUser(); if (grantor == null) { - throw new DBWebException("Cannot grant role in anonymous mode"); + throw new DBWebException("Cannot grant team in anonymous mode"); } if (CommonUtils.equalObjects(user, webSession.getUser().getUserId())) { throw new DBWebException("You cannot edit your own permissions"); } try { var adminSecurityController = webSession.getAdminSecurityController(); - SMRole[] userRoles = adminSecurityController.getUserRoles(user); - List roleIds = Arrays.stream(userRoles).map(SMRole::getRoleId).collect(Collectors.toList()); - if (!roleIds.contains(role)) { - roleIds.add(role); - adminSecurityController.setUserRoles(user, roleIds.toArray(new String[0]), grantor.getUserId()); + SMTeam[] userTeams = adminSecurityController.getUserTeams(user); + List teamIds = Arrays.stream(userTeams).map(SMTeam::getTeamId).collect(Collectors.toList()); + if (!teamIds.contains(team)) { + teamIds.add(team); + adminSecurityController.setUserTeams(user, teamIds.toArray(new String[0]), grantor.getUserId()); } else { - throw new DBWebException("User '" + user + "' already has role '" + role + "'"); + throw new DBWebException("User '" + user + "' already has team '" + team + "'"); } return true; } catch (Exception e) { - throw new DBWebException("Error granting role", e); + throw new DBWebException("Error granting team", e); } } @Override - public boolean revokeUserRole(@NotNull WebSession webSession, String user, String role) throws DBWebException { + public boolean revokeUserTeam(@NotNull WebSession webSession, String user, String team) throws DBWebException { WebUser grantor = webSession.getUser(); if (grantor == null) { - throw new DBWebException("Cannot grant role in anonymous mode"); + throw new DBWebException("Cannot revoke team in anonymous mode"); } if (CommonUtils.equalObjects(user, webSession.getUser().getUserId())) { throw new DBWebException("You cannot edit your own permissions"); } try { var adminSecurityController = webSession.getAdminSecurityController(); - SMRole[] userRoles = adminSecurityController.getUserRoles(user); - List roleIds = Arrays.stream(userRoles).map(SMRole::getRoleId).collect(Collectors.toList()); - if (roleIds.contains(role)) { - roleIds.remove(role); - adminSecurityController.setUserRoles(user, roleIds.toArray(new String[0]), grantor.getUserId()); + SMTeam[] userTeams = adminSecurityController.getUserTeams(user); + List teamIds = Arrays.stream(userTeams).map(SMTeam::getTeamId).collect(Collectors.toList()); + if (teamIds.contains(team)) { + teamIds.remove(team); + adminSecurityController.setUserTeams(user, teamIds.toArray(new String[0]), grantor.getUserId()); } else { - throw new DBWebException("User '" + user + "' doesn't have role '" + role + "'"); + throw new DBWebException("User '" + user + "' doesn't have team '" + team + "'"); } return true; } catch (Exception e) { - throw new DBWebException("Error revoking role", e); + throw new DBWebException("Error revoking team", e); } } @Override - public List setSubjectPermissions(@NotNull WebSession webSession, String roleID, List permissions) throws DBWebException { + public List setSubjectPermissions(@NotNull WebSession webSession, String subjectID, List permissions) throws DBWebException { validatePermissions(SMConstants.SUBJECT_PERMISSION_SCOPE, permissions); WebUser grantor = webSession.getUser(); if (grantor == null) { throw new DBWebException("Cannot change permissions in anonymous mode"); } - if (CommonUtils.equalObjects(roleID, CBConstants.DEFAULT_ADMIN_ROLE)) { - throw new DBWebException("Cannot change permissions for role '" + roleID + "'"); + if (CommonUtils.equalObjects(subjectID, CBConstants.DEFAULT_ADMIN_TEAM)) { + throw new DBWebException("Cannot change permissions for team '" + subjectID + "'"); } - webSession.addInfoMessage("Set permissions to subject - " + roleID); + webSession.addInfoMessage("Set permissions to subject - " + subjectID); try { - webSession.getAdminSecurityController().setSubjectPermissions(roleID, permissions, grantor.getUserId()); - Set subjectPermissions = webSession.getAdminSecurityController().getSubjectPermissions(roleID); + webSession.getAdminSecurityController().setSubjectPermissions(subjectID, permissions, grantor.getUserId()); + Set subjectPermissions = webSession.getAdminSecurityController().getSubjectPermissions(subjectID); webSession.refreshUserData(); return listPermissions(webSession).stream() .filter(p -> subjectPermissions.contains(p.getId())) .collect(Collectors.toList()); } catch (Exception e) { - throw new DBWebException("Error setting role permissions", e); + throw new DBWebException("Error setting subject permissions", e); } } @@ -690,7 +690,7 @@ public class WebServiceAdmin implements DBWServiceAdmin { } WebUser grantor = webSession.getUser(); if (grantor == null) { - throw new DBWebException("Cannot grant role in anonymous mode"); + throw new DBWebException("Cannot grant connection access in anonymous mode"); } try { var adminSM = webSession.getAdminSecurityController(); diff --git a/server/bundles/io.cloudbeaver.service.auth/src/io/cloudbeaver/service/auth/RPSessionHandler.java b/server/bundles/io.cloudbeaver.service.auth/src/io/cloudbeaver/service/auth/RPSessionHandler.java index ba5a390fdb..93b1ada087 100644 --- a/server/bundles/io.cloudbeaver.service.auth/src/io/cloudbeaver/service/auth/RPSessionHandler.java +++ b/server/bundles/io.cloudbeaver.service.auth/src/io/cloudbeaver/service/auth/RPSessionHandler.java @@ -67,14 +67,14 @@ public class RPSessionHandler implements DBWSessionHandler { } SMAuthProviderExternal authProviderExternal = (SMAuthProviderExternal) authProvider.getInstance(); String userName = request.getHeader(RPAuthProvider.X_USER); - String roles = request.getHeader(RPAuthProvider.X_ROLE); - List userRoles = roles == null ? Collections.emptyList() : List.of(roles.split("\\|")); + String teams = request.getHeader(RPAuthProvider.X_ROLE); + List userTeams = teams == null ? Collections.emptyList() : List.of(teams.split("\\|")); if (userName != null) { try { Map credentials = new HashMap<>(); credentials.put("user", userName); Map sessionParameters = webSession.getSessionParameters(); - sessionParameters.put(SMConstants.SESSION_PARAM_TRUSTED_USER_ROLES, userRoles); + sessionParameters.put(SMConstants.SESSION_PARAM_TRUSTED_USER_TEAMS, userTeams); Map userCredentials = authProviderExternal.authExternalUser( webSession.getProgressMonitor(), sessionParameters, credentials); String currentSmSessionId = webSession.getUser() == null ? null : webSession.getUserContext().getSmSessionId(); diff --git a/server/bundles/io.cloudbeaver.service.security/db/cb_schema_create.sql b/server/bundles/io.cloudbeaver.service.security/db/cb_schema_create.sql index bc6b63f0c0..e5fb68c092 100644 --- a/server/bundles/io.cloudbeaver.service.security/db/cb_schema_create.sql +++ b/server/bundles/io.cloudbeaver.service.security/db/cb_schema_create.sql @@ -99,6 +99,7 @@ CREATE TABLE CB_USER IS_ACTIVE CHAR(1) NOT NULL, CREATE_TIME TIMESTAMP NOT NULL, + DEFAULT_AUTH_ROLE VARCHAR(32) NULL, PRIMARY KEY (USER_ID), FOREIGN KEY (USER_ID) REFERENCES CB_AUTH_SUBJECT (SUBJECT_ID) ON DELETE CASCADE @@ -125,29 +126,39 @@ CREATE TABLE CB_USER_PARAMETERS FOREIGN KEY (USER_ID) REFERENCES CB_USER (USER_ID) ON DELETE CASCADE ); -CREATE TABLE CB_ROLE +CREATE TABLE CB_TEAM ( - ROLE_ID VARCHAR(128) NOT NULL, - ROLE_NAME VARCHAR(100) NOT NULL, - ROLE_DESCRIPTION VARCHAR(255) NOT NULL, + TEAM_ID VARCHAR(128) NOT NULL, + TEAM_NAME VARCHAR(100) NOT NULL, + TEAM_DESCRIPTION VARCHAR(255) NOT NULL, CREATE_TIME TIMESTAMP NOT NULL, - PRIMARY KEY (ROLE_ID), - FOREIGN KEY (ROLE_ID) REFERENCES CB_AUTH_SUBJECT (SUBJECT_ID) ON DELETE CASCADE + PRIMARY KEY (TEAM_ID), + FOREIGN KEY (TEAM_ID) REFERENCES CB_AUTH_SUBJECT (SUBJECT_ID) ON DELETE CASCADE ); -CREATE TABLE CB_USER_ROLE +CREATE TABLE CB_EXTERNAL_TEAM +( + TEAM_ID VARCHAR(128) NOT NULL, + EXTERNAL_TEAM_ID VARCHAR(128) NOT NULL, + + PRIMARY KEY (TEAM_ID,EXTERNAL_TEAM_ID), + FOREIGN KEY (TEAM_ID) REFERENCES CB_TEAM (TEAM_ID) ON DELETE CASCADE +); + + +CREATE TABLE CB_USER_TEAM ( USER_ID VARCHAR(128) NOT NULL, - ROLE_ID VARCHAR(128) NOT NULL, + TEAM_ID VARCHAR(128) NOT NULL, GRANT_TIME TIMESTAMP NOT NULL, GRANTED_BY VARCHAR(128) NOT NULL, - PRIMARY KEY (USER_ID, ROLE_ID), + PRIMARY KEY (USER_ID, TEAM_ID), FOREIGN KEY (USER_ID) REFERENCES CB_USER (USER_ID) ON DELETE CASCADE, - FOREIGN KEY (ROLE_ID) REFERENCES CB_ROLE (ROLE_ID) ON DELETE CASCADE + FOREIGN KEY (TEAM_ID) REFERENCES CB_TEAM (TEAM_ID) ON DELETE NO ACTION ); CREATE TABLE CB_AUTH_PROVIDER @@ -175,7 +186,7 @@ CREATE TABLE CB_USER_CREDENTIALS CRED_ID VARCHAR(32) NOT NULL, CRED_VALUE VARCHAR(1024) NOT NULL, - UPDATE_TIME TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, + UPDATE_TIME TIMESTAMP DEFAULT CURRENT_TIMESTAMP NOT NULL, PRIMARY KEY (USER_ID, PROVIDER_ID, CRED_ID), FOREIGN KEY (USER_ID) REFERENCES CB_USER (USER_ID) ON DELETE CASCADE @@ -189,7 +200,7 @@ CREATE TABLE CB_USER_STATE USER_CONFIGURATION TEXT NULL, - UPDATE_TIME TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, + UPDATE_TIME TIMESTAMP DEFAULT CURRENT_TIMESTAMP NOT NULL, PRIMARY KEY (USER_ID), FOREIGN KEY (USER_ID) REFERENCES CB_USER (USER_ID) ON DELETE CASCADE @@ -242,14 +253,15 @@ CREATE TABLE CB_AUTH_TOKEN REFRESH_TOKEN_ID VARCHAR(128), SESSION_ID VARCHAR(64) NOT NULL, USER_ID VARCHAR(128), + AUTH_ROLE VARCHAR(32), EXPIRATION_TIME TIMESTAMP NOT NULL, - REFRESH_TOKEN_EXPIRATION_TIME TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, - CREATE_TIME TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, + REFRESH_TOKEN_EXPIRATION_TIME TIMESTAMP DEFAULT CURRENT_TIMESTAMP NOT NULL, + CREATE_TIME TIMESTAMP DEFAULT CURRENT_TIMESTAMP NOT NULL, PRIMARY KEY (TOKEN_ID), FOREIGN KEY (SESSION_ID) REFERENCES CB_SESSION (SESSION_ID) ON DELETE CASCADE, - FOREIGN KEY (USER_ID) REFERENCES CB_USER (USER_ID) ON DELETE CASCADE + FOREIGN KEY (USER_ID) REFERENCES CB_USER (USER_ID) ON DELETE NO ACTION ); CREATE TABLE CB_AUTH_ATTEMPT @@ -262,7 +274,7 @@ CREATE TABLE CB_AUTH_ATTEMPT SESSION_TYPE VARCHAR(64) NOT NULL, APP_SESSION_STATE TEXT NOT NULL, - CREATE_TIME TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, + CREATE_TIME TIMESTAMP DEFAULT CURRENT_TIMESTAMP NOT NULL, PRIMARY KEY (AUTH_ID), FOREIGN KEY (SESSION_ID) REFERENCES CB_SESSION (SESSION_ID) ON DELETE CASCADE @@ -275,7 +287,7 @@ CREATE TABLE CB_AUTH_ATTEMPT_INFO AUTH_PROVIDER_CONFIGURATION_ID VARCHAR(128), AUTH_STATE TEXT NOT NULL, - CREATE_TIME TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, + CREATE_TIME TIMESTAMP DEFAULT CURRENT_TIMESTAMP NOT NULL, PRIMARY KEY (AUTH_ID, AUTH_PROVIDER_ID), FOREIGN KEY (AUTH_ID) REFERENCES CB_AUTH_ATTEMPT (AUTH_ID) ON DELETE CASCADE @@ -287,18 +299,15 @@ CREATE INDEX CB_SESSION_LOG_INDEX ON CB_SESSION_LOG (SESSION_ID, LOG_TIME); CREATE TABLE CB_USER_SECRETS ( - USER_ID VARCHAR(128) NOT NULL, - SECRET_ID VARCHAR(512) NOT NULL, - SECRET_VALUE VARCHAR(65000) NOT NULL, + USER_ID VARCHAR(128) NOT NULL, + SECRET_ID VARCHAR(512) NOT NULL, + SECRET_VALUE TEXT NOT NULL, SECRET_LABEL VARCHAR(128), SECRET_DESCRIPTION VARCHAR(1024), - UPDATE_TIME TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, + UPDATE_TIME TIMESTAMP DEFAULT CURRENT_TIMESTAMP NOT NULL, PRIMARY KEY (USER_ID, SECRET_ID), FOREIGN KEY (USER_ID) REFERENCES CB_USER (USER_ID) ON DELETE CASCADE ); - -CREATE INDEX CB_USER_SECRETS_ID ON CB_USER_SECRETS (USER_ID,SECRET_ID); - diff --git a/server/bundles/io.cloudbeaver.service.security/db/cb_schema_update_11.sql b/server/bundles/io.cloudbeaver.service.security/db/cb_schema_update_11.sql new file mode 100644 index 0000000000..0585be1e6b --- /dev/null +++ b/server/bundles/io.cloudbeaver.service.security/db/cb_schema_update_11.sql @@ -0,0 +1,46 @@ +ALTER TABLE CB_AUTH_TOKEN ADD COLUMN AUTH_ROLE VARCHAR(32); + +ALTER TABLE CB_USER ADD COLUMN DEFAULT_AUTH_ROLE VARCHAR(32) NULL; + +CREATE TABLE CB_TEAM +( + TEAM_ID VARCHAR(128) NOT NULL, + TEAM_NAME VARCHAR(100) NOT NULL, + TEAM_DESCRIPTION VARCHAR(255) NOT NULL, + + CREATE_TIME TIMESTAMP NOT NULL, + + PRIMARY KEY (TEAM_ID), + FOREIGN KEY (TEAM_ID) REFERENCES CB_AUTH_SUBJECT (SUBJECT_ID) ON DELETE CASCADE +); + +INSERT INTO CB_TEAM (TEAM_ID, TEAM_NAME, TEAM_DESCRIPTION, CREATE_TIME) +SELECT ROLE_ID, ROLE_NAME, ROLE_DESCRIPTION, CREATE_TIME FROM CB_ROLE; + +CREATE TABLE CB_USER_TEAM +( + USER_ID VARCHAR(128) NOT NULL, + TEAM_ID VARCHAR(128) NOT NULL, + + GRANT_TIME TIMESTAMP NOT NULL, + GRANTED_BY VARCHAR(128) NOT NULL, + + PRIMARY KEY (USER_ID, TEAM_ID), + FOREIGN KEY (USER_ID) REFERENCES CB_USER (USER_ID) ON DELETE CASCADE, + FOREIGN KEY (TEAM_ID) REFERENCES CB_TEAM (TEAM_ID) ON DELETE NO ACTION +); + +INSERT INTO CB_USER_TEAM (USER_ID, TEAM_ID, GRANT_TIME, GRANTED_BY) +SELECT USER_ID, ROLE_ID, GRANT_TIME, GRANTED_BY FROM CB_USER_ROLE; + +CREATE TABLE CB_EXTERNAL_TEAM +( + TEAM_ID VARCHAR(128) NOT NULL, + EXTERNAL_TEAM_ID VARCHAR(128) NOT NULL, + + PRIMARY KEY (TEAM_ID,EXTERNAL_TEAM_ID), + FOREIGN KEY (TEAM_ID) REFERENCES CB_TEAM (TEAM_ID) ON DELETE CASCADE +); + +DROP TABLE CB_USER_ROLE; +DROP TABLE CB_ROLE; \ No newline at end of file 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 600a489c8d..73c6571392 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 @@ -38,6 +38,7 @@ import org.jkiss.dbeaver.model.exec.DBCException; 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.runtime.VoidProgressMonitor; import org.jkiss.dbeaver.model.security.*; import org.jkiss.dbeaver.model.security.exception.SMAccessTokenExpiredException; @@ -45,7 +46,7 @@ import org.jkiss.dbeaver.model.security.exception.SMException; import org.jkiss.dbeaver.model.security.exception.SMRefreshTokenExpiredException; import org.jkiss.dbeaver.model.security.user.SMAuthPermissions; import org.jkiss.dbeaver.model.security.user.SMObjectPermissions; -import org.jkiss.dbeaver.model.security.user.SMRole; +import org.jkiss.dbeaver.model.security.user.SMTeam; import org.jkiss.dbeaver.model.security.user.SMUser; import org.jkiss.dbeaver.registry.auth.AuthProviderDescriptor; import org.jkiss.dbeaver.registry.auth.AuthProviderRegistry; @@ -72,7 +73,7 @@ public class CBEmbeddedSecurityController implements SMAdminController, SMAuthen protected static final String CHAR_BOOL_FALSE = "N"; private static final String SUBJECT_USER = "U"; - private static final String SUBJECT_ROLE = "R"; + private static final String SUBJECT_TEAM = "R"; private static final Type MAP_STRING_OBJECT_TYPE = new TypeToken>() { }.getType(); private static final Gson gson = new GsonBuilder().create(); @@ -114,7 +115,7 @@ public class CBEmbeddedSecurityController implements SMAdminController, SMAuthen @Override public void createUser(String userId, Map metaParameters, boolean enabled) throws DBException { if (isSubjectExists(userId)) { - throw new DBCException("User or role '" + userId + "' already exists"); + throw new DBCException("User or team '" + userId + "' already exists"); } try (Connection dbCon = database.openConnection()) { try (JDBCTransaction txn = new JDBCTransaction(dbCon)) { @@ -156,15 +157,15 @@ public class CBEmbeddedSecurityController implements SMAdminController, SMAuthen } @Override - public void setUserRoles(String userId, String[] roleIds, String grantorId) throws DBCException { + public void setUserTeams(String userId, String[] teamIds, String grantorId) throws DBCException { try (Connection dbCon = database.openConnection()) { try (JDBCTransaction txn = new JDBCTransaction(dbCon)) { - JDBCUtils.executeStatement(dbCon, "DELETE FROM CB_USER_ROLE WHERE USER_ID=?", userId); - if (!ArrayUtils.isEmpty(roleIds)) { - try (PreparedStatement dbStat = dbCon.prepareStatement("INSERT INTO CB_USER_ROLE(USER_ID,ROLE_ID,GRANT_TIME,GRANTED_BY) VALUES(?,?,?,?)")) { - for (String roleId : roleIds) { + JDBCUtils.executeStatement(dbCon, "DELETE FROM CB_USER_TEAM WHERE USER_ID=?", userId); + if (!ArrayUtils.isEmpty(teamIds)) { + try (PreparedStatement dbStat = dbCon.prepareStatement("INSERT INTO CB_USER_TEAM(USER_ID,TEAM_ID,GRANT_TIME,GRANTED_BY) VALUES(?,?,?,?)")) { + for (String teamId : teamIds) { dbStat.setString(1, userId); - dbStat.setString(2, roleId); + dbStat.setString(2, teamId); dbStat.setTimestamp(3, new Timestamp(System.currentTimeMillis())); dbStat.setString(4, grantorId); dbStat.execute(); @@ -174,28 +175,28 @@ public class CBEmbeddedSecurityController implements SMAdminController, SMAuthen txn.commit(); } } catch (SQLException e) { - throw new DBCException("Error saving user roles in database", e); + throw new DBCException("Error saving user teams in database", e); } } @NotNull @Override - public SMRole[] getUserRoles(String userId) throws DBException { + public SMTeam[] getUserTeams(String userId) throws DBException { try (Connection dbCon = database.openConnection()) { try (PreparedStatement dbStat = dbCon.prepareStatement( - "SELECT R.* FROM CB_USER_ROLE UR,CB_ROLE R " + - "WHERE UR.USER_ID=? AND UR.ROLE_ID=R.ROLE_ID")) { + "SELECT R.* FROM CB_USER_TEAM UR,CB_TEAM R " + + "WHERE UR.USER_ID=? AND UR.TEAM_ID=R.TEAM_ID")) { dbStat.setString(1, userId); - List roles = new ArrayList<>(); + List teams = new ArrayList<>(); try (ResultSet dbResult = dbStat.executeQuery()) { while (dbResult.next()) { - roles.add(fetchRole(dbResult)); + teams.add(fetchTeam(dbResult)); } } - return roles.toArray(new SMRole[0]); + return teams.toArray(new SMTeam[0]); } } catch (SQLException e) { - throw new DBCException("Error while reading user roles", e); + throw new DBCException("Error while reading user teams", e); } } @@ -215,6 +216,7 @@ public class CBEmbeddedSecurityController implements SMAdminController, SMAuthen } } } + // Metas try (PreparedStatement dbStat = dbCon.prepareStatement("SELECT META_ID,META_VALUE FROM CB_USER_META WHERE USER_ID=?")) { dbStat.setString(1, userId); try (ResultSet dbResult = dbStat.executeQuery()) { @@ -226,6 +228,17 @@ public class CBEmbeddedSecurityController implements SMAdminController, SMAuthen } } } + // Teams + try (PreparedStatement dbStat = dbCon.prepareStatement("SELECT TEAM_ID FROM CB_USER_TEAM WHERE USER_ID=?")) { + dbStat.setString(1, userId); + try (ResultSet dbResult = dbStat.executeQuery()) { + List teamIDs = new ArrayList<>(); + while (dbResult.next()) { + teamIDs.add(dbResult.getString(1)); + } + user.setUserTeams(teamIDs.toArray(new String[0])); + } + } return user; } catch (SQLException e) { throw new DBCException("Error while searching credentials", e); @@ -270,6 +283,24 @@ public class CBEmbeddedSecurityController implements SMAdminController, SMAuthen } } } + // Read teams + try (PreparedStatement dbStat = dbCon.prepareStatement("SELECT USER_ID,TEAM_ID FROM CB_USER_TEAM" + + (CommonUtils.isEmpty(userNameMask) ? "" : " WHERE USER_ID=?"))) { + if (!CommonUtils.isEmpty(userNameMask)) { + dbStat.setString(1, userNameMask); + } + try (ResultSet dbResult = dbStat.executeQuery()) { + while (dbResult.next()) { + String userId = dbResult.getString(1); + String teamId = dbResult.getString(2); + SMUser user = result.get(userId); + if (user != null) { + String[] teams = ArrayUtils.add(String.class, user.getUserTeams(), teamId); + user.setUserTeams(teams); + } + } + } + } return result.values().toArray(new SMUser[0]); } catch (SQLException e) { throw new DBCException("Error while loading users", e); @@ -533,7 +564,7 @@ public class CBEmbeddedSecurityController implements SMAdminController, SMAuthen } } } catch (SQLException e) { - throw new DBCException("Error saving role in database", e); + throw new DBCException("Error reading user credentials", e); } } @@ -556,56 +587,56 @@ public class CBEmbeddedSecurityController implements SMAdminController, SMAuthen } } } catch (SQLException e) { - throw new DBCException("Error saving role in database", e); + throw new DBCException("Error reading user linked providers", e); } } /////////////////////////////////////////// - // Roles + // Teams @NotNull @Override - public SMRole[] readAllRoles() throws DBCException { + public SMTeam[] readAllTeams() throws DBCException { try (Connection dbCon = database.openConnection()) { - Map roles = new LinkedHashMap<>(); + Map teams = new LinkedHashMap<>(); try (Statement dbStat = dbCon.createStatement()) { - try (ResultSet dbResult = dbStat.executeQuery("SELECT * FROM CB_ROLE ORDER BY ROLE_ID")) { + try (ResultSet dbResult = dbStat.executeQuery("SELECT * FROM CB_TEAM ORDER BY TEAM_ID")) { while (dbResult.next()) { - SMRole role = fetchRole(dbResult); - roles.put(role.getRoleId(), role); + SMTeam team = fetchTeam(dbResult); + teams.put(team.getTeamId(), team); } } try (ResultSet dbResult = dbStat.executeQuery("SELECT SUBJECT_ID,PERMISSION_ID\n" + - "FROM CB_AUTH_PERMISSIONS AP,CB_ROLE R\n" + - "WHERE AP.SUBJECT_ID=R.ROLE_ID\n")) { + "FROM CB_AUTH_PERMISSIONS AP,CB_TEAM R\n" + + "WHERE AP.SUBJECT_ID=R.TEAM_ID\n")) { while (dbResult.next()) { - SMRole role = roles.get(dbResult.getString(1)); - if (role != null) { - role.addPermission(dbResult.getString(2)); + SMTeam team = teams.get(dbResult.getString(1)); + if (team != null) { + team.addPermission(dbResult.getString(2)); } } } } - return roles.values().toArray(new SMRole[0]); + return teams.values().toArray(new SMTeam[0]); } catch (SQLException e) { - throw new DBCException("Error reading roles from database", e); + throw new DBCException("Error reading teams from database", e); } } @Override - public SMRole findRole(String roleId) throws DBCException { - return Arrays.stream(readAllRoles()) - .filter(r -> r.getRoleId().equals(roleId)) + public SMTeam findTeam(String teamId) throws DBCException { + return Arrays.stream(readAllTeams()) + .filter(r -> r.getTeamId().equals(teamId)) .findFirst().orElse(null); } @NotNull @Override - public String[] getRoleSubjects(String roleId) throws DBCException { + public String[] getTeamMembers(String teamId) throws DBCException { try (Connection dbCon = database.openConnection()) { try (PreparedStatement dbStat = dbCon.prepareStatement( - "SELECT USER_ID FROM CB_USER_ROLE WHERE ROLE_ID=?")) { - dbStat.setString(1, roleId); + "SELECT USER_ID FROM CB_USER_TEAM WHERE TEAM_ID=?")) { + dbStat.setString(1, teamId); List subjects = new ArrayList<>(); try (ResultSet dbResult = dbStat.executeQuery()) { while (dbResult.next()) { @@ -615,95 +646,96 @@ public class CBEmbeddedSecurityController implements SMAdminController, SMAuthen return subjects.toArray(new String[0]); } } catch (SQLException e) { - throw new DBCException("Error while reading role subjects", e); + throw new DBCException("Error while reading team members", e); } } @NotNull - private SMRole fetchRole(ResultSet dbResult) throws SQLException { - return new SMRole(dbResult.getString("ROLE_ID"), - dbResult.getString("ROLE_NAME"), - dbResult.getString("ROLE_DESCRIPTION") + private SMTeam fetchTeam(ResultSet dbResult) throws SQLException { + return new SMTeam( + dbResult.getString("TEAM_ID"), + dbResult.getString("TEAM_NAME"), + dbResult.getString("TEAM_DESCRIPTION") ); } @Override - public void createRole(String roleId, String name, String description, String grantor) throws DBCException { - if (isSubjectExists(roleId)) { - throw new DBCException("User or role '" + roleId + "' already exists"); + public void createTeam(String teamId, String name, String description, String grantor) throws DBCException { + if (isSubjectExists(teamId)) { + throw new DBCException("User or team '" + teamId + "' already exists"); } try (Connection dbCon = database.openConnection()) { try (JDBCTransaction txn = new JDBCTransaction(dbCon)) { - createAuthSubject(dbCon, roleId, SUBJECT_ROLE); + createAuthSubject(dbCon, teamId, SUBJECT_TEAM); try (PreparedStatement dbStat = dbCon.prepareStatement( - "INSERT INTO CB_ROLE(ROLE_ID,ROLE_NAME,ROLE_DESCRIPTION,CREATE_TIME) VALUES(?,?,?,?)")) { - dbStat.setString(1, roleId); + "INSERT INTO CB_TEAM(TEAM_ID,TEAM_NAME,TEAM_DESCRIPTION,CREATE_TIME) VALUES(?,?,?,?)")) { + dbStat.setString(1, teamId); dbStat.setString(2, CommonUtils.notEmpty(name)); dbStat.setString(3, CommonUtils.notEmpty(description)); dbStat.setTimestamp(4, new Timestamp(System.currentTimeMillis())); dbStat.execute(); } - insertPermissions(dbCon, roleId, + insertPermissions(dbCon, teamId, new String[] {DBWConstants.PERMISSION_PUBLIC} , grantor); txn.commit(); } } catch (SQLException e) { - throw new DBCException("Error saving role in database", e); + throw new DBCException("Error saving tem in database", e); } } @Override - public void updateRole(String roleId, String name, String description) throws DBCException { - if (!isSubjectExists(roleId)) { - throw new DBCException("Role '" + roleId + "' doesn't exists"); + public void updateTeam(String teamId, String name, String description) throws DBCException { + if (!isSubjectExists(teamId)) { + throw new DBCException("Team '" + teamId + "' doesn't exists"); } try (Connection dbCon = database.openConnection()) { try (JDBCTransaction txn = new JDBCTransaction(dbCon)) { try (PreparedStatement dbStat = dbCon.prepareStatement( - "UPDATE CB_ROLE SET ROLE_NAME=?,ROLE_DESCRIPTION=? WHERE ROLE_ID=?")) { + "UPDATE CB_TEAM SET TEAM_NAME=?,TEAM_DESCRIPTION=? WHERE TEAM_ID=?")) { dbStat.setString(1, CommonUtils.notEmpty(name)); dbStat.setString(2, CommonUtils.notEmpty(description)); - dbStat.setString(3, roleId); + dbStat.setString(3, teamId); if (dbStat.executeUpdate() <= 0) { - throw new DBCException("Role '" + roleId + "' doesn't exist"); + throw new DBCException("Team '" + teamId + "' doesn't exist"); } } txn.commit(); } } catch (SQLException e) { - throw new DBCException("Error updating role info in database", e); + throw new DBCException("Error updating team info in database", e); } } @Override - public void deleteRole(String roleId) throws DBCException { + public void deleteTeam(String teamId) throws DBCException { try (Connection dbCon = database.openConnection()) { try (PreparedStatement dbStat = dbCon.prepareStatement( - "SELECT COUNT(*) FROM CB_USER_ROLE WHERE ROLE_ID=?")) { - dbStat.setString(1, roleId); + "SELECT COUNT(*) FROM CB_USER_TEAM WHERE TEAM_ID=?")) { + dbStat.setString(1, teamId); try (ResultSet dbResult = dbStat.executeQuery()) { if (dbResult.next()) { int userCount = dbResult.getInt(1); if (userCount > 0) { - throw new DBCException("Role can't be deleted. There are " + userCount + " user(s) who have this role. Un-assign role first."); + throw new DBCException("Team can't be deleted. There are " + userCount + " user(s) who have this team. Un-assign team first."); } } } } try (JDBCTransaction txn = new JDBCTransaction(dbCon)) { - deleteAuthSubject(dbCon, roleId); + deleteAuthSubject(dbCon, teamId); try (PreparedStatement dbStat = dbCon.prepareStatement( - "DELETE FROM CB_ROLE WHERE ROLE_ID=?")) { - dbStat.setString(1, roleId); + "DELETE FROM CB_TEAM WHERE TEAM_ID=?")) { + dbStat.setString(1, teamId); dbStat.execute(); } txn.commit(); } } catch (SQLException e) { - throw new DBCException("Error deleting role from database", e); + throw new DBCException("Error deleting team from database", e); } } @@ -720,7 +752,7 @@ public class CBEmbeddedSecurityController implements SMAdminController, SMAuthen txn.commit(); } } catch (SQLException e) { - throw new DBCException("Error saving role permissions in database", e); + throw new DBCException("Error saving subject permissions in database", e); } } @@ -753,18 +785,18 @@ public class CBEmbeddedSecurityController implements SMAdminController, SMAuthen } return permissions; } catch (SQLException e) { - throw new DBCException("Error saving role in database", e); + throw new DBCException("Error reading subject permissions", e); } } @NotNull @Override - public Set getUserPermissions(String userId) throws DBException { + public Set getUserPermissions(String userId, String authRole) throws DBException { try (Connection dbCon = database.openConnection()) { Set permissions = new HashSet<>(); try (PreparedStatement dbStat = dbCon.prepareStatement( - "SELECT DISTINCT AP.PERMISSION_ID FROM CB_AUTH_PERMISSIONS AP,CB_USER_ROLE UR\n" + - "WHERE UR.ROLE_ID=AP.SUBJECT_ID AND UR.USER_ID=?")) { + "SELECT DISTINCT AP.PERMISSION_ID FROM CB_AUTH_PERMISSIONS AP,CB_USER_TEAM UR\n" + + "WHERE UR.TEAM_ID=AP.SUBJECT_ID AND UR.USER_ID=?")) { dbStat.setString(1, userId); try (ResultSet dbResult = dbStat.executeQuery()) { while (dbResult.next()) { @@ -822,25 +854,15 @@ public class CBEmbeddedSecurityController implements SMAdminController, SMAuthen + "VALUES(?,?,?,?,?,?,?,?,?)")) { dbStat.setString(1, sessionId); dbStat.setString(2, appSessionId); - if (userId != null) { - dbStat.setString(3, userId); - } else { - dbStat.setNull(3, Types.VARCHAR); - } + JDBCUtils.setStringOrNull(dbStat, 3, userId); Timestamp currentTS = new Timestamp(System.currentTimeMillis()); dbStat.setTimestamp(4, currentTS); dbStat.setTimestamp(5, currentTS); - if (parameters.get(SMConstants.SESSION_PARAM_LAST_REMOTE_ADDRESS) != null) { - dbStat.setString(6, parameters.get(SMConstants.SESSION_PARAM_LAST_REMOTE_ADDRESS).toString()); - } else { - dbStat.setNull(6, Types.VARCHAR); - } - if (parameters.get(SMConstants.SESSION_PARAM_LAST_REMOTE_USER_AGENT) != null) { - dbStat.setString(7, parameters.get(SMConstants.SESSION_PARAM_LAST_REMOTE_USER_AGENT).toString()); - } else { - dbStat.setNull(7, Types.VARCHAR); - } + JDBCUtils.setStringOrNull(dbStat, 6, CommonUtils.truncateString(CommonUtils.toString( + parameters.get(SMConstants.SESSION_PARAM_LAST_REMOTE_ADDRESS), null), 128)); + JDBCUtils.setStringOrNull(dbStat, 7, CommonUtils.truncateString(CommonUtils.toString( + parameters.get(SMConstants.SESSION_PARAM_LAST_REMOTE_USER_AGENT), null), 255)); dbStat.setString(8, database.getInstanceId()); dbStat.setString(9, sessionType.getSessionType()); dbStat.execute(); @@ -853,14 +875,15 @@ public class CBEmbeddedSecurityController implements SMAdminController, SMAuthen try (Connection dbCon = database.openConnection()) { try (JDBCTransaction txn = new JDBCTransaction(dbCon)) { var smSessionId = createSmSession(appSessionId, null, sessionParameters, sessionType, dbCon); - var smTokens = generateNewSessionToken(smSessionId, null, dbCon); + var smTokens = generateNewSessionToken(smSessionId, null, null, dbCon); var permissions = getAnonymousUserPermissions(); txn.commit(); return SMAuthInfo.success( UUID.randomUUID().toString(), smTokens.getSmAccessToken(), smTokens.getSmRefreshToken(), - new SMAuthPermissions(null, smSessionId, permissions), Map.of() + new SMAuthPermissions(null, smSessionId, permissions), + Map.of() ); } } catch (SQLException e) { @@ -869,8 +892,8 @@ public class CBEmbeddedSecurityController implements SMAdminController, SMAuthen } private Set getAnonymousUserPermissions() throws DBException { - var anonymousUserRole = ((WebApplication) DBWorkbench.getPlatform().getApplication()).getAppConfiguration().getAnonymousUserRole(); - return getSubjectPermissions(anonymousUserRole); + var anonymousUserTeam = ((WebApplication) DBWorkbench.getPlatform().getApplication()).getAppConfiguration().getAnonymousUserTeam(); + return getSubjectPermissions(anonymousUserTeam); } @Override @@ -1019,16 +1042,8 @@ public class CBEmbeddedSecurityController implements SMAdminController, SMAuthen try (PreparedStatement dbStat = dbCon.prepareStatement( "UPDATE CB_AUTH_ATTEMPT SET AUTH_STATUS=?,AUTH_ERROR=?,SESSION_ID=? WHERE AUTH_ID=?")) { dbStat.setString(1, authStatus.toString()); - if (error != null) { - dbStat.setString(2, error); - } else { - dbStat.setNull(2, Types.VARCHAR); - } - if (smSessionId != null) { - dbStat.setString(3, smSessionId); - } else { - dbStat.setNull(3, Types.VARCHAR); - } + JDBCUtils.setStringOrNull(dbStat, 2, error); + JDBCUtils.setStringOrNull(dbStat, 3, smSessionId); dbStat.setString(4, authId); if (dbStat.executeUpdate() <= 0) { throw new DBCException("Auth attempt '" + authId + "' doesn't exist"); @@ -1145,6 +1160,7 @@ public class CBEmbeddedSecurityController implements SMAdminController, SMAuthen public SMTokens refreshSession(@NotNull String refreshToken) throws DBException { var currentUserCreds = getCurrentUserCreds(); var currentUserAccessToken = currentUserCreds.getSmToken(); + String currentUserAuthRole = null; // FIXME: read role from auth token var expectedRefreshTokenInfo = findRefreshToken(currentUserAccessToken); @@ -1154,7 +1170,7 @@ public class CBEmbeddedSecurityController implements SMAdminController, SMAuthen try (var dbCon = database.openConnection()) { invalidateUserTokens(currentUserAccessToken); - return generateNewSessionToken(expectedRefreshTokenInfo.getSessionId(), expectedRefreshTokenInfo.getUserId(), dbCon); + return generateNewSessionToken(expectedRefreshTokenInfo.getSessionId(), expectedRefreshTokenInfo.getUserId(), currentUserAuthRole, dbCon); } catch (SQLException e) { throw new DBException("Error refreshing sm session", e); } @@ -1223,7 +1239,11 @@ public class CBEmbeddedSecurityController implements SMAdminController, SMAuthen return finishAuthentication(authInfo, false, true); } - private SMAuthInfo finishAuthentication(@NotNull SMAuthInfo authInfo, boolean forceExpireAuthAfterSuccess, boolean saveSecuredCreds) throws DBException { + private SMAuthInfo finishAuthentication( + @NotNull SMAuthInfo authInfo, + boolean forceExpireAuthAfterSuccess, + boolean saveSecuredCreds + ) throws DBException { String authId = authInfo.getAuthAttemptId(); if (authInfo.getAuthStatus() != SMAuthStatus.IN_PROGRESS) { throw new SMException("Authorization has already been completed with status: " + authInfo.getAuthStatus()); @@ -1233,7 +1253,7 @@ public class CBEmbeddedSecurityController implements SMAdminController, SMAuthen throw new SMException("Authorization providers are not defined"); } - var finishAuthMonitor = new VoidProgressMonitor(); + DBRProgressMonitor finishAuthMonitor = new LoggingProgressMonitor(log); AuthAttemptSessionInfo authAttemptSessionInfo = readAuthAttemptSessionInfo(authId); boolean isMainAuthSession = authAttemptSessionInfo.getSmSessionId() == null; @@ -1287,8 +1307,9 @@ public class CBEmbeddedSecurityController implements SMAdminController, SMAuthen } else { smSessionId = authAttemptSessionInfo.getSmSessionId(); } - smTokens = generateNewSessionToken(smSessionId, activeUserId, dbCon); - permissions = new SMAuthPermissions(activeUserId, smSessionId, getUserPermissions(activeUserId)); + smTokens = generateNewSessionToken(smSessionId, activeUserId, authInfo.getAuthRole(), dbCon); + permissions = new SMAuthPermissions( + activeUserId, smSessionId, getUserPermissions(activeUserId, authInfo.getAuthRole())); txn.commit(); } } catch (SQLException e) { @@ -1364,11 +1385,11 @@ public class CBEmbeddedSecurityController implements SMAdminController, SMAuthen userId = userIdFromCredentials; if (!isSubjectExists(userId)) { - var newUser = new SMUser(userId); + var newUser = new SMUser(userId, true); createUser(newUser.getUserId(), newUser.getMetaParameters(), true); - String defaultRoleName = WebAppUtils.getWebApplication().getAppConfiguration().getDefaultUserRole(); - if (!CommonUtils.isEmpty(defaultRoleName)) { - setUserRoles(userId, new String[]{defaultRoleName}, userId); + String defaultTeamName = WebAppUtils.getWebApplication().getAppConfiguration().getDefaultUserTeam(); + if (!CommonUtils.isEmpty(defaultTeamName)) { + setUserTeams(userId, new String[]{defaultTeamName}, userId); } } setUserCredentials(userId, authProviderId, userCredentials); @@ -1376,9 +1397,9 @@ public class CBEmbeddedSecurityController implements SMAdminController, SMAuthen userId = userIdFromCredentials; } if (authProvider.isTrusted()) { - Object reverseProxyUserRoles = sessionParameters.get(SMConstants.SESSION_PARAM_TRUSTED_USER_ROLES); - if (reverseProxyUserRoles instanceof List) { - setUserRoles(userId, ((List) reverseProxyUserRoles).stream().map(Object::toString).toArray(String[]::new), userId); + Object reverseProxyUserTeams = sessionParameters.get(SMConstants.SESSION_PARAM_TRUSTED_USER_TEAMS); + if (reverseProxyUserTeams instanceof List) { + setUserTeams(userId, ((List) reverseProxyUserTeams).stream().map(Object::toString).toArray(String[]::new), userId); } } return userId; @@ -1387,34 +1408,35 @@ public class CBEmbeddedSecurityController implements SMAdminController, SMAuthen protected SMTokens generateNewSessionToken( @NotNull String smSessionId, @Nullable String userId, + @Nullable String authRole, @NotNull Connection dbCon ) throws SQLException, DBException { JDBCUtils.executeStatement(dbCon, "DELETE FROM CB_AUTH_TOKEN WHERE SESSION_ID=?", smSessionId); - return generateNewSessionTokens(smSessionId, userId, dbCon); + return generateNewSessionTokens(smSessionId, userId, authRole, dbCon); } - private SMTokens generateNewSessionTokens(@NotNull String smSessionId, - @Nullable String userId, - @NotNull Connection dbCon) throws SQLException { + private SMTokens generateNewSessionTokens( + @NotNull String smSessionId, + @Nullable String userId, + @Nullable String authRole, + @NotNull Connection dbCon + ) throws SQLException { try (PreparedStatement dbStat = dbCon.prepareStatement( - "INSERT INTO CB_AUTH_TOKEN(TOKEN_ID,SESSION_ID,USER_ID,EXPIRATION_TIME,REFRESH_TOKEN_ID,REFRESH_TOKEN_EXPIRATION_TIME) " + - "VALUES(?,?,?,?,?,?)")) { + "INSERT INTO CB_AUTH_TOKEN(TOKEN_ID,SESSION_ID,USER_ID,AUTH_ROLE,EXPIRATION_TIME,REFRESH_TOKEN_ID,REFRESH_TOKEN_EXPIRATION_TIME) " + + "VALUES(?,?,?,?,?,?,?)")) { String smAccessToken = SecurityUtils.generatePassword(32); dbStat.setString(1, smAccessToken); dbStat.setString(2, smSessionId); - if (userId == null) { - dbStat.setNull(3, Types.VARCHAR); - } else { - dbStat.setString(3, userId); - } + JDBCUtils.setStringOrNull(dbStat, 3, userId); + JDBCUtils.setStringOrNull(dbStat, 4, authRole); var accessTokenExpirationTime = Timestamp.valueOf(LocalDateTime.now().plusMinutes(smConfig.getAccessTokenTtl())); - dbStat.setTimestamp(4, accessTokenExpirationTime); + dbStat.setTimestamp(5, accessTokenExpirationTime); String smRefreshToken = SecurityUtils.generatePassword(32); - dbStat.setString(5, smRefreshToken); + dbStat.setString(6, smRefreshToken); var refreshTokenExpirationTime = Timestamp.valueOf(LocalDateTime.now().plusMinutes(smConfig.getRefreshTokenTtl())); - dbStat.setTimestamp(6, refreshTokenExpirationTime); + dbStat.setTimestamp(7, refreshTokenExpirationTime); dbStat.execute(); return new SMTokens(smAccessToken, smRefreshToken); @@ -1425,8 +1447,9 @@ public class CBEmbeddedSecurityController implements SMAdminController, SMAuthen public SMAuthPermissions getTokenPermissions(String token) throws DBException { String userId; String sessionId; + String authRole; try (Connection dbCon = database.openConnection(); - PreparedStatement dbStat = dbCon.prepareStatement("SELECT USER_ID, EXPIRATION_TIME, SESSION_ID FROM CB_AUTH_TOKEN WHERE TOKEN_ID=?"); + PreparedStatement dbStat = dbCon.prepareStatement("SELECT USER_ID, EXPIRATION_TIME, SESSION_ID, AUTH_ROLE FROM CB_AUTH_TOKEN WHERE TOKEN_ID=?"); ) { dbStat.setString(1, token); try (var dbResult = dbStat.executeQuery()) { @@ -1439,11 +1462,12 @@ public class CBEmbeddedSecurityController implements SMAdminController, SMAuthen throw new SMAccessTokenExpiredException("Token expired"); } sessionId = dbResult.getString(3); + authRole = dbResult.getString(4); } } catch (SQLException e) { throw new DBCException("Error reading token info in database", e); } - var permissions = userId == null ? getAnonymousUserPermissions() : getUserPermissions(userId); + var permissions = userId == null ? getAnonymousUserPermissions() : getUserPermissions(userId, authRole); return new SMAuthPermissions(userId, sessionId, permissions); } @@ -1491,22 +1515,12 @@ public class CBEmbeddedSecurityController implements SMAdminController, SMAuthen try (Connection dbCon = database.openConnection()) { try (PreparedStatement dbStat = dbCon.prepareStatement( "UPDATE CB_SESSION SET USER_ID=?,LAST_ACCESS_TIME=?,LAST_ACCESS_REMOTE_ADDRESS=?,LAST_ACCESS_USER_AGENT=?,LAST_ACCESS_INSTANCE_ID=? WHERE SESSION_ID=?")) { - if (userId == null) { - dbStat.setNull(1, Types.VARCHAR); - } else { - dbStat.setString(1, userId); - } + JDBCUtils.setStringOrNull(dbStat, 1, userId); dbStat.setTimestamp(2, new Timestamp(System.currentTimeMillis())); - if (parameters.get(SMConstants.SESSION_PARAM_LAST_REMOTE_ADDRESS) != null) { - dbStat.setString(3, CommonUtils.truncateString(parameters.get(SMConstants.SESSION_PARAM_LAST_REMOTE_ADDRESS).toString(), 128)); - } else { - dbStat.setNull(3, Types.VARCHAR); - } - if (parameters.get(SMConstants.SESSION_PARAM_LAST_REMOTE_USER_AGENT) != null) { - dbStat.setString(4, CommonUtils.truncateString(parameters.get(SMConstants.SESSION_PARAM_LAST_REMOTE_USER_AGENT).toString(), 255)); - } else { - dbStat.setNull(4, Types.VARCHAR); - } + JDBCUtils.setStringOrNull(dbStat, 3, CommonUtils.truncateString(CommonUtils.toString( + parameters.get(SMConstants.SESSION_PARAM_LAST_REMOTE_ADDRESS), null), 128)); + JDBCUtils.setStringOrNull(dbStat, 4, CommonUtils.truncateString(CommonUtils.toString( + parameters.get(SMConstants.SESSION_PARAM_LAST_REMOTE_USER_AGENT), null), 255)); dbStat.setString(5, database.getInstanceId()); dbStat.setString(6, sessionId); @@ -1630,10 +1644,10 @@ public class CBEmbeddedSecurityController implements SMAdminController, SMAuthen private Set getAllLinkedSubjects(String subjectId) throws DBException { Set allSubjects = new HashSet<>(); allSubjects.add(subjectId); - var userRoleIds = Arrays.stream(getUserRoles(subjectId)) - .map(SMRole::getRoleId) + var userTeamIds = Arrays.stream(getUserTeams(subjectId)) + .map(SMTeam::getTeamId) .collect(Collectors.toSet()); - allSubjects.addAll(userRoleIds); + allSubjects.addAll(userTeamIds); return allSubjects; } diff --git a/server/bundles/io.cloudbeaver.service.security/src/io/cloudbeaver/service/security/db/CBDatabase.java b/server/bundles/io.cloudbeaver.service.security/src/io/cloudbeaver/service/security/db/CBDatabase.java index 0f50bf591e..29cc7b57ec 100644 --- a/server/bundles/io.cloudbeaver.service.security/src/io/cloudbeaver/service/security/db/CBDatabase.java +++ b/server/bundles/io.cloudbeaver.service.security/src/io/cloudbeaver/service/security/db/CBDatabase.java @@ -36,7 +36,7 @@ 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.SMAdminController; -import org.jkiss.dbeaver.model.security.user.SMRole; +import org.jkiss.dbeaver.model.security.user.SMTeam; import org.jkiss.dbeaver.model.security.user.SMUser; import org.jkiss.dbeaver.model.sql.schema.ClassLoaderScriptSource; import org.jkiss.dbeaver.model.sql.schema.SQLSchemaManager; @@ -68,7 +68,7 @@ public class CBDatabase { public static final String SCHEMA_UPDATE_SQL_PATH = "db/cb_schema_update_"; private static final int LEGACY_SCHEMA_VERSION = 1; - private static final int CURRENT_SCHEMA_VERSION = 10; + private static final int CURRENT_SCHEMA_VERSION = 11; private static final String DEFAULT_DB_USER_NAME = "cb-data"; private static final String DEFAULT_DB_PWD_FILE = ".database-credentials.dat"; @@ -245,7 +245,7 @@ public class CBDatabase { SMUser adminUser = adminSecurityController.getUserById(adminName); if (adminUser == null) { - adminUser = new SMUser(adminName); + adminUser = new SMUser(adminName, true); adminSecurityController.createUser(adminUser.getUserId(), adminUser.getMetaParameters(), true); } @@ -269,11 +269,11 @@ public class CBDatabase { } private void grantAdminPermissionsToUser(String userId) throws DBException { - // Grant all roles - SMRole[] allRoles = adminSecurityController.readAllRoles(); - adminSecurityController.setUserRoles( + // Grant all teams + SMTeam[] allTeams = adminSecurityController.readAllTeams(); + adminSecurityController.setUserTeams( userId, - Arrays.stream(allRoles).map(SMRole::getRoleId).toArray(String[]::new), + Arrays.stream(allTeams).map(SMTeam::getTeamId).toArray(String[]::new), userId); } @@ -345,12 +345,12 @@ public class CBDatabase { String adminName = initialData.getAdminName(); String adminPassword = initialData.getAdminPassword(); - if (!CommonUtils.isEmpty(initialData.getRoles())) { - // Create roles - for (SMRole role : initialData.getRoles()) { - adminSecurityController.createRole(role.getRoleId(), role.getName(), role.getDescription(), adminName); + if (!CommonUtils.isEmpty(initialData.getTeams())) { + // Create teams + for (SMTeam team : initialData.getTeams()) { + adminSecurityController.createTeam(team.getTeamId(), team.getName(), team.getDescription(), adminName); if (adminName != null) { - adminSecurityController.setSubjectPermissions(role.getRoleId(), new ArrayList<>(role.getPermissions()), adminName); + adminSecurityController.setSubjectPermissions(team.getTeamId(), new ArrayList<>(team.getPermissions()), adminName); } } } diff --git a/server/bundles/io.cloudbeaver.service.security/src/io/cloudbeaver/service/security/db/CBDatabaseInitialData.java b/server/bundles/io.cloudbeaver.service.security/src/io/cloudbeaver/service/security/db/CBDatabaseInitialData.java index df55a6169b..e78f506968 100644 --- a/server/bundles/io.cloudbeaver.service.security/src/io/cloudbeaver/service/security/db/CBDatabaseInitialData.java +++ b/server/bundles/io.cloudbeaver.service.security/src/io/cloudbeaver/service/security/db/CBDatabaseInitialData.java @@ -16,14 +16,14 @@ */ package io.cloudbeaver.service.security.db; -import org.jkiss.dbeaver.model.security.user.SMRole; +import org.jkiss.dbeaver.model.security.user.SMTeam; import java.util.List; class CBDatabaseInitialData { private String adminName = "cbadmin"; private String adminPassword = "cbadmin20"; - private List roles; + private List teams; public String getAdminName() { return adminName; @@ -33,11 +33,11 @@ class CBDatabaseInitialData { return adminPassword; } - public List getRoles() { - return roles; + public List getTeams() { + return teams; } - public void setRoles(List roles) { - this.roles = roles; + public void setTeams(List teams) { + this.teams = teams; } } diff --git a/server/product/web-server/CloudbeaverServer.product.launch b/server/product/web-server/CloudbeaverServer.product.launch index f2752415aa..4ebc339734 100644 --- a/server/product/web-server/CloudbeaverServer.product.launch +++ b/server/product/web-server/CloudbeaverServer.product.launch @@ -23,7 +23,7 @@ - + @@ -97,7 +97,7 @@ - + diff --git a/server/test/io.cloudbeaver.test.platform/src/io/cloudbeaver/test/platform/CEServerTestSuite.java b/server/test/io.cloudbeaver.test.platform/src/io/cloudbeaver/test/platform/CEServerTestSuite.java index a0b6874783..8f5e489535 100644 --- a/server/test/io.cloudbeaver.test.platform/src/io/cloudbeaver/test/platform/CEServerTestSuite.java +++ b/server/test/io.cloudbeaver.test.platform/src/io/cloudbeaver/test/platform/CEServerTestSuite.java @@ -50,7 +50,9 @@ public class CEServerTestSuite { } else { System.out.println("Start CBApplication"); testApp = new CBApplication(); - thread = new Thread(() -> testApp.start(null)); + thread = new Thread(() -> { + testApp.start(null); + }); thread.start(); client = HttpClient.newBuilder() .cookieHandler(new CookieManager()) diff --git a/server/test/io.cloudbeaver.test.platform/workspace/conf/initial-data.conf b/server/test/io.cloudbeaver.test.platform/workspace/conf/initial-data.conf index 8821070c42..718fa039bc 100644 --- a/server/test/io.cloudbeaver.test.platform/workspace/conf/initial-data.conf +++ b/server/test/io.cloudbeaver.test.platform/workspace/conf/initial-data.conf @@ -1,15 +1,15 @@ { adminName: "test", adminPassword: "test", - roles: [ + teams: [ { - roleId: "admin", + teamId: "admin", name: "Admin", description: "Administrative access. Has all permissions.", permissions: [ "public", "admin" ] }, { - roleId: "user", + teamId: "user", name: "User", description: "Standard user", permissions: [ "public" ] diff --git a/server/test/io.cloudbeaver.test.platform/workspace/conf/logback.xml b/server/test/io.cloudbeaver.test.platform/workspace/conf/logback.xml index cc255a06b8..4b6241843a 100644 --- a/server/test/io.cloudbeaver.test.platform/workspace/conf/logback.xml +++ b/server/test/io.cloudbeaver.test.platform/workspace/conf/logback.xml @@ -3,7 +3,7 @@ - INFO + DEBUG ACCEPT DENY diff --git a/webapp/packages/core-authentication/src/RolesResource.ts b/webapp/packages/core-authentication/src/RolesResource.ts deleted file mode 100644 index 3635f4a127..0000000000 --- a/webapp/packages/core-authentication/src/RolesResource.ts +++ /dev/null @@ -1,164 +0,0 @@ -/* - * 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 { - GraphQLService, - CachedMapResource, - ResourceKey, - resourceKeyList, - ResourceKeyList, - ResourceKeyUtils, - AdminRoleInfoFragment, - AdminConnectionGrantInfo, - CachedMapAllKey -} from '@cloudbeaver/core-sdk'; -import { isArraysEqual } from '@cloudbeaver/core-utils'; - -const NEW_ROLE_SYMBOL = Symbol('new-role'); - -export type RoleInfo = AdminRoleInfoFragment; -type NewRole = RoleInfo & { [NEW_ROLE_SYMBOL]: boolean; timestamp: number }; - -@injectable() -export class RolesResource extends CachedMapResource { - constructor(private readonly graphQLService: GraphQLService) { - super(); - } - - async loadAll(): Promise> { - await this.load(CachedMapAllKey); - return this.data; - } - - async refreshAll(): Promise> { - await this.refresh(CachedMapAllKey); - return this.data; - } - - async createRole(roleInfo: RoleInfo): Promise { - const response = await this.graphQLService.sdk.createRole(roleInfo); - - const newRole: NewRole = { - ...response.role, - [NEW_ROLE_SYMBOL]: true, - timestamp: Date.now(), - }; - - this.updateRoles(newRole); - - await this.setSubjectPermissions(newRole.roleId, roleInfo.rolePermissions); - - return this.get(roleInfo.roleId)!; - } - - async updateRole(roleInfo: RoleInfo): Promise { - const { role } = await this.graphQLService.sdk.updateRole(roleInfo); - - this.updateRoles(role); - - await this.setSubjectPermissions(role.roleId, roleInfo.rolePermissions); - - return this.get(roleInfo.roleId)!; - } - - async deleteRole(key: ResourceKey): Promise> { - await ResourceKeyUtils.forEachAsync(key, async key => { - await this.graphQLService.sdk.deleteRole({ - roleId: key, - }); - this.delete(key); - }); - - return this.data; - } - - async loadGrantedUsers(roleId: string): Promise { - const { role } = await this.graphQLService.sdk.getRoleGrantedUsers({ roleId }); - return role[0].grantedUsers; - } - - async getSubjectConnectionAccess(subjectId: string): Promise { - const { grantInfo } = await this.graphQLService.sdk.getSubjectConnectionAccess({ subjectId }); - return grantInfo; - } - - async setSubjectPermissions(roleId: string, permissions: string[]): Promise { - const role = this.get(roleId); - - if (role && isArraysEqual(role.rolePermissions, permissions)) { - return; - } - - const { - permissions: newPermissions, - } = await this.graphQLService.sdk.setSubjectPermissions({ roleId, permissions }); - - if (role) { - role.rolePermissions = newPermissions.map(permission => permission.id); - } else { - // TODO: update permissions for role instead - await this.loader(roleId); - } - } - - protected async loader(key: ResourceKey): Promise> { - const all = ResourceKeyUtils.includes(key, CachedMapAllKey); - - await ResourceKeyUtils.forEachAsync(all ? CachedMapAllKey : key, async key => { - const roleId = all ? undefined : key; - - const { roles } = await this.graphQLService.sdk.getRolesList({ - roleId, - }); - - if (all) { - this.data.clear(); - } - - this.updateRoles(...roles); - }); - - return this.data; - } - - cleanNewFlags(): void { - for (const role of this.data.values()) { - (role as NewRole)[NEW_ROLE_SYMBOL] = false; - } - } - - private updateRoles(...roles: RoleInfo[]): ResourceKeyList { - const key = resourceKeyList(roles.map(role => role.roleId)); - - const oldRoles = this.get(key); - this.set(key, oldRoles.map((role, i) => ({ ...role, ...roles[i] }))); - - return key; - } -} - -function isNewRole(role: RoleInfo | NewRole): role is NewRole { - return (role as NewRole)[NEW_ROLE_SYMBOL]; -} - -export function compareRoles(a: RoleInfo, b: RoleInfo): number { - if (isNewRole(a) && isNewRole(b)) { - return b.timestamp - a.timestamp; - } - - if (isNewRole(b)) { - return 1; - } - - if (isNewRole(a)) { - return -1; - } - - return a.roleId.localeCompare(b.roleId); -} diff --git a/webapp/packages/core-authentication/src/RolesManagerService.ts b/webapp/packages/core-authentication/src/TeamsManagerService.ts similarity index 72% rename from webapp/packages/core-authentication/src/RolesManagerService.ts rename to webapp/packages/core-authentication/src/TeamsManagerService.ts index 23dd5d896a..9d6fe3a71e 100644 --- a/webapp/packages/core-authentication/src/RolesManagerService.ts +++ b/webapp/packages/core-authentication/src/TeamsManagerService.ts @@ -8,12 +8,12 @@ import { injectable } from '@cloudbeaver/core-di'; -import { RolesResource } from './RolesResource'; +import { TeamsResource } from './TeamsResource'; @injectable() -export class RolesManagerService { +export class TeamsManagerService { constructor( - readonly roles: RolesResource + readonly teams: TeamsResource ) { } } diff --git a/webapp/packages/core-authentication/src/TeamsResource.ts b/webapp/packages/core-authentication/src/TeamsResource.ts new file mode 100644 index 0000000000..47cc793a75 --- /dev/null +++ b/webapp/packages/core-authentication/src/TeamsResource.ts @@ -0,0 +1,164 @@ +/* + * 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 { + GraphQLService, + CachedMapResource, + ResourceKey, + resourceKeyList, + ResourceKeyList, + ResourceKeyUtils, + AdminTeamInfoFragment, + AdminConnectionGrantInfo, + CachedMapAllKey +} from '@cloudbeaver/core-sdk'; +import { isArraysEqual } from '@cloudbeaver/core-utils'; + +const NEW_TEAM_SYMBOL = Symbol('new-team'); + +export type TeamInfo = AdminTeamInfoFragment; +type NewTeam = TeamInfo & { [NEW_TEAM_SYMBOL]: boolean; timestamp: number }; + +@injectable() +export class TeamsResource extends CachedMapResource { + constructor(private readonly graphQLService: GraphQLService) { + super(); + } + + async loadAll(): Promise> { + await this.load(CachedMapAllKey); + return this.data; + } + + async refreshAll(): Promise> { + await this.refresh(CachedMapAllKey); + return this.data; + } + + async createTeam(teamInfo: TeamInfo): Promise { + const response = await this.graphQLService.sdk.createTeam(teamInfo); + + const newTeam: NewTeam = { + ...response.team, + [NEW_TEAM_SYMBOL]: true, + timestamp: Date.now(), + }; + + this.updateTeams(newTeam); + + await this.setSubjectPermissions(newTeam.teamId, teamInfo.teamPermissions); + + return this.get(teamInfo.teamId)!; + } + + async updateTeam(teamInfo: TeamInfo): Promise { + const { team } = await this.graphQLService.sdk.updateTeam(teamInfo); + + this.updateTeams(team); + + await this.setSubjectPermissions(team.teamId, teamInfo.teamPermissions); + + return this.get(teamInfo.teamId)!; + } + + async deleteTeam(key: ResourceKey): Promise> { + await ResourceKeyUtils.forEachAsync(key, async key => { + await this.graphQLService.sdk.deleteTeam({ + teamId: key, + }); + this.delete(key); + }); + + return this.data; + } + + async loadGrantedUsers(teamId: string): Promise { + const { team } = await this.graphQLService.sdk.getTeamGrantedUsers({ teamId }); + return team[0].grantedUsers; + } + + async getSubjectConnectionAccess(subjectId: string): Promise { + const { grantInfo } = await this.graphQLService.sdk.getSubjectConnectionAccess({ subjectId }); + return grantInfo; + } + + async setSubjectPermissions(subjectId: string, permissions: string[]): Promise { + const team = this.get(subjectId); + + if (team && isArraysEqual(team.teamPermissions, permissions)) { + return; + } + + const { + permissions: newPermissions, + } = await this.graphQLService.sdk.setSubjectPermissions({ subjectId, permissions }); + + if (team) { + team.teamPermissions = newPermissions.map(permission => permission.id); + } else { + // TODO: update permissions for team instead + await this.loader(subjectId); + } + } + + protected async loader(key: ResourceKey): Promise> { + const all = ResourceKeyUtils.includes(key, CachedMapAllKey); + + await ResourceKeyUtils.forEachAsync(all ? CachedMapAllKey : key, async key => { + const teamId = all ? undefined : key; + + const { teams } = await this.graphQLService.sdk.getTeamsList({ + teamId, + }); + + if (all) { + this.data.clear(); + } + + this.updateTeams(...teams); + }); + + return this.data; + } + + cleanNewFlags(): void { + for (const team of this.data.values()) { + (team as NewTeam)[NEW_TEAM_SYMBOL] = false; + } + } + + private updateTeams(...teams: TeamInfo[]): ResourceKeyList { + const key = resourceKeyList(teams.map(team => team.teamId)); + + const oldTeams = this.get(key); + this.set(key, oldTeams.map((team, i) => ({ ...team, ...teams[i] }))); + + return key; + } +} + +function isNewTeam(team: TeamInfo | NewTeam): team is NewTeam { + return (team as NewTeam)[NEW_TEAM_SYMBOL]; +} + +export function compareTeams(a: TeamInfo, b: TeamInfo): number { + if (isNewTeam(a) && isNewTeam(b)) { + return b.timestamp - a.timestamp; + } + + if (isNewTeam(b)) { + return 1; + } + + if (isNewTeam(a)) { + return -1; + } + + return a.teamId.localeCompare(b.teamId); +} diff --git a/webapp/packages/core-authentication/src/UsersResource.ts b/webapp/packages/core-authentication/src/UsersResource.ts index aef9b6ae0c..fc95688dd8 100644 --- a/webapp/packages/core-authentication/src/UsersResource.ts +++ b/webapp/packages/core-authentication/src/UsersResource.ts @@ -37,7 +37,7 @@ type UserResourceIncludes = Omit; interface UserCreateOptions { userId: string; - roles: string[]; + teams: string[]; credentials: IAuthCredentials; metaParameters: Record; grantedConnections: string[]; @@ -66,7 +66,7 @@ export class UsersResource extends CachedMapResource { const { user } = await this.graphQLService.sdk.createUser({ userId, @@ -106,8 +106,8 @@ export class UsersResource extends CachedMapResource { - await this.graphQLService.sdk.grantUserRole({ userId, roleId }); + async grantTeam(userId: string, teamId: string, skipUpdate?: boolean): Promise { + await this.graphQLService.sdk.grantUserTeam({ userId, teamId }); if (!skipUpdate) { await this.refresh(userId); } } - async revokeRole(userId: string, roleId: string, skipUpdate?: boolean): Promise { - await this.graphQLService.sdk.revokeUserRole({ userId, roleId }); + async revokeTeam(userId: string, teamId: string, skipUpdate?: boolean): Promise { + await this.graphQLService.sdk.revokeUserTeam({ userId, teamId }); if (!skipUpdate) { await this.refresh(userId); diff --git a/webapp/packages/core-authentication/src/index.ts b/webapp/packages/core-authentication/src/index.ts index 27986d60b8..648102fcb7 100644 --- a/webapp/packages/core-authentication/src/index.ts +++ b/webapp/packages/core-authentication/src/index.ts @@ -9,8 +9,8 @@ export * from './DATA_CONTEXT_USER'; export * from './IAuthCredentials'; export * from './AuthConfigurationsResource'; export * from './AuthConfigurationParametersResource'; -export * from './RolesManagerService'; -export * from './RolesResource'; +export * from './TeamsManagerService'; +export * from './TeamsResource'; export * from './UserDataService'; export * from './UserInfoResource'; export * from './UserMetaParametersResource'; diff --git a/webapp/packages/core-authentication/src/manifest.ts b/webapp/packages/core-authentication/src/manifest.ts index c9601effc4..36231392a2 100644 --- a/webapp/packages/core-authentication/src/manifest.ts +++ b/webapp/packages/core-authentication/src/manifest.ts @@ -15,8 +15,8 @@ import { AuthInfoService } from './AuthInfoService'; import { AuthProviderService } from './AuthProviderService'; import { AuthProvidersResource } from './AuthProvidersResource'; import { AuthSettingsService } from './AuthSettingsService'; -import { RolesManagerService } from './RolesManagerService'; -import { RolesResource } from './RolesResource'; +import { TeamsManagerService } from './TeamsManagerService'; +import { TeamsResource } from './TeamsResource'; import { UserConfigurationBootstrap } from './UserConfigurationBootstrap'; import { UserDataService } from './UserDataService'; import { UserInfoResource } from './UserInfoResource'; @@ -36,8 +36,8 @@ export const manifest: PluginManifest = { AuthSettingsService, AuthConfigurationsResource, AuthConfigurationParametersResource, - RolesManagerService, - RolesResource, + TeamsManagerService, + TeamsResource, UserDataService, UserInfoResource, UsersResource, diff --git a/webapp/packages/core-blocks/src/index.ts b/webapp/packages/core-blocks/src/index.ts index d4cc427a2f..9cd016638e 100644 --- a/webapp/packages/core-blocks/src/index.ts +++ b/webapp/packages/core-blocks/src/index.ts @@ -146,6 +146,7 @@ export * from './Link'; export * from './Cell'; export * from './UploadArea'; export * from './ErrorMessage'; +export * from './preventFocusHandler'; export * from './StatusMessage'; export * from './ExceptionMessage'; export * from './getComputed'; diff --git a/webapp/packages/core-blocks/src/preventFocusHandler.ts b/webapp/packages/core-blocks/src/preventFocusHandler.ts new file mode 100644 index 0000000000..8bb574b0d0 --- /dev/null +++ b/webapp/packages/core-blocks/src/preventFocusHandler.ts @@ -0,0 +1,11 @@ +/* + * 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. + */ + +export function preventFocusHandler(event: React.MouseEvent) { + event.preventDefault(); +} \ No newline at end of file diff --git a/webapp/packages/core-connections/public/icons/role.svg b/webapp/packages/core-connections/public/icons/team.svg similarity index 100% rename from webapp/packages/core-connections/public/icons/role.svg rename to webapp/packages/core-connections/public/icons/team.svg diff --git a/webapp/packages/core-connections/src/locales/en.ts b/webapp/packages/core-connections/src/locales/en.ts index 995bfdeafe..27e791be66 100644 --- a/webapp/packages/core-connections/src/locales/en.ts +++ b/webapp/packages/core-connections/src/locales/en.ts @@ -5,7 +5,7 @@ export default [ ['connections_administration_new_connection', 'New connection'], ['connections_administration_connection_create_error', 'Create connection error'], ['connections_administration_connection_save_error', 'Save connection error'], - ['connections_administration_connection_access_empty', 'No available users and roles'], + ['connections_administration_connection_access_empty', 'No available users and teams'], ['connections_administration_configuration_wizard_step_title', 'Database connections'], ['connections_administration_configuration_wizard_step_description', 'Add database connections'], ['connections_administration_configuration_wizard_title', 'Add database connections'], @@ -28,15 +28,15 @@ export default [ ['connections_connection_edit_authentication', 'Authentication'], ['connections_connection_edit_access', 'Access'], ['connections_connection_edit_access_load_failed', 'Fail to get connection access'], - ['connections_connection_edit_access_role', 'Role'], + ['connections_connection_edit_access_team', 'Team'], ['connections_connection_edit_search', 'Search'], ['connections_connection_edit_search_hosts', 'Host names'], ['connections_connection_address', 'Address'], ['connections_connection_folder', 'Folder'], ['connections_connection_folder_validation', 'Folder\'s name may contain the following symbols "_-$.()@" and can\'t start with a dot'], ['connections_connection_name', 'Connection name'], - ['connections_connection_access_user_or_role_name', 'User or Role name'], - ['connections_connection_access_filter_placeholder', 'Search for user or role name'], + ['connections_connection_access_user_or_team_name', 'User or Team name'], + ['connections_connection_access_filter_placeholder', 'Search for user or team name'], ['connections_connection_access_admin_info', 'Administrators see all connections.'], ['connections_connection_description', 'Description'], ['connections_connection_project', 'Project'], diff --git a/webapp/packages/core-connections/src/locales/it.ts b/webapp/packages/core-connections/src/locales/it.ts index 459eac0296..f878fabe07 100644 --- a/webapp/packages/core-connections/src/locales/it.ts +++ b/webapp/packages/core-connections/src/locales/it.ts @@ -5,7 +5,6 @@ export default [ ['connections_administration_new_connection', 'Nuova Connessione'], ['connections_administration_connection_create_error', 'Errore di creazione connessione'], ['connections_administration_connection_save_error', 'Errore di salvataggio connessione'], - ['connections_administration_connection_access_empty', 'Non ci sono utenti e ruoli disponibili'], ['connections_administration_configuration_wizard_step_title', 'Connessioni ai Database'], ['connections_administration_configuration_wizard_step_description', 'Aggiungi connessione al database'], ['connections_administration_configuration_wizard_title', 'Aggiungi connessione al database'], @@ -27,18 +26,15 @@ export default [ ['connections_connection_edit_authentication', 'Autenticazione'], ['connections_connection_edit_access', 'Accesso'], ['connections_connection_edit_access_load_failed', 'Errore al recupero dell\'accesso alla connessione'], - ['connections_connection_edit_access_role', 'Ruolo'], ['connections_connection_edit_search', 'Cerca'], ['connections_connection_edit_search_hosts', 'Host names'], ['connections_connection_address', 'Indirizzo'], ['connections_connection_folder', 'Folder'], ['connections_connection_folder_validation', 'Folder\'s name may contain the following symbols "_-$.()@" and can\'t start with a dot'], ['connections_connection_name', 'Nome della connessione'], - ['connections_connection_access_user_or_role_name', 'Nome dell\'Utente o del ruolo'], ['connections_connection_access_revoke', 'Revoca'], ['connections_connection_access_grant', 'Permetti'], ['connections_connection_access_edit', 'Modifica'], - ['connections_connection_access_filter_placeholder', 'Cerca per utente o ruolo'], ['connections_connection_access_admin_info', 'Gli amministratori vedono tutte le connessioni.'], ['connections_connection_description', 'Descrizione'], ['connections_connection_driver', 'Driver'], diff --git a/webapp/packages/core-connections/src/locales/ru.ts b/webapp/packages/core-connections/src/locales/ru.ts index 95aba0ed5b..b5bd3acfee 100644 --- a/webapp/packages/core-connections/src/locales/ru.ts +++ b/webapp/packages/core-connections/src/locales/ru.ts @@ -25,15 +25,15 @@ export default [ ['connections_connection_edit_authentication', 'Авторизация'], ['connections_connection_edit_access', 'Доступ'], ['connections_connection_edit_access_load_failed', 'Не удалось загрузить информацию доступа'], - ['connections_connection_edit_access_role', 'Роль'], + ['connections_connection_edit_access_team', 'Команда'], ['connections_connection_edit_search', 'Поиск'], ['connections_connection_edit_search_hosts', 'Названия хостов'], ['connections_connection_address', 'Адрес'], ['connections_connection_folder', 'Папка'], ['connections_connection_folder_validation', 'Имя папки может содержать следующие символы "_-$.()@" и не может начинаться с точки'], ['connections_connection_name', 'Название подключения'], - ['connections_connection_access_user_or_role_name', 'Имя пользователя или роли'], - ['connections_connection_access_filter_placeholder', 'Поиск по имени пользователя или роли'], + ['connections_connection_access_user_or_team_name', 'Имя пользователя или команды'], + ['connections_connection_access_filter_placeholder', 'Поиск по имени пользователя или команде'], ['connections_connection_access_admin_info', 'Администраторы видят все подключения.'], ['connections_connection_description', 'Описание'], ['connections_connection_project', 'Проект'], diff --git a/webapp/packages/core-connections/src/locales/zh.ts b/webapp/packages/core-connections/src/locales/zh.ts index bbba3eb1b5..20137d2810 100644 --- a/webapp/packages/core-connections/src/locales/zh.ts +++ b/webapp/packages/core-connections/src/locales/zh.ts @@ -5,7 +5,6 @@ export default [ ['connections_administration_new_connection', '新连接'], ['connections_administration_connection_create_error', '创建连接失败'], ['connections_administration_connection_save_error', '保存链接失败'], - ['connections_administration_connection_access_empty', '没有可用用户和角色'], ['connections_administration_configuration_wizard_step_title', '数据库连接'], ['connections_administration_configuration_wizard_step_description', '添加数据库连接'], ['connections_administration_configuration_wizard_title', '添加数据库连接'], @@ -28,15 +27,12 @@ export default [ ['connections_connection_edit_authentication', '认证'], ['connections_connection_edit_access', '权限'], ['connections_connection_edit_access_load_failed', '无法获取连接访问权限'], - ['connections_connection_edit_access_role', '角色'], ['connections_connection_edit_search', '搜索'], ['connections_connection_edit_search_hosts', '主机名称'], ['connections_connection_address', '地址'], ['connections_connection_folder', 'Folder'], ['connections_connection_folder_validation', 'Folder\'s name may contain the following symbols "_-$.()@" and can\'t start with a dot'], ['connections_connection_name', '连接名称'], - ['connections_connection_access_user_or_role_name', '用户或角色名称'], - ['connections_connection_access_filter_placeholder', '搜索用户或角色名称'], ['connections_connection_access_admin_info', '管理员查看所有连接。'], ['connections_connection_description', '描述'], ['connections_connection_project', 'Project'], diff --git a/webapp/packages/core-sdk/src/queries/administration/setSubjectPermissions.gql b/webapp/packages/core-sdk/src/queries/administration/setSubjectPermissions.gql index 018c289763..2482a11efd 100644 --- a/webapp/packages/core-sdk/src/queries/administration/setSubjectPermissions.gql +++ b/webapp/packages/core-sdk/src/queries/administration/setSubjectPermissions.gql @@ -1,5 +1,5 @@ -query setSubjectPermissions($roleId: ID!, $permissions: [ID!]! ) { - permissions: setSubjectPermissions(roleId: $roleId, permissions: $permissions) { +query setSubjectPermissions($subjectId: ID!, $permissions: [ID!]! ) { + permissions: setSubjectPermissions(subjectId: $subjectId, permissions: $permissions) { ...AdminPermissionInfo } } \ No newline at end of file diff --git a/webapp/packages/core-sdk/src/queries/authentication/Roles/createRole.gql b/webapp/packages/core-sdk/src/queries/authentication/Roles/createRole.gql deleted file mode 100644 index 72fc091327..0000000000 --- a/webapp/packages/core-sdk/src/queries/authentication/Roles/createRole.gql +++ /dev/null @@ -1,5 +0,0 @@ -query createRole($roleId: ID!, $roleName: String, $description: String ) { - role: createRole(roleId: $roleId, roleName: $roleName, description: $description) { - ...AdminRoleInfo - } -} \ No newline at end of file diff --git a/webapp/packages/core-sdk/src/queries/authentication/Roles/deleteRole.gql b/webapp/packages/core-sdk/src/queries/authentication/Roles/deleteRole.gql deleted file mode 100644 index 9ccaa6c1e1..0000000000 --- a/webapp/packages/core-sdk/src/queries/authentication/Roles/deleteRole.gql +++ /dev/null @@ -1,3 +0,0 @@ -query deleteRole($roleId: ID!) { - deleteRole(roleId: $roleId) -} \ No newline at end of file diff --git a/webapp/packages/core-sdk/src/queries/authentication/Roles/getRoleGrantedUsers.gql b/webapp/packages/core-sdk/src/queries/authentication/Roles/getRoleGrantedUsers.gql deleted file mode 100644 index 398b2a64de..0000000000 --- a/webapp/packages/core-sdk/src/queries/authentication/Roles/getRoleGrantedUsers.gql +++ /dev/null @@ -1,5 +0,0 @@ -query getRoleGrantedUsers($roleId: ID!) { - role: listRoles(roleId: $roleId) { - grantedUsers - } -} \ No newline at end of file diff --git a/webapp/packages/core-sdk/src/queries/authentication/Roles/getRolesList.gql b/webapp/packages/core-sdk/src/queries/authentication/Roles/getRolesList.gql deleted file mode 100644 index 8768413470..0000000000 --- a/webapp/packages/core-sdk/src/queries/authentication/Roles/getRolesList.gql +++ /dev/null @@ -1,5 +0,0 @@ -query getRolesList($roleId: ID) { - roles: listRoles(roleId: $roleId) { - ...AdminRoleInfo - } -} \ No newline at end of file diff --git a/webapp/packages/core-sdk/src/queries/authentication/Roles/updateRole.gql b/webapp/packages/core-sdk/src/queries/authentication/Roles/updateRole.gql deleted file mode 100644 index a35a5ba5f7..0000000000 --- a/webapp/packages/core-sdk/src/queries/authentication/Roles/updateRole.gql +++ /dev/null @@ -1,5 +0,0 @@ -query updateRole($roleId: ID!, $roleName: String, $description: String ) { - role: updateRole(roleId: $roleId, roleName: $roleName, description: $description) { - ...AdminRoleInfo - } -} \ No newline at end of file diff --git a/webapp/packages/core-sdk/src/queries/authentication/teams/createTeam.gql b/webapp/packages/core-sdk/src/queries/authentication/teams/createTeam.gql new file mode 100644 index 0000000000..6617ea956f --- /dev/null +++ b/webapp/packages/core-sdk/src/queries/authentication/teams/createTeam.gql @@ -0,0 +1,5 @@ +query createTeam($teamId: ID!, $teamName: String, $description: String ) { + team: createTeam(teamId: $teamId, teamName: $teamName, description: $description) { + ...AdminTeamInfo + } +} \ No newline at end of file diff --git a/webapp/packages/core-sdk/src/queries/authentication/teams/deleteTeam.gql b/webapp/packages/core-sdk/src/queries/authentication/teams/deleteTeam.gql new file mode 100644 index 0000000000..c5c93a29e8 --- /dev/null +++ b/webapp/packages/core-sdk/src/queries/authentication/teams/deleteTeam.gql @@ -0,0 +1,3 @@ +query deleteTeam($teamId: ID!) { + deleteTeam(teamId: $teamId) +} \ No newline at end of file diff --git a/webapp/packages/core-sdk/src/queries/authentication/teams/getTeamGrantedUsers.gql b/webapp/packages/core-sdk/src/queries/authentication/teams/getTeamGrantedUsers.gql new file mode 100644 index 0000000000..9948138666 --- /dev/null +++ b/webapp/packages/core-sdk/src/queries/authentication/teams/getTeamGrantedUsers.gql @@ -0,0 +1,5 @@ +query getTeamGrantedUsers($teamId: ID!) { + team: listTeams(teamId: $teamId) { + grantedUsers + } +} \ 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 new file mode 100644 index 0000000000..a7f4901739 --- /dev/null +++ b/webapp/packages/core-sdk/src/queries/authentication/teams/getTeamsList.gql @@ -0,0 +1,5 @@ +query getTeamsList($teamId: ID) { + teams: listTeams(teamId: $teamId) { + ...AdminTeamInfo + } +} \ 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 new file mode 100644 index 0000000000..5b7d115b79 --- /dev/null +++ b/webapp/packages/core-sdk/src/queries/authentication/teams/updateTeam.gql @@ -0,0 +1,5 @@ +query updateTeam($teamId: ID!, $teamName: String, $description: String ) { + team: updateTeam(teamId: $teamId, teamName: $teamName, description: $description) { + ...AdminTeamInfo + } +} \ No newline at end of file diff --git a/webapp/packages/core-sdk/src/queries/authentication/users/grantUserRole.gql b/webapp/packages/core-sdk/src/queries/authentication/users/grantUserRole.gql deleted file mode 100644 index b0e3c5325f..0000000000 --- a/webapp/packages/core-sdk/src/queries/authentication/users/grantUserRole.gql +++ /dev/null @@ -1,3 +0,0 @@ -query grantUserRole($userId: ID!, $roleId: ID!) { - grantUserRole(userId: $userId, roleId: $roleId) -} \ No newline at end of file diff --git a/webapp/packages/core-sdk/src/queries/authentication/users/grantUserTeam.gql b/webapp/packages/core-sdk/src/queries/authentication/users/grantUserTeam.gql new file mode 100644 index 0000000000..bd02e4bcf1 --- /dev/null +++ b/webapp/packages/core-sdk/src/queries/authentication/users/grantUserTeam.gql @@ -0,0 +1,3 @@ +query grantUserTeam($userId: ID!, $teamId: ID!) { + grantUserTeam(userId: $userId, teamId: $teamId) +} \ No newline at end of file diff --git a/webapp/packages/core-sdk/src/queries/authentication/users/revokeUserRole.gql b/webapp/packages/core-sdk/src/queries/authentication/users/revokeUserRole.gql deleted file mode 100644 index 2590b783a9..0000000000 --- a/webapp/packages/core-sdk/src/queries/authentication/users/revokeUserRole.gql +++ /dev/null @@ -1,3 +0,0 @@ -query revokeUserRole($userId: ID!, $roleId: ID!) { - revokeUserRole(userId: $userId, roleId: $roleId) -} \ No newline at end of file diff --git a/webapp/packages/core-sdk/src/queries/authentication/users/revokeUserTeam.gql b/webapp/packages/core-sdk/src/queries/authentication/users/revokeUserTeam.gql new file mode 100644 index 0000000000..7ea92b7e4b --- /dev/null +++ b/webapp/packages/core-sdk/src/queries/authentication/users/revokeUserTeam.gql @@ -0,0 +1,3 @@ +query revokeUserTeam($userId: ID!, $teamId: ID!) { + revokeUserTeam(userId: $userId, teamId: $teamId) +} \ No newline at end of file diff --git a/webapp/packages/core-sdk/src/queries/fragments/AdminRoleInfo.gql b/webapp/packages/core-sdk/src/queries/fragments/AdminRoleInfo.gql deleted file mode 100644 index ea5d61cceb..0000000000 --- a/webapp/packages/core-sdk/src/queries/fragments/AdminRoleInfo.gql +++ /dev/null @@ -1,6 +0,0 @@ -fragment AdminRoleInfo on AdminRoleInfo { - roleId - roleName - description - rolePermissions -} \ No newline at end of file diff --git a/webapp/packages/core-sdk/src/queries/fragments/AdminTeamInfo.gql b/webapp/packages/core-sdk/src/queries/fragments/AdminTeamInfo.gql new file mode 100644 index 0000000000..d30dfb554d --- /dev/null +++ b/webapp/packages/core-sdk/src/queries/fragments/AdminTeamInfo.gql @@ -0,0 +1,6 @@ +fragment AdminTeamInfo on AdminTeamInfo { + teamId + teamName + description + teamPermissions +} \ No newline at end of file diff --git a/webapp/packages/core-sdk/src/queries/fragments/AdminUserInfo.gql b/webapp/packages/core-sdk/src/queries/fragments/AdminUserInfo.gql index f177e32f8d..e17b6e27c6 100644 --- a/webapp/packages/core-sdk/src/queries/fragments/AdminUserInfo.gql +++ b/webapp/packages/core-sdk/src/queries/fragments/AdminUserInfo.gql @@ -1,6 +1,6 @@ fragment AdminUserInfo on AdminUserInfo { userId - grantedRoles + grantedTeams linkedAuthProviders metaParameters @include(if: $includeMetaParameters) diff --git a/webapp/packages/core-sdk/src/sdk.ts b/webapp/packages/core-sdk/src/sdk.ts index d1aec58f44..f3967c8b19 100644 --- a/webapp/packages/core-sdk/src/sdk.ts +++ b/webapp/packages/core-sdk/src/sdk.ts @@ -66,25 +66,25 @@ export interface AdminPermissionInfo { provider: Scalars['String']; } -export interface AdminRoleInfo { +export enum AdminSubjectType { + Team = 'team', + User = 'user' +} + +export interface AdminTeamInfo { description?: Maybe; grantedConnections: Array; grantedUsers: Array; - roleId: Scalars['ID']; - roleName?: Maybe; - rolePermissions: Array; -} - -export enum AdminSubjectType { - Role = 'role', - User = 'user' + teamId: Scalars['ID']; + teamName?: Maybe; + teamPermissions: Array; } export interface AdminUserInfo { configurationParameters: Scalars['Object']; enabled: Scalars['Boolean']; grantedConnections: Array; - grantedRoles: Array; + grantedTeams: Array; linkedAuthProviders: Array; metaParameters: Scalars['Object']; origins: Array; @@ -877,7 +877,7 @@ export interface Query { connectionInfo: ConnectionInfo; copyConnectionConfiguration: ConnectionInfo; createConnectionConfiguration: ConnectionInfo; - createRole: AdminRoleInfo; + createTeam: AdminTeamInfo; createUser: AdminUserInfo; dataTransferAvailableStreamProcessors: Array; dataTransferDefaultExportSettings: DataTransferDefaultExportSettings; @@ -886,20 +886,20 @@ export interface Query { dataTransferRemoveDataFile?: Maybe; deleteAuthProviderConfiguration: Scalars['Boolean']; deleteConnectionConfiguration?: Maybe; - deleteRole?: Maybe; + deleteTeam?: Maybe; deleteUser?: Maybe; deleteUserMetaParameter: Scalars['Boolean']; driverList: Array; enableUser?: Maybe; getConnectionSubjectAccess: Array; getSubjectConnectionAccess: Array; - grantUserRole?: Maybe; + grantUserTeam?: Maybe; listAuthProviderConfigurationParameters: Array; listAuthProviderConfigurations: Array; listFeatureSets: Array; listPermissions: Array; listProjects: Array; - listRoles: Array; + listTeams: Array; listUserProfileProperties: Array; listUsers: Array; metadataGetNodeDDL?: Maybe; @@ -910,7 +910,7 @@ export interface Query { navRefreshNode?: Maybe; networkHandlers: Array; readSessionLog: Array; - revokeUserRole?: Maybe; + revokeUserTeam?: Maybe; rmListProjectGrantedPermissions: Array; rmListProjectPermissions: Array; rmListProjects: Array; @@ -942,7 +942,7 @@ export interface Query { sqlSupportedOperations: Array; templateConnections: Array; updateConnectionConfiguration: ConnectionInfo; - updateRole: AdminRoleInfo; + updateTeam: AdminTeamInfo; userConnections: Array; } @@ -1006,10 +1006,10 @@ export interface QueryCreateConnectionConfigurationArgs { } -export interface QueryCreateRoleArgs { +export interface QueryCreateTeamArgs { description?: InputMaybe; - roleId: Scalars['ID']; - roleName?: InputMaybe; + teamId: Scalars['ID']; + teamName?: InputMaybe; } @@ -1051,8 +1051,8 @@ export interface QueryDeleteConnectionConfigurationArgs { } -export interface QueryDeleteRoleArgs { - roleId: Scalars['ID']; +export interface QueryDeleteTeamArgs { + teamId: Scalars['ID']; } @@ -1088,8 +1088,8 @@ export interface QueryGetSubjectConnectionAccessArgs { } -export interface QueryGrantUserRoleArgs { - roleId: Scalars['ID']; +export interface QueryGrantUserTeamArgs { + teamId: Scalars['ID']; userId: Scalars['ID']; } @@ -1104,8 +1104,8 @@ export interface QueryListAuthProviderConfigurationsArgs { } -export interface QueryListRolesArgs { - roleId?: InputMaybe; +export interface QueryListTeamsArgs { + teamId?: InputMaybe; } @@ -1157,8 +1157,8 @@ export interface QueryReadSessionLogArgs { } -export interface QueryRevokeUserRoleArgs { - roleId: Scalars['ID']; +export interface QueryRevokeUserTeamArgs { + teamId: Scalars['ID']; userId: Scalars['ID']; } @@ -1237,7 +1237,7 @@ export interface QuerySetSubjectConnectionAccessArgs { export interface QuerySetSubjectPermissionsArgs { permissions: Array; - roleId: Scalars['ID']; + subjectId: Scalars['ID']; } @@ -1333,10 +1333,10 @@ export interface QueryUpdateConnectionConfigurationArgs { } -export interface QueryUpdateRoleArgs { +export interface QueryUpdateTeamArgs { description?: InputMaybe; - roleId: Scalars['ID']; - roleName?: InputMaybe; + teamId: Scalars['ID']; + teamName?: InputMaybe; } @@ -1629,7 +1629,7 @@ export type GetPermissionsListQueryVariables = Exact<{ [key: string]: never; }>; export type GetPermissionsListQuery = { permissions: Array<{ id: string, label?: string, description?: string, category?: string }> }; export type SetSubjectPermissionsQueryVariables = Exact<{ - roleId: Scalars['ID']; + subjectId: Scalars['ID']; permissions: Array | Scalars['ID']; }>; @@ -1643,45 +1643,6 @@ export type AsyncTaskCancelMutationVariables = Exact<{ export type AsyncTaskCancelMutation = { result?: boolean }; -export type CreateRoleQueryVariables = Exact<{ - roleId: Scalars['ID']; - roleName?: InputMaybe; - description?: InputMaybe; -}>; - - -export type CreateRoleQuery = { role: { roleId: string, roleName?: string, description?: string, rolePermissions: Array } }; - -export type DeleteRoleQueryVariables = Exact<{ - roleId: Scalars['ID']; -}>; - - -export type DeleteRoleQuery = { deleteRole?: boolean }; - -export type GetRoleGrantedUsersQueryVariables = Exact<{ - roleId: Scalars['ID']; -}>; - - -export type GetRoleGrantedUsersQuery = { role: Array<{ grantedUsers: Array }> }; - -export type GetRolesListQueryVariables = Exact<{ - roleId?: InputMaybe; -}>; - - -export type GetRolesListQuery = { roles: Array<{ roleId: string, roleName?: string, description?: string, rolePermissions: Array }> }; - -export type UpdateRoleQueryVariables = Exact<{ - roleId: Scalars['ID']; - roleName?: InputMaybe; - description?: InputMaybe; -}>; - - -export type UpdateRoleQuery = { role: { roleId: string, roleName?: string, description?: string, rolePermissions: Array } }; - export type AuthChangeLocalPasswordQueryVariables = Exact<{ oldPassword: Scalars['String']; newPassword: Scalars['String']; @@ -1776,6 +1737,45 @@ export type SaveUserMetaParametersQueryVariables = Exact<{ export type SaveUserMetaParametersQuery = { setUserMetaParameterValues: boolean }; +export type CreateTeamQueryVariables = Exact<{ + teamId: Scalars['ID']; + teamName?: InputMaybe; + description?: InputMaybe; +}>; + + +export type CreateTeamQuery = { team: { teamId: string, teamName?: string, description?: string, teamPermissions: Array } }; + +export type DeleteTeamQueryVariables = Exact<{ + teamId: Scalars['ID']; +}>; + + +export type DeleteTeamQuery = { deleteTeam?: boolean }; + +export type GetTeamGrantedUsersQueryVariables = Exact<{ + teamId: Scalars['ID']; +}>; + + +export type GetTeamGrantedUsersQuery = { team: Array<{ grantedUsers: Array }> }; + +export type GetTeamsListQueryVariables = Exact<{ + teamId?: InputMaybe; +}>; + + +export type GetTeamsListQuery = { teams: Array<{ teamId: string, teamName?: string, description?: string, teamPermissions: Array }> }; + +export type UpdateTeamQueryVariables = Exact<{ + teamId: Scalars['ID']; + teamName?: InputMaybe; + description?: InputMaybe; +}>; + + +export type UpdateTeamQuery = { team: { teamId: string, teamName?: string, description?: string, teamPermissions: Array } }; + export type CreateUserQueryVariables = Exact<{ userId: Scalars['ID']; enabled: Scalars['Boolean']; @@ -1784,7 +1784,7 @@ export type CreateUserQueryVariables = Exact<{ }>; -export type CreateUserQuery = { user: { userId: string, grantedRoles: Array, linkedAuthProviders: Array, metaParameters?: any, enabled: boolean, 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 }> }> } }; +export type CreateUserQuery = { user: { userId: string, grantedTeams: Array, linkedAuthProviders: Array, metaParameters?: any, enabled: boolean, 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 }> }> } }; export type DeleteUserQueryVariables = Exact<{ userId: Scalars['ID']; @@ -1822,23 +1822,23 @@ export type GetUsersListQueryVariables = Exact<{ }>; -export type GetUsersListQuery = { users: Array<{ userId: string, grantedRoles: Array, linkedAuthProviders: Array, metaParameters?: any, enabled: boolean, 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 }> }> }> }; +export type GetUsersListQuery = { users: Array<{ userId: string, grantedTeams: Array, linkedAuthProviders: Array, metaParameters?: any, enabled: boolean, 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 }> }> }> }; -export type GrantUserRoleQueryVariables = Exact<{ +export type GrantUserTeamQueryVariables = Exact<{ userId: Scalars['ID']; - roleId: Scalars['ID']; + teamId: Scalars['ID']; }>; -export type GrantUserRoleQuery = { grantUserRole?: boolean }; +export type GrantUserTeamQuery = { grantUserTeam?: boolean }; -export type RevokeUserRoleQueryVariables = Exact<{ +export type RevokeUserTeamQueryVariables = Exact<{ userId: Scalars['ID']; - roleId: Scalars['ID']; + teamId: Scalars['ID']; }>; -export type RevokeUserRoleQuery = { revokeUserRole?: boolean }; +export type RevokeUserTeamQuery = { revokeUserTeam?: boolean }; export type SetConnectionsQueryVariables = Exact<{ userId: Scalars['ID']; @@ -2247,9 +2247,9 @@ export type AdminObjectGrantInfoFragment = { subjectId: string, subjectType: Adm export type AdminPermissionInfoFragment = { id: string, label?: string, description?: string, category?: string }; -export type AdminRoleInfoFragment = { roleId: string, roleName?: string, description?: string, rolePermissions: Array }; +export type AdminTeamInfoFragment = { teamId: string, teamName?: string, description?: string, teamPermissions: Array }; -export type AdminUserInfoFragment = { userId: string, grantedRoles: Array, linkedAuthProviders: Array, metaParameters?: any, enabled: boolean, 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 }> }> }; +export type AdminUserInfoFragment = { userId: string, grantedTeams: Array, linkedAuthProviders: Array, metaParameters?: any, enabled: boolean, 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 }> }> }; export type AllNavigatorSettingsFragment = { showSystemObjects: boolean, showUtilityObjects: boolean, showOnlyEntities: boolean, mergeEntities: boolean, hideFolders: boolean, hideSchemas: boolean, hideVirtualModel: boolean }; @@ -2753,12 +2753,12 @@ export const AdminPermissionInfoFragmentDoc = ` category } `; -export const AdminRoleInfoFragmentDoc = ` - fragment AdminRoleInfo on AdminRoleInfo { - roleId - roleName +export const AdminTeamInfoFragmentDoc = ` + fragment AdminTeamInfo on AdminTeamInfo { + teamId + teamName description - rolePermissions + teamPermissions } `; export const ObjectOriginInfoFragmentDoc = ` @@ -2785,7 +2785,7 @@ export const ObjectOriginInfoFragmentDoc = ` export const AdminUserInfoFragmentDoc = ` fragment AdminUserInfo on AdminUserInfo { userId - grantedRoles + grantedTeams linkedAuthProviders metaParameters @include(if: $includeMetaParameters) origins { @@ -3111,8 +3111,11 @@ export const GetPermissionsListDocument = ` } ${AdminPermissionInfoFragmentDoc}`; export const SetSubjectPermissionsDocument = ` - query setSubjectPermissions($roleId: ID!, $permissions: [ID!]!) { - permissions: setSubjectPermissions(roleId: $roleId, permissions: $permissions) { + query setSubjectPermissions($subjectId: ID!, $permissions: [ID!]!) { + permissions: setSubjectPermissions( + subjectId: $subjectId + permissions: $permissions + ) { ...AdminPermissionInfo } } @@ -3122,47 +3125,6 @@ export const AsyncTaskCancelDocument = ` result: asyncTaskCancel(id: $taskId) } `; -export const CreateRoleDocument = ` - query createRole($roleId: ID!, $roleName: String, $description: String) { - role: createRole( - roleId: $roleId - roleName: $roleName - description: $description - ) { - ...AdminRoleInfo - } -} - ${AdminRoleInfoFragmentDoc}`; -export const DeleteRoleDocument = ` - query deleteRole($roleId: ID!) { - deleteRole(roleId: $roleId) -} - `; -export const GetRoleGrantedUsersDocument = ` - query getRoleGrantedUsers($roleId: ID!) { - role: listRoles(roleId: $roleId) { - grantedUsers - } -} - `; -export const GetRolesListDocument = ` - query getRolesList($roleId: ID) { - roles: listRoles(roleId: $roleId) { - ...AdminRoleInfo - } -} - ${AdminRoleInfoFragmentDoc}`; -export const UpdateRoleDocument = ` - query updateRole($roleId: ID!, $roleName: String, $description: String) { - role: updateRole( - roleId: $roleId - roleName: $roleName - description: $description - ) { - ...AdminRoleInfo - } -} - ${AdminRoleInfoFragmentDoc}`; export const AuthChangeLocalPasswordDocument = ` query authChangeLocalPassword($oldPassword: String!, $newPassword: String!) { authChangeLocalPassword(oldPassword: $oldPassword, newPassword: $newPassword) @@ -3289,6 +3251,47 @@ export const SaveUserMetaParametersDocument = ` setUserMetaParameterValues(userId: $userId, parameters: $parameters) } `; +export const CreateTeamDocument = ` + query createTeam($teamId: ID!, $teamName: String, $description: String) { + team: createTeam( + teamId: $teamId + teamName: $teamName + description: $description + ) { + ...AdminTeamInfo + } +} + ${AdminTeamInfoFragmentDoc}`; +export const DeleteTeamDocument = ` + query deleteTeam($teamId: ID!) { + deleteTeam(teamId: $teamId) +} + `; +export const GetTeamGrantedUsersDocument = ` + query getTeamGrantedUsers($teamId: ID!) { + team: listTeams(teamId: $teamId) { + grantedUsers + } +} + `; +export const GetTeamsListDocument = ` + query getTeamsList($teamId: ID) { + teams: listTeams(teamId: $teamId) { + ...AdminTeamInfo + } +} + ${AdminTeamInfoFragmentDoc}`; +export const UpdateTeamDocument = ` + query updateTeam($teamId: ID!, $teamName: String, $description: String) { + team: updateTeam( + teamId: $teamId + teamName: $teamName + description: $description + ) { + ...AdminTeamInfo + } +} + ${AdminTeamInfoFragmentDoc}`; export const CreateUserDocument = ` query createUser($userId: ID!, $enabled: Boolean!, $includeMetaParameters: Boolean!, $customIncludeOriginDetails: Boolean!) { user: createUser(userId: $userId, enabled: $enabled) { @@ -3328,14 +3331,14 @@ export const GetUsersListDocument = ` } } ${AdminUserInfoFragmentDoc}`; -export const GrantUserRoleDocument = ` - query grantUserRole($userId: ID!, $roleId: ID!) { - grantUserRole(userId: $userId, roleId: $roleId) +export const GrantUserTeamDocument = ` + query grantUserTeam($userId: ID!, $teamId: ID!) { + grantUserTeam(userId: $userId, teamId: $teamId) } `; -export const RevokeUserRoleDocument = ` - query revokeUserRole($userId: ID!, $roleId: ID!) { - revokeUserRole(userId: $userId, roleId: $roleId) +export const RevokeUserTeamDocument = ` + query revokeUserTeam($userId: ID!, $teamId: ID!) { + revokeUserTeam(userId: $userId, teamId: $teamId) } `; export const SetConnectionsDocument = ` @@ -4399,21 +4402,6 @@ export function getSdk(client: GraphQLClient, withWrapper: SdkFunctionWrapper = asyncTaskCancel(variables: AsyncTaskCancelMutationVariables, requestHeaders?: Dom.RequestInit["headers"]): Promise { return withWrapper((wrappedRequestHeaders) => client.request(AsyncTaskCancelDocument, variables, {...requestHeaders, ...wrappedRequestHeaders}), 'asyncTaskCancel', 'mutation'); }, - createRole(variables: CreateRoleQueryVariables, requestHeaders?: Dom.RequestInit["headers"]): Promise { - return withWrapper((wrappedRequestHeaders) => client.request(CreateRoleDocument, variables, {...requestHeaders, ...wrappedRequestHeaders}), 'createRole', 'query'); - }, - deleteRole(variables: DeleteRoleQueryVariables, requestHeaders?: Dom.RequestInit["headers"]): Promise { - return withWrapper((wrappedRequestHeaders) => client.request(DeleteRoleDocument, variables, {...requestHeaders, ...wrappedRequestHeaders}), 'deleteRole', 'query'); - }, - getRoleGrantedUsers(variables: GetRoleGrantedUsersQueryVariables, requestHeaders?: Dom.RequestInit["headers"]): Promise { - return withWrapper((wrappedRequestHeaders) => client.request(GetRoleGrantedUsersDocument, variables, {...requestHeaders, ...wrappedRequestHeaders}), 'getRoleGrantedUsers', 'query'); - }, - getRolesList(variables?: GetRolesListQueryVariables, requestHeaders?: Dom.RequestInit["headers"]): Promise { - return withWrapper((wrappedRequestHeaders) => client.request(GetRolesListDocument, variables, {...requestHeaders, ...wrappedRequestHeaders}), 'getRolesList', 'query'); - }, - updateRole(variables: UpdateRoleQueryVariables, requestHeaders?: Dom.RequestInit["headers"]): Promise { - return withWrapper((wrappedRequestHeaders) => client.request(UpdateRoleDocument, variables, {...requestHeaders, ...wrappedRequestHeaders}), 'updateRole', 'query'); - }, authChangeLocalPassword(variables: AuthChangeLocalPasswordQueryVariables, requestHeaders?: Dom.RequestInit["headers"]): Promise { return withWrapper((wrappedRequestHeaders) => client.request(AuthChangeLocalPasswordDocument, variables, {...requestHeaders, ...wrappedRequestHeaders}), 'authChangeLocalPassword', 'query'); }, @@ -4450,6 +4438,21 @@ export function getSdk(client: GraphQLClient, withWrapper: SdkFunctionWrapper = saveUserMetaParameters(variables: SaveUserMetaParametersQueryVariables, requestHeaders?: Dom.RequestInit["headers"]): Promise { return withWrapper((wrappedRequestHeaders) => client.request(SaveUserMetaParametersDocument, variables, {...requestHeaders, ...wrappedRequestHeaders}), 'saveUserMetaParameters', 'query'); }, + createTeam(variables: CreateTeamQueryVariables, requestHeaders?: Dom.RequestInit["headers"]): Promise { + return withWrapper((wrappedRequestHeaders) => client.request(CreateTeamDocument, variables, {...requestHeaders, ...wrappedRequestHeaders}), 'createTeam', 'query'); + }, + deleteTeam(variables: DeleteTeamQueryVariables, requestHeaders?: Dom.RequestInit["headers"]): Promise { + return withWrapper((wrappedRequestHeaders) => client.request(DeleteTeamDocument, variables, {...requestHeaders, ...wrappedRequestHeaders}), 'deleteTeam', 'query'); + }, + 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 { + return withWrapper((wrappedRequestHeaders) => client.request(GetTeamsListDocument, variables, {...requestHeaders, ...wrappedRequestHeaders}), 'getTeamsList', 'query'); + }, + updateTeam(variables: UpdateTeamQueryVariables, requestHeaders?: Dom.RequestInit["headers"]): Promise { + return withWrapper((wrappedRequestHeaders) => client.request(UpdateTeamDocument, variables, {...requestHeaders, ...wrappedRequestHeaders}), 'updateTeam', 'query'); + }, createUser(variables: CreateUserQueryVariables, requestHeaders?: Dom.RequestInit["headers"]): Promise { return withWrapper((wrappedRequestHeaders) => client.request(CreateUserDocument, variables, {...requestHeaders, ...wrappedRequestHeaders}), 'createUser', 'query'); }, @@ -4468,11 +4471,11 @@ export function getSdk(client: GraphQLClient, withWrapper: SdkFunctionWrapper = getUsersList(variables: GetUsersListQueryVariables, requestHeaders?: Dom.RequestInit["headers"]): Promise { return withWrapper((wrappedRequestHeaders) => client.request(GetUsersListDocument, variables, {...requestHeaders, ...wrappedRequestHeaders}), 'getUsersList', 'query'); }, - grantUserRole(variables: GrantUserRoleQueryVariables, requestHeaders?: Dom.RequestInit["headers"]): Promise { - return withWrapper((wrappedRequestHeaders) => client.request(GrantUserRoleDocument, variables, {...requestHeaders, ...wrappedRequestHeaders}), 'grantUserRole', 'query'); + grantUserTeam(variables: GrantUserTeamQueryVariables, requestHeaders?: Dom.RequestInit["headers"]): Promise { + return withWrapper((wrappedRequestHeaders) => client.request(GrantUserTeamDocument, variables, {...requestHeaders, ...wrappedRequestHeaders}), 'grantUserTeam', 'query'); }, - revokeUserRole(variables: RevokeUserRoleQueryVariables, requestHeaders?: Dom.RequestInit["headers"]): Promise { - return withWrapper((wrappedRequestHeaders) => client.request(RevokeUserRoleDocument, variables, {...requestHeaders, ...wrappedRequestHeaders}), 'revokeUserRole', 'query'); + revokeUserTeam(variables: RevokeUserTeamQueryVariables, requestHeaders?: Dom.RequestInit["headers"]): Promise { + return withWrapper((wrappedRequestHeaders) => client.request(RevokeUserTeamDocument, variables, {...requestHeaders, ...wrappedRequestHeaders}), 'revokeUserTeam', 'query'); }, setConnections(variables: SetConnectionsQueryVariables, requestHeaders?: Dom.RequestInit["headers"]): Promise { return withWrapper((wrappedRequestHeaders) => client.request(SetConnectionsDocument, variables, {...requestHeaders, ...wrappedRequestHeaders}), 'setConnections', 'query'); diff --git a/webapp/packages/core-utils/package.json b/webapp/packages/core-utils/package.json index 3125171093..1c62825bf2 100644 --- a/webapp/packages/core-utils/package.json +++ b/webapp/packages/core-utils/package.json @@ -19,7 +19,8 @@ "@timohausmann/quadtree-ts": "~2.0.0-beta.1", "clsx": "~1.2.1", "md5": "~2.3.0", - "uuid": "~9.0.0" + "uuid": "~9.0.0", + "fast-deep-equal": "~3.1.3" }, "peerDependencies": { "mobx": "~6.x.x" diff --git a/webapp/packages/core-utils/src/MetadataMap.ts b/webapp/packages/core-utils/src/MetadataMap.ts index 68c5ef7d50..168f661611 100644 --- a/webapp/packages/core-utils/src/MetadataMap.ts +++ b/webapp/packages/core-utils/src/MetadataMap.ts @@ -17,7 +17,7 @@ export class MetadataMap { private syncData: Array<[TKey, TValue]> | null; - constructor(private defaultValueGetter?: DefaultValueGetter) { + constructor(private readonly defaultValueGetter?: DefaultValueGetter) { this.data = observable(new Map()); this.length = 0; this.syncData = null; @@ -74,7 +74,7 @@ export class MetadataMap { const value = provider(key, this); untracked(() => { - this.set(key, value); + this.set(key, observable(value as any)); this.length++; }); return this.data.get(key)!; diff --git a/webapp/packages/core-utils/src/index.ts b/webapp/packages/core-utils/src/index.ts index 1ea1946795..12b7e53a4e 100644 --- a/webapp/packages/core-utils/src/index.ts +++ b/webapp/packages/core-utils/src/index.ts @@ -34,6 +34,7 @@ export * from './isImageFormat'; export * from './getCookies'; export * from './getUniqueName'; export * from './isMapsEqual'; +export * from './isObjectsEqual'; export * from './openCenteredPopup'; export * from './download'; export * from './getTextFileReadingProcess'; diff --git a/webapp/packages/core-utils/src/isObjectsEqual.ts b/webapp/packages/core-utils/src/isObjectsEqual.ts new file mode 100644 index 0000000000..619530b8b2 --- /dev/null +++ b/webapp/packages/core-utils/src/isObjectsEqual.ts @@ -0,0 +1,16 @@ +/* + * 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 isEqual from 'fast-deep-equal'; + +export function isObjectsEqual( + a: any, + b: any +): boolean { + return isEqual(a, b); +} diff --git a/webapp/packages/plugin-authentication-administration/src/Administration/Users/MetaParameters/MetaParameters.tsx b/webapp/packages/plugin-authentication-administration/src/Administration/Users/MetaParameters/MetaParameters.tsx index df0d636a7b..b15139e281 100644 --- a/webapp/packages/plugin-authentication-administration/src/Administration/Users/MetaParameters/MetaParameters.tsx +++ b/webapp/packages/plugin-authentication-administration/src/Administration/Users/MetaParameters/MetaParameters.tsx @@ -118,7 +118,7 @@ export const MetaParameters = observer(function MetaParameters({ sub, par )} {translate('authentication_user_name')} - {translate('authentication_user_role')} + {translate('authentication_user_team')} diff --git a/webapp/packages/plugin-authentication-administration/src/Administration/Users/Roles/Contexts/roleFormConfigureContext.ts b/webapp/packages/plugin-authentication-administration/src/Administration/Users/Roles/Contexts/roleFormConfigureContext.ts deleted file mode 100644 index b08773b9a2..0000000000 --- a/webapp/packages/plugin-authentication-administration/src/Administration/Users/Roles/Contexts/roleFormConfigureContext.ts +++ /dev/null @@ -1,25 +0,0 @@ -/* - * 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 type { RoleInfo } from '@cloudbeaver/core-authentication'; -import type { IExecutionContextProvider } from '@cloudbeaver/core-executor'; - -import type { IRoleFormState } from '../IRoleFormProps'; - -export interface IRoleFormConfigureContext { - readonly info: RoleInfo | undefined; -} - -export function roleFormConfigureContext( - contexts: IExecutionContextProvider, - state: IRoleFormState -): IRoleFormConfigureContext { - return { - info: state.info, - }; -} diff --git a/webapp/packages/plugin-authentication-administration/src/Administration/Users/Roles/Options/RoleOptionsTabService.ts b/webapp/packages/plugin-authentication-administration/src/Administration/Users/Roles/Options/RoleOptionsTabService.ts deleted file mode 100644 index 00f16e22a5..0000000000 --- a/webapp/packages/plugin-authentication-administration/src/Administration/Users/Roles/Options/RoleOptionsTabService.ts +++ /dev/null @@ -1,149 +0,0 @@ -/* - * 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 { RolesResource } from '@cloudbeaver/core-authentication'; -import { Bootstrap, injectable } from '@cloudbeaver/core-di'; -import type { IExecutionContextProvider } from '@cloudbeaver/core-executor'; -import { getUniqueName } from '@cloudbeaver/core-utils'; - -import { roleContext } from '../Contexts/roleContext'; -import type { IRoleFormFillConfigData, IRoleFormSubmitData } from '../IRoleFormProps'; -import { RoleFormService } from '../RoleFormService'; -import { RoleOptions } from './RoleOptions'; - -@injectable() -export class RoleOptionsTabService extends Bootstrap { - constructor( - private readonly roleFormService: RoleFormService, - private readonly roleResource: RolesResource, - ) { - super(); - } - - register(): void { - this.roleFormService.tabsContainer.add({ - key: 'options', - name: 'ui_options', - order: 1, - panel: () => RoleOptions, - }); - - this.roleFormService.prepareConfigTask - .addHandler(this.prepareConfig.bind(this)); - - this.roleFormService.formValidationTask - .addHandler(this.validate.bind(this)); - - this.roleFormService.formSubmittingTask - .addHandler(this.save.bind(this)); - - this.roleFormService.fillConfigTask - .addHandler(this.fillConfig.bind(this)); - } - - load(): void { } - - private async prepareConfig( - { - state, - }: IRoleFormSubmitData, - contexts: IExecutionContextProvider - ) { - const config = contexts.getContext(roleContext); - - config.roleId = state.config.roleId; - - if (state.config.roleName) { - config.roleName = state.config.roleName.trim(); - - if (state.mode === 'create') { - const roleNames = this.roleResource.values.map(role => role.roleName).filter(Boolean) as string[]; - config.roleName = getUniqueName(config.roleName, roleNames); - } - } - - if (state.config.description) { - config.description = state.config.description; - } - - config.rolePermissions = [...state.config.rolePermissions]; - } - - private async validate( - { - state, - }: IRoleFormSubmitData, - contexts: IExecutionContextProvider - ) { - const validation = contexts.getContext(this.roleFormService.configurationValidationContext); - - if (state.mode === 'create') { - if (!state.config.roleId.trim()) { - validation.error("Field 'Role ID' can't be empty"); - } - - if (this.roleResource.has(state.config.roleId)) { - validation.error(`A role with ID "${state.config.roleId}" already exists`); - } - } - } - - private async save( - { - state, - }: IRoleFormSubmitData, - contexts: IExecutionContextProvider - ) { - const status = contexts.getContext(this.roleFormService.configurationStatusContext); - const config = contexts.getContext(roleContext); - - const create = state.mode === 'create'; - - try { - if (create) { - const role = await this.roleResource.createRole(config); - status.info('Role created'); - status.info(role.roleId); - } else { - const role = await this.roleResource.updateRole(config); - status.info('Role updated'); - status.info(role.roleId); - } - } catch (exception: any) { - if (create) { - status.error(exception, 'administration_roles_role_create_error'); - } else { - status.error(exception, 'administration_roles_role_save_error'); - } - } - } - - private fillConfig( - { state, updated }: IRoleFormFillConfigData, - contexts: IExecutionContextProvider - ) { - if (!updated) { - return; - } - - if (!state.info) { - return; - } - - if (state.info.roleId) { - state.config.roleId = state.info.roleId; - } - if (state.info.roleName) { - state.config.roleName = state.info.roleName; - } - if (state.info.description) { - state.config.description = state.info.description; - } - state.config.rolePermissions = [...state.info.rolePermissions]; - } -} diff --git a/webapp/packages/plugin-authentication-administration/src/Administration/Users/Roles/useRoleFormState.ts b/webapp/packages/plugin-authentication-administration/src/Administration/Users/Roles/useRoleFormState.ts deleted file mode 100644 index b80ac5b3c1..0000000000 --- a/webapp/packages/plugin-authentication-administration/src/Administration/Users/Roles/useRoleFormState.ts +++ /dev/null @@ -1,36 +0,0 @@ -/* - * 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 { useState } from 'react'; - -import type { RoleInfo } from '@cloudbeaver/core-authentication'; -import { useService } from '@cloudbeaver/core-di'; -import type { CachedMapResource } from '@cloudbeaver/core-sdk'; - -import type { IRoleFormState } from './IRoleFormProps'; -import { RoleFormService } from './RoleFormService'; -import { RoleFormState } from './RoleFormState'; - -export function useRoleFormState( - resource: CachedMapResource, - configure?: (state: IRoleFormState) => any -): IRoleFormState { - const service = useService(RoleFormService); - const [state] = useState(() => { - const state = new RoleFormState( - service, - resource, - ); - configure?.(state); - - state.load(); - return state; - }); - - return state; -} diff --git a/webapp/packages/plugin-authentication-administration/src/Administration/Users/Roles/Contexts/roleContext.ts b/webapp/packages/plugin-authentication-administration/src/Administration/Users/Teams/Contexts/teamContext.ts similarity index 62% rename from webapp/packages/plugin-authentication-administration/src/Administration/Users/Roles/Contexts/roleContext.ts rename to webapp/packages/plugin-authentication-administration/src/Administration/Users/Teams/Contexts/teamContext.ts index a831cd86b9..f5648ed9f6 100644 --- a/webapp/packages/plugin-authentication-administration/src/Administration/Users/Roles/Contexts/roleContext.ts +++ b/webapp/packages/plugin-authentication-administration/src/Administration/Users/Teams/Contexts/teamContext.ts @@ -6,11 +6,11 @@ * you may not use this file except in compliance with the License. */ -import type { RoleInfo } from '@cloudbeaver/core-authentication'; +import type { TeamInfo } from '@cloudbeaver/core-authentication'; -export function roleContext(): RoleInfo { +export function teamContext(): TeamInfo { return { - roleId: '', - rolePermissions: [], + teamId: '', + teamPermissions: [], }; } diff --git a/webapp/packages/plugin-authentication-administration/src/Administration/Users/Teams/Contexts/teamFormConfigureContext.ts b/webapp/packages/plugin-authentication-administration/src/Administration/Users/Teams/Contexts/teamFormConfigureContext.ts new file mode 100644 index 0000000000..c77d612d96 --- /dev/null +++ b/webapp/packages/plugin-authentication-administration/src/Administration/Users/Teams/Contexts/teamFormConfigureContext.ts @@ -0,0 +1,25 @@ +/* + * 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 type { TeamInfo } from '@cloudbeaver/core-authentication'; +import type { IExecutionContextProvider } from '@cloudbeaver/core-executor'; + +import type { ITeamFormState } from '../ITeamFormProps'; + +export interface ITeamFormConfigureContext { + readonly info: TeamInfo | undefined; +} + +export function teamFormConfigureContext( + contexts: IExecutionContextProvider, + state: ITeamFormState +): ITeamFormConfigureContext { + return { + info: state.info, + }; +} diff --git a/webapp/packages/plugin-authentication-administration/src/Administration/Users/Roles/Contexts/roleFormStateContext.ts b/webapp/packages/plugin-authentication-administration/src/Administration/Users/Teams/Contexts/teamFormStateContext.ts similarity index 77% rename from webapp/packages/plugin-authentication-administration/src/Administration/Users/Roles/Contexts/roleFormStateContext.ts rename to webapp/packages/plugin-authentication-administration/src/Administration/Users/Teams/Contexts/teamFormStateContext.ts index 9e77d43b70..dd965562d5 100644 --- a/webapp/packages/plugin-authentication-administration/src/Administration/Users/Roles/Contexts/roleFormStateContext.ts +++ b/webapp/packages/plugin-authentication-administration/src/Administration/Users/Teams/Contexts/teamFormStateContext.ts @@ -6,18 +6,18 @@ * you may not use this file except in compliance with the License. */ -export interface IRoleFormStateInfo { +export interface ITeamFormStateInfo { edited: boolean; disabled: boolean; readonly: boolean; statusMessage: string | null; } -export interface IRoleFormStateContext extends IRoleFormStateInfo { +export interface ITeamFormStateContext extends ITeamFormStateInfo { setStatusMessage: (message: string | null) => void; } -export function roleFormStateContext(): IRoleFormStateContext { +export function teamFormStateContext(): ITeamFormStateContext { return { edited: false, disabled: false, diff --git a/webapp/packages/plugin-authentication-administration/src/Administration/Users/Roles/CreateRole.tsx b/webapp/packages/plugin-authentication-administration/src/Administration/Users/Teams/CreateTeam.tsx similarity index 73% rename from webapp/packages/plugin-authentication-administration/src/Administration/Users/Roles/CreateRole.tsx rename to webapp/packages/plugin-authentication-administration/src/Administration/Users/Teams/CreateTeam.tsx index 3a1af51fa8..ad34ac23f6 100644 --- a/webapp/packages/plugin-authentication-administration/src/Administration/Users/Roles/CreateRole.tsx +++ b/webapp/packages/plugin-authentication-administration/src/Administration/Users/Teams/CreateTeam.tsx @@ -14,11 +14,11 @@ import { useService } from '@cloudbeaver/core-di'; -import { CreateRoleService } from './CreateRoleService'; -import { RoleForm } from './RoleForm'; +import { CreateTeamService } from './CreateTeamService'; +import { TeamForm } from './TeamForm'; const styles = css` - role-create { + team-create { display: flex; flex-direction: column; height: 660px; @@ -35,7 +35,7 @@ const styles = css` flex: auto 0 0; } - role-create-content { + team-create-content { composes: theme-background-secondary theme-text-on-secondary from global; position: relative; display: flex; @@ -49,23 +49,23 @@ const styles = css` } `; -export const CreateRole: React.FC = observer(function CreateRole() { - const service = useService(CreateRoleService); +export const CreateTeam: React.FC = observer(function CreateTeam() { + const service = useService(CreateTeamService); if (!service.data) { return null; } return styled(styles)( - + - + - - - - + + + + ); }); diff --git a/webapp/packages/plugin-authentication-administration/src/Administration/Users/Roles/CreateRoleService.ts b/webapp/packages/plugin-authentication-administration/src/Administration/Users/Teams/CreateTeamService.ts similarity index 50% rename from webapp/packages/plugin-authentication-administration/src/Administration/Users/Roles/CreateRoleService.ts rename to webapp/packages/plugin-authentication-administration/src/Administration/Users/Teams/CreateTeamService.ts index 8862a802f6..1d3e85dfa7 100644 --- a/webapp/packages/plugin-authentication-administration/src/Administration/Users/Roles/CreateRoleService.ts +++ b/webapp/packages/plugin-authentication-administration/src/Administration/Users/Teams/CreateTeamService.ts @@ -8,23 +8,23 @@ import { observable, makeObservable } from 'mobx'; -import { RolesResource } from '@cloudbeaver/core-authentication'; +import { TeamsResource } from '@cloudbeaver/core-authentication'; import { injectable } from '@cloudbeaver/core-di'; -import type { IRoleFormState } from './IRoleFormProps'; -import { RoleFormService } from './RoleFormService'; -import { RoleFormState } from './RoleFormState'; -import { RolesAdministrationNavService } from './RolesAdministrationNavService'; +import type { ITeamFormState } from './ITeamFormProps'; +import { TeamFormService } from './TeamFormService'; +import { TeamFormState } from './TeamFormState'; +import { TeamsAdministrationNavService } from './TeamsAdministrationNavService'; @injectable() -export class CreateRoleService { +export class CreateTeamService { disabled = false; - data: IRoleFormState | null; + data: ITeamFormState | null; constructor( - private readonly rolesAdministrationNavService: RolesAdministrationNavService, - private readonly roleFormService: RoleFormService, - private readonly rolesResource: RolesResource + private readonly teamsAdministrationNavService: TeamsAdministrationNavService, + private readonly teamFormService: TeamFormService, + private readonly teamsResource: TeamsResource ) { this.data = null; @@ -38,17 +38,17 @@ export class CreateRoleService { } cancelCreate(): void { - this.rolesAdministrationNavService.navToRoot(); + this.teamsAdministrationNavService.navToRoot(); } fillData(): void { - this.data = new RoleFormState( - this.roleFormService, - this.rolesResource + this.data = new TeamFormState( + this.teamFormService, + this.teamsResource ); } create(): void { - this.rolesAdministrationNavService.navToCreate(); + this.teamsAdministrationNavService.navToCreate(); } } diff --git a/webapp/packages/plugin-authentication-administration/src/Administration/Users/Roles/GrantedConnections/ConnectionList.tsx b/webapp/packages/plugin-authentication-administration/src/Administration/Users/Teams/GrantedConnections/ConnectionList.tsx similarity index 100% rename from webapp/packages/plugin-authentication-administration/src/Administration/Users/Roles/GrantedConnections/ConnectionList.tsx rename to webapp/packages/plugin-authentication-administration/src/Administration/Users/Teams/GrantedConnections/ConnectionList.tsx diff --git a/webapp/packages/plugin-authentication-administration/src/Administration/Users/Roles/GrantedConnections/GrantedConnections.tsx b/webapp/packages/plugin-authentication-administration/src/Administration/Users/Teams/GrantedConnections/GrantedConnections.tsx similarity index 90% rename from webapp/packages/plugin-authentication-administration/src/Administration/Users/Roles/GrantedConnections/GrantedConnections.tsx rename to webapp/packages/plugin-authentication-administration/src/Administration/Users/Teams/GrantedConnections/GrantedConnections.tsx index f6d19de3a1..044804c4f4 100644 --- a/webapp/packages/plugin-authentication-administration/src/Administration/Users/Roles/GrantedConnections/GrantedConnections.tsx +++ b/webapp/packages/plugin-authentication-administration/src/Administration/Users/Teams/GrantedConnections/GrantedConnections.tsx @@ -21,7 +21,7 @@ import { PROJECT_GLOBAL_ID } from '@cloudbeaver/core-projects'; import { CachedMapAllKey } from '@cloudbeaver/core-sdk'; import { TabContainerPanelComponent, useTab } from '@cloudbeaver/core-ui'; -import type { IRoleFormProps } from '../IRoleFormProps'; +import type { ITeamFormProps } from '../ITeamFormProps'; import { ConnectionList } from './ConnectionList'; import { GrantedConnectionList } from './GrantedConnectionsList'; import { useGrantedConnections } from './useGrantedConnections'; @@ -42,7 +42,7 @@ const styles = css` } `; -export const GrantedConnections: TabContainerPanelComponent = observer(function GrantedConnections({ +export const GrantedConnections: TabContainerPanelComponent = observer(function GrantedConnections({ tabId, state: formState, }) { @@ -51,6 +51,7 @@ export const GrantedConnections: TabContainerPanelComponent = ob const state = useGrantedConnections(formState.config, formState.mode); const { selected } = useTab(tabId); + const loaded = state.state.loaded; const dbDriverResource = useMapResource( GrantedConnections, @@ -70,10 +71,10 @@ export const GrantedConnections: TabContainerPanelComponent = ob ), [state.state.grantedSubjects, connections.resource]); useEffect(() => { - if (selected && !state.state.loaded) { + if (selected && !loaded) { state.load(); } - }, [selected, state.state.loaded]); + }); if (!selected) { return null; @@ -97,7 +98,7 @@ export const GrantedConnections: TabContainerPanelComponent = ob {!connections.resource.values.length ? ( - {translate('administration_roles_role_granted_connections_empty')} + {translate('administration_teams_team_granted_connections_empty')} ) : ( <> diff --git a/webapp/packages/plugin-authentication-administration/src/Administration/Users/Roles/GrantedConnections/GrantedConnectionsList.tsx b/webapp/packages/plugin-authentication-administration/src/Administration/Users/Teams/GrantedConnections/GrantedConnectionsList.tsx similarity index 100% rename from webapp/packages/plugin-authentication-administration/src/Administration/Users/Roles/GrantedConnections/GrantedConnectionsList.tsx rename to webapp/packages/plugin-authentication-administration/src/Administration/Users/Teams/GrantedConnections/GrantedConnectionsList.tsx diff --git a/webapp/packages/plugin-authentication-administration/src/Administration/Users/Roles/GrantedConnections/GrantedConnectionsTabService.ts b/webapp/packages/plugin-authentication-administration/src/Administration/Users/Teams/GrantedConnections/GrantedConnectionsTabService.ts similarity index 64% rename from webapp/packages/plugin-authentication-administration/src/Administration/Users/Roles/GrantedConnections/GrantedConnectionsTabService.ts rename to webapp/packages/plugin-authentication-administration/src/Administration/Users/Teams/GrantedConnections/GrantedConnectionsTabService.ts index 40dcc26bda..70322faca0 100644 --- a/webapp/packages/plugin-authentication-administration/src/Administration/Users/Roles/GrantedConnections/GrantedConnectionsTabService.ts +++ b/webapp/packages/plugin-authentication-administration/src/Administration/Users/Teams/GrantedConnections/GrantedConnectionsTabService.ts @@ -6,26 +6,26 @@ * you may not use this file except in compliance with the License. */ -import { RolesResource } from '@cloudbeaver/core-authentication'; +import { TeamsResource } from '@cloudbeaver/core-authentication'; import { Bootstrap, injectable } from '@cloudbeaver/core-di'; import { NotificationService } from '@cloudbeaver/core-events'; import type { IExecutionContextProvider } from '@cloudbeaver/core-executor'; import { GraphQLService } from '@cloudbeaver/core-sdk'; import { isArraysEqual, MetadataValueGetter } from '@cloudbeaver/core-utils'; -import { roleContext } from '../Contexts/roleContext'; -import type { IRoleFormProps, IRoleFormSubmitData } from '../IRoleFormProps'; -import { RoleFormService } from '../RoleFormService'; +import { teamContext } from '../Contexts/teamContext'; +import type { ITeamFormProps, ITeamFormSubmitData } from '../ITeamFormProps'; +import { TeamFormService } from '../TeamFormService'; import { GrantedConnections } from './GrantedConnections'; import type { IGrantedConnectionsTabState } from './IGrantedConnectionsTabState'; @injectable() export class GrantedConnectionsTabService extends Bootstrap { - private key: string; + private readonly key: string; constructor( - private readonly roleFormService: RoleFormService, - private readonly rolesResource: RolesResource, + private readonly teamFormService: TeamFormService, + private readonly teamsResource: TeamsResource, private readonly graphQLService: GraphQLService, private readonly notificationService: NotificationService ) { @@ -34,21 +34,21 @@ export class GrantedConnectionsTabService extends Bootstrap { } register(): void { - this.roleFormService.tabsContainer.add({ + this.teamFormService.tabsContainer.add({ key: this.key, - name: 'administration_roles_role_granted_connections_tab_title', - title: 'administration_roles_role_granted_connections_tab_title', + name: 'administration_teams_team_granted_connections_tab_title', + title: 'administration_teams_team_granted_connections_tab_title', order: 3, stateGetter: context => this.stateGetter(context), panel: () => GrantedConnections, }); - this.roleFormService.formSubmittingTask.addHandler(this.save.bind(this)); + this.teamFormService.afterFormSubmittingTask.addHandler(this.save.bind(this)); } load(): Promise | void { } - private stateGetter(context: IRoleFormProps): MetadataValueGetter { + private stateGetter(context: ITeamFormProps): MetadataValueGetter { return () => ({ loading: false, loaded: false, @@ -59,27 +59,27 @@ export class GrantedConnectionsTabService extends Bootstrap { } private async save( - data: IRoleFormSubmitData, - contexts: IExecutionContextProvider + data: ITeamFormSubmitData, + contexts: IExecutionContextProvider ) { - const config = contexts.getContext(roleContext); - const status = contexts.getContext(this.roleFormService.configurationStatusContext); + const config = contexts.getContext(teamContext); + const status = contexts.getContext(this.teamFormService.configurationStatusContext); if (!status.saved) { return; } - const state = this.roleFormService.tabsContainer.getTabState( + const state = this.teamFormService.tabsContainer.getTabState( data.state.partsState, this.key, { state: data.state } ); - if (!config.roleId || !state.loaded) { + if (!config.teamId || !state.loaded) { return; } - const grantInfo = await this.rolesResource.getSubjectConnectionAccess(config.roleId); + const grantInfo = await this.teamsResource.getSubjectConnectionAccess(config.teamId); const initial = grantInfo.map(info => info.connectionId); const changed = !isArraysEqual(initial, state.grantedSubjects); @@ -90,7 +90,7 @@ export class GrantedConnectionsTabService extends Bootstrap { try { await this.graphQLService.sdk.setSubjectConnectionAccess({ - subjectId: config.roleId, + subjectId: config.teamId, connections: state.grantedSubjects, }); diff --git a/webapp/packages/plugin-authentication-administration/src/Administration/Users/Roles/GrantedConnections/GrantedConnectionsTableHeader/GrantedConnectionsTableHeader.tsx b/webapp/packages/plugin-authentication-administration/src/Administration/Users/Teams/GrantedConnections/GrantedConnectionsTableHeader/GrantedConnectionsTableHeader.tsx similarity index 95% rename from webapp/packages/plugin-authentication-administration/src/Administration/Users/Roles/GrantedConnections/GrantedConnectionsTableHeader/GrantedConnectionsTableHeader.tsx rename to webapp/packages/plugin-authentication-administration/src/Administration/Users/Teams/GrantedConnections/GrantedConnectionsTableHeader/GrantedConnectionsTableHeader.tsx index d84168befe..895130ec87 100644 --- a/webapp/packages/plugin-authentication-administration/src/Administration/Users/Roles/GrantedConnections/GrantedConnectionsTableHeader/GrantedConnectionsTableHeader.tsx +++ b/webapp/packages/plugin-authentication-administration/src/Administration/Users/Teams/GrantedConnections/GrantedConnectionsTableHeader/GrantedConnectionsTableHeader.tsx @@ -49,7 +49,7 @@ export const GrantedConnectionsTableHeader = observer(function GrantedCon
diff --git a/webapp/packages/plugin-authentication-administration/src/Administration/Users/Roles/GrantedConnections/GrantedConnectionsTableHeader/GrantedConnectionsTableInnerHeader.tsx b/webapp/packages/plugin-authentication-administration/src/Administration/Users/Teams/GrantedConnections/GrantedConnectionsTableHeader/GrantedConnectionsTableInnerHeader.tsx similarity index 100% rename from webapp/packages/plugin-authentication-administration/src/Administration/Users/Roles/GrantedConnections/GrantedConnectionsTableHeader/GrantedConnectionsTableInnerHeader.tsx rename to webapp/packages/plugin-authentication-administration/src/Administration/Users/Teams/GrantedConnections/GrantedConnectionsTableHeader/GrantedConnectionsTableInnerHeader.tsx diff --git a/webapp/packages/plugin-authentication-administration/src/Administration/Users/Roles/GrantedConnections/GrantedConnectionsTableItem.tsx b/webapp/packages/plugin-authentication-administration/src/Administration/Users/Teams/GrantedConnections/GrantedConnectionsTableItem.tsx similarity index 100% rename from webapp/packages/plugin-authentication-administration/src/Administration/Users/Roles/GrantedConnections/GrantedConnectionsTableItem.tsx rename to webapp/packages/plugin-authentication-administration/src/Administration/Users/Teams/GrantedConnections/GrantedConnectionsTableItem.tsx diff --git a/webapp/packages/plugin-authentication-administration/src/Administration/Users/Roles/GrantedConnections/IGrantedConnectionsTabState.ts b/webapp/packages/plugin-authentication-administration/src/Administration/Users/Teams/GrantedConnections/IGrantedConnectionsTabState.ts similarity index 100% rename from webapp/packages/plugin-authentication-administration/src/Administration/Users/Roles/GrantedConnections/IGrantedConnectionsTabState.ts rename to webapp/packages/plugin-authentication-administration/src/Administration/Users/Teams/GrantedConnections/IGrantedConnectionsTabState.ts diff --git a/webapp/packages/plugin-authentication-administration/src/Administration/Users/Roles/GrantedConnections/getFilteredConnections.ts b/webapp/packages/plugin-authentication-administration/src/Administration/Users/Teams/GrantedConnections/getFilteredConnections.ts similarity index 100% rename from webapp/packages/plugin-authentication-administration/src/Administration/Users/Roles/GrantedConnections/getFilteredConnections.ts rename to webapp/packages/plugin-authentication-administration/src/Administration/Users/Teams/GrantedConnections/getFilteredConnections.ts diff --git a/webapp/packages/plugin-authentication-administration/src/Administration/Users/Roles/GrantedConnections/useGrantedConnections.tsx b/webapp/packages/plugin-authentication-administration/src/Administration/Users/Teams/GrantedConnections/useGrantedConnections.tsx similarity index 85% rename from webapp/packages/plugin-authentication-administration/src/Administration/Users/Roles/GrantedConnections/useGrantedConnections.tsx rename to webapp/packages/plugin-authentication-administration/src/Administration/Users/Teams/GrantedConnections/useGrantedConnections.tsx index 38c033bf8f..8c0bf741da 100644 --- a/webapp/packages/plugin-authentication-administration/src/Administration/Users/Roles/GrantedConnections/useGrantedConnections.tsx +++ b/webapp/packages/plugin-authentication-administration/src/Administration/Users/Teams/GrantedConnections/useGrantedConnections.tsx @@ -8,14 +8,14 @@ import { action, computed, observable } from 'mobx'; -import { RoleInfo, RolesResource } from '@cloudbeaver/core-authentication'; -import { useTabState } from '@cloudbeaver/core-ui'; +import { TeamInfo, TeamsResource } from '@cloudbeaver/core-authentication'; import { useObservableRef } from '@cloudbeaver/core-blocks'; import { useService } from '@cloudbeaver/core-di'; import { NotificationService } from '@cloudbeaver/core-events'; +import { useTabState } from '@cloudbeaver/core-ui'; import { isArraysEqual } from '@cloudbeaver/core-utils'; -import type { RoleFormMode } from '../IRoleFormProps'; +import type { TeamFormMode } from '../ITeamFormProps'; import type { IGrantedConnectionsTabState } from './IGrantedConnectionsTabState'; interface State { @@ -27,8 +27,8 @@ interface State { load: () => Promise; } -export function useGrantedConnections(role: RoleInfo, mode: RoleFormMode): Readonly { - const resource = useService(RolesResource); +export function useGrantedConnections(team: TeamInfo, mode: TeamFormMode): Readonly { + const resource = useService(TeamsResource); const notificationService = useService(NotificationService); const state = useTabState(); @@ -54,20 +54,20 @@ export function useGrantedConnections(role: RoleInfo, mode: RoleFormMode): Reado this.state.loading = true; if (this.mode === 'edit') { - const grantInfo = await this.resource.getSubjectConnectionAccess(this.role.roleId); + const grantInfo = await this.resource.getSubjectConnectionAccess(this.team.teamId); this.state.grantedSubjects = grantInfo.map(subject => subject.connectionId); this.state.initialGrantedSubjects = this.state.grantedSubjects.slice(); } this.state.loaded = true; } catch (exception: any) { - this.notificationService.logException(exception, `Error getting granted connections for "${this.role.roleId}"`); + this.notificationService.logException(exception, `Error getting granted connections for "${this.team.teamId}"`); } finally { this.state.loading = false; } }, }), { state: observable.ref, changed: computed, grant: action.bound, revoke: action.bound, edit: action.bound }, - { state, role, mode, resource, notificationService }, + { state, team, mode, resource, notificationService }, ['load']); } diff --git a/webapp/packages/plugin-authentication-administration/src/Administration/Users/Roles/GrantedUsers/GrantedUserList.tsx b/webapp/packages/plugin-authentication-administration/src/Administration/Users/Teams/GrantedUsers/GrantedUserList.tsx similarity index 98% rename from webapp/packages/plugin-authentication-administration/src/Administration/Users/Roles/GrantedUsers/GrantedUserList.tsx rename to webapp/packages/plugin-authentication-administration/src/Administration/Users/Teams/GrantedUsers/GrantedUserList.tsx index 1540bdc284..f0f3b882d9 100644 --- a/webapp/packages/plugin-authentication-administration/src/Administration/Users/Roles/GrantedUsers/GrantedUserList.tsx +++ b/webapp/packages/plugin-authentication-administration/src/Administration/Users/Teams/GrantedUsers/GrantedUserList.tsx @@ -126,7 +126,7 @@ export const GrantedUserList = observer(function GrantedUserList({ key={user.userId} id={user.userId} name={`${user.userId}${activeUser ? ' (you)' : ''}`} - tooltip={activeUser ? translate('administration_roles_role_granted_users_permission_denied') : user.userId} + tooltip={activeUser ? translate('administration_teams_team_granted_users_permission_denied') : user.userId} icon='/icons/user.svg' iconTooltip={translate('authentication_user_icon_tooltip')} disabled={disabled} diff --git a/webapp/packages/plugin-authentication-administration/src/Administration/Users/Roles/GrantedUsers/GrantedUsers.tsx b/webapp/packages/plugin-authentication-administration/src/Administration/Users/Teams/GrantedUsers/GrantedUsers.tsx similarity index 92% rename from webapp/packages/plugin-authentication-administration/src/Administration/Users/Roles/GrantedUsers/GrantedUsers.tsx rename to webapp/packages/plugin-authentication-administration/src/Administration/Users/Teams/GrantedUsers/GrantedUsers.tsx index 5d76a0a7a5..2f50629d49 100644 --- a/webapp/packages/plugin-authentication-administration/src/Administration/Users/Roles/GrantedUsers/GrantedUsers.tsx +++ b/webapp/packages/plugin-authentication-administration/src/Administration/Users/Teams/GrantedUsers/GrantedUsers.tsx @@ -20,7 +20,7 @@ import { CachedMapAllKey } from '@cloudbeaver/core-sdk'; import { TabContainerPanelComponent, useTab } from '@cloudbeaver/core-ui'; -import type { IRoleFormProps } from '../IRoleFormProps'; +import type { ITeamFormProps } from '../ITeamFormProps'; import { GrantedUserList } from './GrantedUserList'; import { useGrantedUsers } from './useGrantedUsers'; import { UserList } from './UserList'; @@ -41,7 +41,7 @@ const styles = css` } `; -export const GrantedUsers: TabContainerPanelComponent = observer(function GrantedUsers({ +export const GrantedUsers: TabContainerPanelComponent = observer(function GrantedUsers({ tabId, state: formState, }) { @@ -73,7 +73,7 @@ export const GrantedUsers: TabContainerPanelComponent = observer {!users.resource.values.length ? ( - {translate('administration_roles_role_granted_users_empty')} + {translate('administration_teams_team_granted_users_empty')} ) : ( <> diff --git a/webapp/packages/plugin-authentication-administration/src/Administration/Users/Roles/GrantedUsers/GrantedUsersTabService.ts b/webapp/packages/plugin-authentication-administration/src/Administration/Users/Teams/GrantedUsers/GrantedUsersTabService.ts similarity index 65% rename from webapp/packages/plugin-authentication-administration/src/Administration/Users/Roles/GrantedUsers/GrantedUsersTabService.ts rename to webapp/packages/plugin-authentication-administration/src/Administration/Users/Teams/GrantedUsers/GrantedUsersTabService.ts index 4aa285dc73..cda0f1a681 100644 --- a/webapp/packages/plugin-authentication-administration/src/Administration/Users/Roles/GrantedUsers/GrantedUsersTabService.ts +++ b/webapp/packages/plugin-authentication-administration/src/Administration/Users/Teams/GrantedUsers/GrantedUsersTabService.ts @@ -6,26 +6,26 @@ * you may not use this file except in compliance with the License. */ -import { RolesResource, UsersResource } from '@cloudbeaver/core-authentication'; +import { TeamsResource, UsersResource } from '@cloudbeaver/core-authentication'; import { Bootstrap, injectable } from '@cloudbeaver/core-di'; import { NotificationService } from '@cloudbeaver/core-events'; import type { IExecutionContextProvider } from '@cloudbeaver/core-executor'; import { isArraysEqual, MetadataValueGetter } from '@cloudbeaver/core-utils'; -import { roleContext } from '../Contexts/roleContext'; -import type { IRoleFormProps, IRoleFormSubmitData } from '../IRoleFormProps'; -import { RoleFormService } from '../RoleFormService'; +import { teamContext } from '../Contexts/teamContext'; +import type { ITeamFormProps, ITeamFormSubmitData } from '../ITeamFormProps'; +import { TeamFormService } from '../TeamFormService'; import { GrantedUsers } from './GrantedUsers'; import type { IGrantedUsersTabState } from './IGrantedUsersTabState'; @injectable() export class GrantedUsersTabService extends Bootstrap { - private key: string; + private readonly key: string; constructor( - private readonly roleFormService: RoleFormService, + private readonly teamFormService: TeamFormService, private readonly usersResource: UsersResource, - private readonly rolesResource: RolesResource, + private readonly teamsResource: TeamsResource, private readonly notificationService: NotificationService ) { super(); @@ -33,21 +33,21 @@ export class GrantedUsersTabService extends Bootstrap { } register(): void { - this.roleFormService.tabsContainer.add({ + this.teamFormService.tabsContainer.add({ key: this.key, - name: 'administration_roles_role_granted_users_tab_title', - title: 'administration_roles_role_granted_users_tab_title', + name: 'administration_teams_team_granted_users_tab_title', + title: 'administration_teams_team_granted_users_tab_title', order: 2, stateGetter: context => this.stateGetter(context), panel: () => GrantedUsers, }); - this.roleFormService.formSubmittingTask.addHandler(this.save.bind(this)); + this.teamFormService.afterFormSubmittingTask.addHandler(this.save.bind(this)); } load(): void { } - private stateGetter(context: IRoleFormProps): MetadataValueGetter { + private stateGetter(context: ITeamFormProps): MetadataValueGetter { return () => ({ loading: false, loaded: false, @@ -58,27 +58,27 @@ export class GrantedUsersTabService extends Bootstrap { } private async save( - data: IRoleFormSubmitData, - contexts: IExecutionContextProvider + data: ITeamFormSubmitData, + contexts: IExecutionContextProvider ) { - const config = contexts.getContext(roleContext); - const status = contexts.getContext(this.roleFormService.configurationStatusContext); + const config = contexts.getContext(teamContext); + const status = contexts.getContext(this.teamFormService.configurationStatusContext); if (!status.saved) { return; } - const state = this.roleFormService.tabsContainer.getTabState( + const state = this.teamFormService.tabsContainer.getTabState( data.state.partsState, this.key, { state: data.state } ); - if (!config.roleId || !state.loaded) { + if (!config.teamId || !state.loaded) { return; } - const initial = await this.rolesResource.loadGrantedUsers(config.roleId); + const initial = await this.teamsResource.loadGrantedUsers(config.teamId); const changed = !isArraysEqual(initial, state.grantedUsers); @@ -93,13 +93,13 @@ export class GrantedUsersTabService extends Bootstrap { try { for (const user of revokedUsers) { - await this.usersResource.revokeRole(user, config.roleId); + await this.usersResource.revokeTeam(user, config.teamId); revoked.push(user); } for (const user of state.grantedUsers) { if (!initial.includes(user)) { - await this.usersResource.grantRole(user, config.roleId); + await this.usersResource.grantTeam(user, config.teamId); granted.push(user); } } diff --git a/webapp/packages/plugin-authentication-administration/src/Administration/Users/Roles/GrantedUsers/GrantedUsersTableHeader/GrantedUsersTableHeader.tsx b/webapp/packages/plugin-authentication-administration/src/Administration/Users/Teams/GrantedUsers/GrantedUsersTableHeader/GrantedUsersTableHeader.tsx similarity index 95% rename from webapp/packages/plugin-authentication-administration/src/Administration/Users/Roles/GrantedUsers/GrantedUsersTableHeader/GrantedUsersTableHeader.tsx rename to webapp/packages/plugin-authentication-administration/src/Administration/Users/Teams/GrantedUsers/GrantedUsersTableHeader/GrantedUsersTableHeader.tsx index 71bb41915a..20b1de2c01 100644 --- a/webapp/packages/plugin-authentication-administration/src/Administration/Users/Roles/GrantedUsers/GrantedUsersTableHeader/GrantedUsersTableHeader.tsx +++ b/webapp/packages/plugin-authentication-administration/src/Administration/Users/Teams/GrantedUsers/GrantedUsersTableHeader/GrantedUsersTableHeader.tsx @@ -49,7 +49,7 @@ export const GrantedUsersTableHeader = observer(function GrantedUsersTabl
diff --git a/webapp/packages/plugin-authentication-administration/src/Administration/Users/Roles/GrantedUsers/GrantedUsersTableHeader/GrantedUsersTableInnerHeader.tsx b/webapp/packages/plugin-authentication-administration/src/Administration/Users/Teams/GrantedUsers/GrantedUsersTableHeader/GrantedUsersTableInnerHeader.tsx similarity index 94% rename from webapp/packages/plugin-authentication-administration/src/Administration/Users/Roles/GrantedUsers/GrantedUsersTableHeader/GrantedUsersTableInnerHeader.tsx rename to webapp/packages/plugin-authentication-administration/src/Administration/Users/Teams/GrantedUsers/GrantedUsersTableHeader/GrantedUsersTableInnerHeader.tsx index 23e66809c1..cf1cfb4d10 100644 --- a/webapp/packages/plugin-authentication-administration/src/Administration/Users/Roles/GrantedUsers/GrantedUsersTableHeader/GrantedUsersTableInnerHeader.tsx +++ b/webapp/packages/plugin-authentication-administration/src/Administration/Users/Teams/GrantedUsers/GrantedUsersTableHeader/GrantedUsersTableInnerHeader.tsx @@ -36,7 +36,7 @@ export const GrantedUsersTableInnerHeader = observer(function GrantedUser - {translate('administration_roles_role_granted_users_user_id')} + {translate('administration_teams_team_granted_users_user_id')} ); }); diff --git a/webapp/packages/plugin-authentication-administration/src/Administration/Users/Roles/GrantedUsers/GrantedUsersTableItem.tsx b/webapp/packages/plugin-authentication-administration/src/Administration/Users/Teams/GrantedUsers/GrantedUsersTableItem.tsx similarity index 100% rename from webapp/packages/plugin-authentication-administration/src/Administration/Users/Roles/GrantedUsers/GrantedUsersTableItem.tsx rename to webapp/packages/plugin-authentication-administration/src/Administration/Users/Teams/GrantedUsers/GrantedUsersTableItem.tsx diff --git a/webapp/packages/plugin-authentication-administration/src/Administration/Users/Roles/GrantedUsers/IGrantedUsersTabState.ts b/webapp/packages/plugin-authentication-administration/src/Administration/Users/Teams/GrantedUsers/IGrantedUsersTabState.ts similarity index 100% rename from webapp/packages/plugin-authentication-administration/src/Administration/Users/Roles/GrantedUsers/IGrantedUsersTabState.ts rename to webapp/packages/plugin-authentication-administration/src/Administration/Users/Teams/GrantedUsers/IGrantedUsersTabState.ts diff --git a/webapp/packages/plugin-authentication-administration/src/Administration/Users/Roles/GrantedUsers/UserList.tsx b/webapp/packages/plugin-authentication-administration/src/Administration/Users/Teams/GrantedUsers/UserList.tsx similarity index 98% rename from webapp/packages/plugin-authentication-administration/src/Administration/Users/Roles/GrantedUsers/UserList.tsx rename to webapp/packages/plugin-authentication-administration/src/Administration/Users/Teams/GrantedUsers/UserList.tsx index 551afb6270..636802e916 100644 --- a/webapp/packages/plugin-authentication-administration/src/Administration/Users/Roles/GrantedUsers/UserList.tsx +++ b/webapp/packages/plugin-authentication-administration/src/Administration/Users/Teams/GrantedUsers/UserList.tsx @@ -118,7 +118,7 @@ export const UserList = observer(function UserList({ key={user.userId} id={user.userId} name={`${user.userId}${activeUser ? ' (you)' : ''}`} - tooltip={activeUser ? translate('administration_roles_role_granted_users_permission_denied') : user.userId} + tooltip={activeUser ? translate('administration_teams_team_granted_users_permission_denied') : user.userId} icon='/icons/user.svg' iconTooltip={translate('authentication_user_icon_tooltip')} disabled={disabled} diff --git a/webapp/packages/plugin-authentication-administration/src/Administration/Users/Roles/GrantedUsers/getFilteredUsers.ts b/webapp/packages/plugin-authentication-administration/src/Administration/Users/Teams/GrantedUsers/getFilteredUsers.ts similarity index 100% rename from webapp/packages/plugin-authentication-administration/src/Administration/Users/Roles/GrantedUsers/getFilteredUsers.ts rename to webapp/packages/plugin-authentication-administration/src/Administration/Users/Teams/GrantedUsers/getFilteredUsers.ts diff --git a/webapp/packages/plugin-authentication-administration/src/Administration/Users/Roles/GrantedUsers/useGrantedUsers.tsx b/webapp/packages/plugin-authentication-administration/src/Administration/Users/Teams/GrantedUsers/useGrantedUsers.tsx similarity index 87% rename from webapp/packages/plugin-authentication-administration/src/Administration/Users/Roles/GrantedUsers/useGrantedUsers.tsx rename to webapp/packages/plugin-authentication-administration/src/Administration/Users/Teams/GrantedUsers/useGrantedUsers.tsx index 425fa60861..673e75a15b 100644 --- a/webapp/packages/plugin-authentication-administration/src/Administration/Users/Roles/GrantedUsers/useGrantedUsers.tsx +++ b/webapp/packages/plugin-authentication-administration/src/Administration/Users/Teams/GrantedUsers/useGrantedUsers.tsx @@ -8,14 +8,14 @@ import { action, computed, observable } from 'mobx'; -import { RoleInfo, RolesResource } from '@cloudbeaver/core-authentication'; -import { useTabState } from '@cloudbeaver/core-ui'; +import { TeamInfo, TeamsResource } from '@cloudbeaver/core-authentication'; import { useObservableRef } from '@cloudbeaver/core-blocks'; import { useService } from '@cloudbeaver/core-di'; import { NotificationService } from '@cloudbeaver/core-events'; +import { useTabState } from '@cloudbeaver/core-ui'; import { isArraysEqual } from '@cloudbeaver/core-utils'; -import type { RoleFormMode } from '../IRoleFormProps'; +import type { TeamFormMode } from '../ITeamFormProps'; import type { IGrantedUsersTabState } from './IGrantedUsersTabState'; interface State { @@ -27,8 +27,8 @@ interface State { load: () => Promise; } -export function useGrantedUsers(role: RoleInfo, mode: RoleFormMode): Readonly { - const resource = useService(RolesResource); +export function useGrantedUsers(team: TeamInfo, mode: TeamFormMode): Readonly { + const resource = useService(TeamsResource); const notificationService = useService(NotificationService); const state = useTabState(); @@ -54,7 +54,7 @@ export function useGrantedUsers(role: RoleInfo, mode: RoleFormMode): Readonly; - readonly info: RoleInfo | undefined; + readonly info: TeamInfo | undefined; readonly statusMessage: string | null; readonly disabled: boolean; readonly readonly: boolean; readonly loading: boolean; - readonly submittingTask: IExecutorHandlersCollection; - readonly resource: CachedMapResource; + readonly submittingTask: IExecutorHandlersCollection; + readonly resource: CachedMapResource; readonly load: () => Promise; - readonly loadRoleInfo: () => Promise; + readonly loadTeamInfo: () => Promise; readonly save: () => Promise; readonly setOptions: ( - mode: RoleFormMode, + mode: TeamFormMode, ) => this; } -export interface IRoleFormProps { - state: IRoleFormState; +export interface ITeamFormProps { + state: ITeamFormState; onCancel?: () => void; } -export interface IRoleFormFillConfigData { +export interface ITeamFormFillConfigData { updated: boolean; - state: IRoleFormState; + state: ITeamFormState; } -export interface IRoleFormSubmitData { - state: IRoleFormState; +export interface ITeamFormSubmitData { + state: ITeamFormState; } diff --git a/webapp/packages/plugin-authentication-administration/src/Administration/Users/Roles/Options/RoleOptions.tsx b/webapp/packages/plugin-authentication-administration/src/Administration/Users/Teams/Options/TeamOptions.tsx similarity index 84% rename from webapp/packages/plugin-authentication-administration/src/Administration/Users/Roles/Options/RoleOptions.tsx rename to webapp/packages/plugin-authentication-administration/src/Administration/Users/Teams/Options/TeamOptions.tsx index 7e330f63da..0c71f21513 100644 --- a/webapp/packages/plugin-authentication-administration/src/Administration/Users/Roles/Options/RoleOptions.tsx +++ b/webapp/packages/plugin-authentication-administration/src/Administration/Users/Teams/Options/TeamOptions.tsx @@ -12,12 +12,10 @@ import styled, { css } from 'reshadow'; import { PermissionsResource } from '@cloudbeaver/core-administration'; import { BASE_CONTAINERS_STYLES, ColoredContainer, FieldCheckbox, Group, GroupTitle, InputField, SubmittingForm, Textarea, useMapResource, useTranslate, useStyles } from '@cloudbeaver/core-blocks'; - import { CachedMapAllKey } from '@cloudbeaver/core-sdk'; - import type { TabContainerPanelComponent } from '@cloudbeaver/core-ui'; -import type { IRoleFormProps } from '../IRoleFormProps'; +import type { ITeamFormProps } from '../ITeamFormProps'; const styles = css` SubmittingForm { @@ -29,13 +27,13 @@ const styles = css` } `; -export const RoleOptions: TabContainerPanelComponent = observer(function RoleOptions({ +export const TeamOptions: TabContainerPanelComponent = observer(function TeamOptions({ state, }) { const formRef = useRef(null); const translate = useTranslate(); - const permissionsResource = useMapResource(RoleOptions, PermissionsResource, CachedMapAllKey); + const permissionsResource = useMapResource(TeamOptions, PermissionsResource, CachedMapAllKey); const style = useStyles(BASE_CONTAINERS_STYLES, styles); const edit = state.mode === 'edit'; @@ -44,7 +42,7 @@ export const RoleOptions: TabContainerPanelComponent = observer( = observer( tiny fill > - {translate('administration_roles_role_id')} + {translate('administration_teams_team_id')} - {translate('administration_roles_role_name')} + {translate('administration_teams_team_name')} - {translate('administration_roles_role_permissions')} + {translate('administration_teams_team_permissions')} {permissionsResource.resource.values.map(permission => { const label = permission.label ?? permission.id; @@ -100,7 +98,7 @@ export const RoleOptions: TabContainerPanelComponent = observer( id={permission.id} value={permission.id} title={tooltip} - name='rolePermissions' + name='teamPermissions' state={state.config} readOnly={state.readonly} disabled={state.disabled} 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 new file mode 100644 index 0000000000..c6614172f9 --- /dev/null +++ b/webapp/packages/plugin-authentication-administration/src/Administration/Users/Teams/Options/TeamOptionsTabService.ts @@ -0,0 +1,153 @@ +/* + * 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 { TeamsResource } from '@cloudbeaver/core-authentication'; +import { Bootstrap, injectable } from '@cloudbeaver/core-di'; +import type { IExecutionContextProvider } from '@cloudbeaver/core-executor'; +import { LocalizationService } from '@cloudbeaver/core-localization'; +import { getUniqueName } from '@cloudbeaver/core-utils'; + +import { teamContext } from '../Contexts/teamContext'; +import type { ITeamFormFillConfigData, ITeamFormSubmitData } from '../ITeamFormProps'; +import { TeamFormService } from '../TeamFormService'; +import { TeamOptions } from './TeamOptions'; + +@injectable() +export class TeamOptionsTabService extends Bootstrap { + constructor( + private readonly teamFormService: TeamFormService, + private readonly teamResource: TeamsResource, + private readonly localizationService: LocalizationService + ) { + super(); + } + + register(): void { + this.teamFormService.tabsContainer.add({ + key: 'options', + name: 'ui_options', + order: 1, + panel: () => TeamOptions, + }); + + this.teamFormService.prepareConfigTask + .addHandler(this.prepareConfig.bind(this)); + + this.teamFormService.formValidationTask + .addHandler(this.validate.bind(this)); + + this.teamFormService.formSubmittingTask + .addHandler(this.save.bind(this)); + + this.teamFormService.fillConfigTask + .addHandler(this.fillConfig.bind(this)); + } + + load(): void { } + + private async prepareConfig( + { + state, + }: ITeamFormSubmitData, + contexts: IExecutionContextProvider + ) { + const config = contexts.getContext(teamContext); + + config.teamId = state.config.teamId; + + if (state.config.teamName) { + config.teamName = state.config.teamName.trim(); + + if (state.mode === 'create') { + const teamNames = this.teamResource.values.map(team => team.teamName).filter(Boolean) as string[]; + config.teamName = getUniqueName(config.teamName, teamNames); + } + } + + if (state.config.description) { + config.description = state.config.description; + } + + config.teamPermissions = [...state.config.teamPermissions]; + } + + private async validate( + { + state, + }: ITeamFormSubmitData, + contexts: IExecutionContextProvider + ) { + const validation = contexts.getContext(this.teamFormService.configurationValidationContext); + + if (state.mode === 'create') { + if (!state.config.teamId.trim()) { + validation.error('administration_teams_team_info_id_invalid'); + } + + if (this.teamResource.has(state.config.teamId)) { + validation.error(this.localizationService.translate('administration_teams_team_info_exists', undefined, { + teamId: state.config.teamId, + })); + } + } + } + + private async save( + { + state, + }: ITeamFormSubmitData, + contexts: IExecutionContextProvider + ) { + const status = contexts.getContext(this.teamFormService.configurationStatusContext); + const config = contexts.getContext(teamContext); + + const create = state.mode === 'create'; + + try { + if (create) { + const team = await this.teamResource.createTeam(config); + status.info('administration_teams_team_info_created'); + status.info(team.teamId); + } else { + const team = await this.teamResource.updateTeam(config); + status.info('administration_teams_team_info_updated'); + status.info(team.teamId); + } + } catch (exception: any) { + if (create) { + status.error(exception, 'administration_teams_team_create_error'); + } else { + status.error(exception, 'administration_teams_team_save_error'); + } + } + } + + private fillConfig( + { state, updated }: ITeamFormFillConfigData, + contexts: IExecutionContextProvider + ) { + if (!updated) { + return; + } + + if (!state.info) { + return; + } + + 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; + } + state.config.teamPermissions = [...state.info.teamPermissions]; + } +} diff --git a/webapp/packages/plugin-authentication-administration/src/Administration/Users/Roles/RoleForm.tsx b/webapp/packages/plugin-authentication-administration/src/Administration/Users/Teams/TeamForm.tsx similarity index 81% rename from webapp/packages/plugin-authentication-administration/src/Administration/Users/Roles/RoleForm.tsx rename to webapp/packages/plugin-authentication-administration/src/Administration/Users/Teams/TeamForm.tsx index 020460f7b8..7f38bab62e 100644 --- a/webapp/packages/plugin-authentication-administration/src/Administration/Users/Roles/RoleForm.tsx +++ b/webapp/packages/plugin-authentication-administration/src/Administration/Users/Teams/TeamForm.tsx @@ -10,16 +10,14 @@ import { observer } from 'mobx-react-lite'; import { useEffect } from 'react'; import styled, { css } from 'reshadow'; -import type { RoleInfo } from '@cloudbeaver/core-authentication'; +import type { TeamInfo } from '@cloudbeaver/core-authentication'; import { Placeholder, useObjectRef, useExecutor, BASE_CONTAINERS_STYLES, IconOrImage, useTranslate, useStyles } from '@cloudbeaver/core-blocks'; import { useService } from '@cloudbeaver/core-di'; - - import { TabsState, TabList, UNDERLINE_TAB_STYLES, TabPanelList, BASE_TAB_STYLES } from '@cloudbeaver/core-ui'; -import { roleContext } from './Contexts/roleContext'; -import type { IRoleFormState } from './IRoleFormProps'; -import { RoleFormService } from './RoleFormService'; +import { teamContext } from './Contexts/teamContext'; +import type { ITeamFormState } from './ITeamFormProps'; +import { TeamFormService } from './TeamFormService'; const tabsStyles = css` TabList { @@ -35,7 +33,7 @@ const tabsStyles = css` `; const topBarStyles = css` - role-top-bar { + team-top-bar { composes: theme-border-color-background theme-background-secondary theme-text-on-secondary from global; position: relative; display: flex; @@ -50,18 +48,18 @@ const topBarStyles = css` border-color: inherit; } } - role-top-bar-tabs { + team-top-bar-tabs { flex: 1; } - role-top-bar-actions { + team-top-bar-actions { display: flex; align-items: center; padding: 0 24px; gap: 16px; } - role-status-message { + team-status-message { composes: theme-typography--caption from global; height: 24px; padding: 0 16px; @@ -96,13 +94,13 @@ const formStyles = css` `; interface Props { - state: IRoleFormState; + state: ITeamFormState; onCancel?: () => void; - onSave?: (role: RoleInfo) => void; + onSave?: (team: TeamInfo) => void; className?: string; } -export const RoleForm = observer(function RoleForm({ +export const TeamForm = observer(function TeamForm({ state, onCancel, onSave = () => { }, @@ -112,14 +110,14 @@ export const RoleForm = observer(function RoleForm({ const props = useObjectRef({ onSave }); const style = [BASE_TAB_STYLES, tabsStyles, UNDERLINE_TAB_STYLES]; const styles = useStyles(style, BASE_CONTAINERS_STYLES, topBarStyles, formStyles); - const service = useService(RoleFormService); + const service = useService(TeamFormService); useExecutor({ executor: state.submittingTask, postHandlers: [function save(data, contexts) { const validation = contexts.getContext(service.configurationValidationContext); const state = contexts.getContext(service.configurationStatusContext); - const config = contexts.getContext(roleContext); + const config = contexts.getContext(teamContext); if (validation.valid && state.saved) { props.onSave(config); @@ -128,7 +126,7 @@ export const RoleForm = observer(function RoleForm({ }); useEffect(() => { - state.loadRoleInfo(); + state.loadTeamInfo(); }, []); return styled(styles)( @@ -139,22 +137,22 @@ export const RoleForm = observer(function RoleForm({ onCancel={onCancel} > - - - + + + {state.statusMessage && ( <> {translate(state.statusMessage)} )} - + - - + + - - + + diff --git a/webapp/packages/plugin-authentication-administration/src/Administration/Users/Roles/RoleFormBaseActions.tsx b/webapp/packages/plugin-authentication-administration/src/Administration/Users/Teams/TeamFormBaseActions.tsx similarity index 85% rename from webapp/packages/plugin-authentication-administration/src/Administration/Users/Roles/RoleFormBaseActions.tsx rename to webapp/packages/plugin-authentication-administration/src/Administration/Users/Teams/TeamFormBaseActions.tsx index 8b4d238e08..0a54a1a5b4 100644 --- a/webapp/packages/plugin-authentication-administration/src/Administration/Users/Roles/RoleFormBaseActions.tsx +++ b/webapp/packages/plugin-authentication-administration/src/Administration/Users/Teams/TeamFormBaseActions.tsx @@ -11,9 +11,9 @@ import { observer } from 'mobx-react-lite'; import { Button, PlaceholderComponent, useTranslate } from '@cloudbeaver/core-blocks'; -import type { IRoleFormProps } from './IRoleFormProps'; +import type { ITeamFormProps } from './ITeamFormProps'; -export const RoleFormBaseActions: PlaceholderComponent = observer(function RoleFormBaseActions({ +export const TeamFormBaseActions: PlaceholderComponent = observer(function TeamFormBaseActions({ state, onCancel, }) { diff --git a/webapp/packages/plugin-authentication-administration/src/Administration/Users/Roles/RoleFormService.ts b/webapp/packages/plugin-authentication-administration/src/Administration/Users/Teams/TeamFormService.ts similarity index 72% rename from webapp/packages/plugin-authentication-administration/src/Administration/Users/Roles/RoleFormService.ts rename to webapp/packages/plugin-authentication-administration/src/Administration/Users/Teams/TeamFormService.ts index 78fa9e748f..efba93b3bc 100644 --- a/webapp/packages/plugin-authentication-administration/src/Administration/Users/Roles/RoleFormService.ts +++ b/webapp/packages/plugin-authentication-administration/src/Administration/Users/Teams/TeamFormService.ts @@ -12,17 +12,17 @@ import { ENotificationType, NotificationService } from '@cloudbeaver/core-events import { ExecutorHandlersCollection, ExecutorInterrupter, IExecutorHandler, IExecutorHandlersCollection } from '@cloudbeaver/core-executor'; import { TabsContainer } from '@cloudbeaver/core-ui'; -import type { IRoleFormFillConfigData, IRoleFormProps, IRoleFormState, IRoleFormSubmitData } from './IRoleFormProps'; -import { RoleFormBaseActions } from './RoleFormBaseActions'; +import type { ITeamFormFillConfigData, ITeamFormProps, ITeamFormState, ITeamFormSubmitData } from './ITeamFormProps'; +import { TeamFormBaseActions } from './TeamFormBaseActions'; -export interface IRoleFormValidation { +export interface ITeamFormValidation { valid: boolean; messages: string[]; info: (message: string) => void; error: (message: string) => void; } -export interface IRoleFormStatus { +export interface ITeamFormStatus { saved: boolean; messages: string[]; exception: Error | null; @@ -31,16 +31,17 @@ export interface IRoleFormStatus { } @injectable() -export class RoleFormService { - readonly tabsContainer: TabsContainer; - readonly actionsContainer: PlaceholderContainer; +export class TeamFormService { + readonly tabsContainer: TabsContainer; + readonly actionsContainer: PlaceholderContainer; - readonly configureTask: IExecutorHandlersCollection; - readonly fillConfigTask: IExecutorHandlersCollection; - readonly prepareConfigTask: IExecutorHandlersCollection; - readonly formValidationTask: IExecutorHandlersCollection; - readonly formSubmittingTask: IExecutorHandlersCollection; - readonly formStateTask: IExecutorHandlersCollection; + readonly configureTask: IExecutorHandlersCollection; + readonly fillConfigTask: IExecutorHandlersCollection; + readonly prepareConfigTask: IExecutorHandlersCollection; + readonly formValidationTask: IExecutorHandlersCollection; + readonly formSubmittingTask: IExecutorHandlersCollection; + readonly afterFormSubmittingTask: IExecutorHandlersCollection; + readonly formStateTask: IExecutorHandlersCollection; constructor( private readonly notificationService: NotificationService, @@ -51,23 +52,25 @@ export class RoleFormService { this.fillConfigTask = new ExecutorHandlersCollection(); this.prepareConfigTask = new ExecutorHandlersCollection(); this.formSubmittingTask = new ExecutorHandlersCollection(); + this.afterFormSubmittingTask = new ExecutorHandlersCollection(); this.formValidationTask = new ExecutorHandlersCollection(); this.formStateTask = new ExecutorHandlersCollection(); this.formSubmittingTask .before(this.formValidationTask) - .before(this.prepareConfigTask); + .before(this.prepareConfigTask) + .next(this.afterFormSubmittingTask); this.formStateTask - .before(this.prepareConfigTask, state => ({ state, submitType: 'submit' })); + .before(this.prepareConfigTask, state => ({ state, submitType: 'submit' })); this.formSubmittingTask.addPostHandler(this.showSubmittingStatusMessage); this.formValidationTask.addPostHandler(this.ensureValidation); - this.actionsContainer.add(RoleFormBaseActions); + this.actionsContainer.add(TeamFormBaseActions); } - configurationValidationContext = (): IRoleFormValidation => ({ + configurationValidationContext = (): ITeamFormValidation => ({ valid: true, messages: [], info(message: string) { @@ -79,7 +82,7 @@ export class RoleFormService { }, }); - configurationStatusContext = (): IRoleFormStatus => ({ + configurationStatusContext = (): ITeamFormStatus => ({ saved: true, messages: [], exception: null, @@ -95,7 +98,7 @@ export class RoleFormService { }, }); - private readonly showSubmittingStatusMessage: IExecutorHandler = (data, contexts) => { + private readonly showSubmittingStatusMessage: IExecutorHandler = (data, contexts) => { const status = contexts.getContext(this.configurationStatusContext); if (!status.saved) { @@ -118,7 +121,7 @@ export class RoleFormService { } }; - private readonly ensureValidation: IExecutorHandler = (data, contexts) => { + private readonly ensureValidation: IExecutorHandler = (data, contexts) => { const validation = contexts.getContext(this.configurationValidationContext); if (!validation.valid) { diff --git a/webapp/packages/plugin-authentication-administration/src/Administration/Users/Roles/RoleFormState.ts b/webapp/packages/plugin-authentication-administration/src/Administration/Users/Teams/TeamFormState.ts similarity index 56% rename from webapp/packages/plugin-authentication-administration/src/Administration/Users/Roles/RoleFormState.ts rename to webapp/packages/plugin-authentication-administration/src/Administration/Users/Teams/TeamFormState.ts index d37238ac21..5caff777aa 100644 --- a/webapp/packages/plugin-authentication-administration/src/Administration/Users/Roles/RoleFormState.ts +++ b/webapp/packages/plugin-authentication-administration/src/Administration/Users/Teams/TeamFormState.ts @@ -8,72 +8,72 @@ import { computed, makeObservable, observable } from 'mobx'; -import type { RoleInfo } from '@cloudbeaver/core-authentication'; +import type { TeamInfo } 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 { roleFormConfigureContext } from './Contexts/roleFormConfigureContext'; -import { IRoleFormStateInfo, roleFormStateContext } from './Contexts/roleFormStateContext'; -import type { IRoleFormState, IRoleFormSubmitData, RoleFormMode } from './IRoleFormProps'; -import type { RoleFormService } from './RoleFormService'; +import { teamFormConfigureContext } from './Contexts/teamFormConfigureContext'; +import { ITeamFormStateInfo, teamFormStateContext } from './Contexts/teamFormStateContext'; +import type { ITeamFormState, ITeamFormSubmitData, TeamFormMode } from './ITeamFormProps'; +import type { TeamFormService } from './TeamFormService'; -export class RoleFormState implements IRoleFormState { - mode: RoleFormMode; - config: RoleInfo; +export class TeamFormState implements ITeamFormState { + mode: TeamFormMode; + config: TeamInfo; statusMessage: string | null; configured: boolean; partsState: MetadataMap; - get info(): RoleInfo | undefined { - if (!this.config.roleId) { + get info(): TeamInfo | undefined { + if (!this.config.teamId) { return undefined; } - return this.resource.get(this.config.roleId); + return this.resource.get(this.config.teamId); } get loading(): boolean { - return this.loadRoleTask.executing || this.submittingTask.executing; + return this.loadTeamTask.executing || this.submittingTask.executing; } get disabled(): boolean { - return this.loading || !!this.stateInfo?.disabled || this.loadRoleTask.executing; + return this.loading || !!this.stateInfo?.disabled || this.loadTeamTask.executing; } get readonly(): boolean { return false; } - readonly resource: CachedMapResource; + readonly resource: CachedMapResource; - readonly service: RoleFormService; - readonly submittingTask: IExecutor; + readonly service: TeamFormService; + readonly submittingTask: IExecutor; - private stateInfo: IRoleFormStateInfo | null; - private readonly loadRoleTask: IExecutor; - private readonly formStateTask: IExecutor; + private stateInfo: ITeamFormStateInfo | null; + private readonly loadTeamTask: IExecutor; + private readonly formStateTask: IExecutor; constructor( - service: RoleFormService, - resource: CachedMapResource + service: TeamFormService, + resource: CachedMapResource ) { this.resource = resource; this.config = { - roleId: '', - rolePermissions: [], + teamId: '', + teamPermissions: [], }; this.stateInfo = null; this.service = service; - this.formStateTask = new Executor(this, () => true); - this.loadRoleTask = new Executor(this, () => true); + this.formStateTask = new Executor(this, () => true); + this.loadTeamTask = new Executor(this, () => true); this.submittingTask = new Executor(); this.statusMessage = null; this.configured = false; this.partsState = new MetadataMap(); this.mode = 'create'; - makeObservable(this, { + makeObservable(this, { mode: observable, config: observable, statusMessage: observable, @@ -89,11 +89,11 @@ export class RoleFormState implements IRoleFormState { .addCollection(service.formStateTask) .addPostHandler(this.updateFormState); - this.loadRoleTask + this.loadTeamTask .before(service.configureTask) .addPostHandler(this.loadInfo) .next(service.fillConfigTask, (state, contexts) => { - const configuration = contexts.getContext(roleFormConfigureContext); + const configuration = contexts.getContext(teamFormConfigureContext); return { state, @@ -105,20 +105,20 @@ export class RoleFormState implements IRoleFormState { async load(): Promise { } - async loadRoleInfo(): Promise { - await this.loadRoleTask.execute(this); + async loadTeamInfo(): Promise { + await this.loadTeamTask.execute(this); return this.info; } setOptions( - mode: RoleFormMode, + mode: TeamFormMode, ): this { this.mode = mode; return this; } - setConfig(config: RoleInfo): this { + setConfig(config: TeamInfo): this { this.config = config; return this; } @@ -133,10 +133,10 @@ export class RoleFormState implements IRoleFormState { } private updateFormState( - data: IRoleFormState, - contexts: IExecutionContextProvider + data: ITeamFormState, + contexts: IExecutionContextProvider ): void { - const context = contexts.getContext(roleFormStateContext); + const context = contexts.getContext(teamFormStateContext); this.statusMessage = context.statusMessage; @@ -145,17 +145,17 @@ export class RoleFormState implements IRoleFormState { } private async loadInfo( - data: IRoleFormState, - contexts: IExecutionContextProvider + data: ITeamFormState, + contexts: IExecutionContextProvider ) { - if (!data.config.roleId) { + if (!data.config.teamId) { return; } - if (!this.resource.has(data.config.roleId)) { + if (!this.resource.has(data.config.teamId)) { return; } - await this.resource.load(data.config.roleId); + await this.resource.load(data.config.teamId); } } diff --git a/webapp/packages/plugin-authentication-administration/src/Administration/Users/Roles/RolesAdministrationNavService.ts b/webapp/packages/plugin-authentication-administration/src/Administration/Users/Teams/TeamsAdministrationNavService.ts similarity index 75% rename from webapp/packages/plugin-authentication-administration/src/Administration/Users/Roles/RolesAdministrationNavService.ts rename to webapp/packages/plugin-authentication-administration/src/Administration/Users/Teams/TeamsAdministrationNavService.ts index 6841f06e8c..4c8f427756 100644 --- a/webapp/packages/plugin-authentication-administration/src/Administration/Users/Roles/RolesAdministrationNavService.ts +++ b/webapp/packages/plugin-authentication-administration/src/Administration/Users/Teams/TeamsAdministrationNavService.ts @@ -11,16 +11,16 @@ import { injectable } from '@cloudbeaver/core-di'; import { EUsersAdministrationSub, UsersAdministrationNavigationService } from '../UsersAdministrationNavigationService'; @injectable() -export class RolesAdministrationNavService { +export class TeamsAdministrationNavService { constructor( - private usersAdministrationNavigationService: UsersAdministrationNavigationService + private readonly usersAdministrationNavigationService: UsersAdministrationNavigationService ) { } navToRoot(): void { - this.usersAdministrationNavigationService.navToSub(EUsersAdministrationSub.Roles); + this.usersAdministrationNavigationService.navToSub(EUsersAdministrationSub.Teams); } navToCreate(): void { - this.usersAdministrationNavigationService.navToSub(EUsersAdministrationSub.Roles, 'create'); + this.usersAdministrationNavigationService.navToSub(EUsersAdministrationSub.Teams, 'create'); } } diff --git a/webapp/packages/plugin-authentication-administration/src/Administration/Users/Roles/RolesAdministrationService.ts b/webapp/packages/plugin-authentication-administration/src/Administration/Users/Teams/TeamsAdministrationService.ts similarity index 58% rename from webapp/packages/plugin-authentication-administration/src/Administration/Users/Roles/RolesAdministrationService.ts rename to webapp/packages/plugin-authentication-administration/src/Administration/Users/Teams/TeamsAdministrationService.ts index 28b87cce7d..fe72520768 100644 --- a/webapp/packages/plugin-authentication-administration/src/Administration/Users/Roles/RolesAdministrationService.ts +++ b/webapp/packages/plugin-authentication-administration/src/Administration/Users/Teams/TeamsAdministrationService.ts @@ -6,15 +6,15 @@ * you may not use this file except in compliance with the License. */ -import type { RoleInfo } from '@cloudbeaver/core-authentication'; +import type { TeamInfo } from '@cloudbeaver/core-authentication'; import { PlaceholderContainer } from '@cloudbeaver/core-blocks'; import { injectable } from '@cloudbeaver/core-di'; -export interface IRoleDetailsInfoProps { - role: RoleInfo; +export interface ITeamDetailsInfoProps { + team: TeamInfo; } @injectable() -export class RolesAdministrationService { - readonly roleDetailsInfoPlaceholder = new PlaceholderContainer(); +export class TeamsAdministrationService { + readonly teamDetailsInfoPlaceholder = new PlaceholderContainer(); } diff --git a/webapp/packages/plugin-authentication-administration/src/Administration/Users/Roles/RolesDrawerItem.tsx b/webapp/packages/plugin-authentication-administration/src/Administration/Users/Teams/TeamsDrawerItem.tsx similarity index 71% rename from webapp/packages/plugin-authentication-administration/src/Administration/Users/Roles/RolesDrawerItem.tsx rename to webapp/packages/plugin-authentication-administration/src/Administration/Users/Teams/TeamsDrawerItem.tsx index 5dd7a0de4b..751e93babe 100644 --- a/webapp/packages/plugin-authentication-administration/src/Administration/Users/Roles/RolesDrawerItem.tsx +++ b/webapp/packages/plugin-authentication-administration/src/Administration/Users/Teams/TeamsDrawerItem.tsx @@ -13,7 +13,7 @@ import { Tab, TabTitle, TabIcon } from '@cloudbeaver/core-ui'; -export const RolesDrawerItem: React.FC = function RolesDrawerItem({ +export const TeamsDrawerItem: React.FC = function TeamsDrawerItem({ item, onSelect, style, @@ -23,11 +23,11 @@ export const RolesDrawerItem: React.FC = function onSelect(item.name)} > - - + + ); }; diff --git a/webapp/packages/plugin-authentication-administration/src/Administration/Users/Roles/RolesPage.tsx b/webapp/packages/plugin-authentication-administration/src/Administration/Users/Teams/TeamsPage.tsx similarity index 81% rename from webapp/packages/plugin-authentication-administration/src/Administration/Users/Roles/RolesPage.tsx rename to webapp/packages/plugin-authentication-administration/src/Administration/Users/Teams/TeamsPage.tsx index 59f9231f9c..cbb2a784ea 100644 --- a/webapp/packages/plugin-authentication-administration/src/Administration/Users/Roles/RolesPage.tsx +++ b/webapp/packages/plugin-authentication-administration/src/Administration/Users/Teams/TeamsPage.tsx @@ -15,10 +15,10 @@ import { useService } from '@cloudbeaver/core-di'; -import { CreateRole } from './CreateRole'; -import { CreateRoleService } from './CreateRoleService'; -import { RolesTable } from './RolesTable/RolesTable'; -import { useRolesTable } from './RolesTable/useRolesTable'; +import { CreateTeam } from './CreateTeam'; +import { CreateTeamService } from './CreateTeamService'; +import { TeamsTable } from './TeamsTable/TeamsTable'; +import { useTeamsTable } from './TeamsTable/useTeamsTable'; const styles = css` layout-grid { @@ -46,15 +46,15 @@ interface Props { param?: string | null; } -export const RolesPage = observer(function RolesPage({ +export const TeamsPage = observer(function TeamsPage({ sub, param, }) { const translate = useTranslate(); const style = useStyles(BASE_LAYOUT_GRID_STYLES, styles, ADMINISTRATION_TOOLS_PANEL_STYLES, BASE_CONTAINERS_STYLES); - const service = useService(CreateRoleService); + const service = useService(CreateTeamService); - const table = useRolesTable(); + const table = useTeamsTable(); const create = param === 'create'; return styled(style)( @@ -63,7 +63,7 @@ export const RolesPage = observer(function RolesPage({ (function RolesPage({ {translate('ui_add')} (function RolesPage({ {translate('ui_refresh')} (function RolesPage({ {create && ( - + )} - (function Role({ role }) { - const service = useService(RolesAdministrationService); +export const Team = observer(function Team({ team }) { + const service = useService(TeamsAdministrationService); return styled(useStyles(styles))( - + - {role.roleId} - {role.roleName || ''} - {role.description || ''} + {team.teamId} + {team.teamName || ''} + {team.description || ''} - + ); diff --git a/webapp/packages/plugin-authentication-administration/src/Administration/Users/Roles/RolesTable/RoleEdit.tsx b/webapp/packages/plugin-authentication-administration/src/Administration/Users/Teams/TeamsTable/TeamEdit.tsx similarity index 79% rename from webapp/packages/plugin-authentication-administration/src/Administration/Users/Roles/RolesTable/RoleEdit.tsx rename to webapp/packages/plugin-authentication-administration/src/Administration/Users/Teams/TeamsTable/TeamEdit.tsx index 9228b99971..b07650a3fa 100644 --- a/webapp/packages/plugin-authentication-administration/src/Administration/Users/Roles/RolesTable/RoleEdit.tsx +++ b/webapp/packages/plugin-authentication-administration/src/Administration/Users/Teams/TeamsTable/TeamEdit.tsx @@ -10,13 +10,13 @@ import { observer } from 'mobx-react-lite'; import { useRef, useEffect, useContext, useCallback } from 'react'; import styled, { css } from 'reshadow'; -import { RolesResource } from '@cloudbeaver/core-authentication'; +import { TeamsResource } from '@cloudbeaver/core-authentication'; import { TableContext, useStyles } from '@cloudbeaver/core-blocks'; import { useService } from '@cloudbeaver/core-di'; -import { RoleForm } from '../RoleForm'; -import { useRoleFormState } from '../useRoleFormState'; +import { TeamForm } from '../TeamForm'; +import { useTeamFormState } from '../useTeamFormState'; const styles = css` box { @@ -33,10 +33,10 @@ interface Props { item: string; } -export const RoleEdit = observer(function RoleEdit({ +export const TeamEdit = observer(function TeamEdit({ item, }) { - const resource = useService(RolesResource); + const resource = useService(TeamsResource); const boxRef = useRef(null); const tableContext = useContext(TableContext); @@ -51,16 +51,16 @@ export const RoleEdit = observer(function RoleEdit({ }); }, []); - const data = useRoleFormState( + const data = useTeamFormState( resource, state => state.setOptions('edit') ); - data.config.roleId = item; + data.config.teamId = item; return styled(useStyles(styles))( - diff --git a/webapp/packages/plugin-authentication-administration/src/Administration/Users/Roles/RolesTable/RolesTable.tsx b/webapp/packages/plugin-authentication-administration/src/Administration/Users/Teams/TeamsTable/TeamsTable.tsx similarity index 66% rename from webapp/packages/plugin-authentication-administration/src/Administration/Users/Roles/RolesTable/RolesTable.tsx rename to webapp/packages/plugin-authentication-administration/src/Administration/Users/Teams/TeamsTable/TeamsTable.tsx index d34b5bcad0..b29ca69049 100644 --- a/webapp/packages/plugin-authentication-administration/src/Administration/Users/Roles/RolesTable/RolesTable.tsx +++ b/webapp/packages/plugin-authentication-administration/src/Administration/Users/Teams/TeamsTable/TeamsTable.tsx @@ -9,12 +9,12 @@ import { observer } from 'mobx-react-lite'; import styled, { css } from 'reshadow'; -import type { RoleInfo } from '@cloudbeaver/core-authentication'; +import type { TeamInfo } from '@cloudbeaver/core-authentication'; import { Table, TableHeader, TableColumnHeader, TableBody, TableSelect, Loader, ILoadableState, useTranslate, useStyles } from '@cloudbeaver/core-blocks'; -import { Role } from './Role'; +import { Team } from './Team'; const styles = css` Table { @@ -29,15 +29,15 @@ const loaderStyle = css` `; interface Props { - roles: RoleInfo[]; + teams: TeamInfo[]; state: ILoadableState; selectedItems: Map; expandedItems: Map; } -export const RolesTable = observer(function RolesTable({ roles, state, selectedItems, expandedItems }) { +export const TeamsTable = observer(function TeamsTable({ teams, state, selectedItems, expandedItems }) { const translate = useTranslate(); - const keys = roles.map(role => role.roleId); + const keys = teams.map(team => team.teamId); return styled(useStyles(styles))( @@ -47,14 +47,14 @@ export const RolesTable = observer(function RolesTable({ roles, state, se - {translate('administration_roles_role_id')} - {translate('administration_roles_role_name')} - {translate('administration_roles_role_description')} + {translate('administration_teams_team_id')} + {translate('administration_teams_team_name')} + {translate('administration_teams_team_description')} - {roles.map(role => ( - + {teams.map(team => ( + ))} diff --git a/webapp/packages/plugin-authentication-administration/src/Administration/Users/Roles/RolesTable/useRolesTable.tsx b/webapp/packages/plugin-authentication-administration/src/Administration/Users/Teams/TeamsTable/useTeamsTable.tsx similarity index 77% rename from webapp/packages/plugin-authentication-administration/src/Administration/Users/Roles/RolesTable/useRolesTable.tsx rename to webapp/packages/plugin-authentication-administration/src/Administration/Users/Teams/TeamsTable/useTeamsTable.tsx index a0cfadbb70..6c3f74e60b 100644 --- a/webapp/packages/plugin-authentication-administration/src/Administration/Users/Roles/RolesTable/useRolesTable.tsx +++ b/webapp/packages/plugin-authentication-administration/src/Administration/Users/Teams/TeamsTable/useTeamsTable.tsx @@ -8,7 +8,7 @@ import { computed, observable } from 'mobx'; -import { compareRoles, RoleInfo, RolesResource } from '@cloudbeaver/core-authentication'; +import { compareTeams, TeamInfo, TeamsResource } from '@cloudbeaver/core-authentication'; import { ILoadableState, TableState, useMapResource, useObservableRef, useTranslate } from '@cloudbeaver/core-blocks'; import { useService } from '@cloudbeaver/core-di'; import { CommonDialogService, ConfirmationDialogDelete, DialogueStateResult } from '@cloudbeaver/core-dialogs'; @@ -19,16 +19,16 @@ import { CachedMapAllKey, resourceKeyList } from '@cloudbeaver/core-sdk'; interface State { tableState: TableState; processing: boolean; - roles: RoleInfo[]; + teams: TeamInfo[]; state: ILoadableState; update: () => Promise; delete: () => Promise; } -export function useRolesTable(): Readonly { +export function useTeamsTable(): Readonly { const notificationService = useService(NotificationService); const dialogService = useService(CommonDialogService); - const resource = useMapResource(useRolesTable, RolesResource, CachedMapAllKey); + const resource = useMapResource(useTeamsTable, TeamsResource, CachedMapAllKey); const translate = useTranslate(); @@ -36,8 +36,8 @@ export function useRolesTable(): Readonly { tableState: new TableState(), processing: false, state: resource, - get roles() { - return resource.resource.values.slice().sort(compareRoles); + get teams() { + return resource.resource.values.slice().sort(compareTeams); }, async update() { if (this.processing) { @@ -47,9 +47,9 @@ export function useRolesTable(): Readonly { try { this.processing = true; await resource.resource.refreshAll(); - notificationService.logSuccess({ title: 'administration_roles_role_list_update_success' }); + notificationService.logSuccess({ title: 'administration_teams_team_list_update_success' }); } catch (exception: any) { - notificationService.logException(exception, 'administration_roles_role_list_update_fail'); + notificationService.logException(exception, 'administration_teams_team_list_update_fail'); } finally { this.processing = false; } @@ -65,8 +65,8 @@ export function useRolesTable(): Readonly { return; } - const roleNames = deletionList.map(name => `"${name}"`).join(', '); - const message = `${translate('administration_roles_delete_confirmation')}${roleNames}. ${translate('ui_are_you_sure')}`; + const teamNames = deletionList.map(name => `"${name}"`).join(', '); + const message = `${translate('administration_teams_delete_confirmation')}${teamNames}. ${translate('ui_are_you_sure')}`; const result = await dialogService.open(ConfirmationDialogDelete, { title: 'ui_data_delete_confirmation', message, @@ -79,18 +79,18 @@ export function useRolesTable(): Readonly { try { this.processing = true; - await resource.resource.deleteRole(resourceKeyList(deletionList)); + await resource.resource.deleteTeam(resourceKeyList(deletionList)); this.tableState.unselect(); this.tableState.unexpand(deletionList); } catch (exception: any) { - notificationService.logException(exception, 'Roles delete Error'); + notificationService.logException(exception, 'Teams delete Error'); } finally { this.processing = false; } }, }), { processing: observable.ref, - roles: computed, + teams: computed, }, false, ['update', 'delete']); } diff --git a/webapp/packages/plugin-authentication-administration/src/Administration/Users/Teams/useTeamFormState.ts b/webapp/packages/plugin-authentication-administration/src/Administration/Users/Teams/useTeamFormState.ts new file mode 100644 index 0000000000..e111564d2b --- /dev/null +++ b/webapp/packages/plugin-authentication-administration/src/Administration/Users/Teams/useTeamFormState.ts @@ -0,0 +1,36 @@ +/* + * 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 { useState } from 'react'; + +import type { TeamInfo } from '@cloudbeaver/core-authentication'; +import { useService } from '@cloudbeaver/core-di'; +import type { CachedMapResource } from '@cloudbeaver/core-sdk'; + +import type { ITeamFormState } from './ITeamFormProps'; +import { TeamFormService } from './TeamFormService'; +import { TeamFormState } from './TeamFormState'; + +export function useTeamFormState( + resource: CachedMapResource, + configure?: (state: ITeamFormState) => any +): ITeamFormState { + const service = useService(TeamFormService); + const [state] = useState(() => { + const state = new TeamFormState( + service, + resource, + ); + configure?.(state); + + state.load(); + return state; + }); + + return state; +} diff --git a/webapp/packages/plugin-authentication-administration/src/Administration/Users/UserForm/ConnectionAccess.tsx b/webapp/packages/plugin-authentication-administration/src/Administration/Users/UserForm/ConnectionAccess.tsx index d7313ff961..b1642bcd2a 100644 --- a/webapp/packages/plugin-authentication-administration/src/Administration/Users/UserForm/ConnectionAccess.tsx +++ b/webapp/packages/plugin-authentication-administration/src/Administration/Users/UserForm/ConnectionAccess.tsx @@ -50,7 +50,7 @@ export const ConnectionAccess: TabContainerPanelComponent = obse const localConnections = useMemo(() => computed( () => controller.connections.filter(connection => !isCloudConnection(connection)) ), [controller.connections]); - const isAdmin = controller.user.grantedRoles.includes('admin'); + const isAdmin = controller.user.grantedTeams.includes('admin'); if (controller.connections.length === 0) { return styled(style)( @@ -97,11 +97,11 @@ export const ConnectionAccess: TabContainerPanelComponent = obse {localConnections.get().map(connection => { const connectionPermission = getConnectionPermission(connection.id); const driver = driversResource.get(connection.driverId); - const isRoleProvided = connectionPermission?.subjectType === AdminSubjectType.Role; + const isTeamProvided = connectionPermission?.subjectType === AdminSubjectType.Team; let grantedBy = ''; - if (isRoleProvided) { - grantedBy = `${translate('authentication_administration_user_connections_access_granted_role')} ${connectionPermission.subjectId}`; + if (isTeamProvided) { + grantedBy = `${translate('authentication_administration_user_connections_access_granted_team')} ${connectionPermission.subjectId}`; } else if (connectionPermission) { grantedBy = translate('authentication_administration_user_connections_access_granted_directly'); } @@ -110,12 +110,12 @@ export const ConnectionAccess: TabContainerPanelComponent = obse diff --git a/webapp/packages/plugin-authentication-administration/src/Administration/Users/UserForm/UserFormController.ts b/webapp/packages/plugin-authentication-administration/src/Administration/Users/UserForm/UserFormController.ts index fa7ad22fc9..f951a1b4c1 100644 --- a/webapp/packages/plugin-authentication-administration/src/Administration/Users/UserForm/UserFormController.ts +++ b/webapp/packages/plugin-authentication-administration/src/Administration/Users/UserForm/UserFormController.ts @@ -8,7 +8,7 @@ import { observable, computed, makeObservable } from 'mobx'; -import { AdminUser, compareRoles, isLocalUser, RoleInfo, RolesResource, UsersResource } from '@cloudbeaver/core-authentication'; +import { AdminUser, compareTeams, isLocalUser, TeamInfo, TeamsResource, UsersResource } from '@cloudbeaver/core-authentication'; import { ConnectionInfoProjectKey, ConnectionInfoResource, DatabaseConnection, DBDriverResource } from '@cloudbeaver/core-connections'; import { injectable, IInitializableController, IDestructibleController } from '@cloudbeaver/core-di'; import { CommonDialogService } from '@cloudbeaver/core-dialogs'; @@ -32,7 +32,7 @@ interface IUserCredentials { password: string; passwordRepeat: string; metaParameters: Record; - roles: Map; + teams: Map; } @injectable() @@ -51,8 +51,8 @@ export class UserFormController implements IInitializableController, IDestructib return this.connectionInfoResource.get(ConnectionInfoProjectKey(PROJECT_GLOBAL_ID)) as DatabaseConnection[]; } - get roles(): RoleInfo[] { - return this.rolesResource.values.slice().sort(compareRoles); + get teams(): TeamInfo[] { + return this.teamsResource.values.slice().sort(compareTeams); } get local(): boolean { @@ -73,7 +73,7 @@ export class UserFormController implements IInitializableController, IDestructib constructor( private readonly notificationService: NotificationService, private readonly commonDialogService: CommonDialogService, - private readonly rolesResource: RolesResource, + private readonly teamsResource: TeamsResource, private readonly usersResource: UsersResource, private readonly connectionInfoResource: ConnectionInfoResource, private readonly dbDriverResource: DBDriverResource @@ -89,7 +89,7 @@ export class UserFormController implements IInitializableController, IDestructib password: '', passwordRepeat: '', metaParameters: {}, - roles: new Map(), + teams: new Map(), }; this.enabled = true; this.error = new GQLErrorCatcher(); @@ -107,7 +107,7 @@ export class UserFormController implements IInitializableController, IDestructib enabled: observable.ref, statusMessage: observable, connections: computed, - roles: computed, + teams: computed, }); } @@ -119,7 +119,7 @@ export class UserFormController implements IInitializableController, IDestructib this.editing = editing; this.collapse = collapse; if (prevUser !== this.user) { - this.loadRoles(); + this.loadTeams(); } } @@ -146,7 +146,7 @@ export class UserFormController implements IInitializableController, IDestructib credentials: { password: this.credentials.password }, }, enabled: this.enabled, - roles: this.getGrantedRoles(), + teams: this.getGrantedTeams(), metaParameters: this.credentials.metaParameters, grantedConnections: this.getGrantedConnections(), }); @@ -163,7 +163,7 @@ export class UserFormController implements IInitializableController, IDestructib } ); } - await this.updateRoles(); + await this.updateTeams(); await this.saveUserStatus(); await this.saveConnectionPermissions(); await this.saveMetaParameters(); @@ -223,7 +223,7 @@ export class UserFormController implements IInitializableController, IDestructib this.selectedConnections.clear(); for (const connection of this.grantedConnections) { - if (connection.subjectType !== AdminSubjectType.Role) { + if (connection.subjectType !== AdminSubjectType.Team) { this.selectedConnections.set(connection.dataSourceId, true); } } @@ -250,7 +250,7 @@ export class UserFormController implements IInitializableController, IDestructib return; } - if (this.rolesResource.has(this.credentials.login)) { + if (this.teamsResource.has(this.credentials.login)) { this.setStatusMessage('authentication_user_login_cant_be_used', ENotificationType.Error); return; } @@ -274,20 +274,20 @@ export class UserFormController implements IInitializableController, IDestructib return true; } - private async updateRoles() { - for (const [roleId, checked] of this.credentials.roles) { + private async updateTeams() { + for (const [teamId, checked] of this.credentials.teams) { if (checked) { - if (!this.user.grantedRoles.includes(roleId)) { - await this.usersResource.grantRole(this.user.userId, roleId, true); + if (!this.user.grantedTeams.includes(teamId)) { + await this.usersResource.grantTeam(this.user.userId, teamId, true); } } else { - await this.usersResource.revokeRole(this.user.userId, roleId, true); + await this.usersResource.revokeTeam(this.user.userId, teamId, true); } } } - private getGrantedRoles() { - return Array.from(this.credentials.roles.keys()).filter(roleId => this.credentials.roles.get(roleId)); + private getGrantedTeams() { + return Array.from(this.credentials.teams.keys()).filter(teamId => this.credentials.teams.get(teamId)); } private getGrantedConnections() { @@ -297,7 +297,7 @@ export class UserFormController implements IInitializableController, IDestructib connectionPermission => connectionPermission.dataSourceId === connectionId ); return this.selectedConnections.get(connectionId) - && connectionPermission?.subjectType !== AdminSubjectType.Role; + && connectionPermission?.subjectType !== AdminSubjectType.Team; }); } @@ -321,12 +321,12 @@ export class UserFormController implements IInitializableController, IDestructib await this.loadConnectionsAccess(); } - private async loadRoles() { + private async loadTeams() { try { - await this.rolesResource.loadAll(); + await this.teamsResource.loadAll(); await this.loadUser(); } catch (exception: any) { - this.notificationService.logException(exception, 'Can\'t load roles'); + this.notificationService.logException(exception, 'Can\'t load teams'); } finally { this.isLoading = false; } @@ -336,7 +336,7 @@ export class UserFormController implements IInitializableController, IDestructib try { this.credentials.metaParameters = this.user.metaParameters; this.credentials.login = this.user.userId; - this.credentials.roles = new Map(this.user.grantedRoles.map(roleId => ([roleId, true]))); + this.credentials.teams = new Map(this.user.grantedTeams.map(teamId => ([teamId, true]))); this.enabled = this.user.enabled; } catch (exception: any) { this.notificationService.logException(exception, 'Can\'t load user'); diff --git a/webapp/packages/plugin-authentication-administration/src/Administration/Users/UserForm/UserInfo.tsx b/webapp/packages/plugin-authentication-administration/src/Administration/Users/UserForm/UserInfo.tsx index 3cc61c8295..a9dbd4fee7 100644 --- a/webapp/packages/plugin-authentication-administration/src/Administration/Users/UserForm/UserInfo.tsx +++ b/webapp/packages/plugin-authentication-administration/src/Administration/Users/UserForm/UserInfo.tsx @@ -12,8 +12,6 @@ import styled, { css } from 'reshadow'; import { UserMetaParametersResource } from '@cloudbeaver/core-authentication'; import { BASE_CONTAINERS_STYLES, ColoredContainer, Container, FieldCheckbox, Group, GroupTitle, InputField, Loader, ObjectPropertyInfoForm, useDataResource, useTranslate, useStyles } from '@cloudbeaver/core-blocks'; - - import type { TabContainerPanelComponent } from '@cloudbeaver/core-ui'; import type { IUserFormProps } from './UserFormService'; @@ -32,8 +30,8 @@ export const UserInfo: TabContainerPanelComponent = observer(fun const translate = useTranslate(); const userMetaParameters = useDataResource(UserInfo, UserMetaParametersResource, undefined); - const handleRoleChange = useCallback( - (roleId: string, value: boolean) => { controller.credentials.roles.set(roleId, value); }, + const handleTeamChange = useCallback( + (teamId: string, value: boolean) => { controller.credentials.teams.set(teamId, value); }, [] ); @@ -98,19 +96,19 @@ export const UserInfo: TabContainerPanelComponent = observer(fun > {translate('authentication_user_enabled')} - {translate('authentication_user_role')} - {controller.roles.map(role => { - const label = `${role.roleId}${role.roleName && role.roleName !== role.roleId ? ' (' + role.roleName + ')' : ''}`; - const tooltip = `${label}${role.description ? '\n' + role.description : ''}`; + {translate('authentication_user_team')} + {controller.teams.map(team => { + const label = `${team.teamId}${team.teamName && team.teamName !== team.teamId ? ' (' + team.teamName + ')' : ''}`; + const tooltip = `${label}${team.description ? '\n' + team.description : ''}`; return ( handleRoleChange(role.roleId, checked)} + onChange={checked => handleTeamChange(team.teamId, checked)} > {label} diff --git a/webapp/packages/plugin-authentication-administration/src/Administration/Users/UsersAdministration.tsx b/webapp/packages/plugin-authentication-administration/src/Administration/Users/UsersAdministration.tsx index 5d2b853363..fc19fdced1 100644 --- a/webapp/packages/plugin-authentication-administration/src/Administration/Users/UsersAdministration.tsx +++ b/webapp/packages/plugin-authentication-administration/src/Administration/Users/UsersAdministration.tsx @@ -12,12 +12,10 @@ import styled, { css } from 'reshadow'; import { AdministrationItemContentComponent, ADMINISTRATION_TOOLS_PANEL_STYLES } from '@cloudbeaver/core-administration'; import { ToolsPanel, useTranslate, useStyles } from '@cloudbeaver/core-blocks'; import { useService } from '@cloudbeaver/core-di'; - - import { BASE_TAB_STYLES, ITabData, Tab, TabList, TabPanel, TabsState, UNDERLINE_TAB_STYLES } from '@cloudbeaver/core-ui'; import { MetaParameters } from './MetaParameters/MetaParameters'; -import { RolesPage } from './Roles/RolesPage'; +import { TeamsPage } from './Teams/TeamsPage'; import { EUsersAdministrationSub, UsersAdministrationNavigationService } from './UsersAdministrationNavigationService'; import { UsersTable } from './UsersTable/UsersTable'; @@ -63,7 +61,7 @@ export const UsersAdministration: AdministrationItemContentComponent = observer( {translate('authentication_administration_item_users')} - {translate('administration_roles_tab_title')} + {translate('administration_teams_tab_title')} {/* - - + + diff --git a/webapp/packages/plugin-authentication-administration/src/Administration/Users/UsersAdministrationNavigationService.ts b/webapp/packages/plugin-authentication-administration/src/Administration/Users/UsersAdministrationNavigationService.ts index 1fe8b2a4d9..1d833ad66a 100644 --- a/webapp/packages/plugin-authentication-administration/src/Administration/Users/UsersAdministrationNavigationService.ts +++ b/webapp/packages/plugin-authentication-administration/src/Administration/Users/UsersAdministrationNavigationService.ts @@ -11,7 +11,7 @@ import { injectable } from '@cloudbeaver/core-di'; export enum EUsersAdministrationSub { Users = 'users', - Roles = 'roles', + Teams = 'teams', MetaProperties = 'metaProperties' } diff --git a/webapp/packages/plugin-authentication-administration/src/Administration/Users/UsersAdministrationService.ts b/webapp/packages/plugin-authentication-administration/src/Administration/Users/UsersAdministrationService.ts index 873b7b326f..3001d79b73 100644 --- a/webapp/packages/plugin-authentication-administration/src/Administration/Users/UsersAdministrationService.ts +++ b/webapp/packages/plugin-authentication-administration/src/Administration/Users/UsersAdministrationService.ts @@ -7,11 +7,11 @@ */ import { AdministrationItemService } from '@cloudbeaver/core-administration'; -import { AdminUser, RolesResource } from '@cloudbeaver/core-authentication'; +import { AdminUser, TeamsResource } from '@cloudbeaver/core-authentication'; import { PlaceholderContainer } from '@cloudbeaver/core-blocks'; import { injectable, Bootstrap } from '@cloudbeaver/core-di'; -import { CreateRoleService } from './Roles/CreateRoleService'; +import { CreateTeamService } from './Teams/CreateTeamService'; import { UsersAdministration } from './UsersAdministration'; import { EUsersAdministrationSub, UsersAdministrationNavigationService } from './UsersAdministrationNavigationService'; import { UsersDrawerItem } from './UsersDrawerItem'; @@ -29,8 +29,8 @@ export class UsersAdministrationService extends Bootstrap { constructor( private readonly administrationItemService: AdministrationItemService, private readonly createUserService: CreateUserService, - private readonly rolesResource: RolesResource, - private readonly createRoleService: CreateRoleService, + private readonly teamsResource: TeamsResource, + private readonly createTeamService: CreateTeamService, ) { super(); } @@ -48,11 +48,11 @@ export class UsersAdministrationService extends Bootstrap { onDeActivate: this.cancelCreate.bind(this), }, { - name: EUsersAdministrationSub.Roles, - onActivate: this.loadRoles.bind(this), + name: EUsersAdministrationSub.Teams, + onActivate: this.loadTeams.bind(this), onDeActivate: (configurationWizard, outside) => { if (outside) { - this.rolesResource.cleanNewFlags(); + this.teamsResource.cleanNewFlags(); } }, }, @@ -72,9 +72,9 @@ export class UsersAdministrationService extends Bootstrap { } } - private async loadRoles(param: string | null) { + private async loadTeams(param: string | null) { if (param === 'create') { - this.createRoleService.fillData(); + this.createTeamService.fillData(); } } } diff --git a/webapp/packages/plugin-authentication-administration/src/Administration/Users/UsersTable/User.tsx b/webapp/packages/plugin-authentication-administration/src/Administration/Users/UsersTable/User.tsx index 1b4e6b549c..a9da0f555f 100644 --- a/webapp/packages/plugin-authentication-administration/src/Administration/Users/UsersTable/User.tsx +++ b/webapp/packages/plugin-authentication-administration/src/Administration/Users/UsersTable/User.tsx @@ -37,7 +37,7 @@ interface Props { export const User = observer(function User({ user, selectable }) { const usersAdministrationService = useService(UsersAdministrationService); - const roles = user.grantedRoles.join(', '); + const teams = user.grantedTeams.join(', '); const usersService = useService(UsersResource); const notificationService = useService(NotificationService); const translate = useTranslate(); @@ -51,7 +51,7 @@ export const User = observer(function User({ user, selectable }) { } const enabledCheckboxTitle = usersService.isActiveUser(user.userId) - ? translate('administration_roles_role_granted_users_permission_denied') : undefined; + ? translate('administration_teams_team_granted_users_permission_denied') : undefined; return styled(styles)( @@ -64,7 +64,7 @@ export const User = observer(function User({ user, selectable }) { {user.userId} - {roles} + {teams} (function UsersTable({ sub, param }) { )} {translate('authentication_user_name')} - {translate('authentication_user_role')} + {translate('authentication_user_team')} {translate('authentication_user_enabled')} diff --git a/webapp/packages/plugin-authentication-administration/src/index.ts b/webapp/packages/plugin-authentication-administration/src/index.ts index d0da6c2481..b822ca23ec 100644 --- a/webapp/packages/plugin-authentication-administration/src/index.ts +++ b/webapp/packages/plugin-authentication-administration/src/index.ts @@ -3,7 +3,7 @@ import { manifest } from './manifest'; export default manifest; export * from './Administration/Users/UsersAdministrationNavigationService'; -export * from './Administration/Users/Roles/RoleFormService'; -export * from './Administration/Users/Roles/IRoleFormProps'; -export * from './Administration/Users/Roles/Contexts/roleContext'; +export * from './Administration/Users/Teams/TeamFormService'; +export * from './Administration/Users/Teams/ITeamFormProps'; +export * from './Administration/Users/Teams/Contexts/teamContext'; export * from './Administration/Users/UserForm/UserFormService'; diff --git a/webapp/packages/plugin-authentication-administration/src/locales/en.ts b/webapp/packages/plugin-authentication-administration/src/locales/en.ts index fd9d7869e3..93671c7e15 100644 --- a/webapp/packages/plugin-authentication-administration/src/locales/en.ts +++ b/webapp/packages/plugin-authentication-administration/src/locales/en.ts @@ -5,7 +5,7 @@ export default [ ['authentication_administration_user_connections_access_connections_load_fail', 'Connections loading failed'], ['authentication_administration_user_connections_access', 'Connections Access'], ['authentication_administration_user_connections_access_granted_by', 'Granted by'], - ['authentication_administration_user_connections_access_granted_role', 'Role:'], + ['authentication_administration_user_connections_access_granted_team', 'Team:'], ['authentication_administration_user_connections_access_granted_directly', 'Directly'], ['authentication_administration_user_connections_access_granted_unmanaged', 'Unmanaged'], ['authentication_administration_user_connections_empty', 'No available connections'], @@ -58,30 +58,34 @@ export default [ ['administration_identity_providers_configuration_list_update_fail', 'Configuration list refresh failed'], ['administration_identity_providers_service_link', 'Edit configurations'], - ['administration_roles_tab_title', 'Roles'], - ['administration_roles_tab_description', 'Role management'], - ['administration_roles_role_creation', 'Role creation'], - ['administration_roles_role_id', 'Role ID'], - ['administration_roles_role_name', 'Role name'], - ['administration_roles_role_description', 'Description'], - ['administration_roles_role_permissions', 'Permissions'], - ['administration_roles_role_create_error', 'Create role error'], - ['administration_roles_role_save_error', 'Save role error'], - ['administration_roles_role_list_update_success', 'Role list was refreshed'], - ['administration_roles_role_list_update_fail', 'Role list refresh failed'], - ['administration_roles_add_tooltip', 'Add new role'], - ['administration_roles_refresh_tooltip', 'Refresh role list'], - ['administration_roles_delete_tooltip', 'Delete selected roles'], - ['administration_roles_delete_confirmation', "You're going to delete these roles: "], + ['administration_teams_tab_title', 'Teams'], + ['administration_teams_tab_description', 'Team management'], + ['administration_teams_team_creation', 'Team creation'], + ['administration_teams_team_id', 'Team ID'], + ['administration_teams_team_name', 'Team name'], + ['administration_teams_team_description', 'Description'], + ['administration_teams_team_permissions', 'Permissions'], + ['administration_teams_team_create_error', 'Create team error'], + ['administration_teams_team_save_error', 'Save team error'], + ['administration_teams_team_list_update_success', 'Team list was refreshed'], + ['administration_teams_team_list_update_fail', 'Team list refresh failed'], + ['administration_teams_team_info_created', 'Team created'], + ['administration_teams_team_info_updated', 'Team updated'], + ['administration_teams_team_info_id_invalid', "Field '{alias:administration_teams_team_id}' can't be empty"], + ['administration_teams_team_info_exists', "A team with ID '{arg:teamId}' already exists"], + ['administration_teams_add_tooltip', 'Add new team'], + ['administration_teams_refresh_tooltip', 'Refresh team list'], + ['administration_teams_delete_tooltip', 'Delete selected teams'], + ['administration_teams_delete_confirmation', "You're going to delete these teams: "], - ['administration_roles_role_granted_users_tab_title', 'Users'], - ['administration_roles_role_granted_users_search_placeholder', 'Search for user ID...'], - ['administration_roles_role_granted_users_user_id', 'User ID'], - ['administration_roles_role_granted_users_user_name', 'User name'], - ['administration_roles_role_granted_users_empty', 'No available users'], - ['administration_roles_role_granted_users_permission_denied', "You can't edit your own permissions"], + ['administration_teams_team_granted_users_tab_title', 'Users'], + ['administration_teams_team_granted_users_search_placeholder', 'Search for user ID...'], + ['administration_teams_team_granted_users_user_id', 'User ID'], + ['administration_teams_team_granted_users_user_name', 'User name'], + ['administration_teams_team_granted_users_empty', 'No available users'], + ['administration_teams_team_granted_users_permission_denied', "You can't edit your own permissions"], - ['administration_roles_role_granted_connections_tab_title', 'Connections'], - ['administration_roles_role_granted_connections_search_placeholder', 'Search for connection name...'], - ['administration_roles_role_granted_connections_empty', 'No available connections'], + ['administration_teams_team_granted_connections_tab_title', 'Connections'], + ['administration_teams_team_granted_connections_search_placeholder', 'Search for connection name...'], + ['administration_teams_team_granted_connections_empty', 'No available connections'], ]; diff --git a/webapp/packages/plugin-authentication-administration/src/locales/it.ts b/webapp/packages/plugin-authentication-administration/src/locales/it.ts index 26b5a80b79..7948205273 100644 --- a/webapp/packages/plugin-authentication-administration/src/locales/it.ts +++ b/webapp/packages/plugin-authentication-administration/src/locales/it.ts @@ -5,7 +5,6 @@ export default [ ['authentication_administration_user_connections_access_connections_load_fail', 'Errore in fase di caricamento delle connessioni'], ['authentication_administration_user_connections_access', 'Accesso alle connessioni'], ['authentication_administration_user_connections_access_granted_by', 'Permesso da'], - ['authentication_administration_user_connections_access_granted_role', 'Ruolo:'], ['authentication_administration_user_connections_access_granted_directly', 'Direttamente'], ['authentication_administration_user_connections_access_granted_unmanaged', 'Non gestito'], ['authentication_administration_user_connections_empty', 'Nessuna connessione disponibile'], @@ -21,6 +20,11 @@ export default [ ['authentication_administration_user_created', 'Utente creato con successo'], ['authentication_administration_user_create_failed', 'Errore di creazione nuovo utente'], + ['administration_teams_team_info_created', 'Team created'], + ['administration_teams_team_info_updated', 'Team updated'], + ['administration_teams_team_info_id_invalid', "Field '{alias:administration_teams_team_id}' can't be empty"], + ['administration_teams_team_info_exists', "A team with ID '{arg:teamId}' already exists"], + ['administration_configuration_wizard_configuration_admin', 'Credenziali amministrative'], ['administration_configuration_wizard_configuration_admin_name', 'Login'], ['administration_configuration_wizard_configuration_admin_password', 'Password'], diff --git a/webapp/packages/plugin-authentication-administration/src/locales/ru.ts b/webapp/packages/plugin-authentication-administration/src/locales/ru.ts index ac24580c5c..966b36cbc2 100644 --- a/webapp/packages/plugin-authentication-administration/src/locales/ru.ts +++ b/webapp/packages/plugin-authentication-administration/src/locales/ru.ts @@ -5,7 +5,7 @@ export default [ ['authentication_administration_user_connections_access_connections_load_fail', 'Ошибка при загрузке списка коннекшенов'], ['authentication_administration_user_connections_access', 'Доступ к базам'], ['authentication_administration_user_connections_access_granted_by', 'Предоставлено'], - ['authentication_administration_user_connections_access_granted_role', 'Роль:'], + ['authentication_administration_user_connections_access_granted_team', 'Команда:'], ['authentication_administration_user_connections_access_granted_directly', 'Напрямую'], ['authentication_administration_user_connections_access_granted_unmanaged', 'Неуправляемый'], ['authentication_administration_user_connections_empty', 'Нет доступных коннекшенов'], @@ -57,30 +57,34 @@ export default [ ['administration_identity_providers_configuration_list_update_fail', 'Не удалось обновить список конфигураций'], ['administration_identity_providers_service_link', 'Настроить'], - ['administration_roles_tab_title', 'Роли'], - ['administration_roles_tab_description', 'Управление ролями'], - ['administration_roles_role_creation', 'Создание роли'], - ['administration_roles_role_id', 'ID Роли'], - ['administration_roles_role_name', 'Название роли'], - ['administration_roles_role_description', 'Описание'], - ['administration_roles_role_permissions', 'Разрешения'], - ['administration_roles_role_create_error', 'Не удалось создать роль'], - ['administration_roles_role_save_error', 'Не удалось обновить роль'], - ['administration_roles_role_list_update_success', 'Список ролей обновлен'], - ['administration_roles_role_list_update_fail', 'Не удалось обновить список ролей'], - ['administration_roles_add_tooltip', 'Создать новую роль'], - ['administration_roles_refresh_tooltip', 'Обновить список ролей'], - ['administration_roles_delete_tooltip', 'Удалить выбранные роли'], - ['administration_roles_delete_confirmation', 'Вы собираетесь удалить следующие роли: '], + ['administration_teams_tab_title', 'Команды'], + ['administration_teams_tab_description', 'Управление командами'], + ['administration_teams_team_creation', 'Создание команды'], + ['administration_teams_team_id', 'ID Команды'], + ['administration_teams_team_name', 'Название команды'], + ['administration_teams_team_description', 'Описание'], + ['administration_teams_team_permissions', 'Разрешения'], + ['administration_teams_team_create_error', 'Не удалось создать команду'], + ['administration_teams_team_save_error', 'Не удалось обновить команду'], + ['administration_teams_team_list_update_success', 'Список команд обновлен'], + ['administration_teams_team_list_update_fail', 'Не удалось обновить список команд'], + ['administration_teams_team_info_created', 'Команда создана'], + ['administration_teams_team_info_updated', 'Команда обновлена'], + ['administration_teams_team_info_id_invalid', "Поле '{alias:administration_teams_team_id}' не может быть пустым"], + ['administration_teams_team_info_exists', "Команда с ID '{arg:teamId}' уже существует"], + ['administration_teams_add_tooltip', 'Создать новую команду'], + ['administration_teams_refresh_tooltip', 'Обновить список команд'], + ['administration_teams_delete_tooltip', 'Удалить выбранные команды'], + ['administration_teams_delete_confirmation', 'Вы собираетесь удалить следующие команды: '], - ['administration_roles_role_granted_users_tab_title', 'Пользователи'], - ['administration_roles_role_granted_users_search_placeholder', 'Поиск по ID пользователя...'], - ['administration_roles_role_granted_users_user_id', 'ID пользователя'], - ['administration_roles_role_granted_users_user_name', 'Имя пользователя'], - ['administration_roles_role_granted_users_empty', 'Нет доступных пользователей'], - ['administration_roles_role_granted_users_permission_denied', 'Вы не можете редактировать свои настройки доступа'], + ['administration_teams_team_granted_users_tab_title', 'Пользователи'], + ['administration_teams_team_granted_users_search_placeholder', 'Поиск по ID пользователя...'], + ['administration_teams_team_granted_users_user_id', 'ID пользователя'], + ['administration_teams_team_granted_users_user_name', 'Имя пользователя'], + ['administration_teams_team_granted_users_empty', 'Нет доступных пользователей'], + ['administration_teams_team_granted_users_permission_denied', 'Вы не можете редактировать свои настройки доступа'], - ['administration_roles_role_granted_connections_tab_title', 'Подключения'], - ['administration_roles_role_granted_connections_search_placeholder', 'Поиск по названию подключения...'], - ['administration_roles_role_granted_connections_empty', 'Нет доступных подключений'], + ['administration_teams_team_granted_connections_tab_title', 'Подключения'], + ['administration_teams_team_granted_connections_search_placeholder', 'Поиск по названию подключения...'], + ['administration_teams_team_granted_connections_empty', 'Нет доступных подключений'], ]; diff --git a/webapp/packages/plugin-authentication-administration/src/locales/zh.ts b/webapp/packages/plugin-authentication-administration/src/locales/zh.ts index 9e46944538..773be62e07 100644 --- a/webapp/packages/plugin-authentication-administration/src/locales/zh.ts +++ b/webapp/packages/plugin-authentication-administration/src/locales/zh.ts @@ -5,7 +5,6 @@ export default [ ['authentication_administration_user_connections_access_connections_load_fail', '连接加载失败'], ['authentication_administration_user_connections_access', '连接访问'], ['authentication_administration_user_connections_access_granted_by', '授予者'], - ['authentication_administration_user_connections_access_granted_role', '角色:'], ['authentication_administration_user_connections_access_granted_directly', '直接'], ['authentication_administration_user_connections_access_granted_unmanaged', '不受管理的'], ['authentication_administration_user_connections_empty', '没有可用连接'], @@ -58,30 +57,21 @@ export default [ ['administration_identity_providers_configuration_list_update_fail', '配置列表刷新失败'], ['administration_identity_providers_service_link', '编辑配置'], - ['administration_roles_tab_title', '角色'], - ['administration_roles_tab_description', '角色管理'], - ['administration_roles_role_creation', '创建角色'], - ['administration_roles_role_id', '角色ID'], - ['administration_roles_role_name', '角色名称'], - ['administration_roles_role_description', '描述'], - ['administration_roles_role_permissions', 'Permissions'], - ['administration_roles_role_create_error', '创建角色出错'], - ['administration_roles_role_save_error', '保存角色出错'], - ['administration_roles_role_list_update_success', '角色列表已刷新'], - ['administration_roles_role_list_update_fail', '角色列表刷新失败'], - ['administration_roles_add_tooltip', '添加新角色'], - ['administration_roles_refresh_tooltip', '刷新角色列表'], - ['administration_roles_delete_tooltip', '删除选中的角色'], - ['administration_roles_delete_confirmation', '您将删除这些角色:'], + ['administration_teams_team_description', '描述'], + ['administration_teams_team_permissions', 'Permissions'], + ['administration_teams_team_info_created', 'Team created'], + ['administration_teams_team_info_updated', 'Team updated'], + ['administration_teams_team_info_id_invalid', "Field '{alias:administration_teams_team_id}' can't be empty"], + ['administration_teams_team_info_exists', "A team with ID '{arg:teamId}' already exists"], - ['administration_roles_role_granted_users_tab_title', '用户'], - ['administration_roles_role_granted_users_search_placeholder', '搜索用户ID...'], - ['administration_roles_role_granted_users_user_id', '用户ID'], - ['administration_roles_role_granted_users_user_name', '用户名称'], - ['administration_roles_role_granted_users_empty', '没有可用用户'], - ['administration_roles_role_granted_users_permission_denied', '您不能编辑自己的权限'], + ['administration_teams_team_granted_users_tab_title', '用户'], + ['administration_teams_team_granted_users_search_placeholder', '搜索用户ID...'], + ['administration_teams_team_granted_users_user_id', '用户ID'], + ['administration_teams_team_granted_users_user_name', '用户名称'], + ['administration_teams_team_granted_users_empty', '没有可用用户'], + ['administration_teams_team_granted_users_permission_denied', '您不能编辑自己的权限'], - ['administration_roles_role_granted_connections_tab_title', '连接'], - ['administration_roles_role_granted_connections_search_placeholder', '搜索连接名称...'], - ['administration_roles_role_granted_connections_empty', '没有可用连接'], + ['administration_teams_team_granted_connections_tab_title', '连接'], + ['administration_teams_team_granted_connections_search_placeholder', '搜索连接名称...'], + ['administration_teams_team_granted_connections_empty', '没有可用连接'], ]; diff --git a/webapp/packages/plugin-authentication-administration/src/manifest.ts b/webapp/packages/plugin-authentication-administration/src/manifest.ts index 470edd3485..47eb4fb96c 100644 --- a/webapp/packages/plugin-authentication-administration/src/manifest.ts +++ b/webapp/packages/plugin-authentication-administration/src/manifest.ts @@ -15,13 +15,13 @@ import { CreateAuthConfigurationService } from './Administration/IdentityProvide import { AuthConfigurationOptionsTabService } from './Administration/IdentityProviders/Options/AuthConfigurationOptionsTabService'; import { ServerConfigurationAuthenticationBootstrap } from './Administration/ServerConfiguration/ServerConfigurationAuthenticationBootstrap'; import { CreateMetaParameterService } from './Administration/Users/MetaParameters/CreateMetaParameterService'; -import { CreateRoleService } from './Administration/Users/Roles/CreateRoleService'; -import { GrantedConnectionsTabService } from './Administration/Users/Roles/GrantedConnections/GrantedConnectionsTabService'; -import { GrantedUsersTabService } from './Administration/Users/Roles/GrantedUsers/GrantedUsersTabService'; -import { RoleOptionsTabService } from './Administration/Users/Roles/Options/RoleOptionsTabService'; -import { RoleFormService } from './Administration/Users/Roles/RoleFormService'; -import { RolesAdministrationNavService } from './Administration/Users/Roles/RolesAdministrationNavService'; -import { RolesAdministrationService } from './Administration/Users/Roles/RolesAdministrationService'; +import { CreateTeamService } from './Administration/Users/Teams/CreateTeamService'; +import { GrantedConnectionsTabService } from './Administration/Users/Teams/GrantedConnections/GrantedConnectionsTabService'; +import { GrantedUsersTabService } from './Administration/Users/Teams/GrantedUsers/GrantedUsersTabService'; +import { TeamOptionsTabService } from './Administration/Users/Teams/Options/TeamOptionsTabService'; +import { TeamFormService } from './Administration/Users/Teams/TeamFormService'; +import { TeamsAdministrationNavService } from './Administration/Users/Teams/TeamsAdministrationNavService'; +import { TeamsAdministrationService } from './Administration/Users/Teams/TeamsAdministrationService'; import { UserFormBaseBootstrap } from './Administration/Users/UserForm/UserFormBaseBootstrap'; import { UserFormService } from './Administration/Users/UserForm/UserFormService'; import { UsersAdministrationNavigationService } from './Administration/Users/UsersAdministrationNavigationService'; @@ -50,11 +50,11 @@ export const manifest: PluginManifest = { AuthConfigurationsAdministrationNavService, AuthConfigurationFormService, AuthConfigurationOptionsTabService, - RolesAdministrationService, - CreateRoleService, - RolesAdministrationNavService, - RoleFormService, - RoleOptionsTabService, + TeamsAdministrationService, + CreateTeamService, + TeamsAdministrationNavService, + TeamFormService, + TeamOptionsTabService, GrantedUsersTabService, GrantedConnectionsTabService, ], diff --git a/webapp/packages/plugin-authentication/public/icons/tab_role.svg b/webapp/packages/plugin-authentication/public/icons/tab_team.svg similarity index 100% rename from webapp/packages/plugin-authentication/public/icons/tab_role.svg rename to webapp/packages/plugin-authentication/public/icons/tab_team.svg diff --git a/webapp/packages/plugin-authentication/src/locales/en.ts b/webapp/packages/plugin-authentication/src/locales/en.ts index 8c88c85c77..1772ab5a05 100644 --- a/webapp/packages/plugin-authentication/src/locales/en.ts +++ b/webapp/packages/plugin-authentication/src/locales/en.ts @@ -17,15 +17,15 @@ export default [ ['authentication_user_meta_parameters', 'Parameters'], ['authentication_user_password', 'User password'], ['authentication_user_password_repeat', 'Repeat password'], - ['authentication_user_role', 'User role'], + ['authentication_user_team', 'User team'], ['authentication_user_status', 'User status'], ['authentication_user_enabled', 'Enabled'], ['authentication_user_login_not_set', 'Login can\'t be empty'], - ['authentication_user_role_not_set', 'At least one role must be selected'], + ['authentication_user_team_not_set', 'At least one team must be selected'], ['authentication_user_password_not_set', 'Password is required'], ['authentication_user_passwords_not_match', "Passwords don't match"], ['authentication_user_login_already_exists', 'The user with this name already exists'], ['authentication_user_login_cant_be_used', 'Sorry, that name cannot be used'], ['authentication_user_icon_tooltip', 'User'], - ['authentication_role_icon_tooltip', 'Role'], + ['authentication_team_icon_tooltip', 'Team'], ]; diff --git a/webapp/packages/plugin-authentication/src/locales/it.ts b/webapp/packages/plugin-authentication/src/locales/it.ts index 846d50c7f7..7cbd41d9cf 100644 --- a/webapp/packages/plugin-authentication/src/locales/it.ts +++ b/webapp/packages/plugin-authentication/src/locales/it.ts @@ -11,15 +11,12 @@ export default [ ['authentication_user_meta_parameters', 'Parameters'], ['authentication_user_password', 'Password utente'], ['authentication_user_password_repeat', 'Ripeti password'], - ['authentication_user_role', 'Ruolo utente'], ['authentication_user_status', 'User status'], ['authentication_user_enabled', 'Enabled'], ['authentication_user_login_not_set', 'Login non può esser vuoto'], - ['authentication_user_role_not_set', 'Selezionare almeno un ruolo'], ['authentication_user_password_not_set', 'La Password è obbligatoria'], ['authentication_user_passwords_not_match', 'Le Passwords non coincidono'], ['authentication_user_login_already_exists', 'Esiste già un utente con quel nome'], ['authentication_user_login_cant_be_used', 'Quel nome non può essere usato'], ['authentication_user_icon_tooltip', 'Utente'], - ['authentication_role_icon_tooltip', 'Ruolo'], ]; diff --git a/webapp/packages/plugin-authentication/src/locales/ru.ts b/webapp/packages/plugin-authentication/src/locales/ru.ts index bac98340c9..6eaa7a9f0d 100644 --- a/webapp/packages/plugin-authentication/src/locales/ru.ts +++ b/webapp/packages/plugin-authentication/src/locales/ru.ts @@ -17,15 +17,15 @@ export default [ ['authentication_user_meta_parameters', 'Параметры'], ['authentication_user_password', 'Пароль'], ['authentication_user_password_repeat', 'Повторите пароль'], - ['authentication_user_role', 'Роль'], + ['authentication_user_team', 'Команда'], ['authentication_user_status', 'Статус пользователя'], ['authentication_user_enabled', 'Включен'], ['authentication_user_login_not_set', 'Логин не может быть пустым'], - ['authentication_user_role_not_set', 'Должна быть выбрана минимум одна роль'], + ['authentication_user_team_not_set', 'Должна быть выбрана минимум одна команда'], ['authentication_user_password_not_set', 'Пароль не задан'], ['authentication_user_passwords_not_match', 'Пароли не совпадают'], ['authentication_user_login_already_exists', 'Пользователь с таким именем уже существует'], ['authentication_user_login_cant_be_used', 'Данное имя нельзя использовать'], ['authentication_user_icon_tooltip', 'Пользователь'], - ['authentication_role_icon_tooltip', 'Роль'], + ['authentication_team_icon_tooltip', 'Команда'], ]; diff --git a/webapp/packages/plugin-authentication/src/locales/zh.ts b/webapp/packages/plugin-authentication/src/locales/zh.ts index bd6c7a63af..c3b15fa70c 100644 --- a/webapp/packages/plugin-authentication/src/locales/zh.ts +++ b/webapp/packages/plugin-authentication/src/locales/zh.ts @@ -17,15 +17,12 @@ export default [ ['authentication_user_meta_parameters', '参数'], ['authentication_user_password', '用户密码'], ['authentication_user_password_repeat', '重复密码'], - ['authentication_user_role', '用户角色'], ['authentication_user_status', 'User status'], ['authentication_user_enabled', 'Enabled'], ['authentication_user_login_not_set', '用户名不能为空'], - ['authentication_user_role_not_set', '至少选择一个角色'], ['authentication_user_password_not_set', '密码是必须的'], ['authentication_user_passwords_not_match', '密码不匹配'], ['authentication_user_login_already_exists', '同名用户已存在'], ['authentication_user_login_cant_be_used', '抱歉,不能使用该名称'], ['authentication_user_icon_tooltip', '用户'], - ['authentication_role_icon_tooltip', '角色'], ]; diff --git a/webapp/packages/plugin-connections-administration/src/ConnectionForm/ConnectionAccess/ConnectionAccess.tsx b/webapp/packages/plugin-connections-administration/src/ConnectionForm/ConnectionAccess/ConnectionAccess.tsx index d80001b945..aae19b8e4e 100644 --- a/webapp/packages/plugin-connections-administration/src/ConnectionForm/ConnectionAccess/ConnectionAccess.tsx +++ b/webapp/packages/plugin-connections-administration/src/ConnectionForm/ConnectionAccess/ConnectionAccess.tsx @@ -11,7 +11,7 @@ import { observer } from 'mobx-react-lite'; import { useMemo } from 'react'; import styled, { css } from 'reshadow'; -import { RolesResource, UsersResource } from '@cloudbeaver/core-authentication'; +import { TeamsResource, UsersResource } from '@cloudbeaver/core-authentication'; import { TextPlaceholder, Loader, @@ -62,22 +62,22 @@ export const ConnectionAccess: TabContainerPanelComponent useAutoLoad(state, selected); - const users = useMapResource(ConnectionAccess, UsersResource, CachedMapAllKey); - const roles = useMapResource(ConnectionAccess, RolesResource, CachedMapAllKey); + const users = useMapResource(ConnectionAccess, UsersResource, CachedMapAllKey, { active: selected }); + const teams = useMapResource(ConnectionAccess, TeamsResource, CachedMapAllKey, { active: selected }); const grantedUsers = useMemo(() => computed(() => users.resource.values .filter(user => state.state.grantedSubjects.includes(user.userId)) ), [state.state.grantedSubjects, users.resource]); - const grantedRoles = useMemo(() => computed(() => roles.resource.values - .filter(role => state.state.grantedSubjects.includes(role.roleId)) - ), [state.state.grantedSubjects, roles.resource]); + const grantedTeams = useMemo(() => computed(() => teams.resource.values + .filter(team => state.state.grantedSubjects.includes(team.teamId)) + ), [state.state.grantedSubjects, teams.resource]); if (!selected) { return null; } - const loading = users.isLoading() || roles.isLoading() || state.state.loading; + const loading = users.isLoading() || teams.isLoading() || state.state.loading; const cloud = formState.info ? isCloudConnection(formState.info) : false; const disabled = loading || !state.state.loaded || formState.disabled || cloud; let info: TLocalizationToken | null = null; @@ -89,10 +89,10 @@ export const ConnectionAccess: TabContainerPanelComponent } return styled(styles, BASE_CONTAINERS_STYLES)( - + {() => styled(styles, BASE_CONTAINERS_STYLES)( - {!users.resource.values.length && !roles.resource.values.length ? ( + {!users.resource.values.length && !teams.resource.values.length ? ( {translate('connections_administration_connection_access_empty')} @@ -102,7 +102,7 @@ export const ConnectionAccess: TabContainerPanelComponent {state.state.editing && ( void; onEdit: () => void; @@ -67,7 +67,7 @@ interface Props { export const ConnectionAccessGrantedList = observer(function ConnectionAccessGrantedList({ grantedUsers, - grantedRoles, + grantedTeams, disabled, onRevoke, onEdit, @@ -84,9 +84,9 @@ export const ConnectionAccessGrantedList = observer(function ConnectionAc selectedSubjects.clear(); }, []); - const roles = getFilteredRoles(grantedRoles, filterState.filterValue); + const teams = getFilteredTeams(grantedTeams, filterState.filterValue); const users = getFilteredUsers(grantedUsers, filterState.filterValue); - const keys = roles.map(role => role.roleId).concat(users.map(user => user.userId)); + const keys = teams.map(team => team.teamId).concat(users.map(user => user.userId)); let tableInfoText: TLocalizationToken = 'connections_connection_access_admin_info'; if (!keys.length) { @@ -113,15 +113,15 @@ export const ConnectionAccessGrantedList = observer(function ConnectionAc {translate(tableInfoText)} - {roles.map(role => ( + {teams.map(team => ( ))} diff --git a/webapp/packages/plugin-connections-administration/src/ConnectionForm/ConnectionAccess/ConnectionAccessList.tsx b/webapp/packages/plugin-connections-administration/src/ConnectionForm/ConnectionAccess/ConnectionAccessList.tsx index 67ba2a2abc..b51bf9f9ca 100644 --- a/webapp/packages/plugin-connections-administration/src/ConnectionForm/ConnectionAccess/ConnectionAccessList.tsx +++ b/webapp/packages/plugin-connections-administration/src/ConnectionForm/ConnectionAccess/ConnectionAccessList.tsx @@ -11,7 +11,7 @@ import { observer } from 'mobx-react-lite'; import { useCallback, useState } from 'react'; import styled, { css } from 'reshadow'; -import type { RoleInfo } from '@cloudbeaver/core-authentication'; +import type { TeamInfo } from '@cloudbeaver/core-authentication'; import { Table, TableBody, @@ -31,7 +31,7 @@ import type { AdminUserInfoFragment } from '@cloudbeaver/core-sdk'; import { ConnectionAccessTableHeader, IFilterState } from './ConnectionAccessTableHeader/ConnectionAccessTableHeader'; import { ConnectionAccessTableInnerHeader } from './ConnectionAccessTableHeader/ConnectionAccessTableInnerHeader'; import { ConnectionAccessTableItem } from './ConnectionAccessTableItem'; -import { getFilteredRoles, getFilteredUsers } from './getFilteredSubjects'; +import { getFilteredTeams, getFilteredUsers } from './getFilteredSubjects'; const styles = css` Table { @@ -58,7 +58,7 @@ const styles = css` interface Props { userList: AdminUserInfoFragment[]; - roleList: RoleInfo[]; + teamList: TeamInfo[]; grantedSubjects: string[]; onGrant: (subjectIds: string[]) => void; disabled: boolean; @@ -66,7 +66,7 @@ interface Props { export const ConnectionAccessList = observer(function ConnectionAccessList({ userList, - roleList, + teamList, grantedSubjects, onGrant, disabled, @@ -76,9 +76,9 @@ export const ConnectionAccessList = observer(function ConnectionAccessLis const [selectedSubjects] = useState>(() => observable(new Map())); const [filterState] = useState(() => observable({ filterValue: '' })); - const roles = getFilteredRoles(roleList, filterState.filterValue); + const teams = getFilteredTeams(teamList, filterState.filterValue); const users = getFilteredUsers(userList, filterState.filterValue); - const keys = roles.map(role => role.roleId).concat(users.map(user => user.userId)); + const keys = teams.map(team => team.teamId).concat(users.map(user => user.userId)); const selected = getComputed(() => Array.from(selectedSubjects.values()).some(v => v)); @@ -108,15 +108,15 @@ export const ConnectionAccessList = observer(function ConnectionAccessLis )} - {roles.map(role => ( + {teams.map(team => ( ))} diff --git a/webapp/packages/plugin-connections-administration/src/ConnectionForm/ConnectionAccess/ConnectionAccessTableHeader/ConnectionAccessTableInnerHeader.tsx b/webapp/packages/plugin-connections-administration/src/ConnectionForm/ConnectionAccess/ConnectionAccessTableHeader/ConnectionAccessTableInnerHeader.tsx index 327030a265..f3d4c2652a 100644 --- a/webapp/packages/plugin-connections-administration/src/ConnectionForm/ConnectionAccess/ConnectionAccessTableHeader/ConnectionAccessTableInnerHeader.tsx +++ b/webapp/packages/plugin-connections-administration/src/ConnectionForm/ConnectionAccess/ConnectionAccessTableHeader/ConnectionAccessTableInnerHeader.tsx @@ -32,10 +32,10 @@ export const ConnectionAccessTableInnerHeader = observer(function Connect return styled(useStyles(styles))( - + - {translate('connections_connection_access_user_or_role_name')} + {translate('connections_connection_access_user_or_team_name')} {translate('connections_connection_description')} ); diff --git a/webapp/packages/plugin-connections-administration/src/ConnectionForm/ConnectionAccess/getFilteredSubjects.ts b/webapp/packages/plugin-connections-administration/src/ConnectionForm/ConnectionAccess/getFilteredSubjects.ts index 3c16874c28..8a3587e631 100644 --- a/webapp/packages/plugin-connections-administration/src/ConnectionForm/ConnectionAccess/getFilteredSubjects.ts +++ b/webapp/packages/plugin-connections-administration/src/ConnectionForm/ConnectionAccess/getFilteredSubjects.ts @@ -6,7 +6,7 @@ * you may not use this file except in compliance with the License. */ -import type { RoleInfo } from '@cloudbeaver/core-authentication'; +import type { TeamInfo } from '@cloudbeaver/core-authentication'; import type { AdminUserInfoFragment } from '@cloudbeaver/core-sdk'; /** @@ -20,11 +20,11 @@ export function getFilteredUsers(users: AdminUserInfoFragment[], filter: string) } /** - * @param {AdminRoleInfo[]} roles + * @param {AdminTeamInfo[]} teams * @param {string} filter */ -export function getFilteredRoles(roles: RoleInfo[], filter: string): RoleInfo[] { - return roles - .filter(role => role.roleName?.toLowerCase().includes(filter.toLowerCase()) && role.roleId !== 'admin') - .sort((a, b) => (a.roleName ?? '').localeCompare(b.roleName ?? '')); +export function getFilteredTeams(teams: TeamInfo[], filter: string): TeamInfo[] { + return teams + .filter(team => team.teamName?.toLowerCase().includes(filter.toLowerCase()) && team.teamId !== 'admin') + .sort((a, b) => (a.teamName ?? '').localeCompare(b.teamName ?? '')); } diff --git a/webapp/packages/plugin-data-spreadsheet-new/src/DataGrid/useGridDragging.ts b/webapp/packages/plugin-data-spreadsheet-new/src/DataGrid/useGridDragging.ts index 0c45348e08..9e1c3520d4 100644 --- a/webapp/packages/plugin-data-spreadsheet-new/src/DataGrid/useGridDragging.ts +++ b/webapp/packages/plugin-data-spreadsheet-new/src/DataGrid/useGridDragging.ts @@ -23,7 +23,7 @@ interface IMousePosition { type DraggingCallback = ( startPosition: IDraggingPosition, currentPosition: IDraggingPosition, - event: React.MouseEvent | MouseEvent + event: React.MouseEvent | MouseEvent ) => void; interface IDraggingState { @@ -37,7 +37,7 @@ interface IDraggingState { interface IDraggingCallbacks { onDragStart?: ( startPosition: IDraggingPosition, - event: React.MouseEvent | MouseEvent + event: React.MouseEvent | MouseEvent ) => void; onDragOver?: DraggingCallback; onDragEnd?: DraggingCallback; @@ -56,7 +56,7 @@ function getDelta(startPosition: IMousePosition | null, currentPosition: IMouseP return Math.max(xDelta, yDelta); } -function getCellPositionFromEvent(event: React.MouseEvent) { +function getCellPositionFromEvent(event: React.MouseEvent) { const target = event.target as HTMLElement; const cell = target.closest('[role="gridcell"]') as HTMLElement | null; @@ -96,7 +96,7 @@ export function useGridDragging(props: IDraggingCallbacks) { mouseDown: false, }), false); - const onMouseDownHandler = useCallback((event: React.MouseEvent) => { + const onMouseDownHandler = useCallback((event: React.MouseEvent) => { const position = getCellPositionFromEvent(event); if (!position) { @@ -108,7 +108,7 @@ export function useGridDragging(props: IDraggingCallbacks) { state.startDraggingCell = { colIdx: position.colIdx, rowIdx: position.rowIdx }; }, []); - const onMouseMoveHandler = useCallback((event: React.MouseEvent) => { + const onMouseMoveHandler = useCallback((event: React.MouseEvent) => { if (!state.mouseDown) { return; } @@ -155,7 +155,7 @@ export function useGridDragging(props: IDraggingCallbacks) { } }, []); - const onMouseUpHandler = useCallback((event: React.MouseEvent | MouseEvent) => { + const onMouseUpHandler = useCallback((event: React.MouseEvent | MouseEvent) => { state.mouseDown = false; state.startMousePosition = null; diff --git a/webapp/packages/plugin-sql-editor/src/SqlEditor/SQLCodeEditorPanel/useSQLCodeEditorPanel.ts b/webapp/packages/plugin-sql-editor/src/SqlEditor/SQLCodeEditorPanel/useSQLCodeEditorPanel.ts index 024d92c59d..ccf2c15fc9 100644 --- a/webapp/packages/plugin-sql-editor/src/SqlEditor/SQLCodeEditorPanel/useSQLCodeEditorPanel.ts +++ b/webapp/packages/plugin-sql-editor/src/SqlEditor/SQLCodeEditorPanel/useSQLCodeEditorPanel.ts @@ -15,9 +15,11 @@ import type { ShowHintOptions, } from 'codemirror'; import { action } from 'mobx'; +import { useCallback } from 'react'; import type { IControlledCodeMirror } from 'react-codemirror2'; import { useExecutor, useObservableRef } from '@cloudbeaver/core-blocks'; +import { throttle } from '@cloudbeaver/core-utils'; import type { ISQLEditorData } from '../ISQLEditorData'; import type { SQLCodeEditorController } from '../SQLCodeEditor/SQLCodeEditorController'; @@ -106,6 +108,8 @@ export function useSQLCodeEditorPanel( this.data.setCursor(cursorPosition); const ignoredChanges = ['+delete', 'undo', 'complete']; + const updateHighlight = throttle(() => this.highlightActiveQuery(), 1000); + const resetLineStateHighlight = throttle(() => this.controller?.resetLineStateHighlight(), 1000); // TODO: probably should be moved to SQLCodeEditorController editor.on('changes', (cm, changes) => { @@ -117,7 +121,7 @@ export function useSQLCodeEditorPanel( this.data.updateParserScriptsThrottle(); } - this.controller?.resetLineStateHighlight(); + resetLineStateHighlight(); if (!this.activeSuggest) { return; } @@ -167,7 +171,7 @@ export function useSQLCodeEditorPanel( } } } - this.highlightActiveQuery(); + updateHighlight(); }); this.highlightActiveQuery(); @@ -276,11 +280,11 @@ export function useSQLCodeEditorPanel( data, controller, }); + const updateHighlight = useCallback(throttle(() => editorPanelData.highlightActiveQuery(), 1000), [editorPanelData]); + useExecutor({ executor: data.onUpdate, - handlers:[function updateHighlight() { - editorPanelData.highlightActiveQuery(); - }], + handlers:[updateHighlight], }); useExecutor({ diff --git a/webapp/packages/plugin-sql-editor/src/SqlEditor/SqlEditor.tsx b/webapp/packages/plugin-sql-editor/src/SqlEditor/SqlEditor.tsx index a0e2b0d9b4..5800b804bc 100644 --- a/webapp/packages/plugin-sql-editor/src/SqlEditor/SqlEditor.tsx +++ b/webapp/packages/plugin-sql-editor/src/SqlEditor/SqlEditor.tsx @@ -10,7 +10,7 @@ import { observer } from 'mobx-react-lite'; import { useMemo, useState } from 'react'; import styled, { css } from 'reshadow'; -import { StaticImage, UploadArea, useTranslate } from '@cloudbeaver/core-blocks'; +import { getComputed, preventFocusHandler, StaticImage, useTranslate } from '@cloudbeaver/core-blocks'; import { useService } from '@cloudbeaver/core-di'; import { BASE_TAB_STYLES, ITabData, TabList, TabPanelList, TabsState, VERTICAL_ROTATED_TAB_STYLES } from '@cloudbeaver/core-ui'; import { MetadataMap } from '@cloudbeaver/core-utils'; @@ -19,9 +19,8 @@ import { useCaptureViewContext } from '@cloudbeaver/core-view'; import { ISqlEditorModeProps, SqlEditorModeService } from '../SqlEditorModeService'; import { DATA_CONTEXT_SQL_EDITOR_DATA } from './DATA_CONTEXT_SQL_EDITOR_DATA'; import type { ISqlEditorProps } from './ISqlEditorProps'; -import { SqlEditorActionsMenu } from './SqlEditorActionsMenu'; +import { SqlEditorTools } from './SqlEditorTools'; import { useSqlEditor } from './useSqlEditor'; -import { useTools } from './useTools'; const styles = css` button, upload { @@ -52,13 +51,6 @@ const styles = css` align-items: center; user-select: none; } - - tools { - width: 32px; - display: flex; - flex-direction: column; - align-items: center; - } button, upload { background: none; @@ -105,11 +97,12 @@ const tabStyles = css` } `; +const tabListStyles = [BASE_TAB_STYLES, VERTICAL_ROTATED_TAB_STYLES, tabStyles]; + export const SqlEditor = observer(function SqlEditor({ state, className }) { const translate = useTranslate(); const sqlEditorModeService = useService(SqlEditorModeService); const data = useSqlEditor(state); - const tools = useTools(state); const [modesState] = useState(() => new MetadataMap()); useMemo(() => { @@ -120,30 +113,12 @@ export const SqlEditor = observer(function SqlEditor({ state, c context?.set(DATA_CONTEXT_SQL_EDITOR_DATA, data); }); - function preventFocus(event: React.MouseEvent) { - event.preventDefault(); - } - - async function handleScriptUpload(event: React.ChangeEvent) { - const file = event.target.files?.[0]; - - if (!file) { - throw new Error('File is not found'); - } - - const prevScript = data.value.trim(); - const script = await tools.tryReadScript(file, prevScript); - - if (script) { - data.setQuery(script); - } - } - function handleModeSelect(tab: ITabData) { state.currentModeId = tab.tabId; } - const trimmedValue = data.value.trim(); + const disabled = getComputed(() => data.isLineScriptEmpty || data.isDisabled); + const isActiveSegmentMode = getComputed(() => data.activeSegmentMode.activeSegmentMode); return styled(styles, BASE_TAB_STYLES, VERTICAL_ROTATED_TAB_STYLES, tabStyles)( (function SqlEditor({ state, c > - + {data.dialect?.supportsExplainExecutionPlan && ( )} - - - {!data.readonly && ( - - )} - - {!data.activeSegmentMode.activeSegmentMode && !data.readonly && ( - - - - - - )} - {/**/} - + - + diff --git a/webapp/packages/plugin-sql-editor/src/SqlEditor/SqlEditorTools.tsx b/webapp/packages/plugin-sql-editor/src/SqlEditor/SqlEditorTools.tsx new file mode 100644 index 0000000000..0f313eb494 --- /dev/null +++ b/webapp/packages/plugin-sql-editor/src/SqlEditor/SqlEditorTools.tsx @@ -0,0 +1,109 @@ +/* + * 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 { observer } from 'mobx-react-lite'; +import styled, { css } from 'reshadow'; + +import { getComputed, preventFocusHandler, StaticImage, UploadArea, useStyles, useTranslate } from '@cloudbeaver/core-blocks'; +import type { ComponentStyle } from '@cloudbeaver/core-theming'; + +import type { ISqlEditorTabState } from '../ISqlEditorTabState'; +import type { ISQLEditorData } from './ISQLEditorData'; +import { SqlEditorActionsMenu } from './SqlEditorActionsMenu'; +import { useTools } from './useTools'; + +const styles = css` + tools { + width: 32px; + display: flex; + flex-direction: column; + align-items: center; + } +`; + +interface Props { + data: ISQLEditorData; + state: ISqlEditorTabState; + style?: ComponentStyle; + className?: string; +} + +export const SqlEditorTools = observer(function SqlEditorTools({ + data, + state, + style, + className, +}) { + const translate = useTranslate(); + const tools = useTools(state); + const scriptEmpty = getComputed(() => !data.value.trim()); + const disabled = getComputed(() => data.isDisabled || data.isScriptEmpty); + const isActiveSegmentMode = getComputed(() => data.activeSegmentMode.activeSegmentMode); + + async function handleScriptUpload(event: React.ChangeEvent) { + const file = event.target.files?.[0]; + + if (!file) { + throw new Error('File is not found'); + } + + const prevScript = data.value.trim(); + const script = await tools.tryReadScript(file, prevScript); + + if (script) { + data.setQuery(script); + } + } + + async function downloadScriptHandler() { + tools.downloadScript(data.value.trim()); + } + + return styled(useStyles(style, styles))( + + + {!data.readonly && ( + + )} + + {!isActiveSegmentMode && !data.readonly && ( + + + + + + )} + {/**/} + + ); +}); \ No newline at end of file diff --git a/webapp/packages/plugin-sql-editor/src/SqlEditor/useSqlEditor.ts b/webapp/packages/plugin-sql-editor/src/SqlEditor/useSqlEditor.ts index d749f7a2ef..d9a47e98e9 100644 --- a/webapp/packages/plugin-sql-editor/src/SqlEditor/useSqlEditor.ts +++ b/webapp/packages/plugin-sql-editor/src/SqlEditor/useSqlEditor.ts @@ -15,7 +15,7 @@ import { useService } from '@cloudbeaver/core-di'; import { CommonDialogService, ConfirmationDialog, DialogueStateResult } from '@cloudbeaver/core-dialogs'; import { SyncExecutor } from '@cloudbeaver/core-executor'; import type { SqlCompletionProposal, SqlDialectInfo } from '@cloudbeaver/core-sdk'; -import { createLastPromiseGetter, LastPromiseGetter, throttleAsync } from '@cloudbeaver/core-utils'; +import { createLastPromiseGetter, LastPromiseGetter, isObjectsEqual, throttleAsync } from '@cloudbeaver/core-utils'; import type { ISqlEditorTabState } from '../ISqlEditorTabState'; import type { ISqlDataSource } from '../SqlDataSource/ISqlDataSource'; @@ -457,7 +457,9 @@ export function useSqlEditor(state: ISqlEditorTabState): ISQLEditorData { showExecutionPlan: action.bound, executeScript: action.bound, switchEditing: action.bound, - activeSegmentMode: computed, + activeSegmentMode: computed({ + equals: isObjectsEqual, + }), dialect: computed, activeSegment: computed, isLineScriptEmpty: computed, @@ -478,7 +480,7 @@ export function useSqlEditor(state: ISqlEditorTabState): ISQLEditorData { commonDialogService, }); - data.init(); + untracked(() => data.init()); useExecutor({ executor: data.dataSource?.onSetScript, diff --git a/webapp/packages/plugin-sql-editor/src/SqlEditorService.ts b/webapp/packages/plugin-sql-editor/src/SqlEditorService.ts index 1f09001cc5..aca632de39 100644 --- a/webapp/packages/plugin-sql-editor/src/SqlEditorService.ts +++ b/webapp/packages/plugin-sql-editor/src/SqlEditorService.ts @@ -11,7 +11,7 @@ import { observable } from 'mobx'; import { Connection, ConnectionExecutionContextProjectKey, ConnectionExecutionContextResource, ConnectionExecutionContextService, ConnectionInfoResource, ConnectionsManagerService, createConnectionParam, IConnectionExecutionContext, IConnectionExecutionContextInfo, IConnectionInfoParams } from '@cloudbeaver/core-connections'; import { injectable } from '@cloudbeaver/core-di'; import { NotificationService } from '@cloudbeaver/core-events'; -import { Executor } from '@cloudbeaver/core-executor'; +import { ISyncExecutor, SyncExecutor } from '@cloudbeaver/core-executor'; import { GraphQLService, SqlCompletionProposal, SqlScriptInfoFragment } from '@cloudbeaver/core-sdk'; import { SqlDataSourceService, ISqlEditorTabState } from '@cloudbeaver/plugin-sql-editor'; @@ -28,7 +28,7 @@ export interface IQueryChangeData { @injectable() export class SqlEditorService { - readonly onQueryChange: Executor; + readonly onQueryChange: ISyncExecutor; constructor( private readonly graphQLService: GraphQLService, @@ -39,7 +39,7 @@ export class SqlEditorService { private readonly connectionInfoResource: ConnectionInfoResource, private readonly sqlDataSourceService: SqlDataSourceService ) { - this.onQueryChange = new Executor(); + this.onQueryChange = new SyncExecutor(); } getState( diff --git a/webapp/packages/product-default/package.json b/webapp/packages/product-default/package.json index 2b77981408..30d19d8c48 100644 --- a/webapp/packages/product-default/package.json +++ b/webapp/packages/product-default/package.json @@ -1,7 +1,7 @@ { "name": "@cloudbeaver/product-default", "sideEffects": false, - "version": "22.2.2", + "version": "22.2.3", "description": "", "license": "Apache-2.0", "main": "lib/index.js", diff --git a/webapp/yarn.lock b/webapp/yarn.lock index 876d198620..f42fac3ff1 100644 --- a/webapp/yarn.lock +++ b/webapp/yarn.lock @@ -7925,7 +7925,7 @@ extsprintf@^1.2.0: resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.4.1.tgz#8d172c064867f235c0c84a596806d279bf4bcc07" integrity sha512-Wrk35e8ydCKDj/ArClo1VrPVmN8zph5V4AtHwIuHhvMXsKf73UT3BOD+azBIW+3wOJ4FhEH7zyaJCFvChjYvMA== -fast-deep-equal@^3.1.1, fast-deep-equal@^3.1.3: +fast-deep-equal@^3.1.1, fast-deep-equal@^3.1.3, fast-deep-equal@~3.1.3: version "3.1.3" resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525" integrity sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==