Browse Source

New solo panel route working in all scenarios I can test

Torkel Ödegaard 6 years ago
parent
commit
aeaac7480b

+ 1 - 102
public/app/core/profiler.ts

@@ -1,106 +1,20 @@
-import $ from 'jquery';
-import angular from 'angular';
 
 export class Profiler {
   panelsRendered: number;
   enabled: boolean;
-  panelsInitCount: any;
-  timings: any;
-  digestCounter: any;
   $rootScope: any;
-  scopeCount: any;
   window: any;
 
   init(config, $rootScope) {
-    this.enabled = config.buildInfo.env === 'development';
-    this.timings = {};
-    this.timings.appStart = { loadStart: new Date().getTime() };
     this.$rootScope = $rootScope;
     this.window = window;
 
     if (!this.enabled) {
       return;
     }
-
-    $rootScope.$watch(
-      () => {
-        this.digestCounter++;
-        return false;
-      },
-      () => {}
-    );
-
-    $rootScope.onAppEvent('refresh', this.refresh.bind(this), $rootScope);
-    $rootScope.onAppEvent('dashboard-fetch-end', this.dashboardFetched.bind(this), $rootScope);
-    $rootScope.onAppEvent('dashboard-initialized', this.dashboardInitialized.bind(this), $rootScope);
-    $rootScope.onAppEvent('panel-initialized', this.panelInitialized.bind(this), $rootScope);
-  }
-
-  refresh() {
-    this.timings.query = 0;
-    this.timings.render = 0;
-
-    setTimeout(() => {
-      console.log('panel count: ' + this.panelsInitCount);
-      console.log('total query: ' + this.timings.query);
-      console.log('total render: ' + this.timings.render);
-      console.log('avg render: ' + this.timings.render / this.panelsInitCount);
-    }, 5000);
-  }
-
-  dashboardFetched() {
-    this.timings.dashboardLoadStart = new Date().getTime();
-    this.panelsInitCount = 0;
-    this.digestCounter = 0;
-    this.panelsInitCount = 0;
-    this.panelsRendered = 0;
-    this.timings.query = 0;
-    this.timings.render = 0;
   }
 
-  dashboardInitialized() {
-    setTimeout(() => {
-      console.log('Dashboard::Performance Total Digests: ' + this.digestCounter);
-      console.log('Dashboard::Performance Total Watchers: ' + this.getTotalWatcherCount());
-      console.log('Dashboard::Performance Total ScopeCount: ' + this.scopeCount);
-
-      const timeTaken = this.timings.lastPanelInitializedAt - this.timings.dashboardLoadStart;
-      console.log('Dashboard::Performance All panels initialized in ' + timeTaken + ' ms');
-
-      // measure digest performance
-      const rootDigestStart = window.performance.now();
-      for (let i = 0; i < 30; i++) {
-        this.$rootScope.$apply();
-      }
-
-      console.log('Dashboard::Performance Root Digest ' + (window.performance.now() - rootDigestStart) / 30);
-    }, 3000);
-  }
-
-  getTotalWatcherCount() {
-    let count = 0;
-    let scopes = 0;
-    const root = $(document.getElementsByTagName('body'));
-
-    const f = element => {
-      if (element.data().hasOwnProperty('$scope')) {
-        scopes++;
-        angular.forEach(element.data().$scope.$$watchers, () => {
-          count++;
-        });
-      }
-
-      angular.forEach(element.children(), childElement => {
-        f($(childElement));
-      });
-    };
-
-    f(root);
-    this.scopeCount = scopes;
-    return count;
-  }
-
-  renderingCompleted(panelId, panelTimings) {
+  renderingCompleted(panelId) {
     // add render counter to root scope
     // used by phantomjs render.js to know when panel has rendered
     this.panelsRendered = (this.panelsRendered || 0) + 1;
@@ -108,21 +22,6 @@ export class Profiler {
     // this window variable is used by backend rendering tools to know
     // all panels have completed rendering
     this.window.panelsRendered = this.panelsRendered;
-
-    if (this.enabled) {
-      panelTimings.renderEnd = new Date().getTime();
-      this.timings.query += panelTimings.queryEnd - panelTimings.queryStart;
-      this.timings.render += panelTimings.renderEnd - panelTimings.renderStart;
-    }
-  }
-
-  panelInitialized() {
-    if (!this.enabled) {
-      return;
-    }
-
-    this.panelsInitCount++;
-    this.timings.lastPanelInitializedAt = new Date().getTime();
   }
 }
 

+ 30 - 8
public/app/features/dashboard/containers/SoloPanelPage.tsx

@@ -5,21 +5,27 @@ import { connect } from 'react-redux';
 
 // Utils & Services
 import appEvents from 'app/core/app_events';
+import locationUtil from 'app/core/utils/location_util';
+import { getBackendSrv } from 'app/core/services/backend_srv';
 
 // Components
 import { DashboardPanel } from '../dashgrid/DashboardPanel';
 
+// Redux
+import { updateLocation } from 'app/core/actions';
+
 // Types
 import { StoreState } from 'app/types';
 import { PanelModel, DashboardModel } from 'app/features/dashboard/state';
 
 interface Props {
   panelId: string;
-  uid?: string;
-  slug?: string;
-  type?: string;
+  urlUid?: string;
+  urlSlug?: string;
+  urlType?: string;
   $scope: any;
   $injector: any;
+  updateLocation: typeof updateLocation;
 }
 
 interface State {
@@ -37,19 +43,34 @@ export class SoloPanelPage extends Component<Props, State> {
   };
 
   componentDidMount() {
-    const { $injector, $scope, uid } = this.props;
+    const { $injector, $scope, urlUid, urlType, urlSlug } = this.props;
+
+    // handle old urls with no uid
+    if (!urlUid && !(urlType === 'script' || urlType === 'snapshot')) {
+      this.redirectToNewUrl();
+      return;
+    }
 
     const dashboardLoaderSrv = $injector.get('dashboardLoaderSrv');
 
     // subscribe to event to know when dashboard controller is done with inititalization
     appEvents.on('dashboard-initialized', this.onDashoardInitialized);
 
-    dashboardLoaderSrv.loadDashboard('', '', uid).then(result => {
+    dashboardLoaderSrv.loadDashboard(urlType, urlSlug, urlUid).then(result => {
       result.meta.soloMode = true;
       $scope.initDashboard(result, $scope);
     });
   }
 
+  redirectToNewUrl() {
+    getBackendSrv().getDashboardBySlug(this.props.urlSlug).then(res => {
+      if (res) {
+        const url = locationUtil.stripBaseFromUrl(res.meta.url.replace('/d/', '/d-solo/'));
+        this.props.updateLocation(url);
+      }
+    });
+  }
+
   onDashoardInitialized = () => {
     const { $scope, panelId } = this.props;
 
@@ -89,13 +110,14 @@ export class SoloPanelPage extends Component<Props, State> {
 }
 
 const mapStateToProps = (state: StoreState) => ({
-  uid: state.location.routeParams.uid,
-  slug: state.location.routeParams.slug,
-  type: state.location.routeParams.type,
+  urlUid: state.location.routeParams.uid,
+  urlSlug: state.location.routeParams.slug,
+  urlType: state.location.routeParams.type,
   panelId: state.location.query.panelId
 });
 
 const mapDispatchToProps = {
+  updateLocation
 };
 
 export default hot(module)(connect(mapStateToProps, mapDispatchToProps)(SoloPanelPage));

+ 0 - 3
public/app/features/dashboard/dashgrid/DataPanel.tsx

@@ -135,11 +135,8 @@ export class DataPanel extends Component<Props, State> {
         cacheTimeout: null,
       };
 
-      console.log('Issuing DataPanel query', queryOptions);
       const resp = await ds.query(queryOptions);
 
-      console.log('Issuing DataPanel query Resp', resp);
-
       if (this.isUnmounted) {
         return;
       }

+ 8 - 1
public/app/features/dashboard/dashgrid/PanelChrome.tsx

@@ -12,11 +12,12 @@ import { DataPanel } from './DataPanel';
 // Utils
 import { applyPanelTimeOverrides } from 'app/features/dashboard/utils/panel';
 import { PANEL_HEADER_HEIGHT } from 'app/core/constants';
+import { profiler } from 'app/core/profiler';
 
 // Types
 import { DashboardModel, PanelModel } from '../state';
 import { PanelPlugin } from 'app/types';
-import { TimeRange } from '@grafana/ui';
+import { TimeRange, LoadingState } from '@grafana/ui';
 
 import variables from 'sass/_variables.scss';
 import templateSrv from 'app/features/templating/template_srv';
@@ -98,6 +99,12 @@ export class PanelChrome extends PureComponent<Props, State> {
     const { timeRange, renderCounter } = this.state;
     const PanelComponent = plugin.exports.Panel;
 
+    // This is only done to increase a counter that is used by backend
+    // image rendering (phantomjs/headless chrome) to know when to capture image
+    if (loading === LoadingState.Done) {
+      profiler.renderingCompleted(panel.id);
+    }
+
     return (
       <div className="panel-content">
         <PanelComponent

+ 0 - 1
public/app/features/panel/all.ts

@@ -1,6 +1,5 @@
 import './panel_header';
 import './panel_directive';
-import './solo_panel_ctrl';
 import './query_ctrl';
 import './panel_editor_tab';
 import './query_editor_row';

+ 0 - 11
public/app/features/panel/metrics_panel_ctrl.ts

@@ -16,7 +16,6 @@ class MetricsPanelCtrl extends PanelCtrl {
   datasourceSrv: any;
   timeSrv: any;
   templateSrv: any;
-  timing: any;
   range: any;
   interval: any;
   intervalMs: any;
@@ -81,7 +80,6 @@ class MetricsPanelCtrl extends PanelCtrl {
     this.loading = true;
 
     // load datasource service
-    this.setTimeQueryStart();
     this.datasourceSrv
       .get(this.panel.datasource)
       .then(this.updateTimeRange.bind(this))
@@ -112,14 +110,6 @@ class MetricsPanelCtrl extends PanelCtrl {
       });
   }
 
-  setTimeQueryStart() {
-    this.timing.queryStart = new Date().getTime();
-  }
-
-  setTimeQueryEnd() {
-    this.timing.queryEnd = new Date().getTime();
-  }
-
   updateTimeRange(datasource?) {
     this.datasource = datasource || this.datasource;
     this.range = this.timeSrv.timeRange();
@@ -181,7 +171,6 @@ class MetricsPanelCtrl extends PanelCtrl {
   }
 
   handleQueryResult(result) {
-    this.setTimeQueryEnd();
     this.loading = false;
 
     // check for if data source returns subject

+ 6 - 19
public/app/features/panel/panel_ctrl.ts

@@ -1,5 +1,4 @@
 import _ from 'lodash';
-import $ from 'jquery';
 import Remarkable from 'remarkable';
 
 import config from 'app/core/config';
@@ -13,7 +12,7 @@ import {
   sharePanel as sharePanelUtil,
 } from 'app/features/dashboard/utils/panel';
 
-import { GRID_CELL_HEIGHT, GRID_CELL_VMARGIN, GRID_COLUMN_COUNT, PANEL_HEADER_HEIGHT, PANEL_BORDER } from 'app/core/constants';
+import { GRID_COLUMN_COUNT, PANEL_HEADER_HEIGHT, PANEL_BORDER } from 'app/core/constants';
 
 export class PanelCtrl {
   panel: any;
@@ -31,8 +30,8 @@ export class PanelCtrl {
   height: any;
   containerHeight: any;
   events: Emitter;
-  timing: any;
   loading: boolean;
+  timing: any;
   maxPanelsPerRowOptions: number[];
 
   constructor($scope, $injector) {
@@ -42,7 +41,7 @@ export class PanelCtrl {
     this.$timeout = $injector.get('$timeout');
     this.editorTabs = [];
     this.events = this.panel.events;
-    this.timing = {};
+    this.timing = {}; // not used but here to not break plugins
 
     const plugin = config.panels[this.panel.type];
     if (plugin) {
@@ -59,7 +58,7 @@ export class PanelCtrl {
   }
 
   renderingCompleted() {
-    profiler.renderingCompleted(this.panel.id, this.timing);
+    profiler.renderingCompleted(this.panel.id);
   }
 
   refresh() {
@@ -200,24 +199,12 @@ export class PanelCtrl {
     return this.dashboard.meta.fullscreen && !this.panel.fullscreen;
   }
 
-  calculatePanelHeight() {
-    if (this.panel.isEditing) {
-      this.containerHeight = $('.panel-wrapper--edit').height();
-    } else if (this.panel.fullscreen)  {
-      this.containerHeight = $('.panel-wrapper--view').height();
-    } else {
-      this.containerHeight = this.panel.gridPos.h * GRID_CELL_HEIGHT + (this.panel.gridPos.h - 1) * GRID_CELL_VMARGIN;
-    }
-
-    if (this.panel.soloMode) {
-      this.containerHeight = $(window).height();
-    }
-
+  calculatePanelHeight(containerHeight) {
+    this.containerHeight = containerHeight;
     this.height = this.containerHeight - (PANEL_BORDER + PANEL_HEADER_HEIGHT);
   }
 
   render(payload?) {
-    this.timing.renderStart = new Date().getTime();
     this.events.emit('render', payload);
   }
 

+ 8 - 6
public/app/features/panel/panel_directive.ts

@@ -101,7 +101,7 @@ module.directive('grafanaPanel', ($rootScope, $document, $timeout) => {
       });
 
       ctrl.events.on('panel-size-changed', () => {
-        ctrl.calculatePanelHeight();
+        ctrl.calculatePanelHeight(panelContainer[0].offsetHeight);
         $timeout(() => {
           resizeScrollableContent();
           ctrl.render();
@@ -112,19 +112,21 @@ module.directive('grafanaPanel', ($rootScope, $document, $timeout) => {
         // first wait one pass for dashboard fullscreen view mode to take effect (classses being applied)
         setTimeout(() => {
           // then recalc style
-          ctrl.calculatePanelHeight();
+          ctrl.calculatePanelHeight(panelContainer[0].offsetHeight);
           // then wait another cycle (this might not be needed)
           $timeout(() => {
             ctrl.render();
             resizeScrollableContent();
           });
-        });
+        }, 10);
       });
 
-      // set initial height
-      ctrl.calculatePanelHeight();
-
       ctrl.events.on('render', () => {
+        // set initial height
+        if (!ctrl.height) {
+          ctrl.calculatePanelHeight(panelContainer[0].offsetHeight);
+        }
+
         if (transparentLastState !== ctrl.panel.transparent) {
           panelContainer.toggleClass('panel-transparent', ctrl.panel.transparent === true);
           transparentLastState = ctrl.panel.transparent;

+ 0 - 4
public/app/features/panel/partials/soloPanel.html

@@ -1,4 +0,0 @@
-<div class="panel-solo" ng-if="panel">
-	<plugin-component type="panel">
-	</plugin-component>
-</div>

+ 0 - 58
public/app/features/panel/solo_panel_ctrl.ts

@@ -1,58 +0,0 @@
-import angular from 'angular';
-import locationUtil from 'app/core/utils/location_util';
-import appEvents from 'app/core/app_events';
-
-export class SoloPanelCtrl {
-  /** @ngInject */
-  constructor($scope, $routeParams, $location, dashboardLoaderSrv, contextSrv, backendSrv) {
-    let panelId;
-
-    $scope.init = () => {
-      contextSrv.sidemenu = false;
-      appEvents.emit('toggle-sidemenu-hidden');
-
-      const params = $location.search();
-      panelId = parseInt(params.panelId, 10);
-
-      appEvents.on('dashboard-initialized', $scope.initPanelScope);
-
-      // if no uid, redirect to new route based on slug
-      if (!($routeParams.type === 'script' || $routeParams.type === 'snapshot') && !$routeParams.uid) {
-        backendSrv.getDashboardBySlug($routeParams.slug).then(res => {
-          if (res) {
-            const url = locationUtil.stripBaseFromUrl(res.meta.url.replace('/d/', '/d-solo/'));
-            $location.path(url).replace();
-          }
-        });
-        return;
-      }
-
-      dashboardLoaderSrv.loadDashboard($routeParams.type, $routeParams.slug, $routeParams.uid).then(result => {
-        result.meta.soloMode = true;
-        $scope.initDashboard(result, $scope);
-      });
-    };
-
-    $scope.initPanelScope = () => {
-      const panelInfo = $scope.dashboard.getPanelInfoById(panelId);
-
-      // fake row ctrl scope
-      $scope.ctrl = {
-        dashboard: $scope.dashboard,
-      };
-
-      $scope.panel = panelInfo.panel;
-      $scope.panel.soloMode = true;
-      $scope.$index = 0;
-
-      if (!$scope.panel) {
-        $scope.appEvent('alert-error', ['Panel not found', '']);
-        return;
-      }
-    };
-
-    $scope.init();
-  }
-}
-
-angular.module('grafana.routes').controller('SoloPanelCtrl', SoloPanelCtrl);

+ 0 - 1
public/app/plugins/panel/table/module.ts

@@ -80,7 +80,6 @@ class TablePanelCtrl extends MetricsPanelCtrl {
     this.pageIndex = 0;
 
     if (this.panel.transform === 'annotations') {
-      this.setTimeQueryStart();
       return this.annotationsSrv
         .getAnnotations({
           dashboard: this.dashboard,

+ 5 - 4
public/app/routes/routes.ts

@@ -59,10 +59,11 @@ export function setupAngularRoutes($routeProvider, $locationProvider) {
       },
     })
     .when('/dashboard-solo/:type/:slug', {
-      templateUrl: 'public/app/features/panel/partials/soloPanel.html',
-      controller: 'SoloPanelCtrl',
-      reloadOnSearch: false,
-      pageClass: 'page-dashboard',
+      template: '<react-container />',
+      pageClass: 'dashboard-solo',
+      resolve: {
+        component: () => SoloPanelPage,
+      },
     })
     .when('/dashboard/new', {
       templateUrl: 'public/app/partials/dashboard.html',