Repository navigation
fix(console): a native push route is hosted under an app, as the inbox hosts it - #29810
Merged
Merged
Conversation
…x hosts it The native navigate listener resolves the shell's route through the inbox's resolveNotificationTarget under the app the person is in or last had open, and the catch-all hosts an unmatched app-relative path under the default app instead of dropping it on Home. app-shell publishes the resolver and the console root-segment table from its root. Claude-Session: https://claude.ai/code/session_01QsR2jVL7fzYGjxa3ani6k8 Co-Authored-By: Claude <noreply@anthropic.com>
…ch-all Claude-Session: https://claude.ai/code/session_01QsR2jVL7fzYGjxa3ani6k8 Co-Authored-By: Claude <noreply@anthropic.com>
…g module's predicate Claude-Session: https://claude.ai/code/session_01QsR2jVL7fzYGjxa3ani6k8 Co-Authored-By: Claude <noreply@anthropic.com>
…s, and the catch-all waits for a settled app list Measured live: a session-cached app list stops `loading` while its re-read still reads `loading`, so the catch-all redirected to Home; and hosting under `currentAppName` (an app name) made the app route re-address the page several times. The listener now hands a route on whenever the URL names no app. Claude-Session: https://claude.ai/code/session_01QsR2jVL7fzYGjxa3ani6k8 Co-Authored-By: Claude <noreply@anthropic.com>
Contributor
Author
|
domain:ui#2 · zhuangjianguo · session_01QsR2jRFuJz9QBZqPVHYVhJ 维护者速读
席位意见: 解析用的是收件箱同一个函数,没有另写一份。冷启动时 App 还没打开任何应用,监听器拿不到应用列表,所以交给兜底路由等列表到齐再放;这条路也顺带覆盖了手机壳以首个网址送达的三种情况。 席位核对 — ACCEPT ·
|
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 #29750
Clause-②: no
Metadata-protocol: none
维护者速读
/opportunity/123)现在会像收件箱一样放进对应的应用里打开记录,不再落到首页;直接打开这种链接作为首个网址时也一样。/notifications/devices) and the APNs + FCM transport that ADR-0012 marks "MUST ship M1" #29041)就会打不开记录。/foo/bar),现在进入默认应用并显示「页面未找到」,而不是回首页。无服务端、无数据改动,回滚即还原本 PR。ui/apps/console/src/components/UnmatchedRoute.tsx(兜底路由何时等应用列表、何时仍回首页)、ui/apps/console/src/App.tsx的NativeShellRouting(推送监听)、ui/apps/console/src/nativeShellRoute.ts。pnpm --dir ui exec vitest run apps/console/src/__tests__/App.nativeShellMode-29039.test.tsx apps/console/src/__tests__/nativeShellRoute-29750.test.ts,应全部通过(15 + 8)。What changes
The push contract (
packages/spec/src/api/push-delivery.zod.ts, #29218) says a pushrouteis the notification'sactionUrl, app-relative (/opportunity/123) or a Console route (/apps/crm/opportunity/123), and that the tap resolves it "as the inbox does, never verbatim". The Console's native navigate listener navigated it verbatim, so/opportunity/123matched no route and the catch-all sent the person to Home. Two legs now host it, both through the inbox's own resolver,resolveNotificationTarget, withresolveHostAppSegment. Nothing is re-implemented.Leg 1, the listener (
NativeShellRoutinginui/apps/console/src/App.tsx). It handsuseNativeHostRoutinga wrappednavigate(pure logic in the newui/apps/console/src/nativeShellRoute.ts,nativeShellRouteTarget):/apps/:appName/*, already the app's route segment)./opportunity/123on/apps/crm/...goes to/apps/crm/opportunity/123;/apps/x/y/1passes through.MetadataProvider. The shell's publishedcurrentAppNameis an app NAME; only the list turns it into its route segment. Measured live: hosting under the name (/apps/crm_app/...for an app addressed as/apps/com.example.crm) made the app route re-address the page four times before it settled.null(blank url) andexternal(scheme or//host) answers navigate nothing, and the event stays cancelled. Neither is reachable through the listener by construction:isInAppRoutein@object-ui/mobilerefuses a blank route, a scheme and a second leading slash before the Console sees the event. Both are pinned at unit level.Leg 2, the catch-all (
path="*", new elementui/apps/console/src/components/UnmatchedRoute.tsx):CONSOLE_ROOT_SEGMENTS, the tablehostInConsolePathalready keeps and the agent-chat route-table test pins againstApp.tsx) orappskeeps today's redirect to/.ProtectedRoute requireOrganization={false}(the same guard as/), waits until the app list has settled (isAppListConclusive, the landing route's own reading), and redirects toresolveNotificationTarget(path + query + hash, resolveHostAppSegment(apps, currentAppName)): the app the person last had open while it is still active, else the first active app. A failed app list keeps the old redirect to/, whose landing resolver owns the retry. A signed-out visitor goes through login and comes back to the same path.mainddcf2d5,lib/shell/console-load.tsandlib/shell/bridge/scripts.ts): a re-created WebView starts at the held route; the 8 s ready timeout on a Console whose listener is not mounted falls back tolocation.assignof the route; a server switch starts at its route. A warm tap is held untilreadyand dispatched as the event, which the listener takes.@object-ui/app-shellexportsresolveNotificationTarget,type NotificationTargetandCONSOLE_ROOT_SEGMENTSfrom the package root (they were onutils/only). The package is private, so nothing is published.ui/packages/mobileis unchanged.Why
From day one of push (#29041), every notification whose link is app-relative (the synthesized
/OBJECT/IDshape) would open Home instead of its record, which is the defect objectui#5179 fixed for the inbox doors.Tests
App.nativeShellMode-29039.test.tsx(realAppunder the realBrowserRouter, fake bridge), two new top-leveldescribeblocks. Listener: hosted under the URL's app with query and hash kept, event cancelled;/apps/x/y/1passes through; with no app open, the route is handed on and the catch-all hosts it under the default app; away from an app, it is hosted under the app last open, by its route segment (_packageId). Catch-all: first active app wins over an inactive one; last-open app re-checked; waits whileloading; waits while a session-cached list is still re-read (statusloading, measured live); a failed list keeps/; controls/dev/nope,/home/nope,/appskeep/; a real/homeis rendered by its own route and never rewritten.nativeShellRoute-29750.test.ts(8 cases): the listener's pure answer, including the unreachablenull/externalbranches, and the unmatched-path predicate's table.App.agentChatLink-10640.test.tsx: itsRootLandingRedirectmock now spreadsimportOriginal(one line, no assertion change), because its control URL reaches the catch-all, which readsisAppListConclusivefrom that module.scripts/ablation-replace.mjs, mutation landed by anchor count and blob, restored to the HEAD blob withgit diff HEADempty): the wrapper navigating verbatim reds "an app-relative route is hosted under the app in the URL"; the catch-all always redirecting to/reds the six hosting and waiting cases, controls stay green.Acceptance notes
/foo/bar) now opens/apps/APP/foo/barinstead of Home. Measured live on app-crm: the app shows its own "Page not found. The URL you followed does not match any view in this app. Go back", inside the app's chrome, no loop, no page error.:appNameonly, notcurrentAppName ?? :appName.currentAppNameis an app name; it reaches the catch-all instead, which re-checks it against the app list exactly as the inbox does./apps/NAME/...URL that addresses an app by its name rather than its_packageIdsegment lands correctly but re-addresses the page several times on the way (live history: alternatingcrm_appandcom.example.crmreplaces). Nothing here produces that form any more.main(ddcf2d5); nothing in that repository changes.Verification
Final head
b1ed0110(main merged twice; neither merge touched this PR's files). On that head: closure rebuild (70 tasks),@object-ui/consoleand@object-ui/app-shelltype-checkDone, and the 13 console test files that mock the root landing or use@object-ui/mobileplus the new unit file: 13 files, 62 tests, all passed.eslinton every touched file: exit 0.Derived gate sweep (dispatch-gates, 35 families, run at 93b08ba, reconciled)
node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstackderived 35 commands; every one exited 0, includingnode scripts/check-sdui-manifest.mjs,pnpm --dir ui exec vitest run scripts/,pnpm check:type-check-debt,pnpm check:test-source-alias,pnpm check:cross-package-test-inputsand the changeset gates.dispatch-gates --ran: 35 derived, 35 run, 0 NOT-MEASURED. The changeset and manifest gates were re-run onb1ed0110before the PR opened.Live run (app-crm --fresh plus the Vite Console on this branch, Playwright, fake bridge)
/apps/com.example.crm/foo/bar: the app's "Page not found" state./foo/bar:/apps/com.example.crm/foo/bar. First URL/crm_opportunity/ID:/apps/com.example.crm/crm_opportunity/record/ID, the record./dev/nope: Home, as before./crm_opportunity/IDfrom a fresh Home, from inside the app, and from Home after visiting the app: all land on/apps/com.example.crm/crm_opportunity/record/ID, event cancelled. Inside the app the history is one push plus the app's own record replace.Human Minimum
packages/specholds no runtime logic. (not touched)pnpm lintpasses (eslint on the touched files; CI runs the full lint).main, one pull request..changeset/29750-native-push-route-hosted.md).packages/spectouched: n/a.content/docs/references/,packages/*/CHANGELOG.mdorcontent/docs/releases/.Generated by Claude Code