Commit 76128323 by Torkel Ödegaard

react panels: working on changing type

parent e052e165
import _ from 'lodash'; import _ from 'lodash';
import { PanelPlugin } from 'app/types/plugins';
export interface BuildInfo { export interface BuildInfo {
version: string; version: string;
...@@ -7,17 +8,6 @@ export interface BuildInfo { ...@@ -7,17 +8,6 @@ export interface BuildInfo {
env: string; env: string;
} }
export interface PanelPlugin {
id: string;
name: string;
meta: any;
hideFromList: boolean;
module: string;
baseUrl: string;
info: any;
sort: number;
}
export class Settings { export class Settings {
datasources: any; datasources: any;
panels: PanelPlugin[]; panels: PanelPlugin[];
......
...@@ -171,6 +171,7 @@ export class DashboardGrid extends React.Component<DashboardGridProps, any> { ...@@ -171,6 +171,7 @@ export class DashboardGrid extends React.Component<DashboardGridProps, any> {
renderPanels() { renderPanels() {
const panelElements = []; const panelElements = [];
console.log('render panels');
for (let panel of this.props.dashboard.panels) { for (let panel of this.props.dashboard.panels) {
const panelClasses = classNames({ panel: true, 'panel--fullscreen': panel.fullscreen }); const panelClasses = classNames({ panel: true, 'panel--fullscreen': panel.fullscreen });
......
...@@ -5,8 +5,10 @@ import { DashboardModel } from '../dashboard_model'; ...@@ -5,8 +5,10 @@ import { DashboardModel } from '../dashboard_model';
import { getAngularLoader, AngularComponent } from 'app/core/services/angular_loader'; import { getAngularLoader, AngularComponent } from 'app/core/services/angular_loader';
import { DashboardRow } from './DashboardRow'; import { DashboardRow } from './DashboardRow';
import { AddPanelPanel } from './AddPanelPanel'; 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 { PanelChrome } from './PanelChrome';
import { PanelEditor } from './PanelEditor';
export interface Props { export interface Props {
panel: PanelModel; panel: PanelModel;
...@@ -29,15 +31,11 @@ export class DashboardPanel extends React.Component<Props, State> { ...@@ -29,15 +31,11 @@ export class DashboardPanel extends React.Component<Props, State> {
this.specialPanels['row'] = this.renderRow.bind(this); this.specialPanels['row'] = this.renderRow.bind(this);
this.specialPanels['add-panel'] = this.renderAddPanel.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() { isSpecial() {
...@@ -52,8 +50,33 @@ export class DashboardPanel extends React.Component<Props, State> { ...@@ -52,8 +50,33 @@ export class DashboardPanel extends React.Component<Props, State> {
return <AddPanelPanel panel={this.props.panel} dashboard={this.props.dashboard} />; return <AddPanelPanel panel={this.props.panel} dashboard={this.props.dashboard} />;
} }
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() { 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) { if (!this.element || this.angularPanel) {
return; return;
} }
...@@ -70,27 +93,45 @@ export class DashboardPanel extends React.Component<Props, State> { ...@@ -70,27 +93,45 @@ export class DashboardPanel extends React.Component<Props, State> {
} }
} }
render() { renderReactPanel() {
const { pluginExports } = this.state; 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';
if (this.isSpecial()) { // this might look strange with these classes that change when edit, but
return this.specialPanels[this.props.panel.type](); // I want to try to keep markup (parents) for panel the same in edit mode to avoide unmount / new mount of panel
} // plugin component
if (!pluginExports) {
return null;
}
if (pluginExports.PanelComponent) {
return ( return (
<div className={containerClass}>
<div className={panelWrapperClass}>
<PanelChrome <PanelChrome
component={pluginExports.PanelComponent} component={pluginExports.PanelComponent}
panel={this.props.panel} panel={this.props.panel}
dashboard={this.props.dashboard} dashboard={this.props.dashboard}
/> />
</div>
{this.props.panel.isEditing && (
<div className="panel-editor-container__editor">
<PanelEditor panel={this.props.panel} dashboard={this.props.dashboard} />
</div>
)}
</div>
); );
} }
render() {
if (this.isSpecial()) {
return this.specialPanels[this.props.panel.type]();
}
if (!this.state.pluginExports) {
return null;
}
if (this.state.pluginExports.PanelComponent) {
return this.renderReactPanel();
}
// legacy angular rendering // legacy angular rendering
return <div ref={element => (this.element = element)} className="panel-height-helper" />; return <div ref={element => (this.element = element)} className="panel-height-helper" />;
} }
......
...@@ -2,23 +2,16 @@ import React, { ComponentClass } from 'react'; ...@@ -2,23 +2,16 @@ import React, { ComponentClass } from 'react';
import $ from 'jquery'; import $ from 'jquery';
import { PanelModel } from '../panel_model'; import { PanelModel } from '../panel_model';
import { DashboardModel } from '../dashboard_model'; import { DashboardModel } from '../dashboard_model';
import { GRID_CELL_HEIGHT, GRID_CELL_VMARGIN } from 'app/core/constants';
import { PanelHeader } from './PanelHeader'; import { PanelHeader } from './PanelHeader';
import { PanelEditor } from './PanelEditor';
import { DataPanel, PanelProps, DataPanelWrapper } from './DataPanel'; import { DataPanel, PanelProps, DataPanelWrapper } from './DataPanel';
const TITLE_HEIGHT = 27;
const PANEL_BORDER = 2;
export interface Props { export interface Props {
panel: PanelModel; panel: PanelModel;
dashboard: DashboardModel; dashboard: DashboardModel;
component: ComponentClass<PanelProps>; component: ComponentClass<PanelProps>;
} }
interface State { interface State {}
height: number;
}
export class PanelChrome extends React.Component<Props, State> { export class PanelChrome extends React.Component<Props, State> {
panelComponent: DataPanel; panelComponent: DataPanel;
...@@ -26,20 +19,9 @@ export class PanelChrome extends React.Component<Props, State> { ...@@ -26,20 +19,9 @@ export class PanelChrome extends React.Component<Props, State> {
constructor(props) { constructor(props) {
super(props); super(props);
this.state = {
height: this.getPanelHeight(),
};
this.panelComponent = DataPanelWrapper(this.props.component); this.panelComponent = DataPanelWrapper(this.props.component);
this.props.panel.events.on('panel-size-changed', this.onPanelSizeChanged);
} }
onPanelSizeChanged = () => {
this.setState({
height: this.getPanelHeight(),
});
};
componentDidMount() { componentDidMount() {
console.log('panel chrome mounted'); console.log('panel chrome mounted');
} }
...@@ -48,31 +30,10 @@ export class PanelChrome extends React.Component<Props, State> { ...@@ -48,31 +30,10 @@ export class PanelChrome extends React.Component<Props, State> {
let PanelComponent = this.panelComponent; let PanelComponent = this.panelComponent;
return ( return (
<div className="panel-editor-container">
<div className="panel-container"> <div className="panel-container">
<PanelHeader panel={this.props.panel} dashboard={this.props.dashboard} /> <PanelHeader panel={this.props.panel} dashboard={this.props.dashboard} />
<div className="panel-content" style={{ height: this.state.height }}> <div className="panel-content">{<PanelComponent type={'test'} queries={[]} isVisible={true} />}</div>
{<PanelComponent type={'test'} queries={[]} isVisible={true} />}
</div>
</div>
{this.props.panel.isEditing && <PanelEditor panel={this.props.panel} dashboard={this.props.dashboard} />}
</div> </div>
); );
} }
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);
}
} }
...@@ -5,7 +5,7 @@ import { DashboardModel } from '../dashboard_model'; ...@@ -5,7 +5,7 @@ import { DashboardModel } from '../dashboard_model';
import { store } from 'app/stores/store'; import { store } from 'app/stores/store';
import { observer } from 'mobx-react'; import { observer } from 'mobx-react';
import { QueriesTab } from './QueriesTab'; import { QueriesTab } from './QueriesTab';
import { PanelPlugin } from 'app/core/config'; import { PanelPlugin } from 'app/types/plugins';
import { VizTypePicker } from './VizTypePicker'; import { VizTypePicker } from './VizTypePicker';
interface PanelEditorProps { interface PanelEditorProps {
...@@ -50,8 +50,8 @@ export class PanelEditor extends React.Component<PanelEditorProps, any> { ...@@ -50,8 +50,8 @@ export class PanelEditor extends React.Component<PanelEditorProps, any> {
} }
onVizTypeChanged = (plugin: PanelPlugin) => { onVizTypeChanged = (plugin: PanelPlugin) => {
this.props.panel.type = plugin.id; console.log('changing type to ', plugin.id);
this.forceUpdate(); this.props.panel.changeType(plugin.id);
}; };
onChangeTab = (tab: PanelEditorTab) => { onChangeTab = (tab: PanelEditorTab) => {
......
...@@ -21,6 +21,16 @@ export class PanelHeader extends React.Component<PanelHeaderProps, any> { ...@@ -21,6 +21,16 @@ export class PanelHeader extends React.Component<PanelHeaderProps, any> {
); );
}; };
onViewPanel = () => {
store.view.updateQuery(
{
panelId: this.props.panel.id,
fullscreen: true,
},
false
);
};
render() { render() {
let isFullscreen = false; let isFullscreen = false;
let isLoading = false; let isLoading = false;
...@@ -52,7 +62,9 @@ export class PanelHeader extends React.Component<PanelHeaderProps, any> { ...@@ -52,7 +62,9 @@ export class PanelHeader extends React.Component<PanelHeaderProps, any> {
</a> </a>
</li> </li>
<li> <li>
<a href="asd">asd</a> <a onClick={this.onViewPanel}>
<i className="fa fa-fw fa-eye" /> View
</a>
</li> </li>
</ul> </ul>
</span> </span>
......
import React, { PureComponent } from 'react'; import React, { PureComponent } from 'react';
import classNames from 'classnames'; 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'; import _ from 'lodash';
interface Props { interface Props {
......
...@@ -97,6 +97,11 @@ export class PanelModel { ...@@ -97,6 +97,11 @@ export class PanelModel {
this.events.emit('panel-init-edit-mode'); this.events.emit('panel-init-edit-mode');
} }
changeType(newType: string) {
this.type = newType;
this.events.emit('panel-size-changed');
}
destroy() { destroy() {
this.events.removeAllListeners(); this.events.removeAllListeners();
} }
......
...@@ -12,6 +12,7 @@ import * as mssqlPlugin from 'app/plugins/datasource/mssql/module'; ...@@ -12,6 +12,7 @@ import * as mssqlPlugin from 'app/plugins/datasource/mssql/module';
import * as textPanel from 'app/plugins/panel/text/module'; import * as textPanel from 'app/plugins/panel/text/module';
import * as text2Panel from 'app/plugins/panel/text2/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 graphPanel from 'app/plugins/panel/graph/module';
import * as dashListPanel from 'app/plugins/panel/dashlist/module'; import * as dashListPanel from 'app/plugins/panel/dashlist/module';
import * as pluginsListPanel from 'app/plugins/panel/pluginlist/module'; import * as pluginsListPanel from 'app/plugins/panel/pluginlist/module';
...@@ -41,6 +42,7 @@ const builtInPlugins = { ...@@ -41,6 +42,7 @@ const builtInPlugins = {
'app/plugins/panel/text/module': textPanel, 'app/plugins/panel/text/module': textPanel,
'app/plugins/panel/text2/module': text2Panel, 'app/plugins/panel/text2/module': text2Panel,
'app/plugins/panel/graph2/module': graph2Panel,
'app/plugins/panel/graph/module': graphPanel, 'app/plugins/panel/graph/module': graphPanel,
'app/plugins/panel/dashlist/module': dashListPanel, 'app/plugins/panel/dashlist/module': dashListPanel,
'app/plugins/panel/pluginlist/module': pluginsListPanel, 'app/plugins/panel/pluginlist/module': pluginsListPanel,
......
...@@ -18,6 +18,7 @@ import config from 'app/core/config'; ...@@ -18,6 +18,7 @@ import config from 'app/core/config';
import TimeSeries from 'app/core/time_series2'; import TimeSeries from 'app/core/time_series2';
import TableModel from 'app/core/table_model'; import TableModel from 'app/core/table_model';
import { coreModule, appEvents, contextSrv } from 'app/core/core'; import { coreModule, appEvents, contextSrv } from 'app/core/core';
import { PluginExports } from 'app/types/plugins';
import * as datemath from 'app/core/utils/datemath'; import * as datemath from 'app/core/utils/datemath';
import * as fileExport from 'app/core/utils/file_export'; import * as fileExport from 'app/core/utils/file_export';
import * as flatten from 'app/core/utils/flatten'; import * as flatten from 'app/core/utils/flatten';
...@@ -143,16 +144,6 @@ for (let flotDep of flotDeps) { ...@@ -143,16 +144,6 @@ for (let flotDep of flotDeps) {
exposeToPlugin(flotDep, { fakeDep: 1 }); 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<PluginExports> { export function importPluginModule(path: string): Promise<PluginExports> {
let builtIn = builtInPlugins[path]; let builtIn = builtInPlugins[path];
if (builtIn) { if (builtIn) {
......
# 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.
import React, { PureComponent } from 'react';
import { PanelProps } from 'app/features/dashboard/dashgrid/DataPanel';
export class ReactTestPanel extends PureComponent<PanelProps> {
constructor(props) {
super(props);
}
render() {
const { data } = this.props;
let value = 0;
if (data.length) {
value = data[0].value;
}
return <h2>Graph Panel! {value}</h2>;
}
}
export { ReactTestPanel as PanelComponent };
{
"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"
}
}
}
...@@ -14,7 +14,7 @@ export class ReactTestPanel extends PureComponent<PanelProps> { ...@@ -14,7 +14,7 @@ export class ReactTestPanel extends PureComponent<PanelProps> {
value = data[0].value; value = data[0].value;
} }
return <h2>I am a react value: {value}</h2>; return <h2>Text Panel {value}</h2>;
} }
} }
......
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;
}
...@@ -35,11 +35,20 @@ div.flot-text { ...@@ -35,11 +35,20 @@ div.flot-text {
height: 100%; height: 100%;
} }
.panel-editor-container__panel {
height: 35%;
}
.panel-editor-container__editor {
height: 65%;
}
.panel-container { .panel-container {
background-color: $panel-bg; background-color: $panel-bg;
border: $panel-border; border: $panel-border;
position: relative; position: relative;
border-radius: 3px; border-radius: 3px;
height: 100%;
&.panel-transparent { &.panel-transparent {
background-color: transparent; background-color: transparent;
......
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