AdaptiveFact() for having a dynamic value as URI - botframework

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.

Related

How to add a custom payload to PromptDialog.Choice

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.

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 get all controls from tab

I need to get all controls from a tab on my form, I tried to use this option I found online but it didn't work ideas anyone?
var tabs = Xrm.Page.ui.tabs.get();
var fieldList = new Array();
for (var i in tabs)
{
var tab = tabs[i];
if(tab.getName() == "tab_2")
{
tab.sections.forEach(function (section, sectionIndex)
{
section.controls.forEach(function (control, controlIndex)
{
switch (control.getControlType())
{
case "standard":
case "lookup":
case "optionset":
var attribute = control.getAttribute();
if (attribute != null)
{
fieldList.push(attribute.getName());
}
break;
}
});
});
}
}
}
I just tried the code and it works.
It looks for a tab called tab_2 and then gets all controls within that tab and adds the control.name to an array (fieldList)
The result is a simple array of control names. When I ran this on my Contact form (with the Tab Name adjusted) I got the following results:
[
"fullname",
"nickname",
"employeeid",
"jobtitle",
"parentcustomerid",
"emailaddress1",
"telephone2",
"telephone1",
"mobilephone",
"fax",
"address1_composite",
"preferredsystemuserid",
"familystatuscode",
"spousesname",
"birthdate",
"description",
"ownerid",
"createdon"
]
If this is not working for you, I suggest the following:
Check the name of the CRM Tab
Depending on where you are running this (e.g. in a web resource or developer console) you may need to change the code context

How do you update objects in a Parse.com database using Xamarin?

I have an online Parse.com database and I can create objects and query them but not update. In the Xamarin section of the Parse.com documentation it only tells you how to update an object directly after you've created it which I don't want to do. I tried adapting what the documentation says for other platforms but it hasn't worked, I have also tried querying the database and entering the new field values directly after that but it treats them as separate functions. Does anyone have any help?
Parse.com documentation:
// Create the object.
var gameScore = new ParseObject("GameScore")
{
{ "score", 1337 },
{ "playerName", "Sean Plott" },
{ "cheatMode", false },
{ "skills", new List<string> { "pwnage", "flying" } },
};
await gameScore.SaveAsync();
// Now let's update it with some new data. In this case, only cheatMode
// and score will get sent to the cloud. playerName hasn't changed.
gameScore["cheatMode"] = true;
gameScore["score"] = 1338;
await gameScore.SaveAsync();
What I tried most recently:
ParseQuery<ParseObject> query = ParseObject.GetQuery("cust_tbl");
IEnumerable<ParseObject> customers = await query.FindAsync();
customers["user"] = admin;
record["score"] = 1338;
await record;
In your example, you are getting an list (IEnumerable) of objects instead of single object. Instead, try something like this:
ParseQuery<ParseObject> query = ParseObject.GetQuery("cust_tbl");
// you need to keep track of the ObjectID assigned when you first saved,
// otherwise you will have to query by some unique field like email or username
ParseObject customer = await query.GetAsync(objectId);
customer["user"] = admin;
customer["score"] = 1338;
await customer.SaveAsync();

Google SpreadSheet Api, Putting List-Based Feeds Which Starts on Specific Cell

As seen as Google Api, i can easily put my data into a spreadsheet as below :
namespace MySpreadsheetIntegration
{
class Program
{
static void Main(string[] args)
{
SpreadsheetsService service = new SpreadsheetsService("MySpreadsheetIntegration-v1");
// TODO: Authorize the service object for a specific user (see other sections)
// Instantiate a SpreadsheetQuery object to retrieve spreadsheets.
SpreadsheetQuery query = new SpreadsheetQuery();
// Make a request to the API and get all spreadsheets.
SpreadsheetFeed feed = service.Query(query);
if (feed.Entries.Count == 0)
{
// TODO: There were no spreadsheets, act accordingly.
}
// TODO: Choose a spreadsheet more intelligently based on your
// app's needs.
SpreadsheetEntry spreadsheet = (SpreadsheetEntry)feed.Entries[0];
Console.WriteLine(spreadsheet.Title.Text);
// Get the first worksheet of the first spreadsheet.
// TODO: Choose a worksheet more intelligently based on your
// app's needs.
WorksheetFeed wsFeed = spreadsheet.Worksheets;
WorksheetEntry worksheet = (WorksheetEntry)wsFeed.Entries[0];
// Define the URL to request the list feed of the worksheet.
AtomLink listFeedLink = worksheet.Links.FindService(GDataSpreadsheetsNameTable.ListRel, null);
// Fetch the list feed of the worksheet.
ListQuery listQuery = new ListQuery(listFeedLink.HRef.ToString());
ListFeed listFeed = service.Query(listQuery);
// Create a local representation of the new row.
ListEntry row = new ListEntry();
row.Elements.Add(new ListEntry.Custom() { LocalName = "firstname", Value = "Joe" });
row.Elements.Add(new ListEntry.Custom() { LocalName = "lastname", Value = "Smith" });
row.Elements.Add(new ListEntry.Custom() { LocalName = "age", Value = "26" });
row.Elements.Add(new ListEntry.Custom() { LocalName = "height", Value = "176" });
// Send the new row to the API for insertion.
service.Insert(listFeed, row);
}
}
}
If i wrote "firstname" into the A1 and "lastname" into the B1, this is working, but i want to start this function ie. F21.
I mean, my localname firstname is in the cell F21 and i want google api to put my data "JOE" into F22 cell and ...
How can i do that ?
Regards.
CellFeed will do that, but list feed is more like an SQL style database table.
Suggest you use CellFeed or update your data SQL style, in whole rows.
I gave up with list feed when I discovered how little control you have over the position of the data.
Good examples:
CellFeed
https://gdata-java-client.googlecode.com/svn-history/r51/trunk/java/sample/spreadsheet/cell/CellDemo.java
ListFeed
https://gdata-java-client.googlecode.com/svn-history/r51/trunk/java/sample/spreadsheet/list/ListDemo.java

Resources