From f21aefa0463732582604ee62e71882bba0a48f63 Mon Sep 17 00:00:00 2001 From: gshivi <123095952+gshivi@users.noreply.github.com> Date: Thu, 8 Aug 2024 17:15:01 +0530 Subject: [PATCH 1/2] Log AadObjectId for desktop extension telemetry (#1009) * Changed for AAD Id * Updates * Removing extra line * change * Adding null check --------- Co-authored-by: Shivika Gupta --- src/client/extension.ts | 13 ++++++++++++- src/client/pac/PacTypes.ts | 7 +++++++ src/client/pac/PacWrapper.ts | 6 +++++- src/common/OneDSLoggerTelemetry/oneDSLogger.ts | 1 + .../OneDSLoggerTelemetry/telemetryConstants.ts | 2 ++ 5 files changed, 27 insertions(+), 2 deletions(-) diff --git a/src/client/extension.ts b/src/client/extension.ts index 3997797e..df44d599 100644 --- a/src/client/extension.ts +++ b/src/client/extension.ts @@ -41,6 +41,8 @@ import { desktopTelemetryEventNames } from "../common/OneDSLoggerTelemetry/clien import { ArtemisService } from "../common/services/ArtemisService"; import { workspaceContainsPortalConfigFolder } from "../common/utilities/PathFinderUtil"; import { getPortalsOrgURLs } from "../common/utilities/WorkspaceInfoFinderUtil"; +import { SUCCESS } from "../common/constants"; +import { AadIdKey } from "../common/OneDSLoggerTelemetry/telemetryConstants"; let client: LanguageClient; let _context: vscode.ExtensionContext; @@ -191,9 +193,18 @@ export async function activate( const orgID = orgDetails.OrgId; const artemisResponse = await ArtemisService.getArtemisResponse(orgID, _telemetry, ""); if (artemisResponse !== null && artemisResponse.response !== null) { + const pacActiveAuth = await pacTerminal.getWrapper()?.activeAuth(); + let AadIdObject; + if ((pacActiveAuth && pacActiveAuth.Status === SUCCESS)) { + AadIdObject = pacActiveAuth.Results?.filter(obj => obj.Key === AadIdKey); + } const { geoName, geoLongName } = artemisResponse.response; oneDSLoggerWrapper.instantiate(geoName, geoLongName); - oneDSLoggerWrapper.getLogger().traceInfo(desktopTelemetryEventNames.DESKTOP_EXTENSION_INIT_CONTEXT, { ...orgDetails, orgGeo: geoName }); + let initContext: object = { ...orgDetails, orgGeo: geoName }; + if (AadIdObject?.[0]?.Value) { + initContext = { ...initContext, AadId: AadIdObject[0].Value } + } + oneDSLoggerWrapper.getLogger().traceInfo(desktopTelemetryEventNames.DESKTOP_EXTENSION_INIT_CONTEXT, initContext); } }) ); diff --git a/src/client/pac/PacTypes.ts b/src/client/pac/PacTypes.ts index b4960914..d18e62b6 100644 --- a/src/client/pac/PacTypes.ts +++ b/src/client/pac/PacTypes.ts @@ -73,3 +73,10 @@ export type ActiveOrgOutput = { } export type PacOrgWhoOutput = PacOutputWithResult; + +export type ActiveAuthOutput = { + Key: string, + Value: string +} + +export type PacAuthWhoOutput = PacOutputWithResultList; diff --git a/src/client/pac/PacWrapper.ts b/src/client/pac/PacWrapper.ts index 2fd655bb..884b2503 100644 --- a/src/client/pac/PacWrapper.ts +++ b/src/client/pac/PacWrapper.ts @@ -10,7 +10,7 @@ import * as fs from "fs-extra"; import { ChildProcessWithoutNullStreams, spawn } from "child_process"; import { BlockingQueue } from "../../common/utilities/BlockingQueue"; import { ITelemetry } from "../../common/OneDSLoggerTelemetry/telemetry/ITelemetry"; -import { PacOutput, PacAdminListOutput, PacAuthListOutput, PacSolutionListOutput, PacOrgListOutput, PacOrgWhoOutput } from "./PacTypes"; +import { PacOutput, PacAdminListOutput, PacAuthListOutput, PacSolutionListOutput, PacOrgListOutput, PacOrgWhoOutput, PacAuthWhoOutput } from "./PacTypes"; import { v4 } from "uuid"; import { oneDSLoggerWrapper } from "../../common/OneDSLoggerTelemetry/oneDSLoggerWrapper"; @@ -168,6 +168,10 @@ export class PacWrapper { return this.executeCommandAndParseResults(new PacArguments("org", "who")); } + public async activeAuth(): Promise { + return this.executeCommandAndParseResults(new PacArguments("auth", "who")); + } + public async pcfInit(outputDirectory: string): Promise { return this.executeCommandAndParseResults(new PacArguments("pcf", "init", "--outputDirectory", outputDirectory)); } diff --git a/src/common/OneDSLoggerTelemetry/oneDSLogger.ts b/src/common/OneDSLoggerTelemetry/oneDSLogger.ts index 4eb69d43..0402ea8a 100644 --- a/src/common/OneDSLoggerTelemetry/oneDSLogger.ts +++ b/src/common/OneDSLoggerTelemetry/oneDSLogger.ts @@ -380,6 +380,7 @@ export class OneDSLogger implements ITelemetryLogger { OneDSLogger.contextInfo.orgId = JSON.parse(envelope.data.eventInfo).OrgId; OneDSLogger.contextInfo.envId = JSON.parse(envelope.data.eventInfo).EnvironmentId; OneDSLogger.contextInfo.orgGeo = JSON.parse(envelope.data.eventInfo).orgGeo; + OneDSLogger.userInfo.oid = JSON.parse(envelope.data.eventInfo).AadId; // TODO: Populate website id OneDSLogger.contextInfo.websiteId = 'test' } diff --git a/src/common/OneDSLoggerTelemetry/telemetryConstants.ts b/src/common/OneDSLoggerTelemetry/telemetryConstants.ts index 9e934e65..eab9ad97 100644 --- a/src/common/OneDSLoggerTelemetry/telemetryConstants.ts +++ b/src/common/OneDSLoggerTelemetry/telemetryConstants.ts @@ -38,3 +38,5 @@ export enum GeoNames { } // Custom telemetry feature flag export const CUSTOM_TELEMETRY_FOR_POWER_PAGES_SETTING_NAME = 'enableTelemetry'; + +export const AadIdKey= 'Entra ID Object Id:'; \ No newline at end of file From 77a0c65a93433eb0b216ee1f9b731855c9ca6024 Mon Sep 17 00:00:00 2001 From: amitjoshi438 <54068463+amitjoshi438@users.noreply.github.com> Date: Fri, 9 Aug 2024 14:01:33 +0530 Subject: [PATCH 2/2] Users/amitjoshi/GitHub copilot string updates (#997) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Users/nityagi/update feature branch (#933) * Moving auth create flow to utils (#926) Co-authored-by: amitjoshi * Making auth provider a common module flow (#928) * refactor: Update QuickPickProvider to handle tab input changes (#930) The code changes in the QuickPickProvider class handle tab input changes by checking if the active tab is an instance of vscode.TabInputCustom or vscode.TabInputText. If it is, the QuickPickProvider updates the quick pick items based on the file path of the tab input. Note: This commit message follows the convention used in recent repository commits. * Updates to Artemis service & telemetry endpoints for gov clouds (#906) * Updates to artemis for gov clouds * change * changes --------- Co-authored-by: Shivika Gupta --------- Co-authored-by: amitjoshi438 <54068463+amitjoshi438@users.noreply.github.com> Co-authored-by: amitjoshi Co-authored-by: Ritik Ramuka <56073559+ritikramuka@users.noreply.github.com> Co-authored-by: gshivi <123095952+gshivi@users.noreply.github.com> Co-authored-by: Shivika Gupta * GitHub copilot chat - @powerpages contribution (#927) * chore: Update package.json with extension dependencies and enabled API proposals for chat participants * feat: Add PowerPagesChatParticipant for chat functionality * feat: Add logic to handle chat requests in PowerPagesChatParticipant * feat: Removed logs * TODO * formatting change * Remove unused extension dependency * feat: Add handler for chat requests in PowerPagesChatParticipant --------- Co-authored-by: amitjoshi Co-authored-by: tyaginidhi Co-authored-by: Nidhi Tyagi πŸŒŸπŸ‡πŸŒ΄β„οΈ * [@powerpages] GitHub copilot auth handling for AIB and PAC (#947) * chore: Update package.json with extension dependencies and enabled API proposals for chat participants * feat: Add PowerPagesChatParticipant for chat functionality * feat: Add logic to handle chat requests in PowerPagesChatParticipant * feat: Removed logs * TODO * feat: Add logic to handle chat requests in PowerPagesChatParticipant(correct response format) * chore: Remove unused code and update PowerPagesChatParticipant initialization * chore: Update PowerPagesChatParticipant initialization and pac integration * feat: Initialize organization details in PowerPagesChatParticipant * chore: Remove unnecessary code and update OrgChangeNotifier initialization * Fix lint warnings * feat: Refactor PowerPagesChatParticipant class The code changes refactor the PowerPagesChatParticipant class in the `PowerPagesChatParticipant.ts` file. The changes include: - Fixing a typo in the `instance` property declaration - Updating the constructor parameters to have consistent spacing - Adding a comment to handle chat requests - Removing a console.log statement - Updating the `intializeOrgDetails` method to have consistent spacing - Updating the `intializeOrgDetails` method to use destructuring assignment - Updating the `intializeOrgDetails` method to update the `orgDetails` in the global state - Removing unused code Co-authored-by: amitjoshi * Added response for error scenarios * Added & removed comments * refactor: Update PowerPagesCopilot name in package.json The code changes in the package.json file update the "name" property for the "powerpages" module to "Power Pages Copilot". This change reflects the updated name for the module. Co-authored-by: amitjoshi * Code refactoring for utils and constants * Enhanced pac auth handling * refactor: Update PowerPagesChatParticipantConstants The code changes in the `PowerPagesChatParticipantConstants.ts` file refactor the constants used in the PowerPages chat participant. The changes include: - Cleaning up the code formatting Co-authored-by: amitjoshi --------- Co-authored-by: amitjoshi Co-authored-by: tyaginidhi Co-authored-by: Nidhi Tyagi πŸŒŸπŸ‡πŸŒ΄β„οΈ * Resolve merge conflicts * [@Powerpages]GitHub copilot request handling (#957) * chore: Update package.json with extension dependencies and enabled API proposals for chat participants * feat: Add PowerPagesChatParticipant for chat functionality * feat: Add logic to handle chat requests in PowerPagesChatParticipant * feat: Removed logs * TODO * feat: Add logic to handle chat requests in PowerPagesChatParticipant(correct response format) * feat: Add getActiveEditorContent function for retrieving active editor data The code changes add a new function called getActiveEditorContent to the Utils module. This function retrieves the content and parameters of the active editor in Visual Studio Code. It is used in the PowerPagesCopilot module to get the active file content and its associated parameters. Co-authored-by: amitjoshi * chore: Remove unused code and update PowerPagesChatParticipant initialization * chore: Update PowerPagesChatParticipant initialization and pac integration * feat: Initialize organization details in PowerPagesChatParticipant * @powerpages aib endpoint handling * feat: Add getActiveEditorContent function to retrieve active editor data The code changes introduce a new function called getActiveEditorContent in the Utils module. This function allows retrieving the content and parameters of the active editor in Visual Studio Code. It is utilized in the PowerPagesCopilot module to obtain the active file content and its associated parameters. Co-authored-by: amitjoshi * Multiline response handling * Todo comment for auth create exp * feat: Handle Copilot Unavailable scenario with response to user * Update in package.json * chore: Remove extension dependency * Full name for @powerpages * refactor: Refactor PowerPagesChatParticipant class - Removing unused code * chat api insider version * refactor: Refactor PowerPagesChatParticipant import paths * Update package.json version to 1.0.1-dev and other refactoring * refactor: Remove unused code in PowerPagesChatParticipant class * refactor: Moved Dataverse details fetch to utils * refactor: Added entity check to utils * refactor: Update localization strings and package version * chore: Remove @types/vscode dependency and update package-lock.json and package.json * chore: Update @types/vscode dependency to version 1.89.0 * chore: Remove @types/vscode dependency and update package-lock.json and package.json --------- Co-authored-by: amitjoshi Co-authored-by: tyaginidhi * [PowerPages] Copilot Availability Check for @powerpages (#962) * feat: Add environmentID field to OrgDetails interface The code changes add an optional `environmentID` field to the `OrgDetails` interface in the `PowerPagesChatParticipantTypes.ts` file. This field represents the ID of the environment associated with the organization. It is used in the `getEndpoint` function in the `PowerPagesChatParticipantUtils.ts` file to retrieve the intelligence endpoint and geo name for the specified organization and environment. Co-authored-by: amitjoshi Co-authored-by: tyaginidhi * feat: Update PowerPagesChatParticipantUtils to return componentInfo and entityName The code changes in PowerPagesChatParticipantUtils modify the getComponentInfo function to return an object with two properties: componentInfo and entityName. This change allows for better handling of component information and entity details for the active file. The updated function is used in PowerPagesChatParticipant to retrieve the necessary data for sending API requests. Co-authored-by: amitjoshi * feat: Modify getComponentInfo to return componentInfo and entityName The code changes in PowerPagesChatParticipantUtils modify the getComponentInfo function to return an object with two properties: componentInfo and entityName. This change improves the handling of component information and entity details for the active file. The updated function is used in PowerPagesChatParticipant to retrieve the necessary data for sending API requests. --------- Co-authored-by: amitjoshi * feat: Add telemetry event names for GitHub Power Pages agent (#969) * feat: Add telemetry event names for GitHub Power Pages agent * chore: Update telemetry event names for GitHub Power Pages agent --------- Co-authored-by: amitjoshi Co-authored-by: tyaginidhi * chore: Update PowerPagesChatParticipantConstants with disclaimer message * chore: Update DISCLAIMER_MESSAGE in PowerPagesChatParticipantConstants.ts * Added link to @powerpages in existing copilot * refactor: Update fullName and description in powerpages package.json * feat: Remove unnecessary code and update GitHub Copilot link in PowerPagesCopilot.ts and copilot.js * feat: Add environment message to PowerPagesCopilot.ts * Remove unused enabledApiProposals from package.json * chore: Update PowerPagesCopilot.ts to include sample request in GitHub Copilot chat * chore: string updates for cost --------- Co-authored-by: tyaginidhi Co-authored-by: amitjoshi Co-authored-by: Ritik Ramuka <56073559+ritikramuka@users.noreply.github.com> Co-authored-by: gshivi <123095952+gshivi@users.noreply.github.com> Co-authored-by: Shivika Gupta Co-authored-by: Nidhi Tyagi πŸŒŸπŸ‡πŸŒ΄β„οΈ --- l10n/bundle.l10n.json | 11 +- .../vscode-powerplatform.xlf | 35 +++- .../powerpages/PowerPagesChatParticipant.ts | 44 +++-- .../PowerPagesChatParticipantConstants.ts | 10 +- .../PowerPagesChatParticipantUtils.ts | 17 +- src/common/copilot/PowerPagesCopilot.ts | 20 ++- src/common/copilot/assets/scripts/copilot.js | 23 ++- src/common/copilot/assets/styles/copilot.css | 13 ++ src/common/copilot/constants.ts | 2 +- .../CopilotNotificationPanel.ts | 161 ++++++++++-------- 10 files changed, 227 insertions(+), 109 deletions(-) diff --git a/l10n/bundle.l10n.json b/l10n/bundle.l10n.json index a2e82af1..f41bfd9e 100644 --- a/l10n/bundle.l10n.json +++ b/l10n/bundle.l10n.json @@ -57,12 +57,16 @@ "In your own words, describe what you need. You can get help with writing code for Power Pages sites in HTML, CSS, and JS languages.": "In your own words, describe what you need. You can get help with writing code for Power Pages sites in HTML, CSS, and JS languages.", "To know more, see Copilot in Power Pages documentation.": "To know more, see Copilot in Power Pages documentation.", "Working on it...": "Working on it...", + "You can use this in GitHub Copilot with @powerpages and leverage best of both world.": "You can use this in GitHub Copilot with @powerpages and leverage best of both world.", + "NEW": "NEW", "Copied to clipboard!": "Copied to clipboard!", "What do you need help with?": "What do you need help with?", "Make sure AI-generated content is accurate and appropriate before using. Learn more | View\n terms": "Make sure AI-generated content is accurate and appropriate before using. Learn more | View\n terms", + "Try @powerpages with GitHub Copilot": "Try @powerpages with GitHub Copilot", + "Get GitHub Copilot to try @powerpages": "Get GitHub Copilot to try @powerpages", "Let Copilot help you code": "Let Copilot help you code", "Whether it’s HTML, CSS, JS, or Liquid code, just describe what you need and let AI build it for you. ": "Whether it’s HTML, CSS, JS, or Liquid code, just describe what you need and let AI build it for you. ", - "Try Copilot for Power Pages": "Try Copilot for Power Pages", + "Continue with Copilot for Power Pages": "Continue with Copilot for Power Pages", "Do not show again": "Do not show again", "Like something? Tell us more.": "Like something? Tell us more.", "Dislike something? Tell us more.": "Dislike something? Tell us more.", @@ -70,10 +74,13 @@ "Tell us more.": "Tell us more.", "Try and be as specific as possible. Your feedback will be used to improve Copilot. View privacy details ": "Try and be as specific as possible. Your feedback will be used to improve Copilot. View privacy details ", "Submit": "Submit", - "Please provide a prompt to get started.\n You can get help with writing code for Power Pages sites in HTML, CSS, and JS languages.": "Please provide a prompt to get started.\n You can get help with writing code for Power Pages sites in HTML, CSS, and JS languages.", + "Hi! Power Pages lets you build secure, professional websites that you can quickly configure and publish across web browsers and devices.\n\nTo create your website, visit the [Power Pages](https://powerpages.microsoft.com/).\nReturn to this chat and @powerpages can help you write and edit your website code.": "Hi! Power Pages lets you build secure, professional websites that you can quickly configure and publish across web browsers and devices.\n\nTo create your website, visit the [Power Pages](https://powerpages.microsoft.com/).\nReturn to this chat and @powerpages can help you write and edit your website code.", "Authentication failed. Please try again.": "Authentication failed. Please try again.", "Copilot is not available. Please contact your administrator.": "Copilot is not available. Please contact your administrator.", "Active auth profile is not found or has expired. Please try again.": "Active auth profile is not found or has expired. Please try again.", + "Make sure AI-generated content is accurate and appropriate before using. [Learn more](https://go.microsoft.com/fwlink/?linkid=2240145) | [View terms](https://go.microsoft.com/fwlink/?linkid=2189520)": "Make sure AI-generated content is accurate and appropriate before using. [Learn more](https://go.microsoft.com/fwlink/?linkid=2240145) | [View terms](https://go.microsoft.com/fwlink/?linkid=2189520)", + "Explain the following code {% include 'Page Copy'%}": "Explain the following code {% include 'Page Copy'%}", + "Hi! @powerpages can help you write, edit, and even summarize your website code.": "Hi! @powerpages can help you write, edit, and even summarize your website code.", "Select Folder for new PCF Control/Do not translate 'PCF' as it is a product name.": { "message": "Select Folder for new PCF Control", "comment": [ diff --git a/loc/translations-export/vscode-powerplatform.xlf b/loc/translations-export/vscode-powerplatform.xlf index 7c87315d..69c3dcd4 100644 --- a/loc/translations-export/vscode-powerplatform.xlf +++ b/loc/translations-export/vscode-powerplatform.xlf @@ -79,6 +79,9 @@ Confirm + + Continue with Copilot for Power Pages + Copied to clipboard! @@ -134,6 +137,9 @@ The {3} represents Solution's Type (Managed or Unmanaged), but that test is loca Explain the following code snippet: + + Explain the following code {% include 'Page Copy'%} + Failed to create: {0}. {0} will be replaced by the error message. @@ -169,15 +175,27 @@ The {3} represents Solution's Type (Managed or Unmanaged), but that test is loca GETTING STARTED + + Get GitHub Copilot to try @powerpages + Here are a few suggestions to get you started Hi + + Hi! @powerpages can help you write, edit, and even summarize your website code. + Hi! Instantly generate code for Power Pages sites by typing in what you need. To start using Copilot, log in to your Microsoft account. + + Hi! Power Pages lets you build secure, professional websites that you can quickly configure and publish across web browsers and devices. + +To create your website, visit the [Power Pages](https://powerpages.microsoft.com/). +Return to this chat and @powerpages can help you write and edit your website code. + Hi! Your Microsoft account doesn’t currently support Copilot. Contact your admin for details. @@ -207,6 +225,9 @@ The {3} represents Solution's Type (Managed or Unmanaged), but that test is loca Make sure AI-generated content is accurate and appropriate before using. <a href="https://go.microsoft.com/fwlink/?linkid=2240145">Learn more</a> | <a href="https://go.microsoft.com/fwlink/?linkid=2189520">View terms</a> + + Make sure AI-generated content is accurate and appropriate before using. [Learn more](https://go.microsoft.com/fwlink/?linkid=2240145) | [View terms](https://go.microsoft.com/fwlink/?linkid=2189520) + Managed @@ -216,6 +237,9 @@ The {3} represents Solution's Type (Managed or Unmanaged), but that test is loca Microsoft wants your feeback + + NEW + Name/Rename Auth Profile @@ -294,10 +318,6 @@ The {3} represents Dataverse Environment's Organization ID (GUID) Please enter a name for the webpage. - - Please provide a prompt to get started. - You can get help with writing code for Power Pages sites in HTML, CSS, and JS languages. - Power Pages Copilot is now connected to the environment: {0} : {1} {0} represents the environment name @@ -380,8 +400,8 @@ The {3} represents Dataverse Environment's Organization ID (GUID) To know more, see <a href="https://go.microsoft.com/fwlink/?linkid=2206366">Copilot in Power Pages documentation. - - Try Copilot for Power Pages + + Try @powerpages with GitHub Copilot Try again @@ -435,6 +455,9 @@ The {3} represents Dataverse Environment's Organization ID (GUID) You are editing a live, public site + + You can use this in <a href="#" id="github-copilot-link">GitHub Copilot with @powerpages</a> and leverage best of both world. + dotnet sdk 6.0 or greater must be installed Do not translate 'dotnet' or 'sdk' diff --git a/src/common/chat-participants/powerpages/PowerPagesChatParticipant.ts b/src/common/chat-participants/powerpages/PowerPagesChatParticipant.ts index 880b3525..55da4726 100644 --- a/src/common/chat-participants/powerpages/PowerPagesChatParticipant.ts +++ b/src/common/chat-participants/powerpages/PowerPagesChatParticipant.ts @@ -11,9 +11,9 @@ import { sendApiRequest } from '../../copilot/IntelligenceApiService'; import { PacWrapper } from '../../../client/pac/PacWrapper'; import { intelligenceAPIAuthentication } from '../../services/AuthenticationProvider'; import { ActiveOrgOutput } from '../../../client/pac/PacTypes'; -import { AUTHENTICATION_FAILED_MSG, COPILOT_NOT_AVAILABLE_MSG, NO_PROMPT_MESSAGE, PAC_AUTH_NOT_FOUND, POWERPAGES_CHAT_PARTICIPANT_ID, RESPONSE_AWAITED_MSG, SKIP_CODES, VSCODE_EXTENSION_GITHUB_POWER_PAGES_AGENT_INVOKED, VSCODE_EXTENSION_GITHUB_POWER_PAGES_AGENT_ORG_DETAILS, VSCODE_EXTENSION_GITHUB_POWER_PAGES_AGENT_ORG_DETAILS_NOT_FOUND, VSCODE_EXTENSION_GITHUB_POWER_PAGES_AGENT_SCENARIO } from './PowerPagesChatParticipantConstants'; +import { AUTHENTICATION_FAILED_MSG, COPILOT_NOT_AVAILABLE_MSG, DISCLAIMER_MESSAGE, NO_PROMPT_MESSAGE, PAC_AUTH_NOT_FOUND, POWERPAGES_CHAT_PARTICIPANT_ID, RESPONSE_AWAITED_MSG, SKIP_CODES, STATER_PROMPTS, VSCODE_EXTENSION_GITHUB_POWER_PAGES_AGENT_INVOKED, VSCODE_EXTENSION_GITHUB_POWER_PAGES_AGENT_ORG_DETAILS, VSCODE_EXTENSION_GITHUB_POWER_PAGES_AGENT_ORG_DETAILS_NOT_FOUND, VSCODE_EXTENSION_GITHUB_POWER_PAGES_AGENT_SCENARIO, WELCOME_MESSAGE, WELCOME_PROMPT } from './PowerPagesChatParticipantConstants'; import { ORG_DETAILS_KEY, handleOrgChangeSuccess, initializeOrgDetails } from '../../utilities/OrgHandlerUtils'; -import { getComponentInfo, getEndpoint } from './PowerPagesChatParticipantUtils'; +import { getComponentInfo, getEndpoint, provideChatParticipantFollowups } from './PowerPagesChatParticipantUtils'; import { checkCopilotAvailability, getActiveEditorContent } from '../../utilities/Utils'; import { IIntelligenceAPIEndpointInformation } from '../../services/Interfaces'; import { v4 as uuidv4 } from 'uuid'; @@ -42,6 +42,10 @@ export class PowerPagesChatParticipant { //TODO: Check the icon image this.chatParticipant.iconPath = vscode.Uri.joinPath(context.extensionUri, 'src', 'common', 'chat-participants', 'powerpages', 'assets', 'copilot.png'); + this.chatParticipant.followupProvider = { + provideFollowups: provideChatParticipantFollowups + }; + this.powerPagesAgentSessionId = uuidv4(); this.telemetry = telemetry; @@ -57,7 +61,6 @@ export class PowerPagesChatParticipant { this._disposables.push(orgChangeErrorEvent(async () => { this.extensionContext.globalState.update(ORG_DETAILS_KEY, { orgID: undefined, orgUrl: undefined }); })); - } public static getInstance(context: vscode.ExtensionContext, telemetry: ITelemetry | TelemetryReporter, pacWrapper?: PacWrapper) { @@ -124,25 +127,32 @@ export class PowerPagesChatParticipant { }; } - if (request.command) { - //TODO: Handle command scenarios + const userPrompt = request.prompt; - } else { + if (userPrompt === WELCOME_PROMPT) { + stream.markdown(WELCOME_MESSAGE); + return{ + metadata: { + command: STATER_PROMPTS + } + } + } - const userPrompt = request.prompt; + if (!userPrompt) { - if (!userPrompt) { + stream.markdown(NO_PROMPT_MESSAGE); - //TODO: String approval is required - stream.markdown(NO_PROMPT_MESSAGE); + return { + metadata: { + command: STATER_PROMPTS + } + }; + } - return { - metadata: { - command: '' - } - }; - } + if (request.command) { + //TODO: Handle command scenarios + } else { const { activeFileParams } = getActiveEditorContent(); const { componentInfo, entityName }: IComponentInfo = await getComponentInfo(this.telemetry, this.orgUrl, activeFileParams, this.powerPagesAgentSessionId); @@ -162,7 +172,7 @@ export class PowerPagesChatParticipant { } stream.markdown('\n'); }); - + stream.markdown(DISCLAIMER_MESSAGE); } return { diff --git a/src/common/chat-participants/powerpages/PowerPagesChatParticipantConstants.ts b/src/common/chat-participants/powerpages/PowerPagesChatParticipantConstants.ts index 0a0f8271..5205a6b6 100644 --- a/src/common/chat-participants/powerpages/PowerPagesChatParticipantConstants.ts +++ b/src/common/chat-participants/powerpages/PowerPagesChatParticipantConstants.ts @@ -6,12 +6,13 @@ import * as vscode from 'vscode'; import { ADX_ENTITYFORM, ADX_ENTITYLIST } from '../../copilot/constants'; -export const NO_PROMPT_MESSAGE = vscode.l10n.t('Please provide a prompt to get started.\n You can get help with writing code for Power Pages sites in HTML, CSS, and JS languages.'); +export const NO_PROMPT_MESSAGE = vscode.l10n.t('Hi! Power Pages lets you build secure, professional websites that you can quickly configure and publish across web browsers and devices.\n\nTo create your website, visit the [Power Pages](https://powerpages.microsoft.com/).\nReturn to this chat and @powerpages can help you write and edit your website code.'); export const POWERPAGES_CHAT_PARTICIPANT_ID = 'powerpages'; export const RESPONSE_AWAITED_MSG = vscode.l10n.t('Working on it...'); export const AUTHENTICATION_FAILED_MSG = vscode.l10n.t('Authentication failed. Please try again.'); export const COPILOT_NOT_AVAILABLE_MSG = vscode.l10n.t('Copilot is not available. Please contact your administrator.'); export const PAC_AUTH_NOT_FOUND = vscode.l10n.t('Active auth profile is not found or has expired. Please try again.'); +export const DISCLAIMER_MESSAGE = vscode.l10n.t('Make sure AI-generated content is accurate and appropriate before using. [Learn more](https://go.microsoft.com/fwlink/?linkid=2240145) | [View terms](https://go.microsoft.com/fwlink/?linkid=2189520)'); export const SUPPORTED_ENTITIES = [ADX_ENTITYFORM, ADX_ENTITYLIST]; // Telemetry Event Names export const VSCODE_EXTENSION_GITHUB_POWER_PAGES_AGENT_INVOKED = 'GitHubPowerPagesAgentInvoked'; @@ -19,5 +20,12 @@ export const VSCODE_EXTENSION_GITHUB_POWER_PAGES_AGENT_ORG_DETAILS = 'GitHubPowe export const VSCODE_EXTENSION_GITHUB_POWER_PAGES_AGENT_ORG_DETAILS_NOT_FOUND = 'GitHubPowerPagesAgentOrgDetailsNotFound'; export const VSCODE_EXTENSION_GITHUB_POWER_PAGES_AGENT_SCENARIO = 'GitHubPowerPagesAgentScenario'; export const SKIP_CODES = ["", null, undefined, "violation", "unclear", "explain"]; +export const EXPLAIN_CODE_PROMPT = vscode.l10n.t('Explain the following code {% include \'Page Copy\'%}'); +export const WEB_API_PROMPT = vscode.l10n.t('Write web API code to query active contact records.'); +export const FORM_PROMPT = vscode.l10n.t('Write JavaScript code for form field validation to check phone field value is in the valid format.'); +export const LIST_PROMPT = vscode.l10n.t('Write JavaScript code to highlight the row where email field is empty in table list.'); +export const STATER_PROMPTS = "starterPrompts" +export const WELCOME_PROMPT = 'how can you help with coding for my website?' +export const WELCOME_MESSAGE = vscode.l10n.t('Hi! @powerpages can help you write, edit, and even summarize your website code.') diff --git a/src/common/chat-participants/powerpages/PowerPagesChatParticipantUtils.ts b/src/common/chat-participants/powerpages/PowerPagesChatParticipantUtils.ts index 96128ead..94ff0628 100644 --- a/src/common/chat-participants/powerpages/PowerPagesChatParticipantUtils.ts +++ b/src/common/chat-participants/powerpages/PowerPagesChatParticipantUtils.ts @@ -10,8 +10,9 @@ import { ITelemetry } from "../../OneDSLoggerTelemetry/telemetry/ITelemetry"; import { ArtemisService } from "../../services/ArtemisService"; import { dataverseAuthentication } from "../../services/AuthenticationProvider"; import { IIntelligenceAPIEndpointInformation } from "../../services/Interfaces"; -import { SUPPORTED_ENTITIES } from "./PowerPagesChatParticipantConstants"; -import { IComponentInfo } from "./PowerPagesChatParticipantTypes"; +import { EXPLAIN_CODE_PROMPT, FORM_PROMPT, LIST_PROMPT, STATER_PROMPTS, SUPPORTED_ENTITIES, WEB_API_PROMPT } from "./PowerPagesChatParticipantConstants"; +import { IComponentInfo, IPowerPagesChatResult } from "./PowerPagesChatParticipantTypes"; +import * as vscode from 'vscode'; export async function getEndpoint( orgID: string, @@ -55,3 +56,15 @@ export async function getComponentInfo(telemetry: ITelemetry, orgUrl: string | u export function isEntityInSupportedList(entity: string): boolean { return SUPPORTED_ENTITIES.includes(entity); } + +// eslint-disable-next-line @typescript-eslint/no-unused-vars +export function provideChatParticipantFollowups(result: IPowerPagesChatResult, _context: vscode.ChatContext, _token: vscode.CancellationToken) { + if (result.metadata.command === STATER_PROMPTS) { + return [ + { prompt: EXPLAIN_CODE_PROMPT }, + { prompt: WEB_API_PROMPT }, + { prompt: LIST_PROMPT }, + { prompt: FORM_PROMPT } + ]; + } +} diff --git a/src/common/copilot/PowerPagesCopilot.ts b/src/common/copilot/PowerPagesCopilot.ts index ba7f53e3..e225848c 100644 --- a/src/common/copilot/PowerPagesCopilot.ts +++ b/src/common/copilot/PowerPagesCopilot.ts @@ -10,7 +10,7 @@ import { dataverseAuthentication, getOIDFromToken, intelligenceAPIAuthentication import { v4 as uuidv4 } from 'uuid' import { PacWrapper } from "../../client/pac/PacWrapper"; import { ITelemetry } from "../OneDSLoggerTelemetry/telemetry/ITelemetry"; -import { ADX_ENTITYFORM, ADX_ENTITYLIST, AUTH_CREATE_FAILED, AUTH_CREATE_MESSAGE, AuthProfileNotFound, COPILOT_UNAVAILABLE, CopilotStylePathSegments, EXPLAIN_CODE, SELECTED_CODE_INFO, SELECTED_CODE_INFO_ENABLED, THUMBS_DOWN, THUMBS_UP, UserPrompt, WebViewMessage, sendIconSvg } from "./constants"; +import { ADX_ENTITYFORM, ADX_ENTITYLIST, AUTH_CREATE_FAILED, AUTH_CREATE_MESSAGE, AuthProfileNotFound, COPILOT_IN_POWERPAGES, COPILOT_UNAVAILABLE, CopilotStylePathSegments, EXPLAIN_CODE, SELECTED_CODE_INFO, SELECTED_CODE_INFO_ENABLED, THUMBS_DOWN, THUMBS_UP, UserPrompt, WebViewMessage, sendIconSvg } from "./constants"; import { IActiveFileParams, IOrgInfo } from './model'; import { checkCopilotAvailability, escapeDollarSign, getActiveEditorContent, getNonce, getSelectedCode, getSelectedCodeLineRange, getUserName, openWalkthrough, showConnectedOrgMessage, showInputBoxAndGetOrgUrl, showProgressWithNotification } from "../utilities/Utils"; import { CESUserFeedback } from "./user-feedback/CESSurvey"; @@ -148,7 +148,7 @@ export class PowerPagesCopilot implements vscode.WebviewViewProvider { ) { this._view = webviewView; - webviewView.title = vscode.l10n.t("Copilot In Power Pages") + (IS_DESKTOP ? "" : " [PREVIEW]"); + webviewView.title = vscode.l10n.t(COPILOT_IN_POWERPAGES) + (IS_DESKTOP ? "" : " [PREVIEW]"); webviewView.description = vscode.l10n.t("PREVIEW"); webviewView.webview.options = { // Allow scripts in the webview @@ -194,9 +194,11 @@ export class PowerPagesCopilot implements vscode.WebviewViewProvider { LOGIN_MESSAGE: vscode.l10n.t("Hi! Instantly generate code for Power Pages sites by typing in what you need. To start using Copilot, log in to your Microsoft account."), LOGIN_BUTTON: vscode.l10n.t("Login"), HI: vscode.l10n.t("Hi"), - WELCOME_MESSAGE: vscode.l10n.t(`In your own words, describe what you need. You can get help with writing code for Power Pages sites in HTML, CSS, and JS languages.`), + WELCOME_MESSAGE: vscode.l10n.t('In your own words, describe what you need. You can get help with writing code for Power Pages sites in HTML, CSS, and JS languages.'), DOCUMENTATION_LINK: vscode.l10n.t("To know more, see Copilot in Power Pages documentation."), - WORKING_ON_IT_MESSAGE: vscode.l10n.t("Working on it...") + WORKING_ON_IT_MESSAGE: vscode.l10n.t("Working on it..."), + GITHUB_COPILOT_CHAT: vscode.l10n.t('You can use this in GitHub Copilot with @powerpages and leverage best of both world.'), + NEW_BADGE: vscode.l10n.t("NEW"), }; this.sendMessageToWebview({ @@ -214,7 +216,7 @@ export class PowerPagesCopilot implements vscode.WebviewViewProvider { } sendTelemetryEvent(this.telemetry, { eventName: CopilotLoadedEvent, copilotSessionId: sessionID, orgId: orgID }); - this.sendMessageToWebview({ type: 'env' }); //TODO Use IS_DESKTOP + this.sendMessageToWebview({ type: 'env' }); await this.checkAuthentication(); if (orgID && userName) { this.sendMessageToWebview({ type: 'isLoggedIn', value: true }); @@ -292,6 +294,14 @@ export class PowerPagesCopilot implements vscode.WebviewViewProvider { sendTelemetryEvent(this.telemetry, { eventName: CopilotCodeLineCountEvent, copilotSessionId: sessionID, codeLineCount: String(data.value), orgId: orgID }); break; } + case "openGitHubCopilotLink": { + //Open the GitHub Copilot Chat with @powerpages if GitHub Copilot Chat is installed + if(vscode.extensions.getExtension('github.copilot-chat')) { + vscode.commands.executeCommand('workbench.action.chat.open', '@powerpages how can you help with coding for my website?'); + } else { + vscode.env.openExternal(vscode.Uri.parse('https://go.microsoft.com/fwlink/?linkid=2276973')); + } + } } }); } diff --git a/src/common/copilot/assets/scripts/copilot.js b/src/common/copilot/assets/scripts/copilot.js index 34b92d9d..813e39c7 100644 --- a/src/common/copilot/assets/scripts/copilot.js +++ b/src/common/copilot/assets/scripts/copilot.js @@ -27,7 +27,6 @@ let copilotStrings = {}; - const inputHistory = []; let currentIndex = -1; @@ -241,6 +240,16 @@ return feedback; } + function createGitHubCopilotLinkDiv() { + const gitHubCopilotText = document.createElement("div"); + gitHubCopilotText.classList.add("github-copilot-text"); + + gitHubCopilotText.innerHTML = `${copilotStrings.NEW_BADGE} + ${copilotStrings.GITHUB_COPILOT_CHAT}` + + return gitHubCopilotText; + } + function createSuggestedPromptDiv() { const suggestedPrompt = document.createElement("div"); suggestedPrompt.classList.add("suggested-prompts"); @@ -384,6 +393,17 @@ `; messageElement.appendChild(loggedInDiv); + // Add GitHub Copilot link + + const gitHubCopilotLink = createGitHubCopilotLinkDiv(); + messageElement.appendChild(gitHubCopilotLink); + + const gitHubCopilotLinkElement = document.getElementById("github-copilot-link"); + gitHubCopilotLinkElement.addEventListener("click", () => { + vscode.postMessage({ type: "openGitHubCopilotLink" }); + }); + + const suggestedPromptDiv = createSuggestedPromptDiv(); messageElement.appendChild(suggestedPromptDiv); @@ -441,7 +461,6 @@ break; } case "env": { - welcomeScreen = setWelcomeScreen(); break; } diff --git a/src/common/copilot/assets/styles/copilot.css b/src/common/copilot/assets/styles/copilot.css index b29e9812..24c66208 100644 --- a/src/common/copilot/assets/styles/copilot.css +++ b/src/common/copilot/assets/styles/copilot.css @@ -250,6 +250,10 @@ a:focus { outline: none; } +a:hover { + text-decoration: underline; +} + li:before { content: "/"; } @@ -339,3 +343,12 @@ hr { margin-right: 4px; /* Add some spacing between icon and text */ } + +.new-badge { + background-color: var(--vscode-button-background); + color: var(--vscode-button-foreground); + border-radius: 50px; + padding: 1px 5px; + font-size: 9px; + /* margin-right: 2px; */ +} diff --git a/src/common/copilot/constants.ts b/src/common/copilot/constants.ts index 1c313a09..4e32e884 100644 --- a/src/common/copilot/constants.ts +++ b/src/common/copilot/constants.ts @@ -35,7 +35,7 @@ export const ATTRIBUTE_DESCRIPTION = 'description'; export const ATTRIBUTE_DATAFIELD_NAME = 'datafieldname'; export const ATTRIBUTE_CLASSID = 'classid'; export const SYSTEFORMS_API_PATH = 'api/data/v9.2/systemforms'; - +export const COPILOT_IN_POWERPAGES = 'Copilot In Power Pages' export type WebViewMessage = { type: string; diff --git a/src/common/copilot/welcome-notification/CopilotNotificationPanel.ts b/src/common/copilot/welcome-notification/CopilotNotificationPanel.ts index e2191865..28fcb98f 100644 --- a/src/common/copilot/welcome-notification/CopilotNotificationPanel.ts +++ b/src/common/copilot/welcome-notification/CopilotNotificationPanel.ts @@ -4,96 +4,111 @@ */ import * as vscode from "vscode"; -import { getNonce, openWalkthrough } from "../../utilities/Utils"; +import { getNonce } from "../../utilities/Utils"; import TelemetryReporter from "@vscode/extension-telemetry"; -import { CopilotNotificationDoNotShowChecked, CopilotTryNotificationClickedEvent, CopilotWalkthroughEvent, CopilotNotificationDoNotShowUnchecked } from "../telemetry/telemetryConstants"; -import { COPILOT_NOTIFICATION_DISABLED } from "../constants"; +import { CopilotNotificationDoNotShowChecked, CopilotTryNotificationClickedEvent, CopilotNotificationDoNotShowUnchecked } from "../telemetry/telemetryConstants"; +import { COPILOT_IN_POWERPAGES, COPILOT_NOTIFICATION_DISABLED } from "../constants"; import { oneDSLoggerWrapper } from "../../OneDSLoggerTelemetry/oneDSLoggerWrapper"; let NotificationPanel: vscode.WebviewPanel | undefined; export async function copilotNotificationPanel(context: vscode.ExtensionContext, telemetry: TelemetryReporter, telemetryData: string, countOfActivePortals?: string) { - if (NotificationPanel) { - NotificationPanel.dispose(); - } - - NotificationPanel = createNotificationPanel(); - - const { notificationCssUri, notificationJsUri, copilotImageUri, arrowImageUri } = getWebviewURIs(context, NotificationPanel); - - const nonce = getNonce(); - const webview = NotificationPanel.webview - NotificationPanel.webview.html = getWebviewContent(notificationCssUri, notificationJsUri, copilotImageUri, arrowImageUri, nonce, webview); - - NotificationPanel.webview.onDidReceiveMessage( - async message => { - switch (message.command) { - case 'checked': - telemetry.sendTelemetryEvent(CopilotNotificationDoNotShowChecked, { listOfOrgs: telemetryData, countOfActivePortals: countOfActivePortals as string }); - oneDSLoggerWrapper.getLogger().traceInfo(CopilotNotificationDoNotShowChecked, { listOfOrgs: telemetryData, countOfActivePortals: countOfActivePortals as string }); - context.globalState.update(COPILOT_NOTIFICATION_DISABLED, true); - break; - case 'unchecked': - telemetry.sendTelemetryEvent(CopilotNotificationDoNotShowUnchecked, { listOfOrgs: telemetryData, countOfActivePortals: countOfActivePortals as string }); - oneDSLoggerWrapper.getLogger().traceInfo(CopilotNotificationDoNotShowUnchecked, { listOfOrgs: telemetryData, countOfActivePortals: countOfActivePortals as string }); - context.globalState.update(COPILOT_NOTIFICATION_DISABLED, false); - break; - case 'tryCopilot': - telemetry.sendTelemetryEvent(CopilotTryNotificationClickedEvent, { listOfOrgs: telemetryData, countOfActivePortals: countOfActivePortals as string }); - oneDSLoggerWrapper.getLogger().traceInfo(CopilotTryNotificationClickedEvent, { listOfOrgs: telemetryData, countOfActivePortals: countOfActivePortals as string }); - vscode.commands.executeCommand('powerpages.copilot.focus') - NotificationPanel?.dispose(); - break; - case 'learnMore': - telemetry.sendTelemetryEvent(CopilotWalkthroughEvent, { listOfOrgs: telemetryData, countOfActivePortals: countOfActivePortals as string }); - openWalkthrough(context.extensionUri); - } - }, - undefined, - context.subscriptions - ); -} + if (NotificationPanel) { + NotificationPanel.dispose(); + } -function createNotificationPanel(): vscode.WebviewPanel { - const NotificationPanel = vscode.window.createWebviewPanel( - "CopilotNotification", - "Copilot in Power Pages", - { - viewColumn: vscode.ViewColumn.Beside, - preserveFocus: true, - }, - { - enableScripts: true, + NotificationPanel = createNotificationPanel(); + + const { notificationCssUri, notificationJsUri, copilotImageUri, arrowImageUri } = getWebviewURIs(context, NotificationPanel); + + const nonce = getNonce(); + const webview = NotificationPanel.webview + let isGitHubCopilotPresent = false; + let GITHUB_COPILOT_CHAT: string; + + if (vscode.extensions.getExtension('github.copilot-chat')) { + GITHUB_COPILOT_CHAT = vscode.l10n.t('Try @powerpages with GitHub Copilot'); + isGitHubCopilotPresent = true; + } else { + GITHUB_COPILOT_CHAT = vscode.l10n.t('Get GitHub Copilot to try @powerpages'); } - ); - return NotificationPanel; + NotificationPanel.webview.html = getWebviewContent(notificationCssUri, notificationJsUri, copilotImageUri, arrowImageUri, nonce, webview, GITHUB_COPILOT_CHAT); + + NotificationPanel.webview.onDidReceiveMessage( + async message => { + switch (message.command) { + case 'checked': + telemetry.sendTelemetryEvent(CopilotNotificationDoNotShowChecked, { listOfOrgs: telemetryData, countOfActivePortals: countOfActivePortals as string }); + oneDSLoggerWrapper.getLogger().traceInfo(CopilotNotificationDoNotShowChecked, { listOfOrgs: telemetryData, countOfActivePortals: countOfActivePortals as string }); + context.globalState.update(COPILOT_NOTIFICATION_DISABLED, true); + break; + case 'unchecked': + telemetry.sendTelemetryEvent(CopilotNotificationDoNotShowUnchecked, { listOfOrgs: telemetryData, countOfActivePortals: countOfActivePortals as string }); + oneDSLoggerWrapper.getLogger().traceInfo(CopilotNotificationDoNotShowUnchecked, { listOfOrgs: telemetryData, countOfActivePortals: countOfActivePortals as string }); + context.globalState.update(COPILOT_NOTIFICATION_DISABLED, false); + break; + case 'tryCopilot': + telemetry.sendTelemetryEvent(CopilotTryNotificationClickedEvent, { listOfOrgs: telemetryData, countOfActivePortals: countOfActivePortals as string }); + oneDSLoggerWrapper.getLogger().traceInfo(CopilotTryNotificationClickedEvent, { listOfOrgs: telemetryData, countOfActivePortals: countOfActivePortals as string }); + vscode.commands.executeCommand('powerpages.copilot.focus') + NotificationPanel?.dispose(); + break; + case 'learnMore': + // telemetry.sendTelemetryEvent(CopilotWalkthroughEvent, { listOfOrgs: telemetryData, countOfActivePortals: countOfActivePortals as string }); + // openWalkthrough(context.extensionUri); + if (isGitHubCopilotPresent) { + vscode.commands.executeCommand('workbench.action.chat.open', '@powerpages how can you help with coding for my website?'); + } else { + vscode.env.openExternal(vscode.Uri.parse('https://go.microsoft.com/fwlink/?linkid=2276973')); + } + } + }, + undefined, + context.subscriptions + ); +} + +function createNotificationPanel(): vscode.WebviewPanel { + const NotificationPanel = vscode.window.createWebviewPanel( + "CopilotNotification", + COPILOT_IN_POWERPAGES, + { + viewColumn: vscode.ViewColumn.Beside, + preserveFocus: true, + }, + { + enableScripts: true, + } + ); + + return NotificationPanel; } function getWebviewURIs(context: vscode.ExtensionContext, NotificationPanel: vscode.WebviewPanel): { notificationCssUri: vscode.Uri, notificationJsUri: vscode.Uri, copilotImageUri: vscode.Uri, arrowImageUri: vscode.Uri } { - const srcPath = vscode.Uri.joinPath(context.extensionUri, 'src', 'common', 'copilot', "welcome-notification"); + const srcPath = vscode.Uri.joinPath(context.extensionUri, 'src', 'common', 'copilot', "welcome-notification"); - const notificationCssPath = vscode.Uri.joinPath(srcPath, "copilotNotification.css"); - const notificationCssUri = NotificationPanel.webview.asWebviewUri(notificationCssPath); + const notificationCssPath = vscode.Uri.joinPath(srcPath, "copilotNotification.css"); + const notificationCssUri = NotificationPanel.webview.asWebviewUri(notificationCssPath); - const notificationJsPath = vscode.Uri.joinPath(srcPath, "copilotNotification.js"); - const notificationJsUri = NotificationPanel.webview.asWebviewUri(notificationJsPath); + const notificationJsPath = vscode.Uri.joinPath(srcPath, "copilotNotification.js"); + const notificationJsUri = NotificationPanel.webview.asWebviewUri(notificationJsPath); - const copilotImagePath = vscode.Uri.joinPath(srcPath, "notification.svg"); - const copilotImageUri = NotificationPanel.webview.asWebviewUri(copilotImagePath); + const copilotImagePath = vscode.Uri.joinPath(srcPath, "notification.svg"); + const copilotImageUri = NotificationPanel.webview.asWebviewUri(copilotImagePath); - const arrowImagePath = vscode.Uri.joinPath(srcPath, "arrow.svg"); - const arrowImageUri = NotificationPanel.webview.asWebviewUri(arrowImagePath); + const arrowImagePath = vscode.Uri.joinPath(srcPath, "arrow.svg"); + const arrowImageUri = NotificationPanel.webview.asWebviewUri(arrowImagePath); - return { notificationCssUri, notificationJsUri, copilotImageUri, arrowImageUri }; + return { notificationCssUri, notificationJsUri, copilotImageUri, arrowImageUri }; } -function getWebviewContent(notificationCssUri: vscode.Uri, notificationJsUri: vscode.Uri, copilotImageUri: vscode.Uri, arrowImageUri: vscode.Uri, nonce: string, webview: vscode.Webview) { +function getWebviewContent(notificationCssUri: vscode.Uri, notificationJsUri: vscode.Uri, copilotImageUri: vscode.Uri, arrowImageUri: vscode.Uri, nonce: string, webview: vscode.Webview, githubCopilotChat: string) { - return ` + return ` @@ -108,8 +123,8 @@ function getWebviewContent(notificationCssUri: vscode.Uri, notificationJsUri: vs

${vscode.l10n.t("Let Copilot help you code")}

${vscode.l10n.t("Whether it’s HTML, CSS, JS, or Liquid code, just describe what you need and let AI build it for you. ")}

- - ${vscode.l10n.t("Learn more about Copilot")} + + ${vscode.l10n.t(githubCopilotChat)}
Image @@ -126,9 +141,9 @@ function getWebviewContent(notificationCssUri: vscode.Uri, notificationJsUri: vs } export function disposeNotificationPanel() { - if (NotificationPanel) { - NotificationPanel.dispose(); - NotificationPanel = undefined; - } + if (NotificationPanel) { + NotificationPanel.dispose(); + NotificationPanel = undefined; + } }