mirror of
https://github.com/suitenumerique/meet.git
synced 2026-07-27 12:19:10 +00:00
Compare commits
5 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| dc9dedb91b | |||
| 3da3641a19 | |||
| 21626b4c4c | |||
| f16cedf5a5 | |||
| 00e4679dc5 |
@@ -1,22 +0,0 @@
|
|||||||
name: Helmfile lint
|
|
||||||
run-name: Helmfile lint
|
|
||||||
|
|
||||||
on:
|
|
||||||
pull_request:
|
|
||||||
branches:
|
|
||||||
- 'main'
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
helmfile-lint:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
container:
|
|
||||||
image: ghcr.io/helmfile/helmfile:latest
|
|
||||||
steps:
|
|
||||||
-
|
|
||||||
uses: numerique-gouv/action-helmfile-lint@main
|
|
||||||
with:
|
|
||||||
app-id: ${{ secrets.APP_ID }}
|
|
||||||
age-key: ${{ secrets.SOPS_PRIVATE }}
|
|
||||||
private-key: ${{ secrets.PRIVATE_KEY }}
|
|
||||||
helmfile-src: "src/helm"
|
|
||||||
repositories: "meet,secrets"
|
|
||||||
@@ -8,4 +8,3 @@ creation_rules:
|
|||||||
- age1tl80n23wq6zxegupwn70ew0yp225ua5v4dk800x7g2w6pvlxz46qk592pa #marie
|
- age1tl80n23wq6zxegupwn70ew0yp225ua5v4dk800x7g2w6pvlxz46qk592pa #marie
|
||||||
- age1qy04neuzwpasmvljqrcvhwnf0kz5cpyteze38c8avp0czewskasszv9pyw #argocd
|
- age1qy04neuzwpasmvljqrcvhwnf0kz5cpyteze38c8avp0czewskasszv9pyw #argocd
|
||||||
- age18fgn6j2vwwswqcpv9xpcehq8mrf9zs2sglwkamp3tzwx8d9jq9jsrskrk9 #manuuu
|
- age18fgn6j2vwwswqcpv9xpcehq8mrf9zs2sglwkamp3tzwx8d9jq9jsrskrk9 #manuuu
|
||||||
- age1hm2hsfgjezpsc3k0y5w5feq9t8vl3seq04qjhgt6ztd6403wfvpsgxu09m # github-repo
|
|
||||||
|
|||||||
@@ -1,13 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
|
|
||||||
set -e
|
|
||||||
|
|
||||||
HELMFILE=src/helm/helmfile.yaml
|
|
||||||
|
|
||||||
environments=$(awk '/environments:/ {flag=1; next} flag && NF {print} !NF {flag=0}' "$HELMFILE" | grep -E '^[[:space:]]{2}[a-zA-Z]+' | sed 's/^[[:space:]]*//;s/:.*//')
|
|
||||||
|
|
||||||
for env in $environments; do
|
|
||||||
echo "################### $env lint ###################"
|
|
||||||
helmfile -e $env -f src/helm/helmfile.yaml lint || exit 1
|
|
||||||
echo -e "\n"
|
|
||||||
done
|
|
||||||
+1
-3
@@ -13,9 +13,7 @@
|
|||||||
"enabled": false,
|
"enabled": false,
|
||||||
"groupName": "ignored js dependencies",
|
"groupName": "ignored js dependencies",
|
||||||
"matchManagers": ["npm"],
|
"matchManagers": ["npm"],
|
||||||
"matchPackageNames": [
|
"matchPackageNames": []
|
||||||
"eslint"
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
Submodule secrets updated: 8ef9f4513a...f5fbc16e6e
@@ -5,7 +5,7 @@ from django.urls import include, path
|
|||||||
|
|
||||||
from rest_framework.routers import DefaultRouter
|
from rest_framework.routers import DefaultRouter
|
||||||
|
|
||||||
from core.api import get_frontend_configuration, viewsets
|
from core.api import viewsets
|
||||||
from core.authentication.urls import urlpatterns as oidc_urls
|
from core.authentication.urls import urlpatterns as oidc_urls
|
||||||
|
|
||||||
# - Main endpoints
|
# - Main endpoints
|
||||||
@@ -23,7 +23,6 @@ urlpatterns = [
|
|||||||
[
|
[
|
||||||
*router.urls,
|
*router.urls,
|
||||||
*oidc_urls,
|
*oidc_urls,
|
||||||
path("config/", get_frontend_configuration, name="config"),
|
|
||||||
]
|
]
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -53,6 +53,7 @@ def generate_token(room: str, user, username: Optional[str] = None) -> str:
|
|||||||
room=room,
|
room=room,
|
||||||
room_join=True,
|
room_join=True,
|
||||||
room_admin=True,
|
room_admin=True,
|
||||||
|
room_record=True,
|
||||||
can_update_own_metadata=True,
|
can_update_own_metadata=True,
|
||||||
can_publish_sources=[
|
can_publish_sources=[
|
||||||
"camera",
|
"camera",
|
||||||
|
|||||||
@@ -251,19 +251,6 @@ class Base(Configuration):
|
|||||||
"REDOC_DIST": "SIDECAR",
|
"REDOC_DIST": "SIDECAR",
|
||||||
}
|
}
|
||||||
|
|
||||||
# Frontend
|
|
||||||
FRONTEND_CONFIGURATION = {
|
|
||||||
"analytics": values.DictValue(
|
|
||||||
{}, environ_name="FRONTEND_ANALYTICS", environ_prefix=None
|
|
||||||
),
|
|
||||||
"support": values.DictValue(
|
|
||||||
{}, environ_name="FRONTEND_SUPPORT", environ_prefix=None
|
|
||||||
),
|
|
||||||
"silence_livekit_debug_logs": values.BooleanValue(
|
|
||||||
False, environ_name="FRONTEND_SILENCE_LIVEKIT_DEBUG", environ_prefix=None
|
|
||||||
),
|
|
||||||
}
|
|
||||||
|
|
||||||
# Mail
|
# Mail
|
||||||
EMAIL_BACKEND = values.Value("django.core.mail.backends.smtp.EmailBackend")
|
EMAIL_BACKEND = values.Value("django.core.mail.backends.smtp.EmailBackend")
|
||||||
EMAIL_HOST = values.Value(None)
|
EMAIL_HOST = values.Value(None)
|
||||||
@@ -271,7 +258,6 @@ class Base(Configuration):
|
|||||||
EMAIL_HOST_PASSWORD = values.Value(None)
|
EMAIL_HOST_PASSWORD = values.Value(None)
|
||||||
EMAIL_PORT = values.PositiveIntegerValue(None)
|
EMAIL_PORT = values.PositiveIntegerValue(None)
|
||||||
EMAIL_USE_TLS = values.BooleanValue(False)
|
EMAIL_USE_TLS = values.BooleanValue(False)
|
||||||
EMAIL_USE_SSL = values.BooleanValue(False)
|
|
||||||
EMAIL_FROM = values.Value("from@example.com")
|
EMAIL_FROM = values.Value("from@example.com")
|
||||||
|
|
||||||
AUTH_USER_MODEL = "core.User"
|
AUTH_USER_MODEL = "core.User"
|
||||||
|
|||||||
+10
-10
@@ -7,7 +7,7 @@ build-backend = "setuptools.build_meta"
|
|||||||
|
|
||||||
[project]
|
[project]
|
||||||
name = "meet"
|
name = "meet"
|
||||||
version = "0.1.7"
|
version = "0.1.5"
|
||||||
authors = [{ "name" = "DINUM", "email" = "dev@mail.numerique.gouv.fr" }]
|
authors = [{ "name" = "DINUM", "email" = "dev@mail.numerique.gouv.fr" }]
|
||||||
classifiers = [
|
classifiers = [
|
||||||
"Development Status :: 5 - Production/Stable",
|
"Development Status :: 5 - Production/Stable",
|
||||||
@@ -25,7 +25,7 @@ license = { file = "LICENSE" }
|
|||||||
readme = "README.md"
|
readme = "README.md"
|
||||||
requires-python = ">=3.10"
|
requires-python = ">=3.10"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"boto3==1.35.19",
|
"boto3==1.35.10",
|
||||||
"Brotli==1.1.0",
|
"Brotli==1.1.0",
|
||||||
"celery[redis]==5.4.0",
|
"celery[redis]==5.4.0",
|
||||||
"django-configurations==2.5.1",
|
"django-configurations==2.5.1",
|
||||||
@@ -36,11 +36,11 @@ dependencies = [
|
|||||||
"django-redis==5.4.0",
|
"django-redis==5.4.0",
|
||||||
"django-storages[s3]==1.14.4",
|
"django-storages[s3]==1.14.4",
|
||||||
"django-timezone-field>=5.1",
|
"django-timezone-field>=5.1",
|
||||||
"django==5.1.1",
|
"django==5.1",
|
||||||
"djangorestframework==3.15.2",
|
"djangorestframework==3.15.2",
|
||||||
"drf_spectacular==0.27.2",
|
"drf_spectacular==0.27.2",
|
||||||
"dockerflow==2024.4.2",
|
"dockerflow==2024.4.2",
|
||||||
"easy_thumbnails==2.10",
|
"easy_thumbnails==2.9",
|
||||||
"factory_boy==3.3.1",
|
"factory_boy==3.3.1",
|
||||||
"freezegun==1.5.1",
|
"freezegun==1.5.1",
|
||||||
"gunicorn==23.0.0",
|
"gunicorn==23.0.0",
|
||||||
@@ -48,11 +48,11 @@ dependencies = [
|
|||||||
"june-analytics-python==2.3.0",
|
"june-analytics-python==2.3.0",
|
||||||
"markdown==3.7",
|
"markdown==3.7",
|
||||||
"nested-multipart-parser==1.5.0",
|
"nested-multipart-parser==1.5.0",
|
||||||
"psycopg[binary]==3.2.2",
|
"psycopg[binary]==3.2.1",
|
||||||
"PyJWT==2.9.0",
|
"PyJWT==2.9.0",
|
||||||
"python-frontmatter==1.1.0",
|
"python-frontmatter==1.1.0",
|
||||||
"requests==2.32.3",
|
"requests==2.32.3",
|
||||||
"sentry-sdk==2.14.0",
|
"sentry-sdk==2.13.0",
|
||||||
"url-normalize==1.4.3",
|
"url-normalize==1.4.3",
|
||||||
"WeasyPrint>=60.2",
|
"WeasyPrint>=60.2",
|
||||||
"whitenoise==6.7.0",
|
"whitenoise==6.7.0",
|
||||||
@@ -76,13 +76,13 @@ dev = [
|
|||||||
"pylint-django==2.5.5",
|
"pylint-django==2.5.5",
|
||||||
"pylint==3.2.7",
|
"pylint==3.2.7",
|
||||||
"pytest-cov==5.0.0",
|
"pytest-cov==5.0.0",
|
||||||
"pytest-django==4.9.0",
|
"pytest-django==4.8.0",
|
||||||
"pytest==8.3.3",
|
"pytest==8.3.2",
|
||||||
"pytest-icdiff==0.9",
|
"pytest-icdiff==0.9",
|
||||||
"pytest-xdist==3.6.1",
|
"pytest-xdist==3.6.1",
|
||||||
"responses==0.25.3",
|
"responses==0.25.3",
|
||||||
"ruff==0.6.5",
|
"ruff==0.6.3",
|
||||||
"types-requests==2.32.0.20240914",
|
"types-requests==2.32.0.20240712",
|
||||||
]
|
]
|
||||||
|
|
||||||
[tool.setuptools]
|
[tool.setuptools]
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
<meta charset="UTF-8" />
|
<meta charset="UTF-8" />
|
||||||
<link rel="icon" type="image/svg+xml" href="/play-icon.svg" />
|
<link rel="icon" type="image/svg+xml" href="/play-icon.svg" />
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
<title>Visio</title>
|
<title>Meet</title>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<div id="root"></div>
|
<div id="root"></div>
|
||||||
|
|||||||
Generated
+2725
-2357
File diff suppressed because it is too large
Load Diff
+27
-30
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"name": "meet",
|
"name": "meet",
|
||||||
"private": true,
|
"private": true,
|
||||||
"version": "0.1.7",
|
"version": "0.1.5",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "panda codegen && vite",
|
"dev": "panda codegen && vite",
|
||||||
@@ -13,48 +13,45 @@
|
|||||||
"check": "prettier --check ./src"
|
"check": "prettier --check ./src"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@livekit/components-react": "2.6.0",
|
"@livekit/components-react": "2.3.3",
|
||||||
"@livekit/components-styles": "1.1.2",
|
"@livekit/components-styles": "1.0.12",
|
||||||
"@livekit/track-processors": "0.3.2",
|
"@pandacss/preset-panda": "0.41.0",
|
||||||
"@pandacss/preset-panda": "0.46.1",
|
|
||||||
"@react-aria/toast": "3.0.0-beta.15",
|
"@react-aria/toast": "3.0.0-beta.15",
|
||||||
"@remixicon/react": "4.2.0",
|
"@remixicon/react": "4.2.0",
|
||||||
"@tanstack/react-query": "5.56.2",
|
"@tanstack/react-query": "5.49.2",
|
||||||
"crisp-sdk-web": "1.0.25",
|
|
||||||
"hoofd": "1.7.1",
|
"hoofd": "1.7.1",
|
||||||
"i18next": "23.15.1",
|
"i18next": "23.12.1",
|
||||||
"i18next-browser-languagedetector": "8.0.0",
|
"i18next-browser-languagedetector": "8.0.0",
|
||||||
"i18next-parser": "9.0.2",
|
"i18next-parser": "9.0.0",
|
||||||
"i18next-resources-to-backend": "1.2.1",
|
"i18next-resources-to-backend": "1.2.1",
|
||||||
"livekit-client": "2.5.3",
|
"livekit-client": "2.3.1",
|
||||||
"posthog-js": "1.164.1",
|
"react": "18.2.0",
|
||||||
"react": "18.3.1",
|
"react-aria-components": "1.2.1",
|
||||||
"react-aria-components": "1.3.3",
|
"react-dom": "18.2.0",
|
||||||
"react-dom": "18.3.1",
|
"react-i18next": "14.1.3",
|
||||||
"react-i18next": "15.0.2",
|
|
||||||
"use-sound": "4.0.3",
|
"use-sound": "4.0.3",
|
||||||
"valtio": "2.0.0",
|
"valtio": "1.13.2",
|
||||||
"wouter": "3.3.5"
|
"wouter": "3.3.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@pandacss/dev": "0.46.1",
|
"@pandacss/dev": "0.41.0",
|
||||||
"@tanstack/eslint-plugin-query": "5.57.1",
|
"@tanstack/eslint-plugin-query": "5.49.1",
|
||||||
"@tanstack/react-query-devtools": "5.56.2",
|
"@tanstack/react-query-devtools": "5.49.2",
|
||||||
"@types/node": "20.16.6",
|
"@types/node": "20.14.9",
|
||||||
"@types/react": "18.3.8",
|
"@types/react": "18.3.3",
|
||||||
"@types/react-dom": "18.3.0",
|
"@types/react-dom": "18.3.0",
|
||||||
"@typescript-eslint/eslint-plugin": "8.7.0",
|
"@typescript-eslint/eslint-plugin": "7.13.1",
|
||||||
"@typescript-eslint/parser": "8.7.0",
|
"@typescript-eslint/parser": "7.13.1",
|
||||||
"@vitejs/plugin-react": "4.3.1",
|
"@vitejs/plugin-react": "4.3.1",
|
||||||
"eslint": "8.57.0",
|
"eslint": "8.57.0",
|
||||||
"eslint-config-prettier": "9.1.0",
|
"eslint-config-prettier": "9.1.0",
|
||||||
"eslint-plugin-jsx-a11y": "6.10.0",
|
"eslint-plugin-jsx-a11y": "6.9.0",
|
||||||
"eslint-plugin-react-hooks": "4.6.2",
|
"eslint-plugin-react-hooks": "4.6.2",
|
||||||
"eslint-plugin-react-refresh": "0.4.12",
|
"eslint-plugin-react-refresh": "0.4.7",
|
||||||
"postcss": "8.4.47",
|
"postcss": "8.4.39",
|
||||||
"prettier": "3.3.3",
|
"prettier": "3.3.3",
|
||||||
"typescript": "5.6.2",
|
"typescript": "5.5.2",
|
||||||
"vite": "5.4.5",
|
"vite": "5.3.1",
|
||||||
"vite-tsconfig-paths": "5.0.1"
|
"vite-tsconfig-paths": "4.3.2"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,15 +11,18 @@ import { Layout } from './layout/Layout'
|
|||||||
import { NotFoundScreen } from './components/NotFoundScreen'
|
import { NotFoundScreen } from './components/NotFoundScreen'
|
||||||
import { routes } from './routes'
|
import { routes } from './routes'
|
||||||
import './i18n/init'
|
import './i18n/init'
|
||||||
|
import { silenceLiveKitLogs } from '@/utils/livekit.ts'
|
||||||
import { queryClient } from '@/api/queryClient'
|
import { queryClient } from '@/api/queryClient'
|
||||||
import { AppInitialization } from '@/components/AppInitialization'
|
|
||||||
|
|
||||||
function App() {
|
function App() {
|
||||||
const { i18n } = useTranslation()
|
const { i18n } = useTranslation()
|
||||||
useLang(i18n.language)
|
useLang(i18n.language)
|
||||||
|
|
||||||
|
const isProduction = import.meta.env.PROD
|
||||||
|
silenceLiveKitLogs(isProduction)
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<QueryClientProvider client={queryClient}>
|
<QueryClientProvider client={queryClient}>
|
||||||
<AppInitialization />
|
|
||||||
<Suspense fallback={null}>
|
<Suspense fallback={null}>
|
||||||
<I18nProvider locale={i18n.language}>
|
<I18nProvider locale={i18n.language}>
|
||||||
<Layout>
|
<Layout>
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
export const keys = {
|
export const keys = {
|
||||||
user: 'user',
|
user: 'user',
|
||||||
room: 'room',
|
room: 'room',
|
||||||
config: 'config',
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,26 +0,0 @@
|
|||||||
import { fetchApi } from './fetchApi'
|
|
||||||
import { keys } from './queryKeys'
|
|
||||||
import { useQuery } from '@tanstack/react-query'
|
|
||||||
|
|
||||||
export interface ApiConfig {
|
|
||||||
analytics?: {
|
|
||||||
id: string
|
|
||||||
host: string
|
|
||||||
}
|
|
||||||
support?: {
|
|
||||||
id: string
|
|
||||||
}
|
|
||||||
silence_livekit_debug_logs?: boolean
|
|
||||||
}
|
|
||||||
|
|
||||||
const fetchConfig = (): Promise<ApiConfig> => {
|
|
||||||
return fetchApi<ApiConfig>(`config/`)
|
|
||||||
}
|
|
||||||
|
|
||||||
export const useConfig = () => {
|
|
||||||
return useQuery({
|
|
||||||
queryKey: [keys.config],
|
|
||||||
queryFn: fetchConfig,
|
|
||||||
staleTime: Infinity,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
@@ -1,20 +0,0 @@
|
|||||||
import { silenceLiveKitLogs } from '@/utils/livekit'
|
|
||||||
import { useConfig } from '@/api/useConfig'
|
|
||||||
import { useAnalytics } from '@/features/analytics/hooks/useAnalytics'
|
|
||||||
import { useSupport } from '@/features/support/hooks/useSupport'
|
|
||||||
|
|
||||||
export const AppInitialization = () => {
|
|
||||||
const { data } = useConfig()
|
|
||||||
|
|
||||||
const {
|
|
||||||
analytics = {},
|
|
||||||
support = {},
|
|
||||||
silence_livekit_debug_logs = false,
|
|
||||||
} = data || {}
|
|
||||||
|
|
||||||
useAnalytics(analytics)
|
|
||||||
useSupport(support)
|
|
||||||
silenceLiveKitLogs(silence_livekit_debug_logs)
|
|
||||||
|
|
||||||
return null
|
|
||||||
}
|
|
||||||
File diff suppressed because one or more lines are too long
@@ -1,39 +0,0 @@
|
|||||||
import { useEffect } from 'react'
|
|
||||||
import { useLocation } from 'wouter'
|
|
||||||
import posthog from 'posthog-js'
|
|
||||||
import { ApiUser } from '@/features/auth/api/ApiUser'
|
|
||||||
|
|
||||||
export const startAnalyticsSession = (data: ApiUser) => {
|
|
||||||
if (posthog._isIdentified()) return
|
|
||||||
const { id, email } = data
|
|
||||||
posthog.identify(id, { email })
|
|
||||||
}
|
|
||||||
|
|
||||||
export const terminateAnalyticsSession = () => {
|
|
||||||
if (!posthog._isIdentified()) return
|
|
||||||
posthog.reset()
|
|
||||||
}
|
|
||||||
|
|
||||||
export type useAnalyticsProps = {
|
|
||||||
id?: string
|
|
||||||
host?: string
|
|
||||||
}
|
|
||||||
|
|
||||||
export const useAnalytics = ({ id, host }: useAnalyticsProps) => {
|
|
||||||
const [location] = useLocation()
|
|
||||||
useEffect(() => {
|
|
||||||
if (!id || !host) return
|
|
||||||
if (posthog.__loaded) return
|
|
||||||
posthog.init(id, {
|
|
||||||
api_host: host,
|
|
||||||
person_profiles: 'always',
|
|
||||||
})
|
|
||||||
}, [id, host])
|
|
||||||
|
|
||||||
// From PostHog tutorial on PageView tracking in a Single Page Application (SPA) context.
|
|
||||||
useEffect(() => {
|
|
||||||
posthog.capture('$pageview')
|
|
||||||
}, [location])
|
|
||||||
|
|
||||||
return null
|
|
||||||
}
|
|
||||||
@@ -20,7 +20,7 @@ export const fetchUser = (): Promise<ApiUser | false> => {
|
|||||||
// make sure to not resolve the promise while trying to silent login
|
// make sure to not resolve the promise while trying to silent login
|
||||||
// so that consumers of fetchUser don't think the work already ended
|
// so that consumers of fetchUser don't think the work already ended
|
||||||
if (canAttemptSilentLogin()) {
|
if (canAttemptSilentLogin()) {
|
||||||
attemptSilentLogin(300)
|
attemptSilentLogin(3600)
|
||||||
} else {
|
} else {
|
||||||
resolve(false)
|
resolve(false)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,12 +2,9 @@ import { useQuery } from '@tanstack/react-query'
|
|||||||
import { keys } from '@/api/queryKeys'
|
import { keys } from '@/api/queryKeys'
|
||||||
import { fetchUser } from './fetchUser'
|
import { fetchUser } from './fetchUser'
|
||||||
import { type ApiUser } from './ApiUser'
|
import { type ApiUser } from './ApiUser'
|
||||||
import { useEffect } from 'react'
|
|
||||||
import { startAnalyticsSession } from '@/features/analytics/hooks/useAnalytics'
|
|
||||||
import { initializeSupportSession } from '@/features/support/hooks/useSupport'
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* returns info about currently logged-in user
|
* returns info about currently logged in user
|
||||||
*
|
*
|
||||||
* `isLoggedIn` is undefined while query is loading and true/false when it's done
|
* `isLoggedIn` is undefined while query is loading and true/false when it's done
|
||||||
*/
|
*/
|
||||||
@@ -15,16 +12,9 @@ export const useUser = () => {
|
|||||||
const query = useQuery({
|
const query = useQuery({
|
||||||
queryKey: [keys.user],
|
queryKey: [keys.user],
|
||||||
queryFn: fetchUser,
|
queryFn: fetchUser,
|
||||||
staleTime: Infinity,
|
staleTime: 1000 * 60 * 60, // 1 hour
|
||||||
})
|
})
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
if (query?.data) {
|
|
||||||
startAnalyticsSession(query.data)
|
|
||||||
initializeSupportSession(query.data)
|
|
||||||
}
|
|
||||||
}, [query.data])
|
|
||||||
|
|
||||||
const isLoggedIn =
|
const isLoggedIn =
|
||||||
query.status === 'success' ? query.data !== false : undefined
|
query.status === 'success' ? query.data !== false : undefined
|
||||||
const isLoggedOut = isLoggedIn === false
|
const isLoggedOut = isLoggedIn === false
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ export const JoinMeetingDialog = () => {
|
|||||||
name="roomId"
|
name="roomId"
|
||||||
label={t('joinInputLabel')}
|
label={t('joinInputLabel')}
|
||||||
description={t('joinInputExample', {
|
description={t('joinInputExample', {
|
||||||
example: 'https://visio.numerique.gouv.fr/azer-tyu-qsdf',
|
example: 'https://meet.numerique.gouv.fr/azer-tyu-qsdf',
|
||||||
})}
|
})}
|
||||||
validate={(value) => {
|
validate={(value) => {
|
||||||
return !isRoomValid(value.trim()) ? (
|
return !isRoomValid(value.trim()) ? (
|
||||||
|
|||||||
@@ -44,7 +44,6 @@ export const LaterMeetingDialog = ({
|
|||||||
setIsCopied(true)
|
setIsCopied(true)
|
||||||
}}
|
}}
|
||||||
onHoverChange={setIsHovered}
|
onHoverChange={setIsHovered}
|
||||||
data-attr="later-dialog-copy"
|
|
||||||
>
|
>
|
||||||
{isCopied ? (
|
{isCopied ? (
|
||||||
<>
|
<>
|
||||||
|
|||||||
@@ -1,18 +1,18 @@
|
|||||||
import { useTranslation } from 'react-i18next'
|
import { useTranslation } from 'react-i18next'
|
||||||
import { DialogTrigger, MenuItem, Menu as RACMenu } from 'react-aria-components'
|
import { DialogTrigger } from 'react-aria-components'
|
||||||
import { Button, Menu, Text } from '@/primitives'
|
import { Button, Menu, Text } from '@/primitives'
|
||||||
import { HStack } from '@/styled-system/jsx'
|
import { HStack } from '@/styled-system/jsx'
|
||||||
import { navigateTo } from '@/navigation/navigateTo'
|
import { navigateTo } from '@/navigation/navigateTo'
|
||||||
import { Screen } from '@/layout/Screen'
|
import { Screen } from '@/layout/Screen'
|
||||||
import { Centered } from '@/layout/Centered'
|
import { Centered } from '@/layout/Centered'
|
||||||
import { generateRoomId } from '@/features/rooms'
|
import { generateRoomId } from '@/features/rooms'
|
||||||
import { useUser, UserAware } from '@/features/auth'
|
import { authUrl, useUser, UserAware } from '@/features/auth'
|
||||||
import { JoinMeetingDialog } from '../components/JoinMeetingDialog'
|
import { JoinMeetingDialog } from '../components/JoinMeetingDialog'
|
||||||
import { ProConnectButton } from '@/components/ProConnectButton'
|
|
||||||
import { useCreateRoom } from '@/features/rooms'
|
import { useCreateRoom } from '@/features/rooms'
|
||||||
import { usePersistentUserChoices } from '@livekit/components-react'
|
import { usePersistentUserChoices } from '@livekit/components-react'
|
||||||
import { menuItemRecipe } from '@/primitives/menuItemRecipe'
|
import { menuItemRecipe } from '@/primitives/menuItemRecipe'
|
||||||
import { RiAddLine, RiLink } from '@remixicon/react'
|
import { RiAddLine, RiLink } from '@remixicon/react'
|
||||||
|
import { MenuItem, Menu as RACMenu } from 'react-aria-components'
|
||||||
import { LaterMeetingDialog } from '@/features/home/components/LaterMeetingDialog'
|
import { LaterMeetingDialog } from '@/features/home/components/LaterMeetingDialog'
|
||||||
import { useState } from 'react'
|
import { useState } from 'react'
|
||||||
|
|
||||||
@@ -42,12 +42,10 @@ export const Home = () => {
|
|||||||
{t('loginToCreateMeeting')}
|
{t('loginToCreateMeeting')}
|
||||||
</Text>
|
</Text>
|
||||||
)}
|
)}
|
||||||
<HStack gap="gutter" alignItems="start">
|
<HStack gap="gutter">
|
||||||
{isLoggedIn ? (
|
{isLoggedIn ? (
|
||||||
<Menu>
|
<Menu>
|
||||||
<Button variant="primary" data-attr="create-meeting">
|
<Button variant="primary">{t('createMeeting')}</Button>
|
||||||
{t('createMeeting')}
|
|
||||||
</Button>
|
|
||||||
<RACMenu>
|
<RACMenu>
|
||||||
<MenuItem
|
<MenuItem
|
||||||
className={menuItemRecipe({ icon: true })}
|
className={menuItemRecipe({ icon: true })}
|
||||||
@@ -59,7 +57,6 @@ export const Home = () => {
|
|||||||
})
|
})
|
||||||
)
|
)
|
||||||
}}
|
}}
|
||||||
data-attr="create-option-instant"
|
|
||||||
>
|
>
|
||||||
<RiAddLine size={18} />
|
<RiAddLine size={18} />
|
||||||
{t('createMenu.instantOption')}
|
{t('createMenu.instantOption')}
|
||||||
@@ -72,7 +69,6 @@ export const Home = () => {
|
|||||||
setLaterRoomId(data.slug)
|
setLaterRoomId(data.slug)
|
||||||
)
|
)
|
||||||
}}
|
}}
|
||||||
data-attr="create-option-later"
|
|
||||||
>
|
>
|
||||||
<RiLink size={18} />
|
<RiLink size={18} />
|
||||||
{t('createMenu.laterOption')}
|
{t('createMenu.laterOption')}
|
||||||
@@ -80,16 +76,12 @@ export const Home = () => {
|
|||||||
</RACMenu>
|
</RACMenu>
|
||||||
</Menu>
|
</Menu>
|
||||||
) : (
|
) : (
|
||||||
<ProConnectButton />
|
<Button variant="primary" href={authUrl()}>
|
||||||
|
{t('login', { ns: 'global' })}
|
||||||
|
</Button>
|
||||||
)}
|
)}
|
||||||
<DialogTrigger>
|
<DialogTrigger>
|
||||||
<Button
|
<Button variant="primary" outline>
|
||||||
variant="primary"
|
|
||||||
outline
|
|
||||||
style={{
|
|
||||||
height: !isLoggedIn ? '56px' : undefined, // Temporary, Align with ProConnect Button fixed height
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{t('joinMeeting')}
|
{t('joinMeeting')}
|
||||||
</Button>
|
</Button>
|
||||||
<JoinMeetingDialog />
|
<JoinMeetingDialog />
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { useEffect } from 'react'
|
import { useEffect } from 'react'
|
||||||
import { useRoomContext } from '@livekit/components-react'
|
import { useRoomContext } from '@livekit/components-react'
|
||||||
import { Participant, RoomEvent } from 'livekit-client'
|
import { Participant, RemoteParticipant, RoomEvent } from 'livekit-client'
|
||||||
import { ToastProvider, toastQueue } from './components/ToastProvider'
|
import { ToastProvider, toastQueue } from './components/ToastProvider'
|
||||||
import { NotificationType } from './NotificationType'
|
import { NotificationType } from './NotificationType'
|
||||||
import { Div } from '@/primitives'
|
import { Div } from '@/primitives'
|
||||||
@@ -50,32 +50,31 @@ export const MainNotificationToast = () => {
|
|||||||
}
|
}
|
||||||
}, [room])
|
}, [room])
|
||||||
|
|
||||||
|
// fixme - close all related toasters when hands are lowered remotely
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
const decoder = new TextDecoder()
|
||||||
|
|
||||||
const handleNotificationReceived = (
|
const handleNotificationReceived = (
|
||||||
prevMetadataStr: string | undefined,
|
payload: Uint8Array,
|
||||||
participant: Participant
|
participant?: RemoteParticipant
|
||||||
) => {
|
) => {
|
||||||
if (!participant) return
|
if (!participant) {
|
||||||
if (isMobileBrowser()) return
|
return
|
||||||
if (participant.isLocal) return
|
}
|
||||||
|
if (isMobileBrowser()) {
|
||||||
const prevMetadata = JSON.parse(prevMetadataStr || '{}')
|
return
|
||||||
const metadata = JSON.parse(participant.metadata || '{}')
|
}
|
||||||
|
const notification = decoder.decode(payload)
|
||||||
if (prevMetadata.raised == metadata.raised) return
|
|
||||||
|
|
||||||
const existingToast = toastQueue.visibleToasts.find(
|
const existingToast = toastQueue.visibleToasts.find(
|
||||||
(toast) =>
|
(toast) =>
|
||||||
toast.content.participant === participant &&
|
toast.content.participant === participant &&
|
||||||
toast.content.type === NotificationType.Raised
|
toast.content.type === NotificationType.Raised
|
||||||
)
|
)
|
||||||
|
if (existingToast && notification === NotificationType.Lowered) {
|
||||||
if (existingToast && prevMetadata.raised && !metadata.raised) {
|
|
||||||
toastQueue.close(existingToast.key)
|
toastQueue.close(existingToast.key)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
if (!existingToast && notification === NotificationType.Raised) {
|
||||||
if (!existingToast && !prevMetadata.raised && metadata.raised) {
|
|
||||||
triggerNotificationSound(NotificationType.Raised)
|
triggerNotificationSound(NotificationType.Raised)
|
||||||
toastQueue.add(
|
toastQueue.add(
|
||||||
{
|
{
|
||||||
@@ -87,23 +86,13 @@ export const MainNotificationToast = () => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
room.on(RoomEvent.ParticipantMetadataChanged, handleNotificationReceived)
|
room.on(RoomEvent.DataReceived, handleNotificationReceived)
|
||||||
|
|
||||||
return () => {
|
return () => {
|
||||||
room.off(RoomEvent.ParticipantMetadataChanged, handleNotificationReceived)
|
room.off(RoomEvent.DataReceived, handleNotificationReceived)
|
||||||
}
|
}
|
||||||
}, [room, triggerNotificationSound])
|
}, [room, triggerNotificationSound])
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
const closeAllToasts = () => {
|
|
||||||
toastQueue.visibleToasts.forEach(({ key }) => toastQueue.close(key))
|
|
||||||
}
|
|
||||||
room.on(RoomEvent.Disconnected, closeAllToasts)
|
|
||||||
return () => {
|
|
||||||
room.off(RoomEvent.Disconnected, closeAllToasts)
|
|
||||||
}
|
|
||||||
}, [room])
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Div position="absolute" bottom={20} right={5} zIndex={1000}>
|
<Div position="absolute" bottom={20} right={5} zIndex={1000}>
|
||||||
<ToastProvider />
|
<ToastProvider />
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ import {
|
|||||||
import { Room, RoomOptions } from 'livekit-client'
|
import { Room, RoomOptions } from 'livekit-client'
|
||||||
import { keys } from '@/api/queryKeys'
|
import { keys } from '@/api/queryKeys'
|
||||||
import { queryClient } from '@/api/queryClient'
|
import { queryClient } from '@/api/queryClient'
|
||||||
|
import { navigateTo } from '@/navigation/navigateTo'
|
||||||
import { Screen } from '@/layout/Screen'
|
import { Screen } from '@/layout/Screen'
|
||||||
import { QueryAware } from '@/components/QueryAware'
|
import { QueryAware } from '@/components/QueryAware'
|
||||||
import { ErrorScreen } from '@/components/ErrorScreen'
|
import { ErrorScreen } from '@/components/ErrorScreen'
|
||||||
@@ -18,7 +19,6 @@ import { useCreateRoom } from '../api/createRoom'
|
|||||||
import { InviteDialog } from './InviteDialog'
|
import { InviteDialog } from './InviteDialog'
|
||||||
|
|
||||||
import { VideoConference } from '../livekit/prefabs/VideoConference'
|
import { VideoConference } from '../livekit/prefabs/VideoConference'
|
||||||
import posthog from 'posthog-js'
|
|
||||||
|
|
||||||
export const Conference = ({
|
export const Conference = ({
|
||||||
roomId,
|
roomId,
|
||||||
@@ -31,9 +31,6 @@ export const Conference = ({
|
|||||||
mode?: 'join' | 'create'
|
mode?: 'join' | 'create'
|
||||||
initialRoomData?: ApiRoom
|
initialRoomData?: ApiRoom
|
||||||
}) => {
|
}) => {
|
||||||
useEffect(() => {
|
|
||||||
posthog.capture('visit-room', { slug: roomId })
|
|
||||||
}, [roomId])
|
|
||||||
const fetchKey = [keys.room, roomId, userConfig.username]
|
const fetchKey = [keys.room, roomId, userConfig.username]
|
||||||
|
|
||||||
const {
|
const {
|
||||||
@@ -82,6 +79,25 @@ export const Conference = ({
|
|||||||
|
|
||||||
const [showInviteDialog, setShowInviteDialog] = useState(mode === 'create')
|
const [showInviteDialog, setShowInviteDialog] = useState(mode === 'create')
|
||||||
|
|
||||||
|
/**
|
||||||
|
* checks for actual click on the leave button instead of
|
||||||
|
* relying on LiveKitRoom onDisconnected because onDisconnected
|
||||||
|
* triggers even on page reload, it's not a user "onLeave" event really.
|
||||||
|
* Here we want to react to the user actually deciding to leave.
|
||||||
|
*/
|
||||||
|
useEffect(() => {
|
||||||
|
const checkOnLeaveClick = (event: MouseEvent) => {
|
||||||
|
const target = event.target as HTMLElement
|
||||||
|
if (target.classList.contains('lk-disconnect-button')) {
|
||||||
|
navigateTo('feedback')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
document.body.addEventListener('click', checkOnLeaveClick)
|
||||||
|
return () => {
|
||||||
|
document.body.removeEventListener('click', checkOnLeaveClick)
|
||||||
|
}
|
||||||
|
}, [])
|
||||||
|
|
||||||
const { t } = useTranslation('rooms')
|
const { t } = useTranslation('rooms')
|
||||||
if (isCreateError) {
|
if (isCreateError) {
|
||||||
// this error screen should be replaced by a proper waiting room for anonymous user.
|
// this error screen should be replaced by a proper waiting room for anonymous user.
|
||||||
|
|||||||
@@ -90,7 +90,6 @@ export const InviteDialog = ({
|
|||||||
setIsCopied(true)
|
setIsCopied(true)
|
||||||
}}
|
}}
|
||||||
onHoverChange={setIsHovered}
|
onHoverChange={setIsHovered}
|
||||||
data-attr="share-dialog-copy"
|
|
||||||
>
|
>
|
||||||
{isCopied ? (
|
{isCopied ? (
|
||||||
<>
|
<>
|
||||||
|
|||||||
@@ -16,8 +16,8 @@ export const Join = ({
|
|||||||
<PreJoin
|
<PreJoin
|
||||||
persistUserChoices
|
persistUserChoices
|
||||||
onSubmit={onSubmit}
|
onSubmit={onSubmit}
|
||||||
micLabel={t('join.audioinput.label')}
|
micLabel={t('join.micLabel')}
|
||||||
camLabel={t('join.videoinput.label')}
|
camLabel={t('join.camlabel')}
|
||||||
joinLabel={t('join.joinLabel')}
|
joinLabel={t('join.joinLabel')}
|
||||||
userLabel={t('join.userLabel')}
|
userLabel={t('join.userLabel')}
|
||||||
/>
|
/>
|
||||||
|
|||||||
@@ -11,7 +11,6 @@ export const useLowerHandParticipants = () => {
|
|||||||
)
|
)
|
||||||
return Promise.all(promises)
|
return Promise.all(promises)
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('An error occurred while lowering hands :', error)
|
|
||||||
throw new Error('An error occurred while lowering hands.')
|
throw new Error('An error occurred while lowering hands.')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,56 @@
|
|||||||
|
import { fetchServerApi } from './fetchServerApi'
|
||||||
|
import { buildServerApiUrl } from './buildServerApiUrl'
|
||||||
|
import { useRoomData } from '../hooks/useRoomData'
|
||||||
|
import { useParams } from 'wouter'
|
||||||
|
|
||||||
|
export const useRecordRoom = () => {
|
||||||
|
const data = useRoomData()
|
||||||
|
const { roomId: roomSlug } = useParams()
|
||||||
|
|
||||||
|
const recordRoom = () => {
|
||||||
|
if (!data || !data?.livekit) {
|
||||||
|
throw new Error('Room data is not available')
|
||||||
|
}
|
||||||
|
if (!roomSlug) {
|
||||||
|
throw new Error('Room ID is not available')
|
||||||
|
}
|
||||||
|
return fetchServerApi(
|
||||||
|
buildServerApiUrl(
|
||||||
|
data.livekit.url,
|
||||||
|
'/twirp/livekit.Egress/StartRoomCompositeEgress'
|
||||||
|
),
|
||||||
|
data.livekit.token,
|
||||||
|
{
|
||||||
|
method: 'POST',
|
||||||
|
body: JSON.stringify({
|
||||||
|
room_name: data.livekit.room,
|
||||||
|
audio_only: true,
|
||||||
|
file_outputs: [
|
||||||
|
{
|
||||||
|
file_extension: 'ogg',
|
||||||
|
filepath: `{room_name}_{time}_${roomSlug}`,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
}),
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
const stopRecordingRoom = (egressId: string) => {
|
||||||
|
if (!data || !data?.livekit) {
|
||||||
|
throw new Error('Room data is not available')
|
||||||
|
}
|
||||||
|
return fetchServerApi(
|
||||||
|
buildServerApiUrl(data.livekit.url, '/twirp/livekit.Egress/StopEgress'),
|
||||||
|
data.livekit.token,
|
||||||
|
{
|
||||||
|
method: 'POST',
|
||||||
|
body: JSON.stringify({
|
||||||
|
egressId,
|
||||||
|
}),
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
return { recordRoom, stopRecordingRoom }
|
||||||
|
}
|
||||||
@@ -1,191 +0,0 @@
|
|||||||
import { useEffect, useRef, useState } from 'react'
|
|
||||||
import { useLocalParticipant } from '@livekit/components-react'
|
|
||||||
import { LocalVideoTrack } from 'livekit-client'
|
|
||||||
import { Text, P, ToggleButton, Div, H } from '@/primitives'
|
|
||||||
import { useTranslation } from 'react-i18next'
|
|
||||||
import { HStack, styled, VStack } from '@/styled-system/jsx'
|
|
||||||
import {
|
|
||||||
BackgroundBlur,
|
|
||||||
BackgroundOptions,
|
|
||||||
ProcessorWrapper,
|
|
||||||
BackgroundTransformer,
|
|
||||||
} from '@livekit/track-processors'
|
|
||||||
|
|
||||||
const Information = styled('div', {
|
|
||||||
base: {
|
|
||||||
backgroundColor: 'orange.50',
|
|
||||||
borderRadius: '4px',
|
|
||||||
padding: '0.75rem 0.75rem',
|
|
||||||
marginTop: '0.8rem',
|
|
||||||
alignItems: 'start',
|
|
||||||
},
|
|
||||||
})
|
|
||||||
|
|
||||||
enum BlurRadius {
|
|
||||||
NONE = 0,
|
|
||||||
LIGHT = 5,
|
|
||||||
NORMAL = 10,
|
|
||||||
}
|
|
||||||
|
|
||||||
export const Effects = () => {
|
|
||||||
const { t } = useTranslation('rooms', { keyPrefix: 'effects' })
|
|
||||||
const { isCameraEnabled, cameraTrack, localParticipant } =
|
|
||||||
useLocalParticipant()
|
|
||||||
const videoRef = useRef<HTMLVideoElement>(null)
|
|
||||||
const [processorPending, setProcessorPending] = useState(false)
|
|
||||||
|
|
||||||
const localCameraTrack = cameraTrack?.track as LocalVideoTrack
|
|
||||||
|
|
||||||
const getProcessor = () => {
|
|
||||||
return localCameraTrack?.getProcessor() as ProcessorWrapper<BackgroundOptions>
|
|
||||||
}
|
|
||||||
|
|
||||||
const getBlurRadius = (): BlurRadius => {
|
|
||||||
const processor = getProcessor()
|
|
||||||
return (
|
|
||||||
(processor?.transformer as BackgroundTransformer)?.options?.blurRadius ||
|
|
||||||
BlurRadius.NONE
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
const toggleBlur = async (blurRadius: number) => {
|
|
||||||
if (!isCameraEnabled) await localParticipant.setCameraEnabled(true)
|
|
||||||
if (!localCameraTrack) return
|
|
||||||
|
|
||||||
setProcessorPending(true)
|
|
||||||
|
|
||||||
const processor = getProcessor()
|
|
||||||
const currentBlurRadius = getBlurRadius()
|
|
||||||
|
|
||||||
try {
|
|
||||||
if (blurRadius == currentBlurRadius && processor) {
|
|
||||||
await localCameraTrack.stopProcessor()
|
|
||||||
} else if (!processor) {
|
|
||||||
await localCameraTrack.setProcessor(BackgroundBlur(blurRadius))
|
|
||||||
} else {
|
|
||||||
await processor?.updateTransformerOptions({ blurRadius })
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
console.error('Error applying blur:', error)
|
|
||||||
} finally {
|
|
||||||
setProcessorPending(false)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
const videoElement = videoRef.current
|
|
||||||
if (!videoElement) return
|
|
||||||
|
|
||||||
const attachVideoTrack = async () => localCameraTrack?.attach(videoElement)
|
|
||||||
attachVideoTrack()
|
|
||||||
|
|
||||||
return () => {
|
|
||||||
if (!videoElement) return
|
|
||||||
localCameraTrack.detach(videoElement)
|
|
||||||
}
|
|
||||||
}, [localCameraTrack, isCameraEnabled])
|
|
||||||
|
|
||||||
const isSelected = (blurRadius: BlurRadius) => {
|
|
||||||
return isCameraEnabled && getBlurRadius() == blurRadius
|
|
||||||
}
|
|
||||||
|
|
||||||
const tooltipLabel = (blurRadius: BlurRadius) => {
|
|
||||||
return t(`blur.${isSelected(blurRadius) ? 'clear' : 'apply'}`)
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
<VStack padding="0 1.5rem">
|
|
||||||
{localCameraTrack && isCameraEnabled ? (
|
|
||||||
<video
|
|
||||||
ref={videoRef}
|
|
||||||
width="100%"
|
|
||||||
muted
|
|
||||||
style={{
|
|
||||||
transform: 'rotateY(180deg)',
|
|
||||||
minHeight: '175px',
|
|
||||||
borderRadius: '8px',
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
) : (
|
|
||||||
<div
|
|
||||||
style={{
|
|
||||||
width: '100%',
|
|
||||||
height: '174px',
|
|
||||||
display: 'flex',
|
|
||||||
backgroundColor: 'black',
|
|
||||||
justifyContent: 'center',
|
|
||||||
flexDirection: 'column',
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<P
|
|
||||||
style={{
|
|
||||||
color: 'white',
|
|
||||||
textAlign: 'center',
|
|
||||||
textWrap: 'balance',
|
|
||||||
marginBottom: 0,
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{t('activateCamera')}
|
|
||||||
</P>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
<Div
|
|
||||||
alignItems={'left'}
|
|
||||||
width={'100%'}
|
|
||||||
style={{
|
|
||||||
border: '1px solid #dadce0',
|
|
||||||
borderRadius: '8px',
|
|
||||||
margin: '0 .625rem',
|
|
||||||
padding: '0.5rem 1rem',
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<H
|
|
||||||
lvl={3}
|
|
||||||
style={{
|
|
||||||
marginBottom: '0.4rem',
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{t('heading')}
|
|
||||||
</H>
|
|
||||||
{ProcessorWrapper.isSupported ? (
|
|
||||||
<HStack>
|
|
||||||
<ToggleButton
|
|
||||||
size={'sm'}
|
|
||||||
legacyStyle
|
|
||||||
aria-label={tooltipLabel(BlurRadius.LIGHT)}
|
|
||||||
tooltip={tooltipLabel(BlurRadius.LIGHT)}
|
|
||||||
isDisabled={processorPending}
|
|
||||||
onPress={async () => await toggleBlur(BlurRadius.LIGHT)}
|
|
||||||
isSelected={isSelected(BlurRadius.LIGHT)}
|
|
||||||
>
|
|
||||||
{t('blur.light')}
|
|
||||||
</ToggleButton>
|
|
||||||
<ToggleButton
|
|
||||||
size={'sm'}
|
|
||||||
legacyStyle
|
|
||||||
aria-label={tooltipLabel(BlurRadius.NORMAL)}
|
|
||||||
tooltip={tooltipLabel(BlurRadius.NORMAL)}
|
|
||||||
isDisabled={processorPending}
|
|
||||||
onPress={async () => await toggleBlur(BlurRadius.NORMAL)}
|
|
||||||
isSelected={isSelected(BlurRadius.NORMAL)}
|
|
||||||
>
|
|
||||||
{t('blur.normal')}
|
|
||||||
</ToggleButton>
|
|
||||||
</HStack>
|
|
||||||
) : (
|
|
||||||
<Text variant="sm">{t('notAvailable')}</Text>
|
|
||||||
)}
|
|
||||||
<Information>
|
|
||||||
<Text
|
|
||||||
variant="sm"
|
|
||||||
style={{
|
|
||||||
textWrap: 'balance',
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
⚠︎ {t('experimental')}
|
|
||||||
</Text>
|
|
||||||
</Information>
|
|
||||||
</Div>
|
|
||||||
</VStack>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,32 @@
|
|||||||
|
import { useRoomContext } from '@livekit/components-react'
|
||||||
|
import { useEffect, useState } from 'react'
|
||||||
|
import { RoomEvent } from 'livekit-client'
|
||||||
|
|
||||||
|
export const RecordingIndicator = () => {
|
||||||
|
const room = useRoomContext()
|
||||||
|
const [isRecording, setIsRecording] = useState(room.isRecording)
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const handleRecordingStatusChanges = (isRecording: boolean) => {
|
||||||
|
setIsRecording(isRecording)
|
||||||
|
}
|
||||||
|
room.on(RoomEvent.RecordingStatusChanged, handleRecordingStatusChanges)
|
||||||
|
return () => {
|
||||||
|
room.off(RoomEvent.RecordingStatusChanged, handleRecordingStatusChanges)
|
||||||
|
}
|
||||||
|
}, [room])
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
style={{
|
||||||
|
display: 'flex',
|
||||||
|
justifyContent: 'center',
|
||||||
|
alignItems: 'center',
|
||||||
|
flexDirection: 'column',
|
||||||
|
width: '100%',
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Room is recording: {isRecording ? 'yes' : 'no'}
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
@@ -1,88 +0,0 @@
|
|||||||
import { useSnapshot } from 'valtio'
|
|
||||||
import { layoutStore } from '@/stores/layout'
|
|
||||||
import { css } from '@/styled-system/css'
|
|
||||||
import { Heading } from 'react-aria-components'
|
|
||||||
import { text } from '@/primitives/Text'
|
|
||||||
import { Box, Button, Div } from '@/primitives'
|
|
||||||
import { RiCloseLine } from '@remixicon/react'
|
|
||||||
import { useTranslation } from 'react-i18next'
|
|
||||||
import { ParticipantsList } from './controls/Participants/ParticipantsList'
|
|
||||||
import { useWidgetInteraction } from '../hooks/useWidgetInteraction'
|
|
||||||
import { ReactNode } from 'react'
|
|
||||||
import { Effects } from './Effects'
|
|
||||||
|
|
||||||
type StyledSidePanelProps = {
|
|
||||||
title: string
|
|
||||||
children: ReactNode
|
|
||||||
onClose: () => void
|
|
||||||
closeButtonTooltip: string
|
|
||||||
}
|
|
||||||
|
|
||||||
const StyledSidePanel = ({
|
|
||||||
title,
|
|
||||||
children,
|
|
||||||
onClose,
|
|
||||||
closeButtonTooltip,
|
|
||||||
}: StyledSidePanelProps) => (
|
|
||||||
<Box
|
|
||||||
size="sm"
|
|
||||||
minWidth="360px"
|
|
||||||
className={css({
|
|
||||||
overflow: 'hidden',
|
|
||||||
display: 'flex',
|
|
||||||
flexDirection: 'column',
|
|
||||||
margin: '1.5rem 1.5rem 1.5rem 0',
|
|
||||||
padding: 0,
|
|
||||||
gap: 0,
|
|
||||||
})}
|
|
||||||
>
|
|
||||||
<Heading
|
|
||||||
slot="title"
|
|
||||||
level={1}
|
|
||||||
className={text({ variant: 'h2' })}
|
|
||||||
style={{
|
|
||||||
paddingLeft: '1.5rem',
|
|
||||||
paddingTop: '1rem',
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{title}
|
|
||||||
</Heading>
|
|
||||||
<Div position="absolute" top="5" right="5">
|
|
||||||
<Button
|
|
||||||
invisible
|
|
||||||
size="xs"
|
|
||||||
onPress={onClose}
|
|
||||||
aria-label={closeButtonTooltip}
|
|
||||||
tooltip={closeButtonTooltip}
|
|
||||||
>
|
|
||||||
<RiCloseLine />
|
|
||||||
</Button>
|
|
||||||
</Div>
|
|
||||||
<Div overflowY="scroll">{children}</Div>
|
|
||||||
</Box>
|
|
||||||
)
|
|
||||||
|
|
||||||
export const SidePanel = () => {
|
|
||||||
const layoutSnap = useSnapshot(layoutStore)
|
|
||||||
const sidePanel = layoutSnap.sidePanel
|
|
||||||
|
|
||||||
const { isParticipantsOpen, isEffectsOpen } = useWidgetInteraction()
|
|
||||||
const { t } = useTranslation('rooms', { keyPrefix: 'sidePanel' })
|
|
||||||
|
|
||||||
if (!sidePanel) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
<StyledSidePanel
|
|
||||||
title={t(`heading.${sidePanel}`)}
|
|
||||||
onClose={() => (layoutStore.sidePanel = null)}
|
|
||||||
closeButtonTooltip={t('closeButton', {
|
|
||||||
content: t(`content.${sidePanel}`),
|
|
||||||
})}
|
|
||||||
>
|
|
||||||
{isParticipantsOpen && <ParticipantsList />}
|
|
||||||
{isEffectsOpen && <Effects />}
|
|
||||||
</StyledSidePanel>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
@@ -5,7 +5,7 @@ import { css } from '@/styled-system/css'
|
|||||||
import { useWidgetInteraction } from '../../hooks/useWidgetInteraction'
|
import { useWidgetInteraction } from '../../hooks/useWidgetInteraction'
|
||||||
|
|
||||||
export const ChatToggle = () => {
|
export const ChatToggle = () => {
|
||||||
const { t } = useTranslation('rooms', { keyPrefix: 'controls.chat' })
|
const { t } = useTranslation('rooms')
|
||||||
|
|
||||||
const { isChatOpen, unreadMessages, toggleChat } = useWidgetInteraction()
|
const { isChatOpen, unreadMessages, toggleChat } = useWidgetInteraction()
|
||||||
const tooltipLabel = isChatOpen ? 'open' : 'closed'
|
const tooltipLabel = isChatOpen ? 'open' : 'closed'
|
||||||
@@ -20,11 +20,10 @@ export const ChatToggle = () => {
|
|||||||
<ToggleButton
|
<ToggleButton
|
||||||
square
|
square
|
||||||
legacyStyle
|
legacyStyle
|
||||||
aria-label={t(tooltipLabel)}
|
aria-label={t(`controls.chat.${tooltipLabel}`)}
|
||||||
tooltip={t(tooltipLabel)}
|
tooltip={t(`controls.chat.${tooltipLabel}`)}
|
||||||
isSelected={isChatOpen}
|
isSelected={isChatOpen}
|
||||||
onPress={() => toggleChat()}
|
onPress={() => toggleChat()}
|
||||||
data-attr={`controls-chat-${tooltipLabel}`}
|
|
||||||
>
|
>
|
||||||
<RiChat1Line />
|
<RiChat1Line />
|
||||||
</ToggleButton>
|
</ToggleButton>
|
||||||
|
|||||||
@@ -4,16 +4,30 @@ import { ToggleButton } from '@/primitives'
|
|||||||
import { css } from '@/styled-system/css'
|
import { css } from '@/styled-system/css'
|
||||||
import { useRoomContext } from '@livekit/components-react'
|
import { useRoomContext } from '@livekit/components-react'
|
||||||
import { useRaisedHand } from '@/features/rooms/livekit/hooks/useRaisedHand'
|
import { useRaisedHand } from '@/features/rooms/livekit/hooks/useRaisedHand'
|
||||||
|
import { NotificationType } from '@/features/notifications/NotificationType'
|
||||||
|
|
||||||
export const HandToggle = () => {
|
export const HandToggle = () => {
|
||||||
const { t } = useTranslation('rooms', { keyPrefix: 'controls.hand' })
|
const { t } = useTranslation('rooms')
|
||||||
|
|
||||||
const room = useRoomContext()
|
const room = useRoomContext()
|
||||||
const { isHandRaised, toggleRaisedHand } = useRaisedHand({
|
const { isHandRaised, toggleRaisedHand } = useRaisedHand({
|
||||||
participant: room.localParticipant,
|
participant: room.localParticipant,
|
||||||
})
|
})
|
||||||
|
|
||||||
const tooltipLabel = isHandRaised ? 'lower' : 'raise'
|
const label = isHandRaised
|
||||||
|
? t('controls.hand.lower')
|
||||||
|
: t('controls.hand.raise')
|
||||||
|
|
||||||
|
const notifyOtherParticipants = (isHandRaised: boolean) => {
|
||||||
|
room.localParticipant.publishData(
|
||||||
|
new TextEncoder().encode(
|
||||||
|
!isHandRaised ? NotificationType.Raised : NotificationType.Lowered
|
||||||
|
),
|
||||||
|
{
|
||||||
|
reliable: true,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
@@ -25,11 +39,13 @@ export const HandToggle = () => {
|
|||||||
<ToggleButton
|
<ToggleButton
|
||||||
square
|
square
|
||||||
legacyStyle
|
legacyStyle
|
||||||
aria-label={t(tooltipLabel)}
|
aria-label={label}
|
||||||
tooltip={t(tooltipLabel)}
|
tooltip={label}
|
||||||
isSelected={isHandRaised}
|
isSelected={isHandRaised}
|
||||||
onPress={() => toggleRaisedHand()}
|
onPress={() => {
|
||||||
data-attr={`controls-hand-${tooltipLabel}`}
|
notifyOtherParticipants(isHandRaised)
|
||||||
|
toggleRaisedHand()
|
||||||
|
}}
|
||||||
>
|
>
|
||||||
<RiHand />
|
<RiHand />
|
||||||
</ToggleButton>
|
</ToggleButton>
|
||||||
|
|||||||
@@ -1,37 +0,0 @@
|
|||||||
import { useConnectionState, useRoomContext } from '@livekit/components-react'
|
|
||||||
import { Button } from '@/primitives'
|
|
||||||
import { navigateTo } from '@/navigation/navigateTo'
|
|
||||||
import { RiPhoneFill } from '@remixicon/react'
|
|
||||||
import { useTranslation } from 'react-i18next'
|
|
||||||
import { ConnectionState } from 'livekit-client'
|
|
||||||
|
|
||||||
export const LeaveButton = () => {
|
|
||||||
const { t } = useTranslation('rooms', { keyPrefix: 'controls' })
|
|
||||||
const room = useRoomContext()
|
|
||||||
const connectionState = useConnectionState(room)
|
|
||||||
return (
|
|
||||||
<Button
|
|
||||||
isDisabled={connectionState === ConnectionState.Disconnected}
|
|
||||||
variant={'danger'}
|
|
||||||
tooltip={t('leave')}
|
|
||||||
aria-label={t('leave')}
|
|
||||||
onPress={() => {
|
|
||||||
room
|
|
||||||
.disconnect(true)
|
|
||||||
.catch((e) =>
|
|
||||||
console.error('An error occurred while disconnecting:', e)
|
|
||||||
)
|
|
||||||
.finally(() => {
|
|
||||||
navigateTo('feedback')
|
|
||||||
})
|
|
||||||
}}
|
|
||||||
data-attr="controls-leave"
|
|
||||||
>
|
|
||||||
<RiPhoneFill
|
|
||||||
style={{
|
|
||||||
transform: 'rotate(135deg)',
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</Button>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
+30
-34
@@ -1,15 +1,14 @@
|
|||||||
import { menuItemRecipe } from '@/primitives/menuItemRecipe'
|
import { menuItemRecipe } from '@/primitives/menuItemRecipe'
|
||||||
import {
|
import {
|
||||||
RiAccountBoxLine,
|
|
||||||
RiFeedbackLine,
|
RiFeedbackLine,
|
||||||
|
RiQuestionLine,
|
||||||
RiSettings3Line,
|
RiSettings3Line,
|
||||||
} from '@remixicon/react'
|
} from '@remixicon/react'
|
||||||
import { MenuItem, Menu as RACMenu, Section } from 'react-aria-components'
|
import { MenuItem, Menu as RACMenu } from 'react-aria-components'
|
||||||
import { useTranslation } from 'react-i18next'
|
import { useTranslation } from 'react-i18next'
|
||||||
import { Dispatch, SetStateAction } from 'react'
|
import { Dispatch, SetStateAction } from 'react'
|
||||||
import { DialogState } from './OptionsButton'
|
import { DialogState } from '@/features/rooms/livekit/components/controls/Options/OptionsButton'
|
||||||
import { Separator } from '@/primitives/Separator'
|
import { RecordingMenuItem } from './RecordingMenuItem.tsx'
|
||||||
import { useWidgetInteraction } from '../../../hooks/useWidgetInteraction'
|
|
||||||
|
|
||||||
// @todo try refactoring it to use MenuList component
|
// @todo try refactoring it to use MenuList component
|
||||||
export const OptionsMenuItems = ({
|
export const OptionsMenuItems = ({
|
||||||
@@ -17,8 +16,8 @@ export const OptionsMenuItems = ({
|
|||||||
}: {
|
}: {
|
||||||
onOpenDialog: Dispatch<SetStateAction<DialogState>>
|
onOpenDialog: Dispatch<SetStateAction<DialogState>>
|
||||||
}) => {
|
}) => {
|
||||||
const { t } = useTranslation('rooms', { keyPrefix: 'options.items' })
|
const { t } = useTranslation('rooms')
|
||||||
const { toggleEffects } = useWidgetInteraction()
|
|
||||||
return (
|
return (
|
||||||
<RACMenu
|
<RACMenu
|
||||||
style={{
|
style={{
|
||||||
@@ -26,33 +25,30 @@ export const OptionsMenuItems = ({
|
|||||||
width: '300px',
|
width: '300px',
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Section>
|
<MenuItem
|
||||||
<MenuItem
|
href="https://tchap.gouv.fr/#/room/!aGImQayAgBLjSBycpm:agent.dinum.tchap.gouv.fr?via=agent.dinum.tchap.gouv.fr"
|
||||||
onAction={() => toggleEffects()}
|
target="_blank"
|
||||||
className={menuItemRecipe({ icon: true })}
|
className={menuItemRecipe({ icon: true })}
|
||||||
>
|
>
|
||||||
<RiAccountBoxLine size={20} />
|
<RiQuestionLine size={18} />
|
||||||
{t('effects')}
|
{t('options.items.support')}
|
||||||
</MenuItem>
|
</MenuItem>
|
||||||
</Section>
|
<MenuItem
|
||||||
<Separator />
|
href="https://grist.incubateur.net/o/docs/forms/1YrfNP1QSSy8p2gCxMFnSf/4"
|
||||||
<Section>
|
target="_blank"
|
||||||
<MenuItem
|
className={menuItemRecipe({ icon: true })}
|
||||||
href="https://grist.incubateur.net/o/docs/forms/1YrfNP1QSSy8p2gCxMFnSf/4"
|
>
|
||||||
target="_blank"
|
<RiFeedbackLine size={18} />
|
||||||
className={menuItemRecipe({ icon: true })}
|
{t('options.items.feedbacks')}
|
||||||
>
|
</MenuItem>
|
||||||
<RiFeedbackLine size={20} />
|
<MenuItem
|
||||||
{t('feedbacks')}
|
className={menuItemRecipe({ icon: true })}
|
||||||
</MenuItem>
|
onAction={() => onOpenDialog('settings')}
|
||||||
<MenuItem
|
>
|
||||||
className={menuItemRecipe({ icon: true })}
|
<RiSettings3Line size={18} />
|
||||||
onAction={() => onOpenDialog('settings')}
|
{t('options.items.settings')}
|
||||||
>
|
</MenuItem>
|
||||||
<RiSettings3Line size={20} />
|
<RecordingMenuItem />
|
||||||
{t('settings')}
|
|
||||||
</MenuItem>
|
|
||||||
</Section>
|
|
||||||
</RACMenu>
|
</RACMenu>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
+51
@@ -0,0 +1,51 @@
|
|||||||
|
import { MenuItem } from 'react-aria-components'
|
||||||
|
import { menuItemRecipe } from '@/primitives/menuItemRecipe.ts'
|
||||||
|
import { RiPauseCircleLine, RiRecordCircleLine } from '@remixicon/react'
|
||||||
|
import { useRecordRoom } from '@/features/rooms/livekit/api/recordRoom.ts'
|
||||||
|
import { useState } from 'react'
|
||||||
|
import { egressStore } from '@/stores/egress.tsx'
|
||||||
|
import { useSnapshot } from 'valtio'
|
||||||
|
|
||||||
|
export const RecordingMenuItem = () => {
|
||||||
|
const { recordRoom, stopRecordingRoom } = useRecordRoom()
|
||||||
|
|
||||||
|
const egressSnap = useSnapshot(egressStore)
|
||||||
|
const egressId = egressSnap.egressId
|
||||||
|
|
||||||
|
const [isPending, setIsPending] = useState(false)
|
||||||
|
|
||||||
|
const handleAction = async () => {
|
||||||
|
if (egressId) {
|
||||||
|
setIsPending(true)
|
||||||
|
const response = await stopRecordingRoom(egressId)
|
||||||
|
console.log(response)
|
||||||
|
egressStore.egressId = undefined
|
||||||
|
setIsPending(false)
|
||||||
|
} else {
|
||||||
|
setIsPending(true)
|
||||||
|
const response = await recordRoom()
|
||||||
|
egressStore.egressId = response['egress_id'] as string
|
||||||
|
setIsPending(false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<MenuItem
|
||||||
|
isDisabled={isPending}
|
||||||
|
className={menuItemRecipe({ icon: true })}
|
||||||
|
onAction={handleAction}
|
||||||
|
>
|
||||||
|
{egressId ? (
|
||||||
|
<>
|
||||||
|
<RiPauseCircleLine size={18} />
|
||||||
|
Stop recording room
|
||||||
|
</>
|
||||||
|
) : (
|
||||||
|
<>
|
||||||
|
<RiRecordCircleLine size={18} />
|
||||||
|
Record room
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</MenuItem>
|
||||||
|
)
|
||||||
|
}
|
||||||
-1
@@ -73,7 +73,6 @@ export const HandRaisedListItem = ({
|
|||||||
size="sm"
|
size="sm"
|
||||||
onPress={() => lowerHandParticipant(participant)}
|
onPress={() => lowerHandParticipant(participant)}
|
||||||
tooltip={t('participants.lowerParticipantHand', { name })}
|
tooltip={t('participants.lowerParticipantHand', { name })}
|
||||||
data-attr="participants-lower-hand"
|
|
||||||
>
|
>
|
||||||
<RiHand />
|
<RiHand />
|
||||||
</Button>
|
</Button>
|
||||||
|
|||||||
-1
@@ -19,7 +19,6 @@ export const LowerAllHandsButton = ({
|
|||||||
fullWidth
|
fullWidth
|
||||||
variant="text"
|
variant="text"
|
||||||
onPress={() => lowerHandParticipants(participants)}
|
onPress={() => lowerHandParticipants(participants)}
|
||||||
data-attr="participants-lower-hands"
|
|
||||||
>
|
>
|
||||||
{t('participants.lowerParticipantsHand')}
|
{t('participants.lowerParticipantsHand')}
|
||||||
</Button>
|
</Button>
|
||||||
|
|||||||
-1
@@ -78,7 +78,6 @@ const MicIndicator = ({ participant }: MicIndicatorProps) => {
|
|||||||
? muteParticipant(participant)
|
? muteParticipant(participant)
|
||||||
: setIsAlertOpen(true)
|
: setIsAlertOpen(true)
|
||||||
}
|
}
|
||||||
data-attr="participants-mute"
|
|
||||||
>
|
>
|
||||||
{isMuted ? (
|
{isMuted ? (
|
||||||
<RiMicOffFill color={'gray'} />
|
<RiMicOffFill color={'gray'} />
|
||||||
|
|||||||
+80
-45
@@ -1,27 +1,27 @@
|
|||||||
import { css } from '@/styled-system/css'
|
import { css } from '@/styled-system/css'
|
||||||
import { allParticipantRoomEvents } from '@livekit/components-core'
|
|
||||||
import { useParticipants } from '@livekit/components-react'
|
import { useParticipants } from '@livekit/components-react'
|
||||||
|
|
||||||
import { Div, H } from '@/primitives'
|
import { Heading } from 'react-aria-components'
|
||||||
|
import { Box, Button, Div, H } from '@/primitives'
|
||||||
|
import { text } from '@/primitives/Text'
|
||||||
|
import { RiCloseLine } from '@remixicon/react'
|
||||||
|
import { participantsStore } from '@/stores/participants'
|
||||||
import { useTranslation } from 'react-i18next'
|
import { useTranslation } from 'react-i18next'
|
||||||
import { ParticipantListItem } from '../../controls/Participants/ParticipantListItem'
|
import { allParticipantRoomEvents } from '@/features/rooms/livekit/constants/events'
|
||||||
import { ParticipantsCollapsableList } from '../../controls/Participants/ParticipantsCollapsableList'
|
import { ParticipantListItem } from '@/features/rooms/livekit/components/controls/Participants/ParticipantListItem'
|
||||||
import { HandRaisedListItem } from '../../controls/Participants/HandRaisedListItem'
|
import { ParticipantsCollapsableList } from '@/features/rooms/livekit/components/controls/Participants/ParticipantsCollapsableList'
|
||||||
import { LowerAllHandsButton } from '../../controls/Participants/LowerAllHandsButton'
|
import { HandRaisedListItem } from '@/features/rooms/livekit/components/controls/Participants/HandRaisedListItem'
|
||||||
import { RoomEvent } from 'livekit-client'
|
import { LowerAllHandsButton } from '@/features/rooms/livekit/components/controls/Participants/LowerAllHandsButton'
|
||||||
|
|
||||||
// TODO: Optimize rendering performance, especially for longer participant lists, even though they are generally short.
|
// TODO: Optimize rendering performance, especially for longer participant lists, even though they are generally short.
|
||||||
export const ParticipantsList = () => {
|
export const ParticipantsList = () => {
|
||||||
const { t } = useTranslation('rooms', { keyPrefix: 'participants' })
|
const { t } = useTranslation('rooms')
|
||||||
|
|
||||||
// Preferred using the 'useParticipants' hook rather than the separate remote and local hooks,
|
// Preferred using the 'useParticipants' hook rather than the separate remote and local hooks,
|
||||||
// because the 'useLocalParticipant' hook does not update the participant's information when their
|
// because the 'useLocalParticipant' hook does not update the participant's information when their
|
||||||
// metadata/name changes. The LiveKit team has marked this as a TODO item in the code.
|
// metadata/name changes. The LiveKit team has marked this as a TODO item in the code.
|
||||||
const participants = useParticipants({
|
const participants = useParticipants({
|
||||||
updateOnlyOn: [
|
updateOnlyOn: allParticipantRoomEvents,
|
||||||
RoomEvent.ParticipantNameChanged,
|
|
||||||
...allParticipantRoomEvents,
|
|
||||||
],
|
|
||||||
})
|
})
|
||||||
|
|
||||||
const sortedRemoteParticipants = participants
|
const sortedRemoteParticipants = participants
|
||||||
@@ -44,40 +44,75 @@ export const ParticipantsList = () => {
|
|||||||
|
|
||||||
// TODO - extract inline styling in a centralized styling file, and avoid magic numbers
|
// TODO - extract inline styling in a centralized styling file, and avoid magic numbers
|
||||||
return (
|
return (
|
||||||
<>
|
<Box
|
||||||
<H
|
size="sm"
|
||||||
lvl={2}
|
minWidth="360px"
|
||||||
className={css({
|
className={css({
|
||||||
fontSize: '0.875rem',
|
overflow: 'hidden',
|
||||||
fontWeight: 'bold',
|
display: 'flex',
|
||||||
color: '#5f6368',
|
flexDirection: 'column',
|
||||||
padding: '0 1.5rem',
|
margin: '1.5rem 1.5rem 1.5rem 0',
|
||||||
marginBottom: '0.83em',
|
padding: 0,
|
||||||
})}
|
gap: 0,
|
||||||
|
})}
|
||||||
|
>
|
||||||
|
<Heading
|
||||||
|
slot="title"
|
||||||
|
level={1}
|
||||||
|
className={text({ variant: 'h2' })}
|
||||||
|
style={{
|
||||||
|
paddingLeft: '1.5rem',
|
||||||
|
paddingTop: '1rem',
|
||||||
|
}}
|
||||||
>
|
>
|
||||||
{t('subheading').toUpperCase()}
|
{t('participants.heading')}
|
||||||
</H>
|
</Heading>
|
||||||
{raisedHandParticipants.length > 0 && (
|
<Div position="absolute" top="5" right="5">
|
||||||
<Div marginBottom=".9375rem">
|
<Button
|
||||||
<ParticipantsCollapsableList
|
invisible
|
||||||
heading={t('raisedHands')}
|
size="xs"
|
||||||
participants={raisedHandParticipants}
|
onPress={() => (participantsStore.showParticipants = false)}
|
||||||
renderParticipant={(participant) => (
|
aria-label={t('participants.closeButton')}
|
||||||
<HandRaisedListItem participant={participant} />
|
tooltip={t('participants.closeButton')}
|
||||||
)}
|
>
|
||||||
action={() => (
|
<RiCloseLine />
|
||||||
<LowerAllHandsButton participants={raisedHandParticipants} />
|
</Button>
|
||||||
)}
|
</Div>
|
||||||
/>
|
<Div overflowY="scroll">
|
||||||
</Div>
|
<H
|
||||||
)}
|
lvl={2}
|
||||||
<ParticipantsCollapsableList
|
className={css({
|
||||||
heading={t('contributors')}
|
fontSize: '0.875rem',
|
||||||
participants={sortedParticipants}
|
fontWeight: 'bold',
|
||||||
renderParticipant={(participant) => (
|
color: '#5f6368',
|
||||||
<ParticipantListItem participant={participant} />
|
padding: '0 1.5rem',
|
||||||
|
marginBottom: '0.83em',
|
||||||
|
})}
|
||||||
|
>
|
||||||
|
{t('participants.subheading').toUpperCase()}
|
||||||
|
</H>
|
||||||
|
{raisedHandParticipants.length > 0 && (
|
||||||
|
<Div marginBottom=".9375rem">
|
||||||
|
<ParticipantsCollapsableList
|
||||||
|
heading={t('participants.raisedHands')}
|
||||||
|
participants={raisedHandParticipants}
|
||||||
|
renderParticipant={(participant) => (
|
||||||
|
<HandRaisedListItem participant={participant} />
|
||||||
|
)}
|
||||||
|
action={() => (
|
||||||
|
<LowerAllHandsButton participants={raisedHandParticipants} />
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
</Div>
|
||||||
)}
|
)}
|
||||||
/>
|
<ParticipantsCollapsableList
|
||||||
</>
|
heading={t('participants.contributors')}
|
||||||
|
participants={sortedParticipants}
|
||||||
|
renderParticipant={(participant) => (
|
||||||
|
<ParticipantListItem participant={participant} />
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
</Div>
|
||||||
|
</Box>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
+3
-4
@@ -6,7 +6,7 @@ import { useParticipants } from '@livekit/components-react'
|
|||||||
import { useWidgetInteraction } from '../../../hooks/useWidgetInteraction'
|
import { useWidgetInteraction } from '../../../hooks/useWidgetInteraction'
|
||||||
|
|
||||||
export const ParticipantsToggle = () => {
|
export const ParticipantsToggle = () => {
|
||||||
const { t } = useTranslation('rooms', { keyPrefix: 'controls.participants' })
|
const { t } = useTranslation('rooms')
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Context could not be used due to inconsistent refresh behavior.
|
* Context could not be used due to inconsistent refresh behavior.
|
||||||
@@ -30,11 +30,10 @@ export const ParticipantsToggle = () => {
|
|||||||
<ToggleButton
|
<ToggleButton
|
||||||
square
|
square
|
||||||
legacyStyle
|
legacyStyle
|
||||||
aria-label={t(tooltipLabel)}
|
aria-label={t(`controls.participants.${tooltipLabel}`)}
|
||||||
tooltip={t(tooltipLabel)}
|
tooltip={t(`controls.participants.${tooltipLabel}`)}
|
||||||
isSelected={isParticipantsOpen}
|
isSelected={isParticipantsOpen}
|
||||||
onPress={() => toggleParticipants()}
|
onPress={() => toggleParticipants()}
|
||||||
data-attr={`controls-participants-${tooltipLabel}`}
|
|
||||||
>
|
>
|
||||||
<RiGroupLine />
|
<RiGroupLine />
|
||||||
</ToggleButton>
|
</ToggleButton>
|
||||||
|
|||||||
@@ -1,56 +0,0 @@
|
|||||||
import { Div, ToggleButton } from '@/primitives'
|
|
||||||
import { RiArrowUpLine, RiCloseFill, RiRectangleLine } from '@remixicon/react'
|
|
||||||
import { useTranslation } from 'react-i18next'
|
|
||||||
import { useTrackToggle, UseTrackToggleProps } from '@livekit/components-react'
|
|
||||||
import { Track } from 'livekit-client'
|
|
||||||
import React from 'react'
|
|
||||||
|
|
||||||
export const ScreenShareToggle = (
|
|
||||||
props: Omit<
|
|
||||||
UseTrackToggleProps<Track.Source.ScreenShare>,
|
|
||||||
'source' | 'captureOptions'
|
|
||||||
>
|
|
||||||
) => {
|
|
||||||
const { t } = useTranslation('rooms', { keyPrefix: 'controls.screenShare' })
|
|
||||||
const { buttonProps, enabled } = useTrackToggle({
|
|
||||||
...props,
|
|
||||||
source: Track.Source.ScreenShare,
|
|
||||||
captureOptions: { audio: true, selfBrowserSurface: 'include' },
|
|
||||||
})
|
|
||||||
|
|
||||||
const tooltipLabel = enabled ? 'stop' : 'start'
|
|
||||||
const Icon = enabled ? RiCloseFill : RiArrowUpLine
|
|
||||||
|
|
||||||
// fixme - remove ToggleButton custom styles when we design a proper icon
|
|
||||||
return (
|
|
||||||
<ToggleButton
|
|
||||||
isSelected={enabled}
|
|
||||||
square
|
|
||||||
legacyStyle
|
|
||||||
tooltip={t(tooltipLabel)}
|
|
||||||
onPress={(e) =>
|
|
||||||
buttonProps.onClick?.(
|
|
||||||
e as unknown as React.MouseEvent<HTMLButtonElement, MouseEvent>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
style={{
|
|
||||||
maxWidth: '46px',
|
|
||||||
maxHeight: '46px',
|
|
||||||
}}
|
|
||||||
data-attr={`controls-screenshare-${tooltipLabel}`}
|
|
||||||
>
|
|
||||||
<Div position="relative">
|
|
||||||
<RiRectangleLine size={28} />
|
|
||||||
<Icon
|
|
||||||
size={16}
|
|
||||||
style={{
|
|
||||||
position: 'absolute',
|
|
||||||
top: '50%',
|
|
||||||
left: '50%',
|
|
||||||
transform: 'translate(-50%, -50%)',
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</Div>
|
|
||||||
</ToggleButton>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
@@ -1,120 +0,0 @@
|
|||||||
import { useTranslation } from 'react-i18next'
|
|
||||||
import {
|
|
||||||
useMediaDeviceSelect,
|
|
||||||
useTrackToggle,
|
|
||||||
UseTrackToggleProps,
|
|
||||||
} from '@livekit/components-react'
|
|
||||||
import { HStack } from '@/styled-system/jsx'
|
|
||||||
import { Button, Menu, MenuList, ToggleButton } from '@/primitives'
|
|
||||||
import {
|
|
||||||
RemixiconComponentType,
|
|
||||||
RiArrowDownSLine,
|
|
||||||
RiMicLine,
|
|
||||||
RiMicOffLine,
|
|
||||||
RiVideoOffLine,
|
|
||||||
RiVideoOnLine,
|
|
||||||
} from '@remixicon/react'
|
|
||||||
import { Track } from 'livekit-client'
|
|
||||||
import React from 'react'
|
|
||||||
|
|
||||||
export type ToggleSource = Exclude<
|
|
||||||
Track.Source,
|
|
||||||
Track.Source.ScreenShareAudio | Track.Source.Unknown
|
|
||||||
>
|
|
||||||
|
|
||||||
type SelectToggleSource = Exclude<ToggleSource, Track.Source.ScreenShare>
|
|
||||||
|
|
||||||
type SelectToggleDeviceConfig = {
|
|
||||||
kind: MediaDeviceKind
|
|
||||||
iconOn: RemixiconComponentType
|
|
||||||
iconOff: RemixiconComponentType
|
|
||||||
}
|
|
||||||
|
|
||||||
type SelectToggleDeviceConfigMap = {
|
|
||||||
[key in SelectToggleSource]: SelectToggleDeviceConfig
|
|
||||||
}
|
|
||||||
|
|
||||||
const selectToggleDeviceConfig: SelectToggleDeviceConfigMap = {
|
|
||||||
[Track.Source.Microphone]: {
|
|
||||||
kind: 'audioinput',
|
|
||||||
iconOn: RiMicLine,
|
|
||||||
iconOff: RiMicOffLine,
|
|
||||||
},
|
|
||||||
[Track.Source.Camera]: {
|
|
||||||
kind: 'videoinput',
|
|
||||||
iconOn: RiVideoOnLine,
|
|
||||||
iconOff: RiVideoOffLine,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
type SelectToggleDeviceProps<T extends ToggleSource> =
|
|
||||||
UseTrackToggleProps<T> & {
|
|
||||||
onActiveDeviceChange: (deviceId: string) => void
|
|
||||||
source: SelectToggleSource
|
|
||||||
}
|
|
||||||
|
|
||||||
export const SelectToggleDevice = <T extends ToggleSource>({
|
|
||||||
onActiveDeviceChange,
|
|
||||||
...props
|
|
||||||
}: SelectToggleDeviceProps<T>) => {
|
|
||||||
const config = selectToggleDeviceConfig[props.source]
|
|
||||||
if (!config) {
|
|
||||||
throw new Error('Invalid source')
|
|
||||||
}
|
|
||||||
|
|
||||||
const { t } = useTranslation('rooms', { keyPrefix: 'join' })
|
|
||||||
const { buttonProps, enabled } = useTrackToggle(props)
|
|
||||||
|
|
||||||
const { kind, iconOn, iconOff } = config
|
|
||||||
|
|
||||||
const { devices, activeDeviceId, setActiveMediaDevice } =
|
|
||||||
useMediaDeviceSelect({ kind })
|
|
||||||
|
|
||||||
const toggleLabel = t(enabled ? 'disable' : 'enable', {
|
|
||||||
keyPrefix: `join.${kind}`,
|
|
||||||
})
|
|
||||||
|
|
||||||
const selectLabel = t('choose', { keyPrefix: `join.${kind}` })
|
|
||||||
const Icon = enabled ? iconOn : iconOff
|
|
||||||
|
|
||||||
return (
|
|
||||||
<HStack gap={0}>
|
|
||||||
<ToggleButton
|
|
||||||
isSelected={enabled}
|
|
||||||
variant={enabled ? undefined : 'danger'}
|
|
||||||
toggledStyles={false}
|
|
||||||
onPress={(e) =>
|
|
||||||
buttonProps.onClick?.(
|
|
||||||
e as unknown as React.MouseEvent<HTMLButtonElement>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
aria-label={toggleLabel}
|
|
||||||
tooltip={toggleLabel}
|
|
||||||
groupPosition="left"
|
|
||||||
>
|
|
||||||
<Icon />
|
|
||||||
</ToggleButton>
|
|
||||||
<Menu>
|
|
||||||
<Button
|
|
||||||
tooltip={selectLabel}
|
|
||||||
aria-label={selectLabel}
|
|
||||||
groupPosition="right"
|
|
||||||
square
|
|
||||||
>
|
|
||||||
<RiArrowDownSLine />
|
|
||||||
</Button>
|
|
||||||
<MenuList
|
|
||||||
items={devices.map((d) => ({
|
|
||||||
value: d.deviceId,
|
|
||||||
label: d.label,
|
|
||||||
}))}
|
|
||||||
selectedItem={activeDeviceId}
|
|
||||||
onAction={(value) => {
|
|
||||||
setActiveMediaDevice(value as string)
|
|
||||||
onActiveDeviceChange(value as string)
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</Menu>
|
|
||||||
</HStack>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,33 @@
|
|||||||
|
import { RoomEvent } from 'livekit-client'
|
||||||
|
|
||||||
|
// Issue: 'allRemoteParticipantRoomEvents' is not exposed or importable. One event is missing
|
||||||
|
// to trigger the real-time update of participants when they change their name.
|
||||||
|
// This code is duplicated from LiveKit.
|
||||||
|
export const allRemoteParticipantRoomEvents = [
|
||||||
|
RoomEvent.ConnectionStateChanged,
|
||||||
|
RoomEvent.RoomMetadataChanged,
|
||||||
|
|
||||||
|
RoomEvent.ActiveSpeakersChanged,
|
||||||
|
RoomEvent.ConnectionQualityChanged,
|
||||||
|
|
||||||
|
RoomEvent.ParticipantConnected,
|
||||||
|
RoomEvent.ParticipantDisconnected,
|
||||||
|
RoomEvent.ParticipantPermissionsChanged,
|
||||||
|
RoomEvent.ParticipantMetadataChanged,
|
||||||
|
RoomEvent.ParticipantNameChanged, // This element is missing in LiveKit and causes problems
|
||||||
|
|
||||||
|
RoomEvent.TrackMuted,
|
||||||
|
RoomEvent.TrackUnmuted,
|
||||||
|
RoomEvent.TrackPublished,
|
||||||
|
RoomEvent.TrackUnpublished,
|
||||||
|
RoomEvent.TrackStreamStateChanged,
|
||||||
|
RoomEvent.TrackSubscriptionFailed,
|
||||||
|
RoomEvent.TrackSubscriptionPermissionChanged,
|
||||||
|
RoomEvent.TrackSubscriptionStatusChanged,
|
||||||
|
]
|
||||||
|
|
||||||
|
export const allParticipantRoomEvents = [
|
||||||
|
...allRemoteParticipantRoomEvents,
|
||||||
|
RoomEvent.LocalTrackPublished,
|
||||||
|
RoomEvent.LocalTrackUnpublished,
|
||||||
|
]
|
||||||
@@ -7,7 +7,6 @@ type useRaisedHandProps = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function useRaisedHand({ participant }: useRaisedHandProps) {
|
export function useRaisedHand({ participant }: useRaisedHandProps) {
|
||||||
// fixme - refactor this part to rely on attributes
|
|
||||||
const { metadata } = useParticipantInfo({ participant })
|
const { metadata } = useParticipantInfo({ participant })
|
||||||
const parsedMetadata = JSON.parse(metadata || '{}')
|
const parsedMetadata = JSON.parse(metadata || '{}')
|
||||||
|
|
||||||
|
|||||||
@@ -1,46 +1,34 @@
|
|||||||
import { useLayoutContext } from '@livekit/components-react'
|
import { useLayoutContext } from '@livekit/components-react'
|
||||||
import { useSnapshot } from 'valtio'
|
import { useSnapshot } from 'valtio'
|
||||||
import { layoutStore } from '@/stores/layout'
|
import { participantsStore } from '@/stores/participants.ts'
|
||||||
|
|
||||||
export const useWidgetInteraction = () => {
|
export const useWidgetInteraction = () => {
|
||||||
const { dispatch, state } = useLayoutContext().widget
|
const { dispatch, state } = useLayoutContext().widget
|
||||||
|
|
||||||
const layoutSnap = useSnapshot(layoutStore)
|
const participantsSnap = useSnapshot(participantsStore)
|
||||||
const sidePanel = layoutSnap.sidePanel
|
const isParticipantsOpen = participantsSnap.showParticipants
|
||||||
|
|
||||||
const isParticipantsOpen = sidePanel == 'participants'
|
|
||||||
const isEffectsOpen = sidePanel == 'effects'
|
|
||||||
|
|
||||||
const toggleParticipants = () => {
|
const toggleParticipants = () => {
|
||||||
if (dispatch && state?.showChat) {
|
if (dispatch && state?.showChat) {
|
||||||
dispatch({ msg: 'toggle_chat' })
|
dispatch({ msg: 'toggle_chat' })
|
||||||
}
|
}
|
||||||
layoutStore.sidePanel = isParticipantsOpen ? null : 'participants'
|
participantsStore.showParticipants = !isParticipantsOpen
|
||||||
}
|
}
|
||||||
|
|
||||||
const toggleChat = () => {
|
const toggleChat = () => {
|
||||||
if (isParticipantsOpen || isEffectsOpen) {
|
if (isParticipantsOpen) {
|
||||||
layoutStore.sidePanel = null
|
participantsStore.showParticipants = false
|
||||||
}
|
}
|
||||||
if (dispatch) {
|
if (dispatch) {
|
||||||
dispatch({ msg: 'toggle_chat' })
|
dispatch({ msg: 'toggle_chat' })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const toggleEffects = () => {
|
|
||||||
if (dispatch && state?.showChat) {
|
|
||||||
dispatch({ msg: 'toggle_chat' })
|
|
||||||
}
|
|
||||||
layoutStore.sidePanel = isEffectsOpen ? null : 'effects'
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
toggleParticipants,
|
toggleParticipants,
|
||||||
toggleChat,
|
toggleChat,
|
||||||
toggleEffects,
|
|
||||||
isChatOpen: state?.showChat,
|
isChatOpen: state?.showChat,
|
||||||
unreadMessages: state?.unreadMessages,
|
unreadMessages: state?.unreadMessages,
|
||||||
isParticipantsOpen,
|
isParticipantsOpen,
|
||||||
isEffectsOpen,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,6 +4,10 @@ import * as React from 'react'
|
|||||||
import { supportsScreenSharing } from '@livekit/components-core'
|
import { supportsScreenSharing } from '@livekit/components-core'
|
||||||
|
|
||||||
import {
|
import {
|
||||||
|
DisconnectButton,
|
||||||
|
LeaveIcon,
|
||||||
|
MediaDeviceMenu,
|
||||||
|
TrackToggle,
|
||||||
useMaybeLayoutContext,
|
useMaybeLayoutContext,
|
||||||
usePersistentUserChoices,
|
usePersistentUserChoices,
|
||||||
} from '@livekit/components-react'
|
} from '@livekit/components-react'
|
||||||
@@ -11,13 +15,11 @@ import {
|
|||||||
import { mergeProps } from '@/utils/mergeProps.ts'
|
import { mergeProps } from '@/utils/mergeProps.ts'
|
||||||
import { StartMediaButton } from '../components/controls/StartMediaButton'
|
import { StartMediaButton } from '../components/controls/StartMediaButton'
|
||||||
import { useMediaQuery } from '../hooks/useMediaQuery'
|
import { useMediaQuery } from '../hooks/useMediaQuery'
|
||||||
|
import { useTranslation } from 'react-i18next'
|
||||||
import { OptionsButton } from '../components/controls/Options/OptionsButton'
|
import { OptionsButton } from '../components/controls/Options/OptionsButton'
|
||||||
import { ParticipantsToggle } from '../components/controls/Participants/ParticipantsToggle'
|
import { ParticipantsToggle } from '@/features/rooms/livekit/components/controls/Participants/ParticipantsToggle'
|
||||||
import { ChatToggle } from '../components/controls/ChatToggle'
|
import { ChatToggle } from '@/features/rooms/livekit/components/controls/ChatToggle'
|
||||||
import { HandToggle } from '../components/controls/HandToggle'
|
import { HandToggle } from '@/features/rooms/livekit/components/controls/HandToggle'
|
||||||
import { SelectToggleDevice } from '../components/controls/SelectToggleDevice'
|
|
||||||
import { LeaveButton } from '../components/controls/LeaveButton'
|
|
||||||
import { ScreenShareToggle } from '../components/controls/ScreenShareToggle'
|
|
||||||
|
|
||||||
/** @public */
|
/** @public */
|
||||||
export type ControlBarControls = {
|
export type ControlBarControls = {
|
||||||
@@ -36,7 +38,7 @@ export interface ControlBarProps extends React.HTMLAttributes<HTMLDivElement> {
|
|||||||
controls?: ControlBarControls
|
controls?: ControlBarControls
|
||||||
/**
|
/**
|
||||||
* If `true`, the user's device choices will be persisted.
|
* If `true`, the user's device choices will be persisted.
|
||||||
* This will enable the user to have the same device choices when they rejoin the room.
|
* This will enables the user to have the same device choices when they rejoin the room.
|
||||||
* @defaultValue true
|
* @defaultValue true
|
||||||
* @alpha
|
* @alpha
|
||||||
*/
|
*/
|
||||||
@@ -65,6 +67,7 @@ export function ControlBar({
|
|||||||
onDeviceError,
|
onDeviceError,
|
||||||
...props
|
...props
|
||||||
}: ControlBarProps) {
|
}: ControlBarProps) {
|
||||||
|
const { t } = useTranslation('rooms')
|
||||||
const [isChatOpen, setIsChatOpen] = React.useState(false)
|
const [isChatOpen, setIsChatOpen] = React.useState(false)
|
||||||
const layoutContext = useMaybeLayoutContext()
|
const layoutContext = useMaybeLayoutContext()
|
||||||
React.useEffect(() => {
|
React.useEffect(() => {
|
||||||
@@ -80,8 +83,26 @@ export function ControlBar({
|
|||||||
const defaultVariation = isTooLittleSpace ? 'minimal' : 'verbose'
|
const defaultVariation = isTooLittleSpace ? 'minimal' : 'verbose'
|
||||||
variation ??= defaultVariation
|
variation ??= defaultVariation
|
||||||
|
|
||||||
|
const showIcon = React.useMemo(
|
||||||
|
() => variation === 'minimal' || variation === 'verbose',
|
||||||
|
[variation]
|
||||||
|
)
|
||||||
|
const showText = React.useMemo(
|
||||||
|
() => variation === 'textOnly' || variation === 'verbose',
|
||||||
|
[variation]
|
||||||
|
)
|
||||||
|
|
||||||
const browserSupportsScreenSharing = supportsScreenSharing()
|
const browserSupportsScreenSharing = supportsScreenSharing()
|
||||||
|
|
||||||
|
const [isScreenShareEnabled, setIsScreenShareEnabled] = React.useState(false)
|
||||||
|
|
||||||
|
const onScreenShareChange = React.useCallback(
|
||||||
|
(enabled: boolean) => {
|
||||||
|
setIsScreenShareEnabled(enabled)
|
||||||
|
},
|
||||||
|
[setIsScreenShareEnabled]
|
||||||
|
)
|
||||||
|
|
||||||
const htmlProps = mergeProps({ className: 'lk-control-bar' }, props)
|
const htmlProps = mergeProps({ className: 'lk-control-bar' }, props)
|
||||||
|
|
||||||
const {
|
const {
|
||||||
@@ -105,38 +126,72 @@ export function ControlBar({
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div {...htmlProps}>
|
<div {...htmlProps}>
|
||||||
<SelectToggleDevice
|
<div className="lk-button-group">
|
||||||
source={Track.Source.Microphone}
|
<TrackToggle
|
||||||
onChange={microphoneOnChange}
|
source={Track.Source.Microphone}
|
||||||
onDeviceError={(error) =>
|
showIcon={showIcon}
|
||||||
onDeviceError?.({ source: Track.Source.Microphone, error })
|
onChange={microphoneOnChange}
|
||||||
}
|
onDeviceError={(error) =>
|
||||||
onActiveDeviceChange={(deviceId) =>
|
onDeviceError?.({ source: Track.Source.Microphone, error })
|
||||||
saveAudioInputDeviceId(deviceId ?? '')
|
}
|
||||||
}
|
>
|
||||||
/>
|
{showText && t('controls.microphone')}
|
||||||
<SelectToggleDevice
|
</TrackToggle>
|
||||||
source={Track.Source.Camera}
|
<div className="lk-button-group-menu">
|
||||||
onChange={cameraOnChange}
|
<MediaDeviceMenu
|
||||||
onDeviceError={(error) =>
|
kind="audioinput"
|
||||||
onDeviceError?.({ source: Track.Source.Camera, error })
|
onActiveDeviceChange={(_kind, deviceId) =>
|
||||||
}
|
saveAudioInputDeviceId(deviceId ?? '')
|
||||||
onActiveDeviceChange={(deviceId) =>
|
}
|
||||||
saveVideoInputDeviceId(deviceId ?? '')
|
/>
|
||||||
}
|
</div>
|
||||||
/>
|
</div>
|
||||||
|
<div className="lk-button-group">
|
||||||
|
<TrackToggle
|
||||||
|
source={Track.Source.Camera}
|
||||||
|
showIcon={showIcon}
|
||||||
|
onChange={cameraOnChange}
|
||||||
|
onDeviceError={(error) =>
|
||||||
|
onDeviceError?.({ source: Track.Source.Camera, error })
|
||||||
|
}
|
||||||
|
>
|
||||||
|
{showText && t('controls.camera')}
|
||||||
|
</TrackToggle>
|
||||||
|
<div className="lk-button-group-menu">
|
||||||
|
<MediaDeviceMenu
|
||||||
|
kind="videoinput"
|
||||||
|
onActiveDeviceChange={(_kind, deviceId) =>
|
||||||
|
saveVideoInputDeviceId(deviceId ?? '')
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
{browserSupportsScreenSharing && (
|
{browserSupportsScreenSharing && (
|
||||||
<ScreenShareToggle
|
<TrackToggle
|
||||||
|
source={Track.Source.ScreenShare}
|
||||||
|
captureOptions={{ audio: true, selfBrowserSurface: 'include' }}
|
||||||
|
showIcon={showIcon}
|
||||||
|
onChange={onScreenShareChange}
|
||||||
onDeviceError={(error) =>
|
onDeviceError={(error) =>
|
||||||
onDeviceError?.({ source: Track.Source.ScreenShare, error })
|
onDeviceError?.({ source: Track.Source.ScreenShare, error })
|
||||||
}
|
}
|
||||||
/>
|
>
|
||||||
|
{showText &&
|
||||||
|
t(
|
||||||
|
isScreenShareEnabled
|
||||||
|
? 'controls.stopScreenShare'
|
||||||
|
: 'controls.shareScreen'
|
||||||
|
)}
|
||||||
|
</TrackToggle>
|
||||||
)}
|
)}
|
||||||
<HandToggle />
|
<HandToggle />
|
||||||
<ChatToggle />
|
<ChatToggle />
|
||||||
<ParticipantsToggle />
|
<ParticipantsToggle />
|
||||||
<OptionsButton />
|
<OptionsButton />
|
||||||
<LeaveButton />
|
<DisconnectButton>
|
||||||
|
{showIcon && <LeaveIcon />}
|
||||||
|
{showText && t('controls.leave')}
|
||||||
|
</DisconnectButton>
|
||||||
<StartMediaButton />
|
<StartMediaButton />
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -30,12 +30,13 @@ import {
|
|||||||
import { ControlBar } from './ControlBar'
|
import { ControlBar } from './ControlBar'
|
||||||
import { styled } from '@/styled-system/jsx'
|
import { styled } from '@/styled-system/jsx'
|
||||||
import { cva } from '@/styled-system/css'
|
import { cva } from '@/styled-system/css'
|
||||||
|
import { ParticipantsList } from '@/features/rooms/livekit/components/controls/Participants/ParticipantsList'
|
||||||
import { useSnapshot } from 'valtio'
|
import { useSnapshot } from 'valtio'
|
||||||
import { layoutStore } from '@/stores/layout'
|
import { participantsStore } from '@/stores/participants'
|
||||||
import { FocusLayout } from '../components/FocusLayout'
|
import { FocusLayout } from '../components/FocusLayout'
|
||||||
import { ParticipantTile } from '../components/ParticipantTile'
|
import { ParticipantTile } from '../components/ParticipantTile'
|
||||||
import { SidePanel } from '../components/SidePanel'
|
|
||||||
import { MainNotificationToast } from '@/features/notifications/MainNotificationToast'
|
import { MainNotificationToast } from '@/features/notifications/MainNotificationToast'
|
||||||
|
import { RecordingIndicator } from '@/features/rooms/livekit/components/RecordingIndicator.tsx'
|
||||||
|
|
||||||
const LayoutWrapper = styled(
|
const LayoutWrapper = styled(
|
||||||
'div',
|
'div',
|
||||||
@@ -172,8 +173,8 @@ export function VideoConference({
|
|||||||
])
|
])
|
||||||
/* eslint-enable react-hooks/exhaustive-deps */
|
/* eslint-enable react-hooks/exhaustive-deps */
|
||||||
|
|
||||||
const layoutSnap = useSnapshot(layoutStore)
|
const participantsSnap = useSnapshot(participantsStore)
|
||||||
const sidePanel = layoutSnap.sidePanel
|
const showParticipants = participantsSnap.showParticipants
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="lk-video-conference" {...props}>
|
<div className="lk-video-conference" {...props}>
|
||||||
@@ -184,6 +185,7 @@ export function VideoConference({
|
|||||||
onWidgetChange={widgetUpdate}
|
onWidgetChange={widgetUpdate}
|
||||||
>
|
>
|
||||||
<div className="lk-video-conference-inner">
|
<div className="lk-video-conference-inner">
|
||||||
|
<RecordingIndicator />
|
||||||
<LayoutWrapper>
|
<LayoutWrapper>
|
||||||
<div
|
<div
|
||||||
style={{ display: 'flex', position: 'relative', width: '100%' }}
|
style={{ display: 'flex', position: 'relative', width: '100%' }}
|
||||||
@@ -223,7 +225,7 @@ export function VideoConference({
|
|||||||
messageEncoder={chatMessageEncoder}
|
messageEncoder={chatMessageEncoder}
|
||||||
messageDecoder={chatMessageDecoder}
|
messageDecoder={chatMessageDecoder}
|
||||||
/>
|
/>
|
||||||
{sidePanel && <SidePanel />}
|
{showParticipants && <ParticipantsList />}
|
||||||
</LayoutWrapper>
|
</LayoutWrapper>
|
||||||
<ControlBar />
|
<ControlBar />
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,8 +1,7 @@
|
|||||||
import { Trans, useTranslation } from 'react-i18next'
|
import { Trans, useTranslation } from 'react-i18next'
|
||||||
import { useLanguageLabels } from '@/i18n/useLanguageLabels'
|
import { useLanguageLabels } from '@/i18n/useLanguageLabels'
|
||||||
import { A, Badge, Dialog, type DialogProps, Field, H, P } from '@/primitives'
|
import { A, Badge, Dialog, type DialogProps, Field, H, P } from '@/primitives'
|
||||||
import { logoutUrl, useUser } from '@/features/auth'
|
import { authUrl, logoutUrl, useUser } from '@/features/auth'
|
||||||
import { ProConnectButton } from '@/components/ProConnectButton'
|
|
||||||
|
|
||||||
export type SettingsDialogProps = Pick<DialogProps, 'isOpen' | 'onOpenChange'>
|
export type SettingsDialogProps = Pick<DialogProps, 'isOpen' | 'onOpenChange'>
|
||||||
|
|
||||||
@@ -29,7 +28,9 @@ export const SettingsDialog = (props: SettingsDialogProps) => {
|
|||||||
) : (
|
) : (
|
||||||
<>
|
<>
|
||||||
<P>{t('account.youAreNotLoggedIn')}</P>
|
<P>{t('account.youAreNotLoggedIn')}</P>
|
||||||
<ProConnectButton />
|
<P>
|
||||||
|
<A href={authUrl()}>{t('login', { ns: 'global' })}</A>
|
||||||
|
</P>
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
<H lvl={2}>{t('language.heading')}</H>
|
<H lvl={2}>{t('language.heading')}</H>
|
||||||
|
|||||||
@@ -4,12 +4,11 @@ import {
|
|||||||
usePersistentUserChoices,
|
usePersistentUserChoices,
|
||||||
useRoomContext,
|
useRoomContext,
|
||||||
} from '@livekit/components-react'
|
} from '@livekit/components-react'
|
||||||
import { logoutUrl, useUser } from '@/features/auth'
|
import { authUrl, logoutUrl, useUser } from '@/features/auth'
|
||||||
import { css } from '@/styled-system/css'
|
import { css } from '@/styled-system/css'
|
||||||
import { TabPanel, TabPanelProps } from '@/primitives/Tabs'
|
import { TabPanel, TabPanelProps } from '@/primitives/Tabs'
|
||||||
import { HStack } from '@/styled-system/jsx'
|
import { HStack } from '@/styled-system/jsx'
|
||||||
import { useState } from 'react'
|
import { useState } from 'react'
|
||||||
import { ProConnectButton } from '@/components/ProConnectButton'
|
|
||||||
|
|
||||||
export type AccountTabProps = Pick<DialogProps, 'onOpenChange'> &
|
export type AccountTabProps = Pick<DialogProps, 'onOpenChange'> &
|
||||||
Pick<TabPanelProps, 'id'>
|
Pick<TabPanelProps, 'id'>
|
||||||
@@ -59,7 +58,9 @@ export const AccountTab = ({ id, onOpenChange }: AccountTabProps) => {
|
|||||||
) : (
|
) : (
|
||||||
<>
|
<>
|
||||||
<P>{t('account.youAreNotLoggedIn')}</P>
|
<P>{t('account.youAreNotLoggedIn')}</P>
|
||||||
<ProConnectButton />
|
<P>
|
||||||
|
<A href={authUrl()}>{t('login', { ns: 'global' })}</A>
|
||||||
|
</P>
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
<HStack
|
<HStack
|
||||||
|
|||||||
@@ -1,31 +0,0 @@
|
|||||||
import { useEffect } from 'react'
|
|
||||||
import { Crisp } from 'crisp-sdk-web'
|
|
||||||
import { ApiUser } from '@/features/auth/api/ApiUser'
|
|
||||||
|
|
||||||
export const initializeSupportSession = (user: ApiUser) => {
|
|
||||||
if (!Crisp.isCrispInjected()) return
|
|
||||||
const { id, email } = user
|
|
||||||
Crisp.setTokenId(`meet-${id}`)
|
|
||||||
Crisp.user.setEmail(email)
|
|
||||||
}
|
|
||||||
|
|
||||||
export const terminateSupportSession = () => {
|
|
||||||
if (!Crisp.isCrispInjected()) return
|
|
||||||
Crisp.setTokenId()
|
|
||||||
Crisp.session.reset()
|
|
||||||
}
|
|
||||||
|
|
||||||
export type useSupportProps = {
|
|
||||||
id?: string
|
|
||||||
}
|
|
||||||
|
|
||||||
// Configure Crisp chat for real-time support across all pages.
|
|
||||||
export const useSupport = ({ id }: useSupportProps) => {
|
|
||||||
useEffect(() => {
|
|
||||||
if (!id || Crisp.isCrispInjected()) return
|
|
||||||
Crisp.configure(id)
|
|
||||||
Crisp.setHideOnMobile(true)
|
|
||||||
}, [id])
|
|
||||||
|
|
||||||
return null
|
|
||||||
}
|
|
||||||
@@ -2,16 +2,13 @@ import { Link } from 'wouter'
|
|||||||
import { css } from '@/styled-system/css'
|
import { css } from '@/styled-system/css'
|
||||||
import { Stack } from '@/styled-system/jsx'
|
import { Stack } from '@/styled-system/jsx'
|
||||||
import { useTranslation } from 'react-i18next'
|
import { useTranslation } from 'react-i18next'
|
||||||
import { Text, Button } from '@/primitives'
|
import { A, Text, Button } from '@/primitives'
|
||||||
import { SettingsButton } from '@/features/settings'
|
import { SettingsButton } from '@/features/settings'
|
||||||
import { logoutUrl, useUser } from '@/features/auth'
|
import { authUrl, logoutUrl, useUser } from '@/features/auth'
|
||||||
import { useMatchesRoute } from '@/navigation/useMatchesRoute'
|
import { useMatchesRoute } from '@/navigation/useMatchesRoute'
|
||||||
import { Feedback } from '@/components/Feedback'
|
import { Feedback } from '@/components/Feedback'
|
||||||
import { Menu } from '@/primitives/Menu'
|
import { Menu } from '@/primitives/Menu'
|
||||||
import { MenuList } from '@/primitives/MenuList'
|
import { MenuList } from '@/primitives/MenuList'
|
||||||
import { ProConnectButton } from '@/components/ProConnectButton'
|
|
||||||
import { terminateAnalyticsSession } from '@/features/analytics/hooks/useAnalytics'
|
|
||||||
import { terminateSupportSession } from '@/features/support/hooks/useSupport'
|
|
||||||
|
|
||||||
export const Header = () => {
|
export const Header = () => {
|
||||||
const { t } = useTranslation()
|
const { t } = useTranslation()
|
||||||
@@ -66,7 +63,7 @@ export const Header = () => {
|
|||||||
<nav>
|
<nav>
|
||||||
<Stack gap={1} direction="row" align="center">
|
<Stack gap={1} direction="row" align="center">
|
||||||
{isLoggedIn === false && !isHome && (
|
{isLoggedIn === false && !isHome && (
|
||||||
<ProConnectButton hint={false} />
|
<A href={authUrl()}>{t('login')}</A>
|
||||||
)}
|
)}
|
||||||
{!!user && (
|
{!!user && (
|
||||||
<Menu>
|
<Menu>
|
||||||
@@ -82,8 +79,6 @@ export const Header = () => {
|
|||||||
items={[{ value: 'logout', label: t('logout') }]}
|
items={[{ value: 'logout', label: t('logout') }]}
|
||||||
onAction={(value) => {
|
onAction={(value) => {
|
||||||
if (value === 'logout') {
|
if (value === 'logout') {
|
||||||
terminateAnalyticsSession()
|
|
||||||
terminateSupportSession()
|
|
||||||
window.location.href = logoutUrl()
|
window.location.href = logoutUrl()
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
{
|
{
|
||||||
"app": "Visio",
|
"app": "Meet",
|
||||||
"backToHome": "",
|
"backToHome": "",
|
||||||
"cancel": "",
|
"cancel": "",
|
||||||
"closeDialog": "",
|
"closeDialog": "",
|
||||||
@@ -12,11 +12,7 @@
|
|||||||
},
|
},
|
||||||
"loading": "",
|
"loading": "",
|
||||||
"loggedInUserTooltip": "",
|
"loggedInUserTooltip": "",
|
||||||
"login": {
|
"login": "Anmelden",
|
||||||
"buttonLabel": "",
|
|
||||||
"linkLabel": "",
|
|
||||||
"link": ""
|
|
||||||
},
|
|
||||||
"logout": "",
|
"logout": "",
|
||||||
"notFound": {
|
"notFound": {
|
||||||
"heading": ""
|
"heading": ""
|
||||||
|
|||||||
@@ -4,27 +4,11 @@
|
|||||||
"heading": ""
|
"heading": ""
|
||||||
},
|
},
|
||||||
"join": {
|
"join": {
|
||||||
"videoinput": {
|
"camlabel": "",
|
||||||
"choose": "",
|
|
||||||
"disable": "",
|
|
||||||
"enable": "",
|
|
||||||
"label": "",
|
|
||||||
"placeholder": ""
|
|
||||||
},
|
|
||||||
"audioinput": {
|
|
||||||
"choose": "",
|
|
||||||
"disable": "",
|
|
||||||
"enable": "",
|
|
||||||
"label": ""
|
|
||||||
},
|
|
||||||
"heading": "",
|
"heading": "",
|
||||||
"joinLabel": "",
|
"joinLabel": "",
|
||||||
"joinMeeting": "",
|
"micLabel": "",
|
||||||
"toggleOff": "",
|
"userLabel": ""
|
||||||
"toggleOn": "",
|
|
||||||
"userLabel": "",
|
|
||||||
"usernameHint": "",
|
|
||||||
"usernameLabel": ""
|
|
||||||
},
|
},
|
||||||
"leaveRoomPrompt": "",
|
"leaveRoomPrompt": "",
|
||||||
"shareDialog": {
|
"shareDialog": {
|
||||||
@@ -53,10 +37,6 @@
|
|||||||
"raise": "",
|
"raise": "",
|
||||||
"lower": ""
|
"lower": ""
|
||||||
},
|
},
|
||||||
"screenShare": {
|
|
||||||
"start": "",
|
|
||||||
"stop": ""
|
|
||||||
},
|
|
||||||
"leave": "",
|
"leave": "",
|
||||||
"participants": {
|
"participants": {
|
||||||
"open": "",
|
"open": "",
|
||||||
@@ -69,35 +49,13 @@
|
|||||||
"feedbacks": "",
|
"feedbacks": "",
|
||||||
"support": "",
|
"support": "",
|
||||||
"settings": "",
|
"settings": "",
|
||||||
"username": "",
|
"username": ""
|
||||||
"effects": ""
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"effects": {
|
|
||||||
"activateCamera": "",
|
|
||||||
"notAvailable": "",
|
|
||||||
"heading": "",
|
|
||||||
"blur": {
|
|
||||||
"light": "",
|
|
||||||
"normal": "",
|
|
||||||
"apply": "",
|
|
||||||
"clear": ""
|
|
||||||
},
|
|
||||||
"experimental": ""
|
|
||||||
},
|
|
||||||
"sidePanel": {
|
|
||||||
"heading": {
|
|
||||||
"participants": "",
|
|
||||||
"effects": ""
|
|
||||||
},
|
|
||||||
"content": {
|
|
||||||
"participants": "",
|
|
||||||
"effects": ""
|
|
||||||
},
|
|
||||||
"closeButton": ""
|
|
||||||
},
|
|
||||||
"participants": {
|
"participants": {
|
||||||
|
"heading": "",
|
||||||
"subheading": "",
|
"subheading": "",
|
||||||
|
"closeButton": "",
|
||||||
"contributors": "",
|
"contributors": "",
|
||||||
"collapsable": {
|
"collapsable": {
|
||||||
"open": "",
|
"open": "",
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
{
|
{
|
||||||
"app": "Visio",
|
"app": "Meet",
|
||||||
"backToHome": "Back to homescreen",
|
"backToHome": "Back to homescreen",
|
||||||
"cancel": "Cancel",
|
"cancel": "Cancel",
|
||||||
"closeDialog": "Close dialog",
|
"closeDialog": "Close dialog",
|
||||||
"error": {
|
"error": {
|
||||||
"heading": "An error occurred while loading the page"
|
"heading": "An error occured while loading the page"
|
||||||
},
|
},
|
||||||
"feedbackAlert": "Give us feedback",
|
"feedbackAlert": "Give us feedback",
|
||||||
"forbidden": {
|
"forbidden": {
|
||||||
@@ -12,11 +12,7 @@
|
|||||||
},
|
},
|
||||||
"loading": "Loading…",
|
"loading": "Loading…",
|
||||||
"loggedInUserTooltip": "Logged in as…",
|
"loggedInUserTooltip": "Logged in as…",
|
||||||
"login": {
|
"login": "Login",
|
||||||
"buttonLabel": "Login with ProConnect",
|
|
||||||
"linkLabel": "What is ProConnect? - new tab",
|
|
||||||
"link": "What is ProConnect?"
|
|
||||||
},
|
|
||||||
"logout": "Logout",
|
"logout": "Logout",
|
||||||
"notFound": {
|
"notFound": {
|
||||||
"heading": "Page not found"
|
"heading": "Page not found"
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"createMeeting": "Create a meeting",
|
"createMeeting": "Create a meeting",
|
||||||
"heading": "Welcome in Visio",
|
"heading": "Welcome in Meet",
|
||||||
"intro": "Work easily, from anywhere.",
|
"intro": "Work easily, from anywhere.",
|
||||||
"joinInputError": "Use a meeting link or code. Examples:",
|
"joinInputError": "Use a meeting link or code. Examples:",
|
||||||
"joinInputExample": "URL or 10-letter code",
|
"joinInputExample": "URL or 10-letter code",
|
||||||
|
|||||||
@@ -1,30 +1,14 @@
|
|||||||
{
|
{
|
||||||
"feedback": {
|
"feedback": {
|
||||||
"body": "Please fill out the form available in the header to give us your precious feedback! Thanks.",
|
"body": "Please fill out the form available in the header to give us your precious feedback! Thanks.",
|
||||||
"heading": "Help us improve Visio"
|
"heading": "Help us improve Meet"
|
||||||
},
|
},
|
||||||
"join": {
|
"join": {
|
||||||
"videoinput": {
|
"camlabel": "Camera",
|
||||||
"choose": "Select camera",
|
"heading": "Join the meeting",
|
||||||
"disable": "Disable camera",
|
|
||||||
"enable": "Enable camera",
|
|
||||||
"label": "Camera",
|
|
||||||
"placeholder": "Enable camera to see the preview"
|
|
||||||
},
|
|
||||||
"audioinput": {
|
|
||||||
"choose": "Select microphone",
|
|
||||||
"disable": "Disable microphone",
|
|
||||||
"enable": "Enable microphone",
|
|
||||||
"label": "Microphone"
|
|
||||||
},
|
|
||||||
"heading": "Verify your settings",
|
|
||||||
"joinLabel": "Join",
|
"joinLabel": "Join",
|
||||||
"joinMeeting": "Join meeting",
|
"micLabel": "Microphone",
|
||||||
"toggleOff": "Click to turn off",
|
"userLabel": "Your name"
|
||||||
"toggleOn": "Click to turn on",
|
|
||||||
"userLabel": "",
|
|
||||||
"usernameHint": "Shown to other participants",
|
|
||||||
"usernameLabel": "Your name"
|
|
||||||
},
|
},
|
||||||
"leaveRoomPrompt": "This will make you leave the meeting.",
|
"leaveRoomPrompt": "This will make you leave the meeting.",
|
||||||
"shareDialog": {
|
"shareDialog": {
|
||||||
@@ -43,6 +27,8 @@
|
|||||||
"controls": {
|
"controls": {
|
||||||
"microphone": "Microphone",
|
"microphone": "Microphone",
|
||||||
"camera": "Camera",
|
"camera": "Camera",
|
||||||
|
"shareScreen": "Share screen",
|
||||||
|
"stopScreenShare": "Stop screen share",
|
||||||
"chat": {
|
"chat": {
|
||||||
"open": "Close the chat",
|
"open": "Close the chat",
|
||||||
"closed": "Open the chat"
|
"closed": "Open the chat"
|
||||||
@@ -51,10 +37,6 @@
|
|||||||
"raise": "Raise hand",
|
"raise": "Raise hand",
|
||||||
"lower": "Lower hand"
|
"lower": "Lower hand"
|
||||||
},
|
},
|
||||||
"screenShare": {
|
|
||||||
"start": "Share screen",
|
|
||||||
"stop": "Stop screen share"
|
|
||||||
},
|
|
||||||
"leave": "Leave",
|
"leave": "Leave",
|
||||||
"participants": {
|
"participants": {
|
||||||
"open": "Hide everyone",
|
"open": "Hide everyone",
|
||||||
@@ -67,35 +49,13 @@
|
|||||||
"feedbacks": "Give us feedbacks",
|
"feedbacks": "Give us feedbacks",
|
||||||
"support": "Get Help on Tchap",
|
"support": "Get Help on Tchap",
|
||||||
"settings": "Settings",
|
"settings": "Settings",
|
||||||
"username": "Update Your Name",
|
"username": "Update Your Name"
|
||||||
"effects": "Apply effects"
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"effects": {
|
|
||||||
"activateCamera": "Your camera is disabled. Choose an option to enable it.",
|
|
||||||
"notAvailable": "The blur effect will be available soon on your browser. We're working on it! In the meantime, you can use Google Chrome :(",
|
|
||||||
"heading": "Blur",
|
|
||||||
"blur": {
|
|
||||||
"light": "Light blur",
|
|
||||||
"normal": "Blur",
|
|
||||||
"apply": "Enable blur",
|
|
||||||
"clear": "Disable blur"
|
|
||||||
},
|
|
||||||
"experimental": "Experimental feature. A v2 is coming for full browser support and improved quality."
|
|
||||||
},
|
|
||||||
"sidePanel": {
|
|
||||||
"heading": {
|
|
||||||
"participants": "Participants",
|
|
||||||
"effects": "Effects"
|
|
||||||
},
|
|
||||||
"content": {
|
|
||||||
"participants": "participants",
|
|
||||||
"effects": "effects"
|
|
||||||
},
|
|
||||||
"closeButton": "Hide {{content}}"
|
|
||||||
},
|
|
||||||
"participants": {
|
"participants": {
|
||||||
|
"heading": "Participants",
|
||||||
"subheading": "In room",
|
"subheading": "In room",
|
||||||
|
"closeButton": "Hide participants",
|
||||||
"you": "You",
|
"you": "You",
|
||||||
"contributors": "Contributors",
|
"contributors": "Contributors",
|
||||||
"collapsable": {
|
"collapsable": {
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
"currentlyLoggedAs": "You are currently logged in as <0>{{user}}</0>",
|
"currentlyLoggedAs": "You are currently logged in as <0>{{user}}</0>",
|
||||||
"heading": "Account",
|
"heading": "Account",
|
||||||
"youAreNotLoggedIn": "You are not logged in.",
|
"youAreNotLoggedIn": "You are not logged in.",
|
||||||
"nameLabel": "Your Name",
|
"nameLabel": "Votre Nom",
|
||||||
"authentication": "Authentication"
|
"authentication": "Authentication"
|
||||||
},
|
},
|
||||||
"audio": {
|
"audio": {
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
{
|
{
|
||||||
"app": "Visio",
|
"app": "Meet",
|
||||||
"backToHome": "Retour à l'accueil",
|
"backToHome": "Retour à l'accueil",
|
||||||
"cancel": "Annuler",
|
"cancel": "Annuler",
|
||||||
"closeDialog": "Fermer la fenêtre modale",
|
"closeDialog": "Fermer la fenêtre modale",
|
||||||
@@ -12,11 +12,7 @@
|
|||||||
},
|
},
|
||||||
"loading": "Chargement…",
|
"loading": "Chargement…",
|
||||||
"loggedInUserTooltip": "Connecté en tant que…",
|
"loggedInUserTooltip": "Connecté en tant que…",
|
||||||
"login": {
|
"login": "Se connecter",
|
||||||
"buttonLabel": "S'identifier avec ProConnect",
|
|
||||||
"linkLabel": "Qu'est-ce que ProConnect ? - nouvelle fenêtre",
|
|
||||||
"link": "Qu'est-ce que ProConnect ?"
|
|
||||||
},
|
|
||||||
"logout": "Se déconnecter",
|
"logout": "Se déconnecter",
|
||||||
"notFound": {
|
"notFound": {
|
||||||
"heading": "Page introuvable"
|
"heading": "Page introuvable"
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"createMeeting": "Créer une réunion",
|
"createMeeting": "Créer une réunion",
|
||||||
"heading": "Visio",
|
"heading": "Meet",
|
||||||
"intro": "Collaborez en toute simplicité, où que vous soyez.",
|
"intro": "Collaborez en toute simplicité, où que vous soyez.",
|
||||||
"joinInputError": "Saisissez un lien ou un code de réunion. Exemples :",
|
"joinInputError": "Saisissez un lien ou un code de réunion. Exemples :",
|
||||||
"joinInputExample": "Un code de réunion ressemble à ceci : abc-defg-hij",
|
"joinInputExample": "Un code de réunion ressemble à ceci : abc-defg-hij",
|
||||||
|
|||||||
@@ -1,30 +1,14 @@
|
|||||||
{
|
{
|
||||||
"feedback": {
|
"feedback": {
|
||||||
"body": "Remplissez le formulaire disponible dans l'entête du site pour nous donner votre avis sur l'outil. Vos retours sont précieux ! Merci.",
|
"body": "Remplissez le formulaire disponible dans l'entête du site pour nous donner votre avis sur l'outil. Vos retours sont précieux ! Merci.",
|
||||||
"heading": "Aidez-nous à améliorer Visio"
|
"heading": "Aidez-nous à améliorer Meet"
|
||||||
},
|
},
|
||||||
"join": {
|
"join": {
|
||||||
"videoinput": {
|
"camlabel": "Webcam",
|
||||||
"choose": "Choisir la webcam",
|
"heading": "Rejoindre la réunion",
|
||||||
"disable": "Désactiver la webcam",
|
|
||||||
"enable": "Activer la webcam",
|
|
||||||
"label": "Webcam",
|
|
||||||
"placeholder": "Activez la webcam pour prévisualiser l'affichage"
|
|
||||||
},
|
|
||||||
"audioinput": {
|
|
||||||
"choose": "Choisir le micro",
|
|
||||||
"disable": "Désactiver le micro",
|
|
||||||
"enable": "Activer le micro",
|
|
||||||
"label": "Microphone"
|
|
||||||
},
|
|
||||||
"heading": "Vérifiez vos paramètres",
|
|
||||||
"joinLabel": "Rejoindre",
|
"joinLabel": "Rejoindre",
|
||||||
"joinMeeting": "Rejoindre la réjoindre",
|
"micLabel": "Micro",
|
||||||
"toggleOff": "Cliquez pour désactiver",
|
"userLabel": "Votre nom"
|
||||||
"toggleOn": "Cliquez pour activer",
|
|
||||||
"userLabel": "",
|
|
||||||
"usernameHint": "Affiché aux autres participants",
|
|
||||||
"usernameLabel": "Votre nom"
|
|
||||||
},
|
},
|
||||||
"leaveRoomPrompt": "Revenir à l'accueil vous fera quitter la réunion.",
|
"leaveRoomPrompt": "Revenir à l'accueil vous fera quitter la réunion.",
|
||||||
"shareDialog": {
|
"shareDialog": {
|
||||||
@@ -43,6 +27,8 @@
|
|||||||
"controls": {
|
"controls": {
|
||||||
"microphone": "Microphone",
|
"microphone": "Microphone",
|
||||||
"camera": "Camera",
|
"camera": "Camera",
|
||||||
|
"shareScreen": "Partager l'écran",
|
||||||
|
"stopScreenShare": "Arrêter le partage",
|
||||||
"chat": {
|
"chat": {
|
||||||
"open": "Masquer le chat",
|
"open": "Masquer le chat",
|
||||||
"closed": "Afficher le chat"
|
"closed": "Afficher le chat"
|
||||||
@@ -51,10 +37,6 @@
|
|||||||
"raise": "Lever la main",
|
"raise": "Lever la main",
|
||||||
"lower": "Baisser la main"
|
"lower": "Baisser la main"
|
||||||
},
|
},
|
||||||
"screenShare": {
|
|
||||||
"start": "Partager l'écran",
|
|
||||||
"stop": "Arrêter le partage"
|
|
||||||
},
|
|
||||||
"leave": "Quitter",
|
"leave": "Quitter",
|
||||||
"participants": {
|
"participants": {
|
||||||
"open": "Masquer les participants",
|
"open": "Masquer les participants",
|
||||||
@@ -67,35 +49,13 @@
|
|||||||
"feedbacks": "Partager votre avis",
|
"feedbacks": "Partager votre avis",
|
||||||
"support": "Obtenir de l'aide sur Tchap",
|
"support": "Obtenir de l'aide sur Tchap",
|
||||||
"settings": "Paramètres",
|
"settings": "Paramètres",
|
||||||
"username": "Choisir votre nom",
|
"username": "Choisir votre nom"
|
||||||
"effects": "Appliquer des effets"
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"effects": {
|
|
||||||
"activateCamera": "Votre camera est désactivée. Choisissez une option pour l'activer.",
|
|
||||||
"notAvailable": "L'effet de flou sera bientôt disponible sur votre navigateur. Nous y travaillons ! En attendant, vous pouvez utiliser Google Chrome :(",
|
|
||||||
"heading": "Flou",
|
|
||||||
"blur": {
|
|
||||||
"light": "Léger flou",
|
|
||||||
"normal": "Flou",
|
|
||||||
"apply": "Appliquer le flou",
|
|
||||||
"clear": "Désactiver le flou"
|
|
||||||
},
|
|
||||||
"experimental": "Fonctionnalité expérimentale. Une v2 arrive pour un support complet sur tous les navigateurs et une meilleur qualité."
|
|
||||||
},
|
|
||||||
"sidePanel": {
|
|
||||||
"heading": {
|
|
||||||
"participants": "Participants",
|
|
||||||
"effects": "Effets"
|
|
||||||
},
|
|
||||||
"content": {
|
|
||||||
"participants": "les participants",
|
|
||||||
"effects": "les effets"
|
|
||||||
},
|
|
||||||
"closeButton": "Masquer {{content}}"
|
|
||||||
},
|
|
||||||
"participants": {
|
"participants": {
|
||||||
|
"heading": "Participants",
|
||||||
"subheading": "Dans la réunion",
|
"subheading": "Dans la réunion",
|
||||||
|
"closeButton": "Masquer les participants",
|
||||||
"you": "Vous",
|
"you": "Vous",
|
||||||
"contributors": "Contributeurs",
|
"contributors": "Contributeurs",
|
||||||
"collapsable": {
|
"collapsable": {
|
||||||
|
|||||||
@@ -134,11 +134,10 @@ export const Checkbox = ({
|
|||||||
>
|
>
|
||||||
<StyledCheckbox {...props}>
|
<StyledCheckbox {...props}>
|
||||||
{(renderProps) => {
|
{(renderProps) => {
|
||||||
if (renderProps.isInvalid && !!props.validate) {
|
renderProps.isInvalid && !!props.validate
|
||||||
setError(props.validate(renderProps.isSelected))
|
? setError(props.validate(renderProps.isSelected))
|
||||||
} else {
|
: setError(null)
|
||||||
setError(null)
|
|
||||||
}
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<div className="mt-Checkbox-checkbox">
|
<div className="mt-Checkbox-checkbox">
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ export const MenuList = <T extends string | number = string>({
|
|||||||
const label = typeof item === 'string' ? item : item.label
|
const label = typeof item === 'string' ? item : item.label
|
||||||
return (
|
return (
|
||||||
<MenuItem
|
<MenuItem
|
||||||
className={menuItemRecipe({ extraPadding: true })}
|
className={menuItemRecipe()}
|
||||||
key={value}
|
key={value}
|
||||||
id={value as string}
|
id={value as string}
|
||||||
onAction={() => {
|
onAction={() => {
|
||||||
|
|||||||
@@ -1,10 +0,0 @@
|
|||||||
import { styled } from '@/styled-system/jsx'
|
|
||||||
import { Separator as RACSeparator } from 'react-aria-components'
|
|
||||||
|
|
||||||
export const Separator = styled(RACSeparator, {
|
|
||||||
base: {
|
|
||||||
height: '1px',
|
|
||||||
background: 'gray.400',
|
|
||||||
margin: '4px 0',
|
|
||||||
},
|
|
||||||
})
|
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
import { proxy } from 'valtio'
|
||||||
|
|
||||||
|
type State = {
|
||||||
|
egressId: string | undefined
|
||||||
|
}
|
||||||
|
|
||||||
|
export const egressStore = proxy<State>({
|
||||||
|
egressId: undefined,
|
||||||
|
})
|
||||||
@@ -2,10 +2,8 @@ import { proxy } from 'valtio'
|
|||||||
|
|
||||||
type State = {
|
type State = {
|
||||||
showHeader: boolean
|
showHeader: boolean
|
||||||
sidePanel: 'participants' | 'effects' | null
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export const layoutStore = proxy<State>({
|
export const layoutStore = proxy<State>({
|
||||||
showHeader: false,
|
showHeader: false,
|
||||||
sidePanel: null,
|
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -0,0 +1,9 @@
|
|||||||
|
import { proxy } from 'valtio'
|
||||||
|
|
||||||
|
type State = {
|
||||||
|
showParticipants: boolean
|
||||||
|
}
|
||||||
|
|
||||||
|
export const participantsStore = proxy<State>({
|
||||||
|
showParticipants: false,
|
||||||
|
})
|
||||||
@@ -18,74 +18,65 @@ sops:
|
|||||||
- recipient: age15fyxdwmg5mvldtqqus87xspuws2u0cpvwheehrtvkexj4tnsqqysw6re2x
|
- recipient: age15fyxdwmg5mvldtqqus87xspuws2u0cpvwheehrtvkexj4tnsqqysw6re2x
|
||||||
enc: |
|
enc: |
|
||||||
-----BEGIN AGE ENCRYPTED FILE-----
|
-----BEGIN AGE ENCRYPTED FILE-----
|
||||||
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBCQnRJY0xWNFVRYkR0QTND
|
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBwZG8rTjAzcVNtVHdLZmJI
|
||||||
Rkc5dDRITUpRMW1EVlhEUk9xN0ttbElrdEJvClBMVnVKMXhGMThTcTVaN0s3OG1v
|
Mm4vemNrV1dDUExEZ1R1UGJmWjN3aWw1VXc0CjF1MVhhUTV6ckl1OEFNSjBJUCta
|
||||||
S0U2UUNYZ3FzcXUwVXRyS1hPZkpxcmsKLS0tIHhWei9KVmxFaXgzRUxmMWU2RmhG
|
MTE3QU04RDJKMWlWcHhDSG1NTmZyTkEKLS0tIHh5UHRqckUxZWZLUDl4d3FDdHJs
|
||||||
Y1ZQekpQS3poSWxHZXUvbitlc2lIczAKjLZlgUSz51W4GHirUn352eFPSxIK1/Wf
|
Y0VMc0llMytmMWNUOW56d3ltTHpwZ2cKEHkn6wuHNeMTk+E6nEMpEJZ6wpdXSi3k
|
||||||
N+kzoUvMLmwwfHDztFFYLOEE9x1zx7GoPGG7fN9bTG7GWgcRdd7NUw==
|
FkzXRa6SudAgA4R6K9EieHKPdiNvi0IsCJOhLpiNQtENu9poF5ozqQ==
|
||||||
-----END AGE ENCRYPTED FILE-----
|
-----END AGE ENCRYPTED FILE-----
|
||||||
- recipient: age16hnlml8yv4ynwy0seer57g8qww075crd0g7nsundz3pj4wk7m3vqftszg7
|
- recipient: age16hnlml8yv4ynwy0seer57g8qww075crd0g7nsundz3pj4wk7m3vqftszg7
|
||||||
enc: |
|
enc: |
|
||||||
-----BEGIN AGE ENCRYPTED FILE-----
|
-----BEGIN AGE ENCRYPTED FILE-----
|
||||||
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSA3aTVDMDNUUFFVQlE3Ykpl
|
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSAva3lFTTM2ZUJpcnozNmJt
|
||||||
ZlFQUHQ0UUdlTU54WlEvanBWeGVlYnd1aEZFClQ3Y1ZSOHp6QUt1UXBLV3NWaGJ4
|
ZHAvRndkSjRCVEZYN29wMWFZVmV5ekNiYW5FCkI3RWUvVTdVZ2dJeWVSY085SW5G
|
||||||
T2ZwKzZXcXh1Z2llQk9SN1RRLzNOdGcKLS0tIHN0YTFpL05SQUc1WTRsQ2Z0ZGtu
|
UWNOempRQlFCUUlmL0RIR1ZZZVI5cDQKLS0tIEpwZkVodENLM1VnQ1o1TmhRSFFi
|
||||||
ZjhoUHhFbkMvRUhscy9LY05xbXFZVlEKXrt6UPLOprcnsTFX1WCF/pIWXmjiPGEx
|
ZEF5MUNVdHRKcW9aK0M2M0ZVNDBxbjgKw8Wp06PcoStrO6ppsOR5zWjXbYrP64Dv
|
||||||
7NNbnAl+A9yfheCeiJdWcj5ZBCa6Nx2udVMNjQ7ITMzhIY4BBSicuQ==
|
XAEHQMa7vyvuu12YIa/fpyDM4HrsrPq3OWudxuWS6p0X8xmPYrXm6g==
|
||||||
-----END AGE ENCRYPTED FILE-----
|
-----END AGE ENCRYPTED FILE-----
|
||||||
- recipient: age1plkp8td6zzfcavjusmsfrlk54t9vn8jjxm8zaz7cmnr7kzl2nfnsd54hwg
|
- recipient: age1plkp8td6zzfcavjusmsfrlk54t9vn8jjxm8zaz7cmnr7kzl2nfnsd54hwg
|
||||||
enc: |
|
enc: |
|
||||||
-----BEGIN AGE ENCRYPTED FILE-----
|
-----BEGIN AGE ENCRYPTED FILE-----
|
||||||
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSA1Y3JyU3JPOWdiamd0cEFV
|
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSB1OU9mZHZFanpTQjE3aGly
|
||||||
UWRUdUQ5V3ZnQXQ0YURLZ3RiY0toN29vNkhJCnIzYWdkV3puVWQ5Nm5SVGpobllB
|
VVZDWFh5ZmRHV1YwWUtsZVd6R090SnkxVVNVCmM1UWwwaFlqTHlhSGFRblZBbVhl
|
||||||
OW5WWkVLaE55eUs2OWNDWkZiOGNuZW8KLS0tIHN3eGVST1BRMU1JRWNRZGNJeGdi
|
aEhtWWp1N1lVTDNqOFJBL0swVFl3Y3cKLS0tIG5ZTHAveFdLdGhQeUc2Tzh1d0dw
|
||||||
SWJXQ2VMZ3kyWElBSjBKc0tQWmIwMjgKLDakU3iHwVTQBYGR0d2TFFdLdsct49y1
|
UzRhNGNTZFR3U3BLNFhCdFp6aU5uZVEKL4K5jFjPfMp/fMA8+nQerj6PE5zvGeHW
|
||||||
/S8vydlcx08L0yWHbfamhiYJE3BZbRXZue6z5irBPKEVjGD42aSREw==
|
1SuHwnDiglKmksj8Gy+7spwLQCmo11JCnW2gXKktVIe5XOyhortq3Q==
|
||||||
-----END AGE ENCRYPTED FILE-----
|
-----END AGE ENCRYPTED FILE-----
|
||||||
- recipient: age12g6f5fse25tgrwweleh4jls3qs52hey2edh759smulwmk5lnzadslu2cp3
|
- recipient: age12g6f5fse25tgrwweleh4jls3qs52hey2edh759smulwmk5lnzadslu2cp3
|
||||||
enc: |
|
enc: |
|
||||||
-----BEGIN AGE ENCRYPTED FILE-----
|
-----BEGIN AGE ENCRYPTED FILE-----
|
||||||
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBKUklKTzRzdHZiZjdHSmY2
|
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSB4Z1lXM0tDRzJnMytDZHBV
|
||||||
WCs3ZFVodFBGcDdvZWZaaHNnbG9mdFk2WVJjCjUwZjA2Qi9CR1JYdjJ3VFlhZDZR
|
ZlpCcTg0U3RGeEVzN2dBMkFYa0FBMFVKMWw4Cm5KeWMvdFBRNHFJWFNSS3NVWlNQ
|
||||||
REEyZStrTjIwbWdCdVU5NWo2Y2hBemsKLS0tIFZmWVh0Z1BFUGRjZExMNlNJSFVJ
|
dnhkc2F2MFVTMmVHT2U2STdUWWcvNzAKLS0tIHkzQXltQW5TWHVrektQU1hES1ll
|
||||||
VnlWY3U4dW4ycXJCOVVUUlJxYzVONGsKy47vHe+awhJyI/pSUOhvUiOt+jtn+Vwg
|
UnVld1laTWRmTlkzWHRKRjJmWVJhbU0KANxoSnhDbxsja+Eo8MVCGv6iThNmlo/m
|
||||||
Rlm93bJr0GNVWYm521r/I409s3TMitQerweGnl3u7t1FaKX7oI1qBQ==
|
y0RXVNVqNlqTreT0F/SKmP74W3lF30nwsfrOywMQyu75k8p5MGwUuQ==
|
||||||
-----END AGE ENCRYPTED FILE-----
|
-----END AGE ENCRYPTED FILE-----
|
||||||
- recipient: age1tl80n23wq6zxegupwn70ew0yp225ua5v4dk800x7g2w6pvlxz46qk592pa
|
- recipient: age1tl80n23wq6zxegupwn70ew0yp225ua5v4dk800x7g2w6pvlxz46qk592pa
|
||||||
enc: |
|
enc: |
|
||||||
-----BEGIN AGE ENCRYPTED FILE-----
|
-----BEGIN AGE ENCRYPTED FILE-----
|
||||||
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBVUE9nVk1SMUp5WW9zYnZs
|
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBwUm9oT3RYbGZXaW5CM20r
|
||||||
OFBYWmpwZW56S0J0Qk43dmlCWG5RV0RIKzM0CkVNbzI5VSs3VVdaT2xnVEhGdW9h
|
QlYyeGZjMG05MFNzdndCU2dUemZqdXF5Um1FCkZWdVlubW1MZ3NwM3V2S3dQRFA1
|
||||||
QW02K0ZmeGxsSDZMTGdETjkwd2xVd2MKLS0tIHp2WWQyUFphMmlZaDBZR0JQZ095
|
cHVvOXBMMGtMdkF4T2s3Wk9wYkJUZUEKLS0tIFBRM3FWYTRrVDNwZStwQWlpbEYx
|
||||||
UTVaYXl6SkZUNElUdUlZcU8rditFd3cK0CqMiDzEItfB/T0K8YEncp9HuKWVTy7q
|
dXA5WE5udnhhMVdLTk1jMzJuU3VWaTQKaxTpyqi5fjmOFR4qOxm+wSqWDxb/96QI
|
||||||
2LgHBQJi35sdBviEpsHZt7BlHTKanbmB5S9oUexNq+3wUP9e1n5CGA==
|
rHGUI+CqMVKZ6w1fMH0uanvCuw7Q9rbmsKB+DsjARMLFGqxzP/psUA==
|
||||||
-----END AGE ENCRYPTED FILE-----
|
-----END AGE ENCRYPTED FILE-----
|
||||||
- recipient: age1qy04neuzwpasmvljqrcvhwnf0kz5cpyteze38c8avp0czewskasszv9pyw
|
- recipient: age1qy04neuzwpasmvljqrcvhwnf0kz5cpyteze38c8avp0czewskasszv9pyw
|
||||||
enc: |
|
enc: |
|
||||||
-----BEGIN AGE ENCRYPTED FILE-----
|
-----BEGIN AGE ENCRYPTED FILE-----
|
||||||
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSB0VDdRaEVCemd5T0ozSmtp
|
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBwMmVOaHV1Unl4UmUrVXEy
|
||||||
NllJa0tURVhxTXlZQS8vNUZxbGFQVnhRMDJjClhlaE53WTRpeEtVSGErYUdyZk1h
|
REJIYWZhQmt3R0R5RFRveTl4Z0JaZlpKNmd3Ckl0dkFUaG90TE5odVh0YVprMVZj
|
||||||
SloxZGNUdFRDZ1J4bzdneFUyNXdXdkUKLS0tIGdxU3RCUEVmcTdnZnFidkROdXJS
|
T2tXS0dSRGVVczdhb1dlVlV0L3JZUncKLS0tIGo2RDBPZXNzU2dQQlJhY0NBS2ps
|
||||||
dVdQUUdVUUhpVVh6SytRV1V0RHV6cDQKagJA6w43n8yh119PrJltPPh/EbHIKjfH
|
RW92OFVTS3d2L3UxOXNrVUFSVFI5TXMKn3pdHbXxBccG6Q+gWPVQK/5wiIKkzdhm
|
||||||
G8RfgXBrf5iWdWsyD8haDL6WsjdbVQsbPCz+ucULfnZ1Dn8A/3yQUQ==
|
HiNzezStrkFHf/lsFS2LNgYkfMMzBQ4rJj7oQkrD1Z8j6qRld3zzLg==
|
||||||
-----END AGE ENCRYPTED FILE-----
|
-----END AGE ENCRYPTED FILE-----
|
||||||
- recipient: age18fgn6j2vwwswqcpv9xpcehq8mrf9zs2sglwkamp3tzwx8d9jq9jsrskrk9
|
- recipient: age18fgn6j2vwwswqcpv9xpcehq8mrf9zs2sglwkamp3tzwx8d9jq9jsrskrk9
|
||||||
enc: |
|
enc: |
|
||||||
-----BEGIN AGE ENCRYPTED FILE-----
|
-----BEGIN AGE ENCRYPTED FILE-----
|
||||||
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBIbGgxRG5sZHFPZm5OTnZw
|
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSAzeWN4ZE5Ya3RPV2VKRFdv
|
||||||
L21JUnFDOTNZUitYNHJad3FnYkk2aDlQRzM0CnI1NXZDcEtQdjBWaVhJMElIOEZU
|
UGQ4QTJUZFovSXpQREhNWXdQbktVUHFQaUhjCmM1dXNxbGdlVjBWNjc5L2E5QlBy
|
||||||
KzFjT0p4OVpzUFlnR1Q5cm5SVnhGaEUKLS0tIFliVVQ4VFg4QVJxazdyZG9PbE9M
|
NjI0S251cjZvYU1nQ2swWXVDdjdhSG8KLS0tIHdFNXptN1VBNytFNW40MUsxTGFM
|
||||||
M3NzZFRKMFkxZHZ1Rmh0VWFWMDZTQlEKxKVEvnnV56t/RSvP94TgjW1Do68Tn2N2
|
WlVnc3VLY1ZReDFxUVlqWU9rM0xMQ00Kq/ckdP1N4BDBo0pSH9pp36skIacwNm3d
|
||||||
tJMI8VIp7rs5vxaToois6CMuhVONsl1CBozAEV8pqS5O830RGa1eog==
|
utiuCgG16Hqe6YDb3agx81BocuSJ9oMOdpegoztnkkBDDP0F+e/VuQ==
|
||||||
-----END AGE ENCRYPTED FILE-----
|
|
||||||
- recipient: age1hm2hsfgjezpsc3k0y5w5feq9t8vl3seq04qjhgt6ztd6403wfvpsgxu09m
|
|
||||||
enc: |
|
|
||||||
-----BEGIN AGE ENCRYPTED FILE-----
|
|
||||||
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBta3VwOGQrSHdENGZLZUpq
|
|
||||||
SGw0Z2YwYm8vZ0h4Y01UclIrQlRVNWVJaHlRCmFMQkp1aGc5R1JrMVdPNmwvbkYv
|
|
||||||
NkxOc3pYY2E5dVVFejZJaitSb0hRUVUKLS0tIGFzclh3VXhBc3NYQjZlUmNUSk10
|
|
||||||
S2xqMEpBcEpaOHdBNUtvOWxsVUhLLzQKGT3grtnocBkaCKXbtH7cZu/ZP9MKsAjt
|
|
||||||
ZNmS1GahpBx2lVEbfJNLfwId+IJ6kOIyHj42g9yIQFfKTPKE32Ht8A==
|
|
||||||
-----END AGE ENCRYPTED FILE-----
|
-----END AGE ENCRYPTED FILE-----
|
||||||
lastmodified: "2024-07-18T13:08:42Z"
|
lastmodified: "2024-07-18T13:08:42Z"
|
||||||
mac: ENC[AES256_GCM,data:a/uHyw9V/SMIePV9nPf+wJgPg+YDYLJGYy7NMLBrBgCXtBWHHonSNjzdmtjix1bW2y+cU0gMqodrtqR1cJGBmXr4NRY7NJqgLWE9rEdYfG7BnfqsWmvAaTIrSs7QMZWkEic7ys/bXoA5BZoau3olhVqIO2A/iyBtoMU9Hv7hPlo=,iv:gaqSCUbN7cxWPNrFPDTl7xNxpOZL6GY/swD/MDCiRqk=,tag:Oz0f/DyD3KGV/9Rprj/1Xw==,type:str]
|
mac: ENC[AES256_GCM,data:a/uHyw9V/SMIePV9nPf+wJgPg+YDYLJGYy7NMLBrBgCXtBWHHonSNjzdmtjix1bW2y+cU0gMqodrtqR1cJGBmXr4NRY7NJqgLWE9rEdYfG7BnfqsWmvAaTIrSs7QMZWkEic7ys/bXoA5BZoau3olhVqIO2A/iyBtoMU9Hv7hPlo=,iv:gaqSCUbN7cxWPNrFPDTl7xNxpOZL6GY/swD/MDCiRqk=,tag:Oz0f/DyD3KGV/9Rprj/1Xw==,type:str]
|
||||||
|
|||||||
@@ -49,8 +49,6 @@ backend:
|
|||||||
LIVEKIT_API_URL: https://livekit.127.0.0.1.nip.io/
|
LIVEKIT_API_URL: https://livekit.127.0.0.1.nip.io/
|
||||||
ANALYTICS_KEY: xwhoIMCZ8PBRjQ2t
|
ANALYTICS_KEY: xwhoIMCZ8PBRjQ2t
|
||||||
ALLOW_UNREGISTERED_ROOMS: False
|
ALLOW_UNREGISTERED_ROOMS: False
|
||||||
FRONTEND_SILENCE_LIVEKIT_DEBUG: False
|
|
||||||
FRONTEND_SUPPORT: "{'id': '58ea6697-8eba-4492-bc59-ad6562585041'}"
|
|
||||||
|
|
||||||
|
|
||||||
migrate:
|
migrate:
|
||||||
@@ -97,11 +95,3 @@ ingress:
|
|||||||
ingressAdmin:
|
ingressAdmin:
|
||||||
enabled: true
|
enabled: true
|
||||||
host: meet.127.0.0.1.nip.io
|
host: meet.127.0.0.1.nip.io
|
||||||
|
|
||||||
posthog:
|
|
||||||
ingress:
|
|
||||||
enabled: false
|
|
||||||
|
|
||||||
ingressAssets:
|
|
||||||
enabled: false
|
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,127 @@
|
|||||||
|
image:
|
||||||
|
repository: lasuite/meet-backend
|
||||||
|
pullPolicy: Always
|
||||||
|
tag: "v0.1.5"
|
||||||
|
|
||||||
|
backend:
|
||||||
|
migrateJobAnnotations:
|
||||||
|
argocd.argoproj.io/hook: PreSync
|
||||||
|
argocd.argoproj.io/hook-delete-policy: HookSucceeded
|
||||||
|
envVars:
|
||||||
|
DJANGO_CSRF_TRUSTED_ORIGINS: http://meet-preprod.beta.numerique.gouv.fr,https://meet-preprod.beta.numerique.gouv.fr
|
||||||
|
DJANGO_CONFIGURATION: Production
|
||||||
|
DJANGO_ALLOWED_HOSTS: meet-preprod.beta.numerique.gouv.fr
|
||||||
|
DJANGO_SUPERUSER_EMAIL:
|
||||||
|
secretKeyRef:
|
||||||
|
name: backend
|
||||||
|
key: DJANGO_SUPERUSER_EMAIL
|
||||||
|
DJANGO_SECRET_KEY:
|
||||||
|
secretKeyRef:
|
||||||
|
name: backend
|
||||||
|
key: DJANGO_SECRET_KEY
|
||||||
|
DJANGO_SETTINGS_MODULE: meet.settings
|
||||||
|
DJANGO_SILENCED_SYSTEM_CHECKS: security.W004, security.W008
|
||||||
|
DJANGO_SUPERUSER_PASSWORD:
|
||||||
|
secretKeyRef:
|
||||||
|
name: backend
|
||||||
|
key: DJANGO_SUPERUSER_PASSWORD
|
||||||
|
DJANGO_EMAIL_HOST: "snap-mail.numerique.gouv.fr"
|
||||||
|
DJANGO_EMAIL_PORT: 465
|
||||||
|
DJANGO_EMAIL_USE_SSL: True
|
||||||
|
OIDC_OP_JWKS_ENDPOINT: https://fca.integ01.dev-agentconnect.fr/api/v2/jwks
|
||||||
|
OIDC_OP_AUTHORIZATION_ENDPOINT: https://fca.integ01.dev-agentconnect.fr/api/v2/authorize
|
||||||
|
OIDC_OP_TOKEN_ENDPOINT: https://fca.integ01.dev-agentconnect.fr/api/v2/token
|
||||||
|
OIDC_OP_USER_ENDPOINT: https://fca.integ01.dev-agentconnect.fr/api/v2/userinfo
|
||||||
|
OIDC_OP_LOGOUT_ENDPOINT: https://fca.integ01.dev-agentconnect.fr/api/v2/session/end
|
||||||
|
OIDC_RP_CLIENT_ID:
|
||||||
|
secretKeyRef:
|
||||||
|
name: backend
|
||||||
|
key: OIDC_RP_CLIENT_ID
|
||||||
|
OIDC_RP_CLIENT_SECRET:
|
||||||
|
secretKeyRef:
|
||||||
|
name: backend
|
||||||
|
key: OIDC_RP_CLIENT_SECRET
|
||||||
|
OIDC_RP_SIGN_ALGO: RS256
|
||||||
|
OIDC_RP_SCOPES: "openid email"
|
||||||
|
OIDC_REDIRECT_ALLOWED_HOSTS: https://meet-preprod.beta.numerique.gouv.fr
|
||||||
|
OIDC_AUTH_REQUEST_EXTRA_PARAMS: "{'acr_values': 'eidas1'}"
|
||||||
|
LOGIN_REDIRECT_URL: https://meet-preprod.beta.numerique.gouv.fr
|
||||||
|
LOGIN_REDIRECT_URL_FAILURE: https://meet-preprod.beta.numerique.gouv.fr
|
||||||
|
LOGOUT_REDIRECT_URL: https://meet-preprod.beta.numerique.gouv.fr
|
||||||
|
DB_HOST:
|
||||||
|
secretKeyRef:
|
||||||
|
name: postgresql.postgres.libre.sh
|
||||||
|
key: host
|
||||||
|
DB_NAME:
|
||||||
|
secretKeyRef:
|
||||||
|
name: postgresql.postgres.libre.sh
|
||||||
|
key: database
|
||||||
|
DB_USER:
|
||||||
|
secretKeyRef:
|
||||||
|
name: postgresql.postgres.libre.sh
|
||||||
|
key: username
|
||||||
|
DB_PASSWORD:
|
||||||
|
secretKeyRef:
|
||||||
|
name: postgresql.postgres.libre.sh
|
||||||
|
key: password
|
||||||
|
DB_PORT:
|
||||||
|
secretKeyRef:
|
||||||
|
name: postgresql.postgres.libre.sh
|
||||||
|
key: port
|
||||||
|
POSTGRES_USER:
|
||||||
|
secretKeyRef:
|
||||||
|
name: postgresql.postgres.libre.sh
|
||||||
|
key: username
|
||||||
|
POSTGRES_DB:
|
||||||
|
secretKeyRef:
|
||||||
|
name: postgresql.postgres.libre.sh
|
||||||
|
key: database
|
||||||
|
POSTGRES_PASSWORD:
|
||||||
|
secretKeyRef:
|
||||||
|
name: postgresql.postgres.libre.sh
|
||||||
|
key: password
|
||||||
|
REDIS_URL:
|
||||||
|
secretKeyRef:
|
||||||
|
name: redis.redis.libre.sh
|
||||||
|
key: url
|
||||||
|
STORAGES_STATICFILES_BACKEND: django.contrib.staticfiles.storage.StaticFilesStorage
|
||||||
|
LIVEKIT_API_SECRET:
|
||||||
|
secretKeyRef:
|
||||||
|
name: backend
|
||||||
|
key: LIVEKIT_API_SECRET
|
||||||
|
LIVEKIT_API_KEY:
|
||||||
|
secretKeyRef:
|
||||||
|
name: backend
|
||||||
|
key: LIVEKIT_API_KEY
|
||||||
|
LIVEKIT_API_URL: https://livekit-preprod.beta.numerique.gouv.fr
|
||||||
|
ALLOW_UNREGISTERED_ROOMS: False
|
||||||
|
|
||||||
|
createsuperuser:
|
||||||
|
command:
|
||||||
|
- "/bin/sh"
|
||||||
|
- "-c"
|
||||||
|
- |
|
||||||
|
python manage.py createsuperuser --email $DJANGO_SUPERUSER_EMAIL --password $DJANGO_SUPERUSER_PASSWORD
|
||||||
|
restartPolicy: Never
|
||||||
|
|
||||||
|
frontend:
|
||||||
|
image:
|
||||||
|
repository: lasuite/meet-frontend
|
||||||
|
pullPolicy: Always
|
||||||
|
tag: "v0.1.5"
|
||||||
|
|
||||||
|
ingress:
|
||||||
|
enabled: true
|
||||||
|
host: meet-preprod.beta.numerique.gouv.fr
|
||||||
|
className: nginx
|
||||||
|
annotations:
|
||||||
|
cert-manager.io/cluster-issuer: letsencrypt-prod
|
||||||
|
|
||||||
|
ingressAdmin:
|
||||||
|
enabled: true
|
||||||
|
host: meet-preprod.beta.numerique.gouv.fr
|
||||||
|
className: nginx
|
||||||
|
annotations:
|
||||||
|
cert-manager.io/cluster-issuer: letsencrypt-prod
|
||||||
|
nginx.ingress.kubernetes.io/auth-signin: https://oauth2-proxy-preprod.beta.numerique.gouv.fr/oauth2/start
|
||||||
|
nginx.ingress.kubernetes.io/auth-url: https://oauth2-proxy-preprod.beta.numerique.gouv.fr/oauth2/auth
|
||||||
@@ -1,16 +1,16 @@
|
|||||||
image:
|
image:
|
||||||
repository: lasuite/meet-backend
|
repository: lasuite/meet-backend
|
||||||
pullPolicy: Always
|
pullPolicy: Always
|
||||||
tag: "v0.1.7"
|
tag: "v0.1.5"
|
||||||
|
|
||||||
backend:
|
backend:
|
||||||
migrateJobAnnotations:
|
migrateJobAnnotations:
|
||||||
argocd.argoproj.io/hook: PostSync
|
argocd.argoproj.io/hook: PostSync
|
||||||
argocd.argoproj.io/hook-delete-policy: HookSucceeded
|
argocd.argoproj.io/hook-delete-policy: HookSucceeded
|
||||||
envVars:
|
envVars:
|
||||||
DJANGO_CSRF_TRUSTED_ORIGINS: https://visio.numerique.gouv.fr,https://meet.numerique.gouv.fr
|
DJANGO_CSRF_TRUSTED_ORIGINS: https://meet.numerique.gouv.fr
|
||||||
DJANGO_CONFIGURATION: Production
|
DJANGO_CONFIGURATION: Production
|
||||||
DJANGO_ALLOWED_HOSTS: visio.numerique.gouv.fr,meet.numerique.gouv.fr
|
DJANGO_ALLOWED_HOSTS: meet.numerique.gouv.fr
|
||||||
DJANGO_SECRET_KEY:
|
DJANGO_SECRET_KEY:
|
||||||
secretKeyRef:
|
secretKeyRef:
|
||||||
name: backend
|
name: backend
|
||||||
@@ -43,11 +43,11 @@ backend:
|
|||||||
key: OIDC_RP_CLIENT_SECRET
|
key: OIDC_RP_CLIENT_SECRET
|
||||||
OIDC_RP_SIGN_ALGO: RS256
|
OIDC_RP_SIGN_ALGO: RS256
|
||||||
OIDC_RP_SCOPES: "openid email"
|
OIDC_RP_SCOPES: "openid email"
|
||||||
OIDC_REDIRECT_ALLOWED_HOSTS: https://visio.numerique.gouv.fr
|
OIDC_REDIRECT_ALLOWED_HOSTS: https://meet.numerique.gouv.fr
|
||||||
OIDC_AUTH_REQUEST_EXTRA_PARAMS: "{'acr_values': 'eidas1'}"
|
OIDC_AUTH_REQUEST_EXTRA_PARAMS: "{'acr_values': 'eidas1'}"
|
||||||
LOGIN_REDIRECT_URL: https://visio.numerique.gouv.fr
|
LOGIN_REDIRECT_URL: https://meet.numerique.gouv.fr
|
||||||
LOGIN_REDIRECT_URL_FAILURE: https://visio.numerique.gouv.fr
|
LOGIN_REDIRECT_URL_FAILURE: https://meet.numerique.gouv.fr
|
||||||
LOGOUT_REDIRECT_URL: https://visio.numerique.gouv.fr
|
LOGOUT_REDIRECT_URL: https://meet.numerique.gouv.fr
|
||||||
DB_HOST:
|
DB_HOST:
|
||||||
secretKeyRef:
|
secretKeyRef:
|
||||||
name: postgresql.postgres.libre.sh
|
name: postgresql.postgres.libre.sh
|
||||||
@@ -96,9 +96,6 @@ backend:
|
|||||||
LIVEKIT_API_URL: https://livekit-preprod.beta.numerique.gouv.fr
|
LIVEKIT_API_URL: https://livekit-preprod.beta.numerique.gouv.fr
|
||||||
ANALYTICS_KEY: mwuxTKi8o2xzWH54
|
ANALYTICS_KEY: mwuxTKi8o2xzWH54
|
||||||
ALLOW_UNREGISTERED_ROOMS: False
|
ALLOW_UNREGISTERED_ROOMS: False
|
||||||
FRONTEND_SILENCE_LIVEKIT_DEBUG: False
|
|
||||||
FRONTEND_ANALYTICS: "{'id': 'phc_RPYko028Oqtj0c9exLIWwrlrjLxSdxT0ntW0Lam4iom', 'host': 'https://product.visio.numerique.gouv.fr'}"
|
|
||||||
FRONTEND_SUPPORT: "{'id': '58ea6697-8eba-4492-bc59-ad6562585041'}"
|
|
||||||
|
|
||||||
createsuperuser:
|
createsuperuser:
|
||||||
command:
|
command:
|
||||||
@@ -112,39 +109,20 @@ frontend:
|
|||||||
image:
|
image:
|
||||||
repository: lasuite/meet-frontend
|
repository: lasuite/meet-frontend
|
||||||
pullPolicy: Always
|
pullPolicy: Always
|
||||||
tag: "v0.1.7"
|
tag: "v0.1.5"
|
||||||
|
|
||||||
ingress:
|
ingress:
|
||||||
enabled: true
|
enabled: true
|
||||||
host: visio.numerique.gouv.fr
|
host: meet.numerique.gouv.fr
|
||||||
className: nginx
|
className: nginx
|
||||||
annotations:
|
annotations:
|
||||||
cert-manager.io/cluster-issuer: letsencrypt
|
cert-manager.io/cluster-issuer: letsencrypt
|
||||||
|
|
||||||
ingressAdmin:
|
ingressAdmin:
|
||||||
enabled: true
|
enabled: true
|
||||||
host: visio.numerique.gouv.fr
|
host: meet.numerique.gouv.fr
|
||||||
className: nginx
|
className: nginx
|
||||||
annotations:
|
annotations:
|
||||||
cert-manager.io/cluster-issuer: letsencrypt
|
cert-manager.io/cluster-issuer: letsencrypt
|
||||||
nginx.ingress.kubernetes.io/auth-signin: https://oauth2-proxy.beta.numerique.gouv.fr/oauth2/start
|
nginx.ingress.kubernetes.io/auth-signin: https://oauth2-proxy.beta.numerique.gouv.fr/oauth2/start
|
||||||
nginx.ingress.kubernetes.io/auth-url: https://oauth2-proxy.beta.numerique.gouv.fr/oauth2/auth
|
nginx.ingress.kubernetes.io/auth-url: https://oauth2-proxy.beta.numerique.gouv.fr/oauth2/auth
|
||||||
|
|
||||||
posthog:
|
|
||||||
ingress:
|
|
||||||
enabled: true
|
|
||||||
host: product.visio.numerique.gouv.fr
|
|
||||||
className: nginx
|
|
||||||
annotations:
|
|
||||||
cert-manager.io/cluster-issuer: letsencrypt
|
|
||||||
nginx.ingress.kubernetes.io/upstream-vhost: eu.i.posthog.com
|
|
||||||
nginx.ingress.kubernetes.io/backend-protocol: https
|
|
||||||
|
|
||||||
ingressAssets:
|
|
||||||
enabled: true
|
|
||||||
host: product.visio.numerique.gouv.fr
|
|
||||||
className: nginx
|
|
||||||
annotations:
|
|
||||||
cert-manager.io/cluster-issuer: letsencrypt
|
|
||||||
nginx.ingress.kubernetes.io/upstream-vhost: eu-assets.i.posthog.com
|
|
||||||
nginx.ingress.kubernetes.io/backend-protocol: https
|
|
||||||
|
|||||||
@@ -1,16 +1,16 @@
|
|||||||
image:
|
image:
|
||||||
repository: lasuite/meet-backend
|
repository: lasuite/meet-backend
|
||||||
pullPolicy: Always
|
pullPolicy: Always
|
||||||
tag: "main"
|
tag: "hackathon"
|
||||||
|
|
||||||
backend:
|
backend:
|
||||||
migrateJobAnnotations:
|
migrateJobAnnotations:
|
||||||
argocd.argoproj.io/hook: PreSync
|
argocd.argoproj.io/hook: PreSync
|
||||||
argocd.argoproj.io/hook-delete-policy: HookSucceeded
|
argocd.argoproj.io/hook-delete-policy: HookSucceeded
|
||||||
envVars:
|
envVars:
|
||||||
DJANGO_CSRF_TRUSTED_ORIGINS: http://visio-staging.beta.numerique.gouv.fr,https://meet-staging.beta.numerique.gouv.fr
|
DJANGO_CSRF_TRUSTED_ORIGINS: http://meet-staging.beta.numerique.gouv.fr,https://meet-staging.beta.numerique.gouv.fr
|
||||||
DJANGO_CONFIGURATION: Production
|
DJANGO_CONFIGURATION: Production
|
||||||
DJANGO_ALLOWED_HOSTS: visio-staging.beta.numerique.gouv.fr
|
DJANGO_ALLOWED_HOSTS: meet-staging.beta.numerique.gouv.fr
|
||||||
DJANGO_SECRET_KEY:
|
DJANGO_SECRET_KEY:
|
||||||
secretKeyRef:
|
secretKeyRef:
|
||||||
name: backend
|
name: backend
|
||||||
@@ -42,11 +42,11 @@ backend:
|
|||||||
key: OIDC_RP_CLIENT_SECRET
|
key: OIDC_RP_CLIENT_SECRET
|
||||||
OIDC_RP_SIGN_ALGO: RS256
|
OIDC_RP_SIGN_ALGO: RS256
|
||||||
OIDC_RP_SCOPES: "openid email"
|
OIDC_RP_SCOPES: "openid email"
|
||||||
OIDC_REDIRECT_ALLOWED_HOSTS: https://visio-staging.beta.numerique.gouv.fr
|
OIDC_REDIRECT_ALLOWED_HOSTS: https://meet-staging.beta.numerique.gouv.fr
|
||||||
OIDC_AUTH_REQUEST_EXTRA_PARAMS: "{'acr_values': 'eidas1'}"
|
OIDC_AUTH_REQUEST_EXTRA_PARAMS: "{'acr_values': 'eidas1'}"
|
||||||
LOGIN_REDIRECT_URL: https://visio-staging.beta.numerique.gouv.fr
|
LOGIN_REDIRECT_URL: https://meet-staging.beta.numerique.gouv.fr
|
||||||
LOGIN_REDIRECT_URL_FAILURE: https://visio-staging.beta.numerique.gouv.fr
|
LOGIN_REDIRECT_URL_FAILURE: https://meet-staging.beta.numerique.gouv.fr
|
||||||
LOGOUT_REDIRECT_URL: https://visio-staging.beta.numerique.gouv.fr
|
LOGOUT_REDIRECT_URL: https://meet-staging.beta.numerique.gouv.fr
|
||||||
DB_HOST:
|
DB_HOST:
|
||||||
secretKeyRef:
|
secretKeyRef:
|
||||||
name: postgresql.postgres.libre.sh
|
name: postgresql.postgres.libre.sh
|
||||||
@@ -95,8 +95,6 @@ backend:
|
|||||||
LIVEKIT_API_URL: https://livekit-staging.beta.numerique.gouv.fr
|
LIVEKIT_API_URL: https://livekit-staging.beta.numerique.gouv.fr
|
||||||
ANALYTICS_KEY: Roi1k6IAc2DEqHB0
|
ANALYTICS_KEY: Roi1k6IAc2DEqHB0
|
||||||
ALLOW_UNREGISTERED_ROOMS: False
|
ALLOW_UNREGISTERED_ROOMS: False
|
||||||
FRONTEND_ANALYTICS: "{'id': 'phc_RPYko028Oqtj0c9exLIWwrlrjLxSdxT0ntW0Lam4iom', 'host': 'https://product.visio-staging.beta.numerique.gouv.fr'}"
|
|
||||||
FRONTEND_SUPPORT: "{'id': '58ea6697-8eba-4492-bc59-ad6562585041'}"
|
|
||||||
|
|
||||||
createsuperuser:
|
createsuperuser:
|
||||||
command:
|
command:
|
||||||
@@ -110,51 +108,20 @@ frontend:
|
|||||||
image:
|
image:
|
||||||
repository: lasuite/meet-frontend
|
repository: lasuite/meet-frontend
|
||||||
pullPolicy: Always
|
pullPolicy: Always
|
||||||
tag: "main"
|
tag: "hackathon"
|
||||||
|
|
||||||
ingress:
|
ingress:
|
||||||
enabled: true
|
enabled: true
|
||||||
host: visio-staging.beta.numerique.gouv.fr
|
host: meet-staging.beta.numerique.gouv.fr
|
||||||
className: nginx
|
className: nginx
|
||||||
annotations:
|
annotations:
|
||||||
cert-manager.io/cluster-issuer: letsencrypt-prod
|
cert-manager.io/cluster-issuer: letsencrypt-prod
|
||||||
tls:
|
|
||||||
enabled: true
|
|
||||||
additional:
|
|
||||||
- secretName: transitional-tls
|
|
||||||
hosts:
|
|
||||||
- {{ .Values.newDomain }}
|
|
||||||
|
|
||||||
ingressAdmin:
|
ingressAdmin:
|
||||||
enabled: true
|
enabled: true
|
||||||
host: visio-staging.beta.numerique.gouv.fr
|
host: meet-staging.beta.numerique.gouv.fr
|
||||||
className: nginx
|
className: nginx
|
||||||
annotations:
|
annotations:
|
||||||
cert-manager.io/cluster-issuer: letsencrypt-prod
|
cert-manager.io/cluster-issuer: letsencrypt-prod
|
||||||
nginx.ingress.kubernetes.io/auth-signin: https://oauth2-proxy-preprod.beta.numerique.gouv.fr/oauth2/start
|
nginx.ingress.kubernetes.io/auth-signin: https://oauth2-proxy-preprod.beta.numerique.gouv.fr/oauth2/start
|
||||||
nginx.ingress.kubernetes.io/auth-url: https://oauth2-proxy-preprod.beta.numerique.gouv.fr/oauth2/auth
|
nginx.ingress.kubernetes.io/auth-url: https://oauth2-proxy-preprod.beta.numerique.gouv.fr/oauth2/auth
|
||||||
tls:
|
|
||||||
enabled: true
|
|
||||||
additional:
|
|
||||||
- secretName: transitional-tls
|
|
||||||
hosts:
|
|
||||||
- {{ .Values.newDomain }}
|
|
||||||
|
|
||||||
posthog:
|
|
||||||
ingress:
|
|
||||||
enabled: true
|
|
||||||
host: product.visio-staging.beta.numerique.gouv.fr
|
|
||||||
className: nginx
|
|
||||||
annotations:
|
|
||||||
cert-manager.io/cluster-issuer: letsencrypt-prod
|
|
||||||
nginx.ingress.kubernetes.io/upstream-vhost: eu.i.posthog.com
|
|
||||||
nginx.ingress.kubernetes.io/backend-protocol: https
|
|
||||||
|
|
||||||
ingressAssets:
|
|
||||||
enabled: true
|
|
||||||
host: product.visio-staging.beta.numerique.gouv.fr
|
|
||||||
className: nginx
|
|
||||||
annotations:
|
|
||||||
cert-manager.io/cluster-issuer: letsencrypt-prod
|
|
||||||
nginx.ingress.kubernetes.io/upstream-vhost: eu-assets.i.posthog.com
|
|
||||||
nginx.ingress.kubernetes.io/backend-protocol: https
|
|
||||||
|
|||||||
@@ -1,55 +0,0 @@
|
|||||||
{{ if .Values.addRedirect }}
|
|
||||||
apiVersion: networking.k8s.io/v1
|
|
||||||
kind: Ingress
|
|
||||||
metadata:
|
|
||||||
annotations:
|
|
||||||
cert-manager.io/cluster-issuer: letsencrypt-prod
|
|
||||||
{{ if .Values.enablePermanentRedirect }}
|
|
||||||
nginx.ingress.kubernetes.io/permanent-redirect: "https://{{ .Values.newDomain }}$request_uri"
|
|
||||||
nginx.ingress.kubernetes.io/permanent-redirect-code: "308"
|
|
||||||
{{ end }}
|
|
||||||
name: temporary-redirect
|
|
||||||
namespace: {{ .Release.Namespace | quote }}
|
|
||||||
spec:
|
|
||||||
ingressClassName: nginx
|
|
||||||
rules:
|
|
||||||
- host: {{ .Values.oldDomain }}
|
|
||||||
http:
|
|
||||||
paths:
|
|
||||||
- backend:
|
|
||||||
service:
|
|
||||||
name: meet-frontend
|
|
||||||
port:
|
|
||||||
number: 80
|
|
||||||
path: /
|
|
||||||
pathType: Prefix
|
|
||||||
- backend:
|
|
||||||
service:
|
|
||||||
name: meet-backend
|
|
||||||
port:
|
|
||||||
number: 80
|
|
||||||
path: /api
|
|
||||||
pathType: Prefix
|
|
||||||
tls:
|
|
||||||
- hosts:
|
|
||||||
- {{ .Values.oldDomain }}
|
|
||||||
secretName: transitional-tls
|
|
||||||
---
|
|
||||||
apiVersion: cert-manager.io/v1
|
|
||||||
kind: Certificate
|
|
||||||
metadata:
|
|
||||||
name: transitional-tls
|
|
||||||
namespace: {{ .Release.Namespace | quote }}
|
|
||||||
spec:
|
|
||||||
dnsNames:
|
|
||||||
- {{ .Values.newDomain }}
|
|
||||||
- {{ .Values.oldDomain }}
|
|
||||||
issuerRef:
|
|
||||||
group: cert-manager.io
|
|
||||||
kind: ClusterIssuer
|
|
||||||
name: {{ index .Values.ingress.annotations "cert-manager.io/cluster-issuer" }}
|
|
||||||
secretName: transitional-tls
|
|
||||||
usages:
|
|
||||||
- digital signature
|
|
||||||
- key encipherment
|
|
||||||
{{ end }}
|
|
||||||
+22
-31
@@ -1,28 +1,3 @@
|
|||||||
environments:
|
|
||||||
dev:
|
|
||||||
values:
|
|
||||||
- version: 0.0.1
|
|
||||||
secrets:
|
|
||||||
- env.d/{{ .Environment.Name }}/secrets.enc.yaml
|
|
||||||
staging:
|
|
||||||
values:
|
|
||||||
- version: 0.0.1
|
|
||||||
addRedirect: True
|
|
||||||
enablePermanentRedirect: True
|
|
||||||
oldDomain: meet-staging.beta.numerique.gouv.fr
|
|
||||||
newDomain: visio-staging.beta.numerique.gouv.fr
|
|
||||||
secrets:
|
|
||||||
- env.d/{{ .Environment.Name }}/secrets.enc.yaml
|
|
||||||
production:
|
|
||||||
values:
|
|
||||||
- version: 0.0.1
|
|
||||||
addRedirect: True
|
|
||||||
enablePermanentRedirect: True
|
|
||||||
oldDomain: meet.numerique.gouv.fr
|
|
||||||
newDomain: visio.numerique.gouv.fr
|
|
||||||
secrets:
|
|
||||||
- env.d/{{ .Environment.Name }}/secrets.enc.yaml
|
|
||||||
|
|
||||||
repositories:
|
repositories:
|
||||||
- name: bitnami
|
- name: bitnami
|
||||||
url: registry-1.docker.io/bitnamicharts
|
url: registry-1.docker.io/bitnamicharts
|
||||||
@@ -61,12 +36,6 @@ releases:
|
|||||||
chart: ./extra
|
chart: ./extra
|
||||||
secrets:
|
secrets:
|
||||||
- env.d/{{ .Environment.Name }}/secrets.enc.yaml
|
- env.d/{{ .Environment.Name }}/secrets.enc.yaml
|
||||||
values:
|
|
||||||
- env.d/{{ .Environment.Name }}/values.meet.yaml.gotmpl
|
|
||||||
- addRedirect: {{ .Values | get "addRedirect" "False" }}
|
|
||||||
enablePermanentRedirect: {{ .Values | get "enablePermanentRedirect" "False"}}
|
|
||||||
oldDomain: {{ .Values | get "oldDomain" "demo.com" }}
|
|
||||||
newDomain: {{ .Values | get "newDomain" "demo.com" }}
|
|
||||||
|
|
||||||
- name: meet
|
- name: meet
|
||||||
version: {{ .Values.version }}
|
version: {{ .Values.version }}
|
||||||
@@ -85,3 +54,25 @@ releases:
|
|||||||
- env.d/{{ .Environment.Name }}/values.livekit.yaml.gotmpl
|
- env.d/{{ .Environment.Name }}/values.livekit.yaml.gotmpl
|
||||||
secrets:
|
secrets:
|
||||||
- env.d/{{ .Environment.Name }}/secrets.enc.yaml
|
- env.d/{{ .Environment.Name }}/secrets.enc.yaml
|
||||||
|
|
||||||
|
environments:
|
||||||
|
dev:
|
||||||
|
values:
|
||||||
|
- version: 0.0.1
|
||||||
|
secrets:
|
||||||
|
- env.d/{{ .Environment.Name }}/secrets.enc.yaml
|
||||||
|
staging:
|
||||||
|
values:
|
||||||
|
- version: 0.0.1
|
||||||
|
secrets:
|
||||||
|
- env.d/{{ .Environment.Name }}/secrets.enc.yaml
|
||||||
|
preprod:
|
||||||
|
values:
|
||||||
|
- version: 0.0.1
|
||||||
|
secrets:
|
||||||
|
- env.d/{{ .Environment.Name }}/secrets.enc.yaml
|
||||||
|
production:
|
||||||
|
values:
|
||||||
|
- version: 0.0.1
|
||||||
|
secrets:
|
||||||
|
- env.d/{{ .Environment.Name }}/secrets.enc.yaml
|
||||||
|
|||||||
@@ -157,15 +157,6 @@ Requires top level scope
|
|||||||
{{ include "meet.fullname" . }}-webrtc
|
{{ include "meet.fullname" . }}-webrtc
|
||||||
{{- end }}
|
{{- end }}
|
||||||
|
|
||||||
{{/*
|
|
||||||
Full name for the Posthog
|
|
||||||
|
|
||||||
Requires top level scope
|
|
||||||
*/}}
|
|
||||||
{{- define "meet.posthog.fullname" -}}
|
|
||||||
{{ include "meet.fullname" . }}-posthog
|
|
||||||
{{- end }}
|
|
||||||
|
|
||||||
{{/*
|
{{/*
|
||||||
Usage : {{ include "meet.secret.dockerconfigjson.name" (dict "fullname" (include "meet.fullname" .) "imageCredentials" .Values.path.to.the.image1) }}
|
Usage : {{ include "meet.secret.dockerconfigjson.name" (dict "fullname" (include "meet.fullname" .) "imageCredentials" .Values.path.to.the.image1) }}
|
||||||
*/}}
|
*/}}
|
||||||
|
|||||||
@@ -6,9 +6,8 @@ kind: Job
|
|||||||
metadata:
|
metadata:
|
||||||
name: {{ $fullName }}-migrate
|
name: {{ $fullName }}-migrate
|
||||||
namespace: {{ .Release.Namespace | quote }}
|
namespace: {{ .Release.Namespace | quote }}
|
||||||
annotations:
|
|
||||||
argocd.argoproj.io/sync-options: Replace=true,Force=true
|
|
||||||
{{- with .Values.backend.migrateJobAnnotations }}
|
{{- with .Values.backend.migrateJobAnnotations }}
|
||||||
|
annotations:
|
||||||
{{- toYaml . | nindent 4 }}
|
{{- toYaml . | nindent 4 }}
|
||||||
{{- end }}
|
{{- end }}
|
||||||
labels:
|
labels:
|
||||||
|
|||||||
@@ -6,9 +6,8 @@ kind: Job
|
|||||||
metadata:
|
metadata:
|
||||||
name: {{ $fullName }}-createsuperuser
|
name: {{ $fullName }}-createsuperuser
|
||||||
namespace: {{ .Release.Namespace | quote }}
|
namespace: {{ .Release.Namespace | quote }}
|
||||||
annotations:
|
|
||||||
argocd.argoproj.io/sync-options: Replace=true,Force=true
|
|
||||||
{{- with .Values.backend.migrateJobAnnotations }}
|
{{- with .Values.backend.migrateJobAnnotations }}
|
||||||
|
annotations:
|
||||||
{{- toYaml . | nindent 4 }}
|
{{- toYaml . | nindent 4 }}
|
||||||
{{- end }}
|
{{- end }}
|
||||||
labels:
|
labels:
|
||||||
|
|||||||
@@ -1,87 +0,0 @@
|
|||||||
{{- if .Values.posthog.ingress.enabled -}}
|
|
||||||
{{- $fullName := include "meet.fullname" . -}}
|
|
||||||
{{- if and .Values.posthog.ingress.className (not (semverCompare ">=1.18-0" .Capabilities.KubeVersion.GitVersion)) }}
|
|
||||||
{{- if not (hasKey .Values.posthog.ingress.annotations "kubernetes.io/ingress.class") }}
|
|
||||||
{{- $_ := set .Values.posthog.ingress.annotations "kubernetes.io/ingress.class" .Values.posthog.ingress.className}}
|
|
||||||
{{- end }}
|
|
||||||
{{- end }}
|
|
||||||
{{- if semverCompare ">=1.19-0" .Capabilities.KubeVersion.GitVersion -}}
|
|
||||||
apiVersion: networking.k8s.io/v1
|
|
||||||
{{- else if semverCompare ">=1.14-0" .Capabilities.KubeVersion.GitVersion -}}
|
|
||||||
apiVersion: networking.k8s.io/v1beta1
|
|
||||||
{{- else -}}
|
|
||||||
apiVersion: extensions/v1beta1
|
|
||||||
{{- end }}
|
|
||||||
kind: Ingress
|
|
||||||
metadata:
|
|
||||||
name: {{ $fullName }}-posthog
|
|
||||||
namespace: {{ .Release.Namespace | quote }}
|
|
||||||
labels:
|
|
||||||
{{- include "meet.labels" . | nindent 4 }}
|
|
||||||
{{- with .Values.posthog.ingress.annotations }}
|
|
||||||
annotations:
|
|
||||||
{{- toYaml . | nindent 4 }}
|
|
||||||
{{- end }}
|
|
||||||
spec:
|
|
||||||
{{- if and .Values.posthog.ingress.className (semverCompare ">=1.18-0" .Capabilities.KubeVersion.GitVersion) }}
|
|
||||||
ingressClassName: {{ .Values.posthog.ingress.className }}
|
|
||||||
{{- end }}
|
|
||||||
{{- if .Values.posthog.ingress.tls.enabled }}
|
|
||||||
tls:
|
|
||||||
{{- if .Values.posthog.ingress.host }}
|
|
||||||
- secretName: {{ $fullName }}-posthog-tls
|
|
||||||
hosts:
|
|
||||||
- {{ .Values.posthog.ingress.host | quote }}
|
|
||||||
{{- end }}
|
|
||||||
{{- range .Values.posthog.ingress.tls.additional }}
|
|
||||||
- hosts:
|
|
||||||
{{- range .hosts }}
|
|
||||||
- {{ . | quote }}
|
|
||||||
{{- end }}
|
|
||||||
secretName: {{ .secretName }}
|
|
||||||
{{- end }}
|
|
||||||
{{- end }}
|
|
||||||
rules:
|
|
||||||
{{- if .Values.posthog.ingress.host }}
|
|
||||||
- host: {{ .Values.posthog.ingress.host | quote }}
|
|
||||||
http:
|
|
||||||
paths:
|
|
||||||
- path: {{ .Values.posthog.ingress.path }}
|
|
||||||
{{- if semverCompare ">=1.18-0" $.Capabilities.KubeVersion.GitVersion }}
|
|
||||||
pathType: Prefix
|
|
||||||
{{- end }}
|
|
||||||
backend:
|
|
||||||
{{- if semverCompare ">=1.19-0" $.Capabilities.KubeVersion.GitVersion }}
|
|
||||||
service:
|
|
||||||
name: {{ include "meet.posthog.fullname" . }}-proxy
|
|
||||||
port:
|
|
||||||
number: {{ .Values.posthog.service.port }}
|
|
||||||
{{- else }}
|
|
||||||
serviceName: {{ include "meet.posthog.fullname" . }}-proxy
|
|
||||||
servicePort: {{ .Values.posthog.service.port }}
|
|
||||||
{{- end }}
|
|
||||||
{{- end }}
|
|
||||||
{{- range .Values.posthog.ingress.hosts }}
|
|
||||||
- host: {{ . | quote }}
|
|
||||||
http:
|
|
||||||
paths:
|
|
||||||
- path: {{ $.Values.posthog.ingress.path | quote }}
|
|
||||||
{{- if semverCompare ">=1.18-0" $.Capabilities.KubeVersion.GitVersion }}
|
|
||||||
pathType: Prefix
|
|
||||||
{{- end }}
|
|
||||||
backend:
|
|
||||||
{{- if semverCompare ">=1.19-0" $.Capabilities.KubeVersion.GitVersion }}
|
|
||||||
service:
|
|
||||||
name: {{ include "meet.posthog.fullname" . }}-proxy
|
|
||||||
port:
|
|
||||||
number: {{ $.Values.posthog.service.port }}
|
|
||||||
{{- else }}
|
|
||||||
serviceName: {{ include "meet.posthog.fullname" . }}-proxy
|
|
||||||
servicePort: {{ $.Values.posthog.service.port }}
|
|
||||||
{{- end }}
|
|
||||||
{{- with $.Values.posthog.assetsService.customBackends }}
|
|
||||||
{{- toYaml . | nindent 10 }}
|
|
||||||
{{- end }}
|
|
||||||
{{- end }}
|
|
||||||
{{- end }}
|
|
||||||
|
|
||||||
@@ -1,87 +0,0 @@
|
|||||||
{{- if .Values.posthog.ingressAssets.enabled -}}
|
|
||||||
{{- $fullName := include "meet.fullname" . -}}
|
|
||||||
{{- if and .Values.posthog.ingressAssets.className (not (semverCompare ">=1.18-0" .Capabilities.KubeVersion.GitVersion)) }}
|
|
||||||
{{- if not (hasKey .Values.posthog.ingressAssets.annotations "kubernetes.io/ingress.class") }}
|
|
||||||
{{- $_ := set .Values.posthog.ingressAssets.annotations "kubernetes.io/ingress.class" .Values.posthog.ingressAssets.className}}
|
|
||||||
{{- end }}
|
|
||||||
{{- end }}
|
|
||||||
{{- if semverCompare ">=1.19-0" .Capabilities.KubeVersion.GitVersion -}}
|
|
||||||
apiVersion: networking.k8s.io/v1
|
|
||||||
{{- else if semverCompare ">=1.14-0" .Capabilities.KubeVersion.GitVersion -}}
|
|
||||||
apiVersion: networking.k8s.io/v1beta1
|
|
||||||
{{- else -}}
|
|
||||||
apiVersion: extensions/v1beta1
|
|
||||||
{{- end }}
|
|
||||||
kind: Ingress
|
|
||||||
metadata:
|
|
||||||
name: {{ $fullName }}-posthog-assets
|
|
||||||
namespace: {{ .Release.Namespace | quote }}
|
|
||||||
labels:
|
|
||||||
{{- include "meet.labels" . | nindent 4 }}
|
|
||||||
{{- with .Values.posthog.ingressAssets.annotations }}
|
|
||||||
annotations:
|
|
||||||
{{- toYaml . | nindent 4 }}
|
|
||||||
{{- end }}
|
|
||||||
spec:
|
|
||||||
{{- if and .Values.posthog.ingressAssets.className (semverCompare ">=1.18-0" .Capabilities.KubeVersion.GitVersion) }}
|
|
||||||
ingressClassName: {{ .Values.posthog.ingressAssets.className }}
|
|
||||||
{{- end }}
|
|
||||||
{{- if .Values.posthog.ingressAssets.tls.enabled }}
|
|
||||||
tls:
|
|
||||||
{{- if .Values.posthog.ingressAssets.host }}
|
|
||||||
- secretName: {{ $fullName }}-posthog-tls
|
|
||||||
hosts:
|
|
||||||
- {{ .Values.posthog.ingressAssets.host | quote }}
|
|
||||||
{{- end }}
|
|
||||||
{{- range .Values.posthog.ingressAssets.tls.additional }}
|
|
||||||
- hosts:
|
|
||||||
{{- range .hosts }}
|
|
||||||
- {{ . | quote }}
|
|
||||||
{{- end }}
|
|
||||||
secretName: {{ .secretName }}
|
|
||||||
{{- end }}
|
|
||||||
{{- end }}
|
|
||||||
rules:
|
|
||||||
{{- if .Values.posthog.ingressAssets.host }}
|
|
||||||
- host: {{ .Values.posthog.ingressAssets.host | quote }}
|
|
||||||
http:
|
|
||||||
paths:
|
|
||||||
- path: {{ .Values.posthog.ingressAssets.path }}
|
|
||||||
{{- if semverCompare ">=1.18-0" $.Capabilities.KubeVersion.GitVersion }}
|
|
||||||
pathType: Prefix
|
|
||||||
{{- end }}
|
|
||||||
backend:
|
|
||||||
{{- if semverCompare ">=1.19-0" $.Capabilities.KubeVersion.GitVersion }}
|
|
||||||
service:
|
|
||||||
name: {{ include "meet.posthog.fullname" . }}-assets-proxy
|
|
||||||
port:
|
|
||||||
number: {{ .Values.posthog.assetsService.port }}
|
|
||||||
{{- else }}
|
|
||||||
serviceName: {{ include "meet.posthog.fullname" . }}
|
|
||||||
servicePort: {{ .Values.posthog.assetsService.port }}
|
|
||||||
{{- end }}
|
|
||||||
{{- end }}
|
|
||||||
{{- range .Values.posthog.ingressAssets.hosts }}
|
|
||||||
- host: {{ . | quote }}
|
|
||||||
http:
|
|
||||||
paths:
|
|
||||||
- path: {{ $.Values.posthog.ingressAssets.path | quote }}
|
|
||||||
{{- if semverCompare ">=1.18-0" $.Capabilities.KubeVersion.GitVersion }}
|
|
||||||
pathType: Prefix
|
|
||||||
{{- end }}
|
|
||||||
backend:
|
|
||||||
{{- if semverCompare ">=1.19-0" $.Capabilities.KubeVersion.GitVersion }}
|
|
||||||
service:
|
|
||||||
name: {{ include "meet.posthog.fullname" . }}-assets-proxy
|
|
||||||
port:
|
|
||||||
number: {{ $.Values.posthog.assetsService.service.port }}
|
|
||||||
{{- else }}
|
|
||||||
serviceName: {{ include "meet.posthog.fullname" . }}-assets-proxy
|
|
||||||
servicePort: {{ $.Values.posthog.assetsService.service.port }}
|
|
||||||
{{- end }}
|
|
||||||
{{- with $.Values.posthog.assetsService.customBackends }}
|
|
||||||
{{- toYaml . | nindent 10 }}
|
|
||||||
{{- end }}
|
|
||||||
{{- end }}
|
|
||||||
{{- end }}
|
|
||||||
|
|
||||||
@@ -1,24 +0,0 @@
|
|||||||
{{- if .Values.posthog.ingressAssets.enabled -}}
|
|
||||||
{{- $envVars := include "meet.common.env" (list . .Values.posthog) -}}
|
|
||||||
{{- $fullName := include "meet.posthog.fullname" . -}}
|
|
||||||
{{- $component := "posthog" -}}
|
|
||||||
apiVersion: v1
|
|
||||||
kind: Service
|
|
||||||
metadata:
|
|
||||||
name: {{ $fullName }}-assets-proxy
|
|
||||||
namespace: {{ .Release.Namespace | quote }}
|
|
||||||
labels:
|
|
||||||
{{- include "meet.common.labels" (list . $component) | nindent 4 }}
|
|
||||||
annotations:
|
|
||||||
{{- toYaml $.Values.posthog.assetsService.annotations | nindent 4 }}
|
|
||||||
spec:
|
|
||||||
type: {{ .Values.posthog.assetsService.type }}
|
|
||||||
externalName: {{ .Values.posthog.assetsService.externalName }}
|
|
||||||
ports:
|
|
||||||
- port: {{ .Values.posthog.assetsService.port }}
|
|
||||||
targetPort: {{ .Values.posthog.assetsService.targetPort }}
|
|
||||||
protocol: TCP
|
|
||||||
name: http
|
|
||||||
selector:
|
|
||||||
{{- include "meet.common.selectorLabels" (list . $component) | nindent 4 }}
|
|
||||||
{{- end }}
|
|
||||||
@@ -1,24 +0,0 @@
|
|||||||
{{- if .Values.posthog.ingress.enabled -}}
|
|
||||||
{{- $envVars := include "meet.common.env" (list . .Values.posthog) -}}
|
|
||||||
{{- $fullName := include "meet.posthog.fullname" . -}}
|
|
||||||
{{- $component := "posthog" -}}
|
|
||||||
apiVersion: v1
|
|
||||||
kind: Service
|
|
||||||
metadata:
|
|
||||||
name: {{ $fullName }}-proxy
|
|
||||||
namespace: {{ .Release.Namespace | quote }}
|
|
||||||
labels:
|
|
||||||
{{- include "meet.common.labels" (list . $component) | nindent 4 }}
|
|
||||||
annotations:
|
|
||||||
{{- toYaml $.Values.posthog.service.annotations | nindent 4 }}
|
|
||||||
spec:
|
|
||||||
type: {{ .Values.posthog.service.type }}
|
|
||||||
externalName: {{ .Values.posthog.service.externalName }}
|
|
||||||
ports:
|
|
||||||
- port: {{ .Values.posthog.service.port }}
|
|
||||||
targetPort: {{ .Values.posthog.service.targetPort }}
|
|
||||||
protocol: TCP
|
|
||||||
name: https
|
|
||||||
selector:
|
|
||||||
{{- include "meet.common.selectorLabels" (list . $component) | nindent 4 }}
|
|
||||||
{{- end }}
|
|
||||||
@@ -3,10 +3,6 @@ kind: Secret
|
|||||||
metadata:
|
metadata:
|
||||||
name: backend
|
name: backend
|
||||||
namespace: {{ .Release.Namespace | quote }}
|
namespace: {{ .Release.Namespace | quote }}
|
||||||
annotations:
|
|
||||||
"helm.sh/hook": pre-install,pre-upgrade
|
|
||||||
"helm.sh/hook-weight": "-5"
|
|
||||||
"helm.sh/hook-delete-policy": before-hook-creation
|
|
||||||
stringData:
|
stringData:
|
||||||
DJANGO_SUPERUSER_EMAIL: {{ .Values.djangoSuperUserEmail }}
|
DJANGO_SUPERUSER_EMAIL: {{ .Values.djangoSuperUserEmail }}
|
||||||
DJANGO_SUPERUSER_PASSWORD: {{ .Values.djangoSuperUserPass }}
|
DJANGO_SUPERUSER_PASSWORD: {{ .Values.djangoSuperUserPass }}
|
||||||
|
|||||||
@@ -263,45 +263,3 @@ frontend:
|
|||||||
|
|
||||||
## @param frontend.extraVolumes Additional volumes to mount on the frontend.
|
## @param frontend.extraVolumes Additional volumes to mount on the frontend.
|
||||||
extraVolumes: []
|
extraVolumes: []
|
||||||
|
|
||||||
## @section Posthog
|
|
||||||
|
|
||||||
posthog:
|
|
||||||
|
|
||||||
ingress:
|
|
||||||
enabled: false
|
|
||||||
className: null
|
|
||||||
host: meet.example.com
|
|
||||||
path: /
|
|
||||||
hosts: [ ]
|
|
||||||
tls:
|
|
||||||
enabled: true
|
|
||||||
additional: [ ]
|
|
||||||
|
|
||||||
customBackends: [ ]
|
|
||||||
annotations: {}
|
|
||||||
|
|
||||||
ingressAssets:
|
|
||||||
enabled: false
|
|
||||||
className: null
|
|
||||||
host: meet.example.com
|
|
||||||
path: /static
|
|
||||||
hosts: [ ]
|
|
||||||
tls:
|
|
||||||
enabled: true
|
|
||||||
additional: [ ]
|
|
||||||
|
|
||||||
customBackends: [ ]
|
|
||||||
annotations: {}
|
|
||||||
|
|
||||||
service:
|
|
||||||
type: ExternalName
|
|
||||||
externalName: eu.i.posthog.com
|
|
||||||
port: 443
|
|
||||||
annotations: {}
|
|
||||||
|
|
||||||
assetsService:
|
|
||||||
type: ExternalName
|
|
||||||
externalName: eu-assets.i.posthog.com
|
|
||||||
port: 443
|
|
||||||
annotations: {}
|
|
||||||
|
|||||||
Generated
+2
-2
@@ -1,12 +1,12 @@
|
|||||||
{
|
{
|
||||||
"name": "mail_mjml",
|
"name": "mail_mjml",
|
||||||
"version": "0.1.7",
|
"version": "0.1.5",
|
||||||
"lockfileVersion": 3,
|
"lockfileVersion": 3,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"name": "mail_mjml",
|
"name": "mail_mjml",
|
||||||
"version": "0.1.7",
|
"version": "0.1.5",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@html-to/text-cli": "0.5.4",
|
"@html-to/text-cli": "0.5.4",
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "mail_mjml",
|
"name": "mail_mjml",
|
||||||
"version": "0.1.7",
|
"version": "0.1.5",
|
||||||
"description": "An util to generate html and text django's templates from mjml templates",
|
"description": "An util to generate html and text django's templates from mjml templates",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
@@ -14,7 +14,7 @@
|
|||||||
"build": "npm run build-mjml-to-html && npm run build-html-to-plain-text"
|
"build": "npm run build-mjml-to-html && npm run build-html-to-plain-text"
|
||||||
},
|
},
|
||||||
"volta": {
|
"volta": {
|
||||||
"node": "20.17.0"
|
"node": "16.15.1"
|
||||||
},
|
},
|
||||||
"repository": "https://github.com/numerique-gouv/meet",
|
"repository": "https://github.com/numerique-gouv/meet",
|
||||||
"author": "DINUM",
|
"author": "DINUM",
|
||||||
|
|||||||
Reference in New Issue
Block a user