mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
TopNav: Move news into profile menu (#99535)
* remove news icon from topnav Signed-off-by: bergquist <carl.bergquist@gmail.com> * TopNav: Move rss feed and kiosk action into profile menu * Update language keys * Update * review fixes * Update * Update --------- Signed-off-by: bergquist <carl.bergquist@gmail.com> Co-authored-by: Torkel Ödegaard <torkel@grafana.com>
This commit is contained in:
parent
6392542db4
commit
a92c8145f1
@ -1003,9 +1003,8 @@ exports[`better eslint`] = {
|
||||
"public/app/core/components/AppChrome/MegaMenu/MegaMenuItem.tsx:5381": [
|
||||
[0, 0, 0, "No untranslated strings in text props. Wrap text with <Trans /> or use t()", "0"]
|
||||
],
|
||||
"public/app/core/components/AppChrome/News/NewsContainer.tsx:5381": [
|
||||
[0, 0, 0, "No untranslated strings in text props. Wrap text with <Trans /> or use t()", "0"],
|
||||
[0, 0, 0, "No untranslated strings in text props. Wrap text with <Trans /> or use t()", "1"]
|
||||
"public/app/core/components/AppChrome/News/NewsDrawer.tsx:5381": [
|
||||
[0, 0, 0, "No untranslated strings in text props. Wrap text with <Trans /> or use t()", "0"]
|
||||
],
|
||||
"public/app/core/components/AppChrome/News/NewsWrapper.tsx:5381": [
|
||||
[0, 0, 0, "No untranslated strings in text props. Wrap text with <Trans /> or use t()", "0"]
|
||||
@ -1016,10 +1015,12 @@ exports[`better eslint`] = {
|
||||
"public/app/core/components/AppChrome/QuickAdd/QuickAdd.tsx:5381": [
|
||||
[0, 0, 0, "No untranslated strings in text props. Wrap text with <Trans /> or use t()", "0"]
|
||||
],
|
||||
"public/app/core/components/AppChrome/TopBar/ProfileButton.tsx:5381": [
|
||||
[0, 0, 0, "No untranslated strings in text props. Wrap text with <Trans /> or use t()", "0"]
|
||||
],
|
||||
"public/app/core/components/AppChrome/TopBar/SingleTopBar.tsx:5381": [
|
||||
[0, 0, 0, "No untranslated strings in text props. Wrap text with <Trans /> or use t()", "0"],
|
||||
[0, 0, 0, "No untranslated strings in text props. Wrap text with <Trans /> or use t()", "1"],
|
||||
[0, 0, 0, "No untranslated strings in text props. Wrap text with <Trans /> or use t()", "2"]
|
||||
[0, 0, 0, "No untranslated strings in text props. Wrap text with <Trans /> or use t()", "1"]
|
||||
],
|
||||
"public/app/core/components/AppChrome/TopBar/TopSearchBarCommandPaletteTrigger.tsx:5381": [
|
||||
[0, 0, 0, "\'@grafana/ui/src/themes/mixins\' import is restricted from being used by a pattern. Import from the public export instead.", "0"]
|
||||
|
@ -1,19 +0,0 @@
|
||||
import { render, screen } from '@testing-library/react';
|
||||
import userEvent from '@testing-library/user-event';
|
||||
|
||||
import { NewsContainer } from './NewsContainer';
|
||||
|
||||
const setup = () => {
|
||||
const { container } = render(<NewsContainer />);
|
||||
|
||||
return { container };
|
||||
};
|
||||
|
||||
describe('News', () => {
|
||||
it('should render the drawer when the drawer button is clicked', async () => {
|
||||
setup();
|
||||
|
||||
await userEvent.click(screen.getByRole('button'));
|
||||
expect(screen.getByText('Latest from the blog')).toBeInTheDocument();
|
||||
});
|
||||
});
|
@ -1,84 +0,0 @@
|
||||
import { css } from '@emotion/css';
|
||||
import { useToggle } from 'react-use';
|
||||
|
||||
import { GrafanaTheme2 } from '@grafana/data';
|
||||
import { selectors } from '@grafana/e2e-selectors';
|
||||
import { IconButton, Drawer, ToolbarButton, useStyles2, Text } from '@grafana/ui';
|
||||
import { t } from 'app/core/internationalization';
|
||||
import { DEFAULT_FEED_URL } from 'app/plugins/panel/news/constants';
|
||||
|
||||
import { NewsWrapper } from './NewsWrapper';
|
||||
|
||||
interface NewsContainerProps {
|
||||
className?: string;
|
||||
}
|
||||
|
||||
export function NewsContainer({ className }: NewsContainerProps) {
|
||||
const [showNewsDrawer, onToggleShowNewsDrawer] = useToggle(false);
|
||||
const styles = useStyles2(getStyles);
|
||||
|
||||
return (
|
||||
<>
|
||||
<ToolbarButton className={className} onClick={onToggleShowNewsDrawer} iconOnly icon="rss" aria-label="News" />
|
||||
{showNewsDrawer && (
|
||||
<Drawer
|
||||
title={
|
||||
<div className={styles.title}>
|
||||
<Text element="h2">{t('news.title', 'Latest from the blog')}</Text>
|
||||
<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}>
|
||||
<IconButton
|
||||
name="times"
|
||||
variant="secondary"
|
||||
onClick={onToggleShowNewsDrawer}
|
||||
data-testid={selectors.components.Drawer.General.close}
|
||||
tooltip={t(`news.drawer.close`, 'Close Drawer')}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
onClose={onToggleShowNewsDrawer}
|
||||
size="md"
|
||||
>
|
||||
<NewsWrapper feedUrl={DEFAULT_FEED_URL} />
|
||||
</Drawer>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
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),
|
||||
}),
|
||||
};
|
||||
};
|
78
public/app/core/components/AppChrome/News/NewsDrawer.tsx
Normal file
78
public/app/core/components/AppChrome/News/NewsDrawer.tsx
Normal file
@ -0,0 +1,78 @@
|
||||
import { css } from '@emotion/css';
|
||||
|
||||
import { GrafanaTheme2 } from '@grafana/data';
|
||||
import { selectors } from '@grafana/e2e-selectors';
|
||||
import { IconButton, Drawer, useStyles2, Text } from '@grafana/ui';
|
||||
import { t } from 'app/core/internationalization';
|
||||
import { DEFAULT_FEED_URL } from 'app/plugins/panel/news/constants';
|
||||
|
||||
import { NewsWrapper } from './NewsWrapper';
|
||||
|
||||
interface NewsContainerProps {
|
||||
className?: string;
|
||||
onClose: () => void;
|
||||
}
|
||||
|
||||
export function NewsContainer({ onClose }: NewsContainerProps) {
|
||||
const styles = useStyles2(getStyles);
|
||||
|
||||
return (
|
||||
<Drawer
|
||||
title={
|
||||
<div className={styles.title}>
|
||||
<Text element="h2">{t('news.title', 'Latest from the blog')}</Text>
|
||||
<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}>
|
||||
<IconButton
|
||||
name="times"
|
||||
variant="secondary"
|
||||
onClick={onClose}
|
||||
data-testid={selectors.components.Drawer.General.close}
|
||||
tooltip={t(`news.drawer.close`, 'Close Drawer')}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
onClose={onClose}
|
||||
size="md"
|
||||
>
|
||||
<NewsWrapper feedUrl={DEFAULT_FEED_URL} />
|
||||
</Drawer>
|
||||
);
|
||||
}
|
||||
|
||||
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),
|
||||
}),
|
||||
};
|
||||
};
|
@ -0,0 +1,71 @@
|
||||
import { css } from '@emotion/css';
|
||||
import { cloneDeep } from 'lodash';
|
||||
import { useToggle } from 'react-use';
|
||||
|
||||
import { GrafanaTheme2, NavModelItem } from '@grafana/data';
|
||||
import { config } from '@grafana/runtime';
|
||||
import { Dropdown, Menu, MenuItem, ToolbarButton, useStyles2 } from '@grafana/ui';
|
||||
import { contextSrv } from 'app/core/core';
|
||||
import { t } from 'app/core/internationalization';
|
||||
|
||||
import { enrichWithInteractionTracking } from '../MegaMenu/utils';
|
||||
import { NewsContainer } from '../News/NewsDrawer';
|
||||
|
||||
import { TopNavBarMenu } from './TopNavBarMenu';
|
||||
|
||||
export interface Props {
|
||||
profileNode: NavModelItem;
|
||||
}
|
||||
|
||||
export function ProfileButton({ profileNode }: Props) {
|
||||
const styles = useStyles2(getStyles);
|
||||
const node = enrichWithInteractionTracking(cloneDeep(profileNode), false);
|
||||
const [showNewsDrawer, onToggleShowNewsDrawer] = useToggle(false);
|
||||
|
||||
if (!node) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const renderMenu = () => (
|
||||
<TopNavBarMenu node={profileNode}>
|
||||
{config.newsFeedEnabled && (
|
||||
<>
|
||||
<Menu.Divider />
|
||||
<MenuItem
|
||||
icon="rss"
|
||||
onClick={onToggleShowNewsDrawer}
|
||||
label={t('navigation.rss-button', 'Latest from the blog')}
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
</TopNavBarMenu>
|
||||
);
|
||||
|
||||
return (
|
||||
<>
|
||||
<Dropdown overlay={renderMenu} placement="bottom-end">
|
||||
<ToolbarButton
|
||||
className={styles.profileButton}
|
||||
imgSrc={contextSrv.user.gravatarUrl}
|
||||
imgAlt="User avatar"
|
||||
aria-label="Profile"
|
||||
/>
|
||||
</Dropdown>
|
||||
{showNewsDrawer && <NewsContainer onClose={onToggleShowNewsDrawer} />}
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
const getStyles = (theme: GrafanaTheme2) => {
|
||||
return {
|
||||
profileButton: css({
|
||||
padding: theme.spacing(0, 0.5),
|
||||
img: {
|
||||
borderRadius: theme.shape.radius.circle,
|
||||
height: '24px',
|
||||
marginRight: 0,
|
||||
width: '24px',
|
||||
},
|
||||
}),
|
||||
};
|
||||
};
|
@ -16,10 +16,10 @@ import { Breadcrumbs } from '../../Breadcrumbs/Breadcrumbs';
|
||||
import { buildBreadcrumbs } from '../../Breadcrumbs/utils';
|
||||
import { HistoryContainer } from '../History/HistoryContainer';
|
||||
import { enrichHelpItem } from '../MegaMenu/utils';
|
||||
import { NewsContainer } from '../News/NewsContainer';
|
||||
import { QuickAdd } from '../QuickAdd/QuickAdd';
|
||||
import { TOP_BAR_LEVEL_HEIGHT } from '../types';
|
||||
|
||||
import { ProfileButton } from './ProfileButton';
|
||||
import { SignInLink } from './SignInLink';
|
||||
import { TopNavBarMenu } from './TopNavBarMenu';
|
||||
import { TopSearchBarCommandPaletteTrigger } from './TopSearchBarCommandPaletteTrigger';
|
||||
@ -80,7 +80,6 @@ export const SingleTopBar = memo(function SingleTopBar({
|
||||
<ToolbarButton iconOnly icon="question-circle" aria-label="Help" />
|
||||
</Dropdown>
|
||||
)}
|
||||
{config.newsFeedEnabled && <NewsContainer />}
|
||||
<ToolbarButton
|
||||
icon="monitor"
|
||||
className={styles.kioskToggle}
|
||||
@ -88,16 +87,7 @@ export const SingleTopBar = memo(function SingleTopBar({
|
||||
tooltip="Enable kiosk mode"
|
||||
/>
|
||||
{!contextSrv.user.isSignedIn && <SignInLink />}
|
||||
{profileNode && (
|
||||
<Dropdown overlay={() => <TopNavBarMenu node={profileNode} />} placement="bottom-end">
|
||||
<ToolbarButton
|
||||
className={styles.profileButton}
|
||||
imgSrc={contextSrv.user.gravatarUrl}
|
||||
imgAlt="User avatar"
|
||||
aria-label="Profile"
|
||||
/>
|
||||
</Dropdown>
|
||||
)}
|
||||
{profileNode && <ProfileButton profileNode={profileNode} />}
|
||||
</Stack>
|
||||
</div>
|
||||
);
|
||||
@ -132,15 +122,6 @@ const getStyles = (theme: GrafanaTheme2, menuDockedAndOpen: boolean) => ({
|
||||
height: theme.spacing(3),
|
||||
width: theme.spacing(3),
|
||||
}),
|
||||
profileButton: css({
|
||||
padding: theme.spacing(0, 0.5),
|
||||
img: {
|
||||
borderRadius: theme.shape.radius.circle,
|
||||
height: '24px',
|
||||
marginRight: 0,
|
||||
width: '24px',
|
||||
},
|
||||
}),
|
||||
kioskToggle: css({
|
||||
[theme.breakpoints.down('lg')]: {
|
||||
display: 'none',
|
||||
|
@ -8,9 +8,10 @@ import { enrichWithInteractionTracking } from '../MegaMenu/utils';
|
||||
|
||||
export interface TopNavBarMenuProps {
|
||||
node: NavModelItem;
|
||||
children?: React.ReactNode;
|
||||
}
|
||||
|
||||
export function TopNavBarMenu({ node: nodePlain }: TopNavBarMenuProps) {
|
||||
export function TopNavBarMenu({ node: nodePlain, children }: TopNavBarMenuProps) {
|
||||
const styles = useStyles2(getStyles);
|
||||
const node = enrichWithInteractionTracking(cloneDeep(nodePlain), false);
|
||||
|
||||
@ -37,6 +38,7 @@ export function TopNavBarMenu({ node: nodePlain }: TopNavBarMenuProps) {
|
||||
<MenuItem icon={item.icon} onClick={item.onClick} label={item.text} key={item.id} />
|
||||
);
|
||||
})}
|
||||
{children}
|
||||
</Menu>
|
||||
);
|
||||
}
|
||||
|
@ -2430,7 +2430,8 @@
|
||||
"list-label": "Navigation",
|
||||
"open": "Open menu",
|
||||
"undock": "Undock menu"
|
||||
}
|
||||
},
|
||||
"rss-button": "Latest from the blog"
|
||||
},
|
||||
"news": {
|
||||
"drawer": {
|
||||
|
@ -2430,7 +2430,8 @@
|
||||
"list-label": "Ńävįģäŧįőʼn",
|
||||
"open": "Øpęʼn męʼnū",
|
||||
"undock": "Ůʼnđőčĸ męʼnū"
|
||||
}
|
||||
},
|
||||
"rss-button": "Ŀäŧęşŧ ƒřőm ŧĥę þľőģ"
|
||||
},
|
||||
"news": {
|
||||
"drawer": {
|
||||
|
Loading…
Reference in New Issue
Block a user