Plugins: Fix update button behavior on downgrade (#101048)

This commit is contained in:
Hugo Kiyodi Oshiro
2025-02-27 15:14:20 +01:00
committed by GitHub
parent f54910342d
commit 7fc1caaf98
6 changed files with 48 additions and 34 deletions
@@ -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}`]);
}
@@ -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);
}
});
}
@@ -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 ? <Spinner className={styles.spinner} inline size="sm" /> : getIcon(installState)}
{getLabel(installState)}{' '}
{isInstalling ? <Spinner className={styles.spinner} inline size="sm" /> : getIcon(installState)}
</Button>
<ConfirmModal
isOpen={isModalOpen}
@@ -131,31 +125,44 @@ export const VersionInstallButton = ({
);
};
function getIcon(installState: InstallState) {
if (installState === InstallState.DOWNGRADE) {
function getLabel(installState: PluginStatus) {
switch (installState) {
case PluginStatus.INSTALL:
return 'Install';
case PluginStatus.UPDATE:
return 'Upgrade';
case PluginStatus.DOWNGRADE:
return 'Downgrade';
default:
return '';
}
}
function getIcon(installState: PluginStatus) {
if (installState === PluginStatus.DOWNGRADE) {
return <Icon name="arrow-down" />;
}
if (installState === InstallState.UPGRADE) {
if (installState === PluginStatus.UPDATE) {
return <Icon name="arrow-up" />;
}
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);
}
@@ -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<CatalogPlugin> = { 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);
}
@@ -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 = () => {
@@ -257,6 +257,7 @@ export enum PluginStatus {
UNINSTALL = 'UNINSTALL',
UPDATE = 'UPDATE',
REINSTALL = 'REINSTALL',
DOWNGRADE = 'DOWNGRADE',
}
export enum PluginTabLabels {