Add InfiniteLoader to fetch rows as needed

This commit is contained in:
Marliana Lara
2019-07-22 13:23:31 -04:00
parent 40560e962f
commit 161c7706bc

View File

@@ -3,6 +3,7 @@ import {
AutoSizer, AutoSizer,
CellMeasurer, CellMeasurer,
CellMeasurerCache, CellMeasurerCache,
InfiniteLoader,
List, List,
} from 'react-virtualized'; } from 'react-virtualized';
@@ -47,8 +48,10 @@ class JobOutput extends Component {
hasContentLoading: true, hasContentLoading: true,
results: [], results: [],
scrollToIndex: -1, scrollToIndex: -1,
startIndex: 0, loadedRowCount: 0,
stopIndex: 0, loadedRowsMap: {},
loadingRowCount: 0,
remoteRowCount: 0,
}; };
this.cache = new CellMeasurerCache({ this.cache = new CellMeasurerCache({
@@ -57,13 +60,14 @@ class JobOutput extends Component {
}); });
this.loadJobEvents = this.loadJobEvents.bind(this); this.loadJobEvents = this.loadJobEvents.bind(this);
this.renderRow = this.renderRow.bind(this); this.rowRenderer = this.rowRenderer.bind(this);
this.handleScrollTop = this.handleScrollTop.bind(this); this.handleScrollTop = this.handleScrollTop.bind(this);
this.handleScrollBottom = this.handleScrollBottom.bind(this); this.handleScrollBottom = this.handleScrollBottom.bind(this);
this.handleScrollNext = this.handleScrollNext.bind(this); this.handleScrollNext = this.handleScrollNext.bind(this);
this.handleScrollPrevious = this.handleScrollPrevious.bind(this); this.handleScrollPrevious = this.handleScrollPrevious.bind(this);
this.handleResize = this.handleResize.bind(this); this.handleResize = this.handleResize.bind(this);
this.onRowsRendered = this.onRowsRendered.bind(this); this.isRowLoaded = this.isRowLoaded.bind(this);
this.loadMoreRows = this.loadMoreRows.bind(this);
} }
componentDidMount() { componentDidMount() {
@@ -76,12 +80,12 @@ class JobOutput extends Component {
this.setState({ hasContentLoading: true }); this.setState({ hasContentLoading: true });
try { try {
const { const {
data: { results = [] }, data: { results = [], count },
} = await JobsAPI.readEvents(job.id, job.type, { } = await JobsAPI.readEvents(job.id, job.type, {
page_size: 200, page_size: 50,
order_by: 'start_line', order_by: 'start_line',
}); });
this.setState({ results }); this.setState({ results, remoteRowCount: count + 1 });
} catch (err) { } catch (err) {
this.setState({ contentError: err }); this.setState({ contentError: err });
} finally { } finally {
@@ -89,8 +93,16 @@ class JobOutput extends Component {
} }
} }
renderRow({ index, parent, key, style }) { isRowLoaded({ index }) {
const { results } = this.state; const { results } = this.state;
return !!results[index];
}
rowRenderer({ index, parent, key, style }) {
const { results } = this.state;
if (!results[index]) {
return;
}
const { created, event, stdout, start_line } = results[index]; const { created, event, stdout, start_line } = results[index];
return ( return (
<CellMeasurer <CellMeasurer
@@ -112,34 +124,46 @@ class JobOutput extends Component {
); );
} }
onRowsRendered({ startIndex, stopIndex }) { async loadMoreRows({ startIndex, stopIndex }) {
this.setState({ startIndex, stopIndex }); const { job } = this.props;
const { results } = this.state;
let params = {
counter__gte: startIndex,
counter__lte: stopIndex,
order_by: 'start_line',
};
return await JobsAPI.readEvents(job.id, job.type, params).then(response => {
this.setState({ results: [...results, ...response.data.results] });
});
} }
handleScrollPrevious() { handleScrollPrevious() {
const { startIndex, stopIndex } = this.state; const startIndex = this.listRef.Grid._renderedRowStartIndex;
const index = startIndex - (stopIndex - startIndex); const stopIndex = this.listRef.Grid._renderedRowStopIndex;
this.setState({ scrollToIndex: Math.max(0, index) }); const range = stopIndex - startIndex + 1;
this.listRef.scrollToRow(Math.max(0, startIndex - range));
} }
handleScrollNext() { handleScrollNext() {
const { stopIndex } = this.state; const stopIndex = this.listRef.Grid._renderedRowStopIndex;
this.setState({ scrollToIndex: stopIndex + 1 }); this.listRef.scrollToRow(stopIndex - 1);
} }
handleScrollTop() { handleScrollTop() {
this.setState({ scrollToIndex: 0 }); this.listRef.scrollToRow(0);
} }
handleScrollBottom() { handleScrollBottom() {
const { results } = this.state; const { remoteRowCount } = this.state;
this.setState({ scrollToIndex: results.length - 1 }); this.listRef.scrollToRow(remoteRowCount - 1);
} }
handleResize({ width }) { handleResize({ width }) {
if (width !== this._previousWidth) { if (width !== this._previousWidth) {
this.cache.clearAll(); this.cache.clearAll();
this.listRef.current.recomputeRowHeights(); this.listRef.recomputeRowHeights();
} }
this._previousWidth = width; this._previousWidth = width;
} }
@@ -147,12 +171,10 @@ class JobOutput extends Component {
render() { render() {
const { job } = this.props; const { job } = this.props;
const { const {
results,
hasContentLoading, hasContentLoading,
contentError, contentError,
scrollToIndex, scrollToIndex,
startIndex, remoteRowCount,
stopIndex,
} = this.state; } = this.state;
if (hasContentLoading) { if (hasContentLoading) {
@@ -175,28 +197,35 @@ class JobOutput extends Component {
/> />
</OutputToolbar> </OutputToolbar>
<OutputWrapper> <OutputWrapper>
<AutoSizer onResize={this.handleResize}> <InfiniteLoader
{({ width, height }) => { isRowLoaded={this.isRowLoaded}
console.log('scroll to index', scrollToIndex); loadMoreRows={this.loadMoreRows}
console.log('start index', startIndex); rowCount={remoteRowCount}
console.log('stop index', stopIndex); >
return ( {({ onRowsRendered, registerChild }) => (
<List <AutoSizer onResize={this.handleResize}>
ref={this.listRef} {({ width, height }) => {
width={width} return (
height={height} <List
deferredMeasurementCache={this.cache} ref={ref => {
rowHeight={this.cache.rowHeight} this.listRef = ref;
rowRenderer={this.renderRow} registerChild(ref);
rowCount={results.length} }}
overscanRowCount={50} deferredMeasurementCache={this.cache}
scrollToIndex={scrollToIndex} height={height}
onRowsRendered={this.onRowsRendered} onRowsRendered={onRowsRendered}
scrollToAlignment="start" rowCount={remoteRowCount}
/> rowHeight={this.cache.rowHeight}
); rowRenderer={this.rowRenderer}
}} scrollToAlignment="start"
</AutoSizer> scrollToIndex={scrollToIndex}
width={width}
/>
);
}}
</AutoSizer>
)}
</InfiniteLoader>
<OutputFooter /> <OutputFooter />
</OutputWrapper> </OutputWrapper>
</CardBody> </CardBody>