chore(ui): hide Mesh, Fleet Secrets, and Host Console behind experimental discovery (#1624)

Gate Routing, Secrets, Host Console, and Mesh dashboard/settings surfaces on the existing useExperimental readiness flag so immature operator surfaces stay out of the default UI while paid and admin backend gates remain unchanged.
This commit is contained in:
Anso
2026-07-13 11:55:50 -04:00
committed by GitHub
parent 9b3f5c5a90
commit 0cd03c6f87
23 changed files with 578 additions and 62 deletions
+27 -2
View File
@@ -15,6 +15,10 @@ export interface ReachabilityContext {
containerLabelsEnabled: boolean;
permissionsStatus: ReadinessStatus;
licenseStatus: ReadinessStatus;
/** Gateway SENCHO_EXPERIMENTAL discovery flag. */
experimental: boolean;
/** True once /meta experimental has settled (success or fail-closed). */
experimentalReady: boolean;
}
/** RBAC/tier gates apply only when permission and license metadata are ready. */
@@ -22,6 +26,15 @@ export function authzReady(ctx: ReachabilityContext): boolean {
return ctx.permissionsStatus === 'ready' && ctx.licenseStatus === 'ready';
}
/**
* Experimental discovery gates apply only after /meta settles. Before that,
* treat surfaces as not-yet-hidden so URL sync does not rewrite enabled
* deep links during cold load.
*/
export function experimentalDiscoveryReady(ctx: ReachabilityContext): boolean {
return ctx.experimentalReady;
}
/** Role/tier hidden views normalize away only when permission and license metadata are ready. */
export function isViewHidden(view: ActiveView, ctx: ReachabilityContext): boolean {
if (!authzReady(ctx)) return false;
@@ -29,11 +42,17 @@ export function isViewHidden(view: ActiveView, ctx: ReachabilityContext): boolea
if (!ctx.isAdmin && view === 'global-observability') return true;
if (!ctx.isAdmin && (view === 'auto-updates' || view === 'scheduled-ops')) return true;
if (!ctx.can('node:read') && view === 'fleet') return true;
if (view === 'host-console') {
// Defer experimental hide until ready so enabled deep links survive cold load.
if (experimentalDiscoveryReady(ctx) && !ctx.experimental) return true;
if (!ctx.isPaid) return true;
if (!ctx.isAdmin) return true;
return false;
}
if (!ctx.isPaid) {
if (view === 'host-console' || view === 'audit-log') return true;
if (view === 'audit-log') return true;
} else {
if (view === 'audit-log' && !ctx.can('system:audit')) return true;
if (view === 'host-console' && !ctx.isAdmin) return true;
}
return false;
}
@@ -48,6 +67,10 @@ export function isViewCapabilityLocked(view: ActiveView, ctx: ReachabilityContex
export function isFleetTabHidden(tab: FleetTab, ctx: ReachabilityContext): boolean {
if (!authzReady(ctx)) return false;
if (tab === 'container-labels' && !ctx.containerLabelsEnabled) return true;
// Defer experimental hide until ready (same cold-load contract as host-console).
if ((tab === 'routing' || tab === 'secrets') && experimentalDiscoveryReady(ctx) && !ctx.experimental) {
return true;
}
return false;
}
@@ -58,6 +81,8 @@ export function isSettingsSectionHidden(section: SectionId, ctx: ReachabilityCon
if (ctx.isRemote && item.hiddenOnRemote) return true;
if (item.adminOnly && !ctx.isAdmin) return true;
if (item.tier === 'paid' && !ctx.isPaid) return true;
// fleet-mesh stays reachable: snapshot_documentation lives there even when
// Mesh discovery is off.
return false;
}