Find replies on Slack direct message - slack

I'm dumping my direct messages in Slack.
I manage to get all the messages one by one.
However I don't find any property that tells which message is a parent message and which ones are replies.
How can we get this information?
Typical code in C#
ConversationsListResponse conversationListRespons = await slackClient.GetConversationsListAsync("",false,100,types);
foreach (var channel in conversationListRespons.channels)
{
ConversationsMessageHistory messages = await slackClient.GetConversationsHistoryAsync(channel);
Even when I test the api from the slack interface, it's not giving the information.
Are there any other apis than the ones I'm using to get the required information?
Api used: https://api.slack.com/methods/conversations.history
Here is an example: This a main Direct Message with 4 replies.
conversations.history returns them without any relationship between them.
The query in slack test interface:
and the result:
{
"ok": true,
"messages": [
{
"type": "message",
"text": "voici un log",
"files": [
{
"id": "F04M6EAEXGX",
"created": 1675280228,
"timestamp": 1675280228,
"name": "32x32.ico",
"title": "32x32.ico",
"mimetype": "application/octet-stream",
"filetype": "binary",
"pretty_type": "Binary",
"user": "U0XNQGD0R",
"user_team": "T0XN0RW8H",
"editable": false,
"size": 4286,
"mode": "hosted",
"is_external": false,
"external_type": "",
"is_public": false,
"public_url_shared": false,
"display_as_bot": false,
"username": "",
"url_private": "https://files.slack.com/files-pri/T0XN0RW8H-F04M6EAEXGX/32x32.ico",
"url_private_download": "https://files.slack.com/files-pri/T0XN0RW8H-F04M6EAEXGX/download/32x32.ico",
"media_display_type": "unknown",
"permalink": "https://sanitized.slack.com/files/U0XNQGD0R/F04M6EAEXGX/32x32.ico",
"permalink_public": "https://slack-files.com/T0XN0RW8H-F04M6EAEXGX-bb8c68eec7",
"is_starred": false,
"has_rich_preview": false,
"file_access": "visible",
"media_progress": null
}
],
"upload": false,
"user": "U0XNQGD0R",
"display_as_bot": false,
"ts": "1675280236.783609",
"blocks": [
{
"type": "rich_text",
"block_id": "Twy",
"elements": [
{
"type": "rich_text_section",
"elements": [
{
"type": "text",
"text": "voici un log"
}
]
}
]
}
],
"client_msg_id": "5bda3f9c-64a8-4c1b-8b5e-f37c3b2e2c5d"
},
{
"client_msg_id": "850f4ecc-59c0-4af0-b13f-e527ed7a88de",
"type": "message",
"text": "<#U0XNQ04JD> test",
"user": "U0XNQGD0R",
"ts": "1675280205.367429",
"blocks": [
{
"type": "rich_text",
"block_id": "qi/vH",
"elements": [
{
"type": "rich_text_section",
"elements": [
{
"type": "user",
"user_id": "U0XNQ04JD"
},
{
"type": "text",
"text": " test"
}
]
}
]
}
],
"team": "T0XN0RW8H"
},
{
"client_msg_id": "e249a07d-f887-4edb-859a-1cc38559dc7b",
"type": "message",
"text": ":100:",
"user": "U0XNQGD0R",
"ts": "1675280190.138859",
"blocks": [
{
"type": "rich_text",
"block_id": "rGp",
"elements": [
{
"type": "rich_text_section",
"elements": [
{
"type": "emoji",
"name": "100",
"unicode": "1f4af"
}
]
}
]
}
],
"team": "T0XN0RW8H"
},
{
"client_msg_id": "df2a2f63-21b1-42d5-91db-3c66b083ed7c",
"type": "message",
"text": "yes<https://www.google.com|link to google>",
"user": "U0XNQGD0R",
"ts": "1675280183.929889",
"blocks": [
{
"type": "rich_text",
"block_id": "GZV",
"elements": [
{
"type": "rich_text_section",
"elements": [
{
"type": "text",
"text": "yes"
},
{
"type": "link",
"url": "https://www.google.com",
"text": "link to google"
}
]
}
]
}
],
"team": "T0XN0RW8H",
"reactions": [
{
"name": "+1",
"users": [
"U0XNQGD0R"
],
"count": 1
}
]
},
{
"client_msg_id": "116e4fc3-ef4a-4148-84ad-975ff0f227e6",
"type": "message",
"text": "Salut Christophe,\nthis is a test for Slack",
"user": "U0XNQGD0R",
"ts": "1675254487.545169",
"blocks": [
{
"type": "rich_text",
"block_id": "O2s",
"elements": [
{
"type": "rich_text_section",
"elements": [
{
"type": "text",
"text": "Salut ,\nthis is a test for Slack"
}
]
}
]
}
],
"team": "T0XN0RW8H"
}
],
"has_more": false,
"is_limited": false,
"pin_count": 0,
"channel_actions_ts": null,
"channel_actions_count": 0
}

To start, there might be some confusion as to what constitutes a reply or thread on Slack. Your first screenshot seems like several "normal" messages posted by the same user one after the other. In Slack a thread is a message posted by selecting the thread icon that corresponds to a parent message as seen in the screenshot.
With that established, you can retrieve threaded messages by making a call to conversations.replies.

Related

Adaptive card version 1.5 Table is not rendering in the Bot Emulator

I am using a table of adaptive card version 1.5 but is not rendering into the emulator. My Emulator version is 4.14.1.
below is the JSON structure of the adaptive card.
{
"type": "AdaptiveCard",
"$schema": "http://adaptivecards.io/schemas/adaptive-card.json",
"version": "1.5",
"body": [
{
"type": "Table",
"columns": [
{
"width": 1
},
{
"width": 1
},
{
"width": 1
}
],
"rows": [
{
"type": "TableRow",
"cells": [
`yourtext`{
"type": "TableCell",
"items": [
{
"type": "TextBlock",
"text": "11",
"wrap": true
}
]
},
{
"type": "TableCell",
"items": [
{
"type": "TextBlock",
"text": "111",
"wrap": true
}
]
},
{
"type": "TableCell",
"items": [
{
"type": "TextBlock",
"text": "1111",
"wrap": true
}
]
}
]
},
{
"type": "TableRow",
"cells": [
{
"type": "TableCell",
"items": [
{
"type": "TextBlock",
"text": "22",
"wrap": true
}
]
},
{
"type": "TableCell",
"items": [
{
"type": "TextBlock",
"text": "222",
"wrap": true
}
]
},
{
"type": "TableCell",
"items": [
{
"type": "TextBlock",
"text": "2222",
"wrap": true
}
]
}
]
},
{
"type": "TableRow",
"cells": [
{
"type": "TableCell",
"items": [
{
"type": "TextBlock",
"text": "33",
"wrap": true
}
]
},
{
"type": "TableCell",
"items": [
{
"type": "TextBlock",
"text": "333",
"wrap": true
}
]
},
{
"type": "TableCell",
"items": [
{
"type": "TextBlock",
"text": "3333",
"wrap": true
}
]
}
]
}
]
}
]
}
Bot Framework supports adaptive card version 1.3. So change Adaptive card "version": "1.5" to "version": "1.3"
Bot Framework should now support 1.5, so this looks like a bug. As you reported it here:
https://github.com/microsoft/BotFramework-Emulator/issues/2407

Disable Submit Actions and Inputs for adaptive cards in BotFramework-Webchat

I am trying to find a way to disable the Action.Submit action type and all inputs of adaptive cards that are not the most recent message in the conversation. I found this option of using the attachmentMiddleware of the BotFramework-Webchat used in React.
const attachmentMiddleware = () => next => ({ activity, attachment, ...others }) => {
if (attachment.contentType === "application/vnd.microsoft.card.custom") {
attachment.contentType = "application/vnd.microsoft.card.adaptive"
}
const { activities } = store.getState()
const messageActivities = activities.filter(
activity =>
activity.type === "message" &&
typeof activity.suggestedActions === "undefined" // to filter out suggested actions
)
const recentBotMessage = messageActivities.pop() === activity
const AdaptiveCardContent = Components.AdaptiveCardContent
switch (attachment.contentType) {
case "application/vnd.microsoft.card.adaptive":
return (
<AdaptiveCardContent
actionPerformedClassName="card__action--performed"
content={
attachment.content
}
disabled={!recentBotMessage}
/>
)
default:
return next({ activity, attachment, ...others })
}
}
This solution sets the disabled property in the AdaptiveCardContent Component for not recent messages by the bot and works really well except for Action.OpenUrl actions on containers.
Any Action.OpenUrl will have no functionality, but will look like it is still an enabled button. Example Screenshot:
As seen in the screenshot, the "primary" actions at the bottom of type Action.Submit are disabled correctly. Now the Action.ToggleVisibility ("Toggle", which changes the visibility of an text) and the Action.OpenUrl ("Open in new tab") are not disabled. The Action.ToggleVisibility ("Toggle") works as it did before, which is our intended behavior and fine. But the Action.OpenUrl which looks like it is still clickable, is in fact not.
I think it is because of the following line #107 and #108 in botframework-webchat\src\adaptiveCards\Attachment\AdaptiveCardRenderer.tsx:
// Only listen to event if it is not disabled and have "tapAction" prop.
const handleClickAndKeyPressForTapAction = !disabled && tapAction ? handleClickAndKeyPress : undefined;
But I do not understand why the Action.ToggleVisibility actions work just fine and the Action.OpenUrl actions, which html elements are not disabled and have no aria-disabled="true" properties, have no handling for clicking them.
I tried a completely different way of achieving this behavior by modifying the card, that is given to the AdaptiveCardContent, but this way leads to not wanted effects like loosing the inputted values of users after disabling the inputs, since it seems the usePersistValuesModEffect is overwritten or something, or like some unwanted effects from re-rendering the changed adaptive card.
Does anybody know if this is a bug or intended behavior of the disabled property and if so if there is a good working solution to disable inputs and only Action.Submit actions of adaptive cards?
EDIT:
This is the attachment.content value, meaning the adaptive card that is given to the <AdaptiveCardContent> component:
{
"contentType": "application/vnd.microsoft.card.adaptive",
"content": {
"type": "AdaptiveCard",
"version": "1.3",
"speak": "",
"body": [
{
"type": "Container",
"id": "content",
"items": [
{
"type": "TextBlock",
"weight": "bolder",
"text": "A title",
"wrap": true
},
{
"type": "Container",
"items": [
{
"type": "TextBlock",
"id": "descriptionPreview",
"text": "Some Content",
"wrap": true
}
],
"spacing": "medium",
"separator": true
},
{
"type": "Container",
"items": [
{
"type": "Container",
"items": [
{
"type": "ColumnSet",
"id": "nonBlocking3",
"columns": [
{
"type": "Column",
"width": "stretch",
"items": [
{
"type": "TextBlock",
"id": "toggleKCostDown",
"weight": "bolder",
"text": "Cost",
"wrap": true
},
{
"type": "TextBlock",
"id": "toggleCostUp",
"weight": "bolder",
"text": "Cost",
"wrap": true,
"isVisible": false
}
],
"verticalContentAlignment": "center"
}
],
"style": "accent",
"selectAction": {
"type": "Action.ToggleVisibility",
"targetElements": [
"toggleCostDown",
"toggleCostDownChevron",
"toggleCostUp",
"toggleCostUpChevron",
"contentCost"
]
},
"bleed": true
},
{
"type": "TextBlock",
"id": "contentCost",
"text": "Some info about costs.",
"wrap": true,
"isVisible": false
}
]
}
],
"bleed": true
},
{
"type": "Container",
"id": "nonBlocking4",
"items": [
{
"type": "ColumnSet",
"columns": [
{
"type": "Column",
"width": "50px",
"items": [
{
"type": "Column",
"width": "70",
"items": [
{
"type": "TextBlock",
"weight": "bolder",
"text": "Open in new tab",
"wrap": true
}
]
}
]
}
]
}
],
"style": "accent",
"selectAction": {
"type": "Action.OpenUrl",
"url": "https://google.com",
"title": "Open in new tab"
},
"spacing": "medium"
}
]
},
{
"type": "TextBlock",
"weight": "bolder",
"text": "Have you found what you are looking for?",
"wrap": true
},
{
"type": "ColumnSet",
"columns": [
{
"type": "Column",
"width": "stretch",
"items": [
{
"type": "ActionSet",
"actions": [
{
"type": "Action.Submit",
"data": "No",
"title": "No",
"style": "destructive"
}
]
}
]
},
{
"type": "Column",
"width": "stretch",
"items": [
{
"type": "ActionSet",
"actions": [
{
"type": "Action.Submit",
"data": "Yes",
"title": "Yes",
"style": "positive"
}
]
}
]
}
],
"spacing": "medium",
"separator": true
}
]
}
}

Type ahead search doesn't work when tried from Task module

When I try to write something in the Input.choices component, it doesn't invoke onInvokeActivity while using it from the Task module, I see there's this issue already mentioned around several months ago, but MSFT teams couldn't share the ETA, please help if you come across this and have solved it.
I am attaching the sample code and the onInvokeActivity method here.
{
"type": "AdaptiveCard",
"body": [
{
"type": "Container",
"items": [
{
"type": "TextBlock",
"text": "Heading",
"wrap": true,
"size": "Small",
"weight": "Bolder"
},
{
"type": "Input.ChoiceSet",
"placeholder": "Select something",
"isRequired": true,
"errorMessage": "Select at least one",
"id": "userId",
"choices": "${choices}",
"choices.data": {
"type": "Data.Query",
"dataset": "hello"
},
"spacing": "None",
"style": "filtered",
"value": "${defaultChoice}"
}
],
"spacing": "ExtraLarge"
}
],
"actions": [
{
"data": {
"commandId": "commandId",
"msteams": {
"type": "invoke",
"value": {
"type": "task/submit"
}
}
},
"title": "Submit",
"type": "Action.Submit"
}
],
"$schema": "http://adaptivecards.io/schemas/adaptive-card.json",
"version": "1.3"
}
protected async onInvokeActivity(
context: TurnContext
): Promise<InvokeResponse<any>> {
if (context.activity.name === "application/search") {
const { queryText, dataset } = context.activity.value;
if (dataset === "hello") {
console.log({ queryText });
}
}
}
Network tab response while typing:
{
"statusCode": 504,
"message": "App is not installed"
}

BotFramework Adaptive Cards - Container Actions are not Rendered

How can I add actions for containers?
According to the documentation Container type has an "actions" object, but when testing the card it in the adaptive cards visualizer or in the bot-framework emulator no button is displayed.
Attached an example for the kind of card I'm trying to generate.
Thanks for your help.
{
"type": "AdaptiveCard",
"body": [
{
"style":"normal",
"type": "Container",
"separation" : "strong",
"actions": [
{
"type": "Action.OpenUrl",
"url": "http://foo.bar.com",
"title": "adaptivecards1"
}
],
"items": [
{
"type": "ColumnSet",
"separation": "strong",
"columns": [
{
"type": "Column",
"size":1,
"items": [
{
"type": "TextBlock",
"text": "Title",
"size": "large",
"isSubtle": true
},
{
"type": "TextBlock",
"text": "Model: ABC",
"size": "small"
}
]
},
{
"type": "Column",
"size": "1",
"items": [
{
"type": "TextBlock",
"text": " "
},
{
"type": "Image",
"url": "https://path/to/image.jpg",
"size": "large",
"horizontalAlignment" :"right"
}
]
}
]
}
]
},
{
"style":"normal",
"type": "Container",
"separation" : "strong",
"actions": [
{
"type": "Action. OpenUrl",
"url": "http://foo.bar.com",
"title": "adaptivecards2"
}
],
"items": [
{
"type": "ColumnSet",
"separation": "strong",
"columns": [
{
"type": "Column",
"size":1,
"items": [
{
"type": "TextBlock",
"text": "Another Title",
"size": "large",
"isSubtle": true
},
{
"type": "TextBlock",
"text": "Model: XYZ",
"size": "small"
} ]
},
{
"type": "Column",
"size": "1",
"items": [
{
"type": "TextBlock",
"text": " "
},
{
"type": "Image",
"url": "https://path/to/other/image.jpg",
"size": "large",
"horizontalAlignment" :"right"
}
]
}
]
}
]
}
]}
Per this GitHub issue, it seems that there is an error in the documentation and that the actions property doesn't exist on Container.
Instead, you should add an item of type ActionSet to your items array, with the list of actions.
Following your sample, it should look like:
{
"type": "AdaptiveCard",
"body": [
{
"style": "normal",
"type": "Container",
"separation": "strong",
"items": [
{
"type": "ActionSet",
"actions": [
{
"type": "Action.OpenUrl",
"url": "http://foo.bar.com",
"title": "adaptivecards1"
}
]
},
{
"type": "ColumnSet",
"separation": "strong",
"columns": [
{
"type": "Column",
"size": 1,
"items": [
{
"type": "TextBlock",
"text": "Title",
"size": "large",
"isSubtle": true
},
{
"type": "TextBlock",
"text": "Model: ABC",
"size": "small"
}
]
},
{
"type": "Column",
"size": "1",
"items": [
{
"type": "TextBlock",
"text": " "
},
{
"type": "Image",
"url": "https://path/to/image.jpg",
"size": "large",
"horizontalAlignment": "right"
}
]
}
]
}
]
},
{
"style": "normal",
"type": "Container",
"separation": "strong",
"items": [
{
"type": "ActionSet",
"actions": [
{
"type": "Action.OpenUrl",
"url": "http://foo.bar.com",
"title": "adaptivecards2"
}
]
},
{
"type": "ColumnSet",
"separation": "strong",
"columns": [
{
"type": "Column",
"size": 1,
"items": [
{
"type": "TextBlock",
"text": "Another Title",
"size": "large",
"isSubtle": true
},
{
"type": "TextBlock",
"text": "Model: XYZ",
"size": "small"
}
]
},
{
"type": "Column",
"size": "1",
"items": [
{
"type": "TextBlock",
"text": " "
},
{
"type": "Image",
"url": "https://path/to/other/image.jpg",
"size": "large",
"horizontalAlignment": "right"
}
]
}
]
}
]
}
]
}
This is also discussed here.

When connecting to LUIS, what does the "forceset" parameter do

In my LUIS app I have an intent called GetWeather requiring a Location to be set.
When connecting to the app using the query
What is the weather in london
it correctly returns
{
"query": "what is the weather in london",
"topScoringIntent": {
"intent": "GetWeather",
"score": 0.999875546,
"actions": [
{
"triggered": true,
"name": "GetWeather",
"parameters": [
{
"name": "Location",
"type": "Location",
"required": true,
"value": [
{
"entity": "london",
"type": "Location",
"resolution": {}
}
]
}
]
}
]
},
"entities": [
{
"entity": "london",
"type": "Location",
"startIndex": 23,
"endIndex": 28,
"score": 0.832388461,
"resolution": {}
}
],
"dialog": {
"contextId": "e1df6c2d-e691-4fc6-89f2-3ee2ef519724",
"status": "Finished"
}
}
If I instead use the query
What is the weather
It returns the following expected result.
{
"query": "what is the weather",
"topScoringIntent": {
"intent": "GetWeather",
"score": 1.0,
"actions": [
{
"triggered": false,
"name": "GetWeather",
"parameters": [
{
"name": "Location",
"type": "Location",
"required": true,
"value": null
}
]
}
]
},
"entities": [],
"dialog": {
"prompt": "Where",
"parameterName": "Location",
"parameterType": "Location",
"contextId": "3b0725f4-7d6f-43fd-ab6e-02fc11c3eed1",
"status": "Question"
}
}
I thought that using the contextID together with the forceSet parameter in my next call would set the parameter Location to whatever I send as the query. The conection string I use is this:
https://api.projectoxford.ai/luis/v2.0/apps/{APP_ID}?subscription-key={SUBSCRIPTION_KEY}&q=london&contextid=3b0725f4-7d6f-43fd-ab6e-02fc11c3eed1&forceset=Location
Instead I get the following response back:
{
"query": "london",
"topScoringIntent": {
"intent": "GetWeather",
"score": 1.0,
"actions": [
{
"triggered": false,
"name": "GetWeather",
"parameters": [
{
"name": "Location",
"type": "Location",
"required": true,
"value": null
}
]
}
]
},
"entities": [],
"dialog": {
"prompt": "Where",
"parameterName": "Location",
"parameterType": "Location",
"contextId": "3b0725f4-7d6f-43fd-ab6e-02fc11c3eed1",
"status": "Question"
}
}
I had expected to get something like my first response back.
Am I doing something wrong or just misunderstanding what the forceSet parameter is supposed to do?

Resources