Repository navigation
Commit 968cacf
fix(app-shell): the Studio canvas runs a report or widget over a draft dataset before the package publishes (#27758)
domain:ui#2 · os-bill · session_01Utp6CY2n1JmZZKrHgtp9jC
<!-- claude-projects-attribution: {"github_login":"os-bill"} -->
_Requested by **Bill** · [project
thread](https://claude.ai/code/project/chan_016iMXWSZDzqWRWvWzdNo8wg?thread=cmsg_016iMXWSZDzqWRWvWzdNo8wgP6XkfpjCfyzzG2KwQPUZfy)_
Fixes #27585
Clause-②: yes (widening)
Metadata-protocol: none
## 维护者速读
- 改了什么:Studio 画布上的报表与仪表盘组件查询数据集时带上草稿标记,草稿数据集在包发布前就能出数;`queryDataset`
新增可选参数 `previewDrafts`。
- 为什么改:作者在 Studio
新建数据集并绑定报表或图表后,画布提示「数据集在此环境中未定义」,直到发布才显示,而旁边的选择器早已能读到这份草稿。
- 风险与回滚:只影响 Studio 内的报表/仪表盘预览;控制台运行时和 Setup 编辑器的请求一字节不变。回滚即还原本 PR。
- 先看:`canvasDataSource.ts`(画布数据源)、`data-objectstack/src/index.ts` 的
`queryDataset` 参数一段、`canvasDataSource-27585.test.tsx`。
- 两分钟验证:`pnpm --dir ui exec vitest run
packages/app-shell/src/views/metadata-admin/previews/canvasDataSource-27585.test.tsx`,预期
5 个测试全过。
- 需要你做的:无,席位落地。
## What changes
**The defect.** In the Studio, a report or a dashboard widget bound to a
dataset that is still a draft said the dataset "is not defined in this
environment" until the package published. `queryDataset` decided the
draft world only from the page URL's `?preview=draft`, and the Studio
canvas is a draft window that does not carry that flag, so its query
went to the published world, where a draft-only dataset does not exist.
The dataset pickers beside the canvas already read the draft-overlaid
catalog (#27518).
**`@object-ui/data-objectstack`: `queryDataset(dataset, selection,
options?)`.** A new optional `{ previewDrafts?: boolean }`. `true` puts
`previewDrafts: true` on the one dataset-query request, exactly what the
URL flag already put there; the server then resolves the dataset from
the draft overlay. It is the same explicit option `listViews(objectName,
{ previewDrafts })` takes. Absent, the page URL decides as before;
given, it wins over the URL. A caller that passes nothing sends a
byte-identical request.
**`@object-ui/app-shell`: the canvas data source.** `ReportPreview` and
`DashboardPreview` render through `useCanvasDataSource()` (new,
internal, `previews/canvasDataSource.ts`). In the Studio, keyed on the
signal the dataset pickers read (`StudioDatasetAuthoringContext`,
provided by the Interfaces pillar around the canvas), it hands the
runtime renderers the adapter with its `queryDataset` asking for
`previewDrafts`; every other member is the adapter's own, bound to it.
Outside the Studio (Setup's editors) it hands back the adapter
unchanged. The shape follows the Form tab preview's data source in
`StudioDesignSurface.tsx` (`formPreviewSource`): the preview hands the
runtime renderer a data source rather than threading a flag through
`plugin-report` and `plugin-dashboard`, so every dataset query those
renderers make (the report, a dataset widget, a dataset-bound chart, a
filter bar's options) carries it with no change in either plugin. One
source per adapter is kept in a module `WeakMap`, so its identity is the
adapter's and never a `useMemo` result (ui/AGENTS.md #10).
**The ruling.** "⛔ The canvas resolves draft datasets the same way the
draft preview resolves other draft metadata. It does not add a second
lookup." The draft preview resolves draft metadata with one
request-level flag the server honours (`?preview=draft` on `/meta`,
`previewDrafts` on the dataset query). The canvas now sends that same
flag on the same request. The dataset is still named and only the server
resolves it: no client-side read of the draft definition, no inline post
of it.
## Measurements (the order's mechanism assumptions)
- **(a) The server's dataset door honours the flag for a draft-only
dataset: yes (code read, not run live).**
`packages/rest/src/analytics-routes.ts`, the `POST
/analytics/dataset/query` handler: `previewDrafts` is
`body.previewDrafts === true` or `?preview=draft`, admitted only for a
caller `mayReadPendingDrafts` admits; the by-name lookup reads
`getMetaItems({ type: 'dataset', previewDrafts })`, the draft-overlaid
list in which draft-only items surface, then hands `previewDrafts` on to
`svc.queryDataset`. It is the one owner of that path in the tree. No
server file changes.
- **(b) The canvas's draft signal.** `useStudioDatasetAuthoring()`
(`studio-design/datasetCreate.tsx`), the context the Interfaces pillar
provides around both the inspector and the canvas.
`DashboardWidgetInspector` and `ReportDefaultInspector` read it to ask
`useDatasetCatalog` for `previewDrafts` since #27518; the canvas
previews now read the same one.
- **(c) The console runtime stays published.** `DashboardView` and
`ReportView` render with the plain adapter and pass no option, so
`queryDataset` still follows the page URL only: no flag on a runtime
page, the flag inside the app draft preview, as before.
## Tests
-
`ui/packages/app-shell/src/views/metadata-admin/previews/canvasDataSource-27585.test.tsx`
(new). Through the real `ObjectStackAdapter` (fetch stubbed) and the
real `plugin-report` / `plugin-dashboard` renderers. The stub server
answers the dataset by name only when the request carries
`previewDrafts: true`, and otherwise answers the door's own `404
NOT_FOUND`, which is what the door does for a draft-only dataset.
- In the Studio context, the report preview and the dashboard preview
post `{ datasetName: 'draft_sales', previewDrafts: true }` on every
dataset query and draw the draft's rows.
- Without the context, the same previews post no `previewDrafts` and
draw no rows.
- `datasetDraftsSource` is one source per adapter, binds every other
member to the adapter, and merges `previewDrafts` into a caller's own
options.
- `ui/packages/data-objectstack/src/queryDataset.test.ts`, new block
"the draft world (objectstack#27585)": the option with no URL flag sends
`previewDrafts: true`; neither sends nothing; the URL flag alone still
sends it; an explicit `previewDrafts: false` wins over the URL flag.
<details><summary>Targeted run, ablations and type-check (head 27e684e,
before the main merge)</summary>
- `pnpm --dir ui exec vitest run --reporter=verbose
packages/data-objectstack/src/queryDataset.test.ts
packages/app-shell/src/views/metadata-admin/previews/canvasDataSource-27585.test.tsx
packages/app-shell/src/views/metadata-admin/previews/ReportPreview.dataset.test.tsx
packages/app-shell/src/views/metadata-admin/previews/DashboardPreview.loneWidget.test.tsx
packages/app-shell/src/views/metadata-admin/previews/DashboardPreview.i18nTitle-10847.test.tsx`
· `VERDICT command-exit 0` · Test Files 5 passed (5) · Tests 56 passed
(56). The three existing preview test files are unchanged and green:
outside the Studio the previews call `queryDataset(name, selection)`
exactly as before.
- Ablation 1, through `scripts/ablation-replace.mjs`:
`canvasDataSource.ts` anchor `return inStudio && adapter` replaced with
a marker that always hands back the adapter (anchor 1 to 0, blob
a3c4bd4 to 3f04dfb10d35). The two Studio tests went red (Tests 2
failed, 3 passed); restored to blob a3c4bd4.
- Ablation 2: `index.ts` anchor `const previewDrafts =
options?.previewDrafts !== undefined` replaced with a marker that
ignores the option (blob a258fe1 to 36c53a39804e). Red: the two
option tests in `queryDataset.test.ts` and the two Studio tests (Tests 4
failed, 36 passed); restored to blob a258fe1.
- `pnpm --filter @object-ui/data-objectstack run type-check && pnpm
--filter @object-ui/app-shell run type-check` (the latter also compiles
the tests through `tsconfig.test.json`) · `VERDICT command-exit 0`.
- The ui vitest resolves `@object-ui/*` to `src`, so neither ablation
needed a dist build.
</details>
## Acceptance notes
- **Who gets drafts.** The server serves the draft world only to a
caller it admits to drafts (`mayReadPendingDrafts`); anyone else gets
the published dataset, as if the flag were absent. A Studio author is
admitted by construction.
- **Not in this PR, and not the same option.** The card's "related,
code-read only" note (Setup's dataset designer field catalog,
`useDatasetFields`, reading objects without the draft overlay) is a
metadata read, not a dataset query; this option does not reach it. Left
as the card noted it.
- **Overlap.** #27713 also edits
`ui/packages/data-objectstack/src/index.ts` (the record-page open
request, another region). This diff in that file is the `queryDataset`
docblock and its option only; whichever lands second rebases.
- **Assignee and reviewers.** None set by this PR's author, by the
dispatch rule: the seat asks once its review is in.
## Verification
<details><summary>Derived gates (dispatch-gates --commands, on the
merged head)</summary>
Head `41685152` (the main merge). Each line is the command and the exit
code captured before any pipe.
```text
node scripts/check-adr-0087-registration.mjs --base origin/main :: exit 0
node scripts/check-adr-0087-registration.mjs --self-test :: exit 0
node scripts/check-changeset-no-major.mjs --base origin/main :: exit 0
node scripts/check-closing-keyword-parity.mjs :: exit 0
node scripts/check-closing-keyword-parity.mjs --self-test :: exit 0
node scripts/check-comment-mask-corpus.mjs :: exit 0
node scripts/check-empty-changeset.mjs --base origin/main :: exit 0
node scripts/check-empty-changeset.mjs --self-test :: exit 0
node scripts/check-sdui-manifest.mjs :: exit 0
node scripts/check-sdui-manifest.mjs --self-test :: exit 0
node scripts/pm/release-rehearsal-clone.mjs --self-test :: exit 0
node scripts/release-pending-publish.mjs --self-test :: exit 0
pnpm --dir ui exec vitest run scripts/ :: exit 0
pnpm --filter @objectstack/spec run check:duration-unit-keys :: exit 0
pnpm check:changeset-gate-self-tests :: exit 0
pnpm check:closed-ceremony-text :: exit 0
pnpm check:cross-package-test-inputs :: exit 0
pnpm check:dispatcher-error-vocabulary :: exit 0
pnpm check:driver-memory-census :: exit 0
pnpm check:engine-double-contract :: exit 0
pnpm check:error-status-conformance :: exit 0
pnpm check:gitlink-declared :: exit 0
pnpm check:nul-bytes :: exit 0
pnpm check:pm-changeset-deadline-census :: exit 0
pnpm check:published-files :: exit 0
pnpm check:query-options-erasure :: exit 0
pnpm check:refd-timer-probe :: exit 0
pnpm check:skill-identifier-liveness :: exit 0
pnpm check:test-source-alias :: exit 0
pnpm check:tier-file-adoption :: exit 0
pnpm check:type-check-coverage :: exit 0
pnpm check:type-check-debt :: exit 0
pnpm check:undeclared-dep-imports :: exit 0
pnpm check:watch-hint-literal :: exit 0
pnpm check:where-matcher :: exit 0
```
`node scripts/pm/dispatch-gates.mjs --ran` reconciliation: 35 derived,
35 run, 0 NOT-MEASURED, 0 UNRUN.
After the merge, on the same head: the six dataset/preview test files
(the five above plus `queryDataset.forbidden-10899.test.ts`) · `VERDICT
command-exit 0` · Test Files 6 passed (6) · Tests 59 passed (59);
`eslint` over the six touched source and test files: 0 errors (the
warnings are pre-existing ones in the edited files; the two new files
carry none).
</details>
CI runs every other family on this PR; its check-runs are the record.
---
_Generated by [Claude
Code](https://claude.ai/code/session_01Utp6CYWA2yJcJwFWLpBa7Q)_
---------
Co-authored-by: Claude <noreply@anthropic.com>1 parent a7af1c1 commit 968cacf
7 files changed
Lines changed: 316 additions & 13 deletions
File tree
- .changeset
- ui/packages
- app-shell/src/views/metadata-admin/previews
- data-objectstack/src
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
7 | 7 | | |
8 | 8 | | |
9 | 9 | | |
10 | | - | |
| 10 | + | |
| 11 | + | |
11 | 12 | | |
12 | 13 | | |
13 | 14 | | |
| |||
18 | 19 | | |
19 | 20 | | |
20 | 21 | | |
21 | | - | |
| 22 | + | |
22 | 23 | | |
23 | 24 | | |
24 | 25 | | |
| |||
42 | 43 | | |
43 | 44 | | |
44 | 45 | | |
45 | | - | |
| 46 | + | |
46 | 47 | | |
47 | 48 | | |
48 | 49 | | |
| |||
194 | 195 | | |
195 | 196 | | |
196 | 197 | | |
197 | | - | |
| 198 | + | |
198 | 199 | | |
199 | 200 | | |
200 | 201 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
10 | 10 | | |
11 | 11 | | |
12 | 12 | | |
13 | | - | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
14 | 16 | | |
15 | 17 | | |
16 | 18 | | |
| |||
20 | 22 | | |
21 | 23 | | |
22 | 24 | | |
23 | | - | |
| 25 | + | |
24 | 26 | | |
25 | 27 | | |
26 | 28 | | |
| |||
30 | 32 | | |
31 | 33 | | |
32 | 34 | | |
33 | | - | |
| 35 | + | |
34 | 36 | | |
35 | 37 | | |
36 | 38 | | |
| |||
61 | 63 | | |
62 | 64 | | |
63 | 65 | | |
64 | | - | |
| 66 | + | |
65 | 67 | | |
66 | 68 | | |
67 | 69 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
| 38 | + | |
| 39 | + | |
| 40 | + | |
| 41 | + | |
| 42 | + | |
| 43 | + | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
| 47 | + | |
| 48 | + | |
| 49 | + | |
| 50 | + | |
| 51 | + | |
| 52 | + | |
| 53 | + | |
| 54 | + | |
| 55 | + | |
| 56 | + | |
| 57 | + | |
| 58 | + | |
| 59 | + | |
| 60 | + | |
| 61 | + | |
| 62 | + | |
| 63 | + | |
| 64 | + | |
| 65 | + | |
| 66 | + | |
| 67 | + | |
| 68 | + | |
| 69 | + | |
| 70 | + | |
| 71 | + | |
| 72 | + | |
| 73 | + | |
| 74 | + | |
| 75 | + | |
| 76 | + | |
| 77 | + | |
| 78 | + | |
| 79 | + | |
| 80 | + | |
| 81 | + | |
| 82 | + | |
| 83 | + | |
| 84 | + | |
| 85 | + | |
| 86 | + | |
| 87 | + | |
| 88 | + | |
| 89 | + | |
| 90 | + | |
| 91 | + | |
| 92 | + | |
| 93 | + | |
| 94 | + | |
| 95 | + | |
| 96 | + | |
| 97 | + | |
| 98 | + | |
| 99 | + | |
| 100 | + | |
| 101 | + | |
| 102 | + | |
| 103 | + | |
| 104 | + | |
| 105 | + | |
| 106 | + | |
| 107 | + | |
| 108 | + | |
| 109 | + | |
| 110 | + | |
| 111 | + | |
| 112 | + | |
| 113 | + | |
| 114 | + | |
| 115 | + | |
| 116 | + | |
| 117 | + | |
| 118 | + | |
| 119 | + | |
| 120 | + | |
| 121 | + | |
| 122 | + | |
| 123 | + | |
| 124 | + | |
| 125 | + | |
| 126 | + | |
| 127 | + | |
| 128 | + | |
| 129 | + | |
| 130 | + | |
| 131 | + | |
| 132 | + | |
| 133 | + | |
| 134 | + | |
| 135 | + | |
| 136 | + | |
| 137 | + | |
| 138 | + | |
| 139 | + | |
| 140 | + | |
| 141 | + | |
| 142 | + | |
| 143 | + | |
| 144 | + | |
| 145 | + | |
| 146 | + | |
| 147 | + | |
| 148 | + | |
| 149 | + | |
| 150 | + | |
| 151 | + | |
| 152 | + | |
| 153 | + | |
| 154 | + | |
| 155 | + | |
| 156 | + | |
| 157 | + | |
| 158 | + | |
| 159 | + | |
| 160 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
| 38 | + | |
| 39 | + | |
| 40 | + | |
| 41 | + | |
| 42 | + | |
| 43 | + | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
| 47 | + | |
| 48 | + | |
| 49 | + | |
| 50 | + | |
| 51 | + | |
| 52 | + | |
| 53 | + | |
| 54 | + | |
| 55 | + | |
| 56 | + | |
| 57 | + | |
| 58 | + | |
| 59 | + | |
| 60 | + | |
| 61 | + | |
| 62 | + | |
| 63 | + | |
| 64 | + | |
| 65 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
6809 | 6809 | | |
6810 | 6810 | | |
6811 | 6811 | | |
| 6812 | + | |
| 6813 | + | |
| 6814 | + | |
| 6815 | + | |
| 6816 | + | |
| 6817 | + | |
6812 | 6818 | | |
6813 | 6819 | | |
6814 | 6820 | | |
6815 | 6821 | | |
| 6822 | + | |
6816 | 6823 | | |
6817 | 6824 | | |
6818 | 6825 | | |
| |||
6873 | 6880 | | |
6874 | 6881 | | |
6875 | 6882 | | |
6876 | | - | |
6877 | | - | |
6878 | | - | |
6879 | | - | |
| 6883 | + | |
| 6884 | + | |
| 6885 | + | |
| 6886 | + | |
| 6887 | + | |
| 6888 | + | |
6880 | 6889 | | |
6881 | 6890 | | |
6882 | 6891 | | |
| |||
0 commit comments