mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
AnnotationList: Support html content (#54916)
* support html content in annolistpanel * improve panel tests * add RenderUserContentAsHTML ui * sanitize content
This commit is contained in:
@@ -132,6 +132,16 @@ describe('AnnoListPanel', () => {
|
||||
expect(screen.getByText(/2021-01-01T00:00:00.000Z/i)).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it("renders annotation item's html content", async () => {
|
||||
const { getMock } = await setupTestContext({
|
||||
results: [{ ...defaultResult, text: '<a href="">test link </a> ' }],
|
||||
});
|
||||
|
||||
getMock.mockClear();
|
||||
expect(screen.getByRole('link')).toBeInTheDocument();
|
||||
expect(getMock).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
describe('and login property is missing in annotation', () => {
|
||||
it('then it renders the annotations correctly', async () => {
|
||||
await setupTestContext({ results: [{ ...defaultResult, login: undefined }] });
|
||||
@@ -203,8 +213,8 @@ describe('AnnoListPanel', () => {
|
||||
const { getMock, pushSpy } = await setupTestContext();
|
||||
|
||||
getMock.mockClear();
|
||||
expect(screen.getByText(/result text/i)).toBeInTheDocument();
|
||||
await userEvent.click(screen.getByText(/result text/i));
|
||||
expect(screen.getByRole('button', { name: /result text/i })).toBeInTheDocument();
|
||||
await userEvent.click(screen.getByRole('button', { name: /result text/i }));
|
||||
await waitFor(() => expect(getMock).toHaveBeenCalledTimes(1));
|
||||
|
||||
expect(getMock).toHaveBeenCalledWith('/api/search', { dashboardUIDs: '7MeksYbmk' });
|
||||
@@ -218,8 +228,9 @@ describe('AnnoListPanel', () => {
|
||||
const { getMock } = await setupTestContext();
|
||||
|
||||
getMock.mockClear();
|
||||
expect(screen.getByText('Result tag B')).toBeInTheDocument();
|
||||
await userEvent.click(screen.getByText('Result tag B'));
|
||||
|
||||
expect(screen.getByRole('button', { name: /result tag b/i })).toBeInTheDocument();
|
||||
await userEvent.click(screen.getByRole('button', { name: /result tag b/i }));
|
||||
|
||||
expect(getMock).toHaveBeenCalledTimes(1);
|
||||
expect(getMock).toHaveBeenCalledWith(
|
||||
|
||||
@@ -2,7 +2,7 @@ import { css } from '@emotion/css';
|
||||
import React, { FC, MouseEvent } from 'react';
|
||||
|
||||
import { AnnotationEvent, DateTimeInput, GrafanaTheme2, PanelProps } from '@grafana/data';
|
||||
import { Card, TagList, Tooltip, useStyles2 } from '@grafana/ui';
|
||||
import { Card, TagList, Tooltip, RenderUserContentAsHTML, useStyles2 } from '@grafana/ui';
|
||||
|
||||
import { PanelOptions } from './models.gen';
|
||||
|
||||
@@ -24,7 +24,7 @@ export const AnnotationListItem: FC<Props> = ({
|
||||
}) => {
|
||||
const styles = useStyles2(getStyles);
|
||||
const { showUser, showTags, showTime } = options;
|
||||
const { text, login, email, avatarUrl, tags, time, timeEnd } = annotation;
|
||||
const { text = '', login, email, avatarUrl, tags, time, timeEnd } = annotation;
|
||||
const onItemClick = () => {
|
||||
onClick(annotation);
|
||||
};
|
||||
@@ -38,7 +38,13 @@ export const AnnotationListItem: FC<Props> = ({
|
||||
return (
|
||||
<Card className={styles.card} onClick={onItemClick}>
|
||||
<Card.Heading>
|
||||
<span>{text}</span>
|
||||
<RenderUserContentAsHTML
|
||||
className={styles.heading}
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
}}
|
||||
content={text}
|
||||
/>
|
||||
</Card.Heading>
|
||||
{showTimeStamp && (
|
||||
<Card.Description className={styles.timestamp}>
|
||||
@@ -118,6 +124,16 @@ function getStyles(theme: GrafanaTheme2) {
|
||||
margin: theme.spacing(0.5),
|
||||
width: 'inherit',
|
||||
}),
|
||||
heading: css({
|
||||
a: {
|
||||
zIndex: 1,
|
||||
position: 'relative',
|
||||
color: theme.colors.text.link,
|
||||
'&:hover': {
|
||||
textDecoration: 'underline',
|
||||
},
|
||||
},
|
||||
}),
|
||||
meta: css({
|
||||
margin: 0,
|
||||
position: 'relative',
|
||||
|
||||
Reference in New Issue
Block a user