From 503176603f12cd4e340db6ba2bb647fb02bf1617 Mon Sep 17 00:00:00 2001 From: Levente Balogh Date: Wed, 22 Nov 2023 13:20:58 +0100 Subject: [PATCH] Plugins: Support markdown in custom plugin deprecation messages (#78251) * feat: support markdown in custom deprecation messages * fix: use a div wrapper for rendered markdown * feat: update the default deprecation message --- .../PluginDetailsDeprecatedWarning.tsx | 30 +++++++++++---- .../admin/pages/PluginDetails.test.tsx | 37 +++++++++++++------ 2 files changed, 49 insertions(+), 18 deletions(-) diff --git a/public/app/features/plugins/admin/components/PluginDetailsDeprecatedWarning.tsx b/public/app/features/plugins/admin/components/PluginDetailsDeprecatedWarning.tsx index 1a6a02eb7cc..c4977b81afc 100644 --- a/public/app/features/plugins/admin/components/PluginDetailsDeprecatedWarning.tsx +++ b/public/app/features/plugins/admin/components/PluginDetailsDeprecatedWarning.tsx @@ -1,5 +1,6 @@ import React, { useState } from 'react'; +import { renderMarkdown } from '@grafana/data'; import { Alert } from '@grafana/ui'; import { CatalogPlugin } from '../types'; @@ -13,16 +14,31 @@ export function PluginDetailsDeprecatedWarning(props: Props): React.ReactElement const { className, plugin } = props; const [dismissed, setDismissed] = useState(false); const isWarningVisible = plugin.isDeprecated && !dismissed; - let deprecationMessage = `This ${plugin.type} plugin is deprecated and has been removed from the catalog. No further updates will be made to the - plugin.`; - - if (plugin.details?.statusContext) { - deprecationMessage += ` More information: ${plugin.details.statusContext}`; - } return isWarningVisible ? ( setDismissed(true)}> -

{deprecationMessage}

+

+ This {plugin.type} plugin is{' '} + + deprecated + {' '} + and has been removed from the catalog. +

+ + {/* Additional contextual deprecation message supporting markdown */} + {plugin.details?.statusContext && ( +
+ )} ) : null; } diff --git a/public/app/features/plugins/admin/pages/PluginDetails.test.tsx b/public/app/features/plugins/admin/pages/PluginDetails.test.tsx index 92c7410c208..259d9a6433d 100644 --- a/public/app/features/plugins/admin/pages/PluginDetails.test.tsx +++ b/public/app/features/plugins/admin/pages/PluginDetails.test.tsx @@ -744,32 +744,28 @@ describe('Plugin details page', () => { }); it('should display a deprecation warning if the plugin is deprecated', async () => { - const { queryByText } = renderPluginDetails({ + const { findByRole } = renderPluginDetails({ id, isInstalled: true, isDeprecated: true, }); - await waitFor(() => - expect(queryByText(/plugin is deprecated and has been removed from the catalog/i)).toBeInTheDocument() - ); + expect(await findByRole('link', { name: 'deprecated' })).toBeInTheDocument(); }); it('should not display a deprecation warning in the plugin is not deprecated', async () => { - const { queryByText } = renderPluginDetails({ + const { queryByRole } = renderPluginDetails({ id, isInstalled: true, isDeprecated: false, }); - await waitFor(() => - expect(queryByText(/plugin is deprecated and has been removed from the catalog/i)).not.toBeInTheDocument() - ); + await waitFor(() => expect(queryByRole('link', { name: 'deprecated' })).not.toBeInTheDocument()); }); it('should display a custom deprecation message if the plugin has it set', async () => { const statusContext = 'A detailed explanation of why this plugin is deprecated.'; - const { queryByText } = renderPluginDetails({ + const { findByText, findByRole } = renderPluginDetails({ id, isInstalled: true, isDeprecated: true, @@ -779,9 +775,28 @@ describe('Plugin details page', () => { }, }); - const re = new RegExp(`No further updates will be made to the plugin. More information: ${statusContext}`, 'i'); + expect(await findByRole('link', { name: 'deprecated' })).toBeInTheDocument(); + expect(await findByText(statusContext)).toBeInTheDocument(); + }); - await waitFor(() => expect(queryByText(re)).toBeInTheDocument()); + it('should be possible to render markdown inside a custom deprecation message', async () => { + const statusContext = + '**This is a custom deprecation message.** [Link 1](https://grafana.com) Link 2'; + const { findByText, findByRole } = renderPluginDetails({ + id, + isInstalled: true, + isDeprecated: true, + details: { + statusContext, + links: [], + }, + }); + + expect(await findByRole('link', { name: 'deprecated' })).toBeInTheDocument(); + expect(await findByText('This is a custom deprecation message.')).toBeInTheDocument(); + expect(await findByRole('link', { name: 'Link 1' })).toBeInTheDocument(); + expect(await findByRole('link', { name: 'Link 2' })).toBeInTheDocument(); + expect(await findByRole('link', { name: 'Link 2' })).toHaveAttribute('href', 'https://grafana.com'); }); });