Repository: cloudstack
Updated Branches:
  refs/heads/master 30aef2890 -> 202b92f24


CLOUDSTACK-9457: Allow retrieval and modification of VM and template details 
via API and UI


Project: http://git-wip-us.apache.org/repos/asf/cloudstack/repo
Commit: http://git-wip-us.apache.org/repos/asf/cloudstack/commit/e8049af1
Tree: http://git-wip-us.apache.org/repos/asf/cloudstack/tree/e8049af1
Diff: http://git-wip-us.apache.org/repos/asf/cloudstack/diff/e8049af1

Branch: refs/heads/master
Commit: e8049af1534f1ab2cc8335034c2fd76c67f9fdec
Parents: 0db4471
Author: nvazquez <[email protected]>
Authored: Tue Dec 27 23:33:50 2016 -0300
Committer: nvazquez <[email protected]>
Committed: Tue Dec 27 23:33:50 2016 -0300

----------------------------------------------------------------------
 .../org/apache/cloudstack/api/ApiConstants.java |   1 +
 .../api/BaseUpdateTemplateOrIsoCmd.java         |  12 +-
 .../api/command/user/vm/UpdateVMCmd.java        |   9 +
 .../com/cloud/storage/VMTemplateDetailVO.java   |  16 ++
 .../schema/src/com/cloud/vm/UserVmDetailVO.java |   7 +
 .../cloud/api/query/dao/UserVmJoinDaoImpl.java  |  11 +-
 .../com/cloud/template/TemplateManagerImpl.java |  13 +-
 server/src/com/cloud/vm/UserVmManagerImpl.java  |  14 +-
 .../cloud/template/TemplateManagerImplTest.java |   9 +
 ui/scripts/instances.js                         | 167 ++++++++++++++++++-
 ui/scripts/templates.js                         | 121 +++++++++++++-
 ui/scripts/ui-custom/granularSettings.js        |  86 +++++++++-
 12 files changed, 445 insertions(+), 21 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cloudstack/blob/e8049af1/api/src/org/apache/cloudstack/api/ApiConstants.java
----------------------------------------------------------------------
diff --git a/api/src/org/apache/cloudstack/api/ApiConstants.java 
b/api/src/org/apache/cloudstack/api/ApiConstants.java
index 00e9d38..f7f2a37 100644
--- a/api/src/org/apache/cloudstack/api/ApiConstants.java
+++ b/api/src/org/apache/cloudstack/api/ApiConstants.java
@@ -648,6 +648,7 @@ public class ApiConstants {
     public static final String OVM3_POOL = "ovm3pool";
     public static final String OVM3_CLUSTER = "ovm3cluster";
     public static final String OVM3_VIP = "ovm3vip";
+    public static final String CLEAN_UP_DETAILS = "cleanupdetails";
 
     public static final String ADMIN = "admin";
 

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/e8049af1/api/src/org/apache/cloudstack/api/BaseUpdateTemplateOrIsoCmd.java
----------------------------------------------------------------------
diff --git a/api/src/org/apache/cloudstack/api/BaseUpdateTemplateOrIsoCmd.java 
b/api/src/org/apache/cloudstack/api/BaseUpdateTemplateOrIsoCmd.java
index 5dc2b06..3676734 100644
--- a/api/src/org/apache/cloudstack/api/BaseUpdateTemplateOrIsoCmd.java
+++ b/api/src/org/apache/cloudstack/api/BaseUpdateTemplateOrIsoCmd.java
@@ -17,7 +17,6 @@
 package org.apache.cloudstack.api;
 
 import org.apache.log4j.Logger;
-
 import org.apache.cloudstack.api.command.user.iso.UpdateIsoCmd;
 import org.apache.cloudstack.api.response.GuestOSResponse;
 import org.apache.cloudstack.api.response.TemplateResponse;
@@ -73,6 +72,11 @@ public abstract class BaseUpdateTemplateOrIsoCmd extends 
BaseCmd {
     @Parameter(name = ApiConstants.DETAILS, type = CommandType.MAP, 
description = "Details in key/value pairs using format 
details[i].keyname=keyvalue. Example: 
details[0].hypervisortoolsversion=xenserver61")
     protected Map details;
 
+    @Parameter(name = ApiConstants.CLEAN_UP_DETAILS,
+            type = CommandType.BOOLEAN,
+            description = "optional boolean field, which indicates if details 
should be cleaned up or not (if set to true, details removed for this resource, 
details field ignored; if false or not set, no action)")
+    private Boolean cleanupDetails;
+
     /////////////////////////////////////////////////////
     /////////////////// Accessors ///////////////////////
     /////////////////////////////////////////////////////
@@ -129,4 +133,8 @@ public abstract class BaseUpdateTemplateOrIsoCmd extends 
BaseCmd {
         Collection paramsCollection = this.details.values();
         return (Map) (paramsCollection.toArray())[0];
     }
-}
\ No newline at end of file
+
+    public boolean isCleanupDetails(){
+        return cleanupDetails == null ? false : cleanupDetails.booleanValue();
+    }
+}

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/e8049af1/api/src/org/apache/cloudstack/api/command/user/vm/UpdateVMCmd.java
----------------------------------------------------------------------
diff --git a/api/src/org/apache/cloudstack/api/command/user/vm/UpdateVMCmd.java 
b/api/src/org/apache/cloudstack/api/command/user/vm/UpdateVMCmd.java
index 4508f7e..eb03f08 100644
--- a/api/src/org/apache/cloudstack/api/command/user/vm/UpdateVMCmd.java
+++ b/api/src/org/apache/cloudstack/api/command/user/vm/UpdateVMCmd.java
@@ -116,6 +116,11 @@ public class UpdateVMCmd extends BaseCustomIdCmd 
implements SecurityGroupAction
             )
     private List<String> securityGroupNameList;
 
+    @Parameter(name = ApiConstants.CLEAN_UP_DETAILS,
+            type = CommandType.BOOLEAN,
+            description = "optional boolean field, which indicates if details 
should be cleaned up or not (if set to true, details removed for this resource, 
details field ignored; if false or not set, no action)")
+    private Boolean cleanupDetails;
+
     /////////////////////////////////////////////////////
     /////////////////// Accessors ///////////////////////
     /////////////////////////////////////////////////////
@@ -173,6 +178,10 @@ public class UpdateVMCmd extends BaseCustomIdCmd 
implements SecurityGroupAction
         return securityGroupNameList;
     }
 
+    public boolean isCleanupDetails(){
+        return cleanupDetails == null ? false : cleanupDetails.booleanValue();
+    }
+
     /////////////////////////////////////////////////////
     /////////////// API Implementation///////////////////
     /////////////////////////////////////////////////////

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/e8049af1/engine/schema/src/com/cloud/storage/VMTemplateDetailVO.java
----------------------------------------------------------------------
diff --git a/engine/schema/src/com/cloud/storage/VMTemplateDetailVO.java 
b/engine/schema/src/com/cloud/storage/VMTemplateDetailVO.java
old mode 100644
new mode 100755
index f988aba..5010edf
--- a/engine/schema/src/com/cloud/storage/VMTemplateDetailVO.java
+++ b/engine/schema/src/com/cloud/storage/VMTemplateDetailVO.java
@@ -79,4 +79,20 @@ public class VMTemplateDetailVO implements ResourceDetail {
     public boolean isDisplay() {
         return display;
     }
+
+    public void setId(long id) {
+        this.id = id;
+    }
+
+    public void setResourceId(long resourceId) {
+        this.resourceId = resourceId;
+    }
+
+    public void setName(String name) {
+        this.name = name;
+    }
+
+    public void setValue(String value) {
+        this.value = value;
+    }
 }

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/e8049af1/engine/schema/src/com/cloud/vm/UserVmDetailVO.java
----------------------------------------------------------------------
diff --git a/engine/schema/src/com/cloud/vm/UserVmDetailVO.java 
b/engine/schema/src/com/cloud/vm/UserVmDetailVO.java
old mode 100644
new mode 100755
index 2b169a3..81bb6dd
--- a/engine/schema/src/com/cloud/vm/UserVmDetailVO.java
+++ b/engine/schema/src/com/cloud/vm/UserVmDetailVO.java
@@ -80,4 +80,11 @@ public class UserVmDetailVO implements ResourceDetail {
         return display;
     }
 
+    public void setName(String name) {
+        this.name = name;
+    }
+
+    public void setValue(String value) {
+        this.value = value;
+    }
 }

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/e8049af1/server/src/com/cloud/api/query/dao/UserVmJoinDaoImpl.java
----------------------------------------------------------------------
diff --git a/server/src/com/cloud/api/query/dao/UserVmJoinDaoImpl.java 
b/server/src/com/cloud/api/query/dao/UserVmJoinDaoImpl.java
index 106cd25..75b42c2 100644
--- a/server/src/com/cloud/api/query/dao/UserVmJoinDaoImpl.java
+++ b/server/src/com/cloud/api/query/dao/UserVmJoinDaoImpl.java
@@ -51,7 +51,6 @@ import com.cloud.utils.db.SearchBuilder;
 import com.cloud.utils.db.SearchCriteria;
 import com.cloud.vm.UserVmDetailVO;
 import com.cloud.vm.VirtualMachine.State;
-import com.cloud.vm.VmDetailConstants;
 import com.cloud.vm.VmStats;
 import com.cloud.vm.dao.NicSecondaryIpVO;
 import com.cloud.vm.dao.UserVmDetailsDao;
@@ -292,11 +291,13 @@ public class UserVmJoinDaoImpl extends 
GenericDaoBaseWithTagInformation<UserVmJo
         }
 
         // set resource details map
-        // only hypervisortoolsversion can be returned to the end user
-        UserVmDetailVO hypervisorToolsVersion = 
_userVmDetailsDao.findDetail(userVm.getId(), 
VmDetailConstants.HYPERVISOR_TOOLS_VERSION);
-        if (hypervisorToolsVersion != null) {
+        // Allow passing details to end user
+        List<UserVmDetailVO> vmDetails = 
_userVmDetailsDao.listDetails(userVm.getId());
+        if (vmDetails != null) {
             Map<String, String> resourceDetails = new HashMap<String, 
String>();
-            resourceDetails.put(hypervisorToolsVersion.getName(), 
hypervisorToolsVersion.getValue());
+            for (UserVmDetailVO userVmDetailVO : vmDetails) {
+                resourceDetails.put(userVmDetailVO.getName(), 
userVmDetailVO.getValue());
+            }
             userVmResponse.setDetails(resourceDetails);
         }
 

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/e8049af1/server/src/com/cloud/template/TemplateManagerImpl.java
----------------------------------------------------------------------
diff --git a/server/src/com/cloud/template/TemplateManagerImpl.java 
b/server/src/com/cloud/template/TemplateManagerImpl.java
index 7130042..c20889e 100644
--- a/server/src/com/cloud/template/TemplateManagerImpl.java
+++ b/server/src/com/cloud/template/TemplateManagerImpl.java
@@ -161,6 +161,7 @@ import com.cloud.storage.dao.LaunchPermissionDao;
 import com.cloud.storage.dao.SnapshotDao;
 import com.cloud.storage.dao.StoragePoolHostDao;
 import com.cloud.storage.dao.VMTemplateDao;
+import com.cloud.storage.dao.VMTemplateDetailsDao;
 import com.cloud.storage.dao.VMTemplatePoolDao;
 import com.cloud.storage.dao.VMTemplateZoneDao;
 import com.cloud.storage.dao.VolumeDao;
@@ -269,6 +270,8 @@ public class TemplateManagerImpl extends ManagerBase 
implements TemplateManager,
     private ImageStoreDao _imgStoreDao;
     @Inject
     MessageBus _messageBus;
+    @Inject
+    private VMTemplateDetailsDao _tmpltDetailsDao;
 
     private boolean _disableExtraction = false;
     private List<TemplateAdapter> _adapters;
@@ -1880,6 +1883,7 @@ public class TemplateManagerImpl extends ManagerBase 
implements TemplateManager,
         Integer sortKey = cmd.getSortKey();
         Map details = cmd.getDetails();
         Account account = CallContext.current().getCallingAccount();
+        boolean cleanupDetails = cmd.isCleanupDetails();
 
         // verify that template exists
         VMTemplateVO template = _tmpltDao.findById(id);
@@ -1911,7 +1915,8 @@ public class TemplateManagerImpl extends ManagerBase 
implements TemplateManager,
                   sortKey == null &&
                   isDynamicallyScalable == null &&
                   isRoutingTemplate == null &&
-                        details == null);
+                  (! cleanupDetails && details == null) //update details in 
every case except this one
+                  );
         if (!updateNeeded) {
             return template;
         }
@@ -1989,7 +1994,11 @@ public class TemplateManagerImpl extends ManagerBase 
implements TemplateManager,
             }
         }
 
-        if (details != null && !details.isEmpty()) {
+        if (cleanupDetails) {
+            template.setDetails(null);
+            _tmpltDetailsDao.removeDetails(id);
+        }
+        else if (details != null && !details.isEmpty()) {
             template.setDetails(details);
             _tmpltDao.saveDetails(template);
         }

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/e8049af1/server/src/com/cloud/vm/UserVmManagerImpl.java
----------------------------------------------------------------------
diff --git a/server/src/com/cloud/vm/UserVmManagerImpl.java 
b/server/src/com/cloud/vm/UserVmManagerImpl.java
index 453800d..1db0956 100644
--- a/server/src/com/cloud/vm/UserVmManagerImpl.java
+++ b/server/src/com/cloud/vm/UserVmManagerImpl.java
@@ -2307,6 +2307,7 @@ public class UserVmManagerImpl extends ManagerBase 
implements UserVmManager, Vir
         Map<String,String> details = cmd.getDetails();
         Account caller = CallContext.current().getCallingAccount();
         List<Long> securityGroupIdList = getSecurityGroupIdList(cmd);
+        boolean cleanupDetails = cmd.isCleanupDetails();
 
         // Input validation and permission checks
         UserVmVO vmInstance = _vmDao.findById(id);
@@ -2345,14 +2346,11 @@ public class UserVmManagerImpl extends ManagerBase 
implements UserVmManager, Vir
 
         }
 
-        if (details != null && !details.isEmpty()) {
-            _vmDao.loadDetails(vmInstance);
-
-            for(Map.Entry<String,String> entry : details.entrySet()) {
-                if(entry instanceof Map.Entry) {
-                    vmInstance.setDetail(entry.getKey(), entry.getValue());
-                }
-            }
+        if (cleanupDetails){
+            _vmDetailsDao.removeDetails(id);
+        }
+        else if (details != null && !details.isEmpty()) {
+            vmInstance.setDetails(details);
             _vmDao.saveDetails(vmInstance);
         }
 

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/e8049af1/server/test/com/cloud/template/TemplateManagerImplTest.java
----------------------------------------------------------------------
diff --git a/server/test/com/cloud/template/TemplateManagerImplTest.java 
b/server/test/com/cloud/template/TemplateManagerImplTest.java
index 6e16938..61a8a4a 100644
--- a/server/test/com/cloud/template/TemplateManagerImplTest.java
+++ b/server/test/com/cloud/template/TemplateManagerImplTest.java
@@ -45,6 +45,7 @@ import com.cloud.storage.dao.LaunchPermissionDao;
 import com.cloud.storage.dao.SnapshotDao;
 import com.cloud.storage.dao.StoragePoolHostDao;
 import com.cloud.storage.dao.VMTemplateDao;
+import com.cloud.storage.dao.VMTemplateDetailsDao;
 import com.cloud.storage.dao.VMTemplatePoolDao;
 import com.cloud.storage.dao.VMTemplateZoneDao;
 import com.cloud.storage.dao.VolumeDao;
@@ -161,6 +162,9 @@ public class TemplateManagerImplTest {
     @Inject
     SnapshotDao snapshotDao;
 
+    @Inject
+    VMTemplateDetailsDao tmpltDetailsDao;
+
     public class CustomThreadPoolExecutor extends ThreadPoolExecutor {
         AtomicInteger ai = new AtomicInteger(0);
         public CustomThreadPoolExecutor(int corePoolSize, int maximumPoolSize, 
long keepAliveTime, TimeUnit unit,
@@ -623,6 +627,11 @@ public class TemplateManagerImplTest {
             return Mockito.mock(TemplateAdapter.class);
         }
 
+        @Bean
+        public VMTemplateDetailsDao vmTemplateDetailsDao() {
+            return Mockito.mock(VMTemplateDetailsDao.class);
+        }
+
         public static class Library implements TypeFilter {
             @Override
             public boolean match(MetadataReader mdr, MetadataReaderFactory 
arg1) throws IOException {

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/e8049af1/ui/scripts/instances.js
----------------------------------------------------------------------
diff --git a/ui/scripts/instances.js b/ui/scripts/instances.js
index 19db257..ec10df8 100644
--- a/ui/scripts/instances.js
+++ b/ui/scripts/instances.js
@@ -497,6 +497,10 @@
                     if (includingSecurityGroupService == false) {
                         hiddenTabs.push("securityGroups");
                     }
+                                       
+                                       if (args.context.instances[0].state == 
'Running') {
+                                               hiddenTabs.push("settings");
+                                       }
 
                     return hiddenTabs;
                 },
@@ -2679,11 +2683,172 @@
                                 }
                             });
                         }
-                    }
+                    },
+                                       
+                                       /**
+                     * Settings tab
+                     */
+                                       settings: {
+                                               title: 'label.settings',
+                                               custom: 
cloudStack.uiCustom.granularDetails({
+                                                       dataProvider: 
function(args) {
+                                                               $.ajax({
+                                                                       url: 
createURL('listVirtualMachines&id=' + args.context.instances[0].id),
+                                                                       
success: function(json) {
+                                                                               
var details = json.listvirtualmachinesresponse.virtualmachine[0].details;
+                                                                               
args.response.success({
+                                                                               
        data: parseDetails(details)
+                                                                               
});
+                                                                       },
+
+                                                                       error: 
function(json) {
+                                                                               
args.response.error(parseXMLHttpResponse(json));
+                                                                       }
+                                                               });
+
+                                                       },
+                                                       actions: {
+                                                               edit: 
function(args) {
+                                                                       var 
data = {
+                                                                               
name: args.data.jsonObj.name,
+                                                                               
value: args.data.value
+                                                                       };
+                                                                       var 
existingDetails;
+                                                                       $.ajax({
+                                                                               
url: createURL('listVirtualMachines&id=' + args.context.instances[0].id),
+                                                                               
async:false,
+                                                                               
success: function(json) {
+                                                                               
        var details = 
json.listvirtualmachinesresponse.virtualmachine[0].details;
+                                                                               
        console.log(details);
+                                                                               
        existingDetails = details;
+                                                                               
},
+
+                                                                               
error: function(json) {
+                                                                               
        args.response.error(parseXMLHttpResponse(json));
+                                                                               
}
+                                                                       });
+                                                                       
console.log(existingDetails);
+                                                                       var 
newDetails = '';
+                                                                       for (d 
in existingDetails) {
+                                                                               
if (d != data.name) {
+                                                                               
        newDetails += 'details[0].' + d + '=' + existingDetails[d] + '&';
+                                                                               
}
+                                                                       }
+                                                                       
newDetails += 'details[0].' + data.name + '=' + data.value;
+                                                                       
+                                                                       $.ajax({
+                                                                               
url: createURL('updateVirtualMachine&id=' + args.context.instances[0].id + '&' 
+ newDetails),
+                                                                               
async:false,
+                                                                               
success: function(json) {
+                                                                               
        var items = json.updatevirtualmachineresponse.virtualmachine.details;
+                                                                               
        args.response.success({
+                                                                               
                data: parseDetails(items)
+                                                                               
        });
+                                                                               
},
+
+                                                                               
error: function(json) {
+                                                                               
        args.response.error(parseXMLHttpResponse(json));
+                                                                               
}
+                                                                       });
+                                                               },
+                                                               remove: 
function(args) {
+                                                                       var 
existingDetails;
+                                                                       $.ajax({
+                                                                               
url: createURL('listVirtualMachines&id=' + args.context.instances[0].id),
+                                                                               
async:false,
+                                                                               
success: function(json) {
+                                                                               
        var details = 
json.listvirtualmachinesresponse.virtualmachine[0].details;
+                                                                               
        existingDetails = details;
+                                                                               
},
+
+                                                                               
error: function(json) {
+                                                                               
        args.response.error(parseXMLHttpResponse(json));
+                                                                               
}
+                                                                       });
+                                                                       
+                                                                       var 
detailToDelete = args.data.jsonObj.name;
+                                                                       var 
newDetails = ''
+                                                                       for 
(detail in existingDetails) {
+                                                                               
if (detail != detailToDelete) {
+                                                                               
        newDetails += 'details[0].' + detail + '=' + existingDetails[detail] + 
'&';
+                                                                               
}
+                                                                       }
+                                                                       if 
(newDetails != '') {
+                                                                               
newDetails = newDetails.substring(0, newDetails.length - 1);
+                                                                       }
+                                                                       else {
+                                                                               
newDetails += 'cleanupdetails=true'
+                                                                       }
+                                                                       $.ajax({
+                                                                               
url: createURL('updateVirtualMachine&id=' + args.context.instances[0].id + '&' 
+ newDetails),
+                                                                               
async:false,
+                                                                               
success: function(json) {
+                                                                               
        var items = json.updatevirtualmachineresponse.virtualmachine.details;
+                                                                               
        args.response.success({
+                                                                               
                data: parseDetails(items)
+                                                                               
        });
+                                                                               
},
+                                                                               
error: function(json) {
+                                                                               
        args.response.error(parseXMLHttpResponse(json));
+                                                                               
}
+                                                                       });
+                                                               },
+                                                               add: 
function(args) {
+                                                                       var 
name = args.data.name;
+                                                                       var 
value = args.data.value;
+                                                                       
+                                                                       var 
details;
+                                                                       $.ajax({
+                                                                               
url: createURL('listVirtualMachines&id=' + args.context.instances[0].id),
+                                                                               
async:false,
+                                                                               
success: function(json) {
+                                                                               
        var dets = json.listvirtualmachinesresponse.virtualmachine[0].details;
+                                                                               
        details = dets;
+                                                                               
},
+
+                                                                               
error: function(json) {
+                                                                               
        args.response.error(parseXMLHttpResponse(json));
+                                                                               
}
+                                                                       });
+                                                                       
+                                                                       var 
detailsFormat = '';
+                                                                       for 
(key in details) {
+                                                                               
detailsFormat += "details[0]." + key + "=" + details[key] + "&";
+                                                                       }
+                                                                       // Add 
new detail to the existing ones
+                                                                       
detailsFormat += "details[0]." + name + "=" + value;
+                                                                       $.ajax({
+                                                                               
url: createURL('updateVirtualMachine&id=' + args.context.instances[0].id + "&" 
+ detailsFormat),
+                                                                               
async: false,
+                                                                               
success: function(json) {
+                                                                               
        var items = json.updatevirtualmachineresponse.virtualmachine.details;
+                                                                               
        args.response.success({
+                                                                               
                data: parseDetails(items)
+                                                                               
        });
+                                                                               
},
+                                                                               
error: function(json) {
+                                                                               
        args.response.error(parseXMLHttpResponse(json));
+                                                                               
}
+                                                                       });
+                                                               }
+                                                       }
+                                               })
+                                       }
                 }
             }
         }
     };
+       
+       var parseDetails = function(details) {
+               var listDetails = [];
+               for (detail in details){
+                       var det = {};
+                       det["name"] = detail;
+                       det["value"] = details[detail];
+                       listDetails.push(det);
+               }
+               return listDetails;
+       }
 
     var vmActionfilter = cloudStack.actionFilter.vmActionFilter = 
function(args) {
         var jsonObj = args.context.item;

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/e8049af1/ui/scripts/templates.js
----------------------------------------------------------------------
diff --git a/ui/scripts/templates.js b/ui/scripts/templates.js
old mode 100644
new mode 100755
index 96ef43a..26f0fd1
--- a/ui/scripts/templates.js
+++ b/ui/scripts/templates.js
@@ -1780,8 +1780,125 @@
                                         }
                                     }}
                                 }
-                            }
-                        }
+                            },
+                            /**
+                                                        * Settings tab
+                                                        */
+                                                       settings: {
+                                                               title: 
'label.settings',
+                                                               custom: 
cloudStack.uiCustom.granularDetails({
+                                                                       
dataProvider: function(args) {
+                                                                               
$.ajax({
+                                                                               
        url: createURL('listTemplates'),
+                                                                               
        data: {
+                                                                               
                templatefilter: "self",
+                                                                               
                id: args.context.templates[0].id
+                                                                               
        },
+                                                                               
        success: function(json) {
+                                                                               
                var details = json.listtemplatesresponse.template[0].details;
+                                                                               
                var listDetails = [];
+                                                                               
                for (detail in details){
+                                                                               
                        var det = {};
+                                                                               
                        det["name"] = detail;
+                                                                               
                        det["value"] = details[detail];
+                                                                               
                        listDetails.push(det);
+                                                                               
                }
+                                                                               
                args.response.success({
+                                                                               
                        data: listDetails
+                                                                               
                });
+                                                                               
        },
+
+                                                                               
        error: function(json) {
+                                                                               
                args.response.error(parseXMLHttpResponse(json));
+                                                                               
        }
+                                                                               
});
+
+                                                                       },
+                                                                       
actions: {
+                                                                               
edit: function(args) {
+                                                                               
        var data = {
+                                                                               
                name: args.data.jsonObj.name,
+                                                                               
                value: args.data.value
+                                                                               
        };
+                                                                               
        var existingDetails = args.context.templates[0].details;
+                                                                               
        var newDetails = '';
+                                                                               
        for (d in existingDetails) {
+                                                                               
                if (d != data.name) {
+                                                                               
                        newDetails += 'details[0].' + d + '=' + 
existingDetails[d] + '&';
+                                                                               
                }
+                                                                               
        }
+                                                                               
        newDetails += 'details[0].' + data.name + '=' + data.value;
+                                                                               
        
+                                                                               
        $.ajax({
+                                                                               
                url: createURL('updateTemplate&id=' + 
args.context.templates[0].id + '&' + newDetails),
+                                                                               
                success: function(json) {
+                                                                               
                        var template = json.updatetemplateresponse.template;
+                                                                               
                        args.context.templates[0].details = template.details;
+                                                                               
                        args.response.success({
+                                                                               
                                data: template.details
+                                                                               
                        });
+                                                                               
                },
+
+                                                                               
                error: function(json) {
+                                                                               
                        args.response.error(parseXMLHttpResponse(json));
+                                                                               
                }
+                                                                               
        });
+                                                                               
},
+                                                                               
remove: function(args) {
+                                                                               
        var existingDetails = args.context.templates[0].details;
+                                                                               
        var detailToDelete = args.data.jsonObj.name;
+                                                                               
        var newDetails = ''
+                                                                               
        for (detail in existingDetails) {
+                                                                               
                if (detail != detailToDelete) {
+                                                                               
                        newDetails += 'details[0].' + detail + '=' + 
existingDetails[detail] + '&';
+                                                                               
                }
+                                                                               
        }
+                                                                               
        if (newDetails != '') {
+                                                                               
                newDetails = newDetails.substring(0, newDetails.length - 1);
+                                                                               
        }
+                                                                               
        else {
+                                                                               
                newDetails += 'cleanupdetails=true';
+                                                                               
        }
+                                                                               
        $.ajax({
+                                                                               
                url: createURL('updateTemplate&id=' + 
args.context.templates[0].id + '&' + newDetails),
+                                                                               
                success: function(json) {
+                                                                               
                        var template = json.updatetemplateresponse.template;
+                                                                               
                        args.context.templates[0].details = template.details;
+                                                                               
                        args.response.success({
+                                                                               
                                data: template.details
+                                                                               
                        });
+                                                                               
                },
+                                                                               
                error: function(json) {
+                                                                               
                        args.response.error(parseXMLHttpResponse(json));
+                                                                               
                }
+                                                                               
        });
+                                                                               
},
+                                                                               
add: function(args) {
+                                                                               
        var name = args.data.name;
+                                                                               
        var value = args.data.value;
+                                                                               
        var details = args.context.templates[0].details;
+                                                                               
        var detailsFormat = '';
+                                                                               
        for (key in details) {
+                                                                               
                detailsFormat += "details[0]." + key + "=" + details[key] + "&";
+                                                                               
        }
+                                                                               
        // Add new detail to the existing ones
+                                                                               
        detailsFormat += "details[0]." + name + "=" + value;
+                                                                               
        $.ajax({
+                                                                               
                url: createURL('updateTemplate&id=' + 
args.context.templates[0].id + "&" + detailsFormat),
+                                                                               
                async: false,
+                                                                               
                success: function(json) {
+                                                                               
                        var template = json.updatetemplateresponse.template;
+                                                                               
                        args.context.templates[0].details = template.details;
+                                                                               
                        args.response.success({
+                                                                               
                                data: template.details
+                                                                               
                        });
+                                                                               
                }
+                                                                               
        });
+                                                                               
}
+                                                                       }
+                                                               })
+                                                       }
+                                               }
                     }
                 }
             },

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/e8049af1/ui/scripts/ui-custom/granularSettings.js
----------------------------------------------------------------------
diff --git a/ui/scripts/ui-custom/granularSettings.js 
b/ui/scripts/ui-custom/granularSettings.js
index 5ab60b7..5312394 100644
--- a/ui/scripts/ui-custom/granularSettings.js
+++ b/ui/scripts/ui-custom/granularSettings.js
@@ -54,4 +54,88 @@
             return $listView;
         }
     };
-}(jQuery, cloudStack));
+       cloudStack.uiCustom.granularDetails = function(args) {
+        var dataProvider = args.dataProvider;
+        var actions = args.actions;
+
+        return function(args) {
+            var context = args.context;
+
+            var listView = {
+                id: 'details',
+                fields: {
+                    name: {
+                        label: 'label.name'
+                    },
+                    value: {
+                        label: 'label.value',
+                        editable: true
+                    }
+                },
+                actions: {
+                    edit: {
+                        label: 'label.change.value',
+                        action: actions.edit
+                    },
+                                       remove: {
+                                               label: 'Remove Setting',
+                                               messages: {
+                                                       confirm: function(args) 
{
+                                                               return 'Delete 
Setting';
+                                                       },
+                                                       notification: 
function(args) {
+                                                               return 'Setting 
deleted';
+                                                       }
+                                               },
+                                               action: actions.remove,
+                                               notification: {
+                                                       poll: function(args) {
+                                                               args.complete();
+                                                       }
+                                               }
+                                       },
+                                       add : {
+                                               label: 'Add Setting',
+                                               messages: {
+                                                       confirm: function(args) 
{
+                                                               return 'Add 
Setting';
+                                                       },
+                                                       notification: 
function(args) {
+                                                               return 'Setting 
added';
+                                                       }
+                                               },
+                                               preFilter: function(args) {
+                                                       return true;
+                                               },
+                                               createForm: {
+                                                       title: 'Add New 
Setting',
+                                                       fields: {
+                                                               name: {
+                                                                       label: 
'label.name',
+                                                                       
validation: {
+                                                                               
required: true
+                                                                       }
+                                                               },
+                                                               value: {
+                                                                       label: 
'label.value',
+                                                                       
validation: {
+                                                                               
required: true
+                                                                       }
+                                                               }
+                                                       }
+                                               },
+                                               action: actions.add
+                                       }
+                },
+                dataProvider: dataProvider
+            };
+
+            var $listView = $('<div>').listView({
+                context: context,
+                listView: listView
+            });
+
+            return $listView;
+        }
+    };
+}(jQuery, cloudStack));
\ No newline at end of file

Reply via email to