Refactor the plugin to support internationalization and ship it in
three languages.
Internationalizing requires updating the manifest, which involves
touching the Helm chart and releasing a new version. Ship a beta
version of the plugin once the i18n work is done to bundle these
changes together.
In the ribbon, the "create a meeting link" action was displayed with
the generic add icon, which is fitting in the context of a menu but
not explicit enough on its own.
Following feedback from the social ministries, replace the add icon
with the app logo to make it clear that this button creates a
videoconference link.
Instead of appending the meeting link at the end of the email, insert
it where the user's cursor is. This ensures the link is not placed
after the email signature, or below the quoted thread in a reply.
Refactor the message builder so that rendered messages are displayed
in a nicer way. Based on user feedback from the social ministries.
Go for a hybrid approach: on the desktop client, insert plain text so
it picks up the default font configured by the client theme; on the
web client, insert HTML, as the editor there is rendered using HTML.
The dialog window does not close itself on Outlook Desktop, which
opens links in a webview that behaves like a different browser.
Calling window.close() fails because, for security reasons, JS is
prevented from closing the window. The browser considers that the JS
script is not the one that opened the dialog.
The dialog also loses its reference to the opener due to the
redirection, so there is no way to message the parent to trigger a
close.
Keeping the dialog reference on the parent side does not help either:
since the opener is lost, the parent cannot call close on the dialog.
After investigation, go with a temporary solution that shows an
explicit message hinting the user to close the dialog manually if it
does not close automatically.
Restrict arm64 builds to release tags only, instead of running them on
every build.
The arm64 pipeline was significantly slowing down CI with little
practical usage, degrading developer experience for regular workflows.
Keep arm64 builds for release validation, and handle occasional failures
manually if needed.
The LiveKit integration was still using RoomInputOptions and
RoomOutputOptions, which emit deprecation warnings.
Update the implementation to use the unified RoomOptions API.
Pin urllib3 to >=2.7.0 via uv constraint-dependencies to fix a moderate
severity decompression DoS vulnerability. Affected versions (2.6.0 to
<2.7.0) could fully decode a compressed response body in a single
operation, leading to excessive CPU and memory consumption.
Pin idna to >=3.15 via uv constraint-dependencies to fix a moderate
severity (CVSS 5.3) information disclosure vulnerability. The flaw is
network-exploitable with no authentication required.
Pin idna to >=3.15 via uv constraint-dependencies to fix a moderate
severity (CVSS 5.3) information disclosure vulnerability. The flaw is
network-exploitable with no authentication required.
Uninstall `vite-tsconfig-paths` as path resolution is now supported
natively by Vite's built-in configuration.
Remove the unused dependency and simplify the frontend tooling setup.
The upgrade introduced around 50 new linting errors. Fix the
low-hanging fruit and address straightforward violations.
Several of the new rules appear to target patterns intended for newer
React compiler capabilities. Since the project currently runs on
React 18 rather than React 19, disable these rules for now instead of
applying potentially inappropriate changes.
Follow-up work can address the new rules in a dedicated PR, potentially
alongside a future React version upgrade.
Removes Node.js type dependency from browser/React code by substituting
the non-portable `NodeJS.Timeout` type with the standard
`ReturnType<typeof setTimeout>` equivalent across all affected files.
Also replaces `process.env.NODE_ENV` in Icon.tsx with
`import.meta.env.MODE` for Vite compatibility.
With the addition of the ANALYSING state
files could be accessed in the short time they
were in that state.
We now require files to be in ready.
Also adds missing frontend types (no impact).
Manually upgrade the frontend codebase to ESLint 9.
Update the linting configuration and related code where required to
maintain compatibility with the new major version.
When analysing a file, the previous commit introduced a row level lock
to make sure we would analyse and promote a single file.
This commit changes the locking mechanism so that it happens with
the upload state which avoids long running db locks and potential
perf issues.
Before this commit, post a file check, the policy could be
reused to change the verified file.
Now, files are uplaoded to a temporary location, then inside
a transaction that prevents concurrent calls, the file is
copied to its final destination and the checks are run on that one.
A new file can still be updated with the policy but it will never be read, etc.
As part of this change, all files in the new tmp directory
on s3 should have an expiration policy.
Introduce a Kubernetes job to run the `merge_duplicate_users`
management command on the backend, as suggested by @rouja.
This provides a standard and reproducible way to execute the user merge
process in deployed environments without requiring manual access to
application containers.
The job can be used alongside the command's dry-run mode to validate
the impact of a merge operation before applying changes.
Add an email substring filter to the user merge management command,
allowing selection of a subset of users concerned by the merge process.
This enables safer incremental execution of the command by testing it
on a controlled group of users before applying it globally.
The goal is to validate behavior and ensure the merge process does not
introduce unexpected side effects or inconsistencies at scale.
Add a management command to merge duplicate users and reassign all
granted resources to the most recent user account in the database.
Support a dry-run mode to estimate the impact of the operation before
applying any changes. This helps validate the command and identify
potential issues in environments where realistic testing is difficult.
Add unit tests to verify the command behavior and ensure database
integrity is preserved during the merge process.
Move user provisioning logic out of the external token viewset into a
dedicated service to keep the viewset lightweight and easier to
maintain.
While extracting the logic, refactor user object handling to improve
robustness and make the provisioning workflow easier to reason about.
Defend against race conditions when concurrent requests attempt to
provision the same user. Rely on the existing database constraints to
guarantee uniqueness and gracefully handle integrity errors raised by
concurrent creations.
Update the test to document the actual contract without modifying the
underlying model behavior.
These tests act as non-regression coverage and explicitly assert that
users may have a null sub or email. They are intended to document the
current behavior of the initial user model rather than evolve or
constrain it.
Ghost rows have not been reported as an operational issue. For the sake
of simplicity, avoid changing the model unless required by a concrete
issue or unless the benefits clearly outweigh the added complexity.
Fix a race condition in the external viewset where concurrent requests
could create multiple pending users with the same email address.
No database constraint enforced email uniqueness for pending users,
allowing duplicates to be created under load.
This caused issues during user reconciliation, which expects a single
matching pending user and raises a warning when multiple records are
found.
Add a narrowly scoped migration to enforce the uniqueness constraint
and address the identified issue.
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.
* 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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.