You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
This repository was archived by the owner on Jul 26, 2026. It is now read-only.
Several organization-scoped dashboard screens independently implement the same collection-management lifecycle for connection or infrastructure resources.
Representative pages include S3 destinations, Docker registries, remote servers, SSH keys, Git providers, notification channels, and AI/provider settings. Common repeated mechanics include:
resolving the active organization;
listing entities with an organization-scoped tRPC query;
maintaining create/edit dialog state and many individual form state variables;
branching between create and update mutations;
closing the dialog, resetting the form, showing a toast, and calling refetch() after success;
maintaining separate delete selection/confirmation state;
repeating onError handlers that select error.message or a fallback;
implementing optional “test connection” mutations with slightly different result and toast handling;
loosely typed any mutation callbacks in some screens.
The domain-specific forms should remain separate. The stable query/mutation/dialog lifecycle has enough duplication to justify small shared hooks and dialog primitives without creating one giant generic form framework.
Reviewed against master at release commit 56c78fb6bbc3c3aacfafb4355288383f9946def5.
Proposed consolidation
Extract focused mutation lifecycle helpers for create/update/delete/test operations, including standardized error normalization and success callbacks.
Prefer query-client invalidation with typed query keys over manually threading refetch() through every mutation.
Add reusable dialog shells for:
create/edit forms with pending submit state;
destructive entity deletion with name/description and confirmation;
connection-test result feedback.
Define a small reusable useEntityFormDialog state helper for open mode, editing entity, close/reset, and dirty-state confirmation.
Keep each feature's schema, fields, payload mapping, secret handling, and authorization-specific copy in its own module.
Standardize mutation error rendering and remove any from error/result callbacks.
Begin with the structurally closest pair—S3 destinations and Docker registries—then validate the abstraction against remote servers or Git providers before wider migration.
Avoid abstracting visual differences or domain behavior until at least three consumers demonstrate a stable contract.
Acceptance criteria
S3 destination and Docker registry screens share the common CRUD lifecycle implementation.
At least one additional connection-resource screen validates that the abstraction is not pair-specific.
Domain forms and typed payload builders remain feature-owned.
Create/update success consistently closes and resets the correct form.
Delete actions use one accessible confirmation pattern with pending protection.
Connection tests use consistent success/failure semantics while preserving provider-specific messages.
Query invalidation replaces repeated ad hoc refetch wiring where practical.
Mutation callbacks no longer use any for ordinary error and result handling.
Tests cover create, edit, delete, test, cancellation, dirty close, mutation failure, and stale collection refresh.
Summary
Several organization-scoped dashboard screens independently implement the same collection-management lifecycle for connection or infrastructure resources.
Representative pages include S3 destinations, Docker registries, remote servers, SSH keys, Git providers, notification channels, and AI/provider settings. Common repeated mechanics include:
refetch()after success;onErrorhandlers that selecterror.messageor a fallback;anymutation callbacks in some screens.The domain-specific forms should remain separate. The stable query/mutation/dialog lifecycle has enough duplication to justify small shared hooks and dialog primitives without creating one giant generic form framework.
Reviewed against
masterat release commit56c78fb6bbc3c3aacfafb4355288383f9946def5.Proposed consolidation
refetch()through every mutation.useEntityFormDialogstate helper for open mode, editing entity, close/reset, and dirty-state confirmation.anyfrom error/result callbacks.Acceptance criteria
anyfor ordinary error and result handling.Representative affected files
apps/web/src/app/(dashboard)/s3-destinations/s3-destinations.tsxapps/web/src/app/(dashboard)/docker-registry/page.tsxapps/web/src/app/(dashboard)/remote-servers/page.tsxapps/web/src/app/(dashboard)/ssh-keys/ssh-keys.tsxapps/web/src/app/(dashboard)/git-providers/git-providers.tsxapps/web/src/app/(dashboard)/notifications/page.tsxapps/web/src/features/settings/components/upgal-settings-panel.tsx