The invitation-accept screen tells the invitee nothing about what they are accepting. Observed page (zh), in full:
接受组织邀请
您受邀加入一个组织。
[ 接受邀请 ] [ 拒绝 ]
No organization name, no inviter, no role being granted, no expiry. The user is asked to join "an organization" and cannot tell which one, from whom, or as what — a decision they have no basis to make, and a soft phishing surface (anyone who can send an invite can get a click on an anonymous "join" button).
The twist: a page that shows all of it already exists and is not routed
Two implementations of the same route live in the tree:
| file | fetches invitation? | shows |
|---|
apps/console/src/pages/auth/AcceptInvitationPage.tsx | no | accept / decline only — this is the one mounted |
packages/app-shell/src/console/organizations/manage/AcceptInvitationPage.tsx | yes (getInvitation) | org name, role, expiry, plus a proper error state |
The router mounts the thin one:
// apps/console/src/App.tsx:65,188import{AcceptInvitationPage}from'./pages/auth/AcceptInvitationPage';…<Routepath="/accept-invitation/:invitationId"element={<AcceptInvitationPage/>}/>while the richer one renders exactly the missing block:
{t('organization.accept.description',{defaultValue: 'You have been invited to join {{orgName}} as {{role}}.',orgName: invitation.organizationName??invitation.organizationId,role: invitation.role,})}…Organization/Role/ExpiresrowsIt is exported (DefaultAcceptInvitationPage from packages/app-shell/src/index.ts:199, and from console/organizations/index.ts) but nothing in apps/console imports it. The locale files carry both key families and the comment in every locale already notes the split:
// Distinct from organization.accept.* (app-shell's richer page, same route).
So the strings for the good page are translated in 10+ locales and shipped, for a page the console never renders.
Expected
The invitee sees at least the organization name and the role being granted before accepting. Inviter would be a further improvement.
Suggested fix
Route the app-shell page (DefaultAcceptInvitationPage) and delete the thin duplicate, or port the detail block into the routed one and retire the unused export + its translation keys. Either way one implementation should survive — two pages for one route with different information density is how this drifted.
Environment
objectos-ee-deploy on http://localhost:8080, zh locale, invitee lisi@acme-test.com accepting an invitation to 测试组织甲, observed 2026-08-12. Source references are the current objectui main checkout, where the routing above still stands — this is not a stale-image artifact.
Related: #8090 (the link that reaches this page is itself broken), #8094 (untranslated strings in the same flow).
The invitation-accept screen tells the invitee nothing about what they are accepting. Observed page (zh), in full:
No organization name, no inviter, no role being granted, no expiry. The user is asked to join "an organization" and cannot tell which one, from whom, or as what — a decision they have no basis to make, and a soft phishing surface (anyone who can send an invite can get a click on an anonymous "join" button).
The twist: a page that shows all of it already exists and is not routed
Two implementations of the same route live in the tree:
apps/console/src/pages/auth/AcceptInvitationPage.tsxpackages/app-shell/src/console/organizations/manage/AcceptInvitationPage.tsxgetInvitation)The router mounts the thin one:
while the richer one renders exactly the missing block:
It is exported (
DefaultAcceptInvitationPagefrompackages/app-shell/src/index.ts:199, and fromconsole/organizations/index.ts) but nothing inapps/consoleimports it. The locale files carry both key families and the comment in every locale already notes the split:So the strings for the good page are translated in 10+ locales and shipped, for a page the console never renders.
Expected
The invitee sees at least the organization name and the role being granted before accepting. Inviter would be a further improvement.
Suggested fix
Route the app-shell page (
DefaultAcceptInvitationPage) and delete the thin duplicate, or port the detail block into the routed one and retire the unused export + its translation keys. Either way one implementation should survive — two pages for one route with different information density is how this drifted.Environment
objectos-ee-deployonhttp://localhost:8080, zh locale, inviteelisi@acme-test.comaccepting an invitation to 测试组织甲, observed 2026-08-12. Source references are the currentobjectuimain checkout, where the routing above still stands — this is not a stale-image artifact.Related: #8090 (the link that reaches this page is itself broken), #8094 (untranslated strings in the same flow).