From ad6cf2ce4de57a26cb7fc48c56234bb2f81f5276 Mon Sep 17 00:00:00 2001 From: Alex Khomenko Date: Wed, 17 Jul 2024 15:00:46 +0300 Subject: [PATCH] Restore dashboards: Design review (#90468) * Update singular case * More copy & count fixes * Translate success messages * Update message * Split no-deleted message --- .../api/browseDashboardsAPI.ts | 42 +++++++++++++++---- .../components/RecentlyDeletedEmptyState.tsx | 9 +++- public/locales/en-US/grafana.json | 21 ++++++---- public/locales/pseudo-LOCALE/grafana.json | 21 ++++++---- 4 files changed, 70 insertions(+), 23 deletions(-) diff --git a/public/app/features/browse-dashboards/api/browseDashboardsAPI.ts b/public/app/features/browse-dashboards/api/browseDashboardsAPI.ts index 47567dcf153..857a54c8360 100644 --- a/public/app/features/browse-dashboards/api/browseDashboardsAPI.ts +++ b/public/app/features/browse-dashboards/api/browseDashboardsAPI.ts @@ -1,10 +1,11 @@ import { BaseQueryFn, createApi } from '@reduxjs/toolkit/query/react'; import { lastValueFrom } from 'rxjs'; -import { isTruthy, locationUtil } from '@grafana/data'; +import { AppEvents, isTruthy, locationUtil } from '@grafana/data'; import { BackendSrvRequest, getBackendSrv, locationService } from '@grafana/runtime'; import { Dashboard } from '@grafana/schema'; import { notifyApp } from 'app/core/actions'; +import appEvents from 'app/core/app_events'; import { createSuccessNotification } from 'app/core/copy/appNotification'; import { contextSrv } from 'app/core/core'; import { getDashboardAPI } from 'app/features/dashboard/api/dashboard_api'; @@ -21,6 +22,7 @@ import { SaveDashboardResponseDTO, } from 'app/types'; +import { t } from '../../../core/internationalization'; import { refetchChildren, refreshParents } from '../state'; import { DashboardTreeSelection } from '../types'; @@ -309,14 +311,25 @@ export const browseDashboardsAPI = createApi({ }, }); } - // Delete all the dashboards sequentially // TODO error handling here for (const dashboardUID of selectedDashboards) { - await baseQuery({ + const response = await baseQuery({ url: `/dashboards/uid/${dashboardUID}`, method: 'DELETE', + showSuccessAlert: false, }); + // @ts-expect-error + const name = response?.data?.title; + + if (name) { + appEvents.publish({ + type: AppEvents.alertSuccess.name, + payload: [ + t('browse-dashboards.soft-delete.success', 'Dashboard {{name}} moved to Recently deleted', { name }), + ], + }); + } } return { data: undefined }; }, @@ -389,10 +402,25 @@ export const browseDashboardsAPI = createApi({ // permanently delete a dashboard. used in PermanentlyDeleteModal. hardDeleteDashboard: builder.mutation({ - query: ({ dashboardUID }) => ({ - url: `/dashboards/uid/${dashboardUID}/trash`, - method: 'DELETE', - }), + queryFn: async ({ dashboardUID }, _api, _extraOptions, baseQuery) => { + const response = await baseQuery({ + url: `/dashboards/uid/${dashboardUID}/trash`, + method: 'DELETE', + showSuccessAlert: false, + }); + + // @ts-expect-error + const name = response?.data?.title; + + if (name) { + appEvents.publish({ + type: AppEvents.alertSuccess.name, + payload: [t('browse-dashboards.hard-delete.success', 'Dashboard {{name}} deleted', { name })], + }); + } + + return { data: undefined }; + }, onQueryStarted: ({ dashboardUID }, { queryFulfilled, dispatch }) => { queryFulfilled.then(() => { dispatch(refreshParents([dashboardUID])); diff --git a/public/app/features/browse-dashboards/components/RecentlyDeletedEmptyState.tsx b/public/app/features/browse-dashboards/components/RecentlyDeletedEmptyState.tsx index 8415b7551fa..5cceb112768 100644 --- a/public/app/features/browse-dashboards/components/RecentlyDeletedEmptyState.tsx +++ b/public/app/features/browse-dashboards/components/RecentlyDeletedEmptyState.tsx @@ -1,5 +1,5 @@ import { EmptyState } from '@grafana/ui'; -import { t } from 'app/core/internationalization'; +import { t, Trans } from 'app/core/internationalization'; import { SearchState } from 'app/features/search/types'; interface RecentlyDeletedEmptyStateProps { @@ -17,6 +17,11 @@ export const RecentlyDeletedEmptyState = ({ searchState }: RecentlyDeletedEmptyS } variant={userIsSearching ? 'not-found' : 'completed'} role="alert" - /> + > + + When you delete a dashboard, it will appear here for 30 days before being permanently deleted. Your organization + administrator can restore recently-deleted dashboards. + + ); }; diff --git a/public/locales/en-US/grafana.json b/public/locales/en-US/grafana.json index ce8d0076cc6..3d995bd627f 100644 --- a/public/locales/en-US/grafana.json +++ b/public/locales/en-US/grafana.json @@ -188,15 +188,15 @@ }, "counts": { "alertRule_one": "{{count}} alert rule", - "alertRule_other": "{{count}} alert rule", + "alertRule_other": "{{count}} alert rules", "dashboard_one": "{{count}} dashboard", - "dashboard_other": "{{count}} dashboard", + "dashboard_other": "{{count}} dashboards", "folder_one": "{{count}} folder", - "folder_other": "{{count}} folder", + "folder_other": "{{count}} folders", "libraryPanel_one": "{{count}} library panel", - "libraryPanel_other": "{{count}} library panel", + "libraryPanel_other": "{{count}} library panels", "total_one": "{{count}} item", - "total_other": "{{count}} item" + "total_other": "{{count}} items" }, "dashboards-tree": { "collapse-folder-button": "Collapse folder {{title}}", @@ -227,6 +227,9 @@ "search-placeholder": "Search folders", "unknown-error": "Unknown error" }, + "hard-delete": { + "success": "Dashboard {{name}} deleted" + }, "manage-folder-nav": { "alert-rules": "Alert rules", "dashboards": "Dashboards", @@ -240,6 +243,9 @@ "no-results": { "clear": "Clear search and filters", "text": "No results found for your query" + }, + "soft-delete": { + "success": "Dashboard {{name}} moved to Recently deleted" } }, "clipboard-button": { @@ -1733,20 +1739,21 @@ }, "page": { "no-deleted-dashboards": "You haven't deleted any dashboards recently.", + "no-deleted-dashboards-text": "When you delete a dashboard, it will appear here for 30 days before being permanently deleted. Your organization administrator can restore recently-deleted dashboards.", "no-search-result": "No results found for your query" }, "permanently-delete-modal": { "confirm-text": "Delete", "delete-button": "Delete", "delete-loading": "Deleting...", - "text_one": "This action will delete {{numberOfDashboards}} dashboards.", + "text_one": "This action will delete {{numberOfDashboards}} dashboard.", "text_other": "This action will delete {{numberOfDashboards}} dashboards.", "title": "Permanently Delete Dashboards" }, "restore-modal": { "restore-button": "Restore", "restore-loading": "Restoring...", - "text_one": "This action will restore {{numberOfDashboards}} dashboards.", + "text_one": "This action will restore {{numberOfDashboards}} dashboard.", "text_other": "This action will restore {{numberOfDashboards}} dashboards.", "title": "Restore Dashboards" } diff --git a/public/locales/pseudo-LOCALE/grafana.json b/public/locales/pseudo-LOCALE/grafana.json index f3b8135be83..285f9b68585 100644 --- a/public/locales/pseudo-LOCALE/grafana.json +++ b/public/locales/pseudo-LOCALE/grafana.json @@ -188,15 +188,15 @@ }, "counts": { "alertRule_one": "{{count}} äľęřŧ řūľę", - "alertRule_other": "{{count}} äľęřŧ řūľę", + "alertRule_other": "{{count}} äľęřŧ řūľęş", "dashboard_one": "{{count}} đäşĥþőäřđ", - "dashboard_other": "{{count}} đäşĥþőäřđ", + "dashboard_other": "{{count}} đäşĥþőäřđş", "folder_one": "{{count}} ƒőľđęř", - "folder_other": "{{count}} ƒőľđęř", + "folder_other": "{{count}} ƒőľđęřş", "libraryPanel_one": "{{count}} ľįþřäřy päʼnęľ", - "libraryPanel_other": "{{count}} ľįþřäřy päʼnęľ", + "libraryPanel_other": "{{count}} ľįþřäřy päʼnęľş", "total_one": "{{count}} įŧęm", - "total_other": "{{count}} įŧęm" + "total_other": "{{count}} įŧęmş" }, "dashboards-tree": { "collapse-folder-button": "Cőľľäpşę ƒőľđęř {{title}}", @@ -227,6 +227,9 @@ "search-placeholder": "Ŝęäřčĥ ƒőľđęřş", "unknown-error": "Ůʼnĸʼnőŵʼn ęřřőř" }, + "hard-delete": { + "success": "Đäşĥþőäřđ {{name}} đęľęŧęđ" + }, "manage-folder-nav": { "alert-rules": "Åľęřŧ řūľęş", "dashboards": "Đäşĥþőäřđş", @@ -240,6 +243,9 @@ "no-results": { "clear": "Cľęäř şęäřčĥ äʼnđ ƒįľŧęřş", "text": "Ńő řęşūľŧş ƒőūʼnđ ƒőř yőūř qūęřy" + }, + "soft-delete": { + "success": "Đäşĥþőäřđ {{name}} mővęđ ŧő Ŗęčęʼnŧľy đęľęŧęđ" } }, "clipboard-button": { @@ -1733,20 +1739,21 @@ }, "page": { "no-deleted-dashboards": "Ÿőū ĥävęʼn'ŧ đęľęŧęđ äʼny đäşĥþőäřđş řęčęʼnŧľy.", + "no-deleted-dashboards-text": "Ŵĥęʼn yőū đęľęŧę ä đäşĥþőäřđ, įŧ ŵįľľ äppęäř ĥęřę ƒőř 30 đäyş þęƒőřę þęįʼnģ pęřmäʼnęʼnŧľy đęľęŧęđ. Ÿőūř őřģäʼnįžäŧįőʼn äđmįʼnįşŧřäŧőř čäʼn řęşŧőřę řęčęʼnŧľy-đęľęŧęđ đäşĥþőäřđş.", "no-search-result": "Ńő řęşūľŧş ƒőūʼnđ ƒőř yőūř qūęřy" }, "permanently-delete-modal": { "confirm-text": "Đęľęŧę", "delete-button": "Đęľęŧę", "delete-loading": "Đęľęŧįʼnģ...", - "text_one": "Ŧĥįş äčŧįőʼn ŵįľľ đęľęŧę {{numberOfDashboards}} đäşĥþőäřđş.", + "text_one": "Ŧĥįş äčŧįőʼn ŵįľľ đęľęŧę {{numberOfDashboards}} đäşĥþőäřđ.", "text_other": "Ŧĥįş äčŧįőʼn ŵįľľ đęľęŧę {{numberOfDashboards}} đäşĥþőäřđş.", "title": "Pęřmäʼnęʼnŧľy Đęľęŧę Đäşĥþőäřđş" }, "restore-modal": { "restore-button": "Ŗęşŧőřę", "restore-loading": "Ŗęşŧőřįʼnģ...", - "text_one": "Ŧĥįş äčŧįőʼn ŵįľľ řęşŧőřę {{numberOfDashboards}} đäşĥþőäřđş.", + "text_one": "Ŧĥįş äčŧįőʼn ŵįľľ řęşŧőřę {{numberOfDashboards}} đäşĥþőäřđ.", "text_other": "Ŧĥįş äčŧįőʼn ŵįľľ řęşŧőřę {{numberOfDashboards}} đäşĥþőäřđş.", "title": "Ŗęşŧőřę Đäşĥþőäřđş" }