TopNav: Make dashboard toolbar actions work in new top nav (#51950)

* Initial work on new toolbar button

* Minor step

* Small progress

* Minor progress

* Minor fix

* removed console.log

* Removing stuff we don't need yet
This commit is contained in:
Torkel Ödegaard 2022-07-14 20:34:00 +02:00 committed by GitHub
parent ecdd4a184f
commit 7947629f82
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 106 additions and 44 deletions

View File

@ -55,6 +55,7 @@ export function createTheme(options: NewThemeOptions = {}): GrafanaTheme2 {
zIndex: {
...zIndex,
},
flags: {},
};
return {

View File

@ -30,6 +30,8 @@ export interface GrafanaTheme2 {
visualization: ThemeVisualizationColors;
transitions: ThemeTransitions;
v1: GrafanaTheme;
/** feature flags that might impact component looks */
flags: { topnav?: boolean };
}
/** @alpha */

View File

@ -169,6 +169,9 @@ export class GrafanaBootConfig implements GrafanaConfig {
}
overrideFeatureTogglesFromUrl(this);
// Special feature toggle that impact theme/component looks
this.theme2.flags.topnav = this.featureToggles.topnav;
}
}

View File

@ -127,6 +127,27 @@ const getStyles = (theme: GrafanaTheme2) => {
const primaryVariant = getPropertiesForVariant(theme, 'primary', 'solid');
const destructiveVariant = getPropertiesForVariant(theme, 'destructive', 'solid');
const defaultOld = css`
color: ${theme.colors.text.secondary};
background-color: ${theme.colors.background.primary};
&:hover {
color: ${theme.colors.text.primary};
background: ${theme.colors.background.secondary};
}
`;
const defaultTopNav = css`
color: ${theme.colors.text.secondary};
background-color: transparent;
border: none;
&:hover {
color: ${theme.colors.text.primary};
background: ${theme.colors.background.secondary};
}
`;
return {
button: css`
label: toolbar-button;
@ -172,15 +193,7 @@ const getStyles = (theme: GrafanaTheme2) => {
}
}
`,
default: css`
color: ${theme.colors.text.secondary};
background-color: ${theme.colors.background.primary};
&:hover {
color: ${theme.colors.text.primary};
background: ${theme.colors.background.secondary};
}
`,
default: theme.flags.topnav ? defaultTopNav : defaultOld,
active: css`
color: ${theme.v1.palette.orangeDark};
border-color: ${theme.v1.palette.orangeDark};

View File

@ -115,7 +115,7 @@ export class AppWrapper extends React.Component<AppWrapperProps, AppWrapperState
<I18nProvider>
<ErrorBoundaryAlert style="page">
<ConfigContext.Provider value={config}>
<ThemeProvider>
<ThemeProvider value={config.theme2}>
<KBarProvider
actions={[]}
options={{ enableHistory: true, callbacks: { onSelectAction: commandPaletteActionSelected } }}

View File

@ -1,3 +1,4 @@
import { config } from '@grafana/runtime';
import coreModule from 'app/angular/core_module';
import { provideTheme } from 'app/core/utils/ConfigProvider';
@ -5,7 +6,7 @@ export function react2AngularDirective(name: string, component: any, options: an
coreModule.directive(name, [
'reactDirective',
(reactDirective) => {
return reactDirective(provideTheme(component), options);
return reactDirective(provideTheme(component, config.theme2), options);
},
]);
}

View File

@ -60,6 +60,7 @@ const getStyles = (theme: GrafanaTheme2) => {
breadcrumbs: css({
display: 'flex',
alignItems: 'center',
flexWrap: 'nowrap',
fontWeight: theme.typography.fontWeightMedium,
}),
breadcrumb: css({
@ -72,6 +73,7 @@ const getStyles = (theme: GrafanaTheme2) => {
}),
breadcrumbLink: css({
color: theme.colors.text.primary,
whiteSpace: 'nowrap',
'&:hover': {
textDecoration: 'underline',
},

View File

@ -2,9 +2,10 @@ import { css } from '@emotion/css';
import React from 'react';
import { GrafanaTheme2, NavModelItem } from '@grafana/data';
import { IconButton, ToolbarButton, useStyles2 } from '@grafana/ui';
import { Icon, IconButton, ToolbarButton, useStyles2 } from '@grafana/ui';
import { Breadcrumbs } from './Breadcrumbs';
import { NavToolbarSeparator } from './NavToolbarSeparator';
import { TOP_BAR_LEVEL_HEIGHT } from './types';
export interface Props {
@ -32,10 +33,12 @@ export function NavToolbar({
<IconButton name="bars" tooltip="Toggle menu" tooltipPlacement="bottom" size="xl" onClick={onToggleMegaMenu} />
</div>
<Breadcrumbs sectionNav={sectionNav} pageNav={pageNav} />
<div className={styles.leftActions}></div>
<div className={styles.rightActions}>
<div className={styles.actions}>
{actions}
<ToolbarButton icon={searchBarHidden ? 'angle-down' : 'angle-up'} onClick={onToggleSearchBar} />
{actions && <NavToolbarSeparator />}
<ToolbarButton onClick={onToggleSearchBar} narrow tooltip="Toggle top search bar">
<Icon name={searchBarHidden ? 'angle-down' : 'angle-up'} size="xl" />
</ToolbarButton>
</div>
</div>
);
@ -55,16 +58,14 @@ const getStyles = (theme: GrafanaTheme2) => {
alignItems: 'center',
paddingRight: theme.spacing(1),
}),
leftActions: css({
actions: css({
display: 'flex',
alignItems: 'center',
flexWrap: 'nowrap',
justifyContent: 'flex-end',
paddingLeft: theme.spacing(1),
flexGrow: 1,
gap: theme.spacing(2),
}),
rightActions: css({
display: 'flex',
alignItems: 'center',
gap: theme.spacing(2),
gap: theme.spacing(0.5),
}),
};
};

View File

@ -0,0 +1,38 @@
import { css } from '@emotion/css';
import React from 'react';
import { GrafanaTheme2 } from '@grafana/data';
import { config } from '@grafana/runtime';
import { useStyles2 } from '@grafana/ui';
export interface Props {
leftActionsSeparator?: boolean;
}
export function NavToolbarSeparator({ leftActionsSeparator }: Props) {
const styles = useStyles2(getStyles);
if (leftActionsSeparator) {
return <div className={styles.leftActionsSeparator} />;
}
if (config.featureToggles.topnav) {
return <div className={styles.line} />;
}
return null;
}
const getStyles = (theme: GrafanaTheme2) => {
return {
leftActionsSeparator: css({
display: 'flex',
flexGrow: 1,
}),
line: css({
width: 1,
backgroundColor: theme.colors.border.medium,
height: 24,
}),
};
};

View File

@ -2,7 +2,7 @@ import React from 'react';
import ReactDOM from 'react-dom';
import { textUtil } from '@grafana/data';
import { CopyPanelEvent } from '@grafana/runtime';
import { config, CopyPanelEvent } from '@grafana/runtime';
import { ConfirmModal, ConfirmModalProps } from '@grafana/ui';
import appEvents from 'app/core/app_events';
import { copyPanel } from 'app/features/dashboard/utils/panel';
@ -32,7 +32,7 @@ export class ModalManager {
},
};
const elem = React.createElement(provideTheme(AngularModalProxy), modalProps);
const elem = React.createElement(provideTheme(AngularModalProxy, config.theme2), modalProps);
this.reactModalRoot.appendChild(this.reactModalNode);
ReactDOM.render(elem, this.reactModalNode);
}
@ -83,7 +83,7 @@ export class ModalManager {
props,
};
const elem = React.createElement(provideTheme(AngularModalProxy), modalProps);
const elem = React.createElement(provideTheme(AngularModalProxy, config.theme2), modalProps);
this.reactModalRoot.appendChild(this.reactModalNode);
ReactDOM.render(elem, this.reactModalNode);
}

View File

@ -1,6 +1,6 @@
import React, { useEffect, useState } from 'react';
import { createTheme } from '@grafana/data';
import { GrafanaTheme2 } from '@grafana/data';
import { config, GrafanaBootConfig, ThemeChangedEvent } from '@grafana/runtime';
import { ThemeContext } from '@grafana/ui';
@ -16,8 +16,8 @@ export const provideConfig = (component: React.ComponentType<any>) => {
return ConfigProvider;
};
export const ThemeProvider = ({ children }: { children: React.ReactNode }) => {
const [theme, setTheme] = useState(getCurrentUserTheme());
export const ThemeProvider = ({ children, value }: { children: React.ReactNode; value: GrafanaTheme2 }) => {
const [theme, setTheme] = useState(value);
useEffect(() => {
const sub = appEvents.subscribe(ThemeChangedEvent, (event) => {
@ -31,14 +31,8 @@ export const ThemeProvider = ({ children }: { children: React.ReactNode }) => {
return <ThemeContext.Provider value={theme}>{children}</ThemeContext.Provider>;
};
function getCurrentUserTheme() {
return createTheme({
colors: {
mode: config.bootData.user.lightTheme ? 'light' : 'dark',
},
});
}
export const provideTheme = (component: React.ComponentType<any>) => {
return provideConfig((props: any) => <ThemeProvider>{React.createElement(component, { ...props })}</ThemeProvider>);
export const provideTheme = (component: React.ComponentType<any>, theme: GrafanaTheme2) => {
return provideConfig((props: any) => (
<ThemeProvider value={theme}>{React.createElement(component, { ...props })}</ThemeProvider>
));
};

View File

@ -6,6 +6,7 @@ import { locationUtil, textUtil } from '@grafana/data';
import { locationService } from '@grafana/runtime';
import { ButtonGroup, ModalsController, ToolbarButton, PageToolbar, useForceUpdate } from '@grafana/ui';
import { AppChromeUpdate } from 'app/core/components/AppChrome/AppChromeUpdate';
import { NavToolbarSeparator } from 'app/core/components/AppChrome/NavToolbarSeparator';
import config from 'app/core/config';
import { toggleKioskMode } from 'app/core/navigation/kiosk';
import { DashboardCommentsModal } from 'app/features/dashboard/components/DashboardComments/DashboardCommentsModal';
@ -109,7 +110,7 @@ export const DashNav = React.memo<Props>((props) => {
return playlistSrv.isPlaying;
};
const renderLeftActionsButton = () => {
const renderLeftActions = () => {
const { dashboard, kioskMode } = props;
const { canStar, canShare, isStarred } = dashboard.meta;
const buttons: ReactNode[] = [];
@ -199,7 +200,7 @@ export const DashNav = React.memo<Props>((props) => {
);
};
const renderRightActionsButton = () => {
const renderRightActions = () => {
const { dashboard, onAddPanel, isFullscreen, kioskMode } = props;
const { canSave, canEdit, showSettings } = dashboard.meta;
const { snapshot } = dashboard;
@ -279,7 +280,13 @@ export const DashNav = React.memo<Props>((props) => {
return (
<AppChromeUpdate
pageNav={{ text: title }}
actions={<ToolbarButton onClick={onOpenSettings} icon="cog"></ToolbarButton>}
actions={
<>
{renderLeftActions()}
<NavToolbarSeparator leftActionsSeparator />
{renderRightActions()}
</>
}
/>
);
}
@ -292,9 +299,9 @@ export const DashNav = React.memo<Props>((props) => {
titleHref={titleHref}
parentHref={parentHref}
onGoBack={onGoBack}
leftItems={renderLeftActionsButton()}
leftItems={renderLeftActions()}
>
{renderRightActionsButton()}
{renderRightActions()}
</PageToolbar>
);
});

View File

@ -58,7 +58,7 @@ import { ThresholdManager } from './threshold_manager';
import { TimeRegionManager } from './time_region_manager';
import { isLegacyGraphHoverEvent } from './utils';
const LegendWithThemeProvider = provideTheme(Legend);
const LegendWithThemeProvider = provideTheme(Legend, config.theme2);
class GraphElement {
ctrl: GraphCtrl;