Skip to content

Commit db42cdf

Browse files
Anurag Awasthirohityadavcloud
authored andcommitted
Async job poller and notifications for actions (#32)
Async job poller tech capability implementation, show notifications on success/fail. Signed-off-by: Rohit Yadav <[email protected]>
1 parent 8b9fccd commit db42cdf

File tree

7 files changed

+101
-12
lines changed

7 files changed

+101
-12
lines changed

ui/src/components/CloudMonkey/Resource.vue

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -234,6 +234,7 @@ import DataView from '@/components/widgets/DataView'
234234
import InstanceView from '@/components/widgets/InstanceView'
235235
import Status from '@/components/widgets/Status'
236236
import { mixinDevice } from '@/utils/mixin.js'
237+
import { constants } from 'crypto';
237238
238239
export default {
239240
name: 'Resource',
@@ -506,9 +507,21 @@ export default {
506507
const closeAction = this.closeAction
507508
const showError = this.$notification['error']
508509
api(this.currentAction.api, params).then(json => {
510+
for (const obj in json) {
511+
if (obj.includes('response')) {
512+
for (const res in json[obj]) {
513+
if (res === 'jobid') {
514+
this.$store.dispatch('AddAsyncJob', { 'title': this.currentAction.label, 'jobid': json[obj][res], 'description': this.resource.name, 'status': 'progress'})
515+
break
516+
}
517+
}
518+
break
519+
}
520+
}
509521
closeAction()
510522
}).catch(function (error) {
511523
closeAction()
524+
console.log(error)
512525
showError({
513526
message: 'Request Failed',
514527
description: error.response.headers['x-description']

ui/src/components/tools/HeaderNotice.vue

Lines changed: 68 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
</a-list-item>
1818
<a-list-item v-for="(job, index) in jobs" :key="index">
1919
<a-list-item-meta :title="job.title" :description="job.description">
20-
<a-avatar :style="job.style" :icon="job.icon" slot="avatar"/>
20+
<a-avatar :style="notificationAvatar[job.status].style" :icon="notificationAvatar[job.status].icon" slot="avatar"/>
2121
</a-list-item-meta>
2222
</a-list-item>
2323
</a-list>
@@ -32,26 +32,89 @@
3232
</template>
3333

3434
<script>
35+
import { api } from '@/api'
36+
import store from '@/store'
37+
import { constants } from 'crypto';
38+
3539
export default {
3640
name: 'HeaderNotice',
3741
data () {
3842
return {
3943
loading: false,
4044
visible: false,
41-
jobs: []
45+
jobs: [],
46+
poller: null,
47+
notificationAvatar: {
48+
'done': { 'icon': 'check-circle', 'style': 'backgroundColor:#87d068' },
49+
'progress': { 'icon': 'loading', 'style': 'backgroundColor:#ffbf00' },
50+
'failed': { 'icon': 'close-circle', 'style': 'backgroundColor:#f56a00' }
51+
}
4252
}
4353
},
4454
methods: {
4555
showNotifications () {
4656
this.visible = !this.visible
47-
this.jobs.push({ 'title': 'Start VM', description: 'VM Deployment', icon: 'check-circle', status: 'done', style: 'backgroundColor:#87d068' })
48-
this.jobs.push({ 'title': 'Start VM', description: 'VM Deployment', icon: 'loading', status: 'progress', style: 'backgroundColor:#ffbf00' })
49-
this.jobs.push({ 'title': 'Start VM', description: 'VM Deployment', icon: 'close-circle', status: 'failed', style: 'backgroundColor:#f56a00' })
5057
},
5158
clearJobs () {
5259
this.visible = false
5360
this.jobs = []
61+
this.$store.commit('SET_ASYNC_JOB_IDS', [])
62+
},
63+
startPolling() {
64+
this.poller = setInterval(() => {
65+
this.pollJobs()
66+
}, 2500)
67+
},
68+
async pollJobs () {
69+
var hasUpdated = false
70+
for (var i in this.jobs) {
71+
if (this.jobs[i].status === 'progress') {
72+
await api('queryAsyncJobResult', {'jobid': this.jobs[i].jobid}).then(json => {
73+
var result = json.queryasyncjobresultresponse
74+
if (result.jobstatus === 1 && this.jobs[i].status !== 'done') {
75+
hasUpdated = true
76+
this.$notification['success']({
77+
message: this.jobs[i].title,
78+
description: this.jobs[i].description
79+
})
80+
this.jobs[i].status = 'done'
81+
} else if (result.jobstatus === 2 && this.jobs[i].status !== 'failed') {
82+
hasUpdated = true
83+
this.jobs[i].status = 'failed'
84+
if (result.jobresult.errortext !== null) {
85+
this.jobs[i].description = '(' + this.jobs[i].description + ') ' + result.jobresult.errortext
86+
}
87+
this.$notification['error']({
88+
message: this.jobs[i].title,
89+
description: this.jobs[i].description
90+
})
91+
}
92+
}).catch(function (e) {
93+
console.log('Error encountered while fetching async job result' + e)
94+
})
95+
}
96+
}
97+
if (hasUpdated) {
98+
this.$store.commit('SET_ASYNC_JOB_IDS', this.jobs.reverse())
99+
}
54100
}
101+
},
102+
beforeDestroy () {
103+
clearInterval(this.poller)
104+
},
105+
created () {
106+
this.startPolling()
107+
},
108+
mounted () {
109+
this.jobs = store.getters.asyncJobIds.reverse()
110+
this.$store.watch(
111+
(state, getters) => getters.asyncJobIds,
112+
(newValue, oldValue) => {
113+
if (oldValue !== newValue && newValue !== undefined) {
114+
this.jobs = newValue.reverse()
115+
}
116+
}
117+
)
55118
}
56119
}
57120
</script>

ui/src/core/bootstrap.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,8 @@ import {
1212
DEFAULT_FIXED_HEADER_HIDDEN,
1313
DEFAULT_FIXED_SIDEMENU,
1414
DEFAULT_CONTENT_WIDTH_TYPE,
15-
DEFAULT_MULTI_TAB
15+
DEFAULT_MULTI_TAB,
16+
ASYNC_JOB_IDS
1617
} from '@/store/mutation-types'
1718
import config from '@/config/settings'
1819

@@ -29,4 +30,5 @@ export default function Initializer () {
2930
store.commit('TOGGLE_MULTI_TAB', Vue.ls.get(DEFAULT_MULTI_TAB, config.multiTab))
3031
store.commit('SET_TOKEN', Vue.ls.get(ACCESS_TOKEN))
3132
store.commit('SET_PROJECT', Vue.ls.get(CURRENT_PROJECT))
33+
store.commit('SET_ASYNC_JOB_IDS', Vue.ls.get(ASYNC_JOB_IDS))
3234
}

ui/src/store/getters.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,8 @@ const getters = {
1010
apis: state => state.user.apis,
1111
userInfo: state => state.user.info,
1212
addRouters: state => state.permission.addRouters,
13-
multiTab: state => state.app.multiTab
13+
multiTab: state => state.app.multiTab,
14+
asyncJobIds: state => state.user.asyncJobIds
1415
}
1516

1617
export default getters

ui/src/store/modules/app.js

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,6 @@ const app = {
3939
state.device = device
4040
},
4141
TOGGLE_THEME: (state, theme) => {
42-
// setStore('_DEFAULT_THEME', theme)
4342
Vue.ls.set(DEFAULT_THEME, theme)
4443
state.theme = theme
4544
},

ui/src/store/modules/user.js

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import Vue from 'vue'
22
import md5 from 'md5'
33
import { login, logout, api } from '@/api'
4-
import { ACCESS_TOKEN, CURRENT_PROJECT } from '@/store/mutation-types'
4+
import { ACCESS_TOKEN, CURRENT_PROJECT, ASYNC_JOB_IDS } from '@/store/mutation-types'
55
import { welcome } from '@/utils/util'
66
// import VueCookies from 'vue-cookies'
77

@@ -13,7 +13,8 @@ const user = {
1313
avatar: '',
1414
info: {},
1515
apis: {},
16-
project: {}
16+
project: {},
17+
asyncJobIds: []
1718
},
1819

1920
mutations: {
@@ -36,6 +37,10 @@ const user = {
3637
},
3738
SET_APIS: (state, apis) => {
3839
state.apis = apis
40+
},
41+
SET_ASYNC_JOB_IDS: (state, jobsJsonArray) => {
42+
Vue.ls.set(ASYNC_JOB_IDS, jobsJsonArray)
43+
state.asyncJobIds = jobsJsonArray
3944
}
4045
},
4146

@@ -61,6 +66,7 @@ const user = {
6166
Vue.ls.set(ACCESS_TOKEN, result.sessionkey, 60 * 60 * 1000)
6267
commit('SET_TOKEN', result.sessionkey)
6368
commit('SET_PROJECT', {})
69+
commit('SET_ASYNC_JOB_IDS', [])
6470

6571
resolve()
6672
}).catch(error => {
@@ -104,7 +110,6 @@ const user = {
104110
})
105111
})
106112
},
107-
108113
Logout ({ commit, state }) {
109114
return new Promise((resolve) => {
110115
// Remove cookies
@@ -122,15 +127,20 @@ const user = {
122127
commit('SET_APIS', {})
123128
Vue.ls.remove(CURRENT_PROJECT)
124129
Vue.ls.remove(ACCESS_TOKEN)
130+
Vue.ls.remove(ASYNC_JOB_IDS)
125131

126132
logout(state.token).then(() => {
127133
resolve()
128134
}).catch(() => {
129135
resolve()
130136
})
131137
})
138+
},
139+
AddAsyncJob ({ commit }, jobJson) {
140+
var jobsArray = Vue.ls.get(ASYNC_JOB_IDS, [])
141+
jobsArray.push(jobJson)
142+
commit('SET_ASYNC_JOB_IDS', jobsArray)
132143
}
133-
134144
}
135145
}
136146

ui/src/store/mutation-types.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ export const DEFAULT_FIXED_SIDEMENU = 'DEFAULT_FIXED_SIDEMENU'
1010
export const DEFAULT_FIXED_HEADER_HIDDEN = 'DEFAULT_FIXED_HEADER_HIDDEN'
1111
export const DEFAULT_CONTENT_WIDTH_TYPE = 'DEFAULT_CONTENT_WIDTH_TYPE'
1212
export const DEFAULT_MULTI_TAB = 'DEFAULT_MULTI_TAB'
13+
export const ASYNC_JOB_IDS = 'ASYNC_JOB_IDS'
1314

1415
export const CONTENT_WIDTH_TYPE = {
1516
Fluid: 'Fluid',

0 commit comments

Comments
 (0)