Merge branch 'ui-vm-affinity'

This commit is contained in:
Brian Federle 2013-04-25 11:04:35 -07:00
commit 5ce289034d
13 changed files with 1136 additions and 540 deletions

View File

@ -14,7 +14,16 @@
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
label.add.affinity.group=Add new affinity group
message.delete.affinity.group=Please confirm that you would like to remove this affinity group.
label.delete.affinity.group=Delete Affinity Group
label.edit.affinity.group=Edit Affinity Group
label.affinity=Affinity
label.anti.affinity=Anti-affinity
label.affinity.groups=Affinity Groups
label.anti.affinity.groups=Anti-affinity Groups
label.affinity.group=Affinity Group
label.anti.affinity.group=Anti-affinity Group
changed.item.properties=Changed item properties
confirm.enable.s3=Please fill in the following information to enable support for S3-backed Secondary Storage
confirm.enable.swift=Please fill in the following information to enable support for Swift

View File

@ -1502,7 +1502,6 @@ div.list-view td.state.off span {
position: relative;
left: 0px;
float: left;
width: 460px;
height: 22px;
border-top: 1px solid #808080;
/*+box-shadow:inset 0px 1px #FFFFFF;*/
@ -1907,7 +1906,7 @@ div.detail-group td.view-all a {
background: url(../images/gradients.png) repeat-x 0px -529px;
font-size: 11px;
display: block;
height: 25px;
height: 27px;
text-decoration: none;
color: #4C5D6C;
/*+text-shadow:0px 1px 2px #FFFFFF;*/
@ -1916,7 +1915,7 @@ div.detail-group td.view-all a {
-o-text-shadow: 0px 1px 2px #FFFFFF;
text-shadow: 0px 1px 2px #FFFFFF;
float: left;
padding: 0 8px 0 5px;
padding: 0 1px;
border-left: 1px solid #9B9EA2;
/*+border-radius:5px 0 0 5px;*/
-moz-border-radius: 5px 0 0 5px;
@ -1971,10 +1970,10 @@ div.details .main-groups label.error {
}
.detail-view td.view-all.multiple {
width: 123px !important;
height: 22px;
float: left;
max-width: 145px;
height: 17px;
display: block;
float: left;
margin: 8px 2px 8px 8px;
border: none !important;
/*+box-shadow:none;*/
@ -5265,6 +5264,10 @@ label.error {
position: relative;
}
.multi-wizard.instance-wizard .progress ul li {
width: 109px;
}
.multi-wizard .progress ul li.first {
/*+border-radius:5px 0 0 5px;*/
-moz-border-radius: 5px 0 0 5px;
@ -5306,6 +5309,10 @@ label.error {
text-align: center;
}
.multi-wizard.instance-wizard .progress ul li span {
left: 36px;
}
.multi-wizard .progress ul li span.multiline {
width: 71px;
top: 12px;
@ -5322,6 +5329,10 @@ label.error {
z-index: 1000;
}
.multi-wizard.instance-wizard .progress ul li span.arrow {
left: 27px;
}
.multi-wizard .progress ul li.active span.arrow {
background-position: -1px -396px;
}
@ -5342,6 +5353,15 @@ label.error {
background: transparent;
}
.multi-wizard.instance-wizard .progress ul li span.number {
left: 16px;
}
.multi-wizard.instance-wizard .progress ul li span.multiline {
width: 79px;
left: 23px;
}
.multi-wizard .progress ul li.active span {
/*+text-shadow:0px -1px 1px #004AFF;*/
-moz-text-shadow: 0px -1px 1px #004AFF;
@ -11670,7 +11690,6 @@ div.ui-dialog div.autoscaler div.field-group div.form-container form div.form-it
background-position: 0px -707px;
}
.attach .icon,
.attachISO .icon,
.attachDisk .icon {
@ -11854,16 +11873,13 @@ div.ui-dialog div.autoscaler div.field-group div.form-container form div.form-it
}
.removeVlanRange .icon {
background-position: 1px -92px;
}
.removeVlanRange:hover .icon{
.removeVlanRange:hover .icon {
background-position: 1px -92px;
}
.resize .icon,
.updateResourceCount .icon {
background-position: -167px -66px;
@ -11893,9 +11909,8 @@ div.ui-dialog div.autoscaler div.field-group div.form-container form div.form-it
background-position: -168px -31px;
}
.scaleUp .icon{
background-position: -167px -66px;
.scaleUp .icon {
background-position: -167px -66px;
}
.restoreVM:hover .icon,
@ -12027,6 +12042,30 @@ div.ui-dialog div.autoscaler div.field-group div.form-container form div.form-it
background-position: -228px -646px;
}
.changeAffinity .icon {
background-position: -264px -2px;
}
.changeAffinity:hover .icon {
background-position: -263px -583px;
}
.releaseFromAccount .icon {
background-position: -230px -123px;
}
.releaseFromAccount:hover .icon {
background-position: -229px -704px;
}
.addAccount .icon {
background-position: -231px -96px;
}
.addAccount:hover .icon {
background-position: -230px -677px;
}
.label-hovered {
cursor: pointer;
color: #0000FF !important;

View File

@ -25,6 +25,16 @@ under the License.
<% long now = System.currentTimeMillis(); %>
<script language="javascript">
dictionary = {
'label.add.affinity.group': '<fmt:message key="label.add.affinity.group"/>',
'message.delete.affinity.group': '<fmt:message key="message.delete.affinity.group"/>',
'label.delete.affinity.group': '<fmt:message key="label.delete.affinity.group"/>',
'label.edit.affinity.group': '<fmt:message key="label.edit.affinity.group"/>',
'label.affinity': '<fmt:message key="label.affinity"/>',
'label.anti.affinity': '<fmt:message key="label.anti.affinity"/>',
'label.affinity.groups': '<fmt:message key="label.affinity.groups"/>',
'label.anti.affinity.groups': '<fmt:message key="label.anti.affinity.groups"/>',
'label.affinity.group': '<fmt:message key="label.affinity.group"/>',
'label.anti.affinity.group': '<fmt:message key="label.anti.affinity.group"/>',
'message.redirecting.region': '<fmt:message key="message.redirecting.region"/>',
'label.use.vm.ip': '<fmt:message key="label.use.vm.ip"/>',
'label.cpu.limits': '<fmt:message key="label.cpu.limits"/>',

Binary file not shown.

Before

Width:  |  Height:  |  Size: 184 KiB

After

Width:  |  Height:  |  Size: 188 KiB

View File

@ -94,8 +94,9 @@ under the License.
<li><span class="number">2</span><span class="multiline"><fmt:message key="label.select.a.template"/></span><span class="arrow"></span></li>
<li><span class="number">3</span><span class="multiline"><fmt:message key="label.compute.offering"/></span><span class="arrow"></span></li>
<li><span class="number">4</span><span class="multiline"><fmt:message key="label.data.disk.offering"/></span><span class="arrow"></span></li>
<li><span class="number">5</span><span><fmt:message key="label.menu.network"/></span><span class="arrow"></span></li>
<li class="last"><span class="number">6</span><span><fmt:message key="label.review"/></span></li>
<li><span class="number">5</span><span><fmt:message key="label.affinity"/></span><span class="arrow"></span></li>
<li><span class="number">6</span><span><fmt:message key="label.menu.network"/></span><span class="arrow"></span></li>
<li class="last"><span class="number">7</span><span><fmt:message key="label.review"/></span></li>
</ul>
</div>
<form>
@ -225,7 +226,15 @@ under the License.
</div>
</div>
<!-- Step 5: Network -->
<!-- Step 5: Affinity groups -->
<div class="step affinity" wizard-step-id="affinity">
<div class="content">
<!-- Existing offerings -->
<div class="select-container"></div>
</div>
</div>
<!-- Step 6: Network -->
<div class="step network always-load" wizard-step-id="network">
<!-- 5a: Network description -->
<div class="wizard-step-conditional nothing-to-select">
@ -325,7 +334,7 @@ under the License.
</div>
</div>
</div>
<!-- Step 6: Review -->
<!-- Step 7: Review -->
<div class="step review" wizard-step-id="review">
<div class="main-desc">
<fmt:message key="message.vm.review.launch"/>
@ -1660,6 +1669,8 @@ under the License.
<script type="text/javascript" src="scripts/dashboard.js?t=<%=now%>"></script>
<script type="text/javascript" src="scripts/ui-custom/instanceWizard.js?t=<%=now%>"></script>
<script type="text/javascript" src="scripts/instanceWizard.js?t=<%=now%>"></script>
<script type="text/javascript" src="scripts/affinity.js?t=<%=now%>"></script>
<script type="text/javascript" src="scripts/ui-custom/affinity.js?t=<%=now%>"></script>
<script type="text/javascript" src="scripts/instances.js?t=<%=now%>"></script>
<script type="text/javascript" src="scripts/events.js?t=<%=now%>"></script>
<script type="text/javascript" src="scripts/regions.js?t=<%=now%>"></script>

183
ui/scripts/affinity.js Normal file
View File

@ -0,0 +1,183 @@
// 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.sections.affinityGroups = {
title: 'label.affinity.groups',
listView: {
id: 'affinityGroups',
fields: {
name: { label: 'label.name' },
type: { label: 'label.type' }
},
dataProvider: function(args) {
var data = {};
if (args.context != null) {
if ("instances" in args.context) {
$.extend(data, {
virtualmachineid: args.context.instances[0].id
});
}
}
$.ajax({
url: createURL('listAffinityGroups'),
data: data,
success: function(json) {
var items = json.listaffinitygroupsresponse.affinitygroup;
args.response.success({data: items});
}
});
},
actions: {
add: {
label: 'label.add.affinity.group',
messages: {
notification: function(args) {
return 'label.add.affinity.group';
}
},
createForm: {
title: 'label.add.affinity.group',
fields: {
name: {
label: 'label.name',
validation: { required: true }
},
description: {
label: 'label.description'
},
type: {
label: 'label.type',
select: function(args) {
$.ajax({
url: createURL('listAffinityGroupTypes'),
success: function(json) {
var types = [];
var items = json.listaffinitygrouptypesresponse.affinityGroupType;
if(items != null) {
for(var i = 0; i < items.length; i++) {
types.push({id: items[i].type, description: items[i].type});
}
}
args.response.success({data: types})
}
});
}
}
}
},
action: function(args) {
var data = {
name: args.data.name,
type: args.data.type
};
if(args.data.description != null && args.data.description.length > 0)
$.extend(data, {description: args.data.description});
$.ajax({
url: createURL('createAffinityGroup'),
data: data,
success: function(json) {
var jid = json.createaffinitygroupresponse.jobid;
args.response.success(
{_custom:
{jobId: jid,
getUpdatedItem: function(json) {
return json.queryasyncjobresultresponse.jobresult.affinitygroup;
}
}
}
);
}
});
},
notification: {
poll: pollAsyncJobResult
}
}
},
detailView: {
actions: {
remove: {
label: 'label.delete.affinity.group',
messages: {
confirm: function(args) {
return 'message.delete.affinity.group';
},
notification: function(args) {
return 'label.delete.affinity.group';
}
},
action: function(args) {
$.ajax({
url: createURL('deleteAffinityGroup'),
data: {
id: args.context.affinityGroups[0].id
},
success: function(json) {
var jid = json.deleteaffinitygroupresponse.jobid;
args.response.success({
_custom:{
jobId: jid
}
});
}
});
},
notification: {
poll: pollAsyncJobResult
}
}
},
viewAll: { path: 'instances', label: 'label.instances' },
tabs: {
details: {
title: 'label.details',
fields: [
{
name: { label: 'label.name' }
},
{
description: { label: 'label.description' },
type: { label: 'label.type' },
id: { label: 'label.id' }
}
],
dataProvider: function(args) {
$.ajax({
url: createURL('listAffinityGroups'),
data: {
id: args.context.affinityGroups[0].id
},
success: function(json) {
var item = json.listaffinitygroupsresponse.affinitygroup[0];
args.response.success({data: item});
}
});
}
}
}
}
}
};
})(cloudStack);

View File

@ -22,16 +22,16 @@
var sections = [];
if(isAdmin()) {
sections = ["dashboard", "instances", "storage", "network", "templates", "accounts", "domains", "events", "system", "global-settings", "configuration", "projects", "regions"];
sections = ["dashboard", "instances", "storage", "network", "templates", "accounts", "domains", "events", "system", "global-settings", "configuration", "projects", "regions", "affinityGroups"];
}
else if(isDomainAdmin()) {
sections = ["dashboard", "instances", "storage", "network", "templates", "accounts", "domains", "events", "projects", "regions"];
sections = ["dashboard", "instances", "storage", "network", "templates", "accounts", "domains", "events", "projects", "regions", "affinityGroups"];
}
else if (g_userProjectsEnabled) {
sections = ["dashboard", "instances", "storage", "network", "templates", "accounts", "events", "projects", "regions"];
sections = ["dashboard", "instances", "storage", "network", "templates", "accounts", "events", "projects", "regions", "affinityGroups"];
}
else { //normal user
sections = ["dashboard", "instances", "storage", "network", "templates", "accounts", "events", "regions"];
sections = ["dashboard", "instances", "storage", "network", "templates", "accounts", "events", "regions", "affinityGroups"];
}
if (cloudStack.plugins.length) {
@ -46,6 +46,7 @@
*/
dashboard: {},
instances: {},
affinityGroups: {},
storage: {},
network: {},
templates: {},

File diff suppressed because it is too large Load Diff

View File

@ -194,17 +194,23 @@
}
if("hosts" in args.context) {
$.extend(data, {
hostid: args.context.hosts[0].id
});
}
$.extend(data, {
hostid: args.context.hosts[0].id
});
}
if("affinityGroups" in args.context) {
$.extend(data, {
affinitygroupid: args.context.affinityGroups[0].id
});
}
if(args.context.zoneType != null && args.context.zoneType.length > 0) { //Basic type or Advanced type
$.extend(data, {
zonetype: args.context.zoneType
});
}
}
$.ajax({
url: createURL('listVirtualMachines'),
data: data,
@ -223,6 +229,7 @@
viewAll: [
{ path: 'storage.volumes', label: 'label.volumes' },
{ path: 'vmsnapshots', label: 'label.snapshots' },
{ path: 'affinityGroups', label: 'label.affinity.groups' },
{
path: '_zone.hosts',
label: 'label.hosts',
@ -426,7 +433,6 @@
poll: pollAsyncJobResult
}
},
snapshot: {
messages: {
notification: function(args) {
@ -489,7 +495,6 @@
pool: pollAsyncJobResult
}
},
destroy: {
label: 'label.action.destroy.instance',
compactLabel: 'label.destroy',
@ -555,7 +560,6 @@
}
}
},
reset: {
label: 'Reset VM',
messages:{
@ -586,8 +590,128 @@
}
}
},
},
changeAffinity: {
label: 'Change affinity',
action: {
custom: cloudStack.uiCustom.affinity({
tierSelect: function(args) {
if ('vpc' in args.context) { //from VPC section
args.$tierSelect.show(); //show tier dropdown
$.ajax({ //populate tier dropdown
url: createURL("listNetworks"),
async: false,
data: {
vpcid: args.context.vpc[0].id,
//listAll: true, //do not pass listAll to listNetworks under VPC
domainid: args.context.vpc[0].domainid,
account: args.context.vpc[0].account,
supportedservices: 'StaticNat'
},
success: function(json) {
var networks = json.listnetworksresponse.network;
var items = [{ id: -1, description: 'Please select a tier' }];
$(networks).each(function(){
items.push({id: this.id, description: this.displaytext});
});
args.response.success({ data: items });
}
});
}
else { //from Guest Network section
args.$tierSelect.hide();
}
args.$tierSelect.change(function() {
args.$tierSelect.closest('.list-view').listView('refresh');
});
args.$tierSelect.closest('.list-view').listView('refresh');
},
listView: {
listView: {
id: 'affinityGroups',
fields: {
name: { label: 'label.name' },
type: { label: 'label.type' }
},
dataProvider: function(args) {
$.ajax({
url: createURL('listAffinityGroups'),
async: false, //make it sync to avoid dataProvider() being called twice which produces duplicate data
success: function(json) {
var items = [];
var allAffinityGroups = json.listaffinitygroupsresponse.affinitygroup;
var previouslySelectedAffinityGroups = args.context.instances[0].affinitygroup;
if(allAffinityGroups != null) {
for(var i = 0; i < allAffinityGroups.length; i++) {
var isPreviouslySelected = false;
if(previouslySelectedAffinityGroups != null) {
for(var k = 0; k < previouslySelectedAffinityGroups.length; k++) {
if(previouslySelectedAffinityGroups[k].id == allAffinityGroups[i].id) {
isPreviouslySelected = true;
break; //break for loop
}
}
}
items.push($.extend(allAffinityGroups[i], {
_isSelected: isPreviouslySelected
}));
}
}
args.response.success({data: items});
}
});
}
}
},
action: function(args) {
var affinityGroupIdArray = [];
if(args.context.affinityGroups != null) {
for(var i = 0; i < args.context.affinityGroups.length; i++) {
if(args.context.affinityGroups[i]._isSelected == true) {
affinityGroupIdArray.push(args.context.affinityGroups[i].id);
}
}
}
var data = {
id: args.context.instances[0].id,
affinitygroupids: affinityGroupIdArray.join(",")
};
$.ajax({
url: createURL('updateVMAffinityGroup'),
data: data,
success: function(json) {
var jid = json.updatevirtualmachineresponse.jobid;
args.response.success(
{_custom:
{jobId: jid,
getUpdatedItem: function(json) {
return json.queryasyncjobresultresponse.jobresult.virtualmachine;
},
getActionFilter: function() {
return vmActionfilter;
}
}
}
);
}
});
}
})
},
messages: {
notification: function(args) {
return 'Change affinity';
}
},
notification: {
poll: pollAsyncJobResult
}
},
edit: {
label: 'label.edit',
@ -597,7 +721,7 @@
group: args.data.group,
ostypeid: args.data.guestosid
};
if(args.data.displayname != args.context.instances[0].displayname) {
$.extend(data, {
displayName: args.data.displayname
@ -1380,7 +1504,7 @@
args.response.success({data: args.context.instances[0].securitygroup});
}
},
/**
* Statistics tab
*/
@ -1450,6 +1574,7 @@
allowedActions.push("reset");
allowedActions.push("snapshot");
allowedActions.push("scaleUp");
allowedActions.push("changeAffinity");
if(isAdmin())
allowedActions.push("migrateToAnotherStorage");

View File

@ -0,0 +1,173 @@
// 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.affinity = function(args) {
var listView = args.listView;
var action = args.action;
var tierSelect = args.tierSelect;
return function(args) {
var context = args.context;
var $instanceRow = args.$instanceRow;
var vmList = function(args) {
// Create a listing of instances, based on limited information
// from main instances list view
var $listView;
var instances = $.extend(true, {}, args.listView, {
context: context,
uiCustom: true
});
instances.listView.actions = {
select: {
label: _l('label.select.instance'),
type: 'checkbox',
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(instances);
// Change action label
$listView.find('th.actions').html(_l('label.select'));
return $listView;
};
var $dataList = vmList({
listView: listView
}).dialog({
dialogClass: 'multi-edit-add-list panel',
width: 825,
title: _l('label.affinity.groups'),
buttons: [
{
text: _l('label.apply'),
'class': 'ok',
click: function() {
if ($dataList.find('.tier-select select').val() == -1) {
cloudStack.dialog.notice({ message: ('Please select a tier')});
return false;
}
var complete = args.complete;
var start = args.start;
start();
$dataList.fadeOut(function() {
action({
tierID: $dataList.find('.tier-select select').val(),
_subselect: $dataList.find('tr.multi-edit-selected .subselect select').val(),
context: $.extend(true, {}, context, {
affinityGroups: $dataList.find('tbody tr').map(function(index, elem) {
var itemData = $(elem).data('json-obj');
itemData._isSelected = false;
if ($(elem).hasClass('multi-edit-selected')) {
itemData._isSelected = true;
}
return itemData;
})
}),
response: {
success: function(args) {
complete({
_custom: args._custom,
$item: $instanceRow
});
},
error: function(args) {
cloudStack.dialog.notice({ message: args });
}
}
});
$dataList.remove();
});
$('div.overlay').fadeOut(function() {
$('div.overlay').remove();
$(':ui-dialog').dialog('destroy');
});
}
},
{
text: _l('label.cancel'),
'class': 'cancel',
click: function() {
$dataList.fadeOut(function() {
$dataList.remove();
});
$('div.overlay').fadeOut(function() {
$('div.overlay').remove();
$(':ui-dialog').dialog('destroy');
});
}
}
]
}).parent('.ui-dialog').overlay();
// Add tier select dialog
if (tierSelect) {
var $toolbar = $dataList.find('.toolbar');
var $tierSelect = $('<div>').addClass('filters tier-select').prependTo($toolbar);
var $tierSelectLabel = $('<label>').html('Select tier').appendTo($tierSelect);
var $tierSelectInput = $('<select>').appendTo($tierSelect);
// Get tier data
tierSelect({
context: context,
$tierSelect: $tierSelect,
response: {
success: function(args) {
var data = args.data;
$(data).map(function(index, item) {
var $option = $('<option>');
$option.attr('value', item.id);
$option.html(item.description);
$option.appendTo($tierSelectInput);
});
},
error: function(message) {
cloudStack.dialog.notice({
message: message ? message : 'Could not retrieve VPC tiers'
});
}
}
});
}
};
};
}(cloudStack, jQuery));

View File

@ -482,6 +482,25 @@
};
},
'affinity': function($step, formData) {
return {
response: {
success: function(args) {
$step.find('.select-container').append(
makeSelects('affinity-groups', args.data.affinityGroups, {
name: 'name',
desc: 'description',
id: 'id'
}, {
type: 'checkbox',
'wizard-field': 'affinity-groups'
})
);
}
}
};
},
'network': function($step, formData) {
var showAddNetwork = true;

View File

@ -15,8 +15,9 @@
// specific language governing permissions and limitations
// under the License.
(function($, cloudStack, _l) {
var replaceListViewItem = function($detailView, newData) {
var $row = $detailView.data('list-view-row');
var replaceListViewItem = function($detailView, newData, options) {
var $row = $detailView ? $detailView.data('list-view-row') :
options.$row;
if (!$row) return;
@ -32,7 +33,9 @@
$row: $row,
data: $.extend(jsonObj, newData),
after: function($newRow) {
$detailView.data('list-view-row', $newRow);
if ($detailView) {
$detailView.data('list-view-row', $newRow);
}
setTimeout(function() {
$('.data-table').dataTable('selectRow', $newRow.index());
@ -42,11 +45,13 @@
}
// Refresh detail view context
$.extend(
$detailView.data('view-args').context[
$detailView.data('view-args').section
][0], newData
);
if ($detailView) {
$.extend(
$detailView.data('view-args').context[
$detailView.data('view-args').section
][0], newData
);
}
};
/**
@ -125,6 +130,7 @@
args = args ? args : {};
var $item = args.$item;
var $row = $detailView.data('list-view-row');
notification.desc = messages.notification(args.messageArgs);
notification._custom = $.extend(args._custom ? args._custom : {}, {
@ -140,11 +146,14 @@
viewArgs.onActionComplete();
}
if (!$detailView.parents('html').size()) return;
if (!$detailView.parents('html').size()) {
replaceListViewItem(null, args.data, { $row: $row });
return;
}
replaceListViewItem($detailView, args.data);
$loading.remove();
$detailView.removeClass('detail-view-loading-state');
replaceListViewItem($detailView, args.data);
if (!noRefresh) {
updateTabContent(args.data);

View File

@ -734,6 +734,8 @@
var makeActionIcons = function($td, actions, options) {
options = options ? options : {};
var allowedActions = options.allowedActions;
var $tr = $td.closest('tr');
var data = $tr && $tr.data('json-obj') ? $tr.data('json-obj') : null;
$.each(actions, function(actionName, action) {
if (actionName == 'add' || action.isHeader)
@ -766,7 +768,9 @@
.append(
$('<input>').attr({
type: 'checkbox',
name: actionName
name: actionName,
checked: data && data._isSelected ?
'checked' : false
})
)
.attr({
@ -776,6 +780,10 @@
.data('list-view-action-id', actionName)
);
if ($td.find('input[type=checkbox]').is(':checked')) {
$tr.addClass('multi-edit-selected');
}
return true;
}