From 0bd9905291a66fbe2fc817bb97566b7c4e25bedc Mon Sep 17 00:00:00 2001 From: hemant10yadav Date: Mon, 2 Dec 2024 15:44:01 +0530 Subject: [PATCH 1/4] wip for super user --- commcare_connect/opportunity/tables.py | 30 +++++++++++++++++++ commcare_connect/opportunity/urls.py | 2 ++ commcare_connect/opportunity/views.py | 28 +++++++++++++++++ commcare_connect/templates/base.html | 4 +++ .../opportunity/all_opportunities_view.html | 20 +++++++++++++ 5 files changed, 84 insertions(+) create mode 100644 commcare_connect/templates/opportunity/all_opportunities_view.html diff --git a/commcare_connect/opportunity/tables.py b/commcare_connect/opportunity/tables.py index a856650f..c2ee0e21 100644 --- a/commcare_connect/opportunity/tables.py +++ b/commcare_connect/opportunity/tables.py @@ -6,6 +6,7 @@ from commcare_connect.opportunity.models import ( CatchmentArea, CompletedWork, + Opportunity, OpportunityAccess, Payment, PaymentInvoice, @@ -16,6 +17,12 @@ VisitValidationStatus, ) +TABLE_TEMPLATE = "django_tables2/bootstrap5.html" +RESPONSIVE_TABLE_AND_LIGHT_HEADER = { + "class": "table border table-responsive", + "thead": {"class": "table-light"}, +} + class OrgContextTable(tables.Table): def __init__(self, *args, **kwargs): @@ -470,3 +477,26 @@ def date_with_time_popup(table, date): date.strftime("%d %b, %Y"), date.strftime("%d %b %Y, %I:%M%p"), ) + + +class OpportunityTable(tables.Table): + name = columns.Column() + Organization = columns.Column() + start_date = columns.DateColumn() + end_date = columns.DateColumn() + active = columns.Column() + program = columns.Column() + + class Meta: + model = Opportunity + fields = ( + "name", + "organization", + "start_date", + "end_date", + "active", + "program", + ) + empty_text = "No visits submitted for review." + template_name = TABLE_TEMPLATE + attrs = RESPONSIVE_TABLE_AND_LIGHT_HEADER diff --git a/commcare_connect/opportunity/urls.py b/commcare_connect/opportunity/urls.py index 66b7a957..4390151f 100644 --- a/commcare_connect/opportunity/urls.py +++ b/commcare_connect/opportunity/urls.py @@ -2,6 +2,7 @@ from commcare_connect.opportunity import views from commcare_connect.opportunity.views import ( + AllOpportunitiesView, OpportunityCompletedWorkTable, OpportunityCreate, OpportunityDeliverStatusTable, @@ -54,6 +55,7 @@ app_name = "opportunity" urlpatterns = [ path("", view=OpportunityList.as_view(), name="list"), + path("all_opportunities", view=AllOpportunitiesView.as_view(), name="all_opportunities"), path("create/", view=OpportunityCreate.as_view(), name="create"), path("init/", view=OpportunityInit.as_view(), name="init"), path("/finalize/", view=OpportunityFinalize.as_view(), name="finalize"), diff --git a/commcare_connect/opportunity/views.py b/commcare_connect/opportunity/views.py index a53c0050..081ac0a0 100644 --- a/commcare_connect/opportunity/views.py +++ b/commcare_connect/opportunity/views.py @@ -73,6 +73,7 @@ DeliverStatusTable, LearnStatusTable, OpportunityPaymentTable, + OpportunityTable, PaymentInvoiceTable, PaymentReportTable, PaymentUnitTable, @@ -122,6 +123,11 @@ def test_func(self): ) or self.request.user.is_superuser +class SuperUserMixin(LoginRequiredMixin, UserPassesTestMixin): + def test_func(self): + return self.request.user.is_superuser + + def get_opportunity_or_404(pk, org_slug): opp = get_object_or_404(Opportunity, id=pk) @@ -164,6 +170,28 @@ def get_context_data(self, **kwargs): return context +class AllOpportunitiesView(SuperUserMixin, SingleTableView): + model = Opportunity + paginate_by = 15 + table_class = OpportunityTable + template_name = "opportunity/all_opportunities_view.html" + + def get_queryset(self): + ordering = self.request.GET.get("sort", "name") + if ordering not in [ + "name", + "-name", + "start_date", + "-start_date", + "end_date", + "-end_date", + "active", + "-active", + ]: + ordering = "name" + return Opportunity.objects.all().order_by(ordering) + + class OpportunityCreate(OrganizationUserMemberRoleMixin, CreateView): template_name = "opportunity/opportunity_create.html" form_class = OpportunityCreationForm diff --git a/commcare_connect/templates/base.html b/commcare_connect/templates/base.html index f417ddab..947c260b 100644 --- a/commcare_connect/templates/base.html +++ b/commcare_connect/templates/base.html @@ -65,6 +65,10 @@ {% translate "Opportunities" %} + {% endif %} {% endif %} diff --git a/commcare_connect/templates/opportunity/all_opportunities_view.html b/commcare_connect/templates/opportunity/all_opportunities_view.html new file mode 100644 index 00000000..05f696cf --- /dev/null +++ b/commcare_connect/templates/opportunity/all_opportunities_view.html @@ -0,0 +1,20 @@ +{% extends "base.html" %} +{% load static %} +{% load sort_link %} +{% load i18n %} +{% load django_tables2 %} + +{% block title %}{{ request.org }} - Opportunities{% endblock %} + +{% block content %} +
+
+
+

All Opportunities

+
+ {% render_table table %} +
+
+
+
+{% endblock content %} From f32c30607b9141adff493b601b585571d3554f7c Mon Sep 17 00:00:00 2001 From: hemant10yadav Date: Mon, 9 Dec 2024 11:36:40 +0530 Subject: [PATCH 2/4] refactor table --- commcare_connect/opportunity/views.py | 71 ++++++++++++------ commcare_connect/templates/base.html | 4 - .../opportunity/all_opportunities_view.html | 43 ++++++++--- .../opportunity/opportunity_list.html | 75 ++----------------- .../partial_opportunity_table.html | 74 ++++++++++++++++++ commcare_connect/templates/pagination.html | 72 ++++++++++++++---- 6 files changed, 223 insertions(+), 116 deletions(-) create mode 100644 commcare_connect/templates/opportunity/partial_opportunity_table.html diff --git a/commcare_connect/opportunity/views.py b/commcare_connect/opportunity/views.py index 081ac0a0..f69baaa5 100644 --- a/commcare_connect/opportunity/views.py +++ b/commcare_connect/opportunity/views.py @@ -12,6 +12,7 @@ from django.forms import modelformset_factory from django.http import FileResponse, Http404, HttpResponse from django.shortcuts import get_object_or_404, redirect, render +from django.template.loader import render_to_string from django.urls import reverse from django.utils.html import format_html from django.utils.safestring import mark_safe @@ -170,28 +171,6 @@ def get_context_data(self, **kwargs): return context -class AllOpportunitiesView(SuperUserMixin, SingleTableView): - model = Opportunity - paginate_by = 15 - table_class = OpportunityTable - template_name = "opportunity/all_opportunities_view.html" - - def get_queryset(self): - ordering = self.request.GET.get("sort", "name") - if ordering not in [ - "name", - "-name", - "start_date", - "-start_date", - "end_date", - "-end_date", - "active", - "-active", - ]: - ordering = "name" - return Opportunity.objects.all().order_by(ordering) - - class OpportunityCreate(OrganizationUserMemberRoleMixin, CreateView): template_name = "opportunity/opportunity_create.html" form_class = OpportunityCreationForm @@ -1250,3 +1229,51 @@ def invoice_approve(request, org_slug, pk): ) payment.save() return HttpResponse(headers={"HX-Trigger": "newInvoice"}) + + +class AllOpportunitiesView(SuperUserMixin, SingleTableView): + model = Opportunity + paginate_by = 10 + template_name = "opportunity/all_opportunities_view.html" + table_class = OpportunityTable + + def get_queryset(self): + search_query = self.request.GET.get("search", "") + status_filter = self.request.GET.get("status", "") + ordering = self.request.GET.get("sort", "name") + + valid_ordering = [ + "name", + "-name", + "start_date", + "-start_date", + "end_date", + "-end_date", + ] + + if ordering not in valid_ordering: + ordering = "name" + + opportunities = Opportunity.objects.all() + + if search_query: + opportunities = opportunities.filter(name__icontains=search_query) + + if status_filter: + if status_filter == "active": + opportunities = opportunities.filter(active=True, end_date__gte=now().date()) + elif status_filter == "inactive": + opportunities = opportunities.filter(end_date__lt=now().date()) + + return opportunities.order_by(ordering) + + def get_context_data(self, **kwargs): + context = super().get_context_data(**kwargs) + context["table"] = self.table_class(self.get_queryset()) + return context + + def render_to_response(self, context, **response_kwargs): + if self.request.htmx: + html = render_to_string("opportunity/partial_opportunity_table.html", context, request=self.request) + return HttpResponse(html) + return super().render_to_response(context, **response_kwargs) diff --git a/commcare_connect/templates/base.html b/commcare_connect/templates/base.html index 947c260b..f417ddab 100644 --- a/commcare_connect/templates/base.html +++ b/commcare_connect/templates/base.html @@ -65,10 +65,6 @@ {% translate "Opportunities" %} - {% endif %} {% endif %} diff --git a/commcare_connect/templates/opportunity/all_opportunities_view.html b/commcare_connect/templates/opportunity/all_opportunities_view.html index 05f696cf..89875d8a 100644 --- a/commcare_connect/templates/opportunity/all_opportunities_view.html +++ b/commcare_connect/templates/opportunity/all_opportunities_view.html @@ -1,20 +1,43 @@ -{% extends "base.html" %} +{% extends "opportunity/base.html" %} {% load static %} -{% load sort_link %} {% load i18n %} -{% load django_tables2 %} +{% block title %}{{ request.org }} - All Opportunities{% endblock %} -{% block title %}{{ request.org }} - Opportunities{% endblock %} +{% block breadcrumbs_inner %} + {{ block.super }} + +{% endblock %} {% block content %} -
-
-
+
+

All Opportunities

-
- {% render_table table %} +
+
+
+
+
+ +
+
+ +
+
+ +
+
+
+
+ {% include 'opportunity/partial_opportunity_table.html' %}
-
{% endblock content %} diff --git a/commcare_connect/templates/opportunity/opportunity_list.html b/commcare_connect/templates/opportunity/opportunity_list.html index 04be5a47..a373d88e 100644 --- a/commcare_connect/templates/opportunity/opportunity_list.html +++ b/commcare_connect/templates/opportunity/opportunity_list.html @@ -19,6 +19,13 @@

Opportunities + {% if request.user.is_superuser %} + + All-Org View + + {% endif %} {% if request.org_membership.is_viewer %}

- - - - - - - - - - - - - {% for opportunity in page_obj %} - - - - - - - - - - {% empty %} - - - - {% endfor %} - -
{% sort_link 'name' 'Name' %}{% sort_link 'start_date' 'Start Date' %}{% sort_link 'end_date' 'End Date' %}StatusProgramManage
{{ opportunity.name }}{{ opportunity.start_date|default:"Not Set" }}{{ opportunity.end_date|default:"Not Set" }} - {% if opportunity.is_setup_complete %} - {% if opportunity.is_active %} - Active - {% else %} - Inactive - {% endif %} - {% else %} - Pending Setup - {% endif %} - {% if opportunity.managed %} {{ opportunity.managedopportunity.program.name }} {% else %} - {% endif %} -
- -  View - - {% if request.org_membership.is_viewer %} - - {% if not opportunity.managed %} - - {% endif %} - {% else %} -  Edit - {% if not opportunity.managed %} -  Add Budget - - {% endif %} - {% endif %} -
-
{% translate "No opportunities yet." %}
+ {% include 'opportunity/partial_opportunity_table.html' %}
- {% include 'pagination.html' %}
{% if program_invitation_table and program_invitation_table.data %} diff --git a/commcare_connect/templates/opportunity/partial_opportunity_table.html b/commcare_connect/templates/opportunity/partial_opportunity_table.html new file mode 100644 index 00000000..3cc64ca4 --- /dev/null +++ b/commcare_connect/templates/opportunity/partial_opportunity_table.html @@ -0,0 +1,74 @@ +{% load sort_link %} +{% load django_tables2 %} +{% load i18n %} +
+ + + + + + + + + + + + + {% for opportunity in page_obj %} + + + + + + + + + + {% empty %} + + + + {% endfor %} + +
{% sort_link 'name' 'Name' %}{% sort_link 'start_date' 'Start Date' %}{% sort_link 'end_date' 'End Date' %}StatusProgramManage
{{ opportunity.name }}{{ opportunity.start_date|default:"Not Set" }}{{ opportunity.end_date|default:"Not Set" }} + {% if opportunity.is_setup_complete %} + {% if opportunity.is_active %} + Active + {% else %} + Inactive + {% endif %} + {% else %} + Pending Setup + {% endif %} + {% if opportunity.managed %} {{ opportunity.managedopportunity.program.name }} {% else %} - {% endif %} +
+ +  View + + {% if request.org_membership.is_viewer %} + + {% if not opportunity.managed %} + + {% endif %} + {% else %} +  Edit + {% if not opportunity.managed %} +  Add Budget + + {% endif %} + {% endif %} +
+
{% translate "No opportunities yet." %}
+
+ {% include 'pagination.html' %} +
+
diff --git a/commcare_connect/templates/pagination.html b/commcare_connect/templates/pagination.html index 0d0a1c8e..8684cc1d 100644 --- a/commcare_connect/templates/pagination.html +++ b/commcare_connect/templates/pagination.html @@ -16,21 +16,67 @@ {% endif %} - {% for page_number in page_obj.paginator.page_range %} - {% if page_obj.number == page_number %} -
  • - - {{ page_number }} - -
  • + {% with total_pages=page_obj.paginator.num_pages current_page=page_obj.number %} + {% if total_pages > 10 %} + {# First page #} + {% if current_page > 4 %} +
  • + 1 +
  • +
  • + ... +
  • + {% endif %} + + {# Intelligent page range #} + {% with start=current_page|add:"-2" end=current_page|add:"2" %} + {% for page_number in page_obj.paginator.page_range %} + {% if page_number >= start and page_number <= end %} + {% if current_page == page_number %} +
  • + {{ page_number }} +
  • + {% else %} +
  • + + {{ page_number }} + +
  • + {% endif %} + {% endif %} + {% endfor %} + {% endwith %} + + {# Last page #} + {% if current_page < total_pages|add:"-3" %} +
  • + ... +
  • +
  • + + {{ total_pages }} + +
  • + {% endif %} + {% else %} -
  • - - {{ page_number }} - -
  • + {# If total pages are 10 or less, show all pages normally #} + {% for page_number in page_obj.paginator.page_range %} + {% if page_obj.number == page_number %} +
  • + {{ page_number }} +
  • + {% else %} +
  • + + {{ page_number }} + +
  • + {% endif %} + {% endfor %} {% endif %} - {% endfor %} + {% endwith %} + {% if page_obj.has_next %}
  • From b0e89e9142173609de12885d17676022379becf0 Mon Sep 17 00:00:00 2001 From: hemant10yadav Date: Mon, 9 Dec 2024 16:26:13 +0530 Subject: [PATCH 3/4] fixed ui --- .../opportunity/all_opportunities_view.html | 39 ++++++++++++------- .../opportunity/opportunity_list.html | 2 +- 2 files changed, 25 insertions(+), 16 deletions(-) diff --git a/commcare_connect/templates/opportunity/all_opportunities_view.html b/commcare_connect/templates/opportunity/all_opportunities_view.html index 89875d8a..38d4e398 100644 --- a/commcare_connect/templates/opportunity/all_opportunities_view.html +++ b/commcare_connect/templates/opportunity/all_opportunities_view.html @@ -5,7 +5,7 @@ {% block breadcrumbs_inner %} {{ block.super }} -
  • + {% endblock %} {% block content %} @@ -19,20 +19,29 @@

    All Opportunities

    hx-target="#opportunity-table" hx-push-url="true" class="mb-3"> -
    -
    - -
    -
    - -
    -
    - -
    +
    +
    + +
    +
    + +
    +
    + +
    diff --git a/commcare_connect/templates/opportunity/opportunity_list.html b/commcare_connect/templates/opportunity/opportunity_list.html index a373d88e..93a8fc57 100644 --- a/commcare_connect/templates/opportunity/opportunity_list.html +++ b/commcare_connect/templates/opportunity/opportunity_list.html @@ -23,7 +23,7 @@

    Opportunities - All-Org View + All Opportunities {% endif %} {% if request.org_membership.is_viewer %} From e03bdd15814270f5d4a43de8d28c72e726e24476 Mon Sep 17 00:00:00 2001 From: hemant10yadav Date: Mon, 9 Dec 2024 16:31:27 +0530 Subject: [PATCH 4/4] removed table class --- commcare_connect/opportunity/tables.py | 30 ------------------- commcare_connect/opportunity/views.py | 6 ++-- .../opportunity/all_opportunities_view.html | 2 +- 3 files changed, 3 insertions(+), 35 deletions(-) diff --git a/commcare_connect/opportunity/tables.py b/commcare_connect/opportunity/tables.py index c2ee0e21..a856650f 100644 --- a/commcare_connect/opportunity/tables.py +++ b/commcare_connect/opportunity/tables.py @@ -6,7 +6,6 @@ from commcare_connect.opportunity.models import ( CatchmentArea, CompletedWork, - Opportunity, OpportunityAccess, Payment, PaymentInvoice, @@ -17,12 +16,6 @@ VisitValidationStatus, ) -TABLE_TEMPLATE = "django_tables2/bootstrap5.html" -RESPONSIVE_TABLE_AND_LIGHT_HEADER = { - "class": "table border table-responsive", - "thead": {"class": "table-light"}, -} - class OrgContextTable(tables.Table): def __init__(self, *args, **kwargs): @@ -477,26 +470,3 @@ def date_with_time_popup(table, date): date.strftime("%d %b, %Y"), date.strftime("%d %b %Y, %I:%M%p"), ) - - -class OpportunityTable(tables.Table): - name = columns.Column() - Organization = columns.Column() - start_date = columns.DateColumn() - end_date = columns.DateColumn() - active = columns.Column() - program = columns.Column() - - class Meta: - model = Opportunity - fields = ( - "name", - "organization", - "start_date", - "end_date", - "active", - "program", - ) - empty_text = "No visits submitted for review." - template_name = TABLE_TEMPLATE - attrs = RESPONSIVE_TABLE_AND_LIGHT_HEADER diff --git a/commcare_connect/opportunity/views.py b/commcare_connect/opportunity/views.py index f69baaa5..2d0bd441 100644 --- a/commcare_connect/opportunity/views.py +++ b/commcare_connect/opportunity/views.py @@ -74,7 +74,6 @@ DeliverStatusTable, LearnStatusTable, OpportunityPaymentTable, - OpportunityTable, PaymentInvoiceTable, PaymentReportTable, PaymentUnitTable, @@ -1231,11 +1230,10 @@ def invoice_approve(request, org_slug, pk): return HttpResponse(headers={"HX-Trigger": "newInvoice"}) -class AllOpportunitiesView(SuperUserMixin, SingleTableView): +class AllOpportunitiesView(SuperUserMixin, ListView): model = Opportunity paginate_by = 10 template_name = "opportunity/all_opportunities_view.html" - table_class = OpportunityTable def get_queryset(self): search_query = self.request.GET.get("search", "") @@ -1269,7 +1267,7 @@ def get_queryset(self): def get_context_data(self, **kwargs): context = super().get_context_data(**kwargs) - context["table"] = self.table_class(self.get_queryset()) + context["table"] = self.get_queryset() return context def render_to_response(self, context, **response_kwargs): diff --git a/commcare_connect/templates/opportunity/all_opportunities_view.html b/commcare_connect/templates/opportunity/all_opportunities_view.html index 38d4e398..db9428e7 100644 --- a/commcare_connect/templates/opportunity/all_opportunities_view.html +++ b/commcare_connect/templates/opportunity/all_opportunities_view.html @@ -30,7 +30,7 @@

    All Opportunities