Browse Source

Handle resolved data for modal components and types

v2.6.x
Soheab_ 4 weeks ago
committed by Rapptz
parent
commit
0b600095ba
  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'] inner_data = data['data']
custom_id = inner_data['custom_id'] custom_id = inner_data['custom_id']
components = inner_data['components'] 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) self.dispatch('interaction', interaction)
def parse_presence_update(self, data: gw.PresenceUpdateEvent) -> None: 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 .snowflake import Snowflake
from .user import User from .user import User
from .guild import GuildFeature from .guild import GuildFeature
from .components import ComponentBase
if TYPE_CHECKING: if TYPE_CHECKING:
from .message import Message from .message import Message
@ -204,19 +205,19 @@ class SelectMessageComponentInteractionData(_BaseMessageComponentInteractionData
MessageComponentInteractionData = Union[ButtonMessageComponentInteractionData, SelectMessageComponentInteractionData] MessageComponentInteractionData = Union[ButtonMessageComponentInteractionData, SelectMessageComponentInteractionData]
class ModalSubmitTextInputInteractionData(TypedDict): class ModalSubmitTextInputInteractionData(ComponentBase):
type: Literal[4] type: Literal[4]
custom_id: str custom_id: str
value: str value: str
class ModalSubmitStringSelectInteractionData(TypedDict): class ModalSubmitSelectInteractionData(ComponentBase):
type: Literal[3] type: Literal[3, 5, 6, 7, 8]
custom_id: str custom_id: str
values: List[str] values: List[str]
ModalSubmitComponentItemInteractionData = Union[ModalSubmitTextInputInteractionData, ModalSubmitStringSelectInteractionData] ModalSubmitComponentItemInteractionData = Union[ModalSubmitSelectInteractionData, ModalSubmitTextInputInteractionData]
class ModalSubmitActionRowInteractionData(TypedDict): class ModalSubmitActionRowInteractionData(TypedDict):
@ -224,19 +225,27 @@ class ModalSubmitActionRowInteractionData(TypedDict):
components: List[ModalSubmitComponentItemInteractionData] components: List[ModalSubmitComponentItemInteractionData]
class ModalSubmitLabelInteractionData(TypedDict): class ModalSubmitTextDisplayInteractionData(ComponentBase):
type: Literal[10]
content: str
class ModalSubmitLabelInteractionData(ComponentBase):
type: Literal[18] type: Literal[18]
component: ModalSubmitComponentItemInteractionData component: ModalSubmitComponentItemInteractionData
ModalSubmitComponentInteractionData = Union[ ModalSubmitComponentInteractionData = Union[
ModalSubmitLabelInteractionData, ModalSubmitActionRowInteractionData, ModalSubmitComponentItemInteractionData ModalSubmitActionRowInteractionData,
ModalSubmitTextDisplayInteractionData,
ModalSubmitLabelInteractionData,
] ]
class ModalSubmitInteractionData(TypedDict): class ModalSubmitInteractionData(TypedDict):
custom_id: str custom_id: str
components: List[ModalSubmitComponentInteractionData] components: List[ModalSubmitComponentInteractionData]
resolved: NotRequired[ResolvedData]
InteractionData = Union[ InteractionData = Union[

4
discord/ui/item.py

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

47
discord/ui/modal.py

@ -36,12 +36,17 @@ from .item import Item
from .view import BaseView from .view import BaseView
from .select import BaseSelect from .select import BaseSelect
from .text_input import TextInput from .text_input import TextInput
from ..interactions import Namespace
if TYPE_CHECKING: if TYPE_CHECKING:
from typing_extensions import Self from typing_extensions import Self
from ..interactions import Interaction 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 # fmt: off
@ -168,27 +173,41 @@ class Modal(BaseView):
""" """
_log.error('Ignoring exception in modal %r:', self, exc_info=error) _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: for component in components:
if component['type'] == 1: if component['type'] == 1:
self._refresh(interaction, component['components']) self._refresh(interaction, component['components'], resolved) # type: ignore
elif component['type'] == 18: elif component['type'] == 18:
self._refresh(interaction, [component['component']]) self._refresh(interaction, [component['component']], resolved) # type: ignore
else: else:
custom_id = component.get('custom_id') custom_id = component.get('custom_id')
if custom_id is None: if custom_id is None:
continue 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: if item is None:
_log.debug('Modal interaction referencing unknown item custom_id %s. Discarding', custom_id) _log.debug('Modal interaction referencing unknown item custom_id %s. Discarding', custom_id)
continue 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: try:
self._refresh_timeout() self._refresh_timeout()
self._refresh(interaction, components) self._refresh(interaction, components, resolved)
allow = await self.interaction_check(interaction) allow = await self.interaction_check(interaction)
if not allow: if not allow:
@ -225,10 +244,18 @@ class Modal(BaseView):
return components return components
def _dispatch_submit( def _dispatch_submit(
self, interaction: Interaction, components: List[ModalSubmitComponentInteractionDataPayload] self,
interaction: Interaction,
components: List[ModalSubmitComponentInteractionDataPayload],
resolved: ResolvedDataPayload,
) -> asyncio.Task[None]: ) -> asyncio.Task[None]:
try:
namespace = Namespace._get_resolved_items(interaction, resolved)
except KeyError:
namespace = {}
return asyncio.create_task( 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]: 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 ..types.interactions import SelectMessageComponentInteractionData
from ..app_commands import AppCommandChannel, AppCommandThread from ..app_commands import AppCommandChannel, AppCommandThread
from ..interactions import Interaction from ..interactions import Interaction
from ..app_commands.namespace import ResolveKey
ValidSelectType: TypeAlias = Literal[ ValidSelectType: TypeAlias = Literal[
ComponentType.string_select, ComponentType.string_select,
@ -356,7 +357,24 @@ class BaseSelect(Item[V]):
def _refresh_component(self, component: SelectMenu) -> None: def _refresh_component(self, component: SelectMenu) -> None:
self._underlying = component 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({}) values = selected_values.get({})
payload: List[PossibleValue] payload: List[PossibleValue]
try: try:
@ -366,7 +384,7 @@ class BaseSelect(Item[V]):
) )
payload = list(resolved.values()) payload = list(resolved.values())
except KeyError: except KeyError:
payload = data.get('values', []) # type: ignore payload = list(data.get('values', []))
self._values = values[self.custom_id] = payload self._values = values[self.custom_id] = payload
selected_values.set(values) selected_values.set(values)

8
discord/ui/view.py

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

Loading…
Cancel
Save