Compare commits

...
Author SHA1 Message Date
Aleksandr Skoblikov 4e82eed3e0 CB-4161 validate custom config status 2023-10-24 18:09:46 +02:00
Aleksandr Skoblikov 87f9bd5e49 CB-4161 auth fix 2023-10-24 17:39:38 +02:00
naumov b2fa46097e CB-3998 delete unsupported actions in updateResults 2023-09-12 09:48:11 +02:00
Dmitriy Osipov 6e736bae41 CB-3970: move error handlers closer to components (#1983)
* CB-3970: move error handlers closer to components

* CB-3970: handle errors of opening navNode

* CB-3970 fix: interrupt executor instead of throwing error
2023-09-07 14:43:06 +03:00
Alexey aa288c536b CB-3957 fix: verify change availability flags (#1988) 2023-09-07 14:42:20 +03:00
Alexey a2ebe8bd82 CB-3953 fix: git description message (#1981) 2023-09-04 11:32:23 +03:00
Alexey f1a75898af CB-3951 fix: check query history permissions (#1977) 2023-09-01 15:33:29 +02:00
Alexander SkoblikovandDenis Sinelnikov d3d8983134 CB-2551 additional creds auth (#1975)
* CB-2551. Fixed additional auth for disabled user

* CB-2551. Fixed additional auth for disabled user

* CB-2551. Fixed additional auth for disabled user

---------

Co-authored-by: Denis Sinelnikov <denis.sinelnikov@dbeaver.com>
2023-08-31 18:50:19 +03:00
AlexeyandDaria Marutkina da3f703639 CB-3891 feat: inverse git sync data (#1965)
Co-authored-by: Daria Marutkina <125263541+dariamarutkina@users.noreply.github.com>
2023-08-31 15:42:02 +03:00
Alexander Skoblikov 2ad858ea80 CB-3931 copy params only for test connection (#1973) 2023-08-30 18:11:06 +03:00
Alexander Skoblikov 81c1b67ab7 CB-3935 create project for new users correctly (#1972) 2023-08-30 18:00:44 +03:00
25 changed files with 218 additions and 122 deletions
@@ -324,6 +324,9 @@ public class LocalResourceController implements RMController {
@Override
public RMProject getProject(@NotNull String projectId, boolean readResources, boolean readProperties) throws DBException {
RMProject project = makeProjectFromId(projectId, true);
if (project == null) {
return null;
}
if (readResources) {
doProjectOperation(projectId, () -> {
project.setChildren(
@@ -870,7 +873,15 @@ public class LocalResourceController implements RMController {
var projectName = parseProjectName(projectId);
var projectPath = getProjectPath(projectId);
if (!Files.exists(projectPath)) {
return null;
if (isPrivateProject(projectId) && isProjectOwner(projectId)) {
try {
Files.createDirectories(projectPath);
} catch (Exception e) {
throw new DBException("Failed to create project " + projectId + ": " + e.getMessage(), e);
}
} else {
return null;
}
}
Set<RMProjectPermission> permissions = Set.of();
if (loadPermissions && credentialsProvider.getActiveUserCredentials() != null) {
@@ -1210,6 +1221,12 @@ public class LocalResourceController implements RMController {
return RMProjectType.USER.getPrefix().equals(rmProjectName.getPrefix());
}
private boolean isProjectOwner(String projectId) {
var activeUserCredentials = credentialsProvider.getActiveUserCredentials();
var userId = activeUserCredentials == null ? null : activeUserCredentials.getUserId();
return isProjectOwner(projectId, userId);
}
public static boolean isProjectOwner(String projectId, String userId) {
RMProjectName rmProjectName = parseProjectNameUnsafe(projectId);
return RMProjectType.USER.getPrefix().equals(rmProjectName.getPrefix()) &&
@@ -17,7 +17,6 @@
package io.cloudbeaver.model.session;
import io.cloudbeaver.DBWConstants;
import io.cloudbeaver.DBWUserIdentity;
import io.cloudbeaver.DBWebException;
import io.cloudbeaver.auth.SMAuthProviderExternal;
@@ -38,7 +37,6 @@ import org.jkiss.utils.CommonUtils;
import java.time.OffsetDateTime;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
@@ -114,15 +112,6 @@ public class WebSessionAuthProcessor {
SMAuthProviderExternal<?> authProviderExternal = authProviderInstance instanceof SMAuthProviderExternal<?> ?
(SMAuthProviderExternal<?>) authProviderInstance : null;
boolean providerDisabled = !isProviderEnabled(providerId);
if (configMode || webSession.hasPermission(DBWConstants.PERMISSION_ADMIN)) {
// 1. Admin can authorize in any providers
// 2. When it authorizes in non-local provider for the first time we force linkUser flag
if (providerDisabled && webSession.getUser() != null) {
linkWithActiveUser = true;
}
}
SMSession authSession;
if (authProviderExternal != null && !configMode && !alreadyLoggedIn) {
@@ -222,6 +222,17 @@ public class WebServiceUtils extends WebCommonUtils {
@Nullable Map<String, Object> authProperties,
boolean saveCredentials,
boolean sharedCredentials
) {
saveAuthProperties(dataSourceContainer, configuration, authProperties, saveCredentials, sharedCredentials, false);
}
public static void saveAuthProperties(
@NotNull DBPDataSourceContainer dataSourceContainer,
@NotNull DBPConnectionConfiguration configuration,
@Nullable Map<String, Object> authProperties,
boolean saveCredentials,
boolean sharedCredentials,
boolean isTest
) {
dataSourceContainer.setSavePassword(saveCredentials);
dataSourceContainer.setSharedCredentials(sharedCredentials);
@@ -242,12 +253,14 @@ public class WebServiceUtils extends WebCommonUtils {
// Read save credentials
DBAAuthCredentials credentials = configuration.getAuthModel().loadCredentials(dataSourceContainer, configuration);
var currentAuthProps = new HashMap<String, String>();
for (Map.Entry<String, Object> stringObjectEntry : authProperties.entrySet()) {
var value = stringObjectEntry.getValue() == null ? null : stringObjectEntry.getValue().toString();
currentAuthProps.put(stringObjectEntry.getKey(), value);
if (isTest) {
var currentAuthProps = new HashMap<String, String>();
for (Map.Entry<String, Object> stringObjectEntry : authProperties.entrySet()) {
var value = stringObjectEntry.getValue() == null ? null : stringObjectEntry.getValue().toString();
currentAuthProps.put(stringObjectEntry.getKey(), value);
}
configuration.setAuthProperties(currentAuthProps);
}
configuration.setAuthProperties(currentAuthProps);
if (!authProperties.isEmpty()) {
// Make new Gson parser with type adapters to deserialize into existing credentials
@@ -660,7 +660,8 @@ public class WebServiceCore implements DBWServiceCore {
testDataSource.getConnectionConfiguration(),
connectionConfig.getCredentials(),
true,
false
false,
true
);
} else {
testDataSource = WebServiceUtils.createConnectionFromConfig(connectionConfig, sessionRegistry);
@@ -68,6 +68,11 @@ public class WebServiceAuthImpl implements DBWServiceAuth {
if (CommonUtils.isEmpty(providerId)) {
throw new DBWebException("Missing auth provider parameter");
}
WebAuthProviderDescriptor authProviderDescriptor = WebAuthProviderRegistry.getInstance()
.getAuthProvider(providerId);
if (authProviderDescriptor.isTrusted()) {
throw new DBWebException(authProviderDescriptor.getLabel() + " not allowed for authorization via GQL API");
}
if (authParameters == null) {
authParameters = Map.of();
}
@@ -1217,6 +1217,9 @@ public class CBEmbeddedSecurityController implements SMAdminController, SMAuthen
@Override
public SMAuthInfo authenticateAnonymousUser(@NotNull String appSessionId, @NotNull Map<String, Object> sessionParameters, @NotNull SMSessionType sessionType) throws DBException {
if (!application.getAppConfiguration().isAnonymousAccessEnabled()) {
throw new SMException("Anonymous access restricted");
}
try (Connection dbCon = database.openConnection()) {
try (JDBCTransaction txn = new JDBCTransaction(dbCon)) {
var smSessionId = createSmSession(appSessionId, null, sessionParameters, sessionType, dbCon);
@@ -1252,6 +1255,9 @@ public class CBEmbeddedSecurityController implements SMAdminController, SMAuthen
@Nullable String authProviderConfigurationId,
@NotNull Map<String, Object> userCredentials
) throws DBException {
if (isProviderDisabled(authProviderId, authProviderConfigurationId)) {
throw new SMException("Unsupported authentication provider: " + authProviderId);
}
var authProgressMonitor = new LoggingProgressMonitor(log);
try (Connection dbCon = database.openConnection()) {
try (JDBCTransaction txn = new JDBCTransaction(dbCon)) {
@@ -1786,40 +1792,41 @@ public class CBEmbeddedSecurityController implements SMAdminController, SMAuthen
}
userAuthData.putAll((Map<String, Object>) authInfo.getAuthData().get(authConfiguration));
SMAutoAssign autoAssign = isMainAuthSession
? getAutoAssignUserData(authProvider, providerConfig, userAuthData, finishAuthMonitor)
//do not auto assign user data if it an additional auth
: null;
if (autoAssign != null) {
detectedAuthRole = autoAssign.getAuthRole();
}
var userIdFromCreds = findOrCreateExternalUserByCredentials(
authProvider,
authAttemptSessionInfo.getSessionParams(),
userAuthData,
finishAuthMonitor,
activeUserId,
activeUserId == null,
detectedAuthRole,
providerConfig
);
if (userIdFromCreds == null) {
var error = "Invalid user credentials";
updateAuthStatus(authId, SMAuthStatus.ERROR, storedUserData, error);
return SMAuthInfo.error(authId, error);
}
if (autoAssign != null && !CommonUtils.isEmpty(autoAssign.getExternalTeamIds())) {
if (allTeams == null) {
allTeams = readAllTeams();
if (isMainAuthSession) {
SMAutoAssign autoAssign =
getAutoAssignUserData(authProvider, providerConfig, userAuthData, finishAuthMonitor);
if (autoAssign != null) {
detectedAuthRole = autoAssign.getAuthRole();
}
autoUpdateUserTeams(authProvider, autoAssign, userIdFromCreds, allTeams);
}
if (activeUserId == null) {
activeUserId = userIdFromCreds;
var userIdFromCreds = findOrCreateExternalUserByCredentials(
authProvider,
authAttemptSessionInfo.getSessionParams(),
userAuthData,
finishAuthMonitor,
activeUserId,
activeUserId == null,
detectedAuthRole,
providerConfig
);
if (userIdFromCreds == null) {
var error = "Invalid user credentials";
updateAuthStatus(authId, SMAuthStatus.ERROR, storedUserData, error);
return SMAuthInfo.error(authId, error);
}
if (autoAssign != null && !CommonUtils.isEmpty(autoAssign.getExternalTeamIds())) {
if (allTeams == null) {
allTeams = readAllTeams();
}
autoUpdateUserTeams(authProvider, autoAssign, userIdFromCreds, allTeams);
}
if (activeUserId == null) {
activeUserId = userIdFromCreds;
}
}
storedUserData.put(authConfiguration,
saveSecuredCreds ? userAuthData : filterSecuredUserData(userAuthData, getAuthProvider(authProviderId)));
@@ -2585,9 +2592,17 @@ public class CBEmbeddedSecurityController implements SMAdminController, SMAuthen
return activeUserCredentials.getUserId();
}
private boolean isProviderEnabled(@NotNull String providerId) {
private boolean isProviderDisabled(@NotNull String providerId, @Nullable String authConfigurationId) {
WebAuthConfiguration appConfiguration = application.getAuthConfiguration();
return appConfiguration.isAuthProviderEnabled(providerId);
if (!appConfiguration.isAuthProviderEnabled(providerId)) {
return true;
}
if (authConfigurationId != null) {
SMAuthProviderCustomConfiguration configuration =
appConfiguration.getAuthProviderConfiguration(authConfigurationId);
return configuration == null || configuration.isDisabled();
}
return false;
}
public void clearOldAuthAttemptInfo() throws DBException {
@@ -33,7 +33,7 @@ import java.nio.file.Path;
@RunWith(Suite.class)
@Suite.SuiteClasses(
{
PlatformTest.class,
ConnectionsTest.class,
AuthenticationTest.class,
ResourceManagerTest.class,
RMLockTest.class
@@ -63,10 +63,7 @@ public class CEServerTestSuite {
testApp.start(null);
});
thread.start();
client = HttpClient.newBuilder()
.cookieHandler(new CookieManager())
.version(HttpClient.Version.HTTP_2)
.build();
client = createClient();
long startTime = System.currentTimeMillis();
long endTime = 0;
while (true) {
@@ -97,6 +94,13 @@ public class CEServerTestSuite {
return client;
}
public static HttpClient createClient() {
return HttpClient.newBuilder()
.cookieHandler(new CookieManager())
.version(HttpClient.Version.HTTP_2)
.build();
}
public static Path getScriptsPath() {
return scriptsPath;
}
@@ -30,7 +30,7 @@ import java.util.Collections;
import java.util.List;
import java.util.Map;
public class PlatformTest {
public class ConnectionsTest {
public static final String GQL_TEMPLATE_CREATE_CONNECTION = "createConnection.json";
public static final String GQL_TEMPLATE_DELETE_CONNECTION = "deleteConnection.json";
@@ -52,12 +52,16 @@ public class PlatformTest {
@Test
public void testBCreateConnection() throws Exception {
HttpClient client = CEServerTestSuite.getClient();
HttpClient client = CEServerTestSuite.createClient();
WebTestUtils.authenticateUser(
client, CEServerTestSuite.getScriptsPath(), CEServerTestSuite.GQL_API_URL);
List<Map<String, Object>> connections = getUserConnections(client);
Map<String, Object> addedConnection = createConnection(client);
if (!getUserConnections(client).contains(addedConnection)) {
throw new Exception("The new connection was not added");
}
boolean deleteConnection = deleteConnection(client, CommonUtils.toString(addedConnection.get("id")));
if (!deleteConnection) {
throw new Exception("The new connection was not deleted");
@@ -1,6 +1,7 @@
{
"query": "\n mutation createConnection($config: ConnectionConfig!) {\n createConnection(config: $config) {\n id\n }\n} ",
"query": "\n mutation createConnection($projectId:ID!, $config: ConnectionConfig!) {\n createConnection(projectId:$projectId, config: $config) {\n id\n }\n} ",
"variables": {
"projectId": "u_test",
"config": {
"name": "PostgreSQL@localhost (1)",
"driverId": "postgresql:postgres-jdbc",
@@ -1,5 +1,8 @@
{"query": "mutation deleteConnection($id: ID!) {deleteConnection(id: $id)}",
"variables": {
"id" : "${connectionId}"
},
"operationName":"deleteConnection"}
{
"query": "mutation deleteConnection($projectId:ID!, $id: ID!) {deleteConnection(projectId:$projectId, id: $id)}",
"variables": {
"projectId": "u_test",
"id": "${connectionId}"
},
"operationName": "deleteConnection"
}
@@ -13,7 +13,6 @@ import {
CachedMapAllKey,
CachedMapResource,
GraphQLService,
ResourceKey,
resourceKeyList,
} from '@cloudbeaver/core-sdk';
@@ -50,7 +50,7 @@ export class UserInfoResource extends CachedDataResource<UserInfo | null, void,
constructor(
private readonly graphQLService: GraphQLService,
private readonly authProviderService: AuthProviderService,
private readonly sessionResource: SessionResource,
sessionResource: SessionResource,
private readonly sessionDataResource: SessionDataResource,
) {
super(() => null, undefined, ['customIncludeOriginDetails', 'includeConfigurationParameters']);
@@ -4,4 +4,5 @@
display: block;
text-transform: none;
white-space: pre-wrap;
}
@@ -19,6 +19,7 @@ export interface CheckboxBaseProps {
mod?: CheckboxMod[];
ripple?: boolean;
indeterminate?: boolean;
inverse?: boolean;
style?: ComponentStyle;
}
@@ -62,6 +63,7 @@ export const Checkbox: CheckboxType = observer(function Checkbox({
checked,
defaultChecked,
children,
inverse,
mod,
ripple,
className,
@@ -77,6 +79,7 @@ export const Checkbox: CheckboxType = observer(function Checkbox({
defaultChecked,
state,
name,
inverse,
onChange,
});
@@ -27,6 +27,7 @@ const switchMod = {
interface IBaseProps {
mod?: Array<keyof typeof switchMod>;
description?: React.ReactNode;
inverse?: boolean;
}
interface SwitchType {
@@ -45,10 +46,11 @@ export const Switch: SwitchType = observer(function Switch({
defaultChecked,
className,
children,
onChange,
inverse,
mod = [],
autoHide,
disabled,
onChange,
...rest
}: IBaseProps & (ICheckboxControlledProps | ICheckboxObjectProps<any>)) {
const checkboxState = useCheckboxState({
@@ -58,6 +60,7 @@ export const Switch: SwitchType = observer(function Switch({
defaultChecked,
state,
name,
inverse,
onChange,
});
rest = filterLayoutFakeProps(rest);
@@ -17,6 +17,7 @@ export type CheckboxStateOptions<TKey extends string> = {
defaultValue: string | undefined;
checked: boolean | undefined;
defaultChecked: boolean | undefined;
inverse: boolean | undefined;
} & (
| {
state: undefined;
@@ -56,12 +57,20 @@ export function useCheckboxState<TKey extends string>(options: CheckboxStateOpti
}
}
if (options.inverse) {
checked = !checked;
}
return useObjectRef<ICheckboxState>(
() => ({
checked,
change(event: React.ChangeEvent<HTMLInputElement>) {
const { state, name, value, onChange, count, context } = optionsRef;
const checked = event.target.checked;
const { inverse, state, name, value, onChange, count, context } = optionsRef;
let checked = event.target.checked;
if (inverse) {
checked = !checked;
}
if (state !== undefined && name !== undefined) {
const currentState = state[name as TKey];
@@ -5,11 +5,12 @@
* Licensed under the Apache License, Version 2.0.
* you may not use this file except in compliance with the License.
*/
import { useService } from '@cloudbeaver/core-di';
import { PermissionsService } from '@cloudbeaver/core-root';
import { SessionPermissionsResource } from '@cloudbeaver/core-root';
import { useResource } from './ResourcesHooks/useResource';
export function usePermission(key: string): boolean {
const permissionsService = useService(PermissionsService);
const sessionPermissionsResource = useResource(usePermission, SessionPermissionsResource, undefined);
return permissionsService.has(key);
return sessionPermissionsResource.data.has(key);
}
@@ -241,7 +241,7 @@ export class ConnectionNavNodeService extends Dependency {
connection = await this.connectionsManagerService.requireConnection(createConnectionParam(connection));
if (!connection?.connected) {
throw new Error('Connection not established');
ExecutorInterrupter.interrupt(contexts);
}
}
}
@@ -198,6 +198,15 @@ export class NotificationService {
console.error(exception);
}
throwSilently(exception: Error | GQLError | undefined | null): void {
this.logError({
title: '',
details: exception,
isSilent: true,
});
throw exception;
}
close(id: number, delayDeleting = true): void {
// TODO: emit event or something
@@ -91,6 +91,11 @@ export class DatabaseDataActions<TOptions, TResult extends IDatabaseDataResult>
const result = results.find(result => result.uniqueResultId === key);
for (const action of actions) {
if (!(action.constructor as any).dataFormat.includes(result?.dataFormat)) {
this.actions.delete(key);
continue;
}
action.updateResults(results);
if (!result) {
@@ -236,7 +236,9 @@ export class ConnectionSchemaManagerBootstrap extends Bootstrap {
this.menuService.addCreator({
menus: [MENU_CONNECTION_DATA_CONTAINER_SELECTOR],
isApplicable: () => this.connectionSchemaManagerService.isObjectCatalogChangeable && !!this.connectionSchemaManagerService.objectContainerList,
isApplicable: () =>
(this.connectionSchemaManagerService.isObjectCatalogChangeable || this.connectionSchemaManagerService.isObjectSchemaChangeable) &&
!!this.connectionSchemaManagerService.objectContainerList,
getItems: (context, items) => {
items = [...items];
@@ -153,6 +153,15 @@ export function useElementsTree(options: IOptions): IElementsTree {
options.expandStateGetters = useMemo(() => options.expandStateGetters || [], [...(options.expandStateGetters || [])]);
const state = options.localState || localTreeNodesState;
async function handleLoadChildren(id: string, manual: boolean): Promise<boolean> {
try {
return await options.loadChildren(id, manual);
} catch (exception: any) {
notificationService.logException(exception);
return false;
}
}
const functionsRef = useObjectRef({
async loadTree(nodeId: string) {
elementsTree.loading = true;
@@ -194,7 +203,7 @@ export function useElementsTree(options: IOptions): IElementsTree {
return;
}
const loaded = await options.loadChildren(child, false);
const loaded = await handleLoadChildren(child, false);
if (!loaded) {
const node = navNodeInfoResource.get(child);
@@ -530,7 +539,7 @@ export function useElementsTree(options: IOptions): IElementsTree {
if (!leaf && this.settings?.foldersTree && expandableOrExpanded) {
const nodeId = node.id;
const loaded = await options.loadChildren(node.id, true);
const loaded = await handleLoadChildren(node.id, false);
if (loaded) {
this.setFilter('');
options.folderExplorer.open(path, nodeId);
@@ -549,7 +558,7 @@ export function useElementsTree(options: IOptions): IElementsTree {
try {
if (state || (this.filtering && !treeNodeState.showInFilter)) {
state = await options.loadChildren(node.id, true);
state = await handleLoadChildren(node.id, true);
}
if (this.filtering) {
@@ -611,7 +620,7 @@ export function useElementsTree(options: IOptions): IElementsTree {
async loadPath(path: string[], lastNode?: string): Promise<string | undefined> {
let lastLoadedNode: string | undefined;
for (const nodeId of path) {
const loaded = await options.loadChildren(nodeId, false);
const loaded = await handleLoadChildren(nodeId, false);
if (!loaded) {
return lastLoadedNode;
@@ -72,53 +72,43 @@ export class NavigationTreeService extends View<string> {
await this.navNodeManagerService.navToNode(id, parentId);
}
async loadNestedNodes(id = ROOT_NODE_PATH, tryConnect?: boolean, notify = true): Promise<boolean> {
try {
if (this.isConnectionNode(id)) {
let connection = this.connectionInfoResource.getConnectionForNode(id);
async loadNestedNodes(id = ROOT_NODE_PATH, tryConnect?: boolean): Promise<boolean> {
if (this.isConnectionNode(id)) {
let connection = this.connectionInfoResource.getConnectionForNode(id);
if (connection) {
connection = await this.connectionInfoResource.load(createConnectionParam(connection));
} else {
return false;
}
if (!connection.connected) {
if (!tryConnect) {
return false;
}
try {
const connected = await this.tryInitConnection(createConnectionParam(connection));
if (!connected) {
return false;
}
} catch {
return false;
}
}
}
await this.navTreeResource.waitLoad();
if (tryConnect && this.navTreeResource.getException(id)) {
this.navTreeResource.markOutdated(id);
}
const parents = this.navNodeInfoResource.getParents(id);
if (parents.length > 0 && !this.navNodeInfoResource.has(id)) {
if (connection) {
connection = await this.connectionInfoResource.load(createConnectionParam(connection));
} else {
return false;
}
await this.navTreeResource.load(CachedResourcePageKey(CACHED_RESOURCE_DEFAULT_PAGE_OFFSET, this.navTreeResource.childrenLimit).setTarget(id));
return true;
} catch (exception: any) {
if (notify) {
this.notificationService.logException(exception);
if (!connection.connected) {
if (!tryConnect) {
return false;
}
const connected = await this.tryInitConnection(createConnectionParam(connection));
if (!connected) {
return false;
}
}
}
return false;
await this.navTreeResource.waitLoad();
if (tryConnect && this.navTreeResource.getException(id)) {
this.navTreeResource.markOutdated(id);
}
const parents = this.navNodeInfoResource.getParents(id);
if (parents.length > 0 && !this.navNodeInfoResource.has(id)) {
return false;
}
await this.navTreeResource.load(CachedResourcePageKey(CACHED_RESOURCE_DEFAULT_PAGE_OFFSET, this.navTreeResource.childrenLimit).setTarget(id));
return true;
}
selectNode(id: string, multiple?: boolean): void {
@@ -7,6 +7,7 @@
*/
import { useObjectRef } from '@cloudbeaver/core-blocks';
import { useService } from '@cloudbeaver/core-di';
import { NotificationService } from '@cloudbeaver/core-events';
import type { NavNode } from '@cloudbeaver/core-navigation-tree';
import { NavigationTreeService } from './NavigationTreeService';
@@ -22,13 +23,19 @@ const bindActions: Array<keyof INavigationTree> = ['handleOpen', 'handleSelect',
export function useNavigationTree(): INavigationTree {
const navigationTreeService = useService(NavigationTreeService);
const notificationService = useService(NotificationService);
return useObjectRef<INavigationTree>(
() => ({
navigationTreeService,
async handleOpen(node: NavNode, folder: boolean) {
if (!folder) {
await this.navigationTreeService.navToNode(node.id, node.parentId);
try {
await this.navigationTreeService.navToNode(node.id, node.parentId);
} catch (exception: any) {
notificationService.logException(exception);
throw exception;
}
}
},
handleSelect(node: NavNode, state: boolean) {
@@ -30,6 +30,7 @@ import {
getRealExecutionContextId,
} from '@cloudbeaver/core-connections';
import { useService } from '@cloudbeaver/core-di';
import { NotificationService } from '@cloudbeaver/core-events';
import { NodeManagerUtils } from '@cloudbeaver/core-navigation-tree';
import type { ISqlEditorTabState } from './ISqlEditorTabState';
@@ -50,6 +51,7 @@ export const SqlEditorOverlay = observer<Props>(function SqlEditorOverlay({ stat
const translate = useTranslate();
const sqlEditorService = useService(SqlEditorService);
const sqlDataSourceService = useService(SqlDataSourceService);
const notificationService = useService(NotificationService);
const dataSource = sqlDataSourceService.get(state.editorId);
const executionContextId = dataSource?.executionContext?.id;
const executionContext = dataSource?.executionContext;
@@ -77,7 +79,11 @@ export const SqlEditorOverlay = observer<Props>(function SqlEditorOverlay({ stat
}
async function init() {
await sqlEditorService.initEditorConnection(state);
try {
await sqlEditorService.initEditorConnection(state);
} catch (exception: any) {
notificationService.logException(exception);
}
}
const dataContainer = getComputed(() =>