Display activity stream on project page #2222

Web handler and template to show activity stream on project page

Review ID: 358001
This commit is contained in:
Tarun Bhardwaj 2013-08-12 13:22:18 +05:30
parent 201c7a8649
commit 3e3f9a7536
6 changed files with 147 additions and 8 deletions

View File

@ -11,7 +11,7 @@ from trytond.pool import Pool
from project import (
WebSite, ProjectUsers, ProjectInvitation,
ProjectWorkInvitation, TimesheetEmployeeDay, Project, Tag,
TaskTags, ProjectHistory, ProjectWorkCommit, Activity,
TaskTags, ProjectHistory, ProjectWorkCommit, Activity, TimesheetLine,
)
from company import Company, CompanyProjectAdmins, NereidUser
@ -34,5 +34,6 @@ def register():
Company,
CompanyProjectAdmins,
NereidUser,
TimesheetLine,
module='nereid_project', type_='model',
)

View File

@ -36,12 +36,14 @@ from trytond.pool import Pool, PoolMeta
from trytond.transaction import Transaction
from trytond.pyson import Eval
from trytond.config import CONFIG
from trytond.tools import get_smtp_server, datetime_strftime
from trytond.tools import get_smtp_server
from trytond.backend import TableHandler
__all__ = ['WebSite', 'ProjectUsers', 'ProjectInvitation',
'TimesheetEmployeeDay', 'ProjectWorkInvitation', 'Project', 'Tag',
'TaskTags', 'ProjectHistory', 'ProjectWorkCommit', 'Activity',]
'TaskTags', 'ProjectHistory', 'ProjectWorkCommit', 'Activity',
'TimesheetLine',
]
__metaclass__ = PoolMeta
@ -385,11 +387,13 @@ class Project:
}
if self.type == 'project':
rv['url'] = url_for(
'project.work.render_project', active_id=self.id
'project.work.render_project', project_id=self.id
)
else:
# TODO: Convert self.parent to self.project
rv['url'] = url_for(
'project.work.render_task', active_id=self.id
'project.work.render_task', project_id=self.parent.id,
task_id=self.id,
)
return rv
@ -1995,6 +1999,26 @@ class Project:
flash("The estimated hours have been changed for this task.")
return redirect(request.referrer)
@login_required
def stream(self):
'''
Return stream for a project.
'''
Activity = Pool().get('nereid.activity')
self.can_read(request.nereid_user)
page = request.args.get('page', 1, int)
domain = [('project', '=', self.id)]
activities = Pagination(Activity, domain, page, 20)
items = filter(
None, map(lambda activity: activity.serialize(), activities)
)
return jsonify({
'totalItems': activities.count,
'items': items,
})
class Tag(ModelSQL, ModelView):
"Tags"
@ -2185,15 +2209,19 @@ class ProjectHistory(ModelSQL, ModelView):
'''
Serialize the history and returns a dictionary.
'''
# TODO: Return changed value also. So that it is possible to handle all
# history events separately.
return {
"url": url_for(
'project.work.render_task_list', comment=self.comment.id
'project.work.render_task', project_id=self.project.parent.id,
task_id=self.project.id,
),
"objectType": self.__name__,
"id": self.id,
"displayName": self.display_name,
"displayName": self.rec_name,
}
@classmethod
def create_history_line(cls, project, changed_values):
"""
@ -2481,6 +2509,28 @@ def invitation_new_user_handler(nereid_user_id):
})
class TimesheetLine:
'''
Timesheet Lines
'''
__name__ = 'timesheet.line'
def _json(self):
'''
Serialize timesheet line and returns a dictionary.
'''
# Render url for timesheet line is task on which this time is marked
return {
"url": url_for(
'project.work.render_task', project_id=self.work.parent.id,
task_id=self.work.id,
),
"objectType": self.__name__,
"id": self.id,
"displayName": "%dh %dm" % (self.hours, (self.hours * 60) % 60),
}
class Activity:
'''
Nereid user activity

6
static/js/underscore.js Normal file

File diff suppressed because one or more lines are too long

View File

@ -135,6 +135,7 @@
<script src="{{ STATIC }}js/jquery.meow.js"></script>
<script src="{{ STATIC }}js/chosen.jquery.min.js"></script>
<script src="{{ STATIC }}js/fullcalendar.min.js"></script>
<script src="{{ STATIC }}js/underscore.js"></script>
<!--<script src="https://ajax.googleapis.com/ajax/libs/jqueryui/1.8.21/jquery-ui.min.js"></script> -->
{% block scripts %}
{% endblock %}

View File

@ -183,7 +183,9 @@
{% block main %}
{% if request.endpoint == 'project.work.render_project' %}
<div class="row-fluid" id="project_timeline"></div>
<div class="row-fluid" id="project_timeline">
<!-- Put stream here -->
</div>
<div class="row-fluid">
<div class="span5"></div>
<a class="btn btn-mini" id="more_project_timeline">{{ _('Show More') }}</a>
@ -193,8 +195,45 @@
{% block scripts %}
{{ super() }}
<script id="created_project" type="text/template">
<div class="well well-small">
<a href="<%= actor.url %>"><%= actor.displayName %></a> created new project <a href="<%= object.url %>"><%= object.displayName %></a>.
</div>
</script>
<script id="created_tag" type="text/template">
<div class="well well-small">
<a href="<%= actor.url %>"><%= actor.displayName %></a> created new tag <a href="<%= object.url %>"><%= object.displayName %></a> for <a href="<%= target.url %>"><%= target.displayName %></a>.
</div>
</script>
<script id="created_task" type="text/template">
<div class="well well-small">
<a href="<%= actor.url %>"><%= actor.displayName %></a> created new task <a href="<%= object.url %>"><%= object.displayName %></a> for <a href="<%= target.url %>"><%= target.displayName %></a>.
</div>
</script>
<script id="reported_time" type="text/template">
<div class="well well-small">
<a href="<%= actor.url %>"><%= actor.displayName %></a> worked for <b><%= object.displayName %></b> on <a href="<%= target.url %>"><%= target.displayName %></a>.
</div>
</script>
<script id="updated_task" type="text/template">
<!--
TODO: Updated_task can have multiple events like commented, changed assignee, changed constrain date etc
Handle all of them.
-->
<div class="well well-small">
<a href="<%= actor.url %>"><%= actor.displayName %></a> updated <a href="<%= target.url %>"><%= target.displayName %></a>.
</div>
</script>
<script>
$(document).ready(function(){
var page = 0;
var created_project_template = _.template($("script#created_project").html());
var created_tag_template = _.template($("script#created_tag").html());
var created_task_template = _.template($("script#created_task").html());
var reported_time_template = _.template($("script#reported_time").html());
var updated_task_template = _.template($("script#updated_task").html());
// Remove a tag
$('.btn-remove-tag').click(function(){
tag_id = $(this).attr('id')
@ -206,6 +245,39 @@
$("div#" + tag_id).hide();
});
});
$("#more_project_timeline").click(function(e){
e.preventDefault();
$.getJSON("{{ url_for('project.work.stream', active_id=project.id) }}?page=" + ++page)
.done(function(response){
if (!response.items.length) {
$("#more_project_timeline").remove();
return;
}
_.each(response.items, function(item){
if (!item) {
return;
}
switch(item.verb) {
case "created_project":
$("#project_timeline").append(created_project_template(item));
break;
case "created_tag":
$("#project_timeline").append(created_tag_template(item));
break;
case "created_task":
$("#project_timeline").append(created_task_template(item));
break;
case "reported_time":
$("#project_timeline").append(reported_time_template(item));
break;
case "updated_task":
$("#project_timeline").append(updated_task_template(item));
break;
}
});
});
}).click();
});
</script>

View File

@ -273,5 +273,14 @@
<field name="sequence" eval="60" />
<field name="url_map" ref="nereid.default_url_map" />
</record>
<!-- Project Activities -->
<record id="project_activity_stream" model="nereid.url_rule">
<field name="rule">/&lt;language&gt;/project-&lt;int:active_id&gt;/stream</field>
<field name="endpoint">project.work.stream</field>
<field name="sequence" eval="50" />
<field name="http_method_get" eval="True"/>
<field name="url_map" ref="nereid.default_url_map" />
</record>
</data>
</tryton>