diff --git a/hypha/apply/dashboard/services.py b/hypha/apply/dashboard/services.py new file mode 100644 index 0000000000..7f9ad5bfca --- /dev/null +++ b/hypha/apply/dashboard/services.py @@ -0,0 +1,28 @@ +from django.db.models import Count + +from hypha.apply.projects.models import PAFApprovals + + +def get_paf_for_review(user, is_paf_approval_sequential): + """Return a list of paf approvals ready for user's review""" + + paf_approvals = PAFApprovals.objects.annotate( + roles_count=Count("paf_reviewer_role__user_roles") + ).filter( + roles_count=len(list(user.groups.all())), + approved=False, + ) + + for role in user.groups.all(): + paf_approvals = paf_approvals.filter(paf_reviewer_role__user_roles__id=role.id) + + if is_paf_approval_sequential: + all_matched_paf_approvals = list(paf_approvals) + for matched_paf_approval in all_matched_paf_approvals: + if matched_paf_approval.project.paf_approvals.filter( + paf_reviewer_role__sort_order__lt=matched_paf_approval.paf_reviewer_role.sort_order, + approved=False, + ).exists(): + paf_approvals = paf_approvals.exclude(id=matched_paf_approval.id) + + return paf_approvals diff --git a/hypha/apply/dashboard/templates/dashboard/contracting_dashboard.html b/hypha/apply/dashboard/templates/dashboard/contracting_dashboard.html index a382b38822..4de5c99286 100644 --- a/hypha/apply/dashboard/templates/dashboard/contracting_dashboard.html +++ b/hypha/apply/dashboard/templates/dashboard/contracting_dashboard.html @@ -15,14 +15,11 @@ {% endadminbar %} <div class="wrapper wrapper--large wrapper--inner-space-medium"> - {% if paf_waiting_for_approval.count %} - {% include "dashboard/includes/paf_waiting_for_approval.html" with paf_waiting_for_approval=paf_waiting_for_approval %} - {% endif %} - {% if paf_waiting_for_assignment.count %} - <div id="paf_waiting_for_assignment" class="wrapper wrapper--bottom-space"> - <h4 class="heading heading--normal">{% trans "PAF waiting for assignee" %}</h4> - {% render_table paf_waiting_for_assignment.table %} + {% if paf_for_review.count %} + <div id="paf_for_review" class="wrapper wrapper--bottom-space"> + <h4 class="heading heading--normal">{% trans "PAFs for review" %}</h4> + {% render_table paf_for_review.table %} </div> {% endif %} diff --git a/hypha/apply/dashboard/templates/dashboard/dashboard.html b/hypha/apply/dashboard/templates/dashboard/dashboard.html index 006d7812ef..ebabadbccb 100644 --- a/hypha/apply/dashboard/templates/dashboard/dashboard.html +++ b/hypha/apply/dashboard/templates/dashboard/dashboard.html @@ -39,15 +39,6 @@ <div class="stat-block__view">{% trans "View" %}</div> {% endif %} </a> - {% if not paf_waiting_for_approval.count is None%} - <a href="#paf-awaiting-approval" class="stat-block__item border"> - <p class="stat-block__number">{{ paf_waiting_for_approval.count }}</p> - <p class="stat-block__text">{% trans "Projects awaiting approval" %}</p> - {% if paf_waiting_for_approval.count %} - <div class="stat-block__view">{% trans "View" %}</div> - {% endif %} - </a> - {% endif %} <a href="#active-invoices" class="stat-block__item border"> <p class="stat-block__number">{{ active_invoices.count }}</p> <p class="stat-block__text">{% trans "Requests for invoices requiring your attention" %}</p> @@ -72,14 +63,10 @@ {% include "funds/includes/round-block.html" with can_export=can_export closed_rounds=rounds.closed open_rounds=rounds.open title="Your rounds and labs" page_type='dashboard' %} {% endif %} - {% if paf_waiting_for_approval.count %} - {% include "dashboard/includes/paf_waiting_for_approval.html" with paf_waiting_for_approval=paf_waiting_for_approval %} - {% endif %} - - {% if paf_waiting_for_assignment.count %} - <div id="paf_waiting_for_assignment" class="wrapper wrapper--bottom-space"> - <h4 class="heading heading--normal">{% trans "PAF waiting for assignee" %}</h4> - {% render_table paf_waiting_for_assignment.table %} + {% if paf_for_review.count %} + <div id="paf_for_review" class="wrapper wrapper--bottom-space"> + <h4 class="heading heading--normal">{% trans "PAFs for review" %}</h4> + {% render_table paf_for_review.table %} </div> {% endif %} @@ -125,6 +112,7 @@ <h4 class="heading heading--normal">{% trans "Active Invoices" %}</h4> {% block extra_js %} {{ my_reviewed.filterset.form.media.js }} <script src="{% static 'js/apply/url-search-params.js' %}"></script> + <script src="{% static 'js/apply/all-submissions-table.js' %}"></script> <script src="{% static 'js/apply/submission-filters.js' %}"></script> <script src="{% static 'js/apply/tabs.js' %}"></script> <script src="{% static 'js/apply/flag.js' %}"></script> diff --git a/hypha/apply/dashboard/templates/dashboard/finance_dashboard.html b/hypha/apply/dashboard/templates/dashboard/finance_dashboard.html index 2b0e6f9a5d..bf0d29a73a 100644 --- a/hypha/apply/dashboard/templates/dashboard/finance_dashboard.html +++ b/hypha/apply/dashboard/templates/dashboard/finance_dashboard.html @@ -84,16 +84,13 @@ <h4 class="heading heading--normal heading--no-margin">{% trans 'Invoices' %} </ </div> - {% if paf_waiting_for_approval.count %} - {% include "dashboard/includes/paf_waiting_for_approval.html" with paf_waiting_for_approval=paf_waiting_for_approval %} - {% endif %} - - {% if paf_waiting_for_assignment.count %} - <div id="paf_waiting_for_assignment" class="wrapper wrapper--bottom-space"> - <h4 class="heading heading--normal">{% trans "PAF waiting for assignee" %}</h4> - {% render_table paf_waiting_for_assignment.table %} + {% if paf_for_review.count %} + <div id="paf_for_review" class="wrapper wrapper--bottom-space"> + <h4 class="heading heading--normal">{% trans "PAFs for review" %}</h4> + {% render_table paf_for_review.table %} </div> {% endif %} + </div> {% endblock %} diff --git a/hypha/apply/dashboard/templates/dashboard/includes/paf_waiting_for_approval.html b/hypha/apply/dashboard/templates/dashboard/includes/paf_waiting_for_approval.html deleted file mode 100644 index 0fdfcaa1a5..0000000000 --- a/hypha/apply/dashboard/templates/dashboard/includes/paf_waiting_for_approval.html +++ /dev/null @@ -1,48 +0,0 @@ -{% load render_table from django_tables2 %} -{% load i18n %} - -<div id="paf-awaiting-approval" class="wrapper wrapper--bottom-space" x-data="{ tab: '{% trans "Awaiting your approval" %}' }"> - <section class="section section--with-options"> - <h2 class="text-xl mb-2"> - {% trans 'PAF waiting for internal approval' %} - </h2> - <nav> - <a class="tab__item tab__item--alt" - role="tab" - href="#" - id="tab-paf-awaiting" - aria-controls="panel-paf-awaiting" - :class="{ 'tab__item--active': tab === '{% trans "Awaiting your approval" %}' }" - @click.prevent="tab = '{% trans "Awaiting your approval" %}'" - >{% trans "Awaiting your approval" %}</a> - <a class="tab__item tab__item--alt" - role="tab" - href="#" - id="tab-paf-approved" - aria-controls="panel-paf-approved" - :class="{ 'tab__item--active': tab === '{% trans "Approved by you" %}' }" - @click.prevent="tab = '{% trans "Approved by you" %}'" - >{% trans "Approved by you" %}</a> - </nav> - </section> - - <div x-show="tab === '{% trans "Awaiting your approval" %}'" role="tabpanel" tabindex="0" aria-labelledby="tab-paf-awaiting" id="panel-paf-awaiting"> - {% if paf_waiting_for_approval.awaiting_your_approval.count %} - {% render_table paf_waiting_for_approval.awaiting_your_approval.table %} - {% else %} - <div class="border px-2 py-4"> - {% trans "You have approved all PAFs, no PAF is waiting for your Approval " %} - </div> - {% endif %} - </div> - <div x-show="tab === '{% trans "Approved by you" %}'" role="tabpanel" tabindex="0" aria-labelledby="tab-paf-approved" id="panel-paf-approved"> - {% if paf_waiting_for_approval.approved_by_you.count %} - {% render_table paf_waiting_for_approval.approved_by_you.table %} - {% else %} - <div class="border px-2 py-4"> - {% trans "No PAF is approved by you yet " %} - </div> - {% endif %} - </div> - -</div> diff --git a/hypha/apply/dashboard/templates/dashboard/reviewer_dashboard.html b/hypha/apply/dashboard/templates/dashboard/reviewer_dashboard.html index 1d6d0c05b6..444531c537 100644 --- a/hypha/apply/dashboard/templates/dashboard/reviewer_dashboard.html +++ b/hypha/apply/dashboard/templates/dashboard/reviewer_dashboard.html @@ -69,15 +69,6 @@ <h6 class="heading heading--no-margin heading--submission-meta"><span>{% trans " </div> {% endif %} - {% if paf_waiting_for_assignment.count %} - <div id="paf_waiting_for_assignment" class="wrapper wrapper--bottom-space"> - <h2 class="text-xl mb-2"> - {% trans "PAF waiting for assignee" %} - </h2> - {% render_table paf_waiting_for_assignment.table %} - </div> - {% endif %} - {% if my_inactive_submissions.data %} <div class="wrapper wrapper--bottom-space"> <h2 class="text-xl mb-2"> diff --git a/hypha/apply/dashboard/views.py b/hypha/apply/dashboard/views.py index 41823412a5..ed90d5547d 100644 --- a/hypha/apply/dashboard/views.py +++ b/hypha/apply/dashboard/views.py @@ -1,9 +1,9 @@ from django.conf import settings -from django.db.models import Count from django.http import HttpResponseForbidden, HttpResponseRedirect from django.shortcuts import render from django.urls import reverse, reverse_lazy from django.views.generic import TemplateView +from django_tables2 import RequestConfig from hypha.apply.funds.models import ( ApplicationSubmission, @@ -21,17 +21,17 @@ review_filter_for_user, ) from hypha.apply.projects.filters import ProjectListFilter -from hypha.apply.projects.models import Invoice, PAFApprovals, Project, ProjectSettings +from hypha.apply.projects.models import Invoice, Project, ProjectSettings from hypha.apply.projects.models.payment import DECLINED, PAID -from hypha.apply.projects.models.project import INTERNAL_APPROVAL -from hypha.apply.projects.permissions import has_permission from hypha.apply.projects.tables import ( InvoiceDashboardTable, - ProjectsAssigneeDashboardTable, + PAFForReviewDashboardTable, ProjectsDashboardTable, ) from hypha.apply.utils.views import ViewDispatcher +from .services import get_paf_for_review + class MySubmissionContextMixin: def get_context_data(self, **kwargs): @@ -91,15 +91,33 @@ def get_context_data(self, **kwargs): "can_export": can_export_submissions(self.request.user), "my_reviewed": self.my_reviewed(submissions), "projects": self.projects(), - "paf_waiting_for_approval": self.paf_waiting_for_approval(), "rounds": self.rounds(), "my_flagged": self.my_flagged(submissions), - "paf_waiting_for_assignment": self.paf_waiting_for_approver_assignment(), + "paf_for_review": self.paf_for_review(), } ) return context + def paf_for_review(self): + if not self.request.user.is_apply_staff: + return {"count": None, "table": None} + project_settings = ProjectSettings.for_request(self.request) + + paf_approvals = get_paf_for_review( + user=self.request.user, + is_paf_approval_sequential=project_settings.paf_approval_sequential, + ) + paf_table = PAFForReviewDashboardTable( + paf_approvals, prefix="paf-review-", order_by="-date_requested" + ) + RequestConfig(self.request, paginate=False).configure(paf_table) + + return { + "count": paf_approvals.count(), + "table": paf_table, + } + def awaiting_reviews(self, submissions): submissions = submissions.in_review_for(self.request.user).order_by( "-submit_time" @@ -146,104 +164,6 @@ def projects(self): "url": reverse("apply:projects:all"), } - def paf_waiting_for_approver_assignment(self): - project_settings = ProjectSettings.for_request(self.request) - - paf_approvals = PAFApprovals.objects.annotate( - roles_count=Count("paf_reviewer_role__user_roles") - ).filter( - roles_count=len(list(self.request.user.groups.all())), - approved=False, - user__isnull=True, - ) - - for role in self.request.user.groups.all(): - paf_approvals = paf_approvals.filter( - paf_reviewer_role__user_roles__id=role.id - ) - - paf_approvals_ids = paf_approvals.values_list("id", flat=True) - projects = Project.objects.filter( - paf_approvals__id__in=paf_approvals_ids - ).for_table() - - if project_settings.paf_approval_sequential: - all_projects = list(projects) - for project in all_projects: - matched_paf_approval = ( - paf_approvals.filter(project=project) - .order_by("paf_reviewer_role__sort_order") - .first() - ) - if project.paf_approvals.filter( - paf_reviewer_role__sort_order__lt=matched_paf_approval.paf_reviewer_role.sort_order, - approved=False, - ).exists(): - projects = projects.exclude(id=project.id) - - return { - "count": projects.count(), - "table": ProjectsAssigneeDashboardTable(projects), - } - - def paf_waiting_for_approval(self): - if ( - not self.request.user.is_apply_staff - or not PAFApprovals.objects.filter( - project__status=INTERNAL_APPROVAL, - user=self.request.user, - ).exists() - ): - return { - "count": None, - "awaiting_your_approval": { - "count": None, - "table": None, - }, - "approved_by_you": { - "count": None, - "table": None, - }, - } - - waiting_paf_approval = Project.objects.internal_approval().for_table() - project_settings = ProjectSettings.for_request(self.request) - if project_settings.paf_approval_sequential: - awaiting_user_approval = [] - for waiting_project in waiting_paf_approval.filter( - paf_approvals__approved=False - ): - permission, _ = has_permission( - "paf_status_update", - self.request.user, - object=waiting_project, - raise_exception=False, - request=self.request, - ) - if permission: - awaiting_user_approval.append(waiting_project) - else: - awaiting_user_approval = waiting_paf_approval.filter( - paf_approvals__user=self.request.user, - paf_approvals__approved=False, - ) - approved_by_user = waiting_paf_approval.filter( - paf_approvals__user=self.request.user, - paf_approvals__approved=True, - ) - - return { - "count": len(awaiting_user_approval) + len(approved_by_user), - "awaiting_your_approval": { - "count": len(awaiting_user_approval), - "table": ProjectsDashboardTable(data=awaiting_user_approval), - }, - "approved_by_you": { - "count": len(approved_by_user), - "table": ProjectsDashboardTable(data=approved_by_user), - }, - } - def my_reviewed(self, submissions): """Staff reviewer's reviewed submissions for 'Previous reviews' block""" submissions = submissions.reviewed_by(self.request.user).order_by( @@ -289,13 +209,27 @@ def get_context_data(self, **kwargs): "active_invoices": self.active_invoices(), "invoices_for_approval": self.invoices_for_approval(), "invoices_to_convert": self.invoices_to_convert(), - "paf_waiting_for_approval": self.paf_waiting_for_approval(), - "paf_waiting_for_assignment": self.paf_waiting_for_approver_assignment(), + "paf_for_review": self.paf_for_review(), } ) return context + def paf_for_review(self): + if not self.request.user.is_finance: + return {"count": None, "table": None} + project_settings = ProjectSettings.for_request(self.request) + + paf_approvals = get_paf_for_review( + user=self.request.user, + is_paf_approval_sequential=project_settings.paf_approval_sequential, + ) + + return { + "count": paf_approvals.count(), + "table": PAFForReviewDashboardTable(paf_approvals), + } + def active_invoices(self): if self.request.user.is_finance_level_2: invoices = Invoice.objects.for_finance_2() @@ -307,46 +241,6 @@ def active_invoices(self): "table": InvoiceDashboardTable(invoices), } - def paf_waiting_for_approver_assignment(self): - project_settings = ProjectSettings.for_request(self.request) - - paf_approvals = PAFApprovals.objects.annotate( - roles_count=Count("paf_reviewer_role__user_roles") - ).filter( - roles_count=len(list(self.request.user.groups.all())), - approved=False, - user__isnull=True, - ) - - for role in self.request.user.groups.all(): - paf_approvals = paf_approvals.filter( - paf_reviewer_role__user_roles__id=role.id - ) - - paf_approvals_ids = paf_approvals.values_list("id", flat=True) - projects = Project.objects.filter( - paf_approvals__id__in=paf_approvals_ids - ).for_table() - - if project_settings.paf_approval_sequential: - all_projects = list(projects) - for project in all_projects: - matched_paf_approval = ( - paf_approvals.filter(project=project) - .order_by("paf_reviewer_role__sort_order") - .first() - ) - if project.paf_approvals.filter( - paf_reviewer_role__sort_order__lt=matched_paf_approval.paf_reviewer_role.sort_order, - approved=False, - ).exists(): - projects = projects.exclude(id=project.id) - - return { - "count": projects.count(), - "table": ProjectsAssigneeDashboardTable(projects), - } - def invoices_for_approval(self): if self.request.user.is_finance_level_2: invoices = Invoice.objects.approved_by_finance_1() @@ -367,64 +261,6 @@ def invoices_to_convert(self): "table": InvoiceDashboardTable(invoices), } - def paf_waiting_for_approval(self): - if ( - not self.request.user.is_finance - or not PAFApprovals.objects.filter( - project__status=INTERNAL_APPROVAL, - user=self.request.user, - ).exists() - ): - return { - "count": None, - "awaiting_your_approval": { - "count": None, - "table": None, - }, - "approved_by_you": { - "count": None, - "table": None, - }, - } - - waiting_paf_approval = Project.objects.internal_approval().for_table() - project_settings = ProjectSettings.for_request(self.request) - if project_settings.paf_approval_sequential: - awaiting_user_approval = [] - for waiting_project in waiting_paf_approval.filter( - paf_approvals__approved=False - ): - permission, _ = has_permission( - "paf_status_update", - self.request.user, - object=waiting_project, - raise_exception=False, - request=self.request, - ) - if permission: - awaiting_user_approval.append(waiting_project) - else: - awaiting_user_approval = waiting_paf_approval.filter( - paf_approvals__user=self.request.user, - paf_approvals__approved=False, - ) - approved_by_user = waiting_paf_approval.filter( - paf_approvals__user=self.request.user, - paf_approvals__approved=True, - ) - - return { - "count": len(awaiting_user_approval) + len(approved_by_user), - "awaiting_your_approval": { - "count": len(awaiting_user_approval), - "table": ProjectsDashboardTable(data=awaiting_user_approval), - }, - "approved_by_you": { - "count": len(approved_by_user), - "table": ProjectsDashboardTable(data=approved_by_user), - }, - } - class ReviewerDashboardView(MyFlaggedMixin, MySubmissionContextMixin, TemplateView): template_name = "dashboard/reviewer_dashboard.html" @@ -464,7 +300,6 @@ def get_context_data(self, **kwargs): "awaiting_reviews": self.awaiting_reviews(submissions), "my_reviewed": self.my_reviewed(submissions), "my_flagged": self.my_flagged(submissions), - "paf_waiting_for_assignment": self.paf_waiting_for_approver_assignment(), } ) @@ -487,46 +322,6 @@ def awaiting_reviews(self, submissions): "table": ReviewerSubmissionsTable(submissions[:limit], prefix="my-review-"), } - def paf_waiting_for_approver_assignment(self): - project_settings = ProjectSettings.for_request(self.request) - - paf_approvals = PAFApprovals.objects.annotate( - roles_count=Count("paf_reviewer_role__user_roles") - ).filter( - roles_count=len(list(self.request.user.groups.all())), - approved=False, - user__isnull=True, - ) - - for role in self.request.user.groups.all(): - paf_approvals = paf_approvals.filter( - paf_reviewer_role__user_roles__id=role.id - ) - - paf_approvals_ids = paf_approvals.values_list("id", flat=True) - projects = Project.objects.filter( - paf_approvals__id__in=paf_approvals_ids - ).for_table() - - if project_settings.paf_approval_sequential: - all_projects = list(projects) - for project in all_projects: - matched_paf_approval = ( - paf_approvals.filter(project=project) - .order_by("paf_reviewer_role__sort_order") - .first() - ) - if project.paf_approvals.filter( - paf_reviewer_role__sort_order__lt=matched_paf_approval.paf_reviewer_role.sort_order, - approved=False, - ).exists(): - projects = projects.exclude(id=project.id) - - return { - "count": projects.count(), - "table": ProjectsAssigneeDashboardTable(projects), - } - def my_reviewed(self, submissions): """Staff reviewer's reviewed submissions for 'Previous reviews' block""" submissions = submissions.reviewed_by(self.request.user).order_by( @@ -583,110 +378,26 @@ def get_context_data(self, **kwargs): context = super().get_context_data(**kwargs) context.update( { - "paf_waiting_for_approval": self.paf_waiting_for_approval(), "projects_in_contracting": self.projects_in_contracting(), - "paf_waiting_for_assignment": self.paf_waiting_for_approver_assignment(), + "paf_for_review": self.paf_for_review(), } ) return context - def paf_waiting_for_approval(self): - if ( - not self.request.user.is_contracting - or not PAFApprovals.objects.filter( - project__status=INTERNAL_APPROVAL, - user=self.request.user, - ).exists() - ): - return { - "count": None, - "awaiting_your_approval": { - "count": None, - "table": None, - }, - "approved_by_you": { - "count": None, - "table": None, - }, - } - - waiting_paf_approval = Project.objects.internal_approval().for_table() - project_settings = ProjectSettings.for_request(self.request) - if project_settings.paf_approval_sequential: - awaiting_user_approval = [] - for waiting_project in waiting_paf_approval.filter( - paf_approvals__approved=False - ): - permission, _ = has_permission( - "paf_status_update", - self.request.user, - object=waiting_project, - raise_exception=False, - request=self.request, - ) - if permission: - awaiting_user_approval.append(waiting_project) - else: - awaiting_user_approval = waiting_paf_approval.filter( - paf_approvals__user=self.request.user, - paf_approvals__approved=False, - ) - approved_by_user = waiting_paf_approval.filter( - paf_approvals__user=self.request.user, - paf_approvals__approved=True, - ) - - return { - "count": len(awaiting_user_approval) + len(approved_by_user), - "awaiting_your_approval": { - "count": len(awaiting_user_approval), - "table": ProjectsDashboardTable(data=awaiting_user_approval), - }, - "approved_by_you": { - "count": len(approved_by_user), - "table": ProjectsDashboardTable(data=approved_by_user), - }, - } - - def paf_waiting_for_approver_assignment(self): + def paf_for_review(self): + if not self.request.user.is_contracting: + return {"count": None, "table": None} project_settings = ProjectSettings.for_request(self.request) - paf_approvals = PAFApprovals.objects.annotate( - roles_count=Count("paf_reviewer_role__user_roles") - ).filter( - roles_count=len(list(self.request.user.groups.all())), - approved=False, - user__isnull=True, + paf_approvals = get_paf_for_review( + user=self.request.user, + is_paf_approval_sequential=project_settings.paf_approval_sequential, ) - for role in self.request.user.groups.all(): - paf_approvals = paf_approvals.filter( - paf_reviewer_role__user_roles__id=role.id - ) - - paf_approvals_ids = paf_approvals.values_list("id", flat=True) - projects = Project.objects.filter( - paf_approvals__id__in=paf_approvals_ids - ).for_table() - - if project_settings.paf_approval_sequential: - all_projects = list(projects) - for project in all_projects: - matched_paf_approval = ( - paf_approvals.filter(project=project) - .order_by("paf_reviewer_role__sort_order") - .first() - ) - if project.paf_approvals.filter( - paf_reviewer_role__sort_order__lt=matched_paf_approval.paf_reviewer_role.sort_order, - approved=False, - ).exists(): - projects = projects.exclude(id=project.id) - return { - "count": projects.count(), - "table": ProjectsAssigneeDashboardTable(projects), + "count": paf_approvals.count(), + "table": PAFForReviewDashboardTable(paf_approvals), } def projects_in_contracting(self): diff --git a/hypha/apply/projects/tables.py b/hypha/apply/projects/tables.py index 117d6db83b..6865c163b1 100644 --- a/hypha/apply/projects/tables.py +++ b/hypha/apply/projects/tables.py @@ -4,7 +4,7 @@ from django.utils.safestring import mark_safe from django.utils.translation import gettext_lazy as _ -from .models import Invoice, Project, Report +from .models import Invoice, PAFApprovals, Project, Report class BaseInvoiceTable(tables.Table): @@ -124,6 +124,50 @@ class Meta: attrs = {"class": "projects-table"} +class PAFForReviewDashboardTable(tables.Table): + date_requested = tables.DateColumn( + verbose_name=_("Date requested"), + accessor="created_at", + orderable=True, + ) + title = tables.LinkColumn( + "funds:projects:detail", + text=lambda r: textwrap.shorten(r.project.title, width=30, placeholder="..."), + accessor="project__title", + args=[tables.utils.A("project__pk")], + orderable=False, + ) + status = tables.Column(verbose_name=_("Status"), accessor="pk", orderable=False) + fund = tables.Column( + verbose_name=_("Fund"), accessor="project__submission__page", orderable=False + ) + + assignee = tables.Column( + verbose_name=_("Assignee"), accessor="user", orderable=False + ) + + class Meta: + fields = ["date_requested", "title", "fund", "status", "assignee"] + model = PAFApprovals + template_name = ( + "funds/tables/table.html" # todo: update it with Project table template + ) + attrs = {"class": "paf-review-table"} + + def order_date_requested(self, qs, is_descending): + direction = "-" if is_descending else "" + + qs = qs.order_by(f"{direction}created_at") + + return qs, True + + def render_status(self, record): + if record.user: + return _("Waiting for approval") + else: + return _("Waiting for assignee") + + class ProjectsListTable(BaseProjectsTable): class Meta: fields = [ diff --git a/hypha/static_src/src/sass/apply/components/_dashboard-table.scss b/hypha/static_src/src/sass/apply/components/_dashboard-table.scss new file mode 100644 index 0000000000..1a63c5334f --- /dev/null +++ b/hypha/static_src/src/sass/apply/components/_dashboard-table.scss @@ -0,0 +1,52 @@ +// stylelint-disable selector-max-compound-selectors + +.paf-review-table { + @include table-ordering-styles; + + thead { + display: none; + + @include media-query($table-breakpoint) { + display: table-header-group; + } + + th { + // ordering - adjust alignment + &.desc { + position: relative; + color: $color--dark-grey; + + &::after { + position: absolute; + top: 40%; + margin-left: 5px; + } + } + + &.asc { + position: relative; + color: $color--dark-grey; + + &::after { + position: absolute; + top: 50%; + margin-left: 5px; + } + } + } + } + + tbody { + td { + // stylelint-disable-next-line force-element-nesting + > span.mobile-label { + display: inline-block; + width: 90px; + + @include media-query($table-breakpoint) { + display: none; + } + } + } + } +} diff --git a/hypha/static_src/src/sass/apply/main.scss b/hypha/static_src/src/sass/apply/main.scss index 40ed6f1c79..ab9dae30ed 100644 --- a/hypha/static_src/src/sass/apply/main.scss +++ b/hypha/static_src/src/sass/apply/main.scss @@ -71,6 +71,7 @@ @import "components/activity-notifications"; @import "components/dropdown"; @import "components/banner"; +@import "components/dashboard-table"; // Layout @import "layout/header"; diff --git a/hypha/static_src/src/sass/apply/styleguide.scss b/hypha/static_src/src/sass/apply/styleguide.scss index 6667c9202f..5499fb5d17 100644 --- a/hypha/static_src/src/sass/apply/styleguide.scss +++ b/hypha/static_src/src/sass/apply/styleguide.scss @@ -65,6 +65,7 @@ @import "components/two-factor"; @import "components/determination"; @import "components/dropdown"; +@import "components/dashboard-table"; // Layout @import "layout/header";