From 8739fb8a912e233f6b0cf20fba9b1ee43a75ee70 Mon Sep 17 00:00:00 2001 From: Yury Molodov Date: Tue, 17 May 2022 14:13:15 +0300 Subject: [PATCH] vmui: add option to customize url params for individual pages (#2582) --- app/vmui/packages/vmui/src/App.tsx | 34 ++++++++-------- .../vmui/src/state/common/StateContext.tsx | 4 +- .../packages/vmui/src/utils/query-string.ts | 40 ++++++++++++++++--- 3 files changed, 54 insertions(+), 24 deletions(-) diff --git a/app/vmui/packages/vmui/src/App.tsx b/app/vmui/packages/vmui/src/App.tsx index 5c1731a9dd..012c16f3ba 100644 --- a/app/vmui/packages/vmui/src/App.tsx +++ b/app/vmui/packages/vmui/src/App.tsx @@ -19,29 +19,29 @@ import DashboardsLayout from "./components/PredefinedPanels/DashboardsLayout"; const App: FC = () => { return <> - {/* CSS Baseline: kind of normalize.css made by materialUI team - can be scoped */} - {/* Allows datepicker to work with DayJS */} - - {/* Material UI theme customization */} - {/* Serialized into query string, common app settings */} - {/* Auth related info - optionally persisted to Local Storage */} - {/* Graph settings */} - {/* Display various snackbars */} - + + {/* CSS Baseline: kind of normalize.css made by materialUI team - can be scoped */} + {/* Allows datepicker to work with DayJS */} + + {/* Material UI theme customization */} + {/* Serialized into query string, common app settings */} + {/* Auth related info - optionally persisted to Local Storage */} + {/* Graph settings */} + {/* Display various snackbars */} }> }/> }/> - - - - - - - - + + + + + + + + ; }; diff --git a/app/vmui/packages/vmui/src/state/common/StateContext.tsx b/app/vmui/packages/vmui/src/state/common/StateContext.tsx index c8e515dc27..4ff8972152 100644 --- a/app/vmui/packages/vmui/src/state/common/StateContext.tsx +++ b/app/vmui/packages/vmui/src/state/common/StateContext.tsx @@ -2,6 +2,7 @@ import React, {createContext, FC, useContext, useEffect, useMemo, useReducer} fr import {Action, AppState, initialState, reducer} from "./reducer"; import {getQueryStringValue, setQueryStringValue} from "../../utils/query-string"; import {Dispatch} from "react"; +import {useLocation} from "react-router-dom"; type StateContextType = { state: AppState, dispatch: Dispatch }; @@ -17,12 +18,13 @@ export const initialPrepopulatedState = Object.entries(initialState) }), {}) as AppState; export const StateProvider: FC = ({children}) => { + const location = useLocation(); const [state, dispatch] = useReducer(reducer, initialPrepopulatedState); useEffect(() => { setQueryStringValue(state as unknown as Record); - }, [state]); + }, [state, location]); const contextValue = useMemo(() => { return { state, dispatch }; diff --git a/app/vmui/packages/vmui/src/utils/query-string.ts b/app/vmui/packages/vmui/src/utils/query-string.ts index 5d407c2c3f..afb928a629 100644 --- a/app/vmui/packages/vmui/src/utils/query-string.ts +++ b/app/vmui/packages/vmui/src/utils/query-string.ts @@ -1,12 +1,18 @@ import qs from "qs"; import get from "lodash.get"; +import router from "../router"; -const stateToUrlParams = { +const graphStateToUrlParams = { "time.duration": "range_input", "time.period.date": "end_input", "time.period.step": "step_input", "time.relativeTime": "relative_time", - "displayType": "tab" + "displayType": "tab", +}; + +const stateToUrlParams = { + [router.home]: graphStateToUrlParams, + [router.dashboards]: graphStateToUrlParams, }; // TODO need function for detect types. @@ -32,14 +38,23 @@ const stateToUrlParams = { export const setQueryStringWithoutPageReload = (qsValue: string): void => { const w = window; if (w) { - const newurl = `${w.location.protocol}//${w.location.host}${w.location.pathname}?${qsValue}${w.location.hash}`; + const qs = qsValue ? `?${qsValue}` : ""; + const newurl = `${w.location.protocol}//${w.location.host}${w.location.pathname}${qs}${w.location.hash}`; w.history.pushState({ path: newurl }, "", newurl); } }; export const setQueryStringValue = (newValue: Record): void => { - const queryMap = new Map(Object.entries(stateToUrlParams)); - const query = get(newValue, "query", "") as string[]; + const route = window.location.hash.replace("#", ""); + const params = stateToUrlParams[route] || {}; + const queryMap = new Map(Object.entries(params)); + const isGraphRoute = route === router.home || route === router.dashboards; + const newQsValue = isGraphRoute ? getGraphQsValue(newValue, queryMap) : getQsValue(newValue, queryMap); + setQueryStringWithoutPageReload(newQsValue.join("&")); +}; + +const getGraphQsValue = (newValue: Record, queryMap: Map): string[] => { + const query = get(newValue, "query", []) as string[]; const newQsValue: string[] = []; query.forEach((q, i) => { queryMap.forEach((queryKey, stateKey) => { @@ -52,7 +67,20 @@ export const setQueryStringValue = (newValue: Record): void => newQsValue.push(`g${i}.expr=${encodeURIComponent(q)}`); }); - setQueryStringWithoutPageReload(newQsValue.join("&")); + return newQsValue; +}; + +const getQsValue = (newValue: Record, queryMap: Map): string[] => { + const newQsValue: string[] = []; + queryMap.forEach((queryKey, stateKey) => { + const value = get(newValue, stateKey, "") as string; + if (value) { + const valueEncoded = encodeURIComponent(value); + newQsValue.push(`${queryKey}=${valueEncoded}`); + } + }); + + return newQsValue; }; export const getQueryStringValue = (