Browse Source

Handle resolved data for modal components and types

pull/10307/head
Soheab_ 4 weeks ago
parent
commit
f6658a58a7
  1. 3
      discord/state.py
  2. 21
      discord/types/interactions.py
  3. 4
      discord/ui/item.py
  4. 47
      discord/ui/modal.py
  5. 22
      discord/ui/select.py
  6. 8
      discord/ui/view.py

3
discord/state.py

@ -828,7 +828,8 @@ class ConnectionState(Generic[ClientT]):
inner_data = data['data']
custom_id = inner_data['custom_id']
components = inner_data['components']
self._view_store.dispatch_modal(custom_id, interaction, components)
resolved = inner_data.get('resolved', {})
self._view_store.dispatch_modal(custom_id, interaction, components, resolved)
self.dispatch('interaction', interaction)
def parse_presence_update(self, data: gw.PresenceUpdateEvent) -> None:

21
discord/types/interactions.py

@ -36,6 +36,7 @@ from .role import Role
from .snowflake import Snowflake
from .user import User
from .guild import GuildFeature
from .components import ComponentBase
if TYPE_CHECKING:
from .message import Message
@ -204,19 +205,19 @@ class SelectMessageComponentInteractionData(_BaseMessageComponentInteractionData
MessageComponentInteractionData = Union[ButtonMessageComponentInteractionData, SelectMessageComponentInteractionData]
class ModalSubmitTextInputInteractionData(TypedDict):
class ModalSubmitTextInputInteractionData(ComponentBase):
type: Literal[4]
custom_id: str
value: str
class ModalSubmitStringSelectInteractionData(TypedDict):
type: Literal[3]
class ModalSubmitSelectInteractionData(ComponentBase):
type: Literal[3, 5, 6, 7, 8]
custom_id: str
values: List[str]
ModalSubmitComponentItemInteractionData = Union[ModalSubmitTextInputInteractionData, ModalSubmitStringSelectInteractionData]
ModalSubmitComponentItemInteractionData = Union[ModalSubmitSelectInteractionData, ModalSubmitTextInputInteractionData]
class ModalSubmitActionRowInteractionData(TypedDict):
@ -224,19 +225,27 @@ class ModalSubmitActionRowInteractionData(TypedDict):
components: List[ModalSubmitComponentItemInteractionData]
class ModalSubmitLabelInteractionData(TypedDict):
class ModalSubmitTextDisplayInteractionData(ComponentBase):
type: Literal[10]
content: str
class ModalSubmitLabelInteractionData(ComponentBase):
type: Literal[18]
component: ModalSubmitComponentItemInteractionData
ModalSubmitComponentInteractionData = Union[
ModalSubmitLabelInteractionData, ModalSubmitActionRowInteractionData, ModalSubmitComponentItemInteractionData
ModalSubmitActionRowInteractionData,
ModalSubmitTextDisplayInteractionData,
ModalSubmitLabelInteractionData,
]
class ModalSubmitInteractionData(TypedDict):
custom_id: str
components: List[ModalSubmitComponentInteractionData]
resolved: NotRequired[ResolvedData]
InteractionData = Union[

4
discord/ui/item.py

@ -45,6 +45,7 @@ if TYPE_CHECKING:
from .action_row import ActionRow
from .container import Container
from .dynamic import DynamicItem
from ..app_commands.namespace import ResolveKey
I = TypeVar('I', bound='Item[Any]')
V = TypeVar('V', bound='BaseView', covariant=True)
@ -97,6 +98,9 @@ class Item(Generic[V]):
def _refresh_component(self, component: Component) -> None:
return None
def _handle_submit(self, interaction: Interaction, data: Dict[str, Any], resolved: Dict[ResolveKey, Any]) -> None:
return self._refresh_state(interaction, data)
def _refresh_state(self, interaction: Interaction, data: Dict[str, Any]) -> None:
return None

47
discord/ui/modal.py

@ -36,12 +36,17 @@ from .item import Item
from .view import BaseView
from .select import BaseSelect
from .text_input import TextInput
from ..interactions import Namespace
if TYPE_CHECKING:
from typing_extensions import Self
from ..interactions import Interaction
from ..types.interactions import ModalSubmitComponentInteractionData as ModalSubmitComponentInteractionDataPayload
from ..types.interactions import (
ModalSubmitComponentInteractionData as ModalSubmitComponentInteractionDataPayload,
ResolvedData as ResolvedDataPayload,
)
from ..app_commands.namespace import ResolveKey
# fmt: off
@ -168,27 +173,41 @@ class Modal(BaseView):
"""
_log.error('Ignoring exception in modal %r:', self, exc_info=error)
def _refresh(self, interaction: Interaction, components: Sequence[ModalSubmitComponentInteractionDataPayload]) -> None:
def _refresh(
self,
interaction: Interaction,
components: Sequence[ModalSubmitComponentInteractionDataPayload],
resolved: Dict[ResolveKey, Any],
) -> None:
for component in components:
if component['type'] == 1:
self._refresh(interaction, component['components'])
self._refresh(interaction, component['components'], resolved) # type: ignore
elif component['type'] == 18:
self._refresh(interaction, [component['component']])
self._refresh(interaction, [component['component']], resolved) # type: ignore
else:
custom_id = component.get('custom_id')
if custom_id is None:
continue
item = find(lambda i: getattr(i, 'custom_id', None) == custom_id, self.walk_children())
item = find(
lambda i: getattr(i, 'custom_id', None) == custom_id,
self.walk_children(),
)
if item is None:
_log.debug('Modal interaction referencing unknown item custom_id %s. Discarding', custom_id)
continue
item._refresh_state(interaction, component) # type: ignore
async def _scheduled_task(self, interaction: Interaction, components: List[ModalSubmitComponentInteractionDataPayload]):
item._handle_submit(interaction, component, resolved) # type: ignore
async def _scheduled_task(
self,
interaction: Interaction,
components: List[ModalSubmitComponentInteractionDataPayload],
resolved: Dict[ResolveKey, Any],
):
try:
self._refresh_timeout()
self._refresh(interaction, components)
self._refresh(interaction, components, resolved)
allow = await self.interaction_check(interaction)
if not allow:
@ -225,10 +244,18 @@ class Modal(BaseView):
return components
def _dispatch_submit(
self, interaction: Interaction, components: List[ModalSubmitComponentInteractionDataPayload]
self,
interaction: Interaction,
components: List[ModalSubmitComponentInteractionDataPayload],
resolved: ResolvedDataPayload,
) -> asyncio.Task[None]:
try:
namespace = Namespace._get_resolved_items(interaction, resolved)
except KeyError:
namespace = {}
return asyncio.create_task(
self._scheduled_task(interaction, components), name=f'discord-ui-modal-dispatch-{self.id}'
self._scheduled_task(interaction, components, namespace), name=f'discord-ui-modal-dispatch-{self.id}'
)
def to_dict(self) -> Dict[str, Any]:

22
discord/ui/select.py

@ -78,6 +78,7 @@ if TYPE_CHECKING:
from ..types.interactions import SelectMessageComponentInteractionData
from ..app_commands import AppCommandChannel, AppCommandThread
from ..interactions import Interaction
from ..app_commands.namespace import ResolveKey
ValidSelectType: TypeAlias = Literal[
ComponentType.string_select,
@ -356,7 +357,24 @@ class BaseSelect(Item[V]):
def _refresh_component(self, component: SelectMenu) -> None:
self._underlying = component
def _refresh_state(self, interaction: Interaction, data: SelectMessageComponentInteractionData) -> None:
def _handle_submit(
self, interaction: Interaction, data: SelectMessageComponentInteractionData, resolved: Dict[ResolveKey, Any]
) -> None:
payload: List[PossibleValue]
values = selected_values.get({})
string_values = data.get('values', [])
payload = [v for k, v in resolved.items() if k.id in string_values]
if not payload:
payload = list(string_values)
self._values = values[self.custom_id] = payload
selected_values.set(values)
def _refresh_state(
self,
interaction: Interaction,
data: SelectMessageComponentInteractionData,
) -> None:
values = selected_values.get({})
payload: List[PossibleValue]
try:
@ -366,7 +384,7 @@ class BaseSelect(Item[V]):
)
payload = list(resolved.values())
except KeyError:
payload = data.get('values', []) # type: ignore
payload = list(data.get('values', []))
self._values = values[self.custom_id] = payload
selected_values.set(values)

8
discord/ui/view.py

@ -85,7 +85,10 @@ if TYPE_CHECKING:
from ..interactions import Interaction
from ..message import Message
from ..types.components import ComponentBase as ComponentBasePayload
from ..types.interactions import ModalSubmitComponentInteractionData as ModalSubmitComponentInteractionDataPayload
from ..types.interactions import (
ModalSubmitComponentInteractionData as ModalSubmitComponentInteractionDataPayload,
ResolvedData as ResolvedDataPayload,
)
from ..state import ConnectionState
from .modal import Modal
@ -1041,13 +1044,14 @@ class ViewStore:
custom_id: str,
interaction: Interaction,
components: List[ModalSubmitComponentInteractionDataPayload],
resolved: ResolvedDataPayload,
) -> None:
modal = self._modals.get(custom_id)
if modal is None:
_log.debug('Modal interaction referencing unknown custom_id %s. Discarding', custom_id)
return
self.add_task(modal._dispatch_submit(interaction, components))
self.add_task(modal._dispatch_submit(interaction, components, resolved))
def remove_interaction_mapping(self, interaction_id: int) -> None:
# This is called before re-adding the view

Loading…
Cancel
Save