From 64513361c27e5257cf40221c9ade8a5efbafa58c Mon Sep 17 00:00:00 2001 From: Taylor Ho Date: Fri, 14 Aug 2026 15:47:20 -0700 Subject: [PATCH] Polish workflow message condition UI Signed-off-by: Taylor Ho --- .../workflows/ui/WorkflowConditionBuilder.tsx | 22 ++++++---- .../workflows/ui/WorkflowFormBuilder.tsx | 42 ++++++++++--------- .../ui/workflowConditionExpression.ts | 2 +- desktop/tests/e2e/workflows.spec.ts | 28 ++++++++++--- 4 files changed, 60 insertions(+), 34 deletions(-) diff --git a/desktop/src/features/workflows/ui/WorkflowConditionBuilder.tsx b/desktop/src/features/workflows/ui/WorkflowConditionBuilder.tsx index b837e5ee3..927379734 100644 --- a/desktop/src/features/workflows/ui/WorkflowConditionBuilder.tsx +++ b/desktop/src/features/workflows/ui/WorkflowConditionBuilder.tsx @@ -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 ( - {operator} “{message}” + + + {isExcluded ? "Excluded message: " : "Selected message: "} + {message} + ); } diff --git a/desktop/src/features/workflows/ui/WorkflowFormBuilder.tsx b/desktop/src/features/workflows/ui/WorkflowFormBuilder.tsx index aa29d8d6c..03f15cf50 100644 --- a/desktop/src/features/workflows/ui/WorkflowFormBuilder.tsx +++ b/desktop/src/features/workflows/ui/WorkflowFormBuilder.tsx @@ -104,26 +104,28 @@ function TriggerConfigFields({ ); case "reaction_added": return ( - - onUpdate({ ...trigger, emoji: undefined, filter }) - } - triggerType={trigger.on} - value={ - trigger.filter ?? - buildConditionExpression({ - field: "trigger_emoji", - operator: "equals", - value: trigger.emoji ?? "", - }) ?? - "" - } - /> +
+ + onUpdate({ ...trigger, emoji: undefined, filter }) + } + triggerType={trigger.on} + value={ + trigger.filter ?? + buildConditionExpression({ + field: "trigger_emoji", + operator: "equals", + value: trigger.emoji ?? "", + }) ?? + "" + } + /> +
); case "webhook": return ( diff --git a/desktop/src/features/workflows/ui/workflowConditionExpression.ts b/desktop/src/features/workflows/ui/workflowConditionExpression.ts index e49d7e22d..045149414 100644 --- a/desktop/src/features/workflows/ui/workflowConditionExpression.ts +++ b/desktop/src/features/workflows/ui/workflowConditionExpression.ts @@ -63,7 +63,7 @@ const FIELDS_BY_TRIGGER: Record = { 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" }], diff --git a/desktop/tests/e2e/workflows.spec.ts b/desktop/tests/e2e/workflows.spec.ts index ce40498da..96cf5ae68 100644 --- a/desktop/tests/e2e/workflows.spec.ts +++ b/desktop/tests/e2e/workflows.spec.ts @@ -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"); }