Polish workflow message condition UI

Signed-off-by: Taylor Ho <taylorkmho@gmail.com>
This commit is contained in:
Taylor Ho
2026-08-14 15:47:20 -07:00
parent 45b27aa755
commit 64513361c2
4 changed files with 60 additions and 34 deletions
@@ -109,7 +109,7 @@ function valueLabel(field: string): string {
case "trigger_author":
return "Author";
case "trigger_message_id":
return "Message ID";
return "Message";
case "trigger_emoji":
return "Emoji";
case "trigger_timestamp":
@@ -187,22 +187,28 @@ function MessageConditionSummary({
);
}
const operator = operatorLabel(
editor.field,
editor.operator,
conditionOperatorsForField(editor.field).length === 2,
);
const message =
content === undefined
? compactValue(editor.value)
: messageSummaryContent(content);
const isExcluded = editor.operator === "not_equals";
return (
<span
className="max-w-40 truncate text-sm text-muted-foreground"
className="min-w-0 shrink text-sm text-muted-foreground"
title={content === undefined ? undefined : message}
>
{operator} “{message}”
<span
aria-hidden="true"
className={cn("block max-w-40 truncate", isExcluded && "line-through")}
data-testid="message-condition-summary"
>
“{message}”
</span>
<span className="sr-only">
{isExcluded ? "Excluded message: " : "Selected message: "}
{message}
</span>
</span>
);
}
@@ -104,26 +104,28 @@ function TriggerConfigFields({
);
case "reaction_added":
return (
<WorkflowConditionBuilder
channelId={workflowChannelId}
channels={channels}
disabled={disabled}
idPrefix="wf-trigger-filter"
matchAllLabel="All reactions"
onChange={(filter) =>
onUpdate({ ...trigger, emoji: undefined, filter })
}
triggerType={trigger.on}
value={
trigger.filter ??
buildConditionExpression({
field: "trigger_emoji",
operator: "equals",
value: trigger.emoji ?? "",
}) ??
""
}
/>
<div className="h-full">
<WorkflowConditionBuilder
channelId={workflowChannelId}
channels={channels}
disabled={disabled}
idPrefix="wf-trigger-filter"
matchAllLabel="All reactions"
onChange={(filter) =>
onUpdate({ ...trigger, emoji: undefined, filter })
}
triggerType={trigger.on}
value={
trigger.filter ??
buildConditionExpression({
field: "trigger_emoji",
operator: "equals",
value: trigger.emoji ?? "",
}) ??
""
}
/>
</div>
);
case "webhook":
return (
@@ -63,7 +63,7 @@ const FIELDS_BY_TRIGGER: Record<TriggerType, ConditionField[]> = {
reaction_added: [
{ label: "Reaction emoji", value: "trigger_emoji" },
AUTHOR_FIELD,
{ label: "Message ID", value: "trigger_message_id" },
{ label: "Message", value: "trigger_message_id" },
],
webhook: [{ label: "Webhook field…", value: "webhook_field" }],
schedule: [{ label: "Scheduled timestamp", value: "trigger_timestamp" }],
+23 -5
View File
@@ -291,9 +291,12 @@ test("builds a valid trigger condition from plain-language choices", async ({
for (const name of ["Author", "Custom"]) {
await expect(conditionFields.getByRole("button", { name })).toBeVisible();
}
for (const name of ["Channel ID", "Message ID"]) {
await expect(conditionFields.getByRole("button", { name })).toHaveCount(0);
}
await expect(
conditionFields.getByRole("button", { name: "Channel ID" }),
).toHaveCount(0);
await expect(
conditionFields.getByRole("button", { name: "Message", exact: true }),
).toHaveCount(0);
await conditionFields.getByRole("button", { name: "Message text" }).click();
await expect(allMessages).toHaveAttribute("aria-pressed", "false");
@@ -572,7 +575,7 @@ test("chooses a reaction emoji condition with the app emoji picker", async ({
inspector = dialog.getByTestId("workflow-node-inspector");
await expect(
inspector.getByRole("button", { name: "Message ID" }),
inspector.getByRole("button", { name: "Message", exact: true }),
).toBeVisible();
await expect(
inspector.getByRole("button", { name: "Channel ID" }),
@@ -613,7 +616,9 @@ test("chooses a reacted-to message from the workflow channel", async ({
name: "Reaction emoji",
});
const authorField = inspector.getByRole("button", { name: "Author" });
const messageField = inspector.getByRole("button", { name: "Message ID" });
const messageField = inspector.getByRole("button", {
name: /^Message(?:$| Selected message:| Excluded message:)/,
});
await emojiField.click();
await inspector
@@ -645,6 +650,19 @@ test("chooses a reacted-to message from the workflow channel", async ({
await expect(targetMessage).toBeVisible();
await targetMessage.click();
const messageSummary = messageField.getByTestId("message-condition-summary");
await expect(messageSummary).toHaveText("“React to me with a custom emoji”");
const messageEditor = inspector.getByTestId(
"workflow-condition-editor-trigger_message_id",
);
await messageEditor.getByText("is not", { exact: true }).click();
await expect(messageSummary).toHaveCSS(
"text-decoration-line",
"line-through",
);
await messageEditor.getByText("is", { exact: true }).click();
await expect(messageSummary).toHaveCSS("text-decoration-line", "none");
for (const field of [emojiField, authorField, messageField]) {
await expect(field).toHaveAttribute("aria-pressed", "true");
}