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;
}