mirror of
https://github.com/apache/superset.git
synced 2026-04-21 00:54:44 +00:00
[sql lab] Make sql editor resizable (#3242)
* Update to the version of react-ace with the fixed sizing issues * Make ace editor resizable * Use small util method for offset calculation instead of $ * Test ResizableAceEditor * Make the right pane of the Sql Lab scrollable * Add default and min height to the ResizableAceEditor * Implement SplitPane * Make Splitter fullscreen * React on resize of the window * Implement min and max * Get rid of a magic number + add margin * Handle resize event with delay + cleanup the code * Make ResultSet adjustable * Make QueryHistory adjustable * Remove ResizableAceEditor * Make linter happy * Test SplitPane * Init sizes properly
This commit is contained in:
committed by
Maxime Beauchemin
parent
6fc837db51
commit
75e69f02e8
146
superset/assets/javascripts/SqlLab/components/SplitPane.jsx
Normal file
146
superset/assets/javascripts/SqlLab/components/SplitPane.jsx
Normal file
@@ -0,0 +1,146 @@
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import delay from 'lodash.delay';
|
||||
import { getTopOffset } from '../../../utils/common';
|
||||
|
||||
|
||||
const propTypes = {
|
||||
north: PropTypes.object.isRequired,
|
||||
south: PropTypes.object.isRequired,
|
||||
minHeight: PropTypes.number,
|
||||
onSizeChange: PropTypes.func,
|
||||
};
|
||||
|
||||
class SplitPane extends React.PureComponent {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = {
|
||||
dragging: false,
|
||||
};
|
||||
|
||||
this.handleDraggingStart = this.handleDraggingStart.bind(this);
|
||||
this.handleMouseUp = this.handleMouseUp.bind(this);
|
||||
this.handleMouseMove = this.handleMouseMove.bind(this);
|
||||
this.handleResize = this.handleResize.bind(this);
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
window.addEventListener('mouseup', this.handleMouseUp);
|
||||
window.addEventListener('mousemove', this.handleMouseMove);
|
||||
window.addEventListener('resize', this.handleResize);
|
||||
|
||||
this.initSize();
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
window.removeEventListener('mouseup', this.handleMouseUp);
|
||||
window.removeEventListener('mousemove', this.handleMouseMove);
|
||||
window.removeEventListener('resize', this.handleResize);
|
||||
}
|
||||
|
||||
setSize(northInPercent, southInPercent) {
|
||||
const totalHeight = this.refs.splitter.clientHeight - this.refs.dragBar.clientHeight;
|
||||
|
||||
const heightNorthInPixels = northInPercent * totalHeight / 100;
|
||||
const heightSouthInPixels = southInPercent * totalHeight / 100;
|
||||
|
||||
if (this.props.onSizeChange) {
|
||||
this.props.onSizeChange({
|
||||
north: heightNorthInPixels,
|
||||
south: heightSouthInPixels,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
initSize() {
|
||||
const totalHeight = this.refs.splitter.clientHeight;
|
||||
const dragBarHeight = this.refs.dragBar.clientHeight;
|
||||
|
||||
const heightInPixels = (totalHeight - dragBarHeight) / 2;
|
||||
const heightInPercent = heightInPixels * 100 / totalHeight;
|
||||
|
||||
this.setState({
|
||||
...this.state,
|
||||
heightNorth: heightInPercent,
|
||||
heightSouth: heightInPercent,
|
||||
});
|
||||
this.setSize(heightInPercent, heightInPercent);
|
||||
}
|
||||
|
||||
handleMouseMove(e) {
|
||||
if (!this.state.dragging) {
|
||||
return;
|
||||
}
|
||||
|
||||
const minHeight = this.props.minHeight || 0;
|
||||
|
||||
const offset = getTopOffset(this.refs.splitter);
|
||||
const totalHeight = this.refs.splitter.clientHeight;
|
||||
const dragBarHeight = this.refs.dragBar.clientHeight;
|
||||
|
||||
const heightNorthInPixels = e.pageY - offset;
|
||||
const heightSouthInPixels = totalHeight - heightNorthInPixels - dragBarHeight;
|
||||
|
||||
const heightNorthInPercent = 100 * heightNorthInPixels / totalHeight;
|
||||
const heightSouthInPercent = 100 * heightSouthInPixels / totalHeight;
|
||||
|
||||
if (heightNorthInPercent >= minHeight
|
||||
&& heightSouthInPercent >= minHeight) {
|
||||
this.setState({
|
||||
...this.state,
|
||||
heightNorth: heightNorthInPercent,
|
||||
heightSouth: heightSouthInPercent,
|
||||
});
|
||||
|
||||
this.setSize(heightNorthInPercent, heightSouthInPercent);
|
||||
}
|
||||
}
|
||||
|
||||
handleDraggingStart() {
|
||||
this.setState({ ...this.state, dragging: true });
|
||||
}
|
||||
|
||||
handleResize() {
|
||||
const { heightNorth, heightSouth } = this.state;
|
||||
/*
|
||||
The `delay` is needed since some events like 'onresize' happen before rendering.
|
||||
That means that we can't calculate the sizes right.
|
||||
*/
|
||||
delay(() => {
|
||||
this.setSize(heightNorth, heightSouth);
|
||||
}, 100);
|
||||
}
|
||||
|
||||
handleMouseUp() {
|
||||
if (this.state.dragging) {
|
||||
this.setState({ ...this.state, dragging: false });
|
||||
}
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<div ref="splitter" className="Splitter">
|
||||
<div
|
||||
style={{ height: this.state.heightNorth + '%' }}
|
||||
>
|
||||
{this.props.north}
|
||||
</div>
|
||||
<div
|
||||
ref="dragBar"
|
||||
className="DragBar"
|
||||
onMouseDown={this.handleDraggingStart}
|
||||
>
|
||||
<div className="DragBarVisible" />
|
||||
</div>
|
||||
<div
|
||||
style={{ height: this.state.heightSouth + '%' }}
|
||||
>
|
||||
{this.props.south}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
SplitPane.propTypes = propTypes;
|
||||
|
||||
export default SplitPane;
|
||||
Reference in New Issue
Block a user