[sqllab] table refactor (#2587)

* make react-virtualized table work
use dynamic sizing for cell width
enable filtering
require height prop for result set component

* fix tests and linting

* move some state to props

* move getTextWidth to visUtils

* make striped rows optional

* fix striped proptype

* update name to FilterableTable

* add basic test and fix linting

* accept array of columns keys rather than an array of objects that needs to be mapped

* move container div inside the component

* rename styles

* fit table component to width if it's smaller than parent container

* move stylesheet to javascript folder otherwise it throws an error on npm run prod

* move css to index.jsx

* fix result set spec

* fix linting and test

* fix result set props

* keep list immutable
This commit is contained in:
Alanna Scott
2017-04-18 14:29:38 -07:00
committed by GitHub
parent f40499e550
commit db6cd21504
13 changed files with 302 additions and 53 deletions

View File

@@ -32,7 +32,13 @@ class DataPreviewModal extends React.PureComponent {
</Modal.Title>
</Modal.Header>
<Modal.Body>
<ResultSet query={query} visualize={false} csv={false} actions={this.props.actions} />
<ResultSet
query={query}
visualize={false}
csv={false}
actions={this.props.actions}
height={400}
/>
</Modal.Body>
</Modal>
);

View File

@@ -134,7 +134,9 @@ class QueryTable extends React.PureComponent {
modalTitle={'Data preview'}
beforeOpen={this.openAsyncResults.bind(this, query)}
onExit={this.clearQueryResults.bind(this, query)}
modalBody={<ResultSet showSql query={query} actions={this.props.actions} />}
modalBody={
<ResultSet showSql query={query} actions={this.props.actions} height={400} />
}
/>
);
} else {

View File

@@ -1,42 +1,40 @@
import React from 'react';
import { Alert, Button, ButtonGroup, ProgressBar } from 'react-bootstrap';
import { Table } from 'reactable';
import shortid from 'shortid';
import VisualizeModal from './VisualizeModal';
import HighlightedSql from './HighlightedSql';
const RESULTS_CONTROLS_HEIGHT = 36;
import FilterableTable from '../../components/FilterableTable/FilterableTable';
const propTypes = {
actions: React.PropTypes.object,
csv: React.PropTypes.bool,
query: React.PropTypes.object,
search: React.PropTypes.bool,
searchText: React.PropTypes.string,
showSql: React.PropTypes.bool,
visualize: React.PropTypes.bool,
cache: React.PropTypes.bool,
resultSetHeight: React.PropTypes.number,
height: React.PropTypes.number.isRequired,
};
const defaultProps = {
search: true,
visualize: true,
showSql: false,
csv: true,
searchText: '',
actions: {},
cache: false,
};
const RESULT_SET_CONTROLS_HEIGHT = 46;
class ResultSet extends React.PureComponent {
export default class ResultSet extends React.PureComponent {
constructor(props) {
super(props);
this.state = {
searchText: '',
showModal: false,
data: [],
height: props.search ? props.height - RESULT_SET_CONTROLS_HEIGHT : props.height,
};
}
componentWillReceiveProps(nextProps) {
@@ -54,6 +52,7 @@ class ResultSet extends React.PureComponent {
this.fetchResults(nextProps.query);
}
}
getControls() {
if (this.props.search || this.props.visualize || this.props.csv) {
let csvButton;
@@ -132,6 +131,7 @@ class ResultSet extends React.PureComponent {
reFetchQueryResults(query) {
this.props.actions.reFetchQueryResults(query);
}
render() {
const query = this.props.query;
const results = query.results;
@@ -195,31 +195,12 @@ class ResultSet extends React.PureComponent {
/>
{this.getControls.bind(this)()}
{sql}
<div
className="ResultSet"
style={{ height: `${this.props.resultSetHeight - RESULTS_CONTROLS_HEIGHT}px` }}
>
<Table
data={data.map(function (row) {
const newRow = {};
for (const k in row) {
const val = row[k];
if (typeof (val) === 'string') {
newRow[k] = val;
} else {
newRow[k] = JSON.stringify(val);
}
}
return newRow;
})}
columns={results.columns.map(col => col.name)}
sortable
className="table table-condensed table-bordered"
filterBy={this.state.searchText}
filterable={results.columns.map(c => c.name)}
hideFilterInput
/>
</div>
<FilterableTable
data={data}
orderedColumnKeys={results.columns.map(col => col.name)}
height={this.state.height}
filterText={this.state.searchText}
/>
</div>
);
}
@@ -240,5 +221,3 @@ class ResultSet extends React.PureComponent {
}
ResultSet.propTypes = propTypes;
ResultSet.defaultProps = defaultProps;
export default ResultSet;

View File

@@ -71,7 +71,7 @@ class SouthPane extends React.PureComponent {
search
query={latestQuery}
actions={props.actions}
resultSetHeight={this.state.innerTabHeight}
height={this.state.innerTabHeight}
/>
);
} else {
@@ -90,7 +90,7 @@ class SouthPane extends React.PureComponent {
csv={false}
actions={props.actions}
cache
resultSetHeight={this.state.innerTabHeight}
height={this.state.innerTabHeight}
/>
</Tab>
));

View File

@@ -9,7 +9,9 @@ import { initEnhancer } from '../reduxUtils';
import { initJQueryAjaxCSRF } from '../modules/utils';
import App from './components/App';
import { appSetup } from '../common';
import './main.css';
require('./main.css');
require('../components/FilterableTable/FilterableTableStyles.css');
appSetup();
initJQueryAjaxCSRF();

View File

@@ -237,16 +237,6 @@ div.tablePopover:hover {
padding-bottom: 3px;
padding-top: 3px;
}
.ResultSet {
overflow: auto;
border-bottom: 1px solid #ccc;
}
.ResultSet table {
margin-bottom: 0px;
}
.ResultSet table tr.last {
border-bottom: none;
}
.ace_editor {
border: 1px solid #ccc;
margin: 0px 0px 10px 0px;