mirror of
https://git.mirrors.martin98.com/https://github.com/SigNoz/signoz
synced 2025-08-08 15:58:59 +08:00
fix: save layout bug is resolved (#840)
* fix: save layout bug is resolved * chore: onClick is also added in the component slider * chore: dashboard Id is added * chore: non dashboard widget is filtered out * chore: panel layout stack issue is resolved
This commit is contained in:
parent
86bdb9a5ad
commit
c00f0f159b
@ -48,7 +48,7 @@ const GridCardGraph = ({
|
||||
(async (): Promise<void> => {
|
||||
try {
|
||||
const getMaxMinTime = GetMaxMinTime({
|
||||
graphType: widget.panelTypes,
|
||||
graphType: widget?.panelTypes,
|
||||
maxTime,
|
||||
minTime,
|
||||
});
|
||||
@ -125,7 +125,7 @@ const GridCardGraph = ({
|
||||
[],
|
||||
);
|
||||
|
||||
const getModals = () => {
|
||||
const getModals = (): JSX.Element => {
|
||||
return (
|
||||
<>
|
||||
<Modal
|
||||
|
@ -1,12 +1,12 @@
|
||||
/* eslint-disable react/display-name */
|
||||
import { SaveFilled } from '@ant-design/icons';
|
||||
import { notification } from 'antd';
|
||||
import updateDashboardApi from 'api/dashboard/update';
|
||||
import Spinner from 'components/Spinner';
|
||||
import { GRAPH_TYPES } from 'container/NewDashboard/ComponentsSlider';
|
||||
import React, { memo, useCallback, useEffect, useRef, useState } from 'react';
|
||||
import { Layout } from 'react-grid-layout';
|
||||
import { useSelector } from 'react-redux';
|
||||
import { useHistory, useLocation } from 'react-router-dom';
|
||||
import { AppState } from 'store/reducers';
|
||||
import DashboardReducer from 'types/reducer/dashboards';
|
||||
import { v4 } from 'uuid';
|
||||
@ -20,11 +20,9 @@ import {
|
||||
CardContainer,
|
||||
ReactGridLayout,
|
||||
} from './styles';
|
||||
import { updateDashboard } from './utils';
|
||||
|
||||
const GridGraph = (): JSX.Element => {
|
||||
const { push } = useHistory();
|
||||
const { pathname } = useLocation();
|
||||
|
||||
const { dashboards, loading } = useSelector<AppState, DashboardReducer>(
|
||||
(state) => state.dashboards,
|
||||
);
|
||||
@ -50,6 +48,7 @@ const GridGraph = (): JSX.Element => {
|
||||
return [];
|
||||
}
|
||||
|
||||
// when the layout is not present
|
||||
if (data.layout === undefined) {
|
||||
return widgets.map((e, index) => {
|
||||
return {
|
||||
@ -69,17 +68,24 @@ const GridGraph = (): JSX.Element => {
|
||||
};
|
||||
});
|
||||
} else {
|
||||
return data.layout.map((e, index) => ({
|
||||
...e,
|
||||
y: 0,
|
||||
Component: (): JSX.Element => (
|
||||
<Graph
|
||||
name={e.i + index}
|
||||
isDeleted={isDeleted}
|
||||
widget={widgets[index]}
|
||||
/>
|
||||
),
|
||||
}));
|
||||
return data.layout
|
||||
.filter((_, index) => widgets[index])
|
||||
.map((e, index) => ({
|
||||
...e,
|
||||
Component: (): JSX.Element => {
|
||||
if (widgets[index]) {
|
||||
return (
|
||||
<Graph
|
||||
name={e.i + index}
|
||||
isDeleted={isDeleted}
|
||||
widget={widgets[index]}
|
||||
yAxisUnit={widgets[index].yAxisUnit}
|
||||
/>
|
||||
);
|
||||
}
|
||||
return <></>;
|
||||
},
|
||||
}));
|
||||
}
|
||||
}, [widgets, data.layout]);
|
||||
|
||||
@ -89,21 +95,34 @@ const GridGraph = (): JSX.Element => {
|
||||
(isMounted.current === true || isDeleted.current === true)
|
||||
) {
|
||||
const preLayouts = getPreLayouts();
|
||||
setLayout(() => [
|
||||
...preLayouts,
|
||||
{
|
||||
i: (preLayouts.length + 1).toString(),
|
||||
x: (preLayouts.length % 2) * 6,
|
||||
y: Infinity,
|
||||
w: 6,
|
||||
h: 2,
|
||||
Component: AddWidgetWrapper,
|
||||
maxW: 6,
|
||||
isDraggable: false,
|
||||
isResizable: false,
|
||||
isBounded: true,
|
||||
},
|
||||
]);
|
||||
setLayout(() => {
|
||||
const getX = (): number => {
|
||||
if (preLayouts && preLayouts?.length > 0) {
|
||||
const last = preLayouts[preLayouts?.length - 1];
|
||||
|
||||
return (last.w + last.x) % 12;
|
||||
}
|
||||
return 0;
|
||||
};
|
||||
|
||||
console.log({ x: getX() });
|
||||
|
||||
return [
|
||||
...preLayouts,
|
||||
{
|
||||
i: (preLayouts.length + 1).toString(),
|
||||
x: getX(),
|
||||
y: Infinity,
|
||||
w: 6,
|
||||
h: 2,
|
||||
Component: AddWidgetWrapper,
|
||||
maxW: 6,
|
||||
isDraggable: false,
|
||||
isResizable: false,
|
||||
isBounded: true,
|
||||
},
|
||||
];
|
||||
});
|
||||
}
|
||||
|
||||
return (): void => {
|
||||
@ -112,18 +131,39 @@ const GridGraph = (): JSX.Element => {
|
||||
}, [widgets, layouts.length, AddWidgetWrapper, loading, getPreLayouts]);
|
||||
|
||||
const onDropHandler = useCallback(
|
||||
(allLayouts: Layout[], currectLayout: Layout, event: DragEvent) => {
|
||||
async (allLayouts: Layout[], currentLayout: Layout, event: DragEvent) => {
|
||||
event.preventDefault();
|
||||
if (event.dataTransfer) {
|
||||
const graphType = event.dataTransfer.getData('text') as GRAPH_TYPES;
|
||||
const generateWidgetId = v4();
|
||||
push(`${pathname}/new?graphType=${graphType}&widgetId=${generateWidgetId}`);
|
||||
try {
|
||||
const graphType = event.dataTransfer.getData('text') as GRAPH_TYPES;
|
||||
const generateWidgetId = v4();
|
||||
|
||||
await updateDashboard({
|
||||
data,
|
||||
generateWidgetId,
|
||||
graphType,
|
||||
selectedDashboard: selectedDashboard,
|
||||
layout: allLayouts
|
||||
.map((e, index) => ({
|
||||
...e,
|
||||
i: index.toString(),
|
||||
// when a new element drops
|
||||
w: e.i === '__dropping-elem__' ? 6 : e.w,
|
||||
h: e.i === '__dropping-elem__' ? 2 : e.h,
|
||||
}))
|
||||
.filter((e) => e.maxW === undefined),
|
||||
});
|
||||
} catch (error) {
|
||||
notification.error({
|
||||
message: error.toString() || 'Something went wrong',
|
||||
});
|
||||
}
|
||||
}
|
||||
},
|
||||
[pathname, push],
|
||||
[data, selectedDashboard],
|
||||
);
|
||||
|
||||
const onLayoutSaveHanlder = async (): Promise<void> => {
|
||||
const onLayoutSaveHandler = async (): Promise<void> => {
|
||||
setSaveLayoutState((state) => ({
|
||||
...state,
|
||||
error: false,
|
||||
@ -175,7 +215,7 @@ const GridGraph = (): JSX.Element => {
|
||||
<ButtonContainer>
|
||||
<Button
|
||||
loading={saveLayoutState.loading}
|
||||
onClick={onLayoutSaveHanlder}
|
||||
onClick={onLayoutSaveHandler}
|
||||
icon={<SaveFilled />}
|
||||
danger={saveLayoutState.error}
|
||||
>
|
||||
@ -198,7 +238,7 @@ const GridGraph = (): JSX.Element => {
|
||||
{layouts.map(({ Component, ...rest }, index) => {
|
||||
const widget = (widgets || [])[index] || {};
|
||||
|
||||
const type = widget.panelTypes;
|
||||
const type = widget?.panelTypes || 'TIME_SERIES';
|
||||
|
||||
const isQueryType = type === 'VALUE';
|
||||
|
||||
|
66
frontend/src/container/GridGraphLayout/utils.ts
Normal file
66
frontend/src/container/GridGraphLayout/utils.ts
Normal file
@ -0,0 +1,66 @@
|
||||
import { notification } from 'antd';
|
||||
import updateDashboardApi from 'api/dashboard/update';
|
||||
import { GRAPH_TYPES } from 'container/NewDashboard/ComponentsSlider';
|
||||
import history from 'lib/history';
|
||||
import { Layout } from 'react-grid-layout';
|
||||
import { Dashboard } from 'types/api/dashboard/getAll';
|
||||
|
||||
export const updateDashboard = async ({
|
||||
data,
|
||||
graphType,
|
||||
generateWidgetId,
|
||||
layout,
|
||||
selectedDashboard,
|
||||
}: UpdateDashboardProps): Promise<void> => {
|
||||
const response = await updateDashboardApi({
|
||||
title: data.title,
|
||||
uuid: selectedDashboard.uuid,
|
||||
description: data.description,
|
||||
name: data.name,
|
||||
tags: data.tags,
|
||||
widgets: [
|
||||
...(data.widgets || []),
|
||||
{
|
||||
description: '',
|
||||
id: generateWidgetId,
|
||||
isStacked: false,
|
||||
nullZeroValues: '',
|
||||
opacity: '',
|
||||
panelTypes: graphType,
|
||||
query: [
|
||||
{
|
||||
query: '',
|
||||
legend: '',
|
||||
},
|
||||
],
|
||||
queryData: {
|
||||
data: [],
|
||||
error: false,
|
||||
errorMessage: '',
|
||||
loading: false,
|
||||
},
|
||||
timePreferance: 'GLOBAL_TIME',
|
||||
title: '',
|
||||
},
|
||||
],
|
||||
layout: layout,
|
||||
});
|
||||
|
||||
if (response.statusCode === 200) {
|
||||
history.push(
|
||||
`${history.location.pathname}/new?graphType=${graphType}&widgetId=${generateWidgetId}`,
|
||||
);
|
||||
} else {
|
||||
notification.error({
|
||||
message: response.error || 'Something went wrong',
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
interface UpdateDashboardProps {
|
||||
data: Dashboard['data'];
|
||||
graphType: GRAPH_TYPES;
|
||||
generateWidgetId: string;
|
||||
layout: Layout[];
|
||||
selectedDashboard: Dashboard;
|
||||
}
|
@ -1,37 +1,75 @@
|
||||
import { notification } from 'antd';
|
||||
import { updateDashboard } from 'container/GridGraphLayout/utils';
|
||||
import React, { useCallback } from 'react';
|
||||
import { useSelector } from 'react-redux';
|
||||
import { useHistory, useLocation } from 'react-router';
|
||||
import { AppState } from 'store/reducers';
|
||||
import AppReducer from 'types/reducer/app';
|
||||
import DashboardReducer from 'types/reducer/dashboards';
|
||||
import { v4 } from 'uuid';
|
||||
|
||||
import menuItems, { ITEMS } from './menuItems';
|
||||
import { Card, Container, Text } from './styles';
|
||||
|
||||
const DashboardGraphSlider = (): JSX.Element => {
|
||||
const { dashboards } = useSelector<AppState, DashboardReducer>(
|
||||
(state) => state.dashboards,
|
||||
);
|
||||
|
||||
const [selectedDashboard] = dashboards;
|
||||
const { data } = selectedDashboard;
|
||||
|
||||
const onDragStartHandler: React.DragEventHandler<HTMLDivElement> = useCallback(
|
||||
(event: React.DragEvent<HTMLDivElement>) => {
|
||||
event.dataTransfer.setData('text/plain', event.currentTarget.id);
|
||||
},
|
||||
[],
|
||||
);
|
||||
const { push } = useHistory();
|
||||
const { pathname } = useLocation();
|
||||
|
||||
const onClickHandler = useCallback(
|
||||
(name: ITEMS) => {
|
||||
const generateWidgetId = v4();
|
||||
push(`${pathname}/new?graphType=${name}&widgetId=${generateWidgetId}`);
|
||||
async (name: ITEMS) => {
|
||||
try {
|
||||
const generateWidgetId = v4();
|
||||
|
||||
const getX = (): number => {
|
||||
if (data.layout && data.layout?.length > 0) {
|
||||
const lastIndexX = data.layout[data.layout?.length - 1];
|
||||
return (lastIndexX.w + lastIndexX.x) % 12;
|
||||
}
|
||||
return 0;
|
||||
};
|
||||
|
||||
await updateDashboard({
|
||||
data,
|
||||
generateWidgetId,
|
||||
graphType: name,
|
||||
layout: [
|
||||
...(data.layout || []),
|
||||
{
|
||||
h: 2,
|
||||
i: ((data.layout || [])?.length + 1).toString(),
|
||||
w: 6,
|
||||
x: getX(),
|
||||
y: 0,
|
||||
},
|
||||
],
|
||||
selectedDashboard,
|
||||
});
|
||||
} catch (error) {
|
||||
notification.error({
|
||||
message: 'Something went wrong',
|
||||
});
|
||||
}
|
||||
},
|
||||
[push, pathname],
|
||||
[data, selectedDashboard],
|
||||
);
|
||||
const { isDarkMode } = useSelector<AppState, AppReducer>((state) => state.app);
|
||||
const fillColor: React.CSSProperties['color'] = isDarkMode ? 'white' : 'black';
|
||||
|
||||
return (
|
||||
<Container>
|
||||
{menuItems.map(({ name, Icon, display }) => (
|
||||
<Card
|
||||
onClick={(): void => onClickHandler(name)}
|
||||
onClick={(): Promise<void> => onClickHandler(name)}
|
||||
id={name}
|
||||
onDragStart={onDragStartHandler}
|
||||
key={name}
|
||||
|
@ -13,7 +13,7 @@ const LeftContainer = ({
|
||||
}: LeftContainerProps): JSX.Element => {
|
||||
return (
|
||||
<>
|
||||
<WidgetGraph selectedGraph={selectedGraph} yAxisUnit={yAxisUnit}/>
|
||||
<WidgetGraph selectedGraph={selectedGraph} yAxisUnit={yAxisUnit} />
|
||||
|
||||
<QueryContainer>
|
||||
<QuerySection selectedTime={selectedTime} />
|
||||
|
@ -23,7 +23,7 @@ import {
|
||||
} from 'store/actions/dashboard/updateQuery';
|
||||
import { AppState } from 'store/reducers';
|
||||
import AppActions from 'types/actions';
|
||||
import { GlobalTime } from 'types/actions/globalTime';
|
||||
import { Widgets } from 'types/api/dashboard/getAll';
|
||||
import DashboardReducer from 'types/reducer/dashboards';
|
||||
import { GlobalReducer } from 'types/reducer/globalTime';
|
||||
|
||||
@ -48,7 +48,7 @@ const NewWidget = ({
|
||||
const { dashboards } = useSelector<AppState, DashboardReducer>(
|
||||
(state) => state.dashboards,
|
||||
);
|
||||
const { maxTime, minTime, selectedTime: globalSelectedInterval } = useSelector<
|
||||
const { selectedTime: globalSelectedInterval } = useSelector<
|
||||
AppState,
|
||||
GlobalReducer
|
||||
>((state) => state.globalTime);
|
||||
@ -77,7 +77,9 @@ const NewWidget = ({
|
||||
const [description, setDescription] = useState<string>(
|
||||
selectedWidget?.description || '',
|
||||
);
|
||||
const [yAxisUnit, setYAxisUnit] = useState<string>(selectedWidget?.yAxisUnit || 'none');
|
||||
const [yAxisUnit, setYAxisUnit] = useState<string>(
|
||||
selectedWidget?.yAxisUnit || 'none',
|
||||
);
|
||||
|
||||
const [stacked, setStacked] = useState<boolean>(
|
||||
selectedWidget?.isStacked || false,
|
||||
@ -125,9 +127,10 @@ const NewWidget = ({
|
||||
saveSettingOfPanel,
|
||||
selectedDashboard,
|
||||
dashboardId,
|
||||
yAxisUnit,
|
||||
]);
|
||||
|
||||
const onClickApplyHandler = () => {
|
||||
const onClickApplyHandler = (): void => {
|
||||
selectedWidget?.query.forEach((element, index) => {
|
||||
updateQuery({
|
||||
widgetId: selectedWidget?.id || '',
|
||||
@ -146,7 +149,7 @@ const NewWidget = ({
|
||||
timePreferance: selectedTime.enum,
|
||||
title,
|
||||
widgetId: selectedWidget?.id || '',
|
||||
yAxisUnit
|
||||
yAxisUnit,
|
||||
});
|
||||
};
|
||||
|
||||
@ -167,11 +170,10 @@ const NewWidget = ({
|
||||
}, [
|
||||
selectedWidget?.query,
|
||||
selectedTime.enum,
|
||||
maxTime,
|
||||
minTime,
|
||||
selectedWidget?.id,
|
||||
selectedGraph,
|
||||
getQueryResults,
|
||||
globalSelectedInterval,
|
||||
]);
|
||||
|
||||
useEffect(() => {
|
||||
@ -188,7 +190,11 @@ const NewWidget = ({
|
||||
|
||||
<PanelContainer>
|
||||
<LeftContainerWrapper flex={5}>
|
||||
<LeftContainer selectedTime={selectedTime} selectedGraph={selectedGraph} yAxisUnit={yAxisUnit}/>
|
||||
<LeftContainer
|
||||
selectedTime={selectedTime}
|
||||
selectedGraph={selectedGraph}
|
||||
yAxisUnit={yAxisUnit}
|
||||
/>
|
||||
</LeftContainerWrapper>
|
||||
|
||||
<RightContainerWrapper flex={1}>
|
||||
@ -219,6 +225,7 @@ const NewWidget = ({
|
||||
|
||||
export interface NewWidgetProps {
|
||||
selectedGraph: GRAPH_TYPES;
|
||||
yAxisUnit: Widgets['yAxisUnit'];
|
||||
}
|
||||
|
||||
interface DispatchProps {
|
||||
|
@ -55,6 +55,7 @@ export const SaveDashboard = ({
|
||||
];
|
||||
|
||||
const response = await updateDashboardApi({
|
||||
...selectedDashboard.data,
|
||||
uuid,
|
||||
// this is the data for the dashboard
|
||||
title: selectedDashboard.data.title,
|
||||
@ -122,4 +123,5 @@ export interface SaveDashboardProps {
|
||||
nullZeroValues: Widgets['nullZeroValues'];
|
||||
widgetId: Widgets['id'];
|
||||
dashboardId: string;
|
||||
yAxisUnit: Widgets['yAxisUnit'];
|
||||
}
|
||||
|
@ -44,6 +44,7 @@ export interface Widgets {
|
||||
}[];
|
||||
};
|
||||
stepSize?: number;
|
||||
yAxisUnit?: string;
|
||||
}
|
||||
|
||||
export interface Query {
|
||||
|
Loading…
x
Reference in New Issue
Block a user