Skip to content

8. UI, Queries, and Forms

Blueprint UI is an interpreter. It uses declared field, relationship, facet, entity, module, and app semantics; it does not reverse-engineer meaning from column names.

Generic enterprise UX belongs to vyuh_studio_ui. CDX packages own controls and view mechanics. vyuh_blueprint_ui maps Blueprint metadata and protocol records into those Studio contracts; it does not introduce a parallel widget system.

The UI hint cascade

text
BlueprintUI defaults
  -> ModuleUI overrides
  -> EntityUI overrides
  -> FacetUI sections
  -> FieldUI intrinsic controls and behavior
  -> ListUI layouts and FormUI composition
  -> client registry bindings

Query limits already resolve property-by-property through entity → module → Blueprint → platform defaults:

dart
final blueprint = Blueprint(
  name: 'pharma',
  version: '1.0.0',
  ui: const BlueprintUI(
    query: QueryUI(maxSortLevels: 3, maxGroupLevels: 3),
  ),
  modules: [
    Module(
      // ...
      ui: const ModuleUI(
        routePrefix: '/ops',
        query: QueryUI(maxGroupLevels: 2),
      ),
    ),
  ],
);

Describe a field once

dart
static const categoryId = UuidField(
  'category_id',
  title: 'Area Category',
  indexed: true,
  db: FieldDb(
    queryPatterns: [QueryPattern.filter, QueryPattern.aggregate],
  ),
  reference: UIReferenceHint(
    targetEntity: 'ops.area_category',
    projection: 'picker',
  ),
  ui: FieldUI(
    input: UIFieldInput.createAndUpdate,
    widget: UIFieldControl.referencePicker,
    formSection: 'hierarchy',
    filterable: true,
    sortable: true,
    order: 40,
    optionSearch: UIOptionSearch.auto,
  ),
);

The same declaration drives:

  • a searchable reference picker in the editor;
  • a linked label in details;
  • a projected table column;
  • a typed filter operand;
  • reference identity on the wire.

Raw UUID entry is not an acceptable reference experience.

Input capability is not storage writability

dart
static const createdBy = ActorField(
  'created_by',
  ui: FieldUI(input: UIFieldInput.never),
);

static const code = CodeField.configured(
  ui: FieldUI(input: UIFieldInput.create),
);

UIFieldInput distinguishes never, create-only, update-only, and both. Runtime-managed fields remain excluded even when physically writable.

Derive form values declaratively

dart
static const name = NameField();

static const code = CodeField.configured(
  ui: FieldUI(
    derivation: UIFieldDerivation(
      sourceFields: [name],
      transforms: [
        UITrimTransform(),
        UIUpperCaseTransform(),
        UIReplacePatternTransform(
          pattern: r'[^A-Z0-9]+',
          replacement: '-',
        ),
        UIReplacePatternTransform(pattern: r'^-+|-+$'),
      ],
      override: UIFieldDerivationOverride.untilOverridden,
    ),
  ),
);

The code follows the name until a person edits it. The editor then preserves the manual value and may expose a relink action.

UIFieldTransformRef('ops.area.code') is the typed escape hatch for a host-registered transform. Keep validation-critical invariants on the server; client derivation is an authoring aid.

Derived and explicit form structures

The app grammar can derive sections from FieldUI.formSection and the owning facet:

dart
const editor = EditorUI(
  name: 'area-editor',
  title: 'Area',
  presentation: EditorPresentation.adaptive,
  operations: {EditorOperation.create, EditorOperation.update},
  form: FormUI.derived(),
);

Or declare a stable custom structure:

dart
const editor = EditorUI(
  name: 'area-editor',
  title: 'Area',
  kind: EditorUIKind.tabs,
  presentation: EditorPresentation.dock,
  parts: [
    EditorPartUI(
      name: 'main',
      title: 'Area',
      form: FormUI.sections(
        sections: [
          FormSectionUI(
            name: 'identity',
            title: 'Identity',
            fieldRefs: [
              ProjectedFieldRef('identity.code'),
              ProjectedFieldRef('identity.name'),
            ],
            columns: 2,
          ),
          FormSectionUI(
            name: 'hierarchy',
            title: 'Hierarchy',
            facetRefs: ['hierarchy'],
            columns: 2,
          ),
        ],
      ),
    ),
  ],
);

Explicit sections cannot make a runtime-managed field editable. Input policy still comes from the field.

Query operands follow field semantics

The field registry maps a projected field to its type, labels, relationship, and query capabilities. Therefore:

  • enum → compact labeled option picker;
  • boolean → semantic Yes/No or Active/Inactive control;
  • date/timestamp → date or date-time picker;
  • reference → entity picker;
  • arrays → multi-value operand;
  • numeric/range → typed numeric/range editor;
  • text → CDX text control;
  • operators with no operand → no value editor.

The client builds a Vyuh/CDX query AST. The server must validate the same field catalog and compile only declared queryable fields. A visible filter that the server cannot execute is a contract error.

Reference controls query the standard slim reference projection. That keeps picker reads to identity fields such as id, code, name, and description instead of loading detail-shaped records. Studio's EntityPicker owns the generic selection interaction; Blueprint UI supplies entity, projection, and query context.

Relationship tabs are explicit when EntityUI.relationshipMode: RelationshipUIMode.explicit is used. In that mode, only declared RelatedUI entries appear; storage edges do not become accidental product navigation.

Action placement references the action catalog

dart
ui: EntityUI(
  actionPlacements: [
    ActionPlacementUI(
      placement: ActionPlacementRef.recordHeader,
      actions: [
        ActionUIRef(
          'governance.activate',
          presentation: UIActionPresentation.icon,
          tooltip: 'Activate area',
        ),
      ],
    ),
  ],
)

The facet owns the action. Placements only decide where and how an effective action appears. Permission, policy, state, and context resolution may make the final action hidden, disabled with a reason, or enabled.

Checkpoint

Build an area editor with:

  • derived identity and hierarchy sections;
  • enum labels;
  • a category reference picker;
  • create-only code that follows name until overridden;
  • at most three sort and group levels;
  • header placement for activate.

Next: Actors, work, and policy.

References: UI Hints · Blueprint UI.

Blue is the Vyuh Blueprint documentation surface.