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
@@ -12,6 +12,11 @@ vi.mock('@/context/LicenseContext', () => ({
useLicense: () => useLicenseMock(),
}));
const useExperimentalMock = vi.fn(() => ({ experimental: true, experimentalReady: true }));
vi.mock('@/hooks/useExperimental', () => ({
useExperimental: () => useExperimentalMock(),
}));
vi.mock('@/lib/utils', async () => {
const actual = await vi.importActual<typeof import('@/lib/utils')>('@/lib/utils');
return {
@@ -39,6 +44,8 @@ function statusJson(status: number, payload: unknown = {}): Response {
beforeEach(() => {
apiFetchMock.mockReset();
useLicenseMock.mockReset();
useExperimentalMock.mockReset();
useExperimentalMock.mockReturnValue({ experimental: true, experimentalReady: true });
});
afterEach(() => {
@@ -91,4 +98,24 @@ describe('useMeshDataPlane', () => {
expect(result.current.status).toBeNull();
expect(result.current.loading).toBe(false);
});
it('does not fetch when paid but experimental discovery is off', async () => {
useLicenseMock.mockReturnValue({ isPaid: true });
useExperimentalMock.mockReturnValue({ experimental: false, experimentalReady: true });
const { result } = renderHook(() => useMeshDataPlane());
await act(async () => { await Promise.resolve(); await Promise.resolve(); });
expect(apiFetchMock).not.toHaveBeenCalled();
expect(result.current.status).toBeNull();
expect(result.current.loading).toBe(false);
});
it('does not fetch while experimental metadata is still loading', async () => {
useLicenseMock.mockReturnValue({ isPaid: true });
useExperimentalMock.mockReturnValue({ experimental: false, experimentalReady: false });
const { result } = renderHook(() => useMeshDataPlane());
await act(async () => { await Promise.resolve(); await Promise.resolve(); });
expect(apiFetchMock).not.toHaveBeenCalled();
expect(result.current.status).toBeNull();
});
});