mirror of
https://github.com/ChuckBuilds/LEDMatrix.git
synced 2026-04-11 13:23:00 +00:00
Add array-of-objects widget support to server-side template
Add detection and rendering for array-of-objects in the Jinja2 template (plugin_config.html). This enables the custom_feeds widget to display properly with name, URL, enabled checkbox, and logo upload fields. The widget is detected by checking if prop.items.type == 'object' && prop.items.properties, and is rendered before the file-upload widget check.
This commit is contained in:
@@ -58,10 +58,115 @@
|
||||
{% if field_type == 'integer' %}step="1"{% else %}step="any"{% endif %}
|
||||
class="form-input w-full rounded-md border-gray-300 shadow-sm focus:border-blue-500 focus:ring-blue-500 bg-white text-black placeholder:text-gray-500">
|
||||
|
||||
{# Array - check if it's a file upload widget #}
|
||||
{# Array - check if it's an array of objects first, then file upload widget #}
|
||||
{% elif field_type == 'array' %}
|
||||
{% set x_widget = prop.get('x-widget') or prop.get('x_widget') %}
|
||||
{% if x_widget == 'file-upload' %}
|
||||
{% set items_schema = prop.get('items') or {} %}
|
||||
{% set is_array_of_objects = items_schema.get('type') == 'object' and items_schema.get('properties') %}
|
||||
{% if is_array_of_objects %}
|
||||
{# Array of objects widget (like custom_feeds with name, url, enabled, logo) #}
|
||||
{% set item_properties = items_schema.get('properties', {}) %}
|
||||
{% set max_items = prop.get('maxItems', 50) %}
|
||||
{% set array_value = value if value is not none and value is iterable and value is not string else (prop.default if prop.default is defined and prop.default is iterable and prop.default is not string else []) %}
|
||||
|
||||
<div class="array-of-objects-container mt-1">
|
||||
<div id="{{ field_id }}_items" class="space-y-4">
|
||||
{% for item in array_value %}
|
||||
{% set item_index = loop.index0 %}
|
||||
<div class="border border-gray-300 rounded-lg p-4 bg-gray-50 array-object-item" data-index="{{ item_index }}">
|
||||
{% for prop_key, prop_schema in item_properties.items() %}
|
||||
{% set prop_value = item.get(prop_key, prop_schema.get('default')) %}
|
||||
{% set prop_label = prop_schema.get('title') or prop_key|replace('_', ' ')|title %}
|
||||
{% set prop_description = prop_schema.get('description') or '' %}
|
||||
{% set prop_full_key = full_key ~ '[' ~ item_index ~ '].' ~ prop_key %}
|
||||
{% set prop_field_id = field_id ~ '_item_' ~ item_index ~ '_' ~ prop_key %}
|
||||
|
||||
<div class="mb-3">
|
||||
{% if prop_schema.get('x-widget') == 'file-upload' %}
|
||||
{# File upload widget for logo field #}
|
||||
{% set upload_config = prop_schema.get('x-upload-config') or {} %}
|
||||
{% set plugin_id_from_config = upload_config.get('plugin_id', plugin_id) %}
|
||||
{% set allowed_types = upload_config.get('allowed_types', ['image/png', 'image/jpeg', 'image/bmp']) %}
|
||||
|
||||
<label class="block text-sm font-medium text-gray-700 mb-1">{{ prop_label }}</label>
|
||||
{% if prop_description %}
|
||||
<p class="text-xs text-gray-500 mb-2">{{ prop_description }}</p>
|
||||
{% endif %}
|
||||
|
||||
<div class="file-upload-widget-inline">
|
||||
<input type="file"
|
||||
id="{{ prop_field_id }}_file"
|
||||
accept="{{ allowed_types|join(',') }}"
|
||||
style="display: none;"
|
||||
onchange="handleArrayObjectFileUpload(event, '{{ field_id }}', {{ item_index }}, '{{ prop_key }}', '{{ plugin_id_from_config }}')">
|
||||
<button type="button"
|
||||
onclick="document.getElementById('{{ prop_field_id }}_file').click()"
|
||||
class="px-3 py-2 text-sm bg-gray-200 hover:bg-gray-300 text-gray-700 rounded-md transition-colors">
|
||||
<i class="fas fa-upload mr-1"></i> Upload Logo
|
||||
</button>
|
||||
|
||||
{% if prop_value and prop_value.get('path') %}
|
||||
<div class="mt-2 flex items-center space-x-2" data-file-data='{{ prop_value|tojson|safe }}' data-prop-key="{{ prop_key }}">
|
||||
<img src="/{{ prop_value.get('path') }}" alt="Logo" class="w-16 h-16 object-cover rounded border">
|
||||
<button type="button"
|
||||
onclick="removeArrayObjectFile('{{ field_id }}', {{ item_index }}, '{{ prop_key }}')"
|
||||
class="text-red-600 hover:text-red-800">
|
||||
<i class="fas fa-trash"></i> Remove
|
||||
</button>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% elif prop_schema.get('type') == 'boolean' %}
|
||||
{# Boolean checkbox #}
|
||||
<label class="flex items-center">
|
||||
<input type="checkbox"
|
||||
id="{{ prop_field_id }}"
|
||||
data-prop-key="{{ prop_key }}"
|
||||
class="h-4 w-4 text-blue-600 focus:ring-blue-500 border-gray-300 rounded"
|
||||
{% if prop_value %}checked{% endif %}
|
||||
onchange="updateArrayObjectData('{{ field_id }}')">
|
||||
<span class="ml-2 text-sm text-gray-700">{{ prop_label }}</span>
|
||||
</label>
|
||||
{% else %}
|
||||
{# Regular text/string input #}
|
||||
<label for="{{ prop_field_id }}" class="block text-sm font-medium text-gray-700 mb-1">
|
||||
{{ prop_label }}
|
||||
</label>
|
||||
{% if prop_description %}
|
||||
<p class="text-xs text-gray-500 mb-1">{{ prop_description }}</p>
|
||||
{% endif %}
|
||||
<input type="text"
|
||||
id="{{ prop_field_id }}"
|
||||
data-prop-key="{{ prop_key }}"
|
||||
class="block w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-blue-500 focus:border-blue-500 sm:text-sm bg-white text-black"
|
||||
value="{{ prop_value if prop_value is not none else '' }}"
|
||||
placeholder="{% if prop_schema.get('format') == 'uri' %}https://example.com/feed{% endif %}"
|
||||
onchange="updateArrayObjectData('{{ field_id }}')">
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endfor %}
|
||||
|
||||
<div class="flex justify-end mt-2">
|
||||
<button type="button"
|
||||
onclick="removeArrayObjectItem('{{ field_id }}', {{ item_index }})"
|
||||
class="px-3 py-2 text-red-600 hover:text-red-800 hover:bg-red-50 rounded-md transition-colors"
|
||||
title="Remove Feed">
|
||||
<i class="fas fa-trash mr-1"></i> Remove Feed
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
|
||||
<button type="button"
|
||||
onclick="addArrayObjectItem('{{ field_id }}', '{{ full_key }}', {{ max_items }})"
|
||||
class="mt-3 px-4 py-2 text-sm bg-blue-600 hover:bg-blue-700 text-white rounded-md transition-colors"
|
||||
{% if array_value|length >= max_items %}disabled style="opacity: 0.5; cursor: not-allowed;"{% endif %}>
|
||||
<i class="fas fa-plus mr-1"></i> Add Feed
|
||||
</button>
|
||||
|
||||
<input type="hidden" id="{{ field_id }}_data" name="{{ full_key }}_data" value='{{ array_value|tojson|safe }}'>
|
||||
</div>
|
||||
{% elif prop.get('x-widget') == 'file-upload' or prop.get('x_widget') == 'file-upload' %}
|
||||
{# File upload widget for arrays #}
|
||||
{% set upload_config = prop.get('x-upload-config') or {} %}
|
||||
{% set max_files = upload_config.get('max_files', 10) %}
|
||||
|
||||
Reference in New Issue
Block a user