Components V2
Summary
Adds support for discord's components v2.
Testing and bug reporting is very much appreciated!
DDevs PR: https://github.com/discord/discord-api-docs/pull/7487
- Adds the following Components -> UI Version:
-
SectionComponent->ui.Section -
TextDisplay->ui.TextDisplay -
ThumbnailComponent->ui.Thumbnail -
MediaGalleryComponent->ui.MediaGallery -
FileComponent->ui.File -
SeparatorComponent->ui.Separator -
Container->ui.Container -
ActionRow->ui.ActionRow
- Adds a new ui view like class,
ui.LayoutView, that allows for these components to exist. - Adds the
idattribute to all Components and UI Components. -> This also adds theget_itemmethod toui.View,ui.LayoutView,ui.Container, andui.Section.
You can install this branch for testing using
py -m pip install -U git+https://github.com/DA-344/d.py@feat/components-v2
These changes have been tested with the following snippets **(outdated)**:
All of these use the jishaku package
Sending Components v2
Code:
class TestButton(discord.ui.Button):
async def callback(self, interaction):
await interaction.response.send_message('t')
class TestContainer(discord.ui.Container):
text1 = discord.ui.TextDisplay("Hello world")
text2 = discord.ui.TextDisplay("Row 3", row=2)
section = discord.ui.Section(
accessory=TestButton(
label="Section Button",
)
).add_item(discord.ui.TextDisplay("Text in a section"))
class TestView(discord.ui.LayoutView):
container = TestContainer(id=1)
await _ctx.send(view=TestView())
Result (as expected):
Sending Components v2 items on webhooks
1st snippet: sends interactible items on app owned and not app owned webhooks
wh = await _channel.create_webhook(name='sumth') # app owned
class TestButton(discord.ui.Button):
async def callback(self, interaction):
await interaction.response.send_message('t')
class TestContainer(discord.ui.Container):
text1 = discord.ui.TextDisplay("Hello world")
text2 = discord.ui.TextDisplay("Row 3", row=2)
section = discord.ui.Section(
accessory=TestButton(
label="Section Button",
)
).add_item(discord.ui.TextDisplay("Text in a section"))
class TestView(discord.ui.LayoutView):
container = TestContainer(id=1)
v = TestView()
await wh.send(view=v)
wh2 = discord.Webhook.from_url('https://discord.com/api/webhooks/1362896342581641286/TOKEN', client=_bot) # not app owned
await wh2.send(view=TestView())
Result (as expected):
2nd snippet: sends non-interactible items on not app owned webhook
class TestButton(discord.ui.Button):
async def callback(self, interaction):
await interaction.response.send_message('t')
class TestContainer(discord.ui.Container):
text1 = discord.ui.TextDisplay("Hello world")
text2 = discord.ui.TextDisplay("Row 3", row=2)
section = discord.ui.Section(
accessory=TestButton(
url="https://google.com",
label='gugol',
)
).add_item(discord.ui.TextDisplay("Text in a section"))
class TestView(discord.ui.LayoutView):
container = TestContainer(id=1)
wh2 = discord.Webhook.from_url('https://discord.com/api/webhooks/1362896342581641286/TOKEN', client=_bot)
await wh2.send(view=TestView())
Result (as expected):
Receiving other message's components v2
Code:
yield _message.reference.resolved.components
Result (as expected):
Checklist
- [x] If code changes were made then they have been tested.
- [x] I have updated the documentation to reflect the changes.
- [ ] This PR fixes an issue.
- [x] 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, ...)
If an action row is added via add_item, view doesn't get set on buttons and they won't work:
class TestButton(discord.ui.Button):
async def callback(self, interaction: Interaction):
await interaction.response.send_message("Test button clicked!")
class TestActionRow(discord.ui.ActionRow):
def __init__(self):
super().__init__()
self.add_item(TestButton(label="test2"))
@discord.ui.button(label="test1")
async def test_button(self, interaction: Interaction, button: discord.ui.Button):
await interaction.response.send_message("Test button clicked!")
class TestLayout(discord.ui.LayoutView):
def __init__(self):
super().__init__()
# test1 and test2 don't work
self.add_item(TestActionRow())
# test3 works
self.add_item(discord.ui.Section(accessory=TestButton(label="test3")).add_item("text"))
If an action row is added via
add_item,viewdoesn't get set on buttons and they won't work
Thanks for reporting it, this should be fixed in the latest commit.
With these changes is there a straightforward way to send the simplest form of a components v2 message, aka just plaintext content?
The reason for wanting this is because the character limit would be 4000 instead of the old 2000.
It would be nice if the character limit of the existing "content" field was increased to 4000; and just make it use components v2 under the hood if it has to.
You can make your own LayoutView subclass and automatically assign it a content with a TextDisplay, as making content be a shortcut for TextDisplay would make it not be consistent with the API.
I have a problem : I cannot get all components from a message
I want to get container and text display components
I have a problem : I cannot get all components from a message
![]()
I want to get container and text display components
This PR hasn't even been merged yet; how did you already get the docs lol? Anyway, with this PR, Message.components does return all the new components too. Have you tried it?
Yes I tried and I get [ ]
Yes I tried and I get [ ]
Code?
Also, consider joining the support server and reporting this in the dedicated discussion thread.
I had forgotten to py -m pip install -U git+https://github.com/DA-344/d.py@feat/components-v2 lol
I don't know what version of the PR you are using, but Containers do not longer inherit from BaseView, and are just normal Items. I've pushed some fixes to is_persistent on v2 items.
Hey, i noticed an error, when you are sending a view with webhook (with client)
and then, editing it, no edit are pushed, and no error are raised
webhook = Webhook.from_url(WEBHOOK, client=Bot)
message = await webhook.send(view=fview,wait=True)
await asyncio.sleep(5)
new_view = NewsView()
await webhook.edit_message(message_id=message.id,view=new_view)
Hey, i noticed an error, when you are sending a view with webhook (with client)
and then, editing it, no edit are pushed, and no error are raised
webhook = Webhook.from_url(WEBHOOK, client=Bot) message = await webhook.send(view=fview,wait=True) await asyncio.sleep(5) new_view = NewsView() await webhook.edit_message(message_id=message.id,view=new_view)
Would be useful to show what the view looks like.
Hey, i noticed an error, when you are sending a view with webhook (with client) and then, editing it, no edit are pushed, and no error are raised
webhook = Webhook.from_url(WEBHOOK, client=Bot) message = await webhook.send(view=fview,wait=True) await asyncio.sleep(5) new_view = NewsView() await webhook.edit_message(message_id=message.id,view=new_view)Would be useful to show what the view looks like.
Any view, a simple view with a MediaGallery arent editable
class first(Container): def init(self, id): super().init(id=id) self.add_item(MediaGallery(row=2).add_item(item=MediaGalleryItem(media=MEDIA_URL),))
self.add_item(TextDisplay("We're bringing new components to messages that you can use in your apps."))
If no errors are logged and the request was sent successfully, this means it is a discord side issue. Try enabling d.py debug mode, and show us the whole view you have, both the NewsView class and the fview one. If you try sending a v2 view and then editing it with a non-v2, it is not possible.
If no errors are logged and the request was sent successfully, this means it is a discord side issue. Try enabling d.py debug mode, and show us the whole view you have, both the
NewsViewclass and thefviewone. If you try sending a v2 view and then editing it with a non-v2, it is not possible.
Here is an example that not working,
from discord.ui import LayoutView, ActionRow, Separator, Section, Container, TextDisplay, Thumbnail, MediaGallery, Button, Item, File, Select,Modal
from discord.components import MediaGalleryItem
from discord import ui
class first(Container):
def __init__(self, id):
super().__init__(id=id)
self.add_item(TextDisplay("FIRST LAYOUT"))
class FIRST_LAYOUT(LayoutView):
def __init__(self):
super().__init__()
self.add_item(first(id=1))
class second(Container):
def __init__(self, id):
super().__init__(id=id)
self.add_item(TextDisplay("SECOND LAYOUT"))
class SECOND_LAYOUT(LayoutView):
def __init__(self):
super().__init__()
self.add_item(second(id=2))
@app_commands.command(name="post_components")
@app_commands.checks.has_permissions(administrator=True)
async def post_components(self,interaction: discord.Interaction):
await interaction.response.defer(ephemeral=True)
session = aiohttp.ClientSession()
try:
first_view = FIRST_LAYOUT()
webhook = Webhook.from_url(COMPONENT_WEBHOOK, client=Bot)
print(1)
message = await webhook.send(view=first_view,wait=True)
second_view = SECOND_LAYOUT()
await asyncio.sleep(2)
await message.edit(view=second_view)
print(2)
if session:
await session.close()
except Exception as e:
Log.print(e,"ERROR")
if session:
await session.close()
keep on getting Invalid Form Body In components.0.components.1.accessory: Value of field "type" must be one of (2, 11). when i try to send a image
keep on getting Invalid Form Body In components.0.components.1.accessory: Value of field "type" must be one of (2, 11). when i try to send a image
A section's accessory can only be an instance of discord.ui.Thumbnail() or discord.ui.Button().
I noticed that your PR claims to include support for the new component v2 system.
However, I couldn’t find any implementation or example in the code that demonstrates usage of the channel select UI element.
Could you confirm whether your PR currently includes support for this, and if so, where it’s implemented? If not, do you plan to add it?
channel select is not a new thing, they exist pre components v2
If no errors are logged and the request was sent successfully, this means it is a discord side issue. Try enabling d.py debug mode, and show us the whole view you have, both the
NewsViewclass and thefviewone. If you try sending a v2 view and then editing it with a non-v2, it is not possible.Here is an example that not working,
from discord.ui import LayoutView, ActionRow, Separator, Section, Container, TextDisplay, Thumbnail, MediaGallery, Button, Item, File, Select,Modal from discord.components import MediaGalleryItem from discord import ui class first(Container): def __init__(self, id): super().__init__(id=id) self.add_item(TextDisplay("FIRST LAYOUT")) class FIRST_LAYOUT(LayoutView): def __init__(self): super().__init__() self.add_item(first(id=1)) class second(Container): def __init__(self, id): super().__init__(id=id) self.add_item(TextDisplay("SECOND LAYOUT")) class SECOND_LAYOUT(LayoutView): def __init__(self): super().__init__() self.add_item(second(id=2)) @app_commands.command(name="post_components") @app_commands.checks.has_permissions(administrator=True) async def post_components(self,interaction: discord.Interaction): await interaction.response.defer(ephemeral=True) session = aiohttp.ClientSession() try: first_view = FIRST_LAYOUT() webhook = Webhook.from_url(COMPONENT_WEBHOOK, client=Bot) print(1) message = await webhook.send(view=first_view,wait=True) second_view = SECOND_LAYOUT() await asyncio.sleep(2) await message.edit(view=second_view) print(2) if session: await session.close() except Exception as e: Log.print(e,"ERROR") if session: await session.close()
Can't edit a component V2 with Webhook where it should be able to ? any news about this issue ?
If discord.py sends the request successfully, may be a Discord side issue, as I mentioned. And, also as I mentioned, enable the debug logs to see the whether the request went through, with what payload, and the response to that request.
when's this shi getting pushed 😭💔 we need cv2
omg no conflicts?? does this mean we get cv2 :o
I've started testing, just to grasp the fundamentals. How would you go about embeding the LayoutView in a discord.embeds.Embed() or has this not yet been implemented? I know it can be done in discord.js I just don't see how it would be done in discord.py?
I was thinking maybe using the example below, and will test with this but am unsure.
class foo(Embed, LayoutView):
@ConnerAdamsMaine Embeds and container v2 are two different things. The closest you have to an "embed" is Container which lets you set an accent colour. There is no way that discord.js supports whatever you're suggesting because they are fundamentally different things at an API layer.
@Rapptz it's not an embed per-say, it was just the best way I could think of it. I realize now that it was an idiotic idea, I do apologize on that part. It's hard thinking with 48 hours of sleep deprivation. I have checked and it is the Container class that I was looking for!
I want to get container and text display components