Add CSPT entity, processed CSS source type, reverse filter, and UI improvements

- Add Color Strip Processing Template (CSPT) entity: reusable filter chains
  for 1D LED strip postprocessing (backend, storage, API, frontend CRUD)
- Add "processed" color strip source type that wraps another CSS source and
  applies a CSPT filter chain (dataclass, stream, schema, modal, cards)
- Add Reverse filter for strip LED order reversal
- Add CSPT and processed CSS nodes/edges to visual graph editor
- Add CSPT test preview WS endpoint with input source selection
- Add device settings CSPT template selector (add + edit modals with hints)
- Use icon grids for palette quantization preset selector in filter lists
- Use EntitySelect for template references and test modal source selectors
- Fix filters.css_filter_template.desc missing localization
- Fix icon grid cell height inequality (grid-auto-rows: 1fr)
- Rename "Processed" subtab to "Processing Templates"
- Localize all new strings (en/ru/zh)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-03-15 02:16:59 +03:00
parent 7e78323c9c
commit 294d704eb0
72 changed files with 2992 additions and 1416 deletions

View File

@@ -31,6 +31,7 @@ from wled_controller.storage.value_source_store import ValueSourceStore
from wled_controller.storage.automation_store import AutomationStore
from wled_controller.storage.scene_preset_store import ScenePresetStore
from wled_controller.storage.sync_clock_store import SyncClockStore
from wled_controller.storage.color_strip_processing_template_store import ColorStripProcessingTemplateStore
from wled_controller.core.processing.sync_clock_manager import SyncClockManager
from wled_controller.core.automations.automation_engine import AutomationEngine
from wled_controller.core.mqtt.mqtt_service import MQTTService
@@ -61,6 +62,7 @@ value_source_store = ValueSourceStore(config.storage.value_sources_file)
automation_store = AutomationStore(config.storage.automations_file)
scene_preset_store = ScenePresetStore(config.storage.scene_presets_file)
sync_clock_store = SyncClockStore(config.storage.sync_clocks_file)
cspt_store = ColorStripProcessingTemplateStore(config.storage.color_strip_processing_templates_file)
sync_clock_manager = SyncClockManager(sync_clock_store)
processor_manager = ProcessorManager(
@@ -74,6 +76,7 @@ processor_manager = ProcessorManager(
value_source_store=value_source_store,
audio_template_store=audio_template_store,
sync_clock_manager=sync_clock_manager,
cspt_store=cspt_store,
)
@@ -144,6 +147,7 @@ async def lifespan(app: FastAPI):
auto_backup_engine=auto_backup_engine,
sync_clock_store=sync_clock_store,
sync_clock_manager=sync_clock_manager,
cspt_store=cspt_store,
)
# Register devices in processor manager for health monitoring
@@ -281,10 +285,12 @@ async def pwa_service_worker():
# Middleware: no-cache for static JS/CSS (development convenience)
@app.middleware("http")
async def _no_cache_static(request: Request, call_next):
response = await call_next(request)
if request.url.path.startswith("/static/") and request.url.path.endswith((".js", ".css", ".json")):
path = request.url.path
if path.startswith("/static/") and path.endswith((".js", ".css", ".json")):
response = await call_next(request)
response.headers["Cache-Control"] = "no-cache, must-revalidate"
return response
return response
return await call_next(request)
# Mount static files
static_path = Path(__file__).parent / "static"