diff --git a/public/app/core/components/TimelineChart/utils.test.ts b/public/app/core/components/TimelineChart/utils.test.ts index 6dc82194d0c..f5a823d6f29 100644 --- a/public/app/core/components/TimelineChart/utils.test.ts +++ b/public/app/core/components/TimelineChart/utils.test.ts @@ -62,6 +62,18 @@ describe('prepare timeline graph', () => { expect(info.warn).toEqual('No graphable fields'); }); + it('errors with no frame', () => { + const info = prepareTimelineFields(undefined, true, timeRange, theme); + expect(info.frames).toBeUndefined(); + expect(info.warn).toBe(''); + }); + + it('errors with empty frame', () => { + const info = prepareTimelineFields([], true, timeRange, theme); + expect(info.frames).toBeUndefined(); + expect(info.warn).toBe(''); + }); + it('will merge duplicate values', () => { const frames = [ toDataFrame({ diff --git a/public/app/core/components/TimelineChart/utils.ts b/public/app/core/components/TimelineChart/utils.ts index c22dfc574e3..7df47641af7 100644 --- a/public/app/core/components/TimelineChart/utils.ts +++ b/public/app/core/components/TimelineChart/utils.ts @@ -23,6 +23,7 @@ import { SpecialValueMatch, } from '@grafana/data'; import { maybeSortFrame, NULL_RETAIN } from '@grafana/data/internal'; +import { t } from '@grafana/i18n'; import { VizLegendOptions, AxisPlacement, @@ -309,8 +310,9 @@ export function prepareTimelineFields( timeRange: TimeRange, theme: GrafanaTheme2 ): { frames?: DataFrame[]; warn?: string } { + // this allows PanelDataErrorView to show the default noValue message if (!series?.length) { - return { warn: 'No data in response' }; + return { warn: '' }; } cacheFieldDisplayNames(series); @@ -436,10 +438,10 @@ export function prepareTimelineFields( } if (!hasTimeseries) { - return { warn: 'Data does not have a time field' }; + return { warn: t('timeline.missing-field.time', 'Data does not have a time field') }; } if (!frames.length) { - return { warn: 'No graphable fields' }; + return { warn: t('timeline.missing-field.all', 'No graphable fields') }; } return { frames }; diff --git a/public/app/features/panel/components/PanelDataErrorView.tsx b/public/app/features/panel/components/PanelDataErrorView.tsx index 7aa2e4b08f7..339a33d84a2 100644 --- a/public/app/features/panel/components/PanelDataErrorView.tsx +++ b/public/app/features/panel/components/PanelDataErrorView.tsx @@ -8,7 +8,7 @@ import { VisualizationSuggestion, } from '@grafana/data'; import { selectors } from '@grafana/e2e-selectors'; -import { Trans } from '@grafana/i18n'; +import { t, Trans } from '@grafana/i18n'; import { PanelDataErrorViewProps, locationService } from '@grafana/runtime'; import { VizPanel } from '@grafana/scenes'; import { usePanelContext, useStyles2 } from '@grafana/ui'; @@ -132,22 +132,22 @@ function getMessageFor( } if (!data.series || data.series.length === 0 || data.series.every((frame) => frame.length === 0)) { - return fieldConfig?.defaults.noValue ?? 'No data'; + return fieldConfig?.defaults.noValue ?? t('panel.panel-data-error-view.no-value.default', 'No data'); } if (needsStringField && !dataSummary.hasStringField) { - return 'Data is missing a string field'; + return t('panel.panel-data-error-view.missing-value.string', 'Data is missing a string field'); } if (needsNumberField && !dataSummary.hasNumberField) { - return 'Data is missing a number field'; + return t('panel.panel-data-error-view.missing-value.number', 'Data is missing a number field'); } if (needsTimeField && !dataSummary.hasTimeField) { - return 'Data is missing a time field'; + return t('panel.panel-data-error-view.missing-value.time', 'Data is missing a time field'); } - return 'Cannot visualize data'; + return t('panel.panel-data-error-view.missing-value.unknown', 'Cannot visualize data'); } const getStyles = (theme: GrafanaTheme2) => { diff --git a/public/app/plugins/panel/barchart/utils.test.ts b/public/app/plugins/panel/barchart/utils.test.ts index f2407cb3a79..4262342cd82 100644 --- a/public/app/plugins/panel/barchart/utils.test.ts +++ b/public/app/plugins/panel/barchart/utils.test.ts @@ -166,14 +166,14 @@ describe('BarChart utils', () => { }); describe('prepareGraphableFrames', () => { - it('will warn when there is no frames in the response', () => { + it('will return empty string when there are no frames in the response', () => { const info = prepSeries([], fieldConfig, StackingMode.None, createTheme()); - const warning = assertIsDefined('warn' in info ? info : null); - expect(warning.warn).toEqual('No data in response'); + expect(info.warn).toBe(''); + expect(info.series).toHaveLength(0); }); - it('will warn when there is no data in the response', () => { + it('will return empty string when there is no data in the response', () => { const info = prepSeries( [ { @@ -185,9 +185,9 @@ describe('BarChart utils', () => { StackingMode.None, createTheme() ); - const warning = assertIsDefined('warn' in info ? info : null); - expect(warning.warn).toEqual('No data in response'); + expect(info.warn).toBe(''); + expect(info.series).toHaveLength(0); }); it('will warn when there is no string or time field', () => { @@ -201,7 +201,7 @@ describe('BarChart utils', () => { const info = prepSeries([df], fieldConfig, StackingMode.None, createTheme()); const warning = assertIsDefined('warn' in info ? info : null); - expect(warning.warn).toEqual('Bar charts requires a string or time field'); + expect(warning.warn).toEqual('Bar charts require a string or time field'); }); it('will warn when there are no numeric fields in the response', () => { diff --git a/public/app/plugins/panel/barchart/utils.ts b/public/app/plugins/panel/barchart/utils.ts index fba262b7abe..36d66a73979 100644 --- a/public/app/plugins/panel/barchart/utils.ts +++ b/public/app/plugins/panel/barchart/utils.ts @@ -14,6 +14,7 @@ import { outerJoinDataFrames, } from '@grafana/data'; import { decoupleHideFromState } from '@grafana/data/internal'; +import { t } from '@grafana/i18n'; import { AxisColorMode, AxisPlacement, @@ -56,8 +57,13 @@ export function prepSeries( xFieldName?: string, colorFieldName?: string ): BarSeries { + // this allows PanelDataErrorView to show the default noValue message if (frames.length === 0 || frames.every((fr) => fr.length === 0)) { - return { series: [], _rest: [], warn: 'No data in response' }; + return { + warn: '', + series: [], + _rest: [], + }; } cacheFieldDisplayNames(frames); @@ -120,7 +126,7 @@ export function prepSeries( let warn: string | null = null; if (fields.length === 1) { - warn = 'No numeric fields found'; + warn = t('bar-chart.warn.missing-numeric', 'No numeric fields found'); } frame.fields = fields; @@ -141,7 +147,7 @@ export function prepSeries( series: [], _rest: [], color: null, - warn: 'Bar charts requires a string or time field', + warn: t('bar-chart.warn.missing-series', 'Bar charts require a string or time field'), }; } diff --git a/public/app/plugins/panel/state-timeline/StateTimelinePanel.tsx b/public/app/plugins/panel/state-timeline/StateTimelinePanel.tsx index 4f83480e765..8182fde105c 100644 --- a/public/app/plugins/panel/state-timeline/StateTimelinePanel.tsx +++ b/public/app/plugins/panel/state-timeline/StateTimelinePanel.tsx @@ -1,6 +1,7 @@ import { useMemo, useState } from 'react'; import { DashboardCursorSync, PanelProps } from '@grafana/data'; +import { PanelDataErrorView } from '@grafana/runtime'; import { AxisPlacement, EventBusPlugin, @@ -37,8 +38,10 @@ export const StateTimelinePanel = ({ options, width, height, + fieldConfig, replaceVariables, onChangeTimeRange, + id: panelId, }: TimelinePanelProps) => { const theme = useTheme2(); @@ -64,12 +67,8 @@ export const StateTimelinePanel = ({ const timezones = useMemo(() => getTimezones(options.timezone, timeZone), [options.timezone, timeZone]); - if (!paginatedFrames || warn) { - return ( -
{warn ?? 'No data found in response'}
-{warn ?? 'No data found in response'}
-