Clean up file hierarchy a bit, add some more comments

Signed-off-by: Julius Volz <julius.volz@gmail.com>
This commit is contained in:
Julius Volz 2024-04-09 12:36:53 +02:00
parent b778c0a249
commit 1049c90cb5
24 changed files with 47 additions and 29 deletions

View file

@ -56,13 +56,13 @@ import FlagsPage from "./pages/FlagsPage";
import ConfigPage from "./pages/ConfigPage"; import ConfigPage from "./pages/ConfigPage";
import AgentPage from "./pages/AgentPage"; import AgentPage from "./pages/AgentPage";
import { Suspense, useContext } from "react"; import { Suspense, useContext } from "react";
import ErrorBoundary from "./ErrorBoundary"; import ErrorBoundary from "./components/ErrorBoundary";
import { ThemeSelector } from "./ThemeSelector"; import { ThemeSelector } from "./components/ThemeSelector";
import { SettingsContext } from "./settings"; import { SettingsContext } from "./settings";
import { Notifications } from "@mantine/notifications"; import { Notifications } from "@mantine/notifications";
import { useAppDispatch } from "./state/hooks"; import { useAppDispatch } from "./state/hooks";
import { updateSettings } from "./state/settingsSlice"; import { updateSettings } from "./state/settingsSlice";
import SettingsMenu from "./SettingsMenu"; import SettingsMenu from "./components/SettingsMenu";
const queryClient = new QueryClient(); const queryClient = new QueryClient();

View file

@ -1,3 +1,5 @@
// Result type for /api/v1/status/config endpoint.
// See: https://prometheus.io/docs/prometheus/latest/querying/api/#config
export default interface ConfigResult { export default interface ConfigResult {
yaml: string; yaml: string;
} }

View file

@ -1 +1,3 @@
// Result type for /api/v1/label/<label_name>/values endpoint.
// See: https://prometheus.io/docs/prometheus/latest/querying/api/#querying-label-values
export type LabelValuesResult = string[]; export type LabelValuesResult = string[];

View file

@ -23,6 +23,8 @@ export interface RangeSamples {
export type SampleValue = [number, string]; export type SampleValue = [number, string];
export type SampleHistogram = [number, Histogram]; export type SampleHistogram = [number, Histogram];
// Result type for /api/v1/query endpoint.
// See: https://prometheus.io/docs/prometheus/latest/querying/api/#instant-queries
export type InstantQueryResult = export type InstantQueryResult =
| { | {
resultType: "vector"; resultType: "vector";

View file

@ -50,10 +50,14 @@ type AlertingRuleGroup = Omit<RuleGroup, "rules"> & {
rules: AlertingRule[]; rules: AlertingRule[];
}; };
export interface RulesMap { // Result type for /api/v1/alerts endpoint.
// See: https://prometheus.io/docs/prometheus/latest/querying/api/#alerts
export interface RulesResult {
groups: RuleGroup[]; groups: RuleGroup[];
} }
export interface AlertingRulesMap { // Same as RulesResult above, but can be used when the caller ensures via a
// "type=alert" query parameter that all rules are alerting rules.
export interface AlertingRulesResult {
groups: AlertingRuleGroup[]; groups: AlertingRuleGroup[];
} }

View file

@ -1 +1,2 @@
// Result type for /api/v1/scrape_pools endpoint.
export type ScrapePoolsResult = { scrapePools: string[] }; export type ScrapePoolsResult = { scrapePools: string[] };

View file

@ -20,6 +20,8 @@ export interface DroppedTarget {
discoveredLabels: Labels; discoveredLabels: Labels;
} }
// Result type for /api/v1/targets endpoint.
// See: https://prometheus.io/docs/prometheus/latest/querying/api/#targets
export type TargetsResult = { export type TargetsResult = {
activeTargets: Target[]; activeTargets: Target[];
droppedTargets: DroppedTarget[]; droppedTargets: DroppedTarget[];

View file

@ -11,7 +11,9 @@ interface HeadStats {
maxTime: number; maxTime: number;
} }
export interface TSDBMap { // Result type for /api/v1/status/tsdb endpoint.
// See: https://prometheus.io/docs/prometheus/latest/querying/api/#tsdb-stats
export interface TSDBStatusResult {
headStats: HeadStats; headStats: HeadStats;
seriesCountByMetricName: Stats[]; seriesCountByMetricName: Stats[];
labelValueCountByLabelName: Stats[]; labelValueCountByLabelName: Stats[];

View file

@ -1,7 +1,7 @@
import { Badge, BadgeVariant, Group, MantineColor } from "@mantine/core"; import { Badge, BadgeVariant, Group, MantineColor } from "@mantine/core";
import { FC } from "react"; import { FC } from "react";
import { escapeString } from "./lib/escapeString"; import { escapeString } from "../lib/escapeString";
import badgeClasses from "./Badge.module.css"; import badgeClasses from "../Badge.module.css";
export interface LabelBadgesProps { export interface LabelBadgesProps {
labels: Record<string, string>; labels: Record<string, string>;

View file

@ -1,9 +1,9 @@
import { Badge, Box, Card, Group, useComputedColorScheme } from "@mantine/core"; import { Badge, Box, Card, Group, useComputedColorScheme } from "@mantine/core";
import { IconClockPause, IconClockPlay } from "@tabler/icons-react"; import { IconClockPause, IconClockPlay } from "@tabler/icons-react";
import { FC } from "react"; import { FC } from "react";
import { formatPrometheusDuration } from "./lib/formatTime"; import { formatPrometheusDuration } from "../lib/formatTime";
import codeboxClasses from "./codebox.module.css"; import codeboxClasses from "./RuleDefinition.module.css";
import { Rule } from "./api/responseTypes/rules"; import { Rule } from "../api/responseTypes/rules";
import CodeMirror, { EditorView } from "@uiw/react-codemirror"; import CodeMirror, { EditorView } from "@uiw/react-codemirror";
import { syntaxHighlighting } from "@codemirror/language"; import { syntaxHighlighting } from "@codemirror/language";
import { import {
@ -11,7 +11,7 @@ import {
darkPromqlHighlighter, darkPromqlHighlighter,
lightTheme, lightTheme,
promqlHighlighter, promqlHighlighter,
} from "./codemirror/theme"; } from "../codemirror/theme";
import { PromQLExtension } from "@prometheus-io/codemirror-promql"; import { PromQLExtension } from "@prometheus-io/codemirror-promql";
import { LabelBadges } from "./LabelBadges"; import { LabelBadges } from "./LabelBadges";

View file

@ -1,8 +1,8 @@
import { Popover, ActionIcon, Fieldset, Checkbox, Stack } from "@mantine/core"; import { Popover, ActionIcon, Fieldset, Checkbox, Stack } from "@mantine/core";
import { IconSettings } from "@tabler/icons-react"; import { IconSettings } from "@tabler/icons-react";
import { FC } from "react"; import { FC } from "react";
import { useAppDispatch, useAppSelector } from "./state/hooks"; import { useAppDispatch, useAppSelector } from "../state/hooks";
import { updateSettings } from "./state/settingsSlice"; import { updateSettings } from "../state/settingsSlice";
const SettingsMenu: FC = () => { const SettingsMenu: FC = () => {
const { const {

View file

@ -1,3 +1,4 @@
// Used for escaping escape sequences and double quotes in double-quoted strings.
export const escapeString = (str: string) => { export const escapeString = (str: string) => {
return str.replace(/([\\"])/g, "\\$1"); return str.replace(/([\\"])/g, "\\$1");
}; };

View file

@ -4,6 +4,7 @@ dayjs.extend(duration);
import utc from "dayjs/plugin/utc"; import utc from "dayjs/plugin/utc";
dayjs.extend(utc); dayjs.extend(utc);
// Parse Prometheus-specific duration strings such as "5m" or "1d2h3m4s" into milliseconds.
export const parsePrometheusDuration = (durationStr: string): number | null => { export const parsePrometheusDuration = (durationStr: string): number | null => {
if (durationStr === "") { if (durationStr === "") {
return null; return null;
@ -44,6 +45,7 @@ export const parsePrometheusDuration = (durationStr: string): number | null => {
return dur; return dur;
}; };
// Format a duration in milliseconds into a Prometheus duration string like "1d2h3m4s".
export const formatPrometheusDuration = (d: number): string => { export const formatPrometheusDuration = (d: number): string => {
let ms = d; let ms = d;
let r = ""; let r = "";

View file

@ -12,19 +12,19 @@ import {
Alert, Alert,
} from "@mantine/core"; } from "@mantine/core";
import { useSuspenseAPIQuery } from "../api/api"; import { useSuspenseAPIQuery } from "../api/api";
import { AlertingRulesMap } from "../api/responseTypes/rules"; import { AlertingRulesResult } from "../api/responseTypes/rules";
import badgeClasses from "../Badge.module.css"; import badgeClasses from "../Badge.module.css";
import RuleDefinition from "../RuleDefinition"; import RuleDefinition from "../components/RuleDefinition";
import { humanizeDurationRelative, now } from "../lib/formatTime"; import { humanizeDurationRelative, now } from "../lib/formatTime";
import { Fragment } from "react"; import { Fragment } from "react";
import { StateMultiSelect } from "../StateMultiSelect"; import { StateMultiSelect } from "../components/StateMultiSelect";
import { useAppDispatch, useAppSelector } from "../state/hooks"; import { useAppDispatch, useAppSelector } from "../state/hooks";
import { IconInfoCircle, IconSearch } from "@tabler/icons-react"; import { IconInfoCircle, IconSearch } from "@tabler/icons-react";
import { LabelBadges } from "../LabelBadges"; import { LabelBadges } from "../components/LabelBadges";
import { updateAlertFilters } from "../state/alertsPageSlice"; import { updateAlertFilters } from "../state/alertsPageSlice";
export default function AlertsPage() { export default function AlertsPage() {
const { data } = useSuspenseAPIQuery<AlertingRulesMap>({ const { data } = useSuspenseAPIQuery<AlertingRulesResult>({
path: `/rules`, path: `/rules`,
params: { params: {
type: "alert", type: "alert",

View file

@ -24,9 +24,9 @@ import {
IconRepeat, IconRepeat,
} from "@tabler/icons-react"; } from "@tabler/icons-react";
import { useSuspenseAPIQuery } from "../api/api"; import { useSuspenseAPIQuery } from "../api/api";
import { RulesMap } from "../api/responseTypes/rules"; import { RulesResult } from "../api/responseTypes/rules";
import badgeClasses from "../Badge.module.css"; import badgeClasses from "../Badge.module.css";
import RuleDefinition from "../RuleDefinition"; import RuleDefinition from "../components/RuleDefinition";
const healthBadgeClass = (state: string) => { const healthBadgeClass = (state: string) => {
switch (state) { switch (state) {
@ -42,7 +42,7 @@ const healthBadgeClass = (state: string) => {
}; };
export default function RulesPage() { export default function RulesPage() {
const { data } = useSuspenseAPIQuery<RulesMap>({ path: `/rules` }); const { data } = useSuspenseAPIQuery<RulesResult>({ path: `/rules` });
return ( return (
<Stack mt="xs"> <Stack mt="xs">

View file

@ -1,6 +1,6 @@
import { Stack, Card, Group, Table, Text } from "@mantine/core"; import { Stack, Card, Group, Table, Text } from "@mantine/core";
import { useSuspenseAPIQuery } from "../api/api"; import { useSuspenseAPIQuery } from "../api/api";
import { TSDBMap } from "../api/responseTypes/tsdbStatus"; import { TSDBStatusResult } from "../api/responseTypes/tsdbStatus";
import { useAppSelector } from "../state/hooks"; import { useAppSelector } from "../state/hooks";
import { formatTimestamp } from "../lib/formatTime"; import { formatTimestamp } from "../lib/formatTime";
@ -15,7 +15,7 @@ export default function TSDBStatusPage() {
seriesCountByLabelValuePair, seriesCountByLabelValuePair,
}, },
}, },
} = useSuspenseAPIQuery<TSDBMap>({ path: `/status/tsdb` }); } = useSuspenseAPIQuery<TSDBStatusResult>({ path: `/status/tsdb` });
const useLocalTime = useAppSelector((state) => state.settings.useLocalTime); const useLocalTime = useAppSelector((state) => state.settings.useLocalTime);

View file

@ -18,7 +18,7 @@ import {
IconLayoutNavbarExpand, IconLayoutNavbarExpand,
IconSearch, IconSearch,
} from "@tabler/icons-react"; } from "@tabler/icons-react";
import { StateMultiSelect } from "../StateMultiSelect"; import { StateMultiSelect } from "../components/StateMultiSelect";
import { useSuspenseAPIQuery } from "../api/api"; import { useSuspenseAPIQuery } from "../api/api";
import { ScrapePoolsResult } from "../api/responseTypes/scrapePools"; import { ScrapePoolsResult } from "../api/responseTypes/scrapePools";
import { Target, TargetsResult } from "../api/responseTypes/targets"; import { Target, TargetsResult } from "../api/responseTypes/targets";
@ -29,14 +29,14 @@ import {
humanizeDuration, humanizeDuration,
now, now,
} from "../lib/formatTime"; } from "../lib/formatTime";
import { LabelBadges } from "../LabelBadges"; import { LabelBadges } from "../components/LabelBadges";
import { useAppDispatch, useAppSelector } from "../state/hooks"; import { useAppDispatch, useAppSelector } from "../state/hooks";
import { import {
setCollapsedPools, setCollapsedPools,
updateTargetFilters, updateTargetFilters,
} from "../state/targetsPageSlice"; } from "../state/targetsPageSlice";
import EndpointLink from "../EndpointLink"; import EndpointLink from "../components/EndpointLink";
import CustomInfiniteScroll from "../CustomInfiniteScroll"; import CustomInfiniteScroll from "../components/CustomInfiniteScroll";
type ScrapePool = { type ScrapePool = {
targets: Target[]; targets: Target[];

View file

@ -1,6 +1,6 @@
import { useDispatch, useSelector } from "react-redux"; import { useDispatch, useSelector } from "react-redux";
import type { RootState, AppDispatch } from "./store"; import type { RootState, AppDispatch } from "./store";
// Use throughout your app instead of plain `useDispatch` and `useSelector` // Use these typed hooks throughout the app instead of plain `useDispatch` and `useSelector`
export const useAppDispatch = useDispatch.withTypes<AppDispatch>(); export const useAppDispatch = useDispatch.withTypes<AppDispatch>();
export const useAppSelector = useSelector.withTypes<RootState>(); export const useAppSelector = useSelector.withTypes<RootState>();