From 9aa0c23686cd932cd1a2643db5674ac17fd1c562 Mon Sep 17 00:00:00 2001 From: Shenoy Pratik Date: Fri, 22 Oct 2021 13:01:39 -0700 Subject: [PATCH] adding cancel button for edit & panel actions (#153) --- .../custom_panels/custom_panel_view.tsx | 196 +++++++++++++----- .../public/components/custom_panels/home.tsx | 7 +- .../panel_modules/panel_grid/panel_grid.tsx | 50 ++--- 3 files changed, 170 insertions(+), 83 deletions(-) diff --git a/dashboards-observability/public/components/custom_panels/custom_panel_view.tsx b/dashboards-observability/public/components/custom_panels/custom_panel_view.tsx index 974bed04b..239b94476 100644 --- a/dashboards-observability/public/components/custom_panels/custom_panel_view.tsx +++ b/dashboards-observability/public/components/custom_panels/custom_panel_view.tsx @@ -13,6 +13,7 @@ import { EuiBreadcrumb, EuiButton, EuiContextMenu, + EuiContextMenuPanelDescriptor, EuiFieldText, EuiFlexGroup, EuiFlexItem, @@ -58,6 +59,7 @@ import { VisaulizationFlyout } from './panel_modules/visualization_flyout'; * chrome: chrome core service * parentBreadcrumb: parent breadcrumb * renameCustomPanel: Rename function for the panel + * cloneCustomPanel: Clone function for the panel * deleteCustomPanel: Delete function for the panel * setToast: create Toast function */ @@ -73,6 +75,7 @@ type Props = { editedCustomPanelId: string ) => Promise | undefined; deleteCustomPanel: (customPanelId: string, customPanelName: string) => Promise; + cloneCustomPanel: (clonedCustomPanelName: string, clonedCustomPanelId: string) => Promise; setToast: ( title: string, color?: string, @@ -89,6 +92,7 @@ export const CustomPanelView = ({ parentBreadcrumb, renameCustomPanel, deleteCustomPanel, + cloneCustomPanel, setToast, }: Props) => { const [openPanelName, setOpenPanelName] = useState(''); @@ -107,6 +111,8 @@ export const CustomPanelView = ({ const [isFlyoutVisible, setIsFlyoutVisible] = useState(false); // Add Visualization Flyout const [isFlyoutReplacement, setisFlyoutReplacement] = useState(false); const [replaceVisualizationId, setReplaceVisualizationId] = useState(''); + const [panelsMenuPopover, setPanelsMenuPopover] = useState(false); + const [editActionType, setEditActionType] = useState(''); // DateTimePicker States const [recentlyUsedRanges, setRecentlyUsedRanges] = useState([]); @@ -183,7 +189,9 @@ export const CustomPanelView = ({ const onDelete = async () => { deleteCustomPanel(panelId, openPanelName).then((res) => { - window.location.assign(`${_.last(parentBreadcrumb).href}`); + setTimeout(() => { + window.location.assign(`${_.last(parentBreadcrumb).href}`); + }, 1000); }); closeModal(); }; @@ -223,14 +231,36 @@ export const CustomPanelView = ({ showModal(); }; + const onClone = async (newCustomPanelName: string) => { + cloneCustomPanel(newCustomPanelName, panelId).then((id: string) => { + setTimeout(() => { + window.location.assign(`${_.last(parentBreadcrumb).href}${id}`); + }, 1000); + }); + closeModal(); + }; + + const clonePanel = () => { + setModalLayout( + getCustomModal( + onClone, + closeModal, + 'Name', + 'Duplicate Panel', + 'Cancel', + 'Duplicate', + openPanelName + ' (copy)', + CREATE_PANEL_MESSAGE + ) + ); + showModal(); + }; + // toggle between panel edit mode - const editPanel = () => { - if (editMode) { - // Save layout - setEditMode(false); - } else { - setEditMode(true); - } + const editPanel = (editType: string) => { + editMode ? setEditMode(false) : setEditMode(true); + if (editType === 'cancel') fetchCustomPanel(); + setEditActionType(editType); }; const closeFlyout = () => { @@ -248,16 +278,26 @@ export const CustomPanelView = ({ }; const checkDisabledInputs = () => { - if (panelVisualizations.length == 0) { + // When not in edit mode and panel has no visualizations + if (panelVisualizations.length === 0 && !editMode) { setEditDisabled(true); setInputDisabled(true); - } else { + setAddVizDisabled(false); + } + + // When in edit mode + if (editMode) { + setEditDisabled(false); + setInputDisabled(true); + setAddVizDisabled(true); + } + + // When panel has visualizations + if (panelVisualizations.length > 0) { setEditDisabled(false); - if (editMode) setInputDisabled(true); - else setInputDisabled(false); + setInputDisabled(false); + setAddVizDisabled(false); } - if (editMode) setAddVizDisabled(true); - else setAddVizDisabled(false); }; const onRefreshFilters = () => { @@ -339,10 +379,40 @@ export const CustomPanelView = ({ ); } + const panelActionsMenu: EuiContextMenuPanelDescriptor[] = [ + { + id: 0, + title: 'Panel actions', + items: [ + { + name: 'Rename panel', + onClick: () => { + setPanelsMenuPopover(false); + renamePanel(); + }, + }, + { + name: 'Duplicate panel', + onClick: () => { + setPanelsMenuPopover(false); + clonePanel(); + }, + }, + { + name: 'Delete panel', + onClick: () => { + setPanelsMenuPopover(false); + deletePanel(); + }, + }, + ], + }, + ]; + // Fetch the custom panel on Initial Mount useEffect(() => { fetchCustomPanel(); - }, []); + }, [panelId]); // Check Validity of Time useEffect(() => { @@ -364,7 +434,7 @@ export const CustomPanelView = ({ href: `${_.last(parentBreadcrumb).href}${panelId}`, }, ]); - }, [openPanelName]); + }, [panelId, openPanelName]); return (
@@ -382,22 +452,52 @@ export const CustomPanelView = ({ - - - Delete - - - - Rename - - - + + editPanel('cancel')} + > + Cancel + + + + editPanel('save')}> + Save + + + + ) : ( + + editPanel('edit')} + disabled={editDisabled} + > + Edit + + + )} + + setPanelsMenuPopover(true)} + > + Panel actions + + } + isOpen={panelsMenuPopover} + closePopover={() => setPanelsMenuPopover(false)} > - {editMode ? 'Save' : 'Edit'} - + + @@ -460,24 +560,24 @@ export const CustomPanelView = ({ getVizContextPanels={getVizContextPanels} /> ) : ( - + <> )} - <> + diff --git a/dashboards-observability/public/components/custom_panels/home.tsx b/dashboards-observability/public/components/custom_panels/home.tsx index a5f10d330..f0d7c92f1 100644 --- a/dashboards-observability/public/components/custom_panels/home.tsx +++ b/dashboards-observability/public/components/custom_panels/home.tsx @@ -136,7 +136,10 @@ export const Home = ({ http, chrome, parentBreadcrumb, pplService, renderProps } }; // Clones an existing Custom Panel, return new Custom Panel id - const cloneCustomPanel = (clonedCustomPanelName: string, clonedCustomPanelId: string) => { + const cloneCustomPanel = ( + clonedCustomPanelName: string, + clonedCustomPanelId: string + ): Promise => { if (!isNameValid(clonedCustomPanelName)) { setToast('Invalid Operational Panel name', 'danger'); return Promise.reject(); @@ -163,6 +166,7 @@ export const Home = ({ http, chrome, parentBreadcrumb, pplService, renderProps } ]; }); setToast(`Operational Panel "${clonedCustomPanelName}" successfully created!`); + return res.clonePanelId; }) .catch((err) => { setToast( @@ -256,6 +260,7 @@ export const Home = ({ http, chrome, parentBreadcrumb, pplService, renderProps } chrome={chrome} parentBreadcrumb={parentBreadcrumb} renameCustomPanel={renameCustomPanel} + cloneCustomPanel={cloneCustomPanel} deleteCustomPanel={deleteCustomPanel} setToast={setToast} /> diff --git a/dashboards-observability/public/components/custom_panels/panel_modules/panel_grid/panel_grid.tsx b/dashboards-observability/public/components/custom_panels/panel_modules/panel_grid/panel_grid.tsx index beab4e7c1..c4c67f8a8 100644 --- a/dashboards-observability/public/components/custom_panels/panel_modules/panel_grid/panel_grid.tsx +++ b/dashboards-observability/public/components/custom_panels/panel_modules/panel_grid/panel_grid.tsx @@ -30,7 +30,7 @@ const ResponsiveGridLayout = WidthProvider(Responsive); * Props taken in as params are: * http: http core service; * chrome: chrome core service; - * panelId: OpenPanel Id + * panelId: OpenPanel Id * panelVisualizations: list of panel visualizations * setPanelVisualizations: function to set panel visualizations * editMode: boolean to check if the panel is in edit mode @@ -41,7 +41,7 @@ const ResponsiveGridLayout = WidthProvider(Responsive); * cloneVisualization: function to clone a visualization in panel * pplFilterValue: string with panel PPL filter value * showFlyout: function to show the flyout - * setEditMode: function to set edit mode in panel + * editActionType: Type of action done while clicking the edit button */ type Props = { @@ -58,7 +58,7 @@ type Props = { cloneVisualization: (visualzationTitle: string, savedVisualizationId: string) => void; pplFilterValue: string; showFlyout: (isReplacement?: boolean | undefined, replaceVizId?: string | undefined) => void; - setEditMode: React.Dispatch>; + editActionType: string; }; export const PanelGrid = ({ @@ -75,16 +75,16 @@ export const PanelGrid = ({ cloneVisualization, pplFilterValue, showFlyout, - setEditMode, + editActionType, }: Props) => { - const [layout, setLayout] = useState([]); - const [editedLayout, setEditedLayout] = useState([]); + const [currentLayout, setCurrentLayout] = useState([]); + const [postEditLayout, setPostEditLayout] = useState([]); const isLocked = useObservable(chrome.getIsNavDrawerLocked$()); // Reset Size of Visualizations when layout is changed const layoutChanged = (currentLayout: Layout[], allLayouts: Layouts) => { window.dispatchEvent(new Event('resize')); - setEditedLayout(currentLayout); + setPostEditLayout(currentLayout); }; // Reload the Layout @@ -99,7 +99,7 @@ export const PanelGrid = ({ static: !editMode, } as Layout; }); - setLayout(tempLayout); + setCurrentLayout(tempLayout); }; // remove visualization from panel in edit mode @@ -107,25 +107,7 @@ export const PanelGrid = ({ const newVisualizationList = _.reject(panelVisualizations, { id: visualizationId, }); - - if (newVisualizationList.length === 0) { - setEditMode(false); - http - .put(`${CUSTOM_PANELS_API_PREFIX}/visualizations/edit`, { - body: JSON.stringify({ - panelId: panelId, - visualizationParams: [], - }), - }) - .then(async (res) => { - setPanelVisualizations(res.visualizations); - return; - }) - .catch((err) => { - console.error(err); - }); - } - mergeLayoutAndVisualizations(editedLayout, newVisualizationList, setPanelVisualizations); + mergeLayoutAndVisualizations(postEditLayout, newVisualizationList, setPanelVisualizations); }; // Save Visualization Layouts when not in edit mode anymore (after users saves the panel) @@ -150,12 +132,12 @@ export const PanelGrid = ({ if (editMode) { reloadLayout(); } else { - const newLayout = editedLayout.map((element) => { - return { ...element, static: true }; - }); - const visualizationParams = newLayout.map((layout) => _.omit(layout, ['static', 'moved'])); - setLayout(newLayout); - if (visualizationParams.length !== 0) saveVisualizationLayouts(panelId, visualizationParams); + if (editActionType === 'save') { + const visualizationParams = postEditLayout.map((layout) => + _.omit(layout, ['static', 'moved']) + ); + saveVisualizationLayouts(panelId, visualizationParams); + } } }, [editMode]); @@ -173,7 +155,7 @@ export const PanelGrid = ({ return (