TopNav: Adding sign in to topnav and hiding it mega menu (#56403)

* TopNav: Adding sign in to topnav and hiding it mega menu

* Added target _self

* remove scss change

* Fix sign in link

* Fix other link
This commit is contained in:
Torkel Ödegaard 2022-10-06 13:00:32 +02:00 committed by GitHub
parent 0958d9ba55
commit a8b883b1fa
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 37 additions and 38 deletions

View File

@ -0,0 +1,29 @@
import { css } from '@emotion/css';
import React from 'react';
import { useLocation } from 'react-router-dom';
import { locationUtil } from '@grafana/data';
import { useStyles2 } from '@grafana/ui';
export function SignInLink() {
const location = useLocation();
const styles = useStyles2(getStyles);
const loginUrl = locationUtil.getUrlForPartial(location, { forceLogin: 'true' });
return (
<a className={styles.link} href={loginUrl} target="_self">
Sign in
</a>
);
}
const getStyles = () => {
return {
link: css({
whiteSpace: 'nowrap',
'&:hover': {
textDecoration: 'underline',
},
}),
};
};

View File

@ -7,6 +7,7 @@ import { contextSrv } from 'app/core/core';
import { useSelector } from 'app/types'; import { useSelector } from 'app/types';
import { NewsContainer } from './News/NewsContainer'; import { NewsContainer } from './News/NewsContainer';
import { SignInLink } from './TopBar/SignInLink';
import { TopNavBarMenu } from './TopBar/TopNavBarMenu'; import { TopNavBarMenu } from './TopBar/TopNavBarMenu';
import { TopSearchBarInput } from './TopSearchBarInput'; import { TopSearchBarInput } from './TopSearchBarInput';
import { TOP_BAR_LEVEL_HEIGHT } from './types'; import { TOP_BAR_LEVEL_HEIGHT } from './types';
@ -35,6 +36,7 @@ export function TopSearchBar() {
</Dropdown> </Dropdown>
)} )}
<NewsContainer /> <NewsContainer />
{!contextSrv.user.isSignedIn && <SignInLink />}
{profileNode && ( {profileNode && (
<Dropdown overlay={<TopNavBarMenu node={profileNode} />}> <Dropdown overlay={<TopNavBarMenu node={profileNode} />}>
<ToolbarButton <ToolbarButton
@ -73,6 +75,7 @@ const getStyles = (theme: GrafanaTheme2) => {
display: 'flex', display: 'flex',
gap: theme.spacing(0.5), gap: theme.spacing(0.5),
justifyContent: 'flex-end', justifyContent: 'flex-end',
alignItems: 'center',
}), }),
profileButton: css({ profileButton: css({
img: { img: {

View File

@ -3,37 +3,12 @@ import { Location } from 'history';
import { GrafanaConfig, locationUtil, NavModelItem } from '@grafana/data'; import { GrafanaConfig, locationUtil, NavModelItem } from '@grafana/data';
import { ContextSrv, setContextSrv } from 'app/core/services/context_srv'; import { ContextSrv, setContextSrv } from 'app/core/services/context_srv';
import { updateConfig } from '../../config'; import { enrichConfigItems, getActiveItem, isMatchOrChildMatch, isSearchActive } from './utils';
import { enrichConfigItems, getActiveItem, getForcedLoginUrl, isMatchOrChildMatch, isSearchActive } from './utils';
jest.mock('../../app_events', () => ({ jest.mock('../../app_events', () => ({
publish: jest.fn(), publish: jest.fn(),
})); }));
describe('getForcedLoginUrl', () => {
it.each`
appSubUrl | url | expected
${''} | ${'/whatever?a=1&b=2'} | ${'/whatever?a=1&b=2&forceLogin=true'}
${'/grafana'} | ${'/whatever?a=1&b=2'} | ${'/grafana/whatever?a=1&b=2&forceLogin=true'}
${'/grafana/test'} | ${'/whatever?a=1&b=2'} | ${'/grafana/test/whatever?a=1&b=2&forceLogin=true'}
${'/grafana'} | ${''} | ${'/grafana?forceLogin=true'}
${'/grafana'} | ${'/whatever'} | ${'/grafana/whatever?forceLogin=true'}
${'/grafana'} | ${'/whatever/'} | ${'/grafana/whatever/?forceLogin=true'}
`(
"when appUrl set to '$appUrl' and appSubUrl set to '$appSubUrl' then result should be '$expected'",
({ appSubUrl, url, expected }) => {
updateConfig({
appSubUrl,
});
const result = getForcedLoginUrl(url);
expect(result).toBe(expected);
}
);
});
describe('enrichConfigItems', () => { describe('enrichConfigItems', () => {
let mockItems: NavModelItem[]; let mockItems: NavModelItem[];
const mockLocation: Location<unknown> = { const mockLocation: Location<unknown> = {

View File

@ -1,8 +1,7 @@
import { Location } from 'history'; import { Location } from 'history';
import { locationUtil, NavModelItem, NavSection } from '@grafana/data'; import { locationUtil, NavModelItem, NavSection } from '@grafana/data';
import { reportInteraction } from '@grafana/runtime'; import { config, reportInteraction } from '@grafana/runtime';
import { getConfig } from 'app/core/config';
import { contextSrv } from 'app/core/services/context_srv'; import { contextSrv } from 'app/core/services/context_srv';
import { ShowModalReactEvent } from '../../../types/events'; import { ShowModalReactEvent } from '../../../types/events';
@ -16,13 +15,6 @@ export const NAV_MENU_PORTAL_CONTAINER_ID = 'navbar-menu-portal-container';
export const getNavMenuPortalContainer = () => document.getElementById(NAV_MENU_PORTAL_CONTAINER_ID) ?? document.body; export const getNavMenuPortalContainer = () => document.getElementById(NAV_MENU_PORTAL_CONTAINER_ID) ?? document.body;
export const getForcedLoginUrl = (url: string) => {
const queryParams = new URLSearchParams(url.split('?')[1]);
queryParams.append('forceLogin', 'true');
return `${getConfig().appSubUrl}${url.split('?')[0]}?${queryParams.toString()}`;
};
export const enrichConfigItems = (items: NavModelItem[], location: Location<unknown>) => { export const enrichConfigItems = (items: NavModelItem[], location: Location<unknown>) => {
const { isSignedIn, user } = contextSrv; const { isSignedIn, user } = contextSrv;
const onOpenShortcuts = () => { const onOpenShortcuts = () => {
@ -41,8 +33,8 @@ export const enrichConfigItems = (items: NavModelItem[], location: Location<unkn
} }
} }
if (!isSignedIn) { if (!isSignedIn && !config.featureToggles.topnav) {
const forcedLoginUrl = getForcedLoginUrl(location.pathname + location.search); const loginUrl = locationUtil.getUrlForPartial(location, { forceLogin: 'true' });
items.unshift({ items.unshift({
icon: 'signout', icon: 'signout',
@ -50,7 +42,7 @@ export const enrichConfigItems = (items: NavModelItem[], location: Location<unkn
section: NavSection.Config, section: NavSection.Config,
target: '_self', target: '_self',
text: 'Sign in', text: 'Sign in',
url: forcedLoginUrl, url: loginUrl,
}); });
} }