mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
Refactor SplitPaneWrapper to be more centralized component, refactor PanelEditor to use it (#58380)
* Move layout to paneleditor, make SplitPaneWrapper more generic * Read/write the size ratio in local storage * Add min height to enable scrollbar * Enable show/hide panel options * Change back variable name
This commit is contained in:
@@ -1,28 +1,23 @@
|
|||||||
import { css, cx } from '@emotion/css';
|
import { css, cx } from '@emotion/css';
|
||||||
import React, { createRef, MutableRefObject, PureComponent, ReactNode } from 'react';
|
import React, { createRef, MutableRefObject, PureComponent } from 'react';
|
||||||
import SplitPane from 'react-split-pane';
|
import SplitPane, { Split } from 'react-split-pane';
|
||||||
|
|
||||||
import { GrafanaTheme2 } from '@grafana/data';
|
import { GrafanaTheme2 } from '@grafana/data';
|
||||||
import { config } from 'app/core/config';
|
import { config } from 'app/core/config';
|
||||||
|
|
||||||
enum Pane {
|
|
||||||
Right,
|
|
||||||
Top,
|
|
||||||
}
|
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
leftPaneComponents: ReactNode[] | ReactNode;
|
splitOrientation?: Split;
|
||||||
rightPaneComponents: ReactNode;
|
paneSize: number;
|
||||||
uiState: { topPaneSize: number; rightPaneSize: number };
|
splitVisible?: boolean;
|
||||||
rightPaneVisible?: boolean;
|
maxSize?: number;
|
||||||
updateUiState: (uiState: { topPaneSize?: number; rightPaneSize?: number }) => void;
|
primary?: 'first' | 'second';
|
||||||
|
onDragFinished?: (size?: number) => void;
|
||||||
|
secondaryPaneStyle?: React.CSSProperties;
|
||||||
}
|
}
|
||||||
|
|
||||||
export class SplitPaneWrapper extends PureComponent<Props> {
|
export class SplitPaneWrapper extends PureComponent<Props> {
|
||||||
|
//requestAnimationFrame reference
|
||||||
rafToken: MutableRefObject<number | null> = createRef();
|
rafToken: MutableRefObject<number | null> = createRef();
|
||||||
static defaultProps = {
|
|
||||||
rightPaneVisible: true,
|
|
||||||
};
|
|
||||||
|
|
||||||
componentDidMount() {
|
componentDidMount() {
|
||||||
window.addEventListener('resize', this.updateSplitPaneSize);
|
window.addEventListener('resize', this.updateSplitPaneSize);
|
||||||
@@ -41,86 +36,41 @@ export class SplitPaneWrapper extends PureComponent<Props> {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
onDragFinished = (pane: Pane, size?: number) => {
|
onDragFinished = (size?: number) => {
|
||||||
document.body.style.cursor = 'auto';
|
document.body.style.cursor = 'auto';
|
||||||
|
|
||||||
// When the drag handle is just clicked size is undefined
|
if (this.props.onDragFinished && size !== undefined) {
|
||||||
if (!size) {
|
this.props.onDragFinished(size);
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const { updateUiState } = this.props;
|
|
||||||
if (pane === Pane.Top) {
|
|
||||||
updateUiState({
|
|
||||||
topPaneSize: size / window.innerHeight,
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
updateUiState({
|
|
||||||
rightPaneSize: size / window.innerWidth,
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
onDragStarted = () => {
|
onDragStarted = () => {
|
||||||
document.body.style.cursor = 'row-resize';
|
document.body.style.cursor = this.props.splitOrientation === 'horizontal' ? 'row-resize' : 'col-resize';
|
||||||
};
|
};
|
||||||
|
|
||||||
renderHorizontalSplit() {
|
|
||||||
const { leftPaneComponents, uiState } = this.props;
|
|
||||||
const styles = getStyles(config.theme2);
|
|
||||||
const topPaneSize = uiState.topPaneSize >= 1 ? uiState.topPaneSize : uiState.topPaneSize * window.innerHeight;
|
|
||||||
|
|
||||||
/*
|
|
||||||
Guesstimate the height of the browser window minus
|
|
||||||
panel toolbar and editor toolbar (~120px). This is to prevent resizing
|
|
||||||
the preview window beyond the browser window.
|
|
||||||
*/
|
|
||||||
|
|
||||||
if (Array.isArray(leftPaneComponents)) {
|
|
||||||
return (
|
|
||||||
<SplitPane
|
|
||||||
split="horizontal"
|
|
||||||
maxSize={-200}
|
|
||||||
primary="first"
|
|
||||||
size={topPaneSize}
|
|
||||||
pane2Style={{ minHeight: 0 }}
|
|
||||||
resizerClassName={styles.resizerH}
|
|
||||||
onDragStarted={this.onDragStarted}
|
|
||||||
onDragFinished={(size) => this.onDragFinished(Pane.Top, size)}
|
|
||||||
>
|
|
||||||
{leftPaneComponents}
|
|
||||||
</SplitPane>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
return <div className={styles.singleLeftPane}>{leftPaneComponents}</div>;
|
|
||||||
}
|
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const { rightPaneVisible, rightPaneComponents, uiState } = this.props;
|
const { paneSize, splitOrientation, maxSize, primary, secondaryPaneStyle } = this.props;
|
||||||
// Limit options pane width to 90% of screen.
|
// Limit options pane width to 90% of screen.
|
||||||
const styles = getStyles(config.theme2);
|
const styles = getStyles(config.theme2);
|
||||||
|
|
||||||
// Need to handle when width is relative. ie a percentage of the viewport
|
// Need to handle when width is relative. ie a percentage of the viewport
|
||||||
const rightPaneSize =
|
const paneSizePx =
|
||||||
uiState.rightPaneSize <= 1 ? uiState.rightPaneSize * window.innerWidth : uiState.rightPaneSize;
|
paneSize <= 1
|
||||||
|
? paneSize * (splitOrientation === 'horizontal' ? window.innerHeight : window.innerWidth)
|
||||||
if (!rightPaneVisible) {
|
: paneSize;
|
||||||
return this.renderHorizontalSplit();
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<SplitPane
|
<SplitPane
|
||||||
split="vertical"
|
split={splitOrientation}
|
||||||
maxSize={-300}
|
maxSize={maxSize}
|
||||||
size={rightPaneSize}
|
size={paneSizePx}
|
||||||
primary="second"
|
primary={primary}
|
||||||
resizerClassName={styles.resizerV}
|
resizerClassName={splitOrientation === 'horizontal' ? styles.resizerH : styles.resizerV}
|
||||||
onDragStarted={() => (document.body.style.cursor = 'col-resize')}
|
onDragStarted={() => this.onDragStarted()}
|
||||||
onDragFinished={(size) => this.onDragFinished(Pane.Right, size)}
|
onDragFinished={(size) => this.onDragFinished(size)}
|
||||||
|
pane2Style={secondaryPaneStyle}
|
||||||
>
|
>
|
||||||
{this.renderHorizontalSplit()}
|
{this.props.children}
|
||||||
{rightPaneComponents}
|
|
||||||
</SplitPane>
|
</SplitPane>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -47,7 +47,7 @@ import { PanelEditorTableView } from './PanelEditorTableView';
|
|||||||
import { PanelEditorTabs } from './PanelEditorTabs';
|
import { PanelEditorTabs } from './PanelEditorTabs';
|
||||||
import { VisualizationButton } from './VisualizationButton';
|
import { VisualizationButton } from './VisualizationButton';
|
||||||
import { discardPanelChanges, initPanelEditor, updatePanelEditorUIState } from './state/actions';
|
import { discardPanelChanges, initPanelEditor, updatePanelEditorUIState } from './state/actions';
|
||||||
import { toggleTableView } from './state/reducers';
|
import { PanelEditorUIState, toggleTableView } from './state/reducers';
|
||||||
import { getPanelEditorTabs } from './state/selectors';
|
import { getPanelEditorTabs } from './state/selectors';
|
||||||
import { DisplayMode, displayModes, PanelEditorTab } from './types';
|
import { DisplayMode, displayModes, PanelEditorTab } from './types';
|
||||||
import { calculatePanelSize } from './utils';
|
import { calculatePanelSize } from './utils';
|
||||||
@@ -438,8 +438,27 @@ export class PanelEditorUnconnected extends PureComponent<Props> {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
renderHorizontalSplit(uiState: PanelEditorUIState, styles: EditorStyles) {
|
||||||
|
return (
|
||||||
|
<SplitPaneWrapper
|
||||||
|
splitOrientation="horizontal"
|
||||||
|
maxSize={-200}
|
||||||
|
paneSize={uiState.topPaneSize}
|
||||||
|
primary="first"
|
||||||
|
secondaryPaneStyle={{ minHeight: 0 }}
|
||||||
|
onDragFinished={(size) => {
|
||||||
|
if (size) {
|
||||||
|
updatePanelEditorUIState({ topPaneSize: size / window.innerHeight });
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{this.renderPanelAndEditor(styles)}
|
||||||
|
</SplitPaneWrapper>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const { initDone, updatePanelEditorUIState, uiState, theme, sectionNav, pageNav, className } = this.props;
|
const { initDone, uiState, theme, sectionNav, pageNav, className, updatePanelEditorUIState } = this.props;
|
||||||
const styles = getStyles(theme, this.props);
|
const styles = getStyles(theme, this.props);
|
||||||
|
|
||||||
if (!initDone) {
|
if (!initDone) {
|
||||||
@@ -457,13 +476,24 @@ export class PanelEditorUnconnected extends PureComponent<Props> {
|
|||||||
>
|
>
|
||||||
<div className={styles.wrapper}>
|
<div className={styles.wrapper}>
|
||||||
<div className={styles.verticalSplitPanesWrapper}>
|
<div className={styles.verticalSplitPanesWrapper}>
|
||||||
<SplitPaneWrapper
|
{!uiState.isPanelOptionsVisible ? (
|
||||||
leftPaneComponents={this.renderPanelAndEditor(styles)}
|
this.renderHorizontalSplit(uiState, styles)
|
||||||
rightPaneComponents={this.renderOptionsPane()}
|
) : (
|
||||||
uiState={uiState}
|
<SplitPaneWrapper
|
||||||
updateUiState={updatePanelEditorUIState}
|
splitOrientation="vertical"
|
||||||
rightPaneVisible={uiState.isPanelOptionsVisible}
|
maxSize={-300}
|
||||||
/>
|
paneSize={uiState.rightPaneSize}
|
||||||
|
primary="second"
|
||||||
|
onDragFinished={(size) => {
|
||||||
|
if (size) {
|
||||||
|
updatePanelEditorUIState({ rightPaneSize: size / window.innerWidth });
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{this.renderHorizontalSplit(uiState, styles)}
|
||||||
|
{this.renderOptionsPane()}
|
||||||
|
</SplitPaneWrapper>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
{this.state.showSaveLibraryPanelModal && (
|
{this.state.showSaveLibraryPanelModal && (
|
||||||
<SaveLibraryPanelModal
|
<SaveLibraryPanelModal
|
||||||
|
|||||||
Reference in New Issue
Block a user