mirror of
https://github.com/apache/cloudstack.git
synced 2025-10-26 08:42:29 +01:00
CLOUDSTACK-9718: Revamp the dropdown showing lists of hosts available for migration in a Zone
Reviewed-By: Rashmi Dixit
Problem: All the hosts suitable for VM Migration are not shown in the UI. This could
confuse the user as the target host might never be shown in the UI.
Root Cause: The API (findHostsForMigration) always returned page 1 results which would
be always <= default.page.size global parameter. Therefore, in case of large
no. of hosts where the result can map to multiple pages, this issue would arise.
Solution: 1. Replace drop-down with listView widget.
2. Allow lazy-loading of records on listView's scroll.
3. Show additional parameters (CPU/Memory used) to assist admin in decision making.
4. Provide 'Search by host name' to limit the results.
Added change where if there are no hosts found, an empty row with message will
appear.
This commit is contained in:
parent
5c0979fff5
commit
d8158fe5f4
@ -401,7 +401,7 @@ public interface ManagementService {
|
||||
* @return Ternary<List<? extends Host>, List<? extends Host>, Map<Host, Boolean>> List of all Hosts to which a VM
|
||||
* can be migrated, list of Hosts with enough capacity and hosts requiring storage motion for migration.
|
||||
*/
|
||||
Ternary<Pair<List<? extends Host>, Integer>, List<? extends Host>, Map<Host, Boolean>> listHostsForMigrationOfVM(Long vmId, Long startIndex, Long pageSize);
|
||||
Ternary<Pair<List<? extends Host>, Integer>, List<? extends Host>, Map<Host, Boolean>> listHostsForMigrationOfVM(Long vmId, Long startIndex, Long pageSize, String keyword);
|
||||
|
||||
/**
|
||||
* List storage pools for live migrating of a volume. The API returns list of all pools in the cluster to which the
|
||||
|
||||
@ -76,7 +76,7 @@ public class FindHostsForMigrationCmd extends BaseListCmd {
|
||||
Map<Host, Boolean> hostsRequiringStorageMotion;
|
||||
|
||||
Ternary<Pair<List<? extends Host>, Integer>, List<? extends Host>, Map<Host, Boolean>> hostsForMigration =
|
||||
_mgr.listHostsForMigrationOfVM(getVirtualMachineId(), this.getStartIndex(), this.getPageSizeVal());
|
||||
_mgr.listHostsForMigrationOfVM(getVirtualMachineId(), this.getStartIndex(), this.getPageSizeVal(), this.getKeyword());
|
||||
result = hostsForMigration.first();
|
||||
List<? extends Host> hostsWithCapacity = hostsForMigration.second();
|
||||
hostsRequiringStorageMotion = hostsForMigration.third();
|
||||
|
||||
@ -209,7 +209,7 @@ public class ListHostsCmd extends BaseListCmd {
|
||||
} else {
|
||||
Pair<List<? extends Host>, Integer> result;
|
||||
Ternary<Pair<List<? extends Host>, Integer>, List<? extends Host>, Map<Host, Boolean>> hostsForMigration =
|
||||
_mgr.listHostsForMigrationOfVM(getVirtualMachineId(), this.getStartIndex(), this.getPageSizeVal());
|
||||
_mgr.listHostsForMigrationOfVM(getVirtualMachineId(), this.getStartIndex(), this.getPageSizeVal(), null);
|
||||
result = hostsForMigration.first();
|
||||
List<? extends Host> hostsWithCapacity = hostsForMigration.second();
|
||||
List<HostResponse> hostResponses = new ArrayList<HostResponse>();
|
||||
|
||||
@ -1112,7 +1112,10 @@ public class ManagementServerImpl extends ManagerBase implements ManagementServe
|
||||
}
|
||||
|
||||
@Override
|
||||
public Ternary<Pair<List<? extends Host>, Integer>, List<? extends Host>, Map<Host, Boolean>> listHostsForMigrationOfVM(final Long vmId, final Long startIndex, final Long pageSize) {
|
||||
public Ternary<Pair<List<? extends Host>, Integer>, List<? extends Host>, Map<Host, Boolean>>
|
||||
listHostsForMigrationOfVM(final Long vmId,
|
||||
final Long startIndex,
|
||||
final Long pageSize, final String keyword) {
|
||||
final Account caller = getCaller();
|
||||
if (!_accountMgr.isRootAdmin(caller.getId())) {
|
||||
if (s_logger.isDebugEnabled()) {
|
||||
@ -1200,9 +1203,8 @@ public class ManagementServerImpl extends ManagerBase implements ManagementServe
|
||||
List<HostVO> allHosts = null;
|
||||
final Map<Host, Boolean> requiresStorageMotion = new HashMap<Host, Boolean>();
|
||||
DataCenterDeployment plan = null;
|
||||
|
||||
if (canMigrateWithStorage) {
|
||||
allHostsPair = searchForServers(startIndex, pageSize, null, hostType, null, srcHost.getDataCenterId(), null, null, null, null, null, null,
|
||||
allHostsPair = searchForServers(startIndex, pageSize, null, hostType, null, srcHost.getDataCenterId(), null, null, null, keyword, null, null,
|
||||
srcHost.getHypervisorType(), srcHost.getHypervisorVersion());
|
||||
allHosts = allHostsPair.first();
|
||||
allHosts.remove(srcHost);
|
||||
@ -1239,7 +1241,7 @@ public class ManagementServerImpl extends ManagerBase implements ManagementServe
|
||||
if (s_logger.isDebugEnabled()) {
|
||||
s_logger.debug("Searching for all hosts in cluster " + cluster + " for migrating VM " + vm);
|
||||
}
|
||||
allHostsPair = searchForServers(startIndex, pageSize, null, hostType, null, null, null, cluster, null, null, null, null, null, null);
|
||||
allHostsPair = searchForServers(startIndex, pageSize, null, hostType, null, null, null, cluster, null, keyword, null, null, null, null);
|
||||
// Filter out the current host.
|
||||
allHosts = allHostsPair.first();
|
||||
allHosts.remove(srcHost);
|
||||
|
||||
@ -1425,6 +1425,27 @@ div.list-view td.state.transition span {
|
||||
background-position: 1px -432px;
|
||||
}
|
||||
|
||||
div.list-view td.state.suitable span {
|
||||
background: url(../images/icons.png) no-repeat scroll 1px -224px;
|
||||
color: #008000;
|
||||
height: 18px;
|
||||
}
|
||||
|
||||
div.list-view td.state.suitable-storage-migration-required span {
|
||||
width: 200px;
|
||||
}
|
||||
|
||||
div.list-view td.state.notsuitable span {
|
||||
background: url(../images/icons.png) no-repeat scroll 1px -190px;
|
||||
color: #B90606;
|
||||
height: 19px;
|
||||
width: 100px;
|
||||
}
|
||||
|
||||
div.list-view td.state.notsuitable-storage-migration-required span {
|
||||
width: 220px !important;
|
||||
}
|
||||
|
||||
.horizontal-overflow tbody td, .horizontal-overflow thead th {
|
||||
min-width: 40px;
|
||||
padding: 10px 10px 5px 0px;
|
||||
@ -13232,3 +13253,21 @@ ul.ui-autocomplete.ui-menu {
|
||||
font-size: 13px;
|
||||
padding: 5px;
|
||||
}
|
||||
|
||||
.multi-edit-add-list .ui-button.migrateok,
|
||||
.multi-edit-add-list .ui-button.migratecancel {
|
||||
top: -5px !important;
|
||||
}
|
||||
|
||||
.migrate-vm-available-host-list div.text-search {
|
||||
right: 30px;
|
||||
}
|
||||
|
||||
.migrate-vm-available-host-list div.ui-widget-content {
|
||||
display: block !important;
|
||||
}
|
||||
|
||||
.list-view-select table th.availableHostSuitability,
|
||||
.list-view-select table td.availableHostSuitability {
|
||||
max-width: 250px;
|
||||
}
|
||||
@ -1852,6 +1852,7 @@
|
||||
<script type="text/javascript" src="scripts/instanceWizard.js"></script>
|
||||
<script type="text/javascript" src="scripts/affinity.js"></script>
|
||||
<script type="text/javascript" src="scripts/ui-custom/affinity.js"></script>
|
||||
<script type="text/javascript" src="scripts/ui-custom/migrate.js"></script>
|
||||
<script type="text/javascript" src="scripts/instances.js"></script>
|
||||
<script type="text/javascript" src="scripts/events.js"></script>
|
||||
<script type="text/javascript" src="scripts/regions.js"></script>
|
||||
|
||||
@ -1466,6 +1466,7 @@ var dictionary = {"ICMP.code":"ICMP Code",
|
||||
"label.select.a.template":"Select a template",
|
||||
"label.select.a.zone":"Select a zone",
|
||||
"label.select.instance":"Select instance",
|
||||
"label.select.host":"Select host",
|
||||
"label.select.instance.to.attach.volume.to":"Select instance to attach volume to",
|
||||
"label.select.iso.or.template":"Select ISO or template",
|
||||
"label.select.offering":"Select offering",
|
||||
@ -1526,6 +1527,7 @@ var dictionary = {"ICMP.code":"ICMP Code",
|
||||
"label.start.vlan":"Start VLAN",
|
||||
"label.start.vxlan":"Start VXLAN",
|
||||
"label.state":"State",
|
||||
"label.suitability": "Suitability",
|
||||
"label.static.nat":"Static NAT",
|
||||
"label.static.nat.enabled":"Static NAT Enabled",
|
||||
"label.static.nat.to":"Static NAT to",
|
||||
@ -2114,6 +2116,7 @@ var dictionary = {"ICMP.code":"ICMP Code",
|
||||
"message.lock.account":"Please confirm that you want to lock this account. By locking the account, all users for this account will no longer be able to manage their cloud resources. Existing resources can still be accessed.",
|
||||
"message.migrate.instance.confirm":"Please confirm the host you wish to migrate the virtual instance to.",
|
||||
"message.migrate.instance.to.host":"Please confirm that you want to migrate instance to another host.",
|
||||
"message.migrate.instance.select.host":"Please select a host for migration",
|
||||
"message.migrate.instance.to.ps":"Please confirm that you want to migrate instance to another primary storage.",
|
||||
"message.migrate.router.confirm":"Please confirm the host you wish to migrate the router to:",
|
||||
"message.migrate.systemvm.confirm":"Please confirm the host you wish to migrate the system VM to:",
|
||||
@ -2123,7 +2126,8 @@ var dictionary = {"ICMP.code":"ICMP Code",
|
||||
"message.network.remote.access.vpn.configuration":"Remote Access VPN configuration has been generated, but it failed to apply. Please check connectivity of the network element, then re-try.",
|
||||
"message.new.user":"Specify the following to add a new user to the account",
|
||||
"message.no.affinity.groups":"You do not have any affinity groups. Please continue to the next step.",
|
||||
"message.no.host.available":"No Hosts are available for Migration",
|
||||
"message.no.host.available":"No hosts are available for migration",
|
||||
"message.no.more.hosts.available":"No more hosts are available for migration",
|
||||
"message.no.network.support":"Your selected hypervisor, vSphere, does not have any additional network features. Please continue to step 5.",
|
||||
"message.no.network.support.configuration.not.true":"You do not have any zone that has security group enabled. Thus, no additional network features. Please continue to step 5.",
|
||||
"message.no.projects":"You do not have any projects.<br/>Please create a new one from the projects section.",
|
||||
|
||||
@ -1468,6 +1468,7 @@ var dictionary = {
|
||||
"label.select.a.zone": "ゾーンの選択",
|
||||
"label.select.instance": "インスタンスの選択",
|
||||
"label.select.instance.to.attach.volume.to": "ボリュームをアタッチするインスタンスを選択してください",
|
||||
"label.select.host":"ホストの選択",
|
||||
"label.select.iso.or.template": "ISO またはテンプレートの選択",
|
||||
"label.select.offering": "オファリングの選択",
|
||||
"label.select.project": "プロジェクトの選択",
|
||||
@ -1527,6 +1528,7 @@ var dictionary = {
|
||||
"label.start.vlan": "開始 VLAN",
|
||||
"label.start.vxlan": "開始 VXLAN",
|
||||
"label.state": "状態",
|
||||
"label.suitability": "適合",
|
||||
"label.static.nat": "静的 NAT",
|
||||
"label.static.nat.enabled": "静的 NAT 有効",
|
||||
"label.static.nat.to": "静的 NAT の設定先:",
|
||||
@ -2115,6 +2117,7 @@ var dictionary = {
|
||||
"message.lock.account": "このアカウントをロックしてもよろしいですか? このアカウントのすべてのユーザーがクラウド リソースを管理できなくなります。その後も既存のリソースにはアクセスできます。",
|
||||
"message.migrate.instance.confirm": "仮想インスタンスの移行先は次のホストでよろしいですか?",
|
||||
"message.migrate.instance.to.host": "別のホストにインスタンスを移行してもよろしいですか?",
|
||||
"message.migrate.instance.select.host": "マイグレーション行うホストを選択。",
|
||||
"message.migrate.instance.to.ps": "別のプライマリ ストレージにインスタンスを移行してもよろしいですか?",
|
||||
"message.migrate.router.confirm": "ルーターの移行先は次のホストでよろしいですか?",
|
||||
"message.migrate.systemvm.confirm": "システム VM の移行先は次のホストでよろしいですか?",
|
||||
@ -2125,6 +2128,7 @@ var dictionary = {
|
||||
"message.new.user": "アカウントに新しいユーザーを追加するために、次の情報を指定してください。",
|
||||
"message.no.affinity.groups": "アフィニティ グループがありません。次の手順に進んでください。",
|
||||
"message.no.host.available": "移行に使用できるホストはありません",
|
||||
"message.no.more.hosts.available": "マイグレーション可能なホストがありません。",
|
||||
"message.no.network.support": "ハイパーバイザーとして vSphere を選択しましたが、このハイパーバイザーに追加のネットワーク機能はありません。手順 5. に進んでください。",
|
||||
"message.no.network.support.configuration.not.true": "セキュリティ グループが有効なゾーンが無いため、追加のネットワーク機能はありません。手順 5. に進んでください。",
|
||||
"message.no.projects": "プロジェクトがありません。<br/>プロジェクト セクションから新しいプロジェクトを作成してください。",
|
||||
|
||||
@ -1468,6 +1468,7 @@ var dictionary = {
|
||||
"label.select.a.zone": "选择一个资源域",
|
||||
"label.select.instance": "选择实例",
|
||||
"label.select.instance.to.attach.volume.to": "选择要将卷附加到的实例",
|
||||
"label.select.host": "选择主机",
|
||||
"label.select.iso.or.template": "选择 ISO 或模板",
|
||||
"label.select.offering": "选择方案",
|
||||
"label.select.project": "选择项目",
|
||||
@ -1527,6 +1528,7 @@ var dictionary = {
|
||||
"label.start.vlan": "起始 VLAN",
|
||||
"label.start.vxlan": "起始 VXLAN",
|
||||
"label.state": "状态",
|
||||
"label.suitability": "适应性",
|
||||
"label.static.nat": "静态 NAT",
|
||||
"label.static.nat.enabled": "已启用静态 NAT",
|
||||
"label.static.nat.to": "静态 NAT 目标",
|
||||
@ -2115,6 +2117,7 @@ var dictionary = {
|
||||
"message.lock.account": "请确认您确实要锁定此帐户。通过锁定此帐户,此帐户的所有用户将不再能够管理各自的云资源,但仍然可以访问现有资源。",
|
||||
"message.migrate.instance.confirm": "请确认要将虚拟实例迁移到的主机。",
|
||||
"message.migrate.instance.to.host": "请确认您确实要将实例迁移到其他主机。",
|
||||
"message.migrate.instance.select.host": "选择用于迁移的主机",
|
||||
"message.migrate.instance.to.ps": "请确认您确实要将实例迁移到其他主存储。",
|
||||
"message.migrate.router.confirm": "请确认您要将路由器迁移到的主机:",
|
||||
"message.migrate.systemvm.confirm": "请确认您要将系统 VM 迁移到的主机:",
|
||||
@ -2125,6 +2128,7 @@ var dictionary = {
|
||||
"message.new.user": "请指定以下信息以向帐户中添加一个新用户",
|
||||
"message.no.affinity.groups": "您没有任何关联性组。请继续执行下一步操作。",
|
||||
"message.no.host.available": "没有可用于迁移的主机",
|
||||
"message.no.more.hosts.available": "没有可用于迁移的主机",
|
||||
"message.no.network.support": "您选择的虚拟机管理程序 vSphere 没有任何其他网络功能。请继续执行步骤 5。",
|
||||
"message.no.network.support.configuration.not.true": "您的所有资源域都未启用安全组,因此无其他网络功能。请继续执行步骤 5。",
|
||||
"message.no.projects": "您没有任何项目。<br/>请从“项目”部分中创建一个新项目。",
|
||||
|
||||
@ -1479,113 +1479,130 @@
|
||||
label: 'label.migrate.instance.to.host',
|
||||
compactLabel: 'label.migrate.to.host',
|
||||
messages: {
|
||||
confirm: function(args) {
|
||||
return 'message.migrate.instance.to.host';
|
||||
},
|
||||
notification: function(args) {
|
||||
return 'label.migrate.instance.to.host';
|
||||
}
|
||||
},
|
||||
createForm: {
|
||||
title: 'label.migrate.instance.to.host',
|
||||
desc: '',
|
||||
fields: {
|
||||
hostId: {
|
||||
label: 'label.host',
|
||||
validation: {
|
||||
required: true
|
||||
},
|
||||
select: function(args) {
|
||||
$.ajax({
|
||||
url: createURL("findHostsForMigration&VirtualMachineId=" + args.context.instances[0].id),
|
||||
dataType: "json",
|
||||
async: true,
|
||||
success: function(json) {
|
||||
if (json.findhostsformigrationresponse.host != undefined) {
|
||||
vmMigrationHostObjs = json.findhostsformigrationresponse.host;
|
||||
var items = [];
|
||||
$(vmMigrationHostObjs).each(function() {
|
||||
if (this.requiresStorageMotion == true) {
|
||||
action: {
|
||||
custom: cloudStack.uiCustom.migrate({
|
||||
listView: {
|
||||
listView: {
|
||||
id: 'availableHosts',
|
||||
fields: {
|
||||
availableHostName: {
|
||||
label: 'label.name'
|
||||
},
|
||||
availableHostSuitability: {
|
||||
label: 'label.suitability',
|
||||
indicator: {
|
||||
'Suitable': 'suitable',
|
||||
'Suitable-Storage migration required': 'suitable suitable-storage-migration-required',
|
||||
'Not Suitable': 'notsuitable',
|
||||
'Not Suitable-Storage migration required': 'notsuitable notsuitable-storage-migration-required'
|
||||
}
|
||||
},
|
||||
cpuused: {
|
||||
label: 'label.cpu.utilized'
|
||||
},
|
||||
memoryused: {
|
||||
label: 'label.memory.used'
|
||||
}
|
||||
},
|
||||
dataProvider: function(args) {
|
||||
var data = {
|
||||
page: args.page,
|
||||
pagesize: pageSize
|
||||
};
|
||||
if (args.filterBy.search.value) {
|
||||
data.keyword = args.filterBy.search.value;
|
||||
}
|
||||
$.ajax({
|
||||
url: createURL("findHostsForMigration&VirtualMachineId=" + args.context.instances[0].id),
|
||||
data: data,
|
||||
dataType: "json",
|
||||
async: true,
|
||||
success: function(json) {
|
||||
if (json.findhostsformigrationresponse.host != undefined) {
|
||||
vmMigrationHostObjs = json.findhostsformigrationresponse.host;
|
||||
var items = [];
|
||||
$(vmMigrationHostObjs).each(function() {
|
||||
var suitability = (this.suitableformigration ? "Suitable" : "Not Suitable");
|
||||
if (this.requiresStorageMotion == true) {
|
||||
suitability += ("-Storage migration required");
|
||||
}
|
||||
items.push({
|
||||
id: this.id,
|
||||
description: (this.name + " (" + (this.suitableformigration ? "Suitable, " : "Not Suitable, ") + "Storage migration required)")
|
||||
});
|
||||
|
||||
} else {
|
||||
items.push({
|
||||
id: this.id,
|
||||
description: (this.name + " (" + (this.suitableformigration ? "Suitable" : "Not Suitable") + ")")
|
||||
availableHostName: this.name,
|
||||
availableHostSuitability: suitability,
|
||||
cpuused: this.cpuused,
|
||||
memoryused: (parseFloat(this.memoryused)/(1024.0*1024.0*1024.0)).toFixed(2) + ' GB'
|
||||
});
|
||||
});
|
||||
args.response.success({
|
||||
data: items
|
||||
});
|
||||
} else if(args.page == 1) {
|
||||
args.response.success({
|
||||
data: null
|
||||
});
|
||||
} else {
|
||||
cloudStack.dialog.notice({
|
||||
message: _l('message.no.more.hosts.available')
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
},
|
||||
action: function(args) {
|
||||
var selectedHostObj;
|
||||
if (args.context.selectedHost != null && args.context.selectedHost.length > 0) {
|
||||
selectedHostObj = args.context.selectedHost[0];
|
||||
if (selectedHostObj.requiresStorageMotion == true) {
|
||||
$.ajax({
|
||||
url: createURL("migrateVirtualMachineWithVolume&hostid=" + selectedHostObj.id + "&virtualmachineid=" + args.context.instances[0].id),
|
||||
dataType: "json",
|
||||
async: true,
|
||||
success: function(json) {
|
||||
var jid = json.migratevirtualmachinewithvolumeresponse.jobid;
|
||||
args.response.success({
|
||||
_custom: {
|
||||
jobId: jid,
|
||||
getUpdatedItem: function(json) {
|
||||
return json.queryasyncjobresultresponse.jobresult.virtualmachine;
|
||||
},
|
||||
getActionFilter: function() {
|
||||
return vmActionfilter;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
} else {
|
||||
$.ajax({
|
||||
url: createURL("migrateVirtualMachine&hostid=" + selectedHostObj.id + "&virtualmachineid=" + args.context.instances[0].id),
|
||||
dataType: "json",
|
||||
async: true,
|
||||
success: function(json) {
|
||||
var jid = json.migratevirtualmachineresponse.jobid;
|
||||
args.response.success({
|
||||
data: items
|
||||
_custom: {
|
||||
jobId: jid,
|
||||
getUpdatedItem: function(json) {
|
||||
return json.queryasyncjobresultresponse.jobresult.virtualmachine;
|
||||
},
|
||||
getActionFilter: function() {
|
||||
return vmActionfilter;
|
||||
}
|
||||
}
|
||||
});
|
||||
} else {
|
||||
cloudStack.dialog.notice({
|
||||
message: _l('message.no.host.available')
|
||||
}); //Only a single host in the set up
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
action: function(args) {
|
||||
var selectedHostObj;
|
||||
if (vmMigrationHostObjs != null) {
|
||||
for (var i = 0; i < vmMigrationHostObjs.length; i++) {
|
||||
if (vmMigrationHostObjs[i].id == args.data.hostId) {
|
||||
selectedHostObj = vmMigrationHostObjs[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (selectedHostObj == null)
|
||||
return;
|
||||
|
||||
if (selectedHostObj.requiresStorageMotion == true) {
|
||||
$.ajax({
|
||||
url: createURL("migrateVirtualMachineWithVolume&hostid=" + args.data.hostId + "&virtualmachineid=" + args.context.instances[0].id),
|
||||
dataType: "json",
|
||||
async: true,
|
||||
success: function(json) {
|
||||
var jid = json.migratevirtualmachinewithvolumeresponse.jobid;
|
||||
args.response.success({
|
||||
_custom: {
|
||||
jobId: jid,
|
||||
getUpdatedItem: function(json) {
|
||||
return json.queryasyncjobresultresponse.jobresult.virtualmachine;
|
||||
},
|
||||
getActionFilter: function() {
|
||||
return vmActionfilter;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
} else {
|
||||
$.ajax({
|
||||
url: createURL("migrateVirtualMachine&hostid=" + args.data.hostId + "&virtualmachineid=" + args.context.instances[0].id),
|
||||
dataType: "json",
|
||||
async: true,
|
||||
success: function(json) {
|
||||
var jid = json.migratevirtualmachineresponse.jobid;
|
||||
args.response.success({
|
||||
_custom: {
|
||||
jobId: jid,
|
||||
getUpdatedItem: function(json) {
|
||||
return json.queryasyncjobresultresponse.jobresult.virtualmachine;
|
||||
},
|
||||
getActionFilter: function() {
|
||||
return vmActionfilter;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
})
|
||||
},
|
||||
notification: {
|
||||
poll: pollAsyncJobResult
|
||||
|
||||
127
ui/scripts/ui-custom/migrate.js
Normal file
127
ui/scripts/ui-custom/migrate.js
Normal file
@ -0,0 +1,127 @@
|
||||
// Licensed to the Apache Software Foundation (ASF) under one
|
||||
// or more contributor license agreements. See the NOTICE file
|
||||
// distributed with this work for additional information
|
||||
// regarding copyright ownership. The ASF licenses this file
|
||||
// to you under the Apache License, Version 2.0 (the
|
||||
// "License"); you may not use this file except in compliance
|
||||
// with the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing,
|
||||
// software distributed under the License is distributed on an
|
||||
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
// KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations
|
||||
// under the License.
|
||||
(function(cloudStack, $) {
|
||||
cloudStack.uiCustom.migrate = function(args) {
|
||||
var listView = args.listView;
|
||||
var action = args.action;
|
||||
|
||||
return function(args) {
|
||||
var context = args.context;
|
||||
|
||||
var hostList = function(args) {
|
||||
var $listView;
|
||||
|
||||
var hosts = $.extend(true, {}, args.listView, {
|
||||
context: context,
|
||||
uiCustom: true
|
||||
});
|
||||
|
||||
hosts.listView.actions = {
|
||||
select: {
|
||||
label: _l('label.select.host'),
|
||||
type: 'radio',
|
||||
action: {
|
||||
uiCustom: function(args) {
|
||||
var $item = args.$item;
|
||||
var $input = $item.find('td.actions input:visible');
|
||||
|
||||
if ($input.attr('type') == 'checkbox') {
|
||||
if ($input.is(':checked'))
|
||||
$item.addClass('multi-edit-selected');
|
||||
else
|
||||
$item.removeClass('multi-edit-selected');
|
||||
} else {
|
||||
$item.siblings().removeClass('multi-edit-selected');
|
||||
$item.addClass('multi-edit-selected');
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
$listView = $('<div>').listView(hosts);
|
||||
|
||||
// Change action label
|
||||
$listView.find('th.actions').html(_l('label.select'));
|
||||
|
||||
return $listView;
|
||||
};
|
||||
|
||||
var $dataList = hostList({
|
||||
listView: listView
|
||||
}).dialog({
|
||||
dialogClass: 'multi-edit-add-list panel migrate-vm-available-host-list',
|
||||
width: 825,
|
||||
draggable: false,
|
||||
title: _l('label.migrate.instance.to.host'),
|
||||
buttons: [{
|
||||
text: _l('label.ok'),
|
||||
'class': 'ok migrateok',
|
||||
click: function() {
|
||||
var complete = args.complete;
|
||||
var selectedHostObj = $dataList.find('tr.multi-edit-selected').data('json-obj');
|
||||
if(selectedHostObj != undefined) {
|
||||
$dataList.fadeOut(function() {
|
||||
action({
|
||||
context: $.extend(true, {}, context, {
|
||||
selectedHost: [
|
||||
selectedHostObj
|
||||
]
|
||||
}),
|
||||
response: {
|
||||
success: function(args) {
|
||||
complete({
|
||||
_custom: args._custom,
|
||||
$item: $('<div>'),
|
||||
});
|
||||
},
|
||||
error: function(args) {
|
||||
cloudStack.dialog.notice({
|
||||
message: args
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
$('div.overlay').fadeOut(function() {
|
||||
$('div.overlay').remove();
|
||||
});
|
||||
}
|
||||
else {
|
||||
cloudStack.dialog.notice({
|
||||
message: _l('message.migrate.instance.select.host')
|
||||
});
|
||||
}
|
||||
}
|
||||
}, {
|
||||
text: _l('label.cancel'),
|
||||
'class': 'cancel migratecancel',
|
||||
click: function() {
|
||||
$dataList.fadeOut(function() {
|
||||
$dataList.remove();
|
||||
});
|
||||
$('div.overlay').fadeOut(function() {
|
||||
$('div.overlay').remove();
|
||||
$(':ui-dialog').dialog('destroy');
|
||||
});
|
||||
}
|
||||
}]
|
||||
}).parent('.ui-dialog').overlay();
|
||||
};
|
||||
};
|
||||
}(cloudStack, jQuery));
|
||||
Loading…
x
Reference in New Issue
Block a user