Skip to content

Commit ab998dd

Browse files
committed
Add shortcut to Explorer section of Portal at namespace level
1 parent ba75e5e commit ab998dd

File tree

3 files changed

+97
-18
lines changed

3 files changed

+97
-18
lines changed

package.json

Lines changed: 27 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
"multi-root ready"
1616
],
1717
"engines": {
18-
"vscode": "^1.63.0"
18+
"vscode": "^1.75.0"
1919
},
2020
"icon": "images/logo.png",
2121
"categories": [
@@ -51,7 +51,7 @@
5151
},
5252
"devDependencies": {
5353
"@intersystems-community/intersystems-servermanager": "latest",
54-
"@types/vscode": "^1.63.0",
54+
"@types/vscode": "^1.75.0",
5555
"@types/glob": "^7.1.1",
5656
"@types/keytar": "^4.4.2",
5757
"@types/mocha": "^9.0.0",
@@ -65,14 +65,7 @@
6565
},
6666
"main": "./out/extension",
6767
"activationEvents": [
68-
"onAuthenticationRequest:intersystems-servermanager-credentials",
69-
"onView:intersystems-community_servermanager",
70-
"onCommand:intersystems-community.servermanager.refreshTree",
71-
"onCommand:intersystems-community.servermanager.addServer",
72-
"onCommand:intersystems-community.servermanager.storePassword",
73-
"onCommand:intersystems-community.servermanager.clearPassword",
74-
"onCommand:intersystems-community.servermanager.migratePasswords",
75-
"onCommand:intersystems-community.servermanager.importServers"
68+
"onAuthenticationRequest:intersystems-servermanager-credentials"
7669
],
7770
"contributes": {
7871
"viewsContainers": {
@@ -292,6 +285,16 @@
292285
"title": "Open Management Portal in Tab",
293286
"icon": "$(tools)"
294287
},
288+
{
289+
"command": "intersystems-community.servermanager.openPortalExplorerTab",
290+
"title": "Open Management Portal's Class Utilities in Tab",
291+
"icon": "$(tools)"
292+
},
293+
{
294+
"command": "intersystems-community.servermanager.openPortalExplorerExternal",
295+
"title": "Open in External Browser",
296+
"icon": "$(link-external)"
297+
},
295298
{
296299
"command": "intersystems-community.servermanager.retryServer",
297300
"title": "Refresh",
@@ -463,6 +466,14 @@
463466
"command": "intersystems-community.servermanager.openPortalTab",
464467
"when": "false"
465468
},
469+
{
470+
"command": "intersystems-community.servermanager.openPortalExplorerExternal",
471+
"when": "false"
472+
},
473+
{
474+
"command": "intersystems-community.servermanager.openPortalExplorerTab",
475+
"when": "false"
476+
},
466477
{
467478
"command": "intersystems-community.servermanager.retryServer",
468479
"when": "false"
@@ -613,6 +624,12 @@
613624
"when": "view == intersystems-community_servermanager && viewItem =~ /\\.server\\./",
614625
"group": "inline@90"
615626
},
627+
{
628+
"command": "intersystems-community.servermanager.openPortalExplorerTab",
629+
"when": "view == intersystems-community_servermanager && viewItem =~ /namespace$/",
630+
"group": "inline@80",
631+
"alt": "intersystems-community.servermanager.openPortalExplorerExternal"
632+
},
616633
{
617634
"command": "intersystems-community.servermanager.retryServer",
618635
"when": "view == intersystems-community_servermanager && viewItem =~ /\\.server\\./",

src/api/getPortalUriWithToken.ts

Lines changed: 34 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -11,14 +11,16 @@ export enum BrowserTarget {
1111

1212
const allTokens = [new Map<string, string>(), new Map<string, string>()];
1313

14+
const simpleBrowserCompatible = new Map<string, boolean>();
15+
1416
export async function getPortalUriWithToken(
1517
target: BrowserTarget,
1618
name: string,
19+
page = "/csp/sys/UtilHome.csp",
20+
namespace = "%SYS",
1721
scope?: vscode.ConfigurationScope,
1822
): Promise<Uri | undefined> {
1923

20-
const PORTAL_HOME = "/csp/sys/UtilHome.csp";
21-
2224
// Use our own API so that the Recent folder updates with our activity
2325
const myApi = vscode.extensions.getExtension(extensionId)?.exports;
2426

@@ -32,8 +34,8 @@ export async function getPortalUriWithToken(
3234
const response = await makeRESTRequest(
3335
"POST",
3436
spec,
35-
{ apiVersion: 1, namespace: "%SYS", path: "/action/query" },
36-
{ query: "select %Atelier_v1_Utils.General_GetCSPToken(?, ?) token", parameters: [PORTAL_HOME, token] },
37+
{ apiVersion: 1, namespace, path: "/action/query" },
38+
{ query: "select %Atelier_v1_Utils.General_GetCSPToken(?, ?) token", parameters: [page, token] },
3739
);
3840

3941
if (!response) {
@@ -45,9 +47,35 @@ export async function getPortalUriWithToken(
4547
allTokens[target].set(name, token);
4648
}
4749

50+
if (target === BrowserTarget.SIMPLE && !simpleBrowserCompatible.has(name)) {
51+
// Check that the portal webapps have all been altered so they don't require session cookie support, which Simple Browser cannot provide
52+
const response = await makeRESTRequest(
53+
"POST",
54+
spec,
55+
{ apiVersion: 1, namespace: "%SYS", path: "/action/query" },
56+
{ query: "SELECT Name FROM Security.Applications WHERE {fn CONCAT(Name, '/')} %STARTSWITH '/csp/sys/' AND UseCookies = 2" },
57+
);
58+
if (response) {
59+
const appsRequiringCookie = (response.data?.result?.content as any[]).map((row) => {
60+
return row.Name as string;
61+
});
62+
if (appsRequiringCookie.length > 0) {
63+
await vscode.window.showWarningMessage(`Portal web apps cannot be used in the Simple Browser tab if their 'UseCookies' property is set to 'Always' (the default). To resolve this, use Portal's security section to change it to 'Autodetect' in these apps: ${appsRequiringCookie.join(", ")}`, { modal: true });
64+
return;
65+
}
66+
else {
67+
simpleBrowserCompatible.set(name, true);
68+
}
69+
}
70+
else {
71+
vscode.window.showWarningMessage(`Unable to check the Portal web apps for compatibility with Simple Browser.`);
72+
simpleBrowserCompatible.set(name, true);
73+
}
74+
}
75+
4876
const webServer = spec.webServer;
49-
const queryString = token ? `CSPCHD=${encodeURIComponent(token)}` : "";
77+
const queryString = `$NAMESPACE=${encodeURIComponent(namespace)}${token ? `&CSPCHD=${encodeURIComponent(token)}` : ""}`;
5078

51-
return vscode.Uri.parse(`${webServer.scheme}://${webServer.host}:${webServer.port}${webServer.pathPrefix}${PORTAL_HOME}?${queryString}`, true);
79+
return vscode.Uri.parse(`${webServer.scheme}://${webServer.host}:${webServer.port}${webServer.pathPrefix}${page}?${queryString}`, true);
5280
}
5381
}

src/extension.ts

Lines changed: 36 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -106,14 +106,48 @@ export function activate(context: vscode.ExtensionContext) {
106106
if (uriWithToken) {
107107
//
108108
// It is essential to pass skipEncoding=true when converting the uri to a string,
109-
// otherwise the encoding done within Simple Browser / webview causes double-encoding
110-
// of the querystring.
109+
// otherwise the querystring's & and = get encoded.
111110
vscode.commands.executeCommand("simpleBrowser.show", uriWithToken.toString(true));
112111
}
113112
});
114113
}
115114
}),
116115
);
116+
context.subscriptions.push(
117+
vscode.commands.registerCommand(`${extensionId}.openPortalExplorerExternal`, (namespaceTreeItem?: NamespaceTreeItem) => {
118+
if (namespaceTreeItem) {
119+
const pathParts = namespaceTreeItem.id?.split(":");
120+
if (pathParts && pathParts.length === 4) {
121+
const serverName = pathParts[1];
122+
const namespace = pathParts[3];
123+
getPortalUriWithToken(BrowserTarget.EXTERNAL, serverName, "/csp/sys/exp/%25CSP.UI.Portal.ClassList.zen", namespace).then((uriWithToken) => {
124+
if (uriWithToken) {
125+
vscode.env.openExternal(uriWithToken);
126+
}
127+
});
128+
}
129+
}
130+
}),
131+
);
132+
context.subscriptions.push(
133+
vscode.commands.registerCommand(`${extensionId}.openPortalExplorerTab`, (namespaceTreeItem?: NamespaceTreeItem) => {
134+
if (namespaceTreeItem) {
135+
const pathParts = namespaceTreeItem.id?.split(":");
136+
if (pathParts && pathParts.length === 4) {
137+
const serverName = pathParts[1];
138+
const namespace = pathParts[3];
139+
getPortalUriWithToken(BrowserTarget.SIMPLE, serverName, "/csp/sys/exp/%2525CSP.UI.Portal.ClassList.zen", namespace).then((uriWithToken) => {
140+
if (uriWithToken) {
141+
//
142+
// It is essential to pass skipEncoding=true when converting the uri to a string,
143+
// otherwise the querystring's & and = get encoded.
144+
vscode.commands.executeCommand("simpleBrowser.show", uriWithToken.toString(true));
145+
}
146+
});
147+
}
148+
}
149+
}),
150+
);
117151
context.subscriptions.push(
118152
vscode.commands.registerCommand(`${extensionId}.editSettings`, (server?: ServerTreeItem) => {
119153
// Until there's a dedicated settings editor the best we can do is jump to the right section

0 commit comments

Comments
 (0)