docs(plugin-config): match the config tab, icon and web-action docs to the code

- PLUGIN_CONFIG_QUICK_START / PLUGIN_CONFIGURATION_TABS /
  PLUGIN_CONFIGURATION_GUIDE: there is no "Reset to Defaults" button (the
  tab has Refresh, Update, Uninstall, Save Configuration); plugin config
  hot-reloads (ConfigService + on_config_change), so no restart; the
  schema is found by the fixed name config_schema.json, not a manifest
  config_schema field; the tab row is "Plugin Manager", not "Plugins";
  forms are server-rendered from /v3/partials/plugin-config/<id>; the
  duration hook is get_display_duration()/display_duration; a class_name
  mismatch raises PluginError; the store requires id, name, class_name and
  display_modes (not version); plugin_system.debug/log_level do not exist
  (use run.py -d / LEDMATRIX_DEBUG). Drop "future" features that shipped.
- PLUGIN_CONFIG_CORE_PROPERTIES: list all of CORE_PLUGIN_PROPERTIES,
  including skin, skin_options and the vegas_* tuning keys.
- PLUGIN_CUSTOM_ICONS: icon is only a Font Awesome class (fallback
  fa-puzzle-piece); emoji/URL icons and getPluginIcon() never existed in
  v3. Note that /api/v3/plugins/installed currently omits icon.
- PLUGIN_WEB_UI_ACTIONS (+ example JSON): success_message, error_message
  and step1_message are never read.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Chuck
2026-09-22 16:21:58 -04:00
co-authored by Claude Opus 5.5
parent 8dad0fd41c
commit 698807cc62
7 changed files with 141 additions and 453 deletions
+23 -25
View File
@@ -9,7 +9,7 @@ The LEDMatrix system uses a plugin-based architecture where each plugin manages
1. **Install a plugin** from the Plugin Store in the web interface 1. **Install a plugin** from the Plugin Store in the web interface
2. **Navigate to the plugin's configuration tab** (automatically created when installed) 2. **Navigate to the plugin's configuration tab** (automatically created when installed)
3. **Configure settings** using the auto-generated form 3. **Configure settings** using the auto-generated form
4. **Save configuration** and restart the display service 4. **Save configuration**; the running display applies it without a restart
For detailed information, see the sections below. For detailed information, see the sections below.
@@ -189,19 +189,20 @@ plugin-repos/
"author": "Your Name", "author": "Your Name",
"entry_point": "manager.py", "entry_point": "manager.py",
"class_name": "MyPlugin", "class_name": "MyPlugin",
"display_modes": ["my_plugin"], "display_modes": ["my_plugin"]
"config_schema": "config_schema.json"
} }
``` ```
The required fields the plugin loader will check for are `id`, The Plugin Store refuses a manifest that lacks any of `id`, `name`,
`name`, `version`, `class_name`, and `display_modes`. `entry_point` `class_name` or `display_modes` (`store_manager.py`); the loader itself
defaults to `manager.py` if omitted. `config_schema` must be a needs `class_name`. `version` is not required, but the store compares it
**file path** (relative to the plugin directory) — the schema itself with the registry's `latest_version` to offer updates, so set it.
lives in a separate JSON file, not inline in the manifest. The `entry_point` defaults to `manager.py` if omitted. The config schema is not
`class_name` value must match the actual class defined in the entry named in the manifest: it is always the file `config_schema.json` in the
point file **exactly** (case-sensitive, no spaces); otherwise the plugin directory. The `class_name` value must match the actual class
loader fails with `AttributeError` at load time. defined in the entry point file **exactly** (case-sensitive, no spaces);
otherwise the loader fails with a `PluginError` ("Class ... not found in
module") at load time.
### Plugin Manager Class ### Plugin Manager Class
@@ -223,9 +224,11 @@ class MyPlugin(BasePlugin):
"""Render plugin content to the LED matrix.""" """Render plugin content to the LED matrix."""
pass pass
def get_duration(self): # BasePlugin.get_display_duration() already returns
"""Get display duration for this plugin""" # self.config['display_duration'] (default 15s); override it only to
return self.config.get('duration', 30) # vary the duration with the content.
def get_display_duration(self):
return self.config.get('display_duration', 30)
``` ```
### Dynamic Duration Configuration ### Dynamic Duration Configuration
@@ -259,7 +262,7 @@ Each installed plugin automatically gets its own dedicated configuration tab in
### Accessing Plugin Configuration ### Accessing Plugin Configuration
1. Navigate to the **Plugins** tab to see all installed plugins 1. Navigate to the **Plugin Manager** tab to see all installed plugins
2. Click the **Configure** button on any plugin card, or 2. Click the **Configure** button on any plugin card, or
3. Click directly on the plugin's tab button in the navigation bar 3. Click directly on the plugin's tab button in the navigation bar
@@ -278,7 +281,6 @@ Configuration forms are automatically generated from each plugin's `config_schem
- **Type-safe inputs**: Form inputs match JSON Schema types - **Type-safe inputs**: Form inputs match JSON Schema types
- **Default values**: Fields show current values or schema defaults - **Default values**: Fields show current values or schema defaults
- **Real-time validation**: Input constraints enforced (min, max, maxLength, etc.) - **Real-time validation**: Input constraints enforced (min, max, maxLength, etc.)
- **Reset to defaults**: One-click reset to restore original settings
- **Help text**: Each field shows description from schema - **Help text**: Each field shows description from schema
For more details, see [Plugin Configuration Tabs](PLUGIN_CONFIGURATION_TABS.md). For more details, see [Plugin Configuration Tabs](PLUGIN_CONFIGURATION_TABS.md).
@@ -337,20 +339,16 @@ The configuration system uses JSON Schema Draft-07 for validation:
2. **Configuration errors**: Validate plugin configuration against schema 2. **Configuration errors**: Validate plugin configuration against schema
3. **Display issues**: Check display durations and plugin display methods 3. **Display issues**: Check display durations and plugin display methods
4. **Performance**: Monitor plugin update intervals and resource usage 4. **Performance**: Monitor plugin update intervals and resource usage
5. **Tab not showing**: Verify `config_schema.json` exists and is referenced in manifest 5. **Form missing or wrong**: Verify `config_schema.json` exists in the plugin directory and is valid JSON Schema
6. **Settings not saving**: Check validation errors and ensure all required fields are filled 6. **Settings not saving**: Check validation errors and ensure all required fields are filled
### Debug Mode ### Debug Mode
Enable debug logging to troubleshoot plugin issues: There is no config key for debug logging. Run the display with debug
logging instead:
```json ```bash
{ python3 run.py -d # or: LEDMATRIX_DEBUG=true python3 run.py
"plugin_system": {
"debug": true,
"log_level": "debug"
}
}
``` ```
## See Also ## See Also
+39 -99
View File
@@ -1,19 +1,8 @@
# Plugin Configuration Tabs # Plugin Configuration Tabs
> **Status note:** this doc was written during the rollout of the
> per-plugin configuration tab feature. The feature itself is shipped
> and working in the current v3 web interface, but a few file paths
> in the "Implementation Details" section below still reference the
> pre-v3 file layout (`web_interface_v2.py`, `templates/index_v2.html`).
> The current implementation lives in `web_interface/app.py`,
> `web_interface/blueprints/api_v3/` (plugin config handlers in
> `plugins.py`), and `web_interface/templates/v3/`.
> The user-facing description (Overview, Features, Form Generation
> Process) is still accurate.
## Overview ## Overview
Each installed plugin now gets its own dedicated configuration tab in the web interface. This provides a clean, organized way to configure plugins without cluttering the main Plugins management tab. Each installed plugin now gets its own dedicated configuration tab in the web interface. This provides a clean, organized way to configure plugins without cluttering the **Plugin Manager** tab.
## Features ## Features
@@ -21,24 +10,27 @@ Each installed plugin now gets its own dedicated configuration tab in the web in
- **JSON Schema-Based Forms**: Configuration forms are automatically generated based on each plugin's `config_schema.json` - **JSON Schema-Based Forms**: Configuration forms are automatically generated based on each plugin's `config_schema.json`
- **Type-Safe Inputs**: Form inputs are created based on the JSON Schema type (boolean, number, string, array, enum) - **Type-Safe Inputs**: Form inputs are created based on the JSON Schema type (boolean, number, string, array, enum)
- **Default Values**: All fields show current values or fallback to schema defaults - **Default Values**: All fields show current values or fallback to schema defaults
- **Reset Functionality**: Users can reset all settings to defaults with one click
- **Real-Time Validation**: Input constraints from JSON Schema are enforced (min, max, maxLength, etc.) - **Real-Time Validation**: Input constraints from JSON Schema are enforced (min, max, maxLength, etc.)
## User Experience ## User Experience
### Accessing Plugin Configuration ### Accessing Plugin Configuration
1. Navigate to the **Plugins** tab to see all installed plugins 1. Navigate to the **Plugin Manager** tab to see all installed plugins
2. Click the **Configure** button on any plugin card 2. Click the **Configure** button on any plugin card
3. You'll be automatically taken to that plugin's configuration tab 3. You'll be automatically taken to that plugin's configuration tab
4. Alternatively, click directly on the plugin's tab button (marked with a puzzle piece icon) 4. Alternatively, click directly on the plugin's tab button in the second nav row
### Configuring a Plugin ### Configuring a Plugin
1. Open the plugin's configuration tab 1. Open the plugin's configuration tab
2. Modify settings using the generated form 2. Modify settings using the generated form
3. Click **Save Configuration** 3. Click **Save Configuration**. The settings apply to the running display
4. Restart the display service to apply changes without a restart: the display service reloads `config.json` when it
changes and calls the plugin's `on_config_change()`
The tab also has **Refresh** (reload the form), **Update** (update the
plugin) and **Uninstall** buttons.
### Plugin Manager vs Per-Plugin Configuration ### Plugin Manager vs Per-Plugin Configuration
@@ -53,22 +45,13 @@ Each installed plugin now gets its own dedicated configuration tab in the web in
### Requirements ### Requirements
To enable automatic configuration tab generation, your plugin must: Every installed plugin gets a tab. To get a generated form in it, include a
`config_schema.json` file in the plugin's directory. The name is fixed: the
web interface finds the schema by that file name (`SchemaManager` in
`src/plugin_system/schema_manager.py`), and no manifest field points to it.
1. Include a `config_schema.json` file **Note:** You can optionally specify a Font Awesome `icon` class for your
2. Reference it in your `manifest.json`: plugin tab in `manifest.json`. See [Plugin Custom Icons Guide](PLUGIN_CUSTOM_ICONS.md) for details.
```json
{
"id": "your-plugin",
"name": "Your Plugin",
"icon": "fas fa-star", // Optional: Custom tab icon
...
"config_schema": "config_schema.json"
}
```
**Note:** You can optionally specify a custom `icon` for your plugin tab. See [Plugin Custom Icons Guide](PLUGIN_CUSTOM_ICONS.md) for details.
### Supported JSON Schema Types ### Supported JSON Schema Types
@@ -209,69 +192,32 @@ Renders as: Dropdown select
### Form Generation Process ### Form Generation Process
1. Web UI loads installed plugins via `/api/v3/plugins/installed` Forms are rendered on the server, not generated in the browser:
2. For each plugin, the backend loads its `config_schema.json`
3. Frontend generates a tab button with plugin name
4. Frontend generates a form based on the JSON Schema
5. Current config values from `config.json` are populated
6. When saved, each field is sent to `/api/v3/plugins/config` endpoint
## Implementation Details 1. The web UI loads installed plugins via `/api/v3/plugins/installed` and adds
a tab button for each one
### Backend Changes 2. Opening a tab loads `/v3/partials/plugin-config/<plugin_id>`
(`web_interface/blueprints/pages_v3.py`), which loads the plugin's schema
**File**: `web_interface_v2.py` through `SchemaManager` and its current values from `config.json`
3. `web_interface/templates/v3/partials/plugin_config.html` renders the form
- Modified `/api/v3/plugins/installed` endpoint to include `config_schema_data` from the schema (widgets named by `x-widget` are rendered by the scripts in
- Loads each plugin's `config_schema.json` if it exists `web_interface/static/v3/js/widgets/`)
- Returns schema data along with plugin info 4. **Save Configuration** posts the form to `/api/v3/plugins/config`
(`web_interface/blueprints/api_v3/plugins.py`), which validates it against
### Frontend Changes the schema, writes `config.json` (secret fields go to
`config_secrets.json`) and shows a notification
**File**: `templates/index_v2.html`
New Functions:
- `generatePluginTabs(plugins)` - Creates tab buttons and content for each plugin
- `generatePluginConfigForm(plugin)` - Generates HTML form from JSON Schema
- `savePluginConfiguration(pluginId)` - Saves form data to backend
- `resetPluginConfig(pluginId)` - Resets all settings to defaults
- `configurePlugin(pluginId)` - Navigates to plugin's tab
### Data Flow
```
Page Load
→ refreshPlugins()
→ /api/v3/plugins/installed
→ Returns plugins with config_schema_data
→ generatePluginTabs()
→ Creates tab buttons
→ Creates tab content
→ generatePluginConfigForm()
→ Reads JSON Schema
→ Creates form inputs
→ Populates current values
User Saves
→ savePluginConfiguration()
→ Reads form data
→ Converts types per schema
→ Sends to /api/v3/plugins/config
→ Updates config.json
→ Shows success notification
```
## Troubleshooting ## Troubleshooting
### Plugin Tab Not Appearing ### Plugin Tab Not Appearing
- Ensure `config_schema.json` exists in plugin directory - Check that the plugin is installed and appears in the **Plugin Manager** tab
- Verify `config_schema` field in `manifest.json`
- Check browser console for errors - Check browser console for errors
- Try refreshing plugins (Plugins tab → Refresh button) - Reload the page
### Form Not Generating Correctly ### Form Not Generating Correctly
- Ensure `config_schema.json` exists in the plugin directory
- Validate your `config_schema.json` against JSON Schema Draft 07 - Validate your `config_schema.json` against JSON Schema Draft 07
- Check that all properties have a `type` field - Check that all properties have a `type` field
- Ensure `default` values match the specified type - Ensure `default` values match the specified type
@@ -283,7 +229,6 @@ User Saves
- Check that config keys match schema properties - Check that config keys match schema properties
- Verify backend API is accessible - Verify backend API is accessible
- Check browser network tab for API errors - Check browser network tab for API errors
- Ensure display service is restarted after config changes
## Migration Guide ## Migration Guide
@@ -301,26 +246,21 @@ If your plugin doesn't have a config schema:
2. Add descriptions for each property 2. Add descriptions for each property
3. Set appropriate defaults 3. Set appropriate defaults
4. Add validation constraints (min, max, etc.) 4. Add validation constraints (min, max, etc.)
5. Reference the schema in your `manifest.json`
### Backward Compatibility ### Backward Compatibility
- Plugins without `config_schema.json` still work normally - Plugins without `config_schema.json` still work normally
- They simply won't have a configuration tab - Their tab shows plain text, number and checkbox inputs for the keys already
in their `config.json` section, or "No configuration options available for
this plugin." when there are none
- Users can still edit config via the Raw JSON editor - Users can still edit config via the Raw JSON editor
- The Configure button will navigate to a tab with a friendly message
## Future Enhancements ## Beyond the Basic Types
Potential improvements for future versions: Nested objects (rendered as collapsible sections), `x-widget` widgets such as
`color-picker` and `file-upload`, and more are supported; see
- **Advanced Schema Features**: Support for nested objects, conditional fields [PLUGIN_CONFIGURATION_GUIDE.md](PLUGIN_CONFIGURATION_GUIDE.md) and
- **Visual Validation**: Real-time validation feedback as user types `web_interface/static/v3/js/widgets/README.md`.
- **Color Pickers**: Special input for RGB/color array types
- **File Uploads**: Support for image/asset uploads
- **Import/Export**: Save and share plugin configurations
- **Presets**: Quick-switch between saved configurations
- **Documentation Links**: Link schema fields to plugin documentation
## Example Plugins ## Example Plugins
+20 -1
View File
@@ -6,7 +6,8 @@ The LEDMatrix plugin system automatically manages certain core properties that a
## Core Properties ## Core Properties
The following properties are automatically managed by the system: The following properties are automatically managed by the system (the list
is `CORE_PLUGIN_PROPERTIES` in `src/plugin_system/schema_manager.py`):
1. **`enabled`** (boolean) 1. **`enabled`** (boolean)
- Default: `true` - Default: `true`
@@ -24,6 +25,24 @@ The following properties are automatically managed by the system:
- Description: Enable live priority takeover when plugin has live content - Description: Enable live priority takeover when plugin has live content
- Used by DisplayController for priority scheduling - Used by DisplayController for priority scheduling
4. **`skin`** (string, object or null; no default)
- Description: Visual skin id, or a per-mode mapping like `{"live": "my-skin"}`
- Not an enum, so a stored value keeps validating after the skin is
uninstalled. Skins do not render with the current scoreboard plugins yet
(see [SKIN_SYSTEM.md](SKIN_SYSTEM.md)); the key is kept so stored values
keep loading and saving
5. **`skin_options`** (object; no default)
- Description: Options passed through to the selected skin
6. **`vegas_width_pct`**, **`vegas_overflow`**, **`vegas_max_width_screens`**
(untyped; no default)
- Description: Vegas mode tuning for this plugin — card width as a
percentage of the panel, `"rotate"` or `"truncate"` on overflow, and the
widest the card may be in screens
- Read by `src/vegas_mode/plugin_adapter.py` and `BasePlugin`, which
validate the values themselves and ignore a bad one with a log line
## How Core Properties Work ## How Core Properties Work
### Schema Validation ### Schema Validation
+19 -27
View File
@@ -10,8 +10,8 @@
and click **Install** and click **Install**
4. Notice a new tab appears in the second nav row with the plugin's name 4. Notice a new tab appears in the second nav row with the plugin's name
5. Click that tab to configure the plugin 5. Click that tab to configure the plugin
6. Modify settings and click **Save** 6. Modify settings and click **Save Configuration**. The running display
7. From **Overview**, click **Restart Display Service** to see changes picks the change up by itself; no restart is needed
That's it! Each installed plugin automatically gets its own configuration tab. That's it! Each installed plugin automatically gets its own configuration tab.
@@ -29,7 +29,6 @@ That's it! Each installed plugin automatically gets its own configuration tab.
- ✅ Proper input types (toggles, numbers, dropdowns) - ✅ Proper input types (toggles, numbers, dropdowns)
- ✅ Help text explaining each setting - ✅ Help text explaining each setting
- ✅ Input validation (min/max, length, etc.) - ✅ Input validation (min/max, length, etc.)
- ✅ One-click reset to defaults
## 📋 Example Walkthrough ## 📋 Example Walkthrough
@@ -40,7 +39,7 @@ Let's configure the "Hello World" plugin:
After installing the plugin, you'll see a new tab: After installing the plugin, you'll see a new tab:
``` ```
[Overview] [General] [...] [Plugins] [Hello World] ← New tab! [Plugin Manager] [Hello World] ← New tab! (second nav row)
``` ```
### Step 2: Configure Settings ### Step 2: Configure Settings
@@ -70,15 +69,16 @@ Display Duration
How long to display in seconds How long to display in seconds
[10 ] [10 ]
[Save Configuration] [Back] [Reset to Defaults] [Refresh] [Update] [Uninstall] [Save Configuration]
``` ```
### Step 3: Save and Apply ### Step 3: Save and Apply
1. Modify any settings 1. Modify any settings
2. Click **Save Configuration** 2. Click **Save Configuration**
3. See confirmation: "Configuration saved for hello-world. Restart display to apply changes." 3. See the confirmation notification. Plugin settings apply live: the
4. Restart the display service display service reloads `config.json` when it changes and passes the new
settings to the plugin's `on_config_change()`
## 🛠️ For Plugin Developers ## 🛠️ For Plugin Developers
@@ -105,19 +105,14 @@ Create `config_schema.json` in your plugin directory:
} }
``` ```
Reference it in `manifest.json`: **Done!** The file name is fixed: the web interface looks for
`config_schema.json` in the plugin's directory; there is no manifest field
for it. Every installed plugin gets a tab; the schema is what turns it into a
form.
```json **Bonus:** an `icon` field in `manifest.json` names a Font Awesome class for
{ the tab (`"icon": "fas fa-star"`). See
"id": "my-plugin", [PLUGIN_CUSTOM_ICONS.md](PLUGIN_CUSTOM_ICONS.md).
"icon": "fas fa-star", // Optional: add a custom icon!
"config_schema": "config_schema.json"
}
```
**Done!** Your plugin now has a configuration tab.
**Bonus:** Add an `icon` field for a custom tab icon! Use Font Awesome icons (`fas fa-star`), emoji (⭐), or custom images. See [PLUGIN_CUSTOM_ICONS.md](PLUGIN_CUSTOM_ICONS.md) for the full guide.
## 🎨 Supported Input Types ## 🎨 Supported Input Types
@@ -171,12 +166,10 @@ User enters: `255, 0, 0`
### For Users ### For Users
1. **Reset Anytime**: Use "Reset to Defaults" to restore original settings 1. **Navigate Back**: Switch to the **Plugin Manager** tab to see the
2. **Navigate Back**: Switch to the **Plugin Manager** tab to see the
full list of installed plugins full list of installed plugins
3. **Check Help Text**: Each field has a description explaining what it does 2. **Check Help Text**: Each field has a description explaining what it does
4. **Restart Required**: Remember to restart the display service from 3. **No Restart Needed**: Saved plugin settings apply to the running display
**Overview** after saving
### For Developers ### For Developers
@@ -189,18 +182,17 @@ User enters: `255, 0, 0`
## 🔧 Troubleshooting ## 🔧 Troubleshooting
### Tab Not Showing ### Tab Not Showing
- Check that `config_schema.json` exists - Check that the plugin is installed and listed under **Plugin Manager**
- Verify `config_schema` is in `manifest.json`
- Refresh the page - Refresh the page
- Check browser console for errors - Check browser console for errors
### Settings Not Saving ### Settings Not Saving
- Ensure plugin is properly installed - Ensure plugin is properly installed
- Restart the display service after saving
- Check that all required fields are filled - Check that all required fields are filled
- Look for validation errors in browser console - Look for validation errors in browser console
### Form Looks Wrong ### Form Looks Wrong
- Check that `config_schema.json` is in the plugin's directory
- Validate your JSON Schema - Validate your JSON Schema
- Check that types match your defaults - Check that types match your defaults
- Ensure descriptions are strings - Ensure descriptions are strings
+34 -282
View File
@@ -2,17 +2,28 @@
## Overview ## 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. A plugin can name an icon for its tab in the web interface's second nav row
(next to **Plugin Manager**) with the `icon` field in `manifest.json`.
## Icon Types Supported > **Status:** the tab code honors `icon`, but `GET /api/v3/plugins/installed`
> (`web_interface/blueprints/api_v3/plugins.py`) does not currently include
> the manifest's `icon` in its response, so every tab shows the default
> puzzle piece. Setting `icon` is harmless and will take effect once the API
> passes it through again.
The system supports three types of icons: ## Font Awesome classes only
### 1. Font Awesome Icons (Recommended) `icon` is used verbatim as the CSS class of an `<i>` element
(`iconEl.className = plugin.icon || 'fas fa-puzzle-piece'` in
`web_interface/static/v3/js/app-shell.js` and the same fallback in
`app-early.js`). So it must be a Font Awesome class string. Emoji, image
paths and URLs are not supported: they would end up as a meaningless class
name and render nothing.
The web interface uses Font Awesome 6, giving you access to thousands of icons. The web interface bundles Font Awesome Free 6
(`web_interface/static/v3/vendor/fontawesome/`), so any free `fas`, `far` or
`fab` icon works.
**Example:**
```json ```json
{ {
"id": "my-plugin", "id": "my-plugin",
@@ -21,292 +32,33 @@ The web interface uses Font Awesome 6, giving you access to thousands of icons.
} }
``` ```
**Common Font Awesome Icons:** Some common choices:
- Clock: `fas fa-clock`
- Clock / calendar: `fas fa-clock`, `fas fa-calendar-alt`
- Weather: `fas fa-cloud-sun`, `fas fa-cloud-rain` - 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`, `fas fa-trophy`
- Sports: `fas fa-football-ball`, `fas fa-basketball-ball`
- Music: `fas fa-music`, `fas fa-headphones` - Music: `fas fa-music`, `fas fa-headphones`
- Finance: `fas fa-chart-line`, `fas fa-dollar-sign` - Finance: `fas fa-chart-line`, `fas fa-dollar-sign`
- News: `fas fa-newspaper`, `fas fa-rss` - News: `fas fa-newspaper`, `fas fa-rss`
- Settings: `fas fa-cog`, `fas fa-sliders-h` - Games: `fas fa-gamepad`, `fas fa-dice`
- 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) Browse the rest in the [Font Awesome gallery](https://fontawesome.com/icons)
(filter to Free, version 6).
### 2. Emoji Icons (Fun & Simple) ## Default
Use any emoji character for a colorful, fun icon. With no `icon` (or an empty one) the tab shows `fas fa-puzzle-piece`.
**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 ## Troubleshooting
### Icon Not Showing 1. Check the class name against the Font Awesome 6 Free gallery; a Pro-only
1. Check that the `icon` field is correctly spelled in `manifest.json` or misspelled class renders as a blank space.
2. For Font Awesome icons, verify the class name is correct 2. Include the style prefix (`fas`, `far` or `fab`) as well as the icon
3. For custom images, check that the file path is accessible class.
4. Refresh the plugins in the web interface 3. See the status note above: the icon is currently not passed through by
5. Check browser console for errors the API.
### 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 ## Related Documentation
- [Plugin Configuration Tabs](PLUGIN_CONFIGURATION_TABS.md) - Main plugin tabs documentation - [Plugin Configuration Tabs](PLUGIN_CONFIGURATION_TABS.md)
- [Plugin Development Guide](PLUGIN_DEVELOPMENT_GUIDE.md) - How to create plugins - [Plugin Development Guide](PLUGIN_DEVELOPMENT_GUIDE.md)
- [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. 🎨
+5 -13
View File
@@ -25,9 +25,6 @@ Add a `web_ui_actions` array to your plugin's `manifest.json`:
"script": "path/to/script.py", "script": "path/to/script.py",
"oauth_flow": false, "oauth_flow": false,
"section_description": "Optional section description", "section_description": "Optional section description",
"success_message": "Action completed successfully",
"error_message": "Action failed",
"step1_message": "Authorization URL generated",
"step2_prompt": "Please paste the full redirect URL:", "step2_prompt": "Please paste the full redirect URL:",
"step2_button_text": "Complete Authentication" "step2_button_text": "Complete Authentication"
} }
@@ -52,12 +49,13 @@ Add a `web_ui_actions` array to your plugin's `manifest.json`:
- **`color`**: Color theme - `"blue"`, `"green"`, `"red"`, `"yellow"`, `"purple"`, etc. (defaults to `"blue"`) - **`color`**: Color theme - `"blue"`, `"green"`, `"red"`, `"yellow"`, `"purple"`, etc. (defaults to `"blue"`)
- **`oauth_flow`**: Set to `true` for OAuth-style two-step authentication flows - **`oauth_flow`**: Set to `true` for OAuth-style two-step authentication flows
- **`section_description`**: Description shown at the top of the actions section - **`section_description`**: Description shown at the top of the actions section
- **`success_message`**: Message shown on successful completion
- **`error_message`**: Message shown on failure
- **`step1_message`**: Message shown after step 1 (for OAuth flows)
- **`step2_prompt`**: Prompt text for step 2 redirect URL input - **`step2_prompt`**: Prompt text for step 2 redirect URL input
- **`step2_button_text`**: Button text for step 2 (defaults to "Complete Authentication") - **`step2_button_text`**: Button text for step 2 (defaults to "Complete Authentication")
The status messages shown after an action runs come from the action's
response (`message`), with built-in fallbacks such as "Action completed
successfully"; there are no manifest fields for them.
## Action Types ## Action Types
### Script Actions (`type: "script"`) ### Script Actions (`type: "script"`)
@@ -98,7 +96,6 @@ For two-step OAuth flows (e.g., Spotify):
"color": "green", "color": "green",
"script": "authenticate_spotify.py", "script": "authenticate_spotify.py",
"oauth_flow": true, "oauth_flow": true,
"step1_message": "Authorization URL generated",
"step2_prompt": "Please paste the full redirect URL from Spotify after authorization:", "step2_prompt": "Please paste the full redirect URL from Spotify after authorization:",
"step2_button_text": "Complete Authentication" "step2_button_text": "Complete Authentication"
} }
@@ -131,9 +128,6 @@ Here's a complete example for the `ledmatrix-music` plugin:
"script": "authenticate_spotify.py", "script": "authenticate_spotify.py",
"oauth_flow": true, "oauth_flow": true,
"section_description": "Authenticate with Spotify or YouTube Music to enable music playback display.", "section_description": "Authenticate with Spotify or YouTube Music to enable music playback display.",
"success_message": "Spotify authentication completed successfully",
"error_message": "Spotify authentication failed",
"step1_message": "Authorization URL generated",
"step2_prompt": "Please paste the full redirect URL from Spotify after authorization:", "step2_prompt": "Please paste the full redirect URL from Spotify after authorization:",
"step2_button_text": "Complete Authentication" "step2_button_text": "Complete Authentication"
}, },
@@ -145,9 +139,7 @@ Here's a complete example for the `ledmatrix-music` plugin:
"button_text": "Authenticate YTM", "button_text": "Authenticate YTM",
"icon": "fab fa-youtube", "icon": "fab fa-youtube",
"color": "red", "color": "red",
"script": "authenticate_ytm.py", "script": "authenticate_ytm.py"
"success_message": "YouTube Music authentication completed successfully",
"error_message": "YouTube Music authentication failed"
} }
] ]
} }
+1 -6
View File
@@ -37,9 +37,6 @@
"script": "authenticate_spotify.py", "script": "authenticate_spotify.py",
"oauth_flow": true, "oauth_flow": true,
"section_description": "Authenticate with Spotify or YouTube Music to enable music playback display.", "section_description": "Authenticate with Spotify or YouTube Music to enable music playback display.",
"success_message": "Spotify authentication completed successfully",
"error_message": "Spotify authentication failed",
"step1_message": "Authorization URL generated",
"step2_prompt": "Please paste the full redirect URL from Spotify after authorization:", "step2_prompt": "Please paste the full redirect URL from Spotify after authorization:",
"step2_button_text": "Complete Authentication" "step2_button_text": "Complete Authentication"
}, },
@@ -51,9 +48,7 @@
"button_text": "Authenticate YTM", "button_text": "Authenticate YTM",
"icon": "fab fa-youtube", "icon": "fab fa-youtube",
"color": "red", "color": "red",
"script": "authenticate_ytm.py", "script": "authenticate_ytm.py"
"success_message": "YouTube Music authentication completed successfully",
"error_message": "YouTube Music authentication failed"
} }
], ],
"versions": [ "versions": [