Dashboard: Add dashboard validation warning to save drawer (#55732)

* add api route for validating a dashboard json

* add feature flag for showDashboardValidationWarnings

* tidy up

* comments and messages

* swagger specs

* fix typo

* more swagger

* tests!

* tidy test a little bit

* no more ioutil

* api will return different status code depending on validation error

* clean up

* handle 4xx errors

* remove console.log

* fix backend tests

* tidy up

* Swagger: Exclude alpha endpoints

Co-authored-by: Sofia Papagiannaki <1632407+papagian@users.noreply.github.com>
This commit is contained in:
Josh Hunt
2022-10-14 14:51:05 +01:00
committed by GitHub
parent e4b1347ca5
commit 2e16d5499e
14 changed files with 324 additions and 3 deletions

View File

@@ -0,0 +1,80 @@
import { css } from '@emotion/css';
import React from 'react';
import { useAsync } from 'react-use';
import { GrafanaTheme2 } from '@grafana/data';
import { FetchError } from '@grafana/runtime';
import { Alert, useStyles2 } from '@grafana/ui';
import { backendSrv } from 'app/core/services/backend_srv';
import { DashboardModel } from '../../state';
interface DashboardValidationProps {
dashboard: DashboardModel;
}
type ValidationResponse = Awaited<ReturnType<typeof backendSrv.validateDashboard>>;
function DashboardValidation({ dashboard }: DashboardValidationProps) {
const styles = useStyles2(getStyles);
const { loading, value, error } = useAsync(async () => {
const saveModel = dashboard.getSaveModelClone();
const respPromise = backendSrv
.validateDashboard(saveModel)
// API returns schema validation errors in 4xx range, so resolve them rather than throwing
.catch((err: FetchError<ValidationResponse>) => {
if (err.status >= 500) {
throw err;
}
return err.data;
});
return respPromise;
}, [dashboard]);
let alert: React.ReactNode;
if (loading) {
alert = <Alert severity="info" title="Checking dashboard validity" />;
} else if (value) {
if (!value.isValid) {
alert = (
<Alert severity="warning" title="Dashboard failed schema validation">
<p>
Validation is provided for development purposes and should be safe to ignore. If you are a Grafana
developer, consider checking and updating the dashboard schema
</p>
<div className={styles.error}>{value.message}</div>
</Alert>
);
}
} else {
const errorMessage = error?.message ?? 'Unknown error';
alert = (
<Alert severity="info" title="Error checking dashboard validity">
<p className={styles.error}>{errorMessage}</p>
</Alert>
);
}
if (alert) {
return <div className={styles.root}>{alert}</div>;
}
return null;
}
const getStyles = (theme: GrafanaTheme2) => ({
root: css({
marginTop: theme.spacing(1),
}),
error: css({
fontFamily: theme.typography.fontFamilyMonospace,
whiteSpace: 'pre-wrap',
overflowX: 'auto',
maxWidth: '100%',
}),
});
export default DashboardValidation;

View File

@@ -7,6 +7,7 @@ import { backendSrv } from 'app/core/services/backend_srv';
import { jsonDiff } from '../VersionHistory/utils';
import DashboardValidation from './DashboardValidation';
import { SaveDashboardDiff } from './SaveDashboardDiff';
import { SaveDashboardErrorProxy } from './SaveDashboardErrorProxy';
import { SaveDashboardAsForm } from './forms/SaveDashboardAsForm';
@@ -68,7 +69,7 @@ export const SaveDashboardDrawer = ({ dashboard, onDismiss, onSaveSuccess, isCop
}
: onDismiss;
const renderBody = () => {
const renderSaveBody = () => {
if (showDiff) {
return <SaveDashboardDiff diff={data.diff} oldValue={previous.value} newValue={data.clone} />;
}
@@ -161,7 +162,9 @@ export const SaveDashboardDrawer = ({ dashboard, onDismiss, onSaveSuccess, isCop
expandable
scrollableContent
>
{renderBody()}
{renderSaveBody()}
{config.featureToggles.showDashboardValidationWarnings && <DashboardValidation dashboard={dashboard} />}
</Drawer>
);
};