Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Sorting of PDS members by date created #2707

Merged
merged 8 commits into from
Feb 15, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions packages/zowe-explorer-api/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@ All notable changes to the "zowe-explorer-api" extension will be documented in t
- Added new functions `loginWithBaseProfile` and `logoutWithBaseProfile` to provide extenders with the ability to automatically login to their respective services. [#2493](https://github.com/zowe/vscode-extension-for-zowe/pull/2493)
- Added APIML dynamic token support. [#2665](https://github.com/zowe/vscode-extension-for-zowe/issues/2665)
- Added new optional method `getCommonApi` to `ZoweExplorerApi.IApiRegisterClient` for enhanced typings in other Zowe Explorer APIs. [#2493](https://github.com/zowe/vscode-extension-for-zowe/pull/2493)
- Add Created Date to `stats` optional variable for storing dataset stats
- Add Date created to DatasetSortOpts enum [#2707](https://github.com/zowe/vscode-extension-for-zowe/pull/2707)

### Bug fixes

Expand Down
2 changes: 2 additions & 0 deletions packages/zowe-explorer-api/src/tree/IZoweTreeNode.ts
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,8 @@ export interface IZoweTreeNode {

export type DatasetStats = {
user: string;
//built from "c4date" variable from the z/OSMF API response
createdDate: Date;
// built from "m4date", "mtime" and "msec" variables from z/OSMF API response
modifiedDate: Date;
};
Expand Down
1 change: 1 addition & 0 deletions packages/zowe-explorer-api/src/tree/sorting.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@

export enum DatasetSortOpts {
Name,
DateCreated,
LastModified,
UserId,
}
Expand Down
2 changes: 2 additions & 0 deletions packages/zowe-explorer/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ All notable changes to the "vscode-extension-for-zowe" extension will be documen

### New features and enhancements

- Implemented sorting of PDS members by date created [#2707](https://github.com/zowe/vscode-extension-for-zowe/pull/2707)

### Bug fixes

- Adjusted order of 'Manage Profile' and 'Edit History' in the jobs tree's context menu to match the other trees. [#2670](https://github.com/zowe/vscode-extension-for-zowe/issues/2670)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2965,21 +2965,21 @@ describe("Dataset Tree Unit Tests - Sorting and Filtering operations", () => {
parentNode: pds,
session: createISession(),
});
nodeA.stats = { user: "someUser", modifiedDate: new Date() };
nodeA.stats = { user: "someUser", createdDate: new Date(), modifiedDate: new Date() };
const nodeB = new ZoweDatasetNode({
label: "B",
collapsibleState: vscode.TreeItemCollapsibleState.Collapsed,
parentNode: pds,
session: createISession(),
});
nodeB.stats = { user: "anotherUser", modifiedDate: new Date("2022-01-01T12:00:00") };
nodeB.stats = { user: "anotherUser", createdDate: new Date("2021-01-01T12:00:00"), modifiedDate: new Date("2022-01-01T12:00:00") };
const nodeC = new ZoweDatasetNode({
label: "C",
collapsibleState: vscode.TreeItemCollapsibleState.Collapsed,
parentNode: pds,
session: createISession(),
});
nodeC.stats = { user: "someUser", modifiedDate: new Date("2022-03-15T16:30:00") };
nodeC.stats = { user: "someUser", createdDate: new Date("2022-02-01T12:00:00"), modifiedDate: new Date("2022-03-15T16:30:00") };
pds.children = [nodeA, nodeB, nodeC];
pds.sort = {
method: DatasetSortOpts.Name,
Expand Down Expand Up @@ -3044,6 +3044,61 @@ describe("Dataset Tree Unit Tests - Sorting and Filtering operations", () => {
expect(nodes.pds.children?.reduce((val, cur) => val + (cur.description as string), "")).toBe("");
});

it("sorts by created date", async () => {
const mocks = getBlockMocks();
const nodes = nodesForSuite();
nodes.pds.sort = {
method: DatasetSortOpts.Name,
direction: SortDirection.Descending,
};
mocks.showQuickPick.mockResolvedValueOnce({ label: "$(calendar) Date Created" });
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", "C", "B"]);
});

it("sorts by created date: handling 2 nodes with same date", async () => {
const mocks = getBlockMocks();
const nodes = nodesForSuite();
nodes.pds.sort = {
method: DatasetSortOpts.Name,
direction: SortDirection.Descending,
};
// insert node with same date modified
const nodeD = new ZoweDatasetNode({
label: "D",
collapsibleState: vscode.TreeItemCollapsibleState.Collapsed,
parentNode: nodes.pds,
session: createISession(),
});
nodeD.stats = { user: "someUser", createdDate: new Date("2021-01-01T12:00:00"), modifiedDate: new Date("2022-03-15T16:30:00") };
nodes.pds.children = [...(nodes.pds.children ?? []), nodeD];
mocks.showQuickPick.mockResolvedValueOnce({ label: "$(calendar) Date Created" });
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", "C", "D", "B"]);
});

it("sorts by created date: handling a invalid date", async () => {
const mocks = getBlockMocks();
const nodes = nodesForSuite();
// insert node with same date modified
const nodeD = new ZoweDatasetNode({
label: "D",
collapsibleState: vscode.TreeItemCollapsibleState.Collapsed,
parentNode: nodes.pds,
session: createISession(),
});
nodeD.stats = { user: "someUser", createdDate: new Date("not a valid date"), modifiedDate: new Date("2022-03-15T16:30:00") };
nodes.pds.children = [...(nodes.pds.children ?? []), nodeD];
mocks.showQuickPick.mockResolvedValueOnce({ label: "$(calendar) Date Created" });
await tree.sortPdsMembersDialog(nodes.pds);
expect(mocks.nodeDataChanged).toHaveBeenCalled();
expect(mocks.refreshElement).not.toHaveBeenCalled();
});

it("sorts by last modified date", async () => {
const mocks = getBlockMocks();
const nodes = nodesForSuite();
Expand All @@ -3067,7 +3122,7 @@ describe("Dataset Tree Unit Tests - Sorting and Filtering operations", () => {
parentNode: nodes.pds,
session: createISession(),
});
nodeD.stats = { user: "someUser", modifiedDate: new Date("2022-03-15T16:30:00") };
nodeD.stats = { user: "someUser", createdDate: new Date("2021-01-01T12:00:00"), modifiedDate: new Date("2022-03-15T16:30:00") };
nodes.pds.children = [...(nodes.pds.children ?? []), nodeD];
await tree.sortPdsMembersDialog(nodes.pds);
expect(mocks.nodeDataChanged).toHaveBeenCalled();
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
{
"ds.sortByName": "$(case-sensitive) Name (default)",
"ds.sortByDateCreated": "$(calendar) Date Created",
"ds.sortByModified": "$(calendar) Date Modified",
"ds.sortByUserId": "$(account) User ID",
"setSortDirection": "$(fold) Sort Direction"
Expand Down
84 changes: 57 additions & 27 deletions packages/zowe-explorer/src/dataset/ZoweDatasetNode.ts
Original file line number Diff line number Diff line change
Expand Up @@ -112,16 +112,18 @@
}

public updateStats(item: any): void {
if ("m4date" in item) {
if ("c4date" in item && "m4date" in item) {
const { m4date, mtime, msec }: { m4date: string; mtime: string; msec: string } = item;
this.stats = {
user: item.user,
createdDate: dayjs(item.c4date).toDate(),
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,
createdDate: item.created ? dayjs(item.created).toDate() : undefined,
modifiedDate: item.changed ? dayjs(item.changed).toDate() : undefined,
};
}
Expand All @@ -132,7 +134,7 @@
*
* @returns {Promise<ZoweDatasetNode[]>}
*/
public async getChildren(): Promise<ZoweDatasetNode[]> {

Check warning on line 137 in packages/zowe-explorer/src/dataset/ZoweDatasetNode.ts

View workflow job for this annotation

GitHub Actions / lint

Async method 'getChildren' has a complexity of 35. Maximum allowed is 15
ZoweLogger.trace("ZoweDatasetNode.getChildren called.");
if (!this.pattern && contextually.isSessionNotFav(this)) {
return [
Expand Down Expand Up @@ -310,7 +312,7 @@
* @returns A function that sorts 2 nodes based on the given sorting method
*/
public static sortBy(sort: NodeSort): (a: IZoweDatasetTreeNode, b: IZoweDatasetTreeNode) => number {
return (a, b): number => {

Check warning on line 315 in packages/zowe-explorer/src/dataset/ZoweDatasetNode.ts

View workflow job for this annotation

GitHub Actions / lint

Arrow function has a complexity of 30. Maximum allowed is 15
const aParent = a.getParent();
if (aParent == null || !contextually.isPds(aParent)) {
return (a.label as string) < (b.label as string) ? -1 : 1;
Expand All @@ -326,45 +328,73 @@
return sortByName(a, b);
}

if (sort.method === DatasetSortOpts.LastModified) {
const dateA = dayjs(a.stats?.modifiedDate ?? null);
const dateB = dayjs(b.stats?.modifiedDate ?? null);
switch (sort.method) {
case DatasetSortOpts.DateCreated: {
const dateA = dayjs(a.stats?.createdDate ?? null);
const dateB = dayjs(b.stats?.createdDate ?? null);

const aValid = dateA.isValid();
const bValid = dateB.isValid();
const aVaild = dateA.isValid();
const bValid = dateB.isValid();

a.description = aValid ? dateA.format("YYYY/MM/DD HH:mm:ss") : undefined;
b.description = bValid ? dateB.format("YYYY/MM/DD HH:mm:ss") : undefined;
a.description = aVaild ? dateA.format("YYYY/MM/DD") : undefined;
b.description = bValid ? dateB.format("YYYY/MM/DD") : undefined;

if (!aValid) {
return sortGreaterThan;
}
if (!aVaild) {
return sortGreaterThan;
}

if (!bValid) {
return sortLessThan;

Check warning on line 347 in packages/zowe-explorer/src/dataset/ZoweDatasetNode.ts

View check run for this annotation

Codecov / codecov/patch

packages/zowe-explorer/src/dataset/ZoweDatasetNode.ts#L347

Added line #L347 was not covered by tests
}

if (dateA.isSame(dateB, "second")) {
return sortByName(a, b);
}

if (!bValid) {
return sortLessThan;
return dateA.isBefore(dateB, "second") ? sortLessThan : sortGreaterThan;
}
case DatasetSortOpts.LastModified: {
const dateA = dayjs(a.stats?.modifiedDate ?? null);
const dateB = dayjs(b.stats?.modifiedDate ?? null);

// for dates that are equal down to the second, fallback to sorting by name
if (dateA.isSame(dateB, "second")) {
return sortByName(a, b);
const aValid = dateA.isValid();
const bValid = dateB.isValid();

a.description = aValid ? dateA.format("YYYY/MM/DD HH:mm:ss") : undefined;
b.description = bValid ? dateB.format("YYYY/MM/DD HH:mm:ss") : undefined;

if (!aValid) {
return sortGreaterThan;

Check warning on line 367 in packages/zowe-explorer/src/dataset/ZoweDatasetNode.ts

View check run for this annotation

Codecov / codecov/patch

packages/zowe-explorer/src/dataset/ZoweDatasetNode.ts#L367

Added line #L367 was not covered by tests
}

if (!bValid) {
return sortLessThan;

Check warning on line 371 in packages/zowe-explorer/src/dataset/ZoweDatasetNode.ts

View check run for this annotation

Codecov / codecov/patch

packages/zowe-explorer/src/dataset/ZoweDatasetNode.ts#L371

Added line #L371 was not covered by tests
}

// 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;
}
case DatasetSortOpts.UserId: {
const userA = a.stats?.user ?? "";
const userB = b.stats?.user ?? "";

return dateA.isBefore(dateB, "second") ? sortLessThan : sortGreaterThan;
} else if (sort.method === DatasetSortOpts.UserId) {
const userA = a.stats?.user ?? "";
const userB = b.stats?.user ?? "";
a.description = userA;
b.description = userB;

a.description = userA;
b.description = userB;
if (userA === userB) {
return sortByName(a, b);
}

if (userA === userB) {
return userA < userB ? sortLessThan : sortGreaterThan;
}
default: {
return sortByName(a, b);
}

return userA < userB ? sortLessThan : sortGreaterThan;
}

return sortByName(a, b);
};
}

Expand Down Expand Up @@ -466,7 +496,7 @@
return responses;
}

public async openDs(forceDownload: boolean, previewMember: boolean, datasetProvider: IZoweTree<IZoweDatasetTreeNode>): Promise<void> {

Check warning on line 499 in packages/zowe-explorer/src/dataset/ZoweDatasetNode.ts

View workflow job for this annotation

GitHub Actions / lint

Async method 'openDs' has a complexity of 21. Maximum allowed is 15
ZoweLogger.trace("ZoweDatasetNode.openDs called.");
await datasetProvider.checkCurrentProfile(this);

Expand Down
1 change: 1 addition & 0 deletions packages/zowe-explorer/src/dataset/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ const localize: nls.LocalizeFunc = nls.loadMessageBundle();

export const DATASET_SORT_OPTS = [
localize("ds.sortByName", "$(case-sensitive) Name (default)"),
localize("ds.sortByDateCreated", "$(calendar) Date Created"),
localize("ds.sortByModified", "$(calendar) Date Modified"),
localize("ds.sortByUserId", "$(account) User ID"),
localize("setSortDirection", "$(fold) Sort Direction"),
Expand Down
Loading