Skip to content
Open
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions changelog.d/1938.added.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Added a kiosk mode to the main view, providing a minimal version of the incident list suitable for passive Argus usage.
9 changes: 9 additions & 0 deletions docs/user-manual.rst
Original file line number Diff line number Diff line change
Expand Up @@ -187,6 +187,15 @@ Change how often the incidents table gets refreshed

3. Select how often you want the incidents to be updated.

Use kiosk mode
--------------

Kiosk mode is a read-only view of the incidents table intended for display
screens such as NOC monitors, which frees up more vertical space by simplifying the interface.
It can be accessed via the ``Kiosk`` button in the filter toolbar, or directly at **/incidents/kiosk/**.

To exit kiosk mode, you can press the ``Exit kiosk`` button in the filter toolbar.

Decide which incidents are shown in the table
---------------------------------------------

Expand Down
1 change: 1 addition & 0 deletions src/argus/htmx/incident/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
app_name = "htmx"
urlpatterns = [
path("", views.incident_list, name="incident-list"),
path("kiosk/", views.incident_list_kiosk, name="incident-list-kiosk"),
path("<int:pk>/", views.incident_detail, name="incident-detail"),
path("update/<str:action>/", views.incident_update, name="incident-update"),
path("filter/", views.filter_form, name="incident-filter"),
Expand Down
26 changes: 22 additions & 4 deletions src/argus/htmx/incident/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
import logging
from collections.abc import Iterable
from datetime import datetime
from urllib.parse import urlencode
from urllib.parse import urlencode, urlparse
from typing import Optional, Any

from django import forms
Expand All @@ -18,6 +18,7 @@
QueryDict,
)
from django.shortcuts import render, get_object_or_404
from django.urls import reverse
from django.utils.timezone import now as tznow
from django.views.decorators.http import require_POST, require_GET

Expand Down Expand Up @@ -46,6 +47,7 @@

User = get_user_model()
LOG = logging.getLogger(__name__)
KIOSK_URL_NAME = "htmx:incident-list-kiosk"


# Map request trigger to parameters for incidents update
Expand Down Expand Up @@ -190,19 +192,24 @@ def delete_filter(request: HtmxHttpRequest, pk: int):

@require_GET
def filter_select(request: HtmxHttpRequest):
current_url = request.htmx.current_url
Comment thread
aleksfl marked this conversation as resolved.
Outdated
kiosk_mode = False
if current_url and urlparse(current_url).path == reverse(KIOSK_URL_NAME):
kiosk_mode = True

filter_id = request.GET.get("filter", None)
if filter_id and get_object_or_404(Filter, id=filter_id):
request.session["selected_filter"] = filter_id
incident_list_filter = get_filter_function()
filter_form, _ = incident_list_filter(request, None)
context = {"filter_form": filter_form}
context = {"filter_form": filter_form, "kiosk_mode": kiosk_mode}
return render(request, "htmx/incident/_incident_filterbox.html", context=context)
else:
request.session["selected_filter"] = None
if request.htmx.trigger:
incident_list_filter = get_filter_function()
filter_form, _ = incident_list_filter(request, None, use_empty_filter=True)
context = {"filter_form": filter_form}
context = {"filter_form": filter_form, "kiosk_mode": kiosk_mode}
return render(request, "htmx/incident/_incident_filterbox.html", context=context)
else:
return retarget(HttpResponse(), "#incident-filter-select")
Expand Down Expand Up @@ -266,7 +273,7 @@ def search_tags(request):


@require_GET
def incident_list(request: HtmxHttpRequest) -> HttpResponse:
def incident_list(request: HtmxHttpRequest, kiosk_mode: bool = False) -> HttpResponse:
LOG = logging.getLogger(__name__ + ".incident_list")
LOG.debug("GET at start: %s", request.GET)
request.GET = dedupe_querydict(request.GET)
Expand All @@ -275,6 +282,8 @@ def incident_list(request: HtmxHttpRequest) -> HttpResponse:
preferences = request.user.get_preferences_context()
column_layout_name = preferences["argus_htmx"]["incidents_table_column_name"]
columns = get_incident_table_columns(column_layout_name)
if kiosk_mode:
columns = [c for c in columns if c.name != "row_select"]

# Handle sorting
sort_form = SortForm(request.GET)
Expand Down Expand Up @@ -345,6 +354,8 @@ def incident_list(request: HtmxHttpRequest) -> HttpResponse:
else:
base_template = "htmx/incident/_base.html"

incident_list_url = reverse(KIOSK_URL_NAME if kiosk_mode else "htmx:incident-list")

LOG.debug("GET at end: %s", request.GET)
context = {
"columns": columns,
Expand All @@ -358,5 +369,12 @@ def incident_list(request: HtmxHttpRequest) -> HttpResponse:
"page": page,
"last_page_num": last_page_num,
"second_to_last_page": last_page_num - 1,
"kiosk_mode": kiosk_mode,
"incident_list_url": incident_list_url,
}
return render(request, "htmx/incident/incident_list.html", context=context)


@require_GET
def incident_list_kiosk(request: HtmxHttpRequest) -> HttpResponse:
Comment thread
github-advanced-security[bot] marked this conversation as resolved.
Fixed
return incident_list(request, kiosk_mode=True)
20 changes: 20 additions & 0 deletions src/argus/htmx/templates/htmx/incident/_filter_controls.html
Original file line number Diff line number Diff line change
Expand Up @@ -49,4 +49,24 @@
<i class="fa-solid fa-chevron-up fa-xs filter-collapse-icon"
aria-hidden="true"></i>
</button>
{% if kiosk_mode %}
<a href="{% url 'htmx:incident-list' %}" class="btn btn-sm btn-ghost">
Comment thread
aleksfl marked this conversation as resolved.
Outdated
<i class="fa-solid fa-xmark fa-xs" aria-hidden="true"></i>
Exit kiosk
</a>
<span class="text-sm font-medium ml-1">
<span class="opacity-60">After filtering:</span>
<span id="kiosk-filtered-count">{{ refresh_info.filtered_count }}</span>
</span>
<span class="text-sm font-medium ml-1">
<span class="opacity-60">Last refreshed:</span>
<span id="kiosk-last-refreshed">{{ refresh_info.last_refreshed|date:preferences.argus_htmx.datetime_format|default:"?" }}</span>
</span>
{% else %}
<a href="{% url 'htmx:incident-list-kiosk' %}"
class="btn btn-sm btn-ghost">
Comment thread
aleksfl marked this conversation as resolved.
Outdated
<i class="fa-solid fa-display fa-xs" aria-hidden="true"></i>
Kiosk
</a>
{% endif %}
</div>
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
<script>
const KIOSK_MODE = {{ kiosk_mode|yesno:"true,false" }};
const FILTER_SELECT_URL = '{% url "htmx:select-filter" %}';
const FILTER_UPDATE_URL_TEMPLATE = '{% url "htmx:filter-update" pk=0 %}'.replace('/0/', '/{id}/');
const FILTER_DELETE_URL_TEMPLATE = '{% url "htmx:filter-delete" pk=0 %}'.replace('/0/', '/{id}/');
Expand Down Expand Up @@ -93,7 +94,9 @@
const box = document.getElementById('filter-controls-box');
box.classList.toggle('filters-collapsed');
const collapsed = box.classList.contains('filters-collapsed');
localStorage.setItem('argus_show_filters', collapsed ? 'false' : 'true');
if (!KIOSK_MODE) {
localStorage.setItem('argus_show_filters', collapsed ? 'false' : 'true');
}
btn.setAttribute('aria-expanded', collapsed ? 'false' : 'true');
}

Expand All @@ -111,7 +114,7 @@
});

document.addEventListener('DOMContentLoaded', () => {
if (localStorage.getItem('argus_show_filters') === 'false') {
if (KIOSK_MODE || localStorage.getItem('argus_show_filters') === 'false') {
document.getElementById('filter-controls-box')?.classList.add('filters-collapsed');
document.getElementById('filter-toggle-btn')?.setAttribute('aria-expanded', 'false');
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,12 @@
{% load widget_tweaks %}
{% if kiosk_mode %}
{% url 'htmx:incident-list-kiosk' as incident_list_url %}
{% else %}
{% url 'htmx:incident-list' as incident_list_url %}
{% endif %}
<form id="incident-filter-box"
class="incident-list-param"
hx-get="{% url 'htmx:incident-list' %}"
hx-get="{{ incident_list_url }}"
hx-include=".incident-list-param"
{% block filter_trigger_control %}
hx-trigger="keydown[keyCode==13], change delay:100ms, load once"
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{# djlint:off #}
{% with preferences.argus_htmx.update_interval as update_interval %}
{% if update_interval != 'never' %}
hx-get="{% url 'htmx:incident-list' %}"
hx-get="{{ incident_list_url }}"
hx-vals='{"page": "{{ page.number }}"}'
hx-target="this"
hx-swap="outerHTML"
Expand Down
24 changes: 13 additions & 11 deletions src/argus/htmx/templates/htmx/incident/_incident_table_footer.html
Original file line number Diff line number Diff line change
@@ -1,21 +1,23 @@
<!-- htmx/incident/_incident_table_footer.html -->
<tfoot id="table-footer">
<tr class="sticky bottom-0 bg-base-100">
<td colspan="{{ columns|length }}" class="border-t border-primary">
<div class="flex justify-between items-center">
{% block refresh_info %}
{% include "htmx/incident/_incident_list_refresh_info.html" %}
{% endblock refresh_info %}
{% include "./_incident_table_paginator.html" %}
</div>
</td>
</tr>
{% if not kiosk_mode %}
<tr class="sticky bottom-0 bg-base-100">
<td colspan="{{ columns|length }}" class="border-t border-primary">
<div class="flex justify-between items-center">
{% block refresh_info %}
{% include "htmx/incident/_incident_list_refresh_info.html" %}
{% endblock refresh_info %}
{% include "./_incident_table_paginator.html" %}
</div>
</td>
</tr>
{% endif %}
</tfoot>
<!-- Include in footer of incident table to add scroll shadows to header and footer -->
<script>
(() => {
const table = document.querySelector("#table");
const elements = [table.querySelector("thead tr"), table.querySelector("tfoot tr")]
const elements = [table.querySelector("thead tr"), table.querySelector("tfoot tr")].filter(Boolean);

elements.forEach((el) => {
const intercept = document.createElement("div");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
displayed as clickable.
-->
<li>
<a hx-get="{% url 'htmx:incident-list' %}"
<a hx-get="{{ incident_list_url }}"
hx-vals='{"page": "{{ page_number }}"}'
href="{% querystring page=page_number %}"
hx-indicator="#incident-list .htmx-indicator"
Expand Down
10 changes: 6 additions & 4 deletions src/argus/htmx/templates/htmx/incident/_incident_toolbar.html
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,10 @@
{% include "htmx/incident/_incident_filterbox.html" %}
</div>
</div>
<div id="bulk-actions"
class="hidden flex gap-2 w-fit border-2 border-primary/50 bg-primary/10 rounded-box p-1">
{% include "htmx/incident/_incident_list_update_menu.html" %}
</div>
{% if not kiosk_mode %}
<div id="bulk-actions"
class="hidden flex gap-2 w-fit border-2 border-primary/50 bg-primary/10 rounded-box p-1">
{% include "htmx/incident/_incident_list_update_menu.html" %}
</div>
{% endif %}
</section>
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,11 @@
tabindex="-1">
<form class="incident-list-param">
{% if not dummy_column %}
{% url 'htmx:incident-list' as incident_list_url %}
{% if kiosk_mode %}
{% url 'htmx:incident-list-kiosk' as incident_list_url %}
{% else %}
{% url 'htmx:incident-list' as incident_list_url %}
{% endif %}
{% endif %}
{# djlint:off #}
<div aria-labelledby="{{ field.name }}-label" {% if not dummy_column %}hx-get="{{ incident_list_url }}" hx-include=".incident-list-param" hx-target="#table-body" hx-select="#table-body" hx-select-oob="#table-footer" hx-swap="outerHTML" hx-push-url="true" hx-indicator="#incident-list .htmx-indicator" hx-trigger="change delay:500ms"{% endif %}>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
class="btn btn-xs btn-ghost p-0 aspect-square min-h-4 h-4 {% if active %}text-primary{% else %}text-base-content/50 hover:text-primary{% endif %}"
aria-label="{{ label }}"
{% if dummy_column %}disabled{% endif %}
hx-get="{% url 'htmx:incident-list' %}"
hx-get="{{ incident_list_url }}"
hx-vals='{"sort": "{{ next_sort }}", "sort_order": "{{ next_order }}"}'
hx-include=".incident-list-param"
hx-target="#table"
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
<!-- htmx/incident/cells/search_fields/input_search.html -->
{% url 'htmx:incident-list' as incident_list_url %}
Comment thread
aleksfl marked this conversation as resolved.
<div class="flex gap-1 input input-xs grow input-primary pr-0 group">
<input name="{{ widget.name }}"
type="text"
Expand Down
Original file line number Diff line number Diff line change
@@ -1,2 +1,6 @@
{% block table %}
{% endblock table %}
{% if kiosk_mode %}
<span hx-swap-oob="innerHTML:#kiosk-filtered-count">{{ refresh_info.filtered_count }}</span>
<span hx-swap-oob="innerHTML:#kiosk-last-refreshed">{{ refresh_info.last_refreshed|date:preferences.argus_htmx.datetime_format|default:"?" }}</span>
{% endif %}
Loading
Loading