mirror of https://github.com/grafana/grafana.git
Datasource view: Show a not-found message (#110417)
This commit is contained in:
parent
0c44a0c14a
commit
13baef080c
|
@ -52,6 +52,18 @@ export function useDataSourceSettingsNav(pageIdParam?: string) {
|
|||
pageNav = getNavModel(navIndex, navIndexId, getDataSourceLoadingNav('settings'));
|
||||
}
|
||||
|
||||
if (!datasource.uid) {
|
||||
const node: NavModelItem = {
|
||||
text: t('connections.use-data-source-settings-nav.node.subTitle.data-source-error', 'Data Source Error'),
|
||||
icon: 'exclamation-triangle',
|
||||
};
|
||||
|
||||
pageNav = {
|
||||
node: node,
|
||||
main: node,
|
||||
};
|
||||
}
|
||||
|
||||
if (plugin) {
|
||||
pageNav = getNavModel(
|
||||
navIndex,
|
||||
|
@ -64,8 +76,8 @@ export function useDataSourceSettingsNav(pageIdParam?: string) {
|
|||
...pageNav.main,
|
||||
dataSourcePluginName: datasourcePlugin?.name || plugin?.meta.name || '',
|
||||
active: true,
|
||||
text: datasource.name,
|
||||
subTitle: `Type: ${dataSourceMeta.name}`,
|
||||
text: datasource.name || '',
|
||||
subTitle: dataSourceMeta.name ? `Type: ${dataSourceMeta.name}` : '',
|
||||
children: (pageNav.main.children || []).map((navModelItem) => ({
|
||||
...navModelItem,
|
||||
url: navModelItem.url?.replace('datasources/edit/', '/connections/datasources/edit/'),
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import { Trans } from '@grafana/i18n';
|
||||
import { Button } from '@grafana/ui';
|
||||
import { t, Trans } from '@grafana/i18n';
|
||||
import { Button, EmptyState } from '@grafana/ui';
|
||||
|
||||
import { DataSourceRights } from '../types';
|
||||
|
||||
|
@ -8,9 +8,10 @@ import { DataSourceReadOnlyMessage } from './DataSourceReadOnlyMessage';
|
|||
export type Props = {
|
||||
dataSourceRights: DataSourceRights;
|
||||
onDelete: () => void;
|
||||
notFound: boolean;
|
||||
};
|
||||
|
||||
export function DataSourceLoadError({ dataSourceRights, onDelete }: Props) {
|
||||
export function DataSourceLoadError({ dataSourceRights, onDelete, notFound }: Props) {
|
||||
const { readOnly, hasDeleteRights } = dataSourceRights;
|
||||
const canDelete = !readOnly && hasDeleteRights;
|
||||
const navigateBack = () => window.history.back();
|
||||
|
@ -20,6 +21,12 @@ export function DataSourceLoadError({ dataSourceRights, onDelete }: Props) {
|
|||
{readOnly && <DataSourceReadOnlyMessage />}
|
||||
|
||||
<div className="gf-form-button-row">
|
||||
{notFound && (
|
||||
<EmptyState
|
||||
variant="not-found"
|
||||
message={t('datasources.data-source-load-error.not-found', 'Data source not found')}
|
||||
/>
|
||||
)}
|
||||
{canDelete && (
|
||||
<Button type="submit" variant="destructive" onClick={onDelete}>
|
||||
<Trans i18nKey="datasources.data-source-load-error.delete">Delete</Trans>
|
||||
|
|
|
@ -108,6 +108,14 @@ describe('<EditDataSource>', () => {
|
|||
|
||||
expect(screen.queryByText(readOnlyMessage)).toBeVisible();
|
||||
});
|
||||
|
||||
it('should render a message if the datasource is not found', () => {
|
||||
setup({
|
||||
dataSource: getMockDataSource({ uid: undefined, id: 0 }),
|
||||
});
|
||||
|
||||
expect(screen.queryByText('Data source not found')).toBeVisible();
|
||||
});
|
||||
});
|
||||
|
||||
describe('On loading', () => {
|
||||
|
|
|
@ -114,7 +114,7 @@ export function EditDataSourceView({
|
|||
}: ViewProps) {
|
||||
const { plugin, loadError, testingStatus, loading } = dataSourceSettings;
|
||||
const { readOnly, hasWriteRights, hasDeleteRights } = dataSourceRights;
|
||||
const hasDataSource = dataSource.id > 0;
|
||||
const hasDataSource = dataSource.id > 0 && dataSource.uid;
|
||||
const { components, isLoading } = useDataSourceConfigPluginExtensions();
|
||||
// This is a workaround to avoid race-conditions between the `setSecureJsonData()` and `setJsonData()` calls instantiated by the extension components.
|
||||
// Both those exposed functions are calling `onOptionsChange()` with the new jsonData and secureJsonData, and if they are called in the same tick, the Redux store
|
||||
|
@ -150,9 +150,14 @@ export function EditDataSourceView({
|
|||
onTest();
|
||||
};
|
||||
|
||||
if (loadError) {
|
||||
if (loading || isLoading) {
|
||||
return <PageLoader />;
|
||||
}
|
||||
|
||||
if (loadError || !hasDataSource || !dsi) {
|
||||
return (
|
||||
<DataSourceLoadError
|
||||
notFound={!hasDataSource || !dsi}
|
||||
dataSourceRights={dataSourceRights}
|
||||
onDelete={() => {
|
||||
trackDsConfigClicked('delete');
|
||||
|
@ -162,15 +167,6 @@ export function EditDataSourceView({
|
|||
);
|
||||
}
|
||||
|
||||
if (loading || isLoading) {
|
||||
return <PageLoader />;
|
||||
}
|
||||
|
||||
// TODO - is this needed?
|
||||
if (!hasDataSource || !dsi) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (pageId) {
|
||||
return (
|
||||
<DataSourcePluginContextProvider instanceSettings={dsi}>
|
||||
|
|
|
@ -90,7 +90,7 @@ const mockDataSource = getMockDataSource({
|
|||
|
||||
// Mock useDataSource hook
|
||||
jest.mock('../state/hooks', () => ({
|
||||
useDataSource: () => mockDataSource,
|
||||
useDataSource: (uid: string) => (uid === 'not-found' ? {} : mockDataSource),
|
||||
}));
|
||||
|
||||
describe('EditDataSourceActions', () => {
|
||||
|
@ -374,6 +374,14 @@ describe('EditDataSourceActions', () => {
|
|||
});
|
||||
});
|
||||
|
||||
describe('DataSource Not Found', () => {
|
||||
it('should not render actions when data source is not found', () => {
|
||||
render(<EditDataSourceActions uid="not-found" />);
|
||||
expect(screen.queryByText('Explore data')).not.toBeInTheDocument();
|
||||
expect(screen.queryByText('Build a dashboard')).not.toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
||||
describe('Favorite Actions', () => {
|
||||
it('should not render favorite button when feature toggle is disabled', () => {
|
||||
config.featureToggles.favoriteDatasources = false;
|
||||
|
|
|
@ -90,6 +90,10 @@ export function EditDataSourceActions({ uid }: Props) {
|
|||
</Menu>
|
||||
);
|
||||
|
||||
if (!dataSource.uid) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<FavoriteButton uid={uid} />
|
||||
|
|
|
@ -11,6 +11,10 @@ export const useDataSourceInfo = (dataSourceInfo: DataSourceInfo): PageInfoItem[
|
|||
const info: PageInfoItem[] = [];
|
||||
const alertingEnabled = dataSourceInfo.alertingSupported;
|
||||
|
||||
if (!dataSourceInfo.dataSourcePluginName) {
|
||||
return info;
|
||||
}
|
||||
|
||||
info.push({
|
||||
label: t('datasources.use-data-source-info.label.type', 'Type'),
|
||||
value: dataSourceInfo.dataSourcePluginName,
|
||||
|
|
|
@ -6543,7 +6543,8 @@
|
|||
},
|
||||
"data-source-load-error": {
|
||||
"back": "Back",
|
||||
"delete": "Delete"
|
||||
"delete": "Delete",
|
||||
"not-found": "Data source not found"
|
||||
},
|
||||
"data-source-missing-rights-message": {
|
||||
"title-missing-rights": "Missing rights"
|
||||
|
|
Loading…
Reference in New Issue