Set up Vitest (jsdom environment) and @testing-library/react.
api.test.ts — fetchRunningApps:
- returns parsed JSON on 2xx
- returns [] on non-ok HTTP status
- returns [] on network error (non-throwing contract)
KnobCard.test.tsx — app_volume:
- datalist is rendered with all supplied runningApps as options
- no datalist / list attr when runningApps is empty or omitted
- onChange called with the new value on input change
KnobCard.test.tsx — group_volume:
- app-picker select rendered with runningApps options
- no picker when runningApps is empty or omitted
- Add button disabled until an app is selected
- Add button enabled after selection
- clicking Add appends app to targets
- clicking Add skips duplicates (onChange not called)
- picker resets to placeholder after a successful Add
- FastAPI + uvicorn server (turnup-ui) serving config API and static files
- React + TypeScript frontend: connection, global LEDs, per-knob/button
cards, preset save/load/apply, toast notifications, dark theme
- Vite builds into src/turnup/ui/static/ so no Node.js needed at install time
- PWA assets (manifest, service worker, icon) in ui/public/
- turnup-ui.service systemd user unit; enabled globally via turnupd.install
- PKGBUILD: add python-fastapi + python-uvicorn deps, install UI service file
- pyproject.toml: ui extras group, turnup-ui entry point