2023-04-28 08:57:17 -05:00
|
|
|
import { css, cx } from '@emotion/css';
|
|
|
|
import React, { HTMLAttributes } from 'react';
|
2022-07-20 02:25:09 -05:00
|
|
|
|
2023-04-28 08:57:17 -05:00
|
|
|
import { DataSourceSettings as DataSourceSettingsType, GrafanaTheme2 } from '@grafana/data';
|
2022-07-20 02:25:09 -05:00
|
|
|
import { selectors as e2eSelectors } from '@grafana/e2e-selectors';
|
2023-04-28 08:57:17 -05:00
|
|
|
import { TestingStatus, config } from '@grafana/runtime';
|
|
|
|
import { AlertVariant, Alert, useTheme2, Link } from '@grafana/ui';
|
|
|
|
|
|
|
|
import { contextSrv } from '../../../core/core';
|
|
|
|
import { AccessControlAction } from '../../../types';
|
|
|
|
import { trackCreateDashboardClicked } from '../tracking';
|
2022-07-20 02:25:09 -05:00
|
|
|
|
|
|
|
export type Props = {
|
|
|
|
testingStatus?: TestingStatus;
|
2023-04-28 08:57:17 -05:00
|
|
|
exploreUrl: string;
|
|
|
|
dataSource: DataSourceSettingsType;
|
|
|
|
};
|
|
|
|
|
|
|
|
interface AlertMessageProps extends HTMLAttributes<HTMLDivElement> {
|
|
|
|
title: string;
|
|
|
|
severity?: AlertVariant;
|
|
|
|
exploreUrl: string;
|
|
|
|
dataSourceId: string;
|
|
|
|
onDashboardLinkClicked: () => void;
|
|
|
|
}
|
|
|
|
|
|
|
|
const getStyles = (theme: GrafanaTheme2, hasTitle: boolean) => {
|
|
|
|
return {
|
|
|
|
content: css`
|
|
|
|
color: ${theme.colors.text.secondary};
|
|
|
|
padding-top: ${hasTitle ? theme.spacing(1) : 0};
|
|
|
|
max-height: 50vh;
|
|
|
|
overflow-y: auto;
|
|
|
|
`,
|
|
|
|
disabled: css`
|
|
|
|
pointer-events: none;
|
|
|
|
color: ${theme.colors.text.secondary};
|
|
|
|
`,
|
|
|
|
};
|
2022-07-20 02:25:09 -05:00
|
|
|
};
|
|
|
|
|
2023-04-28 08:57:17 -05:00
|
|
|
const AlertSuccessMessage = ({ title, exploreUrl, dataSourceId, onDashboardLinkClicked }: AlertMessageProps) => {
|
|
|
|
const theme = useTheme2();
|
|
|
|
const hasTitle = Boolean(title);
|
|
|
|
const styles = getStyles(theme, hasTitle);
|
|
|
|
const canExploreDataSources = contextSrv.hasPermission(AccessControlAction.DataSourcesExplore);
|
|
|
|
|
|
|
|
return (
|
|
|
|
<div className={styles.content}>
|
|
|
|
Next, you can start to visualize data by{' '}
|
|
|
|
<Link
|
|
|
|
aria-label={`Create a dashboard`}
|
|
|
|
href={`/dashboard/new-with-ds/${dataSourceId}`}
|
|
|
|
className="external-link"
|
|
|
|
onClick={onDashboardLinkClicked}
|
|
|
|
>
|
|
|
|
building a dashboard
|
|
|
|
</Link>
|
|
|
|
, or by querying data in the{' '}
|
|
|
|
<Link
|
|
|
|
aria-label={`Explore data`}
|
|
|
|
className={cx('external-link', {
|
|
|
|
[`${styles.disabled}`]: !canExploreDataSources,
|
|
|
|
'test-disabled': !canExploreDataSources,
|
|
|
|
})}
|
|
|
|
href={exploreUrl}
|
|
|
|
>
|
|
|
|
Explore view
|
|
|
|
</Link>
|
|
|
|
.
|
|
|
|
</div>
|
|
|
|
);
|
|
|
|
};
|
|
|
|
|
|
|
|
AlertSuccessMessage.displayName = 'AlertSuccessMessage';
|
|
|
|
|
2023-05-22 06:50:46 -05:00
|
|
|
const alertVariants = new Set<AlertVariant>(['success', 'info', 'warning', 'error']);
|
|
|
|
const isAlertVariant = (str: string): str is AlertVariant => alertVariants.has(str as AlertVariant);
|
|
|
|
const getAlertVariant = (status: string): AlertVariant => {
|
|
|
|
if (status.toLowerCase() === 'ok') {
|
|
|
|
return 'success';
|
|
|
|
}
|
|
|
|
return isAlertVariant(status) ? status : 'info';
|
|
|
|
};
|
|
|
|
|
2023-04-28 08:57:17 -05:00
|
|
|
export function DataSourceTestingStatus({ testingStatus, exploreUrl, dataSource }: Props) {
|
2023-05-22 06:50:46 -05:00
|
|
|
const severity = getAlertVariant(testingStatus?.status ?? 'error');
|
2022-07-20 02:25:09 -05:00
|
|
|
const message = testingStatus?.message;
|
|
|
|
const detailsMessage = testingStatus?.details?.message;
|
|
|
|
const detailsVerboseMessage = testingStatus?.details?.verboseMessage;
|
2023-04-28 08:57:17 -05:00
|
|
|
const onDashboardLinkClicked = () => {
|
|
|
|
trackCreateDashboardClicked({
|
|
|
|
grafana_version: config.buildInfo.version,
|
|
|
|
datasource_uid: dataSource.uid,
|
|
|
|
plugin_name: dataSource.typeName,
|
|
|
|
path: location.pathname,
|
|
|
|
});
|
|
|
|
};
|
2022-07-20 02:25:09 -05:00
|
|
|
|
|
|
|
if (message) {
|
|
|
|
return (
|
|
|
|
<div className="gf-form-group p-t-2">
|
2023-04-28 08:57:17 -05:00
|
|
|
<Alert severity={severity} title={message} aria-label={e2eSelectors.pages.DataSource.alert}>
|
2022-07-20 02:25:09 -05:00
|
|
|
{testingStatus?.details && (
|
|
|
|
<>
|
|
|
|
{detailsMessage}
|
2023-04-28 08:57:17 -05:00
|
|
|
{severity === 'success' ? (
|
|
|
|
<AlertSuccessMessage
|
|
|
|
title={message}
|
|
|
|
exploreUrl={exploreUrl}
|
|
|
|
dataSourceId={dataSource.uid}
|
|
|
|
onDashboardLinkClicked={onDashboardLinkClicked}
|
|
|
|
/>
|
|
|
|
) : null}
|
2022-07-20 02:25:09 -05:00
|
|
|
{detailsVerboseMessage ? (
|
2023-04-11 04:51:54 -05:00
|
|
|
<details style={{ whiteSpace: 'pre-wrap' }}>{String(detailsVerboseMessage)}</details>
|
2022-07-20 02:25:09 -05:00
|
|
|
) : null}
|
|
|
|
</>
|
|
|
|
)}
|
|
|
|
</Alert>
|
|
|
|
</div>
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
return null;
|
|
|
|
}
|