Skip to content

Commit 8a4f1c1

Browse files
priyanshu92claude
andcommitted
Add Clear Cache command for Active Sites in Actions Hub
- Add ClearCacheHandler to clear site cache from context menu - Register command for currentActiveSite and nonCurrentActiveSite - Add optional progressTitle parameter to PreviewSite.clearCache - Add CLEARING_SITE_CACHE message for standalone command - Add telemetry events and success notification - Add unit tests for ClearCacheHandler Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
1 parent 3c2a714 commit 8a4f1c1

8 files changed

Lines changed: 127 additions & 3 deletions

File tree

package.json

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -464,6 +464,10 @@
464464
"command": "microsoft.powerplatform.pages.actionsHub.activeSite.preview",
465465
"title": "%microsoft.powerplatform.pages.actionsHub.activeSite.previewSite.title%"
466466
},
467+
{
468+
"command": "microsoft.powerplatform.pages.actionsHub.activeSite.clearCache",
469+
"title": "%microsoft.powerplatform.pages.actionsHub.activeSite.clearCache.title%"
470+
},
467471
{
468472
"command": "microsoft.powerplatform.pages.actionsHub.newAuthProfile",
469473
"title": "%microsoft.powerplatform.pages.actionsHub.login.title%"
@@ -1153,6 +1157,10 @@
11531157
"command": "microsoft.powerplatform.pages.actionsHub.activeSite.preview",
11541158
"when": "never"
11551159
},
1160+
{
1161+
"command": "microsoft.powerplatform.pages.actionsHub.activeSite.clearCache",
1162+
"when": "never"
1163+
},
11561164
{
11571165
"command": "microsoft.powerplatform.pages.actionsHub.currentActiveSite.revealInOS.windows",
11581166
"when": "never"
@@ -1384,6 +1392,11 @@
13841392
"when": "view == microsoft.powerplatform.pages.actionsHub && (viewItem == currentActiveSite || viewItem == nonCurrentActiveSite)",
13851393
"group": "siteAction@1"
13861394
},
1395+
{
1396+
"command": "microsoft.powerplatform.pages.actionsHub.activeSite.clearCache",
1397+
"when": "view == microsoft.powerplatform.pages.actionsHub && (viewItem == currentActiveSite || viewItem == nonCurrentActiveSite)",
1398+
"group": "siteAction@1"
1399+
},
13871400
{
13881401
"command": "microsoft.powerplatform.pages.actionsHub.activeSite.uploadSite",
13891402
"when": "view == microsoft.powerplatform.pages.actionsHub && (viewItem == currentActiveSite || viewItem == otherSite)",

package.nls.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,7 @@
9898
"microsoft.powerplatform.pages.actionsHub.showEnvironmentDetails.title": "Show Environment Details",
9999
"microsoft.powerplatform.pages.actionsHub.openSitesInStudio.title": "Open in Power Pages Studio",
100100
"microsoft.powerplatform.pages.actionsHub.activeSite.previewSite.title": "Preview",
101+
"microsoft.powerplatform.pages.actionsHub.activeSite.clearCache.title": "Clear Cache",
101102
"microsoft.powerplatform.pages.actionsHub.login": {
102103
"message": "Login and connect to a Power Pages environment to use Power Pages actions. [Learn more](https://go.microsoft.com/fwlink/?linkid=2305702).\n[Login](command:microsoft.powerplatform.pages.actionsHub.newAuthProfile)",
103104
"comment": [

src/client/power-pages/actions-hub/ActionsHubTreeDataProvider.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ import { runCodeQLScreening } from "./handlers/code-ql/RunCodeQlScreeningHandler
1717
import { revealInOS } from "./handlers/RevealInOSHandler";
1818
import { createNewAuthProfile } from "./handlers/CreateNewAuthProfileHandler";
1919
import { previewSite } from "./handlers/PreviewSiteHandler";
20+
import { clearCache } from "./handlers/ClearCacheHandler";
2021
import { openActiveSitesInStudio, openInactiveSitesInStudio, openSiteInStudio } from "./handlers/OpenSiteInStudioHandler";
2122
import { switchEnvironment } from "./handlers/SwitchEnvironmentHandler";
2223
import { showEnvironmentDetails } from "./handlers/ShowEnvironmentDetailsHandler";
@@ -332,6 +333,8 @@ export class ActionsHubTreeDataProvider implements vscode.TreeDataProvider<Actio
332333

333334
vscode.commands.registerCommand("microsoft.powerplatform.pages.actionsHub.activeSite.preview", previewSite),
334335

336+
vscode.commands.registerCommand("microsoft.powerplatform.pages.actionsHub.activeSite.clearCache", clearCache),
337+
335338
vscode.commands.registerCommand("microsoft.powerplatform.pages.actionsHub.newAuthProfile", async () => {
336339
await createNewAuthProfile(this._pacTerminal.getWrapper());
337340
}),

src/client/power-pages/actions-hub/Constants.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,7 @@ export const Constants = {
103103
// CodeQL
104104
INSTALL: vscode.l10n.t("Install"),
105105
CANCEL: vscode.l10n.t("Cancel"),
106+
CLEAR_CACHE_SUCCESS: vscode.l10n.t("Cache cleared successfully."),
106107
CODEQL_EXTENSION_NOT_INSTALLED: vscode.l10n.t("The CodeQL extension is required to run this command. Do you want to install it now?"),
107108
CODEQL_SCREENING_STARTED: vscode.l10n.t("CodeQL screening started. Creating database and analyzing"),
108109
CODEQL_DATABASE_CREATED: vscode.l10n.t("CodeQL database created successfully. You can now run queries from the CodeQL extension."),
@@ -533,6 +534,8 @@ export const Constants = {
533534
ACTIONS_HUB_OPEN_INACTIVE_SITES_IN_STUDIO_FAILED: "ActionsHubOpenInactiveSitesInStudioFailed",
534535
ACTIONS_HUB_PREVIEW_SITE_CALLED: "ActionsHubPreviewSiteCalled",
535536
ACTIONS_HUB_PREVIEW_SITE_FAILED: "ActionsHubPreviewSiteFailed",
537+
ACTIONS_HUB_CLEAR_CACHE_CALLED: "ActionsHubClearCacheCalled",
538+
ACTIONS_HUB_CLEAR_CACHE_FAILED: "ActionsHubClearCacheFailed",
536539
ACTIONS_HUB_CREATE_AUTH_PROFILE_CALLED: "ActionsHubCreateAuthProfileCalled",
537540
ACTIONS_HUB_CREATE_AUTH_PROFILE_FAILED: "ActionsHubCreateAuthProfileFailed",
538541
ACTIONS_HUB_FETCH_WEBSITES_CALLED: "ActionsHubFetchWebsitesCalled",
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
/*
2+
* Copyright (c) Microsoft Corporation. All rights reserved.
3+
* Licensed under the MIT License. See License.txt in the project root for license information.
4+
*/
5+
6+
import { SiteTreeItem } from "../tree-items/SiteTreeItem";
7+
import { Constants } from "../Constants";
8+
import { traceError, traceInfo } from "../TelemetryHelper";
9+
import { PreviewSite } from "../../preview-site/PreviewSite";
10+
import { Messages } from "../../preview-site/Constants";
11+
import * as vscode from "vscode";
12+
13+
export const clearCache = async (siteTreeItem: SiteTreeItem) => {
14+
traceInfo(Constants.EventNames.ACTIONS_HUB_CLEAR_CACHE_CALLED, { methodName: clearCache.name });
15+
try {
16+
await PreviewSite.clearCache(siteTreeItem.siteInfo.websiteUrl, Messages.CLEARING_SITE_CACHE);
17+
await vscode.window.showInformationMessage(Constants.Strings.CLEAR_CACHE_SUCCESS);
18+
} catch (error) {
19+
traceError(Constants.EventNames.ACTIONS_HUB_CLEAR_CACHE_FAILED, error as Error, { methodName: clearCache.name });
20+
}
21+
};

src/client/power-pages/preview-site/Constants.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ export const Messages = {
2828
"The second line should be '[TRANSLATION HERE](https://aka.ms/pages-clear-cache).', keeping brackets and the text in the parentheses unmodified"
2929
]
3030
}),
31+
CLEARING_SITE_CACHE: vscode.l10n.t("Clearing site cache"),
3132
AUTHENTICATING: vscode.l10n.t("Authenticating..."),
3233
UNABLE_TO_CLEAR_CACHE: vscode.l10n.t("Unable to clear cache"),
3334
PREVIEW_WARNING: vscode.l10n.t("Your preview isn't updated. Please upload your site to see the latest changes."),

src/client/power-pages/preview-site/PreviewSite.ts

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -219,7 +219,7 @@ export class PreviewSite {
219219
);
220220
}
221221

222-
public static async clearCache(websiteUrl: string | undefined): Promise<void> {
222+
public static async clearCache(websiteUrl: string | undefined, progressTitle?: string): Promise<void> {
223223
if (!websiteUrl) {
224224
return;
225225
}
@@ -233,9 +233,11 @@ export class PreviewSite {
233233
const requestUrl = `${websiteUrl.endsWith('/') ? websiteUrl : websiteUrl.concat('/')}_services/cache/config`;
234234

235235
await showProgressWithNotification(
236-
Messages.INITIALIZING_PREVIEW,
236+
progressTitle ?? Messages.INITIALIZING_PREVIEW,
237237
async (progress) => {
238-
progress.report({ message: Messages.CLEARING_CACHE });
238+
if (!progressTitle) {
239+
progress.report({ message: Messages.CLEARING_CACHE });
240+
}
239241

240242
const authResponse = await dataverseAuthentication(orgDetails.OrgUrl);
241243

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
/*
2+
* Copyright (c) Microsoft Corporation. All rights reserved.
3+
* Licensed under the MIT License. See License.txt in the project root for license information.
4+
*/
5+
6+
import { expect } from 'chai';
7+
import * as sinon from 'sinon';
8+
import * as vscode from 'vscode';
9+
import { clearCache } from '../../../../../power-pages/actions-hub/handlers/ClearCacheHandler';
10+
import { PreviewSite } from '../../../../../power-pages/preview-site/PreviewSite';
11+
import { SiteTreeItem } from '../../../../../power-pages/actions-hub/tree-items/SiteTreeItem';
12+
import { WebsiteStatus } from '../../../../../power-pages/actions-hub/models/WebsiteStatus';
13+
import { IWebsiteInfo } from '../../../../../power-pages/actions-hub/models/IWebsiteInfo';
14+
import { SiteVisibility } from '../../../../../power-pages/actions-hub/models/SiteVisibility';
15+
import { Messages } from '../../../../../power-pages/preview-site/Constants';
16+
import * as TelemetryHelper from '../../../../../power-pages/actions-hub/TelemetryHelper';
17+
18+
describe('ClearCacheHandler', () => {
19+
let sandbox: sinon.SinonSandbox;
20+
let traceErrorStub: sinon.SinonStub;
21+
let traceInfoStub: sinon.SinonStub;
22+
23+
beforeEach(() => {
24+
sandbox = sinon.createSandbox();
25+
traceErrorStub = sandbox.stub(TelemetryHelper, 'traceError');
26+
sandbox.stub(TelemetryHelper, "getBaseEventInfo").returns({ foo: 'bar' });
27+
traceInfoStub = sandbox.stub(TelemetryHelper, "traceInfo");
28+
sandbox.stub(vscode.env, 'sessionId').get(() => 'test-session-id');
29+
});
30+
31+
afterEach(() => {
32+
sandbox.restore();
33+
});
34+
35+
describe('clearCache', () => {
36+
let mockPreviewSiteClearCache: sinon.SinonStub;
37+
let mockShowInformationMessage: sinon.SinonStub;
38+
let mockSiteInfo: IWebsiteInfo;
39+
40+
beforeEach(() => {
41+
mockPreviewSiteClearCache = sandbox.stub(PreviewSite, 'clearCache');
42+
mockShowInformationMessage = sandbox.stub(vscode.window, 'showInformationMessage');
43+
mockSiteInfo = {
44+
name: "Test Site",
45+
websiteId: "test-id",
46+
dataModelVersion: 1,
47+
status: WebsiteStatus.Active,
48+
websiteUrl: 'https://test-site.com',
49+
isCurrent: false,
50+
siteVisibility: SiteVisibility.Public,
51+
siteManagementUrl: 'https://test-site-management.com',
52+
createdOn: "2025-03-20",
53+
creator: "Test Creator",
54+
isCodeSite: false
55+
};
56+
});
57+
58+
it('should clear cache with correct progress title and show success message', async () => {
59+
const siteTreeItem = new SiteTreeItem(mockSiteInfo);
60+
61+
await clearCache(siteTreeItem);
62+
63+
expect(traceInfoStub.calledOnce).to.be.true;
64+
expect(mockPreviewSiteClearCache.calledOnce).to.be.true;
65+
expect(mockPreviewSiteClearCache.calledWith('https://test-site.com', Messages.CLEARING_SITE_CACHE)).to.be.true;
66+
expect(mockShowInformationMessage.calledOnce).to.be.true;
67+
});
68+
69+
it('should handle errors and log telemetry', async () => {
70+
const error = new Error('Test error');
71+
mockPreviewSiteClearCache.rejects(error);
72+
const siteTreeItem = new SiteTreeItem(mockSiteInfo);
73+
74+
await clearCache(siteTreeItem);
75+
76+
expect(traceErrorStub.calledOnce).to.be.true;
77+
expect(mockShowInformationMessage.called).to.be.false;
78+
});
79+
});
80+
});

0 commit comments

Comments
 (0)