Skip to content

feat(ui): gate Purchases + Inventory pages on view:purchases (closes #1000) - #1003

Merged
cristim merged 1 commit into
feat/multicloud-web-frontendfrom
feat/1000-gate-inaccessible-pages
Jun 6, 2026
Merged

cristim merged 1 commit into
feat/multicloud-web-frontendfrom
feat/1000-gate-inaccessible-pages

Conversation

@cristim

@cristim cristim commented Jun 5, 2026 •

Copy link
Copy Markdown
Member

Summary

  • Adds requires-purchases CSS class (mirrors admin-only pattern) to the Purchases and Inventory & Coverage nav entries so they are hidden by default and shown only when canAccess('view', 'purchases') is true.
  • updateUserUI() in auth.ts toggles .requires-purchases elements visible after login, exactly as it does for .admin-only.
  • switchTab() in navigation.ts guards both the purchases and inventory cases: when the user lacks the permission, renderNoAccess() places a friendly empty-state paragraph and returns early so no API call is fired. Covers direct URL navigation (including legacy /history and /ri-exchange aliases).
  • Reuses the existing gating mechanism verbatim; no new patterns introduced.

Permission string used: view:purchases (confirmed from backend handler comments in internal/api/handler_inventory.go and handler_history.go).

closes #1000

Test plan

  • auth.test.ts: 3 new tests covering requires-purchases visibility for user-with-permission, read-only-user-without-permission, and admin
  • navigation.test.ts: 6 new tests in view:purchases gate describe block - verify no API calls fired and no-access placeholder rendered for both purchases and inventory tabs; verify normal operation when permission is present
  • All 71 test suites pass (2367 passed, 1 pre-existing skip)
  • tsc --noEmit clean
  • npm run build succeeds

Summary by CodeRabbit

  • New Features

    • Permission-based access control now gates the Purchases feature. Users lacking appropriate permissions will not see the Purchases navigation tab. Attempting to access restricted sections displays an access denied message.
  • Tests

    • Added test coverage for permission-based visibility and navigation behavior across all permission states.

…1000)

A read-only user (no view:purchases) was shown raw "permission denied"
backend error banners on the Purchases page and the Inventory & Coverage
pages (Active Commitments, Coverage, RI Exchange).

Fix: reuse the existing admin-only CSS/JS pattern with a new
requires-purchases class. updateUserUI() in auth.ts now toggles the
Purchases and Inventory nav entries visible only when
canAccess('view', 'purchases') is true. switchTab() in navigation.ts
guards both cases: when the user lacks the permission, renderNoAccess()
places a friendly "You do not have access" empty-state paragraph and
returns early so no API call is fired. Direct URL navigation (including
legacy /history and /ri-exchange aliases) hits the same guard.

No regression for users who have view:purchases (admins, standard users).
@cristim cristim added triaged Item has been triaged priority/p3 Polish / idea / may never ship severity/low Minor harm urgency/eventually No deadline impact/few Limited audience effort/m Days type/feat New capability labels Jun 5, 2026
@cristim

cristim commented Jun 5, 2026

Copy link
Copy Markdown
Member Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jun 5, 2026 •

Copy link
Copy Markdown
Contributor
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@coderabbitai

coderabbitai Bot commented Jun 5, 2026 •

Copy link
Copy Markdown
Contributor

Linter diff in the way? Review this PR in Change Stack to focus on meaningful changes and expand context only when needed.

Review Change Stack

Caution

Review failed

The pull request is closed.

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: e823092c-96ed-4d4d-a707-eda87ac817a1

📥 Commits

Reviewing files that changed from the base of the PR and between 5f037eb and 1e9f417.

📒 Files selected for processing (6)
  • frontend/src/__tests__/auth.test.ts
  • frontend/src/__tests__/navigation.test.ts
  • frontend/src/auth.ts
  • frontend/src/index.html
  • frontend/src/navigation.ts
  • frontend/src/styles/base.css

📝 Walkthrough

Walkthrough

This PR implements permission-gated navigation for purchases-related pages and tabs. Users lacking view:purchases permission now see hidden navigation or a friendly "no access" message instead of backend permission-denied errors. The implementation spans CSS styling, authorization checks in the auth and navigation modules, and comprehensive test coverage.

Changes

Purchases Permission Gating

Layer / File(s) Summary
CSS styling and HTML markup for permission gating
frontend/src/styles/base.css, frontend/src/index.html
.requires-purchases CSS rules hide elements by default and show them when the visible class is toggled. The Purchases sidebar tab is marked with the requires-purchases class.
Auth module permission visibility toggle
frontend/src/auth.ts
updateUserUI() imports canAccess and toggles the visible class on all .requires-purchases elements based on canAccess('view', 'purchases').
Navigation module tab-access gating and no-access placeholder
frontend/src/navigation.ts
Added renderNoAccess() helper to display a friendly "no access" message. Two switchTab branches check canAccess('view', 'purchases') and render the placeholder or exit early on denial, preventing data-load errors.
Auth tests for updateUserUI visibility
frontend/src/__tests__/auth.test.ts
Test DOM fixture includes requires-purchases elements. Three new cases verify visibility for users with view:purchases, read-only users without it, and admins with admin:* coverage.
Navigation tests for tab-access gating
frontend/src/__tests__/navigation.test.ts
Default canAccess mock and new view:purchases gate test suite toggle access to verify that tab switching either blocks loading functions and shows "no access" text, or allows loading normally.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

  • LeanerCloud/CUDly#922: The main PR's permission checks rely on canAccess('view','purchases'), which was refactored in this PR to consult fetched effectivePermissions from the /api/auth/me/permissions endpoint.
  • LeanerCloud/CUDly#387: Both PRs modify the Purchases tab switching behavior in frontend/src/navigation.ts, with the main PR adding permission-based access gating that blocks loading, while this PR adds auto-loading on tab switch.
  • LeanerCloud/CUDly#452: This PR extends PR #452's permissions.ts and canAccess helper by applying permission checks in auth.ts and navigation.ts to hide and gate purchases UI, building on the existing permission-gating pattern.

Suggested labels

priority/p2, severity/medium, urgency/this-sprint, impact/many

Poem

A rabbit hops through the nav with care,
Checking permissions here and there,
Hide the tabs they cannot see,
Show "no access" gracefully! 🐰
No more errors—just a friendly gate,
Purchases users won't have to wait.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/1000-gate-inaccessible-pages

Comment @coderabbitai help to get the list of available commands and usage tips.

@cristim

cristim commented Jun 6, 2026

Copy link
Copy Markdown
Member Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jun 6, 2026 •

Copy link
Copy Markdown
Contributor
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@cristim
cristim merged commit 991eb52 into feat/multicloud-web-frontend Jun 6, 2026
5 of 6 checks passed
@cristim
cristim deleted the feat/1000-gate-inaccessible-pages branch July 27, 2026 11:09
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

effort/m Days impact/few Limited audience priority/p3 Polish / idea / may never ship severity/low Minor harm triaged Item has been triaged type/feat New capability urgency/eventually No deadline

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant