1616// under the License.
1717
1818<template >
19- <div >
20- {{ resource }}
21- This needs to implement migrate wizard
22- </div >
19+ <a-list :dataSource =" hosts" itemLayout =" vertical" class =" list" :loading =" loading" >
20+ <div slot =" header" class =" list__header" >
21+ <a-input-search
22+ placeholder =" Search"
23+ v-model =" searchQuery"
24+ @search =" fetchData" />
25+ </div >
26+ <a-list-item
27+ slot =" renderItem"
28+ slot-scope =" host, index"
29+ class =" host-item"
30+ :class =" { 'host-item--selected' : selectedIndex === index }"
31+ >
32+ <div class =" host-item__row" >
33+ <div class =" host-item__value" >
34+ <span class =" host-item__title" >{{ $t('name') }}</span >
35+ {{ host.name }}
36+ </div >
37+ <div class =" host-item__value host-item__value--small" >
38+ <span class =" host-item__title" >Suitability</span >
39+ <a-icon
40+ class =" host-item__suitability-icon"
41+ type =" check-circle"
42+ theme =" twoTone"
43+ twoToneColor =" #52c41a"
44+ v-if =" host.suitableformigration" />
45+ <a-icon
46+ class =" host-item__suitability-icon"
47+ type =" close-circle"
48+ theme =" twoTone"
49+ twoToneColor =" #f5222d"
50+ v-else />
51+ </div >
52+ <div class =" host-item__value host-item__value--full" >
53+ <span class =" host-item__title" >{{ $t('cpuused') }}</span >
54+ {{ host.cpuused }}
55+ </div >
56+ <div class =" host-item__value" >
57+ <span class =" host-item__title" >{{ $t('memused') }}</span >
58+ {{ host.memoryused | byteToGigabyte }} GB
59+ </div >
60+ <a-radio
61+ class =" host-item__radio"
62+ @click =" selectedIndex = index"
63+ :checked =" selectedIndex === index"
64+ :disabled =" !host.suitableformigration" ></a-radio >
65+ </div >
66+ </a-list-item >
67+ <div slot =" footer" class =" list__footer" >
68+ <a-button type =" primary" :disabled =" selectedIndex === null" @click =" submitForm" >
69+ {{ $t('OK') }}
70+ </a-button >
71+ </div >
72+ </a-list >
2373</template >
2474
2575<script >
76+ import { api } from ' @/api'
77+ import { pollActionCompletion } from ' @/utils/methods'
2678
2779export default {
2880 name: ' VMMigrateWizard' ,
29- components: {
30- },
3181 props: {
3282 resource: {
3383 type: Object ,
@@ -36,12 +86,152 @@ export default {
3686 },
3787 data () {
3888 return {
89+ loading: true ,
90+ hosts: [],
91+ selectedIndex: null ,
92+ searchQuery: ' '
3993 }
4094 },
95+ mounted () {
96+ this .fetchData ()
97+ },
4198 methods: {
99+ fetchData () {
100+ this .loading = true
101+ api (' findHostsForMigration' , {
102+ virtualmachineid: this .resource .id ,
103+ keyword: this .searchQuery ,
104+ page: 1 ,
105+ pagesize: 500
106+ }).then (response => {
107+ this .hosts = response .findhostsformigrationresponse .host
108+ this .loading = false
109+ }).catch (error => {
110+ this .$message .error (' Failed to load hosts: ' + error)
111+ })
112+ },
113+ submitForm () {
114+ this .loading = true
115+ api (' migrateVirtualMachine' , {
116+ hostid: this .hosts [this .selectedIndex ].id ,
117+ virtualmachineid: this .resource .id
118+ }).then (response => {
119+ this .$store .dispatch (' AddAsyncJob' , {
120+ title: ` Migrating ${ this .resource .name } ` ,
121+ jobid: response .migratevirtualmachineresponse .jobid ,
122+ description: this .resource .name ,
123+ status: ' progress'
124+ })
125+ pollActionCompletion ({
126+ jobId: response .migratevirtualmachineresponse .jobid ,
127+ successMessage: ` Migration completed successfully for ${ this .resource .name } ` ,
128+ successMethod : () => {
129+ this .$parent .$parent .close ()
130+ },
131+ errorMessage: ' Migration failed' ,
132+ errorMethod : () => {
133+ this .$parent .$parent .close ()
134+ },
135+ loadingMessage: ` Migration in progress for ${ this .resource .name } ` ,
136+ catchMessage: ' Error encountered while fetching async job result' ,
137+ catchMethod : () => {
138+ this .$parent .$parent .close ()
139+ }
140+ })
141+ this .$parent .$parent .close ()
142+ }).catch (error => {
143+ console .error (error)
144+ this .$message .error (' Failed to migrate host.' )
145+ })
146+ }
147+ },
148+ filters: {
149+ byteToGigabyte : value => {
150+ if (! value) return ' '
151+ value = value / Math .pow (10 , 9 )
152+ return value .toFixed (2 )
153+ }
42154 }
43155}
44156 </script >
45157
46- <style scoped>
158+ <style scoped lang="scss">
159+
160+ .list {
161+ max-height : 95vh ;
162+ width : 95vw ;
163+ overflow-y : scroll ;
164+ margin : -24px ;
165+
166+ @media (min-width : 1000px ) {
167+ max-height : 70vh ;
168+ width : 60vw ;
169+ }
170+
171+ & __header ,
172+ & __footer {
173+ padding-left : 20px ;
174+ padding-right : 20px ;
175+ }
176+
177+ & __footer {
178+ display : flex ;
179+ justify-content : flex-end ;
180+ }
181+
182+ }
183+
184+ .host-item {
185+ padding-right : 20px ;
186+ padding-bottom : 0 ;
187+ padding-left : 20px ;
188+
189+ & --selected {
190+ background-color : #e6f7ff ;
191+ }
192+
193+ & __row {
194+ display : flex ;
195+ flex-direction : column ;
196+ width : 100% ;
197+
198+ @media (min-width : 760px ) {
199+ flex-direction : row ;
200+ }
201+
202+ }
203+
204+ & __value {
205+ display : flex ;
206+ flex-direction : column ;
207+ align-items : flex-start ;
208+ flex : 1 ;
209+ margin-bottom : 10px ;
210+
211+ & --small {
212+
213+ @media (min-width : 760px ) {
214+ flex : none ;
215+ margin-right : 40px ;
216+ margin-left : 40px ;
217+ }
218+
219+ }
220+
221+ }
222+
223+ & __title {
224+ font-weight : bold ;
225+ }
226+
227+ & __suitability-icon {
228+ margin-top : 5px ;
229+ }
230+
231+ & __radio {
232+ display : flex ;
233+ align-items : center ;
234+ }
235+
236+ }
47237 </style >
0 commit comments