Skip to content

feat(dashboard): merge agent config modal into expandable sections#795

Merged
aaight merged 3 commits intodevfrom
feature/inline-agent-config-expandable
Mar 14, 2026
Merged

feat(dashboard): merge agent config modal into expandable sections#795
aaight merged 3 commits intodevfrom
feature/inline-agent-config-expandable

Conversation

@aaight
Copy link
Copy Markdown
Collaborator

@aaight aaight commented Mar 14, 2026

Summary

  • Moves agent config form fields (model, max iterations, engine, max concurrency) from the Dialog modal into each agent's expandable row, alongside triggers
  • Adds Save/Reset/Delete buttons in a footer at the bottom of each expanded section
  • Removes the Edit/Delete buttons from collapsed header rows, keeping AgentConfigBadge for quick reference
  • Eliminates the Dialog modal and all modal-related state (dialogOpen, editing, agentType, model, etc.) from ProjectAgentConfigs
  • Cleans up unused imports (Dialog, Pencil, Trash2, etc.)
  • Updates DefinitionAgentSection props interface with onSaveConfig, isSaving, and engines

The global settings modal (AgentConfigFormDialog used by agent-configs-table.tsx) is untouched.

Trello card: https://trello.com/c/MtgOurMH/315-lets-rethink-the-dashboard-ui-for-editing-project-level-agent-configs-right-now-we-have-both-modal-edit-agent-config-and-expanda

Test plan

  • Expand an agent row → config fields (model, iterations, engine, concurrency) and triggers are visible
  • Edit a field and click Save → config is created or updated inline
  • Click Reset → fields revert to saved values
  • Click Delete Config → confirm dialog appears, config is removed
  • Collapsed row shows AgentConfigBadge summary (no Edit/Delete buttons)
  • Global Settings > Agent Configs modal still works (unaffected)
  • All unit tests pass (npm test)
  • Lint and type checks pass

🤖 Generated with Claude Code

Copy link
Copy Markdown
Collaborator

@nhopeatall nhopeatall left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Summary

Clean refactor that moves agent config editing from a modal into inline expandable sections. The approach simplifies state management by eliminating shared modal state and co-locating form state with each agent section. Two issues worth addressing around the "Saved" indicator and timer cleanup.

Code Issues

Should Fix

  • project-agent-configs.tsx ~line 155-156setSaved(true) is called immediately in handleSave() before the async mutation completes. If the mutation fails, the user sees "Saved" text for 2 seconds simultaneously with the error toast, which is confusing and misleading. The "Saved" indicator should only appear after confirmed persistence — either by having onSaveConfig accept a success callback, or by deriving the "just saved" state from the parent (e.g., a prop that flips after onSuccess fires in the mutation).

  • project-agent-configs.tsx ~line 156 — The setTimeout(() => setSaved(false), 2000) timer is not cleaned up on unmount. If the user collapses the section or navigates away within 2 seconds of saving, React will warn about a state update on an unmounted component. Store the timeout ID in a useRef and clear it in a useEffect cleanup, or use a useEffect that reacts to the saved state changing to true.

Both issues also exist in the lifecycle triggers section (line ~564-566 area), but that code predates this PR. Worth fixing both together since the pattern is being replicated.

…p timers

- setSaved(true) now fires only after the mutation's onSuccess callback,
  preventing "Saved" text showing when the mutation fails
- Save success is signalled via a per-agent saveSuccessNonce counter that
  increments on each confirmed onSuccess, so repeated saves always trigger
  the useEffect in DefinitionAgentSection
- setTimeout IDs are stored in useRef and cleared in useEffect cleanup to
  avoid state updates on unmounted components (fixes both agent section and
  lifecycle triggers section)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Copy link
Copy Markdown
Collaborator

@nhopeatall nhopeatall left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Summary

Clean refactoring that consolidates the agent config modal into inline expandable sections. The approach is sound — eliminating the modal in favor of inline editing improves discoverability and reduces state management complexity. CI is green. Two issues worth addressing.

Code Issues

Should Fix

  • Saved indicator race condition (project-agent-configs.tsx:118): After a successful save, onSuccess increments saveSuccessNonce (which triggers setSaved(true) via useEffect) and simultaneously calls invalidateQueries. When the refetch resolves shortly after, the config prop gets a new reference, which triggers the [config] sync useEffect that calls setSaved(false). The "Saved" indicator will flash briefly and then disappear when the query resolves — could be near-instant on fast networks. Consider either (a) skipping the setSaved(false) in the config sync effect when saved is already true, (b) using a ref to track "just saved" state that the config sync effect can check and clear, or (c) keying the nonce reset on a timeout rather than config changes.

  • deleteMutation missing error handling (project-agent-configs.tsx:445-448): The deleteMutation has no onError callback. If a delete fails, the error is silently swallowed — the user clicks Delete, confirms, and gets no feedback. The create/update mutations both have toast.error handlers; the delete mutation should be consistent.

…or handling

- Add `justSavedRef` to prevent the config sync effect from clearing the
  "Saved" indicator when `invalidateQueries` triggers a refetch after save
- Set `justSavedRef.current = true` in the nonce effect before showing the
  indicator, cleared by the next config sync cycle
- Add `onError` toast to `deleteMutation` for consistent error feedback
  alongside create/update mutations

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Copy link
Copy Markdown
Collaborator

@nhopeatall nhopeatall left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Summary

Clean refactoring that moves agent config form fields from a dialog modal into inline expandable sections. The change is well-scoped to a single file, CI passes, types check, and the implementation is sound.

Code Issues

Should Fix

  • project-agent-configs.tsx:639 — Minor race condition in isSaving indicator: savingAgentType is a single string shared across all agent sections. If a user rapidly saves two agents (A then B), savingAgentType is overwritten to B. When A's onSuccess fires setSavingAgentType(null), this clears the saving state while B's mutation is still in-flight, causing B's isSaving prop to briefly evaluate to false. Consider using a Set<string> instead to track saving state per agent type independently.

  • project-agent-configs.tsx:245maxIterations number input is missing min={1} (or min={0}), while maxConcurrency on line 260 correctly has min={1}. This means a user could enter negative iteration values. Add min={1} for consistency.

Both are minor and don't block merge.

What's Good

  • Removing the Dialog and 7 associated state variables (dialogOpen, editing, agentType, model, maxIterations, agentEngine, maxConcurrency) eliminates the biome cognitive-complexity suppression, confirming the refactoring genuinely simplified the component.
  • The nonce-based "Saved" indicator with justSavedRef is a thoughtful design that prevents flicker when invalidateQueries triggers a refetch that would otherwise clear the saved state.
  • Proper error handling added via toast.error on all mutation paths (create, update, delete) — the old code was silently swallowing errors on create/update.
  • Timer cleanup on unmount prevents state updates on unmounted components.
  • Mutations now accept explicit input parameters instead of capturing parent scope, making them more predictable and testable.

@aaight aaight merged commit e8b0177 into dev Mar 14, 2026
6 checks passed
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.

2 participants