mirror of
https://github.com/grafana/grafana.git
synced 2025-09-26 04:24:13 +08:00
Plugins: better warning when plugins fail to load (#18671)
* better pluin feedback * add server side check for module.js
This commit is contained in:

committed by
Torkel Ödegaard

parent
c98c5c3c8e
commit
f7c55d3968
@ -216,6 +216,17 @@ func (scanner *PluginScanner) loadPluginJson(pluginJsonFilePath string) error {
|
|||||||
}
|
}
|
||||||
loader = reflect.New(reflect.TypeOf(pluginGoType)).Interface().(PluginLoader)
|
loader = reflect.New(reflect.TypeOf(pluginGoType)).Interface().(PluginLoader)
|
||||||
|
|
||||||
|
// External plugins need a module.js file for SystemJS to load
|
||||||
|
if !strings.HasPrefix(pluginJsonFilePath, setting.StaticRootPath) {
|
||||||
|
module := filepath.Join(filepath.Dir(pluginJsonFilePath), "module.js")
|
||||||
|
if _, err := os.Stat(module); os.IsNotExist(err) {
|
||||||
|
plog.Warn("Plugin missing module.js",
|
||||||
|
"name", pluginCommon.Name,
|
||||||
|
"warning", "Missing module.js, If you loaded this plugin from git, make sure to compile it.",
|
||||||
|
"path", module)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
reader.Seek(0, 0)
|
reader.Seek(0, 0)
|
||||||
return loader.Load(jsonParser, currentDir)
|
return loader.Load(jsonParser, currentDir)
|
||||||
}
|
}
|
||||||
|
@ -1,10 +1,10 @@
|
|||||||
import React, { FunctionComponent } from 'react';
|
import React, { FunctionComponent, ReactNode } from 'react';
|
||||||
import { AppNotificationSeverity } from 'app/types';
|
import { AppNotificationSeverity } from 'app/types';
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
title: string;
|
title: string;
|
||||||
icon?: string;
|
icon?: string;
|
||||||
text?: string;
|
body?: ReactNode;
|
||||||
severity: AppNotificationSeverity;
|
severity: AppNotificationSeverity;
|
||||||
onClose?: () => void;
|
onClose?: () => void;
|
||||||
}
|
}
|
||||||
@ -22,7 +22,7 @@ function getIconFromSeverity(severity: AppNotificationSeverity): string {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export const AlertBox: FunctionComponent<Props> = ({ title, icon, text, severity, onClose }) => {
|
export const AlertBox: FunctionComponent<Props> = ({ title, icon, body, severity, onClose }) => {
|
||||||
return (
|
return (
|
||||||
<div className={`alert alert-${severity}`}>
|
<div className={`alert alert-${severity}`}>
|
||||||
<div className="alert-icon">
|
<div className="alert-icon">
|
||||||
@ -30,7 +30,7 @@ export const AlertBox: FunctionComponent<Props> = ({ title, icon, text, severity
|
|||||||
</div>
|
</div>
|
||||||
<div className="alert-body">
|
<div className="alert-body">
|
||||||
<div className="alert-title">{title}</div>
|
<div className="alert-title">{title}</div>
|
||||||
{text && <div className="alert-text">{text}</div>}
|
{body && <div className="alert-text">{body}</div>}
|
||||||
</div>
|
</div>
|
||||||
{onClose && (
|
{onClose && (
|
||||||
<button type="button" className="alert-close" onClick={onClose}>
|
<button type="button" className="alert-close" onClick={onClose}>
|
||||||
|
@ -26,7 +26,7 @@ export default class AppNotificationItem extends Component<Props> {
|
|||||||
<AlertBox
|
<AlertBox
|
||||||
severity={appNotification.severity}
|
severity={appNotification.severity}
|
||||||
title={appNotification.title}
|
title={appNotification.title}
|
||||||
text={appNotification.text}
|
body={appNotification.text}
|
||||||
icon={appNotification.icon}
|
icon={appNotification.icon}
|
||||||
onClose={() => onClearNotification(appNotification.id)}
|
onClose={() => onClearNotification(appNotification.id)}
|
||||||
/>
|
/>
|
||||||
|
@ -245,7 +245,7 @@ export class DashboardPage extends PureComponent<Props, State> {
|
|||||||
<AlertBox
|
<AlertBox
|
||||||
severity={AppNotificationSeverity.Error}
|
severity={AppNotificationSeverity.Error}
|
||||||
title={initError.message}
|
title={initError.message}
|
||||||
text={getMessageFromError(initError.error)}
|
body={getMessageFromError(initError.error)}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
@ -1,19 +1,20 @@
|
|||||||
// Libraries
|
// Libraries
|
||||||
import _ from 'lodash';
|
import _ from 'lodash';
|
||||||
import React, { PureComponent } from 'react';
|
import React, { PureComponent, ReactNode } from 'react';
|
||||||
|
|
||||||
// Components
|
// Components
|
||||||
import { AlertBox } from 'app/core/components/AlertBox/AlertBox';
|
import { AlertBox } from 'app/core/components/AlertBox/AlertBox';
|
||||||
|
|
||||||
// Types
|
// Types
|
||||||
import { AppNotificationSeverity } from 'app/types';
|
import { AppNotificationSeverity } from 'app/types';
|
||||||
import { PanelProps, PanelPlugin, PluginType } from '@grafana/ui';
|
import { PanelProps, PanelPlugin, PluginType, PanelPluginMeta } from '@grafana/ui';
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
pluginId: string;
|
title: string;
|
||||||
|
text?: ReactNode;
|
||||||
}
|
}
|
||||||
|
|
||||||
class PanelPluginNotFound extends PureComponent<Props> {
|
class PanelPluginError extends PureComponent<Props> {
|
||||||
constructor(props: Props) {
|
constructor(props: Props) {
|
||||||
super(props);
|
super(props);
|
||||||
}
|
}
|
||||||
@ -28,16 +29,33 @@ class PanelPluginNotFound extends PureComponent<Props> {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div style={style}>
|
<div style={style}>
|
||||||
<AlertBox severity={AppNotificationSeverity.Error} title={`Panel plugin not found: ${this.props.pluginId}`} />
|
<AlertBox severity={AppNotificationSeverity.Error} {...this.props} />
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function getPanelPluginLoadError(meta: PanelPluginMeta, err: any): PanelPlugin {
|
||||||
|
const NotFound = class NotFound extends PureComponent<PanelProps> {
|
||||||
|
render() {
|
||||||
|
const text = (
|
||||||
|
<>
|
||||||
|
Check the server startup logs for more information. <br />
|
||||||
|
If this plugin was loaded from git, make sure it was compiled.
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
return <PanelPluginError title={`Error loading: ${meta.id}`} text={text} />;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
const plugin = new PanelPlugin(NotFound);
|
||||||
|
plugin.meta = meta;
|
||||||
|
return plugin;
|
||||||
|
}
|
||||||
|
|
||||||
export function getPanelPluginNotFound(id: string): PanelPlugin {
|
export function getPanelPluginNotFound(id: string): PanelPlugin {
|
||||||
const NotFound = class NotFound extends PureComponent<PanelProps> {
|
const NotFound = class NotFound extends PureComponent<PanelProps> {
|
||||||
render() {
|
render() {
|
||||||
return <PanelPluginNotFound pluginId={id} />;
|
return <PanelPluginError title={`Panel plugin not found: ${id}`} />;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
@ -199,7 +199,7 @@ export function importAppPlugin(meta: PluginMeta): Promise<AppPlugin> {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
import { getPanelPluginNotFound } from '../dashboard/dashgrid/PanelPluginNotFound';
|
import { getPanelPluginNotFound, getPanelPluginLoadError } from '../dashboard/dashgrid/PanelPluginError';
|
||||||
|
|
||||||
interface PanelCache {
|
interface PanelCache {
|
||||||
[key: string]: PanelPlugin;
|
[key: string]: PanelPlugin;
|
||||||
@ -233,7 +233,7 @@ export function importPanelPlugin(id: string): Promise<PanelPlugin> {
|
|||||||
})
|
})
|
||||||
.catch(err => {
|
.catch(err => {
|
||||||
// TODO, maybe a different error plugin
|
// TODO, maybe a different error plugin
|
||||||
console.log('Error loading panel plugin', err);
|
console.warn('Error loading panel plugin: ' + id, err);
|
||||||
return getPanelPluginNotFound(id);
|
return getPanelPluginLoadError(meta, err);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user