Make "show empty pools" setting persistent

Just like for showing empty groups on the Alerts page, also make the
setting for showing empty pools on the Targets page persistent.

Signed-off-by: leonnicolas <leonloechner@gmx.de>
pull/15807/head
leonnicolas 2025-01-13 09:37:44 +01:00
parent 6ccd9add1e
commit b3531a12f3
No known key found for this signature in database
GPG Key ID: 088D0743E2B65C07
5 changed files with 66 additions and 40 deletions

View File

@ -5,7 +5,7 @@ import {
Checkbox, Checkbox,
Stack, Stack,
Group, Group,
NumberInput NumberInput,
} from "@mantine/core"; } from "@mantine/core";
import { IconSettings } from "@tabler/icons-react"; import { IconSettings } from "@tabler/icons-react";
import { FC } from "react"; import { FC } from "react";
@ -23,7 +23,8 @@ const SettingsMenu: FC = () => {
showAnnotations, showAnnotations,
hideEmptyGroups, hideEmptyGroups,
ruleGroupsPerPage, ruleGroupsPerPage,
alertGroupsPerPage alertGroupsPerPage,
showEmptyPools,
} = useSettings(); } = useSettings();
const dispatch = useAppDispatch(); const dispatch = useAppDispatch();
@ -49,7 +50,7 @@ const SettingsMenu: FC = () => {
onChange={(event) => onChange={(event) =>
dispatch( dispatch(
updateSettings({ updateSettings({
useLocalTime: event.currentTarget.checked useLocalTime: event.currentTarget.checked,
}) })
) )
} }
@ -64,7 +65,7 @@ const SettingsMenu: FC = () => {
onChange={(event) => onChange={(event) =>
dispatch( dispatch(
updateSettings({ updateSettings({
enableQueryHistory: event.currentTarget.checked enableQueryHistory: event.currentTarget.checked,
}) })
) )
} }
@ -75,7 +76,7 @@ const SettingsMenu: FC = () => {
onChange={(event) => onChange={(event) =>
dispatch( dispatch(
updateSettings({ updateSettings({
enableAutocomplete: event.currentTarget.checked enableAutocomplete: event.currentTarget.checked,
}) })
) )
} }
@ -86,7 +87,7 @@ const SettingsMenu: FC = () => {
onChange={(event) => onChange={(event) =>
dispatch( dispatch(
updateSettings({ updateSettings({
enableSyntaxHighlighting: event.currentTarget.checked enableSyntaxHighlighting: event.currentTarget.checked,
}) })
) )
} }
@ -97,13 +98,26 @@ const SettingsMenu: FC = () => {
onChange={(event) => onChange={(event) =>
dispatch( dispatch(
updateSettings({ updateSettings({
enableLinter: event.currentTarget.checked enableLinter: event.currentTarget.checked,
}) })
) )
} }
/> />
</Stack> </Stack>
</Fieldset> </Fieldset>
<Fieldset p="md" legend="Targets page settings">
<Checkbox
checked={showEmptyPools}
label="Show empty pools"
onChange={(event) =>
dispatch(
updateSettings({
showEmptyPools: event.currentTarget.checked,
})
)
}
/>
</Fieldset>
</Stack> </Stack>
<Stack> <Stack>
@ -115,7 +129,7 @@ const SettingsMenu: FC = () => {
onChange={(event) => onChange={(event) =>
dispatch( dispatch(
updateSettings({ updateSettings({
showAnnotations: event.currentTarget.checked showAnnotations: event.currentTarget.checked,
}) })
) )
} }
@ -126,7 +140,7 @@ const SettingsMenu: FC = () => {
onChange={(event) => onChange={(event) =>
dispatch( dispatch(
updateSettings({ updateSettings({
hideEmptyGroups: event.currentTarget.checked hideEmptyGroups: event.currentTarget.checked,
}) })
) )
} }
@ -146,7 +160,7 @@ const SettingsMenu: FC = () => {
dispatch( dispatch(
updateSettings({ updateSettings({
alertGroupsPerPage: value alertGroupsPerPage: value,
}) })
); );
}} }}
@ -165,7 +179,7 @@ const SettingsMenu: FC = () => {
dispatch( dispatch(
updateSettings({ updateSettings({
ruleGroupsPerPage: value ruleGroupsPerPage: value,
}) })
); );
}} }}

View File

@ -11,7 +11,7 @@ import {
Alert, Alert,
TextInput, TextInput,
Anchor, Anchor,
Pagination Pagination,
} from "@mantine/core"; } from "@mantine/core";
import { useSuspenseAPIQuery } from "../api/api"; import { useSuspenseAPIQuery } from "../api/api";
import { AlertingRule, AlertingRulesResult } from "../api/responseTypes/rules"; import { AlertingRule, AlertingRulesResult } from "../api/responseTypes/rules";
@ -30,7 +30,7 @@ import {
NumberParam, NumberParam,
StringParam, StringParam,
useQueryParam, useQueryParam,
withDefault withDefault,
} from "use-query-params"; } from "use-query-params";
import { useDebouncedValue } from "@mantine/hooks"; import { useDebouncedValue } from "@mantine/hooks";
import { KVSearch } from "@nexucis/kvsearch"; import { KVSearch } from "@nexucis/kvsearch";
@ -67,7 +67,7 @@ type AlertsPageData = {
const kvSearch = new KVSearch<AlertingRule>({ const kvSearch = new KVSearch<AlertingRule>({
shouldSort: true, shouldSort: true,
indexedKeys: ["name", "labels", ["labels", /.*/]] indexedKeys: ["name", "labels", ["labels", /.*/]],
}); });
const buildAlertsPageData = ( const buildAlertsPageData = (
@ -79,9 +79,9 @@ const buildAlertsPageData = (
globalCounts: { globalCounts: {
inactive: 0, inactive: 0,
pending: 0, pending: 0,
firing: 0 firing: 0,
}, },
groups: [] groups: [],
}; };
for (const group of data.groups) { for (const group of data.groups) {
@ -89,7 +89,7 @@ const buildAlertsPageData = (
total: 0, total: 0,
inactive: 0, inactive: 0,
pending: 0, pending: 0,
firing: 0 firing: 0,
}; };
for (const r of group.rules) { for (const r of group.rules) {
@ -126,9 +126,9 @@ const buildAlertsPageData = (
rule: r, rule: r,
counts: { counts: {
firing: r.alerts.filter((a) => a.state === "firing").length, firing: r.alerts.filter((a) => a.state === "firing").length,
pending: r.alerts.filter((a) => a.state === "pending").length pending: r.alerts.filter((a) => a.state === "pending").length,
} },
})) })),
}); });
} }
@ -146,8 +146,8 @@ export default function AlertsPage() {
const { data } = useSuspenseAPIQuery<AlertingRulesResult>({ const { data } = useSuspenseAPIQuery<AlertingRulesResult>({
path: `/rules`, path: `/rules`,
params: { params: {
type: "alert" type: "alert",
} },
}); });
const { hideEmptyGroups, showAnnotations } = useSettings(); const { hideEmptyGroups, showAnnotations } = useSettings();
@ -255,7 +255,7 @@ export default function AlertsPage() {
onClick={() => { onClick={() => {
dispatch( dispatch(
updateSettings({ updateSettings({
hideEmptyGroups: true hideEmptyGroups: true,
}) })
); );
}} }}
@ -273,7 +273,7 @@ export default function AlertsPage() {
onClick={() => { onClick={() => {
dispatch( dispatch(
updateSettings({ updateSettings({
hideEmptyGroups: true hideEmptyGroups: true,
}) })
); );
}} }}
@ -295,8 +295,8 @@ export default function AlertsPage() {
// have a different background color than their surrounding group card in dark mode, // have a different background color than their surrounding group card in dark mode,
// but it would be better to use CSS to override the light/dark colors for // but it would be better to use CSS to override the light/dark colors for
// collapsed/expanded accordion items. // collapsed/expanded accordion items.
backgroundColor: "#c0c0c015" backgroundColor: "#c0c0c015",
} },
}} }}
key={j} key={j}
value={j.toString()} value={j.toString()}

View File

@ -30,6 +30,7 @@ import {
setCollapsedPools, setCollapsedPools,
setShowLimitAlert, setShowLimitAlert,
} from "../../state/targetsPageSlice"; } from "../../state/targetsPageSlice";
import { useSettings, updateSettings } from "../../state/settingsSlice";
import EndpointLink from "../../components/EndpointLink"; import EndpointLink from "../../components/EndpointLink";
import CustomInfiniteScroll from "../../components/CustomInfiniteScroll"; import CustomInfiniteScroll from "../../components/CustomInfiniteScroll";
@ -38,7 +39,6 @@ import panelClasses from "../../Panel.module.css";
import TargetLabels from "./TargetLabels"; import TargetLabels from "./TargetLabels";
import { useDebouncedValue } from "@mantine/hooks"; import { useDebouncedValue } from "@mantine/hooks";
import { targetPoolDisplayLimit } from "./TargetsPage"; import { targetPoolDisplayLimit } from "./TargetsPage";
import { BooleanParam, useQueryParam, withDefault } from "use-query-params";
import { badgeIconStyle } from "../../styles"; import { badgeIconStyle } from "../../styles";
type ScrapePool = { type ScrapePool = {
@ -164,11 +164,8 @@ const ScrapePoolList: FC<ScrapePoolListProp> = ({
}, },
}); });
const { showEmptyPools } = useSettings();
const dispatch = useAppDispatch(); const dispatch = useAppDispatch();
const [showEmptyPools, setShowEmptyPools] = useQueryParam(
"showEmptyPools",
withDefault(BooleanParam, true)
);
const { collapsedPools, showLimitAlert } = useAppSelector( const { collapsedPools, showLimitAlert } = useAppSelector(
(state) => state.targetsPage (state) => state.targetsPage
@ -207,7 +204,11 @@ const ScrapePoolList: FC<ScrapePoolListProp> = ({
> >
Hiding {allPoolNames.length - shownPoolNames.length} empty pools due Hiding {allPoolNames.length - shownPoolNames.length} empty pools due
to filters or no targets. to filters or no targets.
<Anchor ml="md" fz="1em" onClick={() => setShowEmptyPools(true)}> <Anchor
ml="md"
fz="1em"
onClick={() => dispatch(updateSettings({ showEmptyPools: true }))}
>
Show empty pools Show empty pools
</Anchor> </Anchor>
</Alert> </Alert>
@ -281,7 +282,9 @@ const ScrapePoolList: FC<ScrapePoolListProp> = ({
<Anchor <Anchor
ml="md" ml="md"
fz="1em" fz="1em"
onClick={() => setShowEmptyPools(false)} onClick={() =>
dispatch(updateSettings({ showEmptyPools: false }))
}
> >
Hide empty pools Hide empty pools
</Anchor> </Anchor>
@ -293,7 +296,9 @@ const ScrapePoolList: FC<ScrapePoolListProp> = ({
<Anchor <Anchor
ml="md" ml="md"
fz="1em" fz="1em"
onClick={() => setShowEmptyPools(false)} onClick={() =>
dispatch(updateSettings({ showEmptyPools: false }))
}
> >
Hide empty pools Hide empty pools
</Anchor> </Anchor>

View File

@ -37,7 +37,7 @@ startAppListening({
effect: ({ payload }) => { effect: ({ payload }) => {
persistToLocalStorage( persistToLocalStorage(
localStorageKeyServiceDiscoveryPageCollapsedPools, localStorageKeyServiceDiscoveryPageCollapsedPools,
payload, payload
); );
}, },
}); });
@ -47,7 +47,7 @@ startAppListening({
effect: (_, { getState }) => { effect: (_, { getState }) => {
persistToLocalStorage( persistToLocalStorage(
localStorageKeyQueryHistory, localStorageKeyQueryHistory,
getState().queryPage.queryHistory, getState().queryPage.queryHistory
); );
}, },
}); });
@ -65,6 +65,7 @@ startAppListening({
case "hideEmptyGroups": case "hideEmptyGroups":
case "showAnnotations": case "showAnnotations":
case "ruleGroupsPerPage": case "ruleGroupsPerPage":
case "showEmptyPools":
return persistToLocalStorage(`settings.${key}`, value); return persistToLocalStorage(`settings.${key}`, value);
} }
}); });

View File

@ -17,6 +17,7 @@ interface Settings {
showAnnotations: boolean; showAnnotations: boolean;
ruleGroupsPerPage: number; ruleGroupsPerPage: number;
alertGroupsPerPage: number; alertGroupsPerPage: number;
showEmptyPools: boolean;
} }
// Declared/defined in public/index.html, value replaced by Prometheus when serving bundle. // Declared/defined in public/index.html, value replaced by Prometheus when serving bundle.
@ -35,6 +36,7 @@ export const localStorageKeyHideEmptyGroups = "settings.hideEmptyGroups";
export const localStorageKeyShowAnnotations = "settings.showAnnotations"; export const localStorageKeyShowAnnotations = "settings.showAnnotations";
export const localStorageKeyRuleGroupsPerPage = "settings.ruleGroupsPerPage"; export const localStorageKeyRuleGroupsPerPage = "settings.ruleGroupsPerPage";
export const localStorageKeyAlertGroupsPerPage = "settings.alertGroupsPerPage"; export const localStorageKeyAlertGroupsPerPage = "settings.alertGroupsPerPage";
export const localStorageKeyShowEmptyPools = "settings.showEmptyPools";
// This dynamically/generically determines the pathPrefix by stripping the first known // This dynamically/generically determines the pathPrefix by stripping the first known
// endpoint suffix from the window location path. It works out of the box for both direct // endpoint suffix from the window location path. It works out of the box for both direct
@ -55,7 +57,7 @@ const getPathPrefix = (path: string) => {
"/flags", "/flags",
"/config", "/config",
"/alertmanager-discovery", "/alertmanager-discovery",
"/agent" "/agent",
]; ];
const pagePath = pagePaths.find((p) => path.endsWith(p)); const pagePath = pagePaths.find((p) => path.endsWith(p));
@ -112,7 +114,11 @@ export const initialState: Settings = {
alertGroupsPerPage: initializeFromLocalStorage<number>( alertGroupsPerPage: initializeFromLocalStorage<number>(
localStorageKeyAlertGroupsPerPage, localStorageKeyAlertGroupsPerPage,
10 10
) ),
showEmptyPools: initializeFromLocalStorage<boolean>(
localStorageKeyShowEmptyPools,
true
),
}; };
export const settingsSlice = createSlice({ export const settingsSlice = createSlice({
@ -121,8 +127,8 @@ export const settingsSlice = createSlice({
reducers: { reducers: {
updateSettings: (state, { payload }: PayloadAction<Partial<Settings>>) => { updateSettings: (state, { payload }: PayloadAction<Partial<Settings>>) => {
Object.assign(state, payload); Object.assign(state, payload);
} },
} },
}); });
export const { updateSettings } = settingsSlice.actions; export const { updateSettings } = settingsSlice.actions;