Show a refresh banner on plugin update (#1720)
* Reload plugin on plugin update * Add a banner that shows when updating the plugin and asks the user to reload * Fix linter
This commit is contained in:
parent
1160477849
commit
3ede6df028
6 changed files with 68 additions and 0 deletions
|
@ -182,6 +182,7 @@ export default class Plugin {
|
||||||
// register websocket handlers
|
// register websocket handlers
|
||||||
this.registry?.registerWebSocketEventHandler(`custom_${manifest.id}_${ACTION_UPDATE_BLOCK}`, (e: any) => wsClient.updateBlockHandler(e.data))
|
this.registry?.registerWebSocketEventHandler(`custom_${manifest.id}_${ACTION_UPDATE_BLOCK}`, (e: any) => wsClient.updateBlockHandler(e.data))
|
||||||
this.registry?.registerWebSocketEventHandler(`custom_${manifest.id}_${ACTION_UPDATE_CLIENT_CONFIG}`, (e: any) => wsClient.updateClientConfigHandler(e.data))
|
this.registry?.registerWebSocketEventHandler(`custom_${manifest.id}_${ACTION_UPDATE_CLIENT_CONFIG}`, (e: any) => wsClient.updateClientConfigHandler(e.data))
|
||||||
|
this.registry?.registerWebSocketEventHandler(`plugin_statuses_changed`, (e: any) => wsClient.pluginStatusesChangedHandler(e.data))
|
||||||
this.registry?.registerWebSocketEventHandler('preferences_changed', (e: any) => {
|
this.registry?.registerWebSocketEventHandler('preferences_changed', (e: any) => {
|
||||||
let preferences
|
let preferences
|
||||||
try {
|
try {
|
||||||
|
|
|
@ -8,6 +8,7 @@
|
||||||
"BoardComponent.no-property-title": "Items with an empty {property} property will go here. This column cannot be removed.",
|
"BoardComponent.no-property-title": "Items with an empty {property} property will go here. This column cannot be removed.",
|
||||||
"BoardComponent.show": "Show",
|
"BoardComponent.show": "Show",
|
||||||
"BoardPage.syncFailed": "Board may be deleted or access revoked.",
|
"BoardPage.syncFailed": "Board may be deleted or access revoked.",
|
||||||
|
"BoardPage.newVersion": "A new version of Boards is available, click here to reload.",
|
||||||
"Calculations.Options.average.displayName": "Average",
|
"Calculations.Options.average.displayName": "Average",
|
||||||
"Calculations.Options.average.label": "Average",
|
"Calculations.Options.average.label": "Average",
|
||||||
"Calculations.Options.count.displayName": "Count",
|
"Calculations.Options.count.displayName": "Count",
|
||||||
|
|
|
@ -19,6 +19,7 @@ import TelemetryClient from './telemetry/telemetryClient'
|
||||||
import {IAppWindow} from './types'
|
import {IAppWindow} from './types'
|
||||||
import {getMessages} from './i18n'
|
import {getMessages} from './i18n'
|
||||||
import {FlashMessages} from './components/flashMessages'
|
import {FlashMessages} from './components/flashMessages'
|
||||||
|
import NewVersionBanner from './components/newVersionBanner'
|
||||||
import BoardPage from './pages/boardPage'
|
import BoardPage from './pages/boardPage'
|
||||||
import ChangePasswordPage from './pages/changePasswordPage'
|
import ChangePasswordPage from './pages/changePasswordPage'
|
||||||
import DashboardPage from './pages/dashboard/dashboardPage'
|
import DashboardPage from './pages/dashboard/dashboardPage'
|
||||||
|
@ -141,6 +142,7 @@ const App = React.memo((): JSX.Element => {
|
||||||
>
|
>
|
||||||
<div id='frame'>
|
<div id='frame'>
|
||||||
<div id='main'>
|
<div id='main'>
|
||||||
|
<NewVersionBanner/>
|
||||||
<Switch>
|
<Switch>
|
||||||
{globalErrorRedirect}
|
{globalErrorRedirect}
|
||||||
<Route path='/error'>
|
<Route path='/error'>
|
||||||
|
|
5
webapp/src/components/newVersionBanner.scss
Normal file
5
webapp/src/components/newVersionBanner.scss
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
.NewVersionBanner {
|
||||||
|
background-color: var(--prop-blue);
|
||||||
|
text-align: center;
|
||||||
|
padding: 10px;
|
||||||
|
}
|
41
webapp/src/components/newVersionBanner.tsx
Normal file
41
webapp/src/components/newVersionBanner.tsx
Normal file
|
@ -0,0 +1,41 @@
|
||||||
|
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||||
|
// See LICENSE.txt for license information.
|
||||||
|
import React, {useState, useEffect} from 'react'
|
||||||
|
import {FormattedMessage} from 'react-intl'
|
||||||
|
|
||||||
|
import wsClient from '../wsclient'
|
||||||
|
|
||||||
|
import './newVersionBanner.scss'
|
||||||
|
|
||||||
|
const NewVersionBanner = () => {
|
||||||
|
const [appVersionChanged, setAppVersionChanged] = useState(false)
|
||||||
|
useEffect(() => {
|
||||||
|
wsClient.onAppVersionChangeHandler = setAppVersionChanged
|
||||||
|
}, [])
|
||||||
|
|
||||||
|
if (!appVersionChanged) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
const newVersionReload = (e: any) => {
|
||||||
|
e.preventDefault()
|
||||||
|
location.reload()
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className='NewVersionBanner'>
|
||||||
|
<a
|
||||||
|
target='_blank'
|
||||||
|
rel='noreferrer'
|
||||||
|
onClick={newVersionReload}
|
||||||
|
>
|
||||||
|
<FormattedMessage
|
||||||
|
id='BoardPage.newVersion'
|
||||||
|
defaultMessage='A new version of Boards is available, click here to reload.'
|
||||||
|
/>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default NewVersionBanner
|
|
@ -49,6 +49,8 @@ type OnConfigChangeHandler = (client: WSClient, clientConfig: ClientConfig) => v
|
||||||
class WSClient {
|
class WSClient {
|
||||||
ws: WebSocket|null = null
|
ws: WebSocket|null = null
|
||||||
client: MMWebSocketClient|null = null
|
client: MMWebSocketClient|null = null
|
||||||
|
pluginId = ''
|
||||||
|
onAppVersionChangeHandler: ((versionHasChanged: boolean) => void) | null = null
|
||||||
clientPrefix = ''
|
clientPrefix = ''
|
||||||
serverUrl: string | undefined
|
serverUrl: string | undefined
|
||||||
state: 'init'|'open'|'close' = 'init'
|
state: 'init'|'open'|'close' = 'init'
|
||||||
|
@ -88,6 +90,7 @@ class WSClient {
|
||||||
}
|
}
|
||||||
|
|
||||||
initPlugin(pluginId: string, client: MMWebSocketClient): void {
|
initPlugin(pluginId: string, client: MMWebSocketClient): void {
|
||||||
|
this.pluginId = pluginId
|
||||||
this.clientPrefix = `custom_${pluginId}_`
|
this.clientPrefix = `custom_${pluginId}_`
|
||||||
this.client = client
|
this.client = client
|
||||||
Utils.log(`WSClient initialised for plugin id "${pluginId}"`)
|
Utils.log(`WSClient initialised for plugin id "${pluginId}"`)
|
||||||
|
@ -299,6 +302,21 @@ class WSClient {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
setOnAppVersionChangeHandler(fn: (versionHasChanged: boolean) => void): void {
|
||||||
|
this.onAppVersionChangeHandler = fn
|
||||||
|
}
|
||||||
|
|
||||||
|
pluginStatusesChangedHandler(data: any): void {
|
||||||
|
if (this.pluginId === '' || !this.onAppVersionChangeHandler) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if (data.plugin_statuses.some((s: any) => s.plugin_id === this.pluginId)) {
|
||||||
|
Utils.log('Boards plugin has been updated')
|
||||||
|
this.onAppVersionChangeHandler(true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
authenticate(workspaceId: string, token: string): void {
|
authenticate(workspaceId: string, token: string): void {
|
||||||
if (!this.hasConn()) {
|
if (!this.hasConn()) {
|
||||||
Utils.assertFailure('WSClient.addBlocks: ws is not open')
|
Utils.assertFailure('WSClient.addBlocks: ws is not open')
|
||||||
|
|
Loading…
Reference in a new issue