Repository navigation
Commit 4831d50
fix(console): save a language picked on the register page as the new person's own when they have none (#30597)
<!-- claude-projects-attribution: {"github_login":"os-sales"} -->
_Requested by **Sales** · [project
thread](https://claude.ai/code/project/chan_01D5bWFY3rFzgJcytD5gD4Uu?thread=cmsg_01D5bWFY3rFzgJcytD5gD4UuTbUduB1ABMv1ARhxiJJCEa)_
Fixes #30338
domain:ui#1 · os-sales · session_01L6bhgWn6zhNa4LL7VB1rtL
## 维护者速读
-
改了什么:在注册页底部选了语言、本人还没设过语言偏好的,注册即登录时这个选择会存成本人的语言偏好(`sys_user.locale`),和登录页(#30399)一样;从邀请链接注册加入组织也一样。
- 为什么改:#30399 只改了登录页;注册页同样靠整页跳转离开,跳转前没人写库,选的语言只留在这台浏览器上。
- 风险与回滚:只有注册页选过语言才多发两次请求(读一次本人记录、写一次),已有偏好不改,没选不发不等,写失败照常进入。回滚即撤本 PR。
- 先看:console `RegisterPage.tsx` 注册后 effect 新增的第 0 步;app-shell
`RegisterPage.tsx` 的 `holdForSignInPick`。
- 两分钟验证:`pnpm --dir ui exec vitest run
apps/console/src/pages/auth/__tests__/registerLanguagePick-30338.test.tsx
packages/app-shell/src/console/auth/__tests__/registerLanguagePick-30338.test.tsx`,预期
25 passed。
- 需要你做的:无,席位落地。
Clause-②: no
Metadata-protocol: none
## What changes
- `ui/apps/console/src/pages/auth/RegisterPage.tsx`, the post-signup
orchestration effect only: a new step 0, the same as `LoginPage`'s
(#30539). When a language was picked on the page while signed out, it
starts app-shell's `saveSignInLanguagePick` once (ref latch), holds the
spinner, and re-runs the effect when the save settles (state). The steps
after it are unchanged, so every exit waits:
| Exit | Line on `main` | Waits |
|---|---|---|
| OAuth provider hand-off (`followOauthAuthorize`) | L194 | yes (step 0
sits above it, as on `/login`) |
| Mobile sign-in hand-off | L206 | yes; a session the hand-off refuses
for its age saves nothing |
| Invitation join entered (#30125) | L218 | yes; the acceptance runs
meanwhile |
| No organization | L233 | yes |
| Several organizations | L236 | yes |
| Final redirect after the single-org auto-select | L241 | yes |
- `ui/packages/app-shell/src/console/auth/RegisterPage.tsx`
(`DefaultRegisterPage`): this page draws no language menu, so a pick
reaches it only from another signed-out page earlier in the same
page-load. Once someone is signed in and a pick is held, the page starts
the save once and renders its empty layout until it settles
(`holdForSignInPick`, from state plus `hasSignInLanguagePick()`, so the
render that first sees the user already holds). That covers its three
ways out: the invitation join's `window.location.assign` to the root
(L132), the signed-in branch's `Navigate` to `/`, and the form's
`onSuccess` `navigate('/')` (L271), which now leaves the move to the
signed-in branch when a pick is held or its save has started.
- Imports only: `hasSignInLanguagePick` / `saveSignInLanguagePick` as
#30539 landed them. No new export, no new storage key, nothing sent
beside a navigation.
## Why
Measured on `origin/main` `27b0bc79`: neither register page called
`saveSignInLanguagePick`, and both leave by navigation after a sign-up
that signs the person in, so a pick made there stayed in the device slot
only. This is the remainder recorded in the `domain:ui#4` ACCEPT on
#30539 ("`RegisterPage.tsx` 同形") and claimed in 6663446873.
## Acceptance notes
- **Bound, as ruled (seat ruling D on this card, carried by the
claim):** memory lasts one page-load. A pick followed by a reload of the
register page, or by an identity provider round trip, is still not
saved. No storage marker was added to change that.
- **No timeout on the save**, the same as `/login`: a hanging request
keeps the spinner up as long as the adapter's own fetch does.
- **Write census:** no new adapter write call site. The pages call
`saveSignInLanguagePick`, whose own `update` is already registered in
`affordanceGrantMap-12082.test.tsx` (`outOfFamily`), and that function
is not a census write helper. The census test ran green unchanged.
- **Observed, not this card's:** with no pick and several organizations,
the post-signup step navigates to the root before the organization list
answers, then again to the picker, the same double navigation #30539
noted on `/login`. The CONTROL pins assert only that the page leaves and
saves nothing.
- Untouched: `LoginPage.tsx`, `useUserLocale.ts`, `loadLocales.ts`'s
signed-out list, `packages/**`.
- Branch `claude/project-thread-b4xtgz` is the card thread's
platform-assigned branch (not `claude/issue-30338-*`).
## Tests
-
`ui/apps/console/src/pages/auth/__tests__/registerLanguagePick-30338.test.tsx`
(new, 19 cases, each reached by a sign-up on the form): for each of the
six exits, nothing leaves while the save is in flight and the expected
exit is taken once it settles; the invitation join accepts its
invitation and still waits; CONTROL for each exit with no pick; for each
exit, a save that settles having failed still lets the page leave.
-
`ui/packages/app-shell/src/console/auth/__tests__/registerLanguagePick-30338.test.tsx`
(new, 6 cases): sign-up to `/` and invitation join to the root each wait
for the save; CONTROL for both with no pick; a failed save still moves
on, both ways.
<details><summary>vitest: both new files, every console and app-shell
auth page test, the sign-in pick hook file and the write census (head
e15bb2e)</summary>
```
pnpm exec vitest run --maxWorkers=2 apps/console/src/pages/auth/ packages/app-shell/src/console/auth/ packages/app-shell/src/hooks/__tests__/userLocaleSignInPick-30338.test.tsx packages/plugin-form/src/affordanceGrantMap-12082.test.tsx
Test Files 47 passed (47)
Tests 404 passed (404)
exit 0
```
</details>
<details><summary>Ablations (each through scripts/ablation-replace.mjs,
mutation proven on disk, restored: blob == HEAD, git diff HEAD
empty)</summary>
```
A1 console RegisterPage: drop step 0's return (the save starts, the first effect run goes on to the exit)
registerLanguagePick-30338 (console): 8 failed | 11 passed (19), exit 1
red: the five non-invitation "waits" cases and three "failed save" cases; green: CONTROLs and both invitation cases
(a later effect run still meets the 'saving' guard, so the invitation exit stays held: hence A1b)
A1b console RegisterPage: delete the "save in flight" guard line
registerLanguagePick-30338 (console): 4 failed | 15 passed (19), exit 1
red: several organizations, one organization, both invitation cases
A2 app-shell RegisterPage: holdForSignInPick forced false
registerLanguagePick-30338 (app-shell): 2 failed | 4 passed (6), exit 1
red: both "waits" cases; green: CONTROLs and both failed-save cases
```
Together every exit has a waits case that goes red when the wait is
removed.
</details>
<details><summary>Type check</summary>
```
pnpm --filter @object-ui/app-shell type-check (tsc --noEmit && tsc -p tsconfig.test.json) exit 0
ui/apps/console: NODE_OPTIONS=--max-old-space-size=6144 tsc --noEmit exit 0
eslint on the four changed files: 0 errors; 2 warnings, both present on main (setState in effect, L145 and L258)
```
</details>
## Verification
Live: showcase `pnpm dev -- --fresh` (invite_only) plus the console on
vite, Playwright `zh-CN`, 1440 wide. The seeded admin invites a fresh
address; the invitee opens the link signed out, follows "注册并加入", picks
Français in the register page's footer menu, registers, and lands in the
app. Then, from the invitee's own session: `sys_user.locale`, the device
slot, the document's `lang` attribute. Before = this head with the
console `RegisterPage.tsx` restored from `27b0bc79` (vite reads source),
put back from HEAD after (`git status` clean). Script and screenshots:
project files `issue-30338/`.
| Row | Picked | Landed | `sys_user.locale` | Slot | `lang` |
|---|---|---|---|---|---|
| before | Français | app, joined | empty | fr | fr |
| after | Français | app, joined | **fr** | fr | fr |
| after, CONTROL | nothing | app, joined | empty, no `PATCH` sent |
empty | zh-CN |
Requests in the after row, in order: `POST sign-up/email`, `GET
get-invitation`, `POST accept-invitation`, `POST set-active`, and on the
data side `GET discovery`, `GET sys_user/ID`, `PATCH sys_user/ID`, then
the next page-load's `GET discovery`.
<details><summary>Gates (head e15bb2e)</summary>
`node scripts/pm/dispatch-gates.mjs --commands --repo
objectstack-ai/objectstack` derived 35; all 35 exit 0, codes captured
before any pipe (`pnpm --dir ui exec vitest run scripts/`: 170 passed, 2
skipped files). `dispatch-gates --ran`: 35 derived, 35 run, 0
NOT-MEASURED (a derived zero). Changed lines 619, under the 3000
threshold.
</details>
🤖 Generated with [Claude Code](https://claude.com/claude-code)
https://claude.ai/code/session_01L6bhgUaeNktxjHB4qxqPKg
---
_Generated by [Claude
Code](https://claude.ai/code/session_01L6bhgUaeNktxjHB4qxqPKg)_
---------
Co-authored-by: Claude <noreply@anthropic.com>1 parent 08e0247 commit 4831d50
5 files changed
Lines changed: 614 additions & 5 deletions
File tree
- .changeset
- ui
- apps/console/src/pages/auth
- __tests__
- packages/app-shell/src/console/auth
- __tests__
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
38 | 38 | | |
39 | 39 | | |
40 | 40 | | |
| 41 | + | |
| 42 | + | |
| 43 | + | |
41 | 44 | | |
42 | 45 | | |
43 | 46 | | |
| |||
57 | 60 | | |
58 | 61 | | |
59 | 62 | | |
| 63 | + | |
| 64 | + | |
60 | 65 | | |
61 | 66 | | |
62 | 67 | | |
| |||
124 | 129 | | |
125 | 130 | | |
126 | 131 | | |
| 132 | + | |
| 133 | + | |
| 134 | + | |
| 135 | + | |
| 136 | + | |
| 137 | + | |
127 | 138 | | |
128 | 139 | | |
129 | 140 | | |
| |||
186 | 197 | | |
187 | 198 | | |
188 | 199 | | |
| 200 | + | |
| 201 | + | |
| 202 | + | |
| 203 | + | |
| 204 | + | |
| 205 | + | |
| 206 | + | |
| 207 | + | |
| 208 | + | |
| 209 | + | |
| 210 | + | |
| 211 | + | |
| 212 | + | |
| 213 | + | |
| 214 | + | |
| 215 | + | |
| 216 | + | |
| 217 | + | |
| 218 | + | |
| 219 | + | |
| 220 | + | |
189 | 221 | | |
190 | 222 | | |
191 | 223 | | |
| |||
250 | 282 | | |
251 | 283 | | |
252 | 284 | | |
| 285 | + | |
253 | 286 | | |
254 | 287 | | |
255 | 288 | | |
| |||
| 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 | + | |
| 238 | + | |
| 239 | + | |
| 240 | + | |
| 241 | + | |
| 242 | + | |
| 243 | + | |
| 244 | + | |
| 245 | + | |
| 246 | + | |
| 247 | + | |
| 248 | + | |
| 249 | + | |
| 250 | + | |
| 251 | + | |
| 252 | + | |
| 253 | + | |
| 254 | + | |
| 255 | + | |
| 256 | + | |
| 257 | + | |
| 258 | + | |
| 259 | + | |
| 260 | + | |
| 261 | + | |
| 262 | + | |
| 263 | + | |
| 264 | + | |
| 265 | + | |
| 266 | + | |
| 267 | + | |
| 268 | + | |
| 269 | + | |
| 270 | + | |
| 271 | + | |
| 272 | + | |
| 273 | + | |
| 274 | + | |
| 275 | + | |
| 276 | + | |
| 277 | + | |
| 278 | + | |
| 279 | + | |
| 280 | + | |
| 281 | + | |
| 282 | + | |
| 283 | + | |
| 284 | + | |
| 285 | + | |
| 286 | + | |
| 287 | + | |
| 288 | + | |
| 289 | + | |
| 290 | + | |
| 291 | + | |
| 292 | + | |
| 293 | + | |
| 294 | + | |
| 295 | + | |
| 296 | + | |
| 297 | + | |
| 298 | + | |
| 299 | + | |
| 300 | + | |
| 301 | + | |
| 302 | + | |
| 303 | + | |
0 commit comments