From 826cbe0803d1821585f25a4a0105f9795543b85d Mon Sep 17 00:00:00 2001 From: GitStart <1501599+gitstart@users.noreply.github.com> Date: Wed, 7 Jun 2023 08:20:01 +0300 Subject: [PATCH] feat: ability to clone a panel (#2444) Co-authored-by: gitstart Co-authored-by: Nitesh Singh Co-authored-by: Palash Gupta Co-authored-by: Prashant Shahi Co-authored-by: Vishal Sharma --- .../container/GridGraphLayout/Graph/index.tsx | 46 +++++++++++++++++++ .../GridGraphLayout/WidgetHeader/index.tsx | 16 ++++++- .../src/container/GridGraphLayout/utils.ts | 19 +++++--- 3 files changed, 73 insertions(+), 8 deletions(-) diff --git a/frontend/src/container/GridGraphLayout/Graph/index.tsx b/frontend/src/container/GridGraphLayout/Graph/index.tsx index 35923b8b12..c581f7f917 100644 --- a/frontend/src/container/GridGraphLayout/Graph/index.tsx +++ b/frontend/src/container/GridGraphLayout/Graph/index.tsx @@ -2,10 +2,12 @@ import { Typography } from 'antd'; import { ChartData } from 'chart.js'; import Spinner from 'components/Spinner'; import GridGraphComponent from 'container/GridGraphComponent'; +import { UpdateDashboard } from 'container/GridGraphLayout/utils'; import { useNotifications } from 'hooks/useNotifications'; import usePreviousValue from 'hooks/usePreviousValue'; import { getDashboardVariables } from 'lib/dashbaordVariables/getDashboardVariables'; import getChartData from 'lib/getChartData'; +import history from 'lib/history'; import isEmpty from 'lodash-es/isEmpty'; import { Dispatch, @@ -33,6 +35,7 @@ import { Widgets } from 'types/api/dashboard/getAll'; import AppReducer from 'types/reducer/app'; import DashboardReducer from 'types/reducer/dashboards'; import { GlobalReducer } from 'types/reducer/globalTime'; +import { v4 } from 'uuid'; import { LayoutProps } from '..'; import EmptyWidget from '../EmptyWidget'; @@ -157,6 +160,46 @@ function GridCardGraph({ t, ]); + const onCloneHandler = async (): Promise => { + const uuid = v4(); + + const layout = [ + { + i: uuid, + w: 6, + x: 0, + h: 2, + y: 0, + }, + ...(selectedDashboard.data.layout || []), + ]; + + if (widget) { + await UpdateDashboard( + { + data: selectedDashboard.data, + generateWidgetId: uuid, + graphType: widget.panelTypes, + selectedDashboard, + layout, + widgetData: widget, + isRedirected: false, + }, + notifications, + ).then(() => { + notifications.success({ + message: 'Panel cloned successfully, redirecting to new copy.', + }); + + setTimeout(() => { + history.push( + `${history.location.pathname}/new?graphType=${widget.panelTypes}&widgetId=${uuid}`, + ); + }, 1500); + }); + } + }; + const getModals = (): JSX.Element => ( <> @@ -241,6 +285,7 @@ function GridCardGraph({ widget={widget} onView={handleOnView} onDelete={handleOnDelete} + onClone={onCloneHandler} queryResponse={queryResponse} errorMessage={errorMessage} /> @@ -286,6 +331,7 @@ function GridCardGraph({ widget={widget} onView={handleOnView} onDelete={handleOnDelete} + onClone={onCloneHandler} queryResponse={queryResponse} errorMessage={errorMessage} /> diff --git a/frontend/src/container/GridGraphLayout/WidgetHeader/index.tsx b/frontend/src/container/GridGraphLayout/WidgetHeader/index.tsx index 64d0ad54e8..10628aee7a 100644 --- a/frontend/src/container/GridGraphLayout/WidgetHeader/index.tsx +++ b/frontend/src/container/GridGraphLayout/WidgetHeader/index.tsx @@ -1,4 +1,5 @@ import { + CopyOutlined, DeleteOutlined, DownOutlined, EditFilled, @@ -38,6 +39,7 @@ interface IWidgetHeaderProps { widget: Widgets; onView: VoidFunction; onDelete: VoidFunction; + onClone: VoidFunction; parentHover: boolean; queryResponse: UseQueryResult< SuccessResponse | ErrorResponse @@ -49,6 +51,7 @@ function WidgetHeader({ widget, onView, onDelete, + onClone, parentHover, queryResponse, errorMessage, @@ -81,8 +84,12 @@ function WidgetHeader({ key: 'delete', method: onDelete, }, + clone: { + key: 'clone', + method: onClone, + }, }), - [onDelete, onEditHandler, onView], + [onDelete, onEditHandler, onView, onClone], ); const onMenuItemSelectHandler: MenuProps['onClick'] = useCallback( @@ -116,6 +123,12 @@ function WidgetHeader({ disabled: !editWidget, label: 'Edit', }, + { + key: keyMethodMapping.clone.key, + icon: , + disabled: false, + label: 'Clone', + }, { key: keyMethodMapping.delete.key, icon: , @@ -130,6 +143,7 @@ function WidgetHeader({ keyMethodMapping.delete.key, keyMethodMapping.edit.key, keyMethodMapping.view.key, + keyMethodMapping.clone.key, queryResponse.isLoading, ], ); diff --git a/frontend/src/container/GridGraphLayout/utils.ts b/frontend/src/container/GridGraphLayout/utils.ts index fe89bbbf0f..625557173f 100644 --- a/frontend/src/container/GridGraphLayout/utils.ts +++ b/frontend/src/container/GridGraphLayout/utils.ts @@ -8,7 +8,7 @@ import { import { GRAPH_TYPES } from 'container/NewDashboard/ComponentsSlider'; import { Layout } from 'react-grid-layout'; import store from 'store'; -import { Dashboard } from 'types/api/dashboard/getAll'; +import { Dashboard, Widgets } from 'types/api/dashboard/getAll'; import { EQueryType } from 'types/common/dashboard'; export const UpdateDashboard = async ( @@ -19,9 +19,11 @@ export const UpdateDashboard = async ( layout, selectedDashboard, isRedirected, + widgetData, }: UpdateDashboardProps, notify: NotificationInstance, ): Promise => { + const copyTitle = `${widgetData?.title} - Copy`; const updatedSelectedDashboard: Dashboard = { ...selectedDashboard, data: { @@ -33,13 +35,13 @@ export const UpdateDashboard = async ( widgets: [ ...(data.widgets || []), { - description: '', + description: widgetData?.description || '', id: generateWidgetId, isStacked: false, - nullZeroValues: '', + nullZeroValues: widgetData?.nullZeroValues || '', opacity: '', panelTypes: graphType, - query: { + query: widgetData?.query || { queryType: EQueryType.QUERY_BUILDER, promql: [initialQueryPromQLData], clickhouse_sql: [initialClickHouseData], @@ -49,13 +51,15 @@ export const UpdateDashboard = async ( }, }, queryData: { - data: { queryData: [] }, + data: { + queryData: widgetData?.queryData.data.queryData || [], + }, error: false, errorMessage: '', loading: false, }, - timePreferance: 'GLOBAL_TIME', - title: '', + timePreferance: widgetData?.timePreferance || 'GLOBAL_TIME', + title: widgetData ? copyTitle : '', }, ], layout, @@ -91,4 +95,5 @@ interface UpdateDashboardProps { layout: Layout[]; selectedDashboard: Dashboard; isRedirected: boolean; + widgetData?: Widgets; }