diff --git a/packages/zowe-explorer-api/src/profiles/ProfilesCache.ts b/packages/zowe-explorer-api/src/profiles/ProfilesCache.ts index b91019eabc..a62cbab1cb 100644 --- a/packages/zowe-explorer-api/src/profiles/ProfilesCache.ts +++ b/packages/zowe-explorer-api/src/profiles/ProfilesCache.ts @@ -224,6 +224,7 @@ export class ProfilesCache { profile: profileInfo, name: profileName, type: profileType, + overwrite: true, }); return newProfile.profile; } diff --git a/packages/zowe-explorer-api/src/tree/IZoweTree.ts b/packages/zowe-explorer-api/src/tree/IZoweTree.ts index a8244fb3ee..d0f11799bb 100644 --- a/packages/zowe-explorer-api/src/tree/IZoweTree.ts +++ b/packages/zowe-explorer-api/src/tree/IZoweTree.ts @@ -47,7 +47,7 @@ export interface IZoweTree extends vscode.TreeDataProvider { * Edit a session to the container * @param node This parameter identifies the node that needs to be called */ - editSession(node: IZoweNodeType): Promise; + editSession(node: IZoweNodeType, zoweFileProvider: IZoweTree): Promise; /** * Add a new session to the container diff --git a/packages/zowe-explorer/__tests__/__unit__/KeytarCredentialManager.unit.test.ts b/packages/zowe-explorer/__tests__/__unit__/KeytarCredentialManager.unit.test.ts index 70da94bb76..296d3950fe 100644 --- a/packages/zowe-explorer/__tests__/__unit__/KeytarCredentialManager.unit.test.ts +++ b/packages/zowe-explorer/__tests__/__unit__/KeytarCredentialManager.unit.test.ts @@ -120,8 +120,7 @@ describe("KeytarCredentialManager Unit Tests", () => { error = err; } expect(error).toBeDefined(); - expect(error.additionalDetails).toContain("Service = Zowe-Plugin"); - expect(error.additionalDetails).toContain("Awesome-Service\n Account = user5"); + expect(error.additionalDetails).toContain("Could not find an entry in the credential vault"); }); it("Test saving passwords to credential store", async () => { diff --git a/packages/zowe-explorer/__tests__/__unit__/Profiles.unit.test.ts b/packages/zowe-explorer/__tests__/__unit__/Profiles.unit.test.ts index 60c019e833..0750123594 100644 --- a/packages/zowe-explorer/__tests__/__unit__/Profiles.unit.test.ts +++ b/packages/zowe-explorer/__tests__/__unit__/Profiles.unit.test.ts @@ -648,7 +648,7 @@ describe("Profiles Unit Tests - Function createNewConnection", () => { globalMocks.mockShowQuickPick.mockResolvedValueOnce("False"); await blockMocks.profiles.createNewConnection("alternate"); - expect(globalMocks.mockShowInformationMessage.mock.calls[0][0]).toBe("Operation Cancelled"); + expect(globalMocks.mockShowInformationMessage.mock.calls[0][0]).toBe("Profile alternate was created."); }); it("Tests that createNewConnection creates an alternate profile with default port value", async () => { @@ -1015,7 +1015,7 @@ describe("Profiles Unit Tests - Function updateProfile", () => { }; newMocks.profiles = await Profiles.createInstance(newMocks.log); newMocks.profileInstance = createInstanceOfProfile(newMocks.profiles); - newMocks.changedImperativeProfile.profile = { user: "test2", password: "test2" }; + newMocks.changedImperativeProfile.profile = { user: "test2", password: "test2", rejectUnauthorize: true }; newMocks.profileInfo = newMocks.changedImperativeProfile; Object.defineProperty(globalMocks.mockCliProfileManager, "load", { value: jest.fn(() => { diff --git a/packages/zowe-explorer/__tests__/__unit__/abstract/TreeProvider.unit.test.ts b/packages/zowe-explorer/__tests__/__unit__/abstract/TreeProvider.unit.test.ts index e252edb2a6..423cf02423 100644 --- a/packages/zowe-explorer/__tests__/__unit__/abstract/TreeProvider.unit.test.ts +++ b/packages/zowe-explorer/__tests__/__unit__/abstract/TreeProvider.unit.test.ts @@ -153,7 +153,7 @@ describe("ZoweJobNode unit tests - Function editSession", () => { const blockMocks = await createBlockMocks(globalMocks); const checkSession = jest.spyOn(blockMocks.testJobsProvider, "editSession"); - await blockMocks.testJobsProvider.editSession(blockMocks.jobNode); + await blockMocks.testJobsProvider.editSession(blockMocks.jobNode, globalMocks.testUSSTree); expect(globalMocks.mockEditSession).toHaveBeenCalled(); }); }); diff --git a/packages/zowe-explorer/__tests__/__unit__/dataset/DatasetTree.unit.test.ts b/packages/zowe-explorer/__tests__/__unit__/dataset/DatasetTree.unit.test.ts index f974349fe0..85c27c2da7 100644 --- a/packages/zowe-explorer/__tests__/__unit__/dataset/DatasetTree.unit.test.ts +++ b/packages/zowe-explorer/__tests__/__unit__/dataset/DatasetTree.unit.test.ts @@ -1629,7 +1629,7 @@ describe("Dataset Tree Unit Tests - Function editSession", () => { null ); - await testTree.editSession(node); + await testTree.editSession(node, testTree); expect(node.getProfile().profile).toBe("testProfile"); }); diff --git a/packages/zowe-explorer/src/KeytarCredentialManager.ts b/packages/zowe-explorer/src/KeytarCredentialManager.ts index 9c5c110689..28ff847782 100644 --- a/packages/zowe-explorer/src/KeytarCredentialManager.ts +++ b/packages/zowe-explorer/src/KeytarCredentialManager.ts @@ -9,9 +9,10 @@ * * */ -import { AbstractCredentialManager, ImperativeError, SecureCredential } from "@zowe/imperative"; +import { AbstractCredentialManager, ImperativeError, SecureCredential, Logger } from "@zowe/imperative"; import * as nls from "vscode-nls"; + // Set up localization nls.config({ messageFormat: nls.MessageFormat.bundle, bundleFormat: nls.BundleFormat.standalone })(); const localize: nls.LocalizeFunc = nls.loadMessageBundle(); @@ -72,10 +73,7 @@ export class KeytarCredentialManager extends AbstractCredentialManager { */ protected async deleteCredentials(account: string): Promise { if (!(await this.deleteCredentialsHelper(account))) { - throw new ImperativeError({ - msg: localize("errorHandling.deleteCredentials", "Unable to delete credentials."), - additionalDetails: this.getMissingEntryMessage(account), - }); + Logger.getAppLogger().debug(localize("errorHandling.deleteCredentials", "Unable to delete credentials.")); } } diff --git a/packages/zowe-explorer/src/Profiles.ts b/packages/zowe-explorer/src/Profiles.ts index 5b2be65b81..5f6f94a8f4 100644 --- a/packages/zowe-explorer/src/Profiles.ts +++ b/packages/zowe-explorer/src/Profiles.ts @@ -13,7 +13,6 @@ import { IProfileLoaded, Logger, ISession, - IUpdateProfileFromCliArgs, ICommandArguments, Session, SessConstants, @@ -605,8 +604,11 @@ export class Profiles extends ProfilesCache { localize("createNewConnection.undefined.username", "Operation Cancelled") ); return undefined; + } else if (newUser === "") { + delete schemaValues[value]; + } else { + schemaValues[value] = newUser; } - schemaValues[value] = newUser; break; case "password": newPass = await this.passwordInfo(); @@ -615,8 +617,11 @@ export class Profiles extends ProfilesCache { localize("createNewConnection.undefined.username", "Operation Cancelled") ); return undefined; + } else if (newPass === "") { + delete schemaValues[value]; + } else { + schemaValues[value] = newPass; } - schemaValues[value] = newPass; break; case "rejectUnauthorized": newRU = await this.ruInfo(); @@ -634,22 +639,18 @@ export class Profiles extends ProfilesCache { switch (response) { case "number": options = await this.optionsValue(value, schema); - const enteredValue = await vscode.window.showInputBox(options); - if (!Number.isNaN(Number(enteredValue))) { - schemaValues[value] = Number(enteredValue); + const enteredValue = Number(await vscode.window.showInputBox(options)); + if (!Number.isNaN(enteredValue)) { + if ((value === "encoding" || value === "responseTimeout") && enteredValue === 0) { + delete schemaValues[value]; + } else { + schemaValues[value] = Number(enteredValue); + } } else { - switch (true) { - case enteredValue === undefined: - vscode.window.showInformationMessage( - localize("createNewConnection.number", "Operation Cancelled") - ); - return undefined; - case schema[value].optionDefinition.hasOwnProperty("defaultValue"): - schemaValues[value] = schema[value].optionDefinition.defaultValue; - break; - default: - schemaValues[value] = undefined; - break; + if (schema[value].optionDefinition.hasOwnProperty("defaultValue")) { + schemaValues[value] = schema[value].optionDefinition.defaultValue; + } else { + delete schemaValues[value]; } } break; @@ -674,9 +675,10 @@ export class Profiles extends ProfilesCache { return undefined; } if (defValue === "") { - break; + delete schemaValues[value]; + } else { + schemaValues[value] = defValue; } - schemaValues[value] = defValue; break; } } @@ -937,7 +939,7 @@ export class Profiles extends ProfilesCache { // Remove from list of all profiles const index = this.allProfiles.findIndex((deleteItem) => { - return deleteItem === deletedProfile; + return deleteItem.name === deletedProfile.name; }); if (index >= 0) { this.allProfiles.splice(index, 1); @@ -1597,26 +1599,35 @@ export class Profiles extends ProfilesCache { const OrigProfileInfo = this.loadedProfile.profile; const NewProfileInfo = ProfileInfo.profile; + // Update the currently-loaded profile with the new info const profileArray = Object.keys(this.loadedProfile.profile); for (const value of profileArray) { - if (value === "user" || value === "password") { - if (!rePrompt) { - OrigProfileInfo.user = NewProfileInfo.user; - OrigProfileInfo.password = NewProfileInfo.password; + if ((value === "encoding" || value === "responseTimeout") && NewProfileInfo[value] === 0) { + // If the updated profile had these fields set to 0, delete them... + // this should get rid of a bad value that was stored + // in these properties before this update + delete OrigProfileInfo[value]; + } else if (NewProfileInfo[value] !== undefined && NewProfileInfo[value] !== "") { + if (value === "user" || value === "password") { + if (!rePrompt) { + OrigProfileInfo.user = NewProfileInfo.user; + OrigProfileInfo.password = NewProfileInfo.password; + } + } else { + OrigProfileInfo[value] = NewProfileInfo[value]; } - } else { - OrigProfileInfo[value] = NewProfileInfo[value]; + } else if (NewProfileInfo[value] === undefined || NewProfileInfo[value] === "") { + // If the updated profile had an empty property, delete it... + // this should get rid of any empty strings + // that were stored in the profile before this update + delete OrigProfileInfo[value]; } } - // Using `IUpdateProfileFromCliArgs` here instead of `IUpdateProfile` is - // kind of a hack, but necessary to support storing secure credentials - // until this is fixed: https://github.com/zowe/imperative/issues/379 - const updateParms: IUpdateProfileFromCliArgs = { + const updateParms: IUpdateProfile = { name: this.loadedProfile.name, - merge: true, - // profile: OrigProfileInfo as IProfile - args: OrigProfileInfo as any, + merge: false, + profile: OrigProfileInfo as IProfile, }; try { this.getCliProfileManager(this.loadedProfile.type).update(updateParms); diff --git a/packages/zowe-explorer/src/abstract/ZoweTreeProvider.ts b/packages/zowe-explorer/src/abstract/ZoweTreeProvider.ts index 04324c62f6..b9b8d96e47 100644 --- a/packages/zowe-explorer/src/abstract/ZoweTreeProvider.ts +++ b/packages/zowe-explorer/src/abstract/ZoweTreeProvider.ts @@ -156,7 +156,7 @@ export class ZoweTreeProvider { return undefined; } - public async editSession(node: IZoweTreeNode) { + public async editSession(node: IZoweTreeNode, zoweFileProvider: IZoweTree) { const profile = node.getProfile(); const profileName = node.getProfileName(); // Check what happens is inactive @@ -165,21 +165,22 @@ export class ZoweTreeProvider { if (EditSession) { node.getProfile().profile = EditSession as IProfile; await setProfile(node, EditSession as IProfile); - await setSession(node, EditSession as ISession); + if (await node.getSession()) { + await setSession(node, EditSession as ISession); + } else { + zoweFileProvider.deleteSession(node.getSessionNode()); + this.mHistory.addSession(node.label); + zoweFileProvider.addSession(node.getProfileName()); + } this.refresh(); } try { - // refresh profilesForValidation to check the profile status again + // Remove the edited profile from profilesForValidation since it should be revalidated Profiles.getInstance().profilesForValidation.forEach((checkProfile, index) => { - if (index === 0) { - Profiles.getInstance().profilesForValidation = []; - } if (checkProfile.name === profileName) { Profiles.getInstance().profilesForValidation.splice(index, 1); } }); - - await this.checkCurrentProfile(node); } catch (error) { await errorHandling(error); } diff --git a/packages/zowe-explorer/src/extension.ts b/packages/zowe-explorer/src/extension.ts index cf76b7905c..f8112be062 100644 --- a/packages/zowe-explorer/src/extension.ts +++ b/packages/zowe-explorer/src/extension.ts @@ -223,7 +223,9 @@ function initDatasetProvider(context: vscode.ExtensionContext, datasetProvider: vscode.commands.registerCommand("zowe.refreshAll", () => refreshActions.refreshAll(datasetProvider)); vscode.commands.registerCommand("zowe.refreshNode", (node) => dsActions.refreshPS(node)); vscode.commands.registerCommand("zowe.pattern", (node) => datasetProvider.filterPrompt(node)); - vscode.commands.registerCommand("zowe.editSession", async (node) => datasetProvider.editSession(node)); + vscode.commands.registerCommand("zowe.editSession", async (node) => + datasetProvider.editSession(node, datasetProvider) + ); vscode.commands.registerCommand("zowe.ZoweNode.openPS", (node) => dsActions.openPS(node, true, datasetProvider)); vscode.commands.registerCommand("zowe.createDataset", (node) => dsActions.createFile(node, datasetProvider)); vscode.commands.registerCommand("zowe.all.profilelink", (node) => linkProfileDialog(node.getProfile())); @@ -286,7 +288,9 @@ function initUSSProvider(context: vscode.ExtensionContext, ussFileProvider: IZow vscode.commands.registerCommand("zowe.uss.fullPath", (node: IZoweUSSTreeNode) => ussFileProvider.filterPrompt(node) ); - vscode.commands.registerCommand("zowe.uss.editSession", async (node) => ussFileProvider.editSession(node)); + vscode.commands.registerCommand("zowe.uss.editSession", async (node) => + ussFileProvider.editSession(node, ussFileProvider) + ); vscode.commands.registerCommand("zowe.uss.ZoweUSSNode.open", (node: IZoweUSSTreeNode) => node.openUSS(false, true, ussFileProvider) ); @@ -371,7 +375,9 @@ function initJobsProvider(context: vscode.ExtensionContext, jobsProvider: IZoweT jobsProvider.setItem(jobsProvider.getTreeView(), job); }); vscode.commands.registerCommand("zowe.jobs.search", (node) => jobsProvider.filterPrompt(node)); - vscode.commands.registerCommand("zowe.jobs.editSession", async (node) => jobsProvider.editSession(node)); + vscode.commands.registerCommand("zowe.jobs.editSession", async (node) => + jobsProvider.editSession(node, jobsProvider) + ); vscode.commands.registerCommand("zowe.issueTsoCmd", async () => MvsCommandHandler.getInstance().issueMvsCommand()); vscode.commands.registerCommand("zowe.issueMvsCmd", async (node, command) => MvsCommandHandler.getInstance().issueMvsCommand(node.session, command, node) diff --git a/packages/zowe-explorer/src/uss/USSTree.ts b/packages/zowe-explorer/src/uss/USSTree.ts index 027a2e8f4f..6291c30d44 100644 --- a/packages/zowe-explorer/src/uss/USSTree.ts +++ b/packages/zowe-explorer/src/uss/USSTree.ts @@ -304,7 +304,7 @@ export class USSTree extends ZoweTreeProvider implements IZoweTree 0) { const createPick = new FilterDescriptor(USSTree.defaultDialogText); diff --git a/packages/zowe-explorer/src/utils/ProfilesUtils.ts b/packages/zowe-explorer/src/utils/ProfilesUtils.ts index 04638b7b87..d259eb28c9 100644 --- a/packages/zowe-explorer/src/utils/ProfilesUtils.ts +++ b/packages/zowe-explorer/src/utils/ProfilesUtils.ts @@ -15,7 +15,7 @@ import * as vscode from "vscode"; import * as os from "os"; import * as path from "path"; import { ISession, IProfile, ImperativeConfig } from "@zowe/imperative"; -import { IZoweTreeNode } from "@zowe/zowe-explorer-api"; +import { IZoweNodeType, IZoweTree, IZoweTreeNode } from "@zowe/zowe-explorer-api"; import { Profiles } from "../Profiles"; import * as nls from "vscode-nls"; @@ -111,14 +111,14 @@ export function isTheia(): boolean { * @param {sessNode} IZoweTreeNode *************************************************************************************************************/ // This function does not perform any UI refresh; it just gets updated profile information. -export function refreshTree(sessNode: IZoweTreeNode) { +export async function refreshTree(sessNode: IZoweTreeNode) { const allProf = Profiles.getInstance().getProfiles(); for (const profNode of allProf) { if (sessNode.getProfileName() === profNode.name) { setProfile(sessNode, profNode.profile); const SessionProfile = profNode.profile as ISession; - if (sessNode.getSession().ISession !== SessionProfile) { - setSession(sessNode, SessionProfile); + if (sessNode.getSession() && sessNode.getSession().ISession !== SessionProfile) { + await setSession(sessNode, SessionProfile); } } }