Skip to content

feat(ui): Schema-driven dynamic forms for source/reaction configuration#88

Open
danielgerlag wants to merge 4 commits intomainfrom
ui-fields
Open

feat(ui): Schema-driven dynamic forms for source/reaction configuration#88
danielgerlag wants to merge 4 commits intomainfrom
ui-fields

Conversation

@danielgerlag
Copy link
Copy Markdown
Contributor

@danielgerlag danielgerlag commented Apr 29, 2026

Summary

Replaces the flat YAML editor in the Drasi UI with schema-driven dynamic forms using RJSF (React JSON Schema Form). Forms are auto-generated from each plugin's JSON Schema with support for x-ui:* extension hints.

Key Changes

New files

  • rjsf-theme/widgets.tsx — 7 custom RJSF widgets (Text, Password, Textarea, Select, Checkbox, Range, Number) matching Drasi's Tailwind design
  • rjsf-theme/templates.tsx — FieldTemplate (x-ui:condition + humanizeLabel), ObjectFieldTemplate (collapsible x-ui:group sections), ArrayFieldTemplate, ErrorListTemplate
  • rjsf-theme/index.ts — Theme export
  • uiSchemaMapper.ts — Extracts x-ui:* extensions from JSON Schema → RJSF uiSchema + field groups

Modified files

  • ConfigEditor.tsx — Complete rewrite with Form/YAML toggle and bidirectional sync
  • SchemaConfigForm.tsx — Uses Drasi theme, uiSchema, formContext
  • SourceForms.tsx / ReactionForms.tsx — Deletion-aware onChange handlers
  • schemaResolver.ts — Preserve x-ui:* annotations during $ref resolution; build ref lookup to resolve utoipa short names (e.g. CallSpecDto) to fully-qualified definition keys (e.g. reaction.http.CallSpec)

Features

  • Form/YAML toggle — Switch between structured form and raw YAML editing
  • Grouped fields — Plugin-defined groups rendered as collapsible sections
  • Widget hints — Password fields, textareas, placeholders from x-ui annotations
  • humanizeLabel — camelCase field names → "Title Case" labels
  • Ref resolution — Handles utoipa Dto-suffixed short names and fully-qualified module paths

Companion PR

Requires drasi-project/drasi-core#421 for the plugin-side x-ui schema annotations.

image image image image

danielgerlag and others added 3 commits April 29, 2026 02:02
Replace flat YAML editor with schema-driven forms using RJSF (React JSON
Schema Form) that render typed fields from each plugin's JSON Schema.

Key changes:
- Custom RJSF theme (widgets.tsx, templates.tsx) matching Drasi Tailwind design
- x-ui:* extension parser (uiSchemaMapper.ts) for UI hints from plugin schemas
- ConfigEditor with Form/YAML toggle and bidirectional sync
- SchemaConfigForm upgraded with uiSchema, formContext, custom theme
- schemaResolver.ts: preserve x-ui:* annotations during $ref resolution,
  build ref lookup to resolve utoipa short names (e.g. CallSpecDto) to
  fully-qualified definition keys (e.g. reaction.http.CallSpec)
- SourceForms/ReactionForms: deletion-aware onChange handlers
- humanizeLabel for camelCase→Title Case field labels

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
utoipa  names (e.g. TemplateSpecDto, QueryConfigDto) don't always
match definition key suffixes (e.g. LogTemplateSpec, LogQueryConfig).
Add suffixMatchRef() that strips 'Dto' and finds definitions whose
short name ends with the base name, resolving the mismatch.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
… queries

When creating a reaction, the 'routes' map (per-query config) is now
automatically expanded into named sections for each selected query.
Instead of a generic key/value map editor, users see a dedicated config
form section for each query they've selected in the checkbox list.

Works by detecting map-type properties (type: object + additionalProperties)
and rewriting them to fixed properties keyed by selected query IDs.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR replaces the flat YAML configuration editor in the UI with schema-driven dynamic forms powered by RJSF, using plugin-provided JSON Schemas (including x-ui:* extension hints) while retaining a YAML fallback editor.

Changes:

  • Added an x-ui:* → RJSF uiSchema mapper (including grouping/order/conditions).
  • Introduced a Drasi-tailored RJSF theme (custom widgets + templates for grouping/collapsing and inline errors).
  • Reworked config editing to support Form/YAML toggle, improved $ref rewriting, and deletion-aware config updates in source/reaction forms.

Reviewed changes

Copilot reviewed 9 out of 9 changed files in this pull request and generated 10 comments.

Show a summary per file
File Description
ui/src/utils/uiSchemaMapper.ts New utility to extract x-ui:* annotations into an RJSF uiSchema (order/groups/conditions).
ui/src/utils/schemaResolver.ts Enhances $ref rewriting (short-name lookup, preserves siblings for known refs/ConfigValue).
ui/src/components/create/rjsf-theme/widgets.tsx Adds Tailwind-styled RJSF widgets (text/password/textarea/select/checkbox/range/number).
ui/src/components/create/rjsf-theme/templates.tsx Adds templates for conditional visibility, grouped/collapsible object sections, arrays, and hides default error list.
ui/src/components/create/rjsf-theme/index.ts Exports the Drasi RJSF theme (widgets + templates).
ui/src/components/create/SchemaConfigForm.tsx Wires the Drasi theme into RJSF and passes formContext for conditions.
ui/src/components/create/ConfigEditor.tsx Main rewrite: Form/YAML toggle, schema rewriting for query-keyed maps, YAML/template syncing, uiSchema extraction.
ui/src/components/create/SourceForms.tsx Makes config updates deletion-aware (“atomic replacement”).
ui/src/components/create/ReactionForms.tsx Same deletion-aware behavior + passes selected queries for per-query config expansion.
Comments suppressed due to low confidence (1)

ui/src/components/create/ReactionForms.tsx:104

  • This handler filters reserved keys (id, autoStart, kind, queries) when clearing old config, but when applying new keys it doesn’t exclude kind. If a user adds kind manually in YAML mode, it will be written into the parent state. Consider applying the same reserved-key filter in the second loop too.
          for (const [key, val] of Object.entries(data)) {
            if (key !== "id" && key !== "autoStart" && key !== "queries") {
              onChange(key, val);
            }
          }

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread ui/src/components/create/rjsf-theme/widgets.tsx Outdated
Comment thread ui/src/components/create/rjsf-theme/widgets.tsx Outdated
Comment thread ui/src/components/create/SourceForms.tsx
Comment thread ui/src/utils/schemaResolver.ts
Comment thread ui/src/components/create/SchemaConfigForm.tsx Outdated
Comment thread ui/src/components/create/ConfigEditor.tsx Outdated
Comment thread ui/src/components/create/ConfigEditor.tsx
Comment thread ui/src/components/create/ConfigEditor.tsx Outdated
Comment thread ui/src/components/create/ConfigEditor.tsx
Comment thread ui/src/components/create/rjsf-theme/widgets.tsx
- CheckboxWidget: add aria-labelledby for screen reader accessibility,
  unify disabled/readonly visual styling
- All widgets: use e.target.value in onBlur/onFocus for current value
- SourceForms: filter 'kind' from applied config keys to prevent
  reserved field leakage from YAML mode
- schemaResolver: preserve sibling x-ui:* keys in unknown ref fallback
- SchemaConfigForm: place submitButtonOptions after uiSchema spread
  so it cannot be overridden
- ConfigEditor: extract uiSchema from effectiveSchema (not raw resolved)
  to keep UI hints in sync with query-expanded schema; reset state when
  kind/category changes; propagate empty {} from YAML to parent state
  to allow clearing all config

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Comment thread ui/src/components/create/rjsf-theme/widgets.tsx
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants