Files
LEDMatrix/web_interface/templates/v3/partials/general.html
T
ChuckandClaude Opus 5 9e1ebd9c17 fix(web): remove the General-tab plugin system toggles that did nothing
plugin_system.auto_discover, auto_load_enabled and development_mode had
General-tab toggles whose help tips promised dormant plugins and verbose
logging, but nothing reads them: every enabled plugin is discovered and
loaded regardless. Remove the three toggles.

The keys stay tolerated in stored configs. The save handler now stores
a flag only when a client sends it; treating a missing key as an
unchecked box would otherwise rewrite all three to false on every
General-tab save, which still posts plugins_directory.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-17 08:52:40 -04:00

197 lines
11 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">General Settings</h2>
<p class="mt-1 text-sm text-gray-600">Configure general system settings and location information.</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="
var xhr = event.detail.xhr;
var isSuccess = xhr.status >= 200 && xhr.status < 300;
var message = '';
var status = 'success';
try {
var data = JSON.parse(xhr.responseText);
message = data.message || '';
status = data.status || status;
} catch (e) {}
if (isSuccess) {
message = message || 'Settings saved';
} else {
message = message || 'Failed to save settings';
status = 'error';
}
showNotification(message, status);
"
class="space-y-6">
<!-- Web Display Autostart -->
<div class="form-group" id="setting-general-web_display_autostart" data-setting-key="web_display_autostart">
<label class="flex items-center">
<input type="checkbox"
name="web_display_autostart"
value="true"
{% if main_config.web_display_autostart %}checked{% endif %}
class="form-control h-4 w-4 text-blue-600 focus:ring-blue-500 border-gray-300 rounded">
<span class="ml-2 text-sm font-medium text-gray-900">Web Display Autostart</span>
{{ ui.help_tip('Automatically start the web interface when the device boots.\nDefault: on. Turn off if you launch the web UI manually or run headless.', 'Web Display Autostart') }}
</label>
</div>
<!-- Weekly Automatic Updates -->
<div class="form-group" id="setting-general-auto_update" data-setting-key="auto_update.enabled">
<label class="flex items-center">
<input type="checkbox"
name="auto_update_enabled"
value="true"
{% if (main_config.auto_update or {}).enabled %}checked{% endif %}
class="form-control h-4 w-4 text-blue-600 focus:ring-blue-500 border-gray-300 rounded">
<span class="ml-2 text-sm font-medium text-gray-900">Automatically check for and install updates once a week</span>
{{ ui.help_tip('Once a week, update LEDMatrix and every installed plugin that has a newer version.\nSkipped (and reported) if you have local changes, low disk space, or the rollback service is missing. After updating, the services are restarted and checked; if they do not stay healthy, the update is rolled back automatically.\nRuns overnight (2-5 AM in your timezone) when possible. Problems show as a banner on Overview. A stopped display is not started. Default: off.', 'Automatic Updates') }}
</label>
{% if auto_update_status and (main_config.auto_update or {}).enabled and auto_update_status.verifier_installed is sameas false %}
<p class="mt-1 ml-6 text-xs text-amber-700">
{% if auto_update_status.setup_status == 'failed' %}
Setting up the update health check failed: {{ auto_update_status.setup_message }}
LEDMatrix code updates are paused until it is fixed; plugin updates still run.
{% else %}
Setting up the update health check. The display service does this when it starts, so it is
ready shortly after saving (or once the display is started). LEDMatrix code updates begin after that.
{% endif %}
</p>
{% endif %}
{% if auto_update_status and auto_update_status.verifying %}
<p class="mt-1 ml-6 text-xs text-blue-700">An update was just installed and its health check is running.</p>
{% endif %}
{% if auto_update_status and (auto_update_status.last_run or auto_update_status.next_due) %}
<div class="mt-1 ml-6 text-xs text-gray-500 space-y-1">
{% if auto_update_status.last_run %}
<p>Last automatic update: {{ auto_update_status.last_run }}
<span class="{{ 'text-red-600' if auto_update_status.status == 'error' else '' }}">— {{ auto_update_status.summary }}</span></p>
{% endif %}
{% if auto_update_status.next_due %}
<p>Next check: {{ auto_update_status.next_due }} or the first overnight window after it</p>
{% endif %}
</div>
{% endif %}
</div>
<!-- Timezone -->
<div class="form-group" id="setting-general-timezone" data-setting-key="timezone">
<label for="timezone" class="block text-sm font-medium text-gray-700">Timezone{{ ui.help_tip('Time zone used for clocks, schedules, and time-based content.\nChoose the zone where the display physically lives so on/off schedules fire at the correct local time.', 'Timezone') }}</label>
<div id="timezone_container" class="mt-1"></div>
</div>
<!-- Scroll frame rate (device-wide) -->
<div class="form-group" id="setting-general-target-fps" data-setting-key="target_fps">
<label for="target_fps" class="block text-sm font-medium text-gray-700">Scroll Frame Rate{{ ui.help_tip('Frames per second for scrolling content, applied across plugins that scroll.\nHigher is smoother but uses more CPU; lower frees CPU but looks steppier.\nRange 30-200. Default: 100.', 'Scroll Frame Rate') }}</label>
<input type="number"
id="target_fps"
name="target_fps"
value="{{ main_config.target_fps or 100 }}"
min="30"
max="200"
class="form-control">
</div>
<script>
(function() {
// Track if already initialized to prevent re-render
if (window.__timezoneWidgetInitialized) return;
function initTimezoneWidget() {
if (!window.LEDMatrixWidgets) { setTimeout(initTimezoneWidget, 50); return; }
var widget = window.LEDMatrixWidgets.get('timezone-selector');
if (!widget) { setTimeout(initTimezoneWidget, 50); return; }
var container = document.getElementById('timezone_container');
if (!container) return;
// Only render if container is empty (not already rendered)
if (container.children.length > 0) return;
widget.render(container, {
'x-options': { showOffset: true, placeholder: 'Select your timezone...' }
}, {{ (main_config.timezone or "America/Chicago")|tojson }}, {
fieldId: 'timezone',
name: 'timezone'
});
window.__timezoneWidgetInitialized = true;
}
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', initTimezoneWidget);
} else {
setTimeout(initTimezoneWidget, 50);
}
})();
</script>
<!-- Location Information -->
<div class="grid grid-cols-1 md:grid-cols-3 xl:grid-cols-3 2xl:grid-cols-3 gap-4">
<div class="form-group" id="setting-general-city" data-setting-key="location.city">
<label for="city" class="block text-sm font-medium text-gray-700">City{{ ui.help_tip('City used for weather, sunrise/sunset, radar, and other location-based content.\nExample: Kansas City.\nUsed as the default for the location_city setting on plugins that have one; a value saved on the plugin itself overrides it.', 'City') }}</label>
<input type="text"
id="city"
name="city"
value="{{ main_config.location.city or 'Dallas' }}"
class="form-control">
</div>
<div class="form-group" id="setting-general-state" data-setting-key="location.state">
<label for="state" class="block text-sm font-medium text-gray-700">State{{ ui.help_tip('State or region for your location.\nExample: Missouri. Improves location-lookup accuracy.\nUsed as the default for the location_state setting on plugins that have one.', 'State') }}</label>
<input type="text"
id="state"
name="state"
value="{{ main_config.location.state or 'Texas' }}"
class="form-control">
</div>
<div class="form-group" id="setting-general-country" data-setting-key="location.country">
<label for="country" class="block text-sm font-medium text-gray-700">Country{{ ui.help_tip('Country code or name for your location.\nExample: US. Used with City and State for weather, radar, and geolocation.\nUsed as the default for the location_country setting on plugins that have one.', 'Country') }}</label>
<input type="text"
id="country"
name="country"
value="{{ main_config.location.country or 'US' }}"
class="form-control">
</div>
</div>
<!-- Plugin System Settings -->
<div class="border-t border-gray-200 pt-6 mt-6">
<h3 class="text-lg font-semibold text-gray-900 mb-4">Plugin System Settings</h3>
<p class="text-sm text-gray-600 mb-4">Configure the core plugin system behavior.</p>
<div class="space-y-4">
<!-- plugin_system.auto_discover, auto_load_enabled and
development_mode used to be toggles here. Nothing reads
them: plugins are always discovered and every enabled
plugin is loaded. Stored values are left alone. -->
<!-- Plugins Directory -->
<div class="form-group" id="setting-general-plugins_directory" data-setting-key="plugin_system.plugins_directory">
<label for="plugins_directory" class="block text-sm font-medium text-gray-700">Plugins Directory{{ ui.help_tip('Folder (relative to the project root) where plugins are stored.\nDefault: plugin-repos. Only change this if you keep plugins in a custom location.', 'Plugins Directory') }}</label>
<input type="text"
id="plugins_directory"
name="plugins_directory"
value="{{ main_config.get('plugin_system', {}).get('plugins_directory', 'plugin-repos') }}"
placeholder="plugin-repos"
class="form-control">
</div>
</div>
</div>
<!-- Submit Button -->
<div class="flex justify-end mt-6">
<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 General Settings
</button>
</div>
</form>
</div>