Files
vibe-kanban/frontend/vite.config.ts
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

78 lines
2.0 KiB
TypeScript

// vite.config.ts
import { sentryVitePlugin } from "@sentry/vite-plugin";
import { defineConfig, Plugin } from "vite";
import react from "@vitejs/plugin-react";
import path from "path";
import fs from "fs";
function executorSchemasPlugin(): Plugin {
const VIRTUAL_ID = "virtual:executor-schemas";
const RESOLVED_VIRTUAL_ID = "\0" + VIRTUAL_ID;
return {
name: "executor-schemas-plugin",
resolveId(id) {
if (id === VIRTUAL_ID) return RESOLVED_VIRTUAL_ID; // keep it virtual
return null;
},
load(id) {
if (id !== RESOLVED_VIRTUAL_ID) return null;
const schemasDir = path.resolve(__dirname, "../shared/schemas");
const files = fs.existsSync(schemasDir)
? fs.readdirSync(schemasDir).filter((f) => f.endsWith(".json"))
: [];
const imports: string[] = [];
const entries: string[] = [];
files.forEach((file, i) => {
const varName = `__schema_${i}`;
const importPath = `shared/schemas/${file}`; // uses your alias
const key = file.replace(/\.json$/, "").toUpperCase(); // claude_code -> CLAUDE_CODE
imports.push(`import ${varName} from "${importPath}";`);
entries.push(` "${key}": ${varName}`);
});
// IMPORTANT: pure JS (no TS types), and quote keys.
const code = `
${imports.join("\n")}
export const schemas = {
${entries.join(",\n")}
};
export default schemas;
`;
return code;
},
};
}
export default defineConfig({
plugins: [
react(),
sentryVitePlugin({ org: "bloop-ai", project: "vibe-kanban" }),
executorSchemasPlugin(),
],
resolve: {
alias: {
"@": path.resolve(__dirname, "./src"),
shared: path.resolve(__dirname, "../shared"),
},
},
server: {
port: parseInt(process.env.FRONTEND_PORT || "3000"),
proxy: {
"/api": {
target: `http://localhost:${process.env.BACKEND_PORT || "3001"}`,
changeOrigin: true,
},
},
fs: {
allow: [path.resolve(__dirname, "."), path.resolve(__dirname, "..")],
},
},
build: { sourcemap: true },
});