From f479d8410ae388babd953f18c6b740dbdf63728a Mon Sep 17 00:00:00 2001 From: Alexey Date: Thu, 7 Sep 2023 14:41:41 +0300 Subject: [PATCH 1/3] CB-3957 fix: verify change availability flags (#1988) --- .../ConnectionSchemaManagerBootstrap.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/webapp/packages/plugin-datasource-context-switch/src/ConnectionSchemaManager/ConnectionSchemaManagerBootstrap.ts b/webapp/packages/plugin-datasource-context-switch/src/ConnectionSchemaManager/ConnectionSchemaManagerBootstrap.ts index 4fdaed4fc9..32e2cc02f7 100644 --- a/webapp/packages/plugin-datasource-context-switch/src/ConnectionSchemaManager/ConnectionSchemaManagerBootstrap.ts +++ b/webapp/packages/plugin-datasource-context-switch/src/ConnectionSchemaManager/ConnectionSchemaManagerBootstrap.ts @@ -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]; From ff32a5a577a469f5ef32b0b6ba10177d4f54d8d2 Mon Sep 17 00:00:00 2001 From: Dmitriy Osipov <75555523+teunlao@users.noreply.github.com> Date: Thu, 7 Sep 2023 13:42:42 +0200 Subject: [PATCH 2/3] 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 --- .../src/NavTree/ConnectionNavNodeService.ts | 2 +- .../core-events/src/NotificationService.ts | 9 +++ .../ElementsTree/useElementsTree.ts | 17 +++-- .../NavigationTree/NavigationTreeService.ts | 64 ++++++++----------- .../src/NavigationTree/useNavigationTree.ts | 9 ++- .../src/SqlEditorOverlay.tsx | 8 ++- 6 files changed, 65 insertions(+), 44 deletions(-) diff --git a/webapp/packages/core-connections/src/NavTree/ConnectionNavNodeService.ts b/webapp/packages/core-connections/src/NavTree/ConnectionNavNodeService.ts index 0845edbf48..c51e55e593 100644 --- a/webapp/packages/core-connections/src/NavTree/ConnectionNavNodeService.ts +++ b/webapp/packages/core-connections/src/NavTree/ConnectionNavNodeService.ts @@ -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); } } } diff --git a/webapp/packages/core-events/src/NotificationService.ts b/webapp/packages/core-events/src/NotificationService.ts index f65f39978a..7718d69dee 100644 --- a/webapp/packages/core-events/src/NotificationService.ts +++ b/webapp/packages/core-events/src/NotificationService.ts @@ -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 diff --git a/webapp/packages/plugin-navigation-tree/src/NavigationTree/ElementsTree/useElementsTree.ts b/webapp/packages/plugin-navigation-tree/src/NavigationTree/ElementsTree/useElementsTree.ts index e8916572ab..ab8d236078 100644 --- a/webapp/packages/plugin-navigation-tree/src/NavigationTree/ElementsTree/useElementsTree.ts +++ b/webapp/packages/plugin-navigation-tree/src/NavigationTree/ElementsTree/useElementsTree.ts @@ -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 { + 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 { 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; diff --git a/webapp/packages/plugin-navigation-tree/src/NavigationTree/NavigationTreeService.ts b/webapp/packages/plugin-navigation-tree/src/NavigationTree/NavigationTreeService.ts index 8e81695a92..d008deb79e 100644 --- a/webapp/packages/plugin-navigation-tree/src/NavigationTree/NavigationTreeService.ts +++ b/webapp/packages/plugin-navigation-tree/src/NavigationTree/NavigationTreeService.ts @@ -72,53 +72,43 @@ export class NavigationTreeService extends View { await this.navNodeManagerService.navToNode(id, parentId); } - async loadNestedNodes(id = ROOT_NODE_PATH, tryConnect?: boolean, notify = true): Promise { - try { - if (this.isConnectionNode(id)) { - let connection = this.connectionInfoResource.getConnectionForNode(id); - - if (connection) { - connection = await this.connectionInfoResource.load(createConnectionParam(connection)); - } else { + async loadNestedNodes(id = ROOT_NODE_PATH, tryConnect?: boolean): Promise { + 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; } - if (!connection.connected) { - if (!tryConnect) { - return false; - } - - try { - const connected = await this.tryInitConnection(createConnectionParam(connection)); - if (!connected) { - return false; - } - } catch { - return false; - } + const connected = await this.tryInitConnection(createConnectionParam(connection)); + if (!connected) { + return false; } } + } - await this.navTreeResource.waitLoad(); - - if (tryConnect && this.navTreeResource.getException(id)) { - this.navTreeResource.markOutdated(id); - } + await this.navTreeResource.waitLoad(); - const parents = this.navNodeInfoResource.getParents(id); + if (tryConnect && this.navTreeResource.getException(id)) { + this.navTreeResource.markOutdated(id); + } - if (parents.length > 0 && !this.navNodeInfoResource.has(id)) { - return false; - } + const parents = this.navNodeInfoResource.getParents(id); - 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 (parents.length > 0 && !this.navNodeInfoResource.has(id)) { + return false; } - 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 { diff --git a/webapp/packages/plugin-navigation-tree/src/NavigationTree/useNavigationTree.ts b/webapp/packages/plugin-navigation-tree/src/NavigationTree/useNavigationTree.ts index 3bb9aa7512..6b9fd7580f 100644 --- a/webapp/packages/plugin-navigation-tree/src/NavigationTree/useNavigationTree.ts +++ b/webapp/packages/plugin-navigation-tree/src/NavigationTree/useNavigationTree.ts @@ -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 = ['handleOpen', 'handleSelect', export function useNavigationTree(): INavigationTree { const navigationTreeService = useService(NavigationTreeService); + const notificationService = useService(NotificationService); return useObjectRef( () => ({ 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) { diff --git a/webapp/packages/plugin-sql-editor/src/SqlEditorOverlay.tsx b/webapp/packages/plugin-sql-editor/src/SqlEditorOverlay.tsx index 779b2b245a..2918502721 100644 --- a/webapp/packages/plugin-sql-editor/src/SqlEditorOverlay.tsx +++ b/webapp/packages/plugin-sql-editor/src/SqlEditorOverlay.tsx @@ -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(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(function SqlEditorOverlay({ stat } async function init() { - await sqlEditorService.initEditorConnection(state); + try { + await sqlEditorService.initEditorConnection(state); + } catch (exception: any) { + notificationService.logException(exception); + } } const dataContainer = getComputed(() => From da6a84c15a5ed4a3eb9af7b7c0ef32752699a130 Mon Sep 17 00:00:00 2001 From: Serge Rider Date: Thu, 7 Sep 2023 14:56:32 +0200 Subject: [PATCH 3/3] Constants reuse --- .../io.cloudbeaver.model/src/io/cloudbeaver/DBWConstants.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/DBWConstants.java b/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/DBWConstants.java index 4750e8ea9c..5a83a18ead 100644 --- a/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/DBWConstants.java +++ b/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/DBWConstants.java @@ -17,6 +17,7 @@ package io.cloudbeaver; import org.jkiss.dbeaver.model.access.DBAPermissionRealm; +import org.jkiss.dbeaver.model.rm.RMConstants; /** * General constants @@ -25,7 +26,7 @@ public class DBWConstants { public static final String PERMISSION_ADMIN = DBAPermissionRealm.PERMISSION_ADMIN; - public static final String PERMISSION_CONFIGURATION_MANAGER = "configuration-manager"; + public static final String PERMISSION_CONFIGURATION_MANAGER = RMConstants.PERMISSION_CONFIGURATION_MANAGER; public static final String PERMISSION_PRIVATE_PROJECT_ACCESS = "private-project-access"; public static final String PERMISSION_EDIT_STRUCTURE = "edit-meta";