Merge pull request #14038 from grafana/plugin-not-found
Plugin not found
This commit is contained in:
@@ -5,13 +5,14 @@ import { getAngularLoader, AngularComponent } from 'app/core/services/AngularLoa
|
||||
import { importPluginModule } from 'app/features/plugins/plugin_loader';
|
||||
|
||||
import { AddPanelPanel } from './AddPanelPanel';
|
||||
import { getPanelPluginNotFound } from './PanelPluginNotFound';
|
||||
import { DashboardRow } from './DashboardRow';
|
||||
import { PanelPlugin } from 'app/types/plugins';
|
||||
import { PanelChrome } from './PanelChrome';
|
||||
import { PanelEditor } from './PanelEditor';
|
||||
|
||||
import { PanelModel } from '../panel_model';
|
||||
import { DashboardModel } from '../dashboard_model';
|
||||
import { PanelPlugin } from 'app/types';
|
||||
|
||||
export interface Props {
|
||||
panel: PanelModel;
|
||||
@@ -70,7 +71,7 @@ export class DashboardPanel extends PureComponent<Props, State> {
|
||||
|
||||
// handle plugin loading & changing of plugin type
|
||||
if (!this.state.plugin || this.state.plugin.id !== panel.type) {
|
||||
const plugin = config.panels[panel.type];
|
||||
const plugin = config.panels[panel.type] || getPanelPluginNotFound(panel.type);
|
||||
|
||||
if (plugin.exports) {
|
||||
this.cleanUpAngularPanel();
|
||||
|
||||
@@ -81,7 +81,7 @@ export class EditorTabBody extends PureComponent<Props, State> {
|
||||
{toolbarItems.map(item => this.renderButton(item))}
|
||||
</div>
|
||||
<div className="panel-editor__scroll">
|
||||
<CustomScrollbar>
|
||||
<CustomScrollbar autoHide={false}>
|
||||
<div className="panel-editor__content">
|
||||
<FadeIn in={openView !== null} duration={200}>
|
||||
{openView && this.renderOpenView(openView)}
|
||||
|
||||
@@ -0,0 +1,64 @@
|
||||
import _ from 'lodash';
|
||||
import React, { PureComponent } from 'react';
|
||||
import { PanelPlugin, PanelProps } from 'app/types';
|
||||
|
||||
interface Props {
|
||||
pluginId: string;
|
||||
}
|
||||
|
||||
class PanelPluginNotFound extends PureComponent<Props> {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
}
|
||||
|
||||
render() {
|
||||
const style = {
|
||||
display: 'flex',
|
||||
'align-items': 'center',
|
||||
'text-align': 'center',
|
||||
height: '100%',
|
||||
};
|
||||
|
||||
return (
|
||||
<div style={style}>
|
||||
<div className="alert alert-error" style={{ margin: '0 auto' }}>
|
||||
Panel plugin with id {this.props.pluginId} could not be found
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export function getPanelPluginNotFound(id: string): PanelPlugin {
|
||||
const NotFound = class NotFound extends PureComponent<PanelProps> {
|
||||
render() {
|
||||
return <PanelPluginNotFound pluginId={id} />;
|
||||
}
|
||||
};
|
||||
|
||||
return {
|
||||
id: id,
|
||||
name: id,
|
||||
sort: 100,
|
||||
module: '',
|
||||
baseUrl: '',
|
||||
info: {
|
||||
author: {
|
||||
name: '',
|
||||
},
|
||||
description: '',
|
||||
links: [],
|
||||
logos: {
|
||||
large: '',
|
||||
small: '',
|
||||
},
|
||||
screenshots: [],
|
||||
updated: '',
|
||||
version: '',
|
||||
},
|
||||
|
||||
exports: {
|
||||
PanelComponent: NotFound,
|
||||
},
|
||||
};
|
||||
}
|
||||
@@ -3,6 +3,7 @@ import { AddPanelPanel } from './../dashgrid/AddPanelPanel';
|
||||
import { PanelModel } from '../panel_model';
|
||||
import { shallow } from 'enzyme';
|
||||
import config from '../../../core/config';
|
||||
import { getPanelPlugin } from 'app/features/plugins/__mocks__/pluginMocks';
|
||||
|
||||
jest.mock('app/core/store', () => ({
|
||||
get: key => {
|
||||
@@ -18,76 +19,11 @@ describe('AddPanelPanel', () => {
|
||||
|
||||
beforeEach(() => {
|
||||
config.panels = [
|
||||
{
|
||||
id: 'singlestat',
|
||||
hideFromList: false,
|
||||
name: 'Singlestat',
|
||||
sort: 2,
|
||||
module: '',
|
||||
baseUrl: '',
|
||||
meta: {},
|
||||
info: {
|
||||
logos: {
|
||||
small: '',
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'hidden',
|
||||
hideFromList: true,
|
||||
name: 'Hidden',
|
||||
sort: 100,
|
||||
meta: {},
|
||||
module: '',
|
||||
baseUrl: '',
|
||||
info: {
|
||||
logos: {
|
||||
small: '',
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'graph',
|
||||
hideFromList: false,
|
||||
name: 'Graph',
|
||||
sort: 1,
|
||||
meta: {},
|
||||
module: '',
|
||||
baseUrl: '',
|
||||
info: {
|
||||
logos: {
|
||||
small: '',
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'alexander_zabbix',
|
||||
hideFromList: false,
|
||||
name: 'Zabbix',
|
||||
sort: 100,
|
||||
meta: {},
|
||||
module: '',
|
||||
baseUrl: '',
|
||||
info: {
|
||||
logos: {
|
||||
small: '',
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'piechart',
|
||||
hideFromList: false,
|
||||
name: 'Piechart',
|
||||
sort: 100,
|
||||
meta: {},
|
||||
module: '',
|
||||
baseUrl: '',
|
||||
info: {
|
||||
logos: {
|
||||
small: '',
|
||||
},
|
||||
},
|
||||
},
|
||||
getPanelPlugin({ id: 'singlestat', sort: 2 }),
|
||||
getPanelPlugin({ id: 'hidden', sort: 100, hideFromList: true }),
|
||||
getPanelPlugin({ id: 'graph', sort: 1 }),
|
||||
getPanelPlugin({ id: 'alexander_zabbix', sort: 100 }),
|
||||
getPanelPlugin({ id: 'piechart', sort: 100 }),
|
||||
];
|
||||
|
||||
dashboardMock = { toggleRow: jest.fn() };
|
||||
@@ -97,16 +33,14 @@ describe('AddPanelPanel', () => {
|
||||
});
|
||||
|
||||
it('should fetch all panels sorted with core plugins first', () => {
|
||||
//console.log(wrapper.debug());
|
||||
//console.log(wrapper.find('.add-panel__item').get(0).props.title);
|
||||
expect(wrapper.find('.add-panel__item').get(1).props.title).toBe('Singlestat');
|
||||
expect(wrapper.find('.add-panel__item').get(4).props.title).toBe('Piechart');
|
||||
expect(wrapper.find('.add-panel__item').get(1).props.title).toBe('singlestat');
|
||||
expect(wrapper.find('.add-panel__item').get(4).props.title).toBe('piechart');
|
||||
});
|
||||
|
||||
it('should filter', () => {
|
||||
wrapper.find('input').simulate('change', { target: { value: 'p' } });
|
||||
|
||||
expect(wrapper.find('.add-panel__item').get(1).props.title).toBe('Piechart');
|
||||
expect(wrapper.find('.add-panel__item').get(0).props.title).toBe('Graph');
|
||||
expect(wrapper.find('.add-panel__item').get(1).props.title).toBe('piechart');
|
||||
expect(wrapper.find('.add-panel__item').get(0).props.title).toBe('graph');
|
||||
});
|
||||
});
|
||||
|
||||
+20
-4
@@ -65,7 +65,11 @@ exports[`Render should render alpha info text 1`] = `
|
||||
"large": "large/logo",
|
||||
"small": "small/logo",
|
||||
},
|
||||
"screenshots": "screenshot/1",
|
||||
"screenshots": Array [
|
||||
Object {
|
||||
"path": "screenshot",
|
||||
},
|
||||
],
|
||||
"updated": "2018-09-26",
|
||||
"version": "1",
|
||||
},
|
||||
@@ -158,7 +162,11 @@ exports[`Render should render beta info text 1`] = `
|
||||
"large": "large/logo",
|
||||
"small": "small/logo",
|
||||
},
|
||||
"screenshots": "screenshot/1",
|
||||
"screenshots": Array [
|
||||
Object {
|
||||
"path": "screenshot",
|
||||
},
|
||||
],
|
||||
"updated": "2018-09-26",
|
||||
"version": "1",
|
||||
},
|
||||
@@ -246,7 +254,11 @@ exports[`Render should render component 1`] = `
|
||||
"large": "large/logo",
|
||||
"small": "small/logo",
|
||||
},
|
||||
"screenshots": "screenshot/1",
|
||||
"screenshots": Array [
|
||||
Object {
|
||||
"path": "screenshot",
|
||||
},
|
||||
],
|
||||
"updated": "2018-09-26",
|
||||
"version": "1",
|
||||
},
|
||||
@@ -339,7 +351,11 @@ exports[`Render should render is ready only message 1`] = `
|
||||
"large": "large/logo",
|
||||
"small": "small/logo",
|
||||
},
|
||||
"screenshots": "screenshot/1",
|
||||
"screenshots": Array [
|
||||
Object {
|
||||
"path": "screenshot",
|
||||
},
|
||||
],
|
||||
"updated": "2018-09-26",
|
||||
"version": "1",
|
||||
},
|
||||
|
||||
@@ -78,7 +78,7 @@ export function getDataSourceLoadingNav(pageName: string): NavModel {
|
||||
large: '',
|
||||
small: '',
|
||||
},
|
||||
screenshots: '',
|
||||
screenshots: [],
|
||||
updated: '',
|
||||
version: '',
|
||||
},
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { Plugin } from 'app/types';
|
||||
import { Plugin, PanelPlugin } from 'app/types';
|
||||
|
||||
export const getMockPlugins = (amount: number): Plugin[] => {
|
||||
const plugins = [];
|
||||
@@ -17,7 +17,7 @@ export const getMockPlugins = (amount: number): Plugin[] => {
|
||||
description: 'pretty decent plugin',
|
||||
links: ['one link'],
|
||||
logos: { small: 'small/logo', large: 'large/logo' },
|
||||
screenshots: `screenshot/${i}`,
|
||||
screenshots: [{ path: `screenshot/${i}` }],
|
||||
updated: '2018-09-26',
|
||||
version: '1',
|
||||
},
|
||||
@@ -33,6 +33,31 @@ export const getMockPlugins = (amount: number): Plugin[] => {
|
||||
return plugins;
|
||||
};
|
||||
|
||||
export const getPanelPlugin = (options: { id: string; sort?: number; hideFromList?: boolean }): PanelPlugin => {
|
||||
return {
|
||||
id: options.id,
|
||||
name: options.id,
|
||||
sort: options.sort || 1,
|
||||
info: {
|
||||
author: {
|
||||
name: options.id + 'name',
|
||||
},
|
||||
description: '',
|
||||
links: [],
|
||||
logos: {
|
||||
large: '',
|
||||
small: '',
|
||||
},
|
||||
screenshots: [],
|
||||
updated: '',
|
||||
version: '',
|
||||
},
|
||||
hideFromList: options.hideFromList === true,
|
||||
module: '',
|
||||
baseUrl: '',
|
||||
};
|
||||
};
|
||||
|
||||
export const getMockPlugin = () => {
|
||||
return {
|
||||
defaultNavUrl: 'some/url',
|
||||
@@ -47,7 +72,7 @@ export const getMockPlugin = () => {
|
||||
description: 'pretty decent plugin',
|
||||
links: ['one link'],
|
||||
logos: { small: 'small/logo', large: 'large/logo' },
|
||||
screenshots: 'screenshot/1',
|
||||
screenshots: [{ path: `screenshot` }],
|
||||
updated: '2018-09-26',
|
||||
version: '1',
|
||||
},
|
||||
|
||||
@@ -28,7 +28,11 @@ exports[`Render should render component 1`] = `
|
||||
"large": "large/logo",
|
||||
"small": "small/logo",
|
||||
},
|
||||
"screenshots": "screenshot/0",
|
||||
"screenshots": Array [
|
||||
Object {
|
||||
"path": "screenshot/0",
|
||||
},
|
||||
],
|
||||
"updated": "2018-09-26",
|
||||
"version": "1",
|
||||
},
|
||||
@@ -62,7 +66,11 @@ exports[`Render should render component 1`] = `
|
||||
"large": "large/logo",
|
||||
"small": "small/logo",
|
||||
},
|
||||
"screenshots": "screenshot/1",
|
||||
"screenshots": Array [
|
||||
Object {
|
||||
"path": "screenshot/1",
|
||||
},
|
||||
],
|
||||
"updated": "2018-09-26",
|
||||
"version": "1",
|
||||
},
|
||||
@@ -96,7 +104,11 @@ exports[`Render should render component 1`] = `
|
||||
"large": "large/logo",
|
||||
"small": "small/logo",
|
||||
},
|
||||
"screenshots": "screenshot/2",
|
||||
"screenshots": Array [
|
||||
Object {
|
||||
"path": "screenshot/2",
|
||||
},
|
||||
],
|
||||
"updated": "2018-09-26",
|
||||
"version": "1",
|
||||
},
|
||||
@@ -130,7 +142,11 @@ exports[`Render should render component 1`] = `
|
||||
"large": "large/logo",
|
||||
"small": "small/logo",
|
||||
},
|
||||
"screenshots": "screenshot/3",
|
||||
"screenshots": Array [
|
||||
Object {
|
||||
"path": "screenshot/3",
|
||||
},
|
||||
],
|
||||
"updated": "2018-09-26",
|
||||
"version": "1",
|
||||
},
|
||||
@@ -164,7 +180,11 @@ exports[`Render should render component 1`] = `
|
||||
"large": "large/logo",
|
||||
"small": "small/logo",
|
||||
},
|
||||
"screenshots": "screenshot/4",
|
||||
"screenshots": Array [
|
||||
Object {
|
||||
"path": "screenshot/4",
|
||||
},
|
||||
],
|
||||
"updated": "2018-09-26",
|
||||
"version": "1",
|
||||
},
|
||||
@@ -198,7 +218,11 @@ exports[`Render should render component 1`] = `
|
||||
"large": "large/logo",
|
||||
"small": "small/logo",
|
||||
},
|
||||
"screenshots": "screenshot/5",
|
||||
"screenshots": Array [
|
||||
Object {
|
||||
"path": "screenshot/5",
|
||||
},
|
||||
],
|
||||
"updated": "2018-09-26",
|
||||
"version": "1",
|
||||
},
|
||||
|
||||
@@ -5,8 +5,6 @@ import config from 'app/core/config';
|
||||
import coreModule from 'app/core/core_module';
|
||||
import { importPluginModule } from './plugin_loader';
|
||||
|
||||
import { UnknownPanelCtrl } from 'app/plugins/panel/unknown/module';
|
||||
|
||||
/** @ngInject */
|
||||
function pluginDirectiveLoader($compile, datasourceSrv, $rootScope, $q, $http, $templateCache, $timeout) {
|
||||
function getTemplate(component) {
|
||||
@@ -69,7 +67,7 @@ function pluginDirectiveLoader($compile, datasourceSrv, $rootScope, $q, $http, $
|
||||
};
|
||||
|
||||
const panelInfo = config.panels[scope.panel.type];
|
||||
let panelCtrlPromise = Promise.resolve(UnknownPanelCtrl);
|
||||
let panelCtrlPromise = Promise.resolve(null);
|
||||
if (panelInfo) {
|
||||
panelCtrlPromise = importPluginModule(panelInfo.module).then(panelModule => {
|
||||
return panelModule.PanelCtrl;
|
||||
|
||||
@@ -1,5 +0,0 @@
|
||||
<div class="text-center" style="padding-top: 2rem">
|
||||
Unknown panel type: <strong>{{ctrl.panel.type}}</strong>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -1,10 +0,0 @@
|
||||
import { PanelCtrl } from 'app/features/panel/panel_ctrl';
|
||||
|
||||
export class UnknownPanelCtrl extends PanelCtrl {
|
||||
static templateUrl = 'public/app/plugins/panel/unknown/module.html';
|
||||
|
||||
/** @ngInject */
|
||||
constructor($scope, $injector) {
|
||||
super($scope, $injector);
|
||||
}
|
||||
}
|
||||
@@ -21,7 +21,7 @@ import {
|
||||
DataQueryOptions,
|
||||
} from './series';
|
||||
import { PanelProps, PanelOptionsProps } from './panel';
|
||||
import { PluginDashboard, PluginMeta, Plugin, PluginsState } from './plugins';
|
||||
import { PluginDashboard, PluginMeta, Plugin, PanelPlugin, PluginsState } from './plugins';
|
||||
import { Organization, OrganizationPreferences, OrganizationState } from './organization';
|
||||
import {
|
||||
AppNotification,
|
||||
@@ -69,6 +69,7 @@ export {
|
||||
UsersState,
|
||||
TimeRange,
|
||||
LoadingState,
|
||||
PanelPlugin,
|
||||
PanelProps,
|
||||
PanelOptionsProps,
|
||||
TimeSeries,
|
||||
|
||||
@@ -12,14 +12,13 @@ export interface PluginExports {
|
||||
// Panel plugin
|
||||
PanelCtrl?;
|
||||
PanelComponent?: ComponentClass<PanelProps>;
|
||||
PanelOptionsComponent: ComponentClass<PanelOptionsProps>;
|
||||
PanelOptionsComponent?: ComponentClass<PanelOptionsProps>;
|
||||
}
|
||||
|
||||
export interface PanelPlugin {
|
||||
id: string;
|
||||
name: string;
|
||||
meta: any;
|
||||
hideFromList: boolean;
|
||||
hideFromList?: boolean;
|
||||
module: string;
|
||||
baseUrl: string;
|
||||
info: any;
|
||||
@@ -49,7 +48,7 @@ export interface PluginInclude {
|
||||
export interface PluginMetaInfo {
|
||||
author: {
|
||||
name: string;
|
||||
url: string;
|
||||
url?: string;
|
||||
};
|
||||
description: string;
|
||||
links: string[];
|
||||
@@ -57,7 +56,7 @@ export interface PluginMetaInfo {
|
||||
large: string;
|
||||
small: string;
|
||||
};
|
||||
screenshots: string;
|
||||
screenshots: any[];
|
||||
updated: string;
|
||||
version: string;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user