Skip to content

Commit f4a8eed

Browse files
feat(spec): a stored view filter list can hold an any-of group (#28380)
🤖 Generated with [Claude Code](https://claude.com/claude-code) https://claude.ai/code/session_017ihL2fi9zfJhUTubyJYb6V Fixes #28020 Clause-②: yes (widening) Metadata-protocol: added ## 维护者速读 - 改了什么:已保存视图的筛选列表(`ListView.filter`、视图页签、页面 `filterBy`、数据源与相关列表等)原来只能写"全部满足"的平铺规则,现在可以多放一种元素 `{ any: [规则, ...] }`,表示"满足其中任意一条";只允许一层,列表本身仍是"并且"。 - 为什么改:业务上最常见的"未完成,或最近 7 天内完成"这类视图以前无法保存,只能拆成两个视图;现在可以作为一个视图存下来。 - 风险与回滚:今天已保存的每个筛选解析结果逐字节不变(接受的输出相同,拒绝的报错码/路径/文案相同);控制台尚未应用该分组(已标 `[PLANNED — not yet rendered]`,由 #28370 跟进),存了分组的视图暂时不会按它过滤;回滚只需还原本 PR。 - 先看:`packages/spec/src/ui/view.zod.ts` 中的 `ViewFilterAnyGroupSchema` / `ViewFilterElementSchema`,以及钉住全部要求的 `packages/spec/src/ui/view-filter-any-group.test.ts`。 - 两分钟验证:`pnpm --filter @objectstack/spec exec vitest run src/ui/view-filter-any-group.test.ts`,再跑 `pnpm --filter @objectstack/lint exec vitest run src/filter-walk-any-group.test.ts`。 - 需要你做的:请裁定这一存储形状(列表中一层 any-of 分组),并批准键名 `any`;另请确认蓝图(solution-blueprint)的 `filters` 保持平铺规则、相关列表的 UI 镜像暂不放开分组这两处取舍。 Independent review: none run (quota); the PR waits for the seat's contract-review hand-off. ## What changes - **Spec (`packages/spec/src/ui/view.zod.ts`).** A view filter list now holds `ViewFilterElementSchema` = `ViewFilterRuleSchema | ViewFilterAnyGroupSchema`. The group is `{ any: [rule, ...] }`: a strict object whose only key is `any`, a non-empty array of `ViewFilterRuleSchema` itself, so the operator vocabulary, the legacy-alias fold, the operator/value coupling and the `icontains` comparand check all apply inside a group as at the top level. One level only. - **Key spelling `any`.** No at-rest any-of spelling exists to mirror. The console builder's `{ id, logic: 'and'|'or', conditions }` is editing state: its `and` arm repeats the list's own AND, so `logic` would have exactly one legal value, and `id` is a UI row key. `$or` on views is out of bounds (no `FilterConditionSchema` admitted). `{ any: [...] }` says the semantics in the key and leaves nothing to agree with. - **Byte-identical for stored filters.** The element union carries a check (the same pattern as `focusClaimedBranch` on `ViewMetadataSchema`) that reports only the branch the element claims, so a refused flat rule shows exactly the issues it showed before, not an `invalid_union`. - **Refusals.** Empty group: `too_small` at `filter.N.any`. Nested group: `unrecognized_keys` naming `any` on the inner element, with guidance. A non-rule member, a non-array `any`, or a rule key beside `any` are refused. `$or`, `or`, `anyOf`, `logic` and `conditions` written on a rule are answered with the group shape. - **Carriers.** Every carrier that held `z.array(ViewFilterRuleSchema)` moved: `ListView.filter`, `ViewTab.filter`, the three page carriers (`ElementDataSource.filter`, record binding filter, `InterfacePageConfig.filterBy`) and the eleven component doors. A source-scan pin holds that set. The one exception is `BlueprintViewSchema.filters` (`packages/spec/src/ai/solution-blueprint.zod.ts`): the model writes it through a strict mirror that cannot carry a union, and its applier lives outside this repo. A comment there says so. - **Readers.** Updated: `@objectstack/lint` `filter-walk.ts` (list-view, dataset and widget field-reference rules), `validate-preset-comparands.ts`, and `validate-page-field-bindings.ts` (`filterBy`, the related-list `filter`). `@objectstack/metadata-protocol` `computeViewReferenceDiagnostics` reads preset-tab filters. Checked and unchanged: `graftNormalizedOperators` (structural, now pinned through a group), `validate-field-consumers` (generic walk, already credits fields inside a group) and `validate-empty-combinators`. Marked `[PLANNED — not yet rendered]`: every console reader that turns the list into a query (plugin-list `buildEffectiveFilter`, core `convertFiltersToAST`, data-objectstack `objectFilterEntriesToAST`, app-shell `viewFilterFold`, plugin-view `parseSpecFilter`). No server-side reader in `packages/` does that, so the group carries the PLANNED tag in its describe, TSDoc and `liveness/view.json`. - **Follow-up.** The console half is filed as **#28370** (domain:ui, `finding`). It lands after this PR. - Prose that said `$or` cannot be written in a rule array (`filter-rule-array.ts`, `conversions/registry.ts`) now names the group. - Changeset: `@objectstack/spec`, `@objectstack/lint`, `@objectstack/metadata-protocol` minor. ## Tests - `packages/spec/src/ui/view-filter-any-group.test.ts` (new) covers: - a group is accepted on ListView, ViewTab, ElementDataSource and InterfacePageConfig; - stored flat rules, accepted and refused, parse identically as an element and as a bare rule; - refinements apply inside a group; - refusals: empty, nested, a non-rule member, a non-array `any`, a stray rule key, the OR spellings; - the wire `id` strip inside a group, and the authoring refusal of `id`; - JSON-schema `anyOf`, the `isViewFilterAnyGroup` predicate, and a carrier source scan. - `packages/lint/src/filter-walk-any-group.test.ts` (new), plus cases in `validate-page-field-bindings.test.ts` and `validate-preset-comparands.test.ts`: a field inside a group is checked at `…[0].any[1]…`, and `any` is never reported as a field. - `packages/metadata-protocol/src/metadata-diagnostics.view-filter-any-group.test.ts` (new): diagnostics through a group, and the operator graft through a group. - `ui/packages/types` type-parity pins move to `ViewFilterElement[]`. The two related-list mirrors are pinned as "the contract minus the group" plus "the contract also takes the group". `record-components.ts` stays flat because widening it reaches plugin-detail prop types, which belong to #28370. ## Acceptance notes - Shape A: one group element, one level, inside the existing list. No `$or`, no `FilterConditionSchema` on views. - `solution-blueprint` view `filters` stay flat (strict mirror, applier out of repo). That call is the seat's to confirm. - The related-list UI mirror (`ui/packages/types/src/record-components.ts`) deliberately lags the contract by the group, with pins that hold the lag exactly. Widening it is #28370's job. - The conversion registry does not write groups: converting a stored `$or` record into a group would widen that conversion, so it is left as is. - The group is `[PLANNED — not yet rendered]` until #28370: a view that stores one saves and validates but does not narrow its rows yet. ## Verification - Post-merge (tree at the head of this PR): - `@objectstack/spec`: 773 files / 22857 tests passed; - targeted lint tests: 4 files / 263 tests passed; - metadata-protocol: 1 file / 3 tests passed. - Pre-merge full suites: - lint: 183 files / 7693 tests, typecheck passed; - metadata-protocol: 285 files, typecheck passed; - ui type-check over spec dependents: green after the pin moves (`@object-ui/types`, plugin-detail); - ui pin tests: 6 files / 184 tests passed. - `dispatch-gates.mjs --commands`: 110 derived commands, each run with its exit code recorded, then reconciled with `--ran`. The result: 110 run, 110 exit 0, 0 NOT-MEASURED. Two gates (`check:skill-examples`, `check:dual-build-cjs-loads`) first exited 3 (prerequisite not met, unbuilt dist). Both were rerun green after building `@objectstack/client-react` and then the full workspace (`turbo run build`, 116/116 tasks). `check:dev-prereqs` and `check:nul-bytes` also pass. - `gen:schema`, `gen:docs`, `check:generated -- --fix` (all artifacts current), `check:liveness` and `check:authorable-surface` all pass. --------- Co-authored-by: Claude <noreply@anthropic.com>
1 parent 5517005 commit f4a8eed

38 files changed

Lines changed: 1253 additions & 122 deletions
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
---
2+
'@objectstack/spec': minor
3+
'@objectstack/lint': minor
4+
'@objectstack/metadata-protocol': minor
5+
---
6+
7+
feat(spec): a stored view filter list can hold an any-of group, `{ or: [rule, ...] }`
8+
9+
Clause-②: yes (widening)
10+
Metadata-protocol: added
11+
12+
A view filter list (`ListView.filter`, a view tab's `filter`, `Page.interfaceConfig.filterBy`, an element data source's `filter`, the related-list and picker filters and the component `filter` doors) was an AND list of flat `{ field, operator, value }` rules, so a view whose natural filter is an any-of ("open, or completed in the last 7 days") could not be stored. The list now takes one more element kind beside the rule: `{ or: [rule, ...] }`, a non-empty array of flat rules of which ANY may match. The list still ANDs its elements.
13+
14+
```ts
15+
filter: [
16+
{ or: [
17+
{ field: 'status', operator: 'equals', value: 'open' },
18+
{ field: 'completed_at', operator: 'after', value: '{7_days_ago}' },
19+
] },
20+
{ field: 'owner', operator: 'equals', value: '{current_user_id}' },
21+
]
22+
```
23+
24+
- New exports from `@objectstack/spec/ui`: `ViewFilterOrGroupSchema`, `ViewFilterElementSchema` (rule or group — what every carrier holds now), their `ViewFilterOrGroup` / `ViewFilterElement` types and `...Parsed` twins, and `isViewFilterOrGroup(value)`, the one test that tells the two element kinds apart.
25+
- A group's members are `ViewFilterRuleSchema` itself, so the operator vocabulary, the legacy-alias fold, the operator/value-shape coupling and the `icontains` comparand check apply inside a group exactly as at the top level.
26+
- Refused at parse: an empty group (`too_small` at `filter.N.or`), a group inside a group (one level only; `unrecognized_keys` naming `or` on the inner element), a member that is not a rule, and a rule key written beside `or`. `$or`, `any`, `anyOf`, `logic` and `conditions` written on a rule are answered with the group shape. The key is `or` by the maintainer's ruling: it matches the and/or wording of Notion, monday.com and Dataverse filters, and a nested level added later would pair with `and`.
27+
- Every filter stored before this change parses exactly as it did: the same output for an accepted rule, and the same issues (code, path, message) for a refused one — the element union reports only the branch the element claims.
28+
- The wire door strips the console's row `id` inside a group as on a plain rule.
29+
- `ViewFilterRule` (the type) is unchanged and still means one flat rule. A reader typed against a carrier's element now sees `ViewFilterElement`, and must step into a group (`isViewFilterOrGroup`) rather than read `field` off every element.
30+
- `solution-blueprint` view `filters` deliberately stay flat rules: the model writes them through a strict mirror that cannot carry a union.
31+
- `[PLANNED — not yet rendered]`: no console applies the group yet. The list query build reads flat rules only, so until it reads this element a view that stores a group is refused when it loads (the server answers the passed-through group with a malformed-filter error and the list shows no rows); it fails closed, and the group's describe says so.
32+
33+
Readers updated: `@objectstack/lint`'s filter field-key walk (`filter-walk.ts`, used by the list-view, dataset and widget field-reference rules), the preset-comparand rule, and the page field-binding rule (`filterBy` and a related list's `filter`) step into a group, so a field inside one is checked and `or` is never reported as a field. `@objectstack/metadata-protocol`'s `computeViewReferenceDiagnostics` checks the fields inside a group in a preset tab's filter.

‎content/docs/references/api/protocol.mdx‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1856,7 +1856,7 @@ The published metadata item body, opaque by ruling (1C). Shape is the item's own
18561856
| **type** | `Enum<'grid' \| 'kanban' \| 'gallery' \| 'calendar' \| 'timeline' \| 'gantt' \| 'map' \| 'chart' \| 'tree'>` | optional (default: `"grid"`) | |
18571857
| **data** | `{ provider: 'object'; object: string } \| { provider: 'value'; items: any[] } \| { provider: 'schema'; schemaId: string; schema?: Record<string, any> }` | optional | Data source configuration (defaults to "object" provider) |
18581858
| **columns** | `string[] \| { field: string; label?: string \| Record<string, string>; width?: number; align?: Enum<'left' \| 'center' \| 'right'>; … }[]` | ✅ | Fields to display as columns — the PROJECTION of the per-view field composition `columns` x `hiddenFields` x `fieldOrder`: this list is the candidate set AND the baseline order; `hiddenFields` subtracts from it and `fieldOrder` orders what survives. `hiddenFields` and `fieldOrder` cannot add a field omitted here. An empty list declares no projection, so neither of them applies: which columns show is then left to the renderer (objectui's `ListView` grid derives the object's default columns). |
1859-
| **filter** | `{ field: string; operator: Enum<'equals' \| 'not_equals' \| 'contains' \| 'not_contains' \| 'icontains' \| …>; value?: string \| number \| boolean \| null \| (string \| number)[] }[]` | optional | Filter criteria (JSON Rules) |
1859+
| **filter** | `({ field: string; operator: Enum<'equals' \| 'not_equals' \| 'contains' \| 'not_contains' \| 'icontains' \| …>; value?: string \| number \| boolean \| null \| (string \| number)[] } \| { or: object[] })[]` | optional | Filter criteria (JSON Rules) |
18601860
| **sort** | `{ field: string; order: Enum<'asc' \| 'desc'> }[]` | optional | |
18611861
| **searchableFields** | `string[]` | optional | Fields enabled for search |
18621862
| **filterableFields** | `never` | optional | [REMOVED] `view.list.filterableFields` was removed in @objectstack/spec 18 (ADR-0049 enforce-or-remove) — the key was declared as a shorthand for `userFilters.fields` (the quick-filter bar), but the one renderer that read it used it as a whitelist of the fields the Filter panel offers instead, so one key carried two meanings and drew no quick filter. Delete the key; no per-view Filter-panel whitelist replaces it. For a curated end-user filter bar, declare `userFilters: { element: 'dropdown', fields: [{ field: '<field_name>' }] }`. The Filter panel offers every field the user may read: field read security decides, and a field the object definition marks `hidden: true` is not offered. Run `os migrate meta --from 17` to list the mechanical edits for existing sources; `--write` applies the ones it can prove, and you apply the rest by hand. |
@@ -1935,7 +1935,7 @@ The published metadata item body, opaque by ruling (1C). Shape is the item's own
19351935
| **type** | `Enum<'grid' \| 'kanban' \| 'gallery' \| 'calendar' \| 'timeline' \| 'gantt' \| 'map' \| 'chart' \| 'tree'>` | optional (default: `"grid"`) | |
19361936
| **data** | `{ provider: 'object'; object: string } \| { provider: 'value'; items: any[] } \| { provider: 'schema'; schemaId: string; schema?: Record<string, any> }` | optional | Data source configuration (defaults to "object" provider) |
19371937
| **columns** | `string[] \| { field: string; label?: string \| Record<string, string>; width?: number; align?: Enum<'left' \| 'center' \| 'right'>; … }[]` | ✅ | Fields to display as columns — the PROJECTION of the per-view field composition `columns` x `hiddenFields` x `fieldOrder`: this list is the candidate set AND the baseline order; `hiddenFields` subtracts from it and `fieldOrder` orders what survives. `hiddenFields` and `fieldOrder` cannot add a field omitted here. An empty list declares no projection, so neither of them applies: which columns show is then left to the renderer (objectui's `ListView` grid derives the object's default columns). |
1938-
| **filter** | `{ field: string; operator: Enum<'equals' \| 'not_equals' \| 'contains' \| 'not_contains' \| 'icontains' \| …>; value?: string \| number \| boolean \| null \| (string \| number)[] }[]` | optional | Filter criteria (JSON Rules) |
1938+
| **filter** | `({ field: string; operator: Enum<'equals' \| 'not_equals' \| 'contains' \| 'not_contains' \| 'icontains' \| …>; value?: string \| number \| boolean \| null \| (string \| number)[] } \| { or: object[] })[]` | optional | Filter criteria (JSON Rules) |
19391939
| **sort** | `{ field: string; order: Enum<'asc' \| 'desc'> }[]` | optional | |
19401940
| **searchableFields** | `string[]` | optional | Fields enabled for search |
19411941
| **filterableFields** | `never` | optional | [REMOVED] `view.list.filterableFields` was removed in @objectstack/spec 18 (ADR-0049 enforce-or-remove) — the key was declared as a shorthand for `userFilters.fields` (the quick-filter bar), but the one renderer that read it used it as a whitelist of the fields the Filter panel offers instead, so one key carried two meanings and drew no quick filter. Delete the key; no per-view Filter-panel whitelist replaces it. For a curated end-user filter bar, declare `userFilters: { element: 'dropdown', fields: [{ field: '<field_name>' }] }`. The Filter panel offers every field the user may read: field read security decides, and a field the object definition marks `hidden: true` is not offered. Run `os migrate meta --from 17` to list the mechanical edits for existing sources; `--write` applies the ones it can prove, and you apply the rest by hand. |

‎content/docs/references/data/object.mdx‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -375,7 +375,7 @@ const result = ApiMethod.parse(data);
375375
| **type** | `Enum<'grid' \| 'kanban' \| 'gallery' \| 'calendar' \| 'timeline' \| 'gantt' \| 'map' \| 'chart' \| 'tree'>` | optional (default: `"grid"`) | |
376376
| **data** | `{ provider: 'object'; object: string } \| { provider: 'value'; items: any[] } \| { provider: 'schema'; schemaId: string; schema?: Record<string, any> }` | optional | Data source configuration (defaults to "object" provider) |
377377
| **columns** | `string[] \| { field: string; label?: string \| Record<string, string>; width?: number; align?: Enum<'left' \| 'center' \| 'right'>; … }[]` | ✅ | Fields to display as columns — the PROJECTION of the per-view field composition `columns` x `hiddenFields` x `fieldOrder`: this list is the candidate set AND the baseline order; `hiddenFields` subtracts from it and `fieldOrder` orders what survives. `hiddenFields` and `fieldOrder` cannot add a field omitted here. An empty list declares no projection, so neither of them applies: which columns show is then left to the renderer (objectui's `ListView` grid derives the object's default columns). |
378-
| **filter** | `{ field: string; operator: Enum<'equals' \| 'not_equals' \| 'contains' \| 'not_contains' \| 'icontains' \| …>; value?: string \| number \| boolean \| null \| (string \| number)[] }[]` | optional | Filter criteria (JSON Rules) |
378+
| **filter** | `({ field: string; operator: Enum<'equals' \| 'not_equals' \| 'contains' \| 'not_contains' \| 'icontains' \| …>; value?: string \| number \| boolean \| null \| (string \| number)[] } \| { or: object[] })[]` | optional | Filter criteria (JSON Rules) |
379379
| **sort** | `{ field: string; order: Enum<'asc' \| 'desc'> }[]` | optional | |
380380
| **searchableFields** | `string[]` | optional | Fields enabled for search |
381381
| **filterableFields** | `never` | optional | [REMOVED] `view.list.filterableFields` was removed in @objectstack/spec 18 (ADR-0049 enforce-or-remove) — the key was declared as a shorthand for `userFilters.fields` (the quick-filter bar), but the one renderer that read it used it as a whitelist of the fields the Filter panel offers instead, so one key carried two meanings and drew no quick filter. Delete the key; no per-view Filter-panel whitelist replaces it. For a curated end-user filter bar, declare `userFilters: { element: 'dropdown', fields: [{ field: '<field_name>' }] }`. The Filter panel offers every field the user may read: field read security decides, and a field the object definition marks `hidden: true` is not offered. Run `os migrate meta --from 17` to list the mechanical edits for existing sources; `--write` applies the ones it can prove, and you apply the rest by hand. |

‎content/docs/references/index.mdx‎

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
---
22
title: Protocol reference — every schema by module
33
navTitle: Protocol Reference
4-
description: Every schema published by @objectstack/spec — 1571 schemas across 14 protocol modules
4+
description: Every schema published by @objectstack/spec — 1573 schemas across 14 protocol modules
55
---
66

77
{/* ⚠️ AUTO-GENERATED — DO NOT EDIT. Run build-docs.ts to regenerate. Hand-written docs live in the module folders under content/docs/. */}
@@ -33,8 +33,8 @@ counts are sums of the rows they head. Regenerate with
3333
| [Shared Protocol](/docs/references/shared) | 10 | 31 | Primitives used across every protocol — identifiers, HTTP, expressions, error maps, enums. |
3434
| [Studio Protocol](/docs/references/studio) | 3 | 35 | Studio designer metadata — the authoring surfaces for the protocols above. |
3535
| [System Protocol](/docs/references/system) | 37 | 287 | The runtime environment — logging, jobs, cache, metrics, notifications, i18n and compliance. |
36-
| [UI Protocol](/docs/references/ui) | 16 | 172 | Apps, pages, views, dashboards, reports, actions and themes — the ObjectUI layer. |
37-
| **Total** | **204** | **1571** | 14 protocol modules |
36+
| [UI Protocol](/docs/references/ui) | 16 | 174 | Apps, pages, views, dashboards, reports, actions and themes — the ObjectUI layer. |
37+
| **Total** | **204** | **1573** | 14 protocol modules |
3838

3939
---
4040

@@ -371,7 +371,7 @@ The runtime environment — logging, jobs, cache, metrics, notifications, i18n a
371371

372372
## UI Protocol
373373

374-
**Source:** `packages/spec/src/ui/` · **Import:** `@objectstack/spec/ui` · **16 pages, 172 schemas**
374+
**Source:** `packages/spec/src/ui/` · **Import:** `@objectstack/spec/ui` · **16 pages, 174 schemas**
375375

376376
Apps, pages, views, dashboards, reports, actions and themes — the ObjectUI layer.
377377

@@ -392,7 +392,7 @@ Apps, pages, views, dashboards, reports, actions and themes — the ObjectUI lay
392392
| [`report.zod.ts`](/docs/references/ui/report) | `JoinedReportBlock`, `Report`, `ReportChart`, `ReportSort`, `ReportType` |
393393
| [`responsive.zod.ts`](/docs/references/ui/responsive) | `ResponsiveStyles`, `StyleMap` |
394394
| [`sharing.zod.ts`](/docs/references/ui/sharing) | `SharingConfig` |
395-
| [`view.zod.ts`](/docs/references/ui/view) | `AddRecordConfig`, `AppearanceConfig`, `CalendarConfig`, `ColumnPrefix`, `ColumnSummary`, `ColumnSummaryConfig`, `EmptyState`, `FormButtonConfig`, `FormField`, `FormSection`, `FormSelectOption`, `FormView`, `GalleryConfig`, `GanttConfig`, `GanttQuickFilter`, `GroupingConfig`, `GroupingField`, `HttpMethodSubset`, `HttpRequest`, `KanbanConfig`, `ListChartConfig`, `ListColumn`, `ListMapConfig`, `ListView`, `NavigationConfig`, `NavigationMode`, `ObjectListView`, `ObjectUserFilters`, `PaginationConfig`, `RowColorConfig`, `RowHeight`, `SelectionConfig`, `TimelineConfig`, `TreeConfig`, `UserActionsConfig`, `UserFilterField`, `UserFilters`, `View`, `ViewData`, `ViewFilterRule`, `ViewItem`, `ViewItemName`, `ViewItemWire`, `ViewKind`, `ViewScope`, `ViewSharing`, `ViewTab`, `VisualizationType` |
395+
| [`view.zod.ts`](/docs/references/ui/view) | `AddRecordConfig`, `AppearanceConfig`, `CalendarConfig`, `ColumnPrefix`, `ColumnSummary`, `ColumnSummaryConfig`, `EmptyState`, `FormButtonConfig`, `FormField`, `FormSection`, `FormSelectOption`, `FormView`, `GalleryConfig`, `GanttConfig`, `GanttQuickFilter`, `GroupingConfig`, `GroupingField`, `HttpMethodSubset`, `HttpRequest`, `KanbanConfig`, `ListChartConfig`, `ListColumn`, `ListMapConfig`, `ListView`, `NavigationConfig`, `NavigationMode`, `ObjectListView`, `ObjectUserFilters`, `PaginationConfig`, `RowColorConfig`, `RowHeight`, `SelectionConfig`, `TimelineConfig`, `TreeConfig`, `UserActionsConfig`, `UserFilterField`, `UserFilters`, `View`, `ViewData`, `ViewFilterElement`, `ViewFilterOrGroup`, `ViewFilterRule`, `ViewItem`, `ViewItemName`, `ViewItemWire`, `ViewKind`, `ViewScope`, `ViewSharing`, `ViewTab`, `VisualizationType` |
396396

397397
---
398398

0 commit comments

Comments
 (0)