Merge pull request #424 from microsoft/emimunoz/messaging-ext-action
51 Teams Messaging Action Extension
This commit is contained in:
Коммит
0036294979
|
@ -3,8 +3,8 @@
|
||||||
|
|
||||||
Bot Framework v4 Conversation Bot sample for Teams.
|
Bot Framework v4 Conversation Bot sample for Teams.
|
||||||
|
|
||||||
This bot has been created using [Bot Framework](https://dev.botframework.com). This sample shows
|
There are two basic types of Messaging Extension in Teams: [Search-based](https://docs.microsoft.com/en-us/microsoftteams/platform/messaging-extensions/how-to/search-commands/define-search-command) and [Action-based](https://docs.microsoft.com/en-us/microsoftteams/platform/messaging-extensions/how-to/action-commands/define-action-command). This sample illustrates how to
|
||||||
how to incorporate basic conversational flow into a Teams application. It also illustrates a few of the Teams specific calls you can make from your bot.
|
build an Action-based Messaging Extension.
|
||||||
|
|
||||||
## Prerequisites
|
## Prerequisites
|
||||||
|
|
||||||
|
@ -48,23 +48,13 @@ the Teams service needs to call into the bot.
|
||||||
|
|
||||||
## Interacting with the bot
|
## Interacting with the bot
|
||||||
|
|
||||||
You can interact with this bot by sending it a message, or selecting a command from the command list. The bot will respond to the following strings.
|
> Note this `manifest.json` specified that the bot will be called from both the `compose` and `message` areas of Teams. Please refer to Teams documentation for more details.
|
||||||
|
|
||||||
1. **Show Welcome**
|
1) Selecting the **Create Card** command from the Compose Box command list. The parameters dialog will be displayed and can be submitted to initiate the card creation within the Messaging Extension code.
|
||||||
- **Result:** The bot will send the welcome card for you to interact with
|
|
||||||
- **Valid Scopes:** personal, group chat, team chat
|
|
||||||
2. **MentionMe**
|
|
||||||
- **Result:** The bot will respond to the message and mention the user
|
|
||||||
- **Valid Scopes:** personal, group chat, team chat
|
|
||||||
3. **MessageAllMembers**
|
|
||||||
- **Result:** The bot will send a 1-on-1 message to each member in the current conversation (aka on the conversation's roster).
|
|
||||||
- **Valid Scopes:** personal, group chat, team chat
|
|
||||||
|
|
||||||
You can select an option from the command list by typing ```@TeamsConversationBot``` into the compose message area and ```What can I do?``` text above the compose area.
|
or
|
||||||
|
|
||||||
### Avoiding Permission-Related Errors
|
2) Selecting the **Share Message** command from the Message command list.
|
||||||
|
|
||||||
You may encounter permission-related errors when sending a proactive message. This can often be mitigated by using `MicrosoftAppCredentials.TrustServiceUrl()`. See [the documentation](https://docs.microsoft.com/en-us/azure/bot-service/bot-builder-howto-proactive-message?view=azure-bot-service-4.0&tabs=csharp#avoiding-401-unauthorized-errors) for more information.
|
|
||||||
|
|
||||||
## Deploy the bot to Azure
|
## Deploy the bot to Azure
|
||||||
|
|
||||||
|
|
|
@ -14,11 +14,11 @@ import org.springframework.context.annotation.Import;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This is the starting point of the Sprint Boot Bot application.
|
* This is the starting point of the Sprint Boot Bot application.
|
||||||
|
* <p>
|
||||||
|
* This class also provides overrides for dependency injections. A class that extends the {@link
|
||||||
|
* com.microsoft.bot.builder.Bot} interface should be annotated with @Component.
|
||||||
*
|
*
|
||||||
* This class also provides overrides for dependency injections. A class that extends the
|
* @see TeamsMessagingExtensionsActionBot
|
||||||
* {@link com.microsoft.bot.builder.Bot} interface should be annotated with @Component.
|
|
||||||
*
|
|
||||||
* @see TeamsConversationBot
|
|
||||||
*/
|
*/
|
||||||
@SpringBootApplication
|
@SpringBootApplication
|
||||||
|
|
||||||
|
@ -29,6 +29,7 @@ import org.springframework.context.annotation.Import;
|
||||||
@Import({BotController.class})
|
@Import({BotController.class})
|
||||||
|
|
||||||
public class Application extends BotDependencyConfiguration {
|
public class Application extends BotDependencyConfiguration {
|
||||||
|
|
||||||
public static void main(String[] args) {
|
public static void main(String[] args) {
|
||||||
SpringApplication.run(Application.class, args);
|
SpringApplication.run(Application.class, args);
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,210 +3,109 @@
|
||||||
|
|
||||||
package com.microsoft.bot.sample.teamsaction;
|
package com.microsoft.bot.sample.teamsaction;
|
||||||
|
|
||||||
import com.codepoetics.protonpack.collectors.CompletableFutures;
|
|
||||||
import com.microsoft.bot.builder.BotFrameworkAdapter;
|
|
||||||
import com.microsoft.bot.builder.MessageFactory;
|
|
||||||
import com.microsoft.bot.builder.TurnContext;
|
import com.microsoft.bot.builder.TurnContext;
|
||||||
import com.microsoft.bot.builder.teams.TeamsActivityHandler;
|
import com.microsoft.bot.builder.teams.TeamsActivityHandler;
|
||||||
import com.microsoft.bot.builder.teams.TeamsInfo;
|
import com.microsoft.bot.schema.CardImage;
|
||||||
import com.microsoft.bot.connector.authentication.MicrosoftAppCredentials;
|
|
||||||
import com.microsoft.bot.integration.Configuration;
|
|
||||||
import com.microsoft.bot.schema.ActionTypes;
|
|
||||||
import com.microsoft.bot.schema.Activity;
|
|
||||||
import com.microsoft.bot.schema.CardAction;
|
|
||||||
import com.microsoft.bot.schema.ConversationParameters;
|
|
||||||
import com.microsoft.bot.schema.ConversationReference;
|
|
||||||
import com.microsoft.bot.schema.HeroCard;
|
import com.microsoft.bot.schema.HeroCard;
|
||||||
import com.microsoft.bot.schema.Mention;
|
import com.microsoft.bot.schema.teams.*;
|
||||||
import com.microsoft.bot.schema.teams.TeamInfo;
|
|
||||||
import com.microsoft.bot.schema.teams.TeamsChannelAccount;
|
|
||||||
import org.apache.commons.lang3.StringUtils;
|
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
import java.net.URLEncoder;
|
import java.util.*;
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.concurrent.CompletableFuture;
|
import java.util.concurrent.CompletableFuture;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This class implements the functionality of the Bot.
|
* This class implements the functionality of the Bot.
|
||||||
*
|
*
|
||||||
* <p>This is where application specific logic for interacting with the users would be
|
* <p>This is where application specific logic for interacting with the users would be
|
||||||
* added. For this sample, the {@link #onMessageActivity(TurnContext)} echos the text
|
* added. There are two basic types of Messaging Extension in Teams: Search-based and Action-based.
|
||||||
* back to the user. The {@link #onMembersAdded(List, TurnContext)} will send a greeting
|
* This sample illustrates how to build an Action-based Messaging Extension.</p>
|
||||||
* to new conversation participants.</p>
|
|
||||||
*/
|
*/
|
||||||
@Component
|
@Component
|
||||||
public class TeamsMessagingExtensionsActionBot extends TeamsActivityHandler {
|
public class TeamsMessagingExtensionsActionBot extends TeamsActivityHandler {
|
||||||
private String appId;
|
|
||||||
private String appPassword;
|
|
||||||
|
|
||||||
public TeamsMessagingExtensionsActionBot(Configuration configuration) {
|
|
||||||
appId = configuration.getProperty("MicrosoftAppId");
|
|
||||||
appPassword = configuration.getProperty("MicrosoftAppPassword");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected CompletableFuture<Void> onMessageActivity(TurnContext turnContext) {
|
protected CompletableFuture<MessagingExtensionActionResponse> onTeamsMessagingExtensionSubmitAction(
|
||||||
turnContext.getActivity().removeRecipientMention();
|
TurnContext turnContext,
|
||||||
|
MessagingExtensionAction action
|
||||||
switch (turnContext.getActivity().getText().trim()) {
|
) {
|
||||||
case "MentionMe":
|
switch (action.getCommandId()) {
|
||||||
return mentionActivity(turnContext);
|
// These commandIds are defined in the Teams App Manifest.
|
||||||
|
case "createCard":
|
||||||
case "UpdateCardAction":
|
return createCardCommand(turnContext, action);
|
||||||
return updateCardActivity(turnContext);
|
|
||||||
|
|
||||||
case "Delete":
|
|
||||||
return deleteCardActivity(turnContext);
|
|
||||||
|
|
||||||
case "MessageAllMembers":
|
|
||||||
return messageAllMembers(turnContext);
|
|
||||||
|
|
||||||
|
case "shareMessage":
|
||||||
|
return shareMessageCommand(turnContext, action);
|
||||||
default:
|
default:
|
||||||
// This will come back deserialized as a Map.
|
return notImplemented(
|
||||||
Object value = new Object() {
|
String.format("Invalid CommandId: %s", action.getCommandId()));
|
||||||
int count = 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
HeroCard card = new HeroCard() {{
|
|
||||||
setTitle("Welcome Card");
|
|
||||||
setText("Click the buttons below to update this card");
|
|
||||||
setButtons(Arrays.asList(
|
|
||||||
new CardAction() {{
|
|
||||||
setType(ActionTypes.MESSAGE_BACK);
|
|
||||||
setTitle("Update Card");
|
|
||||||
setText("UpdateCardAction");
|
|
||||||
setValue(value);
|
|
||||||
}},
|
|
||||||
new CardAction() {{
|
|
||||||
setType(ActionTypes.MESSAGE_BACK);
|
|
||||||
setTitle("Message All Members");
|
|
||||||
setText("MessageAllMembers");
|
|
||||||
}}
|
|
||||||
));
|
|
||||||
}};
|
|
||||||
|
|
||||||
return turnContext.sendActivity(MessageFactory.attachment(card.toAttachment()))
|
|
||||||
.thenApply(resourceResponse -> null);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
private CompletableFuture<MessagingExtensionActionResponse> createCardCommand(
|
||||||
protected CompletableFuture<Void> onTeamsMembersAdded(
|
TurnContext turnContext,
|
||||||
List<TeamsChannelAccount> membersAdded,
|
MessagingExtensionAction action
|
||||||
TeamInfo teamInfo,
|
|
||||||
TurnContext turnContext
|
|
||||||
) {
|
) {
|
||||||
return membersAdded.stream()
|
Map<String, String> actionData = (Map<String, String>) action.getData();
|
||||||
.filter(member -> !StringUtils.equals(member.getId(), turnContext.getActivity().getRecipient().getId()))
|
|
||||||
.map(channel -> turnContext.sendActivity(
|
|
||||||
MessageFactory.text("Welcome to the team " + channel.getGivenName() + " " + channel.getSurname() + ".")))
|
|
||||||
.collect(CompletableFutures.toFutureList())
|
|
||||||
.thenApply(resourceResponses -> null);
|
|
||||||
}
|
|
||||||
|
|
||||||
private CompletableFuture<Void> deleteCardActivity(TurnContext turnContext) {
|
|
||||||
return turnContext.deleteActivity(turnContext.getActivity().getReplyToId());
|
|
||||||
}
|
|
||||||
|
|
||||||
// If you encounter permission-related errors when sending this message, see
|
|
||||||
// https://aka.ms/BotTrustServiceUrl
|
|
||||||
private CompletableFuture<Void> messageAllMembers(TurnContext turnContext) {
|
|
||||||
String teamsChannelId = turnContext.getActivity().teamsGetChannelId();
|
|
||||||
String serviceUrl = turnContext.getActivity().getServiceUrl();
|
|
||||||
MicrosoftAppCredentials credentials = new MicrosoftAppCredentials(appId, appPassword);
|
|
||||||
|
|
||||||
return TeamsInfo.getMembers(turnContext)
|
|
||||||
.thenCompose(members -> {
|
|
||||||
List<CompletableFuture<Void>> conversations = new ArrayList<>();
|
|
||||||
|
|
||||||
// Send a message to each member. These will all go out
|
|
||||||
// at the same time.
|
|
||||||
for (TeamsChannelAccount member : members) {
|
|
||||||
Activity proactiveMessage = MessageFactory.text(
|
|
||||||
"Hello " + member.getGivenName() + " " + member.getSurname()
|
|
||||||
+ ". I'm a Teams conversation bot.");
|
|
||||||
|
|
||||||
ConversationParameters conversationParameters = new ConversationParameters() {{
|
|
||||||
setIsGroup(false);
|
|
||||||
setBot(turnContext.getActivity().getRecipient());
|
|
||||||
setMembers(Collections.singletonList(member));
|
|
||||||
setTenantId(turnContext.getActivity().getConversation().getTenantId());
|
|
||||||
}};
|
|
||||||
|
|
||||||
conversations.add(
|
|
||||||
((BotFrameworkAdapter) turnContext.getAdapter()).createConversation(
|
|
||||||
teamsChannelId,
|
|
||||||
serviceUrl,
|
|
||||||
credentials,
|
|
||||||
conversationParameters,
|
|
||||||
(context) -> {
|
|
||||||
ConversationReference reference = context.getActivity().getConversationReference();
|
|
||||||
return context.getAdapter().continueConversation(
|
|
||||||
appId,
|
|
||||||
reference,
|
|
||||||
(inner_context) -> inner_context.sendActivity(proactiveMessage)
|
|
||||||
.thenApply(resourceResponse -> null)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
return CompletableFuture.allOf(conversations.toArray(new CompletableFuture[0]));
|
|
||||||
})
|
|
||||||
// After all member messages are sent, send confirmation to the user.
|
|
||||||
.thenApply(conversations -> turnContext.sendActivity(MessageFactory.text("All messages have been sent.")))
|
|
||||||
.thenApply(allSent -> null);
|
|
||||||
}
|
|
||||||
|
|
||||||
private CompletableFuture<Void> updateCardActivity(TurnContext turnContext) {
|
|
||||||
Map data = (Map) turnContext.getActivity().getValue();
|
|
||||||
data.put("count", (int) data.get("count") + 1);
|
|
||||||
|
|
||||||
HeroCard card = new HeroCard() {{
|
HeroCard card = new HeroCard() {{
|
||||||
setTitle("Welcome Card");
|
setTitle(actionData.get("title"));
|
||||||
setText("Update count - " + data.get("count"));
|
setSubtitle(actionData.get("subTitle"));
|
||||||
setButtons(Arrays.asList(
|
setText(actionData.get("text"));
|
||||||
new CardAction() {{
|
|
||||||
setType(ActionTypes.MESSAGE_BACK);
|
|
||||||
setTitle("Update Card");
|
|
||||||
setText("UpdateCardAction");
|
|
||||||
setValue(data);
|
|
||||||
}},
|
|
||||||
new CardAction() {{
|
|
||||||
setType(ActionTypes.MESSAGE_BACK);
|
|
||||||
setTitle("Message All Members");
|
|
||||||
setText("MessageAllMembers");
|
|
||||||
}},
|
|
||||||
new CardAction() {{
|
|
||||||
setType(ActionTypes.MESSAGE_BACK);
|
|
||||||
setTitle("Delete card");
|
|
||||||
setText("Delete");
|
|
||||||
}}
|
|
||||||
));
|
|
||||||
}};
|
}};
|
||||||
|
|
||||||
Activity updatedActivity = MessageFactory.attachment(card.toAttachment());
|
List<MessagingExtensionAttachment> attachments = Arrays
|
||||||
updatedActivity.setId(turnContext.getActivity().getReplyToId());
|
.asList(new MessagingExtensionAttachment() {{
|
||||||
|
setContent(card);
|
||||||
|
setContentType(HeroCard.CONTENTTYPE);
|
||||||
|
setPreview(card.toAttachment());
|
||||||
|
}});
|
||||||
|
|
||||||
return turnContext.updateActivity(updatedActivity)
|
return CompletableFuture.completedFuture(new MessagingExtensionActionResponse() {{
|
||||||
.thenApply(resourceResponse -> null);
|
setComposeExtension(new MessagingExtensionResult() {{
|
||||||
|
setAttachments(attachments);
|
||||||
|
setAttachmentLayout("list");
|
||||||
|
setType("result");
|
||||||
|
}});
|
||||||
|
}});
|
||||||
}
|
}
|
||||||
|
|
||||||
private CompletableFuture<Void> mentionActivity(TurnContext turnContext) {
|
private CompletableFuture<MessagingExtensionActionResponse> shareMessageCommand(
|
||||||
Mention mention = new Mention();
|
TurnContext turnContext,
|
||||||
mention.setMentioned(turnContext.getActivity().getFrom());
|
MessagingExtensionAction action
|
||||||
mention.setText("<at>" + URLEncoder.encode(turnContext.getActivity().getFrom().getName()) + "</at>");
|
) {
|
||||||
|
Map<String, String> actionData = (Map<String, String>) action.getData();
|
||||||
|
|
||||||
Activity replyActivity = MessageFactory.text("Hello " + mention.getText() + ".'");
|
HeroCard card = new HeroCard() {{
|
||||||
replyActivity.setMentions(Collections.singletonList(mention));
|
setTitle(
|
||||||
|
action.getMessagePayload().getFrom().getUser() != null ? action.getMessagePayload()
|
||||||
|
.getFrom().getUser().getDisplayName() : "");
|
||||||
|
setText(action.getMessagePayload().getBody().getContent());
|
||||||
|
}};
|
||||||
|
|
||||||
return turnContext.sendActivity(replyActivity)
|
if (action.getMessagePayload().getAttachments() != null && !action.getMessagePayload()
|
||||||
.thenApply(resourceResponse -> null);
|
.getAttachments().isEmpty()) {
|
||||||
|
card.setSubtitle("Attachments not included)");
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean includeImage = actionData.get("includeImage") != null ? (
|
||||||
|
Boolean.valueOf(actionData.get("includeImage"))
|
||||||
|
) : false;
|
||||||
|
if (includeImage) {
|
||||||
|
card.setImages(Arrays.asList(new CardImage() {{
|
||||||
|
setUrl(
|
||||||
|
"https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcQtB3AwMUeNoq4gUBGe6Ocj8kyh3bXa9ZbV7u1fVKQoyKFHdkqU");
|
||||||
|
}}));
|
||||||
|
}
|
||||||
|
|
||||||
|
return CompletableFuture.completedFuture(new MessagingExtensionActionResponse() {{
|
||||||
|
setComposeExtension(new MessagingExtensionResult() {{
|
||||||
|
setAttachmentLayout("list");
|
||||||
|
setType("result");
|
||||||
|
setAttachments(Arrays.asList(new MessagingExtensionAttachment() {{
|
||||||
|
setContent(card);
|
||||||
|
setContentType(HeroCard.CONTENTTYPE);
|
||||||
|
setPreview(card.toAttachment());
|
||||||
|
}}));
|
||||||
|
}});
|
||||||
|
}});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,78 +1,78 @@
|
||||||
{
|
{
|
||||||
"$schema": "https://developer.microsoft.com/en-us/json-schemas/teams/v1.5/MicrosoftTeams.schema.json",
|
"$schema": "https://developer.microsoft.com/en-us/json-schemas/teams/v1.5/MicrosoftTeams.schema.json",
|
||||||
"manifestVersion": "1.5",
|
"manifestVersion": "1.5",
|
||||||
"version": "1.0",
|
"version": "1.0",
|
||||||
"id": "<<YOUR-MICROSOFT-APP-ID>>",
|
"id": "<<YOUR-MICROSOFT-APP-ID>>",
|
||||||
"packageName": "com.microsoft.teams.samples",
|
"packageName": "com.microsoft.teams.samples",
|
||||||
"developer": {
|
"developer": {
|
||||||
"name": "Microsoft",
|
"name": "Microsoft",
|
||||||
"websiteUrl": "https://dev.botframework.com",
|
"websiteUrl": "https://dev.botframework.com",
|
||||||
"privacyUrl": "https://privacy.microsoft.com",
|
"privacyUrl": "https://privacy.microsoft.com",
|
||||||
"termsOfUseUrl": "https://www.microsoft.com/en-us/legal/intellectualproperty/copyright/default.aspx"
|
"termsOfUseUrl": "https://www.microsoft.com/en-us/legal/intellectualproperty/copyright/default.aspx"
|
||||||
},
|
},
|
||||||
"name": {
|
"name": {
|
||||||
"short": "Action Messaging Extension",
|
"short": "Action Messaging Extension",
|
||||||
"full": "Microsoft Teams Action Based Messaging Extension"
|
"full": "Microsoft Teams Action Based Messaging Extension"
|
||||||
},
|
},
|
||||||
"description": {
|
"description": {
|
||||||
"short": "Sample demonstrating an Action Based Messaging Extension",
|
"short": "Sample demonstrating an Action Based Messaging Extension",
|
||||||
"full": "Sample Action Messaging Extension built with the Bot Builder SDK"
|
"full": "Sample Action Messaging Extension built with the Bot Builder SDK"
|
||||||
},
|
},
|
||||||
"icons": {
|
"icons": {
|
||||||
"outline": "icon-outline.png",
|
"outline": "icon-outline.png",
|
||||||
"color": "icon-color.png"
|
"color": "icon-color.png"
|
||||||
},
|
},
|
||||||
"accentColor": "#FFFFFF",
|
"accentColor": "#FFFFFF",
|
||||||
"composeExtensions": [
|
"composeExtensions": [
|
||||||
{
|
|
||||||
"botId": "<<YOUR-MICROSOFT-APP-ID>>",
|
|
||||||
"commands": [
|
|
||||||
{
|
{
|
||||||
"id": "createCard",
|
"botId": "<<YOUR-MICROSOFT-APP-ID>>",
|
||||||
"type": "action",
|
"commands": [
|
||||||
"context": [ "compose" ],
|
{
|
||||||
"description": "Command to run action to create a Card from Compose Box",
|
"id": "createCard",
|
||||||
"title": "Create Card",
|
"type": "action",
|
||||||
"parameters": [
|
"context": [ "compose" ],
|
||||||
{
|
"description": "Command to run action to create a Card from Compose Box",
|
||||||
"name": "title",
|
"title": "Create Card",
|
||||||
"title": "Card title",
|
"parameters": [
|
||||||
"description": "Title for the card",
|
{
|
||||||
"inputType": "text"
|
"name": "title",
|
||||||
},
|
"title": "Card title",
|
||||||
{
|
"description": "Title for the card",
|
||||||
"name": "subTitle",
|
"inputType": "text"
|
||||||
"title": "Subtitle",
|
},
|
||||||
"description": "Subtitle for the card",
|
{
|
||||||
"inputType": "text"
|
"name": "subTitle",
|
||||||
},
|
"title": "Subtitle",
|
||||||
{
|
"description": "Subtitle for the card",
|
||||||
"name": "text",
|
"inputType": "text"
|
||||||
"title": "Text",
|
},
|
||||||
"description": "Text for the card",
|
{
|
||||||
"inputType": "textarea"
|
"name": "text",
|
||||||
}
|
"title": "Text",
|
||||||
]
|
"description": "Text for the card",
|
||||||
},
|
"inputType": "textarea"
|
||||||
{
|
}
|
||||||
"id": "shareMessage",
|
]
|
||||||
"type": "action",
|
},
|
||||||
"context": [ "message" ],
|
{
|
||||||
"description": "Test command to run action on message context (message sharing)",
|
"id": "shareMessage",
|
||||||
"title": "Share Message",
|
"type": "action",
|
||||||
"parameters": [
|
"context": [ "message" ],
|
||||||
{
|
"description": "Test command to run action on message context (message sharing)",
|
||||||
"name": "includeImage",
|
"title": "Share Message",
|
||||||
"title": "Include Image",
|
"parameters": [
|
||||||
"description": "Include image in Hero Card",
|
{
|
||||||
"inputType": "toggle"
|
"name": "includeImage",
|
||||||
}
|
"title": "Include Image",
|
||||||
]
|
"description": "Include image in Hero Card",
|
||||||
|
"inputType": "toggle"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
}
|
}
|
||||||
]
|
],
|
||||||
}
|
"permissions": [
|
||||||
],
|
"identity"
|
||||||
"permissions": [
|
]
|
||||||
"identity"
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
|
|
Загрузка…
Ссылка в новой задаче