mirror of
https://github.com/coder/coder.git
synced 2025-07-15 22:20:27 +00:00
fix(site): hide ws proxy on menu when disabled (#11101)
This commit is contained in:
@ -1,32 +1,13 @@
|
|||||||
import { StoryObj, Meta } from "@storybook/react";
|
import { StoryObj, Meta } from "@storybook/react";
|
||||||
import { AccessURLPage } from "./AccessURLPage";
|
import { AccessURLPage } from "./AccessURLPage";
|
||||||
import { HealthLayout } from "./HealthLayout";
|
import { generateMeta } from "./storybook";
|
||||||
import {
|
|
||||||
reactRouterOutlet,
|
|
||||||
reactRouterParameters,
|
|
||||||
} from "storybook-addon-react-router-v6";
|
|
||||||
import { useQueryClient } from "react-query";
|
|
||||||
import { MockHealth } from "testHelpers/entities";
|
|
||||||
|
|
||||||
const meta: Meta = {
|
const meta: Meta = {
|
||||||
title: "pages/Health/AccessURL",
|
title: "pages/Health/AccessURL",
|
||||||
render: HealthLayout,
|
...generateMeta({
|
||||||
parameters: {
|
path: "/health/access-url",
|
||||||
layout: "fullscreen",
|
element: <AccessURLPage />,
|
||||||
reactRouter: reactRouterParameters({
|
}),
|
||||||
routing: reactRouterOutlet(
|
|
||||||
{ path: "/health/access-url" },
|
|
||||||
<AccessURLPage />,
|
|
||||||
),
|
|
||||||
}),
|
|
||||||
},
|
|
||||||
decorators: [
|
|
||||||
(Story) => {
|
|
||||||
const queryClient = useQueryClient();
|
|
||||||
queryClient.setQueryData(["health"], MockHealth);
|
|
||||||
return <Story />;
|
|
||||||
},
|
|
||||||
],
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export default meta;
|
export default meta;
|
||||||
|
@ -1,29 +1,13 @@
|
|||||||
import { StoryObj, Meta } from "@storybook/react";
|
import { StoryObj, Meta } from "@storybook/react";
|
||||||
import { DERPPage } from "./DERPPage";
|
import { DERPPage } from "./DERPPage";
|
||||||
import { HealthLayout } from "./HealthLayout";
|
import { generateMeta } from "./storybook";
|
||||||
import {
|
|
||||||
reactRouterOutlet,
|
|
||||||
reactRouterParameters,
|
|
||||||
} from "storybook-addon-react-router-v6";
|
|
||||||
import { useQueryClient } from "react-query";
|
|
||||||
import { MockHealth } from "testHelpers/entities";
|
|
||||||
|
|
||||||
const meta: Meta = {
|
const meta: Meta = {
|
||||||
title: "pages/Health/DERP",
|
title: "pages/Health/DERP",
|
||||||
render: HealthLayout,
|
...generateMeta({
|
||||||
parameters: {
|
path: "/health/derp",
|
||||||
layout: "fullscreen",
|
element: <DERPPage />,
|
||||||
reactRouter: reactRouterParameters({
|
}),
|
||||||
routing: reactRouterOutlet({ path: "/health/derp" }, <DERPPage />),
|
|
||||||
}),
|
|
||||||
},
|
|
||||||
decorators: [
|
|
||||||
(Story) => {
|
|
||||||
const queryClient = useQueryClient();
|
|
||||||
queryClient.setQueryData(["health"], MockHealth);
|
|
||||||
return <Story />;
|
|
||||||
},
|
|
||||||
],
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export default meta;
|
export default meta;
|
||||||
|
@ -1,36 +1,18 @@
|
|||||||
import { StoryObj, Meta } from "@storybook/react";
|
import { StoryObj, Meta } from "@storybook/react";
|
||||||
import { DERPRegionPage } from "./DERPRegionPage";
|
import { DERPRegionPage } from "./DERPRegionPage";
|
||||||
import { HealthLayout } from "./HealthLayout";
|
|
||||||
import {
|
|
||||||
reactRouterOutlet,
|
|
||||||
reactRouterParameters,
|
|
||||||
} from "storybook-addon-react-router-v6";
|
|
||||||
import { useQueryClient } from "react-query";
|
|
||||||
import { MockHealth } from "testHelpers/entities";
|
import { MockHealth } from "testHelpers/entities";
|
||||||
|
import { generateMeta } from "./storybook";
|
||||||
|
|
||||||
const firstRegionId = Object.values(MockHealth.derp.regions)[0].region
|
const firstRegionId = Object.values(MockHealth.derp.regions)[0].region
|
||||||
?.RegionID;
|
?.RegionID;
|
||||||
|
|
||||||
const meta: Meta = {
|
const meta: Meta = {
|
||||||
title: "pages/Health/DERPRegion",
|
title: "pages/Health/DERPRegion",
|
||||||
render: HealthLayout,
|
...generateMeta({
|
||||||
parameters: {
|
path: "/health/derp/regions/:regionId",
|
||||||
layout: "fullscreen",
|
element: <DERPRegionPage />,
|
||||||
reactRouter: reactRouterParameters({
|
params: { regionId: firstRegionId },
|
||||||
location: { pathParams: { regionId: firstRegionId } },
|
}),
|
||||||
routing: reactRouterOutlet(
|
|
||||||
{ path: `/health/derp/regions/:regionId` },
|
|
||||||
<DERPRegionPage />,
|
|
||||||
),
|
|
||||||
}),
|
|
||||||
},
|
|
||||||
decorators: [
|
|
||||||
(Story) => {
|
|
||||||
const queryClient = useQueryClient();
|
|
||||||
queryClient.setQueryData(["health"], MockHealth);
|
|
||||||
return <Story />;
|
|
||||||
},
|
|
||||||
],
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export default meta;
|
export default meta;
|
||||||
|
@ -1,32 +1,13 @@
|
|||||||
import { StoryObj, Meta } from "@storybook/react";
|
import { StoryObj, Meta } from "@storybook/react";
|
||||||
import { DatabasePage } from "./DatabasePage";
|
import { DatabasePage } from "./DatabasePage";
|
||||||
import { HealthLayout } from "./HealthLayout";
|
import { generateMeta } from "./storybook";
|
||||||
import {
|
|
||||||
reactRouterOutlet,
|
|
||||||
reactRouterParameters,
|
|
||||||
} from "storybook-addon-react-router-v6";
|
|
||||||
import { useQueryClient } from "react-query";
|
|
||||||
import { MockHealth } from "testHelpers/entities";
|
|
||||||
|
|
||||||
const meta: Meta = {
|
const meta: Meta = {
|
||||||
title: "pages/Health/Database",
|
title: "pages/Health/Database",
|
||||||
render: HealthLayout,
|
...generateMeta({
|
||||||
parameters: {
|
path: "/health/database",
|
||||||
layout: "fullscreen",
|
element: <DatabasePage />,
|
||||||
reactRouter: reactRouterParameters({
|
}),
|
||||||
routing: reactRouterOutlet(
|
|
||||||
{ path: "/health/database" },
|
|
||||||
<DatabasePage />,
|
|
||||||
),
|
|
||||||
}),
|
|
||||||
},
|
|
||||||
decorators: [
|
|
||||||
(Story) => {
|
|
||||||
const queryClient = useQueryClient();
|
|
||||||
queryClient.setQueryData(["health"], MockHealth);
|
|
||||||
return <Story />;
|
|
||||||
},
|
|
||||||
],
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export default meta;
|
export default meta;
|
||||||
|
@ -12,22 +12,16 @@ import Tooltip from "@mui/material/Tooltip";
|
|||||||
import CircularProgress from "@mui/material/CircularProgress";
|
import CircularProgress from "@mui/material/CircularProgress";
|
||||||
import { NavLink, Outlet } from "react-router-dom";
|
import { NavLink, Outlet } from "react-router-dom";
|
||||||
import { css } from "@emotion/css";
|
import { css } from "@emotion/css";
|
||||||
import { kebabCase } from "lodash/fp";
|
import kebabCase from "lodash/fp/kebabCase";
|
||||||
import { Suspense } from "react";
|
import { Suspense } from "react";
|
||||||
import { HealthIcon } from "./Content";
|
import { HealthIcon } from "./Content";
|
||||||
import { HealthSeverity } from "api/typesGenerated";
|
import { HealthSeverity } from "api/typesGenerated";
|
||||||
import NotificationsOffOutlined from "@mui/icons-material/NotificationsOffOutlined";
|
import NotificationsOffOutlined from "@mui/icons-material/NotificationsOffOutlined";
|
||||||
|
import { useDashboard } from "components/Dashboard/DashboardProvider";
|
||||||
const sections = {
|
|
||||||
derp: "DERP",
|
|
||||||
access_url: "Access URL",
|
|
||||||
websocket: "Websocket",
|
|
||||||
database: "Database",
|
|
||||||
workspace_proxy: "Workspace Proxy",
|
|
||||||
} as const;
|
|
||||||
|
|
||||||
export function HealthLayout() {
|
export function HealthLayout() {
|
||||||
const theme = useTheme();
|
const theme = useTheme();
|
||||||
|
const dashboard = useDashboard();
|
||||||
const queryClient = useQueryClient();
|
const queryClient = useQueryClient();
|
||||||
const { data: healthStatus } = useQuery({
|
const { data: healthStatus } = useQuery({
|
||||||
...health(),
|
...health(),
|
||||||
@ -36,6 +30,16 @@ export function HealthLayout() {
|
|||||||
const { mutate: forceRefresh, isLoading: isRefreshing } = useMutation(
|
const { mutate: forceRefresh, isLoading: isRefreshing } = useMutation(
|
||||||
refreshHealth(queryClient),
|
refreshHealth(queryClient),
|
||||||
);
|
);
|
||||||
|
const sections = {
|
||||||
|
derp: "DERP",
|
||||||
|
access_url: "Access URL",
|
||||||
|
websocket: "Websocket",
|
||||||
|
database: "Database",
|
||||||
|
workspace_proxy: dashboard.experiments.includes("moons")
|
||||||
|
? "Workspace Proxy"
|
||||||
|
: undefined,
|
||||||
|
} as const;
|
||||||
|
const visibleSections = filterVisibleSections(sections);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
@ -106,13 +110,13 @@ export function HealthLayout() {
|
|||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{healthStatus.healthy
|
{healthStatus.healthy
|
||||||
? Object.keys(sections).some(
|
? Object.keys(visibleSections).some((key) => {
|
||||||
(key) =>
|
const section =
|
||||||
healthStatus[key as keyof typeof sections]
|
healthStatus[key as keyof typeof visibleSections];
|
||||||
.warnings !== null &&
|
return (
|
||||||
healthStatus[key as keyof typeof sections].warnings
|
section.warnings && section.warnings.length > 0
|
||||||
.length > 0,
|
);
|
||||||
)
|
})
|
||||||
? "All systems operational, but performance might be degraded"
|
? "All systems operational, but performance might be degraded"
|
||||||
: "All systems operational"
|
: "All systems operational"
|
||||||
: "Some issues have been detected"}
|
: "Some issues have been detected"}
|
||||||
@ -145,12 +149,13 @@ export function HealthLayout() {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<nav css={{ display: "flex", flexDirection: "column", gap: 1 }}>
|
<nav css={{ display: "flex", flexDirection: "column", gap: 1 }}>
|
||||||
{Object.keys(sections)
|
{Object.keys(visibleSections)
|
||||||
.sort()
|
.sort()
|
||||||
.map((key) => {
|
.map((key) => {
|
||||||
const label = sections[key as keyof typeof sections];
|
const label =
|
||||||
|
visibleSections[key as keyof typeof visibleSections];
|
||||||
const healthSection =
|
const healthSection =
|
||||||
healthStatus[key as keyof typeof sections];
|
healthStatus[key as keyof typeof visibleSections];
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<NavLink
|
<NavLink
|
||||||
@ -218,3 +223,21 @@ export function HealthLayout() {
|
|||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const filterVisibleSections = <T extends object>(sections: T) => {
|
||||||
|
return Object.keys(sections).reduce(
|
||||||
|
(visible, sectionName) => {
|
||||||
|
const sectionValue = sections[sectionName as keyof typeof sections];
|
||||||
|
|
||||||
|
if (!sectionValue) {
|
||||||
|
return visible;
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
...visible,
|
||||||
|
[sectionName]: sectionValue,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
{} as Partial<typeof sections>,
|
||||||
|
);
|
||||||
|
};
|
||||||
|
@ -1,32 +1,13 @@
|
|||||||
import { StoryObj, Meta } from "@storybook/react";
|
import { StoryObj, Meta } from "@storybook/react";
|
||||||
import { WebsocketPage } from "./WebsocketPage";
|
import { WebsocketPage } from "./WebsocketPage";
|
||||||
import { HealthLayout } from "./HealthLayout";
|
import { generateMeta } from "./storybook";
|
||||||
import {
|
|
||||||
reactRouterOutlet,
|
|
||||||
reactRouterParameters,
|
|
||||||
} from "storybook-addon-react-router-v6";
|
|
||||||
import { useQueryClient } from "react-query";
|
|
||||||
import { MockHealth } from "testHelpers/entities";
|
|
||||||
|
|
||||||
const meta: Meta = {
|
const meta: Meta = {
|
||||||
title: "pages/Health/Websocket",
|
title: "pages/Health/Websocket",
|
||||||
render: HealthLayout,
|
...generateMeta({
|
||||||
parameters: {
|
path: "/health/websocket",
|
||||||
layout: "fullscreen",
|
element: <WebsocketPage />,
|
||||||
reactRouter: reactRouterParameters({
|
}),
|
||||||
routing: reactRouterOutlet(
|
|
||||||
{ path: "/health/derp/websocket" },
|
|
||||||
<WebsocketPage />,
|
|
||||||
),
|
|
||||||
}),
|
|
||||||
},
|
|
||||||
decorators: [
|
|
||||||
(Story) => {
|
|
||||||
const queryClient = useQueryClient();
|
|
||||||
queryClient.setQueryData(["health"], MockHealth);
|
|
||||||
return <Story />;
|
|
||||||
},
|
|
||||||
],
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export default meta;
|
export default meta;
|
||||||
|
@ -1,32 +1,13 @@
|
|||||||
import { StoryObj, Meta } from "@storybook/react";
|
import { StoryObj, Meta } from "@storybook/react";
|
||||||
import { WorkspaceProxyPage } from "./WorkspaceProxyPage";
|
import { WorkspaceProxyPage } from "./WorkspaceProxyPage";
|
||||||
import { HealthLayout } from "./HealthLayout";
|
import { generateMeta } from "./storybook";
|
||||||
import {
|
|
||||||
reactRouterOutlet,
|
|
||||||
reactRouterParameters,
|
|
||||||
} from "storybook-addon-react-router-v6";
|
|
||||||
import { useQueryClient } from "react-query";
|
|
||||||
import { MockHealth } from "testHelpers/entities";
|
|
||||||
|
|
||||||
const meta: Meta = {
|
const meta: Meta = {
|
||||||
title: "pages/Health/WorkspaceProxy",
|
title: "pages/Health/WorkspaceProxy",
|
||||||
render: HealthLayout,
|
...generateMeta({
|
||||||
parameters: {
|
path: "/health/workspace-proxy",
|
||||||
layout: "fullscreen",
|
element: <WorkspaceProxyPage />,
|
||||||
reactRouter: reactRouterParameters({
|
}),
|
||||||
routing: reactRouterOutlet(
|
|
||||||
{ path: "/health/workspace-proxy" },
|
|
||||||
<WorkspaceProxyPage />,
|
|
||||||
),
|
|
||||||
}),
|
|
||||||
},
|
|
||||||
decorators: [
|
|
||||||
(Story) => {
|
|
||||||
const queryClient = useQueryClient();
|
|
||||||
queryClient.setQueryData(["health"], MockHealth);
|
|
||||||
return <Story />;
|
|
||||||
},
|
|
||||||
],
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export default meta;
|
export default meta;
|
||||||
|
@ -4,21 +4,32 @@ import {
|
|||||||
reactRouterOutlet,
|
reactRouterOutlet,
|
||||||
RouteDefinition,
|
RouteDefinition,
|
||||||
} from "storybook-addon-react-router-v6";
|
} from "storybook-addon-react-router-v6";
|
||||||
import { MockHealth, MockHealthSettings } from "testHelpers/entities";
|
import {
|
||||||
|
MockBuildInfo,
|
||||||
|
MockEntitlements,
|
||||||
|
MockExperiments,
|
||||||
|
MockHealth,
|
||||||
|
MockHealthSettings,
|
||||||
|
} from "testHelpers/entities";
|
||||||
import { Meta } from "@storybook/react";
|
import { Meta } from "@storybook/react";
|
||||||
import { HEALTH_QUERY_KEY, HEALTH_QUERY_SETTINGS_KEY } from "api/queries/debug";
|
import { HEALTH_QUERY_KEY, HEALTH_QUERY_SETTINGS_KEY } from "api/queries/debug";
|
||||||
|
import { DashboardProvider } from "components/Dashboard/DashboardProvider";
|
||||||
|
import { HealthLayout } from "./HealthLayout";
|
||||||
|
|
||||||
type MetaOptions = {
|
type MetaOptions = {
|
||||||
element: RouteDefinition;
|
element: RouteDefinition;
|
||||||
path: string;
|
path: string;
|
||||||
|
params?: Record<string, string>;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const generateMeta = ({ element, path }: MetaOptions): Meta => {
|
export const generateMeta = ({ element, path, params }: MetaOptions): Meta => {
|
||||||
return {
|
return {
|
||||||
|
render: HealthLayout,
|
||||||
parameters: {
|
parameters: {
|
||||||
layout: "fullscreen",
|
layout: "fullscreen",
|
||||||
reactRouter: reactRouterParameters({
|
reactRouter: reactRouterParameters({
|
||||||
routing: reactRouterOutlet({ path: `/health/${path}` }, element),
|
location: { pathParams: params },
|
||||||
|
routing: reactRouterOutlet({ path }, element),
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
decorators: [
|
decorators: [
|
||||||
@ -28,6 +39,19 @@ export const generateMeta = ({ element, path }: MetaOptions): Meta => {
|
|||||||
queryClient.setQueryData(HEALTH_QUERY_SETTINGS_KEY, MockHealthSettings);
|
queryClient.setQueryData(HEALTH_QUERY_SETTINGS_KEY, MockHealthSettings);
|
||||||
return <Story />;
|
return <Story />;
|
||||||
},
|
},
|
||||||
|
(Story) => {
|
||||||
|
const queryClient = useQueryClient();
|
||||||
|
queryClient.setQueryData(["buildInfo"], MockBuildInfo);
|
||||||
|
queryClient.setQueryData(["entitlements"], MockEntitlements);
|
||||||
|
queryClient.setQueryData(["experiments"], MockExperiments);
|
||||||
|
queryClient.setQueryData(["appearance"], MockExperiments);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<DashboardProvider>
|
||||||
|
<Story />
|
||||||
|
</DashboardProvider>
|
||||||
|
);
|
||||||
|
},
|
||||||
],
|
],
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
Reference in New Issue
Block a user