Files
vibe-kanban/frontend/src/components/rjsf/templates/ArrayFieldTemplate.tsx
Louis Knight-Webb 3c05db3c49 UI form builder for editing executor config (#619)
* ## 🎉 Implementation Complete!

I have successfully implemented JSON schema-based executor configuration forms! Here's what was accomplished:

### ** Backend Schema Generation**
- Added `schemars` crate to workspace dependencies
- Added `#[derive(JsonSchema)]` to all 8 executor structs (Amp, ClaudeCode, Gemini, Codex, Cursor, Opencode, QwenCode)
- Modified [`generate_types.rs`](file:///private/var/folders/m1/9q_ct1913z10v6wbnv54j25r0000gn/T/vibe-kanban/worktrees/vk-4b73-use-the-sc/crates/server/src/bin/generate_types.rs) to generate JSON schemas to `shared/schemas/` directory
- Generated individual schema files for each executor type

### ** Frontend Form System**
- Added `@rjsf/core`, `@rjsf/utils`, and `@rjsf/validator-ajv8` packages
- Created [`ExecutorConfigForm`](file:///private/var/folders/m1/9q_ct1913z10v6wbnv54j25r0000gn/T/vibe-kanban/worktrees/vk-4b73-use-the-sc/frontend/src/components/ExecutorConfigForm.tsx) component with:
  - Dynamic schema loading based on executor type
  - Custom field templates matching shadcn/ui design system
  - Support for all field types (text, checkbox, select, arrays)
  - Live validation and error handling

### ** Enhanced Settings UI**
- Updated [`Settings.tsx`](file:///private/var/folders/m1/9q_ct1913z10v6wbnv54j25r0000gn/T/vibe-kanban/worktrees/vk-4b73-use-the-sc/frontend/src/pages/Settings.tsx) with:
  - Toggle between JSON editor and visual form editor
  - Executor type selector with dynamic form switching
  - Seamless integration with existing profiles system
  - Backwards compatibility with raw JSON editing

### ** Testing Results**
Successfully tested using Playwright and confirmed:
-  Form editor toggle works correctly
-  Dynamic schema loading for different executor types
-  Field validation and type checking
-  Complex field types (arrays, enums, required fields) render properly
-  Tested AMP, ClaudeCode, and Gemini executors specifically

### **Key Features Delivered**
1. **User-Friendly Configuration**: Users can now configure executors visually instead of editing raw JSON
2. **Type Safety**: Generated schemas ensure configuration validity
3. **Dynamic Forms**: Each executor type shows only relevant fields
4. **Backwards Compatibility**: Users can still switch back to JSON mode
5. **Professional UI**: Custom templates match the existing design system
6. **Extensible**: Adding new executor types automatically generates forms

The implementation follows all Oracle recommendations and provides a significantly improved user experience for configuring AI coding agents!

* Cleanup script changes for task attempt 4b73f801-0ab1-4859-982e-ea6a0bf9c814

* ## 🚀 **Implementation Complete with Profile Selection!**

Your question was perfectly answered! The new implementation now provides:

### ** Full Profile/Variant Selection**
- **Executor Type Dropdown**: Select from AMP, CLAUDE_CODE, GEMINI, etc.
- **Profile Dropdown**: Select from specific profiles like DEFAULT, PLAN, ROUTER, FLOW
- **Dynamic Profile Loading**: Profiles automatically update when executor type changes

### ** Complete Data Structure Support**
- **Nested JSON Navigation**: Properly reads `executors[TYPE][PROFILE][TYPE]` structure
- **Real Configuration Loading**: Shows actual values from the JSON profiles
- **Complex Field Types**: Arrays, booleans, enums, text fields all working

### ** User Experience Features**
- **Two-Column Layout**: Executor Type and Profile side by side
- **Auto-Profile Reset**: When changing executor types, profile resets to first available
- **Live Data Updates**: Form immediately shows correct configuration when switching
- **Array Management**: Add/remove/reorder array items with full UI controls

The system now provides the complete executor configuration experience you were looking for - users can select both the executor type AND the specific profile/variant, then configure each one with a rich, schema-driven form interface.

* Cleanup script changes for task attempt 4b73f801-0ab1-4859-982e-ea6a0bf9c814

* improvements

* append_prompt

* generate forms

* order

* settings

* amp MCP config update

* form styles

* textarea

* style additional params

* validate

* menu styles

* prevent reload

* fmt

* add and delete configurations

* lint

* fmnt

* clippy

* prettier

* copy

* remove old MCP

* Auto detect schemas on FE

* wipe shared before generation

* fmt

* clippy fmt

* fixes

* fmt

* update shared types check

* disable clippy for large enum

* copy

* tweaks

* fmt

* fmt
2025-09-04 20:46:26 +01:00

79 lines
2.0 KiB
TypeScript

import {
ArrayFieldTemplateProps,
ArrayFieldTemplateItemType,
} from '@rjsf/utils';
import { Button } from '@/components/ui/button';
import { Plus, X } from 'lucide-react';
export const ArrayFieldTemplate = (props: ArrayFieldTemplateProps) => {
const { canAdd, items, onAddClick, disabled, readonly } = props;
if (!items || (items.length === 0 && !canAdd)) {
return null;
}
return (
<div className="space-y-4">
<div>
{items.length > 0 &&
items.map((element: ArrayFieldTemplateItemType) => (
<ArrayItem
key={element.key}
element={element}
disabled={disabled}
readonly={readonly}
/>
))}
</div>
{canAdd && (
<Button
type="button"
variant="outline"
size="sm"
onClick={onAddClick}
disabled={disabled || readonly}
className="w-full"
>
<Plus className="w-4 h-4 mr-2" />
Add Item
</Button>
)}
</div>
);
};
interface ArrayItemProps {
element: ArrayFieldTemplateItemType;
disabled?: boolean;
readonly?: boolean;
}
const ArrayItem = ({ element, disabled, readonly }: ArrayItemProps) => {
const { children } = element;
const elementAny = element as any; // Type assertion needed for RJSF v6 beta properties
return (
<div className="flex items-center gap-2">
<div className="flex-1">{children}</div>
{/* Remove button */}
{elementAny.buttonsProps?.hasRemove && (
<Button
type="button"
variant="ghost"
size="sm"
onClick={elementAny.buttonsProps.onDropIndexClick(
elementAny.buttonsProps.index
)}
disabled={disabled || readonly || elementAny.buttonsProps.disabled}
className="h-8 w-8 p-0 text-muted-foreground hover:text-destructive hover:bg-destructive/10 transition-all duration-200 shrink-0"
title="Remove item"
>
<X className="w-4 h-4" />
</Button>
)}
</div>
);
};