/usr/share/grafana/public/app/features/plugins/admin/components
import { useEffect, useMemo, useRef, useState } from 'react'; import { t } from '@grafana/i18n'; import { config, reportInteraction } from '@grafana/runtime'; import { ConfirmModal } from '@grafana/ui'; import { useInstall, useInstallStatus } from '../state/hooks'; import { CatalogPlugin, PluginStatus } from '../types'; import { UpdateModalBody } from './UpdateAllModalBody'; const PLUGINS_UPDATE_ALL_INTERACTION_EVENT_NAME = 'plugins_update_all_clicked'; type UpdateError = { id: string; message: string; }; type Props = { isOpen: boolean; isLoading: boolean; onDismiss: () => void; plugins: CatalogPlugin[]; }; export const UpdateAllModal = ({ isOpen, onDismiss, isLoading, plugins }: Props) => { const install = useInstall(); const { error } = useInstallStatus(); const [errorMap, setErrorMap] = useState(new Map<string, UpdateError>()); const [inProgress, setInProgress] = useState(false); const [selectedPlugins, setSelectedPlugins] = useState<Set<string>>(); const initialPluginsRef = useRef(plugins); const pluginsSet = useMemo(() => new Set(plugins.map((plugin) => plugin.id)), [plugins]); const installsRemaining = plugins.length; // Since the plugins come from the store and changes every time we update a plugin, // we need to keep track of the initial plugins. useEffect(() => { if (initialPluginsRef.current.length === 0) { initialPluginsRef.current = [...plugins]; } }, [plugins]); // Updates the component state on every plugins change, since the installation will change the store content useEffect(() => { if (inProgress) { selectedPlugins?.forEach((id) => { if (!pluginsSet.has(id)) { setSelectedPlugins((prevSelectedPlugins) => { const newSelectedPlugins = new Set(prevSelectedPlugins); newSelectedPlugins.delete(id); return newSelectedPlugins; }); } }); if (selectedPlugins?.size === 0) { setInProgress(false); } } }, [inProgress, pluginsSet, selectedPlugins]); // Initialize the component with all the plugins selected useEffect(() => { if (selectedPlugins === undefined && plugins.length > 0 && !isLoading) { const initialSelectedPlugins = new Set(plugins.map((plugin) => plugin.id)); setSelectedPlugins(initialSelectedPlugins); } }, [isLoading, plugins, selectedPlugins]); // Updates the component state on every error that comes from the store useEffect(() => { if (inProgress && error && !errorMap.has(error.id) && selectedPlugins?.has(error.id)) { setErrorMap((prevErrorMap) => { const newErrorMap = new Map(prevErrorMap); newErrorMap.set(error.id, error); return newErrorMap; }); setSelectedPlugins((prevSelectedPlugins) => { const newSelectedPlugins = new Set(prevSelectedPlugins); newSelectedPlugins.delete(error.id); return newSelectedPlugins; }); } }, [error, errorMap, inProgress, selectedPlugins]); const onConfirm = async () => { if (!inProgress) { reportInteraction(PLUGINS_UPDATE_ALL_INTERACTION_EVENT_NAME, { path: window.location.pathname, count: selectedPlugins?.size, creator_team: 'grafana_plugins_catalog', schema_version: '1.0.0', }); setInProgress(true); // in cloud the requests need to be sync if (config.pluginAdminExternalManageEnabled) { for (let plugin of plugins) { if (selectedPlugins?.has(plugin.id)) { await install(plugin.id, plugin.latestVersion, PluginStatus.UPDATE); } } } else { plugins.forEach((plugin) => { if (selectedPlugins?.has(plugin.id)) { install(plugin.id, plugin.latestVersion, PluginStatus.UPDATE); } }); } } }; const onDismissClick = () => { initialPluginsRef.current = []; setErrorMap(new Map()); setInProgress(false); setSelectedPlugins(undefined); onDismiss(); }; const onCheckboxChange = (id: string) => { setSelectedPlugins((prevSelectedPlugins) => { const newSelectedPlugins = new Set(prevSelectedPlugins); if (newSelectedPlugins.has(id)) { newSelectedPlugins.delete(id); } else { newSelectedPlugins.add(id); } return newSelectedPlugins; }); if (errorMap.has(id)) { setErrorMap((prevErrorMap) => { const newErrorMap = new Map(prevErrorMap); newErrorMap.delete(id); return newErrorMap; }); } }; const pluginsSelected = selectedPlugins?.size || 0; return ( <ConfirmModal isOpen={isOpen} title={t('plugins.catalog.update-all.modal-title', 'Update Plugins')} body={ <UpdateModalBody plugins={initialPluginsRef.current} pluginsNotInstalled={pluginsSet} inProgress={inProgress} errorMap={errorMap} onCheckboxChange={onCheckboxChange} selectedPlugins={selectedPlugins} /> } onConfirm={installsRemaining > 0 ? onConfirm : onDismissClick} onDismiss={onDismissClick} disabled={shouldDisableConfirm(inProgress, installsRemaining, pluginsSelected)} confirmText={getConfirmationText(installsRemaining, inProgress, pluginsSelected)} confirmButtonVariant="primary" /> ); }; function getConfirmationText(installsRemaining: number, inProgress: boolean, pluginsSelected: number) { if (inProgress) { return t('plugins.catalog.update-all.modal-in-progress', 'Updating...'); } if (installsRemaining > 0) { return t('plugins.catalog.update-all.modal-confirmation', 'Update') + ` (${pluginsSelected})`; } return t('plugins.catalog.update-all.modal-dismiss', 'Close'); } function shouldDisableConfirm(inProgress: boolean, installsRemaining: number, pluginsSelected: number) { if (inProgress) { return true; } if (installsRemaining > 0 && pluginsSelected === 0) { return true; } return false; } export default UpdateAllModal;
.
Edit
..
Edit
Badges
Edit
Changelog.tsx
Edit
ConnectionsTab.test.tsx
Edit
ConnectionsTab.tsx
Edit
GetStartedWithPlugin
Edit
HorizontalGroup.tsx
Edit
InstallControls
Edit
Loader.tsx
Edit
PluginActions.test.tsx
Edit
PluginActions.tsx
Edit
PluginDashboards.tsx
Edit
PluginDetailsBody.test.tsx
Edit
PluginDetailsBody.tsx
Edit
PluginDetailsDeprecatedWarning.tsx
Edit
PluginDetailsDisabledError.tsx
Edit
PluginDetailsHeaderDependencies.tsx
Edit
PluginDetailsHeaderSignature.tsx
Edit
PluginDetailsPage.test.tsx
Edit
PluginDetailsPage.tsx
Edit
PluginDetailsPanel.test.tsx
Edit
PluginDetailsPanel.tsx
Edit
PluginDetailsSignature.tsx
Edit
PluginList.test.tsx
Edit
PluginList.tsx
Edit
PluginListItem.test.tsx
Edit
PluginListItem.tsx
Edit
PluginListItemBadges.test.tsx
Edit
PluginListItemBadges.tsx
Edit
PluginLogo.tsx
Edit
PluginSignatureDetailsBadge.tsx
Edit
PluginSubtitle.test.tsx
Edit
PluginSubtitle.tsx
Edit
PluginUsage.tsx
Edit
RoadmapLinks.tsx
Edit
SearchField.tsx
Edit
UpdateAllButton.test.tsx
Edit
UpdateAllButton.tsx
Edit
UpdateAllModal.tsx
Edit
UpdateAllModalBody.tsx
Edit
VersionInstallButton.test.tsx
Edit
VersionInstallButton.tsx
Edit
VersionList.test.tsx
Edit
VersionList.tsx
Edit