Skip to content

feat(console): add enterprise-only license banner#6342

Merged
otavio merged 2 commits into
masterfrom
feature/enterprise-license-banner
May 20, 2026
Merged

feat(console): add enterprise-only license banner#6342
otavio merged 2 commits into
masterfrom
feature/enterprise-license-banner

Conversation

@luannmoreira
Copy link
Copy Markdown
Member

What

Adds a persistent status banner to the React console AppLayout that
alerts enterprise users when the instance license is missing, expired, or
nearing expiration.

Why

Enterprise deployments are self-managed — when the license is invalid the
instance silently degrades. Users need an actionable in-product signal
rather than discovering the problem after the fact.

Cloud is intentionally excluded: in that environment the license is managed
by the provider and end users have no path to upload a new one.

Changes

  • api/license.ts: thin wrapper around GET /admin/api/license,
    typed against the generated GetLicenseResponses[200]
  • stores/licenseStore.ts: Zustand store that fetches on demand and
    computes daysUntilExpiration; 403/network errors are silently swallowed
    so the banner never appears for non-admin users or in non-enterprise builds
  • LicenseBanner.tsx: animated collapse banner mounted in AppLayout
    above the main content area. Severity is split by intent — a missing
    license is an error (red/role="alert"), while expired, grace-period, and
    about-to-expire states are warnings (yellow/role="status"). The CTA
    renders as an upload link for admins and as "Contact your administrator"
    for non-admins. aria-hidden={!visible} keeps the collapsed content out
    of the accessibility tree.
  • LicenseBanner.test.tsx: 23 unit tests covering visibility rules,
    severity mapping, message copy, admin/non-admin action, and fetch
    lifecycle.

@luannmoreira luannmoreira requested a review from a team as a code owner May 19, 2026 20:37
@github-actions
Copy link
Copy Markdown

github-actions Bot commented May 19, 2026

Claude finished @luannmoreira's task in 54s —— View job


Code Review Complete

Reviewed 5 files. 3 inline issues posted (2 high, 1 medium).

# Severity File Issue
1 high api/license.ts GetLicenseResponses[200] — wrong type name, rest of codebase uses GetLicenseResponse (singular)
2 high stores/licenseStore.ts Dual cache — zustand store is never invalidated after license upload, causing stale banner
3 medium LicenseBanner.test.tsx Weak assertion in hidden-state test would pass even if banner were incorrectly visible

Additional notes

The core recommendation for issues 1 and 2 is to remove api/license.ts and stores/licenseStore.ts entirely, and instead reuse the existing useAdminLicense hook in LicenseBanner. This hook already provides cache invalidation on license upload, admin gating, deduplication, and uses the correct generated SDK client. The existing getLicenseAlertConfig() in utils/license.ts also already maps license flags to severity/message and could be reused to avoid duplicating that logic.


If you've addressed the feedback and want a new review, tag @shellhub-io/admin and a team member can trigger it.

Comment thread ui-react/apps/console/src/api/license.ts Outdated
Comment thread ui-react/apps/console/src/stores/licenseStore.ts Outdated
Comment thread ui-react/apps/console/src/components/common/__tests__/LicenseBanner.test.tsx Outdated
@luannmoreira luannmoreira force-pushed the feature/enterprise-license-banner branch 2 times, most recently from 00f8628 to 96601c8 Compare May 19, 2026 21:21
@gustavosbarreto
Copy link
Copy Markdown
Member

/review

@github-actions
Copy link
Copy Markdown

github-actions Bot commented May 20, 2026

Claude finished @gustavosbarreto's task in 11m 22s —— View job


Code Review Complete

Reviewed 3 files. 3 inline issues posted (3 high).

# Severity File Issue
1 high LicenseBanner.tsx Missing !cloud guard — banner will incorrectly show in cloud deployments where both enterprise and cloud are true
2 high LicenseBanner.test.tsx False-pass: "hidden while loading" test doesn't actually verify the isLoading guard (same pattern at line 101 for isError)
3 high LicenseBanner.test.tsx False-pass: "hidden when query fails" test doesn't actually verify the isError guard

Additional notes

The previous review's three issues (wrong type name, dual cache, weak assertion) have all been addressed — api/license.ts and stores/licenseStore.ts were removed and the component now correctly uses the existing useAdminLicense hook.


If you've addressed the feedback and want a new review, tag @shellhub-io/admin and a team member can trigger it.

Comment thread ui-react/apps/console/src/components/common/LicenseBanner.tsx Outdated
@luannmoreira luannmoreira force-pushed the feature/enterprise-license-banner branch from 0d51de6 to 2c10c56 Compare May 20, 2026 19:05
@luannmoreira luannmoreira force-pushed the feature/enterprise-license-banner branch from 2c10c56 to dacbedc Compare May 20, 2026 19:18
@otavio
Copy link
Copy Markdown
Member

otavio commented May 20, 2026

/review

@github-actions
Copy link
Copy Markdown

github-actions Bot commented May 20, 2026

Claude finished @otavio's task in 57s —— View job


Code Review Complete

Reviewed 3 files across code quality, security, testing, TypeScript/React patterns, and architecture — no issues found.

The previous review's three issues (missing !cloud guard, false-pass isLoading test, false-pass isError test) have all been correctly addressed:

  • isEnterprise now uses getConfig().enterprise && !getConfig().cloud, matching the backend pattern
  • Both the isLoading and isError hidden-state tests now pass data: null so the guard under test is the actual cause of visible = false
  • A new test case covers the cloud: true + enterprise: true scenario

The code looks good as-is.


If you push additional changes and want a new review, tag @shellhub-io/admin and a team member can trigger it.

@otavio otavio merged commit 305a0fd into master May 20, 2026
11 checks passed
@otavio otavio deleted the feature/enterprise-license-banner branch May 20, 2026 21:03
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants