Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Copilot] Label for selected code #727

Merged
merged 11 commits into from
Oct 3, 2023
120 changes: 67 additions & 53 deletions src/common/Utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,94 +7,108 @@
import * as vscode from "vscode";
import { EXTENSION_ID } from "../client/constants";

export function getSelectedSnippet(): string {
const editor = vscode.window.activeTextEditor;
if (!editor) {
return "";
}
const selection = editor.selection;
const text = editor.document.getText(selection);
return text;
export function getSelectedCode(editor: vscode.TextEditor): string {
if (!editor) {
return "";
}
const selection = editor.selection;
const text = editor.document.getText(selection);
return text;
}

export function getSelectedCodeLineRange(editor: vscode.TextEditor): { start: number, end: number } {
if (!editor) {
amitjoshi438 marked this conversation as resolved.
Show resolved Hide resolved
return { start: 0, end: 0 };
}
// Get the selection(s) in the editor
const selection = editor.selection;

const startLine = selection.start.line;
const endLine = selection.end.line;
console.log(`Selected lines: ${startLine + 1}-${endLine + 1}`);
amitjoshi438 marked this conversation as resolved.
Show resolved Hide resolved
amitjoshi438 marked this conversation as resolved.
Show resolved Hide resolved

return { start: startLine, end: endLine };

}
// Get the organization ID from the user during login
export async function getOrgID(): Promise<string> {
const orgID = await vscode.window.showInputBox({
placeHolder: vscode.l10n.t("Enter Organization ID")
});
if (!orgID) {
throw new Error("Organization ID is required");
}
return Promise.resolve(orgID);
const orgID = await vscode.window.showInputBox({
placeHolder: vscode.l10n.t("Enter Organization ID")
});
if (!orgID) {
throw new Error("Organization ID is required");
}
return Promise.resolve(orgID);
}


export function getNonce() {
let text = '';
const possible = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
for (let i = 0; i < 32; i++) {
text += possible.charAt(Math.floor(Math.random() * possible.length));
}
return text;
let text = '';
const possible = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
for (let i = 0; i < 32; i++) {
text += possible.charAt(Math.floor(Math.random() * possible.length));
}
return text;
}


export function getUserName(user: string) {
const parts = user.split(" - ");
return parts[0];
const parts = user.split(" - ");
return parts[0];
}

export function getLastThreePartsOfFileName(string: string): string[] {
const parts: string[] = string.split('.');
if (parts.length >= 3) {
return parts.slice(-3);
} else {
return parts;
}
const parts: string[] = string.split('.');
if (parts.length >= 3) {
return parts.slice(-3);
} else {
return parts;
}
}

export function escapeDollarSign(paragraph: string): string {
return paragraph.replace(/\$/g, "\\$");
return paragraph.replace(/\$/g, "\\$");
}

//TODO: Take message as a parameter
export function showConnectedOrgMessage(environmentName: string, orgUrl: string) {
vscode.window.showInformationMessage(
vscode.l10n.t({
message: "Power Pages Copilot is now connected to the environment: {0} : {1}",
args: [environmentName, orgUrl],
comment: ["{0} represents the environment name"]
})
);
vscode.window.showInformationMessage(
vscode.l10n.t({
message: "Power Pages Copilot is now connected to the environment: {0} : {1}",
args: [environmentName, orgUrl],
comment: ["{0} represents the environment name"]
})
);
}

export async function showInputBoxAndGetOrgUrl() {
return vscode.window.showInputBox({
placeHolder: vscode.l10n.t("Enter the environment URL"),
prompt: vscode.l10n.t("Active auth profile is not found or has expired. To create a new auth profile, enter the environment URL.")
});
return vscode.window.showInputBox({
placeHolder: vscode.l10n.t("Enter the environment URL"),
prompt: vscode.l10n.t("Active auth profile is not found or has expired. To create a new auth profile, enter the environment URL.")
});
}

export async function showProgressWithNotification<T>(title: string, task: () => Promise<T>): Promise<T> {
return await vscode.window.withProgress({
location: vscode.ProgressLocation.Notification,
title: title,
cancellable: false
}, async () => {
return await task();
});
return await vscode.window.withProgress({
location: vscode.ProgressLocation.Notification,
title: title,
cancellable: false
}, async () => {
return await task();
});
}

export function getExtensionVersion(): string {
const extension = vscode.extensions.getExtension(EXTENSION_ID);
return extension ? extension.packageJSON.version : "";
const extension = vscode.extensions.getExtension(EXTENSION_ID);
return extension ? extension.packageJSON.version : "";
}

export function getExtensionType(): string {
return vscode.env.uiKind === vscode.UIKind.Desktop ? "Desktop" : "Web";
return vscode.env.uiKind === vscode.UIKind.Desktop ? "Desktop" : "Web";
}

export function openWalkthrough(extensionUri: vscode.Uri) {
const walkthroughUri = vscode.Uri.joinPath(extensionUri, 'src', 'common', 'copilot', 'assets', 'walkthrough', 'Copilot-In-PowerPages.md');
vscode.commands.executeCommand("markdown.showPreview", walkthroughUri);
const walkthroughUri = vscode.Uri.joinPath(extensionUri, 'src', 'common', 'copilot', 'assets', 'walkthrough', 'Copilot-In-PowerPages.md');
vscode.commands.executeCommand("markdown.showPreview", walkthroughUri);
}

20 changes: 18 additions & 2 deletions src/common/copilot/PowerPagesCopilot.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,9 @@ import { dataverseAuthentication, intelligenceAPIAuthentication } from "../../we
import { v4 as uuidv4 } from 'uuid'
import { PacWrapper } from "../../client/pac/PacWrapper";
import { ITelemetry } from "../../client/telemetry/ITelemetry";
import { AUTH_CREATE_FAILED, AUTH_CREATE_MESSAGE, AuthProfileNotFound, COPILOT_UNAVAILABLE, CopilotDisclaimer, CopilotStylePathSegments, DataverseEntityNameMap, EntityFieldMap, FieldTypeMap, PAC_SUCCESS, WebViewMessage, sendIconSvg } from "./constants";
import { AUTH_CREATE_FAILED, AUTH_CREATE_MESSAGE, AuthProfileNotFound, COPILOT_UNAVAILABLE, CopilotDisclaimer, CopilotStylePathSegments, DataverseEntityNameMap, EntityFieldMap, FieldTypeMap, PAC_SUCCESS, SELECTED_CODE_INFO_ENABLED, WebViewMessage, sendIconSvg } from "./constants";
import { IActiveFileParams, IActiveFileData, IOrgInfo } from './model';
import { escapeDollarSign, getLastThreePartsOfFileName, getNonce, getUserName, openWalkthrough, showConnectedOrgMessage, showInputBoxAndGetOrgUrl, showProgressWithNotification } from "../Utils";
import { escapeDollarSign, getLastThreePartsOfFileName, getNonce, getSelectedCode, getSelectedCodeLineRange, getUserName, openWalkthrough, showConnectedOrgMessage, showInputBoxAndGetOrgUrl, showProgressWithNotification } from "../Utils";
import { CESUserFeedback } from "./user-feedback/CESSurvey";
import { GetAuthProfileWatchPattern } from "../../client/lib/AuthPanelView";
import { ActiveOrgOutput } from "../../client/pac/PacTypes";
Expand Down Expand Up @@ -66,6 +66,21 @@ export class PowerPagesCopilot implements vscode.WebviewViewProvider {
)
);


if (SELECTED_CODE_INFO_ENABLED) { //TODO: Remove this check once the feature is ready
this._disposables.push(
vscode.window.onDidChangeTextEditorSelection(async () => {
const editor = vscode.window.activeTextEditor;
if (!editor) {
return;
}
const selectedCode = getSelectedCode(editor);
const selectedCodeLineRange = getSelectedCodeLineRange(editor);
this.sendMessageToWebview({ type: "selectedCodeInfo", value: {start: selectedCodeLineRange.start, end: selectedCodeLineRange.end, selectedCode: selectedCode} });
})
);
}

if (this._pacWrapper) {
this.setupFileWatcher();
}
Expand Down Expand Up @@ -422,6 +437,7 @@ export class PowerPagesCopilot implements vscode.WebviewViewProvider {
</div>

<div class="chat-input" id="input-component">
<label for="chat-input" class="input-label hide" id="input-label-id"></label>
<div class="input-container">
<input type="text" placeholder="What do you need help with?" id="chat-input" class="input-field">
<button aria-label="Match Case" id="send-button" class="send-button">
Expand Down
13 changes: 11 additions & 2 deletions src/common/copilot/assets/scripts/copilot.js
Original file line number Diff line number Diff line change
Expand Up @@ -242,7 +242,6 @@
<path d="M14.3051 16.6203C14.4828 16.6203 14.6073 16.5314 14.6784 16.3536C15.0695 15.2514 15.8517 13.5092 17.0251 11.127C17.0606 10.9847 17.0428 10.8603 16.9717 10.7536C16.9006 10.6114 16.7762 10.5581 16.5984 10.5936H13.3451L12.8117 9.95363V9.47363L13.8784 7.0203C13.914 6.94919 13.914 6.87808 13.8784 6.80697C13.8784 6.7003 13.8428 6.62919 13.7717 6.59363C13.7006 6.52252 13.6117 6.48697 13.5051 6.48697C13.434 6.48697 13.3628 6.52252 13.2917 6.59363L7.21172 12.1403L6.73172 12.3003H5.39839C5.29172 12.3003 5.18506 12.3359 5.07839 12.407C5.00728 12.4781 4.9895 12.567 5.02506 12.6736V16.1936C4.9895 16.3003 5.00728 16.407 5.07839 16.5136C5.18506 16.5847 5.29172 16.6203 5.39839 16.6203H14.3051Z" fill="none" id="thumbsup-path"/>
</svg>


<svg class="thumbsdown" cursor="pointer" width="22" height="23" viewBox="0 0 22 23" fill="none" xmlns="http://www.w3.org/2000/svg">
<title>Thumbs Down</title>
<path d="M8.48 17.6336C8.19556 17.6336 7.92889 17.5447 7.68 17.367C7.43111 17.1536 7.25333 16.9047 7.14667 16.6203C7.07556 16.3003 7.11111 15.9803 7.25333 15.6603L8.21333 13.4736H5.44C5.19111 13.5092 4.96 13.4736 4.74667 13.367C4.53333 13.2603 4.35556 13.1181 4.21333 12.9403C4.10667 12.727 4.03556 12.4959 4 12.247C4 11.9981 4.05333 11.767 4.16 11.5536C5.40444 8.92252 6.16889 7.19808 6.45333 6.3803C6.56 6.13141 6.72 5.93586 6.93333 5.79363C7.18222 5.61586 7.44889 5.50919 7.73333 5.47363H16.64C17.0311 5.50919 17.3511 5.66919 17.6 5.95363C17.8844 6.20252 18.0267 6.52252 18.0267 6.91363V10.4336C18.0267 10.7892 17.8844 11.1092 17.6 11.3936C17.3511 11.6425 17.0311 11.767 16.64 11.767H15.3067L9.44 17.2603C9.15556 17.5092 8.83556 17.6336 8.48 17.6336ZM7.73333 6.48697C7.55556 6.48697 7.43111 6.57586 7.36 6.75363C6.96889 7.85586 6.20444 9.59808 5.06667 11.9803C4.99556 12.1225 4.99556 12.2647 5.06667 12.407C5.13778 12.5136 5.26222 12.5492 5.44 12.5136H8.74667L9.22667 13.1536V13.6336L8.16 16.087C8.12444 16.1581 8.10667 16.247 8.10667 16.3536C8.14222 16.4247 8.19556 16.4959 8.26667 16.567C8.33778 16.6025 8.40889 16.6203 8.48 16.6203C8.58667 16.6203 8.67556 16.5847 8.74667 16.5136L14.8267 10.967L15.3067 10.807H16.64C16.7467 10.807 16.8356 10.7714 16.9067 10.7003C17.0133 10.6292 17.0667 10.5403 17.0667 10.4336V6.91363C17.0667 6.80697 17.0133 6.71808 16.9067 6.64697C16.8356 6.5403 16.7467 6.48697 16.64 6.48697H7.73333Z" class = "thumbsdown-clicked"/>
Expand Down Expand Up @@ -485,7 +484,17 @@
welcomeScreen.userLoggedIn();
}
break;
}}
}
case "selectedCodeInfo": {
const chatInputLabel = document.getElementById("input-label-id");
if (message.value.start == message.value.end && message.value.selectedCode.length == 0) {
chatInputLabel.classList.add("hide");
break;
}
chatInputLabel.classList.remove("hide");
chatInputLabel.innerText = `Lines: ${message.value.start + 1} - ${message.value.end + 1} selected`;
}
}
});

function handleLoginButtonClick() {
Expand Down
20 changes: 16 additions & 4 deletions src/common/copilot/assets/styles/copilot.css
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,16 @@ body {
padding: 12px;
}

.input-label {
margin-bottom: 1px;
color: var(--vscode-input-placeholderForeground);
font-size: 12px;
background: var(--vscode-panelSectionHeader-background);
padding: 5px 0px 5px 10px;
height: auto;
box-sizing: border-box;
}

.input-container {
display: flex;
align-items: center;
Expand Down Expand Up @@ -156,7 +166,6 @@ body {
margin: 10px 0px;
border-radius: 4px;
background-color: var(--vscode-sideBar-background)

}

.code-pre {
Expand Down Expand Up @@ -287,7 +296,8 @@ hr {
color: var(--vscode-input-placeholderForeground);
}

.walkthrough-content, .suggested-prompt {
.walkthrough-content,
.suggested-prompt {
display: inline-flex;
align-items: center;
}
Expand All @@ -310,6 +320,8 @@ hr {


.icon-container {
width: 14px; /* Set a fixed width for the icon */
margin-right: 4px; /* Add some spacing between icon and text */
width: 14px;
/* Set a fixed width for the icon */
margin-right: 4px;
/* Add some spacing between icon and text */
}
1 change: 1 addition & 0 deletions src/common/copilot/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ export const INPUT_CONTENT_FILTERED = 'InputContentFiltered';
export const PROMPT_LIMIT_EXCEEDED = 'PromptLimitExceeded';
export const INVALID_INFERENCE_INPUT = 'InvalidInferenceInput';
export const COPILOT_NOTIFICATION_DISABLED = 'isCopilotNotificationDisabled'
export const SELECTED_CODE_INFO_ENABLED = false;

export type WebViewMessage = {
type: string;
Expand Down
Loading