Skip to content

Commit 60c2ead

Browse files
committed
Add improved list ui
1 parent 86cacb1 commit 60c2ead

File tree

5 files changed

+83
-28
lines changed

5 files changed

+83
-28
lines changed

src/infrastructure/discord/commands/myIssues.ts

Lines changed: 37 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import logger from "@config/logger";
44
import githubDiscordMapJson from "../../../../data/githubDiscordMap.json";
55
import { can } from "../authz";
66
import { buildIssueButtonRow } from "../builders";
7+
import { formatDiscordDate } from "../webhookMessages";
78

89
// Update type to reflect new structure
910
const githubDiscordMap: {
@@ -16,7 +17,13 @@ const githubDiscordMap: {
1617

1718
export const data = new SlashCommandBuilder()
1819
.setName("my-issues")
19-
.setDescription("List all GitHub project issues assigned to you");
20+
.setDescription("List all GitHub project issues assigned to you")
21+
.addIntegerOption((option) =>
22+
option
23+
.setName("index")
24+
.setDescription("Index of the specific issue to display")
25+
.setRequired(false),
26+
);
2027

2128
export async function execute(interaction: CommandInteraction) {
2229
if (!can(interaction)) {
@@ -29,7 +36,6 @@ export async function execute(interaction: CommandInteraction) {
2936

3037
const discordUserId = interaction.user.id;
3138

32-
// Find GitHub username from Discord ID using the new structure
3339
const githubUsername = Object.values(githubDiscordMap).find(
3440
(entry) => entry.discordId === discordUserId,
3541
)?.githubUsername;
@@ -72,25 +78,47 @@ export async function execute(interaction: CommandInteraction) {
7278
return;
7379
}
7480

75-
await interaction.editReply({
76-
content: `📋 Showing ${assignedItems.length} issue(s) assigned to you:`,
77-
});
81+
// @ts-ignore // TODO: Fix type error
82+
const issueIndex = interaction.options.getInteger("index");
7883

79-
for (const item of assignedItems.slice(0, 5)) {
84+
if (issueIndex !== null) {
85+
if (issueIndex < 0 || issueIndex >= assignedItems.length) {
86+
await interaction.editReply({
87+
content: `❌ Invalid issue index. Please use a number between 0 and ${assignedItems.length - 1}.`,
88+
});
89+
return;
90+
}
91+
92+
const item = assignedItems[issueIndex];
8093
const link = item.url ?? "https://github.com/";
8194

8295
const buttons = buildIssueButtonRow(item.githubIssueId, link, [
8396
"unassign",
8497
"open",
8598
]);
8699

87-
await interaction.followUp({
88-
content: `## ${item.title}`,
100+
await interaction.editReply({
101+
content: `📌 **Issue #${issueIndex}**\n## ${item.title}`,
89102
components: [buttons],
90-
ephemeral: true,
91103
});
104+
105+
return;
92106
}
93107

108+
// Show list of issues with index numbers
109+
const list = assignedItems
110+
.map((item, idx) => {
111+
const titleWithLink = `[${item.title}](<${item.url}>)`;
112+
const due = item.dueDate ? formatDiscordDate(item.dueDate) : "";
113+
const status = item.status ?? "";
114+
115+
return `\`${idx}\` — ${titleWithLink}${due ? ` - ${due}` : ""}${status ? ` - ${status}` : ""}`;
116+
})
117+
.join("\n");
118+
await interaction.editReply({
119+
content: `📋 You have ${assignedItems.length} assigned issue(s):\n\n${list}\n\nUse \`/my-issues index:<number>\` to view a specific issue.`,
120+
});
121+
94122
logger.info({
95123
event: "myIssues.success",
96124
body: `${assignedItems.length} issues returned for ${githubUsername}`,

src/infrastructure/discord/commands/unassignedIssues.ts

Lines changed: 38 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import { filterForUnassigned } from "@src/items";
44
import logger from "@config/logger";
55
import { can } from "../authz";
66
import { buildIssueButtonRow } from "../builders";
7+
import { formatDiscordDate } from "../webhookMessages";
78

89
export const data = new SlashCommandBuilder()
910
.setName("unassigned-issues")
@@ -17,21 +18,29 @@ export const data = new SlashCommandBuilder()
1718
{ name: "Today", value: "today" },
1819
{ name: "All Time", value: "all-time" },
1920
),
21+
)
22+
.addIntegerOption((option) =>
23+
option
24+
.setName("index")
25+
.setDescription("Index of the specific issue to display")
26+
.setRequired(false),
2027
);
2128

2229
export async function execute(interaction: CommandInteraction) {
2330
if (!can(interaction)) {
2431
await interaction.reply({
25-
content: "You do not have permission to create an issue.",
32+
content: "You do not have permission to view issues.",
2633
ephemeral: true,
2734
});
2835
return;
2936
}
3037

3138
await interaction.deferReply({ ephemeral: true });
3239

33-
//@ts-ignore // TODO fix this ignore
40+
// @ts-ignore // TODO: Fix types
3441
const dateRange = interaction.options.getString("date-range", true);
42+
// @ts-ignore
43+
const issueIndex = interaction.options.getInteger("index");
3544

3645
const githubItemsResult = await GithubAPI.fetchProjectItems();
3746
if (githubItemsResult.err) {
@@ -67,27 +76,45 @@ export async function execute(interaction: CommandInteraction) {
6776
return;
6877
}
6978

70-
const limitedItems = unassignedItems.slice(0, 5);
71-
72-
await interaction.editReply({
73-
content: `📋 Showing ${limitedItems.length} unassigned issue(s).`,
74-
});
79+
if (issueIndex !== null) {
80+
if (issueIndex < 0 || issueIndex >= unassignedItems.length) {
81+
await interaction.editReply({
82+
content: `❌ Invalid issue index. Please use a number between 0 and ${unassignedItems.length - 1}.`,
83+
});
84+
return;
85+
}
7586

76-
for (const item of limitedItems) {
87+
const item = unassignedItems[issueIndex];
7788
const link = item.url ?? "https://github.com/";
7889

7990
const buttons = buildIssueButtonRow(item.githubIssueId, link, [
8091
"assign",
8192
"open",
8293
]);
8394

84-
await interaction.followUp({
85-
content: `## ${item.title}`,
95+
await interaction.editReply({
96+
content: `📌 **Issue #${issueIndex}**\n## ${item.title}`,
8697
components: [buttons],
87-
ephemeral: true,
8898
});
99+
100+
return;
89101
}
90102

103+
// Show list of issues with index numbers
104+
const list = unassignedItems
105+
.map((item, idx) => {
106+
const titleWithLink = `[${item.title}](<${item.url}>)`;
107+
const due = item.dueDate ? formatDiscordDate(item.dueDate) : "";
108+
const status = item.status ?? "";
109+
110+
return `\`${idx}\` — ${titleWithLink}${due ? ` - ${due}` : ""}${status ? ` - ${status}` : ""}`;
111+
})
112+
.join("\n");
113+
114+
await interaction.editReply({
115+
content: `📋 ${unassignedItems.length} unassigned issue(s) found:\n\n${list}\n\nUse \`/unassigned-issues date-range:${dateRange} index:<number>\` to view a specific issue.`,
116+
});
117+
91118
logger.info({
92119
event: "unassignedIssues.success",
93120
body: `${unassignedItems.length} unassigned issues returned.`,

src/infrastructure/discord/interactions/assigneeSelectInteraction.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,8 @@ export async function assigneeSelectInteraction(
4242

4343
if (result.err) {
4444
await interaction.reply({
45-
content: "❌ Failed to update assignee.",
45+
content:
46+
"❌ Failed to update assignee. Cannot assign to Draft Issues (yet).",
4647
ephemeral: true,
4748
});
4849
return;

src/infrastructure/discord/interactions/issueButtonInteraction.ts

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,9 @@ export async function issueButtonInteraction(
66
) {
77
if (!interaction.isButton()) return;
88

9-
const [_issue, action, githubId] = interaction.customId.split(":");
9+
const [_issue, action, githubIssueId] = interaction.customId.split(":");
1010

11-
if (!githubId) {
11+
if (!githubIssueId) {
1212
await interaction.reply({
1313
content: "⚠️ Invalid button ID.",
1414
ephemeral: true,
@@ -19,24 +19,23 @@ export async function issueButtonInteraction(
1919
switch (action) {
2020
case "edit":
2121
await interaction.reply({
22-
content: `✏️ Editing issue with ID \`${githubId}\` (not yet implemented).`,
22+
content: `✏️ Editing issue with ID \`${githubIssueId}\` (not yet implemented).`,
2323
ephemeral: true,
2424
});
2525
break;
2626

2727
case "assign":
28-
await promptAssigneeSelection(interaction, githubId);
28+
await promptAssigneeSelection(interaction, githubIssueId);
2929
break;
3030

3131
case "delete":
3232
await interaction.reply({
33-
content: `🗑️ Deleting issue \`${githubId}\` (not yet implemented).`,
33+
content: `🗑️ Deleting issue \`${githubIssueId}\` (not yet implemented).`,
3434
ephemeral: true,
3535
});
3636
break;
3737

3838
default:
39-
// logger.warn({ event: "button.unknownAction", action });
4039
await interaction.reply({
4140
content: `❌ Unknown action: \`${action}\``,
4241
ephemeral: true,

src/infrastructure/discord/webhookMessages.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ const githubUrlToDiscordId = (githubUrl: string) => {
6666
].discordId;
6767
};
6868

69-
const formatDiscordDate = (date: Date) => {
69+
export const formatDiscordDate = (date: Date) => {
7070
return `<t:${Math.floor(date.getTime() / 1000)}:D>`;
7171
};
7272

0 commit comments

Comments
 (0)