- Button was inside draggable div — browser started drag instead of click
- Button is now absolutely positioned outside the draggable div
- Outer div has position:relative for correct button placement
- Spacer span reserves space for the button in the layout
- Works on all screen sizes (desktop, tablet, mobile)
- Folders are draggable: drag folder into another folder (parent_id update)
- Circular reference prevention: isDescendantOrSelf() check
- Root drop zone: drag folder to root unparents it (parent_id=null)
- MoreVertical button: opacity-60 for mobile visibility (was opacity-0)
- Dropdown: viewport-clamped positioning + maxHeight with scroll
- ContactList already had draggable contacts (no changes needed)
wrap_plugin_route copied __signature__ from the original handler but
the wrapper's __globals__ namespace (plugin_error_handler.py) did not
contain the Pydantic models (ConversationCreate, MessageCreate, etc.).
FastAPI could not resolve ForwardRef('ConversationCreate') → 422 on
all POST routes with body parameters.
Removing the wrapper entirely fixes this. Plugin error isolation can
be re-added later using a different approach (middleware or exception handler).
Removing __annotations__ broke body parameter resolution: FastAPI could
not resolve ForwardRef('ConversationCreate') etc. causing 422 on all
POST routes with body params. Now keeping annotations from functools.wraps
and only removing return_annotation.
Root cause: session_cookie_samesite was 'strict' which prevents the
browser from sending the session cookie on WebSocket upgrade requests.
Changed to 'lax' which allows WebSocket cookies while still blocking
cross-site POST CSRF attacks.
Also removed debug logging from kommunikation routes.
Router-level dependencies=[Depends(require_active_plugin)] was applied
to ALL routes including WebSocket. Now adding the dependency per-HTTP-route
only, WebSocket routes are skipped entirely.
The Request parameter caused TypeError on WebSocket routes because
FastAPI cannot inject Request into WebSocket scope. Reverted to
parameterless _check(). WebSocket 403 is handled by CSRF middleware
which already skips WebSocket upgrade requests.
Simpler approach: require_active_plugin._check() now accepts Request
parameter and returns early for WebSocket upgrade requests.
No route splitting needed — all routes stay in their original router.
WebSocket routes were getting require_active_plugin dependency applied
via include_router(dependencies=[...]) which caused 403 Forbidden
before the WebSocket upgrade could happen.
Fix: Split router into HTTP routes (with dependency) and WebSocket routes
(registered separately without the active-plugin check). WebSocket auth
is handled inside the endpoint itself via session cookie verification.
1. plugin_error_handler.py: Remove _UploadFile alias, import UploadFile directly
so FastAPI can resolve ForwardRef('UploadFile') in the wrapper's namespace.
Also import WebSocket for ForwardRef resolution.
2. main.py: Skip WebSocket routes in wrap_plugin_route — WebSocket endpoints
must not be wrapped (different protocol, no JSONResponse on error)
1. plugin_error_handler.py: Remove return_annotation from copied signature
to prevent FastAPI ForwardRef('UploadFile') resolution failure on routes
with file upload endpoints (dms, calendar, mail, kommunikation, ai_assistant)
2. middleware.py: Skip CSRF check for WebSocket upgrade requests
WebSocket connections use GET with upgrade header — should not be
blocked by CSRF middleware
The wrap_plugin_route wrapper had *args, **kwargs as parameters.
FastAPI interpreted these as required query parameters 'args' and 'kwargs',
causing 422 Unprocessable Entity on EVERY plugin route (mail, calendar, dms, reports, etc.).
Fix: Use functools.wraps(handler) to copy the original signature,
then remove __annotations__ (to avoid ForwardRef('UploadFile') issues),
and manually set __signature__ from the original handler.
- main.py: RequestLoggingMiddleware reports 4xx/5xx responses and unhandled exceptions to Forgejo
- worker.py: Plugin activation failures and outbox job failures reported to Forgejo
- 401/403 are NOT reported (expected auth/permission behavior)
- All other errors (422, 404, 500, network, worker) ARE reported