mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
PublicDashboards: HoverWidget in panel fix (#66685)
Hover widget modified for public dashboards.
This commit is contained in:
parent
a62cb96089
commit
47aa8c7654
@ -77,6 +77,10 @@ export const Components = {
|
||||
containerByTitle: (title: string) => `${title} panel`,
|
||||
headerCornerInfo: (mode: string) => `Panel header ${mode}`,
|
||||
loadingBar: () => `Panel loading bar`,
|
||||
HoverWidget: {
|
||||
container: 'data-test-id hover-header-container',
|
||||
dragIcon: 'data-testid drag-icon',
|
||||
},
|
||||
},
|
||||
Visualization: {
|
||||
Graph: {
|
||||
|
@ -2,6 +2,7 @@ import { css, cx } from '@emotion/css';
|
||||
import React, { ReactElement, useCallback, useRef, useState } from 'react';
|
||||
|
||||
import { GrafanaTheme2 } from '@grafana/data';
|
||||
import { selectors as e2eSelectors } from '@grafana/e2e-selectors/src';
|
||||
|
||||
import { useStyles2 } from '../../themes';
|
||||
import { Icon } from '../Icon/Icon';
|
||||
@ -16,6 +17,8 @@ interface Props {
|
||||
dragClass?: string;
|
||||
}
|
||||
|
||||
const selectors = e2eSelectors.components.Panels.Panel.HoverWidget;
|
||||
|
||||
export function HoverWidget({ menu, title, dragClass, children, offset = -32 }: Props) {
|
||||
const styles = useStyles2(getStyles);
|
||||
const draggableRef = useRef<HTMLDivElement>(null);
|
||||
@ -39,7 +42,7 @@ export function HoverWidget({ menu, title, dragClass, children, offset = -32 }:
|
||||
<div
|
||||
className={cx(styles.container, { 'show-on-hover': !menuOpen })}
|
||||
style={{ top: `${offset}px` }}
|
||||
data-testid="hover-header-container"
|
||||
data-testid={selectors.container}
|
||||
>
|
||||
{dragClass && (
|
||||
<div
|
||||
@ -47,11 +50,12 @@ export function HoverWidget({ menu, title, dragClass, children, offset = -32 }:
|
||||
onPointerDown={onPointerDown}
|
||||
onPointerUp={onPointerUp}
|
||||
ref={draggableRef}
|
||||
data-testid={selectors.dragIcon}
|
||||
>
|
||||
<Icon name="expand-arrows" className={styles.draggableIcon} />
|
||||
</div>
|
||||
)}
|
||||
{!title && <h6 className={cx(styles.untitled, styles.draggable, dragClass)}>Untitled</h6>}
|
||||
{!title && <h6 className={cx(styles.untitled, { [styles.draggable]: !!dragClass }, dragClass)}>Untitled</h6>}
|
||||
{children}
|
||||
{menu && (
|
||||
<PanelMenu
|
||||
|
@ -1,4 +1,5 @@
|
||||
import { render, screen, waitFor } from '@testing-library/react';
|
||||
import userEvent from '@testing-library/user-event';
|
||||
import React from 'react';
|
||||
import { Provider } from 'react-redux';
|
||||
import { Router } from 'react-router-dom';
|
||||
@ -8,11 +9,12 @@ import { getGrafanaContextMock } from 'test/mocks/getGrafanaContextMock';
|
||||
|
||||
import { selectors as e2eSelectors } from '@grafana/e2e-selectors/src';
|
||||
import { locationService } from '@grafana/runtime';
|
||||
import { Dashboard, DashboardCursorSync } from '@grafana/schema/src';
|
||||
import { Dashboard, DashboardCursorSync, FieldConfigSource, ThresholdsMode, Panel } from '@grafana/schema/src';
|
||||
import config from 'app/core/config';
|
||||
import { GrafanaContext } from 'app/core/context/GrafanaContext';
|
||||
import { getRouteComponentProps } from 'app/core/navigation/__mocks__/routeProps';
|
||||
import { DashboardInitPhase, DashboardMeta, DashboardRoutes } from 'app/types';
|
||||
import * as appTypes from 'app/types';
|
||||
import { DashboardInitPhase, DashboardMeta, DashboardRoutes } from 'app/types';
|
||||
|
||||
import { SafeDynamicImport } from '../../../core/components/DynamicImports/SafeDynamicImport';
|
||||
import { configureStore } from '../../../store/configureStore';
|
||||
@ -125,6 +127,9 @@ const getTestDashboard = (overrides?: Partial<Dashboard>, metaOverrides?: Partia
|
||||
|
||||
describe('PublicDashboardPage', () => {
|
||||
beforeEach(() => {
|
||||
config.featureToggles.publicDashboards = true;
|
||||
config.featureToggles.newPanelChromeUI = true;
|
||||
|
||||
jest.clearAllMocks();
|
||||
});
|
||||
|
||||
@ -175,6 +180,68 @@ describe('PublicDashboardPage', () => {
|
||||
expect(screen.queryByTestId(publicDashboardSelector.NotAvailable.container)).not.toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
||||
it('Should render panel with hover widget but without drag icon when panel title is undefined', async () => {
|
||||
const fieldConfig: FieldConfigSource = {
|
||||
defaults: {
|
||||
thresholds: {
|
||||
mode: ThresholdsMode.Absolute,
|
||||
steps: [
|
||||
{
|
||||
color: 'green',
|
||||
value: 1,
|
||||
},
|
||||
{
|
||||
color: 'red',
|
||||
value: 80,
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
overrides: [],
|
||||
};
|
||||
const panels: Panel[] = [
|
||||
{
|
||||
id: 1,
|
||||
fieldConfig,
|
||||
gridPos: {
|
||||
h: 8,
|
||||
w: 12,
|
||||
x: 0,
|
||||
y: 0,
|
||||
},
|
||||
options: {},
|
||||
title: undefined,
|
||||
type: 'timeseries',
|
||||
repeatDirection: 'h',
|
||||
transformations: [],
|
||||
transparent: false,
|
||||
},
|
||||
];
|
||||
|
||||
const newState = {
|
||||
dashboard: {
|
||||
getModel: () => getTestDashboard({ panels }),
|
||||
initError: null,
|
||||
initPhase: DashboardInitPhase.Completed,
|
||||
permissions: [],
|
||||
},
|
||||
};
|
||||
setup(undefined, newState);
|
||||
|
||||
await waitFor(() => {
|
||||
expect(screen.getByTestId(selectors.Panels.Panel.HoverWidget.container)).toBeInTheDocument();
|
||||
});
|
||||
await userEvent.hover(screen.getByTestId(selectors.Panels.Panel.HoverWidget.container));
|
||||
expect(screen.queryByTestId(selectors.Panels.Panel.HoverWidget.dragIcon)).not.toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('Should render panel without hover widget when panel title is not undefined', async () => {
|
||||
setup(undefined, newState);
|
||||
await waitFor(() => {
|
||||
expect(screen.queryByTestId(selectors.Panels.Panel.HoverWidget.container)).not.toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('Given a public dashboard with time range enabled', () => {
|
||||
|
@ -122,7 +122,7 @@ const PublicDashboardPage = (props: Props) => {
|
||||
const getStyles = (theme: GrafanaTheme2) => ({
|
||||
gridContainer: css({
|
||||
flex: 1,
|
||||
padding: theme.spacing(0, 2, 2, 2),
|
||||
padding: theme.spacing(2, 2, 2, 2),
|
||||
overflow: 'auto',
|
||||
}),
|
||||
});
|
||||
|
@ -142,7 +142,7 @@ export class DashboardGrid extends PureComponent<Props, State> {
|
||||
return { top, bottom: this.lastPanelBottom };
|
||||
}
|
||||
|
||||
renderPanels(gridWidth: number) {
|
||||
renderPanels(gridWidth: number, isDashboardDraggable: boolean) {
|
||||
const panelElements = [];
|
||||
|
||||
// Reset last panel bottom
|
||||
@ -171,7 +171,7 @@ export class DashboardGrid extends PureComponent<Props, State> {
|
||||
isViewing={panel.isViewing}
|
||||
>
|
||||
{(width: number, height: number) => {
|
||||
return this.renderPanel(panel, width, height);
|
||||
return this.renderPanel(panel, width, height, isDashboardDraggable);
|
||||
}}
|
||||
</GrafanaGridItem>
|
||||
);
|
||||
@ -180,7 +180,7 @@ export class DashboardGrid extends PureComponent<Props, State> {
|
||||
return panelElements;
|
||||
}
|
||||
|
||||
renderPanel(panel: PanelModel, width: number, height: number) {
|
||||
renderPanel(panel: PanelModel, width: number, height: number, isDraggable: boolean) {
|
||||
if (panel.type === 'row') {
|
||||
return <DashboardRow key={panel.key} panel={panel} dashboard={this.props.dashboard} />;
|
||||
}
|
||||
@ -202,6 +202,7 @@ export class DashboardGrid extends PureComponent<Props, State> {
|
||||
dashboard={this.props.dashboard}
|
||||
isEditing={panel.isEditing}
|
||||
isViewing={panel.isViewing}
|
||||
isDraggable={isDraggable}
|
||||
width={width}
|
||||
height={height}
|
||||
hideMenu={this.props.hidePanelMenus}
|
||||
@ -258,7 +259,7 @@ export class DashboardGrid extends PureComponent<Props, State> {
|
||||
onResizeStop={this.onResizeStop}
|
||||
onLayoutChange={this.onLayoutChange}
|
||||
>
|
||||
{this.renderPanels(width)}
|
||||
{this.renderPanels(width, draggable)}
|
||||
</ReactGridLayout>
|
||||
</div>
|
||||
) : (
|
||||
@ -290,7 +291,7 @@ export class DashboardGrid extends PureComponent<Props, State> {
|
||||
onResizeStop={this.onResizeStop}
|
||||
onLayoutChange={this.onLayoutChange}
|
||||
>
|
||||
{this.renderPanels(width)}
|
||||
{this.renderPanels(width, draggable)}
|
||||
</ReactGridLayout>
|
||||
</div>
|
||||
);
|
||||
|
@ -17,6 +17,7 @@ export interface OwnProps {
|
||||
dashboard: DashboardModel;
|
||||
isEditing: boolean;
|
||||
isViewing: boolean;
|
||||
isDraggable?: boolean;
|
||||
width: number;
|
||||
height: number;
|
||||
lazy?: boolean;
|
||||
@ -72,7 +73,18 @@ export class DashboardPanelUnconnected extends PureComponent<Props> {
|
||||
};
|
||||
|
||||
renderPanel = ({ isInView }: { isInView: boolean }) => {
|
||||
const { dashboard, panel, isViewing, isEditing, width, height, plugin, timezone, hideMenu } = this.props;
|
||||
const {
|
||||
dashboard,
|
||||
panel,
|
||||
isViewing,
|
||||
isEditing,
|
||||
width,
|
||||
height,
|
||||
plugin,
|
||||
timezone,
|
||||
hideMenu,
|
||||
isDraggable = true,
|
||||
} = this.props;
|
||||
|
||||
if (!plugin) {
|
||||
return null;
|
||||
@ -87,6 +99,7 @@ export class DashboardPanelUnconnected extends PureComponent<Props> {
|
||||
isViewing={isViewing}
|
||||
isEditing={isEditing}
|
||||
isInView={isInView}
|
||||
isDraggable={isDraggable}
|
||||
width={width}
|
||||
height={height}
|
||||
/>
|
||||
@ -101,6 +114,7 @@ export class DashboardPanelUnconnected extends PureComponent<Props> {
|
||||
isViewing={isViewing}
|
||||
isEditing={isEditing}
|
||||
isInView={isInView}
|
||||
isDraggable={isDraggable}
|
||||
width={width}
|
||||
height={height}
|
||||
onInstanceStateChange={this.onInstanceStateChange}
|
||||
|
@ -28,6 +28,7 @@ interface OwnProps {
|
||||
isViewing: boolean;
|
||||
isEditing: boolean;
|
||||
isInView: boolean;
|
||||
isDraggable?: boolean;
|
||||
width: number;
|
||||
height: number;
|
||||
hideMenu?: boolean;
|
||||
|
@ -65,6 +65,7 @@ export interface Props {
|
||||
isViewing: boolean;
|
||||
isEditing: boolean;
|
||||
isInView: boolean;
|
||||
isDraggable?: boolean;
|
||||
width: number;
|
||||
height: number;
|
||||
onInstanceStateChange: (value: any) => void;
|
||||
|
@ -17,6 +17,7 @@ interface CommonProps {
|
||||
isViewing: boolean;
|
||||
isEditing: boolean;
|
||||
isInView: boolean;
|
||||
isDraggable?: boolean;
|
||||
width: number;
|
||||
height: number;
|
||||
hideMenu?: boolean;
|
||||
@ -100,7 +101,8 @@ export function getPanelChromeProps(props: CommonProps) {
|
||||
|
||||
const description = props.panel.description ? onShowPanelDescription() : undefined;
|
||||
|
||||
const dragClass = !(props.isViewing || props.isEditing) ? 'grid-drag-handle' : '';
|
||||
const dragClass =
|
||||
!(props.isViewing || props.isEditing) && Boolean(props.isDraggable ?? true) ? 'grid-drag-handle' : '';
|
||||
|
||||
const title = props.panel.getDisplayTitle();
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user