From 7fc1caaf988413b630363dbdb535ee192e48cdbc Mon Sep 17 00:00:00 2001 From: Hugo Kiyodi Oshiro Date: Thu, 27 Feb 2025 15:14:20 +0100 Subject: [PATCH] Plugins: Fix update button behavior on downgrade (#101048) --- .../InstallControls/InstallControlsButton.tsx | 2 +- .../admin/components/UpdateAllModal.tsx | 6 +-- .../admin/components/VersionInstallButton.tsx | 49 +++++++++++-------- .../features/plugins/admin/state/actions.ts | 20 +++++--- .../app/features/plugins/admin/state/hooks.ts | 4 +- public/app/features/plugins/admin/types.ts | 1 + 6 files changed, 48 insertions(+), 34 deletions(-) diff --git a/public/app/features/plugins/admin/components/InstallControls/InstallControlsButton.tsx b/public/app/features/plugins/admin/components/InstallControls/InstallControlsButton.tsx index 9e0bdf9f811..9824a5c998a 100644 --- a/public/app/features/plugins/admin/components/InstallControls/InstallControlsButton.tsx +++ b/public/app/features/plugins/admin/components/InstallControls/InstallControlsButton.tsx @@ -112,7 +112,7 @@ export function InstallControlsButton({ const onUpdate = async () => { reportInteraction(PLUGIN_UPDATE_INTERACTION_EVENT_NAME, trackingProps); - await install(plugin.id, latestCompatibleVersion?.version, true); + await install(plugin.id, latestCompatibleVersion?.version, PluginStatus.UPDATE); if (!errorInstalling) { appEvents.emit(AppEvents.alertSuccess, [`Updated ${plugin.name}`]); } diff --git a/public/app/features/plugins/admin/components/UpdateAllModal.tsx b/public/app/features/plugins/admin/components/UpdateAllModal.tsx index f12113499b9..7830b1b253e 100644 --- a/public/app/features/plugins/admin/components/UpdateAllModal.tsx +++ b/public/app/features/plugins/admin/components/UpdateAllModal.tsx @@ -5,7 +5,7 @@ import { ConfirmModal } from '@grafana/ui'; import { t } from 'app/core/internationalization'; import { useInstall, useInstallStatus } from '../state/hooks'; -import { CatalogPlugin } from '../types'; +import { CatalogPlugin, PluginStatus } from '../types'; import { UpdateModalBody } from './UpdateAllModalBody'; const PLUGINS_UPDATE_ALL_INTERACTION_EVENT_NAME = 'plugins_update_all_clicked'; @@ -100,13 +100,13 @@ export const UpdateAllModal = ({ isOpen, onDismiss, isLoading, plugins }: Props) if (config.pluginAdminExternalManageEnabled) { for (let plugin of plugins) { if (selectedPlugins?.has(plugin.id)) { - await install(plugin.id, plugin.latestVersion, true); + await install(plugin.id, plugin.latestVersion, PluginStatus.UPDATE); } } } else { plugins.forEach((plugin) => { if (selectedPlugins?.has(plugin.id)) { - install(plugin.id, plugin.latestVersion, true); + install(plugin.id, plugin.latestVersion, PluginStatus.UPDATE); } }); } diff --git a/public/app/features/plugins/admin/components/VersionInstallButton.tsx b/public/app/features/plugins/admin/components/VersionInstallButton.tsx index f0bec011875..7792ffc06a8 100644 --- a/public/app/features/plugins/admin/components/VersionInstallButton.tsx +++ b/public/app/features/plugins/admin/components/VersionInstallButton.tsx @@ -9,17 +9,10 @@ import { t } from 'app/core/internationalization'; import { isPreinstalledPlugin } from '../helpers'; import { useInstall } from '../state/hooks'; -import { Version } from '../types'; +import { PluginStatus, Version } from '../types'; const PLUGINS_VERSION_PAGE_UPGRADE_INTERACTION_EVENT_NAME = 'plugins_upgrade_clicked'; const PLUGINS_VERSION_PAGE_CHANGE_INTERACTION_EVENT_NAME = 'plugins_downgrade_clicked'; - -enum InstallState { - INSTALL = 'Install', - UPGRADE = 'Upgrade', - DOWNGRADE = 'Downgrade', -} - interface Props { pluginId: string; version: Version; @@ -67,7 +60,7 @@ export const VersionInstallButton = ({ schema_version: '1.0.0', }; - if (installState === InstallState.UPGRADE) { + if (installState === PluginStatus.UPDATE) { reportInteraction(PLUGINS_VERSION_PAGE_UPGRADE_INTERACTION_EVENT_NAME, trackProps); } else { reportInteraction(PLUGINS_VERSION_PAGE_CHANGE_INTERACTION_EVENT_NAME, { @@ -76,13 +69,13 @@ export const VersionInstallButton = ({ }); } - install(pluginId, version.version, true); + install(pluginId, version.version, installState); setIsInstalling(true); onConfirmInstallation(); }; const onInstallClick = () => { - if (installState === InstallState.DOWNGRADE) { + if (installState === PluginStatus.DOWNGRADE) { setIsModalOpen(true); } else { performInstallation(); @@ -115,7 +108,8 @@ export const VersionInstallButton = ({ tooltip={tooltip} tooltipPlacement="bottom-start" > - {installState} {isInstalling ? : getIcon(installState)} + {getLabel(installState)}{' '} + {isInstalling ? : getIcon(installState)} ; } - if (installState === InstallState.UPGRADE) { + if (installState === PluginStatus.UPDATE) { return ; } return ''; } -function getInstallState(installedVersion?: string, version?: string): InstallState { +function getInstallState(installedVersion?: string, version?: string): PluginStatus { if (!installedVersion || !version || !valid(installedVersion) || !valid(version)) { - return InstallState.INSTALL; + return PluginStatus.INSTALL; } - return gt(installedVersion, version) ? InstallState.DOWNGRADE : InstallState.UPGRADE; + return gt(installedVersion, version) ? PluginStatus.DOWNGRADE : PluginStatus.UPDATE; } -function getButtonHiddenState(installState: InstallState, isPreinstalled: { found: boolean; withVersion: boolean }) { +function getButtonHiddenState(installState: PluginStatus, isPreinstalled: { found: boolean; withVersion: boolean }) { // Default state for initial install - if (installState === InstallState.INSTALL) { + if (installState === PluginStatus.INSTALL) { return false; } // Handle downgrade case - if (installState === InstallState.DOWNGRADE) { + if (installState === PluginStatus.DOWNGRADE) { return isPreinstalled.found && Boolean(config.featureToggles.preinstallAutoUpdate); } diff --git a/public/app/features/plugins/admin/state/actions.ts b/public/app/features/plugins/admin/state/actions.ts index eab93de18fa..e08e7241c42 100644 --- a/public/app/features/plugins/admin/state/actions.ts +++ b/public/app/features/plugins/admin/state/actions.ts @@ -19,7 +19,7 @@ import { } from '../api'; import { STATE_PREFIX } from '../constants'; import { mapLocalToCatalog, mergeLocalsAndRemotes, updatePanels } from '../helpers'; -import { CatalogPlugin, RemotePlugin, LocalPlugin, InstancePlugin, ProvisionedPlugin } from '../types'; +import { CatalogPlugin, RemotePlugin, LocalPlugin, InstancePlugin, ProvisionedPlugin, PluginStatus } from '../types'; // Fetches export const fetchAll = createAsyncThunk(`${STATE_PREFIX}/fetchAll`, async (_, thunkApi) => { @@ -188,17 +188,23 @@ export const install = createAsyncThunk< { id: string; version?: string; - isUpdating?: boolean; + installType?: PluginStatus; } ->(`${STATE_PREFIX}/install`, async ({ id, version, isUpdating = false }, thunkApi) => { - const changes = isUpdating - ? { isInstalled: true, installedVersion: version, hasUpdate: false } - : { isInstalled: true, installedVersion: version }; +>(`${STATE_PREFIX}/install`, async ({ id, version, installType = PluginStatus.INSTALL }, thunkApi) => { + const changes: Partial = { isInstalled: true, installedVersion: version }; + + if (installType === PluginStatus.UPDATE) { + changes.hasUpdate = false; + } + if (installType === PluginStatus.DOWNGRADE) { + changes.hasUpdate = true; + } + try { await installPlugin(id, version); await updatePanels(); - if (isUpdating) { + if (installType !== PluginStatus.INSTALL) { invalidatePluginInCache(id); } diff --git a/public/app/features/plugins/admin/state/hooks.ts b/public/app/features/plugins/admin/state/hooks.ts index da0ba859a3a..457f2f1d73e 100644 --- a/public/app/features/plugins/admin/state/hooks.ts +++ b/public/app/features/plugins/admin/state/hooks.ts @@ -4,7 +4,7 @@ import { PluginError, PluginType } from '@grafana/data'; import { useDispatch, useSelector } from 'app/types'; import { sortPlugins, Sorters, isPluginUpdatable } from '../helpers'; -import { CatalogPlugin } from '../types'; +import { CatalogPlugin, PluginStatus } from '../types'; import { fetchAll, fetchDetails, fetchRemotePlugins, install, uninstall, fetchAllLocal, unsetInstall } from './actions'; import { @@ -64,7 +64,7 @@ export const useGetErrors = (filterByPluginType?: PluginType): PluginError[] => export const useInstall = () => { const dispatch = useDispatch(); - return (id: string, version?: string, isUpdating?: boolean) => dispatch(install({ id, version, isUpdating })); + return (id: string, version?: string, installType?: PluginStatus) => dispatch(install({ id, version, installType })); }; export const useUnsetInstall = () => { diff --git a/public/app/features/plugins/admin/types.ts b/public/app/features/plugins/admin/types.ts index f3d5783ae3c..96e1d2451d2 100644 --- a/public/app/features/plugins/admin/types.ts +++ b/public/app/features/plugins/admin/types.ts @@ -257,6 +257,7 @@ export enum PluginStatus { UNINSTALL = 'UNINSTALL', UPDATE = 'UPDATE', REINSTALL = 'REINSTALL', + DOWNGRADE = 'DOWNGRADE', } export enum PluginTabLabels {