1
0
mirror of https://github.com/mattermost/focalboard.git synced 2024-11-27 08:31:20 +02:00

Fix #569: Show websocket connection error banner (#570)

* Fix #569: Show websocket connection error banner

* Update fwlink
This commit is contained in:
Chen-I Lim 2021-06-13 16:22:45 -07:00 committed by GitHub
parent 521be8f94d
commit 1cc2337948
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 54 additions and 2 deletions

View File

@ -19,6 +19,7 @@ type WSMessage = {
}
type OnChangeHandler = (blocks: IBlock[]) => void
type OnStateChange = (state: 'open' | 'close') => void
//
// OctoListener calls a handler when a block or any of its children changes
@ -56,7 +57,7 @@ class OctoListener {
return readToken
}
open(workspaceId: string, blockIds: string[], onChange: OnChangeHandler, onReconnect: () => void): void {
open(workspaceId: string, blockIds: string[], onChange: OnChangeHandler, onReconnect: () => void, onStateChange?: OnStateChange): void {
if (this.ws) {
this.close()
}
@ -76,6 +77,7 @@ class OctoListener {
this.authenticate(workspaceId)
this.addBlocks(blockIds)
this.isInitialized = true
onStateChange?.('open')
}
ws.onerror = (e) => {
@ -88,6 +90,7 @@ class OctoListener {
// Unexpected close, re-open
const reopenBlockIds = this.isInitialized ? this.blockIds.slice() : blockIds.slice()
Utils.logError(`Unexpected close, re-opening with ${reopenBlockIds.length} blocks...`)
onStateChange?.('close')
setTimeout(() => {
this.open(workspaceId, reopenBlockIds, onChange, onReconnect)
onReconnect()

View File

@ -4,4 +4,14 @@
text-align: center;
padding: 10px;
}
> .banner {
background-color: rgba(230, 220, 192, 0.9);
text-align: center;
padding: 10px;
}
> .banner.error {
background-color: rgba(230, 192, 192, 0.9);
}
}

View File

@ -1,7 +1,7 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import React from 'react'
import {injectIntl, IntlShape} from 'react-intl'
import {FormattedMessage, injectIntl, IntlShape} from 'react-intl'
import {withRouter, RouteComponentProps} from 'react-router-dom'
import HotKeys from 'react-hot-keys'
@ -30,6 +30,8 @@ type State = {
workspaceTree: WorkspaceTree
boardTree?: BoardTree
syncFailed?: boolean
websocketClosedTimeOutId?: ReturnType<typeof setTimeout>
websocketClosed?: boolean
workspaceUsers: WorkspaceUsersContextData
}
@ -193,6 +195,21 @@ class BoardPage extends React.Component<Props, State> {
keyName='shift+ctrl+z,shift+cmd+z,ctrl+z,cmd+z'
onKeyDown={this.undoRedoHandler}
/>
{(this.state.websocketClosed) &&
<div className='banner error'>
<a
href='https://www.focalboard.com/fwlink/websocket-connect-error.html'
target='_blank'
rel='noreferrer'
>
<FormattedMessage
id='Error.websocket-closed'
defaultMessage='Websocket connection closed, connection interrupted. If this persists, check your server or web proxy configuration.'
/>
</a>
</div>
}
<Workspace
workspace={workspace}
workspaceTree={workspaceTree}
@ -266,6 +283,28 @@ class BoardPage extends React.Component<Props, State> {
Utils.log('workspaceListener.onReconnect')
this.sync()
},
(state) => {
switch (state) {
case 'close': {
// Show error after a delay to ignore brief interruptions
if (!this.state.websocketClosed && !this.state.websocketClosedTimeOutId) {
const timeoutId = setTimeout(() => {
this.setState({websocketClosed: true, websocketClosedTimeOutId: undefined})
}, 5000)
this.setState({websocketClosedTimeOutId: timeoutId})
}
break
}
case 'open': {
if (this.state.websocketClosedTimeOutId) {
clearTimeout(this.state.websocketClosedTimeOutId)
}
this.setState({websocketClosed: false, websocketClosedTimeOutId: undefined})
Utils.log('Connection established')
break
}
}
},
)
if (boardId) {