diff --git a/backend/dev_livekit-othersite.yaml b/backend/dev_livekit-othersite.yaml index 0ae98c24..53fc9ce9 100644 --- a/backend/dev_livekit-othersite.yaml +++ b/backend/dev_livekit-othersite.yaml @@ -18,3 +18,7 @@ keys: devkey: secret room: auto_create: false +webhook: + api_key: devkey + urls: + - https://matrix-rtc.othersite.m.localhost/livekit/jwt/sfu_webhook diff --git a/backend/dev_livekit.yaml b/backend/dev_livekit.yaml index 157e4d04..6cef4241 100644 --- a/backend/dev_livekit.yaml +++ b/backend/dev_livekit.yaml @@ -18,3 +18,7 @@ keys: devkey: secret room: auto_create: false +webhook: + api_key: devkey + urls: + - https://matrix-rtc.m.localhost/livekit/jwt/sfu_webhook diff --git a/dev-backend-docker-compose.yml b/dev-backend-docker-compose.yml index 0a42dad5..95953766 100644 --- a/dev-backend-docker-compose.yml +++ b/dev-backend-docker-compose.yml @@ -1,175 +1,183 @@ -networks: - ecbackend: - -services: - auth-service: - image: ghcr.io/element-hq/lk-jwt-service:pr_171 - pull_policy: always - hostname: auth-server - environment: - - LIVEKIT_JWT_PORT=6080 - - LIVEKIT_URL=wss://matrix-rtc.m.localhost/livekit/sfu - - LIVEKIT_KEY=devkey - - LIVEKIT_SECRET=secret - # If the configured homeserver runs on localhost, it'll probably be using - # a self-signed certificate - - LIVEKIT_INSECURE_SKIP_VERIFY_TLS=YES_I_KNOW_WHAT_I_AM_DOING - - LIVEKIT_FULL_ACCESS_HOMESERVERS=* - deploy: - restart_policy: - condition: on-failure - ports: - # HOST_PORT:CONTAINER_PORT - - 6080:6080 - networks: - - ecbackend - - auth-service-1: - image: ghcr.io/element-hq/lk-jwt-service:pr_171 - pull_policy: always - hostname: auth-server-1 - environment: - - LIVEKIT_JWT_PORT=16080 - - LIVEKIT_URL=wss://matrix-rtc.othersite.m.localhost/livekit/sfu - - LIVEKIT_KEY=devkey - - LIVEKIT_SECRET=secret - # If the configured homeserver runs on localhost, it'll probably be using - # a self-signed certificate - - LIVEKIT_INSECURE_SKIP_VERIFY_TLS=YES_I_KNOW_WHAT_I_AM_DOING - - LIVEKIT_FULL_ACCESS_HOMESERVERS=* - deploy: - restart_policy: - condition: on-failure - ports: - # HOST_PORT:CONTAINER_PORT - - 16080:16080 - networks: - - ecbackend - - livekit: - image: livekit/livekit-server:v1.10.1 - pull_policy: always - hostname: livekit-sfu - command: --dev --config /etc/livekit.yaml - restart: unless-stopped - # The SFU seems to work far more reliably when we let it share the host - # network rather than opening specific ports (but why?? we're not missing - # any…) - ports: - # HOST_PORT:CONTAINER_PORT - - 7880:7880/tcp - - 7881:7881/tcp - - 7882:7882/tcp - - 50100-50200:50100-50200/udp - volumes: - - ./backend/dev_livekit.yaml:/etc/livekit.yaml:Z - networks: - - ecbackend - - livekit-1: - image: livekit/livekit-server:v1.10.1 - pull_policy: always - hostname: livekit-sfu-1 - command: --dev --config /etc/livekit.yaml - restart: unless-stopped - # The SFU seems to work far more reliably when we let it share the host - # network rather than opening specific ports (but why?? we're not missing - # any…) - ports: - # HOST_PORT:CONTAINER_PORT - - 17880:17880/tcp - - 17881:17881/tcp - - 17882:17882/tcp - - 50300-50400:50300-50400/udp - volumes: - - ./backend/dev_livekit-othersite.yaml:/etc/livekit.yaml:Z - networks: - - ecbackend - - synapse: - hostname: homeserver - image: ghcr.io/element-hq/synapse:latest - pull_policy: always - environment: - - SYNAPSE_CONFIG_PATH=/data/cfg/homeserver.yaml - # Needed for rootless podman-compose such that the uid/gid mapping does - # fit local user uid. If the container runs as root (uid 0) it is fine as - # it actually maps to your non-root user on the host (e.g. 1000). - # Otherwise uid mapping will not match your non-root user. - - UID=0 - - GID=0 - volumes: - - ./backend/synapse_tmp:/data:Z - - ./backend/dev_homeserver.yaml:/data/cfg/homeserver.yaml:Z - networks: - - ecbackend - - synapse-1: - hostname: homeserver-1 - image: ghcr.io/element-hq/synapse:latest - pull_policy: always - environment: - - SYNAPSE_CONFIG_PATH=/data/cfg/homeserver.yaml - # Needed for rootless podman-compose such that the uid/gid mapping does - # fit local user uid. If the container runs as root (uid 0) it is fine as - # it actually maps to your non-root user on the host (e.g. 1000). - # Otherwise uid mapping will not match your non-root user. - - UID=0 - - GID=0 - volumes: - - ./backend/synapse_tmp_othersite:/data:Z - - ./backend/dev_homeserver-othersite.yaml:/data/cfg/homeserver.yaml:Z - networks: - - ecbackend - - element-web: - image: ghcr.io/element-hq/element-web:develop - pull_policy: always - volumes: - - ./backend/ew.test.config.json:/app/config.json:Z - environment: - ELEMENT_WEB_PORT: 8081 - ports: - - "8081:8081" - networks: - - ecbackend - - element-web-1: - image: ghcr.io/element-hq/element-web:develop - pull_policy: always - volumes: - - ./backend/ew.test.othersite.config.json:/app/config.json:Z - environment: - ELEMENT_WEB_PORT: 18081 - ports: - # HOST_PORT:CONTAINER_PORT - - "18081:18081" - networks: - - ecbackend - - nginx: - # see backend/dev_tls_setup for how to generate the tls certs - hostname: synapse.m.localhost - image: nginx:latest - pull_policy: always - volumes: - - ./backend/dev_nginx.conf:/etc/nginx/conf.d/default.conf:Z - - ./backend/dev_tls_m.localhost.key:/root/ssl/key.pem:Z - - ./backend/dev_tls_m.localhost.crt:/root/ssl/cert.pem:Z - ports: - # HOST_PORT:CONTAINER_PORT - - "443:443" - - "8008:80" - - "4443:443" - - "8448:8448" - extra_hosts: - - "host.docker.internal:host-gateway" - depends_on: - - synapse - networks: - ecbackend: - aliases: - - synapse.m.localhost - - synapse.othersite.m.localhost - - matrix-rtc.m.localhost - - matrix-rtc.othersite.m.localhost +networks: + ecbackend: + +services: + auth-service: + image: ghcr.io/element-hq/lk-jwt-service:pr_171 + pull_policy: always + hostname: auth-server + environment: + - LIVEKIT_JWT_PORT=6080 + - LIVEKIT_URL=wss://matrix-rtc.m.localhost/livekit/sfu + - LIVEKIT_KEY=devkey + - LIVEKIT_SECRET=secret + # If the configured homeserver runs on localhost, it'll probably be using + # a self-signed certificate + - LIVEKIT_INSECURE_SKIP_VERIFY_TLS=YES_I_KNOW_WHAT_I_AM_DOING + - LIVEKIT_FULL_ACCESS_HOMESERVERS=* + deploy: + restart_policy: + condition: on-failure + ports: + # HOST_PORT:CONTAINER_PORT + - 6080:6080 + networks: + - ecbackend + + auth-service-1: + image: ghcr.io/element-hq/lk-jwt-service:pr_171 + pull_policy: always + hostname: auth-server-1 + environment: + - LIVEKIT_JWT_PORT=16080 + - LIVEKIT_URL=wss://matrix-rtc.othersite.m.localhost/livekit/sfu + - LIVEKIT_KEY=devkey + - LIVEKIT_SECRET=secret + # If the configured homeserver runs on localhost, it'll probably be using + # a self-signed certificate + - LIVEKIT_INSECURE_SKIP_VERIFY_TLS=YES_I_KNOW_WHAT_I_AM_DOING + - LIVEKIT_FULL_ACCESS_HOMESERVERS=* + deploy: + restart_policy: + condition: on-failure + ports: + # HOST_PORT:CONTAINER_PORT + - 16080:16080 + networks: + - ecbackend + + livekit: + image: livekit/livekit-server:v1.10.1 + pull_policy: always + hostname: livekit-sfu + command: --dev --config /etc/livekit.yaml + restart: unless-stopped + # The SFU seems to work far more reliably when we let it share the host + # network rather than opening specific ports (but why?? we're not missing + # any…) + ports: + # HOST_PORT:CONTAINER_PORT + - 7880:7880/tcp + - 7881:7881/tcp + - 7882:7882/tcp + - 50100-50200:50100-50200/udp + volumes: + - ./backend/dev_tls_m.localhost.crt:/local_cert.pem:Z + - ./backend/dev_livekit.yaml:/etc/livekit.yaml:Z + environment: + - SSL_CERT_FILE=/local_cert.pem + networks: + - ecbackend + + livekit-1: + image: livekit/livekit-server:v1.10.1 + pull_policy: always + hostname: livekit-sfu-1 + command: --dev --config /etc/livekit.yaml + restart: unless-stopped + # The SFU seems to work far more reliably when we let it share the host + # network rather than opening specific ports (but why?? we're not missing + # any…) + ports: + # HOST_PORT:CONTAINER_PORT + - 17880:17880/tcp + - 17881:17881/tcp + - 17882:17882/tcp + - 50300-50400:50300-50400/udp + volumes: + - ./backend/dev_tls_m.localhost.crt:/local_cert.pem:Z + - ./backend/dev_livekit-othersite.yaml:/etc/livekit.yaml:Z + environment: + - SSL_CERT_FILE=/local_cert.pem + networks: + - ecbackend + + synapse: + hostname: homeserver + image: ghcr.io/element-hq/synapse:latest + pull_policy: always + environment: + - SYNAPSE_CONFIG_PATH=/data/cfg/homeserver.yaml + # Needed for rootless podman-compose such that the uid/gid mapping does + # fit local user uid. If the container runs as root (uid 0) it is fine as + # it actually maps to your non-root user on the host (e.g. 1000). + # Otherwise uid mapping will not match your non-root user. + - UID=0 + - GID=0 + volumes: + - ./backend/synapse_tmp:/data:Z + - ./backend/dev_homeserver.yaml:/data/cfg/homeserver.yaml:Z + networks: + - ecbackend + + synapse-1: + hostname: homeserver-1 + image: ghcr.io/element-hq/synapse:latest + pull_policy: always + environment: + - SYNAPSE_CONFIG_PATH=/data/cfg/homeserver.yaml + # Needed for rootless podman-compose such that the uid/gid mapping does + # fit local user uid. If the container runs as root (uid 0) it is fine as + # it actually maps to your non-root user on the host (e.g. 1000). + # Otherwise uid mapping will not match your non-root user. + - UID=0 + - GID=0 + volumes: + - ./backend/synapse_tmp_othersite:/data:Z + - ./backend/dev_homeserver-othersite.yaml:/data/cfg/homeserver.yaml:Z + networks: + - ecbackend + + element-web: + image: ghcr.io/element-hq/element-web:develop + pull_policy: always + volumes: + - ./backend/ew.test.config.json:/app/config.json:Z + environment: + ELEMENT_WEB_PORT: 8081 + ports: + - "8081:8081" + networks: + - ecbackend + + element-web-1: + image: ghcr.io/element-hq/element-web:develop + pull_policy: always + volumes: + - ./backend/ew.test.othersite.config.json:/app/config.json:Z + environment: + ELEMENT_WEB_PORT: 18081 + ports: + # HOST_PORT:CONTAINER_PORT + - "18081:18081" + networks: + - ecbackend + + nginx: + # see backend/dev_tls_setup for how to generate the tls certs + hostname: synapse.m.localhost + image: nginx:latest + pull_policy: always + volumes: + - ./backend/dev_nginx.conf:/etc/nginx/conf.d/default.conf:Z + - ./backend/dev_tls_m.localhost.key:/root/ssl/key.pem:Z + - ./backend/dev_tls_m.localhost.crt:/root/ssl/cert.pem:Z + ports: + # HOST_PORT:CONTAINER_PORT + - "443:443" + - "8008:80" + - "4443:443" + - "8448:8448" + extra_hosts: + - "host.docker.internal:host-gateway" + - "auth-server:127.0.0.1" + - "auth-server-1:127.0.0.1" + depends_on: + - synapse + networks: + ecbackend: + aliases: + - synapse.m.localhost + - synapse.othersite.m.localhost + - matrix-rtc.m.localhost + - matrix-rtc.othersite.m.localhost diff --git a/src/useCallViewKeyboardShortcuts.test.tsx b/src/useCallViewKeyboardShortcuts.test.tsx index e22380d1..5a327f83 100644 --- a/src/useCallViewKeyboardShortcuts.test.tsx +++ b/src/useCallViewKeyboardShortcuts.test.tsx @@ -6,7 +6,7 @@ Please see LICENSE in the repository root for full details. */ import { render } from "@testing-library/react"; -import { type FC, useRef } from "react"; +import { type FC, useRef, useState } from "react"; import { expect, test, vi } from "vitest"; import { Button } from "@vector-im/compound-web"; import userEvent from "@testing-library/user-event"; @@ -17,6 +17,7 @@ import { ReactionSet, ReactionsRowSize, } from "./reactions"; +import { type Controls } from "./controls"; // Test Explanation: // - The main objective is to test `useCallViewKeyboardShortcuts`. @@ -27,6 +28,7 @@ interface TestComponentProps { onButtonClick?: () => void; sendReaction?: () => void; toggleHandRaised?: () => void; + initialModalOpen?: boolean; } const TestComponent: FC = ({ @@ -34,7 +36,9 @@ const TestComponent: FC = ({ onButtonClick = (): void => {}, sendReaction = (reaction: ReactionOption): void => {}, toggleHandRaised = (): void => {}, + initialModalOpen = false, }) => { + const [modalOpen, setModalOpen] = useState(initialModalOpen); const ref = useRef(null); useCallViewKeyboardShortcuts( ref, @@ -47,6 +51,19 @@ const TestComponent: FC = ({ return (
+ {modalOpen && ( + { + if (e.key === "Escape") { + e.preventDefault(); + setModalOpen(false); + } + }} + > + + + )}
); }; @@ -118,6 +135,27 @@ test("raised hand can be sent via keyboard presses", async () => { expect(toggleHandRaised).toHaveBeenCalledOnce(); }); +test("raised hand cannot be sent via keyboard presses if modal open and focussed", async () => { + const user = userEvent.setup(); + const toggleHandRaised = vi.fn(); + const { getByRole } = render( + , + ); + getByRole("button", { name: "InModalButton" }).focus(); + await user.keyboard("h"); + + expect(toggleHandRaised).not.toHaveBeenCalledOnce(); + + // once we press esc... + await user.keyboard("[Escape]"); + // we can toggle the hand raise... + await user.keyboard("h"); + expect(toggleHandRaised).toHaveBeenCalledOnce(); +}); + test("unmuting happens in place of the default action", async () => { const user = userEvent.setup(); const defaultPrevented = vi.fn(); @@ -138,3 +176,35 @@ test("unmuting happens in place of the default action", async () => { await user.keyboard("[Space]"); expect(defaultPrevented).toBeCalledWith(true); }); + +test("escape button triggers the controls back action", async () => { + const user = userEvent.setup(); + + window.controls = { onBackButtonPressed: vi.fn() } as unknown as Controls; + // In the real application, we mostly just want the spacebar shortcut to avoid + // scrolling the page. But to test that here in JSDOM, we need some kind of + // container element that can be interactive and receive focus / keydown + // events.