mirror of
https://github.com/YunoHost/yunohost-admin.git
synced 2024-09-03 20:06:15 +02:00
refactor: requests handling
This commit is contained in:
parent
cb344f28fc
commit
254e1aca56
5 changed files with 199 additions and 212 deletions
|
@ -2,13 +2,15 @@
|
||||||
import { onMounted } from 'vue'
|
import { onMounted } from 'vue'
|
||||||
import { useStore } from 'vuex'
|
import { useStore } from 'vuex'
|
||||||
|
|
||||||
|
import { useRequests } from '@/composables/useRequests'
|
||||||
|
import { useSettings } from '@/composables/useSettings'
|
||||||
import { useStoreGetters } from '@/store/utils'
|
import { useStoreGetters } from '@/store/utils'
|
||||||
import { HistoryConsole, ViewLockOverlay } from '@/views/_partials'
|
import { HistoryConsole, ViewLockOverlay } from '@/views/_partials'
|
||||||
import { useSettings } from '@/composables/useSettings'
|
|
||||||
|
|
||||||
const store = useStore()
|
const store = useStore()
|
||||||
|
|
||||||
const { connected, yunohost, routerKey, waiting, ssoLink } = useStoreGetters()
|
const { connected, yunohost, routerKey, ssoLink } = useStoreGetters()
|
||||||
|
const { locked } = useRequests()
|
||||||
const { spinner, dark, transitions, transitionName } = useSettings()
|
const { spinner, dark, transitions, transitionName } = useSettings()
|
||||||
|
|
||||||
async function logout() {
|
async function logout() {
|
||||||
|
@ -78,7 +80,7 @@ onMounted(() => {
|
||||||
<BNavbar>
|
<BNavbar>
|
||||||
<BNavbarBrand
|
<BNavbarBrand
|
||||||
:to="{ name: 'home' }"
|
:to="{ name: 'home' }"
|
||||||
:disabled="waiting"
|
:disabled="locked"
|
||||||
exact-active-class="active"
|
exact-active-class="active"
|
||||||
>
|
>
|
||||||
<span v-if="dark">
|
<span v-if="dark">
|
||||||
|
|
|
@ -1,10 +1,5 @@
|
||||||
/**
|
import { useRequests, type APIRequestAction } from '@/composables/useRequests'
|
||||||
* API module.
|
|
||||||
* @module api
|
|
||||||
*/
|
|
||||||
|
|
||||||
import { useSettings } from '@/composables/useSettings'
|
import { useSettings } from '@/composables/useSettings'
|
||||||
import store from '@/store'
|
|
||||||
import type { Obj } from '@/types/commons'
|
import type { Obj } from '@/types/commons'
|
||||||
import { APIUnauthorizedError, type APIError } from './errors'
|
import { APIUnauthorizedError, type APIError } from './errors'
|
||||||
import { getError, getResponseData, openWebSocket } from './handlers'
|
import { getError, getResponseData, openWebSocket } from './handlers'
|
||||||
|
@ -34,30 +29,7 @@ export type APIErrorData = {
|
||||||
error_key?: string
|
error_key?: string
|
||||||
log_ref?: string
|
log_ref?: string
|
||||||
traceback?: string
|
traceback?: string
|
||||||
name?: string // FIXME name is field id right?
|
name?: string
|
||||||
}
|
|
||||||
|
|
||||||
type RequestStatus = 'pending' | 'success' | 'warning' | 'error'
|
|
||||||
|
|
||||||
export type APIRequest = {
|
|
||||||
method: RequestMethod
|
|
||||||
uri: string
|
|
||||||
humanRouteKey: HumanKey['key']
|
|
||||||
humanRoute: string
|
|
||||||
initial: boolean
|
|
||||||
status: RequestStatus
|
|
||||||
}
|
|
||||||
|
|
||||||
type WebsocketMessage = {
|
|
||||||
text: string
|
|
||||||
status: 'info' | 'success' | 'warning' | 'error'
|
|
||||||
}
|
|
||||||
|
|
||||||
export type APIRequestAction = APIRequest & {
|
|
||||||
messages: WebsocketMessage[]
|
|
||||||
date: number
|
|
||||||
warning: number
|
|
||||||
errors: number
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -131,21 +103,21 @@ export default {
|
||||||
asFormData = true,
|
asFormData = true,
|
||||||
}: APIQuery): Promise<T> {
|
}: APIQuery): Promise<T> {
|
||||||
const { locale } = useSettings()
|
const { locale } = useSettings()
|
||||||
// `await` because Vuex actions returns promises by default.
|
const { startRequest, endRequest } = useRequests()
|
||||||
const request: APIRequest = await store.dispatch('INIT_REQUEST', {
|
|
||||||
|
const request = startRequest({
|
||||||
method,
|
method,
|
||||||
uri,
|
uri,
|
||||||
humanKey,
|
humanKey,
|
||||||
initial,
|
initial,
|
||||||
wait: showModal,
|
showModal,
|
||||||
websocket,
|
websocket,
|
||||||
})
|
})
|
||||||
|
|
||||||
if (websocket) {
|
if (websocket) {
|
||||||
await openWebSocket(request as APIRequestAction)
|
await openWebSocket(request as APIRequestAction)
|
||||||
}
|
}
|
||||||
|
|
||||||
let options = this.options
|
let options = { ...this.options }
|
||||||
if (method === 'GET') {
|
if (method === 'GET') {
|
||||||
uri += `${uri.includes('?') ? '&' : '?'}locale=${locale.value}`
|
uri += `${uri.includes('?') ? '&' : '?'}locale=${locale.value}`
|
||||||
} else {
|
} else {
|
||||||
|
@ -160,7 +132,7 @@ export default {
|
||||||
|
|
||||||
const response = await fetch('/yunohost/api/' + uri, options)
|
const response = await fetch('/yunohost/api/' + uri, options)
|
||||||
const responseData = await getResponseData(response)
|
const responseData = await getResponseData(response)
|
||||||
store.dispatch('END_REQUEST', { request, success: response.ok, wait })
|
endRequest({ request, success: response.ok })
|
||||||
|
|
||||||
if (!response.ok) {
|
if (!response.ok) {
|
||||||
throw getError(request, response, responseData as string | APIErrorData)
|
throw getError(request, response, responseData as string | APIErrorData)
|
||||||
|
|
|
@ -3,10 +3,15 @@
|
||||||
* @module api/handlers
|
* @module api/handlers
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import store from '@/store'
|
import errors, { APIError } from '@/api/errors'
|
||||||
import errors, { APIError } from './errors'
|
import {
|
||||||
|
STATUS_VARIANT,
|
||||||
|
type APIRequest,
|
||||||
|
type APIRequestAction,
|
||||||
|
} from '@/composables/useRequests'
|
||||||
|
import { toEntries } from '@/helpers/commons'
|
||||||
import type { Obj } from '@/types/commons'
|
import type { Obj } from '@/types/commons'
|
||||||
import type { APIErrorData, APIRequest, APIRequestAction } from './api'
|
import type { APIErrorData } from './api'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Try to get response content as json and if it's not as text.
|
* Try to get response content as json and if it's not as text.
|
||||||
|
@ -39,9 +44,26 @@ export function openWebSocket(request: APIRequestAction): Promise<Event> {
|
||||||
`wss://${store.getters.host}/yunohost/api/messages`,
|
`wss://${store.getters.host}/yunohost/api/messages`,
|
||||||
)
|
)
|
||||||
ws.onmessage = ({ data }) => {
|
ws.onmessage = ({ data }) => {
|
||||||
store.dispatch('DISPATCH_MESSAGE', {
|
const messages: Record<'info' | 'success' | 'warning' | 'error', string> =
|
||||||
request,
|
JSON.parse(data)
|
||||||
messages: JSON.parse(data),
|
toEntries(messages).forEach(([status, text]) => {
|
||||||
|
text = text.replaceAll('\n', '<br>')
|
||||||
|
const progressBar = text.match(/^\[#*\+*\.*\] > /)?.[0]
|
||||||
|
if (progressBar) {
|
||||||
|
text = text.replace(progressBar, '')
|
||||||
|
const progress: Obj<number> = { '#': 0, '+': 0, '.': 0 }
|
||||||
|
for (const char of progressBar) {
|
||||||
|
if (char in progress) progress[char] += 1
|
||||||
|
}
|
||||||
|
request.action.progress = Object.values(progress)
|
||||||
|
}
|
||||||
|
request.action.messages.push({
|
||||||
|
text,
|
||||||
|
variant: STATUS_VARIANT[status],
|
||||||
|
})
|
||||||
|
if (['error', 'warning'].includes(status)) {
|
||||||
|
request.action[`${status as 'error' | 'warning'}s`]++
|
||||||
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
// ws.onclose = (e) => {}
|
// ws.onclose = (e) => {}
|
||||||
|
|
157
app/src/composables/useRequests.ts
Normal file
157
app/src/composables/useRequests.ts
Normal file
|
@ -0,0 +1,157 @@
|
||||||
|
import { createGlobalState } from '@vueuse/core'
|
||||||
|
import { v4 as uuid } from 'uuid'
|
||||||
|
import { computed, reactive, shallowRef } from 'vue'
|
||||||
|
|
||||||
|
import type { APIQuery, RequestMethod } from '@/api/api'
|
||||||
|
import { type APIError } from '@/api/errors'
|
||||||
|
import { isObjectLiteral } from '@/helpers/commons'
|
||||||
|
import i18n from '@/i18n'
|
||||||
|
import type { StateVariant } from '@/types/commons'
|
||||||
|
|
||||||
|
export type RequestStatus = 'pending' | 'success' | 'warning' | 'error'
|
||||||
|
|
||||||
|
export type APIRequest = {
|
||||||
|
status: RequestStatus
|
||||||
|
method: RequestMethod
|
||||||
|
uri: string
|
||||||
|
id: string
|
||||||
|
humanRoute: string
|
||||||
|
initial: boolean
|
||||||
|
date: number
|
||||||
|
err?: APIError
|
||||||
|
action?: APIActionProps
|
||||||
|
showModal?: boolean
|
||||||
|
}
|
||||||
|
type APIActionProps = {
|
||||||
|
messages: RequestMessage[]
|
||||||
|
errors: number
|
||||||
|
warnings: number
|
||||||
|
progress?: number[]
|
||||||
|
}
|
||||||
|
|
||||||
|
export type APIRequestAction = APIRequest & {
|
||||||
|
action: APIActionProps
|
||||||
|
}
|
||||||
|
|
||||||
|
export type RequestMessage = {
|
||||||
|
text: string
|
||||||
|
variant: StateVariant
|
||||||
|
}
|
||||||
|
|
||||||
|
export const STATUS_VARIANT = {
|
||||||
|
pending: 'primary',
|
||||||
|
success: 'success',
|
||||||
|
warning: 'warning',
|
||||||
|
error: 'danger',
|
||||||
|
info: 'info',
|
||||||
|
} as const
|
||||||
|
|
||||||
|
export const useRequests = createGlobalState(() => {
|
||||||
|
const requests = shallowRef<APIRequest[]>([])
|
||||||
|
const currentRequest = computed(() => {
|
||||||
|
return requests.value.find((r) => r.showModal)
|
||||||
|
})
|
||||||
|
const locked = computed(() => currentRequest.value?.showModal)
|
||||||
|
const historyList = computed<APIRequestAction[]>(() => {
|
||||||
|
return requests.value
|
||||||
|
.filter((r) => !!r.action || !!r.err)
|
||||||
|
.reverse() as APIRequestAction[]
|
||||||
|
})
|
||||||
|
|
||||||
|
function startRequest({
|
||||||
|
uri,
|
||||||
|
method,
|
||||||
|
humanKey,
|
||||||
|
initial,
|
||||||
|
websocket,
|
||||||
|
showModal,
|
||||||
|
}: {
|
||||||
|
uri: string
|
||||||
|
method: RequestMethod
|
||||||
|
humanKey?: APIQuery['humanKey']
|
||||||
|
showModal: boolean
|
||||||
|
websocket: boolean
|
||||||
|
initial: boolean
|
||||||
|
}): APIRequest {
|
||||||
|
// Try to find a description for an API route to display in history and modals
|
||||||
|
const { key, ...args } = isObjectLiteral(humanKey)
|
||||||
|
? humanKey
|
||||||
|
: { key: humanKey }
|
||||||
|
const humanRoute = key
|
||||||
|
? i18n.global.t(`human_routes.${key}`, args)
|
||||||
|
: `[${method}] /${uri.split('?')[0]}`
|
||||||
|
|
||||||
|
const request: APIRequest = reactive({
|
||||||
|
method,
|
||||||
|
uri,
|
||||||
|
status: 'pending',
|
||||||
|
humanRoute,
|
||||||
|
initial,
|
||||||
|
showModal: false,
|
||||||
|
id: uuid(),
|
||||||
|
date: Date.now(),
|
||||||
|
err: undefined,
|
||||||
|
action: websocket
|
||||||
|
? {
|
||||||
|
messages: [],
|
||||||
|
warnings: 0,
|
||||||
|
errors: 0,
|
||||||
|
}
|
||||||
|
: undefined,
|
||||||
|
})
|
||||||
|
requests.value = [...requests.value, request]
|
||||||
|
const r = requests.value[requests.value.length - 1]!
|
||||||
|
|
||||||
|
if (showModal) {
|
||||||
|
setTimeout(() => {
|
||||||
|
// Display the waiting modal only if the request takes some time.
|
||||||
|
if (r.status === 'pending') {
|
||||||
|
r.showModal = true
|
||||||
|
}
|
||||||
|
}, 300)
|
||||||
|
}
|
||||||
|
|
||||||
|
return r
|
||||||
|
}
|
||||||
|
|
||||||
|
function endRequest({
|
||||||
|
request,
|
||||||
|
success,
|
||||||
|
}: {
|
||||||
|
request: APIRequest
|
||||||
|
success: boolean
|
||||||
|
}) {
|
||||||
|
let status: RequestStatus = success ? 'success' : 'error'
|
||||||
|
let hideModal = success
|
||||||
|
|
||||||
|
if (success && request.action) {
|
||||||
|
const { warnings, errors, messages } = request.action
|
||||||
|
const msgCount = messages.length
|
||||||
|
if (msgCount && messages[msgCount - 1].variant === 'warning') {
|
||||||
|
hideModal = false
|
||||||
|
}
|
||||||
|
if (errors || warnings) status = 'warning'
|
||||||
|
}
|
||||||
|
|
||||||
|
setTimeout(() => {
|
||||||
|
request.status = status
|
||||||
|
|
||||||
|
if (request.showModal && hideModal) {
|
||||||
|
request.showModal = false
|
||||||
|
// We can remove requests that are not actions or has no errors
|
||||||
|
requests.value = requests.value.filter(
|
||||||
|
(r) => r.showModal || !!r.action || !!r.err,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}, 350)
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
requests,
|
||||||
|
historyList,
|
||||||
|
currentRequest,
|
||||||
|
locked,
|
||||||
|
startRequest,
|
||||||
|
endRequest,
|
||||||
|
}
|
||||||
|
})
|
|
@ -1,7 +1,7 @@
|
||||||
import router from '@/router'
|
import router from '@/router'
|
||||||
import i18n from '@/i18n'
|
import i18n from '@/i18n'
|
||||||
import api from '@/api'
|
import api from '@/api'
|
||||||
import { timeout, isEmptyValue, isObjectLiteral } from '@/helpers/commons'
|
import { timeout, isEmptyValue } from '@/helpers/commons'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
state: {
|
state: {
|
||||||
|
@ -9,14 +9,8 @@ export default {
|
||||||
installed: null,
|
installed: null,
|
||||||
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
|
|
||||||
reconnecting: null, // null|Object { attemps, delay, initialDelay }
|
reconnecting: null, // null|Object { attemps, delay, initialDelay }
|
||||||
history: [], // Array of `request`
|
|
||||||
requests: [], // Array of `request`
|
|
||||||
currentRequest: null,
|
|
||||||
error: null, // null || request
|
error: null, // null || request
|
||||||
historyTimer: null, // null || setTimeout id
|
|
||||||
tempMessages: [], // Array of messages
|
|
||||||
routerKey: undefined, // String if current route has params
|
routerKey: undefined, // String if current route has params
|
||||||
breadcrumb: [], // Array of routes
|
breadcrumb: [], // Array of routes
|
||||||
transitionName: null, // String of CSS class if transitions are enabled
|
transitionName: null, // String of CSS class if transitions are enabled
|
||||||
|
@ -36,67 +30,10 @@ export default {
|
||||||
state.yunohost = yunohost
|
state.yunohost = yunohost
|
||||||
},
|
},
|
||||||
|
|
||||||
SET_WAITING(state, boolean) {
|
|
||||||
state.waiting = boolean
|
|
||||||
},
|
|
||||||
|
|
||||||
SET_RECONNECTING(state, args) {
|
SET_RECONNECTING(state, args) {
|
||||||
state.reconnecting = args
|
state.reconnecting = args
|
||||||
},
|
},
|
||||||
|
|
||||||
SET_CURRENT_REQUEST(state, request) {
|
|
||||||
state.currentRequest = request
|
|
||||||
},
|
|
||||||
|
|
||||||
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_REQUEST(state, { key, value }) {
|
|
||||||
// This rely on data persistance and reactivity.
|
|
||||||
state.currentRequest[key] = value
|
|
||||||
},
|
|
||||||
|
|
||||||
REMOVE_REQUEST(state, request) {
|
|
||||||
const index = state.requests.lastIndexOf(request)
|
|
||||||
state.requests.splice(index, 1)
|
|
||||||
},
|
|
||||||
|
|
||||||
ADD_HISTORY_ACTION(state, request) {
|
|
||||||
state.history.push(request)
|
|
||||||
},
|
|
||||||
|
|
||||||
ADD_TEMP_MESSAGE(state, { request, message, type }) {
|
|
||||||
state.tempMessages.push([message, type])
|
|
||||||
},
|
|
||||||
|
|
||||||
UPDATE_DISPLAYED_MESSAGES(state) {
|
|
||||||
if (!state.tempMessages.length) {
|
|
||||||
state.historyTimer = null
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
const { messages, warnings, errors } = state.tempMessages.reduce(
|
|
||||||
(acc, [message, type]) => {
|
|
||||||
acc.messages.push(message)
|
|
||||||
if (['error', 'warning'].includes(type)) acc[type + 's']++
|
|
||||||
return acc
|
|
||||||
},
|
|
||||||
{ messages: [], warnings: 0, errors: 0 },
|
|
||||||
)
|
|
||||||
state.tempMessages = []
|
|
||||||
state.historyTimer = null
|
|
||||||
state.currentRequest.messages =
|
|
||||||
state.currentRequest.messages.concat(messages)
|
|
||||||
state.currentRequest.warnings += warnings
|
|
||||||
state.currentRequest.errors += errors
|
|
||||||
},
|
|
||||||
|
|
||||||
SET_ERROR(state, request) {
|
SET_ERROR(state, request) {
|
||||||
if (request) {
|
if (request) {
|
||||||
state.error = request
|
state.error = request
|
||||||
|
@ -197,108 +134,6 @@ export default {
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
|
||||||
INIT_REQUEST(
|
|
||||||
{ commit },
|
|
||||||
{ method, uri, humanKey, initial, wait, websocket },
|
|
||||||
) {
|
|
||||||
// Try to find a description for an API route to display in history and modals
|
|
||||||
const { key, ...args } = isObjectLiteral(humanKey)
|
|
||||||
? humanKey
|
|
||||||
: { key: humanKey }
|
|
||||||
const humanRoute = key
|
|
||||||
? i18n.global.t('human_routes.' + key, args)
|
|
||||||
: `[${method}] /${uri}`
|
|
||||||
|
|
||||||
let request = {
|
|
||||||
method,
|
|
||||||
uri,
|
|
||||||
humanRouteKey: key,
|
|
||||||
humanRoute,
|
|
||||||
initial,
|
|
||||||
status: 'pending',
|
|
||||||
}
|
|
||||||
if (websocket) {
|
|
||||||
request = {
|
|
||||||
...request,
|
|
||||||
messages: [],
|
|
||||||
date: Date.now(),
|
|
||||||
warnings: 0,
|
|
||||||
errors: 0,
|
|
||||||
}
|
|
||||||
commit('ADD_HISTORY_ACTION', request)
|
|
||||||
}
|
|
||||||
commit('ADD_REQUEST', request)
|
|
||||||
commit('SET_CURRENT_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
|
|
||||||
},
|
|
||||||
|
|
||||||
END_REQUEST({ state, commit }, { request, success, wait }) {
|
|
||||||
// Update last messages before finishing this request
|
|
||||||
clearTimeout(state.historyTimer)
|
|
||||||
commit('UPDATE_DISPLAYED_MESSAGES', { request })
|
|
||||||
|
|
||||||
let status = success ? 'success' : 'error'
|
|
||||||
if (success && (request.warnings || request.errors)) {
|
|
||||||
const messages = request.messages
|
|
||||||
if (
|
|
||||||
messages.length &&
|
|
||||||
messages[messages.length - 1].color === 'warning'
|
|
||||||
) {
|
|
||||||
state.currentRequest.showWarningMessage = true
|
|
||||||
}
|
|
||||||
status = 'warning'
|
|
||||||
}
|
|
||||||
|
|
||||||
commit('UPDATE_REQUEST', { request, key: 'status', value: status })
|
|
||||||
if (wait && !state.currentRequest.showWarningMessage) {
|
|
||||||
// Remove the overlay after a short delay to allow an error to display withtout flickering.
|
|
||||||
setTimeout(() => {
|
|
||||||
commit('SET_WAITING', false)
|
|
||||||
}, 100)
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
DISPATCH_MESSAGE({ state, commit, dispatch }, { request, messages }) {
|
|
||||||
for (const type in messages) {
|
|
||||||
const message = {
|
|
||||||
text: messages[type].replaceAll('\n', '<br>'),
|
|
||||||
color: type === 'error' ? 'danger' : type,
|
|
||||||
}
|
|
||||||
let progressBar = message.text.match(/^\[#*\+*\.*\] > /)
|
|
||||||
if (progressBar) {
|
|
||||||
progressBar = progressBar[0]
|
|
||||||
message.text = message.text.replace(progressBar, '')
|
|
||||||
const progress = { '#': 0, '+': 0, '.': 0 }
|
|
||||||
for (const char of progressBar) {
|
|
||||||
if (char in progress) progress[char] += 1
|
|
||||||
}
|
|
||||||
commit('UPDATE_REQUEST', {
|
|
||||||
request,
|
|
||||||
key: 'progress',
|
|
||||||
value: Object.values(progress),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
if (message.text) {
|
|
||||||
// To avoid rendering lag issues, limit the flow of websocket messages to batches of 50ms.
|
|
||||||
if (state.historyTimer === null) {
|
|
||||||
state.historyTimer = setTimeout(() => {
|
|
||||||
commit('UPDATE_DISPLAYED_MESSAGES', { request })
|
|
||||||
}, 50)
|
|
||||||
}
|
|
||||||
commit('ADD_TEMP_MESSAGE', { request, message, type })
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
HANDLE_ERROR({ commit, dispatch }, error) {
|
HANDLE_ERROR({ commit, dispatch }, error) {
|
||||||
if (error.code === 401) {
|
if (error.code === 401) {
|
||||||
// Unauthorized
|
// Unauthorized
|
||||||
|
@ -423,7 +258,6 @@ export default {
|
||||||
connected: (state) => state.connected,
|
connected: (state) => state.connected,
|
||||||
yunohost: (state) => state.yunohost,
|
yunohost: (state) => state.yunohost,
|
||||||
error: (state) => state.error,
|
error: (state) => state.error,
|
||||||
waiting: (state) => state.waiting,
|
|
||||||
reconnecting: (state) => state.reconnecting,
|
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],
|
||||||
|
|
Loading…
Reference in a new issue