mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
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:
parent
ecdd4a184f
commit
7947629f82
@ -55,6 +55,7 @@ export function createTheme(options: NewThemeOptions = {}): GrafanaTheme2 {
|
||||
zIndex: {
|
||||
...zIndex,
|
||||
},
|
||||
flags: {},
|
||||
};
|
||||
|
||||
return {
|
||||
|
@ -30,6 +30,8 @@ export interface GrafanaTheme2 {
|
||||
visualization: ThemeVisualizationColors;
|
||||
transitions: ThemeTransitions;
|
||||
v1: GrafanaTheme;
|
||||
/** feature flags that might impact component looks */
|
||||
flags: { topnav?: boolean };
|
||||
}
|
||||
|
||||
/** @alpha */
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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};
|
||||
|
@ -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 } }}
|
||||
|
@ -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);
|
||||
},
|
||||
]);
|
||||
}
|
||||
|
@ -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',
|
||||
},
|
||||
|
@ -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),
|
||||
}),
|
||||
};
|
||||
};
|
||||
|
38
public/app/core/components/AppChrome/NavToolbarSeparator.tsx
Normal file
38
public/app/core/components/AppChrome/NavToolbarSeparator.tsx
Normal 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,
|
||||
}),
|
||||
};
|
||||
};
|
@ -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);
|
||||
}
|
||||
|
@ -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>
|
||||
));
|
||||
};
|
||||
|
@ -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>
|
||||
);
|
||||
});
|
||||
|
@ -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;
|
||||
|
Loading…
Reference in New Issue
Block a user