Repository navigation
Commit 3fd0ba1
fix(app-shell): creating an item or opening one from Pending changes asks before it drops a held Studio edit (#26927)
<!-- claude-projects-attribution: {"github_login":"os-warren"} -->
_Requested by **Warren** · [project
thread](https://claude.ai/code/project/chan_01U5RdnAAmkSQmZbqh6FtqZ8?thread=cmsg_01U5RdnAAmkSQmZbqh6FtqZ8KPvkcu6BzA4jz9XAcq4ErH)_
Fixes #26845
Clause-②: no
Metadata-protocol: none
## 维护者速读
- 改了什么:Studio 的 Data、Automations、Interfaces
支柱有暂存未发的编辑时,点「新建对象/流程/仪表盘等」会先弹出同一句离开确认;从 Pending changes
里打开同一支柱的另一个对象也先问。取消则对话框不打开、暂存编辑保留。
- 为什么改:#26839 只拦了离开支柱、左侧栏切换和刷新;新建和 Pending changes
跳转同样会换掉暂存所在的缓冲区,之前一点就静默丢失。分诊裁决是「两条路径都走同一个离开守卫」。
- 风险与回滚:只多问一句,复用 `confirmDropUnsavedWork` 与原有文案,不改保存、发布和暂存判定。有问题直接
revert 本 PR。
- 先看:`StudioDesignSurface.tsx` 中 DataPillar 挪到 `objHeld` 之后的 live
request
effect(唯一的行为改动点),然后三处新建入口(`openCreate`、`openCreateObject`、`openCreateFlow`),最后
`StudioDesignSurface.heldDataCreate-26845.test.tsx`。
- 两分钟验证:`pnpm --dir ui exec vitest run
packages/app-shell/src/views/studio-design/StudioDesignSurface.heldDataCreate-26845.test.tsx`,预期
3 个测试全绿。
- 需要你做的:无,席位落地。
## What changes
Base `94e29cd1`. One shared guard, now read by the two departures #26705
left open:
- **Create while held.** Each pillar asks `confirmDropUnsavedWork`
before its New dialog opens, because a created object, flow or
Interfaces item is opened at once (`setCurrent` in `doCreateObject`,
`doCreateFlow` and `doCreateSurface`), and that load replaces the one
buffer the held edit lives in. Asking before the dialog means a decline
costs nothing and the create itself never asks again.
- Interfaces: `openCreate` (the "+" menu's New dashboard / report /
page) reads `leafHeld`.
- Data: a new `openCreateObject`, declared below `objHeld`, wraps
`openCreateDialog` for the rail's New and the empty state's New (the
empty state can hold nothing; it goes through the same door so every
create asks the same way).
- Automations: `openCreateFlow` reads `flowHeld`.
- **Same-pillar Pending changes request.** Measured: the Data pillar is
the only subscriber of the live surface channel (`useRequestedSurface`),
and the sheet's security block is the only producer, so a same-pillar
request is always an object request applied by the Data pillar. Its
apply effect moves below `objHeld` and asks, like the rail, only when
the requested object is not the open one. Declined, the request id is
spent (as before, at most once) and the held edit stays. A request for
the open object asks nothing.
- **Cross-pillar request:** unchanged. `requestSurface` already asks
through `confirmLeavePillar` (which reads `heldEdit` since #26839) and
vetoes on a decline; the Data pillar it lands on holds nothing, so its
apply asks nothing more. Pinned below, not changed.
- Unchanged by design: how a held edit is judged and saved, Publish
gating, and the question's wording (`engine.edit.unsavedLeaveConfirm`,
no new i18n key). The Access pillar is not touched.
## Why
Triage first grade on the card, verbatim: "**p2, the remainder of
#26705** (PR #26839): two more departures still drop a held pillar edit
without asking: creating a new object, flow or Interfaces item, and
opening another item from Pending changes. Route both through the same
departure guard."
## Tests
Three new files, one per pillar, each through the real
`StudioDesignSurface` on the real route shape, with the held edit
produced as #26839's files produce it (a Picklist with no option, a
Notify step with no Title, a Metric widget with no dataset). The Data
and Automations files replace the mocked Pending changes sheet with a
stand-in that asks the host for an object through `useSurfaceNavigator`,
as the sheet's security block does.
- `StudioDesignSurface.heldDataCreate-26845.test.tsx` (3): New object
asks, Cancel opens no dialog and keeps the held field, OK opens the
dialog and the create (Ticket, stored as `acme_ticket`) asks nothing
more; a Pending changes request for another object asks, Cancel keeps
the held field, a request for the open object asks nothing, OK opens the
other object; CONTROL with nothing held, New object and a request never
ask.
- `StudioDesignSurface.heldFlowCreate-26845.test.tsx` (3): New flow
asks, Cancel opens no dialog and keeps the held step, OK opens the
dialog; a cross-pillar request (an object, from Automations while a step
is held) asks exactly once, Cancel stays on Automations with the held
step, OK opens the Data pillar on that object with no second ask;
CONTROL with nothing held.
- `StudioDesignSurface.heldWidgetCreate-26845.test.tsx` (2): New
dashboard asks, Cancel opens no dialog and keeps the held widget, OK
opens the dialog; CONTROL with nothing held.
<details><summary>Runs (head 3a6924e)</summary>
- New files: 3 files, 8/8 passed (lock VERDICT command-exit 0; tests
3.64 s of wall in total).
- Every test file under `ui/packages` that imports
`StudioDesignSurface`, `DataPillar`, `AutomationsPillar` or
`InterfacesPillar` (161 files, `DataPillar.surfaceRequest.test.tsx` and
the three #26839 files among them): 161/161 files, 1179/1179 tests
passed, lock VERDICT command-exit 0.
- `pnpm --filter @object-ui/app-shell run type-check` (both projects,
tests included): exit 0.
- eslint on the four files: 0 errors; `StudioDesignSurface.tsx` carries
16 warnings, as on the base (the moved effect's `set-state-in-effect`
warning moves with it; the count is unchanged), the three tests none.
</details>
<details><summary>Ablation (one-shot, through
scripts/ablation-replace.mjs --delete; each leg restored to the HEAD
blob with an empty git diff HEAD)</summary>
- Leg 1, drop the Interfaces create guard (`leafHeld`):
`heldWidgetCreate` 1 of 2 red, the create case only.
- Leg 2, drop the Data create guard (`openCreateObject`):
`heldDataCreate` 1 of 3 red, the New object case only.
- Leg 3, drop the Data request guard (in the apply effect):
`heldDataCreate` 1 of 3 red, the Pending changes case only.
- Leg 4, drop the Automations create guard (`flowHeld`):
`heldFlowCreate` 1 of 3 red, the New flow case only. Its cross-pillar
case pins the existing surface guard and stays green, as intended.
</details>
## Acceptance notes
- The Interfaces "+" menu's other kinds (link, group, and the rest) add
a nav entry and open nav editing without changing the open leaf, so they
do not replace the leaf buffer and are not guarded here.
- Only the Data pillar applies a same-pillar live request today; the
Automations and Access pillars do not subscribe to the channel, so a
same-pillar request there opens nothing and drops nothing.
- `origin/main` gained `57820085` (#26856, metadata-protocol only) after
the base; it touches none of these files or the derived gate inputs, so
it was not merged in.
- `@object-ui/app-shell` is `private: true`, so no changeset.
## Verification
Gates derived by `node scripts/pm/dispatch-gates.mjs --commands --repo
objectstack-ai/objectstack` at `3a6924e3`: 24 families, all exit 0,
reconciled with `--ran` (24 run, 0 NOT-MEASURED, 0 UNRUN). `pnpm --dir
ui exec vitest run scripts/` first queued out of the lock (exit 99, not
run) while the 161-file run held it, then ran in full under the same
slot: 178 files passed, 2 skipped, exit 0. `pnpm
check:new-line-citations` (ui): 0 new citations.
## Human Minimum
- [x] 1. Schemas start as Zod; `packages/spec` holds no runtime logic.
(Not touched.)
- [x] 2. Every name I added uses the casing for its kind.
- [x] 3. No formatter ran; `pnpm lint` passes. (eslint on the four
files: 0 errors.)
- [x] 4. One issue, one branch off an up-to-date `main`, one pull
request.
- [x] 5. A change that publishes carries a changeset, and both
declaration lines are filled in here and in the changeset. (Publishes
nothing: `@object-ui/app-shell` is private.)
- [x] 6. `packages/spec` touched: its generated artifacts are
regenerated and committed. (Not touched.)
- [x] 7. No hand edits to `content/docs/references/`,
`packages/*/CHANGELOG.md` or `content/docs/releases/`.
- [x] 8. Title, body and comments are in English, apart from the
maintainer brief above.
- [x] The *Before Submitting* list in CONTRIBUTING.md is done.
---
_Generated by [Claude
Code](https://claude.ai/code/session_01JQwxbZTZSxa584VWULEuMZ)_
---------
Co-authored-by: Claude <noreply@anthropic.com>1 parent 216a39e commit 3fd0ba1
4 files changed
Lines changed: 744 additions & 15 deletions
File tree
- ui/packages/app-shell/src/views/studio-design
| 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 | + | |
| 161 | + | |
| 162 | + | |
| 163 | + | |
| 164 | + | |
| 165 | + | |
| 166 | + | |
| 167 | + | |
| 168 | + | |
| 169 | + | |
| 170 | + | |
| 171 | + | |
| 172 | + | |
| 173 | + | |
| 174 | + | |
| 175 | + | |
| 176 | + | |
| 177 | + | |
| 178 | + | |
| 179 | + | |
| 180 | + | |
| 181 | + | |
| 182 | + | |
| 183 | + | |
| 184 | + | |
| 185 | + | |
| 186 | + | |
| 187 | + | |
| 188 | + | |
| 189 | + | |
| 190 | + | |
| 191 | + | |
| 192 | + | |
| 193 | + | |
| 194 | + | |
| 195 | + | |
| 196 | + | |
| 197 | + | |
| 198 | + | |
| 199 | + | |
| 200 | + | |
| 201 | + | |
| 202 | + | |
| 203 | + | |
| 204 | + | |
| 205 | + | |
| 206 | + | |
| 207 | + | |
| 208 | + | |
| 209 | + | |
| 210 | + | |
| 211 | + | |
| 212 | + | |
| 213 | + | |
| 214 | + | |
| 215 | + | |
| 216 | + | |
| 217 | + | |
| 218 | + | |
| 219 | + | |
| 220 | + | |
| 221 | + | |
| 222 | + | |
| 223 | + | |
| 224 | + | |
| 225 | + | |
| 226 | + | |
| 227 | + | |
| 228 | + | |
| 229 | + | |
| 230 | + | |
| 231 | + | |
| 232 | + | |
| 233 | + | |
| 234 | + | |
| 235 | + | |
| 236 | + | |
| 237 | + | |
0 commit comments