diff --git a/packages/zowe-explorer-api/src/tree/sorting.ts b/packages/zowe-explorer-api/src/tree/sorting.ts index c6fbaa3686..2e4e4aac20 100644 --- a/packages/zowe-explorer-api/src/tree/sorting.ts +++ b/packages/zowe-explorer-api/src/tree/sorting.ts @@ -40,6 +40,7 @@ export namespace Sorting { export enum JobSortOpts { Id, DateSubmitted, + DateCompleted, Name, ReturnCode, } diff --git a/packages/zowe-explorer/__tests__/__mocks__/mockCreators/jobs.ts b/packages/zowe-explorer/__tests__/__mocks__/mockCreators/jobs.ts index 71c813fb78..5ff05ac1ba 100644 --- a/packages/zowe-explorer/__tests__/__mocks__/mockCreators/jobs.ts +++ b/packages/zowe-explorer/__tests__/__mocks__/mockCreators/jobs.ts @@ -45,6 +45,7 @@ export function createIJobObject() { type: "JOB", url: "fake/url", "exec-member": "sampleMember", + "exec-ended": "2024-03-07T00:04:67:980z", }; } diff --git a/packages/zowe-explorer/__tests__/__unit__/trees/job/JobActions.unit.test.ts b/packages/zowe-explorer/__tests__/__unit__/trees/job/JobActions.unit.test.ts index d1c515484d..ee043a6f07 100644 --- a/packages/zowe-explorer/__tests__/__unit__/trees/job/JobActions.unit.test.ts +++ b/packages/zowe-explorer/__tests__/__unit__/trees/job/JobActions.unit.test.ts @@ -55,7 +55,7 @@ function createGlobalMocks() { collapsibleState: vscode.TreeItemCollapsibleState.None, session: createISession(), profile: createIProfile(), - job: settingJobObjects(createIJobObject(), "ZOWEUSR1", "JOB045123", "ABEND S222"), + job: settingJobObjects(createIJobObject(), "ZOWEUSR1", "JOB045123", "ABEND S222", "2024-03-12T10:50:08.950Z"), }), JobNode2: new ZoweJobNode({ label: "testProfile", @@ -69,7 +69,7 @@ function createGlobalMocks() { collapsibleState: vscode.TreeItemCollapsibleState.None, session: createISession(), profile: createIProfile(), - job: settingJobObjects(createIJobObject(), "ZOWEUSR2", "JOB045125", "CC 0000"), + job: settingJobObjects(createIJobObject(), "ZOWEUSR2", "JOB045125", "CC 0000", "2024-03-12T08:30:08.950Z"), }), mockJobArray: [], testJobsTree: null as any, @@ -134,10 +134,17 @@ function createGlobalMocks() { value: jest.fn().mockReturnValue([newMocks.imperativeProfile.name]), configurable: true, }); - function settingJobObjects(job: zosjobs.IJob, setjobname: string, setjobid: string, setjobreturncode: string): zosjobs.IJob { + function settingJobObjects( + job: zosjobs.IJob, + setjobname: string, + setjobid: string, + setjobreturncode: string, + datecompleted?: string + ): zosjobs.IJob { job.jobname = setjobname; job.jobid = setjobid; job.retcode = setjobreturncode; + job["exec-ended"] = datecompleted; return job; } @@ -1438,6 +1445,26 @@ describe("sortJobs function", () => { expect(sortbyretcodespy.mock.calls[0][0].children).toStrictEqual(expected.mSessionNodes[0].children); }); + it("sort by date completed", async () => { + const globalMocks = createGlobalMocks(); + const testtree = new JobTree(); + const expected = new JobTree(); + testtree.mSessionNodes[0].sort = { + method: Sorting.JobSortOpts.DateCompleted, + direction: Sorting.SortDirection.Ascending, + }; + testtree.mSessionNodes[0].children = [...[globalMocks.mockJobArray[0], globalMocks.mockJobArray[1], globalMocks.mockJobArray[2]]]; + expected.mSessionNodes[0].children = [...[globalMocks.mockJobArray[2], globalMocks.mockJobArray[0], globalMocks.mockJobArray[1]]]; + jest.spyOn(Gui, "showQuickPick").mockResolvedValueOnce({ label: "$(calendar) Date Completed" }); + const sortbynamespy = jest.spyOn(JobTree.prototype, "sortBy"); + //act + await JobActions.sortJobs(testtree.mSessionNodes[0], testtree); + //asert + expect(sortbynamespy).toHaveBeenCalledWith(testtree.mSessionNodes[0]); + expect(sortbynamespy).toHaveBeenCalled(); + expect(sortbynamespy.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 JobTree(); diff --git a/packages/zowe-explorer/l10n/bundle.l10n.json b/packages/zowe-explorer/l10n/bundle.l10n.json index d27b82e34d..38aa626ec4 100644 --- a/packages/zowe-explorer/l10n/bundle.l10n.json +++ b/packages/zowe-explorer/l10n/bundle.l10n.json @@ -354,6 +354,7 @@ "Retrieving response from zowe.GetJobs": "Retrieving response from zowe.GetJobs", "$(list-ordered) Job ID (default)": "$(list-ordered) Job ID (default)", "$(calendar) Date Submitted": "$(calendar) Date Submitted", + "$(calendar) Date Completed": "$(calendar) Date Completed", "$(case-sensitive) Job Name": "$(case-sensitive) Job Name", "$(symbol-numeric) Return Code": "$(symbol-numeric) Return Code", "$(fold) Sort Direction": "$(fold) Sort Direction", diff --git a/packages/zowe-explorer/l10n/poeditor.json b/packages/zowe-explorer/l10n/poeditor.json index 9363299157..be85961d07 100644 --- a/packages/zowe-explorer/l10n/poeditor.json +++ b/packages/zowe-explorer/l10n/poeditor.json @@ -577,6 +577,7 @@ "Retrieving response from zowe.GetJobs": "", "$(list-ordered) Job ID (default)": "", "$(calendar) Date Submitted": "", + "$(calendar) Date Completed": "", "$(case-sensitive) Job Name": "", "$(symbol-numeric) Return Code": "", "$(fold) Sort Direction": "", diff --git a/packages/zowe-explorer/src/trees/job/JobUtils.ts b/packages/zowe-explorer/src/trees/job/JobUtils.ts index 0e9f6a059b..f0bfb007bd 100644 --- a/packages/zowe-explorer/src/trees/job/JobUtils.ts +++ b/packages/zowe-explorer/src/trees/job/JobUtils.ts @@ -12,19 +12,20 @@ import * as vscode from "vscode"; import * as zosjobs from "@zowe/zos-jobs-for-zowe-sdk"; import { Sorting } from "@zowe/zowe-explorer-api"; - export class JobUtils { public static JOB_SORT_OPTS = [ vscode.l10n.t("$(list-ordered) Job ID (default)"), vscode.l10n.t("$(calendar) Date Submitted"), + vscode.l10n.t("$(calendar) Date Completed"), vscode.l10n.t("$(case-sensitive) Job Name"), vscode.l10n.t("$(symbol-numeric) Return Code"), vscode.l10n.t("$(fold) Sort Direction"), ]; - public static JOB_SORT_KEYS: Record = { + public static JOB_SORT_KEYS: Record = { [Sorting.JobSortOpts.Id]: "jobid", [Sorting.JobSortOpts.DateSubmitted]: "exec-submitted", + [Sorting.JobSortOpts.DateCompleted]: "exec-ended", [Sorting.JobSortOpts.Name]: "jobname", [Sorting.JobSortOpts.ReturnCode]: "retcode", }; diff --git a/packages/zowe-explorer/src/trees/job/ZoweJobNode.ts b/packages/zowe-explorer/src/trees/job/ZoweJobNode.ts index 520282c6bf..9237a4affa 100644 --- a/packages/zowe-explorer/src/trees/job/ZoweJobNode.ts +++ b/packages/zowe-explorer/src/trees/job/ZoweJobNode.ts @@ -281,8 +281,15 @@ export class ZoweJobNode extends ZoweTreeNode implements IZoweJobTreeNode { const sortLessThan = sortOpts.direction == Sorting.SortDirection.Ascending ? -1 : 1; const sortGreaterThan = sortLessThan * -1; - const keyToSortBy = JobUtils.JOB_SORT_KEYS[sortOpts.method]; + let keyToSortBy = JobUtils.JOB_SORT_KEYS[sortOpts.method]; let xCompare, yCompare; + if (!x.job[keyToSortBy] && !y.job[keyToSortBy]) { + keyToSortBy = JobUtils.JOB_SORT_KEYS[3]; + } else if (!x.job[keyToSortBy]) { + return 1; + } else if (!y.job[keyToSortBy]) { + return -1; + } 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 @@ -292,7 +299,13 @@ export class ZoweJobNode extends ZoweTreeNode implements IZoweJobTreeNode { xCompare = x.job[keyToSortBy]; yCompare = y.job[keyToSortBy]; } - + if (keyToSortBy === "exec-ended") { + x.description = x.job["exec-ended"]; + y.description = y.job["exec-ended"]; + } else { + x.description = ""; + y.description = ""; + } if (xCompare === yCompare) { return x.job["jobid"] > y.job["jobid"] ? sortGreaterThan : sortLessThan; }