Skip to content

[Guide] add guide pages for views/modals #7507

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 27 commits into
base: docs/guide
Choose a base branch
from

Conversation

bijij
Copy link
Contributor

@bijij bijij commented Mar 6, 2022

Summary

Adds guide pages for views/modals

Checklist

  • If code changes were made then they have been tested.
    • I have updated the documentation to reflect the changes.
  • This PR fixes an issue.
  • This PR adds something new (e.g. new method or parameters).
  • This PR is a breaking change (e.g. methods or parameters removed/renamed)
  • This PR is not a code change (e.g. documentation, README, ...)

bijij and others added 8 commits February 26, 2022 18:25
Co-Authored-By: Devon R <Gorialis@users.noreply.github.com>
Co-Authored-By: Riley Miļeško <30989490+Shineydev@users.noreply.github.com>
Co-Authored-By: Nadir Chowdhury <chowdhurynadir0@outlook.com>
Co-Authored-By: Kaylynn Morgan <51037748+kaylynn234@users.noreply.github.com>
Co-Authored-By: Kaylynn Morgan <51037748+kaylynn234@users.noreply.github.com>
@Rapptz Rapptz added the guide This relates to the discord.py guide label Mar 9, 2022
@Rapptz Rapptz mentioned this pull request Mar 12, 2022
23 tasks
Copy link
Contributor

@scarletcafe scarletcafe left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I can't see any problems that stand out to me.

Copy link
Contributor

@ShineyDev ShineyDev left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review'd modals.rst.

Copy link
Contributor

@ShineyDev ShineyDev left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review'd views.rst.

Copy link
Contributor

@ShineyDev ShineyDev left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we also rename the image files from modals1 etc.? :)

bijij and others added 2 commits March 19, 2022 17:59
Co-Authored-By: Riley Miļeško <30989490+ShineyDev@users.noreply.github.com>
@Soheab
Copy link
Contributor

Soheab commented Sep 11, 2023

This is missing the recently added dynamic items. If it's still being worked.

roles = [guild.get_role(id) for id in ROLE_IDS]
await channel.send('Choose your house', view=RoleSelector(0, roles)) # we don't know the message ID yet.

Once we have a message ID we just need to create an instance of our view and attach it to the :class:`~discord.Client`
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(RFC) While a bit out of the scope of this topic, I don't believe that anywhere in the guide we mentions how to get message IDs. Is that something worth adding here?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I kind of hoped it was implied.
But i can be more specific.

Idea is the user sends the message first, then knows the ID then uses it.

Copy link

@thomasemeryy thomasemeryy left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added some grammar corrections and wording suggestions (some of which are nit-picky so feel free to disagree). Great job on the guides.

@bijij
Copy link
Contributor Author

bijij commented Sep 15, 2023

This is missing the recently added dynamic items. If it's still being worked.

Added a new section on dynamic items

@bijij bijij closed this Sep 15, 2023
@bijij bijij reopened this Sep 15, 2023
@bijij
Copy link
Contributor Author

bijij commented Sep 15, 2023

Ctrl+enter defaulted to close with comment?

@bijij bijij requested a review from thomasemeryy September 15, 2023 01:02
Copy link

@thomasemeryy thomasemeryy left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good to me.

Copy link
Contributor

@Aryathel Aryathel left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just a few edits/clarity pieces I think are worth looking at.

Comment on lines +42 to +44
The :class:`~discord.ui.View` class also supports a :meth:`~discord.ui.View.interaction_check` method, which we'll
use to check if the user who clicked on buttons in the view is the same as the user we're prompting for confirmation.
It should return a boolean value which, when ``False``, will cause the interaction to be ignored.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think that this piece deserves its own section. It doesn't need to be long, but having a Checks section after the Creating Components section might be a little more clear.

This is important enough to be mentioned separately, but technically not intrinsically necessary for the function of a view, hence why I recommend putting the guide for it below the part where the components are added.

Copy link

@No767 No767 Feb 6, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I partially disagree on this. It's fine leaving this section here as it's needed to build the context and explain what the code above does. People would be asking "what does interaction_check do in the code" without the proper context. Further details can be linked to the checks guide itself

This is in reference to @Aryathel 's review comment

Comment on lines 302 to 303
Once we have a message ID, we just need to create an instance of our view and attach it to the :class:`~discord.Client`
with the :meth:`~discord.Client.add_view` method.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
Once we have a message ID, we just need to create an instance of our view and attach it to the :class:`~discord.Client`
with the :meth:`~discord.Client.add_view` method.
Once we have a message ID, we just need to create an instance of our view and attach it to the :class:`~discord.Client`
with the :meth:`~discord.Client.add_view` method. By calling this method in our client setup and using a custom ID on all of the view components, the bot will add this view every time it is started. This is what makes a view persistent.

I'm not sure I am perfectly happy with my wording here either, but adding a little more detail describing what exactly this section is for and why this is important for a persistent view seems relevant.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added some extra detail, however I'm not really sure there's much benefit.

Co-authored-by: Arya (She/Her) <arya.mayfield@gmail.com>
Copy link

@No767 No767 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I left some feedback based off of a brief reading of the modal and view pages. Note that it is not a complete read and I may have missed some details along the way.

def __init__(self) -> None:
super().__init__(timeout=None)

@discord.ui.select(
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

discord.ui.select has an kwarg called cls. In this, you pass in the type of select that you want. In this case, all we need to do is to pass in discord.ui.RoleSelect. The current implementation in this page relies on an old method on doing this and uses the base select type.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

RoleSelect doesn't provide the same functionality though (it lists all roles). If we'd rather use it then it would make more sense to just replace the entire example.

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It would make more sense instead of roles, that they are something unique such as colors imo. this kinda depends if the example should be replaced or not

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I fully agree with Josh on this one. The Select classes provide no filter (which is a bit of a silly move on Discord's side IMO>. As such I still view this as best practice as we can filter what is shown to the user, and not make an accidental footgun where a user could give themselves an admin role.

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fair enough

Copy link
Contributor Author

@bijij bijij left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Addressed some review comments.

def __init__(self) -> None:
super().__init__(timeout=None)

@discord.ui.select(
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

RoleSelect doesn't provide the same functionality though (it lists all roles). If we'd rather use it then it would make more sense to just replace the entire example.

Comment on lines 302 to 303
Once we have a message ID, we just need to create an instance of our view and attach it to the :class:`~discord.Client`
with the :meth:`~discord.Client.add_view` method.
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added some extra detail, however I'm not really sure there's much benefit.

Copy link
Contributor

@Soheab Soheab left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just two small things that I'm not sure about whether they need to be mentioned, so it's up to you and others. It looks good otherwise.

The callback is passed a new :class:`~discord.Interaction` instance, which requires a response.

In the example above we respond by sending a message to the user confirming their submission was recorded.
Users responses to specific fields can be accessed via the field's ``value`` attribute.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not super important and not too sure, but I noticed that it is nowhere mentioned that casting the TextInput (or in a f-string (same thing)) to str() will also return the value. This could lead to unexpected behavior or cause confusion for beginners.

Sending a Modal
-----------------

A modal can be sent by calling the :meth:`InteractionResponse.send_modal` method when handling an :class:`Interaction`.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Very straightforward, etc., but it might be worth mentioning that Modals is its own response, thus the response cannot be delayed or sent from a follow-up, etc.

Copy link

@No767 No767 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've left some of my suggestions. Overall, the guide is fine but make sure you address the suggestions that are pointed out in this review.

Comment on lines +42 to +44
The :class:`~discord.ui.View` class also supports a :meth:`~discord.ui.View.interaction_check` method, which we'll
use to check if the user who clicked on buttons in the view is the same as the user we're prompting for confirmation.
It should return a boolean value which, when ``False``, will cause the interaction to be ignored.
Copy link

@No767 No767 Feb 6, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I partially disagree on this. It's fine leaving this section here as it's needed to build the context and explain what the code above does. People would be asking "what does interaction_check do in the code" without the proper context. Further details can be linked to the checks guide itself

This is in reference to @Aryathel 's review comment

We set parameters prior to the creation of the view instance, so context-specific variables are not available.
If modifications are needed, we would instead have to override component instance attributes in the ``__init__`` method.

The function we're decorating acts similarly to the :meth:`~discord.ui.Button.callback` method, it's called when the button is clicked.
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
The function we're decorating acts similarly to the :meth:`~discord.ui.Button.callback` method, it's called when the button is clicked.
The function we're decorating acts similarly to the :meth:`~discord.ui.Button.callback` method as it's called when the button is clicked.

Minor grammatical correction and nitpicking, but separating the two clauses using an comma doesn't make sense. If you read it out loud to yourself, you'll find that using an comma doesn't work as you would want to join these two clauses into an sentence to complete it

def __init__(self) -> None:
super().__init__(timeout=None)

@discord.ui.select(
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fair enough

role = discord.Object(id=role_id, type=discord.Role)
roles = set(interaction.user.roles) - set(self.roles) | {role}
await interaction.user.edit(roles=roles)
await interaction.response.defer()
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Instead of deferring the interaction and not acknowledging the response, you should send an message response instead. The contents of the message should tell the user that their role has been changed to the role that they have selected, and this should be ephemeral.

bijij and others added 3 commits February 20, 2024 22:16
Co-authored-by: Noelle Wang <73260931+No767@users.noreply.github.com>
Co-authored-by: Noelle Wang <73260931+No767@users.noreply.github.com>
Co-authored-by: Noelle Wang <73260931+No767@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
guide This relates to the discord.py guide
Projects
Status: Changes Requested
Development

Successfully merging this pull request may close these issues.