Merge remote-tracking branch 'origin/livekit' into hs/reactions-viewcallmodel

This commit is contained in:
Half-Shot
2024-12-12 09:18:36 +00:00
155 changed files with 1772 additions and 996 deletions

View File

@@ -37,6 +37,12 @@ module.exports = {
"@typescript-eslint/promise-function-async": "error", "@typescript-eslint/promise-function-async": "error",
"@typescript-eslint/require-await": "error", "@typescript-eslint/require-await": "error",
"@typescript-eslint/await-thenable": "error", "@typescript-eslint/await-thenable": "error",
// To help ensure that we get proper vite/rollup lazy loading (e.g. for matrix-js-sdk):
"@typescript-eslint/consistent-type-imports": [
"error",
{ fixStyle: "inline-type-imports" },
],
// To encourage good usage of RxJS:
"rxjs/no-exposed-subjects": "error", "rxjs/no-exposed-subjects": "error",
}, },
settings: { settings: {

View File

@@ -17,5 +17,9 @@
}, },
"rageshake": { "rageshake": {
"submit_url": "https://element.io/bugreports/submit" "submit_url": "https://element.io/bugreports/submit"
},
"sentry": {
"environment": "netlify-pr-preview",
"DSN": "https://b1e328d49be3402ba96101338989fb35@sentry.tools.element.io/41"
} }
} }

View File

@@ -70,6 +70,7 @@
}, },
"developer_mode": { "developer_mode": {
"crypto_version": "Crypto version: {{version}}", "crypto_version": "Crypto version: {{version}}",
"debug_tile_layout_label": "Debug tile layout",
"device_id": "Device ID: {{id}}", "device_id": "Device ID: {{id}}",
"duplicate_tiles_label": "Number of additional tile copies per participant", "duplicate_tiles_label": "Number of additional tile copies per participant",
"hostname": "Hostname: {{hostname}}", "hostname": "Hostname: {{hostname}}",
@@ -147,11 +148,9 @@
"screenshare_button_label": "Share screen", "screenshare_button_label": "Share screen",
"settings": { "settings": {
"audio_tab": { "audio_tab": {
"effect_volume_description": "Volume for sound effects such as: joining or leaving a call, and reactions.", "effect_volume_description": "Adjust the volume at which reactions and hand raised effects play.",
"effect_volume_label": "Sound effect volume" "effect_volume_label": "Sound effect volume"
}, },
"developer_settings_label": "Developer Settings",
"developer_settings_label_description": "Expose developer settings in the settings window.",
"developer_tab_title": "Developer", "developer_tab_title": "Developer",
"feedback_tab_body": "If you are experiencing issues or simply would like to provide some feedback, please send us a short description below.", "feedback_tab_body": "If you are experiencing issues or simply would like to provide some feedback, please send us a short description below.",
"feedback_tab_description_label": "Your feedback", "feedback_tab_description_label": "Your feedback",
@@ -159,17 +158,16 @@
"feedback_tab_send_logs_label": "Include debug logs", "feedback_tab_send_logs_label": "Include debug logs",
"feedback_tab_thank_you": "Thanks, we received your feedback!", "feedback_tab_thank_you": "Thanks, we received your feedback!",
"feedback_tab_title": "Feedback", "feedback_tab_title": "Feedback",
"more_tab_title": "More",
"opt_in_description": "<0></0><1></1>You may withdraw consent by unchecking this box. If you are currently in a call, this setting will take effect at the end of the call.", "opt_in_description": "<0></0><1></1>You may withdraw consent by unchecking this box. If you are currently in a call, this setting will take effect at the end of the call.",
"preferences_tab": { "preferences_tab": {
"developer_mode_label": "Developer mode",
"developer_mode_label_description": "Enable developer mode and show developer settings tab.",
"reactions_play_sound_description": "Play a sound effect when anyone sends a reaction into a call.", "reactions_play_sound_description": "Play a sound effect when anyone sends a reaction into a call.",
"reactions_play_sound_label": "Play reaction sounds", "reactions_play_sound_label": "Play reaction sounds",
"reactions_show_description": "Show an animation when anyone sends a reaction.", "reactions_show_description": "Show an animation when anyone sends a reaction.",
"reactions_show_label": "Show reactions", "reactions_show_label": "Show reactions"
"reactions_title": "Reactions"
}, },
"preferences_tab_body": "Here you can configure extra options for an improved experience", "preferences_tab_body": "Here you can configure extra options for an improved experience.",
"preferences_tab_h4": "Preferences",
"preferences_tab_show_hand_raised_timer_description": "Show a timer when a participant raises their hand", "preferences_tab_show_hand_raised_timer_description": "Show a timer when a participant raises their hand",
"preferences_tab_show_hand_raised_timer_label": "Show hand raise duration", "preferences_tab_show_hand_raised_timer_label": "Show hand raise duration",
"speaker_device_selection_label": "Speaker" "speaker_device_selection_label": "Speaker"

View File

@@ -27,13 +27,13 @@
"@codecov/vite-plugin": "^1.3.0", "@codecov/vite-plugin": "^1.3.0",
"@fontsource/inconsolata": "^5.1.0", "@fontsource/inconsolata": "^5.1.0",
"@fontsource/inter": "^5.1.0", "@fontsource/inter": "^5.1.0",
"@formatjs/intl-durationformat": "^0.6.1", "@formatjs/intl-durationformat": "^0.7.0",
"@formatjs/intl-segmenter": "^11.7.3", "@formatjs/intl-segmenter": "^11.7.3",
"@livekit/components-core": "^0.11.0", "@livekit/components-core": "^0.11.0",
"@livekit/components-react": "^2.0.0", "@livekit/components-react": "^2.0.0",
"@opentelemetry/api": "^1.4.0", "@opentelemetry/api": "^1.4.0",
"@opentelemetry/core": "^1.25.1", "@opentelemetry/core": "^1.25.1",
"@opentelemetry/exporter-trace-otlp-http": "^0.55.0", "@opentelemetry/exporter-trace-otlp-http": "^0.56.0",
"@opentelemetry/resources": "^1.25.1", "@opentelemetry/resources": "^1.25.1",
"@opentelemetry/sdk-trace-base": "^1.25.1", "@opentelemetry/sdk-trace-base": "^1.25.1",
"@opentelemetry/sdk-trace-web": "^1.9.1", "@opentelemetry/sdk-trace-web": "^1.9.1",
@@ -113,7 +113,7 @@
"typescript-eslint-language-service": "^5.0.5", "typescript-eslint-language-service": "^5.0.5",
"unique-names-generator": "^4.6.0", "unique-names-generator": "^4.6.0",
"vaul": "^1.0.0", "vaul": "^1.0.0",
"vite": "^5.0.0", "vite": "^6.0.0",
"vite-plugin-compression2": "^1.3.1", "vite-plugin-compression2": "^1.3.1",
"vite-plugin-html-template": "^1.1.0", "vite-plugin-html-template": "^1.1.0",
"vite-plugin-svgr": "^4.0.0", "vite-plugin-svgr": "^4.0.0",

View File

@@ -7,7 +7,7 @@ Please see LICENSE in the repository root for full details.
import "matrix-js-sdk/src/@types/global"; import "matrix-js-sdk/src/@types/global";
import type { DurationFormat as PolyfillDurationFormat } from "@formatjs/intl-durationformat"; import type { DurationFormat as PolyfillDurationFormat } from "@formatjs/intl-durationformat";
import { Controls } from "../controls"; import { type Controls } from "../controls";
declare global { declare global {
interface Document { interface Document {

View File

@@ -7,7 +7,7 @@ Please see LICENSE in the repository root for full details.
import "i18next"; import "i18next";
// import all namespaces (for the default language, only) // import all namespaces (for the default language, only)
import app from "../../locales/en/app.json"; import type app from "../../locales/en/app.json";
declare module "i18next" { declare module "i18next" {
interface CustomTypeOptions { interface CustomTypeOptions {

View File

@@ -6,8 +6,8 @@ Please see LICENSE in the repository root for full details.
*/ */
import { import {
ElementCallReactionEventType, type ElementCallReactionEventType,
ECallReactionEventContent, type ECallReactionEventContent,
} from "../reactions"; } from "../reactions";
// Extend Matrix JS SDK types via Typescript declaration merging to support unspecced event fields and types // Extend Matrix JS SDK types via Typescript declaration merging to support unspecced event fields and types

View File

@@ -5,7 +5,7 @@ SPDX-License-Identifier: AGPL-3.0-only
Please see LICENSE in the repository root for full details. Please see LICENSE in the repository root for full details.
*/ */
import { FC, Suspense, useEffect, useState } from "react"; import { type FC, Suspense, useEffect, useState } from "react";
import { import {
BrowserRouter as Router, BrowserRouter as Router,
Switch, Switch,
@@ -13,7 +13,7 @@ import {
useLocation, useLocation,
} from "react-router-dom"; } from "react-router-dom";
import * as Sentry from "@sentry/react"; import * as Sentry from "@sentry/react";
import { History } from "history"; import { type History } from "history";
import { TooltipProvider } from "@vector-im/compound-web"; import { TooltipProvider } from "@vector-im/compound-web";
import { logger } from "matrix-js-sdk/src/logger"; import { logger } from "matrix-js-sdk/src/logger";

View File

@@ -7,8 +7,8 @@ Please see LICENSE in the repository root for full details.
import { afterEach, expect, test, vi } from "vitest"; import { afterEach, expect, test, vi } from "vitest";
import { render, screen } from "@testing-library/react"; import { render, screen } from "@testing-library/react";
import { MatrixClient } from "matrix-js-sdk/src/client"; import { type MatrixClient } from "matrix-js-sdk/src/client";
import { FC, PropsWithChildren } from "react"; import { type FC, type PropsWithChildren } from "react";
import { ClientContextProvider } from "./ClientContext"; import { ClientContextProvider } from "./ClientContext";
import { Avatar } from "./Avatar"; import { Avatar } from "./Avatar";

View File

@@ -5,9 +5,15 @@ SPDX-License-Identifier: AGPL-3.0-only
Please see LICENSE in the repository root for full details. Please see LICENSE in the repository root for full details.
*/ */
import { useMemo, FC, CSSProperties, useState, useEffect } from "react"; import {
useMemo,
type FC,
type CSSProperties,
useState,
useEffect,
} from "react";
import { Avatar as CompoundAvatar } from "@vector-im/compound-web"; import { Avatar as CompoundAvatar } from "@vector-im/compound-web";
import { MatrixClient } from "matrix-js-sdk/src/client"; import { type MatrixClient } from "matrix-js-sdk/src/client";
import { useClientState } from "./ClientContext"; import { useClientState } from "./ClientContext";

View File

@@ -6,7 +6,7 @@ Please see LICENSE in the repository root for full details.
*/ */
import { import {
FC, type FC,
useCallback, useCallback,
useEffect, useEffect,
useState, useState,
@@ -18,7 +18,7 @@ import {
import { useHistory } from "react-router-dom"; import { useHistory } from "react-router-dom";
import { logger } from "matrix-js-sdk/src/logger"; import { logger } from "matrix-js-sdk/src/logger";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { ISyncStateData, SyncState } from "matrix-js-sdk/src/sync"; import { type ISyncStateData, type SyncState } from "matrix-js-sdk/src/sync";
import { ClientEvent, type MatrixClient } from "matrix-js-sdk/src/client"; import { ClientEvent, type MatrixClient } from "matrix-js-sdk/src/client";
import type { WidgetApi } from "matrix-widget-api"; import type { WidgetApi } from "matrix-widget-api";

View File

@@ -6,11 +6,11 @@ Please see LICENSE in the repository root for full details.
*/ */
import classNames from "classnames"; import classNames from "classnames";
import { FC, HTMLAttributes, ReactNode } from "react"; import { type FC, type HTMLAttributes, type ReactNode } from "react";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import styles from "./DisconnectedBanner.module.css"; import styles from "./DisconnectedBanner.module.css";
import { ValidClientState, useClientState } from "./ClientContext"; import { type ValidClientState, useClientState } from "./ClientContext";
interface Props extends HTMLAttributes<HTMLElement> { interface Props extends HTMLAttributes<HTMLElement> {
children?: ReactNode; children?: ReactNode;

View File

@@ -5,7 +5,7 @@ SPDX-License-Identifier: AGPL-3.0-only
Please see LICENSE in the repository root for full details. Please see LICENSE in the repository root for full details.
*/ */
import { FC, ReactNode, useCallback, useEffect } from "react"; import { type FC, type ReactNode, useCallback, useEffect } from "react";
import { useLocation } from "react-router-dom"; import { useLocation } from "react-router-dom";
import classNames from "classnames"; import classNames from "classnames";
import { Trans, useTranslation } from "react-i18next"; import { Trans, useTranslation } from "react-i18next";

View File

@@ -6,7 +6,12 @@ Please see LICENSE in the repository root for full details.
*/ */
import classNames from "classnames"; import classNames from "classnames";
import { FC, HTMLAttributes, ReactNode, forwardRef } from "react"; import {
type FC,
type HTMLAttributes,
type ReactNode,
forwardRef,
} from "react";
import { Link } from "react-router-dom"; import { Link } from "react-router-dom";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { Heading, Text } from "@vector-im/compound-web"; import { Heading, Text } from "@vector-im/compound-web";

View File

@@ -7,7 +7,7 @@ Please see LICENSE in the repository root for full details.
import { expect, test } from "vitest"; import { expect, test } from "vitest";
import { render } from "@testing-library/react"; import { render } from "@testing-library/react";
import { ReactNode, useState } from "react"; import { type ReactNode, useState } from "react";
import { afterEach } from "node:test"; import { afterEach } from "node:test";
import userEvent from "@testing-library/user-event"; import userEvent from "@testing-library/user-event";

View File

@@ -5,7 +5,7 @@ SPDX-License-Identifier: AGPL-3.0-only
Please see LICENSE in the repository root for full details. Please see LICENSE in the repository root for full details.
*/ */
import { FC, ReactNode, useCallback } from "react"; import { type FC, type ReactNode, useCallback } from "react";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { import {
Root as DialogRoot, Root as DialogRoot,

View File

@@ -5,7 +5,7 @@ SPDX-License-Identifier: AGPL-3.0-only
Please see LICENSE in the repository root for full details. Please see LICENSE in the repository root for full details.
*/ */
import { FC, useEffect, useState } from "react"; import { type FC, useEffect, useState } from "react";
import { toDataURL } from "qrcode"; import { toDataURL } from "qrcode";
import classNames from "classnames"; import classNames from "classnames";
import { t } from "i18next"; import { t } from "i18next";

View File

@@ -5,7 +5,7 @@ SPDX-License-Identifier: AGPL-3.0-only
Please see LICENSE in the repository root for full details. Please see LICENSE in the repository root for full details.
*/ */
import { FC, useCallback } from "react"; import { type FC, useCallback } from "react";
import { Root, Track, Range, Thumb } from "@radix-ui/react-slider"; import { Root, Track, Range, Thumb } from "@radix-ui/react-slider";
import classNames from "classnames"; import classNames from "classnames";
import { Tooltip } from "@vector-im/compound-web"; import { Tooltip } from "@vector-im/compound-web";

View File

@@ -6,9 +6,9 @@ Please see LICENSE in the repository root for full details.
*/ */
import { import {
ComponentType, type ComponentType,
FC, type FC,
SVGAttributes, type SVGAttributes,
useCallback, useCallback,
useEffect, useEffect,
} from "react"; } from "react";

View File

@@ -97,7 +97,102 @@ describe("UrlParams", () => {
}); });
it("respected in widget mode", () => { it("respected in widget mode", () => {
expect(getUrlParams("?preload=true&widgetId=12345").preload).toBe(true); expect(
getUrlParams(
"?preload=true&widgetId=12345&parentUrl=https%3A%2F%2Flocalhost%2Ffoo",
).preload,
).toBe(true);
});
});
describe("returnToLobby", () => {
it("is true in SPA mode", () => {
expect(getUrlParams("?returnToLobby=false").returnToLobby).toBe(true);
});
it("defaults to false in widget mode", () => {
expect(
getUrlParams("?widgetId=12345&parentUrl=https%3A%2F%2Flocalhost%2Ffoo")
.returnToLobby,
).toBe(false);
});
it("respected in widget mode", () => {
expect(
getUrlParams(
"?returnToLobby=true&widgetId=12345&parentUrl=https%3A%2F%2Flocalhost%2Ffoo",
).returnToLobby,
).toBe(true);
});
});
describe("userId", () => {
it("is ignored in SPA mode", () => {
expect(getUrlParams("?userId=asd").userId).toBe(null);
});
it("is parsed in widget mode", () => {
expect(
getUrlParams(
"?userId=asd&widgetId=12345&parentUrl=https%3A%2F%2Flocalhost%2Ffoo",
).userId,
).toBe("asd");
});
});
describe("deviceId", () => {
it("is ignored in SPA mode", () => {
expect(getUrlParams("?deviceId=asd").deviceId).toBe(null);
});
it("is parsed in widget mode", () => {
expect(
getUrlParams(
"?deviceId=asd&widgetId=12345&parentUrl=https%3A%2F%2Flocalhost%2Ffoo",
).deviceId,
).toBe("asd");
});
});
describe("baseUrl", () => {
it("is ignored in SPA mode", () => {
expect(getUrlParams("?baseUrl=asd").baseUrl).toBe(null);
});
it("is parsed in widget mode", () => {
expect(
getUrlParams(
"?baseUrl=asd&widgetId=12345&parentUrl=https%3A%2F%2Flocalhost%2Ffoo",
).baseUrl,
).toBe("asd");
});
});
describe("viaServers", () => {
it("is ignored in widget mode", () => {
expect(
getUrlParams(
"?viaServers=asd&widgetId=12345&parentUrl=https%3A%2F%2Flocalhost%2Ffoo",
).viaServers,
).toBe(null);
});
it("is parsed in SPA mode", () => {
expect(getUrlParams("?viaServers=asd").viaServers).toBe("asd");
});
});
describe("homeserver", () => {
it("is ignored in widget mode", () => {
expect(
getUrlParams(
"?homeserver=asd&widgetId=12345&parentUrl=https%3A%2F%2Flocalhost%2Ffoo",
).homeserver,
).toBe(null);
});
it("is parsed in SPA mode", () => {
expect(getUrlParams("?homeserver=asd").homeserver).toBe("asd");
}); });
}); });
}); });

View File

@@ -10,7 +10,7 @@ import { useLocation } from "react-router-dom";
import { logger } from "matrix-js-sdk/src/logger"; import { logger } from "matrix-js-sdk/src/logger";
import { Config } from "./config/Config"; import { Config } from "./config/Config";
import { EncryptionSystem } from "./e2ee/sharedKeyManagement"; import { type EncryptionSystem } from "./e2ee/sharedKeyManagement";
import { E2eeType } from "./e2ee/e2eeType"; import { E2eeType } from "./e2ee/e2eeType";
interface RoomIdentifier { interface RoomIdentifier {
@@ -212,11 +212,12 @@ export const getUrlParams = (
const fontScale = parseFloat(parser.getParam("fontScale") ?? ""); const fontScale = parseFloat(parser.getParam("fontScale") ?? "");
const widgetId = parser.getParam("widgetId"); const widgetId = parser.getParam("widgetId");
const isWidget = !!widgetId; const parentUrl = parser.getParam("parentUrl");
const isWidget = !!widgetId && !!parentUrl;
return { return {
widgetId, widgetId,
parentUrl: parser.getParam("parentUrl"), parentUrl,
// NB. we don't validate roomId here as we do in getRoomIdentifierFromUrl: // NB. we don't validate roomId here as we do in getRoomIdentifierFromUrl:
// what would we do if it were invalid? If the widget API says that's what // what would we do if it were invalid? If the widget API says that's what
@@ -232,10 +233,10 @@ export const getUrlParams = (
showControls: parser.getFlagParam("showControls", true), showControls: parser.getFlagParam("showControls", true),
hideScreensharing: parser.getFlagParam("hideScreensharing"), hideScreensharing: parser.getFlagParam("hideScreensharing"),
e2eEnabled: parser.getFlagParam("enableE2EE", true), e2eEnabled: parser.getFlagParam("enableE2EE", true),
userId: parser.getParam("userId"), userId: isWidget ? parser.getParam("userId") : null,
displayName: parser.getParam("displayName"), displayName: parser.getParam("displayName"),
deviceId: parser.getParam("deviceId"), deviceId: isWidget ? parser.getParam("deviceId") : null,
baseUrl: parser.getParam("baseUrl"), baseUrl: isWidget ? parser.getParam("baseUrl") : null,
lang: parser.getParam("lang"), lang: parser.getParam("lang"),
fonts: parser.getAllParams("font"), fonts: parser.getAllParams("font"),
fontScale: Number.isNaN(fontScale) ? null : fontScale, fontScale: Number.isNaN(fontScale) ? null : fontScale,
@@ -243,10 +244,10 @@ export const getUrlParams = (
allowIceFallback: parser.getFlagParam("allowIceFallback"), allowIceFallback: parser.getFlagParam("allowIceFallback"),
perParticipantE2EE: parser.getFlagParam("perParticipantE2EE"), perParticipantE2EE: parser.getFlagParam("perParticipantE2EE"),
skipLobby: parser.getFlagParam("skipLobby"), skipLobby: parser.getFlagParam("skipLobby"),
returnToLobby: parser.getFlagParam("returnToLobby"), returnToLobby: isWidget ? parser.getFlagParam("returnToLobby") : true,
theme: parser.getParam("theme"), theme: parser.getParam("theme"),
viaServers: parser.getParam("viaServers"), viaServers: !isWidget ? parser.getParam("viaServers") : null,
homeserver: parser.getParam("homeserver"), homeserver: !isWidget ? parser.getParam("homeserver") : null,
}; };
}; };

View File

@@ -5,7 +5,7 @@ SPDX-License-Identifier: AGPL-3.0-only
Please see LICENSE in the repository root for full details. Please see LICENSE in the repository root for full details.
*/ */
import { FC, useMemo, useState } from "react"; import { type FC, useMemo, useState } from "react";
import { useLocation } from "react-router-dom"; import { useLocation } from "react-router-dom";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { Menu, MenuItem } from "@vector-im/compound-web"; import { Menu, MenuItem } from "@vector-im/compound-web";

View File

@@ -5,7 +5,7 @@ SPDX-License-Identifier: AGPL-3.0-only
Please see LICENSE in the repository root for full details. Please see LICENSE in the repository root for full details.
*/ */
import { FC, useCallback, useState } from "react"; import { type FC, useCallback, useState } from "react";
import { useHistory, useLocation } from "react-router-dom"; import { useHistory, useLocation } from "react-router-dom";
import { useClientLegacy } from "./ClientContext"; import { useClientLegacy } from "./ClientContext";

View File

@@ -5,7 +5,7 @@ SPDX-License-Identifier: AGPL-3.0-only
Please see LICENSE in the repository root for full details. Please see LICENSE in the repository root for full details.
*/ */
import { FC } from "react"; import { type FC } from "react";
import { Trans } from "react-i18next"; import { Trans } from "react-i18next";
import { ExternalLink } from "../button/Link"; import { ExternalLink } from "../button/Link";

View File

@@ -5,9 +5,13 @@ SPDX-License-Identifier: AGPL-3.0-only
Please see LICENSE in the repository root for full details. Please see LICENSE in the repository root for full details.
*/ */
import posthog, { CaptureOptions, PostHog, Properties } from "posthog-js"; import posthog, {
type CaptureOptions,
type PostHog,
type Properties,
} from "posthog-js";
import { logger } from "matrix-js-sdk/src/logger"; import { logger } from "matrix-js-sdk/src/logger";
import { MatrixClient } from "matrix-js-sdk/src/matrix"; import { type MatrixClient } from "matrix-js-sdk/src/matrix";
import { Buffer } from "buffer"; import { Buffer } from "buffer";
import { widget } from "../widget"; import { widget } from "../widget";

View File

@@ -5,12 +5,12 @@ SPDX-License-Identifier: AGPL-3.0-only
Please see LICENSE in the repository root for full details. Please see LICENSE in the repository root for full details.
*/ */
import { DisconnectReason } from "livekit-client"; import { type DisconnectReason } from "livekit-client";
import { logger } from "matrix-js-sdk/src/logger"; import { logger } from "matrix-js-sdk/src/logger";
import { MatrixRTCSession } from "matrix-js-sdk/src/matrixrtc"; import { type MatrixRTCSession } from "matrix-js-sdk/src/matrixrtc";
import { import {
IPosthogEvent, type IPosthogEvent,
PosthogAnalytics, PosthogAnalytics,
RegistrationType, RegistrationType,
} from "./PosthogAnalytics"; } from "./PosthogAnalytics";

View File

@@ -6,9 +6,9 @@ Please see LICENSE in the repository root for full details.
*/ */
import { import {
SpanProcessor, type SpanProcessor,
ReadableSpan, type ReadableSpan,
Span, type Span,
} from "@opentelemetry/sdk-trace-base"; } from "@opentelemetry/sdk-trace-base";
import { hrTimeToMilliseconds } from "@opentelemetry/core"; import { hrTimeToMilliseconds } from "@opentelemetry/core";
import { logger } from "matrix-js-sdk/src/logger"; import { logger } from "matrix-js-sdk/src/logger";

View File

@@ -5,12 +5,12 @@ SPDX-License-Identifier: AGPL-3.0-only
Please see LICENSE in the repository root for full details. Please see LICENSE in the repository root for full details.
*/ */
import { AttributeValue, Attributes } from "@opentelemetry/api"; import { type AttributeValue, type Attributes } from "@opentelemetry/api";
import { hrTimeToMicroseconds } from "@opentelemetry/core"; import { hrTimeToMicroseconds } from "@opentelemetry/core";
import { import {
SpanProcessor, type SpanProcessor,
ReadableSpan, type ReadableSpan,
Span, type Span,
} from "@opentelemetry/sdk-trace-base"; } from "@opentelemetry/sdk-trace-base";
const dumpAttributes = ( const dumpAttributes = (

View File

@@ -5,7 +5,7 @@ SPDX-License-Identifier: AGPL-3.0-only
Please see LICENSE in the repository root for full details. Please see LICENSE in the repository root for full details.
*/ */
import { FC, FormEvent, useCallback, useRef, useState } from "react"; import { type FC, type FormEvent, useCallback, useRef, useState } from "react";
import { useHistory, useLocation } from "react-router-dom"; import { useHistory, useLocation } from "react-router-dom";
import { Trans, useTranslation } from "react-i18next"; import { Trans, useTranslation } from "react-i18next";
import { Button } from "@vector-im/compound-web"; import { Button } from "@vector-im/compound-web";

View File

@@ -6,9 +6,9 @@ Please see LICENSE in the repository root for full details.
*/ */
import { import {
ChangeEvent, type ChangeEvent,
FC, type FC,
FormEvent, type FormEvent,
useCallback, useCallback,
useEffect, useEffect,
useRef, useRef,

View File

@@ -9,12 +9,12 @@ import { useCallback } from "react";
import { InteractiveAuth } from "matrix-js-sdk/src/interactive-auth"; import { InteractiveAuth } from "matrix-js-sdk/src/interactive-auth";
import { import {
createClient, createClient,
LoginResponse, type LoginResponse,
MatrixClient, type MatrixClient,
} from "matrix-js-sdk/src/matrix"; } from "matrix-js-sdk/src/matrix";
import { initClient } from "../utils/matrix"; import { initClient } from "../utils/matrix";
import { Session } from "../ClientContext"; import { type Session } from "../ClientContext";
/** /**
* This provides the login method to login using user credentials. * This provides the login method to login using user credentials.
* @param oldClient If there is an already authenticated client it should be passed to this hook * @param oldClient If there is an already authenticated client it should be passed to this hook

View File

@@ -9,13 +9,13 @@ import { useState, useEffect, useCallback, useRef } from "react";
import { InteractiveAuth } from "matrix-js-sdk/src/interactive-auth"; import { InteractiveAuth } from "matrix-js-sdk/src/interactive-auth";
import { import {
createClient, createClient,
MatrixClient, type MatrixClient,
RegisterResponse, type RegisterResponse,
} from "matrix-js-sdk/src/matrix"; } from "matrix-js-sdk/src/matrix";
import { logger } from "matrix-js-sdk/src/logger"; import { logger } from "matrix-js-sdk/src/logger";
import { initClient } from "../utils/matrix"; import { initClient } from "../utils/matrix";
import { Session } from "../ClientContext"; import { type Session } from "../ClientContext";
import { Config } from "../config/Config"; import { Config } from "../config/Config";
import { widget } from "../widget"; import { widget } from "../widget";

View File

@@ -4,7 +4,7 @@ Copyright 2022-2024 New Vector Ltd.
SPDX-License-Identifier: AGPL-3.0-only SPDX-License-Identifier: AGPL-3.0-only
Please see LICENSE in the repository root for full details. Please see LICENSE in the repository root for full details.
*/ */
import { ComponentPropsWithoutRef, FC } from "react"; import { type ComponentPropsWithoutRef, type FC } from "react";
import classNames from "classnames"; import classNames from "classnames";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { Button as CpdButton, Tooltip } from "@vector-im/compound-web"; import { Button as CpdButton, Tooltip } from "@vector-im/compound-web";

View File

@@ -5,7 +5,7 @@ SPDX-License-Identifier: AGPL-3.0-only
Please see LICENSE in the repository root for full details. Please see LICENSE in the repository root for full details.
*/ */
import { ComponentPropsWithoutRef, FC } from "react"; import { type ComponentPropsWithoutRef, type FC } from "react";
import { Button } from "@vector-im/compound-web"; import { Button } from "@vector-im/compound-web";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { UserAddIcon } from "@vector-im/compound-design-tokens/assets/web/icons"; import { UserAddIcon } from "@vector-im/compound-design-tokens/assets/web/icons";

View File

@@ -6,15 +6,15 @@ Please see LICENSE in the repository root for full details.
*/ */
import { import {
ComponentPropsWithoutRef, type ComponentPropsWithoutRef,
forwardRef, forwardRef,
MouseEvent, type MouseEvent,
useCallback, useCallback,
useMemo, useMemo,
} from "react"; } from "react";
import { Link as CpdLink } from "@vector-im/compound-web"; import { Link as CpdLink } from "@vector-im/compound-web";
import { useHistory } from "react-router-dom"; import { useHistory } from "react-router-dom";
import { createPath, LocationDescriptor, Path } from "history"; import { createPath, type LocationDescriptor, type Path } from "history";
import classNames from "classnames"; import classNames from "classnames";
import { useLatest } from "../useLatest"; import { useLatest } from "../useLatest";

View File

@@ -5,9 +5,9 @@ SPDX-License-Identifier: AGPL-3.0-only
Please see LICENSE in the repository root for full details. Please see LICENSE in the repository root for full details.
*/ */
import { ComponentPropsWithoutRef, forwardRef } from "react"; import { type ComponentPropsWithoutRef, forwardRef } from "react";
import { Button } from "@vector-im/compound-web"; import { Button } from "@vector-im/compound-web";
import { LocationDescriptor } from "history"; import { type LocationDescriptor } from "history";
import { useLink } from "./Link"; import { useLink } from "./Link";

View File

@@ -9,7 +9,7 @@ import { act, render } from "@testing-library/react";
import { expect, test } from "vitest"; import { expect, test } from "vitest";
import { TooltipProvider } from "@vector-im/compound-web"; import { TooltipProvider } from "@vector-im/compound-web";
import { userEvent } from "@testing-library/user-event"; import { userEvent } from "@testing-library/user-event";
import { ReactNode } from "react"; import { type ReactNode } from "react";
import { MockRoom } from "../utils/testReactions"; import { MockRoom } from "../utils/testReactions";
import { ReactionToggleButton } from "./ReactionToggleButton"; import { ReactionToggleButton } from "./ReactionToggleButton";

View File

@@ -13,9 +13,9 @@ import {
ReactionSolidIcon, ReactionSolidIcon,
} from "@vector-im/compound-design-tokens/assets/web/icons"; } from "@vector-im/compound-design-tokens/assets/web/icons";
import { import {
ComponentPropsWithoutRef, type ComponentPropsWithoutRef,
FC, type FC,
ReactNode, type ReactNode,
useCallback, useCallback,
useEffect, useEffect,
useMemo, useMemo,
@@ -29,7 +29,11 @@ import { map } from "rxjs";
import { useReactions } from "../useReactions"; import { useReactions } from "../useReactions";
import styles from "./ReactionToggleButton.module.css"; import styles from "./ReactionToggleButton.module.css";
import { ReactionOption, ReactionSet, ReactionsRowSize } from "../reactions"; import {
type ReactionOption,
ReactionSet,
ReactionsRowSize,
} from "../reactions";
import { Modal } from "../Modal"; import { Modal } from "../Modal";
import { CallViewModel } from "../state/CallViewModel"; import { CallViewModel } from "../state/CallViewModel";

View File

@@ -10,8 +10,8 @@ import { merge } from "lodash-es";
import { getUrlParams } from "../UrlParams"; import { getUrlParams } from "../UrlParams";
import { import {
DEFAULT_CONFIG, DEFAULT_CONFIG,
ConfigOptions, type ConfigOptions,
ResolvedConfigOptions, type ResolvedConfigOptions,
} from "./ConfigOptions"; } from "./ConfigOptions";
export class Config { export class Config {

View File

@@ -7,7 +7,7 @@ Please see LICENSE in the repository root for full details.
import { describe, expect, test, vi } from "vitest"; import { describe, expect, test, vi } from "vitest";
import { import {
MatrixRTCSession, type MatrixRTCSession,
MatrixRTCSessionEvent, MatrixRTCSessionEvent,
} from "matrix-js-sdk/src/matrixrtc"; } from "matrix-js-sdk/src/matrixrtc";
import { KeyProviderEvent } from "livekit-client"; import { KeyProviderEvent } from "livekit-client";

View File

@@ -8,7 +8,7 @@ Please see LICENSE in the repository root for full details.
import { BaseKeyProvider, createKeyMaterialFromBuffer } from "livekit-client"; import { BaseKeyProvider, createKeyMaterialFromBuffer } from "livekit-client";
import { logger } from "matrix-js-sdk/src/logger"; import { logger } from "matrix-js-sdk/src/logger";
import { import {
MatrixRTCSession, type MatrixRTCSession,
MatrixRTCSessionEvent, MatrixRTCSessionEvent,
} from "matrix-js-sdk/src/matrixrtc/MatrixRTCSession"; } from "matrix-js-sdk/src/matrixrtc/MatrixRTCSession";

View File

@@ -8,7 +8,7 @@ Please see LICENSE in the repository root for full details.
import { useEffect, useMemo } from "react"; import { useEffect, useMemo } from "react";
import { setLocalStorageItem, useLocalStorage } from "../useLocalStorage"; import { setLocalStorageItem, useLocalStorage } from "../useLocalStorage";
import { UrlParams, getUrlParams, useUrlParams } from "../UrlParams"; import { type UrlParams, getUrlParams, useUrlParams } from "../UrlParams";
import { E2eeType } from "./e2eeType"; import { E2eeType } from "./e2eeType";
import { useClient } from "../ClientContext"; import { useClient } from "../ClientContext";

View File

@@ -6,7 +6,7 @@ Please see LICENSE in the repository root for full details.
*/ */
import classNames from "classnames"; import classNames from "classnames";
import { FormEventHandler, forwardRef, ReactNode } from "react"; import { type FormEventHandler, forwardRef, type ReactNode } from "react";
import styles from "./Form.module.css"; import styles from "./Form.module.css";

View File

@@ -5,11 +5,11 @@ SPDX-License-Identifier: AGPL-3.0-only
Please see LICENSE in the repository root for full details. Please see LICENSE in the repository root for full details.
*/ */
import { BehaviorSubject, Observable } from "rxjs"; import { type BehaviorSubject, type Observable } from "rxjs";
import { ComponentType } from "react"; import { type ComponentType } from "react";
import { LayoutProps } from "./Grid"; import { type LayoutProps } from "./Grid";
import { TileViewModel } from "../state/TileViewModel"; import { type TileViewModel } from "../state/TileViewModel";
export interface Bounds { export interface Bounds {
width: number; width: number;

View File

@@ -6,21 +6,21 @@ Please see LICENSE in the repository root for full details.
*/ */
import { import {
SpringRef, type SpringRef,
TransitionFn, type TransitionFn,
animated, type animated,
useTransition, useTransition,
} from "@react-spring/web"; } from "@react-spring/web";
import { EventTypes, Handler, useScroll } from "@use-gesture/react"; import { type EventTypes, type Handler, useScroll } from "@use-gesture/react";
import { import {
CSSProperties, type CSSProperties,
ComponentProps, type ComponentProps,
ComponentType, type ComponentType,
Dispatch, type Dispatch,
FC, type FC,
LegacyRef, type LegacyRef,
ReactNode, type ReactNode,
SetStateAction, type SetStateAction,
createContext, createContext,
forwardRef, forwardRef,
memo, memo,

View File

@@ -5,15 +5,15 @@ SPDX-License-Identifier: AGPL-3.0-only
Please see LICENSE in the repository root for full details. Please see LICENSE in the repository root for full details.
*/ */
import { CSSProperties, forwardRef, useCallback, useMemo } from "react"; import { type CSSProperties, forwardRef, useCallback, useMemo } from "react";
import { distinctUntilChanged } from "rxjs"; import { distinctUntilChanged } from "rxjs";
import { useObservableEagerState } from "observable-hooks"; import { useObservableEagerState } from "observable-hooks";
import { GridLayout as GridLayoutModel } from "../state/CallViewModel"; import { type GridLayout as GridLayoutModel } from "../state/CallViewModel";
import styles from "./GridLayout.module.css"; import styles from "./GridLayout.module.css";
import { useInitial } from "../useInitial"; import { useInitial } from "../useInitial";
import { CallLayout, arrangeTiles } from "./CallLayout"; import { type CallLayout, arrangeTiles } from "./CallLayout";
import { DragCallback, useUpdateLayout } from "./Grid"; import { type DragCallback, useUpdateLayout } from "./Grid";
interface GridCSSProperties extends CSSProperties { interface GridCSSProperties extends CSSProperties {
"--gap": string; "--gap": string;

View File

@@ -9,10 +9,10 @@ import { forwardRef, useCallback, useMemo } from "react";
import { useObservableEagerState } from "observable-hooks"; import { useObservableEagerState } from "observable-hooks";
import classNames from "classnames"; import classNames from "classnames";
import { OneOnOneLayout as OneOnOneLayoutModel } from "../state/CallViewModel"; import { type OneOnOneLayout as OneOnOneLayoutModel } from "../state/CallViewModel";
import { CallLayout, arrangeTiles } from "./CallLayout"; import { type CallLayout, arrangeTiles } from "./CallLayout";
import styles from "./OneOnOneLayout.module.css"; import styles from "./OneOnOneLayout.module.css";
import { DragCallback, useUpdateLayout } from "./Grid"; import { type DragCallback, useUpdateLayout } from "./Grid";
/** /**
* An implementation of the "one-on-one" layout, in which the remote participant * An implementation of the "one-on-one" layout, in which the remote participant

View File

@@ -8,9 +8,9 @@ Please see LICENSE in the repository root for full details.
import { forwardRef, useCallback } from "react"; import { forwardRef, useCallback } from "react";
import { useObservableEagerState } from "observable-hooks"; import { useObservableEagerState } from "observable-hooks";
import { SpotlightExpandedLayout as SpotlightExpandedLayoutModel } from "../state/CallViewModel"; import { type SpotlightExpandedLayout as SpotlightExpandedLayoutModel } from "../state/CallViewModel";
import { CallLayout } from "./CallLayout"; import { type CallLayout } from "./CallLayout";
import { DragCallback, useUpdateLayout } from "./Grid"; import { type DragCallback, useUpdateLayout } from "./Grid";
import styles from "./SpotlightExpandedLayout.module.css"; import styles from "./SpotlightExpandedLayout.module.css";
/** /**

View File

@@ -9,8 +9,8 @@ import { forwardRef } from "react";
import { useObservableEagerState } from "observable-hooks"; import { useObservableEagerState } from "observable-hooks";
import classNames from "classnames"; import classNames from "classnames";
import { CallLayout } from "./CallLayout"; import { type CallLayout } from "./CallLayout";
import { SpotlightLandscapeLayout as SpotlightLandscapeLayoutModel } from "../state/CallViewModel"; import { type SpotlightLandscapeLayout as SpotlightLandscapeLayoutModel } from "../state/CallViewModel";
import styles from "./SpotlightLandscapeLayout.module.css"; import styles from "./SpotlightLandscapeLayout.module.css";
import { useUpdateLayout } from "./Grid"; import { useUpdateLayout } from "./Grid";

View File

@@ -5,12 +5,12 @@ SPDX-License-Identifier: AGPL-3.0-only
Please see LICENSE in the repository root for full details. Please see LICENSE in the repository root for full details.
*/ */
import { CSSProperties, forwardRef } from "react"; import { type CSSProperties, forwardRef } from "react";
import { useObservableEagerState } from "observable-hooks"; import { useObservableEagerState } from "observable-hooks";
import classNames from "classnames"; import classNames from "classnames";
import { CallLayout, arrangeTiles } from "./CallLayout"; import { type CallLayout, arrangeTiles } from "./CallLayout";
import { SpotlightPortraitLayout as SpotlightPortraitLayoutModel } from "../state/CallViewModel"; import { type SpotlightPortraitLayout as SpotlightPortraitLayoutModel } from "../state/CallViewModel";
import styles from "./SpotlightPortraitLayout.module.css"; import styles from "./SpotlightPortraitLayout.module.css";
import { useUpdateLayout } from "./Grid"; import { useUpdateLayout } from "./Grid";

View File

@@ -5,12 +5,12 @@ SPDX-License-Identifier: AGPL-3.0-only
Please see LICENSE in the repository root for full details. Please see LICENSE in the repository root for full details.
*/ */
import { ComponentType, memo, RefObject, useRef } from "react"; import { type ComponentType, memo, type RefObject, useRef } from "react";
import { EventTypes, Handler, useDrag } from "@use-gesture/react"; import { type EventTypes, type Handler, useDrag } from "@use-gesture/react";
import { SpringValue } from "@react-spring/web"; import { type SpringValue } from "@react-spring/web";
import classNames from "classnames"; import classNames from "classnames";
import { TileProps } from "./Grid"; import { type TileProps } from "./Grid";
import styles from "./TileWrapper.module.css"; import styles from "./TileWrapper.module.css";
interface Props<M, R extends HTMLElement> { interface Props<M, R extends HTMLElement> {

View File

@@ -5,13 +5,13 @@ SPDX-License-Identifier: AGPL-3.0-only
Please see LICENSE in the repository root for full details. Please see LICENSE in the repository root for full details.
*/ */
import { render, RenderResult } from "@testing-library/react"; import { render, type RenderResult } from "@testing-library/react";
import { MatrixClient } from "matrix-js-sdk/src/matrix"; import { type MatrixClient } from "matrix-js-sdk/src/matrix";
import { MemoryRouter } from "react-router-dom"; import { MemoryRouter } from "react-router-dom";
import { describe, expect, it } from "vitest"; import { describe, expect, it } from "vitest";
import { CallList } from "../../src/home/CallList"; import { CallList } from "../../src/home/CallList";
import { GroupCallRoom } from "../../src/home/useGroupCallRooms"; import { type GroupCallRoom } from "../../src/home/useGroupCallRooms";
describe("CallList", () => { describe("CallList", () => {
const renderComponent = (rooms: GroupCallRoom[]): RenderResult => { const renderComponent = (rooms: GroupCallRoom[]): RenderResult => {

View File

@@ -6,10 +6,10 @@ Please see LICENSE in the repository root for full details.
*/ */
import { Link } from "react-router-dom"; import { Link } from "react-router-dom";
import { MatrixClient } from "matrix-js-sdk/src/client"; import { type MatrixClient } from "matrix-js-sdk/src/client";
import { RoomMember } from "matrix-js-sdk/src/models/room-member"; import { type RoomMember } from "matrix-js-sdk/src/models/room-member";
import { Room } from "matrix-js-sdk/src/models/room"; import { type Room } from "matrix-js-sdk/src/models/room";
import { FC, useCallback, MouseEvent, useState } from "react"; import { type FC, useCallback, type MouseEvent, useState } from "react";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { IconButton, Text } from "@vector-im/compound-web"; import { IconButton, Text } from "@vector-im/compound-web";
import { CloseIcon } from "@vector-im/compound-design-tokens/assets/web/icons"; import { CloseIcon } from "@vector-im/compound-design-tokens/assets/web/icons";
@@ -18,7 +18,7 @@ import classNames from "classnames";
import { Avatar, Size } from "../Avatar"; import { Avatar, Size } from "../Avatar";
import styles from "./CallList.module.css"; import styles from "./CallList.module.css";
import { getRelativeRoomUrl } from "../utils/matrix"; import { getRelativeRoomUrl } from "../utils/matrix";
import { GroupCallRoom } from "./useGroupCallRooms"; import { type GroupCallRoom } from "./useGroupCallRooms";
import { useRoomEncryptionSystem } from "../e2ee/sharedKeyManagement"; import { useRoomEncryptionSystem } from "../e2ee/sharedKeyManagement";
interface CallListProps { interface CallListProps {

View File

@@ -6,7 +6,7 @@ Please see LICENSE in the repository root for full details.
*/ */
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { FC } from "react"; import { type FC } from "react";
import { useClientState } from "../ClientContext"; import { useClientState } from "../ClientContext";
import { ErrorView, LoadingView } from "../FullScreenView"; import { ErrorView, LoadingView } from "../FullScreenView";

View File

@@ -6,7 +6,7 @@ Please see LICENSE in the repository root for full details.
*/ */
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { FC, MouseEvent } from "react"; import { type FC, type MouseEvent } from "react";
import { Button } from "@vector-im/compound-web"; import { Button } from "@vector-im/compound-web";
import { Modal } from "../Modal"; import { Modal } from "../Modal";

View File

@@ -5,9 +5,15 @@ SPDX-License-Identifier: AGPL-3.0-only
Please see LICENSE in the repository root for full details. Please see LICENSE in the repository root for full details.
*/ */
import { useState, useCallback, FormEvent, FormEventHandler, FC } from "react"; import {
useState,
useCallback,
type FormEvent,
type FormEventHandler,
type FC,
} from "react";
import { useHistory } from "react-router-dom"; import { useHistory } from "react-router-dom";
import { MatrixClient } from "matrix-js-sdk/src/client"; import { type MatrixClient } from "matrix-js-sdk/src/client";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { Heading, Text } from "@vector-im/compound-web"; import { Heading, Text } from "@vector-im/compound-web";
import { logger } from "matrix-js-sdk/src/logger"; import { logger } from "matrix-js-sdk/src/logger";

View File

@@ -5,7 +5,7 @@ SPDX-License-Identifier: AGPL-3.0-only
Please see LICENSE in the repository root for full details. Please see LICENSE in the repository root for full details.
*/ */
import { FC, useCallback, useState, FormEventHandler } from "react"; import { type FC, useCallback, useState, type FormEventHandler } from "react";
import { useHistory } from "react-router-dom"; import { useHistory } from "react-router-dom";
import { randomString } from "matrix-js-sdk/src/randomstring"; import { randomString } from "matrix-js-sdk/src/randomstring";
import { Trans, useTranslation } from "react-i18next"; import { Trans, useTranslation } from "react-i18next";

View File

@@ -5,12 +5,12 @@ SPDX-License-Identifier: AGPL-3.0-only
Please see LICENSE in the repository root for full details. Please see LICENSE in the repository root for full details.
*/ */
import { MatrixClient } from "matrix-js-sdk/src/client"; import { type MatrixClient } from "matrix-js-sdk/src/client";
import { Room, RoomEvent } from "matrix-js-sdk/src/models/room"; import { type Room, RoomEvent } from "matrix-js-sdk/src/models/room";
import { RoomMember } from "matrix-js-sdk/src/models/room-member"; import { type RoomMember } from "matrix-js-sdk/src/models/room-member";
import { useState, useEffect } from "react"; import { useState, useEffect } from "react";
import { EventTimeline, EventType, JoinRule } from "matrix-js-sdk/src/matrix"; import { EventTimeline, EventType, JoinRule } from "matrix-js-sdk/src/matrix";
import { MatrixRTCSession } from "matrix-js-sdk/src/matrixrtc/MatrixRTCSession"; import { type MatrixRTCSession } from "matrix-js-sdk/src/matrixrtc/MatrixRTCSession";
import { MatrixRTCSessionManagerEvents } from "matrix-js-sdk/src/matrixrtc/MatrixRTCSessionManager"; import { MatrixRTCSessionManagerEvents } from "matrix-js-sdk/src/matrixrtc/MatrixRTCSessionManager";
import { KnownMembership } from "matrix-js-sdk/src/types"; import { KnownMembership } from "matrix-js-sdk/src/types";

View File

@@ -6,13 +6,13 @@ Please see LICENSE in the repository root for full details.
*/ */
import { import {
AllHTMLAttributes, type AllHTMLAttributes,
useEffect, useEffect,
useCallback, useCallback,
useState, useState,
ChangeEvent, type ChangeEvent,
useRef, useRef,
FC, type FC,
} from "react"; } from "react";
import classNames from "classnames"; import classNames from "classnames";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";

View File

@@ -6,11 +6,11 @@ Please see LICENSE in the repository root for full details.
*/ */
import { import {
ChangeEvent, type ChangeEvent,
FC, type FC,
ForwardedRef, type ForwardedRef,
forwardRef, forwardRef,
ReactNode, type ReactNode,
useId, useId,
} from "react"; } from "react";
import classNames from "classnames"; import classNames from "classnames";

View File

@@ -6,7 +6,7 @@ Please see LICENSE in the repository root for full details.
*/ */
import { import {
FC, type FC,
createContext, createContext,
useCallback, useCallback,
useContext, useContext,
@@ -16,7 +16,7 @@ import {
useState, useState,
} from "react"; } from "react";
import { createMediaDeviceObserver } from "@livekit/components-core"; import { createMediaDeviceObserver } from "@livekit/components-core";
import { Observable } from "rxjs"; import { type Observable } from "rxjs";
import { logger } from "matrix-js-sdk/src/logger"; import { logger } from "matrix-js-sdk/src/logger";
import { import {
@@ -24,7 +24,7 @@ import {
audioInput as audioInputSetting, audioInput as audioInputSetting,
audioOutput as audioOutputSetting, audioOutput as audioOutputSetting,
videoInput as videoInputSetting, videoInput as videoInputSetting,
Setting, type Setting,
} from "../settings/settings"; } from "../settings/settings";
import { isFirefox } from "../Platform"; import { isFirefox } from "../Platform";

View File

@@ -5,11 +5,11 @@ SPDX-License-Identifier: AGPL-3.0-only
Please see LICENSE in the repository root for full details. Please see LICENSE in the repository root for full details.
*/ */
import { IOpenIDToken, MatrixClient } from "matrix-js-sdk/src/matrix"; import { type IOpenIDToken, type MatrixClient } from "matrix-js-sdk/src/matrix";
import { logger } from "matrix-js-sdk/src/logger"; import { logger } from "matrix-js-sdk/src/logger";
import { MatrixRTCSession } from "matrix-js-sdk/src/matrixrtc/MatrixRTCSession"; import { type MatrixRTCSession } from "matrix-js-sdk/src/matrixrtc/MatrixRTCSession";
import { useEffect, useState } from "react"; import { useEffect, useState } from "react";
import { LivekitFocus } from "matrix-js-sdk/src/matrixrtc/LivekitFocus"; import { type LivekitFocus } from "matrix-js-sdk/src/matrixrtc/LivekitFocus";
import { useActiveLivekitFocus } from "../room/useActiveFocus"; import { useActiveLivekitFocus } from "../room/useActiveFocus";

View File

@@ -8,10 +8,10 @@ Please see LICENSE in the repository root for full details.
import { import {
AudioPresets, AudioPresets,
DefaultReconnectPolicy, DefaultReconnectPolicy,
RoomOptions, type RoomOptions,
ScreenSharePresets, ScreenSharePresets,
TrackPublishDefaults, type TrackPublishDefaults,
VideoPreset, type VideoPreset,
VideoPresets, VideoPresets,
} from "livekit-client"; } from "livekit-client";

View File

@@ -6,10 +6,10 @@ Please see LICENSE in the repository root for full details.
*/ */
import { import {
AudioCaptureOptions, type AudioCaptureOptions,
ConnectionState, ConnectionState,
LocalTrack, type LocalTrack,
Room, type Room,
RoomEvent, RoomEvent,
Track, Track,
} from "livekit-client"; } from "livekit-client";
@@ -17,7 +17,7 @@ import { useCallback, useEffect, useRef, useState } from "react";
import { logger } from "matrix-js-sdk/src/logger"; import { logger } from "matrix-js-sdk/src/logger";
import * as Sentry from "@sentry/react"; import * as Sentry from "@sentry/react";
import { SFUConfig, sfuConfigEquals } from "./openIDSFU"; import { type SFUConfig, sfuConfigEquals } from "./openIDSFU";
import { PosthogAnalytics } from "../analytics/PosthogAnalytics"; import { PosthogAnalytics } from "../analytics/PosthogAnalytics";
declare global { declare global {

View File

@@ -7,32 +7,32 @@ Please see LICENSE in the repository root for full details.
import { import {
ConnectionState, ConnectionState,
E2EEOptions, type E2EEOptions,
ExternalE2EEKeyProvider, ExternalE2EEKeyProvider,
Room, Room,
RoomOptions, type RoomOptions,
Track, Track,
} from "livekit-client"; } from "livekit-client";
import { useEffect, useMemo, useRef } from "react"; import { useEffect, useMemo, useRef } from "react";
import E2EEWorker from "livekit-client/e2ee-worker?worker"; import E2EEWorker from "livekit-client/e2ee-worker?worker";
import { logger } from "matrix-js-sdk/src/logger"; import { logger } from "matrix-js-sdk/src/logger";
import { MatrixRTCSession } from "matrix-js-sdk/src/matrixrtc/MatrixRTCSession"; import { type MatrixRTCSession } from "matrix-js-sdk/src/matrixrtc/MatrixRTCSession";
import { defaultLiveKitOptions } from "./options"; import { defaultLiveKitOptions } from "./options";
import { SFUConfig } from "./openIDSFU"; import { type SFUConfig } from "./openIDSFU";
import { MuteStates } from "../room/MuteStates"; import { type MuteStates } from "../room/MuteStates";
import { import {
MediaDevice, type MediaDevice,
MediaDevices, type MediaDevices,
useMediaDevices, useMediaDevices,
} from "./MediaDevicesContext"; } from "./MediaDevicesContext";
import { import {
ECConnectionState, type ECConnectionState,
useECConnectionState, useECConnectionState,
} from "./useECConnectionState"; } from "./useECConnectionState";
import { MatrixKeyProvider } from "../e2ee/matrixKeyProvider"; import { MatrixKeyProvider } from "../e2ee/matrixKeyProvider";
import { E2eeType } from "../e2ee/e2eeType"; import { E2eeType } from "../e2ee/e2eeType";
import { EncryptionSystem } from "../e2ee/sharedKeyManagement"; import { type EncryptionSystem } from "../e2ee/sharedKeyManagement";
interface UseLivekitResult { interface UseLivekitResult {
livekitRoom?: Room; livekitRoom?: Room;

View File

@@ -5,17 +5,17 @@ SPDX-License-Identifier: AGPL-3.0-only
Please see LICENSE in the repository root for full details. Please see LICENSE in the repository root for full details.
*/ */
import { Span } from "@opentelemetry/api"; import { type Span } from "@opentelemetry/api";
import { MatrixCall } from "matrix-js-sdk/src/matrix"; import { type MatrixCall } from "matrix-js-sdk/src/matrix";
import { CallEvent } from "matrix-js-sdk/src/webrtc/call"; import { CallEvent } from "matrix-js-sdk/src/webrtc/call";
import { import {
TransceiverStats, type TransceiverStats,
CallFeedStats, type CallFeedStats,
} from "matrix-js-sdk/src/webrtc/stats/statsReport"; } from "matrix-js-sdk/src/webrtc/stats/statsReport";
import { ObjectFlattener } from "./ObjectFlattener"; import { ObjectFlattener } from "./ObjectFlattener";
import { ElementCallOpenTelemetry } from "./otel"; import { ElementCallOpenTelemetry } from "./otel";
import { OTelCallAbstractMediaStreamSpan } from "./OTelCallAbstractMediaStreamSpan"; import { type OTelCallAbstractMediaStreamSpan } from "./OTelCallAbstractMediaStreamSpan";
import { OTelCallTransceiverMediaStreamSpan } from "./OTelCallTransceiverMediaStreamSpan"; import { OTelCallTransceiverMediaStreamSpan } from "./OTelCallTransceiverMediaStreamSpan";
import { OTelCallFeedMediaStreamSpan } from "./OTelCallFeedMediaStreamSpan"; import { OTelCallFeedMediaStreamSpan } from "./OTelCallFeedMediaStreamSpan";

View File

@@ -5,10 +5,10 @@ SPDX-License-Identifier: AGPL-3.0-only
Please see LICENSE in the repository root for full details. Please see LICENSE in the repository root for full details.
*/ */
import opentelemetry, { Span } from "@opentelemetry/api"; import opentelemetry, { type Span } from "@opentelemetry/api";
import { TrackStats } from "matrix-js-sdk/src/webrtc/stats/statsReport"; import { type TrackStats } from "matrix-js-sdk/src/webrtc/stats/statsReport";
import { ElementCallOpenTelemetry } from "./otel"; import { type ElementCallOpenTelemetry } from "./otel";
import { OTelCallMediaStreamTrackSpan } from "./OTelCallMediaStreamTrackSpan"; import { OTelCallMediaStreamTrackSpan } from "./OTelCallMediaStreamTrackSpan";
type TrackId = string; type TrackId = string;

View File

@@ -5,13 +5,13 @@ SPDX-License-Identifier: AGPL-3.0-only
Please see LICENSE in the repository root for full details. Please see LICENSE in the repository root for full details.
*/ */
import { Span } from "@opentelemetry/api"; import { type Span } from "@opentelemetry/api";
import { import {
CallFeedStats, type CallFeedStats,
TrackStats, type TrackStats,
} from "matrix-js-sdk/src/webrtc/stats/statsReport"; } from "matrix-js-sdk/src/webrtc/stats/statsReport";
import { ElementCallOpenTelemetry } from "./otel"; import { type ElementCallOpenTelemetry } from "./otel";
import { OTelCallAbstractMediaStreamSpan } from "./OTelCallAbstractMediaStreamSpan"; import { OTelCallAbstractMediaStreamSpan } from "./OTelCallAbstractMediaStreamSpan";
export class OTelCallFeedMediaStreamSpan extends OTelCallAbstractMediaStreamSpan { export class OTelCallFeedMediaStreamSpan extends OTelCallAbstractMediaStreamSpan {

View File

@@ -5,10 +5,10 @@ SPDX-License-Identifier: AGPL-3.0-only
Please see LICENSE in the repository root for full details. Please see LICENSE in the repository root for full details.
*/ */
import { TrackStats } from "matrix-js-sdk/src/webrtc/stats/statsReport"; import { type TrackStats } from "matrix-js-sdk/src/webrtc/stats/statsReport";
import opentelemetry, { Span } from "@opentelemetry/api"; import opentelemetry, { type Span } from "@opentelemetry/api";
import { ElementCallOpenTelemetry } from "./otel"; import { type ElementCallOpenTelemetry } from "./otel";
export class OTelCallMediaStreamTrackSpan { export class OTelCallMediaStreamTrackSpan {
private readonly span: Span; private readonly span: Span;

View File

@@ -5,13 +5,13 @@ SPDX-License-Identifier: AGPL-3.0-only
Please see LICENSE in the repository root for full details. Please see LICENSE in the repository root for full details.
*/ */
import { Span } from "@opentelemetry/api"; import { type Span } from "@opentelemetry/api";
import { import {
TrackStats, type TrackStats,
TransceiverStats, type TransceiverStats,
} from "matrix-js-sdk/src/webrtc/stats/statsReport"; } from "matrix-js-sdk/src/webrtc/stats/statsReport";
import { ElementCallOpenTelemetry } from "./otel"; import { type ElementCallOpenTelemetry } from "./otel";
import { OTelCallAbstractMediaStreamSpan } from "./OTelCallAbstractMediaStreamSpan"; import { OTelCallAbstractMediaStreamSpan } from "./OTelCallAbstractMediaStreamSpan";
export class OTelCallTransceiverMediaStreamSpan extends OTelCallAbstractMediaStreamSpan { export class OTelCallTransceiverMediaStreamSpan extends OTelCallAbstractMediaStreamSpan {

View File

@@ -5,31 +5,35 @@ SPDX-License-Identifier: AGPL-3.0-only
Please see LICENSE in the repository root for full details. Please see LICENSE in the repository root for full details.
*/ */
import opentelemetry, { Span, Attributes, Context } from "@opentelemetry/api"; import opentelemetry, {
type Span,
type Attributes,
type Context,
} from "@opentelemetry/api";
import { import {
GroupCall, type GroupCall,
MatrixClient, type MatrixClient,
MatrixEvent, type MatrixEvent,
RoomMember, type RoomMember,
} from "matrix-js-sdk/src/matrix"; } from "matrix-js-sdk/src/matrix";
import { logger } from "matrix-js-sdk/src/logger"; import { logger } from "matrix-js-sdk/src/logger";
import { import {
CallError, type CallError,
CallState, type CallState,
MatrixCall, type MatrixCall,
VoipEvent, type VoipEvent,
} from "matrix-js-sdk/src/webrtc/call"; } from "matrix-js-sdk/src/webrtc/call";
import { import {
CallsByUserAndDevice, type CallsByUserAndDevice,
GroupCallError, type GroupCallError,
GroupCallEvent, GroupCallEvent,
GroupCallStatsReport, type GroupCallStatsReport,
} from "matrix-js-sdk/src/webrtc/groupCall"; } from "matrix-js-sdk/src/webrtc/groupCall";
import { import {
ConnectionStatsReport, type ConnectionStatsReport,
ByteSentStatsReport, type ByteSentStatsReport,
SummaryStatsReport, type SummaryStatsReport,
CallFeedReport, type CallFeedReport,
} from "matrix-js-sdk/src/webrtc/stats/statsReport"; } from "matrix-js-sdk/src/webrtc/stats/statsReport";
import { ElementCallOpenTelemetry } from "./otel"; import { ElementCallOpenTelemetry } from "./otel";

View File

@@ -5,11 +5,11 @@ SPDX-License-Identifier: AGPL-3.0-only
Please see LICENSE in the repository root for full details. Please see LICENSE in the repository root for full details.
*/ */
import { GroupCallStatsReport } from "matrix-js-sdk/src/webrtc/groupCall"; import { type GroupCallStatsReport } from "matrix-js-sdk/src/webrtc/groupCall";
import { import {
AudioConcealment, type AudioConcealment,
ByteSentStatsReport, type ByteSentStatsReport,
ConnectionStatsReport, type ConnectionStatsReport,
} from "matrix-js-sdk/src/webrtc/stats/statsReport"; } from "matrix-js-sdk/src/webrtc/stats/statsReport";
import { describe, expect, it } from "vitest"; import { describe, expect, it } from "vitest";

View File

@@ -4,13 +4,13 @@ Copyright 2023, 2024 New Vector Ltd.
SPDX-License-Identifier: AGPL-3.0-only SPDX-License-Identifier: AGPL-3.0-only
Please see LICENSE in the repository root for full details. Please see LICENSE in the repository root for full details.
*/ */
import { Attributes } from "@opentelemetry/api"; import { type Attributes } from "@opentelemetry/api";
import { VoipEvent } from "matrix-js-sdk/src/webrtc/call"; import { type VoipEvent } from "matrix-js-sdk/src/webrtc/call";
import { GroupCallStatsReport } from "matrix-js-sdk/src/webrtc/groupCall"; import { type GroupCallStatsReport } from "matrix-js-sdk/src/webrtc/groupCall";
import { import {
ByteSentStatsReport, type ByteSentStatsReport,
ConnectionStatsReport, type ConnectionStatsReport,
SummaryStatsReport, type SummaryStatsReport,
} from "matrix-js-sdk/src/webrtc/stats/statsReport"; } from "matrix-js-sdk/src/webrtc/stats/statsReport";
export class ObjectFlattener { export class ObjectFlattener {

View File

@@ -8,7 +8,7 @@ Please see LICENSE in the repository root for full details.
import { SimpleSpanProcessor } from "@opentelemetry/sdk-trace-base"; import { SimpleSpanProcessor } from "@opentelemetry/sdk-trace-base";
import { OTLPTraceExporter } from "@opentelemetry/exporter-trace-otlp-http"; import { OTLPTraceExporter } from "@opentelemetry/exporter-trace-otlp-http";
import { WebTracerProvider } from "@opentelemetry/sdk-trace-web"; import { WebTracerProvider } from "@opentelemetry/sdk-trace-web";
import opentelemetry, { Tracer } from "@opentelemetry/api"; import opentelemetry, { type Tracer } from "@opentelemetry/api";
import { Resource } from "@opentelemetry/resources"; import { Resource } from "@opentelemetry/resources";
import { SemanticResourceAttributes } from "@opentelemetry/semantic-conventions"; import { SemanticResourceAttributes } from "@opentelemetry/semantic-conventions";
import { logger } from "matrix-js-sdk/src/logger"; import { logger } from "matrix-js-sdk/src/logger";

View File

@@ -5,10 +5,10 @@ SPDX-License-Identifier: AGPL-3.0-only
Please see LICENSE in the repository root for full details. Please see LICENSE in the repository root for full details.
*/ */
import { MatrixClient } from "matrix-js-sdk/src/client"; import { type MatrixClient } from "matrix-js-sdk/src/client";
import { MatrixEvent } from "matrix-js-sdk/src/models/event"; import { type MatrixEvent } from "matrix-js-sdk/src/models/event";
import { User, UserEvent } from "matrix-js-sdk/src/models/user"; import { type User, UserEvent } from "matrix-js-sdk/src/models/user";
import { FileType } from "matrix-js-sdk/src/http-api"; import { type FileType } from "matrix-js-sdk/src/http-api";
import { useState, useCallback, useEffect } from "react"; import { useState, useCallback, useEffect } from "react";
import { logger } from "matrix-js-sdk/src/logger"; import { logger } from "matrix-js-sdk/src/logger";

View File

@@ -6,8 +6,8 @@ Please see LICENSE in the repository root for full details.
*/ */
import { import {
MouseEventHandler, type MouseEventHandler,
ReactNode, type ReactNode,
useCallback, useCallback,
useEffect, useEffect,
useState, useState,

View File

@@ -5,7 +5,7 @@ SPDX-License-Identifier: AGPL-3.0-only
Please see LICENSE in the repository root for full details. Please see LICENSE in the repository root for full details.
*/ */
import { PropsWithChildren, ReactNode } from "react"; import { type PropsWithChildren, type ReactNode } from "react";
import classNames from "classnames"; import classNames from "classnames";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";

View File

@@ -5,7 +5,7 @@ SPDX-License-Identifier: AGPL-3.0-only
Please see LICENSE in the repository root for full details. Please see LICENSE in the repository root for full details.
*/ */
import { RelationType } from "matrix-js-sdk/src/types"; import { type RelationType } from "matrix-js-sdk/src/types";
import catSoundOgg from "../sound/reactions/cat.ogg?url"; import catSoundOgg from "../sound/reactions/cat.ogg?url";
import catSoundMp3 from "../sound/reactions/cat.mp3?url"; import catSoundMp3 from "../sound/reactions/cat.mp3?url";

View File

@@ -5,7 +5,13 @@ SPDX-License-Identifier: AGPL-3.0-only
Please see LICENSE in the repository root for full details. Please see LICENSE in the repository root for full details.
*/ */
import { FC, MouseEvent, useCallback, useMemo, useState } from "react"; import {
type FC,
type MouseEvent,
useCallback,
useMemo,
useState,
} from "react";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { Button, Text } from "@vector-im/compound-web"; import { Button, Text } from "@vector-im/compound-web";
import { PopOutIcon } from "@vector-im/compound-design-tokens/assets/web/icons"; import { PopOutIcon } from "@vector-im/compound-design-tokens/assets/web/icons";

View File

@@ -5,8 +5,14 @@ SPDX-License-Identifier: AGPL-3.0-only
Please see LICENSE in the repository root for full details. Please see LICENSE in the repository root for full details.
*/ */
import { FC, FormEventHandler, ReactNode, useCallback, useState } from "react"; import {
import { MatrixClient } from "matrix-js-sdk/src/client"; type FC,
type FormEventHandler,
type ReactNode,
useCallback,
useState,
} from "react";
import { type MatrixClient } from "matrix-js-sdk/src/client";
import { Trans, useTranslation } from "react-i18next"; import { Trans, useTranslation } from "react-i18next";
import { useHistory } from "react-router-dom"; import { useHistory } from "react-router-dom";
import { Button, Heading, Text } from "@vector-im/compound-web"; import { Button, Heading, Text } from "@vector-im/compound-web";

View File

@@ -10,13 +10,13 @@ import {
afterAll, afterAll,
beforeEach, beforeEach,
expect, expect,
MockedFunction, type MockedFunction,
test, test,
vitest, vitest,
} from "vitest"; } from "vitest";
import { afterEach } from "node:test"; import { afterEach } from "node:test";
import { act } from "react"; import { act } from "react";
import { CallMembership } from "matrix-js-sdk/src/matrixrtc"; import { type CallMembership } from "matrix-js-sdk/src/matrixrtc";
import { mockRtcMembership } from "../utils/test"; import { mockRtcMembership } from "../utils/test";
import { import {

View File

@@ -5,10 +5,10 @@ SPDX-License-Identifier: AGPL-3.0-only
Please see LICENSE in the repository root for full details. Please see LICENSE in the repository root for full details.
*/ */
import { ReactNode, useEffect } from "react"; import { type ReactNode, useEffect } from "react";
import { filter, interval, throttle } from "rxjs"; import { filter, interval, throttle } from "rxjs";
import { CallViewModel } from "../state/CallViewModel"; import { type CallViewModel } from "../state/CallViewModel";
import joinCallSoundMp3 from "../sound/join_call.mp3"; import joinCallSoundMp3 from "../sound/join_call.mp3";
import joinCallSoundOgg from "../sound/join_call.ogg"; import joinCallSoundOgg from "../sound/join_call.ogg";
import leftCallSoundMp3 from "../sound/left_call.mp3"; import leftCallSoundMp3 from "../sound/left_call.mp3";
@@ -24,7 +24,7 @@ import { useLatest } from "../useLatest";
export const MAX_PARTICIPANT_COUNT_FOR_SOUND = 8; export const MAX_PARTICIPANT_COUNT_FOR_SOUND = 8;
export const THROTTLE_SOUND_EFFECT_MS = 500; export const THROTTLE_SOUND_EFFECT_MS = 500;
const sounds = prefetchSounds({ export const callEventAudioSounds = prefetchSounds({
join: { join: {
mp3: joinCallSoundMp3, mp3: joinCallSoundMp3,
ogg: joinCallSoundOgg, ogg: joinCallSoundOgg,
@@ -45,7 +45,7 @@ export function CallEventAudioRenderer({
vm: CallViewModel; vm: CallViewModel;
}): ReactNode { }): ReactNode {
const audioEngineCtx = useAudioContext({ const audioEngineCtx = useAudioContext({
sounds, sounds: callEventAudioSounds,
latencyHint: "interactive", latencyHint: "interactive",
}); });
const audioEngineRef = useLatest(audioEngineCtx); const audioEngineRef = useLatest(audioEngineCtx);
@@ -60,7 +60,7 @@ export function CallEventAudioRenderer({
throttle(() => interval(THROTTLE_SOUND_EFFECT_MS)), throttle(() => interval(THROTTLE_SOUND_EFFECT_MS)),
) )
.subscribe(() => { .subscribe(() => {
audioEngineRef.current?.playSound("join"); void audioEngineRef.current?.playSound("join");
}); });
const leftSub = vm.memberChanges const leftSub = vm.memberChanges
@@ -72,7 +72,7 @@ export function CallEventAudioRenderer({
throttle(() => interval(THROTTLE_SOUND_EFFECT_MS)), throttle(() => interval(THROTTLE_SOUND_EFFECT_MS)),
) )
.subscribe(() => { .subscribe(() => {
audioEngineRef.current?.playSound("left"); void audioEngineRef.current?.playSound("left");
}); });
const handRaisedSub = vm.handRaised.subscribe(() => { const handRaisedSub = vm.handRaised.subscribe(() => {

View File

@@ -5,7 +5,7 @@ SPDX-License-Identifier: AGPL-3.0-only
Please see LICENSE in the repository root for full details. Please see LICENSE in the repository root for full details.
*/ */
import { FC } from "react"; import { type FC } from "react";
import { Tooltip } from "@vector-im/compound-web"; import { Tooltip } from "@vector-im/compound-web";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { import {

View File

@@ -0,0 +1,153 @@
/*
Copyright 2024 New Vector Ltd.
SPDX-License-Identifier: AGPL-3.0-only
Please see LICENSE in the repository root for full details.
*/
import { beforeEach, expect, type MockedFunction, test, vitest } from "vitest";
import { render } from "@testing-library/react";
import { type MatrixClient } from "matrix-js-sdk/src/client";
import { type MatrixRTCSession } from "matrix-js-sdk/src/matrixrtc";
import { of } from "rxjs";
import { JoinRule, type RoomState } from "matrix-js-sdk/src/matrix";
import { Router } from "react-router-dom";
import { createBrowserHistory } from "history";
import userEvent from "@testing-library/user-event";
import { type MuteStates } from "./MuteStates";
import { prefetchSounds } from "../soundUtils";
import { useAudioContext } from "../useAudioContext";
import { ActiveCall } from "./InCallView";
import {
mockMatrixRoom,
mockMatrixRoomMember,
mockRtcMembership,
MockRTCSession,
} from "../utils/test";
import { GroupCallView } from "./GroupCallView";
import { leaveRTCSession } from "../rtcSessionHelpers";
import { type WidgetHelpers } from "../widget";
import { LazyEventEmitter } from "../LazyEventEmitter";
vitest.mock("../soundUtils");
vitest.mock("../useAudioContext");
vitest.mock("./InCallView");
vitest.mock("../rtcSessionHelpers", async (importOriginal) => {
// TODO: perhaps there is a more elegant way to manage the type import here?
// eslint-disable-next-line @typescript-eslint/consistent-type-imports
const orig = await importOriginal<typeof import("../rtcSessionHelpers")>();
vitest.spyOn(orig, "leaveRTCSession");
return orig;
});
let playSound: MockedFunction<
NonNullable<ReturnType<typeof useAudioContext>>["playSound"]
>;
const localRtcMember = mockRtcMembership("@carol:example.org", "CCCC");
const carol = mockMatrixRoomMember(localRtcMember);
const roomMembers = new Map([carol].map((p) => [p.userId, p]));
const roomId = "!foo:bar";
const soundPromise = Promise.resolve(true);
beforeEach(() => {
(prefetchSounds as MockedFunction<typeof prefetchSounds>).mockResolvedValue({
sound: new ArrayBuffer(0),
});
playSound = vitest.fn().mockReturnValue(soundPromise);
(useAudioContext as MockedFunction<typeof useAudioContext>).mockReturnValue({
playSound,
});
// A trivial implementation of Active call to ensure we are testing GroupCallView exclusively here.
(ActiveCall as MockedFunction<typeof ActiveCall>).mockImplementation(
({ onLeave }) => {
return (
<div>
<button onClick={() => onLeave()}>Leave</button>
</div>
);
},
);
});
function createGroupCallView(widget: WidgetHelpers | null): {
rtcSession: MockRTCSession;
getByText: ReturnType<typeof render>["getByText"];
} {
const history = createBrowserHistory();
const client = {
getUser: () => null,
getUserId: () => localRtcMember.sender,
getDeviceId: () => localRtcMember.deviceId,
getRoom: (rId) => (rId === roomId ? room : null),
} as Partial<MatrixClient> as MatrixClient;
const room = mockMatrixRoom({
client,
roomId,
getMember: (userId) => roomMembers.get(userId) ?? null,
getMxcAvatarUrl: () => null,
getCanonicalAlias: () => null,
currentState: {
getJoinRule: () => JoinRule.Invite,
} as Partial<RoomState> as RoomState,
});
const rtcSession = new MockRTCSession(
room,
localRtcMember,
[],
).withMemberships(of([]));
const muteState = {
audio: { enabled: false },
video: { enabled: false },
} as MuteStates;
const { getByText } = render(
<Router history={history}>
<GroupCallView
client={client}
isPasswordlessUser={false}
confineToRoom={false}
preload={false}
skipLobby={false}
hideHeader={true}
rtcSession={rtcSession as unknown as MatrixRTCSession}
muteStates={muteState}
widget={widget}
/>
</Router>,
);
return {
getByText,
rtcSession,
};
}
test("will play a leave sound asynchronously in SPA mode", async () => {
const user = userEvent.setup();
const { getByText, rtcSession } = createGroupCallView(null);
const leaveButton = getByText("Leave");
await user.click(leaveButton);
expect(playSound).toHaveBeenCalledWith("left");
expect(leaveRTCSession).toHaveBeenCalledWith(rtcSession, undefined);
expect(rtcSession.leaveRoomSession).toHaveBeenCalledOnce();
});
test("will play a leave sound synchronously in widget mode", async () => {
const user = userEvent.setup();
const widget = {
api: {
setAlwaysOnScreen: async () => Promise.resolve(true),
} as Partial<WidgetHelpers["api"]>,
lazyActions: new LazyEventEmitter(),
};
const { getByText, rtcSession } = createGroupCallView(
widget as WidgetHelpers,
);
const leaveButton = getByText("Leave");
await user.click(leaveButton);
expect(playSound).toHaveBeenCalledWith("left");
expect(leaveRTCSession).toHaveBeenCalledWith(rtcSession, soundPromise);
expect(rtcSession.leaveRoomSession).toHaveBeenCalledOnce();
});

View File

@@ -5,31 +5,45 @@ SPDX-License-Identifier: AGPL-3.0-only
Please see LICENSE in the repository root for full details. Please see LICENSE in the repository root for full details.
*/ */
import { FC, useCallback, useEffect, useMemo, useRef, useState } from "react"; import {
type FC,
useCallback,
useEffect,
useMemo,
useRef,
useState,
} from "react";
import { useHistory } from "react-router-dom"; import { useHistory } from "react-router-dom";
import { MatrixClient } from "matrix-js-sdk/src/client"; import { type MatrixClient } from "matrix-js-sdk/src/client";
import { import {
Room, Room,
isE2EESupported as isE2EESupportedBrowser, isE2EESupported as isE2EESupportedBrowser,
} from "livekit-client"; } from "livekit-client";
import { logger } from "matrix-js-sdk/src/logger"; import { logger } from "matrix-js-sdk/src/logger";
import { MatrixRTCSession } from "matrix-js-sdk/src/matrixrtc/MatrixRTCSession"; import { type MatrixRTCSession } from "matrix-js-sdk/src/matrixrtc/MatrixRTCSession";
import { JoinRule } from "matrix-js-sdk/src/matrix"; import { JoinRule } from "matrix-js-sdk/src/matrix";
import { Heading, Text } from "@vector-im/compound-web"; import { Heading, Text } from "@vector-im/compound-web";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import type { IWidgetApiRequest } from "matrix-widget-api"; import type { IWidgetApiRequest } from "matrix-widget-api";
import { widget, ElementWidgetActions, JoinCallData } from "../widget"; import {
ElementWidgetActions,
type JoinCallData,
type WidgetHelpers,
} from "../widget";
import { FullScreenView } from "../FullScreenView"; import { FullScreenView } from "../FullScreenView";
import { LobbyView } from "./LobbyView"; import { LobbyView } from "./LobbyView";
import { MatrixInfo } from "./VideoPreview"; import { type MatrixInfo } from "./VideoPreview";
import { CallEndedView } from "./CallEndedView"; import { CallEndedView } from "./CallEndedView";
import { PosthogAnalytics } from "../analytics/PosthogAnalytics"; import { PosthogAnalytics } from "../analytics/PosthogAnalytics";
import { useProfile } from "../profile/useProfile"; import { useProfile } from "../profile/useProfile";
import { findDeviceByName } from "../utils/media"; import { findDeviceByName } from "../utils/media";
import { ActiveCall } from "./InCallView"; import { ActiveCall } from "./InCallView";
import { MUTE_PARTICIPANT_COUNT, MuteStates } from "./MuteStates"; import { MUTE_PARTICIPANT_COUNT, type MuteStates } from "./MuteStates";
import { useMediaDevices, MediaDevices } from "../livekit/MediaDevicesContext"; import {
useMediaDevices,
type MediaDevices,
} from "../livekit/MediaDevicesContext";
import { useMatrixRTCSessionMemberships } from "../useMatrixRTCSessionMemberships"; import { useMatrixRTCSessionMemberships } from "../useMatrixRTCSessionMemberships";
import { enterRTCSession, leaveRTCSession } from "../rtcSessionHelpers"; import { enterRTCSession, leaveRTCSession } from "../rtcSessionHelpers";
import { useMatrixRTCSessionJoinState } from "../useMatrixRTCSessionJoinState"; import { useMatrixRTCSessionJoinState } from "../useMatrixRTCSessionJoinState";
@@ -42,6 +56,9 @@ import { useUrlParams } from "../UrlParams";
import { E2eeType } from "../e2ee/e2eeType"; import { E2eeType } from "../e2ee/e2eeType";
import { Link } from "../button/Link"; import { Link } from "../button/Link";
import { ReactionsProvider } from "../useReactions"; import { ReactionsProvider } from "../useReactions";
import { useAudioContext } from "../useAudioContext";
import { callEventAudioSounds } from "./CallEventAudioRenderer";
import { useLatest } from "../useLatest";
declare global { declare global {
interface Window { interface Window {
@@ -58,6 +75,7 @@ interface Props {
hideHeader: boolean; hideHeader: boolean;
rtcSession: MatrixRTCSession; rtcSession: MatrixRTCSession;
muteStates: MuteStates; muteStates: MuteStates;
widget: WidgetHelpers | null;
} }
export const GroupCallView: FC<Props> = ({ export const GroupCallView: FC<Props> = ({
@@ -69,10 +87,16 @@ export const GroupCallView: FC<Props> = ({
hideHeader, hideHeader,
rtcSession, rtcSession,
muteStates, muteStates,
widget,
}) => { }) => {
const memberships = useMatrixRTCSessionMemberships(rtcSession); const memberships = useMatrixRTCSessionMemberships(rtcSession);
const isJoined = useMatrixRTCSessionJoinState(rtcSession); const isJoined = useMatrixRTCSessionJoinState(rtcSession);
const leaveSoundContext = useLatest(
useAudioContext({
sounds: callEventAudioSounds,
latencyHint: "interactive",
}),
);
// This should use `useEffectEvent` (only available in experimental versions) // This should use `useEffectEvent` (only available in experimental versions)
useEffect(() => { useEffect(() => {
if (memberships.length >= MUTE_PARTICIPANT_COUNT) if (memberships.length >= MUTE_PARTICIPANT_COUNT)
@@ -186,14 +210,14 @@ export const GroupCallView: FC<Props> = ({
ev.detail.data as unknown as JoinCallData, ev.detail.data as unknown as JoinCallData,
); );
await enterRTCSession(rtcSession, perParticipantE2EE); await enterRTCSession(rtcSession, perParticipantE2EE);
widget!.api.transport.reply(ev.detail, {}); widget.api.transport.reply(ev.detail, {});
})().catch((e) => { })().catch((e) => {
logger.error("Error joining RTC session", e); logger.error("Error joining RTC session", e);
}); });
}; };
widget.lazyActions.on(ElementWidgetActions.JoinCall, onJoin); widget.lazyActions.on(ElementWidgetActions.JoinCall, onJoin);
return (): void => { return (): void => {
widget!.lazyActions.off(ElementWidgetActions.JoinCall, onJoin); widget.lazyActions.off(ElementWidgetActions.JoinCall, onJoin);
}; };
} else { } else {
// No lobby and no preload: we enter the rtc session right away // No lobby and no preload: we enter the rtc session right away
@@ -207,7 +231,7 @@ export const GroupCallView: FC<Props> = ({
void enterRTCSession(rtcSession, perParticipantE2EE); void enterRTCSession(rtcSession, perParticipantE2EE);
} }
} }
}, [rtcSession, preload, skipLobby, perParticipantE2EE]); }, [widget, rtcSession, preload, skipLobby, perParticipantE2EE]);
const [left, setLeft] = useState(false); const [left, setLeft] = useState(false);
const [leaveError, setLeaveError] = useState<Error | undefined>(undefined); const [leaveError, setLeaveError] = useState<Error | undefined>(undefined);
@@ -215,12 +239,12 @@ export const GroupCallView: FC<Props> = ({
const onLeave = useCallback( const onLeave = useCallback(
(leaveError?: Error): void => { (leaveError?: Error): void => {
setLeaveError(leaveError); const audioPromise = leaveSoundContext.current?.playSound("left");
setLeft(true);
// In embedded/widget mode the iFrame will be killed right after the call ended prohibiting the posthog event from getting sent, // In embedded/widget mode the iFrame will be killed right after the call ended prohibiting the posthog event from getting sent,
// therefore we want the event to be sent instantly without getting queued/batched. // therefore we want the event to be sent instantly without getting queued/batched.
const sendInstantly = !!widget; const sendInstantly = !!widget;
setLeaveError(leaveError);
setLeft(true);
PosthogAnalytics.instance.eventCallEnded.track( PosthogAnalytics.instance.eventCallEnded.track(
rtcSession.room.roomId, rtcSession.room.roomId,
rtcSession.memberships.length, rtcSession.memberships.length,
@@ -228,8 +252,12 @@ export const GroupCallView: FC<Props> = ({
rtcSession, rtcSession,
); );
// Only sends matrix leave event. The Livekit session will disconnect once the ActiveCall-view unmounts. leaveRTCSession(
leaveRTCSession(rtcSession) rtcSession,
// Wait for the sound in widget mode (it's not long)
sendInstantly && audioPromise ? audioPromise : undefined,
)
// Only sends matrix leave event. The Livekit session will disconnect once the ActiveCall-view unmounts.
.then(() => { .then(() => {
if ( if (
!isPasswordlessUser && !isPasswordlessUser &&
@@ -243,18 +271,25 @@ export const GroupCallView: FC<Props> = ({
logger.error("Error leaving RTC session", e); logger.error("Error leaving RTC session", e);
}); });
}, },
[rtcSession, isPasswordlessUser, confineToRoom, history], [
widget,
rtcSession,
isPasswordlessUser,
confineToRoom,
leaveSoundContext,
history,
],
); );
useEffect(() => { useEffect(() => {
if (widget && isJoined) { if (widget && isJoined) {
// set widget to sticky once joined. // set widget to sticky once joined.
widget!.api.setAlwaysOnScreen(true).catch((e) => { widget.api.setAlwaysOnScreen(true).catch((e) => {
logger.error("Error calling setAlwaysOnScreen(true)", e); logger.error("Error calling setAlwaysOnScreen(true)", e);
}); });
const onHangup = (ev: CustomEvent<IWidgetApiRequest>): void => { const onHangup = (ev: CustomEvent<IWidgetApiRequest>): void => {
widget!.api.transport.reply(ev.detail, {}); widget.api.transport.reply(ev.detail, {});
// Only sends matrix leave event. The Livekit session will disconnect once the ActiveCall-view unmounts. // Only sends matrix leave event. The Livekit session will disconnect once the ActiveCall-view unmounts.
leaveRTCSession(rtcSession).catch((e) => { leaveRTCSession(rtcSession).catch((e) => {
logger.error("Failed to leave RTC session", e); logger.error("Failed to leave RTC session", e);
@@ -262,10 +297,10 @@ export const GroupCallView: FC<Props> = ({
}; };
widget.lazyActions.once(ElementWidgetActions.HangupCall, onHangup); widget.lazyActions.once(ElementWidgetActions.HangupCall, onHangup);
return (): void => { return (): void => {
widget!.lazyActions.off(ElementWidgetActions.HangupCall, onHangup); widget.lazyActions.off(ElementWidgetActions.HangupCall, onHangup);
}; };
} }
}, [isJoined, rtcSession]); }, [widget, isJoined, rtcSession]);
const onReconnect = useCallback(() => { const onReconnect = useCallback(() => {
setLeft(false); setLeft(false);
@@ -360,14 +395,17 @@ export const GroupCallView: FC<Props> = ({
leaveError leaveError
) { ) {
return ( return (
<CallEndedView <>
endedCallId={rtcSession.room.roomId} <CallEndedView
client={client} endedCallId={rtcSession.room.roomId}
isPasswordlessUser={isPasswordlessUser} client={client}
confineToRoom={confineToRoom} isPasswordlessUser={isPasswordlessUser}
leaveError={leaveError} confineToRoom={confineToRoom}
reconnect={onReconnect} leaveError={leaveError}
/> reconnect={onReconnect}
/>
;
</>
); );
} else { } else {
// If the user is a regular user, we'll have sent them back to the homepage, // If the user is a regular user, we'll have sent them back to the homepage,

View File

@@ -10,13 +10,13 @@ import {
RoomContext, RoomContext,
useLocalParticipant, useLocalParticipant,
} from "@livekit/components-react"; } from "@livekit/components-react";
import { ConnectionState, Room } from "livekit-client"; import { ConnectionState, type Room } from "livekit-client";
import { MatrixClient } from "matrix-js-sdk/src/client"; import { type MatrixClient } from "matrix-js-sdk/src/client";
import { import {
FC, type FC,
PointerEvent, type PointerEvent,
PropsWithoutRef, type PropsWithoutRef,
TouchEvent, type TouchEvent,
forwardRef, forwardRef,
useCallback, useCallback,
useEffect, useEffect,
@@ -25,7 +25,7 @@ import {
useState, useState,
} from "react"; } from "react";
import useMeasure from "react-use-measure"; import useMeasure from "react-use-measure";
import { MatrixRTCSession } from "matrix-js-sdk/src/matrixrtc/MatrixRTCSession"; import { type MatrixRTCSession } from "matrix-js-sdk/src/matrixrtc/MatrixRTCSession";
import classNames from "classnames"; import classNames from "classnames";
import { BehaviorSubject, map } from "rxjs"; import { BehaviorSubject, map } from "rxjs";
import { useObservable, useObservableEagerState } from "observable-hooks"; import { useObservable, useObservableEagerState } from "observable-hooks";
@@ -49,28 +49,32 @@ import { useCallViewKeyboardShortcuts } from "../useCallViewKeyboardShortcuts";
import { ElementWidgetActions, widget } from "../widget"; import { ElementWidgetActions, widget } from "../widget";
import styles from "./InCallView.module.css"; import styles from "./InCallView.module.css";
import { GridTile } from "../tile/GridTile"; import { GridTile } from "../tile/GridTile";
import { OTelGroupCallMembership } from "../otel/OTelGroupCallMembership"; import { type OTelGroupCallMembership } from "../otel/OTelGroupCallMembership";
import { SettingsModal, defaultSettingsTab } from "../settings/SettingsModal"; import { SettingsModal, defaultSettingsTab } from "../settings/SettingsModal";
import { useRageshakeRequestModal } from "../settings/submit-rageshake"; import { useRageshakeRequestModal } from "../settings/submit-rageshake";
import { RageshakeRequestModal } from "./RageshakeRequestModal"; import { RageshakeRequestModal } from "./RageshakeRequestModal";
import { useLiveKit } from "../livekit/useLiveKit"; import { useLiveKit } from "../livekit/useLiveKit";
import { useWakeLock } from "../useWakeLock"; import { useWakeLock } from "../useWakeLock";
import { useMergedRefs } from "../useMergedRefs"; import { useMergedRefs } from "../useMergedRefs";
import { MuteStates } from "./MuteStates"; import { type MuteStates } from "./MuteStates";
import { MatrixInfo } from "./VideoPreview"; import { type MatrixInfo } from "./VideoPreview";
import { InviteButton } from "../button/InviteButton"; import { InviteButton } from "../button/InviteButton";
import { LayoutToggle } from "./LayoutToggle"; import { LayoutToggle } from "./LayoutToggle";
import { ECConnectionState } from "../livekit/useECConnectionState"; import { type ECConnectionState } from "../livekit/useECConnectionState";
import { useOpenIDSFU } from "../livekit/openIDSFU"; import { useOpenIDSFU } from "../livekit/openIDSFU";
import { CallViewModel, GridMode, Layout } from "../state/CallViewModel"; import {
import { Grid, TileProps } from "../grid/Grid"; CallViewModel,
type GridMode,
type Layout,
} from "../state/CallViewModel";
import { Grid, type TileProps } from "../grid/Grid";
import { useInitial } from "../useInitial"; import { useInitial } from "../useInitial";
import { SpotlightTile } from "../tile/SpotlightTile"; import { SpotlightTile } from "../tile/SpotlightTile";
import { EncryptionSystem } from "../e2ee/sharedKeyManagement"; import { type EncryptionSystem } from "../e2ee/sharedKeyManagement";
import { E2eeType } from "../e2ee/e2eeType"; import { E2eeType } from "../e2ee/e2eeType";
import { makeGridLayout } from "../grid/GridLayout"; import { makeGridLayout } from "../grid/GridLayout";
import { import {
CallLayoutOutputs, type CallLayoutOutputs,
defaultPipAlignment, defaultPipAlignment,
defaultSpotlightAlignment, defaultSpotlightAlignment,
} from "../grid/CallLayout"; } from "../grid/CallLayout";
@@ -78,12 +82,16 @@ import { makeOneOnOneLayout } from "../grid/OneOnOneLayout";
import { makeSpotlightExpandedLayout } from "../grid/SpotlightExpandedLayout"; import { makeSpotlightExpandedLayout } from "../grid/SpotlightExpandedLayout";
import { makeSpotlightLandscapeLayout } from "../grid/SpotlightLandscapeLayout"; import { makeSpotlightLandscapeLayout } from "../grid/SpotlightLandscapeLayout";
import { makeSpotlightPortraitLayout } from "../grid/SpotlightPortraitLayout"; import { makeSpotlightPortraitLayout } from "../grid/SpotlightPortraitLayout";
import { GridTileViewModel, TileViewModel } from "../state/TileViewModel"; import { GridTileViewModel, type TileViewModel } from "../state/TileViewModel";
import { ReactionsProvider, useReactions } from "../useReactions"; import { ReactionsProvider, useReactions } from "../useReactions";
import { ReactionsAudioRenderer } from "./ReactionAudioRenderer"; import { ReactionsAudioRenderer } from "./ReactionAudioRenderer";
import { useSwitchCamera } from "./useSwitchCamera"; import { useSwitchCamera } from "./useSwitchCamera";
import { ReactionsOverlay } from "./ReactionsOverlay"; import { ReactionsOverlay } from "./ReactionsOverlay";
import { CallEventAudioRenderer } from "./CallEventAudioRenderer"; import { CallEventAudioRenderer } from "./CallEventAudioRenderer";
import {
debugTileLayout as debugTileLayoutSetting,
useSetting,
} from "../settings/settings";
const canScreenshare = "getDisplayMedia" in (navigator.mediaDevices ?? {}); const canScreenshare = "getDisplayMedia" in (navigator.mediaDevices ?? {});
@@ -224,6 +232,8 @@ export const InCallView: FC<InCallViewProps> = ({
const windowMode = useObservableEagerState(vm.windowMode); const windowMode = useObservableEagerState(vm.windowMode);
const layout = useObservableEagerState(vm.layout); const layout = useObservableEagerState(vm.layout);
const tileStoreGeneration = useObservableEagerState(vm.tileStoreGeneration);
const [debugTileLayout] = useSetting(debugTileLayoutSetting);
const gridMode = useObservableEagerState(vm.gridMode); const gridMode = useObservableEagerState(vm.gridMode);
const showHeader = useObservableEagerState(vm.showHeader); const showHeader = useObservableEagerState(vm.showHeader);
const showFooter = useObservableEagerState(vm.showFooter); const showFooter = useObservableEagerState(vm.showFooter);
@@ -587,6 +597,10 @@ export const InCallView: FC<InCallViewProps> = ({
height={11} height={11}
aria-label={import.meta.env.VITE_PRODUCT_NAME || "Element Call"} aria-label={import.meta.env.VITE_PRODUCT_NAME || "Element Call"}
/> />
{/* Don't mind this odd placement, it's just a little debug label */}
{debugTileLayout
? `Tiles generation: ${tileStoreGeneration}`
: undefined}
</div> </div>
)} )}
{showControls && <div className={styles.buttons}>{buttons}</div>} {showControls && <div className={styles.buttons}>{buttons}</div>}

View File

@@ -7,7 +7,7 @@ Please see LICENSE in the repository root for full details.
import { render, screen } from "@testing-library/react"; import { render, screen } from "@testing-library/react";
import { expect, test, vi } from "vitest"; import { expect, test, vi } from "vitest";
import { Room } from "matrix-js-sdk/src/matrix"; import { type Room } from "matrix-js-sdk/src/matrix";
import { axe } from "vitest-axe"; import { axe } from "vitest-axe";
import { BrowserRouter } from "react-router-dom"; import { BrowserRouter } from "react-router-dom";
import userEvent from "@testing-library/user-event"; import userEvent from "@testing-library/user-event";

View File

@@ -5,9 +5,15 @@ SPDX-License-Identifier: AGPL-3.0-only
Please see LICENSE in the repository root for full details. Please see LICENSE in the repository root for full details.
*/ */
import { FC, MouseEvent, useCallback, useMemo, useState } from "react"; import {
type FC,
type MouseEvent,
useCallback,
useMemo,
useState,
} from "react";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { Room } from "matrix-js-sdk/src/matrix"; import { type Room } from "matrix-js-sdk/src/matrix";
import { Button, Text } from "@vector-im/compound-web"; import { Button, Text } from "@vector-im/compound-web";
import { import {
LinkIcon, LinkIcon,

View File

@@ -5,7 +5,7 @@ SPDX-License-Identifier: AGPL-3.0-only
Please see LICENSE in the repository root for full details. Please see LICENSE in the repository root for full details.
*/ */
import { ChangeEvent, FC, TouchEvent, useCallback } from "react"; import { type ChangeEvent, type FC, type TouchEvent, useCallback } from "react";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { Tooltip } from "@vector-im/compound-web"; import { Tooltip } from "@vector-im/compound-web";
import { import {

View File

@@ -5,15 +5,15 @@ SPDX-License-Identifier: AGPL-3.0-only
Please see LICENSE in the repository root for full details. Please see LICENSE in the repository root for full details.
*/ */
import { FC, useCallback, useMemo, useState } from "react"; import { type FC, useCallback, useMemo, useState } from "react";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { MatrixClient } from "matrix-js-sdk/src/matrix"; import { type MatrixClient } from "matrix-js-sdk/src/matrix";
import { Button } from "@vector-im/compound-web"; import { Button } from "@vector-im/compound-web";
import classNames from "classnames"; import classNames from "classnames";
import { useHistory } from "react-router-dom"; import { useHistory } from "react-router-dom";
import { logger } from "matrix-js-sdk/src/logger"; import { logger } from "matrix-js-sdk/src/logger";
import { usePreviewTracks } from "@livekit/components-react"; import { usePreviewTracks } from "@livekit/components-react";
import { LocalVideoTrack, Track } from "livekit-client"; import { type LocalVideoTrack, Track } from "livekit-client";
import { useObservable } from "observable-hooks"; import { useObservable } from "observable-hooks";
import { map } from "rxjs"; import { map } from "rxjs";
@@ -21,8 +21,8 @@ import inCallStyles from "./InCallView.module.css";
import styles from "./LobbyView.module.css"; import styles from "./LobbyView.module.css";
import { Header, LeftNav, RightNav, RoomHeaderInfo } from "../Header"; import { Header, LeftNav, RightNav, RoomHeaderInfo } from "../Header";
import { useLocationNavigation } from "../useLocationNavigation"; import { useLocationNavigation } from "../useLocationNavigation";
import { MatrixInfo, VideoPreview } from "./VideoPreview"; import { type MatrixInfo, VideoPreview } from "./VideoPreview";
import { MuteStates } from "./MuteStates"; import { type MuteStates } from "./MuteStates";
import { InviteButton } from "../button/InviteButton"; import { InviteButton } from "../button/InviteButton";
import { import {
EndCallButton, EndCallButton,

View File

@@ -6,15 +6,15 @@ Please see LICENSE in the repository root for full details.
*/ */
import { afterAll, afterEach, describe, expect, it, vi } from "vitest"; import { afterAll, afterEach, describe, expect, it, vi } from "vitest";
import React, { ReactNode } from "react"; import React, { type ReactNode } from "react";
import { beforeEach } from "vitest"; import { beforeEach } from "vitest";
import { render, screen } from "@testing-library/react"; import { render, screen } from "@testing-library/react";
import { MemoryRouter } from "react-router-dom"; import { MemoryRouter } from "react-router-dom";
import { useMuteStates } from "./MuteStates"; import { useMuteStates } from "./MuteStates";
import { import {
MediaDevice, type MediaDevice,
MediaDevices, type MediaDevices,
MediaDevicesContext, MediaDevicesContext,
} from "../livekit/MediaDevicesContext"; } from "../livekit/MediaDevicesContext";
import { mockConfig } from "../utils/test"; import { mockConfig } from "../utils/test";

View File

@@ -6,16 +6,19 @@ Please see LICENSE in the repository root for full details.
*/ */
import { import {
Dispatch, type Dispatch,
SetStateAction, type SetStateAction,
useCallback, useCallback,
useEffect, useEffect,
useMemo, useMemo,
} from "react"; } from "react";
import { IWidgetApiRequest } from "matrix-widget-api"; import { type IWidgetApiRequest } from "matrix-widget-api";
import { logger } from "matrix-js-sdk/src/logger"; import { logger } from "matrix-js-sdk/src/logger";
import { MediaDevice, useMediaDevices } from "../livekit/MediaDevicesContext"; import {
type MediaDevice,
useMediaDevices,
} from "../livekit/MediaDevicesContext";
import { useReactiveState } from "../useReactiveState"; import { useReactiveState } from "../useReactiveState";
import { ElementWidgetActions, widget } from "../widget"; import { ElementWidgetActions, widget } from "../widget";
import { Config } from "../config/Config"; import { Config } from "../config/Config";

View File

@@ -5,11 +5,11 @@ SPDX-License-Identifier: AGPL-3.0-only
Please see LICENSE in the repository root for full details. Please see LICENSE in the repository root for full details.
*/ */
import { FC, useEffect } from "react"; import { type FC, useEffect } from "react";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { Button, Text } from "@vector-im/compound-web"; import { Button, Text } from "@vector-im/compound-web";
import { Modal, Props as ModalProps } from "../Modal"; import { Modal, type Props as ModalProps } from "../Modal";
import { FieldRow, ErrorMessage } from "../input/Input"; import { FieldRow, ErrorMessage } from "../input/Input";
import { useSubmitRageshake } from "../settings/submit-rageshake"; import { useSubmitRageshake } from "../settings/submit-rageshake";

View File

@@ -12,11 +12,11 @@ import {
expect, expect,
test, test,
vitest, vitest,
MockedFunction, type MockedFunction,
Mock, type Mock,
} from "vitest"; } from "vitest";
import { TooltipProvider } from "@vector-im/compound-web"; import { TooltipProvider } from "@vector-im/compound-web";
import { act, ReactNode } from "react"; import { act, type ReactNode } from "react";
import { afterEach } from "node:test"; import { afterEach } from "node:test";
import { ReactionsAudioRenderer } from "./ReactionAudioRenderer"; import { ReactionsAudioRenderer } from "./ReactionAudioRenderer";

View File

@@ -5,7 +5,7 @@ SPDX-License-Identifier: AGPL-3.0-only
Please see LICENSE in the repository root for full details. Please see LICENSE in the repository root for full details.
*/ */
import { ReactNode, useEffect, useState } from "react"; import { type ReactNode, useEffect, useState } from "react";
import { playReactionsSound, useSetting } from "../settings/settings"; import { playReactionsSound, useSetting } from "../settings/settings";
import { GenericReaction, ReactionSet } from "../reactions"; import { GenericReaction, ReactionSet } from "../reactions";

View File

@@ -5,11 +5,11 @@ SPDX-License-Identifier: AGPL-3.0-only
Please see LICENSE in the repository root for full details. Please see LICENSE in the repository root for full details.
*/ */
import { ReactNode } from "react"; import { type ReactNode } from "react";
import { useObservableState } from "observable-hooks";
import styles from "./ReactionsOverlay.module.css"; import styles from "./ReactionsOverlay.module.css";
import { CallViewModel } from "../state/CallViewModel"; import { CallViewModel } from "../state/CallViewModel";
import { useObservableState } from "observable-hooks";
export function ReactionsOverlay({ vm }: { vm: CallViewModel }): ReactNode { export function ReactionsOverlay({ vm }: { vm: CallViewModel }): ReactNode {
const reactionsIcons = useObservableState(vm.visibleReactions); const reactionsIcons = useObservableState(vm.visibleReactions);

View File

@@ -5,7 +5,7 @@ SPDX-License-Identifier: AGPL-3.0-only
Please see LICENSE in the repository root for full details. Please see LICENSE in the repository root for full details.
*/ */
import { FC, useCallback, useState } from "react"; import { type FC, useCallback, useState } from "react";
import { useLocation } from "react-router-dom"; import { useLocation } from "react-router-dom";
import { Trans, useTranslation } from "react-i18next"; import { Trans, useTranslation } from "react-i18next";
import { logger } from "matrix-js-sdk/src/logger"; import { logger } from "matrix-js-sdk/src/logger";

View File

@@ -5,11 +5,11 @@ SPDX-License-Identifier: AGPL-3.0-only
Please see LICENSE in the repository root for full details. Please see LICENSE in the repository root for full details.
*/ */
import { FC, useEffect, useState, ReactNode, useRef } from "react"; import { type FC, useEffect, useState, type ReactNode, useRef } from "react";
import { logger } from "matrix-js-sdk/src/logger"; import { logger } from "matrix-js-sdk/src/logger";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { CheckIcon } from "@vector-im/compound-design-tokens/assets/web/icons"; import { CheckIcon } from "@vector-im/compound-design-tokens/assets/web/icons";
import { MatrixError } from "matrix-js-sdk/src/http-api"; import { type MatrixError } from "matrix-js-sdk/src/http-api";
import { Heading, Text } from "@vector-im/compound-web"; import { Heading, Text } from "@vector-im/compound-web";
import { useClientLegacy } from "../ClientContext"; import { useClientLegacy } from "../ClientContext";
@@ -98,6 +98,7 @@ export const RoomPage: FC = () => {
case "loaded": case "loaded":
return ( return (
<GroupCallView <GroupCallView
widget={widget}
client={client!} client={client!}
rtcSession={groupCallState.rtcSession} rtcSession={groupCallState.rtcSession}
isPasswordlessUser={passwordlessUser} isPasswordlessUser={passwordlessUser}

View File

@@ -5,15 +5,15 @@ SPDX-License-Identifier: AGPL-3.0-only
Please see LICENSE in the repository root for full details. Please see LICENSE in the repository root for full details.
*/ */
import { useEffect, useRef, FC, ReactNode } from "react"; import { useEffect, useRef, type FC, type ReactNode } from "react";
import useMeasure from "react-use-measure"; import useMeasure from "react-use-measure";
import { facingModeFromLocalTrack, LocalVideoTrack } from "livekit-client"; import { facingModeFromLocalTrack, type LocalVideoTrack } from "livekit-client";
import classNames from "classnames"; import classNames from "classnames";
import { Avatar } from "../Avatar"; import { Avatar } from "../Avatar";
import styles from "./VideoPreview.module.css"; import styles from "./VideoPreview.module.css";
import { MuteStates } from "./MuteStates"; import { type MuteStates } from "./MuteStates";
import { EncryptionSystem } from "../e2ee/sharedKeyManagement"; import { type EncryptionSystem } from "../e2ee/sharedKeyManagement";
export type MatrixInfo = { export type MatrixInfo = {
userId: string; userId: string;

View File

@@ -5,8 +5,8 @@ SPDX-License-Identifier: AGPL-3.0-only
Please see LICENSE in the repository root for full details. Please see LICENSE in the repository root for full details.
*/ */
import { vi, Mocked, test, expect } from "vitest"; import { vi, type Mocked, test, expect } from "vitest";
import { RoomState } from "matrix-js-sdk/src/models/room-state"; import { type RoomState } from "matrix-js-sdk/src/models/room-state";
import { PosthogAnalytics } from "../../src/analytics/PosthogAnalytics"; import { PosthogAnalytics } from "../../src/analytics/PosthogAnalytics";
import { checkForParallelCalls } from "../../src/room/checkForParallelCalls"; import { checkForParallelCalls } from "../../src/room/checkForParallelCalls";

Some files were not shown because too many files have changed in this diff Show More