Skip to content

Commit

Permalink
feat: DHC server / connection management (#106)
Browse files Browse the repository at this point in the history
This is an overhaul of how servers / connections are managed by the
extension.

## Config Settings
> BREAKING CHANGE: config setting keys were changed from hyphenated
names to camelCase ones.

- Servers no longer allow specifying console type in config since users
may re-use same port to start different servers. Console type is now a
connection scoped attribute as opposed to server.
- Server configs now support an optional label that will show up in UI

Here's an example config that should showcase this + other features in
this PR.
```json
"deephaven.coreServers": [
    "http://localhost:10010/",
    {
      "label": "My Groovy Server",
      "url": "http://localhost:10011/"
    },
    "http://localhost:10012/",
    "http://localhost:10013/"  
],
```

## DH View Container
- Accessible via icon in activity bar (sidebar)

### Server tree view
 - Sections for Running / Stopped servers
- ~This panel polls the servers to see if they are running by checking
for 200 status return on jsapi urls. The polling starts the first time
`getServers` is called on the ServerManager which shouldn't happen until
a user either opens the viewcontainer or attempts to select a
connection.~ No longer polls. Instead checks on key events if server
treeview + window is active / visible
- Open connection action (can also click on the server item as a
shortcut)
 - Open in browser action
 
### Connection tree view
- Shows active connections + supported console types
- Editors can be associated with a supporting connection. They show up
as children in the tree
- Supports drag and drop of editors between supporting connections +
dragging editor tab into a supporting connection

## Connection selector status bar item
   - Moved to right to be contextual to current editor
- Shows active connections that support the language of the current
editor + running servers that don't have active connections
   
## Smart connection selection
When clicking a run code button in an editor, different rules determine
what happens
- If there is only 1 running server, connect to it
- If there is 1 active connection that supports the language and no
remaining disconnected servers, use the active connection
- If there is a combination of running servers without connections and /
or active connections that total > 1, prompt the user to select one
- Once an editor is associated with a connection, it will keep running
on that connection without re-prompting. User can re-associate it
explicitly with another connection

resolves #7
  • Loading branch information
bmingles authored Aug 29, 2024
1 parent bc95b80 commit cee03e4
Show file tree
Hide file tree
Showing 46 changed files with 1,984 additions and 694 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ e.g. `.vscode/settings.json`
```json
{
// Core servers
"vscode-deephaven.core-servers": [
"deephaven.coreServers": [
"http://localhost:10000/",
"http://localhost:10001"
]
Expand Down
12 changes: 6 additions & 6 deletions e2e/specs/config.e2e.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@ describe('Extension config testing', () => {
const config = await getConfig();

expect(config).toStrictEqual({
'core-servers': ['http://localhost:10000/'],
'enterprise-servers': [],
coreServers: ['http://localhost:10000/'],
enterpriseServers: [],
});
});

Expand All @@ -27,14 +27,14 @@ describe('Extension config testing', () => {
] as const
).forEach(([label, coreServers, enterpriseServers]) => {
it(`should return custom settings: ${label}`, async () => {
await setConfigSectionSettings('core-servers', coreServers);
await setConfigSectionSettings('enterprise-servers', enterpriseServers);
await setConfigSectionSettings('coreServers', coreServers);
await setConfigSectionSettings('enterpriseServers', enterpriseServers);

const config = await getConfig();

expect(config).toStrictEqual({
'core-servers': coreServers,
'enterprise-servers': enterpriseServers,
coreServers,
enterpriseServers,
});
});
});
Expand Down
6 changes: 1 addition & 5 deletions e2e/specs/test.e2e.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ describe('VS Code Extension Testing', () => {
describe('Connection status bar item', () => {
beforeEach(async () => {
await setConfigSectionSettings(
'core-servers',
'coreServers',
PYTHON_AND_GROOVY_SERVER_CONFIG
);
await openEditors(['test.txt', 'test.groovy', 'test.py']);
Expand All @@ -48,10 +48,6 @@ describe('Connection status bar item', () => {

await workbench.getEditorView().openEditor(supportedTitle);
expect(await hasConnectionStatusBarItem()).toBeTruthy();

// Set to empty array to clear all server configs
await setConfigSectionSettings('core-servers', []);
expect(await hasConnectionStatusBarItem()).toBeFalsy();
});
});
});
20 changes: 10 additions & 10 deletions e2e/testUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,14 @@ import * as vscode from 'vscode';
// passed in as additional parameters.
// See https://www.npmjs.com/package/wdio-vscode-service#accessing-vscode-apis

// EXTENSION_ID and ConfigSectionKey are based on `src/common/constants.ts`.
// CONFIG_ROOT_KEY and ConfigSectionKey are based on `src/common/constants.ts`.
// We can't currently import source code from the extension into the e2e tests
// due to isolated tsconfigs. Should be fine for now since the duplication is
// small and tests should fail if things get out of sync. If this duplication
// grows, will need to figure out how to reconfigure to support importing from
// the source code.
const EXTENSION_ID = 'vscode-deephaven' as const;
type ConfigSectionKey = 'core-servers' | 'enterprise-servers';
const CONFIG_ROOT_KEY = 'deephaven' as const;
type ConfigSectionKey = 'coreServers' | 'enterpriseServers';

export const PYTHON_AND_GROOVY_SERVER_CONFIG = [
'http://localhost:10000',
Expand All @@ -32,7 +32,7 @@ export async function findConnectionStatusBarItem(): Promise<

return workbench.getStatusBar().getItem(
// icon name, display text, tooltip
'debug-disconnect Deephaven: Disconnected, Connect to Deephaven'
'plug Deephaven: Disconnected'
);
}

Expand Down Expand Up @@ -80,15 +80,15 @@ export async function getConfig(): Promise<vscode.WorkspaceConfiguration> {
// See note about `executeWorkbench` at top of this file.
return browser.executeWorkbench(async (vs: typeof vscode, extensionIdIn) => {
return vs.workspace.getConfiguration(extensionIdIn);
}, EXTENSION_ID);
}, CONFIG_ROOT_KEY);
}

/**
* Reset all configuration settings to their default values.
*/
export async function resetConfig(): Promise<void> {
await setConfigSectionSettings('core-servers', undefined);
await setConfigSectionSettings('enterprise-servers', undefined);
await setConfigSectionSettings('coreServers', undefined);
await setConfigSectionSettings('enterpriseServers', undefined);
}

/**
Expand All @@ -106,15 +106,15 @@ export async function setConfigSectionSettings(
await browser.executeWorkbench(
async (
vs: typeof vscode,
extensionIdIn: typeof EXTENSION_ID,
configRootKeyIn: typeof CONFIG_ROOT_KEY,
sectionKeyIn: ConfigSectionKey,
sectionValueIn: unknown | undefined
): Promise<void> => {
await vs.workspace
.getConfiguration(extensionIdIn)
.getConfiguration(configRootKeyIn)
.update(sectionKeyIn, sectionValueIn ?? undefined);
},
EXTENSION_ID,
CONFIG_ROOT_KEY,
sectionKey,
sectionValue
);
Expand Down
142 changes: 126 additions & 16 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -46,9 +46,10 @@
},
"contributes": {
"configuration": {
"title": "Deephaven in VS Code",
"title": "Deephaven",
"properties": {
"vscode-deephaven.core-servers": {
"deephaven.coreServers": {
"description": "List of Deephaven Core servers that the extension can connect to.",
"type": "array",
"items": [
{
Expand All @@ -63,31 +64,25 @@
"type": "string",
"description": "Deephaven Core server URL"
},
"consoleType": {
"label": {
"type": "string",
"title": "Console Type",
"description": "Console type",
"default": "python",
"enum": [
"python",
"groovy"
]
"title": "Label",
"description": "Optional label for the server"
}
}
}
],
"default": [
"http://localhost:10000/"
],
"description": "Deephaven Core servers"
]
},
"vscode-deephaven.enterprise-servers": {
"deephaven.enterpriseServers": {
"description": "List of Deephaven Enterprise servers that the extension can connect to.",
"type": "array",
"items": {
"type": "string"
},
"default": [],
"description": "Deephaven Enterprise servers"
"default": []
}
}
},
Expand Down Expand Up @@ -115,16 +110,74 @@
{
"command": "vscode-deephaven.downloadLogs",
"title": "Deephaven: Download Logs"
},
{
"command": "vscode-deephaven.connectToServer",
"title": "Deephaven: Connect to Server",
"icon": "$(plug)"
},
{
"command": "vscode-deephaven.disconnectEditor",
"title": "Deephaven: Disconnect Editor",
"icon": "$(debug-disconnect)"
},
{
"command": "vscode-deephaven.disconnectFromServer",
"title": "Deephaven: Discard Connection",
"icon": "$(trash)"
},
{
"command": "vscode-deephaven.openInBrowser",
"title": "Deephaven: Open in Browser",
"icon": "$(globe)"
},
{
"command": "vscode-deephaven.refreshServerTree",
"title": "Deephaven: Refresh Server Tree",
"icon": "$(refresh)"
},
{
"command": "vscode-deephaven.refreshServerConnectionTree",
"title": "Deephaven: Refresh Server Connection Tree",
"icon": "$(refresh)"
}
],
"menus": {
"commandPalette": [
{
"command": "vscode-deephaven.selectConnection",
"when": "true"
},
{
"command": "vscode-deephaven.downloadLogs",
"when": "true"
},
{
"command": "vscode-deephaven.runCode",
"when": "false"
"when": "true"
},
{
"command": "vscode-deephaven.runSelection",
"when": "true"
},
{
"command": "vscode-deephaven.connectToServer",
"when": "false"
},
{
"command": "vscode-deephaven.disconnectEditor",
"when": "false"
},
{
"command": "vscode-deephaven.disconnectFromServer",
"when": "false"
},
{
"command": "vscode-deephaven.refreshServerTree",
"when": "false"
},
{
"command": "vscode-deephaven.refreshServerConnectionTree",
"when": "false"
}
],
Expand All @@ -151,6 +204,63 @@
"group": "navigation",
"when": "editorLangId == python || editorLangId == groovy"
}
],
"view/title": [
{
"command": "vscode-deephaven.refreshServerTree",
"group": "navigation",
"when": "view == vscode-deephaven.serverTree"
},
{
"command": "vscode-deephaven.refreshServerConnectionTree",
"group": "navigation",
"when": "view == vscode-deephaven.serverConnectionTree"
}
],
"view/item/context": [
{
"command": "vscode-deephaven.connectToServer",
"when": "view == vscode-deephaven.serverTree && viewItem == isServerRunningDisconnected",
"group": "inline"
},
{
"command": "vscode-deephaven.disconnectEditor",
"when": "view == vscode-deephaven.serverConnectionTree && viewItem != isConnection",
"group": "inline"
},
{
"command": "vscode-deephaven.disconnectFromServer",
"when": "view == vscode-deephaven.serverConnectionTree && viewItem == isConnection",
"group": "inline"
},
{
"command": "vscode-deephaven.openInBrowser",
"when": "view == vscode-deephaven.serverTree && (viewItem == isServerRunningConnected || viewItem == isServerRunningDisconnected)",
"group": "inline"
}
]
},
"viewsContainers": {
"activitybar": [
{
"id": "vscode-deephaven",
"title": "Deephaven",
"icon": "images/dh-community-on-dark-128.svg"
}
]
},
"views": {
"vscode-deephaven": [
{
"id": "vscode-deephaven.serverTree",
"name": "Servers",
"type": "tree"
},
{
"id": "vscode-deephaven.serverConnectionTree",
"name": "Connections",
"type": "tree"
}
]
}
},
Expand Down
12 changes: 12 additions & 0 deletions src/common/commands.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { EXTENSION_ID } from './constants';

export const CONNECT_TO_SERVER_CMD = `${EXTENSION_ID}.connectToServer`;
export const DISCONNECT_EDITOR_CMD = `${EXTENSION_ID}.disconnectEditor`;
export const DISCONNECT_FROM_SERVER_CMD = `${EXTENSION_ID}.disconnectFromServer`;
export const DOWNLOAD_LOGS_CMD = `${EXTENSION_ID}.downloadLogs`;
export const OPEN_IN_BROWSER_CMD = `${EXTENSION_ID}.openInBrowser`;
export const REFRESH_SERVER_TREE_CMD = `${EXTENSION_ID}.refreshServerTree`;
export const REFRESH_SERVER_CONNECTION_TREE_CMD = `${EXTENSION_ID}.refreshServerConnectionTree`;
export const RUN_CODE_COMMAND = `${EXTENSION_ID}.runCode`;
export const RUN_SELECTION_COMMAND = `${EXTENSION_ID}.runSelection`;
export const SELECT_CONNECTION_COMMAND = `${EXTENSION_ID}.selectConnection`;
Loading

0 comments on commit cee03e4

Please sign in to comment.