Files
LEDMatrix/docs/PLUGIN_CONFIGURATION_TABS.md
Chuck 62da1d2b09 docs: fix bare /api/plugins paths in PLUGIN_CONFIGURATION_TABS
Found 5 more bare /api/plugins/* paths in PLUGIN_CONFIGURATION_TABS.md
that I missed in the round 2 sweep — they're inside data flow diagrams
and prose ("loaded via /api/plugins/installed", etc.) so the earlier
grep over Markdown code blocks didn't catch them. Fixed all 5 to use
/api/v3/plugins/* (the api_v3 blueprint mount path verified at
web_interface/app.py:144).

Also added a status banner noting that the "Implementation Details"
section references the pre-v3 file layout (web_interface_v2.py,
templates/index_v2.html) which no longer exists. The current
implementation is in web_interface/app.py, blueprints/api_v3.py, and
templates/v3/. Same kind of historical drift I flagged in
PLUGIN_ARCHITECTURE_SPEC.md and the PLUGIN_CUSTOM_ICONS_FEATURE doc.
The user-facing parts of the doc (Overview, Features, Form Generation
Process) are still accurate.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-07 13:37:52 -04:00

9.5 KiB

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.py, and web_interface/templates/v3/. The user-facing description (Overview, Features, Form Generation Process) is still accurate.

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.

Features

  • Automatic Tab Generation: When a plugin is installed, a new tab is automatically created in the web UI
  • 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)
  • 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.)

User Experience

Accessing Plugin Configuration

  1. Navigate to the Plugins tab to see all installed plugins
  2. Click the Configure button on any plugin card
  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)

Configuring a Plugin

  1. Open the plugin's configuration tab
  2. Modify settings using the generated form
  3. Click Save Configuration
  4. Restart the display service to apply changes

Plugin Manager vs Per-Plugin Configuration

  • Plugin Manager tab (second nav row): used for browsing the Plugin Store, installing plugins, toggling installed plugins on/off, and updating/uninstalling them
  • Per-plugin tabs (one per installed plugin, also in the second nav row): used for configuring that specific plugin's behavior and settings via a form auto-generated from its config_schema.json

For Plugin Developers

Requirements

To enable automatic configuration tab generation, your plugin must:

  1. Include a config_schema.json file
  2. Reference it in your manifest.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 for details.

Supported JSON Schema Types

The form generator supports the following JSON Schema types:

Boolean

{
  "type": "boolean",
  "default": true,
  "description": "Enable or disable this feature"
}

Renders as: Toggle switch

Number / Integer

{
  "type": "integer",
  "default": 60,
  "minimum": 1,
  "maximum": 300,
  "description": "Update interval in seconds"
}

Renders as: Number input with min/max constraints

String

{
  "type": "string",
  "default": "Hello, World!",
  "minLength": 1,
  "maxLength": 50,
  "description": "The message to display"
}

Renders as: Text input with length constraints

Array

{
  "type": "array",
  "items": {
    "type": "integer",
    "minimum": 0,
    "maximum": 255
  },
  "minItems": 3,
  "maxItems": 3,
  "default": [255, 255, 255],
  "description": "RGB color [R, G, B]"
}

Renders as: Text input (comma-separated values)
Example input: 255, 128, 0

Enum (Select)

{
  "type": "string",
  "enum": ["small", "medium", "large"],
  "default": "medium",
  "description": "Display size"
}

Renders as: Dropdown select

Example config_schema.json

{
  "$schema": "http://json-schema.org/draft-07/schema#",
  "type": "object",
  "title": "My Plugin Configuration",
  "description": "Configure my awesome plugin",
  "properties": {
    "enabled": {
      "type": "boolean",
      "default": true,
      "description": "Enable or disable this plugin"
    },
    "message": {
      "type": "string",
      "default": "Hello!",
      "minLength": 1,
      "maxLength": 50,
      "description": "The message to display"
    },
    "update_interval": {
      "type": "integer",
      "default": 60,
      "minimum": 1,
      "maximum": 3600,
      "description": "Update interval in seconds"
    },
    "color": {
      "type": "array",
      "items": {
        "type": "integer",
        "minimum": 0,
        "maximum": 255
      },
      "minItems": 3,
      "maxItems": 3,
      "default": [255, 255, 255],
      "description": "RGB color [R, G, B]"
    },
    "mode": {
      "type": "string",
      "enum": ["scroll", "static", "fade"],
      "default": "scroll",
      "description": "Display mode"
    }
  },
  "required": ["enabled"],
  "additionalProperties": false
}

Best Practices

  1. Use Descriptive Labels: The description field is shown as help text under each input
  2. Set Sensible Defaults: Always provide default values that work out of the box
  3. Use Constraints: Leverage min/max, minLength/maxLength to guide users
  4. Mark Required Fields: Use the required array in your schema
  5. Organize Properties: List properties in order of importance

Form Generation Process

  1. Web UI loads installed plugins via /api/v3/plugins/installed
  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

Backend Changes

File: web_interface_v2.py

  • Modified /api/v3/plugins/installed endpoint to include config_schema_data
  • Loads each plugin's config_schema.json if it exists
  • Returns schema data along with plugin info

Frontend Changes

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

Plugin Tab Not Appearing

  • Ensure config_schema.json exists in plugin directory
  • Verify config_schema field in manifest.json
  • Check browser console for errors
  • Try refreshing plugins (Plugins tab → Refresh button)

Form Not Generating Correctly

  • Validate your config_schema.json against JSON Schema Draft 07
  • Check that all properties have a type field
  • Ensure default values match the specified type
  • Look for JavaScript errors in browser console

Configuration Not Saving

  • Ensure the plugin is properly installed
  • Check that config keys match schema properties
  • Verify backend API is accessible
  • Check browser network tab for API errors
  • Ensure display service is restarted after config changes

Migration Guide

For Existing Plugins

If your plugin already has a config_schema.json:

  1. No changes needed! The tab will be automatically generated.
  2. Test the generated form to ensure all fields render correctly.
  3. Consider adding more descriptive description fields.

If your plugin doesn't have a config schema:

  1. Create config_schema.json based on your current config structure
  2. Add descriptions for each property
  3. Set appropriate defaults
  4. Add validation constraints (min, max, etc.)
  5. Reference the schema in your manifest.json

Backward Compatibility

  • Plugins without config_schema.json still work normally
  • They simply won't have a configuration tab
  • Users can still edit config via the Raw JSON editor
  • The Configure button will navigate to a tab with a friendly message

Future Enhancements

Potential improvements for future versions:

  • Advanced Schema Features: Support for nested objects, conditional fields
  • Visual Validation: Real-time validation feedback as user types
  • 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

See these plugins for examples of config schemas:

  • hello-world: Simple plugin with basic types
  • clock-simple: Plugin with enum and number types

Support

For questions or issues:

  • Check the main LEDMatrix wiki
  • Review plugin documentation
  • Open an issue on GitHub
  • Join the community Discord