How to ask choices from user in multi line? - botframework

I'm asking user to select from multiple options as follows
var reportData = {
"Report A Traffic Violation": {
intent: 'report_a_traffic_violation'
},
"Report a Lost Property": {
intent: 'report_a_traffic_violation'
},
"Describe Incident": {
intent: '/describeIncident'
}
};
builder.Prompts.choice(session, "please select from options", reportData);
But the options shows to the user in single line. How can I show the options to the user using multiple lines as follows?
option one
option two
option three

Node.js
Based on the code you provided I suppose you are using node.js
You may have a look to the Contoso-Flowers sample provided by Microsoft, in its settings function: code here and preview with the list visible here.
Here is how they are handling the list:
var SettingChoice = {
Email: 'edit_email',
Phone: 'edit_phone',
Addresses: 'edit_addresses',
Cancel: 'cancel'
};
var lib = new builder.Library('settings');
lib.dialog('/', [
// Display options
function (session) {
builder.Prompts.choice(session, 'settings_intro', [
session.gettext(SettingChoice.Email),
session.gettext(SettingChoice.Phone),
session.gettext(SettingChoice.Addresses),
session.gettext(SettingChoice.Cancel)
]);
},
Did you try to use an array like here?
C#
For those building their bots in C#, you just have to specify your PromptStyle to PromptStyle.PerLine

For js : Although '\n' is the universal newline characters.
For c# SDK : Environment.NewLine.

Try adding the listStyle parameter:
builder.Prompts.choice(
session,
"please select from options",
reportData,
{listStyle: builder.ListStyle.list}
);
More information on list styles in Bot Framework documentation: https://learn.microsoft.com/en-us/bot-framework/nodejs/bot-builder-nodejs-dialog-prompt

Related

Mailchimp API Node - create campaign for list based on tags

I'm making an async api request with a firebase cloud function to create a campaign within mailchimp for a specific set of users from a list. I read in the documentation that this can be done with tags this way I can build my own structure. I'm building a donation system for a nonprofit and would like the tag to represent the name of a client who is currently being donated to.
Below is my firebase function. I'm stuck at the segment_opts object. I want to define a segment based on whether the list member has a tag equivalent my clients name.
The doc says segment_opts is "An object representing all segmentation options. This object should contain a saved_segment_id to use an existing segment, or you can create a new segment by including both match and conditions options.". I don't have any other segments set up so I figured I'd create a new one that specifies the tags to contain the client's name.
This post helped me get to this point. Stackoverflow post
I now see that condition is supposed to be a Segment Type but in the dropdown I don't see an option for Tags. Here is a link to the documentation reference. Reference
const response = await mailchimp.post('/campaigns', {
type: 'regular',
recipients: {
list_id: functions.config().mailchimp.test,
segment_opts: {
"match": "any",
"conditions": match: 'any',
conditions: [
{
condition_type: 'StaticSegment',
field: 'static_segment',
op: 'static_is',
value: ??? (Int),
},
],
}
},
});
For now I removed segment_opts and will settle on sending campaign to entire list until I figure out how to segment by tags. This version works and creates a campaign within my mailchimp account and from the UI I can see the segment options offered in the documentation but don't see an option to filter by tags
const response = await mailchimp.post('/campaigns', {
type: 'regular',
recipients: {
list_id: functions.config().mailchimp.test,
},
settings: {
subject_line: `${firstName} has been funded!`,
preview_text: `$${goal} has been raised for ${firstName}.`,
title: `${firstName} has been funded`,
from_name: 'Organization name',
reply_to: 'org_email#gmail.com',
},
});
Here is a screenshot of the dropdown options in Mailchimp dashboard.
This is what I have for my campaign segment options. Here I'm checking for two conditions. Is the SITE merge tag = the site variable I pass in, and also does the member belong to the tag/segment called tagName. However, I can't pass a tagName, only a tagId which I lookup beforehand.
'segment_opts':
{
'match': 'all',
'conditions': [
{
'condition_type': 'TextMerge',
'field': 'SITE',
'op': 'is',
'value': site
},
{
'condition_type': 'StaticSegment',
'field': 'static_segment',
'op': 'static_is',
'value': tagId
}
]
}
To get the tagId I use this Python function:
tagId, segments = self.getSegmentIdFromTagName(tagName)
This is the Python code to get the tagId from the tagName, which gets all the Segments/Tags from the system and then looks for the name you pass in:
def getSegmentIdFromTagName(self,reqTagName,segments=None):
audienceId = self.audienceId
reqId = None
if not segments:
segments = self.mcClient.lists.segments.all(list_id=audienceId,get_all=True)
for segment in segments['segments']:
segName = segment['name']
segId = segment['id']
if segName == reqTagName:
reqId = segId
break
return reqId,segments

Semantic-ui form rule only if option is selected

I am using semantic ui and am trying to do some form validation with it.
The scenario I have is the user has 2 options: email,or phone app verrifcation. They select one of the options and enter whatever in a text field then click submit.
However I am not sure how to do rules on this with semantic UI.
I know if I wanted to check if it was blank I could do something like this:
$('.ui.form')
.form({
fields: {
CODE: {
identifier: 'code',
rules: [
{
type : 'empty',
prompt : 'Please enter your verification code'
}
]
}
} } );
However I would like additional rules based upon which option is selected. I have javascript that currently tells me the value of what is selected, and is updated on change. Unsure how to add it into the rules though, so that I can be like -- If phone was select, must be exactly 6 chars long, or IF email was selected, must be 18 chars long (different lengths for different option).
Is there a way to have conditional rules like this? Closet I could find was:
depends: 'id'
Which checks to ensure it is not empty.
Does anyone know how to have conditional rules such as this based on another form element? I am using the most recent version of Semantic-UI
You can do so by adding custom rules.
$.fn.form.settings.rules.atLeastOne = function (value, fields) {
fieldsToCompare = fields.split(",")
if (value) {
// current input is not empty
return true
} else {
// check the other input field(s)
// atLeastOne is not empty
atLeastOne = false
for (i = 0; i < fieldsToCompare.length; i++) {
// gets input based on id
if ($("#" + fieldsToCompare[i]).val()) {
atLeastOne = true
}
}
return atLeastOne
}
}
$(".ui.form").form({
fields: {
number:{
identifier: "number",
rules: [{
type: "exactLength[6]",
prompt: "number has to be 6 chars long"
}, {
// include the input fields to check atLeastOne[email, address, ...]
type: "atLeastOne[email]",
prompt: "Please provide an email or a number"
}]
},
email: {
identifier: "email",
rules: [{
type: "exactLength[18]",
prompt: "email has to be 18 chars long"
}, {
type: "atLeastOne[number]",
prompt: "Please provide an email or a number"
}]
}
}
});
Note that the function uses the input id as the identifier and not the input name. You might also want to look at optional fields.

Can't find cache key in Cache redirect

When I start my react-native app I wan't to query "everything" for an offline experience.
So I
query all {
groups {
...GroupF
}
persons {
...PersonF
}
}${PERSON_ITEM}${GROUP_ITEM}
PersonF and GroupF are fragments.
The first view has a list of groups, each person can belong to a group. When the user clicks on an group the query looks like:
persons($group: ID) {
persons(group: $group) {
...PersonsF
}
}${PERSON_ITEM}
But my cacheRedirects just does not reflect the same data as is returned.
I know this because i console.log out the response in my component wrapper (it looks excellent here)
but in my
const cache = new InMemoryCache({
cacheRedirects: {
Query: {
persons: (_, args, {getCacheKeys}) => {
// I have tried everything here but nothing maps correctly
// I have tried getCacheKey({__typename: 'Person', id: args.group})
// I have tried following the apollo documentation
// No luck, it just can't find the group
// Using the chrome dev tools I don't see persons having groups
const a = getCacheKey({__typename: 'Person', id: args.group});
// Console.log(a) is:
// {generated: false, id: "Person:9", type: "id", typename "Person"}
}
}
}
});
Do you have any suggestions on how I can write a proper cache redirects persons query?
Help really really really appreciated
|1| https://www.apollographql.com/docs/react/advanced/caching.html#cacheRedirect
This was caused by the fact we used the id field in the Person, since we stoped using the field it works perfectly.

Adding a new text field pGina

I need to have a third text field besides the Username and Password fields commonly provided by pGina in windows logon UI. I'll be using this field to receive a password to be checked against a one-time password service running in the background.
How can I add the new field in the pGina logon UI and pass its value to a services running in the background?
Any help is appreciated.
I finally managed to to this.
As pointed out by #Alexander, I edited the TileUiLogon.h and TileUiTypes.h and followed the pattern to add a third field to the logon screen.
Then, I edited Credential::Initialize and added a new line in the "for" loop, following the same pattern for the "password" field (I'm not sure exactly what happens there, but since we're complying with the existing pattern, we don't care as long as the content of the new field is collected by the code similar to the other fields).
Since I didn't want to go through changing all the function signatures and mess with the code, I simply edited the Credential::ProcessLoginAttempt function and concatenated the content of the new field with that of the password field and embedded a custom delimiter to allow me separate the two strings in the following steps. After hitting the submit button, the fields data, prior to the real serialization, are initially sent to a pipe on the other end of which the pGina service is listening (pGinaTransactions.cpp). This service sends the login information to its plugins. I then edited the "Sample" plugin already provided and separated the two concatenated strings, immediately filling the password attribute of the object with the real password provided by the user, since these data will be sent back to the credential provider through pipe for further processing. If the plugin returns success, the password is then used for real serialization and logon attempt.
I have probably missed a few details, which you are very welcome to ask in the comments.
I think you must modify TileUiLogon.h file:
namespace pGina
{
namespace CredProv
{
// Fields for unlock and logon:
typedef enum LOGON_UI_FIELD_ID
{
LUIFI_TILEIMAGE = 0,
LUIFI_MOTD = 1,
LUIFI_USERNAME = 2,
LUIFI_PASSWORD = 3,
LUIFI_OTP = 4,
LUIFI_SUBMIT = 5,
LUIFI_STATUS = 6,
LUIFI_NUM_FIELDS = 7,
};
static const UI_FIELDS s_logonFields =
{
LUIFI_NUM_FIELDS, // Number of fields total
LUIFI_PASSWORD, // Field index which submit button should be adjacent to
LUIFI_USERNAME, // Username field index value
LUIFI_PASSWORD, // Password field index value
LUIFI_STATUS, // Status field
{
// when to display, style, field id, type, name data source value callback
{ { CPFS_DISPLAY_IN_BOTH, CPFIS_NONE }, { LUIFI_TILEIMAGE, CPFT_TILE_IMAGE, L"Image" }, SOURCE_NONE, NULL, NULL },
{ { CPFS_DISPLAY_IN_BOTH, CPFIS_NONE }, { LUIFI_MOTD, CPFT_SMALL_TEXT, L"MOTD" }, SOURCE_DYNAMIC, L"pGina", NULL },
{ { CPFS_DISPLAY_IN_SELECTED_TILE, CPFIS_FOCUSED }, { LUIFI_USERNAME, CPFT_EDIT_TEXT, L"Username" }, SOURCE_NONE, NULL, NULL },
{ { CPFS_DISPLAY_IN_SELECTED_TILE, CPFIS_NONE }, { LUIFI_PASSWORD, CPFT_PASSWORD_TEXT, L"Password" }, SOURCE_NONE, NULL, NULL },
{ { CPFS_DISPLAY_IN_SELECTED_TILE, CPFIS_NONE }, { LUIFI_OTP, CPFT_PASSWORD_TEXT, L"OTP" }, SOURCE_NONE, NULL, NULL },
{ { CPFS_DISPLAY_IN_SELECTED_TILE, CPFIS_NONE }, { LUIFI_SUBMIT, CPFT_SUBMIT_BUTTON, L"Submit" }, SOURCE_NONE, NULL, NULL },
{ { CPFS_DISPLAY_IN_BOTH, CPFIS_NONE }, { LUIFI_STATUS, CPFT_SMALL_TEXT, L"Status" }, SOURCE_STATUS, L"Status", NULL },
}
};
}
}
and other related files like pGinaTransactions.h and so on to handle new field. ;-)
As far as i know (if you're on Vista or above), you gonna have to make your own Credential Provider and register it.
For the interaction with the service, i'd say it depends wether it's running in local or on a distant server. Anyway, that's probably the easy part of the work.
UPDATE : I don't know pGina like AT ALL. But you should look at gina.rc (line 93) under DIALOGS. Seems to be an interesting place to begin.
Try to add a custom EDITEXT (by the way, lots of IDE most likely have a visualizor for those resources. I know that Visual Studio is one of them as i already experienced it.)
Visualizor and resource.h --> /!\ This is a screenshot of what it looks like and the resource.h.
//Third TEXTEDIT I just added
EDITTEXT IDC_CUSTOM_PASSWORD_TXT, 146, 88, 183, 12, ES_PASSWORD | ES_AUTOHSCROLL

Type error with internationalization feature of sails.js based on i18n

I'm trying to use the internationalization feature of sails based on i18n.
In my controller it works well. However, I would like to setup this in my model definition.
Please see the code below:
module.exports = {
attributes: {
name:{
type:'string',
required:true,
displayName: sails.__("test")
},
....
Unfortunately it does not work. I have the error below:
displayName: sails.__("test")
^
TypeError: Object [a Sails app] has no method '__'
Would you have an idea?
Any help will be very much appreciated.
Thanks,
displayName: sails.__("test")
You are trying to invoke the internationalization function statically; that is, you're seeing the error because you're running that function the moment your .js file is require()d by node.js, and before sails has finished loading.
There are two ways you can go about solving this problem.
1. Translate the value on each query
If you'd like to store the original value of displayName, and instead internationalize it each time you query for the model, you can override toJSON().
Instead of writing custom code for every controller action that uses a particular model (including the "out of the box" blueprints), you can manipulate outgoing records by simply overriding the default toJSON function in your model.
For example:
attributes: {
name:{
type:'string',
required:true,
},
getDisplayName: function () {
return sails.__(this.name);
},
toJSON: function () {
var obj = this.toObject();
obj.displayName = sails.__(this.name);
return obj;
},
...
}
2. Translate the value before create
You can use the Waterline Lifecycle Callbacks to translate the value to a particular language before the model is saved to the databas
Sails exposes a handful of lifecycle callbacks on models that are called automatically before or after certain actions. For example, we sometimes use lifecycle callbacks for automatically encrypting a password before creating or updating an Account model.
attributes: {
name:{
type:'string',
required:true,
},
displayName: {
type: 'string'
},
...
},
beforeCreate: function (model, next) {
model.displayName = sails.__(model.name);
next();
}
This internationalized the value of displayName will now be set on your model before it is inserted into the database.
Let me know how this works out for you.
Your solution is interesting. However, my wish would be to have a display name for each properties.
module.exports = {
attributes: {
name:{
type:'string',
required:true,
displayName: "Your great name"
},
adress:{
type:'string',
required:true,
displayName: "Where do you live?"
},
....
So is there a simple or clean solution to apply sails.__( foreach properties display name of the attribute?
Thanks,

Resources