mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
DashboardLinks: Fixes crash when link has no title (#31008)
* DashboardLinks: Fixes crash when link misses title * Chore: updates after PR comments
This commit is contained in:
parent
f43d834a59
commit
297ff9a168
@ -0,0 +1,104 @@
|
||||
import React from 'react';
|
||||
import { render, screen } from '@testing-library/react';
|
||||
import { DataLinksListItem, DataLinksListItemProps } from './DataLinksListItem';
|
||||
|
||||
const baseLink = {
|
||||
url: '',
|
||||
title: '',
|
||||
onBuildUrl: jest.fn(),
|
||||
onClick: jest.fn(),
|
||||
};
|
||||
|
||||
function setupTestContext(options: Partial<DataLinksListItemProps>) {
|
||||
const defaults: DataLinksListItemProps = {
|
||||
index: 0,
|
||||
link: baseLink,
|
||||
data: [],
|
||||
onChange: jest.fn(),
|
||||
onEdit: jest.fn(),
|
||||
onRemove: jest.fn(),
|
||||
suggestions: [],
|
||||
};
|
||||
|
||||
const props = { ...defaults, ...options };
|
||||
const { rerender } = render(<DataLinksListItem {...props} />);
|
||||
|
||||
return { rerender, props };
|
||||
}
|
||||
|
||||
describe('DataLinksListItem', () => {
|
||||
describe('when link has title', () => {
|
||||
it('then the link title should be visible', () => {
|
||||
const link = {
|
||||
...baseLink,
|
||||
title: 'Some Data Link Title',
|
||||
};
|
||||
setupTestContext({ link });
|
||||
|
||||
expect(screen.getByText(/some data link title/i)).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
||||
describe('when link has url', () => {
|
||||
it('then the link url should be visible', () => {
|
||||
const link = {
|
||||
...baseLink,
|
||||
url: 'http://localhost:3000',
|
||||
};
|
||||
setupTestContext({ link });
|
||||
|
||||
expect(screen.getByText(/http:\/\/localhost\:3000/i)).toBeInTheDocument();
|
||||
expect(screen.getByTitle(/http:\/\/localhost\:3000/i)).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
||||
describe('when link is missing title', () => {
|
||||
it('then the link title should be replaced by [Data link title not provided]', () => {
|
||||
const link = {
|
||||
...baseLink,
|
||||
title: (undefined as unknown) as string,
|
||||
};
|
||||
setupTestContext({ link });
|
||||
|
||||
expect(screen.getByText(/data link title not provided/i)).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
||||
describe('when link is missing url', () => {
|
||||
it('then the link url should be replaced by [Data link url not provided]', () => {
|
||||
const link = {
|
||||
...baseLink,
|
||||
url: (undefined as unknown) as string,
|
||||
};
|
||||
setupTestContext({ link });
|
||||
|
||||
expect(screen.getByText(/data link url not provided/i)).toBeInTheDocument();
|
||||
expect(screen.getByTitle('')).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
||||
describe('when link title is empty', () => {
|
||||
it('then the link title should be replaced by [Data link title not provided]', () => {
|
||||
const link = {
|
||||
...baseLink,
|
||||
title: ' ',
|
||||
};
|
||||
setupTestContext({ link });
|
||||
|
||||
expect(screen.getByText(/data link title not provided/i)).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
||||
describe('when link url is empty', () => {
|
||||
it('then the link url should be replaced by [Data link url not provided]', () => {
|
||||
const link = {
|
||||
...baseLink,
|
||||
url: ' ',
|
||||
};
|
||||
setupTestContext({ link });
|
||||
|
||||
expect(screen.getByText(/data link url not provided/i)).toBeInTheDocument();
|
||||
expect(screen.getByTitle('')).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
});
|
@ -5,7 +5,7 @@ import { stylesFactory, useTheme } from '../../../themes';
|
||||
import { HorizontalGroup, VerticalGroup } from '../../Layout/Layout';
|
||||
import { IconButton } from '../../IconButton/IconButton';
|
||||
|
||||
interface DataLinksListItemProps {
|
||||
export interface DataLinksListItemProps {
|
||||
index: number;
|
||||
link: DataLink;
|
||||
data: DataFrame[];
|
||||
@ -19,24 +19,25 @@ interface DataLinksListItemProps {
|
||||
export const DataLinksListItem: FC<DataLinksListItemProps> = ({ link, onEdit, onRemove }) => {
|
||||
const theme = useTheme();
|
||||
const styles = getDataLinkListItemStyles(theme);
|
||||
const { title = '', url = '' } = link;
|
||||
|
||||
const hasTitle = link.title.trim() !== '';
|
||||
const hasUrl = link.url.trim() !== '';
|
||||
const hasTitle = title.trim() !== '';
|
||||
const hasUrl = url.trim() !== '';
|
||||
|
||||
return (
|
||||
<div className={styles.wrapper}>
|
||||
<VerticalGroup spacing="xs">
|
||||
<HorizontalGroup justify="space-between" align="flex-start" width="100%">
|
||||
<div className={cx(styles.title, !hasTitle && styles.notConfigured)}>
|
||||
{hasTitle ? link.title : 'Data link title not provided'}
|
||||
{hasTitle ? title : 'Data link title not provided'}
|
||||
</div>
|
||||
<HorizontalGroup>
|
||||
<IconButton name="pen" onClick={onEdit} />
|
||||
<IconButton name="times" onClick={onRemove} />
|
||||
</HorizontalGroup>
|
||||
</HorizontalGroup>
|
||||
<div className={cx(styles.url, !hasUrl && styles.notConfigured)} title={link.url}>
|
||||
{hasUrl ? link.url : 'Data link url not provided'}
|
||||
<div className={cx(styles.url, !hasUrl && styles.notConfigured)} title={url}>
|
||||
{hasUrl ? url : 'Data link url not provided'}
|
||||
</div>
|
||||
</VerticalGroup>
|
||||
</div>
|
||||
|
Loading…
Reference in New Issue
Block a user