diff --git a/.vscode/settings.json b/.vscode/settings.json index e63df634d1..ead696e4f0 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,5 +1,15 @@ { - "cSpell.words": ["adal", "frameless", "ipados", "teamsjs", "teamspace", "uninitialize", "xvfb"], + "cSpell.words": [ + "adal", + "frameless", + "ipados", + "parentless", + "Subcapability", + "teamsjs", + "teamspace", + "uninitialize", + "xvfb" + ], "editor.defaultFormatter": "esbenp.prettier-vscode", "eslint.workingDirectories": [ "./apps/ssr-test-app/", diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 2858083477..501bbf8592 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -218,26 +218,26 @@ extends: shardNum: 2 shardIndex: 1 - - job: E2ETestIOS - displayName: 'E2E Tests - IOS - Plan A' - pool: - name: Azure Pipelines - image: macos-latest-internal - os: macOS - steps: - - template: tools/yaml-templates/ios-test.yml@self - parameters: - iOSAppHostingSdkGitPath: IOSAppHostingSdk - testPlan: iosE2ETestPlanA - - - job: E2ETestIOS2 - displayName: 'E2E Tests - IOS - Plan B' - pool: - name: Azure Pipelines - image: macos-latest-internal - os: macOS - steps: - - template: tools/yaml-templates/ios-test.yml@self - parameters: - iOSAppHostingSdkGitPath: IOSAppHostingSdk - testPlan: iosE2ETestPlanB + # - job: E2ETestIOS + # displayName: 'E2E Tests - IOS - Plan A' + # pool: + # name: Azure Pipelines + # image: macos-latest-internal + # os: macOS + # steps: + # - template: tools/yaml-templates/ios-test.yml@self + # parameters: + # iOSAppHostingSdkGitPath: IOSAppHostingSdk + # testPlan: iosE2ETestPlanA + + # - job: E2ETestIOS2 + # displayName: 'E2E Tests - IOS - Plan B' + # pool: + # name: Azure Pipelines + # image: macos-latest-internal + # os: macOS + # steps: + # - template: tools/yaml-templates/ios-test.yml@self + # parameters: + # iOSAppHostingSdkGitPath: IOSAppHostingSdk + # testPlan: iosE2ETestPlanB diff --git a/change/@microsoft-teams-js-0bfc106c-dcbd-4193-b604-49700784ee6d.json b/change/@microsoft-teams-js-0bfc106c-dcbd-4193-b604-49700784ee6d.json new file mode 100644 index 0000000000..d00f7a2ad2 --- /dev/null +++ b/change/@microsoft-teams-js-0bfc106c-dcbd-4193-b604-49700784ee6d.json @@ -0,0 +1,7 @@ +{ + "type": "minor", + "comment": "Added `nestedAppAuth` capability against a new client version `2.1.1` to support isNAAChannelRecommended for Teams Mobile", + "packageName": "@microsoft/teams-js", + "email": "singhmanp@microsoft.com", + "dependentChangeType": "patch" +} diff --git a/change/@microsoft-teams-js-bd2fddc6-24a2-4ffc-a0eb-b9c463513e20.json b/change/@microsoft-teams-js-bd2fddc6-24a2-4ffc-a0eb-b9c463513e20.json new file mode 100644 index 0000000000..29d0900b47 --- /dev/null +++ b/change/@microsoft-teams-js-bd2fddc6-24a2-4ffc-a0eb-b9c463513e20.json @@ -0,0 +1,7 @@ +{ + "type": "patch", + "comment": "Removed `@beta` tag from all functions on `dialog` capability (and all subcapabilities)", + "packageName": "@microsoft/teams-js", + "email": "36546967+AE-MS@users.noreply.github.com", + "dependentChangeType": "patch" +} diff --git a/packages/teams-js/src/public/dialog/adaptiveCard/adaptiveCard.ts b/packages/teams-js/src/public/dialog/adaptiveCard/adaptiveCard.ts index 058522fac5..4f7ff902c4 100644 --- a/packages/teams-js/src/public/dialog/adaptiveCard/adaptiveCard.ts +++ b/packages/teams-js/src/public/dialog/adaptiveCard/adaptiveCard.ts @@ -2,7 +2,6 @@ /** * Subcapability for interacting with adaptive card dialogs - * @beta * @module */ @@ -25,8 +24,6 @@ import * as bot from './bot'; * * @param adaptiveCardDialogInfo - An object containing the parameters of the dialog module {@link AdaptiveCardDialogInfo}. * @param submitHandler - Handler that triggers when a dialog fires an [Action.Submit](https://adaptivecards.io/explorer/Action.Submit.html) or when the user closes the dialog. - * - * @beta */ export function open(adaptiveCardDialogInfo: AdaptiveCardDialogInfo, submitHandler?: DialogSubmitHandler): void { ensureInitialized(runtime, FrameContexts.content, FrameContexts.sidePanel, FrameContexts.meetingStage); @@ -50,8 +47,6 @@ export function open(adaptiveCardDialogInfo: AdaptiveCardDialogInfo, submitHandl * @returns boolean to represent whether dialog.adaptiveCard module is supported * * @throws Error if {@linkcode app.initialize} has not successfully completed - * - * @beta */ export function isSupported(): boolean { const isAdaptiveCardVersionSupported = diff --git a/packages/teams-js/src/public/dialog/adaptiveCard/bot.ts b/packages/teams-js/src/public/dialog/adaptiveCard/bot.ts index eb4ef8641e..946935f463 100644 --- a/packages/teams-js/src/public/dialog/adaptiveCard/bot.ts +++ b/packages/teams-js/src/public/dialog/adaptiveCard/bot.ts @@ -1,7 +1,6 @@ /** * Module for interaction with adaptive card dialogs that need to communicate with the bot framework * - * @beta * @module */ @@ -23,8 +22,6 @@ import { DialogSubmitHandler } from '../dialog'; * * @param botAdaptiveCardDialogInfo - An object containing the parameters of the dialog module including completionBotId. * @param submitHandler - Handler that triggers when the dialog has been submitted or closed. - * - * @beta */ export function open(botAdaptiveCardDialogInfo: BotAdaptiveCardDialogInfo, submitHandler?: DialogSubmitHandler): void { ensureInitialized(runtime, FrameContexts.content, FrameContexts.sidePanel, FrameContexts.meetingStage); @@ -50,8 +47,6 @@ export function open(botAdaptiveCardDialogInfo: BotAdaptiveCardDialogInfo, submi * @returns boolean to represent whether dialog.adaptiveCard.bot is supported * * @throws Error if {@linkcode app.initialize} has not successfully completed - * - * @beta */ export function isSupported(): boolean { const isAdaptiveCardVersionSupported = diff --git a/packages/teams-js/src/public/dialog/dialog.ts b/packages/teams-js/src/public/dialog/dialog.ts index bcfef81a41..16efdf1869 100644 --- a/packages/teams-js/src/public/dialog/dialog.ts +++ b/packages/teams-js/src/public/dialog/dialog.ts @@ -13,7 +13,6 @@ * @remarks Note that dialogs were previously called "task modules". While they have been renamed for clarity, the functionality has been maintained. * For more details, see [Dialogs](https://learn.microsoft.com/microsoftteams/platform/task-modules-and-cards/what-are-task-modules) * - * @beta * @module */ @@ -29,8 +28,6 @@ import * as url from './url/url'; /** * Data Structure to represent the SDK response when dialog closes - * - * @beta */ export interface ISdkResponse { /** @@ -49,7 +46,6 @@ export interface ISdkResponse { /** * Handler used to receive and process messages sent between a dialog and the app that launched it - * @beta */ // eslint-disable-next-line @typescript-eslint/no-explicit-any export type PostMessageChannel = (message: any) => void; @@ -59,8 +55,6 @@ export type PostMessageChannel = (message: any) => void; * or an error if the dialog was closed by the user. * * @see {@linkcode ISdkResponse} - * - * @beta */ export type DialogSubmitHandler = (result: ISdkResponse) => void; @@ -72,8 +66,6 @@ export type DialogSubmitHandler = (result: ISdkResponse) => void; * Function is called during app initialization * @internal * Limited to Microsoft-internal use - * - * @beta */ export function initialize(): void { registerHandler( diff --git a/packages/teams-js/src/public/dialog/update.ts b/packages/teams-js/src/public/dialog/update.ts index 1963c166df..b4a8ac168b 100644 --- a/packages/teams-js/src/public/dialog/update.ts +++ b/packages/teams-js/src/public/dialog/update.ts @@ -1,7 +1,6 @@ /** * Module to update the dialog * - * @beta * @module */ @@ -15,8 +14,6 @@ import { runtime } from '../runtime'; * Update dimensions - height/width of a dialog. * * @param dimensions - An object containing width and height properties. - * - * @beta */ export function resize(dimensions: DialogSize): void { updateResizeHelper(getApiVersionTag(dialogTelemetryVersionNumber, ApiName.Dialog_Update_Resize), dimensions); @@ -27,8 +24,6 @@ export function resize(dimensions: DialogSize): void { * @returns boolean to represent whether dialog.update capabilty is supported * * @throws Error if {@linkcode app.initialize} has not successfully completed - * - * @beta */ export function isSupported(): boolean { return ensureInitialized(runtime) && runtime.supports.dialog diff --git a/packages/teams-js/src/public/dialog/url/bot.ts b/packages/teams-js/src/public/dialog/url/bot.ts index fe87a882f4..5c76fa903a 100644 --- a/packages/teams-js/src/public/dialog/url/bot.ts +++ b/packages/teams-js/src/public/dialog/url/bot.ts @@ -1,7 +1,6 @@ /** * Module to open a dialog that sends results to the bot framework * - * @beta * @module */ @@ -20,8 +19,6 @@ import { DialogSubmitHandler, PostMessageChannel } from '../dialog'; * @param messageFromChildHandler - Handler that triggers if dialog sends a message to the app. * * @returns a function that can be used to send messages to the dialog. - * - * @beta */ export function open( botUrlDialogInfo: BotUrlDialogInfo, @@ -42,8 +39,6 @@ export function open( * @returns boolean to represent whether dialog.url.bot is supported * * @throws Error if {@linkcode app.initialize} has not successfully completed - * - * @beta */ export function isSupported(): boolean { return ( diff --git a/packages/teams-js/src/public/dialog/url/parentCommunication.ts b/packages/teams-js/src/public/dialog/url/parentCommunication.ts index 0e7c99b164..d389b64abd 100644 --- a/packages/teams-js/src/public/dialog/url/parentCommunication.ts +++ b/packages/teams-js/src/public/dialog/url/parentCommunication.ts @@ -4,7 +4,6 @@ * @remarks * Note that dialog can be invoked from parentless scenarios e.g. Search Message Extensions. The subcapability `parentCommunication` is not supported in such scenarios. * - * @beta * @module */ @@ -24,8 +23,6 @@ import { PostMessageChannel } from '../dialog'; * This function is only intended to be called from code running within the dialog. Calling it from outside the dialog will have no effect. * * @param message - The message to send to the parent - * - * @beta */ export function sendMessageToParentFromDialog( // eslint-disable-next-line @typescript-eslint/no-explicit-any @@ -50,8 +47,6 @@ export function sendMessageToParentFromDialog( * Send message to the dialog from the parent * * @param message - The message to send - * - * @beta */ export function sendMessageToDialog( // eslint-disable-next-line @typescript-eslint/no-explicit-any @@ -76,8 +71,6 @@ export function sendMessageToDialog( * This function is only intended to be called from code running within the dialog. Calling it from outside the dialog will have no effect. * * @param listener - The listener that will be triggered. - * - * @beta */ export function registerOnMessageFromParent(listener: PostMessageChannel): void { ensureInitialized(runtime, FrameContexts.task); @@ -110,8 +103,6 @@ export function registerOnMessageFromParent(listener: PostMessageChannel): void * @returns boolean to represent whether dialog.url.parentCommunication capability is supported * * @throws Error if {@linkcode app.initialize} has not successfully completed - * - * @beta */ export function isSupported(): boolean { return ensureInitialized(runtime) && !!runtime.supports.dialog?.url?.parentCommunication; diff --git a/packages/teams-js/src/public/dialog/url/url.ts b/packages/teams-js/src/public/dialog/url/url.ts index 3e84299787..807bce2468 100644 --- a/packages/teams-js/src/public/dialog/url/url.ts +++ b/packages/teams-js/src/public/dialog/url/url.ts @@ -19,8 +19,6 @@ import * as parentCommunication from './parentCommunication'; * @param urlDialogInfo - An object containing the parameters of the dialog module. * @param submitHandler - Handler that triggers when a dialog calls the {@linkcode submit} function or when the user closes the dialog. * @param messageFromChildHandler - Handler that triggers if dialog sends a message to the app. - * - * @beta */ export function open( urlDialogInfo: UrlDialogInfo, @@ -45,8 +43,6 @@ export function open( * If this function is called from a dialog while {@link M365ContentAction} is set in the context object by the host, result will be ignored * * @param appIds - Valid application(s) that can receive the result of the submitted dialogs. Specifying this parameter helps prevent malicious apps from retrieving the dialog result. Multiple app IDs can be specified because a web app from a single underlying domain can power multiple apps across different environments and branding schemes. - * - * @beta */ export function submit(result?: string | object, appIds?: string | string[]): void { urlSubmitHelper(getApiVersionTag(dialogTelemetryVersionNumber, ApiName.Dialog_Url_Submit), result, appIds); @@ -58,8 +54,6 @@ export function submit(result?: string | object, appIds?: string | string[]): vo * @returns boolean to represent whether dialog.url module is supported * * @throws Error if {@linkcode app.initialize} has not successfully completed - * - * @beta */ export function isSupported(): boolean { return ensureInitialized(runtime) && (runtime.supports.dialog && runtime.supports.dialog.url) !== undefined; diff --git a/packages/teams-js/src/public/nestedAppAuth.ts b/packages/teams-js/src/public/nestedAppAuth.ts index 47be26730e..8f01b1b252 100644 --- a/packages/teams-js/src/public/nestedAppAuth.ts +++ b/packages/teams-js/src/public/nestedAppAuth.ts @@ -4,7 +4,9 @@ * @module */ +import { GlobalVars } from '../internal/globalVars'; import { ensureInitialized } from '../internal/internalAPIs'; +import { HostClientType } from './constants'; import { runtime } from './runtime'; /** @@ -16,5 +18,26 @@ import { runtime } from './runtime'; * @beta */ export function isNAAChannelRecommended(): boolean { - return (ensureInitialized(runtime) && runtime.isNAAChannelRecommended) ?? false; + return ( + (ensureInitialized(runtime) && + (runtime.isNAAChannelRecommended || isNAAChannelRecommendedForLegacyTeamsMobile())) ?? + false + ); +} + +function isNAAChannelRecommendedForLegacyTeamsMobile(): boolean { + return ensureInitialized(runtime) && + isHostAndroidOrIOSOrIPadOS() && + runtime.isLegacyTeams && + runtime.supports.nestedAppAuth + ? true + : false; +} + +function isHostAndroidOrIOSOrIPadOS(): boolean { + return ( + GlobalVars.hostClientType === HostClientType.android || + GlobalVars.hostClientType === HostClientType.ios || + GlobalVars.hostClientType === HostClientType.ipados + ); } diff --git a/packages/teams-js/src/public/runtime.ts b/packages/teams-js/src/public/runtime.ts index bd300b2d70..635382edb2 100644 --- a/packages/teams-js/src/public/runtime.ts +++ b/packages/teams-js/src/public/runtime.ts @@ -592,6 +592,12 @@ export const mapTeamsVersionToSupportedCapabilities: Record { +describe('nestedAppAuth.isNAAChannelRecommended', () => { const utils = new Utils(); beforeEach(() => { @@ -63,4 +63,97 @@ describe('nestedAppAuth', () => { utils.setRuntimeConfig(runtimeConfig); expect(nestedAppAuth.isNAAChannelRecommended()).toBeFalsy(); }); + + it('should return false if isNAAChannelRecommended is false in runtimeConfig for macos client', async () => { + await utils.initializeWithContext(FrameContexts.content, HostClientType.macos); + const runtimeConfig: Runtime = { + apiVersion: 4, + supports: {}, + isNAAChannelRecommended: false, + }; + utils.setRuntimeConfig(runtimeConfig); + expect(nestedAppAuth.isNAAChannelRecommended()).toBeFalsy(); + }); + + it('should return false if isNAAChannelRecommended is false in runtimeConfig for desktop client', async () => { + await utils.initializeWithContext(FrameContexts.content, HostClientType.desktop); + const runtimeConfig: Runtime = { + apiVersion: 4, + supports: {}, + isNAAChannelRecommended: false, + }; + utils.setRuntimeConfig(runtimeConfig); + expect(nestedAppAuth.isNAAChannelRecommended()).toBeFalsy(); + }); + + it('should return false if isNAAChannelRecommended is false in runtimeConfig for web client', async () => { + await utils.initializeWithContext(FrameContexts.content, HostClientType.web); + const runtimeConfig: Runtime = { + apiVersion: 4, + supports: {}, + isNAAChannelRecommended: false, + }; + utils.setRuntimeConfig(runtimeConfig); + expect(nestedAppAuth.isNAAChannelRecommended()).toBeFalsy(); + }); + + it('should return false if isNAAChannelRecommended is false and isLegacyTeams is false in runtimeConfig', async () => { + await utils.initializeWithContext(FrameContexts.content, HostClientType.android); + const runtimeConfig: Runtime = { + apiVersion: 4, + supports: {}, + isNAAChannelRecommended: false, + isLegacyTeams: false, + }; + utils.setRuntimeConfig(runtimeConfig); + expect(nestedAppAuth.isNAAChannelRecommended()).toBeFalsy(); + }); + + it('should return false if isNAAChannelRecommended is false and isLegacyTeams is true in runtimeConfig for android client that does not supports nestedAppAuth', async () => { + await utils.initializeWithContext(FrameContexts.content, HostClientType.android); + const runtimeConfig: Runtime = { + apiVersion: 4, + supports: {}, + isNAAChannelRecommended: false, + isLegacyTeams: true, + }; + utils.setRuntimeConfig(runtimeConfig); + expect(nestedAppAuth.isNAAChannelRecommended()).toBeFalsy(); + }); + + it('should return true if isNAAChannelRecommended is false and isLegacyTeams is true in runtimeConfig for android client that supports nestedAppAuth', async () => { + await utils.initializeWithContext(FrameContexts.content, HostClientType.android); + const runtimeConfig: Runtime = { + apiVersion: 4, + supports: { nestedAppAuth }, + isNAAChannelRecommended: false, + isLegacyTeams: true, + }; + utils.setRuntimeConfig(runtimeConfig); + expect(nestedAppAuth.isNAAChannelRecommended()).toBeTruthy(); + }); + + it('should return true if isNAAChannelRecommended is false and isLegacyTeams is true in runtimeConfig for ios client that supports nestedAppAuth', async () => { + await utils.initializeWithContext(FrameContexts.content, HostClientType.ios); + const runtimeConfig: Runtime = { + apiVersion: 4, + supports: { nestedAppAuth }, + isNAAChannelRecommended: false, + isLegacyTeams: true, + }; + utils.setRuntimeConfig(runtimeConfig); + expect(nestedAppAuth.isNAAChannelRecommended()).toBeTruthy(); + }); + + it('should return true if isNAAChannelRecommended is false and isLegacyTeams is true in runtimeConfig for ipados client that supports nestedAppAuth', async () => { + await utils.initializeWithContext(FrameContexts.content, HostClientType.ipados); + const runtimeConfig: Runtime = { + apiVersion: 4, + supports: { nestedAppAuth }, + isNAAChannelRecommended: false, + isLegacyTeams: true, + }; + utils.setRuntimeConfig(runtimeConfig); + expect(nestedAppAuth.isNAAChannelRecommended()).toBeTruthy(); + }); }); diff --git a/packages/teams-js/test/public/runtime.spec.ts b/packages/teams-js/test/public/runtime.spec.ts index 1c351c3858..29904a6e6b 100644 --- a/packages/teams-js/test/public/runtime.spec.ts +++ b/packages/teams-js/test/public/runtime.spec.ts @@ -1,6 +1,7 @@ /* eslint-disable @typescript-eslint/ban-types */ import { errorRuntimeNotInitialized } from '../../src/internal/constants'; +import { GlobalVars } from '../../src/internal/globalVars'; import { compareSDKVersions } from '../../src/internal/utils'; import { app, HostClientType } from '../../src/public'; import { @@ -243,6 +244,7 @@ describe('runtime', () => { for (const clientType of capabilityAdditionsInASpecificVersion.hostClientTypes) { await utils.initializeWithContext('content', clientType); + GlobalVars.hostClientType = clientType; const generatedCapabilityObjectForThisVersion = generateVersionBasedTeamsRuntimeConfig( version, versionAndPlatformAgnosticTeamsRuntimeConfig,