Skip to content

Commit 1fd82a5

Browse files
committed
Added server parent nodes in connections + panels views (#DH-22593)
1 parent 6d2cd21 commit 1fd82a5

10 files changed

Lines changed: 328 additions & 66 deletions

src/common/constants.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -159,6 +159,7 @@ export const VARIABLE_UNICODE_ICONS = {
159159
export const CONNECTION_TREE_ITEM_CONTEXT = {
160160
isConnectionConnected: 'isConnectionConnected',
161161
isConnectionConnecting: 'isConnectionConnecting',
162+
isDHEServerConnectionParent: 'isDHEServerConnectionParent',
162163
isUri: 'isUri',
163164
} as const;
164165

src/controllers/ServerConnectionTreeDragAndDropController.ts

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { MIME_TYPE } from '../common';
2-
import { getEditorForUri } from '../util';
2+
import { getEditorForUri, isServerStateNode } from '../util';
33
import type { IServerManager } from '../types';
44
import type { ServerConnectionNode } from '../types/treeViewTypes';
55

@@ -21,8 +21,13 @@ export class ServerConnectionTreeDragAndDropController
2121
dataTransfer: vscode.DataTransfer,
2222
_token: vscode.CancellationToken
2323
): Promise<void> => {
24-
// Only target connection nodes
25-
if (target == null || target instanceof vscode.Uri) {
24+
// Only target connection nodes. DHE server group nodes and uri leaf nodes
25+
// are not valid editor-connection targets.
26+
if (
27+
target == null ||
28+
target instanceof vscode.Uri ||
29+
isServerStateNode(target)
30+
) {
2631
return;
2732
}
2833

src/providers/ServerConnectionPanelTreeProvider.ts

Lines changed: 38 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,15 @@ import * as vscode from 'vscode';
22
import type {
33
IPanelService,
44
IServerManager,
5-
ConnectionState,
65
ServerConnectionPanelNode,
76
} from '../types';
87
import { ServerTreeProviderBase } from './ServerTreeProviderBase';
98
import {
9+
getConnectionServerTreeItem,
10+
getConnectionTreeRootNodes,
1011
getPanelConnectionTreeItem,
1112
getPanelVariableTreeItem,
13+
isServerStateNode,
1214
sortByStringProp,
1315
} from '../util';
1416
import { getFirstSupportedConsoleType } from '../services';
@@ -27,40 +29,61 @@ export class ServerConnectionPanelTreeProvider extends ServerTreeProviderBase<Se
2729
private readonly _panelService: IPanelService;
2830

2931
getTreeItem = async (
30-
connectionOrVariable: ServerConnectionPanelNode
32+
node: ServerConnectionPanelNode
3133
): Promise<vscode.TreeItem> => {
32-
if (Array.isArray(connectionOrVariable)) {
33-
return getPanelVariableTreeItem(connectionOrVariable);
34+
// Variable leaf node.
35+
if (Array.isArray(node)) {
36+
return getPanelVariableTreeItem(node);
37+
}
38+
39+
// DHE server node grouping its worker connections.
40+
if (isServerStateNode(node)) {
41+
return getConnectionServerTreeItem(node);
3442
}
3543

3644
const serverLabel = getServerMatchPortIfLocalHost(
3745
this.serverManager,
38-
connectionOrVariable.serverUrl
46+
node.serverUrl
3947
)?.label;
4048

41-
const workerInfo = await this.serverManager.getWorkerInfo(
42-
connectionOrVariable.serverUrl
43-
);
49+
const workerInfo = await this.serverManager.getWorkerInfo(node.serverUrl);
50+
51+
// DHE worker nodes are nested under their server node (worker name as the
52+
// label); flat DHC connections keep the server label.
53+
const isWorkerChild = this.serverManager.getServerForConnection(node) != null;
4454

4555
return getPanelConnectionTreeItem(
46-
connectionOrVariable,
56+
node,
4757
getFirstSupportedConsoleType,
4858
serverLabel,
49-
workerInfo?.name
59+
workerInfo?.name,
60+
isWorkerChild
5061
);
5162
};
5263

5364
getChildren = (
54-
connectionOrRoot?: ConnectionState
65+
elementOrRoot?: ServerConnectionPanelNode
5566
): vscode.ProviderResult<ServerConnectionPanelNode[]> => {
56-
if (connectionOrRoot == null) {
67+
// Root: DHE server nodes + flat DHC connection nodes.
68+
if (elementOrRoot == null) {
69+
return getConnectionTreeRootNodes(this.serverManager);
70+
}
71+
72+
// Variable leaf nodes have no children.
73+
if (Array.isArray(elementOrRoot)) {
74+
return [];
75+
}
76+
77+
// DHE server node -> its worker connections.
78+
if (isServerStateNode(elementOrRoot)) {
5779
return this.serverManager
58-
.getConnections()
80+
.getConnections(elementOrRoot.url)
5981
.sort(sortByStringProp('serverUrl'));
6082
}
6183

62-
return [...this._panelService.getVariables(connectionOrRoot.serverUrl)]
84+
// Connection node -> its panel variables.
85+
return [...this._panelService.getVariables(elementOrRoot.serverUrl)]
6386
.sort(sortByStringProp('title'))
64-
.map(variable => [connectionOrRoot.serverUrl, variable]);
87+
.map(variable => [elementOrRoot.serverUrl, variable]);
6588
};
6689
}
Lines changed: 54 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,13 @@
11
import * as vscode from 'vscode';
22
import { ServerTreeProviderBase } from './ServerTreeProviderBase';
33
import { CONNECTION_TREE_ITEM_CONTEXT, ICON_ID } from '../common';
4-
import type {
5-
IDhcService,
6-
ConnectionState,
7-
ConsoleType,
8-
ServerConnectionNode,
9-
} from '../types';
4+
import type { ConsoleType, ServerConnectionNode } from '../types';
105
import {
6+
getConnectionServerTreeItem,
7+
getConnectionTreeRootNodes,
118
getConsoleTypeIconId,
129
isInstanceOf,
10+
isServerStateNode,
1311
sortByStringProp,
1412
} from '../util';
1513
import { DhcService } from '../services';
@@ -20,29 +18,31 @@ import { getServerMatchPortIfLocalHost } from '../mcp/utils';
2018
*/
2119
export class ServerConnectionTreeProvider extends ServerTreeProviderBase<ServerConnectionNode> {
2220
getTreeItem = async (
23-
connectionOrUri: ServerConnectionNode
21+
node: ServerConnectionNode
2422
): Promise<vscode.TreeItem> => {
2523
// Uri node associated with a parent connection node
26-
if (connectionOrUri instanceof vscode.Uri) {
24+
if (node instanceof vscode.Uri) {
2725
return {
28-
description: connectionOrUri.path,
26+
description: node.path,
2927
contextValue: CONNECTION_TREE_ITEM_CONTEXT.isUri,
3028
command: {
3129
command: 'vscode.open',
3230
title: 'Open Uri',
33-
arguments: [connectionOrUri],
31+
arguments: [node],
3432
},
35-
resourceUri: connectionOrUri,
33+
resourceUri: node,
3634
};
3735
}
3836

37+
// DHE server node grouping its worker connections.
38+
if (isServerStateNode(node)) {
39+
return getConnectionServerTreeItem(node);
40+
}
41+
3942
// Console type (language) drives the node icon rather than the description.
4043
let consoleType: ConsoleType | undefined;
41-
if (
42-
isInstanceOf(connectionOrUri, DhcService) &&
43-
connectionOrUri.isInitialized
44-
) {
45-
[consoleType] = await connectionOrUri.getConsoleTypes();
44+
if (isInstanceOf(node, DhcService) && node.isInitialized) {
45+
[consoleType] = await node.getConsoleTypes();
4646
}
4747

4848
// Prefer the persistent query name (what the DHE Query Monitor shows) over
@@ -51,25 +51,33 @@ export class ServerConnectionTreeProvider extends ServerTreeProviderBase<ServerC
5151
// diverge from their query name; the PQ name is the stable identifier in
5252
// both cases. Falls back to tagId for plain DHC connections, which have no
5353
// associated WorkerInfo.
54-
const workerInfo = await this.serverManager.getWorkerInfo(
55-
connectionOrUri.serverUrl
56-
);
57-
const description = workerInfo?.name ?? connectionOrUri.tagId ?? '';
54+
const workerInfo = await this.serverManager.getWorkerInfo(node.serverUrl);
55+
const workerName = workerInfo?.name ?? node.tagId ?? '';
56+
57+
const hasUris = this.serverManager.hasConnectionUris(node);
5858

59-
const hasUris = this.serverManager.hasConnectionUris(connectionOrUri);
59+
// DHE worker nodes are nested under their server node, so the worker name
60+
// becomes the node label and the server label lives on the parent. Flat DHC
61+
// connections keep the server label as the node label and show the worker
62+
// name as the description.
63+
const isWorkerChild = this.serverManager.getServerForConnection(node) != null;
6064

6165
const serverLabel = getServerMatchPortIfLocalHost(
6266
this.serverManager,
63-
connectionOrUri.serverUrl
67+
node.serverUrl
6468
)?.label;
6569

66-
const label = serverLabel ?? connectionOrUri.serverUrl.host;
70+
const label = isWorkerChild
71+
? workerName
72+
: (serverLabel ?? node.serverUrl.host);
73+
74+
const description = isWorkerChild ? undefined : workerName;
6775

6876
// Connection node
6977
return {
7078
label,
7179
description,
72-
contextValue: connectionOrUri.isConnected
80+
contextValue: node.isConnected
7381
? CONNECTION_TREE_ITEM_CONTEXT.isConnectionConnected
7482
: CONNECTION_TREE_ITEM_CONTEXT.isConnectionConnecting,
7583
collapsibleState: hasUris
@@ -78,22 +86,34 @@ export class ServerConnectionTreeProvider extends ServerTreeProviderBase<ServerC
7886
// Show the language (Python/Groovy) icon when idle/connected; show the
7987
// spinner while busy (connecting or running code).
8088
iconPath: new vscode.ThemeIcon(
81-
connectionOrUri.isRunningCode || !connectionOrUri.isConnected
89+
node.isRunningCode || !node.isConnected
8290
? ICON_ID.connecting
8391
: getConsoleTypeIconId(consoleType)
8492
),
8593
};
8694
};
8795

8896
getChildren = (
89-
elementOrRoot?: IDhcService
97+
elementOrRoot?: ServerConnectionNode
9098
): vscode.ProviderResult<ServerConnectionNode[]> => {
99+
// Root: DHE server nodes + flat DHC connection nodes.
91100
if (elementOrRoot == null) {
101+
return getConnectionTreeRootNodes(this.serverManager);
102+
}
103+
104+
// Uri leaf nodes have no children.
105+
if (elementOrRoot instanceof vscode.Uri) {
106+
return [];
107+
}
108+
109+
// DHE server node -> its worker connections.
110+
if (isServerStateNode(elementOrRoot)) {
92111
return this.serverManager
93-
.getConnections()
112+
.getConnections(elementOrRoot.url)
94113
.sort(sortByStringProp('serverUrl'));
95114
}
96115

116+
// Connection node -> its editor uris.
97117
return this.serverManager.getConnectionUris(elementOrRoot);
98118
};
99119

@@ -102,11 +122,16 @@ export class ServerConnectionTreeProvider extends ServerTreeProviderBase<ServerC
102122
* for `TreeView.reveal` method to work.
103123
* @param element
104124
*/
105-
getParent = (element: ServerConnectionNode): ConnectionState | null => {
125+
getParent = (element: ServerConnectionNode): ServerConnectionNode | null => {
106126
if (element instanceof vscode.Uri) {
107127
return this.serverManager.getUriConnection(element);
108128
}
109129

110-
return null;
130+
if (isServerStateNode(element)) {
131+
return null;
132+
}
133+
134+
// Connection node -> its parent DHE server (or null for flat DHC).
135+
return this.serverManager.getServerForConnection(element) ?? null;
111136
};
112137
}

src/services/ServerManager.ts

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -695,6 +695,23 @@ export class ServerManager implements IServerManager {
695695
});
696696
};
697697

698+
/**
699+
* Get the parent DHE server for a connection. Returns the DHE server state
700+
* when the connection is a DHE worker (its `serverUrl` is mapped to a DHE
701+
* server URL), or `undefined` for DHC connections, which have no parent
702+
* server node in the tree.
703+
* @param connection The connection to get the parent server for.
704+
* @returns The parent DHE server state, or `undefined`.
705+
*/
706+
getServerForConnection = (
707+
connection: ConnectionState
708+
): ServerState | undefined => {
709+
const dheServerUrl = this._workerURLToServerURLMap.get(
710+
connection.serverUrl
711+
);
712+
return dheServerUrl == null ? undefined : this.getServer(dheServerUrl);
713+
};
714+
698715
/**
699716
* Get all URIs associated with a connection.
700717
* @param connection

src/types/serviceTypes.d.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -190,6 +190,14 @@ export interface IServerManager extends IDisposable {
190190
getConnection: (serverUrl: URL) => ConnectionState | undefined;
191191
getConnections: (serverOrWorkerUrl?: URL) => ConnectionState[];
192192
getConnectionUris: (connection: ConnectionState) => vscode.Uri[];
193+
/**
194+
* Get the parent DHE server for a connection. Returns the DHE `ServerState`
195+
* when the connection is a DHE worker, or `undefined` for DHC connections
196+
* (which have no parent server node in the tree).
197+
*/
198+
getServerForConnection: (
199+
connection: ConnectionState
200+
) => ServerState | undefined;
193201
getDheServiceForWorker: (maybeWorkerUrl: URL) => Promise<IDheService | null>;
194202
getEditorConnection: (uri: vscode.Uri) => Promise<ConnectionState | null>;
195203
getWorkerCredentials: (

src/types/treeViewTypes.d.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,12 +9,13 @@ export type ServerGroupState = 'Managed' | 'Running' | 'Stopped';
99
export type ServerNode = ServerGroupState | ServerState;
1010
export interface ServerTreeView extends vscode.TreeView<ServerNode> {}
1111

12-
export type ServerConnectionNode = ConnectionState | vscode.Uri;
12+
export type ServerConnectionNode = ServerState | ConnectionState | vscode.Uri;
1313

1414
export interface ServerConnectionTreeView
1515
extends vscode.TreeView<ServerConnectionNode> {}
1616

1717
export type ServerConnectionPanelNode =
18+
| ServerState
1819
| ConnectionState
1920
| [URL, VariableDefintion];
2021

0 commit comments

Comments
 (0)