From 02dc099d9b1a73581e31e2da9b8e9005c283c388 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 29 Aug 2025 10:46:52 +0000 Subject: [PATCH 1/4] Initial plan From fb482c862acfbab0d98ec0ee350f97d7d3db279c Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 29 Aug 2025 10:58:27 +0000 Subject: [PATCH 2/4] Fix login button in Power Pages Actions with proper user feedback Co-authored-by: amitjoshi438 <54068463+amitjoshi438@users.noreply.github.com> --- .../actions-hub/ActionsHubCommandHandlers.ts | 19 ++++++++++-- .../ActionsHubCommandHandlers.test.ts | 30 +++++++++++++++---- src/common/services/AuthenticationProvider.ts | 6 +++- 3 files changed, 46 insertions(+), 9 deletions(-) diff --git a/src/client/power-pages/actions-hub/ActionsHubCommandHandlers.ts b/src/client/power-pages/actions-hub/ActionsHubCommandHandlers.ts index 072768169..f217c967b 100644 --- a/src/client/power-pages/actions-hub/ActionsHubCommandHandlers.ts +++ b/src/client/power-pages/actions-hub/ActionsHubCommandHandlers.ts @@ -211,6 +211,8 @@ export const createNewAuthProfile = async (pacWrapper: PacWrapper): Promise { let mockCreateAuthProfileExp: sinon.SinonStub; let mockAuthenticationInVsCode: sinon.SinonStub; let orgInfoStub: sinon.SinonStub; + let mockShowInformationMessage: sinon.SinonStub; + let mockShowErrorMessage: sinon.SinonStub; beforeEach(() => { mockPacWrapper = sandbox.createStubInstance(PacWrapper); mockCreateAuthProfileExp = sandbox.stub(PacAuthUtil, 'createAuthProfileExp'); mockAuthenticationInVsCode = sandbox.stub(authProvider, 'authenticateUserInVSCode'); orgInfoStub = sandbox.stub(PacContext, 'OrgInfo').value({ OrgId: 'testOrgId', OrgUrl: '' }); + mockShowInformationMessage = sandbox.stub(vscode.window, 'showInformationMessage'); + mockShowErrorMessage = sandbox.stub(vscode.window, 'showErrorMessage'); }); - it('should only authenticate in VS Code when PAC auth output is successful', async () => { + it('should only authenticate in VS Code when PAC auth output is successful and show success message', async () => { const mockResults = [{ ActiveOrganization: [null, null] }]; mockCreateAuthProfileExp.resolves({ Status: 'Success', Results: mockResults }); orgInfoStub.value({ OrgId: 'testOrgId', OrgUrl: 'https://test-org-url' }); @@ -561,9 +565,10 @@ describe('ActionsHubCommandHandlers', () => { expect(mockCreateAuthProfileExp.calledOnce).to.be.false; expect(mockAuthenticationInVsCode.calledOnce).to.be.true; + expect(mockShowInformationMessage.calledOnce).to.be.true; }); - it('should handle missing organization URL', async () => { + it('should handle missing organization URL and show error message', async () => { const mockResults = [{ ActiveOrganization: [null, null] }]; mockCreateAuthProfileExp.resolves({ Status: 'Success', Results: mockResults }); @@ -573,9 +578,10 @@ describe('ActionsHubCommandHandlers', () => { expect(mockAuthenticationInVsCode.called).to.be.false; expect(traceErrorStub.calledOnce).to.be.true; expect(traceErrorStub.firstCall.args[0]).to.equal('createNewAuthProfile'); + expect(mockShowErrorMessage.calledOnce).to.be.true; }); - it('should handle empty results array', async () => { + it('should handle empty results array and show error message', async () => { mockCreateAuthProfileExp.resolves({ Status: 'Success', Results: [] }); await createNewAuthProfile(mockPacWrapper); @@ -584,9 +590,10 @@ describe('ActionsHubCommandHandlers', () => { expect(mockAuthenticationInVsCode.called).to.be.false; expect(traceErrorStub.calledOnce).to.be.true; expect(traceErrorStub.firstCall.args[0]).to.equal('createNewAuthProfile'); + expect(mockShowErrorMessage.calledOnce).to.be.true; }); - it('should handle PAC auth output failure', async () => { + it('should handle PAC auth output failure and show error message', async () => { mockCreateAuthProfileExp.resolves({ Status: 'Failed', Results: null }); await createNewAuthProfile(mockPacWrapper); @@ -595,9 +602,10 @@ describe('ActionsHubCommandHandlers', () => { expect(mockAuthenticationInVsCode.called).to.be.false; expect(traceErrorStub.calledOnce).to.be.true; expect(traceErrorStub.firstCall.args[0]).to.equal('createNewAuthProfile'); + expect(mockShowErrorMessage.calledOnce).to.be.true; }); - it('should handle errors during auth profile creation', async () => { + it('should handle errors during auth profile creation and show error message', async () => { const error = new Error('Test error'); mockCreateAuthProfileExp.rejects(error); @@ -607,6 +615,18 @@ describe('ActionsHubCommandHandlers', () => { expect(mockAuthenticationInVsCode.called).to.be.false; expect(traceErrorStub.calledOnce).to.be.true; expect(traceErrorStub.firstCall.args[0]).to.equal('ActionsHubCreateAuthProfileFailed'); + expect(mockShowErrorMessage.calledOnce).to.be.true; + }); + + it('should authenticate and show success message when orgUrl exists and auth profile has organization', async () => { + const mockResults = [{ ActiveOrganization: { Item2: 'https://test-org.com' } }]; + mockCreateAuthProfileExp.resolves({ Status: 'Success', Results: mockResults }); + + await createNewAuthProfile(mockPacWrapper); + + expect(mockCreateAuthProfileExp.calledOnce).to.be.true; + expect(mockAuthenticationInVsCode.calledOnce).to.be.true; + expect(mockShowInformationMessage.calledOnce).to.be.true; }); }); diff --git a/src/common/services/AuthenticationProvider.ts b/src/common/services/AuthenticationProvider.ts index 0e1b6e3e9..cc9558189 100644 --- a/src/common/services/AuthenticationProvider.ts +++ b/src/common/services/AuthenticationProvider.ts @@ -367,7 +367,11 @@ export async function authenticateUserInVSCode(isSilent = false): Promise } else { const isAuthenticated = await authenticateUserInternal(true); if (!isAuthenticated) { - await authenticateUserInternal(false); + const secondAttempt = await authenticateUserInternal(false); + if (!secondAttempt) { + // If both attempts failed and it's not a silent call, inform the user + throw new Error(vscode.l10n.t("Authentication failed. Please try again or check your internet connection.")); + } } } } From ed941e3b49b519609baae025dc391580098e095e Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 29 Aug 2025 11:02:25 +0000 Subject: [PATCH 3/4] Complete login button fix with tests and documentation Co-authored-by: amitjoshi438 <54068463+amitjoshi438@users.noreply.github.com> --- POWER_PAGES_LOGIN_FIX.md | 43 ++++++++ .../actions-hub/LoginButtonFeedback.test.ts | 99 +++++++++++++++++++ 2 files changed, 142 insertions(+) create mode 100644 POWER_PAGES_LOGIN_FIX.md create mode 100644 src/client/test/Integration/power-pages/actions-hub/LoginButtonFeedback.test.ts diff --git a/POWER_PAGES_LOGIN_FIX.md b/POWER_PAGES_LOGIN_FIX.md new file mode 100644 index 000000000..8556a3a55 --- /dev/null +++ b/POWER_PAGES_LOGIN_FIX.md @@ -0,0 +1,43 @@ +# Login Button Fix - Power Pages Actions + +## Issue Summary +The login button in the Power Pages Actions section of VS Code was not providing any feedback to users when clicked, making it appear as if nothing was happening. This was particularly problematic when authentication failed. + +## Root Cause +The `createNewAuthProfile` function in `ActionsHubCommandHandlers.ts` only logged errors to telemetry without showing user-visible messages. When authentication failed or encountered issues, users received no feedback. + +## Solution +Enhanced the authentication flow to provide comprehensive user feedback: + +### 1. Success Notifications +- Added success messages when authentication completes successfully +- Users now see "Authentication completed successfully" when login works + +### 2. Specific Error Messages +- **Missing organization URL**: "Authentication failed: Organization URL is missing." +- **Empty authentication results**: "Authentication failed: No authentication results returned." +- **Profile creation failure**: "Authentication failed: Unable to create authentication profile." +- **General errors**: "Authentication failed: [specific error message]" + +### 3. Enhanced Error Handling +- Improved `authenticateUserInVSCode` function to throw descriptive errors +- Maintained backward compatibility for silent authentication calls +- Better error propagation for user-facing scenarios + +## Files Modified +- `src/client/power-pages/actions-hub/ActionsHubCommandHandlers.ts` +- `src/common/services/AuthenticationProvider.ts` +- `src/client/test/Integration/power-pages/actions-hub/ActionsHubCommandHandlers.test.ts` + +## Testing +- Enhanced existing test cases to verify user notification functionality +- Added new test file `LoginButtonFeedback.test.ts` for comprehensive feedback testing +- Verified both success and error scenarios provide appropriate user feedback + +## User Experience Improvement +Users will now receive immediate feedback when: +- ✅ Authentication succeeds +- ❌ Authentication fails with specific error details +- ⚠️ Configuration issues prevent authentication + +This eliminates the confusion of silent failures and provides clear guidance on next steps. \ No newline at end of file diff --git a/src/client/test/Integration/power-pages/actions-hub/LoginButtonFeedback.test.ts b/src/client/test/Integration/power-pages/actions-hub/LoginButtonFeedback.test.ts new file mode 100644 index 000000000..17ff6ceef --- /dev/null +++ b/src/client/test/Integration/power-pages/actions-hub/LoginButtonFeedback.test.ts @@ -0,0 +1,99 @@ +/* + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + */ + +import { expect } from 'chai'; +import * as sinon from 'sinon'; +import * as vscode from 'vscode'; +import { createNewAuthProfile } from '../../../../power-pages/actions-hub/ActionsHubCommandHandlers'; +import { PacWrapper } from '../../../../pac/PacWrapper'; +import * as authProvider from '../../../../../common/services/AuthenticationProvider'; +import * as PacAuthUtil from '../../../../../common/utilities/PacAuthUtil'; +import PacContext from '../../../../pac/PacContext'; + +describe('Login Button User Feedback Tests', () => { + let sandbox: sinon.SinonSandbox; + let mockShowInformationMessage: sinon.SinonStub; + let mockShowErrorMessage: sinon.SinonStub; + let mockPacWrapper: sinon.SinonStubbedInstance; + let mockCreateAuthProfileExp: sinon.SinonStub; + let mockAuthenticationInVsCode: sinon.SinonStub; + let orgInfoStub: sinon.SinonStub; + + beforeEach(() => { + sandbox = sinon.createSandbox(); + mockShowInformationMessage = sandbox.stub(vscode.window, 'showInformationMessage'); + mockShowErrorMessage = sandbox.stub(vscode.window, 'showErrorMessage'); + mockPacWrapper = sandbox.createStubInstance(PacWrapper); + mockCreateAuthProfileExp = sandbox.stub(PacAuthUtil, 'createAuthProfileExp'); + mockAuthenticationInVsCode = sandbox.stub(authProvider, 'authenticateUserInVSCode'); + orgInfoStub = sandbox.stub(PacContext, 'OrgInfo').value({ OrgId: 'testOrgId', OrgUrl: '' }); + }); + + afterEach(() => { + sandbox.restore(); + }); + + it('should show success message when login is successful', async () => { + // Arrange: Set up successful authentication scenario + orgInfoStub.value({ OrgId: 'testOrgId', OrgUrl: 'https://test-org-url' }); + mockAuthenticationInVsCode.resolves(); + + // Act: Call the login function + await createNewAuthProfile(mockPacWrapper); + + // Assert: Verify success message is shown + expect(mockShowInformationMessage.calledOnce).to.be.true; + expect(mockShowErrorMessage.called).to.be.false; + }); + + it('should show error message when authentication fails', async () => { + // Arrange: Set up authentication failure scenario + const error = new Error('Authentication failed'); + mockAuthenticationInVsCode.rejects(error); + orgInfoStub.value({ OrgId: 'testOrgId', OrgUrl: 'https://test-org-url' }); + + // Act: Call the login function + await createNewAuthProfile(mockPacWrapper); + + // Assert: Verify error message is shown + expect(mockShowErrorMessage.calledOnce).to.be.true; + expect(mockShowInformationMessage.called).to.be.false; + }); + + it('should show error message when organization URL is missing', async () => { + // Arrange: Set up scenario with missing org URL + const mockResults = [{ ActiveOrganization: { Item2: null } }]; + mockCreateAuthProfileExp.resolves({ Status: 'Success', Results: mockResults }); + + // Act: Call the login function + await createNewAuthProfile(mockPacWrapper); + + // Assert: Verify error message is shown + expect(mockShowErrorMessage.calledOnce).to.be.true; + expect(mockShowInformationMessage.called).to.be.false; + }); + + it('should provide user feedback for any authentication scenario', async () => { + // Test success scenario + orgInfoStub.value({ OrgId: 'testOrgId', OrgUrl: 'https://test-org-url' }); + mockAuthenticationInVsCode.resolves(); + + await createNewAuthProfile(mockPacWrapper); + + // Verify user gets feedback + const userGotFeedback = mockShowInformationMessage.called || mockShowErrorMessage.called; + expect(userGotFeedback).to.be.true; + + // Reset for error scenario + mockShowInformationMessage.reset(); + mockShowErrorMessage.reset(); + mockCreateAuthProfileExp.resolves({ Status: 'Failed', Results: null }); + + await createNewAuthProfile(mockPacWrapper); + + // Verify user gets error feedback + expect(mockShowErrorMessage.called).to.be.true; + }); +}); \ No newline at end of file From 2cee291e7644d9394b732fdbc2b369b3437a4de2 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 29 Aug 2025 11:03:57 +0000 Subject: [PATCH 4/4] Fix login button in Power Pages Actions not providing user feedback Co-authored-by: amitjoshi438 <54068463+amitjoshi438@users.noreply.github.com> --- EXPECTED_USER_EXPERIENCE.md | 39 +++++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) create mode 100644 EXPECTED_USER_EXPERIENCE.md diff --git a/EXPECTED_USER_EXPERIENCE.md b/EXPECTED_USER_EXPERIENCE.md new file mode 100644 index 000000000..9a26e770b --- /dev/null +++ b/EXPECTED_USER_EXPERIENCE.md @@ -0,0 +1,39 @@ + + +# Expected User Experience After Fix + +## Before the Fix: +- User clicks "Login" button in Power Pages Actions +- ❌ Nothing happens - no feedback whatsoever +- User is confused and may click multiple times +- No indication if authentication succeeded or failed + +## After the Fix: + +### Success Scenario: +1. User clicks "Login" button in Power Pages Actions +2. Authentication dialog appears (VS Code's built-in authentication) +3. User completes authentication +4. ✅ **Success message appears**: "Authentication completed successfully." +5. Power Pages Actions tree refreshes with user's environments and sites + +### Error Scenarios: +1. User clicks "Login" button +2. If authentication fails: + - ❌ **Clear error message appears** with specific details: + - "Authentication failed: Organization URL is missing." + - "Authentication failed: No authentication results returned." + - "Authentication failed: Unable to create authentication profile." + - "Authentication failed: [specific error message]" +3. User understands what went wrong and can take appropriate action + +### Key Improvements: +- **Immediate feedback** - User always knows something happened +- **Clear error messages** - Specific guidance on what went wrong +- **Success confirmation** - User knows when authentication worked +- **Professional UX** - No more silent failures or confusion + +The login button now provides the professional, responsive experience users expect from VS Code extensions. \ No newline at end of file