Skip to content

Commit

Permalink
[Power Pages][Actions Hub] Add revealInOS command for current active …
Browse files Browse the repository at this point in the history
…site and update translations (#1131)
  • Loading branch information
priyanshu92 authored Feb 19, 2025
1 parent 8b4cb46 commit 467c97e
Show file tree
Hide file tree
Showing 8 changed files with 170 additions and 20 deletions.
9 changes: 9 additions & 0 deletions loc/translations-export/vscode-powerplatform.xlf
Original file line number Diff line number Diff line change
Expand Up @@ -735,6 +735,9 @@ The second line should be '[TRANSLATION HERE](command:pacCLI.authPanel.newAuthPr
<note>This is a Markdown formatted string, and the formatting must persist across translations.
The second line should be '[TRANSLATION HERE](command:powerplatform-walkthrough.overview-learn-more)', keeping brackets and the text in the parentheses unmodified</note>
</trans-unit>
<trans-unit id="microsoft.powerplatform.pages.actionsHub.currentActiveSite.revealInOS.linux.title">
<source xml:lang="en">Open Containing Folder</source>
</trans-unit>
<trans-unit id="pacCLI.openPacLab.title">
<source xml:lang="en">Open PAC Lab</source>
</trans-unit>
Expand Down Expand Up @@ -775,6 +778,12 @@ The second line should be '[TRANSLATION HERE](command:powerplatform-walkthrough.
<trans-unit id="pacCLI.authPanel.refresh.title">
<source xml:lang="en">Refresh</source>
</trans-unit>
<trans-unit id="microsoft.powerplatform.pages.actionsHub.currentActiveSite.revealInOS.windows.title">
<source xml:lang="en">Reveal in Explorer</source>
</trans-unit>
<trans-unit id="microsoft.powerplatform.pages.actionsHub.currentActiveSite.revealInOS.mac.title">
<source xml:lang="en">Reveal in Finder</source>
</trans-unit>
<trans-unit id="microsoft-powerapps-portals.walkthrough.saveConflict.title">
<source xml:lang="en">Save conflict</source>
</trans-unit>
Expand Down
39 changes: 39 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -419,6 +419,18 @@
{
"command": "microsoft.powerplatform.pages.actionsHub.newAuthProfile",
"title": "%microsoft.powerplatform.pages.actionsHub.login.title%"
},
{
"command": "microsoft.powerplatform.pages.actionsHub.currentActiveSite.revealInOS.windows",
"title": "%microsoft.powerplatform.pages.actionsHub.currentActiveSite.revealInOS.windows.title%"
},
{
"command": "microsoft.powerplatform.pages.actionsHub.currentActiveSite.revealInOS.mac",
"title": "%microsoft.powerplatform.pages.actionsHub.currentActiveSite.revealInOS.mac.title%"
},
{
"command": "microsoft.powerplatform.pages.actionsHub.currentActiveSite.revealInOS.linux",
"title": "%microsoft.powerplatform.pages.actionsHub.currentActiveSite.revealInOS.linux.title%"
}
],
"configuration": {
Expand Down Expand Up @@ -883,6 +895,18 @@
{
"command": "microsoft.powerplatform.pages.actionsHub.activeSite.preview",
"when": "never"
},
{
"command": "microsoft.powerplatform.pages.actionsHub.currentActiveSite.revealInOS.windows",
"when": "never"
},
{
"command": "microsoft.powerplatform.pages.actionsHub.currentActiveSite.revealInOS.mac",
"when": "never"
},
{
"command": "microsoft.powerplatform.pages.actionsHub.currentActiveSite.revealInOS.linux",
"when": "never"
}
],
"view/title": [
Expand Down Expand Up @@ -1010,6 +1034,21 @@
"command": "microsoft.powerplatform.pages.actionsHub.activeSite.preview",
"when": "view == microsoft.powerplatform.pages.actionsHub && (viewItem == currentActiveSite || viewItem == nonCurrentActiveSite)",
"group": "activeSiteContextMenuGroup@1"
},
{
"command": "microsoft.powerplatform.pages.actionsHub.currentActiveSite.revealInOS.windows",
"when": "view == microsoft.powerplatform.pages.actionsHub && viewItem == currentActiveSite && isWindows",
"group": "activeSiteContextMenuGroup@2"
},
{
"command": "microsoft.powerplatform.pages.actionsHub.currentActiveSite.revealInOS.mac",
"when": "view == microsoft.powerplatform.pages.actionsHub && viewItem == currentActiveSite && isMac",
"group": "activeSiteContextMenuGroup@2"
},
{
"command": "microsoft.powerplatform.pages.actionsHub.currentActiveSite.revealInOS.linux",
"when": "view == microsoft.powerplatform.pages.actionsHub && viewItem == currentActiveSite && isLinux",
"group": "activeSiteContextMenuGroup@2"
}
]
},
Expand Down
5 changes: 4 additions & 1 deletion package.nls.json
Original file line number Diff line number Diff line change
Expand Up @@ -105,5 +105,8 @@
"The second line should be '[TRANSLATION HERE](command:powerpages.actionsHub.newAuthProfile).', keeping brackets and the text in the parentheses unmodified"
]
},
"microsoft.powerplatform.pages.actionsHub.login.title": "Add New Auth Profile"
"microsoft.powerplatform.pages.actionsHub.login.title": "Add New Auth Profile",
"microsoft.powerplatform.pages.actionsHub.currentActiveSite.revealInOS.windows.title": "Reveal in Explorer",
"microsoft.powerplatform.pages.actionsHub.currentActiveSite.revealInOS.mac.title": "Reveal in Finder",
"microsoft.powerplatform.pages.actionsHub.currentActiveSite.revealInOS.linux.title": "Open Containing Folder"
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import { dataverseAuthentication } from '../../../common/services/Authentication
import { createAuthProfileExp } from '../../../common/utilities/PacAuthUtil';
import { IWebsiteDetails } from '../../../common/services/Interfaces';
import { getActiveWebsites, getAllWebsites } from '../../../common/utilities/WebsiteUtil';
import CurrentSiteContext from './CurrentSiteContext';

export const refreshEnvironment = async (pacTerminal: PacTerminal) => {
const pacWrapper = pacTerminal.getWrapper();
Expand Down Expand Up @@ -221,3 +222,9 @@ export const fetchWebsites = async (): Promise<{ activeSites: IWebsiteDetails[],

return { activeSites: [], inactiveSites: [] };
}

export const revealInOS = async () => {
if (CurrentSiteContext.currentSiteFolderPath) {
await vscode.commands.executeCommand('revealFileInOS', vscode.Uri.file(CurrentSiteContext.currentSiteFolderPath));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import { oneDSLoggerWrapper } from "../../../common/OneDSLoggerTelemetry/oneDSLo
import { EnvironmentGroupTreeItem } from "./tree-items/EnvironmentGroupTreeItem";
import { IEnvironmentInfo } from "./models/IEnvironmentInfo";
import { PacTerminal } from "../../lib/PacTerminal";
import { fetchWebsites, openActiveSitesInStudio, openInactiveSitesInStudio, previewSite, createNewAuthProfile, refreshEnvironment, showEnvironmentDetails, switchEnvironment } from "./ActionsHubCommandHandlers";
import { fetchWebsites, openActiveSitesInStudio, openInactiveSitesInStudio, previewSite, createNewAuthProfile, refreshEnvironment, showEnvironmentDetails, switchEnvironment, revealInOS } from "./ActionsHubCommandHandlers";
import PacContext from "../../pac/PacContext";
import CurrentSiteContext from "./CurrentSiteContext";
import { IWebsiteDetails } from "../../../common/services/Interfaces";
Expand Down Expand Up @@ -115,6 +115,10 @@ export class ActionsHubTreeDataProvider implements vscode.TreeDataProvider<Actio
vscode.commands.registerCommand("powerpages.actionsHub.newAuthProfile", async () => {
await createNewAuthProfile(pacTerminal.getWrapper());
}),

vscode.commands.registerCommand("microsoft.powerplatform.pages.actionsHub.currentActiveSite.revealInOS.windows", revealInOS),
vscode.commands.registerCommand("microsoft.powerplatform.pages.actionsHub.currentActiveSite.revealInOS.mac", revealInOS),
vscode.commands.registerCommand("microsoft.powerplatform.pages.actionsHub.currentActiveSite.revealInOS.linux", revealInOS)
];
}
}
29 changes: 19 additions & 10 deletions src/client/power-pages/actions-hub/CurrentSiteContext.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,23 +9,28 @@ import { findWebsiteYmlFolder, getWebsiteRecordId } from '../../../common/utilit

interface ICurrentSiteContext {
currentSiteId: string | null;
currentSiteFolderPath: string | null;
}

class CurrentSiteContext implements ICurrentSiteContext {
private _currentSiteId: string | null = null;
private _currentSiteFolderPath: string | null = null;
private _disposables: vscode.Disposable[] = [];
private readonly _onChanged = new vscode.EventEmitter<string | null>();
private readonly _onChanged = new vscode.EventEmitter<ICurrentSiteContext>();
public readonly onChanged = this._onChanged.event;

constructor() {
this._currentSiteId = this.getCurrentSiteId();
const { currentSiteId, currentSiteFolderPath } = this.getCurrentSiteInfo();
this._currentSiteId = currentSiteId;
this._currentSiteFolderPath = currentSiteFolderPath;

this._disposables.push(
vscode.window.onDidChangeActiveTextEditor(() => {
const newSiteId = this.getCurrentSiteId();
if (newSiteId !== this._currentSiteId) {
this._currentSiteId = newSiteId;
this._onChanged.fire(newSiteId);
const newSiteInfo = this.getCurrentSiteInfo();
if (newSiteInfo.currentSiteId !== this._currentSiteId) {
this._currentSiteId = newSiteInfo.currentSiteId;
this._currentSiteFolderPath = newSiteInfo.currentSiteFolderPath;
this._onChanged.fire(newSiteInfo);
}
})
);
Expand All @@ -35,12 +40,16 @@ class CurrentSiteContext implements ICurrentSiteContext {
return this._currentSiteId;
}

public get currentSiteFolderPath(): string | null {
return this._currentSiteFolderPath;
}

public dispose() {
this._onChanged.dispose();
this._disposables.forEach(d => d.dispose());
}

private getCurrentSiteId(): string | null {
private getCurrentSiteInfo(): ICurrentSiteContext {
const activeEditor = vscode.window.activeTextEditor;
if (activeEditor) {
const filePath = activeEditor.document.uri.fsPath;
Expand All @@ -50,18 +59,18 @@ class CurrentSiteContext implements ICurrentSiteContext {
if (websiteYmlFolder) {
const siteId = getWebsiteRecordId(websiteYmlFolder);
if (siteId) {
return siteId;
return { currentSiteId: siteId, currentSiteFolderPath: websiteYmlFolder };
}
}
}

// Fallback: check first workspace folder
const workspaceFolders = vscode.workspace.workspaceFolders;
if (workspaceFolders && workspaceFolders.length > 0) {
return getWebsiteRecordId(workspaceFolders[0].uri.fsPath);
return { currentSiteId: getWebsiteRecordId(workspaceFolders[0].uri.fsPath), currentSiteFolderPath: workspaceFolders[0].uri.fsPath };
}

return null;
return { currentSiteId: null, currentSiteFolderPath: null };
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
import { expect } from 'chai';
import * as sinon from 'sinon';
import * as vscode from 'vscode';
import { showEnvironmentDetails, refreshEnvironment, switchEnvironment, openActiveSitesInStudio, openInactiveSitesInStudio, createNewAuthProfile, previewSite, fetchWebsites } from '../../../../power-pages/actions-hub/ActionsHubCommandHandlers';
import { showEnvironmentDetails, refreshEnvironment, switchEnvironment, openActiveSitesInStudio, openInactiveSitesInStudio, createNewAuthProfile, previewSite, fetchWebsites, revealInOS } from '../../../../power-pages/actions-hub/ActionsHubCommandHandlers';
import { Constants } from '../../../../power-pages/actions-hub/Constants';
import { oneDSLoggerWrapper } from '../../../../../common/OneDSLoggerTelemetry/oneDSLoggerWrapper';
import * as CommonUtils from '../../../../power-pages/commonUtility';
Expand All @@ -25,6 +25,7 @@ import { WebsiteStatus } from '../../../../power-pages/actions-hub/models/Websit
import { IWebsiteInfo } from '../../../../power-pages/actions-hub/models/IWebsiteInfo';
import * as WebsiteUtils from '../../../../../common/utilities/WebsiteUtil';
import * as Utils from '../../../../../common/utilities/Utils';
import CurrentSiteContext from '../../../../power-pages/actions-hub/CurrentSiteContext';

describe('ActionsHubCommandHandlers', () => {
let sandbox: sinon.SinonSandbox;
Expand Down Expand Up @@ -704,4 +705,31 @@ describe('ActionsHubCommandHandlers', () => {
expect(response.inactiveSites).to.deep.equal(inactiveSites);
});
});

describe('revealInOS', () => {
let executeCommandStub: sinon.SinonStub;

beforeEach(() => {
executeCommandStub = sinon.stub(vscode.commands, 'executeCommand');
});

afterEach(() => {
executeCommandStub.restore();
});

it('should not reveal file in OS when file path is not provided', async () => {
sinon.stub(CurrentSiteContext, 'currentSiteFolderPath').get(() => undefined);
await revealInOS();

expect(executeCommandStub.called).to.be.false;
});

it('should reveal file in OS when file path is provided', async () => {
const mockPath = 'test-path';
sinon.stub(CurrentSiteContext, 'currentSiteFolderPath').get(() => mockPath);
await revealInOS();

expect(executeCommandStub.calledOnceWith('revealFileInOS', vscode.Uri.file(mockPath))).to.be.true;
});
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -55,53 +55,104 @@ describe("ActionsHubTreeDataProvider", () => {
});

describe('initialize', () => {
it("should register refresh command", () => {
it("should register refresh command", async () => {
const mockCommandHandler = sinon.stub(CommandHandlers, 'refreshEnvironment');
mockCommandHandler.resolves();
const actionsHubTreeDataProvider = ActionsHubTreeDataProvider.initialize(context, pacTerminal);
actionsHubTreeDataProvider["registerPanel"](pacTerminal);

expect(registerCommandStub.calledWith("microsoft.powerplatform.pages.actionsHub.refresh")).to.be.true;

await registerCommandStub.getCall(0).args[1]();
expect(mockCommandHandler.calledOnce).to.be.true;
});

it("should register switchEnvironment command", () => {
it("should register switchEnvironment command", async () => {
const mockCommandHandler = sinon.stub(CommandHandlers, 'switchEnvironment');
mockCommandHandler.resolves();
const actionsHubTreeDataProvider = ActionsHubTreeDataProvider.initialize(context, pacTerminal);
actionsHubTreeDataProvider["registerPanel"](pacTerminal);

expect(registerCommandStub.calledWith("microsoft.powerplatform.pages.actionsHub.switchEnvironment")).to.be.true;

await registerCommandStub.getCall(1).args[1]();
expect(mockCommandHandler.calledOnce).to.be.true;
});

it("should register showEnvironmentDetails command", () => {
it("should register showEnvironmentDetails command", async () => {
const mockCommandHandler = sinon.stub(CommandHandlers, 'showEnvironmentDetails');
mockCommandHandler.resolves();
const actionsHubTreeDataProvider = ActionsHubTreeDataProvider.initialize(context, pacTerminal);
actionsHubTreeDataProvider["registerPanel"](pacTerminal);

expect(registerCommandStub.calledWith("microsoft.powerplatform.pages.actionsHub.showEnvironmentDetails")).to.be.true;

await registerCommandStub.getCall(2).args[1]();
expect(mockCommandHandler.calledOnce).to.be.true;
});

it("should register openActiveSitesInStudio command", () => {
it("should register openActiveSitesInStudio command", async () => {
const mockCommandHandler = sinon.stub(CommandHandlers, 'openActiveSitesInStudio');
mockCommandHandler.resolves();
const actionsHubTreeDataProvider = ActionsHubTreeDataProvider.initialize(context, pacTerminal);
actionsHubTreeDataProvider["registerPanel"](pacTerminal);

expect(registerCommandStub.calledWith("microsoft.powerplatform.pages.actionsHub.openActiveSitesInStudio")).to.be.true;

await registerCommandStub.getCall(3).args[1]();
expect(mockCommandHandler.calledOnce).to.be.true;
});

it("should register openInactiveSitesInStudio command", () => {
it("should register openInactiveSitesInStudio command", async () => {
const mockCommandHandler = sinon.stub(CommandHandlers, 'openInactiveSitesInStudio');
mockCommandHandler.resolves();
const actionsHubTreeDataProvider = ActionsHubTreeDataProvider.initialize(context, pacTerminal);
actionsHubTreeDataProvider["registerPanel"](pacTerminal);

expect(registerCommandStub.calledWith("microsoft.powerplatform.pages.actionsHub.openInactiveSitesInStudio")).to.be.true;

await registerCommandStub.getCall(4).args[1]();
expect(mockCommandHandler.calledOnce).to.be.true;
});

it("should register preview command", () => {
it("should register preview command", async () => {
const mockCommandHandler = sinon.stub(CommandHandlers, 'previewSite');
mockCommandHandler.resolves();
const actionsHubTreeDataProvider = ActionsHubTreeDataProvider.initialize(context, pacTerminal);
actionsHubTreeDataProvider["registerPanel"](pacTerminal);

expect(registerCommandStub.calledWith("microsoft.powerplatform.pages.actionsHub.activeSite.preview")).to.be.true;

await registerCommandStub.getCall(5).args[1]();
expect(mockCommandHandler.calledOnce).to.be.true;
});

it("should register newAuthProfile command", () => {
it("should register newAuthProfile command", async () => {
const mockCommandHandler = sinon.stub(CommandHandlers, 'createNewAuthProfile');
mockCommandHandler.resolves();
const actionsHubTreeDataProvider = ActionsHubTreeDataProvider.initialize(context, pacTerminal);
actionsHubTreeDataProvider["registerPanel"](pacTerminal);

expect(registerCommandStub.calledWith("powerpages.actionsHub.newAuthProfile")).to.be.true;

await registerCommandStub.getCall(6).args[1]();
expect(mockCommandHandler.calledOnce).to.be.true;
});

it("should register revealInOS commands", async () => {
const mockCommandHandler = sinon.stub(CommandHandlers, 'revealInOS');
mockCommandHandler.resolves();
const actionsHubTreeDataProvider = ActionsHubTreeDataProvider.initialize(context, pacTerminal);
actionsHubTreeDataProvider["registerPanel"](pacTerminal);

expect(registerCommandStub.calledWith("microsoft.powerplatform.pages.actionsHub.currentActiveSite.revealInOS.windows")).to.be.true;
expect(registerCommandStub.calledWith("microsoft.powerplatform.pages.actionsHub.currentActiveSite.revealInOS.mac")).to.be.true;
expect(registerCommandStub.calledWith("microsoft.powerplatform.pages.actionsHub.currentActiveSite.revealInOS.linux")).to.be.true;

await registerCommandStub.getCall(7).args[1]();
await registerCommandStub.getCall(8).args[1]();
await registerCommandStub.getCall(9).args[1]();
expect(mockCommandHandler.calledThrice).to.be.true;
});
});

Expand Down

0 comments on commit 467c97e

Please sign in to comment.