Skip to content

Commit

Permalink
2.0.0 candidate, implementing a tree UI
Browse files Browse the repository at this point in the history
  • Loading branch information
gjsjohnmurray committed Apr 16, 2021
1 parent 85b4941 commit e0448fe
Show file tree
Hide file tree
Showing 9 changed files with 183 additions and 85 deletions.
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
## 2.0.0 (16-Apr-2021)
* Add tree view interface.

## 1.0.5 (02-Feb-2021)
* Fix publication problem (#69).

Expand Down
106 changes: 85 additions & 21 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,23 +1,75 @@
# InterSystems Server Manager

This is a VS Code helper extension for defining connections to [InterSystems®](https://www.intersystems.com/) servers. These connection definitions can used by other VS Code extensions when they make connections. One example is the [ObjectScript extension](https://github.com/intersystems-community/vscode-objectscript).

InterSystems Server Manager is a Visual Studio Code extension for defining connections to [InterSystems](https://www.intersystems.com/) servers. These definitions can used by other VS Code extensions when they make connections. One example is the [ObjectScript extension](https://github.com/intersystems-community/vscode-objectscript) for code editing.

# New in 2.0 - April 2021

> We are pleased to publish version 2.0 of this extension, adding a tree-style user interface. This significant new release is competing in the April 2021 InterSystems Programming Contest for Developer Tools. If you like the new 2.0 features please visit the [contest page](https://openexchange.intersystems.com/contest/13) no later than April 25 and vote for us.
> Thanks to [George James Software](https://georgejames.com) for backing this development effort.
## The Server Tree

Server Manager displays connection definitions as a tree on an InterSystems Tools view:

![Server Manager tree](images/README/tree.png)

In this tree you can:

- Launch the InterSystems Management Portal, either in a VS Code tab or in your default browser.
- List namespaces.
- Add namespaces to your VS Code workspace for viewing or editing code on the server with the [ObjectScript extension](https://github.com/intersystems-community/vscode-objectscript).
- Tag favorite servers.
- Set icon colors.
- Focus on recently used connections.
- Manage stored passwords.
- Add new servers, and edit existing ones.

In common with the rest of VS Code, Server Manager stores your connection settings in JSON files. VS Code settings are arranged in a hierarchy that you can learn more about [here](https://code.visualstudio.com/docs/getstarted/settings).

Using Server Manager you can store connection passwords in the native keystore of your workstation's operating system instead of as plaintext in JSON files.
Server Manager can store connection passwords in the native keystore of your workstation's operating system. This is a more secure alternative to you putting them as plaintext in your JSON files.

On Windows, Server Manager can create connection entries for all connections you previously defined with the original Windows app called InterSystems Server Manager. This action is available from the '`...`' menu at the top right corner of Server Manager's tree.

## Defining a New Server

1. Click the '`+`' button on Server Manager's title bar.
2. Complete the sequence of prompts.
3. Expand `All Servers` to see your new entry in the tree.

The server definition is added to your [user-level](https://code.visualstudio.com/docs/getstarted/settings) `settings.json` file.

Optionally use its context menu to store the password for the username you entered when defining the server. You can also set the color of the server icon.

On Windows you can run `Import Servers from Registry` from [Command Palette](https://code.visualstudio.com/docs/getstarted/userinterface#_command-palette) to create connection entries for all connections you previously defined with the InterSystems Server Manager.
The 'star' button that appears when you hover over the row lets you add the server to the `Favorites` list at the top of the tree.

## Defining a new connection
## Launching Management Portal

1. Open the VS Code [Command Palette](https://code.visualstudio.com/docs/getstarted/userinterface#_command-palette) by typing <kbd>Ctrl</kbd>+<kbd>Shift</kbd>+<kbd>P</kbd> (<kbd>Cmd</kbd>+<kbd>Shift</kbd>+<kbd>P</kbd> on macOS) or <kbd>F1</kbd>.
2. Start typing "Server Manager" to locate `InterSystems Server Manager: Store Password in Keychain`.
3. Type the '+' character into the quickpick input field. Alternatively click the '+' button on the top right of the quickpick.
4. Complete the prompts. By the time you reach the password prompt your connection definition has already been saved in **user-level** JSON. If you prefer to enter your password whenever a VS Code extension connects via Server Manager for the first time in a session, press <kbd>Esc</kbd> here.
When you hover over a server entry in the tree, two command buttons let you launch InterSystems Management Portal.

## Amending and removing definitions
The first button uses VS Code's Simple Browser feature, which creates a tab alongside any documents you may have open. The second button opens Portal in your workstation's default web browser.

To manage your definitions, [edit the relevant JSON file](https://code.visualstudio.com/docs/getstarted/settings). VS Code offers several routes to these files. One way is to type "json" into the Command Palette.
### Notes About Simple Browser
- There is only ever a single Simple Browser tab. Launching another server's Management Portal in it will replace the previous one.
- If the server version is InterSystems IRIS 2021.1.1 or later you will need to change a setting on the suite of web applications that implement Management Portal. This is a consequence of change [SGM031 - Support SameSite for CSP session and user cookies](https://docs.intersystems.com/iris20201/csp/docbook/relnotes/index.html#SGM031). Simple Browser will not be permitted to store Portal's session management cookies, so Portal must be willing to fall back to using the CSPCHD query parameter mechanism.
- Locate the five web applications whose path begins with `/csp/sys`
![Portal web app list](images/README/portalWebApps.png)

- Alter the `Use Cookie for Session` setting on each of them so it is `Autodetect` instead of `Always`.
![Portal web app detail](images/README/portalWebAppSetting.png)
Remember to save the change. The change is not thought to have any adverse effects on the usage of Portal from ordinary browsers, which will continue to use session cookies.
- When a 2020.1.1+ Portal has resorted to using CSPCHD (see above) a few inter-page links fail because they don't add the CSPCHD queryparam. One specific case is the breadcrumb links. Pending the arrival of an InterSystems correction (JIRA DP-404817) these links will take you to the login page. Either enter your credentials to proceed, or launch Simple Browser again from the Server Manager tree.

## Amending and Removing Servers

To manage your server definitions, including changing the username it connects with, [edit the relevant JSON file](https://code.visualstudio.com/docs/getstarted/settings).

1. From a server's context menu, or from Server Manager's top-right '`...`' menu, choose `Edit Settings`. This opens VS Code's Settings Editor and filters its contents.

![Edit Settings](images/README/editSettings.png)

2. Click the `Edit in settings.json` link.

In this example two connections have been defined:

Expand Down Expand Up @@ -48,33 +100,45 @@ In this example two connections have been defined:

The JSON editor offers the usual [IntelliSense](https://code.visualstudio.com/docs/editor/intellisense) as you work in this structure.

Notice how you can add a `description` property to each connection. This will be shown alongside its entry in the server quickpick.
Notice how you can add a `description` property to each connection. This will be shown in the hover in Server Manager's tree, and alongside the entry if a server quickpick is used.

Servers are displayed in the quickpick in the order they are defined in the JSON file. The exception is that if a server name is set as the value of the `/default` property (see example above) it will be shown first in the list.

A set of embedded servers with names beginning `default~` will appear at the end of the quickpick unless you add the property `"/hideEmbeddedEntries": true` to your `intersystems.server` object (see above).
A set of embedded servers with names beginning `default~` will appear at the end of the lists unless you add the property `"/hideEmbeddedEntries": true` to your `intersystems.server` object to hide them (see above).

## Removing a Stored Password

Use the server's context menu. Alternatively, run `InterSystems Server Manager: Clear Password from Keychain` from Command Palette.

---

## Technical Notes

### Colors, Favorites and Recents

These features use VS Code's extension-private global state storage. Data is not present in your `settings.json` file.

### The 'All Servers' Folder

## Removing a stored password
The `All Servers` tree respects the optional `/default` and `/hideEmbeddedEntries` settings in the `intersystems.servers` JSON.

The command `InterSystems Server Manager: Clear Password from Keychain` removes a stored password.
If a server has been named in `/default` it is promoted to the top of the list, which is otherwise presented in alphabetical order.

**Usage:**
Embedded entries (built-in default ones) are demoted to the end of the list, or omitted completely if `/hideEmbeddedEntries` is true.

1. Bring up the [Command Palette](https://code.visualstudio.com/docs/getstarted/userinterface#_command-palette) by typing Ctrl+Shift+P (Cmd+Shift+P on Mac) or F1.
2. Start typing "Server Manager" to locate the `InterSystems Server Manager: Clear Password from Keychain` command.
3. Pick a server.
---

## For VS Code Extension Developers: Use By Other Extensions
## Information for VS Code Extension Developers - How To Leverage Server Manager

An extension XYZ needing to connect to InterSystems servers can define this extension as a dependency in its `package.json`
An extension XYZ needing to connect to InterSystems servers can define Server Manager as a dependency in its `package.json` like this:

```json
"extensionDependencies": [
"intersystems-community.servermanager"
],
```

Alternatively the `activate` method of XYZ can detect if the extension is already available, then offer to install it if necessary:
Alternatively the `activate` method of XYZ can detect whether the extension is already available, then offer to install it if necessary:

```ts
const extId = "intersystems-community.servermanager";
Expand Down
Binary file added images/README/editSettings.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added images/README/portalWebAppSetting.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added images/README/portalWebApps.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added images/README/tree.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
16 changes: 14 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
{
"name": "servermanager",
"displayName": "InterSystems Server Manager",
"version": "2.0.0-SNAPSHOT.4",
"version": "2.0.0-SNAPSHOT",
"publisher": "intersystems-community",
"description": "Helper extension for defining connections to InterSystems servers.",
"description": "Define connections to InterSystems servers. Browse and manage those servers.",
"repository": {
"type": "git",
"url": "https://github.com/intersystems-community/intersystems-servermanager"
Expand Down Expand Up @@ -89,6 +89,13 @@
}
]
},
"viewsWelcome": [
{
"view": "explorer",
"contents": "Use the 'InterSystems Tools: Servers' view to work with your servers.\n[Manage Servers $(tools)](command:workbench.view.extension.intersystems-community_servermanager)"
}
]
,
"configuration": {
"title": "InterSystems Server Manager",
"properties": {
Expand Down Expand Up @@ -392,6 +399,11 @@
}
],
"view/item/context": [
{
"command": "intersystems-community.servermanager.addServer",
"when": "view == intersystems-community_servermanager && viewItem == sorted",
"group": "inline@10"
},
{
"command": "intersystems-community.servermanager.addToStarred",
"when": "view == intersystems-community_servermanager && viewItem =~ /\\.server\\.$/",
Expand Down
119 changes: 64 additions & 55 deletions src/api/addServer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,69 +27,78 @@ export async function addServer(
.then(
async (name): Promise<string | undefined> => {
if (name) {
const host = await vscode.window.showInputBox({
placeHolder: "Hostname or IP address of web server",
validateInput: (value) => {
return value.trim().length ? undefined : "Required";
},
const description = await vscode.window.showInputBox({
placeHolder: "Optional description",
ignoreFocusOut: true
});
if (host) {
spec.webServer.host = host.trim();
const portString = await vscode.window.showInputBox({
placeHolder: "Port of web server",
if (typeof description !== 'undefined') {
if (description) {
spec.description = description.trim();
}
const host = await vscode.window.showInputBox({
placeHolder: "Hostname or IP address of web server",
validateInput: (value) => {
const port = +value;
return value.match(/\d+/) &&
port.toString() === value &&
port > 0 &&
port < 65536
? undefined
: "Required, 1-65535";
return value.trim().length ? undefined : "Required";
},
ignoreFocusOut: true
});
if (portString) {
spec.webServer.port = +portString;
const username = await vscode.window.showInputBox({
placeHolder:
"Username",
prompt:
"Leave empty to be prompted when connecting.",
if (host) {
spec.webServer.host = host.trim();
const portString = await vscode.window.showInputBox({
placeHolder: "Port of web server",
validateInput: (value) => {
const port = +value;
return value.match(/\d+/) &&
port.toString() === value &&
port > 0 &&
port < 65536
? undefined
: "Required, 1-65535";
},
ignoreFocusOut: true
});
if (typeof username !== 'undefined') {
const usernameTrimmed = username.trim();
if (usernameTrimmed !== "") {
spec.username = usernameTrimmed;
}
const scheme = await vscode.window.showQuickPick(
["http", "https"],
{
placeHolder:
"Confirm connection type, then the definition will be stored in your User Settings. 'Escape' to cancel.",
ignoreFocusOut: true
});
if (portString) {
spec.webServer.port = +portString;
const username = await vscode.window.showInputBox({
placeHolder:
"Username",
prompt:
"Leave empty to be prompted when connecting.",
ignoreFocusOut: true
});
if (typeof username !== 'undefined') {
const usernameTrimmed = username.trim();
if (usernameTrimmed !== "") {
spec.username = usernameTrimmed;
}
const scheme = await vscode.window.showQuickPick(
["http", "https"],
{
placeHolder:
"Confirm connection type, then the definition will be stored in your User Settings. 'Escape' to cancel.",
ignoreFocusOut: true
}
);
if (scheme) {
spec.webServer.scheme = scheme;
try {
const config = vscode.workspace.getConfiguration(
"intersystems",
scope
);
// For simplicity we always add to the user-level (aka Global) settings
const servers: any =
config.inspect("servers")?.globalValue || {};
servers[name] = spec;
await config.update("servers", servers, true);
vscode.window.showInformationMessage(`Server '${name}' stored in user-level settings.`);
return name;
} catch (error) {
vscode.window.showErrorMessage(
"Failed to store server '${name}' definition."
);
return undefined;
}
);
if (scheme) {
spec.webServer.scheme = scheme;
try {
const config = vscode.workspace.getConfiguration(
"intersystems",
scope
);
// For simplicity we always add to the user-level (aka Global) settings
const servers: any =
config.inspect("servers")?.globalValue || {};
servers[name] = spec;
await config.update("servers", servers, true);
vscode.window.showInformationMessage(`Server '${name}' stored in user-level settings.`);
return name;
} catch (error) {
vscode.window.showErrorMessage(
"Failed to store server '${name}' definition."
);
return undefined;
}
}
}
Expand Down
Loading

0 comments on commit e0448fe

Please sign in to comment.