mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
Panels: No title will no longer make panel header take up space (#16884)
* Panels: Initial poc of no panel titles * moving panel-container to DashboardPanel * Starting to work * Gauge fix * Panels: tweaked panel padding and title z-index stuff * Panels: changed panel padding a bit and simplified it by having same padding in vertical and horizontal * Lots of tweaks to panel padding related stuff * Updated snapshot * Added test dashboard * Final refactorings * Trim title befgor applying panel-container--no-title class * Remove unnecessary type annotation * Panels: hasTitle no need to trim * Gauge: fixed font family
This commit is contained in:
@@ -9,8 +9,4 @@ export const MIN_PANEL_HEIGHT = GRID_CELL_HEIGHT * 3;
|
||||
|
||||
export const LS_PANEL_COPY_KEY = 'panel-copy';
|
||||
|
||||
export const DASHBOARD_TOOLBAR_HEIGHT = 55;
|
||||
export const DASHBOARD_TOP_PADDING = 20;
|
||||
|
||||
export const PANEL_HEADER_HEIGHT = 27;
|
||||
export const PANEL_BORDER = 2;
|
||||
|
||||
@@ -129,16 +129,21 @@ export class DashboardPanel extends PureComponent<Props, State> {
|
||||
this.props.dashboard.setPanelFocus(0);
|
||||
};
|
||||
|
||||
renderReactPanel() {
|
||||
renderPanel() {
|
||||
const { dashboard, panel, isFullscreen, isInView } = this.props;
|
||||
const { plugin } = this.state;
|
||||
|
||||
if (plugin.angularPanelCtrl) {
|
||||
return <div ref={element => (this.element = element)} className="panel-height-helper" />;
|
||||
}
|
||||
|
||||
return (
|
||||
<AutoSizer>
|
||||
{({ width, height }) => {
|
||||
if (width === 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<PanelChrome
|
||||
plugin={plugin}
|
||||
@@ -155,10 +160,6 @@ export class DashboardPanel extends PureComponent<Props, State> {
|
||||
);
|
||||
}
|
||||
|
||||
renderAngularPanel() {
|
||||
return <div ref={element => (this.element = element)} className="panel-height-helper" />;
|
||||
}
|
||||
|
||||
render() {
|
||||
const { panel, dashboard, isFullscreen, isEditing } = this.props;
|
||||
const { plugin, angularPanel, isLazy } = this.state;
|
||||
@@ -177,7 +178,11 @@ export class DashboardPanel extends PureComponent<Props, State> {
|
||||
return null;
|
||||
}
|
||||
|
||||
const containerClass = classNames({ 'panel-editor-container': isEditing, 'panel-height-helper': !isEditing });
|
||||
const editorContainerClasses = classNames({
|
||||
'panel-editor-container': isEditing,
|
||||
'panel-height-helper': !isEditing,
|
||||
});
|
||||
|
||||
const panelWrapperClass = classNames({
|
||||
'panel-wrapper': true,
|
||||
'panel-wrapper--edit': isEditing,
|
||||
@@ -185,7 +190,7 @@ export class DashboardPanel extends PureComponent<Props, State> {
|
||||
});
|
||||
|
||||
return (
|
||||
<div className={containerClass}>
|
||||
<div className={editorContainerClasses}>
|
||||
<PanelResizer
|
||||
isEditing={isEditing}
|
||||
panel={panel}
|
||||
@@ -196,7 +201,7 @@ export class DashboardPanel extends PureComponent<Props, State> {
|
||||
onMouseLeave={this.onMouseLeave}
|
||||
style={styles}
|
||||
>
|
||||
{plugin.angularPanelCtrl ? this.renderAngularPanel() : this.renderReactPanel()}
|
||||
{this.renderPanel()}
|
||||
</div>
|
||||
)}
|
||||
/>
|
||||
|
||||
@@ -1,17 +1,18 @@
|
||||
// Libraries
|
||||
import React, { PureComponent } from 'react';
|
||||
|
||||
// Services
|
||||
import { getTimeSrv, TimeSrv } from '../services/TimeSrv';
|
||||
import classNames from 'classnames';
|
||||
import { Unsubscribable } from 'rxjs';
|
||||
|
||||
// Components
|
||||
import { PanelHeader } from './PanelHeader/PanelHeader';
|
||||
import ErrorBoundary from 'app/core/components/ErrorBoundary/ErrorBoundary';
|
||||
|
||||
// Utils
|
||||
import { applyPanelTimeOverrides } from 'app/features/dashboard/utils/panel';
|
||||
import { PANEL_HEADER_HEIGHT } from 'app/core/constants';
|
||||
// Utils & Services
|
||||
import { getTimeSrv, TimeSrv } from '../services/TimeSrv';
|
||||
import { applyPanelTimeOverrides, calculateInnerPanelHeight } from 'app/features/dashboard/utils/panel';
|
||||
import { profiler } from 'app/core/profiler';
|
||||
import { getProcessedSeriesData } from '../state/PanelQueryState';
|
||||
import templateSrv from 'app/features/templating/template_srv';
|
||||
import config from 'app/core/config';
|
||||
|
||||
// Types
|
||||
@@ -19,11 +20,6 @@ import { DashboardModel, PanelModel } from '../state';
|
||||
import { LoadingState, PanelData, PanelPlugin } from '@grafana/ui';
|
||||
import { ScopedVars } from '@grafana/ui';
|
||||
|
||||
import templateSrv from 'app/features/templating/template_srv';
|
||||
|
||||
import { getProcessedSeriesData } from '../state/PanelQueryState';
|
||||
import { Unsubscribable } from 'rxjs';
|
||||
|
||||
const DEFAULT_PLUGIN_ERROR = 'Error in plugin';
|
||||
|
||||
export interface Props {
|
||||
@@ -232,7 +228,7 @@ export class PanelChrome extends PureComponent<Props, State> {
|
||||
renderPanel(width: number, height: number): JSX.Element {
|
||||
const { panel, plugin } = this.props;
|
||||
const { renderCounter, data, isFirstLoad } = this.state;
|
||||
const PanelComponent = plugin.panel;
|
||||
const { theme } = config;
|
||||
|
||||
// This is only done to increase a counter that is used by backend
|
||||
// image rendering (phantomjs/headless chrome) to know when to capture image
|
||||
@@ -246,6 +242,9 @@ export class PanelChrome extends PureComponent<Props, State> {
|
||||
return this.renderLoadingState();
|
||||
}
|
||||
|
||||
const PanelComponent = plugin.panel;
|
||||
const innerPanelHeight = calculateInnerPanelHeight(panel, height);
|
||||
|
||||
return (
|
||||
<>
|
||||
{loading === LoadingState.Loading && this.renderLoadingState()}
|
||||
@@ -254,8 +253,8 @@ export class PanelChrome extends PureComponent<Props, State> {
|
||||
data={data}
|
||||
timeRange={data.request ? data.request.range : this.timeSrv.timeRange()}
|
||||
options={panel.getOptions(plugin.defaults)}
|
||||
width={width - 2 * config.theme.panelPadding.horizontal}
|
||||
height={height - PANEL_HEADER_HEIGHT - config.theme.panelPadding.vertical}
|
||||
width={width - theme.panelPadding * 2}
|
||||
height={innerPanelHeight}
|
||||
renderCounter={renderCounter}
|
||||
replaceVariables={this.replaceVariables}
|
||||
onOptionsChange={this.onOptionsChange}
|
||||
@@ -278,7 +277,13 @@ export class PanelChrome extends PureComponent<Props, State> {
|
||||
const { errorMessage, data } = this.state;
|
||||
const { transparent } = panel;
|
||||
|
||||
const containerClassNames = `panel-container panel-container--absolute ${transparent ? 'panel-transparent' : ''}`;
|
||||
const containerClassNames = classNames({
|
||||
'panel-container': true,
|
||||
'panel-container--absolute': true,
|
||||
'panel-container--no-title': !panel.hasTitle(),
|
||||
'panel-transparent': transparent,
|
||||
});
|
||||
|
||||
return (
|
||||
<div className={containerClassNames}>
|
||||
<PanelHeader
|
||||
|
||||
@@ -72,10 +72,13 @@ export class PanelHeader extends Component<Props, State> {
|
||||
|
||||
render() {
|
||||
const { panel, dashboard, timeInfo, scopedVars, error, isFullscreen } = this.props;
|
||||
|
||||
const panelHeaderClass = classNames({ 'panel-header': true, 'grid-drag-handle': !isFullscreen });
|
||||
const title = templateSrv.replaceWithText(panel.title, scopedVars);
|
||||
|
||||
const panelHeaderClass = classNames({
|
||||
'panel-header': true,
|
||||
'grid-drag-handle': !isFullscreen,
|
||||
});
|
||||
|
||||
return (
|
||||
<>
|
||||
<PanelHeaderCorner
|
||||
|
||||
@@ -326,6 +326,10 @@ export class PanelModel {
|
||||
return this.queryRunner;
|
||||
}
|
||||
|
||||
hasTitle() {
|
||||
return !!this.title.length;
|
||||
}
|
||||
|
||||
destroy() {
|
||||
this.events.emit('panel-teardown');
|
||||
this.events.removeAllListeners();
|
||||
|
||||
@@ -11,12 +11,13 @@ import { isString as _isString } from 'lodash';
|
||||
import * as rangeUtil from '@grafana/ui/src/utils/rangeutil';
|
||||
import * as dateMath from '@grafana/ui/src/utils/datemath';
|
||||
import appEvents from 'app/core/app_events';
|
||||
import config from 'app/core/config';
|
||||
|
||||
// Services
|
||||
import templateSrv from 'app/features/templating/template_srv';
|
||||
|
||||
// Constants
|
||||
import { LS_PANEL_COPY_KEY } from 'app/core/constants';
|
||||
import { LS_PANEL_COPY_KEY, PANEL_BORDER } from 'app/core/constants';
|
||||
|
||||
export const removePanel = (dashboard: DashboardModel, panel: PanelModel, ask: boolean) => {
|
||||
// confirm deletion
|
||||
@@ -169,3 +170,12 @@ export function getResolution(panel: PanelModel): number {
|
||||
|
||||
return panel.maxDataPoints ? panel.maxDataPoints : Math.ceil(width * (panel.gridPos.w / 24));
|
||||
}
|
||||
|
||||
export function calculateInnerPanelHeight(panel: PanelModel, containerHeight: number): number {
|
||||
return (
|
||||
containerHeight -
|
||||
(panel.hasTitle() ? config.theme.panelHeaderHeight : 0) -
|
||||
config.theme.panelPadding * 2 -
|
||||
PANEL_BORDER
|
||||
);
|
||||
}
|
||||
|
||||
@@ -11,9 +11,10 @@ import {
|
||||
copyPanel as copyPanelUtil,
|
||||
editPanelJson as editPanelJsonUtil,
|
||||
sharePanel as sharePanelUtil,
|
||||
calculateInnerPanelHeight,
|
||||
} from 'app/features/dashboard/utils/panel';
|
||||
|
||||
import { GRID_COLUMN_COUNT, PANEL_HEADER_HEIGHT, PANEL_BORDER } from 'app/core/constants';
|
||||
import { GRID_COLUMN_COUNT } from 'app/core/constants';
|
||||
|
||||
export class PanelCtrl {
|
||||
panel: any;
|
||||
@@ -202,7 +203,7 @@ export class PanelCtrl {
|
||||
|
||||
calculatePanelHeight(containerHeight) {
|
||||
this.containerHeight = containerHeight;
|
||||
this.height = this.containerHeight - (PANEL_BORDER + PANEL_HEADER_HEIGHT);
|
||||
this.height = calculateInnerPanelHeight(this.panel, containerHeight);
|
||||
}
|
||||
|
||||
render(payload?) {
|
||||
|
||||
@@ -6,7 +6,7 @@ import baron from 'baron';
|
||||
const module = angular.module('grafana.directives');
|
||||
|
||||
const panelTemplate = `
|
||||
<div class="panel-container">
|
||||
<div class="panel-container" ng-class="{'panel-container--no-title': !ctrl.panel.title.length}">
|
||||
<div class="panel-header" ng-class="{'grid-drag-handle': !ctrl.panel.fullscreen}">
|
||||
<span class="panel-info-corner">
|
||||
<i class="fa"></i>
|
||||
|
||||
@@ -430,7 +430,7 @@ class SingleStatCtrl extends MetricsPanelCtrl {
|
||||
|
||||
const plotCanvas = $('<div></div>');
|
||||
const plotCss = {
|
||||
top: '10px',
|
||||
top: '5px',
|
||||
margin: 'auto',
|
||||
position: 'relative',
|
||||
height: height * 0.9 + 'px',
|
||||
@@ -494,7 +494,7 @@ class SingleStatCtrl extends MetricsPanelCtrl {
|
||||
},
|
||||
font: {
|
||||
size: fontSize,
|
||||
family: '"Helvetica Neue", Helvetica, Arial, sans-serif',
|
||||
family: config.theme.typography.fontFamily.sansSerif,
|
||||
},
|
||||
},
|
||||
show: true,
|
||||
@@ -512,7 +512,7 @@ class SingleStatCtrl extends MetricsPanelCtrl {
|
||||
}
|
||||
|
||||
function addSparkline() {
|
||||
const width = elem.width() + 20;
|
||||
const width = elem.width();
|
||||
if (width < 30) {
|
||||
// element has not gotten it's width yet
|
||||
// delay sparkline render
|
||||
@@ -524,17 +524,16 @@ class SingleStatCtrl extends MetricsPanelCtrl {
|
||||
const plotCanvas = $('<div></div>');
|
||||
const plotCss: any = {};
|
||||
plotCss.position = 'absolute';
|
||||
plotCss.bottom = '0px';
|
||||
|
||||
if (panel.sparkline.full) {
|
||||
plotCss.bottom = '5px';
|
||||
plotCss.left = '-5px';
|
||||
plotCss.width = width - 10 + 'px';
|
||||
plotCss.left = '0px';
|
||||
plotCss.width = width + 'px';
|
||||
const dynamicHeightMargin = height <= 100 ? 5 : Math.round(height / 100) * 15 + 5;
|
||||
plotCss.height = height - dynamicHeightMargin + 'px';
|
||||
} else {
|
||||
plotCss.bottom = '0px';
|
||||
plotCss.left = '-5px';
|
||||
plotCss.width = width - 10 + 'px';
|
||||
plotCss.left = '0px';
|
||||
plotCss.width = width + 'px';
|
||||
plotCss.height = Math.floor(height * 0.25) + 'px';
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user