Skip to content

fix: enhance components with error handling and improve rate limit logic#234

Open
IamKirbki wants to merge 1 commit into
mainfrom
Hotfixes/small-fixes-to-general-components-and-provider-crud
Open

fix: enhance components with error handling and improve rate limit logic#234
IamKirbki wants to merge 1 commit into
mainfrom
Hotfixes/small-fixes-to-general-components-and-provider-crud

Conversation

@IamKirbki
Copy link
Copy Markdown
Contributor

Form validation, required fields, and rate limit shape cleanup

What

  • project-switcher.tsx: add asChild to DropdownMenuTrigger so it stops rendering its own <button> inside the SidebarMenuButton. Kills the nested button DOM warning.
  • textarea.tsx: wrap in React.forwardRef so react-hook-form's Controller can actually pass a ref through. Kills the "Function components cannot be given refs" warning and lets RHF auto-focus on validation errors.
  • schema-fields.tsx:
    • New optional errors prop keyed by property name, rendered as destructive-styled text under each field (file, template, code, select, primitive, boolean, nested object).
    • Boolean fields without a value now initialize to false so they round-trip cleanly through the form.
    • Swap truthy check on file fields to Boolean(value[key]) for consistency.
    • Pass errors recursively into nested SchemaFields.
    • FormSchemaFields now extracts field-level errors from form.formState.errors[parent], forwards them down, and calls form.clearErrors(fieldName) when a field changes so stale errors don't linger.
    • Replace the UseFormReturn<any> typing with a narrow FormAdapter interface so the component doesn't depend on the full RHF surface.
  • IntegrationSetup.tsx:
    • Collapse rate_limit and rate_interval into a single nested rate_limit: { limit, interval } shape on the form values, defaults, register call, and submit body. Controller name updated to rate_limit.interval, register updated to rate_limit.limit.
    • Pre-submit validation pass over dataSchema.required: missing or whitespace-only values get form.setError with a translated "This field is required" message and submission is aborted.
  • Integrations.tsx: only include search in the actions list query when debouncedQuery is non-empty, so the param isn't sent as an empty string.
  • ListCreateForm.tsx: add cursor-pointer to the dynamic/static TabsTriggers.
  • providers.go (CreateProvider, UpdateProvider): only assign RateLimit / RateInterval when the incoming values are non-zero / non-empty, so partial payloads don't wipe existing values.

Why

Schema-driven fields had no way to surface validation errors and required fields slipped through on submit. The split rate_limit / rate_interval shape was awkward on both sides of the wire and easy to desync, the nested object matches the manifest shape and lets the backend treat empty values as "leave alone." The two console warnings were noise that masked real issues.

@jeroenrinzema jeroenrinzema requested a review from Copilot May 12, 2026 19:06
jeroenrinzema
jeroenrinzema previously approved these changes May 12, 2026
Copy link
Copy Markdown

Copilot AI left a 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 the Console form UX (schema-driven error display, required-field validation, and removal of DOM/ref warnings) and refactors provider rate-limit handling to use a nested { limit, interval } shape consistently across UI and backend.

Changes:

  • Add field-level error rendering to SchemaFields/FormSchemaFields, plus required-field pre-submit validation in integration setup.
  • Refactor integration rate limit form fields to a nested rate_limit.{limit,interval} shape and adjust actions search query behavior.
  • Small UI fixes: forwardRef textarea, remove nested button warning in project switcher, cursor pointer on tabs.

Reviewed changes

Copilot reviewed 7 out of 7 changed files in this pull request and generated 5 comments.

Show a summary per file
File Description
internal/http/controllers/v1/management/providers.go Changes rate limit assignment behavior in create/update provider handlers.
console/src/views/users/ListCreateForm.tsx Adds pointer cursor styling to tab triggers.
console/src/views/settings/IntegrationSetup.tsx Refactors rate limit form shape and adds required-field validation before submit.
console/src/views/settings/Integrations.tsx Omits search query param when the search term is empty.
console/src/components/ui/textarea.tsx Wraps Textarea in forwardRef for react-hook-form compatibility.
console/src/components/schema-fields.tsx Adds error rendering and boolean defaults; introduces RHF adapter + error extraction.
console/src/components/project-switcher.tsx Uses asChild to avoid nested button DOM warnings.
Comments suppressed due to low confidence (1)

console/src/views/settings/IntegrationSetup.tsx:624

  • valueAsNumber: true will produce NaN when the number input is cleared. With the new body.rate_limit = values.rate_limit behavior, that can end up serializing limit as null (via JSON.stringify(NaN)) or otherwise producing an invalid payload. Consider normalizing the value (e.g., convert NaN to 0/undefined) before submit, or use setValueAs/validation to prevent NaN from reaching the request body.
                                                    <Input
                                                        type="number"
                                                        min={0}
                                                        max={maxRateLimit ?? undefined}
                                                        placeholder={String(
                                                            manifestRateLimit.limit,
                                                        )}
                                                        className="w-28"
                                                        {...form.register("rate_limit.limit", {
                                                            valueAsNumber: true,
                                                            min: 0,
                                                            max: maxRateLimit ?? undefined,
                                                        })}

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +397 to +399
if body.RateLimit.Limit > 0 {
update.RateLimit = &body.RateLimit.Limit
}
Comment on lines +397 to +402
if body.RateLimit.Limit > 0 {
update.RateLimit = &body.RateLimit.Limit
}
if body.RateLimit.Interval != "" {
update.RateInterval = &body.RateLimit.Interval
}
rate_limit: null,
rate_interval: "1s",
rate_limit: {
limit: manifestRateLimit?.limit ?? 0,
Comment on lines +412 to +425
// Extract field-level errors from react-hook-form for the parent path
const errors = useMemo(() => {
const parentErrors = formErrors[parent]
if (!parentErrors || typeof parentErrors !== "object") return undefined
const result: Record<string, string | undefined> = {}
for (const [key, err] of Object.entries(
parentErrors as Record<string, { message?: string }>,
)) {
if (err?.message) {
result[key] = err.message
}
}
return Object.keys(result).length > 0 ? result : undefined
}, [formErrors, parent])
Comment on lines 350 to 356
<SchemaFields
schema={item}
value={(value[key] as Record<string, unknown>) ?? {}}
onChange={(nested) => set(key, nested)}
variables={variables}
errors={errors}
/>
@jeroenrinzema jeroenrinzema force-pushed the Hotfixes/small-fixes-to-general-components-and-provider-crud branch from 26ca237 to 232938f Compare May 12, 2026 19:12
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants