Prettier rendering for JSON data on instance page

This commit is contained in:
Tobias Kunze 2025-12-09 15:53:02 +01:00
parent 2527a73bb6
commit c853153533
3 changed files with 48 additions and 13 deletions

View file

@ -182,11 +182,7 @@
{% for field in fieldset.fields %} {% for field in fieldset.fields %}
<dt class="col-sm-3">{{ field.label }}</dt> <dt class="col-sm-3">{{ field.label }}</dt>
<dd class="col-sm-9"> <dd class="col-sm-9">
{% if field.value|default:""|stringformat:"s"|slice:":1" == "{" or field.value|default:""|stringformat:"s"|slice:":1" == "[" %} {{ field.value|render_tree }}
<pre>{{ field.value|pprint }}</pre>
{% else %}
{{ field.value|default:"-" }}
{% endif %}
</dd> </dd>
{% endfor %} {% endfor %}
</dl> </dl>
@ -197,11 +193,7 @@
{% for field in sub_fieldset.fields %} {% for field in sub_fieldset.fields %}
<dt class="col-sm-3">{{ field.label }}</dt> <dt class="col-sm-3">{{ field.label }}</dt>
<dd class="col-sm-9"> <dd class="col-sm-9">
{% if field.value|default:""|stringformat:"s"|slice:":1" == "{" or field.value|default:""|stringformat:"s"|slice:":1" == "[" %} {{ field.value|render_tree }}
<pre>{{ field.value|pprint }}</pre>
{% else %}
{{ field.value|default:"-" }}
{% endif %}
</dd> </dd>
{% endfor %} {% endfor %}
</dl> </dl>

View file

@ -50,3 +50,48 @@ def localtime_tag(value, format_str="datetime"):
format_str, format_str,
iso_value, 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('<span class="text-muted">-</span>')
if isinstance(value, bool):
badge_class = "bg-success" if value else "bg-secondary"
return format_html(
'<span class="badge {}">{}</span>',
badge_class,
"Yes" if value else "No",
)
if isinstance(value, (str, int, float)):
if isinstance(value, str) and len(value) > 100:
return format_html("<code>{}</code>", value)
return format_html("<span>{}</span>", value)
if isinstance(value, list):
if not value:
return mark_safe('<span class="text-muted">[]</span>')
items = []
for item in value:
items.append(f"<li>{render_tree(item)}</li>")
return mark_safe(f'<ul class="list-unstyled mb-0 ps-3">{"".join(items)}</ul>')
if isinstance(value, dict):
if not value:
return mark_safe('<span class="text-muted">{}</span>')
items = []
for k, v in value.items():
rendered_value = render_tree(v, k)
items.append(
f'<dt class="col-sm-4 text-truncate" title="{k}">{deslugify(k)}</dt>'
f'<dd class="col-sm-8">{rendered_value}</dd>'
)
return mark_safe(f'<dl class="row mb-0">{"".join(items)}</dl>')
return format_html("<span>{}</span>", str(value))

View file

@ -73,9 +73,7 @@ const runFqdnInit = () => {
initializeFqdnGeneration("expert"); initializeFqdnGeneration("expert");
} }
document.addEventListener('DOMContentLoaded', () => { document.addEventListener('DOMContentLoaded', runFqdnInit)
runFqdnInit()
});
document.body.addEventListener('htmx:afterSwap', function(event) { document.body.addEventListener('htmx:afterSwap', function(event) {
if (event.detail.target.id === 'service-form') runFqdnInit() if (event.detail.target.id === 'service-form') runFqdnInit()
}); });