Commit 6b2a47f2 by Torkel Ödegaard Committed by GitHub

Merge pull request #14038 from grafana/plugin-not-found

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