diff --git a/.gitattributes b/.gitattributes
index 8da9e1b9ac3cd1c37f90a88a441cce8e225ec754..444a34e600bf8007460446644293d7196ec39179 100644
--- a/.gitattributes
+++ b/.gitattributes
@@ -4751,6 +4751,7 @@ SAS/ResourceAssignment/ResourceAssignmentEditor/lib/__init__.py -text
 SAS/ResourceAssignment/ResourceAssignmentEditor/lib/fakedata.py -text
 SAS/ResourceAssignment/ResourceAssignmentEditor/lib/static/app/app.js -text
 SAS/ResourceAssignment/ResourceAssignmentEditor/lib/static/app/controllers/datacontroller.js -text
+SAS/ResourceAssignment/ResourceAssignmentEditor/lib/static/app/controllers/ganttcontroller.js -text
 SAS/ResourceAssignment/ResourceAssignmentEditor/lib/static/app/controllers/gridcontroller.js -text
 SAS/ResourceAssignment/ResourceAssignmentEditor/lib/static/css/bootstrap.min.css -text
 SAS/ResourceAssignment/ResourceAssignmentEditor/lib/static/css/main.css -text
diff --git a/SAS/ResourceAssignment/ResourceAssignmentEditor/lib/fakedata.py b/SAS/ResourceAssignment/ResourceAssignmentEditor/lib/fakedata.py
index 0ec3dfa2fdaad1239e42707d202a23ace2cb82f9..b7aa095810db0cca6408d4f424ec5cac53da4580 100644
--- a/SAS/ResourceAssignment/ResourceAssignmentEditor/lib/fakedata.py
+++ b/SAS/ResourceAssignment/ResourceAssignmentEditor/lib/fakedata.py
@@ -22,13 +22,13 @@
 from datetime import datetime
 from datetime import timedelta
 
-numProjects = 3
+numProjects = 5
 numObsPerProject = 2
-numPipelinesPerObs = 2
+numPipelinesPerObs = 3
 numCoreStations = 20
-numRemoteStations = 10
+numRemoteStations = 15
 numCobaltNodes = 8
-numComputeNodes = 40
+numComputeNodes = 50
 numIngestNodes = 4
 
 _taskIdCntr = 0
@@ -65,9 +65,9 @@ resourceGroups = []
 coreStationsGroup = {'id': 0, 'name': 'Core Stations', 'childGroupIds': [], 'resourceIds': []}
 remoteStationsGroup = {'id': 1, 'name': 'Remote Stations', 'childGroupIds': [], 'resourceIds': []}
 stationsGroup = {'id': 2, 'name': 'Stations', 'childGroupIds': [coreStationsGroup['id'], remoteStationsGroup['id']], 'resourceIds': []}
-cobaltGroup = {'id': 3, 'name': 'CEP4 Nodes', 'childGroupIds': [], 'resourceIds': []}
+cobaltGroup = {'id': 3, 'name': 'Cobalt', 'childGroupIds': [], 'resourceIds': []}
 cep4NodeGroup = {'id': 4, 'name': 'CEP4 Nodes', 'childGroupIds': [], 'resourceIds': []}
-cep4StorageGroup = {'id': 5, 'name': 'CEP4 Storage', 'childGroupIds': [], 'resourceIds': []}
+cep4StorageGroup = {'id': 5, 'name': 'Storage', 'childGroupIds': [], 'resourceIds': []}
 ingestGroup = {'id': 6, 'name': 'Ingest Nodes', 'childGroupIds': [], 'resourceIds': []}
 resourceGroups.append(coreStationsGroup)
 resourceGroups.append(remoteStationsGroup)
@@ -116,7 +116,9 @@ computenodes = [r for r in resourceItems if r['typeId'] == 2]
 ingestnodes = [r for r in resourceItems if r['typeId'] == 3]
 
 resourceClaims = []
+resourceGroupClaims = []
 for task in allTasks:
+    taskResourceGroupIds = set()
     taskResources = []
     if task['type'] == 'Observation':
         taskResources = stations + correlators
@@ -129,5 +131,12 @@ for task in allTasks:
         claim = {'id': len(resourceClaims), 'resourceId': resource['id'], 'taskId': task['id'], 'startTime': task['from'], 'endTime': task['to'], 'status': 'allocated'}
         resourceClaims.append(claim)
 
-    claim = {'id': len(resourceClaims), 'resourceId': cep4storage['id'], 'taskId': task['id'], 'startTime': task['from'], 'endTime': task['from'] + timedelta(days=3), 'status': 'allocated'}
+        groupIds = [rg['id'] for rg in resourceGroups if resource['id'] in rg['resourceIds']]
+        taskResourceGroupIds |= set(groupIds)
+
+    claim = {'id': len(resourceClaims), 'resourceId': cep4storage['id'], 'taskId': task['id'], 'startTime': task['from'], 'endTime': task['from'] + timedelta(days=1), 'status': 'allocated'}
     resourceClaims.append(claim)
+
+    for groupId in taskResourceGroupIds:
+        groupClaim = {'id': len(resourceGroupClaims), 'resourceGroupId': groupId, 'taskId': task['id'], 'startTime': task['from'], 'endTime': task['to'], 'status': 'allocated'}
+        resourceGroupClaims.append(groupClaim)
diff --git a/SAS/ResourceAssignment/ResourceAssignmentEditor/lib/static/app/app.js b/SAS/ResourceAssignment/ResourceAssignmentEditor/lib/static/app/app.js
index fb97d3c4cb367a41fd85708ad2e79fb68609db4e..20f4de822efc51a3ad6b3d457a72ef27bdaa1f26 100644
--- a/SAS/ResourceAssignment/ResourceAssignmentEditor/lib/static/app/app.js
+++ b/SAS/ResourceAssignment/ResourceAssignmentEditor/lib/static/app/app.js
@@ -1,11 +1,7 @@
 // $Id$
 
 var app = angular.module('raeApp',
-                         ['ngTouch',
-                         'gantt',
-                         'gantt.table',
-                         'gantt.movable',
-                         'gantt.tooltips',
-                         'DataControllerMod',
+                         ['DataControllerMod',
+                         'GanttControllerMod',
                          'GridControllerMod']);
 
diff --git a/SAS/ResourceAssignment/ResourceAssignmentEditor/lib/static/app/controllers/datacontroller.js b/SAS/ResourceAssignment/ResourceAssignmentEditor/lib/static/app/controllers/datacontroller.js
index af369285de7b5e1ab239a4fdc41dea2a9462f10b..63247e47743da243e6acbe75edd77a9f31260154 100644
--- a/SAS/ResourceAssignment/ResourceAssignmentEditor/lib/static/app/controllers/datacontroller.js
+++ b/SAS/ResourceAssignment/ResourceAssignmentEditor/lib/static/app/controllers/datacontroller.js
@@ -4,13 +4,18 @@ angular.module('raeApp').factory("dataService", function(){
     var self = this;
     self.tasks = [];
     self.resources = [];
-    self.resourceclaims = [];
+    self.resourceGroups = [];
+    self.resourceClaims = [];
+    self.resourceGroupClaims = [];
     self.tasktypes = [];
     self.taskstatustypes = [];
 
     self.taskDict = {};
     self.resourceDict = {};
-    self.resourceclaimDict = {};
+    self.resourceGroupsDict = {};
+    self.resourceClaimDict = {};
+    self.resourceGroupClaimDict = {};
+    self.resourceIdToGroupIdsDict = {};
 
     self.resourcesWithClaims = [];
 
@@ -34,6 +39,29 @@ dataControllerMod.controller('DataController',
         return dict;
     };
 
+    function mapResourcesToGroups() {
+        var dict = {}
+        var resources = self.dataService.resources;
+        var resourceGroups = self.dataService.resourceGroups;
+
+        if(resources.length > 0) {
+            for(var i = resources.length-1; i >=0; i--)
+                dict[resources[i].id] = []
+
+            for(var i = resourceGroups.length-1; i >=0; i--) {
+                var group = resourceGroups[i];
+                var childResourceIds = group.resourceIds;
+
+                for(var j = childResourceIds.length-1; j >=0; j--) {
+                    var childResourceId = childResourceIds[j];
+                    dict[childResourceId].push(group.id);
+                }
+            }
+        }
+
+        self.dataService.resourceIdToGroupIdsDict = dict;
+    };
+
     function getTasks() {
         $http.get('/rest/tasks').success(function(result) {
             self.dataService.tasks = result.tasks;
@@ -45,17 +73,29 @@ dataControllerMod.controller('DataController',
         $http.get('/rest/resourceitems').success(function(result) {
             self.dataService.resources = result.resourceitems;
             self.dataService.resourceDict = toIdBasedDict(self.dataService.resources);
-
-            setTimeout(groupResourceClaims(), 10);
+            mapResourcesToGroups();
         });
     };
 
     function getResourceClaims() {
         $http.get('/rest/resourceclaims').success(function(result) {
-            self.dataService.resourceclaims = result.resourceclaims;
-            self.dataService.resourceclaimDict = toIdBasedDict(self.dataService.resourceclaims);
+            self.dataService.resourceClaims = result.resourceclaims;
+            self.dataService.resourceClaimDict = toIdBasedDict(self.dataService.resourceClaims);
+        });
+    };
 
-            setTimeout(groupResourceClaims(), 10);
+    function getResourceGroups() {
+        $http.get('/rest/resourcegroups').success(function(result) {
+            self.dataService.resourceGroups = result.resourcegroups;
+            self.dataService.resourceGroupsDict = toIdBasedDict(self.dataService.resourceGroups);
+            mapResourcesToGroups();
+        });
+    };
+
+    function getResourceGroupClaims() {
+        $http.get('/rest/resourcegroupclaims').success(function(result) {
+            self.dataService.resourceGroupClaims = result.resourcegroupclaims;
+            self.dataService.resourceGroupClaimDict = toIdBasedDict(self.dataService.resourceGroupClaims);
         });
     };
 
@@ -71,46 +111,11 @@ dataControllerMod.controller('DataController',
         });
     };
 
-    function groupResourceClaims() {
-        var grouped = {};
-        var resources = self.dataService.resources;
-
-        for(var i = resources.length-1; i >=0; i--)
-        {
-            var resource = resources[i];
-            grouped[resource.id] = {
-                'id': resource.id,
-                'name': resource.name,
-                'tasks': []
-            };
-        }
-
-        setTimeout(function() {
-            var resourceclaims = self.dataService.resourceclaims;
-            for(var i = resourceclaims.length-1; i >=0; i--)
-            {
-                var claim = resourceclaims[i];
-                var task = self.dataService.taskDict[claim.taskId];
-
-                var row = grouped[claim.resourceId];
-                row.tasks.push({
-                     name: task ? task.name : '<unknown>',
-                    'from': claim.startTime,
-                    'to': claim.endTime
-                });
-            }
-            var groupedArray = [];
-
-            for (var groupId in grouped)
-                groupedArray.push(grouped[groupId]);
-
-            self.dataService.resourcesWithClaims = groupedArray;
-        }, 10);
-    };
-
     getTasks();
     getTaskTypes();
     getTaskStatusTypes();
+    getResourceGroups();
+    getResourceGroupClaims();
     getResources();
     getResourceClaims();
 }
diff --git a/SAS/ResourceAssignment/ResourceAssignmentEditor/lib/static/app/controllers/ganttcontroller.js b/SAS/ResourceAssignment/ResourceAssignmentEditor/lib/static/app/controllers/ganttcontroller.js
new file mode 100644
index 0000000000000000000000000000000000000000..3e8f84409b1bca8bc89b04d1f29a2a711448d128
--- /dev/null
+++ b/SAS/ResourceAssignment/ResourceAssignmentEditor/lib/static/app/controllers/ganttcontroller.js
@@ -0,0 +1,182 @@
+// $Id: ganttcontroller.js 32761 2015-11-02 11:50:21Z schaap $
+
+var ganttControllerMod = angular.module('GanttControllerMod', [
+                                        'gantt',
+                                        'gantt.sortable',
+                                        'gantt.movable',
+                                        'gantt.drawtask',
+                                        'gantt.tooltips',
+                                        'gantt.bounds',
+                                        'gantt.progress',
+                                        'gantt.table',
+                                        'gantt.tree',
+                                        'gantt.groups',
+                                        'gantt.overlap',
+                                        'gantt.resizeSensor']).config(['$compileProvider', function($compileProvider) {
+    $compileProvider.debugInfoEnabled(false); // Remove debug info (angularJS >= 1.3)
+}]);
+
+ganttControllerMod.controller('GanttController', ['$scope', 'dataService', function($scope, dataService) {
+
+    $scope.dataService = dataService;
+    $scope.ganttData = []
+
+    $scope.options = {
+        mode: 'custom',
+        scale: 'day',
+        sideMode: 'Tree',
+        columns: ['model.name', 'from', 'to'],
+        treeTableColumns: ['from', 'to'],
+        columnsHeaders: {'model.name' : 'Name', 'from': 'From', 'to': 'To'},
+        columnsClasses: {'model.name' : 'gantt-column-name', 'from': 'gantt-column-from', 'to': 'gantt-column-to'},
+        columnsFormatters: {
+            'from': function(from) {
+                return from !== undefined ? from.format('lll') : undefined;
+            },
+            'to': function(to) {
+                return to !== undefined ? to.format('lll') : undefined;
+            }
+        },
+        treeHeaderContent: '<i class="fa fa-align-justify"></i> {{getHeader()}}',
+                              columnsHeaderContents: {
+                                  'model.name': '<i class="fa fa-align-justify"></i> {{getHeader()}}',
+                              'from': '<i class="fa fa-calendar"></i> {{getHeader()}}',
+                              'to': '<i class="fa fa-calendar"></i> {{getHeader()}}'
+                              },
+        autoExpand: 'both',
+        api: function(api) {
+            // API Object is used to control methods and events from angular-gantt.
+            $scope.api = api;
+        }
+    };
+
+    function updateGanttData() {
+        var ganntRowsDict = {};
+
+        var resourceGroups = $scope.dataService.resourceGroups;
+        var numResourceGroups = resourceGroups.length;
+
+        var resourceIdToGroupIdsDict = $scope.dataService.resourceIdToGroupIdsDict;
+        var resources = $scope.dataService.resources;
+        var numResources = resources.length;
+
+        var resourceGroupsDict = $scope.dataService.resourceGroupsDict;
+        var taskDict = $scope.dataService.taskDict;
+
+        var resourceGroupClaims = $scope.dataService.resourceGroupClaims;
+        var numResourceGroupClaims = resourceGroupClaims.length;
+
+        var resourceClaims = $scope.dataService.resourceClaims;
+        var numResourceClaims = resourceClaims.length;
+
+        var resourceDict = $scope.dataService.resourceDict;
+
+        //create rows in gantt for resourceGroups
+        for(var i = 0; i < numResourceGroups; i++)
+        {
+            var resourceGroup = resourceGroups[i];
+            var groupRowId = 'group_' + resourceGroup.id;
+            ganntRowsDict[groupRowId] = {
+                'id': groupRowId,
+                'name': resourceGroup.name,
+                'tasks': []
+            };
+        }
+
+        //create rows in gantt for resources
+        //add each resource row to all group rows of which group it is a member
+        for(var i = 0; i < numResources; i++)
+        {
+            var resource = resources[i];
+            var groupIds = resourceIdToGroupIdsDict[resource.id];
+            var numGroups = groupIds.length;
+
+            if(numGroups > 0) {
+                for(var j = 0; j < numGroups; j++) {
+                    var parentRowId = 'group_' + groupIds[j];
+                    var resourceRowId = 'group_' + groupIds[j] + '_resource_' + resource.id;
+                    //make resource row child of group row
+                    ganntRowsDict[resourceRowId] = {
+                        'id': resourceRowId,
+                        'parent': parentRowId,
+                        'name': resource.name,
+                        'tasks': []
+                    };
+                }
+            }
+            else
+            {
+                //no parent groups, so one individual row
+                var resourceRowId = 'resource_' + resource.id;
+                ganntRowsDict[resourceRowId] = {
+                    'id': resourceRowId,
+                    'name': resource.name,
+                    'tasks': []
+                };
+            }
+        }
+
+        //now that we have all rows for the gantt...
+        //assign each groupclaim to its resourcegroup
+        for(var i = 0; i < numResourceGroupClaims; i++) {
+            var groupClaim = resourceGroupClaims[i];
+            var task = taskDict[groupClaim.taskId];
+
+            var groupClaimTask = {
+                name: task ? task.name : '<unknown>',
+                'from': groupClaim.startTime,
+                'to': groupClaim.endTime
+            };
+
+            var groupRowId = 'group_' + groupClaim.resourceGroupId;
+            var ganntGroupRow = ganntRowsDict[groupRowId];
+            if(ganntGroupRow)
+                ganntGroupRow.tasks.push(groupClaimTask);
+        }
+
+        //and assign each resourceclaim to its resource in each group
+        for(var i = 0; i < numResourceClaims; i++) {
+            var claim = resourceClaims[i];
+            var task = taskDict[claim.taskId];
+
+            var groupIds = resourceIdToGroupIdsDict[claim.resourceId];
+            var numGroups = groupIds.length;
+
+            var claimTask = {
+                name: task ? task.name : '<unknown>',
+                'from': claim.startTime,
+                'to': claim.endTime
+            };
+
+            if(numGroups > 0) {
+                for(var j = 0; j < numGroups; j++) {
+                    var resourceRowId = 'group_' + groupIds[j] + '_resource_' + claim.resourceId;
+                    var ganntRow = ganntRowsDict[resourceRowId];
+                    if(ganntRow)
+                        ganntRow.tasks.push(claimTask);
+                }
+            }
+            else {
+                var resourceRowId = 'resource_' + claim.resourceId;
+                var ganntRow = ganntRowsDict[resourceRowId];
+                if(ganntRow)
+                    ganntRow.tasks.push(claimTask);
+            }
+        }
+
+        var ganntRows = [];
+
+        for (var groupId in ganntRowsDict)
+            ganntRows.push(ganntRowsDict[groupId]);
+
+        $scope.ganttData = ganntRows;
+        setTimeout($scope.api.tree.collapseAll(), 10)
+    };
+
+    $scope.$watch('dataService.tasks', updateGanttData);
+    $scope.$watch('dataService.resources', updateGanttData);
+    $scope.$watch('dataService.resourceclaims', updateGanttData);
+    $scope.$watch('dataService.resourceGroups', updateGanttData);
+    $scope.$watch('dataService.resourceGroupClaims', updateGanttData);
+}
+]);
diff --git a/SAS/ResourceAssignment/ResourceAssignmentEditor/lib/templates/index.html b/SAS/ResourceAssignment/ResourceAssignmentEditor/lib/templates/index.html
index 8cc3c4c4177610da3a259deeea20fc62ed77bf0a..8e4ddb2541ae0d421626c8de6995e0674ab810b9 100644
--- a/SAS/ResourceAssignment/ResourceAssignmentEditor/lib/templates/index.html
+++ b/SAS/ResourceAssignment/ResourceAssignmentEditor/lib/templates/index.html
@@ -5,14 +5,15 @@
     <meta http-equiv='Content-Type' content='text/html; charset=utf-8'/>
     <title>{{title}}</title>
     <link rel='shortcut icon' href='{{ url_for('static', filename='favicon.ico') }}'>
-    <link href="/static/css/main.css" rel="stylesheet" type="text/css">
     <link href="/static/css/bootstrap.min.css" rel="stylesheet" type="text/css">
+    <link href="/static/css/main.css" rel="stylesheet" type="text/css">
     <link href="/static/js/angular-ui-grid/ui-grid.min.css" rel="stylesheet" type="text/css">
     <script src="/static/js/angular/angular.js"></script>
     <script src="/static/js/angular-route/angular-route.min.js"></script>
     <script src="/static/js/angular-touch/angular-touch.js"></script>
     <script src="/static/js/angular-resource/angular-resource.min.js"></script>
     <script src="/static/js/angular-ui-grid/ui-grid.js"></script>
+    <script src="/static/js/angular-ui-tree/angular-ui-tree.js"></script>
     <script src="/static/js/moment/moment.js"></script>
     <script src="/static/js/angular-moment/angular-moment.js"></script>
     <link href="/static/js/angular-gantt/angular-gantt.min.css" rel="stylesheet" type="text/css">
@@ -22,21 +23,27 @@
     <script src="/static/app/app.js"></script>
     <script src="/static/app/controllers/datacontroller.js"></script>
     <script src="/static/app/controllers/gridcontroller.js"></script>
+    <script src="/static/app/controllers/ganttcontroller.js"></script>
     </head>
     <body>
     {% raw %}
-    <div ng-controller="GridController as gridCtrl">
-        <strong>Tasks:</strong>
-        <div id="grid1" ui-grid="gridOptions" ui-grid-move-columns class="myGrid"></div>
-    </div>
-    <br/>
-    <br/>
-    <br/>
     <div ng-controller="DataController as dataCtrl">
-        <div gantt "{ data= dataCtrl.dataService.resourcesWithClaims }" >
-            <gantt-table></gantt-table>
-            <gantt-movable></gantt-movable>
-            <gantt-tooltips></gantt-tooltips>
+        <div ng-controller="GridController as gridCtrl">
+            <strong>Tasks:</strong>
+            <div id="grid1" ui-grid="gridOptions" ui-grid-move-columns class="myGrid"></div>
+        </div>
+        <br/>
+        <br/>
+        <br/>
+        <div ng-controller="GanttController as ganttCtrl">
+            <div gantt data=ganttData
+                 api=options.api
+                 show-side='true'>
+                <gantt-tree enabled="true"></gantt-tree>
+<!--                 <gantt-table></gantt-table> -->
+                <gantt-movable></gantt-movable>
+                <gantt-tooltips></gantt-tooltips>
+            </div>
         </div>
     </div>
     {% endraw %}
diff --git a/SAS/ResourceAssignment/ResourceAssignmentEditor/lib/webservice.py b/SAS/ResourceAssignment/ResourceAssignmentEditor/lib/webservice.py
index 16b297a9a8a47f252b56a7657882466bfa9e55fc..7f4be997c823f5b5548a2c60275ed8138ac17749 100755
--- a/SAS/ResourceAssignment/ResourceAssignmentEditor/lib/webservice.py
+++ b/SAS/ResourceAssignment/ResourceAssignmentEditor/lib/webservice.py
@@ -73,6 +73,12 @@ def resourcegroups():
 @gzipped
 def resourceclaims():
     data = {'resourceclaims': resourceClaims}
+    return jsonify(data)
+
+@app.route('/rest/resourcegroupclaims')
+@gzipped
+def resourcegroupclaims():
+    data = {'resourcegroupclaims': resourceGroupClaims}
 
     return jsonify(data)