mirror of
https://github.com/YunoHost/yunohost-admin.git
synced 2024-09-03 20:06:15 +02:00
Update store and overlay components to new api
This commit is contained in:
parent
b130aeda29
commit
9bc365f32a
10 changed files with 223 additions and 173 deletions
|
@ -3,8 +3,8 @@
|
|||
v-bind="$attrs" ref="self"
|
||||
flush :class="{ 'fixed-height': fixedHeight, 'bordered': bordered }"
|
||||
>
|
||||
<b-list-group-item v-for="({ type, text }, i) in messages" :key="i">
|
||||
<span class="status" :class="'bg-' + type" />
|
||||
<b-list-group-item v-for="({ color, text }, i) in messages" :key="i">
|
||||
<span class="status" :class="'bg-' + color" />
|
||||
<span v-html="text" />
|
||||
</b-list-group-item>
|
||||
</b-list-group>
|
||||
|
|
|
@ -1,38 +1,39 @@
|
|||
<template>
|
||||
<div class="query-header w-100" v-on="$listeners" v-bind="$attrs">
|
||||
<!-- STATUS -->
|
||||
<span class="status" :class="['bg-' + color, statusSize]" :aria-label="$t('api.query_status.' + action.status)" />
|
||||
<span class="status" :class="['bg-' + color, statusSize]" :aria-label="$t('api.query_status.' + request.status)" />
|
||||
|
||||
<!-- ACTION DESCRIPTION -->
|
||||
<strong class="action-desc">
|
||||
{{ action.uri | readableUri }}
|
||||
<small>({{ $t('history.methods.' + action.method) }})</small>
|
||||
<!-- REQUEST DESCRIPTION -->
|
||||
<strong class="request-desc">
|
||||
{{ request.uri | readableUri }}
|
||||
<small>({{ $t('history.methods.' + request.method) }})</small>
|
||||
</strong>
|
||||
|
||||
<div>
|
||||
<div v-if="request.errors || request.warnings">
|
||||
<!-- WEBSOCKET ERRORS COUNT -->
|
||||
<span class="count" v-if="errorsCount">
|
||||
{{ errorsCount }}<icon iname="bug" class="text-danger ml-1" />
|
||||
<span class="count" v-if="request.errors">
|
||||
{{ request.errors }}<icon iname="bug" class="text-danger ml-1" />
|
||||
</span>
|
||||
<!-- WEBSOCKET WARNINGS COUNT -->
|
||||
<span class="count" v-if="warningsCount">
|
||||
{{ warningsCount }}<icon iname="warning" class="text-warning ml-1" />
|
||||
<span class="count" v-if="request.warnings">
|
||||
{{ request.warnings }}<icon iname="warning" class="text-warning ml-1" />
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<!-- VIEW ERRO BUTTON -->
|
||||
<!-- VIEW ERROR BUTTON -->
|
||||
<b-button
|
||||
v-if="showError && action.status === 'error'"
|
||||
v-if="showError && request.error"
|
||||
size="sm" pill
|
||||
class="error-btn ml-auto py-0"
|
||||
variant="danger"
|
||||
@click="reviewError"
|
||||
>
|
||||
<small v-t="'api_error.view_error'" />
|
||||
</b-button>
|
||||
|
||||
<!-- TIME DISPLAY -->
|
||||
<time v-if="showTime" :datetime="action.date | hour" :class="!showError || action.status !== 'error' ? 'ml-auto' : 'ml-2'">
|
||||
{{ action.date | hour }}
|
||||
<time v-if="showTime" :datetime="request.date | hour" :class="request.error ? 'ml-2' : 'ml-auto'">
|
||||
{{ request.date | hour }}
|
||||
</time>
|
||||
</div>
|
||||
</template>
|
||||
|
@ -42,11 +43,10 @@ export default {
|
|||
name: 'QueryHeader',
|
||||
|
||||
props: {
|
||||
action: { type: Object, required: true },
|
||||
request: { type: Object, required: true },
|
||||
statusSize: { type: String, default: '' },
|
||||
showTime: { type: Boolean, default: false },
|
||||
showError: { type: Boolean, default: false },
|
||||
truncate: { type: Boolean, default: true }
|
||||
showError: { type: Boolean, default: false }
|
||||
},
|
||||
|
||||
computed: {
|
||||
|
@ -57,21 +57,27 @@ export default {
|
|||
warning: 'warning',
|
||||
error: 'danger'
|
||||
}
|
||||
return statuses[this.action.status]
|
||||
return statuses[this.request.status]
|
||||
},
|
||||
|
||||
errorsCount () {
|
||||
return this.action.messages.filter(({ type }) => type === 'danger').length
|
||||
return this.request.messages.filter(({ type }) => type === 'danger').length
|
||||
},
|
||||
|
||||
warningsCount () {
|
||||
return this.action.messages.filter(({ type }) => type === 'warning').length
|
||||
return this.request.messages.filter(({ type }) => type === 'warning').length
|
||||
}
|
||||
},
|
||||
|
||||
methods: {
|
||||
reviewError () {
|
||||
this.$store.dispatch('REVIEW_ERROR', this.request)
|
||||
}
|
||||
},
|
||||
|
||||
filters: {
|
||||
readableUri (uri) {
|
||||
return uri.split('?')[0].replace('/', ' > ')
|
||||
return uri.split('?')[0].split('/').join(' > ') // replace('/', ' > ')
|
||||
},
|
||||
|
||||
hour (date) {
|
||||
|
@ -110,6 +116,11 @@ div {
|
|||
}
|
||||
}
|
||||
|
||||
time {
|
||||
min-width: 3.5rem;
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
.count {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
@ -117,7 +128,7 @@ div {
|
|||
}
|
||||
|
||||
@include media-breakpoint-down(xs) {
|
||||
.xs-hide .action-desc {
|
||||
.xs-hide .request-desc {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -203,7 +203,6 @@
|
|||
"history": {
|
||||
"title": "History",
|
||||
"last_action": "Last action:",
|
||||
"current_action": "Current action:",
|
||||
"methods": {
|
||||
"DELETE": "delete",
|
||||
"GET": "read",
|
||||
|
|
|
@ -29,7 +29,7 @@ const router = new VueRouter({
|
|||
|
||||
router.beforeEach((to, from, next) => {
|
||||
if (store.getters.error) {
|
||||
store.dispatch('DELETE_ERROR')
|
||||
store.dispatch('DISMISS_ERROR', true)
|
||||
}
|
||||
// Allow if connected or route is not protected
|
||||
if (store.getters.connected || to.meta.noAuth) {
|
||||
|
|
|
@ -90,40 +90,21 @@ export default {
|
|||
},
|
||||
|
||||
actions: {
|
||||
'FETCH' ({ state, commit, rootState }, { uri, param, storeKey = uri, cache = rootState.cache }) {
|
||||
'GET' ({ state, commit, rootState }, { uri, param, storeKey = uri, options = {} }) {
|
||||
const noCache = !rootState.cache || options.noCache || false
|
||||
const currentState = param ? state[storeKey][param] : state[storeKey]
|
||||
// if data has already been queried, simply return
|
||||
if (currentState !== undefined && cache) return currentState
|
||||
if (currentState !== undefined && !noCache) return currentState
|
||||
|
||||
return api.get(param ? `${uri}/${param}` : uri).then(responseData => {
|
||||
return api.fetch('GET', param ? `${uri}/${param}` : uri, null, options).then(responseData => {
|
||||
const data = responseData[storeKey] ? responseData[storeKey] : responseData
|
||||
commit('SET_' + storeKey.toUpperCase(), param ? [param, data] : data)
|
||||
return param ? state[storeKey][param] : state[storeKey]
|
||||
})
|
||||
},
|
||||
|
||||
'FETCH_ALL' ({ state, commit, rootState }, queries) {
|
||||
return Promise.all(queries.map(({ uri, param, storeKey = uri, cache = rootState.cache }) => {
|
||||
const currentState = param ? state[storeKey][param] : state[storeKey]
|
||||
// if data has already been queried, simply return the state as cached
|
||||
if (currentState !== undefined && cache) {
|
||||
return { cached: currentState }
|
||||
}
|
||||
return api.get(param ? `${uri}/${param}` : uri).then(responseData => {
|
||||
return { storeKey, param, responseData }
|
||||
})
|
||||
})).then(responsesData => {
|
||||
return responsesData.map(({ storeKey, param, responseData, cached = undefined }) => {
|
||||
if (cached !== undefined) return cached
|
||||
const data = responseData[storeKey] ? responseData[storeKey] : responseData
|
||||
commit('SET_' + storeKey.toUpperCase(), param ? [param, data] : data)
|
||||
return param ? state[storeKey][param] : state[storeKey]
|
||||
})
|
||||
})
|
||||
},
|
||||
|
||||
'POST' ({ state, commit }, { uri, data, storeKey = uri }) {
|
||||
return api.post(uri, data).then(responseData => {
|
||||
'POST' ({ state, commit }, { uri, storeKey = uri, data, options }) {
|
||||
return api.fetch('POST', uri, data, options).then(responseData => {
|
||||
// FIXME api/domains returns null
|
||||
if (responseData === null) responseData = data
|
||||
responseData = responseData[storeKey] ? responseData[storeKey] : responseData
|
||||
|
@ -132,16 +113,16 @@ export default {
|
|||
})
|
||||
},
|
||||
|
||||
'PUT' ({ state, commit }, { uri, param, data, storeKey = uri }) {
|
||||
return api.put(param ? `${uri}/${param}` : uri, data).then(responseData => {
|
||||
'PUT' ({ state, commit }, { uri, param, storeKey = uri, data, options }) {
|
||||
return api.fetch('PUT', param ? `${uri}/${param}` : uri, data, options).then(responseData => {
|
||||
const data = responseData[storeKey] ? responseData[storeKey] : responseData
|
||||
commit('UPDATE_' + storeKey.toUpperCase(), param ? [param, data] : data)
|
||||
return param ? state[storeKey][param] : state[storeKey]
|
||||
})
|
||||
},
|
||||
|
||||
'DELETE' ({ commit }, { uri, param, data = {}, storeKey = uri }) {
|
||||
return api.delete(param ? `${uri}/${param}` : uri, data).then(() => {
|
||||
'DELETE' ({ commit }, { uri, param, storeKey = uri, data, options }) {
|
||||
return api.fetch('DELETE', param ? `${uri}/${param}` : uri, data, options).then(() => {
|
||||
commit('DEL_' + storeKey.toUpperCase(), param)
|
||||
})
|
||||
}
|
||||
|
@ -164,8 +145,7 @@ export default {
|
|||
})
|
||||
},
|
||||
|
||||
// not cached
|
||||
user: state => name => state.users_details[name],
|
||||
user: state => name => state.users_details[name], // not cached
|
||||
|
||||
domains: state => state.domains,
|
||||
|
||||
|
|
|
@ -5,95 +5,70 @@ import { timeout } from '@/helpers/commons'
|
|||
|
||||
export default {
|
||||
state: {
|
||||
host: window.location.host,
|
||||
connected: localStorage.getItem('connected') === 'true',
|
||||
yunohost: null, // yunohost app infos: Object {version, repo}
|
||||
error: null,
|
||||
waiting: false,
|
||||
history: []
|
||||
host: window.location.host, // String
|
||||
connected: localStorage.getItem('connected') === 'true', // Boolean
|
||||
yunohost: null, // Object { version, repo }
|
||||
waiting: false, // Boolean
|
||||
history: [], // Array of `request`
|
||||
requests: [], // Array of `request`
|
||||
error: null // null || request
|
||||
},
|
||||
|
||||
mutations: {
|
||||
'SET_CONNECTED' (state, connected) {
|
||||
localStorage.setItem('connected', connected)
|
||||
state.connected = connected
|
||||
'SET_CONNECTED' (state, boolean) {
|
||||
localStorage.setItem('connected', boolean)
|
||||
state.connected = boolean
|
||||
},
|
||||
|
||||
'SET_YUNOHOST_INFOS' (state, yunohost) {
|
||||
state.yunohost = yunohost
|
||||
},
|
||||
|
||||
'UPDATE_WAITING' (state, boolean) {
|
||||
'SET_WAITING' (state, boolean) {
|
||||
state.waiting = boolean
|
||||
},
|
||||
|
||||
'ADD_HISTORY_ENTRY' (state, [uri, method, date]) {
|
||||
state.history.push({ uri, method, date, status: 'pending', messages: [] })
|
||||
'ADD_REQUEST' (state, request) {
|
||||
if (state.requests.length > 10) {
|
||||
// We do not remove requests right after it resolves since an error might bring
|
||||
// one back to life but we can safely remove some here.
|
||||
state.requests.shift()
|
||||
}
|
||||
state.requests.push(request)
|
||||
},
|
||||
|
||||
'UPDATE_LAST_HISTORY_ENTRY' (state, [key, value]) {
|
||||
Vue.set(state.history[state.history.length - 1], key, value)
|
||||
'UPDATE_REQUEST' (state, { request, key, value }) {
|
||||
// This rely on data persistance and reactivity.
|
||||
Vue.set(request, key, value)
|
||||
},
|
||||
|
||||
'ADD_MESSAGE' (state, message) {
|
||||
state.history[state.history.length - 1].messages.push(message)
|
||||
'REMOVE_REQUEST' (state, request) {
|
||||
const index = state.requests.lastIndexOf(request)
|
||||
state.requests.splice(index, 1)
|
||||
},
|
||||
|
||||
'UPDATE_PROGRESS' (state, progress) {
|
||||
Vue.set(state.history[state.history.length - 1], 'progress', progress)
|
||||
'ADD_HISTORY_ACTION' (state, request) {
|
||||
state.history.push(request)
|
||||
},
|
||||
|
||||
'SET_ERROR' (state, error) {
|
||||
state.error = error
|
||||
'ADD_MESSAGE' (state, { message, type }) {
|
||||
const request = state.history[state.history.length - 1]
|
||||
request.messages.push(message)
|
||||
if (['error', 'warning'].includes(type)) {
|
||||
request[type + 's']++
|
||||
}
|
||||
},
|
||||
|
||||
'SET_ERROR' (state, request) {
|
||||
if (request) {
|
||||
state.error = request
|
||||
} else {
|
||||
state.error = null
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
actions: {
|
||||
'LOGIN' ({ dispatch }, password) {
|
||||
// Entering a wrong password will trigger a 401 api response.
|
||||
// action `DISCONNECT` will then be triggered by the response handler but will not
|
||||
// redirect to `/login` so the view can display the catched error.
|
||||
return api.post('login', { password }).then(() => {
|
||||
dispatch('CONNECT')
|
||||
})
|
||||
},
|
||||
|
||||
'LOGOUT' ({ dispatch }) {
|
||||
return api.get('logout').then(() => {
|
||||
dispatch('DISCONNECT')
|
||||
})
|
||||
},
|
||||
|
||||
'RESET_CONNECTED' ({ commit }) {
|
||||
commit('SET_CONNECTED', false)
|
||||
commit('SET_YUNOHOST_INFOS', null)
|
||||
},
|
||||
|
||||
'DISCONNECT' ({ dispatch, commit }, route) {
|
||||
dispatch('RESET_CONNECTED')
|
||||
commit('UPDATE_WAITING', false)
|
||||
if (router.currentRoute.name === 'login') return
|
||||
router.push({
|
||||
name: 'login',
|
||||
// Add a redirect query if next route is not unknown (like `logout`) or `login`
|
||||
query: route && !['login', null].includes(route.name)
|
||||
? { redirect: route.path }
|
||||
: {}
|
||||
})
|
||||
},
|
||||
|
||||
'CONNECT' ({ commit, dispatch }) {
|
||||
commit('SET_CONNECTED', true)
|
||||
dispatch('GET_YUNOHOST_INFOS')
|
||||
router.push(router.currentRoute.query.redirect || { name: 'home' })
|
||||
},
|
||||
|
||||
'GET_YUNOHOST_INFOS' ({ commit }) {
|
||||
return api.get('versions').then(versions => {
|
||||
commit('SET_YUNOHOST_INFOS', versions.yunohost)
|
||||
})
|
||||
},
|
||||
|
||||
'CHECK_INSTALL' ({ dispatch }, retry = 2) {
|
||||
// this action will try to query the `/installed` route 3 times every 5 s with
|
||||
// a timeout of the same delay.
|
||||
|
@ -108,29 +83,85 @@ export default {
|
|||
})
|
||||
},
|
||||
|
||||
'WAITING_FOR_RESPONSE' ({ commit }, [uri, method]) {
|
||||
commit('UPDATE_WAITING', true)
|
||||
commit('ADD_HISTORY_ENTRY', [uri, method, Date.now()])
|
||||
'CONNECT' ({ commit, dispatch }) {
|
||||
commit('SET_CONNECTED', true)
|
||||
dispatch('GET_YUNOHOST_INFOS')
|
||||
router.push(router.currentRoute.query.redirect || { name: 'home' })
|
||||
},
|
||||
|
||||
'SERVER_RESPONDED' ({ state, commit }, success) {
|
||||
const action = state.history.length ? state.history[state.history.length - 1] : null
|
||||
if (action) {
|
||||
let status = success ? 'success' : 'error'
|
||||
if (status === 'success' && action.messages.some(msg => msg.type === 'danger' || msg.type === 'warning')) {
|
||||
status = 'warning'
|
||||
}
|
||||
commit('UPDATE_LAST_HISTORY_ENTRY', ['status', status])
|
||||
'RESET_CONNECTED' ({ commit }) {
|
||||
commit('SET_CONNECTED', false)
|
||||
commit('SET_YUNOHOST_INFOS', null)
|
||||
},
|
||||
|
||||
'DISCONNECT' ({ dispatch }, route = router.currentRoute) {
|
||||
dispatch('RESET_CONNECTED')
|
||||
if (router.currentRoute.name === 'login') return
|
||||
router.push({
|
||||
name: 'login',
|
||||
// Add a redirect query if next route is not unknown (like `logout`) or `login`
|
||||
query: route && !['login', null].includes(route.name)
|
||||
? { redirect: route.path }
|
||||
: {}
|
||||
})
|
||||
},
|
||||
|
||||
'LOGIN' ({ dispatch }, password) {
|
||||
return api.post('login', { password }, { websocket: false }).then(() => {
|
||||
dispatch('CONNECT')
|
||||
})
|
||||
},
|
||||
|
||||
'LOGOUT' ({ dispatch }) {
|
||||
dispatch('DISCONNECT')
|
||||
return api.get('logout')
|
||||
},
|
||||
|
||||
'GET_YUNOHOST_INFOS' ({ commit }) {
|
||||
return api.get('versions').then(versions => {
|
||||
commit('SET_YUNOHOST_INFOS', versions.yunohost)
|
||||
})
|
||||
},
|
||||
|
||||
'INIT_REQUEST' ({ commit }, { method, uri, initial, wait, websocket }) {
|
||||
let request = { method, uri, initial, status: 'pending' }
|
||||
if (websocket) {
|
||||
request = { ...request, messages: [], date: Date.now(), warnings: 0, errors: 0 }
|
||||
commit('ADD_HISTORY_ACTION', request)
|
||||
}
|
||||
commit('UPDATE_WAITING', false)
|
||||
commit('ADD_REQUEST', request)
|
||||
if (wait) {
|
||||
setTimeout(() => {
|
||||
// Display the waiting modal only if the request takes some time.
|
||||
if (request.status === 'pending') {
|
||||
commit('SET_WAITING', true)
|
||||
}
|
||||
}, 400)
|
||||
}
|
||||
|
||||
return request
|
||||
},
|
||||
|
||||
'DISPATCH_MESSAGE' ({ commit }, messages) {
|
||||
const typeToColor = { error: 'danger' }
|
||||
'END_REQUEST' ({ commit }, { request, success, wait }) {
|
||||
let status = success ? 'success' : 'error'
|
||||
if (success && (request.warnings || request.errors)) {
|
||||
status = 'warning'
|
||||
}
|
||||
|
||||
commit('UPDATE_REQUEST', { request, key: 'status', value: status })
|
||||
if (wait) {
|
||||
// Remove the overlay after a short delay to allow an error to display withtout flickering.
|
||||
setTimeout(() => {
|
||||
commit('SET_WAITING', false)
|
||||
}, 100)
|
||||
}
|
||||
},
|
||||
|
||||
'DISPATCH_MESSAGE' ({ commit }, { request, messages }) {
|
||||
for (const type in messages) {
|
||||
const message = {
|
||||
text: messages[type],
|
||||
type: type in typeToColor ? typeToColor[type] : type
|
||||
color: type === 'error' ? 'danger' : type
|
||||
}
|
||||
let progressBar = message.text.match(/^\[#*\+*\.*\] > /)
|
||||
if (progressBar) {
|
||||
|
@ -140,15 +171,15 @@ export default {
|
|||
for (const char of progressBar) {
|
||||
if (char in progress) progress[char] += 1
|
||||
}
|
||||
commit('UPDATE_PROGRESS', Object.values(progress))
|
||||
commit('UPDATE_REQUEST', { request, key: 'progress', value: Object.values(progress) })
|
||||
}
|
||||
if (message.text) {
|
||||
commit('ADD_MESSAGE', message)
|
||||
commit('ADD_MESSAGE', { request, message, type })
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
'HANDLE_ERROR' ({ state, commit, dispatch }, error) {
|
||||
'HANDLE_ERROR' ({ commit, dispatch }, error) {
|
||||
if (error.code === 401) {
|
||||
// Unauthorized
|
||||
dispatch('DISCONNECT')
|
||||
|
@ -156,23 +187,47 @@ export default {
|
|||
// Errors that have produced logs
|
||||
router.push({ name: 'tool-log', params: { name: error.logRef } })
|
||||
} else {
|
||||
// The request is temporarely stored in the error for reference, but we reverse
|
||||
// the ownership to stay generic.
|
||||
const request = error.request
|
||||
delete error.request
|
||||
Vue.set(request, 'error', error)
|
||||
// Display the error in a modal on the current view.
|
||||
commit('SET_ERROR', error)
|
||||
commit('SET_ERROR', request)
|
||||
}
|
||||
},
|
||||
|
||||
'DELETE_ERROR' ({ commit }) {
|
||||
'REVIEW_ERROR' ({ commit }, request) {
|
||||
request.review = true
|
||||
commit('SET_ERROR', request)
|
||||
},
|
||||
|
||||
'DISMISS_ERROR' ({ commit, state }, { initial, review = false }) {
|
||||
if (initial && !review) {
|
||||
// In case of an initial request (data that is needed by a view to render itself),
|
||||
// try to go back so the user doesn't get stuck at a never ending skeleton view.
|
||||
if (history.length > 2) {
|
||||
history.back()
|
||||
} else {
|
||||
// if the url was opened in a new tab, return to home
|
||||
router.push({ name: 'home' })
|
||||
}
|
||||
}
|
||||
commit('SET_ERROR', null)
|
||||
}
|
||||
},
|
||||
|
||||
getters: {
|
||||
host: state => state.host,
|
||||
connected: state => (state.connected),
|
||||
yunohost: state => (state.yunohost),
|
||||
connected: state => state.connected,
|
||||
yunohost: state => state.yunohost,
|
||||
error: state => state.error,
|
||||
waiting: state => state.waiting,
|
||||
history: state => state.history,
|
||||
lastAction: state => state.history[state.history.length - 1]
|
||||
lastAction: state => state.history[state.history.length - 1],
|
||||
currentRequest: state => {
|
||||
const request = state.requests.find(({ status }) => status === 'pending')
|
||||
return request || state.requests[state.requests.length - 1]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -30,11 +30,11 @@
|
|||
<pre><code>{{ error.traceback }}</code></pre>
|
||||
</template>
|
||||
|
||||
<template v-if="hasMessages">
|
||||
<template v-if="messages">
|
||||
<p class="my-2">
|
||||
<strong v-t="'api_error.server_said'" />
|
||||
</p>
|
||||
<message-list-group :messages="action.messages" bordered />
|
||||
<message-list-group :messages="messages" bordered />
|
||||
</template>
|
||||
</b-card-body>
|
||||
|
||||
|
@ -49,35 +49,34 @@
|
|||
</template>
|
||||
|
||||
<script>
|
||||
import { mapGetters } from 'vuex'
|
||||
|
||||
import MessageListGroup from '@/components/MessageListGroup'
|
||||
|
||||
export default {
|
||||
name: 'ErrorPage',
|
||||
name: 'ErrorDisplay',
|
||||
|
||||
components: {
|
||||
MessageListGroup
|
||||
},
|
||||
|
||||
props: {
|
||||
action: { type: Object, required: true }
|
||||
request: { type: [Object, null], default: null }
|
||||
},
|
||||
|
||||
computed: {
|
||||
...mapGetters(['error']),
|
||||
error () {
|
||||
return this.request.error
|
||||
},
|
||||
|
||||
hasMessages () {
|
||||
return this.action && this.action.messages.length > 0
|
||||
messages () {
|
||||
const messages = this.request.messages
|
||||
if (messages && messages.length > 0) return messages
|
||||
return null
|
||||
}
|
||||
},
|
||||
|
||||
methods: {
|
||||
dismiss () {
|
||||
if (this.error && this.error.method === 'GET') {
|
||||
history.back()
|
||||
}
|
||||
this.$store.dispatch('DELETE_ERROR')
|
||||
this.$store.dispatch('DISMISS_ERROR', this.request)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -23,9 +23,9 @@
|
|||
@click.prevent="onLastActionClick"
|
||||
@keyup.enter.space.prevent="onLastActionClick"
|
||||
>
|
||||
<small>{{ $t('history.' + (lastAction.status === 'pending' ? 'current_action' : 'last_action')) }}</small>
|
||||
<small>{{ $t('history.last_action') }}</small>
|
||||
</b-button>
|
||||
<query-header v-if="lastAction" :action="lastAction" class="w-auto ml-2 xs-hide" />
|
||||
<query-header v-if="lastAction" :request="lastAction" class="w-auto ml-2 xs-hide" />
|
||||
</b-card-header>
|
||||
|
||||
<b-collapse id="console-collapse" v-model="open">
|
||||
|
@ -43,7 +43,7 @@
|
|||
<!-- ACTION DESC -->
|
||||
<query-header
|
||||
role="tab" v-b-toggle="action.messages.length ? 'messages-collapse-' + i : false"
|
||||
:action="action" show-time show-error
|
||||
:request="action" show-time show-error
|
||||
/>
|
||||
</b-card-header>
|
||||
|
||||
|
|
|
@ -7,12 +7,13 @@
|
|||
<slot name="default" />
|
||||
|
||||
<template v-slot:overlay>
|
||||
<b-card no-body class="card-overlay" v-if="lastAction">
|
||||
<b-card no-body class="card-overlay">
|
||||
<b-card-header header-bg-variant="white">
|
||||
<query-header :action="lastAction" status-size="lg" />
|
||||
<query-header :request="error || currentRequest" status-size="lg" />
|
||||
</b-card-header>
|
||||
|
||||
<component :is="error ? 'ErrorDisplay' : 'WaitingDisplay'" :action="lastAction" />
|
||||
<component v-if="error" :is="'ErrorDisplay'" :request="error" />
|
||||
<component v-else :is="'WaitingDisplay'" :request="currentRequest" />
|
||||
</b-card>
|
||||
</template>
|
||||
</b-overlay>
|
||||
|
@ -26,13 +27,13 @@ import QueryHeader from '@/components/QueryHeader'
|
|||
export default {
|
||||
name: 'ViewLockOverlay',
|
||||
|
||||
computed: mapGetters(['waiting', 'error', 'lastAction']),
|
||||
|
||||
components: {
|
||||
ErrorDisplay,
|
||||
WaitingDisplay,
|
||||
QueryHeader
|
||||
}
|
||||
},
|
||||
|
||||
computed: mapGetters(['waiting', 'error', 'currentRequest'])
|
||||
}
|
||||
</script>
|
||||
|
||||
|
@ -53,8 +54,13 @@ export default {
|
|||
::v-deep {
|
||||
.card-body {
|
||||
padding: 1.5rem;
|
||||
padding-bottom: 0;
|
||||
max-height: 60vh;
|
||||
overflow-y: auto;
|
||||
|
||||
& > :last-child {
|
||||
margin-bottom: 1.5rem;
|
||||
}
|
||||
}
|
||||
|
||||
.card-footer {
|
||||
|
|
|
@ -16,7 +16,7 @@
|
|||
<div v-else class="custom-spinner my-4" :class="spinner" />
|
||||
|
||||
<message-list-group
|
||||
v-if="hasMessages" :messages="action.messages"
|
||||
v-if="hasMessages" :messages="request.messages"
|
||||
bordered fixed-height auto-scroll
|
||||
/>
|
||||
</b-card-body>
|
||||
|
@ -35,28 +35,28 @@ export default {
|
|||
},
|
||||
|
||||
props: {
|
||||
action: { type: Object, required: true }
|
||||
request: { type: Object, required: true }
|
||||
},
|
||||
|
||||
computed: {
|
||||
...mapGetters(['spinner']),
|
||||
|
||||
hasMessages () {
|
||||
return this.action && this.action.messages.length > 0
|
||||
return this.request.messages && this.request.messages.length > 0
|
||||
},
|
||||
|
||||
progress () {
|
||||
const progress = this.action.progress
|
||||
const progress = this.request.progress
|
||||
if (!progress) return null
|
||||
return {
|
||||
values: progress, max: progress.reduce((sum, value) => (sum + value), 0)
|
||||
values: progress,
|
||||
max: progress.reduce((sum, value) => (sum + value), 0)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.custom-spinner {
|
||||
animation: 4s linear infinite;
|
||||
|
|
Loading…
Add table
Reference in a new issue