From a99c01b53f085c7f7f91b24bd2371a6906aed8b2 Mon Sep 17 00:00:00 2001 From: Julius Volz Date: Wed, 4 Sep 2024 17:25:34 +0200 Subject: [PATCH] Implement query history Signed-off-by: Julius Volz --- .../src/pages/query/ExpressionInput.tsx | 18 ++++++++----- .../mantine-ui/src/pages/query/QueryPanel.tsx | 5 ++++ .../src/state/localStorageMiddleware.ts | 18 +++++++++++-- web/ui/mantine-ui/src/state/queryPageSlice.ts | 25 +++++++++++++++++-- 4 files changed, 56 insertions(+), 10 deletions(-) diff --git a/web/ui/mantine-ui/src/pages/query/ExpressionInput.tsx b/web/ui/mantine-ui/src/pages/query/ExpressionInput.tsx index b74d74596..7a6b1f843 100644 --- a/web/ui/mantine-ui/src/pages/query/ExpressionInput.tsx +++ b/web/ui/mantine-ui/src/pages/query/ExpressionInput.tsx @@ -68,6 +68,7 @@ import { notifications } from "@mantine/notifications"; import { useSettings } from "../../state/settingsSlice"; import MetricsExplorer from "./MetricsExplorer/MetricsExplorer"; import ErrorBoundary from "../../components/ErrorBoundary"; +import { useAppSelector } from "../../state/hooks"; const promqlExtension = new PromQLExtension(); @@ -127,11 +128,13 @@ const ExpressionInput: FC = ({ removePanel, }) => { const theme = useComputedColorScheme(); + const { queryHistory } = useAppSelector((state) => state.queryPage); const { pathPrefix, enableAutocomplete, enableSyntaxHighlighting, enableLinter, + enableQueryHistory, } = useSettings(); const [expr, setExpr] = useState(initialExpr); useEffect(() => { @@ -175,10 +178,6 @@ const ExpressionInput: FC = ({ const [showMetricsExplorer, setShowMetricsExplorer] = useState(false); - // TODO: Implement query history. - // This is just a placeholder until query history is implemented, so disable the linter warning. - const queryHistory = useMemo(() => [], []); - // (Re)initialize editor based on settings / setting changes. useEffect(() => { // Build the dynamic part of the config. @@ -193,10 +192,17 @@ const ExpressionInput: FC = ({ cache: { initialMetricList: metricNames }, }, }), - queryHistory + enableQueryHistory ? queryHistory : [] ), }); - }, [pathPrefix, metricNames, enableAutocomplete, enableLinter, queryHistory]); // TODO: Make this depend on external settings changes, maybe use dynamic config compartment again. + }, [ + pathPrefix, + metricNames, + enableAutocomplete, + enableLinter, + enableQueryHistory, + queryHistory, + ]); // TODO: Make this depend on external settings changes, maybe use dynamic config compartment again. return ( diff --git a/web/ui/mantine-ui/src/pages/query/QueryPanel.tsx b/web/ui/mantine-ui/src/pages/query/QueryPanel.tsx index 4918e87fe..3b693e19b 100644 --- a/web/ui/mantine-ui/src/pages/query/QueryPanel.tsx +++ b/web/ui/mantine-ui/src/pages/query/QueryPanel.tsx @@ -17,6 +17,7 @@ import { import { FC, useCallback, useState } from "react"; import { useAppDispatch, useAppSelector } from "../../state/hooks"; import { + addQueryToHistory, GraphDisplayMode, GraphResolution, removePanel, @@ -73,6 +74,10 @@ const QueryPanel: FC = ({ idx, metricNames }) => { executeQuery={(expr: string) => { setRetriggerIdx((idx) => idx + 1); dispatch(setExpr({ idx, expr })); + + if (!metricNames.includes(expr) && expr.trim() !== "") { + dispatch(addQueryToHistory(expr)); + } }} removePanel={() => { dispatch(removePanel(idx)); diff --git a/web/ui/mantine-ui/src/state/localStorageMiddleware.ts b/web/ui/mantine-ui/src/state/localStorageMiddleware.ts index 64ddfafe4..93eae950e 100644 --- a/web/ui/mantine-ui/src/state/localStorageMiddleware.ts +++ b/web/ui/mantine-ui/src/state/localStorageMiddleware.ts @@ -6,9 +6,13 @@ import { } from "./targetsPageSlice"; import { localStorageKeyCollapsedPools as localStorageKeyServiceDiscoveryPageCollapsedPools, - setCollapsedPools as ServiceDiscoveryPageSetCollapsedPools, + setCollapsedPools as serviceDiscoveryPageSetCollapsedPools, } from "./serviceDiscoveryPageSlice"; import { updateSettings } from "./settingsSlice"; +import { + addQueryToHistory, + localStorageKeyQueryHistory, +} from "./queryPageSlice"; const persistToLocalStorage = (key: string, value: T) => { localStorage.setItem(key, JSON.stringify(value)); @@ -29,7 +33,7 @@ startAppListening({ }); startAppListening({ - actionCreator: ServiceDiscoveryPageSetCollapsedPools, + actionCreator: serviceDiscoveryPageSetCollapsedPools, effect: ({ payload }) => { persistToLocalStorage( localStorageKeyServiceDiscoveryPageCollapsedPools, @@ -38,6 +42,16 @@ startAppListening({ }, }); +startAppListening({ + actionCreator: addQueryToHistory, + effect: (_, { getState }) => { + persistToLocalStorage( + localStorageKeyQueryHistory, + getState().queryPage.queryHistory + ); + }, +}); + startAppListening({ actionCreator: updateSettings, effect: ({ payload }) => { diff --git a/web/ui/mantine-ui/src/state/queryPageSlice.ts b/web/ui/mantine-ui/src/state/queryPageSlice.ts index 0de75807f..4f58d549d 100644 --- a/web/ui/mantine-ui/src/state/queryPageSlice.ts +++ b/web/ui/mantine-ui/src/state/queryPageSlice.ts @@ -1,6 +1,9 @@ import { randomId } from "@mantine/hooks"; import { PayloadAction, createSlice } from "@reduxjs/toolkit"; import { encodePanelOptionsToURLParams } from "../pages/query/urlStateEncoding"; +import { initializeFromLocalStorage } from "./initializeFromLocalStorage"; + +export const localStorageKeyQueryHistory = "queryPage.queryHistory"; export enum GraphDisplayMode { Lines = "lines", @@ -68,6 +71,7 @@ export type Panel = { interface QueryPageState { panels: Panel[]; + queryHistory: string[]; } export const newDefaultPanel = (): Panel => ({ @@ -87,6 +91,10 @@ export const newDefaultPanel = (): Panel => ({ const initialState: QueryPageState = { panels: [newDefaultPanel()], + queryHistory: initializeFromLocalStorage( + localStorageKeyQueryHistory, + [] + ), }; const updateURL = (panels: Panel[]) => { @@ -116,6 +124,12 @@ export const queryPageSlice = createSlice({ state.panels[payload.idx].expr = payload.expr; updateURL(state.panels); }, + addQueryToHistory: (state, { payload: query }: PayloadAction) => { + state.queryHistory = [ + query, + ...state.queryHistory.filter((q) => q !== query), + ].slice(0, 50); + }, setVisualizer: ( state, { payload }: PayloadAction<{ idx: number; visualizer: Visualizer }> @@ -126,7 +140,14 @@ export const queryPageSlice = createSlice({ }, }); -export const { setPanels, addPanel, removePanel, setExpr, setVisualizer } = - queryPageSlice.actions; +export const { + setPanels, + addPanel, + removePanel, + setExpr, + addQueryToHistory, + setShowTree, + setVisualizer, +} = queryPageSlice.actions; export default queryPageSlice.reducer;