Skip to content

Commit

Permalink
Merge branch 'main' into users/amitjoshi/copilotPanelLocJson
Browse files Browse the repository at this point in the history
  • Loading branch information
amitjoshi438 authored May 1, 2024
2 parents 4ae51bb + 8c25e3a commit ecedc03
Show file tree
Hide file tree
Showing 18 changed files with 645 additions and 402 deletions.
671 changes: 323 additions & 348 deletions package-lock.json

Large diffs are not rendered by default.

10 changes: 3 additions & 7 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -1085,7 +1085,7 @@
"yargs": "^16.2.0"
},
"dependencies": {
"@fluidframework/azure-client": "^1.1.1",
"@fluidframework/azure-client": "^1.2.0",
"@microsoft/1ds-core-js": "4.0.5",
"@microsoft/1ds-post-js": "4.0.5",
"@microsoft/generator-powerpages": "1.21.19",
Expand All @@ -1096,7 +1096,7 @@
"cockatiel": "^3.1.1",
"command-exists": "^1.2.9",
"find-process": "^1.4.7",
"fluid-framework": "^1.3.3",
"fluid-framework": "^1.4.0",
"glob": "^7.1.7",
"gpt-tokenizer": "^2.1.1",
"https-browserify": "^1.0.0",
Expand All @@ -1123,9 +1123,5 @@
"optionalDependencies": {
"bufferutil": "^4.0.6",
"utf-8-validate": "^5.0.9"
},
"overrides": {
"jsrsasign": "^11.0.0",
"axios": "^0.28.0"
}
}
}
10 changes: 5 additions & 5 deletions src/common/copilot/PowerPagesCopilot.ts
Original file line number Diff line number Diff line change
Expand Up @@ -277,11 +277,11 @@ export class PowerPagesCopilot implements vscode.WebviewViewProvider {

if (feedbackValue === THUMBS_UP) {

sendTelemetryEvent(this.telemetry, { eventName: CopilotUserFeedbackThumbsUpEvent, copilotSessionId: sessionID, orgId: orgID, subScenario: String(messageScenario)});
sendTelemetryEvent(this.telemetry, { eventName: CopilotUserFeedbackThumbsUpEvent, copilotSessionId: sessionID, orgId: orgID, subScenario: String(messageScenario) });
CESUserFeedback(this._extensionContext, sessionID, userID, THUMBS_UP, this.telemetry, this.geoName as string, messageScenario, tenantId)
} else if (feedbackValue === THUMBS_DOWN) {

sendTelemetryEvent(this.telemetry, { eventName: CopilotUserFeedbackThumbsDownEvent, copilotSessionId: sessionID, orgId: orgID, subScenario: String(messageScenario)});
sendTelemetryEvent(this.telemetry, { eventName: CopilotUserFeedbackThumbsDownEvent, copilotSessionId: sessionID, orgId: orgID, subScenario: String(messageScenario) });
CESUserFeedback(this._extensionContext, sessionID, userID, THUMBS_DOWN, this.telemetry, this.geoName as string, messageScenario, tenantId)
}
break;
Expand Down Expand Up @@ -363,12 +363,12 @@ export class PowerPagesCopilot implements vscode.WebviewViewProvider {
this.sendMessageToWebview({ type: 'userName', value: userName });

let metadataInfo = { entityName: '', formName: '' };
let componentInfo : string[] = [];
let componentInfo: string[] = [];

if (activeFileParams.dataverseEntity == ADX_ENTITYFORM || activeFileParams.dataverseEntity == ADX_ENTITYLIST) {
metadataInfo = await getEntityName(telemetry, sessionID, activeFileParams.dataverseEntity);

const dataverseToken = await dataverseAuthentication(activeOrgUrl, true);
const dataverseToken = (await dataverseAuthentication(activeOrgUrl, true)).accessToken;

if (activeFileParams.dataverseEntity == ADX_ENTITYFORM) {
const formColumns = await getFormXml(metadataInfo.entityName, metadataInfo.formName, activeOrgUrl, dataverseToken, telemetry, sessionID);
Expand Down Expand Up @@ -498,7 +498,7 @@ export class PowerPagesCopilot implements vscode.WebviewViewProvider {
<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">
<textarea rows=1 placeholder="What do you need help with?" id="chat-input" class="input-field"></textarea>
<button aria-label="Match Case" id="send-button" class="send-button">
<span>
${sendIconSvg}
Expand Down
7 changes: 6 additions & 1 deletion src/common/copilot/assets/styles/copilot.css
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,12 @@ body {
outline: none;
color: var(--vscode-inputOption-activeForeground);
background-color: transparent;
white-space: pre-wrap;
resize: none;
font-family: var(--vscode-font-family);
}

.input-field::-webkit-scrollbar {
display: none;
}

.input-field:focus {
Expand Down
14 changes: 14 additions & 0 deletions src/common/ecs-features/constants.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
/*
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*/

export const ECS_REQUEST_URL_TEMPLATE = "https://ecs.office.com/config/v1";

export const PowerPagesClientName = 'PortalsMakerExperiences'; // Project name in ECS Portal, Do not change this
export type ProjectTeam = typeof PowerPagesClientName;
export const PowerPagesAppName = 'powerpages-microsoft-com'; // Project name in ECS Portal, Do not change this
export type ProjectName = typeof PowerPagesAppName;

export const VisualStudioCodeDevInsidersUrl = 'https://insiders.vscode.dev/power/portal'; // VScode dev insiders/pre-prod env
export const VisualStudioCodeDevUrl = 'https://vscode.dev/power/portal'; // VScode dev GA/prod env
50 changes: 50 additions & 0 deletions src/common/ecs-features/ecsFeatureClient.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
/*
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*/

import TelemetryReporter from "@vscode/extension-telemetry";
import { ITelemetry } from "../../client/telemetry/ITelemetry";
import { createECSRequestURL } from "./ecsFeatureUtil";
import { ECSFeatureDefinition as ECSFeatureProperties } from "./ecsFeatureProperties";
import { ECSAPIFeatureFlagFilters } from "./ecsFeatureFlagFilters";

export abstract class ECSFeaturesClient {
private static _ecsConfig: Record<string, string | boolean>;
private static _featuresConfig = {};

// Initialize ECSFeatureClient - any client config can be fetched with utility function like below
// EnableMultifileVscodeWeb.getConfig().enableMultifileVscodeWeb
public static async init(telemetry: ITelemetry | TelemetryReporter, filters: ECSAPIFeatureFlagFilters, clientName: string) {
if (this._ecsConfig) return;

const requestURL = createECSRequestURL(filters, clientName);
try {
const response = await fetch(requestURL, {
method: 'GET'
});
if (!response.ok) {
throw new Error('Request failed');
}
const result = await response.json();
// Update telemetry in other PR
// telemetry.sendTelemetryEvent('ECSConfig', {});

// Initialize ECS config
this._ecsConfig = result[clientName];
} catch (error) {
// Log error
// telemetry.sendTelemetryEvent('ECSConfigError', {});
}
}

public static getConfig<TConfig extends Record<string, boolean | string>, TeamName extends string>(
feature: ECSFeatureProperties<TConfig, TeamName>
) {
if (Object.keys(this._featuresConfig).length === 0) {
this._featuresConfig = this._ecsConfig && feature.extractECSFeatureFlagConfig?.(this._ecsConfig as TConfig);
}

return Object.keys(this._featuresConfig).length === 0 ? feature.fallback : this._featuresConfig;
}
}
29 changes: 29 additions & 0 deletions src/common/ecs-features/ecsFeatureFlagFilters.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
/*
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*/

export interface ECSAPIFeatureFlagFilters {
/**
* Application AppName
* @example powerpages-microsoft-com
*/
AppName: string;

/** The AAD user object ID or MSA. */
UserID: string;

/** The AAD tenant object ID. */
TenantID: string;

/** Unique Dataverse Environment ID */
EnvID: string;

/**
* Deployment region
* @example test, preview, prod
*/
Region: string;

// TBD - more API call filters to be added later
}
17 changes: 17 additions & 0 deletions src/common/ecs-features/ecsFeatureGates.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
/*
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*/

import { PowerPagesClientName } from './constants';
import { getFeatureConfigs } from './ecsFeatureUtil';

export const {
feature: EnableMultifileVscodeWeb
} = getFeatureConfigs({
teamName: PowerPagesClientName,
description: 'Enable multiple file view in Visual Studio Code Web',
fallback: {
enableMultifileVscodeWeb: false,
},
});
68 changes: 68 additions & 0 deletions src/common/ecs-features/ecsFeatureProperties.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
/*
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*/

/**
* Interface representing a Feature config in ECS.
*/
export interface ECSFeatureDefinition<TConfig extends Record<string, string | boolean>, TeamName extends string> {
/**
* Name of the Team owning the feature. Must match the "clientTeam" name configured in ECS.
*/
teamName: TeamName;

/**
* Fallback config to be used while loading or if configs are unavailable.
*/
fallback: TConfig;

/**
* Brief description of the feature (used for tracking/cleanup purposes)
*/
description?: string;

/**
* Callback to extract the Feature-specific config from the Team config.
* @param config overall config for the Team.
*/
extractECSFeatureFlagConfig<TTeamConfig extends TConfig>(config: TTeamConfig): Partial<TConfig>;
}

export type ECSFeatureInfo<TConfig extends Record<string, boolean | string>, TeamName extends string> = Omit<
ECSFeatureDefinition<TConfig, TeamName>,
'extractECSFeatureFlagConfig'
>;

/**
* Creates a Feature object based on the feature definition that includes fallback flags and the team owning the feature.
* @param featureInfo Feature definition specifying the fallback flags and the team owning the feature.
*/
export function createECSFeatureDefinition<TConfig extends Record<string, boolean | string>, TeamName extends string>(
featureInfo: ECSFeatureInfo<TConfig, TeamName>
): ECSFeatureDefinition<TConfig, TeamName> {
return {
...featureInfo,
extractECSFeatureFlagConfig: (config) => extractECSFeatureFlagConfig(config, Object.keys(featureInfo.fallback)),
};
}

/**
* Extracts the feature-specific config, based on the provided keys, from the overall Project Team config
* @param teamConfig the overall config object for the Project Team
* @param keys property names to extract from the Project Team config
*/
function extractECSFeatureFlagConfig<TConfig extends Record<string, boolean | string>, TeamConfig extends TConfig>(
teamConfig: TeamConfig,
keys: (keyof TConfig)[]
): Partial<TConfig> {
const config: Partial<TConfig> = {};

for (const key of keys) {
if (typeof teamConfig[key] !== 'undefined') {
config[key] = teamConfig[key];
}
}

return config;
}
38 changes: 38 additions & 0 deletions src/common/ecs-features/ecsFeatureUtil.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
/*
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*/

import { PowerPagesClientName, ECS_REQUEST_URL_TEMPLATE } from "./constants";
import { ECSFeaturesClient } from "./ecsFeatureClient";
import { ECSAPIFeatureFlagFilters } from "./ecsFeatureFlagFilters";
import { ECSFeatureDefinition, ECSFeatureInfo, createECSFeatureDefinition } from "./ecsFeatureProperties";

export function createECSRequestURL(filters: ECSAPIFeatureFlagFilters, clientName = PowerPagesClientName): string {
const queryParams: { [key: string]: string } = {
AppName: filters.AppName,
EnvironmentID: filters.EnvID,
UserID: filters.UserID,
TenantID: filters.TenantID,
region: filters.Region
};

const queryString = Object.keys(queryParams)
.map(key => `${key}=${encodeURIComponent(queryParams[key])}`)
.join('&');

return `${ECS_REQUEST_URL_TEMPLATE}/${clientName}/1.0.0.0?${queryString}`;
}

export function getFeatureConfigs<TConfig extends Record<string, string | boolean>, TeamName extends string>(featureInfo: ECSFeatureInfo<TConfig, TeamName>) {
type EnhancedFeature = ECSFeatureDefinition<TConfig, TeamName> & {
getConfig: () => Partial<TConfig>;
};

const feature = createECSFeatureDefinition(featureInfo) as EnhancedFeature;
feature.getConfig = () => ECSFeaturesClient.getConfig(feature);

return {
feature: feature,
};
}
4 changes: 3 additions & 1 deletion src/web/client/WebExtensionContext.ts
Original file line number Diff line number Diff line change
Expand Up @@ -370,14 +370,15 @@ class WebExtensionContext implements IWebExtensionContext {
const dataverseOrgUrl = this.urlParametersMap.get(
Constants.queryParameters.ORG_URL
) as string;
const accessToken: string = await dataverseAuthentication(
const { accessToken, userId } = await dataverseAuthentication(
dataverseOrgUrl,
firstTimeAuth
);

if (accessToken.length === 0) {
// re-set all properties to default values
this._dataverseAccessToken = "";
this._userId = "";
this._websiteIdToLanguage = new Map<string, string>();
this._websiteLanguageIdToPortalLanguageMap = new Map<
string,
Expand All @@ -394,6 +395,7 @@ class WebExtensionContext implements IWebExtensionContext {
}

this._dataverseAccessToken = accessToken;
this._userId = userId;
}

public async updateFileDetailsInContext(
Expand Down
13 changes: 7 additions & 6 deletions src/web/client/common/authenticationProvider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -87,8 +87,9 @@ export async function intelligenceAPIAuthentication(telemetry: ITelemetry, sessi
export async function dataverseAuthentication(
dataverseOrgURL: string,
firstTimeAuth = false
): Promise<string> {
): Promise<{ accessToken: string, userId: string }> {
let accessToken = "";
let userId = "";
try {
let session = await vscode.authentication.getSession(
PROVIDER_ID,
Expand All @@ -110,6 +111,9 @@ export async function dataverseAuthentication(
}

accessToken = session?.accessToken ?? "";
userId = session?.account.id.split("/").pop() ??
session?.account.id ??
"";
if (!accessToken) {
throw new Error(ERRORS.NO_ACCESS_TOKEN);
}
Expand All @@ -118,10 +122,7 @@ export async function dataverseAuthentication(
WebExtensionContext.telemetry.sendInfoTelemetry(
telemetryEventNames.WEB_EXTENSION_DATAVERSE_AUTHENTICATION_COMPLETED,
{
userId:
session?.account.id.split("/").pop() ??
session?.account.id ??
"",
userId: userId
}
);
}
Expand All @@ -140,7 +141,7 @@ export async function dataverseAuthentication(
);
}

return accessToken;
return { accessToken, userId };
}

export async function npsAuthentication(
Expand Down
Loading

0 comments on commit ecedc03

Please sign in to comment.