From ccd0e151e1c96720d4d69cd3865bdcca3b24443d Mon Sep 17 00:00:00 2001 From: Lucas Brandstaetter <lucas@brandstaetter.tech> Date: Mon, 23 Dec 2024 01:05:44 +0100 Subject: [PATCH] Refactor activity log card - Update header to use tabs - Move activity log card to components - Remove custom JS - Add no script tag to show all messages when JS is disabled - Make help for comment customizable (e.g. for teams) --- .../locale/de/LC_MESSAGES/django.po | 39 +++-- .../locale/en/LC_MESSAGES/django.po | 39 +++-- .../backoffice/activitylog_card.html | 123 -------------- .../assemblyteam_assembly_detail.html | 2 +- .../components/activity_log_card.html | 156 ++++++++++++++++++ .../components/activity_log_entry.html | 33 ++++ src/backoffice/views/assemblyteam.py | 13 +- 7 files changed, 242 insertions(+), 163 deletions(-) delete mode 100644 src/backoffice/templates/backoffice/activitylog_card.html create mode 100644 src/backoffice/templates/backoffice/components/activity_log_card.html create mode 100644 src/backoffice/templates/backoffice/components/activity_log_entry.html diff --git a/src/backoffice/locale/de/LC_MESSAGES/django.po b/src/backoffice/locale/de/LC_MESSAGES/django.po index 4c4697b09..c6356e8bf 100644 --- a/src/backoffice/locale/de/LC_MESSAGES/django.po +++ b/src/backoffice/locale/de/LC_MESSAGES/django.po @@ -95,24 +95,6 @@ msgstr "Hangar-Zugriff" msgid "Room__hangar_backend_link__help" msgstr "Private FTP-Zugang um Dateien im Hangar abzulegen" -msgid "ActivityLog__visible_entries__all" -msgstr "alle Einträge" - -msgid "ActivityLog__visible_entries__msg" -msgstr "nur mit Notiz" - -msgid "ActivityLog_add_comment" -msgstr "Kommentar (als Log-Eintrag) hinzufügen" - -msgid "ActivityLogEntries" -msgstr "Activity Log Einträge" - -msgid "ActivityLog_add_comment_help" -msgstr "Kommentar, der im Log-Eintrag vermerkt wird (nur für Orga sichtbar):" - -msgid "ActivityLog_add_comment_do" -msgstr "Speichern" - msgid "assembly_children" msgstr "Zugeordnete Assemblies" @@ -843,6 +825,24 @@ msgstr "Übersicht" msgid "backoffice__not_a_conference_member" msgstr "Das Nutzerkonto, mit dem du gerade angemeldet bist, ist zur Zeit nicht mit einem Veranstaltungsticket verknüpft. Wenn Du gerade beim Aufbau hilfst, ist das kein Problem. Denk aber bitte daran, rechtzeitig ein Ticket zu kaufen und dies kurz vor Veranstaltungsbeginn mit deinem Nutzerkonto zu verknüpfen. Ansonsten kannst Du mit diesem Nutzerkonto nicht an der Veranstaltung teilnehmen." +msgid "ActivityLogEntries" +msgstr "Activity Log Einträge" + +msgid "ActivityLog__visible_entries__all" +msgstr "alle Einträge" + +msgid "ActivityLog__visible_entries__msg" +msgstr "nur mit Notiz" + +msgid "ActivityLog_add_comment" +msgstr "Kommentar (als Log-Eintrag) hinzufügen" + +msgid "ActivityLog_add_comment_do" +msgstr "Speichern" + +msgid "ActivityLog_no_entries" +msgstr "Keine Activity Log Einträge" + msgid "create" msgstr "Erstellen" @@ -1742,6 +1742,9 @@ msgstr "versteckt" msgid "lists" msgstr "Listen" +msgid "ActivityLog__add_comment__AssemblyTeam" +msgstr "Kommentar, der im Log-Eintrag vermerkt wird (nur für Orga sichtbar):" + msgid "AssemblyTeam__add_comment_success" msgstr "Kommentar wurde als Log-Eintrag gespeichert." diff --git a/src/backoffice/locale/en/LC_MESSAGES/django.po b/src/backoffice/locale/en/LC_MESSAGES/django.po index fd34abffa..5d4a4a195 100644 --- a/src/backoffice/locale/en/LC_MESSAGES/django.po +++ b/src/backoffice/locale/en/LC_MESSAGES/django.po @@ -95,24 +95,6 @@ msgstr "Hangar Access" msgid "Room__hangar_backend_link__help" msgstr "your private ftp access to put files on your hangar" -msgid "ActivityLog__visible_entries__all" -msgstr "all entries" - -msgid "ActivityLog__visible_entries__msg" -msgstr "only w/ note" - -msgid "ActivityLog_add_comment" -msgstr "add comment as log entry" - -msgid "ActivityLogEntries" -msgstr "activity log entries" - -msgid "ActivityLog_add_comment_help" -msgstr "comment which will be added as a log entry (visible for orga only)" - -msgid "ActivityLog_add_comment_do" -msgstr "save" - msgid "assembly_children" msgstr "Grouped Assemblies" @@ -843,6 +825,24 @@ msgstr "overview" msgid "backoffice__not_a_conference_member" msgstr "The user account you are currently logged in with is not linked to an valid event ticket. If you are helping with the set-up, this is not a problem. But please remember to buy a ticket in time and link it to your user account. Otherwise you will not be able to participate in the event with this user account. Linking the ticket to the user account will be available directly before the event." +msgid "ActivityLogEntries" +msgstr "activity log entries" + +msgid "ActivityLog__visible_entries__all" +msgstr "all entries" + +msgid "ActivityLog__visible_entries__msg" +msgstr "only w/ note" + +msgid "ActivityLog_add_comment" +msgstr "add comment as log entry" + +msgid "ActivityLog_add_comment_do" +msgstr "save" + +msgid "ActivityLog_no_entries" +msgstr "No activity log entries" + msgid "create" msgstr "" @@ -1748,6 +1748,9 @@ msgstr "hidden" msgid "lists" msgstr "lists" +msgid "ActivityLog__add_comment__AssemblyTeam" +msgstr "comment which will be added as a log entry (visible for orga only)" + msgid "AssemblyTeam__add_comment_success" msgstr "A log entry with the comment has been added." diff --git a/src/backoffice/templates/backoffice/activitylog_card.html b/src/backoffice/templates/backoffice/activitylog_card.html deleted file mode 100644 index 97951263b..000000000 --- a/src/backoffice/templates/backoffice/activitylog_card.html +++ /dev/null @@ -1,123 +0,0 @@ -{% load c3assemblies %} -{% load i18n %} -{% load humanize %} - -{% gen_rand_str as alc_ident %} -<div class="row mb-3"> - <div class="col-md-12"> - <div class="card" id="logentries_{{ alc_ident }}"> - <div class="card-header"> - <div class="d-inline-block float-end"> - <div class="btn-group d-none me-1" - role="group" - id="visible_logentries_{{ alc_ident }}"> - <input type="radio" - class="btn-check" - name="visible_logentries" - id="visible_logentries_all_{{ alc_ident }}" - autocomplete="off" - checked> - <label class="btn btn-sm btn-outline-primary" - for="visible_logentries_all_{{ alc_ident }}">{% trans "ActivityLog__visible_entries__all" %}</label> - - <input type="radio" - class="btn-check" - name="visible_logentries" - id="visible_logentries_msg_{{ alc_ident }}" - autocomplete="off"> - <label class="btn btn-sm btn-outline-primary" - for="visible_logentries_msg_{{ alc_ident }}">{% trans "ActivityLog__visible_entries__msg" %}</label> - </div> - {% if add_comment_url %} - <button class="btn btn-sm btn-primary" - title="{% trans "ActivityLog_add_comment" %}" - data-bs-toggle="modal" - data-bs-target="#addCommentModal_{{ alc_ident }}"> - <i class="bi bi-chat-left-text"></i> - </button> - {% endif %} - </div> - {% trans "ActivityLogEntries" %} - </div> - <div class="card-body"> - {% for entry in object.logentries.all %} - <div class="mb-3 {% if entry.kind == entry.Kind.SYSTEM %}text-muted{% endif %} logentry" - data-has-msg="{% if entry.comment %}y{% else %}n{% endif %}"> - {% if latest_note and latest_note.pk == entry.pk %}<a id="latest_note"></a>{% endif %} - <div class="border-bottom border-secondary mb-1{% if not entry.comment %} text-muted{% endif %}"> - <abbr title="{{ entry.timestamp }}">{{ entry.timestamp|naturaltime }}</abbr> - <span class="mx-1 badge bg-light text-bg-light border border-secondary-subtle"><i class="bi bi-person"></i> {{ entry.user.username }}</span> - <span class="text-muted">{{ entry.get_kind_display }}</span> - </div> - {% if entry.changes %} - <i class="bi bi-table float-start"></i> - <dl class="ms-4 mb-1 row small text-muted"> - {% for k, v in entry.changes.items %} - {% if k not in filtered_logentry_changes_keys %} - <dt class="col-md-3">{{ k }}:</dt> - <dd class="col-md-9"> - {% if v|is_dict %} - <s class="fst-italic">{{ v.old }}</s> - {{ v.new }} - {% else %} - {{ v }} - {% endif %} - </dd> - {% endif %} - {% endfor %} - </dl> - {% endif %} - {% if entry.comment %} - <i class="bi bi-chat-left-text float-start"></i> - <div class="ms-4 border-1 bg-primary-subtle">{{ entry.comment }}</div> - {% endif %} - </div> - {% endfor %} - </div> - </div> - </div> -</div> - -{% if add_comment_url %} - <div class="modal fade" - id="addCommentModal_{{ alc_ident }}" - tabindex="-1" - aria-labelledby="addCommentModalLabel" - aria-hidden="true"> - <div class="modal-dialog"> - <div class="modal-content"> - <div class="modal-header"> - <h1 class="modal-title fs-5" id="addCommentModalLabel">{% trans "ActivityLog_add_comment" %}</h1> - <button type="button" - class="btn-close" - data-bs-dismiss="modal" - aria-label="Close"></button> - </div> - <div class="modal-body"> - <p>{% trans "ActivityLog_add_comment_help" %}</p> - <form id="add_comment_{{ alc_ident }}" - action="{{ add_comment_url }}" - method="post"> - {% csrf_token %} - <textarea name="comment" class="form-control" placeholder="" required></textarea> - </form> - </div> - <div class="modal-footer"> - <button class="btn btn-primary" form="add_comment_{{ alc_ident }}"> - <i class="bi bi-chat-left-text"></i> {% trans "ActivityLog_add_comment_do" %} - </button> - </div> - </div> - </div> - </div> -{% endif %} - -<script nonce="{{ request.csp_nonce }}"> - alc_div = document.getElementById("logentries_{{ alc_ident }}"); - // make "visible log entries" selector visible and click the "w/ msg only" one - document.getElementById("visible_logentries_{{ alc_ident }}").classList.remove("d-none"); - document.getElementById("visible_logentries_all_{{ alc_ident }}").addEventListener("click", function() { for (const el of alc_div.getElementsByClassName("logentry")) { el.classList.remove("d-none"); } }); - let btn_msg = document.getElementById("visible_logentries_msg_{{ alc_ident }}"); - btn_msg.addEventListener("click", function() { for (const el of alc_div.getElementsByClassName("logentry")) { if (el.getAttribute("data-has-msg") === "n") el.classList.add("d-none"); } }); - btn_msg.click(); -</script> diff --git a/src/backoffice/templates/backoffice/assemblyteam_assembly_detail.html b/src/backoffice/templates/backoffice/assemblyteam_assembly_detail.html index 06c8b523f..96eec278f 100644 --- a/src/backoffice/templates/backoffice/assemblyteam_assembly_detail.html +++ b/src/backoffice/templates/backoffice/assemblyteam_assembly_detail.html @@ -292,6 +292,6 @@ </div> {% url "backoffice:assemblyteam-detail" pk=object.pk as add_comment_url %} - {% include "backoffice/activitylog_card.html" with filtered_logentry_changes_keys="last_update_assembly"|split:"," %} + {% include "backoffice/components/activity_log_card.html" with filtered_logentry_changes_keys="last_update_assembly"|split:"," %} {% endblock content %} diff --git a/src/backoffice/templates/backoffice/components/activity_log_card.html b/src/backoffice/templates/backoffice/components/activity_log_card.html new file mode 100644 index 000000000..6c7ff6f47 --- /dev/null +++ b/src/backoffice/templates/backoffice/components/activity_log_card.html @@ -0,0 +1,156 @@ +{% load c3assemblies %} +{% load i18n %} +{% load humanize %} + +{% gen_rand_str as alc_ident %} +{% if all_log_entries or msg_log_entries %} + <div class="row mb-3"> + <div class="col-md-12"> + <div class="card" id="logentries_{{ alc_ident }}"> + <div class="card-header d-flex p-0 pt-2 border-bottom-0"> + <div class="ps-3 flex-grow-1 border-bottom border-bottom-1"> + <span class="align-middle">{% trans "ActivityLogEntries" %}</span> + </div> + <div class="d-flex float-end"> + <div role="ms-2 navigation justify-content-end"> + <ul class="nav nav-tabs" id="log-message-tabs" role="tablist"> + <li class="nav-item" role="presentation"> + <button class="nav-link {% if not msg_log_entries %}active{% endif %}" + id="all-tab" + data-bs-toggle="tab" + data-bs-target="#all-logs" + type="button" + role="tab" + aria-controls="all-logs" + aria-selected="{% if msg_log_entries %}false{% else %}true{% endif %}"> + {% trans "ActivityLog__visible_entries__all" %} + </button> + </li> + <li class="nav-item" role="presentation"> + <button class="nav-link {% if not msg_log_entries %}disabled{% else %}active{% endif %}" + id="msg-tab" + data-bs-toggle="tab" + data-bs-target="#msg-logs" + type="button" + role="tab" + aria-controls="msg-logs" + {% if msg_log_entries %}aria-disabled="true"{% endif %} + aria-selected="{% if msg_log_entries %}false{% else %}true{% endif %}"> + {% trans "ActivityLog__visible_entries__msg" %} + </button> + </li> + </ul> + </div> + {% if add_comment_url %} + <div class="ps-3 pe-3 border-bottom border-bottom-1"> + <button class="btn btn-sm btn-primary" + title="{% trans "ActivityLog_add_comment" %}" + data-bs-toggle="modal" + data-bs-target="#addCommentModal_{{ alc_ident }}"> + <i class="bi bi-chat-left-text"></i> + </button> + </div> + {% else %} + <div class="pe-3 border-bottom border-bottom-1"></div> + {% endif %} + </div> + + </div> + <div class="card-body"> + <div class="tab-content"> + <div class="tab-pane {% if not msg_log_entries %}active{% endif %}" + id="all-logs" + role="tabpanel" + aria-labelledby="all-tab"> + {% for entry in all_log_entries %} + {% include "backoffice/components/activity_log_entry.html" %} + {% endfor %} + </div> + <div class="tab-pane {% if msg_log_entries %}active{% endif %}" + id="msg-logs" + role="tabpanel" + aria-labelledby="msg-tab"> + {% for entry in msg_log_entries %} + {% include "backoffice/components/activity_log_entry.html" %} + {% endfor %} + </div> + </div> + </div> + </div> + </div> + </div> + + {% if add_comment_url %} + <div class="modal fade" + id="addCommentModal_{{ alc_ident }}" + tabindex="-1" + aria-labelledby="addCommentModalLabel" + aria-hidden="true"> + <div class="modal-dialog"> + <div class="modal-content"> + <div class="modal-header"> + <h1 class="modal-title fs-5" id="addCommentModalLabel">{% trans "ActivityLog_add_comment" %}</h1> + <button type="button" + class="btn-close" + data-bs-dismiss="modal" + aria-label="Close"></button> + </div> + <div class="modal-body"> + <p>{{ add_comment_help }}</p> + <form id="add_comment_{{ alc_ident }}" + action="{{ add_comment_url }}" + method="post"> + {% csrf_token %} + <textarea name="comment" class="form-control" placeholder="" required></textarea> + </form> + </div> + <div class="modal-footer"> + <button class="btn btn-primary" form="add_comment_{{ alc_ident }}"> + <i class="bi bi-chat-left-text"></i> {% trans "ActivityLog_add_comment_do" %} + </button> + </div> + </div> + </div> + </div> + {% endif %} + + <!-- Show all messages and hide the tabs when JS is disabled --> + <noscript> + <style> + #msg-logs { + display: none; + } + #log-message-tabs { + display: none; + } + #all-logs { + display: block; + } + </style> + </noscript> +{% else %} + <div class="row mb-3"> + <div class="col-md-12"> + <div class="card" id="logentries_{{ alc_ident }}"> + <div class="card-header d-flex"> + <div class="flex-grow-1"> + <span>{% trans "ActivityLogEntries" %}</span> + </div> + {% if add_comment_url %} + <div class="ps-3 pe-3 border-bottom border-bottom-1"> + <button class="btn btn-sm btn-primary" + title="{% trans "ActivityLog_add_comment" %}" + data-bs-toggle="modal" + data-bs-target="#addCommentModal_{{ alc_ident }}"> + <i class="bi bi-chat-left-text"></i> + </button> + </div> + {% endif %} + </div> + <div class="card-body"> + <div role="alert">{% trans "ActivityLog_no_entries" %}</div> + </div> + </div> + </div> + </div> +{% endif %} diff --git a/src/backoffice/templates/backoffice/components/activity_log_entry.html b/src/backoffice/templates/backoffice/components/activity_log_entry.html new file mode 100644 index 000000000..63f9b0258 --- /dev/null +++ b/src/backoffice/templates/backoffice/components/activity_log_entry.html @@ -0,0 +1,33 @@ +{% load humanize %} + +<div class="mb-3 logentry {% if entry.kind == entry.Kind.SYSTEM %}text-muted{% endif %}" + data-has-msg="{% if entry.comment %}y{% else %}n{% endif %}"> + {% if latest_note and latest_note.pk == entry.pk %}<a id="latest_note"></a>{% endif %} + <div class="border-bottom border-secondary mb-1 {% if not entry.comment %}text-muted{% endif %}"> + <abbr title="{{ entry.timestamp }}">{{ entry.timestamp|naturaltime }}</abbr> + <span class="mx-1 badge bg-light text-bg-light border border-secondary-subtle"><i class="bi bi-person"></i> {{ entry.user.username }}</span> + <span class="text-muted">{{ entry.get_kind_display }}</span> + </div> + {% if entry.changes %} + <i class="bi bi-table float-start"></i> + <dl class="ms-4 mb-1 row small text-muted"> + {% for k, v in entry.changes.items %} + {% if k not in filtered_logentry_changes_keys %} + <dt class="col-md-3">{{ k }}:</dt> + <dd class="col-md-9"> + {% if v|is_dict %} + <s class="fst-italic">{{ v.old }}</s> + {{ v.new }} + {% else %} + {{ v }} + {% endif %} + </dd> + {% endif %} + {% endfor %} + </dl> + {% endif %} + {% if entry.comment %} + <i class="bi bi-chat-left-text float-start"></i> + <div class="ms-4 p-1 border border-2 border-info rounded">{{ entry.comment }}</div> + {% endif %} +</div> diff --git a/src/backoffice/views/assemblyteam.py b/src/backoffice/views/assemblyteam.py index 6e9654c63..40cedbb0c 100644 --- a/src/backoffice/views/assemblyteam.py +++ b/src/backoffice/views/assemblyteam.py @@ -182,9 +182,16 @@ class AssemblyView(SingleAssemblyTeamMixin, DetailView): template_name = 'backoffice/assemblyteam_assembly_detail.html' def get_context_data(self, *args, **kwargs): - ctx = super().get_context_data(*args, **kwargs) - ctx['latest_note'] = self.assembly.logentries.exclude(comment=None).order_by('-timestamp').first() - return ctx + if not Assembly.type_is(assembly := self.get_object()): # pragma: no cover + raise ValueError('Invalid object found for AssemblyView') + log_entries = assembly.logentries.order_by('-timestamp') + return { + **super().get_context_data(*args, **kwargs), + 'latest_note': log_entries.first(), + 'all_log_entries': log_entries, + 'msg_log_entries': log_entries.filter(comment__isnull=False), + 'add_comment_help': _('ActivityLog__add_comment__AssemblyTeam'), + } def post(self, *args, **kwargs): comment = self.request.POST.get('comment', '').strip() -- GitLab