Skip to main content

UI Schemas

Overview

  • UI Schema provides an “overlay” configuration for front-end presentation and form behavior of resource fields.
  • It supports multi-layer overlays: DEFAULT → TENANT → ROLE → USER, where the latter has higher priority and layers are merged in order.
  • Typical scenarios: customizing component type, default value, validation, and list/form visibility for fields under a given tenant, role, or user.

Structural conventions (overlay schemaJson)

  • Top-level object contains fields: a map keyed by field name.
  • Each field corresponds to a FieldConfig, which contains UI attributes prefixed with x-.

Example:

{
"fields": {
"status": {
"x-component": "Select",
"x-options": ["Open", "Closed", "Pending"],
"x-default-value": "Open",
"x-label": "Status",
"x-visible": true,
"x-required": true
}
}
}

Notes:

  • The merge strategy is deep-merge on fields.<fieldName> by key.
  • x-options supports two forms:
    • Simple array: string[] as above (for quick choices)
    • Object: { choices: Array<Choice>, defaultValue?: any, ... } (commonly used for Select in some modules)

Field-level UI attributes (FieldConfig)

The following x- attributes are commonly used across modules:

  • x-component: component type

    • Values (case-insensitive, shown here with capitalized examples): Text, Textarea, Number, Boolean, Select, Date, DateTime, Email, Url
    • If omitted, the frontend may infer a default component based on the field’s data type.
  • x-label: custom display label (string)

  • x-default-value: default value (string | number | boolean | null)

    • Can be used as an alternative to x-options.defaultValue; if both exist, the value from the higher-priority overlay wins.
  • x-visible: whether the field is visible (boolean)

  • x-required: whether the field is required (boolean)

    • It may also be derived from the model’s isNullable === false.
  • x-tooltip: tooltip text (string)

  • x-placeholder: placeholder text (string)

  • x-options: component options (two forms)

    • Simple array: string[] (quick choices)
    • Object: Record<string, any>, common fields:
      • choices: Array<{ id: string; name: string } | string>
      • defaultValue: default value at component level
      • multiple: boolean (multi-select)
      • other component-specific props (e.g. min/max/step for Number; date format for Date/DateTime, etc.)
  • x-order: ordering weight (number)

    • Controls field order in lists/forms.
  • x-form-hidden: hide the field in forms (boolean)

  • x-list-hidden: hide the field in list/table views (boolean)

  • x-minLength: minimum length (number, for Text/Textarea/Email/Url)
  • x-maxLength: maximum length (number, for Text/Textarea/Email/Url)
  • x-min: minimum value (number, for Number)
  • x-max: maximum value (number, for Number)
  • x-email: email format validation (boolean, for Email)
  • x-filter-choices: filter options for list views (Array<{ id: string; name: string } | string>), used for building filter UI.

Merging and priority

  • Overlay resolution order: DEFAULT → TENANT → ROLE → USER.
  • Merge strategy: map deep-merge, arrays/scalars overwrite (later layer wins).
  • Role level supports merging in the order of roles from the request to honor expected priority.

Overlay API

  • Base path: /metadata/ui-schema-overlays (gateway routes to backend controller /api/v1/ui-schema-overlays)
  • Supports pagination and filtering: scopeType, tenantId, scopeKey, resourceName, page, pageSize
  • CRUD: GET /, GET /{id}, POST /, PUT /{id}, DELETE /{id}
  • JSON validation: GET /validate?json=<schemaJson>

Overlay object (UiSchemaOverlay)

Common fields:

  • scopeType: DEFAULT | TENANT | ROLE | USER (defaults to DEFAULT)
  • scopeKey: scope key (ROLE uses role name, USER uses user ID)
  • resourceId: entity ID (optional; you can also use resourceName)
  • resourceName: entity name (optional; you can also use resourceId)
  • schemaJson: overlay JSON as a string; when empty, the server can generate a default UI Schema from entity fields
  • tenantId: tenant ID (written by server based on request headers)

List overlays

  • GET /ui-schema-overlays
  • Permissions: admin
  • Headers: Authorization, X-Tenant-Id
  • Query params:
    • scopeType, scopeKey, resourceName (optional)
    • page (starting from 1, default 1), pageSize (default 20)

Create overlay (with optional auto-generated schemaJson)

  • POST /ui-schema-overlays
  • Permissions: admin
  • Headers: Authorization, X-Tenant-Id

Rules:

  • At least one of resourceId or resourceName must be provided (for locating the entity and generating default UI Schema).
  • When schemaJson is empty or blank, the server generates default schemaJson from entity fields.
  • When schemaJson is non-empty, it must be valid JSON or INVALID_JSON is returned.

Example:

curl -X POST \
"${API_BASE}/metadata/ui-schema-overlays" \
-H "Authorization: Bearer <token>" \
-H "X-Tenant-Id: tenant-abc123" \
-H "Content-Type: application/json" \
-d '{
"scopeType": "TENANT",
"resourceName": "customers",
"schemaJson": "{ \"fields\": { \"email\": { \"x-component\": \"Email\", \"x-required\": true } } }"
}'

Update / delete / validate JSON

  • PUT /ui-schema-overlays/{id}: update overlay (requires valid JSON in schemaJson)
  • DELETE /ui-schema-overlays/{id}: delete overlay
  • GET /ui-schema-overlays/validate?json=<schemaJson>: verify schemaJson is valid JSON (200 if valid, 400 otherwise)

Examples

1. Select component (object-form x-options)

{
"fields": {
"category": {
"x-component": "Select",
"x-label": "Category",
"x-required": true,
"x-options": {
"choices": [
{ "id": "electronics", "name": "Electronics" },
{ "id": "books", "name": "Books" }
],
"multiple": false,
"defaultValue": "electronics"
}
}
}
}

2. Number component (range and placeholder)

{
"fields": {
"age": {
"x-component": "Number",
"x-label": "Age",
"x-required": true,
"x-min": 0,
"x-max": 120,
"x-placeholder": "Please enter age"
}
}
}

3. Simple array-form x-options (quick choices)

{
"fields": {
"status": {
"x-component": "Select",
"x-options": ["Open", "Closed", "Pending"],
"x-default-value": "Open"
}
}
}

Compatibility and recommendations

  • Both forms of x-options are supported; for richer props, use the object form.
  • To improve query performance, consider adding indexes on combinations like (tenantId, scopeType, resourceName) on the backend.
  • Frontend editors can dynamically show appropriate attributes per component type (such as range and step for Number, date format for Date/DateTime, etc.).

Unified UiSchema DSL (list / form / detail, etc.)

Besides the overlay schemaJson, the frontend also defines a unified UiSchema DSL for describing list pages, form pages, detail pages, related sub-tables, action buttons, and more. Core type definitions are in /ui/web/src/ui-schema-new/types.ts.

Top-level structure (UiSchema):

  • version: version string (for example "1.0")
  • id: optional, ID of the schema itself
  • resource: resource name (for example "orders")
  • i18n: i18n dictionary
  • security: security configuration
    • roles: allowed roles
    • permissions: permission key/value pairs
  • defaults: global defaults
    • perPage: default page size
    • rowClick: list row click behavior (edit | show | expand | none)
  • list: list configuration (ListConfig)
  • form: form configuration (FormConfig, including create / edit)
  • show: detail page configuration (ShowConfig)
  • actions: action definitions (ActionDef[])
  • views: predefined views (ViewDef[])
  • metrics: embedded metric configurations (MetricDef[])

List configuration (ListConfig):

  • title: list title
  • columns: column definitions (ColumnDef[])
    • source: field name
  • label: column title
  • type: column type (text/number/date, etc. as defined in frontend)
  • sortable: whether sortable
  • width: column width
  • format: format string (for dates/numbers, etc.)
  • component: cell component name
  • props: props passed to the component
  • defaultSort: default sort { field, order }
  • filters: filter definitions (FilterDef[])
    • component: filter component (TextInput/NumberInput/BooleanInput/SelectInput/DatetimeInput/SearchInput/ReferenceInput)
    • choices: local enum values (string/array/object)
    • props: component props
  • filterDefaultValues: default filter values
  • toolbar: toolbar actions { actions: ActionRef[] }
  • rowActions: per-row action list
  • selection: selection configuration { enabled: boolean }
  • data: data source configuration (DataSourceDef)
  • perPage: page size (fallback to defaults.perPage if missing)
  • rowClick: row click behavior (fallback to defaults.rowClick if missing)

Form configuration (FormConfig):

  • create / edit: page configs (FormPage)
  • FormPage:
    • title: page title
    • layout: sections (SectionDef[])
    • submit: submit behavior (SubmitDef)
  • SectionDef:
    • id: section ID
    • title: section title
    • cols: total columns (12-grid)
    • fields: list of form fields (FormFieldDef[])
  • FormFieldDef:
    • source: field name
    • label: label
    • component: input component name
    • props: component props
    • visibleIf: visibility expression
    • disabledIf: disabled expression
    • validate: validation rules
    • optionsSource: options source (remote or local choices)

Detail page configuration (ShowConfig):

  • title: detail title
  • layout: section layout (ShowSectionDef[])
  • toolbar: toolbar actions
  • related: related sub-table configs (RelatedDef[])

Related sub-table (RelatedDef):

  • id: sub-table ID
  • title: title
  • resource: related resource name
  • target: relation field (such as foreign key)
  • filter: filter (JSON or template string)
  • sort: sort config
  • perPage: page size
  • columns: column definitions
  • data: data source configuration

Action definition (ActionDef):

  • id: action ID (for reference)
  • label: button label
  • icon: icon name
  • kind: action type (link/dialog/mutation/download/custom)
  • if: condition expression
  • confirm: confirmation message
  • payload: payload template (string or object)
  • request: request definition (RequestDef)
  • onSuccess / onError: action references after success/failure (ActionRef[])
  • feedback: user feedback messages { success, error }
  • inputs: inputs to collect when triggering the action (ActionInputDef[])
  • client: optional client-side behavior configuration (such as updating via dataProvider)

Request definition (RequestDef):

  • url: request URL
  • method: HTTP method (default POST)
  • headers: request headers
  • paramsTemplate: query parameter template
  • bodyTemplate: body template

Data source definition (DataSourceDef):

  • query:
    • url: query URL
    • method: HTTP method
    • params: static query params
  • transform: optional transform expression or transformer name

Recommended approach:

  • Use UiSchema DSL to describe page layout, actions, and data sources.
  • Use UI Schema overlays for field-level overrides (component type, visibility, validations, etc.). These two mechanisms can be combined.