PublicDashboards: Modal warns when using unsupported datasources (#58926)

Adds warning to pubdash modal when dashboard uses datasources not supported by pubdash
This commit is contained in:
owensmallwood 2022-12-01 10:02:10 -06:00 committed by GitHub
parent d2c129fbac
commit 97e81ecbde
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 159 additions and 77 deletions

View File

@ -193,6 +193,7 @@ export const Pages = {
CopyUrlInput: 'data-testid public dashboard copy url input',
CopyUrlButton: 'data-testid public dashboard copy url button',
TemplateVariablesWarningAlert: 'data-testid public dashboard disabled template variables alert',
UnsupportedDatasourcesWarningAlert: 'data-testid public dashboard unsupported datasources',
},
},
Explore: {

View File

@ -10,30 +10,27 @@ import (
"github.com/grafana/grafana/pkg/services/publicdashboards/commands/generate_datasources"
)
var goTemplate = `
var tsDatasourcesTemplate = `
// Code generated by go generate; DO NOT EDIT.
package publicdashboards
var SupportedDatasources = map[string]bool{
export const supportedDatasources = new Set<string>([
{{- range . }}
"{{ printf "%s" . }}": true,
'{{ printf "%s" . }}',
{{- end }}
}
])
`
func main() {
baseUrl := "https://grafana.com"
slugs, err := generate_datasources.GetCompatibleDatasources(baseUrl)
tsTemplate := template.Must(template.New("").Parse(tsDatasourcesTemplate))
myTemplate := template.Must(template.New("").Parse(goTemplate))
file, err := os.Create("supported_datasources_gen.go")
// Generate supported datasources for Typescript
tsFile, err := os.Create("./../../../public/app/features/dashboard/components/ShareModal/SharePublicDashboard/SupportedPubdashDatasources.ts")
if err != nil {
fmt.Println(err)
}
err = myTemplate.Execute(file, slugs)
err = tsTemplate.Execute(tsFile, slugs)
if err != nil {
fmt.Println(err)
}

View File

@ -1,65 +0,0 @@
// Code generated by go generate; DO NOT EDIT.
package publicdashboards
var SupportedDatasources = map[string]bool{
"aquaqanalytics-kdbbackend-datasource": true,
"cloudwatch": true,
"dlopes7-appdynamics-datasource": true,
"doitintl-bigquery-datasource": true,
"elasticsearch": true,
"frser-sqlite-datasource": true,
"grafadruid-druid-datasource": true,
"grafana-athena-datasource": true,
"grafana-azure-data-explorer-datasource": true,
"grafana-azure-monitor-datasource": true,
"grafana-bigquery-datasource": true,
"grafana-clickhouse-datasource": true,
"grafana-databricks-datasource": true,
"grafana-datadog-datasource": true,
"grafana-db2-datasource": true,
"grafana-dynatrace-datasource": true,
"grafana-es-open-distro-datasource": true,
"grafana-github-datasource": true,
"grafana-honeycomb-datasource": true,
"grafana-iot-sitewise-datasource": true,
"grafana-jira-datasource": true,
"grafana-mock-datasource": true,
"grafana-mongodb-datasource": true,
"grafana-newrelic-datasource": true,
"grafana-odbc-datasource": true,
"grafana-opcua-datasource": true,
"grafana-opensearch-datasource": true,
"grafana-oracle-datasource": true,
"grafana-orbit-datasource": true,
"grafana-redshift-datasource": true,
"grafana-salesforce-datasource": true,
"grafana-saphana-datasource": true,
"grafana-sentry-datasource": true,
"grafana-servicenow-datasource": true,
"grafana-snowflake-datasource": true,
"grafana-splunk-datasource": true,
"grafana-splunk-monitoring-datasource": true,
"grafana-timestream-datasource": true,
"grafana-wavefront-datasource": true,
"grafana-x-ray-datasource": true,
"graphite": true,
"hadesarchitect-cassandra-datasource": true,
"influxdb": true,
"innius-grpc-datasource": true,
"kniepdennis-neo4j-datasource": true,
"loki": true,
"marcusolsson-csv-datasource": true,
"marcusolsson-ynab-datasource": true,
"mssql": true,
"mysql": true,
"opentsdb": true,
"postgres": true,
"prometheus": true,
"redis-datasource": true,
"sentinelone-dataset-datasource": true,
"tdengine-datasource": true,
"vertamedia-clickhouse-datasource": true,
"vertica-grafana-datasource": true,
"yesoreyeram-infinity-datasource": true,
}

View File

@ -5,7 +5,7 @@ import React from 'react';
import { Provider } from 'react-redux';
import 'whatwg-fetch';
import { BootData } from '@grafana/data/src';
import { BootData, DataQuery } from '@grafana/data/src';
import { selectors as e2eSelectors } from '@grafana/e2e-selectors/src';
import { setEchoSrv } from '@grafana/runtime/src';
import config from 'app/core/config';
@ -192,6 +192,23 @@ describe('SharePublic - New config setup', () => {
await renderSharePublicDashboard({ panel: mockPanel, dashboard: mockDashboard, onDismiss: () => {} });
expect(screen.getByTestId(selectors.SaveConfigButton)).toBeDisabled();
});
it('when dashboard has unsupported datasources, warning is shown', async () => {
const panelModel = {
targets: [
{
datasource: { type: 'notSupportedDatasource', uid: 'abc123' },
} as DataQuery,
] as DataQuery[],
} as PanelModel;
const dashboard = new DashboardModel({
id: 1,
panels: [panelModel],
});
await renderSharePublicDashboard({ panel: mockPanel, dashboard, onDismiss: () => {} });
expect(screen.queryByTestId(selectors.UnsupportedDatasourcesWarningAlert)).toBeInTheDocument();
});
it('when fetch is done, then no loader spinner appears, inputs are enabled and save button is disabled', async () => {
await renderSharePublicDashboard({ panel: mockPanel, dashboard: mockDashboard, onDismiss: () => {} });
expect(screen.queryByTestId('Spinner')).not.toBeInTheDocument();

View File

@ -31,6 +31,7 @@ import {
Acknowledgements,
dashboardHasTemplateVariables,
generatePublicDashboardUrl,
getUnsupportedDashboardDatasources,
publicDashboardPersisted,
} from 'app/features/dashboard/components/ShareModal/SharePublicDashboard/SharePublicDashboardUtils';
import { ShareModalTabProps } from 'app/features/dashboard/components/ShareModal/types';
@ -161,6 +162,23 @@ export const SharePublicDashboard = (props: Props) => {
{(isGetLoading || isFetching) && <Spinner />}
</HorizontalGroup>
<div className={styles.content}>
{getUnsupportedDashboardDatasources(props.dashboard.panels).length > 0 ? (
<Alert
severity="warning"
title="Unsupported Datasources"
data-testid={selectors.UnsupportedDatasourcesWarningAlert}
>
<div>
{`There are datasources in this dashboard that are unsupported for public dashboards. Panels that use these datasources may not function properly: ${getUnsupportedDashboardDatasources(
props.dashboard.panels
).join(', ')}. See the `}
<a href="https://grafana.com/docs/grafana/latest/dashboards/dashboard-public/" className="text-link">
docs
</a>{' '}
for supported datasources.
</div>
</Alert>
) : null}
{dashboardHasTemplateVariables(dashboardVariables) && !publicDashboardPersisted(publicDashboard) ? (
<Alert
severity="warning"

View File

@ -1,4 +1,6 @@
import { DataSourceRef, DataQuery } from '@grafana/data/src/types/query';
import { updateConfig } from 'app/core/config';
import { PanelModel } from 'app/features/dashboard/state/PanelModel';
import { VariableModel } from 'app/features/variables/types';
import {
@ -6,6 +8,7 @@ import {
dashboardHasTemplateVariables,
publicDashboardPersisted,
generatePublicDashboardUrl,
getUnsupportedDashboardDatasources,
} from './SharePublicDashboardUtils';
describe('dashboardHasTemplateVariables', () => {
@ -45,3 +48,29 @@ describe('publicDashboardPersisted', () => {
expect(publicDashboardPersisted(pubdash)).toBe(false);
});
});
describe('getUnsupportedDashboardDatasources', () => {
it('itIsSupported', () => {
const pm = {
targets: [
{
datasource: { type: 'prometheus' } as DataSourceRef,
} as DataQuery,
] as DataQuery[],
} as PanelModel;
const panelArray: PanelModel[] = [pm];
expect(getUnsupportedDashboardDatasources(panelArray)).toEqual([]);
});
it('itIsNotSupported', () => {
const pm = {
targets: [
{
datasource: { type: 'blah' } as DataSourceRef,
} as DataQuery,
] as DataQuery[],
} as PanelModel;
const panelArray: PanelModel[] = [pm];
expect(getUnsupportedDashboardDatasources(panelArray)).toEqual(['blah']);
});
});

View File

@ -2,6 +2,10 @@ import { getConfig } from 'app/core/config';
import { VariableModel } from 'app/features/variables/types';
import { DashboardDataDTO, DashboardMeta } from 'app/types/dashboard';
import { PanelModel } from '../../../state';
import { supportedDatasources } from './SupportedPubdashDatasources';
export interface PublicDashboard {
accessToken?: string;
annotationsEnabled: boolean;
@ -31,6 +35,24 @@ export const publicDashboardPersisted = (publicDashboard?: PublicDashboard): boo
return publicDashboard?.uid !== '' && publicDashboard?.uid !== undefined;
};
/**
* Get unique datasource names from all panels that are not currently supported by public dashboards.
*/
export const getUnsupportedDashboardDatasources = (panels: PanelModel[]): string[] => {
let unsupportedDS = new Set<string>();
for (const panel of panels) {
for (const target of panel.targets) {
let ds = target?.datasource?.type;
if (ds && !supportedDatasources.has(ds)) {
unsupportedDS.add(ds);
}
}
}
return Array.from(unsupportedDS).sort();
};
/**
* Generate the public dashboard url. Uses the appUrl from the Grafana boot config, so urls will also be correct
* when Grafana is hosted on a subpath.

View File

@ -0,0 +1,63 @@
// Code generated by go generate; DO NOT EDIT.
export const supportedDatasources = new Set<string>([
'aquaqanalytics-kdbbackend-datasource',
'cloudwatch',
'dlopes7-appdynamics-datasource',
'doitintl-bigquery-datasource',
'elasticsearch',
'frser-sqlite-datasource',
'grafadruid-druid-datasource',
'grafana-athena-datasource',
'grafana-azure-data-explorer-datasource',
'grafana-azure-monitor-datasource',
'grafana-bigquery-datasource',
'grafana-clickhouse-datasource',
'grafana-databricks-datasource',
'grafana-datadog-datasource',
'grafana-db2-datasource',
'grafana-dynatrace-datasource',
'grafana-es-open-distro-datasource',
'grafana-github-datasource',
'grafana-honeycomb-datasource',
'grafana-iot-sitewise-datasource',
'grafana-jira-datasource',
'grafana-mock-datasource',
'grafana-mongodb-datasource',
'grafana-newrelic-datasource',
'grafana-odbc-datasource',
'grafana-opcua-datasource',
'grafana-opensearch-datasource',
'grafana-oracle-datasource',
'grafana-orbit-datasource',
'grafana-redshift-datasource',
'grafana-salesforce-datasource',
'grafana-saphana-datasource',
'grafana-sentry-datasource',
'grafana-servicenow-datasource',
'grafana-snowflake-datasource',
'grafana-splunk-datasource',
'grafana-splunk-monitoring-datasource',
'grafana-timestream-datasource',
'grafana-wavefront-datasource',
'grafana-x-ray-datasource',
'graphite',
'hadesarchitect-cassandra-datasource',
'influxdb',
'innius-grpc-datasource',
'kniepdennis-neo4j-datasource',
'loki',
'marcusolsson-csv-datasource',
'marcusolsson-ynab-datasource',
'mssql',
'mysql',
'opentsdb',
'postgres',
'prometheus',
'redis-datasource',
'sentinelone-dataset-datasource',
'tdengine-datasource',
'vertamedia-clickhouse-datasource',
'vertica-grafana-datasource',
'yesoreyeram-infinity-datasource',
]);