mirror of
https://github.com/ChuckBuilds/LEDMatrix.git
synced 2026-04-10 13:02:59 +00:00
* fix: post-audit follow-up code fixes (cache, fonts, icons, dev script, CI) The docs refresh effort (#306, ledmatrix-plugins#92) surfaced seven code bugs that were intentionally left out of the docs PRs because they required code changes rather than doc fixes. This PR addresses the six that belong in LEDMatrix (the seventh — a lacrosse-scoreboard mode rename — lives in the plugins repo). Bug 1: cache_manager.delete() AttributeError src/common/api_helper.py:287 and src/plugin_system/resource_monitor.py:343 both call cache_manager.delete(key), which doesn't exist — only clear_cache(key=None). Added a delete() alias method on CacheManager that forwards to clear_cache(key). Reverts the "There is no delete() method" wording in DEVELOPER_QUICK_REFERENCE, .cursorrules so the docs match the new shim. Bug 2: dev_plugin_setup.sh PROJECT_ROOT resolution scripts/dev/dev_plugin_setup.sh:9 set PROJECT_ROOT to SCRIPT_DIR instead of walking up two levels to the repo root, so PLUGINS_DIR resolved to scripts/dev/plugins/ and created symlinks under the script's own directory. Fixed the path and removed the stray scripts/dev/plugins/of-the-day symlink left by earlier runs. Bug 3: plugin custom icons regressed from v2 to v3 web_interface/blueprints/api_v3.py built the /plugins/installed response without including the manifest's "icon" field, and web_interface/templates/v3/base.html hardcoded fas fa-puzzle-piece in all three plugin-tab render sites. Pass the icon through the API and read it from the templates with a puzzle-piece fallback. Reverts the "currently broken" banners in docs/PLUGIN_CUSTOM_ICONS.md and docs/PLUGIN_CUSTOM_ICONS_FEATURE.md. Bug 4: register_plugin_fonts was never wired up src/font_manager.py:150 defines register_plugin_fonts(plugin_id, font_manifest) but nothing called it, so plugin manifests with a "fonts" block were silently no-ops. Wired the call into PluginManager.load_plugin() right after plugin_loader.load_plugin returns. Reverts the "not currently wired" warning in docs/FONT_MANAGER.md's "For Plugin Developers" section. Bug 5: dead web_interface_v2 import pattern (LEDMatrix half) src/base_odds_manager.py had a try/except importing web_interface_v2.increment_api_counter, falling back to a no-op stub. The module doesn't exist anywhere in the v3 codebase and no API metrics dashboard reads it. Deleted the import block and the single call site; the plugins-repo half of this cleanup lands in ledmatrix-plugins#<next>. Bug 7: no CI test workflow .github/workflows/ only contained security-audit.yml; pytest ran locally but was not gated on PRs. Added .github/workflows/tests.yml running pytest against Python 3.10, 3.11, 3.12 in EMULATOR=true mode, skipping tests marked hardware or slow. Updated docs/HOW_TO_RUN_TESTS.md to reflect that the workflow now exists. Verification done locally: - CacheManager.delete(key) round-trips with set/get - base_odds_manager imports without the v2 module present - dev_plugin_setup.sh PROJECT_ROOT resolves to repo root - api_v3 and plugin_manager compile clean - tests.yml YAML parses - Script syntax check on dev_plugin_setup.sh Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix: address CodeRabbit review comments on #307 - src/cache_manager.py: clear_cache(key) treated empty string as "wipe all" because of `if key:`. Switched to `key is None` branching, made delete(key) and clear_cache(key) reject empty strings and None outright with ValueError, and updated both docstrings to make the contract explicit. Verified locally with a round-trip test that clear_cache() (no arg) still wipes everything but clear_cache("") and delete("") raise. - src/plugin_system/plugin_manager.py: was reaching for the font manager via getattr(self.display_manager, 'font_manager', None). PluginManager already takes a dedicated font_manager parameter (line 54) and stores it as self.font_manager (line 69), so the old path was both wrong and could miss the font manager entirely when the host injects them separately. Switched to self.font_manager directly with the same try/except warning behavior. - web_interface/templates/v3/base.html: in the full plugin-tab renderer, the icon was injected with `<i class="${escapeHtml(plugin.icon)}">` — but escapeHtml only escapes <, >, and &, not double quotes, so a manifest with a quote in its icon string could break out of the class attribute. Replaced the innerHTML template with createElement for the <i> tag, set className from plugin.icon directly (no string interpolation), and used a text node for the label. Same fix shape would also harden the two stub-renderer sites at line 515 / 774, but those already escape `"` to " and CodeRabbit only flagged this site, so leaving them for now. - docs/FONT_MANAGER.md: clarified that the Manual Font Overrides *workflow* (set_override / remove_override / font_overrides.json) is the supported override path today, and only the Fonts tab in the web UI is the placeholder. Previous wording conflated the two and made it sound like overrides themselves were broken. - docs/HOW_TO_RUN_TESTS.md: replaced the vague "see the PR adding it" with a concrete link to #307 and a note that the workflow file itself is held back pending the workflow scope. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Chuck <chuck@example.com> Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
313 lines
8.3 KiB
Markdown
313 lines
8.3 KiB
Markdown
# Plugin Custom Icons Guide
|
||
|
||
## Overview
|
||
|
||
Plugins can specify custom icons that appear next to their name in the web interface tabs. This makes your plugin instantly recognizable and adds visual polish to the UI.
|
||
|
||
## Icon Types Supported
|
||
|
||
The system supports three types of icons:
|
||
|
||
### 1. Font Awesome Icons (Recommended)
|
||
|
||
The web interface uses Font Awesome 6, giving you access to thousands of icons.
|
||
|
||
**Example:**
|
||
```json
|
||
{
|
||
"id": "my-plugin",
|
||
"name": "Weather Display",
|
||
"icon": "fas fa-cloud-sun"
|
||
}
|
||
```
|
||
|
||
**Common Font Awesome Icons:**
|
||
- Clock: `fas fa-clock`
|
||
- Weather: `fas fa-cloud-sun`, `fas fa-cloud-rain`
|
||
- Calendar: `fas fa-calendar`, `fas fa-calendar-alt`
|
||
- Sports: `fas fa-football-ball`, `fas fa-basketball-ball`
|
||
- Music: `fas fa-music`, `fas fa-headphones`
|
||
- Finance: `fas fa-chart-line`, `fas fa-dollar-sign`
|
||
- News: `fas fa-newspaper`, `fas fa-rss`
|
||
- Settings: `fas fa-cog`, `fas fa-sliders-h`
|
||
- Timer: `fas fa-stopwatch`, `fas fa-hourglass`
|
||
- Alert: `fas fa-bell`, `fas fa-exclamation-triangle`
|
||
- Heart: `fas fa-heart`, `far fa-heart` (outline)
|
||
- Star: `fas fa-star`, `far fa-star` (outline)
|
||
- Image: `fas fa-image`, `fas fa-camera`
|
||
- Video: `fas fa-video`, `fas fa-film`
|
||
- Game: `fas fa-gamepad`, `fas fa-dice`
|
||
|
||
**Browse all icons:** [Font Awesome Icon Gallery](https://fontawesome.com/icons)
|
||
|
||
### 2. Emoji Icons (Fun & Simple)
|
||
|
||
Use any emoji character for a colorful, fun icon.
|
||
|
||
**Example:**
|
||
```json
|
||
{
|
||
"id": "hello-world",
|
||
"name": "Hello World",
|
||
"icon": "👋"
|
||
}
|
||
```
|
||
|
||
**Popular Emojis:**
|
||
- Time: ⏰ 🕐 ⏱️ ⏲️
|
||
- Weather: ☀️ ⛅ 🌤️ 🌧️ ⛈️ 🌩️ ❄️
|
||
- Sports: ⚽ 🏀 🏈 ⚾ 🎾 🏐
|
||
- Music: 🎵 🎶 🎸 🎹 🎤
|
||
- Money: 💰 💵 💴 💶 💷
|
||
- Calendar: 📅 📆
|
||
- News: 📰 📻 📡
|
||
- Fun: 🎮 🎲 🎯 🎨 🎭
|
||
- Nature: 🌍 🌎 🌏 🌳 🌺 🌸
|
||
- Food: 🍕 🍔 🍟 🍦 ☕ 🍰
|
||
|
||
### 3. Custom Image URLs (Advanced)
|
||
|
||
Use a custom image file for ultimate branding.
|
||
|
||
**Example:**
|
||
```json
|
||
{
|
||
"id": "my-plugin",
|
||
"name": "My Plugin",
|
||
"icon": "/plugins/my-plugin/icon.png"
|
||
}
|
||
```
|
||
|
||
**Requirements:**
|
||
- Image should be 16x16 to 32x32 pixels
|
||
- Supported formats: PNG, SVG, JPG, GIF
|
||
- Can be a relative path, absolute path, or external URL
|
||
- SVG recommended for best quality at any size
|
||
|
||
## How to Add an Icon
|
||
|
||
### Step 1: Choose Your Icon
|
||
|
||
Decide which type suits your plugin:
|
||
- **Font Awesome**: Professional, consistent with UI
|
||
- **Emoji**: Fun, colorful, no setup needed
|
||
- **Custom Image**: Unique branding, requires image file
|
||
|
||
### Step 2: Add to manifest.json
|
||
|
||
Add the `icon` field to your plugin's `manifest.json`:
|
||
|
||
```json
|
||
{
|
||
"id": "my-weather-plugin",
|
||
"name": "Weather Display",
|
||
"version": "1.0.0",
|
||
"author": "Your Name",
|
||
"description": "Shows weather information",
|
||
"icon": "fas fa-cloud-sun", // ← Add this line
|
||
"entry_point": "manager.py",
|
||
...
|
||
}
|
||
```
|
||
|
||
### Step 3: Test Your Plugin
|
||
|
||
1. Install or update your plugin
|
||
2. Open the web interface
|
||
3. Look for your plugin's tab
|
||
4. The icon should appear next to the plugin name
|
||
|
||
## Examples
|
||
|
||
### Weather Plugin
|
||
```json
|
||
{
|
||
"id": "weather-advanced",
|
||
"name": "Weather Advanced",
|
||
"icon": "fas fa-cloud-sun",
|
||
"description": "Advanced weather display with forecasts"
|
||
}
|
||
```
|
||
**Result:** Tab shows: `☁️ Weather Advanced`
|
||
|
||
### Clock Plugin
|
||
```json
|
||
{
|
||
"id": "digital-clock",
|
||
"name": "Digital Clock",
|
||
"icon": "⏰",
|
||
"description": "A beautiful digital clock"
|
||
}
|
||
```
|
||
**Result:** Tab shows: `⏰ Digital Clock`
|
||
|
||
### Sports Scores Plugin
|
||
```json
|
||
{
|
||
"id": "sports-scores",
|
||
"name": "Sports Scores",
|
||
"icon": "fas fa-trophy",
|
||
"description": "Live sports scores"
|
||
}
|
||
```
|
||
**Result:** Tab shows: `🏆 Sports Scores`
|
||
|
||
### Custom Branding
|
||
```json
|
||
{
|
||
"id": "company-dashboard",
|
||
"name": "Company Dashboard",
|
||
"icon": "/plugins/company-dashboard/logo.svg",
|
||
"description": "Company metrics display"
|
||
}
|
||
```
|
||
**Result:** Tab shows: `[logo] Company Dashboard`
|
||
|
||
## Best Practices
|
||
|
||
### 1. Choose Meaningful Icons
|
||
- Icon should relate to plugin functionality
|
||
- Users should understand what the plugin does at a glance
|
||
- Avoid generic icons for specific functionality
|
||
|
||
### 2. Keep It Simple
|
||
- Simpler icons work better at small sizes
|
||
- Avoid icons with too much detail
|
||
- Test how your icon looks at 16x16 pixels
|
||
|
||
### 3. Match the UI Style
|
||
- Font Awesome icons match the interface best
|
||
- If using emoji, consider contrast with background
|
||
- Custom images should use similar color schemes
|
||
|
||
### 4. Consider Accessibility
|
||
- Icons should be recognizable without color
|
||
- Don't rely solely on color to convey meaning
|
||
- The plugin name should be descriptive
|
||
|
||
### 5. Test on Different Displays
|
||
- Check icon clarity on various screen sizes
|
||
- Ensure emoji render correctly on target devices
|
||
- Custom images should have good contrast
|
||
|
||
## Icon Categories
|
||
|
||
Here are recommended icons by plugin category:
|
||
|
||
### Time & Calendar
|
||
- `fas fa-clock`, `fas fa-calendar`, `fas fa-hourglass`
|
||
- Emoji: ⏰ 📅 ⏱️
|
||
|
||
### Weather
|
||
- `fas fa-cloud-sun`, `fas fa-temperature-high`, `fas fa-wind`
|
||
- Emoji: ☀️ 🌧️ ⛈️
|
||
|
||
### Finance & Stocks
|
||
- `fas fa-chart-line`, `fas fa-dollar-sign`, `fas fa-coins`
|
||
- Emoji: 💰 📈 💵
|
||
|
||
### Sports & Games
|
||
- `fas fa-football-ball`, `fas fa-trophy`, `fas fa-gamepad`
|
||
- Emoji: ⚽ 🏀 🎮
|
||
|
||
### Entertainment
|
||
- `fas fa-music`, `fas fa-film`, `fas fa-tv`
|
||
- Emoji: 🎵 🎬 📺
|
||
|
||
### News & Information
|
||
- `fas fa-newspaper`, `fas fa-rss`, `fas fa-info-circle`
|
||
- Emoji: 📰 📡 ℹ️
|
||
|
||
### Utilities
|
||
- `fas fa-tools`, `fas fa-cog`, `fas fa-wrench`
|
||
- Emoji: 🔧 ⚙️ 🛠️
|
||
|
||
### Social Media
|
||
- `fab fa-twitter`, `fab fa-facebook`, `fab fa-instagram`
|
||
- Emoji: 📱 💬 📧
|
||
|
||
## Troubleshooting
|
||
|
||
### Icon Not Showing
|
||
1. Check that the `icon` field is correctly spelled in `manifest.json`
|
||
2. For Font Awesome icons, verify the class name is correct
|
||
3. For custom images, check that the file path is accessible
|
||
4. Refresh the plugins in the web interface
|
||
5. Check browser console for errors
|
||
|
||
### Emoji Looks Wrong
|
||
- Some emojis render differently on different platforms
|
||
- Try a different emoji if one doesn't work well
|
||
- Consider using Font Awesome instead for consistency
|
||
|
||
### Custom Image Not Loading
|
||
- Verify the image file exists in the specified path
|
||
- Check file permissions (should be readable)
|
||
- Try using an absolute path or URL
|
||
- Ensure image format is supported (PNG, SVG, JPG, GIF)
|
||
- Check image dimensions (16x16 to 32x32 recommended)
|
||
|
||
### Icon Too Large/Small
|
||
- Font Awesome and emoji icons automatically size correctly
|
||
- For custom images, adjust the image file dimensions
|
||
- SVG images scale best
|
||
|
||
## Default Behavior
|
||
|
||
If you don't specify an `icon` field in your manifest:
|
||
- The plugin tab will show a default puzzle piece icon: 🧩
|
||
- This is the fallback for all plugins without custom icons
|
||
|
||
## Technical Details
|
||
|
||
The icon system works as follows:
|
||
|
||
1. **Frontend reads manifest**: When plugins load, the web interface reads each plugin's `manifest.json`
|
||
2. **Icon detection**: The `getPluginIcon()` function determines icon type:
|
||
- Contains `fa-` → Font Awesome icon
|
||
- 1-4 characters → Emoji
|
||
- Starts with `http://`, `https://`, or `/` → Custom image
|
||
- Otherwise → Default puzzle piece
|
||
3. **Rendering**: Icon HTML is generated and inserted into:
|
||
- Tab button in navigation bar
|
||
- Configuration page header
|
||
|
||
## Advanced: Dynamic Icons
|
||
|
||
Want to change icons programmatically? While not officially supported, you could:
|
||
|
||
1. Store multiple icon options in your manifest
|
||
2. Use JavaScript to swap icons based on plugin state
|
||
3. Update the manifest dynamically and refresh plugins
|
||
|
||
**Example (advanced):**
|
||
```json
|
||
{
|
||
"id": "status-display",
|
||
"icon": "fas fa-circle",
|
||
"icon_states": {
|
||
"active": "fas fa-check-circle",
|
||
"error": "fas fa-exclamation-circle",
|
||
"warning": "fas fa-exclamation-triangle"
|
||
}
|
||
}
|
||
```
|
||
|
||
## Related Documentation
|
||
|
||
- [Plugin Configuration Tabs](PLUGIN_CONFIGURATION_TABS.md) - Main plugin tabs documentation
|
||
- [Plugin Development Guide](plugin_docs/) - How to create plugins
|
||
- [Font Awesome Icons](https://fontawesome.com/icons) - Browse all available icons
|
||
- [Emoji Reference](https://unicode.org/emoji/charts/full-emoji-list.html) - All emoji options
|
||
|
||
## Summary
|
||
|
||
Adding a custom icon to your plugin:
|
||
|
||
1. **Choose** your icon (Font Awesome, emoji, or custom image)
|
||
2. **Add** the `icon` field to `manifest.json`
|
||
3. **Test** in the web interface
|
||
|
||
That's it! Your plugin now has a professional, recognizable icon in the UI. 🎨
|
||
|