Excalidraw: Data-loss Fix & Message Reducing

Summary

Hardening and cleanup pass on the Excalidraw whiteboard integration, bundling four related changes:

  1. Prevent storing an empty canvas — stop a mount-window race from wiping everyone's drawing
  2. Hide the Excalidraw help button — remove the footer ? that exposes external links
  3. Strip appState from the persistence/broadcast path — reduce per-message overhead and remove dead, never-read state
  4. Add a stopped message handler — react to the whiteboard being stopped server-side

Implementation notes

1. Prevent storing empty canvas (WhiteboardView.tsx)

  • queueStoreSceneToBackend now filters to syncable elements first and returns early when the result is empty, so a transient empty onChange during the Excalidraw mount window can no longer overwrite the stored scene.

Definition of done

  • Empty/transient onChange no longer dispatches store_scene - existing drawing is preserved on (re)join
  • Clearing the canvas and erasing still persist and sync correctly
  • Help ? button is not visible in the whiteboard footer
  • No appState field present in store_scene / broadcast payloads

QA notes

  • Empty-canvas race: With an existing drawing, repeatedly join/switch into the whiteboard (ideally throttle network) and confirm the board is never blanked for other participants.
  • Erase/clear still works: Draw → Clear Canvas / eraser → confirm the cleared state persists and propagates to other participants and late joiners.
  • Help button: Open the whiteboard, confirm the footer ? is gone and no external links are reachable from it. (Note: keyboard-shortcut discovery via that dialog is also removed - accepted tradeoff.)
  • Message slimming: Inspect a store_scene / broadcast action in Redux devtools - payload should contain elements only, no appState