From 230606146d6db5afaad28ab591188c2cd1a248ff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Torkel=20=C3=96degaard?= Date: Tue, 19 Jun 2018 21:25:57 +0200 Subject: [PATCH 1/2] wip: react panel minor progrss --- public/app/core/components/grafana_app.ts | 5 +++ public/app/core/services/angular_loader.ts | 42 +++++++++++++++++++ public/app/features/dashboard/all.ts | 1 - .../app/features/dashboard/dashboard_ctrl.ts | 10 +---- .../dashboard/dashgrid/DashboardGrid.tsx | 34 +++++++-------- .../dashgrid/DashboardGridDirective.ts | 4 +- .../dashboard/dashgrid/DashboardPanel.tsx | 18 ++++---- .../dashboard/dashgrid/PanelChrome.tsx | 7 +--- .../dashboard/dashgrid/PanelContainer.ts | 7 ---- .../dashboard/dashgrid/PanelEditor.tsx | 36 +++++++++++++++- .../dashboard/dashgrid/PanelLoader.ts | 31 -------------- .../app/features/plugins/plugin_component.ts | 1 + public/app/partials/dashboard.html | 3 +- public/sass/components/_tabbed_view.scss | 9 ++++ 14 files changed, 121 insertions(+), 87 deletions(-) create mode 100644 public/app/core/services/angular_loader.ts delete mode 100644 public/app/features/dashboard/dashgrid/PanelContainer.ts delete mode 100644 public/app/features/dashboard/dashgrid/PanelLoader.ts diff --git a/public/app/core/components/grafana_app.ts b/public/app/core/components/grafana_app.ts index fd2e32db3a7..a888e2973e9 100644 --- a/public/app/core/components/grafana_app.ts +++ b/public/app/core/components/grafana_app.ts @@ -10,6 +10,7 @@ import { createStore } from 'app/stores/store'; import colors from 'app/core/utils/colors'; import { BackendSrv } from 'app/core/services/backend_srv'; import { DatasourceSrv } from 'app/features/plugins/datasource_srv'; +import { AngularLoader, setAngularLoader } from 'app/core/services/angular_loader'; export class GrafanaCtrl { /** @ngInject */ @@ -22,8 +23,12 @@ export class GrafanaCtrl { contextSrv, bridgeSrv, backendSrv: BackendSrv, + angularLoader: AngularLoader, datasourceSrv: DatasourceSrv ) { + // make angular loader service available to react components + setAngularLoader(angularLoader); + // create store with env services createStore({ backendSrv, datasourceSrv }); $scope.init = function() { diff --git a/public/app/core/services/angular_loader.ts b/public/app/core/services/angular_loader.ts new file mode 100644 index 00000000000..36c49be6240 --- /dev/null +++ b/public/app/core/services/angular_loader.ts @@ -0,0 +1,42 @@ +import angular from 'angular'; +import coreModule from 'app/core/core_module'; +import _ from 'lodash'; + +export interface AngularComponent { + destroy(); +} + +export class AngularLoader { + /** @ngInject */ + constructor(private $compile, private $rootScope) {} + + load(elem, scopeProps, template): AngularComponent { + var scope = this.$rootScope.$new(); + + _.assign(scope, scopeProps); + + const compiledElem = this.$compile(template)(scope); + const rootNode = angular.element(elem); + rootNode.append(compiledElem); + + return { + destroy: () => { + scope.$destroy(); + compiledElem.remove(); + }, + }; + } +} + +coreModule.service('angularLoader', AngularLoader); + +let angularLoaderInstance: AngularLoader; + +export function setAngularLoader(pl: AngularLoader) { + angularLoaderInstance = pl; +} + +// away to access it from react +export function getAngularLoader(): AngularLoader { + return angularLoaderInstance; +} diff --git a/public/app/features/dashboard/all.ts b/public/app/features/dashboard/all.ts index a8f491f3ddd..6898b51d095 100644 --- a/public/app/features/dashboard/all.ts +++ b/public/app/features/dashboard/all.ts @@ -22,7 +22,6 @@ import './export_data/export_data_modal'; import './ad_hoc_filters'; import './repeat_option/repeat_option'; import './dashgrid/DashboardGridDirective'; -import './dashgrid/PanelLoader'; import './dashgrid/RowOptions'; import './folder_picker/folder_picker'; import './move_to_folder_modal/move_to_folder'; diff --git a/public/app/features/dashboard/dashboard_ctrl.ts b/public/app/features/dashboard/dashboard_ctrl.ts index 94d0b18f157..a7d1ff23ea4 100644 --- a/public/app/features/dashboard/dashboard_ctrl.ts +++ b/public/app/features/dashboard/dashboard_ctrl.ts @@ -1,11 +1,10 @@ import config from 'app/core/config'; import coreModule from 'app/core/core_module'; -import { PanelContainer } from './dashgrid/PanelContainer'; import { DashboardModel } from './dashboard_model'; import { PanelModel } from './panel_model'; -export class DashboardCtrl implements PanelContainer { +export class DashboardCtrl { dashboard: DashboardModel; dashboardViewState: any; loadedFallbackDashboard: boolean; @@ -22,8 +21,7 @@ export class DashboardCtrl implements PanelContainer { private dashboardSrv, private unsavedChangesSrv, private dashboardViewStateSrv, - public playlistSrv, - private panelLoader + public playlistSrv ) { // temp hack due to way dashboards are loaded // can't use controllerAs on route yet @@ -119,10 +117,6 @@ export class DashboardCtrl implements PanelContainer { return this.dashboard; } - getPanelLoader() { - return this.panelLoader; - } - timezoneChanged() { this.$rootScope.$broadcast('refresh'); } diff --git a/public/app/features/dashboard/dashgrid/DashboardGrid.tsx b/public/app/features/dashboard/dashgrid/DashboardGrid.tsx index 653ed046e8e..9ee6cdbe1f8 100644 --- a/public/app/features/dashboard/dashgrid/DashboardGrid.tsx +++ b/public/app/features/dashboard/dashgrid/DashboardGrid.tsx @@ -3,7 +3,6 @@ import ReactGridLayout from 'react-grid-layout'; import { GRID_CELL_HEIGHT, GRID_CELL_VMARGIN, GRID_COLUMN_COUNT } from 'app/core/constants'; import { DashboardPanel } from './DashboardPanel'; import { DashboardModel } from '../dashboard_model'; -import { PanelContainer } from './PanelContainer'; import { PanelModel } from '../panel_model'; import classNames from 'classnames'; import sizeMe from 'react-sizeme'; @@ -60,18 +59,15 @@ function GridWrapper({ const SizedReactLayoutGrid = sizeMe({ monitorWidth: true })(GridWrapper); export interface DashboardGridProps { - getPanelContainer: () => PanelContainer; + dashboard: DashboardModel; } export class DashboardGrid extends React.Component { gridToPanelMap: any; - panelContainer: PanelContainer; - dashboard: DashboardModel; panelMap: { [id: string]: PanelModel }; constructor(props) { super(props); - this.panelContainer = this.props.getPanelContainer(); this.onLayoutChange = this.onLayoutChange.bind(this); this.onResize = this.onResize.bind(this); this.onResizeStop = this.onResizeStop.bind(this); @@ -81,20 +77,20 @@ export class DashboardGrid extends React.Component { this.state = { animated: false }; // subscribe to dashboard events - this.dashboard = this.panelContainer.getDashboard(); - this.dashboard.on('panel-added', this.triggerForceUpdate.bind(this)); - this.dashboard.on('panel-removed', this.triggerForceUpdate.bind(this)); - this.dashboard.on('repeats-processed', this.triggerForceUpdate.bind(this)); - this.dashboard.on('view-mode-changed', this.onViewModeChanged.bind(this)); - this.dashboard.on('row-collapsed', this.triggerForceUpdate.bind(this)); - this.dashboard.on('row-expanded', this.triggerForceUpdate.bind(this)); + let dashboard = this.props.dashboard; + dashboard.on('panel-added', this.triggerForceUpdate.bind(this)); + dashboard.on('panel-removed', this.triggerForceUpdate.bind(this)); + dashboard.on('repeats-processed', this.triggerForceUpdate.bind(this)); + dashboard.on('view-mode-changed', this.onViewModeChanged.bind(this)); + dashboard.on('row-collapsed', this.triggerForceUpdate.bind(this)); + dashboard.on('row-expanded', this.triggerForceUpdate.bind(this)); } buildLayout() { const layout = []; this.panelMap = {}; - for (let panel of this.dashboard.panels) { + for (let panel of this.props.dashboard.panels) { let stringId = panel.id.toString(); this.panelMap[stringId] = panel; @@ -129,7 +125,7 @@ export class DashboardGrid extends React.Component { this.panelMap[newPos.i].updateGridPos(newPos); } - this.dashboard.sortPanelsByGridPos(); + this.props.dashboard.sortPanelsByGridPos(); } triggerForceUpdate() { @@ -137,7 +133,7 @@ export class DashboardGrid extends React.Component { } onWidthChange() { - for (const panel of this.dashboard.panels) { + for (const panel of this.props.dashboard.panels) { panel.resizeDone(); } } @@ -176,11 +172,11 @@ export class DashboardGrid extends React.Component { renderPanels() { const panelElements = []; - for (let panel of this.dashboard.panels) { + for (let panel of this.props.dashboard.panels) { const panelClasses = classNames({ panel: true, 'panel--fullscreen': panel.fullscreen }); panelElements.push(
- +
); } @@ -193,8 +189,8 @@ export class DashboardGrid extends React.Component { { element: any; - attachedPanel: AttachedPanel; + angularPanel: AngularComponent; pluginInfo: any; pluginExports: any; specialPanels = {}; @@ -55,17 +53,19 @@ export class DashboardPanel extends React.Component { componentDidUpdate() { // skip loading angular component if we have no element // or we have already loaded it - if (!this.element || this.attachedPanel) { + if (!this.element || this.angularPanel) { return; } - const loader = this.props.panelContainer.getPanelLoader(); - this.attachedPanel = loader.load(this.element, this.props.panel, this.props.dashboard); + let loader = getAngularLoader(); + var template = ''; + let scopeProps = { panel: this.props.panel, dashboard: this.props.dashboard }; + this.angularPanel = loader.load(this.element, scopeProps, template); } componentWillUnmount() { - if (this.attachedPanel) { - this.attachedPanel.destroy(); + if (this.angularPanel) { + this.angularPanel.destroy(); } } diff --git a/public/app/features/dashboard/dashgrid/PanelChrome.tsx b/public/app/features/dashboard/dashgrid/PanelChrome.tsx index a0a1dff7c16..bf5f8044a37 100644 --- a/public/app/features/dashboard/dashgrid/PanelChrome.tsx +++ b/public/app/features/dashboard/dashgrid/PanelChrome.tsx @@ -32,7 +32,6 @@ export class PanelChrome extends React.Component { }; let PanelComponent = this.props.component; - console.log('PanelChrome render'); return (
@@ -42,9 +41,7 @@ export class PanelChrome extends React.Component { {}
-
- {this.props.panel.isEditing && } -
+ {this.props.panel.isEditing && } ); } @@ -55,7 +52,7 @@ export class PanelChrome extends React.Component { if (panel.fullscreen) { var docHeight = $(window).height(); - var editHeight = Math.floor(docHeight * 0.4); + var editHeight = Math.floor(docHeight * 0.3); var fullscreenHeight = Math.floor(docHeight * 0.8); height = panel.isEditing ? editHeight : fullscreenHeight; } else { diff --git a/public/app/features/dashboard/dashgrid/PanelContainer.ts b/public/app/features/dashboard/dashgrid/PanelContainer.ts deleted file mode 100644 index 87f3235a176..00000000000 --- a/public/app/features/dashboard/dashgrid/PanelContainer.ts +++ /dev/null @@ -1,7 +0,0 @@ -import { DashboardModel } from '../dashboard_model'; -import { PanelLoader } from './PanelLoader'; - -export interface PanelContainer { - getPanelLoader(): PanelLoader; - getDashboard(): DashboardModel; -} diff --git a/public/app/features/dashboard/dashgrid/PanelEditor.tsx b/public/app/features/dashboard/dashgrid/PanelEditor.tsx index 646a0b65ecd..fc7967d087c 100644 --- a/public/app/features/dashboard/dashgrid/PanelEditor.tsx +++ b/public/app/features/dashboard/dashgrid/PanelEditor.tsx @@ -1,6 +1,7 @@ import React from 'react'; import { PanelModel } from '../panel_model'; import { DashboardModel } from '../dashboard_model'; +import { getAngularLoader, AngularComponent } from 'app/core/services/angular_loader'; interface PanelEditorProps { panel: PanelModel; @@ -8,9 +9,38 @@ interface PanelEditorProps { } export class PanelEditor extends React.Component { + queryElement: any; + queryComp: AngularComponent; + + constructor(props) { + super(props); + } + + componentDidMount() { + if (!this.queryElement) { + return; + } + + let loader = getAngularLoader(); + var template = ''; + let scopeProps = { + ctrl: { + panel: this.props.panel, + dashboard: this.props.dashboard, + panelCtrl: { + panel: this.props.panel, + dashboard: this.props.dashboard, + }, + }, + target: {}, + }; + + this.queryComp = loader.load(this.queryElement, scopeProps, template); + } + render() { return ( -
+
  • @@ -26,7 +56,9 @@ export class PanelEditor extends React.Component {
-
testing
+
+
(this.queryElement = element)} className="panel-height-helper" /> +
); } diff --git a/public/app/features/dashboard/dashgrid/PanelLoader.ts b/public/app/features/dashboard/dashgrid/PanelLoader.ts deleted file mode 100644 index beda30bdff7..00000000000 --- a/public/app/features/dashboard/dashgrid/PanelLoader.ts +++ /dev/null @@ -1,31 +0,0 @@ -import angular from 'angular'; -import coreModule from 'app/core/core_module'; - -export interface AttachedPanel { - destroy(); -} - -export class PanelLoader { - /** @ngInject */ - constructor(private $compile, private $rootScope) {} - - load(elem, panel, dashboard): AttachedPanel { - var template = ''; - var panelScope = this.$rootScope.$new(); - panelScope.panel = panel; - panelScope.dashboard = dashboard; - - const compiledElem = this.$compile(template)(panelScope); - const rootNode = angular.element(elem); - rootNode.append(compiledElem); - - return { - destroy: () => { - panelScope.$destroy(); - compiledElem.remove(); - }, - }; - } -} - -coreModule.service('panelLoader', PanelLoader); diff --git a/public/app/features/plugins/plugin_component.ts b/public/app/features/plugins/plugin_component.ts index 1936e57f558..2ca3dd6bd0b 100644 --- a/public/app/features/plugins/plugin_component.ts +++ b/public/app/features/plugins/plugin_component.ts @@ -110,6 +110,7 @@ function pluginDirectiveLoader($compile, datasourceSrv, $rootScope, $q, $http, $ let datasource = scope.target.datasource || scope.ctrl.panel.datasource; return datasourceSrv.get(datasource).then(ds => { scope.datasource = ds; + console.log('scope', scope); return importPluginModule(ds.meta.module).then(dsModule => { return { diff --git a/public/app/partials/dashboard.html b/public/app/partials/dashboard.html index 9506587c515..9e7d4fa1c6c 100644 --- a/public/app/partials/dashboard.html +++ b/public/app/partials/dashboard.html @@ -11,8 +11,7 @@ - - +
diff --git a/public/sass/components/_tabbed_view.scss b/public/sass/components/_tabbed_view.scss index bf95d453504..a5d38d292a1 100644 --- a/public/sass/components/_tabbed_view.scss +++ b/public/sass/components/_tabbed_view.scss @@ -10,6 +10,15 @@ background: none; } } + + &.tabbed-view--panel-edit-new { + padding: 10px 0 0 0; + + .tabbed-view-header { + padding: 0px; + background: none; + } + } } .tabbed-view-header { From 1099daec38a8ed360e97ee7d018b90a5984cfef1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Torkel=20=C3=96degaard?= Date: Wed, 20 Jun 2018 12:05:03 +0200 Subject: [PATCH 2/2] wip: react panels, query editor loading from react PanelEditor view --- public/app/features/dashboard/panel_model.ts | 5 +++++ public/app/features/panel/metrics_panel_ctrl.ts | 4 ---- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/public/app/features/dashboard/panel_model.ts b/public/app/features/dashboard/panel_model.ts index 0bb2d2755d7..2de409eda57 100644 --- a/public/app/features/dashboard/panel_model.ts +++ b/public/app/features/dashboard/panel_model.ts @@ -31,6 +31,7 @@ export class PanelModel { collapsed?: boolean; panels?: any; soloMode?: boolean; + targets: any[]; // non persisted fullscreen: boolean; @@ -48,6 +49,10 @@ export class PanelModel { if (!this.gridPos) { this.gridPos = { x: 0, y: 0, h: 3, w: 6 }; } + + if (!this.targets) { + this.targets = [{}]; + } } getSaveModel() { diff --git a/public/app/features/panel/metrics_panel_ctrl.ts b/public/app/features/panel/metrics_panel_ctrl.ts index 75c0de3bc6e..ba97ce79c1f 100644 --- a/public/app/features/panel/metrics_panel_ctrl.ts +++ b/public/app/features/panel/metrics_panel_ctrl.ts @@ -45,10 +45,6 @@ class MetricsPanelCtrl extends PanelCtrl { this.scope = $scope; this.panel.datasource = this.panel.datasource || null; - if (!this.panel.targets) { - this.panel.targets = [{}]; - } - this.events.on('refresh', this.onMetricsPanelRefresh.bind(this)); this.events.on('init-edit-mode', this.onInitMetricsPanelEditMode.bind(this)); this.events.on('panel-teardown', this.onPanelTearDown.bind(this));