mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-10 14:44:57 +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,
|
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 {
|
const payload = JSON.parse(eventText.replace("Slack interaction: ", "")) as {
|
||||||
inputs: Array<{
|
inputs: Array<{
|
||||||
actionId: string;
|
actionId: string;
|
||||||
|
inputKind?: string;
|
||||||
selectedValues?: string[];
|
selectedValues?: string[];
|
||||||
selectedLabels?: string[];
|
selectedLabels?: string[];
|
||||||
selectedDate?: string;
|
selectedDate?: string;
|
||||||
selectedTime?: string;
|
selectedTime?: string;
|
||||||
selectedDateTime?: number;
|
selectedDateTime?: number;
|
||||||
|
inputNumber?: number;
|
||||||
|
inputEmail?: string;
|
||||||
|
inputUrl?: string;
|
||||||
|
richTextValue?: unknown;
|
||||||
}>;
|
}>;
|
||||||
};
|
};
|
||||||
expect(payload.inputs).toEqual(
|
expect(payload.inputs).toEqual(
|
||||||
@@ -551,6 +601,39 @@ describe("registerSlackInteractionEvents", () => {
|
|||||||
expect.objectContaining({ actionId: "date_select", selectedDate: "2026-02-16" }),
|
expect.objectContaining({ actionId: "date_select", selectedDate: "2026-02-16" }),
|
||||||
expect.objectContaining({ actionId: "time_select", selectedTime: "12:45" }),
|
expect.objectContaining({ actionId: "time_select", selectedTime: "12:45" }),
|
||||||
expect.objectContaining({ actionId: "datetime_select", selectedDateTime: 1_771_632_300 }),
|
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;
|
actionId: string;
|
||||||
blockId?: string;
|
blockId?: string;
|
||||||
actionType?: string;
|
actionType?: string;
|
||||||
|
inputKind?: "text" | "number" | "email" | "url" | "rich_text";
|
||||||
value?: string;
|
value?: string;
|
||||||
selectedValues?: string[];
|
selectedValues?: string[];
|
||||||
selectedLabels?: string[];
|
selectedLabels?: string[];
|
||||||
@@ -30,6 +31,10 @@ type InteractionSummary = {
|
|||||||
selectedTime?: string;
|
selectedTime?: string;
|
||||||
selectedDateTime?: number;
|
selectedDateTime?: number;
|
||||||
inputValue?: string;
|
inputValue?: string;
|
||||||
|
inputNumber?: number;
|
||||||
|
inputEmail?: string;
|
||||||
|
inputUrl?: string;
|
||||||
|
richTextValue?: unknown;
|
||||||
userId?: string;
|
userId?: string;
|
||||||
teamId?: string;
|
teamId?: string;
|
||||||
triggerId?: string;
|
triggerId?: string;
|
||||||
@@ -43,6 +48,7 @@ type ModalInputSummary = {
|
|||||||
blockId: string;
|
blockId: string;
|
||||||
actionId: string;
|
actionId: string;
|
||||||
actionType?: string;
|
actionType?: string;
|
||||||
|
inputKind?: "text" | "number" | "email" | "url" | "rich_text";
|
||||||
value?: string;
|
value?: string;
|
||||||
selectedValues?: string[];
|
selectedValues?: string[];
|
||||||
selectedLabels?: string[];
|
selectedLabels?: string[];
|
||||||
@@ -50,6 +56,10 @@ type ModalInputSummary = {
|
|||||||
selectedTime?: string;
|
selectedTime?: string;
|
||||||
selectedDateTime?: number;
|
selectedDateTime?: number;
|
||||||
inputValue?: string;
|
inputValue?: string;
|
||||||
|
inputNumber?: number;
|
||||||
|
inputEmail?: string;
|
||||||
|
inputUrl?: string;
|
||||||
|
richTextValue?: unknown;
|
||||||
};
|
};
|
||||||
|
|
||||||
function readOptionValues(options: unknown): string[] | undefined {
|
function readOptionValues(options: unknown): string[] | undefined {
|
||||||
@@ -108,6 +118,7 @@ function summarizeAction(
|
|||||||
selected_time?: string;
|
selected_time?: string;
|
||||||
selected_date_time?: number;
|
selected_date_time?: number;
|
||||||
value?: string;
|
value?: string;
|
||||||
|
rich_text_value?: unknown;
|
||||||
};
|
};
|
||||||
const actionType = typed.type;
|
const actionType = typed.type;
|
||||||
const selectedValues = uniqueNonEmptyStrings([
|
const selectedValues = uniqueNonEmptyStrings([
|
||||||
@@ -124,9 +135,38 @@ function summarizeAction(
|
|||||||
...(typed.selected_option?.text?.text ? [typed.selected_option.text.text] : []),
|
...(typed.selected_option?.text?.text ? [typed.selected_option.text.text] : []),
|
||||||
...(readOptionLabels(typed.selected_options) ?? []),
|
...(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 {
|
return {
|
||||||
actionType,
|
actionType,
|
||||||
|
inputKind,
|
||||||
value: typed.value,
|
value: typed.value,
|
||||||
selectedValues: selectedValues.length > 0 ? selectedValues : undefined,
|
selectedValues: selectedValues.length > 0 ? selectedValues : undefined,
|
||||||
selectedLabels: selectedLabels.length > 0 ? selectedLabels : undefined,
|
selectedLabels: selectedLabels.length > 0 ? selectedLabels : undefined,
|
||||||
@@ -134,7 +174,11 @@ function summarizeAction(
|
|||||||
selectedTime: typed.selected_time,
|
selectedTime: typed.selected_time,
|
||||||
selectedDateTime:
|
selectedDateTime:
|
||||||
typeof typed.selected_date_time === "number" ? typed.selected_date_time : undefined,
|
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