Merge pull request #15141 from grafana/14946-panel-menu-on-move

Don't show panel menu on move
This commit is contained in:
Torkel Ödegaard 2019-01-30 16:11:10 +01:00 committed by GitHub
commit c33e94f438
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 84 additions and 32 deletions

View File

@ -25,7 +25,9 @@
"@types/node": "^8.0.31", "@types/node": "^8.0.31",
"@types/react": "^16.7.6", "@types/react": "^16.7.6",
"@types/react-dom": "^16.0.9", "@types/react-dom": "^16.0.9",
"@types/react-grid-layout": "^0.16.6",
"@types/react-select": "^2.0.4", "@types/react-select": "^2.0.4",
"@types/react-virtualized": "^9.18.12",
"angular-mocks": "1.6.6", "angular-mocks": "1.6.6",
"autoprefixer": "^6.4.0", "autoprefixer": "^6.4.0",
"axios": "^0.17.1", "axios": "^0.17.1",

View File

@ -1,6 +1,6 @@
import React from 'react'; import React from 'react';
import { hot } from 'react-hot-loader'; import { hot } from 'react-hot-loader';
import ReactGridLayout from 'react-grid-layout'; import ReactGridLayout, { ItemCallback } from 'react-grid-layout';
import { GRID_CELL_HEIGHT, GRID_CELL_VMARGIN, GRID_COLUMN_COUNT } from 'app/core/constants'; import { GRID_CELL_HEIGHT, GRID_CELL_VMARGIN, GRID_COLUMN_COUNT } from 'app/core/constants';
import { DashboardPanel } from './DashboardPanel'; import { DashboardPanel } from './DashboardPanel';
import { DashboardModel } from '../dashboard_model'; import { DashboardModel } from '../dashboard_model';
@ -11,6 +11,21 @@ import sizeMe from 'react-sizeme';
let lastGridWidth = 1200; let lastGridWidth = 1200;
let ignoreNextWidthChange = false; let ignoreNextWidthChange = false;
interface GridWrapperProps {
size: { width: number; };
layout: ReactGridLayout.Layout[];
onLayoutChange: (layout: ReactGridLayout.Layout[]) => void;
children: JSX.Element | JSX.Element[];
onDragStop: ItemCallback;
onResize: ItemCallback;
onResizeStop: ItemCallback;
onWidthChange: () => void;
className: string;
isResizable?: boolean;
isDraggable?: boolean;
isFullscreen?: boolean;
}
function GridWrapper({ function GridWrapper({
size, size,
layout, layout,
@ -24,7 +39,7 @@ function GridWrapper({
isResizable, isResizable,
isDraggable, isDraggable,
isFullscreen, isFullscreen,
}) { }: GridWrapperProps) {
const width = size.width > 0 ? size.width : lastGridWidth; const width = size.width > 0 ? size.width : lastGridWidth;
// logic to ignore width changes (optimization) // logic to ignore width changes (optimization)
@ -43,7 +58,6 @@ function GridWrapper({
className={className} className={className}
isDraggable={isDraggable} isDraggable={isDraggable}
isResizable={isResizable} isResizable={isResizable}
measureBeforeMount={false}
containerPadding={[0, 0]} containerPadding={[0, 0]}
useCSSTransforms={false} useCSSTransforms={false}
margin={[GRID_CELL_VMARGIN, GRID_CELL_VMARGIN]} margin={[GRID_CELL_VMARGIN, GRID_CELL_VMARGIN]}
@ -71,22 +85,17 @@ export class DashboardGrid extends React.Component<DashboardGridProps> {
gridToPanelMap: any; gridToPanelMap: any;
panelMap: { [id: string]: PanelModel }; panelMap: { [id: string]: PanelModel };
constructor(props) { constructor(props: DashboardGridProps) {
super(props); super(props);
this.onLayoutChange = this.onLayoutChange.bind(this);
this.onResize = this.onResize.bind(this);
this.onResizeStop = this.onResizeStop.bind(this);
this.onDragStop = this.onDragStop.bind(this);
this.onWidthChange = this.onWidthChange.bind(this);
// subscribe to dashboard events // subscribe to dashboard events
const dashboard = this.props.dashboard; const dashboard = this.props.dashboard;
dashboard.on('panel-added', this.triggerForceUpdate.bind(this)); dashboard.on('panel-added', this.triggerForceUpdate);
dashboard.on('panel-removed', this.triggerForceUpdate.bind(this)); dashboard.on('panel-removed', this.triggerForceUpdate);
dashboard.on('repeats-processed', this.triggerForceUpdate.bind(this)); dashboard.on('repeats-processed', this.triggerForceUpdate);
dashboard.on('view-mode-changed', this.onViewModeChanged.bind(this)); dashboard.on('view-mode-changed', this.onViewModeChanged);
dashboard.on('row-collapsed', this.triggerForceUpdate.bind(this)); dashboard.on('row-collapsed', this.triggerForceUpdate);
dashboard.on('row-expanded', this.triggerForceUpdate.bind(this)); dashboard.on('row-expanded', this.triggerForceUpdate);
} }
buildLayout() { buildLayout() {
@ -123,7 +132,7 @@ export class DashboardGrid extends React.Component<DashboardGridProps> {
return layout; return layout;
} }
onLayoutChange(newLayout) { onLayoutChange = (newLayout: ReactGridLayout.Layout[]) => {
for (const newPos of newLayout) { for (const newPos of newLayout) {
this.panelMap[newPos.i].updateGridPos(newPos); this.panelMap[newPos.i].updateGridPos(newPos);
} }
@ -131,22 +140,22 @@ export class DashboardGrid extends React.Component<DashboardGridProps> {
this.props.dashboard.sortPanelsByGridPos(); this.props.dashboard.sortPanelsByGridPos();
} }
triggerForceUpdate() { triggerForceUpdate = () => {
this.forceUpdate(); this.forceUpdate();
} }
onWidthChange() { onWidthChange = () => {
for (const panel of this.props.dashboard.panels) { for (const panel of this.props.dashboard.panels) {
panel.resizeDone(); panel.resizeDone();
} }
} }
onViewModeChanged(payload) { onViewModeChanged = () => {
ignoreNextWidthChange = true; ignoreNextWidthChange = true;
this.forceUpdate(); this.forceUpdate();
} }
updateGridPos(item, layout) { updateGridPos = (item: ReactGridLayout.Layout, layout: ReactGridLayout.Layout[]) => {
this.panelMap[item.i].updateGridPos(item); this.panelMap[item.i].updateGridPos(item);
// react-grid-layout has a bug (#670), and onLayoutChange() is only called when the component is mounted. // react-grid-layout has a bug (#670), and onLayoutChange() is only called when the component is mounted.
@ -154,16 +163,17 @@ export class DashboardGrid extends React.Component<DashboardGridProps> {
this.onLayoutChange(layout); this.onLayoutChange(layout);
} }
onResize(layout, oldItem, newItem) { onResize: ItemCallback = (layout, oldItem, newItem) => {
console.log();
this.panelMap[newItem.i].updateGridPos(newItem); this.panelMap[newItem.i].updateGridPos(newItem);
} }
onResizeStop(layout, oldItem, newItem) { onResizeStop: ItemCallback = (layout, oldItem, newItem) => {
this.updateGridPos(newItem, layout); this.updateGridPos(newItem, layout);
this.panelMap[newItem.i].resizeDone(); this.panelMap[newItem.i].resizeDone();
} }
onDragStop(layout, oldItem, newItem) { onDragStop: ItemCallback = (layout, oldItem, newItem) => {
this.updateGridPos(newItem, layout); this.updateGridPos(newItem, layout);
} }

View File

@ -1,5 +1,6 @@
import React, { Component } from 'react'; import React, { Component } from 'react';
import classNames from 'classnames'; import classNames from 'classnames';
import { isEqual } from 'lodash';
import PanelHeaderCorner from './PanelHeaderCorner'; import PanelHeaderCorner from './PanelHeaderCorner';
import { PanelHeaderMenu } from './PanelHeaderMenu'; import { PanelHeaderMenu } from './PanelHeaderMenu';
@ -19,21 +20,45 @@ export interface Props {
links?: []; links?: [];
} }
interface ClickCoordinates {
x: number;
y: number;
}
interface State { interface State {
panelMenuOpen: boolean; panelMenuOpen: boolean;
} }
export class PanelHeader extends Component<Props, State> { export class PanelHeader extends Component<Props, State> {
clickCoordinates: ClickCoordinates = {x: 0, y: 0};
state = { state = {
panelMenuOpen: false, panelMenuOpen: false,
clickCoordinates: {x: 0, y: 0}
}; };
onMenuToggle = event => { eventToClickCoordinates = (event: React.MouseEvent<HTMLDivElement>) => {
event.stopPropagation(); return {
x: event.clientX,
y: event.clientY
};
}
this.setState(prevState => ({ onMouseDown = (event: React.MouseEvent<HTMLDivElement>) => {
panelMenuOpen: !prevState.panelMenuOpen, this.clickCoordinates = this.eventToClickCoordinates(event);
})); };
isClick = (clickCoordinates: ClickCoordinates) => {
return isEqual(clickCoordinates, this.clickCoordinates);
}
onMenuToggle = (event: React.MouseEvent<HTMLDivElement>) => {
if (this.isClick(this.eventToClickCoordinates(event))) {
event.stopPropagation();
this.setState(prevState => ({
panelMenuOpen: !prevState.panelMenuOpen,
}));
}
}; };
closeMenu = () => { closeMenu = () => {
@ -64,7 +89,7 @@ export class PanelHeader extends Component<Props, State> {
<i className="fa fa-spinner fa-spin" /> <i className="fa fa-spinner fa-spin" />
</span> </span>
)} )}
<div className="panel-title-container" onClick={this.onMenuToggle}> <div className="panel-title-container" onClick={this.onMenuToggle} onMouseDown={this.onMouseDown}>
<div className="panel-title"> <div className="panel-title">
<span className="icon-gf panel-alert-icon" /> <span className="icon-gf panel-alert-icon" />
<span className="panel-title-text"> <span className="panel-title-text">

View File

@ -1,6 +1,6 @@
import React, { PureComponent } from 'react'; import React, { PureComponent } from 'react';
import { throttle } from 'lodash'; import { throttle } from 'lodash';
import Draggable from 'react-draggable'; import Draggable, { DraggableEventHandler } from 'react-draggable';
import { PanelModel } from '../panel_model'; import { PanelModel } from '../panel_model';
@ -42,7 +42,7 @@ export class PanelResizer extends PureComponent<Props, State> {
return 100; return 100;
} }
changeHeight = height => { changeHeight = (height: number) => {
const sh = this.smallestHeight; const sh = this.smallestHeight;
const lh = this.largestHeight; const lh = this.largestHeight;
height = height < sh ? sh : height; height = height < sh ? sh : height;
@ -54,7 +54,7 @@ export class PanelResizer extends PureComponent<Props, State> {
}); });
}; };
onDrag = (evt, data) => { onDrag: DraggableEventHandler = (evt, data) => {
const newHeight = this.state.editorHeight + data.y; const newHeight = this.state.editorHeight + data.y;
this.throttledChangeHeight(newHeight); this.throttledChangeHeight(newHeight);
this.throttledResizeDone(); this.throttledResizeDone();

View File

@ -1773,6 +1773,13 @@
dependencies: dependencies:
"@types/react" "*" "@types/react" "*"
"@types/react-grid-layout@^0.16.6":
version "0.16.6"
resolved "https://registry.yarnpkg.com/@types/react-grid-layout/-/react-grid-layout-0.16.6.tgz#9149efe128e05d59c54063c7781d18b8febe112c"
integrity sha512-Jp0VfCHJE4uxekPBPpRkADKOjoSHssF2ba1ZMMAfCEqkoSkE+K+3bhI39++fbd7MqGySaqADVHeOoxlBnA3p5g==
dependencies:
"@types/react" "*"
"@types/react-select@^2.0.4": "@types/react-select@^2.0.4":
version "2.0.11" version "2.0.11"
resolved "https://registry.yarnpkg.com/@types/react-select/-/react-select-2.0.11.tgz#9b2b1fdb12b67a5a617c5f572e15617636cc65af" resolved "https://registry.yarnpkg.com/@types/react-select/-/react-select-2.0.11.tgz#9b2b1fdb12b67a5a617c5f572e15617636cc65af"
@ -1796,6 +1803,14 @@
dependencies: dependencies:
"@types/react" "*" "@types/react" "*"
"@types/react-virtualized@^9.18.12":
version "9.18.12"
resolved "https://registry.yarnpkg.com/@types/react-virtualized/-/react-virtualized-9.18.12.tgz#541e65c5e0b4629d6a1c6f339171c7943e016ecb"
integrity sha512-Msdpt9zvYlb5Ul4PA339QUkJ0/z2O+gaFxed1rG+2rZjbe6XdYo7jWfJe206KBnjj84DwPPIbPFQCtoGuNwNTQ==
dependencies:
"@types/prop-types" "*"
"@types/react" "*"
"@types/react@*", "@types/react@16.7.6", "@types/react@^16.7.6": "@types/react@*", "@types/react@16.7.6", "@types/react@^16.7.6":
version "16.7.6" version "16.7.6"
resolved "https://registry.yarnpkg.com/@types/react/-/react-16.7.6.tgz#80e4bab0d0731ad3ae51f320c4b08bdca5f03040" resolved "https://registry.yarnpkg.com/@types/react/-/react-16.7.6.tgz#80e4bab0d0731ad3ae51f320c4b08bdca5f03040"