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
This commit is contained in:
Levente Balogh 2021-09-16 11:27:29 +02:00 committed by GitHub
parent 35f1d0facb
commit 02f9564607
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 61 additions and 9 deletions

View File

@ -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 (
<HorizontalGroup height="auto">
<Button variant="destructive" disabled={isUninstalling} onClick={onUninstall}>
{uninstallBtnText}
</Button>
{hasInstalledPanel && (
<div className={styles.message}>Please refresh your browser window before using this plugin.</div>
)}
</HorizontalGroup>
<>
<ConfirmModal
isOpen={isConfirmModalVisible}
title={`Uninstall ${plugin.name}`}
body="Are you sure you want to uninstall this plugin?"
confirmText="Confirm"
icon="exclamation-triangle"
onConfirm={onUninstall}
onDismiss={hideConfirmModal}
/>
<HorizontalGroup height="auto">
<Button variant="destructive" disabled={isUninstalling} onClick={showConfirmModal}>
{uninstallBtnText}
</Button>
{hasInstalledPanel && (
<div className={styles.message}>Please refresh your browser window before using this plugin.</div>
)}
</HorizontalGroup>
</>
);
}

View File

@ -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();
});
});