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
- 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.
- 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.
- Operator-aware value input —
between → 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).
- 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[].
- 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.
- i18n — all labels (operator names, "from"/"to", placeholders) go through the existing
t(...) locale mechanism; no hardcoded English.
- 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.).
- 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
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.
Background
In the metadata admin (Studio) Edit View Config form, view
filterrules ({ field, operator, value }rows rendered bySchemaForm) are edited as raw inputs today:operatoris a free-text string — no dropdown, no validation, no human-readable labels;valueis a plain text input regardless of the selected field's type (boolean, number, date, select, …);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
FilterBuilder's per-type operator sets.between→ 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)."true"/"false"strings), numbers as numbers,in/not_inas arrays (not comma-joined strings),betweenas a[from, to]pair. The stored format stays specViewFilterRule[].FilterBuilderper-type operator lists / thefilter-builderwidget (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 existingfilter-builderwidget for unified UX.t(...)locale mechanism; no hardcoded English./Operator$///Value$/that can hijack unrelated fields (defaultValue, etc.).ResourceEditPageimprovement of readingdraft.data.objectas a source-object fallback so filter rows get the object field catalog.Acceptance criteria
betweenshowing a range.ViewFilterRuleSchema.filter-builderwidget writes (post framework#3368 canonicalization).*Value/*Operatorfields in other metadata forms.Prior art
PR #2760 — rejected for: parallel operator/value implementation duplicating
FilterBuilder; operator vocabulary conflicting with whatFilterBuilderWidgetwrites (gt/gte/lt/lte);betweenunreachable for date fields (branch-order bug); booleans stored as strings andinvalues 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.