Add warning if incompatible versionsd are being used
This will probably be overly sensitive until we start timing out member events (ie. https://github.com/matrix-org/matrix-js-sdk/pull/2446 lands) because lots of calls might have old member events from people who've joined previously.
This commit is contained in:
parent
fdcedb5592
commit
1f5ac411f6
10 changed files with 141 additions and 3 deletions
|
@ -1,5 +1,5 @@
|
|||
import classNames from "classnames";
|
||||
import React, { useRef } from "react";
|
||||
import React, { useCallback, useRef } from "react";
|
||||
import { Link } from "react-router-dom";
|
||||
import styles from "./Header.module.css";
|
||||
import { ReactComponent as Logo } from "./icons/Logo.svg";
|
||||
|
@ -8,6 +8,9 @@ import { ReactComponent as ArrowLeftIcon } from "./icons/ArrowLeft.svg";
|
|||
import { useButton } from "@react-aria/button";
|
||||
import { Subtitle } from "./typography/Typography";
|
||||
import { Avatar } from "./Avatar";
|
||||
import { IncompatibleversionModal } from "./IncompatibleversionModal";
|
||||
import { useModalTriggerState } from "./Modal";
|
||||
import { Button } from "./button";
|
||||
|
||||
export function Header({ children, className, ...rest }) {
|
||||
return (
|
||||
|
@ -84,3 +87,25 @@ export function RoomSetupHeaderInfo({ roomName, avatarUrl, ...rest }) {
|
|||
</button>
|
||||
);
|
||||
}
|
||||
|
||||
export function VersionMismatchWarning({ users, room }) {
|
||||
const { modalState, modalProps } = useModalTriggerState();
|
||||
|
||||
const onDetailsClick = useCallback(() => {
|
||||
modalState.open();
|
||||
}, [modalState]);
|
||||
|
||||
if (users.size === 0) return null;
|
||||
|
||||
return (
|
||||
<span className={styles.versionMismatchWarning}>
|
||||
Incomaptible versions!
|
||||
<Button variant="link" onClick={onDetailsClick}>
|
||||
Details
|
||||
</Button>
|
||||
{modalState.isOpen && (
|
||||
<IncompatibleversionModal userIds={users} room={room} {...modalProps} />
|
||||
)}
|
||||
</span>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -104,6 +104,24 @@
|
|||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.versionMismatchWarning {
|
||||
padding-left: 15px;
|
||||
}
|
||||
|
||||
.versionMismatchWarning::before {
|
||||
content: "";
|
||||
display: inline-block;
|
||||
position: relative;
|
||||
top: 2px;
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
mask-image: url("./icons/AlertTriangleFilled.svg");
|
||||
mask-repeat: no-repeat;
|
||||
mask-size: contain;
|
||||
background-color: var(--warning);
|
||||
padding-right: 3px;
|
||||
}
|
||||
|
||||
@media (min-width: 800px) {
|
||||
.headerLogo,
|
||||
.roomAvatar,
|
||||
|
|
48
src/IncompatibleVersionModal.tsx
Normal file
48
src/IncompatibleVersionModal.tsx
Normal file
|
@ -0,0 +1,48 @@
|
|||
/*
|
||||
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 { Room } from "matrix-js-sdk";
|
||||
import React from "react";
|
||||
|
||||
import { Modal, ModalContent } from "./Modal";
|
||||
import { Body } from "./typography/Typography";
|
||||
|
||||
interface Props {
|
||||
userIds: Set<string>;
|
||||
room: Room;
|
||||
}
|
||||
|
||||
export const IncompatibleversionModal: React.FC<Props> = ({
|
||||
userIds,
|
||||
room,
|
||||
...rest
|
||||
}) => {
|
||||
const userLis = Array.from(userIds).map((u) => (
|
||||
<li>{room.getMember(u).name}</li>
|
||||
));
|
||||
|
||||
return (
|
||||
<Modal title="Incompatible Versions" isDismissable {...rest}>
|
||||
<ModalContent>
|
||||
<Body>
|
||||
Other users are trying to join this call from incompatible versions.
|
||||
These users should ensure that they have refreshed their browsers:
|
||||
<ul>{userLis}</ul>
|
||||
</Body>
|
||||
</ModalContent>
|
||||
</Modal>
|
||||
);
|
||||
};
|
|
@ -41,6 +41,7 @@ export const variantToClassName = {
|
|||
iconCopy: [styles.iconCopyButton],
|
||||
secondaryHangup: [styles.secondaryHangup],
|
||||
dropdown: [styles.dropdownButton],
|
||||
link: [styles.linkButton],
|
||||
};
|
||||
|
||||
export const sizeToClassName = {
|
||||
|
|
|
@ -207,3 +207,10 @@ limitations under the License.
|
|||
.lg {
|
||||
height: 40px;
|
||||
}
|
||||
|
||||
.linkButton {
|
||||
background-color: transparent;
|
||||
border: none;
|
||||
text-decoration: underline;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
|
4
src/icons/AlertTriangleFilled.svg
Normal file
4
src/icons/AlertTriangleFilled.svg
Normal file
|
@ -0,0 +1,4 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg fill="none" version="1.1" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="m12 2.8965c-0.6991 0-1.3483 0.36517-1.7109 0.96289l-8.4687 14.141c-0.35536 0.6154-0.35777 1.3729-0.0058594 1.9902 0.3519 0.6174 1.0043 1.002 1.7148 1.0098h16.941c0.7106-0.0078 1.3629-0.39237 1.7148-1.0098 0.3519-0.6173 0.34954-1.3748-0.005859-1.9902l-8.4688-14.141c-0.3625-0.59772-1.0118-0.96289-1.7109-0.96289zm0 5.6035a0.5 0.5 0 0 1 0.5 0.5v4a0.5 0.5 0 0 1-0.5 0.5 0.5 0.5 0 0 1-0.5-0.5v-4a0.5 0.5 0 0 1 0.5-0.5zm0 7.5a1 1 0 0 1 1 1 1 1 0 0 1-1 1 1 1 0 0 1-1-1 1 1 0 0 1 1-1z" fill="#000"/>
|
||||
</svg>
|
After Width: | Height: | Size: 635 B |
|
@ -29,6 +29,7 @@ limitations under the License.
|
|||
--accent-20: #0dbd8b33;
|
||||
--alert: #ff5b55;
|
||||
--alert-20: #ff5b5533;
|
||||
--warning: #e8bf37;
|
||||
--links: #0086e6;
|
||||
--primary-content: #ffffff;
|
||||
--secondary-content: #a9b2bc;
|
||||
|
|
|
@ -53,6 +53,7 @@ export function GroupCallView({
|
|||
screenshareFeeds,
|
||||
hasLocalParticipant,
|
||||
participants,
|
||||
unencryptedEventsFromUsers,
|
||||
} = useGroupCall(groupCall);
|
||||
|
||||
const avatarUrl = useRoomAvatar(groupCall.room);
|
||||
|
@ -112,6 +113,7 @@ export function GroupCallView({
|
|||
localScreenshareFeed={localScreenshareFeed}
|
||||
screenshareFeeds={screenshareFeeds}
|
||||
roomId={roomId}
|
||||
unencryptedEventsFromUsers={unencryptedEventsFromUsers}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -22,7 +22,13 @@ import {
|
|||
VideoButton,
|
||||
ScreenshareButton,
|
||||
} from "../button";
|
||||
import { Header, LeftNav, RightNav, RoomHeaderInfo } from "../Header";
|
||||
import {
|
||||
Header,
|
||||
LeftNav,
|
||||
RightNav,
|
||||
RoomHeaderInfo,
|
||||
VersionMismatchWarning,
|
||||
} from "../Header";
|
||||
import { VideoGrid, useVideoGridLayout } from "../video-grid/VideoGrid";
|
||||
import { VideoTileContainer } from "../video-grid/VideoTileContainer";
|
||||
import { GroupCallInspector } from "./GroupCallInspector";
|
||||
|
@ -59,6 +65,7 @@ export function InCallView({
|
|||
isScreensharing,
|
||||
screenshareFeeds,
|
||||
roomId,
|
||||
unencryptedEventsFromUsers,
|
||||
}) {
|
||||
usePreventScroll();
|
||||
const [layout, setLayout] = useVideoGridLayout(screenshareFeeds.length > 0);
|
||||
|
@ -135,6 +142,10 @@ export function InCallView({
|
|||
<Header>
|
||||
<LeftNav>
|
||||
<RoomHeaderInfo roomName={roomName} avatarUrl={avatarUrl} />
|
||||
<VersionMismatchWarning
|
||||
users={unencryptedEventsFromUsers}
|
||||
room={groupCall.room}
|
||||
/>
|
||||
</LeftNav>
|
||||
<RightNav>
|
||||
<GridLayoutMenu layout={layout} setLayout={setLayout} />
|
||||
|
|
|
@ -14,11 +14,14 @@ See the License for the specific language governing permissions and
|
|||
limitations under the License.
|
||||
*/
|
||||
|
||||
import { useCallback, useEffect, useState } from "react";
|
||||
import { useCallback, useEffect, useReducer, useState } from "react";
|
||||
import {
|
||||
GroupCallEvent,
|
||||
GroupCallState,
|
||||
GroupCall,
|
||||
GroupCallErrorCode,
|
||||
GroupCallUnknownDeviceError,
|
||||
GroupCallError,
|
||||
} from "matrix-js-sdk/src/webrtc/groupCall";
|
||||
import { MatrixCall } from "matrix-js-sdk/src/webrtc/call";
|
||||
import { CallFeed } from "matrix-js-sdk/src/webrtc/callFeed";
|
||||
|
@ -48,6 +51,7 @@ export interface UseGroupCallType {
|
|||
localDesktopCapturerSourceId: string;
|
||||
participants: RoomMember[];
|
||||
hasLocalParticipant: boolean;
|
||||
unencryptedEventsFromUsers: Set<string>;
|
||||
}
|
||||
|
||||
interface State {
|
||||
|
@ -106,6 +110,13 @@ export function useGroupCall(groupCall: GroupCall): UseGroupCallType {
|
|||
hasLocalParticipant: false,
|
||||
});
|
||||
|
||||
const [unencryptedEventsFromUsers, addUnencryptedEventUser] = useReducer(
|
||||
(state: Set<string>, newVal: string) => {
|
||||
return new Set(state).add(newVal);
|
||||
},
|
||||
new Set<string>()
|
||||
);
|
||||
|
||||
const updateState = (state: Partial<State>) =>
|
||||
setState((prevState) => ({ ...prevState, ...state }));
|
||||
|
||||
|
@ -180,6 +191,13 @@ export function useGroupCall(groupCall: GroupCall): UseGroupCallType {
|
|||
});
|
||||
}
|
||||
|
||||
function onError(e: GroupCallError): void {
|
||||
if (e.code === GroupCallErrorCode.UnknownDevice) {
|
||||
const unknownDeviceError = e as GroupCallUnknownDeviceError;
|
||||
addUnencryptedEventUser(unknownDeviceError.userId);
|
||||
}
|
||||
}
|
||||
|
||||
groupCall.on(GroupCallEvent.GroupCallStateChanged, onGroupCallStateChanged);
|
||||
groupCall.on(GroupCallEvent.UserMediaFeedsChanged, onUserMediaFeedsChanged);
|
||||
groupCall.on(
|
||||
|
@ -194,6 +212,7 @@ export function useGroupCall(groupCall: GroupCall): UseGroupCallType {
|
|||
);
|
||||
groupCall.on(GroupCallEvent.CallsChanged, onCallsChanged);
|
||||
groupCall.on(GroupCallEvent.ParticipantsChanged, onParticipantsChanged);
|
||||
groupCall.on(GroupCallEvent.Error, onError);
|
||||
|
||||
updateState({
|
||||
error: null,
|
||||
|
@ -242,6 +261,7 @@ export function useGroupCall(groupCall: GroupCall): UseGroupCallType {
|
|||
GroupCallEvent.ParticipantsChanged,
|
||||
onParticipantsChanged
|
||||
);
|
||||
groupCall.removeListener(GroupCallEvent.Error, onError);
|
||||
groupCall.leave();
|
||||
};
|
||||
}, [groupCall]);
|
||||
|
@ -319,5 +339,6 @@ export function useGroupCall(groupCall: GroupCall): UseGroupCallType {
|
|||
localDesktopCapturerSourceId,
|
||||
participants,
|
||||
hasLocalParticipant,
|
||||
unencryptedEventsFromUsers,
|
||||
};
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue