Skip to content

Commit ee14e3b

Browse files
kavins14singhk97lilyyduaacebo
authored
tests/message-extensions & other improvements (#213)
* select item * add missing "invoke" card action type * settings page * settings page fixes * remove index * resolve me docs feedback * lint fix --------- Co-authored-by: Kavin <115390646+singhk97@users.noreply.github.com> Co-authored-by: Lily Du <lilyyduu@gmail.com> Co-authored-by: Alex Acebo <aacebowork@gmail.com>
1 parent 70cb729 commit ee14e3b

File tree

4 files changed

+135
-3
lines changed

4 files changed

+135
-3
lines changed

packages/api/src/models/card/card-action.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,14 @@ export type CardActionType =
77
| 'showImage'
88
| 'downloadFile'
99
| 'signin'
10-
| 'call';
10+
| 'call'
11+
| 'invoke';
1112

1213
export type CardAction = {
1314
/**
1415
* The type of action implemented by this button. Possible values include: 'openUrl', 'imBack',
1516
* 'postBack', 'playAudio', 'playVideo', 'showImage', 'downloadFile', 'signin', 'call',
16-
* messageBack', 'openApp'
17+
* messageBack', 'openApp', 'invoke'
1718
*/
1819
type: CardActionType;
1920

tests/message-extensions/src/card.ts

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -161,7 +161,17 @@ export async function createDummyCards(searchQuery: string) {
161161
thumbnail: {
162162
title: item.title,
163163
text: item.description,
164-
} as ThumbnailCard,
164+
// When a user clicks on a list item in Teams:
165+
// - If the thumbnail has a `tap` property: Teams will trigger the `message.ext.select-item` activity
166+
// - If no `tap` property: Teams will insert the full adaptive card into the compose box
167+
// tap: {
168+
// type: "invoke",
169+
// title: item.title,
170+
// value: {
171+
// "option": index,
172+
// },
173+
// },
174+
} satisfies ThumbnailCard,
165175
};
166176
});
167177

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
<!-- :snippet-start: message-ext-settings-page -->
2+
<html>
3+
<body>
4+
<form>
5+
<fieldset>
6+
<legend>What programming language do you prefer?</legend>
7+
<input type="radio" name="selectedOption" value="typescript" />Typescript<br />
8+
<input type="radio" name="selectedOption" value="csharp" />C#<br />
9+
</fieldset>
10+
11+
<br />
12+
<input type="button" onclick="onSubmit()" value="Save" /> <br />
13+
</form>
14+
15+
<script src="https://res.cdn.office.net/teams-js/2.34.0/js/MicrosoftTeams.min.js" integrity="sha384-brW9AazbKR2dYw2DucGgWCCcmrm2oBFV4HQidyuyZRI/TnAkmOOnTARSTdps3Hwt" crossorigin="anonymous"></script>
16+
17+
<script type="text/javascript">
18+
document.addEventListener("DOMContentLoaded", function () {
19+
// Get the selected option from the URL
20+
var urlParams = new URLSearchParams(window.location.search);
21+
var selectedOption = urlParams.get("selectedOption");
22+
if (selectedOption) {
23+
var checkboxes = document.getElementsByName("selectedOption");
24+
for (var i = 0; i < checkboxes.length; i++) {
25+
var thisCheckbox = checkboxes[i];
26+
if (selectedOption.includes(thisCheckbox.value)) {
27+
checkboxes[i].checked = true;
28+
}
29+
}
30+
}
31+
});
32+
</script>
33+
34+
<script type="text/javascript">
35+
// initialize the Teams JS SDK
36+
microsoftTeams.app.initialize();
37+
38+
// Run when the user clicks the submit button
39+
function onSubmit() {
40+
var newSettings = "";
41+
42+
var checkboxes = document.getElementsByName("selectedOption");
43+
44+
for (var i = 0; i < checkboxes.length; i++) {
45+
if (checkboxes[i].checked) {
46+
newSettings = checkboxes[i].value;
47+
}
48+
}
49+
50+
// Closes the settings page and returns the selected option to the bot
51+
microsoftTeams.authentication.notifySuccess(newSettings);
52+
}
53+
</script>
54+
</body>
55+
</html>
56+
<!-- :snippet-end: message-ext-settings-page -->

tests/message-extensions/src/index.ts

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
import path from 'path';
2+
13
import { cardAttachment } from '@microsoft/teams.api';
24
import { App } from '@microsoft/teams.apps';
35
import { IAdaptiveCard } from '@microsoft/teams.cards';
@@ -11,6 +13,7 @@ import {
1113
createLinkUnfurlCard,
1214
createMessageDetailsCard,
1315
} from './card';
16+
1417
const app = new App({
1518
logger: new ConsoleLogger('@tests/message-extensions', { level: 'debug' }),
1619
plugins: [new DevtoolsPlugin()],
@@ -129,6 +132,68 @@ app.on('message.ext.query', async ({ activity }) => {
129132
});
130133
// :snippet-end: message-ext-query
131134

135+
// :snippet-start: message-ext-select-item
136+
app.on('message.ext.select-item', async ({ activity, send }) => {
137+
const { option } = activity.value;
138+
139+
await send(`Selected item: ${option}`);
140+
141+
return {
142+
status: 200,
143+
};
144+
});
145+
// :snippet-end: message-ext-select-item
146+
147+
// :snippet-start: message-ext-query-settings-url
148+
app.on('message.ext.query-settings-url', async ({ activity }) => {
149+
// Get user settings from storage if available
150+
const userSettings = await app.storage.get(activity.from.id) || { selectedOption: '' };
151+
const escapedSelectedOption = encodeURIComponent(userSettings.selectedOption);
152+
153+
return {
154+
composeExtension: {
155+
type: 'config',
156+
suggestedActions: {
157+
actions: [
158+
{
159+
type: 'openUrl',
160+
title: 'Settings',
161+
// ensure the bot endpoint is set in the environment variables
162+
// process.env.BOT_ENDPOINT is not populated by default in the Teams Toolkit setup.
163+
value: `${process.env.BOT_ENDPOINT}/tabs/settings?selectedOption=${escapedSelectedOption}`
164+
}
165+
]
166+
}
167+
}
168+
};
169+
});
170+
// :snippet-end: message-ext-query-settings-url
171+
172+
// :snippet-start: message-ext-setting
173+
app.on('message.ext.setting', async ({ activity, send }) => {
174+
const { state } = activity.value;
175+
if (state == 'CancelledByUser') {
176+
return {
177+
status: 400
178+
};
179+
}
180+
const selectedOption = state;
181+
182+
// Save the selected option to storage
183+
await app.storage.set(activity.from.id, { selectedOption });
184+
185+
await send(`Selected option: ${selectedOption}`);
186+
187+
return {
188+
status: 200
189+
};
190+
});
191+
// :snippet-end: message-ext-setting
192+
193+
// :snippet-start: message-ext-serve-html
194+
app.tab('settings', path.resolve(__dirname));
195+
// :snippet-end: message-ext-serve-html
196+
132197
(async () => {
133198
await app.start();
134199
})();

0 commit comments

Comments
 (0)