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:
Kristina
2022-11-15 09:10:05 -06:00
committed by GitHub
parent 78f0340031
commit 2055d922f3
2 changed files with 67 additions and 87 deletions

View File

@@ -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>
); );
} }

View File

@@ -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