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

build: merge back main into dev branch #12232

Merged
merged 34 commits into from
Aug 15, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
33a0dc6
Merge pull request #12176 from OfficeDev/dev
kimizhu Aug 7, 2024
2502a99
perf: update generator for json path
KennethBWSong Aug 7, 2024
b682900
Merge pull request #12178 from OfficeDev/bowsong/hotfix_generator
kimizhu Aug 7, 2024
d38773f
fix: scaffold twice
jayzhang Aug 7, 2024
9f109f2
fix: command execute failed due to shell-quote
lijie-lee Aug 8, 2024
5395cb0
Merge pull request #12187 from OfficeDev/huajie/hotfix-oaddin
kimizhu Aug 8, 2024
339ac94
Merge pull request #12189 from OfficeDev/lijie/fix/local_debug_cmd_ex…
kimizhu Aug 8, 2024
ff529f6
fix: cli description
yuqizhou77 Aug 8, 2024
7e2166b
test: ut
yuqizhou77 Aug 8, 2024
116d05f
test: ut
yuqizhou77 Aug 8, 2024
f319927
Merge pull request #12192 from OfficeDev/yuqzho/cli-description
kimizhu Aug 8, 2024
926fa16
fix: the placeholder is not replace app name
huimiu Aug 8, 2024
0c0d708
Merge branch 'main' into hui/typeb-fix
huimiu Aug 8, 2024
6f0d7ca
Merge pull request #12195 from OfficeDev/hui/typeb-fix
kimizhu Aug 8, 2024
f1fd978
fix: fix bug in ai generator python template
KennethBWSong Aug 12, 2024
d46dd3a
fix: add missing import in ai generator python openai template
KennethBWSong Aug 12, 2024
a58046c
Merge pull request #12207 from OfficeDev/bowsong/fix_python_template
kimizhu Aug 12, 2024
da4e4ef
fix(vsc): svg not shown in react app
tecton Aug 12, 2024
fe5c506
Merge pull request #12211 from OfficeDev/nintan/fix-svg-import
kimizhu Aug 12, 2024
13203a2
fix: update launch file for ai generator python template
KennethBWSong Aug 12, 2024
f1bbfe3
docs: update august changelog
MuyangAmigo Aug 12, 2024
b744d9d
docs: update august changelog for language issues
MuyangAmigo Aug 12, 2024
8e22d5e
Merge branch 'main' into changelog-aug
qinezh Aug 13, 2024
2c8d5a8
fix: dc template instruction/description
yuqizhou77 Aug 13, 2024
9620719
Merge pull request #12212 from OfficeDev/bowsong/hotfix_launch
kimizhu Aug 13, 2024
8b5f7bf
Merge branch 'main' into changelog-aug
MuyangAmigo Aug 13, 2024
bfe7f2d
docs: update changelog
MuyangAmigo Aug 13, 2024
b9e539f
Merge pull request #12215 from OfficeDev/changelog-aug
kimizhu Aug 13, 2024
0a4a7c1
fix: dc template more
yuqizhou77 Aug 13, 2024
1ecfb18
Merge branch 'main' into yuqzho/dc-template-fix
yuqizhou77 Aug 13, 2024
4ae3227
Merge pull request #12221 from OfficeDev/yuqzho/dc-template-fix
kimizhu Aug 13, 2024
2857e9f
fix: fix remote run for ai generator python template
KennethBWSong Aug 14, 2024
d0102ed
fix: fix lint error
KennethBWSong Aug 15, 2024
b2df3df
Merge pull request #12227 from OfficeDev/bowsong/hotfix_remote
kimizhu Aug 15, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion packages/cli/src/userInteraction.ts
Original file line number Diff line number Diff line change
Expand Up @@ -206,7 +206,9 @@ class CLIUserInteraction implements UserInteraction {
const choices = (option as OptionItem[]).map((op) => {
return {
id: op.id,
title: labelClean(op.label),
title: !op.description
? labelClean(op.label)
: labelClean(op.label) + ` (${op.description})`,
detail: op.detail,
};
});
Expand Down
30 changes: 30 additions & 0 deletions packages/cli/tests/unit/ui.tests.ts
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,36 @@ describe("User Interaction Tests", function () {
}
});

it("Add description in title", async () => {
const config: SingleSelectConfig = {
name: "test",
title: "test",
options: [{ id: "id1", description: "some description", label: "label" }],
};
sandbox.stub(UI, "loadSelectDynamicData").resolves(ok({} as any));
sandbox.stub(UI, "singleSelect").resolves(ok("id1"));
const result = await UI.selectOption(config);
expect(result.isOk());
if (result.isOk()) {
expect(result.value.result).equal("id1");
}
});

it("No description in title", async () => {
const config: SingleSelectConfig = {
name: "test",
title: "test",
options: [{ id: "id1", label: "label" }],
};
sandbox.stub(UI, "loadSelectDynamicData").resolves(ok({} as any));
sandbox.stub(UI, "singleSelect").resolves(ok("id1"));
const result = await UI.selectOption(config);
expect(result.isOk());
if (result.isOk()) {
expect(result.value.result).equal("id1");
}
});

it("invalid option", async () => {
sandbox.stub(UI, "singleSelect").resolves(ok("c"));
const config: SingleSelectConfig = {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
/* eslint-disable @typescript-eslint/no-namespace */
import * as cp from "child_process";
import * as os from "os";
import * as shellQuote from "shell-quote";

export interface DebugLogger {
debug(message: string): void;
Expand Down Expand Up @@ -57,8 +56,7 @@ export namespace cpUtils {
};
Object.assign(options, additionalOptions);

const quotedCommand = shellQuote.quote([command]);
const childProc: cp.ChildProcess = cp.spawn(quotedCommand, args, options);
const childProc: cp.ChildProcess = cp.spawn(command, args, options);
let timer: NodeJS.Timeout;
if (options.timeout && options.timeout > 0) {
// timeout only exists for exec not spawn
Expand Down
4 changes: 2 additions & 2 deletions packages/fx-core/src/component/generator/apiSpec/helper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -916,7 +916,7 @@ async function updateAdaptiveCardForCustomApi(
const name = item.item.operationId!.replace(/[^a-zA-Z0-9]/g, "_");
const [card, jsonPath] = AdaptiveCardGenerator.generateAdaptiveCard(item.item, true);
if (jsonPath !== "$" && card.body && card.body[0] && (card.body[0] as any).$data) {
(card.body as any).$data = `\${${jsonPath}}`;
(card.body[0] as any).$data = `\${${jsonPath}}`;
}
const cardFilePath = path.join(adaptiveCardsFolderPath, `${name}.json`);
await fs.writeFile(cardFilePath, JSON.stringify(card, null, 2));
Expand Down Expand Up @@ -1022,7 +1022,7 @@ async def {{operationId}}(
):
parameters = context.data
path = parameters.get("path", {})
body = parameters.get("body", {})
body = parameters.get("body", None)
query = parameters.get("query", {})
resp = client.{{operationId}}(**path, json=body, _headers={}, _params=query, _cookies={})

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -259,55 +259,4 @@ export class OfficeAddinGeneratorNew extends DefaultTemplateGenerator {
if (res.isErr()) return err(res.error);
return Promise.resolve(ok([{ templateName: tplName, language: lang }]));
}

public async post(
context: Context,
inputs: Inputs,
destinationPath: string,
actionContext?: ActionContext
): Promise<Result<GeneratorResult, FxError>> {
const res = await OfficeAddinGenerator.doScaffolding(context, inputs, destinationPath);
if (res.isErr()) return err(res.error);
await this.fixIconPath(destinationPath);
return ok({});
}

/**
* this is a work around for MOS API bug that will return invalid package if the icon path is not root folder of appPackage
* so this function will move the two icon files to root folder of appPackage and update the manifest.json
*/
async fixIconPath(projectPath: string): Promise<void> {
const outlineOldPath = join(projectPath, "appPackage", "assets", "outline.png");
const colorOldPath = join(projectPath, "appPackage", "assets", "color.png");
const outlineNewPath = join(projectPath, "appPackage", "outline.png");
const colorNewPath = join(projectPath, "appPackage", "color.png");
const manifestPath = join(projectPath, "appPackage", "manifest.json");
if (!(await fse.pathExists(manifestPath))) return;
const manifest = await fse.readJson(manifestPath);
let change = false;
if (manifest.icons.outline === "assets/outline.png") {
if ((await fse.pathExists(outlineOldPath)) && !(await fse.pathExists(outlineNewPath))) {
await fse.move(outlineOldPath, outlineNewPath);
manifest.icons.outline = "outline.png";
change = true;
}
}
if (manifest.icons.color === "assets/color.png") {
if ((await fse.pathExists(colorOldPath)) && !(await fse.pathExists(colorNewPath))) {
await fse.move(colorOldPath, colorNewPath);
manifest.icons.color = "color.png";
change = true;
}
}
if (change) {
await fse.writeJson(manifestPath, manifest, { spaces: 4 });
const webpackConfigPath = join(projectPath, "webpack.config.js");
const content = await fse.readFile(webpackConfigPath, "utf8");
const newContent = content.replace(
'from: "appPackage/assets/*",\r\n to: "assets/[name][ext][query]",\r\n },',
'from: "appPackage/assets/*",\r\n to: "assets/[name][ext][query]",\r\n },\r\n {\r\n from: "appPackage/*.png",\r\n to: "[name]" + "[ext]",\r\n },'
);
await fse.writeFile(webpackConfigPath, newContent);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -1033,191 +1033,6 @@ describe("OfficeAddinGeneratorNew", () => {
chai.assert.isTrue(res.isErr());
});
});

describe("post()", () => {
const sandbox = sinon.createSandbox();
afterEach(() => {
sandbox.restore();
});
it(`happy`, async () => {
const inputs: Inputs = {
platform: Platform.CLI,
projectPath: "./",
};
sandbox.stub(OfficeAddinGenerator, "doScaffolding").resolves(ok(undefined));
sandbox.stub(generator, "fixIconPath").resolves();
const res = await generator.post(context, inputs, "./");
chai.assert.isTrue(res.isOk());
});
});
});

describe("fixIconPath()", () => {
const generator = new OfficeAddinGeneratorNew();
const sandbox = sinon.createSandbox();
beforeEach(() => {
sandbox.stub(fse, "readFile").resolves("" as any);
sandbox.stub(fse, "writeFile").resolves();
});
afterEach(() => {
sandbox.restore();
});
it("manifest not found", async () => {
sandbox.stub(fse, "pathExists").resolves(false);
const move = sandbox.stub(fse, "move").resolves();
await generator.fixIconPath("./");
chai.assert.isTrue(move.notCalled);
});
it("happy", async () => {
sandbox.stub(fse, "pathExists").callsFake(async (path) => {
if (path.endsWith("manifest.json")) {
return true;
} else if (path.endsWith("assets/outline.png") || path.endsWith("assets\\outline.png")) {
return true;
} else if (path.endsWith("assets/color.png") || path.endsWith("assets\\color.png")) {
return true;
} else if (path.endsWith("color.png")) {
return false;
} else if (path.endsWith("outline.png")) {
return false;
}
});
sandbox
.stub(fse, "readJson")
.resolves({ icons: { outline: "assets/outline.png", color: "assets/color.png" } });
const move = sandbox.stub(fse, "move").resolves();
const writeJson = sandbox.stub(fse, "writeJson").resolves();
await generator.fixIconPath("./");
chai.assert.isTrue(move.calledTwice);
chai.assert.isTrue(writeJson.calledOnce);
});
it("no need to move", async () => {
sandbox.stub(fse, "pathExists").callsFake(async (path) => {
if (path.endsWith("manifest.json")) {
return true;
} else if (path.endsWith("assets/outline.png") || path.endsWith("assets\\outline.png")) {
return true;
} else if (path.endsWith("assets/color.png") || path.endsWith("assets\\color.png")) {
return true;
} else if (path.endsWith("color.png")) {
return false;
} else if (path.endsWith("outline.png")) {
return false;
}
});
sandbox
.stub(fse, "readJson")
.resolves({ icons: { outline: "outline.png", color: "color.png" } });
const move = sandbox.stub(fse, "move").resolves();
const writeJson = sandbox.stub(fse, "writeJson").resolves();
await generator.fixIconPath("./");
chai.assert.isTrue(move.notCalled);
chai.assert.isTrue(writeJson.notCalled);
});
it("no need to move", async () => {
sandbox.stub(fse, "pathExists").callsFake(async (path) => {
if (path.endsWith("manifest.json")) {
return true;
} else if (path.endsWith("assets/outline.png") || path.endsWith("assets\\outline.png")) {
return false;
} else if (path.endsWith("assets/color.png") || path.endsWith("assets\\color.png")) {
return false;
} else if (path.endsWith("color.png")) {
return false;
} else if (path.endsWith("outline.png")) {
return false;
}
});
sandbox
.stub(fse, "readJson")
.resolves({ icons: { outline: "assets/outline.png", color: "assets/color.png" } });
const move = sandbox.stub(fse, "move").resolves();
const writeJson = sandbox.stub(fse, "writeJson").resolves();
await generator.fixIconPath("./");
chai.assert.isTrue(move.notCalled);
chai.assert.isTrue(writeJson.notCalled);
});
describe("fixIconPath()", () => {
const sandbox = sinon.createSandbox();
afterEach(() => {
sandbox.restore();
});
it("manifest not found", async () => {
sandbox.stub(fse, "pathExists").resolves(false);
const move = sandbox.stub(fse, "move").resolves();
await generator.fixIconPath("./");
chai.assert.isTrue(move.notCalled);
});
it("happy", async () => {
sandbox.stub(fse, "pathExists").callsFake(async (path) => {
if (path.endsWith("manifest.json")) {
return true;
} else if (path.endsWith("assets/outline.png") || path.endsWith("assets\\outline.png")) {
return true;
} else if (path.endsWith("assets/color.png") || path.endsWith("assets\\color.png")) {
return true;
} else if (path.endsWith("color.png")) {
return false;
} else if (path.endsWith("outline.png")) {
return false;
}
});
sandbox
.stub(fse, "readJson")
.resolves({ icons: { outline: "assets/outline.png", color: "assets/color.png" } });
const move = sandbox.stub(fse, "move").resolves();
const writeJson = sandbox.stub(fse, "writeJson").resolves();
await generator.fixIconPath("./");
chai.assert.isTrue(move.calledTwice);
chai.assert.isTrue(writeJson.calledOnce);
});
it("no need to move", async () => {
sandbox.stub(fse, "pathExists").callsFake(async (path) => {
if (path.endsWith("manifest.json")) {
return true;
} else if (path.endsWith("assets/outline.png") || path.endsWith("assets\\outline.png")) {
return true;
} else if (path.endsWith("assets/color.png") || path.endsWith("assets\\color.png")) {
return true;
} else if (path.endsWith("color.png")) {
return false;
} else if (path.endsWith("outline.png")) {
return false;
}
});
sandbox
.stub(fse, "readJson")
.resolves({ icons: { outline: "outline.png", color: "color.png" } });
const move = sandbox.stub(fse, "move").resolves();
const writeJson = sandbox.stub(fse, "writeJson").resolves();
await generator.fixIconPath("./");
chai.assert.isTrue(move.notCalled);
chai.assert.isTrue(writeJson.notCalled);
});
it("no need to move", async () => {
sandbox.stub(fse, "pathExists").callsFake(async (path) => {
if (path.endsWith("manifest.json")) {
return true;
} else if (path.endsWith("assets/outline.png") || path.endsWith("assets\\outline.png")) {
return false;
} else if (path.endsWith("assets/color.png") || path.endsWith("assets\\color.png")) {
return false;
} else if (path.endsWith("color.png")) {
return false;
} else if (path.endsWith("outline.png")) {
return false;
}
});
sandbox
.stub(fse, "readJson")
.resolves({ icons: { outline: "assets/outline.png", color: "assets/color.png" } });
const move = sandbox.stub(fse, "move").resolves();
const writeJson = sandbox.stub(fse, "writeJson").resolves();
await generator.fixIconPath("./");
chai.assert.isTrue(move.notCalled);
chai.assert.isTrue(writeJson.notCalled);
});
});
});

describe("doScaffolding()", () => {
Expand Down
33 changes: 33 additions & 0 deletions packages/vscode-extension/PRERELEASE.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,39 @@

> Note: This changelog only includes the changes for the pre-release versions of Teams Toolkit. For the changelog of stable versions, please refer to the [Teams Toolkit Changelog](https://github.com/OfficeDev/TeamsFx/blob/dev/packages/vscode-extension/CHANGELOG.md).

### August 14, 2024

#### New Features
- **Enhanced App Validation**: Developers can now evaluate their app packages using the same test cases Microsoft employs during app review. The Enhanced App Validation feature in Teams Toolkit identifies any errors or warnings within your app package and provides clear guidelines for resolution. For more details on Microsoft test cases, refer to the [Teams Store validation guidelines](https://learn.microsoft.com/en-us/microsoftteams/platform/concepts/deploy-and-publish/appsource/prepare/teams-store-validation-guidelines) and [Commercial marketplace certification policies](https://learn.microsoft.com/en-us/legal/marketplace/certification-policies).
![App Validation](https://github.com/user-attachments/assets/4c2b8c49-6a0a-4ea7-8796-a94464714463)

- **Generate an Intelligent Chatbot with Python**: Following the release of support for building [Custom Engine Copilot](https://learn.microsoft.com/microsoft-365-copilot/extensibility/overview-custom-engine-copilot) during Build 2024, which included the ability to "chat with" your own API, Teams Toolkit now extends this capability to the Python programming language.
![App Generator](https://github.com/user-attachments/assets/21efa344-aea5-4d44-bb78-aa8e26dc68a1)

- **Create Declarative Copilot**: Teams Toolkit now allows you to build a declarative copilot, enabling you to customize Microsoft 365 Copilot by declaring specific instructions, actions, and knowledge. Declarative copilots run on the same orchestrator, foundation models, and trusted AI services that power Microsoft Copilot. You can learn more about [declarative copilots here](https://learn.microsoft.com/microsoft-365-copilot/extensibility/overview-declarative-copilot). The toolkit supports the creation of both basic declarative copilots and those with an API plugin.
![Declarative Copilot](https://github.com/user-attachments/assets/37412cdd-c7e8-4e38-bd45-794997b050ec)

- **Using Assistant API on Azure OpenAI Service**: The Teams Toolkit has updated the `AI Agent` (Python) app template to support the Assistant API on Azure OpenAI Service. You can now build your own AI Agents on Microsoft 365 using Python, with the option to use either Azure OpenAI Service or OpenAI directly. Support for TypeScript and JavaScript is forthcoming.

#### Enhancements

- Teams Toolkit will continue to update scaffold app templates to ensure compliance with [Teams Store validation guidelines](https://learn.microsoft.com/en-us/microsoftteams/platform/concepts/deploy-and-publish/appsource/prepare/teams-store-validation-guidelines). The first round of updates focuses on bot templates, including:
- [PR#12063](https://github.com/OfficeDev/teams-toolkit/pull/12063): Updated `Basic Bot` and `Message Extension`
- [PR#12096](https://github.com/OfficeDev/teams-toolkit/pull/12096): Updated `Chat Command`
- [PR#12123](https://github.com/OfficeDev/teams-toolkit/pull/12123): Updated `Chat Notification Messages`
- [PR#12119](https://github.com/OfficeDev/teams-toolkit/pull/12119): Updated `Sequential Workflow in Chat`
- Teams Toolkit now prompts users to generate an API key before debugging API ME or API Plugin with API Key authentication templates.
- Secret values have been redacted from the Visual Studio Code output channel.

#### Bug Fixes

- Fixed vulnerability issues in TeamsFx SDK. [#11973](https://github.com/OfficeDev/teams-toolkit/pull/11937)
- Resolved compatibility issues with `groupchat` and `groupChat` in the Teams app manifest. [#12028](https://github.com/OfficeDev/teams-toolkit/pull/12028)
- Corrected an issue where the link redirection for the lifecycle `Provision` button was incorrect. [#12120](https://github.com/OfficeDev/teams-toolkit/pull/12120)
- Fixed initialization failures of `publicClientApplication` in TeamsFx SDK. [#12159](https://github.com/OfficeDev/teams-toolkit/pull/12159)
- Addressed issues when creating SharePoint Framework-based tab apps. [#12173](https://github.com/OfficeDev/teams-toolkit/pull/12173)


### July 17, 2024

#### New Features
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import "./offlinePage.scss";

import * as React from "react";

import OfflineImage from "../../../img/webview/sample/offline.svg";
import OfflineImage from "../../../img/webview/sample/offline.svg?react";

export default class OfflinePage extends React.Component<unknown, unknown> {
constructor(props: unknown) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import * as React from "react";

import { Image } from "@fluentui/react";

import Turtle from "../../../img/webview/sample/turtle.svg";
import Turtle from "../../../img/webview/sample/turtle.svg?react";
import { TelemetryTriggerFrom } from "../../telemetry/extTelemetryEvents";
import { SampleProps } from "./ISamples";

Expand Down
Loading
Loading