Repository navigation
feat(console): App lock row on the profile page inside the mobile shell - #29798
Merged
Merged
Conversation
The profile page shows the mobile shell's app-lock state from getAppLock() and opens the shell's native settings screen through openAppLockSettings(), only when the bridge announces it. The Console never writes the lock. @object-ui/mobile gains the two optional bridge members and their wrappers; the ten locale packs gain profile.appLock.*. Co-Authored-By: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QsR2jSM2R4osc3dyaqPHY1
…r the machine locale Co-Authored-By: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QsR2jSM2R4osc3dyaqPHY1
Contributor
Author
|
domain:ui#1 · zhuangjianguo · session_01QsR2jUJ19MstFvFhjgiYTu Contract reviewServed-tier: ① Derived judgments
② Semver levelThe changeset declares ③ Boundary flags
Implemented-by: VERDICT: PASS |
Contributor
Author
|
domain:ui#1 · zhuangjianguo · session_01QsR2jUJ19MstFvFhjgiYTu 席位核对 · ACCEPT · 2026-11-03T05:37ZHead-sha:
|
This was referenced Nov 3, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Requested by Steedos · project thread
Fixes #29748
Clause-②: yes (widening)
Metadata-protocol: none
维护者速读
ui/apps/console/src/pages/system/ProfilePage.tsx(AppLockCard,尤其是重新读取状态的 effect)、ui/packages/mobile/src/nativeHost.ts(两个可选桥接方法和包装函数)、ui/packages/i18n/src/locales/ru.ts(俄语与阿拉伯语的时长句式改成冒号形式以避开格变化)。pnpm --dir ui exec vitest run apps/console/src/pages/system/__tests__/ProfilePage.appLock-29748.test.tsx packages/mobile/src/__tests__/nativeHost.test.tsx,应全部通过(9 + 72)。What changes
The shell contract is objectstack-ai/mobile
docs/HYBRID-SHELL.md, sections "App lock" and "Reading the app lock", read at objectstack-ai/mobile#181 head77ded7bb. That PR is not merged to mobilemainyet. The ruling is objectstack-ai/mobile#145 comment 6593856498, option A: the lock changes only on the shell's native screen, behind biometrics; the Console reads it and opens that screen, and never writes it./system/profileand the Account app'saccount:profile_card, which mount the same page): a newAppLockCardrenders only whennativeHostCan(useNativeHost(), 'openAppLockSettings'), the same feature-detect the header's organization button uses. It is one row: the title, and a state line fromgetAppLock(): "Off", "On, locks as soon as you leave the app" for a0timeout, or "On, locks DURATION after you leave the app". A tap callsnativeOpenAppLockSettings(). There is no toggle.getAppLock()on mount, onvisibilitychangeback tovisible, and on windowfocus. Only the newest read lands. A read the shell refuses leaves the row without a state line.Intl.NumberFormat(style: 'unit',unitDisplay: 'long') in the UI language, falling back touseDisplayLocale(), so no locale pack needs a count family and the machine locale is never used. ru and ar phrase it as "delay: DURATION", becauseIntlnames the unit in the nominative case.@object-ui/mobile:'getAppLock'and'openAppLockSettings'joinNativeHostMethod;getAppLock?()andopenAppLockSettings?()joinObjectStackNativeas optional members (an older shell lacks them, as withscan?); newNativeAppLocktype; newnativeGetAppLock()andnativeOpenAppLockSettings()wrappers with the sameunavailable | ok | failedanswer as the others. README documents them.@object-ui/i18n:profile.appLock.{title,off,onImmediately,onAfter}in all ten packs.In a plain browser, or a shell older than the app lock, nothing changes: no row, no bridge call.
Contract review
@object-ui/mobilegains twoNativeHostMethodmembers, two optionalObjectStackNativemembers, theNativeAppLocktype and two exported wrappers.@object-ui/i18ngains four keys underprofile.appLockin every pack (the builtendeclaration types each leaf).Tests
ProfilePage.appLock-29748.test.tsx(9 cases) renders the realProfilePageand the real@object-ui/mobilereader against a fakewindow.ObjectStackNative:0(immediately) and with an hour; off.openAppLockSettingsonce with no arguments, the card holds no switch or checkbox, and no other bridge method is called.visibilitychangeand on windowfocusafter the lock changed.has()does not announce it. Each draws no row and calls nothing.nativeHost.test.tsx: both methods join the unavailable / has-says-no / method-missing rows; an ok case for the pair; a refusedopenAppLockSettings("The app is locked") resolvesfailed.Acceptance notes
visibilitychangeand windowfocus. A native screen pushed inside the same Android activity may fire neither, so after returning from the settings screen the row can show the old state until the page is shown again. This is reported to the seat as a finding for the shell contract, not worked around here.NativeHostMethodunion, host interface,index.tsand test fake. Whichever lands second merges main and keeps both sets of members.Verification
Head
75f435ad, based on7ba8b11f.mainhas moved 18 commits since (other keys in the same ten locale packs);git merge-treeagainst it is clean, and CI runs on the merge ref.Red on main, ablation, tests, type-check, lint
ProfilePage.tsxrestored to7ba8b11f(tree only; restored to HEAD after,git diff HEADempty), the new file ran 6 failed, 3 passed: every shell case red, the three controls green.scripts/ablation-replace.mjs --deleteof thevisibilitychangeandfocuslistener lines; restored, blob equals HEAD,git diff HEADempty): 1 failed, 8 passed, the re-read case. Vitest aliases@object-ui/*tosrc, so no rebuild is involved.pnpm --dir ui exec vitest run --maxWorkers=2 packages/i18n/ packages/mobile/plus the fiveProfilePage.*suites: Test Files 109 passed, Tests 1633 passed, 13 skipped (the i18n suites includeall-locales-key-parity, the untranslated-identity census and the machine-locale census).turbo run type-check --filter=@object-ui/console --filter=@object-ui/mobile --filter=@object-ui/i18n: 73/73 tasks.eslinton the five changed code files: 0 errors (one pre-existingset-state-in-effectwarning on the page's name sync, untouched).Derived gates
node scripts/pm/dispatch-gates.mjs --commandsat75f435adderived 35 families. The 34 non-vitest families were run with exit codes captured before any pipe, withGITHUB_EVENT_PATHpointing at this body:node scripts/check-adr-0087-registration.mjs --base origin/main: exit 0node scripts/check-adr-0087-registration.mjs --self-test: exit 0node scripts/check-changeset-no-major.mjs --base origin/main: exit 0node scripts/check-closing-keyword-parity.mjs: exit 0node scripts/check-closing-keyword-parity.mjs --self-test: exit 0node scripts/check-comment-mask-corpus.mjs: exit 0node scripts/check-empty-changeset.mjs --base origin/main: exit 0node scripts/check-empty-changeset.mjs --self-test: exit 0node scripts/check-sdui-manifest.mjs: exit 0node scripts/check-sdui-manifest.mjs --self-test: exit 0node scripts/pm/release-rehearsal-clone.mjs --self-test: exit 0node scripts/release-pending-publish.mjs --self-test: exit 0pnpm --filter @objectstack/spec run check:duration-unit-keys: exit 0pnpm check:changeset-gate-self-tests: exit 0pnpm check:closed-ceremony-text: exit 0pnpm check:cross-package-test-inputs: exit 0pnpm check:dispatcher-error-vocabulary: exit 0pnpm check:driver-memory-census: exit 0pnpm check:engine-double-contract: exit 0pnpm check:gitlink-declared: exit 0pnpm check:nul-bytes: exit 0pnpm check:published-files: exit 0pnpm check:query-options-erasure: exit 0pnpm check:refd-timer-probe: exit 0pnpm check:registry-log-declared: exit 0pnpm check:rest-log-spy-declared: exit 0pnpm check:skill-identifier-liveness: exit 0pnpm check:test-source-alias: exit 0pnpm check:tier-file-adoption: exit 0pnpm check:type-check-coverage: exit 0pnpm check:type-check-debt: exit 0pnpm check:undeclared-dep-imports: exit 0pnpm check:watch-hint-literal: exit 0pnpm check:where-matcher: exit 0pnpm --dir ui exec vitest run scripts/: Test Files 170 passed, 2 skipped; Tests 4977 passed, 2 skipped; exit 0pnpm check:new-line-citations(fromui/): 0 new citationsGenerated by Claude Code