Polish workflow trigger presentation

Signed-off-by: Taylor Ho <taylorkmho@gmail.com>
This commit is contained in:
Taylor Ho
2026-08-13 23:15:00 -07:00
parent 5c4a43ec22
commit 4f6ccb2890
5 changed files with 71 additions and 28 deletions
@@ -19,13 +19,16 @@ import { AnimatePresence, motion, useReducedMotion } from "motion/react";
import * as React from "react";
import { createPortal } from "react-dom";
import { useCustomEmoji } from "@/features/custom-emoji/hooks";
import { useUsersBatchQuery } from "@/features/profile/hooks";
import { resolveUserLabel } from "@/features/profile/lib/identity";
import { reactionEmojiUrl } from "@/shared/api/customEmoji";
import { useIdentityQuery } from "@/shared/api/hooks";
import { getEventById } from "@/shared/api/tauri";
import type { Channel } from "@/shared/api/types";
import { Button } from "@/shared/ui/button";
import { cn } from "@/shared/lib/cn";
import { rewriteRelayUrl } from "@/shared/lib/mediaUrl";
import {
DropdownMenu,
DropdownMenuContent,
@@ -496,6 +499,7 @@ export function WorkflowFormBuilder({
const shouldReduceMotion = useReducedMotion();
const previousModeRef = React.useRef(mode);
const identityQuery = useIdentityQuery();
const customEmoji = useCustomEmoji();
const parsedTriggerConditions = React.useMemo(
() =>
formState.trigger.filter
@@ -506,6 +510,17 @@ export function WorkflowFormBuilder({
: [],
[formState.trigger.filter, formState.trigger.on],
);
const triggerReactionCondition = parsedTriggerConditions?.find(
(condition) =>
condition.field === "trigger_emoji" && condition.operator === "equals",
);
const triggerReaction =
formState.trigger.on === "reaction_added"
? triggerReactionCondition?.value || formState.trigger.emoji
: undefined;
const triggerReactionUrl = triggerReaction
? reactionEmojiUrl(triggerReaction, customEmoji)
: undefined;
const triggerAuthorCondition = parsedTriggerConditions?.find(
(condition) => condition.field === "trigger_author",
);
@@ -735,11 +750,35 @@ export function WorkflowFormBuilder({
}
disabled={disabled}
icon={
<TriggerIcon
aria-hidden="true"
className="h-4 w-4"
data-testid={`workflow-trigger-icon-${formState.trigger.on}`}
/>
triggerReaction ? (
triggerReactionUrl ? (
<img
alt={triggerReaction}
className="h-7 w-7 object-contain"
data-testid="workflow-trigger-selected-reaction"
draggable={false}
src={rewriteRelayUrl(triggerReactionUrl)}
/>
) : (
<span
className={cn(
"max-w-8 overflow-hidden leading-none",
triggerReaction.startsWith(":")
? "text-xs"
: "text-2xl",
)}
data-testid="workflow-trigger-selected-reaction"
>
{triggerReaction}
</span>
)
) : (
<TriggerIcon
aria-hidden="true"
className="h-4 w-4"
data-testid={`workflow-trigger-icon-${formState.trigger.on}`}
/>
)
}
label={`Trigger: ${triggerDescription}`}
onAddAfter={(action) => insertStep(0, action)}
@@ -79,9 +79,9 @@ export const DEFAULT_FORM_STATE: WorkflowFormState = {
};
export const TRIGGER_LABELS: Record<TriggerType, string> = {
message_posted: "Message Posted",
reaction_added: "Reaction Added",
diff_posted: "Diff Posted",
message_posted: "Message posted",
reaction_added: "Reaction added",
diff_posted: "Diff posted",
webhook: "Webhook",
schedule: "Schedule",
};
@@ -28,7 +28,7 @@ test("describes selected trigger conditions on the workflow canvas", () => {
on: "reaction_added",
filter: 'trigger_emoji == "🔥"',
}),
"🔥 reaction added",
"Reaction added",
);
assert.equal(
@@ -50,20 +50,20 @@ test("describes selected trigger conditions on the workflow canvas", () => {
},
{ authorLabel: "Carl", messageLabel: "hey yourself" },
),
"👾 reaction added by Carl to “hey yourself”",
"Reaction added by Carl to “hey yourself”",
);
});
test("keeps the base label for unfiltered and custom triggers", () => {
assert.equal(
workflowTriggerDescription({ on: "message_posted" }),
"Message Posted",
"Message posted",
);
assert.equal(
workflowTriggerDescription({
on: "message_posted",
filter: "custom_variable == 1",
}),
"Message Posted",
"Message posted",
);
});
@@ -73,7 +73,7 @@ export function workflowTriggerDescription(
: [];
if (!conditions || conditions.length === 0) {
return trigger.on === "reaction_added" && trigger.emoji
? `${trigger.emoji} reaction added`
? eventPhrase
: baseLabel;
}
@@ -100,7 +100,7 @@ export function workflowTriggerDescription(
description =
emojiCondition.operator === "not_equals"
? `Any reaction except ${emojiCondition.value} added`
: `${emojiCondition.value} reaction added`;
: eventPhrase;
}
if (authorCondition) {
const author =
@@ -138,7 +138,7 @@ export function workflowTriggerDescription(
if (condition.field === "trigger_emoji") {
return condition.operator === "not_equals"
? `Any reaction except ${condition.value} added`
: `${condition.value} reaction added`;
: eventPhrase;
}
if (condition.field === "trigger_message_id") {
+17 -13
View File
@@ -3,9 +3,9 @@ import { expect, test } from "@playwright/test";
import { installMockBridge, TEST_IDENTITIES } from "../helpers/bridge";
const TRIGGER_OPTION_LABELS: Record<string, string> = {
diff_posted: "Diff Posted",
message_posted: "Message Posted",
reaction_added: "Reaction Added",
diff_posted: "Diff posted",
message_posted: "Message posted",
reaction_added: "Reaction added",
schedule: "Schedule",
webhook: "Webhook",
};
@@ -465,7 +465,7 @@ test("chooses and clears a reaction trigger with the app emoji picker", async ({
await dialog.getByRole("button", { name: /^Trigger:/ }).click();
const inspector = dialog.getByTestId("workflow-node-inspector");
await inspector.getByLabel("Trigger event").click();
await page.getByRole("menuitem", { name: "Reaction Added" }).click();
await page.getByRole("menuitem", { name: "Reaction added" }).click();
await inspector.getByRole("button", { name: "Reaction emoji" }).click();
const trigger = inspector.getByRole("button", {
@@ -479,11 +479,13 @@ test("chooses and clears a reaction trigger with the app emoji picker", async ({
await picker.getByRole("button", { name: ":buzz:" }).first().click();
await expect(trigger).toContainText(":buzz:");
const triggerNode = dialog.getByRole("button", {
name: "Trigger: Reaction added",
});
await expect(triggerNode).toBeVisible();
await expect(
dialog.getByRole("button", {
name: "Trigger: :buzz: reaction added",
}),
).toBeVisible();
triggerNode.getByTestId("workflow-trigger-selected-reaction"),
).toHaveAttribute("alt", ":buzz:");
await dialog.getByRole("tab", { name: "YAML" }).click();
await expect(dialog.getByLabel("Workflow YAML")).toHaveValue(/:buzz:/);
@@ -494,7 +496,9 @@ test("chooses and clears a reaction trigger with the app emoji picker", async ({
dialog.getByRole("button", { name: "Choose condition emoji" }),
).toContainText("Choose a reaction");
await expect(
dialog.getByRole("button", { name: "Trigger: Reaction Added" }),
dialog
.getByRole("button", { name: "Trigger: Reaction added" })
.getByTestId("workflow-trigger-icon-reaction_added"),
).toBeVisible();
});
@@ -543,7 +547,7 @@ test("chooses a reaction emoji condition with the app emoji picker", async ({
await dialog.getByRole("button", { name: /^Trigger:/ }).click();
let inspector = dialog.getByTestId("workflow-node-inspector");
await inspector.getByLabel("Trigger event").click();
await page.getByRole("menuitem", { name: "Reaction Added" }).click();
await page.getByRole("menuitem", { name: "Reaction added" }).click();
inspector = dialog.getByTestId("workflow-node-inspector");
await expect(
@@ -583,7 +587,7 @@ test("chooses a reacted-to message from the workflow channel", async ({
.click();
const inspector = dialog.getByTestId("workflow-node-inspector");
await inspector.getByLabel("Trigger event").click();
await page.getByRole("menuitem", { name: "Reaction Added" }).click();
await page.getByRole("menuitem", { name: "Reaction added" }).click();
const emojiField = inspector.getByRole("button", {
name: "Reaction emoji",
});
@@ -625,7 +629,7 @@ test("chooses a reacted-to message from the workflow channel", async ({
}
await expect(
dialog.getByRole("button", {
name: "Trigger: :buzz: reaction added by alice to “React to me with a custom emoji”",
name: "Trigger: Reaction added by alice to “React to me with a custom emoji”",
}),
).toBeVisible();
@@ -867,7 +871,7 @@ test("captures disabled diff workflows in the list UI", async ({ page }) => {
"When a matching diff is posted, wait for a moment",
);
await expect(card).toContainText(description);
await expect(card).toContainText("Diff Posted");
await expect(card).toContainText("Diff posted");
await expect(card).toContainText("disabled");
});