Fix log live updating and add autoscrolling

This commit is contained in:
Tulir Asokan 2018-11-29 12:27:31 +02:00
parent b858b5a056
commit 2b8a5353be
3 changed files with 55 additions and 9 deletions

View File

@ -113,13 +113,57 @@ class LogEntry extends PureComponent {
} }
class Log extends PureComponent { class Log extends PureComponent {
constructor(props) {
super(props)
this.linesRef = React.createRef()
this.linesBottomRef = React.createRef()
}
getSnapshotBeforeUpdate() {
if (this.linesRef.current && this.linesBottomRef.current) {
return Log.isVisible(this.linesRef.current, this.linesBottomRef.current)
}
return false
}
componentDidUpdate(_1, _2, wasVisible) {
if (wasVisible) {
Log.scrollParentToChild(this.linesRef.current, this.linesBottomRef.current)
}
}
componentDidMount() {
if (this.linesRef.current && this.linesBottomRef.current) {
Log.scrollParentToChild(this.linesRef.current, this.linesBottomRef.current)
}
}
static scrollParentToChild(parent, child) {
const parentRect = parent.getBoundingClientRect()
const childRect = child.getBoundingClientRect()
if (!Log.isVisible(parent, child)) {
parent.scrollBy({ top: (childRect.top + parent.scrollTop) - parentRect.top })
}
}
static isVisible(parent, child) {
const parentRect = parent.getBoundingClientRect()
const childRect = child.getBoundingClientRect()
return (childRect.top >= parentRect.top)
&& (childRect.top <= parentRect.top + parent.clientHeight)
}
render() { render() {
return ( return (
<div className="log"> <div className="log" ref={this.linesRef}>
<div className="lines"> <div className="lines">
{this.props.lines.map(data => <LogEntry key={data.id} line={data} {this.props.lines.map(data => <LogEntry key={data.id} line={data}
focus={this.props.focus}/>)} focus={this.props.focus}/>)}
</div> </div>
<div ref={this.linesBottomRef}/>
</div> </div>
) )
} }

View File

@ -30,6 +30,7 @@ class Modal extends Component {
open = () => this.setState({ open: true }) open = () => this.setState({ open: true })
close = () => this.setState({ open: false }) close = () => this.setState({ open: false })
isOpen = () => this.state.open
render() { render() {
return this.state.open && ( return this.state.open && (

View File

@ -34,11 +34,11 @@ class Dashboard extends Component {
sidebarOpen: false, sidebarOpen: false,
modalOpen: false, modalOpen: false,
logFocus: null, logFocus: null,
logLines: [],
} }
this.logLines = []
this.logMap = {}
this.logModal = { this.logModal = {
open: () => undefined, open: () => undefined,
isOpen: () => false,
} }
window.maubot = this window.maubot = this
} }
@ -80,20 +80,21 @@ class Dashboard extends Component {
} else if (entry.name.startsWith("instance.")) { } else if (entry.name.startsWith("instance.")) {
entry.nameLink = `/instance/${entry.name.substr("instance.".length)}` entry.nameLink = `/instance/${entry.name.substr("instance.".length)}`
} }
(this.logMap[entry.name] || (this.logMap[entry.name] = [])).push(entry)
} }
logs.onHistory = history => { logs.onHistory = history => {
for (const data of history) { for (const data of history) {
processEntry(data) processEntry(data)
} }
this.logLines = history this.setState({
this.setState({ logFocus: this.state.logFocus }) logLines: history,
})
} }
logs.onLog = data => { logs.onLog = data => {
processEntry(data) processEntry(data)
this.logLines.push(data) this.setState({
this.setState({ logFocus: this.state.logFocus }) logLines: this.state.logLines.concat(data),
})
} }
} }
@ -209,7 +210,7 @@ class Dashboard extends Component {
renderModal() { renderModal() {
return <Modal ref={ref => this.logModal = ref}> return <Modal ref={ref => this.logModal = ref}>
<Log lines={this.logLines} focus={this.state.logFocus}/> <Log lines={this.state.logLines} focus={this.state.logFocus}/>
</Modal> </Modal>
} }