Commit Graph

1997 Commits

Author SHA1 Message Date
lebaudantoine 28f652e035 🔧(backend) backport logging configuration from docs
Backport the logging configuration from docs to LaSuite Meet after
discussion with @lunika.

Add a proper base logging setup to restore usable logs in production.
The initial repository bootstrap lacked a complete logging
configuration, resulting in limited operational visibility.
2026-06-02 14:27:58 +02:00
lebaudantoine a4997e7431 🔖(minor) bump release to 1.17.0 2026-05-31 18:18:00 +02:00
snyk-bot 13c7b9ad40 fix: upgrade core-js from 3.48.0 to 3.49.0
Snyk has created this PR to upgrade core-js from 3.48.0 to 3.49.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-05-31 00:16:26 +02:00
Florent Chehab ec688e728d (summary) extended support for all video/audio files
* Removed constraint on file extension
* Infer audio/video streams from the media with ffmpeg
* Infer the correct processed audio file extension based on actual
  codec to avoid ffmpeg errors

We need to support more extensions and make audio extraction dynamic,
as we shipped transcript in production and it led to user complaints
requesting more formats.
2026-05-31 00:01:49 +02:00
lebaudantoine bf69cbc14e ♻️(frontend) extract createMeetingMenu into a dedicated component
Avoid stacking too many components in route/home. Keep only the
responsibility of orchestration and layout in the home route, and
move stateful components to their appropriate folder.
2026-05-30 23:39:05 +02:00
lebaudantoine 6378c1e384 ️(frontend) use a more direct read for the username from localStorage
The homepage previously relied on the userChoices store, which loads
the persisted user choices from localStorage. However, this store is
widely used in the room feature, so code splitting ended up loading
the chunk containing the userChoices store at the initial render.
That chunk was bundled with unrelated parts that proved to be heavy.

Switch to a more straightforward approach reading the cached username
and verify the bundle output + intial loading.

Saves a few hundred ko on the initial load, now bundled in another
chunk that is loaded only when entering a room.
2026-05-30 23:39:05 +02:00
lebaudantoine 09b7a23f51 ️(frontend) switch Material icons strategy to per-icon SVG imports
Material icons (and Symbols, the most recent ones from Google
Material) were initially adopted to align with the UI kit. Before
that, we relied on Remixicon, which loads only the icons used and
totals 40ko for the whole library.

To benefit from Material icons, the implementation matched the UI
kit, which uses two fonts: 150ko and 750ko. Unlike the UI kit, the
fonts were preloaded to prevent icon render blinks. On products using
UI kit, the fonts are loaded the first time an icon renders,
and because they are heavy, the icon swap is visible to the user.
Icons are replaced by their text label in the meantime, which also
caused screen-reader vocalization or i18n issues that had to be mitigated.

Preloading the fonts was a quick win that worked fine on high-speed
connections where fonts get loaded fast then cached. However, while
optimizing LCP for users on poor connections (a separate concern that
already affects videoconference joining), preloading proved harmful:
it stole network bandwidth at the most critical moment,
when the main JS chunk was loading.

Switch to a frugal approach: import only the SVG icons actually
needed from Material, treated as components so they are tree-shaken
and customizable (color, etc.). Icons do not change often, so the DX
remains good. The UI kit also supports custom icons not available in
the font, so this approach lets us define them and works like a
charm.

Removal of Remixicon is planned in a follow-up PR.

It save user loading almost 1Mo of assets for few icons.
2026-05-30 23:39:05 +02:00
lebaudantoine c1d30f6923 ️(frontend) load PostHog dynamically
posthog-js was bundled in the main chunk. Loading it dynamically saves
200ko on the initial load and around 4s of loading time on slow 4G
connections.

PostHog, and analytics in general, should not block the initial
rendering. The risk is that some feature-flagged features may not be
instantaneously available to the user, but for most users on
high-speed connections this will be imperceptible.

Other places in the code rely on a direct import from posthog, I only
verified the delay import of posthog for the home page, and did
not for the /room route. I'm pretty sure there is room for
improvements on other parts of the app.
2026-05-30 23:39:05 +02:00
lebaudantoine 04ec967a99 ️(frontend) handle actions on userChoices store directly in the module
The Valtio actions on the store were initially defined inside a hook,
which was a bad idea: it does not follow Valtio's recommendation of
defining actions at the module level, and the function definitions
were re-created every time the hook re-rendered, which happened on
every state update.

These action has nothing related to React.

Additionally, the snapshot should be used more directly so Valtio can
understand and optimize which parts of the proxy are of interest to
the snapshot being made.
2026-05-30 23:39:05 +02:00
lebaudantoine 7390673bfc ️(frontend) backport phone number formatting to the backend
Use the Python port of Google's phone number library on the backend
instead of the JS one on the client. Saves 140Kb of unnecessary JS
and avoids a complex dynamic import that would have been required to
optimize loading.

The transformation is static: the phone number lives in the Django
settings, so the backend can format it once and pass the result to
the client. This avoids every client loading the 140Kb library and
re-computing the same information.

Moreover, within a single client, the transformation was previously
re-computed several times during a webapp lifecycle.
2026-05-30 23:39:05 +02:00
lebaudantoine 8984d863df ️(frontend) isolate the creation menu in a dedicated component
Avoid re-rendering the whole home page when interacting with the later
meeting creation flow.

Maintaining the modal open/close state at the parent level was causing
the whole home page to re-render on every menu open/close state
change.
2026-05-30 23:39:05 +02:00
lebaudantoine 995e6fa41d ️(frontend) code split livekit-client from the main chunk
livekit-client is a 400ko package that was wrongly bundled in the main
index.js chunk.

Every page was loading this enormeous vendor package only necessary
to join and participate to a room.

It made sense to set the LiveKit log level at app init, however the
performance tradeoff forces us to move it as close as possible to
where it is actually needed.
2026-05-30 23:39:05 +02:00
lebaudantoine 426e6258a8 ️(frontend) import LiveKit styles only in the room route
LiveKit styles are not needed across the whole app, only in the room
route. Import them locally there to avoid loading them globally.
2026-05-30 23:39:05 +02:00
lebaudantoine ac520d8b34 ️(frontend) isolate humanize-duration in its own chunk
The library is rarely used, so load it dynamically. It is only 50ko,
which might not have been worth the effort, but these 50ko were
bundled in the main chunk and are not needed on the homepage nor when
launching a room.

The static placeholder is good enough to be acceptable. On very slow
connections, the 50ko might take a second to load, after which the
text is updated with the right content.

Also improves renders across the components touched, especially the
idle modal with the countdown.
2026-05-30 23:39:05 +02:00
lebaudantoine 33ac849d3b ️(frontend) add component to render children only for Admin or User
Introduce a component that renders its children only if the logged-in
user is considered Admin or User. This helps avoid mounting the hooks
and logic of components that previously early-returned when the user
was not admin or owner, but were still re-rendering whenever their
internal logic updated.
2026-05-30 23:39:05 +02:00
lebaudantoine 07a1425fee ️(frontend) lazy load routes to shrink the initial JS chunk
One of the best ways to reduce the size of the initially loaded chunk
(index.js, around 2Mo before optimization) is to lazy load routes and
features so their JS gets isolated in dedicated chunks and is loaded
only when needed.

For example, most of the JS under the legal terms page is never
consulted by users. Likewise, when loading the home page, there is no
need for all the feature-related JS required to display a
videoconference.

After this lazy-loading optimization, the initial chunk is now around
1.2Mo, a significant improvement.
2026-05-30 23:39:05 +02:00
lebaudantoine 233bdce408 🩹(frontend) fix circular imports in Dialog and Form primitives
While attempting to lazy-load routes, Vite/Rollup warnings revealed
that the Dialog and Form primitives were causing circular imports
through their use of the barrel file.

Easy to address: when using primitive elements inside those
primitives, rely on direct imports instead of the barrel file.
2026-05-30 23:39:05 +02:00
lebaudantoine 1b35e3acd9 ️(frontend) remove auth barrel file to improve code splitting
Auth-related code is used across the codebase and imported by many
different features. The barrel file, while convenient for importing
utilities, was harming code splitting by pulling unrelated modules
into shared chunks.

Verified by running `npm run build:debug` before and after: chunking
and code splitting are better without the barrel.
2026-05-30 23:39:05 +02:00
lebaudantoine f8f2ce145b 🧑‍💻(frontend) add Rollup bundle visualizer for dev tooling
Install tooling to visualize the Rollup bundle output. It helps
understand precisely what composes our bundle and what is included in
each chunk, which is a great help when trying to enhance code
splitting.

You can see its output running npm run build:debug.

Note: the library is not compatible with Node 20, which is the build
image we use in Docker to build the frontend, so it will raise a
warning in CI. This does not matter much, as it is a dev-only
dependency used locally without Docker.
2026-05-30 23:39:05 +02:00
lebaudantoine bf6f7430e7 🎨(frontend) clarify type-only JS imports for better code splitting
Mark JS imports as type-only when applicable so they are stripped at
build time and ignored during chunk splitting, ensuring we take full
advantage of Rollup's code-splitting optimizations.
2026-05-30 23:39:05 +02:00
lebaudantoine 7c4f66f91e ️(frontend) avoid inlining ProConnect SVG assets and optimize SVG size
Following the ProConnect documentation leads to inlining almost 40ko of
SVG assets in the JS bundle. Moreover, each SVG asset (around 20ko) is
not optimized in size.

As the ProConnect button is loaded in the main index.js chunk at app
launch, these few Ko are critical.

Optimize index.js by 40ko and preload the hovered variant to avoid any
blink on hover.

Could be further optimized by handling the button background with CSS,
but leaving that as an improvement for later.
2026-05-30 23:39:05 +02:00
lebaudantoine 4d27f217fc ♻️(backend) prefix Swagger routes with /api
Inspired by commit eb23aef in suitenumerique/docs. The same base
route path is used everywhere, which helps when the backend sits
behind an ingress serving it with a regex like `api/*`.
2026-05-30 19:33:48 +02:00
Rahulchourasiya 88b722e741 🩹(backend) use path for redoc url matching 2026-05-30 19:33:48 +02:00
Rahulchourasiya 5ea5460b17 🩹(backend) fix swagger and redoc documentation urls
Use canonical documentation routes and add a regression test.
2026-05-30 19:33:48 +02:00
lebaudantoine 1eefc49f8d ♻️(devx) skip rebuilds for createsuperuser and migrate jobs by default
Ensure the meet-backend createsuperuser and migrate jobs run only
once and do not rebuild the image by default. When the backend
updates, resources should focus on updating the backend pod itself.
2026-05-30 17:59:44 +02:00
lebaudantoine 6cbb3520ee ♻️(devx) align mature features and reorganize backend env variables
Align enabled/disabled mature features across the dev environments.

Also reorganize backend env variables with a clearer scope and add
comments that help understand the responsibility of each setting and
why it exists.
2026-05-30 17:59:44 +02:00
lebaudantoine b2d6d33cc8 ♻️(devx) factorize backend env variables across dev stacks
Share the backend environment variables between the Dinum and
Keycloak dev stacks to avoid duplication and keep them in sync.
2026-05-30 17:59:44 +02:00
lebaudantoine cd19dea09e ♻️(devx) extract common components into a single YAML file
Maintaining the two dev stacks is a nightmare. Start factorizing them
to make sure they stay updated easily, and to highlight differences
between the two at a glance.
2026-05-30 17:59:44 +02:00
lebaudantoine 0ecc25bc74 📝(doc) update external API docs for room configuration support
Document the changes introduced in #128333, which allows passing
configuration to the external API when creating a room.

Warning: this documentation was generated in a rush using an LLM and
may contain minor errors.

Plan to factorize these YAML files into a common and shared
structure.
2026-05-30 16:11:48 +02:00
lebaudantoine 7f817e2c0a 🧑‍💻(devx) revert securityContext on dev Tilt stack
The securityContext and podSecurityContext were harming hot reloading
on the dev stack. The file permission system prevented source updates
because the user running the image was not root.
2026-05-30 14:55:55 +02:00
lebaudantoine fc17c410ae ♻️(tilt) update Tiltfile to track uv dependency files
The Tiltfile was not updated when switching to uv. Make sure
dependencies are refreshed when uv.lock or pyproject.toml change.
2026-05-30 14:55:55 +02:00
rahul f490b095d8 (backend) support config and access level in external API room creation
Allow passing configuration and access level when creating a room
through the external API.

Also add a few guardrails:
* control whether public rooms are accepted on the external API
* set the default access level when creating a new room

Ensure the new room configuration and access level are returned by
the serializer when listing rooms.
2026-05-29 20:15:59 +02:00
ilias 04dfb9922f (backend) add core.recording.event.parsers.S3Parser
Implementation was validated against Ceph Object Store by @agasurfer.
Event payload matches the one from AWS S3 docs.
2026-05-28 19:54:23 +02:00
Bastien Ogier 7d9f282c2e 🚀(paas) remove buildpack requirements.txt to use the new uv.lock
(paas) remove buildpack requirements.txt to use the new uv.lock
2026-05-26 23:28:00 +02:00
lebaudantoine ba8b3bda30 (frontend) add a connection state toast to the PiP window
Surface connection state changes (reconnecting, disconnected,
etc.) directly in the PiP window so the user stays informed
without needing to switch back to the main window.

Co-authored-by: Cyril <c.gromoff@gmail.com>
2026-05-22 17:24:17 +02:00
lebaudantoine ee85768940 ♻️(frontend) use a semantic CSS token for tooltip positioning
Replace the hard-coded tooltip offset with a semantic CSS token,
making it possible to override the spacing per context (e.g.
tighter spacing in the PiP window where vertical room is scarce).

Co-authored-by: Cyril <c.gromoff@gmail.com>
2026-05-22 17:24:17 +02:00
lebaudantoine a9ef134210 🩹(frontend) fix tooltip positioning in cross-document rendering (PiP)
react-aria computes overlay positions against the main window's
dimensions, which produces incorrect placement when the overlay
is rendered into a PiP document. Tooltips were the most visible
symptom, but the issue affects overlays in general.

Introduce a context that lets our primitives know when they're
rendering across documents. When set, the primitives use the
host document's window for positioning instead of falling back
to react-aria's default.

Original work by @ovgod. No cleaner approach seems feasible in
the short term, react-aria doesn't expose a clean way to
override the positioning target, so this works around it at our
primitive layer.

Co-authored-by: Cyril <c.gromoff@gmail.com>
2026-05-22 17:24:17 +02:00
lebaudantoine dee1e46173 (frontend) make the PiP control bar collapsible for responsiveness
The PiP window can be resized to a wide range of dimensions, so
the control bar needs to adapt. Introduce a collapsible mechanism
that hides or condenses controls as available width shrinks,
keeping the UX usable at small sizes.

Original works by @ovgdd

Co-authored-by: Cyril <c.gromoff@gmail.com>
2026-05-22 17:24:17 +02:00
lebaudantoine 60828ed895 🩹(frontend) set a proper page title on pip window
the wip placeholder was temporary, set a descriptive name.

Co-authored-by: Cyril <c.gromoff@gmail.com>
2026-05-22 17:24:17 +02:00
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
renovate[bot] 4911a7cda0 ⬆️(dependencies) update webpack-dev-server to v5.2.4 [SECURITY] 2026-05-22 17:07:13 +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