Files
alex 6ee667c384 feat: add profile includes management UI
- Add includes section to profile editor with drag-and-drop reordering
- Display included profiles with scope badges (Global, Project, Tool)
- Add 'Add Include' dropdown filtered by compatibility and cycle prevention
- Add remove button per include row
- Save includes together with profile form
- Add include count badges to profile list sidebar
- Add drag icon to Icon component

Implements config-profile-includes-ui tasks 1.1-4.3
2026-05-24 21:02:07 +00:00

4.1 KiB

Context

The config profiles backend already supports full ordered include composition:

  • PUT /config-profiles/{id}/includes accepts an ordered array of profile IDs
  • The API validates ownership, self-inclusion, existence, and cycles
  • GET /config-profiles/{id}/preview resolves includes and shows merged output
  • The frontend profile editor (config-profiles.tsx) already loads all profiles via listConfigProfiles()

However, the profile editor UI currently has no includes management surface. Users can create individual profiles but cannot compose them. This design adds a drag-and-drop includes management section to the existing profile editor.

Goals / Non-Goals

Goals:

  • Allow users to see which profiles a profile includes
  • Allow users to add, remove, and reorder includes
  • Prevent invalid includes (self, duplicates, cycles) in the UI
  • Show scope badges on included profiles for clarity
  • Display include count in the profile list sidebar
  • Save includes together with the profile form

Non-Goals:

  • Backend changes (APIs already fully support this)
  • Drag-and-drop library dependency (use native HTML5 DnD)
  • Profile dependency graph visualization (future enhancement)
  • Validation of include compatibility at the scope level (backend handles this)

Decisions

Use Native HTML5 Drag and Drop

Rationale: No additional dependency needed. The includes list is small (typically < 10 items), so native DnD is sufficient and lightweight. Libraries like react-beautiful-dnd add bundle size and complexity for this use case. Alternative considered: @dnd-kit/core — rejected to keep dependencies minimal.

Save Includes with Main Form

Rationale: The user explicitly requested this. It's simpler UX than a separate save button and matches the mental model of "editing a profile." Implementation: On save, first update profile fields via updateConfigProfile(), then update includes via updateProfileIncludes(). If either fails, show error and don't clear dirty state.

Frontend Cycle Detection

Rationale: Prevents the user from even selecting profiles that would create a cycle, providing immediate feedback instead of waiting for the API to reject it. Implementation: Build a graph from the current profiles array (which includes includes data), then traverse from each candidate profile to check if it can reach the current profile.

Scope Badge Display

Rationale: Helps users understand why certain profiles are or aren't available for inclusion, and what scope each layer operates at. Implementation: Reuse existing scope badge logic from the profile list sidebar (Global, Project scoped, Tool scoped, Project + Tool scoped).

Include Count Badge in Sidebar

Rationale: Quick visual indicator of which profiles are composite vs. standalone. Implementation: Add a small numeric badge next to the profile name when profile.includes.length > 0.

Risks / Trade-offs

[Risk] Saving profile and includes as two separate API calls could lead to partial success (profile saved, includes not saved). → Mitigation: Show clear error state if either call fails. The user can retry. Since includes are independent of profile content, partial failure is recoverable.

[Risk] Large number of profiles could make the "Add Include" dropdown unwieldy. → Mitigation: Cap the dropdown height and add scroll. Typical users have < 20 profiles.

[Risk] Drag-and-drop reordering may feel clunky on mobile. → Mitigation: This is primarily a desktop admin/settings interface. Mobile support is nice-to-have but not critical.

Migration Plan

No migration needed — this is a pure frontend addition. Existing profiles with includes (created via API) will immediately show those includes in the UI.

Open Questions

  1. Should we show a preview of the resolved output (with includes applied) in real-time as includes change?

    • Tentative: No, keep the existing Preview button. Real-time resolution could be expensive and is not requested.
  2. Should we allow including profiles from other users (shared profiles)?

    • Tentative: No, backend already restricts to own profiles. Keep it simple.