fix(discord): preserve disabled link buttons

This commit is contained in:
OpenClaw Contributor
2026-05-19 11:45:36 -04:00
committed by clawsweeper
parent 4b15734215
commit 6ae1398c52
4 changed files with 60 additions and 6 deletions
@@ -60,6 +60,7 @@ function createButtonComponent(params: {
class DynamicLinkButton extends LinkButton {
label = params.spec.label;
url = linkUrl;
override disabled = params.spec.disabled ?? false;
}
return { component: new DynamicLinkButton() };
}
+36 -1
View File
@@ -1,4 +1,4 @@
import { MessageFlags } from "discord-api-types/v10";
import { ButtonStyle, MessageFlags } from "discord-api-types/v10";
import { beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
let clearDiscordComponentEntries: typeof import("./components-registry.js").clearDiscordComponentEntries;
@@ -60,6 +60,41 @@ describe("discord components", () => {
expect(result.modals[0]?.allowedUsers).toEqual(["discord:user-1"]);
});
it("serializes disabled link buttons", () => {
const spec = readDiscordComponentSpec({
blocks: [
{
type: "actions",
buttons: [
{
label: "Open docs",
style: "link",
url: "https://example.com/docs",
disabled: true,
},
],
},
],
});
if (!spec) {
throw new Error("Expected component spec to be parsed");
}
const result = buildDiscordComponentMessage({ spec });
const serialized = result.components[0]?.serialize() as
| { components?: Array<{ components?: Array<Record<string, unknown>> }> }
| undefined;
const button = serialized?.components?.[0]?.components?.[0];
expect(button).toMatchObject({
label: "Open docs",
style: ButtonStyle.Link,
url: "https://example.com/docs",
disabled: true,
});
expect(result.entries).toHaveLength(0);
});
it("requires options for modal select fields", () => {
expect(() =>
readDiscordComponentSpec({
@@ -589,7 +589,10 @@ describe("discordOutbound", () => {
blocks: [
{
type: "buttons",
buttons: [{ label: "Already handled", value: "done", disabled: true }],
buttons: [
{ label: "Already handled", value: "done", disabled: true },
{ label: "Open docs", url: "https://example.com/docs", disabled: true },
],
},
],
},
@@ -611,16 +614,22 @@ describe("discordOutbound", () => {
const discordData = payload.channelData?.discord as
| { presentationComponents?: { blocks?: Array<{ type?: string; buttons?: unknown[] }> } }
| undefined;
const button = discordData?.presentationComponents?.blocks?.find(
const buttons = discordData?.presentationComponents?.blocks?.find(
(block) => block.type === "actions",
)?.buttons?.[0];
)?.buttons;
expect(button).toEqual({
expect(buttons?.[0]).toEqual({
label: "Already handled",
style: "secondary",
callbackData: "done",
disabled: true,
});
expect(buttons?.[1]).toEqual({
label: "Open docs",
style: "link",
url: "https://example.com/docs",
disabled: true,
});
});
it("keeps replyToId on every internal component media send when replyToMode is all", async () => {
@@ -157,7 +157,10 @@ describe("buildDiscordInteractiveComponents", () => {
blocks: [
{
type: "buttons",
buttons: [{ label: "Already handled", value: "done", disabled: true }],
buttons: [
{ label: "Already handled", value: "done", disabled: true },
{ label: "Open docs", url: "https://example.com/docs", disabled: true },
],
},
],
}),
@@ -172,6 +175,12 @@ describe("buildDiscordInteractiveComponents", () => {
callbackData: "done",
disabled: true,
},
{
label: "Open docs",
style: "link",
url: "https://example.com/docs",
disabled: true,
},
],
},
],