Inspector: Show transformation query errors (#73344)

This commit is contained in:
Ryan McKinley 2023-09-20 09:09:51 -07:00 committed by GitHub
parent 9def0d2305
commit a1250632c3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 43 additions and 19 deletions

View File

@ -1,7 +1,16 @@
import { isEmpty } from 'lodash'; import { isEmpty } from 'lodash';
import React, { useState } from 'react'; import React, { useState } from 'react';
import { CoreApp, DataSourceApi, formattedValueToString, getValueFormat, PanelData, PanelPlugin } from '@grafana/data'; import {
CoreApp,
DataSourceApi,
formattedValueToString,
getValueFormat,
PanelData,
PanelPlugin,
LoadingState,
DataQueryError,
} from '@grafana/data';
import { getTemplateSrv } from '@grafana/runtime'; import { getTemplateSrv } from '@grafana/runtime';
import { Drawer, Tab, TabsBar } from '@grafana/ui'; import { Drawer, Tab, TabsBar } from '@grafana/ui';
import { t, Trans } from 'app/core/internationalization'; import { t, Trans } from 'app/core/internationalization';
@ -51,10 +60,7 @@ export const InspectContent = ({
return null; return null;
} }
let errors = data?.errors; let errors = getErrors(data);
if (!errors?.length && data?.error) {
errors = [data.error];
}
// Validate that the active tab is actually valid and allowed // Validate that the active tab is actually valid and allowed
let activeTab = currentTab; let activeTab = currentTab;
@ -114,6 +120,22 @@ export const InspectContent = ({
); );
}; };
// This will combine
function getErrors(data: PanelData | undefined): DataQueryError[] {
let errors = data?.errors ?? [];
if (data?.error && !errors.includes(data.error)) {
errors = [data.error, ...errors];
}
if (!errors.length && data?.state === LoadingState.Error) {
return [
{
message: 'Error loading data',
},
];
}
return errors;
}
function formatStats(data: PanelData) { function formatStats(data: PanelData) {
const { request } = data; const { request } = data;

View File

@ -28,16 +28,16 @@ export interface ConnectedProps {
export type Props = OwnProps & ConnectedProps; export type Props = OwnProps & ConnectedProps;
const PanelInspectorUnconnected = ({ panel, dashboard, plugin }: Props) => { const PanelInspectorUnconnected = ({ panel, dashboard, plugin }: Props) => {
const location = useLocation();
const defaultTab = new URLSearchParams(location.search).get('inspectTab') as InspectTab;
const [dataOptions, setDataOptions] = useState<GetDataOptions>({ const [dataOptions, setDataOptions] = useState<GetDataOptions>({
withTransforms: false, withTransforms: defaultTab === InspectTab.Error,
withFieldConfig: true, withFieldConfig: true,
}); });
const location = useLocation(); const { data, isLoading, hasError } = usePanelLatestData(panel, dataOptions, true);
const { data, isLoading, error } = usePanelLatestData(panel, dataOptions, false);
const metaDs = useDatasourceMetadata(data); const metaDs = useDatasourceMetadata(data);
const tabs = useInspectTabs(panel, dashboard, plugin, error, metaDs); const tabs = useInspectTabs(panel, dashboard, plugin, hasError, metaDs);
const defaultTab = new URLSearchParams(location.search).get('inspectTab') as InspectTab;
const onClose = () => { const onClose = () => {
locationService.partial({ locationService.partial({

View File

@ -1,7 +1,7 @@
import { useMemo } from 'react'; import { useMemo } from 'react';
import useAsync from 'react-use/lib/useAsync'; import useAsync from 'react-use/lib/useAsync';
import { DataQueryError, DataSourceApi, PanelData, PanelPlugin } from '@grafana/data'; import { DataSourceApi, PanelData, PanelPlugin } from '@grafana/data';
import { getDataSourceSrv } from '@grafana/runtime'; import { getDataSourceSrv } from '@grafana/runtime';
import { t } from 'app/core/internationalization'; import { t } from 'app/core/internationalization';
import { DashboardModel, PanelModel } from 'app/features/dashboard/state'; import { DashboardModel, PanelModel } from 'app/features/dashboard/state';
@ -42,7 +42,7 @@ export const useInspectTabs = (
panel: PanelModel, panel: PanelModel,
dashboard: DashboardModel, dashboard: DashboardModel,
plugin: PanelPlugin | undefined | null, plugin: PanelPlugin | undefined | null,
error?: DataQueryError, hasError?: boolean,
metaDs?: DataSourceApi metaDs?: DataSourceApi
) => { ) => {
return useMemo(() => { return useMemo(() => {
@ -58,7 +58,7 @@ export const useInspectTabs = (
tabs.push({ label: t('dashboard.inspect.json-tab', 'JSON'), value: InspectTab.JSON }); tabs.push({ label: t('dashboard.inspect.json-tab', 'JSON'), value: InspectTab.JSON });
if (error && error.message) { if (hasError) {
tabs.push({ label: t('dashboard.inspect.error-tab', 'Error'), value: InspectTab.Error }); tabs.push({ label: t('dashboard.inspect.error-tab', 'Error'), value: InspectTab.Error });
} }
@ -66,5 +66,5 @@ export const useInspectTabs = (
tabs.push({ label: t('dashboard.inspect.query-tab', 'Query'), value: InspectTab.Query }); tabs.push({ label: t('dashboard.inspect.query-tab', 'Query'), value: InspectTab.Query });
} }
return tabs; return tabs;
}, [plugin, metaDs, dashboard, error]); }, [plugin, metaDs, dashboard, hasError]);
}; };

View File

@ -1,14 +1,14 @@
import { useEffect, useRef, useState } from 'react'; import { useEffect, useRef, useState } from 'react';
import { Unsubscribable } from 'rxjs'; import { Unsubscribable } from 'rxjs';
import { DataQueryError, LoadingState, PanelData } from '@grafana/data'; import { LoadingState, PanelData } from '@grafana/data';
import { GetDataOptions } from '../../../query/state/PanelQueryRunner'; import { GetDataOptions } from '../../../query/state/PanelQueryRunner';
import { PanelModel } from '../../state'; import { PanelModel } from '../../state';
interface UsePanelLatestData { interface UsePanelLatestData {
data?: PanelData; data?: PanelData;
error?: DataQueryError; hasError: boolean;
isLoading: boolean; isLoading: boolean;
hasSeries: boolean; hasSeries: boolean;
} }
@ -63,8 +63,10 @@ export const usePanelLatestData = (
return { return {
data: latestData, data: latestData,
error: latestData && latestData.error,
isLoading: latestData?.state === LoadingState.Loading, isLoading: latestData?.state === LoadingState.Loading,
hasSeries: latestData ? !!latestData.series : false, hasSeries: latestData ? !!latestData.series : false,
hasError: Boolean(
latestData && (latestData.error || latestData?.errors?.length || latestData.state === LoadingState.Error)
),
}; };
}; };

View File

@ -67,7 +67,7 @@ export const InspectErrorTab = ({ errors }: InspectErrorTabProps) => {
return ( return (
<> <>
{errors.map((error, index) => ( {errors.map((error, index) => (
<Alert title={error.refId || `Query ${index + 1}`} severity="error" key={index}> <Alert title={error.refId || `Error ${index + 1}`} severity="error" key={index}>
{renderError(error)} {renderError(error)}
</Alert> </Alert>
))} ))}

View File

@ -225,7 +225,7 @@ export class PanelQueryRunner {
return of({ return of({
...data, ...data,
state: LoadingState.Error, state: LoadingState.Error,
error: toDataQueryError(err), errors: [toDataQueryError(err)],
}); });
}) })
); );