diff --git a/apps/odk_publish/nav.py b/apps/odk_publish/nav.py index 7e2d5f1..d930fcd 100644 --- a/apps/odk_publish/nav.py +++ b/apps/odk_publish/nav.py @@ -8,7 +8,7 @@ class Link(BaseModel): label: str viewname: str - args: list[int | str] = None + args: list[int | str] | None = None namespace: str = "odk_publish" def __str__(self): diff --git a/apps/odk_publish/tables.py b/apps/odk_publish/tables.py index 48ee3c9..aa7454a 100644 --- a/apps/odk_publish/tables.py +++ b/apps/odk_publish/tables.py @@ -14,11 +14,11 @@ class FormTemplateTable(tables.Table): verbose_name="Latest Version", ) publish_next_version = tables.LinkColumn( - "odk_publish:form-template-publish-next-version", + "odk_publish:form-template-detail", args=[tables.A("project_id"), tables.A("pk")], - text="Publish New Version", + text="View", orderable=False, - verbose_name="Actions", + verbose_name="", attrs={"a": {"class": "text-primary-600 hover:underline"}}, ) @@ -26,5 +26,5 @@ class Meta: model = FormTemplate fields = ["title_base", "form_id_base"] template_name = "patterns/tables/table.html" - attrs = {"th": {"scope": "col", "class": "px-4 py-3 whitespace-nowrap "}} + attrs = {"th": {"scope": "col", "class": "px-4 py-3 whitespace-nowrap"}} orderable = False diff --git a/apps/odk_publish/urls.py b/apps/odk_publish/urls.py index 80c087c..038bd3d 100644 --- a/apps/odk_publish/urls.py +++ b/apps/odk_publish/urls.py @@ -19,6 +19,16 @@ views.form_template_list, name="form-template-list", ), + path( + "/form-templates//", + views.form_template_detail, + name="form-template-detail", + ), + path( + "/form-templates//publish/", + views.form_template_publish, + name="form-template-publish", + ), path( "/form-templates//publish-next-version/", views.form_template_publish_next_version, diff --git a/apps/odk_publish/views.py b/apps/odk_publish/views.py index 8a1cbe1..96e6a8f 100644 --- a/apps/odk_publish/views.py +++ b/apps/odk_publish/views.py @@ -3,8 +3,9 @@ from django.contrib import messages from django.contrib.auth.decorators import login_required from django.db import models, transaction -from django.http import HttpRequest +from django.http import HttpRequest, HttpResponse from django.shortcuts import get_object_or_404, redirect, render +from django.views.decorators.http import require_http_methods from .etl.load import generate_and_save_app_user_collect_qrcodes from .models import FormTemplateVersion, FormTemplate @@ -57,12 +58,62 @@ def form_template_list(request: HttpRequest, odk_project_pk): return render(request, "odk_publish/form_template_list.html", context) +@login_required +def form_template_detail(request: HttpRequest, odk_project_pk: int, form_template_id: int): + form_template: FormTemplate = get_object_or_404( + request.odk_project.form_templates.annotate( + app_user_count=models.Count("app_user_forms"), + ).prefetch_related( + models.Prefetch( + "versions", + queryset=FormTemplateVersion.objects.order_by("-modified_at"), + to_attr="latest_version", + ) + ), + pk=form_template_id, + ) + context = { + "form_template": form_template, + "form_template_app_users": form_template.app_user_forms.values_list( + "app_user__name", flat=True + ), + "breadcrumbs": Breadcrumbs.from_items( + request=request, + items=[ + ("Form Templates", "form-template-list"), + (form_template.title_base, "form-template-detail", [form_template.pk]), + ], + ), + } + return render(request, "odk_publish/form_template_detail.html", context) + + +@login_required +def form_template_publish(request: HttpRequest, odk_project_pk: int, form_template_id: int): + form_template: FormTemplate = get_object_or_404( + request.odk_project.form_templates, pk=form_template_id + ) + context = { + "form_template": form_template, + "breadcrumbs": Breadcrumbs.from_items( + request=request, + items=[ + ("Form Templates", "form-template-list"), + (form_template.title_base, "form-template-detail", [form_template.pk]), + ("Publish", "form-template-publish", [form_template.pk]), + ], + ), + } + return render(request, "odk_publish/form_template_publish.html", context) + + @login_required @transaction.atomic +@require_http_methods(["POST"]) def form_template_publish_next_version(request: HttpRequest, odk_project_pk, form_template_id): form_template: FormTemplate = get_object_or_404( request.odk_project.form_templates, pk=form_template_id ) version = form_template.create_next_version(user=request.user) messages.add_message(request, messages.SUCCESS, f"{version} published.") - return redirect("odk_publish:form-template-list", odk_project_pk=odk_project_pk) + return HttpResponse(status=204) diff --git a/config/assets/styles/tailwind-entry.css b/config/assets/styles/tailwind-entry.css index 9b22a25..ffdda26 100644 --- a/config/assets/styles/tailwind-entry.css +++ b/config/assets/styles/tailwind-entry.css @@ -28,16 +28,10 @@ .btn { @apply font-medium text-center text-sm px-5 py-2.5 rounded-lg cursor-pointer; } - .btn-primary { - @apply text-white bg-primary hover:bg-primary-500 focus:ring-4 focus:outline-none focus:ring-primary-300; - } - .btn-danger { - @apply text-danger-medium bg-white rounded-lg border border-danger-medium hover:bg-danger-medium hover:text-danger-medium focus:outline-none focus:ring-4 focus:ring-gray-200; - } .btn-outline { - @apply text-primary bg-white border border-blue-900 hover:bg-primary-500 hover:text-white focus:ring-4 focus:outline-none focus:ring-primary-300; + @apply text-gray-900 focus:outline-none bg-white rounded-lg border border-gray-200 hover:bg-gray-100 hover:text-primary-700 focus:z-10 focus:ring-4 focus:ring-gray-200 dark:focus:ring-gray-700 dark:bg-gray-800 dark:text-gray-400 dark:border-gray-600 dark:hover:text-white dark:hover:bg-gray-700; } - .btn-active { - @apply text-white bg-primary-500 border border-blue-900 hover:bg-primary-500 hover:text-white focus:ring-4 focus:outline-none focus:ring-primary-300; + .btn-primary { + @apply border-primary-400 bg-gradient-to-r from-primary-100 via-primary-200 to-primary-200 dark:bg-none; } } diff --git a/config/templates/includes/breadcrumbs.html b/config/templates/includes/breadcrumbs.html index 5424044..897dcb9 100644 --- a/config/templates/includes/breadcrumbs.html +++ b/config/templates/includes/breadcrumbs.html @@ -30,7 +30,14 @@ viewBox="0 0 24 24"> - {{ crumb.label }} + {% if not forloop.last %} + + {{ crumb.label }} + + {% else %} + {{ crumb.label }} + {% endif %} {% endfor %} diff --git a/config/templates/includes/navbar.html b/config/templates/includes/navbar.html index b7d78d0..7b95772 100644 --- a/config/templates/includes/navbar.html +++ b/config/templates/includes/navbar.html @@ -143,7 +143,7 @@ {% for tab in request.odk_project_tabs %}
  • {{ tab.label }}
  • {% endfor %} diff --git a/config/templates/odk_publish/form_template_detail.html b/config/templates/odk_publish/form_template_detail.html new file mode 100644 index 0000000..9320afe --- /dev/null +++ b/config/templates/odk_publish/form_template_detail.html @@ -0,0 +1,79 @@ +{% extends "base.html" %} +{% block extra-css %} + +{% endblock extra-css %} +{% block content %} +
    + + + +
    +
    Latest version
    +
    + {{ form_template.latest_version.0.version }} +
    +
    Latest published by
    +
    + {{ form_template.latest_version.0.user.first_name }} {{ form_template.latest_version.0.user.last_name }} +
    +
    XML Form ID
    +
    + {{ form_template.form_id_base }} +
    +
    App Users
    +
    + {{ form_template_app_users | join:", " }} +
    +
    +
    +{% endblock content %} diff --git a/config/templates/odk_publish/form_template_publish.html b/config/templates/odk_publish/form_template_publish.html new file mode 100644 index 0000000..65caf74 --- /dev/null +++ b/config/templates/odk_publish/form_template_publish.html @@ -0,0 +1,7 @@ +{% extends "base.html" %} +{% load django_tables2 %} +{% block page_header %} + Publish next version of {{ form_template.title_base }} +{% endblock page_header %} +{% block content %} +{% endblock content %}