Signed-off-by: Julius Volz <julius.volz@gmail.com>
This commit is contained in:
Julius Volz 2024-09-13 08:21:26 +02:00
parent 5aa3d8260a
commit 2c7bc9833a
11 changed files with 202 additions and 121 deletions

View file

@ -322,9 +322,9 @@ function App() {
color="gray"
title="Documentation"
aria-label="Documentation"
size={32}
size={rem(32)}
>
<IconBook size={20} />
<IconBook style={{ width: "70%", height: "70%" }} />
</ActionIcon>
</>
);

View file

@ -1,4 +1,4 @@
import { Alert } from "@mantine/core";
import { Alert, rem } from "@mantine/core";
import { IconAlertTriangle } from "@tabler/icons-react";
import { Component, ErrorInfo, ReactNode } from "react";
import { useLocation } from "react-router-dom";
@ -32,7 +32,7 @@ class ErrorBoundary extends Component<Props, State> {
<Alert
color="red"
title={this.props.title || "Error querying page data"}
icon={<IconAlertTriangle size={14} />}
icon={<IconAlertTriangle size={rem(14)} />}
maw={500}
mx="auto"
mt="lg"

View file

@ -0,0 +1,31 @@
import { Card, em, Group } from "@mantine/core";
import { TablerIconsProps } from "@tabler/icons-react";
import { FC, ReactNode } from "react";
const InfoPageCard: FC<{
children: ReactNode;
title?: string;
icon?: React.ComponentType<TablerIconsProps>;
}> = ({ children, title, icon: Icon }) => {
return (
<Card shadow="xs" withBorder p="md">
{title && (
<Group
wrap="nowrap"
align="center"
ml="xs"
mb="sm"
gap="xs"
fz="xl"
fw={600}
>
{Icon && <Icon style={{ width: em(17.5), height: em(17.5) }} />}
{title}
</Group>
)}
{children}
</Card>
);
};
export default InfoPageCard;

View file

@ -0,0 +1,12 @@
import { Stack } from "@mantine/core";
import { FC, ReactNode } from "react";
const InfoPageStack: FC<{ children: ReactNode }> = ({ children }) => {
return (
<Stack gap="lg" maw={1000} mx="auto" mt="xs">
{children}
</Stack>
);
};
export default InfoPageStack;

View file

@ -1,4 +1,11 @@
import { Popover, ActionIcon, Fieldset, Checkbox, Stack } from "@mantine/core";
import {
Popover,
ActionIcon,
Fieldset,
Checkbox,
Stack,
Slider,
} from "@mantine/core";
import { IconSettings } from "@tabler/icons-react";
import { FC } from "react";
import { useAppDispatch } from "../state/hooks";
@ -24,7 +31,7 @@ const SettingsMenu: FC = () => {
aria-label="Settings"
size={32}
>
<IconSettings size={20} />
<IconSettings style={{ width: "70%", height: "70%" }} />
</ActionIcon>
</Popover.Target>
<Popover.Dropdown>
@ -39,6 +46,14 @@ const SettingsMenu: FC = () => {
)
}
/>
<Slider
defaultValue={100}
min={70}
max={130}
onChange={(value) => {
document.documentElement.style.fontSize = `${value}%`;
}}
/>
</Fieldset>
<Fieldset p="md" legend="Query page settings">

View file

@ -0,0 +1,35 @@
.promql-code {
font-family: "DejaVu Sans Mono", monospace;
}
.promql-keyword {
color: light-dark(#008080, #14bfad);
}
.promql-metric-name {
/* Should already inherit the right color from the theme. */
}
.promql-label-name {
color: light-dark(#800000, #ff8585);
}
.promql-string {
color: light-dark(#a31515, #fca5a5);
}
.promql-paren,
.promql-brace {
}
.promql-ellipsis {
color: light-dark(rgb(170, 170, 170), rgb(170, 170, 170));
}
.promql-duration {
color: light-dark(#09885a, #22c55e);
}
.promql-number {
color: light-dark(#09885a, #22c55e);
}

View file

@ -1,9 +1,11 @@
import { Alert, Card, Group, Stack, Table, Text } from "@mantine/core";
import { Alert, Table } from "@mantine/core";
import { IconBell, IconBellOff, IconInfoCircle } from "@tabler/icons-react";
import { useSuspenseAPIQuery } from "../api/api";
import { AlertmanagersResult } from "../api/responseTypes/alertmanagers";
import EndpointLink from "../components/EndpointLink";
import InfoPageCard from "../components/InfoPageCard";
import InfoPageStack from "../components/InfoPageStack";
export const targetPoolDisplayLimit = 20;
@ -18,14 +20,8 @@ export default function AlertmanagerDiscoveryPage() {
});
return (
<Stack gap="lg" maw={1000} mx="auto" mt="xs">
<Card shadow="xs" withBorder p="md">
<Group wrap="nowrap" align="center" ml="xs" mb="sm" gap="xs">
<IconBell size={22} />
<Text fz="xl" fw={600}>
Active Alertmanagers
</Text>
</Group>
<InfoPageStack>
<InfoPageCard title="Active Alertmanagers" icon={IconBell}>
{activeAlertmanagers.length === 0 ? (
<Alert title="No active alertmanagers" icon={<IconInfoCircle />}>
No active alertmanagers found.
@ -46,14 +42,8 @@ export default function AlertmanagerDiscoveryPage() {
</Table.Tbody>
</Table>
)}
</Card>
<Card shadow="xs" withBorder p="md">
<Group wrap="nowrap" align="center" ml="xs" mb="sm" gap="xs">
<IconBellOff size={22} />
<Text fz="xl" fw={600}>
Dropped Alertmanagers
</Text>
</Group>
</InfoPageCard>
<InfoPageCard title="Dropped Alertmanagers" icon={IconBellOff}>
{droppedAlertmanagers.length === 0 ? (
<Alert title="No dropped alertmanagers" icon={<IconInfoCircle />}>
No dropped alertmanagers found.
@ -74,7 +64,7 @@ export default function AlertmanagerDiscoveryPage() {
</Table.Tbody>
</Table>
)}
</Card>
</Stack>
</InfoPageCard>
</InfoPageStack>
);
}

View file

@ -8,7 +8,6 @@ import {
TextInput,
rem,
keys,
Card,
} from "@mantine/core";
import {
IconSelector,
@ -18,6 +17,8 @@ import {
} from "@tabler/icons-react";
import classes from "./FlagsPage.module.css";
import { useSuspenseAPIQuery } from "../api/api";
import InfoPageStack from "../components/InfoPageStack";
import InfoPageCard from "../components/InfoPageCard";
interface RowData {
flag: string;
@ -124,59 +125,61 @@ export default function FlagsPage() {
));
return (
<Card shadow="xs" maw={1000} mx="auto" mt="xs" withBorder>
<TextInput
placeholder="Filter by flag name or value"
mb="md"
autoFocus
leftSection={
<IconSearch
style={{ width: rem(16), height: rem(16) }}
stroke={1.5}
/>
}
value={search}
onChange={handleSearchChange}
/>
<Table
horizontalSpacing="md"
verticalSpacing="xs"
miw={700}
layout="fixed"
>
<Table.Tbody>
<Table.Tr>
<Th
sorted={sortBy === "flag"}
reversed={reverseSortDirection}
onSort={() => setSorting("flag")}
>
Flag
</Th>
<Th
sorted={sortBy === "value"}
reversed={reverseSortDirection}
onSort={() => setSorting("value")}
>
Value
</Th>
</Table.Tr>
</Table.Tbody>
<Table.Tbody>
{rows.length > 0 ? (
rows
) : (
<InfoPageStack>
<InfoPageCard>
<TextInput
placeholder="Filter by flag name or value"
mb="md"
autoFocus
leftSection={
<IconSearch
style={{ width: rem(16), height: rem(16) }}
stroke={1.5}
/>
}
value={search}
onChange={handleSearchChange}
/>
<Table
horizontalSpacing="md"
verticalSpacing="xs"
miw={700}
layout="fixed"
>
<Table.Tbody>
<Table.Tr>
<Table.Td colSpan={2}>
<Text fw={500} ta="center">
Nothing found
</Text>
</Table.Td>
<Th
sorted={sortBy === "flag"}
reversed={reverseSortDirection}
onSort={() => setSorting("flag")}
>
Flag
</Th>
<Th
sorted={sortBy === "value"}
reversed={reverseSortDirection}
onSort={() => setSorting("value")}
>
Value
</Th>
</Table.Tr>
)}
</Table.Tbody>
</Table>
</Card>
</Table.Tbody>
<Table.Tbody>
{rows.length > 0 ? (
rows
) : (
<Table.Tr>
<Table.Td colSpan={2}>
<Text fw={500} ta="center">
Nothing found
</Text>
</Table.Td>
</Table.Tr>
)}
</Table.Tbody>
</Table>
</InfoPageCard>
</InfoPageStack>
);
}

View file

@ -1,8 +1,10 @@
import { Card, Group, Stack, Table, Text } from "@mantine/core";
import { Table } from "@mantine/core";
import { useSuspenseAPIQuery } from "../api/api";
import { IconRun, IconWall } from "@tabler/icons-react";
import { formatTimestamp } from "../lib/formatTime";
import { useSettings } from "../state/settingsSlice";
import InfoPageCard from "../components/InfoPageCard";
import InfoPageStack from "../components/InfoPageStack";
export default function StatusPage() {
const { data: buildinfo } = useSuspenseAPIQuery<Record<string, string>>({
@ -42,14 +44,8 @@ export default function StatusPage() {
};
return (
<Stack gap="lg" maw={1000} mx="auto" mt="xs">
<Card shadow="xs" withBorder p="md">
<Group wrap="nowrap" align="center" ml="xs" mb="sm" gap="xs">
<IconWall size={22} />
<Text fz="xl" fw={600}>
Build information
</Text>
</Group>
<InfoPageStack>
<InfoPageCard title="Build information" icon={IconWall}>
<Table layout="fixed">
<Table.Tbody>
{Object.entries(buildinfo.data).map(([k, v]) => (
@ -60,14 +56,8 @@ export default function StatusPage() {
))}
</Table.Tbody>
</Table>
</Card>
<Card shadow="xs" withBorder p="md">
<Group wrap="nowrap" align="center" ml="xs" mb="sm" gap="xs">
<IconRun size={22} />
<Text fz="xl" fw={600}>
Runtime information
</Text>
</Group>
</InfoPageCard>
<InfoPageCard title="Runtime information" icon={IconRun}>
<Table layout="fixed">
<Table.Tbody>
{Object.entries(runtimeinfo.data).map(([k, v]) => {
@ -84,7 +74,7 @@ export default function StatusPage() {
})}
</Table.Tbody>
</Table>
</Card>
</Stack>
</InfoPageCard>
</InfoPageStack>
);
}

View file

@ -1,8 +1,10 @@
import { Stack, Card, Table, Text } from "@mantine/core";
import { Table } from "@mantine/core";
import { useSuspenseAPIQuery } from "../api/api";
import { TSDBStatusResult } from "../api/responseTypes/tsdbStatus";
import { formatTimestamp } from "../lib/formatTime";
import { useSettings } from "../state/settingsSlice";
import InfoPageStack from "../components/InfoPageStack";
import InfoPageCard from "../components/InfoPageCard";
export default function TSDBStatusPage() {
const {
@ -41,7 +43,7 @@ export default function TSDBStatusPage() {
];
return (
<Stack gap="lg" maw={1000} mx="auto" mt="xs">
<InfoPageStack>
{[
{
title: "TSDB Head Status",
@ -70,10 +72,7 @@ export default function TSDBStatusPage() {
formatAsCode: true,
},
].map(({ title, unit = "Count", stats, formatAsCode }) => (
<Card shadow="xs" withBorder p="md">
<Text fz="xl" fw={600} ml="xs" mb="sm">
{title}
</Text>
<InfoPageCard title={title}>
<Table layout="fixed">
<Table.Thead>
<Table.Tr>
@ -82,24 +81,22 @@ export default function TSDBStatusPage() {
</Table.Tr>
</Table.Thead>
<Table.Tbody>
{stats.map(({ name, value }) => {
return (
<Table.Tr key={name}>
<Table.Td
style={{
wordBreak: "break-all",
}}
>
{formatAsCode ? <code>{name}</code> : name}
</Table.Td>
<Table.Td>{value}</Table.Td>
</Table.Tr>
);
})}
{stats.map(({ name, value }) => (
<Table.Tr key={name}>
<Table.Td
style={{
wordBreak: "break-all",
}}
>
{formatAsCode ? <code>{name}</code> : name}
</Table.Td>
<Table.Td>{value}</Table.Td>
</Table.Tr>
))}
</Table.Tbody>
</Table>
</Card>
</InfoPageCard>
))}
</Stack>
</InfoPageStack>
);
}

View file

@ -6,11 +6,19 @@ export default defineConfig({
plugins: [react()],
server: {
proxy: {
// "/api": {
// target: "http://localhost:9090",
// },
// "/-/": {
// target: "http://localhost:9090",
// },
"/api": {
target: "http://localhost:9090",
target: "https://demo-new.promlabs.com/",
changeOrigin: true,
},
"/-/": {
target: "http://localhost:9090",
target: "https://demo-new.promlabs.com/",
changeOrigin: true,
},
// "/api": {
// target: "https://prometheus.demo.do.prometheus.io/",