From 7e0ecf3340217d899f6794846b30eb160644bc97 Mon Sep 17 00:00:00 2001 From: Claude Date: Sat, 8 Aug 2026 22:00:04 +0000 Subject: [PATCH 1/2] =?UTF-8?q?docs(app-shell):=20=E4=B8=A4=E4=B8=AA=20App?= =?UTF-8?q?Content=20=E8=B7=AF=E7=94=B1=E6=B5=8B=E8=AF=95=E7=9A=84?= =?UTF-8?q?=E7=94=9F=E4=BA=A7=E7=AB=AF=E5=8F=99=E8=BF=B0=E6=94=B9=E5=86=99?= =?UTF-8?q?=E4=B8=BA=E3=80=8C=E5=8E=86=E5=8F=B2=20+=20=E7=8E=B0=E7=8A=B6?= =?UTF-8?q?=E3=80=8D=E4=B8=A4=E6=AE=B5=20(#3749)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 三处注释以现在时枚举「侧边栏 / QuickActions 现在发哪些 URL」,而这些 URL 已被 #3660(`sys-datasources`)与 #3739(`sys-objects` + 首页 Manage Objects 卡片)改指 metadata-admin 引擎的规范路由。断言全部正确且全绿 —— 陈旧的只有叙述,以及两个以 生产端命名的 `it` 标题:它们实际量的是别名路由仍能解析且只跳一次。 手法照 #3666:每处拆成「#3610 当时如此」(过去时)与「#3660/#3739 之后如此」 (现在时)两段,现状段正面陈述两条别名今天的身份 —— 不再是任何导航的目标,而是 书签与外部链接的到达路径,这正是重定向必须继续工作的理由。按 #3656,现状段不靠 「不再指向 X」的否认句复述别名 URL。 - `AppContent.noAppComponentRoutes.test.tsx`:头注拆段;两个 `it` 标题从 `sys-datasources:` / `sys-objects:` 改为 `shell alias:` / `host alias:`,即两条 别名各自的改写者(shell 自己的 `LegacyMetadataRedirect` vs 宿主的 `MetadataRedirect`)—— 文件正文本来就画了这条区分。用例体内两处重申同一陈旧 断言的行内注释同步(`sys-datasources` item still points straight at this spelling / this case now measures what production actually does),否则改完标题 的文件会自相矛盾。顺带把同一段落里 `isMetadataRoute` 的现在时「substring test」 收敛为过去时 —— #3638 起它是 `pathSegments.includes('metadata')` 段测试。 - `AppContent.pseudoRouteSegments.test.tsx`:生产端表格按实读重写(逐条读自 `AppSidebar` / `UnifiedSidebar` / `QuickActions` / `HomePage` / `InboxPopover`), 并补一段说明两条旧拼写并未消失,只是从 `navigation` 行移到了上面两行的到达面。 `metadata` 两种拼写下都是完整路径段,所以本文件要证伪的论断不受影响。 - `AppContent.tsx`(#3610 那段):收尾句补上 #3739 也已重指,并注明 `sys-objects` 的链路早在 #3658 就离开了这两条路由。该段前半的过去时叙述保留。 零行为改动:两个测试文件跑前跑后同为 43 passed,断言与用例数未动。 无 changeset —— 注释-only,照 #3666(bd04651ee)与 #3785(f9d70a72e)先例。 Fixes #3749 --- packages/app-shell/src/console/AppContent.tsx | 9 ++- .../AppContent.noAppComponentRoutes.test.tsx | 77 ++++++++++++------- .../AppContent.pseudoRouteSegments.test.tsx | 25 ++++-- 3 files changed, 76 insertions(+), 35 deletions(-) diff --git a/packages/app-shell/src/console/AppContent.tsx b/packages/app-shell/src/console/AppContent.tsx index 8a958ada0..ef1bdaedb 100644 --- a/packages/app-shell/src/console/AppContent.tsx +++ b/packages/app-shell/src/console/AppContent.tsx @@ -655,9 +655,12 @@ export function AppContent({ extraRoutes, extraRoutesNoApp }: AppContentProps = every one of them rendered a blank screen. #3610 mirrored the routes rather than re-point that navigation, because inventing a zero-app-only spelling would have given the alias a second - canonical destination. #3660 re-pointed it anyway — at the shared - `metadata/:type` routes above, so no second spelling was created — - which leaves these two serving bookmarks and external links, the + canonical destination. #3660 re-pointed `sys-datasources` anyway — + at the shared `metadata/:type` routes above, so no second spelling + was created — and #3739 did the same for `sys-objects` and the + home "Manage Objects" card, whose chain had already left these two + routes at #3658, when the host stopped rewriting onto the alias. + What is left for these two is bookmarks and external links: the arrivals that can never be re-pointed. */} } /> } /> diff --git a/packages/app-shell/src/console/__tests__/AppContent.noAppComponentRoutes.test.tsx b/packages/app-shell/src/console/__tests__/AppContent.noAppComponentRoutes.test.tsx index f8e0eebf7..f722a90db 100644 --- a/packages/app-shell/src/console/__tests__/AppContent.noAppComponentRoutes.test.tsx +++ b/packages/app-shell/src/console/__tests__/AppContent.noAppComponentRoutes.test.tsx @@ -4,20 +4,38 @@ * Zero-app console: the `component/metadata/*` destinations must resolve, and * anything unmatched must say so (objectui#3610). * - * ## The defect + * ## The defect, as it stood at objectui#3610 * - * With zero published apps, the system fallback sidebar offers two entries that - * both land inside `AppContent`'s no-`activeApp` branch: + * With zero published apps, the system fallback sidebar offered two entries + * that both landed inside `AppContent`'s no-`activeApp` branch: * * sys-datasources -> /apps/setup/component/metadata/resource?type=datasource * sys-objects -> /apps/setup/system/metadata/object * - * `isMetadataRoute` is a substring test (`pathname.includes('/metadata')`), so - * both URLs pass the "no apps configured" guard and enter the no-`activeApp` - * ``. That branch declared `create-app`, `system/marketplace*` and - * `metadata*` only — no `component/…` at all — and, unlike the with-`activeApp` - * branch, no trailing `path="*"`. A `` with no match renders `null`: - * a fully blank screen, no 404, no error, no empty state. + * `isMetadataRoute` was a substring test (`pathname.includes('/metadata')`) at + * the time, so both URLs passed the "no apps configured" guard and entered the + * no-`activeApp` ``. That branch declared `create-app`, + * `system/marketplace*` and `metadata*` only — no `component/…` at all — and, + * unlike the with-`activeApp` branch, no trailing `path="*"`. A `` with + * no match renders `null`: a fully blank screen, no 404, no error, no empty + * state. + * + * ## What those two URLs are NOW (objectui#3660, #3739) + * + * Neither is anybody's navigation target any more. Both sidebar entries name + * the metadata-admin engine's canonical routes directly — `sys-datasources` -> + * `/apps/setup/metadata/datasource` (#3660), `sys-objects` -> + * `/apps/setup/metadata/object` (#3739) — as does the home QuickActions + * "Manage Objects" card. The two spellings above are ARRIVALS: bookmarks, + * external links, and, for the `system/metadata/:type` one, the host + * fragment's own alias route, which stays declared for exactly those. + * + * That is why this file still measures them, and why the `it` titles below name + * the alias URL and its rewriter rather than the sidebar entry that used to + * emit it: what is under test is that each alias still RESOLVES out of the + * zero-app branch, and still costs exactly one hop. `isMetadataRoute` is a + * segment test since #3638 (`pathSegments.includes('metadata')`), under which + * every URL here stays true. * * ## Which spelling is canonical — MEASURED, and the opposite of the guess * @@ -49,17 +67,18 @@ * `apps/console/src/AppContent.tsx` (`systemRoutes` + its `MetadataRedirect`). * app-shell cannot import from `apps/` — a different Vitest project — so the * rewrite is copied verbatim, including its `prefix` regex, and this comment is - * the pointer back to the original. It is the `sys-objects` leg of the chain: - * without it that URL's route into this branch is invisible here. + * the pointer back to the original. It is the `system/metadata/:type` leg of + * the chain: without it that URL's route into this branch is invisible here. * * ## Why the chain, not just the endpoint (objectui#3661) * * A transcription can go stale, and this one did. objectui#3658 re-pointed the * host straight at the canonical routes; the copy here kept emitting the - * deprecated alias, so the `sys-objects` case went on measuring a two-hop chain - * that production had stopped producing. Nothing went red — the assertions - * pinned only the final pathname, and that is identical either way. Green, for - * a reason that no longer had anything to do with the code under test. + * deprecated alias, so the `system/metadata/object` case went on measuring a + * two-hop chain that production had stopped producing. Nothing went red — the + * assertions pinned only the final pathname, and that is identical either way. + * Green, for a reason that no longer had anything to do with the code under + * test. * * So `renderConsoleAt` now returns every location the router settles on, and * all four redirect cases assert that list exactly. A stub that drifts back @@ -265,15 +284,18 @@ describe('AppContent — zero-app component/metadata destinations (objectui#3610 vi.clearAllMocks(); }); - it('sys-datasources: /apps/setup/component/metadata/resource?type=datasource renders the resource page', async () => { + it('shell alias: /apps/setup/component/metadata/resource?type=datasource resolves in the zero-app branch and hops ONCE to the canonical page', async () => { // The white screen this issue is about. The URL passes `isMetadataRoute` - // (substring `/metadata`) and so enters the no-`activeApp` branch, which - // used to declare nothing matching `component/…` and had no catch-all. + // (a `metadata` path segment; a substring test until #3638) and so enters + // the no-`activeApp` branch, which used to declare nothing matching + // `component/…` and had no catch-all. // // Unlike the two host-rewrite cases below, the alias here is the ENTRY, not - // an intermediate stop — the zero-app fallback sidebar's `sys-datasources` - // item still points straight at this spelling, so this chain is one this - // deployment really produces. + // an intermediate stop: nothing rewrites it on the way in, so this branch's + // own route table is the whole story. The `sys-datasources` sidebar item is + // what emitted it at #3610; since #3660 that item names the canonical route + // and this spelling arrives from bookmarks and external links instead — + // which is precisely why the redirect has to keep working. const chain = renderConsoleAt('/apps/setup/component/metadata/resource?type=datasource'); const page = await screen.findByTestId('metadata-resource-list-page'); @@ -294,17 +316,20 @@ describe('AppContent — zero-app component/metadata destinations (objectui#3610 expect(screen.queryByTestId('root-landing')).not.toBeInTheDocument(); }); - it('sys-objects: /apps/setup/system/metadata/object reaches this branch\'s metadata/:type in ONE hop', async () => { + it('host alias: /apps/setup/system/metadata/object reaches this branch\'s metadata/:type in ONE hop', async () => { // The non-obvious half, pinned on its own because it would regress // silently: this URL is rewritten by the HOST (`MetadataRedirect`) onto the // canonical route, which the zero-app branch declares itself. Two route // tables, one redirect, zero apps. // // It used to be two redirects — the host aimed at the legacy alias and the - // shell forwarded that on. objectui#3658 removed the middle stop; this case - // now measures what production actually does, and objectui#3661 is what it - // cost to notice that it had stopped doing so (the endpoint never moved, so - // nothing failed). + // shell forwarded that on. objectui#3658 removed the middle stop, and + // objectui#3661 is what it cost to notice that the transcribed stub had not + // followed (the endpoint never moved, so nothing failed). Since #3739 no + // click in this repo emits this URL either — `sys-objects` and the home + // "Manage Objects" card name the canonical route — so what is pinned here + // is the arrival path the host still declares for bookmarks and external + // links. const chain = renderConsoleAt('/apps/setup/system/metadata/object'); const page = await screen.findByTestId('metadata-resource-list-page'); diff --git a/packages/app-shell/src/console/__tests__/AppContent.pseudoRouteSegments.test.tsx b/packages/app-shell/src/console/__tests__/AppContent.pseudoRouteSegments.test.tsx index 45072c277..5df9143fc 100644 --- a/packages/app-shell/src/console/__tests__/AppContent.pseudoRouteSegments.test.tsx +++ b/packages/app-shell/src/console/__tests__/AppContent.pseudoRouteSegments.test.tsx @@ -38,14 +38,27 @@ * metadata,metadata/:type,metadata/:type/:name}` * (`developer/*` and `docs/*` are in the same * fragment but flip NO flag — pinned below) - * navigation AppSidebar / UnifiedSidebar `/apps/setup/system{,/apps,/marketplace, - * /metadata/object,/users,/organizations, - * /roles,/settings}` - * `/apps/setup/component/metadata/resource?type=` - * QuickActions / HomePage / `/apps/setup/system/{metadata/object,marketplace, - * InboxPopover approvals}` + * navigation AppSidebar / UnifiedSidebar `/apps/setup/system{,/apps,/marketplace,/users, + * /organizations,/roles,/settings}` + * `/apps/setup/metadata/{object,datasource}` + * QuickActions `/apps/setup/metadata/object`, `/apps/setup/system` + * HomePage / InboxPopover `/apps/setup/system/{marketplace,approvals}` * SystemRedirect (#3637) bare `/system` -> `/apps/setup/system` * + * The metadata-admin entries moved after #3638 landed: the sidebars' + * `sys-objects` / `sys-datasources` items and the QuickActions "Manage Objects" + * card once spelled `…/system/metadata/object` and + * `…/component/metadata/resource?type=datasource`; #3739 and #3660 re-pointed + * all three at the engine's canonical `…/metadata/:type` routes. Those two + * older spellings are still in this input surface, as ARRIVALS rather than + * emissions — declared in the two rows above + * (`component/metadata/{directory,resource/*}` in the shell, + * `system/metadata{,/:type}` in the host) and reached from bookmarks and + * external links. `metadata` is a whole path segment either way, so the claim + * below is indifferent to the move; the `navigation` row is re-read here + * because a producer list naming URLs nothing emits any more is the stale + * pointer objectui#3661 was paid for. + * * In EVERY one of them `system` / `metadata` is a whole path segment, so a * segment test keeps all of them true. That is the claim this file's first two * describes exist to falsify. From 67586091104012408c7ea4b641378c52e26fbab1 Mon Sep 17 00:00:00 2001 From: Claude Date: Sat, 8 Aug 2026 22:03:35 +0000 Subject: [PATCH 2/2] =?UTF-8?q?chore(changeset):=20=E4=B8=BA=20#3749=20?= =?UTF-8?q?=E6=B3=A8=E9=87=8A=E6=94=B9=E5=86=99=E5=A3=B0=E6=98=8E=E3=80=8C?= =?UTF-8?q?=E4=B8=8D=E5=8F=91=E5=B8=83=E4=BB=BB=E4=BD=95=E4=B8=9C=E8=A5=BF?= =?UTF-8?q?=E3=80=8D(=E7=A9=BA=20frontmatter)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit CI 的 Changeset Declaration 门(scripts/check-changeset-presence.mjs)守的是 「fixed 组内任一包的 `/src/**` 被改动 -> 必须有 `.changeset/*.md` 声明」, 本次三个改动文件全部落在 packages/app-shell/src 下,所以门要求声明。 先前照 #3666(bd04651ee)与 #3785(f9d70a72e)判断「注释-only 不带 changeset」是 读错了先例:那两个 PR 早于这道门(#3387 引入),且 #3785 只动 content/docs/**, 根本不在守护面内。门自己写明了正确出口 —— 「If this change really should release nothing, say so — that is a pass, not a workaround」,即空 frontmatter,照 .changeset/registry-inputs-spec-parity-gate-3797.md 的先例写法。 空 frontmatter 而非 patch:AppContent.tsx 只改 JSX 注释,两条 LegacyMetadataRedirect 路由声明与其余每一行代码未动;两个测试文件断言与用例数 逐字节未变(前后同为 43 passed)。确无可发布的行为改动。 本地验证: node scripts/check-changeset-presence.mjs -> exit 0(识别为空 frontmatter 豁免) node scripts/check-changeset-no-major.mjs -> exit 0 --- .../appcontent-route-test-headers-3749.md | 30 +++++++++++++++++++ 1 file changed, 30 insertions(+) create mode 100644 .changeset/appcontent-route-test-headers-3749.md diff --git a/.changeset/appcontent-route-test-headers-3749.md b/.changeset/appcontent-route-test-headers-3749.md new file mode 100644 index 000000000..a799d3beb --- /dev/null +++ b/.changeset/appcontent-route-test-headers-3749.md @@ -0,0 +1,30 @@ +--- +--- + +Comment-only change, no behaviour and no authoring-surface change (objectui#3749). + +Three docblock passages in the zero-app console routing tests enumerated +`sys-datasources` / `sys-objects` in the present tense as the producers of +`…/component/metadata/resource?type=datasource` and `…/system/metadata/object`. +Both entries were re-pointed at the metadata-admin engine's canonical +`…/metadata/:type` routes — `sys-datasources` by objectui#3660, +`sys-objects` (and the home QuickActions "Manage Objects" card) by +objectui#3739 — so the narration described a producer surface that no longer +exists, while the assertions underneath it stayed correct and green. + +Rewritten as "history + current state" per objectui#3666: what was true at +objectui#3610, then what is true now, with the current-state half stating +positively what the two spellings are today (arrivals for bookmarks, external +links and the host's own alias route) rather than denying where they used to +point. The two `it` titles move off the producer names onto what they actually +measure — each alias still resolving out of the zero-app branch in exactly one +hop, named by its rewriter (`shell alias` / `host alias`). + +No package is declared because nothing published changed: `AppContent.tsx` is a +JSX-comment edit with both `LegacyMetadataRedirect` route declarations and every +other line of code untouched, and the two test files keep their assertions and +case count byte for byte (43 passed before, 43 passed after). The reason this is +worth a commit at all is that the same comment family has gone stale once before +at a measured cost — objectui#3661 / #3669, where a transcription that had +drifted left two cases silently measuring a redirect chain production had +stopped emitting.