mirror of
https://github.com/apache/cloudstack.git
synced 2025-10-26 08:42:29 +01:00
Async job poller and notifications for actions (#32)
Async job poller tech capability implementation, show notifications on success/fail. Signed-off-by: Rohit Yadav <rohit.yadav@shapeblue.com>
This commit is contained in:
parent
8b9fccdf11
commit
db42cdf830
@ -234,6 +234,7 @@ import DataView from '@/components/widgets/DataView'
|
||||
import InstanceView from '@/components/widgets/InstanceView'
|
||||
import Status from '@/components/widgets/Status'
|
||||
import { mixinDevice } from '@/utils/mixin.js'
|
||||
import { constants } from 'crypto';
|
||||
|
||||
export default {
|
||||
name: 'Resource',
|
||||
@ -506,9 +507,21 @@ export default {
|
||||
const closeAction = this.closeAction
|
||||
const showError = this.$notification['error']
|
||||
api(this.currentAction.api, params).then(json => {
|
||||
for (const obj in json) {
|
||||
if (obj.includes('response')) {
|
||||
for (const res in json[obj]) {
|
||||
if (res === 'jobid') {
|
||||
this.$store.dispatch('AddAsyncJob', { 'title': this.currentAction.label, 'jobid': json[obj][res], 'description': this.resource.name, 'status': 'progress'})
|
||||
break
|
||||
}
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
closeAction()
|
||||
}).catch(function (error) {
|
||||
closeAction()
|
||||
console.log(error)
|
||||
showError({
|
||||
message: 'Request Failed',
|
||||
description: error.response.headers['x-description']
|
||||
|
||||
@ -17,7 +17,7 @@
|
||||
</a-list-item>
|
||||
<a-list-item v-for="(job, index) in jobs" :key="index">
|
||||
<a-list-item-meta :title="job.title" :description="job.description">
|
||||
<a-avatar :style="job.style" :icon="job.icon" slot="avatar"/>
|
||||
<a-avatar :style="notificationAvatar[job.status].style" :icon="notificationAvatar[job.status].icon" slot="avatar"/>
|
||||
</a-list-item-meta>
|
||||
</a-list-item>
|
||||
</a-list>
|
||||
@ -32,26 +32,89 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { api } from '@/api'
|
||||
import store from '@/store'
|
||||
import { constants } from 'crypto';
|
||||
|
||||
export default {
|
||||
name: 'HeaderNotice',
|
||||
data () {
|
||||
return {
|
||||
loading: false,
|
||||
visible: false,
|
||||
jobs: []
|
||||
jobs: [],
|
||||
poller: null,
|
||||
notificationAvatar: {
|
||||
'done': { 'icon': 'check-circle', 'style': 'backgroundColor:#87d068' },
|
||||
'progress': { 'icon': 'loading', 'style': 'backgroundColor:#ffbf00' },
|
||||
'failed': { 'icon': 'close-circle', 'style': 'backgroundColor:#f56a00' }
|
||||
}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
showNotifications () {
|
||||
this.visible = !this.visible
|
||||
this.jobs.push({ 'title': 'Start VM', description: 'VM Deployment', icon: 'check-circle', status: 'done', style: 'backgroundColor:#87d068' })
|
||||
this.jobs.push({ 'title': 'Start VM', description: 'VM Deployment', icon: 'loading', status: 'progress', style: 'backgroundColor:#ffbf00' })
|
||||
this.jobs.push({ 'title': 'Start VM', description: 'VM Deployment', icon: 'close-circle', status: 'failed', style: 'backgroundColor:#f56a00' })
|
||||
},
|
||||
clearJobs () {
|
||||
this.visible = false
|
||||
this.jobs = []
|
||||
this.$store.commit('SET_ASYNC_JOB_IDS', [])
|
||||
},
|
||||
startPolling() {
|
||||
this.poller = setInterval(() => {
|
||||
this.pollJobs()
|
||||
}, 2500)
|
||||
},
|
||||
async pollJobs () {
|
||||
var hasUpdated = false
|
||||
for (var i in this.jobs) {
|
||||
if (this.jobs[i].status === 'progress') {
|
||||
await api('queryAsyncJobResult', {'jobid': this.jobs[i].jobid}).then(json => {
|
||||
var result = json.queryasyncjobresultresponse
|
||||
if (result.jobstatus === 1 && this.jobs[i].status !== 'done') {
|
||||
hasUpdated = true
|
||||
this.$notification['success']({
|
||||
message: this.jobs[i].title,
|
||||
description: this.jobs[i].description
|
||||
})
|
||||
this.jobs[i].status = 'done'
|
||||
} else if (result.jobstatus === 2 && this.jobs[i].status !== 'failed') {
|
||||
hasUpdated = true
|
||||
this.jobs[i].status = 'failed'
|
||||
if (result.jobresult.errortext !== null) {
|
||||
this.jobs[i].description = '(' + this.jobs[i].description + ') ' + result.jobresult.errortext
|
||||
}
|
||||
this.$notification['error']({
|
||||
message: this.jobs[i].title,
|
||||
description: this.jobs[i].description
|
||||
})
|
||||
}
|
||||
}).catch(function (e) {
|
||||
console.log('Error encountered while fetching async job result' + e)
|
||||
})
|
||||
}
|
||||
}
|
||||
if (hasUpdated) {
|
||||
this.$store.commit('SET_ASYNC_JOB_IDS', this.jobs.reverse())
|
||||
}
|
||||
}
|
||||
},
|
||||
beforeDestroy () {
|
||||
clearInterval(this.poller)
|
||||
},
|
||||
created () {
|
||||
this.startPolling()
|
||||
},
|
||||
mounted () {
|
||||
this.jobs = store.getters.asyncJobIds.reverse()
|
||||
this.$store.watch(
|
||||
(state, getters) => getters.asyncJobIds,
|
||||
(newValue, oldValue) => {
|
||||
if (oldValue !== newValue && newValue !== undefined) {
|
||||
this.jobs = newValue.reverse()
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
4
ui/src/core/bootstrap.js
vendored
4
ui/src/core/bootstrap.js
vendored
@ -12,7 +12,8 @@ import {
|
||||
DEFAULT_FIXED_HEADER_HIDDEN,
|
||||
DEFAULT_FIXED_SIDEMENU,
|
||||
DEFAULT_CONTENT_WIDTH_TYPE,
|
||||
DEFAULT_MULTI_TAB
|
||||
DEFAULT_MULTI_TAB,
|
||||
ASYNC_JOB_IDS
|
||||
} from '@/store/mutation-types'
|
||||
import config from '@/config/settings'
|
||||
|
||||
@ -29,4 +30,5 @@ export default function Initializer () {
|
||||
store.commit('TOGGLE_MULTI_TAB', Vue.ls.get(DEFAULT_MULTI_TAB, config.multiTab))
|
||||
store.commit('SET_TOKEN', Vue.ls.get(ACCESS_TOKEN))
|
||||
store.commit('SET_PROJECT', Vue.ls.get(CURRENT_PROJECT))
|
||||
store.commit('SET_ASYNC_JOB_IDS', Vue.ls.get(ASYNC_JOB_IDS))
|
||||
}
|
||||
|
||||
@ -10,7 +10,8 @@ const getters = {
|
||||
apis: state => state.user.apis,
|
||||
userInfo: state => state.user.info,
|
||||
addRouters: state => state.permission.addRouters,
|
||||
multiTab: state => state.app.multiTab
|
||||
multiTab: state => state.app.multiTab,
|
||||
asyncJobIds: state => state.user.asyncJobIds
|
||||
}
|
||||
|
||||
export default getters
|
||||
|
||||
@ -39,7 +39,6 @@ const app = {
|
||||
state.device = device
|
||||
},
|
||||
TOGGLE_THEME: (state, theme) => {
|
||||
// setStore('_DEFAULT_THEME', theme)
|
||||
Vue.ls.set(DEFAULT_THEME, theme)
|
||||
state.theme = theme
|
||||
},
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
import Vue from 'vue'
|
||||
import md5 from 'md5'
|
||||
import { login, logout, api } from '@/api'
|
||||
import { ACCESS_TOKEN, CURRENT_PROJECT } from '@/store/mutation-types'
|
||||
import { ACCESS_TOKEN, CURRENT_PROJECT, ASYNC_JOB_IDS } from '@/store/mutation-types'
|
||||
import { welcome } from '@/utils/util'
|
||||
// import VueCookies from 'vue-cookies'
|
||||
|
||||
@ -13,7 +13,8 @@ const user = {
|
||||
avatar: '',
|
||||
info: {},
|
||||
apis: {},
|
||||
project: {}
|
||||
project: {},
|
||||
asyncJobIds: []
|
||||
},
|
||||
|
||||
mutations: {
|
||||
@ -36,6 +37,10 @@ const user = {
|
||||
},
|
||||
SET_APIS: (state, apis) => {
|
||||
state.apis = apis
|
||||
},
|
||||
SET_ASYNC_JOB_IDS: (state, jobsJsonArray) => {
|
||||
Vue.ls.set(ASYNC_JOB_IDS, jobsJsonArray)
|
||||
state.asyncJobIds = jobsJsonArray
|
||||
}
|
||||
},
|
||||
|
||||
@ -61,6 +66,7 @@ const user = {
|
||||
Vue.ls.set(ACCESS_TOKEN, result.sessionkey, 60 * 60 * 1000)
|
||||
commit('SET_TOKEN', result.sessionkey)
|
||||
commit('SET_PROJECT', {})
|
||||
commit('SET_ASYNC_JOB_IDS', [])
|
||||
|
||||
resolve()
|
||||
}).catch(error => {
|
||||
@ -104,7 +110,6 @@ const user = {
|
||||
})
|
||||
})
|
||||
},
|
||||
|
||||
Logout ({ commit, state }) {
|
||||
return new Promise((resolve) => {
|
||||
// Remove cookies
|
||||
@ -122,6 +127,7 @@ const user = {
|
||||
commit('SET_APIS', {})
|
||||
Vue.ls.remove(CURRENT_PROJECT)
|
||||
Vue.ls.remove(ACCESS_TOKEN)
|
||||
Vue.ls.remove(ASYNC_JOB_IDS)
|
||||
|
||||
logout(state.token).then(() => {
|
||||
resolve()
|
||||
@ -129,8 +135,12 @@ const user = {
|
||||
resolve()
|
||||
})
|
||||
})
|
||||
},
|
||||
AddAsyncJob ({ commit }, jobJson) {
|
||||
var jobsArray = Vue.ls.get(ASYNC_JOB_IDS, [])
|
||||
jobsArray.push(jobJson)
|
||||
commit('SET_ASYNC_JOB_IDS', jobsArray)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -10,6 +10,7 @@ export const DEFAULT_FIXED_SIDEMENU = 'DEFAULT_FIXED_SIDEMENU'
|
||||
export const DEFAULT_FIXED_HEADER_HIDDEN = 'DEFAULT_FIXED_HEADER_HIDDEN'
|
||||
export const DEFAULT_CONTENT_WIDTH_TYPE = 'DEFAULT_CONTENT_WIDTH_TYPE'
|
||||
export const DEFAULT_MULTI_TAB = 'DEFAULT_MULTI_TAB'
|
||||
export const ASYNC_JOB_IDS = 'ASYNC_JOB_IDS'
|
||||
|
||||
export const CONTENT_WIDTH_TYPE = {
|
||||
Fluid: 'Fluid',
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user