Skip to content

Commit

Permalink
Merge branch 'main' into feat/enhance-credentials-ux
Browse files Browse the repository at this point in the history
  • Loading branch information
t1m0thyj committed Sep 14, 2023
2 parents f779c5b + 6c5d66d commit ce74a2d
Show file tree
Hide file tree
Showing 9 changed files with 30 additions and 124 deletions.
1 change: 1 addition & 0 deletions packages/zowe-explorer/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ All notable changes to the "vscode-extension-for-zowe" extension will be documen

### Bug fixes

- Fixed issue with favorited Job filter search. [#2440](https://github.com/zowe/vscode-extension-for-zowe/issues/2440)
- Remove the 'Show Attributes' context menu action for migrated datasets. [#2033](https://github.com/zowe/vscode-extension-for-zowe/issues/2033)
- Fixed issue with endless credential prompt loop when logging out. [#2262](https://github.com/zowe/vscode-extension-for-zowe/issues/2262)
- Bump `@zowe/secrets-for-zowe-sdk` to 7.18.4 to handle install errors gracefully and to allow running without MSVC redistributables.
Expand Down
90 changes: 0 additions & 90 deletions packages/zowe-explorer/__tests__/__unit__/job/actions.unit.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1038,8 +1038,6 @@ describe("Jobs Actions Unit Tests - Function refreshJobsServer", () => {
it("Checking common execution of function", async () => {
createGlobalMocks();
const blockMocks = createBlockMocks();

mocked(Profiles.getInstance).mockReturnValue(blockMocks.profileInstance);
const job = new Job(
"jobtest",
vscode.TreeItemCollapsibleState.Expanded,
Expand All @@ -1052,75 +1050,11 @@ describe("Jobs Actions Unit Tests - Function refreshJobsServer", () => {
mocked(zowe.ZosmfSession.createSessCfgFromArgs).mockReturnValueOnce(blockMocks.session.ISession);

await jobActions.refreshJobsServer(job, blockMocks.testJobTree);

expect(blockMocks.testJobTree.checkCurrentProfile).toHaveBeenCalledWith(job);
expect(blockMocks.testJobTree.refreshElement).toHaveBeenCalledWith(job);
});
it("Checking common execution of function with Unverified", async () => {
createGlobalMocks();
const blockMocks = createBlockMocks();

mocked(Profiles.getInstance).mockReturnValue(blockMocks.profileInstance);
Object.defineProperty(Profiles, "getInstance", {
value: jest.fn(() => {
return {
checkCurrentProfile: blockMocks.mockCheckCurrentProfile.mockReturnValueOnce({
name: blockMocks.imperativeProfile.name,
status: "unverified",
}),
validProfile: ValidProfileEnum.UNVERIFIED,
};
}),
});
const job = new Job(
"jobtest",
vscode.TreeItemCollapsibleState.Expanded,
null,
blockMocks.session,
blockMocks.iJob,
blockMocks.imperativeProfile
);
job.contextValue = globals.JOBS_SESSION_CONTEXT;
mocked(zowe.ZosmfSession.createSessCfgFromArgs).mockReturnValueOnce(blockMocks.session.ISession);

await jobActions.refreshJobsServer(job, blockMocks.testJobTree);

expect(blockMocks.testJobTree.checkCurrentProfile).toHaveBeenCalledWith(job);
expect(blockMocks.testJobTree.refreshElement).toHaveBeenCalledWith(job);
});
it("Checking failed attempt to execute the function", async () => {
createGlobalMocks();
const blockMocks = createBlockMocks();

mocked(Profiles.getInstance).mockReturnValue(blockMocks.profileInstance);
const job = new Job(
"jobtest",
vscode.TreeItemCollapsibleState.Expanded,
null,
blockMocks.session,
blockMocks.iJob,
blockMocks.imperativeProfile
);
job.contextValue = globals.JOBS_SESSION_CONTEXT;
mocked(zowe.ZosmfSession.createSessCfgFromArgs).mockReturnValueOnce(blockMocks.session.ISession);
blockMocks.testJobTree.checkCurrentProfile.mockImplementationOnce(() => {
throw Error("test");
});

try {
await jobActions.refreshJobsServer(job, blockMocks.testJobTree);
} catch (err) {
expect(err).toEqual(Error("test"));
}

expect(blockMocks.testJobTree.refreshElement).not.toHaveBeenCalled();
});
it("Checking execution of function with credential prompt", async () => {
createGlobalMocks();
const blockMocks = createBlockMocks();

blockMocks.profileInstance.promptCredentials.mockReturnValue(["fake", "fake", "fake"]);
mocked(Profiles.getInstance).mockReturnValue(blockMocks.profileInstance);
const job = new Job(
"jobtest",
vscode.TreeItemCollapsibleState.Expanded,
Expand All @@ -1133,30 +1067,6 @@ describe("Jobs Actions Unit Tests - Function refreshJobsServer", () => {
mocked(zowe.ZosmfSession.createSessCfgFromArgs).mockReturnValueOnce(blockMocks.session.ISession);

await jobActions.refreshJobsServer(job, blockMocks.testJobTree);

expect(blockMocks.testJobTree.checkCurrentProfile).toHaveBeenCalledWith(job);
expect(blockMocks.testJobTree.refreshElement).toHaveBeenCalledWith(job);
});
it("Checking execution of function with credential prompt for favorite", async () => {
createGlobalMocks();
const blockMocks = createBlockMocks();

blockMocks.profileInstance.promptCredentials.mockReturnValue(["fake", "fake", "fake"]);
mocked(Profiles.getInstance).mockReturnValue(blockMocks.profileInstance);
const job = new Job(
"jobtest",
vscode.TreeItemCollapsibleState.Expanded,
null,
blockMocks.session,
blockMocks.iJob,
blockMocks.imperativeProfile
);
job.contextValue = globals.JOBS_SESSION_CONTEXT + globals.FAV_SUFFIX;
mocked(zowe.ZosmfSession.createSessCfgFromArgs).mockReturnValueOnce(blockMocks.session.ISession);

await jobActions.refreshJobsServer(job, blockMocks.testJobTree);

expect(blockMocks.testJobTree.checkCurrentProfile).toHaveBeenCalledWith(job);
expect(blockMocks.testJobTree.refreshElement).toHaveBeenCalledWith(job);
});
});
Expand Down
6 changes: 3 additions & 3 deletions packages/zowe-explorer/__tests__/__unit__/utils.unit.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ describe("Utils Unit Tests - Function errorHandling", () => {
await utils.errorHandling(errorDetails, label);

expect(vscode.window.showErrorMessage).toHaveBeenCalledWith(
`Invalid Credentials. Please ensure the username and password for ${label} are valid or this may lead to a lock-out.`,
`Invalid Credentials for profile '${label}'. Please ensure the username and password are valid or this may lead to a lock-out.`,
{ modal: true },
"Update Credentials"
);
Expand All @@ -105,7 +105,7 @@ describe("Utils Unit Tests - Function errorHandling", () => {
await utils.errorHandling(errorDetails, label);

expect(vscode.window.showErrorMessage).toHaveBeenCalledWith(
`Invalid Credentials. Please ensure the username and password for ${label} are valid or this may lead to a lock-out.`,
`Invalid Credentials for profile '${label}'. Please ensure the username and password are valid or this may lead to a lock-out.`,
{ modal: true },
"Update Credentials"
);
Expand All @@ -126,7 +126,7 @@ describe("Utils Unit Tests - Function errorHandling", () => {

// TODO: check why this return two messages?
expect(vscode.window.showErrorMessage).toHaveBeenCalledWith(
`Invalid Credentials. Please ensure the username and password for ${label} are valid or this may lead to a lock-out.`,
`Invalid Credentials for profile '${label}'. Please ensure the username and password are valid or this may lead to a lock-out.`,
{ modal: true },
"Update Credentials"
);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"errorHandling.invalid.host": "Required parameter 'host' must not be blank.",
"errorHandling.invalid.credentials": "Invalid Credentials. Please ensure the username and password for {0} are valid or this may lead to a lock-out.",
"errorHandling.invalid.credentials": "Invalid Credentials for profile '{0}'. Please ensure the username and password are valid or this may lead to a lock-out.",
"errorHandling.invalid.token": "Your connection is no longer active. Please log in to an authentication service to restore the connection.",
"errorHandling.authentication.login": "Log in to Authentication Service",
"errorHandling.checkCredentials.button": "Update Credentials",
Expand Down
3 changes: 2 additions & 1 deletion packages/zowe-explorer/src/job/ZosJobsProvider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -807,7 +807,7 @@ export class ZosJobsProvider extends ZoweTreeProvider implements IZoweTree<IZowe
ZoweLogger.trace("ZosJobsProvider.searchPrompt called.");
await this.checkCurrentProfile(node);
let searchCriteria: string = "";
if (Profiles.getInstance().validProfile === ValidProfileEnum.VALID || !contextually.isValidationEnabled(node)) {
if (Profiles.getInstance().validProfile !== ValidProfileEnum.INVALID) {
const isSessionNotFav = contextually.isSessionNotFav(node);
const isExpanded = node.collapsibleState === vscode.TreeItemCollapsibleState.Expanded;

Expand Down Expand Up @@ -838,6 +838,7 @@ export class ZosJobsProvider extends ZoweTreeProvider implements IZoweTree<IZowe
}
node.dirty = true;
}
this.refresh();
}
}

Expand Down
8 changes: 4 additions & 4 deletions packages/zowe-explorer/src/job/ZoweJobNode.ts
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ export class Job extends ZoweTreeNode implements IZoweJobTreeNode {
public async getChildren(): Promise<IZoweJobTreeNode[]> {
const thisSessionNode = this.getSessionNode();
ZoweLogger.trace(`ZoweJobNode.getChildren called for ${String(thisSessionNode.label)}.`);
if (contextually.isSession(this) && !this.filtered) {
if (contextually.isSession(this) && !this.filtered && !contextually.isFavorite(this)) {
return [
new Job(
localize("getChildren.search", "Use the search button to display jobs"),
Expand Down Expand Up @@ -178,7 +178,7 @@ export class Job extends ZoweTreeNode implements IZoweJobTreeNode {
// Fetch jobs under session node
const jobs = await this.getJobs(this._owner, this._prefix, this._searchId, this._jobStatus);

if (!jobs || jobs.length === 0) {
if (jobs.length === 0) {
const noJobsNode = new Job(
localize("getChildren.noJobs", "No jobs found"),
vscode.TreeItemCollapsibleState.None,
Expand Down Expand Up @@ -368,14 +368,14 @@ export class Job extends ZoweTreeNode implements IZoweJobTreeNode {
}
}, []);
}
return jobsInternal;
} catch (error) {
ZoweLogger.trace("Error getting jobs from Rest API.");
await errorHandling(error, this.label, localize("getChildren.error.response", "Retrieving response from ") + `zowe.GetJobs`);
await errorHandling(error, cachedProfile.name, localize("getChildren.error.response", "Retrieving response from ") + `zowe.GetJobs`);
syncSessionNode(Profiles.getInstance())((profileValue) => ZoweExplorerApiRegister.getJesApi(profileValue).getSession())(
this.getSessionNode()
);
}
return jobsInternal;
}
}

Expand Down
39 changes: 16 additions & 23 deletions packages/zowe-explorer/src/job/actions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -117,28 +117,24 @@ export async function getSpoolContent(session: string, spool: zowe.IJobFile, ref
}

const statusMsg = Gui.setStatusBarMessage(localize("jobActions.openSpoolFile", "$(sync~spin) Opening spool file...", this.label as string));
await profiles.checkCurrentProfile(zosmfProfile);
if (profiles.validProfile !== ValidProfileEnum.INVALID) {
const uri = encodeJobFile(session, spool);
try {
const spoolFile = SpoolProvider.files[uri.path];
if (spoolFile) {
// Fetch any changes to the spool file if it exists in the SpoolProvider
await spoolFile.fetchContent();
}
await Gui.showTextDocument(uri, { preview: false });
} catch (error) {
const isTextDocActive =
vscode.window.activeTextEditor &&
vscode.window.activeTextEditor.document.uri?.path === `${spool.jobname}.${spool.jobid}.${spool.ddname}`;
const uri = encodeJobFile(session, spool);
try {
const spoolFile = SpoolProvider.files[uri.path];
if (spoolFile) {
// Fetch any changes to the spool file if it exists in the SpoolProvider
await spoolFile.fetchContent();
}
await Gui.showTextDocument(uri, { preview: false });
} catch (error) {
const isTextDocActive =
vscode.window.activeTextEditor && vscode.window.activeTextEditor.document.uri?.path === `${spool.jobname}.${spool.jobid}.${spool.ddname}`;

statusMsg.dispose();
if (isTextDocActive && String(error.message).includes("Failed to show text document")) {
return;
}
await errorHandling(error, session);
statusMsg.dispose();
if (isTextDocActive && String(error.message).includes("Failed to show text document")) {
return;
}
await errorHandling(error, session);
return;
}
statusMsg.dispose();
}
Expand Down Expand Up @@ -191,10 +187,7 @@ export async function getSpoolContentFromMainframe(node: IZoweJobTreeNode): Prom
*/
export async function refreshJobsServer(node: IZoweJobTreeNode, jobsProvider: IZoweTree<IZoweJobTreeNode>): Promise<void> {
ZoweLogger.trace("job.actions.refreshJobsServer called.");
jobsProvider.checkCurrentProfile(node);
if (Profiles.getInstance().validProfile === ValidProfileEnum.VALID || Profiles.getInstance().validProfile === ValidProfileEnum.UNVERIFIED) {
await jobsProvider.refreshElement(node);
}
await jobsProvider.refreshElement(node);
}

/**
Expand Down
1 change: 1 addition & 0 deletions packages/zowe-explorer/src/uss/USSTree.ts
Original file line number Diff line number Diff line change
Expand Up @@ -647,6 +647,7 @@ export class USSTree extends ZoweTreeProvider implements IZoweTree<IZoweUSSTreeN
sessionNode.dirty = true;
this.addSearchHistory(sanitizedPath);
await TreeViewUtils.expandNode(sessionNode, this);
this.refresh();
}
}

Expand Down
4 changes: 2 additions & 2 deletions packages/zowe-explorer/src/utils/ProfilesUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ export async function errorHandling(errorDetails: Error | string, label?: string
} else if (httpErrorCode === imperative.RestConstants.HTTP_STATUS_401) {
const errMsg = localize(
"errorHandling.invalid.credentials",
"Invalid Credentials. Please ensure the username and password for {0} are valid or this may lead to a lock-out.",
"Invalid Credentials for profile '{0}'. Please ensure the username and password are valid or this may lead to a lock-out.",
label
);
const errToken = localize(
Expand Down Expand Up @@ -161,7 +161,7 @@ export const syncSessionNode =
(sessionNode: IZoweTreeNode): void => {
ZoweLogger.trace("ProfilesUtils.syncSessionNode called.");

const profileType = sessionNode.getProfile().type;
const profileType = sessionNode.getProfile()?.type;
const profileName = sessionNode.getProfileName();

let profile: imperative.IProfileLoaded;
Expand Down

0 comments on commit ce74a2d

Please sign in to comment.