From ecd1a6e4216e51d3714d2a31954d211a937fc2da Mon Sep 17 00:00:00 2001 From: Hugo Kiyodi Oshiro Date: Wed, 11 Sep 2024 12:12:06 +0200 Subject: [PATCH] Plugins: Fix plugins count in update all plugins button (#93126) * Plugins: Fix plugins count in update all plugins button * Plugins: Fix new updates filter * Plugins: Update tests --- .../plugins/admin/components/UpdateAllModal.tsx | 13 ++++++++----- public/app/features/plugins/admin/helpers.test.ts | 2 ++ public/app/features/plugins/admin/helpers.ts | 2 ++ public/app/features/plugins/admin/pages/Browse.tsx | 7 ++++--- public/app/features/plugins/admin/state/hooks.ts | 8 ++++++-- .../app/features/plugins/admin/state/selectors.ts | 10 ++++++++++ 6 files changed, 32 insertions(+), 10 deletions(-) diff --git a/public/app/features/plugins/admin/components/UpdateAllModal.tsx b/public/app/features/plugins/admin/components/UpdateAllModal.tsx index 6c247fa6da6..42f631fc451 100644 --- a/public/app/features/plugins/admin/components/UpdateAllModal.tsx +++ b/public/app/features/plugins/admin/components/UpdateAllModal.tsx @@ -160,11 +160,12 @@ const ModalBody = ({ plugins, inProgress, selectedPlugins, onCheckboxChange, err type Props = { isOpen: boolean; + isLoading: boolean; onDismiss: () => void; plugins: CatalogPlugin[]; }; -export const UpdateAllModal = ({ isOpen, onDismiss, plugins }: Props) => { +export const UpdateAllModal = ({ isOpen, onDismiss, isLoading, plugins }: Props) => { const install = useInstall(); const { error } = useInstallStatus(); const [errorMap, setErrorMap] = useState(new Map()); @@ -195,11 +196,11 @@ export const UpdateAllModal = ({ isOpen, onDismiss, plugins }: Props) => { // Initialize the component with all the plugins selected useEffect(() => { - if (selectedPlugins === undefined && plugins.length > 0) { + if (selectedPlugins === undefined && plugins.length > 0 && !isLoading) { const initialSelectedPlugins = new Set(plugins.map((plugin) => plugin.id)); setSelectedPlugins(initialSelectedPlugins); } - }, [plugins, selectedPlugins]); + }, [isLoading, plugins, selectedPlugins]); // Updates the component state on every error that comes from the store useEffect(() => { @@ -265,6 +266,8 @@ export const UpdateAllModal = ({ isOpen, onDismiss, plugins }: Props) => { } }; + const pluginsSelected = selectedPlugins?.size || 0; + return ( { } onConfirm={installsRemaining > 0 ? onConfirm : onDismissClick} onDismiss={onDismissClick} - disabled={selectedPlugins?.size === 0 || inProgress} + disabled={pluginsSelected === 0 || inProgress} confirmText={ installsRemaining > 0 - ? `${t('plugins.catalog.update-all.modal-confirmation', 'Update')} (${selectedPlugins?.size})` + ? `${t('plugins.catalog.update-all.modal-confirmation', 'Update')} (${pluginsSelected})` : t('plugins.catalog.update-all.modal-dismiss', 'Close') } /> diff --git a/public/app/features/plugins/admin/helpers.test.ts b/public/app/features/plugins/admin/helpers.test.ts index b2a80ec3ee0..95152175022 100644 --- a/public/app/features/plugins/admin/helpers.test.ts +++ b/public/app/features/plugins/admin/helpers.test.ts @@ -203,6 +203,7 @@ describe('Plugins/Helpers', () => { isInstalled: false, isDeprecated: false, isPublished: true, + latestVersion: '4.1.5', isManaged: false, isPreinstalled: { found: false, withVersion: false }, name: 'Zabbix', @@ -335,6 +336,7 @@ describe('Plugins/Helpers', () => { isEnterprise: false, isInstalled: true, isPublished: true, + latestVersion: '4.1.5', isDeprecated: false, isManaged: false, isPreinstalled: { found: false, withVersion: false }, diff --git a/public/app/features/plugins/admin/helpers.ts b/public/app/features/plugins/admin/helpers.ts index 8c8f83088a3..d2055b004b5 100644 --- a/public/app/features/plugins/admin/helpers.ts +++ b/public/app/features/plugins/admin/helpers.ts @@ -152,6 +152,7 @@ export function mapRemoteToCatalog(plugin: RemotePlugin, error?: PluginError): C error: error?.errorCode, angularDetected, isFullyInstalled: isDisabled, + latestVersion: plugin.version, }; } @@ -264,6 +265,7 @@ export function mapToCatalogPlugin(local?: LocalPlugin, remote?: RemotePlugin, e angularDetected: local?.angularDetected ?? remote?.angularDetected, isFullyInstalled: Boolean(local) || isDisabled, iam: local?.iam, + latestVersion: local?.latestVersion || remote?.version || '', }; } diff --git a/public/app/features/plugins/admin/pages/Browse.tsx b/public/app/features/plugins/admin/pages/Browse.tsx index 8a724d79784..5153498edb7 100644 --- a/public/app/features/plugins/admin/pages/Browse.tsx +++ b/public/app/features/plugins/admin/pages/Browse.tsx @@ -48,9 +48,9 @@ export default function Browse({ route }: GrafanaRouteComponentProps): ReactElem { value: 'has-update', label: 'New Updates' }, ]; - const updatablePlugins = useGetUpdatable(); + const { isLoading: areUpdatesLoading, updatablePlugins } = useGetUpdatable(); const [showUpdateModal, setShowUpdateModal] = useState(false); - const disableUpdateAllButton = updatablePlugins.length <= 0; + const disableUpdateAllButton = updatablePlugins.length <= 0 || areUpdatesLoading; const onSortByChange = (value: SelectableValue) => { history.push({ query: { sortBy: value.value } }); @@ -90,7 +90,7 @@ export default function Browse({ route }: GrafanaRouteComponentProps): ReactElem const updateAll = ( ); @@ -165,6 +165,7 @@ export default function Browse({ route }: GrafanaRouteComponentProps): ReactElem setShowUpdateModal(false)} plugins={updatablePlugins} /> diff --git a/public/app/features/plugins/admin/state/hooks.ts b/public/app/features/plugins/admin/state/hooks.ts index b0d6df6fb00..061645f45b5 100644 --- a/public/app/features/plugins/admin/state/hooks.ts +++ b/public/app/features/plugins/admin/state/hooks.ts @@ -35,8 +35,12 @@ export const useGetAll = (filters: PluginFilters, sortBy: Sorters = Sorters.name }; export const useGetUpdatable = () => { - const { plugins: installed } = useGetAll({ isInstalled: true }); - return installed.filter((p) => !p.isCore && !p.isManaged && !p.isProvisioned && p.hasUpdate && p.latestVersion); + const { isLoading } = useFetchStatus(); + const updatablePlugins = useSelector(selectPlugins({ isInstalled: true, hasUpdate: true })); + return { + isLoading, + updatablePlugins, + }; }; export const useGetSingle = (id: string): CatalogPlugin | undefined => { diff --git a/public/app/features/plugins/admin/state/selectors.ts b/public/app/features/plugins/admin/state/selectors.ts index 8ffb65ce52c..ce9875e7504 100644 --- a/public/app/features/plugins/admin/state/selectors.ts +++ b/public/app/features/plugins/admin/state/selectors.ts @@ -65,6 +65,16 @@ export const selectPlugins = (filters: PluginFilters) => 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) + ) { + return false; + } + return true; }); });