Skip to content

Commit

Permalink
Merge branch 'main' into ci/fix-merge-by-post
Browse files Browse the repository at this point in the history
  • Loading branch information
traeok authored Oct 17, 2024
2 parents 879e250 + c4f772e commit 5593518
Show file tree
Hide file tree
Showing 67 changed files with 1,156 additions and 566 deletions.
4 changes: 4 additions & 0 deletions packages/zowe-explorer-api/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,10 @@ All notable changes to the "zowe-explorer-api" extension will be documented in t

### New features and enhancements

- Zowe Explorer now includes support for the [VS Code display languages](https://code.visualstudio.com/docs/getstarted/locales) French, German, Japanese, Portuguese, and Spanish.
- Localization of strings within the webviews. [#2983](https://github.com/zowe/zowe-explorer-vscode/issues/2983)
- Update Zowe SDKs to `8.2.0` to get the latest enhancements from Imperative.

### Bug fixes

## `3.0.1`
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,9 @@ import { Table, TableBuilder, WebView } from "../../../../src";
import { env, EventEmitter, Uri, window } from "vscode";
import * as crypto from "crypto";
import { diff } from "deep-object-diff";
import * as fs from "fs";

jest.mock("fs");
function createGlobalMocks() {
const mockPanel = {
dispose: jest.fn(),
Expand All @@ -23,6 +25,10 @@ function createGlobalMocks() {
};
// Mock `vscode.window.createWebviewPanel` to return a usable panel object
const createWebviewPanelMock = jest.spyOn(window, "createWebviewPanel").mockReturnValueOnce(mockPanel as any);
const spyReadFile = jest.fn((path, encoding, callback) => {
callback(null, "file contents");
});
Object.defineProperty(fs, "readFile", { value: spyReadFile, configurable: true });

return {
createWebviewPanelMock,
Expand Down Expand Up @@ -273,6 +279,18 @@ describe("Table.View", () => {
globalMocks.updateWebviewMock.mockRestore();
});

it("should handle the case where 'GET_LOCALIZATION' is the command sent", async () => {
const globalMocks = await createGlobalMocks();
const view = new Table.View(globalMocks.context as any, false, { title: "Table" } as any);
const postMessageSpy = jest.spyOn(view.panel.webview, "postMessage");
await view.onMessageReceived({ command: "GET_LOCALIZATION" });
expect(postMessageSpy).toHaveBeenCalledWith({
command: "GET_LOCALIZATION",
contents: "file contents",
});
globalMocks.updateWebviewMock.mockRestore();
});

it("calls vscode.env.clipboard.writeText when handling the 'copy' command", async () => {
const globalMocks = createGlobalMocks();
const view = new Table.View(globalMocks.context as any, { title: "Table w/ copy" } as any);
Expand Down
18 changes: 9 additions & 9 deletions packages/zowe-explorer-api/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -28,15 +28,15 @@
},
"dependencies": {
"@types/vscode": "^1.53.2",
"@zowe/core-for-zowe-sdk": "^8.1.1",
"@zowe/imperative": "^8.1.0",
"@zowe/secrets-for-zowe-sdk": "^8.1.0",
"@zowe/zos-console-for-zowe-sdk": "^8.1.1",
"@zowe/zos-files-for-zowe-sdk": "^8.1.1",
"@zowe/zos-jobs-for-zowe-sdk": "^8.1.1",
"@zowe/zos-tso-for-zowe-sdk": "^8.1.1",
"@zowe/zos-uss-for-zowe-sdk": "^8.1.1",
"@zowe/zosmf-for-zowe-sdk": "^8.1.1",
"@zowe/core-for-zowe-sdk": "^8.2.0",
"@zowe/imperative": "^8.2.0",
"@zowe/secrets-for-zowe-sdk": "^8.1.2",
"@zowe/zos-console-for-zowe-sdk": "^8.2.0",
"@zowe/zos-files-for-zowe-sdk": "^8.2.0",
"@zowe/zos-jobs-for-zowe-sdk": "^8.2.0",
"@zowe/zos-tso-for-zowe-sdk": "^8.2.0",
"@zowe/zos-uss-for-zowe-sdk": "^8.2.0",
"@zowe/zosmf-for-zowe-sdk": "^8.2.0",
"deep-object-diff": "^1.1.9",
"mustache": "^4.2.0",
"semver": "^7.6.0"
Expand Down
6 changes: 3 additions & 3 deletions packages/zowe-explorer-api/src/fs/BaseProvider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,11 +52,11 @@ export class BaseProvider {
}
await vscode.workspace.fs.writeFile(uri.with({ query: "forceUpload=true" }), fsEntry.data);
Gui.setStatusBarMessage(
vscode.l10n.t({
message: "$(check) Overwrite applied for {0}",
`$(check) ${vscode.l10n.t({
message: "Overwrite applied for {0}",
args: [fsEntry.name],
comment: "File name",
}),
})}`,
this.FS_PROVIDER_UI_TIMEOUT
);
fsEntry.conflictData = null;
Expand Down
17 changes: 16 additions & 1 deletion packages/zowe-explorer-api/src/vscode/ui/TableView.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,8 @@ import { Event, EventEmitter, ExtensionContext, env } from "vscode";
import { randomUUID } from "crypto";
import { diff } from "deep-object-diff";
import { TableMediator } from "./utils/TableMediator";

import * as vscode from "vscode";
import * as fs from "fs";
export namespace Table {
/* The types of supported content for the table and how they are represented in callback functions. */
export type ContentTypes = string | number | boolean | string[];
Expand Down Expand Up @@ -360,6 +361,20 @@ export namespace Table {
case "copy-cell":
await env.clipboard.writeText(message.data.cell);
return;
case "GET_LOCALIZATION": {
const filePath = vscode.l10n.uri?.fsPath + "";
fs.readFile(filePath, "utf8", (err, data) => {
if (err) {
// File doesn't exist, fallback to English strings
return;
}
(this.panel ?? this.view).webview.postMessage({
command: "GET_LOCALIZATION",
contents: data,
});
});
return;
}
default:
break;
}
Expand Down
4 changes: 2 additions & 2 deletions packages/zowe-explorer-ftp-extension/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -52,9 +52,9 @@
"vscode": "^1.79.0"
},
"dependencies": {
"@zowe/zos-files-for-zowe-sdk": "^8.1.1",
"@zowe/zos-files-for-zowe-sdk": "^8.2.0",
"@zowe/zos-ftp-for-zowe-cli": "^3.0.0",
"@zowe/zos-jobs-for-zowe-sdk": "^8.1.1",
"@zowe/zos-jobs-for-zowe-sdk": "^8.2.0",
"@zowe/zowe-explorer-api": "3.1.0-SNAPSHOT",
"tmp": "0.2.3"
},
Expand Down
8 changes: 8 additions & 0 deletions packages/zowe-explorer/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,16 @@ All notable changes to the "vscode-extension-for-zowe" extension will be documen

### New features and enhancements

- Zowe Explorer now includes support for the [VS Code display languages](https://code.visualstudio.com/docs/getstarted/locales) French, German, Japanese, Portuguese, and Spanish. Download the respective language pack and switch.
- Localization of strings within the webviews. [#2983](https://github.com/zowe/zowe-explorer-vscode/issues/2983)
- Added expired JSON web token detection for profiles in each tree view (Data Sets, USS, Jobs). When a user performs a search on a profile, they are prompted to log in if their token expired. [#3175](https://github.com/zowe/zowe-explorer-vscode/issues/3175)

### Bug fixes

- Fixed an issue where the contents of an editor did not update when polling spool content or using the "Pull from Mainframe" action with jobs. [#3249](https://github.com/zowe/zowe-explorer-vscode/pull/3249)
- Fixed an issue where Zowe Explorer sometimes prompted the user to convert V1 profiles when changes were made to a team configuration after initialization. [#3246](https://github.com/zowe/zowe-explorer-vscode/pull/3246)
- Fixed an issue where the encoding of a USS file was not automatically detected when opened for the first time. [#3253](https://github.com/zowe/zowe-explorer-vscode/pull/3253)

## `3.0.1`

### Bug fixes
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -407,6 +407,7 @@ export function createInstanceOfProfileInfo() {
profLoc: { locType: 0, osLoc: ["location"], jsonLoc: "jsonLoc" },
},
],
hasTokenExpiredForProfile: jest.fn(),
updateProperty: jest.fn(),
updateKnownProperty: jest.fn(),
createSession: jest.fn(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -351,6 +351,11 @@ async function createGlobalMocks() {
"zowe.automaticProfileValidation": true,
}),
});
jest.spyOn(ProfilesUtils, "getProfileInfo").mockResolvedValue({
getTeamConfig: jest.fn().mockReturnValue({
exists: jest.fn(),
}),
} as any);
Object.defineProperty(globalMocks.mockProfilesCache, "getProfileInfo", {
value: jest.fn(() => {
return { value: globalMocks.mockProfCacheProfileInfo, configurable: true };
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ import { JobInit } from "../../../src/trees/job/JobInit";
import { createIJobObject, createJobSessionNode } from "../../__mocks__/mockCreators/jobs";
import { createDatasetSessionNode } from "../../__mocks__/mockCreators/datasets";
import { DatasetInit } from "../../../src/trees/dataset/DatasetInit";
import { AuthUtils } from "../../../src/utils/AuthUtils";

async function createGlobalMocks() {
Object.defineProperty(ZoweLocalStorage, "storage", {
Expand Down Expand Up @@ -309,6 +310,7 @@ describe("ZoweJobNode unit tests - Function checkCurrentProfile", () => {
testIJob: createIJobObject(),
testJobsProvider: await JobInit.createJobsTree(imperative.Logger.getAppLogger()),
jobNode: null,
checkJwtTokenForProfile: jest.spyOn(ZoweTreeProvider as any, "checkJwtTokenForProfile").mockImplementationOnce(() => {}),
};

newMocks.jobNode = new ZoweJobNode({
Expand Down Expand Up @@ -627,3 +629,53 @@ describe("Tree Provider Unit Tests - function isGlobalProfileNode", () => {
getOsLocInfoMock.mockRestore();
});
});

describe("Tree Provider Unit Tests - function checkJwtTokenForProfile", () => {
function getBlockMocks() {
const getAllProfiles = jest.fn().mockReturnValue([
{
profName: "zosmf",
profType: "zosmf",
isDefaultProfile: false,
profLoc: {
locType: imperative.ProfLocType.TEAM_CONFIG,
osLoc: ["/a/b/c/zowe.config.json"],
jsonLoc: ["profiles.zosmf"],
},
},
]);
const hasTokenExpiredForProfile = jest.fn();
const mergeArgsForProfile = jest.fn();
const profilesGetInstance = jest.spyOn(Profiles, "getInstance").mockReturnValue({
getProfileInfo: jest.fn().mockResolvedValue({
hasTokenExpiredForProfile,
getAllProfiles,
mergeArgsForProfile,
} as any),
} as any);

return {
getAllProfiles,
hasTokenExpiredForProfile,
mergeArgsForProfile,
profilesGetInstance,
};
}

it("returns early if the profile's token has not expired", async () => {
const blockMocks = getBlockMocks();
blockMocks.hasTokenExpiredForProfile.mockReturnValueOnce(false);
blockMocks.mergeArgsForProfile.mockReturnValue({ knownArgs: [{ argName: "tokenType", argValue: "LtpaToken2" }] });
await (ZoweTreeProvider as any).checkJwtTokenForProfile("zosmf");
expect(blockMocks.hasTokenExpiredForProfile).toHaveBeenCalledWith("zosmf");
});

it("prompts the user to log in if a JWT token is present and has expired", async () => {
const blockMocks = getBlockMocks();
blockMocks.hasTokenExpiredForProfile.mockReturnValueOnce(true);
const promptUserForSsoLogin = jest.spyOn(AuthUtils, "promptUserForSsoLogin").mockImplementation();
await (ZoweTreeProvider as any).checkJwtTokenForProfile("zosmf");
expect(blockMocks.hasTokenExpiredForProfile).toHaveBeenCalledWith("zosmf");
expect(promptUserForSsoLogin).toHaveBeenCalled();
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ import { ZoweScheme } from "../../../../../zowe-explorer-api/src/fs/types/abstra
import { Sorting } from "../../../../../zowe-explorer-api/src/tree";
import { IconUtils } from "../../../../src/icons/IconUtils";
import { SharedContext } from "../../../../src/trees/shared/SharedContext";
import { ZoweTreeProvider } from "../../../../src/trees/ZoweTreeProvider";

jest.mock("fs");
jest.mock("util");
Expand Down Expand Up @@ -1495,6 +1496,7 @@ describe("Dataset Tree Unit Tests - Function datasetFilterPrompt", () => {
qpPlaceholder: 'Choose "Create new..." to define a new profile or select an existing profile to add to the Data Set Explorer',
mockEnableValidationContext: jest.fn(),
testTree: new DatasetTree(),
checkJwtTokenForProfile: jest.spyOn(ZoweTreeProvider as any, "checkJwtTokenForProfile").mockImplementationOnce(() => {}),
};

newMocks.datasetSessionNode = createDatasetSessionNode(newMocks.session, newMocks.imperativeProfile);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
*
*/

import { Disposable, FilePermission, FileType, Uri } from "vscode";
import { Disposable, FilePermission, FileType, Uri, window } from "vscode";
import { FsJobsUtils, FilterEntry, Gui, JobEntry, SpoolEntry, ZoweScheme } from "@zowe/zowe-explorer-api";
import { createIProfile } from "../../../__mocks__/mockCreators/shared";
import { createIJobFile, createIJobObject } from "../../../__mocks__/mockCreators/jobs";
Expand Down Expand Up @@ -91,16 +91,22 @@ describe("refreshSpool", () => {
});

it("calls fetchSpoolAtUri for a valid spool node", async () => {
const node = { resourceUri: testUris.spool, contextValue: "spool" } as any;
const editorListMock = new MockedProperty(window, "visibleTextEditors", {
value: [{ document: { uri: testUris.spool } }],
});
const fetchSpoolAtUriMock = jest.spyOn(JobFSProvider.instance, "fetchSpoolAtUri").mockImplementation();
const disposeMock = jest.fn();
const statusBarMsgMock = jest.spyOn(Gui, "setStatusBarMessage").mockReturnValue({ dispose: disposeMock });
const node = { resourceUri: testUris.spool, contextValue: "spool" } as any;
await JobFSProvider.refreshSpool(node);
expect(statusBarMsgMock).toHaveBeenCalledWith("$(sync~spin) Fetching spool file...");
expect(fetchSpoolAtUriMock).toHaveBeenCalledWith(node.resourceUri);
expect(fetchSpoolAtUriMock).toHaveBeenCalledWith(node.resourceUri, {
document: { uri: { path: "/sestest/TESTJOB(JOB1234) - ACTIVE/JES2.JESMSGLG.2", scheme: "zowe-jobs" } },
});
expect(disposeMock).toHaveBeenCalled();
fetchSpoolAtUriMock.mockRestore();
statusBarMsgMock.mockRestore();
editorListMock[Symbol.dispose]();
});
});

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,9 @@ import { Gui } from "@zowe/zowe-explorer-api";
import { Profiles } from "../../../../src/configuration/Profiles";
import { ZoweLocalStorage } from "../../../../src/tools/ZoweLocalStorage";
import { UssFSProvider } from "../../../../src/trees/uss/UssFSProvider";
import * as fs from "fs";

jest.mock("fs");
async function initializeHistoryViewMock(blockMocks: any, globalMocks: any): Promise<SharedHistoryView> {
return new SharedHistoryView(
{
Expand Down Expand Up @@ -67,7 +69,10 @@ function createGlobalMocks(): any {
},
configurable: true,
});

const spyReadFile = jest.fn((path, encoding, callback) => {
callback(null, "file contents");
});
Object.defineProperty(fs, "readFile", { value: spyReadFile, configurable: true });
return globalMocks;
}

Expand Down Expand Up @@ -278,6 +283,39 @@ describe("HistoryView Unit Tests", () => {
expect(historyView["currentSelection"]).toEqual({ ds: "search", jobs: "search", uss: "search" });
expect(resetEncodingHistorySpy).toHaveBeenCalledTimes(2);
});

it("should handle the case where 'GET_LOCALIZATION' 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");
await historyView["onDidReceiveMessage"]({ command: "GET_LOCALIZATION" });
expect(postMessageSpy).toHaveBeenCalledWith({
command: "GET_LOCALIZATION",
contents: "file contents",
});
});

it("if this.panel doesn't exist in GET_LOCALIZATION", async () => {
const globalMocks = await createGlobalMocks();
const blockMocks = createBlockMocks(globalMocks);
const historyView = await initializeHistoryViewMock(blockMocks, globalMocks);
historyView.panel = undefined as any;
await historyView["onDidReceiveMessage"]({ command: "GET_LOCALIZATION" });
expect(historyView.panel).toBeUndefined();
});

it("if read file throwing an error in GET_LOCALIZATION", async () => {
const globalMocks = await createGlobalMocks();
const blockMocks = createBlockMocks(globalMocks);
const spyReadFile = jest.fn((path, encoding, callback) => {
callback("error", "file contents");
});
Object.defineProperty(fs, "readFile", { value: spyReadFile, configurable: true });
const historyView = await initializeHistoryViewMock(blockMocks, globalMocks);
await historyView["onDidReceiveMessage"]({ command: "GET_LOCALIZATION" });
expect(spyReadFile).toHaveBeenCalledTimes(1);
});
});

describe("getHistoryData", () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -421,6 +421,23 @@ describe("Shared utils unit tests - function promptForEncoding", () => {
);
});

it("prompts for encoding for tagged USS binary file", async () => {
const blockMocks = createBlockMocks();
const node = new ZoweUSSNode({
label: "testFile",
collapsibleState: vscode.TreeItemCollapsibleState.None,
session: blockMocks.session,
profile: blockMocks.profile,
parentPath: "/root",
});
node.setEncoding(binaryEncoding);
blockMocks.showQuickPick.mockImplementationOnce(async (items) => items[0]);
const encoding = await SharedUtils.promptForEncoding(node, "binary");
expect(blockMocks.showQuickPick).toHaveBeenCalled();
expect(await blockMocks.showQuickPick.mock.calls[0][0][0]).toEqual({ label: "binary", description: "USS file tag" });
expect(encoding).toEqual({ kind: "binary" });
});

it("prompts for encoding for USS file when profile contains encoding", async () => {
const blockMocks = createBlockMocks();
(blockMocks.profile.profile as any).encoding = "IBM-1047";
Expand Down
Loading

0 comments on commit 5593518

Please sign in to comment.