mirror of
				https://github.com/apache/cloudstack.git
				synced 2025-10-26 08:42:29 +01:00 
			
		
		
		
	compute: NICs and IPs management (#71)
Adds VM nic/ip management, implement some placement fixes. Signed-off-by: Rohit Yadav <rohit.yadav@shapeblue.com>
This commit is contained in:
		
							parent
							
								
									200f89bc08
								
							
						
					
					
						commit
						b140b738fb
					
				
							
								
								
									
										58
									
								
								ui/package-lock.json
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										58
									
								
								ui/package-lock.json
									
									
									
										generated
									
									
									
								
							| @ -2341,9 +2341,9 @@ | ||||
|       } | ||||
|     }, | ||||
|     "@fortawesome/vue-fontawesome": { | ||||
|       "version": "0.1.8", | ||||
|       "resolved": "https://registry.npmjs.org/@fortawesome/vue-fontawesome/-/vue-fontawesome-0.1.8.tgz", | ||||
|       "integrity": "sha512-SdFiUD+vFDA/xKuEbnQTVrK8FDxoV0eyQaiHxmCcjAc0+vQe0Kf6oGm28opNPIt8MTgKWR3+Yg3xXP455Ae4tQ==" | ||||
|       "version": "0.1.9", | ||||
|       "resolved": "https://registry.npmjs.org/@fortawesome/vue-fontawesome/-/vue-fontawesome-0.1.9.tgz", | ||||
|       "integrity": "sha512-h/emhmZz+DfB2zOGLWawNwXq82UYhn9waTfUjLLmeaIqtnIyNt6kYlpQT/vzJjLZRDRvY2IEJAh1di5qKpKVpA==" | ||||
|     }, | ||||
|     "@hapi/address": { | ||||
|       "version": "2.1.4", | ||||
| @ -8526,9 +8526,9 @@ | ||||
|       } | ||||
|     }, | ||||
|     "core-js": { | ||||
|       "version": "3.4.8", | ||||
|       "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.4.8.tgz", | ||||
|       "integrity": "sha512-b+BBmCZmVgho8KnBUOXpvlqEMguko+0P+kXCwD4vIprsXC6ht1qgPxtb1OK6XgSlrySF71wkwBQ0Hv695bk9gQ==" | ||||
|       "version": "3.5.0", | ||||
|       "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.5.0.tgz", | ||||
|       "integrity": "sha512-Ifh3kj78gzQ7NAoJXeTu+XwzDld0QRIwjBLRqAMhuLhP3d2Av5wmgE9ycfnvK6NAEjTkQ1sDPeoEZAWO3Hx1Uw==" | ||||
|     }, | ||||
|     "core-js-compat": { | ||||
|       "version": "3.4.7", | ||||
| @ -10009,9 +10009,9 @@ | ||||
|       "dev": true | ||||
|     }, | ||||
|     "elliptic": { | ||||
|       "version": "6.5.1", | ||||
|       "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.5.1.tgz", | ||||
|       "integrity": "sha512-xvJINNLbTeWQjrl6X+7eQCrIy/YPv5XCpKW6kB5mKvtnGILoLDcySuwomfdzt0BMdLNVnuRNTuzKNHj0bva1Cg==", | ||||
|       "version": "6.5.2", | ||||
|       "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.5.2.tgz", | ||||
|       "integrity": "sha512-f4x70okzZbIQl/NSRLkI/+tteV/9WqL98zx+SQ69KbXxmVrmjwsNUPn/gYJJ0sHvEak24cZgHIPegRePAtA/xw==", | ||||
|       "dev": true, | ||||
|       "requires": { | ||||
|         "bn.js": "^4.4.0", | ||||
| @ -20621,9 +20621,9 @@ | ||||
|       } | ||||
|     }, | ||||
|     "serialize-javascript": { | ||||
|       "version": "1.9.1", | ||||
|       "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-1.9.1.tgz", | ||||
|       "integrity": "sha512-0Vb/54WJ6k5v8sSWN09S0ora+Hnr+cX40r9F170nT+mSkaxltoE/7R3OrIdBSUv1OoiobH1QoWQbCnAO+e8J1A==", | ||||
|       "version": "2.1.2", | ||||
|       "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-2.1.2.tgz", | ||||
|       "integrity": "sha512-rs9OggEUF0V4jUSecXazOYsLfu7OGK2qIn3c7IPBiffz32XniEp/TX9Xmc9LQfK2nQ2QKHvZ2oygKUGU0lG4jQ==", | ||||
|       "dev": true | ||||
|     }, | ||||
|     "serve-index": { | ||||
| @ -22016,16 +22016,16 @@ | ||||
|       } | ||||
|     }, | ||||
|     "terser-webpack-plugin": { | ||||
|       "version": "1.4.1", | ||||
|       "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-1.4.1.tgz", | ||||
|       "integrity": "sha512-ZXmmfiwtCLfz8WKZyYUuuHf3dMYEjg8NrjHMb0JqHVHVOSkzp3cW2/XG1fP3tRhqEqSzMwzzRQGtAPbs4Cncxg==", | ||||
|       "version": "1.4.3", | ||||
|       "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-1.4.3.tgz", | ||||
|       "integrity": "sha512-QMxecFz/gHQwteWwSo5nTc6UaICqN1bMedC5sMtUc7y3Ha3Q8y6ZO0iCR8pq4RJC8Hjf0FEPEHZqcMB/+DFCrA==", | ||||
|       "dev": true, | ||||
|       "requires": { | ||||
|         "cacache": "^12.0.2", | ||||
|         "find-cache-dir": "^2.1.0", | ||||
|         "is-wsl": "^1.1.0", | ||||
|         "schema-utils": "^1.0.0", | ||||
|         "serialize-javascript": "^1.7.0", | ||||
|         "serialize-javascript": "^2.1.2", | ||||
|         "source-map": "^0.6.1", | ||||
|         "terser": "^4.1.2", | ||||
|         "webpack-sources": "^1.4.0", | ||||
| @ -23005,9 +23005,9 @@ | ||||
|       "dev": true | ||||
|     }, | ||||
|     "vue": { | ||||
|       "version": "2.6.10", | ||||
|       "resolved": "https://registry.npmjs.org/vue/-/vue-2.6.10.tgz", | ||||
|       "integrity": "sha512-ImThpeNU9HbdZL3utgMCq0oiMzAkt1mcgy3/E6zWC/G6AaQoeuFdsl9nDhTDU3X1R6FK7nsIUuRACVcjI+A2GQ==" | ||||
|       "version": "2.6.11", | ||||
|       "resolved": "https://registry.npmjs.org/vue/-/vue-2.6.11.tgz", | ||||
|       "integrity": "sha512-VfPwgcGABbGAue9+sfrD4PuwFar7gPb1yl1UK1MwXoQPAw0BKSqWfoYCT/ThFrdEVWoI51dBuyCoiNU9bZDZxQ==" | ||||
|     }, | ||||
|     "vue-cli-plugin-apollo": { | ||||
|       "version": "0.21.3", | ||||
| @ -23259,9 +23259,9 @@ | ||||
|       "dev": true | ||||
|     }, | ||||
|     "vue-i18n": { | ||||
|       "version": "8.15.1", | ||||
|       "resolved": "https://registry.npmjs.org/vue-i18n/-/vue-i18n-8.15.1.tgz", | ||||
|       "integrity": "sha512-GBbz8qYCu0U2LNu4IcuFLZiuyninG4k26knvhL7GZG5Ncp4RR2VKDEH6g8gQ6I+UUBCvH2MBQVPSdxWe4DBkPw==" | ||||
|       "version": "8.15.3", | ||||
|       "resolved": "https://registry.npmjs.org/vue-i18n/-/vue-i18n-8.15.3.tgz", | ||||
|       "integrity": "sha512-PVNgo6yhOmacZVFjSapZ314oewwLyXHjJwAqjnaPN1GJAJd/dvsrShGzSiJuCX4Hc36G4epJvNXUwO8y7wEKew==" | ||||
|     }, | ||||
|     "vue-i18n-extract": { | ||||
|       "version": "0.4.14", | ||||
| @ -23506,9 +23506,9 @@ | ||||
|       } | ||||
|     }, | ||||
|     "vue-template-compiler": { | ||||
|       "version": "2.6.10", | ||||
|       "resolved": "https://registry.npmjs.org/vue-template-compiler/-/vue-template-compiler-2.6.10.tgz", | ||||
|       "integrity": "sha512-jVZkw4/I/HT5ZMvRnhv78okGusqe0+qH2A0Em0Cp8aq78+NK9TII263CDVz2QXZsIT+yyV/gZc/j/vlwa+Epyg==", | ||||
|       "version": "2.6.11", | ||||
|       "resolved": "https://registry.npmjs.org/vue-template-compiler/-/vue-template-compiler-2.6.11.tgz", | ||||
|       "integrity": "sha512-KIq15bvQDrcCjpGjrAhx4mUlyyHfdmTaoNfeoATHLAiWB+MU3cx4lOzMwrnUh9cCxy0Lt1T11hAFY6TQgroUAA==", | ||||
|       "dev": true, | ||||
|       "requires": { | ||||
|         "de-indent": "^1.0.2", | ||||
| @ -23607,9 +23607,9 @@ | ||||
|       "dev": true | ||||
|     }, | ||||
|     "webpack": { | ||||
|       "version": "4.41.2", | ||||
|       "resolved": "https://registry.npmjs.org/webpack/-/webpack-4.41.2.tgz", | ||||
|       "integrity": "sha512-Zhw69edTGfbz9/8JJoyRQ/pq8FYUoY0diOXqW0T6yhgdhCv6wr0hra5DwwWexNRns2Z2+gsnrNcbe9hbGBgk/A==", | ||||
|       "version": "4.41.3", | ||||
|       "resolved": "https://registry.npmjs.org/webpack/-/webpack-4.41.3.tgz", | ||||
|       "integrity": "sha512-EcNzP9jGoxpQAXq1VOoTet0ik7/VVU1MovIfcUSAjLowc7GhcQku/sOXALvq5nPpSei2HF6VRhibeJSC3i/Law==", | ||||
|       "dev": true, | ||||
|       "requires": { | ||||
|         "@webassemblyjs/ast": "1.8.5", | ||||
| @ -23632,7 +23632,7 @@ | ||||
|         "node-libs-browser": "^2.2.1", | ||||
|         "schema-utils": "^1.0.0", | ||||
|         "tapable": "^1.1.3", | ||||
|         "terser-webpack-plugin": "^1.4.1", | ||||
|         "terser-webpack-plugin": "^1.4.3", | ||||
|         "watchpack": "^1.6.0", | ||||
|         "webpack-sources": "^1.4.1" | ||||
|       } | ||||
|  | ||||
| @ -37,10 +37,10 @@ | ||||
|     "@fortawesome/free-brands-svg-icons": "^5.12.0", | ||||
|     "@fortawesome/free-regular-svg-icons": "^5.12.0", | ||||
|     "@fortawesome/free-solid-svg-icons": "^5.12.0", | ||||
|     "@fortawesome/vue-fontawesome": "^0.1.8", | ||||
|     "@fortawesome/vue-fontawesome": "^0.1.9", | ||||
|     "ant-design-vue": "~1.4.10", | ||||
|     "axios": "^0.19.0", | ||||
|     "core-js": "^3.4.8", | ||||
|     "core-js": "^3.5.0", | ||||
|     "enquire.js": "^2.1.6", | ||||
|     "js-cookie": "^2.2.1", | ||||
|     "lodash.get": "^4.4.2", | ||||
| @ -51,10 +51,10 @@ | ||||
|     "npm-check-updates": "^4.0.1", | ||||
|     "nprogress": "^0.2.0", | ||||
|     "viser-vue": "^2.4.7", | ||||
|     "vue": "^2.6.10", | ||||
|     "vue": "^2.6.11", | ||||
|     "vue-clipboard2": "^0.3.1", | ||||
|     "vue-cropper": "0.4.9", | ||||
|     "vue-i18n": "^8.15.1", | ||||
|     "vue-i18n": "^8.15.3", | ||||
|     "vue-ls": "^3.2.1", | ||||
|     "vue-router": "^3.1.3", | ||||
|     "vue-svg-component-runtime": "^1.0.1", | ||||
| @ -87,8 +87,8 @@ | ||||
|     "sass-loader": "^8.0.0", | ||||
|     "vue-cli-plugin-i18n": "^0.6.0", | ||||
|     "vue-svg-icon-loader": "^2.1.1", | ||||
|     "vue-template-compiler": "^2.6.10", | ||||
|     "webpack": "^4.41.2" | ||||
|     "vue-template-compiler": "^2.6.11", | ||||
|     "webpack": "^4.41.3" | ||||
|   }, | ||||
|   "eslintConfig": { | ||||
|     "root": true, | ||||
|  | ||||
| @ -35,13 +35,36 @@ | ||||
|         :dataSource="detailOptions[newKey]" | ||||
|         placeholder="Value" | ||||
|         @change="e => onAddInputChange(e, 'newValue')" /> | ||||
|       <a-button type="dashed" style="width: 50%" icon="close" @click="showAddDetail = false">Cancel</a-button> | ||||
|       <a-button type="primary" style="width: 50%" icon="plus" @click="addDetail">Add Setting</a-button> | ||||
|       <a-button type="primary" style="width: 25%" icon="plus" @click="addDetail">Add Setting</a-button> | ||||
|       <a-button type="dashed" style="width: 25%" icon="close" @click="showAddDetail = false">Cancel</a-button> | ||||
|     </div> | ||||
|     <a-list size="large"> | ||||
|       <a-list-item :key="index" v-for="(item, index) in details"> | ||||
|         <a-list-item-meta> | ||||
|           <span slot="title"><strong>{{ item.name }}</strong></span> | ||||
|           <span slot="title"> | ||||
|             {{ item.name }} | ||||
|             <a-button shape="circle" size="small" @click="updateDetail(index)" v-if="item.edit"> | ||||
|               <a-icon type="check-circle" theme="twoTone" twoToneColor="#52c41a" /> | ||||
|             </a-button> | ||||
|             <a-button shape="circle" size="small" @click="hideEditDetail(index)" v-if="item.edit" style="margin-left: 5px"> | ||||
|               <a-icon type="close-circle" theme="twoTone" twoToneColor="#f5222d" /> | ||||
|             </a-button> | ||||
|             <a-button shape="circle" size="small" @click="showEditDetail(index)" v-if="!item.edit"> | ||||
|               <a-icon type="edit" /> | ||||
|             </a-button> | ||||
|             <a-divider type="vertical" /> | ||||
|             <a-popconfirm | ||||
|               title="Delete setting?" | ||||
|               @confirm="deleteDetail(index)" | ||||
|               okText="Yes" | ||||
|               cancelText="No" | ||||
|               placement="right" | ||||
|             > | ||||
|               <a-button shape="circle" size="small"> | ||||
|                 <a-icon type="delete" theme="twoTone" twoToneColor="#f5222d" /> | ||||
|               </a-button> | ||||
|             </a-popconfirm> | ||||
|           </span> | ||||
|           <span slot="description" style="word-break: break-all"> | ||||
|             <span v-if="item.edit" style="display: flex"> | ||||
|               <a-auto-complete | ||||
| @ -54,30 +77,6 @@ | ||||
|             <span v-else @click="showEditDetail(index)">{{ item.value }}</span> | ||||
|           </span> | ||||
|         </a-list-item-meta> | ||||
|         <div slot="actions"> | ||||
|           <a-button shape="circle" size="default" @click="updateDetail(index)" v-if="item.edit"> | ||||
|             <a-icon type="check-circle" theme="twoTone" twoToneColor="#52c41a" /> | ||||
|           </a-button> | ||||
|           <a-button shape="circle" size="default" @click="hideEditDetail(index)" v-if="item.edit"> | ||||
|             <a-icon type="close-circle" theme="twoTone" twoToneColor="#f5222d" /> | ||||
|           </a-button> | ||||
|           <a-button shape="circle" @click="showEditDetail(index)" v-if="!item.edit"> | ||||
|             <a-icon type="edit" /> | ||||
|           </a-button> | ||||
|         </div> | ||||
|         <div slot="actions"> | ||||
|           <a-popconfirm | ||||
|             title="Delete setting?" | ||||
|             @confirm="deleteDetail(index)" | ||||
|             okText="Yes" | ||||
|             cancelText="No" | ||||
|             placement="left" | ||||
|           > | ||||
|             <a-button shape="circle"> | ||||
|               <a-icon type="delete" theme="twoTone" twoToneColor="#f5222d" /> | ||||
|             </a-button> | ||||
|           </a-popconfirm> | ||||
|         </div> | ||||
|       </a-list-item> | ||||
|     </a-list> | ||||
|   </a-spin> | ||||
|  | ||||
| @ -17,13 +17,13 @@ | ||||
| 
 | ||||
| <template> | ||||
|   <a-table | ||||
|     size="small" | ||||
|     size="middle" | ||||
|     :loading="loading" | ||||
|     :columns="columns" | ||||
|     :dataSource="items" | ||||
|     :rowKey="record => record.id || record.name" | ||||
|     :pagination="false" | ||||
|     :rowSelection="{selectedRowKeys: selectedRowKeys, onChange: onSelectChange}" | ||||
|     :rowSelection="['vm', 'event', 'alert'].includes($route.name) ? {selectedRowKeys: selectedRowKeys, onChange: onSelectChange} : null" | ||||
|     :rowClassName="getRowClassName" | ||||
|   > | ||||
|     <template slot="footer"> | ||||
| @ -33,7 +33,7 @@ | ||||
|     </template> | ||||
| 
 | ||||
|     <a slot="name" slot-scope="text, record" href="javascript:;"> | ||||
|       <div> | ||||
|       <div style="min-width: 150px; padding-left: 5px"> | ||||
|         <span v-if="$route.path.startsWith('/project')" style="margin-right: 5px"> | ||||
|           <a-button type="dashed" size="small" shape="circle" icon="login" @click="changeProject(record)" /> | ||||
|         </span> | ||||
| @ -41,7 +41,7 @@ | ||||
|         <router-link :to="{ path: $route.path + '/' + record.id }" v-if="record.id">{{ text }}</router-link> | ||||
|         <router-link :to="{ path: $route.path + '/' + record.name }" v-else>{{ text }}</router-link> | ||||
|       </div> | ||||
|       <div v-if="$route.meta.related" style="padding-top: 5px"> | ||||
|       <div v-if="$route.meta.related" style="padding-top: 10px; padding-left: 5px; display: inline-flex"> | ||||
|         <span v-for="item in $route.meta.related" :key="item.path"> | ||||
|           <router-link | ||||
|             v-if="$router.resolve('/' + item.name).route.name !== '404'" | ||||
|  | ||||
| @ -2,7 +2,7 @@ | ||||
|   <a-list size="large" class="list" :loading="loading || tabLoading"> | ||||
|     <a-list-item :key="index" v-for="(item, index) in items" class="item"> | ||||
|       <a-list-item-meta> | ||||
|         <span slot="title" style="word-break: break-all"><strong>{{ item.name }}</strong></span> | ||||
|         <span slot="title" style="word-break: break-all">{{ item.name }}</span> | ||||
|         <span slot="description" style="word-break: break-all">{{ item.description }}</span> | ||||
|       </a-list-item-meta> | ||||
| 
 | ||||
|  | ||||
| @ -173,8 +173,16 @@ export default { | ||||
|           icon: 'safety-certificate', | ||||
|           label: 'Add certificate', | ||||
|           dataView: true, | ||||
|           args: ['name', 'certificate', 'privatekey', 'certchain', 'password'], | ||||
|           show: (record) => { return record.state === 'enabled' } | ||||
|           args: ['name', 'certificate', 'privatekey', 'certchain', 'password', 'account', 'domainid'], | ||||
|           show: (record) => { return record.state === 'enabled' }, | ||||
|           mapping: { | ||||
|             account: { | ||||
|               value: (record) => { return record.name } | ||||
|             }, | ||||
|             domainid: { | ||||
|               value: (record) => { return record.domainid } | ||||
|             } | ||||
|           } | ||||
|         }, | ||||
|         { | ||||
|           api: 'deleteAccount', | ||||
|  | ||||
| @ -134,6 +134,7 @@ | ||||
| "current": "isCurrent", | ||||
| "date": "Date", | ||||
| "dedicated": "Dedicated", | ||||
| "default": "Default", | ||||
| "deleteconfirm": "Please confirm that you would like to delete this {name}", | ||||
| "deleteprofile": "Delete Profile", | ||||
| "deploymentPlanner": "Deployment planner", | ||||
| @ -632,6 +633,10 @@ | ||||
| "memused": "Memory Usage", | ||||
| "message.edit.account": "Edit (\"-1\" indicates no limit to the amount of resources create)", | ||||
| "message.assign.instance.another": "Please specify the account type, domain, account name and network (optional) of the new account. <br> If the default nic of the vm is on a shared network, CloudStack will check if the network can be used by the new account if you do not specify one network. <br> If the default nic of the vm is on a isolated network, and the new account has more one isolated networks, you should specify one.", | ||||
| "message.network.addVM.desc":"Please specify the network that you would like to add this VM to. A new NIC will be added for this network.", | ||||
| "message.network.removeNIC": "Please confirm that want to remove this NIC, which will also remove the associated network from the VM.", | ||||
| "message.network.secondaryIP" : "Please confirm that you would like to acquire a new secondary IP for this NIC. \n NOTE: You need to manually configure the newly-acquired secondary IP inside the virtual machine.", | ||||
| "message.network.updateIp": "Please confirm that you would like to change the IP address for this NIC on VM.", | ||||
| "minCPUNumber": "Min CPU Cores", | ||||
| "minInstance": "Min Instances", | ||||
| "minIops": "Min IOPS", | ||||
| @ -729,6 +734,7 @@ | ||||
| "protocolnumber": "#Protocol", | ||||
| "provider": "HA Provider", | ||||
| "providername": "Provider", | ||||
| "provisioning": "Provisioning", | ||||
| "provisioningType": "Provisioning Type", | ||||
| "provisioningtype": "Provisioning Type", | ||||
| "publicinterface": "Public Interface", | ||||
| @ -754,6 +760,7 @@ | ||||
| "redundantstate": "Redundant state", | ||||
| "redundantvpcrouter": "Redundant VPC", | ||||
| "reenterpassword": "Re-enter Password", | ||||
| "refresh": "Refresh", | ||||
| "relationaloperator": "Operator", | ||||
| "required": "Required", | ||||
| "requireshvm": "HVM", | ||||
| @ -946,6 +953,7 @@ | ||||
| "zoneId": "Zone", | ||||
| "zoneid": "Zone", | ||||
| "zonename": "Zone", | ||||
| "zonenamelabel": "Zone Name", | ||||
| "instance": "Instance", | ||||
| "yourInstance": "Your instance", | ||||
| "newInstance": "New instance", | ||||
|  | ||||
| @ -19,23 +19,25 @@ | ||||
|   <div> | ||||
|     <a-card class="breadcrumb-card"> | ||||
|       <a-row> | ||||
|         <a-col :span="12"> | ||||
|           <breadcrumb style="padding-top: 6px" /> | ||||
|         </a-col> | ||||
|         <a-col :span="12"> | ||||
|           <span style="float: right"> | ||||
|         <a-col :span="24" style="display: flex"> | ||||
|           <breadcrumb /> | ||||
|           <a-tooltip placement="bottom"> | ||||
|             <template slot="title"> | ||||
|               {{ "Refresh" }} | ||||
|             </template> | ||||
|             <a-button | ||||
|               style="margin-left: 8px" | ||||
|               :loading="loading" | ||||
|                 shape="circle" | ||||
|                 type="dashed" | ||||
|                 icon="reload" | ||||
|                 style="margin-right: 5px" | ||||
|                 @click="fetchData()" /> | ||||
|               shape="round" | ||||
|               size="small" | ||||
|               icon="sync" | ||||
|               @click="fetchData()"> | ||||
|               {{ $t('refresh') }} | ||||
|             </a-button> | ||||
|           </a-tooltip> | ||||
|         </a-col> | ||||
|         <a-col :span="24" style="padding-top: 12px; margin-bottom: -6px"> | ||||
|           <span style="padding-left: 5px"> | ||||
|             <a-tooltip | ||||
|               v-for="(action, actionIndex) in actions" | ||||
|               :key="actionIndex" | ||||
| @ -56,7 +58,7 @@ | ||||
|               </a-button> | ||||
|             </a-tooltip> | ||||
|             <a-input-search | ||||
|               style="width: unset" | ||||
|               style="width: 50%; padding-left: 6px" | ||||
|               placeholder="Search" | ||||
|               v-model="searchQuery" | ||||
|               v-if="!dataView && !treeView" | ||||
|  | ||||
| @ -17,18 +17,22 @@ | ||||
| 
 | ||||
| <template> | ||||
|   <div> | ||||
|     <a-collapse v-model="activeKey"> | ||||
|     <a-collapse v-model="activeKey" :bordered="false"> | ||||
| 
 | ||||
|       <a-collapse-panel :header="'ISO: ' + vm.isoname" v-if="vm.isoid" key="1"> | ||||
|         <a-list | ||||
|           itemLayout="horizontal"> | ||||
|           <a-list-item> | ||||
|             <a-list-item-meta :description="vm.isoid"> | ||||
|               <a slot="title" href=""> | ||||
|                 <router-link :to="{ path: '/iso/' + vm.isoid }">{{ vm.isoname }}</router-link> | ||||
|               </a> ({{ vm.isoname }}) | ||||
|               <a-avatar slot="avatar"> | ||||
|             <a-list-item-meta> | ||||
|               <div slot="avatar"> | ||||
|                 <a-avatar> | ||||
|                   <a-icon type="usb" /> | ||||
|                 </a-avatar> | ||||
|               </div> | ||||
|               <div slot="title"> | ||||
|                 <router-link :to="{ path: '/iso/' + vm.isoid }">{{ vm.isoname }}</router-link> <br/> | ||||
|                 <a-icon type="barcode"/> {{ vm.isoid }} | ||||
|               </div> | ||||
|             </a-list-item-meta> | ||||
|           </a-list-item> | ||||
|         </a-list> | ||||
| @ -42,59 +46,220 @@ | ||||
|         > | ||||
|           <a-list-item slot="renderItem" slot-scope="item"> | ||||
|             <a-list-item-meta> | ||||
|               <div slot="title"> | ||||
|                 <router-link :to="{ path: '/volume/' + item.id }">{{ item.name }}</router-link> ({{ item.type }}) <br/> | ||||
|                 <status :text="item.state" displayText /><br/> | ||||
|               </div> | ||||
|               <div slot="description"> | ||||
|                 <a-icon type="barcode"/> {{ item.id }} | ||||
|               </div> | ||||
|               <a-avatar slot="avatar"> | ||||
|               <div slot="avatar"> | ||||
|                 <a-avatar> | ||||
|                   <a-icon type="hdd" /> | ||||
|                 </a-avatar> | ||||
|               </div> | ||||
|               <div slot="title"> | ||||
|                 <router-link :to="{ path: '/volume/' + item.id }">{{ item.name }} </router-link> | ||||
|                 <a-tag v-if="item.type"> | ||||
|                   {{ item.type }} | ||||
|                 </a-tag> | ||||
|                 <a-tag v-if="item.state"> | ||||
|                   {{ item.state }} | ||||
|                 </a-tag> | ||||
|                 <a-tag v-if="item.provisioningtype"> | ||||
|                   {{ item.provisioningtype }} | ||||
|                 </a-tag> | ||||
|                 <br/> | ||||
|                 {{ $t('size') }}: {{ (item.size / (1024 * 1024 * 1024.0)).toFixed(2) }} GB<br/> | ||||
|                 {{ $t('physicalsize') }}: {{ (item.physicalsize / (1024 * 1024 * 1024.0)).toFixed(4) }} GB<br/> | ||||
|                 {{ $t('storagePool') }}: {{ item.storage }} ({{ item.storagetype }})<br/> | ||||
|                 <a-icon type="barcode"/> {{ item.id }} <br/> | ||||
|               </div> | ||||
|             </a-list-item-meta> | ||||
|             <p> | ||||
|               Size: {{ (item.size / (1024 * 1024 * 1024.0)).toFixed(4) }} GB<br/> | ||||
|               Physical Size: {{ (item.physicalsize / (1024 * 1024 * 1024.0)).toFixed(4) }} GB<br/> | ||||
|               Provisioning: {{ item.provisioningtype }}<br/> | ||||
|               Storage Pool: {{ item.storage }} ({{ item.storagetype }})<br/> | ||||
|             </p> | ||||
|             <div slot="actions" class="actions"> | ||||
|             </div> | ||||
|           </a-list-item> | ||||
|         </a-list> | ||||
| 
 | ||||
|       </a-collapse-panel> | ||||
| 
 | ||||
|       <a-collapse-panel :header="'Network Adapter(s): ' + (vm && vm.nic ? vm.nic.length : 0)" key="3" > | ||||
|         <a-button type="primary" @click="showAddModal" :loading="loadingNic"> | ||||
|           <a-icon type="plus"></a-icon> {{ $t('label.network.addVM') }} | ||||
|         </a-button> | ||||
|         <a-list | ||||
|           size="small" | ||||
|           itemLayout="horizontal" | ||||
|           :dataSource="vm.nic" | ||||
|           class="list" | ||||
|           :loading="loadingNic" | ||||
|         > | ||||
|           <a-list-item slot="renderItem" slot-scope="item"> | ||||
|           <a-list-item slot="renderItem" slot-scope="item" class="list__item"> | ||||
|             <a-list-item-meta> | ||||
|               <div slot="title"> | ||||
|                 <span v-show="item.isdefault">(Default) </span> | ||||
|                 <router-link :to="{ path: '/guestnetwork/' + item.networkid }">{{ item.networkname }} </router-link><br/> | ||||
|                 Mac Address: {{ item.macaddress }}<br/> | ||||
|                 <span v-if="item.ipaddress">Address: {{ item.ipaddress }} <br/></span> | ||||
|                 Netmask: {{ item.netmask }}<br/> | ||||
|                 Gateway: {{ item.gateway }}<br/> | ||||
|               </div> | ||||
|               <div slot="description"> | ||||
|                 <a-icon type="barcode"/> {{ item.id }} | ||||
|               </div> | ||||
|               <div slot="avatar"> | ||||
|                 <a-avatar slot="avatar"> | ||||
|                   <a-icon type="wifi" /> | ||||
|                 </a-avatar> | ||||
|                 <br/> | ||||
|                 <a-popconfirm | ||||
|                   title="Please confirm that you would like to make this NIC the default for this VM." | ||||
|                   @confirm="setAsDefault(item)" | ||||
|                   okText="Yes" | ||||
|                   cancelText="No" | ||||
|                 > | ||||
|                   <a-button | ||||
|                     style="margin-top: 10px" | ||||
|                     icon="arrow-right" | ||||
|                     size="small" | ||||
|                     shape="round" /> | ||||
|                 </a-popconfirm> | ||||
|                 <br/> | ||||
|                 <a-tooltip placement="right" v-if="item.type !== 'L2'"> | ||||
|                   <template slot="title"> | ||||
|                     {{ "Change IP Address" }} | ||||
|                   </template> | ||||
|                   <a-button | ||||
|                     style="margin-top: 10px" | ||||
|                     icon="swap" | ||||
|                     size="small" | ||||
|                     shape="round" | ||||
|                     @click="editIpAddressNic = item.id; showUpdateIpModal = true" /> | ||||
|                 </a-tooltip> | ||||
|                 <br/> | ||||
|                 <a-tooltip placement="right" v-if="item.type !== 'L2'"> | ||||
|                   <template slot="title"> | ||||
|                     {{ "Manage Secondary IP Addresses" }} | ||||
|                   </template> | ||||
|                   <a-button | ||||
|                     style="margin-top: 10px" | ||||
|                     icon="environment" | ||||
|                     size="small" | ||||
|                     shape="round" | ||||
|                     @click="fetchSecondaryIPs(item.id)" /> | ||||
|                 </a-tooltip> | ||||
|                 <br/> | ||||
|                 <a-popconfirm | ||||
|                   :title="$t('message.network.removeNIC')" | ||||
|                   @confirm="removeNIC(item)" | ||||
|                   okText="Yes" | ||||
|                   cancelText="No" | ||||
|                   v-if="!item.isdefault" | ||||
|                 > | ||||
|                   <a-button | ||||
|                     style="margin-top: 10px" | ||||
|                     type="danger" | ||||
|                     icon="delete" | ||||
|                     size="small" | ||||
|                     shape="round" /> | ||||
|                 </a-popconfirm> | ||||
|               </div> | ||||
|               <div slot="title"> | ||||
|                 <router-link :to="{ path: '/guestnetwork/' + item.networkid }">{{ item.networkname }} </router-link> | ||||
|                 <a-tag v-if="item.isdefault"> | ||||
|                   {{ $t('default') }} | ||||
|                 </a-tag> | ||||
|                 <a-tag v-if="item.type"> | ||||
|                   {{ item.type }} | ||||
|                 </a-tag> | ||||
|                 <a-tag v-if="item.broadcasturi"> | ||||
|                   {{ item.broadcasturi }} | ||||
|                 </a-tag> | ||||
|                 <a-tag v-if="item.isolationuri"> | ||||
|                   {{ item.isolationuri }} | ||||
|                 </a-tag> | ||||
|                 <br /> | ||||
|                 {{ $t('macaddress') }}: {{ item.macaddress }}<br/> | ||||
|                 <span v-if="item.ipaddress"> | ||||
|                   {{ $t('IP Address') }}: {{ item.ipaddress }} | ||||
|                   <br/> | ||||
|                 </span> | ||||
|                 <span v-if="item.secondaryip && item.type !== 'L2'"> | ||||
|                   {{ $t('Secondary IPs') }}: {{ item.secondaryip.map(x => x.ipaddress).join(', ') }} | ||||
|                   <br/> | ||||
|                 </span> | ||||
|                 <span v-if="item.netmask"> | ||||
|                   {{ $t('netmask') }}: {{ item.netmask }} | ||||
|                   <br/> | ||||
|                 </span> | ||||
|                 <span v-if="item.gateway"> | ||||
|                   {{ $t('gateway') }}: {{ item.gateway }} | ||||
|                   <br/> | ||||
|                 </span> | ||||
|                 <a-icon type="barcode"/> {{ item.id }} | ||||
|               </div> | ||||
|             </a-list-item-meta> | ||||
|             <p> | ||||
|               Type: {{ item.type }}<br/> | ||||
|               Broadcast URI: {{ item.broadcasturi }}<br/> | ||||
|               Isolation URI: {{ item.isolationuri }}<br/> | ||||
|             </p> | ||||
|           </a-list-item> | ||||
|         </a-list> | ||||
|       </a-collapse-panel> | ||||
|     </a-collapse> | ||||
| 
 | ||||
|     <a-modal | ||||
|       :visible="showAddNetworkModal" | ||||
|       :title="$t('label.network.addVM')" | ||||
|       @cancel="closeModals" | ||||
|       @ok="submitAddNetwork"> | ||||
|       {{ $t('message.network.addVM.desc') }} | ||||
| 
 | ||||
|       <div class="modal-form"> | ||||
|         <p class="modal-form__label">{{ $t('Network') }}:</p> | ||||
|         <a-select :defaultValue="addNetworkData.network" @change="e => addNetworkData.network === e"> | ||||
|           <a-select-option | ||||
|             v-for="network in addNetworkData.allNetworks" | ||||
|             :key="network.id" | ||||
|             :value="network.id"> | ||||
|             {{ network.name }} | ||||
|           </a-select-option> | ||||
|         </a-select> | ||||
|         <p class="modal-form__label">{{ $t('publicip') }}:</p> | ||||
|         <a-input v-model="addNetworkData.ip"></a-input> | ||||
|       </div> | ||||
| 
 | ||||
|     </a-modal> | ||||
| 
 | ||||
|     <a-modal | ||||
|       :visible="showUpdateIpModal" | ||||
|       :title="$t('label.change.ipaddress')" | ||||
|       @cancel="closeModals" | ||||
|       @ok="submitUpdateIP" | ||||
|     > | ||||
|       {{ $t('message.network.updateIp') }} | ||||
| 
 | ||||
|       <div class="modal-form"> | ||||
|         <p class="modal-form__label">{{ $t('publicip') }}:</p> | ||||
|         <a-input v-model="editIpAddressValue"></a-input> | ||||
|       </div> | ||||
| 
 | ||||
|     </a-modal> | ||||
| 
 | ||||
|     <a-modal | ||||
|       :visible="showSecondaryIpModal" | ||||
|       :title="$t('label.acquire.new.secondary.ip')" | ||||
|       :footer="null" | ||||
|       :closable="false" | ||||
|       class="wide-modal" | ||||
|     > | ||||
|       <p> | ||||
|         {{ $t('message.network.secondaryIP') }} | ||||
|       </p> | ||||
|       <a-divider /> | ||||
|       <a-input placeholder="Enter new secondary IP address" v-model="newSecondaryIp"></a-input> | ||||
|       <div style="margin-top: 10px; display: flex; justify-content:flex-end;"> | ||||
|         <a-button @click="submitSecondaryIP" type="primary" style="margin-right: 10px;">Add Secondary IP</a-button> | ||||
|         <a-button @click="closeModals">Close</a-button> | ||||
|       </div> | ||||
| 
 | ||||
|       <a-divider /> | ||||
|       <a-list itemLayout="vertical"> | ||||
|         <a-list-item v-for="(ip, index) in secondaryIPs" :key="index"> | ||||
|           <a-popconfirm | ||||
|             title="Release IP?" | ||||
|             @confirm="removeSecondaryIP(ip.id)" | ||||
|             okText="Yes" | ||||
|             cancelText="No" | ||||
|           > | ||||
|             <a-button | ||||
|               type="danger" | ||||
|               shape="circle" | ||||
|               size="small" | ||||
|               icon="delete" /> | ||||
|             {{ ip.ipaddress }} | ||||
|           </a-popconfirm> | ||||
|         </a-list-item> | ||||
|       </a-list> | ||||
|     </a-modal> | ||||
| 
 | ||||
|   </div> | ||||
| </template> | ||||
| 
 | ||||
| @ -120,12 +285,27 @@ export default { | ||||
|       default: false | ||||
|     } | ||||
|   }, | ||||
|   inject: ['parentFetchData'], | ||||
|   data () { | ||||
|     return { | ||||
|       vm: {}, | ||||
|       volumes: [], | ||||
|       totalStorage: 0, | ||||
|       activeKey: ['1', '2', '3'] | ||||
|       activeKey: ['1', '2', '3'], | ||||
|       showAddNetworkModal: false, | ||||
|       showUpdateIpModal: false, | ||||
|       showSecondaryIpModal: false, | ||||
|       addNetworkData: { | ||||
|         allNetworks: [], | ||||
|         network: '', | ||||
|         ip: '' | ||||
|       }, | ||||
|       loadingNic: false, | ||||
|       editIpAddressNic: '', | ||||
|       editIpAddressValue: '', | ||||
|       secondaryIPs: [], | ||||
|       selectedNicId: '', | ||||
|       newSecondaryIp: '' | ||||
|     } | ||||
|   }, | ||||
|   created () { | ||||
| @ -154,13 +334,267 @@ export default { | ||||
|         } | ||||
|         this.$set(this.resource, 'volumes', this.volumes) | ||||
|       }) | ||||
|     }, | ||||
|     listNetworks () { | ||||
|       api('listNetworks', { | ||||
|         listAll: 'true', | ||||
|         zoneid: this.vm.zoneid | ||||
|       }).then(response => { | ||||
|         this.addNetworkData.allNetworks = response.listnetworksresponse.network.filter(network => !this.vm.nic.map(nic => nic.networkid).includes(network.id)) | ||||
|         this.addNetworkData.network = this.addNetworkData.allNetworks[0].id | ||||
|       }) | ||||
|     }, | ||||
|     fetchSecondaryIPs (nicId) { | ||||
|       this.showSecondaryIpModal = true | ||||
|       this.selectedNicId = nicId | ||||
|       api('listNics', { | ||||
|         nicId: nicId, | ||||
|         keyword: '', | ||||
|         virtualmachineid: this.vm.id | ||||
|       }).then(response => { | ||||
|         this.secondaryIPs = response.listnicsresponse.nic[0].secondaryip | ||||
|       }) | ||||
|     }, | ||||
|     showAddModal () { | ||||
|       this.showAddNetworkModal = true | ||||
|       this.listNetworks() | ||||
|     }, | ||||
|     closeModals () { | ||||
|       this.showAddNetworkModal = false | ||||
|       this.showUpdateIpModal = false | ||||
|       this.showSecondaryIpModal = false | ||||
|       this.addNetworkData.network = '' | ||||
|       this.addNetworkData.ip = '' | ||||
|       this.editIpAddressValue = '' | ||||
|       this.newSecondaryIp = '' | ||||
|     }, | ||||
|     submitAddNetwork () { | ||||
|       const params = {} | ||||
|       params.virtualmachineid = this.vm.id | ||||
|       params.networkid = this.addNetworkData.network | ||||
|       if (this.addNetworkData.ip) { | ||||
|         params.ipaddress = this.addNetworkData.ip | ||||
|       } | ||||
|       this.showAddNetworkModal = false | ||||
|       this.loadingNic = true | ||||
|       api('addNicToVirtualMachine', params).then(response => { | ||||
|         this.$pollJob({ | ||||
|           jobId: response.addnictovirtualmachineresponse.jobid, | ||||
|           successMessage: `Successfully added network`, | ||||
|           successMethod: () => { | ||||
|             this.loadingNic = false | ||||
|             this.closeModals() | ||||
|             this.parentFetchData() | ||||
|           }, | ||||
|           errorMessage: 'Adding network failed', | ||||
|           errorMethod: () => { | ||||
|             this.loadingNic = false | ||||
|             this.closeModals() | ||||
|             this.parentFetchData() | ||||
|           }, | ||||
|           loadingMessage: `Adding network...`, | ||||
|           catchMessage: 'Error encountered while fetching async job result', | ||||
|           catchMethod: () => { | ||||
|             this.loadingNic = false | ||||
|             this.closeModals() | ||||
|             this.parentFetchData() | ||||
|           } | ||||
|         }) | ||||
|       }).catch(error => { | ||||
|         this.$notification.error({ | ||||
|           message: `Error ${error.response.status}`, | ||||
|           description: error.response.data.errorresponse.errortext | ||||
|         }) | ||||
|         this.loadingNic = false | ||||
|       }) | ||||
|     }, | ||||
|     setAsDefault (item) { | ||||
|       this.loadingNic = true | ||||
|       api('updateDefaultNicForVirtualMachine', { | ||||
|         virtualmachineid: this.vm.id, | ||||
|         nicid: item.id | ||||
|       }).then(response => { | ||||
|         this.$pollJob({ | ||||
|           jobId: response.updatedefaultnicforvirtualmachineresponse.jobid, | ||||
|           successMessage: `Successfully set ${item.networkname} to default. Please manually update the default NIC on the VM now.`, | ||||
|           successMethod: () => { | ||||
|             this.loadingNic = false | ||||
|             this.parentFetchData() | ||||
|           }, | ||||
|           errorMessage: `Error setting ${item.networkname} to default`, | ||||
|           errorMethod: () => { | ||||
|             this.loadingNic = false | ||||
|             this.parentFetchData() | ||||
|           }, | ||||
|           loadingMessage: `Setting ${item.networkname} to default...`, | ||||
|           catchMessage: 'Error encountered while fetching async job result', | ||||
|           catchMethod: () => { | ||||
|             this.loadingNic = false | ||||
|             this.parentFetchData() | ||||
|           } | ||||
|         }) | ||||
|       }).catch(error => { | ||||
|         this.$notification.error({ | ||||
|           message: `Error ${error.response.status}`, | ||||
|           description: error.response.data.errorresponse.errortext | ||||
|         }) | ||||
|         this.loadingNic = false | ||||
|       }) | ||||
|     }, | ||||
|     submitUpdateIP () { | ||||
|       this.loadingNic = true | ||||
|       this.showUpdateIpModal = false | ||||
|       api('updateVmNicIp', { | ||||
|         nicId: this.editIpAddressNic, | ||||
|         ipaddress: this.editIpAddressValue | ||||
|       }).then(response => { | ||||
|         this.$pollJob({ | ||||
|           jobId: response.updatevmnicipresponse.jobid, | ||||
|           successMessage: `Successfully updated IP Address`, | ||||
|           successMethod: () => { | ||||
|             this.loadingNic = false | ||||
|             this.closeModals() | ||||
|             this.parentFetchData() | ||||
|           }, | ||||
|           errorMessage: `Error`, | ||||
|           errorMethod: () => { | ||||
|             this.loadingNic = false | ||||
|             this.closeModals() | ||||
|             this.parentFetchData() | ||||
|           }, | ||||
|           loadingMessage: `Updating IP Address...`, | ||||
|           catchMessage: 'Error encountered while fetching async job result', | ||||
|           catchMethod: () => { | ||||
|             this.loadingNic = false | ||||
|             this.closeModals() | ||||
|             this.parentFetchData() | ||||
|           } | ||||
|         }) | ||||
|       }) | ||||
|         .catch(error => { | ||||
|           this.$notification.error({ | ||||
|             message: `Error ${error.response.status}`, | ||||
|             description: error.response.data.errorresponse.errortext | ||||
|           }) | ||||
|           this.loadingNic = false | ||||
|         }) | ||||
|     }, | ||||
|     removeNIC (item) { | ||||
|       this.loadingNic = true | ||||
| 
 | ||||
|       api('removeNicFromVirtualMachine', { | ||||
|         nicid: item.id, | ||||
|         virtualmachineid: this.vm.id | ||||
|       }).then(response => { | ||||
|         this.$pollJob({ | ||||
|           jobId: response.removenicfromvirtualmachineresponse.jobid, | ||||
|           successMessage: `Successfully removed`, | ||||
|           successMethod: () => { | ||||
|             this.loadingNic = false | ||||
|             this.parentFetchData() | ||||
|           }, | ||||
|           errorMessage: `There was an error`, | ||||
|           errorMethod: () => { | ||||
|             this.loadingNic = false | ||||
|             this.parentFetchData() | ||||
|           }, | ||||
|           loadingMessage: `Removing NIC...`, | ||||
|           catchMessage: 'Error encountered while fetching async job result', | ||||
|           catchMethod: () => { | ||||
|             this.loadingNic = false | ||||
|             this.parentFetchData() | ||||
|           } | ||||
|         }) | ||||
|       }) | ||||
|         .catch(error => { | ||||
|           this.$notification.error({ | ||||
|             message: `Error ${error.response.status}`, | ||||
|             description: error.response.data.errorresponse.errortext | ||||
|           }) | ||||
|           this.loadingNic = false | ||||
|         }) | ||||
|     }, | ||||
|     submitSecondaryIP () { | ||||
|       this.loadingNic = true | ||||
| 
 | ||||
|       const params = {} | ||||
|       params.nicid = this.selectedNicId | ||||
|       if (this.newSecondaryIp) { | ||||
|         params.ipaddress = this.newSecondaryIp | ||||
|       } | ||||
| 
 | ||||
|       api('addIpToNic', params).then(response => { | ||||
|         this.$pollJob({ | ||||
|           jobId: response.addiptovmnicresponse.jobid, | ||||
|           successMessage: `Successfully added secondary IP Address`, | ||||
|           successMethod: () => { | ||||
|             this.loadingNic = false | ||||
|             this.fetchSecondaryIPs(this.selectedNicId) | ||||
|             this.parentFetchData() | ||||
|           }, | ||||
|           errorMessage: `There was an error adding the secondary IP Address`, | ||||
|           errorMethod: () => { | ||||
|             this.loadingNic = false | ||||
|             this.fetchSecondaryIPs(this.selectedNicId) | ||||
|             this.parentFetchData() | ||||
|           }, | ||||
|           loadingMessage: `Add Secondary IP address...`, | ||||
|           catchMessage: 'Error encountered while fetching async job result', | ||||
|           catchMethod: () => { | ||||
|             this.loadingNic = false | ||||
|             this.fetchSecondaryIPs(this.selectedNicId) | ||||
|             this.parentFetchData() | ||||
|           } | ||||
|         }) | ||||
|       }).catch(error => { | ||||
|         this.$notification.error({ | ||||
|           message: `Error ${error.response.status}`, | ||||
|           description: error.response.data.addiptovmnicresponse.errortext | ||||
|         }) | ||||
|         this.loadingNic = false | ||||
|       }) | ||||
|     }, | ||||
|     removeSecondaryIP (id) { | ||||
|       this.loadingNic = true | ||||
| 
 | ||||
|       api('removeIpFromNic', { id }).then(response => { | ||||
|         this.$pollJob({ | ||||
|           jobId: response.removeipfromnicresponse.jobid, | ||||
|           successMessage: `Successfully removed secondary IP Address`, | ||||
|           successMethod: () => { | ||||
|             this.loadingNic = false | ||||
|             this.fetchSecondaryIPs(this.selectedNicId) | ||||
|             this.parentFetchData() | ||||
|           }, | ||||
|           errorMessage: `There was an error removing the secondary IP Address`, | ||||
|           errorMethod: () => { | ||||
|             this.loadingNic = false | ||||
|             this.fetchSecondaryIPs(this.selectedNicId) | ||||
|             this.parentFetchData() | ||||
|           }, | ||||
|           loadingMessage: `Removing Secondary IP address...`, | ||||
|           catchMessage: 'Error encountered while fetching async job result', | ||||
|           catchMethod: () => { | ||||
|             this.loadingNic = false | ||||
|             this.fetchSecondaryIPs(this.selectedNicId) | ||||
|             this.parentFetchData() | ||||
|           } | ||||
|         }) | ||||
|       }).catch(error => { | ||||
|         this.$notification.error({ | ||||
|           message: `Error ${error.response.status}`, | ||||
|           description: error.response.data.errorresponse.errortext | ||||
|         }) | ||||
|         this.loadingNic = false | ||||
|         this.fetchSecondaryIPs(this.selectedNicId) | ||||
|       }) | ||||
|     } | ||||
|   } | ||||
| } | ||||
| </script> | ||||
| 
 | ||||
| <style lang="less" scoped> | ||||
| .page-header-wrapper-grid-content-main { | ||||
| <style lang="scss" scoped> | ||||
|   .page-header-wrapper-grid-content-main { | ||||
|     width: 100%; | ||||
|     height: 100%; | ||||
|     min-height: 100%; | ||||
| @ -175,5 +609,64 @@ export default { | ||||
|       } | ||||
|       margin-bottom: 8px; | ||||
|     } | ||||
| } | ||||
|   } | ||||
| 
 | ||||
|   .list { | ||||
|     margin-top: 20px; | ||||
| 
 | ||||
|     &__item { | ||||
|       display: flex; | ||||
|       flex-direction: column; | ||||
|       align-items: flex-start; | ||||
| 
 | ||||
|       @media (min-width: 760px) { | ||||
|         flex-direction: row; | ||||
|         align-items: center; | ||||
|       } | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   .modal-form { | ||||
|     display: flex; | ||||
|     flex-direction: column; | ||||
| 
 | ||||
|     &__label { | ||||
|       margin-top: 20px; | ||||
|       margin-bottom: 5px; | ||||
|       font-weight: bold; | ||||
| 
 | ||||
|       &--no-margin { | ||||
|         margin-top: 0; | ||||
|       } | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   .actions { | ||||
|     display: flex; | ||||
|     margin-left: -24px; | ||||
| 
 | ||||
|     button { | ||||
|       &:not(:last-child) { | ||||
|         margin-right: 10px; | ||||
|       } | ||||
|     } | ||||
| 
 | ||||
|     @media (min-width: 760px) { | ||||
|       flex-direction: column; | ||||
|       margin-left: 24px; | ||||
| 
 | ||||
|       button { | ||||
|         &:not(:last-child) { | ||||
|           margin-bottom: 10px; | ||||
|           margin-right: 0; | ||||
|         } | ||||
|       } | ||||
|     } | ||||
|   } | ||||
| </style> | ||||
| 
 | ||||
| <style lang="scss"> | ||||
|   .wide-modal { | ||||
|     min-width: 50vw; | ||||
|   } | ||||
| </style> | ||||
|  | ||||
| @ -19,23 +19,24 @@ | ||||
|   <a-row :gutter="24"> | ||||
|     <a-col :md="24"> | ||||
|       <a-card class="breadcrumb-card"> | ||||
|         <a-col :md="14"> | ||||
|         <a-col :md="24" style="display: flex"> | ||||
|           <breadcrumb style="padding-top: 6px" /> | ||||
|         </a-col> | ||||
|         <a-col :md="10"> | ||||
|           <a-button | ||||
|             style="margin-left: 10px; float: right" | ||||
|             @click="fetchData()" | ||||
|             icon="reload" | ||||
|             style="margin-left: 12px; margin-top: 4px" | ||||
|             :loading="loading" | ||||
|             type="primary"> | ||||
|             {{ $t('Refresh') }} | ||||
|             icon="reload" | ||||
|             size="small" | ||||
|             shape="round" | ||||
|             @click="fetchData()" > | ||||
|             {{ $t('refresh') }} | ||||
|           </a-button> | ||||
|           <a-button | ||||
|             style="margin-left: 10px; float: right" | ||||
|             @click="sslFormVisible = true" | ||||
|             icon="safety-certificate"> | ||||
|             {{ $t('SSL Certificate') }} | ||||
|             style="margin-left: 12px; margin-top: 4px" | ||||
|             icon="safety-certificate" | ||||
|             size="small" | ||||
|             shape="round" | ||||
|             @click="sslFormVisible = true"> | ||||
|             {{ $t('Setup SSL Certificate') }} | ||||
|           </a-button> | ||||
|           <a-modal | ||||
|             :title="$t('SSL Certificate')" | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user