mirror of
				https://gitlab.com/Kwoth/nadekobot.git
				synced 2025-11-04 00:34:26 -05:00 
			
		
		
		
	add: Added dropdown menu for .cmds help and group help (part of cmds). Group help will no longer be on .h
fix: paginated response replies will no longer ping the author
This commit is contained in:
		@@ -4,7 +4,6 @@ using NadekoBot.Modules.Help.Services;
 | 
			
		||||
using Newtonsoft.Json;
 | 
			
		||||
using System.Text;
 | 
			
		||||
using Nadeko.Common.Medusa;
 | 
			
		||||
using Npgsql.EntityFrameworkCore.PostgreSQL.Storage.Internal.Mapping;
 | 
			
		||||
 | 
			
		||||
namespace NadekoBot.Modules.Help;
 | 
			
		||||
 | 
			
		||||
@@ -89,7 +88,7 @@ public sealed partial class Help : NadekoModule<HelpService>
 | 
			
		||||
 | 
			
		||||
        var menu = new SelectMenuBuilder()
 | 
			
		||||
                   .WithPlaceholder("Select a module to see its commands")
 | 
			
		||||
                   .WithCustomId("modules");
 | 
			
		||||
                   .WithCustomId("cmds:modules_select");
 | 
			
		||||
 | 
			
		||||
        foreach (var m in topLevelModules)
 | 
			
		||||
            menu.AddOption(m.Name, m.Name, GetModuleEmoji(m.Name));
 | 
			
		||||
@@ -102,7 +101,7 @@ public sealed partial class Help : NadekoModule<HelpService>
 | 
			
		||||
                var val = smc.Data.Values.FirstOrDefault();
 | 
			
		||||
                if (val is null)
 | 
			
		||||
                    return;
 | 
			
		||||
                
 | 
			
		||||
 | 
			
		||||
                await Commands(val);
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
@@ -242,10 +241,28 @@ public sealed partial class Help : NadekoModule<HelpService>
 | 
			
		||||
        // order by name
 | 
			
		||||
        var allowed = new List<CommandInfo>();
 | 
			
		||||
 | 
			
		||||
        foreach (var cmd in _cmds.Commands
 | 
			
		||||
                                 .Where(c => c.Module.GetTopLevelModule()
 | 
			
		||||
                                              .Name
 | 
			
		||||
                                              .StartsWith(module, StringComparison.InvariantCultureIgnoreCase)))
 | 
			
		||||
        var mdls = _cmds.Commands
 | 
			
		||||
                        .Where(c => c.Module.GetTopLevelModule()
 | 
			
		||||
                                     .Name
 | 
			
		||||
                                     .StartsWith(module, StringComparison.InvariantCultureIgnoreCase))
 | 
			
		||||
                        .ToArray();
 | 
			
		||||
 | 
			
		||||
        if (mdls.Length == 0)
 | 
			
		||||
        {
 | 
			
		||||
            var group = _cmds.Modules
 | 
			
		||||
                             .Where(x => x.Parent is not null)
 | 
			
		||||
                             .FirstOrDefault(x => string.Equals(x.Name.Replace("Commands", ""),
 | 
			
		||||
                                 module,
 | 
			
		||||
                                 StringComparison.InvariantCultureIgnoreCase));
 | 
			
		||||
 | 
			
		||||
            if (group is not null)
 | 
			
		||||
            {
 | 
			
		||||
                await Group(group);
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        foreach (var cmd in mdls)
 | 
			
		||||
        {
 | 
			
		||||
            var result = await _perms.CheckPermsAsync(ctx.Guild,
 | 
			
		||||
                ctx.Channel,
 | 
			
		||||
@@ -257,6 +274,7 @@ public sealed partial class Help : NadekoModule<HelpService>
 | 
			
		||||
                allowed.Add(cmd);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
        var cmds = allowed.OrderBy(c => c.Aliases[0])
 | 
			
		||||
                          .DistinctBy(x => x.Aliases[0])
 | 
			
		||||
                          .ToList();
 | 
			
		||||
@@ -296,55 +314,97 @@ public sealed partial class Help : NadekoModule<HelpService>
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        var cnt = 0;
 | 
			
		||||
        var groups = cmdsWithGroup.GroupBy(_ => cnt++ / 48).ToArray();
 | 
			
		||||
        var sb = new SelectMenuBuilder()
 | 
			
		||||
                 .WithCustomId("cmds:submodule_select")
 | 
			
		||||
                 .WithPlaceholder("Select a submodule to see detailed commands");
 | 
			
		||||
 | 
			
		||||
        var groups = cmdsWithGroup.ToArray();
 | 
			
		||||
        var embed = _sender.CreateEmbed().WithOkColor();
 | 
			
		||||
        foreach (var g in groups)
 | 
			
		||||
        {
 | 
			
		||||
            var last = g.Count();
 | 
			
		||||
            for (var i = 0; i < last; i++)
 | 
			
		||||
            {
 | 
			
		||||
                var transformed = g.ElementAt(i)
 | 
			
		||||
                                   .Select(x =>
 | 
			
		||||
                                   {
 | 
			
		||||
                                       //if cross is specified, and the command doesn't satisfy the requirements, cross it out
 | 
			
		||||
                                       if (opts.View == CommandsOptions.ViewType.Cross)
 | 
			
		||||
                                       {
 | 
			
		||||
                                           return $"{(succ.Contains(x) ? "✅" : "❌")} {prefix + x.Aliases[0]}";
 | 
			
		||||
                                       }
 | 
			
		||||
            sb.AddOption(g.Key, g.Key);
 | 
			
		||||
            var transformed = g
 | 
			
		||||
                .Select(x =>
 | 
			
		||||
                {
 | 
			
		||||
                    //if cross is specified, and the command doesn't satisfy the requirements, cross it out
 | 
			
		||||
                    if (opts.View == CommandsOptions.ViewType.Cross)
 | 
			
		||||
                    {
 | 
			
		||||
                        return $"{(succ.Contains(x) ? "✅" : "❌")} {prefix + x.Aliases[0]}";
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
                                       if (x.Aliases.Count == 1)
 | 
			
		||||
                                           return prefix + x.Aliases[0];
 | 
			
		||||
 | 
			
		||||
                                       return prefix + x.Aliases[0] + " | " + prefix + x.Aliases[1];
 | 
			
		||||
                                   });
 | 
			
		||||
                    if (x.Aliases.Count == 1)
 | 
			
		||||
                        return prefix + x.Aliases[0];
 | 
			
		||||
 | 
			
		||||
                embed.AddField(g.ElementAt(i).Key, "" + string.Join("\n", transformed) + "", true);
 | 
			
		||||
            }
 | 
			
		||||
                    return prefix + x.Aliases[0] + " | " + prefix + x.Aliases[1];
 | 
			
		||||
                });
 | 
			
		||||
 | 
			
		||||
            embed.AddField(g.Key, "" + string.Join("\n", transformed) + "", true);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        embed.WithFooter(GetText(strs.commands_instr(prefix)));
 | 
			
		||||
        await Response().Embed(embed).SendAsync();
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
        var inter = _inter.Create(ctx.User.Id,
 | 
			
		||||
            sb,
 | 
			
		||||
            async (smc) =>
 | 
			
		||||
            {
 | 
			
		||||
                var groupName = smc.Data.Values.FirstOrDefault();
 | 
			
		||||
                var mdl = _cmds.Modules.FirstOrDefault(x
 | 
			
		||||
                    => string.Equals(x.Name.Replace("Commands", ""), groupName, StringComparison.InvariantCultureIgnoreCase));
 | 
			
		||||
                await smc.DeferAsync();
 | 
			
		||||
                await Group(mdl);
 | 
			
		||||
            }
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        await Response().Embed(embed).Interaction(inter).SendAsync();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private async Task Group(ModuleInfo group)
 | 
			
		||||
    {
 | 
			
		||||
        var eb = _sender.CreateEmbed()
 | 
			
		||||
                        .WithTitle(GetText(strs.cmd_group_commands(group.Name)))
 | 
			
		||||
                        .WithOkColor();
 | 
			
		||||
        var menu = new SelectMenuBuilder()
 | 
			
		||||
                   .WithCustomId("cmds:group_select")
 | 
			
		||||
                   .WithPlaceholder("Select a command to see its details");
 | 
			
		||||
 | 
			
		||||
        foreach (var cmd in group.Commands.DistinctBy(x => x.Aliases[0]))
 | 
			
		||||
        {
 | 
			
		||||
            string cmdName;
 | 
			
		||||
            if (cmd.Aliases.Count > 1)
 | 
			
		||||
                cmdName = Format.Code(prefix + cmd.Aliases[0]) + " | " + Format.Code(prefix + cmd.Aliases[1]);
 | 
			
		||||
            else
 | 
			
		||||
                cmdName = Format.Code(prefix + cmd.Aliases.First());
 | 
			
		||||
 | 
			
		||||
            eb.AddField(cmdName, cmd.RealSummary(_strings, _medusae, Culture, prefix));
 | 
			
		||||
            menu.AddOption(prefix + cmd.Aliases[0], cmd.Aliases[0]);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        await Response().Embed(eb).SendAsync();
 | 
			
		||||
        var inter = _inter.Create(ctx.User.Id,
 | 
			
		||||
            menu,
 | 
			
		||||
            async (smc) =>
 | 
			
		||||
            {
 | 
			
		||||
                await smc.DeferAsync();
 | 
			
		||||
 | 
			
		||||
                await H(smc.Data.Values.FirstOrDefault());
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
        await Response()
 | 
			
		||||
              .Paginated()
 | 
			
		||||
              .Items(group.Commands.DistinctBy(x => x.Aliases[0]).ToArray())
 | 
			
		||||
              .PageSize(25)
 | 
			
		||||
              .Interaction(inter)
 | 
			
		||||
              .Page((items, _) =>
 | 
			
		||||
              {
 | 
			
		||||
                  var eb = _sender.CreateEmbed()
 | 
			
		||||
                                  .WithTitle(GetText(strs.cmd_group_commands(group.Name)))
 | 
			
		||||
                                  .WithOkColor();
 | 
			
		||||
 | 
			
		||||
                  foreach (var cmd in items)
 | 
			
		||||
                  {
 | 
			
		||||
                      string cmdName;
 | 
			
		||||
                      if (cmd.Aliases.Count > 1)
 | 
			
		||||
                          cmdName = Format.Code(prefix + cmd.Aliases[0]) + " | " + Format.Code(prefix + cmd.Aliases[1]);
 | 
			
		||||
                      else
 | 
			
		||||
                          cmdName = Format.Code(prefix + cmd.Aliases.First());
 | 
			
		||||
 | 
			
		||||
                      eb.AddField(cmdName, cmd.RealSummary(_strings, _medusae, Culture, prefix));
 | 
			
		||||
                  }
 | 
			
		||||
 | 
			
		||||
                  return eb;
 | 
			
		||||
              })
 | 
			
		||||
              .SendAsync();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    [Cmd]
 | 
			
		||||
@@ -364,12 +424,9 @@ public sealed partial class Help : NadekoModule<HelpService>
 | 
			
		||||
 | 
			
		||||
        var group = _cmds.Modules
 | 
			
		||||
                         .SelectMany(x => x.Submodules)
 | 
			
		||||
                         .FirstOrDefault(x => string.Equals(x.Name?.Replace("Commands", string.Empty),
 | 
			
		||||
                                                  fail,
 | 
			
		||||
                                                  StringComparison.InvariantCultureIgnoreCase)
 | 
			
		||||
                                              || string.Equals(x.Group,
 | 
			
		||||
                                                  fail,
 | 
			
		||||
                                                  StringComparison.InvariantCultureIgnoreCase));
 | 
			
		||||
                         .FirstOrDefault(x => string.Equals(x.Group,
 | 
			
		||||
                             fail,
 | 
			
		||||
                             StringComparison.InvariantCultureIgnoreCase));
 | 
			
		||||
 | 
			
		||||
        if (group is not null)
 | 
			
		||||
        {
 | 
			
		||||
 
 | 
			
		||||
@@ -6,10 +6,10 @@ public sealed class NadekoButtonInteraction : NadekoInteraction
 | 
			
		||||
        DiscordSocketClient client,
 | 
			
		||||
        ulong authorId,
 | 
			
		||||
        ButtonBuilder button,
 | 
			
		||||
        Func<SocketMessageComponent, Task> onClick,
 | 
			
		||||
        Func<SocketMessageComponent, Task> onAction,
 | 
			
		||||
        bool onlyAuthor,
 | 
			
		||||
        bool singleUse = true)
 | 
			
		||||
        : base(client, authorId, button.CustomId, onClick, onlyAuthor, singleUse)
 | 
			
		||||
        : base(client, authorId, button.CustomId, onAction, onlyAuthor, singleUse)
 | 
			
		||||
    {
 | 
			
		||||
        Button = button;
 | 
			
		||||
    }
 | 
			
		||||
 
 | 
			
		||||
@@ -6,10 +6,10 @@ public sealed class NadekoSelectInteraction : NadekoInteraction
 | 
			
		||||
        DiscordSocketClient client,
 | 
			
		||||
        ulong authorId,
 | 
			
		||||
        SelectMenuBuilder menu,
 | 
			
		||||
        Func<SocketMessageComponent, Task> onClick,
 | 
			
		||||
        Func<SocketMessageComponent, Task> onAction,
 | 
			
		||||
        bool onlyAuthor,
 | 
			
		||||
        bool singleUse = true)
 | 
			
		||||
        : base(client, authorId, menu.CustomId, onClick, onlyAuthor, singleUse)
 | 
			
		||||
        : base(client, authorId, menu.CustomId, onAction, onlyAuthor, singleUse)
 | 
			
		||||
    {
 | 
			
		||||
        Menu = menu;
 | 
			
		||||
    }
 | 
			
		||||
 
 | 
			
		||||
@@ -3,7 +3,7 @@
 | 
			
		||||
public abstract class NadekoInteraction
 | 
			
		||||
{
 | 
			
		||||
    private readonly ulong _authorId;
 | 
			
		||||
    private readonly Func<SocketMessageComponent, Task> _onClick;
 | 
			
		||||
    private readonly Func<SocketMessageComponent, Task> _onAction;
 | 
			
		||||
    private readonly bool _onlyAuthor;
 | 
			
		||||
    public DiscordSocketClient Client { get; }
 | 
			
		||||
 | 
			
		||||
@@ -17,13 +17,13 @@ public abstract class NadekoInteraction
 | 
			
		||||
        DiscordSocketClient client,
 | 
			
		||||
        ulong authorId,
 | 
			
		||||
        string customId,
 | 
			
		||||
        Func<SocketMessageComponent, Task> onClick,
 | 
			
		||||
        Func<SocketMessageComponent, Task> onAction,
 | 
			
		||||
        bool onlyAuthor,
 | 
			
		||||
        bool singleUse = true)
 | 
			
		||||
    {
 | 
			
		||||
        _authorId = authorId;
 | 
			
		||||
        _customId = customId;
 | 
			
		||||
        _onClick = onClick;
 | 
			
		||||
        _onAction = onAction;
 | 
			
		||||
        _onlyAuthor = onlyAuthor;
 | 
			
		||||
        _singleUse = singleUse;
 | 
			
		||||
        _interactionCompletedSource = new(TaskCreationOptions.RunContinuationsAsynchronously);
 | 
			
		||||
@@ -61,12 +61,19 @@ public abstract class NadekoInteraction
 | 
			
		||||
 | 
			
		||||
        _ = Task.Run(async () =>
 | 
			
		||||
        {
 | 
			
		||||
            _interactionCompletedSource.TrySetResult(true);
 | 
			
		||||
            await ExecuteOnActionAsync(smc);
 | 
			
		||||
 | 
			
		||||
            if (!smc.HasResponded)
 | 
			
		||||
            try
 | 
			
		||||
            {
 | 
			
		||||
                await smc.DeferAsync();
 | 
			
		||||
                _interactionCompletedSource.TrySetResult(true);
 | 
			
		||||
                await ExecuteOnActionAsync(smc);
 | 
			
		||||
 | 
			
		||||
                if (!smc.HasResponded)
 | 
			
		||||
                {
 | 
			
		||||
                    await smc.DeferAsync();
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            catch (Exception ex)
 | 
			
		||||
            {
 | 
			
		||||
                Log.Warning(ex, "An exception occured while handling an interaction: {Message}", ex.Message);
 | 
			
		||||
            }
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
@@ -77,5 +84,5 @@ public abstract class NadekoInteraction
 | 
			
		||||
    public abstract void AddTo(ComponentBuilder cb);
 | 
			
		||||
 | 
			
		||||
    public Task ExecuteOnActionAsync(SocketMessageComponent smc)
 | 
			
		||||
        => _onClick(smc);
 | 
			
		||||
        => _onAction(smc);
 | 
			
		||||
}
 | 
			
		||||
@@ -44,9 +44,8 @@ public partial class ResponseBuilder
 | 
			
		||||
                var leftButton = new ButtonBuilder()
 | 
			
		||||
                                 .WithStyle(ButtonStyle.Primary)
 | 
			
		||||
                                 .WithCustomId(BUTTON_LEFT)
 | 
			
		||||
                                 .WithDisabled(lastPage == 0)
 | 
			
		||||
                                 .WithEmote(InteractionHelpers.ArrowLeft)
 | 
			
		||||
                                 .WithDisabled(currentPage <= 0);
 | 
			
		||||
                                 .WithDisabled(lastPage == 0 || currentPage <= 0);
 | 
			
		||||
 | 
			
		||||
                var leftBtnInter = new NadekoButtonInteraction(_client,
 | 
			
		||||
                    model.User?.Id ?? 0,
 | 
			
		||||
@@ -78,9 +77,8 @@ public partial class ResponseBuilder
 | 
			
		||||
                var rightButton = new ButtonBuilder()
 | 
			
		||||
                                  .WithStyle(ButtonStyle.Primary)
 | 
			
		||||
                                  .WithCustomId(BUTTON_RIGHT)
 | 
			
		||||
                                  .WithDisabled(lastPage == 0)
 | 
			
		||||
                                  .WithEmote(InteractionHelpers.ArrowRight)
 | 
			
		||||
                                  .WithDisabled(lastPage == 0 || currentPage > lastPage);
 | 
			
		||||
                                  .WithDisabled(lastPage == 0 || currentPage >= lastPage);
 | 
			
		||||
 | 
			
		||||
                var rightBtnInter = new NadekoButtonInteraction(_client,
 | 
			
		||||
                    model.User?.Id ?? 0,
 | 
			
		||||
@@ -141,6 +139,7 @@ public partial class ResponseBuilder
 | 
			
		||||
                                 .SendMessageAsync(model.Text,
 | 
			
		||||
                                     embed: embed.Build(),
 | 
			
		||||
                                     components: cb.Build(),
 | 
			
		||||
                                     allowedMentions: model.SanitizeMentions,
 | 
			
		||||
                                     messageReference: model.MessageReference);
 | 
			
		||||
 | 
			
		||||
            if (lastPage == 0 && _paginationBuilder.InteractionFunc is null)
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user