# Forms\n\nTypeDialog form definitions for interactive configuration of platform services.\n\n## Purpose\n\nForms provide:\n- **Interactive configuration** - Web/TUI/CLI interfaces for user input\n- **Constraint validation** - Dynamic min/max from constraints.toml\n- **Nickel mapping** - Form fields map to Nickel structure via `nickel_path`\n- **Jinja2 template integration** - Generate Nickel configs from form values\n- **nickel-roundtrip workflow** - Load existing Nickel → edit → generate updated Nickel\n\n## File Organization\n\n```\nforms/\n├── README.md                           # This file\n├── orchestrator-form.toml              # Orchestrator configuration form\n├── control-center-form.toml            # Control Center configuration form\n├── mcp-server-form.toml                # MCP Server configuration form\n├── installer-form.toml                 # Installer configuration form\n└── fragments/                          # FLAT fragment directory (all fragments here)\n    ├── workspace-section.toml          # Workspace configuration\n    ├── server-section.toml             # HTTP server settings\n    ├── database-rocksdb-section.toml   # RocksDB configuration\n    ├── database-surrealdb-section.toml # SurrealDB configuration\n    ├── database-postgres-section.toml  # PostgreSQL configuration\n    ├── security-section.toml           # Auth, RBAC, encryption\n    ├── monitoring-section.toml         # Metrics, health checks\n    ├── logging-section.toml            # Log configuration\n    ├── orchestrator-queue-section.toml # Orchestrator queue config\n    ├── orchestrator-workflow-section.toml\n    ├── control-center-jwt-section.toml\n    ├── control-center-rbac-section.toml\n    ├── mcp-capabilities-section.toml\n    ├── deployment-mode-section.toml    # Mode selection\n    └── README.md                       # Fragment documentation\n```\n\n## Critical: Fragment Organization\n\n**Fragments are FLAT** - all stored in `forms/fragments/` at the same level, referenced by paths in form includes:\n\n```\n# Main form (orchestrator-form.toml)\n[[items]]\nname = "workspace_group"\ntype = "group"\nincludes = ["fragments/workspace-section.toml"]  # Path reference to flat fragment\n\n[[items]]\nname = "queue_group"\ntype = "group"\nincludes = ["fragments/orchestrator-queue-section.toml"]  # Same level, different name\n```\n\n**NOT nested directories** like `fragments/orchestrator/queue-section.toml` - all in `fragments/`\n\n## TypeDialog nickel-roundtrip Workflow\n\nCRITICAL: Forms integrate with Nickel config generation via:\n\n```\ntypedialog-web nickel-roundtrip "$CONFIG_FILE" "$FORM_FILE" --output "$CONFIG_FILE" --template "$NCL_TEMPLATE"\n```\n\nThis workflow:\n1. **Loads existing Nickel config** as default values in form\n2. **Shows form** with validated constraints\n3. **User edits** configuration values\n4. **Generates updated Nickel** using Jinja2 template\n\n## Required Fields: nickel_path\n\n**CRITICAL**: Every form element MUST have `nickel_path` to map to Nickel structure:\n\n```\n[[elements]]\nname = "workspace_name"\ntype = "text"\nprompt = "Workspace Name"\nnickel_path = ["orchestrator", "workspace", "name"]  # ← REQUIRED\n```\n\nThe `nickel_path` array specifies the path in the Nickel config structure:\n- `["orchestrator", "workspace", "name"]` → `orchestrator.workspace.name`\n- `["orchestrator", "queue", "max_concurrent_tasks"]` → `orchestrator.queue.max_concurrent_tasks`\n\n## Constraint Interpolation\n\nForm fields reference constraints dynamically:\n\n```\n[[elements]]\nname = "max_concurrent_tasks"\ntype = "number"\nprompt = "Maximum Concurrent Tasks"\nmin = "${constraint.orchestrator.queue.concurrent_tasks.min}"  # Dynamic\nmax = "${constraint.orchestrator.queue.concurrent_tasks.max}"  # Dynamic\nhelp = "Range: ${constraint.orchestrator.queue.concurrent_tasks.min}-${constraint.orchestrator.queue.concurrent_tasks.max}"\nnickel_path = ["orchestrator", "queue", "max_concurrent_tasks"]\n```\n\nTypeDialog resolves `${constraint.path}` from `constraints/constraints.toml`.\n\n## Main Form Structure\n\nAll main forms follow this pattern:\n\n```\nname = "service_configuration"\ndescription = "Interactive configuration for {Service}"\ndisplay_mode = "complete"\n\n# Section 1: Deployment mode selection\n[[items]]\nname = "deployment_mode_group"\ntype = "group"\nincludes = ["fragments/deployment-mode-section.toml"]\n\n# Section 2: Workspace configuration\n[[items]]\nname = "workspace_group"\ntype = "group"\nincludes = ["fragments/workspace-section.toml"]\n\n# Section 3: Server configuration\n[[items]]\nname = "server_group"\ntype = "group"\nincludes = ["fragments/server-section.toml"]\n\n# Section N: Service-specific configuration\n[[items]]\nname = "service_group"\ntype = "group"\nincludes = ["fragments/{service}-specific-section.toml"]\n\n# Optional: Conditional sections\n[[items]]\nname = "monitoring_group"\ntype = "group"\nwhen = "enable_monitoring == true"\nincludes = ["fragments/monitoring-section.toml"]\n```\n\n## Fragment Example: workspace-section.toml\n\n```\n# Workspace configuration fragment\n[[elements]]\nborder_top = true\nborder_bottom = true\nname = "workspace_header"\ntitle = "🗂️ Workspace Configuration"\ntype = "section_header"\n\n[[elements]]\nname = "workspace_name"\ntype = "text"\nprompt = "Workspace Name"\ndefault = "default"\nplaceholder = "e.g., librecloud, production"\nrequired = true\nhelp = "Name of the workspace"\nnickel_path = ["orchestrator", "workspace", "name"]\n\n[[elements]]\nname = "workspace_path"\ntype = "text"\nprompt = "Workspace Path"\ndefault = "/var/lib/provisioning/orchestrator"\nrequired = true\nhelp = "Absolute path to workspace directory"\nnickel_path = ["orchestrator", "workspace", "path"]\n\n[[elements]]\nname = "workspace_enabled"\ntype = "confirm"\nprompt = "Enable Workspace?"\ndefault = true\nnickel_path = ["orchestrator", "workspace", "enabled"]\n\n[[elements]]\nname = "multi_workspace"\ntype = "confirm"\nprompt = "Multi-Workspace Mode?"\ndefault = false\nhelp = "Allow serving multiple workspaces"\nnickel_path = ["orchestrator", "workspace", "multi_workspace"]\n```\n\n## Fragment Example: orchestrator-queue-section.toml\n\n```\n# Orchestrator queue configuration\n[[elements]]\nborder_top = true\nname = "queue_header"\ntitle = "⚙️ Queue Configuration"\ntype = "section_header"\n\n[[elements]]\nname = "max_concurrent_tasks"\ntype = "number"\nprompt = "Maximum Concurrent Tasks"\ndefault = 5\nmin = "${constraint.orchestrator.queue.concurrent_tasks.min}"\nmax = "${constraint.orchestrator.queue.concurrent_tasks.max}"\nrequired = true\nhelp = "Max tasks running simultaneously. Range: ${constraint.orchestrator.queue.concurrent_tasks.min}-${constraint.orchestrator.queue.concurrent_tasks.max}"\nnickel_path = ["orchestrator", "queue", "max_concurrent_tasks"]\n\n[[elements]]\nname = "retry_attempts"\ntype = "number"\nprompt = "Retry Attempts"\ndefault = 3\nmin = 0\nmax = 10\nhelp = "Number of retry attempts for failed tasks"\nnickel_path = ["orchestrator", "queue", "retry_attempts"]\n\n[[elements]]\nname = "retry_delay"\ntype = "number"\nprompt = "Retry Delay (ms)"\ndefault = 5000\nmin = 1000\nmax = 60000\nhelp = "Delay between retries in milliseconds"\nnickel_path = ["orchestrator", "queue", "retry_delay"]\n\n[[elements]]\nname = "task_timeout"\ntype = "number"\nprompt = "Task Timeout (ms)"\ndefault = 3600000\nmin = 60000\nmax = 86400000\nhelp = "Default timeout for task execution (min 1 min, max 24 hrs)"\nnickel_path = ["orchestrator", "queue", "task_timeout"]\n```\n\n## Jinja2 Template Integration\n\nJinja2 templates (`templates/{service}-config.ncl.j2`) convert form values to Nickel:\n\n```\n# templates/orchestrator-config.ncl.j2\n{\n  orchestrator = {\n    workspace = {\n      {%- if workspace_name %}\n      name = "{{ workspace_name }}",\n      {%- endif %}\n      {%- if workspace_path %}\n      path = "{{ workspace_path }}",\n      {%- endif %}\n      {%- if workspace_enabled is defined %}\n      enabled = {{ workspace_enabled | lower }},\n      {%- endif %}\n    },\n    queue = {\n      {%- if max_concurrent_tasks %}\n      max_concurrent_tasks = {{ max_concurrent_tasks }},\n      {%- endif %}\n      {%- if retry_attempts %}\n      retry_attempts = {{ retry_attempts }},\n      {%- endif %}\n      {%- if retry_delay %}\n      retry_delay = {{ retry_delay }},\n      {%- endif %}\n      {%- if task_timeout %}\n      task_timeout = {{ task_timeout }},\n      {%- endif %}\n    },\n  },\n}\n```\n\n## Conditional Sections\n\nForms can show/hide sections based on user selections:\n\n```\n# Always shown\n[[items]]\nname = "deployment_mode_group"\ntype = "group"\nincludes = ["fragments/deployment-mode-section.toml"]\n\n# Only shown if enable_monitoring is true\n[[items]]\nname = "monitoring_group"\ntype = "group"\nwhen = "enable_monitoring == true"\nincludes = ["fragments/monitoring-section.toml"]\n\n# Only shown if deployment_mode is "enterprise"\n[[items]]\nname = "enterprise_options"\ntype = "group"\nwhen = "deployment_mode == 'enterprise'"\nincludes = ["fragments/enterprise-options-section.toml"]\n```\n\n## Element Types\n\n```\ntype = "text"           # Single-line text input\ntype = "number"         # Numeric input\ntype = "confirm"        # Boolean checkbox\ntype = "select"         # Dropdown (single choice)\ntype = "multiselect"    # Checkboxes (multiple choices)\ntype = "password"       # Hidden text input\ntype = "textarea"       # Multi-line text\ntype = "section_header" # Visual section separator\ntype = "footer"         # Confirmation text\ntype = "group"          # Container for fragments\n```\n\n## Usage Workflow\n\n### 1. Run Configuration Wizard\n\n```\nnu provisioning/.typedialog/provisioning/platform/scripts/configure.nu orchestrator solo\n```\n\n### 2. TypeDialog Loads Form\n\n- Shows `forms/orchestrator-form.toml`\n- Includes fragments from `forms/fragments/*.toml`\n- Applies constraint interpolation\n- Loads existing config as defaults (if exists)\n\n### 3. User Edits\n\n- Fills form fields\n- Validates against constraints\n- Shows validation errors\n\n### 4. Generate Nickel\n\n- Uses `templates/orchestrator-config.ncl.j2`\n- Converts form values to Nickel\n- Saves to `values/orchestrator.solo.ncl`\n\n## Best Practices\n\n1. **Use fragments** - Don't duplicate form sections\n2. **Always add nickel_path** - Required for Nickel mapping\n3. **Use constraint interpolation** - Dynamic limits from constraints.toml\n4. **Provide defaults** - Sensible defaults speed up configuration\n5. **Use clear prompts** - Explain what each field does in `help` text\n6. **Group related fields** - Use fragments to organize logically\n7. **Test constraint interpolation** - Verify ${constraint.*} resolves\n8. **Document fragments** - Use headers and help text\n\n## Testing Forms\n\n```\n# Validate form TOML syntax (if supported by TypeDialog)\n# typedialog validate forms/orchestrator-form.toml\n\n# Launch interactive form (web backend)\nnu provisioning/.typedialog/provisioning/platform/scripts/configure.nu orchestrator solo --backend web\n\n# View generated Nickel\ncat provisioning/.typedialog/provisioning/platform/values/orchestrator.solo.ncl\n```\n\n## Adding New Fields\n\nTo add a new configuration field:\n\n1. **Add to schema** (schemas/{service}.ncl)\n2. **Add to defaults** (defaults/{service}-defaults.ncl)\n3. **Add to fragment** (forms/fragments/{appropriate}-section.toml)\n   - Include `nickel_path` mapping\n   - Add constraint if numeric\n4. **Update Jinja2 template** (templates/{service}-config.ncl.j2)\n5. **Test**: `nu scripts/configure.nu {service} {mode}`\n\n---\n\n**Version**: 1.0.0\n**Last Updated**: 2025-01-05
