feat(dashboard): per-engine tabs with credentials, settings, and default indicator#1057
feat(dashboard): per-engine tabs with credentials, settings, and default indicator#1057
Conversation
nhopeatall
left a comment
There was a problem hiding this comment.
Summary
Clean refactor from dropdown-based engine selection to per-engine tabs. The architectural approach is sound — the tab-per-engine model is a good fit for the growing engine catalog, and saving all engine settings (not just the active engine) is correct for multi-engine workflows. CI is green. Three minor issues worth addressing.
Code Issues
Should Fix
-
project-harness-form.tsx:89 —
defaultEngineLabelis dead code. The<Select>dropdown that referenced it was removed in this PR, but the variable was kept. Safe to delete. -
project-harness-form.tsx:304-314 —
sharedNote ?? secret.descriptionreplaces the original description rather than appending. When ANTHROPIC_API_KEY appears on the Claude Code tab, the user sees "Also used by: opencode" but loses the original description ("API key for Claude Code (non-subscription) or OpenCode backend") that explains what the credential is for. Consider combining:secret.description + (sharedNote ? ' · ' + sharedNote : '')so the user gets both the purpose and the sharing info. -
project-harness-form.tsx:306 — The "Also used by" note displays raw engine IDs (
opencode,llmist) while every other part of the UI uses the human-readableengine.labelvalues (e.g., "OpenCode", "LLMist"). Theenginesarray from the catalog is in scope inside the.map()— mapping IDs to labels would keep the UI consistent.
🕵️ claude-code · claude-opus-4-6 · run details
…ions - Remove dead code: `defaultEngineLabel` variable left over after Select dropdown was removed - Combine original secret description with sharing note instead of replacing it - Map shared engine IDs to human-readable labels (engine.label) in "Also used by" note Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…vulnerabilities Fixes two high-severity CVEs in picomatch 4.0.3: - GHSA-c2c7-rcm5-vvqj: ReDoS vulnerability via extglob quantifiers - GHSA-3v7f-55p6-f55p: Method Injection in POSIX Character Classes Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
nhopeatall
left a comment
There was a problem hiding this comment.
Summary
Clean refactor from a dropdown-based engine selector to a per-engine tabbed UI. The implementation is sound overall — pattern consistency with the existing codebase is good, the EngineSettingsFields and ProjectSecretField components are reused correctly, and the state management via useState + handleSubmit works despite the form/card split. All CI checks pass. Two issues worth addressing.
Code Issues
Should Fix
-
project-harness-form.tsx:268 — No way to reset to inherit system default. The old dropdown had a
_noneoption that mapped toagentEngine: null, allowing users to opt out of an explicit engine override and inherit the system default. In the new tabbed UI, once the user clicks Set as Default Engine on any tab, there is no mechanism to revert. Even clicking the system default engine (e.g. claude-code) explicitly setsagentEngine: 'claude-code'instead ofnull, so the project loses the ability to dynamically follow future system default changes. Consider adding a Reset to System Default affordance (e.g. a small link or button on the currently-selected tab) that callssetAgentEngine(''). -
project-harness-form.tsx:173-190 and 333-350 — Duplicate Save Changes button. The save button + status indicators are copy-pasted verbatim into both the Model and Runtime card footer and the Engine Settings and Credentials card footer. Both submit the same
form=engine-runtime-form. This creates two issues: (1) UX confusion — the user sees two identical save buttons and may not realize they are the same action, and (2) maintenance burden — any change to the button markup must be updated in two places. Consider extracting a shared SaveFooter component, or keeping only one save button (either in the last card, or as a sticky footer outside both cards).
🕵️ claude-code · claude-opus-4-6 · run details
…save button
- Add "Reset to system default" link on the default engine tab when an engine
is explicitly set, calling setAgentEngine('') to restore inherit behaviour
- Remove the duplicate Save Changes footer from the Model & Runtime card;
a single save button in the Engine Settings & Credentials card footer
now covers both cards via form="engine-runtime-form"
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
nhopeatall
left a comment
There was a problem hiding this comment.
Summary
LGTM — Clean refactor from a single-engine dropdown to per-engine tabbed layout. The implementation is correct, well-structured, and all CI checks pass.
Notes
A few observations (none blocking):
-
Tabs defaultValuevs controlledvalue: TheTabscomponent usesdefaultValue={defaultTab}(uncontrolled). This means when the user clicks "Reset to system default" and the default engine changes to a different engine, the badge will move to the new default's tab but the user's active tab won't switch automatically. This is a minor UX quirk — the user sees the badge leave their current tab and has to click the new default tab to see it. Consider using controlledvalue+onValueChangeif you want the tab to follow the default engine, but this is a polish item, not a bug. -
Engine settings now saved for all tabs: The change from saving only the active engine's settings to saving all engine settings (
Object.keys(engineSettings).length > 0 ? engineSettings : null) is a nice improvement. Previously, switching the default engine could lose settings configured for the old engine. The backend JSONB column already supports this, so no migration needed. -
Form-across-cards pattern: The
<form id="engine-runtime-form">is in the Model & Runtime card, and the submit<button form="engine-runtime-form">is in the Engine Settings & Credentials card. This is valid HTML5 and works correctly, but it's worth noting this cross-card form association for future maintainers.
🕵️ claude-code · claude-opus-4-6 · run details
Summary
Refactors the Engine (Harness) tab in the dashboard to use a per-engine tabbed layout, replacing the previous single engine dropdown + separate credentials card with an integrated design:
trpc.agentConfigs.engines). New engines auto-get tabs as the catalog grows.Defaultbadge in the tab trigger and a "✓ Default engine for this project" message in the tab content.agentEnginestate and is persisted on "Save Changes".ENGINE_SECRETSare filtered per tab bysecret.engines.includes(engineId). Shared secrets (e.g.OPENROUTER_API_KEYused by both opencode + llmist) show an "Also used by: ..." note.handleSubmitnow saves all engine settings across all tabs (not just the active engine):engineSettings: Object.keys(engineSettings).length > 0 ? engineSettings : null.In usebadge usingenginesInUseQuery, with a contextual note in the tab content.Frontend-only change — no backend changes. The existing DB schema (JSONB
agent_engine_settings), tRPC endpoints, and engine catalog already support multi-engine configuration.Primary file changed:
web/src/components/projects/project-harness-form.tsxTrello: https://trello.com/c/cTpAdvc0/567-engine-configuration-tabs-in-dashboard-per-engine-credentials-settings-and-default-engine-indicator
Test plan
🤖 Generated with Claude Code
🕵️ claude-code · claude-sonnet-4-6 · run details