Skip to content

feat(console): an administrator's first-run checklist on Home replaces the currency and time zone dialog - #30552

Draft
objectstack-fleet[bot] wants to merge 8 commits into
mainfrom
claude/project-thread-5murn7
Draft

objectstack-fleet[bot] wants to merge 8 commits into
mainfrom
claude/project-thread-5murn7

Conversation

@objectstack-fleet

Copy link
Copy Markdown
Contributor

Requested by Sales · project thread

Fixes #30206

Clause-②: yes (widening) — new console i18n keys console.firstRunChecklist.* and console.settingsView.invalidFormat / .invalidFormatHelp / .invalidFormatPick (all ten packs); the retired console.workspaceTimezonePrompt.* keys had no reader outside the removed dialog
Metadata-protocol: none

维护者速读

  • 改了什么:管理员首次打开首页(/home)时,顶部出现一张「完成初始设置」清单,原来一进系统就弹出的时区/货币对话框删掉了;在默认国家里输入「中国」现在能保存为 CN,格式错误的提示也改成读者语言。
  • 为什么改:维护者原话「目前启动时就弹出选择货币很奇怪」;新部署的管理员不知道先设什么,默认语言、国家和货币还互相矛盾。
  • 风险与回滚:只动控制台和语言包,不动服务端;清单只读设置,只有点「确认」才写,写的就是设置页同一个 PUT。回滚即 revert 本 PR,弹窗回来。
  • 先看:ui/apps/console/src/pages/settings/FirstRunChecklist.tsx(读取与只在确认时写入)、firstRunChecklistLogic.ts(每行何时算完成)、SettingsField.tsx 的 optionByName(输入名称匹配代码)。
  • 两分钟验证:os dev --fresh 后用管理员登录,打开 /home,顶部应有清单;中文浏览器下点「默认语言和国家/地区」的「设置」,在国家框输入「中国」后点「确认」,应提示已保存、该行打勾,Setup 页不再弹任何对话框。
  • 需要你做的:无,席位落地。

What changes

The dialog is gone; Home carries an administrator's first-run checklist. WorkspaceTimezonePrompt.tsx and its mount in AppContent.tsx are removed. FirstRunChecklist is drawn at the top of Home by the console's Home route (App.tsx), above the page's own sections, inside the ConsolePermissionsScope that route already sits under. Its logic, firstRunChecklistLogic.ts, is the dialog's logic widened to every row (git shows it as a delete and an add; it keeps browserTimeZone, browserLanguage, browserCurrency, isAdmissibleValue and mayWrite).

Proposed row list (the card leaves it to the PR). Each row's state is read from the real setting every time it is drawn, never from a click:

# Row Done when Action
1 Organization name the active organization's name is no longer Default Organization, the name plugin-auth gives it (#30125 row 1) link to Setup → Organization record
2 Default language and country localization.locale and .default_country both resolve from a rung other than the manifest default edit in place, pre-filled from the browser
3 System timezone localization.timezone resolves from a rung other than the default edit in place, pre-filled with the browser zone
4 Default currency localization.currency holds any value (it has no platform default) edit in place, pre-filled with the browser region's currency
5 Email delivery mail.provider is not log, from_email is set, and SMTP has smtp_host; shown only to a session that may write mail link to Setup → Mail Delivery
6 Invite colleagues a second member or a pending invitation link to Setup → Users (Invite User)

A done row shows its value; a row whose state cannot be read (mail unreadable, members unreadable) is left out rather than shown as not done. Once every row shown is done the checklist draws nothing, and it comes back on its own if a setting is unset again.

The rulings the dialog was built on still hold (objectui#11693 B2, #28872). The browser only pre-fills rows 2 to 4. Nothing is written until the row's Confirm, which is saveSettingsNamespace('localization', changes), the Settings page's own PUT /api/settings/localization. Cancel writes nothing. An unset currency stays on the list until it is set. Language, country and currency are one offer read from the browser's first language (zh-CN → 中文, CN, CNY), so they cannot contradict each other.

Who sees it. A session that may write localization (its manifest's writePermission, failing closed on an unreported answer). A member sees nothing and sends one GET /api/settings (the list, which never refuses) and no namespace read. The close button hides it for that administrator, in that workspace, on that device (localStorage os:first-run-checklist:ORG:USER); nothing is written to the server and no row changes. Its reads wait for the console's first paint (whenBootPainted, objectui#12980), as the dialog's did.

「中国」 in 默认国家. The refusal started in the console: DomainCombobox swapped typed text for a code only when it equalled the option label (「中国 (CN)」) or the code, so 「中国」 went to the server as typed, and the server's ^[A-Za-z]{2}$ pattern refused it with invalid_format in English. Now a typed name that exactly one option carries (the label without its own code beside it, trimmed, case-insensitive) is committed as that option's code; any other text is still committed verbatim and the server stays the judge. A refusal with code: 'invalid_format' is now drawn in the console's words and the reader's language, naming the setting by the label its row draws (settingsFieldRefusals.ts): "Choose a value for Default country from the list." for a picker, and "Gateway model is not in a valid format. Use provider/model." for a typed field, repeating the field's own help line because the refusal takes its place. Every other refusal code keeps the server's sentence. The server's pattern check is unchanged (⛔ packages/**).

Files beyond the claim's named surface, each a reader of what was removed: ui/apps/console/src/pages/auth/SetupPage.tsx (imports browserTimeZone from the renamed module), ui/apps/console/src/loadLocales.ts (comment), the four console tests that mocked the dialog's module, ui/e2e/live/global-setup.ts (it waited up to 60 s for the dialog's testid before every live run; the checklist is not modal, so that step is removed), docs/qa/platform-checklist/RUNNER.md (told QA runners to dismiss the dialog), and three i18n pins that named the dialog's keys or file (machineLocaleCensus-9909, console-copy-system-noun-12956) or count the de pack's quotes (de-quote-pairing-3876, 104 → 106 for two new „…“ pairs).

Tests

  • ui/apps/console/src/pages/settings/__tests__/FirstRunChecklist.test.tsx (10), on the real api.ts against a stubbed fetch and the real MePermissionsProvider: a member reads the list only and sees nothing; no capability answer or an empty one sends no request; a fresh workspace shows all six rows not done with their links and writes nothing; rows the server reports as set are done and a fully set workspace draws nothing; Set pre-fills the currency from the browser, nothing is written until Confirm, and Confirm sends exactly one PUT with { currency: 'CNY' }; language and country are one offer ({ locale: 'zh-CN', default_country: 'CN' }); Cancel and the close button write nothing and the hide survives a remount with no request; an invalid_format refusal is shown in the console's words and the row stays not done; zh copy; no read while the boot splash is up.
  • firstRunChecklistLogic.test.ts (11): localeOffer, browserRegion, the admissible pre-fill, isKeySet, row done, isMailConfigured, isOrganizationNamed, hasInvitedColleagues, the dismissal record and unreadable storage.
  • SettingsField.domainOptionTypedName-30206.test.tsx (5): 「中国」 commits CN; trimmed and case-insensitive with full-width brackets; a name two options carry and part of a name stay verbatim; a currency name commits its code.
  • settingsFieldRefusals-30206.test.ts (5), against the shipped en templates.
  • Updated: SettingsView.field-errors, SettingsView.crypto-unavailable and SettingsView.refusalToast-13146 asserted the server's English sentence for invalid_format; they now assert the console's sentence (and that the server's is gone).
  • Removed with the dialog: WorkspaceTimezonePrompt.test.tsx, .currency-28872.test.tsx, .afterBootPaint-12980.test.tsx; their pins (only Confirm writes, the browser zone pre-fill, the currency arm, the boot-paint wait, members never asked) are carried by the new files above.

Acceptance notes

  • Placement. Home is the environment's own home (ObjectUI ADR-0075) and every deployment that declares no landing app opens there after sign-in. A deployment whose app declares isDefault lands its administrator in that app, and the checklist is then seen on the next visit to Home, not at sign-in. The card allowed "the home page or the top of Setup"; drawing it at the top of Setup too would be an app-shell change and is left for the seat to call.
  • DEFAULT_ORGANIZATION_NAME is a copy of plugin-auth's literal (ensure-default-organization.ts). No test holds the two equal: a ui/ test reading packages/** source would be a cross-package input outside both CI rosters. A rename on the server side would make row 1 read "named" for an organization nobody named.
  • Refusal codes other than invalid_format (for example value_domain) still carry the server's English sentence; localizing FieldError.message is a server concern and out of this card.
  • The dialog's old "asked once" record (os:workspace-timezone-prompt:*) is no longer read; it stays in browsers that have it, harmlessly.
  • packages/plugins/plugin-auth/src/dev-admin-seed-workspace-timezone.test.ts still describes the dialog in its doc comment (the condition it pins is still the one row 3 reads). Left alone: ⛔ packages/** on this card.
  • objectui#11693 is outside this session's repository scope; its ruling B2 is quoted from the code comments that carried it.
  • The branch name is the card thread's platform-assigned claude/project-thread-5murn7, not claude/issue-30206-….
  • First-run flow: small frictions a new deployment's first people meet #30125 rows 1 and 3 are covered here, as the card says.

Verification

All readings on head 9914c31f, unless a line names another.

Live: before on main, after on the branch (showcase os dev --fresh, console dev server, 1440 wide, zh and en)
  • Before, on main fa9c0aa2: entering Setup opened the currency dialog over the page, zh and en (before-setup-dialog-zh-1440.png, before-setup-dialog-en-1440.png).
  • After, zh browser (zh-CN, Asia/Shanghai): /home shows the checklist, rows organization_name=false language_country=false timezone=true currency=false mail=false invite=true, progress 已完成 2/6 (the rig's dev seed sets the zone and seeds members). Opening 默认语言和国家/地区 pre-fills 简体中文 and 中国 (CN). Clearing the country box and typing 「中国」 leaves 中国 (CN) in the box; Confirm sent exactly one write, PUT /api/settings/localization {"locale":"zh-CN","default_country":"CN"}, answered 200, and the row turned done (简体中文、中国 (CN)), progress 已完成 3/6. /apps/setup afterwards: 0 dialogs.
  • After, en browser (en-US, America/New_York): 3 of 6 done; opening Default currency pre-fills USD — US Dollar and sends no write; /apps/setup: 0 dialogs.
  • Screenshots (project files issue-30206/): after-1-home-zh-CN-1440.png, after-2-editor-zh-CN-1440.png, after-3-saved-zh-CN-1440.png, after-4-setup-zh-CN-1440.png, after-1-home-en-US-1440.png, after-2-editor-en-US-1440.png, after-4-setup-en-US-1440.png.
Tests and type-check
  • pnpm exec vitest run apps/console/ (ui root, head 3bcfe085 tree): Test Files 299 passed (299), Tests 2931 passed (2931).
  • On 9914c31f: pnpm exec vitest run apps/console/src/pages/settings/ apps/console/src/__tests__/ apps/console/src/components/FormPage.routePermissions-29187.test.tsx apps/console/src/pages/auth/: Test Files 133 passed (133), Tests 1504 passed (1504).
  • pnpm exec vitest run packages/i18n/: Test Files 95 passed (95), Tests 1443 passed, 13 skipped.
  • pnpm --filter @object-ui/console type-check exit 0 (after pnpm --filter @object-ui/i18n build; the console reads the i18n package's built types), pnpm --filter @object-ui/i18n type-check exit 0, pnpm run type-check:e2e exit 0.
  • eslint on the changed console files: 0 errors (the warnings are on lines this PR does not touch).
Ablations (each through scripts/ablation-replace.mjs, restored to the HEAD blob with git diff HEAD empty)
  • SettingsField.tsx name match removed (?? optionByName(options, text)?.value): SettingsField.domainOptionTypedName-30206 3 failed, 2 passed (the two verbatim cases stay green, as they should).
  • settingsFieldRefusals.ts re-wording disabled (every code keeps the server sentence): 7 failed across settingsFieldRefusals-30206, FirstRunChecklist and SettingsView.field-errors.
  • mayWrite no longer reads the manifest's writePermission: FirstRunChecklist "a member … nothing is drawn" fails, 1 of 10.
  • isKeySet no longer reads source: 7 failed across FirstRunChecklist and firstRunChecklistLogic.
Derived gates: node scripts/pm/dispatch-gates.mjs --commands (42) and --ran
  • 42 of 42 exit 0. pnpm --dir ui exec vitest run scripts/ first went red on check-vi-mock-inherit (the new checklist test's @object-ui/app-shell mock did not inherit the real surface); fixed in 9914c31f and re-run on that head: Test Files 170 passed, 2 skipped; Tests 4985 passed, 2 skipped.
  • --ran: ✓ dispatch-gates --ran: 42 derived famil(ies) accounted for — 42 run, 0 NOT-MEASURED.
  • The other 41 ran on df45b9d1 plus that one test edit; the list derived on 9914c31f is the same 42.

🤖 Generated with Claude Code

https://claude.ai/code/session_01L6bhgVwQZbHRRM9CaXeKif

…s the currency and time zone dialog (#30206)

The dialog that asked for the system timezone and default currency on the
first page an administrator opened is gone. Its questions, and the other
things a new workspace needs, are rows of a checklist at the top of Home:
organization name, default language and country, system timezone, default
currency, email delivery, and invite colleagues. Each row's state is read
from the real setting; the localization rows edit in place with the
Settings page's own fields, pre-filled from the browser and written only
on the row's Confirm. Members see nothing; the close button hides it for
that administrator in that workspace on that device.

A country typed by name into a domain-bearing picker now commits the
option's code (「中国」 → CN), and an invalid_format refusal reads in the
console's words and the reader's language on the Settings page and the
checklist.

Claude-Session: https://claude.ai/code/session_01L6bhgVwQZbHRRM9CaXeKif
Co-authored-by: Claude <noreply@anthropic.com>
@github-actions github-actions Bot added size/xl documentation Improvements or additions to documentation tests tooling Fix lands in tooling, not a product package — enters pm:queue only with Unblocks: or a named surface labels Nov 5, 2026
… workspace prompt (#30206)

The console no longer opens the timezone and currency dialog, so the
showcase smoke's global setup no longer looks for it. Before, with the
currency unset, it waited 60 seconds for a dialog that never opens and
then warned. Sign-in and the storageState it writes are unchanged.

Claude-Session: https://claude.ai/code/session_01L6bhgVwQZbHRRM9CaXeKif
Co-authored-by: Claude <noreply@anthropic.com>
…eys as a narrowing (#30206)

The ten published @object-ui/i18n packs drop the
console.workspaceTimezonePrompt.* keys, so the declaration's arm is
narrowing (the new keys stay named as its widening half), the summary
carries the bang, and the body gains the BREAKING note, the removed-key
table and the ADR-0087 runtime-interface-only disposition.

Claude-Session: https://claude.ai/code/session_01L6bhgVwQZbHRRM9CaXeKif
Co-authored-by: Claude <noreply@anthropic.com>
Conflicts, each two neighbouring additions, both kept: the ten locale
packs (main's console.settingsView.clientAddress* beside this branch's
invalidFormat*), and de-quote-pairing-3876, whose counts now add main's
one pair (#30323) and this branch's two: 107 matched spans, 107/107/0.

Claude-Session: https://claude.ai/code/session_01L6bhgVwQZbHRRM9CaXeKif
Co-authored-by: Claude <noreply@anthropic.com>
…st's measured 203 bytes (#30206)

Build & E2E UI went red on cda63e7: i18n-locale-en measured 60,138
gzipped bytes against a 60,000 ceiling. A control build of the PR base
(main 48b3ae6, with ui/apps/console, ui/packages/i18n and ui/e2e
restored to it) measures 59,935, so this branch adds 203 bytes: the
first-run checklist copy and the invalid_format sentences, net of the
retired prompt keys. Trimming the new copy saves at most 122 bytes, less
than the 138 over, so the ceiling and PER_CHUNK_BASELINE both move by
exactly 203. Headroom stays at the 65 bytes main had. The aggregate
ceiling and every other key are unchanged.

Claude-Session: https://claude.ai/code/session_01L6bhgVwQZbHRRM9CaXeKif
Co-authored-by: Claude <noreply@anthropic.com>
… checklist's measured 203 bytes (#30206)"

This reverts commit 10e7823. The lane is
not raising the i18n-locale-en ceiling: #30588 moves the marketplace.*
copy into a lazily loaded namespace, which brings the eager en catalogue
back under 60,000 once it lands and this branch merges main.

Claude-Session: https://claude.ai/code/session_01L6bhgVwQZbHRRM9CaXeKif
Co-authored-by: Claude <noreply@anthropic.com>

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Improvements or additions to documentation size/xl tests tooling Fix lands in tooling, not a product package — enters pm:queue only with Unblocks: or a named surface

Projects

None yet

Development

Successfully merging this pull request may close these issues.

First-run setup checklist for administrators, replacing the currency and time zone dialog

1 participant