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

Added externalAppCardActionsForCEA APIs #2507

Merged
merged 11 commits into from
Sep 25, 2024
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { externalAppCardActions } from '@microsoft/teams-js';
import { externalAppCardActions, IAdaptiveCardActionSubmit } from '@microsoft/teams-js';
import React from 'react';

import { ApiWithoutInput, ApiWithTextInput } from '../utils';
Expand All @@ -15,7 +15,7 @@ const CheckExternalAppCardActionsCapability = (): React.ReactElement =>
const ProcessActionSubmit = (): React.ReactElement =>
ApiWithTextInput<{
appId: string;
actionSubmitPayload: externalAppCardActions.IAdaptiveCardActionSubmit;
actionSubmitPayload: IAdaptiveCardActionSubmit;
}>({
name: 'processActionSubmit',
title: 'Process Action Submit',
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
import { AppId, externalAppCardActionsForCEA, IAdaptiveCardActionSubmit } from '@microsoft/teams-js';
import React from 'react';

import { ApiWithoutInput, ApiWithTextInput } from '../utils';
import { ModuleWrapper } from '../utils/ModuleWrapper';

const CheckExternalAppCardActionsForCEACapability = (): React.ReactElement =>
ApiWithoutInput({
name: 'checkExternalAppCardActionsForCEACapability',
title: 'Check External App Card Actions For CEA Capability',
onClick: async () =>
`External App Card Actions For CEA module ${
externalAppCardActionsForCEA.isSupported() ? 'is' : 'is not'
} supported`,
});

const CECProcessActionSubmit = (): React.ReactElement =>
ApiWithTextInput<{
appId: AppId;
conversationId: string;
actionSubmitPayload: IAdaptiveCardActionSubmit;
}>({
name: 'processActionSubmitForCEA',
title: 'Process Action Submit For CEA',
onClick: {
validateInput: (input) => {
if (!input.appId) {
throw new Error('appId is required');
}
if (!input.actionSubmitPayload) {
throw new Error('actionSubmitPayload is required');
}
},
submit: async (input) => {
await externalAppCardActionsForCEA.processActionSubmit(
input.appId,
input.conversationId,
input.actionSubmitPayload,
);
return 'Completed';
},
},
defaultInput: JSON.stringify({
appId: 'b7f8c0a0-6c1d-4a9a-9c0a-2c3f1c0a3b0a',
actionSubmitPayload: {
id: 'submitId',
data: 'data1',
},
}),
});

const CECProcessActionOpenUrl = (): React.ReactElement =>
ApiWithTextInput<{
appId: AppId;
conversationId: string;
url: string;
}>({
name: 'processActionOpenUrlForCEA',
title: 'Process Action Open Url For CEA',
onClick: {
validateInput: (input) => {
if (!input.appId) {
throw new Error('appId is required');
}
if (!input.url) {
throw new Error('url is required');
}
},
submit: async (input) => {
const result = await externalAppCardActionsForCEA.processActionOpenUrl(
input.appId,
input.conversationId,
new URL(input.url),
);
return JSON.stringify(result);
},
},
defaultInput: JSON.stringify({
appId: 'b7f8c0a0-6c1d-4a9a-9c0a-2c3f1c0a3b0a',
url: 'https://www.example.com',
}),
});

const ExternalAppCardActionsForCEAAPIs = (): React.ReactElement => (
<ModuleWrapper title="External App Card Actions For CEA">
<CheckExternalAppCardActionsForCEACapability />
<CECProcessActionSubmit />
<CECProcessActionOpenUrl />
</ModuleWrapper>
);

export default ExternalAppCardActionsForCEAAPIs;
2 changes: 2 additions & 0 deletions apps/teams-test-app/src/pages/TestApp.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ import ChatAPIs from '../components/privateApis/ChatAPIs';
import CopilotAPIs from '../components/privateApis/CopilotAPIs';
import ExternalAppAuthenticationAPIs from '../components/privateApis/ExternalAppAuthenticationAPIs';
import ExternalAppCardActionsAPIs from '../components/privateApis/ExternalAppCardActionsAPIs';
import ExternalAppCardActionsForCEAAPIs from '../components/privateApis/ExternalAppCardActionsForCEAAPIs';
import ExternalAppCommandsAPIs from '../components/privateApis/ExternalAppCommandsAPIs';
import FilesAPIs from '../components/privateApis/FilesAPIs';
import FullTrustAPIs from '../components/privateApis/FullTrustAPIs';
Expand Down Expand Up @@ -114,6 +115,7 @@ export const TestApp: React.FC = () => {
<DialogUrlParentCommunicationAPIs childWindowRef={dialogWindowRef} />
<ExternalAppAuthenticationAPIs />
<ExternalAppCardActionsAPIs />
<ExternalAppCardActionsForCEAAPIs />
<ExternalAppCommandsAPIs />
<FilesAPIs />
<FullTrustAPIs />
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"type": "minor",
"comment": "Added APIs for `externalAppCardActionsForCEA` capability.",
"packageName": "@microsoft/teams-js",
"email": "[email protected]",
"dependentChangeType": "patch"
}
2 changes: 2 additions & 0 deletions packages/teams-js/src/internal/telemetry.ts
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,8 @@ export const enum ApiName {
ExternalAppAuthentication_AuthenticateWithPowerPlatformConnectorPlugins = 'externalAppAuthentication.authenticateWithPowerPlatformConnectorPlugins',
ExternalAppCardActions_ProcessActionOpenUrl = 'externalAppCardActions.processActionOpenUrl',
ExternalAppCardActions_ProcessActionSubmit = 'externalAppCardActions.processActionSubmit',
ExternalAppCardActionsForCEA_ProcessActionOpenUrl = 'externalAppCardActionsForCEA.processActionOpenUrl',
ExternalAppCardActionsForCEA_ProcessActionSubmit = 'externalAppCardActionsForCEA.processActionSubmit',
ExternalAppCommands_ProcessActionCommands = 'externalAppCommands.processActionCommand',
Files_AddCloudStorageFolder = 'files.addCloudStorageFolder',
Files_AddCloudStorageProvider = 'files.addCloudStorageProvider',
Expand Down
50 changes: 1 addition & 49 deletions packages/teams-js/src/private/externalAppCardActions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { ApiName, ApiVersionNumber, getApiVersionTag } from '../internal/telemet
import { AppId } from '../public';
import { errorNotSupportedOnPlatform, FrameContexts } from '../public/constants';
import { runtime } from '../public/runtime';
import { ExternalAppErrorCode } from './constants';
import { ActionOpenUrlError, ActionSubmitError, IAdaptiveCardActionSubmit } from './interfaces';

/**
* v2 APIs telemetry file: All of APIs in this capability file should send out API version v2 ONLY
Expand All @@ -31,54 +31,6 @@ export namespace externalAppCardActions {
GenericUrl = 'GenericUrl',
}

/**
* @hidden
* Error that can be thrown from IExternalAppCardActionService.handleActionOpenUrl
*
* @internal
* Limited to Microsoft-internal use
*/
export interface ActionOpenUrlError {
errorCode: ActionOpenUrlErrorCode;
message?: string;
}

/**
* @hidden
* Error codes that can be thrown from IExternalAppCardActionService.handleActionOpenUrl
* @internal
* Limited to Microsoft-internal use
*/
export enum ActionOpenUrlErrorCode {
INTERNAL_ERROR = 'INTERNAL_ERROR', // Generic error
INVALID_LINK = 'INVALID_LINK', // Deep link is invalid
NOT_SUPPORTED = 'NOT_SUPPORTED', // Deep link is not supported
}

/**
* @hidden
* The payload that is used when executing an Adaptive Card Action.Submit
* @internal
* Limited to Microsoft-internal use
*/
export interface IAdaptiveCardActionSubmit {
id: string;
data: string | Record<string, unknown>;
}

/**
*
* @hidden
* Error that can be thrown from IExternalAppCardActionService.handleActionSubmit
*
* @internal
* Limited to Microsoft-internal use
*/
export interface ActionSubmitError {
errorCode: ExternalAppErrorCode;
message?: string;
}

/**
* @beta
* @hidden
Expand Down
108 changes: 108 additions & 0 deletions packages/teams-js/src/private/externalAppCardActionsForCEA.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
import { sendAndUnwrap, sendMessageToParentAsync } from '../internal/communication';
import { ensureInitialized } from '../internal/internalAPIs';
import { ApiName, ApiVersionNumber, getApiVersionTag } from '../internal/telemetry';
import { validateId } from '../internal/utils';
import { AppId } from '../public';
import { errorNotSupportedOnPlatform, FrameContexts } from '../public/constants';
import { runtime } from '../public/runtime';
import { ActionOpenUrlError, ActionOpenUrlType, ActionSubmitError, IAdaptiveCardActionSubmit } from './interfaces';

/**
* All of APIs in this capability file should send out API version v2 ONLY
*/
const externalAppCardActionsTelemetryVersionNumber: ApiVersionNumber = ApiVersionNumber.V_2;
/**
* @beta
* @hidden
* Namespace to delegate adaptive card action for Custom Engine Agent execution to the host
* @internal
* Limited to Microsoft-internal use
MengyiGong marked this conversation as resolved.
Show resolved Hide resolved
*/
export namespace externalAppCardActionsForCEA {
MengyiGong marked this conversation as resolved.
Show resolved Hide resolved
/**
* @beta
* @hidden
* Delegates an Adaptive Card Action.OpenUrl request to the host for the application with the provided app ID.
* @internal
* Limited to Microsoft-internal use
* @param appId ID of the application the request is intended for. This must be a UUID
* @param conversationId To tell the bot what conversation the calls are coming from
* @param url The URL to open
* @throws Error if the response has not successfully completed
* @returns Promise that resolves to ActionOpenUrlType indicating the type of URL that was opened on success and rejects with ActionOpenUrlError if the request fails
MengyiGong marked this conversation as resolved.
Show resolved Hide resolved
*/
export async function processActionOpenUrl(
appId: AppId,
conversationId: string,
url: URL,
): Promise<ActionOpenUrlType> {
ensureInitialized(runtime, FrameContexts.content);
if (!isSupported()) {
throw errorNotSupportedOnPlatform;
}
validateId(conversationId, new Error('conversation id is not valid.'));
const [error, response] = await sendMessageToParentAsync<[ActionOpenUrlError, ActionOpenUrlType]>(
getApiVersionTag(
externalAppCardActionsTelemetryVersionNumber,
ApiName.ExternalAppCardActionsForCEA_ProcessActionOpenUrl,
),
ApiName.ExternalAppCardActionsForCEA_ProcessActionOpenUrl,
[appId, url.href, conversationId],
);
if (error) {
throw error;
} else {
return response;
}
}

/**
* @beta
* @hidden
* Delegates an Adaptive Card Action.Submit request to the host for the application with the provided app ID
* @internal
* Limited to Microsoft-internal use
* @param appId ID of the application the request is intended for. This must be a UUID
* @param conversationId To tell the bot what conversation the calls are coming from
* @param actionSubmitPayload The Adaptive Card Action.Submit payload
* @throws Error if host notifies of an error
* @returns Promise that resolves when the request is completed and rejects with ActionSubmitError if the request fails
*/
export async function processActionSubmit(
appId: AppId,
conversationId: string,
actionSubmitPayload: IAdaptiveCardActionSubmit,
): Promise<void> {
ensureInitialized(runtime, FrameContexts.content);
if (!isSupported()) {
throw errorNotSupportedOnPlatform;
}
validateId(conversationId, new Error('conversation id is not valid.'));
const error = await sendAndUnwrap<ActionSubmitError | undefined>(
getApiVersionTag(
externalAppCardActionsTelemetryVersionNumber,
ApiName.ExternalAppCardActionsForCEA_ProcessActionSubmit,
),
ApiName.ExternalAppCardActionsForCEA_ProcessActionSubmit,
[appId, conversationId, actionSubmitPayload],
);
if (error) {
throw error;
}
}

/**
* @beta
* @hidden
* Checks if the externalAppCardActionsForCEA capability is supported by the host
* @returns boolean to represent whether externalAppCardActions capability is supported
*
* @throws Error if {@linkcode app.initialize} has not successfully completed
*
* @internal
MengyiGong marked this conversation as resolved.
Show resolved Hide resolved
* Limited to Microsoft-internal use
*/
export function isSupported(): boolean {
return ensureInitialized(runtime) && runtime.supports.externalAppCardActionsForCEA ? true : false;
}
}
1 change: 1 addition & 0 deletions packages/teams-js/src/private/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ export { conversations } from './conversations';
export { copilot } from './copilot';
export { externalAppAuthentication } from './externalAppAuthentication';
export { externalAppCardActions } from './externalAppCardActions';
export { externalAppCardActionsForCEA } from './externalAppCardActionsForCEA';
export { externalAppCommands } from './externalAppCommands';
export { files } from './files';
export { meetingRoom } from './meetingRoom';
Expand Down
Loading
Loading