Skip to content

Studio: field-type-aware operator + value editing for view filter rules (Edit View Config) #2764

Description

@os-zhuang

Background

In the metadata admin (Studio) Edit View Config form, view filter rules ({ field, operator, value } rows rendered by SchemaForm) are edited as raw inputs today:

  • operator is a free-text string — no dropdown, no validation, no human-readable labels;
  • value is a plain text input regardless of the selected field's type (boolean, number, date, select, …);
  • unary operators (is_empty, is_null, …) still show a value input even though no value applies.

This is a real UX gap. PR #2760 (paired with objectstack-ai/objectstack#3363) attempted it but was rejected — see "Prior art" below. This issue tracks the redevelopment.

Depends on: objectstack-ai/objectstack#3368 (canonical operator vocabulary in ViewFilterRuleSchema — the operator dropdown needs the spec enum, and the vocabulary the UI writes must be settled there first).

Requirements

  1. Operator select — dropdown with human-readable labels, narrowed to the operators valid for the selected field's type (text / number / boolean / date / select-like / lookup). Must stay consistent with the runtime FilterBuilder's per-type operator sets.
  2. Type-aware value input — boolean → switch, number/currency/percent → number input, date/datetime → date(-time) picker, select/lookup → option picker where the field catalog provides options, default → text.
  3. Operator-aware value inputbetween → from/to range (this must also apply to date fields — operator check has to take precedence over the field-type branch); in/not_in → multi-value input; unary operators → no value input (placeholder).
  4. Correct value typing in stored metadata — booleans stored as real booleans (not "true"/"false" strings), numbers as numbers, in/not_in as arrays (not comma-joined strings), between as a [from, to] pair. The stored format stays spec ViewFilterRule[].
  5. Single source of truth for operator logic — reuse or extract the existing FilterBuilder per-type operator lists / the filter-builder widget (packages/app-shell/src/views/metadata-admin/widgets.tsx) rather than a parallel implementation. Studio must not have two editors writing different operator vocabularies for the same stored field. Evaluate whether the filter rows should simply use the existing filter-builder widget for unified UX.
  6. i18n — all labels (operator names, "from"/"to", placeholders) go through the existing t(...) locale mechanism; no hardcoded English.
  7. Scoped widget detection — target filter-rule rows precisely (e.g. via schema context or explicit widget assignment), not broad name conventions like /Operator$/ / /Value$/ that can hijack unrelated fields (defaultValue, etc.).
  8. Source object detection — keep the ResourceEditPage improvement of reading draft.data.object as a source-object fallback so filter rows get the object field catalog.

Acceptance criteria

  • Edit View Config filter row: operator renders as a labeled dropdown filtered by the selected field's type.
  • Value input adapts to field type and operator per the matrix above, including date + between showing a range.
  • Stored values round-trip with correct JS types and validate against ViewFilterRuleSchema.
  • Operator vocabulary written by this editor matches what the existing filter-builder widget writes (post framework#3368 canonicalization).
  • All user-facing strings localized.
  • No widget detection regressions on unrelated *Value / *Operator fields in other metadata forms.

Prior art

PR #2760 — rejected for: parallel operator/value implementation duplicating FilterBuilder; operator vocabulary conflicting with what FilterBuilderWidget writes (gt/gte/lt/lte); between unreachable for date fields (branch-order bug); booleans stored as strings and in values as comma-joined strings; literal rendered in JSX; hardcoded English labels; over-broad name-convention widget detection; undeclared hard dependency on the framework spec PR.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions