From f85acd91f90542f00f6fb0cc3a17661b3a06ceb3 Mon Sep 17 00:00:00 2001 From: sergeyteleshev Date: Wed, 10 Jun 2026 16:08:32 +0200 Subject: [PATCH] makes isDatabaseObject less heuristic --- .../src/ConnectionInfoResource.ts | 12 ++--------- .../src/NodesManager/NavNodeManagerService.ts | 2 +- .../src/NodesManager/NodeManagerUtils.test.ts | 21 ++++++++++++------- .../src/NodesManager/NodeManagerUtils.ts | 10 +++++---- .../src/NavNodes/ConnectionNavNodeService.ts | 4 ++-- .../navigationTreeProjectFilter.ts | 2 +- .../NodesManager/NavNodeContextMenuService.ts | 2 +- .../src/ObjectViewerTabService.ts | 6 ++++-- 8 files changed, 31 insertions(+), 28 deletions(-) diff --git a/webapp/packages/core-connections/src/ConnectionInfoResource.ts b/webapp/packages/core-connections/src/ConnectionInfoResource.ts index 582681bb47..8d5968a8cf 100644 --- a/webapp/packages/core-connections/src/ConnectionInfoResource.ts +++ b/webapp/packages/core-connections/src/ConnectionInfoResource.ts @@ -297,13 +297,9 @@ export class ConnectionInfoResource extends CachedMapResource { describe('connectionIdToConnectionNodeId', () => { @@ -24,15 +29,17 @@ describe('NodeManagerUtils', () => { }); describe('isDatabaseObject', () => { - it('should return true for objectIds containing "datasources at first segment"', () => { - expect(NodeManagerUtils.isDatabaseObject('node://project/datasources/123')).toBe(true); - expect(NodeManagerUtils.isDatabaseObject('node://project/datasources/abc')).toBe(true); + it('should return true for nodes with an objectId', () => { + expect(NodeManagerUtils.isDatabaseObject(makeNode('connection-123'))).toBe(true); + expect(NodeManagerUtils.isDatabaseObject(makeNode('schema-abc'))).toBe(true); }); - it('should return false for objectIds not containing "datasources"', () => { - expect(NodeManagerUtils.isDatabaseObject('http://example.com')).toBe(false); - expect(NodeManagerUtils.isDatabaseObject('12345')).toBe(false); - expect(NodeManagerUtils.isDatabaseObject('')).toBe(false); + it('should return false for connection folders and navigation-only nodes without objectId', () => { + expect(NodeManagerUtils.isDatabaseObject(makeNode(undefined))).toBe(false); + }); + + it('should return false for undefined', () => { + expect(NodeManagerUtils.isDatabaseObject(undefined)).toBe(false); }); }); diff --git a/webapp/packages/core-navigation-tree/src/NodesManager/NodeManagerUtils.ts b/webapp/packages/core-navigation-tree/src/NodesManager/NodeManagerUtils.ts index 76b0c50d70..c122c37d6e 100644 --- a/webapp/packages/core-navigation-tree/src/NodesManager/NodeManagerUtils.ts +++ b/webapp/packages/core-navigation-tree/src/NodesManager/NodeManagerUtils.ts @@ -6,7 +6,10 @@ * you may not use this file except in compliance with the License. */ -import { createPath, getPathParts } from '@cloudbeaver/core-utils'; +import { createPath } from '@cloudbeaver/core-utils'; + +import type { NavNode } from './EntityTypes.js'; +import { isNotNullDefined } from '@dbeaver/js-helpers'; export const NODE_PATH_PREFIX = 'node://'; export const NODE_DATASOURCES_SEGMENT = 'datasources'; @@ -20,9 +23,8 @@ export const NodeManagerUtils = { return `${schemaId || ''}${schemaId && catalogId ? '@' : ''}${catalogId || ''}`; }, - isDatabaseObject(nodeId: string): boolean { - const segments = getPathParts(this.getPlainPath(nodeId)); - return segments[1] === NODE_DATASOURCES_SEGMENT; + isDatabaseObject(node: NavNode | undefined): boolean { + return isNotNullDefined(node?.objectId); }, getPlainPath(nodeId: string): string { return nodeId.startsWith(NODE_PATH_PREFIX) ? nodeId.slice(NODE_PATH_PREFIX.length) : nodeId; diff --git a/webapp/packages/plugin-connections/src/NavNodes/ConnectionNavNodeService.ts b/webapp/packages/plugin-connections/src/NavNodes/ConnectionNavNodeService.ts index c058f45ac8..c9b3dbee75 100644 --- a/webapp/packages/plugin-connections/src/NavNodes/ConnectionNavNodeService.ts +++ b/webapp/packages/plugin-connections/src/NavNodes/ConnectionNavNodeService.ts @@ -122,7 +122,7 @@ export class ConnectionNavNodeService { if (isResourceAlias(key)) { return; } - if (!ResourceKeyUtils.some(key, key => NodeManagerUtils.isDatabaseObject(key))) { + if (!ResourceKeyUtils.some(key, key => NodeManagerUtils.isDatabaseObject(this.navNodeInfoResource.get(key)))) { return; } @@ -290,7 +290,7 @@ export class ConnectionNavNodeService { private async navigateHandler({ nodeId }: INodeNavigationData, contexts: IExecutionContextProvider): Promise { let connection: Connection | undefined | null = await contexts.getContext(this.navigationNavNodeConnectionContext); - if (NodeManagerUtils.isDatabaseObject(nodeId) && connection) { + if (NodeManagerUtils.isDatabaseObject(this.navNodeInfoResource.get(nodeId)) && connection) { connection = await this.connectionsManagerService.requireConnection(createConnectionParam(connection)); if (!connection?.connected) { diff --git a/webapp/packages/plugin-navigation-tree/src/NavigationTree/ProjectsRenderer/navigationTreeProjectFilter.ts b/webapp/packages/plugin-navigation-tree/src/NavigationTree/ProjectsRenderer/navigationTreeProjectFilter.ts index 93f49119c9..f05e843ef7 100644 --- a/webapp/packages/plugin-navigation-tree/src/NavigationTree/ProjectsRenderer/navigationTreeProjectFilter.ts +++ b/webapp/packages/plugin-navigation-tree/src/NavigationTree/ProjectsRenderer/navigationTreeProjectFilter.ts @@ -44,7 +44,7 @@ export function navigationTreeProjectFilter( return navTreeResource.get(node.uri)?.length; } - return NodeManagerUtils.isDatabaseObject(node.uri); + return NodeManagerUtils.isDatabaseObject(node); }) .map(node => node.uri); diff --git a/webapp/packages/plugin-navigation-tree/src/NodesManager/NavNodeContextMenuService.ts b/webapp/packages/plugin-navigation-tree/src/NodesManager/NavNodeContextMenuService.ts index e712641af0..ff7a52cab1 100644 --- a/webapp/packages/plugin-navigation-tree/src/NodesManager/NavNodeContextMenuService.ts +++ b/webapp/packages/plugin-navigation-tree/src/NodesManager/NavNodeContextMenuService.ts @@ -117,7 +117,7 @@ export class NavNodeContextMenuService extends Bootstrap { isActionApplicable: (context, action) => { const node = context.get(DATA_CONTEXT_NAV_NODE)!; - if (NodeManagerUtils.isDatabaseObject(node.uri) || isConnectionFolder(node)) { + if (NodeManagerUtils.isDatabaseObject(node) || isConnectionFolder(node)) { if (action === ACTION_RENAME) { return node.features?.includes(ENodeFeature.canRename) ?? false; } diff --git a/webapp/packages/plugin-object-viewer/src/ObjectViewerTabService.ts b/webapp/packages/plugin-object-viewer/src/ObjectViewerTabService.ts index c7574b30d4..832b46c4c5 100644 --- a/webapp/packages/plugin-object-viewer/src/ObjectViewerTabService.ts +++ b/webapp/packages/plugin-object-viewer/src/ObjectViewerTabService.ts @@ -1,6 +1,6 @@ /* * CloudBeaver - Cloud Database Manager - * Copyright (C) 2020-2025 DBeaver Corp and others + * Copyright (C) 2020-2026 DBeaver Corp and others * * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. @@ -139,8 +139,10 @@ export class ObjectViewerTabService { tabInfo.registerTab(tab); } + const node = this.navNodeManagerService.getNode(data.nodeId); + function isSupported(): boolean { - return NodeManagerUtils.isDatabaseObject(data.nodeId); + return NodeManagerUtils.isDatabaseObject(node); } if (isSupported()) {