diff --git a/public/app/core/config.ts b/public/app/core/config.ts index eb2eee999ab..249a274ce5d 100644 --- a/public/app/core/config.ts +++ b/public/app/core/config.ts @@ -1,4 +1,5 @@ import _ from 'lodash'; +import { PanelPlugin } from 'app/types/plugins'; export interface BuildInfo { version: string; @@ -7,17 +8,6 @@ export interface BuildInfo { env: string; } -export interface PanelPlugin { - id: string; - name: string; - meta: any; - hideFromList: boolean; - module: string; - baseUrl: string; - info: any; - sort: number; -} - export class Settings { datasources: any; panels: PanelPlugin[]; diff --git a/public/app/features/dashboard/dashgrid/DashboardGrid.tsx b/public/app/features/dashboard/dashgrid/DashboardGrid.tsx index 30d97898900..77b55a2130f 100644 --- a/public/app/features/dashboard/dashgrid/DashboardGrid.tsx +++ b/public/app/features/dashboard/dashgrid/DashboardGrid.tsx @@ -171,6 +171,7 @@ export class DashboardGrid extends React.Component { renderPanels() { const panelElements = []; + console.log('render panels'); for (let panel of this.props.dashboard.panels) { const panelClasses = classNames({ panel: true, 'panel--fullscreen': panel.fullscreen }); diff --git a/public/app/features/dashboard/dashgrid/DashboardPanel.tsx b/public/app/features/dashboard/dashgrid/DashboardPanel.tsx index 0591d90cde2..781e7186a7e 100644 --- a/public/app/features/dashboard/dashgrid/DashboardPanel.tsx +++ b/public/app/features/dashboard/dashgrid/DashboardPanel.tsx @@ -5,8 +5,10 @@ import { DashboardModel } from '../dashboard_model'; import { getAngularLoader, AngularComponent } from 'app/core/services/angular_loader'; import { DashboardRow } from './DashboardRow'; import { AddPanelPanel } from './AddPanelPanel'; -import { importPluginModule, PluginExports } from 'app/features/plugins/plugin_loader'; +import { importPluginModule } from 'app/features/plugins/plugin_loader'; +import { PluginExports } from 'app/types/plugins'; import { PanelChrome } from './PanelChrome'; +import { PanelEditor } from './PanelEditor'; export interface Props { panel: PanelModel; @@ -29,15 +31,11 @@ export class DashboardPanel extends React.Component { this.specialPanels['row'] = this.renderRow.bind(this); this.specialPanels['add-panel'] = this.renderAddPanel.bind(this); + this.props.panel.events.on('panel-size-changed', this.triggerForceUpdate.bind(this)); + } - if (!this.isSpecial()) { - this.pluginInfo = config.panels[this.props.panel.type]; - - // load panel plugin - importPluginModule(this.pluginInfo.module).then(pluginExports => { - this.setState({ pluginExports: pluginExports }); - }); - } + triggerForceUpdate() { + this.forceUpdate(); } isSpecial() { @@ -52,8 +50,33 @@ export class DashboardPanel extends React.Component { return ; } + loadPlugin() { + if (this.isSpecial()) { + return; + } + + // handle plugin loading & changing of plugin type + if (!this.pluginInfo || this.pluginInfo.id !== this.props.panel.type) { + this.pluginInfo = config.panels[this.props.panel.type]; + + if (this.pluginInfo.exports) { + this.setState({ pluginExports: this.pluginInfo.exports }); + } else { + importPluginModule(this.pluginInfo.module).then(pluginExports => { + this.setState({ pluginExports: pluginExports }); + }); + } + } + } + + componentDidMount() { + this.loadPlugin(); + } + componentDidUpdate() { - // skip loading angular component if we have no element or we have already loaded it + this.loadPlugin(); + + // handle angular plugin loading if (!this.element || this.angularPanel) { return; } @@ -70,25 +93,43 @@ export class DashboardPanel extends React.Component { } } - render() { + renderReactPanel() { const { pluginExports } = this.state; + const containerClass = this.props.panel.isEditing ? 'panel-editor-container' : 'panel-height-helper'; + const panelWrapperClass = this.props.panel.isEditing ? 'panel-editor-container__panel' : 'panel-height-helper'; + + // this might look strange with these classes that change when edit, but + // I want to try to keep markup (parents) for panel the same in edit mode to avoide unmount / new mount of panel + // plugin component + return ( +
+
+ +
+ {this.props.panel.isEditing && ( +
+ +
+ )} +
+ ); + } + render() { if (this.isSpecial()) { return this.specialPanels[this.props.panel.type](); } - if (!pluginExports) { + if (!this.state.pluginExports) { return null; } - if (pluginExports.PanelComponent) { - return ( - - ); + if (this.state.pluginExports.PanelComponent) { + return this.renderReactPanel(); } // legacy angular rendering diff --git a/public/app/features/dashboard/dashgrid/PanelChrome.tsx b/public/app/features/dashboard/dashgrid/PanelChrome.tsx index b4584af63f8..eb0b34c3b06 100644 --- a/public/app/features/dashboard/dashgrid/PanelChrome.tsx +++ b/public/app/features/dashboard/dashgrid/PanelChrome.tsx @@ -2,23 +2,16 @@ import React, { ComponentClass } from 'react'; import $ from 'jquery'; import { PanelModel } from '../panel_model'; import { DashboardModel } from '../dashboard_model'; -import { GRID_CELL_HEIGHT, GRID_CELL_VMARGIN } from 'app/core/constants'; import { PanelHeader } from './PanelHeader'; -import { PanelEditor } from './PanelEditor'; import { DataPanel, PanelProps, DataPanelWrapper } from './DataPanel'; -const TITLE_HEIGHT = 27; -const PANEL_BORDER = 2; - export interface Props { panel: PanelModel; dashboard: DashboardModel; component: ComponentClass; } -interface State { - height: number; -} +interface State {} export class PanelChrome extends React.Component { panelComponent: DataPanel; @@ -26,20 +19,9 @@ export class PanelChrome extends React.Component { constructor(props) { super(props); - this.state = { - height: this.getPanelHeight(), - }; - this.panelComponent = DataPanelWrapper(this.props.component); - this.props.panel.events.on('panel-size-changed', this.onPanelSizeChanged); } - onPanelSizeChanged = () => { - this.setState({ - height: this.getPanelHeight(), - }); - }; - componentDidMount() { console.log('panel chrome mounted'); } @@ -48,31 +30,10 @@ export class PanelChrome extends React.Component { let PanelComponent = this.panelComponent; return ( -
-
- -
- {} -
-
- {this.props.panel.isEditing && } +
+ +
{}
); } - - getPanelHeight() { - const panel = this.props.panel; - let height = 0; - - if (panel.fullscreen) { - var docHeight = $(window).height(); - var editHeight = Math.floor(docHeight * 0.3); - var fullscreenHeight = Math.floor(docHeight * 0.8); - height = panel.isEditing ? editHeight : fullscreenHeight; - } else { - height = panel.gridPos.h * GRID_CELL_HEIGHT + (panel.gridPos.h - 1) * GRID_CELL_VMARGIN; - } - - return height - (PANEL_BORDER + TITLE_HEIGHT); - } } diff --git a/public/app/features/dashboard/dashgrid/PanelEditor.tsx b/public/app/features/dashboard/dashgrid/PanelEditor.tsx index 3ddf7d2f81b..1a8b1190928 100644 --- a/public/app/features/dashboard/dashgrid/PanelEditor.tsx +++ b/public/app/features/dashboard/dashgrid/PanelEditor.tsx @@ -5,7 +5,7 @@ import { DashboardModel } from '../dashboard_model'; import { store } from 'app/stores/store'; import { observer } from 'mobx-react'; import { QueriesTab } from './QueriesTab'; -import { PanelPlugin } from 'app/core/config'; +import { PanelPlugin } from 'app/types/plugins'; import { VizTypePicker } from './VizTypePicker'; interface PanelEditorProps { @@ -50,8 +50,8 @@ export class PanelEditor extends React.Component { } onVizTypeChanged = (plugin: PanelPlugin) => { - this.props.panel.type = plugin.id; - this.forceUpdate(); + console.log('changing type to ', plugin.id); + this.props.panel.changeType(plugin.id); }; onChangeTab = (tab: PanelEditorTab) => { diff --git a/public/app/features/dashboard/dashgrid/PanelHeader.tsx b/public/app/features/dashboard/dashgrid/PanelHeader.tsx index 97d41e15a0c..c4c169ceb88 100644 --- a/public/app/features/dashboard/dashgrid/PanelHeader.tsx +++ b/public/app/features/dashboard/dashgrid/PanelHeader.tsx @@ -21,6 +21,16 @@ export class PanelHeader extends React.Component { ); }; + onViewPanel = () => { + store.view.updateQuery( + { + panelId: this.props.panel.id, + fullscreen: true, + }, + false + ); + }; + render() { let isFullscreen = false; let isLoading = false; @@ -52,7 +62,9 @@ export class PanelHeader extends React.Component {
  • - asd + + View +
  • diff --git a/public/app/features/dashboard/dashgrid/VizTypePicker.tsx b/public/app/features/dashboard/dashgrid/VizTypePicker.tsx index 197892090b5..5a77ab6bfcf 100644 --- a/public/app/features/dashboard/dashgrid/VizTypePicker.tsx +++ b/public/app/features/dashboard/dashgrid/VizTypePicker.tsx @@ -1,6 +1,7 @@ import React, { PureComponent } from 'react'; import classNames from 'classnames'; -import config, { PanelPlugin } from 'app/core/config'; +import config from 'app/core/config'; +import { PanelPlugin } from 'app/types/plugins'; import _ from 'lodash'; interface Props { diff --git a/public/app/features/dashboard/panel_model.ts b/public/app/features/dashboard/panel_model.ts index 6ee49886a06..8c9270ad1ab 100644 --- a/public/app/features/dashboard/panel_model.ts +++ b/public/app/features/dashboard/panel_model.ts @@ -97,6 +97,11 @@ export class PanelModel { this.events.emit('panel-init-edit-mode'); } + changeType(newType: string) { + this.type = newType; + this.events.emit('panel-size-changed'); + } + destroy() { this.events.removeAllListeners(); } diff --git a/public/app/features/plugins/built_in_plugins.ts b/public/app/features/plugins/built_in_plugins.ts index 5f1f56b29bd..79f699d2291 100644 --- a/public/app/features/plugins/built_in_plugins.ts +++ b/public/app/features/plugins/built_in_plugins.ts @@ -12,6 +12,7 @@ import * as mssqlPlugin from 'app/plugins/datasource/mssql/module'; import * as textPanel from 'app/plugins/panel/text/module'; import * as text2Panel from 'app/plugins/panel/text2/module'; +import * as graph2Panel from 'app/plugins/panel/graph2/module'; import * as graphPanel from 'app/plugins/panel/graph/module'; import * as dashListPanel from 'app/plugins/panel/dashlist/module'; import * as pluginsListPanel from 'app/plugins/panel/pluginlist/module'; @@ -41,6 +42,7 @@ const builtInPlugins = { 'app/plugins/panel/text/module': textPanel, 'app/plugins/panel/text2/module': text2Panel, + 'app/plugins/panel/graph2/module': graph2Panel, 'app/plugins/panel/graph/module': graphPanel, 'app/plugins/panel/dashlist/module': dashListPanel, 'app/plugins/panel/pluginlist/module': pluginsListPanel, diff --git a/public/app/features/plugins/plugin_loader.ts b/public/app/features/plugins/plugin_loader.ts index ffcd36312fb..4564e5d4fd9 100644 --- a/public/app/features/plugins/plugin_loader.ts +++ b/public/app/features/plugins/plugin_loader.ts @@ -18,6 +18,7 @@ import config from 'app/core/config'; import TimeSeries from 'app/core/time_series2'; import TableModel from 'app/core/table_model'; import { coreModule, appEvents, contextSrv } from 'app/core/core'; +import { PluginExports } from 'app/types/plugins'; import * as datemath from 'app/core/utils/datemath'; import * as fileExport from 'app/core/utils/file_export'; import * as flatten from 'app/core/utils/flatten'; @@ -143,16 +144,6 @@ for (let flotDep of flotDeps) { exposeToPlugin(flotDep, { fakeDep: 1 }); } -export interface PluginExports { - PanelCtrl?; - any; - PanelComponent?: any; - Datasource?: any; - QueryCtrl?: any; - ConfigCtrl?: any; - AnnotationsQueryCtrl?: any; -} - export function importPluginModule(path: string): Promise { let builtIn = builtInPlugins[path]; if (builtIn) { diff --git a/public/app/plugins/panel/graph2/README.md b/public/app/plugins/panel/graph2/README.md new file mode 100644 index 00000000000..667ab51784a --- /dev/null +++ b/public/app/plugins/panel/graph2/README.md @@ -0,0 +1,5 @@ +# Text Panel - Native Plugin + +The Text Panel is **included** with Grafana. + +The Text Panel is a very simple panel that displays text. The source text is written in the Markdown syntax meaning you can format the text. Read [GitHub's Mastering Markdown](https://guides.github.com/features/mastering-markdown/) to learn more. diff --git a/public/app/plugins/panel/graph2/img/icn-graph-panel.svg b/public/app/plugins/panel/graph2/img/icn-graph-panel.svg new file mode 100644 index 00000000000..463b3d5770b --- /dev/null +++ b/public/app/plugins/panel/graph2/img/icn-graph-panel.svg @@ -0,0 +1,186 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/public/app/plugins/panel/graph2/module.tsx b/public/app/plugins/panel/graph2/module.tsx new file mode 100644 index 00000000000..7ae24bd7d40 --- /dev/null +++ b/public/app/plugins/panel/graph2/module.tsx @@ -0,0 +1,21 @@ +import React, { PureComponent } from 'react'; +import { PanelProps } from 'app/features/dashboard/dashgrid/DataPanel'; + +export class ReactTestPanel extends PureComponent { + constructor(props) { + super(props); + } + + render() { + const { data } = this.props; + let value = 0; + + if (data.length) { + value = data[0].value; + } + + return

    Graph Panel! {value}

    ; + } +} + +export { ReactTestPanel as PanelComponent }; diff --git a/public/app/plugins/panel/graph2/plugin.json b/public/app/plugins/panel/graph2/plugin.json new file mode 100644 index 00000000000..bc60d6ad2d7 --- /dev/null +++ b/public/app/plugins/panel/graph2/plugin.json @@ -0,0 +1,17 @@ +{ + "type": "panel", + "name": "React Graph", + "id": "graph2", + + "info": { + "author": { + "name": "Grafana Project", + "url": "https://grafana.com" + }, + "logos": { + "small": "img/icn-graph-panel.svg", + "large": "img/icn-graph-panel.svg" + } + } +} + diff --git a/public/app/plugins/panel/text2/module.tsx b/public/app/plugins/panel/text2/module.tsx index 019cf912340..20b6be4ca72 100644 --- a/public/app/plugins/panel/text2/module.tsx +++ b/public/app/plugins/panel/text2/module.tsx @@ -14,7 +14,7 @@ export class ReactTestPanel extends PureComponent { value = data[0].value; } - return

    I am a react value: {value}

    ; + return

    Text Panel {value}

    ; } } diff --git a/public/app/types/plugins.ts b/public/app/types/plugins.ts new file mode 100644 index 00000000000..9f0208463b9 --- /dev/null +++ b/public/app/types/plugins.ts @@ -0,0 +1,20 @@ +export interface PluginExports { + PanelCtrl?; + PanelComponent?: any; + Datasource?: any; + QueryCtrl?: any; + ConfigCtrl?: any; + AnnotationsQueryCtrl?: any; +} + +export interface PanelPlugin { + id: string; + name: string; + meta: any; + hideFromList: boolean; + module: string; + baseUrl: string; + info: any; + sort: number; + exports?: PluginExports; +} diff --git a/public/sass/pages/_dashboard.scss b/public/sass/pages/_dashboard.scss index 1ff4f2078e7..dad8bfa1c49 100644 --- a/public/sass/pages/_dashboard.scss +++ b/public/sass/pages/_dashboard.scss @@ -35,11 +35,20 @@ div.flot-text { height: 100%; } +.panel-editor-container__panel { + height: 35%; +} + +.panel-editor-container__editor { + height: 65%; +} + .panel-container { background-color: $panel-bg; border: $panel-border; position: relative; border-radius: 3px; + height: 100%; &.panel-transparent { background-color: transparent;