2021-07-21 12:44:43 -05:00
|
|
|
import React from 'react';
|
2021-06-04 12:20:06 -05:00
|
|
|
import { css, cx } from '@emotion/css';
|
2021-07-20 08:20:24 -05:00
|
|
|
import { satisfies } from 'semver';
|
2021-05-12 14:07:37 -05:00
|
|
|
|
|
|
|
import { config } from '@grafana/runtime';
|
2021-05-27 05:45:06 -05:00
|
|
|
import { Button, HorizontalGroup, Icon, LinkButton, useStyles2 } from '@grafana/ui';
|
2021-05-31 11:42:36 -05:00
|
|
|
import { AppEvents, GrafanaTheme2 } from '@grafana/data';
|
2021-05-12 14:07:37 -05:00
|
|
|
|
2021-07-08 10:50:42 -05:00
|
|
|
import appEvents from 'app/core/app_events';
|
2021-07-21 12:44:43 -05:00
|
|
|
import { CatalogPluginDetails, ActionTypes } from '../types';
|
2021-07-20 08:20:24 -05:00
|
|
|
import { api } from '../api';
|
2021-05-31 11:42:36 -05:00
|
|
|
import { isGrafanaAdmin } from '../helpers';
|
2021-05-12 14:07:37 -05:00
|
|
|
|
|
|
|
interface Props {
|
2021-07-20 08:20:24 -05:00
|
|
|
plugin: CatalogPluginDetails;
|
2021-07-21 12:44:43 -05:00
|
|
|
isInflight: boolean;
|
|
|
|
hasUpdate: boolean;
|
|
|
|
hasInstalledPanel: boolean;
|
|
|
|
isInstalled: boolean;
|
|
|
|
dispatch: React.Dispatch<any>;
|
2021-05-12 14:07:37 -05:00
|
|
|
}
|
|
|
|
|
2021-07-21 12:44:43 -05:00
|
|
|
export const InstallControls = ({ plugin, isInflight, hasUpdate, isInstalled, hasInstalledPanel, dispatch }: Props) => {
|
2021-05-27 05:45:06 -05:00
|
|
|
const isExternallyManaged = config.pluginAdminExternalManageEnabled;
|
2021-07-20 08:20:24 -05:00
|
|
|
const externalManageLink = getExternalManageLink(plugin);
|
2021-05-12 14:07:37 -05:00
|
|
|
|
|
|
|
const styles = useStyles2(getStyles);
|
|
|
|
|
2021-07-20 08:20:24 -05:00
|
|
|
if (!plugin) {
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
|
2021-05-12 14:07:37 -05:00
|
|
|
const onInstall = async () => {
|
2021-07-21 12:44:43 -05:00
|
|
|
dispatch({ type: ActionTypes.INFLIGHT });
|
2021-05-12 14:07:37 -05:00
|
|
|
try {
|
2021-07-20 08:20:24 -05:00
|
|
|
await api.installPlugin(plugin.id, plugin.version);
|
|
|
|
appEvents.emit(AppEvents.alertSuccess, [`Installed ${plugin.name}`]);
|
2021-07-21 12:44:43 -05:00
|
|
|
dispatch({ type: ActionTypes.INSTALLED, payload: plugin.type === 'panel' });
|
2021-05-12 14:07:37 -05:00
|
|
|
} catch (error) {
|
2021-07-21 12:44:43 -05:00
|
|
|
dispatch({ type: ActionTypes.ERROR, payload: { error } });
|
2021-05-12 14:07:37 -05:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
const onUninstall = async () => {
|
2021-07-21 12:44:43 -05:00
|
|
|
dispatch({ type: ActionTypes.INFLIGHT });
|
2021-05-12 14:07:37 -05:00
|
|
|
try {
|
2021-07-20 08:20:24 -05:00
|
|
|
await api.uninstallPlugin(plugin.id);
|
|
|
|
appEvents.emit(AppEvents.alertSuccess, [`Uninstalled ${plugin.name}`]);
|
2021-07-21 12:44:43 -05:00
|
|
|
dispatch({ type: ActionTypes.UNINSTALLED });
|
2021-05-12 14:07:37 -05:00
|
|
|
} catch (error) {
|
2021-07-21 12:44:43 -05:00
|
|
|
dispatch({ type: ActionTypes.ERROR, payload: error });
|
2021-05-12 14:07:37 -05:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
const onUpdate = async () => {
|
2021-07-21 12:44:43 -05:00
|
|
|
dispatch({ type: ActionTypes.INFLIGHT });
|
2021-05-12 14:07:37 -05:00
|
|
|
try {
|
2021-07-20 08:20:24 -05:00
|
|
|
await api.installPlugin(plugin.id, plugin.version);
|
|
|
|
appEvents.emit(AppEvents.alertSuccess, [`Updated ${plugin.name}`]);
|
2021-07-21 12:44:43 -05:00
|
|
|
dispatch({ type: ActionTypes.UPDATED });
|
2021-05-12 14:07:37 -05:00
|
|
|
} catch (error) {
|
2021-07-21 12:44:43 -05:00
|
|
|
dispatch({ type: ActionTypes.ERROR, payload: error });
|
2021-05-12 14:07:37 -05:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2021-07-20 08:20:24 -05:00
|
|
|
const grafanaDependency = plugin.grafanaDependency;
|
2021-05-12 14:07:37 -05:00
|
|
|
const unsupportedGrafanaVersion = grafanaDependency
|
|
|
|
? !satisfies(config.buildInfo.version, grafanaDependency, {
|
|
|
|
// needed for when running against master
|
|
|
|
includePrerelease: true,
|
|
|
|
})
|
|
|
|
: false;
|
|
|
|
|
2021-07-20 08:20:24 -05:00
|
|
|
const isDevelopmentBuild = Boolean(plugin.isDev);
|
|
|
|
const isEnterprise = plugin.isEnterprise;
|
|
|
|
const isCore = plugin.isCore;
|
2021-05-31 11:42:36 -05:00
|
|
|
const hasPermission = isGrafanaAdmin();
|
2021-05-12 14:07:37 -05:00
|
|
|
|
2021-07-13 11:22:36 -05:00
|
|
|
if (isCore) {
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
|
2021-07-12 15:18:39 -05:00
|
|
|
if (isEnterprise && !config.licenseInfo?.hasValidLicense) {
|
2021-05-12 14:07:37 -05:00
|
|
|
return (
|
|
|
|
<div className={styles.message}>
|
|
|
|
Marketplace doesn't support installing Enterprise plugins yet. Stay tuned!
|
|
|
|
</div>
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (isDevelopmentBuild) {
|
|
|
|
return (
|
|
|
|
<div className={styles.message}>This is a development build of the plugin and can't be uninstalled.</div>
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2021-08-04 04:49:05 -05:00
|
|
|
if (!hasPermission) {
|
|
|
|
const message = `You need server admin privileges to ${isInstalled ? 'uninstall' : 'install'} this plugin.`;
|
|
|
|
return <div className={styles.message}>{message}</div>;
|
|
|
|
}
|
|
|
|
|
2021-05-12 14:07:37 -05:00
|
|
|
if (isInstalled) {
|
|
|
|
return (
|
|
|
|
<HorizontalGroup height="auto">
|
2021-07-21 12:44:43 -05:00
|
|
|
{hasUpdate &&
|
2021-05-27 05:45:06 -05:00
|
|
|
(isExternallyManaged ? (
|
2021-05-31 11:42:36 -05:00
|
|
|
<LinkButton href={externalManageLink} target="_blank" rel="noopener noreferrer">
|
2021-05-27 05:45:06 -05:00
|
|
|
{'Update via grafana.com'}
|
|
|
|
</LinkButton>
|
|
|
|
) : (
|
2021-07-21 12:44:43 -05:00
|
|
|
<Button disabled={isInflight || !hasPermission} onClick={onUpdate}>
|
|
|
|
{isInflight ? 'Updating' : 'Update'}
|
2021-05-27 05:45:06 -05:00
|
|
|
</Button>
|
|
|
|
))}
|
|
|
|
|
|
|
|
{isExternallyManaged ? (
|
2021-05-31 11:42:36 -05:00
|
|
|
<LinkButton variant="destructive" href={externalManageLink} target="_blank" rel="noopener noreferrer">
|
2021-05-27 05:45:06 -05:00
|
|
|
{'Uninstall via grafana.com'}
|
|
|
|
</LinkButton>
|
|
|
|
) : (
|
2021-05-31 11:42:36 -05:00
|
|
|
<>
|
2021-07-21 12:44:43 -05:00
|
|
|
<Button variant="destructive" disabled={isInflight || !hasPermission} onClick={onUninstall}>
|
|
|
|
{isInflight && !hasUpdate ? 'Uninstalling' : 'Uninstall'}
|
2021-05-31 11:42:36 -05:00
|
|
|
</Button>
|
2021-06-04 12:20:06 -05:00
|
|
|
{hasInstalledPanel && (
|
|
|
|
<div className={cx(styles.message, styles.messageMargin)}>
|
|
|
|
Please refresh your browser window before using this plugin.
|
|
|
|
</div>
|
|
|
|
)}
|
2021-05-31 11:42:36 -05:00
|
|
|
</>
|
2021-05-12 14:07:37 -05:00
|
|
|
)}
|
|
|
|
</HorizontalGroup>
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (unsupportedGrafanaVersion) {
|
|
|
|
return (
|
|
|
|
<div className={styles.message}>
|
|
|
|
<Icon name="exclamation-triangle" />
|
|
|
|
This plugin doesn't support your version of Grafana.
|
|
|
|
</div>
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
return (
|
|
|
|
<HorizontalGroup height="auto">
|
2021-05-27 05:45:06 -05:00
|
|
|
{isExternallyManaged ? (
|
2021-05-31 11:42:36 -05:00
|
|
|
<LinkButton href={externalManageLink} target="_blank" rel="noopener noreferrer">
|
2021-05-27 05:45:06 -05:00
|
|
|
{'Install via grafana.com'}
|
|
|
|
</LinkButton>
|
|
|
|
) : (
|
2021-05-31 11:42:36 -05:00
|
|
|
<>
|
2021-07-21 12:44:43 -05:00
|
|
|
<Button disabled={isInflight || !hasPermission} onClick={onInstall}>
|
|
|
|
{isInflight ? 'Installing' : 'Install'}
|
2021-05-31 11:42:36 -05:00
|
|
|
</Button>
|
|
|
|
</>
|
2021-05-27 05:45:06 -05:00
|
|
|
)}
|
2021-05-12 14:07:37 -05:00
|
|
|
</HorizontalGroup>
|
|
|
|
);
|
|
|
|
};
|
|
|
|
|
2021-07-20 08:20:24 -05:00
|
|
|
function getExternalManageLink(plugin: CatalogPluginDetails): string {
|
|
|
|
return `https://grafana.com/grafana/plugins/${plugin.id}`;
|
2021-05-27 05:45:06 -05:00
|
|
|
}
|
|
|
|
|
2021-05-12 14:07:37 -05:00
|
|
|
export const getStyles = (theme: GrafanaTheme2) => {
|
|
|
|
return {
|
|
|
|
message: css`
|
|
|
|
color: ${theme.colors.text.secondary};
|
|
|
|
`,
|
2021-06-04 12:20:06 -05:00
|
|
|
messageMargin: css`
|
|
|
|
margin-left: ${theme.spacing()};
|
|
|
|
`,
|
2021-05-12 14:07:37 -05:00
|
|
|
};
|
|
|
|
};
|