Compare commits

..

11 Commits

Author SHA1 Message Date
briquet adc0443aec 🔧(dev) configure bureautix proxy for image builds
Builds through the Docker API of the Podman service receive none of the
proxy variables in their RUN steps and fail systematically because of
the proxy rejection. Plain HTTP connections are also rejected by the
proxy with a HTTP 405 method error.

- Passes http_proxy, https_proxy and no_proxy from the shell as build args
- Make the Debian mirror of the agents image a build argument and
  override it for bureautix to force https usage
2026-09-18 15:43:28 +02:00
briquet c34ecbd3ef 🔧(dev) remove the unused bin/compose wrapper
Nothing in the repository nor the CI calls it
2026-09-18 15:17:58 +02:00
briquet 78960d9769 🔧(dev) use a dedicated folder for docker compose overrides
Move extra compose files to docker/compose.d folder
2026-09-18 15:17:51 +02:00
briquet 41d07d36ee 🔧(dev) use port 8081 for keycloak admin on bureautix workstations
The Bureautix workstation proxy listens on 8080, which collides with
Keycloak's published admin port.
2026-09-18 15:17:44 +02:00
Briquet f7386e1741 🔧(dev) add a devenv shell for nix-based workstations
Add the minimal requirements to build and run the project locally on NixOS

- `devenv update` update devenv using NixOS 26.05 stable repositories
- `devenv shell` activates the devenv
- `devenv --profile <profile>` shell uses additional packages when
  activated (profile=agent|summary|k8s)
2026-09-18 15:17:36 +02:00
briquet f1da04eb27 🔧(podman) pin the livekit rtc section for local usage
Pin the LiveKit rtc section: the browser reaches the server through
podman's published ports on loopback while egress and the agents reach
it over the podman network, and those two have no address in common.

`advertise_internal_ip` keeps the container's own interface address as a
host candidate alongside the node_ip one, so LiveKit offers both and ICE
picks whichever works. Without it egress only ever sees 127.0.0.1, which
is the egress container itself, and its peer connection timeouts

`use_external_ip` is turned off since it would advertise the STUN-discovered
public IP, which no local peer can hairpin to.
2026-09-18 15:17:29 +02:00
briquet 2970420b84 🔧(podman) make the dev stack work with rootless podman
Rootless podman maps container UID 0 to the host user and every other
container UID to a subuid that owns nothing in the worktree, so the usual
DOCKER_USER=$(id -u):$(id -g) makes every bind mount effectively
read-only.

Add a compose.podman.yml to override the compose.yml and set
`userns_mode: keep-id` in order to map the host user to the same UID and UID
inside the container. The merge of the docker compose file is now done with
the COMPOSE_FILE environment variable
2026-09-18 15:17:21 +02:00
tanguy chenier 771f58c0aa 🐛(frontend) play the waiting room notification sound on every arrival
The waiting room has its own sound in notifications.mp3, and nothing could play
it: the sprite is named "waiting" while triggerNotificationSound passes a
NotificationType, and howler returns without playing when the sprite id is
unknown. ParticipantWaiting was also absent from the sound settings, so the
check on the store would have refused it first. The toast borrowed the
participant joined sound instead.

The sound was tied to the waiting list going from empty to non empty, so a
second person arriving while someone was still waiting was silent, which is the
case the issue describes.

Name the sprite after the notification type, register the type in the settings,
and sound every arrival, detected on the participant ids so that an admission
and an arrival between two refreshes do not cancel each other out.

closes #1705
2026-09-17 17:06:06 +02:00
briquet b159b20695 🐛(backend) read the Sentry release from pyproject.toml
get_release() read the version from a version.json file  but nothing generates
it during the CI Docker image build, therefore the release reported to Sentry
was always "NA".

Read the version from pyproject.toml instead, which is bumped at each
release and copied into the image.
2026-09-16 15:54:40 +02:00
leo 226d004838 ✅(agents) fix subtitle test
Result of test for display of subtitles was depending on local
env config, potentially failing. Fix this by overriding settings.
2026-09-16 14:20:44 +02:00
lebaudantoine b723b7bb62 🐛(frontend) fix file permissions in the Docker image
Incorrect file permissions in the frontend Docker image caused
problems when running the project, and were surfaced by @briquet
while setting it up with Podman.

Adjust the ownership and permissions applied during the build so
the image works cleanly under Docker and Podman alike.
2026-09-15 00:01:22 +02:00
24 changed files with 504 additions and 40 deletions
+3
View File
@@ -86,3 +86,6 @@ docker/livekit/rootCA.pem
# Frontend rollup-plugin-visualizer
/src/frontend/rollup-plugin-visualizer/*
# NixOS
.devenv
+3 -1
View File
@@ -11,6 +11,7 @@ and this project adheres to
### Added
- ✨(backend) make the LiveKit default video codec configurable
- 🔧(dev) add support for Bureautix workstations
### Changed
@@ -24,7 +25,8 @@ and this project adheres to
- ⬆️(frontend) upgrade humanize-duration from 3.33.2 to 3.34.1
### Fixed
- 🐛(backend) report the app release to Sentry instead of "NA"
- 🐛(frontend) play the waiting room notification sound on every arrival
- 🐛(backend) acknowledge unknown LiveKit webhook events instead of 422
- 🔒️(backend) enforce display name setting on rename API
- 🔒️(backend) reject inactive users in resource server backend
+2 -7
View File
@@ -36,14 +36,9 @@ DB_PORT = 5432
# -- Docker
# Get the current user ID to use for docker run and docker exec commands
ifneq ($(findstring podman,$(DOCKER_HOST)),)
DOCKER_UID = 0
DOCKER_GID = 0
else
DOCKER_UID = $(shell id -u)
DOCKER_GID = $(shell id -g)
endif
DOCKER_USER ?= $(DOCKER_UID):$(DOCKER_GID)
DOCKER_USER = $(DOCKER_UID):$(DOCKER_GID)
COMPOSE = DOCKER_USER=$(DOCKER_USER) docker compose
COMPOSE_EXEC = $(COMPOSE) exec
COMPOSE_EXEC_APP = $(COMPOSE_EXEC) app-dev
@@ -297,7 +292,7 @@ shell: ## connect to database shell
# -- Database
dbshell: ## connect to database shell
docker compose exec app-dev python manage.py dbshell
@$(COMPOSE_EXEC_APP) python manage.py dbshell
.PHONY: dbshell
resetdb: FLUSH_ARGS ?=
+3 -7
View File
@@ -5,7 +5,7 @@ set -eo pipefail
REPO_DIR="$(cd "$( dirname "${BASH_SOURCE[0]}" )/.." && pwd)"
UNSET_USER=0
COMPOSE_FILE="${REPO_DIR}/compose.yml"
export COMPOSE_FILE="${COMPOSE_FILE:-${REPO_DIR}/compose.yml}"
COMPOSE_PROJECT="meet"
@@ -25,11 +25,8 @@ function _set_user() {
return
fi
# USER_ID = USER_ID or the engine-appropriate default if USER_ID is not set.
case "${DOCKER_HOST:-}" in
*podman*) USER_ID=${USER_ID:-0} ;;
*) USER_ID=${USER_ID:-$(id -u)} ;;
esac
# USER_ID = USER_ID or `id -u` if USER_ID is not set
USER_ID=${USER_ID:-$(id -u)}
echo "🙋(user) ID: ${USER_ID}"
}
@@ -45,7 +42,6 @@ function _docker_compose() {
echo "🐳(compose) project: '${COMPOSE_PROJECT}' file: '${COMPOSE_FILE}'"
docker compose \
-p "${COMPOSE_PROJECT}" \
-f "${COMPOSE_FILE}" \
--project-directory "${REPO_DIR}" \
"$@"
}
-6
View File
@@ -1,6 +0,0 @@
#!/usr/bin/env bash
# shellcheck source=bin/_config.sh
source "$(dirname "${BASH_SOURCE[0]}")/_config.sh"
_docker_compose "$@"
+5 -1
View File
@@ -40,7 +40,11 @@ services:
minio:
condition: service_healthy
restart: true
entrypoint: ["/bin/sh", "-c", "mc alias set meet http://minio:9000 meet password && mc mb --ignore-existing meet/meet-media-storage"]
entrypoint: >
sh -c "
/usr/bin/mc alias set meet http://minio:9000 meet password && \
/usr/bin/mc mb meet/meet-media-storage && \
exit 0;"
app-dev:
build:
+47
View File
@@ -0,0 +1,47 @@
{
"nodes": {
"devenv": {
"locked": {
"dir": "src/modules",
"lastModified": 1778705847,
"narHash": "sha256-EQnZCy7r4VMO6KDoytxHBa0mFbM1D9g1kaDfs/s0YZA=",
"ref": "refs/tags/v2.1.2",
"rev": "ea3d94ac9d6bf6a1313773170122ca4e2ef5a0be",
"revCount": 6569,
"type": "git",
"url": "https://github.com/cachix/devenv"
},
"original": {
"dir": "src/modules",
"ref": "refs/tags/v2.1.2",
"type": "git",
"url": "https://github.com/cachix/devenv"
}
},
"nixpkgs": {
"locked": {
"lastModified": 1789542786,
"narHash": "sha256-ajQuqcxnj6RYnwCjA/9FTCnrdR2+BDzstE8UembXf60=",
"ref": "nixos-26.05",
"rev": "4c7870105e7f1fdf9c48688c8d7efc21abf0688a",
"shallow": true,
"type": "git",
"url": "https://github.com/NixOS/nixpkgs"
},
"original": {
"ref": "nixos-26.05",
"shallow": true,
"type": "git",
"url": "https://github.com/NixOS/nixpkgs"
}
},
"root": {
"inputs": {
"devenv": "devenv",
"nixpkgs": "nixpkgs"
}
}
},
"root": "root",
"version": 7
}
+265
View File
@@ -0,0 +1,265 @@
# =============================================================================
# devenv.nix — La Suite Meet ("Visio") developer environment
# =============================================================================
{
pkgs,
lib,
config,
...
}:
let
python = pkgs.python313;
nodejs = pkgs.nodejs_22;
backendDir = "src/backend";
agentsDir = "src/agents";
summaryDir = "src/summary";
frontendDir = "src/frontend";
readDotEnv =
file:
let
lines = lib.splitString "\n" (builtins.readFile file);
unquote =
v:
let
len = builtins.stringLength v;
in
if len >= 2 && lib.hasPrefix "\"" v && lib.hasSuffix "\"" v then
builtins.substring 1 (len - 2) v
else if len >= 2 && lib.hasPrefix "'" v && lib.hasSuffix "'" v then
builtins.substring 1 (len - 2) v
else
v;
parseLine =
line:
let
m = builtins.match "[ \t]*([A-Za-z_][A-Za-z0-9_]*)[ \t]*=[ \t]*(.*)" line;
in
if m == null then null else { name = builtins.elemAt m 0; value = unquote (builtins.elemAt m 1); };
in
builtins.listToAttrs (builtins.filter (x: x != null) (map parseLine lines));
# Reuse existing .env
dotEnv =
(readDotEnv ./env.d/development/common.dist)
// (readDotEnv ./env.d/development/postgresql.dist);
sharedEnv = builtins.removeAttrs dotEnv [ "PYTHONPATH" ]; # only makes sense inside the backend container.
in
{
options.meet = {
agents.enable = lib.mkEnableOption "tooling for the LiveKit agents in src/agents";
summary.enable = lib.mkEnableOption "tooling for the summary service in src/summary";
k8s.enable = lib.mkEnableOption "Kubernetes dev utilities";
};
config = {
# Profile can be activated with devenv --profile <profile> shell
profiles = {
agents.module = {
meet.agents.enable = true;
};
summary.module = {
meet.summary.enable = true;
};
k8s.module = {
meet.k8s.enable = true;
};
};
languages.python = {
enable = true;
package = python;
directory = backendDir;
manylinux.enable = pkgs.stdenv.hostPlatform.isLinux;
libraries = [
"${config.devenv.dotfile}/profile"
pkgs.file
pkgs.zlib
pkgs.libffi
pkgs.openssl
];
uv.enable = true;
uv.sync.enable = false;
venv.enable = false;
lsp.enable = true;
};
languages.javascript = {
enable = true;
package = nodejs;
directory = frontendDir;
npm.enable = true;
yarn.enable = true;
corepack.enable = false;
};
languages.typescript.enable = false;
languages.nix.enable = true;
packages =
with pkgs;
[
gnumake
file
shared-mime-info
gettext
postgresql_16
git
curl
jq
podman
podman-compose
docker-client
]
# -- LiveKit agents
++ lib.optionals config.meet.agents.enable [
glib
portaudio
livekit-cli
]
# -- summary service
++ lib.optionals config.meet.summary.enable [
redis
]
# -- Kubernetes tools
++ lib.optionals config.meet.k8s.enable [
kubectl
kubernetes-helm
helmfile
tilt
kind
mkcert
];
env = sharedEnv // {
UV_LINK_MODE = "copy";
PYTHONDONTWRITEBYTECODE = "1";
PYTHONUNBUFFERED = "1";
UV_PROJECT_ENVIRONMENT = lib.mkForce ".venv";
COMPOSE_PROJECT_NAME = "meet";
DJANGO_DATA_DIR = "${config.devenv.root}/data";
# Database / Pgsql
DB_HOST = "127.0.0.1";
DB_PORT = "15432";
PGHOST = "127.0.0.1";
PGPORT = "15432";
PGDATABASE = sharedEnv.DB_NAME;
PGUSER = sharedEnv.DB_USER;
PGPASSWORD = sharedEnv.DB_PASSWORD;
REDIS_URL = "redis://127.0.0.1:6379/1";
CELERY_BROKER_URL = "redis://127.0.0.1:6379/0";
# S3 / MinIO
AWS_S3_ENDPOINT_URL = "http://127.0.0.1:9000";
# OIDC
OIDC_OP_JWKS_ENDPOINT = "http://localhost:8083/realms/meet/protocol/openid-connect/certs";
OIDC_OP_TOKEN_ENDPOINT = "http://localhost:8083/realms/meet/protocol/openid-connect/token";
OIDC_OP_USER_ENDPOINT = "http://localhost:8083/realms/meet/protocol/openid-connect/userinfo";
OIDC_OP_INTROSPECTION_ENDPOINT = "http://localhost:8083/realms/meet/protocol/openid-connect/token/introspect";
# summary service
SUMMARY_SERVICE_ENDPOINT = "http://127.0.0.1:8001/api/v2/async-jobs/transcribe/";
SUMMARY_SERVICE_VERSION = "2";
# Mail
DJANGO_EMAIL_HOST = "127.0.0.1";
};
scripts = {
meet-venv = {
description = "Create/refresh meet uv virtualenvs for backend, agents and summary";
exec = ''
set -euo pipefail
cd "$DEVENV_ROOT"
echo "==> ${backendDir} (uv sync --locked, dependency-groups)"
( cd "${backendDir}" && uv sync --locked --all-groups )
echo "==> ${agentsDir} (uv sync --locked --all-extras)"
( cd "${agentsDir}" && uv sync --locked --all-extras )
echo "==> ${summaryDir} (uv sync --locked --all-extras)"
( cd "${summaryDir}" && uv sync --locked --all-extras )
echo
echo "Synced the following virtualenvs successfully:"
echo " ${backendDir}/.venv"
echo " ${agentsDir}/.venv"
echo " ${summaryDir}/.venv"
'';
};
};
enterShell = ''
# Make podman socket accessible in order to launch regular docker commands.
# Set MEET_PODMAN_SOCKET=0 to keep the DOCKER_HOST of the calling environment.
case "''${MEET_PODMAN_SOCKET:-1}" in
0|false|no|off) ;;
*)
_rundir="''${XDG_RUNTIME_DIR:-/run/user/$(id -u)}"
export DOCKER_HOST="unix://$_rundir/podman/podman.sock"
unset _rundir
;;
esac
# Compose files to merge
_compose_dir="${config.devenv.root}/docker/compose.d"
_compose_files="${config.devenv.root}/compose.yml"
export DOCKER_USER="$(id -u):$(id -g)"
case "''${DOCKER_HOST:-}" in
*podman*)
_compose_files="$_compose_files:$_compose_dir/compose.podman.yml"
# Build images with Podman/Buildah rather than BuildKit. `docker
# compose build` otherwise has buildx boot a moby/buildkit container,
# and that container lands in its own network namespace with neither
# the proxy in its environment nor any route to it.
# Buildah has neither problem: base images are resolved by the Podman systemd
# service, which inherits the proxy from its systemd socket activated unit, and
# RUN steps execute in the *host* network namespace
export DOCKER_BUILDKIT=0
export COMPOSE_BAKE=false
;;
esac
# Apply Bureautix override
if [ -n "''${http_proxy:-}" ]; then
_compose_files="$_compose_files:$_compose_dir/compose.bureautix.yml"
fi
export COMPOSE_FILE="$_compose_files"
unset _compose_dir _compose_files
# Make binaries accessible
for _d in \
"$DEVENV_ROOT/${backendDir}/.venv/bin" \
"$DEVENV_ROOT/${agentsDir}/.venv/bin" \
"$DEVENV_ROOT/${summaryDir}/.venv/bin" \
"$DEVENV_ROOT/${frontendDir}/node_modules/.bin"
do
[ -d "$_d" ] && export PATH="$_d:$PATH"
done
unset _d
'';
};
}
+5
View File
@@ -0,0 +1,5 @@
inputs:
nixpkgs:
url: git+https://github.com/NixOS/nixpkgs?ref=nixos-26.05&shallow=1
devenv:
url: git+https://github.com/cachix/devenv?ref=refs/tags/v2.1.2&dir=src/modules
+48
View File
@@ -0,0 +1,48 @@
# Bureautix proxy overrides
#
# Builds submitted through the Docker API of the Podman service get none of
# the proxy variables in their RUN steps. We need to pass the http_proxy explicitely
# otherwise all connections fail during the build.
x-proxy-vars: &proxy-vars
http_proxy: ${http_proxy:-}
https_proxy: ${https_proxy:-}
no_proxy: ${no_proxy:-}
services:
app:
build:
args:
<<: *proxy-vars
app-dev:
build:
args:
<<: *proxy-vars
frontend:
build:
args:
<<: *proxy-vars
metadata-collector-dev:
build:
args:
<<: *proxy-vars
multi-user-transcriber-dev:
build:
args:
<<: *proxy-vars
app-summary-dev:
build:
args:
<<: *proxy-vars
celery-summary-transcribe:
build:
args:
<<: *proxy-vars
celery-summary-summarize:
build:
args:
<<: *proxy-vars
# The local proxy listens on 8080 and collides with Keycloak's published admin port.
keycloak:
ports: !override
- "8081:8080"
+33
View File
@@ -0,0 +1,33 @@
# Rootless Podman override for compose.yml.
#
# Rootless Podman maps container UID 0 to the host user and every other
# container UID to a subuid that owns nothing in the worktree. Meet compose.ymlruns
# its containers as DOCKER_USER=$(id -u):$(id -g), which would land on such a
# subuid and make every bind mount effectively read-only.
#
# `userns_mode: keep-id` maps the host user to the same UID and GID inside the
# container instead, so DOCKER_USER keeps its Docker value and files written
# through a bind mount are owned by the host user on both sides.
#
# Only the services that mount the worktree and run as DOCKER_USER are listed.
x-keep-id: &keep-id
userns_mode: keep-id
services:
app-dev:
<<: *keep-id
celery-dev:
<<: *keep-id
minio:
<<: *keep-id
node:
<<: *keep-id
crowdin:
<<: *keep-id
metadata-collector-dev:
<<: *keep-id
multi-user-transcriber-dev:
<<: *keep-id
app-summary-dev:
<<: *keep-id
@@ -21,3 +21,10 @@ turn:
- 192.168.0.0/16
- 172.16.0.0/12
rtc:
node_ip: 127.0.0.1
advertise_internal_ip: true
udp_port: 7882
tcp_port: 7881
use_external_ip: false
+3 -2
View File
@@ -1,7 +1,8 @@
FROM python:3.14.6-slim AS base
# Install system dependencies required by LiveKit
RUN apt-get update && apt-get install -y \
# Install system dependencies required by LiveKit, fetching packages over HTTPS only for Bureautix proxy
RUN sed -i "s|^URIs: http://|URIs: https://|" /etc/apt/sources.list.d/debian.sources \
&& apt-get update && apt-get install -y --no-install-recommends \
libglib2.0-0 \
libgobject-2.0-0 \
&& rm -rf /var/lib/apt/lists/*
@@ -117,9 +117,11 @@ def test_start_subtitle_invalid_token():
assert response.json() == {"detail": "Invalid LiveKit token: Not enough segments"}
def test_start_subtitle_disabled_by_default(mock_livekit_token):
def test_start_subtitle_disabled_by_default(mock_livekit_token, settings):
"""Test that subtitle functionality is disabled when feature flag is off."""
settings.ROOM_SUBTITLE_ENABLED = False
room = RoomFactory()
user = UserFactory()
client = APIClient()
@@ -0,0 +1,47 @@
"""Unit tests for the get_release settings helper."""
import re
import pytest
from meet.settings import get_release
@pytest.fixture(name="base_dir")
def fixture_empty_base_dir(tmp_path, monkeypatch):
"""Point get_release at an empty directory."""
monkeypatch.setattr("meet.settings.BASE_DIR", str(tmp_path))
return tmp_path
def test_get_release_reads_project_pyproject():
"""Should return the semantic version of the backend's pyproject.toml."""
assert re.fullmatch(r"\d+\.\d+\.\d+", get_release())
def test_get_release_reads_pyproject_version(base_dir):
"""Should return the version declared in the [project] table."""
(base_dir / "pyproject.toml").write_text(
'[project]\nname = "meet"\nversion = "1.2.3"\n', encoding="utf-8"
)
assert get_release() == "1.2.3"
@pytest.mark.usefixtures("base_dir")
def test_get_release_missing_pyproject():
"""Should fall back to "NA" without a pyproject.toml."""
assert get_release() == "NA"
@pytest.mark.parametrize(
"content",
[
'[project]\nname = "meet"\n', # no version
"[tool.uv]\npackage = true\n", # no [project] table
"[project\nversion = ", # malformed TOML
],
)
def test_get_release_unreadable_version(base_dir, content):
"""Should fall back to "NA" without a readable version in pyproject.toml."""
(base_dir / "pyproject.toml").write_text(content, encoding="utf-8")
assert get_release() == "NA"
+4 -12
View File
@@ -12,7 +12,7 @@ https://docs.djangoproject.com/en/3.1/ref/settings/
# pylint: disable=too-many-lines
import json
import tomllib
import warnings
from os import path
from socket import gethostbyname, gethostname
@@ -37,19 +37,11 @@ GB = 1024 * MB
def get_release():
"""
Get the current release of the application
By release, we mean the release from the version.json file à la Mozilla [1]
(if any). If this file has not been found, it defaults to "NA".
[1]
https://github.com/mozilla-services/Dockerflow/blob/master/docs/version_object.md
"""
# Try to get the current release from the version.json file generated by the
# CI during the Docker image build
try:
with open(path.join(BASE_DIR, "version.json"), encoding="utf8") as version:
return json.load(version)["version"]
except FileNotFoundError:
with open(path.join(BASE_DIR, "pyproject.toml"), "rb") as pyproject:
return tomllib.load(pyproject)["project"]["version"]
except (FileNotFoundError, KeyError, tomllib.TOMLDecodeError):
return "NA" # Default: not available
@@ -34,6 +34,15 @@ export const WaitingParticipantNotification = () => {
const isParticipantListEmpty = (p?: WaitingParticipant[]) => p?.length == 0
useEffect(() => {
const previousIds = new Set(prevWaitingParticipant?.map(({ id }) => id))
const hasNewWaitingParticipant = waitingParticipants.some(
({ id }) => !previousIds.has(id)
)
if (hasNewWaitingParticipant) {
triggerNotificationSound(NotificationType.ParticipantWaiting)
}
// Show notification when the first participant enters the waiting room
if (
!isParticipantListEmpty(waitingParticipants) &&
@@ -42,8 +51,6 @@ export const WaitingParticipantNotification = () => {
) {
setShowQuickActionsMessage(true)
triggerNotificationSound(NotificationType.ParticipantJoined)
if (timerRef.current !== null) {
clearTimeout(timerRef.current)
}
@@ -11,7 +11,7 @@ export const useNotificationSound = () => {
participantJoined: [0, 1150],
handRaised: [1400, 180],
messageReceived: [1580, 300],
waiting: [2039, 710],
participantWaiting: [2039, 710],
success: [2740, 1304],
},
volume: notificationsSnap.soundNotificationVolume,
@@ -102,6 +102,9 @@
},
"messageReceived": {
"label": "Nachricht erhalten"
},
"participantWaiting": {
"label": "Person im Warteraum"
}
}
},
@@ -102,6 +102,9 @@
},
"messageReceived": {
"label": "Message received"
},
"participantWaiting": {
"label": "Participant waiting"
}
}
},
@@ -102,6 +102,9 @@
},
"messageReceived": {
"label": "Un mensaje recibido"
},
"participantWaiting": {
"label": "Una persona en la sala de espera"
}
}
},
@@ -102,6 +102,9 @@
},
"messageReceived": {
"label": "Un message reçu"
},
"participantWaiting": {
"label": "Une personne en salle d’attente"
}
}
},
@@ -102,6 +102,9 @@
},
"messageReceived": {
"label": "Bericht ontvangen"
},
"participantWaiting": {
"label": "Deelnemer in de wachtkamer"
}
}
},
+1
View File
@@ -16,6 +16,7 @@ const DEFAULT_STATE: State = {
[NotificationType.ParticipantJoined, true],
[NotificationType.HandRaised, true],
[NotificationType.MessageReceived, true],
[NotificationType.ParticipantWaiting, true],
])
),
soundNotificationVolume: 0.1,