Skip to content

Commit

Permalink
Tasklist for resources
Browse files Browse the repository at this point in the history
  • Loading branch information
iNecas committed Jan 15, 2014
1 parent 7164fc8 commit 1161aed
Show file tree
Hide file tree
Showing 9 changed files with 235 additions and 83 deletions.
23 changes: 17 additions & 6 deletions app/controllers/api/v2/dyntasks_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ def rules
param :resource_type, String, :desc => <<-DESC
In case :type = 'resource', what resource id we're searching the tasks for
DESC
param :active_only, :bool
param :page, String
param :per_page, String
end
Expand All @@ -59,11 +60,12 @@ def search
private

def condition_tasks(condition)
DynflowTask.tap do |scope|
scope = ordering_scope(scope, condition)
scope = search_scope(scope, condition)
scope = pagination_scope(scope, condition)
end.all.map { |task| task_hash(task) }
scope = DynflowTask
scope = ordering_scope(scope, condition)
scope = search_scope(scope, condition)
scope = active_scope(scope, condition)
scope = pagination_scope(scope, condition)
scope.all.map { |task| task_hash(task) }
end

def search_scope(scope, condition)
Expand All @@ -77,14 +79,22 @@ def search_scope(scope, condition)
if condition[:resource_type].blank? || condition[:resource_id].blank?
raise HttpErrors::BadRequest, _("User condition requires resource_type and resource_id to be specified")
end
scope.joins(:dynflow_locks).where(dynflows_locks:
scope.joins(:dynflow_locks).where(dynflow_locks:
{ resource_type: condition[:resource_type],
resource_id: condition[:resource_id] })
else
raise HttpErrors::BadRequest, _("Condition %s not supported") % condition[:type]
end
end

def active_scope(scope, condition)
if condition[:active_only]
scope.active
else
scope
end
end

def pagination_scope(scope, condition)
page = condition[:page] || 1
per_page = condition[:per_page] || 10
Expand All @@ -105,6 +115,7 @@ def task_hash(task)
task_hash[:result] = task.execution_plan.result
task_hash[:progress] = task.execution_plan.progress
@tasks[task.uuid] = task_hash
return task_hash
end

end
4 changes: 2 additions & 2 deletions app/models/dynflow_lock.rb
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,12 @@ class DynflowLock < ActiveRecord::Base
belongs_to :resource, polymorphic: true

scope :active, -> do
includes(:dynflow_execution_plan)
joins(:dynflow_execution_plan)
.where('dynflow_execution_plans.state != ?', :stopped)
end

scope :inactive, -> do
includes(:dynflow_execution_plan)
joins(:dynflow_execution_plan)
.where('dynflow_execution_plans.state = ?', :stopped)
end

Expand Down
10 changes: 10 additions & 0 deletions app/models/dynflow_task.rb
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,16 @@ class DynflowTask < ActiveRecord::Base
foreign_key: :uuid
has_many :dynflow_locks, foreign_key: :uuid

scope :active, -> do
joins(:dynflow_execution_plan)
.where('dynflow_execution_plans.state != ?', :stopped)
end

scope :inactive, -> do
joins(:dynflow_execution_plan)
.where('dynflow_execution_plans.state = ?', :stopped)
end

def execution_plan
Orchestrate.world.persistence.load_execution_plan(self.uuid)
end
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@


<div class="details fl">
<taskprogress uuid="{{ repository.current_task }}"></taskprogress>
<tasklist taskActive="true" taskResourceType="Repository" taskResourceId="{{ repository.id }}" ></tasklist>

<section>

Expand Down Expand Up @@ -112,6 +112,8 @@ <h4 translate>Sync Status</h4>

<div class="details fl">

<tasklist taskUserId="1" ></tasklist>

<section>
<h4 translate>Content Counts</h4>

Expand Down
185 changes: 185 additions & 0 deletions engines/bastion/app/assets/bastion/widgets/task-list.directive.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,185 @@
/**
Copyright 2013 Red Hat, Inc.
This software is licensed to you under the GNU General Public
License as published by the Free Software Foundation; either version
2 of the License (GPLv2) or (at your option) any later version.
There is NO WARRANTY for this software, express or implied,
including the implied warranties of MERCHANTABILITY,
NON-INFRINGEMENT, or FITNESS FOR A PARTICULAR PURPOSE. You should
have received a copy of GPLv2 along with this software; if not, see
http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
**/
angular.module('Bastion.widgets')
.factory('taskListProvider', ['$timeout', '$resource', function($timeout, $resource) {
var conditions = [], condToScopes = {}, scopeToCond = {},
timoutId,
taskListResource = $resource('/katello/api/dyntasks',
{},
{query: {method:'POST', isArray: true}});

function updateProgress() {
if(conditions.length == 0) {
return;
}
taskListResource.query({conditions: conditions}, function(conditionsTasks) {
angular.forEach(conditionsTasks, function(conditionTasks) {
var scopes = condToScopes[JSON.stringify(conditionTasks.condition)];
angular.forEach(scopes, function(scope) {
scope.updateTasks(conditionTasks.tasks);
});
});
});
}
function scheduleUpdate() {
// save the timeoutId for canceling
timeoutId = $timeout(function() {
updateProgress();
scheduleUpdate(); // schedule the next update
}, 1500);
}
scheduleUpdate();

function addScope(scope, searchOptions, condition) {
if(searchOptions.activeOnly) {
condition['active_only'] = true;
}
if(!condToScopes[JSON.stringify(condition)]) {
conditions.push(condition);
condToScopes[JSON.stringify(condition)] = [];
}
condToScopes[JSON.stringify(condition)].push(scope);
scopeToCond[scope.$id] = condition;
};

function deleteScope(scope) {
condition = scopeToCond[scope.$id];
if(!condition) {
return;
}
scopeIndex = condToScopes[JSON.stringify(condition)].indexOf(scope);
condToScopes[JSON.stringify(condition)].splice(scopeIndex, 1);
if(condToScopes[JSON.stringify(condition)].length == 0) {
condIndex = conditions.indexOf(condition);
conditions.splice(condIndex, 1);
delete condToScopes[JSON.stringify(condition)];
}
delete scopeToCond[scope.$id];
};

return {
registerUser: function(scope, searchOptions, userId) {
addScope(scope, searchOptions, { type: 'user', user_id: userId });
},
registerResource: function(scope, searchOptions, resourceType, resourceId) {
addScope(scope, searchOptions, { type: 'resource',
resource_type: resourceType,
resource_id: resourceId });
},
unregister: function(scope) { deleteScope(scope); }
};
}])
.filter('progressClasses', function () {
return function(task) {
if(!task) {
return ""
}
var classes = [];
switch(task.result) {
case "success": case "pending":
classes.push("progress-success");
break;
case "error":
classes.push("progress-error");
break;
}

switch(task.state) {
case "running": case "pending":
classes.push("active");
break;
case "stopped": case "paused": default:
classes.push("");
break;
}

return classes.join(' ');
};
})
.directive('tasklistitem', function() {
return {
restrict: 'E',
templateUrl: 'widgets/views/task-list-item.html',
link: function(scope) {
}
};
})
.directive('tasklist',
['$templateCache', '$compile', 'taskListProvider', function($templateCache, $compile, taskListProvider) {
return {
restrict: 'E',
template: '',
scope: {
taskActive: '@taskactive',
taskUserId: '@taskuserid',
taskResourceType: '@taskresourcetype',
taskResourceId: '@taskresourceid',
},
link: function (scope, element, attrs) {
scope.taskListItems = {}
function taskScope(task) {
if(scope.taskListItems[task.uuid]) {
return scope.taskListItems[task.uuid].scope();
} else {
var taskScope = scope.$new();
var taskListItem = $compile('<tasklistitem></tasklistitem>')(taskScope);
element.after(taskListItem);
scope.taskListItems[task.uuid] = taskListItem;
return taskScope;
}
}

function deleteFinishedTasks(tasks) {
var existingUuids = [], uuidsToRemove = [];
angular.forEach(tasks, function(task) {
existingUuids.push(task.uuid.toString());
});

angular.forEach(scope.taskListItems, function(el, uuid) {
if(existingUuids.indexOf(uuid.toString()) == -1) {
uuidsToRemove.push(uuid);
}
});
angular.forEach(uuidsToRemove, function(uuid) {
scope.taskListItems[uuid].remove();
delete scope.taskListItems[uuid];
});
}

function searchOptions() {
return { activeOnly: scope.taskActive == 'true' }
}

scope.updateTasks = function(tasks) {
angular.forEach(tasks, function(task) {
taskScope(task).task = task;
});
deleteFinishedTasks(tasks);
}
scope.$watch('taskUserId', function(userId) {
if(userId) {
taskListProvider.registerUser(scope, searchOptions(), userId)
}
})
scope.$watch('taskResourceId', function(resourceId) {
if(resourceId) {
taskListProvider.registerResource(scope, searchOptions(), scope.taskResourceType, resourceId);
}
})

element.bind('$destroy', function() {
taskListProvider.unregister(scope);
});
}
}
}]);

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<section>
<h4>
{{ "Orchestration Status" | i18n }}
</h4>

<div class="detail">
<span class="info-label">{{ "Task" | i18n }}</span>
<span class="info-value">{{ progressState }} Synchronization</span>
</div>
<div ng-class="task | progressClasses" class="progress progress-striped">
<progress percent="task.progress * 100"></progress>
</div>
<div class="divider"></div>
</section>
Original file line number Diff line number Diff line change
@@ -1,13 +1,12 @@
<section ng-show="uuid">
<section ng-repeat="task in tasks">
<h4>
{{ "Orchestration Status" | i18n }}
</h4>

<div class="detail">
<span class="info-label">{{ "Task" | i18n }}</span>
<span class="info-value">Synchronization</span>
<span class="info-value">{{ task.uuid }} Synchronization</span>
</div>
<progress percent="progress"></progress>
<progress percent="task.progress * 100"></progress>
<div class="divider"></div>
</section>

1 change: 1 addition & 0 deletions engines/bastion/app/assets/bastion/widgets/widgets.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
angular.module("Bastion.widgets", ['ngResource'])

0 comments on commit 1161aed

Please sign in to comment.