add SPA config UI, wire media/rss adapters, event-driven layout push

- React SPA: dashboard, data sources CRUD, widgets CRUD, layout builder,
  presets. TanStack Router + Query, shadcn/ui, Vite proxy to :3000
- wire media + rss adapters into polling loop, remove xtb source type
- media adapter: read username/password from headers, proper subsonic auth
- event handler: subscribe to LayoutChanged, push screen update to clients
- fix clippy warnings across workspace (Default impls, collapsible ifs,
  redundant closures, is_none_or, unused imports)
This commit is contained in:
2026-06-19 00:12:42 +02:00
parent 21c08911df
commit 26ebfad3a2
175 changed files with 12338 additions and 801 deletions

View File

@@ -1,6 +1,6 @@
use std::future::Future;
use crate::entities::WidgetId;
use crate::value_objects::{Layout, WidgetState};
use std::future::Future;
pub trait BroadcastPort {
type Error;

View File

@@ -1,27 +1,53 @@
use std::future::Future;
use crate::entities::{
DataSource, DataSourceId, LayoutPreset, LayoutPresetId, WidgetConfig, WidgetId,
};
use crate::value_objects::Layout;
use std::future::Future;
pub trait ConfigRepository {
type Error;
fn get_widget(&self, id: WidgetId) -> impl Future<Output = Result<Option<WidgetConfig>, Self::Error>> + Send;
fn get_widget(
&self,
id: WidgetId,
) -> impl Future<Output = Result<Option<WidgetConfig>, Self::Error>> + Send;
fn list_widgets(&self) -> impl Future<Output = Result<Vec<WidgetConfig>, Self::Error>> + Send;
fn save_widget(&self, config: &WidgetConfig) -> impl Future<Output = Result<(), Self::Error>> + Send;
fn save_widget(
&self,
config: &WidgetConfig,
) -> impl Future<Output = Result<(), Self::Error>> + Send;
fn delete_widget(&self, id: WidgetId) -> impl Future<Output = Result<(), Self::Error>> + Send;
fn get_data_source(&self, id: DataSourceId) -> impl Future<Output = Result<Option<DataSource>, Self::Error>> + Send;
fn list_data_sources(&self) -> impl Future<Output = Result<Vec<DataSource>, Self::Error>> + Send;
fn save_data_source(&self, source: &DataSource) -> impl Future<Output = Result<(), Self::Error>> + Send;
fn delete_data_source(&self, id: DataSourceId) -> impl Future<Output = Result<(), Self::Error>> + Send;
fn get_data_source(
&self,
id: DataSourceId,
) -> impl Future<Output = Result<Option<DataSource>, Self::Error>> + Send;
fn list_data_sources(
&self,
) -> impl Future<Output = Result<Vec<DataSource>, Self::Error>> + Send;
fn save_data_source(
&self,
source: &DataSource,
) -> impl Future<Output = Result<(), Self::Error>> + Send;
fn delete_data_source(
&self,
id: DataSourceId,
) -> impl Future<Output = Result<(), Self::Error>> + Send;
fn get_layout(&self) -> impl Future<Output = Result<Option<Layout>, Self::Error>> + Send;
fn save_layout(&self, layout: &Layout) -> impl Future<Output = Result<(), Self::Error>> + Send;
fn get_preset(&self, id: LayoutPresetId) -> impl Future<Output = Result<Option<LayoutPreset>, Self::Error>> + Send;
fn get_preset(
&self,
id: LayoutPresetId,
) -> impl Future<Output = Result<Option<LayoutPreset>, Self::Error>> + Send;
fn list_presets(&self) -> impl Future<Output = Result<Vec<LayoutPreset>, Self::Error>> + Send;
fn save_preset(&self, preset: &LayoutPreset) -> impl Future<Output = Result<(), Self::Error>> + Send;
fn delete_preset(&self, id: LayoutPresetId) -> impl Future<Output = Result<(), Self::Error>> + Send;
fn save_preset(
&self,
preset: &LayoutPreset,
) -> impl Future<Output = Result<(), Self::Error>> + Send;
fn delete_preset(
&self,
id: LayoutPresetId,
) -> impl Future<Output = Result<(), Self::Error>> + Send;
}

View File

@@ -1,6 +1,6 @@
use std::future::Future;
use crate::entities::DataSource;
use crate::value_objects::Value;
use std::future::Future;
pub trait DataSourcePort {
type Error;

View File

@@ -1,5 +1,5 @@
use std::future::Future;
use crate::events::DomainEvent;
use std::future::Future;
pub trait EventPublisher {
type Error;

View File

@@ -1,9 +1,9 @@
mod broadcast;
mod config_repository;
mod data_source_port;
mod broadcast;
mod event;
pub use broadcast::BroadcastPort;
pub use config_repository::ConfigRepository;
pub use data_source_port::DataSourcePort;
pub use broadcast::BroadcastPort;
pub use event::EventPublisher;