feat(bugs): impl buttons & editing
vi v@vt3e.cat
Thu, 26 Feb 2026 05:09:39 +0000
6 files changed,
401 insertions(+),
39 deletions(-)
M
src/interactions/commands/bug/index.ts
→
src/interactions/commands/bug/index.ts
@@ -6,7 +6,14 @@ type ModalSubmitInteraction,
SlashCommandBuilder, } from "discord.js"; import { buildReportModal } from "./_shared"; -import { handleNewBugModal } from "./modals"; +import { + handleCloseButton, + handleDeleteButton, + handleEditButton, + handleOpenButton, + handleTrelloButton, +} from "./buttons"; +import { handleEditModal, handleNewBugModal } from "./modals"; const commandData = new SlashCommandBuilder() .setName("bug")@@ -54,16 +61,19 @@ const [, action] = interaction.customId.split(":");
switch (action) { case "close": - // await handleCloseButton(client, interaction); + await handleCloseButton(client, interaction); break; case "open": - // await handleOpenButton(client, interaction); + await handleOpenButton(client, interaction); break; case "edit": - // await handleEditButton(client, interaction); + await handleEditButton(client, interaction); break; case "delete": - // await handleDeleteButton(client, interaction); + await handleDeleteButton(client, interaction); + break; + case "trello": + await handleTrelloButton(client, interaction); break; default: await interaction.reply({@@ -78,10 +88,9 @@ client: Client,
interaction: ModalSubmitInteraction, ) { const [, action] = interaction.customId.split(":"); - console.log(interaction.customId); switch (action) { case "edit": - // await handleEditModal(client, interaction); + await handleEditModal(client, interaction); break; case "report": await handleNewBugModal(client, interaction);
M
src/interactions/commands/bug/modals.ts
→
src/interactions/commands/bug/modals.ts
@@ -7,6 +7,7 @@ INPUT_IDS,
MODAL_IDS, VALIDATION, constructContainer, + updateBugEmbed, } from "./_shared"; export async function handleNewBugModal(@@ -68,7 +69,6 @@ const channel = await interaction.guild?.channels.fetch(channelId);
if (!channel || !channel.isSendable()) return; // send message - // TODO)) buttons const message = await channel.send({ components: [container], flags: ["IsComponentsV2"],@@ -99,3 +99,93 @@ interaction.editReply(
`Bug #${paddedNumber} created successfully! Find it here: ${message.url}`, ); } + +export async function handleEditModal( + client: Client, + interaction: ModalSubmitInteraction, +) { + if (!interaction.guildId) return; + + const parts = interaction.customId.split(":"); + const id = parts[2]; + if (!id) { + await interaction.reply({ + content: "❌ Could not determine bug id.", + flags: ["Ephemeral"], + }); + return; + } + + const title = interaction.fields.getTextInputValue(INPUT_IDS.TITLE); + const description = interaction.fields.getTextInputValue( + INPUT_IDS.DESCRIPTION, + ); + const affected = interaction.fields.getStringSelectValues(INPUT_IDS.AFFECTED); + + if ( + title.length > VALIDATION.TITLE_MAX_LENGTH || + description.length > VALIDATION.DESCRIPTION_MAX_LENGTH + ) { + await interaction.reply({ + content: "❌ Input too long.", + flags: ["Ephemeral"], + }); + return; + } + + const parsedId = Number(id); + if (Number.isNaN(parsedId)) { + await interaction.reply({ + content: "❌ Invalid bug id.", + flags: ["Ephemeral"], + }); + return; + } + + await db + .update(bugs) + .set({ + title, + description, + projects: [...affected], + updatedAt: new Date(), + }) + .where(eq(bugs.id, parsedId)); + + const [updated] = await db.select().from(bugs).where(eq(bugs.id, parsedId)); + if (!updated) { + await interaction.reply({ + content: "❌ Failed to fetch updated bug.", + flags: ["Ephemeral"], + }); + return; + } + + const { data, exists } = await getGuild(interaction.guildId); + if (!exists) { + await interaction.reply({ + content: + "✅ Bug updated, but guild configuration missing for updating the public message.", + flags: ["Ephemeral"], + }); + return; + } + const channelId = data.bug_channel_id; + if (!channelId) { + await interaction.reply({ + content: + "✅ Bug updated, but no bug channel configured to update message.", + flags: ["Ephemeral"], + }); + return; + } + + if (updated.messageId) { + await updateBugEmbed(client, updated, updated.messageId, channelId); + } + + await interaction.reply({ + content: `✅ Bug #${updated.bugNumber.toString().padStart(4, "0")} updated.`, + flags: ["Ephemeral"], + }); +}
M
src/utils/components.ts
→
src/utils/components.ts
@@ -1,3 +1,5 @@
+import { TextDisplayBuilder, ThumbnailBuilder } from "discord.js"; + export function makeComponentId( cmd: unknown, ...parts: Array<string | number>@@ -17,3 +19,10 @@ export function parseComponentId(customId: string) {
const [commandName, ...parts] = customId.split(":"); return { commandName, parts }; } + +export function text(content: string) { + return new TextDisplayBuilder().setContent(content); +} +export function thumbnail(url?: string) { + return url ? new ThumbnailBuilder().setURL(url) : undefined; +}