Skip to content

feat(site): add health warning and a health monitor page #8844

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 20 commits into from
Aug 2, 2023
Merged
Show file tree
Hide file tree
Changes from 16 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 12 additions & 11 deletions .github/workflows/typos.toml
Original file line number Diff line number Diff line change
Expand Up @@ -17,15 +17,16 @@ encrypter = "encrypter"

[files]
extend-exclude = [
"**.svg",
"**.png",
"**.lock",
"go.sum",
"go.mod",
# These files contain base64 strings that confuse the detector
"**XService**.ts",
"**identity.go",
"scripts/ci-report/testdata/**",
"**/*_test.go",
"**/*.test.tsx"
"**.svg",
"**.png",
"**.lock",
"go.sum",
"go.mod",
# These files contain base64 strings that confuse the detector
"**XService**.ts",
"**identity.go",
"scripts/ci-report/testdata/**",
"**/*_test.go",
"**/*.test.tsx",
"site/testHelpers/**/*.ts",
]
6 changes: 4 additions & 2 deletions coderd/apidoc/docs.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 4 additions & 2 deletions coderd/apidoc/swagger.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 4 additions & 0 deletions codersdk/deployment.go
Original file line number Diff line number Diff line change
Expand Up @@ -1871,6 +1871,9 @@ const (
// Insights page
ExperimentTemplateInsightsPage Experiment = "template_insights_page"

// Deployment health page
ExperimentDeploymentHealthPage Experiment = "deployment_health_page"

// Add new experiments here!
// ExperimentExample Experiment = "example"
)
Expand All @@ -1881,6 +1884,7 @@ const (
// not be included here and will be essentially hidden.
var ExperimentsAll = Experiments{
ExperimentTemplateInsightsPage,
ExperimentDeploymentHealthPage,
}

// Experiments is a list of experiments that are enabled for the deployment.
Expand Down
1 change: 1 addition & 0 deletions docs/api/schemas.md

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 3 additions & 0 deletions site/src/AppRouter.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -183,6 +183,7 @@ const TemplateInsightsPage = lazy(
() =>
import("./pages/TemplatePage/TemplateInsightsPage/TemplateInsightsPage"),
)
const HealthPage = lazy(() => import("./pages/HealthPage/HealthPage"))

export const AppRouter: FC = () => {
return (
Expand All @@ -197,6 +198,8 @@ export const AppRouter: FC = () => {
<Route element={<DashboardLayout />}>
<Route index element={<IndexPage />} />

<Route path="health" element={<HealthPage />} />

<Route path="gitauth/:provider" element={<GitAuthPage />} />

<Route path="workspaces" element={<WorkspacesPage />} />
Expand Down
12 changes: 12 additions & 0 deletions site/src/api/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1405,3 +1405,15 @@ export const getInsightsTemplate = async (
const response = await axios.get(`/api/v2/insights/templates?${params}`)
return response.data
}

export const getHealth = () => {
return axios.get<{
healthy: boolean
time: string
coder_version: string
derp: { healthy: boolean }
access_url: { healthy: boolean }
websocket: { healthy: boolean }
database: { healthy: boolean }
}>("/api/v2/debug/health")
}
2 changes: 2 additions & 0 deletions site/src/api/typesGenerated.ts

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions site/src/components/Dashboard/DashboardLayout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import Box from "@mui/material/Box"
import InfoOutlined from "@mui/icons-material/InfoOutlined"
import Button from "@mui/material/Button"
import { docs } from "utils/docs"
import { HealthBanner } from "./HealthBanner"

export const DashboardLayout: FC = () => {
const styles = useStyles()
Expand All @@ -30,6 +31,7 @@ export const DashboardLayout: FC = () => {

return (
<>
<HealthBanner />
<ServiceBanner />
{canViewDeployment && <LicenseBanner />}

Expand Down
45 changes: 45 additions & 0 deletions site/src/components/Dashboard/HealthBanner.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import { Alert } from "components/Alert/Alert"
import { Link as RouterLink } from "react-router-dom"
import Link from "@mui/material/Link"
import { colors } from "theme/colors"
import { useQuery } from "@tanstack/react-query"
import { getHealth } from "api/api"
import { useDashboard } from "./DashboardProvider"

export const HealthBanner = () => {
const { data: healthStatus } = useQuery({
queryKey: ["health"],
queryFn: () => getHealth(),
})
const dashboard = useDashboard()
const hasHealthIssues = healthStatus && !healthStatus.data.healthy

if (
dashboard.experiments.includes("deployment_health_page") &&
hasHealthIssues
) {
return (
<Alert
severity="error"
variant="filled"
sx={{
border: 0,
borderRadius: 0,
backgroundColor: colors.red[10],
}}
>
We have detected problems with your Coder deployment. Please{" "}
<Link
component={RouterLink}
to="/health"
sx={{ fontWeight: 600, color: "inherit" }}
>
inspect the health status
</Link>
.
</Alert>
)
}

return null
}
9 changes: 9 additions & 0 deletions site/src/components/DeploySettingsLayout/Sidebar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import LockRounded from "@mui/icons-material/LockOutlined"
import Globe from "@mui/icons-material/PublicOutlined"
import HubOutlinedIcon from "@mui/icons-material/HubOutlined"
import VpnKeyOutlined from "@mui/icons-material/VpnKeyOutlined"
import MonitorHeartOutlined from "@mui/icons-material/MonitorHeartOutlined"
import { GitIcon } from "components/Icons/GitIcon"
import { Stack } from "components/Stack/Stack"
import { ElementType, PropsWithChildren, ReactNode, FC } from "react"
Expand Down Expand Up @@ -93,6 +94,14 @@ export const Sidebar: React.FC = () => {
>
Security
</SidebarNavItem>
{dashboard.experiments.includes("deployment_health_page") && (
<SidebarNavItem
href="/health"
icon={<SidebarNavItemIcon icon={MonitorHeartOutlined} />}
>
Health
</SidebarNavItem>
)}
</nav>
)
}
Expand Down
17 changes: 13 additions & 4 deletions site/src/components/PageHeader/FullWidthPageHeader.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,17 @@
import { makeStyles } from "@mui/styles"
import { FC, PropsWithChildren } from "react"
import { combineClasses } from "utils/combineClasses"

export const FullWidthPageHeader: FC<PropsWithChildren> = ({ children }) => {
export const FullWidthPageHeader: FC<
PropsWithChildren & { sticky?: boolean }
> = ({ children, sticky = true }) => {
const styles = useStyles()

return (
<header className={styles.header} data-testid="header">
<header
className={combineClasses([styles.header, sticky ? styles.sticky : ""])}
data-testid="header"
>
{children}
</header>
)
Expand Down Expand Up @@ -35,8 +41,7 @@ const useStyles = makeStyles((theme) => ({
display: "flex",
alignItems: "center",
gap: theme.spacing(6),
position: "sticky",
top: 0,

zIndex: 10,
flexWrap: "wrap",

Expand All @@ -48,6 +53,10 @@ const useStyles = makeStyles((theme) => ({
flexDirection: "column",
},
},
sticky: {
position: "sticky",
top: 0,
},
actions: {
marginLeft: "auto",
[theme.breakpoints.down("md")]: {
Expand Down
11 changes: 6 additions & 5 deletions site/src/components/Stats/Stats.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
import Box from "@mui/material/Box"
import { makeStyles } from "@mui/styles"
import { ComponentProps, FC, PropsWithChildren } from "react"
import { combineClasses } from "utils/combineClasses"

export const Stats: FC<ComponentProps<"div">> = (props) => {
export const Stats: FC<ComponentProps<typeof Box>> = (props) => {
const styles = useStyles()
return (
<div
<Box
{...props}
className={combineClasses([styles.stats, props.className])}
/>
Expand All @@ -16,18 +17,18 @@ export const StatsItem: FC<
{
label: string
value: string | number | JSX.Element
} & ComponentProps<"div">
} & ComponentProps<typeof Box>
> = ({ label, value, ...divProps }) => {
const styles = useStyles()

return (
<div
<Box
{...divProps}
className={combineClasses([styles.statItem, divProps.className])}
>
<span className={styles.statsLabel}>{label}:</span>
<span className={styles.statsValue}>{value}</span>
</div>
</Box>
)
}

Expand Down
8 changes: 6 additions & 2 deletions site/src/components/SyntaxHighlighter/SyntaxHighlighter.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { FC } from "react"
import { ComponentProps, FC } from "react"
import Editor, { DiffEditor, loader } from "@monaco-editor/react"
import * as monaco from "monaco-editor"
import { useCoderTheme } from "./coderTheme"
Expand All @@ -9,8 +9,10 @@ loader.config({ monaco })
export const SyntaxHighlighter: FC<{
value: string
language: string
editorProps?: ComponentProps<typeof Editor> &
ComponentProps<typeof DiffEditor>
compareWith?: string
}> = ({ value, compareWith, language }) => {
}> = ({ value, compareWith, language, editorProps }) => {
const styles = useStyles()
const hasDiff = compareWith && value !== compareWith
const coderTheme = useCoderTheme()
Expand All @@ -25,6 +27,7 @@ export const SyntaxHighlighter: FC<{
renderSideBySide: true,
readOnly: true,
},
...editorProps,
}

if (coderTheme.isLoading) {
Expand All @@ -46,5 +49,6 @@ const useStyles = makeStyles((theme) => ({
wrapper: {
padding: theme.spacing(1, 0),
background: theme.palette.background.paper,
height: "100%",
},
}))
33 changes: 33 additions & 0 deletions site/src/pages/HealthPage/HealthPage.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import { Meta, StoryObj } from "@storybook/react"
import { HealthPageView } from "./HealthPage"
import { MockHealth } from "testHelpers/entities"

const meta: Meta<typeof HealthPageView> = {
title: "pages/HealthPageView",
component: HealthPageView,
args: {
tab: {
value: "derp",
set: () => {},
},
healthStatus: MockHealth,
},
}

export default meta
type Story = StoryObj<typeof HealthPageView>

export const HealthPage: Story = {}

export const UnhealthPage: Story = {
args: {
healthStatus: {
...MockHealth,
healthy: false,
derp: {
...MockHealth.derp,
healthy: false,
},
},
},
}
Loading