DashboardGrid: Fixes moving panels on first load (#67953)

* DashboardGrid: Fixes moving panels on first load

* Minor tweak

* Use theme breakpoint and add media query
This commit is contained in:
Torkel Ödegaard 2023-05-09 14:33:41 +02:00 committed by GitHub
parent 6137e45fe1
commit ea1c1b9fb8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 39 additions and 62 deletions

View File

@ -107,6 +107,11 @@ function getStyles(theme: GrafanaTheme2) {
flexDirection: 'column',
maxWidth: '890px',
gap: theme.spacing.gridSize * 4,
paddingTop: theme.spacing(2),
[theme.breakpoints.up('sm')]: {
paddingTop: theme.spacing(12),
},
}),
containerBox: css({
label: 'container-box',

View File

@ -24,12 +24,7 @@ export interface Props {
viewPanel: PanelModel | null;
hidePanelMenus?: boolean;
}
export interface State {
isLayoutInitialized: boolean;
}
export class DashboardGrid extends PureComponent<Props, State> {
export class DashboardGrid extends PureComponent<Props> {
private panelMap: { [key: string]: PanelModel } = {};
private eventSubs = new Subscription();
private windowHeight = 1200;
@ -37,13 +32,10 @@ export class DashboardGrid extends PureComponent<Props, State> {
private gridWidth = 0;
/** Used to keep track of mobile panel layout position */
private lastPanelBottom = 0;
private isLayoutInitialized = false;
constructor(props: Props) {
super(props);
this.state = {
isLayoutInitialized: false,
};
}
componentDidMount() {
@ -93,15 +85,14 @@ export class DashboardGrid extends PureComponent<Props, State> {
onLayoutChange = (newLayout: ReactGridLayout.Layout[]) => {
for (const newPos of newLayout) {
this.panelMap[newPos.i!].updateGridPos(newPos, this.state.isLayoutInitialized);
this.panelMap[newPos.i!].updateGridPos(newPos, this.isLayoutInitialized);
}
if (this.isLayoutInitialized) {
this.isLayoutInitialized = true;
}
this.props.dashboard.sortPanelsByGridPos();
// This is called on grid mount as it can correct invalid initial grid positions
if (!this.state.isLayoutInitialized) {
this.setState({ isLayoutInitialized: true });
}
};
triggerForceUpdate = () => {
@ -210,9 +201,24 @@ export class DashboardGrid extends PureComponent<Props, State> {
);
}
/**
* Without this hack the move animations are triggered on initial load and all panels fly into position.
* This can be quite distracting and make the dashboard appear to less snappy.
*/
onGetWrapperDivRef = (ref: HTMLDivElement | null) => {
if (ref) {
setTimeout(() => {
ref.classList.add('react-grid-layout--enable-move-animations');
}, 50);
}
};
render() {
const { dashboard, isEditable } = this.props;
const hasPanels = dashboard.panels && dashboard.panels.length > 0;
const { isEditable, dashboard } = this.props;
if (config.featureToggles.emptyDashboardPage && dashboard.panels.length === 0) {
return <DashboardEmpty dashboard={dashboard} canCreate={isEditable} />;
}
/**
* We have a parent with "flex: 1 1 0" we need to reset it to "flex: 1 1 auto" to have the AutoSizer
@ -227,59 +233,23 @@ export class DashboardGrid extends PureComponent<Props, State> {
return null;
}
const draggable = width <= 769 ? false : isEditable;
// Disable draggable if mobile device, solving an issue with unintentionally
// moving panels. https://github.com/grafana/grafana/issues/18497
const draggable = width <= config.theme2.breakpoints.values.md ? false : isEditable;
/*
Disable draggable if mobile device, solving an issue with unintentionally
moving panels. https://github.com/grafana/grafana/issues/18497
theme.breakpoints.md = 769
*/
return config.featureToggles.emptyDashboardPage ? (
hasPanels ? (
/**
* The children is using a width of 100% so we need to guarantee that it is wrapped
* in an element that has the calculated size given by the AutoSizer. The AutoSizer
* has a width of 0 and will let its content overflow its div.
*/
<div style={{ width: `${width}px`, height: '100%' }}>
<ReactGridLayout
width={width}
isDraggable={draggable}
isResizable={isEditable}
containerPadding={[0, 0]}
useCSSTransforms={false}
margin={[GRID_CELL_VMARGIN, GRID_CELL_VMARGIN]}
cols={GRID_COLUMN_COUNT}
rowHeight={GRID_CELL_HEIGHT}
draggableHandle=".grid-drag-handle"
draggableCancel=".grid-drag-cancel"
layout={this.buildLayout()}
onDragStop={this.onDragStop}
onResize={this.onResize}
onResizeStop={this.onResizeStop}
onLayoutChange={this.onLayoutChange}
>
{this.renderPanels(width, draggable)}
</ReactGridLayout>
</div>
) : (
<div style={{ width: `${width}px`, height: '100%', padding: `${draggable ? '100px 0' : '0'}` }}>
<DashboardEmpty dashboard={dashboard} canCreate={isEditable} />
</div>
)
) : (
return (
/**
* The children is using a width of 100% so we need to guarantee that it is wrapped
* in an element that has the calculated size given by the AutoSizer. The AutoSizer
* has a width of 0 and will let its content overflow its div.
*/
<div style={{ width: `${width}px`, height: '100%' }}>
<div style={{ width: width, height: '100%' }} ref={this.onGetWrapperDivRef}>
<ReactGridLayout
width={width}
isDraggable={draggable}
isResizable={isEditable}
containerPadding={[0, 0]}
useCSSTransforms={false}
useCSSTransforms={true}
margin={[GRID_CELL_VMARGIN, GRID_CELL_VMARGIN]}
cols={GRID_COLUMN_COUNT}
rowHeight={GRID_CELL_HEIGHT}

View File

@ -94,6 +94,8 @@
transition-property: none;
}
.animated .react-grid-item.cssTransforms {
transition-property: transform;
.react-grid-layout--enable-move-animations {
.react-grid-item.cssTransforms {
transition-property: transform;
}
}