mirror of
https://git.mirrors.martin98.com/https://github.com/SigNoz/signoz
synced 2025-08-01 03:51:59 +08:00
fix: autosave layout to layout change (#4385)
* fix: autosave layout to layout change * fix: autosave layout to layout change * refactor: no update api call on opening dashboard * refactor: removed extra put api call * refactor: if condition changed --------- Co-authored-by: Rajat-Dabade <rajat@signoz.io>
This commit is contained in:
parent
1163c16506
commit
4a1c48b72b
@ -1,6 +1,6 @@
|
|||||||
import './GridCardLayout.styles.scss';
|
import './GridCardLayout.styles.scss';
|
||||||
|
|
||||||
import { PlusOutlined, SaveFilled } from '@ant-design/icons';
|
import { PlusOutlined } from '@ant-design/icons';
|
||||||
import { SOMETHING_WENT_WRONG } from 'constants/api';
|
import { SOMETHING_WENT_WRONG } from 'constants/api';
|
||||||
import { PANEL_TYPES } from 'constants/queryBuilder';
|
import { PANEL_TYPES } from 'constants/queryBuilder';
|
||||||
import { themeColors } from 'constants/theme';
|
import { themeColors } from 'constants/theme';
|
||||||
@ -8,9 +8,12 @@ import { useUpdateDashboard } from 'hooks/dashboard/useUpdateDashboard';
|
|||||||
import useComponentPermission from 'hooks/useComponentPermission';
|
import useComponentPermission from 'hooks/useComponentPermission';
|
||||||
import { useIsDarkMode } from 'hooks/useDarkMode';
|
import { useIsDarkMode } from 'hooks/useDarkMode';
|
||||||
import { useNotifications } from 'hooks/useNotifications';
|
import { useNotifications } from 'hooks/useNotifications';
|
||||||
|
import isEqual from 'lodash-es/isEqual';
|
||||||
import { FullscreenIcon } from 'lucide-react';
|
import { FullscreenIcon } from 'lucide-react';
|
||||||
import { useDashboard } from 'providers/Dashboard/Dashboard';
|
import { useDashboard } from 'providers/Dashboard/Dashboard';
|
||||||
|
import { useEffect, useState } from 'react';
|
||||||
import { FullScreen, useFullScreenHandle } from 'react-full-screen';
|
import { FullScreen, useFullScreenHandle } from 'react-full-screen';
|
||||||
|
import { Layout } from 'react-grid-layout';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
import { useSelector } from 'react-redux';
|
import { useSelector } from 'react-redux';
|
||||||
import { AppState } from 'store/reducers';
|
import { AppState } from 'store/reducers';
|
||||||
@ -29,6 +32,7 @@ import {
|
|||||||
ReactGridLayout,
|
ReactGridLayout,
|
||||||
} from './styles';
|
} from './styles';
|
||||||
import { GraphLayoutProps } from './types';
|
import { GraphLayoutProps } from './types';
|
||||||
|
import { removeUndefinedValuesFromLayout } from './utils';
|
||||||
|
|
||||||
function GraphLayout({ onAddPanelHandler }: GraphLayoutProps): JSX.Element {
|
function GraphLayout({ onAddPanelHandler }: GraphLayoutProps): JSX.Element {
|
||||||
const {
|
const {
|
||||||
@ -51,6 +55,8 @@ function GraphLayout({ onAddPanelHandler }: GraphLayoutProps): JSX.Element {
|
|||||||
|
|
||||||
const isDarkMode = useIsDarkMode();
|
const isDarkMode = useIsDarkMode();
|
||||||
|
|
||||||
|
const [dashboardLayout, setDashboardLayout] = useState(layouts);
|
||||||
|
|
||||||
const updateDashboardMutation = useUpdateDashboard();
|
const updateDashboardMutation = useUpdateDashboard();
|
||||||
|
|
||||||
const { notifications } = useNotifications();
|
const { notifications } = useNotifications();
|
||||||
@ -78,7 +84,7 @@ function GraphLayout({ onAddPanelHandler }: GraphLayoutProps): JSX.Element {
|
|||||||
...selectedDashboard,
|
...selectedDashboard,
|
||||||
data: {
|
data: {
|
||||||
...selectedDashboard.data,
|
...selectedDashboard.data,
|
||||||
layout: layouts.filter((e) => e.i !== PANEL_TYPES.EMPTY_WIDGET),
|
layout: dashboardLayout.filter((e) => e.i !== PANEL_TYPES.EMPTY_WIDGET),
|
||||||
},
|
},
|
||||||
uuid: selectedDashboard.uuid,
|
uuid: selectedDashboard.uuid,
|
||||||
};
|
};
|
||||||
@ -90,9 +96,6 @@ function GraphLayout({ onAddPanelHandler }: GraphLayoutProps): JSX.Element {
|
|||||||
setLayouts(updatedDashboard.payload.data.layout);
|
setLayouts(updatedDashboard.payload.data.layout);
|
||||||
setSelectedDashboard(updatedDashboard.payload);
|
setSelectedDashboard(updatedDashboard.payload);
|
||||||
}
|
}
|
||||||
notifications.success({
|
|
||||||
message: t('dashboard:layout_saved_successfully'),
|
|
||||||
});
|
|
||||||
|
|
||||||
featureResponse.refetch();
|
featureResponse.refetch();
|
||||||
},
|
},
|
||||||
@ -108,6 +111,32 @@ function GraphLayout({ onAddPanelHandler }: GraphLayoutProps): JSX.Element {
|
|||||||
? [...ViewMenuAction, ...EditMenuAction]
|
? [...ViewMenuAction, ...EditMenuAction]
|
||||||
: [...ViewMenuAction];
|
: [...ViewMenuAction];
|
||||||
|
|
||||||
|
const handleLayoutChange = (layout: Layout[]): void => {
|
||||||
|
const filterLayout = removeUndefinedValuesFromLayout(layout);
|
||||||
|
const filterDashboardLayout = removeUndefinedValuesFromLayout(
|
||||||
|
dashboardLayout,
|
||||||
|
);
|
||||||
|
if (!isEqual(filterLayout, filterDashboardLayout)) {
|
||||||
|
setDashboardLayout(layout);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (
|
||||||
|
dashboardLayout &&
|
||||||
|
Array.isArray(dashboardLayout) &&
|
||||||
|
dashboardLayout.length > 0 &&
|
||||||
|
!isEqual(layouts, dashboardLayout) &&
|
||||||
|
!isDashboardLocked &&
|
||||||
|
saveLayoutPermission &&
|
||||||
|
!updateDashboardMutation.isLoading
|
||||||
|
) {
|
||||||
|
onSaveHandler();
|
||||||
|
}
|
||||||
|
|
||||||
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
|
}, [dashboardLayout]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<ButtonContainer>
|
<ButtonContainer>
|
||||||
@ -120,17 +149,6 @@ function GraphLayout({ onAddPanelHandler }: GraphLayoutProps): JSX.Element {
|
|||||||
{t('dashboard:full_view')}
|
{t('dashboard:full_view')}
|
||||||
</Button>
|
</Button>
|
||||||
|
|
||||||
{!isDashboardLocked && saveLayoutPermission && (
|
|
||||||
<Button
|
|
||||||
loading={updateDashboardMutation.isLoading}
|
|
||||||
onClick={onSaveHandler}
|
|
||||||
icon={<SaveFilled />}
|
|
||||||
disabled={updateDashboardMutation.isLoading}
|
|
||||||
>
|
|
||||||
{t('dashboard:save_layout')}
|
|
||||||
</Button>
|
|
||||||
)}
|
|
||||||
|
|
||||||
{!isDashboardLocked && addPanelPermission && (
|
{!isDashboardLocked && addPanelPermission && (
|
||||||
<Button
|
<Button
|
||||||
onClick={onAddPanelHandler}
|
onClick={onAddPanelHandler}
|
||||||
@ -153,12 +171,12 @@ function GraphLayout({ onAddPanelHandler }: GraphLayoutProps): JSX.Element {
|
|||||||
isDroppable={!isDashboardLocked && addPanelPermission}
|
isDroppable={!isDashboardLocked && addPanelPermission}
|
||||||
isResizable={!isDashboardLocked && addPanelPermission}
|
isResizable={!isDashboardLocked && addPanelPermission}
|
||||||
allowOverlap={false}
|
allowOverlap={false}
|
||||||
onLayoutChange={setLayouts}
|
onLayoutChange={handleLayoutChange}
|
||||||
draggableHandle=".drag-handle"
|
draggableHandle=".drag-handle"
|
||||||
layout={layouts}
|
layout={dashboardLayout}
|
||||||
style={{ backgroundColor: isDarkMode ? '' : themeColors.snowWhite }}
|
style={{ backgroundColor: isDarkMode ? '' : themeColors.snowWhite }}
|
||||||
>
|
>
|
||||||
{layouts.map((layout) => {
|
{dashboardLayout.map((layout) => {
|
||||||
const { i: id } = layout;
|
const { i: id } = layout;
|
||||||
const currentWidget = (widgets || [])?.find((e) => e.id === id);
|
const currentWidget = (widgets || [])?.find((e) => e.id === id);
|
||||||
|
|
||||||
|
@ -8,6 +8,8 @@
|
|||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
|
|
||||||
|
cursor: move;
|
||||||
}
|
}
|
||||||
|
|
||||||
.widget-header-title {
|
.widget-header-title {
|
||||||
|
8
frontend/src/container/GridCardLayout/utils.ts
Normal file
8
frontend/src/container/GridCardLayout/utils.ts
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
import { Layout } from 'react-grid-layout';
|
||||||
|
|
||||||
|
export const removeUndefinedValuesFromLayout = (layout: Layout[]): Layout[] =>
|
||||||
|
layout.map((obj) =>
|
||||||
|
Object.fromEntries(
|
||||||
|
Object.entries(obj).filter(([, value]) => value !== undefined),
|
||||||
|
),
|
||||||
|
) as Layout[];
|
Loading…
x
Reference in New Issue
Block a user