fix: Project Portal Enhancements (#26290)
* fix: project portal enhancements * fix: condition for pills
This commit is contained in:
parent
d4146a91d6
commit
5173e74a04
@ -157,6 +157,7 @@ website_route_rules = [
|
||||
"parents": [{"label": _("Material Request"), "route": "material-requests"}]
|
||||
}
|
||||
},
|
||||
{"from_route": "/project", "to_route": "Project"}
|
||||
]
|
||||
|
||||
standard_portal_menu_items = [
|
||||
|
@ -1,28 +1,54 @@
|
||||
{% if doc.status=="Open" %}
|
||||
<div class="web-list-item">
|
||||
<a class="no-decoration" href="/projects?project={{ doc.name | urlencode }}">
|
||||
<div class="row">
|
||||
<div class="col-xs-6">
|
||||
|
||||
{{ doc.name }}
|
||||
</div>
|
||||
<div class="col-xs-3">
|
||||
{% if doc.percent_complete %}
|
||||
<div class="progress" style="margin-bottom: 0!important; margin-top: 10px!important; height:5px;">
|
||||
<div class="progress-bar progress-bar-{{ "warning" if doc.percent_complete|round < 100 else "success"}}" role="progressbar"
|
||||
aria-valuenow="{{ doc.percent_complete|round|int }}"
|
||||
aria-valuemin="0" aria-valuemax="100" style="width:{{ doc.percent_complete|round|int }}%;">
|
||||
</div>
|
||||
</div>
|
||||
{% else %}
|
||||
<span class="indicator {{ "red" if doc.status=="Open" else "gray" }}">
|
||||
{{ doc.status }}</span>
|
||||
{% endif %}
|
||||
</div>
|
||||
<div class="col-xs-3 text-right small text-muted">
|
||||
{{ frappe.utils.pretty_date(doc.modified) }}
|
||||
</div>
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
{% if doc.status == "Open" %}
|
||||
<div class="web-list-item transaction-list-item">
|
||||
<div class="row">
|
||||
<div class="col-xs-2">
|
||||
<a class="transaction-item-link" href="/projects?project={{ doc.name | urlencode }}">Link</a>
|
||||
{{ doc.name }}
|
||||
</div>
|
||||
<div class="col-xs-2">
|
||||
{{ doc.project_name }}
|
||||
</div>
|
||||
<div class="col-xs-3 text-center">
|
||||
{% if doc.percent_complete %}
|
||||
{% set pill_class = "green" if doc.percent_complete | round == 100 else
|
||||
"orange" %}
|
||||
<div class="ellipsis">
|
||||
<span class="indicator-pill {{ pill_class }} filterable ellipsis">
|
||||
<span>{{ frappe.utils.cint(doc.percent_complete) }}
|
||||
%</span>
|
||||
</span>
|
||||
</div>
|
||||
{% else %}
|
||||
<span class="indicator-pill {{ " red" if doc.status=="Open" else " darkgrey" }}">
|
||||
{{ doc.status }}</span>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% if doc["_assign"] %}
|
||||
{% set assigned_users = json.loads(doc["_assign"])%}
|
||||
<div class="col-xs-2">
|
||||
{% for user in assigned_users %}
|
||||
{% set user_details = frappe
|
||||
.db
|
||||
.get_value("User", user, [
|
||||
"full_name", "user_image"
|
||||
], as_dict = True) %}
|
||||
{% if user_details.user_image %}
|
||||
<span class="avatar avatar-small" style="width:32px; height:32px;" title="{{ user_details.full_name }}">
|
||||
<img src="{{ user_details.user_image }}">
|
||||
</span>
|
||||
{% else %}
|
||||
<span class="avatar avatar-small" style="width:32px; height:32px;" title="{{ user_details.full_name }}">
|
||||
<div class='standard-image' style="background-color: #F5F4F4; color: #000;">
|
||||
{{ frappe.utils.get_abbr(user_details.full_name) }}
|
||||
</div>
|
||||
</span>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% endif %}
|
||||
<div class="col-xs-3 text-right small text-muted">
|
||||
{{ frappe.utils.pretty_date(doc.modified) }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
@ -1,32 +1,5 @@
|
||||
{% for task in doc.tasks %}
|
||||
<div class='task'>
|
||||
<a class="no-decoration task-link {{ task.css_seen }}" href="/tasks?name={{ task.name }}">
|
||||
<div class='row project-item'>
|
||||
<div class='col-xs-9'>
|
||||
<span class="indicator {{ "red" if task.status=="Open" else "green" if task.status=="Closed" else "gray" }}" title="{{ task.status }}" > {{ task.subject }}</span>
|
||||
<div class="small text-muted item-timestamp"
|
||||
title="{{ frappe.utils.pretty_date(task.modified) }}">
|
||||
{{ _("modified") }} {{ frappe.utils.pretty_date(task.modified) }}
|
||||
</div>
|
||||
</div>
|
||||
<div class='col-xs-1'>{% if task.todo %}
|
||||
{% if task.todo.user_image %}
|
||||
<span class="avatar avatar-small" title="{{ task.todo.owner }}">
|
||||
<img src="{{ task.todo.user_image }}">
|
||||
</span>
|
||||
{% else %}
|
||||
<span class="avatar avatar-small standard-image" title="Assigned to {{ task.todo.owner }}">
|
||||
|
||||
</span>
|
||||
{% endif %}
|
||||
{% endif %} </div>
|
||||
<div class='col-xs-2'>
|
||||
<span class="pull-right list-comment-count small {{ "text-extra-muted" if task.comment_count==0 else "text-muted" }}">
|
||||
<i class="octicon octicon-comment-discussion"></i>
|
||||
{{ task.comment_count }}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
<div class="web-list-item transaction-list-item">
|
||||
{{ task_row(task, 0) }}
|
||||
</div>
|
||||
{% endfor %}
|
||||
|
@ -1,23 +1,33 @@
|
||||
{% for timesheet in doc.timesheets %}
|
||||
<div class='timesheet'>
|
||||
<a class="no-decoration timesheet-link {{ timesheet.css_seen }}" href="/timesheet/{{ timesheet.info.name}}">
|
||||
<div class='row project-item'>
|
||||
<div class='col-xs-10'>
|
||||
<span class="indicator {{ "blue" if timesheet.info.status=="Submitted" else "red" if timesheet.info.status=="Draft" else "gray" }}" title="{{ timesheet.info.status }}" > {{ timesheet.info.name }} </span>
|
||||
<div class="small text-muted item-timestamp">
|
||||
{{ _("From") }} {{ frappe.format_date(timesheet.from_time) }} {{ _("to") }} {{ frappe.format_date(timesheet.to_time) }}
|
||||
</div>
|
||||
</div>
|
||||
<div class='col-xs-1' style="margin-right:-30px;">
|
||||
<span class="avatar avatar-small" title="{{ timesheet.info.modified_by }}"> <img src="{{ timesheet.info.user_image }}" style="display:flex;"></span>
|
||||
</div>
|
||||
<div class='col-xs-1'>
|
||||
<span class="pull-right list-comment-count small {{ "text-extra-muted" if timesheet.comment_count==0 else "text-muted" }}">
|
||||
<i class="octicon octicon-comment-discussion"></i>
|
||||
{{ timesheet.info.comment_count }}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
{% endfor %}
|
||||
<div class="web-list-item transaction-list-item">
|
||||
<div class="row">
|
||||
<div class="col-xs-2">{{ timesheet.name }}</div>
|
||||
<a class="transaction-item-link" href="/timesheet/{{ timesheet.name}}">Link</a>
|
||||
<div class="col-xs-2">{{ timesheet.status }}</div>
|
||||
<div class="col-xs-2">{{ frappe.utils.format_date(timesheet.from_time, "medium") }}</div>
|
||||
<div class="col-xs-2">{{ frappe.utils.format_date(timesheet.to_time, "medium") }}</div>
|
||||
<div class="col-xs-2">
|
||||
{% set user_details = frappe
|
||||
.db
|
||||
.get_value("User", timesheet.modified_by, [
|
||||
"full_name", "user_image"
|
||||
], as_dict = True)
|
||||
%}
|
||||
{% if user_details.user_image %}
|
||||
<span class="avatar avatar-small" style="width:32px; height:32px;" title="{{ user_details.full_name }}">
|
||||
<img src="{{ user_details.user_image }}">
|
||||
</span>
|
||||
{% else %}
|
||||
<span class="avatar avatar-small" style="width:32px; height:32px;" title="{{ user_details.full_name }}">
|
||||
<div class='standard-image' style='background-color: #F5F4F4; color: #000;'>
|
||||
{{ frappe.utils.get_abbr(user_details.full_name) }}
|
||||
</div>
|
||||
</span>
|
||||
{% endif %}
|
||||
</div>
|
||||
<div class="col-xs-2 text-right">
|
||||
{{ frappe.utils.pretty_date(timesheet.modified) }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
|
@ -1,90 +1,173 @@
|
||||
{% extends "templates/web.html" %}
|
||||
|
||||
{% block title %}{{ doc.project_name }}{% endblock %}
|
||||
{% block title %}
|
||||
{{ doc.project_name }}
|
||||
{% endblock %}
|
||||
|
||||
{% block head_include %}
|
||||
<link rel="stylesheet" href="/assets/frappe/css/font-awesome.css">
|
||||
{% endblock %}
|
||||
|
||||
{% block header %}
|
||||
<h1>{{ doc.project_name }}</h1>
|
||||
<h1>{{ doc.project_name }}</h1>
|
||||
{% endblock %}
|
||||
|
||||
{% block style %}
|
||||
<style>
|
||||
{% include "templates/includes/projects.css" %}
|
||||
</style>
|
||||
<style>
|
||||
{
|
||||
% include "templates/includes/projects.css"%
|
||||
}
|
||||
</style>
|
||||
{% endblock %}
|
||||
|
||||
|
||||
{% block page_content %}
|
||||
{% if doc.percent_complete %}
|
||||
<div class="progress progress-hg">
|
||||
<div class="progress-bar progress-bar-{{ "warning" if doc.percent_complete|round < 100 else "success" }} active" role="progressbar" aria-valuenow="{{ doc.percent_complete|round|int }}"
|
||||
aria-valuemin="0" aria-valuemax="100" style="width:{{ doc.percent_complete|round|int }}%;">
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
<div class="clearfix">
|
||||
<h4 style="float: left;">{{ _("Tasks") }}</h4>
|
||||
<a class="btn btn-secondary btn-light btn-sm" style="float: right; position: relative; top: 10px;" href='/tasks?new=1&project={{ doc.project_name }}'>{{ _("New task") }}</a>
|
||||
</div>
|
||||
{{ progress_bar(doc.percent_complete) }}
|
||||
|
||||
<p>
|
||||
<!-- <a class='small underline task-status-switch' data-status='Open'>{{ _("Show closed") }}</a> -->
|
||||
</p>
|
||||
<div class="d-flex mt-5 mb-5 justify-content-between">
|
||||
<h4>Status:</h4>
|
||||
<h4>Progress:
|
||||
<span>{{ doc.percent_complete }}
|
||||
%</span>
|
||||
</h4>
|
||||
<h4>Hours Spent:
|
||||
<span>{{ doc.actual_time }}</span>
|
||||
</h4>
|
||||
</div>
|
||||
|
||||
{% if doc.tasks %}
|
||||
<div class='project-task-section'>
|
||||
<div class='project-task'>
|
||||
{% include "erpnext/templates/includes/projects/project_tasks.html" %}
|
||||
</div>
|
||||
<p><a id= 'more-task' style='display: none;' class='more-tasks small underline'>{{ _("More") }}</a><p>
|
||||
</div>
|
||||
{% else %}
|
||||
<p class="text-muted">{{ _("No tasks") }}</p>
|
||||
{% endif %}
|
||||
{{ progress_bar(doc.percent_complete) }}
|
||||
|
||||
{% if doc.tasks %}
|
||||
<div class="website-list">
|
||||
<div class="result">
|
||||
<div class="web-list-item transaction-list-item">
|
||||
<div class="row">
|
||||
<h3 class="col-xs-4">Tasks</h3>
|
||||
<h3 class="col-xs-2">Status</h3>
|
||||
<h3 class="col-xs-2">End Date</h3>
|
||||
<h3 class="col-xs-2">Assigned To</h3>
|
||||
<div class="col-xs-2 text-right">
|
||||
<a class="btn btn-secondary btn-light btn-sm" href='/tasks?new=1&project={{ doc.project_name }}'>{{ _("New task") }}</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% include "erpnext/templates/includes/projects/project_tasks.html" %}
|
||||
</div>
|
||||
</div>
|
||||
{% else %}
|
||||
<p class="font-weight-bold">{{ _("No Tasks") }}</p>
|
||||
{% endif %}
|
||||
|
||||
<div class='padding'></div>
|
||||
{% if doc.timesheets %}
|
||||
<div class="website-list">
|
||||
<div class="result">
|
||||
<div class="web-list-item transaction-list-item">
|
||||
<div class="row">
|
||||
<h3 class="col-xs-2">Timesheets</h3>
|
||||
<h3 class="col-xs-2">Status</h3>
|
||||
<h3 class="col-xs-2">From</h3>
|
||||
<h3 class="col-xs-2">To</h3>
|
||||
<h3 class="col-xs-2">Modified By</h3>
|
||||
<h3 class="col-xs-2 text-right">Modified On</h3>
|
||||
</div>
|
||||
</div>
|
||||
{% include "erpnext/templates/includes/projects/project_timesheets.html" %}
|
||||
</div>
|
||||
</div>
|
||||
{% else %}
|
||||
<p class="font-weight-bold mt-5">{{ _("No Timesheets") }}</p>
|
||||
{% endif %}
|
||||
|
||||
<h4>{{ _("Timesheets") }}</h4>
|
||||
{% if doc.attachments %}
|
||||
<div class='padding'></div>
|
||||
|
||||
{% if doc.timesheets %}
|
||||
<div class='project-timelogs'>
|
||||
{% include "erpnext/templates/includes/projects/project_timesheets.html" %}
|
||||
</div>
|
||||
{% if doc.timesheets|length > 9 %}
|
||||
<p><a class='more-timelogs small underline'>{{ _("More") }}</a><p>
|
||||
{% endif %}
|
||||
{% else %}
|
||||
<p class="text-muted">{{ _("No time sheets") }}</p>
|
||||
{% endif %}
|
||||
|
||||
{% if doc.attachments %}
|
||||
<div class='padding'></div>
|
||||
|
||||
<h4>{{ _("Attachments") }}</h4>
|
||||
<div class="project-attachments">
|
||||
{% for attachment in doc.attachments %}
|
||||
<div class="attachment">
|
||||
<a class="no-decoration attachment-link" href="{{ attachment.file_url }}" target="blank">
|
||||
<div class="row">
|
||||
<div class="col-xs-9">
|
||||
<span class="indicator red file-name"> {{ attachment.file_name }}</span>
|
||||
</div>
|
||||
<div class="col-xs-3">
|
||||
<span class="pull-right file-size">{{ attachment.file_size }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% endif %}
|
||||
<h4>{{ _("Attachments") }}</h4>
|
||||
<div class="project-attachments">
|
||||
{% for attachment in doc.attachments %}
|
||||
<div class="attachment">
|
||||
<a class="no-decoration attachment-link" href="{{ attachment.file_url }}" target="blank">
|
||||
<div class="row">
|
||||
<div class="col-xs-9">
|
||||
<span class="indicator red file-name">
|
||||
{{ attachment.file_name }}</span>
|
||||
</div>
|
||||
<div class="col-xs-3">
|
||||
<span class="pull-right file-size">{{ attachment.file_size }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
</div>
|
||||
|
||||
<script>
|
||||
{% include "frappe/public/js/frappe/provide.js" %}
|
||||
{% include "frappe/public/js/frappe/form/formatters.js" %}
|
||||
{ % include "frappe/public/js/frappe/provide.js" %
|
||||
} { % include "frappe/public/js/frappe/form/formatters.js" %
|
||||
}
|
||||
</script>
|
||||
|
||||
{% endblock %}
|
||||
|
||||
{% macro progress_bar(percent_complete) %}
|
||||
{% if percent_complete %}
|
||||
<div class="progress progress-hg" style="height: 5px;">
|
||||
<div class="progress-bar progress-bar-{{ 'warning' if percent_complete|round < 100 else 'success' }} active" role="progressbar" aria-valuenow="{{ percent_complete|round|int }}" aria-valuemin="0" aria-valuemax="100" style="width:{{ percent_complete|round|int }}%;"></div>
|
||||
</div>
|
||||
{% else %}
|
||||
<hr>
|
||||
{% endif %}
|
||||
{% endmacro %}
|
||||
|
||||
{% macro task_row(task, indent) %}
|
||||
<div class="row mt-5 {% if task.children %} font-weight-bold {% endif %}">
|
||||
<div class="col-xs-4">
|
||||
<a class="nav-link " style="color: inherit; {% if task.parent_task %} margin-left: {{ indent }}px {% endif %}" href="/tasks?name={{ task.name | urlencode }}">
|
||||
{% if task.parent_task %}
|
||||
<span class="">
|
||||
<i class="fa fa-level-up fa-rotate-90"></i>
|
||||
</span>
|
||||
{% endif %}
|
||||
{{ task.subject }}</a>
|
||||
</div>
|
||||
<div class="col-xs-2">{{ task.status }}</div>
|
||||
<div class="col-xs-2">
|
||||
{% if task.exp_end_date %}
|
||||
{{ task.exp_end_date }}
|
||||
{% else %}
|
||||
--
|
||||
{% endif %}
|
||||
</div>
|
||||
<div class="col-xs-2">
|
||||
{% if task["_assign"] %}
|
||||
{% set assigned_users = json.loads(task["_assign"])%}
|
||||
{% for user in assigned_users %}
|
||||
{% set user_details = frappe.db.get_value("User", user,
|
||||
["full_name", "user_image"],
|
||||
as_dict = True)%}
|
||||
{% if user_details.user_image %}
|
||||
<span class="avatar avatar-small" style="width:32px; height:32px;" title="{{ user_details.full_name }}">
|
||||
<img src="{{ user_details.user_image }}">
|
||||
</span>
|
||||
{% else %}
|
||||
<span class="avatar avatar-small" style="width:32px; height:32px;" title="{{ user_details.full_name }}">
|
||||
<div class='standard-image' style='background-color: #F5F4F4; color: #000;'>
|
||||
{{ frappe.utils.get_abbr(user_details.full_name) }}
|
||||
</div>
|
||||
</span>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
</div>
|
||||
<div class="col-xs-2 text-right">
|
||||
{{ frappe.utils.pretty_date(task.modified) }}
|
||||
</div>
|
||||
</div>
|
||||
{% if task.children %}
|
||||
{% for child in task.children %}
|
||||
{{ task_row(child, indent + 30) }}
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
{% endmacro %}
|
||||
|
@ -35,26 +35,16 @@ def get_tasks(project, start=0, search=None, item_status=None):
|
||||
# if item_status:
|
||||
# filters["status"] = item_status
|
||||
tasks = frappe.get_all("Task", filters=filters,
|
||||
fields=["name", "subject", "status", "_seen", "_comments", "modified", "description"],
|
||||
fields=["name", "subject", "status", "modified", "_assign", "exp_end_date", "is_group", "parent_task"],
|
||||
limit_start=start, limit_page_length=10)
|
||||
|
||||
task_nest = []
|
||||
for task in tasks:
|
||||
task.todo = frappe.get_all('ToDo',filters={'reference_name':task.name, 'reference_type':'Task'},
|
||||
fields=["assigned_by", "owner", "modified", "modified_by"])
|
||||
|
||||
if task.todo:
|
||||
task.todo=task.todo[0]
|
||||
task.todo.user_image = frappe.db.get_value('User', task.todo.owner, 'user_image')
|
||||
|
||||
|
||||
task.comment_count = len(json.loads(task._comments or "[]"))
|
||||
|
||||
task.css_seen = ''
|
||||
if task._seen:
|
||||
if frappe.session.user in json.loads(task._seen):
|
||||
task.css_seen = 'seen'
|
||||
|
||||
return tasks
|
||||
if task.is_group:
|
||||
child_tasks = list(filter(lambda x: x.parent_task == task.name, tasks))
|
||||
if len(child_tasks):
|
||||
task.children = child_tasks
|
||||
task_nest.append(task)
|
||||
return list(filter(lambda x: not x.parent_task, tasks))
|
||||
|
||||
@frappe.whitelist()
|
||||
def get_task_html(project, start=0, item_status=None):
|
||||
@ -74,19 +64,12 @@ def get_timesheets(project, start=0, search=None):
|
||||
fields=['project','activity_type','from_time','to_time','parent'],
|
||||
limit_start=start, limit_page_length=10)
|
||||
for timesheet in timesheets:
|
||||
timesheet.infos = frappe.get_all('Timesheet', filters={"name": timesheet.parent},
|
||||
fields=['name','_comments','_seen','status','modified','modified_by'],
|
||||
info = frappe.get_all('Timesheet', filters={"name": timesheet.parent},
|
||||
fields=['name','status','modified','modified_by'],
|
||||
limit_start=start, limit_page_length=10)
|
||||
|
||||
for timesheet.info in timesheet.infos:
|
||||
timesheet.info.user_image = frappe.db.get_value('User', timesheet.info.modified_by, 'user_image')
|
||||
|
||||
timesheet.info.comment_count = len(json.loads(timesheet.info._comments or "[]"))
|
||||
|
||||
timesheet.info.css_seen = ''
|
||||
if timesheet.info._seen:
|
||||
if frappe.session.user in json.loads(timesheet.info._seen):
|
||||
timesheet.info.css_seen = 'seen'
|
||||
if len(info):
|
||||
timesheet.update(info[0])
|
||||
return timesheets
|
||||
|
||||
@frappe.whitelist()
|
||||
|
Loading…
x
Reference in New Issue
Block a user