Repository navigation
fix(app-shell): Home, the app switcher and launcher blocks offer only the apps /me/apps lists, so a tabPermissions-hidden app draws no tile - #27021
Conversation
…me/apps answer Home's tiles, the app switcher menu and the app:launcher block listed GET /meta/app, which still serves an app a permission set hides (tabPermissions: hidden); the hide is applied only in GET /me/apps. A LauncherAppsProvider, mounted in the console's ConsolePermissionsScope, reads /me/apps once per user and useLauncherApps narrows each surface's list by its app names. No provider, a 404 or a failed read narrows nothing. Claude-Session: https://claude.ai/code/session_01JQwxbYwBbR8jCpWPE5Kosz Co-authored-by: Claude <noreply@anthropic.com>
… and the switcher Claude-Session: https://claude.ai/code/session_01JQwxbYwBbR8jCpWPE5Kosz Co-authored-by: Claude <noreply@anthropic.com>
席位核对REWORK · One patch round, same claim and branch. The diff reviewed (
Everything else stands; re-run the derived gates on the new head and update the report. |
… an app /me/apps hides The palette's "Switch app" group (Home and in-app) narrows its active apps by the same /me/apps answer through a new useServedApps, keeping its own rule that lists hidden apps; AppContent's default-app fallback for an unresolved segment reads useLauncherApps. One test and one ablation each. Claude-Session: https://claude.ai/code/session_01JQwxbYwBbR8jCpWPE5Kosz Co-authored-by: Claude <noreply@anthropic.com>
…, not a reassigned outer variable Lint UI refused the hook test's `seen = useLauncherApps(...)` under react-hooks/globals; the probe now hands its entries to a vi.fn from an effect. Claude-Session: https://claude.ai/code/session_01JQwxbYwBbR8jCpWPE5Kosz Co-authored-by: Claude <noreply@anthropic.com>
席位核对ACCEPT · 席位意见:返工补齐了卡上"每个启动入口都读同一份
|
⛔ merge queue 构建失败 — 先分诊,再决定要不要重排队列构建 40654802071 红了。队列跑的是全量套件(PR 侧 CI 只跑 affected 子集), 分类: 失败的 job(日志抽取,best effort):
跨 PR 相同签名(24h,按失败测试文件聚合):
历史信号:
分诊清单:
Generated by Claude Code · merge-queue-triage workflow (#4859) |
|
Merge-queue build 40654802071 is red, but the failure does not come from this PR. All four failing cases are in No fix is needed in this PR, and there is nothing to port from main. The failure belongs to #27019. This PR left the queue with the build, so it has to be re-enqueued. A rerun of the same queue build would rebuild the same stack, so this comment does not request one. Generated by Claude Code |
Requested by Warren · project thread
Fixes #26838
Clause-②: no
Metadata-protocol: none
维护者速读
app:launcher页面块都按当前用户的GET /me/apps结果收窄应用列表,权限集里tabPermissions: hidden的应用不再出现。命令面板的应用列表和不带应用段的默认落地也按 /me/apps 收窄。/me/apps生效,而这三个入口都读/meta/app(卡上说切换器已正确,实测它也读/meta/app),成员仍能看到并点开被管理员隐藏的应用。/me/apps答 404、或读取失败,一律回退到原来的完整列表;首页多等一次/me/apps首读。回滚即 revert 本 PR。ui/packages/app-shell/src/hooks/useLauncherApps.tsx(收窄与回退规则)、ui/apps/console/src/AppContent.tsx(唯一挂载点)、ui/packages/app-shell/src/console/home/HomePage.tsx(首页等待首读)。pnpm --dir ui exec vitest run packages/app-shell/src/console/home/__tests__/HomePage.launcherHiddenApps-26838.test.tsx,预期 4 个用例通过,被隐藏的 Showcase 不出磁贴。What changes
ui/packages/app-shell/src/hooks/useLauncherApps.tsx:LauncherAppsProviderreadsGET /api/v1/me/appsonce per signed-in user, and again only when the active/meta/appname set gains a name the held answer was not asked about (an install or a publish mid-session).useLauncherApps(apps)returnsfilterActiveApps(apps)minus every app the answer was asked about and did not list. The entries stay/meta/app's own objects (labels, icons,_packageId, publish state);/me/appscontributes names only.404(no security plugin serves the route) or a failed read narrows nothing. A failure other than404logs oneconsole.warn; a404is not asked again for that user.pendingis true only while the first read is out.ui/apps/console/src/AppContent.tsx:ConsolePermissionsScope, the one common ancestor of/homeand/apps/:appName/*, mountsLauncherAppsProviderinsideMePermissionsProvider, with the same server URL and authenticated fetch. The seat extended the claim's file surface to this file (amendment 6457698059).HomePage: the tiles and the System Settings link come fromuseLauncherApps; the page's loading gate also waits for the first read, so a hidden tile is never drawn and then removed. The host-app resolution and the recent rows' app labels keep the full active list, because a hidden app still opens.AppSwitcher: the menu listsuseLauncherApps(apps). The pill still names a hidden app while the user is in it (its existing fallback over all active apps).app:launcherblock (views/app-launcher-renderer.tsx): its openable set isuseLauncherApps(apps); it still issues no request of its own.LauncherAppsProvideranduseLauncherAppsare exported from@object-ui/app-shell.useServedApps(apps)(exported): the/me/appsnarrowing alone, no active/hidden filter.CommandPalettelistsuseServedApps(apps.filter(active !== false)), so its ownhidden: truebehaviour is unchanged.console/AppContent.tsx: the default-app landing (a URL naming no or an unknown app) picks fromuseLauncherApps(apps); the route lookup still finds a hidden app, which keeps opening from its URL..changeset/26838-launcher-hidden-tabs.md:@object-ui/app-shelland@object-ui/consolepatch.Not changed: no server change, no route guard (a hidden app keeps opening from its URL),
default_offuntouched,console/appObjectScope.tsuntouched.Why a provider, not a hook that fetches
No
@objectstack/clientmethod reads/me/apps, so the read is a direct authenticated fetch. The ui network-escape guard (ui/vitest.setup.network-escape-guard.ts) reds any test whose render reaches a relative fetch, and about 130 test files renderHomePage,AppSwitcher,AppHeaderorHomeLayout. An explicitly mounted provider, theMePermissionsProviderpattern, keeps those tests unchanged: without it a surface reads the unnarrowed list, exactly as before.Tests
hooks/__tests__/useLauncherApps-26838.test.tsx(8 cases): narrows by the answer and keeps the/meta/appentries; no provider narrows nothing;404narrows nothing, silently, and is not re-asked;500narrows nothing and warns once;pendingonly for the first read; an app added after the read passes and triggers one re-read; two consumers share one read; no user, no read.console/home/__tests__/HomePage.launcherHiddenApps-26838.test.tsx(4 cases):/meta/app= [setup, crm, showcase_app] and/me/apps= [setup, crm] draws no Showcase tile; a set hiding Setup removes the System Settings link; the404control draws every tile; the loading line holds while the first read is out.layout/__tests__/AppSwitcher.launcherHiddenApps-26838.test.tsx(3 cases): the hidden app is not in the menu; the404control lists it; the pill still names it when the user is in it.chrome/CommandPalette.launcherHiddenApps-26838.test.tsx(2 cases): the hidden app is not offered; the404control offers it.console/__tests__/AppContent.defaultLandingHiddenApp-26838.test.tsx(3 cases): the declared defaultcrmhidden by/me/apps= [sales] makes an unknown-app URL land onsales; the404control keepscrm; a URL namingcrmstill opens it.Ablations (one-time; restored, blob equals HEAD each time)
Each leg ran under the lock through
node scripts/ablation-replace.mjs(anchor hit 1 -> 0, restored blob equals HEAD,git diff HEADempty), on commit9f4f6f31:HomePage.tsx: the tiles fromactiveAppsinstead oflauncher.apps->HomePage.launcherHiddenApps-26838: 2 failed / 2 passed (the hidden-tile case and the loading-hold case go red).useLauncherApps.tsx: the narrowing predicate replaced byreturn true-> hook, Home and switcher files: 7 cases red across the three files.AppSwitcher.tsx: the menu from the old inlineactive/hiddenfilter ->AppSwitcher.launcherHiddenApps-26838: 2 failed / 1 passed.bb175bf7:CommandPaletteuseServedApps(...)-> the plain active filter: 1 failed / 1 passed; app-shellconsole/AppContentuseLauncherApps(apps)-> the inline active/hidden filter: 1 failed / 2 passed.Acceptance notes
/me/appsand hides the app. Onorigin/mainno file underui/read/me/apps; the switcher read/meta/applike Home. Both are fixed here.GET /me/appsanswers200 { apps: [] }when its handler throws (the outercatchincurrent-user-endpoints.ts). This client cannot tell that from "every app is hidden", so on that answer Home draws no app tiles and no System Settings link (only the page frame), the switcher menu lists no app, and the palette offers no app; a hidden-by-throw state lasts until the next read (a new user or a new app name). Read-only inference from source; not reproduced./me/appsread alongside/meta/app; the read starts once the app list has loaded, so it adds one request round trip before the tiles draw on a cold load.Verification
Round 2 on head
7b20f2d5(8cc708abmergedorigin/mainacc9c57d;7b20f2d5changes one test file): affected set 308 files / 2514 tests passed on8cc708ab;dispatch-gates --commands34/34 exit 0 and--ran0 NOT-MEASURED on8cc708ab; app-shell package lint 0 errors; CI on7b20f2d5green (43 success, 10 skipped). Round 1 readings below.Round 1 on head
cbe8d370(origin/main merged in), app-shell closure built first (7m33s under the lock).HomePage,AppSwitcher,AppHeader,HomeLayout,ConsoleLayout,AppContent, the launcher block or the hook, plus all ofconsole/home/__tests__andlayout/__tests__: 284 files, 2359 tests passed (on9f4f6f31, before the merge of origin/main, which touched no file under these paths).pnpm --filter @object-ui/app-shell run type-check: exit 0.pnpm --filter @object-ui/console run type-check: exit 0 (after--filter '@object-ui/console^...' build).node scripts/pm/dispatch-gates.mjs --commands: 34 derived commands, each exit 0;--ranreconciliation: 34 derived, 34 run, 0 NOT-MEASURED. Includesnode scripts/check-sdui-manifest.mjs(exit 0) andpnpm --dir ui exec vitest run scripts/(exit 0).pnpm --dir ui run check:spec-symbols,check:new-line-citations,check:test-path-roots: exit 0.Human Minimum
packages/specholds no runtime logic. (not touched)pnpm lintpasses. (CI runs the repo lint)main, one pull request.packages/spectouched: its generated artifacts are regenerated and committed. (not touched)content/docs/references/,packages/*/CHANGELOG.mdorcontent/docs/releases/.Generated by Claude Code