mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
PanelChrome: Implement hover header (#61774)
Closes #59078 Co-authored-by: polinaboneva <polina.boneva@grafana.com> Co-authored-by: Ivan Ortega <ivanortegaalba@gmail.com> Co-authored-by: Alexandra Vargas <alexa1866@gmail.com>
This commit is contained in:
@@ -1,3 +1,4 @@
|
||||
import classnames from 'classnames';
|
||||
import React, { PureComponent } from 'react';
|
||||
|
||||
import { PanelMenuItem } from '@grafana/data';
|
||||
@@ -7,13 +8,15 @@ import { PanelHeaderMenuItem } from './PanelHeaderMenuItem';
|
||||
export interface Props {
|
||||
items: PanelMenuItem[];
|
||||
style?: React.CSSProperties;
|
||||
itemsClassName?: string;
|
||||
className?: string;
|
||||
}
|
||||
|
||||
export class PanelHeaderMenu extends PureComponent<Props> {
|
||||
renderItems = (menu: PanelMenuItem[], isSubMenu = false) => {
|
||||
return (
|
||||
<ul
|
||||
className="dropdown-menu dropdown-menu--menu panel-menu"
|
||||
className={classnames('dropdown-menu', 'dropdown-menu--menu', 'panel-menu', this.props.itemsClassName)}
|
||||
style={this.props.style}
|
||||
role={isSubMenu ? '' : 'menu'}
|
||||
>
|
||||
@@ -36,6 +39,10 @@ export class PanelHeaderMenu extends PureComponent<Props> {
|
||||
};
|
||||
|
||||
render() {
|
||||
return <div className="panel-menu-container dropdown open">{this.renderItems(this.props.items)}</div>;
|
||||
return (
|
||||
<div className={classnames('panel-menu-container', 'dropdown', 'open', this.props.className)}>
|
||||
{this.renderItems(this.props.items)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,14 +13,28 @@ interface Props {
|
||||
loadingState?: LoadingState;
|
||||
onClose: () => void;
|
||||
style?: React.CSSProperties;
|
||||
menuItemsClassName?: string;
|
||||
menuWrapperClassName?: string;
|
||||
}
|
||||
|
||||
export function PanelHeaderMenuWrapper({ style, panel, dashboard, loadingState }: Props) {
|
||||
export function PanelHeaderMenuWrapper({
|
||||
style,
|
||||
panel,
|
||||
dashboard,
|
||||
loadingState,
|
||||
menuItemsClassName,
|
||||
menuWrapperClassName,
|
||||
}: Props) {
|
||||
return (
|
||||
<PanelHeaderMenuProvider panel={panel} dashboard={dashboard} loadingState={loadingState}>
|
||||
{({ items }) => {
|
||||
return <PanelHeaderMenu style={style} items={items} />;
|
||||
}}
|
||||
{({ items }) => (
|
||||
<PanelHeaderMenu
|
||||
className={menuWrapperClassName}
|
||||
itemsClassName={menuItemsClassName}
|
||||
style={style}
|
||||
items={items}
|
||||
/>
|
||||
)}
|
||||
</PanelHeaderMenuProvider>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -47,6 +47,8 @@ export function PanelLinks({ panelLinks, onShowPanelLinks }: Props) {
|
||||
const getStyles = (theme: GrafanaTheme2) => {
|
||||
return {
|
||||
menuTrigger: css({
|
||||
height: '100%',
|
||||
background: 'inherit',
|
||||
border: 'none',
|
||||
borderRadius: `${theme.shape.borderRadius()}`,
|
||||
cursor: 'context-menu',
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { css } from '@emotion/css';
|
||||
import classNames from 'classnames';
|
||||
import React, { PureComponent } from 'react';
|
||||
import { Subscription } from 'rxjs';
|
||||
@@ -636,9 +637,12 @@ export class PanelStateWrapper extends PureComponent<Props, State> {
|
||||
const title = panel.getDisplayTitle();
|
||||
const padding: PanelPadding = plugin.noPadding ? 'none' : 'md';
|
||||
|
||||
const dragClass = !(isViewing || isEditing) ? 'grid-drag-handle' : '';
|
||||
|
||||
const titleItems = [
|
||||
const showTitleItems =
|
||||
(panel.links && panel.links.length > 0 && this.onShowPanelLinks) ||
|
||||
(data.series.length > 0 && data.series.some((v) => (v.meta?.notices?.length ?? 0) > 0)) ||
|
||||
(data.request && data.request.timeInfo) ||
|
||||
alertState;
|
||||
const titleItems = showTitleItems && (
|
||||
<PanelHeaderTitleItems
|
||||
key="title-items"
|
||||
alertState={alertState}
|
||||
@@ -646,25 +650,60 @@ export class PanelStateWrapper extends PureComponent<Props, State> {
|
||||
panelId={panel.id}
|
||||
panelLinks={panel.links}
|
||||
onShowPanelLinks={this.onShowPanelLinks}
|
||||
/>,
|
||||
];
|
||||
/>
|
||||
);
|
||||
|
||||
const overrideStyles: { menuItemsClassName?: string; menuWrapperClassName?: string; pos?: React.CSSProperties } = {
|
||||
menuItemsClassName: undefined,
|
||||
menuWrapperClassName: undefined,
|
||||
pos: { top: 0, left: '-156px' },
|
||||
};
|
||||
|
||||
if (config.featureToggles.newPanelChromeUI) {
|
||||
// set override styles
|
||||
overrideStyles.menuItemsClassName = css`
|
||||
width: inherit;
|
||||
top: inherit;
|
||||
left: inherit;
|
||||
position: inherit;
|
||||
float: inherit;
|
||||
`;
|
||||
overrideStyles.menuWrapperClassName = css`
|
||||
position: inherit;
|
||||
width: inherit;
|
||||
top: inherit;
|
||||
left: inherit;
|
||||
float: inherit;
|
||||
.dropdown-submenu > .dropdown-menu {
|
||||
position: absolute;
|
||||
}
|
||||
`;
|
||||
overrideStyles.pos = undefined;
|
||||
}
|
||||
|
||||
// custom styles is neeeded to override legacy panel-menu styles and prevent menu from being cut off
|
||||
let menu;
|
||||
if (!dashboard.meta.publicDashboardAccessToken) {
|
||||
menu = (
|
||||
<div data-testid="panel-dropdown">
|
||||
<PanelHeaderMenuWrapper
|
||||
style={{ top: 0 }}
|
||||
style={overrideStyles.pos}
|
||||
panel={panel}
|
||||
dashboard={dashboard}
|
||||
loadingState={data.state}
|
||||
onClose={() => {}}
|
||||
menuItemsClassName={overrideStyles.menuItemsClassName}
|
||||
menuWrapperClassName={overrideStyles.menuWrapperClassName}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
const dragClass = !(isViewing || isEditing) ? 'grid-drag-handle' : '';
|
||||
if (config.featureToggles.newPanelChromeUI) {
|
||||
// Shift the hover menu down if it's on the top row so it doesn't get clipped by topnav
|
||||
const hoverHeaderOffset = (panel.gridPos?.y ?? 0) === 0 ? -16 : undefined;
|
||||
|
||||
return (
|
||||
<PanelChrome
|
||||
width={width}
|
||||
@@ -679,6 +718,8 @@ export class PanelStateWrapper extends PureComponent<Props, State> {
|
||||
dragClass={dragClass}
|
||||
dragClassCancel="grid-drag-cancel"
|
||||
padding={padding}
|
||||
hoverHeaderOffset={hoverHeaderOffset}
|
||||
hoverHeader={title ? false : true}
|
||||
displayMode={transparent ? 'transparent' : 'default'}
|
||||
>
|
||||
{(innerWidth, innerHeight) => (
|
||||
|
||||
@@ -339,6 +339,9 @@ export class PanelModel implements DataConfigSource, IPanelModel {
|
||||
if (manuallyUpdated) {
|
||||
this.configRev++;
|
||||
}
|
||||
|
||||
// Maybe a bit heavy. Could add a "GridPosChanged" event instead?
|
||||
this.render();
|
||||
}
|
||||
|
||||
runAllPanelQueries({
|
||||
|
||||
Reference in New Issue
Block a user