Add infinite scroll component. Use for Alerts Table and Tickscript Logs.
parent
10b2d56201
commit
60a3624cd5
|
@ -5,7 +5,7 @@ import classnames from 'classnames'
|
|||
import {Link} from 'react-router'
|
||||
import uuid from 'node-uuid'
|
||||
|
||||
import FancyScrollbar from 'shared/components/FancyScrollbar'
|
||||
import InfiniteScroll from 'shared/components/InfiniteScroll'
|
||||
|
||||
import {ALERTS_TABLE} from 'src/alerts/constants/tableSizing'
|
||||
|
||||
|
@ -117,11 +117,10 @@ class AlertsTable extends Component {
|
|||
Value
|
||||
</div>
|
||||
</div>
|
||||
<FancyScrollbar
|
||||
<InfiniteScroll
|
||||
className="alert-history-table--tbody"
|
||||
autoHide={false}
|
||||
>
|
||||
{alerts.map(({name, level, time, host, value}) => {
|
||||
itemHeight={25}
|
||||
items={alerts.map(({name, level, time, host, value}) => {
|
||||
return (
|
||||
<div className="alert-history-table--tr" key={uuid.v4()}>
|
||||
<div
|
||||
|
@ -165,7 +164,7 @@ class AlertsTable extends Component {
|
|||
</div>
|
||||
)
|
||||
})}
|
||||
</FancyScrollbar>
|
||||
/>
|
||||
</div>
|
||||
: this.renderTableEmpty()
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import React, {PropTypes} from 'react'
|
||||
|
||||
import FancyScrollbar from 'shared/components/FancyScrollbar'
|
||||
import InfiniteScroll from 'shared/components/InfiniteScroll'
|
||||
import LogsTableRow from 'src/kapacitor/components/LogsTableRow'
|
||||
|
||||
const LogsTable = ({logs}) =>
|
||||
|
@ -8,18 +8,17 @@ const LogsTable = ({logs}) =>
|
|||
<div className="logs-table--header">
|
||||
<h2 className="panel-title">Logs</h2>
|
||||
</div>
|
||||
<FancyScrollbar
|
||||
className="logs-table--panel fancy-scroll--kapacitor"
|
||||
autoHide={false}
|
||||
>
|
||||
<div className="logs-table">
|
||||
{logs.length
|
||||
? logs.map((log, i) =>
|
||||
<div className="logs-table--panel fancy-scroll--kapacitor">
|
||||
{logs.length
|
||||
? <InfiniteScroll
|
||||
className="logs-table"
|
||||
itemHeight={87}
|
||||
items={logs.map((log, i) =>
|
||||
<LogsTableRow key={log.key} logItem={log} index={i} />
|
||||
)
|
||||
: <div className="page-spinner" />}
|
||||
</div>
|
||||
</FancyScrollbar>
|
||||
)}
|
||||
/>
|
||||
: <div className="page-spinner" />}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
const {arrayOf, shape, string} = PropTypes
|
||||
|
|
|
@ -101,13 +101,13 @@ class TickscriptPage extends Component {
|
|||
}
|
||||
|
||||
this.setState({
|
||||
logs: [...this.state.logs, ...logs],
|
||||
logs: [...logs, ...this.state.logs],
|
||||
failStr,
|
||||
})
|
||||
} catch (err) {
|
||||
console.warn(err, failStr)
|
||||
this.setState({
|
||||
logs: [...this.state.logs, ...logs],
|
||||
logs: [...logs, ...this.state.logs],
|
||||
failStr,
|
||||
})
|
||||
}
|
||||
|
|
|
@ -0,0 +1,104 @@
|
|||
import React, {Component, PropTypes} from 'react'
|
||||
|
||||
const {arrayOf, number, shape, string} = PropTypes
|
||||
|
||||
class InfiniteScroll extends Component {
|
||||
scrollElement
|
||||
|
||||
// Cache values that need to be independent of
|
||||
// Should not be setState as need not trigger a re-render
|
||||
scrollTop = 0
|
||||
containerHeight = 0
|
||||
|
||||
static propTypes = {
|
||||
itemHeight: number.isRequired,
|
||||
items: arrayOf(shape()).isRequired,
|
||||
className: string,
|
||||
}
|
||||
|
||||
state = {
|
||||
topIndex: 0,
|
||||
bottomIndex: 0,
|
||||
topPadding: 0,
|
||||
bottomPadding: 0,
|
||||
}
|
||||
|
||||
windowing = props => {
|
||||
const {itemHeight, items} = props
|
||||
const {bottomIndex} = this.state
|
||||
|
||||
const itemDistance = Math.round(this.scrollTop / itemHeight)
|
||||
const itemCount = Math.round(this.containerHeight / itemHeight)
|
||||
|
||||
console.log(this.containerHeight)
|
||||
console.log(itemDistance, itemCount)
|
||||
|
||||
// If state is the same, do not setState to the same value multiple times.
|
||||
// Improves performance and prevents errors.
|
||||
if (bottomIndex === itemDistance + itemCount) {
|
||||
return
|
||||
}
|
||||
|
||||
this.setState({
|
||||
// Number of items from top
|
||||
topIndex: itemDistance,
|
||||
// Number of items that can fit inside the container div
|
||||
bottomIndex: itemDistance + itemCount,
|
||||
// Offset list from top
|
||||
topPadding: itemDistance * itemHeight,
|
||||
// Provide scrolling room at the bottom of the list
|
||||
bottomPadding: (items.length - itemDistance - itemCount) * itemHeight,
|
||||
})
|
||||
}
|
||||
|
||||
handleScroll = evt => {
|
||||
if (evt.target === this.scrollElement) {
|
||||
this.scrollTop = evt.target.scrollTop
|
||||
this.windowing(this.props)
|
||||
}
|
||||
}
|
||||
|
||||
handleResize = () => {
|
||||
this.containerHeight = this.scrollElement.clientHeight
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
this.containerHeight = this.scrollElement.clientHeight
|
||||
this.windowing(this.props)
|
||||
|
||||
window.addEventListener('scroll', this.handleScroll, true)
|
||||
window.addEventListener('resize', this.handleResize, true)
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
window.removeEventListener('scroll', this.handleScroll, true)
|
||||
window.removeEventListener('resize', this.handleResize, true)
|
||||
}
|
||||
|
||||
componentWillReceiveProps(nextProps) {
|
||||
console.log(nextProps)
|
||||
// Updates values if new items are added
|
||||
this.windowing(nextProps)
|
||||
}
|
||||
|
||||
render() {
|
||||
const {className, items} = this.props
|
||||
const {topIndex, bottomIndex, topPadding, bottomPadding} = this.state
|
||||
console.log(items.length)
|
||||
return (
|
||||
<div
|
||||
className={className}
|
||||
ref={r => (this.scrollElement = r)}
|
||||
style={{
|
||||
overflowY: 'scroll',
|
||||
}}
|
||||
>
|
||||
<div style={{height: topPadding}} />
|
||||
{items.filter((_item, i) => i >= topIndex && i <= bottomIndex)}
|
||||
<div style={{height: bottomPadding}} />
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
export default InfiniteScroll
|
|
@ -32,12 +32,6 @@ $logs-margin: 4px;
|
|||
height: calc(100% - #{$logs-table-header-height}) !important;
|
||||
}
|
||||
|
||||
.logs-table,
|
||||
.logs-table--row {
|
||||
display: flex;
|
||||
align-items: stretch;
|
||||
flex-direction: column;
|
||||
}
|
||||
@keyframes LogsFadeIn {
|
||||
from {
|
||||
background-color: $g6-smoke;
|
||||
|
@ -47,9 +41,10 @@ $logs-margin: 4px;
|
|||
}
|
||||
}
|
||||
.logs-table {
|
||||
flex-direction: column-reverse;
|
||||
height: 100%;
|
||||
}
|
||||
.logs-table--row {
|
||||
height: 87px; // Fixed height, required for Infinite Scroll, allows for 2 tags / fields per line
|
||||
padding: 8px ($logs-table-padding - 16px) 8px ($logs-table-padding / 2);
|
||||
border-bottom: 2px solid $g3-castle;
|
||||
animation-name: LogsFadeIn;
|
||||
|
|
|
@ -234,7 +234,7 @@ $table-tab-scrollbar-height: 6px;
|
|||
color: $g17-whisper;
|
||||
}
|
||||
.alert-history-table--tbody {
|
||||
flex: 1 0 0%;
|
||||
flex: 1 0 0;
|
||||
width: 100%;
|
||||
}
|
||||
.alert-history-table--tr {
|
||||
|
|
Loading…
Reference in New Issue