mirror of
https://github.com/dbeaver/cloudbeaver.git
synced 2026-09-24 16:04:36 +08:00
CB-2881 remove public permission (#1414)
* CB-2881 remove public permission * CB-3035 add authRequired param for WebAction * CB-3035 add authRequired param for WebAction * CB-3035 add authRequired param for WebAction * CB-2881 refactor: replace public permission with authentication check * CB-3035 empty user permissions fix * CB-2881 fix: validate resource keys * CB-3035 user with no teams login fix * CB-2881 remove user teams validation * CB-2881 fix: check is connection is available in ResourceSqlDataSource Co-authored-by: Aleksey Potsetsuev <wrouds@gmail.com> Co-authored-by: kseniaguzeeva <112612526+kseniaguzeeva@users.noreply.github.com>
This commit is contained in:
co-authored by
Aleksey Potsetsuev
kseniaguzeeva
parent
d932094cbd
commit
dec3c37e64
@@ -4,13 +4,13 @@
|
||||
subjectId: "admin",
|
||||
name: "Admin",
|
||||
description: "Administrative access. Has all permissions.",
|
||||
permissions: [ "public", "admin" ]
|
||||
permissions: [ "admin" ]
|
||||
},
|
||||
{
|
||||
subjectId: "user",
|
||||
name: "User",
|
||||
description: "Standard user",
|
||||
permissions: [ "public" ]
|
||||
permissions: [ ]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -23,7 +23,6 @@ import org.jkiss.dbeaver.model.access.DBAPermissionRealm;
|
||||
*/
|
||||
public class DBWConstants {
|
||||
|
||||
public static final String PERMISSION_PUBLIC = DBAPermissionRealm.PERMISSION_PUBLIC;
|
||||
public static final String PERMISSION_ADMIN = DBAPermissionRealm.PERMISSION_ADMIN;
|
||||
|
||||
public static final String PERMISSION_CONFIGURATION_MANAGER = "configuration-manager";
|
||||
|
||||
-3
@@ -161,9 +161,6 @@ public class WebSessionAuthProcessor {
|
||||
providerConfig,
|
||||
authAttrs);
|
||||
|
||||
if (!configMode && securityController.getUserPermissions(userId).isEmpty()) {
|
||||
throw new DBWebException("Access denied (no permissions)");
|
||||
}
|
||||
if (!configMode && !securityController.getCurrentUser().isEnabled()) {
|
||||
throw new DBWebException("User account is locked");
|
||||
}
|
||||
|
||||
-4
@@ -202,10 +202,6 @@ public class WebUserContext implements SMCredentialsProvider {
|
||||
|
||||
private void setUserPermissions(Set<String> permissions) {
|
||||
this.userPermissions = permissions;
|
||||
// FIXME: automatically assign public permission in sm controller˚
|
||||
if (!CommonUtils.isEmpty(userPermissions)) {
|
||||
userPermissions.add(DBWConstants.PERMISSION_PUBLIC);
|
||||
}
|
||||
}
|
||||
|
||||
public DBSSecretController getSecretController() {
|
||||
|
||||
@@ -21,8 +21,6 @@
|
||||
|
||||
<extension point="io.cloudbeaver.service">
|
||||
<service id="core" label="Core service" description="Core services" class="io.cloudbeaver.service.core.WebServiceBindingCore">
|
||||
<permission id="public" label="Public access" category="general" scope="subject"
|
||||
description="Provides access to the data management interface"/>
|
||||
<permission id="access" label="Data source access" category="general" scope="datasource"/>
|
||||
</service>
|
||||
<service id="navigator" label="Database navigator" description="Database navigator services"
|
||||
|
||||
@@ -29,6 +29,8 @@ import java.lang.annotation.Target;
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface WebAction {
|
||||
|
||||
String[] requirePermissions() default { DBWConstants.PERMISSION_PUBLIC };
|
||||
String[] requirePermissions() default { };
|
||||
|
||||
boolean authRequired() default true;
|
||||
|
||||
}
|
||||
|
||||
@@ -31,6 +31,6 @@ public @interface WebActionSet {
|
||||
|
||||
String[] requireFeatures() default { };
|
||||
|
||||
String[] requirePermissions() default { DBWConstants.PERMISSION_PUBLIC };
|
||||
String[] requirePermissions() default { };
|
||||
|
||||
}
|
||||
|
||||
+1
-2
@@ -253,8 +253,7 @@ public abstract class WebServiceBindingBase<API_TYPE extends DBWService> impleme
|
||||
}
|
||||
CBApplication application = CBApplication.getInstance();
|
||||
if (!application.isConfigurationMode()) {
|
||||
Set<String> sessionPermissions = session.getSessionPermissions();
|
||||
if (CommonUtils.isEmpty(sessionPermissions)) {
|
||||
if (webAction.authRequired() && !session.isAuthorizedInSecurityManager()) {
|
||||
log.debug("Anonymous access to " + method.getName() + " restricted");
|
||||
throw new DBWebExceptionAccessDenied("Anonymous access restricted");
|
||||
}
|
||||
|
||||
+9
-9
@@ -38,7 +38,7 @@ import java.util.Map;
|
||||
*/
|
||||
public interface DBWServiceCore extends DBWService {
|
||||
|
||||
@WebAction(requirePermissions = {})
|
||||
@WebAction(authRequired = false)
|
||||
WebServerConfig getServerConfig() throws DBWebException;
|
||||
|
||||
@WebAction
|
||||
@@ -50,14 +50,14 @@ public interface DBWServiceCore extends DBWService {
|
||||
@WebAction
|
||||
List<WebNetworkHandlerDescriptor> getNetworkHandlers(@NotNull WebSession webSession);
|
||||
|
||||
@WebAction(requirePermissions = {})
|
||||
@WebAction(authRequired = false)
|
||||
List<WebConnectionInfo> getUserConnections(
|
||||
@NotNull WebSession webSession,
|
||||
@Nullable String projectId,
|
||||
@Nullable String id,
|
||||
@Nullable List<String> projectIds) throws DBWebException;
|
||||
|
||||
@WebAction(requirePermissions = {})
|
||||
@WebAction(authRequired = false)
|
||||
List<WebConnectionFolderInfo> getConnectionFolders(
|
||||
@NotNull WebSession webSession, @Nullable String projectId, @Nullable String id) throws DBWebException;
|
||||
|
||||
@@ -68,32 +68,32 @@ public interface DBWServiceCore extends DBWService {
|
||||
@WebAction
|
||||
List<WebConnectionInfo> getTemplateConnections(@NotNull WebSession webSession, @Nullable String projectId) throws DBWebException;
|
||||
|
||||
@WebAction(requirePermissions = {})
|
||||
@WebAction(authRequired = false)
|
||||
String[] getSessionPermissions(@NotNull WebSession webSession) throws DBWebException;
|
||||
|
||||
///////////////////////////////////////////
|
||||
// Session
|
||||
|
||||
@WebAction(requirePermissions = {})
|
||||
@WebAction(authRequired = false)
|
||||
WebSession openSession(
|
||||
@NotNull WebSession webSession,
|
||||
@Nullable String defaultLocale,
|
||||
@NotNull HttpServletRequest servletRequest,
|
||||
@NotNull HttpServletResponse servletResponse) throws DBWebException;
|
||||
|
||||
@WebAction(requirePermissions = {})
|
||||
@WebAction(authRequired = false)
|
||||
WebSession getSessionState(@NotNull WebSession webSession) throws DBWebException;
|
||||
|
||||
@WebAction
|
||||
List<WebServerMessage> readSessionLog(@NotNull WebSession webSession, Integer maxEntries, Boolean clearEntries) throws DBWebException;
|
||||
|
||||
@WebAction(requirePermissions = {})
|
||||
@WebAction(authRequired = false)
|
||||
boolean closeSession(HttpServletRequest request) throws DBWebException;
|
||||
|
||||
@WebAction(requirePermissions = {})
|
||||
@WebAction(authRequired = false)
|
||||
boolean touchSession(@NotNull HttpServletRequest request, @NotNull HttpServletResponse servletResponse) throws DBWebException;
|
||||
|
||||
@WebAction(requirePermissions = {})
|
||||
@WebAction(authRequired = false)
|
||||
boolean refreshSessionConnections(@NotNull HttpServletRequest request, @NotNull HttpServletResponse response) throws DBWebException;
|
||||
|
||||
@WebAction
|
||||
|
||||
-1
@@ -208,7 +208,6 @@ public class WebServiceCore implements DBWServiceCore {
|
||||
public String[] getSessionPermissions(@NotNull WebSession webSession) throws DBWebException {
|
||||
if (CBApplication.getInstance().isConfigurationMode()) {
|
||||
return new String[] {
|
||||
DBWConstants.PERMISSION_PUBLIC,
|
||||
DBWConstants.PERMISSION_ADMIN
|
||||
};
|
||||
}
|
||||
|
||||
+5
-5
@@ -32,7 +32,7 @@ import java.util.Map;
|
||||
*/
|
||||
public interface DBWServiceAuth extends DBWService {
|
||||
|
||||
@WebAction(requirePermissions = {})
|
||||
@WebAction(authRequired = false)
|
||||
WebAuthStatus authLogin(
|
||||
@NotNull WebSession webSession,
|
||||
@NotNull String providerId,
|
||||
@@ -41,16 +41,16 @@ public interface DBWServiceAuth extends DBWService {
|
||||
boolean linkWithActiveUser) throws DBWebException;
|
||||
|
||||
|
||||
@WebAction(requirePermissions = {})
|
||||
@WebAction(authRequired = false)
|
||||
WebAuthStatus authUpdateStatus(@NotNull WebSession webSession, @NotNull String authId, boolean linkWithActiveUser) throws DBWebException;
|
||||
|
||||
@WebAction(requirePermissions = {})
|
||||
@WebAction(authRequired = false)
|
||||
void authLogout(@NotNull WebSession webSession, @Nullable String providerId, @Nullable String configurationId) throws DBWebException;
|
||||
|
||||
@WebAction(requirePermissions = {})
|
||||
@WebAction(authRequired = false)
|
||||
WebUserInfo activeUser(@NotNull WebSession webSession) throws DBWebException;
|
||||
|
||||
@WebAction(requirePermissions = {})
|
||||
@WebAction(authRequired = false)
|
||||
WebAuthProviderInfo[] getAuthProviders();
|
||||
|
||||
@WebAction()
|
||||
|
||||
+1
-1
@@ -821,7 +821,7 @@ public class CBEmbeddedSecurityController implements SMAdminController, SMAuthen
|
||||
}
|
||||
|
||||
protected String[] getDefaultTeamPermissions() {
|
||||
return new String[]{DBWConstants.PERMISSION_PUBLIC};
|
||||
return new String[0];
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -6,13 +6,13 @@
|
||||
subjectId: "admin",
|
||||
name: "Admin",
|
||||
description: "Administrative access. Has all permissions.",
|
||||
permissions: [ "public", "admin" ]
|
||||
permissions: [ "admin" ]
|
||||
},
|
||||
{
|
||||
subjectId: "user",
|
||||
name: "User",
|
||||
description: "Standard user",
|
||||
permissions: [ "public" ]
|
||||
permissions: [ ]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
|
||||
import { injectable } from '@cloudbeaver/core-di';
|
||||
import { SessionDataResource } from '@cloudbeaver/core-root';
|
||||
import { GraphQLService, CachedMapResource, CachedMapAllKey, AdminPermissionInfoFragment, AdminObjectGrantInfoFragment } from '@cloudbeaver/core-sdk';
|
||||
import { GraphQLService, CachedMapResource, CachedMapAllKey, AdminPermissionInfoFragment, AdminObjectGrantInfoFragment, ResourceKey } from '@cloudbeaver/core-sdk';
|
||||
|
||||
export type PermissionInfo = AdminPermissionInfoFragment;
|
||||
export type AdminObjectGrantInfo = AdminObjectGrantInfoFragment;
|
||||
@@ -34,4 +34,11 @@ export class PermissionsResource extends CachedMapResource<string, PermissionInf
|
||||
|
||||
return this.data;
|
||||
}
|
||||
|
||||
protected validateParam(param: ResourceKey<string>): boolean {
|
||||
return (
|
||||
super.validateParam(param)
|
||||
|| typeof param === 'string'
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,10 +6,8 @@
|
||||
* you may not use this file except in compliance with the License.
|
||||
*/
|
||||
|
||||
import { usePermission } from '@cloudbeaver/core-blocks';
|
||||
import { useService } from '@cloudbeaver/core-di';
|
||||
import { ServerService } from '@cloudbeaver/core-root';
|
||||
import type { ServerConfig } from '@cloudbeaver/core-sdk';
|
||||
import { usePermission, useResource } from '@cloudbeaver/core-blocks';
|
||||
import { ServerConfigResource } from '@cloudbeaver/core-root';
|
||||
|
||||
import { EAdminPermission } from './EAdminPermission';
|
||||
|
||||
@@ -17,7 +15,7 @@ interface IAdministrationSettings {
|
||||
credentialsSavingEnabled: boolean;
|
||||
}
|
||||
|
||||
function getCredentialsSavingSetting(config: ServerConfig, isAdmin: boolean) {
|
||||
function getCredentialsSavingSetting(config: ServerConfigResource, isAdmin: boolean) {
|
||||
if (config.configurationMode) {
|
||||
return true;
|
||||
}
|
||||
@@ -35,14 +33,9 @@ function getCredentialsSavingSetting(config: ServerConfig, isAdmin: boolean) {
|
||||
|
||||
export function useAdministrationSettings(): IAdministrationSettings {
|
||||
const isAdmin = usePermission(EAdminPermission.admin);
|
||||
const serverService = useService(ServerService);
|
||||
const config = serverService.config.data;
|
||||
|
||||
if (!config) {
|
||||
throw new Error("Can't get credentials save permission");
|
||||
}
|
||||
const { resource: serverConfigResource } = useResource(useAdministrationSettings, ServerConfigResource, undefined);
|
||||
|
||||
return {
|
||||
credentialsSavingEnabled: getCredentialsSavingSetting(config, isAdmin),
|
||||
credentialsSavingEnabled: getCredentialsSavingSetting(serverConfigResource, isAdmin),
|
||||
};
|
||||
}
|
||||
|
||||
@@ -7,28 +7,36 @@
|
||||
*/
|
||||
|
||||
import { injectable, Bootstrap } from '@cloudbeaver/core-di';
|
||||
import { Executor, IExecutor } from '@cloudbeaver/core-executor';
|
||||
import { ServerService } from '@cloudbeaver/core-root';
|
||||
import { Executor, ExecutorInterrupter, IExecutor } from '@cloudbeaver/core-executor';
|
||||
import { ServerConfigResource } from '@cloudbeaver/core-root';
|
||||
import { CachedDataResourceParam, CachedResource, getCachedDataResourceLoaderState } from '@cloudbeaver/core-sdk';
|
||||
import type { ILoadableState } from '@cloudbeaver/core-utils';
|
||||
|
||||
import { UserInfoResource } from './UserInfoResource';
|
||||
|
||||
@injectable()
|
||||
export class AppAuthService extends Bootstrap {
|
||||
get authenticated(): boolean {
|
||||
const config = this.serverService.config.data;
|
||||
const user = this.userInfoResource.data;
|
||||
|
||||
return (
|
||||
!!config?.anonymousAccessEnabled
|
||||
|| this.serverService.config.configurationMode
|
||||
this.serverConfigResource.anonymousAccessEnabled
|
||||
|| this.serverConfigResource.configurationMode
|
||||
|| user !== null
|
||||
);
|
||||
}
|
||||
|
||||
get loaders(): ILoadableState[] {
|
||||
return [
|
||||
getCachedDataResourceLoaderState(this.userInfoResource, undefined),
|
||||
getCachedDataResourceLoaderState(this.serverConfigResource, undefined),
|
||||
];
|
||||
}
|
||||
|
||||
readonly auth: IExecutor<boolean>;
|
||||
|
||||
constructor(
|
||||
private readonly serverService: ServerService,
|
||||
private readonly serverConfigResource: ServerConfigResource,
|
||||
private readonly userInfoResource: UserInfoResource,
|
||||
) {
|
||||
super();
|
||||
@@ -36,21 +44,35 @@ export class AppAuthService extends Bootstrap {
|
||||
this.userInfoResource.onDataUpdate.addHandler(this.authUser.bind(this));
|
||||
}
|
||||
|
||||
requireAuthentication<T = CachedDataResourceParam<UserInfoResource>>(
|
||||
resource: CachedResource<any, any, T, any, any>,
|
||||
map?: (param: T | undefined) => T
|
||||
): this {
|
||||
resource
|
||||
.preloadResource(this.userInfoResource, () => {})
|
||||
.preloadResource(this.serverConfigResource, () => {})
|
||||
.before(ExecutorInterrupter.interrupter(() => !this.authenticated));
|
||||
|
||||
this.userInfoResource.outdateResource<T>(resource, map as any);
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
async isAuthNeeded(): Promise<boolean> {
|
||||
const config = await this.serverService.config.load();
|
||||
const config = await this.serverConfigResource.load();
|
||||
if (!config) {
|
||||
throw new Error('Can\'t configure Authentication');
|
||||
}
|
||||
|
||||
const user = await this.userInfoResource.load(undefined, []);
|
||||
const user = await this.userInfoResource.load();
|
||||
|
||||
return !this.serverService.config.configurationMode
|
||||
&& !config.anonymousAccessEnabled
|
||||
return !this.serverConfigResource.configurationMode
|
||||
&& !this.serverConfigResource.anonymousAccessEnabled
|
||||
&& user === null;
|
||||
}
|
||||
|
||||
async authUser(): Promise<boolean> {
|
||||
const userInfo = await this.userInfoResource.load(undefined, []);
|
||||
const userInfo = await this.userInfoResource.load();
|
||||
|
||||
const state = userInfo !== null;
|
||||
await this.auth.execute(state);
|
||||
|
||||
@@ -46,4 +46,11 @@ export class AuthConfigurationParametersResource
|
||||
|
||||
return this.data;
|
||||
}
|
||||
|
||||
protected validateParam(param: ResourceKey<string>): boolean {
|
||||
return (
|
||||
super.validateParam(param)
|
||||
|| typeof param === 'string'
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -111,6 +111,13 @@ export class AuthConfigurationsResource
|
||||
|
||||
return key;
|
||||
}
|
||||
|
||||
protected validateParam(param: ResourceKey<string>): boolean {
|
||||
return (
|
||||
super.validateParam(param)
|
||||
|| typeof param === 'string'
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
function isNewConfiguration(
|
||||
|
||||
@@ -151,4 +151,11 @@ export class AuthProvidersResource extends CachedMapResource<string, AuthProvide
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
protected validateParam(param: ResourceKey<string>): boolean {
|
||||
return (
|
||||
super.validateParam(param)
|
||||
|| typeof param === 'string'
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -185,6 +185,13 @@ export class TeamsResource extends CachedMapResource<string, TeamInfo, TeamResou
|
||||
includeMetaParameters: false,
|
||||
};
|
||||
}
|
||||
|
||||
protected validateParam(param: ResourceKey<string>): boolean {
|
||||
return (
|
||||
super.validateParam(param)
|
||||
|| typeof param === 'string'
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
function isNewTeam(team: TeamInfo | NewTeam): team is NewTeam {
|
||||
|
||||
@@ -32,7 +32,7 @@ export class UserMetaParametersResource extends CachedDataResource<UserMetaParam
|
||||
|
||||
this.sync(sessionResource, () => {}, () => {});
|
||||
this
|
||||
.preloadResource(userInfoResource)
|
||||
.preloadResource(userInfoResource, () => {})
|
||||
.before(ExecutorInterrupter.interrupter(() => userInfoResource.data === null));
|
||||
}
|
||||
|
||||
|
||||
@@ -251,6 +251,13 @@ export class UsersResource extends CachedMapResource<string, AdminUser, UserReso
|
||||
includeMetaParameters: false,
|
||||
};
|
||||
}
|
||||
|
||||
protected validateParam(param: ResourceKey<string>): boolean {
|
||||
return (
|
||||
super.validateParam(param)
|
||||
|| typeof param === 'string'
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export function isLocalUser(user: AdminUser): boolean {
|
||||
|
||||
@@ -17,7 +17,8 @@ import {
|
||||
ResourceKeyUtils,
|
||||
CachedMapAllKey,
|
||||
resourceKeyList,
|
||||
SqlDialectInfo
|
||||
SqlDialectInfo,
|
||||
isResourceKeyList
|
||||
} from '@cloudbeaver/core-sdk';
|
||||
|
||||
import type { IConnectionExecutionContextInfo } from './ConnectionExecutionContext/IConnectionExecutionContextInfo';
|
||||
@@ -106,4 +107,15 @@ export class ConnectionDialectResource extends CachedMapResource<IConnectionInfo
|
||||
|
||||
return key;
|
||||
}
|
||||
|
||||
protected validateParam(param: ResourceKey<IConnectionInfoParams>): boolean {
|
||||
return (
|
||||
super.validateParam(param)
|
||||
|| (
|
||||
typeof param === 'object' && !isResourceKeyList(param)
|
||||
&& typeof param.projectId === 'string'
|
||||
&& ['string'].includes(typeof param.connectionId)
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
+10
-5
@@ -8,8 +8,8 @@
|
||||
|
||||
import { action, makeObservable, runInAction } from 'mobx';
|
||||
|
||||
import { AppAuthService } from '@cloudbeaver/core-authentication';
|
||||
import { injectable } from '@cloudbeaver/core-di';
|
||||
import { EPermission, SessionPermissionsResource } from '@cloudbeaver/core-root';
|
||||
import {
|
||||
GraphQLService,
|
||||
CachedMapResource,
|
||||
@@ -40,7 +40,7 @@ export class ConnectionExecutionContextResource extends CachedMapResource<string
|
||||
constructor(
|
||||
private readonly graphQLService: GraphQLService,
|
||||
private readonly connectionInfoResource: ConnectionInfoResource,
|
||||
permissionsResource: SessionPermissionsResource
|
||||
appAuthService: AppAuthService,
|
||||
) {
|
||||
super();
|
||||
|
||||
@@ -54,9 +54,7 @@ export class ConnectionExecutionContextResource extends CachedMapResource<string
|
||||
(a, b) => a.mark === b.mark
|
||||
);
|
||||
|
||||
permissionsResource
|
||||
.require(this, EPermission.public)
|
||||
.outdateResource(this);
|
||||
appAuthService.requireAuthentication(this);
|
||||
|
||||
connectionInfoResource.onItemAdd.addHandler(this.updateConnectionContexts.bind(this));
|
||||
connectionInfoResource.onItemDelete.addHandler(this.deleteConnectionContexts.bind(this));
|
||||
@@ -242,6 +240,13 @@ export class ConnectionExecutionContextResource extends CachedMapResource<string
|
||||
|
||||
return key;
|
||||
}
|
||||
|
||||
protected validateParam(param: ResourceKey<string>): boolean {
|
||||
return (
|
||||
super.validateParam(param)
|
||||
|| typeof param === 'string'
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
function getBaseContext(context: SqlContextInfo): IConnectionExecutionContextInfo {
|
||||
|
||||
@@ -8,8 +8,9 @@
|
||||
|
||||
import { action, makeObservable, runInAction } from 'mobx';
|
||||
|
||||
import { AppAuthService } from '@cloudbeaver/core-authentication';
|
||||
import { injectable } from '@cloudbeaver/core-di';
|
||||
import { EPermission, SessionPermissionsResource, SessionDataResource } from '@cloudbeaver/core-root';
|
||||
import { SessionDataResource } from '@cloudbeaver/core-root';
|
||||
import {
|
||||
GraphQLService,
|
||||
CachedMapResource,
|
||||
@@ -42,11 +43,11 @@ export class ConnectionFolderResource extends CachedMapResource<IConnectionFolde
|
||||
constructor(
|
||||
private readonly graphQLService: GraphQLService,
|
||||
sessionDataResource: SessionDataResource,
|
||||
permissionsResource: SessionPermissionsResource
|
||||
appAuthService: AppAuthService
|
||||
) {
|
||||
super();
|
||||
|
||||
permissionsResource.require(this, EPermission.public);
|
||||
appAuthService.requireAuthentication(this);
|
||||
sessionDataResource.outdateResource(this);
|
||||
|
||||
this.addAlias(
|
||||
@@ -170,6 +171,17 @@ export class ConnectionFolderResource extends CachedMapResource<IConnectionFolde
|
||||
|
||||
return key;
|
||||
}
|
||||
|
||||
protected validateParam(param: ResourceKey<IConnectionFolderParam>): boolean {
|
||||
return (
|
||||
super.validateParam(param)
|
||||
|| (
|
||||
typeof param === 'object' && !isResourceKeyList(param)
|
||||
&& typeof param.projectId === 'string'
|
||||
&& ['string'].includes(typeof param.folderId)
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
function isConnectionFolderProjectKey(
|
||||
|
||||
@@ -8,10 +8,11 @@
|
||||
|
||||
import { action, makeObservable, observable, runInAction } from 'mobx';
|
||||
|
||||
import { AppAuthService } from '@cloudbeaver/core-authentication';
|
||||
import { injectable } from '@cloudbeaver/core-di';
|
||||
import { SyncExecutor, ExecutorInterrupter, ISyncExecutor } from '@cloudbeaver/core-executor';
|
||||
import { ProjectInfoResource, ProjectsService } from '@cloudbeaver/core-projects';
|
||||
import { EPermission, NavigatorViewSettings, SessionPermissionsResource, SessionDataResource, DataSynchronizationService, ServerEventId } from '@cloudbeaver/core-root';
|
||||
import { NavigatorViewSettings, SessionDataResource, DataSynchronizationService, ServerEventId } from '@cloudbeaver/core-root';
|
||||
import {
|
||||
GraphQLService,
|
||||
CachedMapResource,
|
||||
@@ -83,7 +84,7 @@ export class ConnectionInfoResource
|
||||
private readonly projectInfoResource: ProjectInfoResource,
|
||||
private readonly dataSynchronizationService: DataSynchronizationService,
|
||||
sessionDataResource: SessionDataResource,
|
||||
permissionsResource: SessionPermissionsResource,
|
||||
appAuthService: AppAuthService,
|
||||
connectionInfoEventHandler: ConnectionInfoEventHandler,
|
||||
) {
|
||||
super();
|
||||
@@ -114,7 +115,7 @@ export class ConnectionInfoResource
|
||||
this.onItemDelete.addHandler(ExecutorInterrupter.interrupter(() => this.sessionUpdate));
|
||||
this.onConnectionCreate.addHandler(ExecutorInterrupter.interrupter(() => this.sessionUpdate));
|
||||
|
||||
permissionsResource.require(this, EPermission.public);
|
||||
appAuthService.requireAuthentication(this);
|
||||
this.sync(this.projectInfoResource, () => CachedMapAllKey, () => CachedMapAllKey);
|
||||
this.projectsService.onActiveProjectChange.addHandler(data => {
|
||||
if (data.type === 'after') {
|
||||
@@ -594,6 +595,19 @@ export class ConnectionInfoResource
|
||||
customIncludeOptions: false,
|
||||
};
|
||||
}
|
||||
|
||||
protected validateParam(param: ResourceKey<IConnectionInfoParams>): boolean {
|
||||
return (
|
||||
super.validateParam(param)
|
||||
|| param === connectionInfoProjectKeySymbol
|
||||
|| param === connectionInfoActiveProjectKeySymbol
|
||||
|| (
|
||||
typeof param === 'object' && !isResourceKeyList(param)
|
||||
&& typeof param.projectId === 'string'
|
||||
&& ['string'].includes(typeof param.connectionId)
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
function isConnectionInfoProjectKey(
|
||||
|
||||
@@ -8,9 +8,9 @@
|
||||
|
||||
import { observable } from 'mobx';
|
||||
|
||||
import { AppAuthService } from '@cloudbeaver/core-authentication';
|
||||
import { injectable } from '@cloudbeaver/core-di';
|
||||
import { ExecutorInterrupter } from '@cloudbeaver/core-executor';
|
||||
import { EPermission, SessionPermissionsResource } from '@cloudbeaver/core-root';
|
||||
import {
|
||||
GraphQLService,
|
||||
CachedDataResource,
|
||||
@@ -61,7 +61,7 @@ string
|
||||
constructor(
|
||||
private readonly graphQLService: GraphQLService,
|
||||
private readonly connectionInfoResource: ConnectionInfoResource,
|
||||
permissionsResource: SessionPermissionsResource,
|
||||
appAuthService: AppAuthService,
|
||||
) {
|
||||
super(new Map());
|
||||
|
||||
@@ -75,7 +75,7 @@ string
|
||||
dependencies: observable([]),
|
||||
}));
|
||||
|
||||
permissionsResource.require(this, EPermission.public);
|
||||
appAuthService.requireAuthentication(this);
|
||||
this.preloadResource(connectionInfoResource, () => ConnectionInfoActiveProjectKey);
|
||||
this.before(ExecutorInterrupter.interrupter(key => !connectionInfoResource.isConnected(key)));
|
||||
|
||||
@@ -205,6 +205,18 @@ string
|
||||
&& param.catalogId === second.catalogId
|
||||
);
|
||||
}
|
||||
|
||||
protected validateParam(param: ObjectContainerParams): boolean {
|
||||
return (
|
||||
super.validateParam(param)
|
||||
|| (
|
||||
typeof param === 'object'
|
||||
&& typeof param.projectId === 'string'
|
||||
&& ['string'].includes(typeof param.connectionId)
|
||||
&& ['string', 'undefined'].includes(typeof param.catalogId)
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
function serializeKey(key: ObjectContainerParams): string {
|
||||
|
||||
@@ -8,8 +8,9 @@
|
||||
|
||||
import { computed, makeObservable, runInAction } from 'mobx';
|
||||
|
||||
import { AppAuthService } from '@cloudbeaver/core-authentication';
|
||||
import { injectable } from '@cloudbeaver/core-di';
|
||||
import { EPermission, SessionPermissionsResource, ServerConfigResource } from '@cloudbeaver/core-root';
|
||||
import { ServerConfigResource } from '@cloudbeaver/core-root';
|
||||
import {
|
||||
GraphQLService,
|
||||
CachedMapResource,
|
||||
@@ -34,10 +35,10 @@ export class DBDriverResource extends CachedMapResource<string, DBDriver, Driver
|
||||
constructor(
|
||||
private readonly serverConfigResource: ServerConfigResource,
|
||||
private readonly graphQLService: GraphQLService,
|
||||
permissionsResource: SessionPermissionsResource,
|
||||
appAuthService: AppAuthService,
|
||||
) {
|
||||
super();
|
||||
permissionsResource.require(this, EPermission.public);
|
||||
appAuthService.requireAuthentication(this);
|
||||
|
||||
this.serverConfigResource.onDataOutdated.addHandler(() => this.markOutdated());
|
||||
|
||||
@@ -97,4 +98,11 @@ export class DBDriverResource extends CachedMapResource<string, DBDriver, Driver
|
||||
const oldDriver = this.get(keys);
|
||||
this.set(keys, oldDriver.map((oldDriver, i) => (Object.assign(oldDriver ?? {}, drivers[i]))));
|
||||
}
|
||||
|
||||
protected validateParam(param: ResourceKey<string>): boolean {
|
||||
return (
|
||||
super.validateParam(param)
|
||||
|| typeof param === 'string'
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,7 +11,8 @@ import {
|
||||
DatabaseAuthModel,
|
||||
GraphQLService,
|
||||
CachedMapResource,
|
||||
resourceKeyList
|
||||
resourceKeyList,
|
||||
ResourceKey
|
||||
} from '@cloudbeaver/core-sdk';
|
||||
|
||||
@injectable()
|
||||
@@ -27,4 +28,11 @@ export class DatabaseAuthModelsResource extends CachedMapResource<string, Databa
|
||||
|
||||
return this.data;
|
||||
}
|
||||
|
||||
protected validateParam(param: ResourceKey<string>): boolean {
|
||||
return (
|
||||
super.validateParam(param)
|
||||
|| typeof param === 'string'
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -13,7 +13,8 @@ import {
|
||||
GraphQLService,
|
||||
CachedMapResource,
|
||||
resourceKeyList,
|
||||
NetworkHandlerConfigInput
|
||||
NetworkHandlerConfigInput,
|
||||
ResourceKey
|
||||
} from '@cloudbeaver/core-sdk';
|
||||
import { MetadataMap } from '@cloudbeaver/core-utils';
|
||||
|
||||
@@ -21,7 +22,7 @@ export const SSH_TUNNEL_ID = 'ssh_tunnel';
|
||||
|
||||
@injectable()
|
||||
export class NetworkHandlerResource extends CachedMapResource<string, NetworkHandlerDescriptor> {
|
||||
private loadedKeyMetadata: MetadataMap<string, boolean>;
|
||||
private readonly loadedKeyMetadata: MetadataMap<string, boolean>;
|
||||
|
||||
constructor(
|
||||
private readonly graphQLService: GraphQLService,
|
||||
@@ -67,4 +68,11 @@ export class NetworkHandlerResource extends CachedMapResource<string, NetworkHan
|
||||
|
||||
return this.data;
|
||||
}
|
||||
|
||||
protected validateParam(param: ResourceKey<string>): boolean {
|
||||
return (
|
||||
super.validateParam(param)
|
||||
|| typeof param === 'string'
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -98,6 +98,13 @@ export class DBObjectResource extends CachedMapResource<string, DBObject> {
|
||||
this.markOutdated(outdateKey);
|
||||
// }
|
||||
}
|
||||
|
||||
protected validateParam(param: ResourceKey<string>): boolean {
|
||||
return (
|
||||
super.validateParam(param)
|
||||
|| typeof param === 'string'
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
function isDBObjectParentKey(
|
||||
|
||||
@@ -8,8 +8,8 @@
|
||||
|
||||
import { action, makeObservable, observable, runInAction } from 'mobx';
|
||||
|
||||
import { AppAuthService } from '@cloudbeaver/core-authentication';
|
||||
import { injectable } from '@cloudbeaver/core-di';
|
||||
import { SessionPermissionsResource, EPermission } from '@cloudbeaver/core-root';
|
||||
import {
|
||||
GraphQLService,
|
||||
CachedMapResource,
|
||||
@@ -39,7 +39,7 @@ export class NavNodeInfoResource extends CachedMapResource<string, NavNode> {
|
||||
protected metadata: MetadataMap<string, INodeMetadata>;
|
||||
constructor(
|
||||
private readonly graphQLService: GraphQLService,
|
||||
permissionsResource: SessionPermissionsResource,
|
||||
appAuthService: AppAuthService,
|
||||
) {
|
||||
super();
|
||||
|
||||
@@ -58,7 +58,7 @@ export class NavNodeInfoResource extends CachedMapResource<string, NavNode> {
|
||||
setParent: action,
|
||||
});
|
||||
|
||||
permissionsResource.require(this, EPermission.public);
|
||||
appAuthService.requireAuthentication(this);
|
||||
}
|
||||
|
||||
updateNode(key: string, node: NavNode): void;
|
||||
@@ -218,6 +218,13 @@ export class NavNodeInfoResource extends CachedMapResource<string, NavNode> {
|
||||
return navNode;
|
||||
});
|
||||
}
|
||||
|
||||
protected validateParam(param: ResourceKey<string>): boolean {
|
||||
return (
|
||||
super.validateParam(param)
|
||||
|| typeof param === 'string'
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export function getNodeDisplayName(node: NavNode): string {
|
||||
|
||||
@@ -9,11 +9,11 @@
|
||||
import { action, computed, makeObservable, observable, runInAction } from 'mobx';
|
||||
|
||||
import { CoreSettingsService } from '@cloudbeaver/core-app';
|
||||
import { UserInfoResource } from '@cloudbeaver/core-authentication';
|
||||
import { AppAuthService, UserInfoResource } from '@cloudbeaver/core-authentication';
|
||||
import { injectable } from '@cloudbeaver/core-di';
|
||||
import { Executor, ExecutorInterrupter, IExecutor } from '@cloudbeaver/core-executor';
|
||||
import { ProjectInfoResource } from '@cloudbeaver/core-projects';
|
||||
import { EPermission, SessionPermissionsResource, SessionDataResource } from '@cloudbeaver/core-root';
|
||||
import { SessionDataResource } from '@cloudbeaver/core-root';
|
||||
import {
|
||||
GraphQLService,
|
||||
CachedMapResource,
|
||||
@@ -78,7 +78,7 @@ export class NavTreeResource extends CachedMapResource<string, string[]> {
|
||||
private readonly sessionDataResource: SessionDataResource,
|
||||
private readonly userInfoResource: UserInfoResource,
|
||||
private readonly projectInfoResource: ProjectInfoResource,
|
||||
permissionsResource: SessionPermissionsResource,
|
||||
appAuthService: AppAuthService,
|
||||
) {
|
||||
super();
|
||||
|
||||
@@ -105,7 +105,7 @@ export class NavTreeResource extends CachedMapResource<string, string[]> {
|
||||
dependencies: observable([]),
|
||||
}));
|
||||
|
||||
permissionsResource.require(this, EPermission.public);
|
||||
appAuthService.requireAuthentication(this);
|
||||
// this.preloadResource(connectionInfo, () => CachedMapAllKey);
|
||||
|
||||
this.onNodeRefresh = new Executor<string>(null, (a, b) => a === b);
|
||||
@@ -524,4 +524,11 @@ export class NavTreeResource extends CachedMapResource<string, string[]> {
|
||||
|
||||
return { navNodeChildren, navNodeInfo, parentPath };
|
||||
}
|
||||
|
||||
protected validateParam(param: ResourceKey<string>): boolean {
|
||||
return (
|
||||
super.validateParam(param)
|
||||
|| typeof param === 'string'
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,10 +8,9 @@
|
||||
|
||||
import { runInAction } from 'mobx';
|
||||
|
||||
import { UserInfoResource } from '@cloudbeaver/core-authentication';
|
||||
import { AppAuthService, UserInfoResource } from '@cloudbeaver/core-authentication';
|
||||
import { injectable } from '@cloudbeaver/core-di';
|
||||
import { SharedProjectsResource } from '@cloudbeaver/core-resource-manager';
|
||||
import { EPermission, SessionPermissionsResource } from '@cloudbeaver/core-root';
|
||||
import { GraphQLService, ProjectInfo as SchemaProjectInfo, CachedMapResource, CachedMapAllKey, ResourceKey, ResourceKeyUtils, resourceKeyList } from '@cloudbeaver/core-sdk';
|
||||
|
||||
export type ProjectInfo = SchemaProjectInfo;
|
||||
@@ -22,13 +21,13 @@ export class ProjectInfoResource extends CachedMapResource<string, ProjectInfo>
|
||||
private readonly graphQLService: GraphQLService,
|
||||
private readonly sharedProjectsResource: SharedProjectsResource,
|
||||
private readonly userInfoResource: UserInfoResource,
|
||||
sessionPermissionsResource: SessionPermissionsResource
|
||||
appAuthService: AppAuthService,
|
||||
) {
|
||||
super(new Map(), []);
|
||||
|
||||
this.sync(this.userInfoResource);
|
||||
this.sync(this.userInfoResource, () => {}, () => CachedMapAllKey);
|
||||
this.sharedProjectsResource.connect(this);
|
||||
sessionPermissionsResource.require(this, EPermission.public);
|
||||
appAuthService.requireAuthentication(this);
|
||||
this.sharedProjectsResource.onDataOutdated.addHandler(this.markOutdated.bind(this));
|
||||
this.sharedProjectsResource.onItemAdd.addHandler(() => this.markOutdated());
|
||||
this.sharedProjectsResource.onItemDelete.addHandler(() => this.markOutdated());
|
||||
@@ -56,6 +55,13 @@ export class ProjectInfoResource extends CachedMapResource<string, ProjectInfo>
|
||||
|
||||
return this.data;
|
||||
}
|
||||
|
||||
protected validateParam(param: ResourceKey<string>): boolean {
|
||||
return (
|
||||
super.validateParam(param)
|
||||
|| typeof param === 'string'
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export function projectInfoSortByName(a: ProjectInfo, b: ProjectInfo) {
|
||||
|
||||
@@ -12,7 +12,7 @@ import { ServerConfigResource } from '@cloudbeaver/core-root';
|
||||
import { GraphQLService, CachedDataResource } from '@cloudbeaver/core-sdk';
|
||||
|
||||
@injectable()
|
||||
export class ProjectPermissionsResource extends CachedDataResource<PermissionInfo[], void | any> {
|
||||
export class ProjectPermissionsResource extends CachedDataResource<PermissionInfo[]> {
|
||||
constructor(
|
||||
private readonly graphQLService: GraphQLService,
|
||||
serverConfigResource: ServerConfigResource
|
||||
|
||||
@@ -498,6 +498,18 @@ export class ResourceManagerResource
|
||||
includeProperties: false,
|
||||
};
|
||||
}
|
||||
|
||||
protected validateParam(param: ResourceKey<IResourceManagerParams>): boolean {
|
||||
return (
|
||||
super.validateParam(param)
|
||||
|| (
|
||||
typeof param === 'object' && !isResourceKeyList(param)
|
||||
&& typeof param.projectId === 'string'
|
||||
&& ['string', 'undefined'].includes(typeof param.path)
|
||||
&& ['string', 'undefined'].includes(typeof param.name)
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export function createParentResourceKey(key: IResourceManagerParams): IResourceManagerParams {
|
||||
|
||||
@@ -149,6 +149,13 @@ export class SharedProjectsResource extends CachedMapResource<string, SharedProj
|
||||
const data = this.data.get(key);
|
||||
this.data.set(key, Object.assign(data ?? {}, value));
|
||||
}
|
||||
|
||||
protected validateParam(param: ResourceKey<string>): boolean {
|
||||
return (
|
||||
super.validateParam(param)
|
||||
|| typeof param === 'string'
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export function isEqualSharedProjectGrantInfo(a: AdminObjectGrantInfo, b: AdminObjectGrantInfo): boolean {
|
||||
|
||||
@@ -18,7 +18,7 @@ import { ServerConfigResource } from './ServerConfigResource';
|
||||
export type ApplicationFeature = WebFeatureSet;
|
||||
|
||||
@injectable()
|
||||
export class FeaturesResource extends CachedDataResource<ApplicationFeature[], void | any> {
|
||||
export class FeaturesResource extends CachedDataResource<ApplicationFeature[]> {
|
||||
constructor(
|
||||
private readonly graphQLService: GraphQLService,
|
||||
serverConfigResource: ServerConfigResource
|
||||
|
||||
@@ -11,7 +11,6 @@ import { injectable } from '@cloudbeaver/core-di';
|
||||
import { SessionPermissionsResource } from './SessionPermissionsResource';
|
||||
|
||||
export enum EPermission {
|
||||
public = 'public'
|
||||
}
|
||||
|
||||
@injectable()
|
||||
|
||||
@@ -73,13 +73,21 @@ export class ServerConfigResource extends CachedDataResource<ServerConfig | null
|
||||
return this.data?.workspaceId || '';
|
||||
}
|
||||
|
||||
get licenseRequired(): boolean {
|
||||
return this.data?.licenseRequired ?? false;
|
||||
}
|
||||
|
||||
get licenseValid(): boolean {
|
||||
return this.data?.licenseValid ?? false;
|
||||
}
|
||||
|
||||
get configurationMode(): boolean {
|
||||
return !!this.data?.configurationMode;
|
||||
}
|
||||
|
||||
get publicDisabled(): boolean {
|
||||
if (
|
||||
this.data?.configurationMode
|
||||
this.configurationMode
|
||||
|| (this.data?.licenseRequired && !this.data.licenseValid)
|
||||
) {
|
||||
return true;
|
||||
@@ -88,6 +96,18 @@ export class ServerConfigResource extends CachedDataResource<ServerConfig | null
|
||||
return false;
|
||||
}
|
||||
|
||||
get adminCredentialsSaveEnabled(): boolean {
|
||||
return this.data?.adminCredentialsSaveEnabled ?? false;
|
||||
}
|
||||
|
||||
get publicCredentialsSaveEnabled(): boolean {
|
||||
return this.data?.publicCredentialsSaveEnabled ?? false;
|
||||
}
|
||||
|
||||
get anonymousAccessEnabled(): boolean {
|
||||
return this.data?.anonymousAccessEnabled ?? false;
|
||||
}
|
||||
|
||||
get enabledFeatures(): string[] {
|
||||
return this.update.enabledFeatures || this.data?.enabledFeatures || [];
|
||||
}
|
||||
|
||||
@@ -75,7 +75,7 @@ export abstract class CachedDataResource<
|
||||
return true;
|
||||
}
|
||||
|
||||
async refresh<T extends CachedResourceIncludeArgs<TData, TContext>>(
|
||||
async refresh<T extends CachedResourceIncludeArgs<TData, TContext> = []>(
|
||||
param: TParam,
|
||||
context?: T
|
||||
): Promise<CachedResourceValueIncludes<TData, T>> {
|
||||
@@ -84,7 +84,7 @@ export abstract class CachedDataResource<
|
||||
return this.data as CachedResourceValueIncludes<TData, T>;
|
||||
}
|
||||
|
||||
async load<T extends CachedResourceIncludeArgs<TData, TContext>>(
|
||||
async load<T extends CachedResourceIncludeArgs<TData, TContext> = []>(
|
||||
param: TParam,
|
||||
context?: T
|
||||
): Promise<CachedResourceValueIncludes<TData, T>> {
|
||||
@@ -92,6 +92,14 @@ export abstract class CachedDataResource<
|
||||
await this.loadData(param, false, context);
|
||||
return this.data as CachedResourceValueIncludes<TData, T>;
|
||||
}
|
||||
|
||||
|
||||
protected validateParam(param: TParam): boolean {
|
||||
return (
|
||||
super.validateParam(param)
|
||||
|| typeof param === 'undefined'
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export function getCachedDataResourceLoaderState<
|
||||
|
||||
@@ -13,7 +13,7 @@ import { ILoadableState, isArraysEqual, isContainsException, MetadataMap, uuid }
|
||||
|
||||
import { CachedResource, CachedResourceKey, CachedResourceParamKey, ICachedResourceMetadata } from './CachedResource';
|
||||
import type { CachedResourceIncludeArgs, CachedResourceValueIncludes } from './CachedResourceIncludes';
|
||||
import { ResourceKey, resourceKeyList, ResourceKeyList, ResourceKeyUtils } from './ResourceKeyList';
|
||||
import { isResourceKeyList, ResourceKey, resourceKeyList, ResourceKeyList, ResourceKeyUtils } from './ResourceKeyList';
|
||||
|
||||
export type CachedMapResourceKey<TResource> = CachedResourceKey<TResource>;
|
||||
export type CachedMapResourceValue<TResource> = TResource extends CachedResource<Map<any, infer T>, any, any, any, any>
|
||||
@@ -40,8 +40,8 @@ export type CachedMapResourceLoader<
|
||||
? Array<CachedResourceValueIncludes<TValue, TIncludes>>
|
||||
: CachedResourceValueIncludes<TValue, TIncludes>;
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-empty-interface
|
||||
export interface ICachedMapResourceMetadata extends ICachedResourceMetadata {
|
||||
includes: string[];
|
||||
}
|
||||
|
||||
export const CachedMapAllKey = resourceKeyList<any>([Symbol('@cached-map-resource/all')], 'all');
|
||||
@@ -82,7 +82,7 @@ export abstract class CachedMapResource<
|
||||
outdated: true,
|
||||
loading: false,
|
||||
exception: null,
|
||||
includes: observable([...this.defaultIncludes]),
|
||||
includes: observable([...this.defaultIncludes as any]),
|
||||
dependencies: observable([]),
|
||||
...this.populateMetadata(key, metadata),
|
||||
}, undefined, { deep: false }));
|
||||
@@ -384,19 +384,19 @@ export abstract class CachedMapResource<
|
||||
}
|
||||
}
|
||||
|
||||
async refresh<T extends CachedResourceIncludeArgs<TValue, TContext>>(
|
||||
async refresh<T extends CachedResourceIncludeArgs<TValue, TContext> = []>(
|
||||
key: TKey,
|
||||
includes?: T
|
||||
): Promise<CachedResourceValueIncludes<TValue, T>>;
|
||||
async refresh<T extends CachedResourceIncludeArgs<TValue, TContext>>(
|
||||
async refresh<T extends CachedResourceIncludeArgs<TValue, TContext> = []>(
|
||||
key: ResourceKeyList<TKey>,
|
||||
includes?: T
|
||||
): Promise<Array<CachedResourceValueIncludes<TValue, T>>>;
|
||||
async refresh<T extends CachedResourceIncludeArgs<TValue, TContext>>(
|
||||
async refresh<T extends CachedResourceIncludeArgs<TValue, TContext> = []>(
|
||||
key: ResourceKey<TKey>,
|
||||
includes?: T
|
||||
): Promise<Array<CachedResourceValueIncludes<TValue, T>> | CachedResourceValueIncludes<TValue, T>>;
|
||||
async refresh<T extends CachedResourceIncludeArgs<TValue, TContext>>(
|
||||
async refresh<T extends CachedResourceIncludeArgs<TValue, TContext> = []>(
|
||||
key: ResourceKey<TKey>,
|
||||
includes?: T
|
||||
): Promise<Array<CachedResourceValueIncludes<TValue, T>> | CachedResourceValueIncludes<TValue, T>> {
|
||||
@@ -405,19 +405,19 @@ export abstract class CachedMapResource<
|
||||
return this.get(key) as Array<CachedResourceValueIncludes<TValue, T>> | CachedResourceValueIncludes<TValue, T>;
|
||||
}
|
||||
|
||||
async load<T extends CachedResourceIncludeArgs<TValue, TContext>>(
|
||||
async load<T extends CachedResourceIncludeArgs<TValue, TContext> = []>(
|
||||
key: TKey,
|
||||
includes?: T
|
||||
): Promise<CachedResourceValueIncludes<TValue, T>>;
|
||||
async load<T extends CachedResourceIncludeArgs<TValue, TContext>>(
|
||||
async load<T extends CachedResourceIncludeArgs<TValue, TContext> = []>(
|
||||
key: ResourceKeyList<TKey>,
|
||||
includes?: T
|
||||
): Promise<Array<CachedResourceValueIncludes<TValue, T>>>;
|
||||
async load<T extends CachedResourceIncludeArgs<TValue, TContext>>(
|
||||
async load<T extends CachedResourceIncludeArgs<TValue, TContext> = []>(
|
||||
key: ResourceKey<TKey>,
|
||||
includes?: T
|
||||
): Promise<Array<CachedResourceValueIncludes<TValue, T>> | CachedResourceValueIncludes<TValue, T>>;
|
||||
async load<T extends CachedResourceIncludeArgs<TValue, TContext>>(
|
||||
async load<T extends CachedResourceIncludeArgs<TValue, TContext> = []>(
|
||||
key: ResourceKey<TKey>,
|
||||
includes?: T
|
||||
): Promise<Array<CachedResourceValueIncludes<TValue, T>> | CachedResourceValueIncludes<TValue, T>> {
|
||||
@@ -622,6 +622,13 @@ export abstract class CachedMapResource<
|
||||
|
||||
this.onDataOutdated.execute(key);
|
||||
}
|
||||
|
||||
protected validateParam(param: ResourceKey<TKey>): boolean {
|
||||
return (
|
||||
super.validateParam(param)
|
||||
|| isResourceKeyList(param)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export function getCachedMapResourceLoaderState<
|
||||
|
||||
@@ -6,12 +6,14 @@
|
||||
* you may not use this file except in compliance with the License.
|
||||
*/
|
||||
|
||||
import { observable, makeObservable, action, computed } from 'mobx';
|
||||
import { observable, makeObservable, action, computed, toJS } from 'mobx';
|
||||
|
||||
import { Dependency } from '@cloudbeaver/core-di';
|
||||
import { Executor, ExecutorInterrupter, IExecutor, IExecutorHandler, ISyncExecutor, SyncExecutor, TaskScheduler } from '@cloudbeaver/core-executor';
|
||||
import { MetadataMap, uuid } from '@cloudbeaver/core-utils';
|
||||
|
||||
import { isResourceKeyList } from './ResourceKeyList';
|
||||
|
||||
export interface ICachedResourceMetadata {
|
||||
outdated: boolean;
|
||||
loading: boolean;
|
||||
@@ -254,7 +256,7 @@ export abstract class CachedResource<
|
||||
param = map(param) as any as TParam;
|
||||
}
|
||||
|
||||
await resource.load(param as any as T, []);
|
||||
await resource.load(param as any as T);
|
||||
} finally {
|
||||
if (this.logActivity) {
|
||||
console.groupEnd();
|
||||
@@ -475,6 +477,16 @@ export abstract class CachedResource<
|
||||
}
|
||||
|
||||
transformParam(param: TParam): TParam {
|
||||
if (!this.validateParam(param)) {
|
||||
let paramString = JSON.stringify(toJS(param));
|
||||
|
||||
if (typeof param === 'symbol') {
|
||||
paramString = param.toString();
|
||||
} else if (isResourceKeyList(param)) {
|
||||
paramString = param.toString();
|
||||
}
|
||||
console.warn(this.getActionPrefixedName(`wrong param "${paramString}"`));
|
||||
}
|
||||
let deep = 0;
|
||||
// eslint-disable-next-line no-labels
|
||||
transform:
|
||||
@@ -538,6 +550,10 @@ export abstract class CachedResource<
|
||||
}, {});
|
||||
}
|
||||
|
||||
protected validateParam(param: TParam): boolean {
|
||||
return param === CachedResourceParamKey;
|
||||
}
|
||||
|
||||
protected resetIncludes(): void {
|
||||
for (const metadata of this.metadata.values()) {
|
||||
metadata.includes = observable([...this.defaultIncludes]);
|
||||
|
||||
@@ -19,23 +19,26 @@ export type CachedResourceIncludeFlags<TValue, TArgs> = {
|
||||
|
||||
export type CachedResourceIncludeList<TValue> = Array<CachedResourceIncludeTemplate<TValue>>;
|
||||
export type CachedResourceIncludeToKey<TKey> = TKey extends ReadonlyArray<`include${infer T}` | `customInclude${Capitalize<string>}`> ? Uncapitalize<T> : unknown;
|
||||
export type CachedResourceIncludeArgs<TValue, TArguments> = TArguments extends Record<string, never>
|
||||
? string[]
|
||||
: (
|
||||
Array<
|
||||
Exclude<
|
||||
keyof CachedResourceIncludeFlags<Exclude<ExtractElementType<TValue>, undefined | null>, TArguments>,
|
||||
number | symbol
|
||||
>
|
||||
>
|
||||
);
|
||||
export type CachedResourceIncludeArgs<TValue, TArguments> = (
|
||||
TArguments extends Record<string, never>
|
||||
? string[]
|
||||
: (
|
||||
Array<
|
||||
Exclude<
|
||||
keyof CachedResourceIncludeFlags<Exclude<ExtractElementType<TValue>, undefined | null>, TArguments>,
|
||||
number | symbol
|
||||
>
|
||||
>
|
||||
)
|
||||
) | [];
|
||||
|
||||
export type ApplyIncludes<TValue, TKeys> = TValue
|
||||
& ({
|
||||
[P in Extract<CachedResourceIncludeToKey<TKeys>, keyof TValue>]-?: Required<TValue>[P] extends undefined
|
||||
? TValue[P]
|
||||
: NonNullable<TValue[P]>;
|
||||
});
|
||||
export type ApplyIncludes<TValue, TKeys> = TValue extends null | undefined
|
||||
? TValue
|
||||
: TValue & ({
|
||||
[P in Extract<CachedResourceIncludeToKey<TKeys>, keyof TValue>]-?: Required<TValue>[P] extends undefined
|
||||
? TValue[P]
|
||||
: NonNullable<TValue[P]>;
|
||||
});
|
||||
|
||||
export type CachedResourceValueElementIncludes<TValue, TKeys> = TValue extends any
|
||||
? (
|
||||
@@ -49,10 +52,14 @@ export type CachedResourceValueElementIncludes<TValue, TKeys> = TValue extends a
|
||||
|
||||
export type CachedResourceValueIncludes<TValue, TKeys> = TValue extends any
|
||||
? (
|
||||
TValue extends Array<infer TElement>
|
||||
? TElement extends Record<any, any>
|
||||
? Array<ApplyIncludes<TElement, TKeys>>
|
||||
: ApplyIncludes<TValue, TKeys>
|
||||
: ApplyIncludes<TValue, TKeys>
|
||||
TKeys extends []
|
||||
? TValue
|
||||
: (
|
||||
TValue extends Array<infer TElement>
|
||||
? TElement extends Record<any, any>
|
||||
? Array<ApplyIncludes<TElement, TKeys>>
|
||||
: ApplyIncludes<TValue, TKeys>
|
||||
: ApplyIncludes<TValue, TKeys>
|
||||
)
|
||||
)
|
||||
: undefined;
|
||||
|
||||
@@ -31,6 +31,10 @@ export class ResourceKeyList<TKey> {
|
||||
|
||||
return this.list.some(current => isEqual(current, key));
|
||||
}
|
||||
|
||||
toString(): string {
|
||||
return `ResourceKeyList(${this.list.join()})${this.mark !== undefined ? '@' + this.mark : ''}`;
|
||||
}
|
||||
}
|
||||
|
||||
interface MapFnc {
|
||||
|
||||
@@ -15,6 +15,6 @@ export class SideBarPanelService {
|
||||
readonly tabsContainer: TabsContainer;
|
||||
|
||||
constructor() {
|
||||
this.tabsContainer = new TabsContainer();
|
||||
this.tabsContainer = new TabsContainer('Right Side Bar');
|
||||
}
|
||||
}
|
||||
@@ -17,6 +17,7 @@ import { TabDefault } from './Tab/TabDefault';
|
||||
import { TabsContext } from './TabsContext';
|
||||
|
||||
interface Props extends Omit<TabListOptions, keyof TabStateReturn> {
|
||||
'aria-label'?: string;
|
||||
style?: ComponentStyle;
|
||||
childrenFirst?: boolean;
|
||||
}
|
||||
@@ -36,7 +37,7 @@ export const TabList = observer<React.PropsWithChildren<Props>>(function TabList
|
||||
if (state.container) {
|
||||
const displayed = state.container.getDisplayed(state.props);
|
||||
return (
|
||||
<BaseTabList {...props} {...state.state}>
|
||||
<BaseTabList {...props} {...state.state} area-label={props['aria-label'] ?? state.container.areaLabel}>
|
||||
{childrenFirst && children}
|
||||
{displayed.map(generateTabElement(
|
||||
(tabInfo, key) => (
|
||||
@@ -48,6 +49,7 @@ export const TabList = observer<React.PropsWithChildren<Props>>(function TabList
|
||||
component={tabInfo.tab?.()}
|
||||
{...state.props}
|
||||
style={style}
|
||||
aria-label={tabInfo.name}
|
||||
disabled={props.disabled || tabInfo.isDisabled?.(tabInfo.key, state.props)}
|
||||
onOpen={tabInfo.onOpen}
|
||||
onClose={tabInfo.onClose}
|
||||
|
||||
@@ -48,6 +48,7 @@ export interface ITabInfo<
|
||||
}
|
||||
|
||||
export interface ITabsContainer<TProps = void, TOptions extends Record<string, any> = never> {
|
||||
readonly areaLabel: string;
|
||||
readonly tabInfoList: Array<ITabInfo<TProps, TOptions>>;
|
||||
readonly selectedId: string | null;
|
||||
has: (tabId: string) => boolean;
|
||||
|
||||
@@ -14,6 +14,7 @@ import type { ITabInfo, ITabInfoOptions, ITabsContainer } from './ITabsContainer
|
||||
|
||||
export class TabsContainer<TProps = void, TOptions extends Record<string, any> = never>
|
||||
implements ITabsContainer<TProps, TOptions> {
|
||||
readonly areaLabel: string;
|
||||
readonly tabInfoMap: Map<string, ITabInfo<TProps, TOptions>>;
|
||||
|
||||
get tabInfoList(): Array<ITabInfo<TProps, TOptions>> {
|
||||
@@ -27,9 +28,10 @@ implements ITabsContainer<TProps, TOptions> {
|
||||
|
||||
private currentTabId: string | null;
|
||||
|
||||
constructor() {
|
||||
constructor(areaLabel: string) {
|
||||
this.tabInfoMap = new Map();
|
||||
this.currentTabId = null;
|
||||
this.areaLabel = areaLabel;
|
||||
|
||||
makeObservable<TabsContainer<TProps, TOptions>, 'currentTabId'>(this, {
|
||||
tabInfoMap: observable.shallow,
|
||||
|
||||
@@ -8,11 +8,11 @@
|
||||
|
||||
import { action, observable } from 'mobx';
|
||||
import { observer } from 'mobx-react-lite';
|
||||
import { useEffect, useState } from 'react';
|
||||
import { useEffect, useMemo, useState } from 'react';
|
||||
import { useTabState } from 'reakit/Tab';
|
||||
|
||||
import { useExecutor, useObjectRef, useObservableRef } from '@cloudbeaver/core-blocks';
|
||||
import { Executor, ExecutorInterrupter, IExecutorHandler } from '@cloudbeaver/core-executor';
|
||||
import { Executor, ExecutorInterrupter } from '@cloudbeaver/core-executor';
|
||||
import { MetadataMap, MetadataValueGetter } from '@cloudbeaver/core-utils';
|
||||
|
||||
import type { ITabData, ITabsContainer } from './TabsContainer/ITabsContainer';
|
||||
@@ -52,7 +52,7 @@ export const TabsState = observer(function TabsState<T = Record<string, any>>({
|
||||
onClose,
|
||||
...rest
|
||||
}: Props<T>): React.ReactElement | null {
|
||||
const props = rest as any as T;
|
||||
const props = useMemo(() => rest as any as T, [...Object.values(rest)]);
|
||||
let displayed: string[] = [];
|
||||
|
||||
if (container) {
|
||||
|
||||
@@ -10,7 +10,7 @@ import { computed, makeObservable, observable, runInAction } from 'mobx';
|
||||
|
||||
import { injectable } from '@cloudbeaver/core-di';
|
||||
import { ServerConfigResource } from '@cloudbeaver/core-root';
|
||||
import { CachedMapAllKey, CachedMapResource } from '@cloudbeaver/core-sdk';
|
||||
import { CachedMapAllKey, CachedMapResource, ResourceKey } from '@cloudbeaver/core-sdk';
|
||||
|
||||
export interface IVersion {
|
||||
number: string;
|
||||
@@ -85,4 +85,11 @@ export class VersionResource extends CachedMapResource<string, IVersion> {
|
||||
|
||||
return this.data;
|
||||
}
|
||||
|
||||
protected validateParam(param: ResourceKey<string>): boolean {
|
||||
return (
|
||||
super.validateParam(param)
|
||||
|| typeof param === 'string'
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -31,7 +31,9 @@ export function useDynamicDataContext(
|
||||
state.dynamic.flush();
|
||||
});
|
||||
|
||||
capture(state.dynamic);
|
||||
useEffect(() => {
|
||||
capture(state.dynamic);
|
||||
});
|
||||
|
||||
useEffect(() => () => state.dynamic.flush(), []);
|
||||
}
|
||||
|
||||
@@ -9,8 +9,8 @@
|
||||
import { observer } from 'mobx-react-lite';
|
||||
import styled from 'reshadow';
|
||||
|
||||
import { usePermission } from '@cloudbeaver/core-blocks';
|
||||
import { EPermission } from '@cloudbeaver/core-root';
|
||||
import { AppAuthService } from '@cloudbeaver/core-authentication';
|
||||
import { useService } from '@cloudbeaver/core-di';
|
||||
import { MenuBar } from '@cloudbeaver/core-ui';
|
||||
import { useMenu } from '@cloudbeaver/core-view';
|
||||
import { MENU_BAR_DISABLE_EFFECT_STYLES, MENU_BAR_ITEM_STYLES, MENU_BAR_STYLES, topMenuStyles } from '@cloudbeaver/plugin-top-app-bar';
|
||||
@@ -19,9 +19,9 @@ import { MENU_APP_ADMINISTRATION_ACTIONS } from './MENU_APP_ADMINISTRATION_ACTIO
|
||||
|
||||
export const AdministrationMenu = observer(function AdministrationMenu() {
|
||||
const menu = useMenu({ menu: MENU_APP_ADMINISTRATION_ACTIONS });
|
||||
const isEnabled = usePermission(EPermission.public);
|
||||
const { authenticated } = useService(AppAuthService);
|
||||
|
||||
if (!isEnabled) {
|
||||
if (!authenticated) {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
+1
-2
@@ -14,7 +14,6 @@ import { AdministrationSettingsService } from '@cloudbeaver/core-administration'
|
||||
import { BASE_CONTAINERS_STYLES, FormContext, GroupTitle, Loader, PlaceholderComponent, Switch, useResource, useTranslate, useStyles } from '@cloudbeaver/core-blocks';
|
||||
import { useService } from '@cloudbeaver/core-di';
|
||||
import { FeaturesResource } from '@cloudbeaver/core-root';
|
||||
import { CachedMapAllKey } from '@cloudbeaver/core-sdk';
|
||||
import type { IConfigurationPlaceholderProps } from '@cloudbeaver/plugin-administration';
|
||||
|
||||
export const ServerConfigurationFeaturesForm: PlaceholderComponent<IConfigurationPlaceholderProps> = observer(function ServerConfigurationFeaturesForm({
|
||||
@@ -22,7 +21,7 @@ export const ServerConfigurationFeaturesForm: PlaceholderComponent<IConfiguratio
|
||||
configurationWizard,
|
||||
}) {
|
||||
const administrationSettingsService = useService(AdministrationSettingsService);
|
||||
const features = useResource(ServerConfigurationFeaturesForm, FeaturesResource, CachedMapAllKey);
|
||||
const features = useResource(ServerConfigurationFeaturesForm, FeaturesResource, undefined);
|
||||
const translate = useTranslate();
|
||||
const styles = useStyles(BASE_CONTAINERS_STYLES);
|
||||
const formContext = useContext(FormContext);
|
||||
|
||||
+1
-1
@@ -177,7 +177,7 @@ export class ServerConfigurationService {
|
||||
data.state.serverConfig.serverName = config.name || config.productInfo.name;
|
||||
data.state.serverConfig.serverURL = config.serverURL;
|
||||
|
||||
if (this.serverConfigResource.configurationMode) {
|
||||
if (this.administrationScreenService.isConfigurationMode) {
|
||||
data.state.serverConfig.serverURL = window.location.origin;
|
||||
}
|
||||
|
||||
|
||||
+4
-4
@@ -6,11 +6,11 @@
|
||||
* you may not use this file except in compliance with the License.
|
||||
*/
|
||||
|
||||
import { TabsContainer } from '@cloudbeaver/core-ui';
|
||||
import { PlaceholderContainer } from '@cloudbeaver/core-blocks';
|
||||
import { injectable } from '@cloudbeaver/core-di';
|
||||
import { ENotificationType, NotificationService } from '@cloudbeaver/core-events';
|
||||
import { ExecutorHandlersCollection, ExecutorInterrupter, IExecutorHandler, IExecutorHandlersCollection } from '@cloudbeaver/core-executor';
|
||||
import { TabsContainer } from '@cloudbeaver/core-ui';
|
||||
|
||||
import { AuthConfigurationFormBaseActions } from './AuthConfigurationFormBaseActions';
|
||||
import type { IAuthConfigurationFormFillConfigData, IAuthConfigurationFormProps, IAuthConfigurationFormSubmitData, IAuthConfigurationFormState } from './IAuthConfigurationFormProps';
|
||||
@@ -45,7 +45,7 @@ export class AuthConfigurationFormService {
|
||||
constructor(
|
||||
private readonly notificationService: NotificationService,
|
||||
) {
|
||||
this.tabsContainer = new TabsContainer();
|
||||
this.tabsContainer = new TabsContainer('Identity Provider settings');
|
||||
this.actionsContainer = new PlaceholderContainer();
|
||||
this.configureTask = new ExecutorHandlersCollection();
|
||||
this.fillConfigTask = new ExecutorHandlersCollection();
|
||||
@@ -93,7 +93,7 @@ export class AuthConfigurationFormService {
|
||||
},
|
||||
});
|
||||
|
||||
private showSubmittingStatusMessage: IExecutorHandler<IAuthConfigurationFormSubmitData> = (data, contexts) => {
|
||||
private readonly showSubmittingStatusMessage: IExecutorHandler<IAuthConfigurationFormSubmitData> = (data, contexts) => {
|
||||
const status = contexts.getContext(this.configurationStatusContext);
|
||||
|
||||
if (!status.saved) {
|
||||
@@ -116,7 +116,7 @@ export class AuthConfigurationFormService {
|
||||
}
|
||||
};
|
||||
|
||||
private ensureValidation: IExecutorHandler<IAuthConfigurationFormSubmitData> = (data, contexts) => {
|
||||
private readonly ensureValidation: IExecutorHandler<IAuthConfigurationFormSubmitData> = (data, contexts) => {
|
||||
const validation = contexts.getContext(this.configurationValidationContext);
|
||||
|
||||
if (!validation.valid) {
|
||||
|
||||
+3
-1
@@ -6,6 +6,7 @@
|
||||
* you may not use this file except in compliance with the License.
|
||||
*/
|
||||
|
||||
import { AdministrationScreenService } from '@cloudbeaver/core-administration';
|
||||
import { AuthProvidersResource, AUTH_PROVIDER_LOCAL_ID } from '@cloudbeaver/core-authentication';
|
||||
import { Bootstrap, injectable } from '@cloudbeaver/core-di';
|
||||
import { NotificationService } from '@cloudbeaver/core-events';
|
||||
@@ -16,6 +17,7 @@ import { ILoadConfigData, IServerConfigSaveData, ServerConfigurationService, ser
|
||||
@injectable()
|
||||
export class ServerConfigurationAuthenticationBootstrap extends Bootstrap {
|
||||
constructor(
|
||||
private readonly administrationScreenService: AdministrationScreenService,
|
||||
private readonly serverConfigurationService: ServerConfigurationService,
|
||||
private readonly authProvidersResource: AuthProvidersResource,
|
||||
private readonly serverConfigResource: ServerConfigResource,
|
||||
@@ -43,7 +45,7 @@ export class ServerConfigurationAuthenticationBootstrap extends Bootstrap {
|
||||
return;
|
||||
}
|
||||
|
||||
if (config.configurationMode) {
|
||||
if (this.administrationScreenService.isConfigurationMode) {
|
||||
await this.authProvidersResource.loadAll();
|
||||
if (this.authProvidersResource.has(AUTH_PROVIDER_LOCAL_ID)) {
|
||||
data.state.serverConfig.adminName = 'cbadmin';
|
||||
|
||||
+1
-1
@@ -46,7 +46,7 @@ export class TeamFormService {
|
||||
constructor(
|
||||
private readonly notificationService: NotificationService,
|
||||
) {
|
||||
this.tabsContainer = new TabsContainer();
|
||||
this.tabsContainer = new TabsContainer('Team settings');
|
||||
this.actionsContainer = new PlaceholderContainer();
|
||||
this.configureTask = new ExecutorHandlersCollection();
|
||||
this.fillConfigTask = new ExecutorHandlersCollection();
|
||||
|
||||
+1
-1
@@ -33,7 +33,7 @@ export class UserFormService {
|
||||
readonly tabsContainer: TabsContainer<IUserFormProps>;
|
||||
|
||||
constructor() {
|
||||
this.tabsContainer = new TabsContainer();
|
||||
this.tabsContainer = new TabsContainer('User settings');
|
||||
this.onFormInit = new Executor();
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -59,7 +59,7 @@ export const UsersAdministration: AdministrationItemContentComponent = observer(
|
||||
return styled(style)(
|
||||
<TabsState selectedId={subName} lazy onChange={openSub}>
|
||||
<ToolsPanel>
|
||||
<TabList style={style}>
|
||||
<TabList aria-label='User Administration pages' style={style}>
|
||||
<Tab tabId={EUsersAdministrationSub.Users} style={style}>{translate('authentication_administration_item_users')}</Tab>
|
||||
<Tab tabId={EUsersAdministrationSub.Teams} style={style}>{translate('administration_teams_tab_title')}</Tab>
|
||||
{/* <Tab
|
||||
|
||||
@@ -188,7 +188,7 @@ export class AuthenticationService extends Bootstrap {
|
||||
this.screenService.routeChange.addHandler(() => this.requireAuthentication());
|
||||
|
||||
this.administrationScreenService.ensurePermissions.addHandler(async () => {
|
||||
const userInfo = await this.userInfoResource.load(undefined, []);
|
||||
const userInfo = await this.userInfoResource.load();
|
||||
if (userInfo) {
|
||||
return;
|
||||
}
|
||||
@@ -224,7 +224,7 @@ export class AuthenticationService extends Bootstrap {
|
||||
}
|
||||
|
||||
await this.authProvidersResource.loadAll();
|
||||
await this.userInfoResource.load(undefined, []);
|
||||
await this.userInfoResource.load();
|
||||
|
||||
if (!this.authProvidersResource.has(data.providerId)) {
|
||||
return;
|
||||
|
||||
@@ -6,10 +6,11 @@
|
||||
* you may not use this file except in compliance with the License.
|
||||
*/
|
||||
|
||||
import { AppAuthService } from '@cloudbeaver/core-authentication';
|
||||
import { Bootstrap, injectable } from '@cloudbeaver/core-di';
|
||||
import { CommonDialogService } from '@cloudbeaver/core-dialogs';
|
||||
import { ProjectInfoResource, ProjectsService } from '@cloudbeaver/core-projects';
|
||||
import { PermissionsService, EPermission } from '@cloudbeaver/core-root';
|
||||
import { PermissionsService } from '@cloudbeaver/core-root';
|
||||
import { CachedMapAllKey, getCachedDataResourceLoaderState, getCachedMapResourceLoaderState } from '@cloudbeaver/core-sdk';
|
||||
import { MenuService, ActionService, DATA_CONTEXT_MENU, DATA_CONTEXT_LOADABLE_STATE } from '@cloudbeaver/core-view';
|
||||
import { MENU_CONNECTIONS } from '@cloudbeaver/plugin-connections';
|
||||
@@ -22,6 +23,7 @@ import { TemplateConnectionsService } from './TemplateConnectionsService';
|
||||
@injectable()
|
||||
export class TemplateConnectionPluginBootstrap extends Bootstrap {
|
||||
constructor(
|
||||
private readonly appAuthService: AppAuthService,
|
||||
private readonly menuService: MenuService,
|
||||
private readonly actionService: ActionService,
|
||||
private readonly projectInfoResource: ProjectInfoResource,
|
||||
@@ -49,7 +51,7 @@ export class TemplateConnectionPluginBootstrap extends Bootstrap {
|
||||
ACTION_CONNECTION_TEMPLATE,
|
||||
].includes(action),
|
||||
isHidden: () => (
|
||||
!this.permissionsService.has(EPermission.public)
|
||||
!this.appAuthService.authenticated
|
||||
|| !this.projectsService.userProject?.canEditDataSources
|
||||
|| !this.templateConnectionsService.projectTemplates.length
|
||||
),
|
||||
@@ -59,6 +61,7 @@ export class TemplateConnectionPluginBootstrap extends Bootstrap {
|
||||
return state.getState(
|
||||
action.id,
|
||||
() => [
|
||||
...this.appAuthService.loaders,
|
||||
getCachedMapResourceLoaderState(this.projectInfoResource, CachedMapAllKey),
|
||||
getCachedDataResourceLoaderState(this.templateConnectionsResource, undefined, undefined),
|
||||
]
|
||||
|
||||
@@ -6,9 +6,10 @@
|
||||
* you may not use this file except in compliance with the License.
|
||||
*/
|
||||
|
||||
import { AppAuthService } from '@cloudbeaver/core-authentication';
|
||||
import { Connection, ConnectionInfoResource } from '@cloudbeaver/core-connections';
|
||||
import { injectable } from '@cloudbeaver/core-di';
|
||||
import { EPermission, SessionDataResource, SessionPermissionsResource } from '@cloudbeaver/core-root';
|
||||
import { SessionDataResource } from '@cloudbeaver/core-root';
|
||||
import { GraphQLService, CachedDataResource, ResourceKeyUtils } from '@cloudbeaver/core-sdk';
|
||||
|
||||
@injectable()
|
||||
@@ -17,15 +18,13 @@ export class TemplateConnectionsResource extends CachedDataResource<Connection[]
|
||||
private readonly graphQLService: GraphQLService,
|
||||
connectionInfoResource: ConnectionInfoResource,
|
||||
sessionDataResource:SessionDataResource,
|
||||
permissionsResource: SessionPermissionsResource,
|
||||
appAuthService: AppAuthService,
|
||||
) {
|
||||
super([]);
|
||||
|
||||
this.sync(sessionDataResource);
|
||||
|
||||
permissionsResource
|
||||
.require(this, EPermission.public)
|
||||
.outdateResource(this);
|
||||
appAuthService.requireAuthentication(this);
|
||||
|
||||
connectionInfoResource.onConnectionCreate.addHandler(connection => {
|
||||
if (connection.template) {
|
||||
|
||||
+1
-1
@@ -41,7 +41,7 @@ export class CreateConnectionService {
|
||||
private readonly projectInfoResource: ProjectInfoResource
|
||||
) {
|
||||
this.data = null;
|
||||
this.tabsContainer = new TabsContainer();
|
||||
this.tabsContainer = new TabsContainer('Connection Creation mode');
|
||||
|
||||
this.setConnectionTemplate = this.setConnectionTemplate.bind(this);
|
||||
this.clearConnectionTemplate = this.clearConnectionTemplate.bind(this);
|
||||
|
||||
@@ -52,7 +52,7 @@ export class ConnectionFormService {
|
||||
private readonly notificationService: NotificationService,
|
||||
private readonly commonDialogService: CommonDialogService,
|
||||
) {
|
||||
this.tabsContainer = new TabsContainer();
|
||||
this.tabsContainer = new TabsContainer('Connection settings');
|
||||
this.actionsContainer = new PlaceholderContainer();
|
||||
this.configureTask = new ExecutorHandlersCollection();
|
||||
this.fillConfigTask = new ExecutorHandlersCollection();
|
||||
|
||||
+1
-1
@@ -344,7 +344,7 @@ export class ConnectionOptionsTabService extends Bootstrap {
|
||||
|
||||
const providerId = authModel.requiredAuth ?? data.info?.requiredAuth ?? AUTH_PROVIDER_LOCAL_ID;
|
||||
|
||||
await this.userInfoResource.load(undefined, []);
|
||||
await this.userInfoResource.load();
|
||||
|
||||
if (!this.userInfoResource.hasToken(providerId)) {
|
||||
const provider = await this.authProvidersResource.load(providerId);
|
||||
|
||||
+2
-2
@@ -35,8 +35,8 @@ export function connectionFormConfigureContext(
|
||||
connectionIncludes: [],
|
||||
include(...includes) {
|
||||
for (const include of includes) {
|
||||
if (!this.connectionIncludes.includes(include)) {
|
||||
this.connectionIncludes.push(include);
|
||||
if (!this.connectionIncludes.includes(include as never)) {
|
||||
this.connectionIncludes.push(include as never);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
@@ -10,7 +10,7 @@ import { injectable } from '@cloudbeaver/core-di';
|
||||
import { GraphQLService, CachedDataResource, DataTransferProcessorInfo } from '@cloudbeaver/core-sdk';
|
||||
|
||||
@injectable()
|
||||
export class DataTransferProcessorsResource extends CachedDataResource<Map<string, DataTransferProcessorInfo>, void> {
|
||||
export class DataTransferProcessorsResource extends CachedDataResource<Map<string, DataTransferProcessorInfo>> {
|
||||
constructor(
|
||||
private readonly graphQLService: GraphQLService
|
||||
) {
|
||||
|
||||
@@ -116,7 +116,7 @@ export const ProcessorConfigureDialog = observer<Props>(function ProcessorConfig
|
||||
>
|
||||
{!processor.isBinary ? (
|
||||
<TabsState currentTabId={currentTabId} onChange={handleTabChange}>
|
||||
<TabList>
|
||||
<TabList aria-label='Export Settings tabs'>
|
||||
<Tab tabId={SETTINGS_TABS.EXTRACTION} style={UNDERLINE_TAB_STYLES}>
|
||||
{translate('data_transfer_format_settings')}
|
||||
</Tab>
|
||||
|
||||
+1
-1
@@ -89,7 +89,7 @@ export const TablePresentationBar = observer<Props>(function TablePresentationBa
|
||||
return styled(style)(
|
||||
<table-left-bar className={className}>
|
||||
<TabsState currentTabId={presentationId} autoSelect={main}>
|
||||
<TabList {...use({ flexible: main })}>
|
||||
<TabList aria-label='Data Presentations' {...use({ flexible: main })}>
|
||||
{presentations.map(presentation => (
|
||||
<Tab
|
||||
key={presentation.id}
|
||||
|
||||
+1
-1
@@ -28,7 +28,7 @@ export class DataValuePanelService {
|
||||
readonly tabs: TabsContainer<IDataValuePanelProps<any>, IDataValuePanelOptions>;
|
||||
|
||||
constructor() {
|
||||
this.tabs = new TabsContainer();
|
||||
this.tabs = new TabsContainer('Value Panel');
|
||||
}
|
||||
|
||||
get(tabId: string): ITabInfo<IDataValuePanelProps<any>, IDataValuePanelOptions> | undefined {
|
||||
|
||||
+2
-2
@@ -6,15 +6,15 @@
|
||||
* you may not use this file except in compliance with the License.
|
||||
*/
|
||||
|
||||
import { ITabInfo, ITabInfoOptions, TabsContainer } from '@cloudbeaver/core-ui';
|
||||
import { injectable } from '@cloudbeaver/core-di';
|
||||
import { ITabInfo, ITabInfoOptions, TabsContainer } from '@cloudbeaver/core-ui';
|
||||
|
||||
@injectable()
|
||||
export class TextValuePresentationService {
|
||||
readonly tabs: TabsContainer;
|
||||
|
||||
constructor() {
|
||||
this.tabs = new TabsContainer();
|
||||
this.tabs = new TabsContainer('Value presentation');
|
||||
}
|
||||
|
||||
get(tabId: string): ITabInfo | undefined {
|
||||
|
||||
+23
-8
@@ -6,10 +6,10 @@
|
||||
* you may not use this file except in compliance with the License.
|
||||
*/
|
||||
|
||||
import { AppAuthService } from '@cloudbeaver/core-authentication';
|
||||
import { compareConnectionsInfo, ConnectionInfoResource, ConnectionsManagerService, ContainerResource, createConnectionParam, serializeConnectionParam } from '@cloudbeaver/core-connections';
|
||||
import { Bootstrap, injectable } from '@cloudbeaver/core-di';
|
||||
import { EObjectFeature, NodeManagerUtils } from '@cloudbeaver/core-navigation-tree';
|
||||
import { EPermission, PermissionsService } from '@cloudbeaver/core-root';
|
||||
import { getCachedDataResourceLoaderState } from '@cloudbeaver/core-sdk';
|
||||
import { OptionsPanelService } from '@cloudbeaver/core-ui';
|
||||
import { DATA_CONTEXT_LOADABLE_STATE, DATA_CONTEXT_MENU, MenuBaseItem, menuExtractItems, MenuSeparatorItem, MenuService } from '@cloudbeaver/core-view';
|
||||
@@ -36,7 +36,7 @@ export class ConnectionSchemaManagerBootstrap extends Bootstrap {
|
||||
private readonly connectionSchemaManagerService: ConnectionSchemaManagerService,
|
||||
private readonly connectionsManagerService: ConnectionsManagerService,
|
||||
private readonly optionsPanelService: OptionsPanelService,
|
||||
private readonly permissionsService: PermissionsService,
|
||||
private readonly appAuthService: AppAuthService,
|
||||
private readonly containerResource: ContainerResource,
|
||||
private readonly menuService: MenuService
|
||||
) {
|
||||
@@ -53,7 +53,7 @@ export class ConnectionSchemaManagerBootstrap extends Bootstrap {
|
||||
id: 'connection-selector-base',
|
||||
isApplicable: context => context.hasValue(DATA_CONTEXT_MENU, MENU_CONNECTION_SELECTOR),
|
||||
isLoading: () => this.connectionSelectorLoading,
|
||||
isHidden: () => this.isHidden(),
|
||||
isHidden: () => this.isHidden() || !this.appAuthService.authenticated,
|
||||
isDisabled: () => (
|
||||
!this.connectionSchemaManagerService.isConnectionChangeable
|
||||
|| this.connectionSelectorLoading
|
||||
@@ -80,10 +80,13 @@ export class ConnectionSchemaManagerBootstrap extends Bootstrap {
|
||||
|
||||
return state.getState(
|
||||
menu.id,
|
||||
() => getCachedDataResourceLoaderState(this.containerResource, {
|
||||
...this.connectionSchemaManagerService.activeConnectionKey!,
|
||||
catalogId: this.connectionSchemaManagerService.activeObjectCatalogId,
|
||||
}, undefined)
|
||||
() => [
|
||||
...this.appAuthService.loaders,
|
||||
getCachedDataResourceLoaderState(this.containerResource, {
|
||||
...this.connectionSchemaManagerService.activeConnectionKey!,
|
||||
catalogId: this.connectionSchemaManagerService.activeObjectCatalogId,
|
||||
}, undefined),
|
||||
]
|
||||
);
|
||||
},
|
||||
});
|
||||
@@ -166,6 +169,7 @@ export class ConnectionSchemaManagerBootstrap extends Bootstrap {
|
||||
),
|
||||
isHidden: () => (
|
||||
this.isHidden()
|
||||
|| !this.appAuthService.authenticated
|
||||
|| !this.connectionSchemaManagerService.objectContainerList
|
||||
|| (
|
||||
this.connectionSchemaManagerService.currentObjectSchemaId === undefined
|
||||
@@ -178,6 +182,18 @@ export class ConnectionSchemaManagerBootstrap extends Bootstrap {
|
||||
&& this.connectionSchemaManagerService.objectContainerList.catalogList.length === 0
|
||||
)
|
||||
),
|
||||
getLoader: (context, menu) => {
|
||||
if (this.isHidden()) {
|
||||
return [];
|
||||
}
|
||||
|
||||
const state = context.get(DATA_CONTEXT_LOADABLE_STATE);
|
||||
|
||||
return state.getState(
|
||||
menu.id,
|
||||
() => this.appAuthService.loaders
|
||||
);
|
||||
},
|
||||
getInfo: (context, menu) => {
|
||||
const connectionSchemaManagerService = this.connectionSchemaManagerService;
|
||||
|
||||
@@ -375,7 +391,6 @@ export class ConnectionSchemaManagerBootstrap extends Bootstrap {
|
||||
!this.connectionSchemaManagerService.isConnectionChangeable
|
||||
&& !this.connectionSchemaManagerService.currentConnectionKey
|
||||
)
|
||||
|| !this.permissionsService.has(EPermission.public)
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
+3
-3
@@ -37,7 +37,7 @@ interface Props extends IConnectionSelectorExtraProps {
|
||||
className?: string;
|
||||
}
|
||||
|
||||
export const ConnectionIcon: React.FC<Props> = observer(function ConnectionInfo({
|
||||
export const ConnectionIcon: React.FC<Props> = observer(function ConnectionIcon({
|
||||
connectionKey,
|
||||
small,
|
||||
style,
|
||||
@@ -46,13 +46,13 @@ export const ConnectionIcon: React.FC<Props> = observer(function ConnectionInfo(
|
||||
const styles = useStyles(style, connectionIconStyle);
|
||||
|
||||
const connection = useResource(
|
||||
ConnectionInfo,
|
||||
ConnectionIcon,
|
||||
ConnectionInfoResource,
|
||||
connectionKey ?? null
|
||||
);
|
||||
const driverId = connection.data?.driverId;
|
||||
|
||||
const driver = useResource(ConnectionInfo, DBDriverResource, driverId!, {
|
||||
const driver = useResource(ConnectionIcon, DBDriverResource, driverId!, {
|
||||
active: driverId !== undefined,
|
||||
});
|
||||
|
||||
|
||||
@@ -9,8 +9,9 @@
|
||||
import { runInAction } from 'mobx';
|
||||
|
||||
import { CoreSettingsService } from '@cloudbeaver/core-app';
|
||||
import { AppAuthService } from '@cloudbeaver/core-authentication';
|
||||
import { injectable } from '@cloudbeaver/core-di';
|
||||
import { EPermission, ServerEventId, SessionDataResource, SessionPermissionsResource } from '@cloudbeaver/core-root';
|
||||
import { ServerEventId, SessionDataResource } from '@cloudbeaver/core-root';
|
||||
import { GraphQLService, CachedDataResource, LogEntry } from '@cloudbeaver/core-sdk';
|
||||
import { uuid } from '@cloudbeaver/core-utils';
|
||||
|
||||
@@ -29,7 +30,7 @@ export class SessionLogsResource extends CachedDataResource<ILogEntry[]> {
|
||||
private readonly coreSettingsService: CoreSettingsService,
|
||||
private readonly logViewerSettingsService: LogViewerSettingsService,
|
||||
sessionDataResource: SessionDataResource,
|
||||
permissionsResource: SessionPermissionsResource,
|
||||
appAuthService: AppAuthService,
|
||||
sessionLogsEventHandler: SessionLogsEventHandler,
|
||||
) {
|
||||
super([]);
|
||||
@@ -38,7 +39,7 @@ export class SessionLogsResource extends CachedDataResource<ILogEntry[]> {
|
||||
this.clear();
|
||||
});
|
||||
|
||||
permissionsResource.require(this, EPermission.public);
|
||||
appAuthService.requireAuthentication(this);
|
||||
|
||||
sessionLogsEventHandler.onEvent(ServerEventId.CbSessionLogUpdated, () => {
|
||||
this.markOutdated();
|
||||
|
||||
+4
-3
@@ -132,6 +132,9 @@ export function useElementsTree(options: IOptions): IElementsTree {
|
||||
})));
|
||||
|
||||
options = useObjectRef(options);
|
||||
options.renderers = useMemo(() => options.renderers || [], [...(options.renderers || [])]);
|
||||
options.filters = useMemo(() => options.filters || [], [...(options.filters || [])]);
|
||||
options.expandStateGetters = useMemo(() => options.expandStateGetters || [], [...(options.expandStateGetters || [])]);
|
||||
const state = options.localState || localTreeNodesState;
|
||||
|
||||
const functionsRef = useObjectRef({
|
||||
@@ -297,8 +300,6 @@ export function useElementsTree(options: IOptions): IElementsTree {
|
||||
)
|
||||
);
|
||||
|
||||
const renderers = useMemo(() => options.renderers || [], [options.renderers]);
|
||||
|
||||
const elementsTree = useObservableRef<IElementsTree>(() => ({
|
||||
actions: new SyncExecutor(),
|
||||
state,
|
||||
@@ -548,7 +549,7 @@ export function useElementsTree(options: IOptions): IElementsTree {
|
||||
root: options.root,
|
||||
settings: options.settings,
|
||||
baseRoot: options.baseRoot,
|
||||
renderers,
|
||||
renderers: options.renderers,
|
||||
userData,
|
||||
}, ['isLoading', 'isLoaded']);
|
||||
|
||||
|
||||
@@ -10,11 +10,11 @@ import { observer } from 'mobx-react-lite';
|
||||
import { useMemo } from 'react';
|
||||
import styled, { css } from 'reshadow';
|
||||
|
||||
import { Translate, usePermission, useUserData } from '@cloudbeaver/core-blocks';
|
||||
import { AppAuthService } from '@cloudbeaver/core-authentication';
|
||||
import { Translate, useUserData } from '@cloudbeaver/core-blocks';
|
||||
import { useService } from '@cloudbeaver/core-di';
|
||||
import { NavNodeInfoResource, NavTreeResource, ProjectsNavNodeService, ROOT_NODE_PATH } from '@cloudbeaver/core-navigation-tree';
|
||||
import { ProjectsService } from '@cloudbeaver/core-projects';
|
||||
import { EPermission } from '@cloudbeaver/core-root';
|
||||
import { CaptureView } from '@cloudbeaver/core-view';
|
||||
|
||||
import { NavNodeViewService } from '../NodesManager/NavNodeView/NavNodeViewService';
|
||||
@@ -84,7 +84,7 @@ export const NavigationTree = observer(function NavigationTree() {
|
||||
const navNodeViewService = useService(NavNodeViewService);
|
||||
|
||||
const root = ROOT_NODE_PATH;
|
||||
const isEnabled = usePermission(EPermission.public);
|
||||
const { authenticated } = useService(AppAuthService);
|
||||
const { handleOpen, handleSelect, handleSelectReset } = useNavigationTree();
|
||||
|
||||
const connectionGroupFilter = useMemo(() => navigationTreeConnectionGroupFilter(
|
||||
@@ -114,7 +114,7 @@ export const NavigationTree = observer(function NavigationTree() {
|
||||
|
||||
const settingsElements = useMemo(() => ([ProjectsSettingsPlaceholderElement]), []);
|
||||
|
||||
if (!isEnabled) {
|
||||
if (!authenticated) {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -44,7 +44,7 @@ export class SessionExpireWarningDialogService extends Bootstrap {
|
||||
private startSessionPolling() {
|
||||
const checkSessionStatus = async () => {
|
||||
if (
|
||||
!this.serverConfigResource.data?.anonymousAccessEnabled
|
||||
!this.serverConfigResource.anonymousAccessEnabled
|
||||
&& !this.userInfoResource.data
|
||||
&& !this.serverConfigResource.configurationMode
|
||||
) {
|
||||
|
||||
+10
-1
@@ -8,7 +8,7 @@
|
||||
|
||||
import { action, computed, makeObservable, observable, runInAction, toJS } from 'mobx';
|
||||
|
||||
import { IConnectionExecutionContextInfo, NOT_INITIALIZED_CONTEXT_ID } from '@cloudbeaver/core-connections';
|
||||
import { ConnectionInfoResource, createConnectionParam, IConnectionExecutionContextInfo, NOT_INITIALIZED_CONTEXT_ID } from '@cloudbeaver/core-connections';
|
||||
import { TaskScheduler } from '@cloudbeaver/core-executor';
|
||||
import { IResourceManagerParams, isResourceManagerParamEqual, ResourceManagerResource } from '@cloudbeaver/core-resource-manager';
|
||||
import { ResourceKey, ResourceKeyUtils } from '@cloudbeaver/core-sdk';
|
||||
@@ -70,6 +70,14 @@ export class ResourceSqlDataSource extends BaseSqlDataSource {
|
||||
}
|
||||
|
||||
get executionContext(): IConnectionExecutionContextInfo | undefined {
|
||||
if (
|
||||
this.state.executionContext
|
||||
&& !this.connectionInfoResource.has(createConnectionParam(
|
||||
this.state.executionContext.projectId,
|
||||
this.state.executionContext.connectionId
|
||||
))) {
|
||||
return undefined;
|
||||
}
|
||||
return this.state.executionContext;
|
||||
}
|
||||
|
||||
@@ -102,6 +110,7 @@ export class ResourceSqlDataSource extends BaseSqlDataSource {
|
||||
private resourceUseKeyId: string | null;
|
||||
|
||||
constructor(
|
||||
private readonly connectionInfoResource: ConnectionInfoResource,
|
||||
private readonly resourceManagerResource: ResourceManagerResource,
|
||||
state: IResourceSqlDataSourceState
|
||||
) {
|
||||
|
||||
+3
@@ -8,6 +8,7 @@
|
||||
|
||||
import { action, makeObservable, observable, untracked } from 'mobx';
|
||||
|
||||
import { ConnectionInfoResource } from '@cloudbeaver/core-connections';
|
||||
import { Bootstrap, injectable } from '@cloudbeaver/core-di';
|
||||
import { CommonDialogService, ConfirmationDialog, DialogueStateResult } from '@cloudbeaver/core-dialogs';
|
||||
import { NotificationService } from '@cloudbeaver/core-events';
|
||||
@@ -34,6 +35,7 @@ export class ResourceSqlDataSourceBootstrap extends Bootstrap {
|
||||
private readonly dataSourceStateState = new Map<string, IResourceSqlDataSourceState>();
|
||||
|
||||
constructor(
|
||||
private readonly connectionInfoResource: ConnectionInfoResource,
|
||||
private readonly networkStateService: NetworkStateService,
|
||||
private readonly sqlDataSourceService: SqlDataSourceService,
|
||||
private readonly commonDialogService: CommonDialogService,
|
||||
@@ -90,6 +92,7 @@ export class ResourceSqlDataSourceBootstrap extends Bootstrap {
|
||||
key: ResourceSqlDataSource.key,
|
||||
getDataSource: (editorId, options) => {
|
||||
const dataSource = new ResourceSqlDataSource(
|
||||
this.connectionInfoResource,
|
||||
this.resourceManagerResource,
|
||||
this.createState(
|
||||
editorId,
|
||||
|
||||
@@ -175,13 +175,20 @@ export class SqlEditorTabService extends Bootstrap {
|
||||
}
|
||||
|
||||
const { projectId, connectionId, defaultCatalog, defaultSchema } = dataSource.executionContext;
|
||||
const connectionKey = createConnectionParam(projectId, connectionId);
|
||||
|
||||
const connection = this.connectionInfoResource.get(connectionKey);
|
||||
|
||||
if (!connection?.connected) {
|
||||
return;
|
||||
}
|
||||
|
||||
let catalogData: ICatalogData | undefined;
|
||||
let schema: NavNodeInfoFragment | undefined;
|
||||
|
||||
if (defaultCatalog) {
|
||||
catalogData = this.containerResource.getCatalogData(
|
||||
createConnectionParam(projectId, connectionId),
|
||||
connectionKey,
|
||||
defaultCatalog
|
||||
);
|
||||
}
|
||||
@@ -196,12 +203,6 @@ export class SqlEditorTabService extends Bootstrap {
|
||||
nodeId = NodeManagerUtils.connectionIdToConnectionNodeId(connectionId);
|
||||
}
|
||||
|
||||
const connection = this.connectionInfoResource.getConnectionForNode(nodeId);
|
||||
|
||||
if (connection?.connected === false) {
|
||||
return;
|
||||
}
|
||||
|
||||
const parents = this.navNodeInfoResource.getParents(nodeId);
|
||||
|
||||
untracked(() => this.navNodeInfoResource.load(nodeId!));
|
||||
|
||||
@@ -22,6 +22,6 @@ export class SqlEditorModeService {
|
||||
readonly tabsContainer: TabsContainer<ISqlEditorModeProps>;
|
||||
|
||||
constructor() {
|
||||
this.tabsContainer = new TabsContainer();
|
||||
this.tabsContainer = new TabsContainer('SQL Editor Mode');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -57,4 +57,11 @@ export class SqlGeneratorsResource extends CachedMapResource<string, SqlQueryGen
|
||||
this.set(resourceKeyList(Array.from(values.keys())), Array.from(values.values()));
|
||||
return this.data;
|
||||
}
|
||||
|
||||
protected validateParam(param: ResourceKey<string>): boolean {
|
||||
return (
|
||||
super.validateParam(param)
|
||||
|| typeof param === 'string'
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -99,7 +99,7 @@ export const SqlResultTabs = observer<Props>(function SqlDataResult({ state, onT
|
||||
onChange={handleSelect}
|
||||
onClose={handleClose}
|
||||
>
|
||||
<TabList style={styles}>
|
||||
<TabList aria-label='SQL Results' style={styles}>
|
||||
{orderedTabs.map(result => (
|
||||
<SqlResultTab
|
||||
key={result.id}
|
||||
|
||||
@@ -12,7 +12,7 @@ import { useRef } from 'react';
|
||||
import styled, { css } from 'reshadow';
|
||||
|
||||
import { useStyles, useUserData } from '@cloudbeaver/core-blocks';
|
||||
import { BASE_TAB_STYLES, ITabData, TabList, TabPanelList, TabsContainer, TabsState, UNDERLINE_TAB_STYLES } from '@cloudbeaver/core-ui';
|
||||
import { BASE_TAB_STYLES, ITabData, ITabsContainer, TabList, TabPanelList, TabsContainer, TabsState, UNDERLINE_TAB_STYLES } from '@cloudbeaver/core-ui';
|
||||
import { isArraysEqual } from '@cloudbeaver/core-utils';
|
||||
|
||||
const tabsStyles = css`
|
||||
@@ -54,7 +54,7 @@ const formStyles = css`
|
||||
`;
|
||||
|
||||
interface Props {
|
||||
container: TabsContainer;
|
||||
container: ITabsContainer;
|
||||
}
|
||||
|
||||
interface IToolsState {
|
||||
|
||||
@@ -14,6 +14,6 @@ export class ToolsPanelService {
|
||||
readonly tabsContainer: TabsContainer;
|
||||
|
||||
constructor() {
|
||||
this.tabsContainer = new TabsContainer();
|
||||
this.tabsContainer = new TabsContainer('Tools');
|
||||
}
|
||||
}
|
||||
@@ -9,8 +9,8 @@
|
||||
import { observer } from 'mobx-react-lite';
|
||||
import styled, { css } from 'reshadow';
|
||||
|
||||
import { usePermission } from '@cloudbeaver/core-blocks';
|
||||
import { EPermission } from '@cloudbeaver/core-root';
|
||||
import { AppAuthService } from '@cloudbeaver/core-authentication';
|
||||
import { useService } from '@cloudbeaver/core-di';
|
||||
import { MenuBar } from '@cloudbeaver/core-ui';
|
||||
import { useMenu } from '@cloudbeaver/core-view';
|
||||
|
||||
@@ -32,9 +32,9 @@ const styles = css`
|
||||
|
||||
export const AppStateMenu = observer(function AppStateMenu() {
|
||||
const menu = useMenu({ menu: MENU_APP_STATE });
|
||||
const isEnabled = usePermission(EPermission.public);
|
||||
const { authenticated } = useService(AppAuthService);
|
||||
|
||||
if (!isEnabled) {
|
||||
if (!authenticated) {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
@@ -9,8 +9,8 @@
|
||||
import { observer } from 'mobx-react-lite';
|
||||
import styled from 'reshadow';
|
||||
|
||||
import { usePermission } from '@cloudbeaver/core-blocks';
|
||||
import { EPermission } from '@cloudbeaver/core-root';
|
||||
import { AppAuthService } from '@cloudbeaver/core-authentication';
|
||||
import { useService } from '@cloudbeaver/core-di';
|
||||
import { MenuBar } from '@cloudbeaver/core-ui';
|
||||
import { useMenu } from '@cloudbeaver/core-view';
|
||||
|
||||
@@ -20,9 +20,9 @@ import { MENU_APP_ACTIONS } from './MENU_APP_ACTIONS';
|
||||
|
||||
export const MainMenu = observer(function MainMenu() {
|
||||
const menu = useMenu({ menu: MENU_APP_ACTIONS });
|
||||
const isEnabled = usePermission(EPermission.public);
|
||||
const { authenticated } = useService(AppAuthService);
|
||||
|
||||
if (!isEnabled) {
|
||||
if (!authenticated) {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
@@ -130,7 +130,7 @@ export const UserForm = observer<Props>(function UserForm({
|
||||
</>
|
||||
)}
|
||||
</status-message>
|
||||
<TabList style={style} disabled={state.info.disabled}>
|
||||
<TabList aria-label='User Settings' style={style} disabled={state.info.disabled}>
|
||||
<UserInfoTab style={style} />
|
||||
{localProvider && <AuthenticationTab style={style} />}
|
||||
{/* <UserAuthProvidersTab style={style} /> */}
|
||||
|
||||
Reference in New Issue
Block a user