diff --git a/public/app/features/plugins/admin/components/PluginListItemBadges.tsx b/public/app/features/plugins/admin/components/PluginListItemBadges.tsx index 909f380db92..e4f8bcaa8f5 100644 --- a/public/app/features/plugins/admin/components/PluginListItemBadges.tsx +++ b/public/app/features/plugins/admin/components/PluginListItemBadges.tsx @@ -1,6 +1,6 @@ -import { PluginType } from '@grafana/data'; import { PluginSignatureBadge, Stack } from '@grafana/ui'; +import { isPluginUpdateable } from '../helpers'; import { CatalogPlugin } from '../types'; import { @@ -18,15 +18,13 @@ type PluginBadgeType = { export function PluginListItemBadges({ plugin }: PluginBadgeType) { // Currently renderer plugins are not supported by the catalog due to complications related to installation / update / uninstall. - const hasUpdate = plugin.hasUpdate && !plugin.isCore && plugin.type !== PluginType.renderer; + const canUpdate = isPluginUpdateable(plugin); if (plugin.isEnterprise) { return ( {plugin.isDisabled && } - {hasUpdate && !plugin.isManaged && !plugin.isPreinstalled.withVersion && ( - - )} + {canUpdate && } {plugin.angularDetected && } ); @@ -38,9 +36,7 @@ export function PluginListItemBadges({ plugin }: PluginBadgeType) { {plugin.isDisabled && } {plugin.isDeprecated && } {plugin.isInstalled && } - {hasUpdate && !plugin.isManaged && !plugin.isPreinstalled.withVersion && ( - - )} + {canUpdate && } {plugin.angularDetected && } ); diff --git a/public/app/features/plugins/admin/helpers.ts b/public/app/features/plugins/admin/helpers.ts index d2055b004b5..b68a6dd44ee 100644 --- a/public/app/features/plugins/admin/helpers.ts +++ b/public/app/features/plugins/admin/helpers.ts @@ -425,3 +425,42 @@ export function filterByKeyword(plugins: CatalogPlugin[], query: string) { } return idxs.map((id) => getId(dataArray[id])); } + +export function isPluginUpdateable(plugin: CatalogPlugin) { + // If there is no update available, the plugin cannot be updated + if (!plugin.hasUpdate) { + return false; + } + + // Provisioned plugins cannot be updated + if (plugin.isProvisioned) { + return false; + } + + // Core plugins cannot be updated + if (plugin.isCore) { + return false; + } + + // Currently renderer plugins are not supported by the catalog due to complications related to installation / update / uninstall. + if (plugin.type === PluginType.renderer) { + return false; + } + + // Preinstalled plugins (with specified version) cannot be updated + if (plugin.isPreinstalled.withVersion) { + return false; + } + + // If the plugin is currently being updated, it should not be updated + if (plugin.isUpdatingFromInstance) { + return false; + } + + // Managed plugins cannot be updated + if (plugin.isManaged) { + return false; + } + + return true; +} diff --git a/public/app/features/plugins/admin/state/hooks.ts b/public/app/features/plugins/admin/state/hooks.ts index 061645f45b5..ddef973b456 100644 --- a/public/app/features/plugins/admin/state/hooks.ts +++ b/public/app/features/plugins/admin/state/hooks.ts @@ -3,7 +3,7 @@ import { useEffect, useMemo } from 'react'; import { PluginError, PluginType } from '@grafana/data'; import { useDispatch, useSelector } from 'app/types'; -import { sortPlugins, Sorters } from '../helpers'; +import { sortPlugins, Sorters, isPluginUpdateable } from '../helpers'; import { CatalogPlugin } from '../types'; import { fetchAll, fetchDetails, fetchRemotePlugins, install, uninstall, fetchAllLocal, unsetInstall } from './actions'; @@ -36,7 +36,8 @@ export const useGetAll = (filters: PluginFilters, sortBy: Sorters = Sorters.name export const useGetUpdatable = () => { const { isLoading } = useFetchStatus(); - const updatablePlugins = useSelector(selectPlugins({ isInstalled: true, hasUpdate: true })); + const { plugins: installed } = useGetAll({ isInstalled: true }); + const updatablePlugins = installed.filter(isPluginUpdateable); return { isLoading, updatablePlugins, diff --git a/public/app/features/plugins/admin/state/selectors.ts b/public/app/features/plugins/admin/state/selectors.ts index ce9875e7504..d0af21fa41c 100644 --- a/public/app/features/plugins/admin/state/selectors.ts +++ b/public/app/features/plugins/admin/state/selectors.ts @@ -3,7 +3,7 @@ import { createSelector } from '@reduxjs/toolkit'; import { PluginError, PluginType, unEscapeStringFromRegex } from '@grafana/data'; import { reportInteraction } from '@grafana/runtime'; -import { filterByKeyword } from '../helpers'; +import { filterByKeyword, isPluginUpdateable } from '../helpers'; import { RequestStatus, PluginCatalogStoreState } from '../types'; import { pluginsAdapter } from './reducer'; @@ -61,17 +61,7 @@ export const selectPlugins = (filters: PluginFilters) => return false; } - if (filters.hasUpdate !== undefined && plugin.hasUpdate !== filters.hasUpdate) { - return false; - } - - // plugins not controlled by the user should not be shown as updatable - if ( - filters.hasUpdate !== undefined && - filters.hasUpdate && - plugin.hasUpdate && - (plugin.isCore || plugin.isManaged || plugin.isProvisioned || plugin.isUpdatingFromInstance) - ) { + if (filters.hasUpdate !== undefined && (plugin.hasUpdate !== filters.hasUpdate || !isPluginUpdateable(plugin))) { return false; }