From 8f6cdd4cda702cf4e161dd8dd16e26f5a9bb41fc Mon Sep 17 00:00:00 2001
From: juanicabanas
Date: Fri, 4 Nov 2022 15:08:50 -0300
Subject: [PATCH] PublicDashboards: Add delete public dashboard button in
public dashboard modal (#58095)
- Delete public dashboard button added in public dashboard modal
- Delete public dashboard button refactored in order to be used in audit table and public dashboard modal
- Tests added
- RTK Query api modified, in order to keep cached data because of having to show public dashboard modal once delete modal is closed.
- RTK Query specific cached data invalidated for public dashboard
- Save button text changed: Create public dashboard when it was never created. Save public dashboard when there's a public dashboard already created
- Public Dashboard modal subscribed to DashboardModel metadata changes
---
.../src/selectors/pages.ts | 1 +
.../dashboard/api/publicDashboardApi.ts | 34 +++---
.../SharePublicDashboard.test.tsx | 61 ++++++++--
.../SharePublicDashboard.tsx | 112 +++++++++++++-----
.../DeletePublicDashboardButton.tsx | 49 +++++---
.../DeletePublicDashboardModal.tsx | 2 +-
.../PublicDashboardListTable.tsx | 13 +-
7 files changed, 195 insertions(+), 77 deletions(-)
diff --git a/packages/grafana-e2e-selectors/src/selectors/pages.ts b/packages/grafana-e2e-selectors/src/selectors/pages.ts
index 9b968cb284d..4bdc8923d45 100644
--- a/packages/grafana-e2e-selectors/src/selectors/pages.ts
+++ b/packages/grafana-e2e-selectors/src/selectors/pages.ts
@@ -188,6 +188,7 @@ export const Pages = {
EnableSwitch: 'data-testid public dashboard on off switch',
EnableAnnotationsSwitch: 'data-testid public dashboard on off switch for annotations',
SaveConfigButton: 'data-testid public dashboard save config button',
+ DeleteButton: 'data-testid public dashboard delete button',
CopyUrlInput: 'data-testid public dashboard copy url input',
CopyUrlButton: 'data-testid public dashboard copy url button',
TemplateVariablesWarningAlert: 'data-testid public dashboard disabled template variables alert',
diff --git a/public/app/features/dashboard/api/publicDashboardApi.ts b/public/app/features/dashboard/api/publicDashboardApi.ts
index 460739f7581..4249547a967 100644
--- a/public/app/features/dashboard/api/publicDashboardApi.ts
+++ b/public/app/features/dashboard/api/publicDashboardApi.ts
@@ -36,7 +36,7 @@ export const publicDashboardApi = createApi({
reducerPath: 'publicDashboardApi',
baseQuery: retry(backendSrvBaseQuery({ baseUrl: '/api/dashboards' }), { maxRetries: 0 }),
tagTypes: ['PublicDashboard', 'AuditTablePublicDashboard'],
- keepUnusedDataFor: 0,
+ refetchOnMountOrArgChange: true,
endpoints: (builder) => ({
getPublicDashboard: builder.query({
query: (dashboardUid) => ({
@@ -53,7 +53,7 @@ export const publicDashboardApi = createApi({
dispatch(notifyApp(createErrorNotification(customError?.error?.data?.message)));
}
},
- providesTags: ['PublicDashboard'],
+ providesTags: (result, error, dashboardUid) => [{ type: 'PublicDashboard', id: dashboardUid }],
}),
createPublicDashboard: builder.mutation({
query: (params) => ({
@@ -72,7 +72,7 @@ export const publicDashboardApi = createApi({
publicDashboardEnabled: data.isEnabled,
});
},
- invalidatesTags: ['PublicDashboard'],
+ invalidatesTags: (result, error, { payload }) => [{ type: 'PublicDashboard', id: payload.dashboardUid }],
}),
updatePublicDashboard: builder.mutation({
query: (params) => ({
@@ -92,7 +92,7 @@ export const publicDashboardApi = createApi({
publicDashboardEnabled: data.isEnabled,
});
},
- invalidatesTags: ['PublicDashboard'],
+ invalidatesTags: (result, error, { payload }) => [{ type: 'PublicDashboard', id: payload.dashboardUid }],
}),
listPublicDashboards: builder.query({
query: () => ({
@@ -100,25 +100,25 @@ export const publicDashboardApi = createApi({
}),
providesTags: ['AuditTablePublicDashboard'],
}),
- deletePublicDashboard: builder.mutation({
+ deletePublicDashboard: builder.mutation({
query: (params) => ({
url: `/uid/${params.dashboardUid}/public-dashboards/${params.uid}`,
method: 'DELETE',
}),
- async onQueryStarted({ dashboardTitle }, { dispatch, queryFulfilled }) {
+ async onQueryStarted({ dashboard, uid }, { dispatch, queryFulfilled }) {
await queryFulfilled;
- dispatch(
- notifyApp(
- createSuccessNotification(
- 'Public dashboard deleted',
- !!dashboardTitle
- ? `Public dashboard for ${dashboardTitle} has been deleted`
- : `Public dashboard has been deleted`
- )
- )
- );
+ dispatch(notifyApp(createSuccessNotification('Public dashboard deleted!')));
+
+ dashboard?.updateMeta({
+ hasPublicDashboard: false,
+ publicDashboardUid: uid,
+ publicDashboardEnabled: false,
+ });
},
- invalidatesTags: ['AuditTablePublicDashboard'],
+ invalidatesTags: (result, error, { dashboardUid }) => [
+ { type: 'PublicDashboard', id: dashboardUid },
+ 'AuditTablePublicDashboard',
+ ],
}),
}),
});
diff --git a/public/app/features/dashboard/components/ShareModal/SharePublicDashboard/SharePublicDashboard.test.tsx b/public/app/features/dashboard/components/ShareModal/SharePublicDashboard/SharePublicDashboard.test.tsx
index 15cdbec7a7d..fa0eb33020e 100644
--- a/public/app/features/dashboard/components/ShareModal/SharePublicDashboard/SharePublicDashboard.test.tsx
+++ b/public/app/features/dashboard/components/ShareModal/SharePublicDashboard/SharePublicDashboard.test.tsx
@@ -100,7 +100,6 @@ describe('SharePublic', () => {
expect(screen.getByRole('tablist')).toHaveTextContent('Link');
expect(screen.getByRole('tablist')).not.toHaveTextContent('Public dashboard');
});
-
it('renders share panel when public dashboards feature is enabled', async () => {
await renderSharePublicDashboard({ panel: mockPanel, dashboard: mockDashboard, onDismiss: () => {} });
@@ -110,8 +109,23 @@ describe('SharePublic', () => {
fireEvent.click(screen.getByText('Public dashboard'));
await screen.findByText('Welcome to Grafana public dashboards alpha!');
+ expect(screen.getByText('Create public dashboard')).toBeInTheDocument();
+ expect(screen.queryByTestId(selectors.DeleteButton)).not.toBeInTheDocument();
});
+ it('renders public dashboard modal without delete button because no public dashboard was already created', async () => {
+ jest.spyOn(contextSrv, 'hasAccess').mockReturnValue(false);
+ await renderSharePublicDashboard({ panel: mockPanel, dashboard: mockDashboard, onDismiss: () => {} });
+ expect(screen.getByRole('tablist')).toHaveTextContent('Link');
+ expect(screen.getByRole('tablist')).toHaveTextContent('Public dashboard');
+
+ fireEvent.click(screen.getByText('Public dashboard'));
+
+ await screen.findByText('Welcome to Grafana public dashboards alpha!');
+
+ expect(screen.getByText('Create public dashboard')).toBeInTheDocument();
+ expect(screen.queryByTestId(selectors.DeleteButton)).not.toBeInTheDocument();
+ });
it('renders default relative time in input', async () => {
expect(mockDashboard.time).toEqual({ from: 'now-6h', to: 'now' });
@@ -137,13 +151,15 @@ describe('SharePublic', () => {
mockDashboard.meta.hasPublicDashboard = true;
await renderSharePublicDashboard({ panel: mockPanel, dashboard: mockDashboard, onDismiss: () => {} });
- expect(await screen.findByTestId('Spinner')).toBeInTheDocument();
+ screen.getAllByTestId('Spinner');
+ expect(screen.getByText('Save public dashboard')).toBeInTheDocument();
expect(screen.getByTestId(selectors.WillBePublicCheckbox)).toBeDisabled();
expect(screen.getByTestId(selectors.LimitedDSCheckbox)).toBeDisabled();
expect(screen.getByTestId(selectors.CostIncreaseCheckbox)).toBeDisabled();
expect(screen.getByTestId(selectors.EnableSwitch)).toBeDisabled();
expect(screen.getByTestId(selectors.SaveConfigButton)).toBeDisabled();
+ expect(screen.queryByTestId(selectors.DeleteButton)).not.toBeInTheDocument();
});
it('when fetch errors happen, then all inputs remain disabled', async () => {
mockDashboard.meta.hasPublicDashboard = true;
@@ -154,14 +170,16 @@ describe('SharePublic', () => {
);
await renderSharePublicDashboard({ panel: mockPanel, dashboard: mockDashboard, onDismiss: () => {} });
- await waitForElementToBeRemoved(screen.getByTestId('Spinner'));
+ await waitForElementToBeRemoved(screen.getAllByTestId('Spinner'));
expect(screen.getByTestId(selectors.WillBePublicCheckbox)).toBeDisabled();
expect(screen.getByTestId(selectors.LimitedDSCheckbox)).toBeDisabled();
expect(screen.getByTestId(selectors.CostIncreaseCheckbox)).toBeDisabled();
expect(screen.getByTestId(selectors.EnableSwitch)).toBeDisabled();
expect(screen.getByTestId(selectors.EnableAnnotationsSwitch)).toBeDisabled();
+ expect(screen.getByText('Save public dashboard')).toBeInTheDocument();
expect(screen.getByTestId(selectors.SaveConfigButton)).toBeDisabled();
+ expect(screen.queryByTestId(selectors.DeleteButton)).not.toBeInTheDocument();
});
// test checking if current version of dashboard in state is persisted to db
});
@@ -183,7 +201,9 @@ describe('SharePublic - New config setup', () => {
expect(screen.getByTestId(selectors.CostIncreaseCheckbox)).toBeEnabled();
expect(screen.getByTestId(selectors.EnableSwitch)).toBeEnabled();
expect(screen.getByTestId(selectors.EnableAnnotationsSwitch)).toBeEnabled();
+ expect(screen.queryByTestId(selectors.DeleteButton)).not.toBeInTheDocument();
+ expect(screen.getByText('Create public dashboard')).toBeInTheDocument();
expect(screen.getByTestId(selectors.SaveConfigButton)).toBeDisabled();
});
it('when checkboxes are filled, then save button remains disabled', async () => {
@@ -194,6 +214,7 @@ describe('SharePublic - New config setup', () => {
fireEvent.click(screen.getByTestId(selectors.LimitedDSCheckbox));
fireEvent.click(screen.getByTestId(selectors.CostIncreaseCheckbox));
+ expect(screen.getByText('Create public dashboard')).toBeInTheDocument();
expect(screen.getByTestId(selectors.SaveConfigButton)).toBeDisabled();
});
it('when checkboxes and switch are filled, then save button is enabled', async () => {
@@ -207,6 +228,10 @@ describe('SharePublic - New config setup', () => {
expect(screen.getByTestId(selectors.SaveConfigButton)).toBeEnabled();
});
+ it('when hasPublicDashboard flag is false, then button text is Create', async () => {
+ await renderSharePublicDashboard({ panel: mockPanel, dashboard: mockDashboard, onDismiss: () => {} });
+ expect(screen.getByText('Create public dashboard')).toBeInTheDocument();
+ });
});
describe('SharePublic - Already persisted', () => {
@@ -228,33 +253,44 @@ describe('SharePublic - Already persisted', () => {
);
});
- it('when modal is opened, then save button is enabled', async () => {
+ it('when modal is opened, then save button and delete button are enabled', async () => {
await renderSharePublicDashboard({ panel: mockPanel, dashboard: mockDashboard, onDismiss: () => {} });
- await waitForElementToBeRemoved(screen.getByTestId('Spinner'));
+ await waitForElementToBeRemoved(screen.getAllByTestId('Spinner'));
+ expect(screen.getByTestId(selectors.DeleteButton)).toBeEnabled();
+ expect(screen.getByText('Save public dashboard')).toBeInTheDocument();
expect(screen.getByTestId(selectors.SaveConfigButton)).toBeEnabled();
});
+ it('delete button is not rendered because lack of permissions', async () => {
+ jest.spyOn(contextSrv, 'hasAccess').mockReturnValue(false);
+ await renderSharePublicDashboard({ panel: mockPanel, dashboard: mockDashboard, onDismiss: () => {} });
+ await waitForElementToBeRemoved(screen.getAllByTestId('Spinner'));
+
+ expect(screen.queryByTestId(selectors.DeleteButton)).not.toBeInTheDocument();
+ });
it('when modal is opened, then annotations toggle is enabled and checked when its enabled in the db', async () => {
await renderSharePublicDashboard({ panel: mockPanel, dashboard: mockDashboard, onDismiss: () => {} });
- await waitForElementToBeRemoved(screen.getByTestId('Spinner'));
+ await waitForElementToBeRemoved(screen.getAllByTestId('Spinner'));
expect(screen.getByTestId(selectors.EnableAnnotationsSwitch)).toBeEnabled();
expect(screen.getByTestId(selectors.EnableAnnotationsSwitch)).toBeChecked();
});
it('when fetch is done, then loader spinner is gone, inputs are disabled and save button is enabled', async () => {
await renderSharePublicDashboard({ panel: mockPanel, dashboard: mockDashboard, onDismiss: () => {} });
- await waitForElementToBeRemoved(screen.getByTestId('Spinner'));
+ await waitForElementToBeRemoved(screen.getAllByTestId('Spinner'));
expect(screen.getByTestId(selectors.WillBePublicCheckbox)).toBeDisabled();
expect(screen.getByTestId(selectors.LimitedDSCheckbox)).toBeDisabled();
expect(screen.getByTestId(selectors.CostIncreaseCheckbox)).toBeDisabled();
expect(screen.getByTestId(selectors.EnableSwitch)).toBeEnabled();
+ expect(screen.getByText('Save public dashboard')).toBeInTheDocument();
expect(screen.getByTestId(selectors.SaveConfigButton)).toBeEnabled();
+ expect(screen.getByTestId(selectors.DeleteButton)).toBeEnabled();
});
it('when pubdash is enabled, then link url is available', async () => {
await renderSharePublicDashboard({ panel: mockPanel, dashboard: mockDashboard, onDismiss: () => {} });
- await waitForElementToBeRemoved(screen.getByTestId('Spinner'));
+ await waitForElementToBeRemoved(screen.getAllByTestId('Spinner'));
expect(screen.getByTestId(selectors.CopyUrlInput)).toBeInTheDocument();
});
it('when pubdash is disabled in the db, then link url is not available and annotations toggle is disabled', async () => {
@@ -274,16 +310,21 @@ describe('SharePublic - Already persisted', () => {
);
await renderSharePublicDashboard({ panel: mockPanel, dashboard: mockDashboard, onDismiss: () => {} });
- await waitForElementToBeRemoved(screen.getByTestId('Spinner'));
+ await waitForElementToBeRemoved(screen.getAllByTestId('Spinner'));
expect(screen.queryByTestId(selectors.CopyUrlInput)).not.toBeInTheDocument();
expect(screen.getByTestId(selectors.EnableAnnotationsSwitch)).not.toBeChecked();
});
it('when pubdash is disabled by the user, then link url is not available', async () => {
await renderSharePublicDashboard({ panel: mockPanel, dashboard: mockDashboard, onDismiss: () => {} });
- await waitForElementToBeRemoved(screen.getByTestId('Spinner'));
+ await waitForElementToBeRemoved(screen.getAllByTestId('Spinner'));
fireEvent.click(screen.getByTestId(selectors.EnableSwitch));
expect(screen.queryByTestId(selectors.CopyUrlInput)).not.toBeInTheDocument();
});
+ it('when hasPublicDashboard flag is true, then button text is Save', async () => {
+ await renderSharePublicDashboard({ panel: mockPanel, dashboard: mockDashboard, onDismiss: () => {} });
+ await waitForElementToBeRemoved(screen.getAllByTestId('Spinner'));
+ expect(screen.getByText('Save public dashboard')).toBeInTheDocument();
+ });
});
diff --git a/public/app/features/dashboard/components/ShareModal/SharePublicDashboard/SharePublicDashboard.tsx b/public/app/features/dashboard/components/ShareModal/SharePublicDashboard/SharePublicDashboard.tsx
index 4af0c3d7ff8..cb5972ba1c3 100644
--- a/public/app/features/dashboard/components/ShareModal/SharePublicDashboard/SharePublicDashboard.tsx
+++ b/public/app/features/dashboard/components/ShareModal/SharePublicDashboard/SharePublicDashboard.tsx
@@ -1,10 +1,23 @@
import { css } from '@emotion/css';
-import React, { useEffect, useMemo, useState } from 'react';
+import React, { useContext, useEffect, useMemo, useState } from 'react';
+import { Subscription } from 'rxjs';
import { GrafanaTheme2 } from '@grafana/data/src';
import { selectors as e2eSelectors } from '@grafana/e2e-selectors/src';
import { reportInteraction } from '@grafana/runtime/src';
-import { Alert, Button, ClipboardButton, Field, HorizontalGroup, Input, useStyles2, Spinner } from '@grafana/ui/src';
+import {
+ Alert,
+ Button,
+ ClipboardButton,
+ Field,
+ HorizontalGroup,
+ Input,
+ useStyles2,
+ Spinner,
+ ModalsContext,
+ useForceUpdate,
+} from '@grafana/ui/src';
+import { Layout } from '@grafana/ui/src/components/Layout/Layout';
import { contextSrv } from 'app/core/services/context_srv';
import {
useGetPublicDashboardQuery,
@@ -21,22 +34,31 @@ import {
publicDashboardPersisted,
} from 'app/features/dashboard/components/ShareModal/SharePublicDashboard/SharePublicDashboardUtils';
import { ShareModalTabProps } from 'app/features/dashboard/components/ShareModal/types';
+import { useIsDesktop } from 'app/features/dashboard/utils/screen';
+import { DeletePublicDashboardButton } from 'app/features/manage-dashboards/components/PublicDashboardListTable/DeletePublicDashboardButton';
import { isOrgAdmin } from 'app/features/plugins/admin/permissions';
import { AccessControlAction } from 'app/types';
+import { DashboardMetaChangedEvent } from '../../../../../types/events';
+import { ShareModal } from '../ShareModal';
+
interface Props extends ShareModalTabProps {}
export const SharePublicDashboard = (props: Props) => {
+ const forceUpdate = useForceUpdate();
+ const styles = useStyles2(getStyles);
+ const { showModal, hideModal } = useContext(ModalsContext);
+ const isDesktop = useIsDesktop();
+
const dashboardVariables = props.dashboard.getVariables();
const selectors = e2eSelectors.pages.ShareDashboardModal.PublicDashboard;
- const styles = useStyles2(getStyles);
-
- const [hasPublicDashboard, setHasPublicDashboard] = useState(props.dashboard.meta.hasPublicDashboard);
+ const { hasPublicDashboard } = props.dashboard.meta;
const {
- isLoading: isFetchingLoading,
+ isLoading: isGetLoading,
data: publicDashboard,
- isError: isFetchingError,
+ isError: isGetError,
+ isFetching,
} = useGetPublicDashboardQuery(props.dashboard.uid, {
// if we don't have a public dashboard, don't try to load public dashboard
skip: !hasPublicDashboard,
@@ -57,8 +79,12 @@ export const SharePublicDashboard = (props: Props) => {
const [annotationsEnabled, setAnnotationsEnabled] = useState(false);
useEffect(() => {
+ const eventSubs = new Subscription();
+ eventSubs.add(props.dashboard.events.subscribe(DashboardMetaChangedEvent, forceUpdate));
reportInteraction('grafana_dashboards_public_share_viewed');
- }, []);
+
+ return () => eventSubs.unsubscribe();
+ }, [props.dashboard.events, forceUpdate]);
useEffect(() => {
if (publicDashboardPersisted(publicDashboard)) {
@@ -73,19 +99,30 @@ export const SharePublicDashboard = (props: Props) => {
setEnabledSwitch((prevState) => ({ ...prevState, isEnabled: !!publicDashboard?.isEnabled }));
}, [publicDashboard]);
- const isLoading = isFetchingLoading || isSaveLoading || isUpdateLoading;
+ const isLoading = isGetLoading || isSaveLoading || isUpdateLoading;
const hasWritePermissions = contextSrv.hasAccess(AccessControlAction.DashboardsPublicWrite, isOrgAdmin());
const acknowledged = acknowledgements.public && acknowledgements.datasources && acknowledgements.usage;
- const isSaveEnabled = useMemo(
+ const isSaveDisabled = useMemo(
() =>
!hasWritePermissions ||
!acknowledged ||
props.dashboard.hasUnsavedChanges() ||
isLoading ||
- isFetchingError ||
+ isFetching ||
+ isGetError ||
(!publicDashboardPersisted(publicDashboard) && !enabledSwitch.wasTouched),
- [hasWritePermissions, acknowledged, props.dashboard, isLoading, isFetchingError, enabledSwitch, publicDashboard]
+ [
+ hasWritePermissions,
+ acknowledged,
+ props.dashboard,
+ isLoading,
+ isGetError,
+ enabledSwitch,
+ publicDashboard,
+ isFetching,
+ ]
);
+ const isDeleteDisabled = isLoading || isFetching || isGetError;
const onSavePublicConfig = async () => {
reportInteraction('grafana_dashboards_public_create_clicked');
@@ -96,20 +133,21 @@ export const SharePublicDashboard = (props: Props) => {
};
// create or update based on whether we have existing uid
-
- if (hasPublicDashboard) {
- await updatePublicDashboard(req).unwrap();
- setHasPublicDashboard(true);
- } else {
- await createPublicDashboard(req).unwrap();
- setHasPublicDashboard(true);
- }
+ hasPublicDashboard ? updatePublicDashboard(req) : createPublicDashboard(req);
};
const onAcknowledge = (field: string, checked: boolean) => {
setAcknowledgements((prevState) => ({ ...prevState, [field]: checked }));
};
+ const onDismissDelete = () => {
+ showModal(ShareModal, {
+ dashboard: props.dashboard,
+ onDismiss: hideModal,
+ activeTab: 'share',
+ });
+ };
+
return (
<>
@@ -120,7 +158,7 @@ export const SharePublicDashboard = (props: Props) => {
>
Welcome to Grafana public dashboards alpha!
- {isFetchingLoading && }
+ {(isGetLoading || isFetching) && }
{dashboardHasTemplateVariables(dashboardVariables) && !publicDashboardPersisted(publicDashboard) ? (
@@ -137,9 +175,7 @@ export const SharePublicDashboard = (props: Props) => {
@@ -148,7 +184,7 @@ export const SharePublicDashboard = (props: Props) => {
setEnabledSwitch((prevState) => ({ isEnabled: !prevState.isEnabled, wasTouched: true }))
@@ -193,10 +229,28 @@ export const SharePublicDashboard = (props: Props) => {
)}
-
- Save sharing configuration
-
- {isSaveLoading && }
+
+
+ {hasPublicDashboard ? 'Save public dashboard' : 'Create public dashboard'}
+
+ {publicDashboard && hasWritePermissions && (
+
+ Delete public dashboard
+
+ )}
+
+ {(isSaveLoading || isFetching) && }
>
)}
diff --git a/public/app/features/manage-dashboards/components/PublicDashboardListTable/DeletePublicDashboardButton.tsx b/public/app/features/manage-dashboards/components/PublicDashboardListTable/DeletePublicDashboardButton.tsx
index 837098f1a4c..125aebe4d3e 100644
--- a/public/app/features/manage-dashboards/components/PublicDashboardListTable/DeletePublicDashboardButton.tsx
+++ b/public/app/features/manage-dashboards/components/PublicDashboardListTable/DeletePublicDashboardButton.tsx
@@ -1,47 +1,60 @@
import React from 'react';
-import { selectors as e2eSelectors } from '@grafana/e2e-selectors/src';
-import { Button, ComponentSize, Icon, ModalsController, Spinner } from '@grafana/ui/src';
-
-import { useDeletePublicDashboardMutation } from '../../../dashboard/api/publicDashboardApi';
-import { ListPublicDashboardResponse } from '../../types';
+import { Button, ModalsController, ButtonProps } from '@grafana/ui/src';
+import { useDeletePublicDashboardMutation } from 'app/features/dashboard/api/publicDashboardApi';
+import { DashboardModel } from 'app/features/dashboard/state/DashboardModel';
import { DeletePublicDashboardModal } from './DeletePublicDashboardModal';
+export interface PublicDashboardDeletion {
+ uid: string;
+ dashboardUid: string;
+ title: string;
+}
+
export const DeletePublicDashboardButton = ({
+ dashboard,
publicDashboard,
- size,
+ loader,
+ children,
+ onDismiss,
+ ...rest
}: {
- publicDashboard: ListPublicDashboardResponse;
- size: ComponentSize;
-}) => {
+ dashboard?: DashboardModel;
+ publicDashboard: PublicDashboardDeletion;
+ loader?: JSX.Element;
+ children: React.ReactNode;
+ onDismiss?: () => void;
+} & ButtonProps) => {
const [deletePublicDashboard, { isLoading }] = useDeletePublicDashboardMutation();
- const onDeletePublicDashboardClick = (pd: ListPublicDashboardResponse, onDelete: () => void) => {
- deletePublicDashboard({ uid: pd.uid, dashboardUid: pd.dashboardUid, dashboardTitle: pd.title });
+ const onDeletePublicDashboardClick = (pd: PublicDashboardDeletion, onDelete: () => void) => {
+ deletePublicDashboard({
+ dashboard,
+ uid: pd.uid,
+ dashboardUid: pd.dashboardUid,
+ });
onDelete();
};
- const selectors = e2eSelectors.pages.PublicDashboards;
-
return (
{({ showModal, hideModal }) => (
showModal(DeletePublicDashboardModal, {
dashboardTitle: publicDashboard.title,
onConfirm: () => onDeletePublicDashboardClick(publicDashboard, hideModal),
- onDismiss: hideModal,
+ onDismiss: () => {
+ onDismiss ? onDismiss() : hideModal();
+ },
})
}
- data-testid={selectors.ListItem.trashcanButton}
- size={size}
+ {...rest}
>
- {isLoading ? : }
+ {isLoading && loader ? loader : children}
)}
diff --git a/public/app/features/manage-dashboards/components/PublicDashboardListTable/DeletePublicDashboardModal.tsx b/public/app/features/manage-dashboards/components/PublicDashboardListTable/DeletePublicDashboardModal.tsx
index aa5dacc86e1..bd2ef614546 100644
--- a/public/app/features/manage-dashboards/components/PublicDashboardListTable/DeletePublicDashboardModal.tsx
+++ b/public/app/features/manage-dashboards/components/PublicDashboardListTable/DeletePublicDashboardModal.tsx
@@ -12,7 +12,7 @@ const Body = ({ title }: { title?: string }) => {
Do you want to delete this public dashboard?
{title
- ? `This will delete the public dashboard for ${title}. Your dashboard will not be deleted.`
+ ? `This will delete the public dashboard for "${title}". Your dashboard will not be deleted.`
: 'Orphaned public dashboard will be deleted'}
>
diff --git a/public/app/features/manage-dashboards/components/PublicDashboardListTable/PublicDashboardListTable.tsx b/public/app/features/manage-dashboards/components/PublicDashboardListTable/PublicDashboardListTable.tsx
index 2b624e53a1d..bd5416f730a 100644
--- a/public/app/features/manage-dashboards/components/PublicDashboardListTable/PublicDashboardListTable.tsx
+++ b/public/app/features/manage-dashboards/components/PublicDashboardListTable/PublicDashboardListTable.tsx
@@ -94,7 +94,15 @@ export const PublicDashboardListTable = () => {
{hasWritePermissions && (
-
+ }
+ >
+
+
)}
@@ -134,9 +142,10 @@ function getStyles(theme: GrafanaTheme2, isMobile: boolean) {
orphanedTitle: css`
display: flex;
align-items: center;
+ gap: ${theme.spacing(1)};
p {
- margin: ${theme.spacing(0, 1, 0, 0)};
+ margin: ${theme.spacing(0)};
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;