Functional but not mergeable—remote participants need to be informed
when recording starts, including the egress ID to prevent collisions.
Quick and dirty implementation.
Room recording status triggers only when the egress worker is active.
Querying the Egress API starts the worker, which joins the room as an invisible participant.
The room is marked as "recording" only once the worker has fully joined.
Not mergeable yet.
Sadly the room event gives no information about the Egress worker’s ID.
(roomId is wrongly named, and designates room’s slug)
Room’s slug are passed in filenames to simplify post-processing. Thus, from filename,
we can retrieve the room being recorded.
Current limitation: audio tracks are mixed, requiring diarization.
Future plans include full audio + video recording for a more complete meeting experience.
Added 'room_record' grant to LiveKit token to enable room recording.
Initial implementation allows any authenticated user to record,
but this needs refinement.
Only admins and persisted room members should have this capability,
as they are the ones notified post-recording. Not ready for merge.
Previously, I prevented clients from fetching new tokens when data is stale.
It seems totally wrong. Enabling data refresh addresses potential issues
with random user disconnections.
Please note the data refresh when stale was only disabled for people
who created the room.
While in focus, left tiles should be large enough to render
long name and still have a big enough size to get who is in the
tile. Temporary, but functional.
Due to responsiveness issues and awkward display on mobile screens.
Note: Chrome inspector's responsive mode inaccurately triggers mobile
behavior. It uses a temporary function imported from LiveKit.
Toast-related components are reusable. They follow React Aria recommendations.
The UI is heavily inspired by GMeet, we should iterate on it.
Why toast? It gives additional information and quick actions when an event
occurs in the room.
The ToastRegion design should be improved to be more extensible, to move away
from poor practices with conditional rendering.
Added initial toast display when users join, with room for further improvement.
Please read the fixme items.
Inspired by the props disableSpeakingIndicator, used the same
logic for all metadata displayed on hover on a participant's tile.
Why? I'll need to render the joining participant tile without any
metadata, so the participant see who is joining the room.
Absolutely needed some toasts to handle in app notifications,
or feedbacks. React Aria is working on it, and has released a
first beta. No component is available, only hooks.
Added user feedback for actions with explicit text indicating
URL will be copied to clipboard. Modeled after Jitsi's button
behavior for clarity and consistency in user experience.
Based on User's feedback.
Having the dialog position visually in the participant tile is
confusing for the user.
Position the dialog to be explicitly outside of a participant
tile container.
Users' feedbacks. Design is inspired from Whereby, a webinars
product. I am not a huge fan of having the indicator on the
left of the participant's name. It causes a shift of the name
when the participant unmute herself.
This should be discussed with the UX designer.
Users's feedbacks. Raised hands in participants' tiles were not
highlighted enough.
It was discussed adding a colorful border around the participant's
tile (idea inspired by Jitsi). Nonetheless, it conflicts with the
current blue border, indicating when a participant is speaking.
Until this blue border is present, it's not a great idea having a
second border indicating a new level of informations.
@sampacoud requested a yellow-ish/colorful indicator of when a
participant raised her hand, inspired by Jitsi. However, I think
yellow color should be reserved for warning or dangerous action.
I chose to use a white background around the participant's name,
to reinforce the visual indication a participant has her hand
raised, while still being discreet. It's inspired by Gmeet.
The Gmeet-inspired indicator was misleading for users,
at least those not used to GSuite products.
They didn't understand how to mute a participant.
Plus, having the button disabled for the local participant,
was creating confusion. To simplify the UX, have all
the buttons enabled is simpler to understand.
Empirical observations with a few number of users, should be
enhance and challenge in the long run.
'hash' built-in function is randomly seed by Python process.
In staging or production, our backend runs over 3 pods, thus 3
Python processes. For a given identity, it was not prompting
the same hash across all pods.
Why 'hash' is randomly seed? For security reasons, there was
a vulnerability disclosure exploiting key collision. Since Python 3.2,
'hash' is by default randomly seed.
Fixed it! Thx @jonathanperret for your help.
Height was varying when muting/unmuting the mic, so I added a minimum height to
avoid layout shift.
Proof of concept for the future UX: a raised hand would be placed on
the left side of the participant's name.
Having the mic indicator and raised hand side by side is temporary and totally
undesired (it feels super weird). I'll refactor the whole UX of the participant
tile in a dedicated PR.
Encapsulate code responsible for toggling hand,
and determining the hand state based on participant metadata.
This gonna be reused across the codebase.
Inspired from Gmeet. Add a button to lower all hands at once.
It should be quite useful for room moderator/admin.
The UX might feel strange, having this action button at the top of
the list, but I could not figure out a better layout. In terms of
UX I feel this is the best we can provide. However, the UI should
definitely be improved.
Show the raised hand waiting list, allow any participant to
lower other participants' hands.
Inspired from Gmeet. I found it quite clear to have a dedicated
waiting list for raised hands.
Will need it for lower hand action.
Actually, this piece of code should be enhanced. It'll act
as a corner stone of all actions dispatched in the interface.
I'll continue refactoring it later on.
Why? This layout is extensible. This menu will have two sections,
to separate in-room participants from the waiting room ones.
It's copied from Gmeet User Experience.
In-room participants will be divided in sub-lists based on their
states (ex: hand raised, …). This User Experience is extensible
if in the future with support subroom in a room or whatever.
Inspired by Magnify. Rely on participant metadata to determine,
if the local user has raised its hand.
There is a todo item in LiveKit code, useLocalParticipant is not
subscribed to metadata updates events.
The contrast of the toggled button in legacy Style is poor,
it needs to be urgently improved. User can barely distinguish if
their hands are raised.
These changes should be discussed. Needed for the audio selects,
that render super long text values.
By default, centered texts are sometime hard to read.
Removed annoying overlay that blocked the user. (feedback from @spaccoud)
Previous design required one click too many. As this dialog doesn't need
an overlay, I couldn't use the default primitive.
It's a hacky but functional, creating technical debt here.
Closer to the Gmeet design. Added a warning about permissions
since the rooms are public in beta.
Apologies @manuhabitela, this may impact accessibility for users unfamiliar
with the copy icon. Let's conduct user testing.
Messy code file organization, but functions are okay. Functional, but not
well-designed and likely hard to maintain. Shipping it, creating technical
debt here. Will be reused for interactions with LiveKit server API.
Participants need to be room admin to interact with LiveKit server
api. Until we offer private room, with moderation, all participants
will be considered as room admin.
note: room admin doesn't offer permission to record a room. please,
refer to LiveKit documentation to learn more.
This commit focuses on the UX more than the code quality. In facts,
we should design a centralized component/alert service, that we
can trigger anywhere in the codebase, when a user is prompted for
confirmation.
The alert modal with cancel/submit buttons and a description is generic.
Creating technical debt here.
Rapidly, a 'more option' button should be added to the row. Thus,
participants will have access to few more actions (ex: remove from
the room, pin camera, etc…).
This flex layout should be definitive, except the code which is dirty,
but not creating much technical debt here.
First raw iteration.
Tried replicating Gmeet UX and layout. However, in their ux, even if
action button are disabled, some tooltips explain to the user why they
cannot perform the action. With the default Trigger, it's not easily
feasible. As soon as the button is disabled, there is no way to trigger
the tooltip in an uncontrolled manner.
In upcoming commits I'll arrange layout, and call the remote LiveKit
ServerApi, to perform the mute action.
Main update: create a component, which has the responsability of
rendering a Participant in the list. I tried gettig closer to a
cleaner codebase, with small and well-scoped components. WIP.
Formatting participants before rendering the list was way to over
complicated, iterating twice on the list was kinda useless. Fixed!
Few updates:
- Removed capitalizing Participant's name to be consistent with the
avatar. This choices mimics GMeet UX.
- Duplicated isLocal utils function from LiveKit, which is not
exported by their package.
Avatar font size was way too small in the participant list context.
I tried improve it. Few font sizing are visually uncomfortable in
the participant list.
oupsy, heavily copied from Gmeet.
Thx Nathan Vasse for his css animation skills, he crushed it.
This component will be core in the app, and reused in many places.
It was necessary for the participants list.
Upgrading Django to 5.1 created a severe issue.
Migrate and create-superuser jobs were failing.
The issue originated from the third party easy_thumbnail.
Please refer to the issue #641 on their repo.
This is the suggested workaround by @Miketsukami.
It explains why participant initials doesn't update when a participant
changes its name.
Similar issue as the one faced while developing on the participant list.
It needs to be fixed at the root, in the LiveKit repo.
Duplicated source from LiveKit internal hooks (not ideal, but necessary)
to ensure the inner content of the participant placeholder consistently
fits its parent container. Unfortunately, I couldn't find
a simpler solution.
This might lead to some performances issues, as for each tile, some js
would be computing avatar's size, which is much more costly than pure
css…
Note: Gmeet achieves this by generating a temporary placeholder image
with a colored background and initials, allowing for a perfectly round,
responsive avatar without relying on JavaScript.
Default 'transparent' value avoid showing the avatar when
participant's info are not yet available. Might be a bad design
if we follow the single responsability pattern. Please feel free
to refactor it.
Color is stored in participant's metadata.
Using a hash of some participant's info allow to persist the color
for logged-in participant without storing the color in db.
Please feel free to tune the saturation and lightness range.
Code is inspired by a tutorial found online.
Inspired by Gmeet animation (mine is far from perfect).
Some details should be improved, especially to have a smooth
animation stop when the user stops speaking.
Duplicated LiveKit sources to customize the participant tile. It’s needed
to enhance the design and color of the participant placeholder.
More in the next commits.
Inspired by the Google Meet user experience.
A simple UX for scheduling meetings was requested by some users.
This is a quick and basic poc to validate the UX in a production
environment. If it gains traction, it will be refined and consolidated.
Inspired by GMeet user experience. Offer a sound tester button
to our users while configuring their audio output.
uprise.mp3 has a free license. We should credit them in our legal
terms asap.
First draft, it lacks important features, as a visual indicator when
the mic is active, and a trigger to test the audio output.
I made some heuristics (e.g. default output/input, etc..) to ship a
first version of this setting tabs that should work good enough to
create value for our current users.
Please refer to the inline comments.
Introduced a General settings tab, currently allowing language configuration.
Although this commit introduces some duplication, the default settings dialog
will be refactored in future updates.
The General tab is designed to accommodate additional features over time.
User can now update their name in a dedicated Account tab,
inspired by Jitsi design. Removed the username dialog.
Account-related updates will be operated through the advanced
settings dialog, in this dedicated tab.
Inspired by other videoconferencing tools' designs.
Sizes are mixing pixels and rem, it should be harmonized.
Will be used by the advanced settings panels.
Refactored it in a proper component. Initially planned to
use it in the Account Tab, but I changed my mind.
This refactoring is an enhancement, the Avatar props are better
encapsulated.
This component should be the definitive layout for settings.
Why extended? I kept the original one, which is still in-use in the
homepage, and considered this settings dialos as an extended version,
or advanced one.
I hope in a close future, we merge these two dialogs to avoid
maintaining too much code. Not the top prio.
Relevant TabPanel components will be introduced in the upcomming commits.
Even if the list is empty, previous assertion was returning true.
Fixed it, mybad, noob error.
In fact, the participants list should never be empty, as you are
in the meeting to access it.
The 'Box' component has a type 'dialog' which limits the Dialog size.
The default size is insufficient for larger dialogs like
the advanced settings.
To address this temporarily, I'm allowing the wrapper component to set the
Dialog size directly. This isn't ideal, but will enable better flexibility
until we finalize the user experience and dialog requirements.
I am not sure of the new props' naming introduced.
Added a new variant for Tabs and TabList components
to support borderless styles.
By default, both Tabs and TabList include borders.
Using React context, TabList’s children will automatically
inherit a borderless style if specified via props.
However, you can still explicitly apply borders
to individual children, even if the parent
TabList is set to be borderless.
Style react aria components and exposed them.
Tabs are needed for the advanced settings component.
Both orientations, horizontal and vertical, are supported.
Introduce an option to render or omit the title in the Dialog component.
This is necessary for the advanced settings Dialog, which displays its
title in the Tab menu.
This could affect existing component API created by @manuhabitela.
The component will become less opinionated, offering more flexibility
in its usage (I am not 100% convinced it's actually a great idea).
Quick fix! Let's enhance it
Text.tsx export not only a component, but also few types.
This triggers an eslint warning. I don't want refactoring it
without discussing it with @manuhabitela. Silence it.
@manuhabitela introduced Menu and MenuTrigger components. Refactor the
options menu to benefits from his components.
Few details are not perfect yet. wip
it seems panda-css didn't like my way of sharing css code. When sharing
bare objects matching panda-css interface, panda-css didn't understand
those were styles and didn't parse them. Now using actual recipes via
the `cva` helper, panda understands correctly those styles need to be
updated on change.
ps: cleaned a few panda imports that didn't use our "@" alias
this will be used for toggled on/off mic and camera buttons. We want
toggled-on buttons that don't look pressed as it looks a bit weird
(we'll change icons on pressed/unpressed state). And we want red buttons
for when the buttons are not pressed, so adding the "danger" variant
too.
the whole colorpalette stuff needs a bit of work to be clean but it'll
do for now
Refactor the existing Button component to extract a new ToggleButton
component that wraps react aria ToggleButton. This will
be used to toggle cam/mic on/off, or any other controls in the control
bar.
ditch the "PopoverList" component that was basically a poor Menu. Now
dropdown buttons can be made with react aria Menu+MenuItems components
via the Menu+MenuList components.
The difference now is dropdown menus behave better with keyboard (they
use up/down arrows instead of tabs), like selects.
Popovers are there if we need to show any content in a big tooltip, not
for actionable list items.
The current design is inefficient, using two separate approaches to manage
the app state and determine which widget is open. This inconsistency affects
the user experience and overall design quality.
Soon, only one container will be open/close, and its content will be toggle,
using an extensible system.
As a quick fix, I’ve added basic logic to ensure that opening one widget
automatically closes any other open widgets, such as the chat or participants
widget. This is a temporary measure to fix state management until a
more robust solution can be implemented.
This commit refactor the default chat toggle to enhance few details:
- styling (e.g. button's size, icon's style, etc)
- accessibility (e.g. tooltip, aria label, keyboard controls)
- notifications (enhanced contrast on the red dot, feedback from Arnaud)
I faced few challenge while using LiveKit hook, please refer to my commits.
I'll work on a PR on their repo to get it fixed. Duplicating their sources
add overhead.
This commit introduce the most minimal participants list possible. More
controls or information will be added in the upcomming commits.
Responsiveness and accessibility should be functional.
Soon, any right side panel will share the same container to avoid visual
glichts.
Introduced a button to manage the visibility of the participants list.
Encountered refresh issues with the room context where the participant count
in the room metadata does not update in real-time, causing discrepancies
between the actual number of participants and the displayed count. To address
this, I utilized the participants hook, which updates more frequently and
ensures consistency.
Encountered issues extending the current button due to the complexity of the
Button and Link props construction. I’ll need to redesign the component to
enhance its extensibility.
The legacy style adheres to the previous interface but suffers from poor
color contrast. Hex codes were used to match the selected toggle color,
resulting in a difficult color system to maintain. This approach needs refactoring
for better color handling. Legacy styles will soon disappear.
Efforts were made to minimize code for handling the toggle functionality.
Future work should focus on refactoring the button to align with the field
approach for improved developer experience and props validation.
In LiveKit, opening the chat causes the entire page layout, including
participant tiles and controls, to shift left. This disrupts the user
experience, as the chat toggle button moves, requiring users to reposition
their cursor to close the chat.
This behavior also prevents effective organization of the control bar,
especially when trying to maintain a centered section for main controls and
a fixed section for quick-access buttons on the left or right bottom corners.
This fix temporarily locks the controls and participant list in place when
the chat is toggled. The styles will be refactored during the upcoming
redesign.
Updated Django's ALLOWED_HOSTS setting from '*' to the specific host of the
server. Setting ALLOWED_HOSTS to '*' is a security risk as it allows any host
to access the application, potentially exposing it to malicious attacks.
Restricting ALLOWED_HOSTS to the server's host ensures only legitimate
requests are processed.
In a Kubernetes environment, we also needed to whitelist the pod's IP address
to allow health checks to pass. This ensures that Kubernetes liveness and
readiness probes can access the application to verify its health.
Few scripts were duplicated between the scripts and the bin folders.
Reorganize the scripts in a common folder, and align filenames to
follow the same rule.
Updated the liveness and readiness probes interval from every 10 seconds to
every 30 seconds. This change reduces the load on the server by decreasing
the frequency of health checks.
Given the current stability of the application, a 30-second interval is
sufficient to ensure that the application remains responsive and healthy.
Silenced certain Django security warnings because the application is served
behind a reverse proxy. These warnings are not applicable in our deployment
context, where the reverse proxy handles these security concerns.
This change ensures relevant security measures are appropriately managed
while avoiding unnecessary warnings. Any question? asked @rouja.
/!\ actually, this commit is not working, and should be fixed.
Some outdated references to Terraform and OpenStack were missed during
the project quickstart. These are legacy elements inherited from OpenFun.
This commit cleans up the codebase.
LiveKit access tokens are valid for 6 hours after generation. Without a
`staleTime` set, room data becomes stale immediately (0 milliseconds),
causing unnecessary refetches, particularly when users switch focus back
to the call window.
This issue led to an excessive number of "get room" events, as observed
in the analytics. For example, during a meeting, if a user switches tabs
and then returns, the room data would be refetched despite the access
token still being valid.
By adding a `staleTime` aligned with the token's validity, we avoid
unnecessary network requests.
(aligned with Google Meet or Jitsi ux)
This ensures participants join a room with a fresh access token.
Some participants information might be altered after the access token
was generated (e.g. their name).
I wanted the initial data to be passed only once, when you navigate
to the room from the create button, but if you reload the page, then
a new access token will be fetched, and the pre-join screen displayed.
Utilized local storage to persist the updated name. After careful
consideration, persisting all user choices in the backend was deemed overly
complex and unnecessary for the value it would provide.
Opted for a single responsibility approach by leveraging local storage to manage
user choices, aligning with LiveKit's default implementation.
Switched to using query parameters instead of GET requests, enabling the
inclusion of additional parameters when calling the create endpoint via POST.
Simplified the access token generation process by removing redundant calls to
`with_identity` and consolidating token generation steps. This streamlines the
method flow by preparing all necessary data before generating the access token.
The user name is initially set by the backend when generating the LiveKit access
token. By default, if the frontend has not provided a username, the backend uses
the user's email address. This approach isn't ideal, as some users prefer using
their first name.
This update allows local participant to change their username in real-time
during a session. However, these changes are not yet persisted for
future meetings. This persistence feature will be added in upcoming commits.
Reintroduced user information in the settings dialog. This change allows
users to see the account they are logged into, which is important for
account management. An additional feature to update usernames will be
added soon. Apologies to @manuhabitela for the oversight.
Removed the header when inside a room to maximize space for the camera
gallery. Settings are now accessible via the options menu.
It aligns the design with common video conference tools as meet,
or jitsi. @manuhabitela was aligned with this change.
I am not hundred percent sure it respects @manuhabitela's guidelines,
but for the options menu, I would need to trigger a dialog in a controlled way.
I tried to have the minimal impact on the existing settings dialog.
Replaced the existing settings button with a new `OptionsButton` component.
This new component integrates a menu for more actions, providing an
extensible and accessible interface.
Refactoring will follow to enhance code maintainability.
A legacy style was introduced to keep visual coherence with the other controls
from the controls bar. It's temporary, until we redesign the whole bar.
It doesn't match pixel-perfect the legacy styles.
A new public Tchap chan was created. All users, and not only beta users,
can now join it using the link in the menu, and reach us.
Localized video conference controls to match the selected language.
Previously, controls were always in English, causing confusion for French users.
A full refactor of the controls is planned soon.
Same approach as the previous commit. Few elements were not exposed
by the LiveKit package, and I had to duplicate them. Let's see if
we can asap get rid off all this complexity.
Basically, duplicate LiveKit code to start iterating on their
components, not sure wether it's the optimal strategy, but at least
we will be more agile, shipping small features which are lacking.
Added CI job to run linting and formatting checks in the frontend
codebase. Please note, we should cache frontend dependencies,
to avoid re-installing them. Future improvement!
Ran Prettier on the entire codebase to fix formatting issues. My IDE was
previously misconfigured, causing most of these errors. The IDE configuration
has been corrected.
Following @manuhabitela's recommendation, we've decided to switch
from Yarn to npm for managing our Node.js dependencies. This update
aligns all remaining parts of the codebase that were still using
Yarn to now utilize npm.
I added an example in the documentation to ensure we remember to upgrade the
frontend image during the release process. This will help prevent any issues
related to outdated images when deploying new versions.
(I did this mistake while releasing)
Enhanced the error screen to support customizable titles and descriptions.
Allows for more detailed and informative error messages for users.
By default, the error screen displays a standard heading. You can
now pass custom title and body content to provide additional context
and clarity.
Attempt to create a room using a mutation if the fetch query fails.
If the mutation succeeds, update the fetch query data to ensure
it is up-to-date.
I tried to reproduce kind of a ‘get or create’ mechanism.
Due to the removal of the 'onError' prop in React Query, it is recommended
to use useEffect for handling such event propagation.
Regarding status handling, the fetch status takes priority over the mutation.
The mutation should only be called if the fetch has failed.
I'll need this key to sync data when the mutation responds successfully.
This is a preliminary refactoring; the mutation will be added
in upcoming commits.
Enabling logs by default in clients during production feels insecure.
Therefore, I have silenced all LiveKit logs.
This might pose a challenge if we need to debug a user in the future,
but currently, we don’t require these logs.
Additionally, my utils file and function work as intended,
though there is room for improvement.
With unregistered rooms being now forbidden, we need to call create a room
in our Django db to get an access token.
Clicking on the 'Create room' will create a new entry using a Post request.
The output serialized already contains an access token to the LiveKit server,
thus we won't need to run the useQuery hook when navigating to the room.
/!\ this modification now prevent authenticated users to create rooms
by simply navigating to it. It'll be fixed in the upcoming commits.
Require users to create a room in the database
before requesting a LiveKit token.
If user request an access token for a room that doesn't
exist in our db, its request would end in a 404 error.
Ensure that rooms must be registered by a user before they can be accessed.
By default, all created rooms remain public, allowing anonymous users to join
any room created by a logged-in user.
However, anonymous users cannot create rooms themselves.
I have set up distinct namespaces for each environment. You can now push
events to the development namespace without affecting production data.
Please note that these keys are not 'secret'. They will also be configured
in the browser SDK, which is inherently insecure. The documentation does not
specify a secure storage method for these keys.
In this commit, we'll integrate a third-party service to track user events.
We start by using the `identify` method to track sign-ins and sign-ups.
Additionally, we use the `track` method to monitor custom events such as room
creation, access token generation, and logouts. This will provide us with
valuable data on current usage patterns.
The analytics library operates by opening a queue in a separate thread for
posting events, ensuring it remains non-blocking for the API. Let's test
this in a real-world scenario.
Add a new property 'email_anonymized' to the User model,
to allow tracking a user's email without any personal data.
In fact, we're dealing with professional data, thus it shouldn't
be subject to the GDPR, however I prefer taking extra care
when working with potentially first and last names.
I've chosen June, a closed project, for our product analysis. Please note that
this is temporary until we find our product-market fit and achieve
significant traction.
I selected June for several reasons, particularly their focus on pre-product-
market fit (PMF) analysis, which is crucial for us. Their approach will help us
track user engagement and identify the most important features.
Remember, the purpose of this data is not to provide definitive answers about
our product, but to prompt us to ask the right questions and engage with users
to find the answers.
Close issue #91. Each <li> element in a list should have a unique key
to avoid React warnings.
Added unique keys to 'popover' items. Although the 'lang' keys are generated
by i18n dependencies and are expected to be unique, this implementation
ensures keys are unique and not based on indexes.
Removing the __init__.py makes it impossible for Pylint to get the sources
to lint from the root folder. We manually set all the paths pylint will lint.
That's not a big deal, as we'll remove Pylint any soon to rely only on ruff.
I took inspiration from marsha or magnify project.
I removed the now useless bash script to run Pylint command. It saves us
wrapper! Plus, having a lint command running with different option locally
and in the CI was quite a pain.
Locally linter was running on diff files; Fixed! CI and make command has now
the same behavior.
Recent updates in dependencies broke the tests.
I am in a rush, I found a stack overflow discussion mentionning we should
NOT consider the root folder of a Django project as a Python package.
My issue was:
Model class app.core.models.User doesn't declare an explicit app_label
and isn't in an application in INSTALLED_APPS.
Removing the __ini__.py file at the root folder fixed the regression.
Recent updates of dev/ruff and dev/pylint dependencies led
to new linting warnings.
Pylint 3.2.0 introduced a new check `possibly-used-before-assignment`,
which ensures variables are defined regardless of conditional statements.
Some if/else branches were missing defaults. These have been fixed.
Previously each route rendered its whole layout from a to z.
Now each route updates a single common wrapper when the layout changes
between pages.
Also the Loading, Error, UserFetched, QueryAware code is more explicit
and understandable.
This introduces valtio as dependency, allowing us to deal with global
state easily in a svelte/vue way (reactive mutable state). This limits
the boilerplaty-ness of immutable state lib approaches, while keeping
rendering optimization better than homemade react contexts.
we query user at load and keep info for a while, way less than user
session anyway. will need to check if we could get de-sync (like loading
the frontend with backend user session ending in 30 minutes while we
don't check user state until an hour)
at the cost of a not-changeable username, logged in users who create
rooms now skip the join page. I think it's good to have this to test
this way, even if the username choice is not there yet.
it was a bit cumbersome to navigate by paths accross the app as if one
path changes a tiny bit we have to make sure we updated everything
everywhere and it's kind of error-prone and cumbersome to build paths by
hand.
now we have a routes file that describes everything: what is the path to
each route, and how to navigate to them.
We use a new navigateTo helper that helps us. It could be better typed
but i'm a newbie.
the issue was we return the fetchUser promise to react query too early
(before the browser reloaded the page). now we make sure react query
doesn't get the info
This commit is totally work in progress.
@manuhabitela the floor is yours.
If the user is logged-out, try silently log-in her every hour,
to avoid any manual login on her side.
The one hour value has been discussed with @manuhabitela, but there
is no real logic behind it. Could definitely be shorter or longer.
It needs at least to be longer than the average silent login flow
to avoid locking the user-agent in an infinite redirection loop.
Enhanced the authentication URL generation to support 'silent'
and 'returnTo' query parameters.
This allows initiating a silent login and specifying a custom
return URL after auth.
Silent login attempts to re-authenticate the user without interaction,
provided they have an active session, improving UX by reducing manual auth.
It's an essential feature to really feel the SSO in La Suite.
A new query parameter, 'silent', allows the client to initiate a silent login.
In this flow, an extra parameter, 'prompt=none', is passed to the OIDC provider.
The requested flow is persisted in session data to adapt the authentication
callback behavior.
In a silent login flow, an authentication failure should not be considered as a
real failure. Instead, users should be redirected back to the originating view.
A silent login fails when user has no active session.
Why return the 'success_url'? The 'success_url' will redirect the user agent to
the 'returnTo' parameter provided when requesting authentication.
It's necessary to enable a silent login on any URL.
Minimal test coverage has been added for these two custom views to ensure
correct behavior.
mozilla-django-oidc now supports a 'returnTo' parameter for redirecting
to a specificURL upon successful login. if not provided,
it defaults to the settings-defined URL.
This allows initiating the login flow from any views,
enhancing UX by returning users to their previous page.
The 'returnTo' naming can be discussed.
Based on @rouja instructions, try to document the Tilt stack,
to enhance the DX of any newcomers, discovering Meet and trying
to run it on K8s.
Having a shared/common onboarding documentation on Tilt with
Impress, Regie, and Meet would be amazing.
Especially, to document how to install Tilt and its dependencies.
Important: The frontend is not deployed locally using the production
target, and I feel important to document it.
Closes#50.
Adopted LiveKit demo app approach for passing
configurations to LiveKitRoom.
Introduced roomOptions for future customizations (e.g.,
video quality, e2e, codec).
DeviceId is persisted in local storage despite boolean flag.
checkout@v2 uses node12 which will be deprecated soon.
I've aligned CI configurations to use a more recent action,
already in-use in the 'meet.yml' flow.
now clicking on the header homepage link asks for confirmation when on
the route page.
this is quick and dirty, using browser confirm ui, and not making a
difference between join page and conference page, but it'll do for now
- show the header on homepage. Not sure we want any header on this app
actually but I guess he's right since we have one it feels more
consistent to have it everywhere
- show logged in email in header. ditched it because i didn't quite get
the value of showing it all the time in this app but i guess it's better
than nothing
- remove user info from settings. Since they are back in the header, no
need
- use the default react-aria DialogTrigger when we want to build buttons
triggering dialogs
- use custom Dialog component as a wrapper to Dialog content
this better permits us to have a Dialog content component somewhere else
than its trigger button. Mainly did this so that the dialog title is
localized with its content.
they are not really helpful, i'd rather stick to the react-aria wording,
easier to understand when looking at react aria examples, converting
code, etc. Not a great value adding this api in our tiny heads
- improve the Form component to abstract the few things we'll certainly
do all the time (data parsing, action buttons rendering)
- add a Field component, the main way to render form fields. It mainly
wraps react aria components with our styling. The Checkbox component is
a bit tricky to go around some current limitations with react aria
this triggered on a few things we didn't want (labels particularly).
plus, handle the focus ring color via panda, so that it's available in
the JS (will be useful in soon to be commited stuff)
until now, we concluded that is `isLoggedIn` !== true meant the user
wasn't logged in. While it also meant that we are currently loading user
info.
wrap the whole in something that doesn't render anything until we made
the first user request to prevent this behavior.
The Pylint job was failing due to those TODO items. In our make lint
command sequence, Pylint runs first. If it fails, Ruff won't run,
which is quite inconvenient.
I've extracted those TODOs into an issue for further review.
Quick and dirty approach. It works, that's essential.
Frontend can pass a desired username for the user. This would
be the name displayed in the room to other participants.
Usernames don't need to be unique, but user identities do
If no username is passed, API will fall back to a default username.
Why? This serves as a security mechanism. If the API is called
incorrectly by a client, it maintains the previous behavior.
when adding keys by hand, we didn't really know where to add them so
that the i18n:extract command would not move them afterwards. Feels like
this will help.
I guess a CI thing checking if the locales file dont change after a push
would be helpful
- this feels a bit less boilerplaty to read
- puting the characters whitelist outside the function to prevent
creating the var each time (yes, this of super great importance)
Enhanced security by ensuring users are redirected to a 404 error page
if they
pass an incorrect roomId path, either intentionally or unintentionally.
This is
a critical security mechanism that should be included in our MVP.
Let's discuss extracting hardcoded elements, such as lengths or
the separator, into proper constants to improve code maintainability.
I was concerned that this might make the code harder to read, it could
enhance
clarity and reusability in the long term.
I prefer exposing the roomIdRegex from the same location where we
generate IDs.
However, this increases the responsibility of that file. Lmk if you have
any
suggestion for a better organization.
Additionally, the current 404 error page displays a 'Page not found'
message for
invalid room IDs. Should we update this message to 'Invalid room name'
to
provide more context to the user?
UUID-v4 room IDs are long and uninviting. Shorter, custom room IDs
can enhance UX by making URLs easier to share and remember.
While UUID-v4s are typically used in database systems for their low
collision probability, for ephemeral room IDs, the collision risk of e+14
combinations is acceptable.
This aligns room IDs with Google Meet format.
Even if the 'slugify' function is not used anymore, I kept it.
Lmk if you prefer removing it @manuhabitela
this will be better in an options page later i think, as we don't pass
our life changing language and we already have a language detector at
load.
this adds a PopoverList primitive to easily create buttons triggering
popovers containing list of actionable items.
- upload local translation files on push
- make crowdin create a pull request when new translations are made
through the crowdin website (webhook configured on crowdin-end)
- dynamically load locale files for smaller footprint
- have a namespace for each feature. At first I'd figured I'd put each
namespace in its correct feature folder but it's kinda cumbersome to
manage if we want to link that to i18n management services like crowdin…
Updated CI to use "npm" instead of yarn for the frontend project based
on @manuhabitela's recommendations. Also updated the dependencies-related CI
steps that were previously missed.
Heavily inspired from openfun handbook instructions,
https://handbook.openfun.fr/git
Document how release a new version. Might be a common
documentation shared with Impress, Regie and Meet projects.
Let's discuss it.
It's quite important that anyone should know how to release,
as we plan to release every week an enhanced version.
@@ -94,6 +94,56 @@ You first need to create a superuser account:
$ make superuser
```
### Run application on local Kubernetes
The application is deployed across staging, preprod, and production environments using Kubernetes (K8s).
Reproducing environment conditions locally is crucial for developing new features or debugging issues.
This is facilitated by [Tilt](https://tilt.dev/) ("Kubernetes for Prod, Tilt for Dev"). Tilt enables smart rebuilds and live updates for services running locally in Kubernetes. We defined our services in a Tiltfile located at `bin/Tiltfile`.
#### Getting Started
Make sure you have installed:
- kubectl
- helm
- helmfile
- tilt
To build and start the Kubernetes cluster using Kind:
```shell
$ make build-k8s-cluster
```
Once the Kubernetes cluster is ready, start the application stack locally:
```shell
$ make start-tilt
```
These commands set up and run your application environment using Tilt for local Kubernetes development.
You can monitor Tilt's at `http://localhost:10350/`. After Tilt actions finish, you can access the app at `https://meet.127.0.0.1.nip.io/`.
#### Debugging frontend
Tilt deploys the `meet-dev` for the frontend by default, to benefit from Vite.js hot reloading while developing.
To troubleshoot production issues, please modify the Tiltfile, switch frontend's target to `frontend-production`:
Whenever we are cooking a new release (e.g. `4.18.1`) we should follow a standard procedure described below:
1. Create a new branch named: `release/4.18.1`.
2. Bump the release number for backend project, frontend projects, and Helm files:
- for backend, update the version number by hand in `pyproject.toml`,
- for each frontend projects (`src/frontend`, `src/mail`), run `npm version 4.18.1` in their directory. This will update both their `package.json` and `package-lock.json` for you,
- for Helm, update Docker image tag in files located at `src/helm/env.d` for both `preprod` and `production` environments:
```yaml
image:
repository: lasuite/meet-backend
pullPolicy: Always
tag: "v4.18.1" # Replace with your new version number, without forgetting the "v" prefix
...
frontend:
image:
repository: lasuite/meet-frontend
pullPolicy: Always
tag: "v4.18.1" # Replace with your new version number, without forgetting the "v" prefix
```
The new images don't exist _yet_: they will be created automatically later in the process.
3. ~~Update the project's `Changelog` following the [keepachangelog](https://keepachangelog.com/en/0.3.0/) recommendations~~ _we don't keep a changelog yet for now as the project is still in its infancy. Soon™!_
4. Commit your changes with the following format: the 🔖 release emoji, the type of release (patch/minor/patch) and the release version:
```text
🔖(minor) bump release to 4.18.0
```
5. Open a pull request, wait for an approval from your peers and merge it.
6. Checkout and pull changes from the `main` branch to ensure you have the latest updates.
7. Tag and push your commit:
```bash
git tag v4.18.1 && git push origin --tags
```
Doing this triggers the CI and tells it to build the new Docker image versions that you targeted earlier in the Helm files.
8. Ensure the new [backend](https://hub.docker.com/r/lasuite/meet-frontend/tags) and [frontend](https://hub.docker.com/r/lasuite/meet-frontend/tags) image tags are on Docker Hub.
9. The release is now done!
# Deploying
> [!TIP]
> The `staging` platform is deployed automatically with every update of the `main` branch.
Making a new release doesn't publish it automatically in production.
Deployment is done by ArgoCD. ArgoCD checks for the `production` tag and automatically deploys the production platform with the targeted commit.
To publish, we mark the commit we want with the `production` tag. ArgoCD is then notified that the tag has changed. It then deploys the Docker image tags specified in the Helm files of the targeted commit.
field=models.JSONField(blank=True,default=dict,help_text='Values for Visio parameters to configure the room.',verbose_name='Visio room configuration'),
field=models.CharField(choices="(('en-us', 'English'), ('fr-fr', 'French'))",default='en-us',help_text='The language in which the user wants to see the interface.',max_length=10,verbose_name='language'),
Some files were not shown because too many files have changed in this diff
Show More
Reference in New Issue
Block a user
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.