makes isDatabaseObject less heuristic

This commit is contained in:
sergeyteleshev
2026-06-10 16:08:32 +02:00
parent 28ae7e5a17
commit f85acd91f9
8 changed files with 31 additions and 28 deletions
@@ -297,13 +297,9 @@ export class ConnectionInfoResource extends CachedMapResource<IConnectionInfoPar
}
getConnectionIdForNodeId(projectId: string, nodeId: string): IConnectionInfoParams | undefined {
if (!NodeManagerUtils.isDatabaseObject(nodeId)) {
return;
}
const node = this.navNodeInfoResource.get(nodeId);
if (!node || !node.objectId) {
if (!node || !NodeManagerUtils.isDatabaseObject(node) || !node.objectId) {
return;
}
@@ -311,13 +307,9 @@ export class ConnectionInfoResource extends CachedMapResource<IConnectionInfoPar
}
getConnectionForNode(nodeId: string): Connection | undefined {
if (!NodeManagerUtils.isDatabaseObject(nodeId)) {
return;
}
const node = this.navNodeInfoResource.get(nodeId);
if (!node || !node.objectId || !node.projectId) {
if (!node || !NodeManagerUtils.isDatabaseObject(node) || !node.objectId || !node.projectId) {
return;
}
@@ -338,7 +338,7 @@ export class NavNodeManagerService extends Bootstrap {
projectId ||= node.projectId;
features = node.features;
if (NodeManagerUtils.isDatabaseObject(nodeId)) {
if (NodeManagerUtils.isDatabaseObject(node)) {
if (node.folder) {
const parent = this.getParent(node);
folderId = nodeId;
@@ -8,6 +8,11 @@
import { describe, expect, it } from 'vitest';
import { NodeManagerUtils } from './NodeManagerUtils.js';
import type { NavNode } from './EntityTypes.js';
function makeNode(objectId?: string): NavNode {
return { uri: '', objectId, folder: false, hasChildren: false, inline: false, navigable: false, filtered: false, objectFeatures: [] };
}
describe('NodeManagerUtils', () => {
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);
});
});
@@ -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;
@@ -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<INodeNavigationData>): Promise<void> {
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) {
@@ -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);
@@ -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;
}
@@ -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()) {