import React, { useState } from 'react'; import { css, cx } from '@emotion/css'; import { gt, satisfies } from 'semver'; import { config } from '@grafana/runtime'; import { Button, HorizontalGroup, Icon, LinkButton, useStyles2 } from '@grafana/ui'; import { AppEvents, GrafanaTheme2 } from '@grafana/data'; import { LocalPlugin, Plugin } from '../types'; import { api } from '../api'; // This isn't exported in the sdk yet // @ts-ignore import appEvents from 'app/core/app_events'; import { isGrafanaAdmin } from '../helpers'; interface Props { localPlugin?: LocalPlugin; remotePlugin: Plugin; } export const InstallControls = ({ localPlugin, remotePlugin }: Props) => { const [loading, setLoading] = useState(false); const [isInstalled, setIsInstalled] = useState(Boolean(localPlugin)); const [shouldUpdate, setShouldUpdate] = useState( remotePlugin?.version && localPlugin?.info.version && gt(remotePlugin?.version!, localPlugin?.info.version!) ); const [hasInstalledPanel, setHasInstalledPanel] = useState(false); const isExternallyManaged = config.pluginAdminExternalManageEnabled; const externalManageLink = getExternalManageLink(remotePlugin); const styles = useStyles2(getStyles); const onInstall = async () => { setLoading(true); try { await api.installPlugin(remotePlugin.slug, remotePlugin.version); appEvents.emit(AppEvents.alertSuccess, [`Installed ${remotePlugin?.name}`]); setLoading(false); setIsInstalled(true); setHasInstalledPanel(remotePlugin.typeCode === 'panel'); } catch (error) { setLoading(false); } }; const onUninstall = async () => { setLoading(true); try { await api.uninstallPlugin(remotePlugin.slug); appEvents.emit(AppEvents.alertSuccess, [`Uninstalled ${remotePlugin?.name}`]); setLoading(false); setIsInstalled(false); } catch (error) { setLoading(false); } }; const onUpdate = async () => { setLoading(true); try { await api.installPlugin(remotePlugin.slug, remotePlugin.version); appEvents.emit(AppEvents.alertSuccess, [`Updated ${remotePlugin?.name}`]); setLoading(false); setShouldUpdate(false); } catch (error) { setLoading(false); } }; const grafanaDependency = remotePlugin?.json?.dependencies?.grafanaDependency; const unsupportedGrafanaVersion = grafanaDependency ? !satisfies(config.buildInfo.version, grafanaDependency, { // needed for when running against master includePrerelease: true, }) : false; const isDevelopmentBuild = Boolean(localPlugin?.dev); const isEnterprise = remotePlugin?.status === 'enterprise'; const hasPermission = isGrafanaAdmin(); if (isEnterprise && !config.licenseInfo?.hasValidLicense) { return (
Marketplace doesn't support installing Enterprise plugins yet. Stay tuned!
); } if (isDevelopmentBuild) { return (
This is a development build of the plugin and can't be uninstalled.
); } if (isInstalled) { return ( {shouldUpdate && (isExternallyManaged ? ( {'Update via grafana.com'} ) : ( ))} {isExternallyManaged ? ( {'Uninstall via grafana.com'} ) : ( <> {hasInstalledPanel && (
Please refresh your browser window before using this plugin.
)} {!hasPermission &&
You need admin privileges to manage this plugin.
} )}
); } if (unsupportedGrafanaVersion) { return (
 This plugin doesn't support your version of Grafana.
); } return ( {isExternallyManaged ? ( {'Install via grafana.com'} ) : ( <> {!hasPermission &&
You need admin privileges to install this plugin.
} )}
); }; function getExternalManageLink(plugin: Plugin): string { return `https://grafana.com/grafana/plugins/${plugin.slug}`; } export const getStyles = (theme: GrafanaTheme2) => { return { message: css` color: ${theme.colors.text.secondary}; `, messageMargin: css` margin-left: ${theme.spacing()}; `, readme: css` margin: ${theme.spacing(3)} 0; & img { max-width: 100%; } h1, h2, h3 { margin-top: ${theme.spacing(3)}; margin-bottom: ${theme.spacing(2)}; } li { margin-left: ${theme.spacing(2)}; & > p { margin: ${theme.spacing()} 0; } } `, }; };