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

[WIP][Task 8700131] Implementing pages.responseButton sub-capabilities #2157

Draft
wants to merge 5 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
2 changes: 2 additions & 0 deletions apps/teams-test-app/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ import PagesAppButtonAPIs from './components/PagesAppButtonAPIs';
import PagesBackStackAPIs from './components/PagesBackStackAPIs';
import PagesConfigAPIs from './components/PagesConfigAPIs';
import PagesCurrentAppAPIs from './components/PagesCurrentAppAPIs';
import PagesResponseButtonAPIs from './components/PagesResponseButtonAPIs';
import PagesTabsAPIs from './components/PagesTabsAPIs';
import PeopleAPIs from './components/PeopleAPIs';
import ChatAPIs from './components/privateApis/ChatAPIs';
Expand Down Expand Up @@ -166,6 +167,7 @@ const App = (): ReactElement => {
<PagesBackStackAPIs />
<PagesConfigAPIs />
<PagesCurrentAppAPIs />
<PagesResponseButtonAPIs />
<PagesTabsAPIs />
<PeopleAPIs />
<PrivateAPIs />
Expand Down
116 changes: 116 additions & 0 deletions apps/teams-test-app/src/components/PagesResponseButtonAPIs.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
import { pages } from '@microsoft/teams-js';
import React, { ReactElement } from 'react';

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

const ShowResponseButton = (): React.ReactElement =>
ApiWithTextInput<pages.responseButton.ResponseInfo>({
name: 'showResponseButton',
title: 'Show Response Button',
onClick: {
validateInput: (input) => {
if (!input) {
throw new Error('reponseInfo is required');
}
},
submit: async (input) => {
await pages.responseButton.showResponseButton(input);
return 'Completed';
},
},
defaultInput: JSON.stringify({
responseId: 'reply',
actionInfo: {
actionId: 'actionId',
actionObjects: [
{
itemId: '1',
secondaryId: {
name: 'driveId',
value: 'secondaryDriveValue',
},
originalSource: {
messageId: 'mockMessageId',
conversationId: 'mockConversationId',
type: 'email',
},
type: 'm365content',
},
],
},
}),
});

const HideResponseButton = (): React.ReactElement =>
ApiWithoutInput({
name: 'hideResponseButton',
title: 'Hide Response Button',
onClick: async () => {
await pages.responseButton.hideResponseButton();
return 'Completed';
},
});

// const RegisterResponseButtonClickEventHandler = (): React.ReactElement =>
// ApiWithoutInput({
// name: 'registerResponseButtonClickEventHandler',
// title: 'Register Response Button Click Event Handler',
// onClick: async (setResult) => {
// pages.responseButton.registerResponseButtonClickEventHandler((): void => {
// setResult('responseButtonEventHandler successfully called');
// });
// return 'Completed';
// },
// });

const RegisterResponseButtonClickEventHandler = (): React.ReactElement =>
ApiWithoutInput({
name: 'registerResponseButtonClickEventHandler',
title: 'Register Response Button Click Event Handler',
onClick: async (setResult) => {
pages.responseButton.registerResponseButtonClickEventHandler(
(event: pages.responseButton.ResponseButtonEvent): void => {
setResult('responseButton click event received.');
event.notifySuccess();
},
);
return 'pages.response.responseButtonEventType()' + noHostSdkMsg;
},
});

const ResponseButtonClickEventHandlerFailure = (): React.ReactElement =>
ApiWithoutInput({
name: 'registerResponseButtonClickEventHandlerFailure',
title: 'Register Response Button Click Event Handler Failure',
onClick: async (setResult) => {
pages.responseButton.registerResponseButtonClickEventHandler(
(removeEvent: pages.responseButton.ResponseButtonEvent): void => {
setResult('responseButton click event failed.');
removeEvent.notifyFailure('theReason');
},
);
return 'pages.response.responseButtonEventType()' + noHostSdkMsg;
},
});

const CheckPagesResponseButtonCapability = (): React.ReactElement =>
ApiWithoutInput({
name: 'checkPagesResponseButtonCapability',
title: 'Check Pages ResponseButton Capability',
onClick: async () =>
`Pages.responseButton module ${pages.responseButton.isSupported() ? 'is' : 'is not'} supported`,
});

const PagesResponseButtonAPIs = (): ReactElement => (
<ModuleWrapper title="Response Button">
<ShowResponseButton />
<HideResponseButton />
<RegisterResponseButtonClickEventHandler />
<ResponseButtonClickEventHandlerFailure />
<CheckPagesResponseButtonCapability />
</ModuleWrapper>
);

export default PagesResponseButtonAPIs;
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"type": "minor",
"comment": "Added a new subcapability, `pages.responseButton`, which will enable the app to interact with the response button in the app header. The capability is still awaiting support in one or most host applications. To track availability of this capability across different hosts see https://aka.ms/capmatrix",
"packageName": "@microsoft/teams-js",
"email": "maggiegong@microsoft.com",
"dependentChangeType": "patch"
}
6 changes: 6 additions & 0 deletions packages/teams-js/src/internal/telemetry.ts
Original file line number Diff line number Diff line change
Expand Up @@ -233,6 +233,12 @@ export enum ApiName {
Pages_SaveEvent_NotifySuccess = 'pages.saveEvent.notifySuccess',
Pages_SetCurrentFrame = 'pages.setCurrentFrame',
Pages_ShareDeepLink = 'pages.shareDeepLink',
Pages_ResponseButton_ShowResponseButton = 'pages.responseButton.showResponseButton',
Pages_ResponseButton_HideResponseButton = 'pages.responseButton.hideResponseButton',
Pages_ResponseButton_RegisterResponseButton = 'pages.responseButton.registerResponseButton',
Pages_ResponseButton_RegisterResponseButtonClickEventHandler = 'pages.responseButton.registerResponseButtonClickEventHandler',
Pages_ResponseButton_RegisterResponsButtonClickEvent_Failure = 'pages.responseButton.registerResponseButtonClickEvent.failure',
Pages_ResponseButton_RegisterResponsButtonClickEvent_Success = 'pages.responseButton.registerResponseButtonClickEvent.success',
Pages_Tabs_GetMruTabInstances = 'pages.tabs.getMruTabInstances',
Pages_Tabs_GetTabInstances = 'pages.tabs.getTabInstances',
Pages_Tabs_NavigateToTab = 'pages.tabs.navigateToTab',
Expand Down
3 changes: 3 additions & 0 deletions packages/teams-js/src/public/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,13 +21,16 @@ export {
DeepLinkParameters,
DialogInfo,
DialogSize,
EmailOriginalSource,
ErrorCode,
FileOpenPreference,
FrameContext,
FrameInfo,
LoadContext,
LocaleInfo,
M365ContentAction,
OriginalSource,
OriginalSourceType,
ResumeContext,
SdkError,
SecondaryId,
Expand Down
37 changes: 37 additions & 0 deletions packages/teams-js/src/public/interfaces.ts
Original file line number Diff line number Diff line change
Expand Up @@ -231,6 +231,11 @@ export interface M365ContentAction extends BaseActionObject<ActionObjectType.M36
itemId: string;
/** Represents an optional secondary identifier for an action in a Microsoft 365 content item. */
secondaryId?: SecondaryId;

/**
* Indicates the original source of the action object.
*/
originalSource?: OriginalSource<OriginalSourceType>;
}

/**
Expand Down Expand Up @@ -261,6 +266,38 @@ export enum SecondaryM365ContentIdName {
UserId = 'userId',
}

/**
* The original source of the action object from
*
* @param T The type of original source
*
* @beta
*/
export interface OriginalSource<T extends OriginalSourceType> {
/** Represents original source type. */
type: T;
}
/**
* The properties of where the action objects original from
*
* @beta
*/
export enum OriginalSourceType {
/** Represents that the original source is from an email. */
Email = 'email',
}
/**
* Stores information necessary to represent the related email and to group the attachments.
*
* @beta
*/
export interface EmailOriginalSource extends OriginalSource<OriginalSourceType.Email> {
/** The exact message where the action was invoked from */
messageId: string;
/** The conversation where the action was invoked from */
conversationId: string;
}

/**
* Information common to all actions
*
Expand Down