Commit Graph

1150 Commits

Author SHA1 Message Date
lebaudantoine 4830ea5673 🩹(frontend) fix reaction toolbar refocusing first button on click
The toolbar's onFocus handler called focusManager.focusFirst() whenever
focus arrived from outside the toolbar, which included clicks on
reaction buttons. This caused focus (and the scroll viewport) to snap
back to the first button on every click.

Use :focus-visible to distinguish keyboard focus from pointer focus.
Only redirect to the first button when focus arrives via keyboard,
leaving click-induced focus untouched.

Co-authored-by: Cyril <c.gromoff@gmail.com>
2026-05-22 17:24:17 +02:00
lebaudantoine e21da647a0 (frontend) handle notifications by reusing the existing notif region
Render the notification region from the main window into the PiP
document via a portal, rather than duplicating it. This keeps a
single listener, a single store, and a single component instance —
so notifications stay consistent across both windows without extra
synchronization.

Simplest approach I could find. Good enough as a first pass;
worth revisiting if the requirements grow.

Co-authored-by: Cyril <c.gromoff@gmail.com>
2026-05-22 17:24:17 +02:00
lebaudantoine 38c131e02c (frontend) introduce the camera stage
The core component of the PiP layout. Adapted from a simplified version
of @ovgodd's work in #890 — see that PR for context on the original design.

Co-authored-by: Cyril <c.gromoff@gmail.com>
2026-05-22 17:24:17 +02:00
lebaudantoine 8b8f9eae92 (frontend) add an options menu to the PiP window
Adding a menu turned out to be tricky. Our usual menu primitive
is built on react-aria, which positions overlays based on the
`window` object. Since the JS runs in the main window, the
computed position refers to the main window's coordinates, and
the menu renders in the wrong place inside the PiP document.

After investigating, we couldn't find a clean way to make
react-aria target the PiP window's `window`/`document` without
significant rework. Agreed with @ovgodd to duplicate the menu in
the PiP window as a pragmatic workaround until a better approach
emerges.

Co-authored-by: Cyril <c.gromoff@gmail.com>
2026-05-22 17:24:17 +02:00
lebaudantoine 4456137948 (frontend) add a basic control bar to the PiP window
The PiP control bar shares state with the main window's control
bar — most importantly, the reaction toolbar and the mic/camera
toggles, which are fully stateful.

Sharing state works naturally here because the PiP content is
rendered through a portal into the same React tree, so the
controls in both windows read from and write to the same stores.

Co-authored-by: Cyril <c.gromoff@gmail.com>
2026-05-22 17:24:17 +02:00
lebaudantoine faa86b8293 ♻️(frontend) add prop to disable reaction toolbar centering adjustment
The main window computes a JS offset to align the reaction toolbar
with the (off-center) reaction toggle. PiP and mobile don't need
this — centering the toolbar is enough. Add `adjustedCentering` to
opt out.

Not a great seam: the component shouldn't know about its host.
A cleaner fix would move the alignment concern to the parent.
Leaving for now to unblock PiP.

Co-authored-by: Cyril <c.gromoff@gmail.com>
2026-05-22 17:24:17 +02:00
lebaudantoine ae9cda463e (frontend) show a visual placeholder while picture-in-picture is open
When the PiP window is active, replace the corresponding content
in the main window with a lightweight placeholder. This avoids
rendering the camera feed (and other expensive media) twice when
the user is only watching the PiP window.

Co-authored-by: Cyril <c.gromoff@gmail.com>
2026-05-22 17:24:17 +02:00
lebaudantoine e9e4b360a0 (frontend) introduce basic document picture-in-picture hook
Add a hook that manages the logic needed to open a document
picture-in-picture window, stores a ref to the window in a global
store, and—once ready—mounts a portal to duplicate content into
the PiP document's container.

Mounting the PiP content via a portal lets us share the same React
tree as the main app, and therefore share application state. This
comes with some trade-offs, particularly around components that
rely on the DOM hierarchy: react-aria popovers and overlays may
not behave correctly across documents.

The logic is kept to a minimum here. This first commit does nothing
more than open a window containing a loading spinner. The topic is
new to us, so plenty is likely to be refined in follow-ups.

Co-authored-by: Cyril <c.gromoff@gmail.com>
2026-05-22 17:24:17 +02:00
lebaudantoine eb74feaa0d ️(frontend) improve accessibility and navigation for reaction toolbar
Refine keyboard behavior so left and right arrow keys no longer
control toolbar navigation, allowing users to directly tab into
individual reaction buttons for faster and more intuitive access.

Remove the reaction toolbar from accessibility tree to avoid
unnecessary focus and announcements, keeping assistive technology
focused on the actual reaction controls.

This ensures the UX centers on reaction actions rather than
auxiliary navigation elements.

Also, not related to this topic, I've reworked the scroll viewport styles.
2026-05-18 23:09:45 +02:00
lebaudantoine 318447f2b3 🩹(frontend) add missing disabled styling for primaryDarkText button
Implement the missing disabled state styling for the
primaryDarkText button variant to ensure consistent UI feedback
when the button is not interactive.
2026-05-18 23:09:45 +02:00
lebaudantoine 224707f4c7 (frontend) enable reactions on mobile devices
Allow reaction interactions on mobile.

Adding the toolbar toggle currently impacts the responsive layout
of the control bar on very small screens. This will be improved in
a future PR with an auto-collapsing mobile control bar.
2026-05-18 23:09:45 +02:00
lebaudantoine d47d13f041 🩹(frontend) improve reaction toolbar centering with dynamic positioning
Replace the previous hardcoded offset approach with a dedicated
hook that dynamically centers the reaction toolbar relative to the
reaction toggle.

This improves layout accuracy and removes reliance on fixed values.

Note: ResizeObserver is used for positioning updates and may not
be supported in older browsers. Additional testing will be
performed before production release.

Replace direct DOM queries using hardcoded IDs with proper constants.
2026-05-18 23:09:45 +02:00
lebaudantoine b4ced74b1f (frontend) make reaction toolbar responsive on small viewports
Add horizontal navigation support using left/right arrow controls
to scroll through available reactions on smaller screens.

This work is inspired by Cyril's implementation.
2026-05-18 23:09:45 +02:00
lebaudantoine ecf5d443d6 ♻️(frontend) refactor strip components and improve naming clarity
Rename strip-related components into a more generic container
abstraction.

Extract the buttons container into a dedicated component file and
update related naming to improve readability and maintainability.
2026-05-18 23:09:45 +02:00
lebaudantoine 0737974f6d ♻️(frontend) refactor reaction keyboard navigation into a component
Extract keyboard navigation logic for reactions into a separate
component/file to reduce file size and improve maintainability.
2026-05-18 23:09:45 +02:00
lebaudantoine 5e030c2a07 ♻️(frontend) refactor useMuteParticipant hook
Fix unreachable code when notifying participants that they were
muted.

Prevent unnecessary function re-creations when props remain
unchanged.

Also guard against missing tokens by logging an error and
returning early when the token is undefined.
2026-05-17 23:39:53 +02:00
lebaudantoine 32fbedd358 (backend) extend live synchronization to lobby access level updates
Extend the existing live synchronization mechanism beyond room
configuration to also include lobby access level changes.

This ensures that all owners and admins sharing a room maintain a
consistent and up-to-date view of room state in the frontend,
including configuration and access control updates.
2026-05-17 23:39:53 +02:00
lebaudantoine aab90650f1 (frontend) add synchroniser for room metadata updates
Listen to room metadata change events and synchronize the React
Query cache with the latest room data fetched from the API.

This ensures clients react to live configuration updates, such as
showing or hiding mute controls when `everyone_can_mute` changes.
2026-05-17 23:39:53 +02:00
lebaudantoine 5bac1668fe ♻️(fullstack) simplify source serialization
Simplify source serialization and validation logic while improving
type safety around room configuration handling.

Introduce a dedicated TypeScript type matching the backend
Pydantic model more precisely.

Also harmonize track source casing between frontend and backend to
remove redundant conversion logic and resolve #1282.
2026-05-17 23:39:53 +02:00
lebaudantoine c20daafd81 (fullstack) support everyone_can_mute room configuration
Introduce a new room setting controlling whether all participants,
including non-privileged users, can mute others.

Update API validation accordingly and add the frontend controls
allowing administrators to toggle the option and persist the
configuration through the API.
2026-05-17 23:39:53 +02:00
lebaudantoine 9846a61bd0 (frontend) update useCanMute hook to reflect room muting behavior
Allow non-privileged users to mute others when the
everyone_can_mute configuration is unset or true.

This setting is not yet customizable by room owners and will be
introduced in a future update.
2026-05-17 23:39:53 +02:00
lebaudantoine 388b7d172d (frontend) allow unauthenticated participants to mute via LiveKit token
Pass the LiveKit token when calling the mute-participant endpoint
to authenticate the request.

This enables non-authenticated participants to mute others through
the API while preserving proper authorization checks.
2026-05-17 23:39:53 +02:00
lebaudantoine dcaa45ccfe 🩹(frontend) fix subtitle background regression
Restore transparent background as the default subtitle background
to match previous behavior.
2026-05-14 15:04:48 +02:00
lebaudantoine 35951ba2a6 🔖(minor) bump release to 1.16.0 2026-05-13 22:30:32 +02:00
lebaudantoine 72184e1370 🩹(frontend) fix spacing regression in mobile control bar
Correct excessive spacing between action buttons in the mobile
control bar introduced by a recent layout change.
2026-05-13 20:15:32 +02:00
lebaudantoine cca5bc2186 ⬆️(frontend) update dependencies 2026-05-12 16:26:16 +02:00
lebaudantoine f8937fc0a1 ♻️(frontend) improve and simplify accessibility font override logic
Fix compatibility issues with the DINUM frontend image, which
overrides the default `font-sans` value.

Simplify the implementation by having the JavaScript layer only
toggle well-scoped CSS classes responsible for accessibility font
overrides. This makes the behavior more predictable and restoring
default styles straightforward.

Also clarify the intent of the hook by making its accessibility
purpose explicit and moving its usage to the App component, where
it better fits the application lifecycle.
2026-05-07 11:20:15 +02:00
Cyril 97b5e3e65c (frontend) add font selector in accessibility settings
Dropdown with description and FR/EN/NL translations.
2026-05-07 11:20:15 +02:00
Cyril b917d82f7e (frontend) apply font preference to app layout
Hook, CSS variable and LiveKit integration for custom fonts.
2026-05-07 11:20:15 +02:00
Cyril 82d146cdf5 (frontend) install accessibility font packages
Lexend, Atkinson Hyperlegible Next and OpenDyslexic via fontsource.
2026-05-07 11:20:15 +02:00
Cyril cbfeea0a4e (frontend) add uiFont preference to accessibility store
Add UiFont type with four options and Extend AccessibilityState.
2026-05-07 11:20:15 +02:00
tuanaiseo fc260b2686 🔒️(frontend) room ids are generated with non-cryptographic rand
Room identifiers are created with `Math.random()`, which is predictable
and not suitable for security-sensitive identifiers. Predictable
room IDs increase the risk of room enumeration and unauthorized
access attempts, especially when IDs are part of join URLs.

Affected files: generateRoomId.ts

Signed-off-by: tuanaiseo <221258316+tuanaiseo@users.noreply.github.com>
2026-05-04 23:47:47 +02:00
Sanjay Santhanam 6830250f2c ♻️(frontend) standardize role terminology across localizations
Fixes #1126 - Inconsistent role terminology in localization files.

Standardize on 'host' as the primary role term across en, de, and nl
locales, replacing mixed usage of 'administrator', 'organizer', 'admin',
'Organisator:in', 'Organisierende', and 'organisator'.
2026-05-04 18:44:20 +02:00
renovate[bot] 597eba6e8a ⬆️(dependencies) update postcss to v8.5.10 [SECURITY] 2026-05-04 16:48:46 +02:00
lebaudantoine 07698ddced 🔖(minor) bump release to 1.15.0 2026-05-01 00:16:34 +02:00
lebaudantoine dd3d47afe6 🩹(frontend) fix reconnect loop caused by connectionObserverStore updates
Updating connectionObserverSnapshot triggered page re-renders,
causing participants to reconnect due to a race condition.

Read directly from the underlying store instead of using the
snapshot to avoid unnecessary re-renders.
2026-04-30 18:32:43 +02:00
lebaudantoine 35863ec3b6 🩹(frontend) fix access control for screen recording feature flag
Ensure screen recording is properly disabled when the feature
flag is set to false.

Previously, no feature flag was enforced, allowing unintended
access.

Also update the blocked-access message to be more generic and not
specific to public sector users.
2026-04-30 13:38:10 +02:00
lebaudantoine 4548f69de8 🚧(addons) introduce initial Microsoft Outlook add-in support (alpha)
Provide the minimal components required to support an Outlook
add-in: user authentication, JWT retrieval, and API calls to
generate meeting links.

This implementation is an early alpha: developer experience is
limited, documentation is incomplete, and the solution is not
white-labeled.

It's too early to consider these parts ready to ship into
production.

As a result, it is currently only available within the DINUM
frontend image.
2026-04-29 16:03:48 +02:00
lebaudantoine 5e1e05b001 🩹(frontend) use a more standard (quality) rating scale
A 1–7 scale is not commonly used in software products. Feedback
from both users and the support team suggests reducing the number
of options to simplify usage and analysis.

Adopting a 1–5 scale improves usability and makes responses
easier to interpret and process.

The scale has to be odd.
2026-04-23 15:20:54 +02:00
lebaudantoine 3b474ba1c0 ♻️(backend) control metadata collector agent launch via feature flag
Allow controlling when the metadata collector agent is started,
enabling users to try the feature and disable it if needed.

Introduce a user-level feature flag to toggle the agent for the
initial release.
2026-04-17 12:17:27 +02:00
lebaudantoine aaf21e97e8 🔖(minor) bump release to 1.14.0 2026-04-16 22:12:48 +02:00
lebaudantoine bd3a26a2af 📈(frontend) track WebRTC peer candidates in PostHog events
Capture selected ICE candidates for both subscriber and publisher
peer connections.

This enables correlation between survey feedback and connectivity
setup, helping identify problematic network configurations.
2026-04-16 15:45:07 +02:00
lebaudantoine 4d222e4ab4 ⬆️(frontend) upgrade frontend image to Alpine 3.23 to address CVEs
Bump the base image to Alpine 3.23 to resolve most vulnerabilities
reported by Cyberwatch and Trivy.

Remaining issues require manual updates:
- musl / musl-utils: upgrade to 1.2.5-r11 (CVE-2026-40200)
- zlib: upgrade to 1.3.2-r0 (CVE-2026-22184)
2026-04-16 15:06:28 +02:00
Cyril f0fda145d9 ️(frontend) set explicit document title on recording download page
RecordingDownload now updates the tab title per state
2026-04-13 20:18:31 +02:00
Cyril d12ced352a ️(frontend) refocus reactions toolbar with shortcut when already open
Shortcut now opens it or moves focus to the first emoji button
2026-04-13 20:14:40 +02:00
lebaudantoine 170763a1f7 ️(frontend) optimize PostHog survey usage and enrich event metadata
Replace costly PostHog surveys with basic surveys, which better
fit our headless usage and avoid short data retention limits.

Enhance emitted events with additional metadata, including a
unique session ID and room ID, to correlate survey responses with
specific sessions.

This lays the groundwork for further enrichment with participant
connection data.
2026-04-09 19:11:33 +02:00
lebaudantoine 5d7a54e809 ♻️(backend) use Authorization header for LiveKit token authentication
Replace passing the LiveKit JWT in the request body with the
Authorization header, following standard authentication practices.

Extend the LiveKit authentication backend usage across additional
endpoints.

This also raises questions about how clients should securely
retrieve LiveKit tokens, to be addressed later.
2026-04-09 00:37:43 +02:00
lebaudantoine 6180ac4e4f 🔒️(backend) rely on backend to allow participant update their metadata
Introduce toggle-hand and rename endpoints in RoomViewSet,
secured with LiveKit token authentication.

Remove direct permission for clients to update their own metadata
via LiveKit tokens to prevent spoofing (e.g. faking admin status).

Proxy participant metadata updates through the backend to enforce
proper validation and authorization.

Signed-off-by: lebaudantoine <lebaud.antoine131@gmail.com>
2026-04-09 00:37:42 +02:00
dependabot[bot] 0c9b83c793 ⬆️(frontend) bump hono from 4.12.8 to 4.12.12 in /src/frontend
Bumps [hono](https://github.com/honojs/hono) from 4.12.8 to 4.12.12.
- [Release notes](https://github.com/honojs/hono/releases)
- [Commits](https://github.com/honojs/hono/compare/v4.12.8...v4.12.12)

---
updated-dependencies:
- dependency-name: hono
  dependency-version: 4.12.12
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-04-08 15:13:05 +02:00
renovate[bot] d8ccd02bb2 ⬆️(dependencies) update vite to v7.3.2 [SECURITY] 2026-04-07 19:12:24 +02:00