Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
45 changes: 43 additions & 2 deletions interactions/api/gateway/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
from aiohttp import ClientWebSocketResponse, WSMessage, WSMsgType

from ...base import __version__, get_logger
from ...client.enums import InteractionType, OptionType
from ...client.enums import ComponentType, InteractionType, OptionType
from ...client.models import Option
from ...utils.missing import MISSING
from ..dispatch import Listener
Expand Down Expand Up @@ -373,7 +373,14 @@ def _dispatch_event(self, event: str, data: dict) -> None:
_name = f"component_{_context.data.custom_id}"

if _context.data._json.get("values"):
__args.append(_context.data.values)
if _context.data.component_type.value not in {5, 6, 7, 8}:
__args.append(_context.data.values)
else:
for value in _context.data._json.get("values"):
_data = self.__select_option_type_context(
_context, _context.data.component_type.value
) # resolved.
__args.append(_data[value])

self._dispatch.dispatch("on_component", _context)
elif data["type"] == InteractionType.APPLICATION_COMMAND_AUTOCOMPLETE:
Expand Down Expand Up @@ -836,6 +843,40 @@ def __option_type_context(self, context: "_Context", type: int) -> dict:
}
return _resolved

def __select_option_type_context(self, context: "_Context", type: int) -> dict:
"""
Looks up the type of select menu respective to the existing option types. This is applicable for non-string
select menus.

:param context: The context to refer types from.
:type context: object
:param type: The option type.
:type type: int
:return: The select menu type context.
:rtype: dict
"""

_resolved = {}

if type == ComponentType.USER_SELECT.value:
_resolved = (
context.data.resolved.members if context.guild_id else context.data.resolved.users
)
elif type == ComponentType.CHANNEL_SELECT.value:
_resolved = context.data.resolved.channels
elif type == ComponentType.ROLE_SELECT.value:
_resolved = context.data.resolved.roles
elif type == ComponentType.MENTIONABLE_SELECT.value:
_resolved = {
**(
context.data.resolved.members
if context.guild_id
else context.data.resolved.users
),
**context.data.resolved.roles,
}
return _resolved

async def _reconnect(self, to_resume: bool, code: Optional[int] = 1012) -> None:
"""
Restarts the client's connection and heartbeat with the Gateway.
Expand Down
4 changes: 2 additions & 2 deletions interactions/client/bot.py
Original file line number Diff line number Diff line change
Expand Up @@ -725,8 +725,8 @@ def event(

:param coro: The coroutine of the event.
:type coro: Optional[Callable[..., Coroutine]]
:param name(?): The name of the event. If not given, this defaults to the coroutine's name.
:type name: Optional[str]
:param name?: The name of the event. If not given, this defaults to the coroutine's name.
:type name?: Optional[str]
:return: A callable response.
:rtype: Callable[..., Any]
"""
Expand Down
11 changes: 10 additions & 1 deletion interactions/client/enums.py
Original file line number Diff line number Diff line change
Expand Up @@ -120,13 +120,22 @@ class ComponentType(IntEnum):
:ivar ACTION_ROW: 1
:ivar BUTTON: 2
:ivar SELECT: 3
:ivar STRING_SELECT: 3
:ivar INPUT_TEXT: 4
:ivar USER_SELECT: 5
:ivar ROLE_SELECT: 6
:ivar MENTIONABLE_SELECT: 7
:ivar CHANNEL_SELECT: 8
"""

ACTION_ROW = 1
BUTTON = 2
SELECT = 3
SELECT = STRING_SELECT = 3
INPUT_TEXT = 4
USER_SELECT = 5
ROLE_SELECT = 6
MENTIONABLE_SELECT = 7
CHANNEL_SELECT = 8


class ButtonStyle(IntEnum):
Expand Down
61 changes: 41 additions & 20 deletions interactions/client/models/component.py
Original file line number Diff line number Diff line change
Expand Up @@ -77,26 +77,31 @@ class SelectMenu(ComponentMixin):
placeholder="Check out my options. :)",
custom_id="menu_component",
)
:ivar ComponentType type: The type of select menu. Always defaults to ``3``.
:ivar ComponentType type: The type of select menu. If not given, it defaults to ``ComponentType.SELECT`` (``STRING_SELECT``)
:ivar str custom_id: The customized "ID" of the select menu.
:ivar List[SelectOption] options: The list of select options in the select menu.
:ivar Optional[List[SelectOption]] options: The list of select options in the select menu. This only applies to String-based selects.
:ivar Optional[str] placeholder?: The placeholder of the select menu.
:ivar Optional[int] min_values?: The minimum "options"/values to choose from the component.
:ivar Optional[int] max_values?: The maximum "options"/values to choose from the component.
:ivar Optional[bool] disabled?: Whether the select menu is unable to be used.
:ivar Optional[List[int]] channel_types: Optional channel types to filter/whitelist. Only works with the CHANNEL_SELECT type.
"""

type: ComponentType = field(converter=ComponentType, default=ComponentType.SELECT)
custom_id: str = field()
options: List[SelectOption] = field(converter=convert_list(SelectOption))
options: Optional[List[SelectOption]] = field(
converter=convert_list(SelectOption), default=None
)
placeholder: Optional[str] = field(default=None)
min_values: Optional[int] = field(default=None)
max_values: Optional[int] = field(default=None)
disabled: Optional[bool] = field(default=None)
channel_types: Optional[List[int]] = field(default=None)

def __attrs_post_init__(self) -> None:
self._json.update({"type": self.type.value})
self._json.update({"options": [option._json for option in self.options]})
if self.options:
self._json.update({"options": [option._json for option in self.options]})


@define()
Expand Down Expand Up @@ -284,10 +289,14 @@ class ActionRow(ComponentMixin):
def __attrs_post_init__(self) -> None:
for component in self.components:
if isinstance(component, SelectMenu):
component._json["options"] = [
option._json if isinstance(option, SelectOption) else option
for option in component._json["options"]
]
component._json["options"] = (
[
option._json if isinstance(option, SelectOption) else option
for option in component._json["options"]
]
if component._json.get("options")
else []
)
self.components = (
[Component(**component._json) for component in self.components]
if self._json.get("components")
Expand Down Expand Up @@ -323,10 +332,14 @@ def __check_action_row():
action_row if isinstance(action_row, list) else action_row.components
):
if isinstance(component, SelectMenu):
component._json["options"] = [
option if isinstance(option, dict) else option._json
for option in component.options
]
component._json["options"] = (
[
option if isinstance(option, dict) else option._json
for option in component.options
]
if component._json.get("options")
else []
)

_components.append(
{
Expand Down Expand Up @@ -367,10 +380,14 @@ def __check_components():
):
for component in components:
if isinstance(component, SelectMenu):
component._json["options"] = [
options if isinstance(options, dict) else options._json
for options in component._json["options"]
]
component._json["options"] = (
[
options if isinstance(options, dict) else options._json
for options in component._json["options"]
]
if component._json.get("options")
else []
)

_components = [
{
Expand All @@ -397,10 +414,14 @@ def __check_components():
return _components
elif isinstance(components, SelectMenu):
_components: List[dict] = [{"type": 1, "components": []}]
components._json["options"] = [
options if isinstance(options, dict) else options._json
for options in components._json["options"]
]
components._json["options"] = (
[
options if isinstance(options, dict) else options._json
for options in components._json["options"]
]
if components._json.get("options")
else []
)

_components[0]["components"] = (
[components._json]
Expand Down