From 7e0d7e647b2f845c046dd72b8d7e0736e5c6e6fc Mon Sep 17 00:00:00 2001 From: Brian Ingles Date: Thu, 5 Sep 2024 10:01:52 -0500 Subject: [PATCH 01/40] assertIsVariableDefinition (#116-2) --- src/util/assertUtil.ts | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/src/util/assertUtil.ts b/src/util/assertUtil.ts index 7710d15b..6ec1b09d 100644 --- a/src/util/assertUtil.ts +++ b/src/util/assertUtil.ts @@ -1,4 +1,5 @@ -import type { VariableID } from '../types'; +import type { dh as DhcType } from '@deephaven/jsapi-types'; +import type { VariableDefintion, VariableID } from '../types'; /** * Assert that a given value is not `null` or `undefined`. @@ -37,3 +38,24 @@ export function assertIsVariableID( throw new Error(`'${name}' is not a valid VariableID`); } } + +/** + * Assert that given object is a VariableDefinition. This is mostly a type guard + * to help the type system infer stricter types for `id` and `type` props than + * specified by the Dh types. + * @param maybeVariableDefinition + */ +export function assertIsVariableDefintion( + maybeVariableDefinition: DhcType.ide.VariableDefinition +): asserts maybeVariableDefinition is VariableDefintion { + const { name, description, id, type, title, applicationId, applicationName } = + maybeVariableDefinition; + + if ( + [name, description, id, type, title, applicationId, applicationName].some( + v => typeof v !== 'string' + ) + ) { + throw new Error('Invalid VariableDefinition'); + } +} From 137bd4a90644c0b306c9f1aeedcff51910b57c84 Mon Sep 17 00:00:00 2001 From: Brian Ingles Date: Thu, 5 Sep 2024 10:02:48 -0500 Subject: [PATCH 02/40] Removed assertion utils (#116-2) --- src/util/assertUtil.ts | 37 ------------------------------------- 1 file changed, 37 deletions(-) diff --git a/src/util/assertUtil.ts b/src/util/assertUtil.ts index 6ec1b09d..5649adb9 100644 --- a/src/util/assertUtil.ts +++ b/src/util/assertUtil.ts @@ -1,6 +1,3 @@ -import type { dh as DhcType } from '@deephaven/jsapi-types'; -import type { VariableDefintion, VariableID } from '../types'; - /** * Assert that a given value is not `null` or `undefined`. * @param dependency The value to assert. @@ -25,37 +22,3 @@ export function assertNever(shouldBeNever: never, name?: string): never { const label = name == null ? 'value' : `'${name}'`; throw new Error(`Unexpected ${label}: ${shouldBeNever}`); } - -/** - * Assert that given variable is a `VariableID`. - * @param maybeVariableId - */ -export function assertIsVariableID( - maybeVariableId: string | null | undefined, - name: string -): asserts maybeVariableId is VariableID { - if (typeof maybeVariableId !== 'string') { - throw new Error(`'${name}' is not a valid VariableID`); - } -} - -/** - * Assert that given object is a VariableDefinition. This is mostly a type guard - * to help the type system infer stricter types for `id` and `type` props than - * specified by the Dh types. - * @param maybeVariableDefinition - */ -export function assertIsVariableDefintion( - maybeVariableDefinition: DhcType.ide.VariableDefinition -): asserts maybeVariableDefinition is VariableDefintion { - const { name, description, id, type, title, applicationId, applicationName } = - maybeVariableDefinition; - - if ( - [name, description, id, type, title, applicationId, applicationName].some( - v => typeof v !== 'string' - ) - ) { - throw new Error('Invalid VariableDefinition'); - } -} From f767c6eeb2d222dcb2b807e6beeb03e4c3bfeecd Mon Sep 17 00:00:00 2001 From: Brian Ingles Date: Fri, 6 Sep 2024 09:58:43 -0500 Subject: [PATCH 03/40] Split out treeviewutils and added some variable panel utils (#116-2) --- src/types/commonTypes.d.ts | 7 ++++++ src/types/treeViewTypes.d.ts | 6 +++++- src/util/serverUtils.ts | 12 +++++++++++ src/util/treeViewUtils.ts | 42 +++++++++++++++++++++++++++++++++++- 4 files changed, 65 insertions(+), 2 deletions(-) diff --git a/src/types/commonTypes.d.ts b/src/types/commonTypes.d.ts index aa8f1842..ce89469b 100644 --- a/src/types/commonTypes.d.ts +++ b/src/types/commonTypes.d.ts @@ -79,8 +79,15 @@ export type VariableDefintion = DhcType.ide.VariableDefinition & { type: VariableType; }; +export type VariableMap = Map; export type VariablePanelMap = Map; +export interface VariableChanges { + readonly created: VariableDefintion[]; + readonly removed: VariableDefintion[]; + readonly updated: VariableDefintion[]; +} + export type VariableType = | 'Figure' | 'deephaven.plot.express.DeephavenFigure' diff --git a/src/types/treeViewTypes.d.ts b/src/types/treeViewTypes.d.ts index 4ee3e324..06bb6f19 100644 --- a/src/types/treeViewTypes.d.ts +++ b/src/types/treeViewTypes.d.ts @@ -1,6 +1,6 @@ import * as vscode from 'vscode'; import type { IDhService } from './serviceTypes'; -import type { ServerState } from './commonTypes'; +import type { ServerState, VariableDefintion } from './commonTypes'; export type ServerGroupState = 'Managed' | 'Running' | 'Stopped'; export type ServerNode = ServerGroupState | ServerState; @@ -9,3 +9,7 @@ export interface ServerTreeView extends vscode.TreeView {} export type ServerConnectionNode = IDhService | vscode.Uri; export interface ServerConnectionTreeView extends vscode.TreeView {} + +export type ServerConnectionPanelNode = IDhService | VariableDefintion; +export interface ServerConnectionPanelTreeView + extends vscode.TreeView {} diff --git a/src/util/serverUtils.ts b/src/util/serverUtils.ts index 9334ac88..5042a458 100644 --- a/src/util/serverUtils.ts +++ b/src/util/serverUtils.ts @@ -131,3 +131,15 @@ export function parsePort(portStr: string): Port { return parsed as Port; } + +/** + * Sort comparator for sorting by `serverUrl`. + * @param a + * @param b + */ +export function sortByServerUrl( + a: { serverUrl: URL }, + b: { serverUrl: URL } +): number { + return a.serverUrl.toString().localeCompare(b.serverUrl.toString()); +} diff --git a/src/util/treeViewUtils.ts b/src/util/treeViewUtils.ts index 2d6ba90a..c06904c3 100644 --- a/src/util/treeViewUtils.ts +++ b/src/util/treeViewUtils.ts @@ -1,11 +1,51 @@ import * as vscode from 'vscode'; -import type { ServerGroupState, ServerState } from '../types'; +import type { + IDhService, + ServerGroupState, + ServerState, + VariableDefintion, +} from '../types'; import { ICON_ID, SERVER_TREE_ITEM_CONTEXT, + VARIABLE_ICONS, type ServerTreeItemContextValue, } from '../common'; +/** + * Get `TreeItem` for a panel connection. + * @param connection + */ +export function getPanelConnectionTreeItem( + connection: IDhService +): vscode.TreeItem { + return { + label: new URL(connection.serverUrl.toString()).host, + // description: consoleType, + // contextValue: CONNECTION_TREE_ITEM_CONTEXT.isConnection, + // collapsibleState: hasUris + // ? vscode.TreeItemCollapsibleState.Expanded + // : undefined, + collapsibleState: vscode.TreeItemCollapsibleState.Expanded, + iconPath: new vscode.ThemeIcon( + connection.isConnected ? ICON_ID.connected : ICON_ID.connecting + ), + }; +} + +/** + * Get `TreeItem` for a panel variable. + * @param variable + */ +export function getPanelVariableTreeItem( + variable: VariableDefintion +): vscode.TreeItem { + const icon = VARIABLE_ICONS[variable.type]; + return { + description: icon == null ? variable.title : `${icon} ${variable.title}`, + }; +} + /** * Get `contextValue` for server tree items. * @param isConnected Whether the server is connected From 255b670209731f6f72549e0f334691f2f0f9fa68 Mon Sep 17 00:00:00 2001 From: Brian Ingles Date: Fri, 6 Sep 2024 13:57:11 -0500 Subject: [PATCH 04/40] Show variables associated with connections (#116-2) --- package.json | 5 ++ src/common/constants.ts | 15 +++++ src/controllers/ExtensionController.ts | 29 +++++++++- .../ServerConnectionPanelTreeProvider.ts | 50 +++++++++++++++++ src/providers/ServerConnectionTreeProvider.ts | 13 ++--- src/providers/ServerTreeProvider.ts | 6 +- src/providers/TreeDataProviderBase.ts | 10 +++- src/providers/index.ts | 1 + src/services/DhService.ts | 8 +++ src/services/PanelService.ts | 56 +++++++++++++++++++ src/types/serviceTypes.d.ts | 5 ++ src/util/dataUtils.ts | 15 +++++ src/util/index.ts | 1 + src/util/serverUtils.ts | 12 ---- src/util/treeViewUtils.ts | 6 +- 15 files changed, 202 insertions(+), 30 deletions(-) create mode 100644 src/providers/ServerConnectionPanelTreeProvider.ts create mode 100644 src/util/dataUtils.ts diff --git a/package.json b/package.json index 1e974b5a..0dabaa03 100644 --- a/package.json +++ b/package.json @@ -707,6 +707,11 @@ "id": "vscode-deephaven.serverConnectionTree", "name": "Connections", "type": "tree" + }, + { + "id": "vscode-deephaven.serverConnectionPanelTree", + "name": "Panels", + "type": "tree" } ] } diff --git a/src/common/constants.ts b/src/common/constants.ts index 47c9e705..9a596d00 100644 --- a/src/common/constants.ts +++ b/src/common/constants.ts @@ -48,6 +48,7 @@ export const TMP_DIR_ROOT = path.join(__dirname, '..', 'tmp'); export const VIEW_ID = { serverTree: `${EXTENSION_ID}.serverTree`, serverConnectionTree: `${EXTENSION_ID}.serverConnectionTree`, + serverConnectionPanelTree: `${EXTENSION_ID}.serverConnectionPanelTree`, } as const; export const ICON_ID = { @@ -61,6 +62,11 @@ export const ICON_ID = { serverConnected: 'circle-large-filled', serverRunning: 'circle-large-outline', serverStopped: 'circle-slash', + table: 'table', + varFigure: 'graph-line', + varExpFigure: 'pie-chart', + varTable: 'preview', + varElement: 'extensions', } as const; /* eslint-disable @typescript-eslint/naming-convention */ @@ -72,6 +78,15 @@ export const VARIABLE_UNICODE_ICONS = { } as const satisfies Record; /* eslint-enable @typescript-eslint/naming-convention */ +/* eslint-disable @typescript-eslint/naming-convention */ +export const VARIABLE_ICONS = { + 'deephaven.plot.express.DeephavenFigure': ICON_ID.varExpFigure, + 'deephaven.ui.Element': ICON_ID.varElement, + Figure: ICON_ID.varFigure, + Table: ICON_ID.varTable, +} as const satisfies Record; +/* eslint-enable @typescript-eslint/naming-convention */ + export const CONNECTION_TREE_ITEM_CONTEXT = { isConnection: 'isConnection', isUri: 'isUri', diff --git a/src/controllers/ExtensionController.ts b/src/controllers/ExtensionController.ts index 509d9024..29515d6f 100644 --- a/src/controllers/ExtensionController.ts +++ b/src/controllers/ExtensionController.ts @@ -30,6 +30,7 @@ import { RunCommandCodeLensProvider, ServerTreeProvider, ServerConnectionTreeProvider, + ServerConnectionPanelTreeProvider, runSelectedLinesHoverProvider, } from '../providers'; import { DhcServiceFactory, PanelService, ServerManager } from '../services'; @@ -41,6 +42,7 @@ import type { IPanelService, IServerManager, IToastService, + ServerConnectionPanelTreeView, ServerConnectionTreeView, ServerState, ServerTreeView, @@ -89,11 +91,19 @@ export class ExtensionController implements Disposable { private _pipServerController: PipServerController | null = null; private _dhcServiceFactory: IDhServiceFactory | null = null; private _serverManager: IServerManager | null = null; + + // Tree providers private _serverTreeProvider: ServerTreeProvider | null = null; private _serverConnectionTreeProvider: ServerConnectionTreeProvider | null = null; + private _serverConnectionPanelTreeProvider: ServerConnectionPanelTreeProvider | null = + null; + + // Tree views private _serverTreeView: ServerTreeView | null = null; private _serverConnectionTreeView: ServerConnectionTreeView | null = null; + private _serverConnectionPanelTreeView: ServerConnectionPanelTreeView | null = + null; private _pythonDiagnostics: vscode.DiagnosticCollection | null = null; private _outputChannel: vscode.OutputChannel | null = null; @@ -349,6 +359,7 @@ export class ExtensionController implements Disposable { * Register web views for the extension. */ initializeWebViews = (): void => { + assertDefined(this._panelService, 'panelService'); assertDefined(this._serverManager, 'serverManager'); // Server tree @@ -374,10 +385,24 @@ export class ExtensionController implements Disposable { } ); + // Connection Panel tree + this._serverConnectionPanelTreeProvider = + new ServerConnectionPanelTreeProvider( + this._serverManager, + this._panelService + ); + this._serverConnectionPanelTreeView = vscode.window.createTreeView( + VIEW_ID.serverConnectionPanelTree, + { + showCollapseAll: true, + treeDataProvider: this._serverConnectionPanelTreeProvider, + } + ); + this._context.subscriptions.push( - this._serverManager, this._serverTreeView, - this._serverConnectionTreeView + this._serverConnectionTreeView, + this._serverConnectionPanelTreeView ); }; diff --git a/src/providers/ServerConnectionPanelTreeProvider.ts b/src/providers/ServerConnectionPanelTreeProvider.ts new file mode 100644 index 00000000..960781bd --- /dev/null +++ b/src/providers/ServerConnectionPanelTreeProvider.ts @@ -0,0 +1,50 @@ +import * as vscode from 'vscode'; +import type { + IDhService, + IPanelService, + IServerManager, + ServerConnectionPanelNode, +} from '../types'; +import { TreeDataProviderBase } from './TreeDataProviderBase'; +import { + getPanelConnectionTreeItem, + getPanelVariableTreeItem, + sortByStringProp, +} from '../util'; + +export class ServerConnectionPanelTreeProvider extends TreeDataProviderBase { + constructor(serverManager: IServerManager, panelService: IPanelService) { + super(serverManager); + this._panelService = panelService; + + this._panelService.onDidUpdate(() => { + this._onDidChangeTreeData.fire(); + }); + } + + private readonly _panelService: IPanelService; + + getTreeItem = async ( + connectionOrVariable: ServerConnectionPanelNode + ): Promise => { + if ('id' in connectionOrVariable) { + return getPanelVariableTreeItem(connectionOrVariable); + } + + return getPanelConnectionTreeItem(connectionOrVariable); + }; + + getChildren = ( + connectionOrRoot?: IDhService + ): vscode.ProviderResult => { + if (connectionOrRoot == null) { + return this.serverManager + .getConnections() + .sort(sortByStringProp('serverUrl')); + } + + return [ + ...this._panelService.getVariables(connectionOrRoot.serverUrl), + ].sort((a, b) => a.title.localeCompare(b.title)); + }; +} diff --git a/src/providers/ServerConnectionTreeProvider.ts b/src/providers/ServerConnectionTreeProvider.ts index cf7a43cc..e4385394 100644 --- a/src/providers/ServerConnectionTreeProvider.ts +++ b/src/providers/ServerConnectionTreeProvider.ts @@ -2,14 +2,15 @@ import * as vscode from 'vscode'; import { TreeDataProviderBase } from './TreeDataProviderBase'; import { CONNECTION_TREE_ITEM_CONTEXT, ICON_ID } from '../common'; import type { IDhService, ServerConnectionNode } from '../types'; +import { sortByStringProp } from '../util'; /** * Provider for the server connection tree view. */ export class ServerConnectionTreeProvider extends TreeDataProviderBase { - async getTreeItem( + getTreeItem = async ( connectionOrUri: ServerConnectionNode - ): Promise { + ): Promise => { // Uri node associated with a parent connection node if (connectionOrUri instanceof vscode.Uri) { return { @@ -41,17 +42,15 @@ export class ServerConnectionTreeProvider extends TreeDataProviderBase => { + ): vscode.ProviderResult => { if (elementOrRoot == null) { return this.serverManager .getConnections() - .sort((a, b) => - a.serverUrl.toString().localeCompare(b.serverUrl.toString()) - ); + .sort(sortByStringProp('serverUrl')); } return this.serverManager.getConnectionUris(elementOrRoot); diff --git a/src/providers/ServerTreeProvider.ts b/src/providers/ServerTreeProvider.ts index b0544cec..24dbe0d7 100644 --- a/src/providers/ServerTreeProvider.ts +++ b/src/providers/ServerTreeProvider.ts @@ -16,9 +16,7 @@ function isServerGroupState(node: ServerNode): node is ServerGroupState { * Provider for the server tree view. */ export class ServerTreeProvider extends TreeDataProviderBase { - getTreeItem( - element: ServerNode - ): vscode.TreeItem | Thenable { + getTreeItem = (element: ServerNode): vscode.TreeItem => { if (isServerGroupState(element)) { return getServerGroupTreeItem(element, this.serverManager.canStartServer); } @@ -33,7 +31,7 @@ export class ServerTreeProvider extends TreeDataProviderBase { isManaged, isRunning, }); - } + }; getChildren(elementOrRoot?: ServerNode): vscode.ProviderResult { const { managed, running, stopped } = groupServers( diff --git a/src/providers/TreeDataProviderBase.ts b/src/providers/TreeDataProviderBase.ts index b6d620ca..f790421b 100644 --- a/src/providers/TreeDataProviderBase.ts +++ b/src/providers/TreeDataProviderBase.ts @@ -7,13 +7,17 @@ import type { IServerManager } from '../types'; export abstract class TreeDataProviderBase implements vscode.TreeDataProvider { - constructor(readonly serverManager: IServerManager) { - serverManager.onDidUpdate(() => { + constructor(serverManager: IServerManager) { + this.serverManager = serverManager; + + this.serverManager.onDidUpdate(() => { this._onDidChangeTreeData.fire(); }); } - private readonly _onDidChangeTreeData = new vscode.EventEmitter< + protected readonly serverManager: IServerManager; + + protected readonly _onDidChangeTreeData = new vscode.EventEmitter< T | undefined | void >(); diff --git a/src/providers/index.ts b/src/providers/index.ts index a44ad351..48c9fe8a 100644 --- a/src/providers/index.ts +++ b/src/providers/index.ts @@ -2,4 +2,5 @@ export * from './RunCommandCodeLensProvider'; export * from './RunSelectedLinesHoverProvider'; export * from './ServerConnectionTreeProvider'; export * from './ServerTreeProvider'; +export * from './ServerConnectionPanelTreeProvider'; export * from './TreeDataProviderBase'; diff --git a/src/services/DhService.ts b/src/services/DhService.ts index 3cd97aa7..3fa95b09 100644 --- a/src/services/DhService.ts +++ b/src/services/DhService.ts @@ -6,6 +6,7 @@ import type { ConsoleType, IDhService, IToastService, + VariableChanges, VariableDefintion, } from '../types'; import { @@ -148,6 +149,13 @@ export abstract class DhService try { const { cn, session } = await this.cachedCreateSession; + cn.subscribeToFieldUpdates(changes => { + this.panelService.updateVariables( + this.serverUrl, + changes as VariableChanges + ); + }); + // TODO: Use constant 'disconnect' event name this.subscriptions.push( cn.addEventListener('disconnect', () => { diff --git a/src/services/PanelService.ts b/src/services/PanelService.ts index 62dffd93..bfdcc680 100644 --- a/src/services/PanelService.ts +++ b/src/services/PanelService.ts @@ -3,16 +3,24 @@ import { URLMap } from './URLMap'; import type { Disposable, IPanelService, + VariableChanges, + VariableDefintion, VariableID, + VariableMap, VariablePanelMap, } from '../types'; export class PanelService implements IPanelService, Disposable { constructor() { this._cnPanelMap = new URLMap(); + this._cnVariableMap = new URLMap(); } + private readonly _onDidUpdate = new vscode.EventEmitter(); + readonly onDidUpdate = this._onDidUpdate.event; + private readonly _cnPanelMap: URLMap; + private readonly _cnVariableMap: URLMap; dispose = async (): Promise => { this._cnPanelMap.clear(); @@ -69,4 +77,52 @@ export class PanelService implements IPanelService, Disposable { this._cnPanelMap.get(url)!.set(variableId, panel); }; + + /** + * Get variables for the given connection url. + * @param url + */ + getVariables = (url: URL): Iterable => { + return this._cnVariableMap.get(url)?.values() ?? []; + }; + + /** + * Update the variables for the given connection url. + * @param url + * @param variableChanges + */ + updateVariables = ( + url: URL, + { created, removed, updated }: VariableChanges + ): void => { + console.log( + '[TESTING] update:', + JSON.stringify({ created, removed, updated }) + ); + + if (!this._cnVariableMap.has(url)) { + this._cnVariableMap.set(url, new Map()); + } + + // if (!this._cnPanelMap.has(url)) { + // this._cnPanelMap.set(url, new Map()); + // } + + // const panelMap = this._cnPanelMap.get(url)!; + const variableMap = this._cnVariableMap.get(url)!; + + for (const variable of created) { + variableMap.set(variable.id, variable); + } + + for (const variable of removed) { + variableMap.delete(variable.id); + } + + for (const variable of updated) { + variableMap.set(variable.id, variable); + } + + this._onDidUpdate.fire(); + }; } diff --git a/src/types/serviceTypes.d.ts b/src/types/serviceTypes.d.ts index aeb273a0..a2c8d6c0 100644 --- a/src/types/serviceTypes.d.ts +++ b/src/types/serviceTypes.d.ts @@ -8,6 +8,7 @@ import type { ServerConnection, ServerState, UnsubscribeEventListener, + VariableChanges, VariableDefintion, VariableID, } from '../types/commonTypes'; @@ -66,6 +67,8 @@ export type IDhServiceFactory = IFactory< >; export interface IPanelService extends Disposable { + readonly onDidUpdate: vscode.Event; + getPanelOrThrow: (url: URL, variableId: VariableID) => vscode.WebviewPanel; deletePanel: (url: URL, variableId: VariableID) => void; hasPanel: (url: URL, variableId: VariableID) => boolean; @@ -74,6 +77,8 @@ export interface IPanelService extends Disposable { variableId: VariableID, panel: vscode.WebviewPanel ) => void; + getVariables: (url: URL) => Iterable; + updateVariables: (url: URL, changes: VariableChanges) => void; } /** diff --git a/src/util/dataUtils.ts b/src/util/dataUtils.ts new file mode 100644 index 00000000..1acb9f3f --- /dev/null +++ b/src/util/dataUtils.ts @@ -0,0 +1,15 @@ +/** + * Create a sort comparator function that compares a stringified property on + * 2 objects. + * @param propName Prop to compare + */ +export function sortByStringProp( + propName: TPropName +) { + return ( + a: TValue, + b: TValue + ): number => { + return String(a[propName]).localeCompare(String(b[propName])); + }; +} diff --git a/src/util/index.ts b/src/util/index.ts index fde7eca2..b4794c4c 100644 --- a/src/util/index.ts +++ b/src/util/index.ts @@ -1,4 +1,5 @@ export * from './assertUtil'; +export * from './dataUtils'; export * from './downloadUtils'; export * from './errorUtils'; export * from './ErrorTypes'; diff --git a/src/util/serverUtils.ts b/src/util/serverUtils.ts index 5042a458..9334ac88 100644 --- a/src/util/serverUtils.ts +++ b/src/util/serverUtils.ts @@ -131,15 +131,3 @@ export function parsePort(portStr: string): Port { return parsed as Port; } - -/** - * Sort comparator for sorting by `serverUrl`. - * @param a - * @param b - */ -export function sortByServerUrl( - a: { serverUrl: URL }, - b: { serverUrl: URL } -): number { - return a.serverUrl.toString().localeCompare(b.serverUrl.toString()); -} diff --git a/src/util/treeViewUtils.ts b/src/util/treeViewUtils.ts index c06904c3..c1fe8c9c 100644 --- a/src/util/treeViewUtils.ts +++ b/src/util/treeViewUtils.ts @@ -40,9 +40,11 @@ export function getPanelConnectionTreeItem( export function getPanelVariableTreeItem( variable: VariableDefintion ): vscode.TreeItem { - const icon = VARIABLE_ICONS[variable.type]; + const iconId = VARIABLE_ICONS[variable.type]; + return { - description: icon == null ? variable.title : `${icon} ${variable.title}`, + description: variable.title, + iconPath: iconId == null ? undefined : new vscode.ThemeIcon(iconId), }; } From 0e49793f01a0f2ba4c630b1e934651c03dbc356b Mon Sep 17 00:00:00 2001 From: Brian Ingles Date: Fri, 6 Sep 2024 10:09:26 -0500 Subject: [PATCH 05/40] Started wiring up open panel cmd (#116-2) --- src/providers/ServerConnectionPanelTreeProvider.ts | 8 ++++---- src/services/PanelService.ts | 5 ----- src/types/treeViewTypes.d.ts | 2 +- src/util/treeViewUtils.ts | 13 ++++++++++--- 4 files changed, 15 insertions(+), 13 deletions(-) diff --git a/src/providers/ServerConnectionPanelTreeProvider.ts b/src/providers/ServerConnectionPanelTreeProvider.ts index 960781bd..2f7d6016 100644 --- a/src/providers/ServerConnectionPanelTreeProvider.ts +++ b/src/providers/ServerConnectionPanelTreeProvider.ts @@ -27,7 +27,7 @@ export class ServerConnectionPanelTreeProvider extends TreeDataProviderBase => { - if ('id' in connectionOrVariable) { + if (Array.isArray(connectionOrVariable)) { return getPanelVariableTreeItem(connectionOrVariable); } @@ -43,8 +43,8 @@ export class ServerConnectionPanelTreeProvider extends TreeDataProviderBase a.title.localeCompare(b.title)); + return [...this._panelService.getVariables(connectionOrRoot.serverUrl)] + .sort((a, b) => a.title.localeCompare(b.title)) + .map(variable => [connectionOrRoot.serverUrl, variable]); }; } diff --git a/src/services/PanelService.ts b/src/services/PanelService.ts index bfdcc680..9d51182e 100644 --- a/src/services/PanelService.ts +++ b/src/services/PanelService.ts @@ -95,11 +95,6 @@ export class PanelService implements IPanelService, Disposable { url: URL, { created, removed, updated }: VariableChanges ): void => { - console.log( - '[TESTING] update:', - JSON.stringify({ created, removed, updated }) - ); - if (!this._cnVariableMap.has(url)) { this._cnVariableMap.set(url, new Map()); } diff --git a/src/types/treeViewTypes.d.ts b/src/types/treeViewTypes.d.ts index 06bb6f19..bd2d0ffc 100644 --- a/src/types/treeViewTypes.d.ts +++ b/src/types/treeViewTypes.d.ts @@ -10,6 +10,6 @@ export type ServerConnectionNode = IDhService | vscode.Uri; export interface ServerConnectionTreeView extends vscode.TreeView {} -export type ServerConnectionPanelNode = IDhService | VariableDefintion; +export type ServerConnectionPanelNode = IDhService | [URL, VariableDefintion]; export interface ServerConnectionPanelTreeView extends vscode.TreeView {} diff --git a/src/util/treeViewUtils.ts b/src/util/treeViewUtils.ts index c1fe8c9c..69ed1f70 100644 --- a/src/util/treeViewUtils.ts +++ b/src/util/treeViewUtils.ts @@ -7,6 +7,7 @@ import type { } from '../types'; import { ICON_ID, + OPEN_VARIABLE_PANEL_CMD, SERVER_TREE_ITEM_CONTEXT, VARIABLE_ICONS, type ServerTreeItemContextValue, @@ -37,14 +38,20 @@ export function getPanelConnectionTreeItem( * Get `TreeItem` for a panel variable. * @param variable */ -export function getPanelVariableTreeItem( - variable: VariableDefintion -): vscode.TreeItem { +export function getPanelVariableTreeItem([url, variable]: [ + URL, + VariableDefintion, +]): vscode.TreeItem { const iconId = VARIABLE_ICONS[variable.type]; return { description: variable.title, iconPath: iconId == null ? undefined : new vscode.ThemeIcon(iconId), + command: { + title: 'Open Panel', + command: OPEN_VARIABLE_PANEL_CMD, + arguments: [url, variable], + }, }; } From 30cf04cb284d47e48593be0bc19ab4b5ddf8d176 Mon Sep 17 00:00:00 2001 From: Brian Ingles Date: Fri, 6 Sep 2024 10:17:06 -0500 Subject: [PATCH 06/40] Fixed type (#116-2) --- src/controllers/ExtensionController.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/controllers/ExtensionController.ts b/src/controllers/ExtensionController.ts index 29515d6f..1e01a58c 100644 --- a/src/controllers/ExtensionController.ts +++ b/src/controllers/ExtensionController.ts @@ -391,7 +391,8 @@ export class ExtensionController implements Disposable { this._serverManager, this._panelService ); - this._serverConnectionPanelTreeView = vscode.window.createTreeView( + this._serverConnectionPanelTreeView = + vscode.window.createTreeView( VIEW_ID.serverConnectionPanelTree, { showCollapseAll: true, From c4bf77e721e9b1c45d1b7af66455c0ba5f2cb327 Mon Sep 17 00:00:00 2001 From: Brian Ingles Date: Fri, 6 Sep 2024 10:18:14 -0500 Subject: [PATCH 07/40] Import missing type (#116-2) --- src/controllers/ExtensionController.ts | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/src/controllers/ExtensionController.ts b/src/controllers/ExtensionController.ts index 1e01a58c..116bccba 100644 --- a/src/controllers/ExtensionController.ts +++ b/src/controllers/ExtensionController.ts @@ -42,6 +42,7 @@ import type { IPanelService, IServerManager, IToastService, + ServerConnectionPanelNode, ServerConnectionPanelTreeView, ServerConnectionTreeView, ServerState, @@ -393,12 +394,12 @@ export class ExtensionController implements Disposable { ); this._serverConnectionPanelTreeView = vscode.window.createTreeView( - VIEW_ID.serverConnectionPanelTree, - { - showCollapseAll: true, - treeDataProvider: this._serverConnectionPanelTreeProvider, - } - ); + VIEW_ID.serverConnectionPanelTree, + { + showCollapseAll: true, + treeDataProvider: this._serverConnectionPanelTreeProvider, + } + ); this._context.subscriptions.push( this._serverTreeView, From c435fcd17a71bd1705ac23dfb3e144491b722be8 Mon Sep 17 00:00:00 2001 From: Brian Ingles Date: Fri, 6 Sep 2024 14:04:38 -0500 Subject: [PATCH 08/40] Added panelService back to DhService (#116-2) --- src/controllers/ExtensionController.ts | 1 + src/services/DhService.ts | 4 ++++ src/services/DhcServiceFactory.ts | 4 +++- src/util/treeViewUtils.ts | 4 ++-- 4 files changed, 10 insertions(+), 3 deletions(-) diff --git a/src/controllers/ExtensionController.ts b/src/controllers/ExtensionController.ts index 116bccba..83563b20 100644 --- a/src/controllers/ExtensionController.ts +++ b/src/controllers/ExtensionController.ts @@ -250,6 +250,7 @@ export class ExtensionController implements Disposable { this._context.subscriptions.push(this._panelService); this._dhcServiceFactory = new DhcServiceFactory( + this._panelService, this._pythonDiagnostics, this._outputChannel, this._toaster diff --git a/src/services/DhService.ts b/src/services/DhService.ts index 3fa95b09..9bf358e8 100644 --- a/src/services/DhService.ts +++ b/src/services/DhService.ts @@ -5,6 +5,7 @@ import type { ConnectionAndSession, ConsoleType, IDhService, + IPanelService, IToastService, VariableChanges, VariableDefintion, @@ -26,11 +27,13 @@ export abstract class DhService { constructor( serverUrl: URL, + panelService: IPanelService, diagnosticsCollection: vscode.DiagnosticCollection, outputChannel: vscode.OutputChannel, toaster: IToastService ) { this.serverUrl = serverUrl; + this.panelService = panelService; this.diagnosticsCollection = diagnosticsCollection; this.outputChannel = outputChannel; this.toaster = toaster; @@ -44,6 +47,7 @@ export abstract class DhService protected readonly outputChannel: vscode.OutputChannel; protected readonly toaster: IToastService; + private readonly panelService: IPanelService; private readonly diagnosticsCollection: vscode.DiagnosticCollection; private cachedCreateClient: Promise | null = null; private cachedCreateSession: Promise< diff --git a/src/services/DhcServiceFactory.ts b/src/services/DhcServiceFactory.ts index b3f30ade..de121508 100644 --- a/src/services/DhcServiceFactory.ts +++ b/src/services/DhcServiceFactory.ts @@ -1,12 +1,13 @@ import * as vscode from 'vscode'; import { DhcService } from './DhcService'; -import type { IDhServiceFactory, IToastService } from '../types'; +import type { IDhServiceFactory, IPanelService, IToastService } from '../types'; /** * Factory for creating DhcService instances. */ export class DhcServiceFactory implements IDhServiceFactory { constructor( + private panelService: IPanelService, private diagnosticsCollection: vscode.DiagnosticCollection, private outputChannel: vscode.OutputChannel, private toaster: IToastService @@ -15,6 +16,7 @@ export class DhcServiceFactory implements IDhServiceFactory { create = (serverUrl: URL, psk?: string): DhcService => { const dhService = new DhcService( serverUrl, + this.panelService, this.diagnosticsCollection, this.outputChannel, this.toaster diff --git a/src/util/treeViewUtils.ts b/src/util/treeViewUtils.ts index 69ed1f70..3b9a8202 100644 --- a/src/util/treeViewUtils.ts +++ b/src/util/treeViewUtils.ts @@ -7,7 +7,7 @@ import type { } from '../types'; import { ICON_ID, - OPEN_VARIABLE_PANEL_CMD, + OPEN_VARIABLE_PANELS_CMD, SERVER_TREE_ITEM_CONTEXT, VARIABLE_ICONS, type ServerTreeItemContextValue, @@ -49,7 +49,7 @@ export function getPanelVariableTreeItem([url, variable]: [ iconPath: iconId == null ? undefined : new vscode.ThemeIcon(iconId), command: { title: 'Open Panel', - command: OPEN_VARIABLE_PANEL_CMD, + command: OPEN_VARIABLE_PANELS_CMD, arguments: [url, variable], }, }; From fe76577323a4b74e45cc08dff185b6402e2738d1 Mon Sep 17 00:00:00 2001 From: Brian Ingles Date: Fri, 6 Sep 2024 16:37:18 -0500 Subject: [PATCH 09/40] Pass array of variables (#116-2) --- src/util/treeViewUtils.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/util/treeViewUtils.ts b/src/util/treeViewUtils.ts index 3b9a8202..91acdf7a 100644 --- a/src/util/treeViewUtils.ts +++ b/src/util/treeViewUtils.ts @@ -50,7 +50,7 @@ export function getPanelVariableTreeItem([url, variable]: [ command: { title: 'Open Panel', command: OPEN_VARIABLE_PANELS_CMD, - arguments: [url, variable], + arguments: [url, [variable]], }, }; } From 848820b7a82bdc7e5d4b6e6fb73fcff4cb6145a5 Mon Sep 17 00:00:00 2001 From: Brian Ingles Date: Fri, 6 Sep 2024 17:05:50 -0500 Subject: [PATCH 10/40] Added logger (#116-2) --- src/controllers/PanelController.ts | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/controllers/PanelController.ts b/src/controllers/PanelController.ts index 2aad4469..b6f0e3be 100644 --- a/src/controllers/PanelController.ts +++ b/src/controllers/PanelController.ts @@ -6,9 +6,11 @@ import type { VariableDefintion, } from '../types'; import { getEmbedWidgetUrl } from '../dh/dhc'; -import { assertDefined, getDHThemeKey, getPanelHtml } from '../util'; +import { assertDefined, getDHThemeKey, getPanelHtml, Logger } from '../util'; import { DhcService } from '../services'; +const logger = new Logger('PanelController'); + export class PanelController implements Disposable { constructor(serverManager: IServerManager, panelService: IPanelService) { this._panelService = panelService; @@ -24,6 +26,8 @@ export class PanelController implements Disposable { serverUrl: URL, variables: VariableDefintion[] ): Promise => { + logger.debug('openPanels', serverUrl, variables); + let lastPanel: vscode.WebviewPanel | null = null; for (const { id, title } of variables) { From d5366d639102aa7fc75abb8148f0eb8faa37a7c8 Mon Sep 17 00:00:00 2001 From: Brian Ingles Date: Tue, 17 Sep 2024 15:33:44 -0500 Subject: [PATCH 11/40] Panel refresh management (#116-2) --- package.json | 8 +++++++ src/common/commands.ts | 1 + src/controllers/ExtensionController.ts | 19 +++++++++++++++ src/controllers/PanelController.ts | 32 +++++++++++++++++++++++++- src/services/DhService.ts | 21 ++++++++++++++++- 5 files changed, 79 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index 0dabaa03..01eb31bb 100644 --- a/package.json +++ b/package.json @@ -141,6 +141,10 @@ "command": "vscode-deephaven.openVariablePanels", "title": "Deephaven: Open Variable Panels" }, + { + "command": "vscode-deephaven.refreshVariablePanels", + "title": "Deephaven: Refresh Variable Panels" + }, { "command": "vscode-deephaven.refreshServerTree", "title": "Deephaven: Refresh Server Tree", @@ -611,6 +615,10 @@ { "command": "vscode-deephaven.refreshServerConnectionTree", "when": "false" + }, + { + "command": "vscode-deephaven.refreshVariablePanels", + "when": "false" } ], "editor/context": [ diff --git a/src/common/commands.ts b/src/common/commands.ts index e3cbe3e7..cdf75395 100644 --- a/src/common/commands.ts +++ b/src/common/commands.ts @@ -9,6 +9,7 @@ export const OPEN_IN_BROWSER_CMD = `${EXTENSION_ID}.openInBrowser`; export const OPEN_VARIABLE_PANELS_CMD = `${EXTENSION_ID}.openVariablePanels`; export const REFRESH_SERVER_TREE_CMD = `${EXTENSION_ID}.refreshServerTree`; export const REFRESH_SERVER_CONNECTION_TREE_CMD = `${EXTENSION_ID}.refreshServerConnectionTree`; +export const REFRESH_VARIABLE_PANELS_CMD = `${EXTENSION_ID}.refreshVariablePanels`; export const RUN_CODE_COMMAND = `${EXTENSION_ID}.runCode`; export const RUN_SELECTION_COMMAND = `${EXTENSION_ID}.runSelection`; export const SELECT_CONNECTION_COMMAND = `${EXTENSION_ID}.selectConnection`; diff --git a/src/controllers/ExtensionController.ts b/src/controllers/ExtensionController.ts index 83563b20..adfcba81 100644 --- a/src/controllers/ExtensionController.ts +++ b/src/controllers/ExtensionController.ts @@ -10,6 +10,7 @@ import { OPEN_VARIABLE_PANELS_CMD, REFRESH_SERVER_CONNECTION_TREE_CMD, REFRESH_SERVER_TREE_CMD, + REFRESH_VARIABLE_PANELS_CMD, RUN_CODE_COMMAND, RUN_SELECTION_COMMAND, SELECT_CONNECTION_COMMAND, @@ -350,6 +351,12 @@ export class ExtensionController implements Disposable { this.onRefreshServerStatus ); + /** Refresh variable panels */ + this.registerCommand( + REFRESH_VARIABLE_PANELS_CMD, + this.onRefreshVariablePanels + ); + /** Start a server */ this.registerCommand(START_SERVER_CMD, this.onStartServer); @@ -532,6 +539,18 @@ export class ExtensionController implements Disposable { await this._serverManager?.updateStatus(); }; + /** + * Refresh variable panels for given url and variables. + * @param url Connection url to refresh panels for. + * @param variables Variables to refresh panels for. + */ + onRefreshVariablePanels = ( + url: URL, + variables: VariableDefintion[] + ): void => { + this._panelController?.refreshPanelsContent(url, variables); + }; + /** * Run all code in editor for given uri. * @param uri diff --git a/src/controllers/PanelController.ts b/src/controllers/PanelController.ts index b6f0e3be..a8a37dee 100644 --- a/src/controllers/PanelController.ts +++ b/src/controllers/PanelController.ts @@ -5,8 +5,8 @@ import type { IServerManager, VariableDefintion, } from '../types'; -import { getEmbedWidgetUrl } from '../dh/dhc'; import { assertDefined, getDHThemeKey, getPanelHtml, Logger } from '../util'; +import { getEmbedWidgetUrl } from '../dh/dhc'; import { DhcService } from '../services'; const logger = new Logger('PanelController'); @@ -32,6 +32,7 @@ export class PanelController implements Disposable { for (const { id, title } of variables) { if (!this._panelService.hasPanel(serverUrl, id)) { + logger.debug('[TESTING] create panel', serverUrl, id); const panel = vscode.window.createWebviewPanel( 'dhPanel', // Identifies the type of the webview. Used internally title, @@ -77,5 +78,34 @@ export class PanelController implements Disposable { } lastPanel?.reveal(); + + this.refreshPanelsContent(serverUrl, variables); + }; + + /** + * Reload the html content for all panels associated with the given server url + * + variables. + * @param serverUrl The server url. + * @param variables Variables identifying the panels to refresh. + */ + refreshPanelsContent = ( + serverUrl: URL, + variables: VariableDefintion[] + ): void => { + const connection = this._serverManager.getConnection(serverUrl); + assertDefined(connection, 'connection'); + + for (const { id, title } of variables) { + const panel = this._panelService.getPanelOrThrow(serverUrl, id); + + const iframeUrl = getEmbedWidgetUrl( + serverUrl, + title, + getDHThemeKey(), + connection instanceof DhcService ? connection.getPsk() : undefined + ); + + panel.webview.html = getPanelHtml(iframeUrl, title); + } }; } diff --git a/src/services/DhService.ts b/src/services/DhService.ts index 9bf358e8..7ee39ebc 100644 --- a/src/services/DhService.ts +++ b/src/services/DhService.ts @@ -9,6 +9,7 @@ import type { IToastService, VariableChanges, VariableDefintion, + VariableID, } from '../types'; import { formatTimestamp, @@ -18,7 +19,11 @@ import { NoConsoleTypesError, parseServerError, } from '../util'; -import { OPEN_VARIABLE_PANELS_CMD, VARIABLE_UNICODE_ICONS } from '../common'; +import { + OPEN_VARIABLE_PANELS_CMD, + REFRESH_VARIABLE_PANELS_CMD, + VARIABLE_UNICODE_ICONS, +} from '../common'; const logger = new Logger('DhService'); @@ -158,6 +163,20 @@ export abstract class DhService this.serverUrl, changes as VariableChanges ); + + const panelVariablesToUpdate = changes.updated.filter( + (variable): variable is VariableDefintion => + this.panelService.hasPanel( + this.serverUrl, + variable.id as VariableID + ) + ); + + vscode.commands.executeCommand( + REFRESH_VARIABLE_PANELS_CMD, + this.serverUrl, + panelVariablesToUpdate + ); }); // TODO: Use constant 'disconnect' event name From ed2d796a2cef84a600f9dc84d493717203466cb5 Mon Sep 17 00:00:00 2001 From: Brian Ingles Date: Mon, 9 Sep 2024 15:45:17 -0500 Subject: [PATCH 12/40] Moved panel update commands to PanelController (#116-2) --- src/controllers/ExtensionController.ts | 33 ------------------- src/controllers/PanelController.ts | 45 +++++++++++++++++++++++++- 2 files changed, 44 insertions(+), 34 deletions(-) diff --git a/src/controllers/ExtensionController.ts b/src/controllers/ExtensionController.ts index adfcba81..ceb4285d 100644 --- a/src/controllers/ExtensionController.ts +++ b/src/controllers/ExtensionController.ts @@ -7,10 +7,8 @@ import { DISCONNECT_FROM_SERVER_CMD, DOWNLOAD_LOGS_CMD, OPEN_IN_BROWSER_CMD, - OPEN_VARIABLE_PANELS_CMD, REFRESH_SERVER_CONNECTION_TREE_CMD, REFRESH_SERVER_TREE_CMD, - REFRESH_VARIABLE_PANELS_CMD, RUN_CODE_COMMAND, RUN_SELECTION_COMMAND, SELECT_CONNECTION_COMMAND, @@ -48,7 +46,6 @@ import type { ServerConnectionTreeView, ServerState, ServerTreeView, - VariableDefintion, } from '../types'; import { ServerConnectionTreeDragAndDropController } from './ServerConnectionTreeDragAndDropController'; import { ConnectionController } from './ConnectionController'; @@ -327,9 +324,6 @@ export class ExtensionController implements Disposable { /** Open server in browser */ this.registerCommand(OPEN_IN_BROWSER_CMD, this.onOpenInBrowser); - /** Open variable panel */ - this.registerCommand(OPEN_VARIABLE_PANELS_CMD, this.onOpenVariablePanels); - /** Run all code in active editor */ this.registerCommand(RUN_CODE_COMMAND, this.onRunCode); @@ -351,12 +345,6 @@ export class ExtensionController implements Disposable { this.onRefreshServerStatus ); - /** Refresh variable panels */ - this.registerCommand( - REFRESH_VARIABLE_PANELS_CMD, - this.onRefreshVariablePanels - ); - /** Start a server */ this.registerCommand(START_SERVER_CMD, this.onStartServer); @@ -525,32 +513,11 @@ export class ExtensionController implements Disposable { ); }; - /** - * Open panels for given url and variables. - * @param url Connection url to open panels for. - * @param variables Variables to open panels for. - */ - onOpenVariablePanels = (url: URL, variables: VariableDefintion[]): void => { - this._panelController?.openPanels(url, variables); - }; - onRefreshServerStatus = async (): Promise => { await this._pipServerController?.syncManagedServers(); await this._serverManager?.updateStatus(); }; - /** - * Refresh variable panels for given url and variables. - * @param url Connection url to refresh panels for. - * @param variables Variables to refresh panels for. - */ - onRefreshVariablePanels = ( - url: URL, - variables: VariableDefintion[] - ): void => { - this._panelController?.refreshPanelsContent(url, variables); - }; - /** * Run all code in editor for given uri. * @param uri diff --git a/src/controllers/PanelController.ts b/src/controllers/PanelController.ts index a8a37dee..bb5abac9 100644 --- a/src/controllers/PanelController.ts +++ b/src/controllers/PanelController.ts @@ -8,6 +8,10 @@ import type { import { assertDefined, getDHThemeKey, getPanelHtml, Logger } from '../util'; import { getEmbedWidgetUrl } from '../dh/dhc'; import { DhcService } from '../services'; +import { + OPEN_VARIABLE_PANELS_CMD, + REFRESH_VARIABLE_PANELS_CMD, +} from '../common'; const logger = new Logger('PanelController'); @@ -15,12 +19,30 @@ export class PanelController implements Disposable { constructor(serverManager: IServerManager, panelService: IPanelService) { this._panelService = panelService; this._serverManager = serverManager; + this._subscriptions = []; + + this._subscriptions.push( + vscode.commands.registerCommand( + OPEN_VARIABLE_PANELS_CMD, + this.onOpenVariablePanels + ), + vscode.commands.registerCommand( + REFRESH_VARIABLE_PANELS_CMD, + this.onRefreshVariablePanels + ) + ); } private readonly _panelService: IPanelService; private readonly _serverManager: IServerManager; + private readonly _subscriptions: vscode.Disposable[]; - dispose = async (): Promise => {}; + dispose = async (): Promise => { + for (const subscription of this._subscriptions) { + subscription.dispose(); + } + this._subscriptions.length = 0; + }; openPanels = async ( serverUrl: URL, @@ -108,4 +130,25 @@ export class PanelController implements Disposable { panel.webview.html = getPanelHtml(iframeUrl, title); } }; + + /** + * Open panels for given url and variables. + * @param url Connection url to open panels for. + * @param variables Variables to open panels for. + */ + onOpenVariablePanels = (url: URL, variables: VariableDefintion[]): void => { + this.openPanels(url, variables); + }; + + /** + * Refresh variable panels for given url and variables. + * @param url Connection url to refresh panels for. + * @param variables Variables to refresh panels for. + */ + onRefreshVariablePanels = ( + url: URL, + variables: VariableDefintion[] + ): void => { + this.refreshPanelsContent(url, variables); + }; } From 8c0ffe904aa02b43df759df051cb7d16b6b390f3 Mon Sep 17 00:00:00 2001 From: Brian Ingles Date: Mon, 9 Sep 2024 15:46:55 -0500 Subject: [PATCH 13/40] Removed debug log (#116-2) --- src/controllers/PanelController.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/src/controllers/PanelController.ts b/src/controllers/PanelController.ts index bb5abac9..48598d3c 100644 --- a/src/controllers/PanelController.ts +++ b/src/controllers/PanelController.ts @@ -54,7 +54,6 @@ export class PanelController implements Disposable { for (const { id, title } of variables) { if (!this._panelService.hasPanel(serverUrl, id)) { - logger.debug('[TESTING] create panel', serverUrl, id); const panel = vscode.window.createWebviewPanel( 'dhPanel', // Identifies the type of the webview. Used internally title, From afbe101c5865145066dc32ae9033b209342ac8c2 Mon Sep 17 00:00:00 2001 From: Brian Ingles Date: Mon, 9 Sep 2024 15:51:59 -0500 Subject: [PATCH 14/40] Made event handlers private (#116-2) --- src/controllers/PanelController.ts | 31 +++++------------------------- 1 file changed, 5 insertions(+), 26 deletions(-) diff --git a/src/controllers/PanelController.ts b/src/controllers/PanelController.ts index 48598d3c..ed4ca1cd 100644 --- a/src/controllers/PanelController.ts +++ b/src/controllers/PanelController.ts @@ -24,11 +24,11 @@ export class PanelController implements Disposable { this._subscriptions.push( vscode.commands.registerCommand( OPEN_VARIABLE_PANELS_CMD, - this.onOpenVariablePanels + this._onOpenPanels ), vscode.commands.registerCommand( REFRESH_VARIABLE_PANELS_CMD, - this.onRefreshVariablePanels + this._onRefreshPanelsContent ) ); } @@ -44,7 +44,7 @@ export class PanelController implements Disposable { this._subscriptions.length = 0; }; - openPanels = async ( + private _onOpenPanels = async ( serverUrl: URL, variables: VariableDefintion[] ): Promise => { @@ -100,7 +100,7 @@ export class PanelController implements Disposable { lastPanel?.reveal(); - this.refreshPanelsContent(serverUrl, variables); + this._onRefreshPanelsContent(serverUrl, variables); }; /** @@ -109,7 +109,7 @@ export class PanelController implements Disposable { * @param serverUrl The server url. * @param variables Variables identifying the panels to refresh. */ - refreshPanelsContent = ( + private _onRefreshPanelsContent = ( serverUrl: URL, variables: VariableDefintion[] ): void => { @@ -129,25 +129,4 @@ export class PanelController implements Disposable { panel.webview.html = getPanelHtml(iframeUrl, title); } }; - - /** - * Open panels for given url and variables. - * @param url Connection url to open panels for. - * @param variables Variables to open panels for. - */ - onOpenVariablePanels = (url: URL, variables: VariableDefintion[]): void => { - this.openPanels(url, variables); - }; - - /** - * Refresh variable panels for given url and variables. - * @param url Connection url to refresh panels for. - * @param variables Variables to refresh panels for. - */ - onRefreshVariablePanels = ( - url: URL, - variables: VariableDefintion[] - ): void => { - this.refreshPanelsContent(url, variables); - }; } From 76b90d19c6d145741851608896a624cfe9ef6203 Mon Sep 17 00:00:00 2001 From: Brian Ingles Date: Mon, 9 Sep 2024 16:18:56 -0500 Subject: [PATCH 15/40] Added consoleType to cn node (#116-2) --- src/util/treeViewUtils.ts | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/util/treeViewUtils.ts b/src/util/treeViewUtils.ts index 91acdf7a..d0b7d808 100644 --- a/src/util/treeViewUtils.ts +++ b/src/util/treeViewUtils.ts @@ -17,16 +17,16 @@ import { * Get `TreeItem` for a panel connection. * @param connection */ -export function getPanelConnectionTreeItem( +export async function getPanelConnectionTreeItem( connection: IDhService -): vscode.TreeItem { +): Promise { + const [consoleType] = connection.isInitialized + ? await connection.getConsoleTypes() + : []; + return { label: new URL(connection.serverUrl.toString()).host, - // description: consoleType, - // contextValue: CONNECTION_TREE_ITEM_CONTEXT.isConnection, - // collapsibleState: hasUris - // ? vscode.TreeItemCollapsibleState.Expanded - // : undefined, + description: consoleType, collapsibleState: vscode.TreeItemCollapsibleState.Expanded, iconPath: new vscode.ThemeIcon( connection.isConnected ? ICON_ID.connected : ICON_ID.connecting From cc6a9cbc2df4fc1ac0f4bc340a2df43df104005f Mon Sep 17 00:00:00 2001 From: Brian Ingles Date: Mon, 9 Sep 2024 18:09:54 -0500 Subject: [PATCH 16/40] dh icon font (#116-2) --- assets/dh-icons.woff | Bin 0 -> 1348 bytes package.json | 16 ++++++++++++++++ src/common/constants.ts | 24 +++++++++++------------- src/types/commonTypes.d.ts | 11 +++++++++-- src/util/treeViewUtils.ts | 31 ++++++++++++++++++++++++++++--- 5 files changed, 64 insertions(+), 18 deletions(-) create mode 100644 assets/dh-icons.woff diff --git a/assets/dh-icons.woff b/assets/dh-icons.woff new file mode 100644 index 0000000000000000000000000000000000000000..cda920b046daddfadbfdac1aa9de9d9c435dc7dc GIT binary patch literal 1348 zcma)5O=uHA7=5#wq&9`7v9=K{x}{J>*ox zi-M;X@#Mji7ms=fDthtc&2u4GJPT5d@qLp`X)%Idcr)*NGyA=7XEyg|QzCP76Jt*|uFE@T5-6F$IEb`2naOPs?zDT6-+YgaYujRrN4Lvz*G zi3R*8^a2M3#a$7pLTAv~0H!W$>;KhwJB_L-U7P6O7Z5=&VmOJ@ET8Bb>La4Wa3VS+ zxp2{XB`>);Ub(JH?^AQLwpUZz?w4PC>TJ#UP)oVSlV5w%b69&-=ylj>2*Wr}zrl`Z zY;Y>7h9(jdKK{kcbRCvu!m3xBp>TLMlU6-xSw^*` zoC~Anpc8-S#!J7x;+eI&HptVyF1I%6^8op(&x5?nKA(rE-}HGHC-6|dqd+H>Zmu-B zL7w%wNq*Jm0rCx>2hk79=OOBIJ`ZCY&zCcv>v;t%BLfdE;i0hL6idrq!5WK?VgU|{ zC~*T9SZ54zjJAEMtvKgoSMzp}rVbljMIJVaZFi=;LfOhX1*d42oh55=-I~sLGwdyn ml=d#uJ3Sm!vcUtp&B0_>5OeDF&C=6?WVY}|za literal 0 HcmV?d00001 diff --git a/package.json b/package.json index 01eb31bb..2db6d10d 100644 --- a/package.json +++ b/package.json @@ -87,6 +87,22 @@ } } }, + "icons": { + "dh-pandas": { + "description": "Deephaven pandas icon", + "default": { + "fontPath": "assets/dh-icons.woff", + "fontCharacter": "\\e900" + } + }, + "dh-table": { + "description": "Deephaven table icon", + "default": { + "fontPath": "assets/dh-icons.woff", + "fontCharacter": "\\e901" + } + } + }, "snippets": [ { "language": "python", diff --git a/src/common/constants.ts b/src/common/constants.ts index 9a596d00..bcfcbaff 100644 --- a/src/common/constants.ts +++ b/src/common/constants.ts @@ -63,10 +63,10 @@ export const ICON_ID = { serverRunning: 'circle-large-outline', serverStopped: 'circle-slash', table: 'table', - varFigure: 'graph-line', - varExpFigure: 'pie-chart', - varTable: 'preview', - varElement: 'extensions', + varFigure: 'graph', + varElement: 'preview', + varPandas: 'dh-pandas', + varTable: 'dh-table', } as const; /* eslint-disable @typescript-eslint/naming-convention */ @@ -74,16 +74,14 @@ export const VARIABLE_UNICODE_ICONS = { 'deephaven.plot.express.DeephavenFigure': '📈', 'deephaven.ui.Element': '✨', Figure: '📈', + HierarchicalTable: '⬜', + OtherWidget: '⬜', + 'pandas.DataFrame': '🐼', + PartitionedTable: '⬜', Table: '⬜', -} as const satisfies Record; -/* eslint-enable @typescript-eslint/naming-convention */ - -/* eslint-disable @typescript-eslint/naming-convention */ -export const VARIABLE_ICONS = { - 'deephaven.plot.express.DeephavenFigure': ICON_ID.varExpFigure, - 'deephaven.ui.Element': ICON_ID.varElement, - Figure: ICON_ID.varFigure, - Table: ICON_ID.varTable, + TableMap: '⬜', + Treemap: '⬜', + TreeTable: '⬜', } as const satisfies Record; /* eslint-enable @typescript-eslint/naming-convention */ diff --git a/src/types/commonTypes.d.ts b/src/types/commonTypes.d.ts index ce89469b..2c380c80 100644 --- a/src/types/commonTypes.d.ts +++ b/src/types/commonTypes.d.ts @@ -89,7 +89,14 @@ export interface VariableChanges { } export type VariableType = - | 'Figure' | 'deephaven.plot.express.DeephavenFigure' + | 'deephaven.ui.Element' + | 'Figure' + | 'HierarchicalTable' + | 'OtherWidget' + | 'pandas.DataFrame' + | 'PartitionedTable' | 'Table' - | 'deephaven.ui.Element'; + | 'TableMap' + | 'Treemap' + | 'TreeTable'; diff --git a/src/util/treeViewUtils.ts b/src/util/treeViewUtils.ts index d0b7d808..23a71dbc 100644 --- a/src/util/treeViewUtils.ts +++ b/src/util/treeViewUtils.ts @@ -4,15 +4,39 @@ import type { ServerGroupState, ServerState, VariableDefintion, + VariableType, } from '../types'; import { ICON_ID, OPEN_VARIABLE_PANELS_CMD, SERVER_TREE_ITEM_CONTEXT, - VARIABLE_ICONS, type ServerTreeItemContextValue, } from '../common'; +export function getVariableIconPath( + variableType: VariableType +): vscode.TreeItem['iconPath'] { + switch (variableType) { + case 'Table': + case 'TableMap': + case 'TreeTable': + case 'HierarchicalTable': + case 'PartitionedTable': + return new vscode.ThemeIcon(ICON_ID.varTable); + + case 'deephaven.plot.express.DeephavenFigure': + case 'Figure': + return new vscode.ThemeIcon(ICON_ID.varFigure); + + case 'pandas.DataFrame': + return new vscode.ThemeIcon(ICON_ID.varPandas); + + case 'deephaven.ui.Element': + default: + return new vscode.ThemeIcon(ICON_ID.varElement); + } +} + /** * Get `TreeItem` for a panel connection. * @param connection @@ -42,11 +66,12 @@ export function getPanelVariableTreeItem([url, variable]: [ URL, VariableDefintion, ]): vscode.TreeItem { - const iconId = VARIABLE_ICONS[variable.type]; + const iconPath = getVariableIconPath(variable.type); return { description: variable.title, - iconPath: iconId == null ? undefined : new vscode.ThemeIcon(iconId), + // iconPath: iconId == null ? undefined : new vscode.ThemeIcon(iconId), + iconPath, command: { title: 'Open Panel', command: OPEN_VARIABLE_PANELS_CMD, From 5a97d3913faa9bc4234a1ab2d6add84d20bb0840 Mon Sep 17 00:00:00 2001 From: Brian Ingles Date: Tue, 10 Sep 2024 14:17:24 -0500 Subject: [PATCH 17/40] Updated icon font (#116-2) --- assets/dh-icons.woff | Bin 1348 -> 6164 bytes package.json | 4 ++-- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/assets/dh-icons.woff b/assets/dh-icons.woff index cda920b046daddfadbfdac1aa9de9d9c435dc7dc..6abba479af5d5c698b678040863793b5a01a7a9f 100644 GIT binary patch literal 6164 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 IkqHC-A40Nh8UO$Q literal 1348 zcma)5O=uHA7=5#wq&9`7v9=K{x}{J>*ox zi-M;X@#Mji7ms=fDthtc&2u4GJPT5d@qLp`X)%Idcr)*NGyA=7XEyg|QzCP76Jt*|uFE@T5-6F$IEb`2naOPs?zDT6-+YgaYujRrN4Lvz*G zi3R*8^a2M3#a$7pLTAv~0H!W$>;KhwJB_L-U7P6O7Z5=&VmOJ@ET8Bb>La4Wa3VS+ zxp2{XB`>);Ub(JH?^AQLwpUZz?w4PC>TJ#UP)oVSlV5w%b69&-=ylj>2*Wr}zrl`Z zY;Y>7h9(jdKK{kcbRCvu!m3xBp>TLMlU6-xSw^*` zoC~Anpc8-S#!J7x;+eI&HptVyF1I%6^8op(&x5?nKA(rE-}HGHC-6|dqd+H>Zmu-B zL7w%wNq*Jm0rCx>2hk79=OOBIJ`ZCY&zCcv>v;t%BLfdE;i0hL6idrq!5WK?VgU|{ zC~*T9SZ54zjJAEMtvKgoSMzp}rVbljMIJVaZFi=;LfOhX1*d42oh55=-I~sLGwdyn ml=d#uJ3Sm!vcUtp&B0_>5OeDF&C=6?WVY}|za diff --git a/package.json b/package.json index 2db6d10d..96c70ab5 100644 --- a/package.json +++ b/package.json @@ -92,14 +92,14 @@ "description": "Deephaven pandas icon", "default": { "fontPath": "assets/dh-icons.woff", - "fontCharacter": "\\e900" + "fontCharacter": "\\e91c" } }, "dh-table": { "description": "Deephaven table icon", "default": { "fontPath": "assets/dh-icons.woff", - "fontCharacter": "\\e901" + "fontCharacter": "\\e930" } } }, From 8c7f9d3abb5c28d57a0c8969f99f68102a78921f Mon Sep 17 00:00:00 2001 From: Brian Ingles Date: Tue, 10 Sep 2024 17:03:38 -0500 Subject: [PATCH 18/40] Fixed rebase (#116-2) --- package.json | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/package.json b/package.json index 96c70ab5..01eb31bb 100644 --- a/package.json +++ b/package.json @@ -87,22 +87,6 @@ } } }, - "icons": { - "dh-pandas": { - "description": "Deephaven pandas icon", - "default": { - "fontPath": "assets/dh-icons.woff", - "fontCharacter": "\\e91c" - } - }, - "dh-table": { - "description": "Deephaven table icon", - "default": { - "fontPath": "assets/dh-icons.woff", - "fontCharacter": "\\e930" - } - } - }, "snippets": [ { "language": "python", From 6d699cdba4516c90f1b2d3223f3e3429a225d7e6 Mon Sep 17 00:00:00 2001 From: Brian Ingles Date: Tue, 10 Sep 2024 17:33:16 -0500 Subject: [PATCH 19/40] Updated table unicode icon (#116-2) --- src/common/constants.ts | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/common/constants.ts b/src/common/constants.ts index bcfcbaff..959c666d 100644 --- a/src/common/constants.ts +++ b/src/common/constants.ts @@ -74,14 +74,14 @@ export const VARIABLE_UNICODE_ICONS = { 'deephaven.plot.express.DeephavenFigure': '📈', 'deephaven.ui.Element': '✨', Figure: '📈', - HierarchicalTable: '⬜', + HierarchicalTable: '▤', OtherWidget: '⬜', 'pandas.DataFrame': '🐼', - PartitionedTable: '⬜', - Table: '⬜', - TableMap: '⬜', - Treemap: '⬜', - TreeTable: '⬜', + PartitionedTable: '▤', + Table: '▤', + TableMap: '▤', + Treemap: '▤', + TreeTable: '▤', } as const satisfies Record; /* eslint-enable @typescript-eslint/naming-convention */ From f53de3edc05af457da91bfe0f65b9c0aa2f7ea96 Mon Sep 17 00:00:00 2001 From: Brian Ingles Date: Tue, 10 Sep 2024 17:36:21 -0500 Subject: [PATCH 20/40] Don't steal focus with pip check terminal (#116-2) --- src/controllers/PipServerController.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/controllers/PipServerController.ts b/src/controllers/PipServerController.ts index 9ab9fc9d..23972482 100644 --- a/src/controllers/PipServerController.ts +++ b/src/controllers/PipServerController.ts @@ -94,6 +94,7 @@ export class PipServerController implements Disposable { const terminal = vscode.window.createTerminal({ name: `Deephaven check pip server install`, isTransient: true, + hideFromUser: true, }); // Give python extension time to setup .venv if configured From ff32a1a9651d00551ced08210e2ee316d56bc2d1 Mon Sep 17 00:00:00 2001 From: Brian Ingles Date: Tue, 10 Sep 2024 17:39:24 -0500 Subject: [PATCH 21/40] Removed unused variable (#116-2) --- src/common/constants.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/src/common/constants.ts b/src/common/constants.ts index 959c666d..d84b7517 100644 --- a/src/common/constants.ts +++ b/src/common/constants.ts @@ -62,7 +62,6 @@ export const ICON_ID = { serverConnected: 'circle-large-filled', serverRunning: 'circle-large-outline', serverStopped: 'circle-slash', - table: 'table', varFigure: 'graph', varElement: 'preview', varPandas: 'dh-pandas', From 0b640ab90a38ae6bd0d5dc2c9c22f6727c10c9bc Mon Sep 17 00:00:00 2001 From: Brian Ingles Date: Wed, 11 Sep 2024 10:13:02 -0500 Subject: [PATCH 22/40] Removed commented out code (#116-2) --- src/services/PanelService.ts | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/services/PanelService.ts b/src/services/PanelService.ts index 9d51182e..2f58126c 100644 --- a/src/services/PanelService.ts +++ b/src/services/PanelService.ts @@ -99,11 +99,6 @@ export class PanelService implements IPanelService, Disposable { this._cnVariableMap.set(url, new Map()); } - // if (!this._cnPanelMap.has(url)) { - // this._cnPanelMap.set(url, new Map()); - // } - - // const panelMap = this._cnPanelMap.get(url)!; const variableMap = this._cnVariableMap.get(url)!; for (const variable of created) { From 2ac060d3548d48c101a1b1749703ef14912e1413 Mon Sep 17 00:00:00 2001 From: Brian Ingles Date: Wed, 11 Sep 2024 10:25:08 -0500 Subject: [PATCH 23/40] Refresh panels on theme change (#116-2) --- src/controllers/PanelController.ts | 10 ++++++++++ src/services/PanelService.ts | 19 +++++++++++++++++++ src/types/serviceTypes.d.ts | 2 ++ 3 files changed, 31 insertions(+) diff --git a/src/controllers/PanelController.ts b/src/controllers/PanelController.ts index ed4ca1cd..e94e2aef 100644 --- a/src/controllers/PanelController.ts +++ b/src/controllers/PanelController.ts @@ -29,6 +29,9 @@ export class PanelController implements Disposable { vscode.commands.registerCommand( REFRESH_VARIABLE_PANELS_CMD, this._onRefreshPanelsContent + ), + vscode.window.onDidChangeActiveColorTheme( + this._onDidChangeActiveColorTheme ) ); } @@ -129,4 +132,11 @@ export class PanelController implements Disposable { panel.webview.html = getPanelHtml(iframeUrl, title); } }; + + private _onDidChangeActiveColorTheme = (): void => { + for (const url of this._panelService.getPanelUrls()) { + const variables = this._panelService.getPanelVariables(url); + this._onRefreshPanelsContent(url, [...variables]); + } + }; } diff --git a/src/services/PanelService.ts b/src/services/PanelService.ts index 2f58126c..41f415c2 100644 --- a/src/services/PanelService.ts +++ b/src/services/PanelService.ts @@ -49,6 +49,25 @@ export class PanelService implements IPanelService, Disposable { this._cnPanelMap.get(url)?.delete(variableId); }; + /** + * Get all connection URLs that have panels. + * @returns Iterable of URLs + */ + getPanelUrls = (): Iterable => { + return [...this._cnPanelMap.keys()].filter( + url => this._cnPanelMap.get(url)?.size ?? 0 > 0 + ); + }; + + /** + * Get all variables for the given connection url that have panels. + * @param url + * @returns Iterable of variables + */ + getPanelVariables = (url: URL): Iterable => { + return [...this.getVariables(url)].filter(v => this.hasPanel(url, v.id)); + }; + /** * Check if a panel is associated with a given connection url + variable id. * @param url diff --git a/src/types/serviceTypes.d.ts b/src/types/serviceTypes.d.ts index a2c8d6c0..d84b6f96 100644 --- a/src/types/serviceTypes.d.ts +++ b/src/types/serviceTypes.d.ts @@ -69,6 +69,8 @@ export type IDhServiceFactory = IFactory< export interface IPanelService extends Disposable { readonly onDidUpdate: vscode.Event; + getPanelUrls: () => Iterable; + getPanelVariables: (url: URL) => Iterable; getPanelOrThrow: (url: URL, variableId: VariableID) => vscode.WebviewPanel; deletePanel: (url: URL, variableId: VariableID) => void; hasPanel: (url: URL, variableId: VariableID) => boolean; From 7936da2f70e1695cdcb0839b578314a2b6ca81f5 Mon Sep 17 00:00:00 2001 From: Brian Ingles Date: Wed, 11 Sep 2024 10:56:30 -0500 Subject: [PATCH 24/40] Added a waitFor(0) (#116-2) --- src/controllers/PanelController.ts | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/controllers/PanelController.ts b/src/controllers/PanelController.ts index e94e2aef..a03f2b9a 100644 --- a/src/controllers/PanelController.ts +++ b/src/controllers/PanelController.ts @@ -12,6 +12,7 @@ import { OPEN_VARIABLE_PANELS_CMD, REFRESH_VARIABLE_PANELS_CMD, } from '../common'; +import { waitFor } from '../util/promiseUtils'; const logger = new Logger('PanelController'); @@ -53,6 +54,10 @@ export class PanelController implements Disposable { ): Promise => { logger.debug('openPanels', serverUrl, variables); + // Waiting for next tick seems to decrease the occurrences of a subtle bug + // where the `editor/title/run` menu gets stuck on a previous selection. + await waitFor(0); + let lastPanel: vscode.WebviewPanel | null = null; for (const { id, title } of variables) { @@ -102,7 +107,6 @@ export class PanelController implements Disposable { } lastPanel?.reveal(); - this._onRefreshPanelsContent(serverUrl, variables); }; @@ -133,6 +137,9 @@ export class PanelController implements Disposable { } }; + /** + * Whenever active theme changes, refresh any open panels. + */ private _onDidChangeActiveColorTheme = (): void => { for (const url of this._panelService.getPanelUrls()) { const variables = this._panelService.getPanelVariables(url); From 43ea53e529896621ac7e4578afa7952dc7aa7db3 Mon Sep 17 00:00:00 2001 From: Brian Ingles Date: Wed, 11 Sep 2024 11:00:41 -0500 Subject: [PATCH 25/40] Consolidated sorting (#116-2) --- src/providers/ServerConnectionPanelTreeProvider.ts | 2 +- src/util/uiUtils.ts | 12 +++--------- 2 files changed, 4 insertions(+), 10 deletions(-) diff --git a/src/providers/ServerConnectionPanelTreeProvider.ts b/src/providers/ServerConnectionPanelTreeProvider.ts index 2f7d6016..4fc2fed1 100644 --- a/src/providers/ServerConnectionPanelTreeProvider.ts +++ b/src/providers/ServerConnectionPanelTreeProvider.ts @@ -44,7 +44,7 @@ export class ServerConnectionPanelTreeProvider extends TreeDataProviderBase a.title.localeCompare(b.title)) + .sort(sortByStringProp('title')) .map(variable => [connectionOrRoot.serverUrl, variable]); }; } diff --git a/src/util/uiUtils.ts b/src/util/uiUtils.ts index 436bfcc5..f5026e7c 100644 --- a/src/util/uiUtils.ts +++ b/src/util/uiUtils.ts @@ -15,6 +15,7 @@ import type { ConnectionPickOption, ServerConnection, } from '../types'; +import { sortByStringProp } from './dataUtils'; export interface ConnectionOption { type: ConnectionType; @@ -79,8 +80,8 @@ export function createConnectionQuickPickOptions< } // Sort options by label - connectionOptions.sort(sortByLabel); - serverOptions.sort(sortByLabel); + connectionOptions.sort(sortByStringProp('label')); + serverOptions.sort(sortByStringProp('label')); return [ createSeparatorPickItem('Active Connections'), @@ -251,13 +252,6 @@ export async function getEditorForUri( return vscode.window.showTextDocument(uri, { preview: false, viewColumn }); } -/** - * Sort function for sorting by label. - */ -export function sortByLabel(a: T, b: T): number { - return a.label.localeCompare(b.label); -} - /** * Update given status bar item based on connection status * and optional `ConnectionOption`. From d8d1fb757dc12c285b28ee03de3f841561811b83 Mon Sep 17 00:00:00 2001 From: Brian Ingles Date: Wed, 11 Sep 2024 11:04:25 -0500 Subject: [PATCH 26/40] Changed types (#116-2) --- src/services/PanelService.ts | 11 ++++++----- src/types/serviceTypes.d.ts | 4 ++-- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/src/services/PanelService.ts b/src/services/PanelService.ts index 41f415c2..29e3f179 100644 --- a/src/services/PanelService.ts +++ b/src/services/PanelService.ts @@ -51,9 +51,9 @@ export class PanelService implements IPanelService, Disposable { /** * Get all connection URLs that have panels. - * @returns Iterable of URLs + * @returns Array of URLs */ - getPanelUrls = (): Iterable => { + getPanelUrls = (): URL[] => { return [...this._cnPanelMap.keys()].filter( url => this._cnPanelMap.get(url)?.size ?? 0 > 0 ); @@ -62,9 +62,9 @@ export class PanelService implements IPanelService, Disposable { /** * Get all variables for the given connection url that have panels. * @param url - * @returns Iterable of variables + * @returns Array of variables */ - getPanelVariables = (url: URL): Iterable => { + getPanelVariables = (url: URL): VariableDefintion[] => { return [...this.getVariables(url)].filter(v => this.hasPanel(url, v.id)); }; @@ -99,7 +99,8 @@ export class PanelService implements IPanelService, Disposable { /** * Get variables for the given connection url. - * @param url + * @param url The connection url. + * @returns Iterable of variables */ getVariables = (url: URL): Iterable => { return this._cnVariableMap.get(url)?.values() ?? []; diff --git a/src/types/serviceTypes.d.ts b/src/types/serviceTypes.d.ts index d84b6f96..18431007 100644 --- a/src/types/serviceTypes.d.ts +++ b/src/types/serviceTypes.d.ts @@ -69,8 +69,8 @@ export type IDhServiceFactory = IFactory< export interface IPanelService extends Disposable { readonly onDidUpdate: vscode.Event; - getPanelUrls: () => Iterable; - getPanelVariables: (url: URL) => Iterable; + getPanelUrls: () => URL[]; + getPanelVariables: (url: URL) => VariableDefintion[]; getPanelOrThrow: (url: URL, variableId: VariableID) => vscode.WebviewPanel; deletePanel: (url: URL, variableId: VariableID) => void; hasPanel: (url: URL, variableId: VariableID) => boolean; From 323d066ad9435b9a875a2210982572bba6e5b68e Mon Sep 17 00:00:00 2001 From: Brian Ingles Date: Wed, 11 Sep 2024 11:04:58 -0500 Subject: [PATCH 27/40] Comments (#116-2) --- src/services/PanelService.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/services/PanelService.ts b/src/services/PanelService.ts index 29e3f179..93babf34 100644 --- a/src/services/PanelService.ts +++ b/src/services/PanelService.ts @@ -61,7 +61,7 @@ export class PanelService implements IPanelService, Disposable { /** * Get all variables for the given connection url that have panels. - * @param url + * @param url The connection url. * @returns Array of variables */ getPanelVariables = (url: URL): VariableDefintion[] => { @@ -70,7 +70,7 @@ export class PanelService implements IPanelService, Disposable { /** * Check if a panel is associated with a given connection url + variable id. - * @param url + * @param url The connection url. * @param variableId */ hasPanel = (url: URL, variableId: VariableID): boolean => { From 15877332cb49ea03a7aaeeb080863972350d08c2 Mon Sep 17 00:00:00 2001 From: Brian Ingles Date: Wed, 11 Sep 2024 11:31:29 -0500 Subject: [PATCH 28/40] Reorder (#116-2) --- src/services/PanelService.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/services/PanelService.ts b/src/services/PanelService.ts index 93babf34..7b698450 100644 --- a/src/services/PanelService.ts +++ b/src/services/PanelService.ts @@ -121,14 +121,14 @@ export class PanelService implements IPanelService, Disposable { const variableMap = this._cnVariableMap.get(url)!; - for (const variable of created) { - variableMap.set(variable.id, variable); - } - for (const variable of removed) { variableMap.delete(variable.id); } + for (const variable of created) { + variableMap.set(variable.id, variable); + } + for (const variable of updated) { variableMap.set(variable.id, variable); } From d032d61fe1884394de31c32d70cb8deb49d5ca0a Mon Sep 17 00:00:00 2001 From: Brian Ingles Date: Wed, 11 Sep 2024 11:39:56 -0500 Subject: [PATCH 29/40] Delete panel (#116-2) --- src/services/PanelService.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/services/PanelService.ts b/src/services/PanelService.ts index 7b698450..25143da8 100644 --- a/src/services/PanelService.ts +++ b/src/services/PanelService.ts @@ -123,6 +123,7 @@ export class PanelService implements IPanelService, Disposable { for (const variable of removed) { variableMap.delete(variable.id); + this.deletePanel(url, variable.id); } for (const variable of created) { From 85c627eed15eb2b8dfa1ad0edb2b3c959bc5777b Mon Sep 17 00:00:00 2001 From: Brian Ingles Date: Wed, 11 Sep 2024 12:27:39 -0500 Subject: [PATCH 30/40] Unit tests (#116-2) --- .../__snapshots__/treeViewUtils.spec.ts.snap | 48 +++++++++ src/util/index.ts | 1 + src/util/testUtils.ts | 35 ++++++ src/util/treeViewUtils.spec.ts | 102 +++++++----------- src/util/treeViewUtils.ts | 1 - 5 files changed, 123 insertions(+), 64 deletions(-) create mode 100644 src/util/testUtils.ts diff --git a/src/util/__snapshots__/treeViewUtils.spec.ts.snap b/src/util/__snapshots__/treeViewUtils.spec.ts.snap index 1fbd7ca6..d6860d55 100644 --- a/src/util/__snapshots__/treeViewUtils.spec.ts.snap +++ b/src/util/__snapshots__/treeViewUtils.spec.ts.snap @@ -1,5 +1,53 @@ // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html +exports[`getPanelConnectionTreeItem > should return panel connection tree item: isConnected:false, isInitialized:false 1`] = ` +{ + "collapsibleState": 2, + "description": undefined, + "iconPath": { + "color": undefined, + "id": "sync~spin", + }, + "label": "localhost:10000", +} +`; + +exports[`getPanelConnectionTreeItem > should return panel connection tree item: isConnected:false, isInitialized:true 1`] = ` +{ + "collapsibleState": 2, + "description": "python", + "iconPath": { + "color": undefined, + "id": "sync~spin", + }, + "label": "localhost:10000", +} +`; + +exports[`getPanelConnectionTreeItem > should return panel connection tree item: isConnected:true, isInitialized:false 1`] = ` +{ + "collapsibleState": 2, + "description": undefined, + "iconPath": { + "color": undefined, + "id": "vm-connect", + }, + "label": "localhost:10000", +} +`; + +exports[`getPanelConnectionTreeItem > should return panel connection tree item: isConnected:true, isInitialized:true 1`] = ` +{ + "collapsibleState": 2, + "description": "python", + "iconPath": { + "color": undefined, + "id": "vm-connect", + }, + "label": "localhost:10000", +} +`; + exports[`getServerContextValue > should return contextValue based on server state: isConnected=false, isManaged=false, isRunning=false 1`] = `"isServerStopped"`; exports[`getServerContextValue > should return contextValue based on server state: isConnected=false, isManaged=false, isRunning=true 1`] = `"isServerRunningDisconnected"`; diff --git a/src/util/index.ts b/src/util/index.ts index b4794c4c..5bcdc833 100644 --- a/src/util/index.ts +++ b/src/util/index.ts @@ -10,6 +10,7 @@ export * from './panelUtils'; export * from './polyfillUtils'; export * from './selectionUtils'; export * from './serverUtils'; +export * from './testUtils'; export * from './treeViewUtils'; export * from './Toaster'; export * from './uiUtils'; diff --git a/src/util/testUtils.ts b/src/util/testUtils.ts new file mode 100644 index 00000000..0ddb41e6 --- /dev/null +++ b/src/util/testUtils.ts @@ -0,0 +1,35 @@ +export const bitValues = [0, 1] as const; +export const boolValues = [true, false] as const; + +/** + * Generate a 2 dimensional array of all possible combinations of the given value + * lists. + * + * e.g. + * matrix([1, 2], ['a', 'b']) => [[1, 'a'], [1, 'b'], [2, 'a'], [2, 'b']] + * + * matrix([1, 2], ['a', 'b', 'c']) => [ + * [1, 'a'], [1, 'b'], [1, 'c'], + * [2, 'a'], [2, 'b'], [2, 'c'], + * ] + * + * @param args Value lists + * @returns 2D array of all possible combinations + */ +export function matrix< + TArgs extends (unknown[] | readonly unknown[])[], + TReturn extends { [P in keyof TArgs]: TArgs[P][number] }, +>(...args: TArgs): TReturn[] { + const [first, ...rest] = args; + + if (rest.length === 0) { + return first.map(value => [value] as TReturn); + } + + // recursively call matrix + const restMatrix = matrix(...rest); + + return first.flatMap(value => + restMatrix.map(values => [value, ...values] as TReturn) + ); +} diff --git a/src/util/treeViewUtils.spec.ts b/src/util/treeViewUtils.spec.ts index 58b5122e..e9824684 100644 --- a/src/util/treeViewUtils.spec.ts +++ b/src/util/treeViewUtils.spec.ts @@ -1,5 +1,7 @@ import { describe, it, expect, vi } from 'vitest'; +import { bitValues, boolValues, matrix } from './testUtils'; import { + getPanelConnectionTreeItem, getServerContextValue, getServerDescription, getServerGroupContextValue, @@ -8,22 +10,36 @@ import { getServerTreeItem, groupServers, } from './treeViewUtils'; -import type { ServerState } from '../types'; +import type { ConsoleType, IDhService, ServerState } from '../types'; // See __mocks__/vscode.ts for the mock implementation vi.mock('vscode'); +describe('getPanelConnectionTreeItem', () => { + const getConsoleTypes: IDhService['getConsoleTypes'] = vi + .fn() + .mockResolvedValue(new Set(['python'])); + + const serverUrl = new URL('http://localhost:10000'); + + it.each(matrix(boolValues, boolValues))( + 'should return panel connection tree item: isConnected:%s, isInitialized:%s', + async (isConnected, isInitialized) => { + const connection = { + isConnected, + isInitialized, + serverUrl, + getConsoleTypes, + } as IDhService; + + const actual = await getPanelConnectionTreeItem(connection); + expect(actual).toMatchSnapshot(); + } + ); +}); + describe('getServerContextValue', () => { - it.each([ - [true, true, true], - [true, true, false], - [true, false, true], - [true, false, false], - [false, true, true], - [false, true, false], - [false, false, true], - [false, false, false], - ])( + it.each(matrix(boolValues, boolValues, boolValues))( 'should return contextValue based on server state: isConnected=%s, isManaged=%s, isRunning=%s', (isConnected, isManaged, isRunning) => { const actual = getServerContextValue({ @@ -37,16 +53,9 @@ describe('getServerContextValue', () => { }); describe('getServerDescription', () => { - it.each([ - [0, true, 'some label'], - [1, true, 'some label'], - [0, false, 'some label'], - [1, false, 'some label'], - [0, true, undefined], - [1, true, undefined], - [0, false, undefined], - [1, false, undefined], - ])( + const label = ['some label', undefined] as const; + + it.each(matrix(bitValues, boolValues, label))( 'should return server description based on parameters: connectionCount=%s, isManaged=%s, label=%s', (connectionCount, isManaged, label) => { const actual = getServerDescription(connectionCount, isManaged, label); @@ -56,12 +65,9 @@ describe('getServerDescription', () => { }); describe('getServerGroupContextValue', () => { - it.each([ - ['Managed', true], - ['Running', true], - ['Managed', false], - ['Running', false], - ] as const)( + const group = ['Managed', 'Running'] as const; + + it.each(matrix(group, boolValues))( 'should return context value when servers can be managed: group=%s, canStartServer=%s', (group, canStartServer) => { const actual = getServerGroupContextValue(group, canStartServer); @@ -71,12 +77,9 @@ describe('getServerGroupContextValue', () => { }); describe('getServerGroupTreeItem', () => { - it.each([ - ['Managed', true], - ['Running', true], - ['Managed', false], - ['Running', false], - ] as const)( + const group = ['Managed', 'Running'] as const; + + it.each(matrix(group, boolValues))( 'should return server group tree item: group=%s, canStartServer=%s', (group, canStartServer) => { const actual = getServerGroupTreeItem(group, canStartServer); @@ -86,16 +89,7 @@ describe('getServerGroupTreeItem', () => { }); describe('getServerIconID', () => { - it.each([ - [true, true, true], - [true, true, false], - [true, false, true], - [true, false, false], - [false, true, true], - [false, true, false], - [false, false, true], - [false, false, false], - ])( + it.each(matrix(boolValues, boolValues, boolValues))( 'should return icon id based on server state: isConnected=%s, isManaged=%s, isRunning=%s', (isConnected, isManaged, isRunning) => { const actual = getServerIconID({ isConnected, isManaged, isRunning }); @@ -110,16 +104,7 @@ describe('getServerTreeItem', () => { url: new URL('http://localhost:10000'), }; - it.each([ - [true, true, true], - [true, true, false], - [true, false, true], - [true, false, false], - [false, true, true], - [false, true, false], - [false, false, true], - [false, false, false], - ])( + it.each(matrix(boolValues, boolValues, boolValues))( 'should return DHC server tree item: isConnected=%s, isManaged=%s, isRunning=%s', (isConnected, isManaged, isRunning) => { const actual = getServerTreeItem({ @@ -136,16 +121,7 @@ describe('getServerTreeItem', () => { describe('groupServers', () => { it('should group servers by state', () => { - const props = [ - [true, true], - [true, true], - [true, false], - [true, false], - [false, true], - [false, true], - [false, false], - [false, false], - ]; + const props = matrix(boolValues, boolValues); const servers = props.map( ([isManaged, isRunning], i) => diff --git a/src/util/treeViewUtils.ts b/src/util/treeViewUtils.ts index 23a71dbc..9ec4661b 100644 --- a/src/util/treeViewUtils.ts +++ b/src/util/treeViewUtils.ts @@ -70,7 +70,6 @@ export function getPanelVariableTreeItem([url, variable]: [ return { description: variable.title, - // iconPath: iconId == null ? undefined : new vscode.ThemeIcon(iconId), iconPath, command: { title: 'Open Panel', From 880c7289ac2277cd980e2e3d64190069bb27522f Mon Sep 17 00:00:00 2001 From: Brian Ingles Date: Wed, 11 Sep 2024 12:37:13 -0500 Subject: [PATCH 31/40] Fixed regression (#116-2) --- src/util/treeViewUtils.spec.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/util/treeViewUtils.spec.ts b/src/util/treeViewUtils.spec.ts index e9824684..28256814 100644 --- a/src/util/treeViewUtils.spec.ts +++ b/src/util/treeViewUtils.spec.ts @@ -121,7 +121,9 @@ describe('getServerTreeItem', () => { describe('groupServers', () => { it('should group servers by state', () => { - const props = matrix(boolValues, boolValues); + // Note that each combination is duplicated so that multiple servers get + // created for each group. + const props = matrix(boolValues, [true, true, false, false]); const servers = props.map( ([isManaged, isRunning], i) => From 696631976379a054ae4cdfbcce7952a53946ee72 Mon Sep 17 00:00:00 2001 From: Brian Ingles Date: Wed, 11 Sep 2024 12:42:13 -0500 Subject: [PATCH 32/40] Unit tests (#116-2) --- .../__snapshots__/treeViewUtils.spec.ts.snap | 253 ++++++++++++++++++ src/util/treeViewUtils.spec.ts | 34 ++- 2 files changed, 286 insertions(+), 1 deletion(-) diff --git a/src/util/__snapshots__/treeViewUtils.spec.ts.snap b/src/util/__snapshots__/treeViewUtils.spec.ts.snap index d6860d55..5eea59ae 100644 --- a/src/util/__snapshots__/treeViewUtils.spec.ts.snap +++ b/src/util/__snapshots__/treeViewUtils.spec.ts.snap @@ -48,6 +48,259 @@ exports[`getPanelConnectionTreeItem > should return panel connection tree item: } `; +exports[`getPanelVariableTreeItem > should return panel variable tree item: type:Figure 1`] = ` +{ + "command": { + "arguments": [ + "http://localhost:10000/", + [ + { + "title": "some title", + "type": "Figure", + }, + ], + ], + "command": "vscode-deephaven.openVariablePanels", + "title": "Open Panel", + }, + "description": "some title", + "iconPath": { + "color": undefined, + "id": "graph", + }, +} +`; + +exports[`getPanelVariableTreeItem > should return panel variable tree item: type:HierarchicalTable 1`] = ` +{ + "command": { + "arguments": [ + "http://localhost:10000/", + [ + { + "title": "some title", + "type": "HierarchicalTable", + }, + ], + ], + "command": "vscode-deephaven.openVariablePanels", + "title": "Open Panel", + }, + "description": "some title", + "iconPath": { + "color": undefined, + "id": "dh-table", + }, +} +`; + +exports[`getPanelVariableTreeItem > should return panel variable tree item: type:OtherWidget 1`] = ` +{ + "command": { + "arguments": [ + "http://localhost:10000/", + [ + { + "title": "some title", + "type": "OtherWidget", + }, + ], + ], + "command": "vscode-deephaven.openVariablePanels", + "title": "Open Panel", + }, + "description": "some title", + "iconPath": { + "color": undefined, + "id": "preview", + }, +} +`; + +exports[`getPanelVariableTreeItem > should return panel variable tree item: type:PartitionedTable 1`] = ` +{ + "command": { + "arguments": [ + "http://localhost:10000/", + [ + { + "title": "some title", + "type": "PartitionedTable", + }, + ], + ], + "command": "vscode-deephaven.openVariablePanels", + "title": "Open Panel", + }, + "description": "some title", + "iconPath": { + "color": undefined, + "id": "dh-table", + }, +} +`; + +exports[`getPanelVariableTreeItem > should return panel variable tree item: type:Table 1`] = ` +{ + "command": { + "arguments": [ + "http://localhost:10000/", + [ + { + "title": "some title", + "type": "Table", + }, + ], + ], + "command": "vscode-deephaven.openVariablePanels", + "title": "Open Panel", + }, + "description": "some title", + "iconPath": { + "color": undefined, + "id": "dh-table", + }, +} +`; + +exports[`getPanelVariableTreeItem > should return panel variable tree item: type:TableMap 1`] = ` +{ + "command": { + "arguments": [ + "http://localhost:10000/", + [ + { + "title": "some title", + "type": "TableMap", + }, + ], + ], + "command": "vscode-deephaven.openVariablePanels", + "title": "Open Panel", + }, + "description": "some title", + "iconPath": { + "color": undefined, + "id": "dh-table", + }, +} +`; + +exports[`getPanelVariableTreeItem > should return panel variable tree item: type:TreeTable 1`] = ` +{ + "command": { + "arguments": [ + "http://localhost:10000/", + [ + { + "title": "some title", + "type": "TreeTable", + }, + ], + ], + "command": "vscode-deephaven.openVariablePanels", + "title": "Open Panel", + }, + "description": "some title", + "iconPath": { + "color": undefined, + "id": "dh-table", + }, +} +`; + +exports[`getPanelVariableTreeItem > should return panel variable tree item: type:Treemap 1`] = ` +{ + "command": { + "arguments": [ + "http://localhost:10000/", + [ + { + "title": "some title", + "type": "Treemap", + }, + ], + ], + "command": "vscode-deephaven.openVariablePanels", + "title": "Open Panel", + }, + "description": "some title", + "iconPath": { + "color": undefined, + "id": "preview", + }, +} +`; + +exports[`getPanelVariableTreeItem > should return panel variable tree item: type:deephaven.plot.express.DeephavenFigure 1`] = ` +{ + "command": { + "arguments": [ + "http://localhost:10000/", + [ + { + "title": "some title", + "type": "deephaven.plot.express.DeephavenFigure", + }, + ], + ], + "command": "vscode-deephaven.openVariablePanels", + "title": "Open Panel", + }, + "description": "some title", + "iconPath": { + "color": undefined, + "id": "graph", + }, +} +`; + +exports[`getPanelVariableTreeItem > should return panel variable tree item: type:deephaven.ui.Element 1`] = ` +{ + "command": { + "arguments": [ + "http://localhost:10000/", + [ + { + "title": "some title", + "type": "deephaven.ui.Element", + }, + ], + ], + "command": "vscode-deephaven.openVariablePanels", + "title": "Open Panel", + }, + "description": "some title", + "iconPath": { + "color": undefined, + "id": "preview", + }, +} +`; + +exports[`getPanelVariableTreeItem > should return panel variable tree item: type:pandas.DataFrame 1`] = ` +{ + "command": { + "arguments": [ + "http://localhost:10000/", + [ + { + "title": "some title", + "type": "pandas.DataFrame", + }, + ], + ], + "command": "vscode-deephaven.openVariablePanels", + "title": "Open Panel", + }, + "description": "some title", + "iconPath": { + "color": undefined, + "id": "dh-pandas", + }, +} +`; + exports[`getServerContextValue > should return contextValue based on server state: isConnected=false, isManaged=false, isRunning=false 1`] = `"isServerStopped"`; exports[`getServerContextValue > should return contextValue based on server state: isConnected=false, isManaged=false, isRunning=true 1`] = `"isServerRunningDisconnected"`; diff --git a/src/util/treeViewUtils.spec.ts b/src/util/treeViewUtils.spec.ts index 28256814..d2bece5c 100644 --- a/src/util/treeViewUtils.spec.ts +++ b/src/util/treeViewUtils.spec.ts @@ -2,6 +2,7 @@ import { describe, it, expect, vi } from 'vitest'; import { bitValues, boolValues, matrix } from './testUtils'; import { getPanelConnectionTreeItem, + getPanelVariableTreeItem, getServerContextValue, getServerDescription, getServerGroupContextValue, @@ -10,7 +11,12 @@ import { getServerTreeItem, groupServers, } from './treeViewUtils'; -import type { ConsoleType, IDhService, ServerState } from '../types'; +import type { + ConsoleType, + IDhService, + ServerState, + VariableDefintion, +} from '../types'; // See __mocks__/vscode.ts for the mock implementation vi.mock('vscode'); @@ -38,6 +44,32 @@ describe('getPanelConnectionTreeItem', () => { ); }); +describe('getPanelVariableTreeItem', () => { + const url = new URL('http://localhost:10000'); + + it.each([ + 'deephaven.plot.express.DeephavenFigure', + 'deephaven.ui.Element', + 'Figure', + 'HierarchicalTable', + 'OtherWidget', + 'pandas.DataFrame', + 'PartitionedTable', + 'Table', + 'TableMap', + 'Treemap', + 'TreeTable', + ] as const)('should return panel variable tree item: type:%s', type => { + const variable = { + title: 'some title', + type, + } as VariableDefintion; + + const actual = getPanelVariableTreeItem([url, variable]); + expect(actual).toMatchSnapshot(); + }); +}); + describe('getServerContextValue', () => { it.each(matrix(boolValues, boolValues, boolValues))( 'should return contextValue based on server state: isConnected=%s, isManaged=%s, isRunning=%s', From c836e4fbe2cd858d93293eb8719af9aa09aefec6 Mon Sep 17 00:00:00 2001 From: Brian Ingles Date: Wed, 11 Sep 2024 12:45:48 -0500 Subject: [PATCH 33/40] Added cases to switch (#116-2) --- src/util/treeViewUtils.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/util/treeViewUtils.ts b/src/util/treeViewUtils.ts index 9ec4661b..0e06dcb7 100644 --- a/src/util/treeViewUtils.ts +++ b/src/util/treeViewUtils.ts @@ -32,6 +32,8 @@ export function getVariableIconPath( return new vscode.ThemeIcon(ICON_ID.varPandas); case 'deephaven.ui.Element': + case 'OtherWidget': + case 'Treemap': default: return new vscode.ThemeIcon(ICON_ID.varElement); } From bc65bdd5d78e3d7a26b8335e002a91753faca267 Mon Sep 17 00:00:00 2001 From: Brian Ingles Date: Wed, 11 Sep 2024 12:48:17 -0500 Subject: [PATCH 34/40] Added comment (#116-2) --- src/util/treeViewUtils.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/util/treeViewUtils.ts b/src/util/treeViewUtils.ts index 0e06dcb7..3b8dd22e 100644 --- a/src/util/treeViewUtils.ts +++ b/src/util/treeViewUtils.ts @@ -16,6 +16,7 @@ import { export function getVariableIconPath( variableType: VariableType ): vscode.TreeItem['iconPath'] { + // Based on @deephaven/console `ObjectIcon` switch (variableType) { case 'Table': case 'TableMap': From 660e8844d837322e61072151c3679cadf4e3bded Mon Sep 17 00:00:00 2001 From: Brian Ingles Date: Wed, 11 Sep 2024 12:58:19 -0500 Subject: [PATCH 35/40] Renamed vars (#116-2) --- src/util/treeViewUtils.spec.ts | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/util/treeViewUtils.spec.ts b/src/util/treeViewUtils.spec.ts index d2bece5c..e514cacf 100644 --- a/src/util/treeViewUtils.spec.ts +++ b/src/util/treeViewUtils.spec.ts @@ -85,9 +85,9 @@ describe('getServerContextValue', () => { }); describe('getServerDescription', () => { - const label = ['some label', undefined] as const; + const labelValeus = ['some label', undefined] as const; - it.each(matrix(bitValues, boolValues, label))( + it.each(matrix(bitValues, boolValues, labelValeus))( 'should return server description based on parameters: connectionCount=%s, isManaged=%s, label=%s', (connectionCount, isManaged, label) => { const actual = getServerDescription(connectionCount, isManaged, label); @@ -97,9 +97,9 @@ describe('getServerDescription', () => { }); describe('getServerGroupContextValue', () => { - const group = ['Managed', 'Running'] as const; + const groupValues = ['Managed', 'Running'] as const; - it.each(matrix(group, boolValues))( + it.each(matrix(groupValues, boolValues))( 'should return context value when servers can be managed: group=%s, canStartServer=%s', (group, canStartServer) => { const actual = getServerGroupContextValue(group, canStartServer); @@ -109,9 +109,9 @@ describe('getServerGroupContextValue', () => { }); describe('getServerGroupTreeItem', () => { - const group = ['Managed', 'Running'] as const; + const groupValues = ['Managed', 'Running'] as const; - it.each(matrix(group, boolValues))( + it.each(matrix(groupValues, boolValues))( 'should return server group tree item: group=%s, canStartServer=%s', (group, canStartServer) => { const actual = getServerGroupTreeItem(group, canStartServer); From cacc9855eb26e69b073952bb692cd280bf9b7277 Mon Sep 17 00:00:00 2001 From: Brian Ingles Date: Wed, 11 Sep 2024 14:30:26 -0500 Subject: [PATCH 36/40] Unit tests (#116-2) --- .../__snapshots__/treeViewUtils.spec.ts.snap | 82 +++++++++++++++++++ src/util/treeViewUtils.spec.ts | 57 ++++++++----- 2 files changed, 118 insertions(+), 21 deletions(-) diff --git a/src/util/__snapshots__/treeViewUtils.spec.ts.snap b/src/util/__snapshots__/treeViewUtils.spec.ts.snap index 5eea59ae..d08eb7d6 100644 --- a/src/util/__snapshots__/treeViewUtils.spec.ts.snap +++ b/src/util/__snapshots__/treeViewUtils.spec.ts.snap @@ -535,6 +535,88 @@ exports[`getServerTreeItem > should return DHC server tree item: isConnected=tru } `; +exports[`getVariableIconPath > should return icon path for variableType 1`] = ` +[ + [ + "deephaven.plot.express.DeephavenFigure", + { + "color": undefined, + "id": "graph", + }, + ], + [ + "deephaven.ui.Element", + { + "color": undefined, + "id": "preview", + }, + ], + [ + "Figure", + { + "color": undefined, + "id": "graph", + }, + ], + [ + "HierarchicalTable", + { + "color": undefined, + "id": "dh-table", + }, + ], + [ + "OtherWidget", + { + "color": undefined, + "id": "preview", + }, + ], + [ + "pandas.DataFrame", + { + "color": undefined, + "id": "dh-pandas", + }, + ], + [ + "PartitionedTable", + { + "color": undefined, + "id": "dh-table", + }, + ], + [ + "Table", + { + "color": undefined, + "id": "dh-table", + }, + ], + [ + "TableMap", + { + "color": undefined, + "id": "dh-table", + }, + ], + [ + "Treemap", + { + "color": undefined, + "id": "preview", + }, + ], + [ + "TreeTable", + { + "color": undefined, + "id": "dh-table", + }, + ], +] +`; + exports[`groupServers > should group servers by state 1`] = ` { "managed": [ diff --git a/src/util/treeViewUtils.spec.ts b/src/util/treeViewUtils.spec.ts index e514cacf..23718f23 100644 --- a/src/util/treeViewUtils.spec.ts +++ b/src/util/treeViewUtils.spec.ts @@ -9,6 +9,7 @@ import { getServerGroupTreeItem, getServerIconID, getServerTreeItem, + getVariableIconPath, groupServers, } from './treeViewUtils'; import type { @@ -16,11 +17,26 @@ import type { IDhService, ServerState, VariableDefintion, + VariableType, } from '../types'; // See __mocks__/vscode.ts for the mock implementation vi.mock('vscode'); +const variableTypes: readonly VariableType[] = [ + 'deephaven.plot.express.DeephavenFigure', + 'deephaven.ui.Element', + 'Figure', + 'HierarchicalTable', + 'OtherWidget', + 'pandas.DataFrame', + 'PartitionedTable', + 'Table', + 'TableMap', + 'Treemap', + 'TreeTable', +] as const; + describe('getPanelConnectionTreeItem', () => { const getConsoleTypes: IDhService['getConsoleTypes'] = vi .fn() @@ -47,27 +63,18 @@ describe('getPanelConnectionTreeItem', () => { describe('getPanelVariableTreeItem', () => { const url = new URL('http://localhost:10000'); - it.each([ - 'deephaven.plot.express.DeephavenFigure', - 'deephaven.ui.Element', - 'Figure', - 'HierarchicalTable', - 'OtherWidget', - 'pandas.DataFrame', - 'PartitionedTable', - 'Table', - 'TableMap', - 'Treemap', - 'TreeTable', - ] as const)('should return panel variable tree item: type:%s', type => { - const variable = { - title: 'some title', - type, - } as VariableDefintion; - - const actual = getPanelVariableTreeItem([url, variable]); - expect(actual).toMatchSnapshot(); - }); + it.each(variableTypes)( + 'should return panel variable tree item: type:%s', + type => { + const variable = { + title: 'some title', + type, + } as VariableDefintion; + + const actual = getPanelVariableTreeItem([url, variable]); + expect(actual).toMatchSnapshot(); + } + ); }); describe('getServerContextValue', () => { @@ -151,6 +158,14 @@ describe('getServerTreeItem', () => { ); }); +describe('getVariableIconPath', () => { + it('should return icon path for variableType', () => { + expect( + variableTypes.map(type => [type, getVariableIconPath(type)]) + ).toMatchSnapshot(); + }); +}); + describe('groupServers', () => { it('should group servers by state', () => { // Note that each combination is duplicated so that multiple servers get From 3a539e89dc13b6a02ae03effa9c149fcdf5111d0 Mon Sep 17 00:00:00 2001 From: Brian Ingles Date: Wed, 11 Sep 2024 14:33:10 -0500 Subject: [PATCH 37/40] Updated type + comments (#116-2) --- src/util/treeViewUtils.ts | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/util/treeViewUtils.ts b/src/util/treeViewUtils.ts index 3b8dd22e..b8fb8c0e 100644 --- a/src/util/treeViewUtils.ts +++ b/src/util/treeViewUtils.ts @@ -13,9 +13,14 @@ import { type ServerTreeItemContextValue, } from '../common'; +/** + * Get a tree item vscode.ThemeIcon for a variable type. + * @param variableType Variable type + * @returns Theme icon for the variable type + */ export function getVariableIconPath( variableType: VariableType -): vscode.TreeItem['iconPath'] { +): vscode.ThemeIcon { // Based on @deephaven/console `ObjectIcon` switch (variableType) { case 'Table': From 50df32d6b672fecbedd76a8f3afd717efc44f5bb Mon Sep 17 00:00:00 2001 From: Brian Ingles Date: Thu, 12 Sep 2024 10:43:18 -0500 Subject: [PATCH 38/40] Backed out broken pip servers (#116-2) --- src/controllers/PipServerController.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/src/controllers/PipServerController.ts b/src/controllers/PipServerController.ts index 23972482..9ab9fc9d 100644 --- a/src/controllers/PipServerController.ts +++ b/src/controllers/PipServerController.ts @@ -94,7 +94,6 @@ export class PipServerController implements Disposable { const terminal = vscode.window.createTerminal({ name: `Deephaven check pip server install`, isTransient: true, - hideFromUser: true, }); // Give python extension time to setup .venv if configured From cdac84c4a5ce5d88987e14785ed651ad55c613cf Mon Sep 17 00:00:00 2001 From: Brian Ingles Date: Thu, 12 Sep 2024 10:55:56 -0500 Subject: [PATCH 39/40] Removed auto show panel for now (#116-2) --- src/controllers/ExtensionController.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/src/controllers/ExtensionController.ts b/src/controllers/ExtensionController.ts index ceb4285d..5cc49acb 100644 --- a/src/controllers/ExtensionController.ts +++ b/src/controllers/ExtensionController.ts @@ -77,7 +77,6 @@ export class ExtensionController implements Disposable { 'Congratulations, your extension "vscode-deephaven" is now active!' ); - this._outputChannel?.show(); this._outputChannel?.appendLine('Deephaven extension activated'); } From 2a1dc809c2e5f3eaa4b9b27ec257694dee262ba1 Mon Sep 17 00:00:00 2001 From: Brian Ingles Date: Tue, 17 Sep 2024 12:10:53 -0500 Subject: [PATCH 40/40] Update src/services/PanelService.ts Co-authored-by: Mike Bender --- src/services/PanelService.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/services/PanelService.ts b/src/services/PanelService.ts index 25143da8..097de023 100644 --- a/src/services/PanelService.ts +++ b/src/services/PanelService.ts @@ -108,8 +108,8 @@ export class PanelService implements IPanelService, Disposable { /** * Update the variables for the given connection url. - * @param url - * @param variableChanges + * @param url The connection URL + * @param variableChanges Changes made on that connection */ updateVariables = ( url: URL,