How to add a custom payload to PromptDialog.Choice - botframework

I am trying to add a custom data payload to PromptDialog.Choice / or PromptDialog.Text to indicate a special activity to my bot client.
I know there is a field to specify InputHint to IMessageActivity.
is there a way to add an inputhint/ or a custom tag to PromptDialog flow?

Your best bet is to use something like this:
var options = new PromptOptions()
{
Prompt = MessageFactory.Text("Pick Me!"),
Choices = new List<Choice>()
};
var channelData = new Dictionary<string, string>();
channelData["testKey"] = "testValue";
options.Choices.Add(new Choice()
{
// Value must be set. There's a PR in place to fix this, but for now just leave blank
Value = "",
Action = new CardAction()
{
// PostBack will prevent the user from seeing "Actual Value" after they select it
Type = ActionTypes.PostBack,
Title = "DISPLAYED TEXT",
Value = "ACTUAL VALUE",
}
});
return await stepContext.PromptAsync(nameof(ChoicePrompt), options);
The comments I left in the code should be explanatory enough.
Another solution might be to display a set of cards that include the ChannelData, then a blank text prompt to wait for the user's response. I have a pretty in-depth answer for how to do this. You'd just need to add a ChannelData property so that you can capture your "special activity" code.

Related

Dynamics 365 API link between ActivityPointer and activitytypecode global option set

I am reading data from the ActivityPointer entity in Dynamics 365 via the API and I want to link the activitytypecode field value to the activitypointer_activitytypecode global option set, which I believe is the correct one. However the values don't seem to match. In the ActivityPointer.activitytypecode field I have values such as:
phonecall
bulkoperation
email
appointment
task
But those values don't appear in the option set definition, using this query: GlobalOptionSetDefinitions(Name='activitypointer_activitytypecode')
The option set has the code values (e.g. 4202 for Email) and the different descriptions in all languages, but nothing matches back to the values on ActivityPointer
Optionset is just key value pairs (4202: Email and so on), If you want to get the formatted text value of optionset (Email, Fax, etc) from your web api query results - then you have to use activitytypecode#OData.Community.Display.V1.FormattedValue to get it. Read more
I recommend this article for complete understanding of CRM activities.
If you are looking for the code integer value in your resultset, that seems to be an issue and the result is not the expected one - old SO thread
The problem is that if you are reading activitytypecode in code, then you will know that you get a string value. This is the logical name of the activity entity, e.g. "email", "phonecall" etc.
If you look at the definition of activitytypecode in Power Apps then it shows it as "Entity name" (i.e. text) but using the classic solution editor it shows as the global activitypointer_activitytypecode option set, which contains values for "Email", "Phone Call" etc.
I am sure that there should be a simple way of converting from activitytypecode (i.e. entity name) to activitypointer_activitytypecode (i.e. option set), but I've yet to find it.
What I am doing is retrieving the global activitypointer_activitytypecode option set, so I have access to all of the text values. Then retrieve details about the entity indicated by activitytypecode, specifically what is of interesting is the display name. Then loop through the option set looking for a case-insensitive match on display name.
This is my C# code:
public int? GetActivityType(IOrganizationService service, string activityTypeCode)
{
// Get all activity types.
var optionSetRequest = new RetrieveOptionSetRequest()
{
Name = "activitypointer_activitytypecode"
};
var optionSetResponse = (RetrieveOptionSetResponse)service.Execute(optionSetRequest);
var optionSetMetadata = (OptionSetMetadata)optionSetResponse.OptionSetMetadata;
var optionValues = new Dictionary<string, int?>(StringComparer.OrdinalIgnoreCase);
foreach (var option in optionSetMetadata.Options)
{
foreach (var optionLabel in option.Label.LocalizedLabels)
{
optionValues[optionLabel.Label] = option.Value;
}
}
// Get the display name for the activity.
var retrieveEntityRequest = new RetrieveEntityRequest
{
EntityFilters = EntityFilters.Entity,
LogicalName = activityTypeCode
};
var retrieveEntityResponse = (RetrieveEntityResponse)service.Execute(retrieveEntityRequest);
LocalizedLabelCollection entityLabels = retrieveEntityResponse.EntityMetadata.DisplayName.LocalizedLabels;
// Look up the display name in the option set values.
foreach (var entityLabel in entityLabels)
{
if (optionValues.TryGetValue(entityLabel.Label, out int? value))
{
return (Schema.GlobalOptionSet.ActivityType?)value;
}
}
// If we get here then we've failed.
return null;
}
That is making two API calls, so best avoided in any situations where performance might be an issue. I'm not saying the code is perfect, but it hasn't let me down yet. Even so, I would recommend making do with the logical names provided by activitytypecode if you can.

AdaptiveFact() for having a dynamic value as URI

I am using an adaptive card (1.0) & am trying to give a hyperlink for the user to click so that he/she can navigate to a particular ServiceNow ticket.
I am not able to figure out how the dynamic sys_id can be passed to the hyperlink as the URI/URN.
The hyperlink for the ticket changes for each ticket so it has to be dynamic. But I am not seeing an option to make the URI/URN dynamic.
I have tried escaping & separating the numbers from texts.
new AdaptiveFact()
{
Title="More Information",
Value ="[Click here to open the ticket in SNOW](https://URL.service-now.com/)"
}
I should be able to take sys_id as a parameter(URI/URN) to navigate to the exact incident in SNOW.
The complete Card generator code is as below
AdaptiveCard card = new AdaptiveCard("1.0");
card.Body.Add(new AdaptiveContainer()
{
Items = new List<AdaptiveElement>()
{
new AdaptiveTextBlock()
{
Text= $"Ticket Status for {JSONArray.1stElementname.ToUpper()} is as follows.",
Weight= AdaptiveTextWeight.Bolder,
Size= AdaptiveTextSize.Large
},
new AdaptiveColumnSet()
{
Columns = new List<AdaptiveColumn>()
{
new AdaptiveColumn()
{
Items = new List<AdaptiveElement>()
{
new AdaptiveFactSet()
{
Facts = new List<AdaptiveFact>()
{
new AdaptiveFact()
{
Title="Short Description",
Value=JSONArray.2ndElementname
},
new AdaptiveFact()
{
Title="More Information",
Value ="[Click here to open the ticket in SNOW](https://service-now.com/JSONArray.3rdDElementname)"
}
},
Separator = true
}
}
}
}
}
},
});
Attachment attachment = new Attachment()
{
ContentType = AdaptiveCard.ContentType,
Content = card
};
return attachment;
It looks like you need to insert the data from the JSON object into your URL. Right now "JSONArray.3rdDElementname" is just rendering as part of the URL instead of pulling the value from the object. Try using string interpolation.
Value = $"[Click here to open the ticket in SNOW](https://service-now.com/{JSONArray.3rdDElementname})"
Here is more documentation on how to interpolation data into a string.
Glad this helped.

BotFramework: Passing additional values via SuggestedActions

I am currently working on a dialog (BotFramework 3.x), that asks the user a span of two numbers. The user should have the option to say "indifferent" if he does not care or it is open end.
So my approach is to have a variety of suggested actions plus an "indifferent" value. The ActionButton should show and write "indifferent" in the chat window but pass a specific int value to the backend:
if (actions != null)
message.SuggestedActions = new SuggestedActions()
{
Actions = new List<CardAction>(actions)
};
message.AttachmentLayout = AttachmentLayoutTypes.Carousel;
And this is how I build together the actions:
CardActions = new List<CardAction>();
for (int i = fromTo.from ?? MinValue; i <= MaxValue; i++)
{
CardActions.Add(new CardAction()
{
Title = i.ToString(),
Value = complexObject,
Text = i.ToString(),
DisplayText = i.ToString(),
Type = ActionTypes.PostBack
});
}
cardActions.Add(new CardAction()
{
Title = "indifferent",
Value = indifferentValue,
Text = "indifferent",
DisplayText = "indifferent"
Type = ActionTypes.PostBack,
});
I am able to get the value in the backend - that is not the problem. What is a problem though is, that the user is not shown hin answer. I want him to see, that he tapped "5" or "indifferent" in the chat history. With ActionTypes.PostBack this does not work. If I use ActionTypes.ImBack I am not able to use a complex JSON object as value - I simply don't get a response in the backend when tapping the suggestedAction. It only works with ActionTypes.ImBack if I use a plain value. But then the chat history shows the value of the action and not the text or displayText, which would make much more sense.
What am I overseeing here??
If I use ActionTypes.ImBack I am not able to use a complex JSON object as value - I simply don't get a response in the backend when tapping the suggestedAction.
To achieve your requirement: display user selection in chat window, you can specify ActionTypes.ImBack and serialize the specified object to a JSON string, like below.
CardActions.Add(new CardAction()
{
Title = i.ToString(),
//serializes to a JSON string
Value = JsonConvert.SerializeObject(complexObject),
Text = i.ToString(),
DisplayText = i.ToString(),
Type = ActionTypes.ImBack
});
Besides, to present buttons/options that the user can tap to provide input, you can also use rich cards or PromptDialog.Choice.
PromptDialog.Choice(
context: context,
resume: ChoiceReceivedAsync,
options: myoptions,
prompt: "Hi. Please Select an option:",
retry: "Selected option not avilabel . Please try again.",
promptStyle: PromptStyle.Auto,
descriptions: desforchoices
);
Test result:

How to use a confirmation button in Google Apps Script spreadsheet embedded scripts?

I have this Google Apps Script to send an email with a request to people I choose in a spreadsheet:
function sendRequestEmail() {
var data = SpreadsheetApp.openById(SPREADSHEET);
if(!employee_ID) {
employee_ID = getCurrentRow();
if (employee_ID == 1) {
var employee_ID = Browser.inputBox("VocĂȘ precisa selecionar um assistido?", "Choose a row or type its number here:", Browser.Buttons.OK_CANCEL);
}
}
// Fetch variable names
// they are column names in the spreadsheet
var sheet = data.getSheets()[0];
var columns = getRowAsArray(sheet, 1);
Logger.log("Processing columns =" + columns);
var employeeData = getRowAsArray(sheet, employee_ID);
Logger.log("Processing employeeData = " + employeeData);
// Assume first column holds the name of the person
var email2Send = "pythonist#example.com";
var title = "Request by email";
var name = employeeData[0];
var mother_name = employeeData[1];
var message = "Hi, I have a request for you, " + name + ", this is... example";
// HERE THE
// CONFIRMATION BUTTON!!!
MailApp.sendEmail(email2Send, title, message);
}
And, before sending the email, I want a confirmation button, something like this:
function showConfirmation(name, email2Send) {
var app = UiApp.createApplication().setHeight(150).setWidth(250);
var msg = "Do you confirm the request to " + email2Send + " about " + name + "?";
app.setTitle("Confirmation of request");
app.add(app.createVerticalPanel().add(app.createLabel(msg)));
var doc = SpreadsheetApp.getActive();
doc.show(app);
}
So, if user press OK, the app will execute the line MailApp.sendEmail(email2Send, title, message); and send an e-mail.
I have to admit my ignorance. I'm reading chapter 4 of the book "Google Apps Script" (Oreilly, by James Ferreira) on handlers. I've tried using an example provided in the documentation from Google (already deleted the code!). But I came across an error that I could not understand.
The code used were this sample:
var ui = DocumentApp.getUi();
var response = ui.prompt('Getting to know you', 'May I know your name?', ui.ButtonSet.YES_NO);
// Process the user's response.
if (response.getSelectedButton() == ui.Button.YES) ... DO THIS
I have some urgency in this simple project, so forgive-me for asking this question before research more for the answer (I'm searching for it while wating for the answer). So, how can I use a confirmation/cancellation button in this code?
The code snippet you showed is for document embedded UI, the equivalent (well... almost) class for spreadsheet context is Browser.MsgBox(prompt,buttons), see doc here, it will be simpler than create a Ui + a handler function... even if the layout and appearance are fairly basic it's easy and efficient.
In your code it becomes :
...
var confirm = Browser.msgBox('send confirmation','Are you sure you want to send this mail ?', Browser.Buttons.OK_CANCEL);
if(confirm=='ok'){ MailApp.sendEmail(email2Send, title, message)};
...

selected Picklist value not saving in dynamic CRM?

I have added javascript for reverse the items in the picklist (rating) to the opportunity entity. It is done. but when I am filling the data and saving it, it is not saving the selected item from the rating picklist to the database. What do I have to do?
var oField = crmForm.all.opportunityratingcode;
var items = oField.options.length;
var arrTexts = new Array(items);
var arrValues = new Array(items);
for(i=0;i<items;i++)
{
arrTexts[i]=oField.Options[i].Text;
arrValues [i]=oField.Options[i].DataValue;
}
for(i=0;i<=items;i++)
{
oField.DeleteOption(i);
}
for(j=items;j>0;j--)
{
var oOption1 =oField.Options;
oOption1.Text=arrTexts[j-1];
oOption1.DataValue= arrValues [j-1];
oField.AddOption(oOption1.Text,oOption1.DataValue);
alert(oOption1.DataValue);
}
Sounds like you need to add a .ForceSubmit in the onSave of the form. This forces CRM to save attribute data changes that you have made with JavaScript.
e.g.
crmForm.all.attribName.ForceSubmit = true;
Check the CRM SDK here: http://technet.microsoft.com/en-us/library/cc189831.aspx

Resources