NewsDrawer: Add grot to news drawer (after news items) (#68173)

* NewsDrawer: Add grot to drawer header

* Update

* Move to bottom

* Updates

* reverted unrelated change

* Update

* fixing test
This commit is contained in:
Torkel Ödegaard 2023-05-12 16:38:19 +02:00 committed by GitHub
parent 3869d2f239
commit c8fd3c20cd
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 133 additions and 26 deletions

View File

@ -1463,6 +1463,9 @@ exports[`better eslint`] = {
[0, 0, 0, "Unexpected any. Specify a different type.", "5"],
[0, 0, 0, "Unexpected any. Specify a different type.", "6"]
],
"public/app/core/components/AppChrome/News/NewsContainer.tsx:5381": [
[0, 0, 0, "Use data-testid for E2E selectors instead of aria-label", "0"]
],
"public/app/core/components/AppChrome/SectionNav/SectionNavItem.tsx:5381": [
[0, 0, 0, "Use data-testid for E2E selectors instead of aria-label", "0"]
],

View File

@ -1,6 +1,5 @@
import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import fs from 'fs';
import React from 'react';
import { NewsContainer } from './NewsContainer';
@ -12,17 +11,10 @@ const setup = () => {
};
describe('News', () => {
const result = fs.readFileSync(`${__dirname}/fixtures/news.xml`, 'utf8');
beforeEach(() => {
jest.resetAllMocks();
window.fetch = jest.fn().mockResolvedValue({ text: () => result });
});
it('should render the drawer when the drawer button is clicked', async () => {
setup();
await userEvent.click(screen.getByRole('button'));
expect(screen.getByRole('article')).toBeInTheDocument();
expect(screen.getByRole('link')).toHaveAttribute('href', 'https://www.example.net/2022/02/10/something-fake/');
expect(screen.getByText('Latest from the blog')).toBeInTheDocument();
});
});

View File

@ -1,7 +1,11 @@
import { css } from '@emotion/css';
import React from 'react';
import { useToggle } from 'react-use';
import { Drawer, ToolbarButton } from '@grafana/ui';
import { GrafanaTheme2 } from '@grafana/data';
import { selectors } from '@grafana/e2e-selectors';
import { Button, Drawer, ToolbarButton, useStyles2 } from '@grafana/ui';
import { H3 } from '@grafana/ui/src/unstable';
import { t } from 'app/core/internationalization';
import { DEFAULT_FEED_URL } from 'app/plugins/panel/news/constants';
@ -13,17 +17,36 @@ interface NewsContainerProps {
export function NewsContainer({ className }: NewsContainerProps) {
const [showNewsDrawer, onToggleShowNewsDrawer] = useToggle(false);
const onChildClick = () => {
onToggleShowNewsDrawer(true);
};
const styles = useStyles2(getStyles);
return (
<>
<ToolbarButton className={className} onClick={onChildClick} iconOnly icon="rss" aria-label="News" />
<ToolbarButton className={className} onClick={onToggleShowNewsDrawer} iconOnly icon="rss" aria-label="News" />
{showNewsDrawer && (
<Drawer
title={t('news.title', 'Latest from the blog')}
title={
<div className={styles.title}>
<H3>{t('news.title', 'Latest from the blog')}</H3>
<a
href="https://grafana.com/blog/"
target="_blank"
rel="noreferrer"
title="Go to Grafana labs blog"
className={styles.grot}
>
<img src="public/img/grot-news.svg" alt="Grot reading news" />
</a>
<div className={styles.actions}>
<Button
icon="times"
variant="secondary"
fill="text"
onClick={onToggleShowNewsDrawer}
aria-label={selectors.components.Drawer.General.close}
/>
</div>
</div>
}
scrollableContent
onClose={onToggleShowNewsDrawer}
size="md"
@ -34,3 +57,31 @@ export function NewsContainer({ className }: NewsContainerProps) {
</>
);
}
const getStyles = (theme: GrafanaTheme2) => {
return {
title: css({
display: `flex`,
alignItems: `center`,
justifyContent: `center`,
gap: theme.spacing(2),
borderBottom: `1px solid ${theme.colors.border.weak}`,
}),
grot: css({
display: `flex`,
alignItems: `center`,
justifyContent: `center`,
padding: theme.spacing(2, 0),
img: {
width: `75px`,
height: `75px`,
},
}),
actions: css({
position: 'absolute',
right: theme.spacing(1),
top: theme.spacing(2),
}),
};
};

View File

@ -1,6 +1,6 @@
import { css } from '@emotion/css';
import React, { useEffect } from 'react';
import AutoSizer from 'react-virtualized-auto-sizer';
import { useMeasure } from 'react-use';
import { GrafanaTheme2 } from '@grafana/data';
import { LoadingPlaceholder, useStyles2 } from '@grafana/ui';
@ -13,6 +13,8 @@ interface NewsWrapperProps {
export function NewsWrapper({ feedUrl }: NewsWrapperProps) {
const styles = useStyles2(getStyles);
const { state, getNews } = useNewsFeed(feedUrl);
const [widthRef, widthMeasure] = useMeasure<HTMLDivElement>();
useEffect(() => {
getNews();
}, [getNews]);
@ -31,15 +33,17 @@ export function NewsWrapper({ feedUrl }: NewsWrapperProps) {
}
return (
<AutoSizer>
{({ width }) => (
<div style={{ width: `${width}px` }}>
{state.value.map((_, index) => (
<News key={index} index={index} showImage width={width} data={state.value} />
))}
</div>
)}
</AutoSizer>
<div ref={widthRef}>
{widthMeasure.width > 0 &&
state.value.map((_, index) => (
<News key={index} index={index} showImage width={widthMeasure.width} data={state.value} />
))}
<div className={styles.grot}>
<a href="https://grafana.com/blog/" target="_blank" rel="noreferrer" title="Go to Grafana labs blog">
<img src="public/img/grot-news.svg" alt="Grot reading news" />
</a>
</div>
</div>
);
}
@ -52,5 +56,16 @@ const getStyles = (theme: GrafanaTheme2) => {
align-items: center;
justify-content: center;
`,
grot: css({
display: `flex`,
alignItems: `center`,
justifyContent: `center`,
padding: theme.spacing(5, 0),
img: {
width: `186px`,
height: `186px`,
},
}),
};
};

46
public/img/grot-news.svg Normal file

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 18 KiB