});
var end = new Date().getTime();
- console.log("APPLY FILTERS took", end - start, "ms");
+ console.log("APPLY FILTERS [", filters, "] took", end - start, "ms");
}
};
});
+// http://stackoverflow.com/questions/19992090/angularjs-group-by-directive
+ManifoldApp.filter('groupBy', ['$parse', function ($parse) {
+ return function (list, group_by) {
+
+ var filtered = [];
+ var prev_item = null;
+ var group_changed = false;
+ // this is a new field which is added to each item where we append "_CHANGED"
+ // to indicate a field change in the list
+ //was var new_field = group_by + '_CHANGED'; - JB 12/17/2013
+ var new_field = 'group_by_CHANGED';
+
+ // loop through each item in the list
+ angular.forEach(list, function (item) {
+
+ group_changed = false;
+
+ // if not the first item
+ if (prev_item !== null) {
+
+ // check if any of the group by field changed
+
+ //force group_by into Array
+ group_by = angular.isArray(group_by) ? group_by : [group_by];
+
+ //check each group by parameter
+ for (var i = 0, len = group_by.length; i < len; i++) {
+ if ($parse(group_by[i])(prev_item) !== $parse(group_by[i])(item)) {
+ group_changed = true;
+ }
+ }
+
+
+ }// otherwise we have the first item in the list which is new
+ else {
+ group_changed = true;
+ }
+
+ // if the group changed, then add a new field to the item
+ // to indicate this
+ if (group_changed) {
+ item[new_field] = true;
+ } else {
+ item[new_field] = false;
+ }
+
+ filtered.push(item);
+ prev_item = item;
+
+ });
+
+ return filtered;
+ };
+}]);
+
+// https://github.com/angular-ui/angular-ui-OLDREPO/blob/master/modules/filters/unique/unique.js
+/**
+ * Filters out all duplicate items from an array by checking the specified key
+ * @param [key] {string} the name of the attribute of each object to compare for uniqueness
+ if the key is empty, the entire object will be compared
+ if the key === false then no filtering will be performed
+ * @return {array}
+ */
+ManifoldApp.filter('unique', function () {
+
+ return function (items, filterOn) {
+
+ if (filterOn === false) {
+ return items;
+ }
+
+ if ((filterOn || angular.isUndefined(filterOn)) && angular.isArray(items)) {
+ var hashCheck = {}, newItems = [];
+
+ var extractValueToCompare = function (item) {
+ if (angular.isObject(item) && angular.isString(filterOn)) {
+ return item[filterOn];
+ } else {
+ return item;
+ }
+ };
+
+ angular.forEach(items, function (item) {
+ var valueToCheck, isDuplicate = false;
+
+ for (var i = 0; i < newItems.length; i++) {
+ if (angular.equals(extractValueToCompare(newItems[i]), extractValueToCompare(item))) {
+ isDuplicate = true;
+ break;
+ }
+ }
+ if (!isDuplicate) {
+ newItems.push(item);
+ }
+
+ });
+ items = newItems;
+ }
+ return items;
+ };
+});
+
// INHERITANCE
// http://alexsexton.com/blog/2010/02/using-inheritance-patterns-to-organize-large-jquery-applications/
// We will use John Resig's proposal
class TestbedsPlugin(Plugin):
- def __init__ (self, query=None, query_networks=None, **settings):
+ def __init__ (self, query=None, **settings):
Plugin.__init__ (self, **settings)
# Until we have a proper way to access queries in Python
self.query = query
- self.query_networks = query_networks
- self.query_networks_uuid = query_networks.query_uuid if query_networks else None
def template_file (self):
return "testbeds.html"
# query_uuid will pass self.query results to the javascript
# and will be available as "record" in :
# on_new_record: function(record)
- return ['plugin_uuid', 'domid', 'query_uuid', 'query_networks_uuid']
+ return ['plugin_uuid', 'domid', 'query_uuid']
def export_json_settings (self):
return True
/* Plugin instance */
$scope.instance = null;
+ $scope.facility_names = Array();
+ $scope.testbed_names = new Object();
+
/* Models */
- $scope.testbeds = Array();
+ //$scope.testbeds = Array();
+ $scope._facility_active = new Object();
+ $scope._testbed_active = new Object();
+
+ $scope.is_facility_active = function(facility)
+ {
+ return (($scope._facility_active[facility] === undefined) || $scope._facility_active[facility]);
+ };
+
+ $scope.is_testbed_active = function(facility, testbed)
+ {
+ return (($scope._testbed_active[facility] === undefined) ||
+ ($scope._testbed_active[facility][testbed] === undefined) ||
+ ($scope._testbed_active[facility][testbed]));
+ };
+ $scope.set_facility_active = function(facility, value)
+ {
+ $scope._facility_active[facility] = value;
+ };
+
+ $scope.set_testbed_active = function(facility, testbed, value)
+ {
+ if ($scope._testbed_active[facility] === undefined)
+ $scope._testbed_active[facility] = new Object();
+ $scope._testbed_active[facility][testbed] = value;
+ };
+
/* Click event */
- $scope.select = function(testbed)
+
+ $scope.select_facility = function(facility)
{
var selected, prev_selected, num, num_selected, num_prev_selected, filter;
- prev_selected = $.map($scope.testbeds, function(x, i) {
- return x.active ? x.network_hrn : null;
+ prev_selected = $.map($scope.facility_names, function(x, i) {
+ return $scope.is_facility_active(x) ? x : null;
});
- testbed.active = !testbed.active;
+ $scope.set_facility_active(facility, ! $scope.is_facility_active(facility));
- selected = $.map($scope.testbeds, function(x, i) {
- return x.active ? x.network_hrn : null;
+ selected = $.map($scope.facility_names, function(x, i) {
+ return $scope.is_facility_active(x) ? x : null;
});
- num = $scope.testbeds.length;
+ num = $scope.facility_names.length;
prev_num_selected = prev_selected.length;
num_selected = selected.length;
-
if ((prev_num_selected != 0) && (prev_num_selected != num)) {
// Remove previous filter
- filter = ['network_hrn', 'included', prev_selected];
+ filter = ['facility_name', 'included', prev_selected];
manifold.raise_event($scope.instance.options.query_uuid, FILTER_REMOVED, filter);
}
if (num_selected != num) {
- filter = ['network_hrn', 'included', selected];
+ filter = ['facility_name', 'included', selected];
+ manifold.raise_event($scope.instance.options.query_uuid, FILTER_ADDED, filter);
+ }
+ };
+
+ $scope.select_testbed = function(facility, testbed)
+ {
+ var selected, prev_selected, num, num_selected, num_prev_selected, filter;
+
+ prev_selected = Array();
+ $.each($scope.facility_names, function(i, facility_name) {
+ $.each($scope.testbed_names[facility_name], function(j, testbed_name) {
+ if ($scope.is_testbed_active(facility_name, testbed_name)) {
+ // XXX We should have a joint facility/testbed filter
+ prev_selected.push(testbed_name);
+ }
+ });
+
+ });
+
+ $scope.set_testbed_active(facility, testbed, ! $scope.is_testbed_active(facility, testbed));
+
+ selected = Array();
+ $.each($scope.facility_names, function(i, facility_name) {
+ $.each($scope.testbed_names[facility_name], function(j, testbed_name) {
+ if ($scope.is_testbed_active(facility_name, testbed_name)) {
+ // XXX We should have a joint facility/testbed filter
+ selected.push(testbed_name);
+ }
+ });
+
+ });
+
+ num = 0;
+ $.each($scope.facility_names, function(i, facility_name) {
+ num += $scope.testbed_names[facility_name].length;
+ });
+ prev_num_selected = prev_selected.length;
+ num_selected = selected.length;
+
+ if ((prev_num_selected != 0) && (prev_num_selected != num)) {
+ // Remove previous filter
+ // XXX We should have a joint facility/testbed filter
+ filter = ['testbed_name', 'included', prev_selected];
+ manifold.raise_event($scope.instance.options.query_uuid, FILTER_REMOVED, filter);
+ }
+
+ if (num_selected != num) {
+ // XXX We should have a joint facility/testbed filter
+ filter = ['testbed_name', 'included', selected];
manifold.raise_event($scope.instance.options.query_uuid, FILTER_ADDED, filter);
}
};
this._super(options, element);
/* Member variables */
- this.filters = Array();
this.testbeds = Array();
this._get_scope().instance = this;
/* HANDLERS */
/* When a filter is added/removed, update the list of filters local to the plugin */
+ /*
on_filter_added: function(filter)
{
this.filters.push(filter);
}
}
},
-
+ */
// ... be sure to list all events here
- on_networks_query_done: function()
+ on_query_done: function()
{
- this.set_networks();
- },
+ var scope, query_ext, resources;
+ scope = this._get_scope();
+ query_ext = manifold.query_store.find_analyzed_query_ext(this.options.query_uuid);
+ resources = query_ext.records.values();
+
+ $.each(resources, function(i, resource) {
+ if ($.inArray(resource.facility_name, scope.facility_names) == -1)
+ scope.facility_names.push(resource.facility_name);
+ if (scope.testbed_names[resource.facility_name] === undefined)
+ scope.testbed_names[resource.facility_name] = Array();
+ if ($.inArray(resource.testbed_name, scope.testbed_names[resource.facility_name]) == -1)
+ scope.testbed_names[resource.facility_name].push(resource.testbed_name);
+ });
- /* INTERNAL FUNCTIONS */
+ scope.$apply();
+ },
- set_networks: function()
+ /*
+ on_networks_query_done: function()
{
var scope = this._get_scope();
var query_ext = manifold.query_store.find_analyzed_query_ext(this.options.query_networks_uuid);
$.each(scope.testbeds, function(i, testbed) { testbed.active = true });
scope.$apply();
},
+*/
+
+ /* INTERNAL FUNCTIONS */
_get_scope : function()
{
<div id={{ domid }} ng-controller="TestbedsCtrl">
-<div class="list-group-item sl-platform"><span class="list-group-item-heading">Testbeds</span></div>
+<div class="list-group-item sl-platform"><span class="list-group-item-heading">Facilities</span></div>
-<div ng-repeat="testbed in testbeds"
- ng-click="select(testbed)">
+<div ng-repeat="facility_name in facility_names">
<a href="#"
class="list-group-item sl-platform"
- ng-class="{active: testbed.active}"
- id="testbeds-filter_{[{ testbed.network_hrn }]}"
- data-platform="{[{ testbed.network_hrn }]}">
- <span class="list-group-item-heading">{[{ testbed.platform }]}</span>
- <!--<p class="list-group-item-heading">{[{ testbed.network_hrn }]}</p>-->
+ ng-class="{active: is_facility_active(facility_name)}"
+ id="facility-filter_{[{ facility_name }]}"
+ ng-click="select_facility(facility_name)"
+ data-platform="{[{ facility_name }]}">
+ <span class="list-group-item-heading">{[{ facility_name }]}</span>
</a>
+ <div ng-repeat="testbed_name in testbed_names[facility_name]">
+ <a href="#"
+ class="list-group-item sl-platform"
+ ng-class="{active: is_testbed_active(facility_name, testbed_name)}"
+ id="testbeds-filter_{[{ testbed_name }]}"
+ ng-click="select_testbed(facility_name, testbed_name)"
+ data-platform="{[{ testbed_name }]}">
+ <span class="list-group-item-heading"> {[{testbed_name}]}</span>
+ </a>
+ </div>
</div>
+<!--
<style>
a.sl-platform {
text-transform: uppercase;
}
</style>
-
+-->
</div>
# Example: select slice_hrn, resource.urn, lease.resource, lease.start_time, lease.end_time from slice where slice_hrn == "ple.upmc.myslicedemo"
main_query = Query.get('slice').filter_by('slice_hrn', '=', slicename)
main_query.select(
- 'slice_urn', # XXX We need the key otherwise the storage of records bugs !
+ # SLICE
'slice_hrn',
+ # - The record key is needed otherwise the storage of records
+ # bugs !
+ 'slice_urn',
+ # RESOURCES
'resource.urn',
'resource.hostname', 'resource.type',
'resource.network_hrn',
+ # - The facility_name and testbed_name are required for the
+ # testbeds plugin to properly work.
+ 'resource.facility_name',
+ 'resource.testbed_name',
+ # LEASES
'lease.resource',
'lease.start_time',
'lease.end_time',
- 'lease.lease_id', # Important for NITOS identify already existing leases
+ # - The lease_id is important for NITOS identify already existing
+ # leases
+ 'lease.lease_id',
+
#'user.user_hrn',
#'application.measurement_point.counter'
)
network_md = metadata.details_by_object('network')
network_fields = [column['name'] for column in network_md['column']]
- query_networks = Query.get('network').select(network_fields)
- page.enqueue_query(query_networks)
+ #query_networks = Query.get('network').select(network_fields)
+ #page.enqueue_query(query_networks)
filter_testbeds = TestbedsPlugin(
page = page,
domid = 'testbeds-filter',
title = 'Filter by testbeds',
query = sq_resource,
- query_networks = query_networks,
- init_key = "network_hrn",
- checkboxes = True,
- datatables_options = {
- 'iDisplayLength': 25,
- 'bLengthChange' : True,
- 'bAutoWidth' : True,
- },
+ #query_networks = query_networks,
+ #init_key = "network_hrn",
+ #checkboxes = True,
+ #datatables_options = {
+ # 'iDisplayLength': 25,
+ # 'bLengthChange' : True,
+ # 'bAutoWidth' : True,
+ # },
)
filter_status = FilterStatusPlugin(