mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
Merge pull request #15155 from grafana/solo-panel-rewrite
New react container route for solo panels
This commit is contained in:
commit
68ae17e4a4
@ -1,106 +1,20 @@
|
|||||||
import $ from 'jquery';
|
|
||||||
import angular from 'angular';
|
|
||||||
|
|
||||||
export class Profiler {
|
export class Profiler {
|
||||||
panelsRendered: number;
|
panelsRendered: number;
|
||||||
enabled: boolean;
|
enabled: boolean;
|
||||||
panelsInitCount: any;
|
|
||||||
timings: any;
|
|
||||||
digestCounter: any;
|
|
||||||
$rootScope: any;
|
$rootScope: any;
|
||||||
scopeCount: any;
|
|
||||||
window: any;
|
window: any;
|
||||||
|
|
||||||
init(config, $rootScope) {
|
init(config, $rootScope) {
|
||||||
this.enabled = config.buildInfo.env === 'development';
|
|
||||||
this.timings = {};
|
|
||||||
this.timings.appStart = { loadStart: new Date().getTime() };
|
|
||||||
this.$rootScope = $rootScope;
|
this.$rootScope = $rootScope;
|
||||||
this.window = window;
|
this.window = window;
|
||||||
|
|
||||||
if (!this.enabled) {
|
if (!this.enabled) {
|
||||||
return;
|
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() {
|
renderingCompleted(panelId) {
|
||||||
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) {
|
|
||||||
// add render counter to root scope
|
// add render counter to root scope
|
||||||
// used by phantomjs render.js to know when panel has rendered
|
// used by phantomjs render.js to know when panel has rendered
|
||||||
this.panelsRendered = (this.panelsRendered || 0) + 1;
|
this.panelsRendered = (this.panelsRendered || 0) + 1;
|
||||||
@ -108,21 +22,6 @@ export class Profiler {
|
|||||||
// this window variable is used by backend rendering tools to know
|
// this window variable is used by backend rendering tools to know
|
||||||
// all panels have completed rendering
|
// all panels have completed rendering
|
||||||
this.window.panelsRendered = this.panelsRendered;
|
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();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
123
public/app/features/dashboard/containers/SoloPanelPage.tsx
Normal file
123
public/app/features/dashboard/containers/SoloPanelPage.tsx
Normal file
@ -0,0 +1,123 @@
|
|||||||
|
// Libraries
|
||||||
|
import React, { Component } from 'react';
|
||||||
|
import { hot } from 'react-hot-loader';
|
||||||
|
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;
|
||||||
|
urlUid?: string;
|
||||||
|
urlSlug?: string;
|
||||||
|
urlType?: string;
|
||||||
|
$scope: any;
|
||||||
|
$injector: any;
|
||||||
|
updateLocation: typeof updateLocation;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface State {
|
||||||
|
panel: PanelModel | null;
|
||||||
|
dashboard: DashboardModel | null;
|
||||||
|
notFound: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export class SoloPanelPage extends Component<Props, State> {
|
||||||
|
|
||||||
|
state: State = {
|
||||||
|
panel: null,
|
||||||
|
dashboard: null,
|
||||||
|
notFound: false,
|
||||||
|
};
|
||||||
|
|
||||||
|
componentDidMount() {
|
||||||
|
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(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;
|
||||||
|
|
||||||
|
const dashboard: DashboardModel = $scope.dashboard;
|
||||||
|
const panel = dashboard.getPanelById(parseInt(panelId, 10));
|
||||||
|
|
||||||
|
if (!panel) {
|
||||||
|
this.setState({ notFound: true });
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.setState({ dashboard, panel });
|
||||||
|
};
|
||||||
|
|
||||||
|
render() {
|
||||||
|
const { panelId } = this.props;
|
||||||
|
const { notFound, panel, dashboard } = this.state;
|
||||||
|
|
||||||
|
if (notFound) {
|
||||||
|
return (
|
||||||
|
<div className="alert alert-error">
|
||||||
|
Panel with id { panelId } not found
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!panel) {
|
||||||
|
return <div>Loading & initializing dashboard</div>;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="panel-solo">
|
||||||
|
<DashboardPanel dashboard={dashboard} panel={panel} isEditing={false} isFullscreen={false} />
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const mapStateToProps = (state: StoreState) => ({
|
||||||
|
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));
|
@ -135,11 +135,8 @@ export class DataPanel extends Component<Props, State> {
|
|||||||
cacheTimeout: null,
|
cacheTimeout: null,
|
||||||
};
|
};
|
||||||
|
|
||||||
console.log('Issuing DataPanel query', queryOptions);
|
|
||||||
const resp = await ds.query(queryOptions);
|
const resp = await ds.query(queryOptions);
|
||||||
|
|
||||||
console.log('Issuing DataPanel query Resp', resp);
|
|
||||||
|
|
||||||
if (this.isUnmounted) {
|
if (this.isUnmounted) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -12,11 +12,12 @@ import { DataPanel } from './DataPanel';
|
|||||||
// Utils
|
// Utils
|
||||||
import { applyPanelTimeOverrides } from 'app/features/dashboard/utils/panel';
|
import { applyPanelTimeOverrides } from 'app/features/dashboard/utils/panel';
|
||||||
import { PANEL_HEADER_HEIGHT } from 'app/core/constants';
|
import { PANEL_HEADER_HEIGHT } from 'app/core/constants';
|
||||||
|
import { profiler } from 'app/core/profiler';
|
||||||
|
|
||||||
// Types
|
// Types
|
||||||
import { DashboardModel, PanelModel } from '../state';
|
import { DashboardModel, PanelModel } from '../state';
|
||||||
import { PanelPlugin } from 'app/types';
|
import { PanelPlugin } from 'app/types';
|
||||||
import { TimeRange } from '@grafana/ui';
|
import { TimeRange, LoadingState } from '@grafana/ui';
|
||||||
|
|
||||||
import variables from 'sass/_variables.scss';
|
import variables from 'sass/_variables.scss';
|
||||||
import templateSrv from 'app/features/templating/template_srv';
|
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 { timeRange, renderCounter } = this.state;
|
||||||
const PanelComponent = plugin.exports.Panel;
|
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 (
|
return (
|
||||||
<div className="panel-content">
|
<div className="panel-content">
|
||||||
<PanelComponent
|
<PanelComponent
|
||||||
|
@ -271,7 +271,7 @@ export class DashboardModel {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
getPanelById(id) {
|
getPanelById(id): PanelModel {
|
||||||
for (const panel of this.panels) {
|
for (const panel of this.panels) {
|
||||||
if (panel.id === id) {
|
if (panel.id === id) {
|
||||||
return panel;
|
return panel;
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
import './panel_header';
|
import './panel_header';
|
||||||
import './panel_directive';
|
import './panel_directive';
|
||||||
import './solo_panel_ctrl';
|
|
||||||
import './query_ctrl';
|
import './query_ctrl';
|
||||||
import './panel_editor_tab';
|
import './panel_editor_tab';
|
||||||
import './query_editor_row';
|
import './query_editor_row';
|
||||||
|
@ -16,7 +16,6 @@ class MetricsPanelCtrl extends PanelCtrl {
|
|||||||
datasourceSrv: any;
|
datasourceSrv: any;
|
||||||
timeSrv: any;
|
timeSrv: any;
|
||||||
templateSrv: any;
|
templateSrv: any;
|
||||||
timing: any;
|
|
||||||
range: any;
|
range: any;
|
||||||
interval: any;
|
interval: any;
|
||||||
intervalMs: any;
|
intervalMs: any;
|
||||||
@ -81,7 +80,6 @@ class MetricsPanelCtrl extends PanelCtrl {
|
|||||||
this.loading = true;
|
this.loading = true;
|
||||||
|
|
||||||
// load datasource service
|
// load datasource service
|
||||||
this.setTimeQueryStart();
|
|
||||||
this.datasourceSrv
|
this.datasourceSrv
|
||||||
.get(this.panel.datasource)
|
.get(this.panel.datasource)
|
||||||
.then(this.updateTimeRange.bind(this))
|
.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?) {
|
updateTimeRange(datasource?) {
|
||||||
this.datasource = datasource || this.datasource;
|
this.datasource = datasource || this.datasource;
|
||||||
this.range = this.timeSrv.timeRange();
|
this.range = this.timeSrv.timeRange();
|
||||||
@ -181,7 +171,6 @@ class MetricsPanelCtrl extends PanelCtrl {
|
|||||||
}
|
}
|
||||||
|
|
||||||
handleQueryResult(result) {
|
handleQueryResult(result) {
|
||||||
this.setTimeQueryEnd();
|
|
||||||
this.loading = false;
|
this.loading = false;
|
||||||
|
|
||||||
// check for if data source returns subject
|
// check for if data source returns subject
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
import _ from 'lodash';
|
import _ from 'lodash';
|
||||||
import $ from 'jquery';
|
|
||||||
import Remarkable from 'remarkable';
|
import Remarkable from 'remarkable';
|
||||||
|
|
||||||
import config from 'app/core/config';
|
import config from 'app/core/config';
|
||||||
@ -13,7 +12,7 @@ import {
|
|||||||
sharePanel as sharePanelUtil,
|
sharePanel as sharePanelUtil,
|
||||||
} from 'app/features/dashboard/utils/panel';
|
} 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 {
|
export class PanelCtrl {
|
||||||
panel: any;
|
panel: any;
|
||||||
@ -31,8 +30,8 @@ export class PanelCtrl {
|
|||||||
height: any;
|
height: any;
|
||||||
containerHeight: any;
|
containerHeight: any;
|
||||||
events: Emitter;
|
events: Emitter;
|
||||||
timing: any;
|
|
||||||
loading: boolean;
|
loading: boolean;
|
||||||
|
timing: any;
|
||||||
maxPanelsPerRowOptions: number[];
|
maxPanelsPerRowOptions: number[];
|
||||||
|
|
||||||
constructor($scope, $injector) {
|
constructor($scope, $injector) {
|
||||||
@ -42,7 +41,7 @@ export class PanelCtrl {
|
|||||||
this.$timeout = $injector.get('$timeout');
|
this.$timeout = $injector.get('$timeout');
|
||||||
this.editorTabs = [];
|
this.editorTabs = [];
|
||||||
this.events = this.panel.events;
|
this.events = this.panel.events;
|
||||||
this.timing = {};
|
this.timing = {}; // not used but here to not break plugins
|
||||||
|
|
||||||
const plugin = config.panels[this.panel.type];
|
const plugin = config.panels[this.panel.type];
|
||||||
if (plugin) {
|
if (plugin) {
|
||||||
@ -59,7 +58,7 @@ export class PanelCtrl {
|
|||||||
}
|
}
|
||||||
|
|
||||||
renderingCompleted() {
|
renderingCompleted() {
|
||||||
profiler.renderingCompleted(this.panel.id, this.timing);
|
profiler.renderingCompleted(this.panel.id);
|
||||||
}
|
}
|
||||||
|
|
||||||
refresh() {
|
refresh() {
|
||||||
@ -200,24 +199,12 @@ export class PanelCtrl {
|
|||||||
return this.dashboard.meta.fullscreen && !this.panel.fullscreen;
|
return this.dashboard.meta.fullscreen && !this.panel.fullscreen;
|
||||||
}
|
}
|
||||||
|
|
||||||
calculatePanelHeight() {
|
calculatePanelHeight(containerHeight) {
|
||||||
if (this.panel.isEditing) {
|
this.containerHeight = containerHeight;
|
||||||
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();
|
|
||||||
}
|
|
||||||
|
|
||||||
this.height = this.containerHeight - (PANEL_BORDER + PANEL_HEADER_HEIGHT);
|
this.height = this.containerHeight - (PANEL_BORDER + PANEL_HEADER_HEIGHT);
|
||||||
}
|
}
|
||||||
|
|
||||||
render(payload?) {
|
render(payload?) {
|
||||||
this.timing.renderStart = new Date().getTime();
|
|
||||||
this.events.emit('render', payload);
|
this.events.emit('render', payload);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -101,7 +101,7 @@ module.directive('grafanaPanel', ($rootScope, $document, $timeout) => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
ctrl.events.on('panel-size-changed', () => {
|
ctrl.events.on('panel-size-changed', () => {
|
||||||
ctrl.calculatePanelHeight();
|
ctrl.calculatePanelHeight(panelContainer[0].offsetHeight);
|
||||||
$timeout(() => {
|
$timeout(() => {
|
||||||
resizeScrollableContent();
|
resizeScrollableContent();
|
||||||
ctrl.render();
|
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)
|
// first wait one pass for dashboard fullscreen view mode to take effect (classses being applied)
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
// then recalc style
|
// then recalc style
|
||||||
ctrl.calculatePanelHeight();
|
ctrl.calculatePanelHeight(panelContainer[0].offsetHeight);
|
||||||
// then wait another cycle (this might not be needed)
|
// then wait another cycle (this might not be needed)
|
||||||
$timeout(() => {
|
$timeout(() => {
|
||||||
ctrl.render();
|
ctrl.render();
|
||||||
resizeScrollableContent();
|
resizeScrollableContent();
|
||||||
});
|
});
|
||||||
});
|
}, 10);
|
||||||
});
|
});
|
||||||
|
|
||||||
// set initial height
|
|
||||||
ctrl.calculatePanelHeight();
|
|
||||||
|
|
||||||
ctrl.events.on('render', () => {
|
ctrl.events.on('render', () => {
|
||||||
|
// set initial height
|
||||||
|
if (!ctrl.height) {
|
||||||
|
ctrl.calculatePanelHeight(panelContainer[0].offsetHeight);
|
||||||
|
}
|
||||||
|
|
||||||
if (transparentLastState !== ctrl.panel.transparent) {
|
if (transparentLastState !== ctrl.panel.transparent) {
|
||||||
panelContainer.toggleClass('panel-transparent', ctrl.panel.transparent === true);
|
panelContainer.toggleClass('panel-transparent', ctrl.panel.transparent === true);
|
||||||
transparentLastState = ctrl.panel.transparent;
|
transparentLastState = ctrl.panel.transparent;
|
||||||
|
@ -1,4 +0,0 @@
|
|||||||
<div class="panel-solo" ng-if="panel">
|
|
||||||
<plugin-component type="panel">
|
|
||||||
</plugin-component>
|
|
||||||
</div>
|
|
@ -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);
|
|
@ -80,7 +80,6 @@ class TablePanelCtrl extends MetricsPanelCtrl {
|
|||||||
this.pageIndex = 0;
|
this.pageIndex = 0;
|
||||||
|
|
||||||
if (this.panel.transform === 'annotations') {
|
if (this.panel.transform === 'annotations') {
|
||||||
this.setTimeQueryStart();
|
|
||||||
return this.annotationsSrv
|
return this.annotationsSrv
|
||||||
.getAnnotations({
|
.getAnnotations({
|
||||||
dashboard: this.dashboard,
|
dashboard: this.dashboard,
|
||||||
|
@ -18,6 +18,8 @@ function WrapInProvider(store, Component, props) {
|
|||||||
export function reactContainer(
|
export function reactContainer(
|
||||||
$route,
|
$route,
|
||||||
$location,
|
$location,
|
||||||
|
$injector,
|
||||||
|
$rootScope,
|
||||||
contextSrv: ContextSrv
|
contextSrv: ContextSrv
|
||||||
) {
|
) {
|
||||||
return {
|
return {
|
||||||
@ -38,7 +40,11 @@ export function reactContainer(
|
|||||||
component = component.default;
|
component = component.default;
|
||||||
}
|
}
|
||||||
|
|
||||||
const props = { };
|
const props = {
|
||||||
|
$injector: $injector,
|
||||||
|
$rootScope: $rootScope,
|
||||||
|
$scope: scope,
|
||||||
|
};
|
||||||
|
|
||||||
ReactDOM.render(WrapInProvider(store, component, props), elem[0]);
|
ReactDOM.render(WrapInProvider(store, component, props), elem[0]);
|
||||||
|
|
||||||
|
@ -19,6 +19,7 @@ import UsersListPage from 'app/features/users/UsersListPage';
|
|||||||
import DataSourceDashboards from 'app/features/datasources/DataSourceDashboards';
|
import DataSourceDashboards from 'app/features/datasources/DataSourceDashboards';
|
||||||
import DataSourceSettingsPage from '../features/datasources/settings/DataSourceSettingsPage';
|
import DataSourceSettingsPage from '../features/datasources/settings/DataSourceSettingsPage';
|
||||||
import OrgDetailsPage from '../features/org/OrgDetailsPage';
|
import OrgDetailsPage from '../features/org/OrgDetailsPage';
|
||||||
|
import SoloPanelPage from '../features/dashboard/containers/SoloPanelPage';
|
||||||
import config from 'app/core/config';
|
import config from 'app/core/config';
|
||||||
|
|
||||||
/** @ngInject */
|
/** @ngInject */
|
||||||
@ -51,16 +52,18 @@ export function setupAngularRoutes($routeProvider, $locationProvider) {
|
|||||||
pageClass: 'page-dashboard',
|
pageClass: 'page-dashboard',
|
||||||
})
|
})
|
||||||
.when('/d-solo/:uid/:slug', {
|
.when('/d-solo/:uid/:slug', {
|
||||||
templateUrl: 'public/app/features/panel/partials/soloPanel.html',
|
template: '<react-container />',
|
||||||
controller: 'SoloPanelCtrl',
|
pageClass: 'dashboard-solo',
|
||||||
reloadOnSearch: false,
|
resolve: {
|
||||||
pageClass: 'page-dashboard',
|
component: () => SoloPanelPage,
|
||||||
|
},
|
||||||
})
|
})
|
||||||
.when('/dashboard-solo/:type/:slug', {
|
.when('/dashboard-solo/:type/:slug', {
|
||||||
templateUrl: 'public/app/features/panel/partials/soloPanel.html',
|
template: '<react-container />',
|
||||||
controller: 'SoloPanelCtrl',
|
pageClass: 'dashboard-solo',
|
||||||
reloadOnSearch: false,
|
resolve: {
|
||||||
pageClass: 'page-dashboard',
|
component: () => SoloPanelPage,
|
||||||
|
},
|
||||||
})
|
})
|
||||||
.when('/dashboard/new', {
|
.when('/dashboard/new', {
|
||||||
templateUrl: 'public/app/partials/dashboard.html',
|
templateUrl: 'public/app/partials/dashboard.html',
|
||||||
|
@ -17,6 +17,13 @@ div.flot-text {
|
|||||||
height: 100%;
|
height: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.dashboard-solo {
|
||||||
|
.footer,
|
||||||
|
.sidemenu {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.panel-solo {
|
.panel-solo {
|
||||||
position: fixed;
|
position: fixed;
|
||||||
bottom: 0;
|
bottom: 0;
|
||||||
|
Loading…
Reference in New Issue
Block a user