diff --git a/erpnext/templates/includes/projects.css b/erpnext/templates/includes/projects.css index e08088092f..d3f2e1786e 100644 --- a/erpnext/templates/includes/projects.css +++ b/erpnext/templates/includes/projects.css @@ -31,19 +31,19 @@ .timeline-centered { position: relative; - margin-bottom: 30px; + margin-bottom: 10px; } .timeline-centered:before { content: ''; position: absolute; display: block; - width: 4px; + width: 3px; background: #f5f5f6; /*left: 50%;*/ - top: 20px; - bottom: 20px; - margin-left: 30px; + top: 0px; + bottom: 0px; + margin-left: 10px; } .timeline-centered .timeline-entry { @@ -51,37 +51,25 @@ /*width: 50%; float: right;*/ margin-top: 5px; - margin-left: 30px; - margin-bottom: 10px; + margin-left: 10px; + margin-bottom: 5px; clear: both; } - -.timeline-centered .timeline-entry.left-aligned .timeline-entry-inner .timeline-label:after { - left: auto; - right: 0; - margin-left: 0; - margin-right: -9px; - -moz-transform: rotate(180deg); - -o-transform: rotate(180deg); - -webkit-transform: rotate(180deg); - -ms-transform: rotate(180deg); - transform: rotate(180deg); -} - .timeline-centered .timeline-entry .timeline-entry-inner { position: relative; - margin-left: -20px; + margin-left: -3px; } .timeline-centered .timeline-entry .timeline-entry-inner .timeline-icon { + margin-top:10px; background: #fff; color: #737881; display: block; - width: 40px; - height: 40px; + width: 10px; + height: 10px; -webkit-background-clip: padding-box; -moz-background-clip: padding; background-clip: padding-box; @@ -89,17 +77,41 @@ float: right;*/ -moz-border-radius: 20px; border-radius: 20px; text-align: center; - -moz-box-shadow: 0 0 0 5px #f5f5f6; - -webkit-box-shadow: 0 0 0 5px #f5f5f6; - box-shadow: 0 0 0 5px #f5f5f6; - line-height: 40px; - font-size: 15px; + -moz-box-shadow: 0 0 0 2px #f5f5f6; + -webkit-box-shadow: 0 0 0 2px #f5f5f6; + box-shadow: 0 0 0 2px #f5f5f6; + line-height: 30px; float: left; } +.timeline-centered .timeline-entry .timeline-entry-inner .timeline-icon.bg-primary { + background-color: #303641; + color: #fff; +} + +.timeline-centered .timeline-entry .timeline-entry-inner .timeline-icon.bg-secondary { + background-color: #ee4749; + color: #fff; +} + +.timeline-centered .timeline-entry .timeline-entry-inner .timeline-icon.bg-success { + background-color: #98d85b; + color: #fff; +} + +.timeline-centered .timeline-entry .timeline-entry-inner .timeline-icon.bg-info { + background-color: #21a9e1; + color: #fff; +} + .timeline-centered .timeline-entry .timeline-entry-inner .timeline-icon.bg-warning { - background-color: #fad839; + background-color: #ffa00a; + color: #fff; +} + +.timeline-centered .timeline-entry .timeline-entry-inner .timeline-icon.bg-danger { + background-color: #ff5858; color: #fff; } @@ -108,7 +120,7 @@ float: right;*/ position: relative; background: #f5f5f6; padding: 1em; - margin-left: 60px; + margin-left: 40px; -webkit-background-clip: padding-box; -moz-background-clip: padding; background-clip: padding-box; diff --git a/erpnext/templates/includes/projects/project_issues.html b/erpnext/templates/includes/projects/project_issues.html index 14ce70f1ad..34f6633af1 100644 --- a/erpnext/templates/includes/projects/project_issues.html +++ b/erpnext/templates/includes/projects/project_issues.html @@ -3,7 +3,7 @@
- + {% if issue.status == "Closed" %} {{ issue.subject }} resolved {{ frappe.utils.pretty_date(issue.resolution_date) }} {% else %} diff --git a/erpnext/templates/includes/projects/project_tasks.html b/erpnext/templates/includes/projects/project_tasks.html index 84de0e8914..b2be27babf 100644 --- a/erpnext/templates/includes/projects/project_tasks.html +++ b/erpnext/templates/includes/projects/project_tasks.html @@ -3,7 +3,7 @@
- + {% if task.status == "Closed" %} {{ task.subject }} completed on {{ task.closing_date }} {% else %} diff --git a/erpnext/templates/includes/projects/timeline.html b/erpnext/templates/includes/projects/timeline.html index 77b0c7609a..605404bb9f 100644 --- a/erpnext/templates/includes/projects/timeline.html +++ b/erpnext/templates/includes/projects/timeline.html @@ -1,44 +1,17 @@ {% for timeline in doc.timelines %} -
-
-
- - - {{timeline.reference_name}} {{timeline.subject }} - - - {{ frappe.utils.pretty_date(timeline.creation) }} - +
+
+
+
+
+ + + {{timeline.reference_name}} {{timeline.subject }} + + + {{ frappe.utils.pretty_date(timeline.creation) }} + +
-
-
-{% endfor %} - \ No newline at end of file + +{% endfor %} \ No newline at end of file diff --git a/erpnext/templates/pages/projects.html b/erpnext/templates/pages/projects.html index bbc5c6ebc8..c71cf2ec08 100644 --- a/erpnext/templates/pages/projects.html +++ b/erpnext/templates/pages/projects.html @@ -2,6 +2,17 @@ {% block title %}{{ doc.project_name }}{% endblock %} +{% block breadcrumbs %} +
+{% endblock %} + {% block header %}

{{ doc.project_name }} @@ -24,7 +35,7 @@ Filtered by "{{ frappe.form_dict.q }}" Clear

{% else %}

{{ _("Activity Feed") }}

-
+
{% include "erpnext/templates/includes/projects/timeline.html" %}
{% if doc.timelines|length > 9 %} @@ -40,7 +51,7 @@

{{ _("Tasks") }}

- +
diff --git a/erpnext/templates/pages/projects.js b/erpnext/templates/pages/projects.js index 87a1ab7b5a..b1468eba2f 100644 --- a/erpnext/templates/pages/projects.js +++ b/erpnext/templates/pages/projects.js @@ -1,172 +1,110 @@ frappe.ready(function() { - var reload_tasks = function(taskstatus) { - $.ajax({ - method: "GET", - url: "/", - dataType: "json", - data: { - cmd: "erpnext.templates.pages.projects.get_tasks_html", - project: '{{ doc.name }}', - taskstatus: taskstatus, - }, - dataType: "json", - success: function(data) { - $('.project-tasks').html(data.message); - - $('.project-tasks-section .btn-group .btn-primary').removeClass('btn-primary'); - $('.btn-'+ taskstatus +'-tasks').addClass( "btn-primary" ); - } - }); - - } + $( window ).load(function() { + $(".btn-open-tasks").click(); + $(".btn-open-issues").click(); + }); $('.btn-closed-tasks').click(function() { - reload_tasks('closed'); + reload_items('closed','tasks'); }); - $('.btn-open-tasks').click(function() { - reload_tasks('open'); - }); - var reload_issues = function(issuestatus) { + $('.btn-open-tasks').click(function() { + reload_items('open','tasks'); + }); + + $('.btn-closed-issues').click(function() { + reload_items('closed','issues'); + }); + + $('.btn-open-issues').click(function() { + reload_items('open','issues'); + }); + + var start = 10; + $(".more-tasks").click(function() { + more_items('tasks', true); + }); + + $(".more-issues").click(function() { + more_items('issues', true); + }); + + $(".more-timelogs").click(function() { + more_items('timelogs', false); + }); + + $(".more-timelines").click(function() { + more_items('timelines', false); + }); + + $( ".project-tasks" ).on('click', '.task-x', function() { + var item_name = $(this).attr('id'); + close_item('task', item_name); + }); + + $( ".project-issues" ).on('click', '.issue-x', function() { + var item_name = $(this).attr('id'); + close_item('issue', item_name); + }); + + var reload_items = function(item_status, item) { $.ajax({ method: "GET", url: "/", dataType: "json", data: { - cmd: "erpnext.templates.pages.projects.get_issues_html", + cmd: "erpnext.templates.pages.projects.get_"+ item +"_html", project: '{{ doc.name }}', - issuestatus: issuestatus, + item_status: item_status, }, dataType: "json", success: function(data) { - $('.project-issues').html(data.message); + $('.project-'+ item).html(data.message); - $('.project-issues-section .btn-group .btn-primary').removeClass('btn-primary'); - $('.btn-'+ issuestatus +'-issues').addClass( "btn-primary" ); + $('.project-'+ item +'-section .btn-group .btn-primary').removeClass('btn-primary'); + $('.btn-'+ item_status +'-'+ item).addClass( "btn-primary" ); + $(".more-"+ item).toggle(true); } }); } - $('.btn-closed-issues').click(function() { - reload_issues('closed'); - }); - $('.btn-open-issues').click(function() { - reload_issues('open'); - }); - - var taskstart = 5; - $(".more-tasks").click(function() { - var task_status = $('.project-tasks-section .btn-group .btn-primary').hasClass('btn-closed-tasks') - ? 'closed' : 'open'; - + var more_items = function(item, item_status){ + if(item_status) + { + var item_status = $('.project-'+ item +'-section .btn-group .btn-primary').hasClass('btn-closed-'+ item) + ? 'closed' : 'open'; + } $.ajax({ method: "GET", url: "/", dataType: "json", data: { - cmd: "erpnext.templates.pages.projects.get_tasks_html", + cmd: "erpnext.templates.pages.projects.get_"+ item +"_html", project: '{{ doc.name }}', - start: taskstart, - taskstatus: task_status, + start: start, + item_status: item_status, }, dataType: "json", success: function(data) { - $(data.message).appendTo('.project-tasks'); + $(data.message).appendTo('.project-'+ item); if(typeof data.message == 'undefined') { - $(".more-tasks").toggle(false); + $(".more-"+ item).toggle(false); } - taskstart = taskstart+5; + start = start+10; } - }); - - }); + }); + } - var issuestart = 2; - $(".more-issues").click(function() { - var issue_status = $('.project-issues-section .btn-group .btn-primary').hasClass('btn-closed-issues') - ? 'closed' : 'open'; - - $.ajax({ - method: "GET", - url: "/", - dataType: "json", - data: { - cmd: "erpnext.templates.pages.projects.get_issues_html", - project: '{{ doc.name }}', - start: issuestart, - issuestatus: issue_status, - }, - dataType: "json", - success: function(data) { - $(data.message).appendTo('.project-issues'); - if(typeof data.message == 'undefined') - { - $(".more-issues").toggle(false); - } - issuestart = issuestart+5; - } - }); - }); - - var timelogstart = 2; - $(".more-timelogs").click(function() { - $.ajax({ - method: "GET", - url: "/", - dataType: "json", - data: { - cmd: "erpnext.templates.pages.projects.get_timelogs_html", - project: '{{ doc.name }}', - start: timelogstart, - }, - dataType: "json", - success: function(data) { - $(data.message).appendTo('.project-timelogs'); - if(typeof data.message == 'undefined') - { - $(".more-timelogs").toggle(false); - } - timelogstart = timelogstart+2; - - } - }); - - }); - - var timelinestart = 10; - $(".more-timelines").click(function() { - $.ajax({ - method: "GET", - url: "/", - dataType: "json", - data: { - cmd: "erpnext.templates.pages.projects.get_timeline_html", - project: '{{ doc.name }}', - start: timelinestart, - - }, - dataType: "json", - success: function(data) { - $(data.message).appendTo('.project-timeline'); - if(typeof data.message == 'undefined') - { - $(".more-timelines").toggle(false); - } - timelinestart = timelinestart+10; - } - }); - }); - - $( ".project-tasks" ).on('click', '.task-x', function() { + var close_item = function(item, item_name){ var args = { project: '{{ doc.name }}', - task_name: $(this).attr('id'), - } + item_name: item_name, + } frappe.call({ btn: this, type: "POST", - method: "erpnext.templates.pages.projects.set_task_status", + method: "erpnext.templates.pages.projects.set_"+ item +"_status", args: args, callback: function(r) { if(r.exc) { @@ -178,27 +116,5 @@ frappe.ready(function() { } }) return false; - }); - - $( ".project-issues" ).on('click', '.issue-x', function() { - var args = { - project: '{{ doc.name }}', - issue_name: $(this).attr('id'), - } - frappe.call({ - btn: this, - type: "POST", - method: "erpnext.templates.pages.projects.set_issue_status", - args: args, - callback: function(r) { - if(r.exc) { - if(r._server_messages) - frappe.msgprint(r._server_messages); - } else { - $(this).remove(); - } - } - }) - return false; - }); + } }); diff --git a/erpnext/templates/pages/projects.py b/erpnext/templates/pages/projects.py index 7d0d2009fe..758113f660 100644 --- a/erpnext/templates/pages/projects.py +++ b/erpnext/templates/pages/projects.py @@ -32,39 +32,43 @@ def get_context(context): def get_timeline(project, start=10): issue_names = '({0})'.format(", ".join(["'{0}'".format(i.name) for i in get_issues(project)])) - print issue_names - timelines = frappe.db.sql("""select sender_full_name, - subject, communication_date, comment_type, name, creation, modified_by, reference_doctype, reference_name, - _liked_by, comment_type, _comments - from tabCommunication - where (reference_doctype='Project' and reference_name=%s) + timelines = frappe.db.sql(""" + select + sender_full_name, + subject, communication_date, comment_type, name, creation, modified_by, reference_doctype, reference_name, + _liked_by, comment_type, _comments + from + tabCommunication + where + (reference_doctype='Project' and reference_name=%s) or (timeline_doctype='Project' and timeline_name=%s) or (reference_doctype='Issue' and reference_name IN {issue_names}) - order by modified DESC limit {start}, {limit}""".format( + order by + modified DESC limit {start}, {limit}""".format( issue_names=issue_names, start=start, limit=10), - (project, project), as_dict=True); + (project, project), as_dict=True); for timeline in timelines: timeline.user_image = frappe.db.get_value('User', timeline.modified_by, 'user_image') return timelines @frappe.whitelist() -def get_timeline_html(project, start=0): +def get_timelines_html(project, start=0): return frappe.render_template("erpnext/templates/includes/projects/timeline.html", {"doc": {"timelines": get_timeline(project, start)}}, is_path=True) def get_issue_list(project): return [issue.name for issue in get_issues(project)] -def get_tasks(project, start=0, search=None, taskstatus=None): +def get_tasks(project, start=0, search=None, item_status=None): filters = {"project": project} if search: filters["subject"] = ("like", "%{0}%".format(search)) - if taskstatus: - filters = {"status": taskstatus} + if item_status: + filters = {"status": item_status} tasks = frappe.get_all("Task", filters=filters, fields=["name", "subject", "status", "exp_start_date", "exp_end_date", "priority"], - limit_start=start, limit_page_length=5) + limit_start=start, limit_page_length=10) for task in tasks: task.todo = frappe.get_all('ToDo',filters={'reference_name':task.name, 'reference_type':'Task'}, @@ -76,22 +80,21 @@ def get_tasks(project, start=0, search=None, taskstatus=None): return tasks @frappe.whitelist() -def get_tasks_html(project, start=0, taskstatus=None): +def get_tasks_html(project, start=0, item_status=None): return frappe.render_template("erpnext/templates/includes/projects/project_tasks.html", - {"doc": {"tasks": get_tasks(project, start, taskstatus=taskstatus)}}, is_path=True) + {"doc": {"tasks": get_tasks(project, start, item_status=item_status)}}, is_path=True) -def get_issues(project, start=0, search=None, issuestatus=None): - print issuestatus +def get_issues(project, start=0, search=None, item_status=None): filters = {"project": project} if search: filters["subject"] = ("like", "%{0}%".format(search)) - if issuestatus: - filters = {"status": issuestatus} + if item_status: + filters = {"status": item_status} issues = frappe.get_all("Issue", filters=filters, fields=["name", "subject", "status", "opening_date", "resolution_date", "resolution_details"], order_by='modified desc', - limit_start=start, limit_page_length=5) + limit_start=start, limit_page_length=10) for issue in issues: issue.todo = frappe.get_all('ToDo',filters={'reference_name':issue.name, 'reference_type':'Issue'}, @@ -103,10 +106,9 @@ def get_issues(project, start=0, search=None, issuestatus=None): return issues @frappe.whitelist() -def get_issues_html(project, start=0, issuestatus=None): - print issuestatus +def get_issues_html(project, start=0, item_status=None): return frappe.render_template("erpnext/templates/includes/projects/project_issues.html", - {"doc": {"issues": get_issues(project, start, issuestatus=issuestatus)}}, is_path=True) + {"doc": {"issues": get_issues(project, start, item_status=item_status)}}, is_path=True) def get_timelogs(project, start=0, search=None): filters = {"project": project} @@ -115,7 +117,7 @@ def get_timelogs(project, start=0, search=None): timelogs = frappe.get_all('Time Log', filters=filters, fields=['name','title','task','activity_type','from_time','to_time','hours','status','modified','modified_by'], - limit_start=start, limit_page_length=2) + limit_start=start, limit_page_length=10) for timelog in timelogs: timelog.user_image = frappe.db.get_value('User', timelog.modified_by, 'user_image') return timelogs @@ -126,14 +128,14 @@ def get_timelogs_html(project, start=0): {"doc": {"timelogs": get_timelogs(project, start)}}, is_path=True) @frappe.whitelist() -def set_task_status(project, task_name): - task = frappe.get_doc("Task", task_name) +def set_task_status(project, item_name): + task = frappe.get_doc("Task", item_name) task.status = 'Closed' task.save(ignore_permissions=True) @frappe.whitelist() -def set_issue_status(project, issue_name): - issue = frappe.get_doc("Issue", issue_name) +def set_issue_status(project, item_name): + issue = frappe.get_doc("Issue", item_name) issue.status = 'Closed' issue.save(ignore_permissions=True)