From 48ae93048b08478edd093c20175a0d199487252b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Torkel=20=C3=96degaard?= Date: Mon, 6 May 2019 15:26:09 +0200 Subject: [PATCH] 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 --- .../panel-common/panels_without_title.json | 904 ++++++++++++++++++ .../ThresholdsEditor.test.tsx.snap | 12 +- .../components/VizRepeater/VizRepeater.tsx | 4 +- .../src/themes/_variables.scss.tmpl.ts | 6 +- packages/grafana-ui/src/themes/default.ts | 6 +- packages/grafana-ui/src/types/theme.ts | 6 +- public/app/core/constants.ts | 4 - .../dashboard/dashgrid/DashboardPanel.tsx | 21 +- .../dashboard/dashgrid/PanelChrome.tsx | 35 +- .../dashgrid/PanelHeader/PanelHeader.tsx | 7 +- .../features/dashboard/state/PanelModel.ts | 4 + public/app/features/dashboard/utils/panel.ts | 12 +- public/app/features/panel/panel_ctrl.ts | 5 +- public/app/features/panel/panel_directive.ts | 2 +- public/app/plugins/panel/singlestat/module.ts | 17 +- public/sass/_grafana.scss | 1 + public/sass/_variables.generated.scss | 4 +- public/sass/components/_panel_editor.scss | 1 + public/sass/components/_panel_graph.scss | 4 +- public/sass/components/_panel_header.scss | 176 ++++ public/sass/components/_panel_singlestat.scss | 11 +- public/sass/pages/_dashboard.scss | 170 +--- public/sass/pages/_explore.scss | 1 - 23 files changed, 1177 insertions(+), 236 deletions(-) create mode 100644 devenv/dev-dashboards/panel-common/panels_without_title.json create mode 100644 public/sass/components/_panel_header.scss diff --git a/devenv/dev-dashboards/panel-common/panels_without_title.json b/devenv/dev-dashboards/panel-common/panels_without_title.json new file mode 100644 index 00000000000..2423da55c26 --- /dev/null +++ b/devenv/dev-dashboards/panel-common/panels_without_title.json @@ -0,0 +1,904 @@ +{ + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": "-- Grafana --", + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "type": "dashboard" + } + ] + }, + "editable": true, + "gnetId": null, + "graphTooltip": 0, + "links": [], + "panels": [ + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": ["#299c46", "#5794F2", "#d44a3a"], + "description": "asdasdas", + "format": "ms", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + "h": 4, + "w": 11, + "x": 0, + "y": 0 + }, + "id": 8, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "100%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": true, + "lineColor": "rgb(31, 120, 193)", + "show": true + }, + "tableColumn": "", + "targets": [ + { + "refId": "A", + "scenarioId": "random_walk" + } + ], + "thresholds": "", + "timeFrom": null, + "timeShift": "2h", + "title": "Title", + "type": "singlestat", + "valueFontSize": "120%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "avg" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": ["#299c46", "#5794F2", "#d44a3a"], + "description": "asdasdas", + "format": "ms", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + "h": 4, + "w": 13, + "x": 11, + "y": 0 + }, + "id": 2, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "100%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": true, + "lineColor": "rgb(31, 120, 193)", + "show": true + }, + "tableColumn": "", + "targets": [ + { + "refId": "A", + "scenarioId": "random_walk" + } + ], + "thresholds": "", + "timeFrom": null, + "timeShift": "2h", + "title": "", + "type": "singlestat", + "valueFontSize": "120%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "avg" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": ["#299c46", "#5794F2", "#d44a3a"], + "description": "asdasdas", + "format": "ms", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + "h": 4, + "w": 11, + "x": 0, + "y": 4 + }, + "id": 4, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "100%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": true, + "lineColor": "rgb(31, 120, 193)", + "show": true + }, + "tableColumn": "", + "targets": [ + { + "refId": "A", + "scenarioId": "random_walk" + } + ], + "thresholds": "", + "timeFrom": null, + "timeShift": "2h", + "title": "Panel Title", + "type": "singlestat", + "valueFontSize": "120%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "avg" + }, + { + "cacheTimeout": null, + "description": "asdasdas", + "gridPos": { + "h": 4, + "w": 6, + "x": 11, + "y": 4 + }, + "id": 9, + "links": [], + "options": { + "maxValue": 100, + "minValue": 0, + "orientation": "auto", + "showThresholdLabels": false, + "showThresholdMarkers": true, + "thresholds": [ + { + "color": "green", + "index": 0, + "value": null + }, + { + "color": "red", + "index": 1, + "value": 80 + } + ], + "valueMappings": [], + "valueOptions": { + "decimals": null, + "prefix": "", + "stat": "mean", + "suffix": "", + "unit": "none" + } + }, + "pluginVersion": "6.2.0-pre", + "targets": [ + { + "refId": "A", + "scenarioId": "random_walk" + } + ], + "timeFrom": null, + "timeShift": "2h", + "title": "Panel Title", + "type": "gauge" + }, + { + "cacheTimeout": null, + "description": "asdasdas", + "gridPos": { + "h": 4, + "w": 7, + "x": 17, + "y": 4 + }, + "id": 11, + "links": [], + "options": { + "maxValue": 100, + "minValue": 0, + "orientation": "auto", + "showThresholdLabels": false, + "showThresholdMarkers": true, + "thresholds": [ + { + "color": "green", + "index": 0, + "value": null + }, + { + "color": "red", + "index": 1, + "value": 80 + } + ], + "valueMappings": [], + "valueOptions": { + "decimals": null, + "prefix": "", + "stat": "mean", + "suffix": "", + "unit": "none" + } + }, + "pluginVersion": "6.2.0-pre", + "targets": [ + { + "refId": "A", + "scenarioId": "random_walk" + } + ], + "timeFrom": null, + "timeShift": "2h", + "title": "Panel Title", + "type": "gauge" + }, + { + "gridPos": { + "h": 4, + "w": 11, + "x": 0, + "y": 8 + }, + "id": 15, + "links": [], + "options": { + "content": "# Title\n\nFor markdown syntax help: [commonmark.org/help](https://commonmark.org/help/)\n\n\n", + "mode": "markdown" + }, + "timeFrom": null, + "timeShift": null, + "title": "", + "type": "text2" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": ["#299c46", "rgba(237, 129, 40, 0.89)", "#d44a3a"], + "description": "asdasdas", + "format": "none", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": true, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + "h": 4, + "w": 6, + "x": 11, + "y": 8 + }, + "id": 10, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "pluginVersion": "6.2.0-pre", + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": false, + "lineColor": "rgb(31, 120, 193)", + "show": false + }, + "tableColumn": "", + "targets": [ + { + "refId": "A", + "scenarioId": "random_walk" + } + ], + "thresholds": "", + "timeFrom": null, + "timeShift": "2h", + "title": "", + "type": "singlestat", + "valueFontSize": "80%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "avg" + }, + { + "cacheTimeout": null, + "description": "asdasdas", + "gridPos": { + "h": 4, + "w": 7, + "x": 17, + "y": 8 + }, + "id": 12, + "links": [], + "options": { + "maxValue": 100, + "minValue": 0, + "orientation": "auto", + "showThresholdLabels": false, + "showThresholdMarkers": true, + "thresholds": [ + { + "color": "green", + "index": 0, + "value": null + }, + { + "color": "red", + "index": 1, + "value": 80 + } + ], + "valueMappings": [], + "valueOptions": { + "decimals": null, + "prefix": "", + "stat": "mean", + "suffix": "", + "unit": "none" + } + }, + "pluginVersion": "6.2.0-pre", + "targets": [ + { + "refId": "A", + "scenarioId": "random_walk" + } + ], + "timeFrom": null, + "timeShift": "2h", + "title": "", + "type": "gauge" + }, + { + "cacheTimeout": null, + "description": "", + "gridPos": { + "h": 6, + "w": 11, + "x": 0, + "y": 12 + }, + "id": 3, + "links": [], + "options": { + "displayMode": "gradient", + "fieldOptions": { + "defaults": { + "max": 100, + "min": 0 + }, + "mappings": [], + "override": {}, + "stats": ["mean"], + "thresholds": [ + { + "color": "green", + "index": 0, + "value": null + }, + { + "color": "red", + "index": 1, + "value": 80 + } + ], + "title": "Testing", + "values": false + }, + "maxValue": 100, + "minValue": 0, + "orientation": "horizontal", + "thresholds": [ + { + "color": "green", + "index": 0, + "value": null + }, + { + "color": "red", + "index": 1, + "value": 80 + } + ], + "valueMappings": [], + "valueOptions": { + "decimals": null, + "prefix": "", + "stat": "mean", + "suffix": "", + "unit": "none" + } + }, + "targets": [ + { + "refId": "A", + "scenarioId": "random_walk" + }, + { + "refId": "B", + "scenarioId": "random_walk" + } + ], + "timeFrom": null, + "timeShift": "2h", + "title": "", + "type": "bargauge" + }, + { + "cacheTimeout": null, + "description": "asdasdas", + "gridPos": { + "h": 6, + "w": 13, + "x": 11, + "y": 12 + }, + "id": 5, + "links": [], + "options": { + "displayMode": "gradient", + "fieldOptions": { + "defaults": { + "max": 100, + "min": 0 + }, + "mappings": [], + "override": {}, + "stats": ["mean"], + "thresholds": [ + { + "color": "green", + "index": 0, + "value": null + }, + { + "color": "red", + "index": 1, + "value": 80 + } + ], + "title": "Testing", + "values": false + }, + "maxValue": 100, + "minValue": 0, + "orientation": "horizontal", + "thresholds": [ + { + "color": "green", + "index": 0, + "value": null + }, + { + "color": "red", + "index": 1, + "value": 80 + } + ], + "valueMappings": [], + "valueOptions": { + "decimals": null, + "prefix": "", + "stat": "mean", + "suffix": "", + "unit": "none" + } + }, + "targets": [ + { + "refId": "A", + "scenarioId": "slow_query", + "stringInput": "1s" + }, + { + "refId": "B", + "scenarioId": "slow_query", + "stringInput": "1s" + } + ], + "timeFrom": null, + "timeShift": "2h", + "title": "My cool pane title", + "type": "bargauge" + }, + { + "cacheTimeout": null, + "description": "asdasdas", + "gridPos": { + "h": 4, + "w": 24, + "x": 0, + "y": 18 + }, + "id": 7, + "links": [], + "options": { + "displayMode": "gradient", + "fieldOptions": { + "defaults": { + "max": 100, + "min": 0 + }, + "mappings": [], + "override": {}, + "stats": ["mean"], + "thresholds": [ + { + "color": "green", + "index": 0, + "value": null + }, + { + "color": "red", + "index": 1, + "value": 80 + } + ], + "title": "Testing", + "values": false + }, + "maxValue": 100, + "minValue": 0, + "orientation": "horizontal", + "thresholds": [ + { + "color": "green", + "index": 0, + "value": null + }, + { + "color": "red", + "index": 1, + "value": 80 + } + ], + "valueMappings": [], + "valueOptions": { + "decimals": null, + "prefix": "", + "stat": "mean", + "suffix": "", + "unit": "none" + } + }, + "targets": [ + { + "refId": "A", + "scenarioId": "slow_query", + "stringInput": "10s" + } + ], + "timeFrom": null, + "timeShift": null, + "title": "My cool pane title", + "type": "bargauge" + }, + { + "aliasColors": {}, + "bars": false, + "cacheTimeout": null, + "dashLength": 10, + "dashes": false, + "description": "asdasdas", + "fill": 1, + "gridPos": { + "h": 6, + "w": 11, + "x": 0, + "y": 22 + }, + "id": 6, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "refId": "A", + "scenarioId": "slow_query", + "stringInput": "5s" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "My cool pane title", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "cacheTimeout": null, + "dashLength": 10, + "dashes": false, + "description": "", + "fill": 1, + "gridPos": { + "h": 6, + "w": 13, + "x": 11, + "y": 22 + }, + "id": 13, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "refId": "A", + "scenarioId": "slow_query", + "stringInput": "5s" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + } + ], + "schemaVersion": 18, + "style": "dark", + "tags": ["gdev", "panel-tests"], + "templating": { + "list": [] + }, + "time": { + "from": "now-6h", + "to": "now" + }, + "timepicker": { + "refresh_intervals": ["5s", "10s", "30s", "1m", "5m", "15m", "30m", "1h", "2h", "1d"], + "time_options": ["5m", "15m", "1h", "6h", "12h", "24h", "2d", "7d", "30d"] + }, + "timezone": "", + "title": "Panel Tests - With & Without title", + "uid": "2WaUpZmWk", + "version": 23 +} diff --git a/packages/grafana-ui/src/components/ThresholdsEditor/__snapshots__/ThresholdsEditor.test.tsx.snap b/packages/grafana-ui/src/components/ThresholdsEditor/__snapshots__/ThresholdsEditor.test.tsx.snap index faa59ddb046..50e45051386 100644 --- a/packages/grafana-ui/src/components/ThresholdsEditor/__snapshots__/ThresholdsEditor.test.tsx.snap +++ b/packages/grafana-ui/src/components/ThresholdsEditor/__snapshots__/ThresholdsEditor.test.tsx.snap @@ -182,10 +182,8 @@ exports[`Render should render with base threshold 1`] = ` "sm": "24px", }, "name": "Grafana Dark", - "panelPadding": Object { - "horizontal": 16, - "vertical": 8, - }, + "panelHeaderHeight": 28, + "panelPadding": 8, "spacing": Object { "d": "14px", "gutter": "30px", @@ -345,10 +343,8 @@ exports[`Render should render with base threshold 1`] = ` "sm": "24px", }, "name": "Grafana Dark", - "panelPadding": Object { - "horizontal": 16, - "vertical": 8, - }, + "panelHeaderHeight": 28, + "panelPadding": 8, "spacing": Object { "d": "14px", "gutter": "30px", diff --git a/packages/grafana-ui/src/components/VizRepeater/VizRepeater.tsx b/packages/grafana-ui/src/components/VizRepeater/VizRepeater.tsx index 3ea44645c44..52b81f1f849 100644 --- a/packages/grafana-ui/src/components/VizRepeater/VizRepeater.tsx +++ b/packages/grafana-ui/src/components/VizRepeater/VizRepeater.tsx @@ -74,12 +74,12 @@ export class VizRepeater extends PureComponent, State> { if (orientation === VizOrientation.Horizontal) { repeaterStyle.flexDirection = 'column'; - itemStyles.margin = `${itemSpacing / 2}px 0`; + itemStyles.marginBottom = `${itemSpacing}px`; vizWidth = width; vizHeight = height / values.length - itemSpacing; } else { repeaterStyle.flexDirection = 'row'; - itemStyles.margin = `0 ${itemSpacing / 2}px`; + itemStyles.marginRight = `${itemSpacing}px`; vizHeight = height; vizWidth = width / values.length - itemSpacing; } diff --git a/packages/grafana-ui/src/themes/_variables.scss.tmpl.ts b/packages/grafana-ui/src/themes/_variables.scss.tmpl.ts index afecc62de29..d4a4dd6f016 100644 --- a/packages/grafana-ui/src/themes/_variables.scss.tmpl.ts +++ b/packages/grafana-ui/src/themes/_variables.scss.tmpl.ts @@ -197,9 +197,9 @@ $side-menu-width: 60px; // dashboard $dashboard-padding: $space-md; -$panel-padding: 0 ${theme.panelPadding.horizontal}px ${theme.panelPadding.vertical}px ${ - theme.panelPadding.horizontal - }px; +$panel-padding: ${theme.panelPadding}px; +$panel-header-height: ${theme.panelHeaderHeight}px; +$panel-header-z-index: 10; // tabs $tabs-padding: 10px 15px 9px; diff --git a/packages/grafana-ui/src/themes/default.ts b/packages/grafana-ui/src/themes/default.ts index 4a0e42312b7..c9f2183e91f 100644 --- a/packages/grafana-ui/src/themes/default.ts +++ b/packages/grafana-ui/src/themes/default.ts @@ -72,10 +72,8 @@ const theme: GrafanaThemeCommons = { md: '32px', lg: '48px', }, - panelPadding: { - horizontal: 16, - vertical: 8, - }, + panelPadding: 8, + panelHeaderHeight: 28, zIndex: { dropdown: '1000', navbarFixed: '1020', diff --git a/packages/grafana-ui/src/types/theme.ts b/packages/grafana-ui/src/types/theme.ts index 2409a837ea9..23857cc9c34 100644 --- a/packages/grafana-ui/src/types/theme.ts +++ b/packages/grafana-ui/src/types/theme.ts @@ -77,10 +77,8 @@ export interface GrafanaThemeCommons { md: string; lg: string; }; - panelPadding: { - horizontal: number; - vertical: number; - }; + panelPadding: number; + panelHeaderHeight: number; zIndex: { dropdown: string; navbarFixed: string; diff --git a/public/app/core/constants.ts b/public/app/core/constants.ts index d51c4cf83d6..2fd634ee157 100644 --- a/public/app/core/constants.ts +++ b/public/app/core/constants.ts @@ -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; diff --git a/public/app/features/dashboard/dashgrid/DashboardPanel.tsx b/public/app/features/dashboard/dashgrid/DashboardPanel.tsx index 8b5b6138c75..e076ee5093c 100644 --- a/public/app/features/dashboard/dashgrid/DashboardPanel.tsx +++ b/public/app/features/dashboard/dashgrid/DashboardPanel.tsx @@ -129,16 +129,21 @@ export class DashboardPanel extends PureComponent { this.props.dashboard.setPanelFocus(0); }; - renderReactPanel() { + renderPanel() { const { dashboard, panel, isFullscreen, isInView } = this.props; const { plugin } = this.state; + if (plugin.angularPanelCtrl) { + return
(this.element = element)} className="panel-height-helper" />; + } + return ( {({ width, height }) => { if (width === 0) { return null; } + return ( { ); } - renderAngularPanel() { - return
(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 { 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 { }); return ( -
+
{ onMouseLeave={this.onMouseLeave} style={styles} > - {plugin.angularPanelCtrl ? this.renderAngularPanel() : this.renderReactPanel()} + {this.renderPanel()}
)} /> diff --git a/public/app/features/dashboard/dashgrid/PanelChrome.tsx b/public/app/features/dashboard/dashgrid/PanelChrome.tsx index 23ffc5c88ca..5a6d35a4427 100644 --- a/public/app/features/dashboard/dashgrid/PanelChrome.tsx +++ b/public/app/features/dashboard/dashgrid/PanelChrome.tsx @@ -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 { 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 { 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 { 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 { 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 (
{ 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 ( <> { // 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 + ); +} diff --git a/public/app/features/panel/panel_ctrl.ts b/public/app/features/panel/panel_ctrl.ts index d3283c4caec..e81312aa0de 100644 --- a/public/app/features/panel/panel_ctrl.ts +++ b/public/app/features/panel/panel_ctrl.ts @@ -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?) { diff --git a/public/app/features/panel/panel_directive.ts b/public/app/features/panel/panel_directive.ts index 8dff4de5872..68c7b64d170 100644 --- a/public/app/features/panel/panel_directive.ts +++ b/public/app/features/panel/panel_directive.ts @@ -6,7 +6,7 @@ import baron from 'baron'; const module = angular.module('grafana.directives'); const panelTemplate = ` -
+
diff --git a/public/app/plugins/panel/singlestat/module.ts b/public/app/plugins/panel/singlestat/module.ts index 34aff09c2ff..d0fa3c3183e 100644 --- a/public/app/plugins/panel/singlestat/module.ts +++ b/public/app/plugins/panel/singlestat/module.ts @@ -430,7 +430,7 @@ class SingleStatCtrl extends MetricsPanelCtrl { const plotCanvas = $('
'); 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 = $('
'); 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'; } diff --git a/public/sass/_grafana.scss b/public/sass/_grafana.scss index 8897e40b655..16618da6486 100644 --- a/public/sass/_grafana.scss +++ b/public/sass/_grafana.scss @@ -99,6 +99,7 @@ @import 'components/page_loader'; @import 'components/toggle_button_group'; @import 'components/popover-box'; +@import 'components/panel_header'; // LOAD @grafana/ui components @import '../../packages/grafana-ui/src/index'; diff --git a/public/sass/_variables.generated.scss b/public/sass/_variables.generated.scss index 510e5649974..8ef586b72f9 100644 --- a/public/sass/_variables.generated.scss +++ b/public/sass/_variables.generated.scss @@ -200,7 +200,9 @@ $side-menu-width: 60px; // dashboard $dashboard-padding: $space-md; -$panel-padding: 0 16px 8px 16px; +$panel-padding: 8px; +$panel-header-height: 28px; +$panel-header-z-index: 10; // tabs $tabs-padding: 10px 15px 9px; diff --git a/public/sass/components/_panel_editor.scss b/public/sass/components/_panel_editor.scss index a50ab0d072d..c1202356805 100644 --- a/public/sass/components/_panel_editor.scss +++ b/public/sass/components/_panel_editor.scss @@ -6,6 +6,7 @@ .panel-wrapper { height: 100%; + position: relative; &--edit { height: 40%; diff --git a/public/sass/components/_panel_graph.scss b/public/sass/components/_panel_graph.scss index 5bfd0abc86c..bc4cc773c39 100644 --- a/public/sass/components/_panel_graph.scss +++ b/public/sass/components/_panel_graph.scss @@ -352,7 +352,7 @@ .left-yaxis-label { top: 50%; - left: 2px; + left: 8px; transform: translateX(-50%) translateY(-50%) rotate(-90deg); // this is needed for phantomsjs 2.1 -webkit-transform: translateX(-50%) translateY(-50%) rotate(-90deg); @@ -360,7 +360,7 @@ .right-yaxis-label { top: 50%; - right: 2px; + right: 8px; transform: translateX(50%) translateY(-50%) rotate(90deg); // this is needed for phantomsjs 2.1 -webkit-transform: translateX(50%) translateY(-50%) rotate(90deg); diff --git a/public/sass/components/_panel_header.scss b/public/sass/components/_panel_header.scss new file mode 100644 index 00000000000..3d6b52dc719 --- /dev/null +++ b/public/sass/components/_panel_header.scss @@ -0,0 +1,176 @@ +$panel-header-no-title-zindex: 1; + +.panel-header { + &:hover { + transition: background-color 0.1s ease-in-out; + background-color: $panel-header-hover-bg; + } +} + +.panel-container--no-title { + .panel-header { + position: absolute; + width: 100%; + z-index: $panel-header-z-index; + } + .panel-content { + height: 100%; + } +} + +.panel-title-container { + cursor: move; + word-wrap: break-word; + display: block; +} + +.panel-title { + border: 0px; + font-weight: $font-weight-semi-bold; + position: relative; + width: 100%; + display: flex; + flex-wrap: nowrap; + justify-content: center; + height: $panel-header-height; + align-items: center; +} + +.panel-title-text { + text-overflow: ellipsis; + overflow: hidden; + white-space: nowrap; + max-width: calc(100% - 38px); + cursor: pointer; + font-weight: $font-weight-semi-bold; + + &:hover { + color: $link-hover-color; + } + .panel-has-alert & { + max-width: calc(100% - 54px); + } +} + +.panel-menu-container { + width: 1px; + height: 19px; + display: inline-block; +} + +.panel-menu-toggle { + color: $text-color-weak; + cursor: pointer; + padding: 3px 5px; + visibility: hidden; + opacity: 0; + width: 16px; + height: 16px; + left: 1px; + top: 2px; + + &:hover { + color: $link-hover-color; + } +} + +.panel-loading { + position: absolute; + top: 4px; + right: 4px; + z-index: $panel-header-z-index + 1; + font-size: $font-size-sm; + color: $text-color-weak; +} + +.panel-empty { + display: flex; + align-items: center; + height: 100%; + width: 100%; + + p { + text-align: center; + color: $text-muted; + font-size: $font-size-lg; + width: 100%; + } +} + +.panel-menu { + top: 25px; + left: -100px; +} + +.panel-info-corner-inner { + width: 0; + height: 0; + position: absolute; + left: 0; + bottom: 0; +} + +@mixin panel-corner-color($corner-bg) { + .panel-info-corner-inner { + border-left: $panel-header-height solid $corner-bg; + border-right: none; + border-bottom: $panel-header-height solid transparent; + } +} + +.panel-info-corner { + color: $text-muted; + cursor: pointer; + position: absolute; + display: none; + left: 0; + width: $panel-header-height; + height: $panel-header-height; + top: 0; + + .fa { + position: relative; + top: -2px; + left: 6px; + font-size: 75%; + z-index: $panel-header-no-title-zindex + 2; + } + + &--info { + display: block; + @include panel-corner-color(lighten($panel-corner, 4%)); + .fa:before { + content: '\f129'; + } + } + + &--links { + display: block; + @include panel-corner-color(lighten($panel-corner, 4%)); + .fa { + left: 4px; + } + .fa:before { + content: '\f08e'; + } + } + + &--error { + display: block; + color: $white; + @include panel-corner-color($popover-error-bg); + .fa:before { + content: '\f12a'; + } + } +} + +.panel-time-info { + font-weight: $font-weight-semi-bold; + float: right; + margin-right: 8px; + color: $blue; + font-size: 85%; + position: absolute; + right: 0; +} diff --git a/public/sass/components/_panel_singlestat.scss b/public/sass/components/_panel_singlestat.scss index d680941bfb1..708fd65de94 100644 --- a/public/sass/components/_panel_singlestat.scss +++ b/public/sass/components/_panel_singlestat.scss @@ -14,6 +14,15 @@ z-index: 1; font-size: 3em; font-weight: $font-weight-semi-bold; + // helps make the title feel more centered when there is a panel title + padding-bottom: $panel-padding; +} + +// Helps +.panel-container--no-title { + .singlestat-panel-value-container { + padding-bottom: 0; + } } .singlestat-panel-prefix { @@ -21,5 +30,5 @@ } #flotGagueValue0 { - font-weight: bold; //please dont hurt me for this! + font-weight: $font-weight-semi-bold; //please dont hurt me for this! } diff --git a/public/sass/pages/_dashboard.scss b/public/sass/pages/_dashboard.scss index c795f3f2dcb..0d989719f05 100644 --- a/public/sass/pages/_dashboard.scss +++ b/public/sass/pages/_dashboard.scss @@ -79,9 +79,9 @@ div.flot-text { .panel-content { padding: $panel-padding; - height: calc(100% - 27px); + height: calc(100% - #{$panel-header-height}); + width: 100%; position: relative; - // Fixes scrolling on mobile devices overflow: auto; } @@ -93,172 +93,6 @@ div.flot-text { } } -.panel-title-container { - min-height: 9px; - cursor: move; - word-wrap: break-word; - display: block; -} - -.panel-title { - border: 0px; - font-weight: $font-weight-semi-bold; - position: relative; - width: 100%; - display: flex; - flex-wrap: nowrap; - justify-content: center; - padding: 4px 0 4px; -} - -.panel-title-text { - text-overflow: ellipsis; - overflow: hidden; - white-space: nowrap; - max-width: calc(100% - 38px); - cursor: pointer; - font-weight: $font-weight-semi-bold; - - &:hover { - color: $link-hover-color; - } - .panel-has-alert & { - max-width: calc(100% - 54px); - } -} - -.panel-menu-container { - width: 1px; - height: 19px; - display: inline-block; -} - -.panel-menu-toggle { - color: $text-color-weak; - cursor: pointer; - padding: 3px 5px; - visibility: hidden; - opacity: 0; - width: 16px; - height: 16px; - left: 1px; - top: 2px; - - &:hover { - color: $link-hover-color; - } -} - -.panel-loading { - position: absolute; - top: -3px; - right: 0px; - z-index: 800; - font-size: $font-size-sm; - color: $text-color-weak; -} - -.panel-empty { - display: flex; - align-items: center; - height: 100%; - width: 100%; - - p { - text-align: center; - color: $text-muted; - font-size: $font-size-lg; - width: 100%; - } -} - -.panel-header { - &:hover { - transition: background-color 0.1s ease-in-out; - background-color: $panel-header-hover-bg; - } -} - -.panel-menu { - top: 25px; - left: -100px; -} - -.panel-info-corner-inner { - width: 0; - height: 0; - position: absolute; - left: 0; - bottom: 0; -} - -@mixin panel-corner-color($corner-bg) { - .panel-info-corner-inner { - border-left: 27px solid $corner-bg; - border-right: none; - border-bottom: 27px solid transparent; - } -} - -.panel-info-corner { - color: $text-muted; - cursor: pointer; - position: absolute; - display: none; - left: 0; - width: 27px; - height: 27px; - top: 0; - z-index: 1; - - .fa { - position: relative; - top: -2px; - left: 6px; - font-size: 75%; - z-index: 1; - } - - &--info { - display: block; - @include panel-corner-color(lighten($panel-corner, 4%)); - .fa:before { - content: '\f129'; - } - } - - &--links { - display: block; - @include panel-corner-color(lighten($panel-corner, 4%)); - .fa { - left: 4px; - } - .fa:before { - content: '\f08e'; - } - } - - &--error { - display: block; - color: $white; - @include panel-corner-color($popover-error-bg); - .fa:before { - content: '\f12a'; - } - } -} - -.panel-time-info { - font-weight: bold; - float: right; - margin-right: 15px; - color: $blue; - font-size: 85%; - position: absolute; - top: 4px; - right: 0; -} - .dashboard-header { font-size: $font-size-h3; text-align: center; diff --git a/public/sass/pages/_explore.scss b/public/sass/pages/_explore.scss index fd0a14193ab..dba0614e11b 100644 --- a/public/sass/pages/_explore.scss +++ b/public/sass/pages/_explore.scss @@ -164,7 +164,6 @@ padding: $space-sm $space-md 0 $space-md; display: flex; cursor: pointer; - margin-bottom: $space-sm; transition: all 0.1s linear; }