mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
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:
parent
d2c129fbac
commit
97e81ecbde
@ -193,6 +193,7 @@ export const Pages = {
|
|||||||
CopyUrlInput: 'data-testid public dashboard copy url input',
|
CopyUrlInput: 'data-testid public dashboard copy url input',
|
||||||
CopyUrlButton: 'data-testid public dashboard copy url button',
|
CopyUrlButton: 'data-testid public dashboard copy url button',
|
||||||
TemplateVariablesWarningAlert: 'data-testid public dashboard disabled template variables alert',
|
TemplateVariablesWarningAlert: 'data-testid public dashboard disabled template variables alert',
|
||||||
|
UnsupportedDatasourcesWarningAlert: 'data-testid public dashboard unsupported datasources',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Explore: {
|
Explore: {
|
||||||
|
@ -10,30 +10,27 @@ import (
|
|||||||
"github.com/grafana/grafana/pkg/services/publicdashboards/commands/generate_datasources"
|
"github.com/grafana/grafana/pkg/services/publicdashboards/commands/generate_datasources"
|
||||||
)
|
)
|
||||||
|
|
||||||
var goTemplate = `
|
var tsDatasourcesTemplate = `
|
||||||
// Code generated by go generate; DO NOT EDIT.
|
// Code generated by go generate; DO NOT EDIT.
|
||||||
|
|
||||||
package publicdashboards
|
export const supportedDatasources = new Set<string>([
|
||||||
|
|
||||||
var SupportedDatasources = map[string]bool{
|
|
||||||
{{- range . }}
|
{{- range . }}
|
||||||
"{{ printf "%s" . }}": true,
|
'{{ printf "%s" . }}',
|
||||||
{{- end }}
|
{{- end }}
|
||||||
}
|
])
|
||||||
`
|
`
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
baseUrl := "https://grafana.com"
|
baseUrl := "https://grafana.com"
|
||||||
slugs, err := generate_datasources.GetCompatibleDatasources(baseUrl)
|
slugs, err := generate_datasources.GetCompatibleDatasources(baseUrl)
|
||||||
|
tsTemplate := template.Must(template.New("").Parse(tsDatasourcesTemplate))
|
||||||
|
|
||||||
myTemplate := template.Must(template.New("").Parse(goTemplate))
|
// Generate supported datasources for Typescript
|
||||||
|
tsFile, err := os.Create("./../../../public/app/features/dashboard/components/ShareModal/SharePublicDashboard/SupportedPubdashDatasources.ts")
|
||||||
file, err := os.Create("supported_datasources_gen.go")
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println(err)
|
fmt.Println(err)
|
||||||
}
|
}
|
||||||
|
err = tsTemplate.Execute(tsFile, slugs)
|
||||||
err = myTemplate.Execute(file, slugs)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println(err)
|
fmt.Println(err)
|
||||||
}
|
}
|
||||||
|
@ -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,
|
|
||||||
}
|
|
@ -5,7 +5,7 @@ import React from 'react';
|
|||||||
import { Provider } from 'react-redux';
|
import { Provider } from 'react-redux';
|
||||||
|
|
||||||
import 'whatwg-fetch';
|
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 { selectors as e2eSelectors } from '@grafana/e2e-selectors/src';
|
||||||
import { setEchoSrv } from '@grafana/runtime/src';
|
import { setEchoSrv } from '@grafana/runtime/src';
|
||||||
import config from 'app/core/config';
|
import config from 'app/core/config';
|
||||||
@ -192,6 +192,23 @@ describe('SharePublic - New config setup', () => {
|
|||||||
await renderSharePublicDashboard({ panel: mockPanel, dashboard: mockDashboard, onDismiss: () => {} });
|
await renderSharePublicDashboard({ panel: mockPanel, dashboard: mockDashboard, onDismiss: () => {} });
|
||||||
expect(screen.getByTestId(selectors.SaveConfigButton)).toBeDisabled();
|
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 () => {
|
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: () => {} });
|
await renderSharePublicDashboard({ panel: mockPanel, dashboard: mockDashboard, onDismiss: () => {} });
|
||||||
expect(screen.queryByTestId('Spinner')).not.toBeInTheDocument();
|
expect(screen.queryByTestId('Spinner')).not.toBeInTheDocument();
|
||||||
|
@ -31,6 +31,7 @@ import {
|
|||||||
Acknowledgements,
|
Acknowledgements,
|
||||||
dashboardHasTemplateVariables,
|
dashboardHasTemplateVariables,
|
||||||
generatePublicDashboardUrl,
|
generatePublicDashboardUrl,
|
||||||
|
getUnsupportedDashboardDatasources,
|
||||||
publicDashboardPersisted,
|
publicDashboardPersisted,
|
||||||
} from 'app/features/dashboard/components/ShareModal/SharePublicDashboard/SharePublicDashboardUtils';
|
} from 'app/features/dashboard/components/ShareModal/SharePublicDashboard/SharePublicDashboardUtils';
|
||||||
import { ShareModalTabProps } from 'app/features/dashboard/components/ShareModal/types';
|
import { ShareModalTabProps } from 'app/features/dashboard/components/ShareModal/types';
|
||||||
@ -161,6 +162,23 @@ export const SharePublicDashboard = (props: Props) => {
|
|||||||
{(isGetLoading || isFetching) && <Spinner />}
|
{(isGetLoading || isFetching) && <Spinner />}
|
||||||
</HorizontalGroup>
|
</HorizontalGroup>
|
||||||
<div className={styles.content}>
|
<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) ? (
|
{dashboardHasTemplateVariables(dashboardVariables) && !publicDashboardPersisted(publicDashboard) ? (
|
||||||
<Alert
|
<Alert
|
||||||
severity="warning"
|
severity="warning"
|
||||||
|
@ -1,4 +1,6 @@
|
|||||||
|
import { DataSourceRef, DataQuery } from '@grafana/data/src/types/query';
|
||||||
import { updateConfig } from 'app/core/config';
|
import { updateConfig } from 'app/core/config';
|
||||||
|
import { PanelModel } from 'app/features/dashboard/state/PanelModel';
|
||||||
import { VariableModel } from 'app/features/variables/types';
|
import { VariableModel } from 'app/features/variables/types';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
@ -6,6 +8,7 @@ import {
|
|||||||
dashboardHasTemplateVariables,
|
dashboardHasTemplateVariables,
|
||||||
publicDashboardPersisted,
|
publicDashboardPersisted,
|
||||||
generatePublicDashboardUrl,
|
generatePublicDashboardUrl,
|
||||||
|
getUnsupportedDashboardDatasources,
|
||||||
} from './SharePublicDashboardUtils';
|
} from './SharePublicDashboardUtils';
|
||||||
|
|
||||||
describe('dashboardHasTemplateVariables', () => {
|
describe('dashboardHasTemplateVariables', () => {
|
||||||
@ -45,3 +48,29 @@ describe('publicDashboardPersisted', () => {
|
|||||||
expect(publicDashboardPersisted(pubdash)).toBe(false);
|
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']);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
@ -2,6 +2,10 @@ import { getConfig } from 'app/core/config';
|
|||||||
import { VariableModel } from 'app/features/variables/types';
|
import { VariableModel } from 'app/features/variables/types';
|
||||||
import { DashboardDataDTO, DashboardMeta } from 'app/types/dashboard';
|
import { DashboardDataDTO, DashboardMeta } from 'app/types/dashboard';
|
||||||
|
|
||||||
|
import { PanelModel } from '../../../state';
|
||||||
|
|
||||||
|
import { supportedDatasources } from './SupportedPubdashDatasources';
|
||||||
|
|
||||||
export interface PublicDashboard {
|
export interface PublicDashboard {
|
||||||
accessToken?: string;
|
accessToken?: string;
|
||||||
annotationsEnabled: boolean;
|
annotationsEnabled: boolean;
|
||||||
@ -31,6 +35,24 @@ export const publicDashboardPersisted = (publicDashboard?: PublicDashboard): boo
|
|||||||
return publicDashboard?.uid !== '' && publicDashboard?.uid !== undefined;
|
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
|
* 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.
|
* when Grafana is hosted on a subpath.
|
||||||
|
@ -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',
|
||||||
|
]);
|
Loading…
Reference in New Issue
Block a user