Component search fixes & improvements (#3123)

This commit is contained in:
Mihail Gribkov
2025-05-09 20:54:08 +03:00
committed by GitHub
parent 57cdec70bf
commit be8e6e0394
6 changed files with 109 additions and 11 deletions

View File

@@ -5,7 +5,7 @@ namespace Discord;
/// <summary>
/// Represents a <see cref="IMessageComponent"/> Row for child components to live in.
/// </summary>
public class ActionRowComponent : IMessageComponent
public class ActionRowComponent : INestedComponent, IMessageComponent
{
/// <inheritdoc/>
public ComponentType Type => ComponentType.ActionRow;

View File

@@ -341,13 +341,30 @@ public static class ComponentContainerExtensions
/// </returns>
public static ComponentT FindComponentById<ComponentT>(this IComponentContainer container, int id)
where ComponentT : class, IMessageComponentBuilder
=> container.Components
.OfType<ComponentT>()
.FirstOrDefault(x => x.Id == id)
?? container.Components
.OfType<IComponentContainer>()
.Select(x => x.FindComponentById<ComponentT>(id))
.FirstOrDefault(x => x is not null);
{
if (container is ComponentT cmp && cmp.Id == id)
return cmp;
foreach (var component in container.Components)
{
if (component.Id == id && component is ComponentT target)
return target;
if (component is SectionBuilder section
&& section.Accessory.Id == id
&& section.Accessory is ComponentT targetAccessory)
return targetAccessory;
if (component is IComponentContainer childContainer)
{
var childSearchResult = childContainer.FindComponentById<ComponentT>(id);
if (childSearchResult is not null)
return childSearchResult;
}
}
return null;
}
/// <summary>
/// Gets a <see cref="IEnumerable{T}">IEnumerable</see> containing ids of <see cref="IMessageComponentBuilder"/>
@@ -360,4 +377,71 @@ public static class ComponentContainerExtensions
.Concat(container.Components
.OfType<IComponentContainer>()
.SelectMany(x => x.GetComponentIds()));
/// <summary>
/// Finds the first <see cref="IMessageComponent"/> in the <see cref="INestedComponent"/>
/// or any of its child <see cref="INestedComponent"/>s with matching id.
/// </summary>
/// <returns>
/// The <see cref="IMessageComponent"/> with matching id, <see langword="null"/> otherwise.
/// </returns>
public static IMessageComponent FindComponentById(this INestedComponent container, int id)
=> container.FindComponentById<IMessageComponent>(id);
/// <summary>
/// Finds the first <c>ComponentT</c> in the <see cref="INestedComponent"/>
/// or any of its child <see cref="INestedComponent"/>s with matching id.
/// </summary>
/// <returns>
/// The <c>ComponentT</c> with matching id, <see langword="null"/> otherwise.
/// </returns>
public static ComponentT FindComponentById<ComponentT>(this INestedComponent container, int id)
where ComponentT : class, IMessageComponent
{
if (container is ComponentT cmp && cmp.Id == id)
return cmp;
return container.Components.FindComponentById<ComponentT>(id);
}
/// <summary>
/// Finds the first <c>ComponentT</c> in the <see cref="IEnumerable{IMessageComponent}"/>
/// or any of its child <see cref="INestedComponent"/>s with matching id.
/// </summary>
/// <returns>
/// The <c>ComponentT</c> with matching id, <see langword="null"/> otherwise.
/// </returns>
public static ComponentT FindComponentById<ComponentT>(this IEnumerable<IMessageComponent> components, int id)
where ComponentT : class, IMessageComponent
{
foreach (var component in components)
{
if (component.Id == id && component is ComponentT target)
return target;
if (component is SectionComponent section
&& section.Accessory.Id == id
&& section.Accessory is ComponentT targetAccessory)
return targetAccessory;
if (component is INestedComponent childContainer)
{
var childSearchResult = childContainer.FindComponentById<ComponentT>(id);
if (childSearchResult is not null)
return childSearchResult;
}
}
return null;
}
/// <summary>
/// Finds the first <see cref="IMessageComponent"/> in the <see cref="IEnumerable{IMessageComponent}"/>
/// or any of its child <see cref="INestedComponent"/>s with matching id.
/// </summary>
/// <returns>
/// The <see cref="IMessageComponent"/> with matching id, <see langword="null"/> otherwise.
/// </returns>
public static IMessageComponent FindComponentById(this IEnumerable<IMessageComponent> components, int id)
=> components.FindComponentById<IMessageComponent>(id);
}

View File

@@ -5,7 +5,7 @@ namespace Discord;
/// <summary>
/// Represents a container component.
/// </summary>
public class ContainerComponent : IMessageComponent
public class ContainerComponent : INestedComponent, IMessageComponent
{
/// <inheritdoc/>
public ComponentType Type => ComponentType.Container;

View File

@@ -0,0 +1,14 @@
using System.Collections.Generic;
namespace Discord;
/// <summary>
/// Represents a <see cref="IMessageComponent"/> containing child components.
/// </summary>
public interface INestedComponent
{
/// <summary>
/// Gets the child components in this container.
/// </summary>
IReadOnlyCollection<IMessageComponent> Components { get; }
}

View File

@@ -5,7 +5,7 @@ namespace Discord;
/// <summary>
/// Represents a component object used to send components with messages.
/// </summary>
public class MessageComponent
public class MessageComponent : INestedComponent
{
/// <summary>
/// Gets the components to be used in a message.

View File

@@ -5,7 +5,7 @@ namespace Discord;
/// <summary>
/// Represents a section component.
/// </summary>
public class SectionComponent : IMessageComponent
public class SectionComponent : INestedComponent, IMessageComponent
{
/// <inheritdoc/>
public ComponentType Type => ComponentType.Section;