https://i.stack.imgur.com/uq9Yv.png
https://i.stack.imgur.com/jaPaz.png
https://i.stack.imgur.com/SHIuS.png
How do I get 'number' parameter to clear and output the prompt 'say a number' when I say 'no'?
To clear parameters in a session for form filling, you have to set the parameter value in the session to null before transitioning back to a page with form filling.
There are two ways on how to set parameter values to null in a session:
Add the parameters that are needed to be cleared with a null value in the fulfillment parameter presets of an intent/condition route of a page.
a. In your case, you can add the “number” parameter with null value in the fulfillment parameter presets of your “No” intent route of your “Confirm Number” page.
b. When the “No” intent route of the “Confirm Number” page is triggered, the “number” parameter will be cleared in the session and will be transitioned back to the “Insert Number” Page to ask again for the number.
Set the parameter values to null through fulfillment webhooks. Below is a sample code for reference:
app.post("/clearnumber", async (request, response) => {
let params = request.body.sessionInfo.parameters; //get the current parameters in the session
let message = "\n\n number parameter has been cleared... ";
console.log("request body:" + request.body);
console.log(".....number........... :" + params.number);
params.number = null; // setting the number parameter to null
console.log("..after.resetting.number........... :" + params.number);
request.body.sessionInfo.parameters = params; //add the parameter changes in the sessionInfo that will be sent back to the agent
let fulfillmentResponse = {
fulfillmentResponse: {
messages: [{
text: {
text: []
}
}]
},
sessionInfo: request.body.sessionInfo
}; fulfillmentResponse.fulfillmentResponse.messages[0].text.text.push(message);
response.json(fulfillmentResponse);
});
As you can see in the screenshot below, the results are the same as using parameter presets in the console.
Related
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.
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:
I am not able to display records on my report.
Report Source: Group Approval(sysapproval_group) table
Condition:Sys Id - is one of - javascript: new GetMyGroupApprovals().getSysIds();
Script Include : MyGroupApproval
Note : Active is checked, Accesible is all application score & Client callable unchecked
var GetMyGroupApprovals = Class.create();
GetMyGroupApprovals.prototype = {
initialize: function() {
},
getSysIds : function getMyGroupMembers(){
var ga = new GlideRecord('sysapproval_group');
ga.addQuery('parent.sys_class_name', '=', 'change_request');
ga.query();
gs.log("TotalRecords1 Before:: " + ga.getRowCount());
var sysIdArray = [];
while(ga.next()){
sysIdArray.push(ga.sys_id);
}
return sysIdArray;
},
type: 'GetMyGroupApprovals'
};
Kindly note that I have to achieve with script approach. I am not able to get records on my report.
This line is probably causing unexpected behavior:
sysIdArray.push(ga.sys_id);
ga.sys_id returns a GlideElement object, which changes for each of the iterations in the GlideRecord, so the contents of sysIdArray will just be an instance of the same object for each row in the result set, but the value will just be the last row in the set.
You need to make sure you push a string to the array by using one of the following methods:
sysIdArray.push(ga.sys_id+''); // implicitly call toString
sysIdArray.push(ga.getValue('sys_id')); // return string value
Quick suggestion, you can use the following to get sys_ids as well:
sysIdArray.push(ga.getUniqueValue());
I'm creating an ASP.NET Core WebAPI that has a route with an optional parameter. In the return result I am embedding links to "previous" and "next" pages. I'm using Url.Link() to generate these links, but the link created is not generating a proper URL.
Example code:
[HttpGet("{page:int?}", Name = "GetResultsRoute")]
public IActionResult GetResults([FromQuery]int page = 0)
{
...
var prevUrl = Url.Link("GetResultsRoute", new { page = page - 1 });
var nextUrl = Url.Link("GetResultsRoute", new { page = page + 1 });
...
The URL generated will be something like:
"http://localhost:65061/api/results/1"
What I want is:
"http://localhost:65061/api/results?page=1"
What am I doing wrong here?
I think you are doing everything right here. It just MVC is able to match your [page] value in Url.Link to the route constraint HttpGet("{page:int?}", thus appending it as a part of the URL path, e.g. results/1
From the docs - Ambient values that don't match a parameter are ignored, and ambient values are also ignored when an explicitly-provided value overrides it, going from left to right in the URL. Values that are explicitly provided but which don't match anything are added to the query string.
In your case,
var prevUrl = Url.Link("GetResultsRoute", new { pageX = page - 1 });
would result in
http://localhost:65061/api/results?pageX=1
So ether append the query string parameter yourself, remove the constraint, or switch to MVC recommend format of URL, e.g. /api/results/xxx
I am building a Chrome extension which should write new rows into a Google Spreadsheet. I manage to read the sheet content but am not able to write an additional row. Currently my error is "400 (Bad Request)". Any idea what I am doing wrong here?
I have gone through the Google Sheets API documentation and other posted questions here but was not able to find any solution.
Here is the code which I use to GET the sheet content (this works):
function loadSpreadsheet(token) {
var y = new XMLHttpRequest();
y.open('GET', 'https://spreadsheets.google.com/feeds/list/spreadsheet_id/default/private/values?access_token=' + token);
y.onload = function() {
console.log(y.response);
};
y.send();
}
And this is the code I try to POST a new row (gives me "400 - Bad Request"):
function appendRow(token){
function constructAtomXML(foo){
var atom = ["<?xml version='1.0' encoding='UTF-8'?>",
'<entry xmlns="http://www.w3.org/2005/Atom" xmlns:gsx="http://schemas.google.com/spreadsheets/2006/extended">',//'--END_OF_PART\r\n',
'<gsx:name>',foo,'</gsx:name>',//'--END_OF_PART\r\n',
'</entry>'].join('');
return atom;
};
var params = {
'body': constructAtomXML("foo")
};
url = 'https://spreadsheets.google.com/feeds/list/spreadsheet_id/default/private/full?alt=json&access_token=' + token;
var z = new XMLHttpRequest();
z.open("POST", url, true);
z.setRequestHeader("Content-type", "application/atom+xml");
z.setRequestHeader("GData-Version", "3.0");
z.setRequestHeader("Authorization", 'Bearer '+ token);
z.onreadystatechange = function() {//Call a function when the state changes.
if(z.readyState == 4 && z.status == 200) {
alert(z.responseText);
}
}
z.send(params);
}
Note: spreadsheet_id is a placeholder for my actual sheet ID.
Follow the protocol and to make it work.
Assume spreadsheet ID is '1TCLgzG-AFsERoibIUOUUE8aNftoE7476TWYKqXQ0xb8'
First use the spreadsheet ID to retrieve list of worksheets:
GET https://spreadsheets.google.com/feeds/worksheets/1TCLgzG-AFsERoibIUOUUE8aNftoE7476TWYKqXQ0xb8/private/full?alt=json
There you can read list of worksheets and their IDs. Let use the first worksheet from the example. You'll find its id in feed > entry[0] > link array. Look for "rel" equal 'http://schemas.google.com/spreadsheets/2006#listfeed'.
In my example the URL for this worksheet is (Worksheet URL): https://spreadsheets.google.com/feeds/list/1TCLgzG-AFsERoibIUOUUE8aNftoE7476TWYKqXQ0xb8/ofs6ake/private/full
Now, to read its content use:
GET [Worksheet URL]?alt=json
Besides list-row feed, you'll also find a "post" URL which should be used to alter spreadsheet using list-row feed. It's the one where "rel" equals "http://schemas.google.com/g/2005#post" under feed > link.
It happens that it is the same URL as for GET request. In my case: https://spreadsheets.google.com/feeds/list/1TCLgzG-AFsERoibIUOUUE8aNftoE7476TWYKqXQ0xb8/ofs6ake/private/full. Just be sure to not append alt=json.
Now, to insert a new row using list-row feed you need to send POST with payload which is specified in docs. You need to send a column name prefixed with "gsx:" as a tag name. However it may not be the same as the column name in the spreadsheet. You need to remove any white-spaces, make it all lowercase and without any national characters. So to make your example work you need to replace <gsx:Name> with <gsx:name>.
Before the change you probably had the following payload message:
Blank rows cannot be written; use delete instead.
It's because the API didn't understand what the "Name" is and it just dropped this part of entry from the request. Without it there were no more items and the row was blank.
Alternatively you can read column names from the GET response. Keys from objects in feed > entry array that begins with gsk$ are columns definitions (everything after $ sign is a column name).
=================================================================
EDIT
To answer a question from the comments.
I've changed two things from your example:
function appendRow(token){
function constructAtomXML(foo){
var atom = ["<?xml version='1.0' encoding='UTF-8'?>",
'<entry xmlns="http://www.w3.org/2005/Atom" xmlns:gsx="http://schemas.google.com/spreadsheets/2006/extended">',
'<gsx:name>',foo,'</gsx:name>',
'</entry>'].join('');
return atom;
};
/*
var params = {
'body': constructAtomXML("foo")
};
*/
var params = constructAtomXML("foo");
url = 'https://spreadsheets.google.com/feeds/list/'+spredsheetId+'/default/private/full?alt=json&access_token=' + token;
var z = new XMLHttpRequest();
z.open("POST", url, true);
z.setRequestHeader("Content-type", "application/atom+xml");
z.setRequestHeader("GData-Version", "3.0");
z.setRequestHeader("Authorization", 'Bearer '+ token);
z.onreadystatechange = function() {//Call a function when the state changes.
if(z.readyState == 4 && z.status == 200) {
alert(z.responseText);
}
}
z.send(params);
}
1) <gsx:Name> to <gsx:name>. Without it you'll receive an error.
2) params object should be a String! Not an object with some 'body' key. You just need to pass a value you want to send to the server.