feat: support dashboard local state (#4475)

This commit is contained in:
Vikrant Gupta 2024-02-05 12:07:55 +05:30 committed by GitHub
parent 6837c41090
commit 26bc94fc46
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 178 additions and 66 deletions

View File

@ -6,6 +6,12 @@
.dynamicColumnTable-button {
align-self: flex-end;
margin: 10px 0;
&.filter-btn {
display: flex;
align-items: center;
justify-content: center;
}
}
}

View File

@ -1,9 +1,9 @@
/* eslint-disable react/jsx-props-no-spreading */
import './DynamicColumnTable.syles.scss';
import { SettingOutlined } from '@ant-design/icons';
import { Button, Dropdown, MenuProps, Switch } from 'antd';
import { ColumnsType } from 'antd/lib/table';
import { SlidersHorizontal } from 'lucide-react';
import { memo, useEffect, useState } from 'react';
import { popupContainer } from 'utils/selectPopupContainer';
@ -90,9 +90,9 @@ function DynamicColumnTable({
trigger={['click']}
>
<Button
className="dynamicColumnTable-button"
className="dynamicColumnTable-button filter-btn"
size="middle"
icon={<SettingOutlined />}
icon={<SlidersHorizontal size={14} />}
/>
</Dropdown>
)}

View File

@ -15,4 +15,5 @@ export enum LOCALSTORAGE {
LOGGED_IN_USER_EMAIL = 'LOGGED_IN_USER_EMAIL',
CHAT_SUPPORT = 'CHAT_SUPPORT',
IS_IDENTIFIED_USER = 'IS_IDENTIFIED_USER',
DASHBOARD_VARIABLES = 'DASHBOARD_VARIABLES',
}

View File

@ -1,18 +1,22 @@
import { Row } from 'antd';
import { useUpdateDashboard } from 'hooks/dashboard/useUpdateDashboard';
import { useNotifications } from 'hooks/useNotifications';
import { useDashboardVariablesFromLocalStorage } from 'hooks/dashboard/useDashboardFromLocalStorage';
import { useDashboard } from 'providers/Dashboard/Dashboard';
import { memo, useEffect, useState } from 'react';
import { useSelector } from 'react-redux';
import { AppState } from 'store/reducers';
import { Dashboard, IDashboardVariable } from 'types/api/dashboard/getAll';
import AppReducer from 'types/reducer/app';
import { IDashboardVariable } from 'types/api/dashboard/getAll';
import { convertVariablesToDbFormat } from './util';
import VariableItem from './VariableItem';
function DashboardVariableSelection(): JSX.Element | null {
const { selectedDashboard, setSelectedDashboard } = useDashboard();
const {
selectedDashboard,
setSelectedDashboard,
dashboardId,
} = useDashboard();
const {
updateLocalStorageDashboardVariables,
} = useDashboardVariablesFromLocalStorage(dashboardId);
const { data } = selectedDashboard || {};
@ -23,8 +27,6 @@ function DashboardVariableSelection(): JSX.Element | null {
const [variablesTableData, setVariablesTableData] = useState<any>([]);
const { role } = useSelector<AppState, AppReducer>((state) => state.app);
useEffect(() => {
if (variables) {
const tableRowData = [];
@ -52,40 +54,6 @@ function DashboardVariableSelection(): JSX.Element | null {
setUpdate(!update);
};
const updateMutation = useUpdateDashboard();
const { notifications } = useNotifications();
const updateVariables = (
name: string,
updatedVariablesData: Dashboard['data']['variables'],
): void => {
if (!selectedDashboard) {
return;
}
updateMutation.mutateAsync(
{
...selectedDashboard,
data: {
...selectedDashboard.data,
variables: updatedVariablesData,
},
},
{
onSuccess: (updatedDashboard) => {
if (updatedDashboard.payload) {
setSelectedDashboard(updatedDashboard.payload);
}
},
onError: () => {
notifications.error({
message: `Error updating ${name} variable`,
});
},
},
);
};
const onValueUpdate = (
name: string,
id: string,
@ -105,12 +73,22 @@ function DashboardVariableSelection(): JSX.Element | null {
return variableCopy;
},
);
updateLocalStorageDashboardVariables(id, value, allSelected);
const variables = convertVariablesToDbFormat(newVariablesArr);
if (role !== 'VIEWER' && selectedDashboard) {
updateVariables(name, variables);
if (selectedDashboard) {
setSelectedDashboard({
...selectedDashboard,
data: {
...selectedDashboard?.data,
variables: {
...variables,
},
},
});
}
onVarChanged(name);
setUpdate(!update);

View File

@ -0,0 +1,100 @@
import getLocalStorageKey from 'api/browser/localstorage/get';
import setLocalStorageKey from 'api/browser/localstorage/set';
import { LOCALSTORAGE } from 'constants/localStorage';
import { defaultTo } from 'lodash-es';
import { useEffect, useState } from 'react';
import { IDashboardVariable } from 'types/api/dashboard/getAll';
interface LocalStoreDashboardVariables {
[id: string]: {
selectedValue: IDashboardVariable['selectedValue'];
allSelected: boolean;
};
}
interface DashboardLocalStorageVariables {
[id: string]: LocalStoreDashboardVariables;
}
interface UseDashboardVariablesFromLocalStorageReturn {
currentDashboard: LocalStoreDashboardVariables;
updateLocalStorageDashboardVariables: (
id: string,
selectedValue: IDashboardVariable['selectedValue'],
allSelected: boolean,
) => void;
}
export const useDashboardVariablesFromLocalStorage = (
dashboardId: string,
): UseDashboardVariablesFromLocalStorageReturn => {
const [
allDashboards,
setAllDashboards,
] = useState<DashboardLocalStorageVariables>({});
const [
currentDashboard,
setCurrentDashboard,
] = useState<LocalStoreDashboardVariables>({});
useEffect(() => {
const localStoreDashboardVariablesString = getLocalStorageKey(
LOCALSTORAGE.DASHBOARD_VARIABLES,
);
let localStoreDashboardVariables: DashboardLocalStorageVariables = {};
if (localStoreDashboardVariablesString === null) {
try {
const serialzedData = JSON.stringify({
[dashboardId]: {},
});
setLocalStorageKey(LOCALSTORAGE.DASHBOARD_VARIABLES, serialzedData);
} catch {
console.error('Failed to seralise the data');
}
} else {
try {
localStoreDashboardVariables = JSON.parse(
localStoreDashboardVariablesString,
);
} catch {
console.error('Failed to parse dashboards from local storage');
localStoreDashboardVariables = {};
} finally {
setAllDashboards(localStoreDashboardVariables);
}
}
setCurrentDashboard(defaultTo(localStoreDashboardVariables[dashboardId], {}));
}, [dashboardId]);
const updateLocalStorageDashboardVariables = (
id: string,
selectedValue: IDashboardVariable['selectedValue'],
allSelected: boolean,
): void => {
const newCurrentDashboard = {
...currentDashboard,
[id]: { selectedValue, allSelected },
};
const newAllDashboards = {
...allDashboards,
[dashboardId]: newCurrentDashboard,
};
try {
const serializedData = JSON.stringify(newAllDashboards);
setLocalStorageKey(LOCALSTORAGE.DASHBOARD_VARIABLES, serializedData);
} catch {
console.error('Failed to set dashboards in local storage');
}
setAllDashboards(newAllDashboards);
setCurrentDashboard(newCurrentDashboard);
};
return {
currentDashboard,
updateLocalStorageDashboardVariables,
};
};

View File

@ -6,6 +6,7 @@ import { REACT_QUERY_KEY } from 'constants/reactQueryKeys';
import ROUTES from 'constants/routes';
import { getMinMax } from 'container/TopNav/AutoRefresh/config';
import dayjs, { Dayjs } from 'dayjs';
import { useDashboardVariablesFromLocalStorage } from 'hooks/dashboard/useDashboardFromLocalStorage';
import useAxiosError from 'hooks/useAxiosError';
import useTabVisibility from 'hooks/useTabFocus';
import { getUpdatedLayout } from 'lib/dashboard/getUpdatedLayout';
@ -95,6 +96,10 @@ export function DashboardProvider({
const [selectedDashboard, setSelectedDashboard] = useState<Dashboard>();
const { currentDashboard } = useDashboardVariablesFromLocalStorage(
dashboardId,
);
const updatedTimeRef = useRef<Dayjs | null>(null); // Using ref to store the updated time
const modalRef = useRef<any>(null);
@ -103,11 +108,33 @@ export function DashboardProvider({
const { t } = useTranslation(['dashboard']);
const dashboardRef = useRef<Dashboard>();
const mergeDBWithLocalStorage = (
data: Dashboard,
localStorageVariables: any,
): Dashboard => {
const updatedData = data;
if (data && localStorageVariables) {
const updatedVariables = data.data.variables;
Object.keys(data.data.variables).forEach((variable) => {
const updatedVariable = {
...data.data.variables[variable],
...localStorageVariables[variable as any],
};
updatedVariables[variable] = updatedVariable;
});
updatedData.data.variables = updatedVariables;
}
return updatedData;
};
// As we do not have order and ID's in the variables object, we have to process variables to add order and ID if they do not exist in the variables object
// eslint-disable-next-line sonarjs/cognitive-complexity
const transformDashboardVariables = (data: Dashboard): Dashboard => {
if (data && data.data && data.data.variables) {
const clonedDashboardData = JSON.parse(JSON.stringify(data));
const clonedDashboardData = mergeDBWithLocalStorage(
JSON.parse(JSON.stringify(data)),
currentDashboard,
);
const { variables } = clonedDashboardData.data;
const existingOrders: Set<number> = new Set();