Commit Graph
42 Commits
Author SHA1 Message Date
Chuck 57aa7d101b fix: Add default value for AVAILABLE_SPACE to prevent TypeError
Fix crash when df produces unexpected output that results in empty
AVAILABLE_SPACE variable, causing 'integer expression expected' error.

Problem:
- df may produce unexpected output format (different locale, unusual
  filesystem name spanning lines, or non-standard df implementation)
- While '|| echo "0"' handles pipeline failures, it doesn't trigger if
  awk succeeds but produces no output (empty string)
- When AVAILABLE_SPACE is empty, comparison [ "$AVAILABLE_SPACE" -lt 500 ]
  fails with 'integer expression expected' error
- With set -e, this causes script to exit unexpectedly

Solution:
- Add AVAILABLE_SPACE=${AVAILABLE_SPACE:-0} before comparison to ensure
  variable always has a numeric value (defaults to 0 if empty)
- This gracefully handles edge cases where df/awk produces unexpected output
2026-01-08 13:41:30 -05:00
Chuck fc33bcf056 fix: Handle None value for feeds config to prevent TypeError
Fix crash when plugin_config['feeds'] exists but is None, causing
TypeError when checking 'custom_feeds' in feeds_config.

Problem:
- When plugin_config['feeds'] exists but is None, dict.get('feeds', {})
  returns None (not the default {}) because dict.get() only uses default
  when key doesn't exist, not when value is None
- Line 3642's 'custom_feeds' in feeds_config raises TypeError because
  None is not iterable
- This can crash the API endpoint if a plugin config has feeds: null

Solution:
- Change plugin_config.get('feeds', {}) to plugin_config.get('feeds') or {}
  to ensure feeds_config is always a dict (never None)
- Add feeds_config check before 'in' operator for extra safety

This ensures the code gracefully handles feeds: null in plugin configuration.
2026-01-08 13:40:12 -05:00
Chuck 77c68ce96a fix: Reorder array type checks to match template order
Fix inconsistent rendering where JavaScript and Jinja template had opposite
ordering for array type checks, causing schemas with both x-widget: file-upload
AND items.type: object (like static-image) to render differently.

Problem:
- Template checks file-upload FIRST (to avoid breaking static-image plugin)
- JavaScript checked array-of-objects FIRST
- Server-rendered forms showed file-upload widget correctly
- JS-rendered forms incorrectly displayed array-of-objects table widget

Solution:
- Reorder JavaScript checks to match template order:
  1. Check file-upload widget FIRST
  2. Check checkbox-group widget
  3. Check custom-feeds widget
  4. Check array-of-objects as fallback
  5. Regular array input (comma-separated)

This ensures consistent rendering between server-rendered and JS-rendered forms
for schemas that have both x-widget: file-upload AND items.type: object.
2026-01-08 13:35:39 -05:00
Chuck 520b87a198 fix: Expose renderArrayObjectItem to window for addArrayObjectItem
Fix scope issue where renderArrayObjectItem is defined inside IIFE but
window.addArrayObjectItem is defined outside, causing the function check
to always fail and fallback to degraded HTML rendering.

Problem:
- renderArrayObjectItem (line 2469) is inside IIFE (lines 796-6417)
- window.addArrayObjectItem (line 6422) is outside IIFE
- Check 'typeof renderArrayObjectItem === function' at line 6454 always fails
- Fallback code lacks file upload widgets, URL input types, descriptions, styling

Solution:
- Expose renderArrayObjectItem to window object before IIFE closes
- Function maintains closure access to escapeHtml and other IIFE-scoped functions
- Newly added items now have full functionality matching initially rendered items
2026-01-08 13:31:55 -05:00
Chuck 89f9876c92 fix: Add hidden input for enabled checkbox to ensure false is submitted
Add hidden input with value='false' before enabled checkbox in custom feeds
table to ensure an explicit false value is sent when checkbox is unchecked.

Pattern implemented:
- Hidden input: name='enabled', value='false' (always submitted)
- Checkbox: name='enabled', value='true' (only submitted when checked)
- When unchecked: only hidden input submits (false)
- When checked: both submit, checkbox value (true) overwrites hidden

Updated in two places:
- Template checkbox in plugin_config.html (existing rows)
- JavaScript addCustomFeedRow function in base.html (new rows)

Backend verification:
- Backend (api_v3.py) handles string boolean values and converts properly
- JavaScript form processing explicitly checks element.checked, independent of this pattern
- Standard form submission uses last value when multiple values share same name
2026-01-08 13:27:30 -05:00
Chuck 3f36c3aadc fix: Add image/gif to custom feed logo upload accept attribute
Update file input accept attributes for custom feed logo uploads to include
image/gif, making it consistent with the file-upload widget which also
allows GIF images.

Updated in three places:
- Template file input (plugin_config.html)
- JavaScript addCustomFeedRow function (base.html)
- Dynamic file input creation in handleCustomFeedLogoUpload (base.html)

All custom feed logo upload inputs now accept: image/png, image/jpeg,
image/bmp, image/gif
2026-01-08 13:24:48 -05:00
Chuck 89f07b8b79 fix: Make custom feeds table widget-specific instead of generic fallback
Replace generic array-of-objects check with widget-specific check for
'custom-feeds' widget to prevent hardcoded schema from breaking other
plugins with different array-of-objects structures.

Changes:
- Check for x-widget == 'custom-feeds' before rendering custom feeds table
- Add schema validation to ensure required fields (name, url) exist
- Show warning message if schema doesn't match expected structure
- Fall back to generic array input for other array-of-objects schemas
- Add comments for future generic array-of-objects support

This ensures the hardcoded custom feeds table (name, url, logo, enabled)
only renders when explicitly requested via widget type, preventing
breakage for other plugins with different array-of-objects schemas.
2026-01-08 12:43:04 -05:00
Chuck 0eb457fbc3 fix: Update upload button onclick when reindexing custom feed rows
Fix removeCustomFeedRow to update button onclick handlers that reference
file input IDs with _logo_<index> when rows are reindexed after deletion.

Previously, after deleting a row, the upload button's onclick still referenced
the old file input ID, causing the upload functionality to fail.

Now properly updates:
- getElementById('..._logo_<num>') patterns in onclick handlers
- Other _logo_<num> patterns in button onclick strings
- Function parameter indices in onclick handlers

This ensures upload buttons continue to work correctly after row deletion.
2026-01-08 12:31:26 -05:00
Chuck c80c23cd08 fix(security): Fix XSS vulnerability in handleCustomFeedLogoUpload
Replace innerHTML usage with safe DOM manipulation using createElement
and setAttribute to prevent XSS when injecting uploadedFile.path and
uploadedFile.id values.

- Clear logoCell using textContent instead of innerHTML
- Create all DOM elements using document.createElement
- Set uploadedFile.path and uploadedFile.id via setAttribute (automatically escaped)
- Properly structure DOM tree by appending elements in order
- Prevents malicious HTML/script injection through file path or ID values
2026-01-08 12:27:41 -05:00
Chuck b88842e672 fix(array-objects): Fix schema lookup, reindexing, and disable file upload
Address PR review feedback for array-of-objects helpers:

1. Schema resolution: Use getSchemaProperty() instead of manual traversal
   - Fixes nested array-of-objects schema lookup (e.g., news.custom_feeds)
   - Now properly descends through .properties for nested objects

2. Reindexing: Replace brittle regex with targeted patterns
   - Only replace index in bracket notation [0], [1], etc. for names
   - Only replace _item_<digits> pattern for IDs (not arbitrary digits)
   - Use specific function parameter patterns for onclick handlers
   - Prevents corruption of fieldId, pluginId, or other numeric values

3. File upload: Disable widget until properly implemented
   - Hide/disable upload button with clear message
   - Show existing logos if present but disable upload functionality
   - Prevents silent failures when users attempt to upload files
   - Added TODO comments for future implementation

Also fixes exit code handling in one-shot-install.sh to properly capture
first_time_install.sh exit status before error trap fires.
2026-01-08 12:26:08 -05:00
Chuck 38ffaf0188 fix: Remove accidental plugins/7-segment-clock submodule entry
Remove uninitialized submodule 'plugins/7-segment-clock' that was
accidentally included. This submodule is not related to the one-shot
installer feature and should not be part of this PR.

- Remove submodule entry from .gitmodules
- Remove submodule from git index
- Clean up submodule configuration
2026-01-08 12:17:26 -05:00
Chuck 19b6fc243f feat(install): Add one-shot installation script
- Create comprehensive one-shot installer with robust error handling
- Includes network checks, disk space validation, and retry logic
- Handles existing installations gracefully (idempotent)
- Updates README with quick install command prominently featured
- Manual installation instructions moved to collapsible section

The script provides explicit error messages and never fails silently.
All prerequisites are validated before starting installation.
2026-01-07 21:47:38 -05:00
Chuck a9a42812ac feat(web): Add checkbox-group widget support for plugin config arrays
Add server-side rendering support for checkbox-group widget in plugin
configuration forms. This allows plugins to use checkboxes for multi-select
array fields instead of comma-separated text inputs.

The implementation:
- Checks for x-widget: 'checkbox-group' in schema
- Renders checkboxes for each enum item in items.enum
- Supports custom labels via x-options.labels
- Works with any plugin that follows the pattern

Already used by:
- ledmatrix-news plugin (enabled_feeds)
- odds-ticker plugin (enabled_leagues)
2026-01-06 17:51:26 -05:00
Chuck a50afed7d1 Add fallback fix for feeds.custom_feeds dict-to-array conversion
- Add explicit fallback conversion for feeds.custom_feeds if fix_array_structures misses it
- This ensures the dict with numeric keys is converted to an array before validation
- Logo field is already optional in schema (not in required array)
2026-01-05 15:05:13 -05:00
Chuck a8c262f3b0 Fix custom feeds table issues
- Fix JavaScript error in removeCustomFeedRow (get tbody before removing row)
- Improve array conversion logic to handle nested paths like feeds.custom_feeds
- Add better error handling and debug logging for array conversion
- Ensure dicts with numeric keys are properly converted to arrays before validation
2026-01-05 14:57:42 -05:00
Chuck cefe17bd5f Add simple table interface for custom feeds
- Replace complex array-of-objects widget with clean table
- Table columns: Name, URL, Logo (upload), Enabled checkbox, Delete
- Use dot notation for form field names (feeds.custom_feeds.0.name)
- Add JavaScript functions for add/remove rows and logo upload
- Fix file-upload detection order to prevent breaking static-image plugin
2026-01-05 14:51:50 -05:00
Chuck a92078442e Replace complex array-of-objects widget with simple table interface
- Replace nested array-of-objects widget with clean table interface
- Table shows: Name, URL, Logo (with upload), Enabled checkbox, Delete button
- Fix file-upload widget detection order to prevent breaking static-image plugin
- Add simple JavaScript functions for add/remove rows and logo upload
- Much more intuitive and easier to use
2026-01-05 14:49:43 -05:00
Chuck 1b14e4e1ce Update cache version for syntax fix 2026-01-05 14:38:38 -05:00
Chuck f7d77de924 Fix syntax error: Add missing closing brace for else block 2026-01-05 14:38:32 -05:00
Chuck e0fff2c3f2 Update cache version for syntax fix 2026-01-05 14:38:13 -05:00
Chuck 927b893447 Add array-of-objects functions after IIFE ends
These functions must be outside the IIFE to be accessible from inline
event handlers in the server-rendered template.
2026-01-05 14:21:23 -05:00
Chuck 16928c0944 Fix: Remove all orphaned code and properly add array-of-objects functions after IIFE 2026-01-05 14:20:38 -05:00
Chuck 63bf14817e Update cache version for array-of-objects fix 2026-01-05 14:19:15 -05:00
Chuck 8803556920 Fix: Add array-of-objects functions after IIFE ends
The functions were removed from inside the IIFE but never added after it.
Also removed orphaned code that was causing syntax errors.
2026-01-05 14:19:08 -05:00
Chuck 8e86e58a2d Update cache version for IIFE fix 2026-01-05 14:17:50 -05:00
Chuck 1fa8e6ae50 Move array-of-objects functions outside IIFE to make them globally available
The functions were inside the IIFE scope, making them inaccessible from
inline event handlers. Moving them outside the IIFE ensures they're
available on window when the script loads.
2026-01-05 14:17:43 -05:00
Chuck e2b0ab2002 Update cache version for array-of-objects fix 2026-01-05 14:16:55 -05:00
Chuck b38027d7ad Fix: Wrap array-of-objects functions in window check and move outside IIFE
Ensure functions are available globally by wrapping them in a window check
and ensuring they're defined outside any IIFE scope. Also fix internal
function calls to use window.updateArrayObjectData for consistency.
2026-01-05 14:16:52 -05:00
Chuck 2993e67eb3 Add debug logging to diagnose addArrayObjectItem availability 2026-01-05 14:06:55 -05:00
Chuck be62ac62f9 Update cache version for syntax fix 2026-01-05 13:58:57 -05:00
Chuck ecea13909d Fix syntax error: Missing indentation for html += in array else block
The html += statement was outside the else block, causing a syntax error.
Fixed by properly indenting it inside the else block.
2026-01-05 13:58:53 -05:00
Chuck 6da2059b8c Use window. prefix for array-of-objects JavaScript functions
Explicitly use window.addArrayObjectItem, window.removeArrayObjectItem, etc.
in the template to ensure the functions are accessible from inline event handlers.
Also add safety checks to prevent errors if functions aren't loaded yet.
2026-01-04 20:20:32 -05:00
Chuck 4d7274b938 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.
2026-01-04 20:08:16 -05:00
Chuck 893436f2d3 Update cache version again 2026-01-04 19:57:25 -05:00
Chuck 7d67495285 Remove duplicate array-of-objects check 2026-01-04 19:57:19 -05:00
Chuck a9351f1c66 Update cache-busting version for array-of-objects fix 2026-01-04 19:57:05 -05:00
Chuck d7b9c47cd8 Fix: Move array-of-objects detection before file-upload/checkbox checks
Move the array-of-objects widget detection to the top of the array handler so it's checked before file-upload and checkbox-group widgets. This ensures custom_feeds is properly detected as an array of objects.
2026-01-04 19:56:11 -05:00
Chuck 668fadb7d5 Update plugins_manager.js cache-busting version
Update version parameter to force browser to load new JavaScript with array-of-objects widget support.
2026-01-04 19:49:10 -05:00
Chuck d01c34384d Add array-of-objects widget support to web UI
- Add support for rendering arrays of objects in web UI (for custom_feeds)
- Implement add/remove/update functions for array-of-objects widgets
- Support file-upload widgets within array items
- Update form data handling to support array JSON data fields
2026-01-04 19:17:56 -05:00
Chuck 6b81873024 fix(plugins): Add onchange handlers to existing custom feed inputs
- Add onchange handlers to key and value inputs for existing patternProperties fields
- Fixes bug where editing existing custom RSS feeds didn't save changes
- Ensures hidden JSON input field is updated when users edit feed entries
- Affects all plugins using patternProperties (custom_feeds, feed_logo_map, etc.)
2026-01-04 16:52:19 -05:00
Chuck 5241bbf89c fix(7-segment-clock): Update submodule with separator and spacing fixes 2026-01-03 18:06:51 -05:00
Chuck 079598b284 fix(plugins): Remove compatible_versions requirement from single plugin install
Remove compatible_versions from required fields in install_from_url method
to match install_plugin behavior. This allows installing plugins from URLs
without manifest version requirements, consistent with store plugin installation.
2026-01-03 10:47:21 -05:00