Merge branch 'livekit' into remove-inspector

This commit is contained in:
Robin
2023-09-28 09:54:37 -04:00
44 changed files with 737 additions and 429 deletions

View File

@@ -18,5 +18,6 @@ export default {
output: "public/locales/$LOCALE/$NAMESPACE.json", output: "public/locales/$LOCALE/$NAMESPACE.json",
input: ["src/**/*.{ts,tsx}"], input: ["src/**/*.{ts,tsx}"],
sort: true, sort: true,
useKeysAsDefaultValue: true, // The key becomes the English version of the string
defaultValue: (_l, _ns, key) => key,
}; };

View File

@@ -44,8 +44,8 @@
"@react-stately/select": "^3.1.3", "@react-stately/select": "^3.1.3",
"@react-stately/tooltip": "^3.0.5", "@react-stately/tooltip": "^3.0.5",
"@react-stately/tree": "^3.2.0", "@react-stately/tree": "^3.2.0",
"@sentry/react": "^6.13.3", "@sentry/react": "^7.0.0",
"@sentry/tracing": "^6.13.3", "@sentry/tracing": "^7.0.0",
"@use-gesture/react": "^10.2.11", "@use-gesture/react": "^10.2.11",
"@vector-im/compound-design-tokens": "^0.0.6", "@vector-im/compound-design-tokens": "^0.0.6",
"@vector-im/compound-web": "^0.4.0", "@vector-im/compound-web": "^0.4.0",
@@ -84,6 +84,7 @@
"@storybook/react": "^6.5.0-alpha.5", "@storybook/react": "^6.5.0-alpha.5",
"@testing-library/jest-dom": "^6.0.0", "@testing-library/jest-dom": "^6.0.0",
"@testing-library/react": "^14.0.0", "@testing-library/react": "^14.0.0",
"@testing-library/user-event": "^14.5.1",
"@types/content-type": "^1.1.5", "@types/content-type": "^1.1.5",
"@types/d3": "^7.4.0", "@types/d3": "^7.4.0",
"@types/dom-screen-wake-lock": "^1.0.1", "@types/dom-screen-wake-lock": "^1.0.1",
@@ -118,7 +119,7 @@
"typescript": "^5.1.6", "typescript": "^5.1.6",
"vite": "^4.2.0", "vite": "^4.2.0",
"vite-plugin-html-template": "^1.1.0", "vite-plugin-html-template": "^1.1.0",
"vite-plugin-svgr": "^3.2.0" "vite-plugin-svgr": "^4.0.0"
}, },
"jest": { "jest": {
"testEnvironment": "./test/environment.ts", "testEnvironment": "./test/environment.ts",
@@ -131,7 +132,7 @@
], ],
"moduleNameMapper": { "moduleNameMapper": {
"\\.css$": "identity-obj-proxy", "\\.css$": "identity-obj-proxy",
"\\.svg$": "<rootDir>/test/mocks/svgr.ts", "\\.svg\\?react$": "<rootDir>/test/mocks/svgr.ts",
"^\\./IndexedDBWorker\\?worker$": "<rootDir>/test/mocks/workerMock.ts", "^\\./IndexedDBWorker\\?worker$": "<rootDir>/test/mocks/workerMock.ts",
"^\\./olm$": "<rootDir>/test/mocks/olmMock.ts" "^\\./olm$": "<rootDir>/test/mocks/olmMock.ts"
}, },

View File

@@ -5,7 +5,6 @@
"{{count}} stars|other": "{{count}} stars", "{{count}} stars|other": "{{count}} stars",
"{{displayName}} is presenting": "{{displayName}} is presenting", "{{displayName}} is presenting": "{{displayName}} is presenting",
"{{displayName}}, your call has ended.": "{{displayName}}, your call has ended.", "{{displayName}}, your call has ended.": "{{displayName}}, your call has ended.",
"{{names, list(style: short;)}}": "{{names, list(style: short;)}}",
"<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.": "<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.", "<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.": "<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.",
"<0>Already have an account?</0><1><0>Log in</0> Or <2>Access as a guest</2></1>": "<0>Already have an account?</0><1><0>Log in</0> Or <2>Access as a guest</2></1>", "<0>Already have an account?</0><1><0>Log in</0> Or <2>Access as a guest</2></1>": "<0>Already have an account?</0><1><0>Log in</0> Or <2>Access as a guest</2></1>",
"<0>Create an account</0> Or <2>Access as a guest</2>": "<0>Create an account</0> Or <2>Access as a guest</2>", "<0>Create an account</0> Or <2>Access as a guest</2>": "<0>Create an account</0> Or <2>Access as a guest</2>",
@@ -30,7 +29,7 @@
"Continue in browser": "Continue in browser", "Continue in browser": "Continue in browser",
"Copied!": "Copied!", "Copied!": "Copied!",
"Copy": "Copy", "Copy": "Copy",
"Copy and share this call link": "Copy and share this call link", "Copy link": "Copy link",
"Create account": "Create account", "Create account": "Create account",
"Debug log request": "Debug log request", "Debug log request": "Debug log request",
"Developer": "Developer", "Developer": "Developer",
@@ -52,9 +51,12 @@
"How did it go?": "How did it go?", "How did it go?": "How did it go?",
"If you are experiencing issues or simply would like to provide some feedback, please send us a short description below.": "If you are experiencing issues or simply would like to provide some feedback, please send us a short description below.", "If you are experiencing issues or simply would like to provide some feedback, please send us a short description below.": "If you are experiencing issues or simply would like to provide some feedback, please send us a short description below.",
"Include debug logs": "Include debug logs", "Include debug logs": "Include debug logs",
"Invite": "Invite",
"Invite to this call": "Invite to this call",
"Join call": "Join call", "Join call": "Join call",
"Join call now": "Join call now", "Join call now": "Join call now",
"Join existing call?": "Join existing call?", "Join existing call?": "Join existing call?",
"Link copied to clipboard": "Link copied to clipboard",
"Loading…": "Loading…", "Loading…": "Loading…",
"Local volume": "Local volume", "Local volume": "Local volume",
"Logging in…": "Logging in…", "Logging in…": "Logging in…",
@@ -71,6 +73,7 @@
"Not now, return to home screen": "Not now, return to home screen", "Not now, return to home screen": "Not now, return to home screen",
"Not registered yet? <2>Create an account</2>": "Not registered yet? <2>Create an account</2>", "Not registered yet? <2>Create an account</2>": "Not registered yet? <2>Create an account</2>",
"Open in the app": "Open in the app", "Open in the app": "Open in the app",
"Participants": "Participants",
"Password": "Password", "Password": "Password",
"Passwords must match": "Passwords must match", "Passwords must match": "Passwords must match",
"Profile": "Profile", "Profile": "Profile",
@@ -89,9 +92,7 @@
"Sending debug logs…": "Sending debug logs…", "Sending debug logs…": "Sending debug logs…",
"Sending…": "Sending…", "Sending…": "Sending…",
"Settings": "Settings", "Settings": "Settings",
"Share": "Share",
"Share screen": "Share screen", "Share screen": "Share screen",
"Share this call": "Share this call",
"Sharing screen": "Sharing screen", "Sharing screen": "Sharing screen",
"Show connection stats": "Show connection stats", "Show connection stats": "Show connection stats",
"Sign in": "Sign in", "Sign in": "Sign in",

View File

@@ -119,7 +119,8 @@
"Stop video": "Ferma video", "Stop video": "Ferma video",
"Unmute microphone": "Riaccendi il microfono", "Unmute microphone": "Riaccendi il microfono",
"Back to recents": "Torna ai recenti", "Back to recents": "Torna ai recenti",
"Start new call": "Inizia nuova chiamata", "Start new call": "Inizia una nuova chiamata",
"Call not found": "Chiamata non trovata", "Call not found": "Chiamata non trovata",
"Calls are now end-to-end encrypted and need to be created from the home page. This helps make sure everyone's using the same encryption key.": "Le chiamate ora sono cifrate end-to-end e devono essere create dalla pagina principale. Ciò assicura che chiunque usi la stessa chiave di crittografia." "Calls are now end-to-end encrypted and need to be created from the home page. This helps make sure everyone's using the same encryption key.": "Le chiamate ora sono cifrate end-to-end e devono essere create dalla pagina principale. Ciò assicura che chiunque usi la stessa chiave di crittografia.",
"Your web browser does not support media end-to-end encryption. Supported Browsers are Chrome, Safari, Firefox >=117": "Il tuo browser non supporta la crittografia end-to-end dei media. I browser supportati sono Chrome, Safari, Firefox >=117"
} }

View File

@@ -107,5 +107,20 @@
"Share this call": "Udostępnij to połączenie", "Share this call": "Udostępnij to połączenie",
"Sharing screen": "Udostępnianie ekranu", "Sharing screen": "Udostępnianie ekranu",
"{{count, number}}|one": "{{count, number}}", "{{count, number}}|one": "{{count, number}}",
"{{names, list(style: short;)}}": "{{names, list(style: short;)}}" "{{names, list(style: short;)}}": "{{names, list(style: short;)}}",
"Continue in browser": "Kontynuuj w przeglądarce",
"Mute microphone": "Wycisz mikrofon",
"Name of call": "Nazwa połączenia",
"Open in the app": "Otwórz w aplikacji",
"Ready to join?": "Gotowy, by dołączyć?",
"Select app": "Wybierz aplikację",
"Start new call": "Rozpocznij nowe połączenie",
"Start video": "Rozpocznij wideo",
"Back to recents": "Wróć do ostatnie",
"Stop video": "Zakończ wideo",
"Unmute microphone": "Odcisz mikrofon",
"Call not found": "Nie znaleziono połączenia",
"Calls are now end-to-end encrypted and need to be created from the home page. This helps make sure everyone's using the same encryption key.": "Połączenia są teraz szyfrowane end-to-end i muszą zostać utworzone ze strony głównej. Pomaga to upewnić się, że każdy korzysta z tego samego klucza szyfrującego.",
"You": "Ty",
"Your web browser does not support media end-to-end encryption. Supported Browsers are Chrome, Safari, Firefox >=117": "Twoja przeglądarka nie wspiera szyfrowania end-to-end. Wspierane przeglądarki to Chrome, Safari, Firefox >=117"
} }

View File

@@ -18,7 +18,7 @@ import { Trans } from "react-i18next";
import { Banner } from "./Banner"; import { Banner } from "./Banner";
import styles from "./E2EEBanner.module.css"; import styles from "./E2EEBanner.module.css";
import { ReactComponent as LockOffIcon } from "./icons/LockOff.svg"; import LockOffIcon from "./icons/LockOff.svg?react";
import { useEnableE2EE } from "./settings/useSetting"; import { useEnableE2EE } from "./settings/useSetting";
export const E2EEBanner = () => { export const E2EEBanner = () => {

View File

@@ -1,66 +0,0 @@
/*
Copyright 2022 New Vector Ltd
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
import { HTMLAttributes } from "react";
import { MatrixClient } from "matrix-js-sdk/src/client";
import { RoomMember } from "matrix-js-sdk/src/models/room-member";
import { useTranslation } from "react-i18next";
import { AvatarStack } from "@vector-im/compound-web";
import { Avatar, Size } from "./Avatar";
interface Props extends HTMLAttributes<HTMLDivElement> {
className?: string;
client: MatrixClient;
members: RoomMember[];
max?: number;
size?: Size | number;
}
export function Facepile({
className,
client,
members,
max = 3,
size = Size.XS,
...rest
}: Props) {
const { t } = useTranslation();
const displayedMembers = members.slice(0, max);
return (
<AvatarStack
title={t("{{names, list(style: short;)}}", {
list: displayedMembers.map((m) => m.name),
})}
{...rest}
>
{displayedMembers.map((member, i) => {
const avatarUrl = member.getMxcAvatarUrl();
return (
<Avatar
key={i}
id={member.userId}
name={member.name}
size={size}
src={avatarUrl ?? undefined}
/>
);
})}
</AvatarStack>
);
}

View File

@@ -111,7 +111,6 @@ limitations under the License.
display: flex; display: flex;
align-items: center; align-items: center;
gap: var(--cpd-space-1-5x); gap: var(--cpd-space-1-5x);
font: var(--cpd-font-body-sm-medium);
} }
@media (min-width: 800px) { @media (min-width: 800px) {

View File

@@ -18,13 +18,12 @@ import classNames from "classnames";
import { FC, HTMLAttributes, ReactNode } from "react"; import { FC, HTMLAttributes, ReactNode } 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 { MatrixClient, RoomMember } from "matrix-js-sdk/src/matrix"; import { Heading, Text } from "@vector-im/compound-web";
import { Heading } from "@vector-im/compound-web"; import UserProfileIcon from "@vector-im/compound-design-tokens/icons/user-profile.svg?react";
import styles from "./Header.module.css"; import styles from "./Header.module.css";
import { ReactComponent as Logo } from "./icons/Logo.svg"; import Logo from "./icons/Logo.svg?react";
import { Avatar, Size } from "./Avatar"; import { Avatar, Size } from "./Avatar";
import { Facepile } from "./Facepile";
import { EncryptionLock } from "./room/EncryptionLock"; import { EncryptionLock } from "./room/EncryptionLock";
import { useMediaQuery } from "./useMediaQuery"; import { useMediaQuery } from "./useMediaQuery";
@@ -118,8 +117,7 @@ interface RoomHeaderInfoProps {
name: string; name: string;
avatarUrl: string | null; avatarUrl: string | null;
encrypted: boolean; encrypted: boolean;
participants: RoomMember[]; participantCount: number;
client: MatrixClient;
} }
export const RoomHeaderInfo: FC<RoomHeaderInfoProps> = ({ export const RoomHeaderInfo: FC<RoomHeaderInfoProps> = ({
@@ -127,8 +125,7 @@ export const RoomHeaderInfo: FC<RoomHeaderInfoProps> = ({
name, name,
avatarUrl, avatarUrl,
encrypted, encrypted,
participants, participantCount,
client,
}) => { }) => {
const { t } = useTranslation(); const { t } = useTranslation();
const size = useMediaQuery("(max-width: 550px)") ? "sm" : "lg"; const size = useMediaQuery("(max-width: 550px)") ? "sm" : "lg";
@@ -153,10 +150,16 @@ export const RoomHeaderInfo: FC<RoomHeaderInfoProps> = ({
</Heading> </Heading>
<EncryptionLock encrypted={encrypted} /> <EncryptionLock encrypted={encrypted} />
</div> </div>
{participants.length > 0 && ( {participantCount > 0 && (
<div className={styles.participantsLine}> <div className={styles.participantsLine}>
<Facepile client={client} members={participants} size={20} /> <UserProfileIcon
{t("{{count, number}}", { count: participants.length })} width={20}
height={20}
aria-label={t("Participants")}
/>
<Text as="span" size="sm" weight="medium">
{t("{{count, number}}", { count: participantCount })}
</Text>
</div> </div>
)} )}
</div> </div>

View File

@@ -14,96 +14,18 @@ See the License for the specific language governing permissions and
limitations under the License. limitations under the License.
*/ */
.overlay {
position: fixed;
z-index: 100;
inset: 0;
background: rgba(3, 12, 27, 0.528);
}
@keyframes fade-in {
from {
opacity: 0;
}
to {
opacity: 1;
}
}
.dialogOverlay[data-state="open"] {
animation: fade-in 200ms;
}
@keyframes fade-out {
from {
opacity: 1;
}
to {
opacity: 0;
}
}
.dialogOverlay[data-state="closed"] {
animation: fade-out 130ms;
}
.modal { .modal {
position: fixed;
z-index: 101;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
} }
.dialog { .dialog {
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
box-sizing: border-box; box-sizing: border-box;
inline-size: 520px; inline-size: 520px;
max-inline-size: 90%; max-inline-size: 90%;
max-block-size: 600px; max-block-size: 600px;
} }
@keyframes zoom-in {
from {
opacity: 0;
transform: translate(-50%, -50%) scale(80%);
}
to {
opacity: 1;
transform: translate(-50%, -50%) scale(100%);
}
}
@keyframes zoom-out {
from {
opacity: 1;
transform: translate(-50%, -50%) scale(100%);
}
to {
opacity: 0;
transform: translate(-50%, -50%) scale(80%);
}
}
.dialog[data-state="open"] {
animation: zoom-in 200ms;
}
.dialog[data-state="closed"] {
animation: zoom-out 130ms;
}
@media (prefers-reduced-motion) {
.dialog[data-state="open"] {
animation-name: fade-in;
}
.dialog[data-state="closed"] {
animation-name: fade-out;
}
}
.content { .content {
display: flex; display: flex;
flex-direction: column; flex-direction: column;

View File

@@ -27,11 +27,12 @@ import {
} from "@radix-ui/react-dialog"; } from "@radix-ui/react-dialog";
import { Drawer } from "vaul"; import { Drawer } from "vaul";
import { VisuallyHidden } from "@radix-ui/react-visually-hidden"; import { VisuallyHidden } from "@radix-ui/react-visually-hidden";
import { ReactComponent as CloseIcon } from "@vector-im/compound-design-tokens/icons/close.svg"; import CloseIcon from "@vector-im/compound-design-tokens/icons/close.svg?react";
import classNames from "classnames"; import classNames from "classnames";
import { Heading } from "@vector-im/compound-web"; import { Heading } from "@vector-im/compound-web";
import styles from "./Modal.module.css"; import styles from "./Modal.module.css";
import overlayStyles from "./Overlay.module.css";
import { useMediaQuery } from "./useMediaQuery"; import { useMediaQuery } from "./useMediaQuery";
import { Glass } from "./Glass"; import { Glass } from "./Glass";
@@ -85,9 +86,14 @@ export function Modal({
dismissible={onDismiss !== undefined} dismissible={onDismiss !== undefined}
> >
<Drawer.Portal> <Drawer.Portal>
<Drawer.Overlay className={styles.overlay} /> <Drawer.Overlay className={classNames(overlayStyles.bg)} />
<Drawer.Content <Drawer.Content
className={classNames(className, styles.modal, styles.drawer)} className={classNames(
className,
overlayStyles.overlay,
styles.modal,
styles.drawer
)}
{...rest} {...rest}
> >
<div className={styles.content}> <div className={styles.content}>
@@ -108,12 +114,18 @@ export function Modal({
<DialogRoot open={open} onOpenChange={onOpenChange}> <DialogRoot open={open} onOpenChange={onOpenChange}>
<DialogPortal> <DialogPortal>
<DialogOverlay <DialogOverlay
className={classNames(styles.overlay, styles.dialogOverlay)} className={classNames(overlayStyles.bg, overlayStyles.animate)}
/> />
<DialogContent asChild {...rest}> <DialogContent asChild {...rest}>
<Glass <Glass
frosted frosted
className={classNames(className, styles.modal, styles.dialog)} className={classNames(
className,
overlayStyles.overlay,
overlayStyles.animate,
styles.modal,
styles.dialog
)}
> >
<div className={styles.content}> <div className={styles.content}>
<div className={styles.header}> <div className={styles.header}>

99
src/Overlay.module.css Normal file
View File

@@ -0,0 +1,99 @@
/*
Copyright 2023 New Vector Ltd
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
.bg {
position: fixed;
z-index: 100;
inset: 0;
background: rgba(3, 12, 27, 0.528);
}
@keyframes fade-in {
from {
opacity: 0;
}
to {
opacity: 1;
}
}
.bg.animate[data-state="open"] {
animation: fade-in 200ms;
}
@keyframes fade-out {
from {
opacity: 1;
}
to {
opacity: 0;
}
}
.bg.animate[data-state="closed"] {
animation: fade-out 130ms;
}
.overlay {
position: fixed;
z-index: 101;
}
.overlay.animate {
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
}
@keyframes zoom-in {
from {
opacity: 0;
transform: translate(-50%, -50%) scale(80%);
}
to {
opacity: 1;
transform: translate(-50%, -50%) scale(100%);
}
}
@keyframes zoom-out {
from {
opacity: 1;
transform: translate(-50%, -50%) scale(100%);
}
to {
opacity: 0;
transform: translate(-50%, -50%) scale(80%);
}
}
.overlay.animate[data-state="open"] {
animation: zoom-in 200ms;
}
.overlay.animate[data-state="closed"] {
animation: zoom-out 130ms;
}
@media (prefers-reduced-motion) {
.overlay.animate[data-state="open"] {
animation-name: fade-in;
}
.overlay.animate[data-state="closed"] {
animation-name: fade-out;
}
}

38
src/Toast.module.css Normal file
View File

@@ -0,0 +1,38 @@
/*
Copyright 2023 New Vector Ltd
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
.toast {
color: var(--cpd-color-text-on-solid-primary);
background: var(--cpd-color-alpha-gray-1200);
padding-inline: var(--cpd-space-3x);
padding-block: var(--cpd-space-1x);
border: none;
border-radius: var(--cpd-radius-pill-effect);
box-shadow: var(--small-drop-shadow);
display: flex;
align-items: center;
gap: var(--cpd-space-1x);
}
.toast > h3 {
margin: 0;
}
.toast > svg {
color: var(--cpd-color-icon-on-solid-primary);
flex-shrink: 0;
margin-inline-end: calc(-1 * var(--cpd-space-1x));
}

108
src/Toast.tsx Normal file
View File

@@ -0,0 +1,108 @@
/*
Copyright 2023 New Vector Ltd
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
import {
ComponentType,
FC,
SVGAttributes,
useCallback,
useEffect,
} from "react";
import {
Root as DialogRoot,
Portal as DialogPortal,
Overlay as DialogOverlay,
Content as DialogContent,
Close as DialogClose,
Title as DialogTitle,
} from "@radix-ui/react-dialog";
import classNames from "classnames";
import { Text } from "@vector-im/compound-web";
import styles from "./Toast.module.css";
import overlayStyles from "./Overlay.module.css";
interface Props {
/**
* The controlled open state of the toast.
*/
open: boolean;
/**
* Callback for when the user dismisses the toast.
*/
onDismiss: () => void;
/**
* A number of milliseconds after which the toast should be automatically
* dismissed.
*/
autoDismiss?: number;
children: string;
/**
* A supporting icon to display within the toast.
*/
Icon?: ComponentType<SVGAttributes<SVGElement>>;
}
/**
* A temporary message shown in an overlay in the center of the screen.
*/
export const Toast: FC<Props> = ({
open,
onDismiss,
autoDismiss,
children,
Icon,
}) => {
const onOpenChange = useCallback(
(open: boolean) => {
if (!open) onDismiss();
},
[onDismiss]
);
useEffect(() => {
if (open && autoDismiss !== undefined) {
const timeout = setTimeout(onDismiss, autoDismiss);
return () => clearTimeout(timeout);
}
}, [open, autoDismiss, onDismiss]);
return (
<DialogRoot open={open} onOpenChange={onOpenChange}>
<DialogPortal>
<DialogOverlay
className={classNames(overlayStyles.bg, overlayStyles.animate)}
/>
<DialogContent asChild>
<DialogClose
className={classNames(
overlayStyles.overlay,
overlayStyles.animate,
styles.toast
)}
>
<DialogTitle asChild>
<Text as="h3" size="sm" weight="semibold">
{children}
</Text>
</DialogTitle>
{Icon && <Icon width={20} height={20} aria-hidden />}
</DialogClose>
</DialogContent>
</DialogPortal>
</DialogRoot>
);
};

View File

@@ -24,10 +24,10 @@ import { PopoverMenuTrigger } from "./popover/PopoverMenu";
import { Menu } from "./Menu"; import { Menu } from "./Menu";
import { TooltipTrigger } from "./Tooltip"; import { TooltipTrigger } from "./Tooltip";
import { Avatar, Size } from "./Avatar"; import { Avatar, Size } from "./Avatar";
import { ReactComponent as UserIcon } from "./icons/User.svg"; import UserIcon from "./icons/User.svg?react";
import { ReactComponent as SettingsIcon } from "./icons/Settings.svg"; import SettingsIcon from "./icons/Settings.svg?react";
import { ReactComponent as LoginIcon } from "./icons/Login.svg"; import LoginIcon from "./icons/Login.svg?react";
import { ReactComponent as LogoutIcon } from "./icons/Logout.svg"; import LogoutIcon from "./icons/Logout.svg?react";
import { Body } from "./typography/Typography"; import { Body } from "./typography/Typography";
import styles from "./UserMenu.module.css"; import styles from "./UserMenu.module.css";

View File

@@ -18,7 +18,7 @@ import { FC, FormEvent, useCallback, useRef, useState } from "react";
import { useHistory, useLocation, Link } from "react-router-dom"; import { useHistory, useLocation, Link } from "react-router-dom";
import { Trans, useTranslation } from "react-i18next"; import { Trans, useTranslation } from "react-i18next";
import { ReactComponent as Logo } from "../icons/LogoLarge.svg"; import Logo from "../icons/LogoLarge.svg?react";
import { useClient } from "../ClientContext"; import { useClient } from "../ClientContext";
import { FieldRow, InputField, ErrorMessage } from "../input/Input"; import { FieldRow, InputField, ErrorMessage } from "../input/Input";
import { Button } from "../button"; import { Button } from "../button";

View File

@@ -34,7 +34,7 @@ import { Button } from "../button";
import { useClientLegacy } from "../ClientContext"; import { useClientLegacy } from "../ClientContext";
import { useInteractiveRegistration } from "./useInteractiveRegistration"; import { useInteractiveRegistration } from "./useInteractiveRegistration";
import styles from "./LoginPage.module.css"; import styles from "./LoginPage.module.css";
import { ReactComponent as Logo } from "../icons/LogoLarge.svg"; import Logo from "../icons/LogoLarge.svg?react";
import { LoadingView } from "../FullScreenView"; import { LoadingView } from "../FullScreenView";
import { useRecaptcha } from "./useRecaptcha"; import { useRecaptcha } from "./useRecaptcha";
import { Caption, Link } from "../typography/Typography"; import { Caption, Link } from "../typography/Typography";

View File

@@ -20,18 +20,18 @@ import { useButton } from "@react-aria/button";
import { mergeProps, useObjectRef } from "@react-aria/utils"; import { mergeProps, useObjectRef } from "@react-aria/utils";
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 { ReactComponent as MicOnSolidIcon } from "@vector-im/compound-design-tokens/icons/mic-on-solid.svg"; import MicOnSolidIcon from "@vector-im/compound-design-tokens/icons/mic-on-solid.svg?react";
import { ReactComponent as MicOffSolidIcon } from "@vector-im/compound-design-tokens/icons/mic-off-solid.svg"; import MicOffSolidIcon from "@vector-im/compound-design-tokens/icons/mic-off-solid.svg?react";
import { ReactComponent as VideoCallIcon } from "@vector-im/compound-design-tokens/icons/video-call.svg"; import VideoCallIcon from "@vector-im/compound-design-tokens/icons/video-call.svg?react";
import { ReactComponent as VideoCallOffIcon } from "@vector-im/compound-design-tokens/icons/video-call-off.svg"; import VideoCallOffIcon from "@vector-im/compound-design-tokens/icons/video-call-off.svg?react";
import { ReactComponent as EndCallIcon } from "@vector-im/compound-design-tokens/icons/end-call.svg"; import EndCallIcon from "@vector-im/compound-design-tokens/icons/end-call.svg?react";
import { ReactComponent as ShareScreenSolidIcon } from "@vector-im/compound-design-tokens/icons/share-screen-solid.svg"; import ShareScreenSolidIcon from "@vector-im/compound-design-tokens/icons/share-screen-solid.svg?react";
import { ReactComponent as SettingsSolidIcon } from "@vector-im/compound-design-tokens/icons/settings-solid.svg"; import SettingsSolidIcon from "@vector-im/compound-design-tokens/icons/settings-solid.svg?react";
import { ReactComponent as ChevronDownIcon } from "@vector-im/compound-design-tokens/icons/chevron-down.svg"; import ChevronDownIcon from "@vector-im/compound-design-tokens/icons/chevron-down.svg?react";
import styles from "./Button.module.css"; import styles from "./Button.module.css";
import { ReactComponent as Fullscreen } from "../icons/Fullscreen.svg"; import Fullscreen from "../icons/Fullscreen.svg?react";
import { ReactComponent as FullscreenExit } from "../icons/FullscreenExit.svg"; import FullscreenExit from "../icons/FullscreenExit.svg?react";
import { VolumeIcon } from "./VolumeIcon"; import { VolumeIcon } from "./VolumeIcon";
export type ButtonVariant = export type ButtonVariant =

View File

@@ -17,8 +17,8 @@ limitations under the License.
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import useClipboard from "react-use-clipboard"; import useClipboard from "react-use-clipboard";
import { ReactComponent as CheckIcon } from "../icons/Check.svg"; import CheckIcon from "../icons/Check.svg?react";
import { ReactComponent as CopyIcon } from "../icons/Copy.svg"; import CopyIcon from "../icons/Copy.svg?react";
import { Button, ButtonVariant } from "./Button"; import { Button, ButtonVariant } from "./Button";
interface Props { interface Props {

View File

@@ -17,15 +17,15 @@ limitations under the License.
import { ComponentPropsWithoutRef, FC } from "react"; import { ComponentPropsWithoutRef, 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 { ReactComponent as UserAddSolidIcon } from "@vector-im/compound-design-tokens/icons/user-add-solid.svg"; import UserAddSolidIcon from "@vector-im/compound-design-tokens/icons/user-add-solid.svg?react";
export const ShareButton: FC< export const InviteButton: FC<
Omit<ComponentPropsWithoutRef<"button">, "children"> Omit<ComponentPropsWithoutRef<"button">, "children">
> = (props) => { > = (props) => {
const { t } = useTranslation(); const { t } = useTranslation();
return ( return (
<Button kind="secondary" size="sm" Icon={UserAddSolidIcon} {...props}> <Button kind="secondary" size="sm" Icon={UserAddSolidIcon} {...props}>
{t("Share")} {t("Invite")}
</Button> </Button>
); );
}; };

View File

@@ -17,9 +17,9 @@ limitations under the License.
import { ComponentPropsWithoutRef, FC } from "react"; import { ComponentPropsWithoutRef, FC } from "react";
import { ReactComponent as AudioMuted } from "../icons/AudioMuted.svg"; import AudioMuted from "../icons/AudioMuted.svg?react";
import { ReactComponent as AudioLow } from "../icons/AudioLow.svg"; import AudioLow from "../icons/AudioLow.svg?react";
import { ReactComponent as Audio } from "../icons/Audio.svg"; import Audio from "../icons/Audio.svg?react";
interface Props extends ComponentPropsWithoutRef<"svg"> { interface Props extends ComponentPropsWithoutRef<"svg"> {
/** /**

View File

@@ -28,7 +28,7 @@ import { useTranslation } from "react-i18next";
import { Avatar, Size } from "../Avatar"; import { Avatar, Size } from "../Avatar";
import { Button } from "../button"; import { Button } from "../button";
import { ReactComponent as EditIcon } from "../icons/Edit.svg"; import EditIcon from "../icons/Edit.svg?react";
import styles from "./AvatarInputField.module.css"; import styles from "./AvatarInputField.module.css";
interface Props extends AllHTMLAttributes<HTMLInputElement> { interface Props extends AllHTMLAttributes<HTMLInputElement> {

View File

@@ -25,7 +25,7 @@ import {
import classNames from "classnames"; import classNames from "classnames";
import styles from "./Input.module.css"; import styles from "./Input.module.css";
import { ReactComponent as CheckIcon } from "../icons/Check.svg"; import CheckIcon from "../icons/Check.svg?react";
import { TranslatedError } from "../TranslatedError"; import { TranslatedError } from "../TranslatedError";
interface FieldRowProps { interface FieldRowProps {

View File

@@ -24,7 +24,7 @@ import { useTranslation } from "react-i18next";
import { Popover } from "../popover/Popover"; import { Popover } from "../popover/Popover";
import { ListBox } from "../ListBox"; import { ListBox } from "../ListBox";
import styles from "./SelectInput.module.css"; import styles from "./SelectInput.module.css";
import { ReactComponent as ArrowDownIcon } from "../icons/ArrowDown.svg"; import ArrowDownIcon from "../icons/ArrowDown.svg?react";
interface Props extends AriaSelectOptions<object> { interface Props extends AriaSelectOptions<object> {
className?: string; className?: string;

View File

@@ -17,8 +17,8 @@ import { useState } from "react";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import styles from "./StarRatingInput.module.css"; import styles from "./StarRatingInput.module.css";
import { ReactComponent as StarSelected } from "../icons/StarSelected.svg"; import StarSelected from "../icons/StarSelected.svg?react";
import { ReactComponent as StarUnselected } from "../icons/StarUnselected.svg"; import StarUnselected from "../icons/StarUnselected.svg?react";
interface Props { interface Props {
starCount: number; starCount: number;

View File

@@ -17,7 +17,7 @@ limitations under the License.
import { FC, MouseEvent, useCallback, useMemo, useState } from "react"; import { FC, 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 { ReactComponent as PopOutIcon } from "@vector-im/compound-design-tokens/icons/pop-out.svg"; import PopOutIcon from "@vector-im/compound-design-tokens/icons/pop-out.svg?react";
import { logger } from "matrix-js-sdk/src/logger"; import { logger } from "matrix-js-sdk/src/logger";
import { Modal } from "../Modal"; import { Modal } from "../Modal";

View File

@@ -17,8 +17,8 @@ limitations under the License.
import { FC } from "react"; import { 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 { ReactComponent as LockIcon } from "@vector-im/compound-design-tokens/icons/lock.svg"; import LockIcon from "@vector-im/compound-design-tokens/icons/lock.svg?react";
import { ReactComponent as LockOffIcon } from "@vector-im/compound-design-tokens/icons/lock-off.svg"; import LockOffIcon from "@vector-im/compound-design-tokens/icons/lock-off.svg?react";
import styles from "./EncryptionLock.module.css"; import styles from "./EncryptionLock.module.css";

View File

@@ -20,7 +20,7 @@ import { MatrixClient } from "matrix-js-sdk/src/client";
import { Room, isE2EESupported } from "livekit-client"; import { Room, isE2EESupported } 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 { MatrixRTCSession } from "matrix-js-sdk/src/matrixrtc/MatrixRTCSession";
import { JoinRule, RoomMember } from "matrix-js-sdk/src/matrix"; import { JoinRule } from "matrix-js-sdk/src/matrix";
import { Heading, Link, Text } from "@vector-im/compound-web"; import { Heading, Link, Text } from "@vector-im/compound-web";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
@@ -47,7 +47,7 @@ import { useEnableE2EE } from "../settings/useSetting";
import { useRoomAvatar } from "./useRoomAvatar"; import { useRoomAvatar } from "./useRoomAvatar";
import { useRoomName } from "./useRoomName"; import { useRoomName } from "./useRoomName";
import { useJoinRule } from "./useJoinRule"; import { useJoinRule } from "./useJoinRule";
import { ShareModal } from "./ShareModal"; import { InviteModal } from "./InviteModal";
declare global { declare global {
interface Window { interface Window {
@@ -111,18 +111,11 @@ export function GroupCallView({
client, client,
]); ]);
const participatingMembers = useMemo(() => { // Count each member only once, regardless of how many devices they use
const members: RoomMember[] = []; const participantCount = useMemo(
// Count each member only once, regardless of how many devices they use () => new Set<string>(memberships.map((m) => m.member.userId)).size,
const addedUserIds = new Set<string>(); [memberships]
for (const membership of memberships) { );
if (!addedUserIds.has(membership.member.userId)) {
addedUserIds.add(membership.member.userId);
members.push(membership.member);
}
}
return members;
}, [memberships]);
const deviceContext = useMediaDevices(); const deviceContext = useMediaDevices();
const latestDevices = useRef<MediaDevices>(); const latestDevices = useRef<MediaDevices>();
@@ -274,15 +267,15 @@ export function GroupCallView({
const joinRule = useJoinRule(rtcSession.room); const joinRule = useJoinRule(rtcSession.room);
const [shareModalOpen, setShareModalOpen] = useState(false); const [shareModalOpen, setInviteModalOpen] = useState(false);
const onDismissShareModal = useCallback( const onDismissInviteModal = useCallback(
() => setShareModalOpen(false), () => setInviteModalOpen(false),
[setShareModalOpen] [setInviteModalOpen]
); );
const onShareClickFn = useCallback( const onShareClickFn = useCallback(
() => setShareModalOpen(true), () => setInviteModalOpen(true),
[setShareModalOpen] [setInviteModalOpen]
); );
const onShareClick = joinRule === JoinRule.Public ? onShareClickFn : null; const onShareClick = joinRule === JoinRule.Public ? onShareClickFn : null;
@@ -325,10 +318,10 @@ export function GroupCallView({
} }
const shareModal = ( const shareModal = (
<ShareModal <InviteModal
room={rtcSession.room} room={rtcSession.room}
open={shareModalOpen} open={shareModalOpen}
onDismiss={onDismissShareModal} onDismiss={onDismissInviteModal}
/> />
); );
@@ -340,7 +333,7 @@ export function GroupCallView({
client={client} client={client}
matrixInfo={matrixInfo} matrixInfo={matrixInfo}
rtcSession={rtcSession} rtcSession={rtcSession}
participatingMembers={participatingMembers} participantCount={participantCount}
onLeave={onLeave} onLeave={onLeave}
hideHeader={hideHeader} hideHeader={hideHeader}
muteStates={muteStates} muteStates={muteStates}
@@ -391,7 +384,7 @@ export function GroupCallView({
onEnter={() => enterRTCSession(rtcSession)} onEnter={() => enterRTCSession(rtcSession)}
confineToRoom={confineToRoom} confineToRoom={confineToRoom}
hideHeader={hideHeader} hideHeader={hideHeader}
participatingMembers={participatingMembers} participantCount={participantCount}
onShareClick={onShareClick} onShareClick={onShareClick}
/> />
</> </>

View File

@@ -33,8 +33,8 @@ import useMeasure from "react-use-measure";
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 { MatrixRTCSession } from "matrix-js-sdk/src/matrixrtc/MatrixRTCSession";
import { ReactComponent as LogoMark } from "../icons/LogoMark.svg"; import LogoMark from "../icons/LogoMark.svg?react";
import { ReactComponent as LogoType } from "../icons/LogoType.svg"; import LogoType from "../icons/LogoType.svg?react";
import type { IWidgetApiRequest } from "matrix-widget-api"; import type { IWidgetApiRequest } from "matrix-widget-api";
import { import {
HangupButton, HangupButton,
@@ -69,7 +69,7 @@ import { useWakeLock } from "../useWakeLock";
import { useMergedRefs } from "../useMergedRefs"; import { useMergedRefs } from "../useMergedRefs";
import { MuteStates } from "./MuteStates"; import { MuteStates } from "./MuteStates";
import { MatrixInfo } from "./VideoPreview"; import { MatrixInfo } from "./VideoPreview";
import { ShareButton } from "../button/ShareButton"; import { InviteButton } from "../button/InviteButton";
import { LayoutToggle } from "./LayoutToggle"; import { LayoutToggle } from "./LayoutToggle";
import { import {
ECAddonConnectionState, ECAddonConnectionState,
@@ -120,7 +120,7 @@ export interface InCallViewProps {
rtcSession: MatrixRTCSession; rtcSession: MatrixRTCSession;
livekitRoom: Room; livekitRoom: Room;
muteStates: MuteStates; muteStates: MuteStates;
participatingMembers: RoomMember[]; participantCount: number;
onLeave: (error?: Error) => void; onLeave: (error?: Error) => void;
hideHeader: boolean; hideHeader: boolean;
otelGroupCallMembership?: OTelGroupCallMembership; otelGroupCallMembership?: OTelGroupCallMembership;
@@ -134,7 +134,7 @@ export function InCallView({
rtcSession, rtcSession,
livekitRoom, livekitRoom,
muteStates, muteStates,
participatingMembers, participantCount,
onLeave, onLeave,
hideHeader, hideHeader,
otelGroupCallMembership, otelGroupCallMembership,
@@ -410,13 +410,12 @@ export function InCallView({
name={matrixInfo.roomName} name={matrixInfo.roomName}
avatarUrl={matrixInfo.roomAvatar} avatarUrl={matrixInfo.roomAvatar}
encrypted={matrixInfo.roomEncrypted} encrypted={matrixInfo.roomEncrypted}
participants={participatingMembers} participantCount={participantCount}
client={client}
/> />
</LeftNav> </LeftNav>
<RightNav> <RightNav>
{!reducedControls && onShareClick !== null && ( {!reducedControls && onShareClick !== null && (
<ShareButton onClick={onShareClick} /> <InviteButton onClick={onShareClick} />
)} )}
</RightNav> </RightNav>
</Header> </Header>

View File

@@ -14,6 +14,12 @@ See the License for the specific language governing permissions and
limitations under the License. limitations under the License.
*/ */
.copyButton { .url {
text-align: center;
color: var(--cpd-color-text-secondary);
margin-block-end: var(--cpd-space-8x);
}
.button {
width: 100%; width: 100%;
} }

84
src/room/InviteModal.tsx Normal file
View File

@@ -0,0 +1,84 @@
/*
Copyright 2022 - 2023 New Vector Ltd
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
import { FC, MouseEvent, useCallback, useMemo, useState } from "react";
import { useTranslation } from "react-i18next";
import { Room } from "matrix-js-sdk";
import { Button, Text } from "@vector-im/compound-web";
import LinkIcon from "@vector-im/compound-design-tokens/icons/link.svg?react";
import CheckIcon from "@vector-im/compound-design-tokens/icons/check.svg?react";
import useClipboard from "react-use-clipboard";
import { Modal } from "../Modal";
import { getAbsoluteRoomUrl } from "../matrix-utils";
import styles from "./InviteModal.module.css";
import { useRoomSharedKey } from "../e2ee/sharedKeyManagement";
import { Toast } from "../Toast";
interface Props {
room: Room;
open: boolean;
onDismiss: () => void;
}
export const InviteModal: FC<Props> = ({ room, open, onDismiss }) => {
const { t } = useTranslation();
const roomSharedKey = useRoomSharedKey(room.roomId);
const url = useMemo(
() =>
getAbsoluteRoomUrl(room.roomId, room.name, roomSharedKey ?? undefined),
[room, roomSharedKey]
);
const [, setCopied] = useClipboard(url);
const [toastOpen, setToastOpen] = useState(false);
const onToastDismiss = useCallback(() => setToastOpen(false), [setToastOpen]);
const onButtonClick = useCallback(
(e: MouseEvent) => {
e.stopPropagation();
setCopied();
onDismiss();
setToastOpen(true);
},
[setCopied, onDismiss]
);
return (
<>
<Modal title={t("Invite to this call")} open={open} onDismiss={onDismiss}>
<Text className={styles.url} size="sm" weight="semibold">
{url}
</Text>
<Button
className={styles.button}
Icon={LinkIcon}
onClick={onButtonClick}
data-testid="modal_inviteLink"
>
{t("Copy link")}
</Button>
</Modal>
<Toast
open={toastOpen}
onDismiss={onToastDismiss}
autoDismiss={2000}
Icon={CheckIcon}
>
{t("Link copied to clipboard")}
</Toast>
</>
);
};

View File

@@ -17,8 +17,8 @@ limitations under the License.
import { ChangeEvent, FC, useCallback, useId } from "react"; import { ChangeEvent, FC, useCallback, useId } 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 { ReactComponent as SpotlightViewIcon } from "@vector-im/compound-design-tokens/icons/spotlight-view.svg"; import SpotlightViewIcon from "@vector-im/compound-design-tokens/icons/spotlight-view.svg?react";
import { ReactComponent as GridViewIcon } from "@vector-im/compound-design-tokens/icons/grid-view.svg"; import GridViewIcon from "@vector-im/compound-design-tokens/icons/grid-view.svg?react";
import classNames from "classnames"; import classNames from "classnames";
import styles from "./LayoutToggle.module.css"; import styles from "./LayoutToggle.module.css";

View File

@@ -16,7 +16,7 @@ limitations under the License.
import { FC, useCallback, useState } from "react"; import { FC, useCallback, useState } from "react";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { MatrixClient, RoomMember } from "matrix-js-sdk/src/matrix"; import { MatrixClient } from "matrix-js-sdk/src/matrix";
import { Button, Link } from "@vector-im/compound-web"; import { Button, Link } 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";
@@ -27,7 +27,7 @@ import { Header, LeftNav, RightNav, RoomHeaderInfo } from "../Header";
import { useLocationNavigation } from "../useLocationNavigation"; import { useLocationNavigation } from "../useLocationNavigation";
import { MatrixInfo, VideoPreview } from "./VideoPreview"; import { MatrixInfo, VideoPreview } from "./VideoPreview";
import { MuteStates } from "./MuteStates"; import { MuteStates } from "./MuteStates";
import { ShareButton } from "../button/ShareButton"; import { InviteButton } from "../button/InviteButton";
import { import {
HangupButton, HangupButton,
MicButton, MicButton,
@@ -44,7 +44,7 @@ interface Props {
onEnter: () => void; onEnter: () => void;
confineToRoom: boolean; confineToRoom: boolean;
hideHeader: boolean; hideHeader: boolean;
participatingMembers: RoomMember[]; participantCount: number;
onShareClick: (() => void) | null; onShareClick: (() => void) | null;
} }
@@ -55,7 +55,7 @@ export const LobbyView: FC<Props> = ({
onEnter, onEnter,
confineToRoom, confineToRoom,
hideHeader, hideHeader,
participatingMembers, participantCount,
onShareClick, onShareClick,
}) => { }) => {
const { t } = useTranslation(); const { t } = useTranslation();
@@ -104,12 +104,11 @@ export const LobbyView: FC<Props> = ({
name={matrixInfo.roomName} name={matrixInfo.roomName}
avatarUrl={matrixInfo.roomAvatar} avatarUrl={matrixInfo.roomAvatar}
encrypted={matrixInfo.roomEncrypted} encrypted={matrixInfo.roomEncrypted}
participants={participatingMembers} participantCount={participantCount}
client={client}
/> />
</LeftNav> </LeftNav>
<RightNav> <RightNav>
{onShareClick !== null && <ShareButton onClick={onShareClick} />} {onShareClick !== null && <InviteButton onClick={onShareClick} />}
</RightNav> </RightNav>
</Header> </Header>
)} )}

View File

@@ -1,51 +0,0 @@
/*
Copyright 2022 - 2023 New Vector Ltd
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
import { FC } from "react";
import { useTranslation } from "react-i18next";
import { Room } from "matrix-js-sdk";
import { Modal } from "../Modal";
import { CopyButton } from "../button";
import { getAbsoluteRoomUrl } from "../matrix-utils";
import styles from "./ShareModal.module.css";
import { useRoomSharedKey } from "../e2ee/sharedKeyManagement";
interface Props {
room: Room;
open: boolean;
onDismiss: () => void;
}
export const ShareModal: FC<Props> = ({ room, open, onDismiss }) => {
const { t } = useTranslation();
const roomSharedKey = useRoomSharedKey(room.roomId);
return (
<Modal title={t("Share this call")} open={open} onDismiss={onDismiss}>
<p>{t("Copy and share this call link")}</p>
<CopyButton
className={styles.copyButton}
value={getAbsoluteRoomUrl(
room.roomId,
room.name,
roomSharedKey ?? undefined
)}
data-testid="modal_inviteLink"
/>
</Modal>
);
};

View File

@@ -22,12 +22,12 @@ import { MatrixClient } from "matrix-js-sdk";
import { Modal } from "../Modal"; import { Modal } from "../Modal";
import styles from "./SettingsModal.module.css"; import styles from "./SettingsModal.module.css";
import { TabContainer, TabItem } from "../tabs/Tabs"; import { TabContainer, TabItem } from "../tabs/Tabs";
import { ReactComponent as AudioIcon } from "../icons/Audio.svg"; import AudioIcon from "../icons/Audio.svg?react";
import { ReactComponent as VideoIcon } from "../icons/Video.svg"; import VideoIcon from "../icons/Video.svg?react";
import { ReactComponent as DeveloperIcon } from "../icons/Developer.svg"; import DeveloperIcon from "../icons/Developer.svg?react";
import { ReactComponent as OverflowIcon } from "../icons/Overflow.svg"; import OverflowIcon from "../icons/Overflow.svg?react";
import { ReactComponent as UserIcon } from "../icons/User.svg"; import UserIcon from "../icons/User.svg?react";
import { ReactComponent as FeedbackIcon } from "../icons/Feedback.svg"; import FeedbackIcon from "../icons/Feedback.svg?react";
import { SelectInput } from "../input/SelectInput"; import { SelectInput } from "../input/SelectInput";
import { import {
useOptInAnalytics, useOptInAnalytics,

View File

@@ -17,9 +17,9 @@ limitations under the License.
import { FC } from "react"; import { FC } from "react";
import { TabContainer, TabItem } from "./Tabs"; import { TabContainer, TabItem } from "./Tabs";
import { ReactComponent as AudioIcon } from "../icons/Audio.svg"; import AudioIcon from "../icons/Audio.svg?react";
import { ReactComponent as VideoIcon } from "../icons/Video.svg"; import VideoIcon from "../icons/Video.svg?react";
import { ReactComponent as DeveloperIcon } from "../icons/Developer.svg"; import DeveloperIcon from "../icons/Developer.svg?react";
import { Body } from "../typography/Typography"; import { Body } from "../typography/Typography";
export default { export default {

View File

@@ -71,8 +71,7 @@ limitations under the License.
padding: var(--cpd-space-1x); padding: var(--cpd-space-1x);
padding-block: var(--cpd-space-1x); padding-block: var(--cpd-space-1x);
color: var(--cpd-color-text-primary); color: var(--cpd-color-text-primary);
/* TODO: un-hardcode this color. It comes from the dark theme. */ background-color: var(--cpd-color-bg-canvas-default);
background-color: rgba(237, 244, 252, 0.79);
display: flex; display: flex;
align-items: center; align-items: center;
border-radius: var(--cpd-radius-pill-effect); border-radius: var(--cpd-radius-pill-effect);
@@ -83,11 +82,6 @@ limitations under the License.
box-shadow: var(--small-drop-shadow); box-shadow: var(--small-drop-shadow);
} }
:global(.cpd-theme-dark) .nameTag {
/* TODO: un-hardcode this color. It comes from the light theme. */
background-color: rgba(2, 7, 13, 0.77);
}
.nameTag > svg { .nameTag > svg {
flex-shrink: 0; flex-shrink: 0;
} }

View File

@@ -34,8 +34,8 @@ import {
RoomMember, RoomMember,
RoomMemberEvent, RoomMemberEvent,
} from "matrix-js-sdk/src/models/room-member"; } from "matrix-js-sdk/src/models/room-member";
import { ReactComponent as MicOnSolidIcon } from "@vector-im/compound-design-tokens/icons/mic-on-solid.svg"; import MicOnSolidIcon from "@vector-im/compound-design-tokens/icons/mic-on-solid.svg?react";
import { ReactComponent as MicOffSolidIcon } from "@vector-im/compound-design-tokens/icons/mic-off-solid.svg"; import MicOffSolidIcon from "@vector-im/compound-design-tokens/icons/mic-off-solid.svg?react";
import { Text } from "@vector-im/compound-web"; import { Text } from "@vector-im/compound-web";
import { Avatar } from "../Avatar"; import { Avatar } from "../Avatar";

59
test/Toast-test.tsx Normal file
View File

@@ -0,0 +1,59 @@
/*
Copyright 2023 New Vector Ltd
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
import { screen, render } from "@testing-library/react";
import { Toast } from "../src/Toast";
import userEvent from "@testing-library/user-event";
import { withFakeTimers } from "./utils";
test("Toast renders", () => {
render(
<Toast open={false} onDismiss={() => {}}>
Hello world!
</Toast>
);
expect(screen.queryByRole("dialog")).toBe(null);
render(
<Toast open={true} onDismiss={() => {}}>
Hello world!
</Toast>
);
expect(screen.getByRole("dialog")).toMatchSnapshot();
});
test("Toast dismisses when clicked", async () => {
const onDismiss = jest.fn();
render(
<Toast open={true} onDismiss={onDismiss}>
Hello world!
</Toast>
);
await userEvent.click(screen.getByRole("dialog"));
expect(onDismiss).toHaveBeenCalled();
});
test("Toast dismisses itself after the specified timeout", async () => {
withFakeTimers(() => {
const onDismiss = jest.fn();
render(
<Toast open={true} onDismiss={onDismiss} autoDismiss={2000}>
Hello world!
</Toast>
);
jest.advanceTimersByTime(2000);
expect(onDismiss).toHaveBeenCalled();
});
});

View File

@@ -0,0 +1,22 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`Toast renders 1`] = `
<button
aria-describedby="radix-:r5:"
aria-labelledby="radix-:r4:"
class="overlay animate toast"
data-state="open"
id="radix-:r3:"
role="dialog"
style="pointer-events: auto;"
tabindex="-1"
type="button"
>
<h3
class="_font-body-sm-semibold_1jx6b_45"
id="radix-:r4:"
>
Hello world!
</h3>
</button>
`;

View File

@@ -1,3 +1,3 @@
// Mock file for SVG imports // Mock file for SVG imports
export default "SvgrURL"; const ReactComponent = "svg";
export const ReactComponent = "div"; export default ReactComponent;

View File

@@ -18,15 +18,7 @@ import { Mocked, mocked } from "jest-mock";
import { RoomState } from "matrix-js-sdk/src/models/room-state"; import { 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";
import { withFakeTimers } from "../utils";
const withFakeTimers = (continuation: () => void) => {
jest.useFakeTimers();
try {
continuation();
} finally {
jest.useRealTimers();
}
};
const withMockedPosthog = ( const withMockedPosthog = (
continuation: (posthog: Mocked<PosthogAnalytics>) => void continuation: (posthog: Mocked<PosthogAnalytics>) => void

24
test/utils.ts Normal file
View File

@@ -0,0 +1,24 @@
/*
Copyright 2023 New Vector Ltd
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
export function withFakeTimers(continuation: () => void): void {
jest.useFakeTimers();
try {
continuation();
} finally {
jest.useRealTimers();
}
}

255
yarn.lock
View File

@@ -65,7 +65,28 @@
semver "^5.4.1" semver "^5.4.1"
source-map "^0.5.0" source-map "^0.5.0"
"@babel/core@^7.11.6", "@babel/core@^7.12.10", "@babel/core@^7.12.3", "@babel/core@^7.16.5", "@babel/core@^7.17.10", "@babel/core@^7.21.3", "@babel/core@^7.22.20", "@babel/core@^7.7.5": "@babel/core@^7.11.6", "@babel/core@^7.12.10", "@babel/core@^7.12.3", "@babel/core@^7.16.5", "@babel/core@^7.17.10", "@babel/core@^7.7.5":
version "7.22.20"
resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.22.20.tgz#e3d0eed84c049e2a2ae0a64d27b6a37edec385b7"
integrity sha512-Y6jd1ahLubuYweD/zJH+vvOY141v4f9igNQAQ+MBgq9JlHS2iTsZKn1aMsb3vGccZsXI16VzTBw52Xx0DWmtnA==
dependencies:
"@ampproject/remapping" "^2.2.0"
"@babel/code-frame" "^7.22.13"
"@babel/generator" "^7.22.15"
"@babel/helper-compilation-targets" "^7.22.15"
"@babel/helper-module-transforms" "^7.22.20"
"@babel/helpers" "^7.22.15"
"@babel/parser" "^7.22.16"
"@babel/template" "^7.22.15"
"@babel/traverse" "^7.22.20"
"@babel/types" "^7.22.19"
convert-source-map "^1.7.0"
debug "^4.1.0"
gensync "^1.0.0-beta.2"
json5 "^2.2.3"
semver "^6.3.1"
"@babel/core@^7.21.3", "@babel/core@^7.22.20":
version "7.23.0" version "7.23.0"
resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.23.0.tgz#f8259ae0e52a123eb40f552551e647b506a94d83" resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.23.0.tgz#f8259ae0e52a123eb40f552551e647b506a94d83"
integrity sha512-97z/ju/Jy1rZmDxybphrBuI+jtJjFVoz7Mr9yUQVVVi+DNZE333uFQeMOqcCIy1x3WYBIbWftUSLmbNXNT7qFQ== integrity sha512-97z/ju/Jy1rZmDxybphrBuI+jtJjFVoz7Mr9yUQVVVi+DNZE333uFQeMOqcCIy1x3WYBIbWftUSLmbNXNT7qFQ==
@@ -96,6 +117,16 @@
"@jridgewell/trace-mapping" "^0.3.17" "@jridgewell/trace-mapping" "^0.3.17"
jsesc "^2.5.1" jsesc "^2.5.1"
"@babel/generator@^7.22.15", "@babel/generator@^7.7.2":
version "7.22.15"
resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.22.15.tgz#1564189c7ec94cb8f77b5e8a90c4d200d21b2339"
integrity sha512-Zu9oWARBqeVOW0dZOjXc3JObrzuqothQ3y/n1kUtrjCoCPLkXUwMvOo/F/TCfoHMbWIFlWwpZtkZVb9ga4U2pA==
dependencies:
"@babel/types" "^7.22.15"
"@jridgewell/gen-mapping" "^0.3.2"
"@jridgewell/trace-mapping" "^0.3.17"
jsesc "^2.5.1"
"@babel/generator@^7.23.0": "@babel/generator@^7.23.0":
version "7.23.0" version "7.23.0"
resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.23.0.tgz#df5c386e2218be505b34837acbcb874d7a983420" resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.23.0.tgz#df5c386e2218be505b34837acbcb874d7a983420"
@@ -106,16 +137,6 @@
"@jridgewell/trace-mapping" "^0.3.17" "@jridgewell/trace-mapping" "^0.3.17"
jsesc "^2.5.1" jsesc "^2.5.1"
"@babel/generator@^7.7.2":
version "7.22.15"
resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.22.15.tgz#1564189c7ec94cb8f77b5e8a90c4d200d21b2339"
integrity sha512-Zu9oWARBqeVOW0dZOjXc3JObrzuqothQ3y/n1kUtrjCoCPLkXUwMvOo/F/TCfoHMbWIFlWwpZtkZVb9ga4U2pA==
dependencies:
"@babel/types" "^7.22.15"
"@jridgewell/gen-mapping" "^0.3.2"
"@jridgewell/trace-mapping" "^0.3.17"
jsesc "^2.5.1"
"@babel/helper-annotate-as-pure@^7.18.6", "@babel/helper-annotate-as-pure@^7.22.5": "@babel/helper-annotate-as-pure@^7.18.6", "@babel/helper-annotate-as-pure@^7.22.5":
version "7.22.5" version "7.22.5"
resolved "https://registry.yarnpkg.com/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.22.5.tgz#e7f06737b197d580a01edf75d97e2c8be99d3882" resolved "https://registry.yarnpkg.com/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.22.5.tgz#e7f06737b197d580a01edf75d97e2c8be99d3882"
@@ -253,6 +274,17 @@
"@babel/helper-split-export-declaration" "^7.22.6" "@babel/helper-split-export-declaration" "^7.22.6"
"@babel/helper-validator-identifier" "^7.22.5" "@babel/helper-validator-identifier" "^7.22.5"
"@babel/helper-module-transforms@^7.22.20":
version "7.22.20"
resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.22.20.tgz#da9edc14794babbe7386df438f3768067132f59e"
integrity sha512-dLT7JVWIUUxKOs1UnJUBR3S70YK+pKX6AbJgB2vMIvEkZkrfJDbYDJesnPshtKV4LhDOR3Oc5YULeDizRek+5A==
dependencies:
"@babel/helper-environment-visitor" "^7.22.20"
"@babel/helper-module-imports" "^7.22.15"
"@babel/helper-simple-access" "^7.22.5"
"@babel/helper-split-export-declaration" "^7.22.6"
"@babel/helper-validator-identifier" "^7.22.20"
"@babel/helper-module-transforms@^7.22.5", "@babel/helper-module-transforms@^7.23.0": "@babel/helper-module-transforms@^7.22.5", "@babel/helper-module-transforms@^7.23.0":
version "7.23.0" version "7.23.0"
resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.23.0.tgz#3ec246457f6c842c0aee62a01f60739906f7047e" resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.23.0.tgz#3ec246457f6c842c0aee62a01f60739906f7047e"
@@ -353,6 +385,15 @@
"@babel/traverse" "^7.22.11" "@babel/traverse" "^7.22.11"
"@babel/types" "^7.22.11" "@babel/types" "^7.22.11"
"@babel/helpers@^7.22.15":
version "7.22.15"
resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.22.15.tgz#f09c3df31e86e3ea0b7ff7556d85cdebd47ea6f1"
integrity sha512-7pAjK0aSdxOwR+CcYAqgWOGy5dcfvzsTIfFTb2odQqW47MDfv14UaJDY6eng8ylM2EaeKXdxaSWESbkmaQHTmw==
dependencies:
"@babel/template" "^7.22.15"
"@babel/traverse" "^7.22.15"
"@babel/types" "^7.22.15"
"@babel/helpers@^7.23.0": "@babel/helpers@^7.23.0":
version "7.23.1" version "7.23.1"
resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.23.1.tgz#44e981e8ce2b9e99f8f0b703f3326a4636c16d15" resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.23.1.tgz#44e981e8ce2b9e99f8f0b703f3326a4636c16d15"
@@ -381,7 +422,7 @@
resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.22.14.tgz#c7de58e8de106e88efca42ce17f0033209dfd245" resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.22.14.tgz#c7de58e8de106e88efca42ce17f0033209dfd245"
integrity sha512-1KucTHgOvaw/LzCVrEOAyXkr9rQlp0A1HiHRYnSUE9dmb8PvPW7o5sscg+5169r54n3vGlbx6GevTE/Iw/P3AQ== integrity sha512-1KucTHgOvaw/LzCVrEOAyXkr9rQlp0A1HiHRYnSUE9dmb8PvPW7o5sscg+5169r54n3vGlbx6GevTE/Iw/P3AQ==
"@babel/parser@^7.14.7": "@babel/parser@^7.14.7", "@babel/parser@^7.22.16":
version "7.22.16" version "7.22.16"
resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.22.16.tgz#180aead7f247305cce6551bea2720934e2fa2c95" resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.22.16.tgz#180aead7f247305cce6551bea2720934e2fa2c95"
integrity sha512-+gPfKv8UWeKKeJTUxe59+OobVcrYHETCsORl61EmSkmgymguYk/X5bp7GuUIXaFsc6y++v8ZxPsLSSuujqDphA== integrity sha512-+gPfKv8UWeKKeJTUxe59+OobVcrYHETCsORl61EmSkmgymguYk/X5bp7GuUIXaFsc6y++v8ZxPsLSSuujqDphA==
@@ -1362,6 +1403,22 @@
debug "^4.1.0" debug "^4.1.0"
globals "^11.1.0" globals "^11.1.0"
"@babel/traverse@^7.22.15", "@babel/traverse@^7.22.20":
version "7.22.20"
resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.22.20.tgz#db572d9cb5c79e02d83e5618b82f6991c07584c9"
integrity sha512-eU260mPZbU7mZ0N+X10pxXhQFMGTeLb9eFS0mxehS8HZp9o1uSnFeWQuG1UPrlxgA7QoUzFhOnilHDp0AXCyHw==
dependencies:
"@babel/code-frame" "^7.22.13"
"@babel/generator" "^7.22.15"
"@babel/helper-environment-visitor" "^7.22.20"
"@babel/helper-function-name" "^7.22.5"
"@babel/helper-hoist-variables" "^7.22.5"
"@babel/helper-split-export-declaration" "^7.22.6"
"@babel/parser" "^7.22.16"
"@babel/types" "^7.22.19"
debug "^4.1.0"
globals "^11.1.0"
"@babel/traverse@^7.23.0": "@babel/traverse@^7.23.0":
version "7.23.0" version "7.23.0"
resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.23.0.tgz#18196ddfbcf4ccea324b7f6d3ada00d8c5a99c53" resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.23.0.tgz#18196ddfbcf4ccea324b7f6d3ada00d8c5a99c53"
@@ -1396,7 +1453,7 @@
"@babel/helper-validator-identifier" "^7.22.5" "@babel/helper-validator-identifier" "^7.22.5"
to-fast-properties "^2.0.0" to-fast-properties "^2.0.0"
"@babel/types@^7.3.3": "@babel/types@^7.22.19", "@babel/types@^7.3.3":
version "7.22.19" version "7.22.19"
resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.22.19.tgz#7425343253556916e440e662bb221a93ddb75684" resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.22.19.tgz#7425343253556916e440e662bb221a93ddb75684"
integrity sha512-P7LAw/LbojPzkgp5oznjE6tQEIWbp4PkkfrZDINTro9zgBRtI324/EYsiSI7lhPbpIQ+DCeR2NNmMWANGGfZsg== integrity sha512-P7LAw/LbojPzkgp5oznjE6tQEIWbp4PkkfrZDINTro9zgBRtI324/EYsiSI7lhPbpIQ+DCeR2NNmMWANGGfZsg==
@@ -3326,15 +3383,27 @@
"@sentry/utils" "7.69.0" "@sentry/utils" "7.69.0"
tslib "^2.4.1 || ^1.9.3" tslib "^2.4.1 || ^1.9.3"
"@sentry/browser@6.19.7": "@sentry-internal/tracing@7.72.0":
version "6.19.7" version "7.72.0"
resolved "https://registry.yarnpkg.com/@sentry/browser/-/browser-6.19.7.tgz#a40b6b72d911b5f1ed70ed3b4e7d4d4e625c0b5f" resolved "https://registry.yarnpkg.com/@sentry-internal/tracing/-/tracing-7.72.0.tgz#6293a08b8b3dff80499207a4b4994ae70aafc34c"
integrity sha512-oDbklp4O3MtAM4mtuwyZLrgO1qDVYIujzNJQzXmi9YzymJCuzMLSRDvhY83NNDCRxf0pds4DShgYeZdbSyKraA== integrity sha512-DToryaRSHk9R5RLgN4ktYEXZjQdqncOAWPqyyIurji8lIobXFRfmLtGL1wjoCK6sQNgWsjhSM9kXxwGnva1DNw==
dependencies: dependencies:
"@sentry/core" "6.19.7" "@sentry/core" "7.72.0"
"@sentry/types" "6.19.7" "@sentry/types" "7.72.0"
"@sentry/utils" "6.19.7" "@sentry/utils" "7.72.0"
tslib "^1.9.3" tslib "^2.4.1 || ^1.9.3"
"@sentry/browser@7.72.0":
version "7.72.0"
resolved "https://registry.yarnpkg.com/@sentry/browser/-/browser-7.72.0.tgz#8920d32920031de7ef70140ac13de267e773e5c7"
integrity sha512-fcFDTzqhPd3VZAmmYW3KvBTBaEfrKjPmRhlAsfhkGWYLCHqVkNtzsFER4cmUNRGNxjyt9tcG3WlTTqgLRucycQ==
dependencies:
"@sentry-internal/tracing" "7.72.0"
"@sentry/core" "7.72.0"
"@sentry/replay" "7.72.0"
"@sentry/types" "7.72.0"
"@sentry/utils" "7.72.0"
tslib "^2.4.1 || ^1.9.3"
"@sentry/bundler-plugin-core@2.7.1": "@sentry/bundler-plugin-core@2.7.1":
version "2.7.1" version "2.7.1"
@@ -3361,17 +3430,6 @@
proxy-from-env "^1.1.0" proxy-from-env "^1.1.0"
which "^2.0.2" which "^2.0.2"
"@sentry/core@6.19.7":
version "6.19.7"
resolved "https://registry.yarnpkg.com/@sentry/core/-/core-6.19.7.tgz#156aaa56dd7fad8c89c145be6ad7a4f7209f9785"
integrity sha512-tOfZ/umqB2AcHPGbIrsFLcvApdTm9ggpi/kQZFkej7kMphjT+SGBiQfYtjyg9jcRW+ilAR4JXC9BGKsdEQ+8Vw==
dependencies:
"@sentry/hub" "6.19.7"
"@sentry/minimal" "6.19.7"
"@sentry/types" "6.19.7"
"@sentry/utils" "6.19.7"
tslib "^1.9.3"
"@sentry/core@7.69.0": "@sentry/core@7.69.0":
version "7.69.0" version "7.69.0"
resolved "https://registry.yarnpkg.com/@sentry/core/-/core-7.69.0.tgz#ebbe01df573f438f8613107020a4e18eb9adca4d" resolved "https://registry.yarnpkg.com/@sentry/core/-/core-7.69.0.tgz#ebbe01df573f438f8613107020a4e18eb9adca4d"
@@ -3381,23 +3439,14 @@
"@sentry/utils" "7.69.0" "@sentry/utils" "7.69.0"
tslib "^2.4.1 || ^1.9.3" tslib "^2.4.1 || ^1.9.3"
"@sentry/hub@6.19.7": "@sentry/core@7.72.0":
version "6.19.7" version "7.72.0"
resolved "https://registry.yarnpkg.com/@sentry/hub/-/hub-6.19.7.tgz#58ad7776bbd31e9596a8ec46365b45cd8b9cfd11" resolved "https://registry.yarnpkg.com/@sentry/core/-/core-7.72.0.tgz#df19f9dc1c2cfc5993a73c0c36283c35f9c52f94"
integrity sha512-y3OtbYFAqKHCWezF0EGGr5lcyI2KbaXW2Ik7Xp8Mu9TxbSTuwTe4rTntwg8ngPjUQU3SUHzgjqVB8qjiGqFXCA== integrity sha512-G03JdQ5ZsFNRjcNNi+QvCjqOuBvYqU92Gs1T2iK3GE8dSBTu2khThydMpG4xrKZQLIpHOyiIhlFZiuPtZ66W8w==
dependencies: dependencies:
"@sentry/types" "6.19.7" "@sentry/types" "7.72.0"
"@sentry/utils" "6.19.7" "@sentry/utils" "7.72.0"
tslib "^1.9.3" tslib "^2.4.1 || ^1.9.3"
"@sentry/minimal@6.19.7":
version "6.19.7"
resolved "https://registry.yarnpkg.com/@sentry/minimal/-/minimal-6.19.7.tgz#b3ee46d6abef9ef3dd4837ebcb6bdfd01b9aa7b4"
integrity sha512-wcYmSJOdvk6VAPx8IcmZgN08XTXRwRtB1aOLZm+MVHjIZIhHoBGZJYTVQS/BWjldsamj2cX3YGbGXNunaCfYJQ==
dependencies:
"@sentry/hub" "6.19.7"
"@sentry/types" "6.19.7"
tslib "^1.9.3"
"@sentry/node@^7.60.0": "@sentry/node@^7.60.0":
version "7.69.0" version "7.69.0"
@@ -3413,46 +3462,42 @@
lru_map "^0.3.3" lru_map "^0.3.3"
tslib "^2.4.1 || ^1.9.3" tslib "^2.4.1 || ^1.9.3"
"@sentry/react@^6.13.3": "@sentry/react@^7.0.0":
version "6.19.7" version "7.72.0"
resolved "https://registry.yarnpkg.com/@sentry/react/-/react-6.19.7.tgz#58cc2d6da20f7d3b0df40638dfbbbc86c9c85caf" resolved "https://registry.yarnpkg.com/@sentry/react/-/react-7.72.0.tgz#badb4b5e28d27c892917210a6816cb6a2af2c2a5"
integrity sha512-VzJeBg/v41jfxUYPkH2WYrKjWc4YiMLzDX0f4Zf6WkJ4v3IlDDSkX6DfmWekjTKBho6wiMkSNy2hJ1dHfGZ9jA== integrity sha512-BYFO3uyB9FfdUq05NtsS+OfU636HMZ7avbSEALo24x+OPuaD+fCByTdgxYVpDRYrBPa7lALYzCge0PDcGnGiig==
dependencies: dependencies:
"@sentry/browser" "6.19.7" "@sentry/browser" "7.72.0"
"@sentry/minimal" "6.19.7" "@sentry/types" "7.72.0"
"@sentry/types" "6.19.7" "@sentry/utils" "7.72.0"
"@sentry/utils" "6.19.7"
hoist-non-react-statics "^3.3.2" hoist-non-react-statics "^3.3.2"
tslib "^1.9.3" tslib "^2.4.1 || ^1.9.3"
"@sentry/tracing@^6.13.3": "@sentry/replay@7.72.0":
version "6.19.7" version "7.72.0"
resolved "https://registry.yarnpkg.com/@sentry/tracing/-/tracing-6.19.7.tgz#54bb99ed5705931cd33caf71da347af769f02a4c" resolved "https://registry.yarnpkg.com/@sentry/replay/-/replay-7.72.0.tgz#39da5d971045a6d9bf5d3bd16ccc1f5c0c42c4c8"
integrity sha512-ol4TupNnv9Zd+bZei7B6Ygnr9N3Gp1PUrNI761QSlHtPC25xXC5ssSD3GMhBgyQrcvpuRcCFHVNNM97tN5cZiA== integrity sha512-dHH/mYCFBwJ/kYmL9L5KihjwQKcefiuvcH0otHSwKSpbbeEoM/BV+SHQoYGd6OMSYnL9fq1dHfF7Zo26p5Yu0Q==
dependencies: dependencies:
"@sentry/hub" "6.19.7" "@sentry/core" "7.72.0"
"@sentry/minimal" "6.19.7" "@sentry/types" "7.72.0"
"@sentry/types" "6.19.7" "@sentry/utils" "7.72.0"
"@sentry/utils" "6.19.7"
tslib "^1.9.3"
"@sentry/types@6.19.7": "@sentry/tracing@^7.0.0":
version "6.19.7" version "7.72.0"
resolved "https://registry.yarnpkg.com/@sentry/types/-/types-6.19.7.tgz#c6b337912e588083fc2896eb012526cf7cfec7c7" resolved "https://registry.yarnpkg.com/@sentry/tracing/-/tracing-7.72.0.tgz#1b6a0475d1e9e19ffb5ead87be011e9c6a0941ae"
integrity sha512-jH84pDYE+hHIbVnab3Hr+ZXr1v8QABfhx39KknxqKWr2l0oEItzepV0URvbEhB446lk/S/59230dlUUIBGsXbg== integrity sha512-DOMlyviMLNwWgN4gJw/TrHaAdBcZWvm8xLbgwMwrihRn/m84kmH2Ui1FUYpL30o/mH+mQS+53IHZukrgQjHkZA==
dependencies:
"@sentry-internal/tracing" "7.72.0"
"@sentry/types@7.69.0": "@sentry/types@7.69.0":
version "7.69.0" version "7.69.0"
resolved "https://registry.yarnpkg.com/@sentry/types/-/types-7.69.0.tgz#012b8d90d270a473cc2a5cf58a56870542739292" resolved "https://registry.yarnpkg.com/@sentry/types/-/types-7.69.0.tgz#012b8d90d270a473cc2a5cf58a56870542739292"
integrity sha512-zPyCox0mzitzU6SIa1KIbNoJAInYDdUpdiA+PoUmMn2hFMH1llGU/cS7f4w/mAsssTlbtlBi72RMnWUCy578bw== integrity sha512-zPyCox0mzitzU6SIa1KIbNoJAInYDdUpdiA+PoUmMn2hFMH1llGU/cS7f4w/mAsssTlbtlBi72RMnWUCy578bw==
"@sentry/utils@6.19.7": "@sentry/types@7.72.0":
version "6.19.7" version "7.72.0"
resolved "https://registry.yarnpkg.com/@sentry/utils/-/utils-6.19.7.tgz#6edd739f8185fd71afe49cbe351c1bbf5e7b7c79" resolved "https://registry.yarnpkg.com/@sentry/types/-/types-7.72.0.tgz#b474d3821338a545fb2db109715d9aad502bc810"
integrity sha512-z95ECmE3i9pbWoXQrD/7PgkBAzJYR+iXtPuTkpBjDKs86O3mT+PXOT3BAn79w2wkn7/i3vOGD2xVr1uiMl26dA== integrity sha512-g6u0mk62yGshx02rfFADIfyR/S9VXcf3RG2qQPuvykrWtOfN/BOTrZypF7I+MiqKwRW76r3Pcu2C/AB+6z9XQA==
dependencies:
"@sentry/types" "6.19.7"
tslib "^1.9.3"
"@sentry/utils@7.69.0", "@sentry/utils@^7.60.0": "@sentry/utils@7.69.0", "@sentry/utils@^7.60.0":
version "7.69.0" version "7.69.0"
@@ -3462,6 +3507,14 @@
"@sentry/types" "7.69.0" "@sentry/types" "7.69.0"
tslib "^2.4.1 || ^1.9.3" tslib "^2.4.1 || ^1.9.3"
"@sentry/utils@7.72.0":
version "7.72.0"
resolved "https://registry.yarnpkg.com/@sentry/utils/-/utils-7.72.0.tgz#798c764ac61bb658e2117792010ccd20ad8c7b02"
integrity sha512-o/MtqI7WJXuswidH0bSgBP40KN2lrnyQEIx5uoyJUJi/QEaboIsqbxU62vaFJpde8SYrbA+rTnP3J3ujF2gUag==
dependencies:
"@sentry/types" "7.72.0"
tslib "^2.4.1 || ^1.9.3"
"@sentry/vite-plugin@^2.0.0": "@sentry/vite-plugin@^2.0.0":
version "2.7.1" version "2.7.1"
resolved "https://registry.yarnpkg.com/@sentry/vite-plugin/-/vite-plugin-2.7.1.tgz#23fa4c95079c3f2ba10b851dce7452c16adc82c8" resolved "https://registry.yarnpkg.com/@sentry/vite-plugin/-/vite-plugin-2.7.1.tgz#23fa4c95079c3f2ba10b851dce7452c16adc82c8"
@@ -4332,6 +4385,11 @@
"@testing-library/dom" "^9.0.0" "@testing-library/dom" "^9.0.0"
"@types/react-dom" "^18.0.0" "@types/react-dom" "^18.0.0"
"@testing-library/user-event@^14.5.1":
version "14.5.1"
resolved "https://registry.yarnpkg.com/@testing-library/user-event/-/user-event-14.5.1.tgz#27337d72046d5236b32fd977edee3f74c71d332f"
integrity sha512-UCcUKrUYGj7ClomOo2SpNVvx4/fkd/2BbIHDCle8A0ax+P3bU7yJwDBDrS6ZwdTMARWTGODX1hEsCcO+7beJjg==
"@tootallnate/once@2": "@tootallnate/once@2":
version "2.0.0" version "2.0.0"
resolved "https://registry.yarnpkg.com/@tootallnate/once/-/once-2.0.0.tgz#f544a148d3ab35801c1f633a7441fd87c2e484bf" resolved "https://registry.yarnpkg.com/@tootallnate/once/-/once-2.0.0.tgz#f544a148d3ab35801c1f633a7441fd87c2e484bf"
@@ -4392,9 +4450,9 @@
"@babel/types" "^7.20.7" "@babel/types" "^7.20.7"
"@types/caseless@*": "@types/caseless@*":
version "0.12.2" version "0.12.3"
resolved "https://registry.yarnpkg.com/@types/caseless/-/caseless-0.12.2.tgz#f65d3d6389e01eeb458bd54dc8f52b95a9463bc8" resolved "https://registry.yarnpkg.com/@types/caseless/-/caseless-0.12.3.tgz#8f7d6c8b536af838966b77ce73d63562561d2b92"
integrity sha512-6ckxMjBBD8URvjB6J3NcnuAn5Pkl7t3TizAg+xdlzzQGSPSmBcXf8KoIH0ua/i+tio+ZRUHEXp0HEmvaR4kt0w== integrity sha512-ZD/NsIJYq/2RH+hY7lXmstfp/v9djGt9ah+xRQ3pcgR79qiKsG4pLl25AI7IcXxVO8dH9GiBE5rAknC0ePntlw==
"@types/content-type@^1.1.5": "@types/content-type@^1.1.5":
version "1.1.6" version "1.1.6"
@@ -4796,9 +4854,9 @@
form-data "^3.0.0" form-data "^3.0.0"
"@types/node@*": "@types/node@*":
version "20.6.2" version "20.7.0"
resolved "https://registry.yarnpkg.com/@types/node/-/node-20.6.2.tgz#a065925409f59657022e9063275cd0b9bd7e1b12" resolved "https://registry.yarnpkg.com/@types/node/-/node-20.7.0.tgz#c03de4572f114a940bc2ca909a33ddb2b925e470"
integrity sha512-Y+/1vGBHV/cYk6OI1Na/LHzwnlNCAfU3ZNGrc1LdRe/LAIbdDPTTv/HU3M7yXN448aTVDq3eKRm2cg7iKLb8gw== integrity sha512-zI22/pJW2wUZOVyguFaUL1HABdmSVxpXrzIqkjsHmyUjNhPoWM1CKfvVuXfetHhIok4RY573cqS0mZ1SJEnoTg==
"@types/node@^14.0.10 || ^16.0.0", "@types/node@^14.14.20 || ^16.0.0": "@types/node@^14.0.10 || ^16.0.0", "@types/node@^14.14.20 || ^16.0.0":
version "16.18.46" version "16.18.46"
@@ -4884,9 +4942,9 @@
csstype "^3.0.2" csstype "^3.0.2"
"@types/request@^2.48.8": "@types/request@^2.48.8":
version "2.48.8" version "2.48.9"
resolved "https://registry.yarnpkg.com/@types/request/-/request-2.48.8.tgz#0b90fde3b655ab50976cb8c5ac00faca22f5a82c" resolved "https://registry.yarnpkg.com/@types/request/-/request-2.48.9.tgz#43e123e93b10bd740a298e25430de6fab7e726c2"
integrity sha512-whjk1EDJPcAR2kYHRbFl/lKeeKYTi05A15K9bnLInCVroNDCtXce57xKdI0/rQaA3K+6q0eFyUBPmqfSndUZdQ== integrity sha512-4mi2hYsvPAhe8RXjk5DKB09sAUzbK68T2XjORehHdWyxFoX2zUnfi1VQ5wU4Md28H/5+uB4DkxY9BS4B87N/0A==
dependencies: dependencies:
"@types/caseless" "*" "@types/caseless" "*"
"@types/node" "*" "@types/node" "*"
@@ -5108,9 +5166,9 @@
svg2vectordrawable "^2.9.1" svg2vectordrawable "^2.9.1"
"@vector-im/compound-web@^0.4.0": "@vector-im/compound-web@^0.4.0":
version "0.4.4" version "0.4.5"
resolved "https://registry.yarnpkg.com/@vector-im/compound-web/-/compound-web-0.4.4.tgz#b7374336f51ad57c40bef67e06b733aca5ef8a48" resolved "https://registry.yarnpkg.com/@vector-im/compound-web/-/compound-web-0.4.5.tgz#6e0e066fc3a51d6daf17251d9590647b51fe7434"
integrity sha512-Ox/5PgwXSue/1fnnxMogl83iW18dnIMIh/JTnogFHn6zCkyz4Zl2pTKO32FiPzID5kdd0Zf7Li5fMdY1ekS3sA== integrity sha512-XkuBqJlj4Brsj+IfwkXtlGhyFGXvc6VoxFO1wDipM9d48SrNUGtK8IOQVZVeBYtML6XPET5lmp9ORnSpzWI3Ig==
dependencies: dependencies:
"@radix-ui/react-form" "^0.0.3" "@radix-ui/react-form" "^0.0.3"
"@radix-ui/react-tooltip" "^1.0.6" "@radix-ui/react-tooltip" "^1.0.6"
@@ -12963,9 +13021,9 @@ postcss@^8.4.27:
source-map-js "^1.0.2" source-map-js "^1.0.2"
posthog-js@^1.29.0: posthog-js@^1.29.0:
version "1.81.1" version "1.81.2"
resolved "https://registry.yarnpkg.com/posthog-js/-/posthog-js-1.81.1.tgz#43f454bf57d0ff649c990e28660bb9a0a292267e" resolved "https://registry.yarnpkg.com/posthog-js/-/posthog-js-1.81.2.tgz#0065b213c2d1ba1f9c167dc881e16656f5c70c07"
integrity sha512-pQfG9ZGVn3R7Uh1cC/S02trZ6u4TOLs1NhZG3WiNrqMKDA8MJQjZ/PqdkLO0/BeozRBfIbON6pw3xfOIneIclg== integrity sha512-3QLdn7koy7n+nj23HAr/KbVYwOmQcCn0K/5zlaWazef8t4s5L8JgJSMkw96pDRuAYfYcUCr9yWLQDpDakPiIHQ==
dependencies: dependencies:
fflate "^0.4.1" fflate "^0.4.1"
@@ -15055,11 +15113,6 @@ tsconfig-paths@^3.14.2:
minimist "^1.2.6" minimist "^1.2.6"
strip-bom "^3.0.0" strip-bom "^3.0.0"
tslib@^1.9.3:
version "1.14.1"
resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00"
integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==
tslib@^2.0.0, tslib@^2.0.1, tslib@^2.0.3, tslib@^2.1.0, tslib@^2.3.0, tslib@^2.4.0, "tslib@^2.4.1 || ^1.9.3": tslib@^2.0.0, tslib@^2.0.1, tslib@^2.0.3, tslib@^2.1.0, tslib@^2.3.0, tslib@^2.4.0, "tslib@^2.4.1 || ^1.9.3":
version "2.6.2" version "2.6.2"
resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.6.2.tgz#703ac29425e7b37cd6fd456e92404d46d1f3e4ae" resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.6.2.tgz#703ac29425e7b37cd6fd456e92404d46d1f3e4ae"
@@ -15664,10 +15717,10 @@ vite-plugin-mdx@^3.5.6:
resolve "^1.20.0" resolve "^1.20.0"
unified "^9.2.1" unified "^9.2.1"
vite-plugin-svgr@^3.2.0: vite-plugin-svgr@^4.0.0:
version "3.3.0" version "4.0.0"
resolved "https://registry.yarnpkg.com/vite-plugin-svgr/-/vite-plugin-svgr-3.3.0.tgz#024f083c0f0831497d8507b82e49a8ee2b29701a" resolved "https://registry.yarnpkg.com/vite-plugin-svgr/-/vite-plugin-svgr-4.0.0.tgz#2fb2537bde793602784c126f04210eaf130304bd"
integrity sha512-vWZMCcGNdPqgziYFKQ3Y95XP0d0YGp28+MM3Dp9cTa/px5CKcHHrIoPl2Jw81rgVm6/ZUNONzjXbZQZ7Kw66og== integrity sha512-ingW8FEJ4vz9mQumnMDhNysE+YleiaThYmgflhUIVI4iIjVsVA1SswYIKprWVmyFsiIk1DqcwUeTFCnUJA3Vvg==
dependencies: dependencies:
"@rollup/pluginutils" "^5.0.4" "@rollup/pluginutils" "^5.0.4"
"@svgr/core" "^8.1.0" "@svgr/core" "^8.1.0"