mirror of
https://github.com/Studio-Saelix/sencho.git
synced 2026-08-18 06:23:18 +00:00
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:
@@ -2,6 +2,8 @@ import { describe, it, expect } from 'vitest';
|
||||
import {
|
||||
authzReady,
|
||||
isViewHidden,
|
||||
isFleetTabHidden,
|
||||
isSettingsSectionHidden,
|
||||
normalizeHiddenView,
|
||||
type ReachabilityContext,
|
||||
} from './reachability';
|
||||
@@ -16,6 +18,8 @@ function ctx(over: Partial<ReachabilityContext> = {}): ReachabilityContext {
|
||||
containerLabelsEnabled: true,
|
||||
permissionsStatus: 'ready',
|
||||
licenseStatus: 'ready',
|
||||
experimental: false,
|
||||
experimentalReady: true,
|
||||
...over,
|
||||
};
|
||||
}
|
||||
@@ -46,7 +50,41 @@ describe('reachability', () => {
|
||||
});
|
||||
|
||||
it('preserves paid views when license metadata failed', () => {
|
||||
const licenseError = ctx({ licenseStatus: 'error' });
|
||||
const licenseError = ctx({ licenseStatus: 'error', experimental: true });
|
||||
expect(isViewHidden('host-console', licenseError)).toBe(false);
|
||||
});
|
||||
|
||||
it('does not apply experimental hide to host-console until experimentalReady', () => {
|
||||
const loading = ctx({ experimental: false, experimentalReady: false, isPaid: true, isAdmin: true });
|
||||
expect(isViewHidden('host-console', loading)).toBe(false);
|
||||
});
|
||||
|
||||
it('hides host-console when experimental is ready and off even for paid admin', () => {
|
||||
const off = ctx({ experimental: false, experimentalReady: true, isPaid: true, isAdmin: true });
|
||||
expect(isViewHidden('host-console', off)).toBe(true);
|
||||
expect(normalizeHiddenView('host-console', off)).toBe('dashboard');
|
||||
});
|
||||
|
||||
it('keeps host-console when experimental is on for paid admin', () => {
|
||||
const on = ctx({ experimental: true, experimentalReady: true, isPaid: true, isAdmin: true });
|
||||
expect(isViewHidden('host-console', on)).toBe(false);
|
||||
});
|
||||
|
||||
it('hides routing and secrets fleet tabs only after experimentalReady when off', () => {
|
||||
const loading = ctx({ experimental: false, experimentalReady: false });
|
||||
expect(isFleetTabHidden('routing', loading)).toBe(false);
|
||||
expect(isFleetTabHidden('secrets', loading)).toBe(false);
|
||||
|
||||
const off = ctx({ experimental: false, experimentalReady: true });
|
||||
expect(isFleetTabHidden('routing', off)).toBe(true);
|
||||
expect(isFleetTabHidden('secrets', off)).toBe(true);
|
||||
expect(isFleetTabHidden('deployments', off)).toBe(false);
|
||||
expect(isFleetTabHidden('federation', off)).toBe(false);
|
||||
expect(isFleetTabHidden('actions', off)).toBe(false);
|
||||
});
|
||||
|
||||
it('does not hide fleet-mesh settings for experimental off', () => {
|
||||
const off = ctx({ experimental: false, experimentalReady: true, isAdmin: true });
|
||||
expect(isSettingsSectionHidden('fleet-mesh', off)).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user