Inline Keyboard with pager that spawns more menus - python-telegram-bot

I try to create following logic:
User start conversation with command /display-playlists
Bot replies with a text for first batch of playlists (or any data) from database. For example first batch is 10 rows from database. Inline keyboard that comes with this message contains buttons for each of those rows + pager button like 'next' and 'previous', for next and previous batches (i already have this implemented, the problem is in the next step)
When user clicks on a button, that is "attached" to the row, bot should reply with a message for only this row, with inline keyboard, having options, that could be applied to this row.
So user calls the conversation to show playlists, chooses one of them, then chooses action for it from bots reply.
How it looks right now
It looks the way I want it to look like. The problem is that the third step is still a part of the initial conversation, so when i click on actions (show or delete) it goes to the entry point of inner conversation, so it just duplicates the message with options.
Conversation Handler for it:
ConversationHandler(
entry_points=[CommandHandler(name, display_playlists)],
states={
0: [
ConversationHandler(
entry_points=[
CallbackQueryHandler(pager, pattern=callback_utils.is_pager_action),
CallbackQueryHandler(action)
],
states={
0: [CallbackQueryHandler(apply)]
},
per_message=True,
fallbacks=[]
),
]
},
fallbacks=[],
allow_reentry=True
)
'pager' is a method for switching through batches (returns 0), 'action' is a method that displays single row keyboard for actions (returns 0), 'apply' is what is supposed to apply chosen action, but it is not implemented yet, as i try to resolve the problem in this post.
As you can see i did put "per_message" so i hoped each message with actions to be in its own conversation, so i could choose as many playlists as i want, and then click on their actions, without then interrupting each other. My guess is that i need to somehow catch clicks on actions through a completly separate CallbackQueryHandler, but i have no idea how to implement it, as there is almost no examples on how to use "per_message" in such manner.
I know that handler right now looks scuffed, i'm just experimenting, trying to make it work, so i guess you can just ignore it.
I'm using python-telegram-bot==13.12

Related

Identify which button in message was clicked

I'm sending messages with Block elements(buttons) to users using Slack API (python-slackclient). Different users can get number of these and can click the buttons with a delay obviously, for example the next day.
I need to identify which button in which message was clicked.
After checking the documentation on Slack API pages it looks like action_id is the way to go as I can specify it in my request and assign it a unique value. I shall get the action_id back in response coming to my endpoint once user clicks one of the buttons which will allow me to match it with sent message.
Is this the correct way to achieve it? Are you aware any better way to implement this?
You can use an action_id on your button in order to tie your button to a response action.
So if you have several buttons that should all trigger the same action, but you'd still need to know which of those buttons was clicked, maybe you could give them all the same action_id (so you can link them to the same action), but specify unique button values.
You need to make sure your action_ids are unique, BUT you can receive a message or an action using RegEx and thus still point them all to the same handler.
For example, this action handler receives all button presses where the action_id starts with "hello"
app.action(/^hello.*/, async ({ body, ack, say }: any) => {
await ack();
await say(`<#${body.user.id}> clicked the button`);
});

NGXS ofActionSuccessful

I have an angular component that subscribes to ofActionSuccessful. This action is dispatched as the user clicks on a button on the page. It is possible that the user may click on this button multiple times resulting in multiple dispatch events for this action
this.actions$.pipe(ofActionSuccessful(UpdateCommunicationPreferences)).subscribe(() => {
console.log('Action Successful');
});
this.store.dispatch(
new UpdateCommunicationPreferences(this.communicationPreferenceForm.value)
);
The issue that I am running into is ofSuccessful is triggered in an accumulated manner. In other words, the first time the user clicks on the button, the "Action Successful" is printed once. Second time the user clicks on the button, it is printed twice and so forth.
Can anyone help if there is a way to not get duplicate ofSuccessful events for the past actions?
Appreciate any insight.
This package was developed with your issue in mind:
https://www.npmjs.com/package/#ngxs-labs/actions-executing
#Select(actionsExecuting([UpdateCommunicationPreference])) myActionIsExecuting$: Observable;
you can use myActionIsExecuting$ in your template with async pipe. you can also simply subscribe to myActionIsExecuting to familiarize yourself with what is returned. null will be returned when all instances of that particular action are finished.
I hope that helps!
Take a look this: https://www.ngxs.io/advanced/cancellation
Extracted from the link: "If you have an async action, you may want to cancel a previous Observable if the action has been dispatched again. This is useful for canceling previous requests like in a typeahead."
Alternatively, you can consider a pattern that disables the UI when the button is clicked (e.g. via 'in progress' dialog) before triggering the action dispatch. When the action is done processing, close the dialog.
Hope this helps.

Calling a child dialog and passing in input parameters

I've read a bunch of articles on how to call dialogs from javascript and integrate them into a ribbon button, but I am running into a problem where I need to do all that AND pass in a string as an input parameter (to a child dialog?).
Is this possible? Would I have to modify the calling url of the dialog?
I've read this one about calling dialogs with the SelectedControlAllItemsId, which is almost what I need.
Ideally I would open the form of the parent entity, click on one of the subgrids in the left hand navigation, then select some of the related/associated entities, click the ribbon button and wait for the dialog or workflow to chew through all of those Ids.
Is it possible to capture these selected items using SelectedControlAllItemsId, then pass that string to a child dialog so it can then call another workflow? Or should I capture that string, store it in the calling record via REST and then let a workflow run on a field-trigger?
The end result is that I must run a custom workflow and manipulate the parent record + the selected related records. I have already written the workflow, but I do not know how to trigger it the way I want.
Perhaps there is something I am overlooking? Is there a way to call a custom bit of code directly from javascript and let it work the rest of the way?
I'm not sure how an interactive dialog should deal with a collection of records. Surely that would require sequential iterations of the dialog, as the user processes each record? As you will see from the SDK (and discussed in your linked thread), it is only possible to run a dialog against a single record.
A workflow is a different matter.
- Custom ribbon button, using SelectedControlAllItemsId
- Supporting JScript handler should iterate SelectedControlAllItemsId
- Each iteration should issue an ExecuteWorkflowRequest using the current item id and based on code such as this (which issues an ExecuteWorkflowRequest from JScript
Remember that the workflow request is asynchronous so you can just send all the requests one after another rather than waiting for the outcome of each request.

How to automatically process contents of <textarea> without user pressing a button?

On my page I have a textarea where users can enter a list of items, items being separated by a newline.
I would like to process the user's input without him/her having to press a submit button. ("Process" means send the information the user entered to the server and update other elements on the current page.) I thought of two days of doing this:
1- Install an event handler for keypress events and, when I get an event for the Enter key being pressed, process the line the user just completed. (Getting cursor position info as done here.) This has the disadvantage of not handling copy-pasting into the form. (And, if I understood correctly from browsing Stack Overflow, support for handling paste events is not great even among most common browsers, right?)
2- Periodically process the contents of the textarea by using setInterval(). I am already using a setInterval() on the page to implement the unique URLs pattern, so if I could I would avoid that.
Are there better ways to achieve this?
There is also an "onchange" event for a textarea. You can use it to detect any changes, including paste or magic inserts.

AJAX and prediction of actions

I'd like to ask your opinion on this. This is a theoretical question.
I'm in a situation where I have an interface shown to a user that uses AJAX to talk to the server. The server-side language does not matter here. I have a form with fields and each of them are deletable. If the user selects a few "delete" -checkboxes and presses Update, then I have these two options to do:
Option 1:
When deleting fields, use JavaScript to remove the HTML immediately and run AJAX on background to delete those fields. This achieves a look of a fast interface -> better user experience. However, if the AJAX call fails on the server side (the fields couldn't be deleted), then the previously deleted HTML fields would give a false assumption for the user (of them being deleted).
Option 2:
When deleting fields, run AJAX, depending on its success, either remove the HTML or do not. This gives accurate feedback for the user, but the form would freeze until the AJAX call finishes = slow(er).
What are your thoughts? Which approach seems better for me to take or should I make it an option?
Option 3: Mark the controls as being deleted (e.g. overlay a translucent gray box with a delete icon on it). Send the request. When it returns, either remove the controls, or change the box to show an error icon for a few seconds (then remove the box).
Allow the rest of the interface to be interacted with while this goes on.
Nice question.
A third option would be to :
disable immediately the controls
delete them when the Ajax returns
This gives the user feedback that something was effectively requested (responsiveness),
while showing also the moment where it is effectively completed.
Also, the user somehow feels the "distant call", which does not induce him in error, because it is was really happens. Anyway, there is nothing meaningful we can do to hide this feeling, because the delay will always be there.

Resources