SingleTopNav: Handle for non-scenes dashboards (#94198)

handle singleTopNav for non-scenes dashboards
This commit is contained in:
Ashley Harrison
2024-10-04 15:11:32 +01:00
committed by GitHub
parent f32fe9a846
commit 40ad52fdbc
12 changed files with 68 additions and 36 deletions
@@ -16,7 +16,6 @@ import {
Badge,
} from '@grafana/ui';
import { updateNavIndex } from 'app/core/actions';
import { AppChromeUpdate } from 'app/core/components/AppChrome/AppChromeUpdate';
import { NavToolbarSeparator } from 'app/core/components/AppChrome/NavToolbar/NavToolbarSeparator';
import config from 'app/core/config';
import { useAppNotification } from 'app/core/copy/appNotification';
@@ -83,6 +82,7 @@ export const DashNav = memo<Props>((props) => {
// this ensures the component rerenders when the location changes
useLocation();
const forceUpdate = useForceUpdate();
const isSingleTopNav = config.featureToggles.singleTopNav;
// We don't really care about the event payload here only that it triggeres a re-render of this component
useBusEvent(props.dashboard.events, DashboardMetaChangedEvent);
@@ -357,15 +357,11 @@ export const DashNav = memo<Props>((props) => {
};
return (
<AppChromeUpdate
actions={
<>
{renderLeftActions()}
<NavToolbarSeparator leftActionsSeparator />
<ToolbarButtonRow alignment="right">{renderRightActions()}</ToolbarButtonRow>
</>
}
/>
<>
{renderLeftActions()}
{!isSingleTopNav && <NavToolbarSeparator leftActionsSeparator />}
<ToolbarButtonRow alignment="right">{renderRightActions()}</ToolbarButtonRow>
</>
);
});
@@ -5,12 +5,12 @@ import { AccessControlAction } from 'app/types';
import { SettingsPageProps } from '../DashboardSettings/types';
export const AccessControlDashboardPermissions = ({ dashboard, sectionNav }: SettingsPageProps) => {
export const AccessControlDashboardPermissions = ({ dashboard, sectionNav, toolbar }: SettingsPageProps) => {
const canSetPermissions = contextSrv.hasPermission(AccessControlAction.DashboardsPermissionsWrite);
const pageNav = sectionNav.node.parentItem;
return (
<Page navModel={sectionNav} pageNav={pageNav}>
<Page navModel={sectionNav} pageNav={pageNav} toolbar={toolbar}>
<Permissions resource={'dashboards'} resourceId={dashboard.uid} canSetPermissions={canSetPermissions} />
</Page>
);
@@ -7,7 +7,7 @@ import { AnnotationSettingsEdit, AnnotationSettingsList, newAnnotationName } fro
import { SettingsPageProps } from './types';
export function AnnotationsSettings({ dashboard, editIndex, sectionNav }: SettingsPageProps) {
export function AnnotationsSettings({ dashboard, editIndex, sectionNav, toolbar }: SettingsPageProps) {
const onNew = () => {
const newAnnotation: AnnotationQuery = {
name: newAnnotationName,
@@ -27,7 +27,7 @@ export function AnnotationsSettings({ dashboard, editIndex, sectionNav }: Settin
const isEditing = editIndex != null && editIndex < dashboard.annotations.list.length;
return (
<Page navModel={sectionNav} pageNav={getSubPageNav(dashboard, editIndex, sectionNav.node)}>
<Page toolbar={toolbar} navModel={sectionNav} pageNav={getSubPageNav(dashboard, editIndex, sectionNav.node)}>
{!isEditing && <AnnotationSettingsList dashboard={dashboard} onNew={onNew} onEdit={onEdit} />}
{isEditing && <AnnotationSettingsEdit dashboard={dashboard} editIdx={editIndex!} />}
</Page>
@@ -4,7 +4,7 @@ import { useLocation } from 'react-router-dom-v5-compat';
import { locationUtil, NavModel, NavModelItem } from '@grafana/data';
import { selectors } from '@grafana/e2e-selectors';
import { locationService } from '@grafana/runtime';
import { config, locationService } from '@grafana/runtime';
import { Button, Stack, Text, ToolbarButtonRow } from '@grafana/ui';
import { AppChromeUpdate } from 'app/core/components/AppChrome/AppChromeUpdate';
import { Page } from 'app/core/components/Page/Page';
@@ -36,6 +36,7 @@ const onClose = () => locationService.partial({ editview: null, editIndex: null
export function DashboardSettings({ dashboard, editview, pageNav, sectionNav }: Props) {
const [updateId, setUpdateId] = useState(0);
const isSingleTopNav = config.featureToggles.singleTopNav;
useEffect(() => {
dashboard.events.subscribe(DashboardMetaChangedEvent, () => setUpdateId((v) => v + 1));
}, [dashboard]);
@@ -81,8 +82,15 @@ export function DashboardSettings({ dashboard, editview, pageNav, sectionNav }:
return (
<>
<AppChromeUpdate actions={<ToolbarButtonRow alignment="right">{actions}</ToolbarButtonRow>} />
<currentPage.component sectionNav={subSectionNav} dashboard={dashboard} editIndex={editIndex} />
{!isSingleTopNav && (
<AppChromeUpdate actions={<ToolbarButtonRow alignment="right">{actions}</ToolbarButtonRow>} />
)}
<currentPage.component
toolbar={isSingleTopNav ? <ToolbarButtonRow alignment="right">{actions}</ToolbarButtonRow> : undefined}
sectionNav={subSectionNav}
dashboard={dashboard}
editIndex={editIndex}
/>
</>
);
}
@@ -209,9 +217,9 @@ function getSectionNav(
};
}
function MakeEditable({ dashboard, sectionNav }: SettingsPageProps) {
function MakeEditable({ dashboard, sectionNav, toolbar }: SettingsPageProps) {
return (
<Page navModel={sectionNav}>
<Page navModel={sectionNav} toolbar={toolbar}>
<Stack direction="column" gap={2} alignItems="flex-start">
<Text variant="h3">Dashboard not editable</Text>
<Button type="submit" onClick={() => dashboard.makeEditable()}>
@@ -39,6 +39,7 @@ export function GeneralSettingsUnconnected({
updateTimeZone,
updateWeekStart,
sectionNav,
toolbar,
}: Props): JSX.Element {
const [renderCounter, setRenderCounter] = useState(0);
const [dashboardTitle, setDashboardTitle] = useState(dashboard.title);
@@ -119,7 +120,7 @@ export function GeneralSettingsUnconnected({
];
return (
<Page navModel={sectionNav} pageNav={pageNav}>
<Page navModel={sectionNav} pageNav={pageNav} toolbar={toolbar}>
<div style={{ maxWidth: '600px' }}>
<Box marginBottom={5}>
<Field
@@ -11,7 +11,7 @@ import { getDashboardSrv } from '../../services/DashboardSrv';
import { SettingsPageProps } from './types';
export function JsonEditorSettings({ dashboard, sectionNav }: SettingsPageProps) {
export function JsonEditorSettings({ dashboard, sectionNav, toolbar }: SettingsPageProps) {
const dashboardSaveModel = dashboard.getSaveModelClone();
const [dashboardJson, setDashboardJson] = useState<string>(JSON.stringify(dashboardSaveModel, null, 2));
const pageNav = sectionNav.node.parentItem;
@@ -24,7 +24,7 @@ export function JsonEditorSettings({ dashboard, sectionNav }: SettingsPageProps)
const styles = useStyles2(getStyles);
return (
<Page navModel={sectionNav} pageNav={pageNav}>
<Page navModel={sectionNav} pageNav={pageNav} toolbar={toolbar}>
<div className={styles.wrapper}>
<Trans i18nKey="dashboard-settings.json-editor.subtitle">
The JSON model below is the data structure that defines the dashboard. This includes dashboard settings, panel
@@ -10,7 +10,7 @@ import { SettingsPageProps } from './types';
export type LinkSettingsMode = 'list' | 'new' | 'edit';
export function LinksSettings({ dashboard, sectionNav, editIndex }: SettingsPageProps) {
export function LinksSettings({ dashboard, sectionNav, editIndex, toolbar }: SettingsPageProps) {
const [isNew, setIsNew] = useState<boolean>(false);
const onGoBack = () => {
@@ -44,7 +44,7 @@ export function LinksSettings({ dashboard, sectionNav, editIndex }: SettingsPage
}
return (
<Page navModel={sectionNav} pageNav={pageNav}>
<Page navModel={sectionNav} pageNav={pageNav} toolbar={toolbar}>
{!isEditing && <LinkSettingsList dashboard={dashboard} onNew={onNew} onEdit={onEdit} />}
{isEditing && <LinkSettingsEdit dashboard={dashboard} editLinkIdx={editIndex} onGoBack={onGoBack} />}
</Page>
@@ -143,7 +143,7 @@ export class VersionsSettings extends PureComponent<Props, State> {
if (viewMode === 'compare') {
return (
<Page navModel={this.props.sectionNav} pageNav={pageNav}>
<Page navModel={this.props.sectionNav} pageNav={pageNav} toolbar={this.props.toolbar}>
<VersionHistoryHeader
onClick={this.reset}
baseVersion={baseInfo?.version}
@@ -165,7 +165,7 @@ export class VersionsSettings extends PureComponent<Props, State> {
}
return (
<Page navModel={this.props.sectionNav} pageNav={pageNav}>
<Page navModel={this.props.sectionNav} pageNav={pageNav} toolbar={this.props.toolbar}>
{isLoading ? (
<VersionsHistorySpinner msg="Fetching history list&hellip;" />
) : (
@@ -1,4 +1,4 @@
import { ComponentType } from 'react';
import { ComponentType, ReactNode } from 'react';
import { NavModel } from '@grafana/data';
import { IconName } from '@grafana/ui';
@@ -17,4 +17,5 @@ export interface SettingsPageProps {
dashboard: DashboardModel;
sectionNav: NavModel;
editIndex?: number;
toolbar?: ReactNode;
}
@@ -6,7 +6,7 @@ import { Subscription } from 'rxjs';
import { FieldConfigSource, GrafanaTheme2, NavModel, NavModelItem, PageLayoutType } from '@grafana/data';
import { selectors } from '@grafana/e2e-selectors';
import { locationService } from '@grafana/runtime';
import { config, locationService } from '@grafana/runtime';
import {
Button,
HorizontalGroup,
@@ -432,6 +432,7 @@ export class PanelEditorUnconnected extends PureComponent<Props> {
render() {
const { initDone, uiState, theme, sectionNav, pageNav, className, updatePanelEditorUIState } = this.props;
const isSingleTopNav = config.featureToggles.singleTopNav;
const styles = getStyles(theme, this.props);
if (!initDone) {
@@ -445,10 +446,17 @@ export class PanelEditorUnconnected extends PureComponent<Props> {
data-testid={selectors.components.PanelEditor.General.content}
layout={PageLayoutType.Custom}
className={className}
toolbar={
isSingleTopNav ? (
<ToolbarButtonRow alignment="right">{this.renderEditorActions()}</ToolbarButtonRow>
) : undefined
}
>
<AppChromeUpdate
actions={<ToolbarButtonRow alignment="right">{this.renderEditorActions()}</ToolbarButtonRow>}
/>
{!isSingleTopNav && (
<AppChromeUpdate
actions={<ToolbarButtonRow alignment="right">{this.renderEditorActions()}</ToolbarButtonRow>}
/>
)}
<div className={styles.wrapper}>
<div className={styles.verticalSplitPanesWrapper}>
{!uiState.isPanelOptionsVisible ? (
@@ -7,6 +7,7 @@ import { selectors } from '@grafana/e2e-selectors';
import { config, locationService } from '@grafana/runtime';
import { Themeable2, withTheme2 } from '@grafana/ui';
import { notifyApp } from 'app/core/actions';
import { AppChromeUpdate } from 'app/core/components/AppChrome/AppChromeUpdate';
import { ScrollRefElement } from 'app/core/components/NativeScrollbar';
import { Page } from 'app/core/components/Page/Page';
import { EntityNotFound } from 'app/core/components/PageNotFound/EntityNotFound';
@@ -359,6 +360,7 @@ export class UnthemedDashboardPage extends PureComponent<Props, State> {
const { editPanel, viewPanel, pageNav, sectionNav } = this.state;
const kioskMode = getKioskMode(this.props.queryParams);
const styles = getStyles(theme);
const isSingleTopNav = config.featureToggles.singleTopNav;
if (!dashboard || !pageNav || !sectionNav) {
return <DashboardLoading initPhase={this.props.initPhase} />;
@@ -434,9 +436,8 @@ export class UnthemedDashboardPage extends PureComponent<Props, State> {
layout={PageLayoutType.Canvas}
className={pageClassName}
onSetScrollRef={this.setScrollRef}
>
{showToolbar && (
<header data-testid={selectors.pages.Dashboard.DashNav.navV2}>
toolbar={
isSingleTopNav ? (
<DashNav
dashboard={dashboard}
title={dashboard.title}
@@ -445,6 +446,23 @@ export class UnthemedDashboardPage extends PureComponent<Props, State> {
kioskMode={kioskMode}
hideTimePicker={dashboard.timepicker.hidden}
/>
) : undefined
}
>
{showToolbar && (
<header data-testid={selectors.pages.Dashboard.DashNav.navV2}>
<AppChromeUpdate
actions={
<DashNav
dashboard={dashboard}
title={dashboard.title}
folderTitle={dashboard.meta.folderTitle}
isFullscreen={!!viewPanel}
kioskMode={kioskMode}
hideTimePicker={dashboard.timepicker.hidden}
/>
}
/>
</header>
)}
<DashboardPrompt dashboard={dashboard} />
@@ -105,14 +105,14 @@ class VariableEditorContainerUnconnected extends PureComponent<Props, State> {
};
render() {
const { editIndex, variables, sectionNav } = this.props;
const { editIndex, variables, sectionNav, toolbar } = this.props;
const variableToEdit = editIndex != null ? variables[editIndex] : undefined;
const node = sectionNav.node;
const parentItem = node.parentItem;
const subPageNav = variableToEdit ? { text: variableToEdit.name, parentItem } : parentItem;
return (
<Page navModel={this.props.sectionNav} pageNav={subPageNav}>
<Page toolbar={toolbar} navModel={this.props.sectionNav} pageNav={subPageNav}>
{!variableToEdit && (
<VariableEditorList
variables={this.props.variables}