Skip to content

Commit 57ea793

Browse files
Added externalAppCardActionsForCEA APIs (#2507)
* CEC Card API changes * address comments * rename CEC to CEA * address comments * address comments * delete test log * address comments for adding hidden tag * Update packages/teams-js/src/private/externalAppCardActionsForCEA.ts Co-authored-by: Trevor Harris <[email protected]> * using sendAndUnwrap function * add beta tag --------- Co-authored-by: Trevor Harris <[email protected]>
1 parent 60eb045 commit 57ea793

File tree

12 files changed

+516
-52
lines changed

12 files changed

+516
-52
lines changed

apps/teams-test-app/src/components/privateApis/ExternalAppCardActionsAPIs.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { externalAppCardActions } from '@microsoft/teams-js';
1+
import { externalAppCardActions, IAdaptiveCardActionSubmit } from '@microsoft/teams-js';
22
import React from 'react';
33

44
import { ApiWithoutInput, ApiWithTextInput } from '../utils';
@@ -15,7 +15,7 @@ const CheckExternalAppCardActionsCapability = (): React.ReactElement =>
1515
const ProcessActionSubmit = (): React.ReactElement =>
1616
ApiWithTextInput<{
1717
appId: string;
18-
actionSubmitPayload: externalAppCardActions.IAdaptiveCardActionSubmit;
18+
actionSubmitPayload: IAdaptiveCardActionSubmit;
1919
}>({
2020
name: 'processActionSubmit',
2121
title: 'Process Action Submit',
Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
import { AppId, externalAppCardActionsForCEA, IAdaptiveCardActionSubmit } from '@microsoft/teams-js';
2+
import React from 'react';
3+
4+
import { ApiWithoutInput, ApiWithTextInput } from '../utils';
5+
import { ModuleWrapper } from '../utils/ModuleWrapper';
6+
7+
const CheckExternalAppCardActionsForCEACapability = (): React.ReactElement =>
8+
ApiWithoutInput({
9+
name: 'checkExternalAppCardActionsForCEACapability',
10+
title: 'Check External App Card Actions For CEA Capability',
11+
onClick: async () =>
12+
`External App Card Actions For CEA module ${
13+
externalAppCardActionsForCEA.isSupported() ? 'is' : 'is not'
14+
} supported`,
15+
});
16+
17+
const CECProcessActionSubmit = (): React.ReactElement =>
18+
ApiWithTextInput<{
19+
appId: AppId;
20+
conversationId: string;
21+
actionSubmitPayload: IAdaptiveCardActionSubmit;
22+
}>({
23+
name: 'processActionSubmitForCEA',
24+
title: 'Process Action Submit For CEA',
25+
onClick: {
26+
validateInput: (input) => {
27+
if (!input.appId) {
28+
throw new Error('appId is required');
29+
}
30+
if (!input.actionSubmitPayload) {
31+
throw new Error('actionSubmitPayload is required');
32+
}
33+
},
34+
submit: async (input) => {
35+
await externalAppCardActionsForCEA.processActionSubmit(
36+
input.appId,
37+
input.conversationId,
38+
input.actionSubmitPayload,
39+
);
40+
return 'Completed';
41+
},
42+
},
43+
defaultInput: JSON.stringify({
44+
appId: 'b7f8c0a0-6c1d-4a9a-9c0a-2c3f1c0a3b0a',
45+
actionSubmitPayload: {
46+
id: 'submitId',
47+
data: 'data1',
48+
},
49+
}),
50+
});
51+
52+
const CECProcessActionOpenUrl = (): React.ReactElement =>
53+
ApiWithTextInput<{
54+
appId: AppId;
55+
conversationId: string;
56+
url: string;
57+
}>({
58+
name: 'processActionOpenUrlForCEA',
59+
title: 'Process Action Open Url For CEA',
60+
onClick: {
61+
validateInput: (input) => {
62+
if (!input.appId) {
63+
throw new Error('appId is required');
64+
}
65+
if (!input.url) {
66+
throw new Error('url is required');
67+
}
68+
},
69+
submit: async (input) => {
70+
const result = await externalAppCardActionsForCEA.processActionOpenUrl(
71+
input.appId,
72+
input.conversationId,
73+
new URL(input.url),
74+
);
75+
return JSON.stringify(result);
76+
},
77+
},
78+
defaultInput: JSON.stringify({
79+
appId: 'b7f8c0a0-6c1d-4a9a-9c0a-2c3f1c0a3b0a',
80+
url: 'https://www.example.com',
81+
}),
82+
});
83+
84+
const ExternalAppCardActionsForCEAAPIs = (): React.ReactElement => (
85+
<ModuleWrapper title="External App Card Actions For CEA">
86+
<CheckExternalAppCardActionsForCEACapability />
87+
<CECProcessActionSubmit />
88+
<CECProcessActionOpenUrl />
89+
</ModuleWrapper>
90+
);
91+
92+
export default ExternalAppCardActionsForCEAAPIs;

apps/teams-test-app/src/pages/TestApp.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ import ChatAPIs from '../components/privateApis/ChatAPIs';
4141
import CopilotAPIs from '../components/privateApis/CopilotAPIs';
4242
import ExternalAppAuthenticationAPIs from '../components/privateApis/ExternalAppAuthenticationAPIs';
4343
import ExternalAppCardActionsAPIs from '../components/privateApis/ExternalAppCardActionsAPIs';
44+
import ExternalAppCardActionsForCEAAPIs from '../components/privateApis/ExternalAppCardActionsForCEAAPIs';
4445
import ExternalAppCommandsAPIs from '../components/privateApis/ExternalAppCommandsAPIs';
4546
import FilesAPIs from '../components/privateApis/FilesAPIs';
4647
import FullTrustAPIs from '../components/privateApis/FullTrustAPIs';
@@ -114,6 +115,7 @@ export const TestApp: React.FC = () => {
114115
<DialogUrlParentCommunicationAPIs childWindowRef={dialogWindowRef} />
115116
<ExternalAppAuthenticationAPIs />
116117
<ExternalAppCardActionsAPIs />
118+
<ExternalAppCardActionsForCEAAPIs />
117119
<ExternalAppCommandsAPIs />
118120
<FilesAPIs />
119121
<FullTrustAPIs />
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
{
2+
"type": "minor",
3+
"comment": "Added APIs for `externalAppCardActionsForCEA` capability.",
4+
"packageName": "@microsoft/teams-js",
5+
"email": "[email protected]",
6+
"dependentChangeType": "patch"
7+
}

packages/teams-js/src/internal/telemetry.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,8 @@ export const enum ApiName {
125125
ExternalAppAuthentication_AuthenticateWithPowerPlatformConnectorPlugins = 'externalAppAuthentication.authenticateWithPowerPlatformConnectorPlugins',
126126
ExternalAppCardActions_ProcessActionOpenUrl = 'externalAppCardActions.processActionOpenUrl',
127127
ExternalAppCardActions_ProcessActionSubmit = 'externalAppCardActions.processActionSubmit',
128+
ExternalAppCardActionsForCEA_ProcessActionOpenUrl = 'externalAppCardActionsForCEA.processActionOpenUrl',
129+
ExternalAppCardActionsForCEA_ProcessActionSubmit = 'externalAppCardActionsForCEA.processActionSubmit',
128130
ExternalAppCommands_ProcessActionCommands = 'externalAppCommands.processActionCommand',
129131
Files_AddCloudStorageFolder = 'files.addCloudStorageFolder',
130132
Files_AddCloudStorageProvider = 'files.addCloudStorageProvider',

packages/teams-js/src/private/externalAppCardActions.ts

Lines changed: 1 addition & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import { ApiName, ApiVersionNumber, getApiVersionTag } from '../internal/telemet
44
import { AppId } from '../public';
55
import { errorNotSupportedOnPlatform, FrameContexts } from '../public/constants';
66
import { runtime } from '../public/runtime';
7-
import { ExternalAppErrorCode } from './constants';
7+
import { ActionOpenUrlError, ActionSubmitError, IAdaptiveCardActionSubmit } from './interfaces';
88

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

34-
/**
35-
* @hidden
36-
* Error that can be thrown from IExternalAppCardActionService.handleActionOpenUrl
37-
*
38-
* @internal
39-
* Limited to Microsoft-internal use
40-
*/
41-
export interface ActionOpenUrlError {
42-
errorCode: ActionOpenUrlErrorCode;
43-
message?: string;
44-
}
45-
46-
/**
47-
* @hidden
48-
* Error codes that can be thrown from IExternalAppCardActionService.handleActionOpenUrl
49-
* @internal
50-
* Limited to Microsoft-internal use
51-
*/
52-
export enum ActionOpenUrlErrorCode {
53-
INTERNAL_ERROR = 'INTERNAL_ERROR', // Generic error
54-
INVALID_LINK = 'INVALID_LINK', // Deep link is invalid
55-
NOT_SUPPORTED = 'NOT_SUPPORTED', // Deep link is not supported
56-
}
57-
58-
/**
59-
* @hidden
60-
* The payload that is used when executing an Adaptive Card Action.Submit
61-
* @internal
62-
* Limited to Microsoft-internal use
63-
*/
64-
export interface IAdaptiveCardActionSubmit {
65-
id: string;
66-
data: string | Record<string, unknown>;
67-
}
68-
69-
/**
70-
*
71-
* @hidden
72-
* Error that can be thrown from IExternalAppCardActionService.handleActionSubmit
73-
*
74-
* @internal
75-
* Limited to Microsoft-internal use
76-
*/
77-
export interface ActionSubmitError {
78-
errorCode: ExternalAppErrorCode;
79-
message?: string;
80-
}
81-
8234
/**
8335
* @beta
8436
* @hidden
Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
import { sendAndUnwrap, sendMessageToParentAsync } from '../internal/communication';
2+
import { ensureInitialized } from '../internal/internalAPIs';
3+
import { ApiName, ApiVersionNumber, getApiVersionTag } from '../internal/telemetry';
4+
import { validateId } from '../internal/utils';
5+
import { AppId } from '../public';
6+
import { errorNotSupportedOnPlatform, FrameContexts } from '../public/constants';
7+
import { runtime } from '../public/runtime';
8+
import { ActionOpenUrlError, ActionOpenUrlType, ActionSubmitError, IAdaptiveCardActionSubmit } from './interfaces';
9+
10+
/**
11+
* All of APIs in this capability file should send out API version v2 ONLY
12+
*/
13+
const externalAppCardActionsTelemetryVersionNumber: ApiVersionNumber = ApiVersionNumber.V_2;
14+
/**
15+
* @beta
16+
* @hidden
17+
* Namespace to delegate adaptive card action for Custom Engine Agent execution to the host
18+
* @internal
19+
* Limited to Microsoft-internal use
20+
*/
21+
export namespace externalAppCardActionsForCEA {
22+
/**
23+
* @beta
24+
* @hidden
25+
* Delegates an Adaptive Card Action.OpenUrl request to the host for the application with the provided app ID.
26+
* @internal
27+
* Limited to Microsoft-internal use
28+
* @param appId ID of the application the request is intended for. This must be a UUID
29+
* @param conversationId To tell the bot what conversation the calls are coming from
30+
* @param url The URL to open
31+
* @throws Error if the response has not successfully completed
32+
* @returns Promise that resolves to ActionOpenUrlType indicating the type of URL that was opened on success and rejects with ActionOpenUrlError if the request fails
33+
*/
34+
export async function processActionOpenUrl(
35+
appId: AppId,
36+
conversationId: string,
37+
url: URL,
38+
): Promise<ActionOpenUrlType> {
39+
ensureInitialized(runtime, FrameContexts.content);
40+
if (!isSupported()) {
41+
throw errorNotSupportedOnPlatform;
42+
}
43+
validateId(conversationId, new Error('conversation id is not valid.'));
44+
const [error, response] = await sendMessageToParentAsync<[ActionOpenUrlError, ActionOpenUrlType]>(
45+
getApiVersionTag(
46+
externalAppCardActionsTelemetryVersionNumber,
47+
ApiName.ExternalAppCardActionsForCEA_ProcessActionOpenUrl,
48+
),
49+
ApiName.ExternalAppCardActionsForCEA_ProcessActionOpenUrl,
50+
[appId, url.href, conversationId],
51+
);
52+
if (error) {
53+
throw error;
54+
} else {
55+
return response;
56+
}
57+
}
58+
59+
/**
60+
* @beta
61+
* @hidden
62+
* Delegates an Adaptive Card Action.Submit request to the host for the application with the provided app ID
63+
* @internal
64+
* Limited to Microsoft-internal use
65+
* @param appId ID of the application the request is intended for. This must be a UUID
66+
* @param conversationId To tell the bot what conversation the calls are coming from
67+
* @param actionSubmitPayload The Adaptive Card Action.Submit payload
68+
* @throws Error if host notifies of an error
69+
* @returns Promise that resolves when the request is completed and rejects with ActionSubmitError if the request fails
70+
*/
71+
export async function processActionSubmit(
72+
appId: AppId,
73+
conversationId: string,
74+
actionSubmitPayload: IAdaptiveCardActionSubmit,
75+
): Promise<void> {
76+
ensureInitialized(runtime, FrameContexts.content);
77+
if (!isSupported()) {
78+
throw errorNotSupportedOnPlatform;
79+
}
80+
validateId(conversationId, new Error('conversation id is not valid.'));
81+
const error = await sendAndUnwrap<ActionSubmitError | undefined>(
82+
getApiVersionTag(
83+
externalAppCardActionsTelemetryVersionNumber,
84+
ApiName.ExternalAppCardActionsForCEA_ProcessActionSubmit,
85+
),
86+
ApiName.ExternalAppCardActionsForCEA_ProcessActionSubmit,
87+
[appId, conversationId, actionSubmitPayload],
88+
);
89+
if (error) {
90+
throw error;
91+
}
92+
}
93+
94+
/**
95+
* @beta
96+
* @hidden
97+
* Checks if the externalAppCardActionsForCEA capability is supported by the host
98+
* @returns boolean to represent whether externalAppCardActions capability is supported
99+
*
100+
* @throws Error if {@linkcode app.initialize} has not successfully completed
101+
*
102+
* @internal
103+
* Limited to Microsoft-internal use
104+
*/
105+
export function isSupported(): boolean {
106+
return ensureInitialized(runtime) && runtime.supports.externalAppCardActionsForCEA ? true : false;
107+
}
108+
}

packages/teams-js/src/private/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ export { conversations } from './conversations';
2222
export { copilot } from './copilot';
2323
export { externalAppAuthentication } from './externalAppAuthentication';
2424
export { externalAppCardActions } from './externalAppCardActions';
25+
export { externalAppCardActionsForCEA } from './externalAppCardActionsForCEA';
2526
export { externalAppCommands } from './externalAppCommands';
2627
export { files } from './files';
2728
export { meetingRoom } from './meetingRoom';

0 commit comments

Comments
 (0)