diff --git a/packages/grafana-ui/src/components/TimeSeries/utils.ts b/packages/grafana-ui/src/components/TimeSeries/utils.ts index 2e7bfb1a513..44d7008a756 100644 --- a/packages/grafana-ui/src/components/TimeSeries/utils.ts +++ b/packages/grafana-ui/src/components/TimeSeries/utils.ts @@ -67,6 +67,10 @@ export const preparePlotConfigBuilder: UPlotConfigPrepFn<{ sync: DashboardCursor let xScaleUnit = '_x'; let yScaleKey = ''; + const xFieldAxisPlacement = + xField.config.custom?.axisPlacement !== AxisPlacement.Hidden ? AxisPlacement.Bottom : AxisPlacement.Hidden; + const xFieldAxisShow = xField.config.custom?.axisPlacement !== AxisPlacement.Hidden; + if (xField.type === FieldType.time) { xScaleUnit = 'time'; builder.addScale({ @@ -83,7 +87,8 @@ export const preparePlotConfigBuilder: UPlotConfigPrepFn<{ sync: DashboardCursor builder.addAxis({ scaleKey: xScaleKey, isTime: true, - placement: AxisPlacement.Bottom, + placement: xFieldAxisPlacement, + show: xFieldAxisShow, label: xField.config.custom?.axisLabel, timeZone, theme, @@ -103,7 +108,8 @@ export const preparePlotConfigBuilder: UPlotConfigPrepFn<{ sync: DashboardCursor builder.addAxis({ scaleKey: xScaleKey, - placement: AxisPlacement.Bottom, + placement: xFieldAxisPlacement, + show: xFieldAxisShow, label: xField.config.custom?.axisLabel, theme, grid: { show: xField.config.custom?.axisGridShow }, diff --git a/public/app/features/dashboard/state/DashboardMigrator.test.ts b/public/app/features/dashboard/state/DashboardMigrator.test.ts index c9a34b728dc..5dc6eef6bc3 100644 --- a/public/app/features/dashboard/state/DashboardMigrator.test.ts +++ b/public/app/features/dashboard/state/DashboardMigrator.test.ts @@ -179,7 +179,7 @@ describe('DashboardModel', () => { }); it('dashboard schema version should be set to latest', () => { - expect(model.schemaVersion).toBe(34); + expect(model.schemaVersion).toBe(35); }); it('graph thresholds should be migrated', () => { @@ -1839,6 +1839,43 @@ describe('DashboardModel', () => { expect(model.panels[3].panels[0].datasource).toEqual({ type: 'prometheus', uid: 'mock-ds-2' }); }); }); + + describe('when migrating time series axis visibility', () => { + test('preserves x axis visibility', () => { + const model = new DashboardModel({ + panels: [ + { + type: 'timeseries', + fieldConfig: { + defaults: { + custom: { + axisPlacement: 'hidden', + }, + }, + overrides: [], + }, + }, + ], + }); + + expect(model.panels[0].fieldConfig.overrides).toMatchInlineSnapshot(` + Array [ + Object { + "matcher": Object { + "id": "byType", + "options": "time", + }, + "properties": Array [ + Object { + "id": "custom.axisPlacement", + "value": "auto", + }, + ], + }, + ] + `); + }); + }); }); function createRow(options: any, panelDescriptions: any[]) { diff --git a/public/app/features/dashboard/state/DashboardMigrator.ts b/public/app/features/dashboard/state/DashboardMigrator.ts index 16e2f7f003f..5eda424eb07 100644 --- a/public/app/features/dashboard/state/DashboardMigrator.ts +++ b/public/app/features/dashboard/state/DashboardMigrator.ts @@ -13,6 +13,9 @@ import { DataQuery, DataSourceRef, DataTransformerConfig, + FieldConfigSource, + FieldMatcherID, + FieldType, getActiveThreshold, getDataSourceRef, isDataSourceRef, @@ -41,7 +44,7 @@ import { VariableHide } from '../../variables/types'; import { config } from 'app/core/config'; import { plugin as statPanelPlugin } from 'app/plugins/panel/stat/module'; import { plugin as gaugePanelPlugin } from 'app/plugins/panel/gauge/module'; -import { getStandardFieldConfigs, getStandardOptionEditors } from '@grafana/ui'; +import { AxisPlacement, getStandardFieldConfigs, getStandardOptionEditors, GraphFieldConfig } from '@grafana/ui'; import { getDataSourceSrv } from '@grafana/runtime'; import { labelsToFieldsTransformer } from '../../../../../packages/grafana-data/src/transformations/transformers/labelsToFields'; import { mergeTransformer } from '../../../../../packages/grafana-data/src/transformations/transformers/merge'; @@ -67,7 +70,7 @@ export class DashboardMigrator { let i, j, k, n; const oldVersion = this.dashboard.schemaVersion; const panelUpgrades: PanelSchemeUpgradeHandler[] = []; - this.dashboard.schemaVersion = 34; + this.dashboard.schemaVersion = 35; if (oldVersion === this.dashboard.schemaVersion) { return; @@ -724,6 +727,10 @@ export class DashboardMigrator { this.migrateCloudWatchAnnotationQuery(); } + if (oldVersion < 35) { + panelUpgrades.push(ensureXAxisVisibility); + } + if (panelUpgrades.length === 0) { return; } @@ -1205,3 +1212,35 @@ function migrateTooltipOptions(panel: PanelModel) { return panel; } + +// This migration is performed when there is a time series panel with all axes configured to be hidden +// To avoid breaking dashboards we add override that persists x-axis visibility +function ensureXAxisVisibility(panel: PanelModel) { + if (panel.type === 'timeseries') { + if ( + (panel.fieldConfig as FieldConfigSource)?.defaults.custom?.axisPlacement === + AxisPlacement.Hidden + ) { + panel.fieldConfig = { + ...panel.fieldConfig, + overrides: [ + ...panel.fieldConfig.overrides, + { + matcher: { + id: FieldMatcherID.byType, + options: FieldType.time, + }, + properties: [ + { + id: 'custom.axisPlacement', + value: AxisPlacement.Auto, + }, + ], + }, + ], + }; + } + } + + return panel; +} diff --git a/public/app/plugins/panel/barchart/utils.ts b/public/app/plugins/panel/barchart/utils.ts index 4c21c6fa17e..0e33b97acf9 100644 --- a/public/app/plugins/panel/barchart/utils.ts +++ b/public/app/plugins/panel/barchart/utils.ts @@ -131,10 +131,18 @@ export const preparePlotConfigBuilder: UPlotConfigPrepFn = ({ direction: vizOrientation.xDir, }); + const xFieldAxisPlacement = + frame.fields[0].config.custom?.axisPlacement !== AxisPlacement.Hidden + ? vizOrientation.xOri === ScaleOrientation.Horizontal + ? AxisPlacement.Bottom + : AxisPlacement.Left + : AxisPlacement.Hidden; + const xFieldAxisShow = frame.fields[0].config.custom?.axisPlacement !== AxisPlacement.Hidden; + builder.addAxis({ scaleKey: 'x', isTime: false, - placement: vizOrientation.xOri === 0 ? AxisPlacement.Bottom : AxisPlacement.Left, + placement: xFieldAxisPlacement, label: frame.fields[0].config.custom?.axisLabel, splits: config.xSplits, values: config.xValues, @@ -143,6 +151,7 @@ export const preparePlotConfigBuilder: UPlotConfigPrepFn = ({ gap: 15, tickLabelRotation: xTickLabelRotation * -1, theme, + show: xFieldAxisShow, }); let seriesIndex = 0; diff --git a/public/app/plugins/panel/timeseries/__snapshots__/migrations.test.ts.snap b/public/app/plugins/panel/timeseries/__snapshots__/migrations.test.ts.snap index fbebe31cfa9..1862a91b058 100644 --- a/public/app/plugins/panel/timeseries/__snapshots__/migrations.test.ts.snap +++ b/public/app/plugins/panel/timeseries/__snapshots__/migrations.test.ts.snap @@ -566,3 +566,28 @@ Object { }, } `; + +exports[`Graph Migrations x axis should hide x axis 1`] = ` +Object { + "defaults": Object { + "custom": Object { + "drawStyle": "points", + "spanNulls": false, + }, + }, + "overrides": Array [ + Object { + "matcher": Object { + "id": "byType", + "options": "time", + }, + "properties": Array [ + Object { + "id": "custom.axisPlacement", + "value": "hidden", + }, + ], + }, + ], +} +`; diff --git a/public/app/plugins/panel/timeseries/migrations.test.ts b/public/app/plugins/panel/timeseries/migrations.test.ts index a2a56526537..06bc7d61fac 100644 --- a/public/app/plugins/panel/timeseries/migrations.test.ts +++ b/public/app/plugins/panel/timeseries/migrations.test.ts @@ -390,6 +390,22 @@ describe('Graph Migrations', () => { expect(panel4.options.tooltip.sort).toBe(SortOrder.None); }); }); + + describe('x axis', () => { + test('should hide x axis', () => { + const old: any = { + angular: { + xaxis: { + show: false, + mode: 'time', + }, + }, + }; + const panel = {} as PanelModel; + panel.options = graphPanelChangedHandler(panel, 'graph', old, prevFieldConfig); + expect(panel.fieldConfig).toMatchSnapshot(); + }); + }); }); const customColor = { diff --git a/public/app/plugins/panel/timeseries/migrations.ts b/public/app/plugins/panel/timeseries/migrations.ts index 91d01aa2957..c62b758811e 100644 --- a/public/app/plugins/panel/timeseries/migrations.ts +++ b/public/app/plugins/panel/timeseries/migrations.ts @@ -7,6 +7,7 @@ import { FieldConfigSource, FieldMatcherID, fieldReducers, + FieldType, NullValueMode, PanelTypeChangedHandler, Threshold, @@ -434,6 +435,20 @@ export function flotToGraphOptions(angular: any): { fieldConfig: FieldConfigSour }; } + if (angular.xaxis && angular.xaxis.show === false && angular.xaxis.mode === 'time') { + overrides.push({ + matcher: { + id: FieldMatcherID.byType, + options: FieldType.time, + }, + properties: [ + { + id: 'custom.axisPlacement', + value: AxisPlacement.Hidden, + }, + ], + }); + } return { fieldConfig: { defaults: omitBy(y1, isNil), diff --git a/public/app/plugins/panel/xychart/scatter.ts b/public/app/plugins/panel/xychart/scatter.ts index 28a2a114c53..56477aaa79c 100644 --- a/public/app/plugins/panel/xychart/scatter.ts +++ b/public/app/plugins/panel/xychart/scatter.ts @@ -548,7 +548,9 @@ const prepConfig = ( builder.addAxis({ scaleKey: 'x', - placement: AxisPlacement.Bottom, + placement: + xField.config.custom?.axisPlacement !== AxisPlacement.Hidden ? AxisPlacement.Bottom : AxisPlacement.Hidden, + show: xField.config.custom?.axisPlacement !== AxisPlacement.Hidden, theme, label: xField.config.custom.axisLabel, }); @@ -571,12 +573,15 @@ const prepConfig = ( range: (u, min, max) => [min, max], }); - builder.addAxis({ - scaleKey, - theme, - label: field.config.custom.axisLabel, - values: (u, splits) => splits.map((s) => field.display!(s).text), - }); + if (field.config.custom?.axisPlacement !== AxisPlacement.Hidden) { + builder.addAxis({ + scaleKey, + theme, + placement: field.config.custom?.axisPlacement, + label: field.config.custom.axisLabel, + values: (u, splits) => splits.map((s) => field.display!(s).text), + }); + } builder.addSeries({ facets: [