Skip to content

Commit 52fa9db

Browse files
claude[bot]claude
andauthored
docs(ui): filter the dashboards Global Filters example on the dotted path it means (#17767)
Clause-②: no Closes #16268 ## The premise triage left open, settled first Triage reserved one reading for the claiming seat: does `opportunity` declare a `region` field? It decides whether the example is *misleading* or *directly illegal*. Measured before touching the example: - **The page never declares `opportunity`'s fields at all.** It names `object: 'opportunity'` and stops. So the question has no literal answer on the page. - **No `opportunity` object exists anywhere in the shipped tree.** The name appears only in unit-test fixtures. The CRM example ships `crm_opportunity`, which declares no `region` and whose dataset carries no `include`. - **But the page's own dataset is affirmative evidence.** It reaches region as `field: 'account.region'` through `include: ['account']`. That join is only necessary if `opportunity` has no own `region` — had it one, the dimension would have been written `field: 'region'`. **Verdict: directly illegal under the page's own implied reading, undecidable under a literal one.** The fix below is green under *both*, so nothing here hangs on the undecidable half. ## Which fix, and why **Fix 2 — the dotted form** — as triage preferred, and its criterion stands unchallenged: this page's reader genuinely wants to filter by the customer's region, so fix 1 (swap in `stage`) would route around the confusion rather than teach the rule, and the harm on this card is precisely that the reader inferred the wrong rule. Two supporting readings taken before committing to it: - Dotted filter fields are really supported, not merely tolerated: `resolveFieldPath` walks them hop by hop, and `packages/lint/src/validate-widget-bindings.test.ts` pins the clean shape green — *"is silent on the clean shape — a dotted path through a declared include"*. - The page's dataset already declares `include: ['account']`, so the sibling rule `dashboard-filter-field-not-included` has nothing to say. The explicit `name: 'region'` is kept and now earned: left to default, the filter's variable key would be `account.region`, dots and all, in every expression and binding. The prose below the block now says so, which turns the retained name into a second lesson rather than a leftover. ## Acceptance 1 — measured, not assumed Transcribed the page's own declarations into a stack and ran the real `validateWidgetBindings` from a freshly built `packages/lint`, under both readings of the open premise: | Reading | Example | `dashboard-filter-field-unknown` | Other rules | | :--- | :--- | :--- | :--- | | `opportunity` has no own `region` (page-implied) | old, `field: 'region'` | **1 finding, severity error** | 0 | | `opportunity` has no own `region` (page-implied) | new, `field: 'account.region'` | **0** | 0 | | `opportunity` owns `region` (counterfactual) | old, `field: 'region'` | 0 | 0 | | `opportunity` owns `region` (counterfactual) | new, `field: 'account.region'` | **0** | 0 | The error the old example raises, verbatim: ``` inherits dashboard filter `region(region)`, but object `opportunity` (dataset "sales") has no field `region`. ``` Row 2's zero across *all* rules is the `include` clause reporting satisfied as well. The before/after pair is a one-off proof run from the scratchpad against the built `dist`; it leaves no test file behind. ## Acceptance 3 — the reverse-read, zeros included **On this page.** Every other `region` on the page is a widget `dimensions` entry selected from the dataset by name — the correct side of the namespace boundary, untouched and still correct. One site examined and deliberately left alone: the Per-Widget Filter Bindings block comments `// Default binding: dateRange -> created_at, region -> region.` That belongs to a *different* illustrative dashboard which declares no `globalFilters` and no dataset, and the statement stays true for any dashboard whose region filter names a field the widget's object owns. It involves no dimension and so carries none of this card's harm. Changing it to `account.region` would have been worse: it would smuggle an implicit `include` requirement into an example that shows no dataset. Recorded rather than edited. **On pages linking here** — seven pages link to this one (`capabilities/analytics`, `getting-started/quick-start`, `ui/apps`, `ui/index`, `ui/pages`, `ui/reports`, `ui/views`). **Zero** repeat the inference; none reuses the `region` filter example. `deployment/validating-metadata` already states the rule correctly. `ui/translations` keys global-filter translations by the filter's `name` — kept as `region`, so that key is unmoved. **Made-false sweep across the tree: zero.** No sentence outside this page depends on the old spelling. ## Changeset — skip, measured No package's `files[]` carries `content/`; the only consumer of `content/docs` is `apps/docs`, which is `private: true` and publishes nothing. Positive control on the same measurement: it reads `dist` in 23 packages' `files[]` and prints `packages/spec`'s full list, so the zero is a real zero and not an empty probe. `skip-changeset` is applied as a **label**. ## Gates All 40 families derived by `node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack` from the real change set: green. `check:skill-examples` — the gate that type-checks the `os:check` fences this diff edits — first returned a prerequisite failure (`packages/client-react` unbuilt), which is not a verdict; after building that package it reports **258 prose examples type-check across 3 surfaces**. Control-byte self-scan on the edited file: zero hits; `check-nul-bytes` green. Verified at `591d48a8b0`. ## 验收备注 - 反向读在本页发现一处 `region -> region` 的绑定注释,判为独立示例、未改,理由见上;归 `noted, not filed`。 --- _Generated by [Claude Code](https://claude.ai/code/session_012GKcPZbMoGq7WPzKLfRBTU)_ Co-authored-by: Claude <noreply@anthropic.com>
1 parent fce7cd4 commit 52fa9db

1 file changed

Lines changed: 8 additions & 2 deletions

File tree

content/docs/ui/dashboards.mdx

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -350,15 +350,21 @@ Add interactive filter controls that apply to all widgets:
350350
{/* os:check */}
351351
```typescript
352352
globalFilters: [
353-
{ name: 'region', field: 'region', label: 'Region', type: 'select' },
353+
// `account.region` is a DOTTED PATH walked from the bound widget's
354+
// `dataset.object` (`opportunity`) through the `include: ['account']` the
355+
// dataset declares. It is not the dataset's dimension that is also spelled
356+
// `region` — a filter's `field` never reads dimension names.
357+
{ name: 'region', field: 'account.region', label: 'Region', type: 'select' },
354358
{ field: 'owner', label: 'Sales Rep', type: 'lookup' },
355359
]
356360
```
357361

358362
Each filter's `name` is its stable identity: the key its value is published
359363
under as a dashboard-level variable (readable in widget expressions as
360364
`page.<name>`) and the key widgets reference in `filterBindings`. It defaults
361-
to `field`; the name `dateRange` is reserved for the built-in date range.
365+
to `field`; the name `dateRange` is reserved for the built-in date range. The
366+
filter above names itself `region` for exactly that reason — left to default it
367+
would be keyed `account.region`, dots and all, in every expression and binding.
362368

363369
### Where a Filter's `field` Resolves
364370

0 commit comments

Comments
 (0)