From aeaac7480bc3b7f3ae13d80f3830e85a7eb29df9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Torkel=20=C3=96degaard?= Date: Fri, 1 Feb 2019 08:12:58 +0100 Subject: [PATCH] New solo panel route working in all scenarios I can test --- public/app/core/profiler.ts | 103 +----------------- .../dashboard/containers/SoloPanelPage.tsx | 38 +++++-- .../features/dashboard/dashgrid/DataPanel.tsx | 3 - .../dashboard/dashgrid/PanelChrome.tsx | 9 +- public/app/features/panel/all.ts | 1 - .../app/features/panel/metrics_panel_ctrl.ts | 11 -- public/app/features/panel/panel_ctrl.ts | 25 +---- public/app/features/panel/panel_directive.ts | 14 ++- .../features/panel/partials/soloPanel.html | 4 - public/app/features/panel/solo_panel_ctrl.ts | 58 ---------- public/app/plugins/panel/table/module.ts | 1 - public/app/routes/routes.ts | 9 +- 12 files changed, 58 insertions(+), 218 deletions(-) delete mode 100644 public/app/features/panel/partials/soloPanel.html delete mode 100644 public/app/features/panel/solo_panel_ctrl.ts diff --git a/public/app/core/profiler.ts b/public/app/core/profiler.ts index 0e738dd3da1..19c67039c41 100644 --- a/public/app/core/profiler.ts +++ b/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(); } } diff --git a/public/app/features/dashboard/containers/SoloPanelPage.tsx b/public/app/features/dashboard/containers/SoloPanelPage.tsx index 9c6b13d6676..097c8015929 100644 --- a/public/app/features/dashboard/containers/SoloPanelPage.tsx +++ b/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 { }; 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 { } 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)); diff --git a/public/app/features/dashboard/dashgrid/DataPanel.tsx b/public/app/features/dashboard/dashgrid/DataPanel.tsx index 353c474bcd9..2183548000b 100644 --- a/public/app/features/dashboard/dashgrid/DataPanel.tsx +++ b/public/app/features/dashboard/dashgrid/DataPanel.tsx @@ -135,11 +135,8 @@ export class DataPanel extends Component { 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; } diff --git a/public/app/features/dashboard/dashgrid/PanelChrome.tsx b/public/app/features/dashboard/dashgrid/PanelChrome.tsx index 68b53714504..99e206c6f51 100644 --- a/public/app/features/dashboard/dashgrid/PanelChrome.tsx +++ b/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 { 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 (
{ }); 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; diff --git a/public/app/features/panel/partials/soloPanel.html b/public/app/features/panel/partials/soloPanel.html deleted file mode 100644 index 644bbe74ffb..00000000000 --- a/public/app/features/panel/partials/soloPanel.html +++ /dev/null @@ -1,4 +0,0 @@ -
- - -
diff --git a/public/app/features/panel/solo_panel_ctrl.ts b/public/app/features/panel/solo_panel_ctrl.ts deleted file mode 100644 index a8bf5371913..00000000000 --- a/public/app/features/panel/solo_panel_ctrl.ts +++ /dev/null @@ -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); diff --git a/public/app/plugins/panel/table/module.ts b/public/app/plugins/panel/table/module.ts index ebc654f8be9..82763e1839a 100644 --- a/public/app/plugins/panel/table/module.ts +++ b/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, diff --git a/public/app/routes/routes.ts b/public/app/routes/routes.ts index 3f4b2fb074d..0f4c09a9c77 100644 --- a/public/app/routes/routes.ts +++ b/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: '', + pageClass: 'dashboard-solo', + resolve: { + component: () => SoloPanelPage, + }, }) .when('/dashboard/new', { templateUrl: 'public/app/partials/dashboard.html',