Skip to content

Releases: objectstack-ai/objectui

@object-ui/types@15.0.0

Choose a tag to compare

@github-actions github-actions released this 16 Jul 15:38
8918202
@object-ui/types@15.0.0

@object-ui/types@14.1.0

Choose a tag to compare

@github-actions github-actions released this 16 Jul 14:35
813b4d1

Minor Changes

  • 887062c: feat(dashboard): dashboard-level filters (date / region) driving multiple charts (framework#2501)

    A dashboard's dateRange + globalFilters declarations are now wired end to
    end: the filter values live as dashboard-level variables (the page variables
    primitive, so they're also readable as page.<name> in widget expressions),
    a filter bar renders above the widgets, and at render time the dashboard
    broadcasts the active values into every bound widget's inline query —
    AND-merged with the widget's own filter. Charts stay inline and
    self-contained; each widget maps a filter to its own field.

    • @object-ui/typesglobalFilters[].name (stable filter/variable key,
      defaults to field) and DashboardWidgetSchema.filterBindings
      (Record<string, string | false>: per-widget field override / false
      opt-out). Zod mirrors included. Pending paired @objectstack/spec
      alignment (framework#2501)
      — same precedent as dataset /
      categoryGranularity.
    • @object-ui/core — new pure dashboard-filters module
      (resolveDashboardFilterDefs, dashboardFilterVariableDefs,
      buildFilterCondition, buildWidgetScopedFilter); mergeFilters lifted
      from plugin-report (re-exported there unchanged). Date presets emit
      date-macro tokens ({30_days_ago} …) so widgets resolve them at query time
      like hand-authored filters.
    • @object-ui/plugin-dashboardDashboardFilterBar (date presets +
      custom range calendar, select with static options or optionsFrom,
      text/number inputs, reset); DashboardRenderer mounts a
      PageVariablesProvider when filters are declared and merges the
      widget-scoped condition into inline widgets' filter and dataset widgets'
      runtimeFilter. Dashboards without filters render exactly as before.

    Binding precedence: explicit filterBindings string/false → legacy
    targetWidgets allow-list → the filter's own field (dateRange defaults to
    created_at). Static-data widgets are not filtered.

  • d5b1bc0: remove(tenant): drop the zero-consumer @object-ui/tenant package and the types/tenant.ts mirror (#2564)

    @object-ui/tenant (TenantProvider / TenantGuard / TenantScopedQuery /
    createTenantResolver / useTenant / useTenantBranding) was an
    exported-but-dead aspirational surface: no workspace package depended on it
    and nothing imported it. Its TenantConfig.isolation strategy enum
    ('database' | 'schema' | 'row' | 'hybrid') was the UI mirror of the spec's
    tenancy.strategy, which framework#2763/framework#2962 removed under the same
    enforce-or-remove doctrine — the platform has exactly two tenancy modes, and
    neither is configured client-side.

    @object-ui/types no longer exports the tenant type family
    (TenantConfig, TenantIsolationStrategy, TenantStatus, TenantPlan,
    TenantBranding, TenantLimits, TenantContext,
    TenantResolutionStrategy, TenantProviderConfig,
    TenantScopedQueryConfig).

    Migration: real tenant scoping is server-enforced — createAuthenticatedFetch
    (@object-ui/auth) already injects the active organization as X-Tenant-ID
    on every API call, and the backend applies row-level isolation
    (tenancy.enabled + tenantField in @objectstack/spec). Per-tenant
    branding is a ThemeSchema concern. The skills guides and docs that
    advertised the dead package have been rewritten to say exactly that.

  • f0f10f5: feat(kanban): default lane field honours the ADR-0085 stageField role

    Kanban views without an explicit groupByField/groupField hard-coded their
    lane field to the literal 'status' (in both app-shell's ObjectView options
    and plugin-list's ListView fallback) — ignoring the object's declared
    lifecycle and even inventing a field the object doesn't have. The default now
    resolves through the shared stageField detector:

    1. explicit view config (unchanged, always wins);
    2. the object's stageField semantic role;
    3. stageField: falseno default lanes (the status-shaped field is
      declared non-linear; the board renders its empty state until the view
      picks a lane field explicitly);
    4. else the shared name/type heuristic (status / stage / state / phase by
      name, then status/stage by type) — never a nonexistent field.

    detectStatusField moved from @object-ui/plugin-detail to
    @object-ui/types (new export, with the StatusFieldSource input type) so
    plugin-list and app-shell share the exact semantics; plugin-detail re-exports
    it unchanged.

    Also fixes ListView's pre-existing rules-of-hooks error while touching the
    file: useListFieldLabel wrapped useObjectLabel() in try/catch (hook-order
    desync risk; the hook is provider-safe) — same fix as objectui#2595's
    useFieldLabel.

    Behavior change is limited to kanban views with no explicit lane field on
    objects that either declare stageField (now honoured), declare
    stageField: false (now suppressed), or have no status-shaped field at all
    (previously grouped by a nonexistent status into one "undefined" lane; now
    an honest empty state). Objects with a real status field — the common case —
    are unchanged.

Patch Changes

  • 2ded18c: Fix: a dashboard filter declaring its static options in the
    @objectstack/spec object form (options: [{ value, label }] — the shape
    the spec validates and what framework-authored dashboards ship) crashed the
    whole dashboard with "Objects are not valid as a React child". Caught driving
    the showcase Revenue Pulse dashboard in a real browser.

    resolveDashboardFilterDefs now normalizes both the spec object form and the
    bare-string shorthand (options: ['EMEA']) to { value, label } pairs —
    DashboardFilterDef.options is typed accordingly — and the filter bar's
    select renders labels (the trigger now shows the selected option's label, not
    its raw value). @object-ui/types aligns the GlobalFilterSchema.options
    shape with the spec union.

  • e628d1f: Dashboard-level filters follow-ups (#2578, framework#2501):

    • i18n: the DashboardFilterBar strings now ship as real locale entries —
      dashboard.filters.* (bar label, "All time", "Custom…", "All", "Reset",
      and the 13 date-range preset labels) added to en and zh. Previously the
      bar always rendered the useSafeTranslate English fallbacks.
    • types: GlobalFilterSchema.name and DashboardWidgetSchema.filterBindings
      landed in @objectstack/spec (framework#2501), so the local type
      annotations flip from "Pending alignment" to "Aligned" — no shape changes.

    Also adds five schema-catalog examples (plugin-dashboard/filtered-dashboard-*:
    dynamic optionsFrom options, text/number/lookup filter types, dataset +
    inline widget mix, targetWidgets allow-list, date presets + custom range)
    and a new "Dashboard-Level Filters" guide page covering the full tutorial,
    page.* expression usage, and known limitations with workarounds.

  • 9e2d58f: Kanban conditionalFormatting now accepts CEL rules in its type + schema (#1584 follow-up).

    Since #1584 moved kanban card styling onto the shared CEL evaluator, the runtime
    already accepts the spec { condition, style } rule shape — but the type and zod
    schema still only allowed the native { field, operator, value } shape, so a
    CEL kanban rule failed validation for something that worked at runtime. The
    KanbanConditionalFormattingRule type and ObjectKanbanSchema zod schema are
    widened to a union of both shapes, matching list/grid conditionalFormatting and
    the runtime. Back-compat: the native shape keeps validating unchanged.

@object-ui/sdui-parser@15.0.0

Choose a tag to compare

@github-actions github-actions released this 16 Jul 15:38
8918202
@object-ui/sdui-parser@15.0.0

@object-ui/sdui-parser@14.1.0

Choose a tag to compare

@github-actions github-actions released this 16 Jul 14:35
813b4d1
@object-ui/sdui-parser@14.1.0

@object-ui/runner@15.0.0

Choose a tag to compare

@github-actions github-actions released this 16 Jul 15:38
8918202

Patch Changes

  • @object-ui/plugin-kanban@15.0.0
  • @object-ui/types@15.0.0
  • @object-ui/core@15.0.0
  • @object-ui/react@15.0.0
  • @object-ui/components@15.0.0
  • @object-ui/plugin-charts@15.0.0

@object-ui/runner@14.1.0

Choose a tag to compare

@github-actions github-actions released this 16 Jul 14:34
813b4d1

Patch Changes

  • Updated dependencies [0890fa7]
  • Updated dependencies [2ded18c]
  • Updated dependencies [e628d1f]
  • Updated dependencies [5523fc4]
  • Updated dependencies [887062c]
  • Updated dependencies [055e1d2]
  • Updated dependencies [d741937]
  • Updated dependencies [9e2d58f]
  • Updated dependencies [dea65f7]
  • Updated dependencies [f30ff68]
  • Updated dependencies [073e7aa]
  • Updated dependencies [6c0135c]
  • Updated dependencies [5b52624]
  • Updated dependencies [4afb251]
  • Updated dependencies [d5b1bc0]
  • Updated dependencies [f94905d]
  • Updated dependencies [f0f10f5]
    • @object-ui/core@14.1.0
    • @object-ui/types@14.1.0
    • @object-ui/react@14.1.0
    • @object-ui/components@14.1.0
    • @object-ui/plugin-kanban@14.1.0
    • @object-ui/plugin-charts@14.1.0

@object-ui/react@15.0.0

Choose a tag to compare

@github-actions github-actions released this 16 Jul 15:39
8918202

Patch Changes

  • @object-ui/types@15.0.0
  • @object-ui/core@15.0.0
  • @object-ui/i18n@15.0.0
  • @object-ui/data-objectstack@15.0.0

@object-ui/react@14.1.0

Choose a tag to compare

@github-actions github-actions released this 16 Jul 14:35
813b4d1

Minor Changes

  • 5523fc4: Dashboard-level filters — the three #2578 item-5 enhancements (framework#2501):

    • react: nested PageVariablesProviders now MERGE instead of shadowing
      wholesale. A filtered dashboard embedded in a Page with its own variables
      keeps the outer page variables readable inside widget subtrees (page.*);
      an inner definition shadows only the SAME name; writes route to the scope
      that defines the variable (writing an outer-defined name from inside the
      nested subtree updates the outer provider); resetVariables stays local.
      Names defined nowhere still write locally, exactly as before.
    • core: buildWidgetScopedFilter accepts an optional knownFields set —
      a DEFAULT binding whose target field is not on the widget's object is
      skipped with a console warning instead of emitting a query the backend
      empty-matches. Explicit filterBindings strings are always honoured (a
      typo surfaces as a visibly empty widget, never a silently dropped filter).
      Omitting knownFields preserves the previous unchecked behaviour.
    • plugin-dashboard: DashboardRenderer feeds knownFields from
      dataSource.getObjectSchema for inline object widgets (best-effort —
      unchecked while metadata loads or when the source can't describe objects).
      optionsFrom dynamic filter options now resolve DISTINCT values
      server-side via a dataset GROUP BY (queryDataset with an inline draft)
      when the data source supports it, falling back to the previous client-side
      top-200 dedupe otherwise.
  • dea65f7: Unify the list-view conditional tier onto the canonical CEL engine (#1584).

    Conditional formatting (list / grid / kanban) and row-action visible /
    disabled predicates are now evaluated by @objectstack/formula's
    ExpressionEngine — the same engine the server uses — instead of the legacy
    JS-dialect ExpressionEvaluator, matching how @objectstack/spec already types
    these surfaces (ExpressionInputSchema / CEL). The whole platform now speaks one
    expression dialect (framework ADR-0058).

    • @object-ui/core: new evalRowPredicate + resolveConditionalFormatting
      helpers (next to evalFieldPredicate). One implementation of all three
      formatting rule shapes; dialect routing (a { dialect: 'cel' } envelope is
      always CEL; a bare string is CEL unless it carries legacy-only syntax
      (${…} / === / ?. / .includes()), which routes to the old engine with a
      one-time deprecation warning); the native { field, operator, value } form is
      translated to CEL.
    • @object-ui/react: new useRowPredicate hook (canonical CEL, ambient
      predicate scope merged).
    • Consumers converged: ListView.evaluateConditionalFormatting (thin wrapper,
      export kept), ObjectGrid row styling (inline copy removed), kanban card
      styles, and the grid / data-table row-action menus. plugin-view's kanban
      branch now forwards top-level conditionalFormatting (previously dropped).
    • Row-action visible fails closed (broken predicate → hidden + warn);
      disabled fails soft. The CEL in operator (and list membership) now work in
      row predicates — the legacy engine could not parse them.
    • The legacy FormField.condition: { field, equals/notEquals/in } is retired to
      a CEL translation (back-compat preserved); FieldDesigner migrated to
      visibleWhen.

    Fully back-compat: existing conditional-formatting rules, row-action predicates,
    and form condition metadata keep working (translated / routed as needed).

  • 5b52624: feat(detail): record-level inline edit — shared InlineEditContext + one atomic Save (objectui#2407 P1)

    Lift the inline-edit session out of DetailView's private state into a
    record-level, shared context so a record page's surfaces can share ONE draft and
    commit it in ONE atomic, cross-field-validated write (replacing the per-field
    save loop).

    • InlineEditContext / InlineEditProvider / useInlineEdit (@object-ui/react)
      — pure UI state (editing, canEdit, draft, autoFocusField, saving,
      error + enter / setField / cancel / reset). A separate context from
      RecordContext (mirrors HighlightFieldsContext) so per-keystroke draft churn
      doesn't re-render other record:* consumers.
    • <InlineEditSaveBar> (@object-ui/plugin-detail) — the record-level sticky
      Save/Cancel bar. Commits the whole draft in ONE
      dataSource.update(obj, id, draft, { ifMatch: data.updated_at })refresh();
      a 409 CONCURRENT_UPDATE reuses <ConcurrentUpdateDialog> (reload / overwrite).
      A callback mode (onFieldSave) preserves the drawer's per-field persistence
      contract with plugin-gantt/calendar/kanban.
    • DetailView now consumes useInlineEdit() instead of owning inline-edit
      state; its header/inline Save-Cancel bars and per-field batch-save are removed
      (the approval-lock badge stays). Rendered without a provider it is simply
      read-only.
    • record:details and RecordDetailDrawer each wrap their DetailView
      in an <InlineEditProvider> + <InlineEditSaveBar>. The object-lifecycle /
      permission gate flows through canEdit; computed / readonly / system fields
      and the OCC path are unchanged.

    Guardrails preserved: computed (formula/summary/rollup/auto_number) +
    readonly + system fields expose no editor; canEdit gate; OCC (ifMatch +
    ConcurrentUpdateDialog); the atomic partial update carries only user-edited
    keys (never computed/read-only). Editable highlights ride on top of this in P2.

  • f94905d: remove(react): drop the unused FormRenderer / FieldFactory duplicate render path (#2545)

    FormRenderer (and its captive FieldFactory) was an exported-but-dead second
    form render path: zero runtime consumers anywhere in the repo — the only import
    was its own test file. It duplicated @object-ui/plugin-form's ObjectForm
    (the path every app actually uses via the component registry) but had drifted
    into a degraded variant: raw-HTML/Tailwind instead of the shared UI primitives,
    a hard-coded Submit button, and no support for submitBehavior / aria /
    groups.

    Breaking (ships as minor per the pre-1.0 launch-window convention): the
    public exports FormRenderer, FormRendererProps, FieldFactory,
    FieldFactoryProps, and ExtendedFormField are removed from
    @object-ui/react. Render forms through the object-form schema node
    (@object-ui/plugin-form ObjectForm, reachable from a FormViewSchema via
    SchemaRenderer / the spec bridge) instead. Closes Phase 4 of #2545.

Patch Changes

  • Updated dependencies [82441e4]
  • Updated dependencies [2efa9fd]
  • Updated dependencies [0890fa7]
  • Updated dependencies [2ded18c]
  • Updated dependencies [e628d1f]
  • Updated dependencies [5523fc4]
  • Updated dependencies [887062c]
  • Updated dependencies [23d65c3]
  • Updated dependencies [9e2d58f]
  • Updated dependencies [dea65f7]
  • Updated dependencies [d5b1bc0]
  • Updated dependencies [f0f10f5]
    • @object-ui/i18n@14.1.0
    • @object-ui/core@14.1.0
    • @object-ui/types@14.1.0
    • @object-ui/data-objectstack@14.1.0

@object-ui/react-runtime@15.0.0

Choose a tag to compare

@github-actions github-actions released this 16 Jul 15:38
8918202
@object-ui/react-runtime@15.0.0

@object-ui/react-runtime@14.1.0

Choose a tag to compare

@github-actions github-actions released this 16 Jul 14:35
813b4d1
@object-ui/react-runtime@14.1.0