diff --git a/.changeset/29382-filter-binding-daterange-prose.md b/.changeset/29382-filter-binding-daterange-prose.md new file mode 100644 index 00000000000..e86c1df054d --- /dev/null +++ b/.changeset/29382-filter-binding-daterange-prose.md @@ -0,0 +1,10 @@ +--- +'@objectstack/lint': patch +--- + +docs(lint): the `dashboard-filter-binding-unknown` explanation no longer says a `dateRange` binding is always reported on a dashboard without `dateRange` + +Clause-②: no +Metadata-protocol: none + +`os explain dashboard-filter-binding-unknown` said a widget's `filterBindings.dateRange` key "on a dashboard that declares no `dateRange` is reported the same way". The rule never did that when the dashboard declares a `globalFilters` entry named `dateRange`: every `globalFilters` entry's name is a declared filter, so the key binds it and the rule accepts it, as the explanation's first paragraph already says. The sentence now reads that a `dateRange` key is reported only when the dashboard declares neither `dateRange` nor a `globalFilters` entry named `dateRange`. The rule's behaviour is unchanged; a new test pins the accepted case. diff --git a/packages/lint/src/rule-explanations.ts b/packages/lint/src/rule-explanations.ts index 770e6e1ffc4..a6f3ca32e95 100644 --- a/packages/lint/src/rule-explanations.ts +++ b/packages/lint/src/rule-explanations.ts @@ -405,8 +405,9 @@ const DASHBOARD_FILTER_BINDING_UNKNOWN_EXPLANATION: RuleExplanation = { 'way the widget counts different rows than the author wrote, with nothing on the page to say so, ' + 'which is why the rule is an error and is not suppressible.', 'To fix it, rename the key to a declared filter name (the finding names the nearest one), declare ' + - 'the filter on the dashboard, or delete the entry. A `dateRange` key on a dashboard that declares ' + - 'no `dateRange` is reported the same way: there is no date range for it to bind.', + 'the filter on the dashboard, or delete the entry. A `dateRange` key is reported the same way ' + + 'only when the dashboard declares neither `dateRange` nor a `globalFilters` entry named `dateRange`: ' + + 'either one is a declared filter under that name, and with neither there is nothing for it to bind.', ], }; diff --git a/packages/lint/src/validate-widget-bindings.test.ts b/packages/lint/src/validate-widget-bindings.test.ts index 3b60081c6b2..295c2cd88af 100644 --- a/packages/lint/src/validate-widget-bindings.test.ts +++ b/packages/lint/src/validate-widget-bindings.test.ts @@ -948,6 +948,14 @@ describe('dashboard-filter-binding-unknown (#27445)', () => { expect(findings[0].hint).toBe('Declare `dateRange` on the dashboard, or delete the `dateRange` entry.'); }); + it('a `globalFilters` entry named `dateRange` declares the name on a dashboard without `dateRange`', () => { + const findings = only(validateWidgetBindings(stack( + { dateRange: undefined, globalFilters: [{ name: 'dateRange', field: 'signed_at', type: 'date' }] }, + { filterBindings: { dateRange: false } }, + ))); + expect(findings).toEqual([]); + }); + it('a dashboard with no filters at all refuses every key and says so', () => { const findings = only(validateWidgetBindings(stack( { dateRange: undefined, globalFilters: undefined }, diff --git a/packages/lint/src/validate-widget-bindings.ts b/packages/lint/src/validate-widget-bindings.ts index a00a229cecb..c943d95ab21 100644 --- a/packages/lint/src/validate-widget-bindings.ts +++ b/packages/lint/src/validate-widget-bindings.ts @@ -79,9 +79,12 @@ import { * counts, which is why this is an error and not the warning tier * `chart-field-unknown` took for its ignored keys (#15463): those re-dress * the same numbers, this one changes them. The declared names are the ones - * {@link dashboardFilterDefs} builds, so the reserved `dateRange` key is - * valid only on a dashboard that declares `dateRange` — the runtime, this - * file and `@objectstack/verify`'s window proof all build that def only then. + * {@link dashboardFilterDefs} builds: every `globalFilters` entry's name, + * and the reserved `dateRange` when the dashboard declares `dateRange` (the + * runtime, this file and `@objectstack/verify`'s window proof all build that + * built-in def only then). A `globalFilters` entry named `dateRange` is a + * declared filter by that name too, so a `dateRange` key binds it on a + * dashboard that declares no `dateRange`. * * Advisory rules — severity `warning`, build stays green: * @@ -450,7 +453,8 @@ export const DASHBOARD_FILTER_FIELD_UNPROVISIONED = 'dashboard-filter-field-unpr export const DASHBOARD_FILTER_FIELD_NOT_INCLUDED = 'dashboard-filter-field-not-included'; /** * [#27445] A widget `filterBindings` key that names no filter the dashboard - * declares (`dateRange` counts only when the dashboard declares one). + * declares (`dateRange` counts when the dashboard declares `dateRange` or a + * `globalFilters` entry named `dateRange`). */ export const DASHBOARD_FILTER_BINDING_UNKNOWN = 'dashboard-filter-binding-unknown'; /** [#14148] A key of the widget's OWN `filter` that resolves to no column. */