Chore: Remove topnav references (#5092)

# What this PR does

- removes references to `topnav`
  - `topnav` was default enabled in grafana v9.5
  - we intend to remove the toggle soon™️ 

## Which issue(s) this PR closes

Related to [issue link here]

<!--
*Note*: If you want the issue to be auto-closed once the PR is merged,
change "Related to" to "Closes" in the line above.
If you have more than one GitHub issue that this PR closes, be sure to
preface
each issue link with a [closing
keyword](https://docs.github.com/en/get-started/writing-on-github/working-with-advanced-formatting/using-keywords-in-issues-and-pull-requests#linking-a-pull-request-to-an-issue).
This ensures that the issue(s) are auto-closed once the PR has been
merged.
-->

## Checklist

- [ ] Unit, integration, and e2e (if applicable) tests updated
- [x] Documentation added (or `pr:no public docs` PR label added if not
required)
- [x] Added the relevant release notes label (see labels prefixed w/
`release:`). These labels dictate how your PR will
    show up in the autogenerated release notes.
This commit is contained in:
Ashley Harrison 2024-09-30 17:22:04 +01:00 committed by GitHub
parent 28526182a5
commit 671a537dbc
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
14 changed files with 64 additions and 159 deletions

View file

@ -70,7 +70,7 @@ grafana:
- name: DATABASE_PASSWORD - name: DATABASE_PASSWORD
value: oncallpassword value: oncallpassword
env: env:
GF_FEATURE_TOGGLES_ENABLE: topnav,externalServiceAccounts GF_FEATURE_TOGGLES_ENABLE: externalServiceAccounts
GF_SECURITY_ADMIN_PASSWORD: oncall GF_SECURITY_ADMIN_PASSWORD: oncall
GF_SECURITY_ADMIN_USER: oncall GF_SECURITY_ADMIN_USER: oncall
GF_PLUGINS_ALLOW_LOADING_UNSIGNED_PLUGINS: grafana-oncall-app GF_PLUGINS_ALLOW_LOADING_UNSIGNED_PLUGINS: grafana-oncall-app

View file

@ -11,9 +11,7 @@ import { TextEncoder, TextDecoder } from 'util';
jest.mock('@grafana/runtime', () => ({ jest.mock('@grafana/runtime', () => ({
__esModule: true, __esModule: true,
config: { config: {
featureToggles: { featureToggles: {},
topNav: false,
},
bootData: { bootData: {
user: { user: {
timezone: 'UTC', timezone: 'UTC',

View file

@ -6,13 +6,12 @@ import { Header } from 'navbar/Header/Header';
import { RenderConditionally } from 'components/RenderConditionally/RenderConditionally'; import { RenderConditionally } from 'components/RenderConditionally/RenderConditionally';
import { pages } from 'pages/pages'; import { pages } from 'pages/pages';
import { isTopNavbar } from 'plugin/GrafanaPluginRootPage.helpers';
interface AppPluginPageProps extends PluginPageProps { interface AppPluginPageProps extends PluginPageProps {
page?: string; page?: string;
} }
export const PluginPage = (isTopNavbar() ? RealPlugin : PluginPageFallback) as React.ComponentType<AppPluginPageProps>; export const PluginPage = RealPlugin as React.ComponentType<AppPluginPageProps>;
function RealPlugin(props: AppPluginPageProps): React.ReactNode { function RealPlugin(props: AppPluginPageProps): React.ReactNode {
const { page } = props; const { page } = props;
@ -33,7 +32,3 @@ function RealPlugin(props: AppPluginPageProps): React.ReactNode {
</RealPluginPage> </RealPluginPage>
); );
} }
export function PluginPageFallback(props: PluginPageProps): React.ReactNode {
return props.children;
}

View file

@ -15,7 +15,6 @@ import { getSlackMessage } from 'containers/DefaultPageLayout/DefaultPageLayout.
import { SlackError } from 'containers/DefaultPageLayout/DefaultPageLayout.types'; import { SlackError } from 'containers/DefaultPageLayout/DefaultPageLayout.types';
import { getIfChatOpsConnected } from 'containers/DefaultPageLayout/helper'; import { getIfChatOpsConnected } from 'containers/DefaultPageLayout/helper';
import { UserHelper } from 'models/user/user.helpers'; import { UserHelper } from 'models/user/user.helpers';
import { isTopNavbar } from 'plugin/GrafanaPluginRootPage.helpers';
import { AppFeature } from 'state/features'; import { AppFeature } from 'state/features';
import { useStore } from 'state/useStore'; import { useStore } from 'state/useStore';
@ -72,7 +71,7 @@ export const Alerts = observer(() => {
return null; return null;
} }
return ( return (
<div className={cx(styles.alertsContainer, { [styles.alertsContainerLegacy]: !isTopNavbar() })}> <div className={styles.alertsContainer}>
{showSlackInstallAlert && ( {showSlackInstallAlert && (
<Alert <Alert
className={styles.alert} className={styles.alert}
@ -192,13 +191,5 @@ const getStyles = (theme: GrafanaTheme2) => {
instructionsLink: css` instructionsLink: css`
color: ${theme.colors.primary.text}; color: ${theme.colors.primary.text};
`, `,
alertsContainerLegacy: css`
paddingtop: '10px';
@media (max-width: 768px) {
padding-top: 50px;
}
`,
}; };
}; };

View file

@ -1,13 +1,11 @@
import React, { FC, ReactElement } from 'react'; import React, { FC } from 'react';
import { css, cx } from '@emotion/css'; import { css } from '@emotion/css';
import { AppRootProps, NavModelItem } from '@grafana/data'; import { AppRootProps, NavModelItem } from '@grafana/data';
import { useStyles2 } from '@grafana/ui'; import { useStyles2 } from '@grafana/ui';
import { PluginPage } from 'PluginPage'; import { PluginPage } from 'PluginPage';
import { observer } from 'mobx-react'; import { observer } from 'mobx-react';
import { Alerts } from 'containers/Alerts/Alerts';
import { isTopNavbar } from 'plugin/GrafanaPluginRootPage.helpers';
interface DefaultPageLayoutProps extends AppRootProps { interface DefaultPageLayoutProps extends AppRootProps {
children?: any; children?: any;
@ -19,39 +17,11 @@ export const DefaultPageLayout: FC<DefaultPageLayoutProps> = observer((props) =>
const { children, page, pageNav } = props; const { children, page, pageNav } = props;
const styles = useStyles2(getStyles); const styles = useStyles2(getStyles);
if (isTopNavbar()) { return (
return renderTopNavbar(); <PluginPage page={page} pageNav={pageNav as any}>
} <div className={styles.root}>{children}</div>
</PluginPage>
return renderLegacyNavbar(); );
function renderTopNavbar(): ReactElement {
return (
<PluginPage page={page} pageNav={pageNav as any}>
<div className={styles.root}>{children}</div>
</PluginPage>
);
}
function renderLegacyNavbar(): ReactElement {
return (
<PluginPage page={page}>
<div
className={cx(
'page-container',
css`
height: 100%;
`
)}
>
<div className={cx(styles.root)}>
<Alerts />
{children}
</div>
</div>
</PluginPage>
);
}
}); });
const getStyles = () => { const getStyles = () => {

View file

@ -9,10 +9,6 @@ import { rootStore } from 'state/rootStore';
import { MobileAppConnection } from './MobileAppConnection'; import { MobileAppConnection } from './MobileAppConnection';
jest.mock('plugin/GrafanaPluginRootPage.helpers', () => ({
isTopNavbar: () => false,
}));
jest.mock('helpers/authorization/authorization', () => ({ jest.mock('helpers/authorization/authorization', () => ({
...jest.requireActual('helpers/authorization/authorization'), ...jest.requireActual('helpers/authorization/authorization'),
isUserActionAllowed: jest.fn().mockReturnValue(true), isUserActionAllowed: jest.fn().mockReturnValue(true),

View file

@ -1,9 +1,7 @@
import { Dayjs, ManipulateType } from 'dayjs'; import { Dayjs, ManipulateType } from 'dayjs';
import { GRAFANA_HEADER_HEIGHT, GRAFANA_LEGACY_SIDEBAR_WIDTH } from 'helpers/consts'; import { GRAFANA_HEADER_HEIGHT } from 'helpers/consts';
import { DraggableData } from 'react-draggable'; import { DraggableData } from 'react-draggable';
import { isTopNavbar } from 'plugin/GrafanaPluginRootPage.helpers';
import { RepeatEveryPeriod } from './RotationForm.types'; import { RepeatEveryPeriod } from './RotationForm.types';
export const getRepeatShiftsEveryOptions = (repeatEveryPeriod: number) => { export const getRepeatShiftsEveryOptions = (repeatEveryPeriod: number) => {
@ -195,20 +193,13 @@ export function getDraggableModalCoordinatesOnInit(
const baseReferenceElRect = body.getBoundingClientRect(); const baseReferenceElRect = body.getBoundingClientRect();
const { innerHeight } = window; const { innerHeight } = window;
const { right, bottom } = baseReferenceElRect; const { right } = baseReferenceElRect;
return isTopNavbar() return {
? { // values are adjusted by any padding/margin differences
// values are adjusted by any padding/margin differences left: -data.node.offsetLeft + 12,
left: -data.node.offsetLeft + 12, right: right - (data.node.offsetLeft + data.node.offsetWidth) - 12,
right: right - (data.node.offsetLeft + data.node.offsetWidth) - 12, top: -offsetTop + GRAFANA_HEADER_HEIGHT + 12,
top: -offsetTop + GRAFANA_HEADER_HEIGHT + 12, bottom: innerHeight - data.node.offsetHeight - offsetTop - 12,
bottom: innerHeight - data.node.offsetHeight - offsetTop - 12, };
}
: {
left: -data.node.offsetLeft + 12 + GRAFANA_LEGACY_SIDEBAR_WIDTH,
right: right - (data.node.offsetLeft + data.node.offsetWidth) - 12,
top: -offsetTop + 12,
bottom: bottom - data.node.offsetHeight - offsetTop - 12,
};
} }

View file

@ -8,7 +8,6 @@ import { observer } from 'mobx-react';
import gitHubStarSVG from 'assets/img/github_star.svg'; import gitHubStarSVG from 'assets/img/github_star.svg';
import logo from 'assets/img/logo.svg'; import logo from 'assets/img/logo.svg';
import { Alerts } from 'containers/Alerts/Alerts'; import { Alerts } from 'containers/Alerts/Alerts';
import { isTopNavbar } from 'plugin/GrafanaPluginRootPage.helpers';
import { getHeaderStyles } from './Header.styles'; import { getHeaderStyles } from './Header.styles';
@ -18,7 +17,7 @@ export const Header = observer(() => {
return ( return (
<> <>
<div> <div>
<div className={cx('page-header__inner', { [styles.headerTopNavbar]: isTopNavbar() })}> <div className={cx('page-header__inner', styles.headerTopNavbar)}>
<div className={styles.navbarLeft}> <div className={styles.navbarLeft}>
<span className={cx('page-header__logo', styles.logoContainer)}> <span className={cx('page-header__logo', styles.logoContainer)}>
<img className={styles.pageHeaderImage} src={logo} alt="Grafana OnCall" /> <img className={styles.pageHeaderImage} src={logo} alt="Grafana OnCall" />

View file

@ -1,11 +1,9 @@
import { isTopNavbar } from 'plugin/GrafanaPluginRootPage.helpers';
interface LegacyNavHeadingProps { interface LegacyNavHeadingProps {
children: JSX.Element; children: JSX.Element;
show?: boolean; show?: boolean;
} }
export const LegacyNavHeading = function (props: LegacyNavHeadingProps): JSX.Element { export const LegacyNavHeading = function (props: LegacyNavHeadingProps): JSX.Element {
const { show = !isTopNavbar(), children } = props; const { show = false, children } = props;
return show ? children : null; return show ? children : null;
}; };

View file

@ -3,7 +3,6 @@ import { UserActions, UserAction, isUserActionAllowed } from 'helpers/authorizat
import { PLUGIN_ROOT } from 'helpers/consts'; import { PLUGIN_ROOT } from 'helpers/consts';
import { matchPath } from 'react-router-dom-v5-compat'; import { matchPath } from 'react-router-dom-v5-compat';
import { isTopNavbar } from 'plugin/GrafanaPluginRootPage.helpers';
import { AppFeature } from 'state/features'; import { AppFeature } from 'state/features';
import { RootBaseStore } from 'state/rootBaseStore/RootBaseStore'; import { RootBaseStore } from 'state/rootBaseStore/RootBaseStore';
@ -109,7 +108,7 @@ export const pages: { [id: string]: PageDefinition } = [
text: 'ChatOps', text: 'ChatOps',
path: getPath('chat-ops'), path: getPath('chat-ops'),
hideFromBreadcrumbs: true, hideFromBreadcrumbs: true,
hideFromTabs: isTopNavbar(), hideFromTabs: true,
action: UserActions.ChatOpsRead, action: UserActions.ChatOpsRead,
}, },
{ {
@ -126,7 +125,7 @@ export const pages: { [id: string]: PageDefinition } = [
text: 'Env Variables', text: 'Env Variables',
hideFromTabsFn: (store: RootBaseStore) => { hideFromTabsFn: (store: RootBaseStore) => {
const hasLiveSettings = store.hasFeature(AppFeature.LiveSettings); const hasLiveSettings = store.hasFeature(AppFeature.LiveSettings);
return isTopNavbar() || !hasLiveSettings; return !hasLiveSettings;
}, },
path: getPath('live-settings'), path: getPath('live-settings'),
action: UserActions.OtherSettingsRead, action: UserActions.OtherSettingsRead,
@ -137,7 +136,7 @@ export const pages: { [id: string]: PageDefinition } = [
text: 'Cloud', text: 'Cloud',
hideFromTabsFn: (store: RootBaseStore) => { hideFromTabsFn: (store: RootBaseStore) => {
const hasCloudFeature = store.hasFeature(AppFeature.CloudConnection); const hasCloudFeature = store.hasFeature(AppFeature.CloudConnection);
return isTopNavbar() || !hasCloudFeature; return !hasCloudFeature;
}, },
path: getPath('cloud'), path: getPath('cloud'),
action: UserActions.OtherSettingsWrite, action: UserActions.OtherSettingsWrite,
@ -161,7 +160,7 @@ export const pages: { [id: string]: PageDefinition } = [
...current, ...current,
getPageNav: (pageTitle: string) => getPageNav: (pageTitle: string) =>
({ ({
text: isTopNavbar() ? '' : current.text, text: '',
parentItem: current.getParentItem ? current.getParentItem(pageTitle) : undefined, parentItem: current.getParentItem ? current.getParentItem(pageTitle) : undefined,
hideFromBreadcrumbs: current.hideFromBreadcrumbs, hideFromBreadcrumbs: current.hideFromBreadcrumbs,
hideFromTabs: current.hideFromTabs, hideFromTabs: current.hideFromTabs,

View file

@ -9,7 +9,6 @@ import { observer } from 'mobx-react';
import { ChatOpsPage } from 'pages/settings/tabs/ChatOps/ChatOps'; import { ChatOpsPage } from 'pages/settings/tabs/ChatOps/ChatOps';
import { MainSettings } from 'pages/settings/tabs/MainSettings/MainSettings'; import { MainSettings } from 'pages/settings/tabs/MainSettings/MainSettings';
import { isTopNavbar } from 'plugin/GrafanaPluginRootPage.helpers';
import { AppFeature } from 'state/features'; import { AppFeature } from 'state/features';
import { WithStoreProps } from 'state/types'; import { WithStoreProps } from 'state/types';
import { withMobXProviderContext } from 'state/withStore'; import { withMobXProviderContext } from 'state/withStore';
@ -54,52 +53,48 @@ class Settings extends React.Component<SettingsPageProps, SettingsPageState> {
const showCloudPage = hasCloudPage && isUserActionAllowed(UserActions.OtherSettingsWrite); const showCloudPage = hasCloudPage && isUserActionAllowed(UserActions.OtherSettingsWrite);
const showLiveSettings = hasLiveSettings && isUserActionAllowed(UserActions.OtherSettingsRead); const showLiveSettings = hasLiveSettings && isUserActionAllowed(UserActions.OtherSettingsRead);
if (isTopNavbar()) { return (
return ( <>
<> <TabsBar>
<TabsBar> <Tab
key={SettingsPageTab.MainSettings.key}
onChangeTab={() => onTabChange(SettingsPageTab.MainSettings.key)}
active={activeTab === SettingsPageTab.MainSettings.key}
label={SettingsPageTab.MainSettings.value}
/>
<Tab
key={SettingsPageTab.ChatOps.key}
onChangeTab={() => onTabChange(SettingsPageTab.ChatOps.key)}
active={activeTab === SettingsPageTab.ChatOps.key}
label={SettingsPageTab.ChatOps.value}
/>
<Tab
key={SettingsPageTab.TeamsSettings.key}
onChangeTab={() => onTabChange(SettingsPageTab.TeamsSettings.key)}
active={activeTab === SettingsPageTab.TeamsSettings.key}
label={SettingsPageTab.TeamsSettings.value}
/>
{showLiveSettings && (
<Tab <Tab
key={SettingsPageTab.MainSettings.key} key={SettingsPageTab.EnvVariables.key}
onChangeTab={() => onTabChange(SettingsPageTab.MainSettings.key)} onChangeTab={() => onTabChange(SettingsPageTab.EnvVariables.key)}
active={activeTab === SettingsPageTab.MainSettings.key} active={activeTab === SettingsPageTab.EnvVariables.key}
label={SettingsPageTab.MainSettings.value} label={SettingsPageTab.EnvVariables.value}
/> />
)}
{showCloudPage && (
<Tab <Tab
key={SettingsPageTab.ChatOps.key} key={SettingsPageTab.Cloud.key}
onChangeTab={() => onTabChange(SettingsPageTab.ChatOps.key)} onChangeTab={() => onTabChange(SettingsPageTab.Cloud.key)}
active={activeTab === SettingsPageTab.ChatOps.key} active={activeTab === SettingsPageTab.Cloud.key}
label={SettingsPageTab.ChatOps.value} label={SettingsPageTab.Cloud.value}
/> />
<Tab )}
key={SettingsPageTab.TeamsSettings.key} </TabsBar>
onChangeTab={() => onTabChange(SettingsPageTab.TeamsSettings.key)}
active={activeTab === SettingsPageTab.TeamsSettings.key}
label={SettingsPageTab.TeamsSettings.value}
/>
{showLiveSettings && (
<Tab
key={SettingsPageTab.EnvVariables.key}
onChangeTab={() => onTabChange(SettingsPageTab.EnvVariables.key)}
active={activeTab === SettingsPageTab.EnvVariables.key}
label={SettingsPageTab.EnvVariables.value}
/>
)}
{showCloudPage && (
<Tab
key={SettingsPageTab.Cloud.key}
onChangeTab={() => onTabChange(SettingsPageTab.Cloud.key)}
active={activeTab === SettingsPageTab.Cloud.key}
label={SettingsPageTab.Cloud.value}
/>
)}
</TabsBar>
<TabsContent activeTab={activeTab} /> <TabsContent activeTab={activeTab} />
</> </>
); );
}
return <MainSettings />;
} }
getMatchingPageNav() { getMatchingPageNav() {

View file

@ -9,8 +9,6 @@ import { LegacyNavHeading } from 'navbar/LegacyNavHeading';
import { Text } from 'components/Text/Text'; import { Text } from 'components/Text/Text';
import { ApiTokenSettings } from 'containers/ApiTokenSettings/ApiTokenSettings'; import { ApiTokenSettings } from 'containers/ApiTokenSettings/ApiTokenSettings';
import { WithPermissionControlTooltip } from 'containers/WithPermissionControl/WithPermissionControlTooltip'; import { WithPermissionControlTooltip } from 'containers/WithPermissionControl/WithPermissionControlTooltip';
import { TeamsSettings } from 'pages/settings/tabs/TeamsSettings/TeamsSettings';
import { isTopNavbar } from 'plugin/GrafanaPluginRootPage.helpers';
import { useStore } from 'state/useStore'; import { useStore } from 'state/useStore';
export const MainSettings = observer(() => { export const MainSettings = observer(() => {
@ -50,14 +48,6 @@ export const MainSettings = observer(() => {
</WithPermissionControlTooltip> </WithPermissionControlTooltip>
</Field> </Field>
</div> </div>
{!isTopNavbar() && (
<div style={{ marginBottom: '20px' }}>
<Text.Title level={3} className={styles.title}>
Teams and Access Settings
</Text.Title>
<TeamsSettings />
</div>
)}
<Text.Title level={3} className={styles.title}> <Text.Title level={3} className={styles.title}>
API URL API URL
</Text.Title> </Text.Title>

View file

@ -1,8 +1,3 @@
import { config } from '@grafana/runtime';
export function isTopNavbar(): boolean {
return !!config.featureToggles.topnav;
}
export function getQueryParams(): any { export function getQueryParams(): any {
const searchParams = new URLSearchParams(window.location.search); const searchParams = new URLSearchParams(window.location.search);

View file

@ -8,8 +8,6 @@ import { DEFAULT_PAGE, getOnCallApiUrl } from 'helpers/consts';
import { FaroHelper } from 'helpers/faro'; import { FaroHelper } from 'helpers/faro';
import { useOnMount } from 'helpers/hooks'; import { useOnMount } from 'helpers/hooks';
import { observer, Provider } from 'mobx-react'; import { observer, Provider } from 'mobx-react';
import { Header } from 'navbar/Header/Header';
import { LegacyNavTabsBar } from 'navbar/LegacyNavTabsBar';
import { Navigate, Route, Routes, useLocation } from 'react-router-dom-v5-compat'; import { Navigate, Route, Routes, useLocation } from 'react-router-dom-v5-compat';
import { RenderConditionally } from 'components/RenderConditionally/RenderConditionally'; import { RenderConditionally } from 'components/RenderConditionally/RenderConditionally';
@ -36,7 +34,7 @@ import { rootStore } from 'state/rootStore';
import { useStore } from 'state/useStore'; import { useStore } from 'state/useStore';
import 'assets/style/global.css'; import 'assets/style/global.css';
import { getQueryParams, isTopNavbar } from './GrafanaPluginRootPage.helpers'; import { getQueryParams } from './GrafanaPluginRootPage.helpers';
import grafanaGlobalStyle from '!raw-loader!assets/style/grafanaGlobalStyles.css'; import grafanaGlobalStyle from '!raw-loader!assets/style/grafanaGlobalStyles.css';
@ -112,22 +110,12 @@ export const Root = observer((props: AppRootProps) => {
return ( return (
<DefaultPageLayout {...props} page={page} pageNav={getPageNav()}> <DefaultPageLayout {...props} page={page} pageNav={getPageNav()}>
{!isTopNavbar() && (
<>
<Header />
<LegacyNavTabsBar currentPage={page} />
</>
)}
<div <div
className={cx( className={cx(
css` css`
position: relative; position: relative;
flex-grow: 1; flex-grow: 1;
`, `,
{
'u-overflow-x-auto': !isTopNavbar(),
'page-body': !isTopNavbar(),
}
)} )}
> >
<RenderConditionally <RenderConditionally