Skip to content

No record-context binding for filter values — element:number and every dataSource filter on a record page can only be scoped to the VIEWER, never to the record #7297

Description

@os-warren

Measured on @objectstack/spec 17.2.0 + objectui at the current checkout, while authoring a read-only "member detail" record page over sys_user for the Duly app (objectstack-ai/duly#13).

The gap

On a type: 'record' page, exactly one authorable component binds itself to the record in context: record:related_list, via relationshipField / relationshipValueField.

Every other data-bearing component takes a FilterCondition (element:number, and the component-level dataSource binding on anything). The complete dynamic vocabulary for a filter value is CONTEXT_TOKENS{current_user_id} and {current_org_id} (@objectstack/spec/data, context-tokens.zod.ts), re-exported verbatim by @object-ui/core's filter-tokens.ts. Both name the signed-in viewer. There is no token for the record the page is bound to.

ElementNumberRenderer (packages/components/src/renderers/basic/elements.tsx) confirms it from the other end — it passes props.filter straight to the adapter and adds nothing record-shaped:

const rows = await adapter.aggregate(props.object, {
  function: props.aggregate,
  filter: props.filter,});

Why it bites

element:number is the only component that renders a computed figure. So "how many open tasks does this person have" — the single most obvious thing to put at the top of a record page — is not authorable. What you get if you write the obvious thing is a count over the whole org, sitting under that person's name, which reads as their number. That is a silent wrong answer, and on the page in question it would also have been a comparison-to-peers the product forbids.

Note the asymmetry that makes it easy to trip over: visibleWhen on the same component does bind record (PageComponentSchema: "Page predicates bind the live page surface: record + current_user plus page state as page.<var>"). So the author can already say whether the block renders based on the record, but not what it counts.

What we did instead

Three record:related_lists (Open / Late / Not moving), each correctly record-scoped and each rendering a real count in RelatedList's badge (the server total). It works and it is honest, but it is three tables where three numbers were wanted.

Suggested shape

A {record_id} filter token alongside the two existing ones, resolved by resolveContextTokens from the record context when one is mounted and refused (loudly, like an unknown token) when it is not. The vocabulary lives in @objectstack/spec, so this needs the spec side too — filing here because the resolver and the record context are both objectui's, and CONTEXT_TOKENS is already consumed as a re-export rather than a fork (objectui#3003).

Whatever the spelling, the failure mode to avoid is the current one: an author writes a plausible filter, gets a number, and the number is about everybody.

🤖 Generated with Claude Code

https://claude.ai/code/session_01SqkTcrxUFci7nqXdbBSe2p

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

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