Skip to content

feat(ui-v2): add CustomPostureSelect component with radio buttons for custom triggers#129

Open
tomerqodo wants to merge 3 commits into
qodo_combined-20260114-qodo-grep-copilot_base_featui-v2_add_custompostureselect_component_with_radio_buttons_for_custom_triggers_pr401from
qodo_combined-20260114-qodo-grep-copilot_head_featui-v2_add_custompostureselect_component_with_radio_buttons_for_custom_triggers_pr401
Open

feat(ui-v2): add CustomPostureSelect component with radio buttons for custom triggers#129
tomerqodo wants to merge 3 commits into
qodo_combined-20260114-qodo-grep-copilot_base_featui-v2_add_custompostureselect_component_with_radio_buttons_for_custom_triggers_pr401from
qodo_combined-20260114-qodo-grep-copilot_head_featui-v2_add_custompostureselect_component_with_radio_buttons_for_custom_triggers_pr401

Conversation

@tomerqodo
Copy link
Copy Markdown

Benchmark PR from qodo-benchmark#401

devin-ai-integration Bot and others added 3 commits January 1, 2026 15:21
… custom triggers

- Create CustomPostureSelect component with 'Observe' and 'Don't observe' radio buttons
- Update CustomTriggerFields to use the new component instead of PostureSelect dropdown
- Export CustomPostureSelect from trigger-step index
- Update tests to verify radio button labels are visible

Co-Authored-By: alex.s@prefect.io <ajstreed1@gmail.com>
- Move component to custom-posture-select/ directory with colocated files
- Add comprehensive unit tests for radio button rendering and posture change logic
- Add Storybook stories showing Reactive and Proactive states
- Tests verify value migration between expect/after fields and within default

Co-Authored-By: alex.s@prefect.io <ajstreed1@gmail.com>
@qodo-code-review
Copy link
Copy Markdown

Code Review by Qodo (Alpha)

🐞 Bugs (3) 📘 Rule Violations (1) 📎 Requirement Gaps (0) 💡 Suggestions (0)

Grey Divider


Action Required

1. `httpcore` version mismatch 📘 Rule Violation
Description
• The root pyproject.toml updates httpcore to >=1.0.6,<2.0.0 while client/pyproject.toml
  still pins httpcore at >=1.0.5,<2.0.0.
• This creates dependency drift between the main project and the client, violating the requirement
  that client dependency updates be mirrored in both files.
• The mismatch can lead to inconsistent environments and hard-to-debug runtime/test differences
  depending on which lock/install path is used.

reliability

Code

pyproject.toml[54]

+    "httpcore>=1.0.6,<2.0.0",
Evidence
PR Compliance ID 12 requires matching dependency updates in both pyproject.toml files when
client-side dependencies are updated. The PR updates httpcore in the root pyproject.toml but
leaves the client constraint unchanged, demonstrating the drift.

AGENTS.md
pyproject.toml[54-54]
client/pyproject.toml[39-39]

Agent Prompt
## Issue description
The `httpcore` dependency was updated in the root `pyproject.toml` but not in `client/pyproject.toml`, causing dependency drift.

## Issue Context
Compliance requires that client dependency changes be applied consistently in both `pyproject.toml` files.

## Fix Focus Areas
- client/pyproject.toml[37-41]
- pyproject.toml[52-55]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


2. Expect not cleared 🐞 Bug
Description
• Switching posture Reactive→Proactive copies trigger.expect into trigger.after but never clears
  trigger.expect, leaving both fields populated.
• This diverges from the existing PostureSelect logic and will produce contradictory/duplicated
  trigger configuration in the form state.
• It also likely breaks the intended UX (the “expected events” textarea would still show values
  after selecting Proactive).

correctness

Code

ui-v2/src/components/automations/automations-wizard/trigger-step/custom-posture-select/index.tsx[R22-39]

+	const handlePostureChange = (value: "Reactive" | "Proactive") => {
+		const previousPosture = form.getValues("trigger.posture");
+		form.setValue("trigger.posture", value);
+
+		// Move state values between expect and after when posture changes
+		// Reactive uses "expect", Proactive uses "after"
+		if (previousPosture === "Reactive" && value === "Proactive") {
+			const expectValues = form.getValues("trigger.expect") ?? [];
+			form.setValue("trigger.after", expectValues);
+			const currentWithin = form.getValues("trigger.within");
+			if (currentWithin === 0) {
+				form.setValue("trigger.within", DEFAULT_PROACTIVE_WITHIN);
+			}
+		} else if (previousPosture === "Proactive" && value === "Reactive") {
+			const afterValues = form.getValues("trigger.after") ?? [];
+			form.setValue("trigger.expect", afterValues);
+			form.setValue("trigger.after", []);
+		}
Evidence
The new CustomPostureSelect does not clear trigger.expect when moving values to trigger.after on
Reactive→Proactive. The existing PostureSelect does clear it, demonstrating the intended behavior
for posture toggles in this codebase.

ui-v2/src/components/automations/automations-wizard/trigger-step/custom-posture-select/index.tsx[22-39]
ui-v2/src/components/automations/automations-wizard/trigger-step/posture-select.tsx[31-55]

Agent Prompt
## Issue description
Reactive→Proactive posture toggle in `CustomPostureSelect` moves `trigger.expect` into `trigger.after` but fails to clear `trigger.expect`, leaving both populated.

## Issue Context
The existing `PostureSelect` clears `trigger.expect` on Reactive→Proactive. `CustomPostureSelect` should match this behavior.

## Fix Focus Areas
- ui-v2/src/components/automations/automations-wizard/trigger-step/custom-posture-select/index.tsx[22-39]
- ui-v2/src/components/automations/automations-wizard/trigger-step/posture-select.tsx[31-55]

## Expected change
- In the Reactive→Proactive branch, add `form.setValue(&quot;trigger.expect&quot;, [])` after setting `trigger.after`.
- (Recommended) Ensure posture updates go through RHF field change semantics (either `field.onChange(value)` or `setValue` with `{shouldDirty:true, shouldTouch:true, shouldValidate:true}`) so the form state behaves consistently.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


3. Proactive within invalid 🐞 Bug
Description
• CustomTriggerFields now allows within values below 10 seconds even when posture is Proactive
  (min=0), but the backend rejects Proactive within values <10s.
• Because the UI Zod schema only enforces within >= 0, users can progress through the wizard and
  only fail at API validation time (or worse, save inconsistent JSON mode values).
• Separately, removing the conditional min makes posture unused in this file, and with
  noUnusedLocals=true this can break the UI build.

correctness

Code

ui-v2/src/components/automations/automations-wizard/trigger-step/custom-trigger-fields.tsx[R122-126]

								<DurationInput
									value={field.value ?? 0}
									onChange={field.onChange}
-									min={posture === "Proactive" ? 10 : 0}
+									min={0}
								/>
Evidence
The backend EventTrigger schema explicitly enforces that Proactive triggers must have `within >=
10s` (and will raise an error for <10s). The UI removed the conditional minimum and now allows any
non-negative value. Additionally, posture is still computed via useWatch but no longer used
anywhere, while the TS config treats unused locals as errors.

ui-v2/src/components/automations/automations-wizard/trigger-step/custom-trigger-fields.tsx[115-126]
src/prefect/events/schemas/automations.py[171-205]
ui-v2/src/components/automations/automations-wizard/trigger-step/custom-trigger-fields.tsx[21-24]
ui-v2/tsconfig.app.json[18-22]

Agent Prompt
## Issue description
Custom trigger `within` input no longer enforces the backend constraint for Proactive triggers (&gt;=10 seconds). The UI can produce values that the server rejects. Additionally, `posture` is now an unused local, which is a TypeScript build error due to `noUnusedLocals: true`.

## Issue Context
Backend enforces `within &gt;= 10s` for Proactive triggers and raises a validation error for values below 10 seconds.

## Fix Focus Areas
- ui-v2/src/components/automations/automations-wizard/trigger-step/custom-trigger-fields.tsx[21-24]
- ui-v2/src/components/automations/automations-wizard/trigger-step/custom-trigger-fields.tsx[115-126]
- src/prefect/events/schemas/automations.py[171-205]

## Expected change
- Restore conditional minimum in `DurationInput`:
 - `min={posture === &quot;Proactive&quot; ? 10 : 0}`
- Optionally (recommended for JSON mode parity), add a Zod object-level validation to the UI `EventTriggerSchema` to prevent Proactive `within` in the range 1..9.
- Ensure `posture` is actually used (by restoring the conditional min) or remove the `useWatch`/`posture` variable entirely if no longer needed.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools



Remediation Recommended

4. RHF change not tracked 🐞 Bug
Description
• CustomPostureSelect updates trigger.posture via form.setValue instead of the provided RHF
  field onChange, which can skip touched/dirty semantics.
• This can lead to posture changes not being reflected in formState (e.g., dirty tracking,
  validation timing) even though the underlying value changes.
• The existing PostureSelect uses field.onChange, so this is an inconsistency that can cause
  subtle wizard UX bugs.

reliability

Code

ui-v2/src/components/automations/automations-wizard/trigger-step/custom-posture-select/index.tsx[R22-25]

+	const handlePostureChange = (value: "Reactive" | "Proactive") => {
+		const previousPosture = form.getValues("trigger.posture");
+		form.setValue("trigger.posture", value);
+
Evidence
CustomPostureSelect uses form.setValue("trigger.posture", value) directly, while the existing
PostureSelect uses field.onChange(value) for posture updates. RHF uses the field handler to
maintain dirty/touched state correctly unless setValue is called with explicit options.

ui-v2/src/components/automations/automations-wizard/trigger-step/custom-posture-select/index.tsx[22-25]
ui-v2/src/components/automations/automations-wizard/trigger-step/posture-select.tsx[31-34]

Agent Prompt
## Issue description
`CustomPostureSelect` updates `trigger.posture` via `form.setValue` instead of the RHF field handler. This can skip dirty/touched semantics.

## Issue Context
Existing `PostureSelect` uses `field.onChange` for posture changes.

## Fix Focus Areas
- ui-v2/src/components/automations/automations-wizard/trigger-step/custom-posture-select/index.tsx[22-25]
- ui-v2/src/components/automations/automations-wizard/trigger-step/posture-select.tsx[31-34]

## Expected change
- Prefer calling `field.onChange(value)` inside the `FormField` render (pass the `field` into your handler), then do the `expect/after/within` migration.
- Alternatively, keep `setValue` but add options: `{ shouldDirty: true, shouldTouch: true, shouldValidate: true }`.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


Grey Divider

Qodo Logo

Comment thread pyproject.toml
"graphviz>=0.20.1",
"griffe>=0.49.0,<2.0.0",
"httpcore>=1.0.5,<2.0.0",
"httpcore>=1.0.6,<2.0.0",
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Action Required

1. httpcore version mismatch 📘 Rule Violation

• The root pyproject.toml updates httpcore to >=1.0.6,<2.0.0 while client/pyproject.toml
  still pins httpcore at >=1.0.5,<2.0.0.
• This creates dependency drift between the main project and the client, violating the requirement
  that client dependency updates be mirrored in both files.
• The mismatch can lead to inconsistent environments and hard-to-debug runtime/test differences
  depending on which lock/install path is used.
Agent Prompt
## Issue description
The `httpcore` dependency was updated in the root `pyproject.toml` but not in `client/pyproject.toml`, causing dependency drift.

## Issue Context
Compliance requires that client dependency changes be applied consistently in both `pyproject.toml` files.

## Fix Focus Areas
- client/pyproject.toml[37-41]
- pyproject.toml[52-55]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

Comment on lines +22 to +39
const handlePostureChange = (value: "Reactive" | "Proactive") => {
const previousPosture = form.getValues("trigger.posture");
form.setValue("trigger.posture", value);

// Move state values between expect and after when posture changes
// Reactive uses "expect", Proactive uses "after"
if (previousPosture === "Reactive" && value === "Proactive") {
const expectValues = form.getValues("trigger.expect") ?? [];
form.setValue("trigger.after", expectValues);
const currentWithin = form.getValues("trigger.within");
if (currentWithin === 0) {
form.setValue("trigger.within", DEFAULT_PROACTIVE_WITHIN);
}
} else if (previousPosture === "Proactive" && value === "Reactive") {
const afterValues = form.getValues("trigger.after") ?? [];
form.setValue("trigger.expect", afterValues);
form.setValue("trigger.after", []);
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Action Required

2. Expect not cleared 🐞 Bug

• Switching posture Reactive→Proactive copies trigger.expect into trigger.after but never clears
  trigger.expect, leaving both fields populated.
• This diverges from the existing PostureSelect logic and will produce contradictory/duplicated
  trigger configuration in the form state.
• It also likely breaks the intended UX (the “expected events” textarea would still show values
  after selecting Proactive).
Agent Prompt
## Issue description
Reactive→Proactive posture toggle in `CustomPostureSelect` moves `trigger.expect` into `trigger.after` but fails to clear `trigger.expect`, leaving both populated.

## Issue Context
The existing `PostureSelect` clears `trigger.expect` on Reactive→Proactive. `CustomPostureSelect` should match this behavior.

## Fix Focus Areas
- ui-v2/src/components/automations/automations-wizard/trigger-step/custom-posture-select/index.tsx[22-39]
- ui-v2/src/components/automations/automations-wizard/trigger-step/posture-select.tsx[31-55]

## Expected change
- In the Reactive→Proactive branch, add `form.setValue("trigger.expect", [])` after setting `trigger.after`.
- (Recommended) Ensure posture updates go through RHF field change semantics (either `field.onChange(value)` or `setValue` with `{shouldDirty:true, shouldTouch:true, shouldValidate:true}`) so the form state behaves consistently.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

Comment on lines 122 to 126
<DurationInput
value={field.value ?? 0}
onChange={field.onChange}
min={posture === "Proactive" ? 10 : 0}
min={0}
/>
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Action Required

3. Proactive within invalid 🐞 Bug

• CustomTriggerFields now allows within values below 10 seconds even when posture is Proactive
  (min=0), but the backend rejects Proactive within values <10s.
• Because the UI Zod schema only enforces within >= 0, users can progress through the wizard and
  only fail at API validation time (or worse, save inconsistent JSON mode values).
• Separately, removing the conditional min makes posture unused in this file, and with
  noUnusedLocals=true this can break the UI build.
Agent Prompt
## Issue description
Custom trigger `within` input no longer enforces the backend constraint for Proactive triggers (>=10 seconds). The UI can produce values that the server rejects. Additionally, `posture` is now an unused local, which is a TypeScript build error due to `noUnusedLocals: true`.

## Issue Context
Backend enforces `within >= 10s` for Proactive triggers and raises a validation error for values below 10 seconds.

## Fix Focus Areas
- ui-v2/src/components/automations/automations-wizard/trigger-step/custom-trigger-fields.tsx[21-24]
- ui-v2/src/components/automations/automations-wizard/trigger-step/custom-trigger-fields.tsx[115-126]
- src/prefect/events/schemas/automations.py[171-205]

## Expected change
- Restore conditional minimum in `DurationInput`:
  - `min={posture === "Proactive" ? 10 : 0}`
- Optionally (recommended for JSON mode parity), add a Zod object-level validation to the UI `EventTriggerSchema` to prevent Proactive `within` in the range 1..9.
- Ensure `posture` is actually used (by restoring the conditional min) or remove the `useWatch`/`posture` variable entirely if no longer needed.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

Comment on lines +22 to +25
const handlePostureChange = (value: "Reactive" | "Proactive") => {
const previousPosture = form.getValues("trigger.posture");
form.setValue("trigger.posture", value);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remediation Recommended

4. Rhf change not tracked 🐞 Bug

• CustomPostureSelect updates trigger.posture via form.setValue instead of the provided RHF
  field onChange, which can skip touched/dirty semantics.
• This can lead to posture changes not being reflected in formState (e.g., dirty tracking,
  validation timing) even though the underlying value changes.
• The existing PostureSelect uses field.onChange, so this is an inconsistency that can cause
  subtle wizard UX bugs.
Agent Prompt
## Issue description
`CustomPostureSelect` updates `trigger.posture` via `form.setValue` instead of the RHF field handler. This can skip dirty/touched semantics.

## Issue Context
Existing `PostureSelect` uses `field.onChange` for posture changes.

## Fix Focus Areas
- ui-v2/src/components/automations/automations-wizard/trigger-step/custom-posture-select/index.tsx[22-25]
- ui-v2/src/components/automations/automations-wizard/trigger-step/posture-select.tsx[31-34]

## Expected change
- Prefer calling `field.onChange(value)` inside the `FormField` render (pass the `field` into your handler), then do the `expect/after/within` migration.
- Alternatively, keep `setValue` but add options: `{ shouldDirty: true, shouldTouch: true, shouldValidate: true }`.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant