mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
AppChrome: Unify logic for chromeless pages that should not have NavBar, CommandPalette, Search etc (#62281)
* Keybindings: No global keybindings on chromeless pages * simplify condition * Refactoring * Align name and file * Move logic into AppChrome * minor fix * Update Page.tsx * Fixing test * Fixed tests * More fixes * Fixed more tests * Fixing final test * Fixed search in old nav
This commit is contained in:
@@ -5,9 +5,12 @@ import { GrafanaTheme2 } from '@grafana/data';
|
||||
import { config } from '@grafana/runtime';
|
||||
import { useStyles2 } from '@grafana/ui';
|
||||
import { useGrafana } from 'app/core/context/GrafanaContext';
|
||||
import { CommandPalette } from 'app/features/commandPalette/CommandPalette';
|
||||
import { SearchWrapper } from 'app/features/search';
|
||||
import { KioskMode } from 'app/types';
|
||||
|
||||
import { MegaMenu } from '../MegaMenu/MegaMenu';
|
||||
import { NavBar } from '../NavBar/NavBar';
|
||||
|
||||
import { NavToolbar } from './NavToolbar';
|
||||
import { TopSearchBar } from './TopSearchBar';
|
||||
@@ -19,9 +22,21 @@ export function AppChrome({ children }: Props) {
|
||||
const styles = useStyles2(getStyles);
|
||||
const { chrome } = useGrafana();
|
||||
const state = chrome.useState();
|
||||
const featureToggles = config.featureToggles;
|
||||
|
||||
if (!config.featureToggles.topnav) {
|
||||
return <main className="main-view">{children}</main>;
|
||||
return (
|
||||
<>
|
||||
{!state.chromeless && (
|
||||
<>
|
||||
<NavBar />
|
||||
<SearchWrapper />
|
||||
{featureToggles.commandPalette && <CommandPalette />}
|
||||
</>
|
||||
)}
|
||||
<main className="main-view">{children}</main>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
const searchBarHidden = state.searchBarHidden || state.kioskMode === KioskMode.TV;
|
||||
@@ -32,24 +47,33 @@ export function AppChrome({ children }: Props) {
|
||||
[styles.contentChromeless]: state.chromeless,
|
||||
});
|
||||
|
||||
// Chromeless routes are without topNav, mega menu, search & command palette
|
||||
if (state.chromeless) {
|
||||
return (
|
||||
<main className="main-view">
|
||||
<div className={contentClass}>{children}</div>
|
||||
</main>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<main className="main-view">
|
||||
{!state.chromeless && (
|
||||
<div className={cx(styles.topNav)}>
|
||||
{!searchBarHidden && <TopSearchBar />}
|
||||
<NavToolbar
|
||||
searchBarHidden={searchBarHidden}
|
||||
sectionNav={state.sectionNav}
|
||||
pageNav={state.pageNav}
|
||||
actions={state.actions}
|
||||
onToggleSearchBar={chrome.onToggleSearchBar}
|
||||
onToggleMegaMenu={chrome.onToggleMegaMenu}
|
||||
onToggleKioskMode={chrome.onToggleKioskMode}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
<div className={cx(styles.topNav)}>
|
||||
{!searchBarHidden && <TopSearchBar />}
|
||||
<NavToolbar
|
||||
searchBarHidden={searchBarHidden}
|
||||
sectionNav={state.sectionNav}
|
||||
pageNav={state.pageNav}
|
||||
actions={state.actions}
|
||||
onToggleSearchBar={chrome.onToggleSearchBar}
|
||||
onToggleMegaMenu={chrome.onToggleMegaMenu}
|
||||
onToggleKioskMode={chrome.onToggleKioskMode}
|
||||
/>
|
||||
</div>
|
||||
<div className={contentClass}>{children}</div>
|
||||
{!state.chromeless && <MegaMenu searchBarHidden={searchBarHidden} onClose={() => chrome.setMegaMenu(false)} />}
|
||||
<MegaMenu searchBarHidden={searchBarHidden} onClose={() => chrome.setMegaMenu(false)} />
|
||||
{featureToggles.commandPalette && <CommandPalette />}
|
||||
{!featureToggles.topNavCommandPalette && <SearchWrapper />}
|
||||
</main>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
import { render, screen } from '@testing-library/react';
|
||||
import React from 'react';
|
||||
import { Provider } from 'react-redux';
|
||||
import { TestProvider } from 'test/helpers/TestProvider';
|
||||
|
||||
import { config } from '@grafana/runtime';
|
||||
import { configureStore } from 'app/store/configureStore';
|
||||
|
||||
import { NavLandingPage } from './NavLandingPage';
|
||||
|
||||
@@ -51,11 +50,10 @@ describe('NavLandingPage', () => {
|
||||
},
|
||||
];
|
||||
|
||||
const store = configureStore();
|
||||
return render(
|
||||
<Provider store={store}>
|
||||
<TestProvider>
|
||||
<NavLandingPage navId={mockId} />
|
||||
</Provider>
|
||||
</TestProvider>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
@@ -1,11 +1,10 @@
|
||||
import { render, screen } from '@testing-library/react';
|
||||
import React from 'react';
|
||||
import { Provider } from 'react-redux';
|
||||
import { TestProvider } from 'test/helpers/TestProvider';
|
||||
|
||||
import { OrgRole } from '@grafana/data';
|
||||
import { ContextSrv, setContextSrv } from 'app/core/services/context_srv';
|
||||
import { getUserOrganizations } from 'app/features/org/state/actions';
|
||||
import { configureStore } from 'app/store/configureStore';
|
||||
import * as appTypes from 'app/types';
|
||||
|
||||
import { OrganizationSwitcher } from './OrganizationSwitcher';
|
||||
@@ -22,12 +21,10 @@ jest.mock('app/types', () => ({
|
||||
}));
|
||||
|
||||
const renderWithProvider = ({ initialState }: { initialState?: Partial<appTypes.StoreState> }) => {
|
||||
const store = configureStore(initialState);
|
||||
|
||||
render(
|
||||
<Provider store={store}>
|
||||
<TestProvider storeState={initialState}>
|
||||
<OrganizationSwitcher />
|
||||
</Provider>
|
||||
</TestProvider>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
@@ -1,11 +1,10 @@
|
||||
import { render, screen } from '@testing-library/react';
|
||||
import userEvent from '@testing-library/user-event';
|
||||
import React from 'react';
|
||||
import { Provider } from 'react-redux';
|
||||
import { TestProvider } from 'test/helpers/TestProvider';
|
||||
|
||||
import { NavModelItem, NavSection } from '@grafana/data';
|
||||
import { reportInteraction } from '@grafana/runtime';
|
||||
import { configureStore } from 'app/store/configureStore';
|
||||
|
||||
import { QuickAdd } from './QuickAdd';
|
||||
|
||||
@@ -37,12 +36,10 @@ const setup = () => {
|
||||
},
|
||||
];
|
||||
|
||||
const store = configureStore({ navBarTree });
|
||||
|
||||
return render(
|
||||
<Provider store={store}>
|
||||
<TestProvider storeState={{ navBarTree }}>
|
||||
<QuickAdd />
|
||||
</Provider>
|
||||
</TestProvider>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
@@ -1,15 +1,12 @@
|
||||
import { render, screen } from '@testing-library/react';
|
||||
import React from 'react';
|
||||
import { Provider } from 'react-redux';
|
||||
import { Router } from 'react-router-dom';
|
||||
import { getGrafanaContextMock } from 'test/mocks/getGrafanaContextMock';
|
||||
|
||||
import { NavModelItem, NavSection } from '@grafana/data';
|
||||
import { locationService } from '@grafana/runtime';
|
||||
import { GrafanaContext } from 'app/core/context/GrafanaContext';
|
||||
import { configureStore } from 'app/store/configureStore';
|
||||
|
||||
import TestProvider from '../../../../test/helpers/TestProvider';
|
||||
import { TestProvider } from '../../../../test/helpers/TestProvider';
|
||||
|
||||
import { MegaMenu } from './MegaMenu';
|
||||
|
||||
@@ -33,21 +30,15 @@ const setup = () => {
|
||||
},
|
||||
];
|
||||
|
||||
const context = getGrafanaContextMock();
|
||||
const store = configureStore({ navBarTree });
|
||||
|
||||
context.chrome.onToggleMegaMenu();
|
||||
const grafanaContext = getGrafanaContextMock();
|
||||
grafanaContext.chrome.onToggleMegaMenu();
|
||||
|
||||
return render(
|
||||
<Provider store={store}>
|
||||
<GrafanaContext.Provider value={context}>
|
||||
<TestProvider>
|
||||
<Router history={locationService.getHistory()}>
|
||||
<MegaMenu onClose={() => {}} />
|
||||
</Router>
|
||||
</TestProvider>
|
||||
</GrafanaContext.Provider>
|
||||
</Provider>
|
||||
<TestProvider storeState={{ navBarTree }} grafanaContext={grafanaContext}>
|
||||
<Router history={locationService.getHistory()}>
|
||||
<MegaMenu onClose={() => {}} />
|
||||
</Router>
|
||||
</TestProvider>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
@@ -1,12 +1,9 @@
|
||||
import { render, screen } from '@testing-library/react';
|
||||
import React from 'react';
|
||||
import { Provider } from 'react-redux';
|
||||
import { Router } from 'react-router-dom';
|
||||
|
||||
import { locationService } from '@grafana/runtime';
|
||||
import { configureStore } from 'app/store/configureStore';
|
||||
|
||||
import TestProvider from '../../../../test/helpers/TestProvider';
|
||||
import { TestProvider } from '../../../../test/helpers/TestProvider';
|
||||
|
||||
import { NavBar } from './NavBar';
|
||||
|
||||
@@ -22,16 +19,10 @@ jest.mock('app/core/services/context_srv', () => ({
|
||||
}));
|
||||
|
||||
const setup = () => {
|
||||
const store = configureStore();
|
||||
|
||||
return render(
|
||||
<Provider store={store}>
|
||||
<TestProvider>
|
||||
<Router history={locationService.getHistory()}>
|
||||
<NavBar />
|
||||
</Router>
|
||||
</TestProvider>
|
||||
</Provider>
|
||||
<TestProvider>
|
||||
<NavBar />
|
||||
</TestProvider>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
@@ -192,10 +192,6 @@ const getStyles = (theme: GrafanaTheme2) => ({
|
||||
navWrapper: css({
|
||||
position: 'relative',
|
||||
display: 'flex',
|
||||
|
||||
'.sidemenu-hidden &': {
|
||||
display: 'none',
|
||||
},
|
||||
}),
|
||||
sidemenu: css({
|
||||
label: 'sidemenu',
|
||||
|
||||
@@ -6,8 +6,6 @@ import { BrowserRouter } from 'react-router-dom';
|
||||
import { locationUtil } from '@grafana/data';
|
||||
import { config, setLocationService } from '@grafana/runtime';
|
||||
|
||||
import TestProvider from '../../../../test/helpers/TestProvider';
|
||||
|
||||
// Need to mock createBrowserHistory here to avoid errors
|
||||
jest.mock('history', () => ({
|
||||
...jest.requireActual('history'),
|
||||
@@ -45,18 +43,16 @@ async function getTestContext(overrides: Partial<Props> = {}, subUrl = '', isMen
|
||||
const props = { ...defaults, ...overrides };
|
||||
|
||||
const { rerender } = render(
|
||||
<TestProvider>
|
||||
<BrowserRouter>
|
||||
<NavBarContext.Provider
|
||||
value={{
|
||||
menuIdOpen: isMenuOpen ? props.link.id : undefined,
|
||||
setMenuIdOpen: setMenuIdOpenMock,
|
||||
}}
|
||||
>
|
||||
<NavBarItem {...props} />
|
||||
</NavBarContext.Provider>
|
||||
</BrowserRouter>
|
||||
</TestProvider>
|
||||
<BrowserRouter>
|
||||
<NavBarContext.Provider
|
||||
value={{
|
||||
menuIdOpen: isMenuOpen ? props.link.id : undefined,
|
||||
setMenuIdOpen: setMenuIdOpenMock,
|
||||
}}
|
||||
>
|
||||
<NavBarItem {...props} />
|
||||
</NavBarContext.Provider>
|
||||
</BrowserRouter>
|
||||
);
|
||||
|
||||
// Need to click this first to set the correct selection range
|
||||
|
||||
@@ -1,10 +1,9 @@
|
||||
import { render, screen } from '@testing-library/react';
|
||||
import React from 'react';
|
||||
import { Provider } from 'react-redux';
|
||||
import { TestProvider } from 'test/helpers/TestProvider';
|
||||
|
||||
import { NavModelItem } from '@grafana/data';
|
||||
import { config } from '@grafana/runtime';
|
||||
import { configureStore } from 'app/store/configureStore';
|
||||
|
||||
import { Page } from './Page';
|
||||
import { PageProps } from './types';
|
||||
@@ -30,14 +29,12 @@ const setup = (props: Partial<PageProps>) => {
|
||||
},
|
||||
];
|
||||
|
||||
const store = configureStore();
|
||||
|
||||
return render(
|
||||
<Provider store={store}>
|
||||
<TestProvider>
|
||||
<Page {...props}>
|
||||
<div data-testid="page-children">Children</div>
|
||||
</Page>
|
||||
</Provider>
|
||||
</TestProvider>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
// Libraries
|
||||
import { css, cx } from '@emotion/css';
|
||||
import React from 'react';
|
||||
import React, { useEffect } from 'react';
|
||||
|
||||
import { GrafanaTheme2, PageLayoutType } from '@grafana/data';
|
||||
import { config } from '@grafana/runtime';
|
||||
import { CustomScrollbar, useStyles2 } from '@grafana/ui';
|
||||
import { useGrafana } from 'app/core/context/GrafanaContext';
|
||||
|
||||
import { Footer } from '../Footer/Footer';
|
||||
import { PageHeader } from '../PageHeader/PageHeader';
|
||||
@@ -34,11 +35,21 @@ export const OldPage: PageType = ({
|
||||
}) => {
|
||||
const styles = useStyles2(getStyles);
|
||||
const navModel = usePageNav(navId, oldNavProp);
|
||||
const { chrome } = useGrafana();
|
||||
|
||||
usePageTitle(navModel, pageNav);
|
||||
|
||||
const pageHeaderNav = pageNav ?? navModel?.main;
|
||||
|
||||
useEffect(() => {
|
||||
if (navModel) {
|
||||
// This is needed for chrome to update it's chromeless state
|
||||
chrome.update({
|
||||
sectionNav: navModel.node,
|
||||
});
|
||||
}
|
||||
}, [navModel, chrome]);
|
||||
|
||||
return (
|
||||
<div className={cx(styles.wrapper, className)} {...otherProps}>
|
||||
{layout === PageLayoutType.Standard && (
|
||||
|
||||
@@ -1,13 +1,11 @@
|
||||
import { render, screen } from '@testing-library/react';
|
||||
import React from 'react';
|
||||
import { Provider } from 'react-redux';
|
||||
import { TestProvider } from 'test/helpers/TestProvider';
|
||||
import { getGrafanaContextMock } from 'test/mocks/getGrafanaContextMock';
|
||||
|
||||
import { NavModelItem } from '@grafana/data';
|
||||
import { config } from '@grafana/runtime';
|
||||
import { GrafanaContext } from 'app/core/context/GrafanaContext';
|
||||
import { HOME_NAV_ID } from 'app/core/reducers/navModel';
|
||||
import { configureStore } from 'app/store/configureStore';
|
||||
|
||||
import { PageProps } from '../Page/types';
|
||||
|
||||
@@ -38,16 +36,13 @@ const setup = (props: Partial<PageProps>) => {
|
||||
];
|
||||
|
||||
const context = getGrafanaContextMock();
|
||||
const store = configureStore();
|
||||
|
||||
const renderResult = render(
|
||||
<Provider store={store}>
|
||||
<GrafanaContext.Provider value={context}>
|
||||
<Page {...props}>
|
||||
<div data-testid="page-children">Children</div>
|
||||
</Page>
|
||||
</GrafanaContext.Provider>
|
||||
</Provider>
|
||||
<TestProvider grafanaContext={context}>
|
||||
<Page {...props}>
|
||||
<div data-testid="page-children">Children</div>
|
||||
</Page>
|
||||
</TestProvider>
|
||||
);
|
||||
|
||||
return { renderResult, context };
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import { render, screen, waitFor } from '@testing-library/react';
|
||||
import userEvent from '@testing-library/user-event';
|
||||
import React from 'react';
|
||||
import TestProvider from 'test/helpers/TestProvider';
|
||||
import { assertInstanceOf } from 'test/helpers/asserts';
|
||||
import { getSelectParent, selectOptionInTest } from 'test/helpers/selectOptionInTest';
|
||||
|
||||
@@ -124,11 +123,7 @@ describe('SharedPreferences', () => {
|
||||
mockReload.mockReset();
|
||||
mockPrefsUpdate.mockReset();
|
||||
|
||||
render(
|
||||
<TestProvider>
|
||||
<SharedPreferences {...props} />
|
||||
</TestProvider>
|
||||
);
|
||||
render(<SharedPreferences {...props} />);
|
||||
|
||||
await waitFor(() => expect(mockPrefsLoad).toHaveBeenCalled());
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user