mirror of
https://github.com/YunoHost/yunohost-admin.git
synced 2024-09-03 20:06:15 +02:00
add ReconnectingDisplay and reconnection mecanism
This commit is contained in:
parent
246c001f84
commit
c259a97a74
5 changed files with 133 additions and 2 deletions
|
@ -189,5 +189,34 @@ export default {
|
||||||
delete (uri, data = {}, humanKey = null, options = {}) {
|
delete (uri, data = {}, humanKey = null, options = {}) {
|
||||||
if (typeof uri === 'string') return this.fetch('DELETE', uri, data, humanKey, options)
|
if (typeof uri === 'string') return this.fetch('DELETE', uri, data, humanKey, options)
|
||||||
return store.dispatch('DELETE', { ...uri, data, humanKey, options })
|
return store.dispatch('DELETE', { ...uri, data, humanKey, options })
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Api reconnection helper. Resolve when server is reachable or fail after n attemps
|
||||||
|
*
|
||||||
|
* @param {Number} attemps - number of attemps before rejecting
|
||||||
|
* @param {Number} delay - delay between calls to the API in ms.
|
||||||
|
* @param {Number} initialDelay - delay before calling the API for the first time in ms.
|
||||||
|
* @return {Promise<undefined|Error>}
|
||||||
|
*/
|
||||||
|
tryToReconnect ({ attemps = 1, delay = 2000, initialDelay = 0 } = {}) {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
const api = this
|
||||||
|
|
||||||
|
function reconnect (n) {
|
||||||
|
api.get('logout', {}, { key: 'reconnecting' }).then(resolve).catch(err => {
|
||||||
|
if (err.name === 'APIUnauthorizedError') {
|
||||||
|
resolve()
|
||||||
|
} else if (n < 1) {
|
||||||
|
reject(err)
|
||||||
|
} else {
|
||||||
|
setTimeout(() => reconnect(n - 1), delay)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
if (initialDelay > 0) setTimeout(() => reconnect(attemps), initialDelay)
|
||||||
|
else reconnect(attemps)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,6 +21,15 @@
|
||||||
"pending": "In progress",
|
"pending": "In progress",
|
||||||
"success": "Successfully completed",
|
"success": "Successfully completed",
|
||||||
"warning": "Successfully completed with errors or alerts"
|
"warning": "Successfully completed with errors or alerts"
|
||||||
|
},
|
||||||
|
"reconnecting": {
|
||||||
|
"title": "Trying to communicate with the server...",
|
||||||
|
"failed": "Looks like the server is not responding. You can try to reconnect again or try to run `systemctl restart yunohost-api` thru ssh.",
|
||||||
|
"reason": {
|
||||||
|
"unknown": "Connection with the server has been closed for unknown reasons.",
|
||||||
|
"upgrade_system": "Connection with the server has been closed due to yunohost upgrade. Waiting for the server to be reachable again…"
|
||||||
|
},
|
||||||
|
"success": "The server is now reachable! You can try to login"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"api_error": {
|
"api_error": {
|
||||||
|
@ -363,6 +372,7 @@
|
||||||
"rerun_diagnosis": "Rerun diagnosis",
|
"rerun_diagnosis": "Rerun diagnosis",
|
||||||
"restore": "Restore",
|
"restore": "Restore",
|
||||||
"restart": "Restart",
|
"restart": "Restart",
|
||||||
|
"retry": "Retry",
|
||||||
"human_routes": {
|
"human_routes": {
|
||||||
"adminpw": "Change admin password",
|
"adminpw": "Change admin password",
|
||||||
"apps": {
|
"apps": {
|
||||||
|
@ -422,6 +432,7 @@
|
||||||
},
|
},
|
||||||
"postinstall": "Run the post-install",
|
"postinstall": "Run the post-install",
|
||||||
"reboot": "Reboot the server",
|
"reboot": "Reboot the server",
|
||||||
|
"reconnecting": "Reconnecting",
|
||||||
"services": {
|
"services": {
|
||||||
"restart": "Restart the service '{name}'",
|
"restart": "Restart the service '{name}'",
|
||||||
"start": "Start the service '{name}'",
|
"start": "Start the service '{name}'",
|
||||||
|
|
|
@ -10,6 +10,7 @@ export default {
|
||||||
connected: localStorage.getItem('connected') === 'true', // Boolean
|
connected: localStorage.getItem('connected') === 'true', // Boolean
|
||||||
yunohost: null, // Object { version, repo }
|
yunohost: null, // Object { version, repo }
|
||||||
waiting: false, // Boolean
|
waiting: false, // Boolean
|
||||||
|
reconnecting: false, // Boolean
|
||||||
history: [], // Array of `request`
|
history: [], // Array of `request`
|
||||||
requests: [], // Array of `request`
|
requests: [], // Array of `request`
|
||||||
error: null, // null || request
|
error: null, // null || request
|
||||||
|
@ -31,6 +32,10 @@ export default {
|
||||||
state.waiting = boolean
|
state.waiting = boolean
|
||||||
},
|
},
|
||||||
|
|
||||||
|
'SET_RECONNECTING' (state, boolean) {
|
||||||
|
state.reconnecting = boolean
|
||||||
|
},
|
||||||
|
|
||||||
'ADD_REQUEST' (state, request) {
|
'ADD_REQUEST' (state, request) {
|
||||||
if (state.requests.length > 10) {
|
if (state.requests.length > 10) {
|
||||||
// We do not remove requests right after it resolves since an error might bring
|
// We do not remove requests right after it resolves since an error might bring
|
||||||
|
@ -133,6 +138,11 @@ export default {
|
||||||
return api.get('logout')
|
return api.get('logout')
|
||||||
},
|
},
|
||||||
|
|
||||||
|
'TRY_TO_RECONNECT' ({ commit, dispatch }) {
|
||||||
|
commit('SET_RECONNECTING', true)
|
||||||
|
dispatch('RESET_CONNECTED')
|
||||||
|
},
|
||||||
|
|
||||||
'GET_YUNOHOST_INFOS' ({ commit }) {
|
'GET_YUNOHOST_INFOS' ({ commit }) {
|
||||||
return api.get('versions').then(versions => {
|
return api.get('versions').then(versions => {
|
||||||
commit('SET_YUNOHOST_INFOS', versions.yunohost)
|
commit('SET_YUNOHOST_INFOS', versions.yunohost)
|
||||||
|
@ -144,7 +154,7 @@ export default {
|
||||||
const { key, ...args } = isObjectLiteral(humanKey) ? humanKey : { key: humanKey }
|
const { key, ...args } = isObjectLiteral(humanKey) ? humanKey : { key: humanKey }
|
||||||
const humanRoute = key ? i18n.t('human_routes.' + key, args) : `[${method}] /${uri}`
|
const humanRoute = key ? i18n.t('human_routes.' + key, args) : `[${method}] /${uri}`
|
||||||
|
|
||||||
let request = { method, uri, humanRoute, initial, status: 'pending' }
|
let request = { method, uri, humanRouteKey: key, humanRoute, initial, status: 'pending' }
|
||||||
if (websocket) {
|
if (websocket) {
|
||||||
request = { ...request, messages: [], date: Date.now(), warnings: 0, errors: 0 }
|
request = { ...request, messages: [], date: Date.now(), warnings: 0, errors: 0 }
|
||||||
commit('ADD_HISTORY_ACTION', request)
|
commit('ADD_HISTORY_ACTION', request)
|
||||||
|
@ -252,7 +262,7 @@ export default {
|
||||||
|
|
||||||
'DISMISS_WARNING' ({ commit, state }, request) {
|
'DISMISS_WARNING' ({ commit, state }, request) {
|
||||||
commit('SET_WAITING', false)
|
commit('SET_WAITING', false)
|
||||||
delete request.showWarningMessage
|
Vue.delete(request, 'showWarningMessage')
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -262,6 +272,7 @@ export default {
|
||||||
yunohost: state => state.yunohost,
|
yunohost: state => state.yunohost,
|
||||||
error: state => state.error,
|
error: state => state.error,
|
||||||
waiting: state => state.waiting,
|
waiting: state => state.waiting,
|
||||||
|
reconnecting: state => state.reconnecting,
|
||||||
history: state => state.history,
|
history: state => state.history,
|
||||||
lastAction: state => state.history[state.history.length - 1],
|
lastAction: state => state.history[state.history.length - 1],
|
||||||
currentRequest: state => {
|
currentRequest: state => {
|
||||||
|
|
79
app/src/views/_partials/ReconnectingDisplay.vue
Normal file
79
app/src/views/_partials/ReconnectingDisplay.vue
Normal file
|
@ -0,0 +1,79 @@
|
||||||
|
<template>
|
||||||
|
<!-- This card receives style from `ViewLockOverlay` if used inside it -->
|
||||||
|
<b-card-body>
|
||||||
|
<b-card-title class="text-center my-4" v-t="'api.reconnecting.title'" />
|
||||||
|
|
||||||
|
<template v-if="status === 'reconnecting'">
|
||||||
|
<spinner class="mb-4" />
|
||||||
|
|
||||||
|
<b-alert
|
||||||
|
v-if="origin"
|
||||||
|
v-t="'api.reconnecting.reason.' + origin"
|
||||||
|
:variant="origin === 'unknow' ? 'warning' : 'info'"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<template v-if="status === 'failed'">
|
||||||
|
<b-alert variant="danger">
|
||||||
|
<markdown-item :label="$t('api.reconnecting.failed')" />
|
||||||
|
</b-alert>
|
||||||
|
|
||||||
|
<div class="d-flex justify-content-end">
|
||||||
|
<b-button
|
||||||
|
variant="success" v-t="'retry'" class="ml-auto"
|
||||||
|
@click="tryToReconnect()"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<template v-if="status === 'success'">
|
||||||
|
<b-alert variant="success" v-t="'api.reconnecting.success'" />
|
||||||
|
|
||||||
|
<login-view skip-install-check force-reload />
|
||||||
|
</template>
|
||||||
|
</b-card-body>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import { mapGetters } from 'vuex'
|
||||||
|
|
||||||
|
import api from '@/api'
|
||||||
|
import LoginView from '@/views/Login'
|
||||||
|
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'ReconnectingDisplay',
|
||||||
|
|
||||||
|
components: {
|
||||||
|
LoginView
|
||||||
|
},
|
||||||
|
|
||||||
|
data () {
|
||||||
|
return {
|
||||||
|
status: 'reconnecting',
|
||||||
|
origin: undefined
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
computed: {
|
||||||
|
...mapGetters(['currentRequest'])
|
||||||
|
},
|
||||||
|
|
||||||
|
methods: {
|
||||||
|
tryToReconnect ({ initialDelay = 0 } = {}) {
|
||||||
|
this.status = 'reconnecting'
|
||||||
|
api.tryToReconnect({ initialDelay }).then(() => {
|
||||||
|
this.status = 'success'
|
||||||
|
}).catch(() => {
|
||||||
|
this.status = 'failed'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
created () {
|
||||||
|
const origin = this.currentRequest.humanRouteKey
|
||||||
|
this.origin = ['upgrade.system'].includes(origin) ? origin.replace('.', '_') : 'unknown'
|
||||||
|
this.tryToReconnect({ initialDelay: 2000 })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
|
@ -1,6 +1,7 @@
|
||||||
export { default as ErrorDisplay } from './ErrorDisplay'
|
export { default as ErrorDisplay } from './ErrorDisplay'
|
||||||
export { default as WarningDisplay } from './WarningDisplay'
|
export { default as WarningDisplay } from './WarningDisplay'
|
||||||
export { default as WaitingDisplay } from './WaitingDisplay'
|
export { default as WaitingDisplay } from './WaitingDisplay'
|
||||||
|
export { default as ReconnectingDisplay } from './ReconnectingDisplay'
|
||||||
|
|
||||||
export { default as HistoryConsole } from './HistoryConsole'
|
export { default as HistoryConsole } from './HistoryConsole'
|
||||||
export { default as ViewLockOverlay } from './ViewLockOverlay'
|
export { default as ViewLockOverlay } from './ViewLockOverlay'
|
||||||
|
|
Loading…
Add table
Reference in a new issue