Commit Graph

2418 Commits

Author SHA1 Message Date
Cyril 13841573ea (frontend) add wheel zoom shortcut hints to screen share controls
Show Ctrl/Cmd+scroll zoom shortcut in tooltips, aria, SR hints, w/ en/fr/nl/de.
2026-09-02 10:18:14 +02:00
Cyril 3f3c9337c8 💄(frontend) improve screen share zoom toolbar sizing and containment
Slightly enlarge toolbar controls while clipping hover states inside the pill so buttons no longer overflow the bar.
2026-09-02 10:18:14 +02:00
Cyril d7206e9e46 💄(frontend) use distinct expand/collapse icons for fullscreen actions
Replace fullscreen icons with expand-diagonal-line and collapse-diagonal-line
2026-09-02 10:18:14 +02:00
Cyril e0e3b91f5d 🌐(frontend) add i18n keys for screen share zoom controls
English and French labels, SR announcements and pan navigation hint.
2026-09-02 10:18:14 +02:00
Cyril d4fa88d9ca (frontend) add ScreenShareZoomableVideo component for zoomable screen shares
Wraps VideoTrack with zoom/pan, keyboard nav and screen reader announcements.
2026-09-02 10:18:14 +02:00
Cyril 3c8b247a99 (frontend) add ScreenShareZoomControls toolbar component
Bottom-right toolbar with zoom, fit-to-window and fullscreen buttons.
2026-09-02 10:13:54 +02:00
Cyril 6b2d67cf61 (frontend) add useScreenShareZoom hook for zoom and pan state management
Manages zoom level, pan offset, wheel zoom, drag-to-pan and keyboard panBy.
2026-09-02 10:13:54 +02:00
kaelvar 1ac1778521 🐛(frontend) keep the sending resolution picked while the camera is off
`handleVideoResolutionChange` did all of its work inside `if (videoTrack)`,
including `saveVideoPublishResolution`. With the camera off there is no camera
publication, so choosing a resolution did nothing at all: it was neither applied
nor recorded, while the selector went on showing the value the user had just
picked. Turning the camera back on then published at the old resolution, and so
did the next session.

Found on a self-hosted instance: a user set the sending resolution with the
camera off, turned it back on, and the publisher kept sending 720p. Nothing in
the UI suggested the choice had been dropped.

Persist the choice first and unconditionally, then restart the track only when
there is one to restart.

Persisting alone is not enough within a session. `roomOptions` is only read by
`new Room(...)`, so a store update never reaches a room that is already built.

Sync the VideoDeviceControl with the userChoiesStore resolution, as we did for
the device id and the processor configuration.

The early return is the honest shape here: with no live track there is nothing
to await, and the defaults above already cover what happens next.
2026-09-02 00:11:43 +02:00
lebaudantoine fcc58065d2 🩹(changelog) fix changelog entry ordering
Restore the correct order of entries in the CHANGELOG, which got
shuffled somewhere between rebases.
2026-09-01 22:08:37 +02:00
lebaudantoine 21c57bffb4 🧑‍💻(devx) add a WebRTC stats and network throttling devtool
Introduce an in-app devtool that monitors WebRTC statistics in
real time and lets developers simulate various network scenarios,
including constraining the uplink and downlink bandwidth.

Makes it much easier to reproduce and investigate connectivity or
quality issues locally without depending on external tools.

The code was AI generated, and might contain some smell.
It's only enabled in dev, and not included in the production
build. Feel free to enhance it as needed.
2026-09-01 22:05:53 +02:00
lebaudantoine bd81c99495 🔧(devx) configure a TURN server on the local LiveKit dev stack
Wire a TURN server into the local LiveKit server used by the dev
stack, so ICE negotiation has more candidate types available during
local testing.

Makes it easier to reproduce connectivity scenarios that would
otherwise only show up on stricter networks in production.
2026-09-01 22:05:53 +02:00
lebaudantoine 839cfa4b80 📝(docs) document v1.30.0 in UPGRADE.md
Add the missing v1.30.0 entry in `UPGRADE.md`, which was overlooked
when the release was published.
2026-09-01 16:22:57 +02:00
lebaudantoine f3673457c3 🐛(summary) refresh summary uv.lock
The summary `uv.lock` had not been updated in the last few releases.
The CI is now refactored to use `uv sync --locked`, which fails when
the lockfile is out of sync with `pyproject.toml`.

Regenerate the lockfile so `uv sync --locked` passes again.
v1.30.0
2026-09-01 13:59:43 +02:00
lebaudantoine 86797d004c 🔖(minor) bump release to 1.30.0 2026-09-01 13:59:43 +02:00
davd-gzl 02a355136f 🔒️(ci) escape the downloaded gitmojis before the regex
The rule joins the list it fetches into an alternation, so any regex character
in a gitmoji entry would change what the pattern matches. re.escape treats each
one as a literal, which is what the match was always meant to do.
2026-08-31 19:03:27 +02:00
davd-gzl fbeb035f50 🔒️(ci) install every Python job through uv
lint-git runs gitlint through uvx, which fetches it for that one command and
puts nothing in the runner's Python. lint-summary and test-summary sync from a
new src/summary/uv.lock, so the versions those jobs resolve are the versions in
the tree, which is what src/backend and src/agents already do. The agents sync
refuses source distributions, since that package installs no project of its own.

Follows suitenumerique/menshen#73.
2026-08-31 19:03:27 +02:00
davd-gzl a0dbfa9357 🔥(ci) drop the requests dependency from the gitmoji rule
The rule downloaded the gitmoji list with requests, so lint-git had to install
that package before the linter could run. urllib.request is in the standard
library and answers the same call, leaving one fewer package fetched on the
runner before the job's own command starts.
2026-08-31 19:03:27 +02:00
davd-gzl 0e9660ead3 🔥(ci) leave the action pins to Renovate 2026-08-31 19:03:27 +02:00
davd-gzl 1721eb0884 🔒️(ci) keep uv run from building a source distribution
--no-sync already stops uv run resolving an environment of its own,
and that is what the version findings were about. Building is a
separate guarantee that nothing on the line carried, so --no-build
now says it outright. It is inert beside --no-sync, and the three
lint jobs are unchanged.
2026-08-31 19:03:27 +02:00
davd-gzl 7538cd886b 🚚(ci) rename meet.yml to ci.yml
The repository is already called meet, so the file name said nothing
about what the workflow holds. The print-statement check now excludes
the whole workflows directory rather than one file by name: its own
grep carries the literal print(, so the rename would otherwise match
it on the deleted lines and fail the job.
2026-08-31 19:03:27 +02:00
davd-gzl aafbc752d5 🔒️(ci) pin every action to a full commit hash
A tag and a branch both move, so actions/checkout@v6 and
numerique-gouv/action-trivy-cache@main ran whatever the owner had last
pushed. Each of the 65 uses now names a 40-character commit, with the
version it resolved to in a trailing comment.

dependabot.yml keeps the hash and that comment moving together.
2026-08-31 19:03:27 +02:00
davd-gzl a24100aceb 🔒️(ci) harden the remaining fetches in the workflow
gitlint-core keeps the linter at 0.19.1, which the wheels-only pin was
resolving down to 0.18.0 through an sdist-only sh. --ignore-scripts
stops three npm ci, one yarn install and one npm install -g running
the scripts of what they fetch, and yarn is pinned to 1.22.22. curl
holds the dockerize download and its redirects to https.
2026-08-31 19:03:27 +02:00
davd-gzl 9e2383a341 🔒️(ci) install dependencies without running their setup code
A package could run arbitrary code on the runner while installing,
and the versions were resolved rather than taken from the pins.
The two pip calls now take wheels only, and uv run no longer
resolves an environment of its own.
2026-08-31 19:03:27 +02:00
moustique82 80d37595ad (frontend) expose publish permissions in MediaStateObserver
The component exposes the local microphone and camera state so external
tools automating the frontend can read it. It does not expose whether
publication is allowed, so such a tool cannot tell a muted microphone from
one it is not permitted to unmute, and ends up offering a control that
silently does nothing.

Expose canPublishMicrophone and canPublishCamera in the event detail and as
data attributes, reusing the useCanPublishTrack hook that already gates the
web client controls. The permissions are part of the effect dependencies so
a mid-meeting permission change emits the event.
2026-08-31 16:55:36 +02:00
snyk-bot 2daa668075 ⬆️(addons) upgrade core-js from 3.49.0 to 3.50.0
Snyk has created this PR to upgrade core-js from 3.49.0 to 3.50.0.

See this package in npm:
core-js

See this project in Snyk:
https://app.eu.snyk.io/org/lasuite-dinum-default/project/af693e79-8c43-4c09-ab65-60580515c9e8?utm_source=github&utm_medium=referral&page=upgrade-pr
2026-08-31 16:43:41 +02:00
Cyril a1e7978348 ️(frontend) announce Escape close hint on side panels
Show "(Escape)" in close tooltip, add aria-describedby for SR keyboard hint.
2026-08-31 15:57:59 +02:00
Cyril 4fa044fa3e ️(frontend) close side panel with Escape key
useEscapeToClose: close panel on Escape, restore focus, let chat input bubble
2026-08-31 15:57:59 +02:00
leo 2c5dd151f1 ♻️(backend) factorize s3 client creation in utils
Factorize s3 client creation in utils for code simplification.
2026-08-31 15:44:38 +02:00
leo a33e35111c ♻️(devex) update Makefile lint targets and harmonize service naming
The make lint target did not cover the summary and agents components. Update
the linting workflow to include both services and harmonize Makefile target
names. Harmonize Docker compose user declarations.
2026-08-31 14:52:10 +02:00
snyk-bot 02714c869a ⬆️(frontend) upgrade @fontsource/opendyslexic from 5.2.5 to 5.3.0
Snyk has created this PR to upgrade @fontsource/opendyslexic from 5.2.5 to 5.3.0.

See this package in npm:
@fontsource/opendyslexic

See this project in Snyk:
https://app.eu.snyk.io/org/lasuite-dinum-default/project/96ea03d8-8d09-493d-86bf-363f274e129e?utm_source=github&utm_medium=referral&page=upgrade-pr
2026-08-31 14:37:44 +02:00
snyk-bot 826cfe0c62 ⬆️(frontend) upgrade @fontsource-variable/lexend from 5.2.11 to 5.3.0
Snyk has created this PR to upgrade @fontsource-variable/lexend from 5.2.11 to 5.3.0.

See this package in npm:
@fontsource-variable/lexend

See this project in Snyk:
https://app.eu.snyk.io/org/lasuite-dinum-default/project/96ea03d8-8d09-493d-86bf-363f274e129e?utm_source=github&utm_medium=referral&page=upgrade-pr
2026-08-31 14:10:02 +02:00
Louis-Jean Teitelbaum ab62ae71ea 🐛(frontend) fix chat text-area bug
Whenever a character was typed, the caret would jump
to the end of the textarea. Fixes #1656.
2026-08-31 13:59:39 +02:00
Miguel Victoria 3991235903 More natural language on interface 2026-08-31 13:59:21 +02:00
Miguel Victoria d2a74a20fd chore: improve backend translations 2026-08-31 13:59:21 +02:00
Miguel Victoria 0446d1e824 update comment lines on django.po files 2026-08-31 13:59:21 +02:00
Villaquiranm a20a0a6b38 🌐(i18n) add Spanish language support
Add Spanish to the language selection system on both trees, with 872
frontend phrases and 145 backend ones translated from the French source.

The frontend to backend language map gains it too, so a Spanish browser
does not write an empty language to the account on every load.
2026-08-31 13:59:21 +02:00
snyk-bot 564b3dc595 ⬆️(frontend) upgrade posthog-js from 1.409.5 to 1.414.0
Snyk has created this PR to upgrade posthog-js from 1.409.5 to 1.414.0.

See this package in npm:
posthog-js

See this project in Snyk:
https://app.eu.snyk.io/org/lasuite-dinum-default/project/96ea03d8-8d09-493d-86bf-363f274e129e?utm_source=github&utm_medium=referral&page=upgrade-pr
2026-08-31 13:56:44 +02:00
leo 0a0cdae896 (agent) support Voxtral realtime as inference engine
The Kyutai open-source model turned out not to be production-ready:
it caused disruptions in the production environment, especially on
long-running meeting sessions.

Switch to the Voxtral realtime model, which looks like a
credible competitor and behaves much better in our setup.

For now, the code handling the Voxtral realtime API lives directly
in the project. It could be extracted into an open-source package
later.

See PR #1277 for the full details of the implementation, proposed
by @cameldev.
2026-08-28 12:18:52 +02:00
leo c7e3168ba3 🔥(backend) remove the S3 storage-event webhook for recordings
Recordings used to be finalized by an inbound notifications sent by
S3. This tied the recording lifecycle to bucket notifications, adding
complexity and dependency to limited S3 services.

The LiveKit egress_ended webhook, added as a fallback in aee1847, does
the same job without any object-storage dependency. Make it the only
mechanism: RecordingEventsService.handle_complete is now called on
EGRESS_COMPLETE / EGRESS_LIMIT_REACHED unconditionally, instead of only
when RECORDING_STORAGE_EVENT_ENABLE is False. Remove the storage-event
path entirely.
2026-08-27 23:09:48 +02:00
lebaudantoine f1d3799434 🔖(minor) bump release to 1.29.0 v1.29.0 2026-08-25 23:22:29 +02:00
lebaudantoine e59aaaa998 📝(changelog) fix a minor changelog issue
Wrongly added to an old section during a rebase.
2026-08-25 23:14:16 +02:00
lebaudantoine 76a24d4787 ️(backend) replace blocking Redis KEYS with cursor-based SCAN
`cache.keys()` runs Redis `KEYS`, a full-keyspace scan on Redis's
single thread that blocks everything else, including session reads
in the same cache. Its cost scales with total keys, not matches,
and some managed providers disable `KEYS` entirely.

The trusted-lobby feature made this urgent: the waiting-list
endpoint scanned on every poll, and its polling audience grows from
a few admins to potentially every authenticated participant.

Switch to cursor-based `SCAN` via two `core.utils` helpers, deleting
in bounded batches so cleanup of a large room cannot block either.
A single seam also lets us forbid raw `cache.keys()` going forward.

`SCAN` still iterates the keyspace incrementally on the polled
path. If monitoring flags it, the follow-up is a per-room set
index — out of scope here since it changes the lobby storage model.
2026-08-25 22:48:47 +02:00
lebaudantoine 943b81676b (frontend) let authenticated users manage the lobby on trusted rooms
Frontend counterpart of the trusted-lobby backend feature: on
`trusted` rooms, any authenticated participant sees the waiting
notification and can accept or deny entry requests, not only admins
and owners.

Gating moves from role to capability: `useCanManageLobby` mirrors
the backend permission and derives from `useRoomData()`. Room
metadata is already synced into the query cache, so an access-level
change mid-meeting recomputes the capability on every client with no
new sync mechanism. It is only a UI gate; the backend re-checks
everything per request and fails closed.

Fetching moves into a single room-level `LobbyProvider`: the hook
was previously instantiated by two components and only worked
because React Query deduplicated their queries. The provider owns
one query and an explicit state machine - ways in (connection
established, ParticipantWaiting broadcast, panel opened, rights
regained while the panel is open) all arm and fetch; ways out
(rights lost, server 401/403) disarm and clear the cached list so
nothing stale can render.

Polling is tiered by audience since managers grow from a few admins
to potentially the whole room: 1s when acting (panel open),
10s when the notification is shown, and zero when the list is empty -
decided in the refetchInterval callback because structural sharing
suppresses data-keyed effects on identical empty responses. A quiet
room costs nothing; fetches are triggered by uncorrelated human
events, never synchronized across the room (the rights-regained
trigger is panel-gated for this reason).
2026-08-25 22:48:47 +02:00
lebaudantoine 7369379106 (backend) let any authenticated user manage the lobby on trusted rooms
On rooms with the `trusted` access level, any authenticated user
connected to the meeting can now manage the lobby. Requested by
several organizations, and a step toward generalized lobby
management once hubs and groups land (same organization only).

Being authenticated is not enough to grant the capability: a
`trusted` room means "trusted to join", not "trusted to decide who
else joins from outside the call". The new `CanManageLobby`
permission therefore also requires the requester to be currently
connected to the meeting, verified against LiveKit and failing
closed, like `IsPresentInMeeting`. The access level itself is never
cached and always read fresh, so an owner switching the room back to
`restricted` revokes the capability on the very next request - the
one guarantee we did not want to trade for performance.

Performance is traded elsewhere: the waiting list is polled by every
lobby manager, and on a trusted room that audience grows from a few
admins to potentially the whole meeting. Hitting LiveKit once per
poll per participant would not survive that fan-out, so presence is
memoized in Redis (`PresenceCache`, `PRESENCE_CACHE_TIMEOUT`, 1h).
Entries are created lazily because only the minority of participants
who actually manage a lobby ever need one, and only positive answers
are cached because a sticky negative would lock out someone joining
right after a miss for the whole TTL. Eager invalidation on
`participant_left`, `room_finished` and admin kick keeps the cache
honest; the TTL is the safety net when an event is lost, and its
value bounds how long a departed participant could still act.

Trade-offs in this v0:

* `PRESENCE_CLEAR_ON_PARTICIPANT_LEFT` gates the eager invalidation
  on `participant_left`: its cost is one Redis DELETE per departure,
  for every departure, so we want to be able to measure it in
  production and turn it off independently of the feature. When
  disabled, invalidation relies on `room_finished` and the TTL only,
  widening the stale window above.
* This can put non-trivial pressure on the cache at scale; the
  rollout will need to be monitored closely.
* The `participant_left` webhook must be enabled in the LiveKit
  deployment, otherwise eager invalidation silently degrades to the
  TTL-only behavior.
2026-08-25 22:48:47 +02:00
lebaudantoine c02d54b6ff ️(frontend) apply frugal constraint to the active meeting audio track
Apply the `VOICE_AUDIO_CONSTRAINTS` to the audio track used during
the active meeting to reduce bandwidth usage.

* Originally proposed by trummerschlunk to reduce bandwidth, but
  previously restricted to the join screen preview.
* Backport the standard voice constraints (48 kHz sample rate,
  mono channel, 16-bit sample size) to the active call session, as
  requested by the BBBA team.
2026-08-25 22:33:42 +02:00
Florent Chehab cec2eb5a10 (summary) add hostname to analytics properties
This helps track down what was the source of events.
This can be usefull when checking perf of different workers for instance.
2026-08-25 14:48:06 +02:00
snyk-bot 2858d141f4 ⬆️(frontend) upgrade posthog-js from 1.404.1 to 1.409.5
Snyk has created this PR to upgrade posthog-js from 1.404.1 to 1.409.5.

See this package in npm:
posthog-js

See this project in Snyk:
https://app.eu.snyk.io/org/lasuite-dinum-default/project/96ea03d8-8d09-493d-86bf-363f274e129e?utm_source=github&utm_medium=referral&page=upgrade-pr
2026-08-24 16:15:15 +02:00
snyk-bot f10429581b ⬆️(frontend) upgrade @pandacss/preset-panda from 1.11.3 to 1.12.0
Snyk has created this PR to upgrade @pandacss/preset-panda from 1.11.3 to 1.12.0.

See this package in npm:
@pandacss/preset-panda

See this project in Snyk:
https://app.eu.snyk.io/org/lasuite-dinum-default/project/96ea03d8-8d09-493d-86bf-363f274e129e?utm_source=github&utm_medium=referral&page=upgrade-pr
2026-08-24 15:58:10 +02:00
snyk-bot b3369cddf7 ⬆️(frontend) upgrade @tanstack/react-query from 5.101.1 to 5.101.4
Snyk has created this PR to upgrade @tanstack/react-query from 5.101.1 to 5.101.4.

See this package in npm:
@tanstack/react-query

See this project in Snyk:
https://app.eu.snyk.io/org/lasuite-dinum-default/project/96ea03d8-8d09-493d-86bf-363f274e129e?utm_source=github&utm_medium=referral&page=upgrade-pr
2026-08-24 15:50:19 +02:00
snyk-bot cfffadc780 ⬆️(frontend) upgrade i18next-resources-to-backend from 1.2.1 to 1.2.3
Snyk has created this PR to upgrade i18next-resources-to-backend from 1.2.1 to 1.2.3.

See this package in npm:
i18next-resources-to-backend

See this project in Snyk:
https://app.eu.snyk.io/org/lasuite-dinum-default/project/96ea03d8-8d09-493d-86bf-363f274e129e?utm_source=github&utm_medium=referral&page=upgrade-pr
2026-08-24 15:41:16 +02:00