♻️(backend) pass the participant role in the LiveKit token

The backend previously passed an abstract is_admin_or_owner boolean
flag in the LiveKit token. That kept the frontend minimalistic and
saved it from having to handle role comparisons.

As we introduce more features that need to distinguish between the
room owner and admins, refactor the token to carry the role
directly. The frontend can then derive the relevant flags from a
richer piece of information.
This commit is contained in:
lebaudantoine
2026-07-07 19:21:12 +02:00
committed by aleb_the_flash
parent f043ad6f98
commit 5a641a4366
13 changed files with 143 additions and 67 deletions
@@ -5,7 +5,7 @@ import { Text } from '@/primitives/Text'
import { useTranslation } from 'react-i18next'
import { Avatar } from '@/components/Avatar'
import { getParticipantColor } from '@/features/rooms/utils/getParticipantColor'
import { getParticipantIsRoomAdmin } from '@/features/rooms/utils/getParticipantIsRoomAdmin'
import { getParticipantIsRoomOwner } from '@/features/rooms/utils/getParticipantIsRoomAdminOrOwner'
import { type LocalParticipant, type Participant, Track } from 'livekit-client'
import { isLocal } from '@/utils/livekit'
import {
@@ -146,7 +146,7 @@ export const ParticipantRow = ({ participant }: ParticipantListItemProps) => {
</span>
)}
</Text>
{getParticipantIsRoomAdmin(participant) && (
{getParticipantIsRoomOwner(participant) && (
<Text variant="xsNote">{t('participants.host')}</Text>
)}
</VStack>
@@ -28,3 +28,5 @@ export type ApiRoom = {
livekit?: ApiLiveKit
configuration?: RoomConfiguration
}
export type ParticipantRole = 'member' | 'administrator' | 'owner'
@@ -8,7 +8,7 @@ import { useRemoteParticipants } from '@livekit/components-react'
import { useUpdateParticipantsPermissions } from '@/features/rooms/api/updateParticipantsPermissions'
import { useRoomData } from '@/features/rooms/livekit/hooks/useRoomData'
import { isSubsetOf } from '@/features/rooms/utils/isSubsetOf'
import { getParticipantIsRoomAdmin } from '@/features/rooms/utils/getParticipantIsRoomAdmin'
import { getParticipantIsRoomAdminOrOwner } from '@/features/rooms/utils/getParticipantIsRoomAdminOrOwner'
import Source = Track.Source
import {
NotificationType,
@@ -48,7 +48,7 @@ export const usePublishSourcesManager = () => {
})
const unprivilegedRemoteParticipants = remoteParticipants.filter(
(participant) => !getParticipantIsRoomAdmin(participant)
(participant) => !getParticipantIsRoomAdminOrOwner(participant)
)
const currentSources = useMemo(() => {
@@ -1,12 +0,0 @@
import type { Participant } from 'livekit-client'
export const getParticipantIsRoomAdmin = (
participant: Participant
): boolean => {
const attributes = participant.attributes
if (!attributes) {
return false
}
return attributes?.room_admin === 'true'
}
@@ -0,0 +1,20 @@
import type { Participant } from 'livekit-client'
import { ParticipantRole } from '@/features/rooms/api/ApiRoom'
const participantHasRoomRole = (
participant: Participant,
roles: ParticipantRole[]
): boolean => {
const role = participant.attributes?.room_role
return role !== undefined && roles.includes(role as ParticipantRole)
}
export const getParticipantIsRoomAdmin = (participant: Participant): boolean =>
participantHasRoomRole(participant, ['administrator'])
export const getParticipantIsRoomOwner = (participant: Participant): boolean =>
participantHasRoomRole(participant, ['owner'])
export const getParticipantIsRoomAdminOrOwner = (
participant: Participant
): boolean => participantHasRoomRole(participant, ['administrator', 'owner'])