mirror of
https://github.com/prometheus/prometheus.git
synced 2025-03-05 20:59:13 -08:00
Make "hide empty rules persistent"
It can be a bit annoying to always press "hide empty rules". This commit uses the session storage of the browser to make it persistent. Signed-off-by: leonnicolas <leonloechner@gmx.de>
This commit is contained in:
parent
0a19f1268e
commit
6ccd9add1e
|
@ -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";
|
||||||
|
@ -21,8 +21,9 @@ const SettingsMenu: FC = () => {
|
||||||
enableSyntaxHighlighting,
|
enableSyntaxHighlighting,
|
||||||
enableLinter,
|
enableLinter,
|
||||||
showAnnotations,
|
showAnnotations,
|
||||||
|
hideEmptyGroups,
|
||||||
ruleGroupsPerPage,
|
ruleGroupsPerPage,
|
||||||
alertGroupsPerPage,
|
alertGroupsPerPage
|
||||||
} = useSettings();
|
} = useSettings();
|
||||||
const dispatch = useAppDispatch();
|
const dispatch = useAppDispatch();
|
||||||
|
|
||||||
|
@ -48,7 +49,7 @@ const SettingsMenu: FC = () => {
|
||||||
onChange={(event) =>
|
onChange={(event) =>
|
||||||
dispatch(
|
dispatch(
|
||||||
updateSettings({
|
updateSettings({
|
||||||
useLocalTime: event.currentTarget.checked,
|
useLocalTime: event.currentTarget.checked
|
||||||
})
|
})
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -63,7 +64,7 @@ const SettingsMenu: FC = () => {
|
||||||
onChange={(event) =>
|
onChange={(event) =>
|
||||||
dispatch(
|
dispatch(
|
||||||
updateSettings({
|
updateSettings({
|
||||||
enableQueryHistory: event.currentTarget.checked,
|
enableQueryHistory: event.currentTarget.checked
|
||||||
})
|
})
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -74,7 +75,7 @@ const SettingsMenu: FC = () => {
|
||||||
onChange={(event) =>
|
onChange={(event) =>
|
||||||
dispatch(
|
dispatch(
|
||||||
updateSettings({
|
updateSettings({
|
||||||
enableAutocomplete: event.currentTarget.checked,
|
enableAutocomplete: event.currentTarget.checked
|
||||||
})
|
})
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -85,7 +86,7 @@ const SettingsMenu: FC = () => {
|
||||||
onChange={(event) =>
|
onChange={(event) =>
|
||||||
dispatch(
|
dispatch(
|
||||||
updateSettings({
|
updateSettings({
|
||||||
enableSyntaxHighlighting: event.currentTarget.checked,
|
enableSyntaxHighlighting: event.currentTarget.checked
|
||||||
})
|
})
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -96,7 +97,7 @@ const SettingsMenu: FC = () => {
|
||||||
onChange={(event) =>
|
onChange={(event) =>
|
||||||
dispatch(
|
dispatch(
|
||||||
updateSettings({
|
updateSettings({
|
||||||
enableLinter: event.currentTarget.checked,
|
enableLinter: event.currentTarget.checked
|
||||||
})
|
})
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -107,17 +108,30 @@ const SettingsMenu: FC = () => {
|
||||||
|
|
||||||
<Stack>
|
<Stack>
|
||||||
<Fieldset p="md" legend="Alerts page settings">
|
<Fieldset p="md" legend="Alerts page settings">
|
||||||
<Checkbox
|
<Stack>
|
||||||
checked={showAnnotations}
|
<Checkbox
|
||||||
label="Show expanded annotations"
|
checked={showAnnotations}
|
||||||
onChange={(event) =>
|
label="Show expanded annotations"
|
||||||
dispatch(
|
onChange={(event) =>
|
||||||
updateSettings({
|
dispatch(
|
||||||
showAnnotations: event.currentTarget.checked,
|
updateSettings({
|
||||||
})
|
showAnnotations: event.currentTarget.checked
|
||||||
)
|
})
|
||||||
}
|
)
|
||||||
/>
|
}
|
||||||
|
/>
|
||||||
|
<Checkbox
|
||||||
|
checked={hideEmptyGroups}
|
||||||
|
label="Hide empty groups"
|
||||||
|
onChange={(event) =>
|
||||||
|
dispatch(
|
||||||
|
updateSettings({
|
||||||
|
hideEmptyGroups: event.currentTarget.checked
|
||||||
|
})
|
||||||
|
)
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
</Stack>
|
||||||
</Fieldset>
|
</Fieldset>
|
||||||
<Fieldset p="md" legend="Alerts page settings">
|
<Fieldset p="md" legend="Alerts page settings">
|
||||||
<NumberInput
|
<NumberInput
|
||||||
|
@ -132,7 +146,7 @@ const SettingsMenu: FC = () => {
|
||||||
|
|
||||||
dispatch(
|
dispatch(
|
||||||
updateSettings({
|
updateSettings({
|
||||||
alertGroupsPerPage: value,
|
alertGroupsPerPage: value
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
}}
|
}}
|
||||||
|
@ -151,7 +165,7 @@ const SettingsMenu: FC = () => {
|
||||||
|
|
||||||
dispatch(
|
dispatch(
|
||||||
updateSettings({
|
updateSettings({
|
||||||
ruleGroupsPerPage: value,
|
ruleGroupsPerPage: value
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
}}
|
}}
|
||||||
|
|
|
@ -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";
|
||||||
|
@ -23,14 +23,14 @@ import { Fragment, useEffect, useMemo } from "react";
|
||||||
import { StateMultiSelect } from "../components/StateMultiSelect";
|
import { StateMultiSelect } from "../components/StateMultiSelect";
|
||||||
import { IconInfoCircle, IconSearch } from "@tabler/icons-react";
|
import { IconInfoCircle, IconSearch } from "@tabler/icons-react";
|
||||||
import { LabelBadges } from "../components/LabelBadges";
|
import { LabelBadges } from "../components/LabelBadges";
|
||||||
import { useSettings } from "../state/settingsSlice";
|
import { useSettings, updateSettings } from "../state/settingsSlice";
|
||||||
|
import { useAppDispatch } from "../state/hooks";
|
||||||
import {
|
import {
|
||||||
ArrayParam,
|
ArrayParam,
|
||||||
BooleanParam,
|
|
||||||
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,11 +146,12 @@ export default function AlertsPage() {
|
||||||
const { data } = useSuspenseAPIQuery<AlertingRulesResult>({
|
const { data } = useSuspenseAPIQuery<AlertingRulesResult>({
|
||||||
path: `/rules`,
|
path: `/rules`,
|
||||||
params: {
|
params: {
|
||||||
type: "alert",
|
type: "alert"
|
||||||
},
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
const { showAnnotations } = useSettings();
|
const { hideEmptyGroups, showAnnotations } = useSettings();
|
||||||
|
const dispatch = useAppDispatch();
|
||||||
|
|
||||||
// Define URL query params.
|
// Define URL query params.
|
||||||
const [stateFilter, setStateFilter] = useQueryParam(
|
const [stateFilter, setStateFilter] = useQueryParam(
|
||||||
|
@ -162,10 +163,6 @@ export default function AlertsPage() {
|
||||||
withDefault(StringParam, "")
|
withDefault(StringParam, "")
|
||||||
);
|
);
|
||||||
const [debouncedSearch] = useDebouncedValue<string>(searchFilter.trim(), 250);
|
const [debouncedSearch] = useDebouncedValue<string>(searchFilter.trim(), 250);
|
||||||
const [showEmptyGroups, setShowEmptyGroups] = useQueryParam(
|
|
||||||
"showEmptyGroups",
|
|
||||||
withDefault(BooleanParam, true)
|
|
||||||
);
|
|
||||||
|
|
||||||
const { alertGroupsPerPage } = useSettings();
|
const { alertGroupsPerPage } = useSettings();
|
||||||
const [activePage, setActivePage] = useQueryParam(
|
const [activePage, setActivePage] = useQueryParam(
|
||||||
|
@ -181,10 +178,10 @@ export default function AlertsPage() {
|
||||||
|
|
||||||
const shownGroups = useMemo(
|
const shownGroups = useMemo(
|
||||||
() =>
|
() =>
|
||||||
showEmptyGroups
|
!hideEmptyGroups
|
||||||
? alertsPageData.groups
|
? alertsPageData.groups
|
||||||
: alertsPageData.groups.filter((g) => g.rules.length > 0),
|
: alertsPageData.groups.filter((g) => g.rules.length > 0),
|
||||||
[alertsPageData.groups, showEmptyGroups]
|
[alertsPageData.groups, hideEmptyGroups]
|
||||||
);
|
);
|
||||||
|
|
||||||
// If we were e.g. on page 10 and the number of total pages decreases to 5 (due to filtering
|
// If we were e.g. on page 10 and the number of total pages decreases to 5 (due to filtering
|
||||||
|
@ -255,7 +252,13 @@ export default function AlertsPage() {
|
||||||
<Anchor
|
<Anchor
|
||||||
ml="md"
|
ml="md"
|
||||||
fz="1em"
|
fz="1em"
|
||||||
onClick={() => setShowEmptyGroups(false)}
|
onClick={() => {
|
||||||
|
dispatch(
|
||||||
|
updateSettings({
|
||||||
|
hideEmptyGroups: true
|
||||||
|
})
|
||||||
|
);
|
||||||
|
}}
|
||||||
>
|
>
|
||||||
Hide empty groups
|
Hide empty groups
|
||||||
</Anchor>
|
</Anchor>
|
||||||
|
@ -267,7 +270,13 @@ export default function AlertsPage() {
|
||||||
<Anchor
|
<Anchor
|
||||||
ml="md"
|
ml="md"
|
||||||
fz="1em"
|
fz="1em"
|
||||||
onClick={() => setShowEmptyGroups(false)}
|
onClick={() => {
|
||||||
|
dispatch(
|
||||||
|
updateSettings({
|
||||||
|
hideEmptyGroups: true
|
||||||
|
})
|
||||||
|
);
|
||||||
|
}}
|
||||||
>
|
>
|
||||||
Hide empty groups
|
Hide empty groups
|
||||||
</Anchor>
|
</Anchor>
|
||||||
|
@ -286,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()}
|
||||||
|
@ -403,7 +412,7 @@ export default function AlertsPage() {
|
||||||
)}
|
)}
|
||||||
</Card>
|
</Card>
|
||||||
)),
|
)),
|
||||||
[currentPageGroups, showAnnotations, setShowEmptyGroups]
|
[currentPageGroups, showAnnotations, dispatch]
|
||||||
);
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
@ -442,7 +451,7 @@ export default function AlertsPage() {
|
||||||
No rules found.
|
No rules found.
|
||||||
</Alert>
|
</Alert>
|
||||||
) : (
|
) : (
|
||||||
!showEmptyGroups &&
|
hideEmptyGroups &&
|
||||||
alertsPageData.groups.length !== shownGroups.length && (
|
alertsPageData.groups.length !== shownGroups.length && (
|
||||||
<Alert
|
<Alert
|
||||||
title="Hiding groups with no matching rules"
|
title="Hiding groups with no matching rules"
|
||||||
|
@ -450,7 +459,13 @@ export default function AlertsPage() {
|
||||||
>
|
>
|
||||||
Hiding {alertsPageData.groups.length - shownGroups.length} empty
|
Hiding {alertsPageData.groups.length - shownGroups.length} empty
|
||||||
groups due to filters or no rules.
|
groups due to filters or no rules.
|
||||||
<Anchor ml="md" fz="1em" onClick={() => setShowEmptyGroups(true)}>
|
<Anchor
|
||||||
|
ml="md"
|
||||||
|
fz="1em"
|
||||||
|
onClick={() =>
|
||||||
|
dispatch(updateSettings({ hideEmptyGroups: false }))
|
||||||
|
}
|
||||||
|
>
|
||||||
Show empty groups
|
Show empty groups
|
||||||
</Anchor>
|
</Anchor>
|
||||||
</Alert>
|
</Alert>
|
||||||
|
|
|
@ -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,
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
@ -62,6 +62,7 @@ startAppListening({
|
||||||
case "enableAutocomplete":
|
case "enableAutocomplete":
|
||||||
case "enableSyntaxHighlighting":
|
case "enableSyntaxHighlighting":
|
||||||
case "enableLinter":
|
case "enableLinter":
|
||||||
|
case "hideEmptyGroups":
|
||||||
case "showAnnotations":
|
case "showAnnotations":
|
||||||
case "ruleGroupsPerPage":
|
case "ruleGroupsPerPage":
|
||||||
return persistToLocalStorage(`settings.${key}`, value);
|
return persistToLocalStorage(`settings.${key}`, value);
|
||||||
|
|
|
@ -13,6 +13,7 @@ interface Settings {
|
||||||
enableAutocomplete: boolean;
|
enableAutocomplete: boolean;
|
||||||
enableSyntaxHighlighting: boolean;
|
enableSyntaxHighlighting: boolean;
|
||||||
enableLinter: boolean;
|
enableLinter: boolean;
|
||||||
|
hideEmptyGroups: boolean;
|
||||||
showAnnotations: boolean;
|
showAnnotations: boolean;
|
||||||
ruleGroupsPerPage: number;
|
ruleGroupsPerPage: number;
|
||||||
alertGroupsPerPage: number;
|
alertGroupsPerPage: number;
|
||||||
|
@ -30,6 +31,7 @@ export const localStorageKeyEnableAutocomplete = "settings.enableAutocomplete";
|
||||||
export const localStorageKeyEnableSyntaxHighlighting =
|
export const localStorageKeyEnableSyntaxHighlighting =
|
||||||
"settings.enableSyntaxHighlighting";
|
"settings.enableSyntaxHighlighting";
|
||||||
export const localStorageKeyEnableLinter = "settings.enableLinter";
|
export const localStorageKeyEnableLinter = "settings.enableLinter";
|
||||||
|
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";
|
||||||
|
@ -53,7 +55,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));
|
||||||
|
@ -95,6 +97,10 @@ export const initialState: Settings = {
|
||||||
localStorageKeyEnableLinter,
|
localStorageKeyEnableLinter,
|
||||||
true
|
true
|
||||||
),
|
),
|
||||||
|
hideEmptyGroups: initializeFromLocalStorage<boolean>(
|
||||||
|
localStorageKeyHideEmptyGroups,
|
||||||
|
false
|
||||||
|
),
|
||||||
showAnnotations: initializeFromLocalStorage<boolean>(
|
showAnnotations: initializeFromLocalStorage<boolean>(
|
||||||
localStorageKeyShowAnnotations,
|
localStorageKeyShowAnnotations,
|
||||||
true
|
true
|
||||||
|
@ -106,7 +112,7 @@ export const initialState: Settings = {
|
||||||
alertGroupsPerPage: initializeFromLocalStorage<number>(
|
alertGroupsPerPage: initializeFromLocalStorage<number>(
|
||||||
localStorageKeyAlertGroupsPerPage,
|
localStorageKeyAlertGroupsPerPage,
|
||||||
10
|
10
|
||||||
),
|
)
|
||||||
};
|
};
|
||||||
|
|
||||||
export const settingsSlice = createSlice({
|
export const settingsSlice = createSlice({
|
||||||
|
@ -115,8 +121,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;
|
||||||
|
|
Loading…
Reference in a new issue