From cdf035f813606da7b2deed779b84e1b1688020c9 Mon Sep 17 00:00:00 2001 From: Laura Benz <48948963+L-M-K-B@users.noreply.github.com> Date: Mon, 2 Sep 2024 18:04:02 +0200 Subject: [PATCH 01/12] Scenes/RestoreDashboards: Adjust DeleteDashboardModal and Toast message (#92601) * refactor: replace soft delete method * refactor: adjust test to new naming * refactor: clean up unused functions * refactor: replace delete modal * refactor: use new delete modal outside of scenes --- .betterer.results | 10 +- .../scene/DashboardScene.test.tsx | 2 +- .../dashboard-scene/scene/DashboardScene.tsx | 4 +- .../settings/DeleteDashboardButton.tsx | 97 +++++++++++++------ .../DeleteDashboard/DeleteDashboardModal.tsx | 27 +----- .../manage-dashboards/state/actions.ts | 44 --------- public/locales/en-US/grafana.json | 5 +- public/locales/pseudo-LOCALE/grafana.json | 5 +- 8 files changed, 79 insertions(+), 115 deletions(-) diff --git a/.betterer.results b/.betterer.results index 0cbbf2c2539..bafa487b8df 100644 --- a/.betterer.results +++ b/.betterer.results @@ -2886,8 +2886,7 @@ exports[`better eslint`] = { [0, 0, 0, "No untranslated strings. Wrap text with ", "2"], [0, 0, 0, "No untranslated strings. Wrap text with ", "3"], [0, 0, 0, "No untranslated strings. Wrap text with ", "4"], - [0, 0, 0, "No untranslated strings. Wrap text with ", "5"], - [0, 0, 0, "No untranslated strings. Wrap text with ", "6"] + [0, 0, 0, "No untranslated strings. Wrap text with ", "5"] ], "public/app/features/dashboard-scene/settings/JsonModelEditView.tsx:5381": [ [0, 0, 0, "No untranslated strings. Wrap text with ", "0"], @@ -4679,12 +4678,7 @@ exports[`better eslint`] = { [0, 0, 0, "Unexpected any. Specify a different type.", "5"], [0, 0, 0, "Unexpected any. Specify a different type.", "6"], [0, 0, 0, "Unexpected any. Specify a different type.", "7"], - [0, 0, 0, "Unexpected any. Specify a different type.", "8"], - [0, 0, 0, "Unexpected any. Specify a different type.", "9"], - [0, 0, 0, "Unexpected any. Specify a different type.", "10"], - [0, 0, 0, "Unexpected any. Specify a different type.", "11"], - [0, 0, 0, "Unexpected any. Specify a different type.", "12"], - [0, 0, 0, "Unexpected any. Specify a different type.", "13"] + [0, 0, 0, "Unexpected any. Specify a different type.", "8"] ], "public/app/features/manage-dashboards/state/reducers.ts:5381": [ [0, 0, 0, "Unexpected any. Specify a different type.", "0"], diff --git a/public/app/features/dashboard-scene/scene/DashboardScene.test.tsx b/public/app/features/dashboard-scene/scene/DashboardScene.test.tsx index 9e2ca410700..10fb8788a03 100644 --- a/public/app/features/dashboard-scene/scene/DashboardScene.test.tsx +++ b/public/app/features/dashboard-scene/scene/DashboardScene.test.tsx @@ -1000,7 +1000,7 @@ describe('DashboardScene', () => { scene.setState({ isDirty: true }); locationService.push('/d/adsdas'); - await scene.deleteDashboard(); + await scene.onDashboardDelete(); expect(scene.state.isDirty).toBe(false); }); diff --git a/public/app/features/dashboard-scene/scene/DashboardScene.tsx b/public/app/features/dashboard-scene/scene/DashboardScene.tsx index 13f1069c653..3378af54647 100644 --- a/public/app/features/dashboard-scene/scene/DashboardScene.tsx +++ b/public/app/features/dashboard-scene/scene/DashboardScene.tsx @@ -34,7 +34,6 @@ import store from 'app/core/store'; import { getDashboardSrv } from 'app/features/dashboard/services/DashboardSrv'; import { DashboardModel, PanelModel } from 'app/features/dashboard/state'; import { dashboardWatcher } from 'app/features/live/dashboard/dashboardWatcher'; -import { deleteDashboard } from 'app/features/manage-dashboards/state/actions'; import { getClosestScopesFacade, ScopesFacade } from 'app/features/scopes'; import { VariablesChanged } from 'app/features/variables/types'; import { DashboardDTO, DashboardMeta, KioskMode, SaveDashboardResponseDTO } from 'app/types'; @@ -891,8 +890,7 @@ export class DashboardScene extends SceneObjectBase { this._initialSaveModel = saveModel; } - public async deleteDashboard() { - await deleteDashboard(this.state.uid!, true); + public async onDashboardDelete() { // Need to mark it non dirty to navigate away without unsaved changes warning this.setState({ isDirty: false }); locationService.replace('/'); diff --git a/public/app/features/dashboard-scene/settings/DeleteDashboardButton.tsx b/public/app/features/dashboard-scene/settings/DeleteDashboardButton.tsx index aca70195cf1..19494d5663d 100644 --- a/public/app/features/dashboard-scene/settings/DeleteDashboardButton.tsx +++ b/public/app/features/dashboard-scene/settings/DeleteDashboardButton.tsx @@ -2,17 +2,56 @@ import { useAsyncFn, useToggle } from 'react-use'; import { selectors } from '@grafana/e2e-selectors'; import { config, reportInteraction } from '@grafana/runtime'; -import { Button, ConfirmModal, Modal } from '@grafana/ui'; -import { Trans } from 'app/core/internationalization'; +import { Button, ConfirmModal, Modal, Space, Text } from '@grafana/ui'; +import { t, Trans } from 'app/core/internationalization'; +import { useDeleteItemsMutation } from '../../browse-dashboards/api/browseDashboardsAPI'; import { DashboardScene } from '../scene/DashboardScene'; interface ButtonProps { dashboard: DashboardScene; } +interface ProvisionedDeleteModalProps { + dashboardId: string | undefined; + onClose: () => void; +} + +interface DeleteModalProps { + dashboardTitle: string; + onConfirm: () => void; + onClose: () => void; +} + export function DeleteDashboardButton({ dashboard }: ButtonProps) { const [showModal, toggleModal] = useToggle(false); + const [deleteItems] = useDeleteItemsMutation(); + + const [, onConfirm] = useAsyncFn(async () => { + reportInteraction('grafana_manage_dashboards_delete_clicked', { + item_counts: { + dashboard: 1, + }, + source: 'dashboard_scene_settings', + restore_enabled: config.featureToggles.dashboardRestoreUI, + }); + toggleModal(); + if (dashboard.state.uid) { + await deleteItems({ + selectedItems: { + dashboard: { + [dashboard.state.uid]: true, + }, + folder: {}, + }, + }); + } + await dashboard.onDashboardDelete(); + }, [dashboard, toggleModal]); + + if (dashboard.state.meta.provisioned && showModal) { + return ; + } return ( <> @@ -24,52 +63,48 @@ export function DeleteDashboardButton({ dashboard }: ButtonProps) { Delete dashboard - {showModal && } + {showModal && ( + + )} ); } -interface ModalProps { - dashboard: DashboardScene; - onClose: () => void; -} - -function DeleteDashboardModal({ dashboard, onClose }: ModalProps) { - const [, onConfirm] = useAsyncFn(async () => { - reportInteraction('grafana_manage_dashboards_delete_clicked', { - item_counts: { - dashboard: 1, - }, - source: 'dashboard_scene_settings', - restore_enabled: config.featureToggles.dashboardRestoreUI, - }); - onClose(); - await dashboard.deleteDashboard(); - }, [dashboard, onClose]); - - if (dashboard.state.meta.provisioned) { - return ; - } - +export function DeleteDashboardModal({ dashboardTitle, onConfirm, onClose }: DeleteModalProps) { return ( -

Do you want to delete this dashboard?

-

{dashboard.state.title}

+ {config.featureToggles.dashboardRestore && ( + <> + + + This action will mark the dashboard for deletion in 30 days. Your organization administrator can + restore it anytime before the 30 days expire. + + + + + )} + + Do you want to delete this dashboard? + + {dashboardTitle} + } onConfirm={onConfirm} onDismiss={onClose} - title="Delete" + title={t('dashboard-settings.delete-modal.title', 'Delete')} icon="trash-alt" - confirmText="Delete" + confirmText={t('dashboard-settings.delete-modal.delete-button', 'Delete')} + confirmationText={t('dashboard-settings.delete-modal.confirmation-text', 'Delete')} /> ); } -function ProvisionedDeleteModal({ dashboard, onClose }: ModalProps) { +function ProvisionedDeleteModal({ dashboardId, onClose }: ProvisionedDeleteModalProps) { return (

@@ -90,7 +125,7 @@ function ProvisionedDeleteModal({ dashboard, onClose }: ModalProps) { for more information about provisioning.
- File path: {dashboard.state.meta.provisionedExternalId} + File path: {dashboardId}