Clarify workflow condition defaults

Signed-off-by: Taylor Ho <taylorkmho@gmail.com>
This commit is contained in:
Taylor Ho
2026-08-13 21:50:32 -07:00
parent 13c9c73ffa
commit 21268599d6
5 changed files with 36 additions and 33 deletions

View File

@@ -84,7 +84,7 @@ export function WorkflowConditionBuilder({
channels,
disabled,
idPrefix,
matchAllHint = "Leave empty to match every event.",
matchAllLabel = "All events",
onChange,
triggerType,
value,
@@ -92,7 +92,7 @@ export function WorkflowConditionBuilder({
channels: Channel[];
disabled?: boolean;
idPrefix: string;
matchAllHint?: string;
matchAllLabel?: string;
onChange: (value: string) => void;
triggerType: TriggerType;
value: string;
@@ -164,23 +164,26 @@ export function WorkflowConditionBuilder({
)
.join(", ");
const fieldOptions = [
{ label: matchAllLabel, value: "" },
...fields,
{ label: "Custom", value: CUSTOM_CONDITION_FIELD },
];
return (
<div className="space-y-3">
<fieldset className="space-y-1.5">
<legend className="text-xs font-medium text-muted-foreground">
Condition (optional)
</legend>
<fieldset>
<legend className="sr-only">Condition</legend>
<div className="grid grid-cols-2 gap-2.5">
{fieldOptions.map((field) => {
const isMatchAll = field.value === "";
const isCustom = field.value === CUSTOM_CONDITION_FIELD;
const isSelected = editor.field === field.value;
return (
<div
className={cn("relative", isCustom && "col-span-2")}
className={cn(
"relative",
(isMatchAll || isCustom) && "col-span-2",
)}
key={field.value}
>
<button
@@ -196,7 +199,8 @@ export function WorkflowConditionBuilder({
)}
disabled={disabled}
onClick={() => {
if (isSelected) {
if (isSelected) return;
if (isMatchAll) {
setEditor({
field: "",
operator: "contains",
@@ -358,8 +362,6 @@ export function WorkflowConditionBuilder({
) : null}
</>
) : null}
<p className="text-xs text-muted-foreground">{matchAllHint}</p>
</div>
);
}

View File

@@ -67,7 +67,9 @@ function TriggerConfigFields({
channels={channels}
disabled={disabled}
idPrefix="wf-trigger-filter"
matchAllHint="Leave empty to trigger on every message."
matchAllLabel={
trigger.on === "message_posted" ? "All messages" : "All diffs"
}
onChange={(filter) => onUpdate({ ...trigger, filter })}
triggerType={trigger.on}
value={trigger.filter ?? ""}

View File

@@ -78,20 +78,9 @@ export function WorkflowScheduleFields({
return (
<div className="space-y-3">
<div className="space-y-1.5">
<div className="flex items-center justify-between gap-3">
<p
className="text-xs font-medium text-muted-foreground"
id="wf-trigger-frequency-label"
>
Repeats
</p>
</div>
<div
aria-labelledby="wf-trigger-frequency-label"
className="grid grid-cols-2 gap-2.5"
role="radiogroup"
>
<fieldset>
<legend className="sr-only">Repeats</legend>
<div className="grid grid-cols-2 gap-2.5">
{SCHEDULE_FREQUENCIES.map((frequency) => {
const id = `wf-trigger-frequency-${frequency}`;
return (
@@ -139,7 +128,7 @@ export function WorkflowScheduleFields({
);
})}
</div>
</div>
</fieldset>
{schedule.frequency === "weekly" ? (
<fieldset className="space-y-1.5">

View File

@@ -386,7 +386,7 @@ export function WorkflowStepCard({
channels={channels}
disabled={disabled}
idPrefix={`${prefix}-condition`}
matchAllHint="Leave empty to run this step every time the workflow starts."
matchAllLabel="Every run"
onChange={(condition) => onUpdate({ ...step, condition })}
triggerType={triggerType}
value={step.condition ?? ""}

View File

@@ -130,7 +130,7 @@ async function createWorkflow(
}
if (options?.stepCondition) {
await dialog
.getByRole("group", { name: "Condition (optional)" })
.getByRole("group", { name: "Condition" })
.getByRole("button", { name: "Custom" })
.click();
await dialog.getByLabel("Custom expression").fill(options.stepCondition);
@@ -275,11 +275,15 @@ test("builds a valid trigger condition from plain-language choices", async ({
await dialog.getByRole("button", { name: /^Trigger:/ }).click();
const inspector = dialog.getByTestId("workflow-node-inspector");
const conditionFields = inspector.getByRole("group", {
name: "Condition (optional)",
});
const conditionFields = inspector.getByRole("group", { name: "Condition" });
const conditionOptions = conditionFields.getByRole("button");
await expect(conditionOptions).toHaveCount(5);
await expect(conditionOptions).toHaveCount(6);
const allMessages = conditionFields.getByRole("button", {
name: "All messages",
});
await expect(allMessages).toHaveAttribute("aria-pressed", "true");
await allMessages.click();
await expect(allMessages).toHaveAttribute("aria-pressed", "true");
await expect(
conditionFields.getByRole("button", { name: "Message text" }),
).toHaveAttribute("aria-pressed", "false");
@@ -288,6 +292,7 @@ test("builds a valid trigger condition from plain-language choices", async ({
}
await conditionFields.getByRole("button", { name: "Message text" }).click();
await expect(allMessages).toHaveAttribute("aria-pressed", "false");
await inspector.getByLabel("Text to match").fill('deploy "buzz"');
await dialog.getByRole("tab", { name: "YAML" }).click();
await expect(dialog.getByLabel("Workflow YAML")).toHaveValue(
@@ -297,7 +302,7 @@ test("builds a valid trigger condition from plain-language choices", async ({
await dialog.getByRole("tab", { name: "Form" }).click();
await dialog.getByRole("button", { name: /^Trigger:/ }).click();
const roundTrippedFields = inspector.getByRole("group", {
name: "Condition (optional)",
name: "Condition",
});
await expect(
roundTrippedFields.getByRole("button", { name: "Message text" }),
@@ -311,6 +316,11 @@ test("builds a valid trigger condition from plain-language choices", async ({
);
await expect(inspector.getByText(/Use an evalexpr expression/)).toBeVisible();
await customCondition.click();
await expect(customCondition).toHaveAttribute("aria-pressed", "true");
await expect(inspector.getByLabel("Custom expression")).toBeVisible();
await roundTrippedFields
.getByRole("button", { name: "All messages" })
.click();
await expect(customCondition).toHaveAttribute("aria-pressed", "false");
await expect(inspector.getByLabel("Custom expression")).not.toBeVisible();
});