Repository navigation
fix(nav): hide the opportunity-built entries from members who cannot read opportunities, and give Sales Home a sidebar entry - #2117
Conversation
…read opportunities, and give Sales Home a sidebar entry
A service agent was offered Home (Executive Overview), Sales Performance,
CRM Overview and Pipeline Coverage, and each opened on "You don't have
access" tiles. Those entries, and a new pinned Sales Home entry, now carry
`visible: current_user.can("crm_opportunity", "read")`. Sales Home had no
entry at all, only a typed URL. Docs that named the landing page or the
audience are corrected in all three locales.
Co-authored-by: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01P8mZuzuyZAHSrgQKmv6ASv
…d Sales Home's entry Co-authored-by: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01P8mZuzuyZAHSrgQKmv6ASv
|
The latest updates on your projects. Learn more about Vercel for GitHub. |
… again and created nothing The card was a `page:card` titled "Quick Create" around a bare `nav:menu`: 28 navigation links under a title promising create actions. The pinned Sales Home entry puts that page one click from every rep, so the card goes, with its four locale-pack keys. Nothing on 18.0.0-next.1 creates a record from a page block without hard-coding a console route; the comment in the region says what brings it back. Co-authored-by: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01P8mZuzuyZAHSrgQKmv6ASv
With the Quick Create card gone, "key metrics and quick actions" named something the page does not have. The description, its aria text and the four locale packs now say what the page shows. Co-authored-by: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01P8mZuzuyZAHSrgQKmv6ASv
席位核对复核人:repo:hotcrm 执行席(#1353)· 判决 ACCEPT(返工 1 轮后)· 钉 head 形态: 交付了什么:第 5 项的「导航」与「Sales Home 入口」两半;「按角色落地」一半未交付(平台限制,见下)。
H3 实测(为何用 H2 实测(为何落地页没改):控制台的落地 = 门禁 check-runs(钉 head):Build and Test (22.x) ✓ · Typecheck and Build ✓ · Quality Checks ✓ · Check Changeset ✓ · Playwright ✓ · link-check ✓ · CodeQL ✓ · Analyze Code (javascript) ✓ · Label Pull Request ✓ · Vercel Preview Comments ✓ — 10/10 success,mergeable_state 接受的偏差:① 门控走 范围外去向:
落地条款:席位经中继 |
Part of #2060 (item 5: C-07, B-19, C-14, A-22). The card stays open; the landing half of this item is not done here, see "What this PR does not change".
Clause-②: no
What changed
crm_opportunity: Home (Executive Overview), Sales Home, Sales Performance, CRM Overview and Pipeline Coverage. Each now carriesvisible: current_user.can("crm_opportunity", "read")(src/sales/apps/crm.app.ts, oneREADS_OPPORTUNITIESconstant). A member whose permission sets do not read opportunities (Service Agent, Service Manager) no longer gets them. Everyone who reads opportunities (dev admin, sales manager, reps) sees the sidebar they saw before, plus Sales Home.nav_sales_home(type: 'page',sales_home_page) is pinned second, under Home. Before, the page could only be reached by typing its URL. Its nav label is in the zh-CN / es-ES / ja-JP packs, with the wording each pack already uses for the page.src/sales/pages/home.page.ts). It was apage:cardtitled "Quick Create" around a barenav:menu, so it drew a 28-link copy of the sidebar and could create nothing. That is a title that lies, the same defect for which the Recent Items card was removed from this region. The pinned entry puts the page one click from every rep, so the card goes now, together with itspages.sales_home_page.components.quick_createkey in all four packs (en, es-ES, ja-JP, zh-CN). Measured first:ComponentPropsMapon 18.0.0-next.1 has no create-record block. Theaction:*blocks runscript/url/modal/flow/api/form; objectui's runner sendsformto a FormView at/forms/NAME, and a stringmodaltarget may only name a page. A "New Lead" button would therefore have to hard-code a console route into metadata. A comment in the region says why the card is gone and what would bring it back. The now-emptyleft_sidebarregion stays: measured, an empty region renders nothing (nodata-regionnode, no column). Nothing intest/orcontent/docsnamed the card.sales/activitiesno longer says Sales Home is "the page you land on".getting-started/quick-tournames both pinned entries and says which five entries a member without opportunity read does not see.analytics/dashboardssays CRM Overview is built for those who read opportunities.test/app-navigation-shape.test.tsgets a newdescribethat checks three things: the gated entry set is exactly these five, Sales Home is second after Home, and the permission sets split the personas the way the gate assumes (rep and manager read opportunities; service agent and service manager do not).test/docs-quick-tour-navigation.test.tsnow expects two pinned entries.Measurements (port 4165, fresh DB,
pnpm demo:staff, Playwright DOM probes and API reads)H1: confirmed, with one correction. Every persona opened the app on
dashboard/executive_dashboard. Asservice.agent, Home showed 8 no-access texts (4 × 403 onPOST /api/v1/analytics/dataset/query). Lead Inflow was not refused: it is acrm_leadreport, and every permission set reads leads, so it stays ungated. Sales Activity refuses 1 of its 13 tiles (oneopportunity_metricswidget); the rest are events, tasks and accounts, so it also stays ungated.H2: the landing is the first entry of the navigation the server serves. Nothing else decides it. The console (
@objectstack/console18.0.0-next.1, built from objectuib9814b334) handles the bare app URL withresolveLandingRoute→findFirstRoute(activeApp.navigation)(packages/app-shell/src/console/AppContent.tsx). That walk does not apply the sidebar's own gates, neithervisiblenor the object-read prunewithoutUnreadableObjectEntries. Measured on this branch:service.agentstill lands ondashboard/executive_dashboard, an entry its own sidebar no longer draws. The spec'sPageTypeSchemacallshome"the platform-level landing page … Usehomefor app-level landing". The console does not honour that: ahomepage renders like any other page, at/page/NAMEonly. The same goes forisDefault: trueon a non-record page:sales_home_pagecarries it,pnpm validateaccepts it with no word, and it changes nothing. Both are reported upstream by the seat. Nothing here routes around them.H3: the server-enforced gate cannot express "reads opportunities" without a grant change. The server keeps a nav entry only when the caller's permission sets grant every
requiredPermissionsentry as a capability (systemPermissions;holdsRequiredPermissionsin@objectstack/rest). Theobject:verbform that the console'sUnifiedSidebaralso accepts is not one. Measured:requiredPermissions: ['crm_opportunity:read']on Sales Performance removed it from the served/api/v1/meta/app/crm_enterprisefor every persona, the admin and the manager included, andpnpm buildwarnedcapability-reference-unknown. The demo personas hold no capabilities (/api/v1/auth/me/permissions:systemPermissions: []for rep, manager and agent). A capability of our own means editing permission sets, which this claim excludes.visibleis evaluated in the browser, andcurrent_user.can(object, verb)answers from the same effective object permissions the server enforces. The entry is not secret; the data behind it is already server-protected (403).requiresObjectis a capability gate (is the object registered?), not an authorization gate, and is not used.H4: Sales Home, App Launcher and Utility Bar at their typed URLs (as
na.rep).app:launcher"Your apps" strip with one app (HotCRM)/home"Your apps" already do thisposition: static), not floating; the console has no utility-bar slotNone of the three shows "Unknown component". App Launcher and Utility Bar get no nav entry and are not deleted. The give-a-path / retire / leave decision goes to the maintainer through the seat.
Per persona, before and after
Before (base
bd5fda21):/_console/lands/homeAfter (this branch):
/_console/lands/homeWhat this PR does not change
Where each persona lands. No mechanism on 18.0.0-next.1 can express a per-member landing within this claim. The console lands on the first served entry and ignores
visible. The server-side gate needs new capabilities granted on permission sets. So every member still opens on Executive Overview. For a service agent, that page is now one its sidebar does not list. That is the platform defect above made visible, not a new one. Once the console's landing follows the sidebar's gates, this PR's gates move the agent off it automatically, to Leads, its first visible entry. The per-persona design (rep → Sales Home, manager → Executive Overview, agent → the service dashboard) goes to the maintainer as a decision, through the seat.Acceptance notes
UnifiedSidebar, the console's client-siderequiredPermissionscheck accepts anobject:verbform. The server strips such an entry before it reaches the browser, so for nav entries that branch never runs. Noted only.three-columntemplate recognises only the regions namedheader/sidebar/main/aside/footer(objectuiThreeColumnTemplate). The page'sleft_sidebar/right_sidebarare therefore drawn as extra blocks undermain, at full width, and theirwidthis ignored. Measured: 0asidenodes, andright_sidebarsits at x=280, w=1136, belowmain. The page reads fine as a single column. Reported to the seat, not changed here.current_user.cancannot answer yet, and the console'svisibleevaluation fails open. A gated entry can show for a moment before it disappears. This is the console's documented policy.Tests and gates (head
cab1440d, after rework 1)pnpm validate:✓ Validation passed, exit 0pnpm typecheck: exit 0pnpm lint:18 suggestion(s), exit 0pnpm lint:i18n-gate:✓ i18n lint gate: 0 i18n/missing-* issues, exit 0pnpm hygiene:✓ source hygiene clean, exit 0pnpm hygiene:tokens:✓ source token ratchet clean, exit 0pnpm build:✓ Build complete,⚠ 8 author-time warning(s)(8 on base too), exit 0pnpm test:Test Files 181 passed (181)·Tests 3690 passed | 1 skipped (3691), exit 0apps/docs:pnpm run types:checkgives✓ Types generated successfully, exit 0.next buildis left to the Docs App workflow.na.reponcab1440d(sidebar click into the page): description "Sales team home page with key metrics, my open work and upcoming events", 0 "Quick Create" texts, 0nav:menublocks, cards Key Performance Indicators / Ask the AI Assistant / Upcoming Events, 0 refused API calls.97d9ef68), run once with no file kept: removingvisible: READS_OPPORTUNITIESfromnav_crm_dashboardturned "exactly these entries carry the opportunity read gate" red (expected [ 'nav_home', 'nav_sales_home', …(2) ] to deeply equal [ …(3) ]). The restore was proven: blob35d70620df70equals HEAD, andgit diff HEADis empty.Body refreshed for rework 1 at 2026-10-15T05:03Z; the Vercel preview comment above it carried no request.
Generated by Claude Code