Skip to content

Commit

Permalink
feat: Issue ZDPT-8744: add clear filter option
Browse files Browse the repository at this point in the history
Signed-off-by: Santhoshi Boyina <[email protected]>
  • Loading branch information
SanthoshiBoyina1 committed Nov 29, 2023
1 parent 68c9167 commit c8f80bd
Show file tree
Hide file tree
Showing 10 changed files with 214 additions and 2 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -243,6 +243,7 @@ async function createGlobalMocks() {
"zowe.jobs.stopPolling",
"zowe.jobs.cancelJob",
"zowe.jobs.sortBy",
"zowe.jobs.filterJobs",
"zowe.manualPoll",
"zowe.editHistory",
"zowe.promptCredentials",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,46 @@ import { jobStringValidator } from "../../../src/shared/utils";
import { ZoweLogger } from "../../../src/utils/LoggerUtils";
import { Poller } from "@zowe/zowe-explorer-api/src/utils";
import { SettingsConfig } from "../../../src/utils/SettingsConfig";
import { TreeProviders } from "../../../src/shared/TreeProviders";

jest.mock("vscode");
const showMock = jest.fn();
const onDidChangeValueMock = {
event: (callback: (value: string) => void): vscode.Disposable => {
const disposable = {
dispose: jest.fn(),
};
callback("");
return disposable;
},
};
const mockInputBox: vscode.InputBox = {
title: "",
value: "",
placeholder: "",
password: false,
onDidChangeValue: onDidChangeValueMock.event,
onDidAccept: jest.fn(),
show: showMock,
hide: jest.fn(),
dispose: jest.fn(),
buttons: [],
onDidTriggerButton: jest.fn(),
prompt: "",
validationMessage: "",
step: 1,
totalSteps: 100,
enabled: true,
busy: false,
ignoreFocusOut: false,
onDidHide: jest.fn(),
};
function setJobObjects(job: zowe.IJob, newJobName: string, newJobId: string, newRetCode: string) {
job.jobname = newJobName;
job.jobid = newJobId;
job.retcode = newRetCode;
return job;
}

async function createGlobalMocks() {
const globalMocks = {
Expand Down Expand Up @@ -126,6 +166,12 @@ async function createGlobalMocks() {
value: globalMocks.mockGetSpoolFiles,
configurable: true,
});
Object.defineProperty(vscode.window, "createInputBox", {
value: jest.fn(() => mockInputBox),
configurable: true,
});

Object.defineProperty(Gui, "infoMessage", { value: jest.fn(), configurable: true });
Object.defineProperty(vscode.window, "createTreeView", { value: globalMocks.createTreeView, configurable: true });
Object.defineProperty(vscode.window, "showQuickPick", { value: globalMocks.mockShowQuickPick, configurable: true });
Object.defineProperty(vscode, "ConfigurationTarget", { value: globalMocks.enums, configurable: true });
Expand Down Expand Up @@ -973,3 +1019,66 @@ describe("getFavorites", () => {
expect(tree.getFavorites()).toEqual(["test1", "test2", "test3"]);
});
});

describe("ZosJobsProvider Unit Test - Filter Jobs", () => {
const node1: IZoweJobTreeNode = new Job(
"jobnew",
vscode.TreeItemCollapsibleState.None,
null,
null,
setJobObjects(createIJobObject(), "ZOWEUSR1", "JOB04945", "CC 0000"),
null
);
const node2: IZoweJobTreeNode = new Job(
"jobnew",
vscode.TreeItemCollapsibleState.None,
null,
null,
setJobObjects(createIJobObject(), "ZOWEUSR2", "JOB05037", "CC 0000"),
null
);
const node3: IZoweJobTreeNode = new Job(
"jobnew",
vscode.TreeItemCollapsibleState.None,
null,
null,
setJobObjects(createIJobObject(), "ZOWEUSR3", "TSU07707", "ABEND S222"),
null
);

let globalMocks;
beforeEach(async () => {
globalMocks = await createGlobalMocks();
const mockTreeProvider = {
refresh: jest.fn(),
} as any;
jest.spyOn(TreeProviders, "job", "get").mockReturnValue(mockTreeProvider);
});

afterEach(() => {
jest.restoreAllMocks();
jest.resetAllMocks();
jest.clearAllMocks();
});

it("To show showInformationMessage", async () => {
const testTree = new ZosJobsProvider();
node1.collapsibleState = vscode.TreeItemCollapsibleState.Collapsed;
await testTree.filterJobsDialog(node1);
expect(mocked(Gui.infoMessage)).toHaveBeenCalled();
});

it("To filter jobs based on a combination of JobName, JobId and Return code", async () => {
const testTree = new ZosJobsProvider();
node1.collapsibleState = vscode.TreeItemCollapsibleState.Expanded;
node1.children = [node2, node3];
const createInputBoxSpy = jest.spyOn(vscode.window, "createInputBox");
mockInputBox.value = "ZOWEUSR2(JOB05037) - CC 0000";
createInputBoxSpy.mockReturnValue(mockInputBox);
globalMocks.mockShowQuickPick.mockReturnValueOnce("Go to Local Filtering");
const filterJobsSpy = jest.spyOn(testTree, "filterJobsDialog");
await testTree.filterJobsDialog(node1);
expect(filterJobsSpy).toHaveBeenCalled();
expect(filterJobsSpy).toBeCalledWith(node1);
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ describe("Test src/jobs/extension", () => {
onDidChangeConfiguration: jest.fn(),
pollData: jest.fn(),
refreshElement: jest.fn(),
filterJobsDialog: jest.fn(),
};
const commands: IJestIt[] = [
{
Expand Down Expand Up @@ -219,6 +220,10 @@ describe("Test src/jobs/extension", () => {
mock: [{ spy: jest.spyOn(jobActions, "cancelJobs"), arg: [jobsProvider, [exampleData.job]] }],
parm: [exampleData.job],
},
{
name: "zowe.jobs.filterJobs",
mock: [{ spy: jest.spyOn(jobsProvider, "filterJobsDialog"), arg: [test.value] }],
},
];

beforeAll(async () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,12 @@
"zowe.polling.intervalOption": "Poll interval (in ms) for: {0}",
"zowe.polling.cancelled": "Polling dismissed for {0}; operation cancelled.",
"zowe.polling.statusBar": "$(sync~spin) Polling: {0}...",
"filter.description": "Filter: {0}",
"filterJobs.message": "Use the search button to display jobs",
"filterJobs.placeholder": "Set a filter...",
"filter.cleared": "$(check) Filter cleared for {0}",
"filterJobs.prompt.message": "Enter local filter...",
"filter.updated": "$(check) Filter updated for {0}",
"zosJobsProvider.specifyCriteria": "Create new...",
"zosJobsProvider.option.submit": "$(check) Submit this query"
}
4 changes: 3 additions & 1 deletion packages/zowe-explorer/i18n/sample/src/job/utils.i18n.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,7 @@
"jobs.sortByDateSubmitted": "$(calendar) Date Submitted",
"jobs.sortByName": "$(case-sensitive) Job Name",
"jobs.sortByReturnCode": "$(symbol-numeric) Return Code",
"setSortDirection": "$(fold) Sort Direction"
"setSortDirection": "$(fold) Sort Direction",
"filterJobs.quickpick.message": "Go to Local Filtering",
"filterJobs.clearProfileFilter": "$(clear-all) Clear filter for profile"
}
16 changes: 16 additions & 0 deletions packages/zowe-explorer/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -766,6 +766,12 @@
"title": "%cancelJobs%",
"category": "Zowe Explorer"
},
{
"command": "zowe.jobs.filterJobs",
"title": "Filter Jobs",
"category": "Zowe Explorer",
"icon": "$(list-filter)"
},
{
"command": "zowe.jobs.search",
"title": "%jobs.search%",
Expand Down Expand Up @@ -1229,6 +1235,11 @@
"command": "zowe.jobs.removeSearchFavorite",
"group": "inline"
},
{
"when": "view == zowe.jobs.explorer && viewItem =~ /^(?!.*_fav.*)server.*/ && !listMultiSelection",
"command": "zowe.jobs.filterJobs",
"group": "inline"
},
{
"when": "view == zowe.jobs.explorer && viewItem =~ /^(?!.*_fav.*)server.*/ && !listMultiSelection",
"command": "zowe.jobs.search",
Expand Down Expand Up @@ -1284,6 +1295,11 @@
"command": "zowe.jobs.addFavorite",
"group": "002_zowe_jobsWorkspace@0"
},
{
"when": "view == zowe.jobs.explorer && viewItem =~ /^(?!.*_fav.*)server.*/ && !listMultiSelection",
"command": "zowe.jobs.filterJobs",
"group": "002_zowe_jobsProfileModification@99"
},
{
"when": "view == zowe.jobs.explorer && viewItem =~ /^job.*_fav.*/",
"command": "zowe.jobs.removeFavorite",
Expand Down
2 changes: 1 addition & 1 deletion packages/zowe-explorer/src/globals.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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 = 115;
export const COMMAND_COUNT = 116;
export const MAX_SEARCH_HISTORY = 5;
export const MAX_FILE_HISTORY = 10;
export const MS_PER_SEC = 1000;
Expand Down
62 changes: 62 additions & 0 deletions packages/zowe-explorer/src/job/ZosJobsProvider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@ import SpoolProvider, { encodeJobFile } from "../SpoolProvider";
import { Poller } from "@zowe/zowe-explorer-api/src/utils";
import { PollDecorator } from "../utils/DecorationProviders";
import { TreeViewUtils } from "../utils/TreeViewUtils";
import { TreeProviders } from "../shared/TreeProviders";
import { JOB_FILTER_OPTS } from "./utils";

// Set up localization
nls.config({
Expand Down Expand Up @@ -1158,6 +1160,66 @@ export class ZosJobsProvider extends ZoweTreeProvider implements IZoweTree<IZowe
this.nodeDataChanged(session);
}
}

/**
* Updates or resets the filter for a given job.
* @param job The job whose filter should be updated/reset
* @param newFilter Either a valid `JobFilter` object, or `null` to reset the filter
* @param isSession Whether the node is a session
*/
public updateFilterForJob(job: IZoweJobTreeNode, newFilter: string | null, isSession: boolean): void {
job.filter = newFilter;
job.description = newFilter ? localize("filter.description", "Filter: {0}", newFilter) : null;
this.nodeDataChanged(job);
if (newFilter === null) {
job["children"] = job["actualJobs"];
TreeProviders.job.refresh();
}
}

public async filterJobsDialog(job: IZoweJobTreeNode): Promise<vscode.InputBox> {
if (job.collapsibleState === vscode.TreeItemCollapsibleState.Collapsed) {
Gui.infoMessage(localize("filterJobs.message", "Use the search button to display jobs"));
return;
}
const selection = await Gui.showQuickPick(JOB_FILTER_OPTS, {
placeHolder: localize("filterJobs.placeholder", "Set a filter..."),
});
const filterMethod = JOB_FILTER_OPTS.indexOf(selection);

const isSession = contextually.isSession(job);
const userDismissed = filterMethod < 0;
if (userDismissed || selection === "$(clear-all) Clear filter for profile") {
if (selection === "$(clear-all) Clear filter for profile") {
this.updateFilterForJob(job, null, isSession);
Gui.setStatusBarMessage(localize("filter.cleared", "$(check) Filter cleared for {0}", job.label as string), globals.MS_PER_SEC * 4);
}
return;
}
if (!("filter" in job) && !("actualJobs" in job)) {
job.actualJobs = job["children"];
}
this.nodeDataChanged(job);

job.description = "";
const actual_jobs: IZoweJobTreeNode[] = job["actualJobs"];
const inputBox = await vscode.window.createInputBox();
inputBox.placeholder = localize("filterJobs.prompt.message", "Enter local filter...");
inputBox.onDidChangeValue((query) => {
query = query.toUpperCase();
job["children"] = actual_jobs.filter((item) => `${item["job"].jobname}(${item["job"].jobid}) - ${item["job"].retcode}`.includes(query));
TreeProviders.job.refresh();
this.updateFilterForJob(job, query, isSession);
Gui.setStatusBarMessage(localize("filter.updated", "$(check) Filter updated for {0}", job.label as string), globals.MS_PER_SEC * 4);
});
job.children = actual_jobs;
this.nodeDataChanged(job);
inputBox.onDidAccept(() => {
inputBox.hide();
});
inputBox.show();
return inputBox;
}
}

/**
Expand Down
6 changes: 6 additions & 0 deletions packages/zowe-explorer/src/job/init.ts
Original file line number Diff line number Diff line change
Expand Up @@ -172,6 +172,12 @@ export async function initJobsProvider(context: vscode.ExtensionContext): Promis
})
);
context.subscriptions.push(vscode.commands.registerCommand("zowe.jobs.sortBy", async (job) => jobActions.sortJobs(job, jobsProvider)));
context.subscriptions.push(
vscode.commands.registerCommand(
"zowe.jobs.filterJobs",
async (job: IZoweJobTreeNode): Promise<vscode.InputBox> => jobsProvider.filterJobsDialog(job)
)
);
initSubscribers(context, jobsProvider);
return jobsProvider;
}
5 changes: 5 additions & 0 deletions packages/zowe-explorer/src/job/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,11 @@ export const JOB_SORT_KEYS: Record<JobSortOpts, keyof (IJob & { "exec-submitted"
[JobSortOpts.ReturnCode]: "retcode",
};

export const JOB_FILTER_OPTS = [
localize("filterJobs.quickpick.message", "Go to Local Filtering"),
localize("filterJobs.clearProfileFilter", "$(clear-all) Clear filter for profile"),
];

export async function resolveQuickPickHelper(quickpick): Promise<FilterItem | undefined> {
ZoweLogger.trace("job.utils.resolveQuickPickHelper called.");
return new Promise<FilterItem | undefined>((c) => {
Expand Down

0 comments on commit c8f80bd

Please sign in to comment.