From 02f956460754a67e7816010f51adf55fb2681298 Mon Sep 17 00:00:00 2001 From: Levente Balogh Date: Thu, 16 Sep 2021 11:27:29 +0200 Subject: [PATCH] Plugins Catalog: show a confirmation modal when uninstalling a plugin (#39244) * feat(Plugins/Admin): show a confirmation modal when uninstalling a plugin * refactor(Plugins/Admin): use a helper function for showing/hiding the modal * test(Plugins/Admin): test if the modal disappears after an uninstall --- .../InstallControls/InstallControlsButton.tsx | 33 ++++++++++++----- .../admin/pages/PluginDetails.test.tsx | 37 +++++++++++++++++++ 2 files changed, 61 insertions(+), 9 deletions(-) diff --git a/public/app/features/plugins/admin/components/InstallControls/InstallControlsButton.tsx b/public/app/features/plugins/admin/components/InstallControls/InstallControlsButton.tsx index ce69db3fa0d..e92927ac780 100644 --- a/public/app/features/plugins/admin/components/InstallControls/InstallControlsButton.tsx +++ b/public/app/features/plugins/admin/components/InstallControls/InstallControlsButton.tsx @@ -1,7 +1,7 @@ import React, { useState } from 'react'; import { useMountedState } from 'react-use'; import { AppEvents, PluginType } from '@grafana/data'; -import { Button, HorizontalGroup, useStyles2 } from '@grafana/ui'; +import { Button, HorizontalGroup, ConfirmModal, useStyles2 } from '@grafana/ui'; import appEvents from 'app/core/app_events'; import { CatalogPlugin, PluginStatus } from '../../types'; @@ -18,6 +18,9 @@ export function InstallControlsButton({ plugin, pluginStatus }: InstallControlsB const { isUninstalling, error: errorUninstalling } = useUninstallStatus(); const install = useInstall(); const uninstall = useUninstall(); + const [isConfirmModalVisible, setIsConfirmModalVisible] = useState(false); + const showConfirmModal = () => setIsConfirmModalVisible(true); + const hideConfirmModal = () => setIsConfirmModalVisible(false); const [hasInstalledPanel, setHasInstalledPanel] = useState(false); const styles = useStyles2(getStyles); const uninstallBtnText = isUninstalling ? 'Uninstalling' : 'Uninstall'; @@ -34,6 +37,7 @@ export function InstallControlsButton({ plugin, pluginStatus }: InstallControlsB }; const onUninstall = async () => { + hideConfirmModal(); await uninstall(plugin.id); if (!errorUninstalling) { appEvents.emit(AppEvents.alertSuccess, [`Uninstalled ${plugin.name}`]); @@ -49,14 +53,25 @@ export function InstallControlsButton({ plugin, pluginStatus }: InstallControlsB if (pluginStatus === PluginStatus.UNINSTALL) { return ( - - - {hasInstalledPanel && ( -
Please refresh your browser window before using this plugin.
- )} -
+ <> + + + + {hasInstalledPanel && ( +
Please refresh your browser window before using this plugin.
+ )} +
+ ); } diff --git a/public/app/features/plugins/admin/pages/PluginDetails.test.tsx b/public/app/features/plugins/admin/pages/PluginDetails.test.tsx index 6597c5bab9b..9922876d6ea 100644 --- a/public/app/features/plugins/admin/pages/PluginDetails.test.tsx +++ b/public/app/features/plugins/admin/pages/PluginDetails.test.tsx @@ -7,6 +7,7 @@ import { configureStore } from 'app/store/configureStore'; import PluginDetailsPage from './PluginDetails'; import { getRouteComponentProps } from 'app/core/navigation/__mocks__/routeProps'; import { CatalogPlugin } from '../types'; +import * as api from '../api'; import { mockPluginApis, getCatalogPluginMock, getPluginsStateMock } from '../__mocks__'; // Mock the config to enable the plugin catalog @@ -46,6 +47,8 @@ describe('Plugin details page', () => { afterEach(() => { jest.clearAllMocks(); + config.pluginAdminExternalManageEnabled = false; + config.licenseInfo.hasValidLicense = false; }); afterAll(() => { @@ -208,4 +211,38 @@ describe('Plugin details page', () => { expect(queryByText('Grafana >=8.0.0')).toBeInTheDocument(); }); + + it('should show a confirm modal when trying to uninstall a plugin', async () => { + // @ts-ignore + api.uninstallPlugin = jest.fn(); + + const { queryByText, queryByRole, getByRole } = renderPluginDetails({ + id, + name: 'Akumuli', + isInstalled: true, + details: { + pluginDependencies: [], + grafanaDependency: '>=8.0.0', + links: [], + }, + }); + + // Wait for the install controls to be loaded + await waitFor(() => expect(queryByRole('button', { name: /install/i })).toBeInTheDocument()); + + // Open the confirmation modal + userEvent.click(getByRole('button', { name: /uninstall/i })); + + expect(queryByText('Uninstall Akumuli')).toBeInTheDocument(); + expect(queryByText('Are you sure you want to uninstall this plugin?')).toBeInTheDocument(); + expect(api.uninstallPlugin).toHaveBeenCalledTimes(0); + + // Confirm the uninstall + userEvent.click(getByRole('button', { name: /confirm/i })); + expect(api.uninstallPlugin).toHaveBeenCalledTimes(1); + expect(api.uninstallPlugin).toHaveBeenCalledWith(id); + + // Check if the modal disappeared + expect(queryByText('Uninstall Akumuli')).not.toBeInTheDocument(); + }); });