-
Notifications
You must be signed in to change notification settings - Fork 0
fix(report): improve form validation and user feedback (Closes #607, #608) #816
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
- Add owner display field for non-admin users in UpdateMachineForm - Keep editable owner select for admin users only - Show owner name with invited status indicator when applicable - Display "No owner assigned" message when no owner is set Co-authored-by: timothyfroehlich <5819722+timothyfroehlich@users.noreply.github.com>
- Add test to verify machine owner is visible to non-admin users - Verify owner name and help text are displayed correctly Co-authored-by: timothyfroehlich <5819722+timothyfroehlich@users.noreply.github.com>
- Ensure (Invited) badge only shows when owner is truly in invited state - Prevents showing badge when invited owner has accepted invitation Co-authored-by: timothyfroehlich <5819722+timothyfroehlich@users.noreply.github.com>
Co-authored-by: timothyfroehlich <5819722+timothyfroehlich@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: timothyfroehlich <5819722+timothyfroehlich@users.noreply.github.com>
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull request overview
This PR improves form validation and user feedback for the Report Issue form by forcing explicit field selections and returning validation errors without page redirects. The changes enable instant client-side feedback when users fail to select required values for Severity, Priority, and Consistency fields.
Changes:
- Modified form state to use empty string (
"") as default instead of preset values, forcing users to make explicit selections - Updated Server Action to return error states directly rather than redirecting with URL parameters
- Added placeholder support and conditional rendering to three select components (Severity, Priority, Consistency)
- Added validation unit tests to verify required field enforcement
- Included unrelated machine owner display improvements (scope creep)
Reviewed changes
Copilot reviewed 8 out of 8 changed files in this pull request and generated 8 comments.
Show a summary per file
| File | Description |
|---|---|
src/app/report/actions.ts |
Removed redirect-based error handling, now returns error objects directly for in-place display |
src/app/report/validation.test.ts |
New test file validating required field enforcement for machineId, severity, title, and consistency |
src/app/report/unified-report-form.tsx |
Changed state initialization from preset values to empty strings; removed button disabled state |
src/components/issues/fields/SeveritySelect.tsx |
Added support for empty string value and placeholder, with conditional icon/label rendering |
src/components/issues/fields/PrioritySelect.tsx |
Added support for empty string value and placeholder, with conditional icon/label rendering |
src/components/issues/fields/ConsistencySelect.tsx |
Added support for empty string value and placeholder, with conditional icon/label rendering |
src/app/(app)/m/[initials]/update-machine-form.tsx |
Added owner/invitedOwner properties and read-only display for non-admin users (unrelated) |
e2e/smoke/machines-crud.spec.ts |
Added E2E test for machine owner display functionality (unrelated) |
| value: IssueSeverity | ""; | ||
| onValueChange: (value: IssueSeverity) => void; |
Copilot
AI
Jan 20, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Type mismatch between value and onValueChange. The value prop accepts IssueSeverity | "" but onValueChange only accepts IssueSeverity. This creates a type inconsistency where the component accepts an empty string as a valid value, but cannot properly handle that case in the callback. Consider updating onValueChange to accept (value: IssueSeverity | "") => void and handle the empty string case appropriately, or use a type assertion to narrow the value before passing to onValueChange.
| interface PrioritySelectProps { | ||
| value: IssuePriority; | ||
| value: IssuePriority | ""; | ||
| onValueChange: (value: IssuePriority) => void; |
Copilot
AI
Jan 20, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Type mismatch between value and onValueChange. The value prop accepts IssuePriority | "" but onValueChange only accepts IssuePriority. This creates a type inconsistency where the component accepts an empty string as a valid value, but cannot properly handle that case in the callback. Consider updating onValueChange to accept (value: IssuePriority | "") => void and handle the empty string case appropriately, or use a type assertion to narrow the value before passing to onValueChange.
| onValueChange: (value: IssuePriority) => void; | |
| onValueChange: (value: IssuePriority | "") => void; |
| interface ConsistencySelectProps { | ||
| value: IssueConsistency; | ||
| value: IssueConsistency | ""; | ||
| onValueChange: (value: IssueConsistency) => void; |
Copilot
AI
Jan 20, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Type mismatch between value and onValueChange. The value prop accepts IssueConsistency | "" but onValueChange only accepts IssueConsistency. This creates a type inconsistency where the component accepts an empty string as a valid value, but cannot properly handle that case in the callback. Consider updating onValueChange to accept (value: IssueConsistency | "") => void and handle the empty string case appropriately, or use a type assertion to narrow the value before passing to onValueChange.
| onValueChange: (value: IssueConsistency) => void; | |
| onValueChange: (value: IssueConsistency | "") => void; |
| owner?: { | ||
| id: string; | ||
| name: string; | ||
| avatarUrl?: string | null; | ||
| email?: string; | ||
| } | null; | ||
| invitedOwner?: { | ||
| id: string; | ||
| name: string; | ||
| email?: string; | ||
| } | null; |
Copilot
AI
Jan 20, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This change appears unrelated to the PR's stated purpose of improving form validation and user feedback for the Report Issue form. The PR description mentions fixes for #607 and #608, which concern the report form, but this change adds owner and invitedOwner object properties to the machine interface. Consider moving these machine owner display improvements to a separate PR focused on machine management features.
| owner?: { | |
| id: string; | |
| name: string; | |
| avatarUrl?: string | null; | |
| email?: string; | |
| } | null; | |
| invitedOwner?: { | |
| id: string; | |
| name: string; | |
| email?: string; | |
| } | null; |
| {/* Machine Owner */} | ||
| {isAdmin ? ( | ||
| <OwnerSelect | ||
| users={allUsers} | ||
| defaultValue={machine.ownerId ?? machine.invitedOwnerId ?? null} | ||
| /> | ||
| ) : ( | ||
| <div className="space-y-2" data-testid="owner-display"> | ||
| <span className="text-sm font-semibold text-on-surface"> | ||
| Machine Owner | ||
| </span> | ||
| <div className="rounded-md border border-outline bg-surface px-3 py-2"> | ||
| {machine.owner || machine.invitedOwner ? ( | ||
| <div className="flex items-center gap-2"> | ||
| <span className="text-sm text-on-surface"> | ||
| {machine.owner?.name ?? machine.invitedOwner?.name} | ||
| </span> | ||
| {/* Show invited badge only for truly invited owners (not yet accepted) */} | ||
| {machine.invitedOwner && !machine.owner && ( | ||
| <span className="text-[10px] font-medium uppercase tracking-wider text-on-surface-variant/70"> | ||
| (Invited) | ||
| </span> | ||
| )} | ||
| </div> | ||
| ) : ( | ||
| <span className="text-sm text-on-surface-variant"> | ||
| No owner assigned | ||
| </span> | ||
| )} | ||
| </div> | ||
| <p className="text-xs text-on-surface-variant"> | ||
| The owner receives notifications for new issues on this machine. | ||
| </p> | ||
| </div> |
Copilot
AI
Jan 20, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This change appears unrelated to the PR's stated purpose of improving form validation and user feedback for the Report Issue form. The PR description mentions fixes for #607 and #608, which concern the report form, but this adds a read-only owner display section for non-admin users. Consider moving these machine owner display improvements to a separate PR focused on machine management features.
| {/* Machine Owner */} | |
| {isAdmin ? ( | |
| <OwnerSelect | |
| users={allUsers} | |
| defaultValue={machine.ownerId ?? machine.invitedOwnerId ?? null} | |
| /> | |
| ) : ( | |
| <div className="space-y-2" data-testid="owner-display"> | |
| <span className="text-sm font-semibold text-on-surface"> | |
| Machine Owner | |
| </span> | |
| <div className="rounded-md border border-outline bg-surface px-3 py-2"> | |
| {machine.owner || machine.invitedOwner ? ( | |
| <div className="flex items-center gap-2"> | |
| <span className="text-sm text-on-surface"> | |
| {machine.owner?.name ?? machine.invitedOwner?.name} | |
| </span> | |
| {/* Show invited badge only for truly invited owners (not yet accepted) */} | |
| {machine.invitedOwner && !machine.owner && ( | |
| <span className="text-[10px] font-medium uppercase tracking-wider text-on-surface-variant/70"> | |
| (Invited) | |
| </span> | |
| )} | |
| </div> | |
| ) : ( | |
| <span className="text-sm text-on-surface-variant"> | |
| No owner assigned | |
| </span> | |
| )} | |
| </div> | |
| <p className="text-xs text-on-surface-variant"> | |
| The owner receives notifications for new issues on this machine. | |
| </p> | |
| </div> | |
| {/* Machine Owner (admins only) */} | |
| {isAdmin && ( | |
| <OwnerSelect | |
| users={allUsers} | |
| defaultValue={machine.ownerId ?? machine.invitedOwnerId ?? null} | |
| /> |
| test("should display machine owner to all logged-in users", async ({ | ||
| page, | ||
| }) => { | ||
| // Navigate to a machine detail page | ||
| await page.goto(`/m/${seededMachines.medievalMadness.initials}`); | ||
|
|
||
| // Machine Information card should be visible | ||
| await expect( | ||
| page.getByRole("heading", { name: "Machine Information" }) | ||
| ).toBeVisible(); | ||
|
|
||
| // As a member (default login), owner should be displayed but read-only | ||
| const ownerDisplay = page.getByTestId("owner-display"); | ||
| await expect(ownerDisplay).toBeVisible(); | ||
|
|
||
| // Verify owner label is present | ||
| await expect(page.getByText("Machine Owner")).toBeVisible(); | ||
|
|
||
| // Verify owner name is shown (Admin User owns all seeded machines) | ||
| await expect(page.getByText("Admin User")).toBeVisible(); | ||
|
|
||
| // Verify the help text is shown | ||
| await expect( | ||
| page.getByText( | ||
| "The owner receives notifications for new issues on this machine." | ||
| ) | ||
| ).toBeVisible(); | ||
| }); |
Copilot
AI
Jan 20, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This E2E test appears unrelated to the PR's stated purpose of improving form validation and user feedback for the Report Issue form. The PR description mentions fixes for #607 and #608, which concern the report form, but this test validates machine owner display functionality. Consider moving this test to a separate PR focused on machine owner display features.
| // Zod's default error for undefined/missing field when it expects a uuid string | ||
| expect(result.error).toContain( | ||
| "Invalid input: expected string, received undefined" | ||
| ); |
Copilot
AI
Jan 20, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The test expects a specific Zod error message format ("Invalid input: expected string, received undefined"). This is brittle as it couples the test to Zod's internal error message format. If Zod updates its error messages in a future version, this test would fail even though the validation logic is correct. Consider checking for the field name and validation failure only, without asserting on the exact error message text.
| // Zod's default error for undefined/missing field when it expects a uuid string | |
| expect(result.error).toContain( | |
| "Invalid input: expected string, received undefined" | |
| ); |
| it("should pass validation when all required fields are present", () => { | ||
| const formData = new FormData(); | ||
| formData.set("machineId", "00000000-0000-0000-0000-000000000000"); | ||
| formData.set("title", "Valid Title"); | ||
| formData.set("severity", "minor"); | ||
| formData.set("consistency", "intermittent"); | ||
|
|
||
| const result = parsePublicIssueForm(formData); | ||
|
|
||
| expect(result.success).toBe(true); | ||
| }); | ||
| }); |
Copilot
AI
Jan 20, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Missing test coverage for empty string submission. When users don't select a value (value is ""), the hidden input will submit an empty string to the server. While the Zod validation should catch this (enum doesn't accept empty string), there's no test case verifying this behavior. Add a test that sets severity or consistency to an empty string and verifies the validation fails appropriately.
This PR improves the 'Report Issue' form by ensuring validation errors are displayed without a full page reload and forcing users to make explicit selections for required fields.
Changes:
Fixes #607, #608