# Forms

TypeDialog form definitions for interactive configuration of platform services.

## Purpose

Forms provide:
- **Interactive configuration** - Web/TUI/CLI interfaces for user input
- **Constraint validation** - Dynamic min/max from constraints.toml
- **Nickel mapping** - Form fields map to Nickel structure via `nickel_path`
- **Jinja2 template integration** - Generate Nickel configs from form values
- **nickel-roundtrip workflow** - Load existing Nickel → edit → generate updated Nickel

## File Organization

```toml
forms/
├── README.md                           # This file
├── orchestrator-form.toml              # Orchestrator configuration form
├── control-center-form.toml            # Control Center configuration form
├── mcp-server-form.toml                # MCP Server configuration form
├── installer-form.toml                 # Installer configuration form
└── fragments/                          # FLAT fragment directory (all fragments here)
    ├── workspace-section.toml          # Workspace configuration
    ├── server-section.toml             # HTTP server settings
    ├── database-rocksdb-section.toml   # RocksDB configuration
    ├── database-surrealdb-section.toml # SurrealDB configuration
    ├── database-postgres-section.toml  # PostgreSQL configuration
    ├── security-section.toml           # Auth, RBAC, encryption
    ├── monitoring-section.toml         # Metrics, health checks
    ├── logging-section.toml            # Log configuration
    ├── orchestrator-queue-section.toml # Orchestrator queue config
    ├── orchestrator-workflow-section.toml
    ├── control-center-jwt-section.toml
    ├── control-center-rbac-section.toml
    ├── mcp-capabilities-section.toml
    ├── deployment-mode-section.toml    # Mode selection
    └── README.md                       # Fragment documentation
```

## Critical: Fragment Organization

**Fragments are FLAT** - all stored in `forms/fragments/` at the same level, referenced by paths in form includes:

```toml
# Main form (orchestrator-form.toml)
[[items]]
name = "workspace_group"
type = "group"
includes = ["fragments/workspace-section.toml"]  # Path reference to flat fragment

[[items]]
name = "queue_group"
type = "group"
includes = ["fragments/orchestrator-queue-section.toml"]  # Same level, different name
```

**NOT nested directories** like `fragments/orchestrator/queue-section.toml` - all in `fragments/`

## TypeDialog nickel-roundtrip Workflow

CRITICAL: Forms integrate with Nickel config generation via:

```nickel
typedialog-web nickel-roundtrip "$CONFIG_FILE" "$FORM_FILE" --output "$CONFIG_FILE" --template "$NCL_TEMPLATE"
```

This workflow:
1. **Loads existing Nickel config** as default values in form
2. **Shows form** with validated constraints
3. **User edits** configuration values
4. **Generates updated Nickel** using Jinja2 template

## Required Fields: nickel_path

**CRITICAL**: Every form element MUST have `nickel_path` to map to Nickel structure:

```toml
[[elements]]
name = "workspace_name"
type = "text"
prompt = "Workspace Name"
nickel_path = ["orchestrator", "workspace", "name"]  # ← REQUIRED
```

The `nickel_path` array specifies the path in the Nickel config structure:
- `["orchestrator", "workspace", "name"]` → `orchestrator.workspace.name`
- `["orchestrator", "queue", "max_concurrent_tasks"]` → `orchestrator.queue.max_concurrent_tasks`

## Constraint Interpolation

Form fields reference constraints dynamically:

```toml
[[elements]]
name = "max_concurrent_tasks"
type = "number"
prompt = "Maximum Concurrent Tasks"
min = "${constraint.orchestrator.queue.concurrent_tasks.min}"  # Dynamic
max = "${constraint.orchestrator.queue.concurrent_tasks.max}"  # Dynamic
help = "Range: ${constraint.orchestrator.queue.concurrent_tasks.min}-${constraint.orchestrator.queue.concurrent_tasks.max}"
nickel_path = ["orchestrator", "queue", "max_concurrent_tasks"]
```

TypeDialog resolves `${constraint.path}` from `constraints/constraints.toml`.

## Main Form Structure

All main forms follow this pattern:

```toml
name = "service_configuration"
description = "Interactive configuration for {Service}"
display_mode = "complete"

# Section 1: Deployment mode selection
[[items]]
name = "deployment_mode_group"
type = "group"
includes = ["fragments/deployment-mode-section.toml"]

# Section 2: Workspace configuration
[[items]]
name = "workspace_group"
type = "group"
includes = ["fragments/workspace-section.toml"]

# Section 3: Server configuration
[[items]]
name = "server_group"
type = "group"
includes = ["fragments/server-section.toml"]

# Section N: Service-specific configuration
[[items]]
name = "service_group"
type = "group"
includes = ["fragments/{service}-specific-section.toml"]

# Optional: Conditional sections
[[items]]
name = "monitoring_group"
type = "group"
when = "enable_monitoring == true"
includes = ["fragments/monitoring-section.toml"]
```

## Fragment Example: workspace-section.toml

```toml
# Workspace configuration fragment
[[elements]]
border_top = true
border_bottom = true
name = "workspace_header"
title = "🗂️ Workspace Configuration"
type = "section_header"

[[elements]]
name = "workspace_name"
type = "text"
prompt = "Workspace Name"
default = "default"
placeholder = "e.g., librecloud, production"
required = true
help = "Name of the workspace"
nickel_path = ["orchestrator", "workspace", "name"]

[[elements]]
name = "workspace_path"
type = "text"
prompt = "Workspace Path"
default = "/var/lib/provisioning/orchestrator"
required = true
help = "Absolute path to workspace directory"
nickel_path = ["orchestrator", "workspace", "path"]

[[elements]]
name = "workspace_enabled"
type = "confirm"
prompt = "Enable Workspace?"
default = true
nickel_path = ["orchestrator", "workspace", "enabled"]

[[elements]]
name = "multi_workspace"
type = "confirm"
prompt = "Multi-Workspace Mode?"
default = false
help = "Allow serving multiple workspaces"
nickel_path = ["orchestrator", "workspace", "multi_workspace"]
```

## Fragment Example: orchestrator-queue-section.toml

```toml
# Orchestrator queue configuration
[[elements]]
border_top = true
name = "queue_header"
title = "⚙️ Queue Configuration"
type = "section_header"

[[elements]]
name = "max_concurrent_tasks"
type = "number"
prompt = "Maximum Concurrent Tasks"
default = 5
min = "${constraint.orchestrator.queue.concurrent_tasks.min}"
max = "${constraint.orchestrator.queue.concurrent_tasks.max}"
required = true
help = "Max tasks running simultaneously. Range: ${constraint.orchestrator.queue.concurrent_tasks.min}-${constraint.orchestrator.queue.concurrent_tasks.max}"
nickel_path = ["orchestrator", "queue", "max_concurrent_tasks"]

[[elements]]
name = "retry_attempts"
type = "number"
prompt = "Retry Attempts"
default = 3
min = 0
max = 10
help = "Number of retry attempts for failed tasks"
nickel_path = ["orchestrator", "queue", "retry_attempts"]

[[elements]]
name = "retry_delay"
type = "number"
prompt = "Retry Delay (ms)"
default = 5000
min = 1000
max = 60000
help = "Delay between retries in milliseconds"
nickel_path = ["orchestrator", "queue", "retry_delay"]

[[elements]]
name = "task_timeout"
type = "number"
prompt = "Task Timeout (ms)"
default = 3600000
min = 60000
max = 86400000
help = "Default timeout for task execution (min 1 min, max 24 hrs)"
nickel_path = ["orchestrator", "queue", "task_timeout"]
```

## Jinja2 Template Integration

Jinja2 templates (`templates/{service}-config.ncl.j2`) convert form values to Nickel:

```nickel
# templates/orchestrator-config.ncl.j2
{
  orchestrator = {
    workspace = {
      {%- if workspace_name %}
      name = "{{ workspace_name }}",
      {%- endif %}
      {%- if workspace_path %}
      path = "{{ workspace_path }}",
      {%- endif %}
      {%- if workspace_enabled is defined %}
      enabled = {{ workspace_enabled | lower }},
      {%- endif %}
    },
    queue = {
      {%- if max_concurrent_tasks %}
      max_concurrent_tasks = {{ max_concurrent_tasks }},
      {%- endif %}
      {%- if retry_attempts %}
      retry_attempts = {{ retry_attempts }},
      {%- endif %}
      {%- if retry_delay %}
      retry_delay = {{ retry_delay }},
      {%- endif %}
      {%- if task_timeout %}
      task_timeout = {{ task_timeout }},
      {%- endif %}
    },
  },
}
```

## Conditional Sections

Forms can show/hide sections based on user selections:

```toml
# Always shown
[[items]]
name = "deployment_mode_group"
type = "group"
includes = ["fragments/deployment-mode-section.toml"]

# Only shown if enable_monitoring is true
[[items]]
name = "monitoring_group"
type = "group"
when = "enable_monitoring == true"
includes = ["fragments/monitoring-section.toml"]

# Only shown if deployment_mode is "enterprise"
[[items]]
name = "enterprise_options"
type = "group"
when = "deployment_mode == 'enterprise'"
includes = ["fragments/enterprise-options-section.toml"]
```

## Element Types

```toml
type = "text"           # Single-line text input
type = "number"         # Numeric input
type = "confirm"        # Boolean checkbox
type = "select"         # Dropdown (single choice)
type = "multiselect"    # Checkboxes (multiple choices)
type = "password"       # Hidden text input
type = "textarea"       # Multi-line text
type = "section_header" # Visual section separator
type = "footer"         # Confirmation text
type = "group"          # Container for fragments
```

## Usage Workflow

### 1. Run Configuration Wizard

```toml
nu provisioning/.typedialog/provisioning/platform/scripts/configure.nu orchestrator solo
```

### 2. TypeDialog Loads Form

- Shows `forms/orchestrator-form.toml`
- Includes fragments from `forms/fragments/*.toml`
- Applies constraint interpolation
- Loads existing config as defaults (if exists)

### 3. User Edits

- Fills form fields
- Validates against constraints
- Shows validation errors

### 4. Generate Nickel

- Uses `templates/orchestrator-config.ncl.j2`
- Converts form values to Nickel
- Saves to `values/orchestrator.solo.ncl`

## Best Practices

1. **Use fragments** - Don't duplicate form sections
2. **Always add nickel_path** - Required for Nickel mapping
3. **Use constraint interpolation** - Dynamic limits from constraints.toml
4. **Provide defaults** - Sensible defaults speed up configuration
5. **Use clear prompts** - Explain what each field does in `help` text
6. **Group related fields** - Use fragments to organize logically
7. **Test constraint interpolation** - Verify ${constraint.*} resolves
8. **Document fragments** - Use headers and help text

## Testing Forms

```toml
# Validate form TOML syntax (if supported by TypeDialog)
# typedialog validate forms/orchestrator-form.toml

# Launch interactive form (web backend)
nu provisioning/.typedialog/provisioning/platform/scripts/configure.nu orchestrator solo --backend web

# View generated Nickel
cat provisioning/.typedialog/provisioning/platform/values/orchestrator.solo.ncl
```

## Adding New Fields

To add a new configuration field:

1. **Add to schema** (schemas/{service}.ncl)
2. **Add to defaults** (defaults/{service}-defaults.ncl)
3. **Add to fragment** (forms/fragments/{appropriate}-section.toml)
   - Include `nickel_path` mapping
   - Add constraint if numeric
4. **Update Jinja2 template** (templates/{service}-config.ncl.j2)
5. **Test**: `nu scripts/configure.nu {service} {mode}`

---

**Version**: 1.0.0
**Last Updated**: 2025-01-05
