From 0a8097858620d47876f81e6c4e05203a18924c90 Mon Sep 17 00:00:00 2001 From: Adam-Battenburg Date: Mon, 24 Jun 2019 15:19:09 -0400 Subject: [PATCH 1/2] Add safesave and pull from mainframe Signed-off-by: Adam-Battenburg --- package-lock.json | 87 +++++++++++++++++++++++++++-------------------- package.json | 22 ++++++++++++ src/extension.ts | 37 ++++++++++++++++++++ 3 files changed, 110 insertions(+), 36 deletions(-) diff --git a/package-lock.json b/package-lock.json index eb4ae79e81..aa7093b685 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8,7 +8,6 @@ "version": "7.0.0", "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.0.0.tgz", "integrity": "sha512-OfC2uemaknXr87bdLUkWog7nYuliM9Ij5HUcajsVcMCpQrcLmtxRbVFTIqmcSkSeYRBFBRxs2FiUqFJDLdiebA==", - "dev": true, "requires": { "@babel/highlight": "^7.0.0" } @@ -132,7 +131,6 @@ "version": "7.0.0", "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.0.0.tgz", "integrity": "sha512-UFMC4ZeFC48Tpvj7C8UgLvtkaUuovQX+5xNWrsIoMG8o2z+XFKjKaN9iVmS84dPwVN00W4wPmqvYoZF3EGAsfw==", - "dev": true, "requires": { "chalk": "^2.0.0", "esutils": "^2.0.2", @@ -6560,7 +6558,6 @@ "version": "3.2.1", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dev": true, "requires": { "color-convert": "^1.9.0" } @@ -7379,6 +7376,11 @@ "integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==", "dev": true }, + "builtin-modules": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-1.1.1.tgz", + "integrity": "sha1-Jw8HbFpywC9bZaR9+Uxf46J4iS8=" + }, "cache-base": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/cache-base/-/cache-base-1.0.1.tgz", @@ -7460,7 +7462,6 @@ "version": "2.4.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, "requires": { "ansi-styles": "^3.2.1", "escape-string-regexp": "^1.0.5", @@ -7470,14 +7471,12 @@ "has-flag": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", - "dev": true + "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=" }, "supports-color": { "version": "5.5.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, "requires": { "has-flag": "^3.0.0" } @@ -7576,7 +7575,6 @@ "version": "1.9.3", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "dev": true, "requires": { "color-name": "1.1.3" } @@ -7584,8 +7582,7 @@ "color-name": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", - "dev": true + "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=" }, "combined-stream": { "version": "1.0.8", @@ -7599,8 +7596,7 @@ "commander": { "version": "2.20.0", "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.0.tgz", - "integrity": "sha512-7j2y+40w61zy6YC2iRNpUe/NwhNyoXrYpHMrSunaMG64nRnaf96zO/KMQR4OyN/UnE5KLyEBnKHd4aG3rskjpQ==", - "dev": true + "integrity": "sha512-7j2y+40w61zy6YC2iRNpUe/NwhNyoXrYpHMrSunaMG64nRnaf96zO/KMQR4OyN/UnE5KLyEBnKHd4aG3rskjpQ==" }, "component-emitter": { "version": "1.3.0", @@ -7843,8 +7839,7 @@ "diff": { "version": "3.5.0", "resolved": "https://registry.npmjs.org/diff/-/diff-3.5.0.tgz", - "integrity": "sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA==", - "dev": true + "integrity": "sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA==" }, "diff-sequences": { "version": "24.3.0", @@ -7972,8 +7967,7 @@ "escape-string-regexp": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", - "dev": true + "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=" }, "escodegen": { "version": "1.11.1", @@ -8017,8 +8011,7 @@ "esutils": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.2.tgz", - "integrity": "sha1-Cr9PHKpbyx96nYrMbepPqqBLrJs=", - "dev": true + "integrity": "sha1-Cr9PHKpbyx96nYrMbepPqqBLrJs=" }, "exec-sh": { "version": "0.3.2", @@ -8294,8 +8287,7 @@ "fs.realpath": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", - "dev": true + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=" }, "fsevents": { "version": "1.2.9", @@ -8888,7 +8880,6 @@ "version": "7.1.4", "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.4.tgz", "integrity": "sha512-hkLPepehmnKk41pUGm3sYxoFs/umurYfYJCerbXEyFIWcAzvpipAgVkBqqT9RBKMGjnq6kMuyYwha6csxbiM1A==", - "dev": true, "requires": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", @@ -9217,7 +9208,6 @@ "version": "1.0.6", "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", - "dev": true, "requires": { "once": "^1.3.0", "wrappy": "1" @@ -9226,8 +9216,7 @@ "inherits": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", - "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", - "dev": true + "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" }, "ini": { "version": "1.3.5", @@ -12897,8 +12886,7 @@ "js-tokens": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", - "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", - "dev": true + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==" }, "js-yaml": { "version": "3.13.1", @@ -13718,7 +13706,6 @@ "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", - "dev": true, "requires": { "wrappy": "1" } @@ -13846,8 +13833,7 @@ "path-is-absolute": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", - "dev": true + "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=" }, "path-key": { "version": "2.0.1", @@ -13858,8 +13844,7 @@ "path-parse": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz", - "integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==", - "dev": true + "integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==" }, "path-to-regexp": { "version": "1.7.0", @@ -14188,7 +14173,6 @@ "version": "1.11.1", "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.11.1.tgz", "integrity": "sha512-vIpgF6wfuJOZI7KKKSP+HmiKggadPQAdsp5HiC1mvqnfp0gF1vdwgBWZIdrVft9pgqoMFQN+R7BSWZiBxx+BBw==", - "dev": true, "requires": { "path-parse": "^1.0.6" } @@ -14621,8 +14605,7 @@ "semver": { "version": "5.5.0", "resolved": "https://registry.npmjs.org/semver/-/semver-5.5.0.tgz", - "integrity": "sha512-4SJ3dm0WAwWy/NVeioZh5AntkdJoWKxHxcmyP622fOkgHa4z3R0TdBJICINyaSDE6uNwVc8gZr+ZinwZAH4xIA==", - "dev": true + "integrity": "sha512-4SJ3dm0WAwWy/NVeioZh5AntkdJoWKxHxcmyP622fOkgHa4z3R0TdBJICINyaSDE6uNwVc8gZr+ZinwZAH4xIA==" }, "set-blocking": { "version": "2.0.0", @@ -15203,6 +15186,39 @@ } } }, + "tslib": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.10.0.tgz", + "integrity": "sha512-qOebF53frne81cf0S9B41ByenJ3/IuH8yJKngAX35CmiZySA0khhkovshKK+jGCaMnVomla7gVlIcc3EvKPbTQ==" + }, + "tslint": { + "version": "5.18.0", + "resolved": "https://registry.npmjs.org/tslint/-/tslint-5.18.0.tgz", + "integrity": "sha512-Q3kXkuDEijQ37nXZZLKErssQVnwCV/+23gFEMROi8IlbaBG6tXqLPQJ5Wjcyt/yHPKBC+hD5SzuGaMora+ZS6w==", + "requires": { + "@babel/code-frame": "^7.0.0", + "builtin-modules": "^1.1.1", + "chalk": "^2.3.0", + "commander": "^2.12.1", + "diff": "^3.2.0", + "glob": "^7.1.1", + "js-yaml": "^3.13.1", + "minimatch": "^3.0.4", + "mkdirp": "^0.5.1", + "resolve": "^1.3.2", + "semver": "^5.3.0", + "tslib": "^1.8.0", + "tsutils": "^2.29.0" + } + }, + "tsutils": { + "version": "2.29.0", + "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-2.29.0.tgz", + "integrity": "sha512-g5JVHCIJwzfISaXpXE1qvNalca5Jwob6FjI4AoPlqMusJ6ftFE7IkkFoMhVLRgK+4Kx3gkzb8UZK5t5yTTvEmA==", + "requires": { + "tslib": "^1.8.1" + } + }, "tunnel": { "version": "0.0.4", "resolved": "https://registry.npmjs.org/tunnel/-/tunnel-0.0.4.tgz", @@ -15579,8 +15595,7 @@ "wrappy": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", - "dev": true + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" }, "write-file-atomic": { "version": "2.4.1", diff --git a/package.json b/package.json index 048a2138a7..3568e5579b 100644 --- a/package.json +++ b/package.json @@ -224,6 +224,14 @@ "command": "zowe.uss.removeSession", "title": "Remove Profile" }, + { + "command": "zowe.uss.safeSaveUSS", + "title": "Safe Save - Merge if Necessary", + "icon": { + "light": "./resources/light/upload.svg", + "dark": "./resources/dark/upload.svg" + } + }, { "command": "zowe.uss.binary", "title": "Toggle Binary" @@ -335,6 +343,16 @@ } ], "view/item/context": [ + { + "when": "view == zowe.uss.explorer && viewItem != favorite && viewItem != uss_session && viewItem != directory && viewItem != directoryf", + "command": "zowe.uss.refreshUSS", + "group": "inline" + }, + { + "when": "view == zowe.uss.explorer && viewItem != favorite && viewItem != uss_session && viewItem != directory && viewItem != directoryf", + "command": "zowe.uss.safeSaveUSS", + "group": "inline" + }, { "when": "view == zowe.uss.explorer && viewItem == directory", "command": "zowe.uss.createFile", @@ -663,6 +681,10 @@ "command": "zowe.uss.refreshUSS", "when": "never" }, + { + "command": "zowe.uss.safeSaveUSS", + "when": "never" + }, { "command": "zowe.uss.removeSession", "when": "never" diff --git a/src/extension.ts b/src/extension.ts index c8e98d5d95..bc059c7071 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -134,6 +134,7 @@ export async function activate(context: vscode.ExtensionContext) { vscode.commands.registerCommand("zowe.uss.fullPath", (node) => enterUSSPattern(node, ussFileProvider)); vscode.commands.registerCommand("zowe.uss.ZoweUSSNode.open", (node) => openUSS(node)); vscode.commands.registerCommand("zowe.uss.removeSession", async (node) => ussFileProvider.deleteSession(node)); + vscode.commands.registerCommand("zowe.uss.safeSaveUSS", async (node) => safeSaveUSS(node)); vscode.commands.registerCommand("zowe.uss.createFile", async (node) => ussActions.createUSSNode(node, ussFileProvider, "file")); vscode.commands.registerCommand("zowe.uss.createFolder", async (node) => ussActions.createUSSNode(node, ussFileProvider, "directory")); // tslint:disable-next-line: max-line-length @@ -1097,6 +1098,8 @@ export async function safeSave(node: ZoweNode) { case ("pds"): label = node.mParent.mLabel + "(" + node.mLabel + ")"; break; + case ("directory"): + break; default: throw Error("safeSave() called from invalid node."); } @@ -1116,6 +1119,40 @@ export async function safeSave(node: ZoweNode) { } } +/** + * Checks if there are changes on the mainframe before pushing changes + * + * @export + * @param {ZoweUSSNode} node + */ +export async function safeSaveUSS(node: ZoweUSSNode) { + + log.debug("safe save requested for node: " + node.mLabel); + let label; + try { + switch (node.mParent.contextValue) { + case ("directory"): + label = node.fullPath; + break; + default: + throw Error("safeSaveUSS() called from invalid node."); + } + log.debug("Invoking safesave for USS file " + label); + await zowe.Download.ussFile(node.getSession(), node.fullPath, { + file: getUSSDocumentFilePath(node) + }); + const document = await vscode.workspace.openTextDocument(getUSSDocumentFilePath(node)); + await vscode.window.showTextDocument(document); + await vscode.window.activeTextEditor.document.save(); + } catch (err) { + if (err.message.includes("not found")) { + vscode.window.showInformationMessage(`Unable to find file: ${label} was probably deleted.`); + } else { + vscode.window.showErrorMessage(err.message); + } + } +} + /** * Uploads the file to the mainframe * From a1ea1a5e683dbfd4481cec3b8c28a172e41cb2c9 Mon Sep 17 00:00:00 2001 From: Adam-Battenburg Date: Tue, 25 Jun 2019 09:56:04 -0400 Subject: [PATCH 2/2] Add unit test Signed-off-by: Adam-Battenburg --- __tests__/extension.test.ts | 91 +++++++++++++++++++++++++++---------- package.json | 20 ++++---- src/extension.ts | 24 ++++------ 3 files changed, 87 insertions(+), 48 deletions(-) diff --git a/__tests__/extension.test.ts b/__tests__/extension.test.ts index 1b6e120e54..9987d68c6f 100644 --- a/__tests__/extension.test.ts +++ b/__tests__/extension.test.ts @@ -389,7 +389,7 @@ describe("Extension Unit Tests", () => { getChildren: mockGetUSSChildren, } }); - expect(registerCommand.mock.calls.length).toBe(47); + expect(registerCommand.mock.calls.length).toBe(48); expect(registerCommand.mock.calls[0][0]).toBe("zowe.addSession"); expect(registerCommand.mock.calls[0][1]).toBeInstanceOf(Function); expect(registerCommand.mock.calls[1][0]).toBe("zowe.addFavorite"); @@ -440,50 +440,52 @@ describe("Extension Unit Tests", () => { expect(registerCommand.mock.calls[23][1]).toBeInstanceOf(Function); expect(registerCommand.mock.calls[24][0]).toBe("zowe.uss.refreshUSS"); expect(registerCommand.mock.calls[24][1]).toBeInstanceOf(Function); - expect(registerCommand.mock.calls[25][0]).toBe("zowe.uss.fullPath"); + expect(registerCommand.mock.calls[25][0]).toBe("zowe.uss.safeSaveUSS"); expect(registerCommand.mock.calls[25][1]).toBeInstanceOf(Function); - expect(registerCommand.mock.calls[26][0]).toBe("zowe.uss.ZoweUSSNode.open"); + expect(registerCommand.mock.calls[26][0]).toBe("zowe.uss.fullPath"); expect(registerCommand.mock.calls[26][1]).toBeInstanceOf(Function); - expect(registerCommand.mock.calls[27][0]).toBe("zowe.uss.removeSession"); + expect(registerCommand.mock.calls[27][0]).toBe("zowe.uss.ZoweUSSNode.open"); expect(registerCommand.mock.calls[27][1]).toBeInstanceOf(Function); - expect(registerCommand.mock.calls[28][0]).toBe("zowe.uss.createFile"); + expect(registerCommand.mock.calls[28][0]).toBe("zowe.uss.removeSession"); expect(registerCommand.mock.calls[28][1]).toBeInstanceOf(Function); - expect(registerCommand.mock.calls[29][0]).toBe("zowe.uss.createFolder"); + expect(registerCommand.mock.calls[29][0]).toBe("zowe.uss.createFile"); expect(registerCommand.mock.calls[29][1]).toBeInstanceOf(Function); - expect(registerCommand.mock.calls[30][0]).toBe("zowe.uss.deleteNode"); + expect(registerCommand.mock.calls[30][0]).toBe("zowe.uss.createFolder"); expect(registerCommand.mock.calls[30][1]).toBeInstanceOf(Function); - expect(registerCommand.mock.calls[31][0]).toBe("zowe.uss.binary"); + expect(registerCommand.mock.calls[31][0]).toBe("zowe.uss.deleteNode"); expect(registerCommand.mock.calls[31][1]).toBeInstanceOf(Function); - expect(registerCommand.mock.calls[32][0]).toBe("zowe.uss.text"); + expect(registerCommand.mock.calls[32][0]).toBe("zowe.uss.binary"); expect(registerCommand.mock.calls[32][1]).toBeInstanceOf(Function); - expect(registerCommand.mock.calls[33][0]).toBe("zowe.uss.renameNode"); + expect(registerCommand.mock.calls[33][0]).toBe("zowe.uss.text"); expect(registerCommand.mock.calls[33][1]).toBeInstanceOf(Function); - expect(registerCommand.mock.calls[34][0]).toBe("zowe.zosJobsOpenspool"); + expect(registerCommand.mock.calls[34][0]).toBe("zowe.uss.renameNode"); expect(registerCommand.mock.calls[34][1]).toBeInstanceOf(Function); - expect(registerCommand.mock.calls[35][0]).toBe("zowe.deleteJob"); + expect(registerCommand.mock.calls[35][0]).toBe("zowe.zosJobsOpenspool"); expect(registerCommand.mock.calls[35][1]).toBeInstanceOf(Function); - expect(registerCommand.mock.calls[36][0]).toBe("zowe.runModifyCommand"); + expect(registerCommand.mock.calls[36][0]).toBe("zowe.deleteJob"); expect(registerCommand.mock.calls[36][1]).toBeInstanceOf(Function); - expect(registerCommand.mock.calls[37][0]).toBe("zowe.runStopCommand"); + expect(registerCommand.mock.calls[37][0]).toBe("zowe.runModifyCommand"); expect(registerCommand.mock.calls[37][1]).toBeInstanceOf(Function); - expect(registerCommand.mock.calls[38][0]).toBe("zowe.refreshJobsServer"); + expect(registerCommand.mock.calls[38][0]).toBe("zowe.runStopCommand"); expect(registerCommand.mock.calls[38][1]).toBeInstanceOf(Function); - expect(registerCommand.mock.calls[39][0]).toBe("zowe.refreshAllJobs"); + expect(registerCommand.mock.calls[39][0]).toBe("zowe.refreshJobsServer"); expect(registerCommand.mock.calls[39][1]).toBeInstanceOf(Function); - expect(registerCommand.mock.calls[40][0]).toBe("zowe.addJobsSession"); + expect(registerCommand.mock.calls[40][0]).toBe("zowe.refreshAllJobs"); expect(registerCommand.mock.calls[40][1]).toBeInstanceOf(Function); - expect(registerCommand.mock.calls[41][0]).toBe("zowe.setOwner"); + expect(registerCommand.mock.calls[41][0]).toBe("zowe.addJobsSession"); expect(registerCommand.mock.calls[41][1]).toBeInstanceOf(Function); - expect(registerCommand.mock.calls[42][0]).toBe("zowe.setPrefix"); + expect(registerCommand.mock.calls[42][0]).toBe("zowe.setOwner"); expect(registerCommand.mock.calls[42][1]).toBeInstanceOf(Function); - expect(registerCommand.mock.calls[43][0]).toBe("zowe.removeJobsSession"); + expect(registerCommand.mock.calls[43][0]).toBe("zowe.setPrefix"); expect(registerCommand.mock.calls[43][1]).toBeInstanceOf(Function); - expect(registerCommand.mock.calls[44][0]).toBe("zowe.downloadSpool"); + expect(registerCommand.mock.calls[44][0]).toBe("zowe.removeJobsSession"); expect(registerCommand.mock.calls[44][1]).toBeInstanceOf(Function); - expect(registerCommand.mock.calls[45][0]).toBe("zowe.getJobJcl"); + expect(registerCommand.mock.calls[45][0]).toBe("zowe.downloadSpool"); expect(registerCommand.mock.calls[45][1]).toBeInstanceOf(Function); - expect(registerCommand.mock.calls[46][0]).toBe("zowe.setJobSpool"); + expect(registerCommand.mock.calls[46][0]).toBe("zowe.getJobJcl"); expect(registerCommand.mock.calls[46][1]).toBeInstanceOf(Function); + expect(registerCommand.mock.calls[47][0]).toBe("zowe.setJobSpool"); + expect(registerCommand.mock.calls[47][1]).toBeInstanceOf(Function); expect(onDidSaveTextDocument.mock.calls.length).toBe(1); expect(existsSync.mock.calls.length).toBe(3); expect(existsSync.mock.calls[0][0]).toBe(extension.BRIGHTTEMPFOLDER); @@ -1249,6 +1251,49 @@ describe("Extension Unit Tests", () => { expect(showErrorMessage.mock.calls[0][0]).toEqual("safeSave() called from invalid node."); }); + it("Testing that safeSaveUSS is executed successfully", async () => { + ussFile.mockReset(); + openTextDocument.mockReset(); + showTextDocument.mockReset(); + showInformationMessage.mockReset(); + save.mockReset(); + + const node = new ZoweUSSNode("node", vscode.TreeItemCollapsibleState.None, ussNode, null, null); + const parent = new ZoweUSSNode("parent", vscode.TreeItemCollapsibleState.Collapsed, ussNode, null, null); + const child = new ZoweUSSNode("child", vscode.TreeItemCollapsibleState.None, parent, null, null); + + openTextDocument.mockResolvedValueOnce("test"); + + await extension.safeSaveUSS(node); + + expect(ussFile.mock.calls.length).toBe(1); + expect(ussFile.mock.calls[0][0]).toBe(node.getSession()); + expect(ussFile.mock.calls[0][1]).toBe(node.fullPath); + expect(ussFile.mock.calls[0][2]).toEqual({file: extension.getUSSDocumentFilePath(node)}); + expect(openTextDocument.mock.calls.length).toBe(1); + expect(openTextDocument.mock.calls[0][0]).toBe(path.join(extension.getUSSDocumentFilePath(node))); + expect(showTextDocument.mock.calls.length).toBe(1); + expect(showTextDocument.mock.calls[0][0]).toBe("test"); + expect(save.mock.calls.length).toBe(1); + + ussFile.mockReset(); + ussFile.mockRejectedValueOnce(Error("not found")); + + await extension.safeSaveUSS(node); + + expect(showInformationMessage.mock.calls.length).toBe(1); + expect(showInformationMessage.mock.calls[0][0]).toBe("Unable to find file: " + node.fullPath + " was probably deleted."); + + ussFile.mockReset(); + showErrorMessage.mockReset(); + ussFile.mockRejectedValueOnce(Error("")); + + await extension.safeSaveUSS(child); + + expect(showErrorMessage.mock.calls.length).toBe(1); + expect(showErrorMessage.mock.calls[0][0]).toEqual(""); + }); + it("Testing that refreshUSS correctly executes with and without error", async () => { const node = new ZoweUSSNode("node", vscode.TreeItemCollapsibleState.None, ussNode, null, null); const parent = new ZoweUSSNode("parent", vscode.TreeItemCollapsibleState.Collapsed, ussNode, null, null); diff --git a/package.json b/package.json index 3568e5579b..21cdb484b2 100644 --- a/package.json +++ b/package.json @@ -343,16 +343,6 @@ } ], "view/item/context": [ - { - "when": "view == zowe.uss.explorer && viewItem != favorite && viewItem != uss_session && viewItem != directory && viewItem != directoryf", - "command": "zowe.uss.refreshUSS", - "group": "inline" - }, - { - "when": "view == zowe.uss.explorer && viewItem != favorite && viewItem != uss_session && viewItem != directory && viewItem != directoryf", - "command": "zowe.uss.safeSaveUSS", - "group": "inline" - }, { "when": "view == zowe.uss.explorer && viewItem == directory", "command": "zowe.uss.createFile", @@ -383,6 +373,16 @@ "command": "zowe.uss.removeFavorite", "group": "navigation" }, + { + "when": "view == zowe.uss.explorer && viewItem != favorite && viewItem != uss_session && viewItem != directory && viewItem != directoryf", + "command": "zowe.uss.refreshUSS", + "group": "inline" + }, + { + "when": "view == zowe.uss.explorer && viewItem != favorite && viewItem != uss_session && viewItem != directory && viewItem != directoryf", + "command": "zowe.uss.safeSaveUSS", + "group": "inline" + }, { "when": "view == zowe.uss.explorer && viewItem != uss_session && viewItem != favorite && viewItem != textFilef && viewItem != binaryFilef && viewItem != directoryf", "command": "zowe.uss.deleteNode", diff --git a/src/extension.ts b/src/extension.ts index bc059c7071..7aae466ac8 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -131,10 +131,10 @@ export async function activate(context: vscode.ExtensionContext) { vscode.commands.registerCommand("zowe.uss.addSession", async () => addUSSSession(ussFileProvider)); vscode.commands.registerCommand("zowe.uss.refreshAll", () => refreshAllUSS(ussFileProvider)); vscode.commands.registerCommand("zowe.uss.refreshUSS", (node) => refreshUSS(node)); + vscode.commands.registerCommand("zowe.uss.safeSaveUSS", async (node) => safeSaveUSS(node)); vscode.commands.registerCommand("zowe.uss.fullPath", (node) => enterUSSPattern(node, ussFileProvider)); vscode.commands.registerCommand("zowe.uss.ZoweUSSNode.open", (node) => openUSS(node)); vscode.commands.registerCommand("zowe.uss.removeSession", async (node) => ussFileProvider.deleteSession(node)); - vscode.commands.registerCommand("zowe.uss.safeSaveUSS", async (node) => safeSaveUSS(node)); vscode.commands.registerCommand("zowe.uss.createFile", async (node) => ussActions.createUSSNode(node, ussFileProvider, "file")); vscode.commands.registerCommand("zowe.uss.createFolder", async (node) => ussActions.createUSSNode(node, ussFileProvider, "directory")); // tslint:disable-next-line: max-line-length @@ -1044,6 +1044,9 @@ export async function refreshPS(node: ZoweNode) { export async function refreshUSS(node: ZoweUSSNode) { let label; switch (node.mParent.contextValue) { + case ("directoryf"): + label = node.fullPath; + break; case ("directory"): label = node.fullPath; break; @@ -1078,7 +1081,7 @@ export async function refreshUSS(node: ZoweUSSNode) { * Checks if there are changes on the mainframe before pushing changes * * @export - * @param {ZoweNode} node + * @param {ZoweNode} node The node which represents the dataset */ export async function safeSave(node: ZoweNode) { @@ -1098,8 +1101,6 @@ export async function safeSave(node: ZoweNode) { case ("pds"): label = node.mParent.mLabel + "(" + node.mLabel + ")"; break; - case ("directory"): - break; default: throw Error("safeSave() called from invalid node."); } @@ -1123,21 +1124,14 @@ export async function safeSave(node: ZoweNode) { * Checks if there are changes on the mainframe before pushing changes * * @export - * @param {ZoweUSSNode} node + * @param {ZoweUSSNode} node The node which represents the file */ export async function safeSaveUSS(node: ZoweUSSNode) { log.debug("safe save requested for node: " + node.mLabel); - let label; try { - switch (node.mParent.contextValue) { - case ("directory"): - label = node.fullPath; - break; - default: - throw Error("safeSaveUSS() called from invalid node."); - } - log.debug("Invoking safesave for USS file " + label); + // Switch case from `safeSave` not needed, as we will only ever receive a file + log.debug("Invoking safesave for USS file " + node.fullPath); await zowe.Download.ussFile(node.getSession(), node.fullPath, { file: getUSSDocumentFilePath(node) }); @@ -1146,7 +1140,7 @@ export async function safeSaveUSS(node: ZoweUSSNode) { await vscode.window.activeTextEditor.document.save(); } catch (err) { if (err.message.includes("not found")) { - vscode.window.showInformationMessage(`Unable to find file: ${label} was probably deleted.`); + vscode.window.showInformationMessage(`Unable to find file: ${node.fullPath} was probably deleted.`); } else { vscode.window.showErrorMessage(err.message); }