Rename Java packages from com.cameleer3 to com.cameleer, module directories from cameleer3-* to cameleer-*, and all references throughout workflows, Dockerfiles, docs, migrations, and pom.xml. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
30 KiB
Cameleer UI Interaction Patterns Audit
Audit date: 2026-04-09
Scope: All .tsx files under ui/src/pages/ and ui/src/components/
1. Delete / Destructive Operations
1.1 Delete User
- File:
ui/src/pages/Admin/UsersTab.tsx(lines 155-172, 358-365, 580-587) - Button location: Detail pane header, top-right, inline with avatar and name
- Button:
<Button size="sm" variant="danger">Delete</Button> - Confirmation:
ConfirmDialog(type-to-confirm)- Message:
Delete user "${name}"? This cannot be undone. - Confirm text: user's
displayName - Has
loadingprop bound to mutation
- Message:
- Self-delete guard: Button is
disabled={isSelf}(cannot delete yourself) - Toast on success:
variant: 'warning', title: "User deleted" - Toast on error:
variant: 'error',duration: 86_400_000
1.2 Remove User From Group (via User detail)
- File:
ui/src/pages/Admin/UsersTab.tsx(lines 588-613) - Button location: Tag
onRemovehandler on group tags in detail pane - Confirmation:
AlertDialog(simple confirm, no type-to-confirm)- Title: "Remove group membership"
- Description: "Removing this group may also revoke inherited roles. Continue?"
- Confirm label: "Remove"
- Variant:
warning
- Toast on success:
variant: 'success', title: "Group removed"
1.3 Remove Role From User (via User detail)
- File:
ui/src/pages/Admin/UsersTab.tsx(lines 504-528) - Button location: Tag
onRemovehandler on role tags in detail pane - Confirmation: NONE -- immediate mutation on tag remove click
- Toast on success:
variant: 'success', title: "Role removed"
INCONSISTENCY: Removing a group shows an AlertDialog confirmation but removing a role does not, even though both can have cascading effects.
1.4 Delete Group
- File:
ui/src/pages/Admin/GroupsTab.tsx(lines 140-155, 340-347, 434-441) - Button location: Detail pane header, top-right
- Button:
<Button size="sm" variant="danger">Delete</Button> - Confirmation:
ConfirmDialog(type-to-confirm)- Message:
Delete group "${name}"? This cannot be undone. - Confirm text: group's
name - Has
loadingprop
- Message:
- Built-in guard: Button is
disabled={isBuiltinAdmins} - Toast on success:
variant: 'warning', title: "Group deleted"
1.5 Remove Role From Group
- File:
ui/src/pages/Admin/GroupsTab.tsx(lines 404-427, 442-455) - Button location: Tag
onRemovehandler on role tags in group detail - Confirmation:
AlertDialogshown ONLY when the group has members (conditional)- Title: "Remove role from group"
- Description:
Removing this role will affect ${members.length} member(s) who inherit it. Continue? - Confirm label: "Remove"
- Variant:
warning
- If group has no members: Immediate mutation, no confirmation
- Toast on success:
variant: 'success', title: "Role removed"
1.6 Remove Member From Group
- File:
ui/src/pages/Admin/GroupsTab.tsx(lines 366-372) - Button location: Tag
onRemovehandler on member tags in group detail - Confirmation: NONE -- immediate mutation on tag remove click
- Toast on success:
variant: 'success', title: "Member removed"
1.7 Delete Role
- File:
ui/src/pages/Admin/RolesTab.tsx(lines 93-110, 261-265, 223-231) - Button location: Detail pane header, top-right
- Button:
<Button size="sm" variant="danger">Delete</Button> - Confirmation:
ConfirmDialog(type-to-confirm)- Message:
Delete role "${name}"? This cannot be undone. - Confirm text: role's
name - Has
loadingprop
- Message:
- System role guard: Button hidden for system roles (
!role.system) - Toast on success:
variant: 'warning', title: "Role deleted"
1.8 Delete Environment
- File:
ui/src/pages/Admin/EnvironmentsPage.tsx(lines 101-112, 245-252, 319-327) - Button location: Detail pane header, top-right
- Button:
<Button size="sm" variant="danger">Delete</Button> - Confirmation:
ConfirmDialog(type-to-confirm)- Message:
Delete environment "${displayName}"? All apps and deployments in this environment will be removed. This cannot be undone. - Confirm text: environment's
slug(NOT the display name) - Has
loadingprop
- Message:
- Default guard: Button is
disabled={isDefault}(cannot delete default environment) - Toast on success:
variant: 'warning', title: "Environment deleted"
NOTE: The confirm text requires the slug but the message shows the display name. This is intentional (slug is the unique identifier) but differs from Users/Groups/Roles which use the display name.
1.9 Delete OIDC Configuration
- File:
ui/src/pages/Admin/OidcConfigPage.tsx(lines 113-124, 253-264) - Button location: Bottom of page in a "Danger Zone" section
- Button:
<Button size="sm" variant="danger">Delete OIDC Configuration</Button> - Confirmation:
ConfirmDialog(type-to-confirm)- Message:
Delete OIDC configuration? All users signed in via OIDC will lose access. - Confirm text:
"delete oidc"(static string) - NO
loadingprop
- Message:
- Toast on success:
variant: 'warning', title: "Configuration deleted"
INCONSISTENCY: No loading prop on this ConfirmDialog, unlike all other delete confirmations.
1.10 Delete App
- File:
ui/src/pages/AppsTab/AppsTab.tsx(lines 533-539, 565, 589-596) - Button location: App detail header, top-right, in
detailActionsdiv alongside "Upload JAR" - Button:
<Button size="sm" variant="danger">Delete App</Button> - Confirmation:
ConfirmDialog(type-to-confirm)- Message:
Delete app "${displayName}"? All versions and deployments will be removed. This cannot be undone. - Confirm text: app's
slug - Has
loadingprop
- Message:
- Toast on success:
variant: 'warning', title: "App deleted" - Post-delete: Navigates to
/apps
1.11 Stop Deployment
- File:
ui/src/pages/AppsTab/AppsTab.tsx(lines 526-531, 672) - Button location: Inline in deployments table, right-aligned actions column
- Button:
<Button size="sm" variant="danger">Stop</Button> - Confirmation: NONE -- immediate mutation on click
- Toast on success:
variant: 'warning', title: "Deployment stopped"
INCONSISTENCY: Stopping a deployment is a destructive operation that affects live services but has NO confirmation dialog. Route stop/suspend in RouteControlBar uses a ConfirmDialog, but deployment stop does not.
1.12 Stop/Suspend Route
- File:
ui/src/pages/Exchanges/RouteControlBar.tsx(lines 43-154) - Button location: Route control bar (segmented button group)
- Button: Custom segmented
<button>elements (not design system Button) - Confirmation:
ConfirmDialog(type-to-confirm) -- only forstopandsuspendactions- Title:
"Stop route?"or"Suspend route?" - Message:
This will ${action} route "${routeId}" on ${application}. This affects all live agents. - Confirm text: the action name (e.g.,
"stop"or"suspend") - Confirm label:
"Stop Route"or"Suspend Route" - Variant:
dangerfor stop,warningfor suspend - Has
loadingprop
- Title:
- Start and Resume: No confirmation (immediate action)
- Toast patterns match others
1.13 Delete Tap (Route Detail page)
- File:
ui/src/pages/Routes/RouteDetail.tsx(lines 991-1001) - Button location: Inline delete icon button in taps table row
- Confirmation:
ConfirmDialog(type-to-confirm)- Title: "Delete Tap"
- Message:
This will remove the tap "${attributeName}" from the configuration. - Confirm text: tap's
attributeName - Confirm label: "Delete"
- Variant:
danger
- No
loadingprop on this dialog
INCONSISTENCY: No loading prop, unlike entity delete confirmations.
1.14 Delete Tap (TapConfigModal)
- File:
ui/src/components/TapConfigModal.tsx(lines 117-122, 249-253) - Button location: Inside the modal footer, left-aligned (only shown when editing)
- Button:
<Button variant="danger">Delete</Button> - Confirmation: NONE -- immediate call to
onDeletethenonClose - Toast: Handled by parent component (ExchangesPage)
INCONSISTENCY: Deleting a tap from the TapConfigModal has no confirmation, but deleting from the RouteDetail table shows a ConfirmDialog.
1.15 Kill Database Query
- File:
ui/src/pages/Admin/DatabaseAdminPage.tsx(line 30) - Button location: Inline in active queries table
- Button:
<Button variant="danger" size="sm">Kill</Button> - Confirmation: NONE -- immediate mutation
- Toast: None visible
INCONSISTENCY: Killing a database query is a destructive action with no confirmation and no toast feedback.
2. Button Placement & Order
2.1 Create Forms (Users, Groups, Roles, Environments)
All four entity create forms use an identical pattern:
| Page | File | Line | Left Button | Right Button |
|---|---|---|---|---|
| Users | UsersTab.tsx |
254-274 | Cancel (ghost) | Create (primary) |
| Groups | GroupsTab.tsx |
251-268 | Cancel (ghost) | Create (primary) |
| Roles | RolesTab.tsx |
142-159 | Cancel (ghost) | Create (primary) |
| Environments | EnvironmentsPage.tsx |
181-194 | Cancel (ghost) | Create (primary) |
- Position: Bottom of inline create form in the list pane
- Container class:
styles.createFormActions - Order: Cancel (left) | Create (right) -- CONSISTENT
- Variants: Cancel =
ghost, Create =primary-- CONSISTENT - Size: Both
sm-- CONSISTENT
2.2 App Creation Page
- File:
ui/src/pages/AppsTab/AppsTab.tsx(lines 282-287) - Position: Top of page in
detailActionsheader area - Order: Cancel (ghost, left) | Create & Deploy / Create (primary, right)
- Size: Both
sm - CONSISTENT with the pattern (Cancel left, Submit right)
2.3 OIDC Config Page (Toolbar)
- File:
ui/src/pages/Admin/OidcConfigPage.tsx(lines 130-137) - Position: Top toolbar
- Order: Test Connection (secondary, left) | Save (primary, right)
- No Cancel button -- form is always editable
NOTE: This is the only admin page without a Cancel button or Edit mode toggle.
2.4 App Detail Header
- File:
ui/src/pages/AppsTab/AppsTab.tsx(lines 560-566) - Position: Top-right header area in
detailActions - Order: Upload JAR (primary) | Delete App (danger)
NOTE: The primary action (Upload) is on the LEFT and the destructive action (Delete) is on the RIGHT.
2.5 App Config Detail Page (AppConfigDetailPage)
- File:
ui/src/pages/Admin/AppConfigDetailPage.tsx(lines 308-319) - Position: Top toolbar
- Read mode: Back (ghost) ... Edit (secondary)
- Edit mode: Back (ghost) ... Save (default/no variant specified!) | Cancel (secondary)
- Order when editing: Save (left) | Cancel (right)
INCONSISTENCY #1: Save button has NO variant prop set -- it renders as default, not primary. Every other Save button uses variant="primary".
INCONSISTENCY #2: Button order is REVERSED from every other form. Here it is Save (left) | Cancel (right). Everywhere else it is Cancel (left) | Save (right).
2.6 App Config Sub-Tab (AppsTab ConfigSubTab)
- File:
ui/src/pages/AppsTab/AppsTab.tsx(lines 922-936) - Position: Top banner bar (editBanner)
- Read mode: Banner text + Edit (secondary)
- Edit mode: Banner text + Cancel (ghost) | Save Configuration (primary)
- Order when editing: Cancel (left) | Save (right) -- CONSISTENT
2.7 Environment Default Resources / JAR Retention Sections
- File:
ui/src/pages/Admin/EnvironmentsPage.tsx(lines 437-446, 505-514) - Position: Bottom of section, right-aligned (
justifyContent: 'flex-end') - Read mode: Edit Defaults / Edit Policy (secondary)
- Edit mode: Cancel (ghost) | Save (primary) -- CONSISTENT
- Size: Both
sm
2.8 User Password Reset
- File:
ui/src/pages/Admin/UsersTab.tsx(lines 407-431) - Position: Inline in Security section
- Order: Cancel (ghost) | Set (primary)
- CONSISTENT pattern (Cancel left, Submit right)
2.9 Tap Modal (TapConfigModal)
- File:
ui/src/components/TapConfigModal.tsx(lines 249-257) - Position: Modal footer
- Order (edit mode): Delete (danger, left, in
footerLeft) | Cancel (secondary) | Save (primary) - Order (create mode): Cancel (secondary) | Save (primary)
- No
sizeprop specified -- renders at default size
NOTE: Uses variant="secondary" for Cancel, not variant="ghost" like create forms.
2.10 Tap Modal (RouteDetail inline version)
- File:
ui/src/pages/Routes/RouteDetail.tsx(lines 984-986) - Position: Modal footer (
tapModalFooter) - Order: Cancel (secondary) | Save (primary)
- No
sizeprop specified - CONSISTENT with TapConfigModal
2.11 About Me Dialog
- File:
ui/src/components/AboutMeDialog.tsx(lines 14, 72) - Uses
Modalwith built-in close button (no explicit action buttons) - Close via: Modal
onClosehandler (X button and backdrop click)
2.12 Login Page
- File:
ui/src/auth/LoginPage.tsx(lines 176-184) - Single button: Sign in (primary, full width, submit type)
- Optional SSO button above: Sign in with SSO (secondary)
Summary of Button Order Patterns
| Location | Cancel Side | Submit Side | Consistent? |
|---|---|---|---|
| User create form | Left (ghost) | Right (primary) | YES |
| Group create form | Left (ghost) | Right (primary) | YES |
| Role create form | Left (ghost) | Right (primary) | YES |
| Env create form | Left (ghost) | Right (primary) | YES |
| App create page | Left (ghost) | Right (primary) | YES |
| Env Default Resources edit | Left (ghost) | Right (primary) | YES |
| Env JAR Retention edit | Left (ghost) | Right (primary) | YES |
| AppsTab config sub-tab edit | Left (ghost) | Right (primary) | YES |
| User password reset | Left (ghost) | Right (primary) | YES |
| TapConfigModal | Left (secondary) | Right (primary) | Variant mismatch |
| RouteDetail tap modal | Left (secondary) | Right (primary) | Variant mismatch |
| AppConfigDetailPage | Left (NO variant) | Right (secondary) | REVERSED |
3. Edit / Save Patterns
3.1 Users (UsersTab)
- Edit mode: No explicit toggle. Display name uses
InlineEdit(click-to-edit). Everything else is managed via tag add/remove. - No Save/Cancel for the detail view -- all changes are immediate mutations.
- Unsaved changes indicator: N/A (no batched editing)
- On success: Toast with
variant: 'success' - On error: Toast with
variant: 'error',duration: 86_400_000(effectively permanent)
3.2 Groups (GroupsTab)
- Edit mode: Name uses
InlineEdit. All other changes (members, roles) are immediate mutations. - Pattern: Same as Users -- no batched edit mode.
3.3 Roles (RolesTab)
- Edit mode: Read-only detail panel. No editing of role fields.
- Only action: Delete
3.4 Environments (EnvironmentsPage)
- Edit mode (name):
InlineEdit - Edit mode (production/enabled toggles): Immediate mutations per toggle change
- Edit mode (Default Resources): Explicit Edit toggle (
setEditing(true))- Cancel/Save buttons appear at bottom-right
- Resets form on cancel
- No unsaved changes indicator
- On success: Toast
variant: 'success'
- Edit mode (JAR Retention): Same pattern as Default Resources
- On environment switch: Both sub-sections auto-reset to read mode
3.5 OIDC Config (OidcConfigPage)
- Edit mode: ALWAYS editable (no toggle)
- Save button: Always visible in top toolbar
- No Cancel button -- cannot discard changes
- No unsaved changes indicator
- On success: Toast
variant: 'success' - On error: Toast
variant: 'error'+ inline<Alert variant="error">both shown
INCONSISTENCY: Only page that is always editable with no way to discard changes. Also the only page that shows BOTH a toast AND an inline alert on error.
3.6 App Config Detail (AppConfigDetailPage)
- Edit mode: Explicit toggle via
Editbutton (Pencil icon) in toolbar - Toolbar in edit mode: Save (unstyled!) | Cancel (secondary)
- Save button text: Shows "Saving..." while pending
- No unsaved changes indicator
- On success: Toast
variant: 'success', exits edit mode - On error: Toast
variant: 'error', stays in edit mode
3.7 App Config Sub-Tab (AppsTab ConfigSubTab)
- Edit mode: Explicit toggle via banner + Edit button
- Banner in read mode: "Configuration is read-only. Enter edit mode to make changes."
- Banner in edit mode: "Editing configuration. Changes are not saved until you click Save." (styled differently with
editBannerActive) - This IS an unsaved changes indicator (the banner text changes)
- Cancel/Save in edit banner: Cancel (ghost) | Save Configuration (primary)
- On success: Toast
variant: 'success', exits edit mode, shows redeploy notice - On error: Toast
variant: 'error', stays in edit mode
3.8 App Create Page
- Edit mode: N/A (always a creation form)
- Multi-step indicator: Shows step text like "Creating app...", "Uploading JAR..." during submission
- On success: Toast
variant: 'success', navigates to app detail page - On error: Toast
variant: 'error'with step context
3.9 Tap Editing (TapConfigModal + RouteDetail inline)
- Edit mode: Modal opens for edit or create
- Save/Cancel: In modal footer
- On success: Modal closes, parent handles toast
- On error: Parent handles toast
Summary of Edit Patterns
| Page | Explicit Edit Toggle? | Unsaved Changes Indicator? | Consistent? |
|---|---|---|---|
| Users | No (inline edits) | N/A | N/A |
| Groups | No (inline edits) | N/A | N/A |
| Roles | No (read-only) | N/A | N/A |
| Environments - name | No (InlineEdit) | N/A | OK |
| Environments - resources | YES | No | Missing |
| Environments - JAR retention | YES | No | Missing |
| OIDC Config | No (always editable) | No | Deviation |
| AppConfigDetailPage | YES | No | Missing |
| AppsTab ConfigSubTab | YES (banner) | YES (banner text) | Best pattern |
INCONSISTENCY: The AppsTab ConfigSubTab is the only one with a proper unsaved-changes indicator. AppConfigDetailPage (which edits the same data for a different entry point) has no such indicator.
4. Toast / Notification Patterns
4.1 Toast Provider
- File:
ui/src/components/LayoutShell.tsx(line 783) - Provider:
<ToastProvider>from@cameleer/design-systemwraps the entire app layout - Hook:
useToast()returns{ toast }function
4.2 Toast Call Signature
All toast calls use the same shape:
toast({
title: string,
description?: string,
variant: 'success' | 'error' | 'warning',
duration?: number
})
4.3 Toast Variants Used
| Variant | Used For | Duration |
|---|---|---|
success |
Successful operations | Default (auto-dismiss) |
error |
Failed operations | 86_400_000 (24 hours = effectively permanent) |
warning |
Destructive successes (delete, stop) AND partial failures | Mixed (see below) |
4.4 Duration Patterns
- Success toasts: No explicit duration (uses design system default) -- CONSISTENT
- Error toasts: Always
duration: 86_400_000-- CONSISTENT (49 occurrences across 10 files) - Warning toasts for deletion success (user/group/role/env/OIDC/app deleted): No explicit duration (auto-dismiss) -- CONSISTENT
- Warning toasts for partial push failures:
duration: 86_400_000-- CONSISTENT
4.5 Naming Conventions for Toast Titles
Success pattern: Action-noun format
- "User created", "Group created", "Role created", "Environment created"
- "Display name updated", "Password updated", "Group renamed"
- "Config saved", "Configuration saved", "Tap configuration saved"
Error pattern: "Failed to [action]" format
- "Failed to create user", "Failed to delete group", "Failed to update password"
- "Save failed", "Upload failed", "Deploy failed" (shorter form)
INCONSISTENCY: Error messages mix two patterns:
- "Failed to [verb] [noun]" (e.g., "Failed to create user") -- used in RBAC pages
- "[Noun] failed" (e.g., "Save failed", "Upload failed") -- used in AppsTab, AppConfigDetailPage
4.6 Warning Variant for Deletions
Successful deletions use variant: 'warning' consistently:
- "User deleted" (UsersTab:162)
- "Group deleted" (GroupsTab:147)
- "Role deleted" (RolesTab:100)
- "Environment deleted" (EnvironmentsPage:105)
- "Configuration deleted" (OidcConfigPage:119)
- "App deleted" (AppsTab:536)
- "Deployment stopped" (AppsTab:529)
CONSISTENT -- all destructive-but-successful operations use warning.
5. Loading / Empty States
5.1 Full-Page Loading States
| Page | Component | Size | Wrapper |
|---|---|---|---|
| UsersTab | <Spinner size="md" /> |
md | Bare return |
| GroupsTab | <Spinner size="md" /> |
md | Bare return |
| RolesTab | <Spinner size="md" /> |
md | Bare return |
| EnvironmentsPage | <Spinner size="md" /> |
md | Bare return |
| AppListView | <Spinner size="md" /> |
md | Bare return |
| AppDetailView | <Spinner size="md" /> |
md | Bare return |
| AgentInstance | <Spinner size="lg" /> |
lg | Bare return |
| AppConfigDetailPage | <Spinner size="lg" /> |
lg | Wrapped in div.loading |
| DashboardPage | <PageLoader /> |
lg | Centered container |
| RuntimePage | <PageLoader /> |
lg | Centered container |
| OidcConfigPage | return null |
N/A | Returns nothing |
INCONSISTENCY #1: Most admin pages use <Spinner size="md" /> as a bare return. AgentInstance and AppConfigDetailPage use size="lg". DashboardPage and RuntimePage use the <PageLoader /> component which wraps <Spinner size="lg" /> in a centered container.
INCONSISTENCY #2: OidcConfigPage returns null while loading (shows a blank page), unlike every other page.
INCONSISTENCY #3: SplitPane detail loading (GroupsTab line 317, RolesTab line 212) uses <Spinner size="md" /> -- consistent within that context.
5.2 Section Loading States
- RouteDetail charts:
<Spinner size="sm" />inline in chart containers (lines 713, 804) - AboutMeDialog:
<Spinner size="md" />in adiv.loadingwrapper
5.3 Empty States
| Context | Pattern | Component Used |
|---|---|---|
| SplitPane list (no search match) | emptyMessage="No X match your search" |
EntityList built-in |
| SplitPane detail (nothing selected) | emptyMessage="Select a X to view details" |
SplitPane built-in |
| Deployments table (none) | <p className={styles.emptyNote}>No deployments yet.</p> |
Plain <p> |
| Versions list (none) | <p className={styles.emptyNote}>No versions uploaded yet.</p> |
Plain <p> |
| Env vars (none, not editing) | <p className={styles.emptyNote}>No environment variables configured.</p> |
Plain <p> |
| Traces/Taps (none) | <p className={styles.emptyNote}>No processor traces or taps configured.</p> |
Plain <p> |
| Route recording (none) | <p className={styles.emptyNote}>No routes found for this application.</p> |
Plain <p> |
| AgentInstance metrics | <EmptyState title="No data" description="No X available" /> |
EmptyState (DS component) |
| Log/Event panels | <div className={logStyles.logEmpty}>No events...</div> |
Styled <div> |
| OIDC default roles | <span className={styles.noRoles}>No default roles configured</span> |
<span> |
| Group members (none) | <span className={styles.inheritedNote}>(no members)</span> |
<span> |
| AppConfigDetailPage (not found) | <div>No configuration found for "{appId}".</div> |
Plain <div> |
| RouteDetail error patterns | <div className={styles.emptyText}>No error patterns found...</div> |
Styled <div> |
| RouteDetail taps (none) | <div className={styles.emptyState}>No taps configured...</div> |
Styled <div> |
INCONSISTENCY: Empty states use at least 5 different approaches:
- Design system
EmptyStatecomponent (only in AgentInstance) <p className={styles.emptyNote}>(AppsTab)<span className={styles.inheritedNote}>with parenthetical format "(none)" (RBAC pages)<div className={styles.emptyText}>(RouteDetail)- Unstyled inline text (AppConfigDetailPage)
The design system provides an EmptyState component but it is only used in one place (AgentInstance).
6. Inconsistency Summary
HIGH Priority (User-facing confusion)
-
AppConfigDetailPage button order is reversed (Save|Cancel instead of Cancel|Save) and Save button has no
variant="primary". File:ui/src/pages/Admin/AppConfigDetailPage.tsx, lines 311-315. -
Deployment Stop has no confirmation dialog. Stopping a running deployment immediately executes with no confirmation, while stopping/suspending a route shows a ConfirmDialog. File:
ui/src/pages/AppsTab/AppsTab.tsx, line 672. -
Tap deletion is inconsistent. Deleting from TapConfigModal: no confirmation. Deleting from RouteDetail table: ConfirmDialog. File:
ui/src/components/TapConfigModal.tsxline 117 vsui/src/pages/Routes/RouteDetail.tsxline 992. -
Kill Query has no confirmation and no feedback. File:
ui/src/pages/Admin/DatabaseAdminPage.tsx, line 30.
MEDIUM Priority (Pattern deviations)
-
Cancel button variant inconsistency. Create forms use
variant="ghost"for Cancel. Modal dialogs (TapConfigModal, RouteDetail tap modal) usevariant="secondary". File:ui/src/components/TapConfigModal.tsxline 255, vsui/src/pages/Admin/UsersTab.tsxline 258. -
Removing a role from a user has no confirmation but removing a group from a user shows an AlertDialog. Both can cascade. File:
ui/src/pages/Admin/UsersTab.tsx, lines 504-528 vs 588-613. -
OIDC Config is always editable with no Cancel/discard. Every other editable form either has inline-edit (immediate save) or explicit edit mode with Cancel. File:
ui/src/pages/Admin/OidcConfigPage.tsx. -
OIDC Config delete ConfirmDialog missing
loadingprop. All other delete ConfirmDialogs passloading={mutation.isPending}. File:ui/src/pages/Admin/OidcConfigPage.tsx, line 258. -
Loading state size inconsistency. Most pages use
Spinner size="md", some usesize="lg", some usePageLoader, and OidcConfigPage returnsnull. No single standard. -
Error toast title format inconsistency. RBAC pages use "Failed to [verb] [noun]" while AppsTab/AppConfigDetailPage use "[Noun] failed". Should pick one.
LOW Priority (Minor deviations)
-
Empty state presentation varies widely. Five different approaches used. Should standardize on the design system
EmptyStatecomponent or at least a consistent CSS class. -
ConfirmDialog confirmText varies between display name and slug. Users/Groups/Roles use display name; Environments and Apps use slug. This is arguably intentional (slug is the technical identifier) but may confuse users.
-
OIDC Config shows both toast and inline Alert on error. No other page shows both simultaneously. File:
ui/src/pages/Admin/OidcConfigPage.tsx, line 92 (toast) + line 139 (inline Alert). -
AppConfigDetailPage Save button text changes to "Saving..." using string interpolation, while every other page uses the
loadingprop on Button (which shows a spinner). File:ui/src/pages/Admin/AppConfigDetailPage.tsx, line 313. -
Unsaved changes indicator only present on AppsTab ConfigSubTab (banner text). AppConfigDetailPage, Environment resource sections, and JAR retention section have no indicator even though they use explicit edit mode.
7. ConfirmDialog Usage Matrix
| Object | File | Line | confirmText Source | Has loading? |
Has variant? |
Has confirmLabel? |
|---|---|---|---|---|---|---|
| User | UsersTab.tsx | 580 | displayName | YES | No (default) | No (default) |
| Group | GroupsTab.tsx | 434 | name | YES | No (default) | No (default) |
| Role | RolesTab.tsx | 223 | name | YES | No (default) | No (default) |
| Environment | EnvironmentsPage.tsx | 319 | slug | YES | No (default) | No (default) |
| OIDC Config | OidcConfigPage.tsx | 258 | "delete oidc" | NO | No (default) | No (default) |
| App | AppsTab.tsx | 589 | slug | YES | No (default) | No (default) |
| Tap (RouteDetail) | RouteDetail.tsx | 992 | attributeName | NO | danger |
"Delete" |
| Route Stop | RouteControlBar.tsx | 139 | action name | YES | danger/warning |
"Stop Route" / "Suspend Route" |
NOTE: RouteControlBar and RouteDetail set explicit variant and confirmLabel on ConfirmDialog while all RBAC/admin pages use defaults. This creates visual differences in the confirmation dialogs.
8. AlertDialog Usage Matrix
| Context | File | Line | Title | Confirm Label | Variant |
|---|---|---|---|---|---|
| Remove group from user | UsersTab.tsx | 588 | "Remove group membership" | "Remove" | warning |
| Remove role from group | GroupsTab.tsx | 442 | "Remove role from group" | "Remove" | warning |
AlertDialog is used consistently where present (both use warning variant and "Remove" label).
9. Files Examined
All .tsx files under ui/src/pages/ and ui/src/components/:
ui/src/pages/Admin/UsersTab.tsxui/src/pages/Admin/GroupsTab.tsxui/src/pages/Admin/RolesTab.tsxui/src/pages/Admin/EnvironmentsPage.tsxui/src/pages/Admin/OidcConfigPage.tsxui/src/pages/Admin/AppConfigDetailPage.tsxui/src/pages/Admin/DatabaseAdminPage.tsxui/src/pages/Admin/ClickHouseAdminPage.tsxui/src/pages/Admin/AuditLogPage.tsxui/src/pages/AppsTab/AppsTab.tsxui/src/pages/Routes/RouteDetail.tsxui/src/pages/Exchanges/ExchangesPage.tsxui/src/pages/Exchanges/RouteControlBar.tsxui/src/pages/AgentHealth/AgentHealth.tsxui/src/pages/AgentInstance/AgentInstance.tsxui/src/pages/DashboardTab/DashboardPage.tsxui/src/pages/RuntimeTab/RuntimePage.tsxui/src/components/TapConfigModal.tsxui/src/components/AboutMeDialog.tsxui/src/components/PageLoader.tsxui/src/components/LayoutShell.tsxui/src/auth/LoginPage.tsx