Revert "feat: added variable in url and made dashboard sync around that and sharable (#7944)"

This reverts commit 1d1557e79ab460d21a12bfacd042c7ce07aecbb8.
This commit is contained in:
SagarRajput-7 2025-08-21 11:29:24 +05:30
parent f84a926310
commit c80b9e4da4
7 changed files with 19 additions and 369 deletions

View File

@ -49,5 +49,4 @@ export enum QueryParams {
tab = 'tab',
thresholds = 'thresholds',
selectedExplorerView = 'selectedExplorerView',
variableConfigs = 'variableConfigs',
}

View File

@ -1,8 +1,8 @@
import { Row } from 'antd';
import useVariablesFromUrl from 'hooks/dashboard/useVariablesFromUrl';
import './DashboardVariableSelection.styles.scss';
import { Alert, Row } from 'antd';
import { isEmpty } from 'lodash-es';
import { useDashboard } from 'providers/Dashboard/Dashboard';
import { initializeDefaultVariables } from 'providers/Dashboard/initializeDefaultVariables';
import { memo, useEffect, useState } from 'react';
import { useSelector } from 'react-redux';
import { AppState } from 'store/reducers';
@ -28,8 +28,6 @@ function DashboardVariableSelection(): JSX.Element | null {
setVariablesToGetUpdated,
} = useDashboard();
const { updateUrlVariable, getUrlVariables } = useVariablesFromUrl();
const { data } = selectedDashboard || {};
const { variables } = data || {};
@ -63,11 +61,8 @@ function DashboardVariableSelection(): JSX.Element | null {
tableRowData.sort((a, b) => a.order - b.order);
setVariablesTableData(tableRowData);
// Initialize variables with default values if not in URL
initializeDefaultVariables(variables, getUrlVariables, updateUrlVariable);
}
}, [getUrlVariables, updateUrlVariable, variables]);
}, [variables]);
useEffect(() => {
if (variablesTableData.length > 0) {
@ -116,8 +111,6 @@ function DashboardVariableSelection(): JSX.Element | null {
if (id) {
updateLocalStorageDashboardVariables(name, value, allSelected);
updateUrlVariable(id, value, allSelected);
if (selectedDashboard) {
setSelectedDashboard((prev) => {
if (prev) {

View File

@ -135,6 +135,17 @@ function VariableItem({
) {
const value = variableData.selectedValue;
let allSelected = false;
// The default value for multi-select is ALL and first value for
// single select
// console.log(valueNotInList);
// if (valueNotInList) {
// if (variableData.multiSelect) {
// value = newOptionsData;
// allSelected = true;
// } else {
// [value] = newOptionsData;
// }
// } else
if (variableData.multiSelect) {
const { selectedValue } = variableData;

View File

@ -1,169 +0,0 @@
import { act, renderHook } from '@testing-library/react';
import { QueryParams } from 'constants/query';
import { createMemoryHistory } from 'history';
import { Router } from 'react-router-dom';
import { IDashboardVariable } from 'types/api/dashboard/getAll';
import useVariablesFromUrl from '../useVariablesFromUrl';
describe('useVariablesFromUrl', () => {
it('should initialize with empty variables when no URL params exist', () => {
const history = createMemoryHistory({
initialEntries: ['/'],
});
const { result } = renderHook(() => useVariablesFromUrl(), {
wrapper: ({ children }: { children: React.ReactNode }) => (
<Router history={history}>{children}</Router>
),
});
expect(result.current.getUrlVariables()).toEqual({});
});
it('should correctly parse variables from URL', () => {
const mockVariables = {
var1: { selectedValue: 'value1', allSelected: false },
var2: { selectedValue: ['value2', 'value3'], allSelected: true },
};
const encodedVariables = encodeURIComponent(JSON.stringify(mockVariables));
const history = createMemoryHistory({
initialEntries: [`/?${QueryParams.variableConfigs}=${encodedVariables}`],
});
const { result } = renderHook(() => useVariablesFromUrl(), {
wrapper: ({ children }: { children: React.ReactNode }) => (
<Router history={history}>{children}</Router>
),
});
expect(result.current.getUrlVariables()).toEqual(mockVariables);
});
it('should handle malformed URL parameters gracefully', () => {
const history = createMemoryHistory({
initialEntries: [`/?${QueryParams.variableConfigs}=invalid-json`],
});
const { result } = renderHook(() => useVariablesFromUrl(), {
wrapper: ({ children }: { children: React.ReactNode }) => (
<Router history={history}>{children}</Router>
),
});
// Should return empty object when JSON parsing fails
expect(result.current.getUrlVariables()).toEqual({});
});
it('should set variables to URL correctly', () => {
const history = createMemoryHistory({
initialEntries: ['/'],
});
const { result } = renderHook(() => useVariablesFromUrl(), {
wrapper: ({ children }: { children: React.ReactNode }) => (
<Router history={history}>{children}</Router>
),
});
const mockVariables = {
var1: { selectedValue: 'value1', allSelected: false },
};
act(() => {
result.current.setUrlVariables(mockVariables);
});
// Check if the URL was updated correctly
const searchParams = new URLSearchParams(history.location.search);
const urlVariables = searchParams.get(QueryParams.variableConfigs);
expect(urlVariables).toBeTruthy();
expect(JSON.parse(decodeURIComponent(urlVariables || ''))).toEqual(
mockVariables,
);
});
it('should remove variables param from URL when empty object is provided', () => {
const mockVariables = {
var1: { selectedValue: 'value1', allSelected: false },
};
const encodedVariables = encodeURIComponent(JSON.stringify(mockVariables));
const history = createMemoryHistory({
initialEntries: [`/?${QueryParams.variableConfigs}=${encodedVariables}`],
});
const { result } = renderHook(() => useVariablesFromUrl(), {
wrapper: ({ children }: { children: React.ReactNode }) => (
<Router history={history}>{children}</Router>
),
});
act(() => {
result.current.setUrlVariables({});
});
// Check if the URL param was removed
const searchParams = new URLSearchParams(history.location.search);
expect(searchParams.has(QueryParams.variableConfigs)).toBe(false);
});
it('should update a specific variable correctly', () => {
const initialVariables = {
var1: { selectedValue: 'value1', allSelected: false },
var2: { selectedValue: ['value2'], allSelected: true },
};
const encodedVariables = encodeURIComponent(JSON.stringify(initialVariables));
const history = createMemoryHistory({
initialEntries: [`/?${QueryParams.variableConfigs}=${encodedVariables}`],
});
const { result } = renderHook(() => useVariablesFromUrl(), {
wrapper: ({ children }: { children: React.ReactNode }) => (
<Router history={history}>{children}</Router>
),
});
const newValue: IDashboardVariable['selectedValue'] = 'updated-value';
act(() => {
result.current.updateUrlVariable('var1', newValue, true);
});
// Check if only the specified variable was updated
const updatedVariables = result.current.getUrlVariables();
expect(updatedVariables.var1).toEqual({
selectedValue: newValue,
allSelected: true,
});
expect(updatedVariables.var2).toEqual(initialVariables.var2);
});
it('should preserve other URL parameters when updating variables', () => {
const history = createMemoryHistory({
initialEntries: ['/?otherParam=value'],
});
const { result } = renderHook(() => useVariablesFromUrl(), {
wrapper: ({ children }: { children: React.ReactNode }) => (
<Router history={history}>{children}</Router>
),
});
const mockVariables = {
var1: { selectedValue: 'value1', allSelected: false },
};
act(() => {
result.current.setUrlVariables(mockVariables);
});
// Check if other params are preserved
const searchParams = new URLSearchParams(history.location.search);
expect(searchParams.get('otherParam')).toBe('value');
expect(searchParams.has(QueryParams.variableConfigs)).toBe(true);
});
});

View File

@ -1,102 +0,0 @@
import { QueryParams } from 'constants/query';
import useUrlQuery from 'hooks/useUrlQuery';
import { useCallback } from 'react';
import { useHistory } from 'react-router-dom';
import { IDashboardVariable } from 'types/api/dashboard/getAll';
interface LocalStoreDashboardVariables {
[id: string]: {
selectedValue: IDashboardVariable['selectedValue'];
allSelected: boolean;
};
}
interface UseVariablesFromUrlReturn {
getUrlVariables: () => LocalStoreDashboardVariables;
setUrlVariables: (variables: LocalStoreDashboardVariables) => void;
updateUrlVariable: (
id: string,
selectedValue: IDashboardVariable['selectedValue'],
allSelected: boolean,
) => void;
clearUrlVariables: () => void;
}
const useVariablesFromUrl = (): UseVariablesFromUrlReturn => {
const urlQuery = useUrlQuery();
const history = useHistory();
const getUrlVariables = useCallback((): LocalStoreDashboardVariables => {
const variableConfigsParam = urlQuery.get(QueryParams.variableConfigs);
if (!variableConfigsParam) {
return {};
}
try {
return JSON.parse(decodeURIComponent(variableConfigsParam));
} catch (error) {
console.error('Failed to parse variables from URL:', error);
return {};
}
}, [urlQuery]);
const setUrlVariables = useCallback(
(variables: LocalStoreDashboardVariables): void => {
const params = new URLSearchParams(urlQuery.toString());
if (Object.keys(variables).length === 0) {
params.delete(QueryParams.variableConfigs);
} else {
try {
const encodedVariables = encodeURIComponent(JSON.stringify(variables));
params.set(QueryParams.variableConfigs, encodedVariables);
} catch (error) {
console.error('Failed to serialize variables for URL:', error);
}
}
history.replace({
search: params.toString(),
});
},
[history, urlQuery],
);
const clearUrlVariables = useCallback((): void => {
const params = new URLSearchParams(urlQuery.toString());
params.delete(QueryParams.variableConfigs);
params.delete('options');
history.replace({
search: params.toString(),
});
}, [history, urlQuery]);
const updateUrlVariable = useCallback(
(
id: string,
selectedValue: IDashboardVariable['selectedValue'],
allSelected: boolean,
): void => {
const currentVariables = getUrlVariables();
const updatedVariables = {
...currentVariables,
[id]: { selectedValue, allSelected },
};
setUrlVariables(updatedVariables);
},
[getUrlVariables, setUrlVariables],
);
return {
getUrlVariables,
setUrlVariables,
updateUrlVariable,
clearUrlVariables,
};
};
export default useVariablesFromUrl;

View File

@ -7,8 +7,6 @@ import ROUTES from 'constants/routes';
import { getMinMax } from 'container/TopNav/AutoRefresh/config';
import dayjs, { Dayjs } from 'dayjs';
import { useDashboardVariablesFromLocalStorage } from 'hooks/dashboard/useDashboardFromLocalStorage';
import useVariablesFromUrl from 'hooks/dashboard/useVariablesFromUrl';
import useAxiosError from 'hooks/useAxiosError';
import { useSafeNavigate } from 'hooks/useSafeNavigate';
import useTabVisibility from 'hooks/useTabFocus';
import useUrlQuery from 'hooks/useUrlQuery';
@ -18,7 +16,6 @@ import isEqual from 'lodash-es/isEqual';
import isUndefined from 'lodash-es/isUndefined';
import omitBy from 'lodash-es/omitBy';
import { useAppContext } from 'providers/App/App';
import { initializeDefaultVariables } from 'providers/Dashboard/initializeDefaultVariables';
import { useErrorModal } from 'providers/ErrorModalProvider';
import {
createContext,
@ -201,12 +198,6 @@ export function DashboardProvider({
updateLocalStorageDashboardVariables,
} = useDashboardVariablesFromLocalStorage(dashboardId);
const {
getUrlVariables,
updateUrlVariable,
clearUrlVariables,
} = useVariablesFromUrl();
const updatedTimeRef = useRef<Dayjs | null>(null); // Using ref to store the updated time
const modalRef = useRef<any>(null);
@ -217,14 +208,6 @@ export function DashboardProvider({
const [isDashboardFetching, setIsDashboardFetching] = useState<boolean>(false);
// Clear variable configs when not on dashboard pages
useEffect(() => {
const isOnDashboardPage = !!isDashboardPage || !!isDashboardWidgetPage;
if (!isOnDashboardPage) {
clearUrlVariables();
}
}, [isDashboardPage, isDashboardWidgetPage, clearUrlVariables]);
const mergeDBWithLocalStorage = (
data: Dashboard,
localStorageVariables: any,
@ -234,23 +217,11 @@ export function DashboardProvider({
const updatedVariables = data.data.variables;
Object.keys(data.data.variables).forEach((variable) => {
const variableData = data.data.variables[variable];
// values from url
const urlVariable = getUrlVariables()[variableData.id];
let updatedVariable = {
const updatedVariable = {
...data.data.variables[variable],
...localStorageVariables[variableData.name as any],
};
// respect the url variable if it is set, override the others
if (urlVariable) {
updatedVariable = {
...updatedVariable,
...urlVariable,
};
}
updatedVariables[variable] = updatedVariable;
});
updatedData.data.variables = updatedVariables;
@ -318,16 +289,9 @@ export function DashboardProvider({
onError: (error) => {
showErrorModal(error as APIError);
},
// eslint-disable-next-line sonarjs/cognitive-complexity
onSuccess: (data) => {
// if the url variable is not set for any variable, set it to the default value
const variables = data?.data?.variables;
if (variables) {
initializeDefaultVariables(variables, getUrlVariables, updateUrlVariable);
}
const updatedDashboardData = transformDashboardVariables(data);
const updatedDate = dayjs(updatedDashboardData.updatedAt);
onSuccess: (data: SuccessResponseV2<Dashboard>) => {
const updatedDashboardData = transformDashboardVariables(data?.data);
const updatedDate = dayjs(updatedDashboardData?.updatedAt);
setIsDashboardLocked(updatedDashboardData?.locked || false);

View File

@ -1,46 +0,0 @@
import { IDashboardVariable } from 'types/api/dashboard/getAll';
import { commaValuesParser } from '../../lib/dashbaordVariables/customCommaValuesParser';
interface UrlVariables {
[key: string]: any;
}
/**
* Initializes default values for dashboard variables if not already in URL
* Handles cases where variables might be keyed by either id or name
*
* @param variables Dashboard variables object
* @param getUrlVariables Function to get variables from URL
* @param updateUrlVariable Function to update URL with variable values
*/
export const initializeDefaultVariables = (
variables: Record<string, IDashboardVariable>,
getUrlVariables: () => UrlVariables | undefined,
updateUrlVariable: (
id: string,
selectedValue: IDashboardVariable['selectedValue'],
allSelected: boolean,
) => void,
): void => {
if (!variables) return;
Object.values(variables).forEach((variable) => {
const { id, name } = variable;
const urlVariables = getUrlVariables();
// Check if either id or name is available in URL variables
const existsInUrl =
(id && urlVariables?.[id]) || (name && urlVariables?.[name]);
if (!existsInUrl) {
updateUrlVariable(
id,
variable.type === 'CUSTOM'
? commaValuesParser(variable?.customValue || '')
: variable?.selectedValue || variable?.defaultValue,
variable.allSelected || false,
);
}
});
};