Commit 76128323 by Torkel Ödegaard

react panels: working on changing type

parent e052e165
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[];
......
......@@ -171,6 +171,7 @@ export class DashboardGrid extends React.Component<DashboardGridProps, any> {
renderPanels() {
const panelElements = [];
console.log('render panels');
for (let panel of this.props.dashboard.panels) {
const panelClasses = classNames({ panel: true, 'panel--fullscreen': panel.fullscreen });
......
......@@ -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<Props, State> {
this.specialPanels['row'] = this.renderRow.bind(this);
this.specialPanels['add-panel'] = this.renderAddPanel.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 });
});
this.props.panel.events.on('panel-size-changed', this.triggerForceUpdate.bind(this));
}
triggerForceUpdate() {
this.forceUpdate();
}
isSpecial() {
......@@ -52,8 +50,33 @@ export class DashboardPanel extends React.Component<Props, State> {
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() {
// 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,27 +93,45 @@ export class DashboardPanel extends React.Component<Props, State> {
}
}
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';
if (this.isSpecial()) {
return this.specialPanels[this.props.panel.type]();
}
if (!pluginExports) {
return null;
}
if (pluginExports.PanelComponent) {
// 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 (
<div className={containerClass}>
<div className={panelWrapperClass}>
<PanelChrome
component={pluginExports.PanelComponent}
panel={this.props.panel}
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
return <div ref={element => (this.element = element)} className="panel-height-helper" />;
}
......
......@@ -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<PanelProps>;
}
interface State {
height: number;
}
interface State {}
export class PanelChrome extends React.Component<Props, State> {
panelComponent: DataPanel;
......@@ -26,20 +19,9 @@ export class PanelChrome extends React.Component<Props, State> {
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<Props, State> {
let PanelComponent = this.panelComponent;
return (
<div className="panel-editor-container">
<div className="panel-container">
<PanelHeader panel={this.props.panel} dashboard={this.props.dashboard} />
<div className="panel-content" style={{ height: this.state.height }}>
{<PanelComponent type={'test'} queries={[]} isVisible={true} />}
</div>
</div>
{this.props.panel.isEditing && <PanelEditor panel={this.props.panel} dashboard={this.props.dashboard} />}
<div className="panel-content">{<PanelComponent type={'test'} queries={[]} isVisible={true} />}</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';
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<PanelEditorProps, any> {
}
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) => {
......
......@@ -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() {
let isFullscreen = false;
let isLoading = false;
......@@ -52,7 +62,9 @@ export class PanelHeader extends React.Component<PanelHeaderProps, any> {
</a>
</li>
<li>
<a href="asd">asd</a>
<a onClick={this.onViewPanel}>
<i className="fa fa-fw fa-eye" /> View
</a>
</li>
</ul>
</span>
......
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 {
......
......@@ -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();
}
......
......@@ -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,
......
......@@ -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<PluginExports> {
let builtIn = builtInPlugins[path];
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> {
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 {
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;
......
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