From c853153533cc17b6d6149d8c43fc7c721f830425 Mon Sep 17 00:00:00 2001 From: Tobias Kunze Date: Tue, 9 Dec 2025 15:53:02 +0100 Subject: [PATCH] Prettier rendering for JSON data on instance page --- .../service_instance_detail.html | 12 +---- .../frontend/templatetags/pprint_filters.py | 45 +++++++++++++++++++ src/servala/static/js/fqdn.js | 4 +- 3 files changed, 48 insertions(+), 13 deletions(-) diff --git a/src/servala/frontend/templates/frontend/organizations/service_instance_detail.html b/src/servala/frontend/templates/frontend/organizations/service_instance_detail.html index a906315..06ef5df 100644 --- a/src/servala/frontend/templates/frontend/organizations/service_instance_detail.html +++ b/src/servala/frontend/templates/frontend/organizations/service_instance_detail.html @@ -182,11 +182,7 @@ {% for field in fieldset.fields %}
{{ field.label }}
- {% if field.value|default:""|stringformat:"s"|slice:":1" == "{" or field.value|default:""|stringformat:"s"|slice:":1" == "[" %} -
{{ field.value|pprint }}
- {% else %} - {{ field.value|default:"-" }} - {% endif %} + {{ field.value|render_tree }}
{% endfor %} @@ -197,11 +193,7 @@ {% for field in sub_fieldset.fields %}
{{ field.label }}
- {% if field.value|default:""|stringformat:"s"|slice:":1" == "{" or field.value|default:""|stringformat:"s"|slice:":1" == "[" %} -
{{ field.value|pprint }}
- {% else %} - {{ field.value|default:"-" }} - {% endif %} + {{ field.value|render_tree }}
{% endfor %} diff --git a/src/servala/frontend/templatetags/pprint_filters.py b/src/servala/frontend/templatetags/pprint_filters.py index 4a0342f..a5627aa 100644 --- a/src/servala/frontend/templatetags/pprint_filters.py +++ b/src/servala/frontend/templatetags/pprint_filters.py @@ -50,3 +50,48 @@ def localtime_tag(value, format_str="datetime"): format_str, iso_value, ) + + +@register.filter +def render_tree(value, key=""): + """ + Render a nested dict/list as a collapsible tree structure. + Used for displaying JSON parameters in a user-friendly way. + """ + if value is None: + return mark_safe('-') + + if isinstance(value, bool): + badge_class = "bg-success" if value else "bg-secondary" + return format_html( + '{}', + badge_class, + "Yes" if value else "No", + ) + + if isinstance(value, (str, int, float)): + if isinstance(value, str) and len(value) > 100: + return format_html("{}", value) + return format_html("{}", value) + + if isinstance(value, list): + if not value: + return mark_safe('[]') + items = [] + for item in value: + items.append(f"
  • {render_tree(item)}
  • ") + return mark_safe(f'') + + if isinstance(value, dict): + if not value: + return mark_safe('{}') + items = [] + for k, v in value.items(): + rendered_value = render_tree(v, k) + items.append( + f'
    {deslugify(k)}
    ' + f'
    {rendered_value}
    ' + ) + return mark_safe(f'
    {"".join(items)}
    ') + + return format_html("{}", str(value)) diff --git a/src/servala/static/js/fqdn.js b/src/servala/static/js/fqdn.js index 9f8506c..86964c4 100644 --- a/src/servala/static/js/fqdn.js +++ b/src/servala/static/js/fqdn.js @@ -73,9 +73,7 @@ const runFqdnInit = () => { initializeFqdnGeneration("expert"); } -document.addEventListener('DOMContentLoaded', () => { - runFqdnInit() -}); +document.addEventListener('DOMContentLoaded', runFqdnInit) document.body.addEventListener('htmx:afterSwap', function(event) { if (event.detail.target.id === 'service-form') runFqdnInit() });