import { PayloadAction, createSlice } from "@reduxjs/toolkit"; import { useAppSelector } from "./hooks"; import { initializeFromLocalStorage } from "./initializeFromLocalStorage"; interface Settings { consolesLink: string | null; lookbackDelta: string; agentMode: boolean; ready: boolean; pathPrefix: string; useLocalTime: boolean; enableQueryHistory: boolean; enableAutocomplete: boolean; enableSyntaxHighlighting: boolean; enableLinter: boolean; showAnnotations: boolean; ruleGroupsPerPage: number; alertGroupsPerPage: number; } // Declared/defined in public/index.html, value replaced by Prometheus when serving bundle. declare const GLOBAL_CONSOLES_LINK: string; declare const GLOBAL_AGENT_MODE: string; declare const GLOBAL_READY: string; declare const GLOBAL_LOOKBACKDELTA: string; export const localStorageKeyUseLocalTime = "settings.useLocalTime"; export const localStorageKeyEnableQueryHistory = "settings.enableQueryHistory"; export const localStorageKeyEnableAutocomplete = "settings.enableAutocomplete"; export const localStorageKeyEnableSyntaxHighlighting = "settings.enableSyntaxHighlighting"; export const localStorageKeyEnableLinter = "settings.enableLinter"; export const localStorageKeyShowAnnotations = "settings.showAnnotations"; export const localStorageKeyRuleGroupsPerPage = "settings.ruleGroupsPerPage"; export const localStorageKeyAlertGroupsPerPage = "settings.alertGroupsPerPage"; // 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 // hosting and reverse proxy deployments with no additional configurations required. const getPathPrefix = (path: string) => { if (path.endsWith("/")) { path = path.slice(0, -1); } const pagePaths = [ "/query", "/alerts", "/targets", "/rules", "/service-discovery", "/status", "/tsdb-status", "/flags", "/config", "/alertmanager-discovery", "/agent", ]; const pagePath = pagePaths.find((p) => path.endsWith(p)); return path.slice(0, path.length - (pagePath || "").length); }; export const initialState: Settings = { consolesLink: GLOBAL_CONSOLES_LINK === "CONSOLES_LINK_PLACEHOLDER" || GLOBAL_CONSOLES_LINK === "" || GLOBAL_CONSOLES_LINK === null ? null : GLOBAL_CONSOLES_LINK, agentMode: GLOBAL_AGENT_MODE === "true", ready: GLOBAL_READY === "true", lookbackDelta: GLOBAL_LOOKBACKDELTA === "LOOKBACKDELTA_PLACEHOLDER" || GLOBAL_LOOKBACKDELTA === null ? "" : GLOBAL_LOOKBACKDELTA, pathPrefix: getPathPrefix(window.location.pathname), useLocalTime: initializeFromLocalStorage( localStorageKeyUseLocalTime, false ), enableQueryHistory: initializeFromLocalStorage( localStorageKeyEnableQueryHistory, false ), enableAutocomplete: initializeFromLocalStorage( localStorageKeyEnableAutocomplete, true ), enableSyntaxHighlighting: initializeFromLocalStorage( localStorageKeyEnableSyntaxHighlighting, true ), enableLinter: initializeFromLocalStorage( localStorageKeyEnableLinter, true ), showAnnotations: initializeFromLocalStorage( localStorageKeyShowAnnotations, true ), ruleGroupsPerPage: initializeFromLocalStorage( localStorageKeyRuleGroupsPerPage, 10 ), alertGroupsPerPage: initializeFromLocalStorage( localStorageKeyAlertGroupsPerPage, 10 ), }; export const settingsSlice = createSlice({ name: "settings", initialState, reducers: { updateSettings: (state, { payload }: PayloadAction>) => { Object.assign(state, payload); }, }, }); export const { updateSettings } = settingsSlice.actions; export const useSettings = () => { return useAppSelector((state) => state.settings); }; export default settingsSlice.reducer;