mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
TopNav: A possible approach having a TopNav that lives outside route (#51301)
* Add topnav in Route * TopBar: Good progress on a approach that looks promising * Added some elements to top level * Get page nav from route * Progress * Making breadcrumbs slightly more real * Updates * Memoize selector * Removed some console.log * correctly type iconName * betterer updates * Change setting to hideNav * Rename again Co-authored-by: Ashley Harrison <ashley.harrison@grafana.com>
This commit is contained in:
parent
6c43eb0b4d
commit
f047f7dcf6
@ -3544,7 +3544,7 @@ exports[`better eslint`] = {
|
||||
[11, 6, 169, "Do not use any type assertions.", "2248693214"],
|
||||
[17, 11, 3, "Unexpected any. Specify a different type.", "193409811"]
|
||||
],
|
||||
"public/app/core/navigation/types.ts:2017971154": [
|
||||
"public/app/core/navigation/types.ts:2395305220": [
|
||||
[10, 38, 3, "Unexpected any. Specify a different type.", "193409811"],
|
||||
[14, 35, 3, "Unexpected any. Specify a different type.", "193409811"]
|
||||
],
|
||||
@ -4653,8 +4653,8 @@ exports[`better eslint`] = {
|
||||
[176, 29, 13, "Do not use any type assertions.", "2146830713"],
|
||||
[195, 32, 3, "Unexpected any. Specify a different type.", "193409811"]
|
||||
],
|
||||
"public/app/features/dashboard/components/DashNav/DashNav.tsx:574528540": [
|
||||
[66, 87, 3, "Unexpected any. Specify a different type.", "193409811"]
|
||||
"public/app/features/dashboard/components/DashNav/DashNav.tsx:1533394562": [
|
||||
[67, 87, 3, "Unexpected any. Specify a different type.", "193409811"]
|
||||
],
|
||||
"public/app/features/dashboard/components/DashNav/DashNavTimeControls.test.tsx:3825334541": [
|
||||
[49, 17, 3, "Unexpected any. Specify a different type.", "193409811"],
|
||||
@ -6580,16 +6580,16 @@ exports[`better eslint`] = {
|
||||
"public/app/features/profile/state/reducers.test.ts:1105044753": [
|
||||
[18, 15, 3, "Unexpected any. Specify a different type.", "193409811"]
|
||||
],
|
||||
"public/app/features/query/components/QueryEditorRow.test.ts:589354782": [
|
||||
[5, 9, 60, "Do not use any type assertions.", "155833034"],
|
||||
[48, 22, 101, "Do not use any type assertions.", "3734235969"],
|
||||
[48, 22, 88, "Do not use any type assertions.", "3757401717"]
|
||||
"public/app/features/query/components/QueryEditorRow.test.ts:4201471442": [
|
||||
[7, 9, 60, "Do not use any type assertions.", "155833034"],
|
||||
[50, 22, 101, "Do not use any type assertions.", "3734235969"],
|
||||
[50, 22, 88, "Do not use any type assertions.", "3757401717"]
|
||||
],
|
||||
"public/app/features/query/components/QueryEditorRow.tsx:3534885470": [
|
||||
[95, 22, 20, "Do not use any type assertions.", "2923490522"],
|
||||
[142, 18, 46, "Do not use any type assertions.", "1673417097"],
|
||||
[142, 18, 21, "Do not use any type assertions.", "1354497810"],
|
||||
[317, 22, 40, "Do not use any type assertions.", "1350130209"]
|
||||
"public/app/features/query/components/QueryEditorRow.tsx:209136238": [
|
||||
[97, 22, 20, "Do not use any type assertions.", "2923490522"],
|
||||
[144, 18, 46, "Do not use any type assertions.", "1673417097"],
|
||||
[144, 18, 21, "Do not use any type assertions.", "1354497810"],
|
||||
[356, 22, 40, "Do not use any type assertions.", "1350130209"]
|
||||
],
|
||||
"public/app/features/query/components/QueryEditorRowHeader.test.tsx:2607197828": [
|
||||
[99, 16, 32, "Do not use any type assertions.", "2255106576"]
|
||||
|
@ -106,6 +106,7 @@ export const getAvailableIcons = () =>
|
||||
'heart',
|
||||
'heart-break',
|
||||
'history',
|
||||
'home',
|
||||
'home-alt',
|
||||
'horizontal-align-center',
|
||||
'horizontal-align-left',
|
||||
@ -179,6 +180,7 @@ export const getAvailableIcons = () =>
|
||||
'vertical-align-center',
|
||||
'vertical-align-top',
|
||||
'wrap-text',
|
||||
'rss',
|
||||
'x',
|
||||
] as const;
|
||||
|
||||
|
82
public/app/core/components/TopNav/Breadcrumbs.tsx
Normal file
82
public/app/core/components/TopNav/Breadcrumbs.tsx
Normal file
@ -0,0 +1,82 @@
|
||||
import { css } from '@emotion/css';
|
||||
import React from 'react';
|
||||
|
||||
import { GrafanaTheme2, NavModelItem } from '@grafana/data';
|
||||
import { useStyles2, Icon, IconName } from '@grafana/ui';
|
||||
|
||||
import { TopNavProps } from './TopNavUpdate';
|
||||
|
||||
export interface Props extends TopNavProps {
|
||||
sectionNav: NavModelItem;
|
||||
subNav?: NavModelItem;
|
||||
}
|
||||
|
||||
export interface Breadcrumb {
|
||||
text?: string;
|
||||
icon?: IconName;
|
||||
href?: string;
|
||||
}
|
||||
|
||||
export function Breadcrumbs({ sectionNav, subNav }: Props) {
|
||||
const styles = useStyles2(getStyles);
|
||||
const crumbs: Breadcrumb[] = [{ icon: 'home', href: '/' }];
|
||||
|
||||
function addCrumbs(node: NavModelItem) {
|
||||
if (node.parentItem) {
|
||||
addCrumbs(node.parentItem);
|
||||
}
|
||||
|
||||
crumbs.push({ text: node.text, href: node.url });
|
||||
}
|
||||
|
||||
addCrumbs(sectionNav);
|
||||
|
||||
if (subNav) {
|
||||
addCrumbs(subNav);
|
||||
}
|
||||
|
||||
return (
|
||||
<ul className={styles.breadcrumbs}>
|
||||
{crumbs.map((breadcrumb, index) => (
|
||||
<li className={styles.breadcrumb} key={index}>
|
||||
{breadcrumb.href && (
|
||||
<a className={styles.breadcrumbLink} href={breadcrumb.href}>
|
||||
{breadcrumb.text}
|
||||
{breadcrumb.icon && <Icon name={breadcrumb.icon} />}
|
||||
</a>
|
||||
)}
|
||||
{!breadcrumb.href && <span className={styles.breadcrumbLink}>{breadcrumb.text}</span>}
|
||||
{index + 1 < crumbs.length && (
|
||||
<div className={styles.separator}>
|
||||
<Icon name="angle-right" />
|
||||
</div>
|
||||
)}
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
);
|
||||
}
|
||||
|
||||
const getStyles = (theme: GrafanaTheme2) => {
|
||||
return {
|
||||
breadcrumbs: css({
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
fontWeight: theme.typography.fontWeightMedium,
|
||||
}),
|
||||
breadcrumb: css({
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
}),
|
||||
separator: css({
|
||||
color: theme.colors.text.secondary,
|
||||
padding: theme.spacing(0, 0.5),
|
||||
}),
|
||||
breadcrumbLink: css({
|
||||
color: theme.colors.text.primary,
|
||||
'&:hover': {
|
||||
textDecoration: 'underline',
|
||||
},
|
||||
}),
|
||||
};
|
||||
};
|
62
public/app/core/components/TopNav/NavToolbar.tsx
Normal file
62
public/app/core/components/TopNav/NavToolbar.tsx
Normal file
@ -0,0 +1,62 @@
|
||||
import { css } from '@emotion/css';
|
||||
import React from 'react';
|
||||
|
||||
import { GrafanaTheme2, NavModelItem } from '@grafana/data';
|
||||
import { IconButton, ToolbarButton, useStyles2 } from '@grafana/ui';
|
||||
|
||||
import { Breadcrumbs } from './Breadcrumbs';
|
||||
import { TopNavProps } from './TopNavUpdate';
|
||||
import { TOP_BAR_LEVEL_HEIGHT } from './types';
|
||||
|
||||
export interface Props extends TopNavProps {
|
||||
onToggleSearchBar(): void;
|
||||
searchBarHidden?: boolean;
|
||||
sectionNav: NavModelItem;
|
||||
subNav?: NavModelItem;
|
||||
}
|
||||
|
||||
export function NavToolbar({ actions, onToggleSearchBar, searchBarHidden, sectionNav, subNav }: Props) {
|
||||
const styles = useStyles2(getStyles);
|
||||
|
||||
return (
|
||||
<div className={styles.pageToolbar}>
|
||||
<div className={styles.menuButton}>
|
||||
<IconButton name="bars" tooltip="Toggle menu" tooltipPlacement="bottom" size="xl" onClick={() => {}} />
|
||||
</div>
|
||||
<Breadcrumbs sectionNav={sectionNav} subNav={subNav} />
|
||||
<div className={styles.leftActions}></div>
|
||||
<div className={styles.rightActions}>
|
||||
{actions}
|
||||
<ToolbarButton icon={searchBarHidden ? 'angle-down' : 'angle-up'} onClick={onToggleSearchBar} />
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
const getStyles = (theme: GrafanaTheme2) => {
|
||||
return {
|
||||
pageToolbar: css({
|
||||
height: TOP_BAR_LEVEL_HEIGHT,
|
||||
display: 'flex',
|
||||
padding: theme.spacing(0, 2),
|
||||
alignItems: 'center',
|
||||
justifyContent: 'space-between',
|
||||
}),
|
||||
menuButton: css({
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
paddingRight: theme.spacing(1),
|
||||
}),
|
||||
leftActions: css({
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
flexGrow: 1,
|
||||
gap: theme.spacing(2),
|
||||
}),
|
||||
rightActions: css({
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
gap: theme.spacing(2),
|
||||
}),
|
||||
};
|
||||
};
|
80
public/app/core/components/TopNav/TopNavPage.tsx
Normal file
80
public/app/core/components/TopNav/TopNavPage.tsx
Normal file
@ -0,0 +1,80 @@
|
||||
import { css, cx } from '@emotion/css';
|
||||
import React, { PropsWithChildren } from 'react';
|
||||
import { useSelector } from 'react-redux';
|
||||
import { useObservable, useToggle } from 'react-use';
|
||||
import { createSelector } from 'reselect';
|
||||
|
||||
import { GrafanaTheme2 } from '@grafana/data';
|
||||
import { useStyles2 } from '@grafana/ui';
|
||||
import { getNavModel } from 'app/core/selectors/navModel';
|
||||
import { StoreState } from 'app/types';
|
||||
|
||||
import { NavToolbar } from './NavToolbar';
|
||||
import { topNavDefaultProps, topNavUpdates } from './TopNavUpdate';
|
||||
import { TopSearchBar } from './TopSearchBar';
|
||||
import { TOP_BAR_LEVEL_HEIGHT } from './types';
|
||||
|
||||
export interface Props extends PropsWithChildren<{}> {
|
||||
/** This is nav tree id provided by route.
|
||||
* It's not enough for item navigation. For that pages will need provide an item nav model as well via TopNavUpdate
|
||||
*/
|
||||
navId?: string;
|
||||
}
|
||||
|
||||
export function TopNavPage({ children, navId }: Props) {
|
||||
const styles = useStyles2(getStyles);
|
||||
const [searchBarHidden, toggleSearchBar] = useToggle(false); // repace with local storage
|
||||
const props = useObservable(topNavUpdates, topNavDefaultProps);
|
||||
const navModel = useSelector(createSelector(getNavIndex, (navIndex) => getNavModel(navIndex, navId ?? 'home')));
|
||||
|
||||
return (
|
||||
<div className={styles.viewport}>
|
||||
<div className={styles.topNav}>
|
||||
{!searchBarHidden && <TopSearchBar />}
|
||||
<NavToolbar
|
||||
{...props}
|
||||
searchBarHidden={searchBarHidden}
|
||||
onToggleSearchBar={toggleSearchBar}
|
||||
sectionNav={navModel.node}
|
||||
/>
|
||||
</div>
|
||||
<div className={cx(styles.content, searchBarHidden && styles.contentNoSearchBar)}>{children}</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
function getNavIndex(store: StoreState) {
|
||||
return store.navIndex;
|
||||
}
|
||||
|
||||
const getStyles = (theme: GrafanaTheme2) => {
|
||||
const shadow = theme.isDark
|
||||
? `0 0.6px 1.5px rgb(0 0 0), 0 2px 4px rgb(0 0 0 / 40%), 0 5px 10px rgb(0 0 0 / 23%)`
|
||||
: '0 0.6px 1.5px rgb(0 0 0 / 8%), 0 2px 4px rgb(0 0 0 / 6%), 0 5px 10px rgb(0 0 0 / 5%)';
|
||||
|
||||
return {
|
||||
viewport: css({
|
||||
display: 'flex',
|
||||
flexGrow: 1,
|
||||
height: '100%',
|
||||
}),
|
||||
content: css({
|
||||
display: 'flex',
|
||||
paddingTop: TOP_BAR_LEVEL_HEIGHT * 2 + 16,
|
||||
flexGrow: 1,
|
||||
}),
|
||||
contentNoSearchBar: css({
|
||||
paddingTop: TOP_BAR_LEVEL_HEIGHT + 16,
|
||||
}),
|
||||
topNav: css({
|
||||
display: 'flex',
|
||||
position: 'fixed',
|
||||
zIndex: theme.zIndex.navbarFixed,
|
||||
left: 0,
|
||||
right: 0,
|
||||
boxShadow: shadow,
|
||||
background: theme.colors.background.primary,
|
||||
flexDirection: 'column',
|
||||
}),
|
||||
};
|
||||
};
|
23
public/app/core/components/TopNav/TopNavUpdate.tsx
Normal file
23
public/app/core/components/TopNav/TopNavUpdate.tsx
Normal file
@ -0,0 +1,23 @@
|
||||
import { useEffect } from 'react';
|
||||
import { Subject } from 'rxjs';
|
||||
|
||||
import { NavModelItem } from '@grafana/data';
|
||||
|
||||
export interface TopNavProps {
|
||||
subNav?: NavModelItem;
|
||||
actions?: React.ReactNode;
|
||||
}
|
||||
|
||||
export const topNavUpdates = new Subject<TopNavProps>();
|
||||
export const topNavDefaultProps: TopNavProps = {};
|
||||
|
||||
/**
|
||||
* This needs to be moved to @grafana/ui or runtime.
|
||||
* This is the way core pages and plugins update the breadcrumbs and page toolbar actions
|
||||
*/
|
||||
export function TopNavUpdate(props: TopNavProps) {
|
||||
useEffect(() => {
|
||||
topNavUpdates.next(props);
|
||||
});
|
||||
return null;
|
||||
}
|
90
public/app/core/components/TopNav/TopSearchBar.tsx
Normal file
90
public/app/core/components/TopNav/TopSearchBar.tsx
Normal file
@ -0,0 +1,90 @@
|
||||
import { css } from '@emotion/css';
|
||||
import React from 'react';
|
||||
|
||||
import { GrafanaTheme2 } from '@grafana/data';
|
||||
import { FilterInput, Icon, Tooltip, useStyles2 } from '@grafana/ui';
|
||||
import { contextSrv } from 'app/core/core';
|
||||
|
||||
import { TOP_BAR_LEVEL_HEIGHT } from './types';
|
||||
|
||||
export function TopSearchBar() {
|
||||
const styles = useStyles2(getStyles);
|
||||
|
||||
return (
|
||||
<div className={styles.searchBar}>
|
||||
<a className={styles.logo} href="/" title="Go to home">
|
||||
<Icon name="grafana" size="xl" />
|
||||
</a>
|
||||
<div className={styles.searchWrapper}>
|
||||
<FilterInput
|
||||
width={50}
|
||||
placeholder="Search grafana"
|
||||
value={''}
|
||||
onChange={() => {}}
|
||||
className={styles.searchInput}
|
||||
/>
|
||||
</div>
|
||||
<div className={styles.actions}>
|
||||
<Tooltip placement="bottom" content="Help menu (todo)">
|
||||
<button className={styles.actionItem}>
|
||||
<Icon name="question-circle" size="lg" />
|
||||
</button>
|
||||
</Tooltip>
|
||||
<Tooltip placement="bottom" content="Grafana news (todo)">
|
||||
<button className={styles.actionItem}>
|
||||
<Icon name="rss" size="lg" />
|
||||
</button>
|
||||
</Tooltip>
|
||||
<Tooltip placement="bottom" content="User profile (todo)">
|
||||
<button className={styles.actionItem}>
|
||||
<img src={contextSrv.user.gravatarUrl} />
|
||||
</button>
|
||||
</Tooltip>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
const getStyles = (theme: GrafanaTheme2) => {
|
||||
return {
|
||||
searchBar: css({
|
||||
height: TOP_BAR_LEVEL_HEIGHT,
|
||||
display: 'flex',
|
||||
padding: theme.spacing(0, 2),
|
||||
alignItems: 'center',
|
||||
justifyContent: 'space-between',
|
||||
border: `1px solid ${theme.colors.border.weak}`,
|
||||
}),
|
||||
logo: css({
|
||||
display: 'flex',
|
||||
}),
|
||||
searchWrapper: css({}),
|
||||
searchInput: css({}),
|
||||
actions: css({
|
||||
display: 'flex',
|
||||
flexGrow: 0,
|
||||
gap: theme.spacing(1),
|
||||
position: 'relative',
|
||||
width: 25, // this and the left pos is to make search input perfectly centered
|
||||
left: -83,
|
||||
}),
|
||||
actionItem: css({
|
||||
display: 'flex',
|
||||
flexGrow: 0,
|
||||
border: 'none',
|
||||
boxShadow: 'none',
|
||||
background: 'none',
|
||||
alignItems: 'center',
|
||||
|
||||
color: theme.colors.text.secondary,
|
||||
'&:hover': {
|
||||
background: theme.colors.background.secondary,
|
||||
},
|
||||
img: {
|
||||
borderRadius: '50%',
|
||||
width: '24px',
|
||||
height: '24px',
|
||||
},
|
||||
}),
|
||||
};
|
||||
};
|
1
public/app/core/components/TopNav/types.ts
Normal file
1
public/app/core/components/TopNav/types.ts
Normal file
@ -0,0 +1 @@
|
||||
export const TOP_BAR_LEVEL_HEIGHT = 40;
|
@ -2,8 +2,9 @@ import React from 'react';
|
||||
// @ts-ignore
|
||||
import Drop from 'tether-drop';
|
||||
|
||||
import { locationSearchToObject, navigationLogger, reportPageview } from '@grafana/runtime';
|
||||
import { config, locationSearchToObject, navigationLogger, reportPageview } from '@grafana/runtime';
|
||||
|
||||
import { TopNavPage } from '../components/TopNav/TopNavPage';
|
||||
import { keybindingSrv } from '../services/keybindingSrv';
|
||||
|
||||
import { GrafanaRouteComponentProps } from './types';
|
||||
@ -70,7 +71,12 @@ export class GrafanaRoute extends React.Component<Props> {
|
||||
navigationLogger('GrafanaRoute', false, 'Rendered', props.route);
|
||||
|
||||
const RouteComponent = props.route.component;
|
||||
const routeElement = <RouteComponent {...props} queryParams={locationSearchToObject(props.location.search)} />;
|
||||
|
||||
return <RouteComponent {...props} queryParams={locationSearchToObject(props.location.search)} />;
|
||||
if (config.featureToggles.topnav && !props.route.navHidden) {
|
||||
return <TopNavPage navId={props.route.navId}>{routeElement}</TopNavPage>;
|
||||
}
|
||||
|
||||
return routeElement;
|
||||
}
|
||||
}
|
||||
|
@ -17,5 +17,7 @@ export interface RouteDescriptor {
|
||||
pageClass?: string;
|
||||
/** Can be used like an id for the route if the same component is used by many routes */
|
||||
routeName?: string;
|
||||
navHidden?: boolean;
|
||||
exact?: boolean;
|
||||
navId?: string;
|
||||
}
|
||||
|
@ -5,6 +5,7 @@ import { useLocation } from 'react-router-dom';
|
||||
import { locationUtil, textUtil } from '@grafana/data';
|
||||
import { locationService } from '@grafana/runtime';
|
||||
import { ButtonGroup, ModalsController, ToolbarButton, PageToolbar, useForceUpdate } from '@grafana/ui';
|
||||
import { TopNavUpdate } from 'app/core/components/TopNav/TopNavUpdate';
|
||||
import config from 'app/core/config';
|
||||
import { toggleKioskMode } from 'app/core/navigation/kiosk';
|
||||
import { DashboardCommentsModal } from 'app/features/dashboard/components/DashboardComments/DashboardCommentsModal';
|
||||
@ -274,6 +275,15 @@ export const DashNav = React.memo<Props>((props) => {
|
||||
const parentHref = locationUtil.getUrlForPartial(location, { search: 'open', folder: 'current' });
|
||||
const onGoBack = isFullscreen ? onClose : undefined;
|
||||
|
||||
if (config.featureToggles.topnav) {
|
||||
return (
|
||||
<TopNavUpdate
|
||||
subNav={{ text: title }}
|
||||
actions={<ToolbarButton onClick={onOpenSettings} icon="cog"></ToolbarButton>}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<PageToolbar
|
||||
pageIcon={isFullscreen ? undefined : 'apps'}
|
||||
|
@ -33,6 +33,7 @@ export function getAppRoutes(): RouteDescriptor[] {
|
||||
},
|
||||
{
|
||||
path: '/d/:uid/:slug?',
|
||||
navId: 'dashboards',
|
||||
pageClass: 'page-dashboard',
|
||||
routeName: DashboardRoutes.Normal,
|
||||
component: SafeDynamicImport(
|
||||
@ -90,6 +91,7 @@ export function getAppRoutes(): RouteDescriptor[] {
|
||||
},
|
||||
{
|
||||
path: '/datasources',
|
||||
navId: 'datasources',
|
||||
component: SafeDynamicImport(
|
||||
() => import(/* webpackChunkName: "DataSourcesListPage"*/ 'app/features/datasources/DataSourcesListPage')
|
||||
),
|
||||
@ -191,6 +193,7 @@ export function getAppRoutes(): RouteDescriptor[] {
|
||||
},
|
||||
{
|
||||
path: '/org/users',
|
||||
navId: 'users',
|
||||
component: SafeDynamicImport(
|
||||
() => import(/* webpackChunkName: "UsersListPage" */ 'app/features/users/UsersListPage')
|
||||
),
|
||||
@ -203,6 +206,7 @@ export function getAppRoutes(): RouteDescriptor[] {
|
||||
},
|
||||
{
|
||||
path: '/org/apikeys',
|
||||
navId: 'apikeys',
|
||||
roles: () => contextSrv.evaluatePermission(() => ['Admin'], [AccessControlAction.ActionAPIKeysRead]),
|
||||
component: SafeDynamicImport(
|
||||
() => import(/* webpackChunkName: "ApiKeysPage" */ 'app/features/api-keys/ApiKeysPage')
|
||||
@ -231,6 +235,7 @@ export function getAppRoutes(): RouteDescriptor[] {
|
||||
},
|
||||
{
|
||||
path: '/org/teams',
|
||||
navId: 'teams',
|
||||
roles: () =>
|
||||
contextSrv.evaluatePermission(
|
||||
() => (config.editorsCanAdmin ? ['Editor', 'Admin'] : ['Admin']),
|
||||
@ -316,6 +321,7 @@ export function getAppRoutes(): RouteDescriptor[] {
|
||||
path: '/login',
|
||||
component: LoginPage,
|
||||
pageClass: 'login-page sidemenu-hidden',
|
||||
navHidden: true,
|
||||
},
|
||||
{
|
||||
path: '/invite/:code',
|
||||
@ -323,6 +329,7 @@ export function getAppRoutes(): RouteDescriptor[] {
|
||||
() => import(/* webpackChunkName: "SignupInvited" */ 'app/features/invites/SignupInvited')
|
||||
),
|
||||
pageClass: 'sidemenu-hidden',
|
||||
navHidden: true,
|
||||
},
|
||||
{
|
||||
path: '/verify',
|
||||
@ -332,6 +339,7 @@ export function getAppRoutes(): RouteDescriptor[] {
|
||||
() => import(/* webpackChunkName "VerifyEmailPage"*/ 'app/core/components/Signup/VerifyEmailPage')
|
||||
),
|
||||
pageClass: 'login-page sidemenu-hidden',
|
||||
navHidden: true,
|
||||
},
|
||||
{
|
||||
path: '/signup',
|
||||
@ -339,10 +347,12 @@ export function getAppRoutes(): RouteDescriptor[] {
|
||||
? () => <Redirect to="/login" />
|
||||
: SafeDynamicImport(() => import(/* webpackChunkName "SignupPage"*/ 'app/core/components/Signup/SignupPage')),
|
||||
pageClass: 'sidemenu-hidden login-page',
|
||||
navHidden: true,
|
||||
},
|
||||
{
|
||||
path: '/user/password/send-reset-email',
|
||||
pageClass: 'sidemenu-hidden',
|
||||
navHidden: true,
|
||||
component: SafeDynamicImport(
|
||||
() =>
|
||||
import(/* webpackChunkName: "SendResetMailPage" */ 'app/core/components/ForgottenPassword/SendResetMailPage')
|
||||
@ -357,6 +367,7 @@ export function getAppRoutes(): RouteDescriptor[] {
|
||||
)
|
||||
),
|
||||
pageClass: 'sidemenu-hidden login-page',
|
||||
navHidden: true,
|
||||
},
|
||||
{
|
||||
path: '/dashboard/snapshots',
|
||||
|
Loading…
Reference in New Issue
Block a user