From 3db7e4d3d08a7b4294c12a44596ed9671fd6ef11 Mon Sep 17 00:00:00 2001 From: Billie Simmons <49491949+JillieBeanSim@users.noreply.github.com> Date: Mon, 11 Sep 2023 09:21:21 -0400 Subject: [PATCH 001/189] add check for selection in quickpick Signed-off-by: Billie Simmons <49491949+JillieBeanSim@users.noreply.github.com> --- .../__tests__/__unit__/job/actions.unit.test.ts | 8 ++++---- packages/zowe-explorer/src/dataset/actions.ts | 4 ++++ 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/packages/zowe-explorer/__tests__/__unit__/job/actions.unit.test.ts b/packages/zowe-explorer/__tests__/__unit__/job/actions.unit.test.ts index c91bcb9607..48ffeaeb74 100644 --- a/packages/zowe-explorer/__tests__/__unit__/job/actions.unit.test.ts +++ b/packages/zowe-explorer/__tests__/__unit__/job/actions.unit.test.ts @@ -513,25 +513,25 @@ describe("Jobs Actions Unit Tests - Function submitJcl", () => { ); }); - it("Checking failed attempt to submit of active text editor content as JCL", async () => { + it("Checking failed attempt to submit of active text editor content as JCL without profile chosen from quickpick", async () => { createGlobalMocks(); const blockMocks = createBlockMocks(); mocked(zowe.ZosmfSession.createSessCfgFromArgs).mockReturnValue(blockMocks.session.ISession); mocked(Profiles.getInstance).mockReturnValue(blockMocks.profileInstance); - mocked(vscode.window.showQuickPick).mockResolvedValueOnce(null); // Here we imitate the case when no profile was selected + mocked(vscode.window.showQuickPick).mockResolvedValueOnce(undefined); // Here we imitate the case when no profile was selected blockMocks.testDatasetTree.getChildren.mockResolvedValueOnce([ new ZoweDatasetNode("node", vscode.TreeItemCollapsibleState.None, blockMocks.datasetSessionNode, null), blockMocks.datasetSessionNode, ]); activeTextEditorDocument.mockReturnValue(blockMocks.textDocument); + const messageSpy = jest.spyOn(Gui, "infoMessage"); const submitJclSpy = jest.spyOn(blockMocks.jesApi, "submitJcl"); submitJclSpy.mockClear(); await dsActions.submitJcl(blockMocks.testDatasetTree); expect(submitJclSpy).not.toBeCalled(); - expect(mocked(ZoweLogger.error)).toBeCalled(); - expect(mocked(ZoweLogger.error).mock.calls[0][0]).toEqual("Session for submitting JCL was null or undefined!"); + expect(messageSpy).toBeCalledWith("Operation Cancelled"); }); it("Checking API error on submit of active text editor content as JCL", async () => { diff --git a/packages/zowe-explorer/src/dataset/actions.ts b/packages/zowe-explorer/src/dataset/actions.ts index d27f5ae6c8..3b21508f32 100644 --- a/packages/zowe-explorer/src/dataset/actions.ts +++ b/packages/zowe-explorer/src/dataset/actions.ts @@ -961,6 +961,10 @@ export async function submitJcl(datasetProvider: api.IZoweTree Date: Mon, 11 Sep 2023 09:30:31 -0400 Subject: [PATCH 002/189] add CHANGELOG Signed-off-by: Billie Simmons <49491949+JillieBeanSim@users.noreply.github.com> --- packages/zowe-explorer/CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/zowe-explorer/CHANGELOG.md b/packages/zowe-explorer/CHANGELOG.md index 0e21e50642..82a537b452 100644 --- a/packages/zowe-explorer/CHANGELOG.md +++ b/packages/zowe-explorer/CHANGELOG.md @@ -11,6 +11,7 @@ All notable changes to the "vscode-extension-for-zowe" extension will be documen ### Bug fixes - Remove the 'Show Attributes' context menu action for migrated datasets. [#2033](https://github.com/zowe/vscode-extension-for-zowe/issues/2033) +- Fixed submitting local JCL using command pallet option Zowe Explorer: Submit JCL by adding a check for chosen profile returned to continue the action. [#1625](https://github.com/zowe/vscode-extension-for-zowe/issues/1625) ## `2.10.0` From 32f0aec598e468f3fb839a52040c8de41b5b38b0 Mon Sep 17 00:00:00 2001 From: Billie Simmons <49491949+JillieBeanSim@users.noreply.github.com> Date: Mon, 11 Sep 2023 09:31:52 -0400 Subject: [PATCH 003/189] add ticks around command in CHANGELOG Signed-off-by: Billie Simmons <49491949+JillieBeanSim@users.noreply.github.com> --- packages/zowe-explorer/CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/zowe-explorer/CHANGELOG.md b/packages/zowe-explorer/CHANGELOG.md index 82a537b452..04dc2ee3e3 100644 --- a/packages/zowe-explorer/CHANGELOG.md +++ b/packages/zowe-explorer/CHANGELOG.md @@ -11,7 +11,7 @@ All notable changes to the "vscode-extension-for-zowe" extension will be documen ### Bug fixes - Remove the 'Show Attributes' context menu action for migrated datasets. [#2033](https://github.com/zowe/vscode-extension-for-zowe/issues/2033) -- Fixed submitting local JCL using command pallet option Zowe Explorer: Submit JCL by adding a check for chosen profile returned to continue the action. [#1625](https://github.com/zowe/vscode-extension-for-zowe/issues/1625) +- Fixed submitting local JCL using command pallet option `Zowe Explorer: Submit JCL` by adding a check for chosen profile returned to continue the action. [#1625](https://github.com/zowe/vscode-extension-for-zowe/issues/1625) ## `2.10.0` From 98cf3616b9b3dbd6128082c7edd12c7f5a0db070 Mon Sep 17 00:00:00 2001 From: Trae Yelovich Date: Tue, 12 Sep 2023 13:15:14 -0400 Subject: [PATCH 004/189] fix(ftp/ds): ECONNRESET error for empty dataset contents Signed-off-by: Trae Yelovich --- .../zowe-explorer-ftp-extension/CHANGELOG.md | 2 ++ .../src/ZoweExplorerFtpMvsApi.ts | 20 ++++++++++++------- 2 files changed, 15 insertions(+), 7 deletions(-) diff --git a/packages/zowe-explorer-ftp-extension/CHANGELOG.md b/packages/zowe-explorer-ftp-extension/CHANGELOG.md index 3b940ff212..121eacc766 100644 --- a/packages/zowe-explorer-ftp-extension/CHANGELOG.md +++ b/packages/zowe-explorer-ftp-extension/CHANGELOG.md @@ -6,6 +6,8 @@ All notable changes to the "zowe-explorer-ftp-extension" extension will be docum ### Bug fixes +- Fixed ECONNRESET error when trying to upload or create an empty data set member. [#2350](https://github.com/zowe/vscode-extension-for-zowe/issues/2350) + ## `2.10.0` ### New features and enhancements diff --git a/packages/zowe-explorer-ftp-extension/src/ZoweExplorerFtpMvsApi.ts b/packages/zowe-explorer-ftp-extension/src/ZoweExplorerFtpMvsApi.ts index 8da98ef634..cad64ce721 100644 --- a/packages/zowe-explorer-ftp-extension/src/ZoweExplorerFtpMvsApi.ts +++ b/packages/zowe-explorer-ftp-extension/src/ZoweExplorerFtpMvsApi.ts @@ -112,11 +112,6 @@ export class FtpMvsApi extends AbstractFtpApi implements ZoweExplorerApi.IMvs { } public async putContents(inputFilePath: string, dataSetName: string, options: IUploadOptions): Promise { - const transferOptions = { - transferType: options.binary ? TRANSFER_TYPE_BINARY : TRANSFER_TYPE_ASCII, - localFile: inputFilePath, - encoding: options.encoding, - }; const file = path.basename(inputFilePath).replace(/[^a-z0-9]+/gi, ""); const member = file.substr(0, MAX_MEMBER_NAME_LEN); let targetDataset: string; @@ -153,6 +148,16 @@ export class FtpMvsApi extends AbstractFtpApi implements ZoweExplorerApi.IMvs { } const lrecl: number = dsAtrribute.apiResponse.items[0].lrecl; const data = fs.readFileSync(inputFilePath, { encoding: "utf8" }); + const transferOptions = { + transferType: options.binary ? TRANSFER_TYPE_BINARY : TRANSFER_TYPE_ASCII, + localFile: inputFilePath, + encoding: options.encoding, + }; + if (data == "") { + // substitute single space for empty DS contents when saving (prevents FTP error) + transferOptions["content"] = " "; + delete transferOptions["localFile"]; + } const lines = data.split(/\r?\n/); const foundIndex = lines.findIndex((line) => line.length > lrecl); if (foundIndex !== -1) { @@ -243,8 +248,9 @@ export class FtpMvsApi extends AbstractFtpApi implements ZoweExplorerApi.IMvs { public async createDataSetMember(dataSetName: string, options?: IUploadOptions): Promise { const transferOptions = { - transferType: options ? TRANSFER_TYPE_BINARY : TRANSFER_TYPE_ASCII, - content: "", + transferType: options.binary ? TRANSFER_TYPE_BINARY : TRANSFER_TYPE_ASCII, + // we have to provide a single space for content, or zos-node-accessor will fail to upload the data set over FTP + content: " ", encoding: options.encoding, }; const result = this.getDefaultResponse(); From 679bfc9098bdffd2b48ef6fd5e254e513a7cab38 Mon Sep 17 00:00:00 2001 From: Trae Yelovich Date: Tue, 12 Sep 2023 14:23:10 -0400 Subject: [PATCH 005/189] test(ftp/ds): Add test case for empty contents Signed-off-by: Trae Yelovich --- .../Mvs/ZoweExplorerFtpMvsApi.unit.test.ts | 26 +++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/packages/zowe-explorer-ftp-extension/__tests__/__unit__/Mvs/ZoweExplorerFtpMvsApi.unit.test.ts b/packages/zowe-explorer-ftp-extension/__tests__/__unit__/Mvs/ZoweExplorerFtpMvsApi.unit.test.ts index 42aee4a69f..2340ed9e71 100644 --- a/packages/zowe-explorer-ftp-extension/__tests__/__unit__/Mvs/ZoweExplorerFtpMvsApi.unit.test.ts +++ b/packages/zowe-explorer-ftp-extension/__tests__/__unit__/Mvs/ZoweExplorerFtpMvsApi.unit.test.ts @@ -123,6 +123,32 @@ describe("FtpMvsApi", () => { expect(MvsApi.releaseConnection).toBeCalled(); }); + it("should upload empty contents to dataset.", async () => { + const localFile = tmp.tmpNameSync({ tmpdir: "/tmp" }); + + fs.writeFileSync(localFile, ""); + const response = TestUtils.getSingleLineStream(); + DataSetUtils.listDataSets = jest.fn().mockReturnValue([{ dsname: "IBMUSER.DS2", dsorg: "PS", lrecl: 2 }]); + DataSetUtils.uploadDataSet = jest.fn().mockReturnValue(response); + jest.spyOn(MvsApi, "getContents").mockResolvedValue({ apiResponse: { etag: "123" } } as any); + + const mockParams = { + inputFilePath: localFile, + dataSetName: " (IBMUSER).DS2", + options: { encoding: "", returnEtag: true, etag: "utf8" }, + }; + + jest.spyOn(MvsApi as any, "getContentsTag").mockReturnValue(undefined); + jest.spyOn(fs, "readFileSync").mockReturnValue(""); + await MvsApi.putContents(mockParams.inputFilePath, mockParams.dataSetName, mockParams.options); + expect(DataSetUtils.uploadDataSet).toHaveBeenCalledWith({ host: "", password: "", port: "", user: "" }, " (IBMUSER).DS2", { + content: " ", + encoding: "", + transferType: "ascii", + }); + expect(MvsApi.releaseConnection).toBeCalled(); + }); + it("should create dataset.", async () => { DataSetUtils.allocateDataSet = jest.fn(); const DATA_SET_SEQUENTIAL = 4; From 54a2e697bf988803cc24d4a6ed5dae9b57469f20 Mon Sep 17 00:00:00 2001 From: Likhitha Nimma Date: Wed, 13 Sep 2023 16:20:55 +0530 Subject: [PATCH 006/189] Sort-Jobs Implemented Signed-off-by: Likhitha Nimma --- packages/zowe-explorer/CHANGELOG.md | 1 + .../__tests__/__unit__/extension.unit.test.ts | 3 + .../__unit__/job/actions.unit.test.ts | 125 ++++++++++++++++++ packages/zowe-explorer/package.json | 30 +++++ packages/zowe-explorer/src/globals.ts | 2 +- packages/zowe-explorer/src/job/actions.ts | 35 ++++- packages/zowe-explorer/src/job/init.ts | 6 +- 7 files changed, 199 insertions(+), 3 deletions(-) diff --git a/packages/zowe-explorer/CHANGELOG.md b/packages/zowe-explorer/CHANGELOG.md index 9fdb0fc6ae..fd4b0c1258 100644 --- a/packages/zowe-explorer/CHANGELOG.md +++ b/packages/zowe-explorer/CHANGELOG.md @@ -54,6 +54,7 @@ All notable changes to the "vscode-extension-for-zowe" extension will be documen - Added option to save unique data set attributes as a template after allocation for future use. [#1425](https://github.com/zowe/vscode-extension-for-zowe/issues/1425) - Added "Cancel Job" feature for job nodes in Jobs tree view. [#2251](https://github.com/zowe/vscode-extension-for-zowe/issues/2251) +- Added "Sort Jobs" feature for job nodes in Jobs tree view. [#2257](https://github.com/zowe/vscode-extension-for-zowe/issues/2251) - Enhanced ID generation for parent tree nodes to ensure uniqueness. - Added support for custom credential manager extensions in Zowe Explorer [#2212](https://github.com/zowe/vscode-extension-for-zowe/issues/2212) diff --git a/packages/zowe-explorer/__tests__/__unit__/extension.unit.test.ts b/packages/zowe-explorer/__tests__/__unit__/extension.unit.test.ts index 1b8e377e58..0f637993a6 100644 --- a/packages/zowe-explorer/__tests__/__unit__/extension.unit.test.ts +++ b/packages/zowe-explorer/__tests__/__unit__/extension.unit.test.ts @@ -238,6 +238,9 @@ async function createGlobalMocks() { "zowe.jobs.startPolling", "zowe.jobs.stopPolling", "zowe.jobs.cancelJob", + "zowe.jobs.sortbyname", + "zowe.jobs.sortbyid", + "zowe.jobs.sortbyreturncode", "zowe.manualPoll", "zowe.updateSecureCredentials", "zowe.promptCredentials", diff --git a/packages/zowe-explorer/__tests__/__unit__/job/actions.unit.test.ts b/packages/zowe-explorer/__tests__/__unit__/job/actions.unit.test.ts index 0c6847479e..bbcb33b0c4 100644 --- a/packages/zowe-explorer/__tests__/__unit__/job/actions.unit.test.ts +++ b/packages/zowe-explorer/__tests__/__unit__/job/actions.unit.test.ts @@ -41,6 +41,7 @@ import * as refreshActions from "../../../src/shared/refresh"; import * as sharedUtils from "../../../src/shared/utils"; import { ZoweLogger } from "../../../src/utils/LoggerUtils"; import { SpoolFile } from "../../../src/SpoolProvider"; +import { ZosJobsProvider } from "../../../src/job/ZosJobsProvider"; const activeTextEditorDocument = jest.fn(); @@ -85,6 +86,49 @@ function createGlobalMocks() { Object.defineProperty(ZoweLogger, "error", { value: jest.fn(), configurable: true }); Object.defineProperty(ZoweLogger, "debug", { value: jest.fn(), configurable: true }); Object.defineProperty(ZoweLogger, "trace", { value: jest.fn(), configurable: true }); + Object.defineProperty(vscode.window, "showInformationMessage", { value: jest.fn(), configurable: true }); + function settingJobObjects(job: zowe.IJob, setjobname: string, setjobid: string, setjobreturncode: string): zowe.IJob { + job.jobname = setjobname; + job.jobid = setjobid; + job.retcode = setjobreturncode; + return job; + } + const newMocks = jest.fn().mockReturnValue([ + (() => { + const JobNode1 = new Job( + "testProfile", + vscode.TreeItemCollapsibleState.None, + null, + createISession(), + settingJobObjects(createIJobObject(), "ZOWEUSR1", "JOB045123", "ABEND S222"), + createIProfile() + ); + return JobNode1; + })(), + (() => { + const JobNode2 = new Job( + "testProfile", + vscode.TreeItemCollapsibleState.None, + null, + createISession(), + settingJobObjects(createIJobObject(), "ZOWEUSR1", "JOB045120", "CC 0000"), + createIProfile() + ); + return JobNode2; + })(), + (() => { + const JobNode3 = new Job( + "testProfile", + vscode.TreeItemCollapsibleState.None, + null, + createISession(), + settingJobObjects(createIJobObject(), "ZOWEUSR2", "JOB045125", "CC 0000"), + createIProfile() + ); + return JobNode3; + })(), + ]); + return newMocks; } // Idea is borrowed from: https://github.com/kulshekhar/ts-jest/blob/master/src/util/testing.ts @@ -1300,3 +1344,84 @@ describe("Job Actions Unit Tests - Misc. functions", () => { expect(statusMsgSpy).toHaveBeenCalledWith(`$(sync~spin) Polling: ${testDoc.fileName}...`); }); }); +describe("sortbyname function", () => { + afterEach(() => { + jest.restoreAllMocks(); + }); + it("if there are no jobs in the zosmf level yet", async () => { + createGlobalMocks(); + const testtree = new ZosJobsProvider(); + //act + await jobActions.sortByName(testtree.mSessionNodes[0], testtree); + //assert + expect(mocked(vscode.window.showInformationMessage)).toBeCalled(); + }); + it("sort by name if same sort by increasing id", async () => { + const globalMocks = createGlobalMocks(); + const testtree = new ZosJobsProvider(); + const expected = new ZosJobsProvider(); + testtree.mSessionNodes[0].children = [...[globalMocks()[2], globalMocks()[1], globalMocks()[0]]]; + expected.mSessionNodes[0].children = [...[globalMocks()[1], globalMocks()[0], globalMocks()[2]]]; + const sortbynamespy = jest.spyOn(jobActions, "sortByName"); + //act + await jobActions.sortByName(testtree.mSessionNodes[0], testtree); + //asert + expect(sortbynamespy).toBeCalledWith(testtree.mSessionNodes[0], testtree); + expect(sortbynamespy).toHaveBeenCalled(); + expect(sortbynamespy.mock.calls[0][0].children).toStrictEqual(expected.mSessionNodes[0].children); + }); +}); +describe("sortbyid function", () => { + afterEach(() => { + jest.restoreAllMocks(); + }); + it("if there are no jobs in the zosmf level yet", async () => { + createGlobalMocks(); + const testtree = new ZosJobsProvider(); + //act + await jobActions.sortById(testtree.mSessionNodes[0], testtree); + //assert + expect(mocked(vscode.window.showInformationMessage)).toBeCalled(); + }); + it("sorts by increasing order of id", async () => { + const globalMocks = createGlobalMocks(); + const testtree = new ZosJobsProvider(); + const expected = new ZosJobsProvider(); + testtree.mSessionNodes[0].children = [...[globalMocks()[2], globalMocks()[1], globalMocks()[0]]]; + expected.mSessionNodes[0].children = [...[globalMocks()[1], globalMocks()[0], globalMocks()[2]]]; + const sortbyidspy = jest.spyOn(jobActions, "sortById"); + //act + await jobActions.sortById(testtree.mSessionNodes[0], testtree); + //asert + expect(sortbyidspy).toBeCalledWith(testtree.mSessionNodes[0], testtree); + expect(sortbyidspy).toHaveBeenCalled(); + expect(sortbyidspy.mock.calls[0][0].children).toStrictEqual(expected.mSessionNodes[0].children); + }); +}); +describe("sortbyretcode function", () => { + afterEach(() => { + jest.restoreAllMocks(); + }); + it("if there are no jobs in the zosmf level yet", async () => { + createGlobalMocks(); + const testtree = new ZosJobsProvider(); + //act + await jobActions.sortByReturnCode(testtree.mSessionNodes[0], testtree); + //assert + expect(mocked(vscode.window.showInformationMessage)).toBeCalled(); + }); + it("sort by retcode if same sort by increasing id", async () => { + const globalMocks = createGlobalMocks(); + const testtree = new ZosJobsProvider(); + const expected = new ZosJobsProvider(); + testtree.mSessionNodes[0].children = [...[globalMocks()[2], globalMocks()[1], globalMocks()[0]]]; + expected.mSessionNodes[0].children = [...[globalMocks()[0], globalMocks()[1], globalMocks()[2]]]; + const sortbyretcodespy = jest.spyOn(jobActions, "sortByReturnCode"); + //act + await jobActions.sortByReturnCode(testtree.mSessionNodes[0], testtree); + //asert + expect(sortbyretcodespy).toBeCalledWith(testtree.mSessionNodes[0], testtree); + expect(sortbyretcodespy).toHaveBeenCalled(); + expect(sortbyretcodespy.mock.calls[0][0].children).toStrictEqual(expected.mSessionNodes[0].children); + }); +}); diff --git a/packages/zowe-explorer/package.json b/packages/zowe-explorer/package.json index 0de5da53c0..5e02a87893 100644 --- a/packages/zowe-explorer/package.json +++ b/packages/zowe-explorer/package.json @@ -121,6 +121,21 @@ } ], "commands": [ + { + "command": "zowe.jobs.sortbyreturncode", + "title": "Sort by returncode", + "category": "Zowe Explorer" + }, + { + "command": "zowe.jobs.sortbyname", + "title": "Sort by name", + "category": "Zowe Explorer" + }, + { + "command": "zowe.jobs.sortbyid", + "title": "Sort by id", + "category": "Zowe Explorer" + }, { "command": "zowe.promptCredentials", "title": "%zowe.promptCredentials%", @@ -1357,6 +1372,21 @@ "when": "view == zowe.jobs.explorer && viewItem =~ /^(?!.*_fav.*)server.*/ && !listMultiSelection", "command": "zowe.jobs.deleteProfile", "group": "099_zowe_jobsProfileModification@99" + }, + { + "when": "view == zowe.jobs.explorer && viewItem =~ /^(?!.*_fav.*)server.*/ && !listMultiSelection", + "command": "zowe.jobs.sortbyid", + "group": "000_zowe_jobsProfileModification@1" + }, + { + "when": "view == zowe.jobs.explorer && viewItem =~ /^(?!.*_fav.*)server.*/ && !listMultiSelection", + "command": "zowe.jobs.sortbyname", + "group": "000_zowe_jobsProfileModification@2" + }, + { + "when": "view == zowe.jobs.explorer && viewItem =~ /^(?!.*_fav.*)server.*/ && !listMultiSelection", + "command": "zowe.jobs.sortbyreturncode", + "group": "000_zowe_jobsProfileModification@2" } ], "commandPalette": [ diff --git a/packages/zowe-explorer/src/globals.ts b/packages/zowe-explorer/src/globals.ts index 7bbba932b2..a503fe7332 100644 --- a/packages/zowe-explorer/src/globals.ts +++ b/packages/zowe-explorer/src/globals.ts @@ -35,7 +35,7 @@ export let DS_DIR: string; export let CONFIG_PATH; // set during activate export let ISTHEIA = false; // set during activate export let LOG: imperative.Logger; -export const COMMAND_COUNT = 110; +export const COMMAND_COUNT = 113; export const MAX_SEARCH_HISTORY = 5; export const MAX_FILE_HISTORY = 10; export const MS_PER_SEC = 1000; diff --git a/packages/zowe-explorer/src/job/actions.ts b/packages/zowe-explorer/src/job/actions.ts index 06fecac4c5..3322266096 100644 --- a/packages/zowe-explorer/src/job/actions.ts +++ b/packages/zowe-explorer/src/job/actions.ts @@ -14,7 +14,7 @@ import * as zowe from "@zowe/cli"; import { errorHandling } from "../utils/ProfilesUtils"; import { Profiles } from "../Profiles"; import { ZoweExplorerApiRegister } from "../ZoweExplorerApiRegister"; -import { Gui, ValidProfileEnum, IZoweTree, IZoweJobTreeNode } from "@zowe/zowe-explorer-api"; +import { Gui, IZoweTree, IZoweJobTreeNode } from "@zowe/zowe-explorer-api"; import { Job, Spool } from "./ZoweJobNode"; import * as nls from "vscode-nls"; import SpoolProvider, { encodeJobFile, getSpoolFiles, matchSpool } from "../SpoolProvider"; @@ -528,3 +528,36 @@ export async function cancelJobs(jobsProvider: IZoweTree, node await Gui.showMessage(localize("cancelJobs.succeeded", "Cancelled selected jobs successfully.")); } } +export async function sortByName(jobs: IZoweJobTreeNode, jobsProvider: IZoweTree): Promise { + if (jobs["children"].length == 0) { + await vscode.window.showInformationMessage("No jobs are present in the profile."); + } + jobs["children"].sort((x, y) => { + if (x["job"]["jobname"] === y["job"]["jobname"]) { + return x["job"]["jobid"] > y["job"]["jobid"] ? 1 : -1; + } else { + return x["job"]["jobname"] > y["job"]["jobname"] ? 1 : -1; + } + }); + jobsProvider.refresh(); +} +export async function sortById(jobs: IZoweJobTreeNode, jobsProvider: IZoweTree): Promise { + if (jobs["children"].length == 0) { + await vscode.window.showInformationMessage("No jobs are present in the profile."); + } + jobs["children"].sort((x, y) => (x["job"]["jobid"] > y["job"]["jobid"] ? 1 : -1)); + jobsProvider.refresh(); +} +export async function sortByReturnCode(jobs: IZoweJobTreeNode, jobsProvider: IZoweTree): Promise { + if (jobs["children"].length == 0) { + await vscode.window.showInformationMessage("No jobs are present in the profile."); + } + jobs["children"].sort((x, y) => { + if (x["job"]["retcode"] === y["job"]["retcode"]) { + return x["job"]["jobid"] > y["job"]["jobid"] ? 1 : -1; + } else { + return x["job"]["retcode"] > y["job"]["retcode"] ? 1 : -1; + } + }); + jobsProvider.refresh(); +} diff --git a/packages/zowe-explorer/src/job/init.ts b/packages/zowe-explorer/src/job/init.ts index 73b3f0ebb8..4571e7e7e9 100644 --- a/packages/zowe-explorer/src/job/init.ts +++ b/packages/zowe-explorer/src/job/init.ts @@ -169,7 +169,11 @@ export async function initJobsProvider(context: vscode.ExtensionContext): Promis await jobActions.cancelJobs(jobsProvider, getSelectedNodeList(node, nodeList)); }) ); - + context.subscriptions.push(vscode.commands.registerCommand("zowe.jobs.sortbyname", (job) => jobActions.sortByName(job, jobsProvider))); + context.subscriptions.push(vscode.commands.registerCommand("zowe.jobs.sortbyid", (job) => jobActions.sortById(job, jobsProvider))); + context.subscriptions.push( + vscode.commands.registerCommand("zowe.jobs.sortbyreturncode", (job) => jobActions.sortByReturnCode(job, jobsProvider)) + ); initSubscribers(context, jobsProvider); return jobsProvider; } From e6fb21e8af7f3eefadf31cc8e537fb6539104f3e Mon Sep 17 00:00:00 2001 From: Trae Yelovich Date: Wed, 13 Sep 2023 10:20:49 -0400 Subject: [PATCH 007/189] test(ftp): update test to ensure localFile isn't in object Signed-off-by: Trae Yelovich --- .../__unit__/Mvs/ZoweExplorerFtpMvsApi.unit.test.ts | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/packages/zowe-explorer-ftp-extension/__tests__/__unit__/Mvs/ZoweExplorerFtpMvsApi.unit.test.ts b/packages/zowe-explorer-ftp-extension/__tests__/__unit__/Mvs/ZoweExplorerFtpMvsApi.unit.test.ts index 2340ed9e71..ac8fcebdbb 100644 --- a/packages/zowe-explorer-ftp-extension/__tests__/__unit__/Mvs/ZoweExplorerFtpMvsApi.unit.test.ts +++ b/packages/zowe-explorer-ftp-extension/__tests__/__unit__/Mvs/ZoweExplorerFtpMvsApi.unit.test.ts @@ -128,24 +128,27 @@ describe("FtpMvsApi", () => { fs.writeFileSync(localFile, ""); const response = TestUtils.getSingleLineStream(); - DataSetUtils.listDataSets = jest.fn().mockReturnValue([{ dsname: "IBMUSER.DS2", dsorg: "PS", lrecl: 2 }]); - DataSetUtils.uploadDataSet = jest.fn().mockReturnValue(response); + DataSetUtils.listDataSets = jest.fn().mockReturnValue([{ dsname: "USER.EMPTYDS", dsorg: "PS", lrecl: 2 }]); + const uploadDataSetMock = jest.fn().mockReturnValue(response); + DataSetUtils.uploadDataSet = uploadDataSetMock; jest.spyOn(MvsApi, "getContents").mockResolvedValue({ apiResponse: { etag: "123" } } as any); const mockParams = { inputFilePath: localFile, - dataSetName: " (IBMUSER).DS2", + dataSetName: "USER.EMPTYDS", options: { encoding: "", returnEtag: true, etag: "utf8" }, }; jest.spyOn(MvsApi as any, "getContentsTag").mockReturnValue(undefined); jest.spyOn(fs, "readFileSync").mockReturnValue(""); await MvsApi.putContents(mockParams.inputFilePath, mockParams.dataSetName, mockParams.options); - expect(DataSetUtils.uploadDataSet).toHaveBeenCalledWith({ host: "", password: "", port: "", user: "" }, " (IBMUSER).DS2", { + expect(DataSetUtils.uploadDataSet).toHaveBeenCalledWith({ host: "", password: "", port: "", user: "" }, "USER.EMPTYDS", { content: " ", encoding: "", transferType: "ascii", }); + // ensure options object at runtime does not have localFile + expect(Object.keys(uploadDataSetMock.mock.calls[0][2]).find((k) => k === "localFile")).toBe(undefined); expect(MvsApi.releaseConnection).toBeCalled(); }); From f18487a938136416daa6a630369b8f74a0acb207 Mon Sep 17 00:00:00 2001 From: Likhitha Nimma Date: Sat, 16 Sep 2023 11:47:44 +0530 Subject: [PATCH 008/189] Modified Changelog and package.json Signed-off-by: Likhitha Nimma --- packages/zowe-explorer/CHANGELOG.md | 3 ++- packages/zowe-explorer/package.json | 6 +++--- packages/zowe-explorer/package.nls.json | 5 ++++- 3 files changed, 9 insertions(+), 5 deletions(-) diff --git a/packages/zowe-explorer/CHANGELOG.md b/packages/zowe-explorer/CHANGELOG.md index 03974e6c1e..494c94a0c9 100644 --- a/packages/zowe-explorer/CHANGELOG.md +++ b/packages/zowe-explorer/CHANGELOG.md @@ -4,6 +4,8 @@ All notable changes to the "vscode-extension-for-zowe" extension will be documen ## TBD Release +- Added "Sort Jobs" feature for job nodes in Jobs tree view. [#2257](https://github.com/zowe/vscode-extension-for-zowe/issues/2251) + ### New features and enhancements ### Bug fixes @@ -61,7 +63,6 @@ All notable changes to the "vscode-extension-for-zowe" extension will be documen - Added option to save unique data set attributes as a template after allocation for future use. [#1425](https://github.com/zowe/vscode-extension-for-zowe/issues/1425) - Added "Cancel Job" feature for job nodes in Jobs tree view. [#2251](https://github.com/zowe/vscode-extension-for-zowe/issues/2251) -- Added "Sort Jobs" feature for job nodes in Jobs tree view. [#2257](https://github.com/zowe/vscode-extension-for-zowe/issues/2251) - Enhanced ID generation for parent tree nodes to ensure uniqueness. - Added support for custom credential manager extensions in Zowe Explorer [#2212](https://github.com/zowe/vscode-extension-for-zowe/issues/2212) diff --git a/packages/zowe-explorer/package.json b/packages/zowe-explorer/package.json index fb6bd6c2f2..527726260b 100644 --- a/packages/zowe-explorer/package.json +++ b/packages/zowe-explorer/package.json @@ -123,17 +123,17 @@ "commands": [ { "command": "zowe.jobs.sortbyreturncode", - "title": "Sort by returncode", + "title": "%jobs.sortbyreturncode%", "category": "Zowe Explorer" }, { "command": "zowe.jobs.sortbyname", - "title": "Sort by name", + "title": "%jobs.sortbyname%", "category": "Zowe Explorer" }, { "command": "zowe.jobs.sortbyid", - "title": "Sort by id", + "title": "%jobs.sortbyid%", "category": "Zowe Explorer" }, { diff --git a/packages/zowe-explorer/package.nls.json b/packages/zowe-explorer/package.nls.json index 5930969b05..8bc5d8bf6c 100644 --- a/packages/zowe-explorer/package.nls.json +++ b/packages/zowe-explorer/package.nls.json @@ -146,5 +146,8 @@ "createZoweSchema.reload.button": "Reload Window", "createZoweSchema.reload.infoMessage": "Team Configuration file created. Location: {0}. \n Please reload your window.", "copyFile": "Copy", - "pasteFile": "Paste" + "pasteFile": "Paste", + "jobs.sortbyreturncode": "Sort by ReturnCode", + "jobs.sortbyname": "Sort by Name", + "jobs.sortbyid": "Sort by ID" } From ef8333e43b221dc9acd58549bbc0fbefed194669 Mon Sep 17 00:00:00 2001 From: Likhitha Nimma Date: Mon, 18 Sep 2023 20:55:54 +0530 Subject: [PATCH 009/189] Modified CHANGELOG file Signed-off-by: Likhitha Nimma --- packages/zowe-explorer/CHANGELOG.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/zowe-explorer/CHANGELOG.md b/packages/zowe-explorer/CHANGELOG.md index 494c94a0c9..99e818bad5 100644 --- a/packages/zowe-explorer/CHANGELOG.md +++ b/packages/zowe-explorer/CHANGELOG.md @@ -4,10 +4,10 @@ All notable changes to the "vscode-extension-for-zowe" extension will be documen ## TBD Release -- Added "Sort Jobs" feature for job nodes in Jobs tree view. [#2257](https://github.com/zowe/vscode-extension-for-zowe/issues/2251) - ### New features and enhancements +- Added "Sort Jobs" feature for job nodes in Jobs tree view. [#2257](https://github.com/zowe/vscode-extension-for-zowe/issues/2251) + ### Bug fixes ## `2.11.0` From 5623883ba5f0e4c63ae91c94c2958519cd2e3ee3 Mon Sep 17 00:00:00 2001 From: Likhitha Nimma Date: Mon, 18 Sep 2023 21:49:16 +0530 Subject: [PATCH 010/189] Modified the functionality to 1 function-Updated actions.ts file Signed-off-by: Likhitha Nimma --- .../__unit__/job/actions.unit.test.ts | 50 +++++-------------- packages/zowe-explorer/src/job/actions.ts | 26 ++-------- packages/zowe-explorer/src/job/init.ts | 6 +-- 3 files changed, 19 insertions(+), 63 deletions(-) diff --git a/packages/zowe-explorer/__tests__/__unit__/job/actions.unit.test.ts b/packages/zowe-explorer/__tests__/__unit__/job/actions.unit.test.ts index bbcb33b0c4..e541a0650f 100644 --- a/packages/zowe-explorer/__tests__/__unit__/job/actions.unit.test.ts +++ b/packages/zowe-explorer/__tests__/__unit__/job/actions.unit.test.ts @@ -1344,7 +1344,7 @@ describe("Job Actions Unit Tests - Misc. functions", () => { expect(statusMsgSpy).toHaveBeenCalledWith(`$(sync~spin) Polling: ${testDoc.fileName}...`); }); }); -describe("sortbyname function", () => { +describe("sortjobsby function", () => { afterEach(() => { jest.restoreAllMocks(); }); @@ -1352,7 +1352,9 @@ describe("sortbyname function", () => { createGlobalMocks(); const testtree = new ZosJobsProvider(); //act - await jobActions.sortByName(testtree.mSessionNodes[0], testtree); + await jobActions.sortJobsBy(testtree.mSessionNodes[0], testtree, "jobname"); + await jobActions.sortJobsBy(testtree.mSessionNodes[0], testtree, "jobid"); + await jobActions.sortJobsBy(testtree.mSessionNodes[0], testtree, "retcode"); //assert expect(mocked(vscode.window.showInformationMessage)).toBeCalled(); }); @@ -1362,65 +1364,39 @@ describe("sortbyname function", () => { const expected = new ZosJobsProvider(); testtree.mSessionNodes[0].children = [...[globalMocks()[2], globalMocks()[1], globalMocks()[0]]]; expected.mSessionNodes[0].children = [...[globalMocks()[1], globalMocks()[0], globalMocks()[2]]]; - const sortbynamespy = jest.spyOn(jobActions, "sortByName"); + const sortbynamespy = jest.spyOn(jobActions, "sortJobsBy"); //act - await jobActions.sortByName(testtree.mSessionNodes[0], testtree); + await jobActions.sortJobsBy(testtree.mSessionNodes[0], testtree, "jobname"); //asert - expect(sortbynamespy).toBeCalledWith(testtree.mSessionNodes[0], testtree); + expect(sortbynamespy).toBeCalledWith(testtree.mSessionNodes[0], testtree, "jobname"); expect(sortbynamespy).toHaveBeenCalled(); expect(sortbynamespy.mock.calls[0][0].children).toStrictEqual(expected.mSessionNodes[0].children); }); -}); -describe("sortbyid function", () => { - afterEach(() => { - jest.restoreAllMocks(); - }); - it("if there are no jobs in the zosmf level yet", async () => { - createGlobalMocks(); - const testtree = new ZosJobsProvider(); - //act - await jobActions.sortById(testtree.mSessionNodes[0], testtree); - //assert - expect(mocked(vscode.window.showInformationMessage)).toBeCalled(); - }); it("sorts by increasing order of id", async () => { const globalMocks = createGlobalMocks(); const testtree = new ZosJobsProvider(); const expected = new ZosJobsProvider(); testtree.mSessionNodes[0].children = [...[globalMocks()[2], globalMocks()[1], globalMocks()[0]]]; expected.mSessionNodes[0].children = [...[globalMocks()[1], globalMocks()[0], globalMocks()[2]]]; - const sortbyidspy = jest.spyOn(jobActions, "sortById"); + const sortbyidspy = jest.spyOn(jobActions, "sortJobsBy"); //act - await jobActions.sortById(testtree.mSessionNodes[0], testtree); + await jobActions.sortJobsBy(testtree.mSessionNodes[0], testtree, "jobid"); //asert - expect(sortbyidspy).toBeCalledWith(testtree.mSessionNodes[0], testtree); + expect(sortbyidspy).toBeCalledWith(testtree.mSessionNodes[0], testtree, "jobid"); expect(sortbyidspy).toHaveBeenCalled(); expect(sortbyidspy.mock.calls[0][0].children).toStrictEqual(expected.mSessionNodes[0].children); }); -}); -describe("sortbyretcode function", () => { - afterEach(() => { - jest.restoreAllMocks(); - }); - it("if there are no jobs in the zosmf level yet", async () => { - createGlobalMocks(); - const testtree = new ZosJobsProvider(); - //act - await jobActions.sortByReturnCode(testtree.mSessionNodes[0], testtree); - //assert - expect(mocked(vscode.window.showInformationMessage)).toBeCalled(); - }); it("sort by retcode if same sort by increasing id", async () => { const globalMocks = createGlobalMocks(); const testtree = new ZosJobsProvider(); const expected = new ZosJobsProvider(); testtree.mSessionNodes[0].children = [...[globalMocks()[2], globalMocks()[1], globalMocks()[0]]]; expected.mSessionNodes[0].children = [...[globalMocks()[0], globalMocks()[1], globalMocks()[2]]]; - const sortbyretcodespy = jest.spyOn(jobActions, "sortByReturnCode"); + const sortbyretcodespy = jest.spyOn(jobActions, "sortJobsBy"); //act - await jobActions.sortByReturnCode(testtree.mSessionNodes[0], testtree); + await jobActions.sortJobsBy(testtree.mSessionNodes[0], testtree, "retcode"); //asert - expect(sortbyretcodespy).toBeCalledWith(testtree.mSessionNodes[0], testtree); + expect(sortbyretcodespy).toBeCalledWith(testtree.mSessionNodes[0], testtree, "retcode"); expect(sortbyretcodespy).toHaveBeenCalled(); expect(sortbyretcodespy.mock.calls[0][0].children).toStrictEqual(expected.mSessionNodes[0].children); }); diff --git a/packages/zowe-explorer/src/job/actions.ts b/packages/zowe-explorer/src/job/actions.ts index 3322266096..b7dd81ef9e 100644 --- a/packages/zowe-explorer/src/job/actions.ts +++ b/packages/zowe-explorer/src/job/actions.ts @@ -528,35 +528,15 @@ export async function cancelJobs(jobsProvider: IZoweTree, node await Gui.showMessage(localize("cancelJobs.succeeded", "Cancelled selected jobs successfully.")); } } -export async function sortByName(jobs: IZoweJobTreeNode, jobsProvider: IZoweTree): Promise { +export async function sortJobsBy(jobs: IZoweJobTreeNode, jobsProvider: IZoweTree, key: keyof zowe.IJob): Promise { if (jobs["children"].length == 0) { await vscode.window.showInformationMessage("No jobs are present in the profile."); } jobs["children"].sort((x, y) => { - if (x["job"]["jobname"] === y["job"]["jobname"]) { + if (key !== "jobid" && x["job"][key] == y["job"][key]) { return x["job"]["jobid"] > y["job"]["jobid"] ? 1 : -1; } else { - return x["job"]["jobname"] > y["job"]["jobname"] ? 1 : -1; - } - }); - jobsProvider.refresh(); -} -export async function sortById(jobs: IZoweJobTreeNode, jobsProvider: IZoweTree): Promise { - if (jobs["children"].length == 0) { - await vscode.window.showInformationMessage("No jobs are present in the profile."); - } - jobs["children"].sort((x, y) => (x["job"]["jobid"] > y["job"]["jobid"] ? 1 : -1)); - jobsProvider.refresh(); -} -export async function sortByReturnCode(jobs: IZoweJobTreeNode, jobsProvider: IZoweTree): Promise { - if (jobs["children"].length == 0) { - await vscode.window.showInformationMessage("No jobs are present in the profile."); - } - jobs["children"].sort((x, y) => { - if (x["job"]["retcode"] === y["job"]["retcode"]) { - return x["job"]["jobid"] > y["job"]["jobid"] ? 1 : -1; - } else { - return x["job"]["retcode"] > y["job"]["retcode"] ? 1 : -1; + return x["job"][key] > y["job"][key] ? 1 : -1; } }); jobsProvider.refresh(); diff --git a/packages/zowe-explorer/src/job/init.ts b/packages/zowe-explorer/src/job/init.ts index 4571e7e7e9..55cb416fa2 100644 --- a/packages/zowe-explorer/src/job/init.ts +++ b/packages/zowe-explorer/src/job/init.ts @@ -169,10 +169,10 @@ export async function initJobsProvider(context: vscode.ExtensionContext): Promis await jobActions.cancelJobs(jobsProvider, getSelectedNodeList(node, nodeList)); }) ); - context.subscriptions.push(vscode.commands.registerCommand("zowe.jobs.sortbyname", (job) => jobActions.sortByName(job, jobsProvider))); - context.subscriptions.push(vscode.commands.registerCommand("zowe.jobs.sortbyid", (job) => jobActions.sortById(job, jobsProvider))); + context.subscriptions.push(vscode.commands.registerCommand("zowe.jobs.sortbyname", (job) => jobActions.sortJobsBy(job, jobsProvider, "jobname"))); + context.subscriptions.push(vscode.commands.registerCommand("zowe.jobs.sortbyid", (job) => jobActions.sortJobsBy(job, jobsProvider, "jobid"))); context.subscriptions.push( - vscode.commands.registerCommand("zowe.jobs.sortbyreturncode", (job) => jobActions.sortByReturnCode(job, jobsProvider)) + vscode.commands.registerCommand("zowe.jobs.sortbyreturncode", (job) => jobActions.sortJobsBy(job, jobsProvider, "retcode")) ); initSubscribers(context, jobsProvider); return jobsProvider; From 72a9770488a55862ae677705cc656d5de34e049e Mon Sep 17 00:00:00 2001 From: Trae Yelovich Date: Tue, 19 Sep 2023 10:23:07 -0400 Subject: [PATCH 011/189] fix(ftp): only use space fix if FTPS is enabled for profile Signed-off-by: Trae Yelovich --- .../src/ZoweExplorerFtpMvsApi.ts | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/packages/zowe-explorer-ftp-extension/src/ZoweExplorerFtpMvsApi.ts b/packages/zowe-explorer-ftp-extension/src/ZoweExplorerFtpMvsApi.ts index cad64ce721..59da88dbf3 100644 --- a/packages/zowe-explorer-ftp-extension/src/ZoweExplorerFtpMvsApi.ts +++ b/packages/zowe-explorer-ftp-extension/src/ZoweExplorerFtpMvsApi.ts @@ -130,9 +130,10 @@ export class FtpMvsApi extends AbstractFtpApi implements ZoweExplorerApi.IMvs { targetDataset = dataSetName + "(" + member + ")"; } const result = this.getDefaultResponse(); + const profile = this.checkedProfile(); let connection; try { - connection = await this.ftpClient(this.checkedProfile()); + connection = await this.ftpClient(profile); if (!connection) { ZoweLogger.logImperativeMessage(result.commandResponse, MessageSeverity.ERROR); throw new Error(result.commandResponse); @@ -153,8 +154,8 @@ export class FtpMvsApi extends AbstractFtpApi implements ZoweExplorerApi.IMvs { localFile: inputFilePath, encoding: options.encoding, }; - if (data == "") { - // substitute single space for empty DS contents when saving (prevents FTP error) + if (profile.profile["secureFtp"] && data == "") { + // substitute single space for empty DS contents when saving (avoids FTPS error) transferOptions["content"] = " "; delete transferOptions["localFile"]; } @@ -247,16 +248,17 @@ export class FtpMvsApi extends AbstractFtpApi implements ZoweExplorerApi.IMvs { } public async createDataSetMember(dataSetName: string, options?: IUploadOptions): Promise { + const profile = this.checkedProfile(); const transferOptions = { transferType: options.binary ? TRANSFER_TYPE_BINARY : TRANSFER_TYPE_ASCII, - // we have to provide a single space for content, or zos-node-accessor will fail to upload the data set over FTP - content: " ", + // we have to provide a single space for content over FTPS, or it will fail to upload + content: profile.profile["secureFtp"] ? " " : "", encoding: options.encoding, }; const result = this.getDefaultResponse(); let connection; try { - connection = await this.ftpClient(this.checkedProfile()); + connection = await this.ftpClient(profile); if (!connection) { throw new Error(result.commandResponse); } From 5f51da0f99dfcd74ef96715871d9d6cebfafe4e1 Mon Sep 17 00:00:00 2001 From: Trae Yelovich Date: Tue, 19 Sep 2023 10:54:21 -0400 Subject: [PATCH 012/189] test(ftp): make test case more specific for FTPS space fix Signed-off-by: Trae Yelovich --- .../__unit__/Mvs/ZoweExplorerFtpMvsApi.unit.test.ts | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/packages/zowe-explorer-ftp-extension/__tests__/__unit__/Mvs/ZoweExplorerFtpMvsApi.unit.test.ts b/packages/zowe-explorer-ftp-extension/__tests__/__unit__/Mvs/ZoweExplorerFtpMvsApi.unit.test.ts index ac8fcebdbb..1836670676 100644 --- a/packages/zowe-explorer-ftp-extension/__tests__/__unit__/Mvs/ZoweExplorerFtpMvsApi.unit.test.ts +++ b/packages/zowe-explorer-ftp-extension/__tests__/__unit__/Mvs/ZoweExplorerFtpMvsApi.unit.test.ts @@ -36,7 +36,7 @@ const MvsApi = new FtpMvsApi(); describe("FtpMvsApi", () => { beforeEach(() => { - MvsApi.checkedProfile = jest.fn().mockReturnValue({ message: "success", type: "zftp", failNotFound: false }); + MvsApi.checkedProfile = jest.fn().mockReturnValue({ message: "success", type: "zftp", profile: { secureFtp: false }, failNotFound: false }); MvsApi.ftpClient = jest.fn().mockReturnValue({ host: "", user: "", password: "", port: "" }); MvsApi.releaseConnection = jest.fn(); sessionMap.get = jest.fn().mockReturnValue({ mvsListConnection: { connected: true } }); @@ -123,7 +123,7 @@ describe("FtpMvsApi", () => { expect(MvsApi.releaseConnection).toBeCalled(); }); - it("should upload empty contents to dataset.", async () => { + it("should upload single space to dataset when secureFtp is true and contents are empty", async () => { const localFile = tmp.tmpNameSync({ tmpdir: "/tmp" }); fs.writeFileSync(localFile, ""); @@ -138,6 +138,14 @@ describe("FtpMvsApi", () => { dataSetName: "USER.EMPTYDS", options: { encoding: "", returnEtag: true, etag: "utf8" }, }; + jest.spyOn(MvsApi, "checkedProfile").mockReturnValueOnce({ + type: "zftp", + message: "", + profile: { + secureFtp: true, + }, + failNotFound: false, + }); jest.spyOn(MvsApi as any, "getContentsTag").mockReturnValue(undefined); jest.spyOn(fs, "readFileSync").mockReturnValue(""); From f42c442204aee8e959b3b7fc890dde7c0e5cf0d5 Mon Sep 17 00:00:00 2001 From: Trae Yelovich Date: Tue, 19 Sep 2023 14:16:14 -0400 Subject: [PATCH 013/189] fix(ftp): access/modify object properties directly Signed-off-by: Trae Yelovich --- .../src/ZoweExplorerFtpMvsApi.ts | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/packages/zowe-explorer-ftp-extension/src/ZoweExplorerFtpMvsApi.ts b/packages/zowe-explorer-ftp-extension/src/ZoweExplorerFtpMvsApi.ts index 59da88dbf3..75bd6bfaac 100644 --- a/packages/zowe-explorer-ftp-extension/src/ZoweExplorerFtpMvsApi.ts +++ b/packages/zowe-explorer-ftp-extension/src/ZoweExplorerFtpMvsApi.ts @@ -149,15 +149,15 @@ export class FtpMvsApi extends AbstractFtpApi implements ZoweExplorerApi.IMvs { } const lrecl: number = dsAtrribute.apiResponse.items[0].lrecl; const data = fs.readFileSync(inputFilePath, { encoding: "utf8" }); - const transferOptions = { + const transferOptions: Record = { transferType: options.binary ? TRANSFER_TYPE_BINARY : TRANSFER_TYPE_ASCII, localFile: inputFilePath, encoding: options.encoding, }; - if (profile.profile["secureFtp"] && data == "") { + if (profile.profile.secureFtp && data == "") { // substitute single space for empty DS contents when saving (avoids FTPS error) - transferOptions["content"] = " "; - delete transferOptions["localFile"]; + transferOptions.content = " "; + delete transferOptions.localFile; } const lines = data.split(/\r?\n/); const foundIndex = lines.findIndex((line) => line.length > lrecl); @@ -252,7 +252,7 @@ export class FtpMvsApi extends AbstractFtpApi implements ZoweExplorerApi.IMvs { const transferOptions = { transferType: options.binary ? TRANSFER_TYPE_BINARY : TRANSFER_TYPE_ASCII, // we have to provide a single space for content over FTPS, or it will fail to upload - content: profile.profile["secureFtp"] ? " " : "", + content: profile.profile.secureFtp ? " " : "", encoding: options.encoding, }; const result = this.getDefaultResponse(); From 3e24aab4b8603386871ecf3c9232bcbf0051acd8 Mon Sep 17 00:00:00 2001 From: Trae Yelovich Date: Tue, 19 Sep 2023 14:22:06 -0400 Subject: [PATCH 014/189] fix(ftp): use eqeqeq for data in putContents Signed-off-by: Trae Yelovich --- .../zowe-explorer-ftp-extension/src/ZoweExplorerFtpMvsApi.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/zowe-explorer-ftp-extension/src/ZoweExplorerFtpMvsApi.ts b/packages/zowe-explorer-ftp-extension/src/ZoweExplorerFtpMvsApi.ts index 75bd6bfaac..4ad04c06bb 100644 --- a/packages/zowe-explorer-ftp-extension/src/ZoweExplorerFtpMvsApi.ts +++ b/packages/zowe-explorer-ftp-extension/src/ZoweExplorerFtpMvsApi.ts @@ -154,7 +154,7 @@ export class FtpMvsApi extends AbstractFtpApi implements ZoweExplorerApi.IMvs { localFile: inputFilePath, encoding: options.encoding, }; - if (profile.profile.secureFtp && data == "") { + if (profile.profile.secureFtp && data === "") { // substitute single space for empty DS contents when saving (avoids FTPS error) transferOptions.content = " "; delete transferOptions.localFile; From 1dea6486fe772bd0165b954e7be8264f866f1b3d Mon Sep 17 00:00:00 2001 From: Rudy Flores <68666202+rudyflores@users.noreply.github.com> Date: Tue, 19 Sep 2023 16:06:40 -0400 Subject: [PATCH 015/189] add option to change tag of uss file Signed-off-by: Rudy Flores <68666202+rudyflores@users.noreply.github.com> --- .../src/profiles/ZoweExplorerApi.ts | 8 +++++++ .../src/profiles/ZoweExplorerZosmfApi.ts | 21 ++++++++++++++++++- packages/zowe-explorer-api/src/utils/files.ts | 1 + .../i18n/sample/package.i18n.json | 5 ++++- .../zowe-explorer/src/uss/AttributeView.ts | 13 ++++++++++++ .../webviews/edit-attributes/src/App.tsx | 13 ++++++++++++ .../webviews/edit-attributes/src/types.ts | 1 + 7 files changed, 60 insertions(+), 2 deletions(-) diff --git a/packages/zowe-explorer-api/src/profiles/ZoweExplorerApi.ts b/packages/zowe-explorer-api/src/profiles/ZoweExplorerApi.ts index 905722b894..d79c99ca37 100644 --- a/packages/zowe-explorer-api/src/profiles/ZoweExplorerApi.ts +++ b/packages/zowe-explorer-api/src/profiles/ZoweExplorerApi.ts @@ -205,6 +205,14 @@ export namespace ZoweExplorerApi { * @returns {Promise} */ rename(currentUssPath: string, newUssPath: string): Promise; + + /** + * Get the tag of a USS file + * + * @param {string} currentUssPath + * @returns {Promise} + */ + getTag?(ussPath: string): Promise; } /** diff --git a/packages/zowe-explorer-api/src/profiles/ZoweExplorerZosmfApi.ts b/packages/zowe-explorer-api/src/profiles/ZoweExplorerZosmfApi.ts index c20cda5208..554515929a 100644 --- a/packages/zowe-explorer-api/src/profiles/ZoweExplorerZosmfApi.ts +++ b/packages/zowe-explorer-api/src/profiles/ZoweExplorerZosmfApi.ts @@ -147,6 +147,14 @@ export class ZosmfUssApi extends ZosmfApiCommon implements ZoweExplorerApi.IUss public async updateAttributes(ussPath: string, attributes: Partial): Promise { try { + if (attributes.tag) { + await zowe.Utilities.putUSSPayload(this.getSession(), ussPath, { + request: "chtag", + action: "set", + type: "text", + codeset: attributes.tag !== null ? attributes.tag.toString() : attributes.tag, + }); + } if ((attributes.group || attributes.gid) && (attributes.owner || attributes.uid)) { await zowe.Utilities.putUSSPayload(this.getSession(), ussPath, { request: "chown", @@ -161,7 +169,6 @@ export class ZosmfUssApi extends ZosmfApiCommon implements ZoweExplorerApi.IUss recursive: true, }); } - if (attributes.perms) { await zowe.Utilities.putUSSPayload(this.getSession(), ussPath, { request: "chmod", @@ -205,6 +212,18 @@ export class ZosmfUssApi extends ZosmfApiCommon implements ZoweExplorerApi.IUss apiResponse: result, }; } + + public async getTag(ussPath: string): Promise { + const result = JSON.parse( + Buffer.from( + await zowe.Utilities.putUSSPayload(this.getSession(), ussPath, { + request: "chtag", + action: "list", + }) + ).toString() + ); + return result.stdout[0].split(" ")[1] as string; + } } /** diff --git a/packages/zowe-explorer-api/src/utils/files.ts b/packages/zowe-explorer-api/src/utils/files.ts index 76b1026ff2..cb95337463 100644 --- a/packages/zowe-explorer-api/src/utils/files.ts +++ b/packages/zowe-explorer-api/src/utils/files.ts @@ -21,6 +21,7 @@ export type FileAttributes = { owner: string; uid: number; perms: string; + tag?: string; }; export function permStringToOctal(perms: string): number { diff --git a/packages/zowe-explorer/i18n/sample/package.i18n.json b/packages/zowe-explorer/i18n/sample/package.i18n.json index 5930969b05..8bc5d8bf6c 100644 --- a/packages/zowe-explorer/i18n/sample/package.i18n.json +++ b/packages/zowe-explorer/i18n/sample/package.i18n.json @@ -146,5 +146,8 @@ "createZoweSchema.reload.button": "Reload Window", "createZoweSchema.reload.infoMessage": "Team Configuration file created. Location: {0}. \n Please reload your window.", "copyFile": "Copy", - "pasteFile": "Paste" + "pasteFile": "Paste", + "jobs.sortbyreturncode": "Sort by ReturnCode", + "jobs.sortbyname": "Sort by Name", + "jobs.sortbyid": "Sort by ID" } diff --git a/packages/zowe-explorer/src/uss/AttributeView.ts b/packages/zowe-explorer/src/uss/AttributeView.ts index baaac36f3a..5a880dbccc 100644 --- a/packages/zowe-explorer/src/uss/AttributeView.ts +++ b/packages/zowe-explorer/src/uss/AttributeView.ts @@ -12,6 +12,7 @@ import { FileAttributes, Gui, IZoweTree, IZoweUSSTreeNode, WebView, ZoweExplorerApi } from "@zowe/zowe-explorer-api"; import { Disposable, ExtensionContext } from "vscode"; import { ZoweExplorerApiRegister } from "../ZoweExplorerApiRegister"; +import * as contextually from "../shared/context"; export class AttributeView extends WebView { private treeProvider: IZoweTree; @@ -30,11 +31,18 @@ export class AttributeView extends WebView { this.ussApi = ZoweExplorerApiRegister.getUssApi(this.ussNode.getProfile()); } + private async attachTag(node: IZoweUSSTreeNode): Promise { + if (this.ussApi.getTag && !contextually.isUssDirectory(node)) { + node.attributes.tag = await this.ussApi.getTag(node.fullPath); + } + } + protected async onDidReceiveMessage(message: any): Promise { switch (message.command) { case "refresh": if (this.canUpdate) { this.onUpdateDisposable = this.ussNode.onUpdate(async (node) => { + await this.attachTag(node); await this.panel.webview.postMessage({ attributes: node.attributes, name: node.fullPath, @@ -51,6 +59,7 @@ export class AttributeView extends WebView { } break; case "ready": + await this.attachTag(this.ussNode); await this.panel.webview.postMessage({ attributes: this.ussNode.attributes, name: this.ussNode.fullPath, @@ -104,6 +113,10 @@ export class AttributeView extends WebView { newAttrs.perms = attrs.perms; } + if (this.ussNode.attributes.tag !== attrs.tag && this.ussApi.getTag) { + newAttrs.tag = attrs.tag; + } + await this.ussApi.updateAttributes(this.ussNode.fullPath, newAttrs); this.ussNode.attributes = { ...(this.ussNode.attributes ?? {}), ...newAttrs } as FileAttributes; diff --git a/packages/zowe-explorer/webviews/edit-attributes/src/App.tsx b/packages/zowe-explorer/webviews/edit-attributes/src/App.tsx index b15dcfd43e..0d44c55652 100644 --- a/packages/zowe-explorer/webviews/edit-attributes/src/App.tsx +++ b/packages/zowe-explorer/webviews/edit-attributes/src/App.tsx @@ -15,6 +15,7 @@ import isEqual from "lodash.isequal"; const vscodeApi = acquireVsCodeApi(); export function App() { + const notSupported = "NOT SUPPORTED"; const [readonly, setReadonly] = useState(false); const [allowUpdate, setAllowUpdate] = useState(false); const [attributes, setAttributes] = useState>({ @@ -111,6 +112,7 @@ export function App() { }; return all; }, {}), + tag: attributes.tag ?? notSupported, }; setAttributes({ @@ -155,6 +157,17 @@ export function App() {
{attributes.current.name}
+ {attributes.initial?.directory ?? false ? null : ( +
+ updateFileAttributes("tag", e.target.value)} + > + Tag + +
+ )}
diff --git a/packages/zowe-explorer/webviews/edit-attributes/src/types.ts b/packages/zowe-explorer/webviews/edit-attributes/src/types.ts index f1dba099f4..72efca076a 100644 --- a/packages/zowe-explorer/webviews/edit-attributes/src/types.ts +++ b/packages/zowe-explorer/webviews/edit-attributes/src/types.ts @@ -15,4 +15,5 @@ export type FileAttributes = { directory: boolean; group: string; perms: FilePermissions; + tag?: string; }; From 54f2cc6686b11def8cae19a049dd2977d20ccd0a Mon Sep 17 00:00:00 2001 From: Rudy Flores <68666202+rudyflores@users.noreply.github.com> Date: Wed, 20 Sep 2023 11:27:11 -0400 Subject: [PATCH 016/189] add changelog Signed-off-by: Rudy Flores <68666202+rudyflores@users.noreply.github.com> --- packages/zowe-explorer-api/CHANGELOG.md | 2 ++ packages/zowe-explorer/CHANGELOG.md | 1 + 2 files changed, 3 insertions(+) diff --git a/packages/zowe-explorer-api/CHANGELOG.md b/packages/zowe-explorer-api/CHANGELOG.md index f3d025e88f..5e1d59f8c7 100644 --- a/packages/zowe-explorer-api/CHANGELOG.md +++ b/packages/zowe-explorer-api/CHANGELOG.md @@ -6,6 +6,8 @@ All notable changes to the "zowe-explorer-api" extension will be documented in t ### New features and enhancements +- Added optional `getTag` function to `ZoweExplorerAPI.IUss` for getting the tag of a file on USS. + ### Bug fixes ## `2.11.0` diff --git a/packages/zowe-explorer/CHANGELOG.md b/packages/zowe-explorer/CHANGELOG.md index d6550315ec..6a0f73f34d 100644 --- a/packages/zowe-explorer/CHANGELOG.md +++ b/packages/zowe-explorer/CHANGELOG.md @@ -7,6 +7,7 @@ All notable changes to the "vscode-extension-for-zowe" extension will be documen ### New features and enhancements - Added "Sort Jobs" feature for job nodes in Jobs tree view. [#2257](https://github.com/zowe/vscode-extension-for-zowe/issues/2251) +- Added new edit feature on `Edit Attributes` view for changing file tags on USS [#2113](https://github.com/zowe/vscode-extension-for-zowe/issues/2113) ### Bug fixes From 8bc51c8410e1a527b761285c90aead8e386a4f25 Mon Sep 17 00:00:00 2001 From: Rudy Flores <68666202+rudyflores@users.noreply.github.com> Date: Wed, 20 Sep 2023 11:31:51 -0400 Subject: [PATCH 017/189] update codeql config to check coverage on webviews code Signed-off-by: Rudy Flores <68666202+rudyflores@users.noreply.github.com> --- .github/resources/codeql-config.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/resources/codeql-config.yml b/.github/resources/codeql-config.yml index c6087ff119..49da1ed460 100644 --- a/.github/resources/codeql-config.yml +++ b/.github/resources/codeql-config.yml @@ -5,5 +5,6 @@ queries: paths: - packages + - packages/zowe-explorer/webviews paths-ignore: - node_modules From d5754baa69c4f0df28e3a8a2f1013120abd30f39 Mon Sep 17 00:00:00 2001 From: Rudy Flores <68666202+rudyflores@users.noreply.github.com> Date: Wed, 20 Sep 2023 11:39:42 -0400 Subject: [PATCH 018/189] Revert "update codeql config to check coverage on webviews code" This reverts commit 8bc51c8410e1a527b761285c90aead8e386a4f25. Signed-off-by: Rudy Flores <68666202+rudyflores@users.noreply.github.com> --- .github/resources/codeql-config.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/resources/codeql-config.yml b/.github/resources/codeql-config.yml index 49da1ed460..c6087ff119 100644 --- a/.github/resources/codeql-config.yml +++ b/.github/resources/codeql-config.yml @@ -5,6 +5,5 @@ queries: paths: - packages - - packages/zowe-explorer/webviews paths-ignore: - node_modules From 9478fa219f6d7ccf38d608c7257048b4cecea705 Mon Sep 17 00:00:00 2001 From: Rudy Flores <68666202+rudyflores@users.noreply.github.com> Date: Wed, 20 Sep 2023 12:14:22 -0400 Subject: [PATCH 019/189] add unit test coverage Signed-off-by: Rudy Flores <68666202+rudyflores@users.noreply.github.com> --- .../api/ZoweExplorerZosmfApi.unit.test.ts | 27 +++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/packages/zowe-explorer/__tests__/__unit__/api/ZoweExplorerZosmfApi.unit.test.ts b/packages/zowe-explorer/__tests__/__unit__/api/ZoweExplorerZosmfApi.unit.test.ts index 21fdff381b..40449b9978 100644 --- a/packages/zowe-explorer/__tests__/__unit__/api/ZoweExplorerZosmfApi.unit.test.ts +++ b/packages/zowe-explorer/__tests__/__unit__/api/ZoweExplorerZosmfApi.unit.test.ts @@ -120,4 +120,31 @@ describe("Zosmf API tests", () => { Promise.resolve(zowe.Download.ussFile(api.getSession(), "/some/input/path", {})) ); }); + + it("should update the tag attribute of a USS file if a new change is made", async () => { + const api = new ZosmfUssApi(); + const changeTagSpy = jest.fn(); + Object.defineProperty(zowe, "Utilities", { + value: { + putUSSPayload: changeTagSpy, + }, + configurable: true, + }); + await expect(api.updateAttributes("/test/path", { tag: "utf-8" })).resolves.not.toThrow(); + expect(changeTagSpy).toBeCalledTimes(1); + }); + + it("should get the tag of a file successfully", async () => { + const api = new ZosmfUssApi(); + jest.spyOn(JSON, "parse").mockReturnValue({ + stdout: ["-t UTF-8 tesfile.txt"], + }); + Object.defineProperty(zowe, "Utilities", { + value: { + putUSSPayload: () => Buffer.from(""), + }, + configurable: true, + }); + await expect(api.getTag("testfile.txt")).resolves.toEqual("UTF-8"); + }); }); From a3297aa9df5b3bd9a4b184d09664c33ad80c9125 Mon Sep 17 00:00:00 2001 From: Rudy Flores <68666202+rudyflores@users.noreply.github.com> Date: Wed, 20 Sep 2023 14:57:18 -0400 Subject: [PATCH 020/189] fix broken test and clean up code Signed-off-by: Rudy Flores <68666202+rudyflores@users.noreply.github.com> --- .../src/profiles/ZoweExplorerZosmfApi.ts | 14 +++++--------- .../__unit__/uss/AttributeView.unit.test.ts | 16 ++++++++++------ 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/packages/zowe-explorer-api/src/profiles/ZoweExplorerZosmfApi.ts b/packages/zowe-explorer-api/src/profiles/ZoweExplorerZosmfApi.ts index 554515929a..1075472f49 100644 --- a/packages/zowe-explorer-api/src/profiles/ZoweExplorerZosmfApi.ts +++ b/packages/zowe-explorer-api/src/profiles/ZoweExplorerZosmfApi.ts @@ -214,15 +214,11 @@ export class ZosmfUssApi extends ZosmfApiCommon implements ZoweExplorerApi.IUss } public async getTag(ussPath: string): Promise { - const result = JSON.parse( - Buffer.from( - await zowe.Utilities.putUSSPayload(this.getSession(), ussPath, { - request: "chtag", - action: "list", - }) - ).toString() - ); - return result.stdout[0].split(" ")[1] as string; + const response = await zowe.Utilities.putUSSPayload(this.getSession(), ussPath, { + request: "chtag", + action: "list", + }); + return JSON.parse(response.toString()).stdout[0].split(" ")[1] as string; } } diff --git a/packages/zowe-explorer/__tests__/__unit__/uss/AttributeView.unit.test.ts b/packages/zowe-explorer/__tests__/__unit__/uss/AttributeView.unit.test.ts index ce554ede95..d26119d6d1 100644 --- a/packages/zowe-explorer/__tests__/__unit__/uss/AttributeView.unit.test.ts +++ b/packages/zowe-explorer/__tests__/__unit__/uss/AttributeView.unit.test.ts @@ -13,6 +13,7 @@ import { ExtensionContext } from "vscode"; import { AttributeView } from "../../../src/uss/AttributeView"; import { IZoweTree, IZoweUSSTreeNode, ZoweExplorerApi } from "@zowe/zowe-explorer-api"; import { ZoweExplorerApiRegister } from "../../../src/ZoweExplorerApiRegister"; +import * as contextually from "../../../src/shared/context"; describe("AttributeView unit tests", () => { let view: AttributeView; @@ -21,6 +22,7 @@ describe("AttributeView unit tests", () => { const node = { attributes: { perms: "----------", + tag: undefined, }, label: "example node", fullPath: "/z/some/path", @@ -33,7 +35,9 @@ describe("AttributeView unit tests", () => { beforeAll(() => { jest.spyOn(ZoweExplorerApiRegister, "getUssApi").mockReturnValue({ updateAttributes: updateAttributesMock, + getTag: () => Promise.resolve("UTF-8"), } as unknown as ZoweExplorerApi.IUss); + jest.spyOn(contextually, "isUssDirectory").mockReturnValue(false); view = new AttributeView(context, treeProvider, node); }); @@ -41,21 +45,21 @@ describe("AttributeView unit tests", () => { node.onUpdate = jest.fn(); }); - it("refreshes properly when webview sends 'refresh' command", () => { + it("refreshes properly when webview sends 'refresh' command", async () => { // case 1: node is a root node - (view as any).onDidReceiveMessage({ command: "refresh" }); + await (view as any).onDidReceiveMessage({ command: "refresh" }); expect(treeProvider.refresh).toHaveBeenCalled(); // case 2: node is a child node node.getParent = jest.fn().mockReturnValueOnce({ label: "parent node" } as IZoweUSSTreeNode); - (view as any).onDidReceiveMessage({ command: "refresh" }); + await (view as any).onDidReceiveMessage({ command: "refresh" }); expect(treeProvider.refreshElement).toHaveBeenCalled(); expect(node.onUpdate).toHaveBeenCalledTimes(2); }); - it("dispatches node data to webview when 'ready' command is received", () => { - (view as any).onDidReceiveMessage({ command: "ready" }); + it("dispatches node data to webview when 'ready' command is received", async () => { + await (view as any).onDidReceiveMessage({ command: "ready" }); expect(view.panel.webview.postMessage).toHaveBeenCalledWith({ attributes: node.attributes, name: node.fullPath, @@ -65,7 +69,7 @@ describe("AttributeView unit tests", () => { it("updates attributes when 'update-attributes' command is received", async () => { // case 1: no attributes provided from webview (sanity check) - (view as any).onDidReceiveMessage({ command: "update-attributes" }); + await (view as any).onDidReceiveMessage({ command: "update-attributes" }); expect(updateAttributesMock).not.toHaveBeenCalled(); const attributes = { From aa68168969551065b801c5f66a234c59f68c654a Mon Sep 17 00:00:00 2001 From: Rudy Flores <68666202+rudyflores@users.noreply.github.com> Date: Wed, 20 Sep 2023 15:26:49 -0400 Subject: [PATCH 021/189] add coverage on API package side Signed-off-by: Rudy Flores <68666202+rudyflores@users.noreply.github.com> --- .../ZoweExplorerZosmfApi.unit.test.ts | 24 +++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/packages/zowe-explorer-api/__tests__/__unit__/profiles/ZoweExplorerZosmfApi.unit.test.ts b/packages/zowe-explorer-api/__tests__/__unit__/profiles/ZoweExplorerZosmfApi.unit.test.ts index ab4e76d44d..f700d6df52 100644 --- a/packages/zowe-explorer-api/__tests__/__unit__/profiles/ZoweExplorerZosmfApi.unit.test.ts +++ b/packages/zowe-explorer-api/__tests__/__unit__/profiles/ZoweExplorerZosmfApi.unit.test.ts @@ -260,6 +260,30 @@ describe("ZosmfUssApi", () => { expect(logoutSpy).toHaveBeenCalledWith(fakeSession); }); + it("should retrieve the tag of a file", async () => { + const zosmfApi = new ZosmfUssApi(); + jest.spyOn(JSON, "parse").mockReturnValue({ + stdout: ["-t UTF-8 tesfile.txt"], + }); + + Object.defineProperty(zowe.Utilities, "putUSSPayload", { + value: () => Buffer.from(""), + configurable: true, + }); + await expect(zosmfApi.getTag("testfile.txt")).resolves.toEqual("UTF-8"); + }); + + it("should update the tag attribute when passed in", async () => { + const zosmfApi = new ZosmfUssApi(); + const changeTagSpy = jest.fn(); + Object.defineProperty(zowe.Utilities, "putUSSPayload", { + value: changeTagSpy, + configurable: true, + }); + await expect(zosmfApi.updateAttributes("/test/path", { tag: "utf-8" })).resolves.not.toThrow(); + expect(changeTagSpy).toBeCalledTimes(1); + }); + const ussApis: ITestApi[] = [ { name: "isFileTagBinOrAscii", From 2964340a83fdd78d74946cec51850c7f41ec772a Mon Sep 17 00:00:00 2001 From: Likhitha Nimma Date: Thu, 21 Sep 2023 15:10:40 +0530 Subject: [PATCH 022/189] Implemented getting metadata for profiletypes Signed-off-by: Likhitha Nimma --- .../profiles/ProfilesCache.unit.test.ts | 24 +++++++++++++++++++ .../src/profiles/ProfilesCache.ts | 11 +++++++++ packages/zowe-explorer/CHANGELOG.md | 1 + .../ZoweExplorerExtender.unit.test.ts | 5 +++- packages/zowe-explorer/src/Profiles.ts | 6 +++-- .../zowe-explorer/src/ZoweExplorerExtender.ts | 6 ++--- 6 files changed, 46 insertions(+), 7 deletions(-) diff --git a/packages/zowe-explorer-api/__tests__/__unit__/profiles/ProfilesCache.unit.test.ts b/packages/zowe-explorer-api/__tests__/__unit__/profiles/ProfilesCache.unit.test.ts index fa0d6393ef..a1fe151594 100644 --- a/packages/zowe-explorer-api/__tests__/__unit__/profiles/ProfilesCache.unit.test.ts +++ b/packages/zowe-explorer-api/__tests__/__unit__/profiles/ProfilesCache.unit.test.ts @@ -85,6 +85,17 @@ const baseProfileWithToken = { tokenValue: "baseToken", }, }; +const profilemetadata: zowe.imperative.ICommandProfileTypeConfiguration[] = [ + { + type: "rse", + schema: { + type: "object", + title: "IBM RSE API Zowe Profile", + description: "A profile to issue commands to z/OS system", + properties: {}, + }, + }, +]; function createProfInfoMock(profiles: Partial[]): zowe.imperative.ProfileInfo { return { @@ -153,6 +164,19 @@ describe("ProfilesCache", () => { expect(Object.keys(keyring).length).toBe(5); }); + it("setConfigArray should set the profileTypeConfigurations array", () => { + const profCache = new ProfilesCache(fakeLogger as unknown as zowe.imperative.Logger); + profCache.setConfigArray(profilemetadata); + expect(profCache.profileTypeConfigurations).toEqual(profilemetadata); + }); + + it("getConfigArray should return the data of profileTypeConfigurations Array", () => { + const profCache = new ProfilesCache(fakeLogger as unknown as zowe.imperative.Logger); + profCache.profileTypeConfigurations = profilemetadata; + const res = profCache.getConfigArray(); + expect(res).toEqual(profilemetadata); + }); + it("loadNamedProfile should find profiles by name and type", () => { const profCache = new ProfilesCache(fakeLogger as unknown as zowe.imperative.Logger); profCache.allProfiles = [lpar1Profile as zowe.imperative.IProfileLoaded, zftpProfile as zowe.imperative.IProfileLoaded]; diff --git a/packages/zowe-explorer-api/src/profiles/ProfilesCache.ts b/packages/zowe-explorer-api/src/profiles/ProfilesCache.ts index 4272a59edd..daa0e67cbc 100644 --- a/packages/zowe-explorer-api/src/profiles/ProfilesCache.ts +++ b/packages/zowe-explorer-api/src/profiles/ProfilesCache.ts @@ -69,6 +69,7 @@ export class ProfilesCache { public profilesForValidation: IProfileValidation[] = []; public profilesValidationSetting: IValidationSetting[] = []; public allProfiles: zowe.imperative.IProfileLoaded[] = []; + public profileTypeConfigurations: zowe.imperative.ICommandProfileTypeConfiguration[] = []; protected allTypes: string[]; protected allExternalTypes = new Set(); protected profilesByType = new Map(); @@ -83,6 +84,16 @@ export class ProfilesCache { return require("@zowe/secrets-for-zowe-sdk").keyring; } + public setConfigArray(extendermetadata: zowe.imperative.ICommandProfileTypeConfiguration[]): void { + extendermetadata?.forEach((item) => { + this.profileTypeConfigurations.push(item); + }); + } + + public getConfigArray(): zowe.imperative.ICommandProfileTypeConfiguration[] { + return this.profileTypeConfigurations; + } + public async getProfileInfo(_envTheia = false): Promise { const mProfileInfo = new zowe.imperative.ProfileInfo("zowe", { // eslint-disable-next-line @typescript-eslint/no-unsafe-return diff --git a/packages/zowe-explorer/CHANGELOG.md b/packages/zowe-explorer/CHANGELOG.md index 5f57f98006..71448c349b 100644 --- a/packages/zowe-explorer/CHANGELOG.md +++ b/packages/zowe-explorer/CHANGELOG.md @@ -9,6 +9,7 @@ All notable changes to the "vscode-extension-for-zowe" extension will be documen ### Bug fixes - Fixed submitting local JCL using command pallet option `Zowe Explorer: Submit JCL` by adding a check for chosen profile returned to continue the action. [#1625](https://github.com/zowe/vscode-extension-for-zowe/issues/1625) +- Fixed the issue of getting the meta data of profile types for creating the config files by adding the setters and getters in the zowe-explorer-api. [#2394](https://github.com/zowe/vscode-extension-for-zowe/issues/2394) ## `2.11.0` diff --git a/packages/zowe-explorer/__tests__/__unit__/ZoweExplorerExtender.unit.test.ts b/packages/zowe-explorer/__tests__/__unit__/ZoweExplorerExtender.unit.test.ts index 6ae337f750..30b4716f93 100644 --- a/packages/zowe-explorer/__tests__/__unit__/ZoweExplorerExtender.unit.test.ts +++ b/packages/zowe-explorer/__tests__/__unit__/ZoweExplorerExtender.unit.test.ts @@ -78,7 +78,10 @@ describe("ZoweExplorerExtender unit tests", () => { value: jest.fn(), configurable: true, }); - + Object.defineProperty(Profiles.getInstance(), "setConfigArray", { + value: jest.fn(), + configurable: true, + }); return newMocks; } diff --git a/packages/zowe-explorer/src/Profiles.ts b/packages/zowe-explorer/src/Profiles.ts index 1cdf3bd059..29820ac9b0 100644 --- a/packages/zowe-explorer/src/Profiles.ts +++ b/packages/zowe-explorer/src/Profiles.ts @@ -643,10 +643,12 @@ export class Profiles extends ProfilesCache { const impConfig: zowe.imperative.IImperativeConfig = zowe.getImperativeConfig(); const knownCliConfig: zowe.imperative.ICommandProfileTypeConfiguration[] = impConfig.profiles; - // add extenders config info from global variable - globals.EXTENDER_CONFIG.forEach((item) => { + + const extenderinfo = this.getConfigArray(); + extenderinfo.forEach((item) => { knownCliConfig.push(item); }); + knownCliConfig.push(impConfig.baseProfile); config.setSchema(zowe.imperative.ConfigSchema.buildSchema(knownCliConfig)); diff --git a/packages/zowe-explorer/src/ZoweExplorerExtender.ts b/packages/zowe-explorer/src/ZoweExplorerExtender.ts index d6b68885b3..924596421b 100644 --- a/packages/zowe-explorer/src/ZoweExplorerExtender.ts +++ b/packages/zowe-explorer/src/ZoweExplorerExtender.ts @@ -191,10 +191,8 @@ export class ZoweExplorerExtender implements ZoweExplorerApi.IApiExplorerExtende }); } } - // add extender config info to global variable - profileTypeConfigurations?.forEach((item) => { - globals.EXTENDER_CONFIG.push(item); - }); + Profiles.getInstance().setConfigArray(profileTypeConfigurations); + // sequentially reload the internal profiles cache to satisfy all the newly added profile types await ZoweExplorerExtender.refreshProfilesQueue.add(async (): Promise => { await Profiles.getInstance().refresh(ZoweExplorerApiRegister.getInstance()); From ea8fd30745b28b65a827dc5005fd1a3b8ab101f2 Mon Sep 17 00:00:00 2001 From: Billie Simmons <49491949+JillieBeanSim@users.noreply.github.com> Date: Thu, 21 Sep 2023 09:29:58 -0400 Subject: [PATCH 023/189] initial work for profile management Signed-off-by: Billie Simmons <49491949+JillieBeanSim@users.noreply.github.com> --- .../__unit__/Profiles.extended.unit.test.ts | 2 +- .../__unit__/utils/ProfilesUtils.unit.test.ts | 2 +- .../i18n/sample/package.i18n.json | 7 +- .../sample/src/utils/ProfilesUtils.i18n.json | 11 ++ packages/zowe-explorer/package.nls.json | 2 +- packages/zowe-explorer/src/Profiles.ts | 4 +- packages/zowe-explorer/src/shared/init.ts | 2 +- .../zowe-explorer/src/utils/ProfilesUtils.ts | 148 ++++++++++++++++-- 8 files changed, 156 insertions(+), 22 deletions(-) diff --git a/packages/zowe-explorer/__tests__/__unit__/Profiles.extended.unit.test.ts b/packages/zowe-explorer/__tests__/__unit__/Profiles.extended.unit.test.ts index 2876032d7b..ebe3b57fe3 100644 --- a/packages/zowe-explorer/__tests__/__unit__/Profiles.extended.unit.test.ts +++ b/packages/zowe-explorer/__tests__/__unit__/Profiles.extended.unit.test.ts @@ -1376,7 +1376,7 @@ describe("Profiles Unit Tests - function checkCurrentProfile", () => { it("should throw an error if using token auth and is logged out or has expired token", async () => { const globalMocks = await createGlobalMocks(); jest.spyOn(utils, "errorHandling").mockImplementation(); - jest.spyOn(utils, "isUsingTokenAuth").mockResolvedValue(true); + jest.spyOn(utils.ProfilesUtils, "isUsingTokenAuth").mockResolvedValue(true); setupProfilesCheck(globalMocks); await expect(Profiles.getInstance().checkCurrentProfile(globalMocks.testProfile)).resolves.toEqual({ name: "sestest", status: "unverified" }); }); diff --git a/packages/zowe-explorer/__tests__/__unit__/utils/ProfilesUtils.unit.test.ts b/packages/zowe-explorer/__tests__/__unit__/utils/ProfilesUtils.unit.test.ts index 65a2121ff8..74cdb85a8a 100644 --- a/packages/zowe-explorer/__tests__/__unit__/utils/ProfilesUtils.unit.test.ts +++ b/packages/zowe-explorer/__tests__/__unit__/utils/ProfilesUtils.unit.test.ts @@ -743,7 +743,7 @@ describe("ProfilesUtils unit tests", () => { jest.spyOn(Profiles.getInstance(), "getDefaultProfile").mockReturnValueOnce({} as any); jest.spyOn(Profiles.getInstance(), "getLoadedProfConfig").mockResolvedValue({ type: "test" } as any); jest.spyOn(Profiles.getInstance(), "getSecurePropsForProfile").mockResolvedValue([]); - await expect(profUtils.isUsingTokenAuth("test")).resolves.toEqual(false); + await expect(profUtils.ProfilesUtils.isUsingTokenAuth("test")).resolves.toEqual(false); }); }); }); diff --git a/packages/zowe-explorer/i18n/sample/package.i18n.json b/packages/zowe-explorer/i18n/sample/package.i18n.json index 5930969b05..5caa899119 100644 --- a/packages/zowe-explorer/i18n/sample/package.i18n.json +++ b/packages/zowe-explorer/i18n/sample/package.i18n.json @@ -2,7 +2,7 @@ "displayName": "Zowe Explorer", "description": "VS Code extension, powered by Zowe CLI, that streamlines interaction with mainframe data sets, USS files, and jobs", "viewsContainers.activitybar": "Zowe Explorer", - "zowe.promptCredentials": "Update Credentials", + "zowe.promptCredentials": "Manage Profile", "zowe.extRefresh": "Refresh Zowe Explorer", "zowe.ds.explorer": "Data Sets", "zowe.uss.explorer": "Unix System Services (USS)", @@ -146,5 +146,8 @@ "createZoweSchema.reload.button": "Reload Window", "createZoweSchema.reload.infoMessage": "Team Configuration file created. Location: {0}. \n Please reload your window.", "copyFile": "Copy", - "pasteFile": "Paste" + "pasteFile": "Paste", + "jobs.sortbyreturncode": "Sort by ReturnCode", + "jobs.sortbyname": "Sort by Name", + "jobs.sortbyid": "Sort by ID" } diff --git a/packages/zowe-explorer/i18n/sample/src/utils/ProfilesUtils.i18n.json b/packages/zowe-explorer/i18n/sample/src/utils/ProfilesUtils.i18n.json index 2ed2cbc4ff..80ab2e3c84 100644 --- a/packages/zowe-explorer/i18n/sample/src/utils/ProfilesUtils.i18n.json +++ b/packages/zowe-explorer/i18n/sample/src/utils/ProfilesUtils.i18n.json @@ -21,5 +21,16 @@ "initializeZoweFolder.error": "Failed to initialize Zowe folder: {0}", "initializeZoweProfiles.success": "Zowe Profiles initialized successfully.", "initializeZoweTempFolder.success": "Zowe Temp folder initialized successfully.", + "profiles.operation.cancelled": "Operation Cancelled", + "editProfileQpItem.editProfile.qpLabel": "Edit profile", + "editProfileQpItem.editProfile.qpDetail": "Update profile information including authentication method", + "updateBasicAuthQpItem.updateCredentials.qpLabel": "Update Credentials", + "updateBasicAuthQpItem.updateCredentials.qpDetail": "Update stored username and password", + "loginQpItem.login.qpLabel": "Login to authentication service", + "loginQpItem.login.qpDetail": "Login to obtain and update stored token value", + "logoutQpItem.logout.qpLabel": "Log out of authentication service", + "logoutQpItem.logout.qpDetail": "Log out to invalidate and remove stored token value", + "qpPlaceholders.qp.basic": "Profile is using basic authentication. Choose a profile action.", + "qpPlaceholders.qp.token": "Profile is using token authentication. Choose a profile action.", "getProfile.notTreeItem": "Tree Item is not a Zowe Explorer item." } diff --git a/packages/zowe-explorer/package.nls.json b/packages/zowe-explorer/package.nls.json index 8bc5d8bf6c..5caa899119 100644 --- a/packages/zowe-explorer/package.nls.json +++ b/packages/zowe-explorer/package.nls.json @@ -2,7 +2,7 @@ "displayName": "Zowe Explorer", "description": "VS Code extension, powered by Zowe CLI, that streamlines interaction with mainframe data sets, USS files, and jobs", "viewsContainers.activitybar": "Zowe Explorer", - "zowe.promptCredentials": "Update Credentials", + "zowe.promptCredentials": "Manage Profile", "zowe.extRefresh": "Refresh Zowe Explorer", "zowe.ds.explorer": "Data Sets", "zowe.uss.explorer": "Unix System Services (USS)", diff --git a/packages/zowe-explorer/src/Profiles.ts b/packages/zowe-explorer/src/Profiles.ts index 1cdf3bd059..47a70a00e4 100644 --- a/packages/zowe-explorer/src/Profiles.ts +++ b/packages/zowe-explorer/src/Profiles.ts @@ -30,7 +30,7 @@ import { getFullPath, getZoweDir, } from "@zowe/zowe-explorer-api"; -import { errorHandling, FilterDescriptor, FilterItem, ProfilesUtils, isUsingTokenAuth } from "./utils/ProfilesUtils"; +import { errorHandling, FilterDescriptor, FilterItem, ProfilesUtils } from "./utils/ProfilesUtils"; import { ZoweExplorerApiRegister } from "./ZoweExplorerApiRegister"; import { ZoweExplorerExtender } from "./ZoweExplorerExtender"; import * as globals from "./globals"; @@ -88,7 +88,7 @@ export class Profiles extends ProfilesCache { public async checkCurrentProfile(theProfile: zowe.imperative.IProfileLoaded): Promise { ZoweLogger.trace("Profiles.checkCurrentProfile called."); let profileStatus: IProfileValidation; - const usingTokenAuth = await isUsingTokenAuth(theProfile.name); + const usingTokenAuth = await ProfilesUtils.isUsingTokenAuth(theProfile.name); if (usingTokenAuth && !theProfile.profile.tokenType) { const error = new zowe.imperative.ImperativeError({ diff --git a/packages/zowe-explorer/src/shared/init.ts b/packages/zowe-explorer/src/shared/init.ts index d023a1a969..acee163494 100644 --- a/packages/zowe-explorer/src/shared/init.ts +++ b/packages/zowe-explorer/src/shared/init.ts @@ -88,7 +88,7 @@ export function registerCommonCommands(context: vscode.ExtensionContext, provide context.subscriptions.push( vscode.commands.registerCommand("zowe.promptCredentials", async (node: IZoweTreeNode) => { - await ProfilesUtils.promptCredentials(node); + await ProfilesUtils.manageProfile(node); }) ); diff --git a/packages/zowe-explorer/src/utils/ProfilesUtils.ts b/packages/zowe-explorer/src/utils/ProfilesUtils.ts index 612284de16..00b4e40b9c 100644 --- a/packages/zowe-explorer/src/utils/ProfilesUtils.ts +++ b/packages/zowe-explorer/src/utils/ProfilesUtils.ts @@ -75,7 +75,7 @@ export async function errorHandling(errorDetails: Error | string, label?: string if (imperativeError.mDetails.additionalDetails) { const tokenError: string = imperativeError.mDetails.additionalDetails; - const isTokenAuth = await isUsingTokenAuth(label); + const isTokenAuth = await ProfilesUtils.isUsingTokenAuth(label); if (tokenError.includes("Token is not valid or expired.") || isTokenAuth) { if (isTheia()) { @@ -132,19 +132,6 @@ export function isTheia(): boolean { return false; } -/** - * Function that checks whether a profile is using token based authentication - * @param profileName the name of the profile to check - * @returns {Promise} a boolean representing whether token based auth is being used or not - */ -export async function isUsingTokenAuth(profileName: string): Promise { - const baseProfile = Profiles.getInstance().getDefaultProfile("base"); - const secureProfileProps = await Profiles.getInstance().getSecurePropsForProfile(profileName); - const secureBaseProfileProps = await Profiles.getInstance().getSecurePropsForProfile(baseProfile?.name); - const profileUsesBasicAuth = secureProfileProps.includes("user") && secureProfileProps.includes("password"); - return (secureProfileProps.includes("tokenValue") || secureBaseProfileProps.includes("tokenValue")) && !profileUsesBasicAuth; -} - /** * Function to update session and profile information in provided node * @param profiles is data source to find profiles @@ -320,6 +307,50 @@ export class ProfilesUtils { } } + public static async manageProfile(node: IZoweTreeNode): Promise { + const profile = node.getProfile(); + switch (true) { + case this.isProfileUsingBasicAuth(profile): { + await this.basicAuthProfileManagement(node); + break; + } + case await this.isUsingTokenAuth(profile.name): { + Gui.infoMessage("profile using token auth."); + break; + } + // will need a case for isUsingCertAuth + default: { + Gui.infoMessage("profile not using stated authentication type."); + break; + } + } + } + + /** + * Function that checks whether a profile is using basic authentication + * @param profile + * @returns {Promise} a boolean representing whether basic auth is being used or not + */ + public static isProfileUsingBasicAuth(profile: imperative.IProfileLoaded): boolean { + if (profile.profile.user && profile.profile.password) { + return true; + } + return false; + } + + /** + * Function that checks whether a profile is using token based authentication + * @param profileName the name of the profile to check + * @returns {Promise} a boolean representing whether token based auth is being used or not + */ + public static async isUsingTokenAuth(profileName: string): Promise { + const baseProfile = Profiles.getInstance().getDefaultProfile("base"); + const secureProfileProps = await Profiles.getInstance().getSecurePropsForProfile(profileName); + const secureBaseProfileProps = await Profiles.getInstance().getSecurePropsForProfile(baseProfile?.name); + const profileUsesBasicAuth = secureProfileProps.includes("user") && secureProfileProps.includes("password"); + return (secureProfileProps.includes("tokenValue") || secureBaseProfileProps.includes("tokenValue")) && !profileUsesBasicAuth; + } + public static async promptCredentials(node: IZoweTreeNode): Promise { ZoweLogger.trace("ProfilesUtils.promptCredentials called."); const mProfileInfo = await Profiles.getInstance().getProfileInfo(); @@ -479,6 +510,95 @@ export class ProfilesUtils { Gui.errorMessage(err.message); } } + + private static AuthQpLabels = { + update: "update-credentials", + edit: "edit-profile", + login: "obtain-token", + logout: "invalidate-token", + }; + private static editProfileQpItem: Record = { + [this.AuthQpLabels.edit]: { + label: localize("editProfileQpItem.editProfile.qpLabel", "Edit profile"), + detail: localize("editProfileQpItem.editProfile.qpDetail", "Update profile information including authentication method"), + }, + }; + private static updateBasicAuthQpItem: Record = { + [this.AuthQpLabels.update]: { + label: localize("updateBasicAuthQpItem.updateCredentials.qpLabel", "Update Credentials"), + detail: localize("updateBasicAuthQpItem.updateCredentials.qpDetail", "Update stored username and password"), + }, + }; + private static loginQpItem: Record = { + [this.AuthQpLabels.login]: { + label: localize("loginQpItem.login.qpLabel", "Login to authentication service"), + detail: localize("loginQpItem.login.qpDetail", "Login to obtain and update stored token value"), + }, + }; + private static logoutQpItem: Record = { + [this.AuthQpLabels.logout]: { + label: localize("logoutQpItem.logout.qpLabel", "Log out of authentication service"), + detail: localize("logoutQpItem.logout.qpDetail", "Log out to invalidate and remove stored token value"), + }, + }; + + private static async basicAuthProfileManagement(node: IZoweTreeNode): Promise { + const profile = node.getProfile(); + const selected = await this.setupProfileManagementQp(imperative.SessConstants.AUTH_TYPE_BASIC, profile.name); + switch (selected) { + case this.updateBasicAuthQpItem[this.AuthQpLabels.update]: { + await this.promptCredentials(node); + break; + } + case this.editProfileQpItem[this.AuthQpLabels.edit]: { + await Profiles.getInstance().editSession(profile, profile.name); + break; + } + default: { + Gui.infoMessage(localize("profiles.operation.cancelled", "Operation Cancelled")); + break; + } + } + } + private static async setupProfileManagementQp(managementType: string, profileName: string): Promise { + const qp = Gui.createQuickPick(); + let quickPickOptions: vscode.QuickPickItem[]; + switch (managementType) { + case imperative.SessConstants.AUTH_TYPE_BASIC: { + quickPickOptions = this.basicAuthQp(); + qp.placeholder = this.qpPlaceholders.basicAuth; + break; + } + case "token": { + quickPickOptions = this.tokenAuthQp(); + qp.placeholder = this.qpPlaceholders.tokenAuth; + break; + } + } + let selectedItem = quickPickOptions[0]; + qp.items = quickPickOptions; + qp.activeItems = [selectedItem]; + qp.show(); + selectedItem = await Gui.resolveQuickPick(qp); + qp.hide(); + return selectedItem; + } + + private static qpPlaceholders = { + basicAuth: localize("qpPlaceholders.qp.basic", "Profile is using basic authentication. Choose a profile action."), + tokenAuth: localize("qpPlaceholders.qp.token", "Profile is using token authentication. Choose a profile action."), + }; + + private static basicAuthQp(): vscode.QuickPickItem[] { + const quickPickOptions: vscode.QuickPickItem[] = Object.values(this.updateBasicAuthQpItem); + quickPickOptions.push(this.editProfileQpItem[this.AuthQpLabels.edit]); + return quickPickOptions; + } + private static tokenAuthQp(): vscode.QuickPickItem[] { + const quickPickOptions: vscode.QuickPickItem[] = Object.values(this.loginQpItem); + quickPickOptions.push(this.editProfileQpItem[this.AuthQpLabels.edit]); + return quickPickOptions; + } } /** From 82c19742811a3600823364f87cdd56c55b8bbc46 Mon Sep 17 00:00:00 2001 From: Billie Simmons <49491949+JillieBeanSim@users.noreply.github.com> Date: Thu, 21 Sep 2023 09:42:48 -0400 Subject: [PATCH 024/189] add token auth part Signed-off-by: Billie Simmons <49491949+JillieBeanSim@users.noreply.github.com> --- .../zowe-explorer/src/utils/ProfilesUtils.ts | 35 ++++++++++++++++--- 1 file changed, 30 insertions(+), 5 deletions(-) diff --git a/packages/zowe-explorer/src/utils/ProfilesUtils.ts b/packages/zowe-explorer/src/utils/ProfilesUtils.ts index 00b4e40b9c..d57d43e9a4 100644 --- a/packages/zowe-explorer/src/utils/ProfilesUtils.ts +++ b/packages/zowe-explorer/src/utils/ProfilesUtils.ts @@ -315,7 +315,7 @@ export class ProfilesUtils { break; } case await this.isUsingTokenAuth(profile.name): { - Gui.infoMessage("profile using token auth."); + await this.tokenAuthProfileManagement(node); break; } // will need a case for isUsingCertAuth @@ -544,7 +544,7 @@ export class ProfilesUtils { private static async basicAuthProfileManagement(node: IZoweTreeNode): Promise { const profile = node.getProfile(); - const selected = await this.setupProfileManagementQp(imperative.SessConstants.AUTH_TYPE_BASIC, profile.name); + const selected = await this.setupProfileManagementQp(imperative.SessConstants.AUTH_TYPE_BASIC, profile); switch (selected) { case this.updateBasicAuthQpItem[this.AuthQpLabels.update]: { await this.promptCredentials(node); @@ -560,7 +560,29 @@ export class ProfilesUtils { } } } - private static async setupProfileManagementQp(managementType: string, profileName: string): Promise { + private static async tokenAuthProfileManagement(node: IZoweTreeNode): Promise { + const profile = node.getProfile(); + const selected = await this.setupProfileManagementQp("token", profile); + switch (selected) { + case this.loginQpItem[this.AuthQpLabels.login]: { + await Profiles.getInstance().ssoLogin(node, profile.name); + break; + } + case this.editProfileQpItem[this.AuthQpLabels.edit]: { + await Profiles.getInstance().editSession(profile, profile.name); + break; + } + case this.logoutQpItem[this.AuthQpLabels.logout]: { + await Profiles.getInstance().ssoLogout(node); + break; + } + default: { + Gui.infoMessage(localize("profiles.operation.cancelled", "Operation Cancelled")); + break; + } + } + } + private static async setupProfileManagementQp(managementType: string, profile: imperative.IProfileLoaded): Promise { const qp = Gui.createQuickPick(); let quickPickOptions: vscode.QuickPickItem[]; switch (managementType) { @@ -570,7 +592,7 @@ export class ProfilesUtils { break; } case "token": { - quickPickOptions = this.tokenAuthQp(); + quickPickOptions = this.tokenAuthQp(profile); qp.placeholder = this.qpPlaceholders.tokenAuth; break; } @@ -594,9 +616,12 @@ export class ProfilesUtils { quickPickOptions.push(this.editProfileQpItem[this.AuthQpLabels.edit]); return quickPickOptions; } - private static tokenAuthQp(): vscode.QuickPickItem[] { + private static tokenAuthQp(profile: imperative.IProfileLoaded): vscode.QuickPickItem[] { const quickPickOptions: vscode.QuickPickItem[] = Object.values(this.loginQpItem); quickPickOptions.push(this.editProfileQpItem[this.AuthQpLabels.edit]); + if (profile.profile.tokenType) { + quickPickOptions.push(this.logoutQpItem[this.AuthQpLabels.logout]); + } return quickPickOptions; } } From 723e3756906ff8a94cf5aac391ad150550f56621 Mon Sep 17 00:00:00 2001 From: Billie Simmons <49491949+JillieBeanSim@users.noreply.github.com> Date: Thu, 21 Sep 2023 10:45:10 -0400 Subject: [PATCH 025/189] remove other commands similar to new profile management options Signed-off-by: Billie Simmons <49491949+JillieBeanSim@users.noreply.github.com> --- packages/zowe-explorer/package.json | 108 --------------------- packages/zowe-explorer/package.nls.json | 7 -- packages/zowe-explorer/src/dataset/init.ts | 10 +- packages/zowe-explorer/src/job/init.ts | 10 +- packages/zowe-explorer/src/uss/init.ts | 10 +- 5 files changed, 15 insertions(+), 130 deletions(-) diff --git a/packages/zowe-explorer/package.json b/packages/zowe-explorer/package.json index 527726260b..6eaccb4e0e 100644 --- a/packages/zowe-explorer/package.json +++ b/packages/zowe-explorer/package.json @@ -262,15 +262,6 @@ "dark": "./resources/dark/plus.svg" } }, - { - "command": "zowe.ds.editSession", - "title": "%editSession%", - "category": "Zowe Explorer", - "icon": { - "light": "./resources/light/edit.svg", - "dark": "./resources/dark/edit.svg" - } - }, { "command": "zowe.ds.deleteProfile", "title": "%deleteProfile%", @@ -480,15 +471,6 @@ "dark": "./resources/dark/plus.svg" } }, - { - "command": "zowe.uss.editSession", - "title": "%editSession%", - "category": "Zowe Explorer", - "icon": { - "light": "./resources/light/edit.svg", - "dark": "./resources/dark/edit.svg" - } - }, { "command": "zowe.uss.deleteProfile", "title": "%deleteProfile%", @@ -658,15 +640,6 @@ "dark": "./resources/dark/refresh.svg" } }, - { - "command": "zowe.jobs.editSession", - "title": "%editSession%", - "category": "Zowe Explorer", - "icon": { - "light": "./resources/light/edit.svg", - "dark": "./resources/dark/edit.svg" - } - }, { "command": "zowe.jobs.deleteProfile", "title": "%deleteProfile%", @@ -968,21 +941,6 @@ "command": "zowe.promptCredentials", "group": "098_zowe_ussProfileAuthentication@3" }, - { - "when": "view == zowe.uss.explorer && viewItem =~ /^(?!.*_fav.*)ussSession.*/ && !listMultiSelection", - "command": "zowe.uss.ssoLogin", - "group": "098_zowe_ussProfileAuthentication@4" - }, - { - "when": "view == zowe.uss.explorer && viewItem =~ /^(?!.*_fav.*)ussSession.*/ && !listMultiSelection", - "command": "zowe.uss.ssoLogout", - "group": "098_zowe_ussProfileAuthentication@5" - }, - { - "when": "viewItem =~ /^(?!.*_fav.*)ussSession.*/ && !listMultiSelection", - "command": "zowe.uss.editSession", - "group": "099_zowe_ussProfileModification@1" - }, { "when": "viewItem =~ /^(?!.*_fav.*)ussSession.*/", "command": "zowe.uss.removeSession", @@ -1183,21 +1141,6 @@ "command": "zowe.promptCredentials", "group": "098_zowe_dsProfileAuthentication@8" }, - { - "when": "view == zowe.ds.explorer && viewItem =~ /^(?!.*_fav.*)session.*/ && !listMultiSelection", - "command": "zowe.ds.ssoLogin", - "group": "098_zowe_dsProfileAuthentication@9" - }, - { - "when": "view == zowe.ds.explorer && viewItem =~ /^(?!.*_fav.*)session.*/ && !listMultiSelection", - "command": "zowe.ds.ssoLogout", - "group": "098_zowe_dsProfileAuthentication@10" - }, - { - "when": "view == zowe.ds.explorer && viewItem =~ /^(?!.*_fav.*)session.*/ && !listMultiSelection", - "command": "zowe.ds.editSession", - "group": "099_zowe_dsProfileModification@0" - }, { "when": "view == zowe.ds.explorer && viewItem =~ /^(?!.*_fav.*)session.*/", "command": "zowe.ds.removeSession", @@ -1348,21 +1291,6 @@ "command": "zowe.promptCredentials", "group": "098_zowe_jobsProfileAuthentication@5" }, - { - "when": "view == zowe.jobs.explorer && viewItem =~ /^(?!.*_fav.*)server.*/ && !listMultiSelection", - "command": "zowe.jobs.ssoLogin", - "group": "098_zowe_jobsProfileAuthentication@6" - }, - { - "when": "view == zowe.jobs.explorer && viewItem =~ /^(?!.*_fav.*)server.*/ && !listMultiSelection", - "command": "zowe.jobs.ssoLogout", - "group": "098_zowe_jobsProfileAuthentication@7" - }, - { - "when": "view == zowe.jobs.explorer && viewItem =~ /^(?!.*_fav.*)server.*/ && !listMultiSelection", - "command": "zowe.jobs.editSession", - "group": "099_zowe_jobsProfileModification@0" - }, { "when": "view == zowe.jobs.explorer && viewItem =~ /^(?!.*_fav.*)server.*/", "command": "zowe.jobs.removeJobsSession", @@ -1414,10 +1342,6 @@ "command": "zowe.ds.showAttributes", "when": "never" }, - { - "command": "zowe.ds.editSession", - "when": "never" - }, { "command": "zowe.ds.createMember", "when": "never" @@ -1510,30 +1434,6 @@ "command": "zowe.jobs.enableValidation", "when": "never" }, - { - "command": "zowe.ds.ssoLogin", - "when": "never" - }, - { - "command": "zowe.ds.ssoLogout", - "when": "never" - }, - { - "command": "zowe.uss.ssoLogin", - "when": "never" - }, - { - "command": "zowe.uss.ssoLogout", - "when": "never" - }, - { - "command": "zowe.jobs.ssoLogin", - "when": "never" - }, - { - "command": "zowe.jobs.ssoLogout", - "when": "never" - }, { "command": "zowe.ds.saveSearch", "when": "never" @@ -1610,10 +1510,6 @@ "command": "zowe.uss.saveSearch", "when": "never" }, - { - "command": "zowe.uss.editSession", - "when": "never" - }, { "command": "zowe.uss.deleteProfile", "when": "never" @@ -1698,10 +1594,6 @@ "command": "zowe.jobs.downloadSpoolBinary", "when": "never" }, - { - "command": "zowe.jobs.editSession", - "when": "never" - }, { "command": "zowe.jobs.removeJobsSession", "when": "never" diff --git a/packages/zowe-explorer/package.nls.json b/packages/zowe-explorer/package.nls.json index 5caa899119..dd0efbc93d 100644 --- a/packages/zowe-explorer/package.nls.json +++ b/packages/zowe-explorer/package.nls.json @@ -15,7 +15,6 @@ "removeFavProfile": "Remove profile from Favorites", "uss.addFavorite": "Add to Favorites", "addSession": "Add Profile to Data Sets View", - "editSession": "Update Profile", "createDataset": "Create New Data Set", "createMember": "Create New Member", "showAttributes": "Show Attributes", @@ -130,12 +129,6 @@ "enableValidation": "Enable Validation for Profile", "uss.enableValidation": "Enable Validation for Profile", "jobs.enableValidation": "Enable Validation for Profile", - "ssoLogin": "Log in to Authentication Service", - "uss.ssoLogin": "Log in to Authentication Service", - "jobs.ssoLogin": "Log in to Authentication Service", - "ssoLogout": "Log out from Authentication Service", - "uss.ssoLogout": "Log out from Authentication Service", - "jobs.ssoLogout": "Log out from Authentication Service", "jobs.refreshJob": "Refresh Job", "jobs.refreshSpool": "Pull from Mainframe", "manualPoll": "Poll Content in Active Editor", diff --git a/packages/zowe-explorer/src/dataset/init.ts b/packages/zowe-explorer/src/dataset/init.ts index 12e81d74eb..f43b4e4a77 100644 --- a/packages/zowe-explorer/src/dataset/init.ts +++ b/packages/zowe-explorer/src/dataset/init.ts @@ -68,9 +68,9 @@ export async function initDatasetProvider(context: vscode.ExtensionContext): Pro }) ); context.subscriptions.push(vscode.commands.registerCommand("zowe.ds.pattern", (node): void => datasetProvider.filterPrompt(node))); - context.subscriptions.push( - vscode.commands.registerCommand("zowe.ds.editSession", async (node) => datasetProvider.editSession(node, datasetProvider)) - ); + // context.subscriptions.push( + // vscode.commands.registerCommand("zowe.ds.editSession", async (node) => datasetProvider.editSession(node, datasetProvider)) + // ); context.subscriptions.push( vscode.commands.registerCommand("zowe.ds.ZoweNode.openPS", async (node) => dsActions.openPS(node, true, datasetProvider)) ); @@ -196,8 +196,8 @@ export async function initDatasetProvider(context: vscode.ExtensionContext): Pro datasetProvider.refreshElement(node); }) ); - context.subscriptions.push(vscode.commands.registerCommand("zowe.ds.ssoLogin", (node: IZoweTreeNode): void => datasetProvider.ssoLogin(node))); - context.subscriptions.push(vscode.commands.registerCommand("zowe.ds.ssoLogout", (node: IZoweTreeNode): void => datasetProvider.ssoLogout(node))); + // context.subscriptions.push(vscode.commands.registerCommand("zowe.ds.ssoLogin", (node: IZoweTreeNode): void => datasetProvider.ssoLogin(node))); + // context.subscriptions.push(vscode.commands.registerCommand("zowe.ds.ssoLogout", (node: IZoweTreeNode): void => datasetProvider.ssoLogout(node))); context.subscriptions.push( vscode.workspace.onDidChangeConfiguration((e) => { datasetProvider.onDidChangeConfiguration(e); diff --git a/packages/zowe-explorer/src/job/init.ts b/packages/zowe-explorer/src/job/init.ts index 55cb416fa2..d0e430b36d 100644 --- a/packages/zowe-explorer/src/job/init.ts +++ b/packages/zowe-explorer/src/job/init.ts @@ -104,9 +104,9 @@ export async function initJobsProvider(context: vscode.ExtensionContext): Promis vscode.commands.registerCommand("zowe.jobs.setJobSpool", async (session, jobId) => jobActions.focusOnJob(jobsProvider, session, jobId)) ); context.subscriptions.push(vscode.commands.registerCommand("zowe.jobs.search", (node): void => jobsProvider.filterPrompt(node))); - context.subscriptions.push( - vscode.commands.registerCommand("zowe.jobs.editSession", async (node): Promise => jobsProvider.editSession(node, jobsProvider)) - ); + // context.subscriptions.push( + // vscode.commands.registerCommand("zowe.jobs.editSession", async (node): Promise => jobsProvider.editSession(node, jobsProvider)) + // ); context.subscriptions.push( vscode.commands.registerCommand("zowe.jobs.addFavorite", async (node, nodeList) => { const selectedNodes = getSelectedNodeList(node, nodeList) as IZoweJobTreeNode[]; @@ -140,8 +140,8 @@ export async function initJobsProvider(context: vscode.ExtensionContext): Promis jobsProvider.refreshElement(node); }) ); - context.subscriptions.push(vscode.commands.registerCommand("zowe.jobs.ssoLogin", (node: IZoweTreeNode): void => jobsProvider.ssoLogin(node))); - context.subscriptions.push(vscode.commands.registerCommand("zowe.jobs.ssoLogout", (node: IZoweTreeNode): void => jobsProvider.ssoLogout(node))); + // context.subscriptions.push(vscode.commands.registerCommand("zowe.jobs.ssoLogin", (node: IZoweTreeNode): void => jobsProvider.ssoLogin(node))); + // context.subscriptions.push(vscode.commands.registerCommand("zowe.jobs.ssoLogout", (node: IZoweTreeNode): void => jobsProvider.ssoLogout(node))); const spoolFileTogglePoll = (startPolling: boolean) => async (node: IZoweTreeNode, nodeList: IZoweTreeNode[]): Promise => { diff --git a/packages/zowe-explorer/src/uss/init.ts b/packages/zowe-explorer/src/uss/init.ts index a4ac9d5ec3..cd3528541c 100644 --- a/packages/zowe-explorer/src/uss/init.ts +++ b/packages/zowe-explorer/src/uss/init.ts @@ -77,9 +77,9 @@ export async function initUSSProvider(context: vscode.ExtensionContext): Promise context.subscriptions.push( vscode.commands.registerCommand("zowe.uss.fullPath", (node: IZoweUSSTreeNode): void => ussFileProvider.filterPrompt(node)) ); - context.subscriptions.push( - vscode.commands.registerCommand("zowe.uss.editSession", async (node) => ussFileProvider.editSession(node, ussFileProvider)) - ); + // context.subscriptions.push( + // vscode.commands.registerCommand("zowe.uss.editSession", async (node) => ussFileProvider.editSession(node, ussFileProvider)) + // ); context.subscriptions.push( vscode.commands.registerCommand("zowe.uss.ZoweUSSNode.open", (node: IZoweUSSTreeNode): void => node.openUSS(false, true, ussFileProvider)) ); @@ -167,8 +167,8 @@ export async function initUSSProvider(context: vscode.ExtensionContext): Promise ussFileProvider.refreshElement(node); }) ); - context.subscriptions.push(vscode.commands.registerCommand("zowe.uss.ssoLogin", (node: IZoweTreeNode): void => ussFileProvider.ssoLogin(node))); - context.subscriptions.push(vscode.commands.registerCommand("zowe.uss.ssoLogout", (node: IZoweTreeNode): void => ussFileProvider.ssoLogout(node))); + // context.subscriptions.push(vscode.commands.registerCommand("zowe.uss.ssoLogin", (node: IZoweTreeNode): void => ussFileProvider.ssoLogin(node))); + // context.subscriptions.push(vscode.commands.registerCommand("zowe.uss.ssoLogout", (node: IZoweTreeNode): void => ussFileProvider.ssoLogout(node))); context.subscriptions.push( vscode.commands.registerCommand("zowe.uss.pasteUssFile", async (node: IZoweUSSTreeNode) => { if (ussFileProvider.copying != null) { From 041bd1fe5184226d910d471389449d9243738737 Mon Sep 17 00:00:00 2001 From: Billie Simmons <49491949+JillieBeanSim@users.noreply.github.com> Date: Thu, 21 Sep 2023 12:51:55 -0400 Subject: [PATCH 026/189] add commands back without when clause as to not be breaking change Signed-off-by: Billie Simmons <49491949+JillieBeanSim@users.noreply.github.com> --- .../__tests__/__unit__/extension.unit.test.ts | 1 + packages/zowe-explorer/package.json | 84 +++++++++++++++++-- packages/zowe-explorer/package.nls.json | 3 +- packages/zowe-explorer/src/dataset/init.ts | 10 +-- packages/zowe-explorer/src/globals.ts | 2 +- packages/zowe-explorer/src/job/init.ts | 10 +-- packages/zowe-explorer/src/shared/init.ts | 6 ++ packages/zowe-explorer/src/uss/init.ts | 10 +-- 8 files changed, 103 insertions(+), 23 deletions(-) diff --git a/packages/zowe-explorer/__tests__/__unit__/extension.unit.test.ts b/packages/zowe-explorer/__tests__/__unit__/extension.unit.test.ts index 0f637993a6..5f111c1d64 100644 --- a/packages/zowe-explorer/__tests__/__unit__/extension.unit.test.ts +++ b/packages/zowe-explorer/__tests__/__unit__/extension.unit.test.ts @@ -244,6 +244,7 @@ async function createGlobalMocks() { "zowe.manualPoll", "zowe.updateSecureCredentials", "zowe.promptCredentials", + "zowe.profileManagement", "zowe.openRecentMember", "zowe.searchInAllLoadedItems", "zowe.ds.deleteProfile", diff --git a/packages/zowe-explorer/package.json b/packages/zowe-explorer/package.json index 6eaccb4e0e..0feb932f4f 100644 --- a/packages/zowe-explorer/package.json +++ b/packages/zowe-explorer/package.json @@ -141,6 +141,11 @@ "title": "%zowe.promptCredentials%", "category": "Zowe Explorer" }, + { + "command": "zowe.profileManagement", + "title": "%zowe.profileManagement%", + "category": "Zowe Explorer" + }, { "command": "zowe.extRefresh", "title": "%zowe.extRefresh%", @@ -262,6 +267,15 @@ "dark": "./resources/dark/plus.svg" } }, + { + "command": "zowe.ds.editSession", + "title": "%editSession%", + "category": "Zowe Explorer", + "icon": { + "light": "./resources/light/edit.svg", + "dark": "./resources/dark/edit.svg" + } + }, { "command": "zowe.ds.deleteProfile", "title": "%deleteProfile%", @@ -471,6 +485,15 @@ "dark": "./resources/dark/plus.svg" } }, + { + "command": "zowe.uss.editSession", + "title": "%editSession%", + "category": "Zowe Explorer", + "icon": { + "light": "./resources/light/edit.svg", + "dark": "./resources/dark/edit.svg" + } + }, { "command": "zowe.uss.deleteProfile", "title": "%deleteProfile%", @@ -640,6 +663,15 @@ "dark": "./resources/dark/refresh.svg" } }, + { + "command": "zowe.jobs.editSession", + "title": "%editSession%", + "category": "Zowe Explorer", + "icon": { + "light": "./resources/light/edit.svg", + "dark": "./resources/dark/edit.svg" + } + }, { "command": "zowe.jobs.deleteProfile", "title": "%deleteProfile%", @@ -938,8 +970,8 @@ }, { "when": "view == zowe.uss.explorer && viewItem =~ /^(?!.*_fav.*)ussSession.*/ && !listMultiSelection", - "command": "zowe.promptCredentials", - "group": "098_zowe_ussProfileAuthentication@3" + "command": "zowe.profileManagement", + "group": "099_zowe_ussProfileAuthentication@97" }, { "when": "viewItem =~ /^(?!.*_fav.*)ussSession.*/", @@ -1138,8 +1170,8 @@ }, { "when": "view == zowe.ds.explorer && viewItem =~ /^(?!.*_fav.*)session.*/ && !listMultiSelection", - "command": "zowe.promptCredentials", - "group": "098_zowe_dsProfileAuthentication@8" + "command": "zowe.profileManagement", + "group": "099_zowe_dsProfileAuthentication@97" }, { "when": "view == zowe.ds.explorer && viewItem =~ /^(?!.*_fav.*)session.*/", @@ -1288,8 +1320,8 @@ }, { "when": "view == zowe.jobs.explorer && viewItem =~ /^(?!.*_fav.*)server.*/ && !listMultiSelection", - "command": "zowe.promptCredentials", - "group": "098_zowe_jobsProfileAuthentication@5" + "command": "zowe.profileManagement", + "group": "098_zowe_jobsProfileAuthentication@97" }, { "when": "view == zowe.jobs.explorer && viewItem =~ /^(?!.*_fav.*)server.*/", @@ -1382,6 +1414,10 @@ "command": "zowe.ds.hMigrateDataSet", "when": "never" }, + { + "command": "zowe.ds.editSession", + "when": "never" + }, { "command": "zowe.ds.hRecallDataSet", "when": "never" @@ -1478,6 +1514,30 @@ "command": "zowe.uss.copyUssFile", "when": "never" }, + { + "command": "zowe.ds.ssoLogin", + "when": "never" + }, + { + "command": "zowe.ds.ssoLogout", + "when": "never" + }, + { + "command": "zowe.uss.ssoLogin", + "when": "never" + }, + { + "command": "zowe.uss.ssoLogout", + "when": "never" + }, + { + "command": "zowe.jobs.ssoLogin", + "when": "never" + }, + { + "command": "zowe.jobs.ssoLogout", + "when": "never" + }, { "command": "zowe.uss.pasteUssFile", "when": "never" @@ -1550,6 +1610,10 @@ "command": "zowe.jobs.setJobSpool", "when": "never" }, + { + "command": "zowe.uss.editSession", + "when": "never" + }, { "command": "zowe.jobs.refreshJobsServer", "when": "never" @@ -1598,6 +1662,10 @@ "command": "zowe.jobs.removeJobsSession", "when": "never" }, + { + "command": "zowe.jobs.editSession", + "when": "never" + }, { "command": "zowe.jobs.deleteProfile", "when": "never" @@ -1621,6 +1689,10 @@ { "command": "zowe.jobs.deleteJob", "when": "never" + }, + { + "command": "zowe.profileManagement", + "when": "never" } ] }, diff --git a/packages/zowe-explorer/package.nls.json b/packages/zowe-explorer/package.nls.json index dd0efbc93d..6b9444af1a 100644 --- a/packages/zowe-explorer/package.nls.json +++ b/packages/zowe-explorer/package.nls.json @@ -2,7 +2,8 @@ "displayName": "Zowe Explorer", "description": "VS Code extension, powered by Zowe CLI, that streamlines interaction with mainframe data sets, USS files, and jobs", "viewsContainers.activitybar": "Zowe Explorer", - "zowe.promptCredentials": "Manage Profile", + "zowe.promptCredentials": "Update Credentials", + "zowe.profileManagement": "Manage Profile", "zowe.extRefresh": "Refresh Zowe Explorer", "zowe.ds.explorer": "Data Sets", "zowe.uss.explorer": "Unix System Services (USS)", diff --git a/packages/zowe-explorer/src/dataset/init.ts b/packages/zowe-explorer/src/dataset/init.ts index f43b4e4a77..12e81d74eb 100644 --- a/packages/zowe-explorer/src/dataset/init.ts +++ b/packages/zowe-explorer/src/dataset/init.ts @@ -68,9 +68,9 @@ export async function initDatasetProvider(context: vscode.ExtensionContext): Pro }) ); context.subscriptions.push(vscode.commands.registerCommand("zowe.ds.pattern", (node): void => datasetProvider.filterPrompt(node))); - // context.subscriptions.push( - // vscode.commands.registerCommand("zowe.ds.editSession", async (node) => datasetProvider.editSession(node, datasetProvider)) - // ); + context.subscriptions.push( + vscode.commands.registerCommand("zowe.ds.editSession", async (node) => datasetProvider.editSession(node, datasetProvider)) + ); context.subscriptions.push( vscode.commands.registerCommand("zowe.ds.ZoweNode.openPS", async (node) => dsActions.openPS(node, true, datasetProvider)) ); @@ -196,8 +196,8 @@ export async function initDatasetProvider(context: vscode.ExtensionContext): Pro datasetProvider.refreshElement(node); }) ); - // context.subscriptions.push(vscode.commands.registerCommand("zowe.ds.ssoLogin", (node: IZoweTreeNode): void => datasetProvider.ssoLogin(node))); - // context.subscriptions.push(vscode.commands.registerCommand("zowe.ds.ssoLogout", (node: IZoweTreeNode): void => datasetProvider.ssoLogout(node))); + context.subscriptions.push(vscode.commands.registerCommand("zowe.ds.ssoLogin", (node: IZoweTreeNode): void => datasetProvider.ssoLogin(node))); + context.subscriptions.push(vscode.commands.registerCommand("zowe.ds.ssoLogout", (node: IZoweTreeNode): void => datasetProvider.ssoLogout(node))); context.subscriptions.push( vscode.workspace.onDidChangeConfiguration((e) => { datasetProvider.onDidChangeConfiguration(e); diff --git a/packages/zowe-explorer/src/globals.ts b/packages/zowe-explorer/src/globals.ts index a503fe7332..3d3d338c62 100644 --- a/packages/zowe-explorer/src/globals.ts +++ b/packages/zowe-explorer/src/globals.ts @@ -35,7 +35,7 @@ export let DS_DIR: string; export let CONFIG_PATH; // set during activate export let ISTHEIA = false; // set during activate export let LOG: imperative.Logger; -export const COMMAND_COUNT = 113; +export const COMMAND_COUNT = 114; export const MAX_SEARCH_HISTORY = 5; export const MAX_FILE_HISTORY = 10; export const MS_PER_SEC = 1000; diff --git a/packages/zowe-explorer/src/job/init.ts b/packages/zowe-explorer/src/job/init.ts index d0e430b36d..55cb416fa2 100644 --- a/packages/zowe-explorer/src/job/init.ts +++ b/packages/zowe-explorer/src/job/init.ts @@ -104,9 +104,9 @@ export async function initJobsProvider(context: vscode.ExtensionContext): Promis vscode.commands.registerCommand("zowe.jobs.setJobSpool", async (session, jobId) => jobActions.focusOnJob(jobsProvider, session, jobId)) ); context.subscriptions.push(vscode.commands.registerCommand("zowe.jobs.search", (node): void => jobsProvider.filterPrompt(node))); - // context.subscriptions.push( - // vscode.commands.registerCommand("zowe.jobs.editSession", async (node): Promise => jobsProvider.editSession(node, jobsProvider)) - // ); + context.subscriptions.push( + vscode.commands.registerCommand("zowe.jobs.editSession", async (node): Promise => jobsProvider.editSession(node, jobsProvider)) + ); context.subscriptions.push( vscode.commands.registerCommand("zowe.jobs.addFavorite", async (node, nodeList) => { const selectedNodes = getSelectedNodeList(node, nodeList) as IZoweJobTreeNode[]; @@ -140,8 +140,8 @@ export async function initJobsProvider(context: vscode.ExtensionContext): Promis jobsProvider.refreshElement(node); }) ); - // context.subscriptions.push(vscode.commands.registerCommand("zowe.jobs.ssoLogin", (node: IZoweTreeNode): void => jobsProvider.ssoLogin(node))); - // context.subscriptions.push(vscode.commands.registerCommand("zowe.jobs.ssoLogout", (node: IZoweTreeNode): void => jobsProvider.ssoLogout(node))); + context.subscriptions.push(vscode.commands.registerCommand("zowe.jobs.ssoLogin", (node: IZoweTreeNode): void => jobsProvider.ssoLogin(node))); + context.subscriptions.push(vscode.commands.registerCommand("zowe.jobs.ssoLogout", (node: IZoweTreeNode): void => jobsProvider.ssoLogout(node))); const spoolFileTogglePoll = (startPolling: boolean) => async (node: IZoweTreeNode, nodeList: IZoweTreeNode[]): Promise => { diff --git a/packages/zowe-explorer/src/shared/init.ts b/packages/zowe-explorer/src/shared/init.ts index acee163494..6efb21cad4 100644 --- a/packages/zowe-explorer/src/shared/init.ts +++ b/packages/zowe-explorer/src/shared/init.ts @@ -88,6 +88,12 @@ export function registerCommonCommands(context: vscode.ExtensionContext, provide context.subscriptions.push( vscode.commands.registerCommand("zowe.promptCredentials", async (node: IZoweTreeNode) => { + await ProfilesUtils.promptCredentials(node); + }) + ); + + context.subscriptions.push( + vscode.commands.registerCommand("zowe.profileManagement", async (node: IZoweTreeNode) => { await ProfilesUtils.manageProfile(node); }) ); diff --git a/packages/zowe-explorer/src/uss/init.ts b/packages/zowe-explorer/src/uss/init.ts index cd3528541c..a4ac9d5ec3 100644 --- a/packages/zowe-explorer/src/uss/init.ts +++ b/packages/zowe-explorer/src/uss/init.ts @@ -77,9 +77,9 @@ export async function initUSSProvider(context: vscode.ExtensionContext): Promise context.subscriptions.push( vscode.commands.registerCommand("zowe.uss.fullPath", (node: IZoweUSSTreeNode): void => ussFileProvider.filterPrompt(node)) ); - // context.subscriptions.push( - // vscode.commands.registerCommand("zowe.uss.editSession", async (node) => ussFileProvider.editSession(node, ussFileProvider)) - // ); + context.subscriptions.push( + vscode.commands.registerCommand("zowe.uss.editSession", async (node) => ussFileProvider.editSession(node, ussFileProvider)) + ); context.subscriptions.push( vscode.commands.registerCommand("zowe.uss.ZoweUSSNode.open", (node: IZoweUSSTreeNode): void => node.openUSS(false, true, ussFileProvider)) ); @@ -167,8 +167,8 @@ export async function initUSSProvider(context: vscode.ExtensionContext): Promise ussFileProvider.refreshElement(node); }) ); - // context.subscriptions.push(vscode.commands.registerCommand("zowe.uss.ssoLogin", (node: IZoweTreeNode): void => ussFileProvider.ssoLogin(node))); - // context.subscriptions.push(vscode.commands.registerCommand("zowe.uss.ssoLogout", (node: IZoweTreeNode): void => ussFileProvider.ssoLogout(node))); + context.subscriptions.push(vscode.commands.registerCommand("zowe.uss.ssoLogin", (node: IZoweTreeNode): void => ussFileProvider.ssoLogin(node))); + context.subscriptions.push(vscode.commands.registerCommand("zowe.uss.ssoLogout", (node: IZoweTreeNode): void => ussFileProvider.ssoLogout(node))); context.subscriptions.push( vscode.commands.registerCommand("zowe.uss.pasteUssFile", async (node: IZoweUSSTreeNode) => { if (ussFileProvider.copying != null) { From 7c49e513504b3d4ffce29ab4d5081531bb6eec06 Mon Sep 17 00:00:00 2001 From: Billie Simmons <49491949+JillieBeanSim@users.noreply.github.com> Date: Thu, 21 Sep 2023 12:54:02 -0400 Subject: [PATCH 027/189] run localization scripts Signed-off-by: Billie Simmons <49491949+JillieBeanSim@users.noreply.github.com> --- packages/zowe-explorer/i18n/sample/package.i18n.json | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/packages/zowe-explorer/i18n/sample/package.i18n.json b/packages/zowe-explorer/i18n/sample/package.i18n.json index 5caa899119..6b9444af1a 100644 --- a/packages/zowe-explorer/i18n/sample/package.i18n.json +++ b/packages/zowe-explorer/i18n/sample/package.i18n.json @@ -2,7 +2,8 @@ "displayName": "Zowe Explorer", "description": "VS Code extension, powered by Zowe CLI, that streamlines interaction with mainframe data sets, USS files, and jobs", "viewsContainers.activitybar": "Zowe Explorer", - "zowe.promptCredentials": "Manage Profile", + "zowe.promptCredentials": "Update Credentials", + "zowe.profileManagement": "Manage Profile", "zowe.extRefresh": "Refresh Zowe Explorer", "zowe.ds.explorer": "Data Sets", "zowe.uss.explorer": "Unix System Services (USS)", @@ -15,7 +16,6 @@ "removeFavProfile": "Remove profile from Favorites", "uss.addFavorite": "Add to Favorites", "addSession": "Add Profile to Data Sets View", - "editSession": "Update Profile", "createDataset": "Create New Data Set", "createMember": "Create New Member", "showAttributes": "Show Attributes", @@ -130,12 +130,6 @@ "enableValidation": "Enable Validation for Profile", "uss.enableValidation": "Enable Validation for Profile", "jobs.enableValidation": "Enable Validation for Profile", - "ssoLogin": "Log in to Authentication Service", - "uss.ssoLogin": "Log in to Authentication Service", - "jobs.ssoLogin": "Log in to Authentication Service", - "ssoLogout": "Log out from Authentication Service", - "uss.ssoLogout": "Log out from Authentication Service", - "jobs.ssoLogout": "Log out from Authentication Service", "jobs.refreshJob": "Refresh Job", "jobs.refreshSpool": "Pull from Mainframe", "manualPoll": "Poll Content in Active Editor", From 36e3120621bc0d37226eb540e9fb73b4bff68b52 Mon Sep 17 00:00:00 2001 From: Billie Simmons <49491949+JillieBeanSim@users.noreply.github.com> Date: Thu, 21 Sep 2023 12:57:10 -0400 Subject: [PATCH 028/189] add items back to package.nls.json Signed-off-by: Billie Simmons <49491949+JillieBeanSim@users.noreply.github.com> --- packages/zowe-explorer/i18n/sample/package.i18n.json | 7 +++++++ packages/zowe-explorer/package.nls.json | 7 +++++++ 2 files changed, 14 insertions(+) diff --git a/packages/zowe-explorer/i18n/sample/package.i18n.json b/packages/zowe-explorer/i18n/sample/package.i18n.json index 6b9444af1a..a73e7985e5 100644 --- a/packages/zowe-explorer/i18n/sample/package.i18n.json +++ b/packages/zowe-explorer/i18n/sample/package.i18n.json @@ -16,6 +16,7 @@ "removeFavProfile": "Remove profile from Favorites", "uss.addFavorite": "Add to Favorites", "addSession": "Add Profile to Data Sets View", + "editSession": "Update Profile", "createDataset": "Create New Data Set", "createMember": "Create New Member", "showAttributes": "Show Attributes", @@ -130,6 +131,12 @@ "enableValidation": "Enable Validation for Profile", "uss.enableValidation": "Enable Validation for Profile", "jobs.enableValidation": "Enable Validation for Profile", + "ssoLogin": "Log in to Authentication Service", + "uss.ssoLogin": "Log in to Authentication Service", + "jobs.ssoLogin": "Log in to Authentication Service", + "ssoLogout": "Log out from Authentication Service", + "uss.ssoLogout": "Log out from Authentication Service", + "jobs.ssoLogout": "Log out from Authentication Service", "jobs.refreshJob": "Refresh Job", "jobs.refreshSpool": "Pull from Mainframe", "manualPoll": "Poll Content in Active Editor", diff --git a/packages/zowe-explorer/package.nls.json b/packages/zowe-explorer/package.nls.json index 6b9444af1a..a73e7985e5 100644 --- a/packages/zowe-explorer/package.nls.json +++ b/packages/zowe-explorer/package.nls.json @@ -16,6 +16,7 @@ "removeFavProfile": "Remove profile from Favorites", "uss.addFavorite": "Add to Favorites", "addSession": "Add Profile to Data Sets View", + "editSession": "Update Profile", "createDataset": "Create New Data Set", "createMember": "Create New Member", "showAttributes": "Show Attributes", @@ -130,6 +131,12 @@ "enableValidation": "Enable Validation for Profile", "uss.enableValidation": "Enable Validation for Profile", "jobs.enableValidation": "Enable Validation for Profile", + "ssoLogin": "Log in to Authentication Service", + "uss.ssoLogin": "Log in to Authentication Service", + "jobs.ssoLogin": "Log in to Authentication Service", + "ssoLogout": "Log out from Authentication Service", + "uss.ssoLogout": "Log out from Authentication Service", + "jobs.ssoLogout": "Log out from Authentication Service", "jobs.refreshJob": "Refresh Job", "jobs.refreshSpool": "Pull from Mainframe", "manualPoll": "Poll Content in Active Editor", From f6010fc581398092b466984844dfeaf731981dbf Mon Sep 17 00:00:00 2001 From: Billie Simmons <49491949+JillieBeanSim@users.noreply.github.com> Date: Thu, 21 Sep 2023 13:19:08 -0400 Subject: [PATCH 029/189] realign for easier comparison Signed-off-by: Billie Simmons <49491949+JillieBeanSim@users.noreply.github.com> --- packages/zowe-explorer/package.json | 54 ++++++++++++++--------------- 1 file changed, 27 insertions(+), 27 deletions(-) diff --git a/packages/zowe-explorer/package.json b/packages/zowe-explorer/package.json index 0feb932f4f..773b4556e8 100644 --- a/packages/zowe-explorer/package.json +++ b/packages/zowe-explorer/package.json @@ -1374,6 +1374,10 @@ "command": "zowe.ds.showAttributes", "when": "never" }, + { + "command": "zowe.ds.editSession", + "when": "never" + }, { "command": "zowe.ds.createMember", "when": "never" @@ -1414,10 +1418,6 @@ "command": "zowe.ds.hMigrateDataSet", "when": "never" }, - { - "command": "zowe.ds.editSession", - "when": "never" - }, { "command": "zowe.ds.hRecallDataSet", "when": "never" @@ -1471,71 +1471,71 @@ "when": "never" }, { - "command": "zowe.ds.saveSearch", + "command": "zowe.ds.ssoLogin", "when": "never" }, { - "command": "zowe.ds.removeSavedSearch", + "command": "zowe.ds.ssoLogout", "when": "never" }, { - "command": "zowe.uss.fullPath", + "command": "zowe.uss.ssoLogin", "when": "never" }, { - "command": "zowe.uss.copyPath", + "command": "zowe.uss.ssoLogout", "when": "never" }, { - "command": "zowe.jobs.search", + "command": "zowe.jobs.ssoLogin", "when": "never" }, { - "command": "zowe.uss.refreshUSS", + "command": "zowe.jobs.ssoLogout", "when": "never" }, { - "command": "zowe.uss.refreshDirectory", + "command": "zowe.ds.saveSearch", "when": "never" }, { - "command": "zowe.uss.createFolder", + "command": "zowe.ds.removeSavedSearch", "when": "never" }, { - "command": "zowe.uss.createFile", + "command": "zowe.uss.fullPath", "when": "never" }, { - "command": "zowe.uss.uploadDialog", + "command": "zowe.uss.copyPath", "when": "never" }, { - "command": "zowe.uss.copyUssFile", + "command": "zowe.jobs.search", "when": "never" }, { - "command": "zowe.ds.ssoLogin", + "command": "zowe.uss.refreshUSS", "when": "never" }, { - "command": "zowe.ds.ssoLogout", + "command": "zowe.uss.refreshDirectory", "when": "never" }, { - "command": "zowe.uss.ssoLogin", + "command": "zowe.uss.createFolder", "when": "never" }, { - "command": "zowe.uss.ssoLogout", + "command": "zowe.uss.createFile", "when": "never" }, { - "command": "zowe.jobs.ssoLogin", + "command": "zowe.uss.uploadDialog", "when": "never" }, { - "command": "zowe.jobs.ssoLogout", + "command": "zowe.uss.copyUssFile", "when": "never" }, { @@ -1570,6 +1570,10 @@ "command": "zowe.uss.saveSearch", "when": "never" }, + { + "command": "zowe.uss.editSession", + "when": "never" + }, { "command": "zowe.uss.deleteProfile", "when": "never" @@ -1610,10 +1614,6 @@ "command": "zowe.jobs.setJobSpool", "when": "never" }, - { - "command": "zowe.uss.editSession", - "when": "never" - }, { "command": "zowe.jobs.refreshJobsServer", "when": "never" @@ -1659,11 +1659,11 @@ "when": "never" }, { - "command": "zowe.jobs.removeJobsSession", + "command": "zowe.jobs.editSession", "when": "never" }, { - "command": "zowe.jobs.editSession", + "command": "zowe.jobs.removeJobsSession", "when": "never" }, { From d6346a7a7d8f61cd47bb37b5f3d63756e994f95a Mon Sep 17 00:00:00 2001 From: Billie Simmons <49491949+JillieBeanSim@users.noreply.github.com> Date: Thu, 21 Sep 2023 13:51:38 -0400 Subject: [PATCH 030/189] handle case of no authentication method shown for profile Signed-off-by: Billie Simmons <49491949+JillieBeanSim@users.noreply.github.com> --- .../sample/src/utils/ProfilesUtils.i18n.json | 1 + .../zowe-explorer/src/utils/ProfilesUtils.ts | 85 +++++++++++-------- 2 files changed, 49 insertions(+), 37 deletions(-) diff --git a/packages/zowe-explorer/i18n/sample/src/utils/ProfilesUtils.i18n.json b/packages/zowe-explorer/i18n/sample/src/utils/ProfilesUtils.i18n.json index 80ab2e3c84..0c0a0b8f76 100644 --- a/packages/zowe-explorer/i18n/sample/src/utils/ProfilesUtils.i18n.json +++ b/packages/zowe-explorer/i18n/sample/src/utils/ProfilesUtils.i18n.json @@ -32,5 +32,6 @@ "logoutQpItem.logout.qpDetail": "Log out to invalidate and remove stored token value", "qpPlaceholders.qp.basic": "Profile is using basic authentication. Choose a profile action.", "qpPlaceholders.qp.token": "Profile is using token authentication. Choose a profile action.", + "qpPlaceholders.qp.choose": "Profile doesn't specify an authentication method. Choose a profile action.", "getProfile.notTreeItem": "Tree Item is not a Zowe Explorer item." } diff --git a/packages/zowe-explorer/src/utils/ProfilesUtils.ts b/packages/zowe-explorer/src/utils/ProfilesUtils.ts index d57d43e9a4..3039737640 100644 --- a/packages/zowe-explorer/src/utils/ProfilesUtils.ts +++ b/packages/zowe-explorer/src/utils/ProfilesUtils.ts @@ -320,7 +320,7 @@ export class ProfilesUtils { } // will need a case for isUsingCertAuth default: { - Gui.infoMessage("profile not using stated authentication type."); + await this.chooseAuthProfileManagement(node); break; } } @@ -520,67 +520,42 @@ export class ProfilesUtils { private static editProfileQpItem: Record = { [this.AuthQpLabels.edit]: { label: localize("editProfileQpItem.editProfile.qpLabel", "Edit profile"), - detail: localize("editProfileQpItem.editProfile.qpDetail", "Update profile information including authentication method"), + description: localize("editProfileQpItem.editProfile.qpDetail", "Update profile information including authentication method"), }, }; private static updateBasicAuthQpItem: Record = { [this.AuthQpLabels.update]: { label: localize("updateBasicAuthQpItem.updateCredentials.qpLabel", "Update Credentials"), - detail: localize("updateBasicAuthQpItem.updateCredentials.qpDetail", "Update stored username and password"), + description: localize("updateBasicAuthQpItem.updateCredentials.qpDetail", "Update stored username and password"), }, }; private static loginQpItem: Record = { [this.AuthQpLabels.login]: { label: localize("loginQpItem.login.qpLabel", "Login to authentication service"), - detail: localize("loginQpItem.login.qpDetail", "Login to obtain and update stored token value"), + description: localize("loginQpItem.login.qpDetail", "Login to obtain and update stored token value"), }, }; private static logoutQpItem: Record = { [this.AuthQpLabels.logout]: { label: localize("logoutQpItem.logout.qpLabel", "Log out of authentication service"), - detail: localize("logoutQpItem.logout.qpDetail", "Log out to invalidate and remove stored token value"), + description: localize("logoutQpItem.logout.qpDetail", "Log out to invalidate and remove stored token value"), }, }; private static async basicAuthProfileManagement(node: IZoweTreeNode): Promise { const profile = node.getProfile(); const selected = await this.setupProfileManagementQp(imperative.SessConstants.AUTH_TYPE_BASIC, profile); - switch (selected) { - case this.updateBasicAuthQpItem[this.AuthQpLabels.update]: { - await this.promptCredentials(node); - break; - } - case this.editProfileQpItem[this.AuthQpLabels.edit]: { - await Profiles.getInstance().editSession(profile, profile.name); - break; - } - default: { - Gui.infoMessage(localize("profiles.operation.cancelled", "Operation Cancelled")); - break; - } - } + await this.handleAuthSelection(selected, node, profile); } private static async tokenAuthProfileManagement(node: IZoweTreeNode): Promise { const profile = node.getProfile(); const selected = await this.setupProfileManagementQp("token", profile); - switch (selected) { - case this.loginQpItem[this.AuthQpLabels.login]: { - await Profiles.getInstance().ssoLogin(node, profile.name); - break; - } - case this.editProfileQpItem[this.AuthQpLabels.edit]: { - await Profiles.getInstance().editSession(profile, profile.name); - break; - } - case this.logoutQpItem[this.AuthQpLabels.logout]: { - await Profiles.getInstance().ssoLogout(node); - break; - } - default: { - Gui.infoMessage(localize("profiles.operation.cancelled", "Operation Cancelled")); - break; - } - } + await this.handleAuthSelection(selected, node, profile); + } + private static async chooseAuthProfileManagement(node: IZoweTreeNode): Promise { + const profile = node.getProfile(); + const selected = await this.setupProfileManagementQp(null, profile); + await this.handleAuthSelection(selected, node, profile); } private static async setupProfileManagementQp(managementType: string, profile: imperative.IProfileLoaded): Promise { const qp = Gui.createQuickPick(); @@ -596,6 +571,11 @@ export class ProfilesUtils { qp.placeholder = this.qpPlaceholders.tokenAuth; break; } + default: { + quickPickOptions = this.chooseAuthQp(); + qp.placeholder = this.qpPlaceholders.chooseAuth; + break; + } } let selectedItem = quickPickOptions[0]; qp.items = quickPickOptions; @@ -605,10 +585,35 @@ export class ProfilesUtils { qp.hide(); return selectedItem; } + private static async handleAuthSelection(selected: vscode.QuickPickItem, node: IZoweTreeNode, profile: imperative.IProfileLoaded): Promise { + switch (selected) { + case this.loginQpItem[this.AuthQpLabels.login]: { + await Profiles.getInstance().ssoLogin(node, profile.name); + break; + } + case this.editProfileQpItem[this.AuthQpLabels.edit]: { + await Profiles.getInstance().editSession(profile, profile.name); + break; + } + case this.logoutQpItem[this.AuthQpLabels.logout]: { + await Profiles.getInstance().ssoLogout(node); + break; + } + case this.updateBasicAuthQpItem[this.AuthQpLabels.update]: { + await this.promptCredentials(node); + break; + } + default: { + Gui.infoMessage(localize("profiles.operation.cancelled", "Operation Cancelled")); + break; + } + } + } private static qpPlaceholders = { basicAuth: localize("qpPlaceholders.qp.basic", "Profile is using basic authentication. Choose a profile action."), tokenAuth: localize("qpPlaceholders.qp.token", "Profile is using token authentication. Choose a profile action."), + chooseAuth: localize("qpPlaceholders.qp.choose", "Profile doesn't specify an authentication method. Choose a profile action."), }; private static basicAuthQp(): vscode.QuickPickItem[] { @@ -624,6 +629,12 @@ export class ProfilesUtils { } return quickPickOptions; } + private static chooseAuthQp(): vscode.QuickPickItem[] { + const quickPickOptions: vscode.QuickPickItem[] = Object.values(this.updateBasicAuthQpItem); + quickPickOptions.push(this.loginQpItem[this.AuthQpLabels.login]); + quickPickOptions.push(this.editProfileQpItem[this.AuthQpLabels.edit]); + return quickPickOptions; + } } /** From 84cf3b56505d319f4987a5ac4c5b05c6933c7032 Mon Sep 17 00:00:00 2001 From: Billie Simmons <49491949+JillieBeanSim@users.noreply.github.com> Date: Thu, 21 Sep 2023 14:01:35 -0400 Subject: [PATCH 031/189] add changelog Signed-off-by: Billie Simmons <49491949+JillieBeanSim@users.noreply.github.com> --- packages/zowe-explorer/CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/zowe-explorer/CHANGELOG.md b/packages/zowe-explorer/CHANGELOG.md index d6550315ec..5703f1ed60 100644 --- a/packages/zowe-explorer/CHANGELOG.md +++ b/packages/zowe-explorer/CHANGELOG.md @@ -7,6 +7,7 @@ All notable changes to the "vscode-extension-for-zowe" extension will be documen ### New features and enhancements - Added "Sort Jobs" feature for job nodes in Jobs tree view. [#2257](https://github.com/zowe/vscode-extension-for-zowe/issues/2251) +- Introduce a new user interface for managing profiles via right-click action "Manage Profile". ### Bug fixes From fb680bb9b955a67067f98be6f96e2ee668730e5f Mon Sep 17 00:00:00 2001 From: Billie Simmons <49491949+JillieBeanSim@users.noreply.github.com> Date: Fri, 22 Sep 2023 09:52:20 -0400 Subject: [PATCH 032/189] update strings in different scenarios Signed-off-by: Billie Simmons <49491949+JillieBeanSim@users.noreply.github.com> --- .../sample/src/utils/ProfilesUtils.i18n.json | 12 ++++++----- .../zowe-explorer/src/utils/ProfilesUtils.ts | 20 ++++++++++++------- 2 files changed, 20 insertions(+), 12 deletions(-) diff --git a/packages/zowe-explorer/i18n/sample/src/utils/ProfilesUtils.i18n.json b/packages/zowe-explorer/i18n/sample/src/utils/ProfilesUtils.i18n.json index 0c0a0b8f76..e41dd4a0b8 100644 --- a/packages/zowe-explorer/i18n/sample/src/utils/ProfilesUtils.i18n.json +++ b/packages/zowe-explorer/i18n/sample/src/utils/ProfilesUtils.i18n.json @@ -22,13 +22,15 @@ "initializeZoweProfiles.success": "Zowe Profiles initialized successfully.", "initializeZoweTempFolder.success": "Zowe Temp folder initialized successfully.", "profiles.operation.cancelled": "Operation Cancelled", - "editProfileQpItem.editProfile.qpLabel": "Edit profile", - "editProfileQpItem.editProfile.qpDetail": "Update profile information including authentication method", - "updateBasicAuthQpItem.updateCredentials.qpLabel": "Update Credentials", + "editProfileQpItem.editProfile.qpLabel": "$(pencil) Edit profile", + "editProfileQpItem.editProfile.qpDetail": "Update profile connection information", + "updateBasicAuthQpItem.updateCredentials.qpLabel": "$(refresh) Update Credentials", "updateBasicAuthQpItem.updateCredentials.qpDetail": "Update stored username and password", - "loginQpItem.login.qpLabel": "Login to authentication service", + "addBasicAuthQpItem.addCredentials.qpLabel": "$(plus) Add Credentials", + "addBasicAuthQpItem.addCredentials.qpDetail": "Add username and password for basic authentication", + "loginQpItem.login.qpLabel": "$(arrow-right) Login to authentication service", "loginQpItem.login.qpDetail": "Login to obtain and update stored token value", - "logoutQpItem.logout.qpLabel": "Log out of authentication service", + "logoutQpItem.logout.qpLabel": "$(arrow-left) Log out of authentication service", "logoutQpItem.logout.qpDetail": "Log out to invalidate and remove stored token value", "qpPlaceholders.qp.basic": "Profile is using basic authentication. Choose a profile action.", "qpPlaceholders.qp.token": "Profile is using token authentication. Choose a profile action.", diff --git a/packages/zowe-explorer/src/utils/ProfilesUtils.ts b/packages/zowe-explorer/src/utils/ProfilesUtils.ts index 3039737640..8bfa3fdaf4 100644 --- a/packages/zowe-explorer/src/utils/ProfilesUtils.ts +++ b/packages/zowe-explorer/src/utils/ProfilesUtils.ts @@ -519,25 +519,31 @@ export class ProfilesUtils { }; private static editProfileQpItem: Record = { [this.AuthQpLabels.edit]: { - label: localize("editProfileQpItem.editProfile.qpLabel", "Edit profile"), - description: localize("editProfileQpItem.editProfile.qpDetail", "Update profile information including authentication method"), + label: localize("editProfileQpItem.editProfile.qpLabel", "$(pencil) Edit profile"), + description: localize("editProfileQpItem.editProfile.qpDetail", "Update profile connection information"), }, }; private static updateBasicAuthQpItem: Record = { [this.AuthQpLabels.update]: { - label: localize("updateBasicAuthQpItem.updateCredentials.qpLabel", "Update Credentials"), + label: localize("updateBasicAuthQpItem.updateCredentials.qpLabel", "$(refresh) Update Credentials"), description: localize("updateBasicAuthQpItem.updateCredentials.qpDetail", "Update stored username and password"), }, }; + private static addBasicAuthQpItem: Record = { + [this.AuthQpLabels.update]: { + label: localize("addBasicAuthQpItem.addCredentials.qpLabel", "$(plus) Add Credentials"), + description: localize("addBasicAuthQpItem.addCredentials.qpDetail", "Add username and password for basic authentication"), + }, + }; private static loginQpItem: Record = { [this.AuthQpLabels.login]: { - label: localize("loginQpItem.login.qpLabel", "Login to authentication service"), + label: localize("loginQpItem.login.qpLabel", "$(arrow-right) Login to authentication service"), description: localize("loginQpItem.login.qpDetail", "Login to obtain and update stored token value"), }, }; private static logoutQpItem: Record = { [this.AuthQpLabels.logout]: { - label: localize("logoutQpItem.logout.qpLabel", "Log out of authentication service"), + label: localize("logoutQpItem.logout.qpLabel", "$(arrow-left) Log out of authentication service"), description: localize("logoutQpItem.logout.qpDetail", "Log out to invalidate and remove stored token value"), }, }; @@ -623,14 +629,14 @@ export class ProfilesUtils { } private static tokenAuthQp(profile: imperative.IProfileLoaded): vscode.QuickPickItem[] { const quickPickOptions: vscode.QuickPickItem[] = Object.values(this.loginQpItem); - quickPickOptions.push(this.editProfileQpItem[this.AuthQpLabels.edit]); if (profile.profile.tokenType) { quickPickOptions.push(this.logoutQpItem[this.AuthQpLabels.logout]); } + quickPickOptions.push(this.editProfileQpItem[this.AuthQpLabels.edit]); return quickPickOptions; } private static chooseAuthQp(): vscode.QuickPickItem[] { - const quickPickOptions: vscode.QuickPickItem[] = Object.values(this.updateBasicAuthQpItem); + const quickPickOptions: vscode.QuickPickItem[] = Object.values(this.addBasicAuthQpItem); quickPickOptions.push(this.loginQpItem[this.AuthQpLabels.login]); quickPickOptions.push(this.editProfileQpItem[this.AuthQpLabels.edit]); return quickPickOptions; From 79bd3f7b4fceff0af51b62cc202c9f2af54d14bb Mon Sep 17 00:00:00 2001 From: Likhitha Nimma Date: Fri, 22 Sep 2023 19:54:12 +0530 Subject: [PATCH 033/189] Changelog file Updated Signed-off-by: Likhitha Nimma --- packages/zowe-explorer-api/CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/packages/zowe-explorer-api/CHANGELOG.md b/packages/zowe-explorer-api/CHANGELOG.md index f3d025e88f..c0dfbbc688 100644 --- a/packages/zowe-explorer-api/CHANGELOG.md +++ b/packages/zowe-explorer-api/CHANGELOG.md @@ -8,6 +8,8 @@ All notable changes to the "zowe-explorer-api" extension will be documented in t ### Bug fixes +- Fixed the issue of getting the meta data of profile types for creating the config files by adding the setters and getters in the zowe-explorer-api. [#2394](https://github.com/zowe/vscode-extension-for-zowe/issues/2394) + ## `2.11.0` ### New features and enhancements From 6a4d068f60751e5354f620387c58062f3c2e164c Mon Sep 17 00:00:00 2001 From: Billie Simmons <49491949+JillieBeanSim@users.noreply.github.com> Date: Fri, 22 Sep 2023 11:18:33 -0400 Subject: [PATCH 034/189] separate the work Signed-off-by: Billie Simmons <49491949+JillieBeanSim@users.noreply.github.com> --- .../src/utils/ProfileManagement.i18n.json | 16 ++ .../sample/src/utils/ProfilesUtils.i18n.json | 14 -- packages/zowe-explorer/src/shared/init.ts | 3 +- .../src/utils/ProfileManagement.ts | 178 ++++++++++++++++++ .../zowe-explorer/src/utils/ProfilesUtils.ts | 150 --------------- 5 files changed, 196 insertions(+), 165 deletions(-) create mode 100644 packages/zowe-explorer/i18n/sample/src/utils/ProfileManagement.i18n.json create mode 100644 packages/zowe-explorer/src/utils/ProfileManagement.ts diff --git a/packages/zowe-explorer/i18n/sample/src/utils/ProfileManagement.i18n.json b/packages/zowe-explorer/i18n/sample/src/utils/ProfileManagement.i18n.json new file mode 100644 index 0000000000..05e99d6246 --- /dev/null +++ b/packages/zowe-explorer/i18n/sample/src/utils/ProfileManagement.i18n.json @@ -0,0 +1,16 @@ +{ + "profiles.operation.cancelled": "Operation Cancelled", + "editProfileQpItem.editProfile.qpLabel": "$(pencil) Edit profile", + "editProfileQpItem.editProfile.qpDetail": "Update profile connection information", + "updateBasicAuthQpItem.updateCredentials.qpLabel": "$(refresh) Update Credentials", + "updateBasicAuthQpItem.updateCredentials.qpDetail": "Update stored username and password", + "addBasicAuthQpItem.addCredentials.qpLabel": "$(plus) Add Credentials", + "addBasicAuthQpItem.addCredentials.qpDetail": "Add username and password for basic authentication", + "loginQpItem.login.qpLabel": "$(arrow-right) Log in to authentication service", + "loginQpItem.login.qpDetail": "Log in to obtain a new token value", + "logoutQpItem.logout.qpLabel": "$(arrow-left) Log out of authentication service", + "logoutQpItem.logout.qpDetail": "Log out to invalidate and remove stored token value", + "qpPlaceholders.qp.basic": "Profile is using basic authentication. Choose a profile action.", + "qpPlaceholders.qp.token": "Profile is using token authentication. Choose a profile action.", + "qpPlaceholders.qp.choose": "Profile doesn't specify an authentication method. Choose a profile action." +} diff --git a/packages/zowe-explorer/i18n/sample/src/utils/ProfilesUtils.i18n.json b/packages/zowe-explorer/i18n/sample/src/utils/ProfilesUtils.i18n.json index e41dd4a0b8..2ed2cbc4ff 100644 --- a/packages/zowe-explorer/i18n/sample/src/utils/ProfilesUtils.i18n.json +++ b/packages/zowe-explorer/i18n/sample/src/utils/ProfilesUtils.i18n.json @@ -21,19 +21,5 @@ "initializeZoweFolder.error": "Failed to initialize Zowe folder: {0}", "initializeZoweProfiles.success": "Zowe Profiles initialized successfully.", "initializeZoweTempFolder.success": "Zowe Temp folder initialized successfully.", - "profiles.operation.cancelled": "Operation Cancelled", - "editProfileQpItem.editProfile.qpLabel": "$(pencil) Edit profile", - "editProfileQpItem.editProfile.qpDetail": "Update profile connection information", - "updateBasicAuthQpItem.updateCredentials.qpLabel": "$(refresh) Update Credentials", - "updateBasicAuthQpItem.updateCredentials.qpDetail": "Update stored username and password", - "addBasicAuthQpItem.addCredentials.qpLabel": "$(plus) Add Credentials", - "addBasicAuthQpItem.addCredentials.qpDetail": "Add username and password for basic authentication", - "loginQpItem.login.qpLabel": "$(arrow-right) Login to authentication service", - "loginQpItem.login.qpDetail": "Login to obtain and update stored token value", - "logoutQpItem.logout.qpLabel": "$(arrow-left) Log out of authentication service", - "logoutQpItem.logout.qpDetail": "Log out to invalidate and remove stored token value", - "qpPlaceholders.qp.basic": "Profile is using basic authentication. Choose a profile action.", - "qpPlaceholders.qp.token": "Profile is using token authentication. Choose a profile action.", - "qpPlaceholders.qp.choose": "Profile doesn't specify an authentication method. Choose a profile action.", "getProfile.notTreeItem": "Tree Item is not a Zowe Explorer item." } diff --git a/packages/zowe-explorer/src/shared/init.ts b/packages/zowe-explorer/src/shared/init.ts index 6efb21cad4..67fc00fb3b 100644 --- a/packages/zowe-explorer/src/shared/init.ts +++ b/packages/zowe-explorer/src/shared/init.ts @@ -27,6 +27,7 @@ import { ZoweLogger } from "../utils/LoggerUtils"; import { ZoweSaveQueue } from "../abstract/ZoweSaveQueue"; import { SettingsConfig } from "../utils/SettingsConfig"; import { spoolFilePollEvent } from "../job/actions"; +import { ProfileManagement } from "../utils/ProfileManagement"; // Set up localization nls.config({ @@ -94,7 +95,7 @@ export function registerCommonCommands(context: vscode.ExtensionContext, provide context.subscriptions.push( vscode.commands.registerCommand("zowe.profileManagement", async (node: IZoweTreeNode) => { - await ProfilesUtils.manageProfile(node); + await ProfileManagement.manageProfile(node); }) ); diff --git a/packages/zowe-explorer/src/utils/ProfileManagement.ts b/packages/zowe-explorer/src/utils/ProfileManagement.ts new file mode 100644 index 0000000000..8a4c893561 --- /dev/null +++ b/packages/zowe-explorer/src/utils/ProfileManagement.ts @@ -0,0 +1,178 @@ +/** + * This program and the accompanying materials are made available under the terms of the + * Eclipse Public License v2.0 which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-v20.html + * + * SPDX-License-Identifier: EPL-2.0 + * + * Copyright Contributors to the Zowe Project. + * + */ + +import * as vscode from "vscode"; +import { Gui, IZoweTreeNode, imperative } from "@zowe/zowe-explorer-api"; +import { ZoweLogger } from "./LoggerUtils"; +import { ProfilesUtils } from "./ProfilesUtils"; +import * as nls from "vscode-nls"; +import { Profiles } from "../Profiles"; + +// Set up localization +nls.config({ + messageFormat: nls.MessageFormat.bundle, + bundleFormat: nls.BundleFormat.standalone, +})(); +const localize: nls.LocalizeFunc = nls.loadMessageBundle(); + +export class ProfileManagement { + public static async manageProfile(node: IZoweTreeNode): Promise { + const profile = node.getProfile(); + switch (true) { + case ProfilesUtils.isProfileUsingBasicAuth(profile): { + ZoweLogger.debug(`Profile ${profile.name} is using basic authentication.`); + await this.basicAuthProfileManagement(node); + break; + } + case await ProfilesUtils.isUsingTokenAuth(profile.name): { + ZoweLogger.debug(`Profile ${profile.name} is using token authentication.`); + await this.tokenAuthProfileManagement(node); + break; + } + // will need a case for isUsingCertAuth + default: { + ZoweLogger.debug(`Profile ${profile.name} authentication method is unkown.`); + await this.chooseAuthProfileManagement(node); + break; + } + } + } + private static AuthQpLabels = { + update: "update-credentials", + edit: "edit-profile", + login: "obtain-token", + logout: "invalidate-token", + }; + private static editProfileQpItem: Record = { + [this.AuthQpLabels.edit]: { + label: localize("editProfileQpItem.editProfile.qpLabel", "$(pencil) Edit profile"), + description: localize("editProfileQpItem.editProfile.qpDetail", "Update profile connection information"), + }, + }; + private static updateBasicAuthQpItem: Record = { + [this.AuthQpLabels.update]: { + label: localize("updateBasicAuthQpItem.updateCredentials.qpLabel", "$(refresh) Update Credentials"), + description: localize("updateBasicAuthQpItem.updateCredentials.qpDetail", "Update stored username and password"), + }, + }; + private static addBasicAuthQpItem: Record = { + [this.AuthQpLabels.update]: { + label: localize("addBasicAuthQpItem.addCredentials.qpLabel", "$(plus) Add Credentials"), + description: localize("addBasicAuthQpItem.addCredentials.qpDetail", "Add username and password for basic authentication"), + }, + }; + private static loginQpItem: Record = { + [this.AuthQpLabels.login]: { + label: localize("loginQpItem.login.qpLabel", "$(arrow-right) Log in to authentication service"), + description: localize("loginQpItem.login.qpDetail", "Log in to obtain a new token value"), + }, + }; + private static logoutQpItem: Record = { + [this.AuthQpLabels.logout]: { + label: localize("logoutQpItem.logout.qpLabel", "$(arrow-left) Log out of authentication service"), + description: localize("logoutQpItem.logout.qpDetail", "Log out to invalidate and remove stored token value"), + }, + }; + + private static async basicAuthProfileManagement(node: IZoweTreeNode): Promise { + const profile = node.getProfile(); + const selected = await this.setupProfileManagementQp(imperative.SessConstants.AUTH_TYPE_BASIC, profile); + await this.handleAuthSelection(selected, node, profile); + } + private static async tokenAuthProfileManagement(node: IZoweTreeNode): Promise { + const profile = node.getProfile(); + const selected = await this.setupProfileManagementQp("token", profile); + await this.handleAuthSelection(selected, node, profile); + } + private static async chooseAuthProfileManagement(node: IZoweTreeNode): Promise { + const profile = node.getProfile(); + const selected = await this.setupProfileManagementQp(null, profile); + await this.handleAuthSelection(selected, node, profile); + } + private static async setupProfileManagementQp(managementType: string, profile: imperative.IProfileLoaded): Promise { + const qp = Gui.createQuickPick(); + let quickPickOptions: vscode.QuickPickItem[]; + switch (managementType) { + case imperative.SessConstants.AUTH_TYPE_BASIC: { + quickPickOptions = this.basicAuthQp(); + qp.placeholder = this.qpPlaceholders.basicAuth; + break; + } + case "token": { + quickPickOptions = this.tokenAuthQp(profile); + qp.placeholder = this.qpPlaceholders.tokenAuth; + break; + } + default: { + quickPickOptions = this.chooseAuthQp(); + qp.placeholder = this.qpPlaceholders.chooseAuth; + break; + } + } + let selectedItem = quickPickOptions[0]; + qp.items = quickPickOptions; + qp.activeItems = [selectedItem]; + qp.show(); + selectedItem = await Gui.resolveQuickPick(qp); + qp.hide(); + return selectedItem; + } + private static async handleAuthSelection(selected: vscode.QuickPickItem, node: IZoweTreeNode, profile: imperative.IProfileLoaded): Promise { + switch (selected) { + case this.loginQpItem[this.AuthQpLabels.login]: { + await Profiles.getInstance().ssoLogin(node, profile.name); + break; + } + case this.editProfileQpItem[this.AuthQpLabels.edit]: { + await Profiles.getInstance().editSession(profile, profile.name); + break; + } + case this.logoutQpItem[this.AuthQpLabels.logout]: { + await Profiles.getInstance().ssoLogout(node); + break; + } + case this.updateBasicAuthQpItem[this.AuthQpLabels.update]: { + await ProfilesUtils.promptCredentials(node); + break; + } + default: { + Gui.infoMessage(localize("profiles.operation.cancelled", "Operation Cancelled")); + break; + } + } + } + + private static qpPlaceholders = { + basicAuth: localize("qpPlaceholders.qp.basic", "Profile is using basic authentication. Choose a profile action."), + tokenAuth: localize("qpPlaceholders.qp.token", "Profile is using token authentication. Choose a profile action."), + chooseAuth: localize("qpPlaceholders.qp.choose", "Profile doesn't specify an authentication method. Choose a profile action."), + }; + + private static basicAuthQp(): vscode.QuickPickItem[] { + const quickPickOptions: vscode.QuickPickItem[] = Object.values(this.updateBasicAuthQpItem); + quickPickOptions.push(this.editProfileQpItem[this.AuthQpLabels.edit]); + return quickPickOptions; + } + private static tokenAuthQp(profile: imperative.IProfileLoaded): vscode.QuickPickItem[] { + const quickPickOptions: vscode.QuickPickItem[] = Object.values(this.loginQpItem); + if (profile.profile.tokenType) { + quickPickOptions.push(this.logoutQpItem[this.AuthQpLabels.logout]); + } + quickPickOptions.push(this.editProfileQpItem[this.AuthQpLabels.edit]); + return quickPickOptions; + } + private static chooseAuthQp(): vscode.QuickPickItem[] { + const quickPickOptions: vscode.QuickPickItem[] = Object.values(this.addBasicAuthQpItem); + quickPickOptions.push(this.loginQpItem[this.AuthQpLabels.login]); + quickPickOptions.push(this.editProfileQpItem[this.AuthQpLabels.edit]); + return quickPickOptions; + } +} diff --git a/packages/zowe-explorer/src/utils/ProfilesUtils.ts b/packages/zowe-explorer/src/utils/ProfilesUtils.ts index 8bfa3fdaf4..2a8dd2979a 100644 --- a/packages/zowe-explorer/src/utils/ProfilesUtils.ts +++ b/packages/zowe-explorer/src/utils/ProfilesUtils.ts @@ -307,25 +307,6 @@ export class ProfilesUtils { } } - public static async manageProfile(node: IZoweTreeNode): Promise { - const profile = node.getProfile(); - switch (true) { - case this.isProfileUsingBasicAuth(profile): { - await this.basicAuthProfileManagement(node); - break; - } - case await this.isUsingTokenAuth(profile.name): { - await this.tokenAuthProfileManagement(node); - break; - } - // will need a case for isUsingCertAuth - default: { - await this.chooseAuthProfileManagement(node); - break; - } - } - } - /** * Function that checks whether a profile is using basic authentication * @param profile @@ -510,137 +491,6 @@ export class ProfilesUtils { Gui.errorMessage(err.message); } } - - private static AuthQpLabels = { - update: "update-credentials", - edit: "edit-profile", - login: "obtain-token", - logout: "invalidate-token", - }; - private static editProfileQpItem: Record = { - [this.AuthQpLabels.edit]: { - label: localize("editProfileQpItem.editProfile.qpLabel", "$(pencil) Edit profile"), - description: localize("editProfileQpItem.editProfile.qpDetail", "Update profile connection information"), - }, - }; - private static updateBasicAuthQpItem: Record = { - [this.AuthQpLabels.update]: { - label: localize("updateBasicAuthQpItem.updateCredentials.qpLabel", "$(refresh) Update Credentials"), - description: localize("updateBasicAuthQpItem.updateCredentials.qpDetail", "Update stored username and password"), - }, - }; - private static addBasicAuthQpItem: Record = { - [this.AuthQpLabels.update]: { - label: localize("addBasicAuthQpItem.addCredentials.qpLabel", "$(plus) Add Credentials"), - description: localize("addBasicAuthQpItem.addCredentials.qpDetail", "Add username and password for basic authentication"), - }, - }; - private static loginQpItem: Record = { - [this.AuthQpLabels.login]: { - label: localize("loginQpItem.login.qpLabel", "$(arrow-right) Login to authentication service"), - description: localize("loginQpItem.login.qpDetail", "Login to obtain and update stored token value"), - }, - }; - private static logoutQpItem: Record = { - [this.AuthQpLabels.logout]: { - label: localize("logoutQpItem.logout.qpLabel", "$(arrow-left) Log out of authentication service"), - description: localize("logoutQpItem.logout.qpDetail", "Log out to invalidate and remove stored token value"), - }, - }; - - private static async basicAuthProfileManagement(node: IZoweTreeNode): Promise { - const profile = node.getProfile(); - const selected = await this.setupProfileManagementQp(imperative.SessConstants.AUTH_TYPE_BASIC, profile); - await this.handleAuthSelection(selected, node, profile); - } - private static async tokenAuthProfileManagement(node: IZoweTreeNode): Promise { - const profile = node.getProfile(); - const selected = await this.setupProfileManagementQp("token", profile); - await this.handleAuthSelection(selected, node, profile); - } - private static async chooseAuthProfileManagement(node: IZoweTreeNode): Promise { - const profile = node.getProfile(); - const selected = await this.setupProfileManagementQp(null, profile); - await this.handleAuthSelection(selected, node, profile); - } - private static async setupProfileManagementQp(managementType: string, profile: imperative.IProfileLoaded): Promise { - const qp = Gui.createQuickPick(); - let quickPickOptions: vscode.QuickPickItem[]; - switch (managementType) { - case imperative.SessConstants.AUTH_TYPE_BASIC: { - quickPickOptions = this.basicAuthQp(); - qp.placeholder = this.qpPlaceholders.basicAuth; - break; - } - case "token": { - quickPickOptions = this.tokenAuthQp(profile); - qp.placeholder = this.qpPlaceholders.tokenAuth; - break; - } - default: { - quickPickOptions = this.chooseAuthQp(); - qp.placeholder = this.qpPlaceholders.chooseAuth; - break; - } - } - let selectedItem = quickPickOptions[0]; - qp.items = quickPickOptions; - qp.activeItems = [selectedItem]; - qp.show(); - selectedItem = await Gui.resolveQuickPick(qp); - qp.hide(); - return selectedItem; - } - private static async handleAuthSelection(selected: vscode.QuickPickItem, node: IZoweTreeNode, profile: imperative.IProfileLoaded): Promise { - switch (selected) { - case this.loginQpItem[this.AuthQpLabels.login]: { - await Profiles.getInstance().ssoLogin(node, profile.name); - break; - } - case this.editProfileQpItem[this.AuthQpLabels.edit]: { - await Profiles.getInstance().editSession(profile, profile.name); - break; - } - case this.logoutQpItem[this.AuthQpLabels.logout]: { - await Profiles.getInstance().ssoLogout(node); - break; - } - case this.updateBasicAuthQpItem[this.AuthQpLabels.update]: { - await this.promptCredentials(node); - break; - } - default: { - Gui.infoMessage(localize("profiles.operation.cancelled", "Operation Cancelled")); - break; - } - } - } - - private static qpPlaceholders = { - basicAuth: localize("qpPlaceholders.qp.basic", "Profile is using basic authentication. Choose a profile action."), - tokenAuth: localize("qpPlaceholders.qp.token", "Profile is using token authentication. Choose a profile action."), - chooseAuth: localize("qpPlaceholders.qp.choose", "Profile doesn't specify an authentication method. Choose a profile action."), - }; - - private static basicAuthQp(): vscode.QuickPickItem[] { - const quickPickOptions: vscode.QuickPickItem[] = Object.values(this.updateBasicAuthQpItem); - quickPickOptions.push(this.editProfileQpItem[this.AuthQpLabels.edit]); - return quickPickOptions; - } - private static tokenAuthQp(profile: imperative.IProfileLoaded): vscode.QuickPickItem[] { - const quickPickOptions: vscode.QuickPickItem[] = Object.values(this.loginQpItem); - if (profile.profile.tokenType) { - quickPickOptions.push(this.logoutQpItem[this.AuthQpLabels.logout]); - } - quickPickOptions.push(this.editProfileQpItem[this.AuthQpLabels.edit]); - return quickPickOptions; - } - private static chooseAuthQp(): vscode.QuickPickItem[] { - const quickPickOptions: vscode.QuickPickItem[] = Object.values(this.addBasicAuthQpItem); - quickPickOptions.push(this.loginQpItem[this.AuthQpLabels.login]); - quickPickOptions.push(this.editProfileQpItem[this.AuthQpLabels.edit]); - return quickPickOptions; - } } /** From 61a021ad8d8b93c17a854945beb9c75238be50db Mon Sep 17 00:00:00 2001 From: Billie Simmons <49491949+JillieBeanSim@users.noreply.github.com> Date: Fri, 22 Sep 2023 11:34:24 -0400 Subject: [PATCH 035/189] update check and strings in Profiles.ssoLogin Signed-off-by: Billie Simmons <49491949+JillieBeanSim@users.noreply.github.com> --- packages/zowe-explorer/i18n/sample/src/Profiles.i18n.json | 4 +++- packages/zowe-explorer/src/Profiles.ts | 8 +++++--- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/packages/zowe-explorer/i18n/sample/src/Profiles.i18n.json b/packages/zowe-explorer/i18n/sample/src/Profiles.i18n.json index 8c54f161a0..db8a613b65 100644 --- a/packages/zowe-explorer/i18n/sample/src/Profiles.i18n.json +++ b/packages/zowe-explorer/i18n/sample/src/Profiles.i18n.json @@ -26,9 +26,11 @@ "validateProfiles.progress": "Validating {0} Profile.", "validateProfiles.cancelled": "Validating {0} was cancelled.", "validateProfiles.error": "Profile validation failed for {0}.", - "ssoAuth.noBase": "This profile does not support token authentication.", + "ssoLogin.usingBasicAuth": "This profile is using basic authentication and does not support token authentication.", + "ssoLogin.tokenType.error": "Error getting supported tokenType value for profile {0}", "ssoLogin.successful": "Login to authentication service was successful.", "ssoLogin.error": "Unable to log in with {0}. {1}", + "ssoAuth.noBase": "This profile does not support token authentication.", "ssoLogout.successful": "Logout from authentication service was successful for {0}.", "ssoLogout.error": "Unable to log out with {0}. {1}", "getConfigLocationPrompt.placeholder.create": "Select the location where the config file will be initialized", diff --git a/packages/zowe-explorer/src/Profiles.ts b/packages/zowe-explorer/src/Profiles.ts index 47a70a00e4..90c886e27c 100644 --- a/packages/zowe-explorer/src/Profiles.ts +++ b/packages/zowe-explorer/src/Profiles.ts @@ -1165,8 +1165,10 @@ export class Profiles extends ProfilesCache { serviceProfile = this.loadNamedProfile(label.trim()); } // This check will handle service profiles that have username and password - if (serviceProfile.profile.user && serviceProfile.profile.password) { - Gui.showMessage(localize("ssoAuth.noBase", "This profile does not support token authentication.")); + if (ProfilesUtils.isProfileUsingBasicAuth(serviceProfile)) { + Gui.showMessage( + localize("ssoLogin.usingBasicAuth", "This profile is using basic authentication and does not support token authentication.") + ); return; } @@ -1174,7 +1176,7 @@ export class Profiles extends ProfilesCache { loginTokenType = await ZoweExplorerApiRegister.getInstance().getCommonApi(serviceProfile).getTokenTypeName(); } catch (error) { ZoweLogger.warn(error); - Gui.showMessage(localize("ssoAuth.noBase", "This profile does not support token authentication.")); + Gui.showMessage(localize("ssoLogin.tokenType.error", "Error getting supported tokenType value for profile {0}", serviceProfile.name)); return; } try { From 0245bb769b8983ac3d0c41dac99d14f7212f1eb9 Mon Sep 17 00:00:00 2001 From: Billie Simmons <49491949+JillieBeanSim@users.noreply.github.com> Date: Fri, 22 Sep 2023 15:16:23 -0400 Subject: [PATCH 036/189] clean up and add some unit tests Signed-off-by: Billie Simmons <49491949+JillieBeanSim@users.noreply.github.com> --- .../utils/ProfileManagement.unit.test.ts | 100 +++++++++++++++++ .../i18n/sample/src/Profiles.i18n.json | 3 +- .../src/utils/ProfileManagement.i18n.json | 16 +-- packages/zowe-explorer/src/Profiles.ts | 8 +- .../src/utils/ProfileManagement.ts | 102 +++++++++--------- 5 files changed, 162 insertions(+), 67 deletions(-) create mode 100644 packages/zowe-explorer/__tests__/__unit__/utils/ProfileManagement.unit.test.ts diff --git a/packages/zowe-explorer/__tests__/__unit__/utils/ProfileManagement.unit.test.ts b/packages/zowe-explorer/__tests__/__unit__/utils/ProfileManagement.unit.test.ts new file mode 100644 index 0000000000..e93bc43d92 --- /dev/null +++ b/packages/zowe-explorer/__tests__/__unit__/utils/ProfileManagement.unit.test.ts @@ -0,0 +1,100 @@ +/** + * This program and the accompanying materials are made available under the terms of the + * Eclipse Public License v2.0 which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-v20.html + * + * SPDX-License-Identifier: EPL-2.0 + * + * Copyright Contributors to the Zowe Project. + * + */ + +import { ZoweDatasetNode } from "../../../src/dataset/ZoweDatasetNode"; +import * as sharedMock from "../../../__mocks__/mockCreators/shared"; +import * as dsMock from "../../../__mocks__/mockCreators/datasets"; +import * as profUtils from "../../../src/utils/ProfilesUtils"; +import { ProfileManagement } from "../../../src/utils/ProfileManagement"; +import { Gui } from "@zowe/zowe-explorer-api"; +import { ZoweLogger } from "../../../src/utils/LoggerUtils"; + +jest.mock("fs"); +jest.mock("vscode"); +jest.mock("@zowe/cli"); + +describe("ProfileManagement unit tests", () => { + afterEach(() => { + jest.clearAllMocks(); + }); + function createGlobalMocks() { + const newMocks = { + mockSession: sharedMock.createISession(), + mockBasicAuthProfile: sharedMock.createValidIProfile(), + mockDsSessionNode: ZoweDatasetNode, + mockUpdateChosen: null as any, + mockAddBasicChosen: null as any, + mockLoginChosen: null as any, + mockLogoutChosen: null as any, + mockEditProfChosen: null as any, + mockCreateQp: jest.fn(), + debugLogSpy: null as any, + }; + newMocks.mockDsSessionNode = dsMock.createDatasetSessionNode(newMocks.mockSession, newMocks.mockBasicAuthProfile) as any; + Object.defineProperty(newMocks.mockDsSessionNode, "getProfile", { + value: jest.fn().mockReturnValue(newMocks.mockBasicAuthProfile), + configurable: true, + }); + newMocks.mockUpdateChosen = ProfileManagement.basicAuthQpItems[ProfileManagement.AuthQpLabels.update]; + newMocks.mockAddBasicChosen = ProfileManagement.basicAuthQpItems[ProfileManagement.AuthQpLabels.add]; + newMocks.mockLoginChosen = ProfileManagement.tokenAuthQpItems[ProfileManagement.AuthQpLabels.login]; + newMocks.mockLogoutChosen = ProfileManagement.tokenAuthQpItems[ProfileManagement.AuthQpLabels.logout]; + newMocks.mockEditProfChosen = ProfileManagement.otherProfileQpItems[ProfileManagement.AuthQpLabels.edit]; + newMocks.mockCreateQp.mockReturnValue({ + show: jest.fn(() => { + return {}; + }), + hide: jest.fn(() => { + return {}; + }), + onDidAccept: jest.fn(() => { + return {}; + }), + }); + Object.defineProperty(profUtils.ProfilesUtils, "promptCredentials", { value: jest.fn(), configurable: true }); + Object.defineProperty(Gui, "createQuickPick", { value: jest.fn(), configurable: true }); + Object.defineProperty(Gui, "createQuickPick", { value: newMocks.mockCreateQp, configurable: true }); + Object.defineProperty(ZoweLogger, "debug", { value: jest.fn(), configurable: true }); + newMocks.debugLogSpy = jest.spyOn(ZoweLogger, "debug"); + // Object.defineProperty(profUtils.ProfilesUtils, "isUsingTokenAuth", { value: jest.fn().mockResolvedValueOnce(false), configurable: true }); + + return newMocks; + } + afterEach(() => { + jest.clearAllMocks(); + jest.resetAllMocks(); + }); + it("profile using basic authentication should see Operation Cancelled when escaping quick pick", async () => { + const globalMocks = createGlobalMocks(); + const logMsg = `Profile ${globalMocks.mockBasicAuthProfile.name} is using basic authentication.`; + Object.defineProperty(Gui, "resolveQuickPick", { value: jest.fn().mockResolvedValueOnce(undefined), configurable: true }); + const updateSpy = jest.spyOn(profUtils.ProfilesUtils, "promptCredentials"); + const opCancelledSpy = jest.spyOn(Gui, "infoMessage"); + await ProfileManagement.manageProfile(globalMocks.mockDsSessionNode as any); + expect(globalMocks.debugLogSpy).toBeCalledWith(logMsg); + expect(updateSpy).not.toBeCalled(); + expect(opCancelledSpy).toBeCalledWith("Operation Cancelled"); + globalMocks.debugLogSpy.mockClear(); + updateSpy.mockClear(); + opCancelledSpy.mockClear(); + }); + it("profile using basic authentication should see promptCredentials called when Update Credentials chosen", async () => { + const globalMocks = createGlobalMocks(); + const logMsg = `Profile ${globalMocks.mockBasicAuthProfile.name} is using basic authentication.`; + Object.defineProperty(Gui, "resolveQuickPick", { value: jest.fn().mockResolvedValueOnce(globalMocks.mockUpdateChosen), configurable: true }); + const scenarioSpy = jest.spyOn(profUtils.ProfilesUtils, "promptCredentials"); + await ProfileManagement.manageProfile(globalMocks.mockDsSessionNode as any); + expect(globalMocks.debugLogSpy).toBeCalledWith(logMsg); + expect(scenarioSpy).toBeCalled(); + globalMocks.debugLogSpy.mockClear(); + scenarioSpy.mockClear(); + }); +}); diff --git a/packages/zowe-explorer/i18n/sample/src/Profiles.i18n.json b/packages/zowe-explorer/i18n/sample/src/Profiles.i18n.json index db8a613b65..b48fbc4ab9 100644 --- a/packages/zowe-explorer/i18n/sample/src/Profiles.i18n.json +++ b/packages/zowe-explorer/i18n/sample/src/Profiles.i18n.json @@ -26,11 +26,10 @@ "validateProfiles.progress": "Validating {0} Profile.", "validateProfiles.cancelled": "Validating {0} was cancelled.", "validateProfiles.error": "Profile validation failed for {0}.", - "ssoLogin.usingBasicAuth": "This profile is using basic authentication and does not support token authentication.", + "ssoAuth.usingBasicAuth": "This profile is using basic authentication and does not support token authentication.", "ssoLogin.tokenType.error": "Error getting supported tokenType value for profile {0}", "ssoLogin.successful": "Login to authentication service was successful.", "ssoLogin.error": "Unable to log in with {0}. {1}", - "ssoAuth.noBase": "This profile does not support token authentication.", "ssoLogout.successful": "Logout from authentication service was successful for {0}.", "ssoLogout.error": "Unable to log out with {0}. {1}", "getConfigLocationPrompt.placeholder.create": "Select the location where the config file will be initialized", diff --git a/packages/zowe-explorer/i18n/sample/src/utils/ProfileManagement.i18n.json b/packages/zowe-explorer/i18n/sample/src/utils/ProfileManagement.i18n.json index 05e99d6246..d168f6392d 100644 --- a/packages/zowe-explorer/i18n/sample/src/utils/ProfileManagement.i18n.json +++ b/packages/zowe-explorer/i18n/sample/src/utils/ProfileManagement.i18n.json @@ -1,16 +1,16 @@ { "profiles.operation.cancelled": "Operation Cancelled", - "editProfileQpItem.editProfile.qpLabel": "$(pencil) Edit profile", - "editProfileQpItem.editProfile.qpDetail": "Update profile connection information", - "updateBasicAuthQpItem.updateCredentials.qpLabel": "$(refresh) Update Credentials", - "updateBasicAuthQpItem.updateCredentials.qpDetail": "Update stored username and password", + "qpPlaceholders.qp.basic": "Profile {0} is using basic authentication. Choose a profile action.", + "qpPlaceholders.qp.token": "Profile {0} is using token authentication. Choose a profile action.", + "qpPlaceholders.qp.choose": "Profile {0} doesn't specify an authentication method. Choose a profile action.", "addBasicAuthQpItem.addCredentials.qpLabel": "$(plus) Add Credentials", "addBasicAuthQpItem.addCredentials.qpDetail": "Add username and password for basic authentication", + "updateBasicAuthQpItem.updateCredentials.qpLabel": "$(refresh) Update Credentials", + "updateBasicAuthQpItem.updateCredentials.qpDetail": "Update stored username and password", + "editProfileQpItem.editProfile.qpLabel": "$(pencil) Edit profile", + "editProfileQpItem.editProfile.qpDetail": "Update profile connection information", "loginQpItem.login.qpLabel": "$(arrow-right) Log in to authentication service", "loginQpItem.login.qpDetail": "Log in to obtain a new token value", "logoutQpItem.logout.qpLabel": "$(arrow-left) Log out of authentication service", - "logoutQpItem.logout.qpDetail": "Log out to invalidate and remove stored token value", - "qpPlaceholders.qp.basic": "Profile is using basic authentication. Choose a profile action.", - "qpPlaceholders.qp.token": "Profile is using token authentication. Choose a profile action.", - "qpPlaceholders.qp.choose": "Profile doesn't specify an authentication method. Choose a profile action." + "logoutQpItem.logout.qpDetail": "Log out to invalidate and remove stored token value" } diff --git a/packages/zowe-explorer/src/Profiles.ts b/packages/zowe-explorer/src/Profiles.ts index 90c886e27c..a32d1801af 100644 --- a/packages/zowe-explorer/src/Profiles.ts +++ b/packages/zowe-explorer/src/Profiles.ts @@ -1167,7 +1167,7 @@ export class Profiles extends ProfilesCache { // This check will handle service profiles that have username and password if (ProfilesUtils.isProfileUsingBasicAuth(serviceProfile)) { Gui.showMessage( - localize("ssoLogin.usingBasicAuth", "This profile is using basic authentication and does not support token authentication.") + localize("ssoAuth.usingBasicAuth", "This profile is using basic authentication and does not support token authentication.") ); return; } @@ -1198,8 +1198,10 @@ export class Profiles extends ProfilesCache { ZoweLogger.trace("Profiles.ssoLogout called."); const serviceProfile = node.getProfile(); // This check will handle service profiles that have username and password - if (serviceProfile.profile?.user && serviceProfile.profile?.password) { - Gui.showMessage(localize("ssoAuth.noBase", "This profile does not support token authentication.")); + if (ProfilesUtils.isProfileUsingBasicAuth(serviceProfile)) { + Gui.showMessage( + localize("ssoAuth.usingBasicAuth", "This profile is using basic authentication and does not support token authentication.") + ); return; } try { diff --git a/packages/zowe-explorer/src/utils/ProfileManagement.ts b/packages/zowe-explorer/src/utils/ProfileManagement.ts index 8a4c893561..b39815a2a7 100644 --- a/packages/zowe-explorer/src/utils/ProfileManagement.ts +++ b/packages/zowe-explorer/src/utils/ProfileManagement.ts @@ -26,94 +26,78 @@ const localize: nls.LocalizeFunc = nls.loadMessageBundle(); export class ProfileManagement { public static async manageProfile(node: IZoweTreeNode): Promise { const profile = node.getProfile(); + let selected: vscode.QuickPickItem; switch (true) { case ProfilesUtils.isProfileUsingBasicAuth(profile): { ZoweLogger.debug(`Profile ${profile.name} is using basic authentication.`); - await this.basicAuthProfileManagement(node); + selected = await this.setupProfileManagementQp(imperative.SessConstants.AUTH_TYPE_BASIC, profile); break; } case await ProfilesUtils.isUsingTokenAuth(profile.name): { ZoweLogger.debug(`Profile ${profile.name} is using token authentication.`); - await this.tokenAuthProfileManagement(node); + selected = await this.setupProfileManagementQp("token", profile); break; } // will need a case for isUsingCertAuth default: { ZoweLogger.debug(`Profile ${profile.name} authentication method is unkown.`); - await this.chooseAuthProfileManagement(node); + selected = await this.setupProfileManagementQp(null, profile); break; } } + await this.handleAuthSelection(selected, node, profile); } - private static AuthQpLabels = { + public static AuthQpLabels = { update: "update-credentials", edit: "edit-profile", login: "obtain-token", logout: "invalidate-token", + add: "add-credentials", }; - private static editProfileQpItem: Record = { - [this.AuthQpLabels.edit]: { - label: localize("editProfileQpItem.editProfile.qpLabel", "$(pencil) Edit profile"), - description: localize("editProfileQpItem.editProfile.qpDetail", "Update profile connection information"), + public static basicAuthQpItems: Record = { + [this.AuthQpLabels.add]: { + label: localize("addBasicAuthQpItem.addCredentials.qpLabel", "$(plus) Add Credentials"), + description: localize("addBasicAuthQpItem.addCredentials.qpDetail", "Add username and password for basic authentication"), }, - }; - private static updateBasicAuthQpItem: Record = { [this.AuthQpLabels.update]: { label: localize("updateBasicAuthQpItem.updateCredentials.qpLabel", "$(refresh) Update Credentials"), description: localize("updateBasicAuthQpItem.updateCredentials.qpDetail", "Update stored username and password"), }, }; - private static addBasicAuthQpItem: Record = { - [this.AuthQpLabels.update]: { - label: localize("addBasicAuthQpItem.addCredentials.qpLabel", "$(plus) Add Credentials"), - description: localize("addBasicAuthQpItem.addCredentials.qpDetail", "Add username and password for basic authentication"), + public static otherProfileQpItems: Record = { + [this.AuthQpLabels.edit]: { + label: localize("editProfileQpItem.editProfile.qpLabel", "$(pencil) Edit profile"), + description: localize("editProfileQpItem.editProfile.qpDetail", "Update profile connection information"), }, }; - private static loginQpItem: Record = { + public static tokenAuthQpItems: Record = { [this.AuthQpLabels.login]: { label: localize("loginQpItem.login.qpLabel", "$(arrow-right) Log in to authentication service"), description: localize("loginQpItem.login.qpDetail", "Log in to obtain a new token value"), }, - }; - private static logoutQpItem: Record = { [this.AuthQpLabels.logout]: { label: localize("logoutQpItem.logout.qpLabel", "$(arrow-left) Log out of authentication service"), description: localize("logoutQpItem.logout.qpDetail", "Log out to invalidate and remove stored token value"), }, }; - - private static async basicAuthProfileManagement(node: IZoweTreeNode): Promise { - const profile = node.getProfile(); - const selected = await this.setupProfileManagementQp(imperative.SessConstants.AUTH_TYPE_BASIC, profile); - await this.handleAuthSelection(selected, node, profile); - } - private static async tokenAuthProfileManagement(node: IZoweTreeNode): Promise { - const profile = node.getProfile(); - const selected = await this.setupProfileManagementQp("token", profile); - await this.handleAuthSelection(selected, node, profile); - } - private static async chooseAuthProfileManagement(node: IZoweTreeNode): Promise { - const profile = node.getProfile(); - const selected = await this.setupProfileManagementQp(null, profile); - await this.handleAuthSelection(selected, node, profile); - } private static async setupProfileManagementQp(managementType: string, profile: imperative.IProfileLoaded): Promise { const qp = Gui.createQuickPick(); let quickPickOptions: vscode.QuickPickItem[]; + const placeholders = this.getQpPlaceholders(profile); switch (managementType) { case imperative.SessConstants.AUTH_TYPE_BASIC: { quickPickOptions = this.basicAuthQp(); - qp.placeholder = this.qpPlaceholders.basicAuth; + qp.placeholder = placeholders.basicAuth; break; } case "token": { quickPickOptions = this.tokenAuthQp(profile); - qp.placeholder = this.qpPlaceholders.tokenAuth; + qp.placeholder = placeholders.tokenAuth; break; } default: { quickPickOptions = this.chooseAuthQp(); - qp.placeholder = this.qpPlaceholders.chooseAuth; + qp.placeholder = placeholders.chooseAuth; break; } } @@ -127,19 +111,23 @@ export class ProfileManagement { } private static async handleAuthSelection(selected: vscode.QuickPickItem, node: IZoweTreeNode, profile: imperative.IProfileLoaded): Promise { switch (selected) { - case this.loginQpItem[this.AuthQpLabels.login]: { - await Profiles.getInstance().ssoLogin(node, profile.name); + case this.basicAuthQpItems[this.AuthQpLabels.add]: { + await ProfilesUtils.promptCredentials(node); break; } - case this.editProfileQpItem[this.AuthQpLabels.edit]: { + case this.otherProfileQpItems[this.AuthQpLabels.edit]: { await Profiles.getInstance().editSession(profile, profile.name); break; } - case this.logoutQpItem[this.AuthQpLabels.logout]: { + case this.tokenAuthQpItems[this.AuthQpLabels.login]: { + await Profiles.getInstance().ssoLogin(node, profile.name); + break; + } + case this.tokenAuthQpItems[this.AuthQpLabels.logout]: { await Profiles.getInstance().ssoLogout(node); break; } - case this.updateBasicAuthQpItem[this.AuthQpLabels.update]: { + case this.basicAuthQpItems[this.AuthQpLabels.update]: { await ProfilesUtils.promptCredentials(node); break; } @@ -150,29 +138,35 @@ export class ProfileManagement { } } - private static qpPlaceholders = { - basicAuth: localize("qpPlaceholders.qp.basic", "Profile is using basic authentication. Choose a profile action."), - tokenAuth: localize("qpPlaceholders.qp.token", "Profile is using token authentication. Choose a profile action."), - chooseAuth: localize("qpPlaceholders.qp.choose", "Profile doesn't specify an authentication method. Choose a profile action."), - }; + private static getQpPlaceholders(profile: imperative.IProfileLoaded) { + return { + basicAuth: localize("qpPlaceholders.qp.basic", "Profile {0} is using basic authentication. Choose a profile action.", profile.name), + tokenAuth: localize("qpPlaceholders.qp.token", "Profile {0} is using token authentication. Choose a profile action.", profile.name), + chooseAuth: localize( + "qpPlaceholders.qp.choose", + "Profile {0} doesn't specify an authentication method. Choose a profile action.", + profile.name + ), + }; + } private static basicAuthQp(): vscode.QuickPickItem[] { - const quickPickOptions: vscode.QuickPickItem[] = Object.values(this.updateBasicAuthQpItem); - quickPickOptions.push(this.editProfileQpItem[this.AuthQpLabels.edit]); + const quickPickOptions: vscode.QuickPickItem[] = Object.values(this.basicAuthQpItems[this.AuthQpLabels.update]); + quickPickOptions.push(this.otherProfileQpItems[this.AuthQpLabels.edit]); return quickPickOptions; } private static tokenAuthQp(profile: imperative.IProfileLoaded): vscode.QuickPickItem[] { - const quickPickOptions: vscode.QuickPickItem[] = Object.values(this.loginQpItem); + const quickPickOptions: vscode.QuickPickItem[] = Object.values(this.tokenAuthQpItems[this.AuthQpLabels.login]); if (profile.profile.tokenType) { - quickPickOptions.push(this.logoutQpItem[this.AuthQpLabels.logout]); + quickPickOptions.push(this.tokenAuthQpItems[this.AuthQpLabels.logout]); } - quickPickOptions.push(this.editProfileQpItem[this.AuthQpLabels.edit]); + quickPickOptions.push(this.otherProfileQpItems[this.AuthQpLabels.edit]); return quickPickOptions; } private static chooseAuthQp(): vscode.QuickPickItem[] { - const quickPickOptions: vscode.QuickPickItem[] = Object.values(this.addBasicAuthQpItem); - quickPickOptions.push(this.loginQpItem[this.AuthQpLabels.login]); - quickPickOptions.push(this.editProfileQpItem[this.AuthQpLabels.edit]); + const quickPickOptions: vscode.QuickPickItem[] = Object.values(this.basicAuthQpItems[this.AuthQpLabels.add]); + quickPickOptions.push(this.tokenAuthQpItems[this.AuthQpLabels.login]); + quickPickOptions.push(this.otherProfileQpItems[this.AuthQpLabels.edit]); return quickPickOptions; } } From 3444400fd18c7f9a4e75054bc85161f953966785 Mon Sep 17 00:00:00 2001 From: Billie Simmons <49491949+JillieBeanSim@users.noreply.github.com> Date: Fri, 22 Sep 2023 15:29:44 -0400 Subject: [PATCH 037/189] fix qp labels I broke Signed-off-by: Billie Simmons <49491949+JillieBeanSim@users.noreply.github.com> --- .../utils/ProfileManagement.unit.test.ts | 9 +++--- .../src/utils/ProfileManagement.ts | 28 +++++++++++-------- 2 files changed, 20 insertions(+), 17 deletions(-) diff --git a/packages/zowe-explorer/__tests__/__unit__/utils/ProfileManagement.unit.test.ts b/packages/zowe-explorer/__tests__/__unit__/utils/ProfileManagement.unit.test.ts index e93bc43d92..9f3997a0d9 100644 --- a/packages/zowe-explorer/__tests__/__unit__/utils/ProfileManagement.unit.test.ts +++ b/packages/zowe-explorer/__tests__/__unit__/utils/ProfileManagement.unit.test.ts @@ -43,10 +43,10 @@ describe("ProfileManagement unit tests", () => { value: jest.fn().mockReturnValue(newMocks.mockBasicAuthProfile), configurable: true, }); - newMocks.mockUpdateChosen = ProfileManagement.basicAuthQpItems[ProfileManagement.AuthQpLabels.update]; - newMocks.mockAddBasicChosen = ProfileManagement.basicAuthQpItems[ProfileManagement.AuthQpLabels.add]; - newMocks.mockLoginChosen = ProfileManagement.tokenAuthQpItems[ProfileManagement.AuthQpLabels.login]; - newMocks.mockLogoutChosen = ProfileManagement.tokenAuthQpItems[ProfileManagement.AuthQpLabels.logout]; + newMocks.mockUpdateChosen = ProfileManagement.basicAuthUpdateQpItems[ProfileManagement.AuthQpLabels.update]; + newMocks.mockAddBasicChosen = ProfileManagement.basicAuthAddQpItems[ProfileManagement.AuthQpLabels.add]; + newMocks.mockLoginChosen = ProfileManagement.tokenAuthLoginQpItem[ProfileManagement.AuthQpLabels.login]; + newMocks.mockLogoutChosen = ProfileManagement.tokenAuthLogoutQpItem[ProfileManagement.AuthQpLabels.logout]; newMocks.mockEditProfChosen = ProfileManagement.otherProfileQpItems[ProfileManagement.AuthQpLabels.edit]; newMocks.mockCreateQp.mockReturnValue({ show: jest.fn(() => { @@ -60,7 +60,6 @@ describe("ProfileManagement unit tests", () => { }), }); Object.defineProperty(profUtils.ProfilesUtils, "promptCredentials", { value: jest.fn(), configurable: true }); - Object.defineProperty(Gui, "createQuickPick", { value: jest.fn(), configurable: true }); Object.defineProperty(Gui, "createQuickPick", { value: newMocks.mockCreateQp, configurable: true }); Object.defineProperty(ZoweLogger, "debug", { value: jest.fn(), configurable: true }); newMocks.debugLogSpy = jest.spyOn(ZoweLogger, "debug"); diff --git a/packages/zowe-explorer/src/utils/ProfileManagement.ts b/packages/zowe-explorer/src/utils/ProfileManagement.ts index b39815a2a7..efb5f69477 100644 --- a/packages/zowe-explorer/src/utils/ProfileManagement.ts +++ b/packages/zowe-explorer/src/utils/ProfileManagement.ts @@ -54,11 +54,13 @@ export class ProfileManagement { logout: "invalidate-token", add: "add-credentials", }; - public static basicAuthQpItems: Record = { + public static basicAuthAddQpItems: Record = { [this.AuthQpLabels.add]: { label: localize("addBasicAuthQpItem.addCredentials.qpLabel", "$(plus) Add Credentials"), description: localize("addBasicAuthQpItem.addCredentials.qpDetail", "Add username and password for basic authentication"), }, + }; + public static basicAuthUpdateQpItems: Record = { [this.AuthQpLabels.update]: { label: localize("updateBasicAuthQpItem.updateCredentials.qpLabel", "$(refresh) Update Credentials"), description: localize("updateBasicAuthQpItem.updateCredentials.qpDetail", "Update stored username and password"), @@ -70,11 +72,13 @@ export class ProfileManagement { description: localize("editProfileQpItem.editProfile.qpDetail", "Update profile connection information"), }, }; - public static tokenAuthQpItems: Record = { + public static tokenAuthLoginQpItem: Record = { [this.AuthQpLabels.login]: { label: localize("loginQpItem.login.qpLabel", "$(arrow-right) Log in to authentication service"), description: localize("loginQpItem.login.qpDetail", "Log in to obtain a new token value"), }, + }; + public static tokenAuthLogoutQpItem: Record = { [this.AuthQpLabels.logout]: { label: localize("logoutQpItem.logout.qpLabel", "$(arrow-left) Log out of authentication service"), description: localize("logoutQpItem.logout.qpDetail", "Log out to invalidate and remove stored token value"), @@ -111,7 +115,7 @@ export class ProfileManagement { } private static async handleAuthSelection(selected: vscode.QuickPickItem, node: IZoweTreeNode, profile: imperative.IProfileLoaded): Promise { switch (selected) { - case this.basicAuthQpItems[this.AuthQpLabels.add]: { + case this.basicAuthAddQpItems[this.AuthQpLabels.add]: { await ProfilesUtils.promptCredentials(node); break; } @@ -119,15 +123,15 @@ export class ProfileManagement { await Profiles.getInstance().editSession(profile, profile.name); break; } - case this.tokenAuthQpItems[this.AuthQpLabels.login]: { + case this.tokenAuthLoginQpItem[this.AuthQpLabels.login]: { await Profiles.getInstance().ssoLogin(node, profile.name); break; } - case this.tokenAuthQpItems[this.AuthQpLabels.logout]: { + case this.tokenAuthLogoutQpItem[this.AuthQpLabels.logout]: { await Profiles.getInstance().ssoLogout(node); break; } - case this.basicAuthQpItems[this.AuthQpLabels.update]: { + case this.basicAuthUpdateQpItems[this.AuthQpLabels.update]: { await ProfilesUtils.promptCredentials(node); break; } @@ -138,7 +142,7 @@ export class ProfileManagement { } } - private static getQpPlaceholders(profile: imperative.IProfileLoaded) { + private static getQpPlaceholders(profile: imperative.IProfileLoaded): { basicAuth: string; tokenAuth: string; chooseAuth: string } { return { basicAuth: localize("qpPlaceholders.qp.basic", "Profile {0} is using basic authentication. Choose a profile action.", profile.name), tokenAuth: localize("qpPlaceholders.qp.token", "Profile {0} is using token authentication. Choose a profile action.", profile.name), @@ -151,21 +155,21 @@ export class ProfileManagement { } private static basicAuthQp(): vscode.QuickPickItem[] { - const quickPickOptions: vscode.QuickPickItem[] = Object.values(this.basicAuthQpItems[this.AuthQpLabels.update]); + const quickPickOptions: vscode.QuickPickItem[] = Object.values(this.basicAuthUpdateQpItems); quickPickOptions.push(this.otherProfileQpItems[this.AuthQpLabels.edit]); return quickPickOptions; } private static tokenAuthQp(profile: imperative.IProfileLoaded): vscode.QuickPickItem[] { - const quickPickOptions: vscode.QuickPickItem[] = Object.values(this.tokenAuthQpItems[this.AuthQpLabels.login]); + const quickPickOptions: vscode.QuickPickItem[] = Object.values(this.tokenAuthLoginQpItem); if (profile.profile.tokenType) { - quickPickOptions.push(this.tokenAuthQpItems[this.AuthQpLabels.logout]); + quickPickOptions.push(this.tokenAuthLogoutQpItem[this.AuthQpLabels.logout]); } quickPickOptions.push(this.otherProfileQpItems[this.AuthQpLabels.edit]); return quickPickOptions; } private static chooseAuthQp(): vscode.QuickPickItem[] { - const quickPickOptions: vscode.QuickPickItem[] = Object.values(this.basicAuthQpItems[this.AuthQpLabels.add]); - quickPickOptions.push(this.tokenAuthQpItems[this.AuthQpLabels.login]); + const quickPickOptions: vscode.QuickPickItem[] = Object.values(this.basicAuthAddQpItems); + quickPickOptions.push(this.tokenAuthLoginQpItem[this.AuthQpLabels.login]); quickPickOptions.push(this.otherProfileQpItems[this.AuthQpLabels.edit]); return quickPickOptions; } From b5139a5343c83400b79ad9a671488e5daff99aeb Mon Sep 17 00:00:00 2001 From: Billie Simmons <49491949+JillieBeanSim@users.noreply.github.com> Date: Fri, 22 Sep 2023 16:42:49 -0400 Subject: [PATCH 038/189] add unit tests Signed-off-by: Billie Simmons <49491949+JillieBeanSim@users.noreply.github.com> --- .../__mocks__/mockCreators/shared.ts | 18 ++ .../utils/ProfileManagement.unit.test.ts | 259 +++++++++++++++--- 2 files changed, 245 insertions(+), 32 deletions(-) diff --git a/packages/zowe-explorer/__mocks__/mockCreators/shared.ts b/packages/zowe-explorer/__mocks__/mockCreators/shared.ts index 1133c38687..82b4039698 100644 --- a/packages/zowe-explorer/__mocks__/mockCreators/shared.ts +++ b/packages/zowe-explorer/__mocks__/mockCreators/shared.ts @@ -218,6 +218,24 @@ export function createValidIProfile(): imperative.IProfileLoaded { }; } +export function createTokenAuthIProfile(): imperative.IProfileLoaded { + return { + name: "sestest", + profile: { + type: "zosmf", + host: "test", + port: 1443, + rejectUnauthorized: false, + tokenType: "apimlAuthenticationToken", + tokenValue: "stringofletters", + name: "testName", + }, + type: "zosmf", + message: "", + failNotFound: false, + }; +} + export function createAltTypeIProfile(): imperative.IProfileLoaded { return { name: "altTypeProfile", diff --git a/packages/zowe-explorer/__tests__/__unit__/utils/ProfileManagement.unit.test.ts b/packages/zowe-explorer/__tests__/__unit__/utils/ProfileManagement.unit.test.ts index 9f3997a0d9..e324c714aa 100644 --- a/packages/zowe-explorer/__tests__/__unit__/utils/ProfileManagement.unit.test.ts +++ b/packages/zowe-explorer/__tests__/__unit__/utils/ProfileManagement.unit.test.ts @@ -16,6 +16,7 @@ import * as profUtils from "../../../src/utils/ProfilesUtils"; import { ProfileManagement } from "../../../src/utils/ProfileManagement"; import { Gui } from "@zowe/zowe-explorer-api"; import { ZoweLogger } from "../../../src/utils/LoggerUtils"; +import { Profiles } from "../../../src/Profiles"; jest.mock("fs"); jest.mock("vscode"); @@ -24,11 +25,14 @@ jest.mock("@zowe/cli"); describe("ProfileManagement unit tests", () => { afterEach(() => { jest.clearAllMocks(); + jest.resetAllMocks(); }); function createGlobalMocks() { const newMocks = { mockSession: sharedMock.createISession(), mockBasicAuthProfile: sharedMock.createValidIProfile(), + mockTokenAuthProfile: sharedMock.createTokenAuthIProfile(), + mockNoAuthProfile: sharedMock.createInvalidIProfile(), mockDsSessionNode: ZoweDatasetNode, mockUpdateChosen: null as any, mockAddBasicChosen: null as any, @@ -37,12 +41,8 @@ describe("ProfileManagement unit tests", () => { mockEditProfChosen: null as any, mockCreateQp: jest.fn(), debugLogSpy: null as any, + opCancelledSpy: jest.spyOn(Gui, "infoMessage"), }; - newMocks.mockDsSessionNode = dsMock.createDatasetSessionNode(newMocks.mockSession, newMocks.mockBasicAuthProfile) as any; - Object.defineProperty(newMocks.mockDsSessionNode, "getProfile", { - value: jest.fn().mockReturnValue(newMocks.mockBasicAuthProfile), - configurable: true, - }); newMocks.mockUpdateChosen = ProfileManagement.basicAuthUpdateQpItems[ProfileManagement.AuthQpLabels.update]; newMocks.mockAddBasicChosen = ProfileManagement.basicAuthAddQpItems[ProfileManagement.AuthQpLabels.add]; newMocks.mockLoginChosen = ProfileManagement.tokenAuthLoginQpItem[ProfileManagement.AuthQpLabels.login]; @@ -63,37 +63,232 @@ describe("ProfileManagement unit tests", () => { Object.defineProperty(Gui, "createQuickPick", { value: newMocks.mockCreateQp, configurable: true }); Object.defineProperty(ZoweLogger, "debug", { value: jest.fn(), configurable: true }); newMocks.debugLogSpy = jest.spyOn(ZoweLogger, "debug"); - // Object.defineProperty(profUtils.ProfilesUtils, "isUsingTokenAuth", { value: jest.fn().mockResolvedValueOnce(false), configurable: true }); return newMocks; } - afterEach(() => { - jest.clearAllMocks(); - jest.resetAllMocks(); + + describe("unit tests around basic auth selections", () => { + function createBlockMocks(globalMocks) { + const newMocks = { + mockProfileInstance: null as any, + editSpy: null as any, + promptSpy: jest.spyOn(profUtils.ProfilesUtils, "promptCredentials"), + logMsg: `Profile ${globalMocks.mockBasicAuthProfile.name} is using basic authentication.`, + }; + newMocks.mockProfileInstance = sharedMock.createInstanceOfProfile(globalMocks.mockBasicAuthProfile); + Object.defineProperty(Profiles, "getInstance", { + value: jest.fn().mockReturnValue(newMocks.mockProfileInstance), + configurable: true, + }); + Object.defineProperty(newMocks.mockProfileInstance, "editSession", { value: jest.fn(), configurable: true }); + newMocks.editSpy = jest.spyOn(newMocks.mockProfileInstance, "editSession"); + globalMocks.mockDsSessionNode = dsMock.createDatasetSessionNode(globalMocks.mockSession, globalMocks.mockBasicAuthProfile) as any; + Object.defineProperty(globalMocks.mockDsSessionNode, "getProfile", { + value: jest.fn().mockReturnValue(globalMocks.mockBasicAuthProfile), + configurable: true, + }); + return newMocks; + } + afterEach(() => { + jest.clearAllMocks(); + jest.resetAllMocks(); + }); + it("profile using basic authentication should see Operation Cancelled when escaping quick pick", async () => { + const globalMocks = createGlobalMocks(); + const blockMocks = createBlockMocks(globalMocks); + Object.defineProperty(Gui, "resolveQuickPick", { value: jest.fn().mockResolvedValueOnce(undefined), configurable: true }); + await ProfileManagement.manageProfile(globalMocks.mockDsSessionNode as any); + expect(globalMocks.debugLogSpy).toBeCalledWith(blockMocks.logMsg); + expect(blockMocks.promptSpy).not.toBeCalled(); + expect(globalMocks.opCancelledSpy).toBeCalledWith("Operation Cancelled"); + globalMocks.debugLogSpy.mockClear(); + blockMocks.promptSpy.mockClear(); + globalMocks.opCancelledSpy.mockClear(); + }); + it("profile using basic authentication should see promptCredentials called when Update Credentials chosen", async () => { + const globalMocks = createGlobalMocks(); + const blockMocks = createBlockMocks(globalMocks); + Object.defineProperty(Gui, "resolveQuickPick", { + value: jest.fn().mockResolvedValueOnce(globalMocks.mockUpdateChosen), + configurable: true, + }); + await ProfileManagement.manageProfile(globalMocks.mockDsSessionNode as any); + expect(globalMocks.debugLogSpy).toBeCalledWith(blockMocks.logMsg); + expect(blockMocks.promptSpy).toBeCalled(); + globalMocks.debugLogSpy.mockClear(); + blockMocks.promptSpy.mockClear(); + }); + it("profile using basic authentication should see editSession called when Edit Profile chosen", async () => { + const globalMocks = createGlobalMocks(); + const blockMocks = createBlockMocks(globalMocks); + Object.defineProperty(Gui, "resolveQuickPick", { + value: jest.fn().mockResolvedValueOnce(globalMocks.mockEditProfChosen), + configurable: true, + }); + await ProfileManagement.manageProfile(globalMocks.mockDsSessionNode as any); + expect(globalMocks.debugLogSpy).toBeCalledWith(blockMocks.logMsg); + expect(blockMocks.promptSpy).not.toBeCalled(); + expect(blockMocks.editSpy).toBeCalled(); + globalMocks.debugLogSpy.mockClear(); + blockMocks.promptSpy.mockClear(); + blockMocks.editSpy.mockClear(); + }); }); - it("profile using basic authentication should see Operation Cancelled when escaping quick pick", async () => { - const globalMocks = createGlobalMocks(); - const logMsg = `Profile ${globalMocks.mockBasicAuthProfile.name} is using basic authentication.`; - Object.defineProperty(Gui, "resolveQuickPick", { value: jest.fn().mockResolvedValueOnce(undefined), configurable: true }); - const updateSpy = jest.spyOn(profUtils.ProfilesUtils, "promptCredentials"); - const opCancelledSpy = jest.spyOn(Gui, "infoMessage"); - await ProfileManagement.manageProfile(globalMocks.mockDsSessionNode as any); - expect(globalMocks.debugLogSpy).toBeCalledWith(logMsg); - expect(updateSpy).not.toBeCalled(); - expect(opCancelledSpy).toBeCalledWith("Operation Cancelled"); - globalMocks.debugLogSpy.mockClear(); - updateSpy.mockClear(); - opCancelledSpy.mockClear(); + describe("unit tests around token auth selections", () => { + function createBlockMocks(globalMocks) { + const newMocks = { + mockProfileInstance: null as any, + loginSpy: null as any, + logoutSpy: null as any, + editSpy: null as any, + logMsg: `Profile ${globalMocks.mockTokenAuthProfile.name} is using token authentication.`, + }; + newMocks.mockProfileInstance = sharedMock.createInstanceOfProfile(globalMocks.mockTokenAuthProfile); + Object.defineProperty(Profiles, "getInstance", { + value: jest.fn().mockReturnValue(newMocks.mockProfileInstance), + configurable: true, + }); + Object.defineProperty(newMocks.mockProfileInstance, "editSession", { value: jest.fn(), configurable: true }); + newMocks.editSpy = jest.spyOn(newMocks.mockProfileInstance, "editSession"); + Object.defineProperty(newMocks.mockProfileInstance, "ssoLogin", { value: jest.fn(), configurable: true }); + newMocks.loginSpy = jest.spyOn(Profiles.getInstance(), "ssoLogin"); + Object.defineProperty(newMocks.mockProfileInstance, "ssoLogout", { value: jest.fn(), configurable: true }); + newMocks.logoutSpy = jest.spyOn(Profiles.getInstance(), "ssoLogout"); + Object.defineProperty(profUtils.ProfilesUtils, "isUsingTokenAuth", { value: jest.fn().mockResolvedValueOnce(true), configurable: true }); + globalMocks.mockDsSessionNode = dsMock.createDatasetSessionNode(globalMocks.mockSession, globalMocks.mockTokenAuthProfile) as any; + Object.defineProperty(globalMocks.mockDsSessionNode, "getProfile", { + value: jest.fn().mockReturnValue(globalMocks.mockTokenAuthProfile), + configurable: true, + }); + return newMocks; + } + afterEach(() => { + jest.clearAllMocks(); + jest.resetAllMocks(); + }); + it("profile using token authentication should see Operation Cancelled when escaping quick pick", async () => { + const globalMocks = createGlobalMocks(); + const blockMocks = createBlockMocks(globalMocks); + Object.defineProperty(Gui, "resolveQuickPick", { value: jest.fn().mockResolvedValueOnce(undefined), configurable: true }); + await ProfileManagement.manageProfile(globalMocks.mockDsSessionNode as any); + expect(globalMocks.debugLogSpy).toBeCalledWith(blockMocks.logMsg); + expect(blockMocks.loginSpy).not.toBeCalled(); + expect(globalMocks.opCancelledSpy).toBeCalledWith("Operation Cancelled"); + globalMocks.debugLogSpy.mockClear(); + blockMocks.loginSpy.mockClear(); + globalMocks.opCancelledSpy.mockClear(); + }); + it("profile using token authentication should see ssoLogin called when Log in to authentication service chosen", async () => { + const globalMocks = createGlobalMocks(); + const blockMocks = createBlockMocks(globalMocks); + Object.defineProperty(Gui, "resolveQuickPick", { + value: jest.fn().mockResolvedValueOnce(globalMocks.mockLoginChosen), + configurable: true, + }); + await ProfileManagement.manageProfile(globalMocks.mockDsSessionNode as any); + expect(globalMocks.debugLogSpy).toBeCalledWith(blockMocks.logMsg); + expect(blockMocks.loginSpy).toBeCalled(); + globalMocks.debugLogSpy.mockClear(); + blockMocks.loginSpy.mockClear(); + }); + it("profile using token authentication should see ssoLogout called when Log out from authentication service chosen", async () => { + const globalMocks = createGlobalMocks(); + const blockMocks = createBlockMocks(globalMocks); + Object.defineProperty(Gui, "resolveQuickPick", { + value: jest.fn().mockResolvedValueOnce(globalMocks.mockLogoutChosen), + configurable: true, + }); + await ProfileManagement.manageProfile(globalMocks.mockDsSessionNode as any); + expect(globalMocks.debugLogSpy).toBeCalledWith(blockMocks.logMsg); + expect(blockMocks.loginSpy).not.toBeCalled(); + expect(blockMocks.logoutSpy).toBeCalled(); + globalMocks.debugLogSpy.mockClear(); + blockMocks.loginSpy.mockClear(); + blockMocks.logoutSpy.mockClear(); + }); }); - it("profile using basic authentication should see promptCredentials called when Update Credentials chosen", async () => { - const globalMocks = createGlobalMocks(); - const logMsg = `Profile ${globalMocks.mockBasicAuthProfile.name} is using basic authentication.`; - Object.defineProperty(Gui, "resolveQuickPick", { value: jest.fn().mockResolvedValueOnce(globalMocks.mockUpdateChosen), configurable: true }); - const scenarioSpy = jest.spyOn(profUtils.ProfilesUtils, "promptCredentials"); - await ProfileManagement.manageProfile(globalMocks.mockDsSessionNode as any); - expect(globalMocks.debugLogSpy).toBeCalledWith(logMsg); - expect(scenarioSpy).toBeCalled(); - globalMocks.debugLogSpy.mockClear(); - scenarioSpy.mockClear(); + describe("unit tests around no auth declared selections", () => { + function createBlockMocks(globalMocks) { + const newMocks = { + mockProfileInstance: null as any, + loginSpy: null as any, + editSpy: null as any, + promptSpy: jest.spyOn(profUtils.ProfilesUtils, "promptCredentials"), + logMsg: `Profile ${globalMocks.mockNoAuthProfile.name} authentication method is unkown.`, + }; + newMocks.mockProfileInstance = sharedMock.createInstanceOfProfile(globalMocks.mockNoAuthProfile); + Object.defineProperty(Profiles, "getInstance", { + value: jest.fn().mockReturnValue(newMocks.mockProfileInstance), + configurable: true, + }); + Object.defineProperty(newMocks.mockProfileInstance, "editSession", { value: jest.fn(), configurable: true }); + newMocks.editSpy = jest.spyOn(newMocks.mockProfileInstance, "editSession"); + Object.defineProperty(newMocks.mockProfileInstance, "ssoLogin", { value: jest.fn(), configurable: true }); + newMocks.loginSpy = jest.spyOn(Profiles.getInstance(), "ssoLogin"); + Object.defineProperty(profUtils.ProfilesUtils, "isUsingTokenAuth", { value: jest.fn().mockResolvedValueOnce(false), configurable: true }); + globalMocks.mockDsSessionNode = dsMock.createDatasetSessionNode(globalMocks.mockSession, globalMocks.mockTokenAuthProfile) as any; + Object.defineProperty(globalMocks.mockDsSessionNode, "getProfile", { + value: jest.fn().mockReturnValue(globalMocks.mockNoAuthProfile), + configurable: true, + }); + return newMocks; + } + afterEach(() => { + jest.clearAllMocks(); + jest.resetAllMocks(); + }); + it("profile with no authentication method should see Operation Cancelled when escaping quick pick", async () => { + const globalMocks = createGlobalMocks(); + const blockMocks = createBlockMocks(globalMocks); + Object.defineProperty(Gui, "resolveQuickPick", { value: jest.fn().mockResolvedValueOnce(undefined), configurable: true }); + await ProfileManagement.manageProfile(globalMocks.mockDsSessionNode as any); + expect(globalMocks.debugLogSpy).toBeCalledWith(blockMocks.logMsg); + expect(blockMocks.loginSpy).not.toBeCalled(); + expect(globalMocks.opCancelledSpy).toBeCalledWith("Operation Cancelled"); + globalMocks.debugLogSpy.mockClear(); + blockMocks.loginSpy.mockClear(); + globalMocks.opCancelledSpy.mockClear(); + }); + it("profile with no authentication method should see promptCredentials called when Add Basic Credentials chosen", async () => { + const globalMocks = createGlobalMocks(); + const blockMocks = createBlockMocks(globalMocks); + Object.defineProperty(Gui, "resolveQuickPick", { + value: jest.fn().mockResolvedValueOnce(globalMocks.mockAddBasicChosen), + configurable: true, + }); + await ProfileManagement.manageProfile(globalMocks.mockDsSessionNode as any); + expect(globalMocks.debugLogSpy).toBeCalledWith(blockMocks.logMsg); + expect(blockMocks.promptSpy).toBeCalled(); + globalMocks.debugLogSpy.mockClear(); + blockMocks.promptSpy.mockClear(); + }); + it("profile with no authentication method should see ssoLogin called when Log in to authentication service chosen", async () => { + const globalMocks = createGlobalMocks(); + const blockMocks = createBlockMocks(globalMocks); + Object.defineProperty(Gui, "resolveQuickPick", { + value: jest.fn().mockResolvedValueOnce(globalMocks.mockLoginChosen), + configurable: true, + }); + await ProfileManagement.manageProfile(globalMocks.mockDsSessionNode as any); + expect(globalMocks.debugLogSpy).toBeCalledWith(blockMocks.logMsg); + expect(blockMocks.loginSpy).toBeCalled(); + globalMocks.debugLogSpy.mockClear(); + blockMocks.loginSpy.mockClear(); + }); + it("profile with no authentication method should see editSession called when Edit Profile chosen", async () => { + const globalMocks = createGlobalMocks(); + const blockMocks = createBlockMocks(globalMocks); + Object.defineProperty(Gui, "resolveQuickPick", { + value: jest.fn().mockResolvedValueOnce(globalMocks.mockEditProfChosen), + configurable: true, + }); + await ProfileManagement.manageProfile(globalMocks.mockDsSessionNode as any); + expect(globalMocks.debugLogSpy).toBeCalledWith(blockMocks.logMsg); + expect(blockMocks.promptSpy).not.toBeCalled(); + expect(blockMocks.editSpy).toBeCalled(); + globalMocks.debugLogSpy.mockClear(); + blockMocks.promptSpy.mockClear(); + blockMocks.editSpy.mockClear(); + }); }); }); From 29987e64d5b938e90b2d9fb0d584e4590178ac3e Mon Sep 17 00:00:00 2001 From: Billie Simmons <49491949+JillieBeanSim@users.noreply.github.com> Date: Fri, 22 Sep 2023 17:02:34 -0400 Subject: [PATCH 039/189] cut down on duplication of test code Signed-off-by: Billie Simmons <49491949+JillieBeanSim@users.noreply.github.com> --- .../utils/ProfileManagement.unit.test.ts | 61 ++++++++----------- 1 file changed, 27 insertions(+), 34 deletions(-) diff --git a/packages/zowe-explorer/__tests__/__unit__/utils/ProfileManagement.unit.test.ts b/packages/zowe-explorer/__tests__/__unit__/utils/ProfileManagement.unit.test.ts index e324c714aa..efd7bf90d6 100644 --- a/packages/zowe-explorer/__tests__/__unit__/utils/ProfileManagement.unit.test.ts +++ b/packages/zowe-explorer/__tests__/__unit__/utils/ProfileManagement.unit.test.ts @@ -20,7 +20,6 @@ import { Profiles } from "../../../src/Profiles"; jest.mock("fs"); jest.mock("vscode"); -jest.mock("@zowe/cli"); describe("ProfileManagement unit tests", () => { afterEach(() => { @@ -42,6 +41,7 @@ describe("ProfileManagement unit tests", () => { mockCreateQp: jest.fn(), debugLogSpy: null as any, opCancelledSpy: jest.spyOn(Gui, "infoMessage"), + promptSpy: null as any, }; newMocks.mockUpdateChosen = ProfileManagement.basicAuthUpdateQpItems[ProfileManagement.AuthQpLabels.update]; newMocks.mockAddBasicChosen = ProfileManagement.basicAuthAddQpItems[ProfileManagement.AuthQpLabels.add]; @@ -60,6 +60,7 @@ describe("ProfileManagement unit tests", () => { }), }); Object.defineProperty(profUtils.ProfilesUtils, "promptCredentials", { value: jest.fn(), configurable: true }); + newMocks.promptSpy = jest.spyOn(profUtils.ProfilesUtils, "promptCredentials"); Object.defineProperty(Gui, "createQuickPick", { value: newMocks.mockCreateQp, configurable: true }); Object.defineProperty(ZoweLogger, "debug", { value: jest.fn(), configurable: true }); newMocks.debugLogSpy = jest.spyOn(ZoweLogger, "debug"); @@ -72,7 +73,6 @@ describe("ProfileManagement unit tests", () => { const newMocks = { mockProfileInstance: null as any, editSpy: null as any, - promptSpy: jest.spyOn(profUtils.ProfilesUtils, "promptCredentials"), logMsg: `Profile ${globalMocks.mockBasicAuthProfile.name} is using basic authentication.`, }; newMocks.mockProfileInstance = sharedMock.createInstanceOfProfile(globalMocks.mockBasicAuthProfile); @@ -90,6 +90,12 @@ describe("ProfileManagement unit tests", () => { return newMocks; } afterEach(() => { + const globalMocks = createGlobalMocks(); + const blockMocks = createBlockMocks(globalMocks); + globalMocks.debugLogSpy.mockClear(); + globalMocks.promptSpy.mockClear(); + blockMocks.editSpy.mockClear(); + globalMocks.opCancelledSpy.mockClear(); jest.clearAllMocks(); jest.resetAllMocks(); }); @@ -99,11 +105,8 @@ describe("ProfileManagement unit tests", () => { Object.defineProperty(Gui, "resolveQuickPick", { value: jest.fn().mockResolvedValueOnce(undefined), configurable: true }); await ProfileManagement.manageProfile(globalMocks.mockDsSessionNode as any); expect(globalMocks.debugLogSpy).toBeCalledWith(blockMocks.logMsg); - expect(blockMocks.promptSpy).not.toBeCalled(); + expect(globalMocks.promptSpy).not.toBeCalled(); expect(globalMocks.opCancelledSpy).toBeCalledWith("Operation Cancelled"); - globalMocks.debugLogSpy.mockClear(); - blockMocks.promptSpy.mockClear(); - globalMocks.opCancelledSpy.mockClear(); }); it("profile using basic authentication should see promptCredentials called when Update Credentials chosen", async () => { const globalMocks = createGlobalMocks(); @@ -114,9 +117,7 @@ describe("ProfileManagement unit tests", () => { }); await ProfileManagement.manageProfile(globalMocks.mockDsSessionNode as any); expect(globalMocks.debugLogSpy).toBeCalledWith(blockMocks.logMsg); - expect(blockMocks.promptSpy).toBeCalled(); - globalMocks.debugLogSpy.mockClear(); - blockMocks.promptSpy.mockClear(); + expect(globalMocks.promptSpy).toBeCalled(); }); it("profile using basic authentication should see editSession called when Edit Profile chosen", async () => { const globalMocks = createGlobalMocks(); @@ -127,11 +128,8 @@ describe("ProfileManagement unit tests", () => { }); await ProfileManagement.manageProfile(globalMocks.mockDsSessionNode as any); expect(globalMocks.debugLogSpy).toBeCalledWith(blockMocks.logMsg); - expect(blockMocks.promptSpy).not.toBeCalled(); + expect(globalMocks.promptSpy).not.toBeCalled(); expect(blockMocks.editSpy).toBeCalled(); - globalMocks.debugLogSpy.mockClear(); - blockMocks.promptSpy.mockClear(); - blockMocks.editSpy.mockClear(); }); }); describe("unit tests around token auth selections", () => { @@ -163,6 +161,13 @@ describe("ProfileManagement unit tests", () => { return newMocks; } afterEach(() => { + const globalMocks = createGlobalMocks(); + const blockMocks = createBlockMocks(globalMocks); + globalMocks.debugLogSpy.mockClear(); + blockMocks.loginSpy.mockClear(); + blockMocks.logoutSpy.mockClear(); + globalMocks.opCancelledSpy.mockClear(); + blockMocks.editSpy.mockClear(); jest.clearAllMocks(); jest.resetAllMocks(); }); @@ -174,9 +179,6 @@ describe("ProfileManagement unit tests", () => { expect(globalMocks.debugLogSpy).toBeCalledWith(blockMocks.logMsg); expect(blockMocks.loginSpy).not.toBeCalled(); expect(globalMocks.opCancelledSpy).toBeCalledWith("Operation Cancelled"); - globalMocks.debugLogSpy.mockClear(); - blockMocks.loginSpy.mockClear(); - globalMocks.opCancelledSpy.mockClear(); }); it("profile using token authentication should see ssoLogin called when Log in to authentication service chosen", async () => { const globalMocks = createGlobalMocks(); @@ -188,8 +190,6 @@ describe("ProfileManagement unit tests", () => { await ProfileManagement.manageProfile(globalMocks.mockDsSessionNode as any); expect(globalMocks.debugLogSpy).toBeCalledWith(blockMocks.logMsg); expect(blockMocks.loginSpy).toBeCalled(); - globalMocks.debugLogSpy.mockClear(); - blockMocks.loginSpy.mockClear(); }); it("profile using token authentication should see ssoLogout called when Log out from authentication service chosen", async () => { const globalMocks = createGlobalMocks(); @@ -202,9 +202,6 @@ describe("ProfileManagement unit tests", () => { expect(globalMocks.debugLogSpy).toBeCalledWith(blockMocks.logMsg); expect(blockMocks.loginSpy).not.toBeCalled(); expect(blockMocks.logoutSpy).toBeCalled(); - globalMocks.debugLogSpy.mockClear(); - blockMocks.loginSpy.mockClear(); - blockMocks.logoutSpy.mockClear(); }); }); describe("unit tests around no auth declared selections", () => { @@ -213,7 +210,6 @@ describe("ProfileManagement unit tests", () => { mockProfileInstance: null as any, loginSpy: null as any, editSpy: null as any, - promptSpy: jest.spyOn(profUtils.ProfilesUtils, "promptCredentials"), logMsg: `Profile ${globalMocks.mockNoAuthProfile.name} authentication method is unkown.`, }; newMocks.mockProfileInstance = sharedMock.createInstanceOfProfile(globalMocks.mockNoAuthProfile); @@ -234,6 +230,13 @@ describe("ProfileManagement unit tests", () => { return newMocks; } afterEach(() => { + const globalMocks = createGlobalMocks(); + const blockMocks = createBlockMocks(globalMocks); + globalMocks.debugLogSpy.mockClear(); + blockMocks.loginSpy.mockClear(); + globalMocks.opCancelledSpy.mockClear(); + globalMocks.promptSpy.mockClear(); + blockMocks.editSpy.mockClear(); jest.clearAllMocks(); jest.resetAllMocks(); }); @@ -245,9 +248,6 @@ describe("ProfileManagement unit tests", () => { expect(globalMocks.debugLogSpy).toBeCalledWith(blockMocks.logMsg); expect(blockMocks.loginSpy).not.toBeCalled(); expect(globalMocks.opCancelledSpy).toBeCalledWith("Operation Cancelled"); - globalMocks.debugLogSpy.mockClear(); - blockMocks.loginSpy.mockClear(); - globalMocks.opCancelledSpy.mockClear(); }); it("profile with no authentication method should see promptCredentials called when Add Basic Credentials chosen", async () => { const globalMocks = createGlobalMocks(); @@ -258,9 +258,7 @@ describe("ProfileManagement unit tests", () => { }); await ProfileManagement.manageProfile(globalMocks.mockDsSessionNode as any); expect(globalMocks.debugLogSpy).toBeCalledWith(blockMocks.logMsg); - expect(blockMocks.promptSpy).toBeCalled(); - globalMocks.debugLogSpy.mockClear(); - blockMocks.promptSpy.mockClear(); + expect(globalMocks.promptSpy).toBeCalled(); }); it("profile with no authentication method should see ssoLogin called when Log in to authentication service chosen", async () => { const globalMocks = createGlobalMocks(); @@ -272,8 +270,6 @@ describe("ProfileManagement unit tests", () => { await ProfileManagement.manageProfile(globalMocks.mockDsSessionNode as any); expect(globalMocks.debugLogSpy).toBeCalledWith(blockMocks.logMsg); expect(blockMocks.loginSpy).toBeCalled(); - globalMocks.debugLogSpy.mockClear(); - blockMocks.loginSpy.mockClear(); }); it("profile with no authentication method should see editSession called when Edit Profile chosen", async () => { const globalMocks = createGlobalMocks(); @@ -284,11 +280,8 @@ describe("ProfileManagement unit tests", () => { }); await ProfileManagement.manageProfile(globalMocks.mockDsSessionNode as any); expect(globalMocks.debugLogSpy).toBeCalledWith(blockMocks.logMsg); - expect(blockMocks.promptSpy).not.toBeCalled(); + expect(globalMocks.promptSpy).not.toBeCalled(); expect(blockMocks.editSpy).toBeCalled(); - globalMocks.debugLogSpy.mockClear(); - blockMocks.promptSpy.mockClear(); - blockMocks.editSpy.mockClear(); }); }); }); From 4484235e38754604112a1b3350aaea1d934e8059 Mon Sep 17 00:00:00 2001 From: Billie Simmons <49491949+JillieBeanSim@users.noreply.github.com> Date: Fri, 22 Sep 2023 17:18:25 -0400 Subject: [PATCH 040/189] clear more duplication Signed-off-by: Billie Simmons <49491949+JillieBeanSim@users.noreply.github.com> --- .../utils/ProfileManagement.unit.test.ts | 97 ++++++------------- 1 file changed, 30 insertions(+), 67 deletions(-) diff --git a/packages/zowe-explorer/__tests__/__unit__/utils/ProfileManagement.unit.test.ts b/packages/zowe-explorer/__tests__/__unit__/utils/ProfileManagement.unit.test.ts index efd7bf90d6..234de03e8e 100644 --- a/packages/zowe-explorer/__tests__/__unit__/utils/ProfileManagement.unit.test.ts +++ b/packages/zowe-explorer/__tests__/__unit__/utils/ProfileManagement.unit.test.ts @@ -28,6 +28,7 @@ describe("ProfileManagement unit tests", () => { }); function createGlobalMocks() { const newMocks = { + mockProfileInstance: null as any, mockSession: sharedMock.createISession(), mockBasicAuthProfile: sharedMock.createValidIProfile(), mockTokenAuthProfile: sharedMock.createTokenAuthIProfile(), @@ -42,6 +43,9 @@ describe("ProfileManagement unit tests", () => { debugLogSpy: null as any, opCancelledSpy: jest.spyOn(Gui, "infoMessage"), promptSpy: null as any, + editSpy: null as any, + loginSpy: null as any, + logoutSpy: null as any, }; newMocks.mockUpdateChosen = ProfileManagement.basicAuthUpdateQpItems[ProfileManagement.AuthQpLabels.update]; newMocks.mockAddBasicChosen = ProfileManagement.basicAuthAddQpItems[ProfileManagement.AuthQpLabels.add]; @@ -71,17 +75,15 @@ describe("ProfileManagement unit tests", () => { describe("unit tests around basic auth selections", () => { function createBlockMocks(globalMocks) { const newMocks = { - mockProfileInstance: null as any, - editSpy: null as any, logMsg: `Profile ${globalMocks.mockBasicAuthProfile.name} is using basic authentication.`, }; - newMocks.mockProfileInstance = sharedMock.createInstanceOfProfile(globalMocks.mockBasicAuthProfile); + globalMocks.mockProfileInstance = sharedMock.createInstanceOfProfile(globalMocks.mockBasicAuthProfile); Object.defineProperty(Profiles, "getInstance", { - value: jest.fn().mockReturnValue(newMocks.mockProfileInstance), + value: jest.fn().mockReturnValue(globalMocks.mockProfileInstance), configurable: true, }); - Object.defineProperty(newMocks.mockProfileInstance, "editSession", { value: jest.fn(), configurable: true }); - newMocks.editSpy = jest.spyOn(newMocks.mockProfileInstance, "editSession"); + Object.defineProperty(globalMocks.mockProfileInstance, "editSession", { value: jest.fn(), configurable: true }); + globalMocks.editSpy = jest.spyOn(globalMocks.mockProfileInstance, "editSession"); globalMocks.mockDsSessionNode = dsMock.createDatasetSessionNode(globalMocks.mockSession, globalMocks.mockBasicAuthProfile) as any; Object.defineProperty(globalMocks.mockDsSessionNode, "getProfile", { value: jest.fn().mockReturnValue(globalMocks.mockBasicAuthProfile), @@ -89,16 +91,6 @@ describe("ProfileManagement unit tests", () => { }); return newMocks; } - afterEach(() => { - const globalMocks = createGlobalMocks(); - const blockMocks = createBlockMocks(globalMocks); - globalMocks.debugLogSpy.mockClear(); - globalMocks.promptSpy.mockClear(); - blockMocks.editSpy.mockClear(); - globalMocks.opCancelledSpy.mockClear(); - jest.clearAllMocks(); - jest.resetAllMocks(); - }); it("profile using basic authentication should see Operation Cancelled when escaping quick pick", async () => { const globalMocks = createGlobalMocks(); const blockMocks = createBlockMocks(globalMocks); @@ -129,29 +121,25 @@ describe("ProfileManagement unit tests", () => { await ProfileManagement.manageProfile(globalMocks.mockDsSessionNode as any); expect(globalMocks.debugLogSpy).toBeCalledWith(blockMocks.logMsg); expect(globalMocks.promptSpy).not.toBeCalled(); - expect(blockMocks.editSpy).toBeCalled(); + expect(globalMocks.editSpy).toBeCalled(); }); }); describe("unit tests around token auth selections", () => { function createBlockMocks(globalMocks) { const newMocks = { - mockProfileInstance: null as any, - loginSpy: null as any, - logoutSpy: null as any, - editSpy: null as any, logMsg: `Profile ${globalMocks.mockTokenAuthProfile.name} is using token authentication.`, }; - newMocks.mockProfileInstance = sharedMock.createInstanceOfProfile(globalMocks.mockTokenAuthProfile); + globalMocks.mockProfileInstance = sharedMock.createInstanceOfProfile(globalMocks.mockTokenAuthProfile); Object.defineProperty(Profiles, "getInstance", { - value: jest.fn().mockReturnValue(newMocks.mockProfileInstance), + value: jest.fn().mockReturnValue(globalMocks.mockProfileInstance), configurable: true, }); - Object.defineProperty(newMocks.mockProfileInstance, "editSession", { value: jest.fn(), configurable: true }); - newMocks.editSpy = jest.spyOn(newMocks.mockProfileInstance, "editSession"); - Object.defineProperty(newMocks.mockProfileInstance, "ssoLogin", { value: jest.fn(), configurable: true }); - newMocks.loginSpy = jest.spyOn(Profiles.getInstance(), "ssoLogin"); - Object.defineProperty(newMocks.mockProfileInstance, "ssoLogout", { value: jest.fn(), configurable: true }); - newMocks.logoutSpy = jest.spyOn(Profiles.getInstance(), "ssoLogout"); + Object.defineProperty(globalMocks.mockProfileInstance, "editSession", { value: jest.fn(), configurable: true }); + globalMocks.editSpy = jest.spyOn(globalMocks.mockProfileInstance, "editSession"); + Object.defineProperty(globalMocks.mockProfileInstance, "ssoLogin", { value: jest.fn(), configurable: true }); + globalMocks.loginSpy = jest.spyOn(Profiles.getInstance(), "ssoLogin"); + Object.defineProperty(globalMocks.mockProfileInstance, "ssoLogout", { value: jest.fn(), configurable: true }); + globalMocks.logoutSpy = jest.spyOn(Profiles.getInstance(), "ssoLogout"); Object.defineProperty(profUtils.ProfilesUtils, "isUsingTokenAuth", { value: jest.fn().mockResolvedValueOnce(true), configurable: true }); globalMocks.mockDsSessionNode = dsMock.createDatasetSessionNode(globalMocks.mockSession, globalMocks.mockTokenAuthProfile) as any; Object.defineProperty(globalMocks.mockDsSessionNode, "getProfile", { @@ -160,24 +148,13 @@ describe("ProfileManagement unit tests", () => { }); return newMocks; } - afterEach(() => { - const globalMocks = createGlobalMocks(); - const blockMocks = createBlockMocks(globalMocks); - globalMocks.debugLogSpy.mockClear(); - blockMocks.loginSpy.mockClear(); - blockMocks.logoutSpy.mockClear(); - globalMocks.opCancelledSpy.mockClear(); - blockMocks.editSpy.mockClear(); - jest.clearAllMocks(); - jest.resetAllMocks(); - }); it("profile using token authentication should see Operation Cancelled when escaping quick pick", async () => { const globalMocks = createGlobalMocks(); const blockMocks = createBlockMocks(globalMocks); Object.defineProperty(Gui, "resolveQuickPick", { value: jest.fn().mockResolvedValueOnce(undefined), configurable: true }); await ProfileManagement.manageProfile(globalMocks.mockDsSessionNode as any); expect(globalMocks.debugLogSpy).toBeCalledWith(blockMocks.logMsg); - expect(blockMocks.loginSpy).not.toBeCalled(); + expect(globalMocks.loginSpy).not.toBeCalled(); expect(globalMocks.opCancelledSpy).toBeCalledWith("Operation Cancelled"); }); it("profile using token authentication should see ssoLogin called when Log in to authentication service chosen", async () => { @@ -189,7 +166,7 @@ describe("ProfileManagement unit tests", () => { }); await ProfileManagement.manageProfile(globalMocks.mockDsSessionNode as any); expect(globalMocks.debugLogSpy).toBeCalledWith(blockMocks.logMsg); - expect(blockMocks.loginSpy).toBeCalled(); + expect(globalMocks.loginSpy).toBeCalled(); }); it("profile using token authentication should see ssoLogout called when Log out from authentication service chosen", async () => { const globalMocks = createGlobalMocks(); @@ -200,27 +177,24 @@ describe("ProfileManagement unit tests", () => { }); await ProfileManagement.manageProfile(globalMocks.mockDsSessionNode as any); expect(globalMocks.debugLogSpy).toBeCalledWith(blockMocks.logMsg); - expect(blockMocks.loginSpy).not.toBeCalled(); - expect(blockMocks.logoutSpy).toBeCalled(); + expect(globalMocks.loginSpy).not.toBeCalled(); + expect(globalMocks.logoutSpy).toBeCalled(); }); }); describe("unit tests around no auth declared selections", () => { function createBlockMocks(globalMocks) { const newMocks = { - mockProfileInstance: null as any, - loginSpy: null as any, - editSpy: null as any, logMsg: `Profile ${globalMocks.mockNoAuthProfile.name} authentication method is unkown.`, }; - newMocks.mockProfileInstance = sharedMock.createInstanceOfProfile(globalMocks.mockNoAuthProfile); + globalMocks.mockProfileInstance = sharedMock.createInstanceOfProfile(globalMocks.mockNoAuthProfile); Object.defineProperty(Profiles, "getInstance", { - value: jest.fn().mockReturnValue(newMocks.mockProfileInstance), + value: jest.fn().mockReturnValue(globalMocks.mockProfileInstance), configurable: true, }); - Object.defineProperty(newMocks.mockProfileInstance, "editSession", { value: jest.fn(), configurable: true }); - newMocks.editSpy = jest.spyOn(newMocks.mockProfileInstance, "editSession"); - Object.defineProperty(newMocks.mockProfileInstance, "ssoLogin", { value: jest.fn(), configurable: true }); - newMocks.loginSpy = jest.spyOn(Profiles.getInstance(), "ssoLogin"); + Object.defineProperty(globalMocks.mockProfileInstance, "editSession", { value: jest.fn(), configurable: true }); + globalMocks.editSpy = jest.spyOn(globalMocks.mockProfileInstance, "editSession"); + Object.defineProperty(globalMocks.mockProfileInstance, "ssoLogin", { value: jest.fn(), configurable: true }); + globalMocks.loginSpy = jest.spyOn(Profiles.getInstance(), "ssoLogin"); Object.defineProperty(profUtils.ProfilesUtils, "isUsingTokenAuth", { value: jest.fn().mockResolvedValueOnce(false), configurable: true }); globalMocks.mockDsSessionNode = dsMock.createDatasetSessionNode(globalMocks.mockSession, globalMocks.mockTokenAuthProfile) as any; Object.defineProperty(globalMocks.mockDsSessionNode, "getProfile", { @@ -229,24 +203,13 @@ describe("ProfileManagement unit tests", () => { }); return newMocks; } - afterEach(() => { - const globalMocks = createGlobalMocks(); - const blockMocks = createBlockMocks(globalMocks); - globalMocks.debugLogSpy.mockClear(); - blockMocks.loginSpy.mockClear(); - globalMocks.opCancelledSpy.mockClear(); - globalMocks.promptSpy.mockClear(); - blockMocks.editSpy.mockClear(); - jest.clearAllMocks(); - jest.resetAllMocks(); - }); it("profile with no authentication method should see Operation Cancelled when escaping quick pick", async () => { const globalMocks = createGlobalMocks(); const blockMocks = createBlockMocks(globalMocks); Object.defineProperty(Gui, "resolveQuickPick", { value: jest.fn().mockResolvedValueOnce(undefined), configurable: true }); await ProfileManagement.manageProfile(globalMocks.mockDsSessionNode as any); expect(globalMocks.debugLogSpy).toBeCalledWith(blockMocks.logMsg); - expect(blockMocks.loginSpy).not.toBeCalled(); + expect(globalMocks.loginSpy).not.toBeCalled(); expect(globalMocks.opCancelledSpy).toBeCalledWith("Operation Cancelled"); }); it("profile with no authentication method should see promptCredentials called when Add Basic Credentials chosen", async () => { @@ -269,7 +232,7 @@ describe("ProfileManagement unit tests", () => { }); await ProfileManagement.manageProfile(globalMocks.mockDsSessionNode as any); expect(globalMocks.debugLogSpy).toBeCalledWith(blockMocks.logMsg); - expect(blockMocks.loginSpy).toBeCalled(); + expect(globalMocks.loginSpy).toBeCalled(); }); it("profile with no authentication method should see editSession called when Edit Profile chosen", async () => { const globalMocks = createGlobalMocks(); @@ -281,7 +244,7 @@ describe("ProfileManagement unit tests", () => { await ProfileManagement.manageProfile(globalMocks.mockDsSessionNode as any); expect(globalMocks.debugLogSpy).toBeCalledWith(blockMocks.logMsg); expect(globalMocks.promptSpy).not.toBeCalled(); - expect(blockMocks.editSpy).toBeCalled(); + expect(globalMocks.editSpy).toBeCalled(); }); }); }); From 847982127d30129c05711454aa08ce4f90a9a002 Mon Sep 17 00:00:00 2001 From: Billie Simmons <49491949+JillieBeanSim@users.noreply.github.com> Date: Fri, 22 Sep 2023 17:30:23 -0400 Subject: [PATCH 041/189] cleanup Signed-off-by: Billie Simmons <49491949+JillieBeanSim@users.noreply.github.com> --- .../utils/ProfileManagement.unit.test.ts | 62 +++++++------------ 1 file changed, 24 insertions(+), 38 deletions(-) diff --git a/packages/zowe-explorer/__tests__/__unit__/utils/ProfileManagement.unit.test.ts b/packages/zowe-explorer/__tests__/__unit__/utils/ProfileManagement.unit.test.ts index 234de03e8e..feac872808 100644 --- a/packages/zowe-explorer/__tests__/__unit__/utils/ProfileManagement.unit.test.ts +++ b/packages/zowe-explorer/__tests__/__unit__/utils/ProfileManagement.unit.test.ts @@ -46,6 +46,7 @@ describe("ProfileManagement unit tests", () => { editSpy: null as any, loginSpy: null as any, logoutSpy: null as any, + logMsg: null as any, }; newMocks.mockUpdateChosen = ProfileManagement.basicAuthUpdateQpItems[ProfileManagement.AuthQpLabels.update]; newMocks.mockAddBasicChosen = ProfileManagement.basicAuthAddQpItems[ProfileManagement.AuthQpLabels.add]; @@ -74,9 +75,7 @@ describe("ProfileManagement unit tests", () => { describe("unit tests around basic auth selections", () => { function createBlockMocks(globalMocks) { - const newMocks = { - logMsg: `Profile ${globalMocks.mockBasicAuthProfile.name} is using basic authentication.`, - }; + globalMocks.logMsg = `Profile ${globalMocks.mockBasicAuthProfile.name} is using basic authentication.`; globalMocks.mockProfileInstance = sharedMock.createInstanceOfProfile(globalMocks.mockBasicAuthProfile); Object.defineProperty(Profiles, "getInstance", { value: jest.fn().mockReturnValue(globalMocks.mockProfileInstance), @@ -89,46 +88,41 @@ describe("ProfileManagement unit tests", () => { value: jest.fn().mockReturnValue(globalMocks.mockBasicAuthProfile), configurable: true, }); - return newMocks; } it("profile using basic authentication should see Operation Cancelled when escaping quick pick", async () => { const globalMocks = createGlobalMocks(); - const blockMocks = createBlockMocks(globalMocks); + createBlockMocks(globalMocks); Object.defineProperty(Gui, "resolveQuickPick", { value: jest.fn().mockResolvedValueOnce(undefined), configurable: true }); await ProfileManagement.manageProfile(globalMocks.mockDsSessionNode as any); - expect(globalMocks.debugLogSpy).toBeCalledWith(blockMocks.logMsg); - expect(globalMocks.promptSpy).not.toBeCalled(); + expect(globalMocks.debugLogSpy).toBeCalledWith(globalMocks.logMsg); expect(globalMocks.opCancelledSpy).toBeCalledWith("Operation Cancelled"); }); it("profile using basic authentication should see promptCredentials called when Update Credentials chosen", async () => { const globalMocks = createGlobalMocks(); - const blockMocks = createBlockMocks(globalMocks); + createBlockMocks(globalMocks); Object.defineProperty(Gui, "resolveQuickPick", { value: jest.fn().mockResolvedValueOnce(globalMocks.mockUpdateChosen), configurable: true, }); await ProfileManagement.manageProfile(globalMocks.mockDsSessionNode as any); - expect(globalMocks.debugLogSpy).toBeCalledWith(blockMocks.logMsg); + expect(globalMocks.debugLogSpy).toBeCalledWith(globalMocks.logMsg); expect(globalMocks.promptSpy).toBeCalled(); }); it("profile using basic authentication should see editSession called when Edit Profile chosen", async () => { const globalMocks = createGlobalMocks(); - const blockMocks = createBlockMocks(globalMocks); + createBlockMocks(globalMocks); Object.defineProperty(Gui, "resolveQuickPick", { value: jest.fn().mockResolvedValueOnce(globalMocks.mockEditProfChosen), configurable: true, }); await ProfileManagement.manageProfile(globalMocks.mockDsSessionNode as any); - expect(globalMocks.debugLogSpy).toBeCalledWith(blockMocks.logMsg); - expect(globalMocks.promptSpy).not.toBeCalled(); + expect(globalMocks.debugLogSpy).toBeCalledWith(globalMocks.logMsg); expect(globalMocks.editSpy).toBeCalled(); }); }); describe("unit tests around token auth selections", () => { function createBlockMocks(globalMocks) { - const newMocks = { - logMsg: `Profile ${globalMocks.mockTokenAuthProfile.name} is using token authentication.`, - }; + globalMocks.logMsg = `Profile ${globalMocks.mockTokenAuthProfile.name} is using token authentication.`; globalMocks.mockProfileInstance = sharedMock.createInstanceOfProfile(globalMocks.mockTokenAuthProfile); Object.defineProperty(Profiles, "getInstance", { value: jest.fn().mockReturnValue(globalMocks.mockProfileInstance), @@ -146,46 +140,41 @@ describe("ProfileManagement unit tests", () => { value: jest.fn().mockReturnValue(globalMocks.mockTokenAuthProfile), configurable: true, }); - return newMocks; } it("profile using token authentication should see Operation Cancelled when escaping quick pick", async () => { const globalMocks = createGlobalMocks(); - const blockMocks = createBlockMocks(globalMocks); + createBlockMocks(globalMocks); Object.defineProperty(Gui, "resolveQuickPick", { value: jest.fn().mockResolvedValueOnce(undefined), configurable: true }); await ProfileManagement.manageProfile(globalMocks.mockDsSessionNode as any); - expect(globalMocks.debugLogSpy).toBeCalledWith(blockMocks.logMsg); - expect(globalMocks.loginSpy).not.toBeCalled(); + expect(globalMocks.debugLogSpy).toBeCalledWith(globalMocks.logMsg); expect(globalMocks.opCancelledSpy).toBeCalledWith("Operation Cancelled"); }); it("profile using token authentication should see ssoLogin called when Log in to authentication service chosen", async () => { const globalMocks = createGlobalMocks(); - const blockMocks = createBlockMocks(globalMocks); + createBlockMocks(globalMocks); Object.defineProperty(Gui, "resolveQuickPick", { value: jest.fn().mockResolvedValueOnce(globalMocks.mockLoginChosen), configurable: true, }); await ProfileManagement.manageProfile(globalMocks.mockDsSessionNode as any); - expect(globalMocks.debugLogSpy).toBeCalledWith(blockMocks.logMsg); + expect(globalMocks.debugLogSpy).toBeCalledWith(globalMocks.logMsg); expect(globalMocks.loginSpy).toBeCalled(); }); it("profile using token authentication should see ssoLogout called when Log out from authentication service chosen", async () => { const globalMocks = createGlobalMocks(); - const blockMocks = createBlockMocks(globalMocks); + createBlockMocks(globalMocks); Object.defineProperty(Gui, "resolveQuickPick", { value: jest.fn().mockResolvedValueOnce(globalMocks.mockLogoutChosen), configurable: true, }); await ProfileManagement.manageProfile(globalMocks.mockDsSessionNode as any); - expect(globalMocks.debugLogSpy).toBeCalledWith(blockMocks.logMsg); - expect(globalMocks.loginSpy).not.toBeCalled(); + expect(globalMocks.debugLogSpy).toBeCalledWith(globalMocks.logMsg); expect(globalMocks.logoutSpy).toBeCalled(); }); }); describe("unit tests around no auth declared selections", () => { function createBlockMocks(globalMocks) { - const newMocks = { - logMsg: `Profile ${globalMocks.mockNoAuthProfile.name} authentication method is unkown.`, - }; + globalMocks.logMsg = `Profile ${globalMocks.mockNoAuthProfile.name} authentication method is unkown.`; globalMocks.mockProfileInstance = sharedMock.createInstanceOfProfile(globalMocks.mockNoAuthProfile); Object.defineProperty(Profiles, "getInstance", { value: jest.fn().mockReturnValue(globalMocks.mockProfileInstance), @@ -201,49 +190,46 @@ describe("ProfileManagement unit tests", () => { value: jest.fn().mockReturnValue(globalMocks.mockNoAuthProfile), configurable: true, }); - return newMocks; } it("profile with no authentication method should see Operation Cancelled when escaping quick pick", async () => { const globalMocks = createGlobalMocks(); - const blockMocks = createBlockMocks(globalMocks); + createBlockMocks(globalMocks); Object.defineProperty(Gui, "resolveQuickPick", { value: jest.fn().mockResolvedValueOnce(undefined), configurable: true }); await ProfileManagement.manageProfile(globalMocks.mockDsSessionNode as any); - expect(globalMocks.debugLogSpy).toBeCalledWith(blockMocks.logMsg); - expect(globalMocks.loginSpy).not.toBeCalled(); + expect(globalMocks.debugLogSpy).toBeCalledWith(globalMocks.logMsg); expect(globalMocks.opCancelledSpy).toBeCalledWith("Operation Cancelled"); }); it("profile with no authentication method should see promptCredentials called when Add Basic Credentials chosen", async () => { const globalMocks = createGlobalMocks(); - const blockMocks = createBlockMocks(globalMocks); + createBlockMocks(globalMocks); Object.defineProperty(Gui, "resolveQuickPick", { value: jest.fn().mockResolvedValueOnce(globalMocks.mockAddBasicChosen), configurable: true, }); await ProfileManagement.manageProfile(globalMocks.mockDsSessionNode as any); - expect(globalMocks.debugLogSpy).toBeCalledWith(blockMocks.logMsg); + expect(globalMocks.debugLogSpy).toBeCalledWith(globalMocks.logMsg); expect(globalMocks.promptSpy).toBeCalled(); }); it("profile with no authentication method should see ssoLogin called when Log in to authentication service chosen", async () => { const globalMocks = createGlobalMocks(); - const blockMocks = createBlockMocks(globalMocks); + createBlockMocks(globalMocks); Object.defineProperty(Gui, "resolveQuickPick", { value: jest.fn().mockResolvedValueOnce(globalMocks.mockLoginChosen), configurable: true, }); await ProfileManagement.manageProfile(globalMocks.mockDsSessionNode as any); - expect(globalMocks.debugLogSpy).toBeCalledWith(blockMocks.logMsg); + expect(globalMocks.debugLogSpy).toBeCalledWith(globalMocks.logMsg); expect(globalMocks.loginSpy).toBeCalled(); }); it("profile with no authentication method should see editSession called when Edit Profile chosen", async () => { const globalMocks = createGlobalMocks(); - const blockMocks = createBlockMocks(globalMocks); + createBlockMocks(globalMocks); Object.defineProperty(Gui, "resolveQuickPick", { value: jest.fn().mockResolvedValueOnce(globalMocks.mockEditProfChosen), configurable: true, }); await ProfileManagement.manageProfile(globalMocks.mockDsSessionNode as any); - expect(globalMocks.debugLogSpy).toBeCalledWith(blockMocks.logMsg); - expect(globalMocks.promptSpy).not.toBeCalled(); + expect(globalMocks.debugLogSpy).toBeCalledWith(globalMocks.logMsg); expect(globalMocks.editSpy).toBeCalled(); }); }); From c046daa4de3efec25b553789e678c391c24c0d04 Mon Sep 17 00:00:00 2001 From: Billie Simmons <49491949+JillieBeanSim@users.noreply.github.com> Date: Fri, 22 Sep 2023 18:01:11 -0400 Subject: [PATCH 042/189] clean duplication unit testing Signed-off-by: Billie Simmons <49491949+JillieBeanSim@users.noreply.github.com> --- .../utils/ProfileManagement.unit.test.ts | 70 ++++++------------- 1 file changed, 23 insertions(+), 47 deletions(-) diff --git a/packages/zowe-explorer/__tests__/__unit__/utils/ProfileManagement.unit.test.ts b/packages/zowe-explorer/__tests__/__unit__/utils/ProfileManagement.unit.test.ts index feac872808..cb6766e044 100644 --- a/packages/zowe-explorer/__tests__/__unit__/utils/ProfileManagement.unit.test.ts +++ b/packages/zowe-explorer/__tests__/__unit__/utils/ProfileManagement.unit.test.ts @@ -28,31 +28,32 @@ describe("ProfileManagement unit tests", () => { }); function createGlobalMocks() { const newMocks = { - mockProfileInstance: null as any, mockSession: sharedMock.createISession(), mockBasicAuthProfile: sharedMock.createValidIProfile(), mockTokenAuthProfile: sharedMock.createTokenAuthIProfile(), mockNoAuthProfile: sharedMock.createInvalidIProfile(), + opCancelledSpy: jest.spyOn(Gui, "infoMessage"), mockDsSessionNode: ZoweDatasetNode, - mockUpdateChosen: null as any, - mockAddBasicChosen: null as any, - mockLoginChosen: null as any, - mockLogoutChosen: null as any, - mockEditProfChosen: null as any, + mockResolveQp: jest.fn(), mockCreateQp: jest.fn(), + mockUpdateChosen: ProfileManagement.basicAuthUpdateQpItems[ProfileManagement.AuthQpLabels.update], + mockAddBasicChosen: ProfileManagement.basicAuthAddQpItems[ProfileManagement.AuthQpLabels.add], + mockLoginChosen: ProfileManagement.tokenAuthLoginQpItem[ProfileManagement.AuthQpLabels.login], + mockLogoutChosen: ProfileManagement.tokenAuthLogoutQpItem[ProfileManagement.AuthQpLabels.logout], + mockEditProfChosen: ProfileManagement.otherProfileQpItems[ProfileManagement.AuthQpLabels.edit], + mockProfileInstance: null as any, debugLogSpy: null as any, - opCancelledSpy: jest.spyOn(Gui, "infoMessage"), promptSpy: null as any, editSpy: null as any, loginSpy: null as any, logoutSpy: null as any, logMsg: null as any, }; - newMocks.mockUpdateChosen = ProfileManagement.basicAuthUpdateQpItems[ProfileManagement.AuthQpLabels.update]; - newMocks.mockAddBasicChosen = ProfileManagement.basicAuthAddQpItems[ProfileManagement.AuthQpLabels.add]; - newMocks.mockLoginChosen = ProfileManagement.tokenAuthLoginQpItem[ProfileManagement.AuthQpLabels.login]; - newMocks.mockLogoutChosen = ProfileManagement.tokenAuthLogoutQpItem[ProfileManagement.AuthQpLabels.logout]; - newMocks.mockEditProfChosen = ProfileManagement.otherProfileQpItems[ProfileManagement.AuthQpLabels.edit]; + Object.defineProperty(profUtils.ProfilesUtils, "promptCredentials", { value: jest.fn(), configurable: true }); + newMocks.promptSpy = jest.spyOn(profUtils.ProfilesUtils, "promptCredentials"); + Object.defineProperty(ZoweLogger, "debug", { value: jest.fn(), configurable: true }); + newMocks.debugLogSpy = jest.spyOn(ZoweLogger, "debug"); + Object.defineProperty(Gui, "resolveQuickPick", { value: newMocks.mockResolveQp, configurable: true }); newMocks.mockCreateQp.mockReturnValue({ show: jest.fn(() => { return {}; @@ -64,11 +65,7 @@ describe("ProfileManagement unit tests", () => { return {}; }), }); - Object.defineProperty(profUtils.ProfilesUtils, "promptCredentials", { value: jest.fn(), configurable: true }); - newMocks.promptSpy = jest.spyOn(profUtils.ProfilesUtils, "promptCredentials"); Object.defineProperty(Gui, "createQuickPick", { value: newMocks.mockCreateQp, configurable: true }); - Object.defineProperty(ZoweLogger, "debug", { value: jest.fn(), configurable: true }); - newMocks.debugLogSpy = jest.spyOn(ZoweLogger, "debug"); return newMocks; } @@ -92,7 +89,7 @@ describe("ProfileManagement unit tests", () => { it("profile using basic authentication should see Operation Cancelled when escaping quick pick", async () => { const globalMocks = createGlobalMocks(); createBlockMocks(globalMocks); - Object.defineProperty(Gui, "resolveQuickPick", { value: jest.fn().mockResolvedValueOnce(undefined), configurable: true }); + globalMocks.mockResolveQp.mockResolvedValueOnce(undefined); await ProfileManagement.manageProfile(globalMocks.mockDsSessionNode as any); expect(globalMocks.debugLogSpy).toBeCalledWith(globalMocks.logMsg); expect(globalMocks.opCancelledSpy).toBeCalledWith("Operation Cancelled"); @@ -100,10 +97,7 @@ describe("ProfileManagement unit tests", () => { it("profile using basic authentication should see promptCredentials called when Update Credentials chosen", async () => { const globalMocks = createGlobalMocks(); createBlockMocks(globalMocks); - Object.defineProperty(Gui, "resolveQuickPick", { - value: jest.fn().mockResolvedValueOnce(globalMocks.mockUpdateChosen), - configurable: true, - }); + globalMocks.mockResolveQp.mockResolvedValueOnce(globalMocks.mockUpdateChosen); await ProfileManagement.manageProfile(globalMocks.mockDsSessionNode as any); expect(globalMocks.debugLogSpy).toBeCalledWith(globalMocks.logMsg); expect(globalMocks.promptSpy).toBeCalled(); @@ -111,10 +105,7 @@ describe("ProfileManagement unit tests", () => { it("profile using basic authentication should see editSession called when Edit Profile chosen", async () => { const globalMocks = createGlobalMocks(); createBlockMocks(globalMocks); - Object.defineProperty(Gui, "resolveQuickPick", { - value: jest.fn().mockResolvedValueOnce(globalMocks.mockEditProfChosen), - configurable: true, - }); + globalMocks.mockResolveQp.mockResolvedValueOnce(globalMocks.mockEditProfChosen); await ProfileManagement.manageProfile(globalMocks.mockDsSessionNode as any); expect(globalMocks.debugLogSpy).toBeCalledWith(globalMocks.logMsg); expect(globalMocks.editSpy).toBeCalled(); @@ -144,7 +135,7 @@ describe("ProfileManagement unit tests", () => { it("profile using token authentication should see Operation Cancelled when escaping quick pick", async () => { const globalMocks = createGlobalMocks(); createBlockMocks(globalMocks); - Object.defineProperty(Gui, "resolveQuickPick", { value: jest.fn().mockResolvedValueOnce(undefined), configurable: true }); + globalMocks.mockResolveQp.mockResolvedValueOnce(undefined); await ProfileManagement.manageProfile(globalMocks.mockDsSessionNode as any); expect(globalMocks.debugLogSpy).toBeCalledWith(globalMocks.logMsg); expect(globalMocks.opCancelledSpy).toBeCalledWith("Operation Cancelled"); @@ -152,10 +143,7 @@ describe("ProfileManagement unit tests", () => { it("profile using token authentication should see ssoLogin called when Log in to authentication service chosen", async () => { const globalMocks = createGlobalMocks(); createBlockMocks(globalMocks); - Object.defineProperty(Gui, "resolveQuickPick", { - value: jest.fn().mockResolvedValueOnce(globalMocks.mockLoginChosen), - configurable: true, - }); + globalMocks.mockResolveQp.mockResolvedValueOnce(globalMocks.mockLoginChosen); await ProfileManagement.manageProfile(globalMocks.mockDsSessionNode as any); expect(globalMocks.debugLogSpy).toBeCalledWith(globalMocks.logMsg); expect(globalMocks.loginSpy).toBeCalled(); @@ -163,10 +151,7 @@ describe("ProfileManagement unit tests", () => { it("profile using token authentication should see ssoLogout called when Log out from authentication service chosen", async () => { const globalMocks = createGlobalMocks(); createBlockMocks(globalMocks); - Object.defineProperty(Gui, "resolveQuickPick", { - value: jest.fn().mockResolvedValueOnce(globalMocks.mockLogoutChosen), - configurable: true, - }); + globalMocks.mockResolveQp.mockResolvedValueOnce(globalMocks.mockLogoutChosen); await ProfileManagement.manageProfile(globalMocks.mockDsSessionNode as any); expect(globalMocks.debugLogSpy).toBeCalledWith(globalMocks.logMsg); expect(globalMocks.logoutSpy).toBeCalled(); @@ -194,7 +179,7 @@ describe("ProfileManagement unit tests", () => { it("profile with no authentication method should see Operation Cancelled when escaping quick pick", async () => { const globalMocks = createGlobalMocks(); createBlockMocks(globalMocks); - Object.defineProperty(Gui, "resolveQuickPick", { value: jest.fn().mockResolvedValueOnce(undefined), configurable: true }); + globalMocks.mockResolveQp.mockResolvedValueOnce(undefined); await ProfileManagement.manageProfile(globalMocks.mockDsSessionNode as any); expect(globalMocks.debugLogSpy).toBeCalledWith(globalMocks.logMsg); expect(globalMocks.opCancelledSpy).toBeCalledWith("Operation Cancelled"); @@ -202,10 +187,7 @@ describe("ProfileManagement unit tests", () => { it("profile with no authentication method should see promptCredentials called when Add Basic Credentials chosen", async () => { const globalMocks = createGlobalMocks(); createBlockMocks(globalMocks); - Object.defineProperty(Gui, "resolveQuickPick", { - value: jest.fn().mockResolvedValueOnce(globalMocks.mockAddBasicChosen), - configurable: true, - }); + globalMocks.mockResolveQp.mockResolvedValueOnce(globalMocks.mockAddBasicChosen); await ProfileManagement.manageProfile(globalMocks.mockDsSessionNode as any); expect(globalMocks.debugLogSpy).toBeCalledWith(globalMocks.logMsg); expect(globalMocks.promptSpy).toBeCalled(); @@ -213,10 +195,7 @@ describe("ProfileManagement unit tests", () => { it("profile with no authentication method should see ssoLogin called when Log in to authentication service chosen", async () => { const globalMocks = createGlobalMocks(); createBlockMocks(globalMocks); - Object.defineProperty(Gui, "resolveQuickPick", { - value: jest.fn().mockResolvedValueOnce(globalMocks.mockLoginChosen), - configurable: true, - }); + globalMocks.mockResolveQp.mockResolvedValueOnce(globalMocks.mockLoginChosen); await ProfileManagement.manageProfile(globalMocks.mockDsSessionNode as any); expect(globalMocks.debugLogSpy).toBeCalledWith(globalMocks.logMsg); expect(globalMocks.loginSpy).toBeCalled(); @@ -224,10 +203,7 @@ describe("ProfileManagement unit tests", () => { it("profile with no authentication method should see editSession called when Edit Profile chosen", async () => { const globalMocks = createGlobalMocks(); createBlockMocks(globalMocks); - Object.defineProperty(Gui, "resolveQuickPick", { - value: jest.fn().mockResolvedValueOnce(globalMocks.mockEditProfChosen), - configurable: true, - }); + globalMocks.mockResolveQp.mockResolvedValueOnce(globalMocks.mockEditProfChosen); await ProfileManagement.manageProfile(globalMocks.mockDsSessionNode as any); expect(globalMocks.debugLogSpy).toBeCalledWith(globalMocks.logMsg); expect(globalMocks.editSpy).toBeCalled(); From 4d4637c0635b74b02420eaf2c2badae01d0f8c2a Mon Sep 17 00:00:00 2001 From: Billie Simmons <49491949+JillieBeanSim@users.noreply.github.com> Date: Fri, 22 Sep 2023 18:10:49 -0400 Subject: [PATCH 043/189] this should fix high duplication failure Signed-off-by: Billie Simmons <49491949+JillieBeanSim@users.noreply.github.com> --- .../utils/ProfileManagement.unit.test.ts | 39 ++++++------------- 1 file changed, 12 insertions(+), 27 deletions(-) diff --git a/packages/zowe-explorer/__tests__/__unit__/utils/ProfileManagement.unit.test.ts b/packages/zowe-explorer/__tests__/__unit__/utils/ProfileManagement.unit.test.ts index cb6766e044..39483cfc0e 100644 --- a/packages/zowe-explorer/__tests__/__unit__/utils/ProfileManagement.unit.test.ts +++ b/packages/zowe-explorer/__tests__/__unit__/utils/ProfileManagement.unit.test.ts @@ -67,19 +67,24 @@ describe("ProfileManagement unit tests", () => { }); Object.defineProperty(Gui, "createQuickPick", { value: newMocks.mockCreateQp, configurable: true }); + newMocks.mockProfileInstance = sharedMock.createInstanceOfProfile(newMocks.mockBasicAuthProfile); + Object.defineProperty(Profiles, "getInstance", { + value: jest.fn().mockReturnValue(newMocks.mockProfileInstance), + configurable: true, + }); + Object.defineProperty(newMocks.mockProfileInstance, "editSession", { value: jest.fn(), configurable: true }); + newMocks.editSpy = jest.spyOn(newMocks.mockProfileInstance, "editSession"); + Object.defineProperty(newMocks.mockProfileInstance, "ssoLogin", { value: jest.fn(), configurable: true }); + newMocks.loginSpy = jest.spyOn(newMocks.mockProfileInstance, "ssoLogin"); + Object.defineProperty(newMocks.mockProfileInstance, "ssoLogout", { value: jest.fn(), configurable: true }); + newMocks.logoutSpy = jest.spyOn(newMocks.mockProfileInstance, "ssoLogout"); + return newMocks; } describe("unit tests around basic auth selections", () => { function createBlockMocks(globalMocks) { globalMocks.logMsg = `Profile ${globalMocks.mockBasicAuthProfile.name} is using basic authentication.`; - globalMocks.mockProfileInstance = sharedMock.createInstanceOfProfile(globalMocks.mockBasicAuthProfile); - Object.defineProperty(Profiles, "getInstance", { - value: jest.fn().mockReturnValue(globalMocks.mockProfileInstance), - configurable: true, - }); - Object.defineProperty(globalMocks.mockProfileInstance, "editSession", { value: jest.fn(), configurable: true }); - globalMocks.editSpy = jest.spyOn(globalMocks.mockProfileInstance, "editSession"); globalMocks.mockDsSessionNode = dsMock.createDatasetSessionNode(globalMocks.mockSession, globalMocks.mockBasicAuthProfile) as any; Object.defineProperty(globalMocks.mockDsSessionNode, "getProfile", { value: jest.fn().mockReturnValue(globalMocks.mockBasicAuthProfile), @@ -114,17 +119,6 @@ describe("ProfileManagement unit tests", () => { describe("unit tests around token auth selections", () => { function createBlockMocks(globalMocks) { globalMocks.logMsg = `Profile ${globalMocks.mockTokenAuthProfile.name} is using token authentication.`; - globalMocks.mockProfileInstance = sharedMock.createInstanceOfProfile(globalMocks.mockTokenAuthProfile); - Object.defineProperty(Profiles, "getInstance", { - value: jest.fn().mockReturnValue(globalMocks.mockProfileInstance), - configurable: true, - }); - Object.defineProperty(globalMocks.mockProfileInstance, "editSession", { value: jest.fn(), configurable: true }); - globalMocks.editSpy = jest.spyOn(globalMocks.mockProfileInstance, "editSession"); - Object.defineProperty(globalMocks.mockProfileInstance, "ssoLogin", { value: jest.fn(), configurable: true }); - globalMocks.loginSpy = jest.spyOn(Profiles.getInstance(), "ssoLogin"); - Object.defineProperty(globalMocks.mockProfileInstance, "ssoLogout", { value: jest.fn(), configurable: true }); - globalMocks.logoutSpy = jest.spyOn(Profiles.getInstance(), "ssoLogout"); Object.defineProperty(profUtils.ProfilesUtils, "isUsingTokenAuth", { value: jest.fn().mockResolvedValueOnce(true), configurable: true }); globalMocks.mockDsSessionNode = dsMock.createDatasetSessionNode(globalMocks.mockSession, globalMocks.mockTokenAuthProfile) as any; Object.defineProperty(globalMocks.mockDsSessionNode, "getProfile", { @@ -160,15 +154,6 @@ describe("ProfileManagement unit tests", () => { describe("unit tests around no auth declared selections", () => { function createBlockMocks(globalMocks) { globalMocks.logMsg = `Profile ${globalMocks.mockNoAuthProfile.name} authentication method is unkown.`; - globalMocks.mockProfileInstance = sharedMock.createInstanceOfProfile(globalMocks.mockNoAuthProfile); - Object.defineProperty(Profiles, "getInstance", { - value: jest.fn().mockReturnValue(globalMocks.mockProfileInstance), - configurable: true, - }); - Object.defineProperty(globalMocks.mockProfileInstance, "editSession", { value: jest.fn(), configurable: true }); - globalMocks.editSpy = jest.spyOn(globalMocks.mockProfileInstance, "editSession"); - Object.defineProperty(globalMocks.mockProfileInstance, "ssoLogin", { value: jest.fn(), configurable: true }); - globalMocks.loginSpy = jest.spyOn(Profiles.getInstance(), "ssoLogin"); Object.defineProperty(profUtils.ProfilesUtils, "isUsingTokenAuth", { value: jest.fn().mockResolvedValueOnce(false), configurable: true }); globalMocks.mockDsSessionNode = dsMock.createDatasetSessionNode(globalMocks.mockSession, globalMocks.mockTokenAuthProfile) as any; Object.defineProperty(globalMocks.mockDsSessionNode, "getProfile", { From c22dbc26fee2f10623c0169940fbc07d0b12873b Mon Sep 17 00:00:00 2001 From: Billie Simmons <49491949+JillieBeanSim@users.noreply.github.com> Date: Fri, 22 Sep 2023 18:18:25 -0400 Subject: [PATCH 044/189] don't think I can condense anything else from file Signed-off-by: Billie Simmons <49491949+JillieBeanSim@users.noreply.github.com> --- .../__tests__/__unit__/utils/ProfileManagement.unit.test.ts | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/packages/zowe-explorer/__tests__/__unit__/utils/ProfileManagement.unit.test.ts b/packages/zowe-explorer/__tests__/__unit__/utils/ProfileManagement.unit.test.ts index 39483cfc0e..c186bd18b3 100644 --- a/packages/zowe-explorer/__tests__/__unit__/utils/ProfileManagement.unit.test.ts +++ b/packages/zowe-explorer/__tests__/__unit__/utils/ProfileManagement.unit.test.ts @@ -66,7 +66,7 @@ describe("ProfileManagement unit tests", () => { }), }); Object.defineProperty(Gui, "createQuickPick", { value: newMocks.mockCreateQp, configurable: true }); - + newMocks.mockDsSessionNode = dsMock.createDatasetSessionNode(newMocks.mockSession, newMocks.mockBasicAuthProfile) as any; newMocks.mockProfileInstance = sharedMock.createInstanceOfProfile(newMocks.mockBasicAuthProfile); Object.defineProperty(Profiles, "getInstance", { value: jest.fn().mockReturnValue(newMocks.mockProfileInstance), @@ -85,7 +85,6 @@ describe("ProfileManagement unit tests", () => { describe("unit tests around basic auth selections", () => { function createBlockMocks(globalMocks) { globalMocks.logMsg = `Profile ${globalMocks.mockBasicAuthProfile.name} is using basic authentication.`; - globalMocks.mockDsSessionNode = dsMock.createDatasetSessionNode(globalMocks.mockSession, globalMocks.mockBasicAuthProfile) as any; Object.defineProperty(globalMocks.mockDsSessionNode, "getProfile", { value: jest.fn().mockReturnValue(globalMocks.mockBasicAuthProfile), configurable: true, @@ -120,7 +119,6 @@ describe("ProfileManagement unit tests", () => { function createBlockMocks(globalMocks) { globalMocks.logMsg = `Profile ${globalMocks.mockTokenAuthProfile.name} is using token authentication.`; Object.defineProperty(profUtils.ProfilesUtils, "isUsingTokenAuth", { value: jest.fn().mockResolvedValueOnce(true), configurable: true }); - globalMocks.mockDsSessionNode = dsMock.createDatasetSessionNode(globalMocks.mockSession, globalMocks.mockTokenAuthProfile) as any; Object.defineProperty(globalMocks.mockDsSessionNode, "getProfile", { value: jest.fn().mockReturnValue(globalMocks.mockTokenAuthProfile), configurable: true, @@ -155,7 +153,6 @@ describe("ProfileManagement unit tests", () => { function createBlockMocks(globalMocks) { globalMocks.logMsg = `Profile ${globalMocks.mockNoAuthProfile.name} authentication method is unkown.`; Object.defineProperty(profUtils.ProfilesUtils, "isUsingTokenAuth", { value: jest.fn().mockResolvedValueOnce(false), configurable: true }); - globalMocks.mockDsSessionNode = dsMock.createDatasetSessionNode(globalMocks.mockSession, globalMocks.mockTokenAuthProfile) as any; Object.defineProperty(globalMocks.mockDsSessionNode, "getProfile", { value: jest.fn().mockReturnValue(globalMocks.mockNoAuthProfile), configurable: true, From 39194d0515a61375b91331a840dbf93da7103a82 Mon Sep 17 00:00:00 2001 From: Billie Simmons <49491949+JillieBeanSim@users.noreply.github.com> Date: Fri, 22 Sep 2023 19:27:38 -0400 Subject: [PATCH 045/189] add delete to management options and group left profile items Signed-off-by: Billie Simmons <49491949+JillieBeanSim@users.noreply.github.com> --- .../utils/ProfileManagement.unit.test.ts | 31 ++++++++++++++- .../src/utils/ProfileManagement.i18n.json | 1 + packages/zowe-explorer/package.json | 39 ++++++------------- .../src/utils/ProfileManagement.ts | 39 ++++++++++++++----- 4 files changed, 73 insertions(+), 37 deletions(-) diff --git a/packages/zowe-explorer/__tests__/__unit__/utils/ProfileManagement.unit.test.ts b/packages/zowe-explorer/__tests__/__unit__/utils/ProfileManagement.unit.test.ts index c186bd18b3..12c62e7ca4 100644 --- a/packages/zowe-explorer/__tests__/__unit__/utils/ProfileManagement.unit.test.ts +++ b/packages/zowe-explorer/__tests__/__unit__/utils/ProfileManagement.unit.test.ts @@ -17,6 +17,7 @@ import { ProfileManagement } from "../../../src/utils/ProfileManagement"; import { Gui } from "@zowe/zowe-explorer-api"; import { ZoweLogger } from "../../../src/utils/LoggerUtils"; import { Profiles } from "../../../src/Profiles"; +import * as vscode from "vscode"; jest.mock("fs"); jest.mock("vscode"); @@ -40,7 +41,8 @@ describe("ProfileManagement unit tests", () => { mockAddBasicChosen: ProfileManagement.basicAuthAddQpItems[ProfileManagement.AuthQpLabels.add], mockLoginChosen: ProfileManagement.tokenAuthLoginQpItem[ProfileManagement.AuthQpLabels.login], mockLogoutChosen: ProfileManagement.tokenAuthLogoutQpItem[ProfileManagement.AuthQpLabels.logout], - mockEditProfChosen: ProfileManagement.otherProfileQpItems[ProfileManagement.AuthQpLabels.edit], + mockEditProfChosen: ProfileManagement.editProfileQpItems[ProfileManagement.AuthQpLabels.edit], + mockDeleteProfChosen: ProfileManagement.deleteProfileQpItem[ProfileManagement.AuthQpLabels.delete], mockProfileInstance: null as any, debugLogSpy: null as any, promptSpy: null as any, @@ -89,6 +91,7 @@ describe("ProfileManagement unit tests", () => { value: jest.fn().mockReturnValue(globalMocks.mockBasicAuthProfile), configurable: true, }); + Object.defineProperty(vscode.commands, "executeCommand", { value: jest.fn(), configurable: true }); } it("profile using basic authentication should see Operation Cancelled when escaping quick pick", async () => { const globalMocks = createGlobalMocks(); @@ -114,6 +117,32 @@ describe("ProfileManagement unit tests", () => { expect(globalMocks.debugLogSpy).toBeCalledWith(globalMocks.logMsg); expect(globalMocks.editSpy).toBeCalled(); }); + it("profile using basic authentication should see editSession called when Delete Profile chosen with v2 profile", async () => { + const globalMocks = createGlobalMocks(); + createBlockMocks(globalMocks); + globalMocks.mockResolveQp.mockResolvedValueOnce(globalMocks.mockDeleteProfChosen); + Object.defineProperty(globalMocks.mockProfileInstance, "getProfileInfo", { + value: jest.fn().mockResolvedValueOnce({ usingTeamConfig: true }), + configurable: true, + }); + await ProfileManagement.manageProfile(globalMocks.mockDsSessionNode as any); + expect(globalMocks.debugLogSpy).toBeCalledWith(globalMocks.logMsg); + expect(globalMocks.editSpy).toBeCalled(); + }); + it("profile using basic authentication should see delete commands called when Delete Profile chosen with v1 profile", async () => { + const globalMocks = createGlobalMocks(); + createBlockMocks(globalMocks); + globalMocks.mockResolveQp.mockResolvedValueOnce(globalMocks.mockDeleteProfChosen); + Object.defineProperty(globalMocks.mockProfileInstance, "getProfileInfo", { + value: jest.fn().mockResolvedValueOnce({ usingTeamConfig: false }), + configurable: true, + }); + const commandSpy = jest.spyOn(vscode.commands, "executeCommand"); + await ProfileManagement.manageProfile(globalMocks.mockDsSessionNode as any); + expect(globalMocks.debugLogSpy).toBeCalledWith(globalMocks.logMsg); + expect(globalMocks.editSpy).not.toBeCalled(); + expect(commandSpy).toBeCalled(); + }); }); describe("unit tests around token auth selections", () => { function createBlockMocks(globalMocks) { diff --git a/packages/zowe-explorer/i18n/sample/src/utils/ProfileManagement.i18n.json b/packages/zowe-explorer/i18n/sample/src/utils/ProfileManagement.i18n.json index d168f6392d..1afb08edfe 100644 --- a/packages/zowe-explorer/i18n/sample/src/utils/ProfileManagement.i18n.json +++ b/packages/zowe-explorer/i18n/sample/src/utils/ProfileManagement.i18n.json @@ -7,6 +7,7 @@ "addBasicAuthQpItem.addCredentials.qpDetail": "Add username and password for basic authentication", "updateBasicAuthQpItem.updateCredentials.qpLabel": "$(refresh) Update Credentials", "updateBasicAuthQpItem.updateCredentials.qpDetail": "Update stored username and password", + "deleteProfileQpItem.delete.qpLabel": "$(trash) Delete Profile", "editProfileQpItem.editProfile.qpLabel": "$(pencil) Edit profile", "editProfileQpItem.editProfile.qpDetail": "Update profile connection information", "loginQpItem.login.qpLabel": "$(arrow-right) Log in to authentication service", diff --git a/packages/zowe-explorer/package.json b/packages/zowe-explorer/package.json index 773b4556e8..398a82c58b 100644 --- a/packages/zowe-explorer/package.json +++ b/packages/zowe-explorer/package.json @@ -961,27 +961,22 @@ { "when": "view == zowe.uss.explorer && viewItem =~ /_validate/ && !listMultiSelection", "command": "zowe.uss.disableValidation", - "group": "098_zowe_ussProfileAuthentication@1" + "group": "099_zowe_ussProfileAuthentication@96" }, { "when": "view == zowe.uss.explorer && viewItem =~ /_noValidate/ && !listMultiSelection", "command": "zowe.uss.enableValidation", - "group": "098_zowe_ussProfileAuthentication@2" + "group": "099_zowe_ussProfileAuthentication@97" }, { "when": "view == zowe.uss.explorer && viewItem =~ /^(?!.*_fav.*)ussSession.*/ && !listMultiSelection", "command": "zowe.profileManagement", - "group": "099_zowe_ussProfileAuthentication@97" + "group": "099_zowe_ussProfileAuthentication@99" }, { "when": "viewItem =~ /^(?!.*_fav.*)ussSession.*/", "command": "zowe.uss.removeSession", - "group": "099_zowe_ussProfileModification@98" - }, - { - "when": "viewItem =~ /^(?!.*_fav.*)ussSession.*/ && !listMultiSelection", - "command": "zowe.uss.deleteProfile", - "group": "099_zowe_ussProfileModification@99" + "group": "099_zowe_ussProfileAuthentication@98" }, { "when": "view == zowe.ds.explorer && viewItem =~ /^(?!.*_fav.*)session.*/ && !listMultiSelection", @@ -1161,27 +1156,22 @@ { "when": "view == zowe.ds.explorer && viewItem =~ /_validate/ && !listMultiSelection", "command": "zowe.ds.disableValidation", - "group": "098_zowe_dsProfileAuthentication@6" + "group": "099_zowe_dsProfileAuthentication@96" }, { "when": "view == zowe.ds.explorer && viewItem =~ /_noValidate/ && !listMultiSelection", "command": "zowe.ds.enableValidation", - "group": "098_zowe_dsProfileAuthentication@7" + "group": "099_zowe_dsProfileAuthentication@97" }, { "when": "view == zowe.ds.explorer && viewItem =~ /^(?!.*_fav.*)session.*/ && !listMultiSelection", "command": "zowe.profileManagement", - "group": "099_zowe_dsProfileAuthentication@97" + "group": "099_zowe_dsProfileAuthentication@99" }, { "when": "view == zowe.ds.explorer && viewItem =~ /^(?!.*_fav.*)session.*/", "command": "zowe.ds.removeSession", - "group": "099_zowe_dsProfileModification@98" - }, - { - "when": "view == zowe.ds.explorer && viewItem =~ /^(?!.*_fav.*)session.*/ && !listMultiSelection", - "command": "zowe.ds.deleteProfile", - "group": "099_zowe_dsProfileModification@99" + "group": "099_zowe_dsProfileAuthentication@98" }, { "when": "view == zowe.jobs.explorer && viewItem =~ /^(?!.*_fav.*)server.*/ && !listMultiSelection", @@ -1311,27 +1301,22 @@ { "when": "view == zowe.jobs.explorer && viewItem =~ /_validate/ && !listMultiSelection", "command": "zowe.jobs.disableValidation", - "group": "098_zowe_jobsProfileAuthentication@3" + "group": "099_zowe_jobsProfileAuthentication@96" }, { "when": "view == zowe.jobs.explorer && viewItem =~ /_noValidate/ && !listMultiSelection", "command": "zowe.jobs.enableValidation", - "group": "098_zowe_jobsProfileAuthentication@4" + "group": "099_zowe_jobsProfileAuthentication@97" }, { "when": "view == zowe.jobs.explorer && viewItem =~ /^(?!.*_fav.*)server.*/ && !listMultiSelection", "command": "zowe.profileManagement", - "group": "098_zowe_jobsProfileAuthentication@97" + "group": "099_zowe_jobsProfileAuthentication@99" }, { "when": "view == zowe.jobs.explorer && viewItem =~ /^(?!.*_fav.*)server.*/", "command": "zowe.jobs.removeJobsSession", - "group": "099_zowe_jobsProfileModification@98" - }, - { - "when": "view == zowe.jobs.explorer && viewItem =~ /^(?!.*_fav.*)server.*/ && !listMultiSelection", - "command": "zowe.jobs.deleteProfile", - "group": "099_zowe_jobsProfileModification@99" + "group": "099_zowe_jobsProfileAuthentication@98" }, { "when": "view == zowe.jobs.explorer && viewItem =~ /^(?!.*_fav.*)server.*/ && !listMultiSelection", diff --git a/packages/zowe-explorer/src/utils/ProfileManagement.ts b/packages/zowe-explorer/src/utils/ProfileManagement.ts index efb5f69477..7369b59ab2 100644 --- a/packages/zowe-explorer/src/utils/ProfileManagement.ts +++ b/packages/zowe-explorer/src/utils/ProfileManagement.ts @@ -48,11 +48,12 @@ export class ProfileManagement { await this.handleAuthSelection(selected, node, profile); } public static AuthQpLabels = { - update: "update-credentials", + add: "add-credentials", + delete: "delete", edit: "edit-profile", login: "obtain-token", logout: "invalidate-token", - add: "add-credentials", + update: "update-credentials", }; public static basicAuthAddQpItems: Record = { [this.AuthQpLabels.add]: { @@ -66,7 +67,12 @@ export class ProfileManagement { description: localize("updateBasicAuthQpItem.updateCredentials.qpDetail", "Update stored username and password"), }, }; - public static otherProfileQpItems: Record = { + public static deleteProfileQpItem: Record = { + [this.AuthQpLabels.delete]: { + label: localize("deleteProfileQpItem.delete.qpLabel", "$(trash) Delete Profile"), + }, + }; + public static editProfileQpItems: Record = { [this.AuthQpLabels.edit]: { label: localize("editProfileQpItem.editProfile.qpLabel", "$(pencil) Edit profile"), description: localize("editProfileQpItem.editProfile.qpDetail", "Update profile connection information"), @@ -119,7 +125,7 @@ export class ProfileManagement { await ProfilesUtils.promptCredentials(node); break; } - case this.otherProfileQpItems[this.AuthQpLabels.edit]: { + case this.editProfileQpItems[this.AuthQpLabels.edit]: { await Profiles.getInstance().editSession(profile, profile.name); break; } @@ -135,6 +141,10 @@ export class ProfileManagement { await ProfilesUtils.promptCredentials(node); break; } + case this.deleteProfileQpItem[this.AuthQpLabels.delete]: { + await this.handleDeleteProfiles(node); + break; + } default: { Gui.infoMessage(localize("profiles.operation.cancelled", "Operation Cancelled")); break; @@ -156,21 +166,32 @@ export class ProfileManagement { private static basicAuthQp(): vscode.QuickPickItem[] { const quickPickOptions: vscode.QuickPickItem[] = Object.values(this.basicAuthUpdateQpItems); - quickPickOptions.push(this.otherProfileQpItems[this.AuthQpLabels.edit]); - return quickPickOptions; + return this.addFinalQpOptions(quickPickOptions); } private static tokenAuthQp(profile: imperative.IProfileLoaded): vscode.QuickPickItem[] { const quickPickOptions: vscode.QuickPickItem[] = Object.values(this.tokenAuthLoginQpItem); if (profile.profile.tokenType) { quickPickOptions.push(this.tokenAuthLogoutQpItem[this.AuthQpLabels.logout]); } - quickPickOptions.push(this.otherProfileQpItems[this.AuthQpLabels.edit]); - return quickPickOptions; + return this.addFinalQpOptions(quickPickOptions); } private static chooseAuthQp(): vscode.QuickPickItem[] { const quickPickOptions: vscode.QuickPickItem[] = Object.values(this.basicAuthAddQpItems); quickPickOptions.push(this.tokenAuthLoginQpItem[this.AuthQpLabels.login]); - quickPickOptions.push(this.otherProfileQpItems[this.AuthQpLabels.edit]); + return this.addFinalQpOptions(quickPickOptions); + } + private static addFinalQpOptions(quickPickOptions: vscode.QuickPickItem[]): vscode.QuickPickItem[] { + quickPickOptions.push(this.editProfileQpItems[this.AuthQpLabels.edit]); + quickPickOptions.push(this.deleteProfileQpItem[this.AuthQpLabels.delete]); return quickPickOptions; } + private static async handleDeleteProfiles(node: IZoweTreeNode): Promise { + const profInfo = await Profiles.getInstance().getProfileInfo(); + if (profInfo.usingTeamConfig) { + const profile = node.getProfile(); + await Profiles.getInstance().editSession(profile, profile.name); + return; + } + await vscode.commands.executeCommand("zowe.ds.deleteProfile", node); + } } From 8daf4114ee1b5d5cb340b8f1117003349dba5645 Mon Sep 17 00:00:00 2001 From: Billie Simmons <49491949+JillieBeanSim@users.noreply.github.com> Date: Fri, 22 Sep 2023 20:14:35 -0400 Subject: [PATCH 046/189] should fix theia tests for delete Signed-off-by: Billie Simmons <49491949+JillieBeanSim@users.noreply.github.com> --- .../__tests__/__theia__/theia/Locators.ts | 2 +- .../__theia__/theia/extension.theiaChrome.ts | 14 ++++++++++---- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/packages/zowe-explorer/__tests__/__theia__/theia/Locators.ts b/packages/zowe-explorer/__tests__/__theia__/theia/Locators.ts index 089c6386bc..2b8793dba2 100644 --- a/packages/zowe-explorer/__tests__/__theia__/theia/Locators.ts +++ b/packages/zowe-explorer/__tests__/__theia__/theia/Locators.ts @@ -28,7 +28,7 @@ export const DatasetsLocators = { favoriteProfileInDatasetXpath: "(//div[contains(@id,'Favorites') and contains(@id,'TestSeleniumProfile')])", addToFavoriteOptionXpath: "//li[@data-command='zowe.ds.saveSearch']", removeFavoriteProfileFromDatasetsOptionXpath: "//li[@data-command='zowe.ds.removeFavProfile']", - deleteProfileFromDatasetsXpath: "(//li[@data-command='zowe.ds.deleteProfile'])", + manageProfileFromDatasetsXpath: "(//li[@data-command='zowe.profileManagement'])", }; export const UssLocators = { diff --git a/packages/zowe-explorer/__tests__/__theia__/theia/extension.theiaChrome.ts b/packages/zowe-explorer/__tests__/__theia__/theia/extension.theiaChrome.ts index d9bd97df36..7d79c7eb9b 100644 --- a/packages/zowe-explorer/__tests__/__theia__/theia/extension.theiaChrome.ts +++ b/packages/zowe-explorer/__tests__/__theia__/theia/extension.theiaChrome.ts @@ -170,23 +170,29 @@ export async function verifyProfileIsHideInJobs() { export async function deleteDefaultProfileInDatasets() { const profileName = await driverChrome.wait(until.elementLocated(By.xpath(DatasetsLocators.defaultDatasetsProfileXpath)), WAITTIME); await driverChrome.actions().click(profileName, Button.RIGHT).perform(); - await driverChrome.wait(until.elementLocated(By.xpath(DatasetsLocators.deleteProfileFromDatasetsXpath)), WAITTIME).click(); + await driverChrome.wait(until.elementLocated(By.xpath(DatasetsLocators.manageProfileFromDatasetsXpath)), WAITTIME).click(); + await driverChrome.sleep(SHORTSLEEPTIME); + const manageProfile = driverChrome.wait(until.elementLocated(By.xpath(DatasetsLocators.emptyInputBoxXpath)), WAITTIME); + manageProfile.sendKeys("Delete Profile"); + manageProfile.sendKeys(Key.ENTER); await driverChrome.sleep(SHORTSLEEPTIME); const deleteProfile = driverChrome.wait(until.elementLocated(By.xpath(DatasetsLocators.emptyInputBoxXpath)), WAITTIME); deleteProfile.sendKeys("Delete"); deleteProfile.sendKeys(Key.ENTER); - return; } export async function deleteProfileInDatasets() { const favprofile = await driverChrome.wait(until.elementLocated(By.xpath(DatasetsLocators.secondDatasetProfileXpath)), WAITTIME); await driverChrome.actions().click(favprofile, Button.RIGHT).perform(); - await driverChrome.wait(until.elementLocated(By.xpath(DatasetsLocators.deleteProfileFromDatasetsXpath)), WAITTIME).click(); + await driverChrome.wait(until.elementLocated(By.xpath(DatasetsLocators.manageProfileFromDatasetsXpath)), WAITTIME).click(); + await driverChrome.sleep(SHORTSLEEPTIME); + const manageProfile = driverChrome.wait(until.elementLocated(By.xpath(DatasetsLocators.emptyInputBoxXpath)), WAITTIME); + manageProfile.sendKeys("Delete Profile"); + manageProfile.sendKeys(Key.ENTER); await driverChrome.sleep(SHORTSLEEPTIME); const deleteProfile = driverChrome.wait(until.elementLocated(By.xpath(DatasetsLocators.emptyInputBoxXpath)), WAITTIME); deleteProfile.sendKeys("Delete"); deleteProfile.sendKeys(Key.ENTER); - return; } export async function verifyRemovedFavoriteProfileInDatasets() { From 6d491d816e3a4738f41fb5ef955146a977c37d1f Mon Sep 17 00:00:00 2001 From: Billie Simmons <49491949+JillieBeanSim@users.noreply.github.com> Date: Fri, 22 Sep 2023 20:41:21 -0400 Subject: [PATCH 047/189] about as clean as test file can get Signed-off-by: Billie Simmons <49491949+JillieBeanSim@users.noreply.github.com> --- .../utils/ProfileManagement.unit.test.ts | 169 ++++++++---------- 1 file changed, 75 insertions(+), 94 deletions(-) diff --git a/packages/zowe-explorer/__tests__/__unit__/utils/ProfileManagement.unit.test.ts b/packages/zowe-explorer/__tests__/__unit__/utils/ProfileManagement.unit.test.ts index 12c62e7ca4..616f590df1 100644 --- a/packages/zowe-explorer/__tests__/__unit__/utils/ProfileManagement.unit.test.ts +++ b/packages/zowe-explorer/__tests__/__unit__/utils/ProfileManagement.unit.test.ts @@ -18,6 +18,7 @@ import { Gui } from "@zowe/zowe-explorer-api"; import { ZoweLogger } from "../../../src/utils/LoggerUtils"; import { Profiles } from "../../../src/Profiles"; import * as vscode from "vscode"; +import { imperative } from "@zowe/cli"; jest.mock("fs"); jest.mock("vscode"); @@ -27,7 +28,7 @@ describe("ProfileManagement unit tests", () => { jest.clearAllMocks(); jest.resetAllMocks(); }); - function createGlobalMocks() { + function createGlobalMocks(): any { const newMocks = { mockSession: sharedMock.createISession(), mockBasicAuthProfile: sharedMock.createValidIProfile(), @@ -43,6 +44,7 @@ describe("ProfileManagement unit tests", () => { mockLogoutChosen: ProfileManagement.tokenAuthLogoutQpItem[ProfileManagement.AuthQpLabels.logout], mockEditProfChosen: ProfileManagement.editProfileQpItems[ProfileManagement.AuthQpLabels.edit], mockDeleteProfChosen: ProfileManagement.deleteProfileQpItem[ProfileManagement.AuthQpLabels.delete], + mockProfileInfo: { usingTeamConfig: true }, mockProfileInstance: null as any, debugLogSpy: null as any, promptSpy: null as any, @@ -85,139 +87,118 @@ describe("ProfileManagement unit tests", () => { } describe("unit tests around basic auth selections", () => { - function createBlockMocks(globalMocks) { + function createBlockMocks(globalMocks): any { globalMocks.logMsg = `Profile ${globalMocks.mockBasicAuthProfile.name} is using basic authentication.`; - Object.defineProperty(globalMocks.mockDsSessionNode, "getProfile", { - value: jest.fn().mockReturnValue(globalMocks.mockBasicAuthProfile), - configurable: true, - }); + globalMocks.mockDsSessionNode.getProfile = jest.fn().mockReturnValue(globalMocks.mockBasicAuthProfile); Object.defineProperty(vscode.commands, "executeCommand", { value: jest.fn(), configurable: true }); + return globalMocks; } it("profile using basic authentication should see Operation Cancelled when escaping quick pick", async () => { - const globalMocks = createGlobalMocks(); - createBlockMocks(globalMocks); - globalMocks.mockResolveQp.mockResolvedValueOnce(undefined); - await ProfileManagement.manageProfile(globalMocks.mockDsSessionNode as any); - expect(globalMocks.debugLogSpy).toBeCalledWith(globalMocks.logMsg); - expect(globalMocks.opCancelledSpy).toBeCalledWith("Operation Cancelled"); + const mocks = createBlockMocks(createGlobalMocks()); + mocks.mockResolveQp.mockResolvedValueOnce(undefined); + await ProfileManagement.manageProfile(mocks.mockDsSessionNode); + expect(mocks.debugLogSpy).toBeCalledWith(mocks.logMsg); + expect(mocks.opCancelledSpy).toBeCalledWith("Operation Cancelled"); }); it("profile using basic authentication should see promptCredentials called when Update Credentials chosen", async () => { - const globalMocks = createGlobalMocks(); - createBlockMocks(globalMocks); - globalMocks.mockResolveQp.mockResolvedValueOnce(globalMocks.mockUpdateChosen); - await ProfileManagement.manageProfile(globalMocks.mockDsSessionNode as any); - expect(globalMocks.debugLogSpy).toBeCalledWith(globalMocks.logMsg); - expect(globalMocks.promptSpy).toBeCalled(); + const mocks = createBlockMocks(createGlobalMocks()); + mocks.mockResolveQp.mockResolvedValueOnce(mocks.mockUpdateChosen); + await ProfileManagement.manageProfile(mocks.mockDsSessionNode); + expect(mocks.debugLogSpy).toBeCalledWith(mocks.logMsg); + expect(mocks.promptSpy).toBeCalled(); }); it("profile using basic authentication should see editSession called when Edit Profile chosen", async () => { - const globalMocks = createGlobalMocks(); - createBlockMocks(globalMocks); - globalMocks.mockResolveQp.mockResolvedValueOnce(globalMocks.mockEditProfChosen); - await ProfileManagement.manageProfile(globalMocks.mockDsSessionNode as any); - expect(globalMocks.debugLogSpy).toBeCalledWith(globalMocks.logMsg); - expect(globalMocks.editSpy).toBeCalled(); + const mocks = createBlockMocks(createGlobalMocks()); + mocks.mockResolveQp.mockResolvedValueOnce(mocks.mockEditProfChosen); + await ProfileManagement.manageProfile(mocks.mockDsSessionNode); + expect(mocks.debugLogSpy).toBeCalledWith(mocks.logMsg); + expect(mocks.editSpy).toBeCalled(); }); it("profile using basic authentication should see editSession called when Delete Profile chosen with v2 profile", async () => { - const globalMocks = createGlobalMocks(); - createBlockMocks(globalMocks); - globalMocks.mockResolveQp.mockResolvedValueOnce(globalMocks.mockDeleteProfChosen); - Object.defineProperty(globalMocks.mockProfileInstance, "getProfileInfo", { - value: jest.fn().mockResolvedValueOnce({ usingTeamConfig: true }), + const mocks = createBlockMocks(createGlobalMocks()); + Object.defineProperty(mocks.mockProfileInstance, "getProfileInfo", { + value: jest.fn().mockResolvedValue(mocks.mockProfileInfo as imperative.ProfileInfo), configurable: true, }); - await ProfileManagement.manageProfile(globalMocks.mockDsSessionNode as any); - expect(globalMocks.debugLogSpy).toBeCalledWith(globalMocks.logMsg); - expect(globalMocks.editSpy).toBeCalled(); + mocks.mockResolveQp.mockResolvedValueOnce(mocks.mockDeleteProfChosen); + await ProfileManagement.manageProfile(mocks.mockDsSessionNode); + expect(mocks.debugLogSpy).toBeCalledWith(mocks.logMsg); + expect(mocks.editSpy).toBeCalled(); }); it("profile using basic authentication should see delete commands called when Delete Profile chosen with v1 profile", async () => { - const globalMocks = createGlobalMocks(); - createBlockMocks(globalMocks); - globalMocks.mockResolveQp.mockResolvedValueOnce(globalMocks.mockDeleteProfChosen); - Object.defineProperty(globalMocks.mockProfileInstance, "getProfileInfo", { - value: jest.fn().mockResolvedValueOnce({ usingTeamConfig: false }), - configurable: true, - }); + const mocks = createBlockMocks(createGlobalMocks()); + mocks.mockResolveQp.mockResolvedValueOnce(mocks.mockDeleteProfChosen); + mocks.mockProfileInfo.usingTeamConfig = false; const commandSpy = jest.spyOn(vscode.commands, "executeCommand"); - await ProfileManagement.manageProfile(globalMocks.mockDsSessionNode as any); - expect(globalMocks.debugLogSpy).toBeCalledWith(globalMocks.logMsg); - expect(globalMocks.editSpy).not.toBeCalled(); + await ProfileManagement.manageProfile(mocks.mockDsSessionNode); + expect(mocks.debugLogSpy).toBeCalledWith(mocks.logMsg); + expect(mocks.editSpy).not.toBeCalled(); expect(commandSpy).toBeCalled(); }); }); describe("unit tests around token auth selections", () => { - function createBlockMocks(globalMocks) { + function createBlockMocks(globalMocks): any { globalMocks.logMsg = `Profile ${globalMocks.mockTokenAuthProfile.name} is using token authentication.`; Object.defineProperty(profUtils.ProfilesUtils, "isUsingTokenAuth", { value: jest.fn().mockResolvedValueOnce(true), configurable: true }); - Object.defineProperty(globalMocks.mockDsSessionNode, "getProfile", { - value: jest.fn().mockReturnValue(globalMocks.mockTokenAuthProfile), - configurable: true, - }); + globalMocks.mockDsSessionNode.getProfile = jest.fn().mockReturnValue(globalMocks.mockTokenAuthProfile); + return globalMocks; } it("profile using token authentication should see Operation Cancelled when escaping quick pick", async () => { - const globalMocks = createGlobalMocks(); - createBlockMocks(globalMocks); - globalMocks.mockResolveQp.mockResolvedValueOnce(undefined); - await ProfileManagement.manageProfile(globalMocks.mockDsSessionNode as any); - expect(globalMocks.debugLogSpy).toBeCalledWith(globalMocks.logMsg); - expect(globalMocks.opCancelledSpy).toBeCalledWith("Operation Cancelled"); + const mocks = createBlockMocks(createGlobalMocks()); + mocks.mockResolveQp.mockResolvedValueOnce(undefined); + await ProfileManagement.manageProfile(mocks.mockDsSessionNode); + expect(mocks.debugLogSpy).toBeCalledWith(mocks.logMsg); + expect(mocks.opCancelledSpy).toBeCalledWith("Operation Cancelled"); }); it("profile using token authentication should see ssoLogin called when Log in to authentication service chosen", async () => { - const globalMocks = createGlobalMocks(); - createBlockMocks(globalMocks); - globalMocks.mockResolveQp.mockResolvedValueOnce(globalMocks.mockLoginChosen); - await ProfileManagement.manageProfile(globalMocks.mockDsSessionNode as any); - expect(globalMocks.debugLogSpy).toBeCalledWith(globalMocks.logMsg); - expect(globalMocks.loginSpy).toBeCalled(); + const mocks = createBlockMocks(createGlobalMocks()); + mocks.mockResolveQp.mockResolvedValueOnce(mocks.mockLoginChosen); + await ProfileManagement.manageProfile(mocks.mockDsSessionNode); + expect(mocks.debugLogSpy).toBeCalledWith(mocks.logMsg); + expect(mocks.loginSpy).toBeCalled(); }); it("profile using token authentication should see ssoLogout called when Log out from authentication service chosen", async () => { - const globalMocks = createGlobalMocks(); - createBlockMocks(globalMocks); - globalMocks.mockResolveQp.mockResolvedValueOnce(globalMocks.mockLogoutChosen); - await ProfileManagement.manageProfile(globalMocks.mockDsSessionNode as any); - expect(globalMocks.debugLogSpy).toBeCalledWith(globalMocks.logMsg); - expect(globalMocks.logoutSpy).toBeCalled(); + const mocks = createBlockMocks(createGlobalMocks()); + mocks.mockResolveQp.mockResolvedValueOnce(mocks.mockLogoutChosen); + await ProfileManagement.manageProfile(mocks.mockDsSessionNode); + expect(mocks.debugLogSpy).toBeCalledWith(mocks.logMsg); + expect(mocks.logoutSpy).toBeCalled(); }); }); describe("unit tests around no auth declared selections", () => { - function createBlockMocks(globalMocks) { + function createBlockMocks(globalMocks): any { globalMocks.logMsg = `Profile ${globalMocks.mockNoAuthProfile.name} authentication method is unkown.`; Object.defineProperty(profUtils.ProfilesUtils, "isUsingTokenAuth", { value: jest.fn().mockResolvedValueOnce(false), configurable: true }); - Object.defineProperty(globalMocks.mockDsSessionNode, "getProfile", { - value: jest.fn().mockReturnValue(globalMocks.mockNoAuthProfile), - configurable: true, - }); + globalMocks.mockDsSessionNode.getProfile = jest.fn().mockReturnValue(globalMocks.mockNoAuthProfile); + return globalMocks; } it("profile with no authentication method should see Operation Cancelled when escaping quick pick", async () => { - const globalMocks = createGlobalMocks(); - createBlockMocks(globalMocks); - globalMocks.mockResolveQp.mockResolvedValueOnce(undefined); - await ProfileManagement.manageProfile(globalMocks.mockDsSessionNode as any); - expect(globalMocks.debugLogSpy).toBeCalledWith(globalMocks.logMsg); - expect(globalMocks.opCancelledSpy).toBeCalledWith("Operation Cancelled"); + const mocks = createBlockMocks(createGlobalMocks()); + mocks.mockResolveQp.mockResolvedValueOnce(undefined); + await ProfileManagement.manageProfile(mocks.mockDsSessionNode); + expect(mocks.debugLogSpy).toBeCalledWith(mocks.logMsg); + expect(mocks.opCancelledSpy).toBeCalledWith("Operation Cancelled"); }); it("profile with no authentication method should see promptCredentials called when Add Basic Credentials chosen", async () => { - const globalMocks = createGlobalMocks(); - createBlockMocks(globalMocks); - globalMocks.mockResolveQp.mockResolvedValueOnce(globalMocks.mockAddBasicChosen); - await ProfileManagement.manageProfile(globalMocks.mockDsSessionNode as any); - expect(globalMocks.debugLogSpy).toBeCalledWith(globalMocks.logMsg); - expect(globalMocks.promptSpy).toBeCalled(); + const mocks = createBlockMocks(createGlobalMocks()); + mocks.mockResolveQp.mockResolvedValueOnce(mocks.mockAddBasicChosen); + await ProfileManagement.manageProfile(mocks.mockDsSessionNode); + expect(mocks.debugLogSpy).toBeCalledWith(mocks.logMsg); + expect(mocks.promptSpy).toBeCalled(); }); it("profile with no authentication method should see ssoLogin called when Log in to authentication service chosen", async () => { - const globalMocks = createGlobalMocks(); - createBlockMocks(globalMocks); - globalMocks.mockResolveQp.mockResolvedValueOnce(globalMocks.mockLoginChosen); - await ProfileManagement.manageProfile(globalMocks.mockDsSessionNode as any); - expect(globalMocks.debugLogSpy).toBeCalledWith(globalMocks.logMsg); - expect(globalMocks.loginSpy).toBeCalled(); + const mocks = createBlockMocks(createGlobalMocks()); + mocks.mockResolveQp.mockResolvedValueOnce(mocks.mockLoginChosen); + await ProfileManagement.manageProfile(mocks.mockDsSessionNode); + expect(mocks.debugLogSpy).toBeCalledWith(mocks.logMsg); + expect(mocks.loginSpy).toBeCalled(); }); it("profile with no authentication method should see editSession called when Edit Profile chosen", async () => { - const globalMocks = createGlobalMocks(); - createBlockMocks(globalMocks); - globalMocks.mockResolveQp.mockResolvedValueOnce(globalMocks.mockEditProfChosen); - await ProfileManagement.manageProfile(globalMocks.mockDsSessionNode as any); - expect(globalMocks.debugLogSpy).toBeCalledWith(globalMocks.logMsg); - expect(globalMocks.editSpy).toBeCalled(); + const mocks = createBlockMocks(createGlobalMocks()); + mocks.mockResolveQp.mockResolvedValueOnce(mocks.mockEditProfChosen); + await ProfileManagement.manageProfile(mocks.mockDsSessionNode); + expect(mocks.debugLogSpy).toBeCalledWith(mocks.logMsg); + expect(mocks.editSpy).toBeCalled(); }); }); }); From eaeec46da4c8e69d0204126ae770bb6d83cf54bc Mon Sep 17 00:00:00 2001 From: Billie Simmons <49491949+JillieBeanSim@users.noreply.github.com> Date: Fri, 22 Sep 2023 21:08:50 -0400 Subject: [PATCH 048/189] add message for manual editing with opening of config Signed-off-by: Billie Simmons <49491949+JillieBeanSim@users.noreply.github.com> --- packages/zowe-explorer/i18n/sample/src/Profiles.i18n.json | 1 + packages/zowe-explorer/src/Profiles.ts | 7 +++++-- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/packages/zowe-explorer/i18n/sample/src/Profiles.i18n.json b/packages/zowe-explorer/i18n/sample/src/Profiles.i18n.json index b48fbc4ab9..520e59516f 100644 --- a/packages/zowe-explorer/i18n/sample/src/Profiles.i18n.json +++ b/packages/zowe-explorer/i18n/sample/src/Profiles.i18n.json @@ -1,5 +1,6 @@ { "profiles.operation.cancelled": "Operation Cancelled", + "profiles.manualEditMsg": "Edit to the config file will need to be done manually.", "checkCurrentProfile.tokenAuthError.msg": "Token auth error", "checkCurrentProfile.tokenAuthError.additionalDetails": "Profile was found using token auth, please log in to continue.", "profiles.createNewConnection": "$(plus) Create a new connection to z/OS", diff --git a/packages/zowe-explorer/src/Profiles.ts b/packages/zowe-explorer/src/Profiles.ts index a32d1801af..6b392b9c8c 100644 --- a/packages/zowe-explorer/src/Profiles.ts +++ b/packages/zowe-explorer/src/Profiles.ts @@ -68,6 +68,7 @@ export class Profiles extends ProfilesCache { private jobsSchema: string = globals.SETTINGS_JOBS_HISTORY; private mProfileInfo: zowe.imperative.ProfileInfo; private profilesOpCancelled = localize("profiles.operation.cancelled", "Operation Cancelled"); + private manualEditMsg = localize("profiles.manualEditMsg", "Editing or removal of profiles will need to be done manually."); public constructor(log: zowe.imperative.Logger, cwd?: string) { super(log, cwd); } @@ -443,6 +444,7 @@ export class Profiles extends ProfilesCache { const currentProfile = await this.getProfileFromConfig(profileLoaded.name); const filePath = currentProfile.profLoc.osLoc[0]; await this.openConfigFile(filePath); + Gui.showMessage(this.manualEditMsg); return; } const editSession = this.loadNamedProfile(profileLoaded.name, profileLoaded.type).profile; @@ -697,6 +699,7 @@ export class Profiles extends ProfilesCache { await this.openConfigFile(file.path); } } + Gui.showMessage(this.manualEditMsg); break; case "global": for (const file of existingLayers) { @@ -704,12 +707,12 @@ export class Profiles extends ProfilesCache { await this.openConfigFile(file.path); } } + Gui.showMessage(this.manualEditMsg); break; default: Gui.showMessage(this.profilesOpCancelled); - return; + break; } - return; } } From 7ff92239fcfc59b79591c9591ac4f195b673d821 Mon Sep 17 00:00:00 2001 From: Billie Simmons <49491949+JillieBeanSim@users.noreply.github.com> Date: Fri, 22 Sep 2023 21:12:01 -0400 Subject: [PATCH 049/189] missed one Signed-off-by: Billie Simmons <49491949+JillieBeanSim@users.noreply.github.com> --- packages/zowe-explorer/src/Profiles.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/zowe-explorer/src/Profiles.ts b/packages/zowe-explorer/src/Profiles.ts index 6b392b9c8c..0100edc162 100644 --- a/packages/zowe-explorer/src/Profiles.ts +++ b/packages/zowe-explorer/src/Profiles.ts @@ -689,6 +689,7 @@ export class Profiles extends ProfilesCache { const existingLayers = await this.getConfigLayers(); if (existingLayers.length === 1) { await this.openConfigFile(existingLayers[0].path); + Gui.showMessage(this.manualEditMsg); } if (existingLayers && existingLayers.length > 1) { const choice = await this.getConfigLocationPrompt("edit"); From b9cd91cdac0431b091134c61d288b1d0efa63c9b Mon Sep 17 00:00:00 2001 From: Billie Simmons <49491949+JillieBeanSim@users.noreply.github.com> Date: Tue, 26 Sep 2023 07:59:11 -0400 Subject: [PATCH 050/189] address feedback Signed-off-by: Billie Simmons <49491949+JillieBeanSim@users.noreply.github.com> --- .../i18n/sample/src/Profiles.i18n.json | 2 +- .../sample/src/utils/ProfileManagement.i18n.json | 2 +- .../zowe-explorer/src/utils/ProfileManagement.ts | 2 +- packages/zowe-explorer/src/utils/ProfilesUtils.ts | 14 +++++++------- 4 files changed, 10 insertions(+), 10 deletions(-) diff --git a/packages/zowe-explorer/i18n/sample/src/Profiles.i18n.json b/packages/zowe-explorer/i18n/sample/src/Profiles.i18n.json index 520e59516f..b2e9851127 100644 --- a/packages/zowe-explorer/i18n/sample/src/Profiles.i18n.json +++ b/packages/zowe-explorer/i18n/sample/src/Profiles.i18n.json @@ -1,6 +1,6 @@ { "profiles.operation.cancelled": "Operation Cancelled", - "profiles.manualEditMsg": "Edit to the config file will need to be done manually.", + "profiles.manualEditMsg": "Editing or removal of profiles will need to be done manually.", "checkCurrentProfile.tokenAuthError.msg": "Token auth error", "checkCurrentProfile.tokenAuthError.additionalDetails": "Profile was found using token auth, please log in to continue.", "profiles.createNewConnection": "$(plus) Create a new connection to z/OS", diff --git a/packages/zowe-explorer/i18n/sample/src/utils/ProfileManagement.i18n.json b/packages/zowe-explorer/i18n/sample/src/utils/ProfileManagement.i18n.json index 1afb08edfe..0b0107edb9 100644 --- a/packages/zowe-explorer/i18n/sample/src/utils/ProfileManagement.i18n.json +++ b/packages/zowe-explorer/i18n/sample/src/utils/ProfileManagement.i18n.json @@ -8,7 +8,7 @@ "updateBasicAuthQpItem.updateCredentials.qpLabel": "$(refresh) Update Credentials", "updateBasicAuthQpItem.updateCredentials.qpDetail": "Update stored username and password", "deleteProfileQpItem.delete.qpLabel": "$(trash) Delete Profile", - "editProfileQpItem.editProfile.qpLabel": "$(pencil) Edit profile", + "editProfileQpItem.editProfile.qpLabel": "$(pencil) Edit Profile", "editProfileQpItem.editProfile.qpDetail": "Update profile connection information", "loginQpItem.login.qpLabel": "$(arrow-right) Log in to authentication service", "loginQpItem.login.qpDetail": "Log in to obtain a new token value", diff --git a/packages/zowe-explorer/src/utils/ProfileManagement.ts b/packages/zowe-explorer/src/utils/ProfileManagement.ts index 7369b59ab2..8a72bb1430 100644 --- a/packages/zowe-explorer/src/utils/ProfileManagement.ts +++ b/packages/zowe-explorer/src/utils/ProfileManagement.ts @@ -74,7 +74,7 @@ export class ProfileManagement { }; public static editProfileQpItems: Record = { [this.AuthQpLabels.edit]: { - label: localize("editProfileQpItem.editProfile.qpLabel", "$(pencil) Edit profile"), + label: localize("editProfileQpItem.editProfile.qpLabel", "$(pencil) Edit Profile"), description: localize("editProfileQpItem.editProfile.qpDetail", "Update profile connection information"), }, }; diff --git a/packages/zowe-explorer/src/utils/ProfilesUtils.ts b/packages/zowe-explorer/src/utils/ProfilesUtils.ts index 2a8dd2979a..46a00b10c7 100644 --- a/packages/zowe-explorer/src/utils/ProfilesUtils.ts +++ b/packages/zowe-explorer/src/utils/ProfilesUtils.ts @@ -313,10 +313,7 @@ export class ProfilesUtils { * @returns {Promise} a boolean representing whether basic auth is being used or not */ public static isProfileUsingBasicAuth(profile: imperative.IProfileLoaded): boolean { - if (profile.profile.user && profile.profile.password) { - return true; - } - return false; + return (profile.profile.user && profile.profile.password) as boolean; } /** @@ -325,11 +322,14 @@ export class ProfilesUtils { * @returns {Promise} a boolean representing whether token based auth is being used or not */ public static async isUsingTokenAuth(profileName: string): Promise { - const baseProfile = Profiles.getInstance().getDefaultProfile("base"); const secureProfileProps = await Profiles.getInstance().getSecurePropsForProfile(profileName); - const secureBaseProfileProps = await Profiles.getInstance().getSecurePropsForProfile(baseProfile?.name); const profileUsesBasicAuth = secureProfileProps.includes("user") && secureProfileProps.includes("password"); - return (secureProfileProps.includes("tokenValue") || secureBaseProfileProps.includes("tokenValue")) && !profileUsesBasicAuth; + if (secureProfileProps.includes("tokenValue")) { + return secureProfileProps.includes("tokenValue") && !profileUsesBasicAuth; + } + const baseProfile = Profiles.getInstance().getDefaultProfile("base"); + const secureBaseProfileProps = await Profiles.getInstance().getSecurePropsForProfile(baseProfile?.name); + return secureBaseProfileProps.includes("tokenValue") && !profileUsesBasicAuth; } public static async promptCredentials(node: IZoweTreeNode): Promise { From 2c5eba7d2b35d856255e73c7b47a811cae64d811 Mon Sep 17 00:00:00 2001 From: Billie Simmons <49491949+JillieBeanSim@users.noreply.github.com> Date: Tue, 26 Sep 2023 08:34:23 -0400 Subject: [PATCH 051/189] fix unit tests Signed-off-by: Billie Simmons <49491949+JillieBeanSim@users.noreply.github.com> --- .../__mocks__/mockCreators/shared.ts | 16 ++++++++++++++++ .../__unit__/Profiles.extended.unit.test.ts | 1 + .../utils/ProfileManagement.unit.test.ts | 2 +- .../zowe-explorer/src/utils/ProfilesUtils.ts | 3 ++- 4 files changed, 20 insertions(+), 2 deletions(-) diff --git a/packages/zowe-explorer/__mocks__/mockCreators/shared.ts b/packages/zowe-explorer/__mocks__/mockCreators/shared.ts index 82b4039698..63bb7cd047 100644 --- a/packages/zowe-explorer/__mocks__/mockCreators/shared.ts +++ b/packages/zowe-explorer/__mocks__/mockCreators/shared.ts @@ -236,6 +236,22 @@ export function createTokenAuthIProfile(): imperative.IProfileLoaded { }; } +export function createNoAuthIProfile(): imperative.IProfileLoaded { + return { + name: "sestest", + profile: { + type: "zosmf", + host: null, + port: 1443, + rejectUnauthorized: false, + name: "testName", + }, + type: "zosmf", + message: "", + failNotFound: false, + }; +} + export function createAltTypeIProfile(): imperative.IProfileLoaded { return { name: "altTypeProfile", diff --git a/packages/zowe-explorer/__tests__/__unit__/Profiles.extended.unit.test.ts b/packages/zowe-explorer/__tests__/__unit__/Profiles.extended.unit.test.ts index ebe3b57fe3..6d41665a89 100644 --- a/packages/zowe-explorer/__tests__/__unit__/Profiles.extended.unit.test.ts +++ b/packages/zowe-explorer/__tests__/__unit__/Profiles.extended.unit.test.ts @@ -1569,6 +1569,7 @@ describe("Profiles Unit Tests - function ssoLogin", () => { ], configurable: true, }); + Object.defineProperty(utils.ProfilesUtils, "isProfileUsingBasicAuth", { value: jest.fn(), configurable: true }); jest.spyOn(Gui, "showMessage").mockImplementation(); }); it("should perform an SSOLogin successfully while fetching the base profile", async () => { diff --git a/packages/zowe-explorer/__tests__/__unit__/utils/ProfileManagement.unit.test.ts b/packages/zowe-explorer/__tests__/__unit__/utils/ProfileManagement.unit.test.ts index 616f590df1..44d605e0d4 100644 --- a/packages/zowe-explorer/__tests__/__unit__/utils/ProfileManagement.unit.test.ts +++ b/packages/zowe-explorer/__tests__/__unit__/utils/ProfileManagement.unit.test.ts @@ -33,7 +33,7 @@ describe("ProfileManagement unit tests", () => { mockSession: sharedMock.createISession(), mockBasicAuthProfile: sharedMock.createValidIProfile(), mockTokenAuthProfile: sharedMock.createTokenAuthIProfile(), - mockNoAuthProfile: sharedMock.createInvalidIProfile(), + mockNoAuthProfile: sharedMock.createNoAuthIProfile(), opCancelledSpy: jest.spyOn(Gui, "infoMessage"), mockDsSessionNode: ZoweDatasetNode, mockResolveQp: jest.fn(), diff --git a/packages/zowe-explorer/src/utils/ProfilesUtils.ts b/packages/zowe-explorer/src/utils/ProfilesUtils.ts index 46a00b10c7..ec2b9d97e1 100644 --- a/packages/zowe-explorer/src/utils/ProfilesUtils.ts +++ b/packages/zowe-explorer/src/utils/ProfilesUtils.ts @@ -313,7 +313,8 @@ export class ProfilesUtils { * @returns {Promise} a boolean representing whether basic auth is being used or not */ public static isProfileUsingBasicAuth(profile: imperative.IProfileLoaded): boolean { - return (profile.profile.user && profile.profile.password) as boolean; + const prof = profile.profile; + return "user" in prof && "password" in prof; } /** From 6006d3c7d694a9b3dad19501daa2153a066efa44 Mon Sep 17 00:00:00 2001 From: Billie Simmons <49491949+JillieBeanSim@users.noreply.github.com> Date: Wed, 27 Sep 2023 15:52:16 -0400 Subject: [PATCH 052/189] address feedback Signed-off-by: Billie Simmons <49491949+JillieBeanSim@users.noreply.github.com> --- .../zowe-explorer/i18n/sample/src/Profiles.i18n.json | 2 +- packages/zowe-explorer/src/Profiles.ts | 5 ++++- .../zowe-explorer/src/utils/ProfileManagement.ts | 12 +++++++++--- packages/zowe-explorer/src/utils/ProfilesUtils.ts | 1 + 4 files changed, 15 insertions(+), 5 deletions(-) diff --git a/packages/zowe-explorer/i18n/sample/src/Profiles.i18n.json b/packages/zowe-explorer/i18n/sample/src/Profiles.i18n.json index b2e9851127..57a7772513 100644 --- a/packages/zowe-explorer/i18n/sample/src/Profiles.i18n.json +++ b/packages/zowe-explorer/i18n/sample/src/Profiles.i18n.json @@ -1,6 +1,6 @@ { "profiles.operation.cancelled": "Operation Cancelled", - "profiles.manualEditMsg": "Editing or removal of profiles will need to be done manually.", + "profiles.manualEditMsg": "The Team configuration file has been opened in the editor. Editing or removal of profiles will need to be done manually.", "checkCurrentProfile.tokenAuthError.msg": "Token auth error", "checkCurrentProfile.tokenAuthError.additionalDetails": "Profile was found using token auth, please log in to continue.", "profiles.createNewConnection": "$(plus) Create a new connection to z/OS", diff --git a/packages/zowe-explorer/src/Profiles.ts b/packages/zowe-explorer/src/Profiles.ts index 0100edc162..3c69c244e9 100644 --- a/packages/zowe-explorer/src/Profiles.ts +++ b/packages/zowe-explorer/src/Profiles.ts @@ -68,7 +68,10 @@ export class Profiles extends ProfilesCache { private jobsSchema: string = globals.SETTINGS_JOBS_HISTORY; private mProfileInfo: zowe.imperative.ProfileInfo; private profilesOpCancelled = localize("profiles.operation.cancelled", "Operation Cancelled"); - private manualEditMsg = localize("profiles.manualEditMsg", "Editing or removal of profiles will need to be done manually."); + private manualEditMsg = localize( + "profiles.manualEditMsg", + "The Team configuration file has been opened in the editor. Editing or removal of profiles will need to be done manually." + ); public constructor(log: zowe.imperative.Logger, cwd?: string) { super(log, cwd); } diff --git a/packages/zowe-explorer/src/utils/ProfileManagement.ts b/packages/zowe-explorer/src/utils/ProfileManagement.ts index 8a72bb1430..874244e4a1 100644 --- a/packages/zowe-explorer/src/utils/ProfileManagement.ts +++ b/packages/zowe-explorer/src/utils/ProfileManagement.ts @@ -15,6 +15,7 @@ import { ZoweLogger } from "./LoggerUtils"; import { ProfilesUtils } from "./ProfilesUtils"; import * as nls from "vscode-nls"; import { Profiles } from "../Profiles"; +import { ZoweExplorerApiRegister } from "../ZoweExplorerApiRegister"; // Set up localization nls.config({ @@ -106,7 +107,7 @@ export class ProfileManagement { break; } default: { - quickPickOptions = this.chooseAuthQp(); + quickPickOptions = this.chooseAuthQp(profile); qp.placeholder = placeholders.chooseAuth; break; } @@ -175,9 +176,14 @@ export class ProfileManagement { } return this.addFinalQpOptions(quickPickOptions); } - private static chooseAuthQp(): vscode.QuickPickItem[] { + private static chooseAuthQp(profile: imperative.IProfileLoaded): vscode.QuickPickItem[] { const quickPickOptions: vscode.QuickPickItem[] = Object.values(this.basicAuthAddQpItems); - quickPickOptions.push(this.tokenAuthLoginQpItem[this.AuthQpLabels.login]); + try { + ZoweExplorerApiRegister.getInstance().getCommonApi(profile).getTokenTypeName(); + quickPickOptions.push(this.tokenAuthLoginQpItem[this.AuthQpLabels.login]); + } catch { + ZoweLogger.debug(`Profile ${profile.name} doesn't support token authentication.`); + } return this.addFinalQpOptions(quickPickOptions); } private static addFinalQpOptions(quickPickOptions: vscode.QuickPickItem[]): vscode.QuickPickItem[] { diff --git a/packages/zowe-explorer/src/utils/ProfilesUtils.ts b/packages/zowe-explorer/src/utils/ProfilesUtils.ts index ec2b9d97e1..67c55bacfd 100644 --- a/packages/zowe-explorer/src/utils/ProfilesUtils.ts +++ b/packages/zowe-explorer/src/utils/ProfilesUtils.ts @@ -23,6 +23,7 @@ import { imperative, getImperativeConfig } from "@zowe/cli"; import { ZoweExplorerExtender } from "../ZoweExplorerExtender"; import { ZoweLogger } from "./LoggerUtils"; import { SettingsConfig } from "./SettingsConfig"; +import { ZoweExplorerApiRegister } from "../ZoweExplorerApiRegister"; // Set up localization nls.config({ From 5b57f4c246d0b4b485a43e5e85c8680b5aeb5efb Mon Sep 17 00:00:00 2001 From: Billie Simmons <49491949+JillieBeanSim@users.noreply.github.com> Date: Wed, 27 Sep 2023 15:54:16 -0400 Subject: [PATCH 053/189] update log string Signed-off-by: Billie Simmons <49491949+JillieBeanSim@users.noreply.github.com> --- packages/zowe-explorer/src/utils/ProfileManagement.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/zowe-explorer/src/utils/ProfileManagement.ts b/packages/zowe-explorer/src/utils/ProfileManagement.ts index 874244e4a1..b72838721e 100644 --- a/packages/zowe-explorer/src/utils/ProfileManagement.ts +++ b/packages/zowe-explorer/src/utils/ProfileManagement.ts @@ -182,7 +182,7 @@ export class ProfileManagement { ZoweExplorerApiRegister.getInstance().getCommonApi(profile).getTokenTypeName(); quickPickOptions.push(this.tokenAuthLoginQpItem[this.AuthQpLabels.login]); } catch { - ZoweLogger.debug(`Profile ${profile.name} doesn't support token authentication.`); + ZoweLogger.debug(`Profile ${profile.name} doesn't support token authentication, will not provide option.`); } return this.addFinalQpOptions(quickPickOptions); } From c5dd06ca4e9501f7cb347489241db1fd213730ab Mon Sep 17 00:00:00 2001 From: Billie Simmons <49491949+JillieBeanSim@users.noreply.github.com> Date: Wed, 27 Sep 2023 15:55:38 -0400 Subject: [PATCH 054/189] address code smell Signed-off-by: Billie Simmons <49491949+JillieBeanSim@users.noreply.github.com> --- packages/zowe-explorer/src/utils/ProfilesUtils.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/zowe-explorer/src/utils/ProfilesUtils.ts b/packages/zowe-explorer/src/utils/ProfilesUtils.ts index 67c55bacfd..ec2b9d97e1 100644 --- a/packages/zowe-explorer/src/utils/ProfilesUtils.ts +++ b/packages/zowe-explorer/src/utils/ProfilesUtils.ts @@ -23,7 +23,6 @@ import { imperative, getImperativeConfig } from "@zowe/cli"; import { ZoweExplorerExtender } from "../ZoweExplorerExtender"; import { ZoweLogger } from "./LoggerUtils"; import { SettingsConfig } from "./SettingsConfig"; -import { ZoweExplorerApiRegister } from "../ZoweExplorerApiRegister"; // Set up localization nls.config({ From c9c7ca30751dc09a032b19d2ce46e7cea3a81acd Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 27 Sep 2023 21:16:56 +0000 Subject: [PATCH 055/189] chore(deps): Bump get-func-name from 2.0.0 to 2.0.2 Bumps [get-func-name](https://github.com/chaijs/get-func-name) from 2.0.0 to 2.0.2. - [Release notes](https://github.com/chaijs/get-func-name/releases) - [Commits](https://github.com/chaijs/get-func-name/commits/v2.0.2) --- updated-dependencies: - dependency-name: get-func-name dependency-type: indirect ... Signed-off-by: dependabot[bot] --- yarn.lock | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/yarn.lock b/yarn.lock index e560eef631..c01f78aaa9 100644 --- a/yarn.lock +++ b/yarn.lock @@ -5941,9 +5941,9 @@ get-caller-file@^2.0.1, get-caller-file@^2.0.5: integrity sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg== get-func-name@^2.0.0: - version "2.0.0" - resolved "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.0.tgz#ead774abee72e20409433a066366023dd6887a41" - integrity sha1-6td0q+5y4gQJQzoGY2YCPdaIekE= + version "2.0.2" + resolved "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.2.tgz#0d7cf20cd13fda808669ffa88f4ffc7a3943fc41" + integrity sha512-8vXOvuE167CtIc3OyItco7N/dpRtBbYOsPsXCz7X/PMnlGjYjSGuZJgM1Y7mmew7BKf9BqvLX2tnOVy1BBUsxQ== get-intrinsic@^1.0.2, get-intrinsic@^1.1.1: version "1.1.1" From ef5d5a20e8e1579b89fb3cce05cb96a759745a3a Mon Sep 17 00:00:00 2001 From: Likhitha Nimma Date: Thu, 28 Sep 2023 22:57:57 +0530 Subject: [PATCH 056/189] Handled Duplicates and made changes to CHANGELOG files Signed-off-by: Likhitha Nimma --- packages/zowe-explorer-api/CHANGELOG.md | 3 +-- .../__unit__/profiles/ProfilesCache.unit.test.ts | 13 +++++++------ .../zowe-explorer-api/src/profiles/ProfilesCache.ts | 4 ++-- packages/zowe-explorer/CHANGELOG.md | 2 +- .../__unit__/ZoweExplorerExtender.unit.test.ts | 2 +- packages/zowe-explorer/src/ZoweExplorerExtender.ts | 2 +- 6 files changed, 13 insertions(+), 13 deletions(-) diff --git a/packages/zowe-explorer-api/CHANGELOG.md b/packages/zowe-explorer-api/CHANGELOG.md index de60eaec37..c8fc4db2b2 100644 --- a/packages/zowe-explorer-api/CHANGELOG.md +++ b/packages/zowe-explorer-api/CHANGELOG.md @@ -7,11 +7,10 @@ All notable changes to the "zowe-explorer-api" extension will be documented in t ### New features and enhancements - Added optional `getTag` function to `ZoweExplorerAPI.IUss` for getting the tag of a file on USS. +- Added new API {ZE Extender MetaData} to allow extenders to have the metadata of registered extenders to aid in team configuration file creation from a view that isn't Zowe Explorer's. [#2394](https://github.com/zowe/vscode-extension-for-zowe/issues/2394) ### Bug fixes -- Fixed the issue of getting the meta data of profile types for creating the config files by adding the setters and getters in the zowe-explorer-api. [#2394](https://github.com/zowe/vscode-extension-for-zowe/issues/2394) - ## `2.11.0` ### New features and enhancements diff --git a/packages/zowe-explorer-api/__tests__/__unit__/profiles/ProfilesCache.unit.test.ts b/packages/zowe-explorer-api/__tests__/__unit__/profiles/ProfilesCache.unit.test.ts index a1fe151594..ac93f74cd9 100644 --- a/packages/zowe-explorer-api/__tests__/__unit__/profiles/ProfilesCache.unit.test.ts +++ b/packages/zowe-explorer-api/__tests__/__unit__/profiles/ProfilesCache.unit.test.ts @@ -87,11 +87,11 @@ const baseProfileWithToken = { }; const profilemetadata: zowe.imperative.ICommandProfileTypeConfiguration[] = [ { - type: "rse", + type: "acme", schema: { type: "object", - title: "IBM RSE API Zowe Profile", - description: "A profile to issue commands to z/OS system", + title: "acme profile1", + description: "A profile to execute commands", properties: {}, }, }, @@ -164,10 +164,11 @@ describe("ProfilesCache", () => { expect(Object.keys(keyring).length).toBe(5); }); - it("setConfigArray should set the profileTypeConfigurations array", () => { + it("addToConfigArray should set the profileTypeConfigurations array", () => { const profCache = new ProfilesCache(fakeLogger as unknown as zowe.imperative.Logger); - profCache.setConfigArray(profilemetadata); - expect(profCache.profileTypeConfigurations).toEqual(profilemetadata); + profilemetadata.push(profilemetadata[0]); + profCache.addToConfigArray(profilemetadata); + expect(profCache.profileTypeConfigurations).toEqual(profilemetadata.filter((a, index) => index == 0)); }); it("getConfigArray should return the data of profileTypeConfigurations Array", () => { diff --git a/packages/zowe-explorer-api/src/profiles/ProfilesCache.ts b/packages/zowe-explorer-api/src/profiles/ProfilesCache.ts index daa0e67cbc..c2d8d7f061 100644 --- a/packages/zowe-explorer-api/src/profiles/ProfilesCache.ts +++ b/packages/zowe-explorer-api/src/profiles/ProfilesCache.ts @@ -84,9 +84,9 @@ export class ProfilesCache { return require("@zowe/secrets-for-zowe-sdk").keyring; } - public setConfigArray(extendermetadata: zowe.imperative.ICommandProfileTypeConfiguration[]): void { + public addToConfigArray(extendermetadata: zowe.imperative.ICommandProfileTypeConfiguration[]): void { extendermetadata?.forEach((item) => { - this.profileTypeConfigurations.push(item); + if (!this.profileTypeConfigurations.some((ele) => ele.type === item.type)) this.profileTypeConfigurations.push(item); }); } diff --git a/packages/zowe-explorer/CHANGELOG.md b/packages/zowe-explorer/CHANGELOG.md index 1ca5e98c24..e00358e7bd 100644 --- a/packages/zowe-explorer/CHANGELOG.md +++ b/packages/zowe-explorer/CHANGELOG.md @@ -8,11 +8,11 @@ All notable changes to the "vscode-extension-for-zowe" extension will be documen - Added "Sort Jobs" feature for job nodes in Jobs tree view. [#2257](https://github.com/zowe/vscode-extension-for-zowe/issues/2251) - Added new edit feature on `Edit Attributes` view for changing file tags on USS [#2113](https://github.com/zowe/vscode-extension-for-zowe/issues/2113) +- Added new API {ZE Extender MetaData} to allow extenders to have the metadata of registered extenders to aid in team configuration file creation from a view that isn't Zowe Explorer's. [#2394](https://github.com/zowe/vscode-extension-for-zowe/issues/2394) ### Bug fixes - Fixed submitting local JCL using command pallet option `Zowe Explorer: Submit JCL` by adding a check for chosen profile returned to continue the action. [#1625](https://github.com/zowe/vscode-extension-for-zowe/issues/1625) -- Fixed the issue of getting the meta data of profile types for creating the config files by adding the setters and getters in the zowe-explorer-api. [#2394](https://github.com/zowe/vscode-extension-for-zowe/issues/2394) ## `2.11.0` diff --git a/packages/zowe-explorer/__tests__/__unit__/ZoweExplorerExtender.unit.test.ts b/packages/zowe-explorer/__tests__/__unit__/ZoweExplorerExtender.unit.test.ts index 30b4716f93..a3bea5845a 100644 --- a/packages/zowe-explorer/__tests__/__unit__/ZoweExplorerExtender.unit.test.ts +++ b/packages/zowe-explorer/__tests__/__unit__/ZoweExplorerExtender.unit.test.ts @@ -78,7 +78,7 @@ describe("ZoweExplorerExtender unit tests", () => { value: jest.fn(), configurable: true, }); - Object.defineProperty(Profiles.getInstance(), "setConfigArray", { + Object.defineProperty(Profiles.getInstance(), "addToConfigArray", { value: jest.fn(), configurable: true, }); diff --git a/packages/zowe-explorer/src/ZoweExplorerExtender.ts b/packages/zowe-explorer/src/ZoweExplorerExtender.ts index 924596421b..dd16135445 100644 --- a/packages/zowe-explorer/src/ZoweExplorerExtender.ts +++ b/packages/zowe-explorer/src/ZoweExplorerExtender.ts @@ -191,7 +191,7 @@ export class ZoweExplorerExtender implements ZoweExplorerApi.IApiExplorerExtende }); } } - Profiles.getInstance().setConfigArray(profileTypeConfigurations); + Profiles.getInstance().addToConfigArray(profileTypeConfigurations); // sequentially reload the internal profiles cache to satisfy all the newly added profile types await ZoweExplorerExtender.refreshProfilesQueue.add(async (): Promise => { From fdd069cc27ec524331c77b6d1cf8d40cf30ceabe Mon Sep 17 00:00:00 2001 From: Rudy Flores <68666202+rudyflores@users.noreply.github.com> Date: Thu, 28 Sep 2023 16:12:03 -0400 Subject: [PATCH 057/189] refactor of webview code Signed-off-by: Rudy Flores <68666202+rudyflores@users.noreply.github.com> --- package.json | 2 +- .../src/vscode/ui/WebView.ts | 13 +- packages/zowe-explorer/package.json | 4 +- .../webviews}/package.json | 18 +- .../webviews/src/edit-attributes}/App.tsx | 13 - .../webviews/src}/edit-attributes/index.html | 2 +- .../webviews/src/edit-attributes}/index.tsx | 0 .../webviews/src/edit-attributes}/types.ts | 12 +- .../webviews}/tsconfig.json | 0 .../webviews}/tsconfig.node.json | 0 .../zowe-explorer/src/webviews/vite.config.ts | 58 ++ .../webviews}/yarn.lock | 636 +++++++++--------- .../webviews/edit-attributes/vite.config.ts | 16 - yarn.lock | 297 +++++--- 14 files changed, 603 insertions(+), 468 deletions(-) rename packages/zowe-explorer/{webviews/edit-attributes => src/webviews}/package.json (57%) rename packages/zowe-explorer/{webviews/edit-attributes/src => src/webviews/src/edit-attributes}/App.tsx (94%) rename packages/zowe-explorer/{webviews => src/webviews/src}/edit-attributes/index.html (81%) rename packages/zowe-explorer/{webviews/edit-attributes/src => src/webviews/src/edit-attributes}/index.tsx (100%) rename packages/zowe-explorer/{webviews/edit-attributes/src => src/webviews/src/edit-attributes}/types.ts (60%) rename packages/zowe-explorer/{webviews/edit-attributes => src/webviews}/tsconfig.json (100%) rename packages/zowe-explorer/{webviews/edit-attributes => src/webviews}/tsconfig.node.json (100%) create mode 100644 packages/zowe-explorer/src/webviews/vite.config.ts rename packages/zowe-explorer/{webviews/edit-attributes => src/webviews}/yarn.lock (59%) delete mode 100644 packages/zowe-explorer/webviews/edit-attributes/vite.config.ts diff --git a/package.json b/package.json index c827660be1..db383ebdf1 100644 --- a/package.json +++ b/package.json @@ -10,7 +10,7 @@ "private": true, "workspaces": [ "packages/*", - "packages/zowe-explorer/webviews/*" + "packages/zowe-explorer/src/webviews" ], "engines": { "vscode": "^1.53.2" diff --git a/packages/zowe-explorer-api/src/vscode/ui/WebView.ts b/packages/zowe-explorer-api/src/vscode/ui/WebView.ts index 1f88b2c994..a37c95f52d 100644 --- a/packages/zowe-explorer-api/src/vscode/ui/WebView.ts +++ b/packages/zowe-explorer-api/src/vscode/ui/WebView.ts @@ -39,11 +39,16 @@ export class WebView { * The webview entrypoint must be located at /dist/assets/index.js. * * @param title The title for the new webview - * @param dirName The directory name (relative to the "webviews" folder in the extension root) with a valid entrypoint (see above). + * @param webviewName The directory name (relative to the "webviews" folder in the extension root) with a valid entrypoint (see above). * @param context The VSCode extension context * @param onDidReceiveMessage Event callback: called when messages are received from the webview */ - public constructor(title: string, dirName: string, context: ExtensionContext, onDidReceiveMessage?: (message: object) => void | Promise) { + public constructor( + title: string, + webviewName: string, + context: ExtensionContext, + onDidReceiveMessage?: (message: object) => void | Promise + ) { this.disposables = []; // Generate random nonce for loading the bundled script @@ -52,8 +57,8 @@ export class WebView { // Build URIs for the webview directory and get the paths as VScode resources this.uris.disk = { - build: Uri.file(joinPath(context.extensionPath, "webviews", dirName)), - script: Uri.file(joinPath(context.extensionPath, "webviews", dirName, "dist", "assets", "index.js")), + build: Uri.file(joinPath(context.extensionPath, "src", "webviews")), + script: Uri.file(joinPath(context.extensionPath, "src", "webviews", "dist", webviewName, `${webviewName}.js`)), }; this.panel = window.createWebviewPanel("ZEAPIWebview", this.title, ViewColumn.Beside, { diff --git a/packages/zowe-explorer/package.json b/packages/zowe-explorer/package.json index 527726260b..7405bf79f7 100644 --- a/packages/zowe-explorer/package.json +++ b/packages/zowe-explorer/package.json @@ -1963,7 +1963,9 @@ "updateStrings": "node ../../scripts/stringUpdateScript.js && prettier --write --loglevel warn ./i18n package.nls*", "package": "vsce package --allow-star-activation --yarn && node ../../scripts/mv-pack.js vscode-extension-for-zowe vsix", "license": "node ../../scripts/updateLicenses.js", - "watch": "gulp build && webpack --mode development --watch --info-verbosity verbose", + "watch": "concurrently 'yarn run watch:webviews' 'yarn run watch:zowe-explorer'", + "watch:zowe-explorer": "gulp build && webpack --mode development --watch --info-verbosity verbose", + "watch:webviews": "yarn workspace webviews dev", "compile": "tsc -b", "compile-web": "webpack --target webworker --entry ./src/web/extension.ts --output-path ./out/src/web", "markdown": "markdownlint CHANGELOG.md README.md", diff --git a/packages/zowe-explorer/webviews/edit-attributes/package.json b/packages/zowe-explorer/src/webviews/package.json similarity index 57% rename from packages/zowe-explorer/webviews/edit-attributes/package.json rename to packages/zowe-explorer/src/webviews/package.json index f26f971a75..7e625a963a 100644 --- a/packages/zowe-explorer/webviews/edit-attributes/package.json +++ b/packages/zowe-explorer/src/webviews/package.json @@ -1,21 +1,22 @@ { - "name": "edit-attributes", + "name": "webviews", "private": true, "type": "module", "version": "2.12.0-SNAPSHOT", "main": "index.js", "license": "EPL-2.0", "scripts": { - "dev": "vite", + "dev": "vite build --watch --config ./vite.config.js", "build": "tsc && vite build", "preview": "vite preview", "fresh-clone": "yarn clean && rimraf node_modules", "clean": "gulp clean", - "package": "echo \"edit-attributes: nothing to package.\"", - "test": "echo \"edit-attributes: nothing to test\"", - "lint": "echo \"edit-attributes: nothing to lint.\"", - "lint:html": "echo \"edit-attributes: nothing to lint.\"", - "pretty": "echo \"edit-attributes: nothing to pretty.\"" + "package": "echo \"webviews: nothing to package.\"", + "test": "echo \"webviews: nothing to test\"", + "lint": "echo \"webviews: nothing to lint.\"", + "lint:html": "echo \"webviews: nothing to lint.\"", + "pretty": "echo \"webviews: nothing to pretty.\"", + "madge": "echo \"webviews: nothing to madge.\"" }, "dependencies": { "@types/vscode-webview": "^1.57.1", @@ -28,6 +29,7 @@ "@types/lodash.isequal": "^4.5.6", "@vscode/codicons": "^0.0.33", "typescript": "^4.5.3", - "vite": "^4.4.8" + "vite": "^4.4.9", + "vite-plugin-checker": "^0.6.2" } } diff --git a/packages/zowe-explorer/webviews/edit-attributes/src/App.tsx b/packages/zowe-explorer/src/webviews/src/edit-attributes/App.tsx similarity index 94% rename from packages/zowe-explorer/webviews/edit-attributes/src/App.tsx rename to packages/zowe-explorer/src/webviews/src/edit-attributes/App.tsx index 0d44c55652..b15dcfd43e 100644 --- a/packages/zowe-explorer/webviews/edit-attributes/src/App.tsx +++ b/packages/zowe-explorer/src/webviews/src/edit-attributes/App.tsx @@ -15,7 +15,6 @@ import isEqual from "lodash.isequal"; const vscodeApi = acquireVsCodeApi(); export function App() { - const notSupported = "NOT SUPPORTED"; const [readonly, setReadonly] = useState(false); const [allowUpdate, setAllowUpdate] = useState(false); const [attributes, setAttributes] = useState>({ @@ -112,7 +111,6 @@ export function App() { }; return all; }, {}), - tag: attributes.tag ?? notSupported, }; setAttributes({ @@ -157,17 +155,6 @@ export function App() {
{attributes.current.name}
- {attributes.initial?.directory ?? false ? null : ( -
- updateFileAttributes("tag", e.target.value)} - > - Tag - -
- )}
diff --git a/packages/zowe-explorer/webviews/edit-attributes/index.html b/packages/zowe-explorer/src/webviews/src/edit-attributes/index.html similarity index 81% rename from packages/zowe-explorer/webviews/edit-attributes/index.html rename to packages/zowe-explorer/src/webviews/src/edit-attributes/index.html index 3a8c5b718b..5789513d71 100644 --- a/packages/zowe-explorer/webviews/edit-attributes/index.html +++ b/packages/zowe-explorer/src/webviews/src/edit-attributes/index.html @@ -7,6 +7,6 @@
- + diff --git a/packages/zowe-explorer/webviews/edit-attributes/src/index.tsx b/packages/zowe-explorer/src/webviews/src/edit-attributes/index.tsx similarity index 100% rename from packages/zowe-explorer/webviews/edit-attributes/src/index.tsx rename to packages/zowe-explorer/src/webviews/src/edit-attributes/index.tsx diff --git a/packages/zowe-explorer/webviews/edit-attributes/src/types.ts b/packages/zowe-explorer/src/webviews/src/edit-attributes/types.ts similarity index 60% rename from packages/zowe-explorer/webviews/edit-attributes/src/types.ts rename to packages/zowe-explorer/src/webviews/src/edit-attributes/types.ts index 72efca076a..baed9f91a3 100644 --- a/packages/zowe-explorer/webviews/edit-attributes/src/types.ts +++ b/packages/zowe-explorer/src/webviews/src/edit-attributes/types.ts @@ -1,3 +1,14 @@ +/** + * This program and the accompanying materials are made available under the terms of the + * Eclipse Public License v2.0 which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-v20.html + * + * SPDX-License-Identifier: EPL-2.0 + * + * Copyright Contributors to the Zowe Project. + * + */ + export type PermissionSet = { read: boolean; write: boolean; @@ -15,5 +26,4 @@ export type FileAttributes = { directory: boolean; group: string; perms: FilePermissions; - tag?: string; }; diff --git a/packages/zowe-explorer/webviews/edit-attributes/tsconfig.json b/packages/zowe-explorer/src/webviews/tsconfig.json similarity index 100% rename from packages/zowe-explorer/webviews/edit-attributes/tsconfig.json rename to packages/zowe-explorer/src/webviews/tsconfig.json diff --git a/packages/zowe-explorer/webviews/edit-attributes/tsconfig.node.json b/packages/zowe-explorer/src/webviews/tsconfig.node.json similarity index 100% rename from packages/zowe-explorer/webviews/edit-attributes/tsconfig.node.json rename to packages/zowe-explorer/src/webviews/tsconfig.node.json diff --git a/packages/zowe-explorer/src/webviews/vite.config.ts b/packages/zowe-explorer/src/webviews/vite.config.ts new file mode 100644 index 0000000000..73818301e4 --- /dev/null +++ b/packages/zowe-explorer/src/webviews/vite.config.ts @@ -0,0 +1,58 @@ +/** + * This program and the accompanying materials are made available under the terms of the + * Eclipse Public License v2.0 which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-v20.html + * + * SPDX-License-Identifier: EPL-2.0 + * + * Copyright Contributors to the Zowe Project. + * + */ + +import { defineConfig } from "vite"; +import preact from "@preact/preset-vite"; +import * as path from "path"; +import { readdirSync } from "fs"; +import checker from "vite-plugin-checker"; + +// https://vitejs.dev/config/ + +interface Webviews { + webview?: string; + webviewLocation?: string; +} + +/** + * Get all available webviews under the source specified + * @param source + * @returns Object the object where the key is the webview and the value is the location of the webview + */ +const getAvailableWebviews = (source: string): Webviews => { + const webviews = readdirSync(source, { withFileTypes: true }) + .filter((dirent) => dirent.isDirectory()) + .map((dirent) => dirent.name); + + return webviews.reduce((o, key) => Object.assign(o, { [key]: path.resolve("src", key, "index.html") }), {}); +}; + +export default defineConfig({ + plugins: [ + preact(), + checker({ + typescript: true, + }), + ], + root: path.resolve(__dirname, "src"), + build: { + emptyOutDir: true, + outDir: path.resolve(__dirname, "dist"), + rollupOptions: { + input: getAvailableWebviews(path.resolve(__dirname, "src")) as any, + output: { + entryFileNames: `[name]/[name].js`, + chunkFileNames: `[name]/[name].js`, + assetFileNames: `[name]/[name].[ext]`, + }, + }, + }, +}); diff --git a/packages/zowe-explorer/webviews/edit-attributes/yarn.lock b/packages/zowe-explorer/src/webviews/yarn.lock similarity index 59% rename from packages/zowe-explorer/webviews/edit-attributes/yarn.lock rename to packages/zowe-explorer/src/webviews/yarn.lock index 55eb2b97eb..b36ce58cf0 100644 --- a/packages/zowe-explorer/webviews/edit-attributes/yarn.lock +++ b/packages/zowe-explorer/src/webviews/yarn.lock @@ -10,45 +10,46 @@ "@jridgewell/gen-mapping" "^0.3.0" "@jridgewell/trace-mapping" "^0.3.9" -"@babel/code-frame@^7.22.5": - version "7.22.5" - resolved "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.22.5.tgz#234d98e1551960604f1246e6475891a570ad5658" - integrity sha512-Xmwn266vad+6DAqEB2A6V/CcZVp62BbwVmcOJc2RPuwih1kw02TjQvWVWlcKGbBPd+8/0V5DEkOcizRGYsspYQ== +"@babel/code-frame@^7.22.13": + version "7.22.13" + resolved "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.22.13.tgz#e3c1c099402598483b7a8c46a721d1038803755e" + integrity sha512-XktuhWlJ5g+3TJXc5upd9Ks1HutSArik6jf2eAjYFyIOf4ej3RN+184cZbzDvbPnuTJIUhPKKJE3cIsYTiAT3w== dependencies: - "@babel/highlight" "^7.22.5" + "@babel/highlight" "^7.22.13" + chalk "^2.4.2" "@babel/compat-data@^7.22.9": - version "7.22.9" - resolved "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.22.9.tgz#71cdb00a1ce3a329ce4cbec3a44f9fef35669730" - integrity sha512-5UamI7xkUcJ3i9qVDS+KFDEK8/7oJ55/sJMB1Ge7IEapr7KfdfV/HErR+koZwOfd+SgtFKOKRhRakdg++DcJpQ== + version "7.22.20" + resolved "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.22.20.tgz#8df6e96661209623f1975d66c35ffca66f3306d0" + integrity sha512-BQYjKbpXjoXwFW5jGqiizJQQT/aC7pFm9Ok1OWssonuguICi264lbgMzRp2ZMmRSlfkX6DsWDDcsrctK8Rwfiw== "@babel/core@^7.22.1": - version "7.22.9" - resolved "https://registry.npmjs.org/@babel/core/-/core-7.22.9.tgz#bd96492c68822198f33e8a256061da3cf391f58f" - integrity sha512-G2EgeufBcYw27U4hhoIwFcgc1XU7TlXJ3mv04oOv1WCuo900U/anZSPzEqNjwdjgffkk2Gs0AN0dW1CKVLcG7w== + version "7.23.0" + resolved "https://registry.npmjs.org/@babel/core/-/core-7.23.0.tgz#f8259ae0e52a123eb40f552551e647b506a94d83" + integrity sha512-97z/ju/Jy1rZmDxybphrBuI+jtJjFVoz7Mr9yUQVVVi+DNZE333uFQeMOqcCIy1x3WYBIbWftUSLmbNXNT7qFQ== dependencies: "@ampproject/remapping" "^2.2.0" - "@babel/code-frame" "^7.22.5" - "@babel/generator" "^7.22.9" - "@babel/helper-compilation-targets" "^7.22.9" - "@babel/helper-module-transforms" "^7.22.9" - "@babel/helpers" "^7.22.6" - "@babel/parser" "^7.22.7" - "@babel/template" "^7.22.5" - "@babel/traverse" "^7.22.8" - "@babel/types" "^7.22.5" - convert-source-map "^1.7.0" + "@babel/code-frame" "^7.22.13" + "@babel/generator" "^7.23.0" + "@babel/helper-compilation-targets" "^7.22.15" + "@babel/helper-module-transforms" "^7.23.0" + "@babel/helpers" "^7.23.0" + "@babel/parser" "^7.23.0" + "@babel/template" "^7.22.15" + "@babel/traverse" "^7.23.0" + "@babel/types" "^7.23.0" + convert-source-map "^2.0.0" debug "^4.1.0" gensync "^1.0.0-beta.2" - json5 "^2.2.2" + json5 "^2.2.3" semver "^6.3.1" -"@babel/generator@^7.22.7", "@babel/generator@^7.22.9": - version "7.22.9" - resolved "https://registry.npmjs.org/@babel/generator/-/generator-7.22.9.tgz#572ecfa7a31002fa1de2a9d91621fd895da8493d" - integrity sha512-KtLMbmicyuK2Ak/FTCJVbDnkN1SlT8/kceFTiuDiiRUUSMnHMidxSCdG4ndkTOHHpoomWe/4xkvHkEOncwjYIw== +"@babel/generator@^7.23.0": + version "7.23.0" + resolved "https://registry.npmjs.org/@babel/generator/-/generator-7.23.0.tgz#df5c386e2218be505b34837acbcb874d7a983420" + integrity sha512-lN85QRR+5IbYrMWM6Y4pE/noaQtg4pNiqeNGX60eqOfo6gtEj6uw/JagelB8vVztSd7R6M5n1+PQkDbHbBRU4g== dependencies: - "@babel/types" "^7.22.5" + "@babel/types" "^7.23.0" "@jridgewell/gen-mapping" "^0.3.2" "@jridgewell/trace-mapping" "^0.3.17" jsesc "^2.5.1" @@ -60,29 +61,29 @@ dependencies: "@babel/types" "^7.22.5" -"@babel/helper-compilation-targets@^7.22.9": - version "7.22.9" - resolved "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.22.9.tgz#f9d0a7aaaa7cd32a3f31c9316a69f5a9bcacb892" - integrity sha512-7qYrNM6HjpnPHJbopxmb8hSPoZ0gsX8IvUS32JGVoy+pU9e5N0nLr1VjJoR6kA4d9dmGLxNYOjeB8sUDal2WMw== +"@babel/helper-compilation-targets@^7.22.15": + version "7.22.15" + resolved "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.22.15.tgz#0698fc44551a26cf29f18d4662d5bf545a6cfc52" + integrity sha512-y6EEzULok0Qvz8yyLkCvVX+02ic+By2UdOhylwUOvOn9dvYc9mKICJuuU1n1XBI02YWsNsnrY1kc6DVbjcXbtw== dependencies: "@babel/compat-data" "^7.22.9" - "@babel/helper-validator-option" "^7.22.5" + "@babel/helper-validator-option" "^7.22.15" browserslist "^4.21.9" lru-cache "^5.1.1" semver "^6.3.1" -"@babel/helper-environment-visitor@^7.22.5": - version "7.22.5" - resolved "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.5.tgz#f06dd41b7c1f44e1f8da6c4055b41ab3a09a7e98" - integrity sha512-XGmhECfVA/5sAt+H+xpSg0mfrHq6FzNr9Oxh7PSEBBRUb/mL7Kz3NICXb194rCqAEdxkhPT1a88teizAFyvk8Q== +"@babel/helper-environment-visitor@^7.22.20": + version "7.22.20" + resolved "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.20.tgz#96159db61d34a29dba454c959f5ae4a649ba9167" + integrity sha512-zfedSIzFhat/gFhWfHtgWvlec0nqB9YEIVrpuwjruLlXfUSnA8cJB0miHKwqDnQ7d32aKo2xt88/xZptwxbfhA== -"@babel/helper-function-name@^7.22.5": - version "7.22.5" - resolved "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.22.5.tgz#ede300828905bb15e582c037162f99d5183af1be" - integrity sha512-wtHSq6jMRE3uF2otvfuD3DIvVhOsSNshQl0Qrd7qC9oQJzHvOL4qQXlQn2916+CXGywIjpGuIkoyZRRxHPiNQQ== +"@babel/helper-function-name@^7.23.0": + version "7.23.0" + resolved "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.23.0.tgz#1f9a3cdbd5b2698a670c30d2735f9af95ed52759" + integrity sha512-OErEqsrxjZTJciZ4Oo+eoZqeW9UIiOcuYKRJA4ZAgV9myA+pOXhhmpfNCKjEH/auVfEYVFJ6y1Tc4r0eIApqiw== dependencies: - "@babel/template" "^7.22.5" - "@babel/types" "^7.22.5" + "@babel/template" "^7.22.15" + "@babel/types" "^7.23.0" "@babel/helper-hoist-variables@^7.22.5": version "7.22.5" @@ -91,23 +92,23 @@ dependencies: "@babel/types" "^7.22.5" -"@babel/helper-module-imports@^7.22.5": - version "7.22.5" - resolved "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.22.5.tgz#1a8f4c9f4027d23f520bd76b364d44434a72660c" - integrity sha512-8Dl6+HD/cKifutF5qGd/8ZJi84QeAKh+CEe1sBzz8UayBBGg1dAIJrdHOcOM5b2MpzWL2yuotJTtGjETq0qjXg== +"@babel/helper-module-imports@^7.22.15": + version "7.22.15" + resolved "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.22.15.tgz#16146307acdc40cc00c3b2c647713076464bdbf0" + integrity sha512-0pYVBnDKZO2fnSPCrgM/6WMc7eS20Fbok+0r88fp+YtWVLZrp4CkafFGIp+W0VKw4a22sgebPT99y+FDNMdP4w== dependencies: - "@babel/types" "^7.22.5" + "@babel/types" "^7.22.15" -"@babel/helper-module-transforms@^7.22.9": - version "7.22.9" - resolved "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.22.9.tgz#92dfcb1fbbb2bc62529024f72d942a8c97142129" - integrity sha512-t+WA2Xn5K+rTeGtC8jCsdAH52bjggG5TKRuRrAGNM/mjIbO4GxvlLMFOEz9wXY5I2XQ60PMFsAG2WIcG82dQMQ== +"@babel/helper-module-transforms@^7.23.0": + version "7.23.0" + resolved "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.23.0.tgz#3ec246457f6c842c0aee62a01f60739906f7047e" + integrity sha512-WhDWw1tdrlT0gMgUJSlX0IQvoO1eN279zrAUbVB+KpV2c3Tylz8+GnKOLllCS6Z/iZQEyVYxhZVUdPTqs2YYPw== dependencies: - "@babel/helper-environment-visitor" "^7.22.5" - "@babel/helper-module-imports" "^7.22.5" + "@babel/helper-environment-visitor" "^7.22.20" + "@babel/helper-module-imports" "^7.22.15" "@babel/helper-simple-access" "^7.22.5" "@babel/helper-split-export-declaration" "^7.22.6" - "@babel/helper-validator-identifier" "^7.22.5" + "@babel/helper-validator-identifier" "^7.22.20" "@babel/helper-plugin-utils@^7.22.5": version "7.22.5" @@ -133,38 +134,38 @@ resolved "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.22.5.tgz#533f36457a25814cf1df6488523ad547d784a99f" integrity sha512-mM4COjgZox8U+JcXQwPijIZLElkgEpO5rsERVDJTc2qfCDfERyob6k5WegS14SX18IIjv+XD+GrqNumY5JRCDw== -"@babel/helper-validator-identifier@^7.22.5": - version "7.22.5" - resolved "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.5.tgz#9544ef6a33999343c8740fa51350f30eeaaaf193" - integrity sha512-aJXu+6lErq8ltp+JhkJUfk1MTGyuA4v7f3pA+BJ5HLfNC6nAQ0Cpi9uOquUj8Hehg0aUiHzWQbOVJGao6ztBAQ== +"@babel/helper-validator-identifier@^7.22.20": + version "7.22.20" + resolved "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz#c4ae002c61d2879e724581d96665583dbc1dc0e0" + integrity sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A== -"@babel/helper-validator-option@^7.22.5": - version "7.22.5" - resolved "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.22.5.tgz#de52000a15a177413c8234fa3a8af4ee8102d0ac" - integrity sha512-R3oB6xlIVKUnxNUxbmgq7pKjxpru24zlimpE8WK47fACIlM0II/Hm1RS8IaOI7NgCr6LNS+jl5l75m20npAziw== +"@babel/helper-validator-option@^7.22.15": + version "7.22.15" + resolved "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.22.15.tgz#694c30dfa1d09a6534cdfcafbe56789d36aba040" + integrity sha512-bMn7RmyFjY/mdECUbgn9eoSY4vqvacUnS9i9vGAGttgFWesO6B4CYWA7XlpbWgBt71iv/hfbPlynohStqnu5hA== -"@babel/helpers@^7.22.6": - version "7.22.6" - resolved "https://registry.npmjs.org/@babel/helpers/-/helpers-7.22.6.tgz#8e61d3395a4f0c5a8060f309fb008200969b5ecd" - integrity sha512-YjDs6y/fVOYFV8hAf1rxd1QvR9wJe1pDBZ2AREKq/SDayfPzgk0PBnVuTCE5X1acEpMMNOVUqoe+OwiZGJ+OaA== +"@babel/helpers@^7.23.0": + version "7.23.1" + resolved "https://registry.npmjs.org/@babel/helpers/-/helpers-7.23.1.tgz#44e981e8ce2b9e99f8f0b703f3326a4636c16d15" + integrity sha512-chNpneuK18yW5Oxsr+t553UZzzAs3aZnFm4bxhebsNTeshrC95yA7l5yl7GBAG+JG1rF0F7zzD2EixK9mWSDoA== dependencies: - "@babel/template" "^7.22.5" - "@babel/traverse" "^7.22.6" - "@babel/types" "^7.22.5" + "@babel/template" "^7.22.15" + "@babel/traverse" "^7.23.0" + "@babel/types" "^7.23.0" -"@babel/highlight@^7.22.5": - version "7.22.5" - resolved "https://registry.npmjs.org/@babel/highlight/-/highlight-7.22.5.tgz#aa6c05c5407a67ebce408162b7ede789b4d22031" - integrity sha512-BSKlD1hgnedS5XRnGOljZawtag7H1yPfQp0tdNJCHoH6AZ+Pcm9VvkrK59/Yy593Ypg0zMxH2BxD1VPYUQ7UIw== +"@babel/highlight@^7.22.13": + version "7.22.20" + resolved "https://registry.npmjs.org/@babel/highlight/-/highlight-7.22.20.tgz#4ca92b71d80554b01427815e06f2df965b9c1f54" + integrity sha512-dkdMCN3py0+ksCgYmGG8jKeGA/8Tk+gJwSYYlFGxG5lmhfKNoAy004YpLxpS1W2J8m/EK2Ew+yOs9pVRwO89mg== dependencies: - "@babel/helper-validator-identifier" "^7.22.5" - chalk "^2.0.0" + "@babel/helper-validator-identifier" "^7.22.20" + chalk "^2.4.2" js-tokens "^4.0.0" -"@babel/parser@^7.22.5", "@babel/parser@^7.22.7": - version "7.22.7" - resolved "https://registry.npmjs.org/@babel/parser/-/parser-7.22.7.tgz#df8cf085ce92ddbdbf668a7f186ce848c9036cae" - integrity sha512-7NF8pOkHP5o2vpmGgNGcfAeCvOYhGLyA3Z4eBQkT1RJlWu47n63bCs93QfJ2hIAFCil7L5P2IWhs1oToVgrL0Q== +"@babel/parser@^7.22.15", "@babel/parser@^7.23.0": + version "7.23.0" + resolved "https://registry.npmjs.org/@babel/parser/-/parser-7.23.0.tgz#da950e622420bf96ca0d0f2909cdddac3acd8719" + integrity sha512-vvPKKdMemU85V9WE/l5wZEmImpCtLqbnTvqDS2U1fJ96KrxoW7KrXhNsNCblQlg8Ck4b85yxdTyelsMUgFUXiw== "@babel/plugin-syntax-jsx@^7.22.5": version "7.22.5" @@ -181,159 +182,159 @@ "@babel/plugin-transform-react-jsx" "^7.22.5" "@babel/plugin-transform-react-jsx@^7.14.9", "@babel/plugin-transform-react-jsx@^7.22.5": - version "7.22.5" - resolved "https://registry.npmjs.org/@babel/plugin-transform-react-jsx/-/plugin-transform-react-jsx-7.22.5.tgz#932c291eb6dd1153359e2a90cb5e557dcf068416" - integrity sha512-rog5gZaVbUip5iWDMTYbVM15XQq+RkUKhET/IHR6oizR+JEoN6CAfTTuHcK4vwUyzca30qqHqEpzBOnaRMWYMA== + version "7.22.15" + resolved "https://registry.npmjs.org/@babel/plugin-transform-react-jsx/-/plugin-transform-react-jsx-7.22.15.tgz#7e6266d88705d7c49f11c98db8b9464531289cd6" + integrity sha512-oKckg2eZFa8771O/5vi7XeTvmM6+O9cxZu+kanTU7tD4sin5nO/G8jGJhq8Hvt2Z0kUoEDRayuZLaUlYl8QuGA== dependencies: "@babel/helper-annotate-as-pure" "^7.22.5" - "@babel/helper-module-imports" "^7.22.5" + "@babel/helper-module-imports" "^7.22.15" "@babel/helper-plugin-utils" "^7.22.5" "@babel/plugin-syntax-jsx" "^7.22.5" - "@babel/types" "^7.22.5" - -"@babel/template@^7.22.5": - version "7.22.5" - resolved "https://registry.npmjs.org/@babel/template/-/template-7.22.5.tgz#0c8c4d944509875849bd0344ff0050756eefc6ec" - integrity sha512-X7yV7eiwAxdj9k94NEylvbVHLiVG1nvzCV2EAowhxLTwODV1jl9UzZ48leOC0sH7OnuHrIkllaBgneUykIcZaw== - dependencies: - "@babel/code-frame" "^7.22.5" - "@babel/parser" "^7.22.5" - "@babel/types" "^7.22.5" - -"@babel/traverse@^7.22.6", "@babel/traverse@^7.22.8": - version "7.22.8" - resolved "https://registry.npmjs.org/@babel/traverse/-/traverse-7.22.8.tgz#4d4451d31bc34efeae01eac222b514a77aa4000e" - integrity sha512-y6LPR+wpM2I3qJrsheCTwhIinzkETbplIgPBbwvqPKc+uljeA5gP+3nP8irdYt1mjQaDnlIcG+dw8OjAco4GXw== - dependencies: - "@babel/code-frame" "^7.22.5" - "@babel/generator" "^7.22.7" - "@babel/helper-environment-visitor" "^7.22.5" - "@babel/helper-function-name" "^7.22.5" + "@babel/types" "^7.22.15" + +"@babel/template@^7.22.15": + version "7.22.15" + resolved "https://registry.npmjs.org/@babel/template/-/template-7.22.15.tgz#09576efc3830f0430f4548ef971dde1350ef2f38" + integrity sha512-QPErUVm4uyJa60rkI73qneDacvdvzxshT3kksGqlGWYdOTIUOwJ7RDUL8sGqslY1uXWSL6xMFKEXDS3ox2uF0w== + dependencies: + "@babel/code-frame" "^7.22.13" + "@babel/parser" "^7.22.15" + "@babel/types" "^7.22.15" + +"@babel/traverse@^7.23.0": + version "7.23.0" + resolved "https://registry.npmjs.org/@babel/traverse/-/traverse-7.23.0.tgz#18196ddfbcf4ccea324b7f6d3ada00d8c5a99c53" + integrity sha512-t/QaEvyIoIkwzpiZ7aoSKK8kObQYeF7T2v+dazAYCb8SXtp58zEVkWW7zAnju8FNKNdr4ScAOEDmMItbyOmEYw== + dependencies: + "@babel/code-frame" "^7.22.13" + "@babel/generator" "^7.23.0" + "@babel/helper-environment-visitor" "^7.22.20" + "@babel/helper-function-name" "^7.23.0" "@babel/helper-hoist-variables" "^7.22.5" "@babel/helper-split-export-declaration" "^7.22.6" - "@babel/parser" "^7.22.7" - "@babel/types" "^7.22.5" + "@babel/parser" "^7.23.0" + "@babel/types" "^7.23.0" debug "^4.1.0" globals "^11.1.0" -"@babel/types@^7.22.5": - version "7.22.5" - resolved "https://registry.npmjs.org/@babel/types/-/types-7.22.5.tgz#cd93eeaab025880a3a47ec881f4b096a5b786fbe" - integrity sha512-zo3MIHGOkPOfoRXitsgHLjEXmlDaD/5KU1Uzuc9GNiZPhSqVxVRtxuPaSBZDsYZ9qV88AjtMtWW7ww98loJ9KA== +"@babel/types@^7.22.15", "@babel/types@^7.22.5", "@babel/types@^7.23.0": + version "7.23.0" + resolved "https://registry.npmjs.org/@babel/types/-/types-7.23.0.tgz#8c1f020c9df0e737e4e247c0619f58c68458aaeb" + integrity sha512-0oIyUfKoI3mSqMvsxBdclDwxXKXAUA8v/apZbc+iSyARYou1o8ZGDxbUYyLFoW2arqS2jDGqJuZvv1d/io1axg== dependencies: "@babel/helper-string-parser" "^7.22.5" - "@babel/helper-validator-identifier" "^7.22.5" + "@babel/helper-validator-identifier" "^7.22.20" to-fast-properties "^2.0.0" -"@esbuild/android-arm64@0.18.17": - version "0.18.17" - resolved "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.18.17.tgz#9e00eb6865ed5f2dbe71a1e96f2c52254cd92903" - integrity sha512-9np+YYdNDed5+Jgr1TdWBsozZ85U1Oa3xW0c7TWqH0y2aGghXtZsuT8nYRbzOMcl0bXZXjOGbksoTtVOlWrRZg== - -"@esbuild/android-arm@0.18.17": - version "0.18.17" - resolved "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.18.17.tgz#1aa013b65524f4e9f794946b415b32ae963a4618" - integrity sha512-wHsmJG/dnL3OkpAcwbgoBTTMHVi4Uyou3F5mf58ZtmUyIKfcdA7TROav/6tCzET4A3QW2Q2FC+eFneMU+iyOxg== - -"@esbuild/android-x64@0.18.17": - version "0.18.17" - resolved "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.18.17.tgz#c2bd0469b04ded352de011fae34a7a1d4dcecb79" - integrity sha512-O+FeWB/+xya0aLg23hHEM2E3hbfwZzjqumKMSIqcHbNvDa+dza2D0yLuymRBQQnC34CWrsJUXyH2MG5VnLd6uw== - -"@esbuild/darwin-arm64@0.18.17": - version "0.18.17" - resolved "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.18.17.tgz#0c21a59cb5bd7a2cec66c7a42431dca42aefeddd" - integrity sha512-M9uJ9VSB1oli2BE/dJs3zVr9kcCBBsE883prage1NWz6pBS++1oNn/7soPNS3+1DGj0FrkSvnED4Bmlu1VAE9g== - -"@esbuild/darwin-x64@0.18.17": - version "0.18.17" - resolved "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.18.17.tgz#92f8763ff6f97dff1c28a584da7b51b585e87a7b" - integrity sha512-XDre+J5YeIJDMfp3n0279DFNrGCXlxOuGsWIkRb1NThMZ0BsrWXoTg23Jer7fEXQ9Ye5QjrvXpxnhzl3bHtk0g== - -"@esbuild/freebsd-arm64@0.18.17": - version "0.18.17" - resolved "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.18.17.tgz#934f74bdf4022e143ba2f21d421b50fd0fead8f8" - integrity sha512-cjTzGa3QlNfERa0+ptykyxs5A6FEUQQF0MuilYXYBGdBxD3vxJcKnzDlhDCa1VAJCmAxed6mYhA2KaJIbtiNuQ== - -"@esbuild/freebsd-x64@0.18.17": - version "0.18.17" - resolved "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.18.17.tgz#16b6e90ba26ecc865eab71c56696258ec7f5d8bf" - integrity sha512-sOxEvR8d7V7Kw8QqzxWc7bFfnWnGdaFBut1dRUYtu+EIRXefBc/eIsiUiShnW0hM3FmQ5Zf27suDuHsKgZ5QrA== - -"@esbuild/linux-arm64@0.18.17": - version "0.18.17" - resolved "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.18.17.tgz#179a58e8d4c72116eb068563629349f8f4b48072" - integrity sha512-c9w3tE7qA3CYWjT+M3BMbwMt+0JYOp3vCMKgVBrCl1nwjAlOMYzEo+gG7QaZ9AtqZFj5MbUc885wuBBmu6aADQ== - -"@esbuild/linux-arm@0.18.17": - version "0.18.17" - resolved "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.18.17.tgz#9d78cf87a310ae9ed985c3915d5126578665c7b5" - integrity sha512-2d3Lw6wkwgSLC2fIvXKoMNGVaeY8qdN0IC3rfuVxJp89CRfA3e3VqWifGDfuakPmp90+ZirmTfye1n4ncjv2lg== - -"@esbuild/linux-ia32@0.18.17": - version "0.18.17" - resolved "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.18.17.tgz#6fed202602d37361bca376c9d113266a722a908c" - integrity sha512-1DS9F966pn5pPnqXYz16dQqWIB0dmDfAQZd6jSSpiT9eX1NzKh07J6VKR3AoXXXEk6CqZMojiVDSZi1SlmKVdg== - -"@esbuild/linux-loong64@0.18.17": - version "0.18.17" - resolved "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.18.17.tgz#cdc60304830be1e74560c704bfd72cab8a02fa06" - integrity sha512-EvLsxCk6ZF0fpCB6w6eOI2Fc8KW5N6sHlIovNe8uOFObL2O+Mr0bflPHyHwLT6rwMg9r77WOAWb2FqCQrVnwFg== - -"@esbuild/linux-mips64el@0.18.17": - version "0.18.17" - resolved "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.18.17.tgz#c367b2855bb0902f5576291a2049812af2088086" - integrity sha512-e0bIdHA5p6l+lwqTE36NAW5hHtw2tNRmHlGBygZC14QObsA3bD4C6sXLJjvnDIjSKhW1/0S3eDy+QmX/uZWEYQ== - -"@esbuild/linux-ppc64@0.18.17": - version "0.18.17" - resolved "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.18.17.tgz#7fdc0083d42d64a4651711ee0a7964f489242f45" - integrity sha512-BAAilJ0M5O2uMxHYGjFKn4nJKF6fNCdP1E0o5t5fvMYYzeIqy2JdAP88Az5LHt9qBoUa4tDaRpfWt21ep5/WqQ== - -"@esbuild/linux-riscv64@0.18.17": - version "0.18.17" - resolved "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.18.17.tgz#5198a417f3f5b86b10c95647b8bc032e5b6b2b1c" - integrity sha512-Wh/HW2MPnC3b8BqRSIme/9Zhab36PPH+3zam5pqGRH4pE+4xTrVLx2+XdGp6fVS3L2x+DrsIcsbMleex8fbE6g== - -"@esbuild/linux-s390x@0.18.17": - version "0.18.17" - resolved "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.18.17.tgz#7459c2fecdee2d582f0697fb76a4041f4ad1dd1e" - integrity sha512-j/34jAl3ul3PNcK3pfI0NSlBANduT2UO5kZ7FCaK33XFv3chDhICLY8wJJWIhiQ+YNdQ9dxqQctRg2bvrMlYgg== - -"@esbuild/linux-x64@0.18.17": - version "0.18.17" - resolved "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.18.17.tgz#948cdbf46d81c81ebd7225a7633009bc56a4488c" - integrity sha512-QM50vJ/y+8I60qEmFxMoxIx4de03pGo2HwxdBeFd4nMh364X6TIBZ6VQ5UQmPbQWUVWHWws5MmJXlHAXvJEmpQ== - -"@esbuild/netbsd-x64@0.18.17": - version "0.18.17" - resolved "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.18.17.tgz#6bb89668c0e093c5a575ded08e1d308bd7fd63e7" - integrity sha512-/jGlhWR7Sj9JPZHzXyyMZ1RFMkNPjC6QIAan0sDOtIo2TYk3tZn5UDrkE0XgsTQCxWTTOcMPf9p6Rh2hXtl5TQ== - -"@esbuild/openbsd-x64@0.18.17": - version "0.18.17" - resolved "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.18.17.tgz#abac2ae75fef820ef6c2c48da4666d092584c79d" - integrity sha512-rSEeYaGgyGGf4qZM2NonMhMOP/5EHp4u9ehFiBrg7stH6BYEEjlkVREuDEcQ0LfIl53OXLxNbfuIj7mr5m29TA== - -"@esbuild/sunos-x64@0.18.17": - version "0.18.17" - resolved "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.18.17.tgz#74a45fe1db8ea96898f1a9bb401dcf1dadfc8371" - integrity sha512-Y7ZBbkLqlSgn4+zot4KUNYst0bFoO68tRgI6mY2FIM+b7ZbyNVtNbDP5y8qlu4/knZZ73fgJDlXID+ohY5zt5g== - -"@esbuild/win32-arm64@0.18.17": - version "0.18.17" - resolved "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.18.17.tgz#fd95ffd217995589058a4ed8ac17ee72a3d7f615" - integrity sha512-bwPmTJsEQcbZk26oYpc4c/8PvTY3J5/QK8jM19DVlEsAB41M39aWovWoHtNm78sd6ip6prilxeHosPADXtEJFw== - -"@esbuild/win32-ia32@0.18.17": - version "0.18.17" - resolved "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.18.17.tgz#9b7ef5d0df97593a80f946b482e34fcba3fa4aaf" - integrity sha512-H/XaPtPKli2MhW+3CQueo6Ni3Avggi6hP/YvgkEe1aSaxw+AeO8MFjq8DlgfTd9Iz4Yih3QCZI6YLMoyccnPRg== - -"@esbuild/win32-x64@0.18.17": - version "0.18.17" - resolved "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.18.17.tgz#bcb2e042631b3c15792058e189ed879a22b2968b" - integrity sha512-fGEb8f2BSA3CW7riJVurug65ACLuQAzKq0SSqkY2b2yHHH0MzDfbLyKIGzHwOI/gkHcxM/leuSW6D5w/LMNitA== +"@esbuild/android-arm64@0.18.20": + version "0.18.20" + resolved "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.18.20.tgz#984b4f9c8d0377443cc2dfcef266d02244593622" + integrity sha512-Nz4rJcchGDtENV0eMKUNa6L12zz2zBDXuhj/Vjh18zGqB44Bi7MBMSXjgunJgjRhCmKOjnPuZp4Mb6OKqtMHLQ== + +"@esbuild/android-arm@0.18.20": + version "0.18.20" + resolved "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.18.20.tgz#fedb265bc3a589c84cc11f810804f234947c3682" + integrity sha512-fyi7TDI/ijKKNZTUJAQqiG5T7YjJXgnzkURqmGj13C6dCqckZBLdl4h7bkhHt/t0WP+zO9/zwroDvANaOqO5Sw== + +"@esbuild/android-x64@0.18.20": + version "0.18.20" + resolved "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.18.20.tgz#35cf419c4cfc8babe8893d296cd990e9e9f756f2" + integrity sha512-8GDdlePJA8D6zlZYJV/jnrRAi6rOiNaCC/JclcXpB+KIuvfBN4owLtgzY2bsxnx666XjJx2kDPUmnTtR8qKQUg== + +"@esbuild/darwin-arm64@0.18.20": + version "0.18.20" + resolved "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.18.20.tgz#08172cbeccf95fbc383399a7f39cfbddaeb0d7c1" + integrity sha512-bxRHW5kHU38zS2lPTPOyuyTm+S+eobPUnTNkdJEfAddYgEcll4xkT8DB9d2008DtTbl7uJag2HuE5NZAZgnNEA== + +"@esbuild/darwin-x64@0.18.20": + version "0.18.20" + resolved "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.18.20.tgz#d70d5790d8bf475556b67d0f8b7c5bdff053d85d" + integrity sha512-pc5gxlMDxzm513qPGbCbDukOdsGtKhfxD1zJKXjCCcU7ju50O7MeAZ8c4krSJcOIJGFR+qx21yMMVYwiQvyTyQ== + +"@esbuild/freebsd-arm64@0.18.20": + version "0.18.20" + resolved "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.18.20.tgz#98755cd12707f93f210e2494d6a4b51b96977f54" + integrity sha512-yqDQHy4QHevpMAaxhhIwYPMv1NECwOvIpGCZkECn8w2WFHXjEwrBn3CeNIYsibZ/iZEUemj++M26W3cNR5h+Tw== + +"@esbuild/freebsd-x64@0.18.20": + version "0.18.20" + resolved "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.18.20.tgz#c1eb2bff03915f87c29cece4c1a7fa1f423b066e" + integrity sha512-tgWRPPuQsd3RmBZwarGVHZQvtzfEBOreNuxEMKFcd5DaDn2PbBxfwLcj4+aenoh7ctXcbXmOQIn8HI6mCSw5MQ== + +"@esbuild/linux-arm64@0.18.20": + version "0.18.20" + resolved "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.18.20.tgz#bad4238bd8f4fc25b5a021280c770ab5fc3a02a0" + integrity sha512-2YbscF+UL7SQAVIpnWvYwM+3LskyDmPhe31pE7/aoTMFKKzIc9lLbyGUpmmb8a8AixOL61sQ/mFh3jEjHYFvdA== + +"@esbuild/linux-arm@0.18.20": + version "0.18.20" + resolved "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.18.20.tgz#3e617c61f33508a27150ee417543c8ab5acc73b0" + integrity sha512-/5bHkMWnq1EgKr1V+Ybz3s1hWXok7mDFUMQ4cG10AfW3wL02PSZi5kFpYKrptDsgb2WAJIvRcDm+qIvXf/apvg== + +"@esbuild/linux-ia32@0.18.20": + version "0.18.20" + resolved "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.18.20.tgz#699391cccba9aee6019b7f9892eb99219f1570a7" + integrity sha512-P4etWwq6IsReT0E1KHU40bOnzMHoH73aXp96Fs8TIT6z9Hu8G6+0SHSw9i2isWrD2nbx2qo5yUqACgdfVGx7TA== + +"@esbuild/linux-loong64@0.18.20": + version "0.18.20" + resolved "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.18.20.tgz#e6fccb7aac178dd2ffb9860465ac89d7f23b977d" + integrity sha512-nXW8nqBTrOpDLPgPY9uV+/1DjxoQ7DoB2N8eocyq8I9XuqJ7BiAMDMf9n1xZM9TgW0J8zrquIb/A7s3BJv7rjg== + +"@esbuild/linux-mips64el@0.18.20": + version "0.18.20" + resolved "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.18.20.tgz#eeff3a937de9c2310de30622a957ad1bd9183231" + integrity sha512-d5NeaXZcHp8PzYy5VnXV3VSd2D328Zb+9dEq5HE6bw6+N86JVPExrA6O68OPwobntbNJ0pzCpUFZTo3w0GyetQ== + +"@esbuild/linux-ppc64@0.18.20": + version "0.18.20" + resolved "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.18.20.tgz#2f7156bde20b01527993e6881435ad79ba9599fb" + integrity sha512-WHPyeScRNcmANnLQkq6AfyXRFr5D6N2sKgkFo2FqguP44Nw2eyDlbTdZwd9GYk98DZG9QItIiTlFLHJHjxP3FA== + +"@esbuild/linux-riscv64@0.18.20": + version "0.18.20" + resolved "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.18.20.tgz#6628389f210123d8b4743045af8caa7d4ddfc7a6" + integrity sha512-WSxo6h5ecI5XH34KC7w5veNnKkju3zBRLEQNY7mv5mtBmrP/MjNBCAlsM2u5hDBlS3NGcTQpoBvRzqBcRtpq1A== + +"@esbuild/linux-s390x@0.18.20": + version "0.18.20" + resolved "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.18.20.tgz#255e81fb289b101026131858ab99fba63dcf0071" + integrity sha512-+8231GMs3mAEth6Ja1iK0a1sQ3ohfcpzpRLH8uuc5/KVDFneH6jtAJLFGafpzpMRO6DzJ6AvXKze9LfFMrIHVQ== + +"@esbuild/linux-x64@0.18.20": + version "0.18.20" + resolved "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.18.20.tgz#c7690b3417af318a9b6f96df3031a8865176d338" + integrity sha512-UYqiqemphJcNsFEskc73jQ7B9jgwjWrSayxawS6UVFZGWrAAtkzjxSqnoclCXxWtfwLdzU+vTpcNYhpn43uP1w== + +"@esbuild/netbsd-x64@0.18.20": + version "0.18.20" + resolved "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.18.20.tgz#30e8cd8a3dded63975e2df2438ca109601ebe0d1" + integrity sha512-iO1c++VP6xUBUmltHZoMtCUdPlnPGdBom6IrO4gyKPFFVBKioIImVooR5I83nTew5UOYrk3gIJhbZh8X44y06A== + +"@esbuild/openbsd-x64@0.18.20": + version "0.18.20" + resolved "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.18.20.tgz#7812af31b205055874c8082ea9cf9ab0da6217ae" + integrity sha512-e5e4YSsuQfX4cxcygw/UCPIEP6wbIL+se3sxPdCiMbFLBWu0eiZOJ7WoD+ptCLrmjZBK1Wk7I6D/I3NglUGOxg== + +"@esbuild/sunos-x64@0.18.20": + version "0.18.20" + resolved "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.18.20.tgz#d5c275c3b4e73c9b0ecd38d1ca62c020f887ab9d" + integrity sha512-kDbFRFp0YpTQVVrqUd5FTYmWo45zGaXe0X8E1G/LKFC0v8x0vWrhOWSLITcCn63lmZIxfOMXtCfti/RxN/0wnQ== + +"@esbuild/win32-arm64@0.18.20": + version "0.18.20" + resolved "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.18.20.tgz#73bc7f5a9f8a77805f357fab97f290d0e4820ac9" + integrity sha512-ddYFR6ItYgoaq4v4JmQQaAI5s7npztfV4Ag6NrhiaW0RrnOXqBkgwZLofVTlq1daVTQNhtI5oieTvkRPfZrePg== + +"@esbuild/win32-ia32@0.18.20": + version "0.18.20" + resolved "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.18.20.tgz#ec93cbf0ef1085cc12e71e0d661d20569ff42102" + integrity sha512-Wv7QBi3ID/rROT08SABTS7eV4hX26sVduqDOTe1MvGMjNd3EjOz4b7zeexIR62GTIEKrfJXKL9LFxTYgkyeu7g== + +"@esbuild/win32-x64@0.18.20": + version "0.18.20" + resolved "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.18.20.tgz#786c5f41f043b07afb1af37683d7c33668858f6d" + integrity sha512-kTdfRcSiDfQca/y9QIkng02avJ+NCaQvrMejlsB3RRv5sE9rRoeBPISaZpKxHELzRxZyLvNts1P27W3wV+8geQ== "@jridgewell/gen-mapping@^0.3.0", "@jridgewell/gen-mapping@^0.3.2": version "0.3.3" @@ -344,33 +345,28 @@ "@jridgewell/sourcemap-codec" "^1.4.10" "@jridgewell/trace-mapping" "^0.3.9" -"@jridgewell/resolve-uri@3.1.0": - version "3.1.0" - resolved "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz#2203b118c157721addfe69d47b70465463066d78" - integrity sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w== +"@jridgewell/resolve-uri@^3.1.0": + version "3.1.1" + resolved "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.1.tgz#c08679063f279615a3326583ba3a90d1d82cc721" + integrity sha512-dSYZh7HhCDtCKm4QakX0xFpsRDqjjtZf/kjI/v3T3Nwt5r8/qz/M19F9ySyOqU94SXBmeG9ttTul+YnR4LOxFA== "@jridgewell/set-array@^1.0.1": version "1.1.2" resolved "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz#7c6cf998d6d20b914c0a55a91ae928ff25965e72" integrity sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw== -"@jridgewell/sourcemap-codec@1.4.14": - version "1.4.14" - resolved "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz#add4c98d341472a289190b424efbdb096991bb24" - integrity sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw== - -"@jridgewell/sourcemap-codec@^1.4.10": +"@jridgewell/sourcemap-codec@^1.4.10", "@jridgewell/sourcemap-codec@^1.4.14": version "1.4.15" resolved "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz#d7c6e6755c78567a951e04ab52ef0fd26de59f32" integrity sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg== "@jridgewell/trace-mapping@^0.3.17", "@jridgewell/trace-mapping@^0.3.9": - version "0.3.18" - resolved "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.18.tgz#25783b2086daf6ff1dcb53c9249ae480e4dd4cd6" - integrity sha512-w+niJYzMHdd7USdiH2U6869nqhD2nbfZXND5Yp93qIbEmnDNk7PD48o+YchRVpzMU7M6jVCbenTR7PA1FLQ9pA== + version "0.3.19" + resolved "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.19.tgz#f8a3249862f91be48d3127c3cfe992f79b4b8811" + integrity sha512-kf37QtfW+Hwx/buWGMPcR60iF9ziHa6r/CZJIHbmcm4+0qrXiVdxegAH0F6yddEVQ7zdkjcGCgCzUu+BcbhQxw== dependencies: - "@jridgewell/resolve-uri" "3.1.0" - "@jridgewell/sourcemap-codec" "1.4.14" + "@jridgewell/resolve-uri" "^3.1.0" + "@jridgewell/sourcemap-codec" "^1.4.14" "@microsoft/fast-element@^1.12.0", "@microsoft/fast-element@^1.6.2", "@microsoft/fast-element@^1.9.0": version "1.12.0" @@ -378,9 +374,9 @@ integrity sha512-gQutuDHPKNxUEcQ4pypZT4Wmrbapus+P9s3bR/SEOLsMbNqNoXigGImITygI5zhb+aA5rzflM6O8YWkmRbGkPA== "@microsoft/fast-foundation@^2.38.0", "@microsoft/fast-foundation@^2.41.1": - version "2.49.0" - resolved "https://registry.npmjs.org/@microsoft/fast-foundation/-/fast-foundation-2.49.0.tgz#cfacc35fb48c713d08d1bb493476bafe88d77455" - integrity sha512-Wk4e4QXFVtT5hPwhMfHyGY30kixM0td8aDs7bAD6NM2z2SCBNvpTTWp+FCjx0I0lpUMlMenb6wsw7pMWQreRkQ== + version "2.49.1" + resolved "https://registry.npmjs.org/@microsoft/fast-foundation/-/fast-foundation-2.49.1.tgz#f9cd36491d4d0080e694eaf0aece5672cdf7075a" + integrity sha512-dSajlZeX+lkqjg4108XbIIhVLECgJTCG32bE8P6rNgo8XCPHVJBDiBejrF34lv5pO9Z2uGORZjeip/N0fPib+g== dependencies: "@microsoft/fast-element" "^1.12.0" "@microsoft/fast-web-utilities" "^5.4.1" @@ -458,14 +454,14 @@ "@types/lodash" "*" "@types/lodash@*": - version "4.14.196" - resolved "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.196.tgz#a7c3d6fc52d8d71328b764e28e080b4169ec7a95" - integrity sha512-22y3o88f4a94mKljsZcanlNWPzO0uBsBdzLAngf2tp533LzZcQzb6+eZPJ+vCTt+bqF2XnvT9gejTLsAcJAJyQ== + version "4.14.199" + resolved "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.199.tgz#c3edb5650149d847a277a8961a7ad360c474e9bf" + integrity sha512-Vrjz5N5Ia4SEzWWgIVwnHNEnb1UE1XMkvY5DGXrAeOGE9imk0hgTHh5GyDjLDJi9OTCn9oo9dXH1uToK1VRfrg== "@types/vscode-webview@^1.57.1": - version "1.57.1" - resolved "https://registry.npmjs.org/@types/vscode-webview/-/vscode-webview-1.57.1.tgz#0bf2c9d57698b99be2bb2813272169f7f62eb714" - integrity sha512-ghW5SfuDmsGDS2A4xkvGsLwDRNc3Vj5rS6rPOyPm/IryZuf3wceZKxgYaUoW+k9f0f/CB7y2c1rRsdOWZWn0PQ== + version "1.57.2" + resolved "https://registry.npmjs.org/@types/vscode-webview/-/vscode-webview-1.57.2.tgz#aa6a8cf02c23ef7ce4e5f2d257f52b15ddd8ec78" + integrity sha512-RpkIso3+FVoi9hFwHj9uBFO+9p8PGym0LnLJ9Yabo9mUJaV39CzOxz6EVtHg8AidA9hAf4cVmG0c+l9pvw6Lbw== "@vscode/codicons@^0.0.33": version "0.0.33" @@ -494,21 +490,21 @@ babel-plugin-transform-hook-names@^1.0.2: integrity sha512-5gafyjyyBTTdX/tQQ0hRgu4AhNHG/hqWi0ZZmg2xvs2FgRkJXzDNKBZCyoYqgFkovfDrgM8OoKg8karoUvWeCw== browserslist@^4.21.9: - version "4.21.10" - resolved "https://registry.npmjs.org/browserslist/-/browserslist-4.21.10.tgz#dbbac576628c13d3b2231332cb2ec5a46e015bb0" - integrity sha512-bipEBdZfVH5/pwrvqc+Ub0kUPVfGUhlKxbvfD+z1BDnPEO/X98ruXGA1WP5ASpAFKan7Qr6j736IacbZQuAlKQ== + version "4.22.0" + resolved "https://registry.npmjs.org/browserslist/-/browserslist-4.22.0.tgz#6adc8116589ccea8a99d0df79c5de2436199abdb" + integrity sha512-v+Jcv64L2LbfTC6OnRcaxtqJNJuQAVhZKSJfR/6hn7lhnChUXl4amwVviqN1k411BB+3rRoKMitELRn1CojeRA== dependencies: - caniuse-lite "^1.0.30001517" - electron-to-chromium "^1.4.477" + caniuse-lite "^1.0.30001539" + electron-to-chromium "^1.4.530" node-releases "^2.0.13" - update-browserslist-db "^1.0.11" + update-browserslist-db "^1.0.13" -caniuse-lite@^1.0.30001517: - version "1.0.30001518" - resolved "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001518.tgz#b3ca93904cb4699c01218246c4d77a71dbe97150" - integrity sha512-rup09/e3I0BKjncL+FesTayKtPrdwKhUufQFd3riFw1hHg8JmIFoInYfB102cFcY/pPgGmdyl/iy+jgiDi2vdA== +caniuse-lite@^1.0.30001539: + version "1.0.30001541" + resolved "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001541.tgz#b1aef0fadd87fb72db4dcb55d220eae17b81cdb1" + integrity sha512-bLOsqxDgTqUBkzxbNlSBt8annkDpQB9NdzdTbO2ooJ+eC/IQcvDspDc058g84ejCelF7vHUx57KIOjEecOHXaw== -chalk@^2.0.0: +chalk@^2.4.2: version "2.4.2" resolved "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424" integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ== @@ -529,10 +525,10 @@ color-name@1.1.3: resolved "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25" integrity sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw== -convert-source-map@^1.7.0: - version "1.9.0" - resolved "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz#7faae62353fb4213366d0ca98358d22e8368b05f" - integrity sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A== +convert-source-map@^2.0.0: + version "2.0.0" + resolved "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz#4b560f649fc4e918dd0ab75cf4961e8bc882d82a" + integrity sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg== debug@^4.1.0, debug@^4.3.1: version "4.3.4" @@ -541,38 +537,38 @@ debug@^4.1.0, debug@^4.3.1: dependencies: ms "2.1.2" -electron-to-chromium@^1.4.477: - version "1.4.480" - resolved "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.480.tgz#40e32849ca50bc23ce29c1516c5adb3fddac919d" - integrity sha512-IXTgg+bITkQv/FLP9FjX6f9KFCs5hQWeh5uNSKxB9mqYj/JXhHDbu+ekS43LVvbkL3eW6/oZy4+r9Om6lan1Uw== +electron-to-chromium@^1.4.530: + version "1.4.534" + resolved "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.534.tgz#2056c1fc41a7157cdd5c634f96e758d727b69201" + integrity sha512-ikY7wAMtMt3jTnHsHG0YLl4MKJiKz2tgidenGSNgwUX2StBLNZ8VCxflD9tZK/ceTs4j8gDC9+6LQQ6iGkK04g== esbuild@^0.18.10: - version "0.18.17" - resolved "https://registry.npmjs.org/esbuild/-/esbuild-0.18.17.tgz#2aaf6bc6759b0c605777fdc435fea3969e091cad" - integrity sha512-1GJtYnUxsJreHYA0Y+iQz2UEykonY66HNWOb0yXYZi9/kNrORUEHVg87eQsCtqh59PEJ5YVZJO98JHznMJSWjg== + version "0.18.20" + resolved "https://registry.npmjs.org/esbuild/-/esbuild-0.18.20.tgz#4709f5a34801b43b799ab7d6d82f7284a9b7a7a6" + integrity sha512-ceqxoedUrcayh7Y7ZX6NdbbDzGROiyVBgC4PriJThBKSVPWnnFHZAkfI1lJT8QFkOwH4qOS2SJkS4wvpGl8BpA== optionalDependencies: - "@esbuild/android-arm" "0.18.17" - "@esbuild/android-arm64" "0.18.17" - "@esbuild/android-x64" "0.18.17" - "@esbuild/darwin-arm64" "0.18.17" - "@esbuild/darwin-x64" "0.18.17" - "@esbuild/freebsd-arm64" "0.18.17" - "@esbuild/freebsd-x64" "0.18.17" - "@esbuild/linux-arm" "0.18.17" - "@esbuild/linux-arm64" "0.18.17" - "@esbuild/linux-ia32" "0.18.17" - "@esbuild/linux-loong64" "0.18.17" - "@esbuild/linux-mips64el" "0.18.17" - "@esbuild/linux-ppc64" "0.18.17" - "@esbuild/linux-riscv64" "0.18.17" - "@esbuild/linux-s390x" "0.18.17" - "@esbuild/linux-x64" "0.18.17" - "@esbuild/netbsd-x64" "0.18.17" - "@esbuild/openbsd-x64" "0.18.17" - "@esbuild/sunos-x64" "0.18.17" - "@esbuild/win32-arm64" "0.18.17" - "@esbuild/win32-ia32" "0.18.17" - "@esbuild/win32-x64" "0.18.17" + "@esbuild/android-arm" "0.18.20" + "@esbuild/android-arm64" "0.18.20" + "@esbuild/android-x64" "0.18.20" + "@esbuild/darwin-arm64" "0.18.20" + "@esbuild/darwin-x64" "0.18.20" + "@esbuild/freebsd-arm64" "0.18.20" + "@esbuild/freebsd-x64" "0.18.20" + "@esbuild/linux-arm" "0.18.20" + "@esbuild/linux-arm64" "0.18.20" + "@esbuild/linux-ia32" "0.18.20" + "@esbuild/linux-loong64" "0.18.20" + "@esbuild/linux-mips64el" "0.18.20" + "@esbuild/linux-ppc64" "0.18.20" + "@esbuild/linux-riscv64" "0.18.20" + "@esbuild/linux-s390x" "0.18.20" + "@esbuild/linux-x64" "0.18.20" + "@esbuild/netbsd-x64" "0.18.20" + "@esbuild/openbsd-x64" "0.18.20" + "@esbuild/sunos-x64" "0.18.20" + "@esbuild/win32-arm64" "0.18.20" + "@esbuild/win32-ia32" "0.18.20" + "@esbuild/win32-x64" "0.18.20" escalade@^3.1.1: version "3.1.1" @@ -595,9 +591,9 @@ exenv-es6@^1.1.1: integrity sha512-vlVu3N8d6yEMpMsEm+7sUBAI81aqYYuEvfK0jNqmdb/OPXzzH7QWDDnVjMvDSY47JdHEqx/dfC/q8WkfoTmpGQ== fsevents@~2.3.2: - version "2.3.2" - resolved "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz#8a526f78b8fdf4623b709e0b975c52c24c02fd1a" - integrity sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA== + version "2.3.3" + resolved "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz#cac6407785d03675a2a5e1a5305c697b347d90d6" + integrity sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw== function-bind@^1.1.1: version "1.1.1" @@ -626,10 +622,10 @@ has@^1.0.3: dependencies: function-bind "^1.1.1" -is-core-module@^2.11.0: - version "2.12.1" - resolved "https://registry.npmjs.org/is-core-module/-/is-core-module-2.12.1.tgz#0c0b6885b6f80011c71541ce15c8d66cf5a4f9fd" - integrity sha512-Q4ZuBAe2FUsKtyQJoQHlvP8OvBERxO3jEmy1I7hcRXcJBGGHFh/aJBswbXuS9sgrDH2QUO8ilkwNPHvHMd8clg== +is-core-module@^2.13.0: + version "2.13.0" + resolved "https://registry.npmjs.org/is-core-module/-/is-core-module-2.13.0.tgz#bb52aa6e2cbd49a30c2ba68c42bf3435ba6072db" + integrity sha512-Z7dk6Qo8pOCp3l4tsX2C5ZVas4V+UxwQodwZhLopL91TX8UyyHEXafPcyoeeWuLrwzHcr3igO78wNLwHJHsMCQ== dependencies: has "^1.0.3" @@ -643,7 +639,7 @@ jsesc@^2.5.1: resolved "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz#80564d2e483dacf6e8ef209650a67df3f0c283a4" integrity sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA== -json5@^2.2.2: +json5@^2.2.3: version "2.2.3" resolved "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz#78cd6f1a19bdc12b73db5ad0c61efd66c1e29283" integrity sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg== @@ -695,33 +691,33 @@ picomatch@^2.2.2: resolved "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz#3ba3833733646d9d3e4995946c1365a67fb07a42" integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA== -postcss@^8.4.26: - version "8.4.27" - resolved "https://registry.npmjs.org/postcss/-/postcss-8.4.27.tgz#234d7e4b72e34ba5a92c29636734349e0d9c3057" - integrity sha512-gY/ACJtJPSmUFPDCHtX78+01fHa64FaU4zaaWfuh1MhGJISufJAH4cun6k/8fwsHYeK4UQmENQK+tRLCFJE8JQ== +postcss@^8.4.27: + version "8.4.30" + resolved "https://registry.npmjs.org/postcss/-/postcss-8.4.30.tgz#0e0648d551a606ef2192a26da4cabafcc09c1aa7" + integrity sha512-7ZEao1g4kd68l97aWG/etQKPKq07us0ieSZ2TnFDk11i0ZfDW2AwKHYU8qv4MZKqN2fdBfg+7q0ES06UA73C1g== dependencies: nanoid "^3.3.6" picocolors "^1.0.0" source-map-js "^1.0.2" preact@^10.16.0: - version "10.16.0" - resolved "https://registry.npmjs.org/preact/-/preact-10.16.0.tgz#68a06d70b191b8a313ea722d61e09c6b2a79a37e" - integrity sha512-XTSj3dJ4roKIC93pald6rWuB2qQJO9gO2iLLyTe87MrjQN+HklueLsmskbywEWqCHlclgz3/M4YLL2iBr9UmMA== + version "10.18.0" + resolved "https://registry.npmjs.org/preact/-/preact-10.18.0.tgz#20aaf95e3ef310a8127489376f54331682c353c7" + integrity sha512-O4dGFmErPd3RNVDvXmCbOW6hetnve6vYtjx5qf51mCUmBS96s66MrNQkEII5UThDGoNF7953ptA+aNupiDxVeg== resolve@^1.20.0: - version "1.22.2" - resolved "https://registry.npmjs.org/resolve/-/resolve-1.22.2.tgz#0ed0943d4e301867955766c9f3e1ae6d01c6845f" - integrity sha512-Sb+mjNHOULsBv818T40qSPeRiuWLyaGMa5ewydRLFimneixmVy2zdivRl+AF6jaYPC8ERxGDmFSiqui6SfPd+g== + version "1.22.6" + resolved "https://registry.npmjs.org/resolve/-/resolve-1.22.6.tgz#dd209739eca3aef739c626fea1b4f3c506195362" + integrity sha512-njhxM7mV12JfufShqGy3Rz8j11RPdLy4xi15UurGJeoHLfJpVXKdh3ueuOqbYUcDZnffr6X739JBo5LzyahEsw== dependencies: - is-core-module "^2.11.0" + is-core-module "^2.13.0" path-parse "^1.0.7" supports-preserve-symlinks-flag "^1.0.0" -rollup@^3.25.2: - version "3.27.0" - resolved "https://registry.npmjs.org/rollup/-/rollup-3.27.0.tgz#15bd07e2e1cbfa9255bf6a3f04a432621c2f3550" - integrity sha512-aOltLCrYZ0FhJDm7fCqwTjIUEVjWjcydKBV/Zeid6Mn8BWgDCUBBWT5beM5ieForYNo/1ZHuGJdka26kvQ3Gzg== +rollup@^3.27.1: + version "3.29.4" + resolved "https://registry.npmjs.org/rollup/-/rollup-3.29.4.tgz#4d70c0f9834146df8705bfb69a9a19c9e1109981" + integrity sha512-oWzmBZwvYrU0iJHtDmhsm662rC15FRXmcjCk1xD771dFDx5jJ02ufAQQTn0etB2emNk4J9EZg/yWKpsn9BWGRw== optionalDependencies: fsevents "~2.3.2" @@ -767,22 +763,22 @@ typescript@^4.5.3: resolved "https://registry.npmjs.org/typescript/-/typescript-4.9.5.tgz#095979f9bcc0d09da324d58d03ce8f8374cbe65a" integrity sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g== -update-browserslist-db@^1.0.11: - version "1.0.11" - resolved "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.11.tgz#9a2a641ad2907ae7b3616506f4b977851db5b940" - integrity sha512-dCwEFf0/oT85M1fHBg4F0jtLwJrutGoHSQXCh7u4o2t1drG+c0a9Flnqww6XUKSfQMPpJBRjU8d4RXB09qtvaA== +update-browserslist-db@^1.0.13: + version "1.0.13" + resolved "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.13.tgz#3c5e4f5c083661bd38ef64b6328c26ed6c8248c4" + integrity sha512-xebP81SNcPuNpPP3uzeW1NYXxI3rxyJzF3pD6sH4jE7o/IX+WtSpwnVU+qIsDPyk0d3hmFQ7mjqc6AtV604hbg== dependencies: escalade "^3.1.1" picocolors "^1.0.0" -vite@^4.4.8: - version "4.4.8" - resolved "https://registry.npmjs.org/vite/-/vite-4.4.8.tgz#31e4a438f8748695c68bd57ffd262ba93540fdf7" - integrity sha512-LONawOUUjxQridNWGQlNizfKH89qPigK36XhMI7COMGztz8KNY0JHim7/xDd71CZwGT4HtSRgI7Hy+RlhG0Gvg== +vite@^4.4.9: + version "4.4.9" + resolved "https://registry.npmjs.org/vite/-/vite-4.4.9.tgz#1402423f1a2f8d66fd8d15e351127c7236d29d3d" + integrity sha512-2mbUn2LlUmNASWwSCNSJ/EG2HuSRTnVNaydp6vMCm5VIqJsjMfbIWtbH2kDuwUVW5mMUKKZvGPX/rqeqVvv1XA== dependencies: esbuild "^0.18.10" - postcss "^8.4.26" - rollup "^3.25.2" + postcss "^8.4.27" + rollup "^3.27.1" optionalDependencies: fsevents "~2.3.2" diff --git a/packages/zowe-explorer/webviews/edit-attributes/vite.config.ts b/packages/zowe-explorer/webviews/edit-attributes/vite.config.ts deleted file mode 100644 index af1080d80b..0000000000 --- a/packages/zowe-explorer/webviews/edit-attributes/vite.config.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { defineConfig } from "vite"; -import preact from "@preact/preset-vite"; - -// https://vitejs.dev/config/ -export default defineConfig({ - plugins: [preact()], - build: { - rollupOptions: { - output: { - entryFileNames: `assets/[name].js`, - chunkFileNames: `assets/[name].js`, - assetFileNames: `assets/[name].[ext]`, - }, - }, - }, -}); diff --git a/yarn.lock b/yarn.lock index c01f78aaa9..98322a7d33 100644 --- a/yarn.lock +++ b/yarn.lock @@ -63,9 +63,9 @@ integrity sha512-EWZ4mE2diW3QALKvDMiXnbZpRvlj+nayZ112nK93SnhqOtpdsbVD4W+2tEoT3YNBAG9RBR0ISY758ZkOgsn6pQ== "@babel/compat-data@^7.22.9": - version "7.22.9" - resolved "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.22.9.tgz#71cdb00a1ce3a329ce4cbec3a44f9fef35669730" - integrity sha512-5UamI7xkUcJ3i9qVDS+KFDEK8/7oJ55/sJMB1Ge7IEapr7KfdfV/HErR+koZwOfd+SgtFKOKRhRakdg++DcJpQ== + version "7.22.20" + resolved "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.22.20.tgz#8df6e96661209623f1975d66c35ffca66f3306d0" + integrity sha512-BQYjKbpXjoXwFW5jGqiizJQQT/aC7pFm9Ok1OWssonuguICi264lbgMzRp2ZMmRSlfkX6DsWDDcsrctK8Rwfiw== "@babel/core@^7.1.0", "@babel/core@^7.12.3", "@babel/core@^7.9.0": version "7.17.10" @@ -110,21 +110,21 @@ semver "^6.3.0" "@babel/core@^7.22.1": - version "7.22.17" - resolved "https://registry.npmjs.org/@babel/core/-/core-7.22.17.tgz#2f9b0b395985967203514b24ee50f9fd0639c866" - integrity sha512-2EENLmhpwplDux5PSsZnSbnSkB3tZ6QTksgO25xwEL7pIDcNOMhF5v/s6RzwjMZzZzw9Ofc30gHv5ChCC8pifQ== + version "7.23.0" + resolved "https://registry.npmjs.org/@babel/core/-/core-7.23.0.tgz#f8259ae0e52a123eb40f552551e647b506a94d83" + integrity sha512-97z/ju/Jy1rZmDxybphrBuI+jtJjFVoz7Mr9yUQVVVi+DNZE333uFQeMOqcCIy1x3WYBIbWftUSLmbNXNT7qFQ== dependencies: "@ampproject/remapping" "^2.2.0" "@babel/code-frame" "^7.22.13" - "@babel/generator" "^7.22.15" + "@babel/generator" "^7.23.0" "@babel/helper-compilation-targets" "^7.22.15" - "@babel/helper-module-transforms" "^7.22.17" - "@babel/helpers" "^7.22.15" - "@babel/parser" "^7.22.16" + "@babel/helper-module-transforms" "^7.23.0" + "@babel/helpers" "^7.23.0" + "@babel/parser" "^7.23.0" "@babel/template" "^7.22.15" - "@babel/traverse" "^7.22.17" - "@babel/types" "^7.22.17" - convert-source-map "^1.7.0" + "@babel/traverse" "^7.23.0" + "@babel/types" "^7.23.0" + convert-source-map "^2.0.0" debug "^4.1.0" gensync "^1.0.0-beta.2" json5 "^2.2.3" @@ -148,12 +148,12 @@ "@jridgewell/gen-mapping" "^0.3.2" jsesc "^2.5.1" -"@babel/generator@^7.22.15": - version "7.22.15" - resolved "https://registry.npmjs.org/@babel/generator/-/generator-7.22.15.tgz#1564189c7ec94cb8f77b5e8a90c4d200d21b2339" - integrity sha512-Zu9oWARBqeVOW0dZOjXc3JObrzuqothQ3y/n1kUtrjCoCPLkXUwMvOo/F/TCfoHMbWIFlWwpZtkZVb9ga4U2pA== +"@babel/generator@^7.23.0": + version "7.23.0" + resolved "https://registry.npmjs.org/@babel/generator/-/generator-7.23.0.tgz#df5c386e2218be505b34837acbcb874d7a983420" + integrity sha512-lN85QRR+5IbYrMWM6Y4pE/noaQtg4pNiqeNGX60eqOfo6gtEj6uw/JagelB8vVztSd7R6M5n1+PQkDbHbBRU4g== dependencies: - "@babel/types" "^7.22.15" + "@babel/types" "^7.23.0" "@jridgewell/gen-mapping" "^0.3.2" "@jridgewell/trace-mapping" "^0.3.17" jsesc "^2.5.1" @@ -258,10 +258,10 @@ resolved "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.18.9.tgz#0c0cee9b35d2ca190478756865bb3528422f51be" integrity sha512-3r/aACDJ3fhQ/EVgFy0hpj8oHyHpQc+LPtJoY9SzTThAsStm4Ptegq92vqKoE3vD706ZVFWITnMnxucw+S9Ipg== -"@babel/helper-environment-visitor@^7.22.5": - version "7.22.5" - resolved "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.5.tgz#f06dd41b7c1f44e1f8da6c4055b41ab3a09a7e98" - integrity sha512-XGmhECfVA/5sAt+H+xpSg0mfrHq6FzNr9Oxh7PSEBBRUb/mL7Kz3NICXb194rCqAEdxkhPT1a88teizAFyvk8Q== +"@babel/helper-environment-visitor@^7.22.20": + version "7.22.20" + resolved "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.20.tgz#96159db61d34a29dba454c959f5ae4a649ba9167" + integrity sha512-zfedSIzFhat/gFhWfHtgWvlec0nqB9YEIVrpuwjruLlXfUSnA8cJB0miHKwqDnQ7d32aKo2xt88/xZptwxbfhA== "@babel/helper-explode-assignable-expression@^7.16.7": version "7.16.7" @@ -286,13 +286,13 @@ "@babel/template" "^7.18.10" "@babel/types" "^7.19.0" -"@babel/helper-function-name@^7.22.5": - version "7.22.5" - resolved "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.22.5.tgz#ede300828905bb15e582c037162f99d5183af1be" - integrity sha512-wtHSq6jMRE3uF2otvfuD3DIvVhOsSNshQl0Qrd7qC9oQJzHvOL4qQXlQn2916+CXGywIjpGuIkoyZRRxHPiNQQ== +"@babel/helper-function-name@^7.23.0": + version "7.23.0" + resolved "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.23.0.tgz#1f9a3cdbd5b2698a670c30d2735f9af95ed52759" + integrity sha512-OErEqsrxjZTJciZ4Oo+eoZqeW9UIiOcuYKRJA4ZAgV9myA+pOXhhmpfNCKjEH/auVfEYVFJ6y1Tc4r0eIApqiw== dependencies: - "@babel/template" "^7.22.5" - "@babel/types" "^7.22.5" + "@babel/template" "^7.22.15" + "@babel/types" "^7.23.0" "@babel/helper-hoist-variables@^7.16.7": version "7.16.7" @@ -371,16 +371,16 @@ "@babel/traverse" "^7.20.1" "@babel/types" "^7.20.2" -"@babel/helper-module-transforms@^7.22.17": - version "7.22.17" - resolved "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.22.17.tgz#7edf129097a51ccc12443adbc6320e90eab76693" - integrity sha512-XouDDhQESrLHTpnBtCKExJdyY4gJCdrvH2Pyv8r8kovX2U8G0dRUOT45T9XlbLtuu9CLXP15eusnkprhoPV5iQ== +"@babel/helper-module-transforms@^7.23.0": + version "7.23.0" + resolved "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.23.0.tgz#3ec246457f6c842c0aee62a01f60739906f7047e" + integrity sha512-WhDWw1tdrlT0gMgUJSlX0IQvoO1eN279zrAUbVB+KpV2c3Tylz8+GnKOLllCS6Z/iZQEyVYxhZVUdPTqs2YYPw== dependencies: - "@babel/helper-environment-visitor" "^7.22.5" + "@babel/helper-environment-visitor" "^7.22.20" "@babel/helper-module-imports" "^7.22.15" "@babel/helper-simple-access" "^7.22.5" "@babel/helper-split-export-declaration" "^7.22.6" - "@babel/helper-validator-identifier" "^7.22.15" + "@babel/helper-validator-identifier" "^7.22.20" "@babel/helper-optimise-call-expression@^7.16.7": version "7.16.7" @@ -493,10 +493,10 @@ resolved "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.19.1.tgz#7eea834cf32901ffdc1a7ee555e2f9c27e249ca2" integrity sha512-awrNfaMtnHUr653GgGEs++LlAvW6w+DcPrOliSMXWCKo597CwL5Acf/wWdNkf/tfEQE3mjkeD1YOVZOUV/od1w== -"@babel/helper-validator-identifier@^7.22.15", "@babel/helper-validator-identifier@^7.22.5": - version "7.22.15" - resolved "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.15.tgz#601fa28e4cc06786c18912dca138cec73b882044" - integrity sha512-4E/F9IIEi8WR94324mbDUMo074YTheJmd7eZF5vITTeYchqAi6sYXRLHUVsmkdmY4QjfKTcB2jB7dVP3NaBElQ== +"@babel/helper-validator-identifier@^7.22.20": + version "7.22.20" + resolved "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz#c4ae002c61d2879e724581d96665583dbc1dc0e0" + integrity sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A== "@babel/helper-validator-option@^7.16.7": version "7.16.7" @@ -541,14 +541,14 @@ "@babel/traverse" "^7.20.1" "@babel/types" "^7.20.0" -"@babel/helpers@^7.22.15": - version "7.22.15" - resolved "https://registry.npmjs.org/@babel/helpers/-/helpers-7.22.15.tgz#f09c3df31e86e3ea0b7ff7556d85cdebd47ea6f1" - integrity sha512-7pAjK0aSdxOwR+CcYAqgWOGy5dcfvzsTIfFTb2odQqW47MDfv14UaJDY6eng8ylM2EaeKXdxaSWESbkmaQHTmw== +"@babel/helpers@^7.23.0": + version "7.23.1" + resolved "https://registry.npmjs.org/@babel/helpers/-/helpers-7.23.1.tgz#44e981e8ce2b9e99f8f0b703f3326a4636c16d15" + integrity sha512-chNpneuK18yW5Oxsr+t553UZzzAs3aZnFm4bxhebsNTeshrC95yA7l5yl7GBAG+JG1rF0F7zzD2EixK9mWSDoA== dependencies: "@babel/template" "^7.22.15" - "@babel/traverse" "^7.22.15" - "@babel/types" "^7.22.15" + "@babel/traverse" "^7.23.0" + "@babel/types" "^7.23.0" "@babel/highlight@^7.10.4", "@babel/highlight@^7.18.6": version "7.18.6" @@ -569,11 +569,11 @@ js-tokens "^4.0.0" "@babel/highlight@^7.22.13": - version "7.22.13" - resolved "https://registry.npmjs.org/@babel/highlight/-/highlight-7.22.13.tgz#9cda839e5d3be9ca9e8c26b6dd69e7548f0cbf16" - integrity sha512-C/BaXcnnvBCmHTpz/VGZ8jgtE2aYlW4hxDhseJAWZb7gqGM/qtCK6iZUb0TyKFf7BOUsBH7Q7fkRsDRhg1XklQ== + version "7.22.20" + resolved "https://registry.npmjs.org/@babel/highlight/-/highlight-7.22.20.tgz#4ca92b71d80554b01427815e06f2df965b9c1f54" + integrity sha512-dkdMCN3py0+ksCgYmGG8jKeGA/8Tk+gJwSYYlFGxG5lmhfKNoAy004YpLxpS1W2J8m/EK2Ew+yOs9pVRwO89mg== dependencies: - "@babel/helper-validator-identifier" "^7.22.5" + "@babel/helper-validator-identifier" "^7.22.20" chalk "^2.4.2" js-tokens "^4.0.0" @@ -587,10 +587,10 @@ resolved "https://registry.npmjs.org/@babel/parser/-/parser-7.20.3.tgz#5358cf62e380cf69efcb87a7bb922ff88bfac6e2" integrity sha512-OP/s5a94frIPXwjzEcv5S/tpQfc6XhxYUnmWpgdqMWGgYCuErA3SzozaRAMQgSZWKeTJxht9aWAkUY+0UzvOFg== -"@babel/parser@^7.22.15", "@babel/parser@^7.22.16": - version "7.22.16" - resolved "https://registry.npmjs.org/@babel/parser/-/parser-7.22.16.tgz#180aead7f247305cce6551bea2720934e2fa2c95" - integrity sha512-+gPfKv8UWeKKeJTUxe59+OobVcrYHETCsORl61EmSkmgymguYk/X5bp7GuUIXaFsc6y++v8ZxPsLSSuujqDphA== +"@babel/parser@^7.22.15", "@babel/parser@^7.23.0": + version "7.23.0" + resolved "https://registry.npmjs.org/@babel/parser/-/parser-7.23.0.tgz#da950e622420bf96ca0d0f2909cdddac3acd8719" + integrity sha512-vvPKKdMemU85V9WE/l5wZEmImpCtLqbnTvqDS2U1fJ96KrxoW7KrXhNsNCblQlg8Ck4b85yxdTyelsMUgFUXiw== "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@^7.16.7": version "7.16.7" @@ -1278,7 +1278,7 @@ "@babel/parser" "^7.18.10" "@babel/types" "^7.18.10" -"@babel/template@^7.22.15", "@babel/template@^7.22.5": +"@babel/template@^7.22.15": version "7.22.15" resolved "https://registry.npmjs.org/@babel/template/-/template-7.22.15.tgz#09576efc3830f0430f4548ef971dde1350ef2f38" integrity sha512-QPErUVm4uyJa60rkI73qneDacvdvzxshT3kksGqlGWYdOTIUOwJ7RDUL8sGqslY1uXWSL6xMFKEXDS3ox2uF0w== @@ -1319,19 +1319,19 @@ debug "^4.1.0" globals "^11.1.0" -"@babel/traverse@^7.22.15", "@babel/traverse@^7.22.17": - version "7.22.17" - resolved "https://registry.npmjs.org/@babel/traverse/-/traverse-7.22.17.tgz#b23c203ab3707e3be816043081b4a994fcacec44" - integrity sha512-xK4Uwm0JnAMvxYZxOVecss85WxTEIbTa7bnGyf/+EgCL5Zt3U7htUpEOWv9detPlamGKuRzCqw74xVglDWpPdg== +"@babel/traverse@^7.23.0": + version "7.23.0" + resolved "https://registry.npmjs.org/@babel/traverse/-/traverse-7.23.0.tgz#18196ddfbcf4ccea324b7f6d3ada00d8c5a99c53" + integrity sha512-t/QaEvyIoIkwzpiZ7aoSKK8kObQYeF7T2v+dazAYCb8SXtp58zEVkWW7zAnju8FNKNdr4ScAOEDmMItbyOmEYw== dependencies: "@babel/code-frame" "^7.22.13" - "@babel/generator" "^7.22.15" - "@babel/helper-environment-visitor" "^7.22.5" - "@babel/helper-function-name" "^7.22.5" + "@babel/generator" "^7.23.0" + "@babel/helper-environment-visitor" "^7.22.20" + "@babel/helper-function-name" "^7.23.0" "@babel/helper-hoist-variables" "^7.22.5" "@babel/helper-split-export-declaration" "^7.22.6" - "@babel/parser" "^7.22.16" - "@babel/types" "^7.22.17" + "@babel/parser" "^7.23.0" + "@babel/types" "^7.23.0" debug "^4.1.0" globals "^11.1.0" @@ -1352,13 +1352,13 @@ "@babel/helper-validator-identifier" "^7.19.1" to-fast-properties "^2.0.0" -"@babel/types@^7.22.15", "@babel/types@^7.22.17", "@babel/types@^7.22.5": - version "7.22.17" - resolved "https://registry.npmjs.org/@babel/types/-/types-7.22.17.tgz#f753352c4610ffddf9c8bc6823f9ff03e2303eee" - integrity sha512-YSQPHLFtQNE5xN9tHuZnzu8vPr61wVTBZdfv1meex1NBosa4iT05k/Jw06ddJugi4bk7The/oSwQGFcksmEJQg== +"@babel/types@^7.22.15", "@babel/types@^7.22.5", "@babel/types@^7.23.0": + version "7.23.0" + resolved "https://registry.npmjs.org/@babel/types/-/types-7.23.0.tgz#8c1f020c9df0e737e4e247c0619f58c68458aaeb" + integrity sha512-0oIyUfKoI3mSqMvsxBdclDwxXKXAUA8v/apZbc+iSyARYou1o8ZGDxbUYyLFoW2arqS2jDGqJuZvv1d/io1axg== dependencies: "@babel/helper-string-parser" "^7.22.5" - "@babel/helper-validator-identifier" "^7.22.15" + "@babel/helper-validator-identifier" "^7.22.20" to-fast-properties "^2.0.0" "@bcoe/v8-coverage@^0.2.3": @@ -2341,9 +2341,9 @@ "@types/lodash" "*" "@types/lodash@*": - version "4.14.198" - resolved "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.198.tgz#4d27465257011aedc741a809f1269941fa2c5d4c" - integrity sha512-trNJ/vtMZYMLhfN45uLq4ShQSw0/S7xCTLLVM+WM1rmFpba/VS42jVUgaO3w/NOLiWR/09lnYk0yMaA/atdIsg== + version "4.14.199" + resolved "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.199.tgz#c3edb5650149d847a277a8961a7ad360c474e9bf" + integrity sha512-Vrjz5N5Ia4SEzWWgIVwnHNEnb1UE1XMkvY5DGXrAeOGE9imk0hgTHh5GyDjLDJi9OTCn9oo9dXH1uToK1VRfrg== "@types/markdown-it@^12.2.3": version "12.2.3" @@ -3014,7 +3014,7 @@ ansi-cyan@^0.1.1: dependencies: ansi-wrap "0.1.0" -ansi-escapes@^4.2.1: +ansi-escapes@^4.2.1, ansi-escapes@^4.3.0: version "4.3.2" resolved "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz#6b2291d1db7d98b6521d5f1efa42d0f3a9feb65e" integrity sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ== @@ -3696,14 +3696,14 @@ browserslist@^4.21.3: update-browserslist-db "^1.0.9" browserslist@^4.21.9: - version "4.21.10" - resolved "https://registry.npmjs.org/browserslist/-/browserslist-4.21.10.tgz#dbbac576628c13d3b2231332cb2ec5a46e015bb0" - integrity sha512-bipEBdZfVH5/pwrvqc+Ub0kUPVfGUhlKxbvfD+z1BDnPEO/X98ruXGA1WP5ASpAFKan7Qr6j736IacbZQuAlKQ== + version "4.22.1" + resolved "https://registry.npmjs.org/browserslist/-/browserslist-4.22.1.tgz#ba91958d1a59b87dab6fed8dfbcb3da5e2e9c619" + integrity sha512-FEVc202+2iuClEhZhrWy6ZiAcRLvNMyYcxZ8raemul1DYVOVdFsbqckWLdsixQZCpJlwe77Z3UTalE7jsjnKfQ== dependencies: - caniuse-lite "^1.0.30001517" - electron-to-chromium "^1.4.477" + caniuse-lite "^1.0.30001541" + electron-to-chromium "^1.4.535" node-releases "^2.0.13" - update-browserslist-db "^1.0.11" + update-browserslist-db "^1.0.13" bs-logger@0.x: version "0.2.6" @@ -3886,10 +3886,10 @@ caniuse-lite@^1.0.30001400: resolved "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001434.tgz#ec1ec1cfb0a93a34a0600d37903853030520a4e5" integrity sha512-aOBHrLmTQw//WFa2rcF1If9fa3ypkC1wzqqiKHgfdrXTWcU8C4gKVZT77eQAPWN1APys3+uQ0Df07rKauXGEYA== -caniuse-lite@^1.0.30001517: - version "1.0.30001532" - resolved "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001532.tgz#c6a4d5d2da6d2b967f0ee5e12e7f680db6ad2fca" - integrity sha512-FbDFnNat3nMnrROzqrsg314zhqN5LGQ1kyyMk2opcrwGbVGpHRhgCWtAgD5YJUqNAiQ+dklreil/c3Qf1dfCTw== +caniuse-lite@^1.0.30001541: + version "1.0.30001541" + resolved "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001541.tgz#b1aef0fadd87fb72db4dcb55d220eae17b81cdb1" + integrity sha512-bLOsqxDgTqUBkzxbNlSBt8annkDpQB9NdzdTbO2ooJ+eC/IQcvDspDc058g84ejCelF7vHUx57KIOjEecOHXaw== capture-stack-trace@^1.0.0: version "1.0.1" @@ -3950,7 +3950,7 @@ chalk@^1.1.3: strip-ansi "^3.0.0" supports-color "^2.0.0" -chalk@^4.0.0, chalk@^4.1.0: +chalk@^4.0.0, chalk@^4.1.0, chalk@^4.1.1: version "4.1.2" resolved "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz#aac4e2b7734a740867aeb16bf02aad556a1e7a01" integrity sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA== @@ -4002,7 +4002,7 @@ cheerio@^1.0.0-rc.9: parse5-htmlparser2-tree-adapter "^6.0.1" tslib "^2.2.0" -chokidar@3.5.3, chokidar@^3.4.1: +chokidar@3.5.3, chokidar@^3.4.1, chokidar@^3.5.1: version "3.5.3" resolved "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz#1cf37c8707b932bd1af1ae22c0432e2acd1903bd" integrity sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw== @@ -4250,6 +4250,11 @@ commander@^6.1.0: resolved "https://registry.npmjs.org/commander/-/commander-6.2.1.tgz#0792eb682dfbc325999bb2b84fddddba110ac73c" integrity sha512-U7VdrJFnJgo4xjrHpTzu0yrHPGImdsmD95ZlgYSEajAn2JKzDhDTPG9kBTefmObL2w/ngeZnilk+OV9CG3d7UA== +commander@^8.0.0: + version "8.3.0" + resolved "https://registry.npmjs.org/commander/-/commander-8.3.0.tgz#4837ea1b2da67b9c616a67afbb0fafee567bca66" + integrity sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww== + commander@~9.4.1: version "9.4.1" resolved "https://registry.npmjs.org/commander/-/commander-9.4.1.tgz#d1dd8f2ce6faf93147295c0df13c7c21141cfbdd" @@ -4917,10 +4922,10 @@ electron-to-chromium@^1.4.251: resolved "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.284.tgz#61046d1e4cab3a25238f6bf7413795270f125592" integrity sha512-M8WEXFuKXMYMVr45fo8mq0wUrrJHheiKZf6BArTKk9ZBYCKJEOU5H8cdWgDT+qCVZf7Na4lVUaZsA+h6uA9+PA== -electron-to-chromium@^1.4.477: - version "1.4.513" - resolved "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.513.tgz#41a50bf749aa7d8058ffbf7a131fc3327a7b1675" - integrity sha512-cOB0xcInjm+E5qIssHeXJ29BaUyWpMyFKT5RB3bsLENDheCja0wMkHJyiPl0NBE/VzDI7JDuNEQWhe6RitEUcw== +electron-to-chromium@^1.4.535: + version "1.4.535" + resolved "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.535.tgz#f14765820a0aa31425e1dbbae917cc70872b2a53" + integrity sha512-4548PpR4S5X5dlvX8NUIw0njH7btQtBoJWcgzpq7n2F9NQ5gMXOPP/6p6iVx6+YT3FVioNhEGa14WJj1k+2SfA== elliptic@^6.5.3: version "6.5.4" @@ -5532,7 +5537,7 @@ fast-glob@3.2.7: merge2 "^1.3.0" micromatch "^4.0.4" -fast-glob@^3.2.4: +fast-glob@^3.2.4, fast-glob@^3.2.7: version "3.3.1" resolved "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.1.tgz#784b4e897340f3dbbef17413b3f11acf03c874c4" integrity sha512-kNFPyjhh5cKjrUltxs+wFx+ZkbRaxxmZ+X0ZU31SOsxCEtP9VPgtq2teZw1DebupL5GmDaNQ6yKMMVcM41iqDg== @@ -5829,6 +5834,15 @@ fs-extra@^10.1.0: jsonfile "^6.0.1" universalify "^2.0.0" +fs-extra@^11.1.0: + version "11.1.1" + resolved "https://registry.npmjs.org/fs-extra/-/fs-extra-11.1.1.tgz#da69f7c39f3b002378b0954bb6ae7efdc0876e2d" + integrity sha512-MGIE4HOvQCeUCzmlHs0vXpih4ysz4wg9qiSAu6cd42lVwPbTM1TjV7RusoyQqMmk/95gdQZX72u+YW+c3eEpFQ== + dependencies: + graceful-fs "^4.2.0" + jsonfile "^6.0.1" + universalify "^2.0.0" + fs-minipass@^2.0.0, fs-minipass@^2.1.0: version "2.1.0" resolved "https://registry.npmjs.org/fs-minipass/-/fs-minipass-2.1.0.tgz#7f5036fdbf12c63c169190cbe4199c852271f9fb" @@ -8018,6 +8032,11 @@ lodash.merge@^4.6.2: resolved "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz#558aa53b43b661e1925a0afdfa36a9a1085fe57a" integrity sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ== +lodash.pick@^4.4.0: + version "4.4.0" + resolved "https://registry.npmjs.org/lodash.pick/-/lodash.pick-4.4.0.tgz#52f05610fff9ded422611441ed1fc123a03001b3" + integrity sha512-hXt6Ul/5yWjfklSGvLQl8vM//l3FtyHZeuelpzK6mm99pNvN9yTDruNZPEJZD1oWrqo+izBmB7oUfWgcCX7s4Q== + lodash.truncate@^4.4.2: version "4.4.2" resolved "https://registry.npmjs.org/lodash.truncate/-/lodash.truncate-4.4.2.tgz#5a350da0b1113b837ecfffd5812cbe58d6eae193" @@ -9498,18 +9517,18 @@ posix-character-classes@^0.1.0: integrity sha1-AerA/jta9xoqbAL+q7jB/vfgDqs= postcss@^8.4.27: - version "8.4.29" - resolved "https://registry.npmjs.org/postcss/-/postcss-8.4.29.tgz#33bc121cf3b3688d4ddef50be869b2a54185a1dd" - integrity sha512-cbI+jaqIeu/VGqXEarWkRCCffhjgXc0qjBtXpqJhTBohMUjUQnbBr0xqX3vEKudc4iviTewcJo5ajcec5+wdJw== + version "8.4.30" + resolved "https://registry.npmjs.org/postcss/-/postcss-8.4.30.tgz#0e0648d551a606ef2192a26da4cabafcc09c1aa7" + integrity sha512-7ZEao1g4kd68l97aWG/etQKPKq07us0ieSZ2TnFDk11i0ZfDW2AwKHYU8qv4MZKqN2fdBfg+7q0ES06UA73C1g== dependencies: nanoid "^3.3.6" picocolors "^1.0.0" source-map-js "^1.0.2" preact@^10.16.0: - version "10.17.1" - resolved "https://registry.npmjs.org/preact/-/preact-10.17.1.tgz#0a1b3c658c019e759326b9648c62912cf5c2dde1" - integrity sha512-X9BODrvQ4Ekwv9GURm9AKAGaomqXmip7NQTZgY7gcNmr7XE83adOMJvd3N42id1tMFU7ojiynRsYnY6/BRFxLA== + version "10.18.0" + resolved "https://registry.npmjs.org/preact/-/preact-10.18.0.tgz#20aaf95e3ef310a8127489376f54331682c353c7" + integrity sha512-O4dGFmErPd3RNVDvXmCbOW6hetnve6vYtjx5qf51mCUmBS96s66MrNQkEII5UThDGoNF7953ptA+aNupiDxVeg== prebuild-install@^7.0.1: version "7.1.0" @@ -10162,9 +10181,9 @@ ripemd160@^2.0.0, ripemd160@^2.0.1: inherits "^2.0.1" rollup@^3.27.1: - version "3.29.1" - resolved "https://registry.npmjs.org/rollup/-/rollup-3.29.1.tgz#ba53a179d46ac3cd79e162dca6ab70d93cd26f78" - integrity sha512-c+ebvQz0VIH4KhhCpDsI+Bik0eT8ZFEVZEYw0cGMVqIP8zc+gnwl7iXCamTw7vzv2MeuZFZfdx5JJIq+ehzDlg== + version "3.29.4" + resolved "https://registry.npmjs.org/rollup/-/rollup-3.29.4.tgz#4d70c0f9834146df8705bfb69a9a19c9e1109981" + integrity sha512-oWzmBZwvYrU0iJHtDmhsm662rC15FRXmcjCk1xD771dFDx5jJ02ufAQQTn0etB2emNk4J9EZg/yWKpsn9BWGRw== optionalDependencies: fsevents "~2.3.2" @@ -10294,7 +10313,7 @@ semver@7.5.2: dependencies: lru-cache "^6.0.0" -semver@7.x, semver@^7.0.0, semver@^7.1.1, semver@^7.1.3, semver@^7.2.1, semver@^7.3.4, semver@^7.3.5, semver@^7.3.7, semver@^7.5.3: +semver@7.x, semver@^7.0.0, semver@^7.1.1, semver@^7.1.3, semver@^7.2.1, semver@^7.3.4, semver@^7.3.5, semver@^7.3.7, semver@^7.5.0, semver@^7.5.3: version "7.5.4" resolved "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz#483986ec4ed38e1c6c48c34894a9182dbff68a6e" integrity sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA== @@ -11089,6 +11108,11 @@ timers-ext@^0.1.7: es5-ext "~0.10.46" next-tick "1" +tiny-invariant@^1.1.0: + version "1.3.1" + resolved "https://registry.npmjs.org/tiny-invariant/-/tiny-invariant-1.3.1.tgz#8560808c916ef02ecfd55e66090df23a4b7aa642" + integrity sha512-AD5ih2NlSssTCwsMznbvwMZpJ1cbhkGd2uueNxzv2jDlEeZdU04JQfRnggJQ8DrcVBGjAsCKwFBbDlVNtEMlzw== + tmp@0.0.30: version "0.0.30" resolved "https://registry.npmjs.org/tmp/-/tmp-0.0.30.tgz#72419d4a8be7d6ce75148fd8b324e593a711c2ed" @@ -11482,10 +11506,10 @@ upath@^1.1.1: resolved "https://registry.npmjs.org/upath/-/upath-1.2.0.tgz#8f66dbcd55a883acdae4408af8b035a5044c1894" integrity sha512-aZwGpamFO61g3OlfT7OQCHqhGnW43ieH9WZeP7QxN/G/jS4jfqUkZxoryvJgVPEcrl5NL/ggHsSmLMHuH64Lhg== -update-browserslist-db@^1.0.11: - version "1.0.11" - resolved "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.11.tgz#9a2a641ad2907ae7b3616506f4b977851db5b940" - integrity sha512-dCwEFf0/oT85M1fHBg4F0jtLwJrutGoHSQXCh7u4o2t1drG+c0a9Flnqww6XUKSfQMPpJBRjU8d4RXB09qtvaA== +update-browserslist-db@^1.0.13: + version "1.0.13" + resolved "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.13.tgz#3c5e4f5c083661bd38ef64b6328c26ed6c8248c4" + integrity sha512-xebP81SNcPuNpPP3uzeW1NYXxI3rxyJzF3pD6sH4jE7o/IX+WtSpwnVU+qIsDPyk0d3hmFQ7mjqc6AtV604hbg== dependencies: escalade "^3.1.1" picocolors "^1.0.0" @@ -11672,7 +11696,30 @@ vinyl@^2.0.0, vinyl@^2.1.0, vinyl@^2.2.1: remove-trailing-separator "^1.0.1" replace-ext "^1.0.0" -vite@^4.4.8: +vite-plugin-checker@^0.6.2: + version "0.6.2" + resolved "https://registry.npmjs.org/vite-plugin-checker/-/vite-plugin-checker-0.6.2.tgz#3790381734440033e6cb3cee9d92fcfdd69a4d71" + integrity sha512-YvvvQ+IjY09BX7Ab+1pjxkELQsBd4rPhWNw8WLBeFVxu/E7O+n6VYAqNsKdK/a2luFlX/sMpoWdGFfg4HvwdJQ== + dependencies: + "@babel/code-frame" "^7.12.13" + ansi-escapes "^4.3.0" + chalk "^4.1.1" + chokidar "^3.5.1" + commander "^8.0.0" + fast-glob "^3.2.7" + fs-extra "^11.1.0" + lodash.debounce "^4.0.8" + lodash.pick "^4.4.0" + npm-run-path "^4.0.1" + semver "^7.5.0" + strip-ansi "^6.0.0" + tiny-invariant "^1.1.0" + vscode-languageclient "^7.0.0" + vscode-languageserver "^7.0.0" + vscode-languageserver-textdocument "^1.0.1" + vscode-uri "^3.0.2" + +vite@^4.4.9: version "4.4.9" resolved "https://registry.npmjs.org/vite/-/vite-4.4.9.tgz#1402423f1a2f8d66fd8d15e351127c7236d29d3d" integrity sha512-2mbUn2LlUmNASWwSCNSJ/EG2HuSRTnVNaydp6vMCm5VIqJsjMfbIWtbH2kDuwUVW5mMUKKZvGPX/rqeqVvv1XA== @@ -11714,6 +11761,45 @@ vsce@2.15.0: yauzl "^2.3.1" yazl "^2.2.2" +vscode-jsonrpc@6.0.0: + version "6.0.0" + resolved "https://registry.npmjs.org/vscode-jsonrpc/-/vscode-jsonrpc-6.0.0.tgz#108bdb09b4400705176b957ceca9e0880e9b6d4e" + integrity sha512-wnJA4BnEjOSyFMvjZdpiOwhSq9uDoK8e/kpRJDTaMYzwlkrhG1fwDIZI94CLsLzlCK5cIbMMtFlJlfR57Lavmg== + +vscode-languageclient@^7.0.0: + version "7.0.0" + resolved "https://registry.npmjs.org/vscode-languageclient/-/vscode-languageclient-7.0.0.tgz#b505c22c21ffcf96e167799757fca07a6bad0fb2" + integrity sha512-P9AXdAPlsCgslpP9pRxYPqkNYV7Xq8300/aZDpO35j1fJm/ncize8iGswzYlcvFw5DQUx4eVk+KvfXdL0rehNg== + dependencies: + minimatch "^3.0.4" + semver "^7.3.4" + vscode-languageserver-protocol "3.16.0" + +vscode-languageserver-protocol@3.16.0: + version "3.16.0" + resolved "https://registry.npmjs.org/vscode-languageserver-protocol/-/vscode-languageserver-protocol-3.16.0.tgz#34135b61a9091db972188a07d337406a3cdbe821" + integrity sha512-sdeUoAawceQdgIfTI+sdcwkiK2KU+2cbEYA0agzM2uqaUy2UpnnGHtWTHVEtS0ES4zHU0eMFRGN+oQgDxlD66A== + dependencies: + vscode-jsonrpc "6.0.0" + vscode-languageserver-types "3.16.0" + +vscode-languageserver-textdocument@^1.0.1: + version "1.0.11" + resolved "https://registry.npmjs.org/vscode-languageserver-textdocument/-/vscode-languageserver-textdocument-1.0.11.tgz#0822a000e7d4dc083312580d7575fe9e3ba2e2bf" + integrity sha512-X+8T3GoiwTVlJbicx/sIAF+yuJAqz8VvwJyoMVhwEMoEKE/fkDmrqUgDMyBECcM2A2frVZIUj5HI/ErRXCfOeA== + +vscode-languageserver-types@3.16.0: + version "3.16.0" + resolved "https://registry.npmjs.org/vscode-languageserver-types/-/vscode-languageserver-types-3.16.0.tgz#ecf393fc121ec6974b2da3efb3155644c514e247" + integrity sha512-k8luDIWJWyenLc5ToFQQMaSrqCHiLwyKPHKPQZ5zz21vM+vIVUSvsRpcbiECH4WR88K2XZqc4ScRcZ7nk/jbeA== + +vscode-languageserver@^7.0.0: + version "7.0.0" + resolved "https://registry.npmjs.org/vscode-languageserver/-/vscode-languageserver-7.0.0.tgz#49b068c87cfcca93a356969d20f5d9bdd501c6b0" + integrity sha512-60HTx5ID+fLRcgdHfmz0LDZAXYEV68fzwG0JWwEPBode9NuMYTIxuYXPg4ngO8i8+Ou0lM7y6GzaYWbiDL0drw== + dependencies: + vscode-languageserver-protocol "3.16.0" + vscode-nls-dev@^4.0.0: version "4.0.0" resolved "https://registry.npmjs.org/vscode-nls-dev/-/vscode-nls-dev-4.0.0.tgz#2da842826d2b02ac575590ba4e7a9308d9def19a" @@ -11747,6 +11833,11 @@ vscode-test@^1.4.0: rimraf "^3.0.2" unzipper "^0.10.11" +vscode-uri@^3.0.2: + version "3.0.7" + resolved "https://registry.npmjs.org/vscode-uri/-/vscode-uri-3.0.7.tgz#6d19fef387ee6b46c479e5fb00870e15e58c1eb8" + integrity sha512-eOpPHogvorZRobNqJGhapa0JdwaxpjVvyBp0QIUMRMSf8ZAlqOdEquKuRmw9Qwu0qXtJIWqFtMkmvJjUZmMjVA== + w3c-hr-time@^1.0.2: version "1.0.2" resolved "https://registry.npmjs.org/w3c-hr-time/-/w3c-hr-time-1.0.2.tgz#0a89cdf5cc15822df9c360543676963e0cc308cd" From 0881ac1d79c5ea0702e23348dd6dd968c29ff4fb Mon Sep 17 00:00:00 2001 From: Rudy Flores <68666202+rudyflores@users.noreply.github.com> Date: Thu, 28 Sep 2023 16:25:43 -0400 Subject: [PATCH 058/189] add back tag code lost from merge Signed-off-by: Rudy Flores <68666202+rudyflores@users.noreply.github.com> --- .../src/webviews/src/edit-attributes/App.tsx | 13 +++++++++++++ .../src/webviews/src/edit-attributes/types.ts | 1 + 2 files changed, 14 insertions(+) diff --git a/packages/zowe-explorer/src/webviews/src/edit-attributes/App.tsx b/packages/zowe-explorer/src/webviews/src/edit-attributes/App.tsx index b15dcfd43e..0d44c55652 100644 --- a/packages/zowe-explorer/src/webviews/src/edit-attributes/App.tsx +++ b/packages/zowe-explorer/src/webviews/src/edit-attributes/App.tsx @@ -15,6 +15,7 @@ import isEqual from "lodash.isequal"; const vscodeApi = acquireVsCodeApi(); export function App() { + const notSupported = "NOT SUPPORTED"; const [readonly, setReadonly] = useState(false); const [allowUpdate, setAllowUpdate] = useState(false); const [attributes, setAttributes] = useState>({ @@ -111,6 +112,7 @@ export function App() { }; return all; }, {}), + tag: attributes.tag ?? notSupported, }; setAttributes({ @@ -155,6 +157,17 @@ export function App() {
{attributes.current.name}
+ {attributes.initial?.directory ?? false ? null : ( +
+ updateFileAttributes("tag", e.target.value)} + > + Tag + +
+ )}
diff --git a/packages/zowe-explorer/src/webviews/src/edit-attributes/types.ts b/packages/zowe-explorer/src/webviews/src/edit-attributes/types.ts index baed9f91a3..5abc08315f 100644 --- a/packages/zowe-explorer/src/webviews/src/edit-attributes/types.ts +++ b/packages/zowe-explorer/src/webviews/src/edit-attributes/types.ts @@ -26,4 +26,5 @@ export type FileAttributes = { directory: boolean; group: string; perms: FilePermissions; + tag?: string; }; From e5990bb4ae4d54278008b2cf9eaa89ca22fb15f3 Mon Sep 17 00:00:00 2001 From: Rudy Flores <68666202+rudyflores@users.noreply.github.com> Date: Thu, 28 Sep 2023 17:00:54 -0400 Subject: [PATCH 059/189] fix lint check Signed-off-by: Rudy Flores <68666202+rudyflores@users.noreply.github.com> --- packages/zowe-explorer/src/webviews/package.json | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/packages/zowe-explorer/src/webviews/package.json b/packages/zowe-explorer/src/webviews/package.json index 7e625a963a..d533079509 100644 --- a/packages/zowe-explorer/src/webviews/package.json +++ b/packages/zowe-explorer/src/webviews/package.json @@ -13,9 +13,10 @@ "clean": "gulp clean", "package": "echo \"webviews: nothing to package.\"", "test": "echo \"webviews: nothing to test\"", - "lint": "echo \"webviews: nothing to lint.\"", + "lint": "yarn lint:pretty", "lint:html": "echo \"webviews: nothing to lint.\"", - "pretty": "echo \"webviews: nothing to pretty.\"", + "lint:pretty": "prettier --check .", + "pretty": "prettier --write .", "madge": "echo \"webviews: nothing to madge.\"" }, "dependencies": { From 3bc88aa3853886019fb105457ff89efeb8278a4e Mon Sep 17 00:00:00 2001 From: Rudy Flores <68666202+rudyflores@users.noreply.github.com> Date: Fri, 29 Sep 2023 10:38:17 -0400 Subject: [PATCH 060/189] add new dist location to prettierignore Signed-off-by: Rudy Flores <68666202+rudyflores@users.noreply.github.com> --- packages/zowe-explorer/.prettierignore | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/zowe-explorer/.prettierignore b/packages/zowe-explorer/.prettierignore index 524eab72be..7a0ab09158 100644 --- a/packages/zowe-explorer/.prettierignore +++ b/packages/zowe-explorer/.prettierignore @@ -1,4 +1,4 @@ out results scripts -webviews/**/dist \ No newline at end of file +src/webviews/dist From 45585bc600a62634c988a778a9107c9de7dab229 Mon Sep 17 00:00:00 2001 From: Rudy Flores <68666202+rudyflores@users.noreply.github.com> Date: Fri, 29 Sep 2023 13:21:32 -0400 Subject: [PATCH 061/189] revert lint to original no lint message Signed-off-by: Rudy Flores <68666202+rudyflores@users.noreply.github.com> --- packages/zowe-explorer/src/webviews/package.json | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/packages/zowe-explorer/src/webviews/package.json b/packages/zowe-explorer/src/webviews/package.json index d533079509..d8cb90f888 100644 --- a/packages/zowe-explorer/src/webviews/package.json +++ b/packages/zowe-explorer/src/webviews/package.json @@ -13,10 +13,9 @@ "clean": "gulp clean", "package": "echo \"webviews: nothing to package.\"", "test": "echo \"webviews: nothing to test\"", - "lint": "yarn lint:pretty", + "lint": "echo \"webviews: nothing to lint.\"", "lint:html": "echo \"webviews: nothing to lint.\"", - "lint:pretty": "prettier --check .", - "pretty": "prettier --write .", + "pretty": "echo \"edit-attributes: nothing to pretty.\"", "madge": "echo \"webviews: nothing to madge.\"" }, "dependencies": { From 5afd103c4e38e7d2dc96f723a0483e52c49ae861 Mon Sep 17 00:00:00 2001 From: Likhitha Nimma Date: Sat, 30 Sep 2023 00:39:47 +0530 Subject: [PATCH 062/189] addToConfigArray functionality changed Signed-off-by: Likhitha Nimma --- packages/zowe-explorer-api/src/profiles/ProfilesCache.ts | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/packages/zowe-explorer-api/src/profiles/ProfilesCache.ts b/packages/zowe-explorer-api/src/profiles/ProfilesCache.ts index c2d8d7f061..63b441a2ee 100644 --- a/packages/zowe-explorer-api/src/profiles/ProfilesCache.ts +++ b/packages/zowe-explorer-api/src/profiles/ProfilesCache.ts @@ -86,7 +86,13 @@ export class ProfilesCache { public addToConfigArray(extendermetadata: zowe.imperative.ICommandProfileTypeConfiguration[]): void { extendermetadata?.forEach((item) => { - if (!this.profileTypeConfigurations.some((ele) => ele.type === item.type)) this.profileTypeConfigurations.push(item); + let index = this.profileTypeConfigurations.findIndex((ele) => ele.type == item.type) + if(index!=-1){ + this.profileTypeConfigurations[index] = item; + } + else{ + this.profileTypeConfigurations.push(item); + } }); } From 9a013ed562d6cf8fa892f92577248674059b8e46 Mon Sep 17 00:00:00 2001 From: Likhitha Nimma Date: Sun, 1 Oct 2023 00:51:01 +0530 Subject: [PATCH 063/189] Fixed Linting Signed-off-by: Likhitha Nimma --- packages/zowe-explorer-api/src/profiles/ProfilesCache.ts | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/packages/zowe-explorer-api/src/profiles/ProfilesCache.ts b/packages/zowe-explorer-api/src/profiles/ProfilesCache.ts index 63b441a2ee..7fea938432 100644 --- a/packages/zowe-explorer-api/src/profiles/ProfilesCache.ts +++ b/packages/zowe-explorer-api/src/profiles/ProfilesCache.ts @@ -86,11 +86,10 @@ export class ProfilesCache { public addToConfigArray(extendermetadata: zowe.imperative.ICommandProfileTypeConfiguration[]): void { extendermetadata?.forEach((item) => { - let index = this.profileTypeConfigurations.findIndex((ele) => ele.type == item.type) - if(index!=-1){ + const index = this.profileTypeConfigurations.findIndex((ele) => ele.type == item.type); + if (index !== -1) { this.profileTypeConfigurations[index] = item; - } - else{ + } else { this.profileTypeConfigurations.push(item); } }); From cac1c2b9a1eb0b7fc3eac016693860dc6b934346 Mon Sep 17 00:00:00 2001 From: Timothy Johnson Date: Mon, 2 Oct 2023 08:20:32 -0400 Subject: [PATCH 064/189] Fix Coverity issue and use local ZE API in samples Signed-off-by: Timothy Johnson --- .../zowe-explorer/src/dataset/ZoweDatasetNode.ts | 2 +- samples/menu-item-sample/package.json | 2 +- samples/menu-item-sample/yarn.lock | 16 +++++++--------- samples/tree-view-sample/package.json | 2 +- samples/tree-view-sample/yarn.lock | 16 +++++++--------- samples/uss-profile-sample/package.json | 2 +- samples/uss-profile-sample/yarn.lock | 16 +++++++--------- samples/vue-webview-sample/package.json | 2 +- samples/vue-webview-sample/yarn.lock | 16 +++++++--------- 9 files changed, 33 insertions(+), 41 deletions(-) diff --git a/packages/zowe-explorer/src/dataset/ZoweDatasetNode.ts b/packages/zowe-explorer/src/dataset/ZoweDatasetNode.ts index 2e966abb34..8d369eb00d 100644 --- a/packages/zowe-explorer/src/dataset/ZoweDatasetNode.ts +++ b/packages/zowe-explorer/src/dataset/ZoweDatasetNode.ts @@ -305,7 +305,7 @@ export class ZoweDatasetNode extends ZoweTreeNode implements IZoweDatasetTreeNod ), ]; const mvsApi = ZoweExplorerApiRegister.getMvsApi(cachedProfile); - if (!mvsApi.getSession(mvsApi?.profile)) { + if (!mvsApi.getSession(cachedProfile)) { throw new zowe.imperative.ImperativeError({ msg: localize("getDataSets.error.sessionMissing", "Profile auth error"), additionalDetails: localize("getDataSets.error.additionalDetails", "Profile is not authenticated, please log in to continue"), diff --git a/samples/menu-item-sample/package.json b/samples/menu-item-sample/package.json index bb1acfa0e5..7856483b49 100644 --- a/samples/menu-item-sample/package.json +++ b/samples/menu-item-sample/package.json @@ -46,7 +46,7 @@ "watch": "tsc -watch -p ./" }, "dependencies": { - "@zowe/zowe-explorer-api": "^2.10.0" + "@zowe/zowe-explorer-api": "file:../../packages/zowe-explorer-api" }, "devDependencies": { "@types/node": "^16.18.34", diff --git a/samples/menu-item-sample/yarn.lock b/samples/menu-item-sample/yarn.lock index 254e09d7f1..59eb328aa3 100644 --- a/samples/menu-item-sample/yarn.lock +++ b/samples/menu-item-sample/yarn.lock @@ -356,10 +356,10 @@ resolved "https://registry.npmjs.org/@zowe/secrets-for-zowe-sdk/-/secrets-for-zowe-sdk-7.18.0.tgz#d7974ac234e79ce220e15fc4f7f17d880754b739" integrity sha512-lWs7oVjXpotWw8bu4NxPszu+MiTJgzdiYgj/0q0OBYLJdoZtKBTGRSohtoLZWpu6mfObiEICI1k8UDE8v7xbPw== -"@zowe/secrets-for-zowe-sdk@7.18.1": - version "7.18.1" - resolved "https://registry.npmjs.org/@zowe/secrets-for-zowe-sdk/-/secrets-for-zowe-sdk-7.18.1.tgz#546a63f5ed880418f0e0496d0218c284c815c3ee" - integrity sha512-bcAnauDpTQXCPT8rMx2wrZwhg6xih1lDujG20h1sUGJC5eqvsNCq6gvpOtcahEpUF25oBJ931dKlIu1T99LQ7w== +"@zowe/secrets-for-zowe-sdk@7.18.4": + version "7.18.4" + resolved "https://registry.npmjs.org/@zowe/secrets-for-zowe-sdk/-/secrets-for-zowe-sdk-7.18.4.tgz#b755a063217a45bdffffb8d21c30afaad136b08c" + integrity sha512-eeVYZ+s9OlgqnHVVopJj3Bz4Ir6gDos5ZiT9Zf+gB6DQaeHFyvC4a2JZrLu9bEMAiVyiCTJydRaspcN4xoEi9Q== "@zowe/zos-console-for-zowe-sdk@7.18.0": version "7.18.0" @@ -412,14 +412,12 @@ resolved "https://registry.npmjs.org/@zowe/zosmf-for-zowe-sdk/-/zosmf-for-zowe-sdk-7.18.0.tgz#1d7be74dae8a7844386a50b3b581046dd8febe2c" integrity sha512-rrk/fQEOb7izgZnlsxFcniuY+NZaDZPDI90/ePzdWSQZPeA1lzq42Wzww9KXMpnZa3sliXXe9qfLBnrCnZYCbg== -"@zowe/zowe-explorer-api@^2.10.0": - version "2.10.0" - resolved "https://registry.npmjs.org/@zowe/zowe-explorer-api/-/zowe-explorer-api-2.10.0.tgz#a015dfb5dfb47549b86fc13359e9116cd150f39a" - integrity sha512-wx/IikaoMYWD/MCkSlSAGcDVC9JopF7jh321cTNRn/sAWpvBxVywaQ9YQniKZ9ADy6FyDIOR8/gTWLb47TElrQ== +"@zowe/zowe-explorer-api@file:../../packages/zowe-explorer-api": + version "2.12.0-SNAPSHOT" dependencies: "@types/vscode" "^1.53.2" "@zowe/cli" "^7.18.0" - "@zowe/secrets-for-zowe-sdk" "7.18.1" + "@zowe/secrets-for-zowe-sdk" "7.18.4" handlebars "^4.7.7" semver "^7.5.3" diff --git a/samples/tree-view-sample/package.json b/samples/tree-view-sample/package.json index 51b609d4d2..eb7d9a00dc 100644 --- a/samples/tree-view-sample/package.json +++ b/samples/tree-view-sample/package.json @@ -50,7 +50,7 @@ }, "dependencies": { "@zowe/imperative": "^5.18.0", - "@zowe/zowe-explorer-api": "^2.10.0" + "@zowe/zowe-explorer-api": "file:../../packages/zowe-explorer-api" }, "devDependencies": { "@types/node": "^16.18.34", diff --git a/samples/tree-view-sample/yarn.lock b/samples/tree-view-sample/yarn.lock index 1c2c866b6a..5d8538b3b9 100644 --- a/samples/tree-view-sample/yarn.lock +++ b/samples/tree-view-sample/yarn.lock @@ -356,10 +356,10 @@ resolved "https://registry.npmjs.org/@zowe/secrets-for-zowe-sdk/-/secrets-for-zowe-sdk-7.18.0.tgz#d7974ac234e79ce220e15fc4f7f17d880754b739" integrity sha512-lWs7oVjXpotWw8bu4NxPszu+MiTJgzdiYgj/0q0OBYLJdoZtKBTGRSohtoLZWpu6mfObiEICI1k8UDE8v7xbPw== -"@zowe/secrets-for-zowe-sdk@7.18.1": - version "7.18.1" - resolved "https://registry.npmjs.org/@zowe/secrets-for-zowe-sdk/-/secrets-for-zowe-sdk-7.18.1.tgz#546a63f5ed880418f0e0496d0218c284c815c3ee" - integrity sha512-bcAnauDpTQXCPT8rMx2wrZwhg6xih1lDujG20h1sUGJC5eqvsNCq6gvpOtcahEpUF25oBJ931dKlIu1T99LQ7w== +"@zowe/secrets-for-zowe-sdk@7.18.4": + version "7.18.4" + resolved "https://registry.npmjs.org/@zowe/secrets-for-zowe-sdk/-/secrets-for-zowe-sdk-7.18.4.tgz#b755a063217a45bdffffb8d21c30afaad136b08c" + integrity sha512-eeVYZ+s9OlgqnHVVopJj3Bz4Ir6gDos5ZiT9Zf+gB6DQaeHFyvC4a2JZrLu9bEMAiVyiCTJydRaspcN4xoEi9Q== "@zowe/zos-console-for-zowe-sdk@7.18.0": version "7.18.0" @@ -412,14 +412,12 @@ resolved "https://registry.npmjs.org/@zowe/zosmf-for-zowe-sdk/-/zosmf-for-zowe-sdk-7.18.0.tgz#1d7be74dae8a7844386a50b3b581046dd8febe2c" integrity sha512-rrk/fQEOb7izgZnlsxFcniuY+NZaDZPDI90/ePzdWSQZPeA1lzq42Wzww9KXMpnZa3sliXXe9qfLBnrCnZYCbg== -"@zowe/zowe-explorer-api@^2.10.0": - version "2.10.0" - resolved "https://registry.npmjs.org/@zowe/zowe-explorer-api/-/zowe-explorer-api-2.10.0.tgz#a015dfb5dfb47549b86fc13359e9116cd150f39a" - integrity sha512-wx/IikaoMYWD/MCkSlSAGcDVC9JopF7jh321cTNRn/sAWpvBxVywaQ9YQniKZ9ADy6FyDIOR8/gTWLb47TElrQ== +"@zowe/zowe-explorer-api@file:../../packages/zowe-explorer-api": + version "2.12.0-SNAPSHOT" dependencies: "@types/vscode" "^1.53.2" "@zowe/cli" "^7.18.0" - "@zowe/secrets-for-zowe-sdk" "7.18.1" + "@zowe/secrets-for-zowe-sdk" "7.18.4" handlebars "^4.7.7" semver "^7.5.3" diff --git a/samples/uss-profile-sample/package.json b/samples/uss-profile-sample/package.json index 248f3010d4..956ffb9893 100644 --- a/samples/uss-profile-sample/package.json +++ b/samples/uss-profile-sample/package.json @@ -34,7 +34,7 @@ }, "dependencies": { "@zowe/cli": "^7.18.0", - "@zowe/zowe-explorer-api": "^2.10.0", + "@zowe/zowe-explorer-api": "file:../../packages/zowe-explorer-api", "ssh2-sftp-client": "^9.1.0" }, "devDependencies": { diff --git a/samples/uss-profile-sample/yarn.lock b/samples/uss-profile-sample/yarn.lock index 13c14c0656..91dfa9747f 100644 --- a/samples/uss-profile-sample/yarn.lock +++ b/samples/uss-profile-sample/yarn.lock @@ -375,10 +375,10 @@ resolved "https://registry.npmjs.org/@zowe/secrets-for-zowe-sdk/-/secrets-for-zowe-sdk-7.18.0.tgz#d7974ac234e79ce220e15fc4f7f17d880754b739" integrity sha512-lWs7oVjXpotWw8bu4NxPszu+MiTJgzdiYgj/0q0OBYLJdoZtKBTGRSohtoLZWpu6mfObiEICI1k8UDE8v7xbPw== -"@zowe/secrets-for-zowe-sdk@7.18.1": - version "7.18.1" - resolved "https://registry.npmjs.org/@zowe/secrets-for-zowe-sdk/-/secrets-for-zowe-sdk-7.18.1.tgz#546a63f5ed880418f0e0496d0218c284c815c3ee" - integrity sha512-bcAnauDpTQXCPT8rMx2wrZwhg6xih1lDujG20h1sUGJC5eqvsNCq6gvpOtcahEpUF25oBJ931dKlIu1T99LQ7w== +"@zowe/secrets-for-zowe-sdk@7.18.4": + version "7.18.4" + resolved "https://registry.npmjs.org/@zowe/secrets-for-zowe-sdk/-/secrets-for-zowe-sdk-7.18.4.tgz#b755a063217a45bdffffb8d21c30afaad136b08c" + integrity sha512-eeVYZ+s9OlgqnHVVopJj3Bz4Ir6gDos5ZiT9Zf+gB6DQaeHFyvC4a2JZrLu9bEMAiVyiCTJydRaspcN4xoEi9Q== "@zowe/zos-console-for-zowe-sdk@7.18.0": version "7.18.0" @@ -431,14 +431,12 @@ resolved "https://registry.npmjs.org/@zowe/zosmf-for-zowe-sdk/-/zosmf-for-zowe-sdk-7.18.0.tgz#1d7be74dae8a7844386a50b3b581046dd8febe2c" integrity sha512-rrk/fQEOb7izgZnlsxFcniuY+NZaDZPDI90/ePzdWSQZPeA1lzq42Wzww9KXMpnZa3sliXXe9qfLBnrCnZYCbg== -"@zowe/zowe-explorer-api@^2.10.0": - version "2.10.0" - resolved "https://registry.npmjs.org/@zowe/zowe-explorer-api/-/zowe-explorer-api-2.10.0.tgz#a015dfb5dfb47549b86fc13359e9116cd150f39a" - integrity sha512-wx/IikaoMYWD/MCkSlSAGcDVC9JopF7jh321cTNRn/sAWpvBxVywaQ9YQniKZ9ADy6FyDIOR8/gTWLb47TElrQ== +"@zowe/zowe-explorer-api@file:../../packages/zowe-explorer-api": + version "2.12.0-SNAPSHOT" dependencies: "@types/vscode" "^1.53.2" "@zowe/cli" "^7.18.0" - "@zowe/secrets-for-zowe-sdk" "7.18.1" + "@zowe/secrets-for-zowe-sdk" "7.18.4" handlebars "^4.7.7" semver "^7.5.3" diff --git a/samples/vue-webview-sample/package.json b/samples/vue-webview-sample/package.json index 40a2294ecc..d400e9786b 100644 --- a/samples/vue-webview-sample/package.json +++ b/samples/vue-webview-sample/package.json @@ -27,7 +27,7 @@ "watch": "npx tsc -watch -p ./" }, "dependencies": { - "@zowe/zowe-explorer-api": "^2.10.0" + "@zowe/zowe-explorer-api": "file:../../packages/zowe-explorer-api" }, "devDependencies": { "@types/node": "^16.18.41", diff --git a/samples/vue-webview-sample/yarn.lock b/samples/vue-webview-sample/yarn.lock index 0e9aad212f..cf594255b8 100644 --- a/samples/vue-webview-sample/yarn.lock +++ b/samples/vue-webview-sample/yarn.lock @@ -434,10 +434,10 @@ resolved "https://registry.npmjs.org/@zowe/secrets-for-zowe-sdk/-/secrets-for-zowe-sdk-7.18.0.tgz#d7974ac234e79ce220e15fc4f7f17d880754b739" integrity sha512-lWs7oVjXpotWw8bu4NxPszu+MiTJgzdiYgj/0q0OBYLJdoZtKBTGRSohtoLZWpu6mfObiEICI1k8UDE8v7xbPw== -"@zowe/secrets-for-zowe-sdk@7.18.1": - version "7.18.1" - resolved "https://registry.npmjs.org/@zowe/secrets-for-zowe-sdk/-/secrets-for-zowe-sdk-7.18.1.tgz#546a63f5ed880418f0e0496d0218c284c815c3ee" - integrity sha512-bcAnauDpTQXCPT8rMx2wrZwhg6xih1lDujG20h1sUGJC5eqvsNCq6gvpOtcahEpUF25oBJ931dKlIu1T99LQ7w== +"@zowe/secrets-for-zowe-sdk@7.18.4": + version "7.18.4" + resolved "https://registry.npmjs.org/@zowe/secrets-for-zowe-sdk/-/secrets-for-zowe-sdk-7.18.4.tgz#b755a063217a45bdffffb8d21c30afaad136b08c" + integrity sha512-eeVYZ+s9OlgqnHVVopJj3Bz4Ir6gDos5ZiT9Zf+gB6DQaeHFyvC4a2JZrLu9bEMAiVyiCTJydRaspcN4xoEi9Q== "@zowe/zos-console-for-zowe-sdk@7.18.0": version "7.18.0" @@ -490,14 +490,12 @@ resolved "https://registry.npmjs.org/@zowe/zosmf-for-zowe-sdk/-/zosmf-for-zowe-sdk-7.18.0.tgz#1d7be74dae8a7844386a50b3b581046dd8febe2c" integrity sha512-rrk/fQEOb7izgZnlsxFcniuY+NZaDZPDI90/ePzdWSQZPeA1lzq42Wzww9KXMpnZa3sliXXe9qfLBnrCnZYCbg== -"@zowe/zowe-explorer-api@^2.10.0": - version "2.10.0" - resolved "https://registry.npmjs.org/@zowe/zowe-explorer-api/-/zowe-explorer-api-2.10.0.tgz#a015dfb5dfb47549b86fc13359e9116cd150f39a" - integrity sha512-wx/IikaoMYWD/MCkSlSAGcDVC9JopF7jh321cTNRn/sAWpvBxVywaQ9YQniKZ9ADy6FyDIOR8/gTWLb47TElrQ== +"@zowe/zowe-explorer-api@file:../../packages/zowe-explorer-api": + version "2.12.0-SNAPSHOT" dependencies: "@types/vscode" "^1.53.2" "@zowe/cli" "^7.18.0" - "@zowe/secrets-for-zowe-sdk" "7.18.1" + "@zowe/secrets-for-zowe-sdk" "7.18.4" handlebars "^4.7.7" semver "^7.5.3" From 2a214965cceedfd748385eeae82be4d539f32a46 Mon Sep 17 00:00:00 2001 From: Timothy Johnson Date: Mon, 2 Oct 2023 08:24:25 -0400 Subject: [PATCH 065/189] Build ZE API in samples workflow Signed-off-by: Timothy Johnson --- .github/workflows/zowe-explorer-samples.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/zowe-explorer-samples.yml b/.github/workflows/zowe-explorer-samples.yml index 5a0c6bec12..d18ad85f9f 100644 --- a/.github/workflows/zowe-explorer-samples.yml +++ b/.github/workflows/zowe-explorer-samples.yml @@ -41,5 +41,7 @@ jobs: # install yarn - run: npm install -g yarn + - run: yarn config set network-timeout 60000 && yarn install --frozen-lockfile + - run: for dir in samples/*; do pushd $dir && yarn && yarn run compile && popd; done shell: bash From ef4c4bba113b85c25062bda65cb2cac989835738 Mon Sep 17 00:00:00 2001 From: Rudy Flores <68666202+rudyflores@users.noreply.github.com> Date: Mon, 2 Oct 2023 10:12:58 -0400 Subject: [PATCH 066/189] update description of webviews creation function Signed-off-by: Rudy Flores <68666202+rudyflores@users.noreply.github.com> --- packages/zowe-explorer-api/src/vscode/ui/WebView.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/zowe-explorer-api/src/vscode/ui/WebView.ts b/packages/zowe-explorer-api/src/vscode/ui/WebView.ts index a37c95f52d..558ab3d3c5 100644 --- a/packages/zowe-explorer-api/src/vscode/ui/WebView.ts +++ b/packages/zowe-explorer-api/src/vscode/ui/WebView.ts @@ -36,10 +36,10 @@ export class WebView { /** * Constructs a webview for use with bundled assets. - * The webview entrypoint must be located at /dist/assets/index.js. + * The webview entrypoint must be located at src//dist//index.js. * * @param title The title for the new webview - * @param webviewName The directory name (relative to the "webviews" folder in the extension root) with a valid entrypoint (see above). + * @param webviewName The webview name, the same name given to the directory of your webview in the webviews/src directory. * @param context The VSCode extension context * @param onDidReceiveMessage Event callback: called when messages are received from the webview */ From 1beddfb799e5a0b96c1e21d3fccf11bcdb429bf7 Mon Sep 17 00:00:00 2001 From: Likhitha Nimma Date: Mon, 2 Oct 2023 19:43:00 +0530 Subject: [PATCH 067/189] checked whether array is valid Signed-off-by: Likhitha Nimma --- packages/zowe-explorer/src/ZoweExplorerExtender.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/zowe-explorer/src/ZoweExplorerExtender.ts b/packages/zowe-explorer/src/ZoweExplorerExtender.ts index dd16135445..6dd235aa7a 100644 --- a/packages/zowe-explorer/src/ZoweExplorerExtender.ts +++ b/packages/zowe-explorer/src/ZoweExplorerExtender.ts @@ -191,7 +191,7 @@ export class ZoweExplorerExtender implements ZoweExplorerApi.IApiExplorerExtende }); } } - Profiles.getInstance().addToConfigArray(profileTypeConfigurations); + if (profileTypeConfigurations !== undefined) Profiles.getInstance().addToConfigArray(profileTypeConfigurations); // sequentially reload the internal profiles cache to satisfy all the newly added profile types await ZoweExplorerExtender.refreshProfilesQueue.add(async (): Promise => { From fdace6e445eda9c153a7841b4e39af2b75c6deeb Mon Sep 17 00:00:00 2001 From: Billie Simmons <49491949+JillieBeanSim@users.noreply.github.com> Date: Mon, 2 Oct 2023 10:28:17 -0400 Subject: [PATCH 068/189] address login feedback Signed-off-by: Billie Simmons <49491949+JillieBeanSim@users.noreply.github.com> --- packages/zowe-explorer/src/Profiles.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/zowe-explorer/src/Profiles.ts b/packages/zowe-explorer/src/Profiles.ts index 3c69c244e9..23d73b7e5d 100644 --- a/packages/zowe-explorer/src/Profiles.ts +++ b/packages/zowe-explorer/src/Profiles.ts @@ -1192,7 +1192,6 @@ export class Profiles extends ProfilesCache { } else { await this.loginWithBaseProfile(serviceProfile, loginTokenType, node); } - Gui.showMessage(localize("ssoLogin.successful", "Login to authentication service was successful.")); } catch (err) { const message = localize("ssoLogin.error", "Unable to log in with {0}. {1}", serviceProfile.name, err?.message); ZoweLogger.error(message); @@ -1297,6 +1296,7 @@ export class Profiles extends ProfilesCache { profile: { ...node.getProfile().profile, ...updBaseProfile }, }); } + Gui.showMessage(localize("ssoLogin.successful", "Login to authentication service was successful.")); } } @@ -1322,6 +1322,7 @@ export class Profiles extends ProfilesCache { profile: { ...node.getProfile().profile, ...session }, }); } + Gui.showMessage(localize("ssoLogin.successful", "Login to authentication service was successful.")); } private async getConfigLocationPrompt(action: string): Promise { From c22fb83c85fee127bc9bd63e290dd3a8ec14eb89 Mon Sep 17 00:00:00 2001 From: Rudy Flores <68666202+rudyflores@users.noreply.github.com> Date: Mon, 2 Oct 2023 12:26:04 -0400 Subject: [PATCH 069/189] concurrently fix for windows users Signed-off-by: Rudy Flores <68666202+rudyflores@users.noreply.github.com> --- packages/zowe-explorer/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/zowe-explorer/package.json b/packages/zowe-explorer/package.json index 7405bf79f7..2c95e16902 100644 --- a/packages/zowe-explorer/package.json +++ b/packages/zowe-explorer/package.json @@ -1963,7 +1963,7 @@ "updateStrings": "node ../../scripts/stringUpdateScript.js && prettier --write --loglevel warn ./i18n package.nls*", "package": "vsce package --allow-star-activation --yarn && node ../../scripts/mv-pack.js vscode-extension-for-zowe vsix", "license": "node ../../scripts/updateLicenses.js", - "watch": "concurrently 'yarn run watch:webviews' 'yarn run watch:zowe-explorer'", + "watch": "concurrently -n \"yarn run watch:webviews\" \"yarn run watch:zowe-explorer\"", "watch:zowe-explorer": "gulp build && webpack --mode development --watch --info-verbosity verbose", "watch:webviews": "yarn workspace webviews dev", "compile": "tsc -b", From 71cd777833bdd7fd24c6af196e895b2fe81a3d5b Mon Sep 17 00:00:00 2001 From: Billie Simmons <49491949+JillieBeanSim@users.noreply.github.com> Date: Mon, 2 Oct 2023 13:51:35 -0400 Subject: [PATCH 070/189] move enable, disable, and delete to quickpick Signed-off-by: Billie Simmons <49491949+JillieBeanSim@users.noreply.github.com> --- .../__tests__/__theia__/theia/Locators.ts | 2 + .../__theia__/theia/extension.theiaChrome.ts | 12 +- .../i18n/sample/src/Profiles.i18n.json | 2 +- .../src/utils/ProfileManagement.i18n.json | 6 + packages/zowe-explorer/package.json | 45 -------- .../src/utils/ProfileManagement.ts | 104 +++++++++++++++--- 6 files changed, 108 insertions(+), 63 deletions(-) diff --git a/packages/zowe-explorer/__tests__/__theia__/theia/Locators.ts b/packages/zowe-explorer/__tests__/__theia__/theia/Locators.ts index 2b8793dba2..5e3eb996bc 100644 --- a/packages/zowe-explorer/__tests__/__theia__/theia/Locators.ts +++ b/packages/zowe-explorer/__tests__/__theia__/theia/Locators.ts @@ -44,6 +44,7 @@ export const UssLocators = { addToFavoriteOptionXpath: "//li[@data-command='zowe.uss.addFavorite']", removeFavoriteProfileFromUssOptionXpath: "//li[@data-command='zowe.uss.removeFavProfile']", hideProfileFromUssOptionXpath: "//li[@data-command='zowe.uss.removeSession']", + manageProfileFromUnixXpath: "(//li[@data-command='zowe.profileManagement'])", }; export const JobsLocators = { @@ -60,6 +61,7 @@ export const JobsLocators = { removeFavoriteProfileFromJobsOptionXpath: "//li[@data-command='zowe.jobs.removeFavProfile']", hideProfileFromJobsOptionXpath: "//li[@data-command='zowe.jobs.removeJobsSession']", secondJobsProfileBeforeHidingXpath: "(//div[contains(@id,'TestSeleniumProfile')])[2]", + manageProfileFromJobsXpath: "(//li[@data-command='zowe.profileManagement'])", }; export const TheiaNotificationMessages = { diff --git a/packages/zowe-explorer/__tests__/__theia__/theia/extension.theiaChrome.ts b/packages/zowe-explorer/__tests__/__theia__/theia/extension.theiaChrome.ts index 7d79c7eb9b..239aadb46a 100644 --- a/packages/zowe-explorer/__tests__/__theia__/theia/extension.theiaChrome.ts +++ b/packages/zowe-explorer/__tests__/__theia__/theia/extension.theiaChrome.ts @@ -138,13 +138,21 @@ export async function addProfileToFavoritesInJobs() { export async function hideProfileInUss() { const hideProfileFromUss = await driverChrome.wait(until.elementLocated(By.xpath(UssLocators.secondUssProfileXpath)), WAITTIME); await driverChrome.actions().click(hideProfileFromUss, Button.RIGHT).perform(); - await driverChrome.wait(until.elementLocated(By.xpath(UssLocators.hideProfileFromUssOptionXpath)), WAITTIME).click(); + driverChrome.wait(until.elementLocated(By.xpath(UssLocators.manageProfileFromUnixXpath)), WAITTIME).click(); + await driverChrome.sleep(SHORTSLEEPTIME); + const manageProfile = driverChrome.wait(until.elementLocated(By.xpath(UssLocators.emptyInputBoxXpath)), WAITTIME); + manageProfile.sendKeys("Hide Profile"); + manageProfile.sendKeys(Key.ENTER); } export async function hideProfileInJobs() { const hideProfileFromJobs = await driverChrome.wait(until.elementLocated(By.xpath(JobsLocators.secondJobsProfileBeforeHidingXpath)), WAITTIME); await driverChrome.actions().click(hideProfileFromJobs, Button.RIGHT).perform(); - await driverChrome.wait(until.elementLocated(By.xpath(JobsLocators.hideProfileFromJobsOptionXpath)), WAITTIME).click(); + driverChrome.wait(until.elementLocated(By.xpath(JobsLocators.manageProfileFromJobsXpath)), WAITTIME).click(); + await driverChrome.sleep(SHORTSLEEPTIME); + const manageProfile = driverChrome.wait(until.elementLocated(By.xpath(JobsLocators.emptyInputBoxXpath)), WAITTIME); + manageProfile.sendKeys("Hide Profile"); + manageProfile.sendKeys(Key.ENTER); } export async function verifyProfileIsHideInUss() { diff --git a/packages/zowe-explorer/i18n/sample/src/Profiles.i18n.json b/packages/zowe-explorer/i18n/sample/src/Profiles.i18n.json index 57a7772513..a7bdfe81e4 100644 --- a/packages/zowe-explorer/i18n/sample/src/Profiles.i18n.json +++ b/packages/zowe-explorer/i18n/sample/src/Profiles.i18n.json @@ -29,10 +29,10 @@ "validateProfiles.error": "Profile validation failed for {0}.", "ssoAuth.usingBasicAuth": "This profile is using basic authentication and does not support token authentication.", "ssoLogin.tokenType.error": "Error getting supported tokenType value for profile {0}", - "ssoLogin.successful": "Login to authentication service was successful.", "ssoLogin.error": "Unable to log in with {0}. {1}", "ssoLogout.successful": "Logout from authentication service was successful for {0}.", "ssoLogout.error": "Unable to log out with {0}. {1}", + "ssoLogin.successful": "Login to authentication service was successful.", "getConfigLocationPrompt.placeholder.create": "Select the location where the config file will be initialized", "getConfigLocationPrompt.placeholder.edit": "Select the location of the config file to edit", "getConfigLocationPrompt.showQuickPick.global": "Global: in the Zowe home directory", diff --git a/packages/zowe-explorer/i18n/sample/src/utils/ProfileManagement.i18n.json b/packages/zowe-explorer/i18n/sample/src/utils/ProfileManagement.i18n.json index 0b0107edb9..56776e1f3b 100644 --- a/packages/zowe-explorer/i18n/sample/src/utils/ProfileManagement.i18n.json +++ b/packages/zowe-explorer/i18n/sample/src/utils/ProfileManagement.i18n.json @@ -8,8 +8,14 @@ "updateBasicAuthQpItem.updateCredentials.qpLabel": "$(refresh) Update Credentials", "updateBasicAuthQpItem.updateCredentials.qpDetail": "Update stored username and password", "deleteProfileQpItem.delete.qpLabel": "$(trash) Delete Profile", + "disableProfileValildationQpItem.disableValidation.qpLabel": "$(workspace-untrusted) Disable Profile Validation", + "disableProfileValildationQpItem.disableValidation.qpDetail": "Disable validation of server check for profile.", + "enableProfileValildationQpItem.enableValidation.qpLabel": "$(workspace-trusted) Enable Profile Validation", + "enableProfileValildationQpItem.enableValidation.qpDetail": "Enable validation of server check for profile.", "editProfileQpItem.editProfile.qpLabel": "$(pencil) Edit Profile", "editProfileQpItem.editProfile.qpDetail": "Update profile connection information", + "hideProfileQpItems.hideProfile.qpLabel": "$(eye-closed) Hide Profile", + "hideProfileQpItems.hideProfile.qpDetail": "Hide profile name from tree view.", "loginQpItem.login.qpLabel": "$(arrow-right) Log in to authentication service", "loginQpItem.login.qpDetail": "Log in to obtain a new token value", "logoutQpItem.logout.qpLabel": "$(arrow-left) Log out of authentication service", diff --git a/packages/zowe-explorer/package.json b/packages/zowe-explorer/package.json index 398a82c58b..b50a2b6557 100644 --- a/packages/zowe-explorer/package.json +++ b/packages/zowe-explorer/package.json @@ -958,26 +958,11 @@ "command": "zowe.uss.deleteNode", "group": "099_zowe_ussModification:@4" }, - { - "when": "view == zowe.uss.explorer && viewItem =~ /_validate/ && !listMultiSelection", - "command": "zowe.uss.disableValidation", - "group": "099_zowe_ussProfileAuthentication@96" - }, - { - "when": "view == zowe.uss.explorer && viewItem =~ /_noValidate/ && !listMultiSelection", - "command": "zowe.uss.enableValidation", - "group": "099_zowe_ussProfileAuthentication@97" - }, { "when": "view == zowe.uss.explorer && viewItem =~ /^(?!.*_fav.*)ussSession.*/ && !listMultiSelection", "command": "zowe.profileManagement", "group": "099_zowe_ussProfileAuthentication@99" }, - { - "when": "viewItem =~ /^(?!.*_fav.*)ussSession.*/", - "command": "zowe.uss.removeSession", - "group": "099_zowe_ussProfileAuthentication@98" - }, { "when": "view == zowe.ds.explorer && viewItem =~ /^(?!.*_fav.*)session.*/ && !listMultiSelection", "command": "zowe.ds.pattern", @@ -1153,26 +1138,11 @@ "command": "zowe.ds.deleteDataset", "group": "099_zowe_dsModification@5" }, - { - "when": "view == zowe.ds.explorer && viewItem =~ /_validate/ && !listMultiSelection", - "command": "zowe.ds.disableValidation", - "group": "099_zowe_dsProfileAuthentication@96" - }, - { - "when": "view == zowe.ds.explorer && viewItem =~ /_noValidate/ && !listMultiSelection", - "command": "zowe.ds.enableValidation", - "group": "099_zowe_dsProfileAuthentication@97" - }, { "when": "view == zowe.ds.explorer && viewItem =~ /^(?!.*_fav.*)session.*/ && !listMultiSelection", "command": "zowe.profileManagement", "group": "099_zowe_dsProfileAuthentication@99" }, - { - "when": "view == zowe.ds.explorer && viewItem =~ /^(?!.*_fav.*)session.*/", - "command": "zowe.ds.removeSession", - "group": "099_zowe_dsProfileAuthentication@98" - }, { "when": "view == zowe.jobs.explorer && viewItem =~ /^(?!.*_fav.*)server.*/ && !listMultiSelection", "command": "zowe.jobs.search", @@ -1298,26 +1268,11 @@ "command": "zowe.jobs.cancelJob", "group": "099_zowe_jobsModification" }, - { - "when": "view == zowe.jobs.explorer && viewItem =~ /_validate/ && !listMultiSelection", - "command": "zowe.jobs.disableValidation", - "group": "099_zowe_jobsProfileAuthentication@96" - }, - { - "when": "view == zowe.jobs.explorer && viewItem =~ /_noValidate/ && !listMultiSelection", - "command": "zowe.jobs.enableValidation", - "group": "099_zowe_jobsProfileAuthentication@97" - }, { "when": "view == zowe.jobs.explorer && viewItem =~ /^(?!.*_fav.*)server.*/ && !listMultiSelection", "command": "zowe.profileManagement", "group": "099_zowe_jobsProfileAuthentication@99" }, - { - "when": "view == zowe.jobs.explorer && viewItem =~ /^(?!.*_fav.*)server.*/", - "command": "zowe.jobs.removeJobsSession", - "group": "099_zowe_jobsProfileAuthentication@98" - }, { "when": "view == zowe.jobs.explorer && viewItem =~ /^(?!.*_fav.*)server.*/ && !listMultiSelection", "command": "zowe.jobs.sortbyid", diff --git a/packages/zowe-explorer/src/utils/ProfileManagement.ts b/packages/zowe-explorer/src/utils/ProfileManagement.ts index b72838721e..55a2f57eae 100644 --- a/packages/zowe-explorer/src/utils/ProfileManagement.ts +++ b/packages/zowe-explorer/src/utils/ProfileManagement.ts @@ -10,12 +10,14 @@ */ import * as vscode from "vscode"; +import * as globals from "../globals"; import { Gui, IZoweTreeNode, imperative } from "@zowe/zowe-explorer-api"; import { ZoweLogger } from "./LoggerUtils"; import { ProfilesUtils } from "./ProfilesUtils"; import * as nls from "vscode-nls"; import { Profiles } from "../Profiles"; import { ZoweExplorerApiRegister } from "../ZoweExplorerApiRegister"; +import { isZoweDatasetTreeNode, isZoweUSSTreeNode } from "../shared/utils"; // Set up localization nls.config({ @@ -31,18 +33,18 @@ export class ProfileManagement { switch (true) { case ProfilesUtils.isProfileUsingBasicAuth(profile): { ZoweLogger.debug(`Profile ${profile.name} is using basic authentication.`); - selected = await this.setupProfileManagementQp(imperative.SessConstants.AUTH_TYPE_BASIC, profile); + selected = await this.setupProfileManagementQp(imperative.SessConstants.AUTH_TYPE_BASIC, node); break; } case await ProfilesUtils.isUsingTokenAuth(profile.name): { ZoweLogger.debug(`Profile ${profile.name} is using token authentication.`); - selected = await this.setupProfileManagementQp("token", profile); + selected = await this.setupProfileManagementQp("token", node); break; } // will need a case for isUsingCertAuth default: { ZoweLogger.debug(`Profile ${profile.name} authentication method is unkown.`); - selected = await this.setupProfileManagementQp(null, profile); + selected = await this.setupProfileManagementQp(null, node); break; } } @@ -50,8 +52,11 @@ export class ProfileManagement { } public static AuthQpLabels = { add: "add-credentials", - delete: "delete", + delete: "delete-profile", + disable: "disable-validation", edit: "edit-profile", + enable: "enable-validation", + hide: "hide-profile", login: "obtain-token", logout: "invalidate-token", update: "update-credentials", @@ -73,12 +78,30 @@ export class ProfileManagement { label: localize("deleteProfileQpItem.delete.qpLabel", "$(trash) Delete Profile"), }, }; + public static disableProfileValildationQpItem: Record = { + [this.AuthQpLabels.disable]: { + label: localize("disableProfileValildationQpItem.disableValidation.qpLabel", "$(workspace-untrusted) Disable Profile Validation"), + description: localize("disableProfileValildationQpItem.disableValidation.qpDetail", "Disable validation of server check for profile."), + }, + }; + public static enableProfileValildationQpItem: Record = { + [this.AuthQpLabels.enable]: { + label: localize("enableProfileValildationQpItem.enableValidation.qpLabel", "$(workspace-trusted) Enable Profile Validation"), + description: localize("enableProfileValildationQpItem.enableValidation.qpDetail", "Enable validation of server check for profile."), + }, + }; public static editProfileQpItems: Record = { [this.AuthQpLabels.edit]: { label: localize("editProfileQpItem.editProfile.qpLabel", "$(pencil) Edit Profile"), description: localize("editProfileQpItem.editProfile.qpDetail", "Update profile connection information"), }, }; + public static hideProfileQpItems: Record = { + [this.AuthQpLabels.hide]: { + label: localize("hideProfileQpItems.hideProfile.qpLabel", "$(eye-closed) Hide Profile"), + description: localize("hideProfileQpItems.hideProfile.qpDetail", "Hide profile name from tree view."), + }, + }; public static tokenAuthLoginQpItem: Record = { [this.AuthQpLabels.login]: { label: localize("loginQpItem.login.qpLabel", "$(arrow-right) Log in to authentication service"), @@ -91,23 +114,24 @@ export class ProfileManagement { description: localize("logoutQpItem.logout.qpDetail", "Log out to invalidate and remove stored token value"), }, }; - private static async setupProfileManagementQp(managementType: string, profile: imperative.IProfileLoaded): Promise { + private static async setupProfileManagementQp(managementType: string, node: IZoweTreeNode): Promise { + const profile = node.getProfile(); const qp = Gui.createQuickPick(); let quickPickOptions: vscode.QuickPickItem[]; const placeholders = this.getQpPlaceholders(profile); switch (managementType) { case imperative.SessConstants.AUTH_TYPE_BASIC: { - quickPickOptions = this.basicAuthQp(); + quickPickOptions = this.basicAuthQp(node); qp.placeholder = placeholders.basicAuth; break; } case "token": { - quickPickOptions = this.tokenAuthQp(profile); + quickPickOptions = this.tokenAuthQp(node); qp.placeholder = placeholders.tokenAuth; break; } default: { - quickPickOptions = this.chooseAuthQp(profile); + quickPickOptions = this.chooseAuthQp(node); qp.placeholder = placeholders.chooseAuth; break; } @@ -142,10 +166,22 @@ export class ProfileManagement { await ProfilesUtils.promptCredentials(node); break; } + case this.hideProfileQpItems[this.AuthQpLabels.hide]: { + await this.handleHideProfiles(node); + break; + } case this.deleteProfileQpItem[this.AuthQpLabels.delete]: { await this.handleDeleteProfiles(node); break; } + case this.enableProfileValildationQpItem[this.AuthQpLabels.enable]: { + await this.handleEnableProfileValidation(node); + break; + } + case this.disableProfileValildationQpItem[this.AuthQpLabels.disable]: { + await this.handleDisableProfileValidation(node); + break; + } default: { Gui.infoMessage(localize("profiles.operation.cancelled", "Operation Cancelled")); break; @@ -165,18 +201,20 @@ export class ProfileManagement { }; } - private static basicAuthQp(): vscode.QuickPickItem[] { + private static basicAuthQp(node: IZoweTreeNode): vscode.QuickPickItem[] { const quickPickOptions: vscode.QuickPickItem[] = Object.values(this.basicAuthUpdateQpItems); - return this.addFinalQpOptions(quickPickOptions); + return this.addFinalQpOptions(node, quickPickOptions); } - private static tokenAuthQp(profile: imperative.IProfileLoaded): vscode.QuickPickItem[] { + private static tokenAuthQp(node: IZoweTreeNode): vscode.QuickPickItem[] { + const profile = node.getProfile(); const quickPickOptions: vscode.QuickPickItem[] = Object.values(this.tokenAuthLoginQpItem); if (profile.profile.tokenType) { quickPickOptions.push(this.tokenAuthLogoutQpItem[this.AuthQpLabels.logout]); } - return this.addFinalQpOptions(quickPickOptions); + return this.addFinalQpOptions(node, quickPickOptions); } - private static chooseAuthQp(profile: imperative.IProfileLoaded): vscode.QuickPickItem[] { + private static chooseAuthQp(node: IZoweTreeNode): vscode.QuickPickItem[] { + const profile = node.getProfile(); const quickPickOptions: vscode.QuickPickItem[] = Object.values(this.basicAuthAddQpItems); try { ZoweExplorerApiRegister.getInstance().getCommonApi(profile).getTokenTypeName(); @@ -184,10 +222,16 @@ export class ProfileManagement { } catch { ZoweLogger.debug(`Profile ${profile.name} doesn't support token authentication, will not provide option.`); } - return this.addFinalQpOptions(quickPickOptions); + return this.addFinalQpOptions(node, quickPickOptions); } - private static addFinalQpOptions(quickPickOptions: vscode.QuickPickItem[]): vscode.QuickPickItem[] { + private static addFinalQpOptions(node: IZoweTreeNode, quickPickOptions: vscode.QuickPickItem[]): vscode.QuickPickItem[] { + if (node.contextValue.includes(globals.NO_VALIDATE_SUFFIX)) { + quickPickOptions.push(this.enableProfileValildationQpItem[this.AuthQpLabels.enable]); + } else { + quickPickOptions.push(this.disableProfileValildationQpItem[this.AuthQpLabels.disable]); + } quickPickOptions.push(this.editProfileQpItems[this.AuthQpLabels.edit]); + quickPickOptions.push(this.hideProfileQpItems[this.AuthQpLabels.hide]); quickPickOptions.push(this.deleteProfileQpItem[this.AuthQpLabels.delete]); return quickPickOptions; } @@ -200,4 +244,34 @@ export class ProfileManagement { } await vscode.commands.executeCommand("zowe.ds.deleteProfile", node); } + + private static async handleHideProfiles(node: IZoweTreeNode): Promise { + if (isZoweDatasetTreeNode(node)) { + return vscode.commands.executeCommand("zowe.ds.removeSession", node); + } + if (isZoweUSSTreeNode(node)) { + return vscode.commands.executeCommand("zowe.uss.removeSession", node); + } + return vscode.commands.executeCommand("zowe.jobs.removeJobsSession", node); + } + + private static async handleEnableProfileValidation(node: IZoweTreeNode): Promise { + if (isZoweDatasetTreeNode(node)) { + return vscode.commands.executeCommand("zowe.ds.enableValidation", node); + } + if (isZoweUSSTreeNode(node)) { + return vscode.commands.executeCommand("zowe.uss.enableValidation", node); + } + return vscode.commands.executeCommand("zowe.jobs.enableValidation", node); + } + + private static async handleDisableProfileValidation(node: IZoweTreeNode): Promise { + if (isZoweDatasetTreeNode(node)) { + return vscode.commands.executeCommand("zowe.ds.disableValidation", node); + } + if (isZoweUSSTreeNode(node)) { + return vscode.commands.executeCommand("zowe.uss.disableValidation", node); + } + return vscode.commands.executeCommand("zowe.jobs.disableValidation", node); + } } From 00af76309c21583b9981be9aa0287976f80da7e8 Mon Sep 17 00:00:00 2001 From: Billie Simmons <49491949+JillieBeanSim@users.noreply.github.com> Date: Mon, 2 Oct 2023 18:35:28 -0400 Subject: [PATCH 071/189] add unit tests Signed-off-by: Billie Simmons <49491949+JillieBeanSim@users.noreply.github.com> --- .../utils/ProfileManagement.unit.test.ts | 61 ++++++++++++++++++- 1 file changed, 58 insertions(+), 3 deletions(-) diff --git a/packages/zowe-explorer/__tests__/__unit__/utils/ProfileManagement.unit.test.ts b/packages/zowe-explorer/__tests__/__unit__/utils/ProfileManagement.unit.test.ts index 44d605e0d4..2cd395f690 100644 --- a/packages/zowe-explorer/__tests__/__unit__/utils/ProfileManagement.unit.test.ts +++ b/packages/zowe-explorer/__tests__/__unit__/utils/ProfileManagement.unit.test.ts @@ -12,6 +12,7 @@ import { ZoweDatasetNode } from "../../../src/dataset/ZoweDatasetNode"; import * as sharedMock from "../../../__mocks__/mockCreators/shared"; import * as dsMock from "../../../__mocks__/mockCreators/datasets"; +import * as unixMock from "../../../__mocks__/mockCreators/uss"; import * as profUtils from "../../../src/utils/ProfilesUtils"; import { ProfileManagement } from "../../../src/utils/ProfileManagement"; import { Gui } from "@zowe/zowe-explorer-api"; @@ -19,6 +20,7 @@ import { ZoweLogger } from "../../../src/utils/LoggerUtils"; import { Profiles } from "../../../src/Profiles"; import * as vscode from "vscode"; import { imperative } from "@zowe/cli"; +import { ZoweUSSNode } from "../../../src/uss/ZoweUSSNode"; jest.mock("fs"); jest.mock("vscode"); @@ -36,6 +38,7 @@ describe("ProfileManagement unit tests", () => { mockNoAuthProfile: sharedMock.createNoAuthIProfile(), opCancelledSpy: jest.spyOn(Gui, "infoMessage"), mockDsSessionNode: ZoweDatasetNode, + mockUnixSessionNode: ZoweUSSNode, mockResolveQp: jest.fn(), mockCreateQp: jest.fn(), mockUpdateChosen: ProfileManagement.basicAuthUpdateQpItems[ProfileManagement.AuthQpLabels.update], @@ -44,6 +47,9 @@ describe("ProfileManagement unit tests", () => { mockLogoutChosen: ProfileManagement.tokenAuthLogoutQpItem[ProfileManagement.AuthQpLabels.logout], mockEditProfChosen: ProfileManagement.editProfileQpItems[ProfileManagement.AuthQpLabels.edit], mockDeleteProfChosen: ProfileManagement.deleteProfileQpItem[ProfileManagement.AuthQpLabels.delete], + mockHideProfChosen: ProfileManagement.hideProfileQpItems[ProfileManagement.AuthQpLabels.hide], + mockEnableValidationChosen: ProfileManagement.enableProfileValildationQpItem[ProfileManagement.AuthQpLabels.enable], + mockDisableValidationChosen: ProfileManagement.disableProfileValildationQpItem[ProfileManagement.AuthQpLabels.disable], mockProfileInfo: { usingTeamConfig: true }, mockProfileInstance: null as any, debugLogSpy: null as any, @@ -52,6 +58,7 @@ describe("ProfileManagement unit tests", () => { loginSpy: null as any, logoutSpy: null as any, logMsg: null as any, + commandSpy: null as any, }; Object.defineProperty(profUtils.ProfilesUtils, "promptCredentials", { value: jest.fn(), configurable: true }); newMocks.promptSpy = jest.spyOn(profUtils.ProfilesUtils, "promptCredentials"); @@ -82,6 +89,8 @@ describe("ProfileManagement unit tests", () => { newMocks.loginSpy = jest.spyOn(newMocks.mockProfileInstance, "ssoLogin"); Object.defineProperty(newMocks.mockProfileInstance, "ssoLogout", { value: jest.fn(), configurable: true }); newMocks.logoutSpy = jest.spyOn(newMocks.mockProfileInstance, "ssoLogout"); + Object.defineProperty(vscode.commands, "executeCommand", { value: jest.fn(), configurable: true }); + newMocks.commandSpy = jest.spyOn(vscode.commands, "executeCommand"); return newMocks; } @@ -90,7 +99,6 @@ describe("ProfileManagement unit tests", () => { function createBlockMocks(globalMocks): any { globalMocks.logMsg = `Profile ${globalMocks.mockBasicAuthProfile.name} is using basic authentication.`; globalMocks.mockDsSessionNode.getProfile = jest.fn().mockReturnValue(globalMocks.mockBasicAuthProfile); - Object.defineProperty(vscode.commands, "executeCommand", { value: jest.fn(), configurable: true }); return globalMocks; } it("profile using basic authentication should see Operation Cancelled when escaping quick pick", async () => { @@ -125,22 +133,34 @@ describe("ProfileManagement unit tests", () => { expect(mocks.debugLogSpy).toBeCalledWith(mocks.logMsg); expect(mocks.editSpy).toBeCalled(); }); + it("profile using basic authentication should see hide session command called for profile in data set tree view", async () => { + const mocks = createBlockMocks(createGlobalMocks()); + Object.defineProperty(mocks.mockProfileInstance, "getProfileInfo", { + value: jest.fn().mockResolvedValue(mocks.mockProfileInfo as imperative.ProfileInfo), + configurable: true, + }); + mocks.mockResolveQp.mockResolvedValueOnce(mocks.mockHideProfChosen); + await ProfileManagement.manageProfile(mocks.mockDsSessionNode); + expect(mocks.debugLogSpy).toBeCalledWith(mocks.logMsg); + expect(mocks.commandSpy).toHaveBeenLastCalledWith("zowe.ds.removeSession", mocks.mockDsSessionNode); + }); it("profile using basic authentication should see delete commands called when Delete Profile chosen with v1 profile", async () => { const mocks = createBlockMocks(createGlobalMocks()); mocks.mockResolveQp.mockResolvedValueOnce(mocks.mockDeleteProfChosen); mocks.mockProfileInfo.usingTeamConfig = false; - const commandSpy = jest.spyOn(vscode.commands, "executeCommand"); await ProfileManagement.manageProfile(mocks.mockDsSessionNode); expect(mocks.debugLogSpy).toBeCalledWith(mocks.logMsg); expect(mocks.editSpy).not.toBeCalled(); - expect(commandSpy).toBeCalled(); + expect(mocks.commandSpy).toHaveBeenLastCalledWith("zowe.ds.deleteProfile", mocks.mockDsSessionNode); }); }); describe("unit tests around token auth selections", () => { function createBlockMocks(globalMocks): any { globalMocks.logMsg = `Profile ${globalMocks.mockTokenAuthProfile.name} is using token authentication.`; + globalMocks.mockUnixSessionNode = unixMock.createUSSSessionNode(globalMocks.mockSession, globalMocks.mockBasicAuthProfile) as any; Object.defineProperty(profUtils.ProfilesUtils, "isUsingTokenAuth", { value: jest.fn().mockResolvedValueOnce(true), configurable: true }); globalMocks.mockDsSessionNode.getProfile = jest.fn().mockReturnValue(globalMocks.mockTokenAuthProfile); + globalMocks.mockUnixSessionNode.getProfile = jest.fn().mockReturnValue(globalMocks.mockTokenAuthProfile); return globalMocks; } it("profile using token authentication should see Operation Cancelled when escaping quick pick", async () => { @@ -164,6 +184,27 @@ describe("ProfileManagement unit tests", () => { expect(mocks.debugLogSpy).toBeCalledWith(mocks.logMsg); expect(mocks.logoutSpy).toBeCalled(); }); + it("profile using token authentication should see correct command called for hiding a unix tree session node", async () => { + const mocks = createBlockMocks(createGlobalMocks()); + mocks.mockResolveQp.mockResolvedValueOnce(mocks.mockHideProfChosen); + await ProfileManagement.manageProfile(mocks.mockUnixSessionNode); + expect(mocks.debugLogSpy).toBeCalledWith(mocks.logMsg); + expect(mocks.commandSpy).toHaveBeenLastCalledWith("zowe.uss.removeSession", mocks.mockUnixSessionNode); + }); + it("profile using token authentication should see correct command called for enabling validation a unix tree session node", async () => { + const mocks = createBlockMocks(createGlobalMocks()); + mocks.mockResolveQp.mockResolvedValueOnce(mocks.mockEnableValidationChosen); + await ProfileManagement.manageProfile(mocks.mockUnixSessionNode); + expect(mocks.debugLogSpy).toBeCalledWith(mocks.logMsg); + expect(mocks.commandSpy).toHaveBeenLastCalledWith("zowe.uss.enableValidation", mocks.mockUnixSessionNode); + }); + it("profile using token authentication should see correct command called for disabling validation a unix tree session node", async () => { + const mocks = createBlockMocks(createGlobalMocks()); + mocks.mockResolveQp.mockResolvedValueOnce(mocks.mockDisableValidationChosen); + await ProfileManagement.manageProfile(mocks.mockUnixSessionNode); + expect(mocks.debugLogSpy).toBeCalledWith(mocks.logMsg); + expect(mocks.commandSpy).toHaveBeenLastCalledWith("zowe.uss.disableValidation", mocks.mockUnixSessionNode); + }); }); describe("unit tests around no auth declared selections", () => { function createBlockMocks(globalMocks): any { @@ -200,5 +241,19 @@ describe("ProfileManagement unit tests", () => { expect(mocks.debugLogSpy).toBeCalledWith(mocks.logMsg); expect(mocks.editSpy).toBeCalled(); }); + it("profile using token authentication should see correct command called for enabling validation a data set tree session node", async () => { + const mocks = createBlockMocks(createGlobalMocks()); + mocks.mockResolveQp.mockResolvedValueOnce(mocks.mockEnableValidationChosen); + await ProfileManagement.manageProfile(mocks.mockDsSessionNode); + expect(mocks.debugLogSpy).toBeCalledWith(mocks.logMsg); + expect(mocks.commandSpy).toHaveBeenLastCalledWith("zowe.ds.enableValidation", mocks.mockDsSessionNode); + }); + it("profile using token authentication should see correct command called for disabling validation a data set tree session node", async () => { + const mocks = createBlockMocks(createGlobalMocks()); + mocks.mockResolveQp.mockResolvedValueOnce(mocks.mockDisableValidationChosen); + await ProfileManagement.manageProfile(mocks.mockDsSessionNode); + expect(mocks.debugLogSpy).toBeCalledWith(mocks.logMsg); + expect(mocks.commandSpy).toHaveBeenLastCalledWith("zowe.ds.disableValidation", mocks.mockDsSessionNode); + }); }); }); From abc276edc1603ffe0745088b245aca383214f010 Mon Sep 17 00:00:00 2001 From: Rudy Flores <68666202+rudyflores@users.noreply.github.com> Date: Tue, 3 Oct 2023 12:39:18 -0400 Subject: [PATCH 072/189] Update credential management flow Signed-off-by: Rudy Flores <68666202+rudyflores@users.noreply.github.com> --- .../i18n/sample/package.i18n.json | 1 + .../sample/src/utils/ProfilesUtils.i18n.json | 12 +- packages/zowe-explorer/package.json | 6 + packages/zowe-explorer/package.nls.json | 1 + .../zowe-explorer/src/ZoweExplorerExtender.ts | 2 +- packages/zowe-explorer/src/globals.ts | 1 + .../zowe-explorer/src/utils/ProfilesUtils.ts | 243 ++++++++++++++---- 7 files changed, 220 insertions(+), 46 deletions(-) diff --git a/packages/zowe-explorer/i18n/sample/package.i18n.json b/packages/zowe-explorer/i18n/sample/package.i18n.json index 8bc5d8bf6c..d20dc2e1fe 100644 --- a/packages/zowe-explorer/i18n/sample/package.i18n.json +++ b/packages/zowe-explorer/i18n/sample/package.i18n.json @@ -108,6 +108,7 @@ "zowe.pollInterval.info": "Default interval (in milliseconds) when polling spool files.", "zowe.separator.recentFilters": "Recent Filters", "zowe.settings.version": "Track if migration has been processed", + "zowe.security.checkForCustomCredentialManagers": "Check for any installed VS Code extensions for handling credentials when activating Zowe Explorer", "zowe.security.secureCredentialsEnabled": "Allow credentials to be stored securely. If disabled and autoStore is set to true, z/OS credentials are stored as clear text in zowe.config.json.", "issueTsoCmd": "Issue TSO Command", "deleteProfile": "Delete Profile", diff --git a/packages/zowe-explorer/i18n/sample/src/utils/ProfilesUtils.i18n.json b/packages/zowe-explorer/i18n/sample/src/utils/ProfilesUtils.i18n.json index 2ed2cbc4ff..d828603181 100644 --- a/packages/zowe-explorer/i18n/sample/src/utils/ProfilesUtils.i18n.json +++ b/packages/zowe-explorer/i18n/sample/src/utils/ProfilesUtils.i18n.json @@ -6,8 +6,16 @@ "errorHandling.checkCredentials.button": "Update Credentials", "errorHandling.checkCredentials.cancelled": "Operation Cancelled", "activateCredentialManagerOverride.failedToActivate": "Custom credential manager failed to activate", - "ProfilesUtils.getProfileInfo.usingCustom": "Custom credential manager found, attempting to activate.", - "ProfilesUtils.getProfileInfo.usingDefault": "No custom credential managers found, using the default instead.", + "ProfilesUtils.setupCustomCredentialManager.usingCustom": "Custom credential manager {0} found, attempting to activate.", + "ProfilesUtils.setupDefaultCredentialManager.usingDefault": "No custom credential managers found, using the default instead.", + "ProfilesUtils.promptAndHandleMissingCredentialManager.suggestInstallHeader": "Plugin of name \"{0}\" was defined for custom credential management on imperative.json file.", + "ProfilesUtils.promptAndHandleMissingCredentialManager.suggestInstallMessage": "Please install associated VS Code extension for\n custom credential manager or revert to default.", + "ProfilesUtils.promptAndHandleMissingCredentialManager.revertToDefault": "Use Default", + "ProfilesUtils.promptAndHandleMissingCredentialManager.install": "Install", + "ProfilesUtils.fetchRegisteredPlugins.customCredentialManagerFound": "Custom credential manager {0} found", + "ProfilesUtils.fetchRegisteredPlugins.message": "Do you wish to use this credential manager instead?", + "ProfilesUtils.fetchRegisteredPlugins.yes": "Yes", + "ProfilesUtils.fetchRegisteredPlugins.no": "No", "zowe.promptCredentials.notSupported": "\"Update Credentials\" operation not supported when \"autoStore\" is false", "createNewConnection.option.prompt.profileName.placeholder": "Connection Name", "createNewConnection.option.prompt.profileName": "Enter a name for the connection.", diff --git a/packages/zowe-explorer/package.json b/packages/zowe-explorer/package.json index 2c95e16902..13e1c61e23 100644 --- a/packages/zowe-explorer/package.json +++ b/packages/zowe-explorer/package.json @@ -1903,6 +1903,12 @@ "description": "%zowe.settings.version%", "scope": "window" }, + "zowe.security.checkForCustomCredentialManagers": { + "type": "boolean", + "description": "%zowe.security.checkForCustomCredentialManagers%", + "scope": "window", + "default": "true" + }, "zowe.security.secureCredentialsEnabled": { "default": true, "type": "boolean", diff --git a/packages/zowe-explorer/package.nls.json b/packages/zowe-explorer/package.nls.json index 8bc5d8bf6c..d20dc2e1fe 100644 --- a/packages/zowe-explorer/package.nls.json +++ b/packages/zowe-explorer/package.nls.json @@ -108,6 +108,7 @@ "zowe.pollInterval.info": "Default interval (in milliseconds) when polling spool files.", "zowe.separator.recentFilters": "Recent Filters", "zowe.settings.version": "Track if migration has been processed", + "zowe.security.checkForCustomCredentialManagers": "Check for any installed VS Code extensions for handling credentials when activating Zowe Explorer", "zowe.security.secureCredentialsEnabled": "Allow credentials to be stored securely. If disabled and autoStore is set to true, z/OS credentials are stored as clear text in zowe.config.json.", "issueTsoCmd": "Issue TSO Command", "deleteProfile": "Delete Profile", diff --git a/packages/zowe-explorer/src/ZoweExplorerExtender.ts b/packages/zowe-explorer/src/ZoweExplorerExtender.ts index 6dd235aa7a..1be6625d8e 100644 --- a/packages/zowe-explorer/src/ZoweExplorerExtender.ts +++ b/packages/zowe-explorer/src/ZoweExplorerExtender.ts @@ -165,7 +165,7 @@ export class ZoweExplorerExtender implements ZoweExplorerApi.IApiExplorerExtende */ let usingTeamConfig: boolean; try { - const mProfileInfo = await ProfilesUtils.getProfileInfo(globals.ISTHEIA); + const mProfileInfo = await ProfilesUtils.getProfileInfo(); if (vscode.workspace.workspaceFolders && vscode.workspace.workspaceFolders[0]) { const rootPath = vscode.workspace.workspaceFolders[0].uri.fsPath; await mProfileInfo.readProfilesFromDisk({ homeDir: zoweDir, projectDir: getFullPath(rootPath) }); diff --git a/packages/zowe-explorer/src/globals.ts b/packages/zowe-explorer/src/globals.ts index a503fe7332..142e840507 100644 --- a/packages/zowe-explorer/src/globals.ts +++ b/packages/zowe-explorer/src/globals.ts @@ -94,6 +94,7 @@ export const SETTINGS_DS_HISTORY = "zowe.ds.history"; export const SETTINGS_USS_HISTORY = "zowe.uss.history"; export const SETTINGS_JOBS_HISTORY = "zowe.jobs.history"; export const SETTINGS_SECURE_CREDENTIALS_ENABLED = "zowe.security.secureCredentialsEnabled"; +export const SETTINGS_CHECK_FOR_CUSTOM_CREDENTIAL_MANAGERS = "zowe.security.checkForCustomCredentialManagers"; export const LOGGER_SETTINGS = "zowe.logger"; export const EXTENDER_CONFIG: imperative.ICommandProfileTypeConfiguration[] = []; export const ZOWE_CLI_SCM = "@zowe/cli"; diff --git a/packages/zowe-explorer/src/utils/ProfilesUtils.ts b/packages/zowe-explorer/src/utils/ProfilesUtils.ts index 612284de16..e469195c3b 100644 --- a/packages/zowe-explorer/src/utils/ProfilesUtils.ts +++ b/packages/zowe-explorer/src/utils/ProfilesUtils.ts @@ -225,23 +225,65 @@ export class FilterDescriptor implements vscode.QuickPickItem { } export class ProfilesUtils { - public static getCredentialManagerOverride(): imperative.ICredentialManagerNameMap | undefined { + /** + * Check if the credential manager's vsix is installed for use + * @param credentialManager the display name of the credential manager + * @returns boolean whether the VS Code extension for the custom credential manager is installed + */ + public static isVSCodeCredentialPluginInstalled(credentialManager: string): boolean { + ZoweLogger.trace("ProfilesUtils.isVSCodeCredentialPluginInstalled called."); + try { + const plugin = imperative.CredentialManagerOverride.getCredMgrInfoByDisplayName(credentialManager); + return vscode.extensions.getExtension(plugin?.credMgrZEName) !== undefined; + } catch (err) { + return false; + } + } + + /** + * Get the current credential manager specified in imperative.json + * @returns string the credential manager override + */ + public static getCredentialManagerOverride(): string { ZoweLogger.trace("ProfilesUtils.getCredentialManagerOverride called."); - const knownCredentialManagers = imperative.CredentialManagerOverride.getKnownCredMgrs(); - const credentialManager = knownCredentialManagers.find((knownCredentialManager) => { - try { - return vscode.extensions.getExtension(knownCredentialManager.credMgrZEName); - } catch (err) { - return false; - } - }); - if (!credentialManager) { - return undefined; + const settingsFile = path.join(getZoweDir(), "settings", "imperative.json"); + const imperativeConfig = JSON.parse(fs.readFileSync(settingsFile).toString()); + const credentialManagerOverride = imperativeConfig?.overrides[imperative.CredentialManagerOverride.CRED_MGR_SETTING_NAME]; + if (typeof credentialManagerOverride === "string") { + return credentialManagerOverride; } - return imperative.CredentialManagerOverride.getCredMgrInfoByDisplayName(credentialManager.credMgrDisplayName); + return imperative.CredentialManagerOverride.DEFAULT_CRED_MGR_NAME; } - public static async activateCredentialManagerOverride( + /** + * Get the map of names associated with the custom credential manager + * @param string credentialManager the credential manager display name + * @returns imperative.ICredentialManagerNameMap the map with all names related to the credential manager + */ + public static getCredentialManagerMap(credentialManager: string): imperative.ICredentialManagerNameMap | undefined { + ZoweLogger.trace("ProfilesUtils.getCredentialManagerNameMap called."); + return imperative.CredentialManagerOverride.getCredMgrInfoByDisplayName(credentialManager); + } + + /** + * Update the current credential manager override + * @param setting the credential manager to use in imperative.json + */ + public static async updateCredentialManagerSetting(setting: string): Promise { + ZoweLogger.trace("ProfilesUtils.updateCredentialManagerSetting called."); + const settingEnabled: boolean = SettingsConfig.getDirectValue(globals.SETTINGS_SECURE_CREDENTIALS_ENABLED); + if (settingEnabled) { + await globals.setGlobalSecurityValue(setting); + imperative.CredentialManagerOverride.recordCredMgrInConfig(setting); + } + } + + /** + * Activate a vscode extension of a custom credential manager + * @param credentialManagerExtension The credential manager VS Code extension name to activate + * @returns Promise the constructor of the activated credential manager + */ + private static async activateCredentialManagerOverride( credentialManagerExtension: vscode.Extension ): Promise { try { @@ -256,37 +298,44 @@ export class ProfilesUtils { } } - public static async updateCredentialManagerSetting(setting: string): Promise { - ZoweLogger.trace("ProfilesUtils.updateCredentialManagerSetting called."); - const settingEnabled: boolean = SettingsConfig.getDirectValue(globals.SETTINGS_SECURE_CREDENTIALS_ENABLED); - if (settingEnabled) { - await globals.setGlobalSecurityValue(setting); - imperative.CredentialManagerOverride.recordCredMgrInConfig(setting); - } - } - - public static async getProfileInfo(envTheia: boolean): Promise { - ZoweLogger.trace("ProfilesUtils.getProfileInfo called."); - const credentialManagerMap = ProfilesUtils.getCredentialManagerOverride(); + /** + * Use the custom credential manager in Zowe Explorer and setup before use + * @param credentialManagerMap The map with associated names of the custom credential manager + * @returns Promise the object of profileInfo using the custom credential manager + */ + private static async setupCustomCredentialManager(credentialManagerMap: imperative.ICredentialManagerNameMap): Promise { + ZoweLogger.trace("ProfilesUtils.setupCustomCredentialManager called."); + ZoweLogger.info( + localize( + "ProfilesUtils.setupCustomCredentialManager.usingCustom", + "Custom credential manager {0} found, attempting to activate.", + credentialManagerMap.credMgrDisplayName + ) + ); const customCredentialManagerExtension = credentialManagerMap?.credMgrZEName && vscode.extensions.getExtension(credentialManagerMap.credMgrZEName); - const settingEnabled: boolean = SettingsConfig.getDirectValue(globals.SETTINGS_SECURE_CREDENTIALS_ENABLED); - if (credentialManagerMap && customCredentialManagerExtension && settingEnabled) { - ZoweLogger.info(localize("ProfilesUtils.getProfileInfo.usingCustom", "Custom credential manager found, attempting to activate.")); - const credentialManager = await ProfilesUtils.activateCredentialManagerOverride(customCredentialManagerExtension); - if (credentialManager) { - Object.setPrototypeOf(credentialManager.prototype, imperative.AbstractCredentialManager.prototype); - await ProfilesUtils.updateCredentialManagerSetting(credentialManagerMap.credMgrDisplayName); - return new imperative.ProfileInfo("zowe", { - credMgrOverride: { - Manager: credentialManager, - service: credentialManagerMap.credMgrDisplayName, - }, - }); - } + const credentialManager = await ProfilesUtils.activateCredentialManagerOverride(customCredentialManagerExtension); + if (credentialManager) { + Object.setPrototypeOf(credentialManager.prototype, imperative.AbstractCredentialManager.prototype); + await ProfilesUtils.updateCredentialManagerSetting(credentialManagerMap.credMgrDisplayName); + return new imperative.ProfileInfo("zowe", { + credMgrOverride: { + Manager: credentialManager, + service: credentialManagerMap.credMgrDisplayName, + }, + }); } + } - ZoweLogger.info(localize("ProfilesUtils.getProfileInfo.usingDefault", "No custom credential managers found, using the default instead.")); + /** + * Use the default credential manager in Zowe Explorer and setup before use + * @returns Promise the object of profileInfo using the default credential manager + */ + private static async setupDefaultCredentialManager(): Promise { + ZoweLogger.trace("ProfilesUtils.setupDefaultCredentialManager called."); + ZoweLogger.info( + localize("ProfilesUtils.setupDefaultCredentialManager.usingDefault", "No custom credential managers found, using the default instead.") + ); await ProfilesUtils.updateCredentialManagerSetting(globals.ZOWE_CLI_SCM); return new imperative.ProfileInfo("zowe", { // eslint-disable-next-line @typescript-eslint/no-unsafe-return @@ -294,10 +343,118 @@ export class ProfilesUtils { }); } + /** + * Fetches the first available registered custom credential manager from installed VS Code extensions. + * This function will suggest changing the imperative.json file override property if the override is different + * from the available custom credential manager. + * + * @returns Promise + */ + private static async fetchRegisteredPlugins(): Promise { + ZoweLogger.trace("ProfilesUtils.fetchRegisteredPlugins called."); + const knownCredentialManagers = imperative.CredentialManagerOverride.getKnownCredMgrs(); + const credentialManager = knownCredentialManagers.find((knownCredentialManager) => { + try { + return vscode.extensions.getExtension(knownCredentialManager.credMgrZEName); + } catch (err) { + return false; + } + }); + if (credentialManager) { + const header = localize( + "ProfilesUtils.fetchRegisteredPlugins.customCredentialManagerFound", + `Custom credential manager {0} found`, + credentialManager.credMgrDisplayName + ); + + const message = localize("ProfilesUtils.fetchRegisteredPlugins.message", "Do you wish to use this credential manager instead?"); + const optionYes = localize("ProfilesUtils.fetchRegisteredPlugins.yes", "Yes"); + const optionDontAskAgain = localize("ProfilesUtils.fetchRegisteredPlugins.dontAskAgain", "Don't ask again"); + + await Gui.infoMessage(header, { items: [optionYes, optionDontAskAgain], vsCodeOpts: { modal: true, detail: message } }).then( + async (selection) => { + if (selection === optionYes) { + await this.updateCredentialManagerSetting(credentialManager.credMgrDisplayName); + SettingsConfig.setDirectValue( + globals.SETTINGS_CHECK_FOR_CUSTOM_CREDENTIAL_MANAGERS, + false, + vscode.ConfigurationTarget.Global + ); + } + if (selection === optionDontAskAgain) { + SettingsConfig.setDirectValue( + globals.SETTINGS_CHECK_FOR_CUSTOM_CREDENTIAL_MANAGERS, + false, + vscode.ConfigurationTarget.Global + ); + } + } + ); + } + } + + /** + * Prompts to install the missing VS Code extension associated with the credential manager override in imperative.json + * + * @param credentialManager the credential manager to handle its missing VS Code extension + * @returns Promise + */ + private static async promptAndHandleMissingCredentialManager(credentialManager: imperative.ICredentialManagerNameMap): Promise { + ZoweLogger.trace("ProfilesUtils.promptAndHandleMissingCredentialManager called."); + const header = localize( + "ProfilesUtils.promptAndHandleMissingCredentialManager.suggestInstallHeader", + `Plugin of name "{0}" was defined for custom credential management on imperative.json file.`, + credentialManager.credMgrDisplayName + ); + const message = localize( + "ProfilesUtils.promptAndHandleMissingCredentialManager.suggestInstallMessage", + `Please install associated VS Code extension for + custom credential manager or revert to default.` + ); + const revertToDefaultButton = localize("ProfilesUtils.promptAndHandleMissingCredentialManager.revertToDefault", "Use Default"); + const installButton = localize("ProfilesUtils.promptAndHandleMissingCredentialManager.install", "Install"); + await Gui.infoMessage(header, { items: [installButton, revertToDefaultButton], vsCodeOpts: { modal: true, detail: message } }).then( + async (selection) => { + if (selection === installButton) { + const credentialManagerInstallURL = vscode.Uri.parse( + `https://marketplace.visualstudio.com/items?itemName=${credentialManager.credMgrZEName}` + ); + await vscode.env.openExternal(credentialManagerInstallURL); + } else { + await this.setupDefaultCredentialManager(); + } + } + ); + } + + public static async getProfileInfo(): Promise { + ZoweLogger.trace("ProfilesUtils.getProfileInfo called."); + + const shouldCheckForCustomCredentialManagers = SettingsConfig.getDirectValue(globals.SETTINGS_CHECK_FOR_CUSTOM_CREDENTIAL_MANAGERS); + if (shouldCheckForCustomCredentialManagers) { + await this.fetchRegisteredPlugins(); + } + + const credentialManagerOverride = this.getCredentialManagerOverride(); + const isVSCodeCredentialPluginInstalled = this.isVSCodeCredentialPluginInstalled(credentialManagerOverride); + const isCustomCredentialPluginDefined = credentialManagerOverride !== imperative.CredentialManagerOverride.DEFAULT_CRED_MGR_NAME; + const settingEnabled: boolean = SettingsConfig.getDirectValue(globals.SETTINGS_SECURE_CREDENTIALS_ENABLED); + const credentialManagerMap = ProfilesUtils.getCredentialManagerMap(credentialManagerOverride); + + if (isCustomCredentialPluginDefined && !isVSCodeCredentialPluginInstalled && credentialManagerMap && settingEnabled) { + await this.promptAndHandleMissingCredentialManager(credentialManagerMap); + } + if (credentialManagerMap && isVSCodeCredentialPluginInstalled && settingEnabled) { + return this.setupCustomCredentialManager(credentialManagerMap); + } + + return this.setupDefaultCredentialManager(); + } + public static async readConfigFromDisk(): Promise { ZoweLogger.trace("ProfilesUtils.readConfigFromDisk called."); let rootPath: string; - const mProfileInfo = await ProfilesUtils.getProfileInfo(globals.ISTHEIA); + const mProfileInfo = await ProfilesUtils.getProfileInfo(); if (vscode.workspace.workspaceFolders && vscode.workspace.workspaceFolders[0]) { rootPath = vscode.workspace.workspaceFolders[0].uri.fsPath; await mProfileInfo.readProfilesFromDisk({ homeDir: getZoweDir(), projectDir: getFullPath(rootPath) }); @@ -365,8 +522,8 @@ export class ProfilesUtils { ZoweLogger.trace("ProfilesUtils.initializeZoweFolder called."); // ensure the Secure Credentials Enabled value is read // set globals.PROFILE_SECURITY value accordingly - const credentialManagerMap = ProfilesUtils.getCredentialManagerOverride(); - await globals.setGlobalSecurityValue(credentialManagerMap?.credMgrDisplayName ?? globals.ZOWE_CLI_SCM); + const credentialManagerOverride = ProfilesUtils.getCredentialManagerOverride(); + await globals.setGlobalSecurityValue(credentialManagerOverride ?? globals.ZOWE_CLI_SCM); // Ensure that ~/.zowe folder exists // Ensure that the ~/.zowe/settings/imperative.json exists // TODO: update code below once this imperative issue is resolved. From 976725898a0a63764312a5ede07a20fcc1308e0d Mon Sep 17 00:00:00 2001 From: Rudy Flores <68666202+rudyflores@users.noreply.github.com> Date: Tue, 3 Oct 2023 14:24:22 -0400 Subject: [PATCH 073/189] reload after installing Signed-off-by: Rudy Flores <68666202+rudyflores@users.noreply.github.com> --- .../sample/src/utils/ProfilesUtils.i18n.json | 10 ++++++---- .../zowe-explorer/src/utils/ProfilesUtils.ts | 18 +++++++++++++----- 2 files changed, 19 insertions(+), 9 deletions(-) diff --git a/packages/zowe-explorer/i18n/sample/src/utils/ProfilesUtils.i18n.json b/packages/zowe-explorer/i18n/sample/src/utils/ProfilesUtils.i18n.json index d828603181..a895fcdba1 100644 --- a/packages/zowe-explorer/i18n/sample/src/utils/ProfilesUtils.i18n.json +++ b/packages/zowe-explorer/i18n/sample/src/utils/ProfilesUtils.i18n.json @@ -8,14 +8,16 @@ "activateCredentialManagerOverride.failedToActivate": "Custom credential manager failed to activate", "ProfilesUtils.setupCustomCredentialManager.usingCustom": "Custom credential manager {0} found, attempting to activate.", "ProfilesUtils.setupDefaultCredentialManager.usingDefault": "No custom credential managers found, using the default instead.", + "ProfilesUtils.fetchRegisteredPlugins.customCredentialManagerFound": "Custom credential manager {0} found", + "ProfilesUtils.fetchRegisteredPlugins.message": "Do you wish to use this credential manager instead?", + "ProfilesUtils.fetchRegisteredPlugins.yes": "Yes", + "ProfilesUtils.fetchRegisteredPlugins.dontAskAgain": "Don't ask again", "ProfilesUtils.promptAndHandleMissingCredentialManager.suggestInstallHeader": "Plugin of name \"{0}\" was defined for custom credential management on imperative.json file.", "ProfilesUtils.promptAndHandleMissingCredentialManager.suggestInstallMessage": "Please install associated VS Code extension for\n custom credential manager or revert to default.", "ProfilesUtils.promptAndHandleMissingCredentialManager.revertToDefault": "Use Default", "ProfilesUtils.promptAndHandleMissingCredentialManager.install": "Install", - "ProfilesUtils.fetchRegisteredPlugins.customCredentialManagerFound": "Custom credential manager {0} found", - "ProfilesUtils.fetchRegisteredPlugins.message": "Do you wish to use this credential manager instead?", - "ProfilesUtils.fetchRegisteredPlugins.yes": "Yes", - "ProfilesUtils.fetchRegisteredPlugins.no": "No", + "ProfilesUtils.promptAndHandleMissingCredentialManager.refreshMessage": "After installing the extension, please make sure to reload\n your VS Code window in order to start using the installed credential manager", + "ProfilesUtils.promptAndHandleMissingCredentialManager.refreshButton": "Refresh", "zowe.promptCredentials.notSupported": "\"Update Credentials\" operation not supported when \"autoStore\" is false", "createNewConnection.option.prompt.profileName.placeholder": "Connection Name", "createNewConnection.option.prompt.profileName": "Enter a name for the connection.", diff --git a/packages/zowe-explorer/src/utils/ProfilesUtils.ts b/packages/zowe-explorer/src/utils/ProfilesUtils.ts index e469195c3b..2f925d2379 100644 --- a/packages/zowe-explorer/src/utils/ProfilesUtils.ts +++ b/packages/zowe-explorer/src/utils/ProfilesUtils.ts @@ -406,22 +406,30 @@ export class ProfilesUtils { `Plugin of name "{0}" was defined for custom credential management on imperative.json file.`, credentialManager.credMgrDisplayName ); - const message = localize( + const installMessage = localize( "ProfilesUtils.promptAndHandleMissingCredentialManager.suggestInstallMessage", `Please install associated VS Code extension for custom credential manager or revert to default.` ); const revertToDefaultButton = localize("ProfilesUtils.promptAndHandleMissingCredentialManager.revertToDefault", "Use Default"); const installButton = localize("ProfilesUtils.promptAndHandleMissingCredentialManager.install", "Install"); - await Gui.infoMessage(header, { items: [installButton, revertToDefaultButton], vsCodeOpts: { modal: true, detail: message } }).then( + await Gui.infoMessage(header, { items: [installButton, revertToDefaultButton], vsCodeOpts: { modal: true, detail: installMessage } }).then( async (selection) => { if (selection === installButton) { const credentialManagerInstallURL = vscode.Uri.parse( `https://marketplace.visualstudio.com/items?itemName=${credentialManager.credMgrZEName}` ); - await vscode.env.openExternal(credentialManagerInstallURL); - } else { - await this.setupDefaultCredentialManager(); + if (await vscode.env.openExternal(credentialManagerInstallURL)) { + const refreshMessage = localize( + "ProfilesUtils.promptAndHandleMissingCredentialManager.refreshMessage", + `After installing the extension, please make sure to reload + your VS Code window in order to start using the installed credential manager` + ); + const refreshButton = localize("ProfilesUtils.promptAndHandleMissingCredentialManager.refreshButton", "Refresh"); + if ((await Gui.showMessage(refreshMessage, { items: [refreshButton] })) === refreshButton) { + await vscode.commands.executeCommand("workbench.action.reloadWindow"); + } + } } } ); From 7ba0dbf12f24fe3c67d32431acbdd62d8fb4b53c Mon Sep 17 00:00:00 2001 From: Rudy Flores <68666202+rudyflores@users.noreply.github.com> Date: Tue, 3 Oct 2023 14:25:59 -0400 Subject: [PATCH 074/189] add changelog Signed-off-by: Rudy Flores <68666202+rudyflores@users.noreply.github.com> --- packages/zowe-explorer/CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/zowe-explorer/CHANGELOG.md b/packages/zowe-explorer/CHANGELOG.md index e00358e7bd..4f3cf46896 100644 --- a/packages/zowe-explorer/CHANGELOG.md +++ b/packages/zowe-explorer/CHANGELOG.md @@ -9,6 +9,7 @@ All notable changes to the "vscode-extension-for-zowe" extension will be documen - Added "Sort Jobs" feature for job nodes in Jobs tree view. [#2257](https://github.com/zowe/vscode-extension-for-zowe/issues/2251) - Added new edit feature on `Edit Attributes` view for changing file tags on USS [#2113](https://github.com/zowe/vscode-extension-for-zowe/issues/2113) - Added new API {ZE Extender MetaData} to allow extenders to have the metadata of registered extenders to aid in team configuration file creation from a view that isn't Zowe Explorer's. [#2394](https://github.com/zowe/vscode-extension-for-zowe/issues/2394) +- Added ability to install extension from VS Code marketplace if custom credential manager extension is missing after defining it on `imperative.json` [#2381](https://github.com/zowe/vscode-extension-for-zowe/issues/2381) ### Bug fixes From 5e203ed3b32bd6dfcb4cb5a6e7dd01329bc79b4e Mon Sep 17 00:00:00 2001 From: Rudy Flores <68666202+rudyflores@users.noreply.github.com> Date: Tue, 3 Oct 2023 15:22:35 -0400 Subject: [PATCH 075/189] fix broken unit tests Signed-off-by: Rudy Flores <68666202+rudyflores@users.noreply.github.com> --- .../__unit__/Profiles.extended.unit.test.ts | 6 ++ .../__tests__/__unit__/extension.unit.test.ts | 2 + .../__unit__/utils/ProfilesUtils.unit.test.ts | 87 ++++++------------- 3 files changed, 35 insertions(+), 60 deletions(-) diff --git a/packages/zowe-explorer/__tests__/__unit__/Profiles.extended.unit.test.ts b/packages/zowe-explorer/__tests__/__unit__/Profiles.extended.unit.test.ts index 2876032d7b..c403394cbe 100644 --- a/packages/zowe-explorer/__tests__/__unit__/Profiles.extended.unit.test.ts +++ b/packages/zowe-explorer/__tests__/__unit__/Profiles.extended.unit.test.ts @@ -340,6 +340,8 @@ describe("Profiles Unit Tests - Function createNewConnection for v1 Profiles", ( const globalMocks = await createGlobalMocks(); const blockMocks = await createBlockMocks(globalMocks); + jest.spyOn(utils.ProfilesUtils, "getCredentialManagerOverride").mockReturnValueOnce("@zowe/cli"); + jest.spyOn(globalMocks.mockProfileInstance, "getSchema").mockReturnValue(blockMocks.testSchemas); jest.spyOn(globalMocks.mockProfileInstance, "urlInfo").mockReturnValue(globalMocks.mockUrlInfo); jest.spyOn(globalMocks.mockProfileInstance, "userInfo").mockReturnValue(globalMocks.testProfile.profile.user); @@ -377,6 +379,7 @@ describe("Profiles Unit Tests - Function createNewConnection for v1 Profiles", ( it("Tests that createNewConnection returns 'fake' if the port is undefined and portInfo() returns correct port", async () => { const globalMocks = await createGlobalMocks(); const blockMocks = await createBlockMocks(globalMocks); + jest.spyOn(utils.ProfilesUtils, "getCredentialManagerOverride").mockReturnValueOnce("@zowe/cli"); const customURLInfo = { valid: true, protocol: "https", @@ -424,6 +427,7 @@ describe("Profiles Unit Tests - Function createNewConnection for v1 Profiles", ( const globalMocks = await createGlobalMocks(); const blockMocks = await createBlockMocks(globalMocks); + jest.spyOn(utils.ProfilesUtils, "getCredentialManagerOverride").mockReturnValueOnce("@zowe/cli"); jest.spyOn(globalMocks.mockProfileInstance, "getSchema").mockReturnValueOnce(blockMocks.testSchemas); jest.spyOn(globalMocks.mockProfileInstance, "urlInfo").mockReturnValueOnce(globalMocks.mockUrlInfo); jest.spyOn(globalMocks.mockProfileInstance, "userInfo").mockReturnValueOnce(globalMocks.testProfile.profile.user); @@ -447,6 +451,7 @@ describe("Profiles Unit Tests - Function createNewConnection for v1 Profiles", ( const globalMocks = await createGlobalMocks(); const blockMocks = await createBlockMocks(globalMocks); + jest.spyOn(utils.ProfilesUtils, "getCredentialManagerOverride").mockReturnValueOnce("@zowe/cli"); jest.spyOn(globalMocks.mockProfileInstance, "getSchema").mockReturnValueOnce(blockMocks.testSchemas); jest.spyOn(globalMocks.mockProfileInstance, "urlInfo").mockReturnValueOnce(globalMocks.mockUrlInfo); jest.spyOn(globalMocks.mockProfileInstance, "userInfo").mockReturnValueOnce(globalMocks.testProfile.profile.user); @@ -499,6 +504,7 @@ describe("Profiles Unit Tests - Function createNewConnection for v1 Profiles", ( const globalMocks = await createGlobalMocks(); const blockMocks = await createBlockMocks(globalMocks); + jest.spyOn(utils.ProfilesUtils, "getCredentialManagerOverride").mockReturnValueOnce("@zowe/cli"); jest.spyOn(globalMocks.mockProfileInstance, "getSchema").mockReturnValueOnce(blockMocks.testSchemas); jest.spyOn(globalMocks.mockProfileInstance, "urlInfo").mockReturnValueOnce(globalMocks.mockUrlInfo); jest.spyOn(globalMocks.mockProfileInstance, "userInfo").mockReturnValueOnce(globalMocks.testProfile.profile.user); diff --git a/packages/zowe-explorer/__tests__/__unit__/extension.unit.test.ts b/packages/zowe-explorer/__tests__/__unit__/extension.unit.test.ts index 0f637993a6..ee0b88ac51 100644 --- a/packages/zowe-explorer/__tests__/__unit__/extension.unit.test.ts +++ b/packages/zowe-explorer/__tests__/__unit__/extension.unit.test.ts @@ -30,6 +30,7 @@ import { DatasetTree } from "../../src/dataset/DatasetTree"; import { USSTree } from "../../src/uss/USSTree"; import { ZoweLogger } from "../../src/utils/LoggerUtils"; import { ZoweSaveQueue } from "../../src/abstract/ZoweSaveQueue"; +import { ProfilesUtils } from "../../src/utils/ProfilesUtils"; jest.mock("vscode"); jest.mock("fs"); @@ -561,6 +562,7 @@ describe("Extension Unit Tests", () => { describe("Extension Unit Tests - THEIA", () => { it("Tests that activate() works correctly for Theia", async () => { const globalMocks = await createGlobalMocks(); + jest.spyOn(ProfilesUtils, "getCredentialManagerOverride").mockReturnValueOnce("@zowe/cli"); Object.defineProperty(vscode.env, "appName", { value: "Eclipse Theia" }); Object.defineProperty(vscode.env, "uriScheme", { value: "theia" }); diff --git a/packages/zowe-explorer/__tests__/__unit__/utils/ProfilesUtils.unit.test.ts b/packages/zowe-explorer/__tests__/__unit__/utils/ProfilesUtils.unit.test.ts index 65a2121ff8..9f75a0505e 100644 --- a/packages/zowe-explorer/__tests__/__unit__/utils/ProfilesUtils.unit.test.ts +++ b/packages/zowe-explorer/__tests__/__unit__/utils/ProfilesUtils.unit.test.ts @@ -473,6 +473,12 @@ describe("ProfilesUtils unit tests", () => { describe("initializeZoweFolder", () => { it("should create directories and files that do not exist", async () => { const blockMocks = createBlockMocks(); + jest.spyOn(fs, "readFileSync").mockReturnValueOnce(""); + jest.spyOn(JSON, "parse").mockReturnValueOnce({ + overrides: { + credentialManager: "@zowe/cli", + }, + }); blockMocks.mockGetDirectValue.mockReturnValue(true); blockMocks.mockExistsSync.mockReturnValue(false); const createFileSpy = jest.spyOn(profUtils.ProfilesUtils, "writeOverridesFile"); @@ -484,6 +490,7 @@ describe("ProfilesUtils unit tests", () => { it("should skip creating directories and files that already exist", async () => { const blockMocks = createBlockMocks(); + jest.spyOn(profUtils.ProfilesUtils, "getCredentialManagerOverride").mockReturnValueOnce("@zowe/cli"); blockMocks.mockGetDirectValue.mockReturnValue("@zowe/cli"); blockMocks.mockExistsSync.mockReturnValue(true); const fileJson = blockMocks.mockFileRead; @@ -557,6 +564,7 @@ describe("ProfilesUtils unit tests", () => { describe("initializeZoweProfiles", () => { it("should successfully initialize Zowe folder and read config from disk", async () => { const initZoweFolderSpy = jest.spyOn(profUtils.ProfilesUtils, "initializeZoweFolder"); + jest.spyOn(profUtils.ProfilesUtils, "getCredentialManagerOverride").mockReturnValueOnce("@zowe/cli"); const readConfigFromDiskSpy = jest.spyOn(profUtils.ProfilesUtils, "readConfigFromDisk").mockResolvedValueOnce(); await profUtils.ProfilesUtils.initializeZoweProfiles(); expect(initZoweFolderSpy).toHaveBeenCalledTimes(1); @@ -603,40 +611,6 @@ describe("ProfilesUtils unit tests", () => { expect(testFilterItem.label).toEqual("test undefined"); }); - describe("getCredentialManagerOverride", () => { - afterEach(() => { - jest.clearAllMocks(); - jest.resetAllMocks(); - }); - - it("should successfully retrieve the credential manager override map", () => { - const expectedValue = { - credMgrZEName: "test", - credMgrPluginName: "test", - } as zowe.imperative.ICredentialManagerNameMap; - const zoweLoggerTraceSpy = jest.spyOn(ZoweLogger, "trace"); - jest.spyOn(zowe.imperative.CredentialManagerOverride, "getKnownCredMgrs").mockReturnValueOnce([expectedValue]); - jest.spyOn(vscode.extensions, "getExtension").mockReturnValueOnce({ test: "test" } as any); - jest.spyOn(zowe.imperative.CredentialManagerOverride, "getCredMgrInfoByDisplayName").mockReturnValueOnce(expectedValue); - expect(profUtils.ProfilesUtils.getCredentialManagerOverride()).toEqual(expectedValue); - expect(zoweLoggerTraceSpy).toBeCalledTimes(1); - }); - it("should return undefined if no credential manager is found", () => { - const expectedValue = { - credMgrZEName: "test", - credMgrPluginName: "test", - } as zowe.imperative.ICredentialManagerNameMap; - const zoweLoggerTraceSpy = jest.spyOn(ZoweLogger, "trace"); - jest.spyOn(zowe.imperative.CredentialManagerOverride, "getKnownCredMgrs").mockReturnValueOnce([expectedValue]); - jest.spyOn(vscode.extensions, "getExtension").mockImplementationOnce(() => { - throw new Error("failed to get extension"); - }); - jest.spyOn(zowe.imperative.CredentialManagerOverride, "getCredMgrInfoByDisplayName").mockReturnValueOnce(expectedValue); - expect(profUtils.ProfilesUtils.getCredentialManagerOverride()).toEqual(undefined); - expect(zoweLoggerTraceSpy).toBeCalledTimes(1); - }); - }); - describe("activateCredentialManagerOverride", () => { afterEach(() => { jest.clearAllMocks(); @@ -651,7 +625,7 @@ describe("ProfilesUtils unit tests", () => { isActive: true, } as any; - await expect(profUtils.ProfilesUtils.activateCredentialManagerOverride(credentialManagerExtension)).resolves.toEqual( + await expect((profUtils.ProfilesUtils as any).activateCredentialManagerOverride(credentialManagerExtension)).resolves.toEqual( {} as zowe.imperative.ICredentialManagerConstructor ); expect(activateSpy).toBeCalledTimes(1); @@ -665,7 +639,7 @@ describe("ProfilesUtils unit tests", () => { isActive: true, } as any; - await expect(profUtils.ProfilesUtils.activateCredentialManagerOverride(credentialManagerExtension)).resolves.toEqual(undefined); + await expect((profUtils.ProfilesUtils as any).activateCredentialManagerOverride(credentialManagerExtension)).resolves.toEqual(undefined); expect(activateSpy).toBeCalledTimes(1); }); @@ -678,7 +652,7 @@ describe("ProfilesUtils unit tests", () => { isActive: true, } as any; - await expect(profUtils.ProfilesUtils.activateCredentialManagerOverride(credentialManagerExtension)).rejects.toThrow( + await expect((profUtils.ProfilesUtils as any).activateCredentialManagerOverride(credentialManagerExtension)).rejects.toThrow( "Custom credential manager failed to activate" ); }); @@ -707,34 +681,27 @@ describe("ProfilesUtils unit tests", () => { }); it("should retrieve the custom credential manager", async () => { - jest.spyOn(profUtils.ProfilesUtils, "getCredentialManagerOverride").mockReturnValueOnce({ - credMgrDisplayName: "test1", - credMgrPluginName: "test2", - credMgrZEName: "test3", - }); - jest.spyOn(vscode.extensions, "getExtension").mockReturnValueOnce({} as any); + jest.spyOn(SettingsConfig, "getDirectValue").mockReturnValueOnce(false); + jest.spyOn(profUtils.ProfilesUtils, "getCredentialManagerOverride").mockReturnValue("test"); + jest.spyOn(profUtils.ProfilesUtils, "isVSCodeCredentialPluginInstalled").mockReturnValueOnce(true); jest.spyOn(SettingsConfig, "getDirectValue").mockReturnValueOnce(true); - const activateCredenitalManagerOverrideSpy = jest - .spyOn(profUtils.ProfilesUtils, "activateCredentialManagerOverride") - .mockResolvedValueOnce({ - prototype: {}, - } as zowe.imperative.ICredentialManagerConstructor); - const updateCredentialManagerSettingSpy = jest.spyOn(profUtils.ProfilesUtils, "updateCredentialManagerSetting").mockImplementation(); - jest.spyOn(zowe.imperative, "ProfileInfo").mockReturnValueOnce({} as any); - await expect(profUtils.ProfilesUtils.getProfileInfo(false)).resolves.toEqual({}); - expect(activateCredenitalManagerOverrideSpy).toBeCalledWith({}); - expect(updateCredentialManagerSettingSpy).toBeCalledWith("test1"); + jest.spyOn(profUtils.ProfilesUtils, "getCredentialManagerMap").mockReturnValueOnce({ + credMgrDisplayName: "test", + credMgrPluginName: "test", + credMgrZEName: "test", + }); + jest.spyOn((profUtils as any).ProfilesUtils, "setupCustomCredentialManager").mockReturnValueOnce({}); + await expect(profUtils.ProfilesUtils.getProfileInfo()).resolves.toEqual({}); }); it("should retrieve the default credential manager if no custom credential manager is found", async () => { - jest.spyOn(profUtils.ProfilesUtils, "getCredentialManagerOverride").mockReturnValueOnce(undefined); - const defaultCredMgrSpy = jest.spyOn(zowe.imperative.ProfileCredentials, "defaultCredMgrWithKeytar"); - jest.spyOn(vscode.extensions, "getExtension").mockReturnValueOnce(undefined); + jest.spyOn(SettingsConfig, "getDirectValue").mockReturnValueOnce(false); + jest.spyOn(profUtils.ProfilesUtils, "getCredentialManagerOverride").mockReturnValue("@zowe/cli"); + jest.spyOn(profUtils.ProfilesUtils, "isVSCodeCredentialPluginInstalled").mockReturnValueOnce(false); jest.spyOn(SettingsConfig, "getDirectValue").mockReturnValueOnce(true); - const updateCredentialManagerSettingSpy = jest.spyOn(profUtils.ProfilesUtils, "updateCredentialManagerSetting").mockImplementation(); - await expect(profUtils.ProfilesUtils.getProfileInfo(true)).resolves.toEqual({}); - expect(updateCredentialManagerSettingSpy).toBeCalledWith(globals.ZOWE_CLI_SCM); - expect(defaultCredMgrSpy).toHaveBeenCalledWith(ProfilesCache.requireKeyring); + jest.spyOn(profUtils.ProfilesUtils, "getCredentialManagerMap").mockReturnValueOnce(undefined); + jest.spyOn((profUtils as any).ProfilesUtils, "setupDefaultCredentialManager").mockReturnValueOnce({}); + await expect(profUtils.ProfilesUtils.getProfileInfo()).resolves.toEqual({}); }); }); From 6a268a77f812cdd44029f7b57ad2f7be4cb2b4db Mon Sep 17 00:00:00 2001 From: Trae Yelovich Date: Tue, 3 Oct 2023 15:37:20 -0400 Subject: [PATCH 076/189] feat(ds): Sort by date modified, name, or user ID Signed-off-by: Trae Yelovich --- .../src/tree/IZoweTreeNode.ts | 19 +++++++++ .../i18n/sample/package.i18n.json | 8 ++-- packages/zowe-explorer/package.json | 32 ++++++++++++++- packages/zowe-explorer/package.nls.json | 8 ++-- .../src/abstract/ZoweTreeProvider.ts | 10 +++++ .../zowe-explorer/src/dataset/DatasetTree.ts | 17 ++++++++ .../src/dataset/ZoweDatasetNode.ts | 34 ++++++++++++--- packages/zowe-explorer/src/dataset/init.ts | 41 ++++++++++++------- 8 files changed, 143 insertions(+), 26 deletions(-) diff --git a/packages/zowe-explorer-api/src/tree/IZoweTreeNode.ts b/packages/zowe-explorer-api/src/tree/IZoweTreeNode.ts index 7bd2349f31..d2ff45e178 100644 --- a/packages/zowe-explorer-api/src/tree/IZoweTreeNode.ts +++ b/packages/zowe-explorer-api/src/tree/IZoweTreeNode.ts @@ -20,6 +20,17 @@ export enum NodeAction { Download = "download", } +export enum DatasetSort { + LastModified, + Name, + UserId, +} + +export type DatasetStats = { + user: string; + m4date: Date; +}; + /** * The base interface for Zowe tree nodes that are implemented by vscode.TreeItem. * @@ -135,6 +146,14 @@ export interface IZoweDatasetTreeNode extends IZoweTreeNode { * Search criteria for a Dataset member search */ memberPattern?: string; + /** + * Sort members of a node by the given sorting method + */ + sortMethod?: DatasetSort; + /** + * Additional statistics about this data set + */ + stats?: Partial; /** * Retrieves child nodes of this IZoweDatasetTreeNode * diff --git a/packages/zowe-explorer/i18n/sample/package.i18n.json b/packages/zowe-explorer/i18n/sample/package.i18n.json index 8bc5d8bf6c..c157c7a0a2 100644 --- a/packages/zowe-explorer/i18n/sample/package.i18n.json +++ b/packages/zowe-explorer/i18n/sample/package.i18n.json @@ -147,7 +147,9 @@ "createZoweSchema.reload.infoMessage": "Team Configuration file created. Location: {0}. \n Please reload your window.", "copyFile": "Copy", "pasteFile": "Paste", - "jobs.sortbyreturncode": "Sort by ReturnCode", - "jobs.sortbyname": "Sort by Name", - "jobs.sortbyid": "Sort by ID" + "jobs.sortbyreturncode": "Sort by Return Code", + "jobs.sortbyid": "Sort by ID", + "sortByName": "Sort by Name", + "ds.sortByUserId": "Sort by User ID", + "ds.sortByModified": "Sort by Date Modified" } diff --git a/packages/zowe-explorer/package.json b/packages/zowe-explorer/package.json index 2c95e16902..8d5a227b12 100644 --- a/packages/zowe-explorer/package.json +++ b/packages/zowe-explorer/package.json @@ -128,7 +128,7 @@ }, { "command": "zowe.jobs.sortbyname", - "title": "%jobs.sortbyname%", + "title": "%sortByName%", "category": "Zowe Explorer" }, { @@ -276,6 +276,21 @@ "title": "%deleteProfile%", "category": "Zowe Explorer" }, + { + "command": "zowe.ds.sortByName", + "title": "%sortByName%", + "category": "Zowe Explorer" + }, + { + "command": "zowe.ds.sortByModified", + "title": "%ds.sortByModified%", + "category": "Zowe Explorer" + }, + { + "command": "zowe.ds.sortByUserId", + "title": "%ds.sortByUserId%", + "category": "Zowe Explorer" + }, { "command": "zowe.cmd.deleteProfile", "title": "%cmd.deleteProfile%", @@ -1108,6 +1123,21 @@ "command": "zowe.ds.removeFavProfile", "group": "002_zowe_dsWorkspace@4" }, + { + "when": "view == zowe.ds.explorer && viewItem =~ /^(pds).*/ && !listMultiSelection", + "command": "zowe.ds.sortByModified", + "group": "003_zowe_dsSort@1" + }, + { + "when": "view == zowe.ds.explorer && viewItem =~ /^(pds).*/ && !listMultiSelection", + "command": "zowe.ds.sortByName", + "group": "003_zowe_dsSort@2" + }, + { + "when": "view == zowe.ds.explorer && viewItem =~ /^(pds).*/ && !listMultiSelection", + "command": "zowe.ds.sortByUserId", + "group": "003_zowe_dsSort@3" + }, { "when": "view == zowe.ds.explorer && viewItem =~ /^fileError.*/", "command": "zowe.ds.showFileErrorDetails", diff --git a/packages/zowe-explorer/package.nls.json b/packages/zowe-explorer/package.nls.json index 8bc5d8bf6c..c157c7a0a2 100644 --- a/packages/zowe-explorer/package.nls.json +++ b/packages/zowe-explorer/package.nls.json @@ -147,7 +147,9 @@ "createZoweSchema.reload.infoMessage": "Team Configuration file created. Location: {0}. \n Please reload your window.", "copyFile": "Copy", "pasteFile": "Paste", - "jobs.sortbyreturncode": "Sort by ReturnCode", - "jobs.sortbyname": "Sort by Name", - "jobs.sortbyid": "Sort by ID" + "jobs.sortbyreturncode": "Sort by Return Code", + "jobs.sortbyid": "Sort by ID", + "sortByName": "Sort by Name", + "ds.sortByUserId": "Sort by User ID", + "ds.sortByModified": "Sort by Date Modified" } diff --git a/packages/zowe-explorer/src/abstract/ZoweTreeProvider.ts b/packages/zowe-explorer/src/abstract/ZoweTreeProvider.ts index 0321cad081..afbdfef2e2 100644 --- a/packages/zowe-explorer/src/abstract/ZoweTreeProvider.ts +++ b/packages/zowe-explorer/src/abstract/ZoweTreeProvider.ts @@ -85,6 +85,16 @@ export class ZoweTreeProvider { } } + /** + * Fire the "onDidChangeTreeData" event to signal that a node in the tree has changed. + * Unlike `refreshElement`, this function does NOT signal a refresh for the given node - + * it simply tells VS Code to repaint the node in the tree. + * @param node The node that should be repainted + */ + public nodeDataChanged(node: IZoweTreeNode): void { + this.mOnDidChangeTreeData.fire(node); + } + /** * Called whenever the tree needs to be refreshed, and fires the data change event * diff --git a/packages/zowe-explorer/src/dataset/DatasetTree.ts b/packages/zowe-explorer/src/dataset/DatasetTree.ts index 41e428768d..542587aef2 100644 --- a/packages/zowe-explorer/src/dataset/DatasetTree.ts +++ b/packages/zowe-explorer/src/dataset/DatasetTree.ts @@ -23,6 +23,7 @@ import { PersistenceSchemaEnum, NodeInteraction, IZoweTreeNode, + DatasetSort, } from "@zowe/zowe-explorer-api"; import { Profiles } from "../Profiles"; import { ZoweExplorerApiRegister } from "../ZoweExplorerApiRegister"; @@ -1287,4 +1288,20 @@ export class DatasetTree extends ZoweTreeProvider implements IZoweTree 0) { + // If children nodes already exist, sort now and avoid extra refresh + node.children.sort(ZoweDatasetNode.sortBy(method)); + this.nodeDataChanged(node); + } else { + this.refreshElement(node); + } + } } diff --git a/packages/zowe-explorer/src/dataset/ZoweDatasetNode.ts b/packages/zowe-explorer/src/dataset/ZoweDatasetNode.ts index 8d369eb00d..a72a95b934 100644 --- a/packages/zowe-explorer/src/dataset/ZoweDatasetNode.ts +++ b/packages/zowe-explorer/src/dataset/ZoweDatasetNode.ts @@ -13,7 +13,7 @@ import * as zowe from "@zowe/cli"; import * as vscode from "vscode"; import * as globals from "../globals"; import { errorHandling } from "../utils/ProfilesUtils"; -import { Gui, NodeAction, IZoweDatasetTreeNode, ZoweTreeNode } from "@zowe/zowe-explorer-api"; +import { DatasetSort, DatasetStats, Gui, NodeAction, IZoweDatasetTreeNode, ZoweTreeNode } from "@zowe/zowe-explorer-api"; import { ZoweExplorerApiRegister } from "../ZoweExplorerApiRegister"; import { getIconByNode } from "../generators/icons"; import * as contextually from "../shared/context"; @@ -43,6 +43,8 @@ export class ZoweDatasetNode extends ZoweTreeNode implements IZoweDatasetTreeNod public errorDetails: zowe.imperative.ImperativeError; public ongoingActions: Record> = {}; public wasDoubleClicked: boolean = false; + public sortMethod: DatasetSort = DatasetSort.Name; + public stats: DatasetStats; /** * Creates an instance of ZoweDatasetNode @@ -77,8 +79,8 @@ export class ZoweDatasetNode extends ZoweTreeNode implements IZoweDatasetTreeNod if (icon) { this.iconPath = icon.path; } - if (!globals.ISTHEIA && this.getParent() && contextually.isSession(this.getParent())) { - this.id = `${mParent?.id ?? mParent?.label?.toString() ?? ""}.${this.label as string}`; + if (!globals.ISTHEIA && contextually.isSession(this)) { + this.id = this.label as string; } } @@ -235,6 +237,12 @@ export class ZoweDatasetNode extends ZoweTreeNode implements IZoweDatasetTreeNod msg: localize("getChildren.invalidMember", "Cannot access member with control characters in the name: {0}", item.member), }); } + if (item.m4date) { + temp.stats = { + user: item.user, + m4date: new Date(`${item.m4date.replace(/\//g, "-")}T${item.mtime as string}:${item.msec as string}`), + }; + } elementChildren[temp.label.toString()] = temp; } } @@ -253,16 +261,32 @@ export class ZoweDatasetNode extends ZoweTreeNode implements IZoweDatasetTreeNod ]; } else { const newChildren = Object.keys(elementChildren) - .sort() .filter((label) => this.children.find((c) => (c.label as string) === label) == null) .map((label) => elementChildren[label]); - this.children = this.children.concat(newChildren).filter((c) => (c.label as string) in elementChildren); + this.children = this.children + .concat(newChildren) + .filter((c) => (c.label as string) in elementChildren) + .sort(ZoweDatasetNode.sortBy(this.sortMethod)); } return this.children; } + public static sortBy(method: DatasetSort): (a: IZoweDatasetTreeNode, b: IZoweDatasetTreeNode) => number { + return (a, b): number => { + switch (method) { + case DatasetSort.LastModified: + return a.stats?.m4date < b.stats?.m4date ? -1 : 1; + case DatasetSort.UserId: + return a.stats?.user < b.stats?.user ? -1 : 1; + case DatasetSort.Name: + default: + return (a.label as string) < (b.label as string) ? -1 : 1; + } + }; + } + public getSessionNode(): IZoweDatasetTreeNode { ZoweLogger.trace("ZoweDatasetNode.getSessionNode called."); return this.getParent() ? this.getParent().getSessionNode() : this; diff --git a/packages/zowe-explorer/src/dataset/init.ts b/packages/zowe-explorer/src/dataset/init.ts index 12e81d74eb..9668ee1040 100644 --- a/packages/zowe-explorer/src/dataset/init.ts +++ b/packages/zowe-explorer/src/dataset/init.ts @@ -13,7 +13,7 @@ import * as globals from "../globals"; import * as vscode from "vscode"; import * as dsActions from "./actions"; import * as refreshActions from "../shared/refresh"; -import { IZoweDatasetTreeNode, IZoweTreeNode, IZoweTree } from "@zowe/zowe-explorer-api"; +import { IZoweDatasetTreeNode, IZoweTreeNode, IZoweTree, DatasetSort } from "@zowe/zowe-explorer-api"; import { Profiles } from "../Profiles"; import { createDatasetTree } from "./DatasetTree"; import { ZoweDatasetNode } from "./ZoweDatasetNode"; @@ -25,7 +25,7 @@ import { TreeViewUtils } from "../utils/TreeViewUtils"; export async function initDatasetProvider(context: vscode.ExtensionContext): Promise> { ZoweLogger.trace("dataset.init.initDatasetProvider called."); - const datasetProvider: IZoweTree = await createDatasetTree(globals.LOG); + const datasetProvider = await createDatasetTree(globals.LOG); if (datasetProvider == null) { return null; } @@ -37,10 +37,10 @@ export async function initDatasetProvider(context: vscode.ExtensionContext): Pro ); context.subscriptions.push(vscode.commands.registerCommand("zowe.ds.addSession", async () => datasetProvider.createZoweSession(datasetProvider))); context.subscriptions.push( - vscode.commands.registerCommand("zowe.ds.addFavorite", (node, nodeList) => { + vscode.commands.registerCommand("zowe.ds.addFavorite", async (node, nodeList) => { const selectedNodes = getSelectedNodeList(node, nodeList); for (const item of selectedNodes) { - datasetProvider.addFavorite(item); + await datasetProvider.addFavorite(item); } }) ); @@ -67,7 +67,7 @@ export async function initDatasetProvider(context: vscode.ExtensionContext): Pro } }) ); - context.subscriptions.push(vscode.commands.registerCommand("zowe.ds.pattern", (node): void => datasetProvider.filterPrompt(node))); + context.subscriptions.push(vscode.commands.registerCommand("zowe.ds.pattern", (node) => datasetProvider.filterPrompt(node))); context.subscriptions.push( vscode.commands.registerCommand("zowe.ds.editSession", async (node) => datasetProvider.editSession(node, datasetProvider)) ); @@ -126,10 +126,10 @@ export async function initDatasetProvider(context: vscode.ExtensionContext): Pro } }) ); - context.subscriptions.push(vscode.commands.registerCommand("zowe.ds.saveSearch", (node): void => datasetProvider.addFavorite(node))); - context.subscriptions.push(vscode.commands.registerCommand("zowe.ds.removeSavedSearch", (node): void => datasetProvider.removeFavorite(node))); + context.subscriptions.push(vscode.commands.registerCommand("zowe.ds.saveSearch", (node) => datasetProvider.addFavorite(node))); + context.subscriptions.push(vscode.commands.registerCommand("zowe.ds.removeSavedSearch", (node) => datasetProvider.removeFavorite(node))); context.subscriptions.push( - vscode.commands.registerCommand("zowe.ds.removeFavProfile", (node): void => datasetProvider.removeFavProfile(node.label, true)) + vscode.commands.registerCommand("zowe.ds.removeFavProfile", (node) => datasetProvider.removeFavProfile(node.label, true)) ); context.subscriptions.push(vscode.commands.registerCommand("zowe.ds.submitJcl", async () => dsActions.submitJcl(datasetProvider))); context.subscriptions.push(vscode.commands.registerCommand("zowe.ds.submitMember", async (node) => dsActions.submitMember(node))); @@ -143,7 +143,7 @@ export async function initDatasetProvider(context: vscode.ExtensionContext): Pro } }) ); - context.subscriptions.push(vscode.commands.registerCommand("zowe.ds.renameDataSet", (node): void => datasetProvider.rename(node))); + context.subscriptions.push(vscode.commands.registerCommand("zowe.ds.renameDataSet", (node) => datasetProvider.rename(node))); context.subscriptions.push( vscode.commands.registerCommand("zowe.ds.copyDataSets", async (node, nodeList) => dsActions.copyDataSets(node, nodeList, datasetProvider)) ); @@ -156,7 +156,7 @@ export async function initDatasetProvider(context: vscode.ExtensionContext): Pro await dsActions.refreshDataset(node.getParent(), datasetProvider); }) ); - context.subscriptions.push(vscode.commands.registerCommand("zowe.ds.renameDataSetMember", (node): void => datasetProvider.rename(node))); + context.subscriptions.push(vscode.commands.registerCommand("zowe.ds.renameDataSetMember", (node) => datasetProvider.rename(node))); context.subscriptions.push( vscode.commands.registerCommand("zowe.ds.hMigrateDataSet", async (node, nodeList) => { let selectedNodes = getSelectedNodeList(node, nodeList); @@ -196,11 +196,24 @@ export async function initDatasetProvider(context: vscode.ExtensionContext): Pro datasetProvider.refreshElement(node); }) ); - context.subscriptions.push(vscode.commands.registerCommand("zowe.ds.ssoLogin", (node: IZoweTreeNode): void => datasetProvider.ssoLogin(node))); - context.subscriptions.push(vscode.commands.registerCommand("zowe.ds.ssoLogout", (node: IZoweTreeNode): void => datasetProvider.ssoLogout(node))); + context.subscriptions.push(vscode.commands.registerCommand("zowe.ds.ssoLogin", (node: IZoweTreeNode) => datasetProvider.ssoLogin(node))); + context.subscriptions.push(vscode.commands.registerCommand("zowe.ds.ssoLogout", (node: IZoweTreeNode) => datasetProvider.ssoLogout(node))); context.subscriptions.push( - vscode.workspace.onDidChangeConfiguration((e) => { - datasetProvider.onDidChangeConfiguration(e); + vscode.commands.registerCommand("zowe.ds.sortByName", (node: IZoweDatasetTreeNode): void => datasetProvider.sortBy(DatasetSort.Name, node)) + ); + context.subscriptions.push( + vscode.commands.registerCommand("zowe.ds.sortByModified", (node: IZoweDatasetTreeNode): void => + datasetProvider.sortBy(DatasetSort.LastModified, node) + ) + ); + context.subscriptions.push( + vscode.commands.registerCommand("zowe.ds.sortByUserId", (node: IZoweDatasetTreeNode): void => + datasetProvider.sortBy(DatasetSort.UserId, node) + ) + ); + context.subscriptions.push( + vscode.workspace.onDidChangeConfiguration(async (e) => { + await datasetProvider.onDidChangeConfiguration(e); }) ); From 735703cb9a00d448118c6ad55712ecfb2e42266a Mon Sep 17 00:00:00 2001 From: Trae Yelovich Date: Tue, 3 Oct 2023 16:08:30 -0400 Subject: [PATCH 077/189] fix(ds): deconstruct date, time, seconds from API response Signed-off-by: Trae Yelovich --- packages/zowe-explorer/src/dataset/ZoweDatasetNode.ts | 7 +++++-- packages/zowe-explorer/src/job/ZoweJobNode.ts | 4 ++-- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/packages/zowe-explorer/src/dataset/ZoweDatasetNode.ts b/packages/zowe-explorer/src/dataset/ZoweDatasetNode.ts index a72a95b934..26d12a7904 100644 --- a/packages/zowe-explorer/src/dataset/ZoweDatasetNode.ts +++ b/packages/zowe-explorer/src/dataset/ZoweDatasetNode.ts @@ -237,10 +237,13 @@ export class ZoweDatasetNode extends ZoweTreeNode implements IZoweDatasetTreeNod msg: localize("getChildren.invalidMember", "Cannot access member with control characters in the name: {0}", item.member), }); } - if (item.m4date) { + + // get user and last modified date for sorting, if available + const { m4date, mtime, msec }: { m4date: string; mtime: string; msec: string } = item; + if (m4date) { temp.stats = { user: item.user, - m4date: new Date(`${item.m4date.replace(/\//g, "-")}T${item.mtime as string}:${item.msec as string}`), + m4date: new Date(`${m4date.replace(/\//g, "-")}T${mtime}:${msec}`), }; } elementChildren[temp.label.toString()] = temp; diff --git a/packages/zowe-explorer/src/job/ZoweJobNode.ts b/packages/zowe-explorer/src/job/ZoweJobNode.ts index 1bcc7f86f3..dc757c8b2d 100644 --- a/packages/zowe-explorer/src/job/ZoweJobNode.ts +++ b/packages/zowe-explorer/src/job/ZoweJobNode.ts @@ -89,8 +89,8 @@ export class Job extends ZoweTreeNode implements IZoweJobTreeNode { this.iconPath = icon.path; } - if (!globals.ISTHEIA && !(this instanceof Spool)) { - this.id = `${mParent?.id ?? mParent?.label?.toString() ?? ""}.${this.label as string}`; + if (!globals.ISTHEIA && contextually.isSession(this)) { + this.id = this.label as string; } } From e06bc6f4968d8a418424db22ac45ebbe67abadce Mon Sep 17 00:00:00 2001 From: Trae Yelovich Date: Tue, 3 Oct 2023 16:46:49 -0400 Subject: [PATCH 078/189] fix(ds, jobs): update node children check; adjust sortJobsBy function for session persistence (wip) Signed-off-by: Trae Yelovich --- .../zowe-explorer/src/dataset/DatasetTree.ts | 2 +- packages/zowe-explorer/src/job/actions.ts | 24 ++++++++++--------- packages/zowe-explorer/src/job/init.ts | 20 +++++++++------- 3 files changed, 25 insertions(+), 21 deletions(-) diff --git a/packages/zowe-explorer/src/dataset/DatasetTree.ts b/packages/zowe-explorer/src/dataset/DatasetTree.ts index 542587aef2..e4b691a3c3 100644 --- a/packages/zowe-explorer/src/dataset/DatasetTree.ts +++ b/packages/zowe-explorer/src/dataset/DatasetTree.ts @@ -1296,7 +1296,7 @@ export class DatasetTree extends ZoweTreeProvider implements IZoweTree 0) { + if (node.children != null) { // If children nodes already exist, sort now and avoid extra refresh node.children.sort(ZoweDatasetNode.sortBy(method)); this.nodeDataChanged(node); diff --git a/packages/zowe-explorer/src/job/actions.ts b/packages/zowe-explorer/src/job/actions.ts index b7dd81ef9e..afce5c131d 100644 --- a/packages/zowe-explorer/src/job/actions.ts +++ b/packages/zowe-explorer/src/job/actions.ts @@ -20,6 +20,7 @@ import * as nls from "vscode-nls"; import SpoolProvider, { encodeJobFile, getSpoolFiles, matchSpool } from "../SpoolProvider"; import { ZoweLogger } from "../utils/LoggerUtils"; import { getDefaultUri } from "../shared/utils"; +import { ZosJobsProvider } from "./ZosJobsProvider"; // Set up localization nls.config({ @@ -528,16 +529,17 @@ export async function cancelJobs(jobsProvider: IZoweTree, node await Gui.showMessage(localize("cancelJobs.succeeded", "Cancelled selected jobs successfully.")); } } -export async function sortJobsBy(jobs: IZoweJobTreeNode, jobsProvider: IZoweTree, key: keyof zowe.IJob): Promise { - if (jobs["children"].length == 0) { - await vscode.window.showInformationMessage("No jobs are present in the profile."); +export function sortJobsBy(session: IZoweJobTreeNode, jobsProvider: ZosJobsProvider, key: keyof zowe.IJob): void { + if (session.children != null) { + session.children.sort((x, y) => { + if (key !== "jobid" && x["job"][key] == y["job"][key]) { + return x["job"]["jobid"] > y["job"]["jobid"] ? 1 : -1; + } else { + return x["job"][key] > y["job"][key] ? 1 : -1; + } + }); + jobsProvider.nodeDataChanged(session); + } else { + jobsProvider.refreshElement(session); } - jobs["children"].sort((x, y) => { - if (key !== "jobid" && x["job"][key] == y["job"][key]) { - return x["job"]["jobid"] > y["job"]["jobid"] ? 1 : -1; - } else { - return x["job"][key] > y["job"][key] ? 1 : -1; - } - }); - jobsProvider.refresh(); } diff --git a/packages/zowe-explorer/src/job/init.ts b/packages/zowe-explorer/src/job/init.ts index 55cb416fa2..4fb0ebec2e 100644 --- a/packages/zowe-explorer/src/job/init.ts +++ b/packages/zowe-explorer/src/job/init.ts @@ -24,7 +24,7 @@ import { ZoweLogger } from "../utils/LoggerUtils"; export async function initJobsProvider(context: vscode.ExtensionContext): Promise> { ZoweLogger.trace("job.init.initJobsProvider called."); - const jobsProvider: IZoweTree = await createJobsTree(globals.LOG); + const jobsProvider = await createJobsTree(globals.LOG); if (jobsProvider == null) { return null; } @@ -103,7 +103,7 @@ export async function initJobsProvider(context: vscode.ExtensionContext): Promis context.subscriptions.push( vscode.commands.registerCommand("zowe.jobs.setJobSpool", async (session, jobId) => jobActions.focusOnJob(jobsProvider, session, jobId)) ); - context.subscriptions.push(vscode.commands.registerCommand("zowe.jobs.search", (node): void => jobsProvider.filterPrompt(node))); + context.subscriptions.push(vscode.commands.registerCommand("zowe.jobs.search", async (node): Promise => jobsProvider.filterPrompt(node))); context.subscriptions.push( vscode.commands.registerCommand("zowe.jobs.editSession", async (node): Promise => jobsProvider.editSession(node, jobsProvider)) ); @@ -123,10 +123,12 @@ export async function initJobsProvider(context: vscode.ExtensionContext): Promis } }) ); - context.subscriptions.push(vscode.commands.registerCommand("zowe.jobs.saveSearch", (node): void => jobsProvider.saveSearch(node))); - context.subscriptions.push(vscode.commands.registerCommand("zowe.jobs.removeSearchFavorite", (node): void => jobsProvider.removeFavorite(node))); + context.subscriptions.push(vscode.commands.registerCommand("zowe.jobs.saveSearch", (node): void => void jobsProvider.saveSearch(node))); context.subscriptions.push( - vscode.commands.registerCommand("zowe.jobs.removeFavProfile", (node): void => jobsProvider.removeFavProfile(node.label, true)) + vscode.commands.registerCommand("zowe.jobs.removeSearchFavorite", async (node): Promise => jobsProvider.removeFavorite(node)) + ); + context.subscriptions.push( + vscode.commands.registerCommand("zowe.jobs.removeFavProfile", async (node): Promise => jobsProvider.removeFavProfile(node.label, true)) ); context.subscriptions.push( vscode.commands.registerCommand("zowe.jobs.disableValidation", (node) => { @@ -140,8 +142,8 @@ export async function initJobsProvider(context: vscode.ExtensionContext): Promis jobsProvider.refreshElement(node); }) ); - context.subscriptions.push(vscode.commands.registerCommand("zowe.jobs.ssoLogin", (node: IZoweTreeNode): void => jobsProvider.ssoLogin(node))); - context.subscriptions.push(vscode.commands.registerCommand("zowe.jobs.ssoLogout", (node: IZoweTreeNode): void => jobsProvider.ssoLogout(node))); + context.subscriptions.push(vscode.commands.registerCommand("zowe.jobs.ssoLogin", async (node): Promise => jobsProvider.ssoLogin(node))); + context.subscriptions.push(vscode.commands.registerCommand("zowe.jobs.ssoLogout", async (node): Promise => jobsProvider.ssoLogout(node))); const spoolFileTogglePoll = (startPolling: boolean) => async (node: IZoweTreeNode, nodeList: IZoweTreeNode[]): Promise => { @@ -160,8 +162,8 @@ export async function initJobsProvider(context: vscode.ExtensionContext): Promis context.subscriptions.push(vscode.commands.registerCommand("zowe.jobs.startPolling", spoolFileTogglePoll(true))); context.subscriptions.push(vscode.commands.registerCommand("zowe.jobs.stopPolling", spoolFileTogglePoll(false))); context.subscriptions.push( - vscode.workspace.onDidChangeConfiguration((e) => { - jobsProvider.onDidChangeConfiguration(e); + vscode.workspace.onDidChangeConfiguration(async (e) => { + await jobsProvider.onDidChangeConfiguration(e); }) ); context.subscriptions.push( From 5cc3d901fa5802b1863323e22c092c0090749997 Mon Sep 17 00:00:00 2001 From: Rudy Flores <68666202+rudyflores@users.noreply.github.com> Date: Tue, 3 Oct 2023 16:56:43 -0400 Subject: [PATCH 079/189] add code coverage Signed-off-by: Rudy Flores <68666202+rudyflores@users.noreply.github.com> --- .../__unit__/utils/ProfilesUtils.unit.test.ts | 204 +++++++++++++++++- 1 file changed, 203 insertions(+), 1 deletion(-) diff --git a/packages/zowe-explorer/__tests__/__unit__/utils/ProfilesUtils.unit.test.ts b/packages/zowe-explorer/__tests__/__unit__/utils/ProfilesUtils.unit.test.ts index 9f75a0505e..02d9088bb7 100644 --- a/packages/zowe-explorer/__tests__/__unit__/utils/ProfilesUtils.unit.test.ts +++ b/packages/zowe-explorer/__tests__/__unit__/utils/ProfilesUtils.unit.test.ts @@ -680,8 +680,27 @@ describe("ProfilesUtils unit tests", () => { jest.resetAllMocks(); }); + it("should prompt and install for missing extension of custom credential manager if override defined", async () => { + const isVSCodeCredentialPluginInstalledSpy = jest.spyOn(profUtils.ProfilesUtils, "isVSCodeCredentialPluginInstalled"); + + jest.spyOn(SettingsConfig, "getDirectValue").mockReturnValueOnce(true); + jest.spyOn(profUtils.ProfilesUtils as any, "fetchRegisteredPlugins").mockImplementation(); + jest.spyOn(profUtils.ProfilesUtils, "getCredentialManagerOverride").mockReturnValue("test"); + jest.spyOn(profUtils.ProfilesUtils, "isVSCodeCredentialPluginInstalled").mockReturnValueOnce(false); + jest.spyOn(SettingsConfig, "getDirectValue").mockReturnValueOnce(true); + jest.spyOn(profUtils.ProfilesUtils, "getCredentialManagerMap").mockReturnValueOnce({ + credMgrDisplayName: "test", + credMgrPluginName: "test", + credMgrZEName: "test", + }); + jest.spyOn((profUtils as any).ProfilesUtils, "setupCustomCredentialManager").mockReturnValueOnce({}); + await expect(profUtils.ProfilesUtils.getProfileInfo()).resolves.toEqual({}); + expect(isVSCodeCredentialPluginInstalledSpy).toBeCalledTimes(1); + }); + it("should retrieve the custom credential manager", async () => { - jest.spyOn(SettingsConfig, "getDirectValue").mockReturnValueOnce(false); + jest.spyOn(SettingsConfig, "getDirectValue").mockReturnValueOnce(true); + jest.spyOn(profUtils.ProfilesUtils as any, "fetchRegisteredPlugins").mockImplementation(); jest.spyOn(profUtils.ProfilesUtils, "getCredentialManagerOverride").mockReturnValue("test"); jest.spyOn(profUtils.ProfilesUtils, "isVSCodeCredentialPluginInstalled").mockReturnValueOnce(true); jest.spyOn(SettingsConfig, "getDirectValue").mockReturnValueOnce(true); @@ -713,4 +732,187 @@ describe("ProfilesUtils unit tests", () => { await expect(profUtils.isUsingTokenAuth("test")).resolves.toEqual(false); }); }); + + describe("isVSCodeCredentialPluginInstalled", () => { + beforeEach(() => { + jest.clearAllMocks(); + jest.resetAllMocks(); + jest.restoreAllMocks(); + }); + + it("should return false if an error is thrown when getting extension from available VS Code extensions", () => { + const zoweLoggerTraceSpy = jest.spyOn(ZoweLogger, "trace"); + jest.spyOn(zowe.imperative.CredentialManagerOverride, "getCredMgrInfoByDisplayName").mockReturnValue({ + credMgrDisplayName: "test", + credMgrPluginName: "test", + credMgrZEName: "test", + }); + jest.spyOn(vscode.extensions, "getExtension").mockImplementation(() => { + throw new Error("test error"); + }); + expect(profUtils.ProfilesUtils.isVSCodeCredentialPluginInstalled("test")).toBe(false); + expect(zoweLoggerTraceSpy).toBeCalledTimes(1); + }); + }); + + describe("getCredentialManagerOverride", () => { + afterEach(() => { + jest.clearAllMocks(); + jest.resetAllMocks(); + jest.restoreAllMocks(); + }); + + it("should return the custom credential manager override if of type string", () => { + const zoweLoggerTraceSpy = jest.spyOn(ZoweLogger, "trace"); + + jest.spyOn(fs, "readFileSync").mockReturnValueOnce( + Buffer.from( + JSON.stringify({ + overrides: { + credentialManager: "My Custom Credential Manager", + }, + }) + ) + ); + Object.defineProperty(zowe.imperative.CredentialManagerOverride, "CRED_MGR_SETTING_NAME", { + value: "credentialManager", + configurable: true, + }); + + expect(profUtils.ProfilesUtils.getCredentialManagerOverride()).toBe("My Custom Credential Manager"); + expect(zoweLoggerTraceSpy).toBeCalledTimes(1); + }); + }); + + describe("setupCustomCredentialManager", () => { + afterEach(() => { + jest.clearAllMocks(); + jest.resetAllMocks(); + jest.restoreAllMocks(); + }); + + it("should return the profileInfo object with the custom credential manager constructor", async () => { + const zoweLoggerTraceSpy = jest.spyOn(ZoweLogger, "trace"); + const zoweLoggerInfoSpy = jest.spyOn(ZoweLogger, "info"); + + jest.spyOn(vscode.extensions, "getExtension").mockImplementation(); + jest.spyOn(profUtils.ProfilesUtils as any, "activateCredentialManagerOverride").mockResolvedValue(jest.fn()); + + await expect( + profUtils.ProfilesUtils["setupCustomCredentialManager"]({ + credMgrDisplayName: "test", + credMgrPluginName: "test", + credMgrZEName: "test", + }) + ).resolves.toEqual({} as zowe.imperative.ProfileInfo); + expect(zoweLoggerTraceSpy).toBeCalledTimes(2); + expect(zoweLoggerInfoSpy).toBeCalledTimes(1); + }); + }); + + describe("fetchRegisteredPlugins", () => { + afterEach(() => { + jest.clearAllMocks(); + jest.resetAllMocks(); + jest.restoreAllMocks(); + }); + + it("should not find any registered plugins and simply return", async () => { + const zoweLoggerTraceSpy = jest.spyOn(ZoweLogger, "trace"); + const updateCredentialManagerSettingSpy = jest.spyOn(profUtils.ProfilesUtils, "updateCredentialManagerSetting"); + const setDirectValueSpy = jest.spyOn(SettingsConfig, "setDirectValue"); + + jest.spyOn(zowe.imperative.CredentialManagerOverride, "getKnownCredMgrs").mockReturnValue([ + { + credMgrDisplayName: "test", + credMgrPluginName: "test", + credMgrZEName: "test", + }, + ]); + jest.spyOn(vscode.extensions, "getExtension").mockImplementation(() => { + throw new Error("test error"); + }); + + await expect(profUtils.ProfilesUtils["fetchRegisteredPlugins"]()).resolves.not.toThrow(); + expect(zoweLoggerTraceSpy).toBeCalledTimes(1); + expect(updateCredentialManagerSettingSpy).toBeCalledTimes(0); + expect(setDirectValueSpy).toBeCalledTimes(0); + }); + + it("suggest changing the override setting after finding a registered custom credential manager and selecting 'yes'", async () => { + const zoweLoggerTraceSpy = jest.spyOn(ZoweLogger, "trace"); + const updateCredentialManagerSettingSpy = jest.spyOn(profUtils.ProfilesUtils, "updateCredentialManagerSetting"); + const setDirectValueSpy = jest.spyOn(SettingsConfig, "setDirectValue"); + + jest.spyOn(zowe.imperative.CredentialManagerOverride, "getKnownCredMgrs").mockReturnValue([ + { + credMgrDisplayName: "test", + credMgrPluginName: "test", + credMgrZEName: "test", + }, + ]); + jest.spyOn(vscode.extensions, "getExtension").mockReturnValue({ + credMgrDisplayName: "test", + } as any); + jest.spyOn(Gui, "infoMessage").mockResolvedValue("Yes"); + + await expect(profUtils.ProfilesUtils["fetchRegisteredPlugins"]()).resolves.not.toThrow(); + expect(zoweLoggerTraceSpy).toBeCalledTimes(3); + expect(updateCredentialManagerSettingSpy).toBeCalledTimes(1); + expect(setDirectValueSpy).toBeCalledTimes(1); + }); + + it("suggest changing the override setting and selecting 'no' and should keep the default manager", async () => { + const zoweLoggerTraceSpy = jest.spyOn(ZoweLogger, "trace"); + const updateCredentialManagerSettingSpy = jest.spyOn(profUtils.ProfilesUtils, "updateCredentialManagerSetting"); + const setDirectValueSpy = jest.spyOn(SettingsConfig, "setDirectValue"); + + jest.spyOn(zowe.imperative.CredentialManagerOverride, "getKnownCredMgrs").mockReturnValue([ + { + credMgrDisplayName: "test", + credMgrPluginName: "test", + credMgrZEName: "test", + }, + ]); + jest.spyOn(vscode.extensions, "getExtension").mockReturnValue({ + credMgrDisplayName: "test", + } as any); + jest.spyOn(Gui, "infoMessage").mockResolvedValue("Don't ask again"); + + await expect(profUtils.ProfilesUtils["fetchRegisteredPlugins"]()).resolves.not.toThrow(); + expect(zoweLoggerTraceSpy).toBeCalledTimes(2); + expect(updateCredentialManagerSettingSpy).toBeCalledTimes(0); + expect(setDirectValueSpy).toBeCalledTimes(1); + }); + }); + + describe("promptAndHandleMissingCredentialManager", () => { + afterEach(() => { + jest.clearAllMocks(); + jest.resetAllMocks(); + jest.restoreAllMocks(); + }); + + it("should prompt to install missing custom credential manager defined in 'imperative.json'", async () => { + const zoweLoggerTraceSpy = jest.spyOn(ZoweLogger, "trace"); + const reloadWindowSpy = jest.spyOn(vscode.commands, "executeCommand"); + + jest.spyOn(Gui, "infoMessage").mockResolvedValue("Install"); + Object.defineProperty(vscode.env, "openExternal", { + value: () => true, + configurable: true, + }); + jest.spyOn(Gui, "showMessage").mockResolvedValue("Refresh"); + + await expect( + profUtils.ProfilesUtils["promptAndHandleMissingCredentialManager"]({ + credMgrDisplayName: "test", + credMgrPluginName: "test", + credMgrZEName: "test", + }) + ).resolves.not.toThrow(); + expect(zoweLoggerTraceSpy).toBeCalledTimes(1); + expect(reloadWindowSpy).toBeCalledWith("workbench.action.reloadWindow"); + }); + }); }); From 96d6dc38649bef8857089df4f0ff66d198051644 Mon Sep 17 00:00:00 2001 From: Trae Yelovich Date: Wed, 4 Oct 2023 13:46:58 -0400 Subject: [PATCH 080/189] tests(ds): Add test cases for DatasetTree.sortBy Signed-off-by: Trae Yelovich --- .../__tests__/__unit__/ZoweNode.unit.test.ts | 2 - .../__unit__/dataset/DatasetTree.unit.test.ts | 57 ++++++++++++++++++- .../__unit__/dataset/init.unit.test.ts | 14 +++++ .../__tests__/__unit__/extension.unit.test.ts | 3 + .../__unit__/job/actions.unit.test.ts | 10 ---- .../zowe-explorer/src/dataset/DatasetTree.ts | 2 +- packages/zowe-explorer/src/globals.ts | 2 +- 7 files changed, 75 insertions(+), 15 deletions(-) diff --git a/packages/zowe-explorer/__tests__/__unit__/ZoweNode.unit.test.ts b/packages/zowe-explorer/__tests__/__unit__/ZoweNode.unit.test.ts index 3bc557fb9f..72da57e2c7 100644 --- a/packages/zowe-explorer/__tests__/__unit__/ZoweNode.unit.test.ts +++ b/packages/zowe-explorer/__tests__/__unit__/ZoweNode.unit.test.ts @@ -238,7 +238,6 @@ describe("Unit Tests (Jest)", () => { undefined, profileOne ); - infoChild.id = "root.Use the search button to display data sets"; rootNode.contextValue = globals.DS_SESSION_CONTEXT; rootNode.dirty = false; await expect(await rootNode.getChildren()).toEqual([infoChild]); @@ -259,7 +258,6 @@ describe("Unit Tests (Jest)", () => { undefined, profileOne ); - infoChild.id = "root.Use the search button to display data sets"; rootNode.contextValue = globals.DS_SESSION_CONTEXT; await expect(await rootNode.getChildren()).toEqual([infoChild]); }); 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 9cb5357619..e11409d50a 100644 --- a/packages/zowe-explorer/__tests__/__unit__/dataset/DatasetTree.unit.test.ts +++ b/packages/zowe-explorer/__tests__/__unit__/dataset/DatasetTree.unit.test.ts @@ -15,7 +15,7 @@ import * as fs from "fs"; import * as zowe from "@zowe/cli"; import { DatasetTree } from "../../../src/dataset/DatasetTree"; import { ZoweDatasetNode } from "../../../src/dataset/ZoweDatasetNode"; -import { Gui, IZoweDatasetTreeNode, ProfilesCache, ValidProfileEnum } from "@zowe/zowe-explorer-api"; +import { DatasetSort, Gui, IZoweDatasetTreeNode, ProfilesCache, ValidProfileEnum } from "@zowe/zowe-explorer-api"; import { ZoweExplorerApiRegister } from "../../../src/ZoweExplorerApiRegister"; import { Profiles } from "../../../src/Profiles"; import * as utils from "../../../src/utils/ProfilesUtils"; @@ -2696,3 +2696,58 @@ describe("Dataset Tree Unit Tests - Function initializeFavorites", () => { expect(() => testTree.initializeFavorites(log)).not.toThrow(); }); }); + +describe("Dataset Tree Unit Tests - Function sortBy", () => { + const testTree = new DatasetTree(); + const mocks = { + nodeDataChanged: jest.spyOn(DatasetTree.prototype, "nodeDataChanged"), + refreshElement: jest.spyOn(DatasetTree.prototype, "refreshElement"), + }; + const testNode = new ZoweDatasetNode("test", vscode.TreeItemCollapsibleState.Collapsed, null, createISession()); + + beforeEach(() => { + testNode.children = [ + { label: "A", stats: { user: "someUser", m4date: Date.now() } } as unknown as ZoweDatasetNode, + { label: "B", stats: { user: "anotherUser", m4date: Date.parse("2022-01-01T12:00:00") } } as unknown as ZoweDatasetNode, + { label: "C", stats: { user: "someUser", m4date: Date.parse("2022-03-15T16:30:00") } } as unknown as ZoweDatasetNode, + ]; + }); + + afterEach(() => { + mocks.nodeDataChanged.mockClear(); + mocks.refreshElement.mockClear(); + }); + + afterAll(() => { + mocks.nodeDataChanged.mockRestore(); + mocks.refreshElement.mockRestore(); + }); + + it("calls refreshElement if no children exist", () => { + testNode.children = []; + testTree.sortBy(DatasetSort.Name, testNode); + expect(mocks.nodeDataChanged).not.toHaveBeenCalled(); + expect(mocks.refreshElement).toHaveBeenCalledWith(testNode); + }); + + it("sorts by name", () => { + testTree.sortBy(DatasetSort.Name, testNode); + expect(mocks.nodeDataChanged).toHaveBeenCalled(); + expect(mocks.refreshElement).not.toHaveBeenCalled(); + expect(testNode.children.map((c: IZoweDatasetTreeNode) => c.label)).toStrictEqual(["A", "B", "C"]); + }); + + it("sorts by last modified date", () => { + testTree.sortBy(DatasetSort.LastModified, testNode); + expect(mocks.nodeDataChanged).toHaveBeenCalled(); + expect(mocks.refreshElement).not.toHaveBeenCalled(); + expect(testNode.children.map((c: IZoweDatasetTreeNode) => c.label)).toStrictEqual(["B", "C", "A"]); + }); + + it("sorts by user ID", () => { + testTree.sortBy(DatasetSort.UserId, testNode); + expect(mocks.nodeDataChanged).toHaveBeenCalled(); + expect(mocks.refreshElement).not.toHaveBeenCalled(); + expect(testNode.children.map((c: IZoweDatasetTreeNode) => c.label)).toStrictEqual(["B", "A", "C"]); + }); +}); diff --git a/packages/zowe-explorer/__tests__/__unit__/dataset/init.unit.test.ts b/packages/zowe-explorer/__tests__/__unit__/dataset/init.unit.test.ts index bacbe6f822..0fc7719101 100644 --- a/packages/zowe-explorer/__tests__/__unit__/dataset/init.unit.test.ts +++ b/packages/zowe-explorer/__tests__/__unit__/dataset/init.unit.test.ts @@ -19,6 +19,7 @@ import { initDatasetProvider } from "../../../src/dataset/init"; import { Profiles } from "../../../src/Profiles"; import { IJestIt, ITestContext, processSubscriptions, spyOnSubscriptions } from "../../__common__/testUtils"; import { ZoweLogger } from "../../../src/utils/LoggerUtils"; +import { DatasetSort } from "@zowe/zowe-explorer-api"; describe("Test src/dataset/extension", () => { describe("initDatasetProvider", () => { @@ -45,6 +46,7 @@ describe("Test src/dataset/extension", () => { onDidChangeConfiguration: jest.fn(), getTreeView: jest.fn(), refreshElement: jest.fn(), + sortBy: jest.fn(), }; const commands: IJestIt[] = [ { @@ -250,6 +252,18 @@ describe("Test src/dataset/extension", () => { name: "zowe.ds.ssoLogout", mock: [{ spy: jest.spyOn(dsProvider, "ssoLogout"), arg: [test.value] }], }, + { + name: "zowe.ds.sortByName", + mock: [{ spy: jest.spyOn(dsProvider, "sortBy"), arg: [DatasetSort.Name, test.value] }], + }, + { + name: "zowe.ds.sortByModified", + mock: [{ spy: jest.spyOn(dsProvider, "sortBy"), arg: [DatasetSort.LastModified, test.value] }], + }, + { + name: "zowe.ds.sortByUserId", + mock: [{ spy: jest.spyOn(dsProvider, "sortBy"), arg: [DatasetSort.UserId, test.value] }], + }, { name: "onDidChangeConfiguration", mock: [{ spy: jest.spyOn(dsProvider, "onDidChangeConfiguration"), arg: [test.value] }], diff --git a/packages/zowe-explorer/__tests__/__unit__/extension.unit.test.ts b/packages/zowe-explorer/__tests__/__unit__/extension.unit.test.ts index 0f637993a6..fe655a8c29 100644 --- a/packages/zowe-explorer/__tests__/__unit__/extension.unit.test.ts +++ b/packages/zowe-explorer/__tests__/__unit__/extension.unit.test.ts @@ -176,6 +176,9 @@ async function createGlobalMocks() { "zowe.ds.enableValidation", "zowe.ds.ssoLogin", "zowe.ds.ssoLogout", + "zowe.ds.sortByName", + "zowe.ds.sortByModified", + "zowe.ds.sortByUserId", "zowe.uss.addFavorite", "zowe.uss.removeFavorite", "zowe.uss.addSession", diff --git a/packages/zowe-explorer/__tests__/__unit__/job/actions.unit.test.ts b/packages/zowe-explorer/__tests__/__unit__/job/actions.unit.test.ts index 85737a5c89..16851a1b32 100644 --- a/packages/zowe-explorer/__tests__/__unit__/job/actions.unit.test.ts +++ b/packages/zowe-explorer/__tests__/__unit__/job/actions.unit.test.ts @@ -1348,16 +1348,6 @@ describe("sortjobsby function", () => { afterEach(() => { jest.restoreAllMocks(); }); - it("if there are no jobs in the zosmf level yet", async () => { - createGlobalMocks(); - const testtree = new ZosJobsProvider(); - //act - await jobActions.sortJobsBy(testtree.mSessionNodes[0], testtree, "jobname"); - await jobActions.sortJobsBy(testtree.mSessionNodes[0], testtree, "jobid"); - await jobActions.sortJobsBy(testtree.mSessionNodes[0], testtree, "retcode"); - //assert - expect(mocked(vscode.window.showInformationMessage)).toBeCalled(); - }); it("sort by name if same sort by increasing id", async () => { const globalMocks = createGlobalMocks(); const testtree = new ZosJobsProvider(); diff --git a/packages/zowe-explorer/src/dataset/DatasetTree.ts b/packages/zowe-explorer/src/dataset/DatasetTree.ts index e4b691a3c3..be15b95964 100644 --- a/packages/zowe-explorer/src/dataset/DatasetTree.ts +++ b/packages/zowe-explorer/src/dataset/DatasetTree.ts @@ -1296,7 +1296,7 @@ export class DatasetTree extends ZoweTreeProvider implements IZoweTree 0) { // If children nodes already exist, sort now and avoid extra refresh node.children.sort(ZoweDatasetNode.sortBy(method)); this.nodeDataChanged(node); diff --git a/packages/zowe-explorer/src/globals.ts b/packages/zowe-explorer/src/globals.ts index a503fe7332..596308f59c 100644 --- a/packages/zowe-explorer/src/globals.ts +++ b/packages/zowe-explorer/src/globals.ts @@ -35,7 +35,7 @@ export let DS_DIR: string; export let CONFIG_PATH; // set during activate export let ISTHEIA = false; // set during activate export let LOG: imperative.Logger; -export const COMMAND_COUNT = 113; +export const COMMAND_COUNT = 116; export const MAX_SEARCH_HISTORY = 5; export const MAX_FILE_HISTORY = 10; export const MS_PER_SEC = 1000; From 3409f3147959af656e9eda97dd46e9e144d96339 Mon Sep 17 00:00:00 2001 From: Trae Yelovich Date: Thu, 5 Oct 2023 09:26:59 -0400 Subject: [PATCH 081/189] ds: move 'Sort by' options to session context menu Signed-off-by: Trae Yelovich --- .../i18n/sample/package.i18n.json | 5 ++- packages/zowe-explorer/package.json | 42 ++++++++++++------- packages/zowe-explorer/package.nls.json | 5 ++- .../zowe-explorer/src/dataset/DatasetTree.ts | 17 ++++---- .../src/dataset/ZoweDatasetNode.ts | 8 +++- packages/zowe-explorer/src/dataset/init.ts | 19 +++++---- 6 files changed, 61 insertions(+), 35 deletions(-) diff --git a/packages/zowe-explorer/i18n/sample/package.i18n.json b/packages/zowe-explorer/i18n/sample/package.i18n.json index c157c7a0a2..3b4eee2b5a 100644 --- a/packages/zowe-explorer/i18n/sample/package.i18n.json +++ b/packages/zowe-explorer/i18n/sample/package.i18n.json @@ -147,8 +147,9 @@ "createZoweSchema.reload.infoMessage": "Team Configuration file created. Location: {0}. \n Please reload your window.", "copyFile": "Copy", "pasteFile": "Paste", - "jobs.sortbyreturncode": "Sort by Return Code", - "jobs.sortbyid": "Sort by ID", + "jobs.sortByReturnCode": "Sort by Return Code", + "jobs.sortById": "Sort by ID", + "jobs.sortByDateSubmitted": "Sort by Date Submitted", "sortByName": "Sort by Name", "ds.sortByUserId": "Sort by User ID", "ds.sortByModified": "Sort by Date Modified" diff --git a/packages/zowe-explorer/package.json b/packages/zowe-explorer/package.json index 8d5a227b12..9c4632466e 100644 --- a/packages/zowe-explorer/package.json +++ b/packages/zowe-explorer/package.json @@ -122,18 +122,23 @@ ], "commands": [ { - "command": "zowe.jobs.sortbyreturncode", - "title": "%jobs.sortbyreturncode%", + "command": "zowe.jobs.sortByReturnCode", + "title": "%jobs.sortByReturnCode%", "category": "Zowe Explorer" }, { - "command": "zowe.jobs.sortbyname", + "command": "zowe.jobs.sortByName", "title": "%sortByName%", "category": "Zowe Explorer" }, { - "command": "zowe.jobs.sortbyid", - "title": "%jobs.sortbyid%", + "command": "zowe.jobs.sortById", + "title": "%jobs.sortById%", + "category": "Zowe Explorer" + }, + { + "command": "zowe.jobs.sortByDateSubmitted", + "title": "%jobs.sortByDateSubmitted%", "category": "Zowe Explorer" }, { @@ -1124,19 +1129,19 @@ "group": "002_zowe_dsWorkspace@4" }, { - "when": "view == zowe.ds.explorer && viewItem =~ /^(pds).*/ && !listMultiSelection", - "command": "zowe.ds.sortByModified", - "group": "003_zowe_dsSort@1" + "when": "view == zowe.ds.explorer && viewItem =~ /^session.*/ && !listMultiSelection", + "command": "zowe.ds.sortByName", + "group": "003_zowe_dsSort@0" }, { - "when": "view == zowe.ds.explorer && viewItem =~ /^(pds).*/ && !listMultiSelection", - "command": "zowe.ds.sortByName", - "group": "003_zowe_dsSort@2" + "when": "view == zowe.ds.explorer && viewItem =~ /^session.*/ && !listMultiSelection", + "command": "zowe.ds.sortByModified", + "group": "003_zowe_dsSort@1" }, { - "when": "view == zowe.ds.explorer && viewItem =~ /^(pds).*/ && !listMultiSelection", + "when": "view == zowe.ds.explorer && viewItem =~ /^session.*/ && !listMultiSelection", "command": "zowe.ds.sortByUserId", - "group": "003_zowe_dsSort@3" + "group": "003_zowe_dsSort@2" }, { "when": "view == zowe.ds.explorer && viewItem =~ /^fileError.*/", @@ -1405,18 +1410,23 @@ }, { "when": "view == zowe.jobs.explorer && viewItem =~ /^(?!.*_fav.*)server.*/ && !listMultiSelection", - "command": "zowe.jobs.sortbyid", + "command": "zowe.jobs.sortById", "group": "000_zowe_jobsProfileModification@1" }, { "when": "view == zowe.jobs.explorer && viewItem =~ /^(?!.*_fav.*)server.*/ && !listMultiSelection", - "command": "zowe.jobs.sortbyname", + "command": "zowe.jobs.sortByName", "group": "000_zowe_jobsProfileModification@2" }, { "when": "view == zowe.jobs.explorer && viewItem =~ /^(?!.*_fav.*)server.*/ && !listMultiSelection", - "command": "zowe.jobs.sortbyreturncode", + "command": "zowe.jobs.sortByReturnCode", "group": "000_zowe_jobsProfileModification@2" + }, + { + "when": "view == zowe.jobs.explorer && viewItem =~ /^(?!.*_fav.*)server.*/ && !listMultiSelection", + "command": "zowe.jobs.sortByDateSubmitted", + "group": "000_zowe_jobsProfileModification@3" } ], "commandPalette": [ diff --git a/packages/zowe-explorer/package.nls.json b/packages/zowe-explorer/package.nls.json index c157c7a0a2..3b4eee2b5a 100644 --- a/packages/zowe-explorer/package.nls.json +++ b/packages/zowe-explorer/package.nls.json @@ -147,8 +147,9 @@ "createZoweSchema.reload.infoMessage": "Team Configuration file created. Location: {0}. \n Please reload your window.", "copyFile": "Copy", "pasteFile": "Paste", - "jobs.sortbyreturncode": "Sort by Return Code", - "jobs.sortbyid": "Sort by ID", + "jobs.sortByReturnCode": "Sort by Return Code", + "jobs.sortById": "Sort by ID", + "jobs.sortByDateSubmitted": "Sort by Date Submitted", "sortByName": "Sort by Name", "ds.sortByUserId": "Sort by User ID", "ds.sortByModified": "Sort by Date Modified" diff --git a/packages/zowe-explorer/src/dataset/DatasetTree.ts b/packages/zowe-explorer/src/dataset/DatasetTree.ts index be15b95964..b8679fa2f9 100644 --- a/packages/zowe-explorer/src/dataset/DatasetTree.ts +++ b/packages/zowe-explorer/src/dataset/DatasetTree.ts @@ -1290,16 +1290,19 @@ export class DatasetTree extends ZoweTreeProvider implements IZoweTree 0) { - // If children nodes already exist, sort now and avoid extra refresh - node.children.sort(ZoweDatasetNode.sortBy(method)); - this.nodeDataChanged(node); + // children nodes already exist, sort and repaint to avoid extra refresh + for (const c of node.children) { + if (contextually.isPds(c) && c.children) { + c.children.sort(ZoweDatasetNode.sortBy(method)); + this.nodeDataChanged(c); + } + } } else { this.refreshElement(node); } diff --git a/packages/zowe-explorer/src/dataset/ZoweDatasetNode.ts b/packages/zowe-explorer/src/dataset/ZoweDatasetNode.ts index 26d12a7904..f334917162 100644 --- a/packages/zowe-explorer/src/dataset/ZoweDatasetNode.ts +++ b/packages/zowe-explorer/src/dataset/ZoweDatasetNode.ts @@ -270,7 +270,7 @@ export class ZoweDatasetNode extends ZoweTreeNode implements IZoweDatasetTreeNod this.children = this.children .concat(newChildren) .filter((c) => (c.label as string) in elementChildren) - .sort(ZoweDatasetNode.sortBy(this.sortMethod)); + .sort(ZoweDatasetNode.sortBy(this.getSessionNode().sortMethod ?? DatasetSort.Name)); } return this.children; @@ -278,6 +278,12 @@ export class ZoweDatasetNode extends ZoweTreeNode implements IZoweDatasetTreeNod public static sortBy(method: DatasetSort): (a: IZoweDatasetTreeNode, b: IZoweDatasetTreeNode) => number { return (a, b): number => { + // we can only sort PDS members, compared nodes are at same level (same parent) + const aParent = a.getParent(); + if (aParent == null || !contextually.isPds(aParent)) { + return (a.label as string) < (b.label as string) ? -1 : 1; + } + switch (method) { case DatasetSort.LastModified: return a.stats?.m4date < b.stats?.m4date ? -1 : 1; diff --git a/packages/zowe-explorer/src/dataset/init.ts b/packages/zowe-explorer/src/dataset/init.ts index 9668ee1040..61275cb3de 100644 --- a/packages/zowe-explorer/src/dataset/init.ts +++ b/packages/zowe-explorer/src/dataset/init.ts @@ -199,17 +199,22 @@ export async function initDatasetProvider(context: vscode.ExtensionContext): Pro context.subscriptions.push(vscode.commands.registerCommand("zowe.ds.ssoLogin", (node: IZoweTreeNode) => datasetProvider.ssoLogin(node))); context.subscriptions.push(vscode.commands.registerCommand("zowe.ds.ssoLogout", (node: IZoweTreeNode) => datasetProvider.ssoLogout(node))); context.subscriptions.push( - vscode.commands.registerCommand("zowe.ds.sortByName", (node: IZoweDatasetTreeNode): void => datasetProvider.sortBy(DatasetSort.Name, node)) + vscode.commands.registerCommand("zowe.ds.sortByName", (node: IZoweDatasetTreeNode): void => { + node.sortMethod = DatasetSort.Name; + datasetProvider.sortPdsBy(node.sortMethod, node); + }) ); context.subscriptions.push( - vscode.commands.registerCommand("zowe.ds.sortByModified", (node: IZoweDatasetTreeNode): void => - datasetProvider.sortBy(DatasetSort.LastModified, node) - ) + vscode.commands.registerCommand("zowe.ds.sortByModified", (node: IZoweDatasetTreeNode): void => { + node.sortMethod = DatasetSort.LastModified; + datasetProvider.sortPdsBy(node.sortMethod, node); + }) ); context.subscriptions.push( - vscode.commands.registerCommand("zowe.ds.sortByUserId", (node: IZoweDatasetTreeNode): void => - datasetProvider.sortBy(DatasetSort.UserId, node) - ) + vscode.commands.registerCommand("zowe.ds.sortByUserId", (node: IZoweDatasetTreeNode): void => { + node.sortMethod = DatasetSort.UserId; + datasetProvider.sortPdsBy(node.sortMethod, node); + }) ); context.subscriptions.push( vscode.workspace.onDidChangeConfiguration(async (e) => { From 12dfac5d70b82d2364353acc80856a85a0301680 Mon Sep 17 00:00:00 2001 From: Trae Yelovich Date: Thu, 5 Oct 2023 10:15:50 -0400 Subject: [PATCH 082/189] ds: Change sort UX to single menu option Signed-off-by: Trae Yelovich --- .../i18n/sample/package.i18n.json | 7 +++-- .../sample/src/dataset/DatasetTree.i18n.json | 4 +++ packages/zowe-explorer/package.json | 26 +++--------------- packages/zowe-explorer/package.nls.json | 7 +++-- .../zowe-explorer/src/dataset/DatasetTree.ts | 27 +++++++++++++++++-- packages/zowe-explorer/src/dataset/init.ts | 21 ++------------- 6 files changed, 44 insertions(+), 48 deletions(-) diff --git a/packages/zowe-explorer/i18n/sample/package.i18n.json b/packages/zowe-explorer/i18n/sample/package.i18n.json index 3b4eee2b5a..7d47977f3c 100644 --- a/packages/zowe-explorer/i18n/sample/package.i18n.json +++ b/packages/zowe-explorer/i18n/sample/package.i18n.json @@ -151,6 +151,9 @@ "jobs.sortById": "Sort by ID", "jobs.sortByDateSubmitted": "Sort by Date Submitted", "sortByName": "Sort by Name", - "ds.sortByUserId": "Sort by User ID", - "ds.sortByModified": "Sort by Date Modified" + "ds.selectSortOpt": "Select a sorting option for PDS members in {0}.", + "ds.sortBy": "Sort by...", + "ds.sortByName": "Name", + "ds.sortByModified": "Date Modified", + "ds.sortByUserId": "User ID" } diff --git a/packages/zowe-explorer/i18n/sample/src/dataset/DatasetTree.i18n.json b/packages/zowe-explorer/i18n/sample/src/dataset/DatasetTree.i18n.json index 53eff9a390..37581454c9 100644 --- a/packages/zowe-explorer/i18n/sample/src/dataset/DatasetTree.i18n.json +++ b/packages/zowe-explorer/i18n/sample/src/dataset/DatasetTree.i18n.json @@ -26,5 +26,9 @@ "renameDataSet.log.debug": "Renaming data set ", "renameDataSet.error": "Unable to rename data set:", "dataset.validation": "Enter a valid data set name.", + "ds.sortByName": "Name", + "ds.sortByModified": "Date Modified", + "ds.sortByUserId": "User ID", + "ds.selectSortOpt": "Select a sorting option for PDS members in {0}.", "defaultFilterPrompt.option.prompt.search": "$(plus) Create a new filter. For example: HLQ.*, HLQ.aaa.bbb, HLQ.ccc.ddd(member)" } diff --git a/packages/zowe-explorer/package.json b/packages/zowe-explorer/package.json index 9c4632466e..fdef40a450 100644 --- a/packages/zowe-explorer/package.json +++ b/packages/zowe-explorer/package.json @@ -282,18 +282,8 @@ "category": "Zowe Explorer" }, { - "command": "zowe.ds.sortByName", - "title": "%sortByName%", - "category": "Zowe Explorer" - }, - { - "command": "zowe.ds.sortByModified", - "title": "%ds.sortByModified%", - "category": "Zowe Explorer" - }, - { - "command": "zowe.ds.sortByUserId", - "title": "%ds.sortByUserId%", + "command": "zowe.ds.sortBy", + "title": "%ds.sortBy%", "category": "Zowe Explorer" }, { @@ -1130,19 +1120,9 @@ }, { "when": "view == zowe.ds.explorer && viewItem =~ /^session.*/ && !listMultiSelection", - "command": "zowe.ds.sortByName", + "command": "zowe.ds.sortBy", "group": "003_zowe_dsSort@0" }, - { - "when": "view == zowe.ds.explorer && viewItem =~ /^session.*/ && !listMultiSelection", - "command": "zowe.ds.sortByModified", - "group": "003_zowe_dsSort@1" - }, - { - "when": "view == zowe.ds.explorer && viewItem =~ /^session.*/ && !listMultiSelection", - "command": "zowe.ds.sortByUserId", - "group": "003_zowe_dsSort@2" - }, { "when": "view == zowe.ds.explorer && viewItem =~ /^fileError.*/", "command": "zowe.ds.showFileErrorDetails", diff --git a/packages/zowe-explorer/package.nls.json b/packages/zowe-explorer/package.nls.json index 3b4eee2b5a..7d47977f3c 100644 --- a/packages/zowe-explorer/package.nls.json +++ b/packages/zowe-explorer/package.nls.json @@ -151,6 +151,9 @@ "jobs.sortById": "Sort by ID", "jobs.sortByDateSubmitted": "Sort by Date Submitted", "sortByName": "Sort by Name", - "ds.sortByUserId": "Sort by User ID", - "ds.sortByModified": "Sort by Date Modified" + "ds.selectSortOpt": "Select a sorting option for PDS members in {0}.", + "ds.sortBy": "Sort by...", + "ds.sortByName": "Name", + "ds.sortByModified": "Date Modified", + "ds.sortByUserId": "User ID" } diff --git a/packages/zowe-explorer/src/dataset/DatasetTree.ts b/packages/zowe-explorer/src/dataset/DatasetTree.ts index b8679fa2f9..fbe9181ac4 100644 --- a/packages/zowe-explorer/src/dataset/DatasetTree.ts +++ b/packages/zowe-explorer/src/dataset/DatasetTree.ts @@ -1294,12 +1294,35 @@ export class DatasetTree extends ZoweTreeProvider implements IZoweTree { + const options = [localize("ds.sortByName", "Name"), localize("ds.sortByModified", "Date Modified"), localize("ds.sortByUserId", "User ID")]; + + const selection = await Gui.showQuickPick(options, { + placeHolder: localize("ds.selectSortOpt", "Select a sorting option for PDS members in {0}.", node.label as string), + }); + if (selection == null) { + return; + } + + switch (selection) { + case options[0]: + node.sortMethod = DatasetSort.Name; + break; + case options[1]: + node.sortMethod = DatasetSort.LastModified; + break; + case options[2]: + node.sortMethod = DatasetSort.UserId; + break; + default: + return; + } + if (node.children != null && node.children.length > 0) { // children nodes already exist, sort and repaint to avoid extra refresh for (const c of node.children) { if (contextually.isPds(c) && c.children) { - c.children.sort(ZoweDatasetNode.sortBy(method)); + c.children.sort(ZoweDatasetNode.sortBy(node.sortMethod)); this.nodeDataChanged(c); } } diff --git a/packages/zowe-explorer/src/dataset/init.ts b/packages/zowe-explorer/src/dataset/init.ts index 61275cb3de..a1ca9e9e3b 100644 --- a/packages/zowe-explorer/src/dataset/init.ts +++ b/packages/zowe-explorer/src/dataset/init.ts @@ -13,7 +13,7 @@ import * as globals from "../globals"; import * as vscode from "vscode"; import * as dsActions from "./actions"; import * as refreshActions from "../shared/refresh"; -import { IZoweDatasetTreeNode, IZoweTreeNode, IZoweTree, DatasetSort } from "@zowe/zowe-explorer-api"; +import { IZoweDatasetTreeNode, IZoweTreeNode, IZoweTree } from "@zowe/zowe-explorer-api"; import { Profiles } from "../Profiles"; import { createDatasetTree } from "./DatasetTree"; import { ZoweDatasetNode } from "./ZoweDatasetNode"; @@ -198,24 +198,7 @@ export async function initDatasetProvider(context: vscode.ExtensionContext): Pro ); context.subscriptions.push(vscode.commands.registerCommand("zowe.ds.ssoLogin", (node: IZoweTreeNode) => datasetProvider.ssoLogin(node))); context.subscriptions.push(vscode.commands.registerCommand("zowe.ds.ssoLogout", (node: IZoweTreeNode) => datasetProvider.ssoLogout(node))); - context.subscriptions.push( - vscode.commands.registerCommand("zowe.ds.sortByName", (node: IZoweDatasetTreeNode): void => { - node.sortMethod = DatasetSort.Name; - datasetProvider.sortPdsBy(node.sortMethod, node); - }) - ); - context.subscriptions.push( - vscode.commands.registerCommand("zowe.ds.sortByModified", (node: IZoweDatasetTreeNode): void => { - node.sortMethod = DatasetSort.LastModified; - datasetProvider.sortPdsBy(node.sortMethod, node); - }) - ); - context.subscriptions.push( - vscode.commands.registerCommand("zowe.ds.sortByUserId", (node: IZoweDatasetTreeNode): void => { - node.sortMethod = DatasetSort.UserId; - datasetProvider.sortPdsBy(node.sortMethod, node); - }) - ); + context.subscriptions.push(vscode.commands.registerCommand("zowe.ds.sortBy", (node: IZoweDatasetTreeNode) => datasetProvider.sortPdsBy(node))); context.subscriptions.push( vscode.workspace.onDidChangeConfiguration(async (e) => { await datasetProvider.onDidChangeConfiguration(e); From 5af78cd22414c22cb064de1215e4cd65c4fef6ac Mon Sep 17 00:00:00 2001 From: Trae Yelovich Date: Thu, 5 Oct 2023 10:36:38 -0400 Subject: [PATCH 083/189] ds: Update sorting UX to use inline icon beside session Signed-off-by: Trae Yelovich --- packages/zowe-explorer/package.json | 26 +++++++++++++++---------- packages/zowe-explorer/package.nls.json | 2 +- 2 files changed, 17 insertions(+), 11 deletions(-) diff --git a/packages/zowe-explorer/package.json b/packages/zowe-explorer/package.json index fdef40a450..7979832f9b 100644 --- a/packages/zowe-explorer/package.json +++ b/packages/zowe-explorer/package.json @@ -284,7 +284,8 @@ { "command": "zowe.ds.sortBy", "title": "%ds.sortBy%", - "category": "Zowe Explorer" + "category": "Zowe Explorer", + "icon": "$(list-ordered)" }, { "command": "zowe.cmd.deleteProfile", @@ -1003,10 +1004,15 @@ "command": "zowe.uss.deleteProfile", "group": "099_zowe_ussProfileModification@99" }, + { + "when": "view == zowe.ds.explorer && viewItem =~ /^session.*/ && !listMultiSelection", + "command": "zowe.ds.sortBy", + "group": "inline@0" + }, { "when": "view == zowe.ds.explorer && viewItem =~ /^(?!.*_fav.*)session.*/ && !listMultiSelection", "command": "zowe.ds.pattern", - "group": "inline" + "group": "inline@1" }, { "when": "view == zowe.ds.explorer && viewItem =~ /^(pds|ds|migr).*_fav.*/", @@ -1118,11 +1124,6 @@ "command": "zowe.ds.removeFavProfile", "group": "002_zowe_dsWorkspace@4" }, - { - "when": "view == zowe.ds.explorer && viewItem =~ /^session.*/ && !listMultiSelection", - "command": "zowe.ds.sortBy", - "group": "003_zowe_dsSort@0" - }, { "when": "view == zowe.ds.explorer && viewItem =~ /^fileError.*/", "command": "zowe.ds.showFileErrorDetails", @@ -1208,20 +1209,25 @@ "command": "zowe.ds.ssoLogout", "group": "098_zowe_dsProfileAuthentication@10" }, + { + "when": "view == zowe.ds.explorer && viewItem =~ /^session.*/ && !listMultiSelection", + "command": "zowe.ds.sortBy", + "group": "099_zowe_dsSort" + }, { "when": "view == zowe.ds.explorer && viewItem =~ /^(?!.*_fav.*)session.*/ && !listMultiSelection", "command": "zowe.ds.editSession", - "group": "099_zowe_dsProfileModification@0" + "group": "100_zowe_dsProfileModification@0" }, { "when": "view == zowe.ds.explorer && viewItem =~ /^(?!.*_fav.*)session.*/", "command": "zowe.ds.removeSession", - "group": "099_zowe_dsProfileModification@98" + "group": "100_zowe_dsProfileModification@98" }, { "when": "view == zowe.ds.explorer && viewItem =~ /^(?!.*_fav.*)session.*/ && !listMultiSelection", "command": "zowe.ds.deleteProfile", - "group": "099_zowe_dsProfileModification@99" + "group": "100_zowe_dsProfileModification@99" }, { "when": "view == zowe.jobs.explorer && viewItem =~ /^(?!.*_fav.*)server.*/ && !listMultiSelection", diff --git a/packages/zowe-explorer/package.nls.json b/packages/zowe-explorer/package.nls.json index 7d47977f3c..27bc42848e 100644 --- a/packages/zowe-explorer/package.nls.json +++ b/packages/zowe-explorer/package.nls.json @@ -152,7 +152,7 @@ "jobs.sortByDateSubmitted": "Sort by Date Submitted", "sortByName": "Sort by Name", "ds.selectSortOpt": "Select a sorting option for PDS members in {0}.", - "ds.sortBy": "Sort by...", + "ds.sortBy": "Sort PDS members...", "ds.sortByName": "Name", "ds.sortByModified": "Date Modified", "ds.sortByUserId": "User ID" From 3fb7cda38d1a5f5bbadb8f1fb2b1e9b92eb36ce1 Mon Sep 17 00:00:00 2001 From: Trae Yelovich Date: Thu, 5 Oct 2023 16:21:59 -0400 Subject: [PATCH 084/189] fix(ds, jobs): Add session-level and per-PDS sort, cache job sort method - Converted "Sort jobs" feature to use a quick pick and icon - Added "selected" checkmark beside active sorting method for DS & jobs - Optimized job sorting by avoiding refresh if children exist - Adjusted localized strings for jobs and DS sorting Signed-off-by: Trae Yelovich --- .../src/tree/IZoweTreeNode.ts | 27 +++++--- .../i18n/sample/package.i18n.json | 12 +--- .../sample/src/dataset/DatasetTree.i18n.json | 7 +- .../i18n/sample/src/dataset/utils.i18n.json | 5 ++ .../i18n/sample/src/job/actions.i18n.json | 3 +- .../i18n/sample/src/job/utils.i18n.json | 6 ++ packages/zowe-explorer/package.json | 68 ++++++------------ packages/zowe-explorer/package.nls.json | 15 ++-- .../zowe-explorer/src/dataset/DatasetTree.ts | 69 +++++++++++-------- .../src/dataset/ZoweDatasetNode.ts | 28 +++++--- packages/zowe-explorer/src/dataset/init.ts | 4 +- packages/zowe-explorer/src/dataset/utils.ts | 14 ++++ .../zowe-explorer/src/job/ZosJobsProvider.ts | 13 +++- packages/zowe-explorer/src/job/ZoweJobNode.ts | 26 +++---- packages/zowe-explorer/src/job/actions.ts | 30 ++++---- packages/zowe-explorer/src/job/init.ts | 6 +- packages/zowe-explorer/src/job/utils.ts | 24 +++++++ 17 files changed, 208 insertions(+), 149 deletions(-) create mode 100644 packages/zowe-explorer/i18n/sample/src/dataset/utils.i18n.json create mode 100644 packages/zowe-explorer/i18n/sample/src/job/utils.i18n.json diff --git a/packages/zowe-explorer-api/src/tree/IZoweTreeNode.ts b/packages/zowe-explorer-api/src/tree/IZoweTreeNode.ts index d2ff45e178..6a997e9719 100644 --- a/packages/zowe-explorer-api/src/tree/IZoweTreeNode.ts +++ b/packages/zowe-explorer-api/src/tree/IZoweTreeNode.ts @@ -20,17 +20,24 @@ export enum NodeAction { Download = "download", } -export enum DatasetSort { - LastModified, - Name, - UserId, -} - export type DatasetStats = { user: string; m4date: Date; }; +export enum DatasetSortOpts { + Name, + LastModified, + UserId, +} + +export enum JobSortOpts { + Id, + DateSubmitted, + Name, + ReturnCode, +} + /** * The base interface for Zowe tree nodes that are implemented by vscode.TreeItem. * @@ -89,6 +96,10 @@ export interface IZoweTreeNode { * whether the node was double-clicked */ wasDoubleClicked?: boolean; + /** + * Sorting method for this node's children + */ + sortMethod?: DatasetSortOpts | JobSortOpts; /** * Retrieves the node label */ @@ -146,10 +157,6 @@ export interface IZoweDatasetTreeNode extends IZoweTreeNode { * Search criteria for a Dataset member search */ memberPattern?: string; - /** - * Sort members of a node by the given sorting method - */ - sortMethod?: DatasetSort; /** * Additional statistics about this data set */ diff --git a/packages/zowe-explorer/i18n/sample/package.i18n.json b/packages/zowe-explorer/i18n/sample/package.i18n.json index 7d47977f3c..a9ce9a9d1a 100644 --- a/packages/zowe-explorer/i18n/sample/package.i18n.json +++ b/packages/zowe-explorer/i18n/sample/package.i18n.json @@ -147,13 +147,7 @@ "createZoweSchema.reload.infoMessage": "Team Configuration file created. Location: {0}. \n Please reload your window.", "copyFile": "Copy", "pasteFile": "Paste", - "jobs.sortByReturnCode": "Sort by Return Code", - "jobs.sortById": "Sort by ID", - "jobs.sortByDateSubmitted": "Sort by Date Submitted", - "sortByName": "Sort by Name", - "ds.selectSortOpt": "Select a sorting option for PDS members in {0}.", - "ds.sortBy": "Sort by...", - "ds.sortByName": "Name", - "ds.sortByModified": "Date Modified", - "ds.sortByUserId": "User ID" + "jobs.sortBy": "Sort jobs...", + "jobs.selectSortOpt": "Select a sorting option for jobs in {0}", + "ds.sortBy": "Sort PDS members..." } diff --git a/packages/zowe-explorer/i18n/sample/src/dataset/DatasetTree.i18n.json b/packages/zowe-explorer/i18n/sample/src/dataset/DatasetTree.i18n.json index 37581454c9..ffdd605c77 100644 --- a/packages/zowe-explorer/i18n/sample/src/dataset/DatasetTree.i18n.json +++ b/packages/zowe-explorer/i18n/sample/src/dataset/DatasetTree.i18n.json @@ -26,9 +26,8 @@ "renameDataSet.log.debug": "Renaming data set ", "renameDataSet.error": "Unable to rename data set:", "dataset.validation": "Enter a valid data set name.", - "ds.sortByName": "Name", - "ds.sortByModified": "Date Modified", - "ds.sortByUserId": "User ID", - "ds.selectSortOpt": "Select a sorting option for PDS members in {0}.", + "ds.allPdsSort": "all PDS members in {0}", + "ds.singlePdsSort": "the PDS members in {0}", + "ds.selectSortOpt": "Select a sorting option for {0}", "defaultFilterPrompt.option.prompt.search": "$(plus) Create a new filter. For example: HLQ.*, HLQ.aaa.bbb, HLQ.ccc.ddd(member)" } diff --git a/packages/zowe-explorer/i18n/sample/src/dataset/utils.i18n.json b/packages/zowe-explorer/i18n/sample/src/dataset/utils.i18n.json new file mode 100644 index 0000000000..55ee3b4e20 --- /dev/null +++ b/packages/zowe-explorer/i18n/sample/src/dataset/utils.i18n.json @@ -0,0 +1,5 @@ +{ + "ds.sortByName": "Name", + "ds.sortByModified": "Date Modified", + "ds.sortByUserId": "User ID" +} diff --git a/packages/zowe-explorer/i18n/sample/src/job/actions.i18n.json b/packages/zowe-explorer/i18n/sample/src/job/actions.i18n.json index f1c4dad3d1..d8c3c6dc48 100644 --- a/packages/zowe-explorer/i18n/sample/src/job/actions.i18n.json +++ b/packages/zowe-explorer/i18n/sample/src/job/actions.i18n.json @@ -21,5 +21,6 @@ "cancelJobs.notImplemented": "The cancel function is not implemented in this API.", "cancelJobs.notCancelled": "The job was not cancelled.", "cancelJobs.failed": "One or more jobs failed to cancel: {0}", - "cancelJobs.succeeded": "Cancelled selected jobs successfully." + "cancelJobs.succeeded": "Cancelled selected jobs successfully.", + "jobs.selectSortOpt": "Select a sorting option for jobs in {0}" } diff --git a/packages/zowe-explorer/i18n/sample/src/job/utils.i18n.json b/packages/zowe-explorer/i18n/sample/src/job/utils.i18n.json new file mode 100644 index 0000000000..79f5b24932 --- /dev/null +++ b/packages/zowe-explorer/i18n/sample/src/job/utils.i18n.json @@ -0,0 +1,6 @@ +{ + "jobs.sortById": "Job ID", + "jobs.sortByDateSubmitted": "Date Submitted", + "jobs.sortByName": "Job Name", + "jobs.sortByReturnCode": "Return Code" +} diff --git a/packages/zowe-explorer/package.json b/packages/zowe-explorer/package.json index 7979832f9b..b68bd36e13 100644 --- a/packages/zowe-explorer/package.json +++ b/packages/zowe-explorer/package.json @@ -122,24 +122,10 @@ ], "commands": [ { - "command": "zowe.jobs.sortByReturnCode", - "title": "%jobs.sortByReturnCode%", - "category": "Zowe Explorer" - }, - { - "command": "zowe.jobs.sortByName", - "title": "%sortByName%", - "category": "Zowe Explorer" - }, - { - "command": "zowe.jobs.sortById", - "title": "%jobs.sortById%", - "category": "Zowe Explorer" - }, - { - "command": "zowe.jobs.sortByDateSubmitted", - "title": "%jobs.sortByDateSubmitted%", - "category": "Zowe Explorer" + "command": "zowe.jobs.sortBy", + "title": "%jobs.sortBy%", + "category": "Zowe Explorer", + "icon": "$(list-ordered)" }, { "command": "zowe.promptCredentials", @@ -1137,7 +1123,7 @@ { "when": "view == zowe.ds.explorer && viewItem =~ /^(ds.*|^pds.*)/", "command": "zowe.ds.hMigrateDataSet", - "group": "099_zowe_dsModification@0" + "group": "z_zowe_dsModification@0" }, { "when": "view == zowe.ds.explorer && viewItem =~ /^ds.*/", @@ -1162,7 +1148,7 @@ { "when": "view == zowe.ds.explorer && viewItem =~ /^pds.*/ && !listMultiSelection", "command": "zowe.ds.renameDataSet", - "group": "099_zowe_dsModification@2" + "group": "z_zowe_dsModification@2" }, { "when": "view == zowe.ds.explorer && viewItem =~ /^ds.*/", @@ -1177,7 +1163,7 @@ { "when": "view == zowe.ds.explorer && viewItem =~ /^pds.*/", "command": "zowe.ds.deleteDataset", - "group": "099_zowe_dsModification@5" + "group": "z_zowe_dsModification@5" }, { "when": "view == zowe.ds.explorer && viewItem =~ /^migr.*/", @@ -1210,7 +1196,7 @@ "group": "098_zowe_dsProfileAuthentication@10" }, { - "when": "view == zowe.ds.explorer && viewItem =~ /^session.*/ && !listMultiSelection", + "when": "view == zowe.ds.explorer && viewItem =~ /^(pds|session).*/ && !listMultiSelection", "command": "zowe.ds.sortBy", "group": "099_zowe_dsSort" }, @@ -1229,10 +1215,15 @@ "command": "zowe.ds.deleteProfile", "group": "100_zowe_dsProfileModification@99" }, + { + "when": "view == zowe.jobs.explorer && viewItem =~ /^(?!.*_fav.*)server.*/ && !listMultiSelection", + "command": "zowe.jobs.sortBy", + "group": "inline@0" + }, { "when": "view == zowe.jobs.explorer && viewItem =~ /^(?!.*_fav.*)server.*/ && !listMultiSelection", "command": "zowe.jobs.search", - "group": "inline" + "group": "inline@1" }, { "when": "view == zowe.jobs.explorer && viewItem =~ /^(?!.*_fav.*)job.*/", @@ -1379,40 +1370,25 @@ "command": "zowe.jobs.ssoLogout", "group": "098_zowe_jobsProfileAuthentication@7" }, + { + "when": "view == zowe.jobs.explorer && viewItem =~ /^(?!.*_fav.*)server.*/ && !listMultiSelection", + "command": "zowe.jobs.sortBy", + "group": "099_zowe_jobsSort" + }, { "when": "view == zowe.jobs.explorer && viewItem =~ /^(?!.*_fav.*)server.*/ && !listMultiSelection", "command": "zowe.jobs.editSession", - "group": "099_zowe_jobsProfileModification@0" + "group": "100_zowe_jobsProfileModification@0" }, { "when": "view == zowe.jobs.explorer && viewItem =~ /^(?!.*_fav.*)server.*/", "command": "zowe.jobs.removeJobsSession", - "group": "099_zowe_jobsProfileModification@98" + "group": "100_zowe_jobsProfileModification@98" }, { "when": "view == zowe.jobs.explorer && viewItem =~ /^(?!.*_fav.*)server.*/ && !listMultiSelection", "command": "zowe.jobs.deleteProfile", - "group": "099_zowe_jobsProfileModification@99" - }, - { - "when": "view == zowe.jobs.explorer && viewItem =~ /^(?!.*_fav.*)server.*/ && !listMultiSelection", - "command": "zowe.jobs.sortById", - "group": "000_zowe_jobsProfileModification@1" - }, - { - "when": "view == zowe.jobs.explorer && viewItem =~ /^(?!.*_fav.*)server.*/ && !listMultiSelection", - "command": "zowe.jobs.sortByName", - "group": "000_zowe_jobsProfileModification@2" - }, - { - "when": "view == zowe.jobs.explorer && viewItem =~ /^(?!.*_fav.*)server.*/ && !listMultiSelection", - "command": "zowe.jobs.sortByReturnCode", - "group": "000_zowe_jobsProfileModification@2" - }, - { - "when": "view == zowe.jobs.explorer && viewItem =~ /^(?!.*_fav.*)server.*/ && !listMultiSelection", - "command": "zowe.jobs.sortByDateSubmitted", - "group": "000_zowe_jobsProfileModification@3" + "group": "100_zowe_jobsProfileModification@99" } ], "commandPalette": [ diff --git a/packages/zowe-explorer/package.nls.json b/packages/zowe-explorer/package.nls.json index 27bc42848e..31e61b4c91 100644 --- a/packages/zowe-explorer/package.nls.json +++ b/packages/zowe-explorer/package.nls.json @@ -147,13 +147,10 @@ "createZoweSchema.reload.infoMessage": "Team Configuration file created. Location: {0}. \n Please reload your window.", "copyFile": "Copy", "pasteFile": "Paste", - "jobs.sortByReturnCode": "Sort by Return Code", - "jobs.sortById": "Sort by ID", - "jobs.sortByDateSubmitted": "Sort by Date Submitted", - "sortByName": "Sort by Name", - "ds.selectSortOpt": "Select a sorting option for PDS members in {0}.", - "ds.sortBy": "Sort PDS members...", - "ds.sortByName": "Name", - "ds.sortByModified": "Date Modified", - "ds.sortByUserId": "User ID" + "jobs.sortBy": "Sort jobs...", + "ds.allPdsSort": "all PDS members in {0}", + "ds.singlePdsSort": "the PDS members in {0}", + "ds.selectSortOpt": "Select a sorting option for {0}", + "jobs.selectSortOpt": "Select a sorting option for jobs in {0}", + "ds.sortBy": "Sort PDS members..." } diff --git a/packages/zowe-explorer/src/dataset/DatasetTree.ts b/packages/zowe-explorer/src/dataset/DatasetTree.ts index fbe9181ac4..244508bfed 100644 --- a/packages/zowe-explorer/src/dataset/DatasetTree.ts +++ b/packages/zowe-explorer/src/dataset/DatasetTree.ts @@ -15,15 +15,14 @@ import * as nls from "vscode-nls"; import * as globals from "../globals"; import * as dsActions from "./actions"; import { - Gui, DataSetAllocTemplate, + Gui, ValidProfileEnum, IZoweTree, IZoweDatasetTreeNode, PersistenceSchemaEnum, NodeInteraction, IZoweTreeNode, - DatasetSort, } from "@zowe/zowe-explorer-api"; import { Profiles } from "../Profiles"; import { ZoweExplorerApiRegister } from "../ZoweExplorerApiRegister"; @@ -37,7 +36,7 @@ import * as contextually from "../shared/context"; import { resetValidationSettings } from "../shared/actions"; import { closeOpenedTextFile } from "../utils/workspace"; import { IDataSet, IListOptions, imperative } from "@zowe/cli"; -import { validateDataSetName, validateMemberName } from "./utils"; +import { DATASET_SORT_OPTS, validateDataSetName, validateMemberName } from "./utils"; import { SettingsConfig } from "../utils/SettingsConfig"; import { ZoweLogger } from "../utils/LoggerUtils"; import { TreeViewUtils } from "../utils/TreeViewUtils"; @@ -1290,44 +1289,56 @@ export class DatasetTree extends ZoweTreeProvider implements IZoweTree { - const options = [localize("ds.sortByName", "Name"), localize("ds.sortByModified", "Date Modified"), localize("ds.sortByUserId", "User ID")]; - - const selection = await Gui.showQuickPick(options, { - placeHolder: localize("ds.selectSortOpt", "Select a sorting option for PDS members in {0}.", node.label as string), - }); + public async sortPdsMembers(node: IZoweDatasetTreeNode): Promise { + const isSession = contextually.isSession(node); + + const specifier = isSession + ? localize("ds.allPdsSort", "all PDS members in {0}", node.label as string) + : localize("ds.singlePdsSort", "the PDS members in {0}", node.label as string); + const selection = await Gui.showQuickPick( + DATASET_SORT_OPTS.map((sortOpt, i) => (node.sortMethod === i ? `${sortOpt} $(check)` : sortOpt)), + { + placeHolder: localize("ds.selectSortOpt", "Select a sorting option for {0}", specifier), + } + ); if (selection == null) { return; } - switch (selection) { - case options[0]: - node.sortMethod = DatasetSort.Name; - break; - case options[1]: - node.sortMethod = DatasetSort.LastModified; - break; - case options[2]: - node.sortMethod = DatasetSort.UserId; - break; - default: - return; + const sortMethod = DATASET_SORT_OPTS.indexOf(selection); + if (sortMethod == -1) { + return; } - if (node.children != null && node.children.length > 0) { - // children nodes already exist, sort and repaint to avoid extra refresh - for (const c of node.children) { - if (contextually.isPds(c) && c.children) { - c.children.sort(ZoweDatasetNode.sortBy(node.sortMethod)); - this.nodeDataChanged(c); + node.sortMethod = sortMethod; + + if (isSession) { + // if a session was selected, apply this sort to ALL PDS members + if (node.children != null && node.children.length > 0) { + // children nodes already exist, sort and repaint to avoid extra refresh + for (const c of node.children) { + if (contextually.isPds(c) && c.children) { + c.sortMethod = sortMethod; + c.children.sort(ZoweDatasetNode.sortBy(sortMethod)); + this.nodeDataChanged(c); + } } + } else { + this.refreshElement(node); } } else { - this.refreshElement(node); + // Only sort the PDS members for this PDS + if (node.children != null && node.children.length > 0) { + // children nodes already exist, sort and repaint to avoid extra refresh + node.children.sort(ZoweDatasetNode.sortBy(sortMethod)); + this.nodeDataChanged(node); + } else { + this.refreshElement(node); + } } } } diff --git a/packages/zowe-explorer/src/dataset/ZoweDatasetNode.ts b/packages/zowe-explorer/src/dataset/ZoweDatasetNode.ts index f334917162..2cc4b1083d 100644 --- a/packages/zowe-explorer/src/dataset/ZoweDatasetNode.ts +++ b/packages/zowe-explorer/src/dataset/ZoweDatasetNode.ts @@ -13,13 +13,14 @@ import * as zowe from "@zowe/cli"; import * as vscode from "vscode"; import * as globals from "../globals"; import { errorHandling } from "../utils/ProfilesUtils"; -import { DatasetSort, DatasetStats, Gui, NodeAction, IZoweDatasetTreeNode, ZoweTreeNode } from "@zowe/zowe-explorer-api"; +import { DatasetSortOpts, DatasetStats, Gui, NodeAction, IZoweDatasetTreeNode, ZoweTreeNode } from "@zowe/zowe-explorer-api"; import { ZoweExplorerApiRegister } from "../ZoweExplorerApiRegister"; import { getIconByNode } from "../generators/icons"; import * as contextually from "../shared/context"; import * as nls from "vscode-nls"; import { Profiles } from "../Profiles"; import { ZoweLogger } from "../utils/LoggerUtils"; + // Set up localization nls.config({ messageFormat: nls.MessageFormat.bundle, @@ -43,8 +44,8 @@ export class ZoweDatasetNode extends ZoweTreeNode implements IZoweDatasetTreeNod public errorDetails: zowe.imperative.ImperativeError; public ongoingActions: Record> = {}; public wasDoubleClicked: boolean = false; - public sortMethod: DatasetSort = DatasetSort.Name; public stats: DatasetStats; + public sortMethod = DatasetSortOpts.Name; /** * Creates an instance of ZoweDatasetNode @@ -267,31 +268,38 @@ export class ZoweDatasetNode extends ZoweTreeNode implements IZoweDatasetTreeNod .filter((label) => this.children.find((c) => (c.label as string) === label) == null) .map((label) => elementChildren[label]); + const sortMethod = (this.sortMethod ? this.sortMethod : this.getSessionNode().sortMethod) as DatasetSortOpts; + this.children = this.children .concat(newChildren) .filter((c) => (c.label as string) in elementChildren) - .sort(ZoweDatasetNode.sortBy(this.getSessionNode().sortMethod ?? DatasetSort.Name)); + .sort(ZoweDatasetNode.sortBy(sortMethod ?? DatasetSortOpts.Name)); } return this.children; } - public static sortBy(method: DatasetSort): (a: IZoweDatasetTreeNode, b: IZoweDatasetTreeNode) => number { + /** + * Returns a sorting function based on the given sorting method. + * If the nodes are not PDS members, it will simply sort by name. + * @param method The sorting method to use + * @returns A function that sorts 2 nodes based on the given sorting method + */ + public static sortBy(method: DatasetSortOpts): (a: IZoweDatasetTreeNode, b: IZoweDatasetTreeNode) => number { return (a, b): number => { - // we can only sort PDS members, compared nodes are at same level (same parent) const aParent = a.getParent(); if (aParent == null || !contextually.isPds(aParent)) { return (a.label as string) < (b.label as string) ? -1 : 1; } switch (method) { - case DatasetSort.LastModified: - return a.stats?.m4date < b.stats?.m4date ? -1 : 1; - case DatasetSort.UserId: - return a.stats?.user < b.stats?.user ? -1 : 1; - case DatasetSort.Name: + case DatasetSortOpts.Name: default: return (a.label as string) < (b.label as string) ? -1 : 1; + case DatasetSortOpts.LastModified: + return a.stats?.m4date < b.stats?.m4date ? -1 : 1; + case DatasetSortOpts.UserId: + return a.stats?.user < b.stats?.user ? -1 : 1; } }; } diff --git a/packages/zowe-explorer/src/dataset/init.ts b/packages/zowe-explorer/src/dataset/init.ts index a1ca9e9e3b..dfb156ac98 100644 --- a/packages/zowe-explorer/src/dataset/init.ts +++ b/packages/zowe-explorer/src/dataset/init.ts @@ -198,7 +198,9 @@ export async function initDatasetProvider(context: vscode.ExtensionContext): Pro ); context.subscriptions.push(vscode.commands.registerCommand("zowe.ds.ssoLogin", (node: IZoweTreeNode) => datasetProvider.ssoLogin(node))); context.subscriptions.push(vscode.commands.registerCommand("zowe.ds.ssoLogout", (node: IZoweTreeNode) => datasetProvider.ssoLogout(node))); - context.subscriptions.push(vscode.commands.registerCommand("zowe.ds.sortBy", (node: IZoweDatasetTreeNode) => datasetProvider.sortPdsBy(node))); + context.subscriptions.push( + vscode.commands.registerCommand("zowe.ds.sortBy", async (node: IZoweDatasetTreeNode) => datasetProvider.sortPdsMembers(node)) + ); context.subscriptions.push( vscode.workspace.onDidChangeConfiguration(async (e) => { await datasetProvider.onDidChangeConfiguration(e); diff --git a/packages/zowe-explorer/src/dataset/utils.ts b/packages/zowe-explorer/src/dataset/utils.ts index 1debf45d39..c7445dce71 100644 --- a/packages/zowe-explorer/src/dataset/utils.ts +++ b/packages/zowe-explorer/src/dataset/utils.ts @@ -10,9 +10,23 @@ */ import * as globals from "../globals"; +import * as nls from "vscode-nls"; import { IZoweNodeType } from "@zowe/zowe-explorer-api"; import { ZoweLogger } from "../utils/LoggerUtils"; +// Set up localization +nls.config({ + messageFormat: nls.MessageFormat.bundle, + bundleFormat: nls.BundleFormat.standalone, +})(); +const localize: nls.LocalizeFunc = nls.loadMessageBundle(); + +export const DATASET_SORT_OPTS = [ + localize("ds.sortByName", "Name"), + localize("ds.sortByModified", "Date Modified"), + localize("ds.sortByUserId", "User ID"), +]; + export function getProfileAndDataSetName(node: IZoweNodeType): { profileName: string; dataSetName: string; diff --git a/packages/zowe-explorer/src/job/ZosJobsProvider.ts b/packages/zowe-explorer/src/job/ZosJobsProvider.ts index 3333724e6f..2747b322ff 100644 --- a/packages/zowe-explorer/src/job/ZosJobsProvider.ts +++ b/packages/zowe-explorer/src/job/ZosJobsProvider.ts @@ -12,7 +12,7 @@ import * as vscode from "vscode"; import * as globals from "../globals"; import { IJob, imperative } from "@zowe/cli"; -import { Gui, ValidProfileEnum, IZoweTree, IZoweJobTreeNode, PersistenceSchemaEnum, NodeInteraction } from "@zowe/zowe-explorer-api"; +import { Gui, ValidProfileEnum, IZoweTree, IZoweJobTreeNode, PersistenceSchemaEnum, NodeInteraction, JobSortOpts } from "@zowe/zowe-explorer-api"; import { FilterItem, errorHandling } from "../utils/ProfilesUtils"; import { Profiles } from "../Profiles"; import { ZoweExplorerApiRegister } from "../ZoweExplorerApiRegister"; @@ -1122,6 +1122,17 @@ export class ZosJobsProvider extends ZoweTreeProvider implements IZoweTree this.children.find((ch) => ch.label === c.label) == null); + const sortMethod = contextually.isSession(this) ? this.sortMethod : JobSortOpts.Id; // Remove any children that are no longer present in the built record this.children = this.children .concat(newChildren) .filter((ch) => Object.values(elementChildren).find((recordCh) => recordCh.label === ch.label) != null) - .sort((a, b) => Job.sortJobs(a, b)); + .sort(Job.sortJobs(sortMethod)); this.dirty = false; return this.children; } - public static sortJobs(a: IZoweJobTreeNode, b: IZoweJobTreeNode): number { - if (a.job.jobid > b.job.jobid) { - return 1; - } - - if (a.job.jobid < b.job.jobid) { - return -1; - } - - return 0; + public static sortJobs(method: JobSortOpts): (x: IZoweJobTreeNode, y: IZoweJobTreeNode) => number { + return (x, y) => { + const keyToSortBy = JOB_SORT_KEYS[method]; + if (keyToSortBy !== "jobid" && x["job"][keyToSortBy] == y["job"][keyToSortBy]) { + return x["job"]["jobid"] > y["job"]["jobid"] ? 1 : -1; + } else { + return x["job"][keyToSortBy] > y["job"][keyToSortBy] ? 1 : -1; + } + }; } public getSessionNode(): IZoweJobTreeNode { diff --git a/packages/zowe-explorer/src/job/actions.ts b/packages/zowe-explorer/src/job/actions.ts index afce5c131d..218c50f9f5 100644 --- a/packages/zowe-explorer/src/job/actions.ts +++ b/packages/zowe-explorer/src/job/actions.ts @@ -21,6 +21,7 @@ import SpoolProvider, { encodeJobFile, getSpoolFiles, matchSpool } from "../Spoo import { ZoweLogger } from "../utils/LoggerUtils"; import { getDefaultUri } from "../shared/utils"; import { ZosJobsProvider } from "./ZosJobsProvider"; +import { JOB_SORT_OPTS } from "./utils"; // Set up localization nls.config({ @@ -529,17 +530,22 @@ export async function cancelJobs(jobsProvider: IZoweTree, node await Gui.showMessage(localize("cancelJobs.succeeded", "Cancelled selected jobs successfully.")); } } -export function sortJobsBy(session: IZoweJobTreeNode, jobsProvider: ZosJobsProvider, key: keyof zowe.IJob): void { - if (session.children != null) { - session.children.sort((x, y) => { - if (key !== "jobid" && x["job"][key] == y["job"][key]) { - return x["job"]["jobid"] > y["job"]["jobid"] ? 1 : -1; - } else { - return x["job"][key] > y["job"][key] ? 1 : -1; - } - }); - jobsProvider.nodeDataChanged(session); - } else { - jobsProvider.refreshElement(session); +export async function sortJobs(session: IZoweJobTreeNode, jobsProvider: ZosJobsProvider): Promise { + const selection = await Gui.showQuickPick( + JOB_SORT_OPTS.map((sortOpt, i) => (i === session.sortMethod ? `${sortOpt} $(check)` : sortOpt)), + { + placeHolder: localize("jobs.selectSortOpt", "Select a sorting option for jobs in {0}", session.label as string), + } + ); + if (selection == null) { + return; } + + const optIndex = JOB_SORT_OPTS.indexOf(selection); + if (optIndex == -1) { + return; + } + + session.sortMethod = optIndex; + jobsProvider.sortBy(session); } diff --git a/packages/zowe-explorer/src/job/init.ts b/packages/zowe-explorer/src/job/init.ts index 4fb0ebec2e..cca4b1f913 100644 --- a/packages/zowe-explorer/src/job/init.ts +++ b/packages/zowe-explorer/src/job/init.ts @@ -171,11 +171,7 @@ export async function initJobsProvider(context: vscode.ExtensionContext): Promis await jobActions.cancelJobs(jobsProvider, getSelectedNodeList(node, nodeList)); }) ); - context.subscriptions.push(vscode.commands.registerCommand("zowe.jobs.sortbyname", (job) => jobActions.sortJobsBy(job, jobsProvider, "jobname"))); - context.subscriptions.push(vscode.commands.registerCommand("zowe.jobs.sortbyid", (job) => jobActions.sortJobsBy(job, jobsProvider, "jobid"))); - context.subscriptions.push( - vscode.commands.registerCommand("zowe.jobs.sortbyreturncode", (job) => jobActions.sortJobsBy(job, jobsProvider, "retcode")) - ); + context.subscriptions.push(vscode.commands.registerCommand("zowe.jobs.sortBy", async (job) => jobActions.sortJobs(job, jobsProvider))); initSubscribers(context, jobsProvider); return jobsProvider; } diff --git a/packages/zowe-explorer/src/job/utils.ts b/packages/zowe-explorer/src/job/utils.ts index 9a5f3d7611..9e9db05d3c 100644 --- a/packages/zowe-explorer/src/job/utils.ts +++ b/packages/zowe-explorer/src/job/utils.ts @@ -9,8 +9,32 @@ * */ +import { JobSortOpts } from "@zowe/zowe-explorer-api"; import { ZoweLogger } from "../utils/LoggerUtils"; import { FilterItem } from "../utils/ProfilesUtils"; +import * as nls from "vscode-nls"; +import { IJob } from "@zowe/cli"; + +// Set up localization +nls.config({ + messageFormat: nls.MessageFormat.bundle, + bundleFormat: nls.BundleFormat.standalone, +})(); +const localize: nls.LocalizeFunc = nls.loadMessageBundle(); + +export const JOB_SORT_OPTS = [ + localize("jobs.sortById", "Job ID"), + localize("jobs.sortByDateSubmitted", "Date Submitted"), + localize("jobs.sortByName", "Job Name"), + localize("jobs.sortByReturnCode", "Return Code"), +]; + +export const JOB_SORT_KEYS: Record = { + [JobSortOpts.Id]: "jobid", + [JobSortOpts.DateSubmitted]: "exec-submitted", + [JobSortOpts.Name]: "jobname", + [JobSortOpts.ReturnCode]: "retcode", +}; export async function resolveQuickPickHelper(quickpick): Promise { ZoweLogger.trace("job.utils.resolveQuickPickHelper called."); From 742a90e8065fadbbe4fef118aa1f06600996f79e Mon Sep 17 00:00:00 2001 From: Billie Simmons <49491949+JillieBeanSim@users.noreply.github.com> Date: Fri, 6 Oct 2023 09:05:15 -0400 Subject: [PATCH 085/189] address feedback Signed-off-by: Billie Simmons <49491949+JillieBeanSim@users.noreply.github.com> --- .../i18n/sample/src/utils/ProfileManagement.i18n.json | 6 +++--- packages/zowe-explorer/src/utils/ProfileManagement.ts | 10 +++++----- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/packages/zowe-explorer/i18n/sample/src/utils/ProfileManagement.i18n.json b/packages/zowe-explorer/i18n/sample/src/utils/ProfileManagement.i18n.json index 56776e1f3b..f487573b50 100644 --- a/packages/zowe-explorer/i18n/sample/src/utils/ProfileManagement.i18n.json +++ b/packages/zowe-explorer/i18n/sample/src/utils/ProfileManagement.i18n.json @@ -9,13 +9,13 @@ "updateBasicAuthQpItem.updateCredentials.qpDetail": "Update stored username and password", "deleteProfileQpItem.delete.qpLabel": "$(trash) Delete Profile", "disableProfileValildationQpItem.disableValidation.qpLabel": "$(workspace-untrusted) Disable Profile Validation", - "disableProfileValildationQpItem.disableValidation.qpDetail": "Disable validation of server check for profile.", + "disableProfileValildationQpItem.disableValidation.qpDetail": "Disable validation of server check for profile", "enableProfileValildationQpItem.enableValidation.qpLabel": "$(workspace-trusted) Enable Profile Validation", - "enableProfileValildationQpItem.enableValidation.qpDetail": "Enable validation of server check for profile.", + "enableProfileValildationQpItem.enableValidation.qpDetail": "Enable validation of server check for profile", "editProfileQpItem.editProfile.qpLabel": "$(pencil) Edit Profile", "editProfileQpItem.editProfile.qpDetail": "Update profile connection information", "hideProfileQpItems.hideProfile.qpLabel": "$(eye-closed) Hide Profile", - "hideProfileQpItems.hideProfile.qpDetail": "Hide profile name from tree view.", + "hideProfileQpItems.hideProfile.qpDetail": "Hide profile name from tree view", "loginQpItem.login.qpLabel": "$(arrow-right) Log in to authentication service", "loginQpItem.login.qpDetail": "Log in to obtain a new token value", "logoutQpItem.logout.qpLabel": "$(arrow-left) Log out of authentication service", diff --git a/packages/zowe-explorer/src/utils/ProfileManagement.ts b/packages/zowe-explorer/src/utils/ProfileManagement.ts index 55a2f57eae..5825a8fdac 100644 --- a/packages/zowe-explorer/src/utils/ProfileManagement.ts +++ b/packages/zowe-explorer/src/utils/ProfileManagement.ts @@ -81,13 +81,13 @@ export class ProfileManagement { public static disableProfileValildationQpItem: Record = { [this.AuthQpLabels.disable]: { label: localize("disableProfileValildationQpItem.disableValidation.qpLabel", "$(workspace-untrusted) Disable Profile Validation"), - description: localize("disableProfileValildationQpItem.disableValidation.qpDetail", "Disable validation of server check for profile."), + description: localize("disableProfileValildationQpItem.disableValidation.qpDetail", "Disable validation of server check for profile"), }, }; public static enableProfileValildationQpItem: Record = { [this.AuthQpLabels.enable]: { label: localize("enableProfileValildationQpItem.enableValidation.qpLabel", "$(workspace-trusted) Enable Profile Validation"), - description: localize("enableProfileValildationQpItem.enableValidation.qpDetail", "Enable validation of server check for profile."), + description: localize("enableProfileValildationQpItem.enableValidation.qpDetail", "Enable validation of server check for profile"), }, }; public static editProfileQpItems: Record = { @@ -99,7 +99,7 @@ export class ProfileManagement { public static hideProfileQpItems: Record = { [this.AuthQpLabels.hide]: { label: localize("hideProfileQpItems.hideProfile.qpLabel", "$(eye-closed) Hide Profile"), - description: localize("hideProfileQpItems.hideProfile.qpDetail", "Hide profile name from tree view."), + description: localize("hideProfileQpItems.hideProfile.qpDetail", "Hide profile name from tree view"), }, }; public static tokenAuthLoginQpItem: Record = { @@ -225,13 +225,13 @@ export class ProfileManagement { return this.addFinalQpOptions(node, quickPickOptions); } private static addFinalQpOptions(node: IZoweTreeNode, quickPickOptions: vscode.QuickPickItem[]): vscode.QuickPickItem[] { + quickPickOptions.push(this.editProfileQpItems[this.AuthQpLabels.edit]); + quickPickOptions.push(this.hideProfileQpItems[this.AuthQpLabels.hide]); if (node.contextValue.includes(globals.NO_VALIDATE_SUFFIX)) { quickPickOptions.push(this.enableProfileValildationQpItem[this.AuthQpLabels.enable]); } else { quickPickOptions.push(this.disableProfileValildationQpItem[this.AuthQpLabels.disable]); } - quickPickOptions.push(this.editProfileQpItems[this.AuthQpLabels.edit]); - quickPickOptions.push(this.hideProfileQpItems[this.AuthQpLabels.hide]); quickPickOptions.push(this.deleteProfileQpItem[this.AuthQpLabels.delete]); return quickPickOptions; } From 33edd0c19955574338be5e9b2540e1de1106cd75 Mon Sep 17 00:00:00 2001 From: Trae Yelovich Date: Fri, 6 Oct 2023 11:07:53 -0400 Subject: [PATCH 086/189] tests(ds, jobs): Fix test cases to work with UX changes Signed-off-by: Trae Yelovich --- .../__tests__/__unit__/ZoweNode.unit.test.ts | 5 +- .../__unit__/dataset/DatasetTree.unit.test.ts | 74 +++++++++++++------ .../__unit__/dataset/init.unit.test.ts | 15 +--- .../__tests__/__unit__/extension.unit.test.ts | 8 +- .../__unit__/job/ZoweJobNode.unit.test.ts | 4 +- .../__unit__/job/actions.unit.test.ts | 22 +++--- .../src/dataset/ZoweDatasetNode.ts | 6 +- packages/zowe-explorer/src/globals.ts | 2 +- 8 files changed, 81 insertions(+), 55 deletions(-) diff --git a/packages/zowe-explorer/__tests__/__unit__/ZoweNode.unit.test.ts b/packages/zowe-explorer/__tests__/__unit__/ZoweNode.unit.test.ts index 72da57e2c7..8aa7ec2dec 100644 --- a/packages/zowe-explorer/__tests__/__unit__/ZoweNode.unit.test.ts +++ b/packages/zowe-explorer/__tests__/__unit__/ZoweNode.unit.test.ts @@ -18,6 +18,7 @@ import { List, imperative } from "@zowe/cli"; import { Profiles } from "../../src/Profiles"; import * as globals from "../../src/globals"; import { ZoweLogger } from "../../src/utils/LoggerUtils"; +import { DatasetSortOpts } from "@zowe/zowe-explorer-api"; describe("Unit Tests (Jest)", () => { // Globals @@ -354,11 +355,13 @@ describe("Unit Tests (Jest)", () => { }; }), }); + const sessionNode = { getSessionNode: jest.fn(), sortMethod: DatasetSortOpts.Name } as unknown as ZoweDatasetNode; + jest.spyOn(ZoweDatasetNode.prototype, "getSessionNode").mockReturnValueOnce(sessionNode); // Creating a rootNode const pds = new ZoweDatasetNode( "[root]: something", vscode.TreeItemCollapsibleState.Collapsed, - { getSessionNode: jest.fn() } as unknown as ZoweDatasetNode, + sessionNode, session, undefined, undefined, 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 e11409d50a..76d3d6a604 100644 --- a/packages/zowe-explorer/__tests__/__unit__/dataset/DatasetTree.unit.test.ts +++ b/packages/zowe-explorer/__tests__/__unit__/dataset/DatasetTree.unit.test.ts @@ -15,7 +15,7 @@ import * as fs from "fs"; import * as zowe from "@zowe/cli"; import { DatasetTree } from "../../../src/dataset/DatasetTree"; import { ZoweDatasetNode } from "../../../src/dataset/ZoweDatasetNode"; -import { DatasetSort, Gui, IZoweDatasetTreeNode, ProfilesCache, ValidProfileEnum } from "@zowe/zowe-explorer-api"; +import { Gui, IZoweDatasetTreeNode, ProfilesCache, ValidProfileEnum } from "@zowe/zowe-explorer-api"; import { ZoweExplorerApiRegister } from "../../../src/ZoweExplorerApiRegister"; import { Profiles } from "../../../src/Profiles"; import * as utils from "../../../src/utils/ProfilesUtils"; @@ -2702,52 +2702,80 @@ describe("Dataset Tree Unit Tests - Function sortBy", () => { const mocks = { nodeDataChanged: jest.spyOn(DatasetTree.prototype, "nodeDataChanged"), refreshElement: jest.spyOn(DatasetTree.prototype, "refreshElement"), + showQuickPick: jest.spyOn(Gui, "showQuickPick"), + getParent: jest.spyOn(ZoweDatasetNode.prototype, "getParent"), }; - const testNode = new ZoweDatasetNode("test", vscode.TreeItemCollapsibleState.Collapsed, null, createISession()); + const testSession = new ZoweDatasetNode("testSession", vscode.TreeItemCollapsibleState.Collapsed, null, createISession()); + const testPds = new ZoweDatasetNode("testPds", vscode.TreeItemCollapsibleState.Collapsed, testSession, createISession()); + testPds.contextValue = globals.DS_PDS_CONTEXT; beforeEach(() => { - testNode.children = [ - { label: "A", stats: { user: "someUser", m4date: Date.now() } } as unknown as ZoweDatasetNode, - { label: "B", stats: { user: "anotherUser", m4date: Date.parse("2022-01-01T12:00:00") } } as unknown as ZoweDatasetNode, - { label: "C", stats: { user: "someUser", m4date: Date.parse("2022-03-15T16:30:00") } } as unknown as ZoweDatasetNode, + mocks.getParent.mockReturnValue(testSession); + testPds.children = [ + { label: "A", stats: { user: "someUser", m4date: Date.now() }, getParent: mocks.getParent } as unknown as ZoweDatasetNode, + { + label: "B", + stats: { user: "anotherUser", m4date: Date.parse("2022-01-01T12:00:00") }, + getParent: mocks.getParent, + } as unknown as ZoweDatasetNode, + { + label: "C", + stats: { user: "someUser", m4date: Date.parse("2022-03-15T16:30:00") }, + getParent: mocks.getParent, + } as unknown as ZoweDatasetNode, ]; + testSession.children = [testPds]; }); afterEach(() => { - mocks.nodeDataChanged.mockClear(); - mocks.refreshElement.mockClear(); + for (const mock of Object.values(mocks)) { + mock.mockClear(); + } }); afterAll(() => { - mocks.nodeDataChanged.mockRestore(); - mocks.refreshElement.mockRestore(); + for (const mock of Object.values(mocks)) { + mock.mockRestore(); + } }); - it("calls refreshElement if no children exist", () => { - testNode.children = []; - testTree.sortBy(DatasetSort.Name, testNode); + it("calls refreshElement if no children exist", async () => { + // case 1: called on session node + mocks.showQuickPick.mockResolvedValueOnce("Name" as any); + testPds.children = []; + await testTree.sortPdsMembers(testPds); + expect(mocks.nodeDataChanged).not.toHaveBeenCalled(); + expect(mocks.refreshElement).toHaveBeenCalledWith(testPds); + + // case 2: called on PDS node + mocks.showQuickPick.mockResolvedValueOnce("Name" as any); + testSession.children = []; + await testTree.sortPdsMembers(testSession); expect(mocks.nodeDataChanged).not.toHaveBeenCalled(); - expect(mocks.refreshElement).toHaveBeenCalledWith(testNode); + expect(mocks.refreshElement).toHaveBeenCalledWith(testSession); }); - it("sorts by name", () => { - testTree.sortBy(DatasetSort.Name, testNode); + it("sorts by name", async () => { + mocks.showQuickPick.mockResolvedValueOnce("Name" as any); + await testTree.sortPdsMembers(testPds); expect(mocks.nodeDataChanged).toHaveBeenCalled(); expect(mocks.refreshElement).not.toHaveBeenCalled(); - expect(testNode.children.map((c: IZoweDatasetTreeNode) => c.label)).toStrictEqual(["A", "B", "C"]); + expect(testPds.children.map((c: IZoweDatasetTreeNode) => c.label)).toStrictEqual(["A", "B", "C"]); }); - it("sorts by last modified date", () => { - testTree.sortBy(DatasetSort.LastModified, testNode); + it("sorts by last modified date", async () => { + mocks.showQuickPick.mockResolvedValueOnce("Date Modified" as any); + await testTree.sortPdsMembers(testPds); expect(mocks.nodeDataChanged).toHaveBeenCalled(); expect(mocks.refreshElement).not.toHaveBeenCalled(); - expect(testNode.children.map((c: IZoweDatasetTreeNode) => c.label)).toStrictEqual(["B", "C", "A"]); + expect(testPds.children.map((c: IZoweDatasetTreeNode) => c.label)).toStrictEqual(["B", "C", "A"]); }); - it("sorts by user ID", () => { - testTree.sortBy(DatasetSort.UserId, testNode); + it("sorts by user ID", async () => { + mocks.showQuickPick.mockResolvedValueOnce("User ID" as any); + await testTree.sortPdsMembers(testPds); expect(mocks.nodeDataChanged).toHaveBeenCalled(); expect(mocks.refreshElement).not.toHaveBeenCalled(); - expect(testNode.children.map((c: IZoweDatasetTreeNode) => c.label)).toStrictEqual(["B", "A", "C"]); + expect(testPds.children.map((c: IZoweDatasetTreeNode) => c.label)).toStrictEqual(["B", "A", "C"]); }); }); diff --git a/packages/zowe-explorer/__tests__/__unit__/dataset/init.unit.test.ts b/packages/zowe-explorer/__tests__/__unit__/dataset/init.unit.test.ts index 0fc7719101..fedbf07666 100644 --- a/packages/zowe-explorer/__tests__/__unit__/dataset/init.unit.test.ts +++ b/packages/zowe-explorer/__tests__/__unit__/dataset/init.unit.test.ts @@ -19,7 +19,6 @@ import { initDatasetProvider } from "../../../src/dataset/init"; import { Profiles } from "../../../src/Profiles"; import { IJestIt, ITestContext, processSubscriptions, spyOnSubscriptions } from "../../__common__/testUtils"; import { ZoweLogger } from "../../../src/utils/LoggerUtils"; -import { DatasetSort } from "@zowe/zowe-explorer-api"; describe("Test src/dataset/extension", () => { describe("initDatasetProvider", () => { @@ -46,7 +45,7 @@ describe("Test src/dataset/extension", () => { onDidChangeConfiguration: jest.fn(), getTreeView: jest.fn(), refreshElement: jest.fn(), - sortBy: jest.fn(), + sortPdsMembers: jest.fn(), }; const commands: IJestIt[] = [ { @@ -253,16 +252,8 @@ describe("Test src/dataset/extension", () => { mock: [{ spy: jest.spyOn(dsProvider, "ssoLogout"), arg: [test.value] }], }, { - name: "zowe.ds.sortByName", - mock: [{ spy: jest.spyOn(dsProvider, "sortBy"), arg: [DatasetSort.Name, test.value] }], - }, - { - name: "zowe.ds.sortByModified", - mock: [{ spy: jest.spyOn(dsProvider, "sortBy"), arg: [DatasetSort.LastModified, test.value] }], - }, - { - name: "zowe.ds.sortByUserId", - mock: [{ spy: jest.spyOn(dsProvider, "sortBy"), arg: [DatasetSort.UserId, test.value] }], + name: "zowe.ds.sortBy", + mock: [{ spy: jest.spyOn(dsProvider, "sortPdsMembers"), arg: [test.value] }], }, { name: "onDidChangeConfiguration", diff --git a/packages/zowe-explorer/__tests__/__unit__/extension.unit.test.ts b/packages/zowe-explorer/__tests__/__unit__/extension.unit.test.ts index fe655a8c29..4f3294d3b4 100644 --- a/packages/zowe-explorer/__tests__/__unit__/extension.unit.test.ts +++ b/packages/zowe-explorer/__tests__/__unit__/extension.unit.test.ts @@ -176,9 +176,7 @@ async function createGlobalMocks() { "zowe.ds.enableValidation", "zowe.ds.ssoLogin", "zowe.ds.ssoLogout", - "zowe.ds.sortByName", - "zowe.ds.sortByModified", - "zowe.ds.sortByUserId", + "zowe.ds.sortBy", "zowe.uss.addFavorite", "zowe.uss.removeFavorite", "zowe.uss.addSession", @@ -241,9 +239,7 @@ async function createGlobalMocks() { "zowe.jobs.startPolling", "zowe.jobs.stopPolling", "zowe.jobs.cancelJob", - "zowe.jobs.sortbyname", - "zowe.jobs.sortbyid", - "zowe.jobs.sortbyreturncode", + "zowe.jobs.sortBy", "zowe.manualPoll", "zowe.updateSecureCredentials", "zowe.promptCredentials", diff --git a/packages/zowe-explorer/__tests__/__unit__/job/ZoweJobNode.unit.test.ts b/packages/zowe-explorer/__tests__/__unit__/job/ZoweJobNode.unit.test.ts index 2ab7070292..4bfa4a8f33 100644 --- a/packages/zowe-explorer/__tests__/__unit__/job/ZoweJobNode.unit.test.ts +++ b/packages/zowe-explorer/__tests__/__unit__/job/ZoweJobNode.unit.test.ts @@ -16,7 +16,7 @@ import * as zowe from "@zowe/cli"; import * as globals from "../../../src/globals"; import { createIJobFile, createIJobObject, createJobSessionNode } from "../../../__mocks__/mockCreators/jobs"; import { Job } from "../../../src/job/ZoweJobNode"; -import { IZoweJobTreeNode, ProfilesCache, Gui } from "@zowe/zowe-explorer-api"; +import { IZoweJobTreeNode, ProfilesCache, Gui, JobSortOpts } from "@zowe/zowe-explorer-api"; import { ZoweExplorerApiRegister } from "../../../src/ZoweExplorerApiRegister"; import { Profiles } from "../../../src/Profiles"; import * as sessUtils from "../../../src/utils/SessionUtils"; @@ -851,7 +851,7 @@ describe("Job - sortJobs", () => { jobid: "JOBID120", }, } as IZoweJobTreeNode, - ].sort((a, b) => Job.sortJobs(a, b)); + ].sort(Job.sortJobs(JobSortOpts.Id)); expect(sorted[0].job.jobid).toBe("JOBID120"); expect(sorted[1].job.jobid).toBe("JOBID120"); expect(sorted[2].job.jobid).toBe("JOBID123"); diff --git a/packages/zowe-explorer/__tests__/__unit__/job/actions.unit.test.ts b/packages/zowe-explorer/__tests__/__unit__/job/actions.unit.test.ts index 16851a1b32..b9083fb6fb 100644 --- a/packages/zowe-explorer/__tests__/__unit__/job/actions.unit.test.ts +++ b/packages/zowe-explorer/__tests__/__unit__/job/actions.unit.test.ts @@ -1354,11 +1354,12 @@ describe("sortjobsby function", () => { const expected = new ZosJobsProvider(); testtree.mSessionNodes[0].children = [...[globalMocks()[2], globalMocks()[1], globalMocks()[0]]]; expected.mSessionNodes[0].children = [...[globalMocks()[1], globalMocks()[0], globalMocks()[2]]]; - const sortbynamespy = jest.spyOn(jobActions, "sortJobsBy"); + jest.spyOn(Gui, "showQuickPick").mockResolvedValueOnce("Job Name" as any); + const sortbynamespy = jest.spyOn(ZosJobsProvider.prototype, "sortBy"); //act - await jobActions.sortJobsBy(testtree.mSessionNodes[0], testtree, "jobname"); + await jobActions.sortJobs(testtree.mSessionNodes[0], testtree); //asert - expect(sortbynamespy).toBeCalledWith(testtree.mSessionNodes[0], testtree, "jobname"); + expect(sortbynamespy).toBeCalledWith(testtree.mSessionNodes[0]); expect(sortbynamespy).toHaveBeenCalled(); expect(sortbynamespy.mock.calls[0][0].children).toStrictEqual(expected.mSessionNodes[0].children); }); @@ -1368,11 +1369,12 @@ describe("sortjobsby function", () => { const expected = new ZosJobsProvider(); testtree.mSessionNodes[0].children = [...[globalMocks()[2], globalMocks()[1], globalMocks()[0]]]; expected.mSessionNodes[0].children = [...[globalMocks()[1], globalMocks()[0], globalMocks()[2]]]; - const sortbyidspy = jest.spyOn(jobActions, "sortJobsBy"); + const sortbyidspy = jest.spyOn(ZosJobsProvider.prototype, "sortBy"); + jest.spyOn(Gui, "showQuickPick").mockResolvedValueOnce("Job ID" as any); //act - await jobActions.sortJobsBy(testtree.mSessionNodes[0], testtree, "jobid"); + await jobActions.sortJobs(testtree.mSessionNodes[0], testtree); //asert - expect(sortbyidspy).toBeCalledWith(testtree.mSessionNodes[0], testtree, "jobid"); + expect(sortbyidspy).toBeCalledWith(testtree.mSessionNodes[0]); expect(sortbyidspy).toHaveBeenCalled(); expect(sortbyidspy.mock.calls[0][0].children).toStrictEqual(expected.mSessionNodes[0].children); }); @@ -1382,11 +1384,13 @@ describe("sortjobsby function", () => { const expected = new ZosJobsProvider(); testtree.mSessionNodes[0].children = [...[globalMocks()[2], globalMocks()[1], globalMocks()[0]]]; expected.mSessionNodes[0].children = [...[globalMocks()[0], globalMocks()[1], globalMocks()[2]]]; - const sortbyretcodespy = jest.spyOn(jobActions, "sortJobsBy"); + const sortbyretcodespy = jest.spyOn(ZosJobsProvider.prototype, "sortBy"); + jest.spyOn(Gui, "showQuickPick").mockResolvedValueOnce("Return Code" as any); + //act - await jobActions.sortJobsBy(testtree.mSessionNodes[0], testtree, "retcode"); + await jobActions.sortJobs(testtree.mSessionNodes[0], testtree); //asert - expect(sortbyretcodespy).toBeCalledWith(testtree.mSessionNodes[0], testtree, "retcode"); + expect(sortbyretcodespy).toBeCalledWith(testtree.mSessionNodes[0]); expect(sortbyretcodespy).toHaveBeenCalled(); expect(sortbyretcodespy.mock.calls[0][0].children).toStrictEqual(expected.mSessionNodes[0].children); }); diff --git a/packages/zowe-explorer/src/dataset/ZoweDatasetNode.ts b/packages/zowe-explorer/src/dataset/ZoweDatasetNode.ts index 2cc4b1083d..f66e6a864f 100644 --- a/packages/zowe-explorer/src/dataset/ZoweDatasetNode.ts +++ b/packages/zowe-explorer/src/dataset/ZoweDatasetNode.ts @@ -268,7 +268,11 @@ export class ZoweDatasetNode extends ZoweTreeNode implements IZoweDatasetTreeNod .filter((label) => this.children.find((c) => (c.label as string) === label) == null) .map((label) => elementChildren[label]); - const sortMethod = (this.sortMethod ? this.sortMethod : this.getSessionNode().sortMethod) as DatasetSortOpts; + // get sort method for session + const sessionSortMethod = contextually.isSession(this) ? this.sortMethod : this.getSessionNode().sortMethod; + + // use the PDS sort method if one is defined; otherwise, use session sort method + const sortMethod = (this.sortMethod ?? sessionSortMethod) as DatasetSortOpts; this.children = this.children .concat(newChildren) diff --git a/packages/zowe-explorer/src/globals.ts b/packages/zowe-explorer/src/globals.ts index 596308f59c..b4dda79aef 100644 --- a/packages/zowe-explorer/src/globals.ts +++ b/packages/zowe-explorer/src/globals.ts @@ -35,7 +35,7 @@ export let DS_DIR: string; export let CONFIG_PATH; // set during activate export let ISTHEIA = false; // set during activate export let LOG: imperative.Logger; -export const COMMAND_COUNT = 116; +export const COMMAND_COUNT = 112; export const MAX_SEARCH_HISTORY = 5; export const MAX_FILE_HISTORY = 10; export const MS_PER_SEC = 1000; From 57ceb65b5893b179c06fabc67514430b0320163e Mon Sep 17 00:00:00 2001 From: Rudy Flores <68666202+rudyflores@users.noreply.github.com> Date: Fri, 6 Oct 2023 13:13:27 -0400 Subject: [PATCH 087/189] add persistent items editor webview Signed-off-by: Rudy Flores <68666202+rudyflores@users.noreply.github.com> --- .../i18n/sample/package.i18n.json | 1 + .../sample/src/shared/HistoryView.i18n.json | 3 + packages/zowe-explorer/package.json | 14 ++ packages/zowe-explorer/package.nls.json | 1 + .../zowe-explorer/src/PersistentFilters.ts | 10 + .../zowe-explorer/src/dataset/DatasetTree.ts | 20 ++ .../zowe-explorer/src/job/ZosJobsProvider.ts | 25 ++ .../zowe-explorer/src/shared/HistoryView.ts | 122 +++++++++ packages/zowe-explorer/src/shared/init.ts | 8 + packages/zowe-explorer/src/uss/USSTree.ts | 20 ++ .../src/webviews/src/edit-history/App.tsx | 232 ++++++++++++++++++ .../src/edit-history/assets/trash.svg | 2 + .../src/webviews/src/edit-history/index.html | 12 + .../src/webviews/src/edit-history/index.tsx | 4 + 14 files changed, 474 insertions(+) create mode 100644 packages/zowe-explorer/i18n/sample/src/shared/HistoryView.i18n.json create mode 100644 packages/zowe-explorer/src/shared/HistoryView.ts create mode 100644 packages/zowe-explorer/src/webviews/src/edit-history/App.tsx create mode 100644 packages/zowe-explorer/src/webviews/src/edit-history/assets/trash.svg create mode 100644 packages/zowe-explorer/src/webviews/src/edit-history/index.html create mode 100644 packages/zowe-explorer/src/webviews/src/edit-history/index.tsx diff --git a/packages/zowe-explorer/i18n/sample/package.i18n.json b/packages/zowe-explorer/i18n/sample/package.i18n.json index 8bc5d8bf6c..2b99224dd7 100644 --- a/packages/zowe-explorer/i18n/sample/package.i18n.json +++ b/packages/zowe-explorer/i18n/sample/package.i18n.json @@ -4,6 +4,7 @@ "viewsContainers.activitybar": "Zowe Explorer", "zowe.promptCredentials": "Update Credentials", "zowe.extRefresh": "Refresh Zowe Explorer", + "zowe.editHistory": "Edit History for Zowe Explorer", "zowe.ds.explorer": "Data Sets", "zowe.uss.explorer": "Unix System Services (USS)", "zowe.jobs.explorer": "Jobs", diff --git a/packages/zowe-explorer/i18n/sample/src/shared/HistoryView.i18n.json b/packages/zowe-explorer/i18n/sample/src/shared/HistoryView.i18n.json new file mode 100644 index 0000000000..9d8e611fde --- /dev/null +++ b/packages/zowe-explorer/i18n/sample/src/shared/HistoryView.i18n.json @@ -0,0 +1,3 @@ +{ + "HistoryView.addItem.prompt": "Type the new pattern to add to history" +} diff --git a/packages/zowe-explorer/package.json b/packages/zowe-explorer/package.json index 2c95e16902..457006e076 100644 --- a/packages/zowe-explorer/package.json +++ b/packages/zowe-explorer/package.json @@ -90,6 +90,11 @@ "key": "ctrl+alt+z", "mac": "cmd+alt+z" }, + { + "command": "zowe.editHistory", + "key": "ctrl+y", + "mac": "cmd+y" + }, { "command": "zowe.uss.copyUssFile", "key": "ctrl+c", @@ -150,6 +155,15 @@ "dark": "./resources/dark/refresh.svg" } }, + { + "command": "zowe.editHistory", + "title": "%zowe.editHistory%", + "category": "Zowe Explorer", + "icon": { + "light": "./resources/light/refresh.svg", + "dark": "./resources/dark/refresh.svg" + } + }, { "command": "zowe.ds.disableValidation", "title": "%disableValidation%", diff --git a/packages/zowe-explorer/package.nls.json b/packages/zowe-explorer/package.nls.json index 8bc5d8bf6c..2b99224dd7 100644 --- a/packages/zowe-explorer/package.nls.json +++ b/packages/zowe-explorer/package.nls.json @@ -4,6 +4,7 @@ "viewsContainers.activitybar": "Zowe Explorer", "zowe.promptCredentials": "Update Credentials", "zowe.extRefresh": "Refresh Zowe Explorer", + "zowe.editHistory": "Edit History for Zowe Explorer", "zowe.ds.explorer": "Data Sets", "zowe.uss.explorer": "Unix System Services (USS)", "zowe.jobs.explorer": "Jobs", diff --git a/packages/zowe-explorer/src/PersistentFilters.ts b/packages/zowe-explorer/src/PersistentFilters.ts index a9424b6502..b200a3ce35 100644 --- a/packages/zowe-explorer/src/PersistentFilters.ts +++ b/packages/zowe-explorer/src/PersistentFilters.ts @@ -200,6 +200,16 @@ export class PersistentFilters { return this.updateFileHistory(); } + public removeSearchHistory(name: string): Thenable { + const index = this.mSearchHistory.findIndex((searchHistoryItem) => { + return searchHistoryItem.includes(name); + }); + if (index >= 0) { + this.mSearchHistory.splice(index, 1); + } + return this.updateSearchHistory(); + } + /*********************************************************************************************************************************************/ /* Reset functions, for resetting the persistent array to empty (in the extension and in settings.json) /*********************************************************************************************************************************************/ diff --git a/packages/zowe-explorer/src/dataset/DatasetTree.ts b/packages/zowe-explorer/src/dataset/DatasetTree.ts index 41e428768d..92cced7001 100644 --- a/packages/zowe-explorer/src/dataset/DatasetTree.ts +++ b/packages/zowe-explorer/src/dataset/DatasetTree.ts @@ -757,6 +757,16 @@ export class DatasetTree extends ZoweTreeProvider implements IZoweTree { ZoweLogger.trace("ZosJobsProvider.getUserJobsMenuChoice called."); const items: FilterItem[] = this.mHistory diff --git a/packages/zowe-explorer/src/shared/HistoryView.ts b/packages/zowe-explorer/src/shared/HistoryView.ts new file mode 100644 index 0000000000..bef4a5f6e1 --- /dev/null +++ b/packages/zowe-explorer/src/shared/HistoryView.ts @@ -0,0 +1,122 @@ +/** + * This program and the accompanying materials are made available under the terms of the + * Eclipse Public License v2.0 which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-v20.html + * + * SPDX-License-Identifier: EPL-2.0 + * + * Copyright Contributors to the Zowe Project. + * + */ +import * as vscode from "vscode"; +import * as nls from "vscode-nls"; +import { WebView, Gui, DataSetAllocTemplate } from "@zowe/zowe-explorer-api"; +import { ExtensionContext } from "vscode"; +import { IZoweProviders } from "./init"; +import { USSTree } from "../uss/USSTree"; +import { DatasetTree } from "../dataset/DatasetTree"; +import { ZosJobsProvider } from "../job/ZosJobsProvider"; +import { ZoweLogger } from "../utils/LoggerUtils"; + +const localize: nls.LocalizeFunc = nls.loadMessageBundle(); + +type TreeProvider = USSTree | DatasetTree | ZosJobsProvider; + +type History = { + search: string[]; + sessions: string[]; + fileHistory: string[]; + dsTemplates?: DataSetAllocTemplate[]; + favorites: string[]; +}; + +const tabs = { + ds: "ds-panel-tab", + uss: "uss-panel-tab", + jobs: "jobs-panel-tab", +}; + +export class HistoryView extends WebView { + private treeProviders: IZoweProviders; + private currentTab: string; + + public constructor(context: ExtensionContext, treeProviders: IZoweProviders) { + const label = "Edit History"; + super(label, "edit-history", context, (message: object) => this.onDidReceiveMessage(message)); + this.treeProviders = treeProviders; + } + + protected async onDidReceiveMessage(message: any): Promise { + switch (message.command) { + case "refresh": + await this.refreshView(message); + break; + case "ready": + await this.panel.webview.postMessage({ + ds: this.getHistoryData("ds"), + uss: this.getHistoryData("uss"), + jobs: this.getHistoryData("job"), + tab: this.currentTab, + }); + break; + case "add-item": + await this.addItem(message); + break; + case "remove-item": + await this.removeItem(message); + break; + case "clear-all": + await this.clearAll(message); + break; + default: + break; + } + } + + private getTreeProvider(type: string): TreeProvider { + return this.treeProviders[type === "jobs" ? "job" : type] as TreeProvider; + } + + private getHistoryData(type: string): History { + const treeProvider = this.treeProviders[type] as TreeProvider; + return { + search: treeProvider.getSearchHistory(), + sessions: treeProvider.getSessions(), + fileHistory: treeProvider.getFileHistory(), + dsTemplates: type === "ds" ? (treeProvider as DatasetTree).getDsTemplates() : undefined, + favorites: treeProvider.getFavorites(), + }; + } + + private async addItem(message): Promise { + ZoweLogger.trace("HistoryView.addItem called."); + const options: vscode.InputBoxOptions = { + prompt: localize("HistoryView.addItem.prompt", "Type the new pattern to add to history"), + value: "", + }; + const item = await Gui.showInputBox(options); + const treeProvider = this.getTreeProvider(message.attrs.type); + treeProvider.addSearchHistory(item); + await this.refreshView(message); + } + + private async removeItem(message): Promise { + ZoweLogger.trace("HistoryView.removeItem called."); + const treeProvider = this.getTreeProvider(message.attrs.type); + treeProvider.removeSearchHistory(message.attrs.name); + await this.refreshView(message); + } + + private async clearAll(message): Promise { + ZoweLogger.trace("HistoryView.clearAll called."); + const treeProvider = this.getTreeProvider(message.attrs.type); + treeProvider.resetSearchHistory(); + await this.refreshView(message); + } + + private async refreshView(message): Promise { + ZoweLogger.trace("HistoryView.refreshView called."); + this.currentTab = tabs[message.attrs.type]; + await vscode.commands.executeCommand("workbench.action.webview.reloadWebviewAction"); + } +} diff --git a/packages/zowe-explorer/src/shared/init.ts b/packages/zowe-explorer/src/shared/init.ts index d023a1a969..2a59c88287 100644 --- a/packages/zowe-explorer/src/shared/init.ts +++ b/packages/zowe-explorer/src/shared/init.ts @@ -27,6 +27,7 @@ import { ZoweLogger } from "../utils/LoggerUtils"; import { ZoweSaveQueue } from "../abstract/ZoweSaveQueue"; import { SettingsConfig } from "../utils/SettingsConfig"; import { spoolFilePollEvent } from "../job/actions"; +import { HistoryView } from "./HistoryView"; // Set up localization nls.config({ @@ -78,6 +79,13 @@ export function registerCommonCommands(context: vscode.ExtensionContext, provide }) ); + // Webview for editing persistent items on Zowe Explorer + context.subscriptions.push( + vscode.commands.registerCommand("zowe.editHistory", () => { + return new HistoryView(context, providers); + }) + ); + // Update imperative.json to false only when VS Code setting is set to false context.subscriptions.push( vscode.commands.registerCommand("zowe.updateSecureCredentials", async (customCredentialManager?: string) => { diff --git a/packages/zowe-explorer/src/uss/USSTree.ts b/packages/zowe-explorer/src/uss/USSTree.ts index c53a3b3fd3..45b143e7ed 100644 --- a/packages/zowe-explorer/src/uss/USSTree.ts +++ b/packages/zowe-explorer/src/uss/USSTree.ts @@ -850,6 +850,26 @@ export class USSTree extends ZoweTreeProvider implements IZoweTree + +
+ ); +} + +function View(): JSXInternal.Element { + const [loading, setLoading] = useState(true); + + useEffect(() => { + setLoading(false); + }, []); + + return loading ? Loading : ; +} + +function Body(): JSXInternal.Element { + const [currentTab, setCurrentTab] = useState(""); + + useEffect(() => { + window.addEventListener("message", (event) => { + if ("tab" in event.data) { + setCurrentTab(event.data.tab); + } + }); + vscodeApi.postMessage({ command: "ready" }); + }, []); + + return ( +
+

Manage Persistent Properties

+ + +

Data Sets

+
+ +

Unix System Services (USS)

+
+ +

Jobs

+
+ + + +
+
+ ); +} + +function UtilitiesBar({ type }: { type: string }): JSXInternal.Element { + return ( +
+ + + + +
+ ); +} + +function DropdownPersistentOptions(): JSXInternal.Element { + return ( +
+ + DS Templates + Favorites + File History + Search History + Sessions + +
+ ); +} + +function AddNewHistoryItemButton({ type }: { type: string }): JSXInternal.Element { + const handleClick = () => { + vscodeApi.postMessage({ + command: "add-item", + attrs: { + type, + }, + }); + }; + + return ( + + Add Item + + ); +} + +function RefreshButton({ type }: { type: string }): JSXInternal.Element { + const handleClick = () => { + vscodeApi.postMessage({ + command: "refresh", + attrs: { + type, + }, + }); + }; + + return ( + + Refresh + + ); +} + +function ClearAllButton({ type }: { type: string }): JSXInternal.Element { + const handleClick = () => { + vscodeApi.postMessage({ + command: "clear-all", + attrs: { + type, + }, + }); + }; + + return ( + + Clear All + + ); +} + +function DataGridHeaders(): JSXInternal.Element { + return ( + + + Item + + + Delete + + + ); +} + +function TableData({ type }: { type: string }): JSXInternal.Element { + const [persistentProperty, setPersistentProperty] = useState([]); + + useEffect(() => { + window.addEventListener("message", (event) => { + if (type in event.data) { + setPersistentProperty(event.data[type]["search"]); + } + }); + }, []); + + const handleClick = (item: number) => { + vscodeApi.postMessage({ + command: "remove-item", + attrs: { + name: persistentProperty[item], + type, + }, + }); + }; + + const data = persistentProperty.map((item, i) => { + return ( + + {item} + handleClick(i)} style={{ maxWidth: "5vw", textAlign: "center" }}> + + + + ); + }); + + return <>{data}; +} + +function DsPanel(): JSXInternal.Element { + const type = "ds"; + return ( + + + + + + + + ); +} + +function USSPanel(): JSXInternal.Element { + const type = "uss"; + + return ( + + + + + + + + ); +} + +function JobsPanel(): JSXInternal.Element { + const type = "jobs"; + + return ( + + + + + + + + ); +} diff --git a/packages/zowe-explorer/src/webviews/src/edit-history/assets/trash.svg b/packages/zowe-explorer/src/webviews/src/edit-history/assets/trash.svg new file mode 100644 index 0000000000..a0772f3802 --- /dev/null +++ b/packages/zowe-explorer/src/webviews/src/edit-history/assets/trash.svg @@ -0,0 +1,2 @@ + + diff --git a/packages/zowe-explorer/src/webviews/src/edit-history/index.html b/packages/zowe-explorer/src/webviews/src/edit-history/index.html new file mode 100644 index 0000000000..5789513d71 --- /dev/null +++ b/packages/zowe-explorer/src/webviews/src/edit-history/index.html @@ -0,0 +1,12 @@ + + + + + + Edit Attributes + + +
+ + + diff --git a/packages/zowe-explorer/src/webviews/src/edit-history/index.tsx b/packages/zowe-explorer/src/webviews/src/edit-history/index.tsx new file mode 100644 index 0000000000..74832990aa --- /dev/null +++ b/packages/zowe-explorer/src/webviews/src/edit-history/index.tsx @@ -0,0 +1,4 @@ +import { render } from "preact"; +import { App } from "./App"; + +render(, document.getElementById("webviewRoot")!); From 353ff74fe3172cb6549f573b34a7b0b5da1d00d9 Mon Sep 17 00:00:00 2001 From: Timothy Johnson Date: Fri, 6 Oct 2023 13:38:27 -0400 Subject: [PATCH 088/189] Fix conflict resolution skipped if local and remote file are same size Signed-off-by: Timothy Johnson --- packages/zowe-explorer/CHANGELOG.md | 1 + .../__mocks__/mockCreators/shared.ts | 6 +- .../__unit__/dataset/actions.unit.test.ts | 68 +++++++++++++++++++ packages/zowe-explorer/src/shared/utils.ts | 22 +++++- 4 files changed, 93 insertions(+), 4 deletions(-) diff --git a/packages/zowe-explorer/CHANGELOG.md b/packages/zowe-explorer/CHANGELOG.md index e00358e7bd..c96a16391a 100644 --- a/packages/zowe-explorer/CHANGELOG.md +++ b/packages/zowe-explorer/CHANGELOG.md @@ -13,6 +13,7 @@ All notable changes to the "vscode-extension-for-zowe" extension will be documen ### Bug fixes - Fixed submitting local JCL using command pallet option `Zowe Explorer: Submit JCL` by adding a check for chosen profile returned to continue the action. [#1625](https://github.com/zowe/vscode-extension-for-zowe/issues/1625) +- Fixed conflict resolution being skipped if local and remote file have different contents but are the same size. [#2496](https://github.com/zowe/vscode-extension-for-zowe/issues/2496) ## `2.11.0` diff --git a/packages/zowe-explorer/__mocks__/mockCreators/shared.ts b/packages/zowe-explorer/__mocks__/mockCreators/shared.ts index 1133c38687..fb08566cf2 100644 --- a/packages/zowe-explorer/__mocks__/mockCreators/shared.ts +++ b/packages/zowe-explorer/__mocks__/mockCreators/shared.ts @@ -259,12 +259,12 @@ export function createTextDocument(name: string, sessionNode?: ZoweDatasetNode | isDirty: null, isClosed: null, save: null, - eol: null, + eol: 1, lineCount: null, lineAt: null, offsetAt: null, - positionAt: null, - getText: jest.fn(), + positionAt: jest.fn(), + getText: jest.fn().mockReturnValue(""), getWordRangeAtPosition: null, validateRange: null, validatePosition: null, diff --git a/packages/zowe-explorer/__tests__/__unit__/dataset/actions.unit.test.ts b/packages/zowe-explorer/__tests__/__unit__/dataset/actions.unit.test.ts index 09c1e79759..93aeba652e 100644 --- a/packages/zowe-explorer/__tests__/__unit__/dataset/actions.unit.test.ts +++ b/packages/zowe-explorer/__tests__/__unit__/dataset/actions.unit.test.ts @@ -1454,6 +1454,74 @@ describe("Dataset Actions Unit Tests - Function saveFile", () => { logSpy.mockClear(); commandSpy.mockClear(); }); + + it("Checking common dataset saving failed due to conflict with server version when file size has not changed", async () => { + globals.defineGlobals(""); + createGlobalMocks(); + const blockMocks = createBlockMocks(); + const node = new ZoweDatasetNode( + "HLQ.TEST.AFILE", + vscode.TreeItemCollapsibleState.None, + blockMocks.datasetSessionNode, + null, + undefined, + undefined, + blockMocks.imperativeProfile + ); + blockMocks.datasetSessionNode.children.push(node); + + mocked(sharedUtils.concatChildNodes).mockReturnValueOnce([node]); + blockMocks.testDatasetTree.getChildren.mockReturnValueOnce([blockMocks.datasetSessionNode]); + mocked(zowe.List.dataSet).mockResolvedValue({ + success: true, + commandResponse: "", + apiResponse: { + items: [{ dsname: "HLQ.TEST.AFILE" }], + }, + }); + mocked(zowe.Upload.pathToDataSet).mockResolvedValueOnce({ + success: false, + commandResponse: "Rest API failure with HTTP(S) status 412", + apiResponse: [], + }); + + mocked(vscode.window.withProgress).mockImplementation((progLocation, callback) => { + return callback(); + }); + const profile = blockMocks.imperativeProfile; + profile.profile.encoding = 1047; + blockMocks.profileInstance.loadNamedProfile.mockReturnValueOnce(blockMocks.imperativeProfile); + mocked(Profiles.getInstance).mockReturnValue(blockMocks.profileInstance); + Object.defineProperty(wsUtils, "markDocumentUnsaved", { + value: jest.fn(), + configurable: true, + }); + Object.defineProperty(context, "isTypeUssTreeNode", { + value: jest.fn().mockReturnValueOnce(false), + configurable: true, + }); + Object.defineProperty(ZoweExplorerApiRegister.getMvsApi, "getContents", { + value: jest.fn(), + configurable: true, + }); + + const testDocument = createTextDocument("HLQ.TEST.AFILE", blockMocks.datasetSessionNode); + (testDocument as any).fileName = path.join(globals.DS_DIR, testDocument.fileName); + const logSpy = jest.spyOn(ZoweLogger, "warn"); + const commandSpy = jest.spyOn(vscode.commands, "executeCommand"); + const applyEditSpy = jest.spyOn(vscode.workspace, "applyEdit"); + jest.spyOn(fs, "statSync").mockReturnValueOnce({ size: 0 } as any); + + await dsActions.saveFile(testDocument, blockMocks.testDatasetTree); + + expect(logSpy).toBeCalledWith("Remote file has changed. Presenting with way to resolve file."); + expect(mocked(sharedUtils.concatChildNodes)).toBeCalled(); + expect(commandSpy).toBeCalledWith("workbench.files.action.compareWithSaved"); + expect(applyEditSpy).toHaveBeenCalledTimes(2); + logSpy.mockClear(); + commandSpy.mockClear(); + applyEditSpy.mockClear(); + }); }); describe("Dataset Actions Unit Tests - Function showAttributes", () => { diff --git a/packages/zowe-explorer/src/shared/utils.ts b/packages/zowe-explorer/src/shared/utils.ts index 98b6a293ad..354c9a6732 100644 --- a/packages/zowe-explorer/src/shared/utils.ts +++ b/packages/zowe-explorer/src/shared/utils.ts @@ -11,6 +11,7 @@ // Generic utility functions related to all node types. See ./src/utils.ts for other utility functions. +import * as fs from "fs"; import * as vscode from "vscode"; import * as path from "path"; import * as globals from "../globals"; @@ -383,8 +384,27 @@ export async function compareFileContent( responseTimeout: prof.profile?.responseTimeout, }); } + + // If local and remote file size are the same, then VS Code won't detect + // there is a conflict and remote changes may get overwritten. To work + // around this limitation of VS Code, when the sizes are identical we + // temporarily add a trailing newline byte to the local copy which forces + // the file size to be different. This is a terrible hack but it works. + // See https://github.com/microsoft/vscode/issues/119002 + const oldSize = doc.getText().length; + const newSize = fs.statSync(doc.fileName).size; + if (newSize === oldSize) { + const edits = new vscode.WorkspaceEdit(); + edits.insert(doc.uri, doc.positionAt(oldSize), doc.eol.toString()); + await vscode.workspace.applyEdit(edits); + } ZoweLogger.warn(localize("saveFile.etagMismatch.log.warning", "Remote file has changed. Presenting with way to resolve file.")); - vscode.commands.executeCommand("workbench.files.action.compareWithSaved"); + await vscode.commands.executeCommand("workbench.files.action.compareWithSaved"); + if (newSize === oldSize) { + const edits2 = new vscode.WorkspaceEdit(); + edits2.delete(doc.uri, new vscode.Range(doc.positionAt(oldSize), doc.positionAt(oldSize + doc.eol.toString().length))); + await vscode.workspace.applyEdit(edits2); + } // re-assign etag, so that it can be used with subsequent requests const downloadEtag = downloadResponse?.apiResponse?.etag; if (node && downloadEtag !== node.getEtag()) { From 88fe3d5c0a7ddb82881c3aeffe57d55dae33a2b5 Mon Sep 17 00:00:00 2001 From: Rudy Flores <68666202+rudyflores@users.noreply.github.com> Date: Fri, 6 Oct 2023 14:51:19 -0400 Subject: [PATCH 089/189] Add missing webviews to vsix bundle Signed-off-by: Rudy Flores <68666202+rudyflores@users.noreply.github.com> --- packages/zowe-explorer/.vscodeignore | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/zowe-explorer/.vscodeignore b/packages/zowe-explorer/.vscodeignore index 931447bc41..0a539b22c5 100644 --- a/packages/zowe-explorer/.vscodeignore +++ b/packages/zowe-explorer/.vscodeignore @@ -8,7 +8,7 @@ !resources/**/*.png !resources/**/*.svg !prebuilds/** -!webviews/*/dist/ +!src/webviews/dist/** !CHANGELOG.md !LICENSE From a0b70a0075c38ca8d9ae5d5d08695c3fa0cf2ec4 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 8 Oct 2023 04:26:05 +0000 Subject: [PATCH 090/189] chore(deps): Bump postcss from 8.4.30 to 8.4.31 Bumps [postcss](https://github.com/postcss/postcss) from 8.4.30 to 8.4.31. - [Release notes](https://github.com/postcss/postcss/releases) - [Changelog](https://github.com/postcss/postcss/blob/main/CHANGELOG.md) - [Commits](https://github.com/postcss/postcss/compare/8.4.30...8.4.31) --- updated-dependencies: - dependency-name: postcss dependency-type: indirect ... Signed-off-by: dependabot[bot] --- yarn.lock | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/yarn.lock b/yarn.lock index 98322a7d33..08e9d1f09a 100644 --- a/yarn.lock +++ b/yarn.lock @@ -9517,9 +9517,9 @@ posix-character-classes@^0.1.0: integrity sha1-AerA/jta9xoqbAL+q7jB/vfgDqs= postcss@^8.4.27: - version "8.4.30" - resolved "https://registry.npmjs.org/postcss/-/postcss-8.4.30.tgz#0e0648d551a606ef2192a26da4cabafcc09c1aa7" - integrity sha512-7ZEao1g4kd68l97aWG/etQKPKq07us0ieSZ2TnFDk11i0ZfDW2AwKHYU8qv4MZKqN2fdBfg+7q0ES06UA73C1g== + version "8.4.31" + resolved "https://registry.npmjs.org/postcss/-/postcss-8.4.31.tgz#92b451050a9f914da6755af352bdc0192508656d" + integrity sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ== dependencies: nanoid "^3.3.6" picocolors "^1.0.0" From b1755a9f7e269b4071f6dbed0a3405233140b389 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 9 Oct 2023 11:43:46 +0000 Subject: [PATCH 091/189] chore(deps): Bump postcss Bumps [postcss](https://github.com/postcss/postcss) from 8.4.27 to 8.4.31. - [Release notes](https://github.com/postcss/postcss/releases) - [Changelog](https://github.com/postcss/postcss/blob/main/CHANGELOG.md) - [Commits](https://github.com/postcss/postcss/compare/8.4.27...8.4.31) --- updated-dependencies: - dependency-name: postcss dependency-type: indirect ... Signed-off-by: dependabot[bot] --- samples/vue-webview-sample/webviews/vue-sample/yarn.lock | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/samples/vue-webview-sample/webviews/vue-sample/yarn.lock b/samples/vue-webview-sample/webviews/vue-sample/yarn.lock index 1ff23b64ea..af86b44273 100644 --- a/samples/vue-webview-sample/webviews/vue-sample/yarn.lock +++ b/samples/vue-webview-sample/webviews/vue-sample/yarn.lock @@ -367,9 +367,9 @@ picocolors@^1.0.0: integrity sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ== postcss@^8.1.10, postcss@^8.4.27: - version "8.4.27" - resolved "https://registry.npmjs.org/postcss/-/postcss-8.4.27.tgz#234d7e4b72e34ba5a92c29636734349e0d9c3057" - integrity sha512-gY/ACJtJPSmUFPDCHtX78+01fHa64FaU4zaaWfuh1MhGJISufJAH4cun6k/8fwsHYeK4UQmENQK+tRLCFJE8JQ== + version "8.4.31" + resolved "https://registry.npmjs.org/postcss/-/postcss-8.4.31.tgz#92b451050a9f914da6755af352bdc0192508656d" + integrity sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ== dependencies: nanoid "^3.3.6" picocolors "^1.0.0" From 065e285627e6116ac8d3fa0d9ff2bf793a2bccec Mon Sep 17 00:00:00 2001 From: Trae Yelovich Date: Mon, 9 Oct 2023 13:44:01 -0400 Subject: [PATCH 092/189] feat(ds): Filter PDS members (session-level and PDS-level); fix broken tests Signed-off-by: Trae Yelovich --- .../src/tree/IZoweTreeNode.ts | 26 +++- .../__tests__/__unit__/ZoweNode.unit.test.ts | 3 +- .../__unit__/dataset/DatasetTree.unit.test.ts | 10 +- .../__tests__/__unit__/extension.unit.test.ts | 1 + .../__unit__/job/ZoweJobNode.unit.test.ts | 4 +- .../__unit__/job/actions.unit.test.ts | 20 ++- .../i18n/sample/package.i18n.json | 5 + .../sample/src/dataset/DatasetTree.i18n.json | 9 ++ .../i18n/sample/src/dataset/utils.i18n.json | 7 +- .../i18n/sample/src/globals.i18n.json | 1 + .../i18n/sample/src/job/actions.i18n.json | 6 +- .../i18n/sample/src/job/utils.i18n.json | 9 +- .../i18n/sample/src/shared/utils.i18n.json | 2 + packages/zowe-explorer/package.json | 23 +++- packages/zowe-explorer/package.nls.json | 2 + .../zowe-explorer/src/dataset/DatasetTree.ts | 127 ++++++++++++++++-- .../src/dataset/ZoweDatasetNode.ts | 80 +++++++++-- packages/zowe-explorer/src/dataset/init.ts | 6 + packages/zowe-explorer/src/dataset/utils.ts | 16 ++- packages/zowe-explorer/src/globals.ts | 3 +- .../zowe-explorer/src/job/ZosJobsProvider.ts | 4 +- packages/zowe-explorer/src/job/ZoweJobNode.ts | 27 ++-- packages/zowe-explorer/src/job/actions.ts | 26 +++- packages/zowe-explorer/src/job/utils.ts | 9 +- packages/zowe-explorer/src/shared/utils.ts | 7 +- yarn.lock | 5 + 26 files changed, 366 insertions(+), 72 deletions(-) diff --git a/packages/zowe-explorer-api/src/tree/IZoweTreeNode.ts b/packages/zowe-explorer-api/src/tree/IZoweTreeNode.ts index 6a997e9719..0055a72814 100644 --- a/packages/zowe-explorer-api/src/tree/IZoweTreeNode.ts +++ b/packages/zowe-explorer-api/src/tree/IZoweTreeNode.ts @@ -31,6 +31,26 @@ export enum DatasetSortOpts { UserId, } +export enum SortDirection { + Ascending, + Descending, +} + +export enum DatasetFilterOpts { + LastModified, + UserId, +} + +export type DatasetFilter = { + method: DatasetFilterOpts; + value: string; +}; + +export type NodeSort = { + method: DatasetSortOpts | JobSortOpts; + direction: SortDirection; +}; + export enum JobSortOpts { Id, DateSubmitted, @@ -99,7 +119,7 @@ export interface IZoweTreeNode { /** * Sorting method for this node's children */ - sortMethod?: DatasetSortOpts | JobSortOpts; + sort?: NodeSort; /** * Retrieves the node label */ @@ -161,6 +181,10 @@ export interface IZoweDatasetTreeNode extends IZoweTreeNode { * Additional statistics about this data set */ stats?: Partial; + /** + * Filter method for this data set's children + */ + filter?: DatasetFilter; /** * Retrieves child nodes of this IZoweDatasetTreeNode * diff --git a/packages/zowe-explorer/__tests__/__unit__/ZoweNode.unit.test.ts b/packages/zowe-explorer/__tests__/__unit__/ZoweNode.unit.test.ts index 8aa7ec2dec..f7a716e91c 100644 --- a/packages/zowe-explorer/__tests__/__unit__/ZoweNode.unit.test.ts +++ b/packages/zowe-explorer/__tests__/__unit__/ZoweNode.unit.test.ts @@ -356,7 +356,7 @@ describe("Unit Tests (Jest)", () => { }), }); const sessionNode = { getSessionNode: jest.fn(), sortMethod: DatasetSortOpts.Name } as unknown as ZoweDatasetNode; - jest.spyOn(ZoweDatasetNode.prototype, "getSessionNode").mockReturnValueOnce(sessionNode); + const getSessionNodeSpy = jest.spyOn(ZoweDatasetNode.prototype, "getSessionNode").mockReturnValue(sessionNode); // Creating a rootNode const pds = new ZoweDatasetNode( "[root]: something", @@ -384,6 +384,7 @@ describe("Unit Tests (Jest)", () => { expect(pdsChildren[0].contextValue).toEqual(globals.DS_FILE_ERROR_CONTEXT); expect(pdsChildren[1].label).toEqual("GOODMEM1"); expect(pdsChildren[1].contextValue).toEqual(globals.DS_MEMBER_CONTEXT); + getSessionNodeSpy.mockRestore(); }); /************************************************************************************************************* 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 76d3d6a604..6063c7f6b4 100644 --- a/packages/zowe-explorer/__tests__/__unit__/dataset/DatasetTree.unit.test.ts +++ b/packages/zowe-explorer/__tests__/__unit__/dataset/DatasetTree.unit.test.ts @@ -2741,14 +2741,14 @@ describe("Dataset Tree Unit Tests - Function sortBy", () => { it("calls refreshElement if no children exist", async () => { // case 1: called on session node - mocks.showQuickPick.mockResolvedValueOnce("Name" as any); + mocks.showQuickPick.mockResolvedValueOnce({ label: "$(case-sensitive) Name (default)" }); testPds.children = []; await testTree.sortPdsMembers(testPds); expect(mocks.nodeDataChanged).not.toHaveBeenCalled(); expect(mocks.refreshElement).toHaveBeenCalledWith(testPds); // case 2: called on PDS node - mocks.showQuickPick.mockResolvedValueOnce("Name" as any); + mocks.showQuickPick.mockResolvedValueOnce({ label: "$(case-sensitive) Name (default)" }); testSession.children = []; await testTree.sortPdsMembers(testSession); expect(mocks.nodeDataChanged).not.toHaveBeenCalled(); @@ -2756,7 +2756,7 @@ describe("Dataset Tree Unit Tests - Function sortBy", () => { }); it("sorts by name", async () => { - mocks.showQuickPick.mockResolvedValueOnce("Name" as any); + mocks.showQuickPick.mockResolvedValueOnce({ label: "$(case-sensitive) Name (default)" }); await testTree.sortPdsMembers(testPds); expect(mocks.nodeDataChanged).toHaveBeenCalled(); expect(mocks.refreshElement).not.toHaveBeenCalled(); @@ -2764,7 +2764,7 @@ describe("Dataset Tree Unit Tests - Function sortBy", () => { }); it("sorts by last modified date", async () => { - mocks.showQuickPick.mockResolvedValueOnce("Date Modified" as any); + mocks.showQuickPick.mockResolvedValueOnce({ label: "$(calendar) Date Modified" }); await testTree.sortPdsMembers(testPds); expect(mocks.nodeDataChanged).toHaveBeenCalled(); expect(mocks.refreshElement).not.toHaveBeenCalled(); @@ -2772,7 +2772,7 @@ describe("Dataset Tree Unit Tests - Function sortBy", () => { }); it("sorts by user ID", async () => { - mocks.showQuickPick.mockResolvedValueOnce("User ID" as any); + mocks.showQuickPick.mockResolvedValueOnce({ label: "$(account) User ID" }); await testTree.sortPdsMembers(testPds); expect(mocks.nodeDataChanged).toHaveBeenCalled(); expect(mocks.refreshElement).not.toHaveBeenCalled(); diff --git a/packages/zowe-explorer/__tests__/__unit__/extension.unit.test.ts b/packages/zowe-explorer/__tests__/__unit__/extension.unit.test.ts index 4f3294d3b4..19d4a1ea58 100644 --- a/packages/zowe-explorer/__tests__/__unit__/extension.unit.test.ts +++ b/packages/zowe-explorer/__tests__/__unit__/extension.unit.test.ts @@ -177,6 +177,7 @@ async function createGlobalMocks() { "zowe.ds.ssoLogin", "zowe.ds.ssoLogout", "zowe.ds.sortBy", + "zowe.ds.filterBy", "zowe.uss.addFavorite", "zowe.uss.removeFavorite", "zowe.uss.addSession", diff --git a/packages/zowe-explorer/__tests__/__unit__/job/ZoweJobNode.unit.test.ts b/packages/zowe-explorer/__tests__/__unit__/job/ZoweJobNode.unit.test.ts index 4bfa4a8f33..ec06c21ef7 100644 --- a/packages/zowe-explorer/__tests__/__unit__/job/ZoweJobNode.unit.test.ts +++ b/packages/zowe-explorer/__tests__/__unit__/job/ZoweJobNode.unit.test.ts @@ -16,7 +16,7 @@ import * as zowe from "@zowe/cli"; import * as globals from "../../../src/globals"; import { createIJobFile, createIJobObject, createJobSessionNode } from "../../../__mocks__/mockCreators/jobs"; import { Job } from "../../../src/job/ZoweJobNode"; -import { IZoweJobTreeNode, ProfilesCache, Gui, JobSortOpts } from "@zowe/zowe-explorer-api"; +import { IZoweJobTreeNode, ProfilesCache, Gui, JobSortOpts, SortDirection } from "@zowe/zowe-explorer-api"; import { ZoweExplorerApiRegister } from "../../../src/ZoweExplorerApiRegister"; import { Profiles } from "../../../src/Profiles"; import * as sessUtils from "../../../src/utils/SessionUtils"; @@ -851,7 +851,7 @@ describe("Job - sortJobs", () => { jobid: "JOBID120", }, } as IZoweJobTreeNode, - ].sort(Job.sortJobs(JobSortOpts.Id)); + ].sort(Job.sortJobs({ method: JobSortOpts.Id, direction: SortDirection.Ascending })); expect(sorted[0].job.jobid).toBe("JOBID120"); expect(sorted[1].job.jobid).toBe("JOBID120"); expect(sorted[2].job.jobid).toBe("JOBID123"); diff --git a/packages/zowe-explorer/__tests__/__unit__/job/actions.unit.test.ts b/packages/zowe-explorer/__tests__/__unit__/job/actions.unit.test.ts index b9083fb6fb..5f43c7283d 100644 --- a/packages/zowe-explorer/__tests__/__unit__/job/actions.unit.test.ts +++ b/packages/zowe-explorer/__tests__/__unit__/job/actions.unit.test.ts @@ -11,7 +11,7 @@ import * as vscode from "vscode"; import * as zowe from "@zowe/cli"; -import { Gui, IZoweJobTreeNode, ValidProfileEnum } from "@zowe/zowe-explorer-api"; +import { Gui, IZoweJobTreeNode, JobSortOpts, SortDirection, ValidProfileEnum } from "@zowe/zowe-explorer-api"; import { Job, Spool } from "../../../src/job/ZoweJobNode"; import { createISession, @@ -1352,9 +1352,13 @@ describe("sortjobsby function", () => { const globalMocks = createGlobalMocks(); const testtree = new ZosJobsProvider(); const expected = new ZosJobsProvider(); + testtree.mSessionNodes[0].sort = { + method: JobSortOpts.Id, + direction: SortDirection.Ascending, + }; testtree.mSessionNodes[0].children = [...[globalMocks()[2], globalMocks()[1], globalMocks()[0]]]; expected.mSessionNodes[0].children = [...[globalMocks()[1], globalMocks()[0], globalMocks()[2]]]; - jest.spyOn(Gui, "showQuickPick").mockResolvedValueOnce("Job Name" as any); + jest.spyOn(Gui, "showQuickPick").mockResolvedValueOnce({ label: "$(case-sensitive) Job Name" }); const sortbynamespy = jest.spyOn(ZosJobsProvider.prototype, "sortBy"); //act await jobActions.sortJobs(testtree.mSessionNodes[0], testtree); @@ -1367,10 +1371,14 @@ describe("sortjobsby function", () => { const globalMocks = createGlobalMocks(); const testtree = new ZosJobsProvider(); const expected = new ZosJobsProvider(); + testtree.mSessionNodes[0].sort = { + method: JobSortOpts.Id, + direction: SortDirection.Ascending, + }; testtree.mSessionNodes[0].children = [...[globalMocks()[2], globalMocks()[1], globalMocks()[0]]]; expected.mSessionNodes[0].children = [...[globalMocks()[1], globalMocks()[0], globalMocks()[2]]]; const sortbyidspy = jest.spyOn(ZosJobsProvider.prototype, "sortBy"); - jest.spyOn(Gui, "showQuickPick").mockResolvedValueOnce("Job ID" as any); + jest.spyOn(Gui, "showQuickPick").mockResolvedValueOnce({ label: "$(list-ordered) Job ID (default)" }); //act await jobActions.sortJobs(testtree.mSessionNodes[0], testtree); //asert @@ -1382,10 +1390,14 @@ describe("sortjobsby function", () => { const globalMocks = createGlobalMocks(); const testtree = new ZosJobsProvider(); const expected = new ZosJobsProvider(); + testtree.mSessionNodes[0].sort = { + method: JobSortOpts.Id, + direction: SortDirection.Ascending, + }; testtree.mSessionNodes[0].children = [...[globalMocks()[2], globalMocks()[1], globalMocks()[0]]]; expected.mSessionNodes[0].children = [...[globalMocks()[0], globalMocks()[1], globalMocks()[2]]]; const sortbyretcodespy = jest.spyOn(ZosJobsProvider.prototype, "sortBy"); - jest.spyOn(Gui, "showQuickPick").mockResolvedValueOnce("Return Code" as any); + jest.spyOn(Gui, "showQuickPick").mockResolvedValueOnce({ label: "$(symbol-numeric) Return Code" }); //act await jobActions.sortJobs(testtree.mSessionNodes[0], testtree); diff --git a/packages/zowe-explorer/i18n/sample/package.i18n.json b/packages/zowe-explorer/i18n/sample/package.i18n.json index a9ce9a9d1a..fe540d76c5 100644 --- a/packages/zowe-explorer/i18n/sample/package.i18n.json +++ b/packages/zowe-explorer/i18n/sample/package.i18n.json @@ -148,6 +148,11 @@ "copyFile": "Copy", "pasteFile": "Paste", "jobs.sortBy": "Sort jobs...", + "ds.allPdsSort": "all PDS members in {0}", + "ds.singlePdsSort": "the PDS members in {0}", + "ds.selectFilterOpt": "Set a filter for {0}", + "ds.selectSortOpt": "Select a sorting option for {0}", "jobs.selectSortOpt": "Select a sorting option for jobs in {0}", + "ds.filterBy": "Filter PDS members...", "ds.sortBy": "Sort PDS members..." } diff --git a/packages/zowe-explorer/i18n/sample/src/dataset/DatasetTree.i18n.json b/packages/zowe-explorer/i18n/sample/src/dataset/DatasetTree.i18n.json index ffdd605c77..c3ac5386eb 100644 --- a/packages/zowe-explorer/i18n/sample/src/dataset/DatasetTree.i18n.json +++ b/packages/zowe-explorer/i18n/sample/src/dataset/DatasetTree.i18n.json @@ -29,5 +29,14 @@ "ds.allPdsSort": "all PDS members in {0}", "ds.singlePdsSort": "the PDS members in {0}", "ds.selectSortOpt": "Select a sorting option for {0}", + "setSortDirection": "$(fold) Sort Direction", + "sort.asc": "Ascending", + "sort.desc": "Descending", + "sort.selectDirection": "Select a sorting direction", + "ds.clearAllFilters": "$(clear-all) Clear all filters", + "ds.clearPdsFilter": "$(clear-all) Clear filters for this PDS", + "ds.selectFilterOpt": "Set a filter for {0}", + "ds.filterEntry.title": "Enter a value to filter by", + "ds.filterEntry.invalidDate": "Invalid date format specified", "defaultFilterPrompt.option.prompt.search": "$(plus) Create a new filter. For example: HLQ.*, HLQ.aaa.bbb, HLQ.ccc.ddd(member)" } diff --git a/packages/zowe-explorer/i18n/sample/src/dataset/utils.i18n.json b/packages/zowe-explorer/i18n/sample/src/dataset/utils.i18n.json index 55ee3b4e20..0aad47e3d5 100644 --- a/packages/zowe-explorer/i18n/sample/src/dataset/utils.i18n.json +++ b/packages/zowe-explorer/i18n/sample/src/dataset/utils.i18n.json @@ -1,5 +1,6 @@ { - "ds.sortByName": "Name", - "ds.sortByModified": "Date Modified", - "ds.sortByUserId": "User ID" + "ds.sortByName": "$(case-sensitive) Name (default)", + "ds.sortByModified": "$(calendar) Date Modified", + "ds.sortByUserId": "$(account) User ID", + "setSortDirection": "$(fold) Sort Direction" } diff --git a/packages/zowe-explorer/i18n/sample/src/globals.i18n.json b/packages/zowe-explorer/i18n/sample/src/globals.i18n.json index ec7d8bddd5..a6c64f66d8 100644 --- a/packages/zowe-explorer/i18n/sample/src/globals.i18n.json +++ b/packages/zowe-explorer/i18n/sample/src/globals.i18n.json @@ -17,6 +17,7 @@ "createFile.attribute.storclass": "Enter the SMS storage class", "createFile.attribute.volser": "Enter the volume serial on which the data set should be placed", "zowe.separator.recentFilters": "Recent Filters", + "zowe.separator.options": "Options", "globals.defineGlobals.isTheia": "Zowe Explorer is running in Theia environment.", "globals.defineGlobals.tempFolder": "Zowe Explorer's temp folder is located at {0}", "globals.setActivated.success": "Zowe Explorer has activated successfully.", diff --git a/packages/zowe-explorer/i18n/sample/src/job/actions.i18n.json b/packages/zowe-explorer/i18n/sample/src/job/actions.i18n.json index d8c3c6dc48..95dec6d4a4 100644 --- a/packages/zowe-explorer/i18n/sample/src/job/actions.i18n.json +++ b/packages/zowe-explorer/i18n/sample/src/job/actions.i18n.json @@ -22,5 +22,9 @@ "cancelJobs.notCancelled": "The job was not cancelled.", "cancelJobs.failed": "One or more jobs failed to cancel: {0}", "cancelJobs.succeeded": "Cancelled selected jobs successfully.", - "jobs.selectSortOpt": "Select a sorting option for jobs in {0}" + "jobs.selectSortOpt": "Select a sorting option for jobs in {0}", + "setSortDirection": "$(fold) Sort Direction", + "sort.asc": "Ascending", + "sort.desc": "Descending", + "sort.selectDirection": "Select a sorting direction" } diff --git a/packages/zowe-explorer/i18n/sample/src/job/utils.i18n.json b/packages/zowe-explorer/i18n/sample/src/job/utils.i18n.json index 79f5b24932..b32e729f24 100644 --- a/packages/zowe-explorer/i18n/sample/src/job/utils.i18n.json +++ b/packages/zowe-explorer/i18n/sample/src/job/utils.i18n.json @@ -1,6 +1,7 @@ { - "jobs.sortById": "Job ID", - "jobs.sortByDateSubmitted": "Date Submitted", - "jobs.sortByName": "Job Name", - "jobs.sortByReturnCode": "Return Code" + "jobs.sortById": "$(list-ordered) Job ID (default)", + "jobs.sortByDateSubmitted": "$(calendar) Date Submitted", + "jobs.sortByName": "$(case-sensitive) Job Name", + "jobs.sortByReturnCode": "$(symbol-numeric) Return Code", + "setSortDirection": "$(fold) Sort Direction" } diff --git a/packages/zowe-explorer/i18n/sample/src/shared/utils.i18n.json b/packages/zowe-explorer/i18n/sample/src/shared/utils.i18n.json index 7bdcd3a109..9ee68cb025 100644 --- a/packages/zowe-explorer/i18n/sample/src/shared/utils.i18n.json +++ b/packages/zowe-explorer/i18n/sample/src/shared/utils.i18n.json @@ -3,6 +3,8 @@ "zowe.jobs.confirmSubmission.yourJobs": "Your jobs", "zowe.jobs.confirmSubmission.otherUserJobs": "Other user jobs", "zowe.jobs.confirmSubmission.allJobs": "All jobs", + "sort.asc": "Ascending", + "sort.desc": "Descending", "uploadContent.putContents": "Uploading USS file", "saveFile.response.save.title": "Saving data set...", "saveUSSFile.response.title": "Saving file...", diff --git a/packages/zowe-explorer/package.json b/packages/zowe-explorer/package.json index b68bd36e13..7339cf21a3 100644 --- a/packages/zowe-explorer/package.json +++ b/packages/zowe-explorer/package.json @@ -267,6 +267,12 @@ "title": "%deleteProfile%", "category": "Zowe Explorer" }, + { + "command": "zowe.ds.filterBy", + "title": "%ds.filterBy%", + "category": "Zowe Explorer", + "icon": "$(list-filter)" + }, { "command": "zowe.ds.sortBy", "title": "%ds.sortBy%", @@ -992,13 +998,18 @@ }, { "when": "view == zowe.ds.explorer && viewItem =~ /^session.*/ && !listMultiSelection", - "command": "zowe.ds.sortBy", + "command": "zowe.ds.filterBy", "group": "inline@0" }, + { + "when": "view == zowe.ds.explorer && viewItem =~ /^session.*/ && !listMultiSelection", + "command": "zowe.ds.sortBy", + "group": "inline@1" + }, { "when": "view == zowe.ds.explorer && viewItem =~ /^(?!.*_fav.*)session.*/ && !listMultiSelection", "command": "zowe.ds.pattern", - "group": "inline@1" + "group": "inline@2" }, { "when": "view == zowe.ds.explorer && viewItem =~ /^(pds|ds|migr).*_fav.*/", @@ -1195,10 +1206,15 @@ "command": "zowe.ds.ssoLogout", "group": "098_zowe_dsProfileAuthentication@10" }, + { + "when": "view == zowe.ds.explorer && viewItem =~ /^(pds|session).*/ && !listMultiSelection", + "command": "zowe.ds.filterBy", + "group": "099_zowe_dsSort@0" + }, { "when": "view == zowe.ds.explorer && viewItem =~ /^(pds|session).*/ && !listMultiSelection", "command": "zowe.ds.sortBy", - "group": "099_zowe_dsSort" + "group": "099_zowe_dsSort@1" }, { "when": "view == zowe.ds.explorer && viewItem =~ /^(?!.*_fav.*)session.*/ && !listMultiSelection", @@ -2027,6 +2043,7 @@ "dependencies": { "@zowe/secrets-for-zowe-sdk": "7.18.4", "@zowe/zowe-explorer-api": "2.12.0-SNAPSHOT", + "dayjs": "^1.11.10", "fs-extra": "8.0.1", "isbinaryfile": "4.0.4", "js-yaml": "3.13.1", diff --git a/packages/zowe-explorer/package.nls.json b/packages/zowe-explorer/package.nls.json index 31e61b4c91..fe540d76c5 100644 --- a/packages/zowe-explorer/package.nls.json +++ b/packages/zowe-explorer/package.nls.json @@ -150,7 +150,9 @@ "jobs.sortBy": "Sort jobs...", "ds.allPdsSort": "all PDS members in {0}", "ds.singlePdsSort": "the PDS members in {0}", + "ds.selectFilterOpt": "Set a filter for {0}", "ds.selectSortOpt": "Select a sorting option for {0}", "jobs.selectSortOpt": "Select a sorting option for jobs in {0}", + "ds.filterBy": "Filter PDS members...", "ds.sortBy": "Sort PDS members..." } diff --git a/packages/zowe-explorer/src/dataset/DatasetTree.ts b/packages/zowe-explorer/src/dataset/DatasetTree.ts index 244508bfed..a7e17bf326 100644 --- a/packages/zowe-explorer/src/dataset/DatasetTree.ts +++ b/packages/zowe-explorer/src/dataset/DatasetTree.ts @@ -23,20 +23,23 @@ import { PersistenceSchemaEnum, NodeInteraction, IZoweTreeNode, + DatasetFilter, + DatasetSortOpts, } from "@zowe/zowe-explorer-api"; import { Profiles } from "../Profiles"; import { ZoweExplorerApiRegister } from "../ZoweExplorerApiRegister"; import { FilterDescriptor, FilterItem, errorHandling, syncSessionNode } from "../utils/ProfilesUtils"; -import { sortTreeItems, getAppName, getDocumentFilePath } from "../shared/utils"; +import { sortTreeItems, getAppName, getDocumentFilePath, SORT_OPTS_TO_ENUM } from "../shared/utils"; import { ZoweTreeProvider } from "../abstract/ZoweTreeProvider"; import { ZoweDatasetNode } from "./ZoweDatasetNode"; import { getIconById, getIconByNode, IconId, IIconItem } from "../generators/icons"; +import * as dayjs from "dayjs"; import * as fs from "fs"; import * as contextually from "../shared/context"; import { resetValidationSettings } from "../shared/actions"; import { closeOpenedTextFile } from "../utils/workspace"; import { IDataSet, IListOptions, imperative } from "@zowe/cli"; -import { DATASET_SORT_OPTS, validateDataSetName, validateMemberName } from "./utils"; +import { DATASET_FILTER_KEYS, DATASET_FILTER_OPTS, DATASET_SORT_OPTS, validateDataSetName, validateMemberName } from "./utils"; import { SettingsConfig } from "../utils/SettingsConfig"; import { ZoweLogger } from "../utils/LoggerUtils"; import { TreeViewUtils } from "../utils/TreeViewUtils"; @@ -1300,7 +1303,10 @@ export class DatasetTree extends ZoweTreeProvider implements IZoweTree (node.sortMethod === i ? `${sortOpt} $(check)` : sortOpt)), + DATASET_SORT_OPTS.map((sortOpt, i) => ({ + label: node.sort?.method === i ? `${sortOpt} $(check)` : sortOpt, + description: i === DATASET_SORT_OPTS.length - 1 ? Object.keys(SORT_OPTS_TO_ENUM)[node.sort.direction] : null, + })), { placeHolder: localize("ds.selectSortOpt", "Select a sorting option for {0}", specifier), } @@ -1309,12 +1315,26 @@ export class DatasetTree extends ZoweTreeProvider implements IZoweTree 0) { // children nodes already exist, sort and repaint to avoid extra refresh - node.children.sort(ZoweDatasetNode.sortBy(sortMethod)); + node.children.sort(ZoweDatasetNode.sortBy(node.sort)); this.nodeDataChanged(node); } else { this.refreshElement(node); } } } + + public updateFilters(node: IZoweDatasetTreeNode, newFilter: DatasetFilter | null, isSession: boolean): void { + node.filter = newFilter; + + if (isSession) { + // if a session was selected, apply this sort to ALL PDS members + if (node.children != null && node.children.length > 0) { + // children nodes already exist, sort and repaint to avoid extra refresh + for (const c of node.children) { + const asDs = c as IZoweDatasetTreeNode; + if (contextually.isPds(c) && c.children) { + if (asDs.filter != null) { + // if there was a filter set for this PDS, refresh it to get any missing nodes back + // since refreshing the PDS will filter its children, we can return early + this.refreshElement(c); + continue; + } + if (newFilter != null) { + c.children = c.children.filter(ZoweDatasetNode.filterBy(newFilter)); + this.nodeDataChanged(c); + } else { + this.refreshElement(c); + } + } + } + } else { + this.refreshElement(node); + } + } else { + // Only sort the PDS members for this PDS + if (node.filter != null) { + // if there was a filter set for this PDS, refresh it to get any missing nodes back + // since refreshing the PDS will filter its children, we can return early + this.refreshElement(node); + return; + } + if (node.children != null && node.children.length > 0 && newFilter != null) { + // children nodes already exist, sort and repaint to avoid extra refresh + node.children = node.children.filter(ZoweDatasetNode.filterBy(newFilter)); + this.nodeDataChanged(node); + } else { + this.refreshElement(node); + } + } + } + + public async filterPdsMembers(node: IZoweDatasetTreeNode): Promise { + const isSession = contextually.isSession(node); + + const specifier = isSession + ? localize("ds.allPdsSort", "all PDS members in {0}", node.label as string) + : localize("ds.singlePdsSort", "the PDS members in {0}", node.label as string); + const clearFilter = isSession + ? localize("ds.clearAllFilters", "$(clear-all) Clear all filters") + : localize("ds.clearPdsFilter", "$(clear-all) Clear filters for this PDS"); + const selection = ( + await Gui.showQuickPick( + [...DATASET_FILTER_OPTS.map((sortOpt, i) => (node.filter?.method === i ? `${sortOpt} $(check)` : sortOpt)), clearFilter], + { + placeHolder: localize("ds.selectFilterOpt", "Set a filter for {0}", specifier), + } + ) + )?.replace(" $(check)", ""); + if (selection === clearFilter) { + this.updateFilters(node, null, isSession); + return; + } + + if (selection == null || !(selection in DATASET_FILTER_KEYS)) { + return; + } + + const filterMethod = DATASET_FILTER_KEYS[selection]; + const filter = await Gui.showInputBox({ + title: localize("ds.filterEntry.title", "Enter a value to filter by"), + placeHolder: "", + validateInput(value) { + return dayjs(value).isValid() ? null : localize("ds.filterEntry.invalidDate", "Invalid date format specified"); + }, + }); + if (filter == null) { + return; + } + + const newFilter = { + method: filterMethod, + value: filter, + }; + + this.updateFilters(node, newFilter, isSession); + } } diff --git a/packages/zowe-explorer/src/dataset/ZoweDatasetNode.ts b/packages/zowe-explorer/src/dataset/ZoweDatasetNode.ts index f66e6a864f..1cfd7b2f8e 100644 --- a/packages/zowe-explorer/src/dataset/ZoweDatasetNode.ts +++ b/packages/zowe-explorer/src/dataset/ZoweDatasetNode.ts @@ -13,13 +13,25 @@ import * as zowe from "@zowe/cli"; import * as vscode from "vscode"; import * as globals from "../globals"; import { errorHandling } from "../utils/ProfilesUtils"; -import { DatasetSortOpts, DatasetStats, Gui, NodeAction, IZoweDatasetTreeNode, ZoweTreeNode } from "@zowe/zowe-explorer-api"; +import { + DatasetFilter, + DatasetFilterOpts, + DatasetSortOpts, + DatasetStats, + Gui, + NodeAction, + IZoweDatasetTreeNode, + ZoweTreeNode, + SortDirection, + NodeSort, +} from "@zowe/zowe-explorer-api"; import { ZoweExplorerApiRegister } from "../ZoweExplorerApiRegister"; import { getIconByNode } from "../generators/icons"; import * as contextually from "../shared/context"; import * as nls from "vscode-nls"; import { Profiles } from "../Profiles"; import { ZoweLogger } from "../utils/LoggerUtils"; +import * as dayjs from "dayjs"; // Set up localization nls.config({ @@ -45,7 +57,11 @@ export class ZoweDatasetNode extends ZoweTreeNode implements IZoweDatasetTreeNod public ongoingActions: Record> = {}; public wasDoubleClicked: boolean = false; public stats: DatasetStats; - public sortMethod = DatasetSortOpts.Name; + public sort: NodeSort = { + method: DatasetSortOpts.Name, + direction: SortDirection.Ascending, + }; + public filter: DatasetFilter; /** * Creates an instance of ZoweDatasetNode @@ -268,16 +284,21 @@ export class ZoweDatasetNode extends ZoweTreeNode implements IZoweDatasetTreeNod .filter((label) => this.children.find((c) => (c.label as string) === label) == null) .map((label) => elementChildren[label]); - // get sort method for session - const sessionSortMethod = contextually.isSession(this) ? this.sortMethod : this.getSessionNode().sortMethod; + // get sort settings for session + const sessionSort = contextually.isSession(this) ? this.sort : this.getSessionNode().sort; - // use the PDS sort method if one is defined; otherwise, use session sort method - const sortMethod = (this.sortMethod ?? sessionSortMethod) as DatasetSortOpts; + // use the PDS sort settings if defined; otherwise, use session sort method + const sortOpts = this.sort ?? sessionSort; + + // use the PDS filter if one is set, otherwise try using the session filter + const sessionFilter = contextually.isSession(this) ? this.filter : this.getSessionNode().filter; + const filter = this.filter ?? sessionFilter; this.children = this.children .concat(newChildren) .filter((c) => (c.label as string) in elementChildren) - .sort(ZoweDatasetNode.sortBy(sortMethod ?? DatasetSortOpts.Name)); + .filter(filter ? ZoweDatasetNode.filterBy(filter) : (_c): boolean => true) + .sort(ZoweDatasetNode.sortBy(sortOpts)); } return this.children; @@ -289,21 +310,54 @@ export class ZoweDatasetNode extends ZoweTreeNode implements IZoweDatasetTreeNod * @param method The sorting method to use * @returns A function that sorts 2 nodes based on the given sorting method */ - public static sortBy(method: DatasetSortOpts): (a: IZoweDatasetTreeNode, b: IZoweDatasetTreeNode) => number { + public static sortBy(sort: NodeSort): (a: IZoweDatasetTreeNode, b: IZoweDatasetTreeNode) => number { return (a, b): number => { + const sortLessThan = sort.direction == SortDirection.Ascending ? -1 : 1; + const sortGreaterThan = sortLessThan * -1; + const aParent = a.getParent(); if (aParent == null || !contextually.isPds(aParent)) { - return (a.label as string) < (b.label as string) ? -1 : 1; + return (a.label as string) < (b.label as string) ? sortLessThan : sortGreaterThan; } - switch (method) { + switch (sort.method) { case DatasetSortOpts.Name: default: - return (a.label as string) < (b.label as string) ? -1 : 1; + return (a.label as string) < (b.label as string) ? sortLessThan : sortGreaterThan; case DatasetSortOpts.LastModified: - return a.stats?.m4date < b.stats?.m4date ? -1 : 1; + return a.stats?.m4date < b.stats?.m4date ? sortLessThan : sortGreaterThan; case DatasetSortOpts.UserId: - return a.stats?.user < b.stats?.user ? -1 : 1; + return a.stats?.user < b.stats?.user ? sortLessThan : sortGreaterThan; + } + }; + } + + /** + * Returns a filter function based on the given method. + * If the nodes are not PDS members, it will not filter those nodes. + * @param method The sorting method to use + * @returns A function that sorts 2 nodes based on the given sorting method + */ + public static filterBy(filter: DatasetFilter): (node: IZoweDatasetTreeNode) => boolean { + const isDateFilter = (f: string): boolean => { + return dayjs(f).isValid(); + }; + + return (node): boolean => { + const aParent = node.getParent(); + if (aParent == null || !contextually.isPds(aParent)) { + return true; + } + + switch (filter.method) { + case DatasetFilterOpts.LastModified: + if (!isDateFilter(filter.value)) { + return true; + } + + return dayjs(node.stats?.m4date).isSame(filter.value, "day"); + case DatasetFilterOpts.UserId: + return node.stats?.user === filter.value; } }; } diff --git a/packages/zowe-explorer/src/dataset/init.ts b/packages/zowe-explorer/src/dataset/init.ts index dfb156ac98..441b370455 100644 --- a/packages/zowe-explorer/src/dataset/init.ts +++ b/packages/zowe-explorer/src/dataset/init.ts @@ -201,6 +201,12 @@ export async function initDatasetProvider(context: vscode.ExtensionContext): Pro context.subscriptions.push( vscode.commands.registerCommand("zowe.ds.sortBy", async (node: IZoweDatasetTreeNode) => datasetProvider.sortPdsMembers(node)) ); + context.subscriptions.push( + vscode.commands.registerCommand( + "zowe.ds.filterBy", + async (node: IZoweDatasetTreeNode): Promise => datasetProvider.filterPdsMembers(node) + ) + ); context.subscriptions.push( vscode.workspace.onDidChangeConfiguration(async (e) => { await datasetProvider.onDidChangeConfiguration(e); diff --git a/packages/zowe-explorer/src/dataset/utils.ts b/packages/zowe-explorer/src/dataset/utils.ts index c7445dce71..40d861c577 100644 --- a/packages/zowe-explorer/src/dataset/utils.ts +++ b/packages/zowe-explorer/src/dataset/utils.ts @@ -11,7 +11,7 @@ import * as globals from "../globals"; import * as nls from "vscode-nls"; -import { IZoweNodeType } from "@zowe/zowe-explorer-api"; +import { DatasetFilterOpts, IZoweNodeType } from "@zowe/zowe-explorer-api"; import { ZoweLogger } from "../utils/LoggerUtils"; // Set up localization @@ -22,11 +22,19 @@ nls.config({ const localize: nls.LocalizeFunc = nls.loadMessageBundle(); export const DATASET_SORT_OPTS = [ - localize("ds.sortByName", "Name"), - localize("ds.sortByModified", "Date Modified"), - localize("ds.sortByUserId", "User ID"), + localize("ds.sortByName", "$(case-sensitive) Name (default)"), + localize("ds.sortByModified", "$(calendar) Date Modified"), + localize("ds.sortByUserId", "$(account) User ID"), + localize("setSortDirection", "$(fold) Sort Direction"), ]; +export const DATASET_FILTER_OPTS = [localize("ds.sortByModified", "$(calendar) Date Modified"), localize("ds.sortByUserId", "$(account) User ID")]; + +export const DATASET_FILTER_KEYS: Record = { + [localize("ds.sortByModified", "$(calendar) Date Modified")]: DatasetFilterOpts.LastModified, + [localize("ds.sortByUserId", "$(account) User ID")]: DatasetFilterOpts.UserId, +}; + export function getProfileAndDataSetName(node: IZoweNodeType): { profileName: string; dataSetName: string; diff --git a/packages/zowe-explorer/src/globals.ts b/packages/zowe-explorer/src/globals.ts index b4dda79aef..6686c4c069 100644 --- a/packages/zowe-explorer/src/globals.ts +++ b/packages/zowe-explorer/src/globals.ts @@ -35,7 +35,7 @@ export let DS_DIR: string; export let CONFIG_PATH; // set during activate export let ISTHEIA = false; // set during activate export let LOG: imperative.Logger; -export const COMMAND_COUNT = 112; +export const COMMAND_COUNT = 113; export const MAX_SEARCH_HISTORY = 5; export const MAX_FILE_HISTORY = 10; export const MS_PER_SEC = 1000; @@ -279,6 +279,7 @@ export enum JobPickerTypes { export const SEPARATORS = { BLANK: { kind: vscode.QuickPickItemKind.Separator, label: "" }, RECENT_FILTERS: { kind: vscode.QuickPickItemKind.Separator, label: localize("zowe.separator.recentFilters", "Recent Filters") }, + OPTIONS: { kind: vscode.QuickPickItemKind.Separator, label: localize("zowe.separator.options", "Options") }, }; /** diff --git a/packages/zowe-explorer/src/job/ZosJobsProvider.ts b/packages/zowe-explorer/src/job/ZosJobsProvider.ts index 2747b322ff..c1c3dd0f2d 100644 --- a/packages/zowe-explorer/src/job/ZosJobsProvider.ts +++ b/packages/zowe-explorer/src/job/ZosJobsProvider.ts @@ -1124,10 +1124,8 @@ export class ZosJobsProvider extends ZoweTreeProvider implements IZoweTree this.children.find((ch) => ch.label === c.label) == null); - const sortMethod = contextually.isSession(this) ? this.sortMethod : JobSortOpts.Id; + const sortMethod = contextually.isSession(this) ? this.sort : { method: JobSortOpts.Id, direction: SortDirection.Ascending }; // Remove any children that are no longer present in the built record this.children = this.children .concat(newChildren) @@ -238,13 +244,16 @@ export class Job extends ZoweTreeNode implements IZoweJobTreeNode { return this.children; } - public static sortJobs(method: JobSortOpts): (x: IZoweJobTreeNode, y: IZoweJobTreeNode) => number { + public static sortJobs(sortOpts: NodeSort): (x: IZoweJobTreeNode, y: IZoweJobTreeNode) => number { return (x, y) => { - const keyToSortBy = JOB_SORT_KEYS[method]; + const sortLessThan = sortOpts.direction == SortDirection.Ascending ? -1 : 1; + const sortGreaterThan = sortLessThan * -1; + + const keyToSortBy = JOB_SORT_KEYS[sortOpts.method]; if (keyToSortBy !== "jobid" && x["job"][keyToSortBy] == y["job"][keyToSortBy]) { - return x["job"]["jobid"] > y["job"]["jobid"] ? 1 : -1; + return x["job"]["jobid"] > y["job"]["jobid"] ? sortGreaterThan : sortLessThan; } else { - return x["job"][keyToSortBy] > y["job"][keyToSortBy] ? 1 : -1; + return x["job"][keyToSortBy] > y["job"][keyToSortBy] ? sortGreaterThan : sortLessThan; } }; } diff --git a/packages/zowe-explorer/src/job/actions.ts b/packages/zowe-explorer/src/job/actions.ts index 218c50f9f5..121238a909 100644 --- a/packages/zowe-explorer/src/job/actions.ts +++ b/packages/zowe-explorer/src/job/actions.ts @@ -14,12 +14,12 @@ import * as zowe from "@zowe/cli"; import { errorHandling } from "../utils/ProfilesUtils"; import { Profiles } from "../Profiles"; import { ZoweExplorerApiRegister } from "../ZoweExplorerApiRegister"; -import { Gui, IZoweTree, IZoweJobTreeNode } from "@zowe/zowe-explorer-api"; +import { Gui, IZoweTree, IZoweJobTreeNode, JobSortOpts } from "@zowe/zowe-explorer-api"; import { Job, Spool } from "./ZoweJobNode"; import * as nls from "vscode-nls"; import SpoolProvider, { encodeJobFile, getSpoolFiles, matchSpool } from "../SpoolProvider"; import { ZoweLogger } from "../utils/LoggerUtils"; -import { getDefaultUri } from "../shared/utils"; +import { SORT_OPTS_TO_ENUM, getDefaultUri } from "../shared/utils"; import { ZosJobsProvider } from "./ZosJobsProvider"; import { JOB_SORT_OPTS } from "./utils"; @@ -532,7 +532,10 @@ export async function cancelJobs(jobsProvider: IZoweTree, node } export async function sortJobs(session: IZoweJobTreeNode, jobsProvider: ZosJobsProvider): Promise { const selection = await Gui.showQuickPick( - JOB_SORT_OPTS.map((sortOpt, i) => (i === session.sortMethod ? `${sortOpt} $(check)` : sortOpt)), + JOB_SORT_OPTS.map((sortOpt, i) => ({ + label: i === session.sort.method ? `${sortOpt} $(check)` : sortOpt, + description: i === JOB_SORT_OPTS.length - 1 ? Object.keys(SORT_OPTS_TO_ENUM)[session.sort.direction] : null, + })), { placeHolder: localize("jobs.selectSortOpt", "Select a sorting option for jobs in {0}", session.label as string), } @@ -540,12 +543,25 @@ export async function sortJobs(session: IZoweJobTreeNode, jobsProvider: ZosJobsP if (selection == null) { return; } + if (selection.label === localize("setSortDirection", "$(fold) Sort Direction")) { + const dir = await Gui.showQuickPick([localize("sort.asc", "Ascending"), localize("sort.desc", "Descending")], { + placeHolder: localize("sort.selectDirection", "Select a sorting direction"), + }); + if (dir != null) { + session.sort = { + ...(session.sort ?? { method: JobSortOpts.Id }), + direction: SORT_OPTS_TO_ENUM[dir], + }; + } + await sortJobs(session, jobsProvider); + return; + } - const optIndex = JOB_SORT_OPTS.indexOf(selection); + const optIndex = JOB_SORT_OPTS.indexOf(selection.label.replace(" $(check)", "")); if (optIndex == -1) { return; } - session.sortMethod = optIndex; + session.sort.method = optIndex; jobsProvider.sortBy(session); } diff --git a/packages/zowe-explorer/src/job/utils.ts b/packages/zowe-explorer/src/job/utils.ts index 9e9db05d3c..9747139144 100644 --- a/packages/zowe-explorer/src/job/utils.ts +++ b/packages/zowe-explorer/src/job/utils.ts @@ -23,10 +23,11 @@ nls.config({ const localize: nls.LocalizeFunc = nls.loadMessageBundle(); export const JOB_SORT_OPTS = [ - localize("jobs.sortById", "Job ID"), - localize("jobs.sortByDateSubmitted", "Date Submitted"), - localize("jobs.sortByName", "Job Name"), - localize("jobs.sortByReturnCode", "Return Code"), + localize("jobs.sortById", "$(list-ordered) Job ID (default)"), + localize("jobs.sortByDateSubmitted", "$(calendar) Date Submitted"), + localize("jobs.sortByName", "$(case-sensitive) Job Name"), + localize("jobs.sortByReturnCode", "$(symbol-numeric) Return Code"), + localize("setSortDirection", "$(fold) Sort Direction"), ]; export const JOB_SORT_KEYS: Record = { diff --git a/packages/zowe-explorer/src/shared/utils.ts b/packages/zowe-explorer/src/shared/utils.ts index 98b6a293ad..aa4d5a4e56 100644 --- a/packages/zowe-explorer/src/shared/utils.ts +++ b/packages/zowe-explorer/src/shared/utils.ts @@ -15,7 +15,7 @@ import * as vscode from "vscode"; import * as path from "path"; import * as globals from "../globals"; import * as os from "os"; -import { Gui, IZoweTreeNode, IZoweNodeType, IZoweDatasetTreeNode, IZoweUSSTreeNode, IZoweJobTreeNode } from "@zowe/zowe-explorer-api"; +import { Gui, IZoweTreeNode, IZoweNodeType, IZoweDatasetTreeNode, IZoweUSSTreeNode, IZoweJobTreeNode, SortDirection } from "@zowe/zowe-explorer-api"; import { ZoweExplorerApiRegister } from "../ZoweExplorerApiRegister"; import * as nls from "vscode-nls"; import { IZosFilesResponse, imperative } from "@zowe/cli"; @@ -44,6 +44,11 @@ export const JOB_SUBMIT_DIALOG_OPTS = [ localize("zowe.jobs.confirmSubmission.allJobs", "All jobs"), ]; +export const SORT_OPTS_TO_ENUM: Record = { + [localize("sort.asc", "Ascending")]: SortDirection.Ascending, + [localize("sort.desc", "Descending")]: SortDirection.Descending, +}; + export function filterTreeByString(value: string, treeItems: vscode.QuickPickItem[]): vscode.QuickPickItem[] { ZoweLogger.trace("shared.utils.filterTreeByString called."); const filteredArray: vscode.QuickPickItem[] = []; diff --git a/yarn.lock b/yarn.lock index 98322a7d33..566be7b985 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4573,6 +4573,11 @@ dateformat@3.0.2: resolved "https://registry.npmjs.org/dateformat/-/dateformat-3.0.2.tgz#9a4df4bff158ac2f34bc637abdb15471607e1659" integrity sha1-mk30v/FYrC80vGN6vbFUcWB+Flk= +dayjs@^1.11.10: + version "1.11.10" + resolved "https://registry.npmjs.org/dayjs/-/dayjs-1.11.10.tgz#68acea85317a6e164457d6d6947564029a6a16a0" + integrity sha512-vjAczensTgRcqDERK0SR2XMwsF/tSvnvlv6VcF2GIhg6Sx4yOIt/irsr1RDJsKiIyBzJDpCoXiWWq28MqH2cnQ== + debug-fabulous@1.X: version "1.1.0" resolved "https://registry.npmjs.org/debug-fabulous/-/debug-fabulous-1.1.0.tgz#af8a08632465224ef4174a9f06308c3c2a1ebc8e" From 55df8a27e06c0ec0915dca33ed6ce074787f8dc1 Mon Sep 17 00:00:00 2001 From: Rudy Flores <68666202+rudyflores@users.noreply.github.com> Date: Mon, 9 Oct 2023 14:27:37 -0400 Subject: [PATCH 093/189] add option to add/remove different persistence items Signed-off-by: Rudy Flores <68666202+rudyflores@users.noreply.github.com> --- .../sample/src/shared/HistoryView.i18n.json | 3 +- .../zowe-explorer/src/shared/HistoryView.ts | 25 ++- packages/zowe-explorer/src/uss/USSTree.ts | 4 +- .../src/webviews/src/edit-history/App.tsx | 146 ++++++++++-------- 4 files changed, 110 insertions(+), 68 deletions(-) diff --git a/packages/zowe-explorer/i18n/sample/src/shared/HistoryView.i18n.json b/packages/zowe-explorer/i18n/sample/src/shared/HistoryView.i18n.json index 9d8e611fde..e340965fb3 100644 --- a/packages/zowe-explorer/i18n/sample/src/shared/HistoryView.i18n.json +++ b/packages/zowe-explorer/i18n/sample/src/shared/HistoryView.i18n.json @@ -1,3 +1,4 @@ { - "HistoryView.addItem.prompt": "Type the new pattern to add to history" + "HistoryView.addItem.prompt": "Type the new pattern to add to history", + "HistoryView.removeItem.notSupported": "action is not supported for this property type." } diff --git a/packages/zowe-explorer/src/shared/HistoryView.ts b/packages/zowe-explorer/src/shared/HistoryView.ts index bef4a5f6e1..726ce10edd 100644 --- a/packages/zowe-explorer/src/shared/HistoryView.ts +++ b/packages/zowe-explorer/src/shared/HistoryView.ts @@ -8,6 +8,7 @@ * Copyright Contributors to the Zowe Project. * */ + import * as vscode from "vscode"; import * as nls from "vscode-nls"; import { WebView, Gui, DataSetAllocTemplate } from "@zowe/zowe-explorer-api"; @@ -39,6 +40,7 @@ const tabs = { export class HistoryView extends WebView { private treeProviders: IZoweProviders; private currentTab: string; + private currentSelection; public constructor(context: ExtensionContext, treeProviders: IZoweProviders) { const label = "Edit History"; @@ -57,8 +59,12 @@ export class HistoryView extends WebView { uss: this.getHistoryData("uss"), jobs: this.getHistoryData("job"), tab: this.currentTab, + selection: this.currentSelection, }); break; + case "update-selection": + this.updateSelection(message); + break; case "add-item": await this.addItem(message); break; @@ -88,6 +94,11 @@ export class HistoryView extends WebView { }; } + private updateSelection(message): void { + ZoweLogger.trace("HistoryView.updateSelection called."); + this.currentSelection = message.attrs.selection; + } + private async addItem(message): Promise { ZoweLogger.trace("HistoryView.addItem called."); const options: vscode.InputBoxOptions = { @@ -103,7 +114,19 @@ export class HistoryView extends WebView { private async removeItem(message): Promise { ZoweLogger.trace("HistoryView.removeItem called."); const treeProvider = this.getTreeProvider(message.attrs.type); - treeProvider.removeSearchHistory(message.attrs.name); + switch (message.attrs.selection) { + case "search": + treeProvider.removeSearchHistory(message.attrs.name); + break; + case "fileHistory": + if (!(treeProvider instanceof ZosJobsProvider)) { + treeProvider.removeFileHistory(message.attrs.name); + } + break; + default: + Gui.showMessage(localize("HistoryView.removeItem.notSupported", "action is not supported for this property type.")); + break; + } await this.refreshView(message); } diff --git a/packages/zowe-explorer/src/uss/USSTree.ts b/packages/zowe-explorer/src/uss/USSTree.ts index 45b143e7ed..ac0b94608c 100644 --- a/packages/zowe-explorer/src/uss/USSTree.ts +++ b/packages/zowe-explorer/src/uss/USSTree.ts @@ -861,12 +861,12 @@ export class USSTree extends ZoweTreeProvider implements IZoweTree({}); + const [data, setData] = useState<{ [type: string]: { [property: string]: string[] } }>({ ds: {}, uss: {}, jobs: {} }); useEffect(() => { window.addEventListener("message", (event) => { + setData(event.data); if ("tab" in event.data) { - setCurrentTab(event.data.tab); + setCurrentTab(() => ({ + tab: event.data.tab, + })); } }); vscodeApi.postMessage({ command: "ready" }); @@ -48,7 +51,7 @@ function Body(): JSXInternal.Element { return (

Manage Persistent Properties

- +

Data Sets

@@ -58,18 +61,18 @@ function Body(): JSXInternal.Element {

Jobs

- - - + + +
); } -function UtilitiesBar({ type }: { type: string }): JSXInternal.Element { +function UtilitiesBar({ type, handleChange }: { type: string; handleChange: Function }): JSXInternal.Element { return (
- + @@ -77,15 +80,15 @@ function UtilitiesBar({ type }: { type: string }): JSXInternal.Element { ); } -function DropdownPersistentOptions(): JSXInternal.Element { +function DropdownPersistentOptions({ handleChange }: { handleChange: Function }): JSXInternal.Element { return (
- - DS Templates - Favorites - File History - Search History - Sessions + handleChange(event.target.value)}> + Search History + DS Templates + Favorites + File History + Sessions
); @@ -155,77 +158,92 @@ function DataGridHeaders(): JSXInternal.Element { ); } -function TableData({ type }: { type: string }): JSXInternal.Element { - const [persistentProperty, setPersistentProperty] = useState([]); - - useEffect(() => { - window.addEventListener("message", (event) => { - if (type in event.data) { - setPersistentProperty(event.data[type]["search"]); - } - }); - }, []); - +function TableData({ + type, + persistentProp, + selection, +}: { + type: string; + persistentProp: string[]; + selection: { selection: string }; +}): JSXInternal.Element { const handleClick = (item: number) => { vscodeApi.postMessage({ command: "remove-item", attrs: { - name: persistentProperty[item], + name: persistentProp[item], type, + selection: selection.selection, }, }); }; - const data = persistentProperty.map((item, i) => { - return ( + const data = + persistentProp && persistentProp.length ? ( + persistentProp.map((item, i) => { + return ( + + {item} + handleClick(i)} style={{ maxWidth: "5vw", textAlign: "center" }}> + + + + ); + }) + ) : ( - {item} - handleClick(i)} style={{ maxWidth: "5vw", textAlign: "center" }}> - - + No records found + ); - }); return <>{data}; } -function DsPanel(): JSXInternal.Element { - const type = "ds"; - return ( - - - - - - - - ); -} +function PersistentDataPanel({ data, type }: { data: { [type: string]: { [property: string]: string[] } }; type: string }): JSXInternal.Element { + const panelId: { [key: string]: string } = { + ds: "ds-panel-view", + uss: "uss-panel-view", + jobs: "jobs-panel-view", + }; -function USSPanel(): JSXInternal.Element { - const type = "uss"; + const [selection, setSelection] = useState<{ selection: string }>({ selection: "search" }); + const [persistentProp, setPersistentProp] = useState([]); - return ( - - - - - - - - ); -} + const handleChange = (newSelection: string) => { + setSelection(() => ({ selection: newSelection })); + vscodeApi.postMessage({ + command: "update-selection", + attrs: { + selection: newSelection, + }, + }); + }; -function JobsPanel(): JSXInternal.Element { - const type = "jobs"; + useEffect(() => { + window.addEventListener("message", (event) => { + if ("selection" in event.data) { + setSelection(() => ({ + selection: event.data.selection, + })); + } + }); + }, []); + + useEffect(() => { + setPersistentProp(() => data[type][selection.selection]); + }, [data]); + + useEffect(() => { + setPersistentProp(() => data[type][selection.selection]); + }, [selection]); return ( - - + + - + ); From b17e6e4bb87429652e59631cd0ca7858d2ff59fe Mon Sep 17 00:00:00 2001 From: Trae Yelovich Date: Mon, 9 Oct 2023 14:32:22 -0400 Subject: [PATCH 094/189] fix: some SonarCloud code smells Signed-off-by: Trae Yelovich --- .../__tests__/__unit__/job/ZoweJobNode.unit.test.ts | 5 ++--- packages/zowe-explorer/src/dataset/DatasetTree.ts | 13 +++++-------- .../zowe-explorer/src/dataset/ZoweDatasetNode.ts | 6 +++--- packages/zowe-explorer/src/job/ZosJobsProvider.ts | 5 ++--- packages/zowe-explorer/src/job/init.ts | 2 +- 5 files changed, 13 insertions(+), 18 deletions(-) diff --git a/packages/zowe-explorer/__tests__/__unit__/job/ZoweJobNode.unit.test.ts b/packages/zowe-explorer/__tests__/__unit__/job/ZoweJobNode.unit.test.ts index ec06c21ef7..ac20a2055c 100644 --- a/packages/zowe-explorer/__tests__/__unit__/job/ZoweJobNode.unit.test.ts +++ b/packages/zowe-explorer/__tests__/__unit__/job/ZoweJobNode.unit.test.ts @@ -583,9 +583,8 @@ describe("ZoweJobNode unit tests - Function saveSearch", () => { const expectedJob = favJob; expectedJob.contextValue = globals.JOBS_SESSION_CONTEXT + globals.FAV_SUFFIX; - const savedFavJob = await globalMocks.testJobsProvider.saveSearch(favJob); - - expect(savedFavJob).toEqual(expectedJob); + globalMocks.testJobsProvider.saveSearch(favJob); + expect(expectedJob.contextValue).toEqual(favJob.contextValue); }); }); diff --git a/packages/zowe-explorer/src/dataset/DatasetTree.ts b/packages/zowe-explorer/src/dataset/DatasetTree.ts index a7e17bf326..0e002eba92 100644 --- a/packages/zowe-explorer/src/dataset/DatasetTree.ts +++ b/packages/zowe-explorer/src/dataset/DatasetTree.ts @@ -1350,15 +1350,12 @@ export class DatasetTree extends ZoweTreeProvider implements IZoweTree 0) { + // children nodes already exist, sort and repaint to avoid extra refresh + node.children.sort(ZoweDatasetNode.sortBy(node.sort)); + this.nodeDataChanged(node); } else { - // Only sort the PDS members for this PDS - if (node.children != null && node.children.length > 0) { - // children nodes already exist, sort and repaint to avoid extra refresh - node.children.sort(ZoweDatasetNode.sortBy(node.sort)); - this.nodeDataChanged(node); - } else { - this.refreshElement(node); - } + this.refreshElement(node); } } diff --git a/packages/zowe-explorer/src/dataset/ZoweDatasetNode.ts b/packages/zowe-explorer/src/dataset/ZoweDatasetNode.ts index 1cfd7b2f8e..364cc2b983 100644 --- a/packages/zowe-explorer/src/dataset/ZoweDatasetNode.ts +++ b/packages/zowe-explorer/src/dataset/ZoweDatasetNode.ts @@ -321,13 +321,13 @@ export class ZoweDatasetNode extends ZoweTreeNode implements IZoweDatasetTreeNod } switch (sort.method) { - case DatasetSortOpts.Name: - default: - return (a.label as string) < (b.label as string) ? sortLessThan : sortGreaterThan; case DatasetSortOpts.LastModified: return a.stats?.m4date < b.stats?.m4date ? sortLessThan : sortGreaterThan; case DatasetSortOpts.UserId: return a.stats?.user < b.stats?.user ? sortLessThan : sortGreaterThan; + case DatasetSortOpts.Name: + default: + return (a.label as string) < (b.label as string) ? sortLessThan : sortGreaterThan; } }; } diff --git a/packages/zowe-explorer/src/job/ZosJobsProvider.ts b/packages/zowe-explorer/src/job/ZosJobsProvider.ts index c1c3dd0f2d..f87700e297 100644 --- a/packages/zowe-explorer/src/job/ZosJobsProvider.ts +++ b/packages/zowe-explorer/src/job/ZosJobsProvider.ts @@ -12,7 +12,7 @@ import * as vscode from "vscode"; import * as globals from "../globals"; import { IJob, imperative } from "@zowe/cli"; -import { Gui, ValidProfileEnum, IZoweTree, IZoweJobTreeNode, PersistenceSchemaEnum, NodeInteraction, JobSortOpts } from "@zowe/zowe-explorer-api"; +import { Gui, ValidProfileEnum, IZoweTree, IZoweJobTreeNode, PersistenceSchemaEnum, NodeInteraction } from "@zowe/zowe-explorer-api"; import { FilterItem, errorHandling } from "../utils/ProfilesUtils"; import { Profiles } from "../Profiles"; import { ZoweExplorerApiRegister } from "../ZoweExplorerApiRegister"; @@ -159,10 +159,9 @@ export class ZosJobsProvider extends ZoweTreeProvider implements IZoweTree void jobsProvider.saveSearch(node))); + context.subscriptions.push(vscode.commands.registerCommand("zowe.jobs.saveSearch", (node): void => jobsProvider.saveSearch(node))); context.subscriptions.push( vscode.commands.registerCommand("zowe.jobs.removeSearchFavorite", async (node): Promise => jobsProvider.removeFavorite(node)) ); From addf454fd754f5d71a54f17778a938fb86ed1cfb Mon Sep 17 00:00:00 2001 From: Rudy Flores <68666202+rudyflores@users.noreply.github.com> Date: Mon, 9 Oct 2023 15:50:03 -0400 Subject: [PATCH 095/189] organize file structure of webview Signed-off-by: Rudy Flores <68666202+rudyflores@users.noreply.github.com> --- .../src/webviews/src/edit-history/App.tsx | 227 ++---------------- .../PersistentAddNewHistoryItemButton.tsx | 20 ++ .../components/PersistentClearAllButton.tsx | 20 ++ .../components/PersistentDataGridHeaders.tsx | 15 ++ .../components/PersistentDataPanel.tsx | 72 ++++++ .../components/PersistentDropdownOptions.tsx | 20 ++ .../components/PersistentRefreshButton.tsx | 20 ++ .../components/PersistentTableData.tsx | 45 ++++ .../components/PersistentUtilitiesBar.tsx | 16 ++ .../components/PersistentVSCodeAPI.ts | 9 + 10 files changed, 251 insertions(+), 213 deletions(-) create mode 100644 packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentAddNewHistoryItemButton.tsx create mode 100644 packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentClearAllButton.tsx create mode 100644 packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentDataGridHeaders.tsx create mode 100644 packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentDataPanel.tsx create mode 100644 packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentDropdownOptions.tsx create mode 100644 packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentRefreshButton.tsx create mode 100644 packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentTableData.tsx create mode 100644 packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentUtilitiesBar.tsx create mode 100644 packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentVSCodeAPI.ts diff --git a/packages/zowe-explorer/src/webviews/src/edit-history/App.tsx b/packages/zowe-explorer/src/webviews/src/edit-history/App.tsx index dff670654f..f1a773dec8 100644 --- a/packages/zowe-explorer/src/webviews/src/edit-history/App.tsx +++ b/packages/zowe-explorer/src/webviews/src/edit-history/App.tsx @@ -1,43 +1,24 @@ import { useEffect, useState } from "preact/hooks"; -import { - VSCodeProgressRing, - VSCodePanels, - VSCodePanelTab, - VSCodePanelView, - VSCodeDataGridRow, - VSCodeDataGridCell, - VSCodeDataGrid, - VSCodeDropdown, - VSCodeOption, - VSCodeButton, -} from "@vscode/webview-ui-toolkit/react"; +import { VSCodePanels, VSCodePanelTab } from "@vscode/webview-ui-toolkit/react"; import { JSXInternal } from "preact/src/jsx"; - -const vscodeApi = acquireVsCodeApi(); +import PersistentDataPanel from "./components/PersistentDataPanel"; +import PersistentVSCodeAPI from "./components/PersistentVSCodeAPI"; export function App(): JSXInternal.Element { - return ( -
- -
- ); -} - -function View(): JSXInternal.Element { - const [loading, setLoading] = useState(true); - - useEffect(() => { - setLoading(false); - }, []); - - return loading ? Loading : ; -} - -function Body(): JSXInternal.Element { const [currentTab, setCurrentTab] = useState<{ [key: string]: string }>({}); const [data, setData] = useState<{ [type: string]: { [property: string]: string[] } }>({ ds: {}, uss: {}, jobs: {} }); + useEffect(() => { window.addEventListener("message", (event) => { + const eventUrl = new URL(event.origin); + const isWebUser = + (eventUrl.protocol === document.location.protocol && eventUrl.hostname === document.location.hostname) || + eventUrl.hostname.endsWith(".github.dev"); + const isLocalVSCodeUser = eventUrl.protocol === "vscode-webview:"; + + if (!isWebUser && !isLocalVSCodeUser) { + return; + } setData(event.data); if ("tab" in event.data) { setCurrentTab(() => ({ @@ -45,7 +26,7 @@ function Body(): JSXInternal.Element { })); } }); - vscodeApi.postMessage({ command: "ready" }); + PersistentVSCodeAPI.getVSCodeAPI().postMessage({ command: "ready" }); }, []); return ( @@ -68,183 +49,3 @@ function Body(): JSXInternal.Element {
); } - -function UtilitiesBar({ type, handleChange }: { type: string; handleChange: Function }): JSXInternal.Element { - return ( -
- - - - -
- ); -} - -function DropdownPersistentOptions({ handleChange }: { handleChange: Function }): JSXInternal.Element { - return ( -
- handleChange(event.target.value)}> - Search History - DS Templates - Favorites - File History - Sessions - -
- ); -} - -function AddNewHistoryItemButton({ type }: { type: string }): JSXInternal.Element { - const handleClick = () => { - vscodeApi.postMessage({ - command: "add-item", - attrs: { - type, - }, - }); - }; - - return ( - - Add Item - - ); -} - -function RefreshButton({ type }: { type: string }): JSXInternal.Element { - const handleClick = () => { - vscodeApi.postMessage({ - command: "refresh", - attrs: { - type, - }, - }); - }; - - return ( - - Refresh - - ); -} - -function ClearAllButton({ type }: { type: string }): JSXInternal.Element { - const handleClick = () => { - vscodeApi.postMessage({ - command: "clear-all", - attrs: { - type, - }, - }); - }; - - return ( - - Clear All - - ); -} - -function DataGridHeaders(): JSXInternal.Element { - return ( - - - Item - - - Delete - - - ); -} - -function TableData({ - type, - persistentProp, - selection, -}: { - type: string; - persistentProp: string[]; - selection: { selection: string }; -}): JSXInternal.Element { - const handleClick = (item: number) => { - vscodeApi.postMessage({ - command: "remove-item", - attrs: { - name: persistentProp[item], - type, - selection: selection.selection, - }, - }); - }; - - const data = - persistentProp && persistentProp.length ? ( - persistentProp.map((item, i) => { - return ( - - {item} - handleClick(i)} style={{ maxWidth: "5vw", textAlign: "center" }}> - - - - ); - }) - ) : ( - - No records found - - - ); - - return <>{data}; -} - -function PersistentDataPanel({ data, type }: { data: { [type: string]: { [property: string]: string[] } }; type: string }): JSXInternal.Element { - const panelId: { [key: string]: string } = { - ds: "ds-panel-view", - uss: "uss-panel-view", - jobs: "jobs-panel-view", - }; - - const [selection, setSelection] = useState<{ selection: string }>({ selection: "search" }); - const [persistentProp, setPersistentProp] = useState([]); - - const handleChange = (newSelection: string) => { - setSelection(() => ({ selection: newSelection })); - vscodeApi.postMessage({ - command: "update-selection", - attrs: { - selection: newSelection, - }, - }); - }; - - useEffect(() => { - window.addEventListener("message", (event) => { - if ("selection" in event.data) { - setSelection(() => ({ - selection: event.data.selection, - })); - } - }); - }, []); - - useEffect(() => { - setPersistentProp(() => data[type][selection.selection]); - }, [data]); - - useEffect(() => { - setPersistentProp(() => data[type][selection.selection]); - }, [selection]); - - return ( - - - - - - - - ); -} diff --git a/packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentAddNewHistoryItemButton.tsx b/packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentAddNewHistoryItemButton.tsx new file mode 100644 index 0000000000..8bb3bb6d52 --- /dev/null +++ b/packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentAddNewHistoryItemButton.tsx @@ -0,0 +1,20 @@ +import { VSCodeButton } from "@vscode/webview-ui-toolkit/react"; +import { JSXInternal } from "preact/src/jsx"; +import PersistentVSCodeAPI from "./PersistentVSCodeAPI"; + +export default function PersistentAddNewHistoryItemButton({ type }: { type: string }): JSXInternal.Element { + const handleClick = () => { + PersistentVSCodeAPI.getVSCodeAPI().postMessage({ + command: "add-item", + attrs: { + type, + }, + }); + }; + + return ( + + Add Item + + ); +} diff --git a/packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentClearAllButton.tsx b/packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentClearAllButton.tsx new file mode 100644 index 0000000000..e7956a7076 --- /dev/null +++ b/packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentClearAllButton.tsx @@ -0,0 +1,20 @@ +import { VSCodeButton } from "@vscode/webview-ui-toolkit/react"; +import { JSXInternal } from "preact/src/jsx"; +import PersistentVSCodeAPI from "./PersistentVSCodeAPI"; + +export default function PersistentClearAllButton({ type }: { type: string }): JSXInternal.Element { + const handleClick = () => { + PersistentVSCodeAPI.getVSCodeAPI().postMessage({ + command: "clear-all", + attrs: { + type, + }, + }); + }; + + return ( + + Clear All + + ); +} diff --git a/packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentDataGridHeaders.tsx b/packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentDataGridHeaders.tsx new file mode 100644 index 0000000000..6dbe293fe9 --- /dev/null +++ b/packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentDataGridHeaders.tsx @@ -0,0 +1,15 @@ +import { VSCodeDataGridRow, VSCodeDataGridCell } from "@vscode/webview-ui-toolkit/react"; +import { JSXInternal } from "preact/src/jsx"; + +export default function PersistentDataGridHeaders(): JSXInternal.Element { + return ( + + + Item + + + Delete + + + ); +} diff --git a/packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentDataPanel.tsx b/packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentDataPanel.tsx new file mode 100644 index 0000000000..85edf0b74e --- /dev/null +++ b/packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentDataPanel.tsx @@ -0,0 +1,72 @@ +import { useEffect, useState } from "preact/hooks"; +import { VSCodePanelView, VSCodeDataGrid } from "@vscode/webview-ui-toolkit/react"; +import { JSXInternal } from "preact/src/jsx"; +import PersistentUtilitiesBar from "./PersistentUtilitiesBar"; +import PersistentTableData from "./PersistentTableData"; +import PersistentDataGridHeaders from "./PersistentDataGridHeaders"; +import PersistentVSCodeAPI from "./PersistentVSCodeAPI"; + +export default function PersistentDataPanel({ + data, + type, +}: { + data: { [type: string]: { [property: string]: string[] } }; + type: string; +}): JSXInternal.Element { + const panelId: { [key: string]: string } = { + ds: "ds-panel-view", + uss: "uss-panel-view", + jobs: "jobs-panel-view", + }; + + const [selection, setSelection] = useState<{ selection: string }>({ selection: "search" }); + const [persistentProp, setPersistentProp] = useState([]); + + const handleChange = (newSelection: string) => { + setSelection(() => ({ selection: newSelection })); + PersistentVSCodeAPI.getVSCodeAPI().postMessage({ + command: "update-selection", + attrs: { + selection: newSelection, + }, + }); + }; + + useEffect(() => { + window.addEventListener("message", (event) => { + const eventUrl = new URL(event.origin); + const isWebUser = + (eventUrl.protocol === document.location.protocol && eventUrl.hostname === document.location.hostname) || + eventUrl.hostname.endsWith(".github.dev"); + const isLocalVSCodeUser = eventUrl.protocol === "vscode-webview:"; + + if (!isWebUser && !isLocalVSCodeUser) { + return; + } + + if ("selection" in event.data) { + setSelection(() => ({ + selection: event.data.selection, + })); + } + }); + }, []); + + useEffect(() => { + setPersistentProp(() => data[type][selection.selection]); + }, [data]); + + useEffect(() => { + setPersistentProp(() => data[type][selection.selection]); + }, [selection]); + + return ( + + + + + + + + ); +} diff --git a/packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentDropdownOptions.tsx b/packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentDropdownOptions.tsx new file mode 100644 index 0000000000..604b883924 --- /dev/null +++ b/packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentDropdownOptions.tsx @@ -0,0 +1,20 @@ +import { VSCodeDropdown, VSCodeOption } from "@vscode/webview-ui-toolkit/react"; +import { JSXInternal } from "preact/src/jsx"; + +export default function PersistentDropdownOptions({ handleChange }: { handleChange: Function }): JSXInternal.Element { + const options = [ + Search History, + DS Templates, + Favorites, + File History, + Sessions, + ]; + + return ( +
+ handleChange(event.target.value)}> + {options} + +
+ ); +} diff --git a/packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentRefreshButton.tsx b/packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentRefreshButton.tsx new file mode 100644 index 0000000000..38acf94554 --- /dev/null +++ b/packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentRefreshButton.tsx @@ -0,0 +1,20 @@ +import { VSCodeButton } from "@vscode/webview-ui-toolkit/react"; +import { JSXInternal } from "preact/src/jsx"; +import PersistentVSCodeAPI from "./PersistentVSCodeAPI"; + +export default function PersistentRefreshButton({ type }: { type: string }): JSXInternal.Element { + const handleClick = () => { + PersistentVSCodeAPI.getVSCodeAPI().postMessage({ + command: "refresh", + attrs: { + type, + }, + }); + }; + + return ( + + Refresh + + ); +} diff --git a/packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentTableData.tsx b/packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentTableData.tsx new file mode 100644 index 0000000000..e0b822ae3a --- /dev/null +++ b/packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentTableData.tsx @@ -0,0 +1,45 @@ +import { VSCodeDataGridCell, VSCodeDataGridRow } from "@vscode/webview-ui-toolkit/react"; +import { JSXInternal } from "preact/src/jsx"; +import PersistentVSCodeAPI from "./PersistentVSCodeAPI"; + +export default function PersistentTableData({ + type, + persistentProp, + selection, +}: { + type: string; + persistentProp: string[]; + selection: { selection: string }; +}): JSXInternal.Element { + const handleClick = (item: number) => { + PersistentVSCodeAPI.getVSCodeAPI().postMessage({ + command: "remove-item", + attrs: { + name: persistentProp[item], + type, + selection: selection.selection, + }, + }); + }; + + const data = + persistentProp && persistentProp.length ? ( + persistentProp.map((item, i) => { + return ( + + {item} + handleClick(i)} style={{ maxWidth: "5vw", textAlign: "center" }}> + + + + ); + }) + ) : ( + + No records found + + + ); + + return <>{data}; +} diff --git a/packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentUtilitiesBar.tsx b/packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentUtilitiesBar.tsx new file mode 100644 index 0000000000..11cf51a40a --- /dev/null +++ b/packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentUtilitiesBar.tsx @@ -0,0 +1,16 @@ +import { JSXInternal } from "preact/src/jsx"; +import PersistentClearAllButton from "./PersistentClearAllButton"; +import PersistentRefreshButton from "./PersistentRefreshButton"; +import PersistentDropdownOptions from "./PersistentDropdownOptions"; +import PersistentAddNewHistoryItemButton from "./PersistentAddNewHistoryItemButton"; + +export default function PersistentUtilitiesBar({ type, handleChange }: { type: string; handleChange: Function }): JSXInternal.Element { + return ( +
+ + + + +
+ ); +} diff --git a/packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentVSCodeAPI.ts b/packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentVSCodeAPI.ts new file mode 100644 index 0000000000..30c6e4091a --- /dev/null +++ b/packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentVSCodeAPI.ts @@ -0,0 +1,9 @@ +import { WebviewApi } from "vscode-webview"; + +export default class PersistentVSCodeAPI { + private static vscodeAPI = acquireVsCodeApi(); + + public static getVSCodeAPI(): WebviewApi { + return this.vscodeAPI; + } +} From 4808c2f5b64dc285b50649719ab204e4aabfab66 Mon Sep 17 00:00:00 2001 From: Rudy Flores <68666202+rudyflores@users.noreply.github.com> Date: Mon, 9 Oct 2023 15:59:16 -0400 Subject: [PATCH 096/189] solve refresh issue Signed-off-by: Rudy Flores <68666202+rudyflores@users.noreply.github.com> --- packages/zowe-explorer/src/shared/HistoryView.ts | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/packages/zowe-explorer/src/shared/HistoryView.ts b/packages/zowe-explorer/src/shared/HistoryView.ts index 726ce10edd..30680397e4 100644 --- a/packages/zowe-explorer/src/shared/HistoryView.ts +++ b/packages/zowe-explorer/src/shared/HistoryView.ts @@ -140,6 +140,12 @@ export class HistoryView extends WebView { private async refreshView(message): Promise { ZoweLogger.trace("HistoryView.refreshView called."); this.currentTab = tabs[message.attrs.type]; - await vscode.commands.executeCommand("workbench.action.webview.reloadWebviewAction"); + await this.panel.webview.postMessage({ + ds: this.getHistoryData("ds"), + uss: this.getHistoryData("uss"), + jobs: this.getHistoryData("job"), + tab: this.currentTab, + selection: this.currentSelection, + }); } } From d05954188d437a051f37dd0d1efacee150568bad Mon Sep 17 00:00:00 2001 From: Rudy Flores <68666202+rudyflores@users.noreply.github.com> Date: Mon, 9 Oct 2023 16:43:28 -0400 Subject: [PATCH 097/189] clean up view Signed-off-by: Rudy Flores <68666202+rudyflores@users.noreply.github.com> --- .../sample/src/shared/HistoryView.i18n.json | 5 ++++- .../zowe-explorer/src/dataset/DatasetTree.ts | 5 +++++ .../zowe-explorer/src/shared/HistoryView.ts | 22 +++++++++++++++++-- packages/zowe-explorer/src/uss/USSTree.ts | 5 +++++ .../src/webviews/src/edit-history/App.tsx | 10 ++++++--- .../PersistentManagerHeader.tsx | 12 ++++++++++ .../PersistentDataGridHeaders.tsx | 0 .../PersistentDataPanel.tsx | 6 ++--- .../PersistentTableData.tsx | 2 +- .../PersistentAddNewHistoryItemButton.tsx | 2 +- .../PersistentClearAllButton.tsx | 5 +++-- .../PersistentDropdownOptions.tsx | 0 .../PersistentRefreshButton.tsx | 2 +- .../PersistentUtilitiesBar.tsx | 14 +++++++++--- 14 files changed, 73 insertions(+), 17 deletions(-) create mode 100644 packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentManagerHeader/PersistentManagerHeader.tsx rename packages/zowe-explorer/src/webviews/src/edit-history/components/{ => PersistentTable}/PersistentDataGridHeaders.tsx (100%) rename packages/zowe-explorer/src/webviews/src/edit-history/components/{ => PersistentTable}/PersistentDataPanel.tsx (92%) rename packages/zowe-explorer/src/webviews/src/edit-history/components/{ => PersistentTable}/PersistentTableData.tsx (95%) rename packages/zowe-explorer/src/webviews/src/edit-history/components/{ => PersistentUtils}/PersistentAddNewHistoryItemButton.tsx (90%) rename packages/zowe-explorer/src/webviews/src/edit-history/components/{ => PersistentUtils}/PersistentClearAllButton.tsx (62%) rename packages/zowe-explorer/src/webviews/src/edit-history/components/{ => PersistentUtils}/PersistentDropdownOptions.tsx (100%) rename packages/zowe-explorer/src/webviews/src/edit-history/components/{ => PersistentUtils}/PersistentRefreshButton.tsx (89%) rename packages/zowe-explorer/src/webviews/src/edit-history/components/{ => PersistentUtils}/PersistentUtilitiesBar.tsx (59%) diff --git a/packages/zowe-explorer/i18n/sample/src/shared/HistoryView.i18n.json b/packages/zowe-explorer/i18n/sample/src/shared/HistoryView.i18n.json index e340965fb3..e8a920e719 100644 --- a/packages/zowe-explorer/i18n/sample/src/shared/HistoryView.i18n.json +++ b/packages/zowe-explorer/i18n/sample/src/shared/HistoryView.i18n.json @@ -1,4 +1,7 @@ { "HistoryView.addItem.prompt": "Type the new pattern to add to history", - "HistoryView.removeItem.notSupported": "action is not supported for this property type." + "HistoryView.removeItem.notSupported": "action is not supported for this property type.", + "HistoryView.clearAll.confirmMessage": "Clear all history contents for this persistent property?", + "HistoryView.clearAll.Yes": "Yes", + "HistoryView.clearAll.No": "No" } diff --git a/packages/zowe-explorer/src/dataset/DatasetTree.ts b/packages/zowe-explorer/src/dataset/DatasetTree.ts index 92cced7001..85b603bb35 100644 --- a/packages/zowe-explorer/src/dataset/DatasetTree.ts +++ b/packages/zowe-explorer/src/dataset/DatasetTree.ts @@ -767,6 +767,11 @@ export class DatasetTree extends ZoweTreeProvider implements IZoweTree { ZoweLogger.trace("HistoryView.clearAll called."); const treeProvider = this.getTreeProvider(message.attrs.type); - treeProvider.resetSearchHistory(); - await this.refreshView(message); + const infoMessage = localize("HistoryView.clearAll.confirmMessage", "Clear all history contents for this persistent property?"); + const yesButton = localize("HistoryView.clearAll.Yes", "Yes"); + const noButton = localize("HistoryView.clearAll.No", "No"); + const choice = await Gui.showMessage(infoMessage, { items: [yesButton, noButton], vsCodeOpts: { modal: true } }); + if (choice === yesButton) { + switch (message.attrs.selection) { + case "search": + treeProvider.resetSearchHistory(); + break; + case "fileHistory": + if (!(treeProvider instanceof ZosJobsProvider)) { + treeProvider.resetFileHistory(); + } + break; + default: + Gui.showMessage(localize("HistoryView.removeItem.notSupported", "action is not supported for this property type.")); + break; + } + await this.refreshView(message); + } } private async refreshView(message): Promise { diff --git a/packages/zowe-explorer/src/uss/USSTree.ts b/packages/zowe-explorer/src/uss/USSTree.ts index ac0b94608c..354e43e7c0 100644 --- a/packages/zowe-explorer/src/uss/USSTree.ts +++ b/packages/zowe-explorer/src/uss/USSTree.ts @@ -860,6 +860,11 @@ export class USSTree extends ZoweTreeProvider implements IZoweTree(); const [currentTab, setCurrentTab] = useState<{ [key: string]: string }>({}); const [data, setData] = useState<{ [type: string]: { [property: string]: string[] } }>({ ds: {}, uss: {}, jobs: {} }); @@ -25,13 +27,15 @@ export function App(): JSXInternal.Element { tab: event.data.tab, })); } + setTimestamp(new Date()); }); PersistentVSCodeAPI.getVSCodeAPI().postMessage({ command: "ready" }); }, []); return (
-

Manage Persistent Properties

+ +

Data Sets

diff --git a/packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentManagerHeader/PersistentManagerHeader.tsx b/packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentManagerHeader/PersistentManagerHeader.tsx new file mode 100644 index 0000000000..e1b4548875 --- /dev/null +++ b/packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentManagerHeader/PersistentManagerHeader.tsx @@ -0,0 +1,12 @@ +import { JSXInternal } from "preact/src/jsx"; + +export default function PersistentManagerHeader({ timestamp }: { timestamp: Date | undefined }): JSXInternal.Element { + return ( +
+

Manage Persistent Properties

+
+ {timestamp &&

Last refreshed: {timestamp.toLocaleString(navigator.language)}

} +
+
+ ); +} diff --git a/packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentDataGridHeaders.tsx b/packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentTable/PersistentDataGridHeaders.tsx similarity index 100% rename from packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentDataGridHeaders.tsx rename to packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentTable/PersistentDataGridHeaders.tsx diff --git a/packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentDataPanel.tsx b/packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentTable/PersistentDataPanel.tsx similarity index 92% rename from packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentDataPanel.tsx rename to packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentTable/PersistentDataPanel.tsx index 85edf0b74e..e9266539b8 100644 --- a/packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentDataPanel.tsx +++ b/packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentTable/PersistentDataPanel.tsx @@ -1,10 +1,10 @@ import { useEffect, useState } from "preact/hooks"; import { VSCodePanelView, VSCodeDataGrid } from "@vscode/webview-ui-toolkit/react"; import { JSXInternal } from "preact/src/jsx"; -import PersistentUtilitiesBar from "./PersistentUtilitiesBar"; +import PersistentUtilitiesBar from "../PersistentUtils/PersistentUtilitiesBar"; import PersistentTableData from "./PersistentTableData"; import PersistentDataGridHeaders from "./PersistentDataGridHeaders"; -import PersistentVSCodeAPI from "./PersistentVSCodeAPI"; +import PersistentVSCodeAPI from "../PersistentVSCodeAPI"; export default function PersistentDataPanel({ data, @@ -62,7 +62,7 @@ export default function PersistentDataPanel({ return ( - + diff --git a/packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentTableData.tsx b/packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentTable/PersistentTableData.tsx similarity index 95% rename from packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentTableData.tsx rename to packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentTable/PersistentTableData.tsx index e0b822ae3a..7d1559f39e 100644 --- a/packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentTableData.tsx +++ b/packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentTable/PersistentTableData.tsx @@ -1,6 +1,6 @@ import { VSCodeDataGridCell, VSCodeDataGridRow } from "@vscode/webview-ui-toolkit/react"; import { JSXInternal } from "preact/src/jsx"; -import PersistentVSCodeAPI from "./PersistentVSCodeAPI"; +import PersistentVSCodeAPI from "../PersistentVSCodeAPI"; export default function PersistentTableData({ type, diff --git a/packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentAddNewHistoryItemButton.tsx b/packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentUtils/PersistentAddNewHistoryItemButton.tsx similarity index 90% rename from packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentAddNewHistoryItemButton.tsx rename to packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentUtils/PersistentAddNewHistoryItemButton.tsx index 8bb3bb6d52..99d938143c 100644 --- a/packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentAddNewHistoryItemButton.tsx +++ b/packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentUtils/PersistentAddNewHistoryItemButton.tsx @@ -1,6 +1,6 @@ import { VSCodeButton } from "@vscode/webview-ui-toolkit/react"; import { JSXInternal } from "preact/src/jsx"; -import PersistentVSCodeAPI from "./PersistentVSCodeAPI"; +import PersistentVSCodeAPI from "../PersistentVSCodeAPI"; export default function PersistentAddNewHistoryItemButton({ type }: { type: string }): JSXInternal.Element { const handleClick = () => { diff --git a/packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentClearAllButton.tsx b/packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentUtils/PersistentClearAllButton.tsx similarity index 62% rename from packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentClearAllButton.tsx rename to packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentUtils/PersistentClearAllButton.tsx index e7956a7076..61295748f8 100644 --- a/packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentClearAllButton.tsx +++ b/packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentUtils/PersistentClearAllButton.tsx @@ -1,13 +1,14 @@ import { VSCodeButton } from "@vscode/webview-ui-toolkit/react"; import { JSXInternal } from "preact/src/jsx"; -import PersistentVSCodeAPI from "./PersistentVSCodeAPI"; +import PersistentVSCodeAPI from "../PersistentVSCodeAPI"; -export default function PersistentClearAllButton({ type }: { type: string }): JSXInternal.Element { +export default function PersistentClearAllButton({ type, selection }: { type: string; selection: { selection: string } }): JSXInternal.Element { const handleClick = () => { PersistentVSCodeAPI.getVSCodeAPI().postMessage({ command: "clear-all", attrs: { type, + selection: selection.selection, }, }); }; diff --git a/packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentDropdownOptions.tsx b/packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentUtils/PersistentDropdownOptions.tsx similarity index 100% rename from packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentDropdownOptions.tsx rename to packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentUtils/PersistentDropdownOptions.tsx diff --git a/packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentRefreshButton.tsx b/packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentUtils/PersistentRefreshButton.tsx similarity index 89% rename from packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentRefreshButton.tsx rename to packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentUtils/PersistentRefreshButton.tsx index 38acf94554..52ce61721f 100644 --- a/packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentRefreshButton.tsx +++ b/packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentUtils/PersistentRefreshButton.tsx @@ -1,6 +1,6 @@ import { VSCodeButton } from "@vscode/webview-ui-toolkit/react"; import { JSXInternal } from "preact/src/jsx"; -import PersistentVSCodeAPI from "./PersistentVSCodeAPI"; +import PersistentVSCodeAPI from "../PersistentVSCodeAPI"; export default function PersistentRefreshButton({ type }: { type: string }): JSXInternal.Element { const handleClick = () => { diff --git a/packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentUtilitiesBar.tsx b/packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentUtils/PersistentUtilitiesBar.tsx similarity index 59% rename from packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentUtilitiesBar.tsx rename to packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentUtils/PersistentUtilitiesBar.tsx index 11cf51a40a..8f7f8cea48 100644 --- a/packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentUtilitiesBar.tsx +++ b/packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentUtils/PersistentUtilitiesBar.tsx @@ -4,13 +4,21 @@ import PersistentRefreshButton from "./PersistentRefreshButton"; import PersistentDropdownOptions from "./PersistentDropdownOptions"; import PersistentAddNewHistoryItemButton from "./PersistentAddNewHistoryItemButton"; -export default function PersistentUtilitiesBar({ type, handleChange }: { type: string; handleChange: Function }): JSXInternal.Element { +export default function PersistentUtilitiesBar({ + type, + handleChange, + selection, +}: { + type: string; + handleChange: Function; + selection: { selection: string }; +}): JSXInternal.Element { return (
- + {selection.selection === "search" && type !== "jobs" ? : null} - +
); } From a68761d474cd0ac311b03342e856893d2f60ab68 Mon Sep 17 00:00:00 2001 From: Trae Yelovich Date: Mon, 9 Oct 2023 17:04:09 -0400 Subject: [PATCH 098/189] tests(ds): Bump patch coverage for DatasetTree.filterPdsMembers Signed-off-by: Trae Yelovich --- .../__unit__/dataset/DatasetTree.unit.test.ts | 105 +++++++++++++++++- .../zowe-explorer/src/dataset/DatasetTree.ts | 18 +-- 2 files changed, 110 insertions(+), 13 deletions(-) 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 6063c7f6b4..42f33d7df9 100644 --- a/packages/zowe-explorer/__tests__/__unit__/dataset/DatasetTree.unit.test.ts +++ b/packages/zowe-explorer/__tests__/__unit__/dataset/DatasetTree.unit.test.ts @@ -2697,19 +2697,20 @@ describe("Dataset Tree Unit Tests - Function initializeFavorites", () => { }); }); -describe("Dataset Tree Unit Tests - Function sortBy", () => { +describe("Dataset Tree Unit Tests - Function sortPdsMembers", () => { const testTree = new DatasetTree(); - const mocks = { + const getBlockMocks = (): Record => ({ nodeDataChanged: jest.spyOn(DatasetTree.prototype, "nodeDataChanged"), refreshElement: jest.spyOn(DatasetTree.prototype, "refreshElement"), showQuickPick: jest.spyOn(Gui, "showQuickPick"), getParent: jest.spyOn(ZoweDatasetNode.prototype, "getParent"), - }; + }); const testSession = new ZoweDatasetNode("testSession", vscode.TreeItemCollapsibleState.Collapsed, null, createISession()); const testPds = new ZoweDatasetNode("testPds", vscode.TreeItemCollapsibleState.Collapsed, testSession, createISession()); testPds.contextValue = globals.DS_PDS_CONTEXT; beforeEach(() => { + const mocks = getBlockMocks(); mocks.getParent.mockReturnValue(testSession); testPds.children = [ { label: "A", stats: { user: "someUser", m4date: Date.now() }, getParent: mocks.getParent } as unknown as ZoweDatasetNode, @@ -2728,26 +2729,29 @@ describe("Dataset Tree Unit Tests - Function sortBy", () => { }); afterEach(() => { + const mocks = getBlockMocks(); for (const mock of Object.values(mocks)) { mock.mockClear(); } }); afterAll(() => { + const mocks = getBlockMocks(); for (const mock of Object.values(mocks)) { mock.mockRestore(); } }); it("calls refreshElement if no children exist", async () => { - // case 1: called on session node + const mocks = getBlockMocks(); + // case 1: called on PDS node mocks.showQuickPick.mockResolvedValueOnce({ label: "$(case-sensitive) Name (default)" }); testPds.children = []; await testTree.sortPdsMembers(testPds); expect(mocks.nodeDataChanged).not.toHaveBeenCalled(); expect(mocks.refreshElement).toHaveBeenCalledWith(testPds); - // case 2: called on PDS node + // case 2: called on session node mocks.showQuickPick.mockResolvedValueOnce({ label: "$(case-sensitive) Name (default)" }); testSession.children = []; await testTree.sortPdsMembers(testSession); @@ -2756,6 +2760,7 @@ describe("Dataset Tree Unit Tests - Function sortBy", () => { }); it("sorts by name", async () => { + const mocks = getBlockMocks(); mocks.showQuickPick.mockResolvedValueOnce({ label: "$(case-sensitive) Name (default)" }); await testTree.sortPdsMembers(testPds); expect(mocks.nodeDataChanged).toHaveBeenCalled(); @@ -2764,6 +2769,7 @@ describe("Dataset Tree Unit Tests - Function sortBy", () => { }); it("sorts by last modified date", async () => { + const mocks = getBlockMocks(); mocks.showQuickPick.mockResolvedValueOnce({ label: "$(calendar) Date Modified" }); await testTree.sortPdsMembers(testPds); expect(mocks.nodeDataChanged).toHaveBeenCalled(); @@ -2772,6 +2778,7 @@ describe("Dataset Tree Unit Tests - Function sortBy", () => { }); it("sorts by user ID", async () => { + const mocks = getBlockMocks(); mocks.showQuickPick.mockResolvedValueOnce({ label: "$(account) User ID" }); await testTree.sortPdsMembers(testPds); expect(mocks.nodeDataChanged).toHaveBeenCalled(); @@ -2779,3 +2786,91 @@ describe("Dataset Tree Unit Tests - Function sortBy", () => { expect(testPds.children.map((c: IZoweDatasetTreeNode) => c.label)).toStrictEqual(["B", "A", "C"]); }); }); + +describe("Dataset Tree Unit Tests - Function filterPdsMembers", () => { + const testTree = new DatasetTree(); + const getBlockMocks = (): Record => ({ + nodeDataChanged: jest.spyOn(DatasetTree.prototype, "nodeDataChanged"), + refreshElement: jest.spyOn(DatasetTree.prototype, "refreshElement"), + showQuickPick: jest.spyOn(Gui, "showQuickPick"), + getParent: jest.spyOn(ZoweDatasetNode.prototype, "getParent"), + showInputBox: jest.spyOn(Gui, "showInputBox"), + }); + const testSession = new ZoweDatasetNode("testSession", vscode.TreeItemCollapsibleState.Collapsed, null, createISession()); + const testPds = new ZoweDatasetNode("testPds", vscode.TreeItemCollapsibleState.Collapsed, testSession, createISession()); + testPds.contextValue = globals.DS_PDS_CONTEXT; + + beforeEach(() => { + const mocks = getBlockMocks(); + mocks.getParent.mockReturnValue(testSession); + testPds.children = [ + { label: "A", stats: { user: "someUser", m4date: Date.now() }, getParent: mocks.getParent } as unknown as ZoweDatasetNode, + { + label: "B", + stats: { user: "anotherUser", m4date: Date.parse("2022-01-01T12:00:00") }, + getParent: mocks.getParent, + } as unknown as ZoweDatasetNode, + { + label: "C", + stats: { user: "someUser", m4date: Date.parse("2022-03-15T16:30:00") }, + getParent: mocks.getParent, + } as unknown as ZoweDatasetNode, + ]; + testSession.children = [testPds]; + }); + + afterEach(() => { + const mocks = getBlockMocks(); + for (const mock of Object.values(mocks)) { + mock.mockReset(); + } + }); + + afterAll(() => { + const mocks = getBlockMocks(); + for (const mock of Object.values(mocks)) { + mock.mockRestore(); + } + }); + + it("calls refreshElement if no children exist", async () => { + const mocks = getBlockMocks(); + // case 1: called on PDS node + mocks.showQuickPick.mockResolvedValue("$(calendar) Date Modified" as any); + mocks.showInputBox.mockResolvedValueOnce("2022-01-01"); + testPds.children = []; + await testTree.filterPdsMembers(testPds); + expect(mocks.nodeDataChanged).not.toHaveBeenCalled(); + expect(mocks.refreshElement).toHaveBeenCalledWith(testPds); + testPds.filter = undefined as any; + + // case 2: called on session node + mocks.showQuickPick.mockResolvedValue("$(calendar) Date Modified" as any); + mocks.showInputBox.mockResolvedValueOnce("2022-01-01"); + testSession.children = []; + await testTree.filterPdsMembers(testSession); + expect(mocks.nodeDataChanged).not.toHaveBeenCalled(); + expect(mocks.refreshElement).toHaveBeenCalledWith(testSession); + }); + + it("filters by last modified date", async () => { + const mocks = getBlockMocks(); + mocks.showQuickPick.mockResolvedValue("$(calendar) Date Modified" as any); + mocks.showInputBox.mockResolvedValueOnce("2022-03-15"); + await testTree.filterPdsMembers(testPds); + expect(mocks.nodeDataChanged).toHaveBeenCalled(); + expect(mocks.refreshElement).not.toHaveBeenCalled(); + expect(testPds.children.map((c: IZoweDatasetTreeNode) => c.label)).toStrictEqual(["C"]); + testPds.filter = undefined as any; + }); + + it("filters by user ID", async () => { + const mocks = getBlockMocks(); + mocks.showQuickPick.mockResolvedValue("$(account) User ID" as any); + mocks.showInputBox.mockResolvedValueOnce("anotherUser"); + await testTree.filterPdsMembers(testPds); + expect(mocks.nodeDataChanged).toHaveBeenCalled(); + expect(mocks.refreshElement).not.toHaveBeenCalled(); + expect(testPds.children.map((c: IZoweDatasetTreeNode) => c.label)).toStrictEqual(["B"]); + }); +}); diff --git a/packages/zowe-explorer/src/dataset/DatasetTree.ts b/packages/zowe-explorer/src/dataset/DatasetTree.ts index 0e002eba92..a73eca237a 100644 --- a/packages/zowe-explorer/src/dataset/DatasetTree.ts +++ b/packages/zowe-explorer/src/dataset/DatasetTree.ts @@ -1360,6 +1360,7 @@ export class DatasetTree extends ZoweTreeProvider implements IZoweTree 0) { c.children = c.children.filter(ZoweDatasetNode.filterBy(newFilter)); this.nodeDataChanged(c); } else { @@ -1388,13 +1390,13 @@ export class DatasetTree extends ZoweTreeProvider implements IZoweTree 0 && newFilter != null) { + + if (newFilter != null && node.children != null && node.children.length > 0) { // children nodes already exist, sort and repaint to avoid extra refresh node.children = node.children.filter(ZoweDatasetNode.filterBy(newFilter)); this.nodeDataChanged(node); From bee64899d107e7ef38871381994fea138c0a33b1 Mon Sep 17 00:00:00 2001 From: Trae Yelovich Date: Mon, 9 Oct 2023 19:12:37 -0400 Subject: [PATCH 099/189] chore(ds/sort): code refactor, add typedoc, cleanup strings Signed-off-by: Trae Yelovich --- packages/zowe-explorer-api/src/index.ts | 1 + .../src/tree/IZoweTreeNode.ts | 44 +---- packages/zowe-explorer-api/src/tree/index.ts | 1 + .../zowe-explorer-api/src/tree/sorting.ts | 43 +++++ .../__unit__/dataset/DatasetTree.unit.test.ts | 22 +-- .../__unit__/dataset/init.unit.test.ts | 9 +- .../sample/src/dataset/DatasetTree.i18n.json | 7 +- .../zowe-explorer/src/dataset/DatasetTree.ts | 157 +++++++++++------- packages/zowe-explorer/src/dataset/init.ts | 4 +- packages/zowe-explorer/src/dataset/utils.ts | 5 - packages/zowe-explorer/src/job/actions.ts | 8 +- packages/zowe-explorer/src/shared/utils.ts | 5 +- 12 files changed, 181 insertions(+), 125 deletions(-) create mode 100644 packages/zowe-explorer-api/src/tree/sorting.ts diff --git a/packages/zowe-explorer-api/src/index.ts b/packages/zowe-explorer-api/src/index.ts index 33d3dad8c4..a9e308a3f0 100644 --- a/packages/zowe-explorer-api/src/index.ts +++ b/packages/zowe-explorer-api/src/index.ts @@ -23,6 +23,7 @@ export * from "./tree/ZoweExplorerTreeApi"; export * from "./tree/ZoweTreeNode"; export * from "./tree/IZoweTree"; export * from "./tree/IZoweTreeNode"; +export * from "./tree/sorting"; export * from "./utils"; export * from "./vscode/ZoweVsCodeExtension"; export * from "./vscode/ui"; diff --git a/packages/zowe-explorer-api/src/tree/IZoweTreeNode.ts b/packages/zowe-explorer-api/src/tree/IZoweTreeNode.ts index 0055a72814..e5f0d3c1fd 100644 --- a/packages/zowe-explorer-api/src/tree/IZoweTreeNode.ts +++ b/packages/zowe-explorer-api/src/tree/IZoweTreeNode.ts @@ -13,6 +13,7 @@ import * as vscode from "vscode"; import { IJob, imperative } from "@zowe/cli"; import { IZoweTree } from "./IZoweTree"; import { FileAttributes } from "../utils/files"; +import { DatasetFilter, NodeSort } from "./sorting"; export type IZoweNodeType = IZoweDatasetTreeNode | IZoweUSSTreeNode | IZoweJobTreeNode; @@ -20,44 +21,6 @@ export enum NodeAction { Download = "download", } -export type DatasetStats = { - user: string; - m4date: Date; -}; - -export enum DatasetSortOpts { - Name, - LastModified, - UserId, -} - -export enum SortDirection { - Ascending, - Descending, -} - -export enum DatasetFilterOpts { - LastModified, - UserId, -} - -export type DatasetFilter = { - method: DatasetFilterOpts; - value: string; -}; - -export type NodeSort = { - method: DatasetSortOpts | JobSortOpts; - direction: SortDirection; -}; - -export enum JobSortOpts { - Id, - DateSubmitted, - Name, - ReturnCode, -} - /** * The base interface for Zowe tree nodes that are implemented by vscode.TreeItem. * @@ -162,6 +125,11 @@ export interface IZoweTreeNode { setSessionToChoice(sessionObj: imperative.Session): void; } +export type DatasetStats = { + user: string; + m4date: Date; +}; + /** * Extended interface for Zowe Dataset tree nodes. * diff --git a/packages/zowe-explorer-api/src/tree/index.ts b/packages/zowe-explorer-api/src/tree/index.ts index 420c04ac45..23d5dd01bc 100644 --- a/packages/zowe-explorer-api/src/tree/index.ts +++ b/packages/zowe-explorer-api/src/tree/index.ts @@ -9,6 +9,7 @@ * */ +export * from "./sorting"; export * from "./ZoweExplorerTreeApi"; export * from "./ZoweTreeNode"; export * from "./IZoweTree"; diff --git a/packages/zowe-explorer-api/src/tree/sorting.ts b/packages/zowe-explorer-api/src/tree/sorting.ts new file mode 100644 index 0000000000..cefcf68eb0 --- /dev/null +++ b/packages/zowe-explorer-api/src/tree/sorting.ts @@ -0,0 +1,43 @@ +/** + * This program and the accompanying materials are made available under the terms of the + * Eclipse Public License v2.0 which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-v20.html + * + * SPDX-License-Identifier: EPL-2.0 + * + * Copyright Contributors to the Zowe Project. + * + */ + +export enum DatasetSortOpts { + Name, + LastModified, + UserId, +} + +export enum SortDirection { + Ascending, + Descending, +} + +export enum DatasetFilterOpts { + LastModified, + UserId, +} + +export type DatasetFilter = { + method: DatasetFilterOpts; + value: string; +}; + +export type NodeSort = { + method: DatasetSortOpts | JobSortOpts; + direction: SortDirection; +}; + +export enum JobSortOpts { + Id, + DateSubmitted, + Name, + ReturnCode, +} 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 42f33d7df9..893e1fc414 100644 --- a/packages/zowe-explorer/__tests__/__unit__/dataset/DatasetTree.unit.test.ts +++ b/packages/zowe-explorer/__tests__/__unit__/dataset/DatasetTree.unit.test.ts @@ -2697,7 +2697,7 @@ describe("Dataset Tree Unit Tests - Function initializeFavorites", () => { }); }); -describe("Dataset Tree Unit Tests - Function sortPdsMembers", () => { +describe("Dataset Tree Unit Tests - Function sortPdsMembersDialog", () => { const testTree = new DatasetTree(); const getBlockMocks = (): Record => ({ nodeDataChanged: jest.spyOn(DatasetTree.prototype, "nodeDataChanged"), @@ -2747,14 +2747,14 @@ describe("Dataset Tree Unit Tests - Function sortPdsMembers", () => { // case 1: called on PDS node mocks.showQuickPick.mockResolvedValueOnce({ label: "$(case-sensitive) Name (default)" }); testPds.children = []; - await testTree.sortPdsMembers(testPds); + await testTree.sortPdsMembersDialog(testPds); expect(mocks.nodeDataChanged).not.toHaveBeenCalled(); expect(mocks.refreshElement).toHaveBeenCalledWith(testPds); // case 2: called on session node mocks.showQuickPick.mockResolvedValueOnce({ label: "$(case-sensitive) Name (default)" }); testSession.children = []; - await testTree.sortPdsMembers(testSession); + await testTree.sortPdsMembersDialog(testSession); expect(mocks.nodeDataChanged).not.toHaveBeenCalled(); expect(mocks.refreshElement).toHaveBeenCalledWith(testSession); }); @@ -2762,7 +2762,7 @@ describe("Dataset Tree Unit Tests - Function sortPdsMembers", () => { it("sorts by name", async () => { const mocks = getBlockMocks(); mocks.showQuickPick.mockResolvedValueOnce({ label: "$(case-sensitive) Name (default)" }); - await testTree.sortPdsMembers(testPds); + await testTree.sortPdsMembersDialog(testPds); expect(mocks.nodeDataChanged).toHaveBeenCalled(); expect(mocks.refreshElement).not.toHaveBeenCalled(); expect(testPds.children.map((c: IZoweDatasetTreeNode) => c.label)).toStrictEqual(["A", "B", "C"]); @@ -2771,7 +2771,7 @@ describe("Dataset Tree Unit Tests - Function sortPdsMembers", () => { it("sorts by last modified date", async () => { const mocks = getBlockMocks(); mocks.showQuickPick.mockResolvedValueOnce({ label: "$(calendar) Date Modified" }); - await testTree.sortPdsMembers(testPds); + await testTree.sortPdsMembersDialog(testPds); expect(mocks.nodeDataChanged).toHaveBeenCalled(); expect(mocks.refreshElement).not.toHaveBeenCalled(); expect(testPds.children.map((c: IZoweDatasetTreeNode) => c.label)).toStrictEqual(["B", "C", "A"]); @@ -2780,14 +2780,14 @@ describe("Dataset Tree Unit Tests - Function sortPdsMembers", () => { it("sorts by user ID", async () => { const mocks = getBlockMocks(); mocks.showQuickPick.mockResolvedValueOnce({ label: "$(account) User ID" }); - await testTree.sortPdsMembers(testPds); + await testTree.sortPdsMembersDialog(testPds); expect(mocks.nodeDataChanged).toHaveBeenCalled(); expect(mocks.refreshElement).not.toHaveBeenCalled(); expect(testPds.children.map((c: IZoweDatasetTreeNode) => c.label)).toStrictEqual(["B", "A", "C"]); }); }); -describe("Dataset Tree Unit Tests - Function filterPdsMembers", () => { +describe("Dataset Tree Unit Tests - Function filterPdsMembersDialog", () => { const testTree = new DatasetTree(); const getBlockMocks = (): Record => ({ nodeDataChanged: jest.spyOn(DatasetTree.prototype, "nodeDataChanged"), @@ -2839,7 +2839,7 @@ describe("Dataset Tree Unit Tests - Function filterPdsMembers", () => { mocks.showQuickPick.mockResolvedValue("$(calendar) Date Modified" as any); mocks.showInputBox.mockResolvedValueOnce("2022-01-01"); testPds.children = []; - await testTree.filterPdsMembers(testPds); + await testTree.filterPdsMembersDialog(testPds); expect(mocks.nodeDataChanged).not.toHaveBeenCalled(); expect(mocks.refreshElement).toHaveBeenCalledWith(testPds); testPds.filter = undefined as any; @@ -2848,7 +2848,7 @@ describe("Dataset Tree Unit Tests - Function filterPdsMembers", () => { mocks.showQuickPick.mockResolvedValue("$(calendar) Date Modified" as any); mocks.showInputBox.mockResolvedValueOnce("2022-01-01"); testSession.children = []; - await testTree.filterPdsMembers(testSession); + await testTree.filterPdsMembersDialog(testSession); expect(mocks.nodeDataChanged).not.toHaveBeenCalled(); expect(mocks.refreshElement).toHaveBeenCalledWith(testSession); }); @@ -2857,7 +2857,7 @@ describe("Dataset Tree Unit Tests - Function filterPdsMembers", () => { const mocks = getBlockMocks(); mocks.showQuickPick.mockResolvedValue("$(calendar) Date Modified" as any); mocks.showInputBox.mockResolvedValueOnce("2022-03-15"); - await testTree.filterPdsMembers(testPds); + await testTree.filterPdsMembersDialog(testPds); expect(mocks.nodeDataChanged).toHaveBeenCalled(); expect(mocks.refreshElement).not.toHaveBeenCalled(); expect(testPds.children.map((c: IZoweDatasetTreeNode) => c.label)).toStrictEqual(["C"]); @@ -2868,7 +2868,7 @@ describe("Dataset Tree Unit Tests - Function filterPdsMembers", () => { const mocks = getBlockMocks(); mocks.showQuickPick.mockResolvedValue("$(account) User ID" as any); mocks.showInputBox.mockResolvedValueOnce("anotherUser"); - await testTree.filterPdsMembers(testPds); + await testTree.filterPdsMembersDialog(testPds); expect(mocks.nodeDataChanged).toHaveBeenCalled(); expect(mocks.refreshElement).not.toHaveBeenCalled(); expect(testPds.children.map((c: IZoweDatasetTreeNode) => c.label)).toStrictEqual(["B"]); diff --git a/packages/zowe-explorer/__tests__/__unit__/dataset/init.unit.test.ts b/packages/zowe-explorer/__tests__/__unit__/dataset/init.unit.test.ts index fedbf07666..2697d100c1 100644 --- a/packages/zowe-explorer/__tests__/__unit__/dataset/init.unit.test.ts +++ b/packages/zowe-explorer/__tests__/__unit__/dataset/init.unit.test.ts @@ -45,7 +45,8 @@ describe("Test src/dataset/extension", () => { onDidChangeConfiguration: jest.fn(), getTreeView: jest.fn(), refreshElement: jest.fn(), - sortPdsMembers: jest.fn(), + sortPdsMembersDialog: jest.fn(), + filterPdsMembersDialog: jest.fn(), }; const commands: IJestIt[] = [ { @@ -253,7 +254,11 @@ describe("Test src/dataset/extension", () => { }, { name: "zowe.ds.sortBy", - mock: [{ spy: jest.spyOn(dsProvider, "sortPdsMembers"), arg: [test.value] }], + mock: [{ spy: jest.spyOn(dsProvider, "sortPdsMembersDialog"), arg: [test.value] }], + }, + { + name: "zowe.ds.filterBy", + mock: [{ spy: jest.spyOn(dsProvider, "filterPdsMembersDialog"), arg: [test.value] }], }, { name: "onDidChangeConfiguration", diff --git a/packages/zowe-explorer/i18n/sample/src/dataset/DatasetTree.i18n.json b/packages/zowe-explorer/i18n/sample/src/dataset/DatasetTree.i18n.json index c3ac5386eb..d59c6ecff8 100644 --- a/packages/zowe-explorer/i18n/sample/src/dataset/DatasetTree.i18n.json +++ b/packages/zowe-explorer/i18n/sample/src/dataset/DatasetTree.i18n.json @@ -33,10 +33,11 @@ "sort.asc": "Ascending", "sort.desc": "Descending", "sort.selectDirection": "Select a sorting direction", - "ds.clearAllFilters": "$(clear-all) Clear all filters", - "ds.clearPdsFilter": "$(clear-all) Clear filters for this PDS", + "ds.clearProfileFilter": "$(clear-all) Clear filter for profile", + "ds.clearPdsFilter": "$(clear-all) Clear filter for PDS", "ds.selectFilterOpt": "Set a filter for {0}", - "ds.filterEntry.title": "Enter a value to filter by", "ds.filterEntry.invalidDate": "Invalid date format specified", + "ds.filterEntry.title": "Enter a value to filter by", + "ds.filterEntry.invalid": "Invalid filter specified", "defaultFilterPrompt.option.prompt.search": "$(plus) Create a new filter. For example: HLQ.*, HLQ.aaa.bbb, HLQ.ccc.ddd(member)" } diff --git a/packages/zowe-explorer/src/dataset/DatasetTree.ts b/packages/zowe-explorer/src/dataset/DatasetTree.ts index a73eca237a..f21a6a0ffa 100644 --- a/packages/zowe-explorer/src/dataset/DatasetTree.ts +++ b/packages/zowe-explorer/src/dataset/DatasetTree.ts @@ -25,11 +25,14 @@ import { IZoweTreeNode, DatasetFilter, DatasetSortOpts, + SortDirection, + NodeSort, + DatasetFilterOpts, } from "@zowe/zowe-explorer-api"; import { Profiles } from "../Profiles"; import { ZoweExplorerApiRegister } from "../ZoweExplorerApiRegister"; import { FilterDescriptor, FilterItem, errorHandling, syncSessionNode } from "../utils/ProfilesUtils"; -import { sortTreeItems, getAppName, getDocumentFilePath, SORT_OPTS_TO_ENUM } from "../shared/utils"; +import { sortTreeItems, getAppName, getDocumentFilePath, SORT_DIRS } from "../shared/utils"; import { ZoweTreeProvider } from "../abstract/ZoweTreeProvider"; import { ZoweDatasetNode } from "./ZoweDatasetNode"; import { getIconById, getIconByNode, IconId, IIconItem } from "../generators/icons"; @@ -39,7 +42,7 @@ import * as contextually from "../shared/context"; import { resetValidationSettings } from "../shared/actions"; import { closeOpenedTextFile } from "../utils/workspace"; import { IDataSet, IListOptions, imperative } from "@zowe/cli"; -import { DATASET_FILTER_KEYS, DATASET_FILTER_OPTS, DATASET_SORT_OPTS, validateDataSetName, validateMemberName } from "./utils"; +import { DATASET_FILTER_OPTS, DATASET_SORT_OPTS, validateDataSetName, validateMemberName } from "./utils"; import { SettingsConfig } from "../utils/SettingsConfig"; import { ZoweLogger } from "../utils/LoggerUtils"; import { TreeViewUtils } from "../utils/TreeViewUtils"; @@ -1293,19 +1296,57 @@ export class DatasetTree extends ZoweTreeProvider implements IZoweTree { + public updateSortForNode(node: IZoweDatasetTreeNode, sortOpts: NodeSort, isSession: boolean): void { + node.sort = sortOpts; + + if (isSession) { + // if a session was selected, apply this sort to ALL PDS members + if (node.children != null && node.children.length > 0) { + // children nodes already exist, sort and repaint to avoid extra refresh + for (const c of node.children) { + if (contextually.isPds(c) && c.children) { + c.sort = node.sort; + c.children.sort(ZoweDatasetNode.sortBy(node.sort)); + this.nodeDataChanged(c); + } + } + } else { + this.refreshElement(node); + } + } else if (node.children != null && node.children.length > 0) { + // children nodes already exist, sort and repaint to avoid extra refresh + node.children.sort(ZoweDatasetNode.sortBy(node.sort)); + this.nodeDataChanged(node); + } else { + this.refreshElement(node); + } + } + + /** + * Presents a dialog to the user with options and methods for sorting PDS members. + * @param node The node that was interacted with (via icon or right-click -> "Sort PDS members...") + */ + public async sortPdsMembersDialog(node: IZoweDatasetTreeNode): Promise { const isSession = contextually.isSession(node); + // Assume defaults if a user hasn't selected any sort options yet + const sortOpts = node.sort ?? { + method: DatasetSortOpts.Name, + direction: SortDirection.Ascending, + }; + + // Adapt menus to user based on the node that was interacted with const specifier = isSession ? localize("ds.allPdsSort", "all PDS members in {0}", node.label as string) : localize("ds.singlePdsSort", "the PDS members in {0}", node.label as string); const selection = await Gui.showQuickPick( - DATASET_SORT_OPTS.map((sortOpt, i) => ({ - label: node.sort?.method === i ? `${sortOpt} $(check)` : sortOpt, - description: i === DATASET_SORT_OPTS.length - 1 ? Object.keys(SORT_OPTS_TO_ENUM)[node.sort.direction] : null, + DATASET_SORT_OPTS.map((opt, i) => ({ + label: sortOpts.method === i ? `${opt} $(check)` : opt, + description: i === DATASET_SORT_OPTS.length - 1 ? SORT_DIRS[sortOpts.direction] : null, })), { placeHolder: localize("ds.selectSortOpt", "Select a sorting option for {0}", specifier), @@ -1316,50 +1357,37 @@ export class DatasetTree extends ZoweTreeProvider implements IZoweTree 0) { - // children nodes already exist, sort and repaint to avoid extra refresh - for (const c of node.children) { - if (contextually.isPds(c) && c.children) { - c.sort = node.sort; - c.children.sort(ZoweDatasetNode.sortBy(node.sort)); - this.nodeDataChanged(c); - } - } - } else { - this.refreshElement(node); - } - } else if (node.children != null && node.children.length > 0) { - // children nodes already exist, sort and repaint to avoid extra refresh - node.children.sort(ZoweDatasetNode.sortBy(node.sort)); - this.nodeDataChanged(node); - } else { - this.refreshElement(node); - } + // Update sort for node based on selections + this.updateSortForNode(node, { ...sortOpts, method: sortMethod }, isSession); } - public updateFilters(node: IZoweDatasetTreeNode, newFilter: DatasetFilter | null, isSession: boolean): void { + /** + * Updates or resets the filter for a given data set node. + * @param node The node whose filter should be updated/reset + * @param newFilter Either a valid `DatasetFilter` object, or `null` to reset the filter + * @param isSession Whether the node is a session + */ + public updateFilterForNode(node: IZoweDatasetTreeNode, newFilter: DatasetFilter | null, isSession: boolean): void { const oldFilter = node.filter; node.filter = newFilter; @@ -1406,15 +1434,20 @@ export class DatasetTree extends ZoweTreeProvider implements IZoweTree { + /** + * Presents a dialog to the user with options and methods for sorting PDS members. + * @param node The data set node that was interacted with (via icon or right-click => "Filter PDS members...") + */ + public async filterPdsMembersDialog(node: IZoweDatasetTreeNode): Promise { const isSession = contextually.isSession(node); + // Adapt menus to user based on the node that was interacted with const specifier = isSession ? localize("ds.allPdsSort", "all PDS members in {0}", node.label as string) : localize("ds.singlePdsSort", "the PDS members in {0}", node.label as string); const clearFilter = isSession - ? localize("ds.clearAllFilters", "$(clear-all) Clear all filters") - : localize("ds.clearPdsFilter", "$(clear-all) Clear filters for this PDS"); + ? localize("ds.clearProfileFilter", "$(clear-all) Clear filter for profile") + : localize("ds.clearPdsFilter", "$(clear-all) Clear filter for PDS"); const selection = ( await Gui.showQuickPick( [...DATASET_FILTER_OPTS.map((sortOpt, i) => (node.filter?.method === i ? `${sortOpt} $(check)` : sortOpt)), clearFilter], @@ -1423,32 +1456,44 @@ export class DatasetTree extends ZoweTreeProvider implements IZoweTree { + return dayjs(value).isValid() ? null : localize("ds.filterEntry.invalidDate", "Invalid date format specified"); + }; + const filter = await Gui.showInputBox({ title: localize("ds.filterEntry.title", "Enter a value to filter by"), placeHolder: "", - validateInput(value) { - return dayjs(value).isValid() ? null : localize("ds.filterEntry.invalidDate", "Invalid date format specified"); - }, + validateInput: + filterMethod === DatasetFilterOpts.LastModified + ? dateValidation + : (val): string => (val.length > 0 ? null : localize("ds.filterEntry.invalid", "Invalid filter specified")), }); + + // User dismissed filter entry, go back to filter selection if (filter == null) { + await this.filterPdsMembersDialog(node); return; } - const newFilter = { - method: filterMethod, - value: filter, - }; - - this.updateFilters(node, newFilter, isSession); + // Update filter for node based on selection & filter entry + this.updateFilterForNode( + node, + { + method: filterMethod, + value: filter, + }, + isSession + ); } } diff --git a/packages/zowe-explorer/src/dataset/init.ts b/packages/zowe-explorer/src/dataset/init.ts index 441b370455..01ffc33e0f 100644 --- a/packages/zowe-explorer/src/dataset/init.ts +++ b/packages/zowe-explorer/src/dataset/init.ts @@ -199,12 +199,12 @@ export async function initDatasetProvider(context: vscode.ExtensionContext): Pro context.subscriptions.push(vscode.commands.registerCommand("zowe.ds.ssoLogin", (node: IZoweTreeNode) => datasetProvider.ssoLogin(node))); context.subscriptions.push(vscode.commands.registerCommand("zowe.ds.ssoLogout", (node: IZoweTreeNode) => datasetProvider.ssoLogout(node))); context.subscriptions.push( - vscode.commands.registerCommand("zowe.ds.sortBy", async (node: IZoweDatasetTreeNode) => datasetProvider.sortPdsMembers(node)) + vscode.commands.registerCommand("zowe.ds.sortBy", async (node: IZoweDatasetTreeNode) => datasetProvider.sortPdsMembersDialog(node)) ); context.subscriptions.push( vscode.commands.registerCommand( "zowe.ds.filterBy", - async (node: IZoweDatasetTreeNode): Promise => datasetProvider.filterPdsMembers(node) + async (node: IZoweDatasetTreeNode): Promise => datasetProvider.filterPdsMembersDialog(node) ) ); context.subscriptions.push( diff --git a/packages/zowe-explorer/src/dataset/utils.ts b/packages/zowe-explorer/src/dataset/utils.ts index 40d861c577..0d8601dfad 100644 --- a/packages/zowe-explorer/src/dataset/utils.ts +++ b/packages/zowe-explorer/src/dataset/utils.ts @@ -30,11 +30,6 @@ export const DATASET_SORT_OPTS = [ export const DATASET_FILTER_OPTS = [localize("ds.sortByModified", "$(calendar) Date Modified"), localize("ds.sortByUserId", "$(account) User ID")]; -export const DATASET_FILTER_KEYS: Record = { - [localize("ds.sortByModified", "$(calendar) Date Modified")]: DatasetFilterOpts.LastModified, - [localize("ds.sortByUserId", "$(account) User ID")]: DatasetFilterOpts.UserId, -}; - export function getProfileAndDataSetName(node: IZoweNodeType): { profileName: string; dataSetName: string; diff --git a/packages/zowe-explorer/src/job/actions.ts b/packages/zowe-explorer/src/job/actions.ts index 121238a909..dcf93b0308 100644 --- a/packages/zowe-explorer/src/job/actions.ts +++ b/packages/zowe-explorer/src/job/actions.ts @@ -19,7 +19,7 @@ import { Job, Spool } from "./ZoweJobNode"; import * as nls from "vscode-nls"; import SpoolProvider, { encodeJobFile, getSpoolFiles, matchSpool } from "../SpoolProvider"; import { ZoweLogger } from "../utils/LoggerUtils"; -import { SORT_OPTS_TO_ENUM, getDefaultUri } from "../shared/utils"; +import { SORT_DIRS, getDefaultUri } from "../shared/utils"; import { ZosJobsProvider } from "./ZosJobsProvider"; import { JOB_SORT_OPTS } from "./utils"; @@ -534,7 +534,7 @@ export async function sortJobs(session: IZoweJobTreeNode, jobsProvider: ZosJobsP const selection = await Gui.showQuickPick( JOB_SORT_OPTS.map((sortOpt, i) => ({ label: i === session.sort.method ? `${sortOpt} $(check)` : sortOpt, - description: i === JOB_SORT_OPTS.length - 1 ? Object.keys(SORT_OPTS_TO_ENUM)[session.sort.direction] : null, + description: i === JOB_SORT_OPTS.length - 1 ? SORT_DIRS[session.sort.direction] : null, })), { placeHolder: localize("jobs.selectSortOpt", "Select a sorting option for jobs in {0}", session.label as string), @@ -544,13 +544,13 @@ export async function sortJobs(session: IZoweJobTreeNode, jobsProvider: ZosJobsP return; } if (selection.label === localize("setSortDirection", "$(fold) Sort Direction")) { - const dir = await Gui.showQuickPick([localize("sort.asc", "Ascending"), localize("sort.desc", "Descending")], { + const dir = await Gui.showQuickPick(SORT_DIRS, { placeHolder: localize("sort.selectDirection", "Select a sorting direction"), }); if (dir != null) { session.sort = { ...(session.sort ?? { method: JobSortOpts.Id }), - direction: SORT_OPTS_TO_ENUM[dir], + direction: SORT_DIRS.indexOf(dir), }; } await sortJobs(session, jobsProvider); diff --git a/packages/zowe-explorer/src/shared/utils.ts b/packages/zowe-explorer/src/shared/utils.ts index aa4d5a4e56..35b846825a 100644 --- a/packages/zowe-explorer/src/shared/utils.ts +++ b/packages/zowe-explorer/src/shared/utils.ts @@ -44,10 +44,7 @@ export const JOB_SUBMIT_DIALOG_OPTS = [ localize("zowe.jobs.confirmSubmission.allJobs", "All jobs"), ]; -export const SORT_OPTS_TO_ENUM: Record = { - [localize("sort.asc", "Ascending")]: SortDirection.Ascending, - [localize("sort.desc", "Descending")]: SortDirection.Descending, -}; +export const SORT_DIRS: string[] = [localize("sort.asc", "Ascending"), localize("sort.desc", "Descending")]; export function filterTreeByString(value: string, treeItems: vscode.QuickPickItem[]): vscode.QuickPickItem[] { ZoweLogger.trace("shared.utils.filterTreeByString called."); From 21fb8413ea4132597b5d3d52a0e5b10f3810a78f Mon Sep 17 00:00:00 2001 From: Trae Yelovich Date: Mon, 9 Oct 2023 19:23:06 -0400 Subject: [PATCH 100/189] fix(ds/sort): some SonarCloud code smells Signed-off-by: Trae Yelovich --- packages/zowe-explorer/src/dataset/DatasetTree.ts | 6 +++--- packages/zowe-explorer/src/dataset/utils.ts | 2 +- packages/zowe-explorer/src/shared/utils.ts | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/packages/zowe-explorer/src/dataset/DatasetTree.ts b/packages/zowe-explorer/src/dataset/DatasetTree.ts index f21a6a0ffa..3974227d96 100644 --- a/packages/zowe-explorer/src/dataset/DatasetTree.ts +++ b/packages/zowe-explorer/src/dataset/DatasetTree.ts @@ -1393,7 +1393,7 @@ export class DatasetTree extends ZoweTreeProvider implements IZoweTree 0) { + if (node.children?.length > 0) { // children nodes already exist, sort and repaint to avoid extra refresh for (const c of node.children) { const asDs = c as IZoweDatasetTreeNode; @@ -1405,7 +1405,7 @@ export class DatasetTree extends ZoweTreeProvider implements IZoweTree 0) { + if (newFilter != null && c.children?.length > 0) { c.children = c.children.filter(ZoweDatasetNode.filterBy(newFilter)); this.nodeDataChanged(c); } else { @@ -1424,7 +1424,7 @@ export class DatasetTree extends ZoweTreeProvider implements IZoweTree 0) { + if (newFilter != null && node.children?.length > 0) { // children nodes already exist, sort and repaint to avoid extra refresh node.children = node.children.filter(ZoweDatasetNode.filterBy(newFilter)); this.nodeDataChanged(node); diff --git a/packages/zowe-explorer/src/dataset/utils.ts b/packages/zowe-explorer/src/dataset/utils.ts index 0d8601dfad..956ae28f31 100644 --- a/packages/zowe-explorer/src/dataset/utils.ts +++ b/packages/zowe-explorer/src/dataset/utils.ts @@ -11,7 +11,7 @@ import * as globals from "../globals"; import * as nls from "vscode-nls"; -import { DatasetFilterOpts, IZoweNodeType } from "@zowe/zowe-explorer-api"; +import { IZoweNodeType } from "@zowe/zowe-explorer-api"; import { ZoweLogger } from "../utils/LoggerUtils"; // Set up localization diff --git a/packages/zowe-explorer/src/shared/utils.ts b/packages/zowe-explorer/src/shared/utils.ts index b0a5770d8c..af0ce5a45c 100644 --- a/packages/zowe-explorer/src/shared/utils.ts +++ b/packages/zowe-explorer/src/shared/utils.ts @@ -16,7 +16,7 @@ import * as vscode from "vscode"; import * as path from "path"; import * as globals from "../globals"; import * as os from "os"; -import { Gui, IZoweTreeNode, IZoweNodeType, IZoweDatasetTreeNode, IZoweUSSTreeNode, IZoweJobTreeNode, SortDirection } from "@zowe/zowe-explorer-api"; +import { Gui, IZoweTreeNode, IZoweNodeType, IZoweDatasetTreeNode, IZoweUSSTreeNode, IZoweJobTreeNode } from "@zowe/zowe-explorer-api"; import { ZoweExplorerApiRegister } from "../ZoweExplorerApiRegister"; import * as nls from "vscode-nls"; import { IZosFilesResponse, imperative } from "@zowe/cli"; From b2e0d9d30c62e07bc4eb0a3e9cba018cfd201992 Mon Sep 17 00:00:00 2001 From: Trae Yelovich Date: Mon, 9 Oct 2023 21:38:36 -0400 Subject: [PATCH 101/189] test(ds): Add test cases for filter/sort options Signed-off-by: Trae Yelovich --- .../__unit__/dataset/DatasetTree.unit.test.ts | 48 +++++++++++------ .../src/abstract/ZoweTreeProvider.ts | 2 +- .../zowe-explorer/src/dataset/DatasetTree.ts | 53 +++++++++---------- 3 files changed, 58 insertions(+), 45 deletions(-) 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 893e1fc414..05c8af3d5a 100644 --- a/packages/zowe-explorer/__tests__/__unit__/dataset/DatasetTree.unit.test.ts +++ b/packages/zowe-explorer/__tests__/__unit__/dataset/DatasetTree.unit.test.ts @@ -15,7 +15,7 @@ import * as fs from "fs"; import * as zowe from "@zowe/cli"; import { DatasetTree } from "../../../src/dataset/DatasetTree"; import { ZoweDatasetNode } from "../../../src/dataset/ZoweDatasetNode"; -import { Gui, IZoweDatasetTreeNode, ProfilesCache, ValidProfileEnum } from "@zowe/zowe-explorer-api"; +import { DatasetFilterOpts, Gui, IZoweDatasetTreeNode, ProfilesCache, ValidProfileEnum } from "@zowe/zowe-explorer-api"; import { ZoweExplorerApiRegister } from "../../../src/ZoweExplorerApiRegister"; import { Profiles } from "../../../src/Profiles"; import * as utils from "../../../src/utils/ProfilesUtils"; @@ -2742,21 +2742,21 @@ describe("Dataset Tree Unit Tests - Function sortPdsMembersDialog", () => { } }); - it("calls refreshElement if no children exist", async () => { + // for sorting, we shouldn't need to refresh since all nodes + // should be intact, just in a different order + it("does nothing if no children exist", async () => { const mocks = getBlockMocks(); // case 1: called on PDS node mocks.showQuickPick.mockResolvedValueOnce({ label: "$(case-sensitive) Name (default)" }); testPds.children = []; await testTree.sortPdsMembersDialog(testPds); expect(mocks.nodeDataChanged).not.toHaveBeenCalled(); - expect(mocks.refreshElement).toHaveBeenCalledWith(testPds); // case 2: called on session node mocks.showQuickPick.mockResolvedValueOnce({ label: "$(case-sensitive) Name (default)" }); testSession.children = []; await testTree.sortPdsMembersDialog(testSession); expect(mocks.nodeDataChanged).not.toHaveBeenCalled(); - expect(mocks.refreshElement).toHaveBeenCalledWith(testSession); }); it("sorts by name", async () => { @@ -2785,6 +2785,17 @@ describe("Dataset Tree Unit Tests - Function sortPdsMembersDialog", () => { expect(mocks.refreshElement).not.toHaveBeenCalled(); expect(testPds.children.map((c: IZoweDatasetTreeNode) => c.label)).toStrictEqual(["B", "A", "C"]); }); + + it("returns to sort selection dialog when sort direction selection is canceled", async () => { + const sortPdsMembersDialog = jest.spyOn(testTree, "sortPdsMembersDialog"); + const mocks = getBlockMocks(); + mocks.showQuickPick.mockResolvedValueOnce({ label: "$(fold) Sort Direction" }); + mocks.showQuickPick.mockResolvedValueOnce(undefined); + await testTree.sortPdsMembersDialog(testPds); + expect(mocks.nodeDataChanged).not.toHaveBeenCalled(); + expect(mocks.refreshElement).not.toHaveBeenCalled(); + expect(sortPdsMembersDialog).toHaveBeenCalledTimes(2); + }); }); describe("Dataset Tree Unit Tests - Function filterPdsMembersDialog", () => { @@ -2817,6 +2828,7 @@ describe("Dataset Tree Unit Tests - Function filterPdsMembersDialog", () => { } as unknown as ZoweDatasetNode, ]; testSession.children = [testPds]; + testPds.filter = undefined as any; }); afterEach(() => { @@ -2833,40 +2845,42 @@ describe("Dataset Tree Unit Tests - Function filterPdsMembersDialog", () => { } }); - it("calls refreshElement if no children exist", async () => { + it("calls refreshElement if children were removed from a previous filter", async () => { const mocks = getBlockMocks(); - // case 1: called on PDS node - mocks.showQuickPick.mockResolvedValue("$(calendar) Date Modified" as any); + mocks.showQuickPick.mockResolvedValueOnce("$(calendar) Date Modified" as any); mocks.showInputBox.mockResolvedValueOnce("2022-01-01"); + + testPds.filter = { method: DatasetFilterOpts.UserId, value: "invalidUserId" }; testPds.children = []; await testTree.filterPdsMembersDialog(testPds); expect(mocks.nodeDataChanged).not.toHaveBeenCalled(); expect(mocks.refreshElement).toHaveBeenCalledWith(testPds); - testPds.filter = undefined as any; + }); - // case 2: called on session node - mocks.showQuickPick.mockResolvedValue("$(calendar) Date Modified" as any); - mocks.showInputBox.mockResolvedValueOnce("2022-01-01"); - testSession.children = []; - await testTree.filterPdsMembersDialog(testSession); + it("returns to filter selection dialog when filter entry is canceled", async () => { + const filterPdsMembersSpy = jest.spyOn(testTree, "filterPdsMembersDialog"); + const mocks = getBlockMocks(); + mocks.showQuickPick.mockResolvedValueOnce("$(calendar) Date Modified" as any); + mocks.showInputBox.mockResolvedValueOnce(undefined); + await testTree.filterPdsMembersDialog(testPds); expect(mocks.nodeDataChanged).not.toHaveBeenCalled(); - expect(mocks.refreshElement).toHaveBeenCalledWith(testSession); + expect(mocks.refreshElement).not.toHaveBeenCalled(); + expect(filterPdsMembersSpy).toHaveBeenCalledTimes(2); }); it("filters by last modified date", async () => { const mocks = getBlockMocks(); - mocks.showQuickPick.mockResolvedValue("$(calendar) Date Modified" as any); + mocks.showQuickPick.mockResolvedValueOnce("$(calendar) Date Modified" as any); mocks.showInputBox.mockResolvedValueOnce("2022-03-15"); await testTree.filterPdsMembersDialog(testPds); expect(mocks.nodeDataChanged).toHaveBeenCalled(); expect(mocks.refreshElement).not.toHaveBeenCalled(); expect(testPds.children.map((c: IZoweDatasetTreeNode) => c.label)).toStrictEqual(["C"]); - testPds.filter = undefined as any; }); it("filters by user ID", async () => { const mocks = getBlockMocks(); - mocks.showQuickPick.mockResolvedValue("$(account) User ID" as any); + mocks.showQuickPick.mockResolvedValueOnce("$(account) User ID" as any); mocks.showInputBox.mockResolvedValueOnce("anotherUser"); await testTree.filterPdsMembersDialog(testPds); expect(mocks.nodeDataChanged).toHaveBeenCalled(); diff --git a/packages/zowe-explorer/src/abstract/ZoweTreeProvider.ts b/packages/zowe-explorer/src/abstract/ZoweTreeProvider.ts index afbdfef2e2..eddd2868d5 100644 --- a/packages/zowe-explorer/src/abstract/ZoweTreeProvider.ts +++ b/packages/zowe-explorer/src/abstract/ZoweTreeProvider.ts @@ -87,7 +87,7 @@ export class ZoweTreeProvider { /** * Fire the "onDidChangeTreeData" event to signal that a node in the tree has changed. - * Unlike `refreshElement`, this function does NOT signal a refresh for the given node - + * Unlike `refreshElement`, this function does *not* signal a refresh for the given node - * it simply tells VS Code to repaint the node in the tree. * @param node The node that should be repainted */ diff --git a/packages/zowe-explorer/src/dataset/DatasetTree.ts b/packages/zowe-explorer/src/dataset/DatasetTree.ts index 3974227d96..4ac818c759 100644 --- a/packages/zowe-explorer/src/dataset/DatasetTree.ts +++ b/packages/zowe-explorer/src/dataset/DatasetTree.ts @@ -1305,7 +1305,7 @@ export class DatasetTree extends ZoweTreeProvider implements IZoweTree 0) { + if (node.children?.length > 0) { // children nodes already exist, sort and repaint to avoid extra refresh for (const c of node.children) { if (contextually.isPds(c) && c.children) { @@ -1314,15 +1314,11 @@ export class DatasetTree extends ZoweTreeProvider implements IZoweTree 0) { + } else if (node.children?.length > 0) { // children nodes already exist, sort and repaint to avoid extra refresh node.children.sort(ZoweDatasetNode.sortBy(node.sort)); this.nodeDataChanged(node); - } else { - this.refreshElement(node); } } @@ -1391,16 +1387,22 @@ export class DatasetTree extends ZoweTreeProvider implements IZoweTree 0) { // children nodes already exist, sort and repaint to avoid extra refresh for (const c of node.children) { const asDs = c as IZoweDatasetTreeNode; - if (contextually.isPds(c) && c.children) { - // If a filter was NOT set for this PDS AND there was an old session-wide filter set, - // refresh it to get any missing nodes back since it will use the new session-wide filter - if (asDs.filter == null && oldFilter != null) { + + // PDS-level filters should have precedence over a session-level filter + if (asDs.filter != null) { + continue; + } + + if (contextually.isPds(c)) { + // If there was an old session-wide filter set: refresh to get any + // missing nodes - new filter will be applied + if (oldFilter != null) { this.refreshElement(c); continue; } @@ -1413,24 +1415,21 @@ export class DatasetTree extends ZoweTreeProvider implements IZoweTree 0) { - // children nodes already exist, sort and repaint to avoid extra refresh - node.children = node.children.filter(ZoweDatasetNode.filterBy(newFilter)); - this.nodeDataChanged(node); - } else { - this.refreshElement(node); - } + // Updating filter for PDS node + // if a filter was already set, just refresh to grab any missing nodes + if (oldFilter != null) { + this.refreshElement(node); + return; + } + + // since there wasn't a previous filter, sort and repaint existing nodes + if (newFilter != null && node.children?.length > 0) { + node.children = node.children.filter(ZoweDatasetNode.filterBy(newFilter)); + this.nodeDataChanged(node); } } From 3cde152b3f87db1e6fcb3df4bd7b0d805b14f339 Mon Sep 17 00:00:00 2001 From: Trae Yelovich Date: Tue, 10 Oct 2023 09:27:26 -0400 Subject: [PATCH 102/189] fix: sort direction should only apply to PDS members - Also adds unit tests for dataset filtering, sorting, and sorting jobs Signed-off-by: Trae Yelovich --- .../__unit__/dataset/DatasetTree.unit.test.ts | 37 +++++++++++++++++-- .../__unit__/job/actions.unit.test.ts | 19 +++++++++- .../src/dataset/ZoweDatasetNode.ts | 24 +++++++----- packages/zowe-explorer/src/job/actions.ts | 7 +--- 4 files changed, 68 insertions(+), 19 deletions(-) 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 05c8af3d5a..57b901c912 100644 --- a/packages/zowe-explorer/__tests__/__unit__/dataset/DatasetTree.unit.test.ts +++ b/packages/zowe-explorer/__tests__/__unit__/dataset/DatasetTree.unit.test.ts @@ -2845,7 +2845,7 @@ describe("Dataset Tree Unit Tests - Function filterPdsMembersDialog", () => { } }); - it("calls refreshElement if children were removed from a previous filter", async () => { + it("calls refreshElement if PDS children were removed from a previous filter", async () => { const mocks = getBlockMocks(); mocks.showQuickPick.mockResolvedValueOnce("$(calendar) Date Modified" as any); mocks.showInputBox.mockResolvedValueOnce("2022-01-01"); @@ -2868,7 +2868,7 @@ describe("Dataset Tree Unit Tests - Function filterPdsMembersDialog", () => { expect(filterPdsMembersSpy).toHaveBeenCalledTimes(2); }); - it("filters by last modified date", async () => { + it("filters single PDS by last modified date", async () => { const mocks = getBlockMocks(); mocks.showQuickPick.mockResolvedValueOnce("$(calendar) Date Modified" as any); mocks.showInputBox.mockResolvedValueOnce("2022-03-15"); @@ -2878,7 +2878,7 @@ describe("Dataset Tree Unit Tests - Function filterPdsMembersDialog", () => { expect(testPds.children.map((c: IZoweDatasetTreeNode) => c.label)).toStrictEqual(["C"]); }); - it("filters by user ID", async () => { + it("filters single PDS by user ID", async () => { const mocks = getBlockMocks(); mocks.showQuickPick.mockResolvedValueOnce("$(account) User ID" as any); mocks.showInputBox.mockResolvedValueOnce("anotherUser"); @@ -2887,4 +2887,35 @@ describe("Dataset Tree Unit Tests - Function filterPdsMembersDialog", () => { expect(mocks.refreshElement).not.toHaveBeenCalled(); expect(testPds.children.map((c: IZoweDatasetTreeNode) => c.label)).toStrictEqual(["B"]); }); + + it("filters PDS members using the session node filter", async () => { + const mocks = getBlockMocks(); + const uidString = "$(account) User ID" as any; + const anotherUser = "anotherUser"; + mocks.showQuickPick.mockResolvedValueOnce(uidString).mockResolvedValueOnce(uidString); + mocks.showInputBox.mockResolvedValueOnce(anotherUser).mockResolvedValueOnce(anotherUser); + + // case 1: old filter was set on session, just refresh PDS to use new filter + testSession.filter = { + method: DatasetFilterOpts.LastModified, + value: "2020-01-01", + }; + await testTree.filterPdsMembersDialog(testSession); + expect(mocks.refreshElement).toHaveBeenCalled(); + + // case 2: no old filter present, PDS has children to be filtered + testSession.filter = undefined; + await testTree.filterPdsMembersDialog(testSession); + expect(mocks.nodeDataChanged).toHaveBeenCalled(); + }); + + it("clears filter for a PDS when selected in dialog", async () => { + const mocks = getBlockMocks(); + const resp = "$(clear-all) Clear filter for PDS" as any; + mocks.showQuickPick.mockResolvedValueOnce(resp); + const updateFilterForNode = jest.spyOn(DatasetTree.prototype, "updateFilterForNode"); + await testTree.filterPdsMembersDialog(testPds); + expect(mocks.refreshElement).not.toHaveBeenCalled(); + expect(updateFilterForNode).toHaveBeenCalledWith(testPds, null, false); + }); }); diff --git a/packages/zowe-explorer/__tests__/__unit__/job/actions.unit.test.ts b/packages/zowe-explorer/__tests__/__unit__/job/actions.unit.test.ts index 5f43c7283d..a29d9efa9e 100644 --- a/packages/zowe-explorer/__tests__/__unit__/job/actions.unit.test.ts +++ b/packages/zowe-explorer/__tests__/__unit__/job/actions.unit.test.ts @@ -1344,7 +1344,7 @@ describe("Job Actions Unit Tests - Misc. functions", () => { expect(statusMsgSpy).toHaveBeenCalledWith(`$(sync~spin) Polling: ${testDoc.fileName}...`); }); }); -describe("sortjobsby function", () => { +describe("sortJobs function", () => { afterEach(() => { jest.restoreAllMocks(); }); @@ -1406,4 +1406,21 @@ describe("sortjobsby function", () => { expect(sortbyretcodespy).toHaveBeenCalled(); expect(sortbyretcodespy.mock.calls[0][0].children).toStrictEqual(expected.mSessionNodes[0].children); }); + + it("updates sort options after selecting sort direction; returns user to sort selection", async () => { + const globalMocks = createGlobalMocks(); + const testtree = new ZosJobsProvider(); + testtree.mSessionNodes[0].sort = { + method: JobSortOpts.Id, + direction: SortDirection.Ascending, + }; + testtree.mSessionNodes[0].children = [globalMocks()[0]]; + const jobsSortBy = jest.spyOn(ZosJobsProvider.prototype, "sortBy"); + const quickPickSpy = jest.spyOn(Gui, "showQuickPick").mockResolvedValueOnce({ label: "$(fold) Sort Direction" }); + quickPickSpy.mockResolvedValueOnce("Descending" as any); + await jobActions.sortJobs(testtree.mSessionNodes[0], testtree); + expect(testtree.mSessionNodes[0].sort.direction).toBe(SortDirection.Descending); + expect(quickPickSpy).toHaveBeenCalledTimes(3); + expect(jobsSortBy).not.toHaveBeenCalled(); + }); }); diff --git a/packages/zowe-explorer/src/dataset/ZoweDatasetNode.ts b/packages/zowe-explorer/src/dataset/ZoweDatasetNode.ts index 364cc2b983..9b83a8915d 100644 --- a/packages/zowe-explorer/src/dataset/ZoweDatasetNode.ts +++ b/packages/zowe-explorer/src/dataset/ZoweDatasetNode.ts @@ -57,11 +57,8 @@ export class ZoweDatasetNode extends ZoweTreeNode implements IZoweDatasetTreeNod public ongoingActions: Record> = {}; public wasDoubleClicked: boolean = false; public stats: DatasetStats; - public sort: NodeSort = { - method: DatasetSortOpts.Name, - direction: SortDirection.Ascending, - }; - public filter: DatasetFilter; + public sort?: NodeSort; + public filter?: DatasetFilter; /** * Creates an instance of ZoweDatasetNode @@ -96,6 +93,15 @@ export class ZoweDatasetNode extends ZoweTreeNode implements IZoweDatasetTreeNod if (icon) { this.iconPath = icon.path; } + + if (this.getParent() == null) { + // set default sort options for session nodes + this.sort = { + method: DatasetSortOpts.Name, + direction: SortDirection.Ascending, + }; + } + if (!globals.ISTHEIA && contextually.isSession(this)) { this.id = this.label as string; } @@ -312,14 +318,14 @@ export class ZoweDatasetNode extends ZoweTreeNode implements IZoweDatasetTreeNod */ public static sortBy(sort: NodeSort): (a: IZoweDatasetTreeNode, b: IZoweDatasetTreeNode) => number { return (a, b): number => { - const sortLessThan = sort.direction == SortDirection.Ascending ? -1 : 1; - const sortGreaterThan = sortLessThan * -1; - const aParent = a.getParent(); if (aParent == null || !contextually.isPds(aParent)) { - return (a.label as string) < (b.label as string) ? sortLessThan : sortGreaterThan; + return (a.label as string) < (b.label as string) ? -1 : 1; } + const sortLessThan = sort.direction == SortDirection.Ascending ? -1 : 1; + const sortGreaterThan = sortLessThan * -1; + switch (sort.method) { case DatasetSortOpts.LastModified: return a.stats?.m4date < b.stats?.m4date ? sortLessThan : sortGreaterThan; diff --git a/packages/zowe-explorer/src/job/actions.ts b/packages/zowe-explorer/src/job/actions.ts index dcf93b0308..4a5d3d4adb 100644 --- a/packages/zowe-explorer/src/job/actions.ts +++ b/packages/zowe-explorer/src/job/actions.ts @@ -557,11 +557,6 @@ export async function sortJobs(session: IZoweJobTreeNode, jobsProvider: ZosJobsP return; } - const optIndex = JOB_SORT_OPTS.indexOf(selection.label.replace(" $(check)", "")); - if (optIndex == -1) { - return; - } - - session.sort.method = optIndex; + session.sort.method = JOB_SORT_OPTS.indexOf(selection.label.replace(" $(check)", "")); jobsProvider.sortBy(session); } From 8fe027a4497c6b97d48fa851b3837a9a861ce4ec Mon Sep 17 00:00:00 2001 From: Billie Simmons <49491949+JillieBeanSim@users.noreply.github.com> Date: Tue, 10 Oct 2023 09:42:02 -0400 Subject: [PATCH 103/189] Submit JCL right-click option added for local JCL Signed-off-by: Billie Simmons <49491949+JillieBeanSim@users.noreply.github.com> --- packages/zowe-explorer/package.json | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/packages/zowe-explorer/package.json b/packages/zowe-explorer/package.json index c602c3c2d8..b79b9c3b1d 100644 --- a/packages/zowe-explorer/package.json +++ b/packages/zowe-explorer/package.json @@ -822,6 +822,20 @@ "group": "navigation" } ], + "editor/context": [ + { + "when": "resourceLangId == jcl", + "command": "zowe.ds.submitJcl", + "group": "000_zowe_dsMainframeInteraction@1" + } + ], + "explorer/context": [ + { + "when": "resourceLangId == jcl", + "command": "zowe.ds.submitJcl", + "group": "000_zowe_dsMainframeInteraction@1" + } + ], "view/item/context": [ { "when": "viewItem =~ /^(?!.*_fav.*)ussSession.*/ && !listMultiSelection", From 9ade075f1f6fb675a64be1bbf146d004bc4a13e0 Mon Sep 17 00:00:00 2001 From: Billie Simmons <49491949+JillieBeanSim@users.noreply.github.com> Date: Tue, 10 Oct 2023 09:42:10 -0400 Subject: [PATCH 104/189] Add check for doc language in the Submit JCL method Signed-off-by: Billie Simmons <49491949+JillieBeanSim@users.noreply.github.com> --- packages/zowe-explorer/src/dataset/actions.ts | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/packages/zowe-explorer/src/dataset/actions.ts b/packages/zowe-explorer/src/dataset/actions.ts index 7c7d64c02e..aa7d712e40 100644 --- a/packages/zowe-explorer/src/dataset/actions.ts +++ b/packages/zowe-explorer/src/dataset/actions.ts @@ -976,12 +976,21 @@ export async function showAttributes(node: api.IZoweDatasetTreeNode, datasetProv export async function submitJcl(datasetProvider: api.IZoweTree): Promise { ZoweLogger.trace("dataset.actions.submitJcl called."); if (!vscode.window.activeTextEditor) { - const errorMsg = localize("submitJcl.noDocumentOpen", "No editor with a document that could be submitted as JCL is currently open."); - api.Gui.errorMessage(errorMsg); - ZoweLogger.error(errorMsg); + const notActiveEditorMsg = localize( + "submitJcl.notActiveEditorMsg", + "No editor with a document that could be submitted as JCL is currently open." + ); + api.Gui.errorMessage(notActiveEditorMsg); + ZoweLogger.error(notActiveEditorMsg); return; } const doc = vscode.window.activeTextEditor.document; + if (doc.languageId !== "jcl") { + const notJclMsg = localize("submitJcl.notJclMsg", "The document being submitted is not a JCL, submission cancelled."); + api.Gui.errorMessage(notJclMsg); + ZoweLogger.error(notJclMsg); + return; + } ZoweLogger.debug(localize("submitJcl.submitting", "Submitting JCL in document {0}", doc.fileName)); // get session name const sessionregex = /\[(.*)(\])(?!.*\])/g; From bd32734658649fffcc3b62736d48e9849b334403 Mon Sep 17 00:00:00 2001 From: Trae Yelovich Date: Tue, 10 Oct 2023 09:46:16 -0400 Subject: [PATCH 105/189] fix(test): Fix 'fake session node' sort options in test case Signed-off-by: Trae Yelovich --- .../zowe-explorer/__tests__/__unit__/ZoweNode.unit.test.ts | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/packages/zowe-explorer/__tests__/__unit__/ZoweNode.unit.test.ts b/packages/zowe-explorer/__tests__/__unit__/ZoweNode.unit.test.ts index f7a716e91c..f52fb1af0a 100644 --- a/packages/zowe-explorer/__tests__/__unit__/ZoweNode.unit.test.ts +++ b/packages/zowe-explorer/__tests__/__unit__/ZoweNode.unit.test.ts @@ -18,7 +18,7 @@ import { List, imperative } from "@zowe/cli"; import { Profiles } from "../../src/Profiles"; import * as globals from "../../src/globals"; import { ZoweLogger } from "../../src/utils/LoggerUtils"; -import { DatasetSortOpts } from "@zowe/zowe-explorer-api"; +import { DatasetSortOpts, SortDirection } from "@zowe/zowe-explorer-api"; describe("Unit Tests (Jest)", () => { // Globals @@ -355,7 +355,10 @@ describe("Unit Tests (Jest)", () => { }; }), }); - const sessionNode = { getSessionNode: jest.fn(), sortMethod: DatasetSortOpts.Name } as unknown as ZoweDatasetNode; + const sessionNode = { + getSessionNode: jest.fn(), + sort: { method: DatasetSortOpts.Name, direction: SortDirection.Ascending }, + } as unknown as ZoweDatasetNode; const getSessionNodeSpy = jest.spyOn(ZoweDatasetNode.prototype, "getSessionNode").mockReturnValue(sessionNode); // Creating a rootNode const pds = new ZoweDatasetNode( From 0bf58caf89a03fac473dbbe285742f256a7e97ae Mon Sep 17 00:00:00 2001 From: Billie Simmons <49491949+JillieBeanSim@users.noreply.github.com> Date: Tue, 10 Oct 2023 09:49:01 -0400 Subject: [PATCH 106/189] fix unit tests Signed-off-by: Billie Simmons <49491949+JillieBeanSim@users.noreply.github.com> --- .../zowe-explorer/__tests__/__unit__/job/actions.unit.test.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/zowe-explorer/__tests__/__unit__/job/actions.unit.test.ts b/packages/zowe-explorer/__tests__/__unit__/job/actions.unit.test.ts index 85737a5c89..ad589fd9e2 100644 --- a/packages/zowe-explorer/__tests__/__unit__/job/actions.unit.test.ts +++ b/packages/zowe-explorer/__tests__/__unit__/job/actions.unit.test.ts @@ -486,6 +486,7 @@ describe("Jobs Actions Unit Tests - Function submitJcl", () => { Object.defineProperty(profileInstance, "loadNamedProfile", { value: jest.fn(), }); + (textDocument.languageId as any) = "jcl"; return { session, From a761593bfdd7d9622847335c4fbbd30b56e97e1c Mon Sep 17 00:00:00 2001 From: Billie Simmons <49491949+JillieBeanSim@users.noreply.github.com> Date: Tue, 10 Oct 2023 09:55:37 -0400 Subject: [PATCH 107/189] add CHANGELOG Signed-off-by: Billie Simmons <49491949+JillieBeanSim@users.noreply.github.com> --- packages/zowe-explorer/CHANGELOG.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/zowe-explorer/CHANGELOG.md b/packages/zowe-explorer/CHANGELOG.md index b4815bcd01..ef6267c634 100644 --- a/packages/zowe-explorer/CHANGELOG.md +++ b/packages/zowe-explorer/CHANGELOG.md @@ -10,10 +10,11 @@ All notable changes to the "vscode-extension-for-zowe" extension will be documen - Introduce a new user interface for managing profiles via right-click action "Manage Profile". - Added new edit feature on `Edit Attributes` view for changing file tags on USS [#2113](https://github.com/zowe/vscode-extension-for-zowe/issues/2113) - Added new API {ZE Extender MetaData} to allow extenders to have the metadata of registered extenders to aid in team configuration file creation from a view that isn't Zowe Explorer's. [#2394](https://github.com/zowe/vscode-extension-for-zowe/issues/2394) +- Added new right-click action for `Submit JCL` to local JCL files in VS Code file explorer as well as JCL opened in the VS Code text editor. [#2475](https://github.com/zowe/vscode-extension-for-zowe/issues/2475) ### Bug fixes -- Fixed submitting local JCL using command pallet option `Zowe Explorer: Submit JCL` by adding a check for chosen profile returned to continue the action. [#1625](https://github.com/zowe/vscode-extension-for-zowe/issues/1625) +- Fixed submitting local JCL using command pallet option `Zowe Explorer: Submit JCL` by adding a check for chosen profile returned to continue the action and added check on the language id for JCL. [#1625](https://github.com/zowe/vscode-extension-for-zowe/issues/1625) - Fixed conflict resolution being skipped if local and remote file have different contents but are the same size. [#2496](https://github.com/zowe/vscode-extension-for-zowe/issues/2496) ## `2.11.0` From 64ea1e431ef6d0ace622c8b40c2cb37d1bb95ef3 Mon Sep 17 00:00:00 2001 From: Billie Simmons <49491949+JillieBeanSim@users.noreply.github.com> Date: Tue, 10 Oct 2023 09:58:29 -0400 Subject: [PATCH 108/189] run prepublish Signed-off-by: Billie Simmons <49491949+JillieBeanSim@users.noreply.github.com> --- .../zowe-explorer/i18n/sample/src/dataset/actions.i18n.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/zowe-explorer/i18n/sample/src/dataset/actions.i18n.json b/packages/zowe-explorer/i18n/sample/src/dataset/actions.i18n.json index aa1718439c..114e621ffc 100644 --- a/packages/zowe-explorer/i18n/sample/src/dataset/actions.i18n.json +++ b/packages/zowe-explorer/i18n/sample/src/dataset/actions.i18n.json @@ -42,7 +42,8 @@ "showAttributes.lengthError": "No matching names found for query: {0}", "showAttributes.error": "Unable to list attributes.", "attributes.title": "Attributes", - "submitJcl.noDocumentOpen": "No editor with a document that could be submitted as JCL is currently open.", + "submitJcl.notActiveEditorMsg": "No editor with a document that could be submitted as JCL is currently open.", + "submitJcl.notJclMsg": "The document being submitted is not a JCL, submission cancelled.", "submitJcl.submitting": "Submitting JCL in document {0}", "submitJcl.qp.placeholder": "Select the Profile to use to submit the job", "submitJcl.noProfile": "No profiles available", From 79cf64988d7f40ba801159a1d5d4e3909de01558 Mon Sep 17 00:00:00 2001 From: Trae Yelovich Date: Tue, 10 Oct 2023 10:05:14 -0400 Subject: [PATCH 109/189] fix, chore: remove unnecessary refresh in sortBy; update CHANGELOGS Signed-off-by: Trae Yelovich --- packages/zowe-explorer-api/CHANGELOG.md | 3 +++ packages/zowe-explorer/CHANGELOG.md | 4 +++- packages/zowe-explorer/src/job/ZosJobsProvider.ts | 2 -- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/packages/zowe-explorer-api/CHANGELOG.md b/packages/zowe-explorer-api/CHANGELOG.md index c8fc4db2b2..7dc201454d 100644 --- a/packages/zowe-explorer-api/CHANGELOG.md +++ b/packages/zowe-explorer-api/CHANGELOG.md @@ -8,6 +8,9 @@ All notable changes to the "zowe-explorer-api" extension will be documented in t - Added optional `getTag` function to `ZoweExplorerAPI.IUss` for getting the tag of a file on USS. - Added new API {ZE Extender MetaData} to allow extenders to have the metadata of registered extenders to aid in team configuration file creation from a view that isn't Zowe Explorer's. [#2394](https://github.com/zowe/vscode-extension-for-zowe/issues/2394) +- Add `sort` and `filter` optional variables for storing sort/filter options alongside tree nodes. [#2420](https://github.com/zowe/vscode-extension-for-zowe/issues/2420) +- Add `stats` optional variable for storing dataset stats (such as user, modified date, etc.) +- Add option enums and types for sorting, filtering and sort direction in tree nodes. [#2420](https://github.com/zowe/vscode-extension-for-zowe/issues/2420) ### Bug fixes diff --git a/packages/zowe-explorer/CHANGELOG.md b/packages/zowe-explorer/CHANGELOG.md index c96a16391a..ae5535716e 100644 --- a/packages/zowe-explorer/CHANGELOG.md +++ b/packages/zowe-explorer/CHANGELOG.md @@ -6,9 +6,11 @@ All notable changes to the "vscode-extension-for-zowe" extension will be documen ### New features and enhancements -- Added "Sort Jobs" feature for job nodes in Jobs tree view. [#2257](https://github.com/zowe/vscode-extension-for-zowe/issues/2251) +- Added "Sort Jobs" feature for job nodes in Jobs tree view: accessible via sort icon or right-clicking on session node. [#2257](https://github.com/zowe/vscode-extension-for-zowe/issues/2251) - Added new edit feature on `Edit Attributes` view for changing file tags on USS [#2113](https://github.com/zowe/vscode-extension-for-zowe/issues/2113) - Added new API {ZE Extender MetaData} to allow extenders to have the metadata of registered extenders to aid in team configuration file creation from a view that isn't Zowe Explorer's. [#2394](https://github.com/zowe/vscode-extension-for-zowe/issues/2394) +- Added "Sort PDS members" feature in Data Sets tree view: accessible via sort icon on session node, or by right-clicking a PDS or session. [#2420](https://github.com/zowe/vscode-extension-for-zowe/issues/2420) +- Added "Filter PDS members" feature in Data Sets tree view: accessible via filter icon on session node, or by right-clicking a PDS or session. [#2420](https://github.com/zowe/vscode-extension-for-zowe/issues/2420) ### Bug fixes diff --git a/packages/zowe-explorer/src/job/ZosJobsProvider.ts b/packages/zowe-explorer/src/job/ZosJobsProvider.ts index f87700e297..1da57d443b 100644 --- a/packages/zowe-explorer/src/job/ZosJobsProvider.ts +++ b/packages/zowe-explorer/src/job/ZosJobsProvider.ts @@ -1126,8 +1126,6 @@ export class ZosJobsProvider extends ZoweTreeProvider implements IZoweTree Date: Tue, 10 Oct 2023 14:15:57 -0400 Subject: [PATCH 110/189] fix(ds/filter): Refresh PDS if session/PDS had a previous filter Signed-off-by: Trae Yelovich --- packages/zowe-explorer/src/dataset/DatasetTree.ts | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/packages/zowe-explorer/src/dataset/DatasetTree.ts b/packages/zowe-explorer/src/dataset/DatasetTree.ts index 4ac818c759..8520764a3b 100644 --- a/packages/zowe-explorer/src/dataset/DatasetTree.ts +++ b/packages/zowe-explorer/src/dataset/DatasetTree.ts @@ -1420,8 +1420,9 @@ export class DatasetTree extends ZoweTreeProvider implements IZoweTree Date: Tue, 10 Oct 2023 16:16:30 -0400 Subject: [PATCH 111/189] add conditional rendering Signed-off-by: Rudy Flores <68666202+rudyflores@users.noreply.github.com> --- .../PersistentDataGridHeaders.tsx | 14 +++++-- .../PersistentTable/PersistentDataPanel.tsx | 2 +- .../PersistentTable/PersistentTableData.tsx | 38 ++++++++++++------- .../PersistentDropdownOptions.tsx | 4 +- .../PersistentUtilitiesBar.tsx | 2 +- 5 files changed, 38 insertions(+), 22 deletions(-) diff --git a/packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentTable/PersistentDataGridHeaders.tsx b/packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentTable/PersistentDataGridHeaders.tsx index 6dbe293fe9..0eeaf2a463 100644 --- a/packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentTable/PersistentDataGridHeaders.tsx +++ b/packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentTable/PersistentDataGridHeaders.tsx @@ -1,15 +1,21 @@ import { VSCodeDataGridRow, VSCodeDataGridCell } from "@vscode/webview-ui-toolkit/react"; import { JSXInternal } from "preact/src/jsx"; -export default function PersistentDataGridHeaders(): JSXInternal.Element { +export default function PersistentDataGridHeaders({ selection }: { selection: { selection: string } }): JSXInternal.Element { + const renderDeleteHeader = () => { + return selection.selection === "search" || selection.selection === "fileHistory" ? ( + + Delete + + ) : null; + }; + return ( Item - - Delete - + {renderDeleteHeader()} ); } diff --git a/packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentTable/PersistentDataPanel.tsx b/packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentTable/PersistentDataPanel.tsx index e9266539b8..102c9ba9f3 100644 --- a/packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentTable/PersistentDataPanel.tsx +++ b/packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentTable/PersistentDataPanel.tsx @@ -64,7 +64,7 @@ export default function PersistentDataPanel({ - + diff --git a/packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentTable/PersistentTableData.tsx b/packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentTable/PersistentTableData.tsx index 7d1559f39e..e206efed6c 100644 --- a/packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentTable/PersistentTableData.tsx +++ b/packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentTable/PersistentTableData.tsx @@ -22,24 +22,34 @@ export default function PersistentTableData({ }); }; - const data = - persistentProp && persistentProp.length ? ( - persistentProp.map((item, i) => { - return ( - - {item} - handleClick(i)} style={{ maxWidth: "5vw", textAlign: "center" }}> - - - - ); - }) - ) : ( + const renderDeleteButton = (i: number) => { + return selection.selection === "search" || selection.selection === "fileHistory" ? ( + handleClick(i)} style={{ maxWidth: "20vw", textAlign: "center" }}> + + + ) : null; + }; + + const renderOptions = () => { + return persistentProp.map((item, i) => { + return ( + + {item} + {renderDeleteButton(i)} + + ); + }); + }; + + const renderNoRecordsFound = () => { + return ( No records found - ); + }; + + const data = persistentProp && persistentProp.length ? renderOptions() : renderNoRecordsFound(); return <>{data}; } diff --git a/packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentUtils/PersistentDropdownOptions.tsx b/packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentUtils/PersistentDropdownOptions.tsx index 604b883924..8f276528b0 100644 --- a/packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentUtils/PersistentDropdownOptions.tsx +++ b/packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentUtils/PersistentDropdownOptions.tsx @@ -1,14 +1,14 @@ import { VSCodeDropdown, VSCodeOption } from "@vscode/webview-ui-toolkit/react"; import { JSXInternal } from "preact/src/jsx"; -export default function PersistentDropdownOptions({ handleChange }: { handleChange: Function }): JSXInternal.Element { +export default function PersistentDropdownOptions({ handleChange, type }: { handleChange: Function; type: string }): JSXInternal.Element { const options = [ Search History, DS Templates, Favorites, File History, Sessions, - ]; + ].filter((option) => type === "ds" || option.props.value !== "dsTemplates"); return (
diff --git a/packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentUtils/PersistentUtilitiesBar.tsx b/packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentUtils/PersistentUtilitiesBar.tsx index 8f7f8cea48..f14e3f05cf 100644 --- a/packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentUtils/PersistentUtilitiesBar.tsx +++ b/packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentUtils/PersistentUtilitiesBar.tsx @@ -15,7 +15,7 @@ export default function PersistentUtilitiesBar({ }): JSXInternal.Element { return (
- + {selection.selection === "search" && type !== "jobs" ? : null} From 481a23f89c82fa2e9184b7affa82fbc0d8fbebd0 Mon Sep 17 00:00:00 2001 From: Trae Yelovich Date: Tue, 10 Oct 2023 18:29:04 -0400 Subject: [PATCH 112/189] fix(ds): Add sort/filter support for FTP response; fix test cases Signed-off-by: Trae Yelovich --- .../__unit__/dataset/DatasetTree.unit.test.ts | 351 ++++++++---------- .../src/dataset/ZoweDatasetNode.ts | 12 +- 2 files changed, 174 insertions(+), 189 deletions(-) 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 57b901c912..f8e6ddcc98 100644 --- a/packages/zowe-explorer/__tests__/__unit__/dataset/DatasetTree.unit.test.ts +++ b/packages/zowe-explorer/__tests__/__unit__/dataset/DatasetTree.unit.test.ts @@ -2696,36 +2696,34 @@ describe("Dataset Tree Unit Tests - Function initializeFavorites", () => { expect(() => testTree.initializeFavorites(log)).not.toThrow(); }); }); +describe("Dataset Tree Unit Tests - Sorting and Filtering operations", () => { + const tree = new DatasetTree(); + const nodesForSuite = (): Record => { + const session = new ZoweDatasetNode("testSession", vscode.TreeItemCollapsibleState.Collapsed, null, createISession()); + session.contextValue = globals.DS_SESSION_CONTEXT; + const pds = new ZoweDatasetNode("testPds", vscode.TreeItemCollapsibleState.Collapsed, session, createISession()); + pds.contextValue = globals.DS_PDS_CONTEXT; + + const nodeA = new ZoweDatasetNode("A", vscode.TreeItemCollapsibleState.Collapsed, pds, createISession()); + nodeA.stats = { user: "someUser", m4date: new Date() }; + const nodeB = new ZoweDatasetNode("B", vscode.TreeItemCollapsibleState.Collapsed, pds, createISession()); + nodeB.stats = { user: "anotherUser", m4date: new Date("2022-01-01T12:00:00") }; + const nodeC = new ZoweDatasetNode("C", vscode.TreeItemCollapsibleState.Collapsed, pds, createISession()); + nodeC.stats = { user: "someUser", m4date: new Date("2022-03-15T16:30:00") }; + pds.children = [nodeA, nodeB, nodeC]; + session.children = [pds]; + + return { + session, + pds, + }; + }; -describe("Dataset Tree Unit Tests - Function sortPdsMembersDialog", () => { - const testTree = new DatasetTree(); const getBlockMocks = (): Record => ({ nodeDataChanged: jest.spyOn(DatasetTree.prototype, "nodeDataChanged"), refreshElement: jest.spyOn(DatasetTree.prototype, "refreshElement"), showQuickPick: jest.spyOn(Gui, "showQuickPick"), - getParent: jest.spyOn(ZoweDatasetNode.prototype, "getParent"), - }); - const testSession = new ZoweDatasetNode("testSession", vscode.TreeItemCollapsibleState.Collapsed, null, createISession()); - const testPds = new ZoweDatasetNode("testPds", vscode.TreeItemCollapsibleState.Collapsed, testSession, createISession()); - testPds.contextValue = globals.DS_PDS_CONTEXT; - - beforeEach(() => { - const mocks = getBlockMocks(); - mocks.getParent.mockReturnValue(testSession); - testPds.children = [ - { label: "A", stats: { user: "someUser", m4date: Date.now() }, getParent: mocks.getParent } as unknown as ZoweDatasetNode, - { - label: "B", - stats: { user: "anotherUser", m4date: Date.parse("2022-01-01T12:00:00") }, - getParent: mocks.getParent, - } as unknown as ZoweDatasetNode, - { - label: "C", - stats: { user: "someUser", m4date: Date.parse("2022-03-15T16:30:00") }, - getParent: mocks.getParent, - } as unknown as ZoweDatasetNode, - ]; - testSession.children = [testPds]; + showInputBox: jest.spyOn(Gui, "showInputBox"), }); afterEach(() => { @@ -2742,180 +2740,161 @@ describe("Dataset Tree Unit Tests - Function sortPdsMembersDialog", () => { } }); - // for sorting, we shouldn't need to refresh since all nodes - // should be intact, just in a different order - it("does nothing if no children exist", async () => { - const mocks = getBlockMocks(); - // case 1: called on PDS node - mocks.showQuickPick.mockResolvedValueOnce({ label: "$(case-sensitive) Name (default)" }); - testPds.children = []; - await testTree.sortPdsMembersDialog(testPds); - expect(mocks.nodeDataChanged).not.toHaveBeenCalled(); - - // case 2: called on session node - mocks.showQuickPick.mockResolvedValueOnce({ label: "$(case-sensitive) Name (default)" }); - testSession.children = []; - await testTree.sortPdsMembersDialog(testSession); - expect(mocks.nodeDataChanged).not.toHaveBeenCalled(); - }); - - it("sorts by name", async () => { - const mocks = getBlockMocks(); - mocks.showQuickPick.mockResolvedValueOnce({ label: "$(case-sensitive) Name (default)" }); - await testTree.sortPdsMembersDialog(testPds); - expect(mocks.nodeDataChanged).toHaveBeenCalled(); - expect(mocks.refreshElement).not.toHaveBeenCalled(); - expect(testPds.children.map((c: IZoweDatasetTreeNode) => c.label)).toStrictEqual(["A", "B", "C"]); - }); - - it("sorts by last modified date", async () => { - const mocks = getBlockMocks(); - mocks.showQuickPick.mockResolvedValueOnce({ label: "$(calendar) Date Modified" }); - await testTree.sortPdsMembersDialog(testPds); - expect(mocks.nodeDataChanged).toHaveBeenCalled(); - expect(mocks.refreshElement).not.toHaveBeenCalled(); - expect(testPds.children.map((c: IZoweDatasetTreeNode) => c.label)).toStrictEqual(["B", "C", "A"]); - }); - - it("sorts by user ID", async () => { - const mocks = getBlockMocks(); - mocks.showQuickPick.mockResolvedValueOnce({ label: "$(account) User ID" }); - await testTree.sortPdsMembersDialog(testPds); - expect(mocks.nodeDataChanged).toHaveBeenCalled(); - expect(mocks.refreshElement).not.toHaveBeenCalled(); - expect(testPds.children.map((c: IZoweDatasetTreeNode) => c.label)).toStrictEqual(["B", "A", "C"]); - }); + describe("sortBy & sortPdsMembersDialog", () => { + // for sorting, we shouldn't need to refresh since all nodes + // should be intact, just in a different order + it("does nothing if no children exist", async () => { + const mocks = getBlockMocks(); + const nodes = nodesForSuite(); + // case 1: called on PDS node + mocks.showQuickPick.mockResolvedValueOnce({ label: "$(case-sensitive) Name (default)" }); + nodes.pds.children = []; + await tree.sortPdsMembersDialog(nodes.pds); + expect(mocks.nodeDataChanged).not.toHaveBeenCalled(); + + // case 2: called on session node + mocks.showQuickPick.mockResolvedValueOnce({ label: "$(case-sensitive) Name (default)" }); + nodes.session.children = []; + await tree.sortPdsMembersDialog(nodes.session); + expect(mocks.nodeDataChanged).not.toHaveBeenCalled(); + }); - it("returns to sort selection dialog when sort direction selection is canceled", async () => { - const sortPdsMembersDialog = jest.spyOn(testTree, "sortPdsMembersDialog"); - const mocks = getBlockMocks(); - mocks.showQuickPick.mockResolvedValueOnce({ label: "$(fold) Sort Direction" }); - mocks.showQuickPick.mockResolvedValueOnce(undefined); - await testTree.sortPdsMembersDialog(testPds); - expect(mocks.nodeDataChanged).not.toHaveBeenCalled(); - expect(mocks.refreshElement).not.toHaveBeenCalled(); - expect(sortPdsMembersDialog).toHaveBeenCalledTimes(2); - }); -}); + it("sorts by name", async () => { + const mocks = getBlockMocks(); + const nodes = nodesForSuite(); + mocks.showQuickPick.mockResolvedValueOnce({ label: "$(case-sensitive) Name (default)" }); + await tree.sortPdsMembersDialog(nodes.pds); + expect(mocks.nodeDataChanged).toHaveBeenCalled(); + expect(mocks.refreshElement).not.toHaveBeenCalled(); + expect(nodes.pds.children?.map((c: IZoweDatasetTreeNode) => c.label)).toStrictEqual(["A", "B", "C"]); + }); -describe("Dataset Tree Unit Tests - Function filterPdsMembersDialog", () => { - const testTree = new DatasetTree(); - const getBlockMocks = (): Record => ({ - nodeDataChanged: jest.spyOn(DatasetTree.prototype, "nodeDataChanged"), - refreshElement: jest.spyOn(DatasetTree.prototype, "refreshElement"), - showQuickPick: jest.spyOn(Gui, "showQuickPick"), - getParent: jest.spyOn(ZoweDatasetNode.prototype, "getParent"), - showInputBox: jest.spyOn(Gui, "showInputBox"), - }); - const testSession = new ZoweDatasetNode("testSession", vscode.TreeItemCollapsibleState.Collapsed, null, createISession()); - const testPds = new ZoweDatasetNode("testPds", vscode.TreeItemCollapsibleState.Collapsed, testSession, createISession()); - testPds.contextValue = globals.DS_PDS_CONTEXT; + it("sorts by last modified date", async () => { + const mocks = getBlockMocks(); + const nodes = nodesForSuite(); + mocks.showQuickPick.mockResolvedValueOnce({ label: "$(calendar) Date Modified" }); + await tree.sortPdsMembersDialog(nodes.pds); + expect(mocks.nodeDataChanged).toHaveBeenCalled(); + expect(mocks.refreshElement).not.toHaveBeenCalled(); + expect(nodes.pds.children?.map((c: IZoweDatasetTreeNode) => c.label)).toStrictEqual(["B", "C", "A"]); + }); - beforeEach(() => { - const mocks = getBlockMocks(); - mocks.getParent.mockReturnValue(testSession); - testPds.children = [ - { label: "A", stats: { user: "someUser", m4date: Date.now() }, getParent: mocks.getParent } as unknown as ZoweDatasetNode, - { - label: "B", - stats: { user: "anotherUser", m4date: Date.parse("2022-01-01T12:00:00") }, - getParent: mocks.getParent, - } as unknown as ZoweDatasetNode, - { - label: "C", - stats: { user: "someUser", m4date: Date.parse("2022-03-15T16:30:00") }, - getParent: mocks.getParent, - } as unknown as ZoweDatasetNode, - ]; - testSession.children = [testPds]; - testPds.filter = undefined as any; - }); + it("sorts by user ID", async () => { + const mocks = getBlockMocks(); + const nodes = nodesForSuite(); + mocks.showQuickPick.mockResolvedValueOnce({ label: "$(account) User ID" }); + await tree.sortPdsMembersDialog(nodes.pds); + expect(mocks.nodeDataChanged).toHaveBeenCalled(); + expect(mocks.refreshElement).not.toHaveBeenCalled(); + expect(nodes.pds.children?.map((c: IZoweDatasetTreeNode) => c.label)).toStrictEqual(["B", "A", "C"]); + }); - afterEach(() => { - const mocks = getBlockMocks(); - for (const mock of Object.values(mocks)) { - mock.mockReset(); - } + it("returns to sort selection dialog when sort direction selection is canceled", async () => { + const sortPdsMembersDialog = jest.spyOn(tree, "sortPdsMembersDialog"); + const mocks = getBlockMocks(); + const nodes = nodesForSuite(); + mocks.showQuickPick.mockResolvedValueOnce({ label: "$(fold) Sort Direction" }); + mocks.showQuickPick.mockResolvedValueOnce(undefined); + await tree.sortPdsMembersDialog(nodes.pds); + expect(mocks.nodeDataChanged).not.toHaveBeenCalled(); + expect(mocks.refreshElement).not.toHaveBeenCalled(); + expect(sortPdsMembersDialog).toHaveBeenCalledTimes(2); + }); }); - afterAll(() => { - const mocks = getBlockMocks(); - for (const mock of Object.values(mocks)) { - mock.mockRestore(); - } - }); + describe("filterBy & filterPdsMembersDialog", () => { + afterEach(() => { + const mocks = getBlockMocks(); + for (const mock of Object.values(mocks)) { + mock.mockReset(); + } + }); - it("calls refreshElement if PDS children were removed from a previous filter", async () => { - const mocks = getBlockMocks(); - mocks.showQuickPick.mockResolvedValueOnce("$(calendar) Date Modified" as any); - mocks.showInputBox.mockResolvedValueOnce("2022-01-01"); + afterAll(() => { + const mocks = getBlockMocks(); + for (const mock of Object.values(mocks)) { + mock.mockRestore(); + } + }); - testPds.filter = { method: DatasetFilterOpts.UserId, value: "invalidUserId" }; - testPds.children = []; - await testTree.filterPdsMembersDialog(testPds); - expect(mocks.nodeDataChanged).not.toHaveBeenCalled(); - expect(mocks.refreshElement).toHaveBeenCalledWith(testPds); - }); + it("calls refreshElement if PDS children were removed from a previous filter", async () => { + const mocks = getBlockMocks(); + const nodes = nodesForSuite(); + mocks.showQuickPick.mockResolvedValueOnce("$(calendar) Date Modified" as any); + mocks.showInputBox.mockResolvedValueOnce("2022-01-01"); + + nodes.pds.filter = { method: DatasetFilterOpts.UserId, value: "invalidUserId" }; + nodes.pds.children = []; + await tree.filterPdsMembersDialog(nodes.pds); + expect(mocks.nodeDataChanged).not.toHaveBeenCalled(); + expect(mocks.refreshElement).toHaveBeenCalledWith(nodes.pds); + }); - it("returns to filter selection dialog when filter entry is canceled", async () => { - const filterPdsMembersSpy = jest.spyOn(testTree, "filterPdsMembersDialog"); - const mocks = getBlockMocks(); - mocks.showQuickPick.mockResolvedValueOnce("$(calendar) Date Modified" as any); - mocks.showInputBox.mockResolvedValueOnce(undefined); - await testTree.filterPdsMembersDialog(testPds); - expect(mocks.nodeDataChanged).not.toHaveBeenCalled(); - expect(mocks.refreshElement).not.toHaveBeenCalled(); - expect(filterPdsMembersSpy).toHaveBeenCalledTimes(2); - }); + it("returns to filter selection dialog when filter entry is canceled", async () => { + const filterPdsMembersSpy = jest.spyOn(tree, "filterPdsMembersDialog"); + const mocks = getBlockMocks(); + const nodes = nodesForSuite(); + mocks.showQuickPick.mockResolvedValueOnce("$(calendar) Date Modified" as any); + mocks.showInputBox.mockResolvedValueOnce(undefined); + await tree.filterPdsMembersDialog(nodes.pds); + expect(mocks.nodeDataChanged).not.toHaveBeenCalled(); + expect(mocks.refreshElement).not.toHaveBeenCalled(); + expect(filterPdsMembersSpy).toHaveBeenCalledTimes(2); + }); - it("filters single PDS by last modified date", async () => { - const mocks = getBlockMocks(); - mocks.showQuickPick.mockResolvedValueOnce("$(calendar) Date Modified" as any); - mocks.showInputBox.mockResolvedValueOnce("2022-03-15"); - await testTree.filterPdsMembersDialog(testPds); - expect(mocks.nodeDataChanged).toHaveBeenCalled(); - expect(mocks.refreshElement).not.toHaveBeenCalled(); - expect(testPds.children.map((c: IZoweDatasetTreeNode) => c.label)).toStrictEqual(["C"]); - }); + it("filters single PDS by last modified date", async () => { + const mocks = getBlockMocks(); + const nodes = nodesForSuite(); + mocks.showQuickPick.mockResolvedValueOnce("$(calendar) Date Modified" as any); + mocks.showInputBox.mockResolvedValueOnce("2022-03-15"); + await tree.filterPdsMembersDialog(nodes.pds); + expect(mocks.nodeDataChanged).toHaveBeenCalled(); + expect(mocks.refreshElement).not.toHaveBeenCalled(); + expect(nodes.pds.children?.map((c: IZoweDatasetTreeNode) => c.label)).toStrictEqual(["C"]); + }); - it("filters single PDS by user ID", async () => { - const mocks = getBlockMocks(); - mocks.showQuickPick.mockResolvedValueOnce("$(account) User ID" as any); - mocks.showInputBox.mockResolvedValueOnce("anotherUser"); - await testTree.filterPdsMembersDialog(testPds); - expect(mocks.nodeDataChanged).toHaveBeenCalled(); - expect(mocks.refreshElement).not.toHaveBeenCalled(); - expect(testPds.children.map((c: IZoweDatasetTreeNode) => c.label)).toStrictEqual(["B"]); - }); + it("filters single PDS by user ID", async () => { + const mocks = getBlockMocks(); + const nodes = nodesForSuite(); + mocks.showQuickPick.mockResolvedValueOnce("$(account) User ID" as any); + mocks.showInputBox.mockResolvedValueOnce("anotherUser"); + await tree.filterPdsMembersDialog(nodes.pds); + expect(mocks.nodeDataChanged).toHaveBeenCalled(); + expect(mocks.refreshElement).not.toHaveBeenCalled(); + expect(nodes.pds.children?.map((c: IZoweDatasetTreeNode) => c.label)).toStrictEqual(["B"]); + }); - it("filters PDS members using the session node filter", async () => { - const mocks = getBlockMocks(); - const uidString = "$(account) User ID" as any; - const anotherUser = "anotherUser"; - mocks.showQuickPick.mockResolvedValueOnce(uidString).mockResolvedValueOnce(uidString); - mocks.showInputBox.mockResolvedValueOnce(anotherUser).mockResolvedValueOnce(anotherUser); - - // case 1: old filter was set on session, just refresh PDS to use new filter - testSession.filter = { - method: DatasetFilterOpts.LastModified, - value: "2020-01-01", - }; - await testTree.filterPdsMembersDialog(testSession); - expect(mocks.refreshElement).toHaveBeenCalled(); + it("filters PDS members using the session node filter", async () => { + const mocks = getBlockMocks(); + const nodes = nodesForSuite(); + const uidString = "$(account) User ID" as any; + const anotherUser = "anotherUser"; + mocks.showQuickPick.mockResolvedValueOnce(uidString).mockResolvedValueOnce(uidString); + mocks.showInputBox.mockResolvedValueOnce(anotherUser).mockResolvedValueOnce(anotherUser); + + // case 1: old filter was set on session, just refresh PDS to use new filter + nodes.session.filter = { + method: DatasetFilterOpts.LastModified, + value: "2020-01-01", + }; + await tree.filterPdsMembersDialog(nodes.session); + expect(mocks.refreshElement).toHaveBeenCalled(); - // case 2: no old filter present, PDS has children to be filtered - testSession.filter = undefined; - await testTree.filterPdsMembersDialog(testSession); - expect(mocks.nodeDataChanged).toHaveBeenCalled(); - }); + // case 2: no old filter present, PDS has children to be filtered + nodes.session.filter = undefined; + await tree.filterPdsMembersDialog(nodes.session); + expect(mocks.nodeDataChanged).toHaveBeenCalled(); + }); - it("clears filter for a PDS when selected in dialog", async () => { - const mocks = getBlockMocks(); - const resp = "$(clear-all) Clear filter for PDS" as any; - mocks.showQuickPick.mockResolvedValueOnce(resp); - const updateFilterForNode = jest.spyOn(DatasetTree.prototype, "updateFilterForNode"); - await testTree.filterPdsMembersDialog(testPds); - expect(mocks.refreshElement).not.toHaveBeenCalled(); - expect(updateFilterForNode).toHaveBeenCalledWith(testPds, null, false); + it("clears filter for a PDS when selected in dialog", async () => { + const mocks = getBlockMocks(); + const nodes = nodesForSuite(); + const resp = "$(clear-all) Clear filter for PDS" as any; + mocks.showQuickPick.mockResolvedValueOnce(resp); + const updateFilterForNode = jest.spyOn(DatasetTree.prototype, "updateFilterForNode"); + await tree.filterPdsMembersDialog(nodes.pds); + expect(mocks.refreshElement).not.toHaveBeenCalled(); + expect(updateFilterForNode).toHaveBeenCalledWith(nodes.pds, null, false); + }); }); }); diff --git a/packages/zowe-explorer/src/dataset/ZoweDatasetNode.ts b/packages/zowe-explorer/src/dataset/ZoweDatasetNode.ts index 9b83a8915d..fdd90426b4 100644 --- a/packages/zowe-explorer/src/dataset/ZoweDatasetNode.ts +++ b/packages/zowe-explorer/src/dataset/ZoweDatasetNode.ts @@ -262,11 +262,17 @@ export class ZoweDatasetNode extends ZoweTreeNode implements IZoweDatasetTreeNod } // get user and last modified date for sorting, if available - const { m4date, mtime, msec }: { m4date: string; mtime: string; msec: string } = item; - if (m4date) { + if ("m4date" in item) { + const { m4date, mtime, msec }: { m4date: string; mtime: string; msec: string } = item; temp.stats = { user: item.user, - m4date: new Date(`${m4date.replace(/\//g, "-")}T${mtime}:${msec}`), + m4date: dayjs(`${m4date} ${mtime}:${msec}`).toDate(), + }; + } else if ("id" in item || "changed" in item) { + // missing keys from API response; check for FTP keys + temp.stats = { + user: item.id, + m4date: item.changed ? dayjs(item.changed).toDate() : null, }; } elementChildren[temp.label.toString()] = temp; From e70c83a91037a078682e5333830936ca10ff6bc6 Mon Sep 17 00:00:00 2001 From: Rudy Flores <68666202+rudyflores@users.noreply.github.com> Date: Wed, 11 Oct 2023 10:02:06 -0400 Subject: [PATCH 113/189] UI icons update for buttons Signed-off-by: Rudy Flores <68666202+rudyflores@users.noreply.github.com> --- packages/zowe-explorer/src/shared/HistoryView.ts | 4 ++++ .../webviews/src/edit-history/assets/clear-all.svg | 7 +++++++ .../src/webviews/src/edit-history/assets/plus.svg | 1 + .../webviews/src/edit-history/assets/refresh.svg | 1 + .../PersistentAddNewHistoryItemButton.tsx | 4 ++-- .../PersistentUtils/PersistentClearAllButton.tsx | 4 ++-- .../PersistentUtils/PersistentRefreshButton.tsx | 4 ++-- .../PersistentUtils/PersistentUtilitiesBar.tsx | 14 ++++++++++++-- 8 files changed, 31 insertions(+), 8 deletions(-) create mode 100644 packages/zowe-explorer/src/webviews/src/edit-history/assets/clear-all.svg create mode 100644 packages/zowe-explorer/src/webviews/src/edit-history/assets/plus.svg create mode 100644 packages/zowe-explorer/src/webviews/src/edit-history/assets/refresh.svg diff --git a/packages/zowe-explorer/src/shared/HistoryView.ts b/packages/zowe-explorer/src/shared/HistoryView.ts index 7c72ce68c1..0656636b0a 100644 --- a/packages/zowe-explorer/src/shared/HistoryView.ts +++ b/packages/zowe-explorer/src/shared/HistoryView.ts @@ -101,9 +101,13 @@ export class HistoryView extends WebView { private async addItem(message): Promise { ZoweLogger.trace("HistoryView.addItem called."); + + const example = message.attrs.type === "ds" ? "e.g: USER.PDS.*" : "e.g: /u/user/mydir"; + const options: vscode.InputBoxOptions = { prompt: localize("HistoryView.addItem.prompt", "Type the new pattern to add to history"), value: "", + placeHolder: example, }; const item = await Gui.showInputBox(options); const treeProvider = this.getTreeProvider(message.attrs.type); diff --git a/packages/zowe-explorer/src/webviews/src/edit-history/assets/clear-all.svg b/packages/zowe-explorer/src/webviews/src/edit-history/assets/clear-all.svg new file mode 100644 index 0000000000..24571c077f --- /dev/null +++ b/packages/zowe-explorer/src/webviews/src/edit-history/assets/clear-all.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/packages/zowe-explorer/src/webviews/src/edit-history/assets/plus.svg b/packages/zowe-explorer/src/webviews/src/edit-history/assets/plus.svg new file mode 100644 index 0000000000..2f8606ea31 --- /dev/null +++ b/packages/zowe-explorer/src/webviews/src/edit-history/assets/plus.svg @@ -0,0 +1 @@ + diff --git a/packages/zowe-explorer/src/webviews/src/edit-history/assets/refresh.svg b/packages/zowe-explorer/src/webviews/src/edit-history/assets/refresh.svg new file mode 100644 index 0000000000..d79fdaa4e8 --- /dev/null +++ b/packages/zowe-explorer/src/webviews/src/edit-history/assets/refresh.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentUtils/PersistentAddNewHistoryItemButton.tsx b/packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentUtils/PersistentAddNewHistoryItemButton.tsx index 99d938143c..dad1c9d489 100644 --- a/packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentUtils/PersistentAddNewHistoryItemButton.tsx +++ b/packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentUtils/PersistentAddNewHistoryItemButton.tsx @@ -13,8 +13,8 @@ export default function PersistentAddNewHistoryItemButton({ type }: { type: stri }; return ( - - Add Item + + ); } diff --git a/packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentUtils/PersistentClearAllButton.tsx b/packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentUtils/PersistentClearAllButton.tsx index 61295748f8..5ef15ce78c 100644 --- a/packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentUtils/PersistentClearAllButton.tsx +++ b/packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentUtils/PersistentClearAllButton.tsx @@ -14,8 +14,8 @@ export default function PersistentClearAllButton({ type, selection }: { type: st }; return ( - - Clear All + + ); } diff --git a/packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentUtils/PersistentRefreshButton.tsx b/packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentUtils/PersistentRefreshButton.tsx index 52ce61721f..94b0cecddf 100644 --- a/packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentUtils/PersistentRefreshButton.tsx +++ b/packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentUtils/PersistentRefreshButton.tsx @@ -13,8 +13,8 @@ export default function PersistentRefreshButton({ type }: { type: string }): JSX }; return ( - - Refresh + + ); } diff --git a/packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentUtils/PersistentUtilitiesBar.tsx b/packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentUtils/PersistentUtilitiesBar.tsx index f14e3f05cf..2ef9a1eb4c 100644 --- a/packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentUtils/PersistentUtilitiesBar.tsx +++ b/packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentUtils/PersistentUtilitiesBar.tsx @@ -13,12 +13,22 @@ export default function PersistentUtilitiesBar({ handleChange: Function; selection: { selection: string }; }): JSXInternal.Element { + const renderAddItemButton = () => { + return selection.selection === "search" && type !== "jobs" ? : null; + }; + + const renderClearAllButton = () => { + return selection.selection === "search" || selection.selection === "fileHistory" ? ( + + ) : null; + }; + return (
- {selection.selection === "search" && type !== "jobs" ? : null} - + {renderClearAllButton()} + {renderAddItemButton()}
); } From 9df717a53b863b353800fd14e508701c539fc121 Mon Sep 17 00:00:00 2001 From: Rudy Flores <68666202+rudyflores@users.noreply.github.com> Date: Wed, 11 Oct 2023 10:45:40 -0400 Subject: [PATCH 114/189] independent selection states for each tab Signed-off-by: Rudy Flores <68666202+rudyflores@users.noreply.github.com> --- .../zowe-explorer/src/shared/HistoryView.ts | 5 ++-- .../src/webviews/src/edit-history/App.tsx | 9 ++++--- .../PersistentDataGridHeaders.tsx | 4 ++-- .../PersistentTable/PersistentDataPanel.tsx | 24 +++++++++---------- .../PersistentTable/PersistentTableData.tsx | 6 ++--- .../PersistentClearAllButton.tsx | 4 ++-- .../PersistentUtilitiesBar.tsx | 8 +++---- 7 files changed, 28 insertions(+), 32 deletions(-) diff --git a/packages/zowe-explorer/src/shared/HistoryView.ts b/packages/zowe-explorer/src/shared/HistoryView.ts index 0656636b0a..ce8428a0c0 100644 --- a/packages/zowe-explorer/src/shared/HistoryView.ts +++ b/packages/zowe-explorer/src/shared/HistoryView.ts @@ -40,12 +40,13 @@ const tabs = { export class HistoryView extends WebView { private treeProviders: IZoweProviders; private currentTab: string; - private currentSelection; + private currentSelection: { [type: string]: string }; public constructor(context: ExtensionContext, treeProviders: IZoweProviders) { const label = "Edit History"; super(label, "edit-history", context, (message: object) => this.onDidReceiveMessage(message)); this.treeProviders = treeProviders; + // this.currentSelection = { ds: "search", uss: "search", jobs: "search" }; } protected async onDidReceiveMessage(message: any): Promise { @@ -96,7 +97,7 @@ export class HistoryView extends WebView { private updateSelection(message): void { ZoweLogger.trace("HistoryView.updateSelection called."); - this.currentSelection = message.attrs.selection; + this.currentSelection[message.attrs.type] = message.attrs.selection; } private async addItem(message): Promise { diff --git a/packages/zowe-explorer/src/webviews/src/edit-history/App.tsx b/packages/zowe-explorer/src/webviews/src/edit-history/App.tsx index b70504bdec..f182ca6551 100644 --- a/packages/zowe-explorer/src/webviews/src/edit-history/App.tsx +++ b/packages/zowe-explorer/src/webviews/src/edit-history/App.tsx @@ -8,7 +8,6 @@ import PersistentManagerHeader from "./components/PersistentManagerHeader/Persis export function App(): JSXInternal.Element { const [timestamp, setTimestamp] = useState(); const [currentTab, setCurrentTab] = useState<{ [key: string]: string }>({}); - const [data, setData] = useState<{ [type: string]: { [property: string]: string[] } }>({ ds: {}, uss: {}, jobs: {} }); useEffect(() => { window.addEventListener("message", (event) => { @@ -21,7 +20,7 @@ export function App(): JSXInternal.Element { if (!isWebUser && !isLocalVSCodeUser) { return; } - setData(event.data); + if ("tab" in event.data) { setCurrentTab(() => ({ tab: event.data.tab, @@ -46,9 +45,9 @@ export function App(): JSXInternal.Element {

Jobs

- - - + + +
); diff --git a/packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentTable/PersistentDataGridHeaders.tsx b/packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentTable/PersistentDataGridHeaders.tsx index 0eeaf2a463..abe6003a00 100644 --- a/packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentTable/PersistentDataGridHeaders.tsx +++ b/packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentTable/PersistentDataGridHeaders.tsx @@ -1,9 +1,9 @@ import { VSCodeDataGridRow, VSCodeDataGridCell } from "@vscode/webview-ui-toolkit/react"; import { JSXInternal } from "preact/src/jsx"; -export default function PersistentDataGridHeaders({ selection }: { selection: { selection: string } }): JSXInternal.Element { +export default function PersistentDataGridHeaders({ selection, type }: { selection: { [type: string]: string }; type: string }): JSXInternal.Element { const renderDeleteHeader = () => { - return selection.selection === "search" || selection.selection === "fileHistory" ? ( + return selection[type] === "search" || selection[type] === "fileHistory" ? ( Delete diff --git a/packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentTable/PersistentDataPanel.tsx b/packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentTable/PersistentDataPanel.tsx index 102c9ba9f3..fe61c82f7c 100644 --- a/packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentTable/PersistentDataPanel.tsx +++ b/packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentTable/PersistentDataPanel.tsx @@ -6,28 +6,24 @@ import PersistentTableData from "./PersistentTableData"; import PersistentDataGridHeaders from "./PersistentDataGridHeaders"; import PersistentVSCodeAPI from "../PersistentVSCodeAPI"; -export default function PersistentDataPanel({ - data, - type, -}: { - data: { [type: string]: { [property: string]: string[] } }; - type: string; -}): JSXInternal.Element { +export default function PersistentDataPanel({ type }: { type: string }): JSXInternal.Element { const panelId: { [key: string]: string } = { ds: "ds-panel-view", uss: "uss-panel-view", jobs: "jobs-panel-view", }; - const [selection, setSelection] = useState<{ selection: string }>({ selection: "search" }); + const [data, setData] = useState<{ [type: string]: { [property: string]: string[] } }>({ ds: {}, uss: {}, jobs: {} }); + const [selection, setSelection] = useState<{ [type: string]: string }>({ [type]: "search" }); const [persistentProp, setPersistentProp] = useState([]); const handleChange = (newSelection: string) => { - setSelection(() => ({ selection: newSelection })); + setSelection(() => ({ [type]: newSelection })); PersistentVSCodeAPI.getVSCodeAPI().postMessage({ command: "update-selection", attrs: { selection: newSelection, + type, }, }); }; @@ -44,27 +40,29 @@ export default function PersistentDataPanel({ return; } + setData(event.data); + if ("selection" in event.data) { setSelection(() => ({ - selection: event.data.selection, + [type]: event.data.selection[type], })); } }); }, []); useEffect(() => { - setPersistentProp(() => data[type][selection.selection]); + setPersistentProp(() => data[type][selection[type]]); }, [data]); useEffect(() => { - setPersistentProp(() => data[type][selection.selection]); + setPersistentProp(() => data[type][selection[type]]); }, [selection]); return ( - + diff --git a/packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentTable/PersistentTableData.tsx b/packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentTable/PersistentTableData.tsx index e206efed6c..105f5a09e0 100644 --- a/packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentTable/PersistentTableData.tsx +++ b/packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentTable/PersistentTableData.tsx @@ -9,7 +9,7 @@ export default function PersistentTableData({ }: { type: string; persistentProp: string[]; - selection: { selection: string }; + selection: { [type: string]: string }; }): JSXInternal.Element { const handleClick = (item: number) => { PersistentVSCodeAPI.getVSCodeAPI().postMessage({ @@ -17,13 +17,13 @@ export default function PersistentTableData({ attrs: { name: persistentProp[item], type, - selection: selection.selection, + selection: selection[type], }, }); }; const renderDeleteButton = (i: number) => { - return selection.selection === "search" || selection.selection === "fileHistory" ? ( + return selection[type] === "search" || selection[type] === "fileHistory" ? ( handleClick(i)} style={{ maxWidth: "20vw", textAlign: "center" }}> diff --git a/packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentUtils/PersistentClearAllButton.tsx b/packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentUtils/PersistentClearAllButton.tsx index 5ef15ce78c..67ca278af6 100644 --- a/packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentUtils/PersistentClearAllButton.tsx +++ b/packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentUtils/PersistentClearAllButton.tsx @@ -2,13 +2,13 @@ import { VSCodeButton } from "@vscode/webview-ui-toolkit/react"; import { JSXInternal } from "preact/src/jsx"; import PersistentVSCodeAPI from "../PersistentVSCodeAPI"; -export default function PersistentClearAllButton({ type, selection }: { type: string; selection: { selection: string } }): JSXInternal.Element { +export default function PersistentClearAllButton({ type, selection }: { type: string; selection: { [type: string]: string } }): JSXInternal.Element { const handleClick = () => { PersistentVSCodeAPI.getVSCodeAPI().postMessage({ command: "clear-all", attrs: { type, - selection: selection.selection, + selection: selection[type], }, }); }; diff --git a/packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentUtils/PersistentUtilitiesBar.tsx b/packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentUtils/PersistentUtilitiesBar.tsx index 2ef9a1eb4c..717ac2bb9f 100644 --- a/packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentUtils/PersistentUtilitiesBar.tsx +++ b/packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentUtils/PersistentUtilitiesBar.tsx @@ -11,16 +11,14 @@ export default function PersistentUtilitiesBar({ }: { type: string; handleChange: Function; - selection: { selection: string }; + selection: { [type: string]: string }; }): JSXInternal.Element { const renderAddItemButton = () => { - return selection.selection === "search" && type !== "jobs" ? : null; + return selection[type] === "search" && type !== "jobs" ? : null; }; const renderClearAllButton = () => { - return selection.selection === "search" || selection.selection === "fileHistory" ? ( - - ) : null; + return selection[type] === "search" || selection[type] === "fileHistory" ? : null; }; return ( From 2cfcb59b5e6daa65d83f0584b4650ef0c1cff84a Mon Sep 17 00:00:00 2001 From: Rudy Flores <68666202+rudyflores@users.noreply.github.com> Date: Wed, 11 Oct 2023 11:17:15 -0400 Subject: [PATCH 115/189] add option for retaining context on focus loss Signed-off-by: Rudy Flores <68666202+rudyflores@users.noreply.github.com> --- .../src/vscode/ui/WebView.ts | 4 +++- .../zowe-explorer/src/shared/HistoryView.ts | 4 ++-- .../src/webviews/src/edit-history/App.tsx | 10 ++------ .../PersistentManagerHeader.tsx | 8 ++++--- .../PersistentTable/PersistentDataPanel.tsx | 13 ++++------ .../PersistentAddNewHistoryItemButton.tsx | 0 .../PersistentClearAllButton.tsx | 0 .../PersistentDropdownOptions.tsx | 5 ++++ .../PersistentRefreshButton.tsx | 0 .../PersistentToolBar.tsx} | 2 +- .../components/PersistentUtils.ts | 24 +++++++++++++++++++ .../components/PersistentVSCodeAPI.ts | 11 +++++++++ 12 files changed, 57 insertions(+), 24 deletions(-) rename packages/zowe-explorer/src/webviews/src/edit-history/components/{PersistentUtils => PersistentToolBar}/PersistentAddNewHistoryItemButton.tsx (100%) rename packages/zowe-explorer/src/webviews/src/edit-history/components/{PersistentUtils => PersistentToolBar}/PersistentClearAllButton.tsx (100%) rename packages/zowe-explorer/src/webviews/src/edit-history/components/{PersistentUtils => PersistentToolBar}/PersistentDropdownOptions.tsx (91%) rename packages/zowe-explorer/src/webviews/src/edit-history/components/{PersistentUtils => PersistentToolBar}/PersistentRefreshButton.tsx (100%) rename packages/zowe-explorer/src/webviews/src/edit-history/components/{PersistentUtils/PersistentUtilitiesBar.tsx => PersistentToolBar/PersistentToolBar.tsx} (95%) create mode 100644 packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentUtils.ts diff --git a/packages/zowe-explorer-api/src/vscode/ui/WebView.ts b/packages/zowe-explorer-api/src/vscode/ui/WebView.ts index 558ab3d3c5..a0f18ba622 100644 --- a/packages/zowe-explorer-api/src/vscode/ui/WebView.ts +++ b/packages/zowe-explorer-api/src/vscode/ui/WebView.ts @@ -47,7 +47,8 @@ export class WebView { title: string, webviewName: string, context: ExtensionContext, - onDidReceiveMessage?: (message: object) => void | Promise + onDidReceiveMessage?: (message: object) => void | Promise, + retainContext?: boolean ) { this.disposables = []; @@ -64,6 +65,7 @@ export class WebView { this.panel = window.createWebviewPanel("ZEAPIWebview", this.title, ViewColumn.Beside, { enableScripts: true, localResourceRoots: [this.uris.disk.build], + retainContextWhenHidden: retainContext ?? false, }); // Associate URI resources with webview diff --git a/packages/zowe-explorer/src/shared/HistoryView.ts b/packages/zowe-explorer/src/shared/HistoryView.ts index ce8428a0c0..337c28963a 100644 --- a/packages/zowe-explorer/src/shared/HistoryView.ts +++ b/packages/zowe-explorer/src/shared/HistoryView.ts @@ -44,9 +44,9 @@ export class HistoryView extends WebView { public constructor(context: ExtensionContext, treeProviders: IZoweProviders) { const label = "Edit History"; - super(label, "edit-history", context, (message: object) => this.onDidReceiveMessage(message)); + super(label, "edit-history", context, (message: object) => this.onDidReceiveMessage(message), true); this.treeProviders = treeProviders; - // this.currentSelection = { ds: "search", uss: "search", jobs: "search" }; + this.currentSelection = { ds: "search", uss: "search", jobs: "search" }; } protected async onDidReceiveMessage(message: any): Promise { diff --git a/packages/zowe-explorer/src/webviews/src/edit-history/App.tsx b/packages/zowe-explorer/src/webviews/src/edit-history/App.tsx index f182ca6551..54337efe95 100644 --- a/packages/zowe-explorer/src/webviews/src/edit-history/App.tsx +++ b/packages/zowe-explorer/src/webviews/src/edit-history/App.tsx @@ -4,6 +4,7 @@ import { JSXInternal } from "preact/src/jsx"; import PersistentDataPanel from "./components/PersistentTable/PersistentDataPanel"; import PersistentVSCodeAPI from "./components/PersistentVSCodeAPI"; import PersistentManagerHeader from "./components/PersistentManagerHeader/PersistentManagerHeader"; +import { isSecureOrigin } from "./components/PersistentUtils"; export function App(): JSXInternal.Element { const [timestamp, setTimestamp] = useState(); @@ -11,16 +12,9 @@ export function App(): JSXInternal.Element { useEffect(() => { window.addEventListener("message", (event) => { - const eventUrl = new URL(event.origin); - const isWebUser = - (eventUrl.protocol === document.location.protocol && eventUrl.hostname === document.location.hostname) || - eventUrl.hostname.endsWith(".github.dev"); - const isLocalVSCodeUser = eventUrl.protocol === "vscode-webview:"; - - if (!isWebUser && !isLocalVSCodeUser) { + if (!isSecureOrigin(event.origin)) { return; } - if ("tab" in event.data) { setCurrentTab(() => ({ tab: event.data.tab, diff --git a/packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentManagerHeader/PersistentManagerHeader.tsx b/packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentManagerHeader/PersistentManagerHeader.tsx index e1b4548875..7ec82d98d5 100644 --- a/packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentManagerHeader/PersistentManagerHeader.tsx +++ b/packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentManagerHeader/PersistentManagerHeader.tsx @@ -1,12 +1,14 @@ import { JSXInternal } from "preact/src/jsx"; export default function PersistentManagerHeader({ timestamp }: { timestamp: Date | undefined }): JSXInternal.Element { + const renderTimestamp = () => { + return timestamp &&

Last refreshed: {timestamp.toLocaleString(navigator.language)}

; + }; + return (

Manage Persistent Properties

-
- {timestamp &&

Last refreshed: {timestamp.toLocaleString(navigator.language)}

} -
+
{renderTimestamp()}
); } diff --git a/packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentTable/PersistentDataPanel.tsx b/packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentTable/PersistentDataPanel.tsx index fe61c82f7c..0ebdcd8603 100644 --- a/packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentTable/PersistentDataPanel.tsx +++ b/packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentTable/PersistentDataPanel.tsx @@ -1,10 +1,11 @@ import { useEffect, useState } from "preact/hooks"; import { VSCodePanelView, VSCodeDataGrid } from "@vscode/webview-ui-toolkit/react"; import { JSXInternal } from "preact/src/jsx"; -import PersistentUtilitiesBar from "../PersistentUtils/PersistentUtilitiesBar"; +import PersistentToolBar from "../PersistentToolBar/PersistentToolBar"; import PersistentTableData from "./PersistentTableData"; import PersistentDataGridHeaders from "./PersistentDataGridHeaders"; import PersistentVSCodeAPI from "../PersistentVSCodeAPI"; +import { isSecureOrigin } from "../PersistentUtils"; export default function PersistentDataPanel({ type }: { type: string }): JSXInternal.Element { const panelId: { [key: string]: string } = { @@ -30,13 +31,7 @@ export default function PersistentDataPanel({ type }: { type: string }): JSXInte useEffect(() => { window.addEventListener("message", (event) => { - const eventUrl = new URL(event.origin); - const isWebUser = - (eventUrl.protocol === document.location.protocol && eventUrl.hostname === document.location.hostname) || - eventUrl.hostname.endsWith(".github.dev"); - const isLocalVSCodeUser = eventUrl.protocol === "vscode-webview:"; - - if (!isWebUser && !isLocalVSCodeUser) { + if (!isSecureOrigin(event.origin)) { return; } @@ -60,7 +55,7 @@ export default function PersistentDataPanel({ type }: { type: string }): JSXInte return ( - + diff --git a/packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentUtils/PersistentAddNewHistoryItemButton.tsx b/packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentToolBar/PersistentAddNewHistoryItemButton.tsx similarity index 100% rename from packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentUtils/PersistentAddNewHistoryItemButton.tsx rename to packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentToolBar/PersistentAddNewHistoryItemButton.tsx diff --git a/packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentUtils/PersistentClearAllButton.tsx b/packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentToolBar/PersistentClearAllButton.tsx similarity index 100% rename from packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentUtils/PersistentClearAllButton.tsx rename to packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentToolBar/PersistentClearAllButton.tsx diff --git a/packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentUtils/PersistentDropdownOptions.tsx b/packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentToolBar/PersistentDropdownOptions.tsx similarity index 91% rename from packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentUtils/PersistentDropdownOptions.tsx rename to packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentToolBar/PersistentDropdownOptions.tsx index 8f276528b0..fe2efd678a 100644 --- a/packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentUtils/PersistentDropdownOptions.tsx +++ b/packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentToolBar/PersistentDropdownOptions.tsx @@ -1,7 +1,12 @@ import { VSCodeDropdown, VSCodeOption } from "@vscode/webview-ui-toolkit/react"; +import { useEffect } from "preact/hooks"; import { JSXInternal } from "preact/src/jsx"; export default function PersistentDropdownOptions({ handleChange, type }: { handleChange: Function; type: string }): JSXInternal.Element { + useEffect(() => { + console.log("change"); + }); + const options = [ Search History, DS Templates, diff --git a/packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentUtils/PersistentRefreshButton.tsx b/packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentToolBar/PersistentRefreshButton.tsx similarity index 100% rename from packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentUtils/PersistentRefreshButton.tsx rename to packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentToolBar/PersistentRefreshButton.tsx diff --git a/packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentUtils/PersistentUtilitiesBar.tsx b/packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentToolBar/PersistentToolBar.tsx similarity index 95% rename from packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentUtils/PersistentUtilitiesBar.tsx rename to packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentToolBar/PersistentToolBar.tsx index 717ac2bb9f..a2b438d21c 100644 --- a/packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentUtils/PersistentUtilitiesBar.tsx +++ b/packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentToolBar/PersistentToolBar.tsx @@ -4,7 +4,7 @@ import PersistentRefreshButton from "./PersistentRefreshButton"; import PersistentDropdownOptions from "./PersistentDropdownOptions"; import PersistentAddNewHistoryItemButton from "./PersistentAddNewHistoryItemButton"; -export default function PersistentUtilitiesBar({ +export default function PersistentToolBar({ type, handleChange, selection, diff --git a/packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentUtils.ts b/packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentUtils.ts new file mode 100644 index 0000000000..2ffdf3e3fd --- /dev/null +++ b/packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentUtils.ts @@ -0,0 +1,24 @@ +/** + * This program and the accompanying materials are made available under the terms of the + * Eclipse Public License v2.0 which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-v20.html + * + * SPDX-License-Identifier: EPL-2.0 + * + * Copyright Contributors to the Zowe Project. + * + */ + +export function isSecureOrigin(origin: string): boolean { + const eventUrl = new URL(origin); + const isWebUser = + (eventUrl.protocol === document.location.protocol && eventUrl.hostname === document.location.hostname) || + eventUrl.hostname.endsWith(".github.dev"); + const isLocalVSCodeUser = eventUrl.protocol === "vscode-webview:"; + + if (!isWebUser && !isLocalVSCodeUser) { + return false; + } + + return true; +} diff --git a/packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentVSCodeAPI.ts b/packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentVSCodeAPI.ts index 30c6e4091a..740dd37242 100644 --- a/packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentVSCodeAPI.ts +++ b/packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentVSCodeAPI.ts @@ -1,3 +1,14 @@ +/** + * This program and the accompanying materials are made available under the terms of the + * Eclipse Public License v2.0 which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-v20.html + * + * SPDX-License-Identifier: EPL-2.0 + * + * Copyright Contributors to the Zowe Project. + * + */ + import { WebviewApi } from "vscode-webview"; export default class PersistentVSCodeAPI { From b97a78a628da1e3f05c9571c3289652fa4df4adf Mon Sep 17 00:00:00 2001 From: Rudy Flores <68666202+rudyflores@users.noreply.github.com> Date: Wed, 11 Oct 2023 12:14:02 -0400 Subject: [PATCH 116/189] add types Signed-off-by: Rudy Flores <68666202+rudyflores@users.noreply.github.com> --- .../src/webviews/src/edit-history/App.tsx | 11 ++++++++++ .../PersistentTable/PersistentDataPanel.tsx | 13 ++++------- .../PersistentAddNewHistoryItemButton.tsx | 22 ++++++++++++++----- .../PersistentClearAllButton.tsx | 14 +++++++----- .../PersistentDropdownOptions.tsx | 7 +----- .../PersistentToolBar/PersistentToolBar.tsx | 18 +++++---------- .../src/webviews/src/edit-history/index.html | 4 ++++ .../src/webviews/src/edit-history/index.tsx | 11 ++++++++++ .../src/webviews/src/edit-history/types.ts | 16 ++++++++++++++ 9 files changed, 77 insertions(+), 39 deletions(-) create mode 100644 packages/zowe-explorer/src/webviews/src/edit-history/types.ts diff --git a/packages/zowe-explorer/src/webviews/src/edit-history/App.tsx b/packages/zowe-explorer/src/webviews/src/edit-history/App.tsx index 54337efe95..9bd258394f 100644 --- a/packages/zowe-explorer/src/webviews/src/edit-history/App.tsx +++ b/packages/zowe-explorer/src/webviews/src/edit-history/App.tsx @@ -1,3 +1,14 @@ +/** + * This program and the accompanying materials are made available under the terms of the + * Eclipse Public License v2.0 which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-v20.html + * + * SPDX-License-Identifier: EPL-2.0 + * + * Copyright Contributors to the Zowe Project. + * + */ + import { useEffect, useState } from "preact/hooks"; import { VSCodeDivider, VSCodePanels, VSCodePanelTab } from "@vscode/webview-ui-toolkit/react"; import { JSXInternal } from "preact/src/jsx"; diff --git a/packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentTable/PersistentDataPanel.tsx b/packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentTable/PersistentDataPanel.tsx index 0ebdcd8603..7df1d98bc6 100644 --- a/packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentTable/PersistentDataPanel.tsx +++ b/packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentTable/PersistentDataPanel.tsx @@ -6,14 +6,9 @@ import PersistentTableData from "./PersistentTableData"; import PersistentDataGridHeaders from "./PersistentDataGridHeaders"; import PersistentVSCodeAPI from "../PersistentVSCodeAPI"; import { isSecureOrigin } from "../PersistentUtils"; +import { panelId } from "../../types"; export default function PersistentDataPanel({ type }: { type: string }): JSXInternal.Element { - const panelId: { [key: string]: string } = { - ds: "ds-panel-view", - uss: "uss-panel-view", - jobs: "jobs-panel-view", - }; - const [data, setData] = useState<{ [type: string]: { [property: string]: string[] } }>({ ds: {}, uss: {}, jobs: {} }); const [selection, setSelection] = useState<{ [type: string]: string }>({ [type]: "search" }); const [persistentProp, setPersistentProp] = useState([]); @@ -55,10 +50,10 @@ export default function PersistentDataPanel({ type }: { type: string }): JSXInte return ( - + - - + + ); diff --git a/packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentToolBar/PersistentAddNewHistoryItemButton.tsx b/packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentToolBar/PersistentAddNewHistoryItemButton.tsx index dad1c9d489..314388a7ce 100644 --- a/packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentToolBar/PersistentAddNewHistoryItemButton.tsx +++ b/packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentToolBar/PersistentAddNewHistoryItemButton.tsx @@ -2,7 +2,13 @@ import { VSCodeButton } from "@vscode/webview-ui-toolkit/react"; import { JSXInternal } from "preact/src/jsx"; import PersistentVSCodeAPI from "../PersistentVSCodeAPI"; -export default function PersistentAddNewHistoryItemButton({ type }: { type: string }): JSXInternal.Element { +export default function PersistentAddNewHistoryItemButton({ + type, + selection, +}: { + type: string; + selection: { [type: string]: string }; +}): JSXInternal.Element { const handleClick = () => { PersistentVSCodeAPI.getVSCodeAPI().postMessage({ command: "add-item", @@ -12,9 +18,13 @@ export default function PersistentAddNewHistoryItemButton({ type }: { type: stri }); }; - return ( - - - - ); + const renderAddItemButton = () => { + return selection[type] === "search" && type !== "jobs" ? ( + + + + ) : null; + }; + + return <>{renderAddItemButton()}; } diff --git a/packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentToolBar/PersistentClearAllButton.tsx b/packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentToolBar/PersistentClearAllButton.tsx index 67ca278af6..154573dd97 100644 --- a/packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentToolBar/PersistentClearAllButton.tsx +++ b/packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentToolBar/PersistentClearAllButton.tsx @@ -13,9 +13,13 @@ export default function PersistentClearAllButton({ type, selection }: { type: st }); }; - return ( - - - - ); + const renderClearAllButton = () => { + selection[type] === "search" || selection[type] === "fileHistory" ? ( + + + + ) : null; + }; + + return <>{renderClearAllButton()}; } diff --git a/packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentToolBar/PersistentDropdownOptions.tsx b/packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentToolBar/PersistentDropdownOptions.tsx index fe2efd678a..674898863f 100644 --- a/packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentToolBar/PersistentDropdownOptions.tsx +++ b/packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentToolBar/PersistentDropdownOptions.tsx @@ -1,12 +1,7 @@ import { VSCodeDropdown, VSCodeOption } from "@vscode/webview-ui-toolkit/react"; -import { useEffect } from "preact/hooks"; import { JSXInternal } from "preact/src/jsx"; -export default function PersistentDropdownOptions({ handleChange, type }: { handleChange: Function; type: string }): JSXInternal.Element { - useEffect(() => { - console.log("change"); - }); - +export default function PersistentDropdownOptions({ type, handleChange }: { type: string; handleChange: Function }): JSXInternal.Element { const options = [ Search History, DS Templates, diff --git a/packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentToolBar/PersistentToolBar.tsx b/packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentToolBar/PersistentToolBar.tsx index a2b438d21c..5f24c6d509 100644 --- a/packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentToolBar/PersistentToolBar.tsx +++ b/packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentToolBar/PersistentToolBar.tsx @@ -6,27 +6,19 @@ import PersistentAddNewHistoryItemButton from "./PersistentAddNewHistoryItemButt export default function PersistentToolBar({ type, - handleChange, selection, + handleChange, }: { type: string; - handleChange: Function; selection: { [type: string]: string }; + handleChange: Function; }): JSXInternal.Element { - const renderAddItemButton = () => { - return selection[type] === "search" && type !== "jobs" ? : null; - }; - - const renderClearAllButton = () => { - return selection[type] === "search" || selection[type] === "fileHistory" ? : null; - }; - return (
- + - {renderClearAllButton()} - {renderAddItemButton()} + +
); } diff --git a/packages/zowe-explorer/src/webviews/src/edit-history/index.html b/packages/zowe-explorer/src/webviews/src/edit-history/index.html index 5789513d71..ec4f8fc819 100644 --- a/packages/zowe-explorer/src/webviews/src/edit-history/index.html +++ b/packages/zowe-explorer/src/webviews/src/edit-history/index.html @@ -1,3 +1,7 @@ + + diff --git a/packages/zowe-explorer/src/webviews/src/edit-history/index.tsx b/packages/zowe-explorer/src/webviews/src/edit-history/index.tsx index 74832990aa..748009dcd9 100644 --- a/packages/zowe-explorer/src/webviews/src/edit-history/index.tsx +++ b/packages/zowe-explorer/src/webviews/src/edit-history/index.tsx @@ -1,3 +1,14 @@ +/** + * This program and the accompanying materials are made available under the terms of the + * Eclipse Public License v2.0 which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-v20.html + * + * SPDX-License-Identifier: EPL-2.0 + * + * Copyright Contributors to the Zowe Project. + * + */ + import { render } from "preact"; import { App } from "./App"; diff --git a/packages/zowe-explorer/src/webviews/src/edit-history/types.ts b/packages/zowe-explorer/src/webviews/src/edit-history/types.ts new file mode 100644 index 0000000000..edc3f444af --- /dev/null +++ b/packages/zowe-explorer/src/webviews/src/edit-history/types.ts @@ -0,0 +1,16 @@ +/** + * This program and the accompanying materials are made available under the terms of the + * Eclipse Public License v2.0 which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-v20.html + * + * SPDX-License-Identifier: EPL-2.0 + * + * Copyright Contributors to the Zowe Project. + * + */ + +export const panelId: { [key: string]: string } = { + ds: "ds-panel-view", + uss: "uss-panel-view", + jobs: "jobs-panel-view", +}; From af84af185af1a05b1460d71f1b7f23a6532b2460 Mon Sep 17 00:00:00 2001 From: Rudy Flores <68666202+rudyflores@users.noreply.github.com> Date: Wed, 11 Oct 2023 12:50:24 -0400 Subject: [PATCH 117/189] final cleanup using context Signed-off-by: Rudy Flores <68666202+rudyflores@users.noreply.github.com> --- .../PersistentManagerHeader.tsx | 11 +++++++ .../PersistentDataGridHeaders.tsx | 16 +++++++++- .../PersistentTable/PersistentDataPanel.tsx | 29 ++++++++++++++----- .../PersistentTable/PersistentTableData.tsx | 24 +++++++++------ .../PersistentAddNewHistoryItemButton.tsx | 22 +++++++++----- .../PersistentClearAllButton.tsx | 16 +++++++++- .../PersistentDropdownOptions.tsx | 18 ++++++++++-- .../PersistentRefreshButton.tsx | 16 +++++++++- .../PersistentToolBar/PersistentToolBar.tsx | 29 ++++++++++--------- .../components/PersistentUtils.ts | 14 +++++++++ .../src/webviews/src/edit-history/types.ts | 5 ++++ 11 files changed, 158 insertions(+), 42 deletions(-) diff --git a/packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentManagerHeader/PersistentManagerHeader.tsx b/packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentManagerHeader/PersistentManagerHeader.tsx index 7ec82d98d5..3e1304de88 100644 --- a/packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentManagerHeader/PersistentManagerHeader.tsx +++ b/packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentManagerHeader/PersistentManagerHeader.tsx @@ -1,3 +1,14 @@ +/** + * This program and the accompanying materials are made available under the terms of the + * Eclipse Public License v2.0 which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-v20.html + * + * SPDX-License-Identifier: EPL-2.0 + * + * Copyright Contributors to the Zowe Project. + * + */ + import { JSXInternal } from "preact/src/jsx"; export default function PersistentManagerHeader({ timestamp }: { timestamp: Date | undefined }): JSXInternal.Element { diff --git a/packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentTable/PersistentDataGridHeaders.tsx b/packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentTable/PersistentDataGridHeaders.tsx index abe6003a00..e70372fb37 100644 --- a/packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentTable/PersistentDataGridHeaders.tsx +++ b/packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentTable/PersistentDataGridHeaders.tsx @@ -1,7 +1,21 @@ +/** + * This program and the accompanying materials are made available under the terms of the + * Eclipse Public License v2.0 which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-v20.html + * + * SPDX-License-Identifier: EPL-2.0 + * + * Copyright Contributors to the Zowe Project. + * + */ + import { VSCodeDataGridRow, VSCodeDataGridCell } from "@vscode/webview-ui-toolkit/react"; import { JSXInternal } from "preact/src/jsx"; +import { useDataPanelContext } from "../PersistentUtils"; + +export default function PersistentDataGridHeaders(): JSXInternal.Element { + const { type, selection } = useDataPanelContext(); -export default function PersistentDataGridHeaders({ selection, type }: { selection: { [type: string]: string }; type: string }): JSXInternal.Element { const renderDeleteHeader = () => { return selection[type] === "search" || selection[type] === "fileHistory" ? ( diff --git a/packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentTable/PersistentDataPanel.tsx b/packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentTable/PersistentDataPanel.tsx index 7df1d98bc6..7274806c20 100644 --- a/packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentTable/PersistentDataPanel.tsx +++ b/packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentTable/PersistentDataPanel.tsx @@ -1,3 +1,14 @@ +/** + * This program and the accompanying materials are made available under the terms of the + * Eclipse Public License v2.0 which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-v20.html + * + * SPDX-License-Identifier: EPL-2.0 + * + * Copyright Contributors to the Zowe Project. + * + */ + import { useEffect, useState } from "preact/hooks"; import { VSCodePanelView, VSCodeDataGrid } from "@vscode/webview-ui-toolkit/react"; import { JSXInternal } from "preact/src/jsx"; @@ -5,7 +16,7 @@ import PersistentToolBar from "../PersistentToolBar/PersistentToolBar"; import PersistentTableData from "./PersistentTableData"; import PersistentDataGridHeaders from "./PersistentDataGridHeaders"; import PersistentVSCodeAPI from "../PersistentVSCodeAPI"; -import { isSecureOrigin } from "../PersistentUtils"; +import { DataPanelContext, isSecureOrigin } from "../PersistentUtils"; import { panelId } from "../../types"; export default function PersistentDataPanel({ type }: { type: string }): JSXInternal.Element { @@ -49,12 +60,14 @@ export default function PersistentDataPanel({ type }: { type: string }): JSXInte }, [selection]); return ( - - - - - - - + + + + + + + + + ); } diff --git a/packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentTable/PersistentTableData.tsx b/packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentTable/PersistentTableData.tsx index 105f5a09e0..6cc82ac6c0 100644 --- a/packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentTable/PersistentTableData.tsx +++ b/packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentTable/PersistentTableData.tsx @@ -1,16 +1,22 @@ +/** + * This program and the accompanying materials are made available under the terms of the + * Eclipse Public License v2.0 which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-v20.html + * + * SPDX-License-Identifier: EPL-2.0 + * + * Copyright Contributors to the Zowe Project. + * + */ + import { VSCodeDataGridCell, VSCodeDataGridRow } from "@vscode/webview-ui-toolkit/react"; import { JSXInternal } from "preact/src/jsx"; import PersistentVSCodeAPI from "../PersistentVSCodeAPI"; +import { useDataPanelContext } from "../PersistentUtils"; + +export default function PersistentTableData({ persistentProp }: { persistentProp: string[] }): JSXInternal.Element { + const { type, selection } = useDataPanelContext(); -export default function PersistentTableData({ - type, - persistentProp, - selection, -}: { - type: string; - persistentProp: string[]; - selection: { [type: string]: string }; -}): JSXInternal.Element { const handleClick = (item: number) => { PersistentVSCodeAPI.getVSCodeAPI().postMessage({ command: "remove-item", diff --git a/packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentToolBar/PersistentAddNewHistoryItemButton.tsx b/packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentToolBar/PersistentAddNewHistoryItemButton.tsx index 314388a7ce..859d907f47 100644 --- a/packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentToolBar/PersistentAddNewHistoryItemButton.tsx +++ b/packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentToolBar/PersistentAddNewHistoryItemButton.tsx @@ -1,14 +1,22 @@ +/** + * This program and the accompanying materials are made available under the terms of the + * Eclipse Public License v2.0 which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-v20.html + * + * SPDX-License-Identifier: EPL-2.0 + * + * Copyright Contributors to the Zowe Project. + * + */ + import { VSCodeButton } from "@vscode/webview-ui-toolkit/react"; import { JSXInternal } from "preact/src/jsx"; import PersistentVSCodeAPI from "../PersistentVSCodeAPI"; +import { useDataPanelContext } from "../PersistentUtils"; + +export default function PersistentAddNewHistoryItemButton(): JSXInternal.Element { + const { type, selection } = useDataPanelContext(); -export default function PersistentAddNewHistoryItemButton({ - type, - selection, -}: { - type: string; - selection: { [type: string]: string }; -}): JSXInternal.Element { const handleClick = () => { PersistentVSCodeAPI.getVSCodeAPI().postMessage({ command: "add-item", diff --git a/packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentToolBar/PersistentClearAllButton.tsx b/packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentToolBar/PersistentClearAllButton.tsx index 154573dd97..9c2beb0ec5 100644 --- a/packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentToolBar/PersistentClearAllButton.tsx +++ b/packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentToolBar/PersistentClearAllButton.tsx @@ -1,8 +1,22 @@ +/** + * This program and the accompanying materials are made available under the terms of the + * Eclipse Public License v2.0 which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-v20.html + * + * SPDX-License-Identifier: EPL-2.0 + * + * Copyright Contributors to the Zowe Project. + * + */ + import { VSCodeButton } from "@vscode/webview-ui-toolkit/react"; import { JSXInternal } from "preact/src/jsx"; import PersistentVSCodeAPI from "../PersistentVSCodeAPI"; +import { useDataPanelContext } from "../PersistentUtils"; + +export default function PersistentClearAllButton(): JSXInternal.Element { + const { type, selection } = useDataPanelContext(); -export default function PersistentClearAllButton({ type, selection }: { type: string; selection: { [type: string]: string } }): JSXInternal.Element { const handleClick = () => { PersistentVSCodeAPI.getVSCodeAPI().postMessage({ command: "clear-all", diff --git a/packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentToolBar/PersistentDropdownOptions.tsx b/packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentToolBar/PersistentDropdownOptions.tsx index 674898863f..bd9724969f 100644 --- a/packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentToolBar/PersistentDropdownOptions.tsx +++ b/packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentToolBar/PersistentDropdownOptions.tsx @@ -1,14 +1,28 @@ +/** + * This program and the accompanying materials are made available under the terms of the + * Eclipse Public License v2.0 which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-v20.html + * + * SPDX-License-Identifier: EPL-2.0 + * + * Copyright Contributors to the Zowe Project. + * + */ + import { VSCodeDropdown, VSCodeOption } from "@vscode/webview-ui-toolkit/react"; import { JSXInternal } from "preact/src/jsx"; +import { useDataPanelContext } from "../PersistentUtils"; + +export default function PersistentDropdownOptions({ handleChange }: { handleChange: Function }): JSXInternal.Element { + const dataPanelContext = useDataPanelContext(); -export default function PersistentDropdownOptions({ type, handleChange }: { type: string; handleChange: Function }): JSXInternal.Element { const options = [ Search History, DS Templates, Favorites, File History, Sessions, - ].filter((option) => type === "ds" || option.props.value !== "dsTemplates"); + ].filter((option) => dataPanelContext.type === "ds" || option.props.value !== "dsTemplates"); return (
diff --git a/packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentToolBar/PersistentRefreshButton.tsx b/packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentToolBar/PersistentRefreshButton.tsx index 94b0cecddf..dab67e3d99 100644 --- a/packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentToolBar/PersistentRefreshButton.tsx +++ b/packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentToolBar/PersistentRefreshButton.tsx @@ -1,8 +1,22 @@ +/** + * This program and the accompanying materials are made available under the terms of the + * Eclipse Public License v2.0 which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-v20.html + * + * SPDX-License-Identifier: EPL-2.0 + * + * Copyright Contributors to the Zowe Project. + * + */ + import { VSCodeButton } from "@vscode/webview-ui-toolkit/react"; import { JSXInternal } from "preact/src/jsx"; import PersistentVSCodeAPI from "../PersistentVSCodeAPI"; +import { useDataPanelContext } from "../PersistentUtils"; + +export default function PersistentRefreshButton(): JSXInternal.Element { + const { type } = useDataPanelContext(); -export default function PersistentRefreshButton({ type }: { type: string }): JSXInternal.Element { const handleClick = () => { PersistentVSCodeAPI.getVSCodeAPI().postMessage({ command: "refresh", diff --git a/packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentToolBar/PersistentToolBar.tsx b/packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentToolBar/PersistentToolBar.tsx index 5f24c6d509..ad8f760f91 100644 --- a/packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentToolBar/PersistentToolBar.tsx +++ b/packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentToolBar/PersistentToolBar.tsx @@ -1,24 +1,27 @@ +/** + * This program and the accompanying materials are made available under the terms of the + * Eclipse Public License v2.0 which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-v20.html + * + * SPDX-License-Identifier: EPL-2.0 + * + * Copyright Contributors to the Zowe Project. + * + */ + import { JSXInternal } from "preact/src/jsx"; import PersistentClearAllButton from "./PersistentClearAllButton"; import PersistentRefreshButton from "./PersistentRefreshButton"; import PersistentDropdownOptions from "./PersistentDropdownOptions"; import PersistentAddNewHistoryItemButton from "./PersistentAddNewHistoryItemButton"; -export default function PersistentToolBar({ - type, - selection, - handleChange, -}: { - type: string; - selection: { [type: string]: string }; - handleChange: Function; -}): JSXInternal.Element { +export default function PersistentToolBar({ handleChange }: { handleChange: Function }): JSXInternal.Element { return (
- - - - + + + +
); } diff --git a/packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentUtils.ts b/packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentUtils.ts index 2ffdf3e3fd..86eca22d96 100644 --- a/packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentUtils.ts +++ b/packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentUtils.ts @@ -9,6 +9,12 @@ * */ +import { createContext } from "preact"; +import { DataPanelContextType } from "../types"; +import { useContext } from "preact/hooks"; + +export const DataPanelContext = createContext(null); + export function isSecureOrigin(origin: string): boolean { const eventUrl = new URL(origin); const isWebUser = @@ -22,3 +28,11 @@ export function isSecureOrigin(origin: string): boolean { return true; } + +export function useDataPanelContext(): DataPanelContextType { + const dataPanelContext = useContext(DataPanelContext); + if (!dataPanelContext) { + throw new Error("DataPanelContext has to be used within "); + } + return dataPanelContext; +} diff --git a/packages/zowe-explorer/src/webviews/src/edit-history/types.ts b/packages/zowe-explorer/src/webviews/src/edit-history/types.ts index edc3f444af..b00005125b 100644 --- a/packages/zowe-explorer/src/webviews/src/edit-history/types.ts +++ b/packages/zowe-explorer/src/webviews/src/edit-history/types.ts @@ -14,3 +14,8 @@ export const panelId: { [key: string]: string } = { uss: "uss-panel-view", jobs: "jobs-panel-view", }; + +export type DataPanelContextType = { + type: string; + selection: { [type: string]: string }; +}; From 11123c10171f43c92d2d56625bd0195c34479ec7 Mon Sep 17 00:00:00 2001 From: Rudy Flores <68666202+rudyflores@users.noreply.github.com> Date: Wed, 11 Oct 2023 13:09:08 -0400 Subject: [PATCH 118/189] add localized strings Signed-off-by: Rudy Flores <68666202+rudyflores@users.noreply.github.com> --- .../src/webviews/src/edit-history/App.tsx | 2 +- .../PersistentTable/PersistentDataGridHeaders.tsx | 9 +++++++-- .../PersistentTable/PersistentDataPanel.tsx | 4 ++-- .../PersistentTable/PersistentTableData.tsx | 2 +- .../PersistentAddNewHistoryItemButton.tsx | 9 +++++++-- .../PersistentToolBar/PersistentClearAllButton.tsx | 11 ++++++++--- .../PersistentToolBar/PersistentRefreshButton.tsx | 9 +++++++-- 7 files changed, 33 insertions(+), 13 deletions(-) diff --git a/packages/zowe-explorer/src/webviews/src/edit-history/App.tsx b/packages/zowe-explorer/src/webviews/src/edit-history/App.tsx index 9bd258394f..3c9ed2e157 100644 --- a/packages/zowe-explorer/src/webviews/src/edit-history/App.tsx +++ b/packages/zowe-explorer/src/webviews/src/edit-history/App.tsx @@ -12,10 +12,10 @@ import { useEffect, useState } from "preact/hooks"; import { VSCodeDivider, VSCodePanels, VSCodePanelTab } from "@vscode/webview-ui-toolkit/react"; import { JSXInternal } from "preact/src/jsx"; +import { isSecureOrigin } from "./components/PersistentUtils"; import PersistentDataPanel from "./components/PersistentTable/PersistentDataPanel"; import PersistentVSCodeAPI from "./components/PersistentVSCodeAPI"; import PersistentManagerHeader from "./components/PersistentManagerHeader/PersistentManagerHeader"; -import { isSecureOrigin } from "./components/PersistentUtils"; export function App(): JSXInternal.Element { const [timestamp, setTimestamp] = useState(); diff --git a/packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentTable/PersistentDataGridHeaders.tsx b/packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentTable/PersistentDataGridHeaders.tsx index e70372fb37..f8a6c2abff 100644 --- a/packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentTable/PersistentDataGridHeaders.tsx +++ b/packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentTable/PersistentDataGridHeaders.tsx @@ -12,14 +12,19 @@ import { VSCodeDataGridRow, VSCodeDataGridCell } from "@vscode/webview-ui-toolkit/react"; import { JSXInternal } from "preact/src/jsx"; import { useDataPanelContext } from "../PersistentUtils"; +import * as nls from "vscode-nls"; + +const localize: nls.LocalizeFunc = nls.loadMessageBundle(); export default function PersistentDataGridHeaders(): JSXInternal.Element { const { type, selection } = useDataPanelContext(); + const itemText = localize("PersistentDataGridHeaders.item", "Item"); const renderDeleteHeader = () => { + const deleteText = localize("PersistentDataGridHeaders.delete", "Delete"); return selection[type] === "search" || selection[type] === "fileHistory" ? ( - Delete + {deleteText} ) : null; }; @@ -27,7 +32,7 @@ export default function PersistentDataGridHeaders(): JSXInternal.Element { return ( - Item + {itemText} {renderDeleteHeader()} diff --git a/packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentTable/PersistentDataPanel.tsx b/packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentTable/PersistentDataPanel.tsx index 7274806c20..7ea1375897 100644 --- a/packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentTable/PersistentDataPanel.tsx +++ b/packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentTable/PersistentDataPanel.tsx @@ -12,12 +12,12 @@ import { useEffect, useState } from "preact/hooks"; import { VSCodePanelView, VSCodeDataGrid } from "@vscode/webview-ui-toolkit/react"; import { JSXInternal } from "preact/src/jsx"; +import { DataPanelContext, isSecureOrigin } from "../PersistentUtils"; +import { panelId } from "../../types"; import PersistentToolBar from "../PersistentToolBar/PersistentToolBar"; import PersistentTableData from "./PersistentTableData"; import PersistentDataGridHeaders from "./PersistentDataGridHeaders"; import PersistentVSCodeAPI from "../PersistentVSCodeAPI"; -import { DataPanelContext, isSecureOrigin } from "../PersistentUtils"; -import { panelId } from "../../types"; export default function PersistentDataPanel({ type }: { type: string }): JSXInternal.Element { const [data, setData] = useState<{ [type: string]: { [property: string]: string[] } }>({ ds: {}, uss: {}, jobs: {} }); diff --git a/packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentTable/PersistentTableData.tsx b/packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentTable/PersistentTableData.tsx index 6cc82ac6c0..b1690a6155 100644 --- a/packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentTable/PersistentTableData.tsx +++ b/packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentTable/PersistentTableData.tsx @@ -11,8 +11,8 @@ import { VSCodeDataGridCell, VSCodeDataGridRow } from "@vscode/webview-ui-toolkit/react"; import { JSXInternal } from "preact/src/jsx"; -import PersistentVSCodeAPI from "../PersistentVSCodeAPI"; import { useDataPanelContext } from "../PersistentUtils"; +import PersistentVSCodeAPI from "../PersistentVSCodeAPI"; export default function PersistentTableData({ persistentProp }: { persistentProp: string[] }): JSXInternal.Element { const { type, selection } = useDataPanelContext(); diff --git a/packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentToolBar/PersistentAddNewHistoryItemButton.tsx b/packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentToolBar/PersistentAddNewHistoryItemButton.tsx index 859d907f47..b217118627 100644 --- a/packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentToolBar/PersistentAddNewHistoryItemButton.tsx +++ b/packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentToolBar/PersistentAddNewHistoryItemButton.tsx @@ -11,8 +11,11 @@ import { VSCodeButton } from "@vscode/webview-ui-toolkit/react"; import { JSXInternal } from "preact/src/jsx"; -import PersistentVSCodeAPI from "../PersistentVSCodeAPI"; import { useDataPanelContext } from "../PersistentUtils"; +import PersistentVSCodeAPI from "../PersistentVSCodeAPI"; +import * as nls from "vscode-nls"; + +const localize: nls.LocalizeFunc = nls.loadMessageBundle(); export default function PersistentAddNewHistoryItemButton(): JSXInternal.Element { const { type, selection } = useDataPanelContext(); @@ -26,9 +29,11 @@ export default function PersistentAddNewHistoryItemButton(): JSXInternal.Element }); }; + const newHistoryItemText = localize("PersistentAddNewHistoryItemButton.newHistoryItem", "Add New History Item"); + const renderAddItemButton = () => { return selection[type] === "search" && type !== "jobs" ? ( - + ) : null; diff --git a/packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentToolBar/PersistentClearAllButton.tsx b/packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentToolBar/PersistentClearAllButton.tsx index 9c2beb0ec5..83337dc0d4 100644 --- a/packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentToolBar/PersistentClearAllButton.tsx +++ b/packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentToolBar/PersistentClearAllButton.tsx @@ -11,8 +11,11 @@ import { VSCodeButton } from "@vscode/webview-ui-toolkit/react"; import { JSXInternal } from "preact/src/jsx"; -import PersistentVSCodeAPI from "../PersistentVSCodeAPI"; import { useDataPanelContext } from "../PersistentUtils"; +import PersistentVSCodeAPI from "../PersistentVSCodeAPI"; +import * as nls from "vscode-nls"; + +const localize: nls.LocalizeFunc = nls.loadMessageBundle(); export default function PersistentClearAllButton(): JSXInternal.Element { const { type, selection } = useDataPanelContext(); @@ -28,8 +31,10 @@ export default function PersistentClearAllButton(): JSXInternal.Element { }; const renderClearAllButton = () => { - selection[type] === "search" || selection[type] === "fileHistory" ? ( - + const clearAllText = localize("PersistentClearAllButton.clearAll", "Clear All"); + + return selection[type] === "search" || selection[type] === "fileHistory" ? ( + ) : null; diff --git a/packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentToolBar/PersistentRefreshButton.tsx b/packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentToolBar/PersistentRefreshButton.tsx index dab67e3d99..1d97fe8511 100644 --- a/packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentToolBar/PersistentRefreshButton.tsx +++ b/packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentToolBar/PersistentRefreshButton.tsx @@ -11,8 +11,11 @@ import { VSCodeButton } from "@vscode/webview-ui-toolkit/react"; import { JSXInternal } from "preact/src/jsx"; -import PersistentVSCodeAPI from "../PersistentVSCodeAPI"; import { useDataPanelContext } from "../PersistentUtils"; +import PersistentVSCodeAPI from "../PersistentVSCodeAPI"; +import * as nls from "vscode-nls"; + +const localize: nls.LocalizeFunc = nls.loadMessageBundle(); export default function PersistentRefreshButton(): JSXInternal.Element { const { type } = useDataPanelContext(); @@ -26,8 +29,10 @@ export default function PersistentRefreshButton(): JSXInternal.Element { }); }; + const refreshText = localize("PersistentRefreshButton.refresh", "Refresh"); + return ( - + ); From f7b34f3caecf8c9ac16184203cab3ab8fce21d39 Mon Sep 17 00:00:00 2001 From: Billie Simmons <49491949+JillieBeanSim@users.noreply.github.com> Date: Wed, 11 Oct 2023 14:20:25 -0400 Subject: [PATCH 119/189] update checks for langId and add passing of file when needed Signed-off-by: Billie Simmons <49491949+JillieBeanSim@users.noreply.github.com> --- .../__unit__/dataset/init.unit.test.ts | 2 +- .../__unit__/job/actions.unit.test.ts | 262 ++++++++++++------ packages/zowe-explorer/package.json | 4 +- packages/zowe-explorer/src/dataset/actions.ts | 14 +- packages/zowe-explorer/src/dataset/init.ts | 2 +- 5 files changed, 189 insertions(+), 95 deletions(-) diff --git a/packages/zowe-explorer/__tests__/__unit__/dataset/init.unit.test.ts b/packages/zowe-explorer/__tests__/__unit__/dataset/init.unit.test.ts index bacbe6f822..297a96ea7d 100644 --- a/packages/zowe-explorer/__tests__/__unit__/dataset/init.unit.test.ts +++ b/packages/zowe-explorer/__tests__/__unit__/dataset/init.unit.test.ts @@ -156,7 +156,7 @@ describe("Test src/dataset/extension", () => { }, { name: "zowe.ds.submitJcl", - mock: [{ spy: jest.spyOn(dsActions, "submitJcl"), arg: [dsProvider] }], + mock: [{ spy: jest.spyOn(dsActions, "submitJcl"), arg: [dsProvider, test.value] }], }, { name: "zowe.ds.submitMember", diff --git a/packages/zowe-explorer/__tests__/__unit__/job/actions.unit.test.ts b/packages/zowe-explorer/__tests__/__unit__/job/actions.unit.test.ts index ad589fd9e2..3f99de5765 100644 --- a/packages/zowe-explorer/__tests__/__unit__/job/actions.unit.test.ts +++ b/packages/zowe-explorer/__tests__/__unit__/job/actions.unit.test.ts @@ -46,6 +46,34 @@ import { ZosJobsProvider } from "../../../src/job/ZosJobsProvider"; const activeTextEditorDocument = jest.fn(); function createGlobalMocks() { + const newMocks = { + JobNode1: new Job( + "testProfile", + vscode.TreeItemCollapsibleState.None, + null as any, + createISession(), + settingJobObjects(createIJobObject(), "ZOWEUSR1", "JOB045123", "ABEND S222"), + createIProfile() + ), + JobNode2: new Job( + "testProfile", + vscode.TreeItemCollapsibleState.None, + null as any, + createISession(), + settingJobObjects(createIJobObject(), "ZOWEUSR1", "JOB045120", "CC 0000"), + createIProfile() + ), + JobNode3: new Job( + "testProfile", + vscode.TreeItemCollapsibleState.None, + null as any, + createISession(), + settingJobObjects(createIJobObject(), "ZOWEUSR2", "JOB045125", "CC 0000"), + createIProfile() + ), + mockJobArray: [], + }; + newMocks.mockJobArray = [newMocks.JobNode1, newMocks.JobNode2, newMocks.JobNode3] as any; Object.defineProperty(vscode.workspace, "getConfiguration", { value: jest.fn().mockImplementation(() => new Map([["zowe.jobs.confirmSubmission", false]])), configurable: true, @@ -93,41 +121,7 @@ function createGlobalMocks() { job.retcode = setjobreturncode; return job; } - const newMocks = jest.fn().mockReturnValue([ - (() => { - const JobNode1 = new Job( - "testProfile", - vscode.TreeItemCollapsibleState.None, - null, - createISession(), - settingJobObjects(createIJobObject(), "ZOWEUSR1", "JOB045123", "ABEND S222"), - createIProfile() - ); - return JobNode1; - })(), - (() => { - const JobNode2 = new Job( - "testProfile", - vscode.TreeItemCollapsibleState.None, - null, - createISession(), - settingJobObjects(createIJobObject(), "ZOWEUSR1", "JOB045120", "CC 0000"), - createIProfile() - ); - return JobNode2; - })(), - (() => { - const JobNode3 = new Job( - "testProfile", - vscode.TreeItemCollapsibleState.None, - null, - createISession(), - settingJobObjects(createIJobObject(), "ZOWEUSR2", "JOB045125", "CC 0000"), - createIProfile() - ); - return JobNode3; - })(), - ]); + return newMocks; } @@ -157,7 +151,7 @@ describe("Jobs Actions Unit Tests - Function setPrefix", () => { it("Checking that the prefix is set correctly on the job", async () => { createGlobalMocks(); const blockMocks = createBlockMocks(); - const node = new Job("job", vscode.TreeItemCollapsibleState.None, null, blockMocks.session, null, null); + const node = new Job("job", vscode.TreeItemCollapsibleState.None, null as any, blockMocks.session, null as any, null as any); const mySpy = mocked(vscode.window.showInputBox).mockResolvedValue("*"); await jobActions.setPrefix(node, blockMocks.testJobsTree); @@ -192,7 +186,14 @@ describe("Jobs Actions Unit Tests - Function setOwner", () => { it("Checking that the owner is set correctly on the job", async () => { createGlobalMocks(); const blockMocks = createBlockMocks(); - const node = new Job("job", vscode.TreeItemCollapsibleState.None, null, blockMocks.session, blockMocks.iJob, blockMocks.imperativeProfile); + const node = new Job( + "job", + vscode.TreeItemCollapsibleState.None, + null as any, + blockMocks.session, + blockMocks.iJob, + blockMocks.imperativeProfile + ); const mySpy = mocked(vscode.window.showInputBox).mockResolvedValue("OWNER"); await jobActions.setOwner(node, blockMocks.testJobsTree); @@ -224,7 +225,14 @@ describe("Jobs Actions Unit Tests - Function stopCommand", () => { it("Checking that stop command of Job Node is executed properly", async () => { createGlobalMocks(); const blockMocks = createBlockMocks(); - const node = new Job("job", vscode.TreeItemCollapsibleState.None, null, blockMocks.session, blockMocks.iJob, blockMocks.imperativeProfile); + const node = new Job( + "job", + vscode.TreeItemCollapsibleState.None, + null as any, + blockMocks.session, + blockMocks.iJob, + blockMocks.imperativeProfile + ); mocked(zowe.IssueCommand.issueSimple).mockResolvedValueOnce({ success: false, @@ -238,7 +246,14 @@ describe("Jobs Actions Unit Tests - Function stopCommand", () => { it("Checking failed attempt to issue stop command for Job Node.", async () => { createGlobalMocks(); const blockMocks = createBlockMocks(); - const node = new Job("job", vscode.TreeItemCollapsibleState.None, null, blockMocks.session, undefined, blockMocks.imperativeProfile); + const node = new Job( + "job", + vscode.TreeItemCollapsibleState.None, + null as any, + blockMocks.session, + undefined as any, + blockMocks.imperativeProfile + ); mocked(zowe.IssueCommand.issueSimple).mockResolvedValueOnce({ success: false, zosmfResponse: [], @@ -265,7 +280,14 @@ describe("Jobs Actions Unit Tests - Function modifyCommand", () => { it("Checking modification of Job Node", async () => { createGlobalMocks(); const blockMocks = createBlockMocks(); - const node = new Job("job", vscode.TreeItemCollapsibleState.None, null, blockMocks.session, blockMocks.iJob, blockMocks.imperativeProfile); + const node = new Job( + "job", + vscode.TreeItemCollapsibleState.None, + null as any, + blockMocks.session, + blockMocks.iJob, + blockMocks.imperativeProfile + ); mocked(vscode.window.showInputBox).mockResolvedValue("modify"); mocked(zowe.IssueCommand.issueSimple).mockResolvedValueOnce({ @@ -280,7 +302,14 @@ describe("Jobs Actions Unit Tests - Function modifyCommand", () => { it("Checking failed attempt to modify Job Node", async () => { createGlobalMocks(); const blockMocks = createBlockMocks(); - const node = new Job("job", vscode.TreeItemCollapsibleState.None, null, blockMocks.session, undefined, blockMocks.imperativeProfile); + const node = new Job( + "job", + vscode.TreeItemCollapsibleState.None, + null as any, + blockMocks.session, + undefined as any, + blockMocks.imperativeProfile + ); mocked(vscode.window.showInputBox).mockResolvedValue("modify"); mocked(zowe.IssueCommand.issueSimple).mockResolvedValueOnce({ success: false, @@ -312,7 +341,14 @@ describe("Jobs Actions Unit Tests - Function downloadSpool", () => { createGlobalMocks(); const blockMocks = createBlockMocks(); const jobs: Job[] = []; - const node = new Job("job", vscode.TreeItemCollapsibleState.None, null, blockMocks.session, blockMocks.iJob, blockMocks.imperativeProfile); + const node = new Job( + "job", + vscode.TreeItemCollapsibleState.None, + null as any, + blockMocks.session, + blockMocks.iJob, + blockMocks.imperativeProfile + ); const fileUri = { fsPath: "/tmp/foo", scheme: "", @@ -346,7 +382,7 @@ describe("Jobs Actions Unit Tests - Function downloadSpool", () => { query: "", }; mocked(Gui.showOpenDialog).mockResolvedValue([fileUri as vscode.Uri]); - await jobActions.downloadSpool(undefined); + await jobActions.downloadSpool(undefined as any); expect(mocked(Gui.errorMessage).mock.calls.length).toBe(1); }); }); @@ -375,7 +411,7 @@ describe("Jobs Actions Unit Tests - Function downloadSingleSpool", () => { const node = new Job( "test:dd - 1", vscode.TreeItemCollapsibleState.None, - null, + null as any, blockMocks.session, blockMocks.iJob, blockMocks.imperativeProfile @@ -413,7 +449,7 @@ describe("Jobs Actions Unit Tests - Function downloadSingleSpool", () => { const node = new Job( "test:dd - 1", vscode.TreeItemCollapsibleState.None, - null, + null as any, blockMocks.session, blockMocks.iJob, blockMocks.imperativeProfile @@ -456,7 +492,14 @@ describe("Jobs Actions Unit Tests - Function downloadJcl", () => { it("Checking download of Job JCL", async () => { createGlobalMocks(); const blockMocks = createBlockMocks(); - const node = new Job("job", vscode.TreeItemCollapsibleState.None, null, blockMocks.session, blockMocks.iJob, blockMocks.imperativeProfile); + const node = new Job( + "job", + vscode.TreeItemCollapsibleState.None, + null as any, + blockMocks.session, + blockMocks.iJob, + blockMocks.imperativeProfile + ); await jobActions.downloadJcl(node); expect(mocked(zowe.GetJobs.getJclForJob)).toBeCalled(); expect(mocked(vscode.workspace.openTextDocument)).toBeCalled(); @@ -465,7 +508,7 @@ describe("Jobs Actions Unit Tests - Function downloadJcl", () => { it("Checking failed attempt to download Job JCL", async () => { createGlobalMocks(); const blockMocks = createBlockMocks(); - await jobActions.downloadJcl(undefined); + await jobActions.downloadJcl(undefined as any); expect(mocked(Gui.errorMessage)).toBeCalled(); }); }); @@ -478,15 +521,17 @@ describe("Jobs Actions Unit Tests - Function submitJcl", () => { const imperativeProfile = createIProfile(); const datasetSessionNode = createDatasetSessionNode(session, imperativeProfile); const textDocument = createTextDocument("HLQ.TEST.AFILE(mem)", datasetSessionNode); + (textDocument.languageId as any) = "jcl"; const profileInstance = createInstanceOfProfile(imperativeProfile); const jesApi = createJesApi(imperativeProfile); const mockCheckCurrentProfile = jest.fn(); bindJesApi(jesApi); - Object.defineProperty(profileInstance, "loadNamedProfile", { value: jest.fn(), + configurable: true, }); - (textDocument.languageId as any) = "jcl"; + const errorGuiMsgSpy = jest.spyOn(Gui, "errorMessage"); + const errorLogSpy = jest.spyOn(ZoweLogger, "error"); return { session, @@ -499,6 +544,8 @@ describe("Jobs Actions Unit Tests - Function submitJcl", () => { profileInstance, jesApi, mockCheckCurrentProfile, + errorLogSpy, + errorGuiMsgSpy, }; } @@ -513,14 +560,14 @@ describe("Jobs Actions Unit Tests - Function submitJcl", () => { }) ); blockMocks.testDatasetTree.getChildren.mockResolvedValueOnce([ - new ZoweDatasetNode("node", vscode.TreeItemCollapsibleState.None, blockMocks.datasetSessionNode, null), + new ZoweDatasetNode("node", vscode.TreeItemCollapsibleState.None, blockMocks.datasetSessionNode, null as any), blockMocks.datasetSessionNode, ]); activeTextEditorDocument.mockReturnValue(blockMocks.textDocument); const submitJclSpy = jest.spyOn(blockMocks.jesApi, "submitJcl"); submitJclSpy.mockClear(); submitJclSpy.mockResolvedValueOnce(blockMocks.iJob); - await dsActions.submitJcl(blockMocks.testDatasetTree); + await dsActions.submitJcl(blockMocks.testDatasetTree, undefined); expect(submitJclSpy).toBeCalled(); expect(mocked(Gui.showMessage)).toBeCalled(); @@ -541,14 +588,14 @@ describe("Jobs Actions Unit Tests - Function submitJcl", () => { }) ); blockMocks.testDatasetTree.getChildren.mockResolvedValueOnce([ - new ZoweDatasetNode("node", vscode.TreeItemCollapsibleState.None, blockMocks.datasetSessionNode, null), + new ZoweDatasetNode("node", vscode.TreeItemCollapsibleState.None, blockMocks.datasetSessionNode, null as any), blockMocks.datasetSessionNode, ]); activeTextEditorDocument.mockReturnValue(blockMocks.textDocument); const submitJclSpy = jest.spyOn(blockMocks.jesApi, "submitJcl"); submitJclSpy.mockClear(); submitJclSpy.mockResolvedValueOnce(blockMocks.iJob); - await dsActions.submitJcl(blockMocks.testDatasetTree); + await dsActions.submitJcl(blockMocks.testDatasetTree, undefined); expect(submitJclSpy).toBeCalled(); expect(mocked(Gui.showMessage)).toBeCalled(); @@ -557,6 +604,42 @@ describe("Jobs Actions Unit Tests - Function submitJcl", () => { "Job submitted [JOB1234](command:zowe.jobs.setJobSpool?%5B%22sestest%22%2C%22JOB1234%22%5D)" ); }); + it("Checking failure of submitting of active text editor content not JCL", async () => { + createGlobalMocks(); + const blockMocks: any = createBlockMocks(); + mocked(zowe.ZosmfSession.createSessCfgFromArgs).mockReturnValue(blockMocks.session); + mocked(Profiles.getInstance).mockReturnValue(blockMocks.profileInstance); + mocked(vscode.window.showQuickPick).mockReturnValueOnce( + new Promise((resolve) => { + resolve(blockMocks.datasetSessionNode.label); + }) + ); + blockMocks.testDatasetTree.getChildren.mockResolvedValueOnce([ + new ZoweDatasetNode("node", vscode.TreeItemCollapsibleState.None, blockMocks.datasetSessionNode, null as any), + blockMocks.datasetSessionNode, + ]); + activeTextEditorDocument.mockReturnValue(blockMocks.textDocument); + (blockMocks.textDocument.languageId as string) = "java"; + await dsActions.submitJcl(blockMocks.testDatasetTree, undefined); + + const errorMsg = "The document being submitted is not a JCL, submission cancelled."; + expect(blockMocks.errorLogSpy).toBeCalledWith(errorMsg); + expect(blockMocks.errorGuiMsgSpy).toBeCalledWith(errorMsg); + }); + // it("Checking failure of submitting JCL via command palette if not active text editor", async () => { + // createGlobalMocks(); + // Object.defineProperty(vscode.workspace, "activeTextEditor", { + // value: jest.fn().mockReturnValue(undefined), + // configurable: true, + // }); + // const blockMocks = createBlockMocks(); + + // await dsActions.submitJcl(blockMocks.testDatasetTree, undefined); + + // const errorMsg = "No editor with a document that could be submitted as JCL is currently open."; + // expect(blockMocks.errorLogSpy).toBeCalledWith(errorMsg); + // expect(blockMocks.errorGuiMsgSpy).toBeCalledWith(errorMsg); + // }); it("Checking failed attempt to submit of active text editor content as JCL without profile chosen from quickpick", async () => { createGlobalMocks(); @@ -565,7 +648,7 @@ describe("Jobs Actions Unit Tests - Function submitJcl", () => { mocked(Profiles.getInstance).mockReturnValue(blockMocks.profileInstance); mocked(vscode.window.showQuickPick).mockResolvedValueOnce(undefined); // Here we imitate the case when no profile was selected blockMocks.testDatasetTree.getChildren.mockResolvedValueOnce([ - new ZoweDatasetNode("node", vscode.TreeItemCollapsibleState.None, blockMocks.datasetSessionNode, null), + new ZoweDatasetNode("node", vscode.TreeItemCollapsibleState.None, blockMocks.datasetSessionNode, null as any), blockMocks.datasetSessionNode, ]); activeTextEditorDocument.mockReturnValue(blockMocks.textDocument); @@ -573,7 +656,7 @@ describe("Jobs Actions Unit Tests - Function submitJcl", () => { const submitJclSpy = jest.spyOn(blockMocks.jesApi, "submitJcl"); submitJclSpy.mockClear(); - await dsActions.submitJcl(blockMocks.testDatasetTree); + await dsActions.submitJcl(blockMocks.testDatasetTree, undefined); expect(submitJclSpy).not.toBeCalled(); expect(messageSpy).toBeCalledWith("Operation Cancelled"); @@ -590,7 +673,7 @@ describe("Jobs Actions Unit Tests - Function submitJcl", () => { }) ); blockMocks.testDatasetTree.getChildren.mockResolvedValueOnce([ - new ZoweDatasetNode("node", vscode.TreeItemCollapsibleState.None, blockMocks.datasetSessionNode, null), + new ZoweDatasetNode("node", vscode.TreeItemCollapsibleState.None, blockMocks.datasetSessionNode, null as any), blockMocks.datasetSessionNode, ]); activeTextEditorDocument.mockReturnValue(blockMocks.textDocument); @@ -598,7 +681,7 @@ describe("Jobs Actions Unit Tests - Function submitJcl", () => { submitJclSpy.mockClear(); const testError = new Error("submitJcl failed"); submitJclSpy.mockRejectedValueOnce(testError); - await dsActions.submitJcl(blockMocks.testDatasetTree); + await dsActions.submitJcl(blockMocks.testDatasetTree, undefined); expect(submitJclSpy).toBeCalled(); expect(mocked(Gui.errorMessage)).toBeCalled(); @@ -632,9 +715,9 @@ describe("Jobs Actions Unit Tests - Function submitMember", () => { createGlobalMocks(); const blockMocks = createBlockMocks(); mocked(Profiles.getInstance).mockReturnValue(blockMocks.profileInstance); - const subNode = new ZoweDatasetNode("dataset", vscode.TreeItemCollapsibleState.Collapsed, blockMocks.datasetSessionNode, null); + const subNode = new ZoweDatasetNode("dataset", vscode.TreeItemCollapsibleState.Collapsed, blockMocks.datasetSessionNode, null as any); subNode.contextValue = globals.DS_PDS_CONTEXT; - const member = new ZoweDatasetNode("member", vscode.TreeItemCollapsibleState.None, subNode, null); + const member = new ZoweDatasetNode("member", vscode.TreeItemCollapsibleState.None, subNode, null as any); member.contextValue = globals.DS_MEMBER_CONTEXT; const submitJobSpy = jest.spyOn(blockMocks.jesApi, "submitJob"); submitJobSpy.mockResolvedValueOnce(blockMocks.iJob); @@ -662,9 +745,9 @@ describe("Jobs Actions Unit Tests - Function submitMember", () => { }; }), }); - const subNode = new ZoweDatasetNode("dataset", vscode.TreeItemCollapsibleState.Collapsed, blockMocks.datasetSessionNode, null); + const subNode = new ZoweDatasetNode("dataset", vscode.TreeItemCollapsibleState.Collapsed, blockMocks.datasetSessionNode, null as any); subNode.contextValue = globals.DS_PDS_CONTEXT; - const member = new ZoweDatasetNode("member", vscode.TreeItemCollapsibleState.None, subNode, null); + const member = new ZoweDatasetNode("member", vscode.TreeItemCollapsibleState.None, subNode, null as any); member.contextValue = globals.DS_MEMBER_CONTEXT; const submitJobSpy = jest.spyOn(blockMocks.jesApi, "submitJob"); submitJobSpy.mockResolvedValueOnce(blockMocks.iJob); @@ -681,7 +764,7 @@ describe("Jobs Actions Unit Tests - Function submitMember", () => { createGlobalMocks(); const blockMocks = createBlockMocks(); mocked(Profiles.getInstance).mockReturnValue(blockMocks.profileInstance); - const dataset = new ZoweDatasetNode("dataset", vscode.TreeItemCollapsibleState.Collapsed, blockMocks.datasetSessionNode, null); + const dataset = new ZoweDatasetNode("dataset", vscode.TreeItemCollapsibleState.Collapsed, blockMocks.datasetSessionNode, null as any); dataset.contextValue = globals.DS_DS_CONTEXT; const submitJobSpy = jest.spyOn(blockMocks.jesApi, "submitJob"); submitJobSpy.mockClear(); @@ -699,11 +782,11 @@ describe("Jobs Actions Unit Tests - Function submitMember", () => { createGlobalMocks(); const blockMocks = createBlockMocks(); mocked(Profiles.getInstance).mockReturnValue(blockMocks.profileInstance); - const favProfileNode = new ZoweDatasetNode("test", vscode.TreeItemCollapsibleState.Collapsed, blockMocks.datasetSessionNode, null); + const favProfileNode = new ZoweDatasetNode("test", vscode.TreeItemCollapsibleState.Collapsed, blockMocks.datasetSessionNode, null as any); favProfileNode.contextValue = globals.FAV_PROFILE_CONTEXT; - const favoriteSubNode = new ZoweDatasetNode("TEST.JCL", vscode.TreeItemCollapsibleState.Collapsed, favProfileNode, null); + const favoriteSubNode = new ZoweDatasetNode("TEST.JCL", vscode.TreeItemCollapsibleState.Collapsed, favProfileNode, null as any); favoriteSubNode.contextValue = globals.DS_PDS_CONTEXT + globals.FAV_SUFFIX; - const favoriteMember = new ZoweDatasetNode(globals.DS_PDS_CONTEXT, vscode.TreeItemCollapsibleState.Collapsed, favoriteSubNode, null); + const favoriteMember = new ZoweDatasetNode(globals.DS_PDS_CONTEXT, vscode.TreeItemCollapsibleState.Collapsed, favoriteSubNode, null as any); favoriteMember.contextValue = globals.DS_MEMBER_CONTEXT; const submitJobSpy = jest.spyOn(blockMocks.jesApi, "submitJob"); submitJobSpy.mockClear(); @@ -721,9 +804,9 @@ describe("Jobs Actions Unit Tests - Function submitMember", () => { createGlobalMocks(); const blockMocks = createBlockMocks(); mocked(Profiles.getInstance).mockReturnValue(blockMocks.profileInstance); - const favProfileNode = new ZoweDatasetNode("test", vscode.TreeItemCollapsibleState.Collapsed, blockMocks.datasetSessionNode, null); + const favProfileNode = new ZoweDatasetNode("test", vscode.TreeItemCollapsibleState.Collapsed, blockMocks.datasetSessionNode, null as any); favProfileNode.contextValue = globals.FAV_PROFILE_CONTEXT; - const favoriteDataset = new ZoweDatasetNode("TEST.JCL", vscode.TreeItemCollapsibleState.Collapsed, favProfileNode, null); + const favoriteDataset = new ZoweDatasetNode("TEST.JCL", vscode.TreeItemCollapsibleState.Collapsed, favProfileNode, null as any); favoriteDataset.contextValue = globals.DS_DS_CONTEXT + globals.FAV_SUFFIX; const submitJobSpy = jest.spyOn(blockMocks.jesApi, "submitJob"); submitJobSpy.mockClear(); @@ -741,9 +824,9 @@ describe("Jobs Actions Unit Tests - Function submitMember", () => { createGlobalMocks(); const blockMocks = createBlockMocks(); mocked(Profiles.getInstance).mockReturnValue(blockMocks.profileInstance); - const corruptedNode = new ZoweDatasetNode("gibberish", vscode.TreeItemCollapsibleState.Collapsed, blockMocks.datasetSessionNode, null); + const corruptedNode = new ZoweDatasetNode("gibberish", vscode.TreeItemCollapsibleState.Collapsed, blockMocks.datasetSessionNode, null as any); corruptedNode.contextValue = "gibberish"; - const corruptedSubNode = new ZoweDatasetNode("gibberishmember", vscode.TreeItemCollapsibleState.Collapsed, corruptedNode, null); + const corruptedSubNode = new ZoweDatasetNode("gibberishmember", vscode.TreeItemCollapsibleState.Collapsed, corruptedNode, null as any); const submitJobSpy = jest.spyOn(blockMocks.jesApi, "submitJob"); submitJobSpy.mockClear(); submitJobSpy.mockResolvedValueOnce(blockMocks.iJob); @@ -764,7 +847,12 @@ describe("Jobs Actions Unit Tests - Function submitMember", () => { const blockMocks = createBlockMocks(); mocked(Profiles.getInstance).mockReturnValue(blockMocks.profileInstance); - const dataset = new ZoweDatasetNode("TESTUSER.DATASET", vscode.TreeItemCollapsibleState.Collapsed, blockMocks.datasetSessionNode, null); + const dataset = new ZoweDatasetNode( + "TESTUSER.DATASET", + vscode.TreeItemCollapsibleState.Collapsed, + blockMocks.datasetSessionNode, + null as any + ); dataset.contextValue = globals.DS_DS_CONTEXT; for (let o = 0; o < sharedUtils.JOB_SUBMIT_DIALOG_OPTS.length; o++) { @@ -801,7 +889,7 @@ describe("Jobs Actions Unit Tests - Function submitMember", () => { } // Test for "Cancel" or closing the dialog - mocked(Gui.warningMessage).mockReturnValueOnce(undefined); + mocked(Gui.warningMessage).mockReturnValueOnce(undefined as any); await dsActions.submitMember(dataset); expect(mocked(Gui.warningMessage)).toBeCalledWith("Are you sure you want to submit the following job?\n\n" + dataset.getLabel(), { items: [{ title: "Submit" }], @@ -933,7 +1021,7 @@ describe("Jobs Actions Unit Tests - Function getSpoolContent", () => { vscode.TreeItemCollapsibleState.None, createJobFavoritesNode(), createISessionWithoutCredentials(), - null, + null as any, createIProfile() ); jest.spyOn(Spool.prototype, "getProfile").mockReturnValue({ @@ -1086,7 +1174,7 @@ describe("Jobs Actions Unit Tests - Function refreshJobsServer", () => { const job = new Job( "jobtest", vscode.TreeItemCollapsibleState.Expanded, - null, + null as any, blockMocks.session, blockMocks.iJob, blockMocks.imperativeProfile @@ -1103,7 +1191,7 @@ describe("Jobs Actions Unit Tests - Function refreshJobsServer", () => { const job = new Job( "jobtest", vscode.TreeItemCollapsibleState.Expanded, - null, + null as any, blockMocks.session, blockMocks.iJob, blockMocks.imperativeProfile @@ -1239,7 +1327,7 @@ describe("job deletion command", () => { const jobsProvider = createJobsTree(session, job, profile, createTreeView()); jobsProvider.delete.mockResolvedValueOnce(Promise.resolve()); - const jobNode = new Job("jobtest", vscode.TreeItemCollapsibleState.Expanded, null, session, job, profile); + const jobNode = new Job("jobtest", vscode.TreeItemCollapsibleState.Expanded, null as any, session, job, profile); await jobActions.deleteCommand(jobsProvider, jobNode); @@ -1253,8 +1341,8 @@ describe("job deletion command", () => { const jobsProvider = createJobsTree(session, job, profile, createTreeView()); jobsProvider.mSessionNodes.push(job2); jobsProvider.delete.mockResolvedValue(Promise.resolve()); - const jobNode1 = new Job("jobtest1", vscode.TreeItemCollapsibleState.Expanded, null, session, job, profile); - const jobNode2 = new Job("jobtest2", vscode.TreeItemCollapsibleState.Expanded, null, session, job2, profile); + const jobNode1 = new Job("jobtest1", vscode.TreeItemCollapsibleState.Expanded, null as any, session, job, profile); + const jobNode2 = new Job("jobtest2", vscode.TreeItemCollapsibleState.Expanded, null as any, session, job2, profile); const jobs = [jobNode1, jobNode2]; // act await jobActions.deleteCommand(jobsProvider, undefined, jobs); @@ -1268,7 +1356,7 @@ describe("job deletion command", () => { const jobsProvider = createJobsTree(session, job, profile, createTreeView()); jobsProvider.delete.mockResolvedValueOnce(Promise.resolve()); - const jobNode = new Job("jobtest", vscode.TreeItemCollapsibleState.Expanded, null, session, job, profile); + const jobNode = new Job("jobtest", vscode.TreeItemCollapsibleState.Expanded, null as any, session, job, profile); await jobActions.deleteCommand(jobsProvider, jobNode); expect(mocked(jobsProvider.delete)).not.toBeCalled(); @@ -1279,7 +1367,7 @@ describe("job deletion command", () => { const jobsProvider = createJobsTree(session, job, profile, createTreeView()); jobsProvider.delete.mockResolvedValueOnce(Promise.reject(new Error("something went wrong!"))); - const jobNode = new Job("jobtest", vscode.TreeItemCollapsibleState.Expanded, null, session, job, profile); + const jobNode = new Job("jobtest", vscode.TreeItemCollapsibleState.Expanded, null as any, session, job, profile); // act await jobActions.deleteCommand(jobsProvider, jobNode); // assert @@ -1292,7 +1380,7 @@ describe("job deletion command", () => { const jobsProvider = createJobsTree(session, job, profile, createTreeView()); jobsProvider.delete.mockResolvedValueOnce(Promise.resolve()); - const jobNode = new Job("jobtest", vscode.TreeItemCollapsibleState.Expanded, null, session, job, profile); + const jobNode = new Job("jobtest", vscode.TreeItemCollapsibleState.Expanded, null as any, session, job, profile); jobsProvider.getTreeView.mockReturnValueOnce({ ...jobsProvider.getTreeView(), selection: [jobNode] }); // act await jobActions.deleteCommand(jobsProvider, undefined); @@ -1307,7 +1395,7 @@ describe("Job Actions Unit Tests - Misc. functions", () => { const session = createISession(); const profile = createIProfile(); const job = createIJobObject(); - const jobNode = new Job("job", vscode.TreeItemCollapsibleState.None, null, session, job, profile); + const jobNode = new Job("job", vscode.TreeItemCollapsibleState.None, null as any, session, job, profile); it("refreshJob works as intended", () => { const jobsProvider = createJobsTree(session, job, profile, createTreeView()); @@ -1363,8 +1451,8 @@ describe("sortjobsby function", () => { const globalMocks = createGlobalMocks(); const testtree = new ZosJobsProvider(); const expected = new ZosJobsProvider(); - testtree.mSessionNodes[0].children = [...[globalMocks()[2], globalMocks()[1], globalMocks()[0]]]; - expected.mSessionNodes[0].children = [...[globalMocks()[1], globalMocks()[0], globalMocks()[2]]]; + testtree.mSessionNodes[0].children = [...[globalMocks.mockJobArray[2], globalMocks.mockJobArray[1], globalMocks.mockJobArray[0]]]; + expected.mSessionNodes[0].children = [...[globalMocks.mockJobArray[1], globalMocks.mockJobArray[0], globalMocks.mockJobArray[2]]]; const sortbynamespy = jest.spyOn(jobActions, "sortJobsBy"); //act await jobActions.sortJobsBy(testtree.mSessionNodes[0], testtree, "jobname"); @@ -1377,8 +1465,8 @@ describe("sortjobsby function", () => { const globalMocks = createGlobalMocks(); const testtree = new ZosJobsProvider(); const expected = new ZosJobsProvider(); - testtree.mSessionNodes[0].children = [...[globalMocks()[2], globalMocks()[1], globalMocks()[0]]]; - expected.mSessionNodes[0].children = [...[globalMocks()[1], globalMocks()[0], globalMocks()[2]]]; + testtree.mSessionNodes[0].children = [...[globalMocks.mockJobArray[2], globalMocks.mockJobArray[1], globalMocks.mockJobArray[0]]]; + expected.mSessionNodes[0].children = [...[globalMocks.mockJobArray[1], globalMocks.mockJobArray[0], globalMocks.mockJobArray[2]]]; const sortbyidspy = jest.spyOn(jobActions, "sortJobsBy"); //act await jobActions.sortJobsBy(testtree.mSessionNodes[0], testtree, "jobid"); @@ -1391,8 +1479,8 @@ describe("sortjobsby function", () => { const globalMocks = createGlobalMocks(); const testtree = new ZosJobsProvider(); const expected = new ZosJobsProvider(); - testtree.mSessionNodes[0].children = [...[globalMocks()[2], globalMocks()[1], globalMocks()[0]]]; - expected.mSessionNodes[0].children = [...[globalMocks()[0], globalMocks()[1], globalMocks()[2]]]; + testtree.mSessionNodes[0].children = [...[globalMocks.mockJobArray[2], globalMocks.mockJobArray[1], globalMocks.mockJobArray[0]]]; + expected.mSessionNodes[0].children = [...[globalMocks.mockJobArray[0], globalMocks.mockJobArray[1], globalMocks.mockJobArray[2]]]; const sortbyretcodespy = jest.spyOn(jobActions, "sortJobsBy"); //act await jobActions.sortJobsBy(testtree.mSessionNodes[0], testtree, "retcode"); diff --git a/packages/zowe-explorer/package.json b/packages/zowe-explorer/package.json index b79b9c3b1d..e4d81203f0 100644 --- a/packages/zowe-explorer/package.json +++ b/packages/zowe-explorer/package.json @@ -824,14 +824,14 @@ ], "editor/context": [ { - "when": "resourceLangId == jcl", + "when": "resourceLangId =~ /^.*jcl.*/i", "command": "zowe.ds.submitJcl", "group": "000_zowe_dsMainframeInteraction@1" } ], "explorer/context": [ { - "when": "resourceLangId == jcl", + "when": "resourceLangId =~ /^.*jcl.*/i", "command": "zowe.ds.submitJcl", "group": "000_zowe_dsMainframeInteraction@1" } diff --git a/packages/zowe-explorer/src/dataset/actions.ts b/packages/zowe-explorer/src/dataset/actions.ts index aa7d712e40..d555694ead 100644 --- a/packages/zowe-explorer/src/dataset/actions.ts +++ b/packages/zowe-explorer/src/dataset/actions.ts @@ -967,15 +967,15 @@ export async function showAttributes(node: api.IZoweDatasetTreeNode, datasetProv } /** - * Submit the contents of the editor as JCL. + * Submit the contents of the editor or file as JCL. * * @export * @param {DatasetTree} datasetProvider - our DatasetTree object */ // This function does not appear to currently be made available in the UI -export async function submitJcl(datasetProvider: api.IZoweTree): Promise { +export async function submitJcl(datasetProvider: api.IZoweTree, file?: vscode.Uri): Promise { ZoweLogger.trace("dataset.actions.submitJcl called."); - if (!vscode.window.activeTextEditor) { + if (!vscode.window.activeTextEditor && !file) { const notActiveEditorMsg = localize( "submitJcl.notActiveEditorMsg", "No editor with a document that could be submitted as JCL is currently open." @@ -984,8 +984,14 @@ export async function submitJcl(datasetProvider: api.IZoweTree datasetProvider.removeFavProfile(node.label, true)) ); - context.subscriptions.push(vscode.commands.registerCommand("zowe.ds.submitJcl", async () => dsActions.submitJcl(datasetProvider))); + context.subscriptions.push(vscode.commands.registerCommand("zowe.ds.submitJcl", async (file) => dsActions.submitJcl(datasetProvider, file))); context.subscriptions.push(vscode.commands.registerCommand("zowe.ds.submitMember", async (node) => dsActions.submitMember(node))); context.subscriptions.push( vscode.commands.registerCommand("zowe.ds.showAttributes", async (node, nodeList) => { From f04ea4580c34f9134d984e4ac4ebbd2193429e28 Mon Sep 17 00:00:00 2001 From: Rudy Flores <68666202+rudyflores@users.noreply.github.com> Date: Wed, 11 Oct 2023 15:44:37 -0400 Subject: [PATCH 120/189] multi-select deletion support Signed-off-by: Rudy Flores <68666202+rudyflores@users.noreply.github.com> --- .../zowe-explorer/src/shared/HistoryView.ts | 12 +++++- .../PersistentTable/PersistentDataPanel.tsx | 19 ++++++++- .../PersistentTable/PersistentTableData.tsx | 40 +++++++++++-------- .../PersistentDeleteSelectedButton.tsx | 35 ++++++++++++++++ .../PersistentToolBar/PersistentToolBar.tsx | 2 + .../src/webviews/src/edit-history/types.ts | 4 ++ 6 files changed, 91 insertions(+), 21 deletions(-) create mode 100644 packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentToolBar/PersistentDeleteSelectedButton.tsx diff --git a/packages/zowe-explorer/src/shared/HistoryView.ts b/packages/zowe-explorer/src/shared/HistoryView.ts index 337c28963a..2c3da383e8 100644 --- a/packages/zowe-explorer/src/shared/HistoryView.ts +++ b/packages/zowe-explorer/src/shared/HistoryView.ts @@ -121,11 +121,19 @@ export class HistoryView extends WebView { const treeProvider = this.getTreeProvider(message.attrs.type); switch (message.attrs.selection) { case "search": - treeProvider.removeSearchHistory(message.attrs.name); + Object.keys(message.attrs.selectedItems).forEach((selectedItem) => { + if (message.attrs.selectedItems[selectedItem]) { + treeProvider.removeSearchHistory(selectedItem); + } + }); break; case "fileHistory": if (!(treeProvider instanceof ZosJobsProvider)) { - treeProvider.removeFileHistory(message.attrs.name); + Object.keys(message.attrs.selectedItems).forEach((selectedItem) => { + if (message.attrs.selectedItems[selectedItem]) { + treeProvider.removeFileHistory(selectedItem); + } + }); } break; default: diff --git a/packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentTable/PersistentDataPanel.tsx b/packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentTable/PersistentDataPanel.tsx index 7ea1375897..23d1b39f6c 100644 --- a/packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentTable/PersistentDataPanel.tsx +++ b/packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentTable/PersistentDataPanel.tsx @@ -9,7 +9,7 @@ * */ -import { useEffect, useState } from "preact/hooks"; +import { useEffect, useMemo, useState } from "preact/hooks"; import { VSCodePanelView, VSCodeDataGrid } from "@vscode/webview-ui-toolkit/react"; import { JSXInternal } from "preact/src/jsx"; import { DataPanelContext, isSecureOrigin } from "../PersistentUtils"; @@ -23,6 +23,15 @@ export default function PersistentDataPanel({ type }: { type: string }): JSXInte const [data, setData] = useState<{ [type: string]: { [property: string]: string[] } }>({ ds: {}, uss: {}, jobs: {} }); const [selection, setSelection] = useState<{ [type: string]: string }>({ [type]: "search" }); const [persistentProp, setPersistentProp] = useState([]); + const [selectedItems, setSelectedItems] = useState({}); + + const selectedItemsMemo = useMemo( + () => ({ + val: selectedItems, + setVal: (newVal: any) => setSelectedItems(newVal), + }), + [selectedItems] + ); const handleChange = (newSelection: string) => { setSelection(() => ({ [type]: newSelection })); @@ -33,6 +42,12 @@ export default function PersistentDataPanel({ type }: { type: string }): JSXInte type, }, }); + + const newSelectedItems: { [key: string]: boolean } = { ...selectedItemsMemo.val }; + Object.keys(newSelectedItems).forEach((item) => { + newSelectedItems[item] = false; + }); + selectedItemsMemo.setVal(newSelectedItems); }; useEffect(() => { @@ -60,7 +75,7 @@ export default function PersistentDataPanel({ type }: { type: string }): JSXInte }, [selection]); return ( - + diff --git a/packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentTable/PersistentTableData.tsx b/packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentTable/PersistentTableData.tsx index b1690a6155..4fb76e6762 100644 --- a/packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentTable/PersistentTableData.tsx +++ b/packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentTable/PersistentTableData.tsx @@ -9,29 +9,35 @@ * */ -import { VSCodeDataGridCell, VSCodeDataGridRow } from "@vscode/webview-ui-toolkit/react"; +import { VSCodeCheckbox, VSCodeDataGridCell, VSCodeDataGridRow } from "@vscode/webview-ui-toolkit/react"; import { JSXInternal } from "preact/src/jsx"; import { useDataPanelContext } from "../PersistentUtils"; -import PersistentVSCodeAPI from "../PersistentVSCodeAPI"; +import { useEffect, useState } from "preact/hooks"; +import isEqual from "lodash.isequal"; export default function PersistentTableData({ persistentProp }: { persistentProp: string[] }): JSXInternal.Element { - const { type, selection } = useDataPanelContext(); - - const handleClick = (item: number) => { - PersistentVSCodeAPI.getVSCodeAPI().postMessage({ - command: "remove-item", - attrs: { - name: persistentProp[item], - type, - selection: selection[type], - }, - }); + const { type, selection, selectedItems } = useDataPanelContext(); + const [oldPersistentProp, setOldPersistentProp] = useState([]); + + useEffect(() => { + if (!isEqual(oldPersistentProp, persistentProp) && persistentProp) { + const newSelectedItemsList: { [key: string]: boolean } = {}; + persistentProp.forEach((prop) => { + newSelectedItemsList[prop] = false; + }); + selectedItems.setVal(newSelectedItemsList); + setOldPersistentProp(persistentProp); + } + }, [persistentProp]); + + const handleClick = (event: any, item: number) => { + selectedItems.setVal({ ...selectedItems.val, [persistentProp[item]]: !event.target.checked }); }; - const renderDeleteButton = (i: number) => { + const renderDeleteButton = (item: string, i: number) => { return selection[type] === "search" || selection[type] === "fileHistory" ? ( - handleClick(i)} style={{ maxWidth: "20vw", textAlign: "center" }}> - + + handleClick(event, i)}> ) : null; }; @@ -41,7 +47,7 @@ export default function PersistentTableData({ persistentProp }: { persistentProp return ( {item} - {renderDeleteButton(i)} + {renderDeleteButton(item, i)} ); }); diff --git a/packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentToolBar/PersistentDeleteSelectedButton.tsx b/packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentToolBar/PersistentDeleteSelectedButton.tsx new file mode 100644 index 0000000000..0b461c49e7 --- /dev/null +++ b/packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentToolBar/PersistentDeleteSelectedButton.tsx @@ -0,0 +1,35 @@ +import { VSCodeButton } from "@vscode/webview-ui-toolkit/react"; +import { JSXInternal } from "preact/src/jsx"; +import * as nls from "vscode-nls"; +import PersistentVSCodeAPI from "../PersistentVSCodeAPI"; +import { useDataPanelContext } from "../PersistentUtils"; + +const localize: nls.LocalizeFunc = nls.loadMessageBundle(); + +export default function PersistentDeleteSelectedButton(): JSXInternal.Element { + const deleteSelectedText = localize("PersistentDeleteSelectedButton.deleteSelected", "Delete Selected"); + const { selection, type, selectedItems } = useDataPanelContext(); + + const handleClick = () => { + PersistentVSCodeAPI.getVSCodeAPI().postMessage({ + command: "remove-item", + attrs: { + selectedItems: selectedItems.val, + selection: selection[type], + type, + }, + }); + + const newSelectedItems: { [key: string]: boolean } = { ...selectedItems.val }; + Object.keys(newSelectedItems).forEach((item) => { + newSelectedItems[item] = false; + }); + selectedItems.setVal(newSelectedItems); + }; + + return ( + + + + ); +} diff --git a/packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentToolBar/PersistentToolBar.tsx b/packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentToolBar/PersistentToolBar.tsx index ad8f760f91..6e5d745833 100644 --- a/packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentToolBar/PersistentToolBar.tsx +++ b/packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentToolBar/PersistentToolBar.tsx @@ -14,6 +14,7 @@ import PersistentClearAllButton from "./PersistentClearAllButton"; import PersistentRefreshButton from "./PersistentRefreshButton"; import PersistentDropdownOptions from "./PersistentDropdownOptions"; import PersistentAddNewHistoryItemButton from "./PersistentAddNewHistoryItemButton"; +import PersistentDeleteSelectedButton from "./PersistentDeleteSelectedButton"; export default function PersistentToolBar({ handleChange }: { handleChange: Function }): JSXInternal.Element { return ( @@ -22,6 +23,7 @@ export default function PersistentToolBar({ handleChange }: { handleChange: Func +
); } diff --git a/packages/zowe-explorer/src/webviews/src/edit-history/types.ts b/packages/zowe-explorer/src/webviews/src/edit-history/types.ts index b00005125b..77e6d08087 100644 --- a/packages/zowe-explorer/src/webviews/src/edit-history/types.ts +++ b/packages/zowe-explorer/src/webviews/src/edit-history/types.ts @@ -18,4 +18,8 @@ export const panelId: { [key: string]: string } = { export type DataPanelContextType = { type: string; selection: { [type: string]: string }; + selectedItems: { + val: { [type: string]: boolean }; + setVal: (newVal: any) => void; + }; }; From fb9eb13c85147a1700d3fe4d387b8fdd49c4a1ce Mon Sep 17 00:00:00 2001 From: Billie Simmons <49491949+JillieBeanSim@users.noreply.github.com> Date: Wed, 11 Oct 2023 15:53:01 -0400 Subject: [PATCH 121/189] clean up some duplication in test file Signed-off-by: Billie Simmons <49491949+JillieBeanSim@users.noreply.github.com> --- .../__unit__/job/actions.unit.test.ts | 139 +++--------------- 1 file changed, 20 insertions(+), 119 deletions(-) diff --git a/packages/zowe-explorer/__tests__/__unit__/job/actions.unit.test.ts b/packages/zowe-explorer/__tests__/__unit__/job/actions.unit.test.ts index 3f99de5765..5ec985c41f 100644 --- a/packages/zowe-explorer/__tests__/__unit__/job/actions.unit.test.ts +++ b/packages/zowe-explorer/__tests__/__unit__/job/actions.unit.test.ts @@ -11,7 +11,7 @@ import * as vscode from "vscode"; import * as zowe from "@zowe/cli"; -import { Gui, IZoweJobTreeNode, ValidProfileEnum } from "@zowe/zowe-explorer-api"; +import { Gui, IZoweJobTreeNode, IZoweTree, ValidProfileEnum } from "@zowe/zowe-explorer-api"; import { Job, Spool } from "../../../src/job/ZoweJobNode"; import { createISession, @@ -47,6 +47,10 @@ const activeTextEditorDocument = jest.fn(); function createGlobalMocks() { const newMocks = { + session: createISession(), + treeView: createTreeView(), + iJob: createIJobObject(), + imperativeProfile: createIProfile(), JobNode1: new Job( "testProfile", vscode.TreeItemCollapsibleState.None, @@ -72,8 +76,13 @@ function createGlobalMocks() { createIProfile() ), mockJobArray: [], + testJobsTree: null as any, + jesApi: null as any, }; + newMocks.testJobsTree = createJobsTree(newMocks.session, newMocks.iJob, newMocks.imperativeProfile, newMocks.treeView); newMocks.mockJobArray = [newMocks.JobNode1, newMocks.JobNode2, newMocks.JobNode3] as any; + newMocks.jesApi = createJesApi(newMocks.imperativeProfile); + bindJesApi(newMocks.jesApi); Object.defineProperty(vscode.workspace, "getConfiguration", { value: jest.fn().mockImplementation(() => new Map([["zowe.jobs.confirmSubmission", false]])), configurable: true, @@ -133,24 +142,8 @@ afterEach(() => { }); describe("Jobs Actions Unit Tests - Function setPrefix", () => { - function createBlockMocks() { - const session = createISession(); - const treeView = createTreeView(); - const iJob = createIJobObject(); - const imperativeProfile = createIProfile(); - - return { - session, - treeView, - iJob, - imperativeProfile, - testJobsTree: createJobsTree(session, iJob, imperativeProfile, treeView), - }; - } - it("Checking that the prefix is set correctly on the job", async () => { - createGlobalMocks(); - const blockMocks = createBlockMocks(); + const blockMocks = createGlobalMocks(); const node = new Job("job", vscode.TreeItemCollapsibleState.None, null as any, blockMocks.session, null as any, null as any); const mySpy = mocked(vscode.window.showInputBox).mockResolvedValue("*"); @@ -168,24 +161,8 @@ describe("Jobs Actions Unit Tests - Function setPrefix", () => { }); describe("Jobs Actions Unit Tests - Function setOwner", () => { - function createBlockMocks() { - const session = createISession(); - const treeView = createTreeView(); - const iJob = createIJobObject(); - const imperativeProfile = createIProfile(); - - return { - session, - treeView, - iJob, - imperativeProfile, - testJobsTree: createJobsTree(session, iJob, imperativeProfile, treeView), - }; - } - it("Checking that the owner is set correctly on the job", async () => { - createGlobalMocks(); - const blockMocks = createBlockMocks(); + const blockMocks = createGlobalMocks(); const node = new Job( "job", vscode.TreeItemCollapsibleState.None, @@ -210,21 +187,8 @@ describe("Jobs Actions Unit Tests - Function setOwner", () => { }); describe("Jobs Actions Unit Tests - Function stopCommand", () => { - function createBlockMocks() { - const session = createISession(); - const iJob = createIJobObject(); - const imperativeProfile = createIProfile(); - - return { - session, - iJob, - imperativeProfile, - }; - } - it("Checking that stop command of Job Node is executed properly", async () => { - createGlobalMocks(); - const blockMocks = createBlockMocks(); + const blockMocks = createGlobalMocks(); const node = new Job( "job", vscode.TreeItemCollapsibleState.None, @@ -244,8 +208,7 @@ describe("Jobs Actions Unit Tests - Function stopCommand", () => { expect(mocked(Gui.showMessage).mock.calls[0][0]).toEqual("Command response: fake response"); }); it("Checking failed attempt to issue stop command for Job Node.", async () => { - createGlobalMocks(); - const blockMocks = createBlockMocks(); + const blockMocks = createGlobalMocks(); const node = new Job( "job", vscode.TreeItemCollapsibleState.None, @@ -265,21 +228,8 @@ describe("Jobs Actions Unit Tests - Function stopCommand", () => { }); describe("Jobs Actions Unit Tests - Function modifyCommand", () => { - function createBlockMocks() { - const session = createISession(); - const iJob = createIJobObject(); - const imperativeProfile = createIProfile(); - - return { - session, - iJob, - imperativeProfile, - }; - } - it("Checking modification of Job Node", async () => { - createGlobalMocks(); - const blockMocks = createBlockMocks(); + const blockMocks = createGlobalMocks(); const node = new Job( "job", vscode.TreeItemCollapsibleState.None, @@ -300,8 +250,7 @@ describe("Jobs Actions Unit Tests - Function modifyCommand", () => { expect(mocked(Gui.showMessage).mock.calls[0][0]).toEqual("Command response: fake response"); }); it("Checking failed attempt to modify Job Node", async () => { - createGlobalMocks(); - const blockMocks = createBlockMocks(); + const blockMocks = createGlobalMocks(); const node = new Job( "job", vscode.TreeItemCollapsibleState.None, @@ -322,24 +271,8 @@ describe("Jobs Actions Unit Tests - Function modifyCommand", () => { }); describe("Jobs Actions Unit Tests - Function downloadSpool", () => { - function createBlockMocks() { - const session = createISession(); - const iJob = createIJobObject(); - const imperativeProfile = createIProfile(); - const jesApi = createJesApi(imperativeProfile); - bindJesApi(jesApi); - - return { - session, - iJob, - imperativeProfile, - jesApi, - }; - } - it("Checking download of Job Spool", async () => { - createGlobalMocks(); - const blockMocks = createBlockMocks(); + const blockMocks = createGlobalMocks(); const jobs: Job[] = []; const node = new Job( "job", @@ -372,7 +305,6 @@ describe("Jobs Actions Unit Tests - Function downloadSpool", () => { }); it("Checking failed attempt to download Job Spool", async () => { createGlobalMocks(); - const blockMocks = createBlockMocks(); const fileUri = { fsPath: "/tmp/foo", scheme: "", @@ -388,24 +320,8 @@ describe("Jobs Actions Unit Tests - Function downloadSpool", () => { }); describe("Jobs Actions Unit Tests - Function downloadSingleSpool", () => { - function createBlockMocks() { - const session = createISession(); - const iJob = createIJobObject(); - const imperativeProfile = createIProfile(); - const jesApi = createJesApi(imperativeProfile); - bindJesApi(jesApi); - - return { - session, - iJob, - imperativeProfile, - jesApi, - }; - } - it("Checking download of Job Spool", async () => { - createGlobalMocks(); - const blockMocks = createBlockMocks(); + const blockMocks = createGlobalMocks(); const iJobFile = createIJobFile(); const jobs: Job[] = []; const node = new Job( @@ -442,8 +358,7 @@ describe("Jobs Actions Unit Tests - Function downloadSingleSpool", () => { }); it("should fail to download single spool files if the extender has not implemented the operation", async () => { - createGlobalMocks(); - const blockMocks = createBlockMocks(); + const blockMocks = createGlobalMocks(); const iJobFile = createIJobFile(); const jobs: Job[] = []; const node = new Job( @@ -477,21 +392,8 @@ describe("Jobs Actions Unit Tests - Function downloadSingleSpool", () => { }); describe("Jobs Actions Unit Tests - Function downloadJcl", () => { - function createBlockMocks() { - const session = createISession(); - const iJob = createIJobObject(); - const imperativeProfile = createIProfile(); - - return { - session, - iJob, - imperativeProfile, - }; - } - it("Checking download of Job JCL", async () => { - createGlobalMocks(); - const blockMocks = createBlockMocks(); + const blockMocks = createGlobalMocks(); const node = new Job( "job", vscode.TreeItemCollapsibleState.None, @@ -507,7 +409,6 @@ describe("Jobs Actions Unit Tests - Function downloadJcl", () => { }); it("Checking failed attempt to download Job JCL", async () => { createGlobalMocks(); - const blockMocks = createBlockMocks(); await jobActions.downloadJcl(undefined as any); expect(mocked(Gui.errorMessage)).toBeCalled(); }); From 88384ebc129767e7b9c105a7037a91bef13d450a Mon Sep 17 00:00:00 2001 From: Rudy Flores <68666202+rudyflores@users.noreply.github.com> Date: Thu, 12 Oct 2023 10:36:32 -0400 Subject: [PATCH 122/189] error handling Signed-off-by: Rudy Flores <68666202+rudyflores@users.noreply.github.com> --- .../sample/src/shared/HistoryView.i18n.json | 2 +- packages/zowe-explorer/package.json | 2 +- .../zowe-explorer/src/shared/HistoryView.ts | 10 +++++- .../PersistentDeleteSelectedButton.tsx | 32 +++++++++++++++---- 4 files changed, 37 insertions(+), 9 deletions(-) diff --git a/packages/zowe-explorer/i18n/sample/src/shared/HistoryView.i18n.json b/packages/zowe-explorer/i18n/sample/src/shared/HistoryView.i18n.json index e8a920e719..396eec3ae3 100644 --- a/packages/zowe-explorer/i18n/sample/src/shared/HistoryView.i18n.json +++ b/packages/zowe-explorer/i18n/sample/src/shared/HistoryView.i18n.json @@ -1,7 +1,7 @@ { "HistoryView.addItem.prompt": "Type the new pattern to add to history", "HistoryView.removeItem.notSupported": "action is not supported for this property type.", - "HistoryView.clearAll.confirmMessage": "Clear all history contents for this persistent property?", + "HistoryView.clearAll.confirmMessage": "Clear all history items for this persistent property?", "HistoryView.clearAll.Yes": "Yes", "HistoryView.clearAll.No": "No" } diff --git a/packages/zowe-explorer/package.json b/packages/zowe-explorer/package.json index 457006e076..c72d2b4414 100644 --- a/packages/zowe-explorer/package.json +++ b/packages/zowe-explorer/package.json @@ -1977,7 +1977,7 @@ "updateStrings": "node ../../scripts/stringUpdateScript.js && prettier --write --loglevel warn ./i18n package.nls*", "package": "vsce package --allow-star-activation --yarn && node ../../scripts/mv-pack.js vscode-extension-for-zowe vsix", "license": "node ../../scripts/updateLicenses.js", - "watch": "concurrently -n \"yarn run watch:webviews\" \"yarn run watch:zowe-explorer\"", + "watch": "concurrently \"yarn run watch:webviews\" \"yarn run watch:zowe-explorer\"", "watch:zowe-explorer": "gulp build && webpack --mode development --watch --info-verbosity verbose", "watch:webviews": "yarn workspace webviews dev", "compile": "tsc -b", diff --git a/packages/zowe-explorer/src/shared/HistoryView.ts b/packages/zowe-explorer/src/shared/HistoryView.ts index 2c3da383e8..d4f0b08620 100644 --- a/packages/zowe-explorer/src/shared/HistoryView.ts +++ b/packages/zowe-explorer/src/shared/HistoryView.ts @@ -63,6 +63,9 @@ export class HistoryView extends WebView { selection: this.currentSelection, }); break; + case "show-error": + this.showError(message); + break; case "update-selection": this.updateSelection(message); break; @@ -95,6 +98,11 @@ export class HistoryView extends WebView { }; } + private showError(message): void { + ZoweLogger.trace("HistoryView.showError called."); + Gui.errorMessage(message.attrs.errorMsg); + } + private updateSelection(message): void { ZoweLogger.trace("HistoryView.updateSelection called."); this.currentSelection[message.attrs.type] = message.attrs.selection; @@ -146,7 +154,7 @@ export class HistoryView extends WebView { private async clearAll(message): Promise { ZoweLogger.trace("HistoryView.clearAll called."); const treeProvider = this.getTreeProvider(message.attrs.type); - const infoMessage = localize("HistoryView.clearAll.confirmMessage", "Clear all history contents for this persistent property?"); + const infoMessage = localize("HistoryView.clearAll.confirmMessage", "Clear all history items for this persistent property?"); const yesButton = localize("HistoryView.clearAll.Yes", "Yes"); const noButton = localize("HistoryView.clearAll.No", "No"); const choice = await Gui.showMessage(infoMessage, { items: [yesButton, noButton], vsCodeOpts: { modal: true } }); diff --git a/packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentToolBar/PersistentDeleteSelectedButton.tsx b/packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentToolBar/PersistentDeleteSelectedButton.tsx index 0b461c49e7..0f2b4c0d2a 100644 --- a/packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentToolBar/PersistentDeleteSelectedButton.tsx +++ b/packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentToolBar/PersistentDeleteSelectedButton.tsx @@ -10,7 +10,18 @@ export default function PersistentDeleteSelectedButton(): JSXInternal.Element { const deleteSelectedText = localize("PersistentDeleteSelectedButton.deleteSelected", "Delete Selected"); const { selection, type, selectedItems } = useDataPanelContext(); - const handleClick = () => { + const handleClick = async () => { + const hasSelectedItems = Object.keys(selectedItems.val).find((item) => selectedItems.val[item] === true); + if (!hasSelectedItems) { + PersistentVSCodeAPI.getVSCodeAPI().postMessage({ + command: "show-error", + attrs: { + errorMsg: localize("PersistentDeleteSelectedButton.handleClick.error", "Select an item before deleting"), + }, + }); + return; + } + PersistentVSCodeAPI.getVSCodeAPI().postMessage({ command: "remove-item", attrs: { @@ -27,9 +38,18 @@ export default function PersistentDeleteSelectedButton(): JSXInternal.Element { selectedItems.setVal(newSelectedItems); }; - return ( - - - - ); + const renderDeleteSelectedButton = () => { + return selection[type] === "search" || selection[type] === "fileHistory" ? ( + await handleClick()} + > + + + ) : null; + }; + + return <>{renderDeleteSelectedButton()}; } From 810bc6f271896a4eca28dd847da09eb8edcc29a3 Mon Sep 17 00:00:00 2001 From: Trae Yelovich Date: Thu, 12 Oct 2023 13:54:56 -0400 Subject: [PATCH 123/189] fix(jobs/sort): Proper handling for jobs with null retcodes Signed-off-by: Trae Yelovich --- packages/zowe-explorer/src/job/ZoweJobNode.ts | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/packages/zowe-explorer/src/job/ZoweJobNode.ts b/packages/zowe-explorer/src/job/ZoweJobNode.ts index 3db60de46b..8c49527eee 100644 --- a/packages/zowe-explorer/src/job/ZoweJobNode.ts +++ b/packages/zowe-explorer/src/job/ZoweJobNode.ts @@ -250,11 +250,22 @@ export class Job extends ZoweTreeNode implements IZoweJobTreeNode { const sortGreaterThan = sortLessThan * -1; const keyToSortBy = JOB_SORT_KEYS[sortOpts.method]; - if (keyToSortBy !== "jobid" && x["job"][keyToSortBy] == y["job"][keyToSortBy]) { - return x["job"]["jobid"] > y["job"]["jobid"] ? sortGreaterThan : sortLessThan; + let xCompare, yCompare; + if (keyToSortBy === "retcode") { + // some jobs (such as active ones) will have a null retcode + // in this case, use status as the key to compare for that node only + xCompare = x.job["retcode"] == null ? x.job["status"] : x.job["retcode"]; + yCompare = y.job["retcode"] == null ? y.job["status"] : y.job["retcode"]; } else { - return x["job"][keyToSortBy] > y["job"][keyToSortBy] ? sortGreaterThan : sortLessThan; + xCompare = x.job[keyToSortBy]; + yCompare = y.job[keyToSortBy]; } + + if (xCompare === yCompare) { + return x.job["jobid"] > y.job["jobid"] ? sortGreaterThan : sortLessThan; + } + + return xCompare > yCompare ? sortGreaterThan : sortLessThan; }; } From aed4ae03096fd6aa4126f6bde99a457688ef7d4d Mon Sep 17 00:00:00 2001 From: Trae Yelovich Date: Thu, 12 Oct 2023 15:41:45 -0400 Subject: [PATCH 124/189] fix(jobs/sort): use nullish coalescing for retcode/status check Signed-off-by: Trae Yelovich --- packages/zowe-explorer/src/job/ZoweJobNode.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/zowe-explorer/src/job/ZoweJobNode.ts b/packages/zowe-explorer/src/job/ZoweJobNode.ts index 8c49527eee..0ac960be2a 100644 --- a/packages/zowe-explorer/src/job/ZoweJobNode.ts +++ b/packages/zowe-explorer/src/job/ZoweJobNode.ts @@ -254,8 +254,8 @@ export class Job extends ZoweTreeNode implements IZoweJobTreeNode { if (keyToSortBy === "retcode") { // some jobs (such as active ones) will have a null retcode // in this case, use status as the key to compare for that node only - xCompare = x.job["retcode"] == null ? x.job["status"] : x.job["retcode"]; - yCompare = y.job["retcode"] == null ? y.job["status"] : y.job["retcode"]; + xCompare = x.job["retcode"] ?? x.job["status"]; + yCompare = y.job["retcode"] ?? y.job["status"]; } else { xCompare = x.job[keyToSortBy]; yCompare = y.job[keyToSortBy]; From aefb07e0a19ac46ac8beb6986c805a35129f3ae4 Mon Sep 17 00:00:00 2001 From: Rudy Flores <68666202+rudyflores@users.noreply.github.com> Date: Thu, 12 Oct 2023 15:58:36 -0400 Subject: [PATCH 125/189] add webview to menu options Signed-off-by: Rudy Flores <68666202+rudyflores@users.noreply.github.com> --- .../i18n/sample/package.i18n.json | 2 +- packages/zowe-explorer/package.json | 19 ++++++++++++++-- packages/zowe-explorer/package.nls.json | 2 +- .../zowe-explorer/resources/dark/history.svg | 3 +++ .../zowe-explorer/resources/light/history.svg | 3 +++ .../src/edit-history/assets/checklist.svg | 3 +++ .../PersistentDataGridHeaders.tsx | 6 ++--- .../PersistentTable/PersistentTableData.tsx | 4 ++-- .../PersistentSelectAllButton.tsx | 22 +++++++++++++++++++ .../PersistentToolBar/PersistentToolBar.tsx | 2 ++ 10 files changed, 57 insertions(+), 9 deletions(-) create mode 100644 packages/zowe-explorer/resources/dark/history.svg create mode 100644 packages/zowe-explorer/resources/light/history.svg create mode 100644 packages/zowe-explorer/src/webviews/src/edit-history/assets/checklist.svg create mode 100644 packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentToolBar/PersistentSelectAllButton.tsx diff --git a/packages/zowe-explorer/i18n/sample/package.i18n.json b/packages/zowe-explorer/i18n/sample/package.i18n.json index 2b99224dd7..8e9980e1d9 100644 --- a/packages/zowe-explorer/i18n/sample/package.i18n.json +++ b/packages/zowe-explorer/i18n/sample/package.i18n.json @@ -4,7 +4,7 @@ "viewsContainers.activitybar": "Zowe Explorer", "zowe.promptCredentials": "Update Credentials", "zowe.extRefresh": "Refresh Zowe Explorer", - "zowe.editHistory": "Edit History for Zowe Explorer", + "zowe.editHistory": "Edit History", "zowe.ds.explorer": "Data Sets", "zowe.uss.explorer": "Unix System Services (USS)", "zowe.jobs.explorer": "Jobs", diff --git a/packages/zowe-explorer/package.json b/packages/zowe-explorer/package.json index c72d2b4414..53598dbe77 100644 --- a/packages/zowe-explorer/package.json +++ b/packages/zowe-explorer/package.json @@ -160,8 +160,8 @@ "title": "%zowe.editHistory%", "category": "Zowe Explorer", "icon": { - "light": "./resources/light/refresh.svg", - "dark": "./resources/dark/refresh.svg" + "light": "./resources/light/history.svg", + "dark": "./resources/dark/history.svg" } }, { @@ -992,6 +992,11 @@ "command": "zowe.uss.ssoLogout", "group": "098_zowe_ussProfileAuthentication@5" }, + { + "when": "view == zowe.uss.explorer && viewItem =~ /^(?!.*_fav.*)ussSession.*/ && !listMultiSelection", + "command": "zowe.editHistory", + "group": "100_zowe_editHistory@100" + }, { "when": "viewItem =~ /^(?!.*_fav.*)ussSession.*/ && !listMultiSelection", "command": "zowe.uss.editSession", @@ -1222,6 +1227,11 @@ "command": "zowe.ds.deleteProfile", "group": "099_zowe_dsProfileModification@99" }, + { + "when": "view == zowe.ds.explorer && viewItem =~ /^(?!.*_fav.*)session.*/ && !listMultiSelection", + "command": "zowe.editHistory", + "group": "100_zowe_editHistory@100" + }, { "when": "view == zowe.jobs.explorer && viewItem =~ /^(?!.*_fav.*)server.*/ && !listMultiSelection", "command": "zowe.jobs.search", @@ -1401,6 +1411,11 @@ "when": "view == zowe.jobs.explorer && viewItem =~ /^(?!.*_fav.*)server.*/ && !listMultiSelection", "command": "zowe.jobs.sortbyreturncode", "group": "000_zowe_jobsProfileModification@2" + }, + { + "when": "view == zowe.jobs.explorer && viewItem =~ /^(?!.*_fav.*)server.*/ && !listMultiSelection", + "command": "zowe.editHistory", + "group": "100_zowe_editHistory@100" } ], "commandPalette": [ diff --git a/packages/zowe-explorer/package.nls.json b/packages/zowe-explorer/package.nls.json index 2b99224dd7..8e9980e1d9 100644 --- a/packages/zowe-explorer/package.nls.json +++ b/packages/zowe-explorer/package.nls.json @@ -4,7 +4,7 @@ "viewsContainers.activitybar": "Zowe Explorer", "zowe.promptCredentials": "Update Credentials", "zowe.extRefresh": "Refresh Zowe Explorer", - "zowe.editHistory": "Edit History for Zowe Explorer", + "zowe.editHistory": "Edit History", "zowe.ds.explorer": "Data Sets", "zowe.uss.explorer": "Unix System Services (USS)", "zowe.jobs.explorer": "Jobs", diff --git a/packages/zowe-explorer/resources/dark/history.svg b/packages/zowe-explorer/resources/dark/history.svg new file mode 100644 index 0000000000..d82fe00e64 --- /dev/null +++ b/packages/zowe-explorer/resources/dark/history.svg @@ -0,0 +1,3 @@ + + + diff --git a/packages/zowe-explorer/resources/light/history.svg b/packages/zowe-explorer/resources/light/history.svg new file mode 100644 index 0000000000..0aded818e8 --- /dev/null +++ b/packages/zowe-explorer/resources/light/history.svg @@ -0,0 +1,3 @@ + + + diff --git a/packages/zowe-explorer/src/webviews/src/edit-history/assets/checklist.svg b/packages/zowe-explorer/src/webviews/src/edit-history/assets/checklist.svg new file mode 100644 index 0000000000..d4811a86c2 --- /dev/null +++ b/packages/zowe-explorer/src/webviews/src/edit-history/assets/checklist.svg @@ -0,0 +1,3 @@ + + + diff --git a/packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentTable/PersistentDataGridHeaders.tsx b/packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentTable/PersistentDataGridHeaders.tsx index f8a6c2abff..0cc61a56ab 100644 --- a/packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentTable/PersistentDataGridHeaders.tsx +++ b/packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentTable/PersistentDataGridHeaders.tsx @@ -20,8 +20,8 @@ export default function PersistentDataGridHeaders(): JSXInternal.Element { const { type, selection } = useDataPanelContext(); const itemText = localize("PersistentDataGridHeaders.item", "Item"); - const renderDeleteHeader = () => { - const deleteText = localize("PersistentDataGridHeaders.delete", "Delete"); + const renderSelectHeader = () => { + const deleteText = localize("PersistentDataGridHeaders.select", "Select"); return selection[type] === "search" || selection[type] === "fileHistory" ? ( {deleteText} @@ -34,7 +34,7 @@ export default function PersistentDataGridHeaders(): JSXInternal.Element { {itemText} - {renderDeleteHeader()} + {renderSelectHeader()} ); } diff --git a/packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentTable/PersistentTableData.tsx b/packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentTable/PersistentTableData.tsx index 4fb76e6762..db204b2dbd 100644 --- a/packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentTable/PersistentTableData.tsx +++ b/packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentTable/PersistentTableData.tsx @@ -34,7 +34,7 @@ export default function PersistentTableData({ persistentProp }: { persistentProp selectedItems.setVal({ ...selectedItems.val, [persistentProp[item]]: !event.target.checked }); }; - const renderDeleteButton = (item: string, i: number) => { + const renderSelectButton = (item: string, i: number) => { return selection[type] === "search" || selection[type] === "fileHistory" ? ( handleClick(event, i)}> @@ -47,7 +47,7 @@ export default function PersistentTableData({ persistentProp }: { persistentProp return ( {item} - {renderDeleteButton(item, i)} + {renderSelectButton(item, i)} ); }); diff --git a/packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentToolBar/PersistentSelectAllButton.tsx b/packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentToolBar/PersistentSelectAllButton.tsx new file mode 100644 index 0000000000..2d5c58bcff --- /dev/null +++ b/packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentToolBar/PersistentSelectAllButton.tsx @@ -0,0 +1,22 @@ +import { VSCodeButton } from "@vscode/webview-ui-toolkit/react"; +import { JSXInternal } from "preact/src/jsx"; +import * as nls from "vscode-nls"; +import { useDataPanelContext } from "../PersistentUtils"; + +const localize: nls.LocalizeFunc = nls.loadMessageBundle(); + +export default function PersistentSelectAllButton(): JSXInternal.Element { + const selectAllText = localize("PersistentSelectAllButton.selectAll", "Select All"); + + const { selectAll } = useDataPanelContext(); + + const handleClick = () => { + selectAll.setVal(!selectAll.val); + }; + + return ( + handleClick()}> + + + ); +} diff --git a/packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentToolBar/PersistentToolBar.tsx b/packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentToolBar/PersistentToolBar.tsx index 6e5d745833..51ec5a19be 100644 --- a/packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentToolBar/PersistentToolBar.tsx +++ b/packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentToolBar/PersistentToolBar.tsx @@ -15,6 +15,7 @@ import PersistentRefreshButton from "./PersistentRefreshButton"; import PersistentDropdownOptions from "./PersistentDropdownOptions"; import PersistentAddNewHistoryItemButton from "./PersistentAddNewHistoryItemButton"; import PersistentDeleteSelectedButton from "./PersistentDeleteSelectedButton"; +import PersistentSelectAllButton from "./PersistentSelectAllButton"; export default function PersistentToolBar({ handleChange }: { handleChange: Function }): JSXInternal.Element { return ( @@ -24,6 +25,7 @@ export default function PersistentToolBar({ handleChange }: { handleChange: Func +
); } From 63331bc922d4fa0b14df843a2dbf13dd6d9edac7 Mon Sep 17 00:00:00 2001 From: Rudy Flores <68666202+rudyflores@users.noreply.github.com> Date: Mon, 16 Oct 2023 14:53:50 -0400 Subject: [PATCH 126/189] Fix for unsecure profile token auth Signed-off-by: Rudy Flores <68666202+rudyflores@users.noreply.github.com> --- packages/zowe-explorer/src/Profiles.ts | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/packages/zowe-explorer/src/Profiles.ts b/packages/zowe-explorer/src/Profiles.ts index ba164cd8d6..c1bcfc4b9d 100644 --- a/packages/zowe-explorer/src/Profiles.ts +++ b/packages/zowe-explorer/src/Profiles.ts @@ -1259,13 +1259,16 @@ export class Profiles extends ProfilesCache { if (!profileName) { return []; } - if ((await this.getProfileInfo()).usingTeamConfig) { + const usingSecureCreds = !SettingsConfig.getDirectValue(globals.SETTINGS_SECURE_CREDENTIALS_ENABLED); + if ((await this.getProfileInfo()).usingTeamConfig && !usingSecureCreds) { const config = (await this.getProfileInfo()).getTeamConfig(); return config.api.secure.securePropsForProfile(profileName); } const profAttrs = await this.getProfileFromConfig(profileName); const mergedArgs = (await this.getProfileInfo()).mergeArgsForProfile(profAttrs); - return mergedArgs.knownArgs.filter((arg) => arg.secure).map((arg) => arg.argName); + return mergedArgs.knownArgs + .filter((arg) => arg.secure || arg.argName === "tokenType" || arg.argName === "tokenValue") + .map((arg) => arg.argName); } private async loginWithBaseProfile(serviceProfile: zowe.imperative.IProfileLoaded, loginTokenType: string, node?: IZoweNodeType): Promise { From 7dfae3f4b6765987eb3cb8b6f227e687dfc82c06 Mon Sep 17 00:00:00 2001 From: Rudy Flores <68666202+rudyflores@users.noreply.github.com> Date: Mon, 16 Oct 2023 15:01:37 -0400 Subject: [PATCH 127/189] add changelog Signed-off-by: Rudy Flores <68666202+rudyflores@users.noreply.github.com> --- packages/zowe-explorer/CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/zowe-explorer/CHANGELOG.md b/packages/zowe-explorer/CHANGELOG.md index b4815bcd01..7c00e2f0dd 100644 --- a/packages/zowe-explorer/CHANGELOG.md +++ b/packages/zowe-explorer/CHANGELOG.md @@ -15,6 +15,7 @@ All notable changes to the "vscode-extension-for-zowe" extension will be documen - Fixed submitting local JCL using command pallet option `Zowe Explorer: Submit JCL` by adding a check for chosen profile returned to continue the action. [#1625](https://github.com/zowe/vscode-extension-for-zowe/issues/1625) - Fixed conflict resolution being skipped if local and remote file have different contents but are the same size. [#2496](https://github.com/zowe/vscode-extension-for-zowe/issues/2496) +- Fixed issue with token based auth for unsecure profiles in Zowe Explorer [#2518](https://github.com/zowe/vscode-extension-for-zowe/issues/2518) ## `2.11.0` From 3058145102c84b8b1241654b2bf7554cf3377203 Mon Sep 17 00:00:00 2001 From: Rudy Flores <68666202+rudyflores@users.noreply.github.com> Date: Mon, 16 Oct 2023 16:43:44 -0400 Subject: [PATCH 128/189] remove filters on logout Signed-off-by: Rudy Flores <68666202+rudyflores@users.noreply.github.com> --- packages/zowe-explorer/src/Profiles.ts | 36 ++++++++++++++ packages/zowe-explorer/src/extension.ts | 9 ++-- .../zowe-explorer/src/shared/TreeProviders.ts | 49 +++++++++++++++++++ 3 files changed, 89 insertions(+), 5 deletions(-) create mode 100644 packages/zowe-explorer/src/shared/TreeProviders.ts diff --git a/packages/zowe-explorer/src/Profiles.ts b/packages/zowe-explorer/src/Profiles.ts index c1bcfc4b9d..3c1dabe75c 100644 --- a/packages/zowe-explorer/src/Profiles.ts +++ b/packages/zowe-explorer/src/Profiles.ts @@ -37,6 +37,8 @@ import * as globals from "./globals"; import * as nls from "vscode-nls"; import { SettingsConfig } from "./utils/SettingsConfig"; import { ZoweLogger } from "./utils/LoggerUtils"; +import { isZoweDatasetTreeNode, isZoweJobTreeNode, isZoweUSSTreeNode } from "./shared/utils"; +import { TreeProviders } from "./shared/TreeProviders"; // Set up localization nls.config({ @@ -1202,6 +1204,37 @@ export class Profiles extends ProfilesCache { } } + public clearFiltersFromTrees(node: IZoweNodeType): void { + const dsNode = TreeProviders.ds.mSessionNodes.find((n) => n.getProfile()?.name === node.getProfile()?.name); + const ussNode = TreeProviders.uss.mSessionNodes.find((n) => n.getProfile()?.name === node.getProfile()?.name); + const jobNode = TreeProviders.job.mSessionNodes.find((n) => n.getProfile()?.name === node.getProfile()?.name); + if (isZoweDatasetTreeNode(dsNode)) { + dsNode.tooltip = node.getProfile()?.name; + dsNode.description = ""; + dsNode.pattern = ""; + TreeProviders.ds.flipState(dsNode, false); + TreeProviders.ds.refreshElement(dsNode); + } + if (isZoweUSSTreeNode(ussNode)) { + ussNode.tooltip = node.getProfile()?.name; + dsNode.description = ""; + ussNode.fullPath = ""; + TreeProviders.uss.flipState(ussNode, false); + TreeProviders.uss.refreshElement(ussNode); + } + if (isZoweJobTreeNode(jobNode)) { + jobNode.tooltip = node.getProfile()?.name; + jobNode.description = ""; + jobNode.owner = ""; + jobNode.prefix = ""; + jobNode.status = ""; + jobNode.filtered = false; + jobNode.children = []; + TreeProviders.job.flipState(jobNode, false); + TreeProviders.job.refreshElement(jobNode); + } + } + public async ssoLogout(node: IZoweNodeType): Promise { ZoweLogger.trace("Profiles.ssoLogout called."); const serviceProfile = node.getProfile(); @@ -1212,6 +1245,9 @@ export class Profiles extends ProfilesCache { ); return; } + + this.clearFiltersFromTrees(node); + try { // this will handle extenders if (serviceProfile.type !== "zosmf" && serviceProfile.profile?.tokenType !== zowe.imperative.SessConstants.TOKEN_TYPE_APIML) { diff --git a/packages/zowe-explorer/src/extension.ts b/packages/zowe-explorer/src/extension.ts index e68d3f999c..ccfc29f77f 100644 --- a/packages/zowe-explorer/src/extension.ts +++ b/packages/zowe-explorer/src/extension.ts @@ -26,6 +26,7 @@ import { IZoweProviders, registerCommonCommands, registerRefreshCommand, watchCo import { ZoweLogger } from "./utils/LoggerUtils"; import { ZoweSaveQueue } from "./abstract/ZoweSaveQueue"; import { PollDecorator } from "./utils/DecorationProviders"; +import { TreeProviders } from "./shared/TreeProviders"; /** * The function that runs when the extension is loaded @@ -52,11 +53,9 @@ export async function activate(context: vscode.ExtensionContext): Promise; + static #uss: IZoweTree; + static #job: IZoweTree; + + public static async initializeProviders(context: vscode.ExtensionContext): Promise { + TreeProviders.#ds = await initDatasetProvider(context); + TreeProviders.#uss = await initUSSProvider(context); + TreeProviders.#job = await initJobsProvider(context); + } + + public static get ds(): IZoweTree { + return TreeProviders.#ds; + } + + public static get uss(): IZoweTree { + return TreeProviders.#uss; + } + + public static get job(): IZoweTree { + return TreeProviders.#job; + } + + public static get providers(): IZoweProviders { + return { + ds: TreeProviders.#ds, + uss: TreeProviders.#uss, + job: TreeProviders.#job, + }; + } +} From d11a09303497de2db0c6322def64a44c234c8f23 Mon Sep 17 00:00:00 2001 From: Billie Simmons <49491949+JillieBeanSim@users.noreply.github.com> Date: Tue, 17 Oct 2023 07:47:28 -0400 Subject: [PATCH 129/189] updates to CHANGELOGs Signed-off-by: Billie Simmons <49491949+JillieBeanSim@users.noreply.github.com> --- packages/zowe-explorer-api/CHANGELOG.md | 8 ---- .../zowe-explorer-ftp-extension/CHANGELOG.md | 8 ---- yarn.lock | 46 +++++++++---------- 3 files changed, 23 insertions(+), 39 deletions(-) diff --git a/packages/zowe-explorer-api/CHANGELOG.md b/packages/zowe-explorer-api/CHANGELOG.md index 5b223cd925..7b0b76bd7d 100644 --- a/packages/zowe-explorer-api/CHANGELOG.md +++ b/packages/zowe-explorer-api/CHANGELOG.md @@ -19,10 +19,6 @@ All notable changes to the "zowe-explorer-api" extension will be documented in t ## `2.11.1` -### New features and enhancements - -### Bug fixes - ## `2.11.0` ### New features and enhancements @@ -44,10 +40,6 @@ All notable changes to the "zowe-explorer-api" extension will be documented in t ## `2.9.2` -### New features and enhancements - -### Bug fixes - ## `2.9.1` ### New features and enhancements diff --git a/packages/zowe-explorer-ftp-extension/CHANGELOG.md b/packages/zowe-explorer-ftp-extension/CHANGELOG.md index b9d2ee79ff..1d58ca0e0c 100644 --- a/packages/zowe-explorer-ftp-extension/CHANGELOG.md +++ b/packages/zowe-explorer-ftp-extension/CHANGELOG.md @@ -16,10 +16,6 @@ All notable changes to the "zowe-explorer-ftp-extension" extension will be docum ## `2.11.1` -### New features and enhancements - -### Bug fixes - ## `2.11.0` ### Bug fixes @@ -39,10 +35,6 @@ All notable changes to the "zowe-explorer-ftp-extension" extension will be docum ## `2.9.2` -### New features and enhancements - -### Bug fixes - ## `2.9.1` ### Bug fixes diff --git a/yarn.lock b/yarn.lock index 9841e2ab42..2d03241b4c 100644 --- a/yarn.lock +++ b/yarn.lock @@ -139,7 +139,7 @@ "@jridgewell/gen-mapping" "^0.3.2" jsesc "^2.5.1" -"@babel/generator@^7.23.0": +"@babel/generator@^7.22.15", "@babel/generator@^7.23.0": version "7.23.0" resolved "https://registry.npmjs.org/@babel/generator/-/generator-7.23.0.tgz#df5c386e2218be505b34837acbcb874d7a983420" integrity sha512-lN85QRR+5IbYrMWM6Y4pE/noaQtg4pNiqeNGX60eqOfo6gtEj6uw/JagelB8vVztSd7R6M5n1+PQkDbHbBRU4g== @@ -362,7 +362,7 @@ "@babel/traverse" "^7.20.1" "@babel/types" "^7.20.2" -"@babel/helper-module-transforms@^7.23.0": +"@babel/helper-module-transforms@^7.22.17": version "7.23.0" resolved "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.23.0.tgz#3ec246457f6c842c0aee62a01f60739906f7047e" integrity sha512-WhDWw1tdrlT0gMgUJSlX0IQvoO1eN279zrAUbVB+KpV2c3Tylz8+GnKOLllCS6Z/iZQEyVYxhZVUdPTqs2YYPw== @@ -484,7 +484,7 @@ resolved "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.19.1.tgz" integrity sha512-awrNfaMtnHUr653GgGEs++LlAvW6w+DcPrOliSMXWCKo597CwL5Acf/wWdNkf/tfEQE3mjkeD1YOVZOUV/od1w== -"@babel/helper-validator-identifier@^7.22.20": +"@babel/helper-validator-identifier@^7.22.15", "@babel/helper-validator-identifier@^7.22.20", "@babel/helper-validator-identifier@^7.22.5": version "7.22.20" resolved "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz#c4ae002c61d2879e724581d96665583dbc1dc0e0" integrity sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A== @@ -532,13 +532,13 @@ "@babel/traverse" "^7.20.1" "@babel/types" "^7.20.0" -"@babel/helpers@^7.23.0": - version "7.23.1" - resolved "https://registry.npmjs.org/@babel/helpers/-/helpers-7.23.1.tgz#44e981e8ce2b9e99f8f0b703f3326a4636c16d15" - integrity sha512-chNpneuK18yW5Oxsr+t553UZzzAs3aZnFm4bxhebsNTeshrC95yA7l5yl7GBAG+JG1rF0F7zzD2EixK9mWSDoA== +"@babel/helpers@^7.22.15": + version "7.23.2" + resolved "https://registry.npmjs.org/@babel/helpers/-/helpers-7.23.2.tgz#2832549a6e37d484286e15ba36a5330483cac767" + integrity sha512-lzchcp8SjTSVe/fPmLwtWVBFC7+Tbn8LGHDVfDp9JGxpAY5opSaEFgt8UQvrnECWOTdji2mOWMz1rOhkHscmGQ== dependencies: "@babel/template" "^7.22.15" - "@babel/traverse" "^7.23.0" + "@babel/traverse" "^7.23.2" "@babel/types" "^7.23.0" "@babel/highlight@^7.10.4", "@babel/highlight@^7.16.7", "@babel/highlight@^7.18.6": @@ -574,7 +574,7 @@ resolved "https://registry.npmjs.org/@babel/parser/-/parser-7.22.16.tgz" integrity sha512-+gPfKv8UWeKKeJTUxe59+OobVcrYHETCsORl61EmSkmgymguYk/X5bp7GuUIXaFsc6y++v8ZxPsLSSuujqDphA== -"@babel/parser@^7.23.0": +"@babel/parser@^7.22.16", "@babel/parser@^7.23.0": version "7.23.0" resolved "https://registry.npmjs.org/@babel/parser/-/parser-7.23.0.tgz#da950e622420bf96ca0d0f2909cdddac3acd8719" integrity sha512-vvPKKdMemU85V9WE/l5wZEmImpCtLqbnTvqDS2U1fJ96KrxoW7KrXhNsNCblQlg8Ck4b85yxdTyelsMUgFUXiw== @@ -1299,10 +1299,10 @@ debug "^4.1.0" globals "^11.1.0" -"@babel/traverse@^7.23.0": - version "7.23.0" - resolved "https://registry.npmjs.org/@babel/traverse/-/traverse-7.23.0.tgz#18196ddfbcf4ccea324b7f6d3ada00d8c5a99c53" - integrity sha512-t/QaEvyIoIkwzpiZ7aoSKK8kObQYeF7T2v+dazAYCb8SXtp58zEVkWW7zAnju8FNKNdr4ScAOEDmMItbyOmEYw== +"@babel/traverse@^7.22.17", "@babel/traverse@^7.23.2": + version "7.23.2" + resolved "https://registry.npmjs.org/@babel/traverse/-/traverse-7.23.2.tgz#329c7a06735e144a506bdb2cad0268b7f46f4ad8" + integrity sha512-azpe59SQ48qG6nu2CzcMLbxUudtN+dOM9kDbUqGq3HXUJRlo7i8fvPoxQUzYgLZ4cMVmuZgm8vvBpNeRhd6XSw== dependencies: "@babel/code-frame" "^7.22.13" "@babel/generator" "^7.23.0" @@ -1341,7 +1341,7 @@ "@babel/helper-validator-identifier" "^7.22.15" to-fast-properties "^2.0.0" -"@babel/types@^7.23.0": +"@babel/types@^7.22.17", "@babel/types@^7.23.0": version "7.23.0" resolved "https://registry.npmjs.org/@babel/types/-/types-7.23.0.tgz#8c1f020c9df0e737e4e247c0619f58c68458aaeb" integrity sha512-0oIyUfKoI3mSqMvsxBdclDwxXKXAUA8v/apZbc+iSyARYou1o8ZGDxbUYyLFoW2arqS2jDGqJuZvv1d/io1axg== @@ -3847,10 +3847,10 @@ caniuse-lite@^1.0.30001400: resolved "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001434.tgz" integrity sha512-aOBHrLmTQw//WFa2rcF1If9fa3ypkC1wzqqiKHgfdrXTWcU8C4gKVZT77eQAPWN1APys3+uQ0Df07rKauXGEYA== -caniuse-lite@^1.0.30001541: - version "1.0.30001541" - resolved "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001541.tgz#b1aef0fadd87fb72db4dcb55d220eae17b81cdb1" - integrity sha512-bLOsqxDgTqUBkzxbNlSBt8annkDpQB9NdzdTbO2ooJ+eC/IQcvDspDc058g84ejCelF7vHUx57KIOjEecOHXaw== +caniuse-lite@^1.0.30001517: + version "1.0.30001549" + resolved "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001549.tgz#7d1a3dce7ea78c06ed72c32c2743ea364b3615aa" + integrity sha512-qRp48dPYSCYaP+KurZLhDYdVE+yEyht/3NlmcJgVQ2VMGt6JL36ndQ/7rgspdZsJuxDPFIo/OzBT2+GmIJ53BA== capture-stack-trace@^1.0.0: version "1.0.1" @@ -4896,10 +4896,10 @@ electron-to-chromium@^1.4.251: resolved "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.284.tgz" integrity sha512-M8WEXFuKXMYMVr45fo8mq0wUrrJHheiKZf6BArTKk9ZBYCKJEOU5H8cdWgDT+qCVZf7Na4lVUaZsA+h6uA9+PA== -electron-to-chromium@^1.4.535: - version "1.4.535" - resolved "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.535.tgz#f14765820a0aa31425e1dbbae917cc70872b2a53" - integrity sha512-4548PpR4S5X5dlvX8NUIw0njH7btQtBoJWcgzpq7n2F9NQ5gMXOPP/6p6iVx6+YT3FVioNhEGa14WJj1k+2SfA== +electron-to-chromium@^1.4.477: + version "1.4.556" + resolved "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.556.tgz#97385917eb6ea3ac6a3378cf87bb39ee1db96e76" + integrity sha512-6RPN0hHfzDU8D56E72YkDvnLw5Cj2NMXZGg3UkgyoHxjVhG99KZpsKgBWMmTy0Ei89xwan+rbRsVB9yzATmYzQ== elliptic@^6.5.3: version "6.5.4" @@ -11503,7 +11503,7 @@ upath@^1.1.1: resolved "https://registry.npmjs.org/upath/-/upath-1.2.0.tgz" integrity sha512-aZwGpamFO61g3OlfT7OQCHqhGnW43ieH9WZeP7QxN/G/jS4jfqUkZxoryvJgVPEcrl5NL/ggHsSmLMHuH64Lhg== -update-browserslist-db@^1.0.13: +update-browserslist-db@^1.0.11: version "1.0.13" resolved "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.13.tgz#3c5e4f5c083661bd38ef64b6328c26ed6c8248c4" integrity sha512-xebP81SNcPuNpPP3uzeW1NYXxI3rxyJzF3pD6sH4jE7o/IX+WtSpwnVU+qIsDPyk0d3hmFQ7mjqc6AtV604hbg== From e0dda45083eb367d3c522c685dcc64d7089ce7a2 Mon Sep 17 00:00:00 2001 From: Trae Yelovich Date: Tue, 17 Oct 2023 10:47:51 -0400 Subject: [PATCH 130/189] feat(ds, jobs): Show status bar msg when sort/filter is applied - Renamed `m4date` to `modifiedDate` in `DatasetStats` API type Signed-off-by: Trae Yelovich --- packages/zowe-explorer-api/src/tree/IZoweTreeNode.ts | 3 ++- .../__tests__/__unit__/dataset/DatasetTree.unit.test.ts | 6 +++--- .../i18n/sample/src/dataset/DatasetTree.i18n.json | 5 +++-- .../zowe-explorer/i18n/sample/src/job/actions.i18n.json | 5 ++--- packages/zowe-explorer/src/dataset/DatasetTree.ts | 3 +++ packages/zowe-explorer/src/dataset/ZoweDatasetNode.ts | 8 ++++---- packages/zowe-explorer/src/job/actions.ts | 2 ++ 7 files changed, 19 insertions(+), 13 deletions(-) diff --git a/packages/zowe-explorer-api/src/tree/IZoweTreeNode.ts b/packages/zowe-explorer-api/src/tree/IZoweTreeNode.ts index e5f0d3c1fd..4f731b8c14 100644 --- a/packages/zowe-explorer-api/src/tree/IZoweTreeNode.ts +++ b/packages/zowe-explorer-api/src/tree/IZoweTreeNode.ts @@ -127,7 +127,8 @@ export interface IZoweTreeNode { export type DatasetStats = { user: string; - m4date: Date; + // built from "m4date", "mtime" and "msec" variables from z/OSMF API response + modifiedDate: Date; }; /** 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 f8e6ddcc98..65cb06a4a7 100644 --- a/packages/zowe-explorer/__tests__/__unit__/dataset/DatasetTree.unit.test.ts +++ b/packages/zowe-explorer/__tests__/__unit__/dataset/DatasetTree.unit.test.ts @@ -2705,11 +2705,11 @@ describe("Dataset Tree Unit Tests - Sorting and Filtering operations", () => { pds.contextValue = globals.DS_PDS_CONTEXT; const nodeA = new ZoweDatasetNode("A", vscode.TreeItemCollapsibleState.Collapsed, pds, createISession()); - nodeA.stats = { user: "someUser", m4date: new Date() }; + nodeA.stats = { user: "someUser", modifiedDate: new Date() }; const nodeB = new ZoweDatasetNode("B", vscode.TreeItemCollapsibleState.Collapsed, pds, createISession()); - nodeB.stats = { user: "anotherUser", m4date: new Date("2022-01-01T12:00:00") }; + nodeB.stats = { user: "anotherUser", modifiedDate: new Date("2022-01-01T12:00:00") }; const nodeC = new ZoweDatasetNode("C", vscode.TreeItemCollapsibleState.Collapsed, pds, createISession()); - nodeC.stats = { user: "someUser", m4date: new Date("2022-03-15T16:30:00") }; + nodeC.stats = { user: "someUser", modifiedDate: new Date("2022-03-15T16:30:00") }; pds.children = [nodeA, nodeB, nodeC]; session.children = [pds]; diff --git a/packages/zowe-explorer/i18n/sample/src/dataset/DatasetTree.i18n.json b/packages/zowe-explorer/i18n/sample/src/dataset/DatasetTree.i18n.json index d59c6ecff8..a466d5c330 100644 --- a/packages/zowe-explorer/i18n/sample/src/dataset/DatasetTree.i18n.json +++ b/packages/zowe-explorer/i18n/sample/src/dataset/DatasetTree.i18n.json @@ -30,14 +30,15 @@ "ds.singlePdsSort": "the PDS members in {0}", "ds.selectSortOpt": "Select a sorting option for {0}", "setSortDirection": "$(fold) Sort Direction", - "sort.asc": "Ascending", - "sort.desc": "Descending", "sort.selectDirection": "Select a sorting direction", + "sort.updated": "$(check) Sorting updated for {0}", "ds.clearProfileFilter": "$(clear-all) Clear filter for profile", "ds.clearPdsFilter": "$(clear-all) Clear filter for PDS", "ds.selectFilterOpt": "Set a filter for {0}", + "filter.cleared": "$(check) Filter cleared for {0}", "ds.filterEntry.invalidDate": "Invalid date format specified", "ds.filterEntry.title": "Enter a value to filter by", "ds.filterEntry.invalid": "Invalid filter specified", + "filter.updated": "$(check) Filter updated for {0}", "defaultFilterPrompt.option.prompt.search": "$(plus) Create a new filter. For example: HLQ.*, HLQ.aaa.bbb, HLQ.ccc.ddd(member)" } diff --git a/packages/zowe-explorer/i18n/sample/src/job/actions.i18n.json b/packages/zowe-explorer/i18n/sample/src/job/actions.i18n.json index 95dec6d4a4..eb36cd951f 100644 --- a/packages/zowe-explorer/i18n/sample/src/job/actions.i18n.json +++ b/packages/zowe-explorer/i18n/sample/src/job/actions.i18n.json @@ -24,7 +24,6 @@ "cancelJobs.succeeded": "Cancelled selected jobs successfully.", "jobs.selectSortOpt": "Select a sorting option for jobs in {0}", "setSortDirection": "$(fold) Sort Direction", - "sort.asc": "Ascending", - "sort.desc": "Descending", - "sort.selectDirection": "Select a sorting direction" + "sort.selectDirection": "Select a sorting direction", + "sort.updated": "$(check) Sorting updated for {0}" } diff --git a/packages/zowe-explorer/src/dataset/DatasetTree.ts b/packages/zowe-explorer/src/dataset/DatasetTree.ts index 8520764a3b..c479f8141f 100644 --- a/packages/zowe-explorer/src/dataset/DatasetTree.ts +++ b/packages/zowe-explorer/src/dataset/DatasetTree.ts @@ -1375,6 +1375,7 @@ export class DatasetTree extends ZoweTreeProvider implements IZoweTree Date: Tue, 17 Oct 2023 17:35:32 +0000 Subject: [PATCH 131/189] chore(deps): Bump @babel/traverse from 7.17.10 to 7.23.2 Bumps [@babel/traverse](https://github.com/babel/babel/tree/HEAD/packages/babel-traverse) from 7.17.10 to 7.23.2. - [Release notes](https://github.com/babel/babel/releases) - [Changelog](https://github.com/babel/babel/blob/main/CHANGELOG.md) - [Commits](https://github.com/babel/babel/commits/v7.23.2/packages/babel-traverse) --- updated-dependencies: - dependency-name: "@babel/traverse" dependency-type: indirect ... Signed-off-by: dependabot[bot] --- yarn.lock | 61 +++++++------------------------------------------------ 1 file changed, 7 insertions(+), 54 deletions(-) diff --git a/yarn.lock b/yarn.lock index 37ae9cb03e..d0f1c2792c 100644 --- a/yarn.lock +++ b/yarn.lock @@ -139,7 +139,7 @@ "@jridgewell/gen-mapping" "^0.1.0" jsesc "^2.5.1" -"@babel/generator@^7.20.1", "@babel/generator@^7.20.2", "@babel/generator@^7.7.2": +"@babel/generator@^7.20.2", "@babel/generator@^7.7.2": version "7.20.4" resolved "https://registry.npmjs.org/@babel/generator/-/generator-7.20.4.tgz#4d9f8f0c30be75fd90a0562099a26e5839602ab8" integrity sha512-luCf7yk/cm7yab6CAW1aiFnmEfBJplb/JojV56MYEK7ziWfGmFlTfmL9Ehwfy4gFhbjBfWO1wj7/TuSbVNEEtA== @@ -278,14 +278,6 @@ "@babel/template" "^7.16.7" "@babel/types" "^7.17.0" -"@babel/helper-function-name@^7.19.0": - version "7.19.0" - resolved "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.19.0.tgz#941574ed5390682e872e52d3f38ce9d1bef4648c" - integrity sha512-WAwHBINyrpqywkUH0nTnNgI5ina5TFn85HKS0pbPDfxFfhyR/aNQEn4hGi1P1JyT//I0t4OgXUlofzWILRvS5w== - dependencies: - "@babel/template" "^7.18.10" - "@babel/types" "^7.19.0" - "@babel/helper-function-name@^7.23.0": version "7.23.0" resolved "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.23.0.tgz#1f9a3cdbd5b2698a670c30d2735f9af95ed52759" @@ -301,13 +293,6 @@ dependencies: "@babel/types" "^7.16.7" -"@babel/helper-hoist-variables@^7.18.6": - version "7.18.6" - resolved "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.18.6.tgz#d4d2c8fb4baeaa5c68b99cc8245c56554f926678" - integrity sha512-UlJQPkFqFULIcyW5sbzgbkxn2FKRgwWiRexcuaR8RNJRy8+LLveqPjwZV/bwrLZCN0eUHD/x8D0heK1ozuoo6Q== - dependencies: - "@babel/types" "^7.18.6" - "@babel/helper-hoist-variables@^7.22.5": version "7.22.5" resolved "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.22.5.tgz#c01a007dac05c085914e8fb652b339db50d823bb" @@ -582,7 +567,7 @@ resolved "https://registry.npmjs.org/@babel/parser/-/parser-7.17.10.tgz#873b16db82a8909e0fbd7f115772f4b739f6ce78" integrity sha512-n2Q6i+fnJqzOaq2VkdXxy2TCPCWQZHiCo0XqmrCvDWcZQKRyZzYi4Z0yxlBuN0w+r2ZHmre+Q087DSrw3pbJDQ== -"@babel/parser@^7.18.10", "@babel/parser@^7.20.1", "@babel/parser@^7.20.2": +"@babel/parser@^7.18.10", "@babel/parser@^7.20.2": version "7.20.3" resolved "https://registry.npmjs.org/@babel/parser/-/parser-7.20.3.tgz#5358cf62e380cf69efcb87a7bb922ff88bfac6e2" integrity sha512-OP/s5a94frIPXwjzEcv5S/tpQfc6XhxYUnmWpgdqMWGgYCuErA3SzozaRAMQgSZWKeTJxht9aWAkUY+0UzvOFg== @@ -1287,42 +1272,10 @@ "@babel/parser" "^7.22.15" "@babel/types" "^7.22.15" -"@babel/traverse@^7.13.0", "@babel/traverse@^7.16.7", "@babel/traverse@^7.16.8", "@babel/traverse@^7.17.10", "@babel/traverse@^7.17.3", "@babel/traverse@^7.17.9": - version "7.17.10" - resolved "https://registry.npmjs.org/@babel/traverse/-/traverse-7.17.10.tgz#1ee1a5ac39f4eac844e6cf855b35520e5eb6f8b5" - integrity sha512-VmbrTHQteIdUUQNTb+zE12SHS/xQVIShmBPhlNP12hD5poF2pbITW1Z4172d03HegaQWhLffdkRJYtAzp0AGcw== - dependencies: - "@babel/code-frame" "^7.16.7" - "@babel/generator" "^7.17.10" - "@babel/helper-environment-visitor" "^7.16.7" - "@babel/helper-function-name" "^7.17.9" - "@babel/helper-hoist-variables" "^7.16.7" - "@babel/helper-split-export-declaration" "^7.16.7" - "@babel/parser" "^7.17.10" - "@babel/types" "^7.17.10" - debug "^4.1.0" - globals "^11.1.0" - -"@babel/traverse@^7.20.1", "@babel/traverse@^7.7.2": - version "7.20.1" - resolved "https://registry.npmjs.org/@babel/traverse/-/traverse-7.20.1.tgz#9b15ccbf882f6d107eeeecf263fbcdd208777ec8" - integrity sha512-d3tN8fkVJwFLkHkBN479SOsw4DMZnz8cdbL/gvuDuzy3TS6Nfw80HuQqhw1pITbIruHyh7d1fMA47kWzmcUEGA== - dependencies: - "@babel/code-frame" "^7.18.6" - "@babel/generator" "^7.20.1" - "@babel/helper-environment-visitor" "^7.18.9" - "@babel/helper-function-name" "^7.19.0" - "@babel/helper-hoist-variables" "^7.18.6" - "@babel/helper-split-export-declaration" "^7.18.6" - "@babel/parser" "^7.20.1" - "@babel/types" "^7.20.0" - debug "^4.1.0" - globals "^11.1.0" - -"@babel/traverse@^7.23.0": - version "7.23.0" - resolved "https://registry.npmjs.org/@babel/traverse/-/traverse-7.23.0.tgz#18196ddfbcf4ccea324b7f6d3ada00d8c5a99c53" - integrity sha512-t/QaEvyIoIkwzpiZ7aoSKK8kObQYeF7T2v+dazAYCb8SXtp58zEVkWW7zAnju8FNKNdr4ScAOEDmMItbyOmEYw== +"@babel/traverse@^7.13.0", "@babel/traverse@^7.16.7", "@babel/traverse@^7.16.8", "@babel/traverse@^7.17.10", "@babel/traverse@^7.17.3", "@babel/traverse@^7.17.9", "@babel/traverse@^7.20.1", "@babel/traverse@^7.23.0", "@babel/traverse@^7.7.2": + version "7.23.2" + resolved "https://registry.npmjs.org/@babel/traverse/-/traverse-7.23.2.tgz#329c7a06735e144a506bdb2cad0268b7f46f4ad8" + integrity sha512-azpe59SQ48qG6nu2CzcMLbxUudtN+dOM9kDbUqGq3HXUJRlo7i8fvPoxQUzYgLZ4cMVmuZgm8vvBpNeRhd6XSw== dependencies: "@babel/code-frame" "^7.22.13" "@babel/generator" "^7.23.0" @@ -1343,7 +1296,7 @@ "@babel/helper-validator-identifier" "^7.16.7" to-fast-properties "^2.0.0" -"@babel/types@^7.18.10", "@babel/types@^7.18.6", "@babel/types@^7.19.0", "@babel/types@^7.20.0", "@babel/types@^7.20.2": +"@babel/types@^7.18.10", "@babel/types@^7.18.6", "@babel/types@^7.20.0", "@babel/types@^7.20.2": version "7.20.2" resolved "https://registry.npmjs.org/@babel/types/-/types-7.20.2.tgz#67ac09266606190f496322dbaff360fdaa5e7842" integrity sha512-FnnvsNWgZCr232sqtXggapvlkk/tuwR/qhGzcmxI0GXLCjmPYQPzio2FbdlWuY6y1sHFfQKk+rRbUZ9VStQMog== From 129efde4db92c1a5277351caa90513e016a3cfcd Mon Sep 17 00:00:00 2001 From: Rudy Flores <68666202+rudyflores@users.noreply.github.com> Date: Tue, 17 Oct 2023 14:29:50 -0400 Subject: [PATCH 132/189] remove circular imports Signed-off-by: Rudy Flores <68666202+rudyflores@users.noreply.github.com> --- .../__unit__/Profiles.extended.unit.test.ts | 9 ++++ packages/zowe-explorer/src/Profiles.ts | 54 +++++++++---------- packages/zowe-explorer/src/extension.ts | 12 ++--- .../zowe-explorer/src/shared/TreeProviders.ts | 16 +++--- 4 files changed, 48 insertions(+), 43 deletions(-) diff --git a/packages/zowe-explorer/__tests__/__unit__/Profiles.extended.unit.test.ts b/packages/zowe-explorer/__tests__/__unit__/Profiles.extended.unit.test.ts index 6d41665a89..8f87010c86 100644 --- a/packages/zowe-explorer/__tests__/__unit__/Profiles.extended.unit.test.ts +++ b/packages/zowe-explorer/__tests__/__unit__/Profiles.extended.unit.test.ts @@ -38,6 +38,7 @@ import { createIJobObject, createJobsTree } from "../../__mocks__/mockCreators/j import * as path from "path"; import { SettingsConfig } from "../../src/utils/SettingsConfig"; import { ZoweLogger } from "../../src/utils/LoggerUtils"; +import { TreeProviders } from "../../src/shared/TreeProviders"; jest.mock("child_process"); jest.mock("fs"); @@ -1642,6 +1643,14 @@ describe("Profiles Unit Tests - function ssoLogout", () => { jest.spyOn(Gui, "showMessage").mockImplementation(); }); it("should logout successfully and refresh zowe explorer", async () => { + const mockTreeProvider = { + mSessionNodes: [testNode], + flipState: jest.fn(), + refreshElement: jest.fn(), + } as any; + jest.spyOn(TreeProviders, "ds", "get").mockReturnValue(mockTreeProvider); + jest.spyOn(TreeProviders, "uss", "get").mockReturnValue(mockTreeProvider); + jest.spyOn(TreeProviders, "job", "get").mockReturnValue(mockTreeProvider); const getTokenTypeNameMock = jest.fn(); const logoutMock = jest.fn(); jest.spyOn(ZoweExplorerApiRegister.getInstance(), "getCommonApi").mockImplementation(() => ({ diff --git a/packages/zowe-explorer/src/Profiles.ts b/packages/zowe-explorer/src/Profiles.ts index 3c1dabe75c..ca1e454438 100644 --- a/packages/zowe-explorer/src/Profiles.ts +++ b/packages/zowe-explorer/src/Profiles.ts @@ -37,7 +37,6 @@ import * as globals from "./globals"; import * as nls from "vscode-nls"; import { SettingsConfig } from "./utils/SettingsConfig"; import { ZoweLogger } from "./utils/LoggerUtils"; -import { isZoweDatasetTreeNode, isZoweJobTreeNode, isZoweUSSTreeNode } from "./shared/utils"; import { TreeProviders } from "./shared/TreeProviders"; // Set up localization @@ -1205,34 +1204,31 @@ export class Profiles extends ProfilesCache { } public clearFiltersFromTrees(node: IZoweNodeType): void { - const dsNode = TreeProviders.ds.mSessionNodes.find((n) => n.getProfile()?.name === node.getProfile()?.name); - const ussNode = TreeProviders.uss.mSessionNodes.find((n) => n.getProfile()?.name === node.getProfile()?.name); - const jobNode = TreeProviders.job.mSessionNodes.find((n) => n.getProfile()?.name === node.getProfile()?.name); - if (isZoweDatasetTreeNode(dsNode)) { - dsNode.tooltip = node.getProfile()?.name; - dsNode.description = ""; - dsNode.pattern = ""; - TreeProviders.ds.flipState(dsNode, false); - TreeProviders.ds.refreshElement(dsNode); - } - if (isZoweUSSTreeNode(ussNode)) { - ussNode.tooltip = node.getProfile()?.name; - dsNode.description = ""; - ussNode.fullPath = ""; - TreeProviders.uss.flipState(ussNode, false); - TreeProviders.uss.refreshElement(ussNode); - } - if (isZoweJobTreeNode(jobNode)) { - jobNode.tooltip = node.getProfile()?.name; - jobNode.description = ""; - jobNode.owner = ""; - jobNode.prefix = ""; - jobNode.status = ""; - jobNode.filtered = false; - jobNode.children = []; - TreeProviders.job.flipState(jobNode, false); - TreeProviders.job.refreshElement(jobNode); - } + const dsNode: IZoweDatasetTreeNode = TreeProviders.ds.mSessionNodes.find((n) => n.getProfile()?.name === node.getProfile()?.name); + const ussNode: IZoweUSSTreeNode = TreeProviders.uss.mSessionNodes.find((n) => n.getProfile()?.name === node.getProfile()?.name); + const jobNode: IZoweJobTreeNode = TreeProviders.job.mSessionNodes.find((n) => n.getProfile()?.name === node.getProfile()?.name); + + dsNode.tooltip = node.getProfile()?.name; + dsNode.description = ""; + dsNode.pattern = ""; + TreeProviders.ds.flipState(dsNode, false); + TreeProviders.ds.refreshElement(dsNode); + + ussNode.tooltip = node.getProfile()?.name; + ussNode.description = ""; + ussNode.fullPath = ""; + TreeProviders.uss.flipState(ussNode, false); + TreeProviders.uss.refreshElement(ussNode); + + jobNode.tooltip = node.getProfile()?.name; + jobNode.description = ""; + jobNode.owner = ""; + jobNode.prefix = ""; + jobNode.status = ""; + jobNode.filtered = false; + jobNode.children = []; + TreeProviders.job.flipState(jobNode, false); + TreeProviders.job.refreshElement(jobNode); } public async ssoLogout(node: IZoweNodeType): Promise { diff --git a/packages/zowe-explorer/src/extension.ts b/packages/zowe-explorer/src/extension.ts index ccfc29f77f..d20fd9629d 100644 --- a/packages/zowe-explorer/src/extension.ts +++ b/packages/zowe-explorer/src/extension.ts @@ -19,14 +19,14 @@ import { ProfilesUtils } from "./utils/ProfilesUtils"; import { initializeSpoolProvider } from "./SpoolProvider"; import { cleanTempDir, hideTempFolder } from "./utils/TempFolder"; import { SettingsConfig } from "./utils/SettingsConfig"; -import { initDatasetProvider } from "./dataset/init"; -import { initUSSProvider } from "./uss/init"; -import { initJobsProvider } from "./job/init"; -import { IZoweProviders, registerCommonCommands, registerRefreshCommand, watchConfigProfile } from "./shared/init"; +import { registerCommonCommands, registerRefreshCommand, watchConfigProfile } from "./shared/init"; import { ZoweLogger } from "./utils/LoggerUtils"; import { ZoweSaveQueue } from "./abstract/ZoweSaveQueue"; import { PollDecorator } from "./utils/DecorationProviders"; import { TreeProviders } from "./shared/TreeProviders"; +import { initDatasetProvider } from "./dataset/init"; +import { initUSSProvider } from "./uss/init"; +import { initJobsProvider } from "./job/init"; /** * The function that runs when the extension is loaded @@ -53,9 +53,7 @@ export async function activate(context: vscode.ExtensionContext): Promise Promise>; export class TreeProviders { static #ds: IZoweTree; static #uss: IZoweTree; static #job: IZoweTree; - public static async initializeProviders(context: vscode.ExtensionContext): Promise { - TreeProviders.#ds = await initDatasetProvider(context); - TreeProviders.#uss = await initUSSProvider(context); - TreeProviders.#job = await initJobsProvider(context); + public static async initializeProviders( + context: vscode.ExtensionContext, + initializers: { ds: ProviderFunction; uss: ProviderFunction; job: ProviderFunction } + ): Promise { + TreeProviders.#ds = await initializers.ds(context); + TreeProviders.#uss = await initializers.uss(context); + TreeProviders.#job = await initializers.job(context); + return TreeProviders.providers; } public static get ds(): IZoweTree { From 0838214229a50d2e0cd892346de9ccefb8a777e7 Mon Sep 17 00:00:00 2001 From: Billie Simmons <49491949+JillieBeanSim@users.noreply.github.com> Date: Tue, 17 Oct 2023 14:34:24 -0400 Subject: [PATCH 133/189] add coverage Signed-off-by: Billie Simmons <49491949+JillieBeanSim@users.noreply.github.com> --- .../__unit__/job/actions.unit.test.ts | 63 ++++++++++++++----- 1 file changed, 48 insertions(+), 15 deletions(-) diff --git a/packages/zowe-explorer/__tests__/__unit__/job/actions.unit.test.ts b/packages/zowe-explorer/__tests__/__unit__/job/actions.unit.test.ts index 5ec985c41f..262b6b2d46 100644 --- a/packages/zowe-explorer/__tests__/__unit__/job/actions.unit.test.ts +++ b/packages/zowe-explorer/__tests__/__unit__/job/actions.unit.test.ts @@ -11,7 +11,7 @@ import * as vscode from "vscode"; import * as zowe from "@zowe/cli"; -import { Gui, IZoweJobTreeNode, IZoweTree, ValidProfileEnum } from "@zowe/zowe-explorer-api"; +import { Gui, IZoweJobTreeNode, ValidProfileEnum } from "@zowe/zowe-explorer-api"; import { Job, Spool } from "../../../src/job/ZoweJobNode"; import { createISession, @@ -451,6 +451,39 @@ describe("Jobs Actions Unit Tests - Function submitJcl", () => { } it("Checking submit of active text editor content as JCL", async () => { + createGlobalMocks(); + const blockMocks: any = createBlockMocks(); + mocked(zowe.ZosmfSession.createSessCfgFromArgs).mockReturnValue(blockMocks.session); + mocked(Profiles.getInstance).mockReturnValue(blockMocks.profileInstance); + mocked(vscode.window.showQuickPick).mockReturnValueOnce( + new Promise((resolve) => { + resolve(blockMocks.datasetSessionNode.label); + }) + ); + const mockFile = { + path: "/fake/path/file.txt", + } as vscode.Uri; + blockMocks.testDatasetTree.getChildren.mockResolvedValueOnce([ + new ZoweDatasetNode("node", vscode.TreeItemCollapsibleState.None, blockMocks.datasetSessionNode, null as any), + blockMocks.datasetSessionNode, + ]); + const commandSpy = jest.spyOn(vscode.commands, "executeCommand"); + activeTextEditorDocument.mockReturnValue(blockMocks.textDocument); + const submitJclSpy = jest.spyOn(blockMocks.jesApi, "submitJcl"); + submitJclSpy.mockClear(); + submitJclSpy.mockResolvedValueOnce(blockMocks.iJob); + await dsActions.submitJcl(blockMocks.testDatasetTree, mockFile); + + expect(commandSpy).toBeCalled(); + expect(submitJclSpy).toBeCalled(); + expect(mocked(Gui.showMessage)).toBeCalled(); + expect(mocked(Gui.showMessage).mock.calls.length).toBe(1); + expect(mocked(Gui.showMessage).mock.calls[0][0]).toEqual( + "Job submitted [JOB1234](command:zowe.jobs.setJobSpool?%5B%22sestest%22%2C%22JOB1234%22%5D)" + ); + commandSpy.mockClear(); + }); + it("Checking submit of JCL file from VSC explorer tree", async () => { createGlobalMocks(); const blockMocks: any = createBlockMocks(); mocked(zowe.ZosmfSession.createSessCfgFromArgs).mockReturnValue(blockMocks.session); @@ -527,20 +560,20 @@ describe("Jobs Actions Unit Tests - Function submitJcl", () => { expect(blockMocks.errorLogSpy).toBeCalledWith(errorMsg); expect(blockMocks.errorGuiMsgSpy).toBeCalledWith(errorMsg); }); - // it("Checking failure of submitting JCL via command palette if not active text editor", async () => { - // createGlobalMocks(); - // Object.defineProperty(vscode.workspace, "activeTextEditor", { - // value: jest.fn().mockReturnValue(undefined), - // configurable: true, - // }); - // const blockMocks = createBlockMocks(); - - // await dsActions.submitJcl(blockMocks.testDatasetTree, undefined); - - // const errorMsg = "No editor with a document that could be submitted as JCL is currently open."; - // expect(blockMocks.errorLogSpy).toBeCalledWith(errorMsg); - // expect(blockMocks.errorGuiMsgSpy).toBeCalledWith(errorMsg); - // }); + it("Checking failure of submitting JCL via command palette if not active text editor", async () => { + createGlobalMocks(); + const blockMocks = createBlockMocks(); + Object.defineProperty(vscode.window, "activeTextEditor", { + value: undefined, + configurable: true, + }); + + await dsActions.submitJcl(blockMocks.testDatasetTree, undefined); + + const errorMsg = "No editor with a document that could be submitted as JCL is currently open."; + expect(blockMocks.errorLogSpy).toBeCalledWith(errorMsg); + expect(blockMocks.errorGuiMsgSpy).toBeCalledWith(errorMsg); + }); it("Checking failed attempt to submit of active text editor content as JCL without profile chosen from quickpick", async () => { createGlobalMocks(); From 7311c533d07d22718168b86e8d4208210e74daf0 Mon Sep 17 00:00:00 2001 From: Rudy Flores <68666202+rudyflores@users.noreply.github.com> Date: Tue, 17 Oct 2023 14:41:31 -0400 Subject: [PATCH 134/189] code cleanup Signed-off-by: Rudy Flores <68666202+rudyflores@users.noreply.github.com> --- packages/zowe-explorer/src/Profiles.ts | 38 +++++++++++++++++++++----- 1 file changed, 31 insertions(+), 7 deletions(-) diff --git a/packages/zowe-explorer/src/Profiles.ts b/packages/zowe-explorer/src/Profiles.ts index ca1e454438..6762b9b08a 100644 --- a/packages/zowe-explorer/src/Profiles.ts +++ b/packages/zowe-explorer/src/Profiles.ts @@ -1203,23 +1203,41 @@ export class Profiles extends ProfilesCache { } } - public clearFiltersFromTrees(node: IZoweNodeType): void { - const dsNode: IZoweDatasetTreeNode = TreeProviders.ds.mSessionNodes.find((n) => n.getProfile()?.name === node.getProfile()?.name); - const ussNode: IZoweUSSTreeNode = TreeProviders.uss.mSessionNodes.find((n) => n.getProfile()?.name === node.getProfile()?.name); - const jobNode: IZoweJobTreeNode = TreeProviders.job.mSessionNodes.find((n) => n.getProfile()?.name === node.getProfile()?.name); - + public clearDSFilterFromTree(node: IZoweNodeType): void { + if (!TreeProviders.ds || !TreeProviders.ds.mSessionNodes) { + return; + } + const dsNode: IZoweDatasetTreeNode = TreeProviders.ds.mSessionNodes.find( + (sessionNode: IZoweDatasetTreeNode) => sessionNode.getProfile()?.name === node.getProfile()?.name + ); dsNode.tooltip = node.getProfile()?.name; dsNode.description = ""; dsNode.pattern = ""; TreeProviders.ds.flipState(dsNode, false); TreeProviders.ds.refreshElement(dsNode); + } + public clearUSSFilterFromTree(node: IZoweNodeType): void { + if (!TreeProviders.uss || !TreeProviders.uss.mSessionNodes) { + return; + } + const ussNode: IZoweUSSTreeNode = TreeProviders.uss.mSessionNodes.find( + (sessionNode: IZoweUSSTreeNode) => sessionNode.getProfile()?.name === node.getProfile()?.name + ); ussNode.tooltip = node.getProfile()?.name; ussNode.description = ""; ussNode.fullPath = ""; TreeProviders.uss.flipState(ussNode, false); TreeProviders.uss.refreshElement(ussNode); + } + public clearJobFilterFromTree(node: IZoweNodeType): void { + if (!TreeProviders.job || !TreeProviders.job.mSessionNodes) { + return; + } + const jobNode: IZoweJobTreeNode = TreeProviders.job.mSessionNodes.find( + (sessionNode: IZoweJobTreeNode) => sessionNode.getProfile()?.name === node.getProfile()?.name + ); jobNode.tooltip = node.getProfile()?.name; jobNode.description = ""; jobNode.owner = ""; @@ -1231,6 +1249,12 @@ export class Profiles extends ProfilesCache { TreeProviders.job.refreshElement(jobNode); } + public clearFilterFromAllTrees(node: IZoweNodeType): void { + this.clearDSFilterFromTree(node); + this.clearUSSFilterFromTree(node); + this.clearJobFilterFromTree(node); + } + public async ssoLogout(node: IZoweNodeType): Promise { ZoweLogger.trace("Profiles.ssoLogout called."); const serviceProfile = node.getProfile(); @@ -1242,9 +1266,9 @@ export class Profiles extends ProfilesCache { return; } - this.clearFiltersFromTrees(node); - try { + this.clearFilterFromAllTrees(node); + // this will handle extenders if (serviceProfile.type !== "zosmf" && serviceProfile.profile?.tokenType !== zowe.imperative.SessConstants.TOKEN_TYPE_APIML) { await ZoweExplorerApiRegister.getInstance() From 577d39ecfe21cb0b5b0ff3647ab0f7dbd6a19a04 Mon Sep 17 00:00:00 2001 From: Rudy Flores <68666202+rudyflores@users.noreply.github.com> Date: Tue, 17 Oct 2023 16:02:31 -0400 Subject: [PATCH 135/189] add code coverage Signed-off-by: Rudy Flores <68666202+rudyflores@users.noreply.github.com> --- .../__unit__/Profiles.extended.unit.test.ts | 35 +++++++++++++++ ....test.ts => ZoweTreeProvider.unit.test.ts} | 0 .../__unit__/shared/TreeProvider.unit.test.ts | 43 +++++++++++++++++++ packages/zowe-explorer/src/Profiles.ts | 6 +-- 4 files changed, 81 insertions(+), 3 deletions(-) rename packages/zowe-explorer/__tests__/__unit__/abstract/{TreeProvider.unit.test.ts => ZoweTreeProvider.unit.test.ts} (100%) create mode 100644 packages/zowe-explorer/__tests__/__unit__/shared/TreeProvider.unit.test.ts diff --git a/packages/zowe-explorer/__tests__/__unit__/Profiles.extended.unit.test.ts b/packages/zowe-explorer/__tests__/__unit__/Profiles.extended.unit.test.ts index 8f87010c86..8a72d9283d 100644 --- a/packages/zowe-explorer/__tests__/__unit__/Profiles.extended.unit.test.ts +++ b/packages/zowe-explorer/__tests__/__unit__/Profiles.extended.unit.test.ts @@ -1809,3 +1809,38 @@ describe("Profiles Unit Tests - function getSecurePropsForProfile", () => { await expect(Profiles.getInstance().getSecurePropsForProfile(globalMocks.testProfile.name ?? "")).resolves.toEqual(["tokenValue"]); }); }); + +describe("Profiles Unit Tests - function clearFilterFromAllTrees", () => { + afterEach(() => { + jest.clearAllMocks(); + jest.resetModules(); + jest.restoreAllMocks(); + }); + + it("should fail to clear filter if no session nodes are available", async () => { + const globalMocks = await createGlobalMocks(); + const testNode = new (ZoweTreeNode as any)( + "fake", + vscode.TreeItemCollapsibleState.None, + undefined, + globalMocks.testSession, + globalMocks.testProfile + ); + + const flipStateSpy = jest.fn(); + const refreshElementSpy = jest.fn(); + + const mockTreeProvider = { + mSessionNodes: [], + flipState: flipStateSpy, + refreshElement: refreshElementSpy, + } as any; + jest.spyOn(TreeProviders, "ds", "get").mockReturnValue(mockTreeProvider); + jest.spyOn(TreeProviders, "uss", "get").mockReturnValue(mockTreeProvider); + jest.spyOn(TreeProviders, "job", "get").mockReturnValue(mockTreeProvider); + + expect(Profiles.getInstance().clearFilterFromAllTrees(testNode)); + expect(flipStateSpy).toBeCalledTimes(0); + expect(refreshElementSpy).toBeCalledTimes(0); + }); +}); diff --git a/packages/zowe-explorer/__tests__/__unit__/abstract/TreeProvider.unit.test.ts b/packages/zowe-explorer/__tests__/__unit__/abstract/ZoweTreeProvider.unit.test.ts similarity index 100% rename from packages/zowe-explorer/__tests__/__unit__/abstract/TreeProvider.unit.test.ts rename to packages/zowe-explorer/__tests__/__unit__/abstract/ZoweTreeProvider.unit.test.ts diff --git a/packages/zowe-explorer/__tests__/__unit__/shared/TreeProvider.unit.test.ts b/packages/zowe-explorer/__tests__/__unit__/shared/TreeProvider.unit.test.ts new file mode 100644 index 0000000000..7b1f542251 --- /dev/null +++ b/packages/zowe-explorer/__tests__/__unit__/shared/TreeProvider.unit.test.ts @@ -0,0 +1,43 @@ +/** + * This program and the accompanying materials are made available under the terms of the + * Eclipse Public License v2.0 which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-v20.html + * + * SPDX-License-Identifier: EPL-2.0 + * + * Copyright Contributors to the Zowe Project. + * + */ + +import { createTreeView } from "../../../__mocks__/mockCreators/shared"; +import { TreeProviders } from "../../../src/shared/TreeProviders"; + +describe("TreeProvider Unit Tests - Function getters", () => { + it("should retrieve the ds provider", async () => { + const mockTree = createTreeView("ds"); + await TreeProviders.initializeProviders({} as any, { + ds: jest.fn(() => mockTree) as any, + uss: jest.fn(), + job: jest.fn(), + }); + expect(TreeProviders.ds).toEqual(mockTree); + }); + it("should retrieve the uss provider", async () => { + const mockTree = createTreeView("uss"); + await TreeProviders.initializeProviders({} as any, { + ds: jest.fn(), + uss: jest.fn(() => mockTree) as any, + job: jest.fn(), + }); + expect(TreeProviders.uss).toEqual(mockTree); + }); + it("should retrieve the uss provider", async () => { + const mockTree = createTreeView("job"); + await TreeProviders.initializeProviders({} as any, { + ds: jest.fn(), + uss: jest.fn(), + job: jest.fn(() => mockTree) as any, + }); + expect(TreeProviders.job).toEqual(mockTree); + }); +}); diff --git a/packages/zowe-explorer/src/Profiles.ts b/packages/zowe-explorer/src/Profiles.ts index 6762b9b08a..4dc3274637 100644 --- a/packages/zowe-explorer/src/Profiles.ts +++ b/packages/zowe-explorer/src/Profiles.ts @@ -1204,7 +1204,7 @@ export class Profiles extends ProfilesCache { } public clearDSFilterFromTree(node: IZoweNodeType): void { - if (!TreeProviders.ds || !TreeProviders.ds.mSessionNodes) { + if (!TreeProviders.ds?.mSessionNodes || !TreeProviders.ds?.mSessionNodes.length) { return; } const dsNode: IZoweDatasetTreeNode = TreeProviders.ds.mSessionNodes.find( @@ -1218,7 +1218,7 @@ export class Profiles extends ProfilesCache { } public clearUSSFilterFromTree(node: IZoweNodeType): void { - if (!TreeProviders.uss || !TreeProviders.uss.mSessionNodes) { + if (!TreeProviders.uss?.mSessionNodes || !TreeProviders.uss?.mSessionNodes.length) { return; } const ussNode: IZoweUSSTreeNode = TreeProviders.uss.mSessionNodes.find( @@ -1232,7 +1232,7 @@ export class Profiles extends ProfilesCache { } public clearJobFilterFromTree(node: IZoweNodeType): void { - if (!TreeProviders.job || !TreeProviders.job.mSessionNodes) { + if (!TreeProviders.job?.mSessionNodes || !TreeProviders.job?.mSessionNodes.length) { return; } const jobNode: IZoweJobTreeNode = TreeProviders.job.mSessionNodes.find( From 2ea9ce5915316160ea6a37348504c27d8d542b07 Mon Sep 17 00:00:00 2001 From: Trae Yelovich Date: Tue, 17 Oct 2023 17:30:31 -0400 Subject: [PATCH 136/189] feat(ds): show descriptions for filter and sort values for clarity Signed-off-by: Trae Yelovich --- .../__unit__/dataset/DatasetTree.unit.test.ts | 3 ++- .../i18n/sample/src/dataset/DatasetTree.i18n.json | 1 + packages/zowe-explorer/src/dataset/DatasetTree.ts | 11 +++++++++++ packages/zowe-explorer/src/dataset/ZoweDatasetNode.ts | 5 ++++- 4 files changed, 18 insertions(+), 2 deletions(-) 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 65cb06a4a7..9965c6181a 100644 --- a/packages/zowe-explorer/__tests__/__unit__/dataset/DatasetTree.unit.test.ts +++ b/packages/zowe-explorer/__tests__/__unit__/dataset/DatasetTree.unit.test.ts @@ -2826,7 +2826,8 @@ describe("Dataset Tree Unit Tests - Sorting and Filtering operations", () => { nodes.pds.filter = { method: DatasetFilterOpts.UserId, value: "invalidUserId" }; nodes.pds.children = []; await tree.filterPdsMembersDialog(nodes.pds); - expect(mocks.nodeDataChanged).not.toHaveBeenCalled(); + // nodeDataChanged called once to show new description + expect(mocks.nodeDataChanged).toHaveBeenCalledWith(nodes.pds); expect(mocks.refreshElement).toHaveBeenCalledWith(nodes.pds); }); diff --git a/packages/zowe-explorer/i18n/sample/src/dataset/DatasetTree.i18n.json b/packages/zowe-explorer/i18n/sample/src/dataset/DatasetTree.i18n.json index a466d5c330..61d6e5e457 100644 --- a/packages/zowe-explorer/i18n/sample/src/dataset/DatasetTree.i18n.json +++ b/packages/zowe-explorer/i18n/sample/src/dataset/DatasetTree.i18n.json @@ -32,6 +32,7 @@ "setSortDirection": "$(fold) Sort Direction", "sort.selectDirection": "Select a sorting direction", "sort.updated": "$(check) Sorting updated for {0}", + "filter.description": "Filter: {0}", "ds.clearProfileFilter": "$(clear-all) Clear filter for profile", "ds.clearPdsFilter": "$(clear-all) Clear filter for PDS", "ds.selectFilterOpt": "Set a filter for {0}", diff --git a/packages/zowe-explorer/src/dataset/DatasetTree.ts b/packages/zowe-explorer/src/dataset/DatasetTree.ts index c479f8141f..dcd5ed2b91 100644 --- a/packages/zowe-explorer/src/dataset/DatasetTree.ts +++ b/packages/zowe-explorer/src/dataset/DatasetTree.ts @@ -1310,12 +1310,21 @@ export class DatasetTree extends ZoweTreeProvider implements IZoweTree 0) { + for (const c of node.children) { + // remove any descriptions from child nodes + c.description = ""; + } // children nodes already exist, sort and repaint to avoid extra refresh node.children.sort(ZoweDatasetNode.sortBy(node.sort)); this.nodeDataChanged(node); @@ -1387,6 +1396,8 @@ export class DatasetTree extends ZoweTreeProvider implements IZoweTree Date: Wed, 18 Oct 2023 09:03:45 -0400 Subject: [PATCH 137/189] address code smells Signed-off-by: Billie Simmons <49491949+JillieBeanSim@users.noreply.github.com> --- .../__tests__/__unit__/job/actions.unit.test.ts | 12 ++---------- packages/zowe-explorer/src/dataset/actions.ts | 1 - 2 files changed, 2 insertions(+), 11 deletions(-) diff --git a/packages/zowe-explorer/__tests__/__unit__/job/actions.unit.test.ts b/packages/zowe-explorer/__tests__/__unit__/job/actions.unit.test.ts index 87a0ab588e..81256609a4 100644 --- a/packages/zowe-explorer/__tests__/__unit__/job/actions.unit.test.ts +++ b/packages/zowe-explorer/__tests__/__unit__/job/actions.unit.test.ts @@ -488,11 +488,7 @@ describe("Jobs Actions Unit Tests - Function submitJcl", () => { const blockMocks: any = createBlockMocks(); mocked(zowe.ZosmfSession.createSessCfgFromArgs).mockReturnValue(blockMocks.session); mocked(Profiles.getInstance).mockReturnValue(blockMocks.profileInstance); - mocked(vscode.window.showQuickPick).mockReturnValueOnce( - new Promise((resolve) => { - resolve(blockMocks.datasetSessionNode.label); - }) - ); + mocked(vscode.window.showQuickPick).mockReturnValueOnce(Promise.resolve(blockMocks.datasetSessionNode.label)); blockMocks.testDatasetTree.getChildren.mockResolvedValueOnce([ new ZoweDatasetNode("node", vscode.TreeItemCollapsibleState.None, blockMocks.datasetSessionNode, null as any), blockMocks.datasetSessionNode, @@ -543,11 +539,7 @@ describe("Jobs Actions Unit Tests - Function submitJcl", () => { const blockMocks: any = createBlockMocks(); mocked(zowe.ZosmfSession.createSessCfgFromArgs).mockReturnValue(blockMocks.session); mocked(Profiles.getInstance).mockReturnValue(blockMocks.profileInstance); - mocked(vscode.window.showQuickPick).mockReturnValueOnce( - new Promise((resolve) => { - resolve(blockMocks.datasetSessionNode.label); - }) - ); + mocked(vscode.window.showQuickPick).mockReturnValueOnce(Promise.resolve(blockMocks.datasetSessionNode.label)); blockMocks.testDatasetTree.getChildren.mockResolvedValueOnce([ new ZoweDatasetNode("node", vscode.TreeItemCollapsibleState.None, blockMocks.datasetSessionNode, null as any), blockMocks.datasetSessionNode, diff --git a/packages/zowe-explorer/src/dataset/actions.ts b/packages/zowe-explorer/src/dataset/actions.ts index d555694ead..cd034a4fec 100644 --- a/packages/zowe-explorer/src/dataset/actions.ts +++ b/packages/zowe-explorer/src/dataset/actions.ts @@ -991,7 +991,6 @@ export async function submitJcl(datasetProvider: api.IZoweTree Date: Wed, 18 Oct 2023 09:17:31 -0400 Subject: [PATCH 138/189] chore: Update CHANGELOG Signed-off-by: Trae Yelovich --- packages/zowe-explorer/CHANGELOG.md | 1 + packages/zowe-explorer/src/dataset/ZoweDatasetNode.ts | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/zowe-explorer/CHANGELOG.md b/packages/zowe-explorer/CHANGELOG.md index 21ae5fd53e..adad1b3c69 100644 --- a/packages/zowe-explorer/CHANGELOG.md +++ b/packages/zowe-explorer/CHANGELOG.md @@ -12,6 +12,7 @@ All notable changes to the "vscode-extension-for-zowe" extension will be documen - Added new API {ZE Extender MetaData} to allow extenders to have the metadata of registered extenders to aid in team configuration file creation from a view that isn't Zowe Explorer's. [#2394](https://github.com/zowe/vscode-extension-for-zowe/issues/2394) - Added "Sort PDS members" feature in Data Sets tree view: accessible via sort icon on session node, or by right-clicking a PDS or session. [#2420](https://github.com/zowe/vscode-extension-for-zowe/issues/2420) - Added "Filter PDS members" feature in Data Sets tree view: accessible via filter icon on session node, or by right-clicking a PDS or session. [#2420](https://github.com/zowe/vscode-extension-for-zowe/issues/2420) +- Added descriptions to data set nodes if filtering and/or sorting is enabled (where applicable). ### Bug fixes diff --git a/packages/zowe-explorer/src/dataset/ZoweDatasetNode.ts b/packages/zowe-explorer/src/dataset/ZoweDatasetNode.ts index 6fc5bd6231..87d743fe78 100644 --- a/packages/zowe-explorer/src/dataset/ZoweDatasetNode.ts +++ b/packages/zowe-explorer/src/dataset/ZoweDatasetNode.ts @@ -339,7 +339,7 @@ export class ZoweDatasetNode extends ZoweTreeNode implements IZoweDatasetTreeNod return a.stats?.modifiedDate < b.stats?.modifiedDate ? sortLessThan : sortGreaterThan; case DatasetSortOpts.UserId: a.description = a.stats?.user; - a.description = a.stats?.user; + b.description = b.stats?.user; return a.stats?.user < b.stats?.user ? sortLessThan : sortGreaterThan; case DatasetSortOpts.Name: return (a.label as string) < (b.label as string) ? sortLessThan : sortGreaterThan; From ebd9a2615f65157dbef5ade1cb296434da1c3038 Mon Sep 17 00:00:00 2001 From: Trae Yelovich Date: Wed, 18 Oct 2023 09:46:56 -0400 Subject: [PATCH 139/189] fix(ds/sort): Handle edge cases to ensure proper sorting Signed-off-by: Trae Yelovich --- packages/zowe-explorer/src/dataset/ZoweDatasetNode.ts | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/packages/zowe-explorer/src/dataset/ZoweDatasetNode.ts b/packages/zowe-explorer/src/dataset/ZoweDatasetNode.ts index 87d743fe78..f46de2ba3e 100644 --- a/packages/zowe-explorer/src/dataset/ZoweDatasetNode.ts +++ b/packages/zowe-explorer/src/dataset/ZoweDatasetNode.ts @@ -272,7 +272,7 @@ export class ZoweDatasetNode extends ZoweTreeNode implements IZoweDatasetTreeNod // missing keys from API response; check for FTP keys temp.stats = { user: item.id, - modifiedDate: item.changed ? dayjs(item.changed).toDate() : null, + modifiedDate: item.changed ? dayjs(item.changed).toDate() : undefined, }; } elementChildren[temp.label.toString()] = temp; @@ -332,6 +332,10 @@ export class ZoweDatasetNode extends ZoweTreeNode implements IZoweDatasetTreeNod const sortLessThan = sort.direction == SortDirection.Ascending ? -1 : 1; const sortGreaterThan = sortLessThan * -1; + if (!a.stats && !b.stats) { + return (a.label as string) < (b.label as string) ? sortLessThan : sortGreaterThan; + } + switch (sort.method) { case DatasetSortOpts.LastModified: a.description = dayjs(a.stats?.modifiedDate).format("YYYY/MM/DD HH:mm:ss"); From fe0619d19b5c1821c38d396b0ff9ecbde58cea65 Mon Sep 17 00:00:00 2001 From: Trae Yelovich Date: Wed, 18 Oct 2023 10:11:35 -0400 Subject: [PATCH 140/189] test(ds/sort): Add case for resetting node descriptions at session-level Signed-off-by: Trae Yelovich --- .../__unit__/dataset/DatasetTree.unit.test.ts | 12 ++++++++++++ 1 file changed, 12 insertions(+) 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 9965c6181a..209564b7be 100644 --- a/packages/zowe-explorer/__tests__/__unit__/dataset/DatasetTree.unit.test.ts +++ b/packages/zowe-explorer/__tests__/__unit__/dataset/DatasetTree.unit.test.ts @@ -2767,6 +2767,7 @@ describe("Dataset Tree Unit Tests - Sorting and Filtering operations", () => { expect(mocks.nodeDataChanged).toHaveBeenCalled(); expect(mocks.refreshElement).not.toHaveBeenCalled(); expect(nodes.pds.children?.map((c: IZoweDatasetTreeNode) => c.label)).toStrictEqual(["A", "B", "C"]); + expect(nodes.pds.children?.reduce((val, cur) => val + (cur.description as string), "")).toBe(""); }); it("sorts by last modified date", async () => { @@ -2800,6 +2801,17 @@ describe("Dataset Tree Unit Tests - Sorting and Filtering operations", () => { expect(mocks.refreshElement).not.toHaveBeenCalled(); expect(sortPdsMembersDialog).toHaveBeenCalledTimes(2); }); + + it("sorting by session: descriptions are reset when sorted by name", async () => { + const mocks = getBlockMocks(); + const nodes = nodesForSuite(); + mocks.showQuickPick.mockResolvedValueOnce({ label: "$(case-sensitive) Name (default)" }); + await tree.sortPdsMembersDialog(nodes.session); + expect(mocks.nodeDataChanged).toHaveBeenCalled(); + expect(mocks.refreshElement).not.toHaveBeenCalled(); + expect(nodes.pds.children?.map((c: IZoweDatasetTreeNode) => c.label)).toStrictEqual(["A", "B", "C"]); + expect(nodes.pds.children?.reduce((val, cur) => val + (cur.description as string), "")).toBe(""); + }); }); describe("filterBy & filterPdsMembersDialog", () => { From f6f9ad95297a7a2af7ccd7257e376c4bec9d0c83 Mon Sep 17 00:00:00 2001 From: Rudy Flores <68666202+rudyflores@users.noreply.github.com> Date: Wed, 18 Oct 2023 12:51:10 -0400 Subject: [PATCH 141/189] remove icons due to packaging conflict Signed-off-by: Rudy Flores <68666202+rudyflores@users.noreply.github.com> --- .../src/edit-history/assets/checklist.svg | 3 --- .../src/edit-history/assets/clear-all.svg | 7 ------ .../webviews/src/edit-history/assets/plus.svg | 1 - .../src/edit-history/assets/refresh.svg | 1 - .../src/edit-history/assets/trash.svg | 2 -- .../PersistentAddNewHistoryItemButton.tsx | 2 +- .../PersistentClearAllButton.tsx | 2 +- .../PersistentDeleteSelectedButton.tsx | 2 +- .../PersistentRefreshButton.tsx | 2 +- .../PersistentSelectAllButton.tsx | 22 ------------------- .../PersistentToolBar/PersistentToolBar.tsx | 2 -- .../zowe-explorer/src/webviews/tsconfig.json | 3 ++- .../zowe-explorer/src/webviews/vite.config.ts | 9 ++++---- 13 files changed, 10 insertions(+), 48 deletions(-) delete mode 100644 packages/zowe-explorer/src/webviews/src/edit-history/assets/checklist.svg delete mode 100644 packages/zowe-explorer/src/webviews/src/edit-history/assets/clear-all.svg delete mode 100644 packages/zowe-explorer/src/webviews/src/edit-history/assets/plus.svg delete mode 100644 packages/zowe-explorer/src/webviews/src/edit-history/assets/refresh.svg delete mode 100644 packages/zowe-explorer/src/webviews/src/edit-history/assets/trash.svg delete mode 100644 packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentToolBar/PersistentSelectAllButton.tsx diff --git a/packages/zowe-explorer/src/webviews/src/edit-history/assets/checklist.svg b/packages/zowe-explorer/src/webviews/src/edit-history/assets/checklist.svg deleted file mode 100644 index d4811a86c2..0000000000 --- a/packages/zowe-explorer/src/webviews/src/edit-history/assets/checklist.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/packages/zowe-explorer/src/webviews/src/edit-history/assets/clear-all.svg b/packages/zowe-explorer/src/webviews/src/edit-history/assets/clear-all.svg deleted file mode 100644 index 24571c077f..0000000000 --- a/packages/zowe-explorer/src/webviews/src/edit-history/assets/clear-all.svg +++ /dev/null @@ -1,7 +0,0 @@ - - - - - - - diff --git a/packages/zowe-explorer/src/webviews/src/edit-history/assets/plus.svg b/packages/zowe-explorer/src/webviews/src/edit-history/assets/plus.svg deleted file mode 100644 index 2f8606ea31..0000000000 --- a/packages/zowe-explorer/src/webviews/src/edit-history/assets/plus.svg +++ /dev/null @@ -1 +0,0 @@ - diff --git a/packages/zowe-explorer/src/webviews/src/edit-history/assets/refresh.svg b/packages/zowe-explorer/src/webviews/src/edit-history/assets/refresh.svg deleted file mode 100644 index d79fdaa4e8..0000000000 --- a/packages/zowe-explorer/src/webviews/src/edit-history/assets/refresh.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/packages/zowe-explorer/src/webviews/src/edit-history/assets/trash.svg b/packages/zowe-explorer/src/webviews/src/edit-history/assets/trash.svg deleted file mode 100644 index a0772f3802..0000000000 --- a/packages/zowe-explorer/src/webviews/src/edit-history/assets/trash.svg +++ /dev/null @@ -1,2 +0,0 @@ - - diff --git a/packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentToolBar/PersistentAddNewHistoryItemButton.tsx b/packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentToolBar/PersistentAddNewHistoryItemButton.tsx index b217118627..6daaa283de 100644 --- a/packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentToolBar/PersistentAddNewHistoryItemButton.tsx +++ b/packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentToolBar/PersistentAddNewHistoryItemButton.tsx @@ -34,7 +34,7 @@ export default function PersistentAddNewHistoryItemButton(): JSXInternal.Element const renderAddItemButton = () => { return selection[type] === "search" && type !== "jobs" ? ( - + Add ) : null; }; diff --git a/packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentToolBar/PersistentClearAllButton.tsx b/packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentToolBar/PersistentClearAllButton.tsx index 83337dc0d4..39ca37d232 100644 --- a/packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentToolBar/PersistentClearAllButton.tsx +++ b/packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentToolBar/PersistentClearAllButton.tsx @@ -35,7 +35,7 @@ export default function PersistentClearAllButton(): JSXInternal.Element { return selection[type] === "search" || selection[type] === "fileHistory" ? ( - + Clear All ) : null; }; diff --git a/packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentToolBar/PersistentDeleteSelectedButton.tsx b/packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentToolBar/PersistentDeleteSelectedButton.tsx index 0f2b4c0d2a..8806995caf 100644 --- a/packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentToolBar/PersistentDeleteSelectedButton.tsx +++ b/packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentToolBar/PersistentDeleteSelectedButton.tsx @@ -46,7 +46,7 @@ export default function PersistentDeleteSelectedButton(): JSXInternal.Element { style={{ maxWidth: "20vw", marginRight: "15px" }} onClick={async () => await handleClick()} > - + Delete ) : null; }; diff --git a/packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentToolBar/PersistentRefreshButton.tsx b/packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentToolBar/PersistentRefreshButton.tsx index 1d97fe8511..543356e77a 100644 --- a/packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentToolBar/PersistentRefreshButton.tsx +++ b/packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentToolBar/PersistentRefreshButton.tsx @@ -33,7 +33,7 @@ export default function PersistentRefreshButton(): JSXInternal.Element { return ( - + Refresh ); } diff --git a/packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentToolBar/PersistentSelectAllButton.tsx b/packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentToolBar/PersistentSelectAllButton.tsx deleted file mode 100644 index 2d5c58bcff..0000000000 --- a/packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentToolBar/PersistentSelectAllButton.tsx +++ /dev/null @@ -1,22 +0,0 @@ -import { VSCodeButton } from "@vscode/webview-ui-toolkit/react"; -import { JSXInternal } from "preact/src/jsx"; -import * as nls from "vscode-nls"; -import { useDataPanelContext } from "../PersistentUtils"; - -const localize: nls.LocalizeFunc = nls.loadMessageBundle(); - -export default function PersistentSelectAllButton(): JSXInternal.Element { - const selectAllText = localize("PersistentSelectAllButton.selectAll", "Select All"); - - const { selectAll } = useDataPanelContext(); - - const handleClick = () => { - selectAll.setVal(!selectAll.val); - }; - - return ( - handleClick()}> - - - ); -} diff --git a/packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentToolBar/PersistentToolBar.tsx b/packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentToolBar/PersistentToolBar.tsx index 51ec5a19be..6e5d745833 100644 --- a/packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentToolBar/PersistentToolBar.tsx +++ b/packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentToolBar/PersistentToolBar.tsx @@ -15,7 +15,6 @@ import PersistentRefreshButton from "./PersistentRefreshButton"; import PersistentDropdownOptions from "./PersistentDropdownOptions"; import PersistentAddNewHistoryItemButton from "./PersistentAddNewHistoryItemButton"; import PersistentDeleteSelectedButton from "./PersistentDeleteSelectedButton"; -import PersistentSelectAllButton from "./PersistentSelectAllButton"; export default function PersistentToolBar({ handleChange }: { handleChange: Function }): JSXInternal.Element { return ( @@ -25,7 +24,6 @@ export default function PersistentToolBar({ handleChange }: { handleChange: Func -
); } diff --git a/packages/zowe-explorer/src/webviews/tsconfig.json b/packages/zowe-explorer/src/webviews/tsconfig.json index 58f679257b..464518df51 100644 --- a/packages/zowe-explorer/src/webviews/tsconfig.json +++ b/packages/zowe-explorer/src/webviews/tsconfig.json @@ -19,7 +19,8 @@ "strict": true, "noUnusedLocals": true, "noUnusedParameters": true, - "noFallthroughCasesInSwitch": true + "noFallthroughCasesInSwitch": true, + "types": ["vite/client"] }, "include": ["src"], "references": [{ "path": "./tsconfig.node.json" }] diff --git a/packages/zowe-explorer/src/webviews/vite.config.ts b/packages/zowe-explorer/src/webviews/vite.config.ts index 73818301e4..63643cfaa5 100644 --- a/packages/zowe-explorer/src/webviews/vite.config.ts +++ b/packages/zowe-explorer/src/webviews/vite.config.ts @@ -28,11 +28,10 @@ interface Webviews { * @returns Object the object where the key is the webview and the value is the location of the webview */ const getAvailableWebviews = (source: string): Webviews => { - const webviews = readdirSync(source, { withFileTypes: true }) + return readdirSync(source, { withFileTypes: true }) .filter((dirent) => dirent.isDirectory()) - .map((dirent) => dirent.name); - - return webviews.reduce((o, key) => Object.assign(o, { [key]: path.resolve("src", key, "index.html") }), {}); + .map((dirent) => dirent.name) + .reduce((o, key) => Object.assign(o, { [key]: path.resolve("src", key, "index.html") }), {}); }; export default defineConfig({ @@ -51,7 +50,7 @@ export default defineConfig({ output: { entryFileNames: `[name]/[name].js`, chunkFileNames: `[name]/[name].js`, - assetFileNames: `[name]/[name].[ext]`, + assetFileNames: `assets/[name].[ext]`, }, }, }, From d898363f9b65c9a4dc83bfe783d51aa818a68e19 Mon Sep 17 00:00:00 2001 From: Rudy Flores <68666202+rudyflores@users.noreply.github.com> Date: Wed, 18 Oct 2023 13:03:02 -0400 Subject: [PATCH 142/189] fix broken unit tests Signed-off-by: Rudy Flores <68666202+rudyflores@users.noreply.github.com> --- .../zowe-explorer/__tests__/__unit__/extension.unit.test.ts | 1 + packages/zowe-explorer/src/globals.ts | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/zowe-explorer/__tests__/__unit__/extension.unit.test.ts b/packages/zowe-explorer/__tests__/__unit__/extension.unit.test.ts index 7e5df21fd1..acc51871c3 100644 --- a/packages/zowe-explorer/__tests__/__unit__/extension.unit.test.ts +++ b/packages/zowe-explorer/__tests__/__unit__/extension.unit.test.ts @@ -242,6 +242,7 @@ async function createGlobalMocks() { "zowe.jobs.cancelJob", "zowe.jobs.sortBy", "zowe.manualPoll", + "zowe.editHistory", "zowe.updateSecureCredentials", "zowe.promptCredentials", "zowe.profileManagement", diff --git a/packages/zowe-explorer/src/globals.ts b/packages/zowe-explorer/src/globals.ts index b8d95dfc77..3624a6a84e 100644 --- a/packages/zowe-explorer/src/globals.ts +++ b/packages/zowe-explorer/src/globals.ts @@ -35,7 +35,7 @@ export let DS_DIR: string; export let CONFIG_PATH; // set during activate export let ISTHEIA = false; // set during activate export let LOG: imperative.Logger; -export const COMMAND_COUNT = 114; +export const COMMAND_COUNT = 115; export const MAX_SEARCH_HISTORY = 5; export const MAX_FILE_HISTORY = 10; export const MS_PER_SEC = 1000; From b14013c2849cabb3b0a1293f6e4a6b8ef9b24f42 Mon Sep 17 00:00:00 2001 From: Rudy Flores <68666202+rudyflores@users.noreply.github.com> Date: Wed, 18 Oct 2023 14:02:59 -0400 Subject: [PATCH 143/189] add code coverage Signed-off-by: Rudy Flores <68666202+rudyflores@users.noreply.github.com> --- .../__unit__/PersistentFilters.unit.test.ts | 8 ++++ .../__unit__/dataset/DatasetTree.unit.test.ts | 47 +++++++++++++++++++ .../__unit__/job/ZosJobsProvider.unit.test.ts | 31 ++++++++++++ .../__unit__/shared/init.unit.test.ts | 5 ++ .../__unit__/uss/USSTree.unit.test.ts | 35 ++++++++++++++ packages/zowe-explorer/package.json | 5 -- 6 files changed, 126 insertions(+), 5 deletions(-) diff --git a/packages/zowe-explorer/__tests__/__unit__/PersistentFilters.unit.test.ts b/packages/zowe-explorer/__tests__/__unit__/PersistentFilters.unit.test.ts index c9dcd00ce4..cf4ec8f6d8 100644 --- a/packages/zowe-explorer/__tests__/__unit__/PersistentFilters.unit.test.ts +++ b/packages/zowe-explorer/__tests__/__unit__/PersistentFilters.unit.test.ts @@ -87,4 +87,12 @@ describe("PersistentFilters Unit Test", () => { expect(pf.getDsTemplates()).toEqual([mockTemplate]); }); }); + describe("removeSearchHistory", () => { + it("should remove the specified item from the persistent object", () => { + const pf: PersistentFilters = new PersistentFilters("test", 2, 2); + pf["mSearchHistory"] = ["test1", "test2"]; + pf.removeSearchHistory("test1"); + expect(pf.getSearchHistory().length).toEqual(1); + }); + }); }); 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 65cb06a4a7..0e455aa298 100644 --- a/packages/zowe-explorer/__tests__/__unit__/dataset/DatasetTree.unit.test.ts +++ b/packages/zowe-explorer/__tests__/__unit__/dataset/DatasetTree.unit.test.ts @@ -2897,4 +2897,51 @@ describe("Dataset Tree Unit Tests - Sorting and Filtering operations", () => { expect(updateFilterForNode).toHaveBeenCalledWith(nodes.pds, null, false); }); }); + + describe("removeSearchHistory", () => { + it("removes the search item passed in from the current history", () => { + tree.addSearchHistory("test"); + expect(tree["mHistory"]["mSearchHistory"].length).toEqual(1); + tree.removeSearchHistory("test"); + expect(tree["mHistory"]["mSearchHistory"].length).toEqual(0); + }); + }); + + describe("resetSearchHistory", () => { + it("clears the entire search history", () => { + tree.addSearchHistory("test1"); + tree.addSearchHistory("test2"); + tree.addSearchHistory("test3"); + tree.addSearchHistory("test4"); + expect(tree["mHistory"]["mSearchHistory"].length).toEqual(4); + tree.resetSearchHistory(); + expect(tree["mHistory"]["mSearchHistory"].length).toEqual(0); + }); + }); + + describe("resetFileHistory", () => { + it("clears the entire file history", () => { + tree.addFileHistory("test1"); + tree.addFileHistory("test2"); + tree.addFileHistory("test3"); + tree.addFileHistory("test4"); + expect(tree["mHistory"]["mFileHistory"].length).toEqual(4); + tree.resetFileHistory(); + expect(tree["mHistory"]["mFileHistory"].length).toEqual(0); + }); + }); + + describe("addDsTemplate", () => { + it("adds a new DS template to the persistent object", () => { + tree.addDsTemplate({ test: "test" } as any); + expect(tree["mHistory"]["mDsTemplates"].length).toEqual(1); + }); + }); + + describe("getSessions", () => { + it("gets all the available sessions from persistent object", () => { + tree["mHistory"]["mSessions"] = ["sestest"]; + expect(tree.getSessions()).toEqual(["sestest"]); + }); + }); }); diff --git a/packages/zowe-explorer/__tests__/__unit__/job/ZosJobsProvider.unit.test.ts b/packages/zowe-explorer/__tests__/__unit__/job/ZosJobsProvider.unit.test.ts index da5b74ffa7..4c790ec672 100644 --- a/packages/zowe-explorer/__tests__/__unit__/job/ZosJobsProvider.unit.test.ts +++ b/packages/zowe-explorer/__tests__/__unit__/job/ZosJobsProvider.unit.test.ts @@ -925,3 +925,34 @@ describe("Jobs utils unit tests - Function jobStringValidator", () => { invalidOpts.forEach((invalidOpt) => expect(jobStringValidator(invalidOpt[0], invalidOpt[1])).toContain("Invalid")); }); }); + +describe("removeSearchHistory", () => { + it("removes the search item passed in from the current history", () => { + const tree = new ZosJobsProvider(); + tree.addSearchHistory("test"); + expect(tree["mHistory"]["mSearchHistory"].length).toEqual(1); + tree.removeSearchHistory("test"); + expect(tree["mHistory"]["mSearchHistory"].length).toEqual(0); + }); +}); + +describe("resetSearchHistory", () => { + it("clears the entire search history", () => { + const tree = new ZosJobsProvider(); + tree.addSearchHistory("test1"); + tree.addSearchHistory("test2"); + tree.addSearchHistory("test3"); + tree.addSearchHistory("test4"); + expect(tree["mHistory"]["mSearchHistory"].length).toEqual(4); + tree.resetSearchHistory(); + expect(tree["mHistory"]["mSearchHistory"].length).toEqual(0); + }); +}); + +describe("getSessions", () => { + it("gets all the available sessions from persistent object", () => { + const tree = new ZosJobsProvider(); + tree["mHistory"]["mSessions"] = ["sestest"]; + expect(tree.getSessions()).toEqual(["sestest"]); + }); +}); diff --git a/packages/zowe-explorer/__tests__/__unit__/shared/init.unit.test.ts b/packages/zowe-explorer/__tests__/__unit__/shared/init.unit.test.ts index e6e11e5db0..1ba5e2fd0a 100644 --- a/packages/zowe-explorer/__tests__/__unit__/shared/init.unit.test.ts +++ b/packages/zowe-explorer/__tests__/__unit__/shared/init.unit.test.ts @@ -26,6 +26,7 @@ import { saveUSSFile } from "../../../src/uss/actions"; import { ZoweLogger } from "../../../src/utils/LoggerUtils"; import { ZoweSaveQueue } from "../../../src/abstract/ZoweSaveQueue"; import { ZoweExplorerApiRegister } from "../../../src/ZoweExplorerApiRegister"; +import * as HistoryView from "../../../src/shared/HistoryView"; describe("Test src/shared/extension", () => { describe("registerCommonCommands", () => { @@ -58,6 +59,10 @@ describe("Test src/shared/extension", () => { { spy: jest.spyOn(profUtils.ProfilesUtils, "writeOverridesFile"), arg: [] }, ], }, + { + name: "zowe.editHistory", + mock: [{ spy: jest.spyOn(HistoryView, "HistoryView"), arg: [test.context, test.value.providers] }], + }, { name: "zowe.promptCredentials", mock: [{ spy: jest.spyOn(profUtils.ProfilesUtils, "promptCredentials"), arg: [test.value] }], diff --git a/packages/zowe-explorer/__tests__/__unit__/uss/USSTree.unit.test.ts b/packages/zowe-explorer/__tests__/__unit__/uss/USSTree.unit.test.ts index 56d20ad5b0..e28acf549d 100644 --- a/packages/zowe-explorer/__tests__/__unit__/uss/USSTree.unit.test.ts +++ b/packages/zowe-explorer/__tests__/__unit__/uss/USSTree.unit.test.ts @@ -1698,4 +1698,39 @@ describe("USSTree Unit Tests - Function USSTree.editSession()", () => { globalMocks.testTree.editSession(testSessionNode); expect(checkSession).toHaveBeenCalled(); }); + + describe("removeSearchHistory", () => { + it("removes the search item passed in from the current history", async () => { + const globalMocks = await createGlobalMocks(); + expect(globalMocks.testTree["mHistory"]["mSearchHistory"].length).toEqual(3); + globalMocks.testTree.removeSearchHistory("/u/myuser"); + expect(globalMocks.testTree["mHistory"]["mSearchHistory"].length).toEqual(2); + }); + }); + + describe("resetSearchHistory", () => { + it("clears the entire search history", async () => { + const globalMocks = await createGlobalMocks(); + expect(globalMocks.testTree["mHistory"]["mSearchHistory"].length).toEqual(3); + globalMocks.testTree.resetSearchHistory(); + expect(globalMocks.testTree["mHistory"]["mSearchHistory"].length).toEqual(0); + }); + }); + + describe("resetFileHistory", () => { + it("clears the entire file history", async () => { + const globalMocks = await createGlobalMocks(); + expect(globalMocks.testTree["mHistory"]["mFileHistory"].length).toEqual(2); + globalMocks.testTree.resetFileHistory(); + expect(globalMocks.testTree["mHistory"]["mFileHistory"].length).toEqual(0); + }); + }); + + describe("getSessions", () => { + it("gets all the available sessions from persistent object", async () => { + const globalMocks = await createGlobalMocks(); + globalMocks.testTree["mHistory"]["mSessions"] = ["sestest"]; + expect(globalMocks.testTree.getSessions()).toEqual(["sestest"]); + }); + }); }); diff --git a/packages/zowe-explorer/package.json b/packages/zowe-explorer/package.json index 7aaf5aa7ab..a7be51ddb8 100644 --- a/packages/zowe-explorer/package.json +++ b/packages/zowe-explorer/package.json @@ -1345,11 +1345,6 @@ "command": "zowe.jobs.sortBy", "group": "099_zowe_jobsSort" }, - { - "when": "view == zowe.jobs.explorer && viewItem =~ /^(?!.*_fav.*)server.*/ && !listMultiSelection", - "command": "zowe.jobs.sortbyreturncode", - "group": "000_zowe_jobsProfileModification@2" - }, { "when": "view == zowe.jobs.explorer && viewItem =~ /^(?!.*_fav.*)server.*/ && !listMultiSelection", "command": "zowe.editHistory", From 63f95d6cf427a8c1f7c5814b8d5785b67ff3c3d7 Mon Sep 17 00:00:00 2001 From: Rudy Flores <68666202+rudyflores@users.noreply.github.com> Date: Wed, 18 Oct 2023 14:07:30 -0400 Subject: [PATCH 144/189] add changelog Signed-off-by: Rudy Flores <68666202+rudyflores@users.noreply.github.com> --- packages/zowe-explorer-api/CHANGELOG.md | 1 + packages/zowe-explorer/CHANGELOG.md | 1 + 2 files changed, 2 insertions(+) diff --git a/packages/zowe-explorer-api/CHANGELOG.md b/packages/zowe-explorer-api/CHANGELOG.md index 7dc201454d..9dee31f5b2 100644 --- a/packages/zowe-explorer-api/CHANGELOG.md +++ b/packages/zowe-explorer-api/CHANGELOG.md @@ -11,6 +11,7 @@ All notable changes to the "zowe-explorer-api" extension will be documented in t - Add `sort` and `filter` optional variables for storing sort/filter options alongside tree nodes. [#2420](https://github.com/zowe/vscode-extension-for-zowe/issues/2420) - Add `stats` optional variable for storing dataset stats (such as user, modified date, etc.) - Add option enums and types for sorting, filtering and sort direction in tree nodes. [#2420](https://github.com/zowe/vscode-extension-for-zowe/issues/2420) +- Added option for retaining context when generating webviews in Webview API ### Bug fixes diff --git a/packages/zowe-explorer/CHANGELOG.md b/packages/zowe-explorer/CHANGELOG.md index 21ae5fd53e..1cca536cd5 100644 --- a/packages/zowe-explorer/CHANGELOG.md +++ b/packages/zowe-explorer/CHANGELOG.md @@ -12,6 +12,7 @@ All notable changes to the "vscode-extension-for-zowe" extension will be documen - Added new API {ZE Extender MetaData} to allow extenders to have the metadata of registered extenders to aid in team configuration file creation from a view that isn't Zowe Explorer's. [#2394](https://github.com/zowe/vscode-extension-for-zowe/issues/2394) - Added "Sort PDS members" feature in Data Sets tree view: accessible via sort icon on session node, or by right-clicking a PDS or session. [#2420](https://github.com/zowe/vscode-extension-for-zowe/issues/2420) - Added "Filter PDS members" feature in Data Sets tree view: accessible via filter icon on session node, or by right-clicking a PDS or session. [#2420](https://github.com/zowe/vscode-extension-for-zowe/issues/2420) +- Added webview for editing persistent items on Zowe Explorer [#2488](https://github.com/zowe/vscode-extension-for-zowe/issues/2488) ### Bug fixes From aec67d9442ba2ab6aa3836a329f117a786eacc16 Mon Sep 17 00:00:00 2001 From: Rudy Flores <68666202+rudyflores@users.noreply.github.com> Date: Wed, 18 Oct 2023 14:21:14 -0400 Subject: [PATCH 145/189] address code smells Signed-off-by: Rudy Flores <68666202+rudyflores@users.noreply.github.com> --- .../PersistentManagerHeader.tsx | 2 +- .../PersistentTable/PersistentDataPanel.tsx | 2 +- .../PersistentTable/PersistentTableData.tsx | 8 +++---- .../PersistentDropdownOptions.tsx | 22 ++++++++++++++----- .../PersistentToolBar/PersistentToolBar.tsx | 2 +- 5 files changed, 23 insertions(+), 13 deletions(-) diff --git a/packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentManagerHeader/PersistentManagerHeader.tsx b/packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentManagerHeader/PersistentManagerHeader.tsx index 3e1304de88..17e11ec9bd 100644 --- a/packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentManagerHeader/PersistentManagerHeader.tsx +++ b/packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentManagerHeader/PersistentManagerHeader.tsx @@ -11,7 +11,7 @@ import { JSXInternal } from "preact/src/jsx"; -export default function PersistentManagerHeader({ timestamp }: { timestamp: Date | undefined }): JSXInternal.Element { +export default function PersistentManagerHeader({ timestamp }: { timestamp: Readonly }): JSXInternal.Element { const renderTimestamp = () => { return timestamp &&

Last refreshed: {timestamp.toLocaleString(navigator.language)}

; }; diff --git a/packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentTable/PersistentDataPanel.tsx b/packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentTable/PersistentDataPanel.tsx index 23d1b39f6c..5071ce075b 100644 --- a/packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentTable/PersistentDataPanel.tsx +++ b/packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentTable/PersistentDataPanel.tsx @@ -19,7 +19,7 @@ import PersistentTableData from "./PersistentTableData"; import PersistentDataGridHeaders from "./PersistentDataGridHeaders"; import PersistentVSCodeAPI from "../PersistentVSCodeAPI"; -export default function PersistentDataPanel({ type }: { type: string }): JSXInternal.Element { +export default function PersistentDataPanel({ type }: { type: Readonly }): JSXInternal.Element { const [data, setData] = useState<{ [type: string]: { [property: string]: string[] } }>({ ds: {}, uss: {}, jobs: {} }); const [selection, setSelection] = useState<{ [type: string]: string }>({ [type]: "search" }); const [persistentProp, setPersistentProp] = useState([]); diff --git a/packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentTable/PersistentTableData.tsx b/packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentTable/PersistentTableData.tsx index db204b2dbd..c0dc6a1730 100644 --- a/packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentTable/PersistentTableData.tsx +++ b/packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentTable/PersistentTableData.tsx @@ -15,9 +15,9 @@ import { useDataPanelContext } from "../PersistentUtils"; import { useEffect, useState } from "preact/hooks"; import isEqual from "lodash.isequal"; -export default function PersistentTableData({ persistentProp }: { persistentProp: string[] }): JSXInternal.Element { +export default function PersistentTableData({ persistentProp }: { persistentProp: readonly string[] }): JSXInternal.Element { const { type, selection, selectedItems } = useDataPanelContext(); - const [oldPersistentProp, setOldPersistentProp] = useState([]); + const [oldPersistentProp, setOldPersistentProp] = useState([]); useEffect(() => { if (!isEqual(oldPersistentProp, persistentProp) && persistentProp) { @@ -45,7 +45,7 @@ export default function PersistentTableData({ persistentProp }: { persistentProp const renderOptions = () => { return persistentProp.map((item, i) => { return ( - + {item} {renderSelectButton(item, i)} @@ -61,7 +61,7 @@ export default function PersistentTableData({ persistentProp }: { persistentProp ); }; - const data = persistentProp && persistentProp.length ? renderOptions() : renderNoRecordsFound(); + const data = persistentProp?.length ? renderOptions() : renderNoRecordsFound(); return <>{data}; } diff --git a/packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentToolBar/PersistentDropdownOptions.tsx b/packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentToolBar/PersistentDropdownOptions.tsx index bd9724969f..4d3ad880ab 100644 --- a/packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentToolBar/PersistentDropdownOptions.tsx +++ b/packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentToolBar/PersistentDropdownOptions.tsx @@ -13,15 +13,25 @@ import { VSCodeDropdown, VSCodeOption } from "@vscode/webview-ui-toolkit/react"; import { JSXInternal } from "preact/src/jsx"; import { useDataPanelContext } from "../PersistentUtils"; -export default function PersistentDropdownOptions({ handleChange }: { handleChange: Function }): JSXInternal.Element { +export default function PersistentDropdownOptions({ handleChange }: { handleChange: Readonly }): JSXInternal.Element { const dataPanelContext = useDataPanelContext(); const options = [ - Search History, - DS Templates, - Favorites, - File History, - Sessions, + + Search History + , + + DS Templates + , + + Favorites + , + + File History + , + + Sessions + , ].filter((option) => dataPanelContext.type === "ds" || option.props.value !== "dsTemplates"); return ( diff --git a/packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentToolBar/PersistentToolBar.tsx b/packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentToolBar/PersistentToolBar.tsx index 6e5d745833..774cd2ba9f 100644 --- a/packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentToolBar/PersistentToolBar.tsx +++ b/packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentToolBar/PersistentToolBar.tsx @@ -16,7 +16,7 @@ import PersistentDropdownOptions from "./PersistentDropdownOptions"; import PersistentAddNewHistoryItemButton from "./PersistentAddNewHistoryItemButton"; import PersistentDeleteSelectedButton from "./PersistentDeleteSelectedButton"; -export default function PersistentToolBar({ handleChange }: { handleChange: Function }): JSXInternal.Element { +export default function PersistentToolBar({ handleChange }: { handleChange: Readonly }): JSXInternal.Element { return (
From 778de00157d1fae85229e1b240f2dff86b34b2ee Mon Sep 17 00:00:00 2001 From: Rudy Flores <68666202+rudyflores@users.noreply.github.com> Date: Wed, 18 Oct 2023 14:27:45 -0400 Subject: [PATCH 146/189] address additional code smells Signed-off-by: Rudy Flores <68666202+rudyflores@users.noreply.github.com> --- .../PersistentManagerHeader/PersistentManagerHeader.tsx | 2 +- .../components/PersistentTable/PersistentTableData.tsx | 4 ++-- .../PersistentToolBar/PersistentDropdownOptions.tsx | 2 +- .../components/PersistentToolBar/PersistentToolBar.tsx | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentManagerHeader/PersistentManagerHeader.tsx b/packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentManagerHeader/PersistentManagerHeader.tsx index 17e11ec9bd..9020c76f8a 100644 --- a/packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentManagerHeader/PersistentManagerHeader.tsx +++ b/packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentManagerHeader/PersistentManagerHeader.tsx @@ -11,7 +11,7 @@ import { JSXInternal } from "preact/src/jsx"; -export default function PersistentManagerHeader({ timestamp }: { timestamp: Readonly }): JSXInternal.Element { +export default function PersistentManagerHeader({ timestamp }: Readonly<{ timestamp: Readonly }>): JSXInternal.Element { const renderTimestamp = () => { return timestamp &&

Last refreshed: {timestamp.toLocaleString(navigator.language)}

; }; diff --git a/packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentTable/PersistentTableData.tsx b/packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentTable/PersistentTableData.tsx index c0dc6a1730..d41dd3eeba 100644 --- a/packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentTable/PersistentTableData.tsx +++ b/packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentTable/PersistentTableData.tsx @@ -15,7 +15,7 @@ import { useDataPanelContext } from "../PersistentUtils"; import { useEffect, useState } from "preact/hooks"; import isEqual from "lodash.isequal"; -export default function PersistentTableData({ persistentProp }: { persistentProp: readonly string[] }): JSXInternal.Element { +export default function PersistentTableData({ persistentProp }: Readonly<{ persistentProp: readonly string[] }>): JSXInternal.Element { const { type, selection, selectedItems } = useDataPanelContext(); const [oldPersistentProp, setOldPersistentProp] = useState([]); @@ -45,7 +45,7 @@ export default function PersistentTableData({ persistentProp }: { persistentProp const renderOptions = () => { return persistentProp.map((item, i) => { return ( - + {item} {renderSelectButton(item, i)} diff --git a/packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentToolBar/PersistentDropdownOptions.tsx b/packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentToolBar/PersistentDropdownOptions.tsx index 4d3ad880ab..89549ac98d 100644 --- a/packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentToolBar/PersistentDropdownOptions.tsx +++ b/packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentToolBar/PersistentDropdownOptions.tsx @@ -13,7 +13,7 @@ import { VSCodeDropdown, VSCodeOption } from "@vscode/webview-ui-toolkit/react"; import { JSXInternal } from "preact/src/jsx"; import { useDataPanelContext } from "../PersistentUtils"; -export default function PersistentDropdownOptions({ handleChange }: { handleChange: Readonly }): JSXInternal.Element { +export default function PersistentDropdownOptions({ handleChange }: Readonly<{ handleChange: Readonly }>): JSXInternal.Element { const dataPanelContext = useDataPanelContext(); const options = [ diff --git a/packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentToolBar/PersistentToolBar.tsx b/packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentToolBar/PersistentToolBar.tsx index 774cd2ba9f..94155d1e21 100644 --- a/packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentToolBar/PersistentToolBar.tsx +++ b/packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentToolBar/PersistentToolBar.tsx @@ -16,7 +16,7 @@ import PersistentDropdownOptions from "./PersistentDropdownOptions"; import PersistentAddNewHistoryItemButton from "./PersistentAddNewHistoryItemButton"; import PersistentDeleteSelectedButton from "./PersistentDeleteSelectedButton"; -export default function PersistentToolBar({ handleChange }: { handleChange: Readonly }): JSXInternal.Element { +export default function PersistentToolBar({ handleChange }: Readonly<{ handleChange: Readonly }>): JSXInternal.Element { return (
From 6d6d3685f4c2060afc5caf58ce0c611e8bdb2f79 Mon Sep 17 00:00:00 2001 From: Rudy Flores <68666202+rudyflores@users.noreply.github.com> Date: Wed, 18 Oct 2023 14:31:14 -0400 Subject: [PATCH 147/189] make data panel readonly Signed-off-by: Rudy Flores <68666202+rudyflores@users.noreply.github.com> --- .../components/PersistentTable/PersistentDataPanel.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentTable/PersistentDataPanel.tsx b/packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentTable/PersistentDataPanel.tsx index 5071ce075b..2f556a41bc 100644 --- a/packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentTable/PersistentDataPanel.tsx +++ b/packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentTable/PersistentDataPanel.tsx @@ -19,7 +19,7 @@ import PersistentTableData from "./PersistentTableData"; import PersistentDataGridHeaders from "./PersistentDataGridHeaders"; import PersistentVSCodeAPI from "../PersistentVSCodeAPI"; -export default function PersistentDataPanel({ type }: { type: Readonly }): JSXInternal.Element { +export default function PersistentDataPanel({ type }: Readonly<{ type: Readonly }>): JSXInternal.Element { const [data, setData] = useState<{ [type: string]: { [property: string]: string[] } }>({ ds: {}, uss: {}, jobs: {} }); const [selection, setSelection] = useState<{ [type: string]: string }>({ [type]: "search" }); const [persistentProp, setPersistentProp] = useState([]); From 22f6d0c9dad14edbc7c188358a5ab2c42535c2ed Mon Sep 17 00:00:00 2001 From: Rudy Flores <68666202+rudyflores@users.noreply.github.com> Date: Wed, 18 Oct 2023 14:56:17 -0400 Subject: [PATCH 148/189] add missing code coverage Signed-off-by: Rudy Flores <68666202+rudyflores@users.noreply.github.com> --- .../__unit__/dataset/DatasetTree.unit.test.ts | 18 ++++++++++++++++++ .../__unit__/job/ZosJobsProvider.unit.test.ts | 18 ++++++++++++++++++ .../__unit__/uss/USSTree.unit.test.ts | 10 ++++++++++ 3 files changed, 46 insertions(+) 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 0e455aa298..a16d30ff3c 100644 --- a/packages/zowe-explorer/__tests__/__unit__/dataset/DatasetTree.unit.test.ts +++ b/packages/zowe-explorer/__tests__/__unit__/dataset/DatasetTree.unit.test.ts @@ -2944,4 +2944,22 @@ describe("Dataset Tree Unit Tests - Sorting and Filtering operations", () => { expect(tree.getSessions()).toEqual(["sestest"]); }); }); + + describe("getDsTemplates", () => { + it("gets all the DS templates from persistent object", () => { + jest.spyOn(vscode.workspace, "getConfiguration").mockReturnValue({ + get: () => ["test1", "test2", "test3"], + } as any); + expect(tree.getDsTemplates()).toEqual(["test1", "test2", "test3"]); + }); + }); + + describe("getFavorites", () => { + it("gets all the favorites from persistent object", () => { + jest.spyOn(vscode.workspace, "getConfiguration").mockReturnValue({ + get: () => ["test1", "test2", "test3"], + } as any); + expect(tree.getFavorites()).toEqual(["test1", "test2", "test3"]); + }); + }); }); diff --git a/packages/zowe-explorer/__tests__/__unit__/job/ZosJobsProvider.unit.test.ts b/packages/zowe-explorer/__tests__/__unit__/job/ZosJobsProvider.unit.test.ts index 4c790ec672..ca6befdf59 100644 --- a/packages/zowe-explorer/__tests__/__unit__/job/ZosJobsProvider.unit.test.ts +++ b/packages/zowe-explorer/__tests__/__unit__/job/ZosJobsProvider.unit.test.ts @@ -956,3 +956,21 @@ describe("getSessions", () => { expect(tree.getSessions()).toEqual(["sestest"]); }); }); + +describe("getFileHistory", () => { + it("gets all the file history from persistent object", () => { + const tree = new ZosJobsProvider(); + tree["mHistory"]["mFileHistory"] = ["test1", "test2", "test3"]; + expect(tree.getFileHistory()).toEqual(["test1", "test2", "test3"]); + }); +}); + +describe("getFavorites", () => { + it("gets all the favorites from persistent object", () => { + const tree = new ZosJobsProvider(); + jest.spyOn(vscode.workspace, "getConfiguration").mockReturnValue({ + get: () => ["test1", "test2", "test3"], + } as any); + expect(tree.getFavorites()).toEqual(["test1", "test2", "test3"]); + }); +}); diff --git a/packages/zowe-explorer/__tests__/__unit__/uss/USSTree.unit.test.ts b/packages/zowe-explorer/__tests__/__unit__/uss/USSTree.unit.test.ts index e28acf549d..5092e6da65 100644 --- a/packages/zowe-explorer/__tests__/__unit__/uss/USSTree.unit.test.ts +++ b/packages/zowe-explorer/__tests__/__unit__/uss/USSTree.unit.test.ts @@ -1733,4 +1733,14 @@ describe("USSTree Unit Tests - Function USSTree.editSession()", () => { expect(globalMocks.testTree.getSessions()).toEqual(["sestest"]); }); }); + + describe("getFavorites", () => { + it("gets all the favorites from persistent object", async () => { + const globalMocks = await createGlobalMocks(); + jest.spyOn(vscode.workspace, "getConfiguration").mockReturnValue({ + get: () => ["test1", "test2", "test3"], + } as any); + expect(globalMocks.testTree.getFavorites()).toEqual(["test1", "test2", "test3"]); + }); + }); }); From 64f791971da3ff845edc569fdefe3e2619be3a95 Mon Sep 17 00:00:00 2001 From: Rudy Flores <68666202+rudyflores@users.noreply.github.com> Date: Wed, 18 Oct 2023 16:33:30 -0400 Subject: [PATCH 149/189] coverage for HistoryView.ts Signed-off-by: Rudy Flores <68666202+rudyflores@users.noreply.github.com> --- .../__mocks__/mockCreators/datasets.ts | 6 + .../__mocks__/mockCreators/jobs.ts | 7 + .../__mocks__/mockCreators/uss.ts | 6 + .../__unit__/shared/HistoryView.unit.test.ts | 296 ++++++++++++++++++ .../zowe-explorer/src/shared/HistoryView.ts | 1 + 5 files changed, 316 insertions(+) create mode 100644 packages/zowe-explorer/__tests__/__unit__/shared/HistoryView.unit.test.ts diff --git a/packages/zowe-explorer/__mocks__/mockCreators/datasets.ts b/packages/zowe-explorer/__mocks__/mockCreators/datasets.ts index 18a2a5cda1..41ee8758f2 100644 --- a/packages/zowe-explorer/__mocks__/mockCreators/datasets.ts +++ b/packages/zowe-explorer/__mocks__/mockCreators/datasets.ts @@ -43,6 +43,11 @@ export function createDatasetTree(sessionNode: ZoweDatasetNode, treeView: any, f addFavorite: jest.fn(), getSearchHistory: jest.fn(), getFileHistory: jest.fn(), + getSessions: jest.fn(), + getFavorites: jest.fn(), + removeSearchHistory: jest.fn(), + resetSearchHistory: jest.fn(), + resetFileHistory: jest.fn(), refresh: jest.fn(), refreshElement: jest.fn(), checkCurrentProfile: jest.fn(), @@ -78,6 +83,7 @@ export function createDatasetTree(sessionNode: ZoweDatasetNode, treeView: any, f testDatasetTree.removeFileHistory.mockImplementation((badFile) => testDatasetTree.mFileHistory.splice(testDatasetTree.mFileHistory.indexOf(badFile), 1) ); + testDatasetTree.getSearchHistory.mockImplementation(); testDatasetTree.getFileHistory.mockImplementation(() => testDatasetTree.mFileHistory); testDatasetTree.deleteSession.mockImplementation((badSession) => removeNodeFromArray(badSession, testDatasetTree.mSessionNodes)); testDatasetTree.removeFavorite.mockImplementation((badFavorite) => removeNodeFromArray(badFavorite, testDatasetTree.mFavorites)); diff --git a/packages/zowe-explorer/__mocks__/mockCreators/jobs.ts b/packages/zowe-explorer/__mocks__/mockCreators/jobs.ts index a3f1503b22..d223f5951f 100644 --- a/packages/zowe-explorer/__mocks__/mockCreators/jobs.ts +++ b/packages/zowe-explorer/__mocks__/mockCreators/jobs.ts @@ -86,6 +86,12 @@ export function createJobsTree(session: imperative.Session, iJob: IJob, profile: dispose: jest.fn(), }; }), + getSessions: jest.fn(), + getFavorites: jest.fn(), + getSearchHistory: jest.fn(), + removeSearchHistory: jest.fn(), + resetSearchHistory: jest.fn(), + resetFileHistory: jest.fn(), deleteSession: jest.fn(), addFavorite: jest.fn(), removeFavorite: jest.fn(), @@ -105,6 +111,7 @@ export function createJobsTree(session: imperative.Session, iJob: IJob, profile: testJobsTree.addFavorite.mockImplementation((newFavorite) => { testJobsTree.mFavorites.push(newFavorite); }); + testJobsTree.getSearchHistory.mockImplementation(); testJobsTree.deleteSession.mockImplementation((badSession) => removeNodeFromArray(badSession, testJobsTree.mSessionNodes)); testJobsTree.removeFavorite.mockImplementation((badFavorite) => removeNodeFromArray(badFavorite, testJobsTree.mFavorites)); testJobsTree.removeFavProfile.mockImplementation((badFavProfileName) => { diff --git a/packages/zowe-explorer/__mocks__/mockCreators/uss.ts b/packages/zowe-explorer/__mocks__/mockCreators/uss.ts index 422f0da7eb..1d5c327c06 100644 --- a/packages/zowe-explorer/__mocks__/mockCreators/uss.ts +++ b/packages/zowe-explorer/__mocks__/mockCreators/uss.ts @@ -24,6 +24,12 @@ export function createUSSTree(favoriteNodes: ZoweUSSNode[], sessionNodes: ZoweUS newTree.mSessionNodes = [...sessionNodes]; newTree.mFavorites = favoriteNodes; newTree.addSession = jest.fn(); + newTree.getSessions = jest.fn(); + newTree.getFavorites = jest.fn(); + newTree.getSearchHistory = jest.fn(); + newTree.removeSearchHistory = jest.fn(); + newTree.resetSearchHistory = jest.fn(); + newTree.resetFileHistory = jest.fn(); newTree.refresh = jest.fn(); newTree.checkCurrentProfile = jest.fn(); newTree.refreshElement = jest.fn(); diff --git a/packages/zowe-explorer/__tests__/__unit__/shared/HistoryView.unit.test.ts b/packages/zowe-explorer/__tests__/__unit__/shared/HistoryView.unit.test.ts new file mode 100644 index 0000000000..fac2143e1b --- /dev/null +++ b/packages/zowe-explorer/__tests__/__unit__/shared/HistoryView.unit.test.ts @@ -0,0 +1,296 @@ +import { HistoryView } from "../../../src/shared/HistoryView"; +import { createDatasetSessionNode, createDatasetTree } from "../../../__mocks__/mockCreators/datasets"; +import { createUSSSessionNode, createUSSTree } from "../../../__mocks__/mockCreators/uss"; +import { + createIProfile, + createISession, + createISessionWithoutCredentials, + createInstanceOfProfile, + createTreeView, +} from "../../../__mocks__/mockCreators/shared"; +import { createIJobObject, createJobsTree } from "../../../__mocks__/mockCreators/jobs"; +import * as vscode from "vscode"; +import { Gui } from "@zowe/zowe-explorer-api"; +import { Profiles } from "../../../src/Profiles"; +import * as globals from "../../../src/globals"; +import * as zowe from "@zowe/cli"; +import { ZoweLogger } from "../../../src/utils/LoggerUtils"; + +async function initializeHistoryViewMock(blockMocks: any, globalMocks: any): Promise { + return new HistoryView( + { + extensionPath: "", + } as any, + { + ds: await createDatasetTree(blockMocks.datasetSessionNode, globalMocks.treeView), + uss: createUSSTree([blockMocks.datasetSessionNode], [globalMocks.testSession], globalMocks.treeView), + jobs: await createJobsTree(globalMocks.testSession, createIJobObject(), globalMocks.testProfile, createTreeView()), + } as any + ); +} + +function createBlockMocks(globalMocks: any): any { + return { + datasetSessionNode: createDatasetSessionNode(globalMocks.session, globalMocks.imperativeProfile), + ussSessionNode: createUSSSessionNode(globalMocks.session, globalMocks.imperativeProfile), + }; +} + +describe("HistoryView Unit Tests", () => { + function createGlobalMocks(): any { + const globalMocks = { + session: createISessionWithoutCredentials(), + testSession: createISession(), + treeView: createTreeView(), + imperativeProfile: createIProfile(), + withProgress: null, + mockCallback: null, + ProgressLocation: jest.fn().mockImplementation(() => { + return { + Notification: 15, + }; + }), + qpPlaceholder: 'Choose "Create new..." to define a new profile or select an existing profile to add to the Data Set Explorer', + }; + + Object.defineProperty(vscode.window, "withProgress", { + value: jest.fn().mockImplementation((progLocation, callback) => { + const progress = { + report: (message) => { + return; + }, + }; + const token = { + isCancellationRequested: false, + onCancellationRequested: undefined, + }; + return callback(progress, token); + }), + configurable: true, + }); + + Object.defineProperty(Gui, "setStatusBarMessage", { + value: jest.fn().mockReturnValue({ + dispose: jest.fn(), + }), + configurable: true, + }); + Object.defineProperty(vscode.window, "createTreeView", { value: jest.fn(), configurable: true }); + Object.defineProperty(vscode.workspace, "getConfiguration", { value: jest.fn(), configurable: true }); + Object.defineProperty(vscode.window, "showInformationMessage", { value: jest.fn(), configurable: true }); + Object.defineProperty(vscode.window, "showInputBox", { value: jest.fn(), configurable: true }); + Object.defineProperty(vscode.window, "showErrorMessage", { value: jest.fn(), configurable: true }); + Object.defineProperty(Gui, "showMessage", { value: jest.fn(), configurable: true }); + Object.defineProperty(Gui, "resolveQuickPick", { value: jest.fn(), configurable: true }); + Object.defineProperty(Gui, "createQuickPick", { value: jest.fn(), configurable: true }); + Object.defineProperty(vscode.commands, "executeCommand", { value: globalMocks.withProgress, configurable: true }); + Object.defineProperty(vscode, "ProgressLocation", { value: globalMocks.ProgressLocation, configurable: true }); + Object.defineProperty(Profiles, "getInstance", { + value: jest.fn().mockReturnValue(createInstanceOfProfile(globalMocks.imperativeProfile)), + configurable: true, + }); + Object.defineProperty(zowe, "Download", { + value: { + ussFile: jest.fn().mockReturnValue({ + apiResponse: { + etag: "ABC123", + }, + }), + }, + configurable: true, + }); + Object.defineProperty(zowe, "Utilities", { value: jest.fn(), configurable: true }); + Object.defineProperty(zowe.Utilities, "isFileTagBinOrAscii", { value: jest.fn(), configurable: true }); + Object.defineProperty(globals, "LOG", { value: jest.fn(), configurable: true }); + Object.defineProperty(globals.LOG, "debug", { value: jest.fn(), configurable: true }); + Object.defineProperty(globals.LOG, "error", { value: jest.fn(), configurable: true }); + Object.defineProperty(globals.LOG, "warn", { value: jest.fn(), configurable: true }); + Object.defineProperty(ZoweLogger, "error", { value: jest.fn(), configurable: true }); + Object.defineProperty(ZoweLogger, "debug", { value: jest.fn(), configurable: true }); + Object.defineProperty(ZoweLogger, "warn", { value: jest.fn(), configurable: true }); + Object.defineProperty(ZoweLogger, "info", { value: jest.fn(), configurable: true }); + Object.defineProperty(ZoweLogger, "trace", { value: jest.fn(), configurable: true }); + + return globalMocks; + } + + describe("constructor", () => { + it("should create the webview instance and initialize", () => { + const historyView = new HistoryView( + { + extensionPath: "", + } as any, + { test: "test" } as any + ); + expect(historyView["treeProviders"]).toEqual({ test: "test" }); + expect(historyView["currentSelection"]).toEqual({ ds: "search", uss: "search", jobs: "search" }); + }); + }); + + describe("onDidReceiveMessage", () => { + it("should handle the case where 'refresh' is the command sent", async () => { + const globalMocks = await createGlobalMocks(); + const blockMocks = createBlockMocks(globalMocks); + const historyView = await initializeHistoryViewMock(blockMocks, globalMocks); + const postMessageSpy = jest.spyOn(historyView.panel.webview, "postMessage"); + jest.spyOn(historyView as any, "getHistoryData").mockReturnValue([]); + await historyView["onDidReceiveMessage"]({ command: "refresh", attrs: { type: "uss" } }); + expect(postMessageSpy).toBeCalledTimes(1); + expect(historyView["currentTab"]).toEqual("uss-panel-tab"); + }); + + it("should handle the case where 'ready' is the command sent", async () => { + const globalMocks = await createGlobalMocks(); + const blockMocks = createBlockMocks(globalMocks); + const historyView = await initializeHistoryViewMock(blockMocks, globalMocks); + const postMessageSpy = jest.spyOn(historyView.panel.webview, "postMessage"); + jest.spyOn(historyView as any, "getHistoryData").mockReturnValue([]); + await historyView["onDidReceiveMessage"]({ command: "ready" }); + expect(postMessageSpy).toBeCalledWith({ + ds: [], + uss: [], + jobs: [], + tab: undefined, + selection: { + ds: "search", + jobs: "search", + uss: "search", + }, + }); + }); + + it("should handle the case where 'show-error' is the command sent", async () => { + const globalMocks = await createGlobalMocks(); + const blockMocks = createBlockMocks(globalMocks); + const historyView = await initializeHistoryViewMock(blockMocks, globalMocks); + const errorMessageSpy = jest.spyOn(Gui, "errorMessage"); + await historyView["onDidReceiveMessage"]({ command: "show-error", attrs: { errorMsg: "test error" } }); + expect(errorMessageSpy).toBeCalledWith("test error"); + }); + + it("should handle the case where 'update-selection' is the command sent", async () => { + const globalMocks = await createGlobalMocks(); + const blockMocks = createBlockMocks(globalMocks); + const historyView = await initializeHistoryViewMock(blockMocks, globalMocks); + await historyView["onDidReceiveMessage"]({ command: "update-selection", attrs: { type: "uss", selection: "favorites" } }); + expect(historyView["currentSelection"]).toEqual({ ds: "search", jobs: "search", uss: "favorites" }); + }); + + it("should handle the case where 'add-item' is the command sent", async () => { + const globalMocks = await createGlobalMocks(); + const blockMocks = createBlockMocks(globalMocks); + const historyView = await initializeHistoryViewMock(blockMocks, globalMocks); + jest.spyOn(Gui, "showInputBox").mockResolvedValue("test"); + const addSearchHistorySpy = jest.spyOn(historyView["treeProviders"].uss, "addSearchHistory"); + jest.spyOn(historyView as any, "refreshView").mockImplementation(); + await historyView["onDidReceiveMessage"]({ command: "add-item", attrs: { type: "uss" } }); + expect(historyView["currentSelection"]).toEqual({ ds: "search", jobs: "search", uss: "search" }); + expect(addSearchHistorySpy).toBeCalledWith("test"); + }); + + it("should handle the case where 'remove-item' is the command sent and the selection is 'search'", async () => { + const globalMocks = await createGlobalMocks(); + const blockMocks = createBlockMocks(globalMocks); + const historyView = await initializeHistoryViewMock(blockMocks, globalMocks); + jest.spyOn(historyView as any, "refreshView").mockImplementation(); + const removeSearchHistorySpy = jest.spyOn(historyView["treeProviders"].ds as any, "removeSearchHistory"); + await historyView["onDidReceiveMessage"]({ + command: "remove-item", + attrs: { type: "ds", selection: "search", selectedItems: { test: "test1" } }, + }); + expect(historyView["currentSelection"]).toEqual({ ds: "search", jobs: "search", uss: "search" }); + expect(removeSearchHistorySpy).toBeCalledWith("test"); + }); + + it("should handle the case where 'remove-item' is the command sent and the selection is 'fileHistory'", async () => { + const globalMocks = await createGlobalMocks(); + const blockMocks = createBlockMocks(globalMocks); + const historyView = await initializeHistoryViewMock(blockMocks, globalMocks); + jest.spyOn(historyView as any, "refreshView").mockImplementation(); + const removeFileHistorySpy = jest.spyOn(historyView["treeProviders"].ds, "removeFileHistory"); + await historyView["onDidReceiveMessage"]({ + command: "remove-item", + attrs: { type: "ds", selection: "fileHistory", selectedItems: { test: "test1" } }, + }); + expect(historyView["currentSelection"]).toEqual({ ds: "search", jobs: "search", uss: "search" }); + expect(removeFileHistorySpy).toBeCalledWith("test"); + }); + + it("should handle the case where 'remove-item' is the command sent and the selection is not supported", async () => { + const globalMocks = await createGlobalMocks(); + const blockMocks = createBlockMocks(globalMocks); + const historyView = await initializeHistoryViewMock(blockMocks, globalMocks); + jest.spyOn(historyView as any, "refreshView").mockImplementation(); + const showMessageSpy = jest.spyOn(Gui, "showMessage"); + await historyView["onDidReceiveMessage"]({ + command: "remove-item", + attrs: { type: "ds", selection: "favorites", selectedItems: { test: "test1" } }, + }); + expect(historyView["currentSelection"]).toEqual({ ds: "search", jobs: "search", uss: "search" }); + expect(showMessageSpy).toBeCalledTimes(1); + }); + + it("should handle the case where 'clear-all' is the command sent and the selection is 'search'", async () => { + const globalMocks = await createGlobalMocks(); + const blockMocks = createBlockMocks(globalMocks); + const historyView = await initializeHistoryViewMock(blockMocks, globalMocks); + jest.spyOn(historyView as any, "refreshView").mockImplementation(); + jest.spyOn(Gui, "showMessage").mockResolvedValue("Yes"); + + const resetSearchHistorySpy = jest.spyOn(historyView["treeProviders"].ds as any, "resetSearchHistory"); + await historyView["onDidReceiveMessage"]({ + command: "clear-all", + attrs: { type: "ds", selection: "search" }, + }); + expect(historyView["currentSelection"]).toEqual({ ds: "search", jobs: "search", uss: "search" }); + expect(resetSearchHistorySpy).toBeCalledTimes(1); + }); + + it("should handle the case where 'clear-all' is the command sent and the selection is 'fileHistory'", async () => { + const globalMocks = await createGlobalMocks(); + const blockMocks = createBlockMocks(globalMocks); + const historyView = await initializeHistoryViewMock(blockMocks, globalMocks); + jest.spyOn(historyView as any, "refreshView").mockImplementation(); + jest.spyOn(Gui, "showMessage").mockResolvedValue("Yes"); + + const resetFileHistorySpy = jest.spyOn(historyView["treeProviders"].ds as any, "resetFileHistory"); + await historyView["onDidReceiveMessage"]({ + command: "clear-all", + attrs: { type: "ds", selection: "fileHistory" }, + }); + expect(historyView["currentSelection"]).toEqual({ ds: "search", jobs: "search", uss: "search" }); + expect(resetFileHistorySpy).toBeCalledTimes(1); + }); + + it("should handle the case where 'clear-all' is the command sent and the selection is 'fileHistory'", async () => { + const globalMocks = await createGlobalMocks(); + const blockMocks = createBlockMocks(globalMocks); + const historyView = await initializeHistoryViewMock(blockMocks, globalMocks); + jest.spyOn(historyView as any, "refreshView").mockImplementation(); + jest.spyOn(Gui, "showMessage").mockResolvedValueOnce("Yes"); + const showMessageSpy = jest.spyOn(Gui, "showMessage"); + await historyView["onDidReceiveMessage"]({ + command: "clear-all", + attrs: { type: "ds", selection: "favorites" }, + }); + expect(historyView["currentSelection"]).toEqual({ ds: "search", jobs: "search", uss: "search" }); + expect(showMessageSpy).toBeCalledTimes(2); + }); + }); + + describe("getHistoryData", () => { + it("should get the latest history data", async () => { + const globalMocks = await createGlobalMocks(); + const blockMocks = createBlockMocks(globalMocks); + const historyView = await initializeHistoryViewMock(blockMocks, globalMocks); + + expect(historyView["getHistoryData"]("ds")).toEqual({ + dsTemplates: undefined, + favorites: undefined, + fileHistory: [], + search: undefined, + sessions: undefined, + }); + }); + }); +}); diff --git a/packages/zowe-explorer/src/shared/HistoryView.ts b/packages/zowe-explorer/src/shared/HistoryView.ts index d4f0b08620..d112acc9cf 100644 --- a/packages/zowe-explorer/src/shared/HistoryView.ts +++ b/packages/zowe-explorer/src/shared/HistoryView.ts @@ -89,6 +89,7 @@ export class HistoryView extends WebView { private getHistoryData(type: string): History { const treeProvider = this.treeProviders[type] as TreeProvider; + console.log(treeProvider.getSearchHistory); return { search: treeProvider.getSearchHistory(), sessions: treeProvider.getSessions(), From 7c634bb9cc330361fe69494aef241fd448815fd9 Mon Sep 17 00:00:00 2001 From: Rudy Flores <68666202+rudyflores@users.noreply.github.com> Date: Wed, 18 Oct 2023 16:45:43 -0400 Subject: [PATCH 150/189] Address code smells from new tests Signed-off-by: Rudy Flores <68666202+rudyflores@users.noreply.github.com> --- .../__unit__/shared/HistoryView.unit.test.ts | 99 ++++--------------- .../zowe-explorer/src/shared/HistoryView.ts | 1 - 2 files changed, 18 insertions(+), 82 deletions(-) diff --git a/packages/zowe-explorer/__tests__/__unit__/shared/HistoryView.unit.test.ts b/packages/zowe-explorer/__tests__/__unit__/shared/HistoryView.unit.test.ts index fac2143e1b..2784971215 100644 --- a/packages/zowe-explorer/__tests__/__unit__/shared/HistoryView.unit.test.ts +++ b/packages/zowe-explorer/__tests__/__unit__/shared/HistoryView.unit.test.ts @@ -9,12 +9,8 @@ import { createTreeView, } from "../../../__mocks__/mockCreators/shared"; import { createIJobObject, createJobsTree } from "../../../__mocks__/mockCreators/jobs"; -import * as vscode from "vscode"; import { Gui } from "@zowe/zowe-explorer-api"; import { Profiles } from "../../../src/Profiles"; -import * as globals from "../../../src/globals"; -import * as zowe from "@zowe/cli"; -import { ZoweLogger } from "../../../src/utils/LoggerUtils"; async function initializeHistoryViewMock(blockMocks: any, globalMocks: any): Promise { return new HistoryView( @@ -29,6 +25,24 @@ async function initializeHistoryViewMock(blockMocks: any, globalMocks: any): Pro ); } +function createGlobalMocks(): any { + const globalMocks = { + session: createISessionWithoutCredentials(), + testSession: createISession(), + treeView: createTreeView(), + imperativeProfile: createIProfile(), + }; + Object.defineProperty(Gui, "showMessage", { value: jest.fn(), configurable: true }); + Object.defineProperty(Gui, "resolveQuickPick", { value: jest.fn(), configurable: true }); + Object.defineProperty(Gui, "createQuickPick", { value: jest.fn(), configurable: true }); + Object.defineProperty(Profiles, "getInstance", { + value: jest.fn().mockReturnValue(createInstanceOfProfile(globalMocks.imperativeProfile)), + configurable: true, + }); + + return globalMocks; +} + function createBlockMocks(globalMocks: any): any { return { datasetSessionNode: createDatasetSessionNode(globalMocks.session, globalMocks.imperativeProfile), @@ -37,83 +51,6 @@ function createBlockMocks(globalMocks: any): any { } describe("HistoryView Unit Tests", () => { - function createGlobalMocks(): any { - const globalMocks = { - session: createISessionWithoutCredentials(), - testSession: createISession(), - treeView: createTreeView(), - imperativeProfile: createIProfile(), - withProgress: null, - mockCallback: null, - ProgressLocation: jest.fn().mockImplementation(() => { - return { - Notification: 15, - }; - }), - qpPlaceholder: 'Choose "Create new..." to define a new profile or select an existing profile to add to the Data Set Explorer', - }; - - Object.defineProperty(vscode.window, "withProgress", { - value: jest.fn().mockImplementation((progLocation, callback) => { - const progress = { - report: (message) => { - return; - }, - }; - const token = { - isCancellationRequested: false, - onCancellationRequested: undefined, - }; - return callback(progress, token); - }), - configurable: true, - }); - - Object.defineProperty(Gui, "setStatusBarMessage", { - value: jest.fn().mockReturnValue({ - dispose: jest.fn(), - }), - configurable: true, - }); - Object.defineProperty(vscode.window, "createTreeView", { value: jest.fn(), configurable: true }); - Object.defineProperty(vscode.workspace, "getConfiguration", { value: jest.fn(), configurable: true }); - Object.defineProperty(vscode.window, "showInformationMessage", { value: jest.fn(), configurable: true }); - Object.defineProperty(vscode.window, "showInputBox", { value: jest.fn(), configurable: true }); - Object.defineProperty(vscode.window, "showErrorMessage", { value: jest.fn(), configurable: true }); - Object.defineProperty(Gui, "showMessage", { value: jest.fn(), configurable: true }); - Object.defineProperty(Gui, "resolveQuickPick", { value: jest.fn(), configurable: true }); - Object.defineProperty(Gui, "createQuickPick", { value: jest.fn(), configurable: true }); - Object.defineProperty(vscode.commands, "executeCommand", { value: globalMocks.withProgress, configurable: true }); - Object.defineProperty(vscode, "ProgressLocation", { value: globalMocks.ProgressLocation, configurable: true }); - Object.defineProperty(Profiles, "getInstance", { - value: jest.fn().mockReturnValue(createInstanceOfProfile(globalMocks.imperativeProfile)), - configurable: true, - }); - Object.defineProperty(zowe, "Download", { - value: { - ussFile: jest.fn().mockReturnValue({ - apiResponse: { - etag: "ABC123", - }, - }), - }, - configurable: true, - }); - Object.defineProperty(zowe, "Utilities", { value: jest.fn(), configurable: true }); - Object.defineProperty(zowe.Utilities, "isFileTagBinOrAscii", { value: jest.fn(), configurable: true }); - Object.defineProperty(globals, "LOG", { value: jest.fn(), configurable: true }); - Object.defineProperty(globals.LOG, "debug", { value: jest.fn(), configurable: true }); - Object.defineProperty(globals.LOG, "error", { value: jest.fn(), configurable: true }); - Object.defineProperty(globals.LOG, "warn", { value: jest.fn(), configurable: true }); - Object.defineProperty(ZoweLogger, "error", { value: jest.fn(), configurable: true }); - Object.defineProperty(ZoweLogger, "debug", { value: jest.fn(), configurable: true }); - Object.defineProperty(ZoweLogger, "warn", { value: jest.fn(), configurable: true }); - Object.defineProperty(ZoweLogger, "info", { value: jest.fn(), configurable: true }); - Object.defineProperty(ZoweLogger, "trace", { value: jest.fn(), configurable: true }); - - return globalMocks; - } - describe("constructor", () => { it("should create the webview instance and initialize", () => { const historyView = new HistoryView( diff --git a/packages/zowe-explorer/src/shared/HistoryView.ts b/packages/zowe-explorer/src/shared/HistoryView.ts index d112acc9cf..d4f0b08620 100644 --- a/packages/zowe-explorer/src/shared/HistoryView.ts +++ b/packages/zowe-explorer/src/shared/HistoryView.ts @@ -89,7 +89,6 @@ export class HistoryView extends WebView { private getHistoryData(type: string): History { const treeProvider = this.treeProviders[type] as TreeProvider; - console.log(treeProvider.getSearchHistory); return { search: treeProvider.getSearchHistory(), sessions: treeProvider.getSessions(), From abb7b93f943937a6f4bb06462cbfd8eb43abb239 Mon Sep 17 00:00:00 2001 From: Rudy Flores <68666202+rudyflores@users.noreply.github.com> Date: Thu, 19 Oct 2023 12:05:05 -0400 Subject: [PATCH 151/189] fix dropdown height issue Signed-off-by: Rudy Flores <68666202+rudyflores@users.noreply.github.com> --- .../components/PersistentTable/PersistentDataPanel.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentTable/PersistentDataPanel.tsx b/packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentTable/PersistentDataPanel.tsx index 2f556a41bc..5abf8d6e74 100644 --- a/packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentTable/PersistentDataPanel.tsx +++ b/packages/zowe-explorer/src/webviews/src/edit-history/components/PersistentTable/PersistentDataPanel.tsx @@ -76,7 +76,7 @@ export default function PersistentDataPanel({ type }: Readonly<{ type: Readonly< return ( - + From 38d34765b09a6f0643f0c68f6678091c8bd17adb Mon Sep 17 00:00:00 2001 From: Billie Simmons <49491949+JillieBeanSim@users.noreply.github.com> Date: Thu, 19 Oct 2023 13:05:22 -0400 Subject: [PATCH 152/189] run build locally to make sure lock correct Signed-off-by: Billie Simmons <49491949+JillieBeanSim@users.noreply.github.com> --- yarn.lock | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/yarn.lock b/yarn.lock index ab80a337f2..806ddd0951 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1261,7 +1261,7 @@ "@babel/parser" "^7.22.15" "@babel/types" "^7.22.15" -"@babel/traverse@^7.13.0", "@babel/traverse@^7.16.7", "@babel/traverse@^7.16.8", "@babel/traverse@^7.17.10", "@babel/traverse@^7.17.3", "@babel/traverse@^7.17.9", "@babel/traverse@^7.20.1", "@babel/traverse@^7.23.0", "@babel/traverse@^7.7.2": +"@babel/traverse@^7.13.0", "@babel/traverse@^7.16.7", "@babel/traverse@^7.16.8", "@babel/traverse@^7.17.10", "@babel/traverse@^7.17.3", "@babel/traverse@^7.17.9", "@babel/traverse@^7.20.1", "@babel/traverse@^7.22.17", "@babel/traverse@^7.23.2", "@babel/traverse@^7.7.2": version "7.23.2" resolved "https://registry.npmjs.org/@babel/traverse/-/traverse-7.23.2.tgz#329c7a06735e144a506bdb2cad0268b7f46f4ad8" integrity sha512-azpe59SQ48qG6nu2CzcMLbxUudtN+dOM9kDbUqGq3HXUJRlo7i8fvPoxQUzYgLZ4cMVmuZgm8vvBpNeRhd6XSw== From 6bf988689d11b386c47d416f18f348b2a681b992 Mon Sep 17 00:00:00 2001 From: Rudy Flores <68666202+rudyflores@users.noreply.github.com> Date: Thu, 19 Oct 2023 14:00:41 -0400 Subject: [PATCH 153/189] fix broken unit test Signed-off-by: Rudy Flores <68666202+rudyflores@users.noreply.github.com> --- .../__tests__/__unit__/dataset/DatasetTree.unit.test.ts | 2 ++ 1 file changed, 2 insertions(+) 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 ffc89fa3cc..fa30016800 100644 --- a/packages/zowe-explorer/__tests__/__unit__/dataset/DatasetTree.unit.test.ts +++ b/packages/zowe-explorer/__tests__/__unit__/dataset/DatasetTree.unit.test.ts @@ -2700,6 +2700,8 @@ describe("Dataset Tree Unit Tests - Function initializeFavorites", () => { }); }); describe("Dataset Tree Unit Tests - Sorting and Filtering operations", () => { + createGlobalMocks(); + mocked(vscode.window.createTreeView).mockReturnValueOnce(createTreeView()); const tree = new DatasetTree(); const nodesForSuite = (): Record => { const session = new ZoweDatasetNode("testSession", vscode.TreeItemCollapsibleState.Collapsed, null, createISession()); From 415cb12fda5af8ced9ea5a0c001f8453638c7b90 Mon Sep 17 00:00:00 2001 From: Billie Simmons <49491949+JillieBeanSim@users.noreply.github.com> Date: Fri, 20 Oct 2023 09:36:56 -0400 Subject: [PATCH 154/189] fix tests and add header to file Signed-off-by: Billie Simmons <49491949+JillieBeanSim@users.noreply.github.com> --- .../__unit__/shared/HistoryView.unit.test.ts | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/packages/zowe-explorer/__tests__/__unit__/shared/HistoryView.unit.test.ts b/packages/zowe-explorer/__tests__/__unit__/shared/HistoryView.unit.test.ts index 2784971215..fd65a8aa11 100644 --- a/packages/zowe-explorer/__tests__/__unit__/shared/HistoryView.unit.test.ts +++ b/packages/zowe-explorer/__tests__/__unit__/shared/HistoryView.unit.test.ts @@ -1,3 +1,15 @@ +/** + * This program and the accompanying materials are made available under the terms of the + * Eclipse Public License v2.0 which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-v20.html + * + * SPDX-License-Identifier: EPL-2.0 + * + * Copyright Contributors to the Zowe Project. + * + */ + +import * as vscode from "vscode"; import { HistoryView } from "../../../src/shared/HistoryView"; import { createDatasetSessionNode, createDatasetTree } from "../../../__mocks__/mockCreators/datasets"; import { createUSSSessionNode, createUSSTree } from "../../../__mocks__/mockCreators/uss"; @@ -39,6 +51,7 @@ function createGlobalMocks(): any { value: jest.fn().mockReturnValue(createInstanceOfProfile(globalMocks.imperativeProfile)), configurable: true, }); + Object.defineProperty(vscode.window, "createTreeView", { value: jest.fn().mockReturnValueOnce(globalMocks.treeView), configurable: true }); return globalMocks; } From 88b5ae46800bf76994d46a2769db9d238b18eebc Mon Sep 17 00:00:00 2001 From: Rudy Flores <68666202+rudyflores@users.noreply.github.com> Date: Fri, 20 Oct 2023 13:45:40 -0400 Subject: [PATCH 155/189] fix for assignment on non existent property Signed-off-by: Rudy Flores <68666202+rudyflores@users.noreply.github.com> --- packages/zowe-explorer/src/Profiles.ts | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/packages/zowe-explorer/src/Profiles.ts b/packages/zowe-explorer/src/Profiles.ts index 4dc3274637..682cb45747 100644 --- a/packages/zowe-explorer/src/Profiles.ts +++ b/packages/zowe-explorer/src/Profiles.ts @@ -1210,9 +1210,9 @@ export class Profiles extends ProfilesCache { const dsNode: IZoweDatasetTreeNode = TreeProviders.ds.mSessionNodes.find( (sessionNode: IZoweDatasetTreeNode) => sessionNode.getProfile()?.name === node.getProfile()?.name ); - dsNode.tooltip = node.getProfile()?.name; - dsNode.description = ""; - dsNode.pattern = ""; + dsNode.tooltip &&= node.getProfile()?.name; + dsNode.description &&= ""; + dsNode.pattern &&= ""; TreeProviders.ds.flipState(dsNode, false); TreeProviders.ds.refreshElement(dsNode); } @@ -1224,9 +1224,9 @@ export class Profiles extends ProfilesCache { const ussNode: IZoweUSSTreeNode = TreeProviders.uss.mSessionNodes.find( (sessionNode: IZoweUSSTreeNode) => sessionNode.getProfile()?.name === node.getProfile()?.name ); - ussNode.tooltip = node.getProfile()?.name; - ussNode.description = ""; - ussNode.fullPath = ""; + ussNode.tooltip &&= node.getProfile()?.name; + ussNode.description &&= ""; + ussNode.fullPath &&= ""; TreeProviders.uss.flipState(ussNode, false); TreeProviders.uss.refreshElement(ussNode); } @@ -1238,13 +1238,13 @@ export class Profiles extends ProfilesCache { const jobNode: IZoweJobTreeNode = TreeProviders.job.mSessionNodes.find( (sessionNode: IZoweJobTreeNode) => sessionNode.getProfile()?.name === node.getProfile()?.name ); - jobNode.tooltip = node.getProfile()?.name; - jobNode.description = ""; - jobNode.owner = ""; - jobNode.prefix = ""; - jobNode.status = ""; - jobNode.filtered = false; - jobNode.children = []; + jobNode.tooltip &&= node.getProfile()?.name; + jobNode.description &&= ""; + jobNode.owner &&= ""; + jobNode.prefix &&= ""; + jobNode.status &&= ""; + jobNode.filtered &&= false; + jobNode.children &&= []; TreeProviders.job.flipState(jobNode, false); TreeProviders.job.refreshElement(jobNode); } From d732a3cde3a71727b1e91c15bf58488724739628 Mon Sep 17 00:00:00 2001 From: Rudy Flores <68666202+rudyflores@users.noreply.github.com> Date: Fri, 20 Oct 2023 14:14:10 -0400 Subject: [PATCH 156/189] change function access back to public Signed-off-by: Rudy Flores <68666202+rudyflores@users.noreply.github.com> --- packages/zowe-explorer/src/ZoweExplorerExtender.ts | 2 +- packages/zowe-explorer/src/utils/ProfilesUtils.ts | 14 +++++++------- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/packages/zowe-explorer/src/ZoweExplorerExtender.ts b/packages/zowe-explorer/src/ZoweExplorerExtender.ts index 1be6625d8e..6dd235aa7a 100644 --- a/packages/zowe-explorer/src/ZoweExplorerExtender.ts +++ b/packages/zowe-explorer/src/ZoweExplorerExtender.ts @@ -165,7 +165,7 @@ export class ZoweExplorerExtender implements ZoweExplorerApi.IApiExplorerExtende */ let usingTeamConfig: boolean; try { - const mProfileInfo = await ProfilesUtils.getProfileInfo(); + const mProfileInfo = await ProfilesUtils.getProfileInfo(globals.ISTHEIA); if (vscode.workspace.workspaceFolders && vscode.workspace.workspaceFolders[0]) { const rootPath = vscode.workspace.workspaceFolders[0].uri.fsPath; await mProfileInfo.readProfilesFromDisk({ homeDir: zoweDir, projectDir: getFullPath(rootPath) }); diff --git a/packages/zowe-explorer/src/utils/ProfilesUtils.ts b/packages/zowe-explorer/src/utils/ProfilesUtils.ts index 01782e043c..ef9853ffa3 100644 --- a/packages/zowe-explorer/src/utils/ProfilesUtils.ts +++ b/packages/zowe-explorer/src/utils/ProfilesUtils.ts @@ -270,7 +270,7 @@ export class ProfilesUtils { * @param credentialManagerExtension The credential manager VS Code extension name to activate * @returns Promise the constructor of the activated credential manager */ - private static async activateCredentialManagerOverride( + public static async activateCredentialManagerOverride( credentialManagerExtension: vscode.Extension ): Promise { try { @@ -290,7 +290,7 @@ export class ProfilesUtils { * @param credentialManagerMap The map with associated names of the custom credential manager * @returns Promise the object of profileInfo using the custom credential manager */ - private static async setupCustomCredentialManager(credentialManagerMap: imperative.ICredentialManagerNameMap): Promise { + public static async setupCustomCredentialManager(credentialManagerMap: imperative.ICredentialManagerNameMap): Promise { ZoweLogger.trace("ProfilesUtils.setupCustomCredentialManager called."); ZoweLogger.info( localize( @@ -318,7 +318,7 @@ export class ProfilesUtils { * Use the default credential manager in Zowe Explorer and setup before use * @returns Promise the object of profileInfo using the default credential manager */ - private static async setupDefaultCredentialManager(): Promise { + public static async setupDefaultCredentialManager(): Promise { ZoweLogger.trace("ProfilesUtils.setupDefaultCredentialManager called."); ZoweLogger.info( localize("ProfilesUtils.setupDefaultCredentialManager.usingDefault", "No custom credential managers found, using the default instead.") @@ -337,7 +337,7 @@ export class ProfilesUtils { * * @returns Promise */ - private static async fetchRegisteredPlugins(): Promise { + public static async fetchRegisteredPlugins(): Promise { ZoweLogger.trace("ProfilesUtils.fetchRegisteredPlugins called."); const knownCredentialManagers = imperative.CredentialManagerOverride.getKnownCredMgrs(); const credentialManager = knownCredentialManagers.find((knownCredentialManager) => { @@ -386,7 +386,7 @@ export class ProfilesUtils { * @param credentialManager the credential manager to handle its missing VS Code extension * @returns Promise */ - private static async promptAndHandleMissingCredentialManager(credentialManager: imperative.ICredentialManagerNameMap): Promise { + public static async promptAndHandleMissingCredentialManager(credentialManager: imperative.ICredentialManagerNameMap): Promise { ZoweLogger.trace("ProfilesUtils.promptAndHandleMissingCredentialManager called."); const header = localize( "ProfilesUtils.promptAndHandleMissingCredentialManager.suggestInstallHeader", @@ -422,7 +422,7 @@ export class ProfilesUtils { ); } - public static async getProfileInfo(): Promise { + public static async getProfileInfo(envTheia: boolean): Promise { ZoweLogger.trace("ProfilesUtils.getProfileInfo called."); const shouldCheckForCustomCredentialManagers = SettingsConfig.getDirectValue(globals.SETTINGS_CHECK_FOR_CUSTOM_CREDENTIAL_MANAGERS); @@ -449,7 +449,7 @@ export class ProfilesUtils { public static async readConfigFromDisk(): Promise { ZoweLogger.trace("ProfilesUtils.readConfigFromDisk called."); let rootPath: string; - const mProfileInfo = await ProfilesUtils.getProfileInfo(); + const mProfileInfo = await ProfilesUtils.getProfileInfo(globals.ISTHEIA); if (vscode.workspace.workspaceFolders && vscode.workspace.workspaceFolders[0]) { rootPath = vscode.workspace.workspaceFolders[0].uri.fsPath; await mProfileInfo.readProfilesFromDisk({ homeDir: getZoweDir(), projectDir: getFullPath(rootPath) }); From c20d02aebabfa21495a13e605cca5025c87b9b60 Mon Sep 17 00:00:00 2001 From: Rudy Flores <68666202+rudyflores@users.noreply.github.com> Date: Fri, 20 Oct 2023 14:25:53 -0400 Subject: [PATCH 157/189] fix broken unit test Signed-off-by: Rudy Flores <68666202+rudyflores@users.noreply.github.com> --- .../__tests__/__unit__/utils/ProfilesUtils.unit.test.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/zowe-explorer/__tests__/__unit__/utils/ProfilesUtils.unit.test.ts b/packages/zowe-explorer/__tests__/__unit__/utils/ProfilesUtils.unit.test.ts index 5c85b651f4..e66594e130 100644 --- a/packages/zowe-explorer/__tests__/__unit__/utils/ProfilesUtils.unit.test.ts +++ b/packages/zowe-explorer/__tests__/__unit__/utils/ProfilesUtils.unit.test.ts @@ -694,7 +694,7 @@ describe("ProfilesUtils unit tests", () => { credMgrZEName: "test", }); jest.spyOn((profUtils as any).ProfilesUtils, "setupCustomCredentialManager").mockReturnValueOnce({}); - await expect(profUtils.ProfilesUtils.getProfileInfo()).resolves.toEqual({}); + await expect(profUtils.ProfilesUtils.getProfileInfo(false)).resolves.toEqual({}); expect(isVSCodeCredentialPluginInstalledSpy).toBeCalledTimes(1); }); @@ -710,7 +710,7 @@ describe("ProfilesUtils unit tests", () => { credMgrZEName: "test", }); jest.spyOn((profUtils as any).ProfilesUtils, "setupCustomCredentialManager").mockReturnValueOnce({}); - await expect(profUtils.ProfilesUtils.getProfileInfo()).resolves.toEqual({}); + await expect(profUtils.ProfilesUtils.getProfileInfo(false)).resolves.toEqual({}); }); it("should retrieve the default credential manager if no custom credential manager is found", async () => { @@ -720,7 +720,7 @@ describe("ProfilesUtils unit tests", () => { jest.spyOn(SettingsConfig, "getDirectValue").mockReturnValueOnce(true); jest.spyOn(profUtils.ProfilesUtils, "getCredentialManagerMap").mockReturnValueOnce(undefined); jest.spyOn((profUtils as any).ProfilesUtils, "setupDefaultCredentialManager").mockReturnValueOnce({}); - await expect(profUtils.ProfilesUtils.getProfileInfo()).resolves.toEqual({}); + await expect(profUtils.ProfilesUtils.getProfileInfo(false)).resolves.toEqual({}); }); }); From 097391ccf19c50e96669fdd0006a9d0dc79ed2c2 Mon Sep 17 00:00:00 2001 From: Billie Simmons <49491949+JillieBeanSim@users.noreply.github.com> Date: Tue, 24 Oct 2023 09:36:14 -0400 Subject: [PATCH 158/189] address comment and remove check for langID including JCL Signed-off-by: Billie Simmons <49491949+JillieBeanSim@users.noreply.github.com> --- packages/zowe-explorer/CHANGELOG.md | 2 +- .../__unit__/job/actions.unit.test.ts | 18 ------------ .../i18n/sample/package.i18n.json | 2 +- .../i18n/sample/src/dataset/actions.i18n.json | 3 +- packages/zowe-explorer/package.json | 28 +++++++++---------- packages/zowe-explorer/package.nls.json | 2 +- packages/zowe-explorer/src/dataset/actions.ts | 10 +------ 7 files changed, 19 insertions(+), 46 deletions(-) diff --git a/packages/zowe-explorer/CHANGELOG.md b/packages/zowe-explorer/CHANGELOG.md index d39707c7e3..a051013a40 100644 --- a/packages/zowe-explorer/CHANGELOG.md +++ b/packages/zowe-explorer/CHANGELOG.md @@ -10,7 +10,7 @@ All notable changes to the "vscode-extension-for-zowe" extension will be documen - Introduce a new user interface for managing profiles via right-click action "Manage Profile". - Added new edit feature on `Edit Attributes` view for changing file tags on USS [#2113](https://github.com/zowe/vscode-extension-for-zowe/issues/2113) - Added new API {ZE Extender MetaData} to allow extenders to have the metadata of registered extenders to aid in team configuration file creation from a view that isn't Zowe Explorer's. [#2394](https://github.com/zowe/vscode-extension-for-zowe/issues/2394) -- Added new right-click action for `Submit JCL` to local JCL files in VS Code file explorer as well as JCL opened in the VS Code text editor. [#2475](https://github.com/zowe/vscode-extension-for-zowe/issues/2475) +- Added new right-click action for `Submit as JCL` for local files in the VS Code file explorer as well as files opened in the VS Code text editor. [#2475](https://github.com/zowe/vscode-extension-for-zowe/issues/2475) - Added "Sort PDS members" feature in Data Sets tree view: accessible via sort icon on session node, or by right-clicking a PDS or session. [#2420](https://github.com/zowe/vscode-extension-for-zowe/issues/2420) - Added "Filter PDS members" feature in Data Sets tree view: accessible via filter icon on session node, or by right-clicking a PDS or session. [#2420](https://github.com/zowe/vscode-extension-for-zowe/issues/2420) - Added descriptions to data set nodes if filtering and/or sorting is enabled (where applicable). diff --git a/packages/zowe-explorer/__tests__/__unit__/job/actions.unit.test.ts b/packages/zowe-explorer/__tests__/__unit__/job/actions.unit.test.ts index 39ceab19ce..dd91a263b2 100644 --- a/packages/zowe-explorer/__tests__/__unit__/job/actions.unit.test.ts +++ b/packages/zowe-explorer/__tests__/__unit__/job/actions.unit.test.ts @@ -535,24 +535,6 @@ describe("Jobs Actions Unit Tests - Function submitJcl", () => { "Job submitted [JOB1234](command:zowe.jobs.setJobSpool?%5B%22sestest%22%2C%22JOB1234%22%5D)" ); }); - it("Checking failure of submitting of active text editor content not JCL", async () => { - createGlobalMocks(); - const blockMocks: any = createBlockMocks(); - mocked(zowe.ZosmfSession.createSessCfgFromArgs).mockReturnValue(blockMocks.session); - mocked(Profiles.getInstance).mockReturnValue(blockMocks.profileInstance); - mocked(vscode.window.showQuickPick).mockReturnValueOnce(Promise.resolve(blockMocks.datasetSessionNode.label)); - blockMocks.testDatasetTree.getChildren.mockResolvedValueOnce([ - new ZoweDatasetNode("node", vscode.TreeItemCollapsibleState.None, blockMocks.datasetSessionNode, null as any), - blockMocks.datasetSessionNode, - ]); - activeTextEditorDocument.mockReturnValue(blockMocks.textDocument); - (blockMocks.textDocument.languageId as string) = "java"; - await dsActions.submitJcl(blockMocks.testDatasetTree, undefined); - - const errorMsg = "The document being submitted is not a JCL, submission cancelled."; - expect(blockMocks.errorLogSpy).toBeCalledWith(errorMsg); - expect(blockMocks.errorGuiMsgSpy).toBeCalledWith(errorMsg); - }); it("Checking failure of submitting JCL via command palette if not active text editor", async () => { createGlobalMocks(); const blockMocks = createBlockMocks(); diff --git a/packages/zowe-explorer/i18n/sample/package.i18n.json b/packages/zowe-explorer/i18n/sample/package.i18n.json index a5a3599fe6..e3c8819b8b 100644 --- a/packages/zowe-explorer/i18n/sample/package.i18n.json +++ b/packages/zowe-explorer/i18n/sample/package.i18n.json @@ -40,7 +40,7 @@ "removeSavedSearch": "Remove Search", "removeSession": "Hide Profile", "saveSearch": "Add to Favorites", - "submitJcl": "Submit JCL", + "submitJcl": "Submit as JCL", "submitMember": "Submit Job", "uss.addSession": "Add Profile to USS View", "uss.copyPath": "Copy Path", diff --git a/packages/zowe-explorer/i18n/sample/src/dataset/actions.i18n.json b/packages/zowe-explorer/i18n/sample/src/dataset/actions.i18n.json index 114e621ffc..209867b8c6 100644 --- a/packages/zowe-explorer/i18n/sample/src/dataset/actions.i18n.json +++ b/packages/zowe-explorer/i18n/sample/src/dataset/actions.i18n.json @@ -43,8 +43,7 @@ "showAttributes.error": "Unable to list attributes.", "attributes.title": "Attributes", "submitJcl.notActiveEditorMsg": "No editor with a document that could be submitted as JCL is currently open.", - "submitJcl.notJclMsg": "The document being submitted is not a JCL, submission cancelled.", - "submitJcl.submitting": "Submitting JCL in document {0}", + "submitJcl.submitting": "Submitting as JCL in document {0}", "submitJcl.qp.placeholder": "Select the Profile to use to submit the job", "submitJcl.noProfile": "No profiles available", "submitJcl.nullSession.error": "Session for submitting JCL was null or undefined!", diff --git a/packages/zowe-explorer/package.json b/packages/zowe-explorer/package.json index 21d4f95437..001a2b6772 100644 --- a/packages/zowe-explorer/package.json +++ b/packages/zowe-explorer/package.json @@ -807,6 +807,20 @@ } ], "menus": { + "editor/context": [ + { + "when": "editorFocus", + "command": "zowe.ds.submitJcl", + "group": "000_zowe_dsMainframeInteraction@1" + } + ], + "explorer/context": [ + { + "when": "!explorerResourceIsFolder", + "command": "zowe.ds.submitJcl", + "group": "000_zowe_dsMainframeInteraction@1" + } + ], "view/title": [ { "when": "view == zowe.ds.explorer", @@ -839,20 +853,6 @@ "group": "navigation" } ], - "editor/context": [ - { - "when": "resourceLangId =~ /^.*jcl.*/i", - "command": "zowe.ds.submitJcl", - "group": "000_zowe_dsMainframeInteraction@1" - } - ], - "explorer/context": [ - { - "when": "resourceLangId =~ /^.*jcl.*/i", - "command": "zowe.ds.submitJcl", - "group": "000_zowe_dsMainframeInteraction@1" - } - ], "view/item/context": [ { "when": "viewItem =~ /^(?!.*_fav.*)ussSession.*/ && !listMultiSelection", diff --git a/packages/zowe-explorer/package.nls.json b/packages/zowe-explorer/package.nls.json index a5a3599fe6..e3c8819b8b 100644 --- a/packages/zowe-explorer/package.nls.json +++ b/packages/zowe-explorer/package.nls.json @@ -40,7 +40,7 @@ "removeSavedSearch": "Remove Search", "removeSession": "Hide Profile", "saveSearch": "Add to Favorites", - "submitJcl": "Submit JCL", + "submitJcl": "Submit as JCL", "submitMember": "Submit Job", "uss.addSession": "Add Profile to USS View", "uss.copyPath": "Copy Path", diff --git a/packages/zowe-explorer/src/dataset/actions.ts b/packages/zowe-explorer/src/dataset/actions.ts index cd034a4fec..b7e6c9e6c0 100644 --- a/packages/zowe-explorer/src/dataset/actions.ts +++ b/packages/zowe-explorer/src/dataset/actions.ts @@ -988,15 +988,7 @@ export async function submitJcl(datasetProvider: api.IZoweTree Date: Tue, 24 Oct 2023 09:42:09 -0400 Subject: [PATCH 159/189] update bug fix changelog for this item Signed-off-by: Billie Simmons <49491949+JillieBeanSim@users.noreply.github.com> --- packages/zowe-explorer/CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/zowe-explorer/CHANGELOG.md b/packages/zowe-explorer/CHANGELOG.md index a051013a40..f14cec82e9 100644 --- a/packages/zowe-explorer/CHANGELOG.md +++ b/packages/zowe-explorer/CHANGELOG.md @@ -18,7 +18,7 @@ All notable changes to the "vscode-extension-for-zowe" extension will be documen ### Bug fixes -- Fixed submitting local JCL using command pallet option `Zowe Explorer: Submit JCL` by adding a check for chosen profile returned to continue the action and added check on the language id for JCL. [#1625](https://github.com/zowe/vscode-extension-for-zowe/issues/1625) +- Fixed submitting local JCL using command pallet option `Zowe Explorer: Submit as JCL` by adding a check for chosen profile returned to continue the action. [#1625](https://github.com/zowe/vscode-extension-for-zowe/issues/1625) - Fixed conflict resolution being skipped if local and remote file have different contents but are the same size. [#2496](https://github.com/zowe/vscode-extension-for-zowe/issues/2496) ## `2.11.2` From d1f90d27619c2e15c3a1ddb7ee2319edb64be286 Mon Sep 17 00:00:00 2001 From: Rudy Flores <68666202+rudyflores@users.noreply.github.com> Date: Tue, 24 Oct 2023 10:30:53 -0400 Subject: [PATCH 160/189] fix for issue when profile not listed Signed-off-by: Rudy Flores <68666202+rudyflores@users.noreply.github.com> --- .../__unit__/Profiles.extended.unit.test.ts | 29 +++++++++++++++++++ packages/zowe-explorer/src/Profiles.ts | 9 ++++++ 2 files changed, 38 insertions(+) diff --git a/packages/zowe-explorer/__tests__/__unit__/Profiles.extended.unit.test.ts b/packages/zowe-explorer/__tests__/__unit__/Profiles.extended.unit.test.ts index e31dfe23d9..f1e35c53e3 100644 --- a/packages/zowe-explorer/__tests__/__unit__/Profiles.extended.unit.test.ts +++ b/packages/zowe-explorer/__tests__/__unit__/Profiles.extended.unit.test.ts @@ -1846,4 +1846,33 @@ describe("Profiles Unit Tests - function clearFilterFromAllTrees", () => { expect(flipStateSpy).toBeCalledTimes(0); expect(refreshElementSpy).toBeCalledTimes(0); }); + + it("should fail to clear filters if the session node is not listed in the tree", async () => { + const globalMocks = await createGlobalMocks(); + const testNode = new (ZoweTreeNode as any)( + "fake", + vscode.TreeItemCollapsibleState.None, + undefined, + globalMocks.testSession, + globalMocks.testProfile + ); + + const flipStateSpy = jest.fn(); + const refreshElementSpy = jest.fn(); + const getProfileSpy = jest.fn(() => ({ name: "test" })); + + const mockTreeProvider = { + mSessionNodes: [{ getProfile: getProfileSpy }], + flipState: flipStateSpy, + refreshElement: refreshElementSpy, + } as any; + jest.spyOn(TreeProviders, "ds", "get").mockReturnValue(mockTreeProvider); + jest.spyOn(TreeProviders, "uss", "get").mockReturnValue(mockTreeProvider); + jest.spyOn(TreeProviders, "job", "get").mockReturnValue(mockTreeProvider); + + expect(Profiles.getInstance().clearFilterFromAllTrees(testNode)); + expect(flipStateSpy).toBeCalledTimes(0); + expect(refreshElementSpy).toBeCalledTimes(0); + expect(getProfileSpy).toBeCalledTimes(3); + }); }); diff --git a/packages/zowe-explorer/src/Profiles.ts b/packages/zowe-explorer/src/Profiles.ts index 682cb45747..bad675e265 100644 --- a/packages/zowe-explorer/src/Profiles.ts +++ b/packages/zowe-explorer/src/Profiles.ts @@ -1210,6 +1210,9 @@ export class Profiles extends ProfilesCache { const dsNode: IZoweDatasetTreeNode = TreeProviders.ds.mSessionNodes.find( (sessionNode: IZoweDatasetTreeNode) => sessionNode.getProfile()?.name === node.getProfile()?.name ); + if (!dsNode) { + return; + } dsNode.tooltip &&= node.getProfile()?.name; dsNode.description &&= ""; dsNode.pattern &&= ""; @@ -1224,6 +1227,9 @@ export class Profiles extends ProfilesCache { const ussNode: IZoweUSSTreeNode = TreeProviders.uss.mSessionNodes.find( (sessionNode: IZoweUSSTreeNode) => sessionNode.getProfile()?.name === node.getProfile()?.name ); + if (!ussNode) { + return; + } ussNode.tooltip &&= node.getProfile()?.name; ussNode.description &&= ""; ussNode.fullPath &&= ""; @@ -1238,6 +1244,9 @@ export class Profiles extends ProfilesCache { const jobNode: IZoweJobTreeNode = TreeProviders.job.mSessionNodes.find( (sessionNode: IZoweJobTreeNode) => sessionNode.getProfile()?.name === node.getProfile()?.name ); + if (!jobNode) { + return; + } jobNode.tooltip &&= node.getProfile()?.name; jobNode.description &&= ""; jobNode.owner &&= ""; From 6805f34b2ff8da37e7059a46386f48c4d707ff27 Mon Sep 17 00:00:00 2001 From: Trae Yelovich Date: Tue, 24 Oct 2023 13:12:50 -0400 Subject: [PATCH 161/189] fix(ftp): Use fileSync instead of tmpNameSync when checking e-tag Signed-off-by: Trae Yelovich --- .../zowe-explorer-ftp-extension/src/ZoweExplorerFtpMvsApi.ts | 5 +++-- .../zowe-explorer-ftp-extension/src/ZoweExplorerFtpUssApi.ts | 5 +++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/packages/zowe-explorer-ftp-extension/src/ZoweExplorerFtpMvsApi.ts b/packages/zowe-explorer-ftp-extension/src/ZoweExplorerFtpMvsApi.ts index 4ad04c06bb..db1be5ff5e 100644 --- a/packages/zowe-explorer-ftp-extension/src/ZoweExplorerFtpMvsApi.ts +++ b/packages/zowe-explorer-ftp-extension/src/ZoweExplorerFtpMvsApi.ts @@ -360,13 +360,14 @@ export class FtpMvsApi extends AbstractFtpApi implements ZoweExplorerApi.IMvs { } private async getContentsTag(dataSetName: string): Promise { - const tmpFileName = tmp.tmpNameSync(); + const tmpFile = tmp.fileSync({ discardDescriptor: true }); const options: zowe.IDownloadOptions = { binary: false, - file: tmpFileName, + file: tmpFile.name, }; const loadResult = await this.getContents(dataSetName, options); const etag: string = loadResult.apiResponse.etag; + fs.rmSync(tmpFile.name); return etag; } private getDefaultResponse(): zowe.IZosFilesResponse { diff --git a/packages/zowe-explorer-ftp-extension/src/ZoweExplorerFtpUssApi.ts b/packages/zowe-explorer-ftp-extension/src/ZoweExplorerFtpUssApi.ts index 17642df3e5..128596ee62 100644 --- a/packages/zowe-explorer-ftp-extension/src/ZoweExplorerFtpUssApi.ts +++ b/packages/zowe-explorer-ftp-extension/src/ZoweExplorerFtpUssApi.ts @@ -267,13 +267,14 @@ export class FtpUssApi extends AbstractFtpApi implements ZoweExplorerApi.IUss { } private async getContentsTag(ussFilePath: string): Promise { - const tmpFileName = tmp.tmpNameSync(); + const tmpFile = tmp.fileSync({ discardDescriptor: true }); const options: zowe.IDownloadOptions = { binary: false, - file: tmpFileName, + file: tmpFile.name, }; const loadResult = await this.getContents(ussFilePath, options); const etag: string = loadResult.apiResponse.etag; + fs.rmSync(tmpFile.name); return etag; } From 610a81255f2f84b4ba38229e27d2b44a3b64192f Mon Sep 17 00:00:00 2001 From: Trae Yelovich Date: Tue, 24 Oct 2023 13:27:22 -0400 Subject: [PATCH 162/189] test(ftp): Update test cases to verify tmp.fileSync call Signed-off-by: Trae Yelovich --- .../__unit__/Mvs/ZoweExplorerFtpMvsApi.unit.test.ts | 5 ++++- .../__unit__/Uss/ZoweExplorerFtpUssApi.unit.test.ts | 5 ++++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/packages/zowe-explorer-ftp-extension/__tests__/__unit__/Mvs/ZoweExplorerFtpMvsApi.unit.test.ts b/packages/zowe-explorer-ftp-extension/__tests__/__unit__/Mvs/ZoweExplorerFtpMvsApi.unit.test.ts index 1836670676..46be2da10a 100644 --- a/packages/zowe-explorer-ftp-extension/__tests__/__unit__/Mvs/ZoweExplorerFtpMvsApi.unit.test.ts +++ b/packages/zowe-explorer-ftp-extension/__tests__/__unit__/Mvs/ZoweExplorerFtpMvsApi.unit.test.ts @@ -100,6 +100,7 @@ describe("FtpMvsApi", () => { it("should upload content to dataset.", async () => { const localFile = tmp.tmpNameSync({ tmpdir: "/tmp" }); + const fileSyncSpy = jest.spyOn(tmp, "fileSync"); fs.writeFileSync(localFile, "hello"); const response = TestUtils.getSingleLineStream(); @@ -113,7 +114,7 @@ describe("FtpMvsApi", () => { dataSetName: " (IBMUSER).DS2", options: { encoding: "", returnEtag: true, etag: "utf8" }, }; - jest.spyOn(MvsApi as any, "getContentsTag").mockReturnValue(undefined); + jest.spyOn(MvsApi as any, "getContents").mockResolvedValueOnce({ apiResponse: { etag: "utf8" } }); jest.spyOn(fs, "readFileSync").mockReturnValue("test"); jest.spyOn(Gui, "warningMessage").mockImplementation(); const result = await MvsApi.putContents(mockParams.inputFilePath, mockParams.dataSetName, mockParams.options); @@ -121,6 +122,8 @@ describe("FtpMvsApi", () => { expect(DataSetUtils.listDataSets).toBeCalledTimes(1); expect(DataSetUtils.uploadDataSet).toBeCalledTimes(1); expect(MvsApi.releaseConnection).toBeCalled(); + // check that correct function is called from node-tmp + expect(fileSyncSpy).toHaveBeenCalledWith({ discardDescriptor: true }); }); it("should upload single space to dataset when secureFtp is true and contents are empty", async () => { diff --git a/packages/zowe-explorer-ftp-extension/__tests__/__unit__/Uss/ZoweExplorerFtpUssApi.unit.test.ts b/packages/zowe-explorer-ftp-extension/__tests__/__unit__/Uss/ZoweExplorerFtpUssApi.unit.test.ts index fa8d863d88..de1bc5b727 100644 --- a/packages/zowe-explorer-ftp-extension/__tests__/__unit__/Uss/ZoweExplorerFtpUssApi.unit.test.ts +++ b/packages/zowe-explorer-ftp-extension/__tests__/__unit__/Uss/ZoweExplorerFtpUssApi.unit.test.ts @@ -96,6 +96,7 @@ describe("FtpUssApi", () => { const localFile = tmp.tmpNameSync({ tmpdir: "/tmp" }); const response = TestUtils.getSingleLineStream(); UssUtils.uploadFile = jest.fn().mockReturnValue(response); + const fileSyncSpy = jest.spyOn(tmp, "fileSync"); jest.spyOn(UssApi, "getContents").mockResolvedValue({ apiResponse: { etag: "test" } } as any); const mockParams = { inputFilePath: localFile, @@ -107,11 +108,13 @@ describe("FtpUssApi", () => { }, }; const result = await UssApi.putContents(mockParams.inputFilePath, mockParams.ussFilePath, undefined, undefined, "test", true); - jest.spyOn(UssApi as any, "getContentsTag").mockReturnValue("test"); + jest.spyOn(UssApi as any, "getContents").mockResolvedValueOnce({ apiResponse: { etag: "test" } }); expect(result.commandResponse).toContain("File uploaded successfully."); expect(UssUtils.downloadFile).toBeCalledTimes(1); expect(UssUtils.uploadFile).toBeCalledTimes(1); expect(UssApi.releaseConnection).toBeCalled(); + // check that correct function is called from node-tmp + expect(fileSyncSpy).toHaveBeenCalledWith({ discardDescriptor: true }); }); it("should call putContents when calling putContent", async () => { From 6c1c9b6c7e72aee307c94ee4e83955c7b979b914 Mon Sep 17 00:00:00 2001 From: Trae Yelovich Date: Tue, 24 Oct 2023 14:13:53 -0400 Subject: [PATCH 163/189] fix(ftp): adjust getContentsTag calls so only one FTP connection is active Signed-off-by: Trae Yelovich --- .../src/ZoweExplorerFtpMvsApi.ts | 23 +++++++++++-------- .../src/ZoweExplorerFtpUssApi.ts | 18 +++++++++------ 2 files changed, 25 insertions(+), 16 deletions(-) diff --git a/packages/zowe-explorer-ftp-extension/src/ZoweExplorerFtpMvsApi.ts b/packages/zowe-explorer-ftp-extension/src/ZoweExplorerFtpMvsApi.ts index db1be5ff5e..975266ed41 100644 --- a/packages/zowe-explorer-ftp-extension/src/ZoweExplorerFtpMvsApi.ts +++ b/packages/zowe-explorer-ftp-extension/src/ZoweExplorerFtpMvsApi.ts @@ -131,6 +131,17 @@ export class FtpMvsApi extends AbstractFtpApi implements ZoweExplorerApi.IMvs { } const result = this.getDefaultResponse(); const profile = this.checkedProfile(); + + // Save-Save with FTP requires loading the file first + // (moved this block above connection request so only one connection is active at a time) + if (options.returnEtag && options.etag) { + const contentsTag = await this.getContentsTag(dataSetName); + if (contentsTag && contentsTag !== options.etag) { + result.success = false; + result.commandResponse = "Rest API failure with HTTP(S) status 412 Save conflict."; + return result; + } + } let connection; try { connection = await this.ftpClient(profile); @@ -138,15 +149,6 @@ export class FtpMvsApi extends AbstractFtpApi implements ZoweExplorerApi.IMvs { ZoweLogger.logImperativeMessage(result.commandResponse, MessageSeverity.ERROR); throw new Error(result.commandResponse); } - // Save-Save with FTP requires loading the file first - if (options.returnEtag && options.etag) { - const contentsTag = await this.getContentsTag(dataSetName); - if (contentsTag && contentsTag !== options.etag) { - result.success = false; - result.commandResponse = "Rest API failure with HTTP(S) status 412 Save conflict."; - return result; - } - } const lrecl: number = dsAtrribute.apiResponse.items[0].lrecl; const data = fs.readFileSync(inputFilePath, { encoding: "utf8" }); const transferOptions: Record = { @@ -178,6 +180,9 @@ export class FtpMvsApi extends AbstractFtpApi implements ZoweExplorerApi.IMvs { await DataSetUtils.uploadDataSet(connection, targetDataset, transferOptions); result.success = true; if (options.returnEtag) { + // release this connection instance because a new one will be made with getContentsTag + this.releaseConnection(connection); + connection = null; const contentsTag = await this.getContentsTag(dataSetName); result.apiResponse = [ { diff --git a/packages/zowe-explorer-ftp-extension/src/ZoweExplorerFtpUssApi.ts b/packages/zowe-explorer-ftp-extension/src/ZoweExplorerFtpUssApi.ts index 128596ee62..baf4509c0c 100644 --- a/packages/zowe-explorer-ftp-extension/src/ZoweExplorerFtpUssApi.ts +++ b/packages/zowe-explorer-ftp-extension/src/ZoweExplorerFtpUssApi.ts @@ -126,23 +126,27 @@ export class FtpUssApi extends AbstractFtpApi implements ZoweExplorerApi.IUss { localFile: inputFilePath, }; const result = this.getDefaultResponse(); + // Save-Save with FTP requires loading the file first + // (moved this block above connection request so only one connection is active at a time) + if (returnEtag && etag) { + const contentsTag = await this.getContentsTag(ussFilePath); + if (contentsTag && contentsTag !== etag) { + throw new Error("Rest API failure with HTTP(S) status 412 Save conflict."); + } + } let connection; try { connection = await this.ftpClient(this.checkedProfile()); if (!connection) { throw new Error(result.commandResponse); } - // Save-Save with FTP requires loading the file first - if (returnEtag && etag) { - const contentsTag = await this.getContentsTag(ussFilePath); - if (contentsTag && contentsTag !== etag) { - throw new Error("Rest API failure with HTTP(S) status 412 Save conflict."); - } - } await UssUtils.uploadFile(connection, ussFilePath, transferOptions); result.success = true; if (returnEtag) { + // release this connection instance because a new one will be made with getContentsTag + this.releaseConnection(connection); + connection = null; const contentsTag = await this.getContentsTag(ussFilePath); result.apiResponse.etag = contentsTag; } From 4e55a999b4e49cf9a2f31b910f775297e609497a Mon Sep 17 00:00:00 2001 From: Trae Yelovich Date: Tue, 24 Oct 2023 14:30:16 -0400 Subject: [PATCH 164/189] chore: update FTP changelog Signed-off-by: Trae Yelovich --- packages/zowe-explorer-ftp-extension/CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/packages/zowe-explorer-ftp-extension/CHANGELOG.md b/packages/zowe-explorer-ftp-extension/CHANGELOG.md index 1d58ca0e0c..83ba9a3a0e 100644 --- a/packages/zowe-explorer-ftp-extension/CHANGELOG.md +++ b/packages/zowe-explorer-ftp-extension/CHANGELOG.md @@ -7,6 +7,8 @@ All notable changes to the "zowe-explorer-ftp-extension" extension will be docum ### Bug fixes - Fixed ECONNRESET error when trying to upload or create an empty data set member. [#2350](https://github.com/zowe/vscode-extension-for-zowe/issues/2350) +- Fixed issue where temporary files for e-tag comparison were not deleted after use. +- Fixed issue where another connection attempt was made inside `putContents` (in `getContentsTag`) even though a connection was already active. ## `2.11.2` From d493cf4c72f40214ea0a882bc5bf6c5f5e6d0a10 Mon Sep 17 00:00:00 2001 From: Trae Yelovich Date: Tue, 24 Oct 2023 17:38:21 -0400 Subject: [PATCH 165/189] fix(ftp,tests): Revert back to tmpNameSync, add assertions in tests - `UssUtils.downloadFile` ultimately calls `fs.createWriteStream`, so we don't need to make the file first. - Added checks in tests for `tmpNameSync` and `rmSync` to verify that temp files are removed Signed-off-by: Trae Yelovich --- .../__unit__/Mvs/ZoweExplorerFtpMvsApi.unit.test.ts | 6 ++++-- .../__unit__/Uss/ZoweExplorerFtpUssApi.unit.test.ts | 6 ++++-- .../src/ZoweExplorerFtpMvsApi.ts | 6 +++--- .../src/ZoweExplorerFtpUssApi.ts | 6 +++--- 4 files changed, 14 insertions(+), 10 deletions(-) diff --git a/packages/zowe-explorer-ftp-extension/__tests__/__unit__/Mvs/ZoweExplorerFtpMvsApi.unit.test.ts b/packages/zowe-explorer-ftp-extension/__tests__/__unit__/Mvs/ZoweExplorerFtpMvsApi.unit.test.ts index 46be2da10a..2d4ca5f5ff 100644 --- a/packages/zowe-explorer-ftp-extension/__tests__/__unit__/Mvs/ZoweExplorerFtpMvsApi.unit.test.ts +++ b/packages/zowe-explorer-ftp-extension/__tests__/__unit__/Mvs/ZoweExplorerFtpMvsApi.unit.test.ts @@ -100,7 +100,8 @@ describe("FtpMvsApi", () => { it("should upload content to dataset.", async () => { const localFile = tmp.tmpNameSync({ tmpdir: "/tmp" }); - const fileSyncSpy = jest.spyOn(tmp, "fileSync"); + const tmpNameSyncSpy = jest.spyOn(tmp, "tmpNameSync"); + const rmSyncSpy = jest.spyOn(fs, "rmSync"); fs.writeFileSync(localFile, "hello"); const response = TestUtils.getSingleLineStream(); @@ -123,7 +124,8 @@ describe("FtpMvsApi", () => { expect(DataSetUtils.uploadDataSet).toBeCalledTimes(1); expect(MvsApi.releaseConnection).toBeCalled(); // check that correct function is called from node-tmp - expect(fileSyncSpy).toHaveBeenCalledWith({ discardDescriptor: true }); + expect(tmpNameSyncSpy).toHaveBeenCalled(); + expect(rmSyncSpy).toHaveBeenCalled(); }); it("should upload single space to dataset when secureFtp is true and contents are empty", async () => { diff --git a/packages/zowe-explorer-ftp-extension/__tests__/__unit__/Uss/ZoweExplorerFtpUssApi.unit.test.ts b/packages/zowe-explorer-ftp-extension/__tests__/__unit__/Uss/ZoweExplorerFtpUssApi.unit.test.ts index de1bc5b727..18ecf95c59 100644 --- a/packages/zowe-explorer-ftp-extension/__tests__/__unit__/Uss/ZoweExplorerFtpUssApi.unit.test.ts +++ b/packages/zowe-explorer-ftp-extension/__tests__/__unit__/Uss/ZoweExplorerFtpUssApi.unit.test.ts @@ -96,7 +96,8 @@ describe("FtpUssApi", () => { const localFile = tmp.tmpNameSync({ tmpdir: "/tmp" }); const response = TestUtils.getSingleLineStream(); UssUtils.uploadFile = jest.fn().mockReturnValue(response); - const fileSyncSpy = jest.spyOn(tmp, "fileSync"); + const tmpNameSyncSpy = jest.spyOn(tmp, "tmpNameSync"); + const rmSyncSpy = jest.spyOn(fs, "rmSync"); jest.spyOn(UssApi, "getContents").mockResolvedValue({ apiResponse: { etag: "test" } } as any); const mockParams = { inputFilePath: localFile, @@ -114,7 +115,8 @@ describe("FtpUssApi", () => { expect(UssUtils.uploadFile).toBeCalledTimes(1); expect(UssApi.releaseConnection).toBeCalled(); // check that correct function is called from node-tmp - expect(fileSyncSpy).toHaveBeenCalledWith({ discardDescriptor: true }); + expect(tmpNameSyncSpy).toHaveBeenCalled(); + expect(rmSyncSpy).toHaveBeenCalled(); }); it("should call putContents when calling putContent", async () => { diff --git a/packages/zowe-explorer-ftp-extension/src/ZoweExplorerFtpMvsApi.ts b/packages/zowe-explorer-ftp-extension/src/ZoweExplorerFtpMvsApi.ts index 975266ed41..c893ec5eae 100644 --- a/packages/zowe-explorer-ftp-extension/src/ZoweExplorerFtpMvsApi.ts +++ b/packages/zowe-explorer-ftp-extension/src/ZoweExplorerFtpMvsApi.ts @@ -365,14 +365,14 @@ export class FtpMvsApi extends AbstractFtpApi implements ZoweExplorerApi.IMvs { } private async getContentsTag(dataSetName: string): Promise { - const tmpFile = tmp.fileSync({ discardDescriptor: true }); + const tmpFileName = tmp.tmpNameSync(); const options: zowe.IDownloadOptions = { binary: false, - file: tmpFile.name, + file: tmpFileName, }; const loadResult = await this.getContents(dataSetName, options); const etag: string = loadResult.apiResponse.etag; - fs.rmSync(tmpFile.name); + fs.rmSync(tmpFileName, { force: true }); return etag; } private getDefaultResponse(): zowe.IZosFilesResponse { diff --git a/packages/zowe-explorer-ftp-extension/src/ZoweExplorerFtpUssApi.ts b/packages/zowe-explorer-ftp-extension/src/ZoweExplorerFtpUssApi.ts index baf4509c0c..db048ecd1c 100644 --- a/packages/zowe-explorer-ftp-extension/src/ZoweExplorerFtpUssApi.ts +++ b/packages/zowe-explorer-ftp-extension/src/ZoweExplorerFtpUssApi.ts @@ -271,14 +271,14 @@ export class FtpUssApi extends AbstractFtpApi implements ZoweExplorerApi.IUss { } private async getContentsTag(ussFilePath: string): Promise { - const tmpFile = tmp.fileSync({ discardDescriptor: true }); + const tmpFileName = tmp.tmpNameSync(); const options: zowe.IDownloadOptions = { binary: false, - file: tmpFile.name, + file: tmpFileName, }; const loadResult = await this.getContents(ussFilePath, options); const etag: string = loadResult.apiResponse.etag; - fs.rmSync(tmpFile.name); + fs.rmSync(tmpFileName, { force: true }); return etag; } From 51672dcf6f257b8c9b8558cf5c497b96291f49b1 Mon Sep 17 00:00:00 2001 From: Rudy Flores <68666202+rudyflores@users.noreply.github.com> Date: Wed, 25 Oct 2023 11:54:13 -0400 Subject: [PATCH 166/189] refactor condition for checking for custom credential managers Signed-off-by: Rudy Flores <68666202+rudyflores@users.noreply.github.com> --- .../__theia__/mockFiles/settings.json | 3 +- .../__theia__/theia/extension.theiaChrome.ts | 6 ++-- .../__theia__/theia/extension.theiaFirefox.ts | 2 +- .../zowe-explorer/src/utils/ProfilesUtils.ts | 30 ++++++++++--------- 4 files changed, 22 insertions(+), 19 deletions(-) diff --git a/packages/zowe-explorer/__tests__/__theia__/mockFiles/settings.json b/packages/zowe-explorer/__tests__/__theia__/mockFiles/settings.json index 8c61d7946f..4a203675de 100644 --- a/packages/zowe-explorer/__tests__/__theia__/mockFiles/settings.json +++ b/packages/zowe-explorer/__tests__/__theia__/mockFiles/settings.json @@ -23,5 +23,6 @@ "fileHistory": [], "searchHistory": [] }, - "zowe.security.secureCredentialsEnabled": false + "zowe.security.secureCredentialsEnabled": false, + "zowe.security.checkForCustomCredentialManagers": false } diff --git a/packages/zowe-explorer/__tests__/__theia__/theia/extension.theiaChrome.ts b/packages/zowe-explorer/__tests__/__theia__/theia/extension.theiaChrome.ts index 239aadb46a..c7709d3fe6 100644 --- a/packages/zowe-explorer/__tests__/__theia__/theia/extension.theiaChrome.ts +++ b/packages/zowe-explorer/__tests__/__theia__/theia/extension.theiaChrome.ts @@ -20,12 +20,12 @@ let driverChrome: any; export async function openBrowser() { const chromeOptions = new chrome.Options(); - chromeOptions.addArguments("--headless"); - chromeOptions.addArguments("--no-sandbox"); + // chromeOptions.addArguments("--headless"); + // chromeOptions.addArguments("--no-sandbox"); // chromeOptions.addArguments("--disable-dev-shm-usage"); // Linux ONLY - chromeOptions.addArguments("--window-size=1200,1100"); + // chromeOptions.addArguments("--window-size=1200,1100"); driverChrome = new Builder().forBrowser("chrome").setChromeOptions(chromeOptions).build(); } diff --git a/packages/zowe-explorer/__tests__/__theia__/theia/extension.theiaFirefox.ts b/packages/zowe-explorer/__tests__/__theia__/theia/extension.theiaFirefox.ts index 1f52bc1851..c3919bd98c 100644 --- a/packages/zowe-explorer/__tests__/__theia__/theia/extension.theiaFirefox.ts +++ b/packages/zowe-explorer/__tests__/__theia__/theia/extension.theiaFirefox.ts @@ -19,7 +19,7 @@ let driverFirefox: any; export async function openBrowser() { const firefoxOptions = new firefox.Options(); - firefoxOptions.headless(); + // firefoxOptions.headless(); driverFirefox = new Builder().forBrowser("firefox").setFirefoxOptions(firefoxOptions).build(); } diff --git a/packages/zowe-explorer/src/utils/ProfilesUtils.ts b/packages/zowe-explorer/src/utils/ProfilesUtils.ts index ef9853ffa3..ece7d322f7 100644 --- a/packages/zowe-explorer/src/utils/ProfilesUtils.ts +++ b/packages/zowe-explorer/src/utils/ProfilesUtils.ts @@ -424,23 +424,25 @@ export class ProfilesUtils { public static async getProfileInfo(envTheia: boolean): Promise { ZoweLogger.trace("ProfilesUtils.getProfileInfo called."); + const hasSecureCredentialManagerEnabled: boolean = SettingsConfig.getDirectValue(globals.SETTINGS_SECURE_CREDENTIALS_ENABLED); - const shouldCheckForCustomCredentialManagers = SettingsConfig.getDirectValue(globals.SETTINGS_CHECK_FOR_CUSTOM_CREDENTIAL_MANAGERS); - if (shouldCheckForCustomCredentialManagers) { - await this.fetchRegisteredPlugins(); - } + if (hasSecureCredentialManagerEnabled) { + const shouldCheckForCustomCredentialManagers = SettingsConfig.getDirectValue(globals.SETTINGS_CHECK_FOR_CUSTOM_CREDENTIAL_MANAGERS); + if (shouldCheckForCustomCredentialManagers) { + await this.fetchRegisteredPlugins(); + } - const credentialManagerOverride = this.getCredentialManagerOverride(); - const isVSCodeCredentialPluginInstalled = this.isVSCodeCredentialPluginInstalled(credentialManagerOverride); - const isCustomCredentialPluginDefined = credentialManagerOverride !== imperative.CredentialManagerOverride.DEFAULT_CRED_MGR_NAME; - const settingEnabled: boolean = SettingsConfig.getDirectValue(globals.SETTINGS_SECURE_CREDENTIALS_ENABLED); - const credentialManagerMap = ProfilesUtils.getCredentialManagerMap(credentialManagerOverride); + const credentialManagerOverride = this.getCredentialManagerOverride(); + const isVSCodeCredentialPluginInstalled = this.isVSCodeCredentialPluginInstalled(credentialManagerOverride); + const isCustomCredentialPluginDefined = credentialManagerOverride !== imperative.CredentialManagerOverride.DEFAULT_CRED_MGR_NAME; + const credentialManagerMap = ProfilesUtils.getCredentialManagerMap(credentialManagerOverride); - if (isCustomCredentialPluginDefined && !isVSCodeCredentialPluginInstalled && credentialManagerMap && settingEnabled) { - await this.promptAndHandleMissingCredentialManager(credentialManagerMap); - } - if (credentialManagerMap && isVSCodeCredentialPluginInstalled && settingEnabled) { - return this.setupCustomCredentialManager(credentialManagerMap); + if (isCustomCredentialPluginDefined && !isVSCodeCredentialPluginInstalled && credentialManagerMap) { + await this.promptAndHandleMissingCredentialManager(credentialManagerMap); + } + if (credentialManagerMap && isVSCodeCredentialPluginInstalled) { + return this.setupCustomCredentialManager(credentialManagerMap); + } } return this.setupDefaultCredentialManager(); From 65cb11e5d9bdf07fa9f1baf6531e3976398bfd26 Mon Sep 17 00:00:00 2001 From: Rudy Flores <68666202+rudyflores@users.noreply.github.com> Date: Wed, 25 Oct 2023 11:57:48 -0400 Subject: [PATCH 167/189] add back headless used for testing Signed-off-by: Rudy Flores <68666202+rudyflores@users.noreply.github.com> --- .../__tests__/__theia__/theia/extension.theiaChrome.ts | 6 +++--- .../__tests__/__theia__/theia/extension.theiaFirefox.ts | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/zowe-explorer/__tests__/__theia__/theia/extension.theiaChrome.ts b/packages/zowe-explorer/__tests__/__theia__/theia/extension.theiaChrome.ts index c7709d3fe6..239aadb46a 100644 --- a/packages/zowe-explorer/__tests__/__theia__/theia/extension.theiaChrome.ts +++ b/packages/zowe-explorer/__tests__/__theia__/theia/extension.theiaChrome.ts @@ -20,12 +20,12 @@ let driverChrome: any; export async function openBrowser() { const chromeOptions = new chrome.Options(); - // chromeOptions.addArguments("--headless"); - // chromeOptions.addArguments("--no-sandbox"); + chromeOptions.addArguments("--headless"); + chromeOptions.addArguments("--no-sandbox"); // chromeOptions.addArguments("--disable-dev-shm-usage"); // Linux ONLY - // chromeOptions.addArguments("--window-size=1200,1100"); + chromeOptions.addArguments("--window-size=1200,1100"); driverChrome = new Builder().forBrowser("chrome").setChromeOptions(chromeOptions).build(); } diff --git a/packages/zowe-explorer/__tests__/__theia__/theia/extension.theiaFirefox.ts b/packages/zowe-explorer/__tests__/__theia__/theia/extension.theiaFirefox.ts index c3919bd98c..1f52bc1851 100644 --- a/packages/zowe-explorer/__tests__/__theia__/theia/extension.theiaFirefox.ts +++ b/packages/zowe-explorer/__tests__/__theia__/theia/extension.theiaFirefox.ts @@ -19,7 +19,7 @@ let driverFirefox: any; export async function openBrowser() { const firefoxOptions = new firefox.Options(); - // firefoxOptions.headless(); + firefoxOptions.headless(); driverFirefox = new Builder().forBrowser("firefox").setFirefoxOptions(firefoxOptions).build(); } From 4d6179a646e170b50ddf76403d2d5e0068091a35 Mon Sep 17 00:00:00 2001 From: Billie Simmons <49491949+JillieBeanSim@users.noreply.github.com> Date: Wed, 25 Oct 2023 16:23:54 -0400 Subject: [PATCH 168/189] remove extra call and register before for theia = false Signed-off-by: Billie Simmons <49491949+JillieBeanSim@users.noreply.github.com> --- .../__tests__/__unit__/extension.unit.test.ts | 2 +- .../__unit__/shared/init.unit.test.ts | 7 ------- .../__unit__/utils/ProfilesUtils.unit.test.ts | 7 ------- packages/zowe-explorer/src/extension.ts | 3 ++- packages/zowe-explorer/src/shared/init.ts | 18 ++++++++++-------- .../zowe-explorer/src/utils/ProfilesUtils.ts | 4 ---- 6 files changed, 13 insertions(+), 28 deletions(-) diff --git a/packages/zowe-explorer/__tests__/__unit__/extension.unit.test.ts b/packages/zowe-explorer/__tests__/__unit__/extension.unit.test.ts index e51fbd53af..b891f9ddc3 100644 --- a/packages/zowe-explorer/__tests__/__unit__/extension.unit.test.ts +++ b/packages/zowe-explorer/__tests__/__unit__/extension.unit.test.ts @@ -140,6 +140,7 @@ async function createGlobalMocks() { appName: vscode.env.appName, uriScheme: vscode.env.uriScheme, expectedCommands: [ + "zowe.updateSecureCredentials", "zowe.extRefresh", "zowe.all.config.init", "zowe.ds.addSession", @@ -244,7 +245,6 @@ async function createGlobalMocks() { "zowe.jobs.sortBy", "zowe.manualPoll", "zowe.editHistory", - "zowe.updateSecureCredentials", "zowe.promptCredentials", "zowe.profileManagement", "zowe.openRecentMember", diff --git a/packages/zowe-explorer/__tests__/__unit__/shared/init.unit.test.ts b/packages/zowe-explorer/__tests__/__unit__/shared/init.unit.test.ts index 1ba5e2fd0a..4322f5faf5 100644 --- a/packages/zowe-explorer/__tests__/__unit__/shared/init.unit.test.ts +++ b/packages/zowe-explorer/__tests__/__unit__/shared/init.unit.test.ts @@ -52,13 +52,6 @@ describe("Test src/shared/extension", () => { name: "zowe.manualPoll", mock: [], }, - { - name: "zowe.updateSecureCredentials", - mock: [ - { spy: jest.spyOn(globals, "setGlobalSecurityValue"), arg: [test.value] }, - { spy: jest.spyOn(profUtils.ProfilesUtils, "writeOverridesFile"), arg: [] }, - ], - }, { name: "zowe.editHistory", mock: [{ spy: jest.spyOn(HistoryView, "HistoryView"), arg: [test.context, test.value.providers] }], diff --git a/packages/zowe-explorer/__tests__/__unit__/utils/ProfilesUtils.unit.test.ts b/packages/zowe-explorer/__tests__/__unit__/utils/ProfilesUtils.unit.test.ts index e66594e130..d431ee721d 100644 --- a/packages/zowe-explorer/__tests__/__unit__/utils/ProfilesUtils.unit.test.ts +++ b/packages/zowe-explorer/__tests__/__unit__/utils/ProfilesUtils.unit.test.ts @@ -473,12 +473,6 @@ describe("ProfilesUtils unit tests", () => { describe("initializeZoweFolder", () => { it("should create directories and files that do not exist", async () => { const blockMocks = createBlockMocks(); - jest.spyOn(fs, "readFileSync").mockReturnValueOnce(""); - jest.spyOn(JSON, "parse").mockReturnValueOnce({ - overrides: { - credentialManager: "@zowe/cli", - }, - }); blockMocks.mockGetDirectValue.mockReturnValue(true); blockMocks.mockExistsSync.mockReturnValue(false); const createFileSpy = jest.spyOn(profUtils.ProfilesUtils, "writeOverridesFile"); @@ -490,7 +484,6 @@ describe("ProfilesUtils unit tests", () => { it("should skip creating directories and files that already exist", async () => { const blockMocks = createBlockMocks(); - jest.spyOn(profUtils.ProfilesUtils, "getCredentialManagerOverride").mockReturnValueOnce("@zowe/cli"); blockMocks.mockGetDirectValue.mockReturnValue("@zowe/cli"); blockMocks.mockExistsSync.mockReturnValue(true); const fileJson = blockMocks.mockFileRead; diff --git a/packages/zowe-explorer/src/extension.ts b/packages/zowe-explorer/src/extension.ts index d20fd9629d..167f7658aa 100644 --- a/packages/zowe-explorer/src/extension.ts +++ b/packages/zowe-explorer/src/extension.ts @@ -19,7 +19,7 @@ import { ProfilesUtils } from "./utils/ProfilesUtils"; import { initializeSpoolProvider } from "./SpoolProvider"; import { cleanTempDir, hideTempFolder } from "./utils/TempFolder"; import { SettingsConfig } from "./utils/SettingsConfig"; -import { registerCommonCommands, registerRefreshCommand, watchConfigProfile } from "./shared/init"; +import { registerCommonCommands, registerCredentialManager, registerRefreshCommand, watchConfigProfile } from "./shared/init"; import { ZoweLogger } from "./utils/LoggerUtils"; import { ZoweSaveQueue } from "./abstract/ZoweSaveQueue"; import { PollDecorator } from "./utils/DecorationProviders"; @@ -43,6 +43,7 @@ export async function activate(context: vscode.ExtensionContext): Promise { - await globals.setGlobalSecurityValue(customCredentialManager); - ProfilesUtils.writeOverridesFile(); - }) - ); - context.subscriptions.push( vscode.commands.registerCommand("zowe.promptCredentials", async (node: IZoweTreeNode) => { await ProfilesUtils.promptCredentials(node); @@ -218,6 +210,16 @@ export function registerCommonCommands(context: vscode.ExtensionContext, provide } } +export function registerCredentialManager(context: vscode.ExtensionContext): void { + // Update imperative.json to false only when VS Code setting is set to false + context.subscriptions.push( + vscode.commands.registerCommand("zowe.updateSecureCredentials", async (customCredentialManager?: string) => { + await globals.setGlobalSecurityValue(customCredentialManager); + ProfilesUtils.writeOverridesFile(); + }) + ); +} + export function watchConfigProfile(context: vscode.ExtensionContext, providers: IZoweProviders): void { ZoweLogger.trace("shared.init.watchConfigProfile called."); const watchers: vscode.FileSystemWatcher[] = []; diff --git a/packages/zowe-explorer/src/utils/ProfilesUtils.ts b/packages/zowe-explorer/src/utils/ProfilesUtils.ts index ece7d322f7..00ed49c3c8 100644 --- a/packages/zowe-explorer/src/utils/ProfilesUtils.ts +++ b/packages/zowe-explorer/src/utils/ProfilesUtils.ts @@ -543,10 +543,6 @@ export class ProfilesUtils { public static async initializeZoweFolder(): Promise { ZoweLogger.trace("ProfilesUtils.initializeZoweFolder called."); - // ensure the Secure Credentials Enabled value is read - // set globals.PROFILE_SECURITY value accordingly - const credentialManagerOverride = ProfilesUtils.getCredentialManagerOverride(); - await globals.setGlobalSecurityValue(credentialManagerOverride ?? globals.ZOWE_CLI_SCM); // Ensure that ~/.zowe folder exists // Ensure that the ~/.zowe/settings/imperative.json exists // TODO: update code below once this imperative issue is resolved. From 1ca3714c621c0c726d08c1edf8cbc4eb1b7ebab8 Mon Sep 17 00:00:00 2001 From: Billie Simmons <49491949+JillieBeanSim@users.noreply.github.com> Date: Wed, 25 Oct 2023 16:38:38 -0400 Subject: [PATCH 169/189] fix code smell Signed-off-by: Billie Simmons <49491949+JillieBeanSim@users.noreply.github.com> --- packages/zowe-explorer/src/extension.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/zowe-explorer/src/extension.ts b/packages/zowe-explorer/src/extension.ts index 167f7658aa..84b995c995 100644 --- a/packages/zowe-explorer/src/extension.ts +++ b/packages/zowe-explorer/src/extension.ts @@ -43,7 +43,7 @@ export async function activate(context: vscode.ExtensionContext): Promise Date: Wed, 25 Oct 2023 17:04:55 -0400 Subject: [PATCH 170/189] issue where imperative override was set back to default fix Signed-off-by: Rudy Flores <68666202+rudyflores@users.noreply.github.com> --- packages/zowe-explorer/src/utils/ProfilesUtils.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/packages/zowe-explorer/src/utils/ProfilesUtils.ts b/packages/zowe-explorer/src/utils/ProfilesUtils.ts index 00ed49c3c8..115afb8d34 100644 --- a/packages/zowe-explorer/src/utils/ProfilesUtils.ts +++ b/packages/zowe-explorer/src/utils/ProfilesUtils.ts @@ -555,6 +555,9 @@ export class ProfilesUtils { if (!fs.existsSync(settingsPath)) { fs.mkdirSync(settingsPath); } + // set global variable of security value to existing override + // this will later get reverted to default in getProfilesInfo.ts if user chooses to + await ProfilesUtils.updateCredentialManagerSetting(ProfilesUtils.getCredentialManagerOverride()); ProfilesUtils.writeOverridesFile(); // If not using team config, ensure that the ~/.zowe/profiles directory // exists with appropriate types within From ea9070e5cf48f863a7f7c1c6d69329e2a714bc81 Mon Sep 17 00:00:00 2001 From: Billie Simmons <49491949+JillieBeanSim@users.noreply.github.com> Date: Thu, 26 Oct 2023 09:36:48 -0400 Subject: [PATCH 171/189] try this Signed-off-by: Billie Simmons <49491949+JillieBeanSim@users.noreply.github.com> --- packages/zowe-explorer/src/utils/ProfilesUtils.ts | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/packages/zowe-explorer/src/utils/ProfilesUtils.ts b/packages/zowe-explorer/src/utils/ProfilesUtils.ts index 115afb8d34..3783c9454c 100644 --- a/packages/zowe-explorer/src/utils/ProfilesUtils.ts +++ b/packages/zowe-explorer/src/utils/ProfilesUtils.ts @@ -555,10 +555,10 @@ export class ProfilesUtils { if (!fs.existsSync(settingsPath)) { fs.mkdirSync(settingsPath); } + ProfilesUtils.writeOverridesFile(); // set global variable of security value to existing override // this will later get reverted to default in getProfilesInfo.ts if user chooses to await ProfilesUtils.updateCredentialManagerSetting(ProfilesUtils.getCredentialManagerOverride()); - ProfilesUtils.writeOverridesFile(); // If not using team config, ensure that the ~/.zowe/profiles directory // exists with appropriate types within if (!imperative.ImperativeConfig.instance.config?.exists) { @@ -595,7 +595,7 @@ export class ProfilesUtils { ZoweLogger.error(errorMsg); ZoweLogger.debug(fileContent.toString()); settings = { ...defaultImperativeJson }; - fs.writeFileSync(settingsFile, JSON.stringify(settings, null, 2), { + return fs.writeFileSync(settingsFile, JSON.stringify(settings, null, 2), { encoding: "utf-8", flag: "w", }); @@ -610,12 +610,11 @@ export class ProfilesUtils { } else { settings = { ...defaultImperativeJson }; } - settings.overrides.CredentialManager = globals.PROFILE_SECURITY; const newData = JSON.stringify(settings, null, 2); ZoweLogger.debug( localize("writeOverridesFile.updateFile", "Updating imperative.json Credential Manager to {0}.\n{1}", globals.PROFILE_SECURITY, newData) ); - fs.writeFileSync(settingsFile, newData, { + return fs.writeFileSync(settingsFile, newData, { encoding: "utf-8", flag: "w", }); From 27468498e25474cc12e544fc89bb619abe3bd797 Mon Sep 17 00:00:00 2001 From: Rudy Flores <68666202+rudyflores@users.noreply.github.com> Date: Thu, 26 Oct 2023 11:56:39 -0400 Subject: [PATCH 172/189] fix broken unit tests Signed-off-by: Rudy Flores <68666202+rudyflores@users.noreply.github.com> --- .../__tests__/__unit__/extension.unit.test.ts | 1 + .../__unit__/utils/ProfilesUtils.unit.test.ts | 10 ++++++---- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/packages/zowe-explorer/__tests__/__unit__/extension.unit.test.ts b/packages/zowe-explorer/__tests__/__unit__/extension.unit.test.ts index b891f9ddc3..5c9bc961a8 100644 --- a/packages/zowe-explorer/__tests__/__unit__/extension.unit.test.ts +++ b/packages/zowe-explorer/__tests__/__unit__/extension.unit.test.ts @@ -453,6 +453,7 @@ describe("Extension Unit Tests", () => { let globalMocks; beforeAll(async () => { globalMocks = await createGlobalMocks(); + jest.spyOn(fs, "readFileSync").mockReturnValue(Buffer.from(JSON.stringify({ overrides: { credentialManager: "@zowe/cli" } }), "utf-8")); Object.defineProperty(zowe.imperative, "ProfileInfo", { value: globalMocks.mockImperativeProfileInfo, configurable: true, diff --git a/packages/zowe-explorer/__tests__/__unit__/utils/ProfilesUtils.unit.test.ts b/packages/zowe-explorer/__tests__/__unit__/utils/ProfilesUtils.unit.test.ts index d431ee721d..ebecd94b89 100644 --- a/packages/zowe-explorer/__tests__/__unit__/utils/ProfilesUtils.unit.test.ts +++ b/packages/zowe-explorer/__tests__/__unit__/utils/ProfilesUtils.unit.test.ts @@ -475,6 +475,7 @@ describe("ProfilesUtils unit tests", () => { const blockMocks = createBlockMocks(); blockMocks.mockGetDirectValue.mockReturnValue(true); blockMocks.mockExistsSync.mockReturnValue(false); + jest.spyOn(fs, "readFileSync").mockReturnValue(Buffer.from(JSON.stringify({ overrides: { credentialManager: "@zowe/cli" } }), "utf-8")); const createFileSpy = jest.spyOn(profUtils.ProfilesUtils, "writeOverridesFile"); await profUtils.ProfilesUtils.initializeZoweFolder(); expect(globals.PROFILE_SECURITY).toBe(globals.ZOWE_CLI_SCM); @@ -487,6 +488,7 @@ describe("ProfilesUtils unit tests", () => { blockMocks.mockGetDirectValue.mockReturnValue("@zowe/cli"); blockMocks.mockExistsSync.mockReturnValue(true); const fileJson = blockMocks.mockFileRead; + jest.spyOn(fs, "readFileSync").mockReturnValue(Buffer.from(JSON.stringify({ overrides: { credentialManager: "@zowe/cli" } }), "utf-8")); blockMocks.mockReadFileSync.mockReturnValueOnce(JSON.stringify(fileJson, null, 2)); await profUtils.ProfilesUtils.initializeZoweFolder(); expect(globals.PROFILE_SECURITY).toBe("@zowe/cli"); @@ -498,11 +500,11 @@ describe("ProfilesUtils unit tests", () => { describe("writeOverridesFile", () => { it("should have file exist", () => { const blockMocks = createBlockMocks(); - const fileJson = { overrides: { CredentialManager: "@zowe/cli", testValue: true } }; - const content = JSON.stringify(fileJson, null, 2); - blockMocks.mockReadFileSync.mockReturnValueOnce(JSON.stringify({ overrides: { CredentialManager: false, testValue: true } }, null, 2)); + blockMocks.mockReadFileSync.mockReturnValueOnce( + JSON.stringify({ overrides: { CredentialManager: "@zowe/cli", testValue: true } }, null, 2) + ); profUtils.ProfilesUtils.writeOverridesFile(); - expect(blockMocks.mockWriteFileSync).toBeCalledWith(blockMocks.zoweDir, content, { encoding: "utf-8", flag: "w" }); + expect(blockMocks.mockWriteFileSync).toBeCalledTimes(0); }); it("should return and have no change to the existing file if PROFILE_SECURITY matches file", () => { From 926e6fe8cc013b3303e2e8f3d8a1769194e5b620 Mon Sep 17 00:00:00 2001 From: Rudy Flores <68666202+rudyflores@users.noreply.github.com> Date: Thu, 26 Oct 2023 12:07:57 -0400 Subject: [PATCH 173/189] add missing code coverage Signed-off-by: Rudy Flores <68666202+rudyflores@users.noreply.github.com> --- .../__unit__/shared/init.unit.test.ts | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/packages/zowe-explorer/__tests__/__unit__/shared/init.unit.test.ts b/packages/zowe-explorer/__tests__/__unit__/shared/init.unit.test.ts index 4322f5faf5..0659a61f09 100644 --- a/packages/zowe-explorer/__tests__/__unit__/shared/init.unit.test.ts +++ b/packages/zowe-explorer/__tests__/__unit__/shared/init.unit.test.ts @@ -377,4 +377,22 @@ describe("Test src/shared/extension", () => { expect(spyExpand).not.toHaveBeenCalled(); }); }); + + describe("registerCredentialManager", () => { + let context: any; + + beforeEach(() => { + context = { subscriptions: [] }; + jest.clearAllMocks(); + }); + afterAll(() => { + jest.restoreAllMocks(); + }); + + it("should register command for updating credentials", () => { + const registerCommandSpy = jest.spyOn(vscode.commands, "registerCommand"); + sharedExtension.registerCredentialManager(context); + expect(registerCommandSpy).toBeCalledWith("zowe.updateSecureCredentials", expect.any(Function)); + }); + }); }); From 9608789b0d75ceb85543f6e7c110509821e337e2 Mon Sep 17 00:00:00 2001 From: Rudy Flores <68666202+rudyflores@users.noreply.github.com> Date: Thu, 26 Oct 2023 15:17:26 -0400 Subject: [PATCH 174/189] fix odd string issue Signed-off-by: Rudy Flores <68666202+rudyflores@users.noreply.github.com> --- .../i18n/sample/src/utils/ProfilesUtils.i18n.json | 6 +++--- packages/zowe-explorer/src/utils/ProfilesUtils.ts | 9 ++++----- 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/packages/zowe-explorer/i18n/sample/src/utils/ProfilesUtils.i18n.json b/packages/zowe-explorer/i18n/sample/src/utils/ProfilesUtils.i18n.json index a895fcdba1..f09de76f70 100644 --- a/packages/zowe-explorer/i18n/sample/src/utils/ProfilesUtils.i18n.json +++ b/packages/zowe-explorer/i18n/sample/src/utils/ProfilesUtils.i18n.json @@ -12,11 +12,11 @@ "ProfilesUtils.fetchRegisteredPlugins.message": "Do you wish to use this credential manager instead?", "ProfilesUtils.fetchRegisteredPlugins.yes": "Yes", "ProfilesUtils.fetchRegisteredPlugins.dontAskAgain": "Don't ask again", - "ProfilesUtils.promptAndHandleMissingCredentialManager.suggestInstallHeader": "Plugin of name \"{0}\" was defined for custom credential management on imperative.json file.", - "ProfilesUtils.promptAndHandleMissingCredentialManager.suggestInstallMessage": "Please install associated VS Code extension for\n custom credential manager or revert to default.", + "ProfilesUtils.promptAndHandleMissingCredentialManager.suggestInstallHeader": "Plugin of name '{0}' was defined for custom credential management on imperative.json file.", + "ProfilesUtils.promptAndHandleMissingCredentialManager.suggestInstallMessage": "Please install associated VS Code extension for custom credential manager or revert to default.", "ProfilesUtils.promptAndHandleMissingCredentialManager.revertToDefault": "Use Default", "ProfilesUtils.promptAndHandleMissingCredentialManager.install": "Install", - "ProfilesUtils.promptAndHandleMissingCredentialManager.refreshMessage": "After installing the extension, please make sure to reload\n your VS Code window in order to start using the installed credential manager", + "ProfilesUtils.promptAndHandleMissingCredentialManager.refreshMessage": "After installing the extension, please make sure to reload your VS Code window in order\n to start using the installed credential manager", "ProfilesUtils.promptAndHandleMissingCredentialManager.refreshButton": "Refresh", "zowe.promptCredentials.notSupported": "\"Update Credentials\" operation not supported when \"autoStore\" is false", "createNewConnection.option.prompt.profileName.placeholder": "Connection Name", diff --git a/packages/zowe-explorer/src/utils/ProfilesUtils.ts b/packages/zowe-explorer/src/utils/ProfilesUtils.ts index 3783c9454c..65564f2064 100644 --- a/packages/zowe-explorer/src/utils/ProfilesUtils.ts +++ b/packages/zowe-explorer/src/utils/ProfilesUtils.ts @@ -390,13 +390,12 @@ export class ProfilesUtils { ZoweLogger.trace("ProfilesUtils.promptAndHandleMissingCredentialManager called."); const header = localize( "ProfilesUtils.promptAndHandleMissingCredentialManager.suggestInstallHeader", - `Plugin of name "{0}" was defined for custom credential management on imperative.json file.`, + "Plugin of name '{0}' was defined for custom credential management on imperative.json file.", credentialManager.credMgrDisplayName ); const installMessage = localize( "ProfilesUtils.promptAndHandleMissingCredentialManager.suggestInstallMessage", - `Please install associated VS Code extension for - custom credential manager or revert to default.` + "Please install associated VS Code extension for custom credential manager or revert to default." ); const revertToDefaultButton = localize("ProfilesUtils.promptAndHandleMissingCredentialManager.revertToDefault", "Use Default"); const installButton = localize("ProfilesUtils.promptAndHandleMissingCredentialManager.install", "Install"); @@ -409,8 +408,8 @@ export class ProfilesUtils { if (await vscode.env.openExternal(credentialManagerInstallURL)) { const refreshMessage = localize( "ProfilesUtils.promptAndHandleMissingCredentialManager.refreshMessage", - `After installing the extension, please make sure to reload - your VS Code window in order to start using the installed credential manager` + `After installing the extension, please make sure to reload your VS Code window in order + to start using the installed credential manager` ); const refreshButton = localize("ProfilesUtils.promptAndHandleMissingCredentialManager.refreshButton", "Refresh"); if ((await Gui.showMessage(refreshMessage, { items: [refreshButton] })) === refreshButton) { From 30dceaafa72a88594f643e55149bbe84caf95d27 Mon Sep 17 00:00:00 2001 From: Rudy Flores <68666202+rudyflores@users.noreply.github.com> Date: Thu, 26 Oct 2023 15:45:40 -0400 Subject: [PATCH 175/189] change refresh to reload Signed-off-by: Rudy Flores <68666202+rudyflores@users.noreply.github.com> --- .../i18n/sample/src/utils/ProfilesUtils.i18n.json | 2 +- packages/zowe-explorer/src/utils/ProfilesUtils.ts | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/zowe-explorer/i18n/sample/src/utils/ProfilesUtils.i18n.json b/packages/zowe-explorer/i18n/sample/src/utils/ProfilesUtils.i18n.json index f09de76f70..b21b95cfa8 100644 --- a/packages/zowe-explorer/i18n/sample/src/utils/ProfilesUtils.i18n.json +++ b/packages/zowe-explorer/i18n/sample/src/utils/ProfilesUtils.i18n.json @@ -17,7 +17,7 @@ "ProfilesUtils.promptAndHandleMissingCredentialManager.revertToDefault": "Use Default", "ProfilesUtils.promptAndHandleMissingCredentialManager.install": "Install", "ProfilesUtils.promptAndHandleMissingCredentialManager.refreshMessage": "After installing the extension, please make sure to reload your VS Code window in order\n to start using the installed credential manager", - "ProfilesUtils.promptAndHandleMissingCredentialManager.refreshButton": "Refresh", + "ProfilesUtils.promptAndHandleMissingCredentialManager.refreshButton": "Reload", "zowe.promptCredentials.notSupported": "\"Update Credentials\" operation not supported when \"autoStore\" is false", "createNewConnection.option.prompt.profileName.placeholder": "Connection Name", "createNewConnection.option.prompt.profileName": "Enter a name for the connection.", diff --git a/packages/zowe-explorer/src/utils/ProfilesUtils.ts b/packages/zowe-explorer/src/utils/ProfilesUtils.ts index 65564f2064..9d5418d4e9 100644 --- a/packages/zowe-explorer/src/utils/ProfilesUtils.ts +++ b/packages/zowe-explorer/src/utils/ProfilesUtils.ts @@ -411,8 +411,8 @@ export class ProfilesUtils { `After installing the extension, please make sure to reload your VS Code window in order to start using the installed credential manager` ); - const refreshButton = localize("ProfilesUtils.promptAndHandleMissingCredentialManager.refreshButton", "Refresh"); - if ((await Gui.showMessage(refreshMessage, { items: [refreshButton] })) === refreshButton) { + const reloadButton = localize("ProfilesUtils.promptAndHandleMissingCredentialManager.refreshButton", "Reload"); + if ((await Gui.showMessage(refreshMessage, { items: [reloadButton] })) === reloadButton) { await vscode.commands.executeCommand("workbench.action.reloadWindow"); } } From 23cb591fd78ca3de062a5e06a0d86ca0dd95e740 Mon Sep 17 00:00:00 2001 From: Rudy Flores <68666202+rudyflores@users.noreply.github.com> Date: Thu, 26 Oct 2023 15:54:23 -0400 Subject: [PATCH 176/189] fix broken test Signed-off-by: Rudy Flores <68666202+rudyflores@users.noreply.github.com> --- .../__tests__/__unit__/utils/ProfilesUtils.unit.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/zowe-explorer/__tests__/__unit__/utils/ProfilesUtils.unit.test.ts b/packages/zowe-explorer/__tests__/__unit__/utils/ProfilesUtils.unit.test.ts index ebecd94b89..a0a75e8549 100644 --- a/packages/zowe-explorer/__tests__/__unit__/utils/ProfilesUtils.unit.test.ts +++ b/packages/zowe-explorer/__tests__/__unit__/utils/ProfilesUtils.unit.test.ts @@ -897,7 +897,7 @@ describe("ProfilesUtils unit tests", () => { value: () => true, configurable: true, }); - jest.spyOn(Gui, "showMessage").mockResolvedValue("Refresh"); + jest.spyOn(Gui, "showMessage").mockResolvedValue("Reload"); await expect( profUtils.ProfilesUtils["promptAndHandleMissingCredentialManager"]({ From 5042058ceadb478b23079365ddfda6b1174c1407 Mon Sep 17 00:00:00 2001 From: Billie Simmons <49491949+JillieBeanSim@users.noreply.github.com> Date: Fri, 27 Oct 2023 09:04:52 -0400 Subject: [PATCH 177/189] update lerna, clean changelogs Signed-off-by: Billie Simmons <49491949+JillieBeanSim@users.noreply.github.com> --- lerna.json | 2 +- .../eslint-plugin-zowe-explorer/CHANGELOG.md | 40 ------------------- packages/zowe-explorer-api/CHANGELOG.md | 6 +-- .../zowe-explorer-ftp-extension/CHANGELOG.md | 2 - packages/zowe-explorer/CHANGELOG.md | 8 ++-- 5 files changed, 7 insertions(+), 51 deletions(-) diff --git a/lerna.json b/lerna.json index c6e4b4889b..37d602990f 100644 --- a/lerna.json +++ b/lerna.json @@ -1,5 +1,5 @@ { - "version": "2.12.0-SNAPSHOT", + "version": "2.12.0", "command": { "version": { "forcePublish": true, diff --git a/packages/eslint-plugin-zowe-explorer/CHANGELOG.md b/packages/eslint-plugin-zowe-explorer/CHANGELOG.md index 43da47da30..7fb64f5e17 100644 --- a/packages/eslint-plugin-zowe-explorer/CHANGELOG.md +++ b/packages/eslint-plugin-zowe-explorer/CHANGELOG.md @@ -2,56 +2,22 @@ All notable changes to the "eslint-plugin-zowe-explorer" package will be documen ## TBD Release -### New features and enhancements - -### Bug fixes - ## `2.11.2` -### New features and enhancements - -### Bug fixes - ## `2.11.1` -### New features and enhancements - -### Bug fixes - ## `2.11.0` -### New features and enhancements - -### Bug fixes - ## `2.10.0` -### New features and enhancements - -### Bug fixes - ## `2.9.2` -### New features and enhancements - -### Bug fixes - ## `2.9.1` -### New features and enhancements - -### Bug fixes - ## `2.9.0` -### New features and enhancements - -### Bug fixes - ## `2.8.1` -### New features and enhancements - ### Bug fixes - Added `no-floating-promises` rule that ignores floating thenables without a `.catch` method. [#2291](https://github.com/zowe/vscode-extension-for-zowe/issues/2291) @@ -62,14 +28,8 @@ All notable changes to the "eslint-plugin-zowe-explorer" package will be documen - Updated linter rules and addressed linter errors throughout the codebase. [#2184](https://github.com/zowe/vscode-extension-for-zowe/issues/2184) -### Bug fixes - ## `2.7.0` -### New features and enhancements - -### Bug fixes - ## `2.6.0` ### New features and enhancements diff --git a/packages/zowe-explorer-api/CHANGELOG.md b/packages/zowe-explorer-api/CHANGELOG.md index 55a7c5ba0d..7b6164f5f2 100644 --- a/packages/zowe-explorer-api/CHANGELOG.md +++ b/packages/zowe-explorer-api/CHANGELOG.md @@ -9,11 +9,9 @@ All notable changes to the "zowe-explorer-api" extension will be documented in t - Added optional `getTag` function to `ZoweExplorerAPI.IUss` for getting the tag of a file on USS. - Added new API {ZE Extender MetaData} to allow extenders to have the metadata of registered extenders to aid in team configuration file creation from a view that isn't Zowe Explorer's. [#2394](https://github.com/zowe/vscode-extension-for-zowe/issues/2394) - Add `sort` and `filter` optional variables for storing sort/filter options alongside tree nodes. [#2420](https://github.com/zowe/vscode-extension-for-zowe/issues/2420) -- Add `stats` optional variable for storing dataset stats (such as user, modified date, etc.) +- Add `stats` optional variable for storing dataset stats (such as user, modified date, etc.). - Add option enums and types for sorting, filtering and sort direction in tree nodes. [#2420](https://github.com/zowe/vscode-extension-for-zowe/issues/2420) -- Added option for retaining context when generating webviews in Webview API - -### Bug fixes +- Added option for retaining context when generating webviews in Webview API. ## `2.11.2` diff --git a/packages/zowe-explorer-ftp-extension/CHANGELOG.md b/packages/zowe-explorer-ftp-extension/CHANGELOG.md index 1d58ca0e0c..934bfea0c3 100644 --- a/packages/zowe-explorer-ftp-extension/CHANGELOG.md +++ b/packages/zowe-explorer-ftp-extension/CHANGELOG.md @@ -2,8 +2,6 @@ All notable changes to the "zowe-explorer-ftp-extension" extension will be docum ## TBD Release -### New features and enhancements - ### Bug fixes - Fixed ECONNRESET error when trying to upload or create an empty data set member. [#2350](https://github.com/zowe/vscode-extension-for-zowe/issues/2350) diff --git a/packages/zowe-explorer/CHANGELOG.md b/packages/zowe-explorer/CHANGELOG.md index 092edb0a19..c718756d9e 100644 --- a/packages/zowe-explorer/CHANGELOG.md +++ b/packages/zowe-explorer/CHANGELOG.md @@ -8,20 +8,20 @@ All notable changes to the "vscode-extension-for-zowe" extension will be documen - Added "Sort Jobs" feature in Jobs tree view: accessible via sort icon or right-clicking on session node. [#2257](https://github.com/zowe/vscode-extension-for-zowe/issues/2257) - Introduce a new user interface for managing profiles via right-click action "Manage Profile". -- Added new edit feature on `Edit Attributes` view for changing file tags on USS [#2113](https://github.com/zowe/vscode-extension-for-zowe/issues/2113) +- Added new edit feature on `Edit Attributes` view for changing file tags on USS. [#2113](https://github.com/zowe/vscode-extension-for-zowe/issues/2113) - Added new API {ZE Extender MetaData} to allow extenders to have the metadata of registered extenders to aid in team configuration file creation from a view that isn't Zowe Explorer's. [#2394](https://github.com/zowe/vscode-extension-for-zowe/issues/2394) -- Added ability to install extension from VS Code marketplace if custom credential manager extension is missing after defining it on `imperative.json` [#2381](https://github.com/zowe/vscode-extension-for-zowe/issues/2381) +- Added ability to install extension from VS Code marketplace if custom credential manager extension is missing after defining it on `imperative.json`. [#2381](https://github.com/zowe/vscode-extension-for-zowe/issues/2381) - Added new right-click action for `Submit as JCL` for local files in the VS Code file explorer as well as files opened in the VS Code text editor. [#2475](https://github.com/zowe/vscode-extension-for-zowe/issues/2475) - Added "Sort PDS members" feature in Data Sets tree view: accessible via sort icon on session node, or by right-clicking a PDS or session. [#2420](https://github.com/zowe/vscode-extension-for-zowe/issues/2420) - Added "Filter PDS members" feature in Data Sets tree view: accessible via filter icon on session node, or by right-clicking a PDS or session. [#2420](https://github.com/zowe/vscode-extension-for-zowe/issues/2420) - Added descriptions to data set nodes if filtering and/or sorting is enabled (where applicable). -- Added webview for editing persistent items on Zowe Explorer [#2488](https://github.com/zowe/vscode-extension-for-zowe/issues/2488) +- Added webview for editing persistent items on Zowe Explorer. [#2488](https://github.com/zowe/vscode-extension-for-zowe/issues/2488) ### Bug fixes - Fixed submitting local JCL using command pallet option `Zowe Explorer: Submit as JCL` by adding a check for chosen profile returned to continue the action. [#1625](https://github.com/zowe/vscode-extension-for-zowe/issues/1625) - Fixed conflict resolution being skipped if local and remote file have different contents but are the same size. [#2496](https://github.com/zowe/vscode-extension-for-zowe/issues/2496) -- Fixed issue with token based auth for unsecure profiles in Zowe Explorer [#2518](https://github.com/zowe/vscode-extension-for-zowe/issues/2518) +- Fixed issue with token based auth for unsecure profiles in Zowe Explorer. [#2518](https://github.com/zowe/vscode-extension-for-zowe/issues/2518) ## `2.11.2` From 539cbf2170594299758a54b6ffd843a9f703c8d7 Mon Sep 17 00:00:00 2001 From: Billie Simmons <49491949+JillieBeanSim@users.noreply.github.com> Date: Mon, 30 Oct 2023 13:25:46 -0400 Subject: [PATCH 178/189] update CHANGELOGs Signed-off-by: Billie Simmons <49491949+JillieBeanSim@users.noreply.github.com> --- packages/zowe-explorer-api/CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/zowe-explorer-api/CHANGELOG.md b/packages/zowe-explorer-api/CHANGELOG.md index 7b6164f5f2..2f9c9cd953 100644 --- a/packages/zowe-explorer-api/CHANGELOG.md +++ b/packages/zowe-explorer-api/CHANGELOG.md @@ -7,7 +7,7 @@ All notable changes to the "zowe-explorer-api" extension will be documented in t ### New features and enhancements - Added optional `getTag` function to `ZoweExplorerAPI.IUss` for getting the tag of a file on USS. -- Added new API {ZE Extender MetaData} to allow extenders to have the metadata of registered extenders to aid in team configuration file creation from a view that isn't Zowe Explorer's. [#2394](https://github.com/zowe/vscode-extension-for-zowe/issues/2394) +- Added new ProfilesCache API `getConfigArray` to allow extenders to get the registered profile type's metadata for team configuration file creation handled outside of Zowe Explorer views. [#2394](https://github.com/zowe/vscode-extension-for-zowe/issues/2394) - Add `sort` and `filter` optional variables for storing sort/filter options alongside tree nodes. [#2420](https://github.com/zowe/vscode-extension-for-zowe/issues/2420) - Add `stats` optional variable for storing dataset stats (such as user, modified date, etc.). - Add option enums and types for sorting, filtering and sort direction in tree nodes. [#2420](https://github.com/zowe/vscode-extension-for-zowe/issues/2420) From 548a8df61c4a8befcb066324ba175fa6b6284e2c Mon Sep 17 00:00:00 2001 From: Rudy Flores <68666202+rudyflores@users.noreply.github.com> Date: Mon, 30 Oct 2023 18:07:57 -0400 Subject: [PATCH 179/189] move to new PR against main Signed-off-by: Rudy Flores <68666202+rudyflores@users.noreply.github.com> --- .../__unit__/utils/ProfilesUtils.unit.test.ts | 18 +++++++++++++ .../zowe-explorer/src/utils/ProfilesUtils.ts | 26 ++++++++++++------- 2 files changed, 35 insertions(+), 9 deletions(-) diff --git a/packages/zowe-explorer/__tests__/__unit__/utils/ProfilesUtils.unit.test.ts b/packages/zowe-explorer/__tests__/__unit__/utils/ProfilesUtils.unit.test.ts index a0a75e8549..6bd720ab07 100644 --- a/packages/zowe-explorer/__tests__/__unit__/utils/ProfilesUtils.unit.test.ts +++ b/packages/zowe-explorer/__tests__/__unit__/utils/ProfilesUtils.unit.test.ts @@ -485,6 +485,7 @@ describe("ProfilesUtils unit tests", () => { it("should skip creating directories and files that already exist", async () => { const blockMocks = createBlockMocks(); + jest.spyOn(profUtils.ProfilesUtils, "getCredentialManagerOverride").mockReturnValue("@zowe/cli"); blockMocks.mockGetDirectValue.mockReturnValue("@zowe/cli"); blockMocks.mockExistsSync.mockReturnValue(true); const fileJson = blockMocks.mockFileRead; @@ -777,6 +778,23 @@ describe("ProfilesUtils unit tests", () => { expect(profUtils.ProfilesUtils.getCredentialManagerOverride()).toBe("My Custom Credential Manager"); expect(zoweLoggerTraceSpy).toBeCalledTimes(1); }); + + it("should return default manager if the override file does not exist", () => { + const zoweLoggerTraceSpy = jest.spyOn(ZoweLogger, "trace"); + const zoweLoggerInfoSpy = jest.spyOn(ZoweLogger, "info"); + + jest.spyOn(fs, "readFileSync").mockImplementation(() => { + throw new Error("test"); + }); + try { + profUtils.ProfilesUtils.getCredentialManagerOverride(); + } catch (err) { + expect(err).toBe("test"); + } + + expect(zoweLoggerTraceSpy).toBeCalledTimes(1); + expect(zoweLoggerInfoSpy).toBeCalledTimes(1); + }); }); describe("setupCustomCredentialManager", () => { diff --git a/packages/zowe-explorer/src/utils/ProfilesUtils.ts b/packages/zowe-explorer/src/utils/ProfilesUtils.ts index 9d5418d4e9..d5557c7e14 100644 --- a/packages/zowe-explorer/src/utils/ProfilesUtils.ts +++ b/packages/zowe-explorer/src/utils/ProfilesUtils.ts @@ -233,13 +233,19 @@ export class ProfilesUtils { */ public static getCredentialManagerOverride(): string { ZoweLogger.trace("ProfilesUtils.getCredentialManagerOverride called."); - const settingsFile = path.join(getZoweDir(), "settings", "imperative.json"); - const imperativeConfig = JSON.parse(fs.readFileSync(settingsFile).toString()); - const credentialManagerOverride = imperativeConfig?.overrides[imperative.CredentialManagerOverride.CRED_MGR_SETTING_NAME]; - if (typeof credentialManagerOverride === "string") { - return credentialManagerOverride; + try { + const settingsFilePath = path.join(getZoweDir(), "settings", "imperative.json"); + const settingsFile = fs.readFileSync(settingsFilePath); + const imperativeConfig = JSON.parse(settingsFile.toString()); + const credentialManagerOverride = imperativeConfig?.overrides[imperative.CredentialManagerOverride.CRED_MGR_SETTING_NAME]; + if (typeof credentialManagerOverride === "string") { + return credentialManagerOverride; + } + return imperative.CredentialManagerOverride.DEFAULT_CRED_MGR_NAME; + } catch (err) { + ZoweLogger.info("imperative.json does not exist, returning the default override of @zowe/cli"); + return imperative.CredentialManagerOverride.DEFAULT_CRED_MGR_NAME; } - return imperative.CredentialManagerOverride.DEFAULT_CRED_MGR_NAME; } /** @@ -542,6 +548,10 @@ export class ProfilesUtils { public static async initializeZoweFolder(): Promise { ZoweLogger.trace("ProfilesUtils.initializeZoweFolder called."); + // ensure the Secure Credentials Enabled value is read + // set globals.PROFILE_SECURITY value accordingly + const credentialManagerMap = ProfilesUtils.getCredentialManagerOverride(); + await globals.setGlobalSecurityValue(credentialManagerMap ?? globals.ZOWE_CLI_SCM); // Ensure that ~/.zowe folder exists // Ensure that the ~/.zowe/settings/imperative.json exists // TODO: update code below once this imperative issue is resolved. @@ -555,9 +565,6 @@ export class ProfilesUtils { fs.mkdirSync(settingsPath); } ProfilesUtils.writeOverridesFile(); - // set global variable of security value to existing override - // this will later get reverted to default in getProfilesInfo.ts if user chooses to - await ProfilesUtils.updateCredentialManagerSetting(ProfilesUtils.getCredentialManagerOverride()); // If not using team config, ensure that the ~/.zowe/profiles directory // exists with appropriate types within if (!imperative.ImperativeConfig.instance.config?.exists) { @@ -609,6 +616,7 @@ export class ProfilesUtils { } else { settings = { ...defaultImperativeJson }; } + settings.overrides.CredentialManager = globals.PROFILE_SECURITY; const newData = JSON.stringify(settings, null, 2); ZoweLogger.debug( localize("writeOverridesFile.updateFile", "Updating imperative.json Credential Manager to {0}.\n{1}", globals.PROFILE_SECURITY, newData) From ab7284cc8be063e87028d10acd3e19240c0f22a8 Mon Sep 17 00:00:00 2001 From: Trae Yelovich Date: Tue, 31 Oct 2023 09:33:37 -0400 Subject: [PATCH 180/189] fix(ds/sort): Fallback to sorting by name when values are equal Signed-off-by: Trae Yelovich --- .../__unit__/dataset/DatasetTree.unit.test.ts | 30 +++++++++++++- .../src/dataset/ZoweDatasetNode.ts | 40 +++++++++++++------ 2 files changed, 57 insertions(+), 13 deletions(-) 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 698fb29f2d..55d8ebf0c4 100644 --- a/packages/zowe-explorer/__tests__/__unit__/dataset/DatasetTree.unit.test.ts +++ b/packages/zowe-explorer/__tests__/__unit__/dataset/DatasetTree.unit.test.ts @@ -15,7 +15,15 @@ import * as fs from "fs"; import * as zowe from "@zowe/cli"; import { DatasetTree } from "../../../src/dataset/DatasetTree"; import { ZoweDatasetNode } from "../../../src/dataset/ZoweDatasetNode"; -import { DatasetFilterOpts, Gui, IZoweDatasetTreeNode, ProfilesCache, ValidProfileEnum } from "@zowe/zowe-explorer-api"; +import { + DatasetFilterOpts, + DatasetSortOpts, + Gui, + IZoweDatasetTreeNode, + ProfilesCache, + SortDirection, + ValidProfileEnum, +} from "@zowe/zowe-explorer-api"; import { ZoweExplorerApiRegister } from "../../../src/ZoweExplorerApiRegister"; import { Profiles } from "../../../src/Profiles"; import * as utils from "../../../src/utils/ProfilesUtils"; @@ -2716,6 +2724,10 @@ describe("Dataset Tree Unit Tests - Sorting and Filtering operations", () => { const nodeC = new ZoweDatasetNode("C", vscode.TreeItemCollapsibleState.Collapsed, pds, createISession()); nodeC.stats = { user: "someUser", modifiedDate: new Date("2022-03-15T16:30:00") }; pds.children = [nodeA, nodeB, nodeC]; + pds.sort = { + method: DatasetSortOpts.Name, + direction: SortDirection.Ascending, + }; session.children = [pds]; return { @@ -2785,6 +2797,22 @@ describe("Dataset Tree Unit Tests - Sorting and Filtering operations", () => { expect(nodes.pds.children?.map((c: IZoweDatasetTreeNode) => c.label)).toStrictEqual(["B", "C", "A"]); }); + it("sorts by last modified date: handling 2 nodes with same date", async () => { + const mocks = getBlockMocks(); + const nodes = nodesForSuite(); + mocks.showQuickPick.mockResolvedValueOnce({ label: "$(fold) Sort Direction" }); + mocks.showQuickPick.mockResolvedValueOnce({ label: "Descending" }); + mocks.showQuickPick.mockResolvedValueOnce({ label: "$(calendar) Date Modified" }); + // insert node with same date modified + const nodeD = new ZoweDatasetNode("D", vscode.TreeItemCollapsibleState.Collapsed, nodes.pds, createISession()); + nodeD.stats = { user: "someUser", modifiedDate: new Date("2022-03-15T16:30:00") }; + nodes.pds.children = [...(nodes.pds.children ?? []), nodeD]; + await tree.sortPdsMembersDialog(nodes.pds); + expect(mocks.nodeDataChanged).toHaveBeenCalled(); + expect(mocks.refreshElement).not.toHaveBeenCalled(); + expect(nodes.pds.children?.map((c: IZoweDatasetTreeNode) => c.label)).toStrictEqual(["A", "D", "C", "B"]); + }); + it("sorts by user ID", async () => { const mocks = getBlockMocks(); const nodes = nodesForSuite(); diff --git a/packages/zowe-explorer/src/dataset/ZoweDatasetNode.ts b/packages/zowe-explorer/src/dataset/ZoweDatasetNode.ts index f46de2ba3e..845039b713 100644 --- a/packages/zowe-explorer/src/dataset/ZoweDatasetNode.ts +++ b/packages/zowe-explorer/src/dataset/ZoweDatasetNode.ts @@ -332,22 +332,38 @@ export class ZoweDatasetNode extends ZoweTreeNode implements IZoweDatasetTreeNod const sortLessThan = sort.direction == SortDirection.Ascending ? -1 : 1; const sortGreaterThan = sortLessThan * -1; + const sortByName = (nodeA: IZoweDatasetTreeNode, nodeB: IZoweDatasetTreeNode): number => + (nodeA.label as string) < (nodeB.label as string) ? sortLessThan : sortGreaterThan; + if (!a.stats && !b.stats) { - return (a.label as string) < (b.label as string) ? sortLessThan : sortGreaterThan; + return sortByName(a, b); } - switch (sort.method) { - case DatasetSortOpts.LastModified: - a.description = dayjs(a.stats?.modifiedDate).format("YYYY/MM/DD HH:mm:ss"); - b.description = dayjs(b.stats?.modifiedDate).format("YYYY/MM/DD HH:mm:ss"); - return a.stats?.modifiedDate < b.stats?.modifiedDate ? sortLessThan : sortGreaterThan; - case DatasetSortOpts.UserId: - a.description = a.stats?.user; - b.description = b.stats?.user; - return a.stats?.user < b.stats?.user ? sortLessThan : sortGreaterThan; - case DatasetSortOpts.Name: - return (a.label as string) < (b.label as string) ? sortLessThan : sortGreaterThan; + if (sort.method === DatasetSortOpts.LastModified) { + const dateA = dayjs(a.stats?.modifiedDate); + const dateB = dayjs(b.stats?.modifiedDate); + + a.description = dateA.format("YYYY/MM/DD HH:mm:ss"); + b.description = dateB.format("YYYY/MM/DD HH:mm:ss"); + + // for dates that are equal down to the second, fallback to sorting by name + if (dateA.isSame(dateB, "second")) { + return sortByName(a, b); + } + + return dateA.isBefore(dateB, "second") ? sortLessThan : sortGreaterThan; + } else if (sort.method === DatasetSortOpts.UserId) { + a.description = a.stats?.user; + b.description = b.stats?.user; + + if (a.stats?.user === b.stats?.user) { + return sortByName(a, b); + } + + return a.stats?.user < b.stats?.user ? sortLessThan : sortGreaterThan; } + + return sortByName(a, b); }; } From db09e31878238f283bafd3a75cdf00910694c67c Mon Sep 17 00:00:00 2001 From: Trae Yelovich Date: Tue, 31 Oct 2023 10:13:47 -0400 Subject: [PATCH 181/189] fix(ds/sort): Remove node description if date from API is invalid (unlikely, but possible) Signed-off-by: Trae Yelovich --- packages/zowe-explorer/src/dataset/ZoweDatasetNode.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/zowe-explorer/src/dataset/ZoweDatasetNode.ts b/packages/zowe-explorer/src/dataset/ZoweDatasetNode.ts index 845039b713..bb758876a6 100644 --- a/packages/zowe-explorer/src/dataset/ZoweDatasetNode.ts +++ b/packages/zowe-explorer/src/dataset/ZoweDatasetNode.ts @@ -343,8 +343,8 @@ export class ZoweDatasetNode extends ZoweTreeNode implements IZoweDatasetTreeNod const dateA = dayjs(a.stats?.modifiedDate); const dateB = dayjs(b.stats?.modifiedDate); - a.description = dateA.format("YYYY/MM/DD HH:mm:ss"); - b.description = dateB.format("YYYY/MM/DD HH:mm:ss"); + a.description = dateA.isValid() ? dateA.format("YYYY/MM/DD HH:mm:ss") : undefined; + b.description = dateB.isValid() ? dateB.format("YYYY/MM/DD HH:mm:ss") : undefined; // for dates that are equal down to the second, fallback to sorting by name if (dateA.isSame(dateB, "second")) { From bc94caf0705c313460d3bb6dc638cb3e1402435b Mon Sep 17 00:00:00 2001 From: Trae Yelovich Date: Tue, 31 Oct 2023 10:31:34 -0400 Subject: [PATCH 182/189] fix(ds/sort): update stats on existing nodes Signed-off-by: Trae Yelovich --- .../src/dataset/ZoweDatasetNode.ts | 31 +++++++++++-------- 1 file changed, 18 insertions(+), 13 deletions(-) diff --git a/packages/zowe-explorer/src/dataset/ZoweDatasetNode.ts b/packages/zowe-explorer/src/dataset/ZoweDatasetNode.ts index bb758876a6..cb9e4d6085 100644 --- a/packages/zowe-explorer/src/dataset/ZoweDatasetNode.ts +++ b/packages/zowe-explorer/src/dataset/ZoweDatasetNode.ts @@ -155,6 +155,22 @@ export class ZoweDatasetNode extends ZoweTreeNode implements IZoweDatasetTreeNod return; } + const updateStats = (node: IZoweDatasetTreeNode, item: any): void => { + if ("m4date" in item) { + const { m4date, mtime, msec }: { m4date: string; mtime: string; msec: string } = item; + node.stats = { + user: item.user, + modifiedDate: dayjs(`${m4date} ${mtime}:${msec}`).toDate(), + }; + } else if ("id" in item || "changed" in item) { + // missing keys from API response; check for FTP keys + node.stats = { + user: item.id, + modifiedDate: item.changed ? dayjs(item.changed).toDate() : undefined, + }; + } + }; + // push nodes to an object with property names to avoid duplicates const elementChildren: { [k: string]: ZoweDatasetNode } = {}; for (const response of responses) { @@ -169,6 +185,7 @@ export class ZoweDatasetNode extends ZoweTreeNode implements IZoweDatasetTreeNod for (const item of response.apiResponse.items ?? response.apiResponse) { const existing = this.children.find((element) => element.label.toString() === item.dsname); if (existing) { + updateStats(existing, item); elementChildren[existing.label.toString()] = existing; // Creates a ZoweDatasetNode for a PDS } else if (item.dsorg === "PO" || item.dsorg === "PO-E") { @@ -262,19 +279,7 @@ export class ZoweDatasetNode extends ZoweTreeNode implements IZoweDatasetTreeNod } // get user and last modified date for sorting, if available - if ("m4date" in item) { - const { m4date, mtime, msec }: { m4date: string; mtime: string; msec: string } = item; - temp.stats = { - user: item.user, - modifiedDate: dayjs(`${m4date} ${mtime}:${msec}`).toDate(), - }; - } else if ("id" in item || "changed" in item) { - // missing keys from API response; check for FTP keys - temp.stats = { - user: item.id, - modifiedDate: item.changed ? dayjs(item.changed).toDate() : undefined, - }; - } + updateStats(temp, item); elementChildren[temp.label.toString()] = temp; } } From 9235f28b8bff80ad1d6816c881c1f7d2385888cc Mon Sep 17 00:00:00 2001 From: Trae Yelovich Date: Tue, 31 Oct 2023 11:16:28 -0400 Subject: [PATCH 183/189] fix(ds/sort): Handle single nodes with empty user ID Signed-off-by: Trae Yelovich --- packages/zowe-explorer/src/dataset/ZoweDatasetNode.ts | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/packages/zowe-explorer/src/dataset/ZoweDatasetNode.ts b/packages/zowe-explorer/src/dataset/ZoweDatasetNode.ts index cb9e4d6085..8497910964 100644 --- a/packages/zowe-explorer/src/dataset/ZoweDatasetNode.ts +++ b/packages/zowe-explorer/src/dataset/ZoweDatasetNode.ts @@ -358,14 +358,17 @@ export class ZoweDatasetNode extends ZoweTreeNode implements IZoweDatasetTreeNod return dateA.isBefore(dateB, "second") ? sortLessThan : sortGreaterThan; } else if (sort.method === DatasetSortOpts.UserId) { - a.description = a.stats?.user; - b.description = b.stats?.user; + const userA = a.stats?.user ?? ""; + const userB = b.stats?.user ?? ""; - if (a.stats?.user === b.stats?.user) { + a.description = userA; + b.description = userB; + + if (userA === userB) { return sortByName(a, b); } - return a.stats?.user < b.stats?.user ? sortLessThan : sortGreaterThan; + return userA < userB ? sortLessThan : sortGreaterThan; } return sortByName(a, b); From 19f031cc45605eb41d25e29b06a00a240347831a Mon Sep 17 00:00:00 2001 From: Trae Yelovich Date: Tue, 31 Oct 2023 12:16:17 -0400 Subject: [PATCH 184/189] test(sort): Add patch coverage for updateStats fn Signed-off-by: Trae Yelovich --- .../__unit__/dataset/DatasetTree.unit.test.ts | 37 +++++++++++++++++++ .../src/dataset/ZoweDatasetNode.ts | 36 +++++++++--------- 2 files changed, 55 insertions(+), 18 deletions(-) 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 55d8ebf0c4..d4f853238b 100644 --- a/packages/zowe-explorer/__tests__/__unit__/dataset/DatasetTree.unit.test.ts +++ b/packages/zowe-explorer/__tests__/__unit__/dataset/DatasetTree.unit.test.ts @@ -1769,6 +1769,43 @@ describe("Dataset Tree Unit Tests - Function datasetFilterPrompt", () => { expect(await testTree.datasetFilterPrompt(testTree.mSessionNodes[1])).not.toBeDefined(); }); + + it("updates stats with modified date and user ID if provided in API", async () => { + const globalMocks = createGlobalMocks(); + const blockMocks = await createBlockMocks(globalMocks); + + const testTree = new DatasetTree(); + testTree.mSessionNodes.push(blockMocks.datasetSessionNode); + const newNode = new ZoweDatasetNode("TEST.PDS", vscode.TreeItemCollapsibleState.Collapsed, testTree.mSessionNodes[1], blockMocks.session); + testTree.mSessionNodes[1].children = [newNode]; + const updateStatsSpy = jest.spyOn(ZoweDatasetNode.prototype, "updateStats"); + const getDatasetsSpy = jest.spyOn((ZoweDatasetNode as any).prototype, "getDatasets"); + getDatasetsSpy.mockResolvedValueOnce([ + { + success: true, + commandResponse: null, + apiResponse: { + items: [ + { + m4date: "2023-10-31", + mtime: "12:00", + msec: "30", + member: "HI", + user: "SOMEUSR", + }, + { + changed: "2023-10-31 03:00:00", + member: "BYE", + id: "SOMEUSR", + }, + ], + }, + }, + ]); + await testTree.mSessionNodes[1].children[0].getChildren(); + + expect(updateStatsSpy).toHaveBeenCalled(); + }); }); describe("Dataset Tree Unit Tests - Function editSession", () => { async function createBlockMocks() { diff --git a/packages/zowe-explorer/src/dataset/ZoweDatasetNode.ts b/packages/zowe-explorer/src/dataset/ZoweDatasetNode.ts index 8497910964..808b90bf9e 100644 --- a/packages/zowe-explorer/src/dataset/ZoweDatasetNode.ts +++ b/packages/zowe-explorer/src/dataset/ZoweDatasetNode.ts @@ -118,6 +118,22 @@ export class ZoweDatasetNode extends ZoweTreeNode implements IZoweDatasetTreeNod return this.getProfile() ? this.getProfile().name : undefined; } + public updateStats(item: any): void { + if ("m4date" in item) { + const { m4date, mtime, msec }: { m4date: string; mtime: string; msec: string } = item; + this.stats = { + user: item.user, + modifiedDate: dayjs(`${m4date} ${mtime}:${msec}`).toDate(), + }; + } else if ("id" in item || "changed" in item) { + // missing keys from API response; check for FTP keys + this.stats = { + user: item.id, + modifiedDate: item.changed ? dayjs(item.changed).toDate() : undefined, + }; + } + } + /** * Retrieves child nodes of this ZoweDatasetNode * @@ -155,22 +171,6 @@ export class ZoweDatasetNode extends ZoweTreeNode implements IZoweDatasetTreeNod return; } - const updateStats = (node: IZoweDatasetTreeNode, item: any): void => { - if ("m4date" in item) { - const { m4date, mtime, msec }: { m4date: string; mtime: string; msec: string } = item; - node.stats = { - user: item.user, - modifiedDate: dayjs(`${m4date} ${mtime}:${msec}`).toDate(), - }; - } else if ("id" in item || "changed" in item) { - // missing keys from API response; check for FTP keys - node.stats = { - user: item.id, - modifiedDate: item.changed ? dayjs(item.changed).toDate() : undefined, - }; - } - }; - // push nodes to an object with property names to avoid duplicates const elementChildren: { [k: string]: ZoweDatasetNode } = {}; for (const response of responses) { @@ -185,7 +185,7 @@ export class ZoweDatasetNode extends ZoweTreeNode implements IZoweDatasetTreeNod for (const item of response.apiResponse.items ?? response.apiResponse) { const existing = this.children.find((element) => element.label.toString() === item.dsname); if (existing) { - updateStats(existing, item); + existing.updateStats(item); elementChildren[existing.label.toString()] = existing; // Creates a ZoweDatasetNode for a PDS } else if (item.dsorg === "PO" || item.dsorg === "PO-E") { @@ -279,7 +279,7 @@ export class ZoweDatasetNode extends ZoweTreeNode implements IZoweDatasetTreeNod } // get user and last modified date for sorting, if available - updateStats(temp, item); + temp.updateStats(item); elementChildren[temp.label.toString()] = temp; } } From 2da3995bbe5bbccc6cb7846a45cdab407e680f02 Mon Sep 17 00:00:00 2001 From: Trae Yelovich Date: Tue, 31 Oct 2023 14:32:20 -0400 Subject: [PATCH 185/189] fix(ds): Fix 'existing node' check in getChildren for PDS members Signed-off-by: Trae Yelovich --- packages/zowe-explorer/src/dataset/ZoweDatasetNode.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/zowe-explorer/src/dataset/ZoweDatasetNode.ts b/packages/zowe-explorer/src/dataset/ZoweDatasetNode.ts index 808b90bf9e..30242cb10c 100644 --- a/packages/zowe-explorer/src/dataset/ZoweDatasetNode.ts +++ b/packages/zowe-explorer/src/dataset/ZoweDatasetNode.ts @@ -183,7 +183,8 @@ export class ZoweDatasetNode extends ZoweTreeNode implements IZoweDatasetTreeNod // Loops through all the returned dataset members and creates nodes for them for (const item of response.apiResponse.items ?? response.apiResponse) { - const existing = this.children.find((element) => element.label.toString() === item.dsname); + const dsEntry = item.dsname ?? item.member; + const existing = this.children.find((element) => element.label.toString() === dsEntry); if (existing) { existing.updateStats(item); elementChildren[existing.label.toString()] = existing; From 89fc8139a5afb2ab47b631cdf126948a9d877ef5 Mon Sep 17 00:00:00 2001 From: zowe-robot Date: Thu, 2 Nov 2023 15:12:53 +0000 Subject: [PATCH 186/189] Bump version to 2.12.0 [ci skip] Signed-off-by: zowe-robot --- packages/eslint-plugin-zowe-explorer/CHANGELOG.md | 2 +- packages/eslint-plugin-zowe-explorer/package.json | 2 +- packages/zowe-explorer-api/CHANGELOG.md | 2 +- packages/zowe-explorer-api/package.json | 2 +- packages/zowe-explorer-ftp-extension/CHANGELOG.md | 2 +- packages/zowe-explorer-ftp-extension/package.json | 4 ++-- packages/zowe-explorer/CHANGELOG.md | 2 +- packages/zowe-explorer/package.json | 6 +++--- packages/zowe-explorer/src/webviews/package.json | 2 +- 9 files changed, 12 insertions(+), 12 deletions(-) diff --git a/packages/eslint-plugin-zowe-explorer/CHANGELOG.md b/packages/eslint-plugin-zowe-explorer/CHANGELOG.md index 7fb64f5e17..f5e1e7a28e 100644 --- a/packages/eslint-plugin-zowe-explorer/CHANGELOG.md +++ b/packages/eslint-plugin-zowe-explorer/CHANGELOG.md @@ -1,6 +1,6 @@ All notable changes to the "eslint-plugin-zowe-explorer" package will be documented in this file. -## TBD Release +## `2.12.0` ## `2.11.2` diff --git a/packages/eslint-plugin-zowe-explorer/package.json b/packages/eslint-plugin-zowe-explorer/package.json index 5f07b57d56..861cce5304 100644 --- a/packages/eslint-plugin-zowe-explorer/package.json +++ b/packages/eslint-plugin-zowe-explorer/package.json @@ -1,6 +1,6 @@ { "name": "eslint-plugin-zowe-explorer", - "version": "2.12.0-SNAPSHOT", + "version": "2.12.0", "description": "Custom ESLint Rules for ZOWE Explorer", "keywords": [ "eslint", diff --git a/packages/zowe-explorer-api/CHANGELOG.md b/packages/zowe-explorer-api/CHANGELOG.md index 2f9c9cd953..25cb51d0cb 100644 --- a/packages/zowe-explorer-api/CHANGELOG.md +++ b/packages/zowe-explorer-api/CHANGELOG.md @@ -2,7 +2,7 @@ All notable changes to the "zowe-explorer-api" extension will be documented in this file. -## TBD Release +## `2.12.0` ### New features and enhancements diff --git a/packages/zowe-explorer-api/package.json b/packages/zowe-explorer-api/package.json index 0203a8ee4c..4e48c2905a 100644 --- a/packages/zowe-explorer-api/package.json +++ b/packages/zowe-explorer-api/package.json @@ -1,6 +1,6 @@ { "name": "@zowe/zowe-explorer-api", - "version": "2.12.0-SNAPSHOT", + "version": "2.12.0", "description": "Extensibility API for Zowe Explorer.", "publisher": "Zowe", "author": "Zowe", diff --git a/packages/zowe-explorer-ftp-extension/CHANGELOG.md b/packages/zowe-explorer-ftp-extension/CHANGELOG.md index 934bfea0c3..80ff379f4a 100644 --- a/packages/zowe-explorer-ftp-extension/CHANGELOG.md +++ b/packages/zowe-explorer-ftp-extension/CHANGELOG.md @@ -1,6 +1,6 @@ All notable changes to the "zowe-explorer-ftp-extension" extension will be documented in this file. -## TBD Release +## `2.12.0` ### Bug fixes diff --git a/packages/zowe-explorer-ftp-extension/package.json b/packages/zowe-explorer-ftp-extension/package.json index db66761841..3459fddb20 100644 --- a/packages/zowe-explorer-ftp-extension/package.json +++ b/packages/zowe-explorer-ftp-extension/package.json @@ -5,7 +5,7 @@ "author": "Zowe", "license": "EPL-2.0", "description": "Adds zFTP support to Zowe Explorer demonstrating how to extend the Zowe Explorer using its extensibility API.", - "version": "2.12.0-SNAPSHOT", + "version": "2.12.0", "icon": "resources/zowe-ftp-color.png", "repository": { "url": "https://github.com/zowe/vscode-extension-for-zowe" @@ -48,7 +48,7 @@ }, "dependencies": { "@zowe/zos-ftp-for-zowe-cli": "2.1.2", - "@zowe/zowe-explorer-api": "2.12.0-SNAPSHOT", + "@zowe/zowe-explorer-api": "2.12.0", "tmp": "0.2.1" }, "devDependencies": { diff --git a/packages/zowe-explorer/CHANGELOG.md b/packages/zowe-explorer/CHANGELOG.md index c718756d9e..db493f32f1 100644 --- a/packages/zowe-explorer/CHANGELOG.md +++ b/packages/zowe-explorer/CHANGELOG.md @@ -2,7 +2,7 @@ All notable changes to the "vscode-extension-for-zowe" extension will be documented in this file. -## TBD Release +## `2.12.0` ### New features and enhancements diff --git a/packages/zowe-explorer/package.json b/packages/zowe-explorer/package.json index 0ccfad3817..976e5fc47c 100644 --- a/packages/zowe-explorer/package.json +++ b/packages/zowe-explorer/package.json @@ -2,7 +2,7 @@ "name": "vscode-extension-for-zowe", "displayName": "%displayName%", "description": "%description%", - "version": "2.12.0-SNAPSHOT", + "version": "2.12.0", "publisher": "Zowe", "author": "Zowe", "license": "EPL-2.0", @@ -1989,7 +1989,7 @@ "copy-webpack-plugin": "^6.4.1", "cross-env": "^5.2.0", "del": "^4.1.1", - "eslint-plugin-zowe-explorer": "2.12.0-SNAPSHOT", + "eslint-plugin-zowe-explorer": "2.12.0", "event-stream": "^4.0.1", "expect": "^24.8.0", "geckodriver": "^1.19.1", @@ -2015,7 +2015,7 @@ }, "dependencies": { "@zowe/secrets-for-zowe-sdk": "7.18.4", - "@zowe/zowe-explorer-api": "2.12.0-SNAPSHOT", + "@zowe/zowe-explorer-api": "2.12.0", "dayjs": "^1.11.10", "fs-extra": "8.0.1", "isbinaryfile": "4.0.4", diff --git a/packages/zowe-explorer/src/webviews/package.json b/packages/zowe-explorer/src/webviews/package.json index 43c49ef0ce..2dddf75290 100644 --- a/packages/zowe-explorer/src/webviews/package.json +++ b/packages/zowe-explorer/src/webviews/package.json @@ -2,7 +2,7 @@ "name": "webviews", "private": true, "type": "module", - "version": "2.11.3-SNAPSHOT", + "version": "2.12.0", "main": "index.js", "license": "EPL-2.0", "scripts": { From 7d9bf7cc088de91de114bd7118a71ddaf35a581c Mon Sep 17 00:00:00 2001 From: zowe-robot Date: Thu, 2 Nov 2023 15:15:23 +0000 Subject: [PATCH 187/189] Bump version to 2.13.0-SNAPSHOT [ci skip] Signed-off-by: zowe-robot --- lerna.json | 2 +- packages/eslint-plugin-zowe-explorer/CHANGELOG.md | 6 ++++++ packages/eslint-plugin-zowe-explorer/package.json | 2 +- packages/zowe-explorer-api/CHANGELOG.md | 6 ++++++ packages/zowe-explorer-api/package.json | 2 +- packages/zowe-explorer-ftp-extension/CHANGELOG.md | 6 ++++++ packages/zowe-explorer-ftp-extension/package.json | 4 ++-- packages/zowe-explorer/CHANGELOG.md | 6 ++++++ packages/zowe-explorer/package.json | 6 +++--- packages/zowe-explorer/src/webviews/package.json | 2 +- 10 files changed, 33 insertions(+), 9 deletions(-) diff --git a/lerna.json b/lerna.json index 37d602990f..be5de7fc16 100644 --- a/lerna.json +++ b/lerna.json @@ -1,5 +1,5 @@ { - "version": "2.12.0", + "version": "2.13.0-SNAPSHOT", "command": { "version": { "forcePublish": true, diff --git a/packages/eslint-plugin-zowe-explorer/CHANGELOG.md b/packages/eslint-plugin-zowe-explorer/CHANGELOG.md index f5e1e7a28e..ee5da00885 100644 --- a/packages/eslint-plugin-zowe-explorer/CHANGELOG.md +++ b/packages/eslint-plugin-zowe-explorer/CHANGELOG.md @@ -1,5 +1,11 @@ All notable changes to the "eslint-plugin-zowe-explorer" package will be documented in this file. +## TBD Release + +### New features and enhancements + +### Bug fixes + ## `2.12.0` ## `2.11.2` diff --git a/packages/eslint-plugin-zowe-explorer/package.json b/packages/eslint-plugin-zowe-explorer/package.json index 861cce5304..7d9500aee8 100644 --- a/packages/eslint-plugin-zowe-explorer/package.json +++ b/packages/eslint-plugin-zowe-explorer/package.json @@ -1,6 +1,6 @@ { "name": "eslint-plugin-zowe-explorer", - "version": "2.12.0", + "version": "2.13.0-SNAPSHOT", "description": "Custom ESLint Rules for ZOWE Explorer", "keywords": [ "eslint", diff --git a/packages/zowe-explorer-api/CHANGELOG.md b/packages/zowe-explorer-api/CHANGELOG.md index 25cb51d0cb..e60ca4eb87 100644 --- a/packages/zowe-explorer-api/CHANGELOG.md +++ b/packages/zowe-explorer-api/CHANGELOG.md @@ -2,6 +2,12 @@ All notable changes to the "zowe-explorer-api" extension will be documented in this file. +## TBD Release + +### New features and enhancements + +### Bug fixes + ## `2.12.0` ### New features and enhancements diff --git a/packages/zowe-explorer-api/package.json b/packages/zowe-explorer-api/package.json index 4e48c2905a..0ab60faf1e 100644 --- a/packages/zowe-explorer-api/package.json +++ b/packages/zowe-explorer-api/package.json @@ -1,6 +1,6 @@ { "name": "@zowe/zowe-explorer-api", - "version": "2.12.0", + "version": "2.13.0-SNAPSHOT", "description": "Extensibility API for Zowe Explorer.", "publisher": "Zowe", "author": "Zowe", diff --git a/packages/zowe-explorer-ftp-extension/CHANGELOG.md b/packages/zowe-explorer-ftp-extension/CHANGELOG.md index 80ff379f4a..6041058d00 100644 --- a/packages/zowe-explorer-ftp-extension/CHANGELOG.md +++ b/packages/zowe-explorer-ftp-extension/CHANGELOG.md @@ -1,5 +1,11 @@ All notable changes to the "zowe-explorer-ftp-extension" extension will be documented in this file. +## TBD Release + +### New features and enhancements + +### Bug fixes + ## `2.12.0` ### Bug fixes diff --git a/packages/zowe-explorer-ftp-extension/package.json b/packages/zowe-explorer-ftp-extension/package.json index 3459fddb20..2bb7410c46 100644 --- a/packages/zowe-explorer-ftp-extension/package.json +++ b/packages/zowe-explorer-ftp-extension/package.json @@ -5,7 +5,7 @@ "author": "Zowe", "license": "EPL-2.0", "description": "Adds zFTP support to Zowe Explorer demonstrating how to extend the Zowe Explorer using its extensibility API.", - "version": "2.12.0", + "version": "2.13.0-SNAPSHOT", "icon": "resources/zowe-ftp-color.png", "repository": { "url": "https://github.com/zowe/vscode-extension-for-zowe" @@ -48,7 +48,7 @@ }, "dependencies": { "@zowe/zos-ftp-for-zowe-cli": "2.1.2", - "@zowe/zowe-explorer-api": "2.12.0", + "@zowe/zowe-explorer-api": "2.13.0-SNAPSHOT", "tmp": "0.2.1" }, "devDependencies": { diff --git a/packages/zowe-explorer/CHANGELOG.md b/packages/zowe-explorer/CHANGELOG.md index db493f32f1..dc8ce095c8 100644 --- a/packages/zowe-explorer/CHANGELOG.md +++ b/packages/zowe-explorer/CHANGELOG.md @@ -2,6 +2,12 @@ All notable changes to the "vscode-extension-for-zowe" extension will be documented in this file. +## TBD Release + +### New features and enhancements + +### Bug fixes + ## `2.12.0` ### New features and enhancements diff --git a/packages/zowe-explorer/package.json b/packages/zowe-explorer/package.json index 976e5fc47c..a5d29c0c2b 100644 --- a/packages/zowe-explorer/package.json +++ b/packages/zowe-explorer/package.json @@ -2,7 +2,7 @@ "name": "vscode-extension-for-zowe", "displayName": "%displayName%", "description": "%description%", - "version": "2.12.0", + "version": "2.13.0-SNAPSHOT", "publisher": "Zowe", "author": "Zowe", "license": "EPL-2.0", @@ -1989,7 +1989,7 @@ "copy-webpack-plugin": "^6.4.1", "cross-env": "^5.2.0", "del": "^4.1.1", - "eslint-plugin-zowe-explorer": "2.12.0", + "eslint-plugin-zowe-explorer": "2.13.0-SNAPSHOT", "event-stream": "^4.0.1", "expect": "^24.8.0", "geckodriver": "^1.19.1", @@ -2015,7 +2015,7 @@ }, "dependencies": { "@zowe/secrets-for-zowe-sdk": "7.18.4", - "@zowe/zowe-explorer-api": "2.12.0", + "@zowe/zowe-explorer-api": "2.13.0-SNAPSHOT", "dayjs": "^1.11.10", "fs-extra": "8.0.1", "isbinaryfile": "4.0.4", diff --git a/packages/zowe-explorer/src/webviews/package.json b/packages/zowe-explorer/src/webviews/package.json index 2dddf75290..894ac5f089 100644 --- a/packages/zowe-explorer/src/webviews/package.json +++ b/packages/zowe-explorer/src/webviews/package.json @@ -2,7 +2,7 @@ "name": "webviews", "private": true, "type": "module", - "version": "2.12.0", + "version": "2.13.0-SNAPSHOT", "main": "index.js", "license": "EPL-2.0", "scripts": { From c92eba05819554d13b9c5f99dec3a923b6524377 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 2 Nov 2023 15:16:10 +0000 Subject: [PATCH 188/189] chore(deps): Bump browserify-sign from 4.2.1 to 4.2.2 Bumps [browserify-sign](https://github.com/crypto-browserify/browserify-sign) from 4.2.1 to 4.2.2. - [Changelog](https://github.com/browserify/browserify-sign/blob/main/CHANGELOG.md) - [Commits](https://github.com/crypto-browserify/browserify-sign/compare/v4.2.1...v4.2.2) --- updated-dependencies: - dependency-name: browserify-sign dependency-type: indirect ... Signed-off-by: dependabot[bot] --- yarn.lock | 42 ++++++++++++++++++++++++++++-------------- 1 file changed, 28 insertions(+), 14 deletions(-) diff --git a/yarn.lock b/yarn.lock index 806ddd0951..5243ccd7c9 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3468,11 +3468,16 @@ bn.js@^4.0.0, bn.js@^4.1.0, bn.js@^4.11.9: resolved "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz" integrity sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA== -bn.js@^5.0.0, bn.js@^5.1.1: +bn.js@^5.0.0: version "5.2.0" resolved "https://registry.npmjs.org/bn.js/-/bn.js-5.2.0.tgz" integrity sha512-D7iWRBvnZE8ecXiLj/9wbxH7Tk79fAh8IHaTNq1RWRixsS02W+5qS+iE9yq6RYl0asXx5tw0bLhmT5pIfbSquw== +bn.js@^5.2.1: + version "5.2.1" + resolved "https://registry.npmjs.org/bn.js/-/bn.js-5.2.1.tgz#0bc527a6a0d18d0aa8d5b0538ce4a77dccfa7b70" + integrity sha512-eXRvHzWyYPBuB4NBy0cmYQjGitUrtqwbvlzP3G6VFnNRbsZQIxQ10PbKKHt8gZ/HW/D/747aDl+QkDqg3KQLMQ== + boolbase@^1.0.0: version "1.0.0" resolved "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz" @@ -3567,7 +3572,7 @@ browserify-des@^1.0.0: inherits "^2.0.1" safe-buffer "^5.1.2" -browserify-rsa@^4.0.0, browserify-rsa@^4.0.1: +browserify-rsa@^4.0.0, browserify-rsa@^4.1.0: version "4.1.0" resolved "https://registry.npmjs.org/browserify-rsa/-/browserify-rsa-4.1.0.tgz" integrity sha512-AdEER0Hkspgno2aR97SAf6vi0y0k8NuOpGnVH3O99rcA5Q6sh8QxcngtHuJ6uXwnfAXNM4Gn1Gb7/MV1+Ymbog== @@ -3576,19 +3581,19 @@ browserify-rsa@^4.0.0, browserify-rsa@^4.0.1: randombytes "^2.0.1" browserify-sign@^4.0.0: - version "4.2.1" - resolved "https://registry.npmjs.org/browserify-sign/-/browserify-sign-4.2.1.tgz" - integrity sha512-/vrA5fguVAKKAVTNJjgSm1tRQDHUU6DbwO9IROu/0WAzC8PKhucDSh18J0RMvVeHAn5puMd+QHC2erPRNf8lmg== + version "4.2.2" + resolved "https://registry.npmjs.org/browserify-sign/-/browserify-sign-4.2.2.tgz#e78d4b69816d6e3dd1c747e64e9947f9ad79bc7e" + integrity sha512-1rudGyeYY42Dk6texmv7c4VcQ0EsvVbLwZkA+AQB7SxvXxmcD93jcHie8bzecJ+ChDlmAm2Qyu0+Ccg5uhZXCg== dependencies: - bn.js "^5.1.1" - browserify-rsa "^4.0.1" + bn.js "^5.2.1" + browserify-rsa "^4.1.0" create-hash "^1.2.0" create-hmac "^1.1.7" - elliptic "^6.5.3" + elliptic "^6.5.4" inherits "^2.0.4" - parse-asn1 "^5.1.5" - readable-stream "^3.6.0" - safe-buffer "^5.2.0" + parse-asn1 "^5.1.6" + readable-stream "^3.6.2" + safe-buffer "^5.2.1" browserify-zlib@^0.2.0: version "0.2.0" @@ -4868,7 +4873,7 @@ electron-to-chromium@^1.4.477: resolved "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.556.tgz#97385917eb6ea3ac6a3378cf87bb39ee1db96e76" integrity sha512-6RPN0hHfzDU8D56E72YkDvnLw5Cj2NMXZGg3UkgyoHxjVhG99KZpsKgBWMmTy0Ei89xwan+rbRsVB9yzATmYzQ== -elliptic@^6.5.3: +elliptic@^6.5.3, elliptic@^6.5.4: version "6.5.4" resolved "https://registry.npmjs.org/elliptic/-/elliptic-6.5.4.tgz" integrity sha512-iLhC6ULemrljPZb+QutR5TQGB+pdW6KGD5RSegS+8sorOZT+rdQFbsQFJgvN3eRqNALqJer4oQ16YvJHlU8hzQ== @@ -9172,7 +9177,7 @@ parent-module@^1.0.0: dependencies: callsites "^3.0.0" -parse-asn1@^5.0.0, parse-asn1@^5.1.5: +parse-asn1@^5.0.0, parse-asn1@^5.1.6: version "5.1.6" resolved "https://registry.npmjs.org/parse-asn1/-/parse-asn1-5.1.6.tgz" integrity sha512-RnZRo1EPU6JBnra2vGHj0yhp6ebyjBZpmUCLHWiFhxlzvBCCpAuZ7elsBp1PVAbQN0/04VD/19rfzlBSwLstMw== @@ -9840,6 +9845,15 @@ readable-stream@1.1.x: string_decoder "^1.1.1" util-deprecate "^1.0.1" +readable-stream@^3.6.2: + version "3.6.2" + resolved "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz#56a9b36ea965c00c5a93ef31eb111a0f11056967" + integrity sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA== + dependencies: + inherits "^2.0.3" + string_decoder "^1.1.1" + util-deprecate "^1.0.1" + readable-stream@~1.0.31: version "1.0.34" resolved "https://registry.npmjs.org/readable-stream/-/readable-stream-1.0.34.tgz" @@ -10186,7 +10200,7 @@ rxjs@^6.5.2: dependencies: tslib "^1.9.0" -safe-buffer@^5.0.1, safe-buffer@^5.1.0, safe-buffer@^5.1.1, safe-buffer@^5.1.2, safe-buffer@^5.2.0, safe-buffer@~5.2.0: +safe-buffer@^5.0.1, safe-buffer@^5.1.0, safe-buffer@^5.1.1, safe-buffer@^5.1.2, safe-buffer@^5.2.0, safe-buffer@^5.2.1, safe-buffer@~5.2.0: version "5.2.1" resolved "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz" integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ== From 18b37fba26b0e08895ff8cf6bb80eb6545b86cca Mon Sep 17 00:00:00 2001 From: Billie Simmons <49491949+JillieBeanSim@users.noreply.github.com> Date: Thu, 2 Nov 2023 16:52:41 -0400 Subject: [PATCH 189/189] update all to "2.12.1-SNAPSHOT" Signed-off-by: Billie Simmons <49491949+JillieBeanSim@users.noreply.github.com> --- lerna.json | 2 +- packages/eslint-plugin-zowe-explorer/package.json | 2 +- packages/zowe-explorer-api/package.json | 2 +- packages/zowe-explorer-ftp-extension/package.json | 4 ++-- packages/zowe-explorer/package.json | 6 +++--- packages/zowe-explorer/src/webviews/package.json | 2 +- 6 files changed, 9 insertions(+), 9 deletions(-) diff --git a/lerna.json b/lerna.json index be5de7fc16..387ae1b4df 100644 --- a/lerna.json +++ b/lerna.json @@ -1,5 +1,5 @@ { - "version": "2.13.0-SNAPSHOT", + "version": "2.12.1-SNAPSHOT", "command": { "version": { "forcePublish": true, diff --git a/packages/eslint-plugin-zowe-explorer/package.json b/packages/eslint-plugin-zowe-explorer/package.json index 7d9500aee8..fa4457b4e3 100644 --- a/packages/eslint-plugin-zowe-explorer/package.json +++ b/packages/eslint-plugin-zowe-explorer/package.json @@ -1,6 +1,6 @@ { "name": "eslint-plugin-zowe-explorer", - "version": "2.13.0-SNAPSHOT", + "version": "2.12.1-SNAPSHOT", "description": "Custom ESLint Rules for ZOWE Explorer", "keywords": [ "eslint", diff --git a/packages/zowe-explorer-api/package.json b/packages/zowe-explorer-api/package.json index 0ab60faf1e..c444021d31 100644 --- a/packages/zowe-explorer-api/package.json +++ b/packages/zowe-explorer-api/package.json @@ -1,6 +1,6 @@ { "name": "@zowe/zowe-explorer-api", - "version": "2.13.0-SNAPSHOT", + "version": "2.12.1-SNAPSHOT", "description": "Extensibility API for Zowe Explorer.", "publisher": "Zowe", "author": "Zowe", diff --git a/packages/zowe-explorer-ftp-extension/package.json b/packages/zowe-explorer-ftp-extension/package.json index 2bb7410c46..8204c5d2f4 100644 --- a/packages/zowe-explorer-ftp-extension/package.json +++ b/packages/zowe-explorer-ftp-extension/package.json @@ -5,7 +5,7 @@ "author": "Zowe", "license": "EPL-2.0", "description": "Adds zFTP support to Zowe Explorer demonstrating how to extend the Zowe Explorer using its extensibility API.", - "version": "2.13.0-SNAPSHOT", + "version": "2.12.1-SNAPSHOT", "icon": "resources/zowe-ftp-color.png", "repository": { "url": "https://github.com/zowe/vscode-extension-for-zowe" @@ -48,7 +48,7 @@ }, "dependencies": { "@zowe/zos-ftp-for-zowe-cli": "2.1.2", - "@zowe/zowe-explorer-api": "2.13.0-SNAPSHOT", + "@zowe/zowe-explorer-api": "2.12.1-SNAPSHOT", "tmp": "0.2.1" }, "devDependencies": { diff --git a/packages/zowe-explorer/package.json b/packages/zowe-explorer/package.json index a5d29c0c2b..6a0ff19c00 100644 --- a/packages/zowe-explorer/package.json +++ b/packages/zowe-explorer/package.json @@ -2,7 +2,7 @@ "name": "vscode-extension-for-zowe", "displayName": "%displayName%", "description": "%description%", - "version": "2.13.0-SNAPSHOT", + "version": "2.12.1-SNAPSHOT", "publisher": "Zowe", "author": "Zowe", "license": "EPL-2.0", @@ -1989,7 +1989,7 @@ "copy-webpack-plugin": "^6.4.1", "cross-env": "^5.2.0", "del": "^4.1.1", - "eslint-plugin-zowe-explorer": "2.13.0-SNAPSHOT", + "eslint-plugin-zowe-explorer": "2.12.1-SNAPSHOT", "event-stream": "^4.0.1", "expect": "^24.8.0", "geckodriver": "^1.19.1", @@ -2015,7 +2015,7 @@ }, "dependencies": { "@zowe/secrets-for-zowe-sdk": "7.18.4", - "@zowe/zowe-explorer-api": "2.13.0-SNAPSHOT", + "@zowe/zowe-explorer-api": "2.12.1-SNAPSHOT", "dayjs": "^1.11.10", "fs-extra": "8.0.1", "isbinaryfile": "4.0.4", diff --git a/packages/zowe-explorer/src/webviews/package.json b/packages/zowe-explorer/src/webviews/package.json index 894ac5f089..a2e53f84a4 100644 --- a/packages/zowe-explorer/src/webviews/package.json +++ b/packages/zowe-explorer/src/webviews/package.json @@ -2,7 +2,7 @@ "name": "webviews", "private": true, "type": "module", - "version": "2.13.0-SNAPSHOT", + "version": "2.12.1-SNAPSHOT", "main": "index.js", "license": "EPL-2.0", "scripts": {