mirror of
https://github.com/apache/superset.git
synced 2024-09-12 08:39:45 -04:00
[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:
parent
f40499e550
commit
db6cd21504
@ -32,7 +32,13 @@ class DataPreviewModal extends React.PureComponent {
|
|||||||
</Modal.Title>
|
</Modal.Title>
|
||||||
</Modal.Header>
|
</Modal.Header>
|
||||||
<Modal.Body>
|
<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.Body>
|
||||||
</Modal>
|
</Modal>
|
||||||
);
|
);
|
||||||
|
@ -134,7 +134,9 @@ class QueryTable extends React.PureComponent {
|
|||||||
modalTitle={'Data preview'}
|
modalTitle={'Data preview'}
|
||||||
beforeOpen={this.openAsyncResults.bind(this, query)}
|
beforeOpen={this.openAsyncResults.bind(this, query)}
|
||||||
onExit={this.clearQueryResults.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 {
|
} else {
|
||||||
|
@ -1,42 +1,40 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { Alert, Button, ButtonGroup, ProgressBar } from 'react-bootstrap';
|
import { Alert, Button, ButtonGroup, ProgressBar } from 'react-bootstrap';
|
||||||
import { Table } from 'reactable';
|
|
||||||
import shortid from 'shortid';
|
import shortid from 'shortid';
|
||||||
|
|
||||||
import VisualizeModal from './VisualizeModal';
|
import VisualizeModal from './VisualizeModal';
|
||||||
import HighlightedSql from './HighlightedSql';
|
import HighlightedSql from './HighlightedSql';
|
||||||
|
import FilterableTable from '../../components/FilterableTable/FilterableTable';
|
||||||
const RESULTS_CONTROLS_HEIGHT = 36;
|
|
||||||
|
|
||||||
const propTypes = {
|
const propTypes = {
|
||||||
actions: React.PropTypes.object,
|
actions: React.PropTypes.object,
|
||||||
csv: React.PropTypes.bool,
|
csv: React.PropTypes.bool,
|
||||||
query: React.PropTypes.object,
|
query: React.PropTypes.object,
|
||||||
search: React.PropTypes.bool,
|
search: React.PropTypes.bool,
|
||||||
searchText: React.PropTypes.string,
|
|
||||||
showSql: React.PropTypes.bool,
|
showSql: React.PropTypes.bool,
|
||||||
visualize: React.PropTypes.bool,
|
visualize: React.PropTypes.bool,
|
||||||
cache: React.PropTypes.bool,
|
cache: React.PropTypes.bool,
|
||||||
resultSetHeight: React.PropTypes.number,
|
height: React.PropTypes.number.isRequired,
|
||||||
};
|
};
|
||||||
const defaultProps = {
|
const defaultProps = {
|
||||||
search: true,
|
search: true,
|
||||||
visualize: true,
|
visualize: true,
|
||||||
showSql: false,
|
showSql: false,
|
||||||
csv: true,
|
csv: true,
|
||||||
searchText: '',
|
|
||||||
actions: {},
|
actions: {},
|
||||||
cache: false,
|
cache: false,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const RESULT_SET_CONTROLS_HEIGHT = 46;
|
||||||
|
|
||||||
class ResultSet extends React.PureComponent {
|
export default class ResultSet extends React.PureComponent {
|
||||||
constructor(props) {
|
constructor(props) {
|
||||||
super(props);
|
super(props);
|
||||||
this.state = {
|
this.state = {
|
||||||
searchText: '',
|
searchText: '',
|
||||||
showModal: false,
|
showModal: false,
|
||||||
data: [],
|
data: [],
|
||||||
|
height: props.search ? props.height - RESULT_SET_CONTROLS_HEIGHT : props.height,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
componentWillReceiveProps(nextProps) {
|
componentWillReceiveProps(nextProps) {
|
||||||
@ -54,6 +52,7 @@ class ResultSet extends React.PureComponent {
|
|||||||
this.fetchResults(nextProps.query);
|
this.fetchResults(nextProps.query);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
getControls() {
|
getControls() {
|
||||||
if (this.props.search || this.props.visualize || this.props.csv) {
|
if (this.props.search || this.props.visualize || this.props.csv) {
|
||||||
let csvButton;
|
let csvButton;
|
||||||
@ -132,6 +131,7 @@ class ResultSet extends React.PureComponent {
|
|||||||
reFetchQueryResults(query) {
|
reFetchQueryResults(query) {
|
||||||
this.props.actions.reFetchQueryResults(query);
|
this.props.actions.reFetchQueryResults(query);
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const query = this.props.query;
|
const query = this.props.query;
|
||||||
const results = query.results;
|
const results = query.results;
|
||||||
@ -195,31 +195,12 @@ class ResultSet extends React.PureComponent {
|
|||||||
/>
|
/>
|
||||||
{this.getControls.bind(this)()}
|
{this.getControls.bind(this)()}
|
||||||
{sql}
|
{sql}
|
||||||
<div
|
<FilterableTable
|
||||||
className="ResultSet"
|
data={data}
|
||||||
style={{ height: `${this.props.resultSetHeight - RESULTS_CONTROLS_HEIGHT}px` }}
|
orderedColumnKeys={results.columns.map(col => col.name)}
|
||||||
>
|
height={this.state.height}
|
||||||
<Table
|
filterText={this.state.searchText}
|
||||||
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>
|
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -240,5 +221,3 @@ class ResultSet extends React.PureComponent {
|
|||||||
}
|
}
|
||||||
ResultSet.propTypes = propTypes;
|
ResultSet.propTypes = propTypes;
|
||||||
ResultSet.defaultProps = defaultProps;
|
ResultSet.defaultProps = defaultProps;
|
||||||
|
|
||||||
export default ResultSet;
|
|
||||||
|
@ -71,7 +71,7 @@ class SouthPane extends React.PureComponent {
|
|||||||
search
|
search
|
||||||
query={latestQuery}
|
query={latestQuery}
|
||||||
actions={props.actions}
|
actions={props.actions}
|
||||||
resultSetHeight={this.state.innerTabHeight}
|
height={this.state.innerTabHeight}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
@ -90,7 +90,7 @@ class SouthPane extends React.PureComponent {
|
|||||||
csv={false}
|
csv={false}
|
||||||
actions={props.actions}
|
actions={props.actions}
|
||||||
cache
|
cache
|
||||||
resultSetHeight={this.state.innerTabHeight}
|
height={this.state.innerTabHeight}
|
||||||
/>
|
/>
|
||||||
</Tab>
|
</Tab>
|
||||||
));
|
));
|
||||||
|
@ -9,7 +9,9 @@ import { initEnhancer } from '../reduxUtils';
|
|||||||
import { initJQueryAjaxCSRF } from '../modules/utils';
|
import { initJQueryAjaxCSRF } from '../modules/utils';
|
||||||
import App from './components/App';
|
import App from './components/App';
|
||||||
import { appSetup } from '../common';
|
import { appSetup } from '../common';
|
||||||
import './main.css';
|
|
||||||
|
require('./main.css');
|
||||||
|
require('../components/FilterableTable/FilterableTableStyles.css');
|
||||||
|
|
||||||
appSetup();
|
appSetup();
|
||||||
initJQueryAjaxCSRF();
|
initJQueryAjaxCSRF();
|
||||||
|
@ -237,16 +237,6 @@ div.tablePopover:hover {
|
|||||||
padding-bottom: 3px;
|
padding-bottom: 3px;
|
||||||
padding-top: 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 {
|
.ace_editor {
|
||||||
border: 1px solid #ccc;
|
border: 1px solid #ccc;
|
||||||
margin: 0px 0px 10px 0px;
|
margin: 0px 0px 10px 0px;
|
||||||
|
@ -0,0 +1,190 @@
|
|||||||
|
import { List } from 'immutable';
|
||||||
|
import React, { PropTypes, PureComponent } from 'react';
|
||||||
|
import {
|
||||||
|
Column,
|
||||||
|
Table,
|
||||||
|
SortDirection,
|
||||||
|
SortIndicator,
|
||||||
|
} from 'react-virtualized';
|
||||||
|
import { getTextWidth } from '../../modules/visUtils';
|
||||||
|
|
||||||
|
const propTypes = {
|
||||||
|
orderedColumnKeys: PropTypes.array.isRequired,
|
||||||
|
data: PropTypes.array.isRequired,
|
||||||
|
height: PropTypes.number.isRequired,
|
||||||
|
filterText: PropTypes.string,
|
||||||
|
headerHeight: PropTypes.number,
|
||||||
|
overscanRowCount: PropTypes.number,
|
||||||
|
rowHeight: PropTypes.number,
|
||||||
|
striped: PropTypes.bool,
|
||||||
|
};
|
||||||
|
|
||||||
|
const defaultProps = {
|
||||||
|
filterText: '',
|
||||||
|
headerHeight: 32,
|
||||||
|
overscanRowCount: 10,
|
||||||
|
rowHeight: 32,
|
||||||
|
striped: true,
|
||||||
|
};
|
||||||
|
|
||||||
|
export default class FilterableTable extends PureComponent {
|
||||||
|
constructor(props) {
|
||||||
|
super(props);
|
||||||
|
this.list = List(this.formatTableData(props.data));
|
||||||
|
this.headerRenderer = this.headerRenderer.bind(this);
|
||||||
|
this.rowClassName = this.rowClassName.bind(this);
|
||||||
|
this.sort = this.sort.bind(this);
|
||||||
|
|
||||||
|
this.widthsForColumnsByKey = this.getWidthsForColumns();
|
||||||
|
this.totalTableWidth = props.orderedColumnKeys
|
||||||
|
.map(key => this.widthsForColumnsByKey[key])
|
||||||
|
.reduce((curr, next) => curr + next);
|
||||||
|
|
||||||
|
this.state = {
|
||||||
|
sortBy: props.orderedColumnKeys[0],
|
||||||
|
sortDirection: SortDirection.ASC,
|
||||||
|
fitted: false,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
componentDidMount() {
|
||||||
|
this.fitTableToWidthIfNeeded();
|
||||||
|
}
|
||||||
|
|
||||||
|
getDatum(list, index) {
|
||||||
|
return list.get(index % list.size);
|
||||||
|
}
|
||||||
|
|
||||||
|
getWidthsForColumns() {
|
||||||
|
const PADDING = 40; // accounts for cell padding and width of sorting icon
|
||||||
|
const widthsByColumnKey = {};
|
||||||
|
this.props.orderedColumnKeys.forEach((key) => {
|
||||||
|
const colWidths = this.list
|
||||||
|
.map(d => getTextWidth(d[key]) + PADDING) // get width for each value for a key
|
||||||
|
.push(getTextWidth(key) + PADDING); // add width of column key to end of list
|
||||||
|
// set max width as value for key
|
||||||
|
widthsByColumnKey[key] = Math.max(...colWidths);
|
||||||
|
});
|
||||||
|
return widthsByColumnKey;
|
||||||
|
}
|
||||||
|
|
||||||
|
fitTableToWidthIfNeeded() {
|
||||||
|
const containerWidth = this.container.getBoundingClientRect().width;
|
||||||
|
if (containerWidth > this.totalTableWidth) {
|
||||||
|
this.totalTableWidth = containerWidth - 2; // accomodates 1px border on container
|
||||||
|
}
|
||||||
|
this.setState({ fitted: true });
|
||||||
|
}
|
||||||
|
|
||||||
|
formatTableData(data) {
|
||||||
|
const formattedData = data.map((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;
|
||||||
|
});
|
||||||
|
return formattedData;
|
||||||
|
}
|
||||||
|
|
||||||
|
hasMatch(text, row) {
|
||||||
|
const values = [];
|
||||||
|
for (const key in row) {
|
||||||
|
if (row.hasOwnProperty(key)) {
|
||||||
|
values.push(row[key].toLowerCase());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return values.some(v => v.includes(text.toLowerCase()));
|
||||||
|
}
|
||||||
|
|
||||||
|
headerRenderer({ dataKey, label, sortBy, sortDirection }) {
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
{label}
|
||||||
|
{sortBy === dataKey &&
|
||||||
|
<SortIndicator sortDirection={sortDirection} />
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
rowClassName({ index }) {
|
||||||
|
let className = '';
|
||||||
|
if (this.props.striped) {
|
||||||
|
className = index % 2 === 0 ? 'even-row' : 'odd-row';
|
||||||
|
}
|
||||||
|
return className;
|
||||||
|
}
|
||||||
|
|
||||||
|
sort({ sortBy, sortDirection }) {
|
||||||
|
this.setState({ sortBy, sortDirection });
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
const { sortBy, sortDirection } = this.state;
|
||||||
|
const {
|
||||||
|
filterText,
|
||||||
|
headerHeight,
|
||||||
|
height,
|
||||||
|
orderedColumnKeys,
|
||||||
|
overscanRowCount,
|
||||||
|
rowHeight,
|
||||||
|
} = this.props;
|
||||||
|
|
||||||
|
let sortedAndFilteredList = this.list;
|
||||||
|
// filter list
|
||||||
|
if (filterText) {
|
||||||
|
sortedAndFilteredList = this.list.filter(row => this.hasMatch(filterText, row));
|
||||||
|
}
|
||||||
|
// sort list
|
||||||
|
sortedAndFilteredList = sortedAndFilteredList
|
||||||
|
.sortBy(item => item[sortBy])
|
||||||
|
.update(list => sortDirection === SortDirection.DESC ? list.reverse() : list);
|
||||||
|
|
||||||
|
const rowGetter = ({ index }) => this.getDatum(sortedAndFilteredList, index);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
style={{ height }}
|
||||||
|
className="filterable-table-container"
|
||||||
|
ref={(ref) => { this.container = ref; }}
|
||||||
|
>
|
||||||
|
{this.state.fitted &&
|
||||||
|
<Table
|
||||||
|
ref="Table"
|
||||||
|
headerHeight={headerHeight}
|
||||||
|
height={height - 2}
|
||||||
|
overscanRowCount={overscanRowCount}
|
||||||
|
rowClassName={this.rowClassName}
|
||||||
|
rowHeight={rowHeight}
|
||||||
|
rowGetter={rowGetter}
|
||||||
|
rowCount={sortedAndFilteredList.size}
|
||||||
|
sort={this.sort}
|
||||||
|
sortBy={sortBy}
|
||||||
|
sortDirection={sortDirection}
|
||||||
|
width={this.totalTableWidth}
|
||||||
|
>
|
||||||
|
{orderedColumnKeys.map(columnKey => (
|
||||||
|
<Column
|
||||||
|
dataKey={columnKey}
|
||||||
|
disableSort={false}
|
||||||
|
headerRenderer={this.headerRenderer}
|
||||||
|
width={this.widthsForColumnsByKey[columnKey]}
|
||||||
|
label={columnKey}
|
||||||
|
key={columnKey}
|
||||||
|
/>
|
||||||
|
))}
|
||||||
|
</Table>
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
FilterableTable.propTypes = propTypes;
|
||||||
|
FilterableTable.defaultProps = defaultProps;
|
@ -0,0 +1,60 @@
|
|||||||
|
.ReactVirtualized__Table__headerRow {
|
||||||
|
font-weight: 700;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
.ReactVirtualized__Table__row {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
}
|
||||||
|
.ReactVirtualized__Table__headerTruncatedText {
|
||||||
|
display: inline-block;
|
||||||
|
max-width: 100%;
|
||||||
|
white-space: nowrap;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
.ReactVirtualized__Table__headerColumn,
|
||||||
|
.ReactVirtualized__Table__rowColumn {
|
||||||
|
min-width: 0px;
|
||||||
|
border-right: 1px solid #ccc;
|
||||||
|
align-self: center;
|
||||||
|
padding: 12px;
|
||||||
|
font-size: 12px;
|
||||||
|
}
|
||||||
|
.ReactVirtualized__Table__headerColumn:last-of-type,
|
||||||
|
.ReactVirtualized__Table__rowColumn:last-of-type {
|
||||||
|
border-right: 0px;
|
||||||
|
}
|
||||||
|
.ReactVirtualized__Table__headerColumn:focus,
|
||||||
|
.ReactVirtualized__Table__Grid:focus {
|
||||||
|
outline: none;
|
||||||
|
}
|
||||||
|
.ReactVirtualized__Table__rowColumn {
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
.ReactVirtualized__Table__sortableHeaderColumn {
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
.ReactVirtualized__Table__sortableHeaderIconContainer {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
.ReactVirtualized__Table__sortableHeaderIcon {
|
||||||
|
flex: 0 0 24px;
|
||||||
|
height: 1em;
|
||||||
|
width: 1em;
|
||||||
|
fill: currentColor;
|
||||||
|
}
|
||||||
|
.even-row { background: #f2f2f2; }
|
||||||
|
.odd-row { background: #ffffff; }
|
||||||
|
.even-row,
|
||||||
|
.odd-row {
|
||||||
|
border: none;
|
||||||
|
}
|
||||||
|
.filterable-table-container {
|
||||||
|
overflow: auto;
|
||||||
|
border: 1px solid #ccc;
|
||||||
|
}
|
11
superset/assets/javascripts/modules/visUtils.js
Normal file
11
superset/assets/javascripts/modules/visUtils.js
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
export function getTextWidth(text, fontDetails = '12px Roboto') {
|
||||||
|
const canvas = document.createElement('canvas');
|
||||||
|
const context = canvas.getContext('2d');
|
||||||
|
context.font = fontDetails;
|
||||||
|
const metrics = context.measureText(text);
|
||||||
|
return metrics.width;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default {
|
||||||
|
getTextWidth,
|
||||||
|
};
|
@ -84,6 +84,7 @@
|
|||||||
"react-select-fast-filter-options": "^0.2.1",
|
"react-select-fast-filter-options": "^0.2.1",
|
||||||
"react-syntax-highlighter": "^5.0.0",
|
"react-syntax-highlighter": "^5.0.0",
|
||||||
"react-virtualized-select": "^2.4.0",
|
"react-virtualized-select": "^2.4.0",
|
||||||
|
"react-virtualized": "^9.3.0",
|
||||||
"reactable": "^0.14.0",
|
"reactable": "^0.14.0",
|
||||||
"redux": "^3.5.2",
|
"redux": "^3.5.2",
|
||||||
"redux-localstorage": "^0.4.1",
|
"redux-localstorage": "^0.4.1",
|
||||||
|
@ -0,0 +1,10 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import { describe, it } from 'mocha';
|
||||||
|
import { expect } from 'chai';
|
||||||
|
import FilterableTable from '../../../../javascripts/components/FilterableTable/FilterableTable';
|
||||||
|
|
||||||
|
describe('FilterableTable', () => {
|
||||||
|
it('is valid element', () => {
|
||||||
|
expect(React.isValidElement(<FilterableTable />)).to.equal(true);
|
||||||
|
});
|
||||||
|
});
|
@ -2,8 +2,7 @@ import React from 'react';
|
|||||||
import { shallow } from 'enzyme';
|
import { shallow } from 'enzyme';
|
||||||
import { describe, it } from 'mocha';
|
import { describe, it } from 'mocha';
|
||||||
import { expect } from 'chai';
|
import { expect } from 'chai';
|
||||||
import { Table } from 'reactable';
|
import FilterableTable from '../../../javascripts/components/FilterableTable/FilterableTable';
|
||||||
|
|
||||||
import ResultSet from '../../../javascripts/SqlLab/components/ResultSet';
|
import ResultSet from '../../../javascripts/SqlLab/components/ResultSet';
|
||||||
import { queries } from './fixtures';
|
import { queries } from './fixtures';
|
||||||
|
|
||||||
@ -21,6 +20,6 @@ describe('ResultSet', () => {
|
|||||||
});
|
});
|
||||||
it('renders a Table', () => {
|
it('renders a Table', () => {
|
||||||
const wrapper = shallow(<ResultSet {...mockedProps} />);
|
const wrapper = shallow(<ResultSet {...mockedProps} />);
|
||||||
expect(wrapper.find(Table)).to.have.length(1);
|
expect(wrapper.find(FilterableTable)).to.have.length(1);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -91,7 +91,6 @@
|
|||||||
@import "../../node_modules/react-select/less/mixins.less";
|
@import "../../node_modules/react-select/less/mixins.less";
|
||||||
@import "../../node_modules/react-select/less/multi.less";
|
@import "../../node_modules/react-select/less/multi.less";
|
||||||
@import "../../node_modules/react-select/less/spinner.less";
|
@import "../../node_modules/react-select/less/spinner.less";
|
||||||
@import "../../node_modules/react-virtualized/styles.css";
|
|
||||||
|
|
||||||
// importing css from "../../node_modules/react-virtualized-select/styles.css";
|
// importing css from "../../node_modules/react-virtualized-select/styles.css";
|
||||||
// so the background color of a selected option matches the other selects
|
// so the background color of a selected option matches the other selects
|
||||||
|
Loading…
Reference in New Issue
Block a user