From ab998dd252dfa1999c5cd785c987789702d6bdc0 Mon Sep 17 00:00:00 2001 From: gjsjohnmurray Date: Tue, 13 Jun 2023 19:41:40 +0100 Subject: [PATCH 1/4] Add shortcut to Explorer section of Portal at namespace level --- package.json | 37 +++++++++++++++++++++-------- src/api/getPortalUriWithToken.ts | 40 +++++++++++++++++++++++++++----- src/extension.ts | 38 ++++++++++++++++++++++++++++-- 3 files changed, 97 insertions(+), 18 deletions(-) diff --git a/package.json b/package.json index f825abb..1ae7117 100644 --- a/package.json +++ b/package.json @@ -15,7 +15,7 @@ "multi-root ready" ], "engines": { - "vscode": "^1.63.0" + "vscode": "^1.75.0" }, "icon": "images/logo.png", "categories": [ @@ -51,7 +51,7 @@ }, "devDependencies": { "@intersystems-community/intersystems-servermanager": "latest", - "@types/vscode": "^1.63.0", + "@types/vscode": "^1.75.0", "@types/glob": "^7.1.1", "@types/keytar": "^4.4.2", "@types/mocha": "^9.0.0", @@ -65,14 +65,7 @@ }, "main": "./out/extension", "activationEvents": [ - "onAuthenticationRequest:intersystems-servermanager-credentials", - "onView:intersystems-community_servermanager", - "onCommand:intersystems-community.servermanager.refreshTree", - "onCommand:intersystems-community.servermanager.addServer", - "onCommand:intersystems-community.servermanager.storePassword", - "onCommand:intersystems-community.servermanager.clearPassword", - "onCommand:intersystems-community.servermanager.migratePasswords", - "onCommand:intersystems-community.servermanager.importServers" + "onAuthenticationRequest:intersystems-servermanager-credentials" ], "contributes": { "viewsContainers": { @@ -292,6 +285,16 @@ "title": "Open Management Portal in Tab", "icon": "$(tools)" }, + { + "command": "intersystems-community.servermanager.openPortalExplorerTab", + "title": "Open Management Portal's Class Utilities in Tab", + "icon": "$(tools)" + }, + { + "command": "intersystems-community.servermanager.openPortalExplorerExternal", + "title": "Open in External Browser", + "icon": "$(link-external)" + }, { "command": "intersystems-community.servermanager.retryServer", "title": "Refresh", @@ -463,6 +466,14 @@ "command": "intersystems-community.servermanager.openPortalTab", "when": "false" }, + { + "command": "intersystems-community.servermanager.openPortalExplorerExternal", + "when": "false" + }, + { + "command": "intersystems-community.servermanager.openPortalExplorerTab", + "when": "false" + }, { "command": "intersystems-community.servermanager.retryServer", "when": "false" @@ -613,6 +624,12 @@ "when": "view == intersystems-community_servermanager && viewItem =~ /\\.server\\./", "group": "inline@90" }, + { + "command": "intersystems-community.servermanager.openPortalExplorerTab", + "when": "view == intersystems-community_servermanager && viewItem =~ /namespace$/", + "group": "inline@80", + "alt": "intersystems-community.servermanager.openPortalExplorerExternal" + }, { "command": "intersystems-community.servermanager.retryServer", "when": "view == intersystems-community_servermanager && viewItem =~ /\\.server\\./", diff --git a/src/api/getPortalUriWithToken.ts b/src/api/getPortalUriWithToken.ts index 05911fc..297d77e 100644 --- a/src/api/getPortalUriWithToken.ts +++ b/src/api/getPortalUriWithToken.ts @@ -11,14 +11,16 @@ export enum BrowserTarget { const allTokens = [new Map(), new Map()]; +const simpleBrowserCompatible = new Map(); + export async function getPortalUriWithToken( target: BrowserTarget, name: string, + page = "/csp/sys/UtilHome.csp", + namespace = "%SYS", scope?: vscode.ConfigurationScope, ): Promise { - const PORTAL_HOME = "/csp/sys/UtilHome.csp"; - // Use our own API so that the Recent folder updates with our activity const myApi = vscode.extensions.getExtension(extensionId)?.exports; @@ -32,8 +34,8 @@ export async function getPortalUriWithToken( const response = await makeRESTRequest( "POST", spec, - { apiVersion: 1, namespace: "%SYS", path: "/action/query" }, - { query: "select %Atelier_v1_Utils.General_GetCSPToken(?, ?) token", parameters: [PORTAL_HOME, token] }, + { apiVersion: 1, namespace, path: "/action/query" }, + { query: "select %Atelier_v1_Utils.General_GetCSPToken(?, ?) token", parameters: [page, token] }, ); if (!response) { @@ -45,9 +47,35 @@ export async function getPortalUriWithToken( allTokens[target].set(name, token); } + if (target === BrowserTarget.SIMPLE && !simpleBrowserCompatible.has(name)) { + // Check that the portal webapps have all been altered so they don't require session cookie support, which Simple Browser cannot provide + const response = await makeRESTRequest( + "POST", + spec, + { apiVersion: 1, namespace: "%SYS", path: "/action/query" }, + { query: "SELECT Name FROM Security.Applications WHERE {fn CONCAT(Name, '/')} %STARTSWITH '/csp/sys/' AND UseCookies = 2" }, + ); + if (response) { + const appsRequiringCookie = (response.data?.result?.content as any[]).map((row) => { + return row.Name as string; + }); + if (appsRequiringCookie.length > 0) { + 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 }); + return; + } + else { + simpleBrowserCompatible.set(name, true); + } + } + else { + vscode.window.showWarningMessage(`Unable to check the Portal web apps for compatibility with Simple Browser.`); + simpleBrowserCompatible.set(name, true); + } + } + const webServer = spec.webServer; - const queryString = token ? `CSPCHD=${encodeURIComponent(token)}` : ""; + const queryString = `$NAMESPACE=${encodeURIComponent(namespace)}${token ? `&CSPCHD=${encodeURIComponent(token)}` : ""}`; - return vscode.Uri.parse(`${webServer.scheme}://${webServer.host}:${webServer.port}${webServer.pathPrefix}${PORTAL_HOME}?${queryString}`, true); + return vscode.Uri.parse(`${webServer.scheme}://${webServer.host}:${webServer.port}${webServer.pathPrefix}${page}?${queryString}`, true); } } diff --git a/src/extension.ts b/src/extension.ts index 824ff72..121e3fc 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -106,14 +106,48 @@ export function activate(context: vscode.ExtensionContext) { if (uriWithToken) { // // It is essential to pass skipEncoding=true when converting the uri to a string, - // otherwise the encoding done within Simple Browser / webview causes double-encoding - // of the querystring. + // otherwise the querystring's & and = get encoded. vscode.commands.executeCommand("simpleBrowser.show", uriWithToken.toString(true)); } }); } }), ); + context.subscriptions.push( + vscode.commands.registerCommand(`${extensionId}.openPortalExplorerExternal`, (namespaceTreeItem?: NamespaceTreeItem) => { + if (namespaceTreeItem) { + const pathParts = namespaceTreeItem.id?.split(":"); + if (pathParts && pathParts.length === 4) { + const serverName = pathParts[1]; + const namespace = pathParts[3]; + getPortalUriWithToken(BrowserTarget.EXTERNAL, serverName, "/csp/sys/exp/%25CSP.UI.Portal.ClassList.zen", namespace).then((uriWithToken) => { + if (uriWithToken) { + vscode.env.openExternal(uriWithToken); + } + }); + } + } + }), + ); + context.subscriptions.push( + vscode.commands.registerCommand(`${extensionId}.openPortalExplorerTab`, (namespaceTreeItem?: NamespaceTreeItem) => { + if (namespaceTreeItem) { + const pathParts = namespaceTreeItem.id?.split(":"); + if (pathParts && pathParts.length === 4) { + const serverName = pathParts[1]; + const namespace = pathParts[3]; + getPortalUriWithToken(BrowserTarget.SIMPLE, serverName, "/csp/sys/exp/%2525CSP.UI.Portal.ClassList.zen", namespace).then((uriWithToken) => { + if (uriWithToken) { + // + // It is essential to pass skipEncoding=true when converting the uri to a string, + // otherwise the querystring's & and = get encoded. + vscode.commands.executeCommand("simpleBrowser.show", uriWithToken.toString(true)); + } + }); + } + } + }), + ); context.subscriptions.push( vscode.commands.registerCommand(`${extensionId}.editSettings`, (server?: ServerTreeItem) => { // Until there's a dedicated settings editor the best we can do is jump to the right section From 2336e941264dcefdf52ed58a1aef6c9c9268148e Mon Sep 17 00:00:00 2001 From: gjsjohnmurray Date: Tue, 13 Jun 2023 19:54:13 +0100 Subject: [PATCH 2/4] Updated package-lock.json --- package-lock.json | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/package-lock.json b/package-lock.json index 0158b6a..ac46f47 100644 --- a/package-lock.json +++ b/package-lock.json @@ -20,7 +20,7 @@ "@types/keytar": "^4.4.2", "@types/mocha": "^9.0.0", "@types/node": "^8.10.60", - "@types/vscode": "^1.63.0", + "@types/vscode": "^1.75.0", "@vscode/test-electron": "^2.1.5", "glob": "^7.1.6", "mocha": "^9.2.2", @@ -29,7 +29,7 @@ "typescript": "^3.8.3" }, "engines": { - "vscode": "^1.63.0" + "vscode": "^1.75.0" } }, "node_modules/@babel/code-frame": { @@ -217,9 +217,9 @@ "peer": true }, "node_modules/@types/vscode": { - "version": "1.66.0", - "resolved": "https://registry.npmjs.org/@types/vscode/-/vscode-1.66.0.tgz", - "integrity": "sha512-ZfJck4M7nrGasfs4A4YbUoxis3Vu24cETw3DERsNYtDZmYSYtk6ljKexKFKhImO/ZmY6ZMsmegu2FPkXoUFImA==", + "version": "1.79.0", + "resolved": "https://registry.npmjs.org/@types/vscode/-/vscode-1.79.0.tgz", + "integrity": "sha512-Tfowu2rSW8hVGbqzQLSPlOEiIOYYryTkgJ+chMecpYiJcnw9n0essvSiclnK+Qh/TcSVJHgaK4EMrQDZjZJ/Sw==", "dev": true }, "node_modules/@ungap/promise-all-settled": { @@ -3423,9 +3423,9 @@ "peer": true }, "@types/vscode": { - "version": "1.66.0", - "resolved": "https://registry.npmjs.org/@types/vscode/-/vscode-1.66.0.tgz", - "integrity": "sha512-ZfJck4M7nrGasfs4A4YbUoxis3Vu24cETw3DERsNYtDZmYSYtk6ljKexKFKhImO/ZmY6ZMsmegu2FPkXoUFImA==", + "version": "1.79.0", + "resolved": "https://registry.npmjs.org/@types/vscode/-/vscode-1.79.0.tgz", + "integrity": "sha512-Tfowu2rSW8hVGbqzQLSPlOEiIOYYryTkgJ+chMecpYiJcnw9n0essvSiclnK+Qh/TcSVJHgaK4EMrQDZjZJ/Sw==", "dev": true }, "@ungap/promise-all-settled": { From 5385a15bb26440ea058ed43ce010eb56ccb01363 Mon Sep 17 00:00:00 2001 From: gjsjohnmurray Date: Tue, 13 Jun 2023 20:00:55 +0100 Subject: [PATCH 3/4] Bump typescript --- package-lock.json | 14 +++++++------- package.json | 2 +- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/package-lock.json b/package-lock.json index ac46f47..d72f3b1 100644 --- a/package-lock.json +++ b/package-lock.json @@ -26,7 +26,7 @@ "mocha": "^9.2.2", "ts-loader": "^9.4.2", "tslint": "^5.20.1", - "typescript": "^3.8.3" + "typescript": "^4.4.3" }, "engines": { "vscode": "^1.75.0" @@ -2837,9 +2837,9 @@ } }, "node_modules/typescript": { - "version": "3.9.10", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.9.10.tgz", - "integrity": "sha512-w6fIxVE/H1PkLKcCPsFqKE7Kv7QUwhU8qQY2MueZXWx5cPZdwFupLgKK3vntcK98BtNHZtAF4LA/yl2a7k8R6Q==", + "version": "4.9.5", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.5.tgz", + "integrity": "sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==", "dev": true, "bin": { "tsc": "bin/tsc", @@ -5431,9 +5431,9 @@ } }, "typescript": { - "version": "3.9.10", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.9.10.tgz", - "integrity": "sha512-w6fIxVE/H1PkLKcCPsFqKE7Kv7QUwhU8qQY2MueZXWx5cPZdwFupLgKK3vntcK98BtNHZtAF4LA/yl2a7k8R6Q==", + "version": "4.9.5", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.5.tgz", + "integrity": "sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==", "dev": true }, "universalify": { diff --git a/package.json b/package.json index 1ae7117..a127417 100644 --- a/package.json +++ b/package.json @@ -61,7 +61,7 @@ "mocha": "^9.2.2", "ts-loader": "^9.4.2", "tslint": "^5.20.1", - "typescript": "^3.8.3" + "typescript": "^4.4.3" }, "main": "./out/extension", "activationEvents": [ From cc512eae5841625e42a2b9817eafdd1774c5c600 Mon Sep 17 00:00:00 2001 From: gjsjohnmurray Date: Fri, 4 Aug 2023 16:43:17 +0100 Subject: [PATCH 4/4] Compromise by removing namespace-specific Simple Browser variant --- package.json | 16 +++------------- src/extension.ts | 19 ------------------- 2 files changed, 3 insertions(+), 32 deletions(-) diff --git a/package.json b/package.json index 34bce44..8209482 100644 --- a/package.json +++ b/package.json @@ -302,14 +302,9 @@ "title": "Open Management Portal in Tab", "icon": "$(tools)" }, - { - "command": "intersystems-community.servermanager.openPortalExplorerTab", - "title": "Open Management Portal's Class Utilities in Tab", - "icon": "$(tools)" - }, { "command": "intersystems-community.servermanager.openPortalExplorerExternal", - "title": "Open in External Browser", + "title": "Open Management Portal Here in External Browser", "icon": "$(link-external)" }, { @@ -459,10 +454,6 @@ "command": "intersystems-community.servermanager.openPortalExplorerExternal", "when": "false" }, - { - "command": "intersystems-community.servermanager.openPortalExplorerTab", - "when": "false" - }, { "command": "intersystems-community.servermanager.retryServer", "when": "false" @@ -614,10 +605,9 @@ "group": "inline@90" }, { - "command": "intersystems-community.servermanager.openPortalExplorerTab", + "command": "intersystems-community.servermanager.openPortalExplorerExternal", "when": "view == intersystems-community_servermanager && viewItem =~ /namespace$/", - "group": "inline@80", - "alt": "intersystems-community.servermanager.openPortalExplorerExternal" + "group": "inline@80" }, { "command": "intersystems-community.servermanager.retryServer", diff --git a/src/extension.ts b/src/extension.ts index 0820095..c7a8cc5 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -128,25 +128,6 @@ export function activate(context: vscode.ExtensionContext) { } }), ); - context.subscriptions.push( - vscode.commands.registerCommand(`${extensionId}.openPortalExplorerTab`, (namespaceTreeItem?: NamespaceTreeItem) => { - if (namespaceTreeItem) { - const pathParts = namespaceTreeItem.id?.split(":"); - if (pathParts && pathParts.length === 4) { - const serverName = pathParts[1]; - const namespace = pathParts[3]; - getPortalUriWithToken(BrowserTarget.SIMPLE, serverName, "/csp/sys/exp/%2525CSP.UI.Portal.ClassList.zen", namespace).then((uriWithToken) => { - if (uriWithToken) { - // - // It is essential to pass skipEncoding=true when converting the uri to a string, - // otherwise the querystring's & and = get encoded. - vscode.commands.executeCommand("simpleBrowser.show", uriWithToken.toString(true)); - } - }); - } - } - }), - ); context.subscriptions.push( vscode.commands.registerCommand(`${extensionId}.editSettings`, (server?: ServerTreeItem) => { // Until there's a dedicated settings editor the best we can do is jump to the right section