Skip to content

feat(forms): add declarative form builder and migrate routes to it - #546

Draft
thokra-nav wants to merge 4 commits into
mainfrom
formbuilder
Draft

thokra-nav wants to merge 4 commits into
mainfrom
formbuilder

Conversation

@thokra-nav

Copy link
Copy Markdown
Contributor

Forms were hand-rolled per route: each page wired up its own controls, its own validation and its own error handling, so the same concerns were re-implemented (and drifted) across every create, edit and delete page.

Introduce a single declarative definition that both sides share:

  • $lib/ui/Form renders a form from a field definition, validates on the client with the very same zod schema the action uses, and reports issues in a linked error summary. Supports groups, conditional fields via dynamic, and repeatable field groups.
  • $lib/server/form provides validateForm and formAction, which build the validate/mutate/report cycle an action performs. GraphQL errors the API attributes to an input land on the offending control; submitted values are echoed back so a failed submit stays editable.
  • $lib/forms/* holds the field definitions, shared by page and action so the two can never disagree about which fields exist.

Migrate the service account, team, workload (env/image/resize/delete), opensearch, valkey and postgres routes onto it, and add tests covering the schema building, rendering and action behaviour.

Adds zod as a dependency.

Comment thread src/lib/forms/team.ts Fixed
thokra-nav and others added 4 commits August 5, 2026 14:39
Forms were hand-rolled per route: each page wired up its own controls,
its own validation and its own error handling, so the same concerns were
re-implemented (and drifted) across every create, edit and delete page.

Introduce a single declarative definition that both sides share:

- `$lib/ui/Form` renders a form from a field definition, validates on the
  client with the very same zod schema the action uses, and reports issues
  in a linked error summary. Supports groups, conditional fields via
  `dynamic`, and repeatable field groups.
- `$lib/server/form` provides `validateForm` and `formAction`, which build
  the validate/mutate/report cycle an action performs. GraphQL errors the
  API attributes to an input land on the offending control; submitted
  values are echoed back so a failed submit stays editable.
- `$lib/forms/*` holds the field definitions, shared by page and action so
  the two can never disagree about which fields exist.

Migrate the service account, team, workload (env/image/resize/delete),
opensearch, valkey and postgres routes onto it, and add tests covering the
schema building, rendering and action behaviour.

Adds zod as a dependency.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

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 introduces a shared, declarative form system (field definitions + Zod validation + reusable server action helpers) and migrates many routes from hand-rolled forms/actions to the new implementation, with tests and dependency updates to support the change.

Changes:

  • Added $lib/ui/Form rendering/validation components (including repeatable groups) and $lib/server/form helpers (validateForm, formAction) to unify client/server validation + error mapping.
  • Migrated multiple create/edit/delete flows (team, service accounts, Valkey, OpenSearch, Postgres, app/job actions, vulnerabilities search) to the declarative forms.
  • Added Vitest support + unit tests for schema building and action behavior; added zod dependency.

Reviewed changes

Copilot reviewed 84 out of 85 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
vitest.config.js Adds alias to stub $app/forms during tests.
src/styles/app.css Adds a dark-mode <option> background fix.
src/routes/vulnerabilities/(single)/+page.server.ts Uses shared validateForm for CVE search action.
src/routes/team/create/+page.svelte Migrates team create UI to <Form> + shared field definition.
src/routes/team/create/+page.server.ts Migrates team create action to formAction.
src/routes/team/[team]/valkey/create/+page.svelte Migrates Valkey create UI to <Form> with groups/defaults/options overrides.
src/routes/team/[team]/valkey/create/+page.server.ts Migrates Valkey create action to formAction.
src/routes/team/[team]/valkey/+page.svelte Removes PageModal-based create flow wiring.
src/routes/team/[team]/settings/service_accounts/create/+page.ts Improves page title + adds doc link metadata.
src/routes/team/[team]/settings/service_accounts/create/+page.svelte Updates props usage for new form handling.
src/routes/team/[team]/settings/service_accounts/create/+page.server.ts Migrates service account create action to formAction.
src/routes/team/[team]/settings/service_accounts/+page.svelte Removes PageModal flow; uses List actions snippet for create button.
src/routes/team/[team]/settings/service_accounts/[serviceAccountID]/token/create/+page.ts Adds doc link + breadcrumb label adjustment.
src/routes/team/[team]/settings/service_accounts/[serviceAccountID]/token/create/+page.svelte Passes form into CreateTokenForm.
src/routes/team/[team]/settings/service_accounts/[serviceAccountID]/token/create/+page.server.ts Migrates token creation to formAction + server-side expiry resolution.
src/routes/team/[team]/settings/service_accounts/[serviceAccountID]/binding/add/+page.ts Adds doc link metadata.
src/routes/team/[team]/settings/service_accounts/[serviceAccountID]/binding/add/+page.svelte Uses shared failureMessage helper for enhance failures.
src/routes/team/[team]/settings/service_accounts/[serviceAccountID]/binding/add/+page.server.ts Migrates add-binding action to formAction.
src/routes/team/[team]/settings/service_accounts/[serviceAccountID]/+page.svelte Removes modal invalidation + embedded modal routes.
src/routes/team/[team]/settings/service_accounts/[serviceAccountID]/+page.server.ts Migrates delete-token/remove-binding actions to formAction.
src/routes/team/[team]/opensearch/create/+page.svelte Migrates OpenSearch create UI to <Form> with defaults/options overrides.
src/routes/team/[team]/opensearch/create/+page.server.ts Migrates OpenSearch create action to formAction.
src/routes/team/[team]/[env]/valkey/[valkey]/edit/+page.svelte Migrates Valkey edit UI to <Form> with defaults.
src/routes/team/[team]/[env]/valkey/[valkey]/edit/+page.server.ts Migrates Valkey edit action to formAction.
src/routes/team/[team]/[env]/valkey/[valkey]/delete/+page.svelte Migrates Valkey delete UI to <Form> + cancel/back link.
src/routes/team/[team]/[env]/valkey/[valkey]/delete/+page.server.ts Migrates Valkey delete action to formAction + confirmation schema factory.
src/routes/team/[team]/[env]/postgres/[postgres]/delete/+page.svelte Migrates Postgres delete UI to <Form> + cancel/back link.
src/routes/team/[team]/[env]/postgres/[postgres]/delete/+page.server.ts Migrates Postgres delete action to formAction + confirmation schema factory.
src/routes/team/[team]/[env]/opensearch/[opensearch]/edit/+page.svelte Migrates OpenSearch edit UI to <Form> and keeps “reducing storage” hint.
src/routes/team/[team]/[env]/opensearch/[opensearch]/edit/+page.server.ts Migrates OpenSearch edit action to formAction.
src/routes/team/[team]/[env]/opensearch/[opensearch]/delete/+page.svelte Migrates OpenSearch delete UI to <Form> + cancel/back link.
src/routes/team/[team]/[env]/opensearch/[opensearch]/delete/+page.server.ts Migrates OpenSearch delete action to formAction + confirmation schema factory.
src/routes/team/[team]/[env]/job/[job]/JobActions.svelte Removes PageModal-based “env” modal wiring.
src/routes/team/[team]/[env]/job/[job]/env/+page.svelte Migrates job env var editor to repeatable <Form>.
src/routes/team/[team]/[env]/job/[job]/env/+page.server.ts Migrates job env update action to formAction + rename mapping.
src/routes/team/[team]/[env]/job/[job]/delete/+page.svelte Migrates job delete UI to shared delete confirmation form.
src/routes/team/[team]/[env]/job/[job]/delete/+page.server.ts Adds server action for job deletion via formAction.
src/routes/team/[team]/[env]/app/[app]/resize/+page.svelte Migrates app resize UI to <Form> + refine constraint.
src/routes/team/[team]/[env]/app/[app]/resize/+page.server.ts Migrates app resize action to formAction + rename mapping.
src/routes/team/[team]/[env]/app/[app]/image/+page.svelte Migrates image rollback UI to <Form> with radio options and better labels.
src/routes/team/[team]/[env]/app/[app]/image/+page.server.ts Adds optionsOverrides fetching to restrict image choices server-side; uses formAction.
src/routes/team/[team]/[env]/app/[app]/env/+page.svelte Migrates app env var editor to repeatable <Form>.
src/routes/team/[team]/[env]/app/[app]/env/+page.server.ts Migrates app env update action to formAction + rename mapping.
src/routes/team/[team]/[env]/app/[app]/delete/+page.svelte Migrates app delete UI to shared delete confirmation form.
src/routes/team/[team]/[env]/app/[app]/delete/+page.server.ts Adds server action for app deletion via formAction.
src/routes/team/[team]/[env]/app/[app]/AppActions.svelte Removes PageModal wiring for resize/env/image actions.
src/routes/admin/service_accounts/create/+page.svelte Updates to accept form via props rather than $app/state.
src/routes/admin/service_accounts/create/+page.server.ts Migrates admin service account create action to formAction.
src/routes/admin/service_accounts/[serviceAccountID]/token/create/+page.svelte Passes form into CreateTokenForm.
src/routes/admin/service_accounts/[serviceAccountID]/token/create/+page.server.ts Migrates admin token creation to formAction + server-side expiry resolution.
src/routes/admin/service_accounts/[serviceAccountID]/binding/add/+page.svelte Uses shared failureMessage helper for enhance failures.
src/routes/admin/service_accounts/[serviceAccountID]/binding/add/+page.server.ts Migrates admin add-binding action to formAction.
src/routes/admin/service_accounts/[serviceAccountID]/+page.server.ts Migrates delete-token/remove-binding actions to formAction.
src/routes/+page.svelte Removes PageModal-based “Create team” flow.
src/lib/ui/Textarea.svelte Extends Textarea with error rendering/ARIA, optional snippet description, sizing.
src/lib/ui/Form/RepeatField.svelte Adds repeatable field-group rendering (add/remove rows).
src/lib/ui/Form/FormField.svelte Adds field renderer mapping form field definitions to DS components.
src/lib/ui/Form/Form.svelte Adds core form renderer with client-side Zod validation + error summary linking + enhance handling.
src/lib/test/app-forms.ts Provides Vitest stub for $app/forms.
src/lib/server/form.ts Adds server helpers for validation + action wiring + GraphQL error→field mapping.
src/lib/server/form.test.ts Adds unit tests for server form helpers and GraphQL issue mapping.
src/lib/forms/workload.ts Adds shared workload forms (resize, set image version) + refinement.
src/lib/forms/workload-env.ts Adds repeatable env-var form + uniqueness refinement.
src/lib/forms/vulnerability.ts Adds CVE search form definition.
src/lib/forms/valkey.ts Adds Valkey form definition + group config.
src/lib/forms/valkey.snippets.svelte Adds snippet descriptions for Valkey fields.
src/lib/forms/team.ts Adds team create form definition + validation.
src/lib/forms/serviceaccounts.ts Adds service account + binding/token removal form definitions.
src/lib/forms/service-account-token.ts Adds service account token create/delete form definitions.
src/lib/forms/opensearch.ts Adds OpenSearch form definition with dynamic option/constraint logic.
src/lib/forms/forms.test.ts Adds unit tests for several form schemas/refinements.
src/lib/forms/delete-confirmation.ts Adds reusable “type name to confirm” form factory.
src/lib/domain/vulnerability/CveSearch.svelte Improves enhance failure handling and displays failure message.
src/lib/domain/service-accounts/tokenExpiry.ts Updates expiry option shape to { value, label }.
src/lib/domain/service-accounts/ServiceAccountDetail.svelte Removes modal-click wiring for token/binding actions.
src/lib/domain/service-accounts/ServiceAccountAuthentications.svelte Uses shared failureMessage helper for enhance failures.
src/lib/domain/service-accounts/CreateTokenForm.svelte Migrates token form UI to shared <Form> + shared field definition.
src/lib/domain/service-accounts/createToken.server.ts Removes legacy create-token action implementation.
src/lib/domain/service-accounts/CreateServiceAccountForm.svelte Migrates service account create UI to shared <Form>.
pnpm-workspace.yaml Allows building houdini-svelte in pnpm constraints.
pnpm-lock.yaml Locks added zod@4.4.3.
package.json Adds zod@4.4.3 dependency.
Files not reviewed (1)
  • pnpm-lock.yaml: Generated file

Comment thread src/styles/app.css
Comment on lines +484 to +489
/* fix option background color in dark mode */
@media (prefers-color-scheme: dark) {
option {
background-color: var(--ax-bg-raised);
}
}
Comment on lines 75 to 79
{/if}
<textarea
class="aksel-textarea__input aksel-body-short aksel-body-short--small textarea"
{name}
class="aksel-textarea__input aksel-body-short aksel-body-short--{size} textarea"
{id}
Comment on lines +90 to +97
<Button
{size}
type="button"
variant="tertiary-neutral"
icon={TrashIcon}
title="Remove {field.label} entry {index + 1}"
onclick={() => removeRow(index)}
/>
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