feat: Update user messages inbox and collection user messages with enhanced acknowledgment statistics and navigation links

This commit is contained in:
Ross
2026-04-27 22:05:30 +01:00
parent 1876a7f845
commit 3772846e55
3 changed files with 84 additions and 7 deletions
@@ -45,6 +45,17 @@
<span class="badge bg-danger">{{ row.stats.outstanding_total_count }} outstanding</span>
</div>
<div class="card-body pt-0">
<div class="d-flex flex-wrap gap-2 mt-2 mb-2">
<a class="btn btn-sm btn-outline-secondary" href="{% url 'atlas:collection_detail' collection.id %}">
Collection
</a>
<a class="btn btn-sm btn-outline-secondary" href="{% url 'atlas:collection_case_view' pk=collection.id case_number=row.casedetail.sort_order %}">
Case In Collection
</a>
<a class="btn btn-sm btn-outline-primary" href="{% if target_user %}{% url 'atlas:collection_history_user' collection.id target_user.id %}{% else %}{% url 'atlas:collection_history_ciduser' collection.id target_cid %}{% endif %}#case-history-{{ row.casedetail.case.id }}">
User Answer In Context
</a>
</div>
<div hx-get="{{ row.thread_url }}{% if row.cid %}?cid={{ row.cid }}{% endif %}"
hx-trigger="load"
hx-target="this"
@@ -78,6 +89,17 @@
</h2>
<div id="history-collapse-{{ row.casedetail.case.id }}" class="accordion-collapse collapse" aria-labelledby="history-heading-{{ row.casedetail.case.id }}" data-bs-parent="#userMessageHistoryAccordion">
<div class="accordion-body pt-0">
<div class="d-flex flex-wrap gap-2 mt-2 mb-2">
<a class="btn btn-sm btn-outline-secondary" href="{% url 'atlas:collection_detail' collection.id %}">
Collection
</a>
<a class="btn btn-sm btn-outline-secondary" href="{% url 'atlas:collection_case_view' pk=collection.id case_number=row.casedetail.sort_order %}">
Case In Collection
</a>
<a class="btn btn-sm btn-outline-primary" href="{% if target_user %}{% url 'atlas:collection_history_user' collection.id target_user.id %}{% else %}{% url 'atlas:collection_history_ciduser' collection.id target_cid %}{% endif %}#case-history-{{ row.casedetail.case.id }}">
User Answer In Context
</a>
</div>
<div hx-get="{{ row.thread_url }}{% if row.cid %}?cid={{ row.cid }}{% endif %}"
hx-trigger="revealed once"
hx-target="this"
+23 -6
View File
@@ -9,7 +9,13 @@
<div class="card border-secondary" style="min-width: 320px;">
<div class="card-body py-2 px-3">
<div class="small text-muted">Pending acknowledgements</div>
<div class="fw-semibold {% if total_outstanding %}text-danger{% endif %}">
<div class="fw-semibold {% if total_needs_your_ack %}text-danger{% endif %}">
{{ total_needs_your_ack }} need your acknowledgement
</div>
<div class="small mt-1 {% if total_waiting_on_other %}text-warning-emphasis{% else %}text-muted{% endif %}">
{{ total_waiting_on_other }} waiting on another user
</div>
<div class="small mt-1 text-muted">
{{ total_outstanding }} unacknowledged message{{ total_outstanding|pluralize }}
</div>
<div class="mt-2">
@@ -38,11 +44,13 @@
{% endif %}
</div>
<div class="d-flex flex-wrap gap-2 align-items-center">
{% if row.outstanding_count %}
<span class="badge bg-danger">{{ row.outstanding_count }} unacknowledged</span>
{% else %}
<span class="badge bg-secondary">No outstanding</span>
<span class="badge {% if row.needs_your_ack_count %}bg-danger{% else %}bg-secondary{% endif %}">
{{ row.needs_your_ack_count }} need your ack
</span>
{% if row.waiting_on_other_count %}
<span class="badge text-bg-warning">{{ row.waiting_on_other_count }} waiting on other</span>
{% endif %}
<span class="badge bg-dark-subtle text-dark-emphasis">{{ row.outstanding_count }} total unacknowledged</span>
<a class="btn btn-sm btn-outline-secondary" href="{{ row.detail_url }}">Open user message page</a>
</div>
</div>
@@ -59,7 +67,13 @@
{% if row.collection.show_title_post %}
<span class="text-muted">{{ case_row.casedetail.case.title|default:case_row.casedetail.case.pk|truncatechars:90 }}</span>
{% endif %}
<span class="badge bg-danger">{{ case_row.stats.outstanding_total_count }} unacknowledged</span>
<span class="badge {% if case_row.stats.needs_your_ack_count %}bg-danger{% else %}bg-secondary{% endif %}">
{{ case_row.stats.needs_your_ack_count }} need your ack
</span>
{% if case_row.stats.waiting_on_other_count %}
<span class="badge text-bg-warning">{{ case_row.stats.waiting_on_other_count }} waiting on other</span>
{% endif %}
<span class="badge bg-dark-subtle text-dark-emphasis">{{ case_row.stats.outstanding_total_count }} total</span>
</summary>
{% if row.viewer_role == 'moderator' %}
<div class="d-flex flex-wrap gap-2 mt-2">
@@ -114,6 +128,9 @@
: {{ case_row.casedetail.case.title|default:case_row.casedetail.case.pk|truncatechars:90 }}
{% endif %}
<span class="badge bg-secondary ms-2">{{ case_row.stats.message_count }} messages</span>
{% if case_row.stats.outstanding_total_count %}
<span class="badge bg-dark-subtle text-dark-emphasis ms-1">{{ case_row.stats.outstanding_total_count }} unacknowledged</span>
{% endif %}
</button>
</h2>
<div id="history-collapse-{{ row.attempt.id }}-{{ case_row.casedetail.case.id }}" class="accordion-collapse collapse" aria-labelledby="history-heading-{{ row.attempt.id }}-{{ case_row.casedetail.case.id }}" data-bs-parent="#history-{{ row.attempt.id }}">
+39 -1
View File
@@ -4500,6 +4500,8 @@ def user_messages_inbox(request):
{
"inbox_rows": [],
"total_outstanding": 0,
"total_needs_your_ack": 0,
"total_waiting_on_other": 0,
"show_all": request.GET.get("show") == "all",
},
)
@@ -4537,12 +4539,23 @@ def user_messages_inbox(request):
acknowledged_at__isnull=True,
),
),
outstanding_query_count=Count(
"id",
filter=Q(
requires_acknowledgement=True,
acknowledged_at__isnull=True,
message_type=CaseReviewMessage.MessageType.QUERY,
),
),
)
):
outstanding_total_count = row["outstanding_total_count"]
outstanding_query_count = row["outstanding_query_count"]
message_stats_by_attempt_case[row["cid_user_exam_id"]][row["case_id"]] = {
"message_count": row["message_count"],
"outstanding_total_count": outstanding_total_count,
"outstanding_query_count": outstanding_query_count,
"outstanding_feedback_count": outstanding_total_count - outstanding_query_count,
"has_messages": row["message_count"] > 0,
"has_outstanding_any": outstanding_total_count > 0,
}
@@ -4567,14 +4580,31 @@ def user_messages_inbox(request):
{
"message_count": 0,
"outstanding_total_count": 0,
"outstanding_query_count": 0,
"outstanding_feedback_count": 0,
"has_messages": False,
"has_outstanding_any": False,
},
)
outstanding_query_count = stats.get("outstanding_query_count", 0)
outstanding_feedback_count = stats.get("outstanding_feedback_count", 0)
if viewer_role == "moderator":
needs_your_ack_count = outstanding_query_count
waiting_on_other_count = outstanding_feedback_count
else:
needs_your_ack_count = outstanding_feedback_count
waiting_on_other_count = outstanding_query_count
enriched_stats = {
**stats,
"needs_your_ack_count": needs_your_ack_count,
"waiting_on_other_count": waiting_on_other_count,
}
feedback_rows.append(
{
"casedetail": casedetail,
"stats": stats,
"stats": enriched_stats,
"thread_url": reverse(
"atlas:collection_case_review_thread",
kwargs={
@@ -4610,6 +4640,8 @@ def user_messages_inbox(request):
)
outstanding_count = sum(row["stats"].get("outstanding_total_count", 0) for row in feedback_rows)
needs_your_ack_count = sum(row["stats"].get("needs_your_ack_count", 0) for row in feedback_rows)
waiting_on_other_count = sum(row["stats"].get("waiting_on_other_count", 0) for row in feedback_rows)
inbox_rows.append(
{
"collection": collection,
@@ -4620,6 +4652,8 @@ def user_messages_inbox(request):
"outstanding_rows": outstanding_rows,
"history_rows": history_rows,
"outstanding_count": outstanding_count,
"needs_your_ack_count": needs_your_ack_count,
"waiting_on_other_count": waiting_on_other_count,
}
)
@@ -4633,6 +4667,8 @@ def user_messages_inbox(request):
)
total_outstanding = sum(row["outstanding_count"] for row in inbox_rows)
total_needs_your_ack = sum(row["needs_your_ack_count"] for row in inbox_rows)
total_waiting_on_other = sum(row["waiting_on_other_count"] for row in inbox_rows)
show_all = request.GET.get("show") == "all"
return render(
@@ -4641,6 +4677,8 @@ def user_messages_inbox(request):
{
"inbox_rows": inbox_rows,
"total_outstanding": total_outstanding,
"total_needs_your_ack": total_needs_your_ack,
"total_waiting_on_other": total_waiting_on_other,
"show_all": show_all,
},
)