Add smart contextual autocomplete for admin role management
- Add autocomplete to /config roles add/remove commands - /config roles add only shows roles not currently self-assignable - /config roles remove only shows roles currently self-assignable - Filter out bot roles, @everyone, and unmanageable roles - Convert role parameter to string with autocomplete for better UX - Add role name validation and lookup in config command Admin Experience Improvements: - Smart role suggestions prevent duplicate/invalid selections - No more seeing roles already in the self-assignable list - Only see roles the bot can actually manage - Clean, focused autocomplete interface 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -112,10 +112,11 @@ module.exports = {
|
||||
{ name: 'Show current roles', value: 'list' }
|
||||
)
|
||||
)
|
||||
.addRoleOption(option =>
|
||||
.addStringOption(option =>
|
||||
option.setName('role')
|
||||
.setDescription('The role to add or remove (not needed for list/clear)')
|
||||
.setRequired(false)
|
||||
.setAutocomplete(true)
|
||||
)
|
||||
),
|
||||
|
||||
@@ -193,7 +194,7 @@ module.exports = {
|
||||
|
||||
case 'roles':
|
||||
const action = interaction.options.getString('action');
|
||||
const role = interaction.options.getRole('role');
|
||||
const roleName = interaction.options.getString('role');
|
||||
|
||||
if (action === 'list') {
|
||||
const allowedRoleIds = databaseService.getAllowedRoleIds(interaction.guild.id);
|
||||
@@ -240,13 +241,25 @@ module.exports = {
|
||||
break;
|
||||
}
|
||||
|
||||
if (!role) {
|
||||
if (!roleName) {
|
||||
return interaction.reply({
|
||||
content: '❌ You must specify a role for add/remove actions.',
|
||||
flags: [MessageFlags.Ephemeral]
|
||||
});
|
||||
}
|
||||
|
||||
// Find the role by name
|
||||
const role = interaction.guild.roles.cache.find(r =>
|
||||
r.name.toLowerCase() === roleName.toLowerCase()
|
||||
);
|
||||
|
||||
if (!role) {
|
||||
return interaction.reply({
|
||||
content: `❌ Role **${roleName}** not found on this server.`,
|
||||
flags: [MessageFlags.Ephemeral]
|
||||
});
|
||||
}
|
||||
|
||||
// Check if bot can manage this role
|
||||
if (!interaction.guild.members.me.permissions.has('ManageRoles') ||
|
||||
role.position >= interaction.guild.members.me.roles.highest.position) {
|
||||
@@ -290,5 +303,63 @@ module.exports = {
|
||||
await interaction.reply({ embeds: [embed] });
|
||||
|
||||
console.log(`Configuration updated for ${interaction.guild.name}: ${subcommand} by @${interaction.user.username}`);
|
||||
},
|
||||
|
||||
async autocomplete(interaction, guildConfig) {
|
||||
const subcommand = interaction.options.getSubcommand();
|
||||
|
||||
// Only handle autocomplete for roles subcommand
|
||||
if (subcommand !== 'roles') {
|
||||
return interaction.respond([]);
|
||||
}
|
||||
|
||||
const action = interaction.options.getString('action');
|
||||
const focusedValue = interaction.options.getFocused().toLowerCase();
|
||||
const databaseService = configManager.databaseService;
|
||||
|
||||
if (!databaseService) {
|
||||
return interaction.respond([]);
|
||||
}
|
||||
|
||||
// Get currently allowed role IDs
|
||||
const allowedRoleIds = databaseService.getAllowedRoleIds(interaction.guild.id);
|
||||
let availableRoles = [];
|
||||
|
||||
if (action === 'add') {
|
||||
// For add: show roles NOT currently in the allowed list
|
||||
const allRoles = interaction.guild.roles.cache
|
||||
.filter(role =>
|
||||
!role.managed && // Exclude bot/integration roles
|
||||
role.id !== interaction.guild.id && // Exclude @everyone
|
||||
!allowedRoleIds.includes(role.id) && // Exclude already allowed roles
|
||||
role.position < interaction.guild.members.me.roles.highest.position // Only manageable roles
|
||||
);
|
||||
|
||||
availableRoles = Array.from(allRoles.values());
|
||||
|
||||
} else if (action === 'remove') {
|
||||
// For remove: show roles currently in the allowed list
|
||||
for (const roleId of allowedRoleIds) {
|
||||
try {
|
||||
const role = await interaction.guild.roles.fetch(roleId);
|
||||
if (role) {
|
||||
availableRoles.push(role);
|
||||
}
|
||||
} catch (error) {
|
||||
// Role doesn't exist anymore, skip
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Filter based on what user has typed and limit to 25
|
||||
const filtered = availableRoles
|
||||
.filter(role => role.name.toLowerCase().includes(focusedValue))
|
||||
.slice(0, 25)
|
||||
.map(role => ({
|
||||
name: role.name,
|
||||
value: role.name
|
||||
}));
|
||||
|
||||
await interaction.respond(filtered);
|
||||
}
|
||||
};
|
||||
Reference in New Issue
Block a user