Skip to content

Commit

Permalink
feat(solution): support configurable tabs. (#258)
Browse files Browse the repository at this point in the history
* fix(solution): save programming language in config

* fix lint error

* fix lint error

* feat(solution): support configurable tabs

* change sanity check for staticTabs and configurableTabs

* feat(solution): VSpublish

* remove tab scope question from solution

* fix(solution): remove tab scope question

* fix(solution): call setApplicationInContext after provision
  • Loading branch information
1yefuwang1 authored Apr 14, 2021
1 parent 158ddb3 commit fce3698
Show file tree
Hide file tree
Showing 3 changed files with 68 additions and 24 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -215,6 +215,8 @@ export namespace AppStudio {
appId: string,
domains: string[],
webApplicationInfoResource: string,
staticTabs: string,
configurableTabs: string,
tabEndpoint?: string,
appName?: string,
version?: string,
Expand Down Expand Up @@ -242,6 +244,14 @@ export namespace AppStudio {
updatedManifest.composeExtensions = JSON.parse(composeExtensions) as IComposeExtension[];
}

if (staticTabs) {
updatedManifest.staticTabs = JSON.parse(staticTabs);
}

if (configurableTabs) {
updatedManifest.configurableTabs = JSON.parse(configurableTabs);
}

for (const domain of domains) {
updatedManifest.validDomains?.push(domain);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@ export const PERMISSION_REQUEST = "permissionRequest";
* Config key whose value is either javascript, typescript or csharp.
*/
export const PROGRAMMING_LANGUAGE = "programmingLanguage";
export const STATIC_TABS = "staticTabs";
export const CONFIGURABLE_TABS = "configurableTabs";

/**
* Config keys that are useful for generating remote teams app manifest
Expand Down
80 changes: 56 additions & 24 deletions packages/fx-core/src/plugins/solution/fx-solution/solution.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,6 @@ import {
FRONTEND_DOMAIN,
FRONTEND_ENDPOINT,
AAD_REMOTE_CLIENT_ID,
TEAMS_APP_MANIFEST_TEMPLATE,
REMOTE_TEAMS_APP_ID,
Void,
SOLUTION_PROVISION_SUCCEEDED,
Expand All @@ -65,7 +64,9 @@ import {
WEB_APPLICATION_INFO_SOURCE,
LOCAL_WEB_APPLICATION_INFO_SOURCE,
PROVISION_MANIFEST,
PROGRAMMING_LANGUAGE
PROGRAMMING_LANGUAGE,
CONFIGURABLE_TABS,
STATIC_TABS
} from "./constants";

import { SpfxPlugin } from "../../resource/spfx";
Expand Down Expand Up @@ -781,12 +782,24 @@ export class TeamsAppSolution implements Solution {
ctx.logProvider?.debug(`Failed to get webApplicationInfoResource from aad by key ${WEB_APPLICATION_INFO_SOURCE}.`);
return err(returnSystemError(new Error("Failed to get webApplicationInfoResource"), "Solution", SolutionError.UpdateManifestError));
}
// STATIC_TABS and CONFIGURABLE_TABS are only available after postProvision.
const staticTabs = ctx.config.get(this.fehostPlugin.name)?.getString(STATIC_TABS);
const configurableTabs = ctx.config.get(this.fehostPlugin.name)?.getString(CONFIGURABLE_TABS);
if (!staticTabs || !configurableTabs ||
(staticTabs === "[]" && configurableTabs === "[]")) {
return err(returnSystemError(
new Error(`Invalid frontend config: ${STATIC_TABS}: ${staticTabs} ${CONFIGURABLE_TABS}: ${configurableTabs}`),
"Solution",
SolutionError.UpdateManifestError));
}

const [appDefinition, updatedManifest] = AppStudio.getDevAppDefinition(
manifestString,
clientId,
validDomains,
webApplicationInfoResource,
staticTabs,
configurableTabs,
endpoint.endsWith("/") ? endpoint.substring(0, endpoint.length - 1) : endpoint,
);
const teamsAppId = ctx.config.get(GLOBAL_CONFIG)?.getString(REMOTE_TEAMS_APP_ID);
Expand Down Expand Up @@ -970,18 +983,18 @@ export class TeamsAppSolution implements Solution {
ctx.logProvider?.info("[Teams Toolkit]: provison finished!");
if (selectedPlugins.some((plugin) => plugin.name === this.aadPlugin.name)) {
const aadPlugin: AadAppForTeamsPlugin = this.aadPlugin as any;
const result = aadPlugin.setApplicationInContext(
return aadPlugin.setApplicationInContext(
getPluginContext(ctx, this.aadPlugin.name, this.manifest),
);
if (result.isErr()) {
return result;
}

}
return this.createAndConfigTeamsManifest(ctx);
return ok(undefined);
},
async () => {

const result = this.createAndConfigTeamsManifest(ctx);
ctx.logProvider?.info("[Teams Toolkit]: configuration finished!");
return ok(undefined);
return result;
},
);
}
Expand Down Expand Up @@ -1164,9 +1177,6 @@ export class TeamsAppSolution implements Solution {
async getTabScaffoldQuestions(ctx: SolutionContext):Promise<Result<QTreeNode | undefined, FxError>> {
const tabNode = new QTreeNode({ type: NodeType.group });

const tab_scope = new QTreeNode(TabScopQuestion);
tabNode.addChild(tab_scope);

const frontend_host_type = new QTreeNode(FrontendHostTypeQuestion);
tabNode.addChild(frontend_host_type);

Expand Down Expand Up @@ -1432,6 +1442,16 @@ export class TeamsAppSolution implements Solution {
return result;
}
}
const result = this.loadTeamsAppTenantId(ctx.config, await ctx.appStudioToken?.getJsonObject());

if (result.isErr()) {
return result;
}

const postLocalDebugResult = await executeConcurrently(postLocalDebugWithCtx);
if (postLocalDebugResult.isErr()) {
return postLocalDebugResult;
}

const maybeConfig = this.getLocalDebugConfig(ctx.config);

Expand All @@ -1451,12 +1471,24 @@ export class TeamsAppSolution implements Solution {
validDomains.push(localBotDomain);
}

// STATIC_TABS and CONFIGURABLE_TABS are only available after postProvision.
const staticTabs = ctx.config.get(this.fehostPlugin.name)?.getString(STATIC_TABS);
const configurableTabs = ctx.config.get(this.fehostPlugin.name)?.getString(CONFIGURABLE_TABS);
if (!staticTabs || !configurableTabs ||
(staticTabs === "[]" && configurableTabs === "[]")) {
return err(returnSystemError(
new Error(`Invalid frontend config: ${STATIC_TABS}: ${staticTabs} ${CONFIGURABLE_TABS}: ${configurableTabs}`),
"Solution",
SolutionError.UpdateManifestError));
}
const manifestTpl = (await fs.readFile(`${ctx.root}/.${ConfigFolderName}/manifest.remote.json`)).toString();
const [appDefinition, _updatedManifest] = AppStudio.getDevAppDefinition(
manifestTpl,
localAADId,
validDomains,
webApplicationInfoResource,
staticTabs,
configurableTabs,
localTabEndpoint,
this.manifest!.name.short,
this.manifest!.version,
Expand Down Expand Up @@ -1489,14 +1521,7 @@ export class TeamsAppSolution implements Solution {
}
ctx.config.get(GLOBAL_CONFIG)?.set(LOCAL_DEBUG_TEAMS_APP_ID, maybeTeamsAppId.value);
}

const result = this.loadTeamsAppTenantId(ctx.config, await ctx.appStudioToken?.getJsonObject());

if (result.isErr()) {
return result;
}

return executeConcurrently(postLocalDebugWithCtx);
return ok(Void);
}

private parseTeamsAppTenantId(appStudioToken?: object): Result<string, FxError> {
Expand Down Expand Up @@ -1908,12 +1933,19 @@ export class TeamsAppSolution implements Solution {
if(method === "addCapability"){
return await this.executeAddCapability(func, ctx);
}
if (namespace.includes("solution") && method === "registerTeamsAppAndAad") {
const maybeParams = this.extractParamForRegisterTeamsAppAndAad(ctx.answers);
if (maybeParams.isErr()) {
return maybeParams;
if (namespace.includes("solution")) {
if (method === "registerTeamsAppAndAad") {
const maybeParams = this.extractParamForRegisterTeamsAppAndAad(ctx.answers);
if (maybeParams.isErr()) {
return maybeParams;
}
return this.registerTeamsAppAndAad(ctx, maybeParams.value);
} else if (method === "VSpublish") {
// VSpublish means VS calling cli to do publish. It is different than normal cli work flow
// It's teamsfx init followed by teamsfx publish without running provision.
// Using executeUserTask here could bypass the fx project check.
return this.publish(ctx);
}
return this.registerTeamsAppAndAad(ctx, maybeParams.value);
} else if (array.length == 2) {
const pluginName = array[1];
const plugin = this.pluginMap.get(pluginName);
Expand Down

0 comments on commit fce3698

Please sign in to comment.