mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-08 01:31:23 +00:00
Slack: enrich modal input payload normalization
This commit is contained in:
@@ -519,6 +519,51 @@ describe("registerSlackInteractionEvents", () => {
|
||||
selected_date_time: 1_771_632_300,
|
||||
},
|
||||
},
|
||||
radio_block: {
|
||||
radio_select: {
|
||||
type: "radio_buttons",
|
||||
selected_option: {
|
||||
text: { type: "plain_text", text: "Blue" },
|
||||
value: "blue",
|
||||
},
|
||||
},
|
||||
},
|
||||
checks_block: {
|
||||
checks_select: {
|
||||
type: "checkboxes",
|
||||
selected_options: [
|
||||
{ text: { type: "plain_text", text: "A" }, value: "a" },
|
||||
{ text: { type: "plain_text", text: "B" }, value: "b" },
|
||||
],
|
||||
},
|
||||
},
|
||||
number_block: {
|
||||
number_input: {
|
||||
type: "number_input",
|
||||
value: "42.5",
|
||||
},
|
||||
},
|
||||
email_block: {
|
||||
email_input: {
|
||||
type: "email_text_input",
|
||||
value: "team@openclaw.ai",
|
||||
},
|
||||
},
|
||||
url_block: {
|
||||
url_input: {
|
||||
type: "url_text_input",
|
||||
value: "https://docs.openclaw.ai",
|
||||
},
|
||||
},
|
||||
richtext_block: {
|
||||
richtext_input: {
|
||||
type: "rich_text_input",
|
||||
rich_text_value: {
|
||||
type: "rich_text",
|
||||
elements: [{ type: "rich_text_section", elements: [] }],
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -531,11 +576,16 @@ describe("registerSlackInteractionEvents", () => {
|
||||
const payload = JSON.parse(eventText.replace("Slack interaction: ", "")) as {
|
||||
inputs: Array<{
|
||||
actionId: string;
|
||||
inputKind?: string;
|
||||
selectedValues?: string[];
|
||||
selectedLabels?: string[];
|
||||
selectedDate?: string;
|
||||
selectedTime?: string;
|
||||
selectedDateTime?: number;
|
||||
inputNumber?: number;
|
||||
inputEmail?: string;
|
||||
inputUrl?: string;
|
||||
richTextValue?: unknown;
|
||||
}>;
|
||||
};
|
||||
expect(payload.inputs).toEqual(
|
||||
@@ -551,6 +601,39 @@ describe("registerSlackInteractionEvents", () => {
|
||||
expect.objectContaining({ actionId: "date_select", selectedDate: "2026-02-16" }),
|
||||
expect.objectContaining({ actionId: "time_select", selectedTime: "12:45" }),
|
||||
expect.objectContaining({ actionId: "datetime_select", selectedDateTime: 1_771_632_300 }),
|
||||
expect.objectContaining({
|
||||
actionId: "radio_select",
|
||||
selectedValues: ["blue"],
|
||||
selectedLabels: ["Blue"],
|
||||
}),
|
||||
expect.objectContaining({
|
||||
actionId: "checks_select",
|
||||
selectedValues: ["a", "b"],
|
||||
selectedLabels: ["A", "B"],
|
||||
}),
|
||||
expect.objectContaining({
|
||||
actionId: "number_input",
|
||||
inputKind: "number",
|
||||
inputNumber: 42.5,
|
||||
}),
|
||||
expect.objectContaining({
|
||||
actionId: "email_input",
|
||||
inputKind: "email",
|
||||
inputEmail: "team@openclaw.ai",
|
||||
}),
|
||||
expect.objectContaining({
|
||||
actionId: "url_input",
|
||||
inputKind: "url",
|
||||
inputUrl: "https://docs.openclaw.ai/",
|
||||
}),
|
||||
expect.objectContaining({
|
||||
actionId: "richtext_input",
|
||||
inputKind: "rich_text",
|
||||
richTextValue: {
|
||||
type: "rich_text",
|
||||
elements: [{ type: "rich_text_section", elements: [] }],
|
||||
},
|
||||
}),
|
||||
]),
|
||||
);
|
||||
});
|
||||
|
||||
@@ -23,6 +23,7 @@ type InteractionSummary = {
|
||||
actionId: string;
|
||||
blockId?: string;
|
||||
actionType?: string;
|
||||
inputKind?: "text" | "number" | "email" | "url" | "rich_text";
|
||||
value?: string;
|
||||
selectedValues?: string[];
|
||||
selectedLabels?: string[];
|
||||
@@ -30,6 +31,10 @@ type InteractionSummary = {
|
||||
selectedTime?: string;
|
||||
selectedDateTime?: number;
|
||||
inputValue?: string;
|
||||
inputNumber?: number;
|
||||
inputEmail?: string;
|
||||
inputUrl?: string;
|
||||
richTextValue?: unknown;
|
||||
userId?: string;
|
||||
teamId?: string;
|
||||
triggerId?: string;
|
||||
@@ -43,6 +48,7 @@ type ModalInputSummary = {
|
||||
blockId: string;
|
||||
actionId: string;
|
||||
actionType?: string;
|
||||
inputKind?: "text" | "number" | "email" | "url" | "rich_text";
|
||||
value?: string;
|
||||
selectedValues?: string[];
|
||||
selectedLabels?: string[];
|
||||
@@ -50,6 +56,10 @@ type ModalInputSummary = {
|
||||
selectedTime?: string;
|
||||
selectedDateTime?: number;
|
||||
inputValue?: string;
|
||||
inputNumber?: number;
|
||||
inputEmail?: string;
|
||||
inputUrl?: string;
|
||||
richTextValue?: unknown;
|
||||
};
|
||||
|
||||
function readOptionValues(options: unknown): string[] | undefined {
|
||||
@@ -108,6 +118,7 @@ function summarizeAction(
|
||||
selected_time?: string;
|
||||
selected_date_time?: number;
|
||||
value?: string;
|
||||
rich_text_value?: unknown;
|
||||
};
|
||||
const actionType = typed.type;
|
||||
const selectedValues = uniqueNonEmptyStrings([
|
||||
@@ -124,9 +135,38 @@ function summarizeAction(
|
||||
...(typed.selected_option?.text?.text ? [typed.selected_option.text.text] : []),
|
||||
...(readOptionLabels(typed.selected_options) ?? []),
|
||||
]);
|
||||
const inputValue = typeof typed.value === "string" ? typed.value : undefined;
|
||||
const inputNumber =
|
||||
actionType === "number_input" && inputValue != null ? Number.parseFloat(inputValue) : undefined;
|
||||
const parsedNumber = Number.isFinite(inputNumber) ? inputNumber : undefined;
|
||||
const inputEmail =
|
||||
actionType === "email_text_input" && inputValue?.includes("@") ? inputValue : undefined;
|
||||
let inputUrl: string | undefined;
|
||||
if (actionType === "url_text_input" && inputValue) {
|
||||
try {
|
||||
// Normalize to a canonical URL string so downstream handlers do not need to reparse.
|
||||
inputUrl = new URL(inputValue).toString();
|
||||
} catch {
|
||||
inputUrl = undefined;
|
||||
}
|
||||
}
|
||||
const richTextValue = actionType === "rich_text_input" ? typed.rich_text_value : undefined;
|
||||
const inputKind =
|
||||
actionType === "number_input"
|
||||
? "number"
|
||||
: actionType === "email_text_input"
|
||||
? "email"
|
||||
: actionType === "url_text_input"
|
||||
? "url"
|
||||
: actionType === "rich_text_input"
|
||||
? "rich_text"
|
||||
: inputValue != null
|
||||
? "text"
|
||||
: undefined;
|
||||
|
||||
return {
|
||||
actionType,
|
||||
inputKind,
|
||||
value: typed.value,
|
||||
selectedValues: selectedValues.length > 0 ? selectedValues : undefined,
|
||||
selectedLabels: selectedLabels.length > 0 ? selectedLabels : undefined,
|
||||
@@ -134,7 +174,11 @@ function summarizeAction(
|
||||
selectedTime: typed.selected_time,
|
||||
selectedDateTime:
|
||||
typeof typed.selected_date_time === "number" ? typed.selected_date_time : undefined,
|
||||
inputValue: typed.value,
|
||||
inputValue,
|
||||
inputNumber: parsedNumber,
|
||||
inputEmail,
|
||||
inputUrl,
|
||||
richTextValue,
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user