I am using the ms adaptive cards for teams using nodejs. I can see actions has button of type Action.Submit to pass form data. However, I want to understand how to handle cancel case.
Is there a way to simply close the form on clicking cancel button or I have to let it behave like save button and return nothing from server side when the cancel button is pressed.
my card is like below
{
"type": "AdaptiveCard",
"body": [
{
"type": "TextBlock",
"size": "Medium",
"weight": "Bolder",
"text": "{title}"
},
{
"type": "ColumnSet",
"columns": [
{
"type": "Column",
"items": [
{
"type": "Image",
"style": "Person",
"url": "{creator.profileImage}",
"size": "Small"
}
],
"width": "auto"
},
{
"type": "Column",
"items": [
{
"type": "TextBlock",
"weight": "Bolder",
"text": "{creator.name}",
"wrap": true
},
{
"type": "TextBlock",
"spacing": "None",
"text": "Created {{DATE({createdUtc},SHORT)}}",
"isSubtle": true,
"wrap": true
}
],
"width": "stretch"
}
]
}
],
"actions": [
{
"type": "Action.ShowCard",
"title": "Set due date",
"card": {
"type": "AdaptiveCard",
"body": [
{
"type": "Input.Text",
"id": "comment",
"placeholder": "Add a comment",
"isMultiline": true
}
],
"actions": [
{
"type": "Action.Submit",
"title": "OK"
},
{
"type": "Action.Submit",
"title": "Cancel"
}
],
"$schema": "http://adaptivecards.io/schemas/adaptive-card.json"
}
}
],
"$schema": "http://adaptivecards.io/schemas/adaptive-card.json",
"version": "1.0"
}
There is no exact defined way to handle Cancel functionality.
You have to manage it code behind additionally, Yes you are right like Save Action you also have to set functionality for Cancel
For example what I did is when my user choose sorry, not now (Think
like Cancel) I took that response and under a Switch-Case reply as
required.
//Check Each User Input
switch (checkUserInput.ToLower())
{
case "sorry, not now":
await turnContext.SendActivityAsync(MessageFactory.Text("Okay, Can I help with anything else?"), cancellationToken);
//Send Another Yes/No Card
var yesNoFlow = _customFlowRepository.YesNoFlow();
await turnContext.SendActivityAsync(yesNoFlow).ConfigureAwait(false);
break;
default: //When nothing found in user intent
await turnContext.SendActivityAsync(MessageFactory.Text("What are you looking for?"), cancellationToken);
break;
}
You could have a look the screen shot below:
Hope this would help you to figure out your issue. Let me know if you have any more concern.
There's no way to "Cancel" a card per se, to make it go away - if the user doesn't want to continue, they can simply stop interacting with the card. However, here are some possible alternatives:
You -could- implement a "cancel" button as a submit action, which you could detect in the bot, and reply with an appropriate message
You could look at consider the "ShowCard" action? It basically lets you collapse part of your card, and only open it when a user clicks on a button. That way you could possibly group your card into sections and show each one at a time. See here for more.
Another option in future is the new ToggleVisibility action in AdaptiveCards 1.2, but it's only if your client supports 1.2. (e.g. it's only available in Developer Preview for Teams right now (so very likely/hopefully coming in future, but not available at the moment))
There is nothing such as a cancel button in Adaptive Cards. If you want to close the card/not show the card anymore you could try updating that card with another new card that you would like to show.
From your code, the Cancel Button acts just like that of Submit. It's
because the Submit button will be associated with all the fields and
inputs that you are providing from your Bot and the same applies for
Cancel as it is defaulted to all Inputs.
By adding the changes as that of below, once you hit the Cancel Button,
you will come out of the form and navigate to whichever dialog/flow
that follows.
{
"type": "Action.Submit",
"title": "Cancel",
"associatedInputs": "none"
}
For more information please find this link:
https://adaptivecards.io/explorer/Action.Submit.html.
I believe this might resolve the problem.
another approach is to look for a cancel data object:
new AdaptiveSubmitAction
{
Title = "Login",
Style="positive",
AssociatedInputs = AdaptiveAssociatedInputs.Auto,
Id="ok",
},
new AdaptiveSubmitAction
{
Title = "Cancel",
Style="negative",
AssociatedInputs = AdaptiveAssociatedInputs.None,
Data = CANCEL_VALUE,
Id="cancel"
}
You can then detect the cancel like:
private async Task<DialogTurnResult> SignUserInStepAsync(WaterfallStepContext stepContext, CancellationToken cancellationToken)
{
if (stepContext.Context.Activity.AsMessageActivity()?.Text == CANCEL_VALUE)
{
return new DialogTurnResult(DialogTurnStatus.Cancelled);
}
NOTE:It's important to indicate that the cancel button is not associated with the rest of the card's fields, by setting AssociatedInputs = AdaptiveAssociatedInputs.None.
Related
i'am using slack block in a channel using python and webhook.
Messages are sent and arrived perfectly, the messages contains text and also checkboxes.
When user check a checkbox only that user can see the checked checboxes and not all other user in the channel.
Is it possible for all users to see the selected checkbox?
Thank you
This is my code for build the
checkbox = []
checkbox.append({
"type": "input",
"element": {
"type": "checkboxes",
"options": [
{
"text": {
"type": "plain_text",
"text": "Caricati {} {} di {}".format(
r.qta_caricata, r.articolo.um_elementare,
r.articolo.as_id),
"emoji": True
},
"value": "value-0"
}
],
"action_id": "checkboxes-action"
},
"label": {
"type": "plain_text",
"text": " ",
"emoji": True
}
})
slack_data = {
"username": usr,
"icon_emoji": icon_emoji,
"text": preview,
"blocks": checkbox
}
byte_length = str(sys.getsizeof(slack_data))
headers = {'Content-Type': "application/json",
'Content-Length': byte_length}
response = requests.post(wh_url, data=json.dumps(slack_data),
headers=headers)
Understanding the problem
When user makes changes to the message, those changes are at Client Side, and hence does not reflect on other users view.
Solution
Capture the client's interactivity (check/uncheck of the checkbox), and update the message using Slack APIs from server side.
In your given scenario, you are using web-hooks for posting messages.
Web-hooks are used for one-way communication and therefore, the event of user checking/unchecking the box can't be captured and can't be updated.
This is a continuation of my other question:
My first question
What I am trying to accomplish:
User enters a mention
My web service creates an adaptive card form with custom data (same schema)
presents the card to my user
user enters some data
Submit sends this form data to my web service for processing
Here is the card (the result of the 1st http) I am sending in reply to mention
$var = '{
"type": "AdaptiveCard",
"$schema": "http://adaptivecards.io/schemas/adaptive-card.json",
"version": "1.2",
"msTeams": {
"width": "full"
},
"body": [
{
"type": "TextBlock",
"text": "Adaptive Card Example",
"wrap": true,
"size": "large",
"weight": "bolder",
"id": "title"
},
{
"type": "Input.Text",
"placeholder": "Provide your thoughts",
"separator": true,
"isMultiline": true,
"id": "thoughts"
},
{
"type": "ActionSet",
"separator": true,
"actions": [
{
"type": "Action.Submit",
"title": "Submit",
"style": "positive",
"id": "submit"
}
]
}
]
}
';
How do i get to the value of input.text with the id of thoughts? everything i see, it ends up blank.
I am not sure what else you need to help, i can edit/post anything else.
*EDIT
this is my dynamic dropdown.
You should be able to make use of the dynamic content presented to you that is taken directly from your adaptive card definition ...
If the dynamic property doesn't exist, the easiest way to get the result is to simply refer to it using an expression ...
body('Post_adaptive_card_and_wait_for_a_response')?['data']?['thoughts']
... you could do the work to fully qualify the dynamic properties but in this case, it seems like overkill.
This is the output after I completed the card in my Teams channel ...
How can I get user response from the adaptive card using Adaptive Cards Action.Submit action from MS Teams channel using Microsoft Bot Framework?
Here is my sample Adaptive Card with two button Yes and No. Once the user will click on any button, I need to capture the response in the bot application in the backend implemented using Microsoft Bot Framework 4.
{
"$schema": "http://adaptivecards.io/schemas/adaptive-card.json",
"type": "AdaptiveCard",
"version": "1.2",
"body": [
{
"type": "TextBlock",
"text": "Does this information help you?"
},
{
"type": "ActionSet",
"actions": [
{
"type": "Action.Execute",
"title": "Yes",
"verb": "personalDetailsFormSubmit",
"id": "surveyReplyYes",
"userIds": "" ,
"data":{
"key1": true,
"key2":"okay"
},
"fallback": {
"type": "Action.Submit",
"title": "Yes"
}
},
{
"type": "Action.Execute",
"title": "No",
"verb": "personalDetailsFormSubmit",
"id": "surveyReplyNo",
"userIds": "" ,
"data":{
"key1": false,
"key2":"np"
},
"fallback": {
"type": "Action.Submit",
"title": "No"
}
}
]
}
]
}
Every channel has some additional requirement to achieve this kind of requirement obviously MS Teams Channels Adaptive card required special property with the name "msteams" to the object in an object submit action's data property. As per your adaptive card, it only contains 'data' property so change a little bit and try it out.
Example:
{
"type": "Action.Submit",
"title": "Click me for messageBack",
"data": {
"msteams": {
"type": "messageBack",
"displayText": "I clicked this button",
"text": "text to bots",
"value": "{\"bfKey\": \"bfVal\", \"conflictKey\": \"from value\"}"
},
"extraData": {}
}
}
Reference: Adaptive Cards in Teams
Essentially, your bot is a service waiting to be called by the user. When the user sends a regular text message, that will come in to your bot as a "MessageActivity" event. However, if they click a button in an Adaptive Card, that will come as an "InvokeActivity" event, so you can hook into that and check if the user clicked one of your buttons, and respond appropriately. Here's an example of a bot doing that based on one of it's cards. See in particular OnMessageActivityAsync vs OnInvokeActivityAsync (C# only - see below for Node).
Here's another very detailed blog on working with this, covering both DotNet and Node, from the Microsoft Bot Framework team. That post is a bit old, so it doesn't cover what you're using in your sample, which is quite new - Universal Actions. It's just a slightly newer way of specifying the json for the Action.
This is totally optional, but there's also a way to make the card buttons behave a little differently. For instance, when the user clicks a button you can make it appear as if the user -typed- that text into the bot. See here for more on that.
I am developing Bot in .NET Core 3.1 C#. I want to send Hero card with 4 buttons & welcome prompt as soon as user joins /activates bot. I have tried it in OnMembersAddedAsync
if (member.Id != turnContext.Activity.Recipient.Id)
{
var welcomeCard = CreateAdaptiveCardAttachment();
var response = MessageFactory.Attachment(welcomeCard);
await turnContext.SendActivityAsync( response, cancellationToken);
}
This will display adaptive card where type is Action.Submit. But I am not sure how to get values of the button which customer click on. I tried it on OnMessageActivityAsync
if (turnContext.Activity.Value != null)
{
var mainMenu = turnContext.Activity.Value;
}
But values are always null. Json for adaptive card is :
{
"$schema": "http://adaptivecards.io/schemas/adaptive-card.json",
"type": "AdaptiveCard",
"version": "1.0",
"body": [
{
"type": "TextBlock",
"spacing": "medium",
"size": "default",
"weight": "bolder",
"text": "Welcome to ABC Bank !",
"wrap": true,
"maxLines": 0
},
{
"type": "TextBlock",
"size": "default",
"isSubtle": true,
"text": "Please select user type from below ....",
"wrap": true,
"maxLines": 0
}
],
"actions": [
{
"type": "Action.Submit",
"title": "Consumer"
},
{
"type": "Action.Submit",
"title": "Client"
},
{
"type": "Action.Submit",
"title": "Merchant"
}
]
}
Yes. As said in comments you need to add data property. This is not required. But if you want to collect which option user has provided you need to specify it. Since you don't have any other input field. This will act as an input to carry further operations.
Note: For any input element you need to use id property to identify collected input when submit action is performed.
Similarly for Submit action data. Make sure value in data for each action is unique. If you want 2 buttons to perform same action (nativate to same dialog) then you can specify same value in data
Here is the official link which gives you an idea.
Submit action
Hope this helps
I understand that adaptive cards are down-rendered as image on channels that does not support them. I just want to know how to either remove or set the "Title" element as shown on the fb channel:
The AdaptiveCard.Title element is deprecated and I did try setting that, it did not have any effect.
Here is my sample json:
{
"type": "AdaptiveCard",
"body": [
{
"type": "TextBlock",
"id": "Title",
"horizontalAlignment": "Center",
"size": "Large",
"weight": "Bolder",
"text": "See results on our website!"
},
{
"type": "Image",
"horizontalAlignment": "Center",
"url": "mylogo.png",
"size": "Stretch"
},
{
"type": "TextBlock",
"id": "Subtitle",
"horizontalAlignment": "Center",
"size": "ExtraLarge",
"text": "This channel does not allow us to display your results. Click the button to view it on our website.",
"wrap": true
}
],
"actions": [
{
"type": "Action.OpenUrl",
"id": "OpenUrl",
"title": "Take me there!"
}
],
"$schema": "http://adaptivecards.io/schemas/adaptive-card.json",
"version": "1.0"
}
Unfortunately, when the BotFramewrok renders the card into an image for Facebook Messenger it adds the title above the actions which is strange. The only way to get rid of it is to remove the action from the card, which defeats its purpose in this case. An alternative is to send a Facebook Button Template in the activity's channel data instead of the adaptive card when the user is on Facebook Messenger. For more details checkout the Facebook Documentation on Button Templates and the code snippet below.
Screenshot
Bot Code - Node
async onTurn(turnContext) {
if (turnContext.activity.type === ActivityTypes.Message) {
if (turnContext.activity.channelId === 'facebook') {
await turnContext.sendActivity({
channelData: {
"attachment": {
"type": "template",
"payload": {
"template_type":"button",
"text":"This channel does not allow us to display your results. Click the button to view it on our website.",
"buttons":[{
"type":"web_url",
"url":"https://www.microsoft.com",
"title":"Take me there!"
}]
}
}
}
});
} else {
await turnContext.sendActivity({
attachments: [this.createAdaptiveCard()],
});
}
}
}
Hope this helps!
I had the same problem but I find an alternative using HeroCard.
If you are developing it with C# there it goes the code:
// first of all check if it is Facebook channel
// note that Channels is from Microsoft.Bot.Connector, the old one is deprecated.
if (turnContext.Activity.ChannelId == Channels.Facebook)
{
Activity replyToConversation = _flowService.ConvertMarkdownUrlToFacebookUrl(turnContext.Activity, response.Answer);
await turnContext.SendActivityAsync(replyToConversation, cancellationToken: cancellationToken);
}
public Activity ConvertMarkdownUrlToFacebookUrl(Activity message, string queryResponse)
{
var buttons = getButtons(queryResponse, out string result);
Activity replyToConversation = message.CreateReply();
replyToConversation.Attachments = new List<Attachment>();
List<CardAction> actions = new List<CardAction>();
foreach (var button in buttons)
{
actions.Add(new CardAction()
{
Title = button.Key, // text hyperlink
Type = ActionTypes.OpenUrl,
Value = button.Value // url
});
}
Attachment attachment = new HeroCard
{
Text = result, // your text
Buttons = actions
}.ToAttachment();
replyToConversation.Attachments.Add(attachment);
return replyToConversation;
}
You'll obtain something like this:
(sorry I had to delete the text)
Maybe it's not perfect (my first time with cards and attachments) but I hope that this will help someone 🙂