Merge pull request #1621 from vector-im/renovate/prettier-3.x
Update dependency prettier to v3
This commit is contained in:
@@ -14,7 +14,7 @@ module.exports = {
|
||||
Array.isArray(item) &&
|
||||
item.length > 0 &&
|
||||
item[0].name === "vite-plugin-mdx"
|
||||
)
|
||||
),
|
||||
);
|
||||
config.plugins.push(svgrPlugin());
|
||||
config.resolve = config.resolve || {};
|
||||
|
||||
@@ -117,7 +117,7 @@
|
||||
"jest": "^29.2.2",
|
||||
"jest-environment-jsdom": "^29.3.1",
|
||||
"jest-mock": "^29.5.0",
|
||||
"prettier": "^2.6.2",
|
||||
"prettier": "^3.0.0",
|
||||
"sass": "^1.42.1",
|
||||
"typescript": "^5.1.6",
|
||||
"typescript-eslint-language-service": "^5.0.5",
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<!DOCTYPE html>
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
|
||||
@@ -58,7 +58,7 @@ export const Avatar: FC<Props> = ({
|
||||
Object.values(Size).includes(size as Size)
|
||||
? sizes.get(size as Size)
|
||||
: (size as number),
|
||||
[size]
|
||||
[size],
|
||||
);
|
||||
|
||||
const resolvedSrc = useMemo(() => {
|
||||
|
||||
@@ -190,7 +190,7 @@ export const ClientProvider: FC<Props> = ({ children }) => {
|
||||
user: session.user_id,
|
||||
password: session.tempPassword,
|
||||
},
|
||||
password
|
||||
password,
|
||||
);
|
||||
|
||||
saveSession({ ...session, passwordlessUser: false });
|
||||
@@ -200,7 +200,7 @@ export const ClientProvider: FC<Props> = ({ children }) => {
|
||||
passwordlessUser: false,
|
||||
});
|
||||
},
|
||||
[initClientState?.client]
|
||||
[initClientState?.client],
|
||||
);
|
||||
|
||||
const setClient = useCallback(
|
||||
@@ -222,7 +222,7 @@ export const ClientProvider: FC<Props> = ({ children }) => {
|
||||
setInitClientState(null);
|
||||
}
|
||||
},
|
||||
[initClientState?.client]
|
||||
[initClientState?.client],
|
||||
);
|
||||
|
||||
const logout = useCallback(async () => {
|
||||
@@ -250,7 +250,7 @@ export const ClientProvider: FC<Props> = ({ children }) => {
|
||||
}, []);
|
||||
|
||||
const [alreadyOpenedErr, setAlreadyOpenedErr] = useState<Error | undefined>(
|
||||
undefined
|
||||
undefined,
|
||||
);
|
||||
useEventTarget(
|
||||
loadChannel,
|
||||
@@ -258,9 +258,9 @@ export const ClientProvider: FC<Props> = ({ children }) => {
|
||||
useCallback(() => {
|
||||
initClientState?.client.stopClient();
|
||||
setAlreadyOpenedErr(
|
||||
translatedError("This application has been opened in another tab.", t)
|
||||
translatedError("This application has been opened in another tab.", t),
|
||||
);
|
||||
}, [initClientState?.client, setAlreadyOpenedErr, t])
|
||||
}, [initClientState?.client, setAlreadyOpenedErr, t]),
|
||||
);
|
||||
|
||||
const [isDisconnected, setIsDisconnected] = useState(false);
|
||||
@@ -301,7 +301,7 @@ export const ClientProvider: FC<Props> = ({ children }) => {
|
||||
(state: SyncState, _old: SyncState | null, data?: ISyncStateData) => {
|
||||
setIsDisconnected(clientIsDisconnected(state, data));
|
||||
},
|
||||
[]
|
||||
[],
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
@@ -387,7 +387,7 @@ async function loadClient(): Promise<InitResult | null> {
|
||||
logger.warn(
|
||||
"The previous session was lost, and we couldn't log it out, " +
|
||||
err +
|
||||
"either"
|
||||
"either",
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -423,6 +423,6 @@ const loadSession = (): Session | undefined => {
|
||||
|
||||
const clientIsDisconnected = (
|
||||
syncState: SyncState,
|
||||
syncData?: ISyncStateData
|
||||
syncData?: ISyncStateData,
|
||||
): boolean =>
|
||||
syncState === "ERROR" && syncData?.error?.name === "ConnectionError";
|
||||
|
||||
@@ -48,5 +48,5 @@ export const Glass = forwardRef<HTMLDivElement, Props>(
|
||||
>
|
||||
{Children.only(children)}
|
||||
</div>
|
||||
)
|
||||
),
|
||||
);
|
||||
|
||||
@@ -58,7 +58,7 @@ export const LeftNav: FC<LeftNavProps> = ({
|
||||
styles.nav,
|
||||
styles.leftNav,
|
||||
{ [styles.hideMobile]: hideMobile },
|
||||
className
|
||||
className,
|
||||
)}
|
||||
{...rest}
|
||||
>
|
||||
@@ -85,7 +85,7 @@ export const RightNav: FC<RightNavProps> = ({
|
||||
styles.nav,
|
||||
styles.rightNav,
|
||||
{ [styles.hideMobile]: hideMobile },
|
||||
className
|
||||
className,
|
||||
)}
|
||||
{...rest}
|
||||
>
|
||||
|
||||
@@ -63,7 +63,7 @@ export class LazyEventEmitter extends EventEmitter {
|
||||
public addListener(
|
||||
type: string | symbol,
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
listener: (...args: any[]) => void
|
||||
listener: (...args: any[]) => void,
|
||||
): this {
|
||||
return this.on(type, listener);
|
||||
}
|
||||
|
||||
@@ -77,7 +77,7 @@ function Option<T>({ item, state, className }: OptionProps<T>): ReactNode {
|
||||
const { optionProps, isSelected, isFocused, isDisabled } = useOption(
|
||||
{ key: item.key },
|
||||
state,
|
||||
ref
|
||||
ref,
|
||||
);
|
||||
|
||||
// Hack: remove the onPointerUp event handler and re-wire it to
|
||||
@@ -97,7 +97,7 @@ function Option<T>({ item, state, className }: OptionProps<T>): ReactNode {
|
||||
// @ts-ignore
|
||||
origPointerUp(e as unknown as PointerEvent<HTMLElement>);
|
||||
},
|
||||
[origPointerUp]
|
||||
[origPointerUp],
|
||||
);
|
||||
|
||||
return (
|
||||
|
||||
@@ -82,7 +82,7 @@ function MenuItem<T>({
|
||||
onClose,
|
||||
},
|
||||
state,
|
||||
ref
|
||||
ref,
|
||||
);
|
||||
|
||||
const [isFocused, setFocused] = useState(false);
|
||||
|
||||
@@ -75,7 +75,7 @@ export const Modal: FC<Props> = ({
|
||||
(open: boolean) => {
|
||||
if (!open) onDismiss?.();
|
||||
},
|
||||
[onDismiss]
|
||||
[onDismiss],
|
||||
);
|
||||
|
||||
if (touchscreen) {
|
||||
@@ -92,7 +92,7 @@ export const Modal: FC<Props> = ({
|
||||
className,
|
||||
overlayStyles.overlay,
|
||||
styles.modal,
|
||||
styles.drawer
|
||||
styles.drawer,
|
||||
)}
|
||||
{...rest}
|
||||
>
|
||||
@@ -124,7 +124,7 @@ export const Modal: FC<Props> = ({
|
||||
overlayStyles.overlay,
|
||||
overlayStyles.animate,
|
||||
styles.modal,
|
||||
styles.dialog
|
||||
styles.dialog,
|
||||
)}
|
||||
>
|
||||
<div className={styles.content}>
|
||||
|
||||
@@ -70,7 +70,7 @@ export const Toast: FC<Props> = ({
|
||||
(open: boolean) => {
|
||||
if (!open) onDismiss();
|
||||
},
|
||||
[onDismiss]
|
||||
[onDismiss],
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
@@ -91,7 +91,7 @@ export const Toast: FC<Props> = ({
|
||||
className={classNames(
|
||||
overlayStyles.overlay,
|
||||
overlayStyles.animate,
|
||||
styles.toast
|
||||
styles.toast,
|
||||
)}
|
||||
>
|
||||
<DialogTitle asChild>
|
||||
|
||||
@@ -43,7 +43,7 @@ interface TooltipProps {
|
||||
const Tooltip = forwardRef<HTMLDivElement, TooltipProps>(
|
||||
(
|
||||
{ state, className, children, ...rest }: TooltipProps,
|
||||
ref: ForwardedRef<HTMLDivElement>
|
||||
ref: ForwardedRef<HTMLDivElement>,
|
||||
) => {
|
||||
const { tooltipProps } = useTooltip(rest, state);
|
||||
|
||||
@@ -56,7 +56,7 @@ const Tooltip = forwardRef<HTMLDivElement, TooltipProps>(
|
||||
{children}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
interface TooltipTriggerProps {
|
||||
@@ -69,7 +69,7 @@ interface TooltipTriggerProps {
|
||||
export const TooltipTrigger = forwardRef<HTMLElement, TooltipTriggerProps>(
|
||||
(
|
||||
{ children, placement, tooltip, ...rest }: TooltipTriggerProps,
|
||||
ref: ForwardedRef<HTMLElement>
|
||||
ref: ForwardedRef<HTMLElement>,
|
||||
) => {
|
||||
const tooltipTriggerProps = { delay: 250, ...rest };
|
||||
const tooltipState = useTooltipTriggerState(tooltipTriggerProps);
|
||||
@@ -78,7 +78,7 @@ export const TooltipTrigger = forwardRef<HTMLElement, TooltipTriggerProps>(
|
||||
const { triggerProps, tooltipProps } = useTooltipTrigger(
|
||||
tooltipTriggerProps,
|
||||
tooltipState,
|
||||
triggerRef
|
||||
triggerRef,
|
||||
);
|
||||
|
||||
const { overlayProps } = useOverlayPosition({
|
||||
@@ -94,7 +94,7 @@ export const TooltipTrigger = forwardRef<HTMLElement, TooltipTriggerProps>(
|
||||
<children.type
|
||||
{...mergeProps<typeof children.props | typeof rest>(
|
||||
children.props,
|
||||
rest
|
||||
rest,
|
||||
)}
|
||||
/>
|
||||
{tooltipState.isOpen && (
|
||||
@@ -110,5 +110,5 @@ export const TooltipTrigger = forwardRef<HTMLElement, TooltipTriggerProps>(
|
||||
)}
|
||||
</FocusableProvider>
|
||||
);
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
@@ -39,5 +39,5 @@ class TranslatedErrorImpl extends TranslatedError {}
|
||||
// function instead
|
||||
export const translatedError = (
|
||||
messageKey: string,
|
||||
t: typeof i18n.t
|
||||
t: typeof i18n.t,
|
||||
): TranslatedError => new TranslatedErrorImpl(messageKey, t);
|
||||
|
||||
@@ -119,17 +119,17 @@ interface UrlParams {
|
||||
// file.
|
||||
export function editFragmentQuery(
|
||||
hash: string,
|
||||
edit: (params: URLSearchParams) => URLSearchParams
|
||||
edit: (params: URLSearchParams) => URLSearchParams,
|
||||
): string {
|
||||
const fragmentQueryStart = hash.indexOf("?");
|
||||
const fragmentParams = edit(
|
||||
new URLSearchParams(
|
||||
fragmentQueryStart === -1 ? "" : hash.substring(fragmentQueryStart)
|
||||
)
|
||||
fragmentQueryStart === -1 ? "" : hash.substring(fragmentQueryStart),
|
||||
),
|
||||
);
|
||||
return `${hash.substring(
|
||||
0,
|
||||
fragmentQueryStart
|
||||
fragmentQueryStart,
|
||||
)}?${fragmentParams.toString()}`;
|
||||
}
|
||||
|
||||
@@ -142,7 +142,7 @@ class ParamParser {
|
||||
|
||||
const fragmentQueryStart = hash.indexOf("?");
|
||||
this.fragmentParams = new URLSearchParams(
|
||||
fragmentQueryStart === -1 ? "" : hash.substring(fragmentQueryStart)
|
||||
fragmentQueryStart === -1 ? "" : hash.substring(fragmentQueryStart),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -174,7 +174,7 @@ class ParamParser {
|
||||
*/
|
||||
export const getUrlParams = (
|
||||
search = window.location.search,
|
||||
hash = window.location.hash
|
||||
hash = window.location.hash,
|
||||
): UrlParams => {
|
||||
const parser = new ParamParser(search, hash);
|
||||
|
||||
@@ -221,7 +221,7 @@ export const useUrlParams = (): UrlParams => {
|
||||
export function getRoomIdentifierFromUrl(
|
||||
pathname: string,
|
||||
search: string,
|
||||
hash: string
|
||||
hash: string,
|
||||
): RoomIdentifier {
|
||||
let roomAlias: string | null = null;
|
||||
pathname = pathname.substring(1); // Strip the "/"
|
||||
@@ -281,6 +281,6 @@ export const useRoomIdentifier = (): RoomIdentifier => {
|
||||
const { pathname, search, hash } = useLocation();
|
||||
return useMemo(
|
||||
() => getRoomIdentifierFromUrl(pathname, search, hash),
|
||||
[pathname, search, hash]
|
||||
[pathname, search, hash],
|
||||
);
|
||||
};
|
||||
|
||||
@@ -34,7 +34,7 @@ export const UserMenuContainer: FC<Props> = ({ preventNavigation = false }) => {
|
||||
const [settingsModalOpen, setSettingsModalOpen] = useState(false);
|
||||
const onDismissSettingsModal = useCallback(
|
||||
() => setSettingsModalOpen(false),
|
||||
[setSettingsModalOpen]
|
||||
[setSettingsModalOpen],
|
||||
);
|
||||
|
||||
const [defaultSettingsTab, setDefaultSettingsTab] = useState<string>();
|
||||
@@ -58,7 +58,7 @@ export const UserMenuContainer: FC<Props> = ({ preventNavigation = false }) => {
|
||||
break;
|
||||
}
|
||||
},
|
||||
[history, location, logout, setSettingsModalOpen]
|
||||
[history, location, logout, setSettingsModalOpen],
|
||||
);
|
||||
|
||||
const userName = client?.getUserIdLocalpart() ?? "";
|
||||
|
||||
@@ -146,7 +146,7 @@ export class PosthogAnalytics {
|
||||
this.enabled = true;
|
||||
} else {
|
||||
logger.info(
|
||||
"Posthog is not enabled because there is no api key or no host given in the config"
|
||||
"Posthog is not enabled because there is no api key or no host given in the config",
|
||||
);
|
||||
this.enabled = false;
|
||||
}
|
||||
@@ -157,7 +157,7 @@ export class PosthogAnalytics {
|
||||
|
||||
private sanitizeProperties = (
|
||||
properties: Properties,
|
||||
_eventName: string
|
||||
_eventName: string,
|
||||
): Properties => {
|
||||
// Callback from posthog to sanitize properties before sending them to the server.
|
||||
// Here we sanitize posthog's built in properties which leak PII e.g. url reporting.
|
||||
@@ -201,7 +201,7 @@ export class PosthogAnalytics {
|
||||
private capture(
|
||||
eventName: string,
|
||||
properties: Properties,
|
||||
options?: CaptureOptions
|
||||
options?: CaptureOptions,
|
||||
): void {
|
||||
if (!this.enabled) {
|
||||
return;
|
||||
@@ -237,7 +237,7 @@ export class PosthogAnalytics {
|
||||
}
|
||||
|
||||
private async identifyUser(
|
||||
analyticsIdGenerator: () => string
|
||||
analyticsIdGenerator: () => string,
|
||||
): Promise<void> {
|
||||
if (this.anonymity == Anonymity.Pseudonymous && this.enabled) {
|
||||
// Check the user's account_data for an analytics ID to use. Storing the ID in account_data allows
|
||||
@@ -260,14 +260,14 @@ export class PosthogAnalytics {
|
||||
// The above could fail due to network requests, but not essential to starting the application,
|
||||
// so swallow it.
|
||||
logger.log(
|
||||
"Unable to identify user for tracking" + (e as Error)?.toString()
|
||||
"Unable to identify user for tracking" + (e as Error)?.toString(),
|
||||
);
|
||||
}
|
||||
if (analyticsID) {
|
||||
this.posthog.identify(analyticsID);
|
||||
} else {
|
||||
logger.info(
|
||||
"No analyticsID is availble. Should not try to setup posthog"
|
||||
"No analyticsID is availble. Should not try to setup posthog",
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -280,7 +280,7 @@ export class PosthogAnalytics {
|
||||
accountAnalyticsId = getUrlParams().analyticsID;
|
||||
} else {
|
||||
const accountData = await client.getAccountDataFromServer(
|
||||
PosthogAnalytics.ANALYTICS_EVENT_TYPE
|
||||
PosthogAnalytics.ANALYTICS_EVENT_TYPE,
|
||||
);
|
||||
accountAnalyticsId = accountData?.id;
|
||||
}
|
||||
@@ -294,13 +294,13 @@ export class PosthogAnalytics {
|
||||
}
|
||||
|
||||
private async hashedEcAnalyticsId(
|
||||
accountAnalyticsId: string
|
||||
accountAnalyticsId: string,
|
||||
): Promise<string> {
|
||||
const client: MatrixClient = window.matrixclient;
|
||||
const posthogIdMaterial = "ec" + accountAnalyticsId + client.getUserId();
|
||||
const bufferForPosthogId = await crypto.subtle.digest(
|
||||
"sha-256",
|
||||
Buffer.from(posthogIdMaterial, "utf-8")
|
||||
Buffer.from(posthogIdMaterial, "utf-8"),
|
||||
);
|
||||
const view = new Int32Array(bufferForPosthogId);
|
||||
return Array.from(view)
|
||||
@@ -314,11 +314,11 @@ export class PosthogAnalytics {
|
||||
|
||||
// the analytics ID only needs to be set in the standalone version.
|
||||
const accountData = await client.getAccountDataFromServer(
|
||||
PosthogAnalytics.ANALYTICS_EVENT_TYPE
|
||||
PosthogAnalytics.ANALYTICS_EVENT_TYPE,
|
||||
);
|
||||
await client.setAccountData(
|
||||
PosthogAnalytics.ANALYTICS_EVENT_TYPE,
|
||||
Object.assign({ id: analyticsID }, accountData)
|
||||
Object.assign({ id: analyticsID }, accountData),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -360,7 +360,7 @@ export class PosthogAnalytics {
|
||||
}
|
||||
|
||||
private async updateAnonymityAndIdentifyUser(
|
||||
pseudonymousOptIn: boolean
|
||||
pseudonymousOptIn: boolean,
|
||||
): Promise<void> {
|
||||
// Update this.anonymity based on the user's analytics opt-in settings
|
||||
const anonymity = pseudonymousOptIn
|
||||
@@ -376,11 +376,11 @@ export class PosthogAnalytics {
|
||||
this.setRegistrationType(
|
||||
window.matrixclient.isGuest() || window.passwordlessUser
|
||||
? RegistrationType.Guest
|
||||
: RegistrationType.Registered
|
||||
: RegistrationType.Registered,
|
||||
);
|
||||
// store the promise to await posthog-tracking-events until the identification is done.
|
||||
this.identificationPromise = this.identifyUser(
|
||||
PosthogAnalytics.getRandomAnalyticsId
|
||||
PosthogAnalytics.getRandomAnalyticsId,
|
||||
);
|
||||
await this.identificationPromise;
|
||||
if (this.userRegisteredInThisSession()) {
|
||||
@@ -395,7 +395,7 @@ export class PosthogAnalytics {
|
||||
|
||||
public async trackEvent<E extends IPosthogEvent>(
|
||||
{ eventName, ...properties }: E,
|
||||
options?: CaptureOptions
|
||||
options?: CaptureOptions,
|
||||
): Promise<void> {
|
||||
if (this.identificationPromise) {
|
||||
// only make calls to posthog after the identificaion is done
|
||||
|
||||
@@ -43,14 +43,14 @@ export class CallEndedTracker {
|
||||
public cacheParticipantCountChanged(count: number): void {
|
||||
this.cache.maxParticipantsCount = Math.max(
|
||||
count,
|
||||
this.cache.maxParticipantsCount
|
||||
this.cache.maxParticipantsCount,
|
||||
);
|
||||
}
|
||||
|
||||
public track(
|
||||
callId: string,
|
||||
callParticipantsNow: number,
|
||||
sendInstantly: boolean
|
||||
sendInstantly: boolean,
|
||||
): void {
|
||||
PosthogAnalytics.instance.trackEvent<CallEnded>(
|
||||
{
|
||||
@@ -60,7 +60,7 @@ export class CallEndedTracker {
|
||||
callParticipantsOnLeave: callParticipantsNow,
|
||||
callDuration: (Date.now() - this.cache.startTime.getTime()) / 1000,
|
||||
},
|
||||
{ send_instantly: sendInstantly }
|
||||
{ send_instantly: sendInstantly },
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -148,7 +148,7 @@ export class PosthogSpanProcessor implements SpanProcessor {
|
||||
ratioPeerConnectionToDevices: ratioPeerConnectionToDevices,
|
||||
},
|
||||
// Send instantly because the window might be closing
|
||||
{ send_instantly: true }
|
||||
{ send_instantly: true },
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,7 +23,7 @@ import {
|
||||
} from "@opentelemetry/sdk-trace-base";
|
||||
|
||||
const dumpAttributes = (
|
||||
attr: Attributes
|
||||
attr: Attributes,
|
||||
): {
|
||||
key: string;
|
||||
type:
|
||||
|
||||
@@ -22,7 +22,7 @@ limitations under the License.
|
||||
// Array.prototype.findLastIndex
|
||||
export function findLastIndex<T>(
|
||||
array: T[],
|
||||
predicate: (item: T, index: number) => boolean
|
||||
predicate: (item: T, index: number) => boolean,
|
||||
): number | null {
|
||||
for (let i = array.length - 1; i >= 0; i--) {
|
||||
if (predicate(array[i], i)) return i;
|
||||
@@ -36,9 +36,9 @@ export function findLastIndex<T>(
|
||||
*/
|
||||
export const count = <T>(
|
||||
array: T[],
|
||||
predicate: (item: T, index: number) => boolean
|
||||
predicate: (item: T, index: number) => boolean,
|
||||
): number =>
|
||||
array.reduce(
|
||||
(acc, item, index) => (predicate(item, index) ? acc + 1 : acc),
|
||||
0
|
||||
0,
|
||||
);
|
||||
|
||||
@@ -80,7 +80,7 @@ export const LoginPage: FC = () => {
|
||||
setLoading(false);
|
||||
});
|
||||
},
|
||||
[login, location, history, homeserver, setClient]
|
||||
[login, location, history, homeserver, setClient],
|
||||
);
|
||||
|
||||
return (
|
||||
|
||||
@@ -78,7 +78,7 @@ export const RegisterPage: FC = () => {
|
||||
password,
|
||||
userName,
|
||||
recaptchaResponse,
|
||||
passwordlessUser
|
||||
passwordlessUser,
|
||||
);
|
||||
|
||||
if (client && client?.groupCallEventHandler && passwordlessUser) {
|
||||
@@ -135,7 +135,7 @@ export const RegisterPage: FC = () => {
|
||||
execute,
|
||||
client,
|
||||
setClient,
|
||||
]
|
||||
],
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
|
||||
@@ -24,13 +24,13 @@ import { Session } from "../ClientContext";
|
||||
export function useInteractiveLogin(): (
|
||||
homeserver: string,
|
||||
username: string,
|
||||
password: string
|
||||
password: string,
|
||||
) => Promise<[MatrixClient, Session]> {
|
||||
return useCallback<
|
||||
(
|
||||
homeserver: string,
|
||||
username: string,
|
||||
password: string
|
||||
password: string,
|
||||
) => Promise<[MatrixClient, Session]>
|
||||
>(async (homeserver: string, username: string, password: string) => {
|
||||
const authClient = createClient({ baseUrl: homeserver });
|
||||
@@ -70,7 +70,7 @@ export function useInteractiveLogin(): (
|
||||
userId: user_id,
|
||||
deviceId: device_id,
|
||||
},
|
||||
false
|
||||
false,
|
||||
);
|
||||
/* eslint-enable camelcase */
|
||||
return [client, session];
|
||||
|
||||
@@ -30,14 +30,14 @@ export const useInteractiveRegistration = (): {
|
||||
password: string,
|
||||
displayName: string,
|
||||
recaptchaResponse: string,
|
||||
passwordlessUser: boolean
|
||||
passwordlessUser: boolean,
|
||||
) => Promise<[MatrixClient, Session]>;
|
||||
} => {
|
||||
const [privacyPolicyUrl, setPrivacyPolicyUrl] = useState<string | undefined>(
|
||||
undefined
|
||||
undefined,
|
||||
);
|
||||
const [recaptchaKey, setRecaptchaKey] = useState<string | undefined>(
|
||||
undefined
|
||||
undefined,
|
||||
);
|
||||
|
||||
const authClient = useRef<MatrixClient>();
|
||||
@@ -50,7 +50,7 @@ export const useInteractiveRegistration = (): {
|
||||
useEffect(() => {
|
||||
authClient.current!.registerRequest({}).catch((error) => {
|
||||
setPrivacyPolicyUrl(
|
||||
error.data?.params["m.login.terms"]?.policies?.privacy_policy?.en?.url
|
||||
error.data?.params["m.login.terms"]?.policies?.privacy_policy?.en?.url,
|
||||
);
|
||||
setRecaptchaKey(error.data?.params["m.login.recaptcha"]?.public_key);
|
||||
});
|
||||
@@ -62,7 +62,7 @@ export const useInteractiveRegistration = (): {
|
||||
password: string,
|
||||
displayName: string,
|
||||
recaptchaResponse: string,
|
||||
passwordlessUser: boolean
|
||||
passwordlessUser: boolean,
|
||||
): Promise<[MatrixClient, Session]> => {
|
||||
const interactiveAuth = new InteractiveAuth({
|
||||
matrixClient: authClient.current!,
|
||||
@@ -106,7 +106,7 @@ export const useInteractiveRegistration = (): {
|
||||
userId: user_id,
|
||||
deviceId: device_id,
|
||||
},
|
||||
false
|
||||
false,
|
||||
);
|
||||
|
||||
await client.setDisplayName(displayName);
|
||||
@@ -129,7 +129,7 @@ export const useInteractiveRegistration = (): {
|
||||
|
||||
return [client, session];
|
||||
},
|
||||
[]
|
||||
[],
|
||||
);
|
||||
|
||||
return { privacyPolicyUrl, recaptchaKey, register };
|
||||
|
||||
@@ -108,7 +108,7 @@ export function useRecaptcha(sitekey?: string): {
|
||||
window.grecaptcha.execute();
|
||||
|
||||
const iframe = document.querySelector<HTMLIFrameElement>(
|
||||
'iframe[src*="recaptcha/api2/bframe"]'
|
||||
'iframe[src*="recaptcha/api2/bframe"]',
|
||||
);
|
||||
|
||||
if (iframe?.parentNode?.parentNode) {
|
||||
|
||||
@@ -48,7 +48,7 @@ export function useRegisterPasswordlessUser(): UseRegisterPasswordlessUserType {
|
||||
randomString(16),
|
||||
displayName,
|
||||
recaptchaResponse,
|
||||
true
|
||||
true,
|
||||
);
|
||||
setClient({ client, session });
|
||||
} catch (e) {
|
||||
@@ -56,7 +56,7 @@ export function useRegisterPasswordlessUser(): UseRegisterPasswordlessUserType {
|
||||
throw e;
|
||||
}
|
||||
},
|
||||
[execute, reset, register, setClient]
|
||||
[execute, reset, register, setClient],
|
||||
);
|
||||
|
||||
return { privacyPolicyUrl, registerPasswordlessUser, recaptchaId };
|
||||
|
||||
@@ -146,7 +146,9 @@ limitations under the License.
|
||||
.copyButton {
|
||||
width: 100%;
|
||||
height: 40px;
|
||||
transition: border-color 250ms, background-color 250ms;
|
||||
transition:
|
||||
border-color 250ms,
|
||||
background-color 250ms;
|
||||
}
|
||||
|
||||
.copyButton span {
|
||||
|
||||
@@ -94,12 +94,12 @@ export const Button = forwardRef<HTMLButtonElement, Props>(
|
||||
onPressStart,
|
||||
...rest
|
||||
},
|
||||
ref
|
||||
ref,
|
||||
) => {
|
||||
const buttonRef = useObjectRef<HTMLButtonElement>(ref);
|
||||
const { buttonProps } = useButton(
|
||||
{ onPress, onPressStart, ...rest },
|
||||
buttonRef
|
||||
buttonRef,
|
||||
);
|
||||
|
||||
// TODO: react-aria's useButton hook prevents form submission via keyboard
|
||||
@@ -121,7 +121,7 @@ export const Button = forwardRef<HTMLButtonElement, Props>(
|
||||
{
|
||||
[styles.on]: on,
|
||||
[styles.off]: off,
|
||||
}
|
||||
},
|
||||
)}
|
||||
{...mergeProps(rest, filteredButtonProps)}
|
||||
ref={buttonRef}
|
||||
@@ -132,7 +132,7 @@ export const Button = forwardRef<HTMLButtonElement, Props>(
|
||||
</>
|
||||
</button>
|
||||
);
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
export const MicButton: FC<{
|
||||
|
||||
@@ -47,7 +47,7 @@ export const LinkButton: FC<Props> = ({
|
||||
className={classNames(
|
||||
variantToClassName[variant || "secondary"],
|
||||
size ? sizeToClassName[size] : [],
|
||||
className
|
||||
className,
|
||||
)}
|
||||
to={to}
|
||||
{...rest}
|
||||
|
||||
@@ -57,7 +57,7 @@ export class Config {
|
||||
}
|
||||
|
||||
async function downloadConfig(
|
||||
configJsonFilename: string
|
||||
configJsonFilename: string,
|
||||
): Promise<ConfigOptions> {
|
||||
const url = new URL(configJsonFilename, window.location.href);
|
||||
url.searchParams.set("cachebuster", Date.now().toString());
|
||||
|
||||
@@ -26,7 +26,7 @@ export const getRoomSharedKeyLocalStorageKey = (roomId: string): string =>
|
||||
`room-shared-key-${roomId}`;
|
||||
|
||||
const useInternalRoomSharedKey = (
|
||||
roomId: string
|
||||
roomId: string,
|
||||
): [string | null, (value: string) => void] => {
|
||||
const key = useMemo(() => getRoomSharedKeyLocalStorageKey(roomId), [roomId]);
|
||||
const [e2eeEnabled] = useEnableE2EE();
|
||||
@@ -68,6 +68,6 @@ export const useIsRoomE2EE = (roomId: string): boolean | null => {
|
||||
// should inspect the e2eEnabled URL parameter here?
|
||||
return useMemo(
|
||||
() => widget === null && (room === null || !room.getCanonicalAlias()),
|
||||
[room]
|
||||
[room],
|
||||
);
|
||||
};
|
||||
|
||||
@@ -36,5 +36,5 @@ export const Form = forwardRef<HTMLFormElement, FormProps>(
|
||||
{children}
|
||||
</form>
|
||||
);
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
@@ -74,7 +74,7 @@ const CallTile: FC<CallTileProps> = ({ name, avatarUrl, room }) => {
|
||||
to={getRelativeRoomUrl(
|
||||
room.roomId,
|
||||
room.name,
|
||||
roomSharedKey ?? undefined
|
||||
roomSharedKey ?? undefined,
|
||||
)}
|
||||
className={styles.callTileLink}
|
||||
>
|
||||
@@ -92,7 +92,7 @@ const CallTile: FC<CallTileProps> = ({ name, avatarUrl, room }) => {
|
||||
value={getAbsoluteRoomUrl(
|
||||
room.roomId,
|
||||
room.name,
|
||||
roomSharedKey ?? undefined
|
||||
roomSharedKey ?? undefined,
|
||||
)}
|
||||
/>
|
||||
</div>
|
||||
|
||||
@@ -56,7 +56,7 @@ export const RegisteredView: FC<Props> = ({ client }) => {
|
||||
useState(false);
|
||||
const onDismissJoinExistingCallModal = useCallback(
|
||||
() => setJoinExistingCallModalOpen(false),
|
||||
[setJoinExistingCallModalOpen]
|
||||
[setJoinExistingCallModalOpen],
|
||||
);
|
||||
const [e2eeEnabled] = useEnableE2EE();
|
||||
|
||||
@@ -77,15 +77,15 @@ export const RegisteredView: FC<Props> = ({ client }) => {
|
||||
const createRoomResult = await createRoom(
|
||||
client,
|
||||
roomName,
|
||||
e2eeEnabled ?? false
|
||||
e2eeEnabled ?? false,
|
||||
);
|
||||
|
||||
history.push(
|
||||
getRelativeRoomUrl(
|
||||
createRoomResult.roomId,
|
||||
roomName,
|
||||
createRoomResult.password
|
||||
)
|
||||
createRoomResult.password,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -102,7 +102,7 @@ export const RegisteredView: FC<Props> = ({ client }) => {
|
||||
}
|
||||
});
|
||||
},
|
||||
[client, history, setJoinExistingCallModalOpen, e2eeEnabled]
|
||||
[client, history, setJoinExistingCallModalOpen, e2eeEnabled],
|
||||
);
|
||||
|
||||
const recentRooms = useGroupCallRooms(client);
|
||||
|
||||
@@ -57,7 +57,7 @@ export const UnauthenticatedView: FC = () => {
|
||||
useState(false);
|
||||
const onDismissJoinExistingCallModal = useCallback(
|
||||
() => setJoinExistingCallModalOpen(false),
|
||||
[setJoinExistingCallModalOpen]
|
||||
[setJoinExistingCallModalOpen],
|
||||
);
|
||||
const [onFinished, setOnFinished] = useState<() => void>();
|
||||
const history = useHistory();
|
||||
@@ -82,7 +82,7 @@ export const UnauthenticatedView: FC = () => {
|
||||
randomString(16),
|
||||
displayName,
|
||||
recaptchaResponse,
|
||||
true
|
||||
true,
|
||||
);
|
||||
|
||||
let createRoomResult;
|
||||
@@ -90,7 +90,7 @@ export const UnauthenticatedView: FC = () => {
|
||||
createRoomResult = await createRoom(
|
||||
client,
|
||||
roomName,
|
||||
e2eeEnabled ?? false
|
||||
e2eeEnabled ?? false,
|
||||
);
|
||||
} catch (error) {
|
||||
if (!setClient) {
|
||||
@@ -124,8 +124,8 @@ export const UnauthenticatedView: FC = () => {
|
||||
getRelativeRoomUrl(
|
||||
createRoomResult.roomId,
|
||||
roomName,
|
||||
createRoomResult.password
|
||||
)
|
||||
createRoomResult.password,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -144,7 +144,7 @@ export const UnauthenticatedView: FC = () => {
|
||||
setJoinExistingCallModalOpen,
|
||||
setClient,
|
||||
e2eeEnabled,
|
||||
]
|
||||
],
|
||||
);
|
||||
|
||||
return (
|
||||
|
||||
@@ -47,7 +47,7 @@ function getLastTs(client: MatrixClient, r: Room): number {
|
||||
if (r.getMyMembership() !== "join") {
|
||||
const membershipEvent = r.currentState.getStateEvents(
|
||||
"m.room.member",
|
||||
myUserId
|
||||
myUserId,
|
||||
);
|
||||
|
||||
if (membershipEvent && !Array.isArray(membershipEvent)) {
|
||||
@@ -115,7 +115,7 @@ export function useGroupCallRooms(client: MatrixClient): GroupCallRoom[] {
|
||||
client.removeListener(GroupCallEventHandlerEvent.Incoming, updateRooms);
|
||||
client.removeListener(
|
||||
GroupCallEventHandlerEvent.Participants,
|
||||
updateRooms
|
||||
updateRooms,
|
||||
);
|
||||
};
|
||||
}, [client]);
|
||||
|
||||
@@ -68,7 +68,8 @@ limitations under the License.
|
||||
font-weight: 400;
|
||||
font-display: swap;
|
||||
unicode-range: var(--inter-unicode-range);
|
||||
src: url("/fonts/Inter/Inter-Regular.woff2") format("woff2"),
|
||||
src:
|
||||
url("/fonts/Inter/Inter-Regular.woff2") format("woff2"),
|
||||
url("/fonts/Inter/Inter-Regular.woff") format("woff");
|
||||
}
|
||||
|
||||
@@ -78,7 +79,8 @@ limitations under the License.
|
||||
font-weight: 400;
|
||||
font-display: swap;
|
||||
unicode-range: var(--inter-unicode-range);
|
||||
src: url("/fonts/Inter/Inter-Italic.woff2") format("woff2"),
|
||||
src:
|
||||
url("/fonts/Inter/Inter-Italic.woff2") format("woff2"),
|
||||
url("/fonts/Inter/Inter-Italic.woff") format("woff");
|
||||
}
|
||||
|
||||
@@ -88,7 +90,8 @@ limitations under the License.
|
||||
font-weight: 500;
|
||||
font-display: swap;
|
||||
unicode-range: var(--inter-unicode-range);
|
||||
src: url("/fonts/Inter/Inter-Medium.woff2") format("woff2"),
|
||||
src:
|
||||
url("/fonts/Inter/Inter-Medium.woff2") format("woff2"),
|
||||
url("/fonts/Inter/Inter-Medium.woff") format("woff");
|
||||
}
|
||||
|
||||
@@ -98,7 +101,8 @@ limitations under the License.
|
||||
font-weight: 500;
|
||||
font-display: swap;
|
||||
unicode-range: var(--inter-unicode-range);
|
||||
src: url("/fonts/Inter/Inter-MediumItalic.woff2") format("woff2"),
|
||||
src:
|
||||
url("/fonts/Inter/Inter-MediumItalic.woff2") format("woff2"),
|
||||
url("/fonts/Inter/Inter-MediumItalic.woff") format("woff");
|
||||
}
|
||||
|
||||
@@ -108,7 +112,8 @@ limitations under the License.
|
||||
font-weight: 600;
|
||||
font-display: swap;
|
||||
unicode-range: var(--inter-unicode-range);
|
||||
src: url("/fonts/Inter/Inter-SemiBold.woff2") format("woff2"),
|
||||
src:
|
||||
url("/fonts/Inter/Inter-SemiBold.woff2") format("woff2"),
|
||||
url("/fonts/Inter/Inter-SemiBold.woff") format("woff");
|
||||
}
|
||||
|
||||
@@ -118,7 +123,8 @@ limitations under the License.
|
||||
font-weight: 600;
|
||||
font-display: swap;
|
||||
unicode-range: var(--inter-unicode-range);
|
||||
src: url("/fonts/Inter/Inter-SemiBoldItalic.woff2") format("woff2"),
|
||||
src:
|
||||
url("/fonts/Inter/Inter-SemiBoldItalic.woff2") format("woff2"),
|
||||
url("/fonts/Inter/Inter-SemiBoldItalic.woff") format("woff");
|
||||
}
|
||||
|
||||
@@ -128,7 +134,8 @@ limitations under the License.
|
||||
font-weight: 700;
|
||||
font-display: swap;
|
||||
unicode-range: var(--inter-unicode-range);
|
||||
src: url("/fonts/Inter/Inter-Bold.woff2") format("woff2"),
|
||||
src:
|
||||
url("/fonts/Inter/Inter-Bold.woff2") format("woff2"),
|
||||
url("/fonts/Inter/Inter-Bold.woff") format("woff");
|
||||
}
|
||||
|
||||
@@ -138,7 +145,8 @@ limitations under the License.
|
||||
font-weight: 700;
|
||||
font-display: swap;
|
||||
unicode-range: var(--inter-unicode-range);
|
||||
src: url("/fonts/Inter/Inter-BoldItalic.woff2") format("woff2"),
|
||||
src:
|
||||
url("/fonts/Inter/Inter-BoldItalic.woff2") format("woff2"),
|
||||
url("/fonts/Inter/Inter-BoldItalic.woff") format("woff");
|
||||
}
|
||||
|
||||
|
||||
@@ -99,13 +99,13 @@ export class Initializer {
|
||||
if (fontScale !== null) {
|
||||
document.documentElement.style.setProperty(
|
||||
"--font-scale",
|
||||
fontScale.toString()
|
||||
fontScale.toString(),
|
||||
);
|
||||
}
|
||||
if (fonts.length > 0) {
|
||||
document.documentElement.style.setProperty(
|
||||
"--font-family",
|
||||
fonts.map((f) => `"${f}"`).join(", ")
|
||||
fonts.map((f) => `"${f}"`).join(", "),
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -52,7 +52,7 @@ export const AvatarInputField = forwardRef<HTMLInputElement, Props>(
|
||||
onRemoveAvatar,
|
||||
...rest
|
||||
},
|
||||
ref
|
||||
ref,
|
||||
) => {
|
||||
const { t } = useTranslation();
|
||||
|
||||
@@ -120,5 +120,5 @@ export const AvatarInputField = forwardRef<HTMLInputElement, Props>(
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
@@ -85,8 +85,11 @@ limitations under the License.
|
||||
}
|
||||
|
||||
.inputField label {
|
||||
transition: font-size 0.25s ease-out 0.1s, color 0.25s ease-out 0.1s,
|
||||
top 0.25s ease-out 0.1s, background-color 0.25s ease-out 0.1s;
|
||||
transition:
|
||||
font-size 0.25s ease-out 0.1s,
|
||||
color 0.25s ease-out 0.1s,
|
||||
top 0.25s ease-out 0.1s,
|
||||
background-color 0.25s ease-out 0.1s;
|
||||
color: var(--cpd-color-text-secondary);
|
||||
background-color: transparent;
|
||||
font-size: var(--font-size-body);
|
||||
@@ -118,8 +121,11 @@ limitations under the License.
|
||||
.inputField textarea:not(:placeholder-shown) + label,
|
||||
.inputField.prefix textarea + label {
|
||||
background-color: var(--cpd-color-bg-canvas-default);
|
||||
transition: font-size 0.25s ease-out 0s, color 0.25s ease-out 0s,
|
||||
top 0.25s ease-out 0s, background-color 0.25s ease-out 0s;
|
||||
transition:
|
||||
font-size 0.25s ease-out 0s,
|
||||
color 0.25s ease-out 0s,
|
||||
top 0.25s ease-out 0s,
|
||||
background-color 0.25s ease-out 0s;
|
||||
font-size: var(--font-size-micro);
|
||||
top: -13px;
|
||||
padding: 0 2px;
|
||||
|
||||
@@ -44,7 +44,7 @@ export function FieldRow({
|
||||
className={classNames(
|
||||
styles.fieldRow,
|
||||
{ [styles.rightAlign]: rightAlign },
|
||||
className
|
||||
className,
|
||||
)}
|
||||
>
|
||||
{children}
|
||||
@@ -102,7 +102,7 @@ export const InputField = forwardRef<
|
||||
disabled,
|
||||
...rest
|
||||
},
|
||||
ref
|
||||
ref,
|
||||
) => {
|
||||
const descriptionId = useId();
|
||||
|
||||
@@ -114,7 +114,7 @@ export const InputField = forwardRef<
|
||||
[styles.prefix]: !!prefix,
|
||||
[styles.disabled]: disabled,
|
||||
},
|
||||
className
|
||||
className,
|
||||
)}
|
||||
>
|
||||
{prefix && <span>{prefix}</span>}
|
||||
@@ -163,7 +163,7 @@ export const InputField = forwardRef<
|
||||
)}
|
||||
</Field>
|
||||
);
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
interface ErrorMessageProps {
|
||||
|
||||
@@ -38,7 +38,7 @@ export function SelectInput(props: Props): JSX.Element {
|
||||
const { labelProps, triggerProps, valueProps, menuProps } = useSelect(
|
||||
props,
|
||||
state,
|
||||
ref
|
||||
ref,
|
||||
);
|
||||
|
||||
const { buttonProps } = useButton(triggerProps, ref);
|
||||
|
||||
@@ -51,7 +51,7 @@ export interface MediaDevices {
|
||||
// Cargo-culted from @livekit/components-react
|
||||
function useObservableState<T>(
|
||||
observable: Observable<T> | undefined,
|
||||
startWith: T
|
||||
startWith: T,
|
||||
): T {
|
||||
const [state, setState] = useState<T>(startWith);
|
||||
useEffect(() => {
|
||||
@@ -67,7 +67,7 @@ function useMediaDevice(
|
||||
kind: MediaDeviceKind,
|
||||
fallbackDevice: string | undefined,
|
||||
usingNames: boolean,
|
||||
alwaysDefault: boolean = false
|
||||
alwaysDefault: boolean = false,
|
||||
): MediaDevice {
|
||||
// Make sure we don't needlessly reset to a device observer without names,
|
||||
// once permissions are already given
|
||||
@@ -83,7 +83,7 @@ function useMediaDevice(
|
||||
// kind, which then results in multiple permissions requests.
|
||||
const deviceObserver = useMemo(
|
||||
() => createMediaDeviceObserver(kind, requestPermissions),
|
||||
[kind, requestPermissions]
|
||||
[kind, requestPermissions],
|
||||
);
|
||||
const available = useObservableState(deviceObserver, []);
|
||||
const [selectedId, select] = useState(fallbackDevice);
|
||||
@@ -143,18 +143,18 @@ export const MediaDevicesProvider: FC<Props> = ({ children }) => {
|
||||
const audioInput = useMediaDevice(
|
||||
"audioinput",
|
||||
audioInputSetting,
|
||||
usingNames
|
||||
usingNames,
|
||||
);
|
||||
const audioOutput = useMediaDevice(
|
||||
"audiooutput",
|
||||
audioOutputSetting,
|
||||
useOutputNames,
|
||||
alwaysUseDefaultAudio
|
||||
alwaysUseDefaultAudio,
|
||||
);
|
||||
const videoInput = useMediaDevice(
|
||||
"videoinput",
|
||||
videoInputSetting,
|
||||
usingNames
|
||||
usingNames,
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
@@ -176,11 +176,11 @@ export const MediaDevicesProvider: FC<Props> = ({ children }) => {
|
||||
|
||||
const startUsingDeviceNames = useCallback(
|
||||
() => setNumCallersUsingNames((n) => n + 1),
|
||||
[setNumCallersUsingNames]
|
||||
[setNumCallersUsingNames],
|
||||
);
|
||||
const stopUsingDeviceNames = useCallback(
|
||||
() => setNumCallersUsingNames((n) => n - 1),
|
||||
[setNumCallersUsingNames]
|
||||
[setNumCallersUsingNames],
|
||||
);
|
||||
|
||||
const context: MediaDevices = useMemo(
|
||||
@@ -197,7 +197,7 @@ export const MediaDevicesProvider: FC<Props> = ({ children }) => {
|
||||
videoInput,
|
||||
startUsingDeviceNames,
|
||||
stopUsingDeviceNames,
|
||||
]
|
||||
],
|
||||
);
|
||||
|
||||
return (
|
||||
@@ -218,7 +218,7 @@ export const useMediaDevices = (): MediaDevices =>
|
||||
*/
|
||||
export const useMediaDeviceNames = (
|
||||
context: MediaDevices,
|
||||
enabled = true
|
||||
enabled = true,
|
||||
): void =>
|
||||
useEffect(() => {
|
||||
if (enabled) {
|
||||
|
||||
@@ -42,7 +42,7 @@ export type OpenIDClientParts = Pick<
|
||||
|
||||
export function useOpenIDSFU(
|
||||
client: OpenIDClientParts,
|
||||
rtcSession: MatrixRTCSession
|
||||
rtcSession: MatrixRTCSession,
|
||||
): SFUConfig | undefined {
|
||||
const [sfuConfig, setSFUConfig] = useState<SFUConfig | undefined>(undefined);
|
||||
|
||||
@@ -62,20 +62,20 @@ export function useOpenIDSFU(
|
||||
|
||||
export async function getSFUConfigWithOpenID(
|
||||
client: OpenIDClientParts,
|
||||
activeFocus: LivekitFocus
|
||||
activeFocus: LivekitFocus,
|
||||
): Promise<SFUConfig | undefined> {
|
||||
const openIdToken = await client.getOpenIdToken();
|
||||
logger.debug("Got openID token", openIdToken);
|
||||
|
||||
try {
|
||||
logger.info(
|
||||
`Trying to get JWT from call's active focus URL of ${activeFocus.livekit_service_url}...`
|
||||
`Trying to get JWT from call's active focus URL of ${activeFocus.livekit_service_url}...`,
|
||||
);
|
||||
const sfuConfig = await getLiveKitJWT(
|
||||
client,
|
||||
activeFocus.livekit_service_url,
|
||||
activeFocus.livekit_alias,
|
||||
openIdToken
|
||||
openIdToken,
|
||||
);
|
||||
logger.info(`Got JWT from call's active focus URL.`);
|
||||
|
||||
@@ -83,7 +83,7 @@ export async function getSFUConfigWithOpenID(
|
||||
} catch (e) {
|
||||
logger.warn(
|
||||
`Failed to get JWT from RTC session's active focus URL of ${activeFocus.livekit_service_url}.`,
|
||||
e
|
||||
e,
|
||||
);
|
||||
return undefined;
|
||||
}
|
||||
@@ -93,7 +93,7 @@ async function getLiveKitJWT(
|
||||
client: OpenIDClientParts,
|
||||
livekitServiceURL: string,
|
||||
roomName: string,
|
||||
openIDToken: IOpenIDToken
|
||||
openIDToken: IOpenIDToken,
|
||||
): Promise<SFUConfig> {
|
||||
try {
|
||||
const res = await fetch(livekitServiceURL + "/sfu/get", {
|
||||
|
||||
@@ -51,7 +51,7 @@ async function doConnect(
|
||||
livekitRoom: Room,
|
||||
sfuConfig: SFUConfig,
|
||||
audioEnabled: boolean,
|
||||
audioOptions: AudioCaptureOptions
|
||||
audioOptions: AudioCaptureOptions,
|
||||
): Promise<void> {
|
||||
await livekitRoom!.connect(sfuConfig!.url, sfuConfig!.jwt);
|
||||
|
||||
@@ -76,12 +76,12 @@ export function useECConnectionState(
|
||||
initialAudioOptions: AudioCaptureOptions,
|
||||
initialAudioEnabled: boolean,
|
||||
livekitRoom?: Room,
|
||||
sfuConfig?: SFUConfig
|
||||
sfuConfig?: SFUConfig,
|
||||
): ECConnectionState {
|
||||
const [connState, setConnState] = useState(
|
||||
sfuConfig && livekitRoom
|
||||
? livekitRoom.state
|
||||
: ECAddonConnectionState.ECWaiting
|
||||
: ECAddonConnectionState.ECWaiting,
|
||||
);
|
||||
|
||||
const [isSwitchingFocus, setSwitchingFocus] = useState(false);
|
||||
@@ -116,7 +116,7 @@ export function useECConnectionState(
|
||||
!sfuConfigEquals(currentSFUConfig.current, sfuConfig)
|
||||
) {
|
||||
logger.info(
|
||||
`SFU config changed! URL was ${currentSFUConfig.current?.url} now ${sfuConfig?.url}`
|
||||
`SFU config changed! URL was ${currentSFUConfig.current?.url} now ${sfuConfig?.url}`,
|
||||
);
|
||||
|
||||
(async (): Promise<void> => {
|
||||
@@ -128,7 +128,7 @@ export function useECConnectionState(
|
||||
livekitRoom!,
|
||||
sfuConfig!,
|
||||
initialAudioEnabled,
|
||||
initialAudioOptions
|
||||
initialAudioOptions,
|
||||
);
|
||||
} finally {
|
||||
setIsInDoConnect(false);
|
||||
@@ -149,7 +149,7 @@ export function useECConnectionState(
|
||||
livekitRoom!,
|
||||
sfuConfig!,
|
||||
initialAudioEnabled,
|
||||
initialAudioOptions
|
||||
initialAudioOptions,
|
||||
).finally(() => setIsInDoConnect(false));
|
||||
}
|
||||
|
||||
|
||||
@@ -52,7 +52,7 @@ interface UseLivekitResult {
|
||||
export function useLiveKit(
|
||||
muteStates: MuteStates,
|
||||
sfuConfig?: SFUConfig,
|
||||
e2eeConfig?: E2EEConfig
|
||||
e2eeConfig?: E2EEConfig,
|
||||
): UseLivekitResult {
|
||||
const e2eeOptions = useMemo(() => {
|
||||
if (!e2eeConfig?.sharedKey) return undefined;
|
||||
@@ -67,7 +67,7 @@ export function useLiveKit(
|
||||
if (!e2eeConfig?.sharedKey || !e2eeOptions) return;
|
||||
|
||||
(e2eeOptions.keyProvider as ExternalE2EEKeyProvider).setKey(
|
||||
e2eeConfig?.sharedKey
|
||||
e2eeConfig?.sharedKey,
|
||||
);
|
||||
}, [e2eeOptions, e2eeConfig?.sharedKey]);
|
||||
|
||||
@@ -93,7 +93,7 @@ export function useLiveKit(
|
||||
},
|
||||
e2ee: e2eeOptions,
|
||||
}),
|
||||
[e2eeOptions]
|
||||
[e2eeOptions],
|
||||
);
|
||||
|
||||
// useECConnectionState creates and publishes an audio track by hand. To keep
|
||||
@@ -131,7 +131,7 @@ export function useLiveKit(
|
||||
},
|
||||
initialMuteStates.current.audio.enabled,
|
||||
room,
|
||||
sfuConfig
|
||||
sfuConfig,
|
||||
);
|
||||
|
||||
// Unblock audio once the connection is finished
|
||||
@@ -215,11 +215,11 @@ export function useLiveKit(
|
||||
room.options.audioCaptureDefaults?.deviceId === "default"
|
||||
) {
|
||||
const activeMicTrack = Array.from(
|
||||
room.localParticipant.audioTracks.values()
|
||||
room.localParticipant.audioTracks.values(),
|
||||
).find((d) => d.source === Track.Source.Microphone)?.track;
|
||||
|
||||
const defaultDevice = device.available.find(
|
||||
(d) => d.deviceId === "default"
|
||||
(d) => d.deviceId === "default",
|
||||
);
|
||||
if (
|
||||
defaultDevice &&
|
||||
@@ -245,7 +245,7 @@ export function useLiveKit(
|
||||
room
|
||||
.switchActiveDevice(kind, id)
|
||||
.catch((e) =>
|
||||
logger.error(`Failed to sync ${kind} device with LiveKit`, e)
|
||||
logger.error(`Failed to sync ${kind} device with LiveKit`, e),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -48,7 +48,7 @@ if (!window.isSecureContext) {
|
||||
fatalError = new Error(
|
||||
"This app cannot run in an insecure context. To fix this, access the app " +
|
||||
"via a local loopback address, or serve it over HTTPS.\n" +
|
||||
"https://developer.mozilla.org/en-US/docs/Web/Security/Secure_Contexts"
|
||||
"https://developer.mozilla.org/en-US/docs/Web/Security/Secure_Contexts",
|
||||
);
|
||||
} else if (!navigator.mediaDevices) {
|
||||
fatalError = new Error("Your browser does not support WebRTC.");
|
||||
@@ -66,5 +66,5 @@ const history = createBrowserHistory();
|
||||
root.render(
|
||||
<StrictMode>
|
||||
<App history={history} />
|
||||
</StrictMode>
|
||||
</StrictMode>,
|
||||
);
|
||||
|
||||
@@ -59,7 +59,7 @@ function waitForSync(client: MatrixClient): Promise<void> {
|
||||
const onSync = (
|
||||
state: SyncState,
|
||||
_old: SyncState | null,
|
||||
data?: ISyncStateData
|
||||
data?: ISyncStateData,
|
||||
): void => {
|
||||
if (state === "PREPARED") {
|
||||
client.removeListener(ClientEvent.Sync, onSync);
|
||||
@@ -83,7 +83,7 @@ function secureRandomString(entropyBytes: number): string {
|
||||
// yet) so just use the built-in one and convert, replace the chars and strip the
|
||||
// padding from the end (otherwise we'd need to pull in another dependency).
|
||||
return btoa(
|
||||
key.reduce((acc, current) => acc + String.fromCharCode(current), "")
|
||||
key.reduce((acc, current) => acc + String.fromCharCode(current), ""),
|
||||
)
|
||||
.replace("+", "-")
|
||||
.replace("/", "_")
|
||||
@@ -101,7 +101,7 @@ function secureRandomString(entropyBytes: number): string {
|
||||
*/
|
||||
export async function initClient(
|
||||
clientOptions: ICreateClientOpts,
|
||||
restore: boolean
|
||||
restore: boolean,
|
||||
): Promise<MatrixClient> {
|
||||
await loadOlm();
|
||||
|
||||
@@ -148,7 +148,7 @@ export async function initClient(
|
||||
if (indexedDB) {
|
||||
const cryptoStoreExists = await IndexedDBCryptoStore.exists(
|
||||
indexedDB,
|
||||
CRYPTO_STORE_NAME
|
||||
CRYPTO_STORE_NAME,
|
||||
);
|
||||
if (!cryptoStoreExists) throw new CryptoStoreIntegrityError();
|
||||
} else if (localStorage) {
|
||||
@@ -164,7 +164,7 @@ export async function initClient(
|
||||
if (indexedDB) {
|
||||
baseOpts.cryptoStore = new IndexedDBCryptoStore(
|
||||
indexedDB,
|
||||
CRYPTO_STORE_NAME
|
||||
CRYPTO_STORE_NAME,
|
||||
);
|
||||
} else if (localStorage) {
|
||||
baseOpts.cryptoStore = new LocalStorageCryptoStore(localStorage);
|
||||
@@ -198,7 +198,7 @@ export async function initClient(
|
||||
} catch (error) {
|
||||
logger.error(
|
||||
"Error starting matrix client store. Falling back to memory store.",
|
||||
error
|
||||
error,
|
||||
);
|
||||
client.store = new MemoryStore({ localStorage });
|
||||
await client.store.startup();
|
||||
@@ -268,7 +268,7 @@ export function roomNameFromRoomId(roomId: string): string {
|
||||
.substring(1)
|
||||
.split("-")
|
||||
.map((part) =>
|
||||
part.length > 0 ? part.charAt(0).toUpperCase() + part.slice(1) : part
|
||||
part.length > 0 ? part.charAt(0).toUpperCase() + part.slice(1) : part,
|
||||
)
|
||||
.join(" ")
|
||||
.toLowerCase();
|
||||
@@ -297,7 +297,7 @@ interface CreateRoomResult {
|
||||
export async function createRoom(
|
||||
client: MatrixClient,
|
||||
name: string,
|
||||
e2ee: boolean
|
||||
e2ee: boolean,
|
||||
): Promise<CreateRoomResult> {
|
||||
logger.log(`Creating room for group call`);
|
||||
const createPromise = client.createRoom({
|
||||
@@ -358,7 +358,7 @@ export async function createRoom(
|
||||
GroupCallType.Video,
|
||||
false,
|
||||
GroupCallIntent.Room,
|
||||
true
|
||||
true,
|
||||
);
|
||||
|
||||
let password;
|
||||
@@ -366,7 +366,7 @@ export async function createRoom(
|
||||
password = secureRandomString(16);
|
||||
setLocalStorageItem(
|
||||
getRoomSharedKeyLocalStorageKey(result.room_id),
|
||||
password
|
||||
password,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -386,7 +386,7 @@ export async function createRoom(
|
||||
export function getAbsoluteRoomUrl(
|
||||
roomId: string,
|
||||
roomName?: string,
|
||||
password?: string
|
||||
password?: string,
|
||||
): string {
|
||||
return `${window.location.protocol}//${
|
||||
window.location.host
|
||||
@@ -402,7 +402,7 @@ export function getAbsoluteRoomUrl(
|
||||
export function getRelativeRoomUrl(
|
||||
roomId: string,
|
||||
roomName?: string,
|
||||
password?: string
|
||||
password?: string,
|
||||
): string {
|
||||
// The password shouldn't need URL encoding here (we generate URL-safe ones) but encode
|
||||
// it in case it came from another client that generated a non url-safe one
|
||||
@@ -419,7 +419,7 @@ export function getRelativeRoomUrl(
|
||||
export function getAvatarUrl(
|
||||
client: MatrixClient,
|
||||
mxcUrl: string,
|
||||
avatarSize = 96
|
||||
avatarSize = 96,
|
||||
): string {
|
||||
const width = Math.floor(avatarSize * window.devicePixelRatio);
|
||||
const height = Math.floor(avatarSize * window.devicePixelRatio);
|
||||
|
||||
@@ -23,10 +23,10 @@ limitations under the License.
|
||||
export async function findDeviceByName(
|
||||
deviceName: string,
|
||||
kind: MediaDeviceKind,
|
||||
devices: MediaDeviceInfo[]
|
||||
devices: MediaDeviceInfo[],
|
||||
): Promise<string | undefined> {
|
||||
const deviceInfo = devices.find(
|
||||
(d) => d.kind === kind && d.label === deviceName
|
||||
(d) => d.kind === kind && d.label === deviceName,
|
||||
);
|
||||
return deviceInfo?.deviceId;
|
||||
}
|
||||
|
||||
@@ -48,14 +48,14 @@ export class OTelCall {
|
||||
public userId: string,
|
||||
public deviceId: string,
|
||||
public call: MatrixCall,
|
||||
public span: Span
|
||||
public span: Span,
|
||||
) {
|
||||
if (call.peerConn) {
|
||||
this.addCallPeerConnListeners();
|
||||
} else {
|
||||
this.call.once(
|
||||
CallEvent.PeerConnectionCreated,
|
||||
this.addCallPeerConnListeners
|
||||
this.addCallPeerConnListeners,
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -63,46 +63,46 @@ export class OTelCall {
|
||||
public dispose(): void {
|
||||
this.call.peerConn?.removeEventListener(
|
||||
"connectionstatechange",
|
||||
this.onCallConnectionStateChanged
|
||||
this.onCallConnectionStateChanged,
|
||||
);
|
||||
this.call.peerConn?.removeEventListener(
|
||||
"signalingstatechange",
|
||||
this.onCallSignalingStateChanged
|
||||
this.onCallSignalingStateChanged,
|
||||
);
|
||||
this.call.peerConn?.removeEventListener(
|
||||
"iceconnectionstatechange",
|
||||
this.onIceConnectionStateChanged
|
||||
this.onIceConnectionStateChanged,
|
||||
);
|
||||
this.call.peerConn?.removeEventListener(
|
||||
"icegatheringstatechange",
|
||||
this.onIceGatheringStateChanged
|
||||
this.onIceGatheringStateChanged,
|
||||
);
|
||||
this.call.peerConn?.removeEventListener(
|
||||
"icecandidateerror",
|
||||
this.onIceCandidateError
|
||||
this.onIceCandidateError,
|
||||
);
|
||||
}
|
||||
|
||||
private addCallPeerConnListeners = (): void => {
|
||||
this.call.peerConn?.addEventListener(
|
||||
"connectionstatechange",
|
||||
this.onCallConnectionStateChanged
|
||||
this.onCallConnectionStateChanged,
|
||||
);
|
||||
this.call.peerConn?.addEventListener(
|
||||
"signalingstatechange",
|
||||
this.onCallSignalingStateChanged
|
||||
this.onCallSignalingStateChanged,
|
||||
);
|
||||
this.call.peerConn?.addEventListener(
|
||||
"iceconnectionstatechange",
|
||||
this.onIceConnectionStateChanged
|
||||
this.onIceConnectionStateChanged,
|
||||
);
|
||||
this.call.peerConn?.addEventListener(
|
||||
"icegatheringstatechange",
|
||||
this.onIceGatheringStateChanged
|
||||
this.onIceGatheringStateChanged,
|
||||
);
|
||||
this.call.peerConn?.addEventListener(
|
||||
"icecandidateerror",
|
||||
this.onIceCandidateError
|
||||
this.onIceCandidateError,
|
||||
);
|
||||
};
|
||||
|
||||
@@ -147,8 +147,8 @@ export class OTelCall {
|
||||
new OTelCallFeedMediaStreamSpan(
|
||||
ElementCallOpenTelemetry.instance,
|
||||
this.span,
|
||||
feed
|
||||
)
|
||||
feed,
|
||||
),
|
||||
);
|
||||
}
|
||||
this.trackFeedSpan.get(feed.stream)?.update(feed);
|
||||
@@ -171,13 +171,13 @@ export class OTelCall {
|
||||
new OTelCallTransceiverMediaStreamSpan(
|
||||
ElementCallOpenTelemetry.instance,
|
||||
this.span,
|
||||
transStats
|
||||
)
|
||||
transStats,
|
||||
),
|
||||
);
|
||||
}
|
||||
this.trackTransceiverSpan.get(transStats.mid)?.update(transStats);
|
||||
prvTransSpan = prvTransSpan.filter(
|
||||
(prvStreamId) => prvStreamId !== transStats.mid
|
||||
(prvStreamId) => prvStreamId !== transStats.mid,
|
||||
);
|
||||
});
|
||||
|
||||
@@ -190,7 +190,7 @@ export class OTelCall {
|
||||
public end(): void {
|
||||
this.trackFeedSpan.forEach((feedSpan) => feedSpan.end());
|
||||
this.trackTransceiverSpan.forEach((transceiverSpan) =>
|
||||
transceiverSpan.end()
|
||||
transceiverSpan.end(),
|
||||
);
|
||||
this.span.end();
|
||||
}
|
||||
|
||||
@@ -32,11 +32,11 @@ export abstract class OTelCallAbstractMediaStreamSpan {
|
||||
public constructor(
|
||||
protected readonly oTel: ElementCallOpenTelemetry,
|
||||
protected readonly callSpan: Span,
|
||||
protected readonly type: string
|
||||
protected readonly type: string,
|
||||
) {
|
||||
const ctx = opentelemetry.trace.setSpan(
|
||||
opentelemetry.context.active(),
|
||||
callSpan
|
||||
callSpan,
|
||||
);
|
||||
const options = {
|
||||
links: [
|
||||
@@ -54,7 +54,7 @@ export abstract class OTelCallAbstractMediaStreamSpan {
|
||||
if (!this.trackSpans.has(t.id)) {
|
||||
this.trackSpans.set(
|
||||
t.id,
|
||||
new OTelCallMediaStreamTrackSpan(this.oTel, this.span, t)
|
||||
new OTelCallMediaStreamTrackSpan(this.oTel, this.span, t),
|
||||
);
|
||||
}
|
||||
this.trackSpans.get(t.id)?.update(t);
|
||||
|
||||
@@ -29,7 +29,7 @@ export class OTelCallFeedMediaStreamSpan extends OTelCallAbstractMediaStreamSpan
|
||||
public constructor(
|
||||
protected readonly oTel: ElementCallOpenTelemetry,
|
||||
protected readonly callSpan: Span,
|
||||
callFeed: CallFeedStats
|
||||
callFeed: CallFeedStats,
|
||||
) {
|
||||
const postFix =
|
||||
callFeed.type === "local" && callFeed.prefix === "from-call-feed"
|
||||
|
||||
@@ -26,11 +26,11 @@ export class OTelCallMediaStreamTrackSpan {
|
||||
public constructor(
|
||||
protected readonly oTel: ElementCallOpenTelemetry,
|
||||
protected readonly streamSpan: Span,
|
||||
data: TrackStats
|
||||
data: TrackStats,
|
||||
) {
|
||||
const ctx = opentelemetry.trace.setSpan(
|
||||
opentelemetry.context.active(),
|
||||
streamSpan
|
||||
streamSpan,
|
||||
);
|
||||
const options = {
|
||||
links: [
|
||||
|
||||
@@ -32,7 +32,7 @@ export class OTelCallTransceiverMediaStreamSpan extends OTelCallAbstractMediaStr
|
||||
public constructor(
|
||||
protected readonly oTel: ElementCallOpenTelemetry,
|
||||
protected readonly callSpan: Span,
|
||||
stats: TransceiverStats
|
||||
stats: TransceiverStats,
|
||||
) {
|
||||
super(oTel, callSpan, `matrix.call.transceiver.${stats.mid}`);
|
||||
this.span.setAttribute("transceiver.mid", stats.mid);
|
||||
|
||||
@@ -62,7 +62,10 @@ export class OTelGroupCallMembership {
|
||||
};
|
||||
private readonly speakingSpans = new Map<RoomMember, Map<string, Span>>();
|
||||
|
||||
public constructor(private groupCall: GroupCall, client: MatrixClient) {
|
||||
public constructor(
|
||||
private groupCall: GroupCall,
|
||||
client: MatrixClient,
|
||||
) {
|
||||
const clientId = client.getUserId();
|
||||
if (clientId) {
|
||||
this.myUserId = clientId;
|
||||
@@ -79,7 +82,7 @@ export class OTelGroupCallMembership {
|
||||
public dispose(): void {
|
||||
this.groupCall.removeListener(
|
||||
GroupCallEvent.CallsChanged,
|
||||
this.onCallsChanged
|
||||
this.onCallsChanged,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -93,22 +96,22 @@ export class OTelGroupCallMembership {
|
||||
// Create the main span that tracks the time we intend to be in the call
|
||||
this.callMembershipSpan =
|
||||
ElementCallOpenTelemetry.instance.tracer.startSpan(
|
||||
"matrix.groupCallMembership"
|
||||
"matrix.groupCallMembership",
|
||||
);
|
||||
this.callMembershipSpan.setAttribute(
|
||||
"matrix.confId",
|
||||
this.groupCall.groupCallId
|
||||
this.groupCall.groupCallId,
|
||||
);
|
||||
this.callMembershipSpan.setAttribute("matrix.userId", this.myUserId);
|
||||
this.callMembershipSpan.setAttribute("matrix.deviceId", this.myDeviceId);
|
||||
this.callMembershipSpan.setAttribute(
|
||||
"matrix.displayName",
|
||||
this.myMember ? this.myMember.name : "unknown-name"
|
||||
this.myMember ? this.myMember.name : "unknown-name",
|
||||
);
|
||||
|
||||
this.groupCallContext = opentelemetry.trace.setSpan(
|
||||
opentelemetry.context.active(),
|
||||
this.callMembershipSpan
|
||||
this.callMembershipSpan,
|
||||
);
|
||||
|
||||
this.callMembershipSpan?.addEvent("matrix.joinCall");
|
||||
@@ -138,7 +141,7 @@ export class OTelGroupCallMembership {
|
||||
|
||||
this.callMembershipSpan?.addEvent(
|
||||
`matrix.roomStateEvent_${event.getType()}`,
|
||||
ObjectFlattener.flattenVoipEvent(event.getContent())
|
||||
ObjectFlattener.flattenVoipEvent(event.getContent()),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -150,7 +153,7 @@ export class OTelGroupCallMembership {
|
||||
const span = ElementCallOpenTelemetry.instance.tracer.startSpan(
|
||||
`matrix.call`,
|
||||
undefined,
|
||||
this.groupCallContext
|
||||
this.groupCallContext,
|
||||
);
|
||||
// XXX: anonymity
|
||||
span.setAttribute("matrix.call.target.userId", userId);
|
||||
@@ -160,7 +163,7 @@ export class OTelGroupCallMembership {
|
||||
span.setAttribute("matrix.call.target.displayName", displayName);
|
||||
this.callsByCallId.set(
|
||||
call.callId,
|
||||
new OTelCall(userId, deviceId, call, span)
|
||||
new OTelCall(userId, deviceId, call, span),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -210,12 +213,12 @@ export class OTelGroupCallMembership {
|
||||
if (event.type === "toDevice") {
|
||||
callTrackingInfo.span.addEvent(
|
||||
`matrix.sendToDeviceEvent_${event.eventType}`,
|
||||
ObjectFlattener.flattenVoipEvent(event)
|
||||
ObjectFlattener.flattenVoipEvent(event),
|
||||
);
|
||||
} else if (event.type === "sendEvent") {
|
||||
callTrackingInfo.span.addEvent(
|
||||
`matrix.sendToRoomEvent_${event.eventType}`,
|
||||
ObjectFlattener.flattenVoipEvent(event)
|
||||
ObjectFlattener.flattenVoipEvent(event),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -239,7 +242,7 @@ export class OTelGroupCallMembership {
|
||||
"matrix.receive_voip_event_unknown_callid",
|
||||
{
|
||||
"sender.userId": event.getSender(),
|
||||
}
|
||||
},
|
||||
);
|
||||
logger.error("Received call event for unknown call ID " + callId);
|
||||
return;
|
||||
@@ -284,7 +287,7 @@ export class OTelGroupCallMembership {
|
||||
public onSpeaking(
|
||||
member: RoomMember,
|
||||
deviceId: string,
|
||||
speaking: boolean
|
||||
speaking: boolean,
|
||||
): void {
|
||||
if (speaking) {
|
||||
// Ensure that there's an audio activity span for this speaker
|
||||
@@ -298,7 +301,7 @@ export class OTelGroupCallMembership {
|
||||
const span = ElementCallOpenTelemetry.instance.tracer.startSpan(
|
||||
"matrix.audioActivity",
|
||||
undefined,
|
||||
this.groupCallContext
|
||||
this.groupCallContext,
|
||||
);
|
||||
span.setAttribute("matrix.userId", member.userId);
|
||||
span.setAttribute("matrix.displayName", member.rawDisplayName);
|
||||
@@ -336,7 +339,7 @@ export class OTelGroupCallMembership {
|
||||
}
|
||||
|
||||
public onCallFeedStatsReport(
|
||||
report: GroupCallStatsReport<CallFeedReport>
|
||||
report: GroupCallStatsReport<CallFeedReport>,
|
||||
): void {
|
||||
if (!ElementCallOpenTelemetry.instance) return;
|
||||
let call: OTelCall | undefined;
|
||||
@@ -354,10 +357,10 @@ export class OTelGroupCallMembership {
|
||||
"call.opponentMemberId": report.report?.opponentMemberId
|
||||
? report.report?.opponentMemberId
|
||||
: "unknown",
|
||||
}
|
||||
},
|
||||
);
|
||||
logger.error(
|
||||
`Received ${OTelStatsReportType.CallFeedReport} with unknown call ID: ${callId}`
|
||||
`Received ${OTelStatsReportType.CallFeedReport} with unknown call ID: ${callId}`,
|
||||
);
|
||||
return;
|
||||
} else {
|
||||
@@ -367,26 +370,26 @@ export class OTelGroupCallMembership {
|
||||
}
|
||||
|
||||
public onConnectionStatsReport(
|
||||
statsReport: GroupCallStatsReport<ConnectionStatsReport>
|
||||
statsReport: GroupCallStatsReport<ConnectionStatsReport>,
|
||||
): void {
|
||||
this.buildCallStatsSpan(
|
||||
OTelStatsReportType.ConnectionReport,
|
||||
statsReport.report
|
||||
statsReport.report,
|
||||
);
|
||||
}
|
||||
|
||||
public onByteSentStatsReport(
|
||||
statsReport: GroupCallStatsReport<ByteSentStatsReport>
|
||||
statsReport: GroupCallStatsReport<ByteSentStatsReport>,
|
||||
): void {
|
||||
this.buildCallStatsSpan(
|
||||
OTelStatsReportType.ByteSentReport,
|
||||
statsReport.report
|
||||
statsReport.report,
|
||||
);
|
||||
}
|
||||
|
||||
public buildCallStatsSpan(
|
||||
type: OTelStatsReportType,
|
||||
report: ByteSentStatsReport | ConnectionStatsReport
|
||||
report: ByteSentStatsReport | ConnectionStatsReport,
|
||||
): void {
|
||||
if (!ElementCallOpenTelemetry.instance) return;
|
||||
let call: OTelCall | undefined;
|
||||
@@ -409,7 +412,7 @@ export class OTelGroupCallMembership {
|
||||
const data = ObjectFlattener.flattenReportObject(type, report);
|
||||
const ctx = opentelemetry.trace.setSpan(
|
||||
opentelemetry.context.active(),
|
||||
call.span
|
||||
call.span,
|
||||
);
|
||||
|
||||
const options = {
|
||||
@@ -423,20 +426,20 @@ export class OTelGroupCallMembership {
|
||||
const span = ElementCallOpenTelemetry.instance.tracer.startSpan(
|
||||
type,
|
||||
options,
|
||||
ctx
|
||||
ctx,
|
||||
);
|
||||
|
||||
span.setAttribute("matrix.callId", callId ?? "unknown");
|
||||
span.setAttribute(
|
||||
"matrix.opponentMemberId",
|
||||
report.opponentMemberId ? report.opponentMemberId : "unknown"
|
||||
report.opponentMemberId ? report.opponentMemberId : "unknown",
|
||||
);
|
||||
span.addEvent("matrix.call.connection_stats_event", data);
|
||||
span.end();
|
||||
}
|
||||
|
||||
public onSummaryStatsReport(
|
||||
statsReport: GroupCallStatsReport<SummaryStatsReport>
|
||||
statsReport: GroupCallStatsReport<SummaryStatsReport>,
|
||||
): void {
|
||||
if (!ElementCallOpenTelemetry.instance) return;
|
||||
|
||||
@@ -445,12 +448,12 @@ export class OTelGroupCallMembership {
|
||||
if (this.statsReportSpan.span === undefined && this.callMembershipSpan) {
|
||||
const ctx = setSpan(
|
||||
opentelemetry.context.active(),
|
||||
this.callMembershipSpan
|
||||
this.callMembershipSpan,
|
||||
);
|
||||
const span = ElementCallOpenTelemetry.instance?.tracer.startSpan(
|
||||
"matrix.groupCallMembership.summaryReport",
|
||||
undefined,
|
||||
ctx
|
||||
ctx,
|
||||
);
|
||||
if (span === undefined) {
|
||||
return;
|
||||
@@ -459,7 +462,7 @@ export class OTelGroupCallMembership {
|
||||
span.setAttribute("matrix.userId", this.myUserId);
|
||||
span.setAttribute(
|
||||
"matrix.displayName",
|
||||
this.myMember ? this.myMember.name : "unknown-name"
|
||||
this.myMember ? this.myMember.name : "unknown-name",
|
||||
);
|
||||
span.addEvent(type, data);
|
||||
span.end();
|
||||
|
||||
@@ -25,7 +25,7 @@ import {
|
||||
export class ObjectFlattener {
|
||||
public static flattenReportObject(
|
||||
prefix: string,
|
||||
report: ConnectionStatsReport | ByteSentStatsReport
|
||||
report: ConnectionStatsReport | ByteSentStatsReport,
|
||||
): Attributes {
|
||||
const flatObject = {};
|
||||
ObjectFlattener.flattenObjectRecursive(report, flatObject, `${prefix}.`, 0);
|
||||
@@ -33,27 +33,27 @@ export class ObjectFlattener {
|
||||
}
|
||||
|
||||
public static flattenByteSentStatsReportObject(
|
||||
statsReport: GroupCallStatsReport<ByteSentStatsReport>
|
||||
statsReport: GroupCallStatsReport<ByteSentStatsReport>,
|
||||
): Attributes {
|
||||
const flatObject = {};
|
||||
ObjectFlattener.flattenObjectRecursive(
|
||||
statsReport.report,
|
||||
flatObject,
|
||||
"matrix.stats.bytesSent.",
|
||||
0
|
||||
0,
|
||||
);
|
||||
return flatObject;
|
||||
}
|
||||
|
||||
public static flattenSummaryStatsReportObject(
|
||||
statsReport: GroupCallStatsReport<SummaryStatsReport>
|
||||
statsReport: GroupCallStatsReport<SummaryStatsReport>,
|
||||
): Attributes {
|
||||
const flatObject = {};
|
||||
ObjectFlattener.flattenObjectRecursive(
|
||||
statsReport.report,
|
||||
flatObject,
|
||||
"matrix.stats.summary.",
|
||||
0
|
||||
0,
|
||||
);
|
||||
return flatObject;
|
||||
}
|
||||
@@ -67,7 +67,7 @@ export class ObjectFlattener {
|
||||
event as unknown as Record<string, unknown>, // XXX Types
|
||||
flatObject,
|
||||
"matrix.event.",
|
||||
0
|
||||
0,
|
||||
);
|
||||
|
||||
return flatObject;
|
||||
@@ -77,12 +77,12 @@ export class ObjectFlattener {
|
||||
obj: Object,
|
||||
flatObject: Attributes,
|
||||
prefix: string,
|
||||
depth: number
|
||||
depth: number,
|
||||
): void {
|
||||
if (depth > 10)
|
||||
throw new Error(
|
||||
"Depth limit exceeded: aborting VoipEvent recursion. Prefix is " +
|
||||
prefix
|
||||
prefix,
|
||||
);
|
||||
let entries;
|
||||
if (obj instanceof Map) {
|
||||
@@ -101,7 +101,7 @@ export class ObjectFlattener {
|
||||
v,
|
||||
flatObject,
|
||||
prefix + k + ".",
|
||||
depth + 1
|
||||
depth + 1,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -50,7 +50,7 @@ export class ElementCallOpenTelemetry {
|
||||
|
||||
sharedInstance = new ElementCallOpenTelemetry(
|
||||
config.opentelemetry?.collector_url,
|
||||
config.rageshake?.submit_url
|
||||
config.rageshake?.submit_url,
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -61,7 +61,7 @@ export class ElementCallOpenTelemetry {
|
||||
|
||||
private constructor(
|
||||
collectorUrl: string | undefined,
|
||||
rageshakeUrl: string | undefined
|
||||
rageshakeUrl: string | undefined,
|
||||
) {
|
||||
// This is how we can make Jaeger show a reasonable service in the dropdown on the left.
|
||||
const providerConfig = {
|
||||
@@ -77,7 +77,7 @@ export class ElementCallOpenTelemetry {
|
||||
url: collectorUrl,
|
||||
});
|
||||
this._provider.addSpanProcessor(
|
||||
new SimpleSpanProcessor(this.otlpExporter)
|
||||
new SimpleSpanProcessor(this.otlpExporter),
|
||||
);
|
||||
} else {
|
||||
logger.info("OTLP collector disabled");
|
||||
@@ -93,7 +93,7 @@ export class ElementCallOpenTelemetry {
|
||||
|
||||
this._tracer = opentelemetry.trace.getTracer(
|
||||
// This is not the serviceName shown in jaeger
|
||||
"my-element-call-otl-tracer"
|
||||
"my-element-call-otl-tracer",
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -40,7 +40,7 @@ export const Popover = forwardRef<HTMLDivElement, Props>(
|
||||
shouldCloseOnBlur: true,
|
||||
isDismissable: true,
|
||||
},
|
||||
popoverRef
|
||||
popoverRef,
|
||||
);
|
||||
|
||||
return (
|
||||
@@ -56,5 +56,5 @@ export const Popover = forwardRef<HTMLDivElement, Props>(
|
||||
</div>
|
||||
</FocusScope>
|
||||
);
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
@@ -43,7 +43,7 @@ export const PopoverMenuTrigger = forwardRef<
|
||||
const { menuTriggerProps, menuProps } = useMenuTrigger(
|
||||
{},
|
||||
popoverMenuState,
|
||||
buttonRef
|
||||
buttonRef,
|
||||
);
|
||||
|
||||
const popoverRef = useRef(null);
|
||||
@@ -62,7 +62,7 @@ export const PopoverMenuTrigger = forwardRef<
|
||||
typeof children[1] !== "function"
|
||||
) {
|
||||
throw new Error(
|
||||
"PopoverMenu must have two props. The first being a button and the second being a render prop."
|
||||
"PopoverMenu must have two props. The first being a button and the second being a render prop.",
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -63,7 +63,7 @@ export function useProfile(client: MatrixClient | undefined): UseProfile {
|
||||
useEffect(() => {
|
||||
const onChangeUser = (
|
||||
_event: MatrixEvent | undefined,
|
||||
{ displayName, avatarUrl }: User
|
||||
{ displayName, avatarUrl }: User,
|
||||
): void => {
|
||||
setState({
|
||||
success: false,
|
||||
@@ -108,9 +108,8 @@ export function useProfile(client: MatrixClient | undefined): UseProfile {
|
||||
if (removeAvatar) {
|
||||
await client.setAvatarUrl("");
|
||||
} else if (avatar) {
|
||||
({ content_uri: mxcAvatarUrl } = await client.uploadContent(
|
||||
avatar
|
||||
));
|
||||
({ content_uri: mxcAvatarUrl } =
|
||||
await client.uploadContent(avatar));
|
||||
await client.setAvatarUrl(mxcAvatarUrl);
|
||||
}
|
||||
|
||||
@@ -135,7 +134,7 @@ export function useProfile(client: MatrixClient | undefined): UseProfile {
|
||||
logger.error("Client not initialized before calling saveProfile");
|
||||
}
|
||||
},
|
||||
[client]
|
||||
[client],
|
||||
);
|
||||
|
||||
return {
|
||||
|
||||
@@ -40,14 +40,14 @@ export const AppSelectionModal: FC<Props> = ({ roomId }) => {
|
||||
e.stopPropagation();
|
||||
setOpen(false);
|
||||
},
|
||||
[setOpen]
|
||||
[setOpen],
|
||||
);
|
||||
|
||||
const roomSharedKey = useRoomSharedKey(roomId ?? "");
|
||||
const roomIsEncrypted = useIsRoomE2EE(roomId ?? "");
|
||||
if (roomIsEncrypted && roomSharedKey === undefined) {
|
||||
logger.error(
|
||||
"Generating app redirect URL for encrypted room but don't have key available!"
|
||||
"Generating app redirect URL for encrypted room but don't have key available!",
|
||||
);
|
||||
}
|
||||
|
||||
@@ -60,7 +60,7 @@ export const AppSelectionModal: FC<Props> = ({ roomId }) => {
|
||||
const url = new URL(
|
||||
roomId === null
|
||||
? window.location.href
|
||||
: getAbsoluteRoomUrl(roomId, undefined, roomSharedKey ?? undefined)
|
||||
: getAbsoluteRoomUrl(roomId, undefined, roomSharedKey ?? undefined),
|
||||
);
|
||||
// Edit the URL to prevent the app selection prompt from appearing a second
|
||||
// time within the app, and to keep the user confined to the current room
|
||||
|
||||
@@ -64,7 +64,7 @@ export const CallEndedView: FC<Props> = ({
|
||||
PosthogAnalytics.instance.eventQualitySurvey.track(
|
||||
endedCallId,
|
||||
feedbackText,
|
||||
starRating
|
||||
starRating,
|
||||
);
|
||||
|
||||
setSubmitting(true);
|
||||
@@ -83,7 +83,7 @@ export const CallEndedView: FC<Props> = ({
|
||||
}, 1000);
|
||||
}, 1000);
|
||||
},
|
||||
[endedCallId, history, isPasswordlessUser, confineToRoom, starRating]
|
||||
[endedCallId, history, isPasswordlessUser, confineToRoom, starRating],
|
||||
);
|
||||
|
||||
const createAccountDialog = isPasswordlessUser && (
|
||||
|
||||
@@ -47,7 +47,7 @@ export function GroupCallLoader({
|
||||
ev.preventDefault();
|
||||
history.push("/");
|
||||
},
|
||||
[history]
|
||||
[history],
|
||||
);
|
||||
|
||||
switch (groupCallState.kind) {
|
||||
@@ -66,7 +66,7 @@ export function GroupCallLoader({
|
||||
<Heading>{t("Call not found")}</Heading>
|
||||
<Text>
|
||||
{t(
|
||||
"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."
|
||||
"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.",
|
||||
)}
|
||||
</Text>
|
||||
{/* XXX: A 'create it for me' button would be the obvious UX here. Two screens already have
|
||||
|
||||
@@ -111,7 +111,7 @@ export const GroupCallView: FC<Props> = ({
|
||||
// Count each member only once, regardless of how many devices they use
|
||||
const participantCount = useMemo(
|
||||
() => new Set<string>(memberships.map((m) => m.sender!)).size,
|
||||
[memberships]
|
||||
[memberships],
|
||||
);
|
||||
|
||||
const deviceContext = useMediaDevices();
|
||||
@@ -126,7 +126,7 @@ export const GroupCallView: FC<Props> = ({
|
||||
if (widget && preload) {
|
||||
// In preload mode, wait for a join action before entering
|
||||
const onJoin = async (
|
||||
ev: CustomEvent<IWidgetApiRequest>
|
||||
ev: CustomEvent<IWidgetApiRequest>,
|
||||
): Promise<void> => {
|
||||
// XXX: I think this is broken currently - LiveKit *won't* request
|
||||
// permissions and give you device names unless you specify a kind, but
|
||||
@@ -143,14 +143,14 @@ export const GroupCallView: FC<Props> = ({
|
||||
const deviceId = await findDeviceByName(
|
||||
audioInput,
|
||||
"audioinput",
|
||||
devices
|
||||
devices,
|
||||
);
|
||||
if (!deviceId) {
|
||||
logger.warn("Unknown audio input: " + audioInput);
|
||||
latestMuteStates.current!.audio.setEnabled?.(false);
|
||||
} else {
|
||||
logger.debug(
|
||||
`Found audio input ID ${deviceId} for name ${audioInput}`
|
||||
`Found audio input ID ${deviceId} for name ${audioInput}`,
|
||||
);
|
||||
latestDevices.current!.audioInput.select(deviceId);
|
||||
latestMuteStates.current!.audio.setEnabled?.(true);
|
||||
@@ -163,14 +163,14 @@ export const GroupCallView: FC<Props> = ({
|
||||
const deviceId = await findDeviceByName(
|
||||
videoInput,
|
||||
"videoinput",
|
||||
devices
|
||||
devices,
|
||||
);
|
||||
if (!deviceId) {
|
||||
logger.warn("Unknown video input: " + videoInput);
|
||||
latestMuteStates.current!.video.setEnabled?.(false);
|
||||
} else {
|
||||
logger.debug(
|
||||
`Found video input ID ${deviceId} for name ${videoInput}`
|
||||
`Found video input ID ${deviceId} for name ${videoInput}`,
|
||||
);
|
||||
latestDevices.current!.videoInput.select(deviceId);
|
||||
latestMuteStates.current!.video.setEnabled?.(true);
|
||||
@@ -182,7 +182,7 @@ export const GroupCallView: FC<Props> = ({
|
||||
PosthogAnalytics.instance.eventCallEnded.cacheStartCall(new Date());
|
||||
// we only have room sessions right now, so call ID is the emprty string - we use the room ID
|
||||
PosthogAnalytics.instance.eventCallStarted.track(
|
||||
rtcSession.room.roomId
|
||||
rtcSession.room.roomId,
|
||||
);
|
||||
|
||||
await Promise.all([
|
||||
@@ -213,7 +213,7 @@ export const GroupCallView: FC<Props> = ({
|
||||
PosthogAnalytics.instance.eventCallEnded.track(
|
||||
rtcSession.room.roomId,
|
||||
rtcSession.memberships.length,
|
||||
sendInstantly
|
||||
sendInstantly,
|
||||
);
|
||||
|
||||
await leaveRTCSession(rtcSession);
|
||||
@@ -237,13 +237,13 @@ export const GroupCallView: FC<Props> = ({
|
||||
history.push("/");
|
||||
}
|
||||
},
|
||||
[rtcSession, isPasswordlessUser, confineToRoom, history]
|
||||
[rtcSession, isPasswordlessUser, confineToRoom, history],
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
if (widget && isJoined) {
|
||||
const onHangup = async (
|
||||
ev: CustomEvent<IWidgetApiRequest>
|
||||
ev: CustomEvent<IWidgetApiRequest>,
|
||||
): Promise<void> => {
|
||||
leaveRTCSession(rtcSession);
|
||||
widget!.api.transport.reply(ev.detail, {});
|
||||
@@ -260,7 +260,7 @@ export const GroupCallView: FC<Props> = ({
|
||||
|
||||
const e2eeConfig = useMemo(
|
||||
() => (e2eeSharedKey ? { sharedKey: e2eeSharedKey } : undefined),
|
||||
[e2eeSharedKey]
|
||||
[e2eeSharedKey],
|
||||
);
|
||||
|
||||
const onReconnect = useCallback(() => {
|
||||
@@ -274,12 +274,12 @@ export const GroupCallView: FC<Props> = ({
|
||||
const [shareModalOpen, setInviteModalOpen] = useState(false);
|
||||
const onDismissInviteModal = useCallback(
|
||||
() => setInviteModalOpen(false),
|
||||
[setInviteModalOpen]
|
||||
[setInviteModalOpen],
|
||||
);
|
||||
|
||||
const onShareClickFn = useCallback(
|
||||
() => setInviteModalOpen(true),
|
||||
[setInviteModalOpen]
|
||||
[setInviteModalOpen],
|
||||
);
|
||||
const onShareClick = joinRule === JoinRule.Public ? onShareClickFn : null;
|
||||
|
||||
@@ -288,7 +288,7 @@ export const GroupCallView: FC<Props> = ({
|
||||
ev.preventDefault();
|
||||
history.push("/");
|
||||
},
|
||||
[history]
|
||||
[history],
|
||||
);
|
||||
|
||||
const { t } = useTranslation();
|
||||
@@ -298,7 +298,7 @@ export const GroupCallView: FC<Props> = ({
|
||||
<ErrorView
|
||||
error={
|
||||
new Error(
|
||||
"No E2EE key provided: please make sure the URL you're using to join this call has been retrieved using the in-app button."
|
||||
"No E2EE key provided: please make sure the URL you're using to join this call has been retrieved using the in-app button.",
|
||||
)
|
||||
}
|
||||
/>
|
||||
@@ -309,7 +309,7 @@ export const GroupCallView: FC<Props> = ({
|
||||
<Heading>Incompatible Browser</Heading>
|
||||
<Text>
|
||||
{t(
|
||||
"Your web browser does not support media end-to-end encryption. Supported Browsers are Chrome, Safari, Firefox >=117"
|
||||
"Your web browser does not support media end-to-end encryption. Supported Browsers are Chrome, Safari, Firefox >=117",
|
||||
)}
|
||||
</Text>
|
||||
<Link href="/" onClick={onHomeClick}>
|
||||
|
||||
@@ -105,7 +105,7 @@ export const ActiveCall: FC<ActiveCallProps> = (props) => {
|
||||
const { livekitRoom, connState } = useLiveKit(
|
||||
props.muteStates,
|
||||
sfuConfig,
|
||||
props.e2eeConfig
|
||||
props.e2eeConfig,
|
||||
);
|
||||
|
||||
if (!livekitRoom) {
|
||||
@@ -172,10 +172,10 @@ export const InCallView: FC<InCallViewProps> = ({
|
||||
[{ source: Track.Source.ScreenShare, withPlaceholder: false }],
|
||||
{
|
||||
room: livekitRoom,
|
||||
}
|
||||
},
|
||||
);
|
||||
const { layout, setLayout } = useVideoGridLayout(
|
||||
screenSharingTracks.length > 0
|
||||
screenSharingTracks.length > 0,
|
||||
);
|
||||
|
||||
const [showConnectionStats] = useShowConnectionStats();
|
||||
@@ -188,11 +188,11 @@ export const InCallView: FC<InCallViewProps> = ({
|
||||
|
||||
const toggleMicrophone = useCallback(
|
||||
() => muteStates.audio.setEnabled?.((e) => !e),
|
||||
[muteStates]
|
||||
[muteStates],
|
||||
);
|
||||
const toggleCamera = useCallback(
|
||||
() => muteStates.video.setEnabled?.((e) => !e),
|
||||
[muteStates]
|
||||
[muteStates],
|
||||
);
|
||||
|
||||
// This function incorrectly assumes that there is a camera and microphone, which is not always the case.
|
||||
@@ -201,7 +201,7 @@ export const InCallView: FC<InCallViewProps> = ({
|
||||
containerRef1,
|
||||
toggleMicrophone,
|
||||
toggleCamera,
|
||||
(muted) => muteStates.audio.setEnabled?.(!muted)
|
||||
(muted) => muteStates.audio.setEnabled?.(!muted),
|
||||
);
|
||||
|
||||
const onLeavePress = useCallback(() => {
|
||||
@@ -213,7 +213,7 @@ export const InCallView: FC<InCallViewProps> = ({
|
||||
layout === "grid"
|
||||
? ElementWidgetActions.TileLayout
|
||||
: ElementWidgetActions.SpotlightLayout,
|
||||
{}
|
||||
{},
|
||||
);
|
||||
}, [layout]);
|
||||
|
||||
@@ -231,14 +231,14 @@ export const InCallView: FC<InCallViewProps> = ({
|
||||
widget.lazyActions.on(ElementWidgetActions.TileLayout, onTileLayout);
|
||||
widget.lazyActions.on(
|
||||
ElementWidgetActions.SpotlightLayout,
|
||||
onSpotlightLayout
|
||||
onSpotlightLayout,
|
||||
);
|
||||
|
||||
return () => {
|
||||
widget!.lazyActions.off(ElementWidgetActions.TileLayout, onTileLayout);
|
||||
widget!.lazyActions.off(
|
||||
ElementWidgetActions.SpotlightLayout,
|
||||
onSpotlightLayout
|
||||
onSpotlightLayout,
|
||||
);
|
||||
};
|
||||
}
|
||||
@@ -261,7 +261,7 @@ export const InCallView: FC<InCallViewProps> = ({
|
||||
(noControls
|
||||
? items.find((item) => item.isSpeaker) ?? items.at(0) ?? null
|
||||
: null),
|
||||
[fullscreenItem, noControls, items]
|
||||
[fullscreenItem, noControls, items],
|
||||
);
|
||||
|
||||
const Grid =
|
||||
@@ -320,18 +320,18 @@ export const InCallView: FC<InCallViewProps> = ({
|
||||
};
|
||||
|
||||
const rageshakeRequestModalProps = useRageshakeRequestModal(
|
||||
rtcSession.room.roomId
|
||||
rtcSession.room.roomId,
|
||||
);
|
||||
|
||||
const [settingsModalOpen, setSettingsModalOpen] = useState(false);
|
||||
|
||||
const openSettings = useCallback(
|
||||
() => setSettingsModalOpen(true),
|
||||
[setSettingsModalOpen]
|
||||
[setSettingsModalOpen],
|
||||
);
|
||||
const closeSettings = useCallback(
|
||||
() => setSettingsModalOpen(false),
|
||||
[setSettingsModalOpen]
|
||||
[setSettingsModalOpen],
|
||||
);
|
||||
|
||||
const toggleScreensharing = useCallback(async () => {
|
||||
@@ -365,7 +365,7 @@ export const InCallView: FC<InCallViewProps> = ({
|
||||
onPress={toggleCamera}
|
||||
disabled={muteStates.video.setEnabled === null}
|
||||
data-testid="incall_videomute"
|
||||
/>
|
||||
/>,
|
||||
);
|
||||
|
||||
if (!reducedControls) {
|
||||
@@ -376,14 +376,18 @@ export const InCallView: FC<InCallViewProps> = ({
|
||||
enabled={isScreenShareEnabled}
|
||||
onPress={toggleScreensharing}
|
||||
data-testid="incall_screenshare"
|
||||
/>
|
||||
/>,
|
||||
);
|
||||
}
|
||||
buttons.push(<SettingsButton key="4" onPress={openSettings} />);
|
||||
}
|
||||
|
||||
buttons.push(
|
||||
<HangupButton key="6" onPress={onLeavePress} data-testid="incall_leave" />
|
||||
<HangupButton
|
||||
key="6"
|
||||
onPress={onLeavePress}
|
||||
data-testid="incall_leave"
|
||||
/>,
|
||||
);
|
||||
footer = (
|
||||
<div className={styles.footer}>
|
||||
@@ -447,7 +451,7 @@ export const InCallView: FC<InCallViewProps> = ({
|
||||
|
||||
function findMatrixMember(
|
||||
room: MatrixRoom,
|
||||
id: string
|
||||
id: string,
|
||||
): RoomMember | undefined {
|
||||
if (!id) return undefined;
|
||||
|
||||
@@ -455,7 +459,7 @@ function findMatrixMember(
|
||||
// must be at least 3 parts because we know the first part is a userId which must necessarily contain a colon
|
||||
if (parts.length < 3) {
|
||||
logger.warn(
|
||||
"Livekit participants ID doesn't look like a userId:deviceId combination"
|
||||
"Livekit participants ID doesn't look like a userId:deviceId combination",
|
||||
);
|
||||
return undefined;
|
||||
}
|
||||
@@ -469,7 +473,7 @@ function findMatrixMember(
|
||||
function useParticipantTiles(
|
||||
livekitRoom: Room,
|
||||
matrixRoom: MatrixRoom,
|
||||
connState: ECConnectionState
|
||||
connState: ECConnectionState,
|
||||
): TileDescriptor<ItemData>[] {
|
||||
const previousTiles = useRef<TileDescriptor<ItemData>[]>([]);
|
||||
|
||||
@@ -498,7 +502,7 @@ function useParticipantTiles(
|
||||
// connected, this is fine and we'll be in "all ghosts" mode.
|
||||
if (id !== "" && member === undefined) {
|
||||
logger.warn(
|
||||
`Ruh, roh! No matrix member found for SFU participant '${id}': creating g-g-g-ghost!`
|
||||
`Ruh, roh! No matrix member found for SFU participant '${id}': creating g-g-g-ghost!`,
|
||||
);
|
||||
}
|
||||
allGhosts &&= member === undefined;
|
||||
@@ -542,11 +546,11 @@ function useParticipantTiles(
|
||||
return screenShareTile
|
||||
? [userMediaTile, screenShareTile]
|
||||
: [userMediaTile];
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
PosthogAnalytics.instance.eventCallEnded.cacheParticipantCountChanged(
|
||||
tiles.length
|
||||
tiles.length,
|
||||
);
|
||||
|
||||
// If every item is a ghost, that probably means we're still connecting and
|
||||
|
||||
@@ -40,7 +40,7 @@ export const InviteModal: FC<Props> = ({ room, open, onDismiss }) => {
|
||||
const url = useMemo(
|
||||
() =>
|
||||
getAbsoluteRoomUrl(room.roomId, room.name, roomSharedKey ?? undefined),
|
||||
[room, roomSharedKey]
|
||||
[room, roomSharedKey],
|
||||
);
|
||||
const [, setCopied] = useClipboard(url);
|
||||
const [toastOpen, setToastOpen] = useState(false);
|
||||
@@ -53,7 +53,7 @@ export const InviteModal: FC<Props> = ({ room, open, onDismiss }) => {
|
||||
onDismiss();
|
||||
setToastOpen(true);
|
||||
},
|
||||
[setCopied, onDismiss]
|
||||
[setCopied, onDismiss],
|
||||
);
|
||||
|
||||
return (
|
||||
|
||||
@@ -36,7 +36,7 @@ export const LayoutToggle: FC<Props> = ({ layout, setLayout, className }) => {
|
||||
|
||||
const onChange = useCallback(
|
||||
(e: ChangeEvent<HTMLInputElement>) => setLayout(e.target.value as Layout),
|
||||
[setLayout]
|
||||
[setLayout],
|
||||
);
|
||||
|
||||
const spotlightId = useId();
|
||||
|
||||
@@ -63,22 +63,22 @@ export const LobbyView: FC<Props> = ({
|
||||
|
||||
const onAudioPress = useCallback(
|
||||
() => muteStates.audio.setEnabled?.((e) => !e),
|
||||
[muteStates]
|
||||
[muteStates],
|
||||
);
|
||||
const onVideoPress = useCallback(
|
||||
() => muteStates.video.setEnabled?.((e) => !e),
|
||||
[muteStates]
|
||||
[muteStates],
|
||||
);
|
||||
|
||||
const [settingsModalOpen, setSettingsModalOpen] = useState(false);
|
||||
|
||||
const openSettings = useCallback(
|
||||
() => setSettingsModalOpen(true),
|
||||
[setSettingsModalOpen]
|
||||
[setSettingsModalOpen],
|
||||
);
|
||||
const closeSettings = useCallback(
|
||||
() => setSettingsModalOpen(false),
|
||||
[setSettingsModalOpen]
|
||||
[setSettingsModalOpen],
|
||||
);
|
||||
|
||||
const history = useHistory();
|
||||
|
||||
@@ -49,18 +49,18 @@ export interface MuteStates {
|
||||
|
||||
function useMuteState(
|
||||
device: MediaDevice,
|
||||
enabledByDefault: () => boolean
|
||||
enabledByDefault: () => boolean,
|
||||
): MuteState {
|
||||
const [enabled, setEnabled] = useReactiveState<boolean>(
|
||||
(prev) => device.available.length > 0 && (prev ?? enabledByDefault()),
|
||||
[device]
|
||||
[device],
|
||||
);
|
||||
return useMemo(
|
||||
() =>
|
||||
device.available.length === 0
|
||||
? deviceUnavailable
|
||||
: { enabled, setEnabled },
|
||||
[device, enabled, setEnabled]
|
||||
[device, enabled, setEnabled],
|
||||
);
|
||||
}
|
||||
|
||||
@@ -69,7 +69,7 @@ export function useMuteStates(participantCount: number): MuteStates {
|
||||
|
||||
const audio = useMuteState(
|
||||
devices.audioInput,
|
||||
() => participantCount <= MUTE_PARTICIPANT_COUNT
|
||||
() => participantCount <= MUTE_PARTICIPANT_COUNT,
|
||||
);
|
||||
const video = useMuteState(devices.videoInput, () => true);
|
||||
|
||||
|
||||
@@ -47,7 +47,7 @@ export const RageshakeRequestModal: FC<Props> = ({
|
||||
<Modal title={t("Debug log request")} open={open} onDismiss={onDismiss}>
|
||||
<Body>
|
||||
{t(
|
||||
"Another user on this call is having an issue. In order to better diagnose these issues we'd like to collect a debug log."
|
||||
"Another user on this call is having an issue. In order to better diagnose these issues we'd like to collect a debug log.",
|
||||
)}
|
||||
</Body>
|
||||
<FieldRow>
|
||||
|
||||
@@ -52,7 +52,7 @@ export const RoomAuthView: FC = () => {
|
||||
setError(error);
|
||||
});
|
||||
},
|
||||
[registerPasswordlessUser]
|
||||
[registerPasswordlessUser],
|
||||
);
|
||||
|
||||
const { t } = useTranslation();
|
||||
|
||||
@@ -81,7 +81,7 @@ export const RoomPage: FC = () => {
|
||||
hideHeader={hideHeader}
|
||||
/>
|
||||
),
|
||||
[client, passwordlessUser, confineToRoom, preload, hideHeader]
|
||||
[client, passwordlessUser, confineToRoom, preload, hideHeader],
|
||||
);
|
||||
|
||||
let content: ReactNode;
|
||||
|
||||
@@ -82,14 +82,14 @@ export const VideoPreview: FC<Props> = ({
|
||||
},
|
||||
(error) => {
|
||||
logger.error("Error while creating preview Tracks:", error);
|
||||
}
|
||||
},
|
||||
);
|
||||
const videoTrack = useMemo(
|
||||
() =>
|
||||
tracks?.find((t) => t.kind === Track.Kind.Video) as
|
||||
| LocalVideoTrack
|
||||
| undefined,
|
||||
[tracks]
|
||||
[tracks],
|
||||
);
|
||||
|
||||
const videoEl = useRef<HTMLVideoElement | null>(null);
|
||||
|
||||
@@ -24,7 +24,7 @@ import { deepCompare } from "matrix-js-sdk/src/utils";
|
||||
import { LivekitFocus } from "../livekit/LivekitFocus";
|
||||
|
||||
function getActiveFocus(
|
||||
rtcSession: MatrixRTCSession
|
||||
rtcSession: MatrixRTCSession,
|
||||
): LivekitFocus | undefined {
|
||||
const oldestMembership = rtcSession.getOldestMembership();
|
||||
return oldestMembership?.getActiveFoci()[0] as LivekitFocus;
|
||||
@@ -36,10 +36,10 @@ function getActiveFocus(
|
||||
* and the same focus.
|
||||
*/
|
||||
export function useActiveFocus(
|
||||
rtcSession: MatrixRTCSession
|
||||
rtcSession: MatrixRTCSession,
|
||||
): LivekitFocus | undefined {
|
||||
const [activeFocus, setActiveFocus] = useState(() =>
|
||||
getActiveFocus(rtcSession)
|
||||
getActiveFocus(rtcSession),
|
||||
);
|
||||
|
||||
const onMembershipsChanged = useCallback(() => {
|
||||
@@ -53,13 +53,13 @@ export function useActiveFocus(
|
||||
useEffect(() => {
|
||||
rtcSession.on(
|
||||
MatrixRTCSessionEvent.MembershipsChanged,
|
||||
onMembershipsChanged
|
||||
onMembershipsChanged,
|
||||
);
|
||||
|
||||
return () => {
|
||||
rtcSession.off(
|
||||
MatrixRTCSessionEvent.MembershipsChanged,
|
||||
onMembershipsChanged
|
||||
onMembershipsChanged,
|
||||
);
|
||||
};
|
||||
});
|
||||
|
||||
@@ -66,7 +66,7 @@ export function useFullscreen<T>(items: TileDescriptor<T>[]): {
|
||||
prevItem == null
|
||||
? null
|
||||
: items.find((i) => i.id === prevItem.id) ?? null,
|
||||
[items]
|
||||
[items],
|
||||
);
|
||||
|
||||
const latestItems = useRef<TileDescriptor<T>[]>(items);
|
||||
@@ -80,15 +80,15 @@ export function useFullscreen<T>(items: TileDescriptor<T>[]): {
|
||||
setFullscreenItem(
|
||||
latestFullscreenItem.current === null
|
||||
? latestItems.current.find((i) => i.id === itemId) ?? null
|
||||
: null
|
||||
: null,
|
||||
);
|
||||
},
|
||||
[setFullscreenItem]
|
||||
[setFullscreenItem],
|
||||
);
|
||||
|
||||
const exitFullscreenCallback = useCallback(
|
||||
() => setFullscreenItem(null),
|
||||
[setFullscreenItem]
|
||||
[setFullscreenItem],
|
||||
);
|
||||
|
||||
useLayoutEffect(() => {
|
||||
@@ -103,7 +103,7 @@ export function useFullscreen<T>(items: TileDescriptor<T>[]): {
|
||||
useFullscreenChange(
|
||||
useCallback(() => {
|
||||
if (!isFullscreen()) setFullscreenItem(null);
|
||||
}, [setFullscreenItem])
|
||||
}, [setFullscreenItem]),
|
||||
);
|
||||
|
||||
return {
|
||||
|
||||
@@ -23,6 +23,6 @@ import { useRoomState } from "./useRoomState";
|
||||
export function useJoinRule(room: Room): JoinRule {
|
||||
return useRoomState(
|
||||
room,
|
||||
useCallback((state) => state.getJoinRule(), [])
|
||||
useCallback((state) => state.getJoinRule(), []),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -52,7 +52,7 @@ export interface GroupCallLoadState {
|
||||
export const useLoadGroupCall = (
|
||||
client: MatrixClient,
|
||||
roomIdOrAlias: string,
|
||||
viaServers: string[]
|
||||
viaServers: string[],
|
||||
): GroupCallStatus => {
|
||||
const { t } = useTranslation();
|
||||
const [state, setState] = useState<GroupCallStatus>({ kind: "loading" });
|
||||
@@ -70,7 +70,7 @@ export const useLoadGroupCall = (
|
||||
// join anyway but the js-sdk recreates the room if you pass the alias for a
|
||||
// room you're already joined to (which it probably ought not to).
|
||||
const lookupResult = await client.getRoomIdForAlias(
|
||||
roomIdOrAlias.toLowerCase()
|
||||
roomIdOrAlias.toLowerCase(),
|
||||
);
|
||||
logger.info(`${roomIdOrAlias} resolved to ${lookupResult.room_id}`);
|
||||
room = client.getRoom(lookupResult.room_id);
|
||||
@@ -81,7 +81,7 @@ export const useLoadGroupCall = (
|
||||
});
|
||||
} else {
|
||||
logger.info(
|
||||
`Already in room ${lookupResult.room_id}, not rejoining.`
|
||||
`Already in room ${lookupResult.room_id}, not rejoining.`,
|
||||
);
|
||||
}
|
||||
} else {
|
||||
@@ -92,7 +92,7 @@ export const useLoadGroupCall = (
|
||||
}
|
||||
|
||||
logger.info(
|
||||
`Joined ${roomIdOrAlias}, waiting room to be ready for group calls`
|
||||
`Joined ${roomIdOrAlias}, waiting room to be ready for group calls`,
|
||||
);
|
||||
await client.waitUntilRoomReadyForGroupCalls(room.roomId);
|
||||
logger.info(`${roomIdOrAlias}, is ready for group calls`);
|
||||
@@ -110,7 +110,7 @@ export const useLoadGroupCall = (
|
||||
const waitForClientSyncing = async (): Promise<void> => {
|
||||
if (client.getSyncState() !== SyncState.Syncing) {
|
||||
logger.debug(
|
||||
"useLoadGroupCall: waiting for client to start syncing..."
|
||||
"useLoadGroupCall: waiting for client to start syncing...",
|
||||
);
|
||||
await new Promise<void>((resolve) => {
|
||||
const onSync = (): void => {
|
||||
|
||||
@@ -22,6 +22,6 @@ import { useRoomState } from "./useRoomState";
|
||||
export function useRoomAvatar(room: Room): string | null {
|
||||
return useRoomState(
|
||||
room,
|
||||
useCallback(() => room.getMxcAvatarUrl(), [room])
|
||||
useCallback(() => room.getMxcAvatarUrl(), [room]),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -31,7 +31,7 @@ export const useRoomState = <T>(room: Room, f: (state: RoomState) => T): T => {
|
||||
useTypedEventEmitter(
|
||||
room,
|
||||
RoomStateEvent.Update,
|
||||
useCallback(() => setNumUpdates((n) => n + 1), [setNumUpdates])
|
||||
useCallback(() => setNumUpdates((n) => n + 1), [setNumUpdates]),
|
||||
);
|
||||
// We want any change to the update counter to trigger an update here
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
|
||||
@@ -48,7 +48,7 @@ export function enterRTCSession(rtcSession: MatrixRTCSession): void {
|
||||
}
|
||||
|
||||
export async function leaveRTCSession(
|
||||
rtcSession: MatrixRTCSession
|
||||
rtcSession: MatrixRTCSession,
|
||||
): Promise<void> {
|
||||
//groupCallOTelMembership?.onLeaveCall();
|
||||
await rtcSession.leaveRoomSession();
|
||||
|
||||
@@ -57,7 +57,7 @@ export const FeedbackSettingsTab: FC<Props> = ({ roomId }) => {
|
||||
sendRageshakeRequest(roomId, rageshakeRequestId);
|
||||
}
|
||||
},
|
||||
[submitRageshake, roomId, sendRageshakeRequest]
|
||||
[submitRageshake, roomId, sendRageshakeRequest],
|
||||
);
|
||||
|
||||
return (
|
||||
@@ -65,7 +65,7 @@ export const FeedbackSettingsTab: FC<Props> = ({ roomId }) => {
|
||||
<h4 className={styles.label}>{t("Submit feedback")}</h4>
|
||||
<Body>
|
||||
{t(
|
||||
"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.",
|
||||
)}
|
||||
</Body>
|
||||
<form onSubmit={onSubmitFeedback}>
|
||||
|
||||
@@ -69,7 +69,7 @@ export const SettingsModal: FC<Props> = (props) => {
|
||||
// Generate a `SelectInput` with a list of devices for a given device kind.
|
||||
const generateDeviceSelection = (
|
||||
devices: MediaDevice,
|
||||
caption: string
|
||||
caption: string,
|
||||
): ReactNode => {
|
||||
if (devices.available.length == 0) return null;
|
||||
|
||||
@@ -100,7 +100,7 @@ export const SettingsModal: FC<Props> = (props) => {
|
||||
(tab: Key) => {
|
||||
setSelectedTab(tab.toString());
|
||||
},
|
||||
[setSelectedTab]
|
||||
[setSelectedTab],
|
||||
);
|
||||
|
||||
const optInDescription = (
|
||||
|
||||
@@ -133,7 +133,7 @@ class IndexedDBLogStore {
|
||||
|
||||
public constructor(
|
||||
private indexedDB: IDBFactory,
|
||||
private loggerInstance: ConsoleLogger
|
||||
private loggerInstance: ConsoleLogger,
|
||||
) {
|
||||
this.id = "instance-" + randomString(16);
|
||||
|
||||
@@ -177,7 +177,7 @@ class IndexedDBLogStore {
|
||||
logObjStore.createIndex("id", "id", { unique: false });
|
||||
|
||||
logObjStore.add(
|
||||
this.generateLogEntry(new Date() + " ::: Log database was created.")
|
||||
this.generateLogEntry(new Date() + " ::: Log database was created."),
|
||||
);
|
||||
|
||||
// This records the last time each instance ID generated a log message, such
|
||||
@@ -208,7 +208,7 @@ class IndexedDBLogStore {
|
||||
{
|
||||
leading: false,
|
||||
trailing: true,
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
/**
|
||||
@@ -366,8 +366,8 @@ class IndexedDBLogStore {
|
||||
txn.onerror = (): void => {
|
||||
reject(
|
||||
new Error(
|
||||
"Failed to delete logs for " + `'${id}' : ${txn?.error?.message}`
|
||||
)
|
||||
"Failed to delete logs for " + `'${id}' : ${txn?.error?.message}`,
|
||||
),
|
||||
);
|
||||
};
|
||||
// delete last modified entries
|
||||
@@ -410,7 +410,7 @@ class IndexedDBLogStore {
|
||||
},
|
||||
(err) => {
|
||||
logger.error(err);
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
return logs;
|
||||
@@ -445,7 +445,7 @@ class IndexedDBLogStore {
|
||||
function selectQuery<T>(
|
||||
store: IDBObjectStore,
|
||||
keyRange: IDBKeyRange | undefined,
|
||||
resultMapper: (cursor: IDBCursorWithValue) => T
|
||||
resultMapper: (cursor: IDBCursorWithValue) => T,
|
||||
): Promise<T[]> {
|
||||
const query = store.openCursor(keyRange);
|
||||
return new Promise((resolve, reject) => {
|
||||
@@ -510,7 +510,7 @@ function tryInitStorage(): Promise<void> {
|
||||
if (indexedDB) {
|
||||
global.mx_rage_store = new IndexedDBLogStore(
|
||||
indexedDB,
|
||||
global.mx_rage_logger
|
||||
global.mx_rage_logger,
|
||||
);
|
||||
global.mx_rage_initStoragePromise = global.mx_rage_store.connect();
|
||||
return global.mx_rage_initStoragePromise;
|
||||
@@ -547,7 +547,7 @@ export async function getLogsForReport(): Promise<LogEntry[]> {
|
||||
type StringifyReplacer = (
|
||||
this: unknown,
|
||||
key: string,
|
||||
value: unknown
|
||||
value: unknown,
|
||||
) => unknown;
|
||||
|
||||
// From https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Errors/Cyclic_object_value#circular_references
|
||||
@@ -600,7 +600,7 @@ export function setLogExtension(extension: LogExtensionFunc): void {
|
||||
logger.methodFactory = function (
|
||||
methodName,
|
||||
configLevel,
|
||||
loggerName
|
||||
loggerName,
|
||||
): LoggingMethod {
|
||||
const rawMethod = originalFactory(methodName, configLevel, loggerName);
|
||||
|
||||
|
||||
@@ -95,12 +95,12 @@ export function useSubmitRageshake(): {
|
||||
const body = new FormData();
|
||||
body.append(
|
||||
"text",
|
||||
description ?? "User did not supply any additional text."
|
||||
description ?? "User did not supply any additional text.",
|
||||
);
|
||||
body.append("app", "matrix-video-chat");
|
||||
body.append(
|
||||
"version",
|
||||
(import.meta.env.VITE_APP_VERSION as string) || "dev"
|
||||
(import.meta.env.VITE_APP_VERSION as string) || "dev",
|
||||
);
|
||||
body.append("user_agent", userAgent);
|
||||
body.append("installed_pwa", "false");
|
||||
@@ -132,22 +132,22 @@ export function useSubmitRageshake(): {
|
||||
|
||||
body.append(
|
||||
"cross_signing_ready",
|
||||
String(await client.isCrossSigningReady())
|
||||
String(await client.isCrossSigningReady()),
|
||||
);
|
||||
body.append(
|
||||
"cross_signing_supported_by_hs",
|
||||
String(
|
||||
await client.doesServerSupportUnstableFeature(
|
||||
"org.matrix.e2e_cross_signing"
|
||||
)
|
||||
)
|
||||
"org.matrix.e2e_cross_signing",
|
||||
),
|
||||
),
|
||||
);
|
||||
body.append("cross_signing_key", crossSigning.getId()!);
|
||||
body.append(
|
||||
"cross_signing_privkey_in_secret_storage",
|
||||
String(
|
||||
!!(await crossSigning.isStoredInSecretStorage(secretStorage))
|
||||
)
|
||||
!!(await crossSigning.isStoredInSecretStorage(secretStorage)),
|
||||
),
|
||||
);
|
||||
|
||||
const pkCache = client.getCrossSigningCacheCallbacks();
|
||||
@@ -157,8 +157,8 @@ export function useSubmitRageshake(): {
|
||||
!!(
|
||||
pkCache?.getCrossSigningKeyCache &&
|
||||
(await pkCache.getCrossSigningKeyCache("master"))
|
||||
)
|
||||
)
|
||||
),
|
||||
),
|
||||
);
|
||||
body.append(
|
||||
"cross_signing_self_signing_privkey_cached",
|
||||
@@ -166,8 +166,8 @@ export function useSubmitRageshake(): {
|
||||
!!(
|
||||
pkCache?.getCrossSigningKeyCache &&
|
||||
(await pkCache.getCrossSigningKeyCache("self_signing"))
|
||||
)
|
||||
)
|
||||
),
|
||||
),
|
||||
);
|
||||
body.append(
|
||||
"cross_signing_user_signing_privkey_cached",
|
||||
@@ -175,32 +175,32 @@ export function useSubmitRageshake(): {
|
||||
!!(
|
||||
pkCache?.getCrossSigningKeyCache &&
|
||||
(await pkCache.getCrossSigningKeyCache("user_signing"))
|
||||
)
|
||||
)
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
body.append(
|
||||
"secret_storage_ready",
|
||||
String(await client.isSecretStorageReady())
|
||||
String(await client.isSecretStorageReady()),
|
||||
);
|
||||
body.append(
|
||||
"secret_storage_key_in_account",
|
||||
String(!!(await secretStorage.hasKey()))
|
||||
String(!!(await secretStorage.hasKey())),
|
||||
);
|
||||
|
||||
body.append(
|
||||
"session_backup_key_in_secret_storage",
|
||||
String(!!(await client.isKeyBackupKeyStored()))
|
||||
String(!!(await client.isKeyBackupKeyStored())),
|
||||
);
|
||||
const sessionBackupKeyFromCache =
|
||||
await client.crypto!.getSessionBackupPrivateKey();
|
||||
body.append(
|
||||
"session_backup_key_cached",
|
||||
String(!!sessionBackupKeyFromCache)
|
||||
String(!!sessionBackupKeyFromCache),
|
||||
);
|
||||
body.append(
|
||||
"session_backup_key_well_formed",
|
||||
String(sessionBackupKeyFromCache instanceof Uint8Array)
|
||||
String(sessionBackupKeyFromCache instanceof Uint8Array),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -214,7 +214,7 @@ export function useSubmitRageshake(): {
|
||||
try {
|
||||
body.append(
|
||||
"storageManager_persisted",
|
||||
String(await navigator.storage.persisted())
|
||||
String(await navigator.storage.persisted()),
|
||||
);
|
||||
} catch (e) {}
|
||||
} else if (document.hasStorageAccess) {
|
||||
@@ -222,7 +222,7 @@ export function useSubmitRageshake(): {
|
||||
try {
|
||||
body.append(
|
||||
"storageManager_persisted",
|
||||
String(await document.hasStorageAccess())
|
||||
String(await document.hasStorageAccess()),
|
||||
);
|
||||
} catch (e) {}
|
||||
}
|
||||
@@ -240,7 +240,7 @@ export function useSubmitRageshake(): {
|
||||
Object.keys(estimate.usageDetails).forEach((k) => {
|
||||
body.append(
|
||||
`storageManager_usage_${k}`,
|
||||
String(estimate.usageDetails![k])
|
||||
String(estimate.usageDetails![k]),
|
||||
);
|
||||
});
|
||||
}
|
||||
@@ -257,14 +257,14 @@ export function useSubmitRageshake(): {
|
||||
body.append(
|
||||
"file",
|
||||
gzip(ElementCallOpenTelemetry.instance.rageshakeProcessor!.dump()),
|
||||
"traces.json.gz"
|
||||
"traces.json.gz",
|
||||
);
|
||||
}
|
||||
|
||||
if (opts.rageshakeRequestId) {
|
||||
body.append(
|
||||
"group_call_rageshake_request_id",
|
||||
opts.rageshakeRequestId
|
||||
opts.rageshakeRequestId,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -279,7 +279,7 @@ export function useSubmitRageshake(): {
|
||||
logger.error(error);
|
||||
}
|
||||
},
|
||||
[client, sending]
|
||||
[client, sending],
|
||||
);
|
||||
|
||||
return {
|
||||
@@ -292,7 +292,7 @@ export function useSubmitRageshake(): {
|
||||
|
||||
export function useRageshakeRequest(): (
|
||||
roomId: string,
|
||||
rageshakeRequestId: string
|
||||
rageshakeRequestId: string,
|
||||
) => void {
|
||||
const { client } = useClient();
|
||||
|
||||
@@ -302,14 +302,14 @@ export function useRageshakeRequest(): (
|
||||
request_id: rageshakeRequestId,
|
||||
});
|
||||
},
|
||||
[client]
|
||||
[client],
|
||||
);
|
||||
|
||||
return sendRageshakeRequest;
|
||||
}
|
||||
|
||||
export function useRageshakeRequestModal(
|
||||
roomId: string
|
||||
roomId: string,
|
||||
): ComponentProps<typeof RageshakeRequestModal> {
|
||||
const [open, setOpen] = useState(false);
|
||||
const onDismiss = useCallback(() => setOpen(false), [setOpen]);
|
||||
|
||||
@@ -38,13 +38,13 @@ export const useSetting = <T>(name: string, defaultValue: T): Setting<T> => {
|
||||
|
||||
const value = useMemo(
|
||||
() => (item == null ? defaultValue : JSON.parse(item)),
|
||||
[item, defaultValue]
|
||||
[item, defaultValue],
|
||||
);
|
||||
const setValue = useCallback(
|
||||
(value: T) => {
|
||||
setItem(JSON.stringify(value));
|
||||
},
|
||||
[setItem]
|
||||
[setItem],
|
||||
);
|
||||
|
||||
return [value, setValue];
|
||||
@@ -94,7 +94,7 @@ export const useOptInAnalytics = (): DisableableSetting<boolean | null> => {
|
||||
export const useEnableE2EE = (): DisableableSetting<boolean | null> => {
|
||||
const settingVal = useSetting<boolean | null>(
|
||||
"enable-end-to-end-encryption",
|
||||
true
|
||||
true,
|
||||
);
|
||||
if (isE2EESupported()) return settingVal;
|
||||
|
||||
|
||||
@@ -29,7 +29,7 @@ interface TabContainerProps<T> extends TabListProps<T> {
|
||||
}
|
||||
|
||||
export function TabContainer<T extends object>(
|
||||
props: TabContainerProps<T>
|
||||
props: TabContainerProps<T>,
|
||||
): JSX.Element {
|
||||
const state = useTabListState<T>(props);
|
||||
const ref = useRef<HTMLUListElement>(null);
|
||||
|
||||
@@ -39,7 +39,7 @@ export const Headline = forwardRef<HTMLHeadingElement, TypographyProps>(
|
||||
overflowEllipsis,
|
||||
...rest
|
||||
},
|
||||
ref
|
||||
ref,
|
||||
) => {
|
||||
return createElement(
|
||||
Component,
|
||||
@@ -48,13 +48,13 @@ export const Headline = forwardRef<HTMLHeadingElement, TypographyProps>(
|
||||
className: classNames(
|
||||
styles[fontWeight ?? ""],
|
||||
{ [styles.overflowEllipsis]: overflowEllipsis },
|
||||
className
|
||||
className,
|
||||
),
|
||||
ref,
|
||||
},
|
||||
children
|
||||
children,
|
||||
);
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
export const Title = forwardRef<HTMLHeadingElement, TypographyProps>(
|
||||
@@ -67,7 +67,7 @@ export const Title = forwardRef<HTMLHeadingElement, TypographyProps>(
|
||||
overflowEllipsis,
|
||||
...rest
|
||||
},
|
||||
ref
|
||||
ref,
|
||||
) => {
|
||||
return createElement(
|
||||
Component,
|
||||
@@ -76,13 +76,13 @@ export const Title = forwardRef<HTMLHeadingElement, TypographyProps>(
|
||||
className: classNames(
|
||||
styles[fontWeight ?? ""],
|
||||
{ [styles.overflowEllipsis]: overflowEllipsis },
|
||||
className
|
||||
className,
|
||||
),
|
||||
ref,
|
||||
},
|
||||
children
|
||||
children,
|
||||
);
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
export const Subtitle = forwardRef<HTMLParagraphElement, TypographyProps>(
|
||||
@@ -95,7 +95,7 @@ export const Subtitle = forwardRef<HTMLParagraphElement, TypographyProps>(
|
||||
overflowEllipsis,
|
||||
...rest
|
||||
},
|
||||
ref
|
||||
ref,
|
||||
) => {
|
||||
return createElement(
|
||||
Component,
|
||||
@@ -104,13 +104,13 @@ export const Subtitle = forwardRef<HTMLParagraphElement, TypographyProps>(
|
||||
className: classNames(
|
||||
styles[fontWeight ?? ""],
|
||||
{ [styles.overflowEllipsis]: overflowEllipsis },
|
||||
className
|
||||
className,
|
||||
),
|
||||
ref,
|
||||
},
|
||||
children
|
||||
children,
|
||||
);
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
export const Body = forwardRef<HTMLParagraphElement, TypographyProps>(
|
||||
@@ -123,7 +123,7 @@ export const Body = forwardRef<HTMLParagraphElement, TypographyProps>(
|
||||
overflowEllipsis,
|
||||
...rest
|
||||
},
|
||||
ref
|
||||
ref,
|
||||
) => {
|
||||
return createElement(
|
||||
Component,
|
||||
@@ -132,13 +132,13 @@ export const Body = forwardRef<HTMLParagraphElement, TypographyProps>(
|
||||
className: classNames(
|
||||
styles[fontWeight ?? ""],
|
||||
{ [styles.overflowEllipsis]: overflowEllipsis },
|
||||
className
|
||||
className,
|
||||
),
|
||||
ref,
|
||||
},
|
||||
children
|
||||
children,
|
||||
);
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
export const Caption = forwardRef<HTMLParagraphElement, TypographyProps>(
|
||||
@@ -151,7 +151,7 @@ export const Caption = forwardRef<HTMLParagraphElement, TypographyProps>(
|
||||
overflowEllipsis,
|
||||
...rest
|
||||
},
|
||||
ref
|
||||
ref,
|
||||
) => {
|
||||
return createElement(
|
||||
Component,
|
||||
@@ -161,13 +161,13 @@ export const Caption = forwardRef<HTMLParagraphElement, TypographyProps>(
|
||||
styles.caption,
|
||||
styles[fontWeight ?? ""],
|
||||
{ [styles.overflowEllipsis]: overflowEllipsis },
|
||||
className
|
||||
className,
|
||||
),
|
||||
ref,
|
||||
},
|
||||
children
|
||||
children,
|
||||
);
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
export const Micro = forwardRef<HTMLParagraphElement, TypographyProps>(
|
||||
@@ -180,7 +180,7 @@ export const Micro = forwardRef<HTMLParagraphElement, TypographyProps>(
|
||||
overflowEllipsis,
|
||||
...rest
|
||||
},
|
||||
ref
|
||||
ref,
|
||||
) => {
|
||||
return createElement(
|
||||
Component,
|
||||
@@ -190,13 +190,13 @@ export const Micro = forwardRef<HTMLParagraphElement, TypographyProps>(
|
||||
styles.micro,
|
||||
styles[fontWeight ?? ""],
|
||||
{ [styles.overflowEllipsis]: overflowEllipsis },
|
||||
className
|
||||
className,
|
||||
),
|
||||
ref,
|
||||
},
|
||||
children
|
||||
children,
|
||||
);
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
interface LinkProps extends TypographyProps {
|
||||
@@ -217,7 +217,7 @@ export const Link = forwardRef<HTMLAnchorElement, LinkProps>(
|
||||
overflowEllipsis,
|
||||
...rest
|
||||
},
|
||||
ref
|
||||
ref,
|
||||
) => {
|
||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||
// @ts-ignore
|
||||
@@ -246,11 +246,11 @@ export const Link = forwardRef<HTMLAnchorElement, LinkProps>(
|
||||
styles[color],
|
||||
styles[fontWeight ?? ""],
|
||||
{ [styles.overflowEllipsis]: overflowEllipsis },
|
||||
className
|
||||
className,
|
||||
),
|
||||
ref: ref,
|
||||
},
|
||||
children
|
||||
children,
|
||||
);
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
@@ -34,7 +34,7 @@ export function useCallViewKeyboardShortcuts(
|
||||
focusElement: RefObject<HTMLElement | null>,
|
||||
toggleMicrophoneMuted: () => void,
|
||||
toggleLocalVideoMuted: () => void,
|
||||
setMicrophoneMuted: (muted: boolean) => void
|
||||
setMicrophoneMuted: (muted: boolean) => void,
|
||||
): void {
|
||||
const spacebarHeld = useRef(false);
|
||||
|
||||
@@ -63,8 +63,8 @@ export function useCallViewKeyboardShortcuts(
|
||||
toggleLocalVideoMuted,
|
||||
toggleMicrophoneMuted,
|
||||
setMicrophoneMuted,
|
||||
]
|
||||
)
|
||||
],
|
||||
),
|
||||
);
|
||||
|
||||
useEventTarget(
|
||||
@@ -80,8 +80,8 @@ export function useCallViewKeyboardShortcuts(
|
||||
setMicrophoneMuted(true);
|
||||
}
|
||||
},
|
||||
[focusElement, setMicrophoneMuted]
|
||||
)
|
||||
[focusElement, setMicrophoneMuted],
|
||||
),
|
||||
);
|
||||
|
||||
useEventTarget(
|
||||
@@ -92,6 +92,6 @@ export function useCallViewKeyboardShortcuts(
|
||||
spacebarHeld.current = false;
|
||||
setMicrophoneMuted(true);
|
||||
}
|
||||
}, [setMicrophoneMuted, spacebarHeld])
|
||||
}, [setMicrophoneMuted, spacebarHeld]),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -28,7 +28,7 @@ export function useEventTarget<T extends Event>(
|
||||
target: EventTarget | null | undefined,
|
||||
eventType: string,
|
||||
listener: (event: T) => void,
|
||||
options?: AddEventListenerOptions
|
||||
options?: AddEventListenerOptions,
|
||||
): void {
|
||||
useEffect(() => {
|
||||
if (target) {
|
||||
@@ -37,7 +37,7 @@ export function useEventTarget<T extends Event>(
|
||||
target.removeEventListener(
|
||||
eventType,
|
||||
listener as EventListener,
|
||||
options
|
||||
options,
|
||||
);
|
||||
}
|
||||
}, [target, eventType, listener, options]);
|
||||
@@ -47,11 +47,11 @@ export function useEventTarget<T extends Event>(
|
||||
export function useTypedEventEmitter<
|
||||
Events extends string,
|
||||
Arguments extends ListenerMap<Events>,
|
||||
T extends Events
|
||||
T extends Events,
|
||||
>(
|
||||
emitter: TypedEventEmitter<Events, Arguments>,
|
||||
eventType: T,
|
||||
listener: Listener<Events, Arguments, T>
|
||||
listener: Listener<Events, Arguments, T>,
|
||||
): void {
|
||||
useEffect(() => {
|
||||
emitter.on(eventType, listener);
|
||||
@@ -64,11 +64,11 @@ export function useTypedEventEmitter<
|
||||
// Shortcut for registering a listener on an eventemitter3 EventEmitter (ie. what the LiveKit SDK uses)
|
||||
export function useEventEmitterThree<
|
||||
EventType extends keyof T,
|
||||
T extends EventMap
|
||||
T extends EventMap,
|
||||
>(
|
||||
emitter: EventEmitter<T>,
|
||||
eventType: EventType,
|
||||
listener: T[EventType]
|
||||
listener: T[EventType],
|
||||
): void {
|
||||
useEffect(() => {
|
||||
emitter.on(eventType, listener);
|
||||
|
||||
@@ -24,10 +24,10 @@ export const localStorageBus = new EventEmitter();
|
||||
|
||||
// Like useState, but reads from and persists the value to localStorage
|
||||
export const useLocalStorage = (
|
||||
key: string
|
||||
key: string,
|
||||
): [LocalStorageItem, (value: string) => void] => {
|
||||
const [value, setValue] = useState<LocalStorageItem>(() =>
|
||||
localStorage.getItem(key)
|
||||
localStorage.getItem(key),
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
@@ -45,7 +45,7 @@ export const useLocalStorage = (
|
||||
localStorage.setItem(key, newValue);
|
||||
localStorageBus.emit(key, newValue);
|
||||
},
|
||||
[key, setValue]
|
||||
[key, setValue],
|
||||
),
|
||||
];
|
||||
};
|
||||
|
||||
@@ -22,7 +22,7 @@ import {
|
||||
import { useCallback, useEffect, useState } from "react";
|
||||
|
||||
export function useMatrixRTCSessionJoinState(
|
||||
rtcSession: MatrixRTCSession
|
||||
rtcSession: MatrixRTCSession,
|
||||
): boolean {
|
||||
const [isJoined, setJoined] = useState(rtcSession.isJoined());
|
||||
|
||||
@@ -30,7 +30,7 @@ export function useMatrixRTCSessionJoinState(
|
||||
logger.info(
|
||||
`Session in room ${rtcSession.room.roomId} changed to ${
|
||||
rtcSession.isJoined() ? "joined" : "left"
|
||||
}`
|
||||
}`,
|
||||
);
|
||||
setJoined(rtcSession.isJoined());
|
||||
}, [rtcSession]);
|
||||
@@ -41,7 +41,7 @@ export function useMatrixRTCSessionJoinState(
|
||||
return () => {
|
||||
rtcSession.off(
|
||||
MatrixRTCSessionEvent.JoinStateChanged,
|
||||
onJoinStateChanged
|
||||
onJoinStateChanged,
|
||||
);
|
||||
};
|
||||
}, [rtcSession, onJoinStateChanged]);
|
||||
|
||||
@@ -23,13 +23,13 @@ import {
|
||||
import { useCallback, useEffect, useState } from "react";
|
||||
|
||||
export function useMatrixRTCSessionMemberships(
|
||||
rtcSession: MatrixRTCSession
|
||||
rtcSession: MatrixRTCSession,
|
||||
): CallMembership[] {
|
||||
const [memberships, setMemberships] = useState(rtcSession.memberships);
|
||||
|
||||
const onMembershipsChanged = useCallback(() => {
|
||||
logger.info(
|
||||
`Memberships changed for call in room ${rtcSession.room.roomId} (${rtcSession.memberships.length} members)`
|
||||
`Memberships changed for call in room ${rtcSession.room.roomId} (${rtcSession.memberships.length} members)`,
|
||||
);
|
||||
setMemberships(rtcSession.memberships);
|
||||
}, [rtcSession]);
|
||||
@@ -37,13 +37,13 @@ export function useMatrixRTCSessionMemberships(
|
||||
useEffect(() => {
|
||||
rtcSession.on(
|
||||
MatrixRTCSessionEvent.MembershipsChanged,
|
||||
onMembershipsChanged
|
||||
onMembershipsChanged,
|
||||
);
|
||||
|
||||
return () => {
|
||||
rtcSession.off(
|
||||
MatrixRTCSessionEvent.MembershipsChanged,
|
||||
onMembershipsChanged
|
||||
onMembershipsChanged,
|
||||
);
|
||||
};
|
||||
}, [rtcSession, onMembershipsChanged]);
|
||||
|
||||
@@ -28,7 +28,7 @@ export function useMediaQuery(query: string): boolean {
|
||||
useEventTarget(
|
||||
mediaQuery,
|
||||
"change",
|
||||
useCallback(() => setNumChanges((n) => n + 1), [setNumChanges])
|
||||
useCallback(() => setNumChanges((n) => n + 1), [setNumChanges]),
|
||||
);
|
||||
|
||||
// We want any change to the update counter to trigger an update here
|
||||
|
||||
@@ -35,5 +35,5 @@ export const useMergedRefs = <T>(
|
||||
// Since this isn't an array literal, we can't use the static dependency
|
||||
// checker, but that's okay
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
refs
|
||||
refs,
|
||||
);
|
||||
|
||||
@@ -30,7 +30,7 @@ import {
|
||||
*/
|
||||
export const useReactiveState = <T>(
|
||||
updateFn: (prevState?: T) => T,
|
||||
deps: DependencyList
|
||||
deps: DependencyList,
|
||||
): [T, Dispatch<SetStateAction<T>>] => {
|
||||
const state = useRef<T>();
|
||||
if (state.current === undefined) state.current = updateFn();
|
||||
@@ -61,7 +61,7 @@ export const useReactiveState = <T>(
|
||||
}
|
||||
setNumUpdates((n) => n + 1); // Force an update
|
||||
},
|
||||
[setNumUpdates]
|
||||
[setNumUpdates],
|
||||
),
|
||||
];
|
||||
};
|
||||
|
||||
@@ -78,7 +78,7 @@ export interface SparseGrid {
|
||||
export function getPaths(
|
||||
g: SparseGrid,
|
||||
dest: number,
|
||||
avoid: (cell: number) => boolean = (): boolean => false
|
||||
avoid: (cell: number) => boolean = (): boolean => false,
|
||||
): (number | null)[] {
|
||||
const destRow = row(dest, g);
|
||||
const destColumn = column(dest, g);
|
||||
@@ -145,7 +145,7 @@ function inArea(
|
||||
index: number,
|
||||
start: number,
|
||||
end: number,
|
||||
g: SparseGrid
|
||||
g: SparseGrid,
|
||||
): boolean {
|
||||
const indexColumn = column(index, g);
|
||||
const indexRow = row(index, g);
|
||||
@@ -160,7 +160,7 @@ function inArea(
|
||||
function* cellsInArea(
|
||||
start: number,
|
||||
end: number,
|
||||
g: SparseGrid
|
||||
g: SparseGrid,
|
||||
): Generator<number, void, unknown> {
|
||||
const startColumn = column(start, g);
|
||||
const endColumn = column(end, g);
|
||||
@@ -179,7 +179,7 @@ export function forEachCellInArea<G extends Grid | SparseGrid>(
|
||||
start: number,
|
||||
end: number,
|
||||
g: G,
|
||||
fn: (c: G["cells"][0], i: number) => void
|
||||
fn: (c: G["cells"][0], i: number) => void,
|
||||
): void {
|
||||
for (const i of cellsInArea(start, end, g)) fn(g.cells[i], i);
|
||||
}
|
||||
@@ -188,7 +188,7 @@ function allCellsInArea<G extends Grid | SparseGrid>(
|
||||
start: number,
|
||||
end: number,
|
||||
g: G,
|
||||
fn: (c: G["cells"][0], i: number) => boolean
|
||||
fn: (c: G["cells"][0], i: number) => boolean,
|
||||
): boolean {
|
||||
for (const i of cellsInArea(start, end, g)) {
|
||||
if (!fn(g.cells[i], i)) return false;
|
||||
@@ -204,7 +204,7 @@ function countCellsInArea<G extends Grid | SparseGrid>(
|
||||
start: number,
|
||||
end: number,
|
||||
g: G,
|
||||
predicate: (c: G["cells"][0], i: number) => boolean
|
||||
predicate: (c: G["cells"][0], i: number) => boolean,
|
||||
): number {
|
||||
let count = 0;
|
||||
for (const i of cellsInArea(start, end, g)) {
|
||||
@@ -217,7 +217,7 @@ const areaEnd = (
|
||||
start: number,
|
||||
columns: number,
|
||||
rows: number,
|
||||
g: SparseGrid
|
||||
g: SparseGrid,
|
||||
): number => start + columns - 1 + g.columns * (rows - 1);
|
||||
|
||||
const cloneGrid = <G extends Grid | SparseGrid>(g: G): G => ({
|
||||
@@ -231,7 +231,7 @@ const cloneGrid = <G extends Grid | SparseGrid>(g: G): G => ({
|
||||
*/
|
||||
function getNextGap(
|
||||
g: SparseGrid,
|
||||
ignoreGap: (cell: number) => boolean
|
||||
ignoreGap: (cell: number) => boolean,
|
||||
): number | null {
|
||||
const last1By1Index = findLast1By1Index(g);
|
||||
if (last1By1Index === null) return null;
|
||||
@@ -278,13 +278,13 @@ function moveTileUnchecked(g: SparseGrid, from: number, to: number): void {
|
||||
to,
|
||||
toEnd,
|
||||
g,
|
||||
(_c, i) => (g.cells[i] = movingCells.shift())
|
||||
(_c, i) => (g.cells[i] = movingCells.shift()),
|
||||
);
|
||||
forEachCellInArea(
|
||||
from,
|
||||
fromEnd,
|
||||
g,
|
||||
(_c, i) => (g.cells[i] ??= displacedTiles.shift())
|
||||
(_c, i) => (g.cells[i] ??= displacedTiles.shift()),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -294,7 +294,7 @@ function moveTileUnchecked(g: SparseGrid, from: number, to: number): void {
|
||||
export function moveTile<G extends Grid | SparseGrid>(
|
||||
g: G,
|
||||
from: number,
|
||||
to: number
|
||||
to: number,
|
||||
): G {
|
||||
const tile = g.cells[from]!;
|
||||
|
||||
@@ -333,7 +333,7 @@ function pushTileUp(
|
||||
g: SparseGrid,
|
||||
from: number,
|
||||
rows: number,
|
||||
avoid: (cell: number) => boolean = (): boolean => false
|
||||
avoid: (cell: number) => boolean = (): boolean => false,
|
||||
): number {
|
||||
const tile = g.cells[from]!;
|
||||
|
||||
@@ -347,7 +347,7 @@ function pushTileUp(
|
||||
to,
|
||||
Math.min(from - g.columns + tile.columns - 1, toEnd),
|
||||
g,
|
||||
(c, i) => (c === undefined || is1By1(c)) && !avoid(i)
|
||||
(c, i) => (c === undefined || is1By1(c)) && !avoid(i),
|
||||
);
|
||||
|
||||
if (cellsAboveAreDisplacable) {
|
||||
@@ -376,7 +376,7 @@ function canVacateArea(g: SparseGrid, start: number, end: number): boolean {
|
||||
start,
|
||||
end - newFullRows * g.columns,
|
||||
g,
|
||||
(c) => c === undefined || is1By1(c)
|
||||
(c) => c === undefined || is1By1(c),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -391,7 +391,7 @@ function vacateArea(g: SparseGrid, start: number, end: number): SparseGrid {
|
||||
start,
|
||||
end,
|
||||
g,
|
||||
(c, i) => c !== undefined || i >= g.cells.length
|
||||
(c, i) => c !== undefined || i >= g.cells.length,
|
||||
);
|
||||
const newFullRows = Math.floor(newCellCount / g.columns);
|
||||
const endRow = row(end, g);
|
||||
@@ -452,7 +452,7 @@ function vacateArea(g: SparseGrid, start: number, end: number): SparseGrid {
|
||||
const inputStructure = fillGaps(
|
||||
outputStructure,
|
||||
false,
|
||||
(i) => inArea(i, start, end, g) && g.cells[i] === undefined
|
||||
(i) => inArea(i, start, end, g) && g.cells[i] === undefined,
|
||||
);
|
||||
|
||||
// We exploit the fact that g and inputStructure have the same structure to
|
||||
@@ -464,7 +464,7 @@ function vacateArea(g: SparseGrid, start: number, end: number): SparseGrid {
|
||||
return {
|
||||
columns: g.columns,
|
||||
cells: outputStructure.cells.map((placeholder) =>
|
||||
structureMapping.get(placeholder)
|
||||
structureMapping.get(placeholder),
|
||||
),
|
||||
};
|
||||
}
|
||||
@@ -475,21 +475,21 @@ function vacateArea(g: SparseGrid, start: number, end: number): SparseGrid {
|
||||
export function fillGaps(
|
||||
g: SparseGrid,
|
||||
packLargeTiles?: true,
|
||||
ignoreGap?: () => false
|
||||
ignoreGap?: () => false,
|
||||
): Grid;
|
||||
export function fillGaps(
|
||||
g: SparseGrid,
|
||||
packLargeTiles?: boolean,
|
||||
ignoreGap?: (cell: number) => boolean
|
||||
ignoreGap?: (cell: number) => boolean,
|
||||
): SparseGrid;
|
||||
export function fillGaps(
|
||||
g: SparseGrid,
|
||||
packLargeTiles = true,
|
||||
ignoreGap: (cell: number) => boolean = (): boolean => false
|
||||
ignoreGap: (cell: number) => boolean = (): boolean => false,
|
||||
): SparseGrid {
|
||||
const lastGap = findLastIndex(
|
||||
g.cells,
|
||||
(c, i) => c === undefined && !ignoreGap(i)
|
||||
(c, i) => c === undefined && !ignoreGap(i),
|
||||
);
|
||||
if (lastGap === null) return g; // There are no gaps to fill
|
||||
const lastGapRow = row(lastGap, g);
|
||||
@@ -500,10 +500,10 @@ export function fillGaps(
|
||||
// allowed to pack the large tiles into the rest of the grid as necessary)
|
||||
let idealLength = count(
|
||||
result.cells,
|
||||
(c, i) => c !== undefined || ignoreGap(i)
|
||||
(c, i) => c !== undefined || ignoreGap(i),
|
||||
);
|
||||
const fullRowsRemoved = Math.floor(
|
||||
(g.cells.length - idealLength) / g.columns
|
||||
(g.cells.length - idealLength) / g.columns,
|
||||
);
|
||||
|
||||
// Step 1: Push all large tiles below the last gap upwards, so that they move
|
||||
@@ -620,7 +620,7 @@ function createRows(g: SparseGrid, count: number, atRow: number): SparseGrid {
|
||||
g,
|
||||
(c, i) => {
|
||||
result.cells[i + offset] = c;
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
});
|
||||
@@ -633,7 +633,7 @@ function createRows(g: SparseGrid, count: number, atRow: number): SparseGrid {
|
||||
*/
|
||||
export function addItems(
|
||||
items: TileDescriptor<unknown>[],
|
||||
g: SparseGrid
|
||||
g: SparseGrid,
|
||||
): SparseGrid {
|
||||
let result: SparseGrid = cloneGrid(g);
|
||||
|
||||
@@ -655,7 +655,7 @@ export function addItems(
|
||||
// This item wants to be placed near another; let's put it on a row
|
||||
// directly below the related tile
|
||||
const placeNear = result.cells.findIndex(
|
||||
(c) => c?.item.id === item.placeNear
|
||||
(c) => c?.item.id === item.placeNear,
|
||||
);
|
||||
if (placeNear === -1) {
|
||||
// Can't find the related tile, so let's give up and place it at the end
|
||||
@@ -666,7 +666,7 @@ export function addItems(
|
||||
placeNear,
|
||||
placeNearCell.columns,
|
||||
placeNearCell.rows,
|
||||
result
|
||||
result,
|
||||
);
|
||||
|
||||
result = createRows(result, 1, row(placeNearEnd, result) + 1);
|
||||
@@ -699,7 +699,7 @@ const extraLargeTileDimensions = (g: SparseGrid): [number, number] =>
|
||||
|
||||
export function cycleTileSize<G extends Grid | SparseGrid>(
|
||||
g: G,
|
||||
tile: TileDescriptor<unknown>
|
||||
tile: TileDescriptor<unknown>,
|
||||
): G {
|
||||
const from = g.cells.findIndex((c) => c?.item === tile);
|
||||
if (from === -1) return g; // Tile removed, no change
|
||||
@@ -727,7 +727,7 @@ function findNearestCell<G extends Grid | SparseGrid>(
|
||||
g: G,
|
||||
nearestTo: number,
|
||||
shouldScan: (index: number) => boolean,
|
||||
predicate: (cell: G["cells"][0], index: number) => boolean
|
||||
predicate: (cell: G["cells"][0], index: number) => boolean,
|
||||
): number | null {
|
||||
const scanLocations = new Set([nearestTo]);
|
||||
|
||||
@@ -758,7 +758,7 @@ export function setTileSize<G extends Grid | SparseGrid>(
|
||||
g: G,
|
||||
from: number,
|
||||
toWidth: number,
|
||||
toHeight: number
|
||||
toHeight: number,
|
||||
): G {
|
||||
const fromCell = g.cells[from]!;
|
||||
const fromWidth = fromCell.columns;
|
||||
@@ -771,12 +771,12 @@ export function setTileSize<G extends Grid | SparseGrid>(
|
||||
0,
|
||||
Math.min(
|
||||
g.columns - toWidth,
|
||||
column(from, g) + Math.trunc((fromWidth - toWidth) / 2)
|
||||
)
|
||||
column(from, g) + Math.trunc((fromWidth - toWidth) / 2),
|
||||
),
|
||||
);
|
||||
const toRow = Math.max(
|
||||
0,
|
||||
row(from, g) + Math.trunc((fromHeight - toHeight) / 2)
|
||||
row(from, g) + Math.trunc((fromHeight - toHeight) / 2),
|
||||
);
|
||||
const targetDest = toColumn + toRow * g.columns;
|
||||
|
||||
@@ -788,7 +788,7 @@ export function setTileSize<G extends Grid | SparseGrid>(
|
||||
const placeTile = (
|
||||
to: number,
|
||||
toEnd: number,
|
||||
grid: Grid | SparseGrid
|
||||
grid: Grid | SparseGrid,
|
||||
): void => {
|
||||
forEachCellInArea(to, toEnd, grid, (_c, i) => {
|
||||
grid.cells[i] = {
|
||||
@@ -824,7 +824,7 @@ export function setTileSize<G extends Grid | SparseGrid>(
|
||||
(_c, i) => {
|
||||
const end = areaEnd(i, toWidth, toHeight, g);
|
||||
return end < newGridSize && canVacateArea(gridWithoutTile, i, end);
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
if (to !== null) {
|
||||
@@ -848,7 +848,7 @@ export function setTileSize<G extends Grid | SparseGrid>(
|
||||
(_c, i) => {
|
||||
const end = areaEnd(i, toWidth, toHeight, g);
|
||||
return end < newGridSize && canVacateArea(packedGridWithoutTile, i, end);
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
if (to === null) return g; // There's no space anywhere; give up
|
||||
@@ -949,7 +949,7 @@ function updateTiles(g: Grid, tiles: TileDescriptor<unknown>[]): Grid {
|
||||
|
||||
// Step 2: Add new tiles
|
||||
const existingItemIds = new Set(
|
||||
grid1.cells.filter((c) => c !== undefined).map((c) => c!.item.id)
|
||||
grid1.cells.filter((c) => c !== undefined).map((c) => c!.item.id),
|
||||
);
|
||||
const newItems = tiles.filter((i) => !existingItemIds.has(i.id));
|
||||
const grid2 = addItems(newItems, grid1);
|
||||
@@ -967,7 +967,7 @@ function updateBounds(g: Grid, bounds: RectReadOnly): Grid {
|
||||
|
||||
const Slots: FC<{ s: Grid }> = memo(({ s: g }) => {
|
||||
const areas = new Array<(number | null)[]>(
|
||||
Math.ceil(g.cells.length / g.columns)
|
||||
Math.ceil(g.cells.length / g.columns),
|
||||
);
|
||||
for (let i = 0; i < areas.length; i++)
|
||||
areas[i] = new Array<number | null>(g.columns).fill(null);
|
||||
@@ -981,7 +981,7 @@ const Slots: FC<{ s: Grid }> = memo(({ s: g }) => {
|
||||
i,
|
||||
slotEnd,
|
||||
g,
|
||||
(_c, j) => (areas[row(j, g)][column(j, g)] = slotCount)
|
||||
(_c, j) => (areas[row(j, g)][column(j, g)] = slotCount),
|
||||
);
|
||||
slotCount++;
|
||||
}
|
||||
@@ -993,7 +993,7 @@ const Slots: FC<{ s: Grid }> = memo(({ s: g }) => {
|
||||
(row) =>
|
||||
`'${row
|
||||
.map((slotId) => (slotId === null ? "." : `s${slotId}`))
|
||||
.join(" ")}'`
|
||||
.join(" ")}'`,
|
||||
)
|
||||
.join(" "),
|
||||
gridTemplateColumns: `repeat(${g.columns}, 1fr)`,
|
||||
@@ -1019,7 +1019,7 @@ function positionOnTileToCell(
|
||||
g: SparseGrid,
|
||||
tileOriginIndex: number,
|
||||
xPositionOnTile: number,
|
||||
yPositionOnTile: number
|
||||
yPositionOnTile: number,
|
||||
): number {
|
||||
const tileOrigin = g.cells[tileOriginIndex]!;
|
||||
const columnOnTile = Math.floor(xPositionOnTile * tileOrigin.columns);
|
||||
@@ -1034,7 +1034,7 @@ function dragTile(
|
||||
xPositionOnFrom: number,
|
||||
yPositionOnFrom: number,
|
||||
xPositionOnTo: number,
|
||||
yPositionOnTo: number
|
||||
yPositionOnTo: number,
|
||||
): Grid {
|
||||
const fromOrigin = g.cells.findIndex((c) => c.item === from);
|
||||
const toOrigin = g.cells.findIndex((c) => c.item === to);
|
||||
@@ -1042,13 +1042,13 @@ function dragTile(
|
||||
g,
|
||||
fromOrigin,
|
||||
xPositionOnFrom,
|
||||
yPositionOnFrom
|
||||
yPositionOnFrom,
|
||||
);
|
||||
const toCell = positionOnTileToCell(
|
||||
g,
|
||||
toOrigin,
|
||||
xPositionOnTo,
|
||||
yPositionOnTo
|
||||
yPositionOnTo,
|
||||
);
|
||||
|
||||
return moveTile(g, fromOrigin, fromOrigin + toCell - fromCell);
|
||||
|
||||
@@ -61,7 +61,7 @@ export interface Layout<State> {
|
||||
xPositionOnFrom: number,
|
||||
yPositionOnFrom: number,
|
||||
xPositionOnTo: number,
|
||||
yPositionOnTo: number
|
||||
yPositionOnTo: number,
|
||||
) => State;
|
||||
/**
|
||||
* Toggles the focus of the given tile (if this layout has the concept of
|
||||
@@ -109,7 +109,7 @@ interface UseLayout<State, T> {
|
||||
xPositionOnFrom: number,
|
||||
yPositionOnFrom: number,
|
||||
xPositionOnTo: number,
|
||||
yPositionOnTo: number
|
||||
yPositionOnTo: number,
|
||||
) => void;
|
||||
toggleFocus: ((tile: TileDescriptor<T>) => void) | undefined;
|
||||
slots: ReactNode;
|
||||
@@ -123,7 +123,7 @@ export function useLayout<State, T>(
|
||||
layout: Layout<State>,
|
||||
items: TileDescriptor<T>[],
|
||||
bounds: RectReadOnly,
|
||||
layoutStates: LayoutStatesMap
|
||||
layoutStates: LayoutStatesMap,
|
||||
): UseLayout<State, T> {
|
||||
const prevLayout = useRef<Layout<unknown>>();
|
||||
const prevState = layoutStates.get(layout);
|
||||
@@ -159,7 +159,7 @@ export function useLayout<State, T>(
|
||||
generation: generation.current,
|
||||
canDragTile: useCallback(
|
||||
(tile: TileDescriptor<T>) => layout.canDragTile(state, tile),
|
||||
[layout, state]
|
||||
[layout, state],
|
||||
),
|
||||
dragTile: useCallback(
|
||||
(
|
||||
@@ -168,7 +168,7 @@ export function useLayout<State, T>(
|
||||
xPositionOnFrom: number,
|
||||
yPositionOnFrom: number,
|
||||
xPositionOnTo: number,
|
||||
yPositionOnTo: number
|
||||
yPositionOnTo: number,
|
||||
) =>
|
||||
setState((s) =>
|
||||
layout.dragTile(
|
||||
@@ -178,17 +178,17 @@ export function useLayout<State, T>(
|
||||
xPositionOnFrom,
|
||||
yPositionOnFrom,
|
||||
xPositionOnTo,
|
||||
yPositionOnTo
|
||||
)
|
||||
yPositionOnTo,
|
||||
),
|
||||
),
|
||||
[layout, setState]
|
||||
[layout, setState],
|
||||
),
|
||||
toggleFocus: useMemo(
|
||||
() =>
|
||||
layout.toggleFocus &&
|
||||
((tile: TileDescriptor<T>): void =>
|
||||
setState((s) => layout.toggleFocus!(s, tile))),
|
||||
[layout, setState]
|
||||
[layout, setState],
|
||||
),
|
||||
slots: <layout.Slots s={state} />,
|
||||
};
|
||||
|
||||
@@ -98,13 +98,13 @@ export function NewVideoGrid<T>({
|
||||
useEffect(() => {
|
||||
if (slotsRoot !== null) {
|
||||
setRenderedGeneration(
|
||||
parseInt(slotsRoot.getAttribute("data-generation")!)
|
||||
parseInt(slotsRoot.getAttribute("data-generation")!),
|
||||
);
|
||||
|
||||
const observer = new MutationObserver((mutations) => {
|
||||
if (mutations.some((m) => m.type === "attributes")) {
|
||||
setRenderedGeneration(
|
||||
parseInt(slotsRoot.getAttribute("data-generation")!)
|
||||
parseInt(slotsRoot.getAttribute("data-generation")!),
|
||||
);
|
||||
}
|
||||
});
|
||||
@@ -158,13 +158,13 @@ export function NewVideoGrid<T>({
|
||||
if (renderedGeneration !== generation) return prevTiles ?? [];
|
||||
|
||||
const tileRects = new Map(
|
||||
zip(orderedItems, slotRects) as [TileDescriptor<T>, Rect][]
|
||||
zip(orderedItems, slotRects) as [TileDescriptor<T>, Rect][],
|
||||
);
|
||||
// In order to not break drag gestures, it's critical that we render tiles
|
||||
// in a stable order (that of 'items')
|
||||
return items.map((item) => ({ ...tileRects.get(item)!, item }));
|
||||
},
|
||||
[slotRects, grid, renderedGeneration]
|
||||
[slotRects, grid, renderedGeneration],
|
||||
);
|
||||
|
||||
// Drag state is stored in a ref rather than component state, because we use
|
||||
@@ -200,7 +200,7 @@ export function NewVideoGrid<T>({
|
||||
},
|
||||
leave: { opacity: 0, scale: 0, immediate: disableAnimations },
|
||||
config: { mass: 0.7, tension: 252, friction: 25 },
|
||||
})
|
||||
}),
|
||||
// react-spring's types are bugged and can't infer the spring type
|
||||
) as unknown as [TransitionFn<Tile<T>, TileSpring>, SpringRef<TileSpring>];
|
||||
|
||||
@@ -242,7 +242,7 @@ export function NewVideoGrid<T>({
|
||||
disableAnimations ||
|
||||
((key): boolean =>
|
||||
key === "zIndex" || key === "x" || key === "y"),
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
const overTile = tiles.find(
|
||||
@@ -250,7 +250,7 @@ export function NewVideoGrid<T>({
|
||||
cursorX >= t.x &&
|
||||
cursorX < t.x + t.width &&
|
||||
cursorY >= t.y &&
|
||||
cursorY < t.y + t.height
|
||||
cursorY < t.y + t.height,
|
||||
);
|
||||
|
||||
if (overTile !== undefined)
|
||||
@@ -260,7 +260,7 @@ export function NewVideoGrid<T>({
|
||||
(cursorX - tileX) / tile.width,
|
||||
(cursorY - tileY) / tile.height,
|
||||
(cursorX - overTile.x) / overTile.width,
|
||||
(cursorY - overTile.y) / overTile.height
|
||||
(cursorY - overTile.y) / overTile.height,
|
||||
);
|
||||
};
|
||||
|
||||
@@ -287,7 +287,7 @@ export function NewVideoGrid<T>({
|
||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||
// @ts-ignore
|
||||
last,
|
||||
}: Parameters<Handler<"drag", EventTypes["drag"]>>[0]
|
||||
}: Parameters<Handler<"drag", EventTypes["drag"]>>[0],
|
||||
): void => {
|
||||
if (tap) {
|
||||
const now = Date.now();
|
||||
@@ -303,7 +303,7 @@ export function NewVideoGrid<T>({
|
||||
}
|
||||
} else {
|
||||
const tileController = springRef.current.find(
|
||||
(c) => (c.item as Tile<T>).item.id === tileId
|
||||
(c) => (c.item as Tile<T>).item.id === tileId,
|
||||
)!;
|
||||
|
||||
if (canDragTile((tileController.item as Tile<T>).item)) {
|
||||
@@ -347,7 +347,7 @@ export function NewVideoGrid<T>({
|
||||
animateDraggedTile(false);
|
||||
}
|
||||
},
|
||||
{ target: gridRef2 }
|
||||
{ target: gridRef2 },
|
||||
);
|
||||
|
||||
// Render nothing if the grid has yet to be generated
|
||||
|
||||
@@ -25,7 +25,7 @@ interface Props<T> {
|
||||
onDragRef: RefObject<
|
||||
(
|
||||
tileId: string,
|
||||
state: Parameters<Handler<"drag", EventTypes["drag"]>>[0]
|
||||
state: Parameters<Handler<"drag", EventTypes["drag"]>>[0],
|
||||
) => void
|
||||
>;
|
||||
targetWidth: number;
|
||||
@@ -87,7 +87,7 @@ export const TileWrapper = memo(
|
||||
height,
|
||||
boxShadow: to(
|
||||
[shadow, shadowSpread],
|
||||
(s, ss) => `rgba(0, 0, 0, 0.5) 0px ${s}px ${2 * s}px ${ss}px`
|
||||
(s, ss) => `rgba(0, 0, 0, 0.5) 0px ${s}px ${2 * s}px ${ss}px`,
|
||||
),
|
||||
},
|
||||
targetWidth,
|
||||
@@ -96,7 +96,7 @@ export const TileWrapper = memo(
|
||||
})}
|
||||
</>
|
||||
);
|
||||
}
|
||||
},
|
||||
// We pretend this component is a simple function rather than a
|
||||
// NamedExoticComponent, because that's the only way we can fit in a type
|
||||
// parameter
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user