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.
Related
I'm building a slack app using the slack Bolt API, and I want to open modals from my App's home page when a button on the home page is clicked.
Here's the relevant bit of the action listener that is connected to the button:
app.action("follow-users-button", async ({ ack, payload, client }) => {
await ack();
console.log("app_home opening keyusermodal");
// await block_actions.unfollowKeyuser(action);
console.log("payload = " + JSON.stringify(payload));
await client.views.open({
trigger_id: payload.trigger_id,
Here's what I get on my terminal when I click that button:
payload = {"action_id":"follow-users-button","block_id":"2JW","text":{"type":"plain_text","text":"Users","emoji":true},"value":"click_me_123","type":"button","action_ts":"1642280065.631917"}
[ERROR] bolt-app missing required field: trigger_id
The JSON there is the action payload.
However, according to the Slack docs, this payload should be much larger. Here's the sample payload from Slack's Block Kit Builder:
{
"type": "block_actions",
"user": {
"id": "U02NF0A8D9T",
"username": "person",
"name": "person",
"team_id": "T02NTJ0UDP3"
},
"api_app_id": "A02",
"token": "Shh_its_a_seekrit",
"container": {
"type": "message",
"text": "The contents of the original message where the action originated"
},
"trigger_id": "12466734323.1395872398",
"team": {
"id": "T02NTJ0UDK3",
"domain": "4most-r637660"
},
"enterprise": null,
"is_enterprise_install": false,
"state": {
"values": {}
},
"response_url": "https://www.postresponsestome.com/T123567/1509734234",
"actions": [
{
"type": "button",
"block_id": "QdL",
"action_id": "button-action",
"text": {
"type": "plain_text",
"text": "Click Me",
"emoji": true
},
"value": "click_me_123",
"action_ts": "1642279809.506518"
}
]
}
As you can see, I'm only receiving the actions element in my payload. Where's the rest of it? Why isn't it coming over? I need the trigger_id to open a modal (not having it causes the error), and getting things like user_id would be extremely helpful for my app.
Thanks in advance!
When working with the Bolt JS framework, the expected way to parse the action payload to get the trigger id is body.trigger_id.
According to Slack's documentation, you can use blocks to update an entire ephemeral message by simply replacing the entire message by setting replace_original as true when posting to the response_url provided in the interaction payload when using buttons.
However, when I'm sending the POST request to the provided response_url after a button has been pressed and I attempt to use blocks, I get the following error: 404 : [{"ok":false,"error":"invalid_blocks"}]
Strangely enough, the payload I'm including for blocks is generated by the same method that creates the original ephemeral message which works fine without any issues.
I was able to replace the entire message with just a plain text message by using the text field indicated in the documentation and it works fine if I don't include the blocks array. I did find some documentation here for posting messages via incoming webhooks here but it looks the same as what I'm sending now.
Here's the body of the request I'm sending:
{
"blocks":
[
{
"type": "image",
"imageUrl": "https://example.com/image.jpeg",
"altText": "alt-text",
"title":
{
"type": "plain_text",
"text": "some text"
}
},
{
"type": "actions",
"elements":
[
{
"type": "button",
"text":
{
"type": "plain_text",
"text": "Send",
"emoji": false
},
"value": "send",
"style": "primary"
},
{
"type": "button",
"text":
{
"type": "plain_text",
"text": "Find new",
"emoji": false
},
"value": "some text"
},
{
"type": "button",
"text":
{
"type": "plain_text",
"text": "Cancel",
"emoji": false
},
"value": "cancel"
}
]
}
],
"replace_original": "true",
"text": "some fallback text"
}
You have two typos in your blocks: imageUrl and altText. Slack expects these to be snake case, i.e. image_url and alt_text.
You can use Slack's Block Kit Builder to debug the blocks payload.
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
Question
I have a Slack modal with a section block containing an input element. When a user submits my modal without entering a value in this input, how do I communicate that error to the user?
My attempt #1: respond with a validation error
Slack's documentation describes how to validate input blocks when I receive a view_submission event (https://api.slack.com/surfaces/modals/using#displaying_errors). But if I return an error for a section block containing a static_select, then Slack does not display an error message (nor does it close the modal).
My attempt #2: set the optional field to false
input blocks have an optional field that can be used for validation. But a static_select in a section block does not have an optional field: https://api.slack.com/reference/block-kit/block-elements#select
My attempt #3: use input blocks
I can not use input blocks because they do not trigger block_actions messages (documented at https://api.slack.com/surfaces/modals/using#interactions). I need to update the modal as the users answer questions.
My attempt #4: the desperation solution that works
I could reply to the view_submission event with a "response_action": "update" response. In that response include an error message like this above the input with the missing value:
{
"type": "section",
"text": {
"type": "mrkdwn",
"text": "*Please provide a start time:*"
}
}
I do not like this solution because I doubt I can duplicate the nice error messaging UX that Slack provides for input block validation.
Details
Here is a simplified version of the view parameter that I am passing to the views.open call:
{
"blocks": [
{
"block_id": "start_times",
"type": "section",
"text": {
"type": "plain_text",
"text": "Choose a start time"
},
"accessory": {
"action_id": "start_times",
"type": "static_select",
"placeholder": {
"type": "plain_text",
"text": "Choose start"
},
"options": [
{
"text": {
"type": "plain_text",
"text": "10:27 pm"
},
"value":
"{\"path\":\"bookings/new\",\"date\":\"2020-02-14 04:27:22 UTC\"}"
},
{
"text": {
"type": "plain_text",
"text": "10:45 pm"
},
"value":
"{\"path\":\"bookings/new\",\"date\":\"2020-02-14 04:45:00 UTC\"}"
}
]
}
}
],
"callback_id": "create booking",
"private_metadata":
"{\"channel_id\":\"C6M2A4690\",\"min_start_time\":\"2020-02-14 04:27:22 UTC\",\"path\":\"bookings/create\",\"room_id\":175128,\"selected_end_time\":null,\"selected_start_time\":null}",
"type": "modal",
"submit": {
"type": "plain_text",
"text": "Book"
},
"title": {
"type": "plain_text",
"text": "Booking room"
}
}
If the user immediately clicks submit, this is my response to the view_submission event:
{
"response_action": "errors",
"errors": {
"start_times": "Please complete this required field"
}
}
Upon receipt of my response, Slack turns off the spinner, leaves the modal open, but does not display an error message. The modal looks exactly the same as when it was first opened via views.open.
Since you posted your question, the functionality of input blocks has changed. Earlier this month, the ability for input blocks to emit block_actions payloads was introduced.
In the Block Kit reference docs for the input block you can see a new dispatch_action parameter. This is a boolean which, when set to true, causes the interactive element inside the input block to emit a block_actions payload when changed.
Therefore, to answer your question more directly, your #3 solution should now be possible without the caveat that you included. Place the static_select inside of an input block, and set dispatch_action to true, like so:
{
"type": "input",
"dispatch_action": true,
"element": {
"type": "static_select",
"placeholder": {
"type": "plain_text",
"text": "Select an item",
"emoji": true
},
"options": [
{
"text": {
"type": "plain_text",
"text": "*this is plain_text text*",
"emoji": true
},
"value": "value-0"
},
{
"text": {
"type": "plain_text",
"text": "*this is plain_text text*",
"emoji": true
},
"value": "value-1"
},
{
"text": {
"type": "plain_text",
"text": "*this is plain_text text*",
"emoji": true
},
"value": "value-2"
}
],
"action_id": "static_select-action"
},
"label": {
"type": "plain_text",
"text": "Label",
"emoji": true
}
}
Upon receiving a view_submission payload, you'll now be able to respond with the correct validation errors and display them to a user. And you can still receive block_actions payloads as needed too.
Set the response's "content_type" to "application/json" before returning response.
If you are using Django as backend then you can do this.
error_object = {
"response_action": "errors",
"errors": {
"start_times": "Please complete this required field"
}
}
return HttpResponse(json.dumps(error_object), content_type="application/json")
===OR===
return JsonResponse(error_object)
don't forget to import JsonReponse if you are using it:
from django.http import JsonResponse
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.