diff --git a/public/components/custom_panels/custom_panel_table.tsx b/public/components/custom_panels/custom_panel_table.tsx index 4b1fd571d5..354c3f9f9a 100644 --- a/public/components/custom_panels/custom_panel_table.tsx +++ b/public/components/custom_panels/custom_panel_table.tsx @@ -50,6 +50,7 @@ import { DeleteModal } from '../common/helpers/delete_modal'; import { createPanel, deletePanels, + doesNameExist, fetchPanels, isUuid, newPanelTemplate, @@ -120,7 +121,9 @@ export const CustomPanelTable = ({ }; const onCreate = async (newCustomPanelName: string) => { - if (!isNameValid(newCustomPanelName)) { + if (await doesNameExist(newCustomPanelName)) { + setToast(`Observability Dashboard with name "${newCustomPanelName}" already exists`, 'danger'); + } else if (!isNameValid(newCustomPanelName)) { setToast('Invalid Dashboard name', 'danger'); } else { const newPanel = newPanelTemplate(newCustomPanelName); @@ -130,7 +133,9 @@ export const CustomPanelTable = ({ }; const onRename = async (newCustomPanelName: string) => { - if (!isNameValid(newCustomPanelName)) { + if (await doesNameExist(newCustomPanelName)) { + setToast(`Observability Dashboard with name "${newCustomPanelName}" already exists`, 'danger'); + } else if (!isNameValid(newCustomPanelName)) { setToast('Invalid Dashboard name', 'danger'); } else { dispatch(renameCustomPanel(newCustomPanelName, selectedCustomPanels[0].id)); @@ -139,7 +144,9 @@ export const CustomPanelTable = ({ }; const onClone = async (newName: string) => { - if (!isNameValid(newName)) { + if (await doesNameExist(newName)) { + setToast(`Observability Dashboard with name "${newName}" already exists`, 'danger'); + } else if (!isNameValid(newName)) { setToast('Invalid Operational Panel name', 'danger'); } else { let sourcePanel = selectedCustomPanels[0]; diff --git a/public/components/custom_panels/custom_panel_view_so.tsx b/public/components/custom_panels/custom_panel_view_so.tsx index 65b10416a0..8d0a16fc4f 100644 --- a/public/components/custom_panels/custom_panel_view_so.tsx +++ b/public/components/custom_panels/custom_panel_view_so.tsx @@ -57,6 +57,7 @@ import { VisaulizationFlyoutSO } from './panel_modules/visualization_flyout/visu import { clonePanel, deletePanels, + doesNameExist, fetchPanel, renameCustomPanel, selectPanel, @@ -208,7 +209,9 @@ export const CustomPanelViewSO = (props: CustomPanelViewProps) => { }; const onRename = async (newCustomPanelName: string) => { - if (!isNameValid(newCustomPanelName)) { + if (await doesNameExist(newCustomPanelName)) { + setToast(`Observability Dashboard with name "${newCustomPanelName}" already exists`, 'danger'); + } else if (!isNameValid(newCustomPanelName)) { setToast('Invalid Dashboard name', 'danger'); } else { dispatch(renameCustomPanel(newCustomPanelName, panel.id)); diff --git a/public/components/custom_panels/redux/panel_slice.ts b/public/components/custom_panels/redux/panel_slice.ts index 1bad8f4523..3470936fca 100644 --- a/public/components/custom_panels/redux/panel_slice.ts +++ b/public/components/custom_panels/redux/panel_slice.ts @@ -29,6 +29,7 @@ import { addVisualizationPanel, } from '../helpers/add_visualization_helper'; import { useToast } from '../../../../public/components/common/toast'; +import { htmlIdGenerator } from '@elastic/eui'; interface InitialState { id: string; @@ -84,7 +85,7 @@ const normalizedPanel = (panel: CustomPanelType): CustomPanelType => ({ export const selectPanelList = (rootState): CustomPanelType[] => rootState.customPanel.panelList; -const {setToast} = useToast(); +const { setToast } = useToast(); /* ** ASYNC DISPATCH FUNCTIONS @@ -128,7 +129,7 @@ export const fetchPanel = (id) => async (dispatch, getState) => { dispatch(setPanel(panel)); }; -export const fetchVisualization = () => (dispatch, getState) => {}; +export const fetchVisualization = () => (dispatch, getState) => { }; const updateLegacyPanel = (panel: CustomPanelType) => coreRefs.http!.post(`${CUSTOM_PANELS_API_PREFIX}/panels/update`, { @@ -141,6 +142,10 @@ export const uuidRx = /^[0-9a-fA-F]{8}\b-[0-9a-fA-F]{4}\b-[0-9a-fA-F]{4}\b-[0-9a export const isUuid = (id) => !!id.match(uuidRx); +export const doesNameExist = async (newCustomPanelName: string) => { + const panels = await fetchCustomPanels(); + return (panels.some(({ title }: {title: string}) => title === newCustomPanelName)); +} export const updatePanel = (panel: CustomPanelType, successMsg: string, failureMsg: string) => async (dispatch, getState) => { try { if (isUuid(panel.id)) await updateSavedObjectPanel(panel); @@ -151,7 +156,7 @@ export const updatePanel = (panel: CustomPanelType, successMsg: string, failureM dispatch(setPanel(panel)); const panelList = getState().customPanel.panelList.map((p) => (p.id === panel.id ? panel : p)); dispatch(setPanelList(panelList)); - } catch (e) { + } catch (e) { if (failureMsg) { setToast(failureMsg, 'danger') } @@ -193,7 +198,7 @@ export const replaceVizInPanel = (oldPanel, oldVizId, vizId, newVisualizationTit const visualizationsWithNewPanel = addVisualizationPanel(vizId, oldVizId, allVisualizations); const updatedPanel = { ...panel, visualizations: visualizationsWithNewPanel }; - + dispatch(updatePanel(updatedPanel, `Visualization ${newVisualizationTitle} successfully added!`, `Error in adding ${newVisualizationTitle} visualization to the panel`)); }; @@ -211,9 +216,8 @@ const deleteLegacyPanels = (customPanelIdList: string[]) => { }; export const deletePanels = (panelsToDelete: CustomPanelType[]) => async (dispatch, getState) => { - const toastMessage = `Observability Dashboard${ - panelsToDelete.length > 1 ? 's' : ' ' + panelsToDelete[0].title - } successfully deleted!`; + const toastMessage = `Observability Dashboard${panelsToDelete.length > 1 ? 's' : ' ' + panelsToDelete[0].title + } successfully deleted!`; try { const ids = panelsToDelete.map((p) => p.id); await Promise.all([deleteLegacyPanels(ids), deletePanelSO(ids)]); @@ -254,7 +258,7 @@ export const createPanelSample = (vizIds) => async (dispatch, getState) => { ...createDemoPanel(vizIds), dateCreated: new Date().getTime(), dateModified: new Date().getTime(), - title: samplePanelName, + title: htmlIdGenerator(samplePanelName)(), }; const newSOPanel = await savedObjectPanelsClient.create(samplePanel); const newPanel = savedObjectToCustomPanel(newSOPanel);