7.7 KiB
Dynamic Parameter Forms
Overview
The web UI now supports dynamic form generation for rule creation based on parameter schemas defined in triggers and actions. This replaces the previous raw JSON textarea inputs with type-aware form fields.
Features
- Type-aware inputs: Automatically renders appropriate form controls based on parameter type
- Validation: Real-time validation with error messages for required fields and type constraints
- Default values: Auto-populates form fields with default values from schema
- Enum support: Renders dropdown selects for enum-type parameters
- Complex types: JSON editing support for arrays and objects with live parsing
Component Architecture
ParamSchemaForm Component
Location: web/src/components/common/ParamSchemaForm.tsx
A reusable React component that dynamically generates form inputs based on a parameter schema.
Props:
schema: Parameter schema object (flat key-value structure)values: Current parameter valuesonChange: Callback when values changeerrors: Validation errors to displaydisabled: Whether form is disabledclassName: Additional CSS classes
Supported Types:
string- Text input (or select dropdown ifenumis provided)number- Numeric input with decimal supportinteger- Numeric input (whole numbers only)boolean- Checkbox with labelarray- JSON textarea with syntax validationobject- JSON textarea with syntax validation
Parameter Schema Format
The component expects a flat schema structure:
{
[parameterName]: {
type?: "string" | "number" | "integer" | "boolean" | "array" | "object";
description?: string;
required?: boolean;
default?: any;
enum?: string[];
}
}
Example:
{
"expression": {
"type": "string",
"description": "Cron expression in standard format",
"required": true
},
"timezone": {
"type": "string",
"description": "Timezone for cron schedule",
"default": "UTC"
},
"interval": {
"type": "integer",
"description": "Number of time units between each trigger",
"default": 60,
"required": true
},
"unit": {
"type": "string",
"enum": ["seconds", "minutes", "hours"],
"description": "Time unit for the interval",
"default": "seconds",
"required": true
}
}
Usage in Rule Creation
When creating a rule through the web UI:
- Select Pack: Choose which pack to use
- Select Trigger: Dropdown shows available triggers from the pack
- Configure Trigger Params: Dynamic form appears based on trigger's
param_schema - Select Action: Dropdown shows available actions from the pack
- Configure Action Params: Dynamic form appears based on action's
param_schema - Set Conditions: JSON-based conditional logic (optional)
- Submit: Form validates all required fields before submission
Data Flow
1. User selects trigger (from summary list)
↓
2. System fetches full trigger details (GET /api/v1/triggers/{ref})
↓
3. Extract param_schema from TriggerResponse
↓
4. ParamSchemaForm renders inputs based on schema
↓
5. User fills in parameters
↓
6. Validation runs on submission
↓
7. Parameters sent as trigger_params in CreateRuleRequest
Same flow applies for action parameters.
API Design Pattern
The implementation follows the "summary for lists, details on demand" pattern:
- List endpoints (
/api/v1/packs/{pack_ref}/triggers): ReturnTriggerSummarywithoutparam_schema - Detail endpoints (
/api/v1/triggers/{ref}): ReturnTriggerResponsewith fullparam_schema
This keeps list responses lightweight while providing full schema information when needed.
Pack Definition Format
Trigger YAML Structure
name: intervaltimer
ref: core.intervaltimer
description: "Fires at regular intervals"
enabled: true
type: interval
# Parameter schema - flat structure
parameters:
unit:
type: string
enum:
- seconds
- minutes
- hours
description: "Time unit for the interval"
default: "seconds"
required: true
interval:
type: integer
description: "Number of time units between each trigger"
default: 60
required: true
# Output schema (payload emitted when trigger fires)
output:
type: object
properties:
type:
type: string
interval_seconds:
type: integer
fired_at:
type: string
format: date-time
Action YAML Structure
Actions use the same flat parameter schema format:
name: echo
ref: core.echo
description: "Echoes a message"
runtime: shell
# Parameter schema - flat structure
parameters:
message:
type: string
description: "Message to echo"
required: true
uppercase:
type: boolean
description: "Convert message to uppercase"
default: false
Pack Loader Mapping
The Python pack loader (scripts/load_core_pack.py) maps YAML keys to database columns:
| YAML Key | Database Column |
|---|---|
parameters |
param_schema |
output |
out_schema |
The loader serializes the YAML structure as JSON and stores it in the param_schema JSONB column.
Validation
The validateParamSchema utility function validates parameter values against the schema:
import { validateParamSchema } from '@/components/common/ParamSchemaForm';
const errors = validateParamSchema(schema, values);
// Returns: { [fieldName]: "error message" }
Validation Rules:
- Required fields must have non-empty values
- Numbers must be valid numeric values
- Arrays must be valid JSON arrays
- Objects must be valid JSON objects
Future Enhancements
Potential improvements for the parameter form system:
- Advanced validation: Support for min/max, pattern matching, custom validators
- Conditional fields: Show/hide fields based on other field values
- Field hints: Helper text, examples, tooltips
- Template variables: Autocomplete for Jinja2 template syntax (e.g.,
{{ trigger.payload.* }}) - Schema versioning: Handle schema changes across pack versions
- Array item editing: Better UX for editing array items individually
- Nested objects: Support for deeply nested object schemas
- File uploads: Support for file-type parameters
- Date pickers: Native date/time inputs for datetime parameters
Troubleshooting
Parameters not showing in UI
Check:
- Is the trigger/action selected?
- Does the database record have
param_schemapopulated?SELECT ref, param_schema FROM trigger WHERE ref = 'core.intervaltimer'; - Is the API returning the full record (not summary)?
- Check browser console for JavaScript errors
Schema not loading from pack YAML
Check:
- YAML uses
parameterskey (notparameters_schema) - Schema is in flat format (not nested JSON Schema with
properties) - Pack was reloaded after YAML changes:
./scripts/load-core-pack.sh - Database has correct schema:
SELECT param_schema FROM trigger WHERE ref = 'pack.trigger';
Validation errors
Check:
- Required fields are marked with
required: truein schema - Type matches expected format (e.g., integer vs string)
- Enum values match exactly (case-sensitive)
Related Files
web/src/components/common/ParamSchemaForm.tsx- Core form componentweb/src/components/forms/RuleForm.tsx- Rule creation form using ParamSchemaFormweb/src/pages/actions/ActionsPage.tsx- Execute action modal using ParamSchemaFormscripts/load_core_pack.py- Pack loader that converts YAML to database schemapacks/core/triggers/*.yaml- Example trigger definitionspacks/core/actions/*.yaml- Example action definitions