AnnotationList: Support html content (#54916)

* support html content in annolistpanel

* improve panel tests

* add RenderUserContentAsHTML ui

* sanitize content
This commit is contained in:
Leo
2022-10-11 13:35:03 +02:00
committed by GitHub
parent 6969354490
commit a91d77003d
7 changed files with 125 additions and 7 deletions

View File

@@ -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(

View File

@@ -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',