mirror of
https://github.com/ChuckBuilds/LEDMatrix.git
synced 2026-08-01 16:58:06 +00:00
The primary rotation's order was invisible and unconfigurable: modes are registered in parallel-load COMPLETION order, so rotation order actually varied between restarts. Only the niche Vegas Scroll mode had a working order UI. This adds real, persisted ordering end to end: Backend: - config.template.json: new display.plugin_rotation_order (default [], fully backward compatible). - display_controller.py: _apply_plugin_rotation_order() rebuilds available_modes grouped by plugin per the configured list (each plugin's modes keep their declared order; unlisted plugins follow in existing relative order; empty config = exact no-op). Applied at startup after parallel load and after live enable/disable reconcile (before the existing _resync_mode_index_after_change, which preserves the current mode). Mirrors vegas_mode get_ordered_plugins() semantics. - api_v3.py save_main_config: accepts plugin_rotation_order as a JSON array (same parse/guard pattern as vegas_plugin_order). Frontend: - New shared widget static/v3/js/widgets/plugin-order-list.js: the Vegas section's drag-and-drop list factored out verbatim (native HTML5 drag events, saved-order-first rendering, hidden-input JSON sync), parameterized by container/order-input/optional exclude-checkbox/badge. - display.html: Vegas section now calls the shared module; its ~130-line inline copy of the same logic is deleted. - durations.html: new "Rotation Order" card above the durations grid using the same module, posting plugin_rotation_order with the existing form. Deviation from plan, deliberate: durations stay as their own mode-keyed grid rather than inline in the drag rows - verified display_durations keys are MODE names (display_controller.py resolves duration per mode_key), not plugin ids, and one plugin can own several modes, so the planned 1:1 inline pairing was wrong. Validation: py_compile on both Python files; _apply_plugin_rotation_order unit-tested standalone (configured order applied, empty-config no-op, unknown ids skipped - 3/3); both templates render with balanced divs, the hidden input carries the saved order, and the old inline implementation is confirmed gone; config.template.json parses. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01KEZK1P1Q1fu5pcuVrkrCFZ
83 lines
3.9 KiB
HTML
83 lines
3.9 KiB
HTML
{% import 'v3/partials/_macros.html' as ui %}
|
||
<div class="bg-white rounded-lg shadow p-6">
|
||
<div class="border-b border-gray-200 pb-4 mb-6">
|
||
<h2 class="text-lg font-semibold text-gray-900">Display Durations</h2>
|
||
<p class="mt-1 text-sm text-gray-600">Configure how long each screen is shown before switching. Values in seconds.</p>
|
||
</div>
|
||
|
||
{{ ui.settings_filter() }}
|
||
|
||
<form hx-post="/api/v3/config/main"
|
||
hx-ext="json-enc"
|
||
hx-headers='{"Content-Type": "application/json"}'
|
||
hx-swap="none"
|
||
hx-on:htmx:after-request="showNotification(event.detail.xhr.responseJSON?.message || 'Durations saved', event.detail.xhr.responseJSON?.status || 'success')"
|
||
class="space-y-6"
|
||
novalidate
|
||
onsubmit="fixInvalidNumberInputs(this); return true;">
|
||
|
||
<!-- Primary rotation order: drag to reorder which plugin shows first,
|
||
second, ... in the normal display rotation. Saved as
|
||
display.plugin_rotation_order and applied by the display
|
||
controller on startup and live plugin enable/disable. -->
|
||
<div class="bg-gray-50 rounded-lg p-4">
|
||
<h3 class="text-md font-medium text-gray-900 mb-1">Rotation Order</h3>
|
||
<p class="text-sm text-gray-600 mb-3">Drag plugins to set the order they rotate on the display. Each plugin's screens keep their own order within its turn. Takes effect after saving and restarting the display.</p>
|
||
<div id="rotation_plugin_order" class="space-y-2 bg-white rounded-lg p-3 border border-gray-200">
|
||
<p class="text-sm text-gray-500 italic">Loading plugins…</p>
|
||
</div>
|
||
<input type="hidden" id="rotation_plugin_order_value" name="plugin_rotation_order"
|
||
value='{{ main_config.display.get("plugin_rotation_order", [])|tojson }}'>
|
||
</div>
|
||
|
||
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4">
|
||
{% for key, value in main_config.display.display_durations.items() %}
|
||
<div class="form-group" id="setting-durations-{{ key }}" data-setting-key="display.display_durations.{{ key }}">
|
||
<label for="duration_{{ key }}" class="block text-sm font-medium text-gray-700">
|
||
{{ key | replace('_', ' ') | title }}{{ ui.help_tip('How long the ' ~ (key | replace('_', ' ')) ~ ' screen stays on before rotating to the next one, in seconds.\nRange: 5–600. Currently ' ~ value ~ 's.', key | replace('_', ' ') | title) }}
|
||
</label>
|
||
<input type="number"
|
||
id="duration_{{ key }}"
|
||
name="{{ key }}"
|
||
value="{{ value }}"
|
||
min="5"
|
||
max="600"
|
||
class="form-control">
|
||
</div>
|
||
{% endfor %}
|
||
</div>
|
||
|
||
<!-- Submit Button -->
|
||
<div class="flex justify-end">
|
||
<button type="submit"
|
||
class="btn bg-blue-600 hover:bg-blue-700 text-white px-4 py-2 rounded-md">
|
||
<i class="fas fa-save mr-2"></i>
|
||
Save Durations
|
||
</button>
|
||
</div>
|
||
</form>
|
||
</div>
|
||
|
||
<script>
|
||
(function () {
|
||
// Shared drag-and-drop plugin list (static/v3/js/widgets/plugin-order-list.js,
|
||
// same module the Vegas Scroll section uses).
|
||
function initRotationOrderList() {
|
||
if (!document.getElementById('rotation_plugin_order')) return;
|
||
if (!window.PluginOrderList) {
|
||
setTimeout(initRotationOrderList, 100);
|
||
return;
|
||
}
|
||
window.PluginOrderList.init({
|
||
containerId: 'rotation_plugin_order',
|
||
orderInputId: 'rotation_plugin_order_value'
|
||
});
|
||
}
|
||
if (document.readyState === 'loading') {
|
||
document.addEventListener('DOMContentLoaded', initRotationOrderList);
|
||
} else {
|
||
initRotationOrderList();
|
||
}
|
||
}());
|
||
</script>
|