How can I change a button's emoji without resetting the component? - javascript

I am trying to change button's current emoji to a new one like this:
// Initializing button
const row = new MessageActionRow()
.addComponents(
new MessageButton()
.setCustomId('play_pause')
.setEmoji('⏸')
.setStyle('PRIMARY')
)
// Button was sent to Discord
await message.channel.send({
components: [row]
});
// Changing content of a button
row.components[0].setEmoji('▶');
But in the Discord nothing changes.
When I call console log, I get this:
MessageButton {
type: 'BUTTON',
label: null,
customId: 'play_pause',
style: 'PRIMARY',
emoji: { animated: false, name: '▶', id: null },
url: null,
disabled: false
}
So as I get it, I need to resend the button for it to change.
But can I somehow change the content without resending it?

It is not possible to edit any of a <MessageButton>'s properties without re-setting a <MessageActionRow>'s components.

Related

Slack API : how to update a user message from a button in ephemeral message

I exposed to you my problem with ephemeral message and update of user message
A simplified user case can :
when you write "hi" in a channel, that triggers an ephemeral message with a button "click", and when you click that button, it updates your first "hi" message, to "goodbye" for instance.
This is the code I tried. Unfortunatly, I think I have the wrong message_ts for the update. It seems to be the message_ts of the ephemeral message. Not the one of the original message. What do you think about it?
Have you an idea about how to achieve my goal?
const { WebClient } = require("#slack/web-api");
const slack_bot_token = process.env.SLACK_BOT_TOKEN;
const signing_secret = process.env.SLACK_SIGNING_SECRET;
const webClient = new WebClient(process.env.SLACK_BOT_TOKEN);
const { App } = require("#slack/bolt");
const app = new App({
token: slack_bot_token,
signingSecret: signing_secret,
});
app.message("hi", async ({ message, channel, say }) => {
// Respond to action with an ephemeral message
let channelID = message.channel;
let userID = message.user;
let ts = message.timestamp;
await webClient.chat.postEphemeral({
channel: channelID,
user: userID,
text: `👋 Hi <#${message.user}>`,
blocks: [
{
type: "section",
text: {
type: "mrkdwn",
text: `👋 Hey <#${message.user}>`,
},
accessory: {
type: "button",
text: {
type: "plain_text",
text: "Click me",
emoji: true,
},
action_id: "click",
},
},
],
});
});
// when the button with action_id "click" is clicked, the ephemeral message is discarded, and the user message is updated
app.action("click", async ({ ack, body, client, respond }) => {
// Acknowledge action request before anything else
await ack();
let channelID = body.channel.id;
let userID = body.user.id;
let message_ts = body.container.message_ts;
// erase original ephemeral message
respond({
response_type: "ephemeral",
text: "",
replace_original: true,
delete_original: true,
});
// update the original "hi" message
console.log (body.container);
webClient.chat.update({
token: slack_bot_token,
channel: body.container.channel_id,
ts: body.container.message_ts,
text: "goodbye",
replace_original: true,
delete_original: true,
});
});
(async () => {
// Start your app
await app.start(process.env.PORT || 3000);
console.log("⚡️ Bolt app is running!!");
})();
Thanks for your help
You're right that the message_ts you're trying to use right now is not the correct one. You'll need to save the message_ts of the original "hi" message instead.
You can do that in a number of ways, one would be to use a database, store the message_ts value and retrieve it when you need it again. However, if you want to avoid doing that, a neat thing you can do is set the value of the button you're generating in the ephemeral message as the message_ts of the original message.
// Keep in mind I've removed the code that isn't relevant
app.message("hi", async ({ message, channel, say }) => {
...
let ts = message.timestamp;
await webClient.chat.postEphemeral({
...
type: "button",
text: {
type: "plain_text",
text: "Click me",
emoji: true,
},
action_id: "click",
value: `${ts}` // <- store the message_ts here
},
},
],
});
});
So then in the response to the users button click, you'll receive a payload which will, among other things, contain the value that you set earlier when you generated the button. You can then use this value to update the original message, as you are doing right now.
An example of action response payload: https://api.slack.com/reference/interaction-payloads/block-actions#examples

How to update an array field on mongodb by pushing it if the element is not present and if it is present update it?

I am working on a IT ticketing system where every time a new comment or a note has been added to a ticket a notification needs to be send to the user who is following the ticket. Below code only inserts new ticket in list of tickets followed by the user if it is not already present, however if it is present it ignores it. What I need to do is if the ticket that has just been updated is already present, change clicked field to false. In my application's frontend, when user clicks the notification icon it will change clicked to TRUE but when a new comment is added clicked needs to be changed to FALSE so that the user gets notification that comment has been added to the same ticket. How do I go about achieving it?
const ReqNotificationSchema = new Schema({
user: { type: Schema.Types.ObjectId, ref: "User" },
notifications: [
{
request: { type: Schema.Types.ObjectId, ref: "Request" },
clicked: { type: Boolean, default: false },
},
],
});
if(updated){
await ReqNotificationModel.findOneAndUpdate(
{
user: follower.user,
"notifications.request": { $ne: updated._id },
},
{
$push: { notifications: { request: updated._id, clicked: false } },
},
{ new: true }
);
}
I wasn't able to do it in one step , so I tried in a 2 step approach.
const notification = await ReqNotificationModel.findOne({
user: follower.user,
});
let index = notification.notifications
.map((obj) => obj.request.toString())
.indexOf(updated._id.toString());
notification.notifications[index].clicked = false;
await notification.save();
});

Can I give a link in standard message box in SAP UI5?

Is it possible to give a link instead of a message in standard message box in sap ui5? I want to navigate to another view on the click of that link. Is it possible to achieve without creating a new fragment and adding something in the standard message box?
The sap.m.MessageBox does not allow links, but the use of custom actions. Just take a look at the sample Error with custom action. Maybe this will help you.
I had the same problem and found the following solution:
if (!this.oSuccessMessageDialog) {
this.oSuccessMessageDialog = new sap.m.Dialog({
type: sap.m.DialogType.Message,
title: "Success",
state: sap.ui.core.ValueState.Success,
content: [
new sap.m.Text({ text: "Click on\u00a0" }),
new sap.m.Link({
text: "this",
emphasized: true,
press: <your_handler>
}),
new sap.m.Text({ text: "\u00a0Link." })
],
beginButton: new sap.m.Button({
type: sap.m.ButtonType.Emphasized,
text: "OK",
press: function () {
this.oSuccessMessageDialog.close();
}.bind(this)
})
});
}
this.oSuccessMessageDialog.open();

How to add custom data to ChoicePrompt with ListStyle.heroCard

I have a ChoicePrompt with style ListStyle.heroCard as follow:
import {ChoicePrompt, ListStyle} from 'botbuilder-dialogs';
import {PromptValidator} from 'botbuilder-dialogs/src/prompts/prompt';
import {FoundChoice} from 'botbuilder-dialogs/src/choices/findChoices';
export class HeroCardChoicePrompt extends ChoicePrompt{
constructor(dialogId: string, validator?: PromptValidator<FoundChoice>, defaultLocale?: string){
super(dialogId, validator, defaultLocale)
this.style = ListStyle.heroCard
}
}
Then I added this choice object:
choices.push({
action: {
text: 'Lolipop',
displayText: 'Lolipop',
channelData: 'Lolipop',
type: 'postBack',
title: 'Lolipop',
value: 'Lolipop',
},
value: 'Can you please help me to manage...',
synonyms: []
},)
How do I get the data 'Lolipop' in my code when the user clicks on the choice?
When I check the JSON object received by the client in the bot emulator, I do not see the data 'Lolipop' at all.
Using ListStyle.heroCard makes the prompt use ChoiceFactory.heroCard to generate the card. You can see in the source code that ChoiceFactory.heroCard doesn't use the actions in the choices and instead just creates imBack actions:
const buttons: CardAction[] = choices.map(choice => ({
title: choice.value,
type: ActionTypes.ImBack,
value: choice.value
} as CardAction));
If you want to supply custom actions in your prompt then you'll need to create your own hero card and supply it as the prompt field of your prompt options and use ListStyle.none. It's unclear why you'd want to do that because the actions generated by ChoiceFactory will match the available choices in the choice prompt so there's no need for the activity to have a hidden value.

EXTJS + Updating a store with the database ID after saving a grid

I'm trying to learn how to use the EXTJS grids for some simple CRUD operations over a table in a admin app.
I have a simple grid that allows someone to edit users, the store is defined as:
var userDataStore = new Ext.data.Store({
id: 'userDataStore',
autoSave: false,
batch: true,
proxy: new Ext.data.HttpProxy({
api: {
read: '/Admin/Users/All',
create: '/Admin/Users/Save',
update: '/Admin/Users/Save'
}
}),
reader: new Ext.data.JsonReader(
{
root: 'Data',
idProperty: 'ID',
totalProperty: 'total',
successProperty: 'success',
messageProperty: 'message'
}, [
{ name: 'ID', type: 'string', allowBlanks: false },
{ name: 'NT_ID', type: 'string', allowBlank: false },
{ name: 'EMail', type: 'string', allowBlank: false },
{ name: 'Name', type: 'string', allowBlank: false },
{ name: 'Enabled', type: 'bool', allowBlank: false },
{ name: 'CurrentRoleCode', type: 'string', allowBlank: false}]
),
writer: new Ext.data.JsonWriter(
{
encode: false,
writeAllFields: true,
listful: true
})
});
This is bound to a grid, and I am able to load and save users without issue. The save button looks like this:
var saveButton = new Ext.Button({
text: 'Save',
disabled: true,
handler: function() {
userDataStore.save();
pageState.ClearDirty();
saveButton.disable();
}
});
However, when creating a new user, the JSON POST for the user is posted to the same REST service end point as "Update", with the only difference being that no ID value is posted (as one is only set in the store when loading from the server).
This works, and I am able to create users.
The save REST service emits back the created row with the new database ID, and I was under the assumption that EXTJS would automatically bind the new generated database ID to the row. This allows the user to further edit that row, and cause an update instead of a insert.
Instead, the row continues to have a blank user ID, so an additional save creates another new user.
So either:
EXTJS is supposed to resolve generated row ID's automatically and I am just doing something wrong.
I am supposed to manually reload the grid after each save with an additional REST call.
I've been looking at EXTJS documentation and forums, but I am unclear on the proper approach.
Can someone clarify?
EDIT: I tried returning Success = True in JSON to match the SuccessProperty, however this still didn't seem to work.
EDIT #2: So far the only thing I've found that works is doing "userDataStore.reload()" after saving, however because I was returning the contents of the store back after saving, I was hoping that EXTJS would understand that and update the row values.
I've got an idea that may help you. Let't suppose that user added a new
record in grid, in that moment add a new property newRecOrderNo to the record to
identify the record after response. When user will post data to server after
inserting you must get a new ID and associate it to newRecOrderNo
(like Map<Integer,Integer>). Then return json object like that :
{
success : true,
newIdes : {
1 : 23,
2 : 34
}
}
Then when you get response do set proper IDs to records:
userDataStore.each(function(rec){
if(rec.data.newRecOrderNo){
rec.data.ID = response.newIdes[rec.data.newRecOrderNo];
delete rec.data.newRedOrderNo;
}
})
})
Yes, it sets id (and also other fields, if server returns modified values of them), if create ajax backend returns record with set id, at least in extjs 4.1. You should return inserted record, with id set, under 'root' key as json dictionary, in this example root is 'Data', i.e.:
{
"Data": {
"ID": 8932,
"NT_ID": 28738273,
...
"CurrentRoleCode": "aaa",
},
"success": true
}
You need reload store with new params in savebtn handler
like
store.reload();
of course you can add more params to load action

Categories

Resources