Conform more code to strict null checking (#10169)
* Conform more code to strict null checking * delint * Iterate * delint * Fix bad test
This commit is contained in:
parent
5123d7e641
commit
e8b92b308b
85 changed files with 283 additions and 287 deletions
|
@ -68,7 +68,7 @@ interface IState {
|
||||||
export default class LeftPanel extends React.Component<IProps, IState> {
|
export default class LeftPanel extends React.Component<IProps, IState> {
|
||||||
private listContainerRef = createRef<HTMLDivElement>();
|
private listContainerRef = createRef<HTMLDivElement>();
|
||||||
private roomListRef = createRef<RoomList>();
|
private roomListRef = createRef<RoomList>();
|
||||||
private focusedElement: Element = null;
|
private focusedElement: Element | null = null;
|
||||||
private isDoingStickyHeaders = false;
|
private isDoingStickyHeaders = false;
|
||||||
|
|
||||||
public constructor(props: IProps) {
|
public constructor(props: IProps) {
|
||||||
|
|
|
@ -41,7 +41,7 @@ const KEY_FILE_MAX_SIZE = 128;
|
||||||
const VALIDATION_THROTTLE_MS = 200;
|
const VALIDATION_THROTTLE_MS = 200;
|
||||||
|
|
||||||
interface IProps extends IDialogProps {
|
interface IProps extends IDialogProps {
|
||||||
keyInfo: ISecretStorageKeyInfo;
|
keyInfo?: ISecretStorageKeyInfo;
|
||||||
checkPrivateKey: (k: { passphrase?: string; recoveryKey?: string }) => boolean;
|
checkPrivateKey: (k: { passphrase?: string; recoveryKey?: string }) => boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -137,7 +137,7 @@ export default class AccessSecretStorageDialog extends React.PureComponent<IProp
|
||||||
};
|
};
|
||||||
|
|
||||||
private onRecoveryKeyFileChange = async (ev: ChangeEvent<HTMLInputElement>): Promise<void> => {
|
private onRecoveryKeyFileChange = async (ev: ChangeEvent<HTMLInputElement>): Promise<void> => {
|
||||||
if (ev.target.files.length === 0) return;
|
if (!ev.target.files?.length) return;
|
||||||
|
|
||||||
const f = ev.target.files[0];
|
const f = ev.target.files[0];
|
||||||
|
|
||||||
|
@ -170,7 +170,7 @@ export default class AccessSecretStorageDialog extends React.PureComponent<IProp
|
||||||
};
|
};
|
||||||
|
|
||||||
private onRecoveryKeyFileUploadClick = (): void => {
|
private onRecoveryKeyFileUploadClick = (): void => {
|
||||||
this.fileUpload.current.click();
|
this.fileUpload.current?.click();
|
||||||
};
|
};
|
||||||
|
|
||||||
private onPassPhraseNext = async (ev: FormEvent<HTMLFormElement> | React.MouseEvent): Promise<void> => {
|
private onPassPhraseNext = async (ev: FormEvent<HTMLFormElement> | React.MouseEvent): Promise<void> => {
|
||||||
|
@ -269,15 +269,11 @@ export default class AccessSecretStorageDialog extends React.PureComponent<IProp
|
||||||
}
|
}
|
||||||
|
|
||||||
public render(): React.ReactNode {
|
public render(): React.ReactNode {
|
||||||
const hasPassphrase =
|
const hasPassphrase = this.props.keyInfo?.passphrase?.salt && this.props.keyInfo?.passphrase?.iterations;
|
||||||
this.props.keyInfo &&
|
|
||||||
this.props.keyInfo.passphrase &&
|
|
||||||
this.props.keyInfo.passphrase.salt &&
|
|
||||||
this.props.keyInfo.passphrase.iterations;
|
|
||||||
|
|
||||||
const resetButton = (
|
const resetButton = (
|
||||||
<div className="mx_AccessSecretStorageDialog_reset">
|
<div className="mx_AccessSecretStorageDialog_reset">
|
||||||
{_t("Forgotten or lost all recovery methods? <a>Reset all</a>", null, {
|
{_t("Forgotten or lost all recovery methods? <a>Reset all</a>", undefined, {
|
||||||
a: (sub) => (
|
a: (sub) => (
|
||||||
<AccessibleButton
|
<AccessibleButton
|
||||||
kind="link_inline"
|
kind="link_inline"
|
||||||
|
@ -405,7 +401,7 @@ export default class AccessSecretStorageDialog extends React.PureComponent<IProp
|
||||||
value={this.state.recoveryKey}
|
value={this.state.recoveryKey}
|
||||||
onChange={this.onRecoveryKeyChange}
|
onChange={this.onRecoveryKeyChange}
|
||||||
autoFocus={true}
|
autoFocus={true}
|
||||||
forceValidity={this.state.recoveryKeyCorrect}
|
forceValidity={this.state.recoveryKeyCorrect ?? undefined}
|
||||||
autoComplete="off"
|
autoComplete="off"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -112,8 +112,8 @@ export interface INativeOnChangeInputProps extends IProps, InputHTMLAttributes<H
|
||||||
type PropShapes = IInputProps | ISelectProps | ITextareaProps | INativeOnChangeInputProps;
|
type PropShapes = IInputProps | ISelectProps | ITextareaProps | INativeOnChangeInputProps;
|
||||||
|
|
||||||
interface IState {
|
interface IState {
|
||||||
valid: boolean;
|
valid?: boolean;
|
||||||
feedback: React.ReactNode;
|
feedback?: React.ReactNode;
|
||||||
feedbackVisible: boolean;
|
feedbackVisible: boolean;
|
||||||
focused: boolean;
|
focused: boolean;
|
||||||
}
|
}
|
||||||
|
@ -148,8 +148,6 @@ export default class Field extends React.PureComponent<PropShapes, IState> {
|
||||||
public constructor(props: PropShapes) {
|
public constructor(props: PropShapes) {
|
||||||
super(props);
|
super(props);
|
||||||
this.state = {
|
this.state = {
|
||||||
valid: undefined,
|
|
||||||
feedback: undefined,
|
|
||||||
feedbackVisible: false,
|
feedbackVisible: false,
|
||||||
focused: false,
|
focused: false,
|
||||||
};
|
};
|
||||||
|
@ -199,7 +197,7 @@ export default class Field extends React.PureComponent<PropShapes, IState> {
|
||||||
this.props.onBlur?.(ev);
|
this.props.onBlur?.(ev);
|
||||||
};
|
};
|
||||||
|
|
||||||
public async validate({ focused, allowEmpty = true }: IValidateOpts): Promise<boolean> {
|
public async validate({ focused, allowEmpty = true }: IValidateOpts): Promise<boolean | undefined> {
|
||||||
if (!this.props.onValidate) {
|
if (!this.props.onValidate) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -268,11 +266,11 @@ export default class Field extends React.PureComponent<PropShapes, IState> {
|
||||||
|
|
||||||
const fieldInput = React.createElement(this.props.element, inputProps_, children);
|
const fieldInput = React.createElement(this.props.element, inputProps_, children);
|
||||||
|
|
||||||
let prefixContainer = null;
|
let prefixContainer: JSX.Element | undefined;
|
||||||
if (prefixComponent) {
|
if (prefixComponent) {
|
||||||
prefixContainer = <span className="mx_Field_prefix">{prefixComponent}</span>;
|
prefixContainer = <span className="mx_Field_prefix">{prefixComponent}</span>;
|
||||||
}
|
}
|
||||||
let postfixContainer = null;
|
let postfixContainer: JSX.Element | undefined;
|
||||||
if (postfixComponent) {
|
if (postfixComponent) {
|
||||||
postfixContainer = <span className="mx_Field_postfix">{postfixComponent}</span>;
|
postfixContainer = <span className="mx_Field_postfix">{postfixComponent}</span>;
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,7 +17,7 @@ See the License for the specific language governing permissions and
|
||||||
limitations under the License.
|
limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import React from "react";
|
import React, { ReactNode } from "react";
|
||||||
import { Room } from "matrix-js-sdk/src/models/room";
|
import { Room } from "matrix-js-sdk/src/models/room";
|
||||||
|
|
||||||
import { _t, _td } from "../../../languageHandler";
|
import { _t, _td } from "../../../languageHandler";
|
||||||
|
@ -41,12 +41,12 @@ export default class UrlPreviewSettings extends React.Component<IProps> {
|
||||||
dis.fire(Action.ViewUserSettings);
|
dis.fire(Action.ViewUserSettings);
|
||||||
};
|
};
|
||||||
|
|
||||||
public render(): React.ReactNode {
|
public render(): ReactNode {
|
||||||
const roomId = this.props.room.roomId;
|
const roomId = this.props.room.roomId;
|
||||||
const isEncrypted = MatrixClientPeg.get().isRoomEncrypted(roomId);
|
const isEncrypted = MatrixClientPeg.get().isRoomEncrypted(roomId);
|
||||||
|
|
||||||
let previewsForAccount = null;
|
let previewsForAccount: ReactNode | undefined;
|
||||||
let previewsForRoom = null;
|
let previewsForRoom: ReactNode | undefined;
|
||||||
|
|
||||||
if (!isEncrypted) {
|
if (!isEncrypted) {
|
||||||
// Only show account setting state and room state setting state in non-e2ee rooms where they apply
|
// Only show account setting state and room state setting state in non-e2ee rooms where they apply
|
||||||
|
|
|
@ -28,10 +28,10 @@ import { SettingLevel } from "../../../settings/SettingLevel";
|
||||||
|
|
||||||
interface IProps {
|
interface IProps {
|
||||||
userId?: string;
|
userId?: string;
|
||||||
displayName: string;
|
displayName?: string;
|
||||||
avatarUrl: string;
|
avatarUrl?: string;
|
||||||
messagePreviewText: string;
|
messagePreviewText: string;
|
||||||
onLayoutChanged?: (layout: Layout) => void;
|
onLayoutChanged: (layout: Layout) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface IState {
|
interface IState {
|
||||||
|
|
|
@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
|
||||||
limitations under the License.
|
limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import React from "react";
|
import React, { ReactNode } from "react";
|
||||||
import { IAnnotatedPushRule, IPusher, PushRuleAction, PushRuleKind, RuleId } from "matrix-js-sdk/src/@types/PushRules";
|
import { IAnnotatedPushRule, IPusher, PushRuleAction, PushRuleKind, RuleId } from "matrix-js-sdk/src/@types/PushRules";
|
||||||
import { IThreepid, ThreepidMedium } from "matrix-js-sdk/src/@types/threepids";
|
import { IThreepid, ThreepidMedium } from "matrix-js-sdk/src/@types/threepids";
|
||||||
import { logger } from "matrix-js-sdk/src/logger";
|
import { logger } from "matrix-js-sdk/src/logger";
|
||||||
|
@ -152,7 +152,7 @@ export default class Notifications extends React.PureComponent<IProps, IState> {
|
||||||
// the master rule is *enabled* it means all other rules are *disabled* (or
|
// the master rule is *enabled* it means all other rules are *disabled* (or
|
||||||
// inhibited). Conversely, when the master rule is *disabled* then all other rules
|
// inhibited). Conversely, when the master rule is *disabled* then all other rules
|
||||||
// are *enabled* (or operate fine).
|
// are *enabled* (or operate fine).
|
||||||
return this.state.masterPushRule?.enabled;
|
return !!this.state.masterPushRule?.enabled;
|
||||||
}
|
}
|
||||||
|
|
||||||
public componentDidMount(): void {
|
public componentDidMount(): void {
|
||||||
|
@ -622,12 +622,12 @@ export default class Notifications extends React.PureComponent<IProps, IState> {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
private renderCategory(category: RuleClass): JSX.Element {
|
private renderCategory(category: RuleClass): ReactNode {
|
||||||
if (category !== RuleClass.VectorOther && this.isInhibited) {
|
if (category !== RuleClass.VectorOther && this.isInhibited) {
|
||||||
return null; // nothing to show for the section
|
return null; // nothing to show for the section
|
||||||
}
|
}
|
||||||
|
|
||||||
let clearNotifsButton: JSX.Element;
|
let clearNotifsButton: JSX.Element | undefined;
|
||||||
if (
|
if (
|
||||||
category === RuleClass.VectorOther &&
|
category === RuleClass.VectorOther &&
|
||||||
MatrixClientPeg.get()
|
MatrixClientPeg.get()
|
||||||
|
@ -660,7 +660,7 @@ export default class Notifications extends React.PureComponent<IProps, IState> {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
let keywordComposer: JSX.Element;
|
let keywordComposer: JSX.Element | undefined;
|
||||||
if (category === RuleClass.VectorMentions) {
|
if (category === RuleClass.VectorMentions) {
|
||||||
keywordComposer = (
|
keywordComposer = (
|
||||||
<TagComposer
|
<TagComposer
|
||||||
|
@ -691,7 +691,7 @@ export default class Notifications extends React.PureComponent<IProps, IState> {
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
|
|
||||||
const fieldsetRows = this.state.vectorPushRules[category].map((r) => (
|
const fieldsetRows = this.state.vectorPushRules[category]?.map((r) => (
|
||||||
<fieldset
|
<fieldset
|
||||||
key={category + r.ruleId}
|
key={category + r.ruleId}
|
||||||
data-testid={category + r.ruleId}
|
data-testid={category + r.ruleId}
|
||||||
|
@ -736,10 +736,10 @@ export default class Notifications extends React.PureComponent<IProps, IState> {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
private renderTargets(): JSX.Element {
|
private renderTargets(): ReactNode {
|
||||||
if (this.isInhibited) return null; // no targets if there's no notifications
|
if (this.isInhibited) return null; // no targets if there's no notifications
|
||||||
|
|
||||||
const rows = this.state.pushers.map((p) => (
|
const rows = this.state.pushers?.map((p) => (
|
||||||
<tr key={p.kind + p.pushkey}>
|
<tr key={p.kind + p.pushkey}>
|
||||||
<td>{p.app_display_name}</td>
|
<td>{p.app_display_name}</td>
|
||||||
<td>{p.device_display_name}</td>
|
<td>{p.device_display_name}</td>
|
||||||
|
|
|
@ -34,11 +34,11 @@ import PosthogTrackers from "../../../PosthogTrackers";
|
||||||
|
|
||||||
interface IState {
|
interface IState {
|
||||||
userId?: string;
|
userId?: string;
|
||||||
originalDisplayName?: string;
|
originalDisplayName: string;
|
||||||
displayName?: string;
|
displayName: string;
|
||||||
originalAvatarUrl?: string;
|
originalAvatarUrl: string | null;
|
||||||
avatarUrl?: string | ArrayBuffer;
|
avatarUrl?: string | ArrayBuffer;
|
||||||
avatarFile?: File;
|
avatarFile?: File | null;
|
||||||
enableProfileSave?: boolean;
|
enableProfileSave?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -52,25 +52,25 @@ export default class ProfileSettings extends React.Component<{}, IState> {
|
||||||
let avatarUrl = OwnProfileStore.instance.avatarMxc;
|
let avatarUrl = OwnProfileStore.instance.avatarMxc;
|
||||||
if (avatarUrl) avatarUrl = mediaFromMxc(avatarUrl).getSquareThumbnailHttp(96);
|
if (avatarUrl) avatarUrl = mediaFromMxc(avatarUrl).getSquareThumbnailHttp(96);
|
||||||
this.state = {
|
this.state = {
|
||||||
userId: client.getUserId(),
|
userId: client.getUserId()!,
|
||||||
originalDisplayName: OwnProfileStore.instance.displayName,
|
originalDisplayName: OwnProfileStore.instance.displayName ?? "",
|
||||||
displayName: OwnProfileStore.instance.displayName,
|
displayName: OwnProfileStore.instance.displayName ?? "",
|
||||||
originalAvatarUrl: avatarUrl,
|
originalAvatarUrl: avatarUrl,
|
||||||
avatarUrl: avatarUrl,
|
avatarUrl: avatarUrl ?? undefined,
|
||||||
avatarFile: null,
|
avatarFile: null,
|
||||||
enableProfileSave: false,
|
enableProfileSave: false,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
private uploadAvatar = (): void => {
|
private uploadAvatar = (): void => {
|
||||||
this.avatarUpload.current.click();
|
this.avatarUpload.current?.click();
|
||||||
};
|
};
|
||||||
|
|
||||||
private removeAvatar = (): void => {
|
private removeAvatar = (): void => {
|
||||||
// clear file upload field so same file can be selected
|
// clear file upload field so same file can be selected
|
||||||
this.avatarUpload.current.value = "";
|
this.avatarUpload.current.value = "";
|
||||||
this.setState({
|
this.setState({
|
||||||
avatarUrl: null,
|
avatarUrl: undefined,
|
||||||
avatarFile: null,
|
avatarFile: null,
|
||||||
enableProfileSave: true,
|
enableProfileSave: true,
|
||||||
});
|
});
|
||||||
|
@ -84,7 +84,7 @@ export default class ProfileSettings extends React.Component<{}, IState> {
|
||||||
this.setState({
|
this.setState({
|
||||||
enableProfileSave: false,
|
enableProfileSave: false,
|
||||||
displayName: this.state.originalDisplayName,
|
displayName: this.state.originalDisplayName,
|
||||||
avatarUrl: this.state.originalAvatarUrl,
|
avatarUrl: this.state.originalAvatarUrl ?? undefined,
|
||||||
avatarFile: null,
|
avatarFile: null,
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
@ -97,7 +97,7 @@ export default class ProfileSettings extends React.Component<{}, IState> {
|
||||||
this.setState({ enableProfileSave: false });
|
this.setState({ enableProfileSave: false });
|
||||||
|
|
||||||
const client = MatrixClientPeg.get();
|
const client = MatrixClientPeg.get();
|
||||||
const newState: IState = {};
|
const newState: Partial<IState> = {};
|
||||||
|
|
||||||
const displayName = this.state.displayName.trim();
|
const displayName = this.state.displayName.trim();
|
||||||
try {
|
try {
|
||||||
|
@ -114,7 +114,7 @@ export default class ProfileSettings extends React.Component<{}, IState> {
|
||||||
);
|
);
|
||||||
const { content_uri: uri } = await client.uploadContent(this.state.avatarFile);
|
const { content_uri: uri } = await client.uploadContent(this.state.avatarFile);
|
||||||
await client.setAvatarUrl(uri);
|
await client.setAvatarUrl(uri);
|
||||||
newState.avatarUrl = mediaFromMxc(uri).getSquareThumbnailHttp(96);
|
newState.avatarUrl = mediaFromMxc(uri).getSquareThumbnailHttp(96) ?? undefined;
|
||||||
newState.originalAvatarUrl = newState.avatarUrl;
|
newState.originalAvatarUrl = newState.avatarUrl;
|
||||||
newState.avatarFile = null;
|
newState.avatarFile = null;
|
||||||
} else if (this.state.originalAvatarUrl !== this.state.avatarUrl) {
|
} else if (this.state.originalAvatarUrl !== this.state.avatarUrl) {
|
||||||
|
@ -128,7 +128,7 @@ export default class ProfileSettings extends React.Component<{}, IState> {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
this.setState(newState);
|
this.setState<any>(newState);
|
||||||
};
|
};
|
||||||
|
|
||||||
private onDisplayNameChanged = (e: React.ChangeEvent<HTMLInputElement>): void => {
|
private onDisplayNameChanged = (e: React.ChangeEvent<HTMLInputElement>): void => {
|
||||||
|
@ -141,7 +141,7 @@ export default class ProfileSettings extends React.Component<{}, IState> {
|
||||||
private onAvatarChanged = (e: React.ChangeEvent<HTMLInputElement>): void => {
|
private onAvatarChanged = (e: React.ChangeEvent<HTMLInputElement>): void => {
|
||||||
if (!e.target.files || !e.target.files.length) {
|
if (!e.target.files || !e.target.files.length) {
|
||||||
this.setState({
|
this.setState({
|
||||||
avatarUrl: this.state.originalAvatarUrl,
|
avatarUrl: this.state.originalAvatarUrl ?? undefined,
|
||||||
avatarFile: null,
|
avatarFile: null,
|
||||||
enableProfileSave: false,
|
enableProfileSave: false,
|
||||||
});
|
});
|
||||||
|
@ -152,7 +152,7 @@ export default class ProfileSettings extends React.Component<{}, IState> {
|
||||||
const reader = new FileReader();
|
const reader = new FileReader();
|
||||||
reader.onload = (ev) => {
|
reader.onload = (ev) => {
|
||||||
this.setState({
|
this.setState({
|
||||||
avatarUrl: ev.target.result,
|
avatarUrl: ev.target?.result,
|
||||||
avatarFile: file,
|
avatarFile: file,
|
||||||
enableProfileSave: true,
|
enableProfileSave: true,
|
||||||
});
|
});
|
||||||
|
@ -162,7 +162,7 @@ export default class ProfileSettings extends React.Component<{}, IState> {
|
||||||
|
|
||||||
public render(): React.ReactNode {
|
public render(): React.ReactNode {
|
||||||
const hostingSignupLink = getHostingLink("user-settings");
|
const hostingSignupLink = getHostingLink("user-settings");
|
||||||
let hostingSignup = null;
|
let hostingSignup: JSX.Element | undefined;
|
||||||
if (hostingSignupLink) {
|
if (hostingSignupLink) {
|
||||||
hostingSignup = (
|
hostingSignup = (
|
||||||
<span>
|
<span>
|
||||||
|
|
|
@ -27,7 +27,7 @@ import ToggleSwitch from "../elements/ToggleSwitch";
|
||||||
interface IProps {}
|
interface IProps {}
|
||||||
|
|
||||||
interface IState {
|
interface IState {
|
||||||
currentManager: IntegrationManagerInstance;
|
currentManager: IntegrationManagerInstance | null;
|
||||||
provisioningEnabled: boolean;
|
provisioningEnabled: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -162,7 +162,7 @@ export default class ThemeChoicePanel extends React.Component<IProps, IState> {
|
||||||
this.setState({ customThemeUrl: e.target.value });
|
this.setState({ customThemeUrl: e.target.value });
|
||||||
};
|
};
|
||||||
|
|
||||||
private renderHighContrastCheckbox(): React.ReactElement<HTMLDivElement> {
|
private renderHighContrastCheckbox(): React.ReactElement<HTMLDivElement> | undefined {
|
||||||
if (
|
if (
|
||||||
!this.state.useSystemTheme &&
|
!this.state.useSystemTheme &&
|
||||||
(findHighContrastTheme(this.state.theme) || isHighContrastTheme(this.state.theme))
|
(findHighContrastTheme(this.state.theme) || isHighContrastTheme(this.state.theme))
|
||||||
|
@ -181,7 +181,7 @@ export default class ThemeChoicePanel extends React.Component<IProps, IState> {
|
||||||
}
|
}
|
||||||
|
|
||||||
private highContrastThemeChanged(checked: boolean): void {
|
private highContrastThemeChanged(checked: boolean): void {
|
||||||
let newTheme: string;
|
let newTheme: string | undefined;
|
||||||
if (checked) {
|
if (checked) {
|
||||||
newTheme = findHighContrastTheme(this.state.theme);
|
newTheme = findHighContrastTheme(this.state.theme);
|
||||||
} else {
|
} else {
|
||||||
|
@ -194,7 +194,7 @@ export default class ThemeChoicePanel extends React.Component<IProps, IState> {
|
||||||
|
|
||||||
public render(): React.ReactElement<HTMLDivElement> {
|
public render(): React.ReactElement<HTMLDivElement> {
|
||||||
const themeWatcher = new ThemeWatcher();
|
const themeWatcher = new ThemeWatcher();
|
||||||
let systemThemeSection: JSX.Element;
|
let systemThemeSection: JSX.Element | undefined;
|
||||||
if (themeWatcher.isSystemThemeSupported()) {
|
if (themeWatcher.isSystemThemeSupported()) {
|
||||||
systemThemeSection = (
|
systemThemeSection = (
|
||||||
<div>
|
<div>
|
||||||
|
@ -208,9 +208,9 @@ export default class ThemeChoicePanel extends React.Component<IProps, IState> {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
let customThemeForm: JSX.Element;
|
let customThemeForm: JSX.Element | undefined;
|
||||||
if (SettingsStore.getValue("feature_custom_themes")) {
|
if (SettingsStore.getValue("feature_custom_themes")) {
|
||||||
let messageElement = null;
|
let messageElement: JSX.Element | undefined;
|
||||||
if (this.state.customThemeMessage.text) {
|
if (this.state.customThemeMessage.text) {
|
||||||
if (this.state.customThemeMessage.isError) {
|
if (this.state.customThemeMessage.isError) {
|
||||||
messageElement = <div className="text-error">{this.state.customThemeMessage.text}</div>;
|
messageElement = <div className="text-error">{this.state.customThemeMessage.text}</div>;
|
||||||
|
@ -268,7 +268,7 @@ export default class ThemeChoicePanel extends React.Component<IProps, IState> {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public apparentSelectedThemeId(): string {
|
public apparentSelectedThemeId(): string | undefined {
|
||||||
if (this.state.useSystemTheme) {
|
if (this.state.useSystemTheme) {
|
||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,7 +27,7 @@ import AccessibleButton from "../../../components/views/elements/AccessibleButto
|
||||||
import { CheckUpdatesPayload } from "../../../dispatcher/payloads/CheckUpdatesPayload";
|
import { CheckUpdatesPayload } from "../../../dispatcher/payloads/CheckUpdatesPayload";
|
||||||
|
|
||||||
function installUpdate(): void {
|
function installUpdate(): void {
|
||||||
PlatformPeg.get().installUpdate();
|
PlatformPeg.get()?.installUpdate();
|
||||||
}
|
}
|
||||||
|
|
||||||
function getStatusText(status: UpdateCheckStatus, errorDetail?: string): ReactNode {
|
function getStatusText(status: UpdateCheckStatus, errorDetail?: string): ReactNode {
|
||||||
|
@ -58,11 +58,11 @@ function getStatusText(status: UpdateCheckStatus, errorDetail?: string): ReactNo
|
||||||
const doneStatuses = [UpdateCheckStatus.Ready, UpdateCheckStatus.Error, UpdateCheckStatus.NotAvailable];
|
const doneStatuses = [UpdateCheckStatus.Ready, UpdateCheckStatus.Error, UpdateCheckStatus.NotAvailable];
|
||||||
|
|
||||||
const UpdateCheckButton: React.FC = () => {
|
const UpdateCheckButton: React.FC = () => {
|
||||||
const [state, setState] = useState<CheckUpdatesPayload>(null);
|
const [state, setState] = useState<CheckUpdatesPayload | null>(null);
|
||||||
|
|
||||||
const onCheckForUpdateClick = (): void => {
|
const onCheckForUpdateClick = (): void => {
|
||||||
setState(null);
|
setState(null);
|
||||||
PlatformPeg.get().startUpdateCheck();
|
PlatformPeg.get()?.startUpdateCheck();
|
||||||
};
|
};
|
||||||
|
|
||||||
useDispatcher(dis, ({ action, ...params }) => {
|
useDispatcher(dis, ({ action, ...params }) => {
|
||||||
|
@ -71,9 +71,9 @@ const UpdateCheckButton: React.FC = () => {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
const busy = state && !doneStatuses.includes(state.status);
|
const busy = !!state && !doneStatuses.includes(state.status);
|
||||||
|
|
||||||
let suffix;
|
let suffix: JSX.Element | undefined;
|
||||||
if (state) {
|
if (state) {
|
||||||
suffix = (
|
suffix = (
|
||||||
<span className="mx_UpdateCheckButton_summary">
|
<span className="mx_UpdateCheckButton_summary">
|
||||||
|
|
|
@ -31,14 +31,14 @@ import { ExtendedDevice } from "./types";
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
device: ExtendedDevice;
|
device: ExtendedDevice;
|
||||||
pusher?: IPusher | undefined;
|
pusher?: IPusher;
|
||||||
localNotificationSettings?: LocalNotificationSettings | undefined;
|
localNotificationSettings?: LocalNotificationSettings;
|
||||||
isSigningOut: boolean;
|
isSigningOut: boolean;
|
||||||
onVerifyDevice?: () => void;
|
onVerifyDevice?: () => void;
|
||||||
onSignOutDevice: () => void;
|
onSignOutDevice: () => void;
|
||||||
saveDeviceName: (deviceName: string) => Promise<void>;
|
saveDeviceName: (deviceName: string) => Promise<void>;
|
||||||
setPushNotifications?: (deviceId: string, enabled: boolean) => Promise<void> | undefined;
|
setPushNotifications?: (deviceId: string, enabled: boolean) => Promise<void>;
|
||||||
supportsMSC3881?: boolean | undefined;
|
supportsMSC3881?: boolean;
|
||||||
className?: string;
|
className?: string;
|
||||||
isCurrentDevice?: boolean;
|
isCurrentDevice?: boolean;
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,7 +23,7 @@ import SettingsSubsection from "../shared/SettingsSubsection";
|
||||||
|
|
||||||
interface IProps {
|
interface IProps {
|
||||||
onShowQr: () => void;
|
onShowQr: () => void;
|
||||||
versions: IServerVersions;
|
versions?: IServerVersions;
|
||||||
}
|
}
|
||||||
|
|
||||||
export default class LoginWithQRSection extends React.Component<IProps> {
|
export default class LoginWithQRSection extends React.Component<IProps> {
|
||||||
|
|
|
@ -40,6 +40,7 @@ interface IRecommendedVersion {
|
||||||
}
|
}
|
||||||
|
|
||||||
interface IState {
|
interface IState {
|
||||||
|
// This is eventually set to the value of room.getRecommendedVersion()
|
||||||
upgradeRecommendation?: IRecommendedVersion;
|
upgradeRecommendation?: IRecommendedVersion;
|
||||||
oldRoomId?: string;
|
oldRoomId?: string;
|
||||||
oldEventId?: string;
|
oldEventId?: string;
|
||||||
|
@ -52,14 +53,11 @@ export default class AdvancedRoomSettingsTab extends React.Component<IProps, ISt
|
||||||
|
|
||||||
const msc3946ProcessDynamicPredecessor = SettingsStore.getValue("feature_dynamic_room_predecessors");
|
const msc3946ProcessDynamicPredecessor = SettingsStore.getValue("feature_dynamic_room_predecessors");
|
||||||
|
|
||||||
this.state = {
|
this.state = {};
|
||||||
// This is eventually set to the value of room.getRecommendedVersion()
|
|
||||||
upgradeRecommendation: null,
|
|
||||||
};
|
|
||||||
|
|
||||||
// we handle lack of this object gracefully later, so don't worry about it failing here.
|
// we handle lack of this object gracefully later, so don't worry about it failing here.
|
||||||
const room = MatrixClientPeg.get().getRoom(this.props.roomId);
|
const room = MatrixClientPeg.get().getRoom(this.props.roomId);
|
||||||
room.getRecommendedVersion().then((v) => {
|
room?.getRecommendedVersion().then((v) => {
|
||||||
const tombstone = room.currentState.getStateEvents(EventType.RoomTombstone, "");
|
const tombstone = room.currentState.getStateEvents(EventType.RoomTombstone, "");
|
||||||
|
|
||||||
const additionalStateChanges: Partial<IState> = {};
|
const additionalStateChanges: Partial<IState> = {};
|
||||||
|
@ -99,11 +97,10 @@ export default class AdvancedRoomSettingsTab extends React.Component<IProps, ISt
|
||||||
public render(): React.ReactNode {
|
public render(): React.ReactNode {
|
||||||
const client = MatrixClientPeg.get();
|
const client = MatrixClientPeg.get();
|
||||||
const room = client.getRoom(this.props.roomId);
|
const room = client.getRoom(this.props.roomId);
|
||||||
const isSpace = room.isSpaceRoom();
|
const isSpace = room?.isSpaceRoom();
|
||||||
|
|
||||||
let unfederatableSection;
|
let unfederatableSection: JSX.Element | undefined;
|
||||||
const createEvent = room.currentState.getStateEvents(EventType.RoomCreate, "");
|
if (room?.currentState.getStateEvents(EventType.RoomCreate, "")?.getContent()["m.federate"] === false) {
|
||||||
if (createEvent && createEvent.getContent()["m.federate"] === false) {
|
|
||||||
unfederatableSection = <div>{_t("This room is not accessible by remote Matrix servers")}</div>;
|
unfederatableSection = <div>{_t("This room is not accessible by remote Matrix servers")}</div>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -132,13 +129,13 @@ export default class AdvancedRoomSettingsTab extends React.Component<IProps, ISt
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
let oldRoomLink;
|
let oldRoomLink: JSX.Element | undefined;
|
||||||
if (this.state.oldRoomId) {
|
if (this.state.oldRoomId) {
|
||||||
let copy: string;
|
let copy: string;
|
||||||
if (isSpace) {
|
if (isSpace) {
|
||||||
copy = _t("View older version of %(spaceName)s.", { spaceName: room.name });
|
copy = _t("View older version of %(spaceName)s.", { spaceName: room?.name ?? this.state.oldRoomId });
|
||||||
} else {
|
} else {
|
||||||
copy = _t("View older messages in %(roomName)s.", { roomName: room.name });
|
copy = _t("View older messages in %(roomName)s.", { roomName: room?.name ?? this.state.oldRoomId });
|
||||||
}
|
}
|
||||||
|
|
||||||
oldRoomLink = (
|
oldRoomLink = (
|
||||||
|
@ -165,7 +162,7 @@ export default class AdvancedRoomSettingsTab extends React.Component<IProps, ISt
|
||||||
<span className="mx_SettingsTab_subheading">{_t("Room version")}</span>
|
<span className="mx_SettingsTab_subheading">{_t("Room version")}</span>
|
||||||
<div>
|
<div>
|
||||||
<span>{_t("Room version:")}</span>
|
<span>{_t("Room version:")}</span>
|
||||||
{room.getVersion()}
|
{room?.getVersion()}
|
||||||
</div>
|
</div>
|
||||||
{oldRoomLink}
|
{oldRoomLink}
|
||||||
{roomUpgradeButton}
|
{roomUpgradeButton}
|
||||||
|
|
|
@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
|
||||||
limitations under the License.
|
limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import React from "react";
|
import React, { ReactNode } from "react";
|
||||||
import { Room } from "matrix-js-sdk/src/models/room";
|
import { Room } from "matrix-js-sdk/src/models/room";
|
||||||
import { MatrixEvent } from "matrix-js-sdk/src/models/event";
|
import { MatrixEvent } from "matrix-js-sdk/src/models/event";
|
||||||
|
|
||||||
|
@ -34,17 +34,16 @@ interface IProps {
|
||||||
}
|
}
|
||||||
|
|
||||||
export default class BridgeSettingsTab extends React.Component<IProps> {
|
export default class BridgeSettingsTab extends React.Component<IProps> {
|
||||||
private renderBridgeCard(event: MatrixEvent, room: Room): JSX.Element {
|
private renderBridgeCard(event: MatrixEvent, room: Room | null): ReactNode {
|
||||||
const content = event.getContent();
|
const content = event.getContent();
|
||||||
if (!content || !content.channel || !content.protocol) {
|
if (!room || !content?.channel || !content.protocol) return null;
|
||||||
return null;
|
|
||||||
}
|
|
||||||
return <BridgeTile key={event.getId()} room={room} ev={event} />;
|
return <BridgeTile key={event.getId()} room={room} ev={event} />;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static getBridgeStateEvents(roomId: string): MatrixEvent[] {
|
public static getBridgeStateEvents(roomId: string): MatrixEvent[] {
|
||||||
const client = MatrixClientPeg.get();
|
const client = MatrixClientPeg.get();
|
||||||
const roomState = client.getRoom(roomId).currentState;
|
const roomState = client.getRoom(roomId)?.currentState;
|
||||||
|
if (!roomState) return [];
|
||||||
|
|
||||||
return BRIDGE_EVENT_TYPES.map((typeName) => roomState.getStateEvents(typeName)).flat(1);
|
return BRIDGE_EVENT_TYPES.map((typeName) => roomState.getStateEvents(typeName)).flat(1);
|
||||||
}
|
}
|
||||||
|
|
|
@ -61,15 +61,14 @@ export default class GeneralRoomSettingsTab extends React.Component<IProps, ISta
|
||||||
const room = client.getRoom(this.props.roomId);
|
const room = client.getRoom(this.props.roomId);
|
||||||
|
|
||||||
const canSetAliases = true; // Previously, we arbitrarily only allowed admins to do this
|
const canSetAliases = true; // Previously, we arbitrarily only allowed admins to do this
|
||||||
const canSetCanonical = room.currentState.mayClientSendStateEvent("m.room.canonical_alias", client);
|
const canSetCanonical = room?.currentState.mayClientSendStateEvent("m.room.canonical_alias", client);
|
||||||
const canonicalAliasEv = room.currentState.getStateEvents("m.room.canonical_alias", "");
|
const canonicalAliasEv = room?.currentState.getStateEvents("m.room.canonical_alias", "") ?? undefined;
|
||||||
|
|
||||||
const urlPreviewSettings = SettingsStore.getValue(UIFeature.URLPreviews) ? (
|
const urlPreviewSettings =
|
||||||
<UrlPreviewSettings room={room} />
|
room && SettingsStore.getValue(UIFeature.URLPreviews) ? <UrlPreviewSettings room={room} /> : null;
|
||||||
) : null;
|
|
||||||
|
|
||||||
let leaveSection;
|
let leaveSection;
|
||||||
if (room.getMyMembership() === "join") {
|
if (room?.getMyMembership() === "join") {
|
||||||
leaveSection = (
|
leaveSection = (
|
||||||
<>
|
<>
|
||||||
<span className="mx_SettingsTab_subheading">{_t("Leave room")}</span>
|
<span className="mx_SettingsTab_subheading">{_t("Leave room")}</span>
|
||||||
|
|
|
@ -40,7 +40,7 @@ interface IProps {
|
||||||
|
|
||||||
interface IState {
|
interface IState {
|
||||||
currentSound: string;
|
currentSound: string;
|
||||||
uploadedFile: File;
|
uploadedFile: File | null;
|
||||||
}
|
}
|
||||||
|
|
||||||
export default class NotificationsSettingsTab extends React.Component<IProps, IState> {
|
export default class NotificationsSettingsTab extends React.Component<IProps, IState> {
|
||||||
|
@ -71,7 +71,7 @@ export default class NotificationsSettingsTab extends React.Component<IProps, IS
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
|
|
||||||
this.soundUpload.current.click();
|
this.soundUpload.current?.click();
|
||||||
};
|
};
|
||||||
|
|
||||||
private onSoundUploadChanged = (e: React.ChangeEvent<HTMLInputElement>): void => {
|
private onSoundUploadChanged = (e: React.ChangeEvent<HTMLInputElement>): void => {
|
||||||
|
@ -156,7 +156,7 @@ export default class NotificationsSettingsTab extends React.Component<IProps, IS
|
||||||
};
|
};
|
||||||
|
|
||||||
public render(): React.ReactNode {
|
public render(): React.ReactNode {
|
||||||
let currentUploadedFile = null;
|
let currentUploadedFile: JSX.Element | undefined;
|
||||||
if (this.state.uploadedFile) {
|
if (this.state.uploadedFile) {
|
||||||
currentUploadedFile = (
|
currentUploadedFile = (
|
||||||
<div>
|
<div>
|
||||||
|
|
|
@ -239,13 +239,13 @@ export default class RolesRoomSettingsTab extends React.Component<IProps> {
|
||||||
public render(): React.ReactNode {
|
public render(): React.ReactNode {
|
||||||
const client = MatrixClientPeg.get();
|
const client = MatrixClientPeg.get();
|
||||||
const room = client.getRoom(this.props.roomId);
|
const room = client.getRoom(this.props.roomId);
|
||||||
const isSpaceRoom = room.isSpaceRoom();
|
const isSpaceRoom = room?.isSpaceRoom();
|
||||||
|
|
||||||
const plEvent = room.currentState.getStateEvents(EventType.RoomPowerLevels, "");
|
const plEvent = room?.currentState.getStateEvents(EventType.RoomPowerLevels, "");
|
||||||
const plContent = plEvent ? plEvent.getContent() || {} : {};
|
const plContent = plEvent ? plEvent.getContent() || {} : {};
|
||||||
const canChangeLevels = room.currentState.mayClientSendStateEvent(EventType.RoomPowerLevels, client);
|
const canChangeLevels = room?.currentState.mayClientSendStateEvent(EventType.RoomPowerLevels, client);
|
||||||
|
|
||||||
const plEventsToLabels: Record<EventType | string, string> = {
|
const plEventsToLabels: Record<EventType | string, string | null> = {
|
||||||
// These will be translated for us later.
|
// These will be translated for us later.
|
||||||
[EventType.RoomAvatar]: isSpaceRoom ? _td("Change space avatar") : _td("Change room avatar"),
|
[EventType.RoomAvatar]: isSpaceRoom ? _td("Change space avatar") : _td("Change room avatar"),
|
||||||
[EventType.RoomName]: isSpaceRoom ? _td("Change space name") : _td("Change room name"),
|
[EventType.RoomName]: isSpaceRoom ? _td("Change space name") : _td("Change room name"),
|
||||||
|
@ -322,7 +322,7 @@ export default class RolesRoomSettingsTab extends React.Component<IProps> {
|
||||||
powerLevelDescriptors.users_default.defaultValue,
|
powerLevelDescriptors.users_default.defaultValue,
|
||||||
);
|
);
|
||||||
|
|
||||||
let currentUserLevel = userLevels[client.getUserId()];
|
let currentUserLevel = userLevels[client.getUserId()!];
|
||||||
if (currentUserLevel === undefined) {
|
if (currentUserLevel === undefined) {
|
||||||
currentUserLevel = defaultUserLevel;
|
currentUserLevel = defaultUserLevel;
|
||||||
}
|
}
|
||||||
|
@ -391,16 +391,16 @@ export default class RolesRoomSettingsTab extends React.Component<IProps> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const banned = room.getMembersWithMembership("ban");
|
const banned = room?.getMembersWithMembership("ban");
|
||||||
let bannedUsersSection;
|
let bannedUsersSection: JSX.Element | undefined;
|
||||||
if (banned.length) {
|
if (banned?.length) {
|
||||||
const canBanUsers = currentUserLevel >= banLevel;
|
const canBanUsers = currentUserLevel >= banLevel;
|
||||||
bannedUsersSection = (
|
bannedUsersSection = (
|
||||||
<SettingsFieldset legend={_t("Banned users")}>
|
<SettingsFieldset legend={_t("Banned users")}>
|
||||||
<ul>
|
<ul>
|
||||||
{banned.map((member) => {
|
{banned.map((member) => {
|
||||||
const banEvent = member.events.member.getContent();
|
const banEvent = member.events.member?.getContent();
|
||||||
const sender = room.getMember(member.events.member.getSender());
|
const sender = room?.getMember(member.events.member.getSender());
|
||||||
let bannedBy = member.events.member.getSender(); // start by falling back to mxid
|
let bannedBy = member.events.member.getSender(); // start by falling back to mxid
|
||||||
if (sender) bannedBy = sender.name;
|
if (sender) bannedBy = sender.name;
|
||||||
return (
|
return (
|
||||||
|
|
|
@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
|
||||||
limitations under the License.
|
limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import React from "react";
|
import React, { ReactNode } from "react";
|
||||||
import { GuestAccess, HistoryVisibility, JoinRule } from "matrix-js-sdk/src/@types/partials";
|
import { GuestAccess, HistoryVisibility, JoinRule } from "matrix-js-sdk/src/@types/partials";
|
||||||
import { MatrixEvent } from "matrix-js-sdk/src/models/event";
|
import { MatrixEvent } from "matrix-js-sdk/src/models/event";
|
||||||
import { RoomStateEvent } from "matrix-js-sdk/src/models/room-state";
|
import { RoomStateEvent } from "matrix-js-sdk/src/models/room-state";
|
||||||
|
@ -61,16 +61,16 @@ export default class SecurityRoomSettingsTab extends React.Component<IProps, ISt
|
||||||
public constructor(props: IProps, context: React.ContextType<typeof MatrixClientContext>) {
|
public constructor(props: IProps, context: React.ContextType<typeof MatrixClientContext>) {
|
||||||
super(props, context);
|
super(props, context);
|
||||||
|
|
||||||
const state = context.getRoom(this.props.roomId).currentState;
|
const state = context.getRoom(this.props.roomId)?.currentState;
|
||||||
|
|
||||||
this.state = {
|
this.state = {
|
||||||
guestAccess: this.pullContentPropertyFromEvent<GuestAccess>(
|
guestAccess: this.pullContentPropertyFromEvent<GuestAccess>(
|
||||||
state.getStateEvents(EventType.RoomGuestAccess, ""),
|
state?.getStateEvents(EventType.RoomGuestAccess, ""),
|
||||||
"guest_access",
|
"guest_access",
|
||||||
GuestAccess.Forbidden,
|
GuestAccess.Forbidden,
|
||||||
),
|
),
|
||||||
history: this.pullContentPropertyFromEvent<HistoryVisibility>(
|
history: this.pullContentPropertyFromEvent<HistoryVisibility>(
|
||||||
state.getStateEvents(EventType.RoomHistoryVisibility, ""),
|
state?.getStateEvents(EventType.RoomHistoryVisibility, ""),
|
||||||
"history_visibility",
|
"history_visibility",
|
||||||
HistoryVisibility.Shared,
|
HistoryVisibility.Shared,
|
||||||
),
|
),
|
||||||
|
@ -85,7 +85,7 @@ export default class SecurityRoomSettingsTab extends React.Component<IProps, ISt
|
||||||
this.hasAliases().then((hasAliases) => this.setState({ hasAliases }));
|
this.hasAliases().then((hasAliases) => this.setState({ hasAliases }));
|
||||||
}
|
}
|
||||||
|
|
||||||
private pullContentPropertyFromEvent<T>(event: MatrixEvent, key: string, defaultValue: T): T {
|
private pullContentPropertyFromEvent<T>(event: MatrixEvent | null | undefined, key: string, defaultValue: T): T {
|
||||||
return event?.getContent()[key] || defaultValue;
|
return event?.getContent()[key] || defaultValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -117,7 +117,7 @@ export default class SecurityRoomSettingsTab extends React.Component<IProps, ISt
|
||||||
"You'll get none of the benefits of encryption, and you won't be able to turn it " +
|
"You'll get none of the benefits of encryption, and you won't be able to turn it " +
|
||||||
"off later. Encrypting messages in a public room will make receiving and sending " +
|
"off later. Encrypting messages in a public room will make receiving and sending " +
|
||||||
"messages slower.",
|
"messages slower.",
|
||||||
null,
|
undefined,
|
||||||
{ b: (sub) => <b>{sub}</b> },
|
{ b: (sub) => <b>{sub}</b> },
|
||||||
)}{" "}
|
)}{" "}
|
||||||
</p>
|
</p>
|
||||||
|
@ -126,7 +126,7 @@ export default class SecurityRoomSettingsTab extends React.Component<IProps, ISt
|
||||||
{_t(
|
{_t(
|
||||||
"To avoid these issues, create a <a>new encrypted room</a> for " +
|
"To avoid these issues, create a <a>new encrypted room</a> for " +
|
||||||
"the conversation you plan to have.",
|
"the conversation you plan to have.",
|
||||||
null,
|
undefined,
|
||||||
{
|
{
|
||||||
a: (sub) => (
|
a: (sub) => (
|
||||||
<AccessibleButton
|
<AccessibleButton
|
||||||
|
@ -236,7 +236,7 @@ export default class SecurityRoomSettingsTab extends React.Component<IProps, ISt
|
||||||
};
|
};
|
||||||
|
|
||||||
private updateBlacklistDevicesFlag = (checked: boolean): void => {
|
private updateBlacklistDevicesFlag = (checked: boolean): void => {
|
||||||
this.context.getRoom(this.props.roomId).setBlacklistUnverifiedDevices(checked);
|
this.context.getRoom(this.props.roomId)?.setBlacklistUnverifiedDevices(checked);
|
||||||
};
|
};
|
||||||
|
|
||||||
private async hasAliases(): Promise<boolean> {
|
private async hasAliases(): Promise<boolean> {
|
||||||
|
@ -250,8 +250,8 @@ export default class SecurityRoomSettingsTab extends React.Component<IProps, ISt
|
||||||
const client = this.context;
|
const client = this.context;
|
||||||
const room = client.getRoom(this.props.roomId);
|
const room = client.getRoom(this.props.roomId);
|
||||||
|
|
||||||
let aliasWarning = null;
|
let aliasWarning: JSX.Element | undefined;
|
||||||
if (room.getJoinRule() === JoinRule.Public && !this.state.hasAliases) {
|
if (room?.getJoinRule() === JoinRule.Public && !this.state.hasAliases) {
|
||||||
aliasWarning = (
|
aliasWarning = (
|
||||||
<div className="mx_SecurityRoomSettingsTab_warning">
|
<div className="mx_SecurityRoomSettingsTab_warning">
|
||||||
<WarningIcon width={15} height={15} />
|
<WarningIcon width={15} height={15} />
|
||||||
|
@ -297,7 +297,7 @@ export default class SecurityRoomSettingsTab extends React.Component<IProps, ISt
|
||||||
"It will mean anyone can find and join the room, so anyone can read messages. " +
|
"It will mean anyone can find and join the room, so anyone can read messages. " +
|
||||||
"You'll get none of the benefits of encryption. Encrypting messages in a public " +
|
"You'll get none of the benefits of encryption. Encrypting messages in a public " +
|
||||||
"room will make receiving and sending messages slower.",
|
"room will make receiving and sending messages slower.",
|
||||||
null,
|
undefined,
|
||||||
{ b: (sub) => <b>{sub}</b> },
|
{ b: (sub) => <b>{sub}</b> },
|
||||||
)}{" "}
|
)}{" "}
|
||||||
</p>
|
</p>
|
||||||
|
@ -306,7 +306,7 @@ export default class SecurityRoomSettingsTab extends React.Component<IProps, ISt
|
||||||
{_t(
|
{_t(
|
||||||
"To avoid these issues, create a <a>new public room</a> for the conversation " +
|
"To avoid these issues, create a <a>new public room</a> for the conversation " +
|
||||||
"you plan to have.",
|
"you plan to have.",
|
||||||
null,
|
undefined,
|
||||||
{
|
{
|
||||||
a: (sub) => (
|
a: (sub) => (
|
||||||
<AccessibleButton
|
<AccessibleButton
|
||||||
|
@ -335,15 +335,15 @@ export default class SecurityRoomSettingsTab extends React.Component<IProps, ISt
|
||||||
return true;
|
return true;
|
||||||
};
|
};
|
||||||
|
|
||||||
private renderHistory(): JSX.Element {
|
private renderHistory(): ReactNode {
|
||||||
if (!SettingsStore.getValue(UIFeature.RoomHistorySettings)) {
|
if (!SettingsStore.getValue(UIFeature.RoomHistorySettings)) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
const client = this.context;
|
const client = this.context;
|
||||||
const history = this.state.history;
|
const history = this.state.history;
|
||||||
const state = client.getRoom(this.props.roomId).currentState;
|
const state = client.getRoom(this.props.roomId)?.currentState;
|
||||||
const canChangeHistory = state.mayClientSendStateEvent(EventType.RoomHistoryVisibility, client);
|
const canChangeHistory = state?.mayClientSendStateEvent(EventType.RoomHistoryVisibility, client);
|
||||||
|
|
||||||
const options = [
|
const options = [
|
||||||
{
|
{
|
||||||
|
@ -393,8 +393,8 @@ export default class SecurityRoomSettingsTab extends React.Component<IProps, ISt
|
||||||
private renderAdvanced(): JSX.Element {
|
private renderAdvanced(): JSX.Element {
|
||||||
const client = this.context;
|
const client = this.context;
|
||||||
const guestAccess = this.state.guestAccess;
|
const guestAccess = this.state.guestAccess;
|
||||||
const state = client.getRoom(this.props.roomId).currentState;
|
const state = client.getRoom(this.props.roomId)?.currentState;
|
||||||
const canSetGuestAccess = state.mayClientSendStateEvent(EventType.RoomGuestAccess, client);
|
const canSetGuestAccess = state?.mayClientSendStateEvent(EventType.RoomGuestAccess, client);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
|
@ -418,10 +418,10 @@ export default class SecurityRoomSettingsTab extends React.Component<IProps, ISt
|
||||||
const client = this.context;
|
const client = this.context;
|
||||||
const room = client.getRoom(this.props.roomId);
|
const room = client.getRoom(this.props.roomId);
|
||||||
const isEncrypted = this.state.encrypted;
|
const isEncrypted = this.state.encrypted;
|
||||||
const hasEncryptionPermission = room.currentState.mayClientSendStateEvent(EventType.RoomEncryption, client);
|
const hasEncryptionPermission = room?.currentState.mayClientSendStateEvent(EventType.RoomEncryption, client);
|
||||||
const canEnableEncryption = !isEncrypted && hasEncryptionPermission;
|
const canEnableEncryption = !isEncrypted && hasEncryptionPermission;
|
||||||
|
|
||||||
let encryptionSettings = null;
|
let encryptionSettings: JSX.Element | undefined;
|
||||||
if (isEncrypted && SettingsStore.isEnabled("blacklistUnverifiedDevices")) {
|
if (isEncrypted && SettingsStore.isEnabled("blacklistUnverifiedDevices")) {
|
||||||
encryptionSettings = (
|
encryptionSettings = (
|
||||||
<SettingsFlag
|
<SettingsFlag
|
||||||
|
@ -435,8 +435,8 @@ export default class SecurityRoomSettingsTab extends React.Component<IProps, ISt
|
||||||
|
|
||||||
const historySection = this.renderHistory();
|
const historySection = this.renderHistory();
|
||||||
|
|
||||||
let advanced;
|
let advanced: JSX.Element | undefined;
|
||||||
if (room.getJoinRule() === JoinRule.Public) {
|
if (room?.getJoinRule() === JoinRule.Public) {
|
||||||
advanced = (
|
advanced = (
|
||||||
<div className="mx_SettingsTab_section">
|
<div className="mx_SettingsTab_section">
|
||||||
<AccessibleButton
|
<AccessibleButton
|
||||||
|
|
|
@ -15,7 +15,7 @@ See the License for the specific language governing permissions and
|
||||||
limitations under the License.
|
limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import React, { ChangeEvent } from "react";
|
import React, { ChangeEvent, ReactNode } from "react";
|
||||||
|
|
||||||
import { _t } from "../../../../../languageHandler";
|
import { _t } from "../../../../../languageHandler";
|
||||||
import SdkConfig from "../../../../../SdkConfig";
|
import SdkConfig from "../../../../../SdkConfig";
|
||||||
|
@ -41,8 +41,8 @@ interface IState {
|
||||||
layout: Layout;
|
layout: Layout;
|
||||||
// User profile data for the message preview
|
// User profile data for the message preview
|
||||||
userId?: string;
|
userId?: string;
|
||||||
displayName: string;
|
displayName?: string;
|
||||||
avatarUrl: string;
|
avatarUrl?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export default class AppearanceUserSettingsTab extends React.Component<IProps, IState> {
|
export default class AppearanceUserSettingsTab extends React.Component<IProps, IState> {
|
||||||
|
@ -58,16 +58,13 @@ export default class AppearanceUserSettingsTab extends React.Component<IProps, I
|
||||||
systemFont: SettingsStore.getValue("systemFont"),
|
systemFont: SettingsStore.getValue("systemFont"),
|
||||||
showAdvanced: false,
|
showAdvanced: false,
|
||||||
layout: SettingsStore.getValue("layout"),
|
layout: SettingsStore.getValue("layout"),
|
||||||
userId: null,
|
|
||||||
displayName: null,
|
|
||||||
avatarUrl: null,
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
public async componentDidMount(): Promise<void> {
|
public async componentDidMount(): Promise<void> {
|
||||||
// Fetch the current user profile for the message preview
|
// Fetch the current user profile for the message preview
|
||||||
const client = MatrixClientPeg.get();
|
const client = MatrixClientPeg.get();
|
||||||
const userId = client.getUserId();
|
const userId = client.getUserId()!;
|
||||||
const profileInfo = await client.getProfileInfo(userId);
|
const profileInfo = await client.getProfileInfo(userId);
|
||||||
if (this.unmounted) return;
|
if (this.unmounted) return;
|
||||||
|
|
||||||
|
@ -86,7 +83,7 @@ export default class AppearanceUserSettingsTab extends React.Component<IProps, I
|
||||||
this.setState({ layout: layout });
|
this.setState({ layout: layout });
|
||||||
};
|
};
|
||||||
|
|
||||||
private renderAdvancedSection(): JSX.Element {
|
private renderAdvancedSection(): ReactNode {
|
||||||
if (!SettingsStore.getValue(UIFeature.AdvancedSettings)) return null;
|
if (!SettingsStore.getValue(UIFeature.AdvancedSettings)) return null;
|
||||||
|
|
||||||
const brand = SdkConfig.get().brand;
|
const brand = SdkConfig.get().brand;
|
||||||
|
@ -115,7 +112,7 @@ export default class AppearanceUserSettingsTab extends React.Component<IProps, I
|
||||||
/>
|
/>
|
||||||
<Field
|
<Field
|
||||||
className="mx_AppearanceUserSettingsTab_systemFont"
|
className="mx_AppearanceUserSettingsTab_systemFont"
|
||||||
label={SettingsStore.getDisplayName("systemFont")}
|
label={SettingsStore.getDisplayName("systemFont")!}
|
||||||
onChange={(value: ChangeEvent<HTMLInputElement>) => {
|
onChange={(value: ChangeEvent<HTMLInputElement>) => {
|
||||||
this.setState({
|
this.setState({
|
||||||
systemFont: value.target.value,
|
systemFont: value.target.value,
|
||||||
|
|
|
@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
|
||||||
limitations under the License.
|
limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import React from "react";
|
import React, { ReactNode } from "react";
|
||||||
import { logger } from "matrix-js-sdk/src/logger";
|
import { logger } from "matrix-js-sdk/src/logger";
|
||||||
|
|
||||||
import AccessibleButton from "../../../elements/AccessibleButton";
|
import AccessibleButton from "../../../elements/AccessibleButton";
|
||||||
|
@ -37,7 +37,7 @@ interface IProps {
|
||||||
}
|
}
|
||||||
|
|
||||||
interface IState {
|
interface IState {
|
||||||
appVersion: string;
|
appVersion: string | null;
|
||||||
canUpdate: boolean;
|
canUpdate: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -53,13 +53,13 @@ export default class HelpUserSettingsTab extends React.Component<IProps, IState>
|
||||||
|
|
||||||
public componentDidMount(): void {
|
public componentDidMount(): void {
|
||||||
PlatformPeg.get()
|
PlatformPeg.get()
|
||||||
.getAppVersion()
|
?.getAppVersion()
|
||||||
.then((ver) => this.setState({ appVersion: ver }))
|
.then((ver) => this.setState({ appVersion: ver }))
|
||||||
.catch((e) => {
|
.catch((e) => {
|
||||||
logger.error("Error getting vector version: ", e);
|
logger.error("Error getting vector version: ", e);
|
||||||
});
|
});
|
||||||
PlatformPeg.get()
|
PlatformPeg.get()
|
||||||
.canSelfUpdate()
|
?.canSelfUpdate()
|
||||||
.then((v) => this.setState({ canUpdate: v }))
|
.then((v) => this.setState({ canUpdate: v }))
|
||||||
.catch((e) => {
|
.catch((e) => {
|
||||||
logger.error("Error getting self updatability: ", e);
|
logger.error("Error getting self updatability: ", e);
|
||||||
|
@ -90,7 +90,7 @@ export default class HelpUserSettingsTab extends React.Component<IProps, IState>
|
||||||
MatrixClientPeg.get()
|
MatrixClientPeg.get()
|
||||||
.store.deleteAllData()
|
.store.deleteAllData()
|
||||||
.then(() => {
|
.then(() => {
|
||||||
PlatformPeg.get().reload();
|
PlatformPeg.get()?.reload();
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -106,11 +106,11 @@ export default class HelpUserSettingsTab extends React.Component<IProps, IState>
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
private renderLegal(): JSX.Element {
|
private renderLegal(): ReactNode {
|
||||||
const tocLinks = SdkConfig.get().terms_and_conditions_links;
|
const tocLinks = SdkConfig.get().terms_and_conditions_links;
|
||||||
if (!tocLinks) return null;
|
if (!tocLinks) return null;
|
||||||
|
|
||||||
const legalLinks = [];
|
const legalLinks: JSX.Element[] = [];
|
||||||
for (const tocEntry of tocLinks) {
|
for (const tocEntry of tocLinks) {
|
||||||
legalLinks.push(
|
legalLinks.push(
|
||||||
<div key={tocEntry.url}>
|
<div key={tocEntry.url}>
|
||||||
|
@ -248,7 +248,7 @@ export default class HelpUserSettingsTab extends React.Component<IProps, IState>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
let updateButton = null;
|
let updateButton: JSX.Element | undefined;
|
||||||
if (this.state.canUpdate) {
|
if (this.state.canUpdate) {
|
||||||
updateButton = <UpdateCheckButton />;
|
updateButton = <UpdateCheckButton />;
|
||||||
}
|
}
|
||||||
|
|
|
@ -105,7 +105,7 @@ export default class MjolnirUserSettingsTab extends React.Component<{}, IState>
|
||||||
this.setState({ busy: true });
|
this.setState({ busy: true });
|
||||||
try {
|
try {
|
||||||
const list = Mjolnir.sharedInstance().getPersonalList();
|
const list = Mjolnir.sharedInstance().getPersonalList();
|
||||||
await list.unbanEntity(rule.kind, rule.entity);
|
await list!.unbanEntity(rule.kind, rule.entity);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
logger.error(e);
|
logger.error(e);
|
||||||
|
|
||||||
|
@ -142,7 +142,7 @@ export default class MjolnirUserSettingsTab extends React.Component<{}, IState>
|
||||||
const renderRules = (rules: ListRule[]): JSX.Element => {
|
const renderRules = (rules: ListRule[]): JSX.Element => {
|
||||||
if (rules.length === 0) return <i>{_t("None")}</i>;
|
if (rules.length === 0) return <i>{_t("None")}</i>;
|
||||||
|
|
||||||
const tiles = [];
|
const tiles: JSX.Element[] = [];
|
||||||
for (const rule of rules) {
|
for (const rule of rules) {
|
||||||
tiles.push(
|
tiles.push(
|
||||||
<li key={rule.kind + rule.entity}>
|
<li key={rule.kind + rule.entity}>
|
||||||
|
@ -173,7 +173,7 @@ export default class MjolnirUserSettingsTab extends React.Component<{}, IState>
|
||||||
const rules = list ? [...list.userRules, ...list.serverRules] : [];
|
const rules = list ? [...list.userRules, ...list.serverRules] : [];
|
||||||
if (!list || rules.length <= 0) return <i>{_t("You have not ignored anyone.")}</i>;
|
if (!list || rules.length <= 0) return <i>{_t("You have not ignored anyone.")}</i>;
|
||||||
|
|
||||||
const tiles = [];
|
const tiles: JSX.Element[] = [];
|
||||||
for (const rule of rules) {
|
for (const rule of rules) {
|
||||||
tiles.push(
|
tiles.push(
|
||||||
<li key={rule.entity} className="mx_MjolnirUserSettingsTab_listItem">
|
<li key={rule.entity} className="mx_MjolnirUserSettingsTab_listItem">
|
||||||
|
@ -205,7 +205,7 @@ export default class MjolnirUserSettingsTab extends React.Component<{}, IState>
|
||||||
});
|
});
|
||||||
if (!lists || lists.length <= 0) return <i>{_t("You are not subscribed to any lists")}</i>;
|
if (!lists || lists.length <= 0) return <i>{_t("You are not subscribed to any lists")}</i>;
|
||||||
|
|
||||||
const tiles = [];
|
const tiles: JSX.Element[] = [];
|
||||||
for (const list of lists) {
|
for (const list of lists) {
|
||||||
const room = MatrixClientPeg.get().getRoom(list.roomId);
|
const room = MatrixClientPeg.get().getRoom(list.roomId);
|
||||||
const name = room ? (
|
const name = room ? (
|
||||||
|
|
|
@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
|
||||||
limitations under the License.
|
limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import React from "react";
|
import React, { ReactNode } from "react";
|
||||||
import { sleep } from "matrix-js-sdk/src/utils";
|
import { sleep } from "matrix-js-sdk/src/utils";
|
||||||
import { Room, RoomEvent } from "matrix-js-sdk/src/models/room";
|
import { Room, RoomEvent } from "matrix-js-sdk/src/models/room";
|
||||||
import { logger } from "matrix-js-sdk/src/logger";
|
import { logger } from "matrix-js-sdk/src/logger";
|
||||||
|
@ -169,7 +169,7 @@ export default class SecurityUserSettingsTab extends React.Component<IProps, ISt
|
||||||
return MatrixClientPeg.get()
|
return MatrixClientPeg.get()
|
||||||
.getRooms()
|
.getRooms()
|
||||||
.filter((r) => {
|
.filter((r) => {
|
||||||
return r.hasMembershipState(MatrixClientPeg.get().getUserId(), "invite");
|
return r.hasMembershipState(MatrixClientPeg.get().getUserId()!, "invite");
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -247,7 +247,7 @@ export default class SecurityUserSettingsTab extends React.Component<IProps, ISt
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
private renderManageInvites(): JSX.Element {
|
private renderManageInvites(): ReactNode {
|
||||||
const { invitedRoomIds } = this.state;
|
const { invitedRoomIds } = this.state;
|
||||||
|
|
||||||
if (invitedRoomIds.size === 0) {
|
if (invitedRoomIds.size === 0) {
|
||||||
|
|
|
@ -15,7 +15,7 @@ See the License for the specific language governing permissions and
|
||||||
limitations under the License.
|
limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import React from "react";
|
import React, { ReactNode } from "react";
|
||||||
|
|
||||||
import { _t } from "../../../../../languageHandler";
|
import { _t } from "../../../../../languageHandler";
|
||||||
import MediaDeviceHandler, { IMediaDevices, MediaDeviceKindEnum } from "../../../../../MediaDeviceHandler";
|
import MediaDeviceHandler, { IMediaDevices, MediaDeviceKindEnum } from "../../../../../MediaDeviceHandler";
|
||||||
|
@ -28,10 +28,10 @@ import LabelledToggleSwitch from "../../../elements/LabelledToggleSwitch";
|
||||||
import { requestMediaPermissions } from "../../../../../utils/media/requestMediaPermissions";
|
import { requestMediaPermissions } from "../../../../../utils/media/requestMediaPermissions";
|
||||||
|
|
||||||
interface IState {
|
interface IState {
|
||||||
mediaDevices: IMediaDevices;
|
mediaDevices: IMediaDevices | null;
|
||||||
[MediaDeviceKindEnum.AudioOutput]: string;
|
[MediaDeviceKindEnum.AudioOutput]: string | null;
|
||||||
[MediaDeviceKindEnum.AudioInput]: string;
|
[MediaDeviceKindEnum.AudioInput]: string | null;
|
||||||
[MediaDeviceKindEnum.VideoInput]: string;
|
[MediaDeviceKindEnum.VideoInput]: string | null;
|
||||||
audioAutoGainControl: boolean;
|
audioAutoGainControl: boolean;
|
||||||
audioEchoCancellation: boolean;
|
audioEchoCancellation: boolean;
|
||||||
audioNoiseSuppression: boolean;
|
audioNoiseSuppression: boolean;
|
||||||
|
@ -104,7 +104,7 @@ export default class VoiceUserSettingsTab extends React.Component<{}, IState> {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private renderDropdown(kind: MediaDeviceKindEnum, label: string): JSX.Element {
|
private renderDropdown(kind: MediaDeviceKindEnum, label: string): ReactNode {
|
||||||
const devices = this.state.mediaDevices[kind].slice(0);
|
const devices = this.state.mediaDevices[kind].slice(0);
|
||||||
if (devices.length === 0) return null;
|
if (devices.length === 0) return null;
|
||||||
|
|
||||||
|
@ -121,11 +121,11 @@ export default class VoiceUserSettingsTab extends React.Component<{}, IState> {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public render(): React.ReactNode {
|
public render(): ReactNode {
|
||||||
let requestButton = null;
|
let requestButton: ReactNode | undefined;
|
||||||
let speakerDropdown = null;
|
let speakerDropdown: ReactNode | undefined;
|
||||||
let microphoneDropdown = null;
|
let microphoneDropdown: ReactNode | undefined;
|
||||||
let webcamDropdown = null;
|
let webcamDropdown: ReactNode | undefined;
|
||||||
if (!this.state.mediaDevices) {
|
if (!this.state.mediaDevices) {
|
||||||
requestButton = (
|
requestButton = (
|
||||||
<div className="mx_VoiceUserSettingsTab_missingMediaPermissions">
|
<div className="mx_VoiceUserSettingsTab_missingMediaPermissions">
|
||||||
|
|
|
@ -46,8 +46,8 @@ const QuickSettingsButton: React.FC<{
|
||||||
const { [MetaSpace.Favourites]: favouritesEnabled, [MetaSpace.People]: peopleEnabled } =
|
const { [MetaSpace.Favourites]: favouritesEnabled, [MetaSpace.People]: peopleEnabled } =
|
||||||
useSettingValue<Record<MetaSpace, boolean>>("Spaces.enabledMetaSpaces");
|
useSettingValue<Record<MetaSpace, boolean>>("Spaces.enabledMetaSpaces");
|
||||||
|
|
||||||
let contextMenu: JSX.Element;
|
let contextMenu: JSX.Element | undefined;
|
||||||
if (menuDisplayed) {
|
if (menuDisplayed && handle.current) {
|
||||||
contextMenu = (
|
contextMenu = (
|
||||||
<ContextMenu
|
<ContextMenu
|
||||||
{...alwaysAboveRightOf(handle.current.getBoundingClientRect(), ChevronFace.None, 16)}
|
{...alwaysAboveRightOf(handle.current.getBoundingClientRect(), ChevronFace.None, 16)}
|
||||||
|
|
|
@ -38,9 +38,9 @@ const SpaceSettingsGeneralTab: React.FC<IProps> = ({ matrixClient: cli, space, o
|
||||||
const [busy, setBusy] = useState(false);
|
const [busy, setBusy] = useState(false);
|
||||||
const [error, setError] = useState("");
|
const [error, setError] = useState("");
|
||||||
|
|
||||||
const userId = cli.getUserId();
|
const userId = cli.getUserId()!;
|
||||||
|
|
||||||
const [newAvatar, setNewAvatar] = useState<File>(null); // undefined means to remove avatar
|
const [newAvatar, setNewAvatar] = useState<File | null | undefined>(null); // undefined means to remove avatar
|
||||||
const canSetAvatar = space.currentState.maySendStateEvent(EventType.RoomAvatar, userId);
|
const canSetAvatar = space.currentState.maySendStateEvent(EventType.RoomAvatar, userId);
|
||||||
const avatarChanged = newAvatar !== null;
|
const avatarChanged = newAvatar !== null;
|
||||||
|
|
||||||
|
@ -48,8 +48,8 @@ const SpaceSettingsGeneralTab: React.FC<IProps> = ({ matrixClient: cli, space, o
|
||||||
const canSetName = space.currentState.maySendStateEvent(EventType.RoomName, userId);
|
const canSetName = space.currentState.maySendStateEvent(EventType.RoomName, userId);
|
||||||
const nameChanged = name !== space.name;
|
const nameChanged = name !== space.name;
|
||||||
|
|
||||||
const currentTopic = getTopic(space)?.text;
|
const currentTopic = getTopic(space)?.text ?? "";
|
||||||
const [topic, setTopic] = useState<string>(currentTopic);
|
const [topic, setTopic] = useState(currentTopic);
|
||||||
const canSetTopic = space.currentState.maySendStateEvent(EventType.RoomTopic, userId);
|
const canSetTopic = space.currentState.maySendStateEvent(EventType.RoomTopic, userId);
|
||||||
const topicChanged = topic !== currentTopic;
|
const topicChanged = topic !== currentTopic;
|
||||||
|
|
||||||
|
@ -104,7 +104,7 @@ const SpaceSettingsGeneralTab: React.FC<IProps> = ({ matrixClient: cli, space, o
|
||||||
|
|
||||||
<div className="mx_SettingsTab_section">
|
<div className="mx_SettingsTab_section">
|
||||||
<SpaceBasicSettings
|
<SpaceBasicSettings
|
||||||
avatarUrl={avatarUrlForRoom(space, 80, 80, "crop")}
|
avatarUrl={avatarUrlForRoom(space, 80, 80, "crop") ?? undefined}
|
||||||
avatarDisabled={busy || !canSetAvatar}
|
avatarDisabled={busy || !canSetAvatar}
|
||||||
setAvatar={setNewAvatar}
|
setAvatar={setNewAvatar}
|
||||||
name={name}
|
name={name}
|
||||||
|
|
|
@ -47,7 +47,7 @@ const SpaceSettingsVisibilityTab: React.FC<IProps> = ({ matrixClient: cli, space
|
||||||
false,
|
false,
|
||||||
);
|
);
|
||||||
|
|
||||||
const userId = cli.getUserId();
|
const userId = cli.getUserId()!;
|
||||||
|
|
||||||
const joinRule = useRoomState(space, (state) => state.getJoinRule());
|
const joinRule = useRoomState(space, (state) => state.getJoinRule());
|
||||||
const [guestAccessEnabled, setGuestAccessEnabled] = useLocalEcho<boolean>(
|
const [guestAccessEnabled, setGuestAccessEnabled] = useLocalEcho<boolean>(
|
||||||
|
@ -120,7 +120,7 @@ const SpaceSettingsVisibilityTab: React.FC<IProps> = ({ matrixClient: cli, space
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
let addressesSection;
|
let addressesSection: JSX.Element | undefined;
|
||||||
if (space.getJoinRule() === JoinRule.Public) {
|
if (space.getJoinRule() === JoinRule.Public) {
|
||||||
addressesSection = (
|
addressesSection = (
|
||||||
<>
|
<>
|
||||||
|
@ -129,7 +129,7 @@ const SpaceSettingsVisibilityTab: React.FC<IProps> = ({ matrixClient: cli, space
|
||||||
roomId={space.roomId}
|
roomId={space.roomId}
|
||||||
canSetCanonicalAlias={canSetCanonical}
|
canSetCanonicalAlias={canSetCanonical}
|
||||||
canSetAliases={true}
|
canSetAliases={true}
|
||||||
canonicalAliasEvent={canonicalAliasEv}
|
canonicalAliasEvent={canonicalAliasEv ?? undefined}
|
||||||
hidePublishSetting={!serverSupportsExploringSpaces}
|
hidePublishSetting={!serverSupportsExploringSpaces}
|
||||||
/>
|
/>
|
||||||
</>
|
</>
|
||||||
|
|
|
@ -83,7 +83,7 @@ export default class InlineTermsAgreement extends React.Component<IProps, IState
|
||||||
};
|
};
|
||||||
|
|
||||||
private renderCheckboxes(): React.ReactNode[] {
|
private renderCheckboxes(): React.ReactNode[] {
|
||||||
const rendered = [];
|
const rendered: JSX.Element[] = [];
|
||||||
for (let i = 0; i < this.state.policies.length; i++) {
|
for (let i = 0; i < this.state.policies.length; i++) {
|
||||||
const policy = this.state.policies[i];
|
const policy = this.state.policies[i];
|
||||||
const introText = _t(
|
const introText = _t(
|
||||||
|
|
|
@ -77,7 +77,7 @@ export default class VerificationRequestToast extends React.PureComponent<IProps
|
||||||
const device = await cli.getDevice(request.channel.deviceId);
|
const device = await cli.getDevice(request.channel.deviceId);
|
||||||
const ip = device.last_seen_ip;
|
const ip = device.last_seen_ip;
|
||||||
this.setState({
|
this.setState({
|
||||||
device: cli.getStoredDevice(cli.getUserId(), request.channel.deviceId),
|
device: cli.getStoredDevice(cli.getUserId()!, request.channel.deviceId),
|
||||||
ip,
|
ip,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -137,7 +137,7 @@ export default class VerificationRequestToast extends React.PureComponent<IProps
|
||||||
request.cancel();
|
request.cancel();
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
null,
|
undefined,
|
||||||
/* priority = */ false,
|
/* priority = */ false,
|
||||||
/* static = */ true,
|
/* static = */ true,
|
||||||
);
|
);
|
||||||
|
|
|
@ -39,7 +39,7 @@ export function UserOnboardingButton({ selected, minimized }: Props): JSX.Elemen
|
||||||
const visible = useSettingValue<boolean>("FTUE.userOnboardingButton");
|
const visible = useSettingValue<boolean>("FTUE.userOnboardingButton");
|
||||||
|
|
||||||
if (!visible || minimized || !showUserOnboardingPage(useCase)) {
|
if (!visible || minimized || !showUserOnboardingPage(useCase)) {
|
||||||
return null;
|
return <></>;
|
||||||
}
|
}
|
||||||
|
|
||||||
return <UserOnboardingButtonInternal selected={selected} minimized={minimized} />;
|
return <UserOnboardingButtonInternal selected={selected} minimized={minimized} />;
|
||||||
|
|
|
@ -26,7 +26,7 @@ import { shouldShowFeedback } from "../../../utils/Feedback";
|
||||||
|
|
||||||
export function UserOnboardingFeedback(): JSX.Element {
|
export function UserOnboardingFeedback(): JSX.Element {
|
||||||
if (!shouldShowFeedback()) {
|
if (!shouldShowFeedback()) {
|
||||||
return null;
|
return <></>;
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|
|
@ -57,7 +57,7 @@ export function UserOnboardingTask({ task, completed = false }: Props): JSX.Elem
|
||||||
kind="primary_outline"
|
kind="primary_outline"
|
||||||
href={task.action.href}
|
href={task.action.href}
|
||||||
target="_blank"
|
target="_blank"
|
||||||
onClick={task.action.onClick}
|
onClick={task.action.onClick ?? null}
|
||||||
>
|
>
|
||||||
{task.action.label}
|
{task.action.label}
|
||||||
</AccessibleButton>
|
</AccessibleButton>
|
||||||
|
|
|
@ -150,7 +150,7 @@ export const Lobby: FC<LobbyProps> = ({ room, joinCallButtonDisabledTooltip, con
|
||||||
}, [videoMuted, setVideoMuted]);
|
}, [videoMuted, setVideoMuted]);
|
||||||
|
|
||||||
const [videoStream, audioInputs, videoInputs] = useAsyncMemo(
|
const [videoStream, audioInputs, videoInputs] = useAsyncMemo(
|
||||||
async (): Promise<[MediaStream, MediaDeviceInfo[], MediaDeviceInfo[]]> => {
|
async (): Promise<[MediaStream | null, MediaDeviceInfo[], MediaDeviceInfo[]]> => {
|
||||||
let devices = await MediaDeviceHandler.getDevices();
|
let devices = await MediaDeviceHandler.getDevices();
|
||||||
|
|
||||||
// We get the preview stream before requesting devices: this is because
|
// We get the preview stream before requesting devices: this is because
|
||||||
|
@ -335,7 +335,7 @@ const StartCallView: FC<StartCallViewProps> = ({ room, resizing, call, setStarti
|
||||||
<AppTile
|
<AppTile
|
||||||
app={call.widget}
|
app={call.widget}
|
||||||
room={room}
|
room={room}
|
||||||
userId={cli.credentials.userId}
|
userId={cli.credentials.userId!}
|
||||||
creatorUserId={call.widget.creatorUserId}
|
creatorUserId={call.widget.creatorUserId}
|
||||||
waitForIframeLoad={call.widget.waitForIframeLoad}
|
waitForIframeLoad={call.widget.waitForIframeLoad}
|
||||||
showMenubar={false}
|
showMenubar={false}
|
||||||
|
@ -402,7 +402,7 @@ const JoinCallView: FC<JoinCallViewProps> = ({ room, resizing, call }) => {
|
||||||
<AppTile
|
<AppTile
|
||||||
app={call.widget}
|
app={call.widget}
|
||||||
room={room}
|
room={room}
|
||||||
userId={cli.credentials.userId}
|
userId={cli.credentials.userId!}
|
||||||
creatorUserId={call.widget.creatorUserId}
|
creatorUserId={call.widget.creatorUserId}
|
||||||
waitForIframeLoad={call.widget.waitForIframeLoad}
|
waitForIframeLoad={call.widget.waitForIframeLoad}
|
||||||
showMenubar={false}
|
showMenubar={false}
|
||||||
|
|
|
@ -180,7 +180,7 @@ export default class LegacyCallView extends React.Component<IProps, IState> {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
private updateCallListeners(oldCall: MatrixCall, newCall: MatrixCall): void {
|
private updateCallListeners(oldCall: MatrixCall, newCall: MatrixCall | null): void {
|
||||||
if (oldCall === newCall) return;
|
if (oldCall === newCall) return;
|
||||||
|
|
||||||
if (oldCall) {
|
if (oldCall) {
|
||||||
|
@ -430,7 +430,7 @@ export default class LegacyCallView extends React.Component<IProps, IState> {
|
||||||
const { pipMode, call, onResize } = this.props;
|
const { pipMode, call, onResize } = this.props;
|
||||||
const { isLocalOnHold, isRemoteOnHold, sidebarShown, primaryFeed, secondaryFeed, sidebarFeeds } = this.state;
|
const { isLocalOnHold, isRemoteOnHold, sidebarShown, primaryFeed, secondaryFeed, sidebarFeeds } = this.state;
|
||||||
|
|
||||||
const callRoom = MatrixClientPeg.get().getRoom(call.roomId);
|
const callRoom = MatrixClientPeg.get().getRoom(call.roomId) ?? undefined;
|
||||||
const avatarSize = pipMode ? 76 : 160;
|
const avatarSize = pipMode ? 76 : 160;
|
||||||
const transfereeCall = LegacyCallHandler.instance.getTransfereeForCallId(call.callId);
|
const transfereeCall = LegacyCallHandler.instance.getTransfereeForCallId(call.callId);
|
||||||
const isOnHold = isLocalOnHold || isRemoteOnHold;
|
const isOnHold = isLocalOnHold || isRemoteOnHold;
|
||||||
|
|
|
@ -190,6 +190,8 @@ function getTextAndOffsetToNode(editor: HTMLDivElement, selectionNode: Node): {
|
||||||
// get text value of text node, ignoring ZWS if it's a caret node
|
// get text value of text node, ignoring ZWS if it's a caret node
|
||||||
function getTextNodeValue(node: Node): string {
|
function getTextNodeValue(node: Node): string {
|
||||||
const nodeText = node.nodeValue;
|
const nodeText = node.nodeValue;
|
||||||
|
if (!nodeText) return "";
|
||||||
|
|
||||||
// filter out ZWS for caret nodes
|
// filter out ZWS for caret nodes
|
||||||
if (isCaretNode(node.parentElement)) {
|
if (isCaretNode(node.parentElement)) {
|
||||||
// typed in the caret node, so there is now something more in it than the ZWS
|
// typed in the caret node, so there is now something more in it than the ZWS
|
||||||
|
@ -200,9 +202,9 @@ function getTextNodeValue(node: Node): string {
|
||||||
// only contains ZWS, which is ignored, so return empty string
|
// only contains ZWS, which is ignored, so return empty string
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
return nodeText;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return nodeText;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getRangeForSelection(editor: HTMLDivElement, model: EditorModel, selection: Selection): Range {
|
export function getRangeForSelection(editor: HTMLDivElement, model: EditorModel, selection: Selection): Range {
|
||||||
|
|
|
@ -424,7 +424,7 @@ class RoomPillPart extends PillPart {
|
||||||
let initialLetter = "";
|
let initialLetter = "";
|
||||||
let avatarUrl = Avatar.avatarUrlForRoom(this.room, 16, 16, "crop");
|
let avatarUrl = Avatar.avatarUrlForRoom(this.room, 16, 16, "crop");
|
||||||
if (!avatarUrl) {
|
if (!avatarUrl) {
|
||||||
initialLetter = Avatar.getInitialLetter(this.room?.name || this.resourceId);
|
initialLetter = Avatar.getInitialLetter(this.room?.name || this.resourceId) ?? "";
|
||||||
avatarUrl = Avatar.defaultAvatarUrlForString(this.room?.roomId ?? this.resourceId);
|
avatarUrl = Avatar.defaultAvatarUrlForString(this.room?.roomId ?? this.resourceId);
|
||||||
}
|
}
|
||||||
this.setAvatarVars(node, avatarUrl, initialLetter);
|
this.setAvatarVars(node, avatarUrl, initialLetter);
|
||||||
|
@ -478,7 +478,7 @@ class UserPillPart extends PillPart {
|
||||||
const avatarUrl = Avatar.avatarUrlForMember(this.member, 16, 16, "crop");
|
const avatarUrl = Avatar.avatarUrlForMember(this.member, 16, 16, "crop");
|
||||||
let initialLetter = "";
|
let initialLetter = "";
|
||||||
if (avatarUrl === defaultAvatarUrl) {
|
if (avatarUrl === defaultAvatarUrl) {
|
||||||
initialLetter = Avatar.getInitialLetter(name);
|
initialLetter = Avatar.getInitialLetter(name) ?? "";
|
||||||
}
|
}
|
||||||
this.setAvatarVars(node, avatarUrl, initialLetter);
|
this.setAvatarVars(node, avatarUrl, initialLetter);
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,7 +18,9 @@ import { useState, useEffect, DependencyList } from "react";
|
||||||
|
|
||||||
type Fn<T> = () => Promise<T>;
|
type Fn<T> = () => Promise<T>;
|
||||||
|
|
||||||
export const useAsyncMemo = <T>(fn: Fn<T>, deps: DependencyList, initialValue?: T): T | undefined => {
|
export function useAsyncMemo<T>(fn: Fn<T>, deps: DependencyList, initialValue: T): T;
|
||||||
|
export function useAsyncMemo<T>(fn: Fn<T>, deps: DependencyList, initialValue?: T): T | undefined;
|
||||||
|
export function useAsyncMemo<T>(fn: Fn<T>, deps: DependencyList, initialValue?: T): T | undefined {
|
||||||
const [value, setValue] = useState<T | undefined>(initialValue);
|
const [value, setValue] = useState<T | undefined>(initialValue);
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
let discard = false;
|
let discard = false;
|
||||||
|
@ -32,4 +34,4 @@ export const useAsyncMemo = <T>(fn: Fn<T>, deps: DependencyList, initialValue?:
|
||||||
};
|
};
|
||||||
}, deps); // eslint-disable-line react-hooks/exhaustive-deps
|
}, deps); // eslint-disable-line react-hooks/exhaustive-deps
|
||||||
return value;
|
return value;
|
||||||
};
|
}
|
||||||
|
|
|
@ -37,7 +37,7 @@ interface UserOnboardingTask {
|
||||||
relevant?: UseCase[];
|
relevant?: UseCase[];
|
||||||
action?: {
|
action?: {
|
||||||
label: string;
|
label: string;
|
||||||
onClick?: (ev?: ButtonEvent) => void;
|
onClick?: (ev: ButtonEvent) => void;
|
||||||
href?: string;
|
href?: string;
|
||||||
hideOnComplete?: boolean;
|
hideOnComplete?: boolean;
|
||||||
};
|
};
|
||||||
|
|
|
@ -87,7 +87,7 @@ export function _td(s: string): string {
|
||||||
* for this reason, force fallbackLocale === locale in the first call to translate
|
* for this reason, force fallbackLocale === locale in the first call to translate
|
||||||
* and fallback 'manually' so we can mark fallback strings appropriately
|
* and fallback 'manually' so we can mark fallback strings appropriately
|
||||||
* */
|
* */
|
||||||
const translateWithFallback = (text: string, options?: IVariables): { translated?: string; isFallback?: boolean } => {
|
const translateWithFallback = (text: string, options?: IVariables): { translated: string; isFallback?: boolean } => {
|
||||||
const translated = counterpart.translate(text, { ...options, fallbackLocale: counterpart.getLocale() });
|
const translated = counterpart.translate(text, { ...options, fallbackLocale: counterpart.getLocale() });
|
||||||
if (!translated || translated.startsWith("missing translation:")) {
|
if (!translated || translated.startsWith("missing translation:")) {
|
||||||
const fallbackTranslated = counterpart.translate(text, { ...options, locale: FALLBACK_LOCALE });
|
const fallbackTranslated = counterpart.translate(text, { ...options, locale: FALLBACK_LOCALE });
|
||||||
|
@ -117,7 +117,7 @@ const translateWithFallback = (text: string, options?: IVariables): { translated
|
||||||
|
|
||||||
// Wrapper for counterpart's translation function so that it handles nulls and undefineds properly
|
// Wrapper for counterpart's translation function so that it handles nulls and undefineds properly
|
||||||
// Takes the same arguments as counterpart.translate()
|
// Takes the same arguments as counterpart.translate()
|
||||||
function safeCounterpartTranslate(text: string, variables?: IVariables): { translated?: string; isFallback?: boolean } {
|
function safeCounterpartTranslate(text: string, variables?: IVariables): { translated: string; isFallback?: boolean } {
|
||||||
// Don't do substitutions in counterpart. We handle it ourselves so we can replace with React components
|
// Don't do substitutions in counterpart. We handle it ourselves so we can replace with React components
|
||||||
// However, still pass the variables to counterpart so that it can choose the correct plural if count is given
|
// However, still pass the variables to counterpart so that it can choose the correct plural if count is given
|
||||||
// It is enough to pass the count variable, but in the future counterpart might make use of other information too
|
// It is enough to pass the count variable, but in the future counterpart might make use of other information too
|
||||||
|
@ -251,7 +251,7 @@ export function sanitizeForTranslation(text: string): string {
|
||||||
* @return a React <span> component if any non-strings were used in substitutions, otherwise a string
|
* @return a React <span> component if any non-strings were used in substitutions, otherwise a string
|
||||||
*/
|
*/
|
||||||
export function substitute(text: string, variables?: IVariables): string;
|
export function substitute(text: string, variables?: IVariables): string;
|
||||||
export function substitute(text: string, variables: IVariables, tags: Tags): string;
|
export function substitute(text: string, variables: IVariables | undefined, tags: Tags | undefined): string;
|
||||||
export function substitute(text: string, variables?: IVariables, tags?: Tags): string | React.ReactNode {
|
export function substitute(text: string, variables?: IVariables, tags?: Tags): string | React.ReactNode {
|
||||||
let result: React.ReactNode | string = text;
|
let result: React.ReactNode | string = text;
|
||||||
|
|
||||||
|
@ -619,7 +619,7 @@ let cachedCustomTranslationsExpire = 0; // zero to trigger expiration right away
|
||||||
// This awkward class exists so the test runner can get at the function. It is
|
// This awkward class exists so the test runner can get at the function. It is
|
||||||
// not intended for practical or realistic usage.
|
// not intended for practical or realistic usage.
|
||||||
export class CustomTranslationOptions {
|
export class CustomTranslationOptions {
|
||||||
public static lookupFn: (url: string) => ICustomTranslations;
|
public static lookupFn?: (url: string) => ICustomTranslations;
|
||||||
|
|
||||||
private constructor() {
|
private constructor() {
|
||||||
// static access for tests only
|
// static access for tests only
|
||||||
|
|
|
@ -74,7 +74,7 @@ export class VoiceRecordingStore extends AsyncStoreWithClient<IState> {
|
||||||
* @param {string} voiceRecordingId The room ID (with optionally the thread ID if in one) to start recording in.
|
* @param {string} voiceRecordingId The room ID (with optionally the thread ID if in one) to start recording in.
|
||||||
* @returns {VoiceRecording} The recording.
|
* @returns {VoiceRecording} The recording.
|
||||||
*/
|
*/
|
||||||
public startRecording(voiceRecordingId: string): VoiceMessageRecording {
|
public startRecording(voiceRecordingId?: string): VoiceMessageRecording {
|
||||||
if (!this.matrixClient) throw new Error("Cannot start a recording without a MatrixClient");
|
if (!this.matrixClient) throw new Error("Cannot start a recording without a MatrixClient");
|
||||||
if (!voiceRecordingId) throw new Error("Recording must be associated with a room");
|
if (!voiceRecordingId) throw new Error("Recording must be associated with a room");
|
||||||
if (this.state[voiceRecordingId]) throw new Error("A recording is already in progress");
|
if (this.state[voiceRecordingId]) throw new Error("A recording is already in progress");
|
||||||
|
|
|
@ -218,15 +218,15 @@ export class StopGapWidgetDriver extends WidgetDriver {
|
||||||
public async sendEvent(
|
public async sendEvent(
|
||||||
eventType: string,
|
eventType: string,
|
||||||
content: IContent,
|
content: IContent,
|
||||||
stateKey: string = null,
|
stateKey?: string,
|
||||||
targetRoomId: string = null,
|
targetRoomId?: string,
|
||||||
): Promise<ISendEventDetails> {
|
): Promise<ISendEventDetails> {
|
||||||
const client = MatrixClientPeg.get();
|
const client = MatrixClientPeg.get();
|
||||||
const roomId = targetRoomId || SdkContextClass.instance.roomViewStore.getRoomId();
|
const roomId = targetRoomId || SdkContextClass.instance.roomViewStore.getRoomId();
|
||||||
|
|
||||||
if (!client || !roomId) throw new Error("Not in a room or not attached to a client");
|
if (!client || !roomId) throw new Error("Not in a room or not attached to a client");
|
||||||
|
|
||||||
let r: { event_id: string } = null; // eslint-disable-line camelcase
|
let r: { event_id: string } | null = null; // eslint-disable-line camelcase
|
||||||
if (stateKey !== null) {
|
if (stateKey !== null) {
|
||||||
// state event
|
// state event
|
||||||
r = await client.sendStateEvent(roomId, eventType, content, stateKey);
|
r = await client.sendStateEvent(roomId, eventType, content, stateKey);
|
||||||
|
@ -242,7 +242,7 @@ export class StopGapWidgetDriver extends WidgetDriver {
|
||||||
if (containsEmoji(content, effect.emojis)) {
|
if (containsEmoji(content, effect.emojis)) {
|
||||||
// For initial threads launch, chat effects are disabled
|
// For initial threads launch, chat effects are disabled
|
||||||
// see #19731
|
// see #19731
|
||||||
const isNotThread = content["m.relates_to"].rel_type !== THREAD_RELATION_TYPE.name;
|
const isNotThread = content["m.relates_to"]?.rel_type !== THREAD_RELATION_TYPE.name;
|
||||||
if (!SettingsStore.getValue("feature_threadenabled") || isNotThread) {
|
if (!SettingsStore.getValue("feature_threadenabled") || isNotThread) {
|
||||||
dis.dispatch({ action: `effects.${effect.command}` });
|
dis.dispatch({ action: `effects.${effect.command}` });
|
||||||
}
|
}
|
||||||
|
@ -300,7 +300,7 @@ export class StopGapWidgetDriver extends WidgetDriver {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private pickRooms(roomIds: (string | Symbols.AnyRoom)[] = null): Room[] {
|
private pickRooms(roomIds?: (string | Symbols.AnyRoom)[]): Room[] {
|
||||||
const client = MatrixClientPeg.get();
|
const client = MatrixClientPeg.get();
|
||||||
if (!client) throw new Error("Not attached to a client");
|
if (!client) throw new Error("Not attached to a client");
|
||||||
|
|
||||||
|
@ -309,14 +309,14 @@ export class StopGapWidgetDriver extends WidgetDriver {
|
||||||
? client.getVisibleRooms()
|
? client.getVisibleRooms()
|
||||||
: roomIds.map((r) => client.getRoom(r))
|
: roomIds.map((r) => client.getRoom(r))
|
||||||
: [client.getRoom(SdkContextClass.instance.roomViewStore.getRoomId())];
|
: [client.getRoom(SdkContextClass.instance.roomViewStore.getRoomId())];
|
||||||
return targetRooms.filter((r) => !!r);
|
return targetRooms.filter((r) => !!r) as Room[];
|
||||||
}
|
}
|
||||||
|
|
||||||
public async readRoomEvents(
|
public async readRoomEvents(
|
||||||
eventType: string,
|
eventType: string,
|
||||||
msgtype: string | undefined,
|
msgtype: string | undefined,
|
||||||
limitPerRoom: number,
|
limitPerRoom: number,
|
||||||
roomIds: (string | Symbols.AnyRoom)[] = null,
|
roomIds?: (string | Symbols.AnyRoom)[],
|
||||||
): Promise<IRoomEvent[]> {
|
): Promise<IRoomEvent[]> {
|
||||||
limitPerRoom = limitPerRoom > 0 ? Math.min(limitPerRoom, Number.MAX_SAFE_INTEGER) : Number.MAX_SAFE_INTEGER; // relatively arbitrary
|
limitPerRoom = limitPerRoom > 0 ? Math.min(limitPerRoom, Number.MAX_SAFE_INTEGER) : Number.MAX_SAFE_INTEGER; // relatively arbitrary
|
||||||
|
|
||||||
|
@ -343,7 +343,7 @@ export class StopGapWidgetDriver extends WidgetDriver {
|
||||||
eventType: string,
|
eventType: string,
|
||||||
stateKey: string | undefined,
|
stateKey: string | undefined,
|
||||||
limitPerRoom: number,
|
limitPerRoom: number,
|
||||||
roomIds: (string | Symbols.AnyRoom)[] = null,
|
roomIds?: (string | Symbols.AnyRoom)[],
|
||||||
): Promise<IRoomEvent[]> {
|
): Promise<IRoomEvent[]> {
|
||||||
limitPerRoom = limitPerRoom > 0 ? Math.min(limitPerRoom, Number.MAX_SAFE_INTEGER) : Number.MAX_SAFE_INTEGER; // relatively arbitrary
|
limitPerRoom = limitPerRoom > 0 ? Math.min(limitPerRoom, Number.MAX_SAFE_INTEGER) : Number.MAX_SAFE_INTEGER; // relatively arbitrary
|
||||||
|
|
||||||
|
@ -467,8 +467,8 @@ export class StopGapWidgetDriver extends WidgetDriver {
|
||||||
|
|
||||||
return {
|
return {
|
||||||
chunk: events.map((e) => e.getEffectiveEvent() as IRoomEvent),
|
chunk: events.map((e) => e.getEffectiveEvent() as IRoomEvent),
|
||||||
nextBatch,
|
nextBatch: nextBatch ?? undefined,
|
||||||
prevBatch,
|
prevBatch: prevBatch ?? undefined,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -48,10 +48,12 @@ export const getBeaconBounds = (beacons: Beacon[]): Bounds | undefined => {
|
||||||
const sortedByLat = [...coords].sort((left, right) => right.latitude - left.latitude);
|
const sortedByLat = [...coords].sort((left, right) => right.latitude - left.latitude);
|
||||||
const sortedByLong = [...coords].sort((left, right) => right.longitude - left.longitude);
|
const sortedByLong = [...coords].sort((left, right) => right.longitude - left.longitude);
|
||||||
|
|
||||||
|
if (sortedByLat.length < 1 || sortedByLong.length < 1) return;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
north: sortedByLat[0].latitude,
|
north: sortedByLat[0]!.latitude,
|
||||||
south: sortedByLat[sortedByLat.length - 1].latitude,
|
south: sortedByLat[sortedByLat.length - 1]!.latitude,
|
||||||
east: sortedByLong[0].longitude,
|
east: sortedByLong[0]!.longitude,
|
||||||
west: sortedByLong[sortedByLong.length - 1].longitude,
|
west: sortedByLong[sortedByLong.length - 1]!.longitude,
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
|
@ -135,7 +135,7 @@ export class CapabilityText {
|
||||||
// First see if we have a super simple line of text to provide back
|
// First see if we have a super simple line of text to provide back
|
||||||
if (CapabilityText.simpleCaps[capability]) {
|
if (CapabilityText.simpleCaps[capability]) {
|
||||||
const textForKind = CapabilityText.simpleCaps[capability];
|
const textForKind = CapabilityText.simpleCaps[capability];
|
||||||
if (textForKind[kind]) return { primary: _t(textForKind[kind]) };
|
if (textForKind[kind]) return { primary: _t(textForKind[kind]!) };
|
||||||
if (textForKind[GENERIC_WIDGET_KIND]) return { primary: _t(textForKind[GENERIC_WIDGET_KIND]) };
|
if (textForKind[GENERIC_WIDGET_KIND]) return { primary: _t(textForKind[GENERIC_WIDGET_KIND]) };
|
||||||
|
|
||||||
// ... we'll fall through to the generic capability processing at the end of this
|
// ... we'll fall through to the generic capability processing at the end of this
|
||||||
|
@ -195,8 +195,8 @@ export class CapabilityText {
|
||||||
: CapabilityText.nonStateSendRecvCaps;
|
: CapabilityText.nonStateSendRecvCaps;
|
||||||
if (evSendRecv[eventCap.eventType]) {
|
if (evSendRecv[eventCap.eventType]) {
|
||||||
const textForKind = evSendRecv[eventCap.eventType];
|
const textForKind = evSendRecv[eventCap.eventType];
|
||||||
const textForDirection = textForKind[kind] || textForKind[GENERIC_WIDGET_KIND];
|
const textForDirection = textForKind?.[kind] || textForKind?.[GENERIC_WIDGET_KIND];
|
||||||
if (textForDirection && textForDirection[eventCap.direction]) {
|
if (textForDirection?.[eventCap.direction]) {
|
||||||
return {
|
return {
|
||||||
primary: _t(textForDirection[eventCap.direction]),
|
primary: _t(textForDirection[eventCap.direction]),
|
||||||
// no byline because we would have already represented the event properly
|
// no byline because we would have already represented the event properly
|
||||||
|
|
|
@ -87,7 +87,7 @@ export class Jitsi {
|
||||||
* @param {string} url The URL to parse.
|
* @param {string} url The URL to parse.
|
||||||
* @returns {JitsiWidgetData} The widget data if eligible, otherwise null.
|
* @returns {JitsiWidgetData} The widget data if eligible, otherwise null.
|
||||||
*/
|
*/
|
||||||
public parsePreferredConferenceUrl(url: string): JitsiWidgetData {
|
public parsePreferredConferenceUrl(url: string): JitsiWidgetData | null {
|
||||||
const parsed = new URL(url);
|
const parsed = new URL(url);
|
||||||
if (parsed.hostname !== this.preferredDomain) return null; // invalid
|
if (parsed.hostname !== this.preferredDomain) return null; // invalid
|
||||||
return {
|
return {
|
||||||
|
|
|
@ -57,7 +57,7 @@ describe("PosthogAnalytics", () => {
|
||||||
digest: async (_: AlgorithmIdentifier, encodedMessage: BufferSource) => {
|
digest: async (_: AlgorithmIdentifier, encodedMessage: BufferSource) => {
|
||||||
const message = new TextDecoder().decode(encodedMessage);
|
const message = new TextDecoder().decode(encodedMessage);
|
||||||
const hexHash = shaHashes[message];
|
const hexHash = shaHashes[message];
|
||||||
const bytes = [];
|
const bytes: number[] = [];
|
||||||
for (let c = 0; c < hexHash.length; c += 2) {
|
for (let c = 0; c < hexHash.length; c += 2) {
|
||||||
bytes.push(parseInt(hexHash.slice(c, c + 2), 16));
|
bytes.push(parseInt(hexHash.slice(c, c + 2), 16));
|
||||||
}
|
}
|
||||||
|
@ -68,6 +68,7 @@ describe("PosthogAnalytics", () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
afterEach(() => {
|
afterEach(() => {
|
||||||
|
// @ts-ignore
|
||||||
window.crypto = null;
|
window.crypto = null;
|
||||||
SdkConfig.unset(); // we touch the config, so clean up
|
SdkConfig.unset(); // we touch the config, so clean up
|
||||||
});
|
});
|
||||||
|
@ -116,7 +117,7 @@ describe("PosthogAnalytics", () => {
|
||||||
foo: "bar",
|
foo: "bar",
|
||||||
});
|
});
|
||||||
expect(mocked(fakePosthog).capture.mock.calls[0][0]).toBe("JestTestEvents");
|
expect(mocked(fakePosthog).capture.mock.calls[0][0]).toBe("JestTestEvents");
|
||||||
expect(mocked(fakePosthog).capture.mock.calls[0][1]["foo"]).toEqual("bar");
|
expect(mocked(fakePosthog).capture.mock.calls[0][1]!["foo"]).toEqual("bar");
|
||||||
});
|
});
|
||||||
|
|
||||||
it("Should not track events if anonymous", async () => {
|
it("Should not track events if anonymous", async () => {
|
||||||
|
@ -209,7 +210,7 @@ describe("PosthogAnalytics", () => {
|
||||||
analytics.trackEvent<ITestEvent>({
|
analytics.trackEvent<ITestEvent>({
|
||||||
eventName: "JestTestEvents",
|
eventName: "JestTestEvents",
|
||||||
});
|
});
|
||||||
expect(mocked(fakePosthog).capture.mock.calls[0][1]["$set"]).toStrictEqual({
|
expect(mocked(fakePosthog).capture.mock.calls[0][1]!["$set"]).toStrictEqual({
|
||||||
WebLayout: "IRC",
|
WebLayout: "IRC",
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -226,7 +227,7 @@ describe("PosthogAnalytics", () => {
|
||||||
analytics.trackEvent<ITestEvent>({
|
analytics.trackEvent<ITestEvent>({
|
||||||
eventName: "JestTestEvents",
|
eventName: "JestTestEvents",
|
||||||
});
|
});
|
||||||
expect(mocked(fakePosthog).capture.mock.calls[0][1]["$set"]).toStrictEqual({
|
expect(mocked(fakePosthog).capture.mock.calls[0][1]!["$set"]).toStrictEqual({
|
||||||
WebLayout: "Bubble",
|
WebLayout: "Bubble",
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -243,7 +244,7 @@ describe("PosthogAnalytics", () => {
|
||||||
analytics.trackEvent<ITestEvent>({
|
analytics.trackEvent<ITestEvent>({
|
||||||
eventName: "JestTestEvents",
|
eventName: "JestTestEvents",
|
||||||
});
|
});
|
||||||
expect(mocked(fakePosthog).capture.mock.calls[0][1]["$set"]).toStrictEqual({
|
expect(mocked(fakePosthog).capture.mock.calls[0][1]!["$set"]).toStrictEqual({
|
||||||
WebLayout: "Group",
|
WebLayout: "Group",
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -261,7 +262,7 @@ describe("PosthogAnalytics", () => {
|
||||||
analytics.trackEvent<ITestEvent>({
|
analytics.trackEvent<ITestEvent>({
|
||||||
eventName: "JestTestEvents",
|
eventName: "JestTestEvents",
|
||||||
});
|
});
|
||||||
expect(mocked(fakePosthog).capture.mock.calls[0][1]["$set"]).toStrictEqual({
|
expect(mocked(fakePosthog).capture.mock.calls[0][1]!["$set"]).toStrictEqual({
|
||||||
WebLayout: "Compact",
|
WebLayout: "Compact",
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -53,7 +53,7 @@ describe("ScalarAuthClient", function () {
|
||||||
client.getOpenIdToken = jest.fn().mockResolvedValue(tokenObject);
|
client.getOpenIdToken = jest.fn().mockResolvedValue(tokenObject);
|
||||||
|
|
||||||
sac.exchangeForScalarToken = jest.fn((arg) => {
|
sac.exchangeForScalarToken = jest.fn((arg) => {
|
||||||
if (arg === tokenObject) return Promise.resolve("wokentoken");
|
return Promise.resolve(arg === tokenObject ? "wokentoken" : "othertoken");
|
||||||
});
|
});
|
||||||
|
|
||||||
await sac.connect();
|
await sac.connect();
|
||||||
|
|
|
@ -223,7 +223,7 @@ describe("SlashCommands", () => {
|
||||||
const command = getCommand("/part #foo:bar");
|
const command = getCommand("/part #foo:bar");
|
||||||
expect(command.cmd).toBeDefined();
|
expect(command.cmd).toBeDefined();
|
||||||
expect(command.args).toBeDefined();
|
expect(command.args).toBeDefined();
|
||||||
await command.cmd!.run("room-id", null, command.args);
|
await command.cmd!.run("room-id", null, command.args!);
|
||||||
expect(client.leaveRoomChain).toHaveBeenCalledWith("room-id", expect.anything());
|
expect(client.leaveRoomChain).toHaveBeenCalledWith("room-id", expect.anything());
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -232,7 +232,7 @@ describe("SlashCommands", () => {
|
||||||
const command = findCommand(commandName)!;
|
const command = findCommand(commandName)!;
|
||||||
|
|
||||||
it("should return usage if no args", () => {
|
it("should return usage if no args", () => {
|
||||||
expect(command.run(roomId, null).error).toBe(command.getUsage());
|
expect(command.run(roomId, null, undefined).error).toBe(command.getUsage());
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should make things rainbowy", () => {
|
it("should make things rainbowy", () => {
|
||||||
|
|
|
@ -58,7 +58,7 @@ describe("SlidingSyncManager", () => {
|
||||||
event_id: "$abc123",
|
event_id: "$abc123",
|
||||||
sender: client.getUserId()!,
|
sender: client.getUserId()!,
|
||||||
content: {
|
content: {
|
||||||
creator: client.getUserId(),
|
creator: client.getUserId()!,
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
]);
|
]);
|
||||||
|
|
|
@ -125,7 +125,7 @@ describe("VoiceMessageRecording", () => {
|
||||||
const encryptedFile = {} as unknown as IEncryptedFile;
|
const encryptedFile = {} as unknown as IEncryptedFile;
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
voiceRecording.onDataAvailable(testBuf);
|
voiceRecording.onDataAvailable!(testBuf);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("contentLength should return the buffer length", () => {
|
it("contentLength should return the buffer length", () => {
|
||||||
|
@ -143,9 +143,9 @@ describe("VoiceMessageRecording", () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("upload", () => {
|
describe("upload", () => {
|
||||||
let uploadFileClient: MatrixClient;
|
let uploadFileClient: MatrixClient | null;
|
||||||
let uploadFileRoomId: string;
|
let uploadFileRoomId: string | null;
|
||||||
let uploadBlob: Blob;
|
let uploadBlob: Blob | null;
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
uploadFileClient = null;
|
uploadFileClient = null;
|
||||||
|
@ -182,8 +182,8 @@ describe("VoiceMessageRecording", () => {
|
||||||
expect(mocked(uploadFile)).toHaveBeenCalled();
|
expect(mocked(uploadFile)).toHaveBeenCalled();
|
||||||
expect(uploadFileClient).toBe(client);
|
expect(uploadFileClient).toBe(client);
|
||||||
expect(uploadFileRoomId).toBe(roomId);
|
expect(uploadFileRoomId).toBe(roomId);
|
||||||
expect(uploadBlob.type).toBe(contentType);
|
expect(uploadBlob?.type).toBe(contentType);
|
||||||
const blobArray = await uploadBlob.arrayBuffer();
|
const blobArray = await uploadBlob!.arrayBuffer();
|
||||||
expect(new Uint8Array(blobArray)).toEqual(testBuf);
|
expect(new Uint8Array(blobArray)).toEqual(testBuf);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -79,7 +79,7 @@ describe("RoomView", () => {
|
||||||
stores.client = cli;
|
stores.client = cli;
|
||||||
stores.rightPanelStore.useUnitTestClient(cli);
|
stores.rightPanelStore.useUnitTestClient(cli);
|
||||||
|
|
||||||
jest.spyOn(VoipUserMapper.sharedInstance(), "getVirtualRoomForRoom").mockResolvedValue(null);
|
jest.spyOn(VoipUserMapper.sharedInstance(), "getVirtualRoomForRoom").mockResolvedValue(undefined);
|
||||||
});
|
});
|
||||||
|
|
||||||
afterEach(async () => {
|
afterEach(async () => {
|
||||||
|
@ -175,7 +175,7 @@ describe("RoomView", () => {
|
||||||
instance = await getRoomViewInstance();
|
instance = await getRoomViewInstance();
|
||||||
oldRoom = new Room("!old:example.com", cli, cli.getSafeUserId());
|
oldRoom = new Room("!old:example.com", cli, cli.getSafeUserId());
|
||||||
rooms.set(oldRoom.roomId, oldRoom);
|
rooms.set(oldRoom.roomId, oldRoom);
|
||||||
jest.spyOn(room, "findPredecessor").mockReturnValue({ roomId: oldRoom.roomId, eventId: null });
|
jest.spyOn(room, "findPredecessor").mockReturnValue({ roomId: oldRoom.roomId });
|
||||||
});
|
});
|
||||||
|
|
||||||
it("and it has 0 unreads, getHiddenHighlightCount should return 0", async () => {
|
it("and it has 0 unreads, getHiddenHighlightCount should return 0", async () => {
|
||||||
|
|
|
@ -181,7 +181,7 @@ describe("Login", function () {
|
||||||
const { container, rerender } = render(getRawComponent());
|
const { container, rerender } = render(getRawComponent());
|
||||||
await waitForElementToBeRemoved(() => screen.queryAllByLabelText("Loading…"));
|
await waitForElementToBeRemoved(() => screen.queryAllByLabelText("Loading…"));
|
||||||
|
|
||||||
fireEvent.click(container.querySelector(".mx_SSOButton"));
|
fireEvent.click(container.querySelector(".mx_SSOButton")!);
|
||||||
expect(platform.startSingleSignOn.mock.calls[0][0].baseUrl).toBe("https://matrix.org");
|
expect(platform.startSingleSignOn.mock.calls[0][0].baseUrl).toBe("https://matrix.org");
|
||||||
|
|
||||||
fetchMock.get("https://server2/_matrix/client/versions", {
|
fetchMock.get("https://server2/_matrix/client/versions", {
|
||||||
|
@ -190,7 +190,7 @@ describe("Login", function () {
|
||||||
});
|
});
|
||||||
rerender(getRawComponent("https://server2"));
|
rerender(getRawComponent("https://server2"));
|
||||||
|
|
||||||
fireEvent.click(container.querySelector(".mx_SSOButton"));
|
fireEvent.click(container.querySelector(".mx_SSOButton")!);
|
||||||
expect(platform.startSingleSignOn.mock.calls[1][0].baseUrl).toBe("https://server2");
|
expect(platform.startSingleSignOn.mock.calls[1][0].baseUrl).toBe("https://server2");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -118,7 +118,7 @@ describe("Registration", function () {
|
||||||
const { container, rerender } = render(getRawComponent());
|
const { container, rerender } = render(getRawComponent());
|
||||||
await waitForElementToBeRemoved(() => screen.queryAllByLabelText("Loading…"));
|
await waitForElementToBeRemoved(() => screen.queryAllByLabelText("Loading…"));
|
||||||
|
|
||||||
fireEvent.click(container.querySelector(".mx_SSOButton"));
|
fireEvent.click(container.querySelector(".mx_SSOButton")!);
|
||||||
expect(registerRequest.mock.instances[0].baseUrl).toBe("https://matrix.org");
|
expect(registerRequest.mock.instances[0].baseUrl).toBe("https://matrix.org");
|
||||||
|
|
||||||
fetchMock.get("https://server2/_matrix/client/versions", {
|
fetchMock.get("https://server2/_matrix/client/versions", {
|
||||||
|
@ -128,7 +128,7 @@ describe("Registration", function () {
|
||||||
rerender(getRawComponent("https://server2"));
|
rerender(getRawComponent("https://server2"));
|
||||||
await waitForElementToBeRemoved(() => screen.queryAllByLabelText("Loading…"));
|
await waitForElementToBeRemoved(() => screen.queryAllByLabelText("Loading…"));
|
||||||
|
|
||||||
fireEvent.click(container.querySelector(".mx_SSOButton"));
|
fireEvent.click(container.querySelector(".mx_SSOButton")!);
|
||||||
expect(registerRequest.mock.instances[1].baseUrl).toBe("https://server2");
|
expect(registerRequest.mock.instances[1].baseUrl).toBe("https://server2");
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -84,7 +84,7 @@ describe("<BeaconListItem />", () => {
|
||||||
|
|
||||||
const member = new RoomMember(roomId, aliceId);
|
const member = new RoomMember(roomId, aliceId);
|
||||||
member.name = `Alice`;
|
member.name = `Alice`;
|
||||||
const room = mockClient.getRoom(roomId);
|
const room = mockClient.getRoom(roomId)!;
|
||||||
jest.spyOn(room, "getMember").mockReturnValue(member);
|
jest.spyOn(room, "getMember").mockReturnValue(member);
|
||||||
|
|
||||||
return beacons;
|
return beacons;
|
||||||
|
@ -185,7 +185,7 @@ describe("<BeaconListItem />", () => {
|
||||||
const { container } = getComponent({ beacon, onClick });
|
const { container } = getComponent({ beacon, onClick });
|
||||||
|
|
||||||
// click the beacon name
|
// click the beacon name
|
||||||
fireEvent.click(container.querySelector(".mx_BeaconStatus_description"));
|
fireEvent.click(container.querySelector(".mx_BeaconStatus_description")!);
|
||||||
expect(onClick).toHaveBeenCalled();
|
expect(onClick).toHaveBeenCalled();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -47,7 +47,7 @@ describe("<ShareLatestLocation />", () => {
|
||||||
const { container, asFragment } = getComponent();
|
const { container, asFragment } = getComponent();
|
||||||
expect(asFragment()).toMatchSnapshot();
|
expect(asFragment()).toMatchSnapshot();
|
||||||
|
|
||||||
fireEvent.click(container.querySelector(".mx_CopyableText_copyButton"));
|
fireEvent.click(container.querySelector(".mx_CopyableText_copyButton")!);
|
||||||
await flushPromises();
|
await flushPromises();
|
||||||
|
|
||||||
expect(copyPlaintext).toHaveBeenCalledWith("51,42");
|
expect(copyPlaintext).toHaveBeenCalledWith("51,42");
|
||||||
|
|
|
@ -575,7 +575,7 @@ function createMenu(
|
||||||
|
|
||||||
return mount(
|
return mount(
|
||||||
<RoomContext.Provider value={context as IRoomState}>
|
<RoomContext.Provider value={context as IRoomState}>
|
||||||
<MessageContextMenu chevronFace={null} mxEvent={mxEvent} onFinished={jest.fn()} {...props} />
|
<MessageContextMenu mxEvent={mxEvent} onFinished={jest.fn()} {...props} />
|
||||||
</RoomContext.Provider>,
|
</RoomContext.Provider>,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -32,7 +32,6 @@ describe("AccessSecretStorageDialog", () => {
|
||||||
const defaultProps: ComponentProps<typeof AccessSecretStorageDialog> = {
|
const defaultProps: ComponentProps<typeof AccessSecretStorageDialog> = {
|
||||||
onFinished: jest.fn(),
|
onFinished: jest.fn(),
|
||||||
checkPrivateKey: jest.fn(),
|
checkPrivateKey: jest.fn(),
|
||||||
keyInfo: undefined,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const renderComponent = (props = {}): void => {
|
const renderComponent = (props = {}): void => {
|
||||||
|
|
|
@ -66,11 +66,11 @@ describe("EventListSummary", function () {
|
||||||
}
|
}
|
||||||
const generateMembershipEvent = (
|
const generateMembershipEvent = (
|
||||||
eventId: string,
|
eventId: string,
|
||||||
{ senderId, userId, membership, prevMembership }: MembershipEventParams,
|
{ senderId, userId, membership, prevMembership }: MembershipEventParams & { userId: string },
|
||||||
): MatrixEvent => {
|
): MatrixEvent => {
|
||||||
const member = new RoomMember(roomId, userId);
|
const member = new RoomMember(roomId, userId);
|
||||||
// Use localpart as display name;
|
// Use localpart as display name;
|
||||||
member.name = userId.match(/@([^:]*):/)[1];
|
member.name = userId.match(/@([^:]*):/)![1];
|
||||||
jest.spyOn(member, "getAvatarUrl").mockReturnValue("avatar.jpeg");
|
jest.spyOn(member, "getAvatarUrl").mockReturnValue("avatar.jpeg");
|
||||||
jest.spyOn(member, "getMxcAvatarUrl").mockReturnValue("mxc://avatar.url/image.png");
|
jest.spyOn(member, "getMxcAvatarUrl").mockReturnValue("mxc://avatar.url/image.png");
|
||||||
const e = mkMembership({
|
const e = mkMembership({
|
||||||
|
@ -89,8 +89,8 @@ describe("EventListSummary", function () {
|
||||||
};
|
};
|
||||||
|
|
||||||
// Generate mock MatrixEvents from the array of parameters
|
// Generate mock MatrixEvents from the array of parameters
|
||||||
const generateEvents = (parameters: MembershipEventParams[]) => {
|
const generateEvents = (parameters: Array<MembershipEventParams & { userId: string }>) => {
|
||||||
const res = [];
|
const res: MatrixEvent[] = [];
|
||||||
for (let i = 0; i < parameters.length; i++) {
|
for (let i = 0; i < parameters.length; i++) {
|
||||||
res.push(generateMembershipEvent(`event${i}`, parameters[i]));
|
res.push(generateMembershipEvent(`event${i}`, parameters[i]));
|
||||||
}
|
}
|
||||||
|
@ -108,7 +108,9 @@ describe("EventListSummary", function () {
|
||||||
events.forEach((e) => {
|
events.forEach((e) => {
|
||||||
e.userId = userId;
|
e.userId = userId;
|
||||||
});
|
});
|
||||||
eventsForUsers = eventsForUsers.concat(generateEvents(events));
|
eventsForUsers = eventsForUsers.concat(
|
||||||
|
generateEvents(events as Array<MembershipEventParams & { userId: string }>),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
return eventsForUsers;
|
return eventsForUsers;
|
||||||
};
|
};
|
||||||
|
|
|
@ -29,7 +29,10 @@ describe("<LearnMore />", () => {
|
||||||
};
|
};
|
||||||
const getComponent = (props = {}) => <LearnMore {...defaultProps} {...props} />;
|
const getComponent = (props = {}) => <LearnMore {...defaultProps} {...props} />;
|
||||||
|
|
||||||
const modalSpy = jest.spyOn(Modal, "createDialog").mockReturnValue(undefined);
|
const modalSpy = jest.spyOn(Modal, "createDialog").mockReturnValue({
|
||||||
|
finished: new Promise(() => {}),
|
||||||
|
close: jest.fn(),
|
||||||
|
});
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
jest.clearAllMocks();
|
jest.clearAllMocks();
|
||||||
|
|
|
@ -36,7 +36,7 @@ describe("<TooltipTarget />", () => {
|
||||||
// clean up renderer tooltips
|
// clean up renderer tooltips
|
||||||
const wrapper = document.querySelector(".mx_Tooltip_wrapper");
|
const wrapper = document.querySelector(".mx_Tooltip_wrapper");
|
||||||
while (wrapper?.firstChild) {
|
while (wrapper?.firstChild) {
|
||||||
wrapper.removeChild(wrapper.lastChild);
|
wrapper.removeChild(wrapper.lastChild!);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -50,10 +50,10 @@ describe("MKeyVerificationConclusion", () => {
|
||||||
}) => {
|
}) => {
|
||||||
class MockVerificationRequest extends EventEmitter {
|
class MockVerificationRequest extends EventEmitter {
|
||||||
constructor(
|
constructor(
|
||||||
public readonly pending: boolean,
|
public readonly pending?: boolean,
|
||||||
public readonly cancelled: boolean,
|
public readonly cancelled?: boolean,
|
||||||
public readonly done: boolean,
|
public readonly done?: boolean,
|
||||||
public readonly otherUserId: string,
|
public readonly otherUserId?: string,
|
||||||
) {
|
) {
|
||||||
super();
|
super();
|
||||||
}
|
}
|
||||||
|
|
|
@ -140,7 +140,9 @@ describe("MLocationBody", () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
it("opens map dialog on click", () => {
|
it("opens map dialog on click", () => {
|
||||||
const modalSpy = jest.spyOn(Modal, "createDialog").mockReturnValue(undefined);
|
const modalSpy = jest
|
||||||
|
.spyOn(Modal, "createDialog")
|
||||||
|
.mockReturnValue({ finished: new Promise(() => {}), close: jest.fn() });
|
||||||
const component = getComponent();
|
const component = getComponent();
|
||||||
|
|
||||||
act(() => {
|
act(() => {
|
||||||
|
|
|
@ -63,7 +63,7 @@ describe("MessageEvent", () => {
|
||||||
event = mkEvent({
|
event = mkEvent({
|
||||||
event: true,
|
event: true,
|
||||||
type: VoiceBroadcastInfoEventType,
|
type: VoiceBroadcastInfoEventType,
|
||||||
user: client.getUserId(),
|
user: client.getUserId()!,
|
||||||
room: room.roomId,
|
room: room.roomId,
|
||||||
content: {
|
content: {
|
||||||
state: VoiceBroadcastInfoState.Started,
|
state: VoiceBroadcastInfoState.Started,
|
||||||
|
|
|
@ -108,7 +108,7 @@ describe("<PinnedMessagesCard />", () => {
|
||||||
const room = pins.props().room;
|
const room = pins.props().room;
|
||||||
const pinListener = mocked(room.currentState).on.mock.calls.find(
|
const pinListener = mocked(room.currentState).on.mock.calls.find(
|
||||||
([eventName, listener]) => eventName === RoomStateEvent.Events,
|
([eventName, listener]) => eventName === RoomStateEvent.Events,
|
||||||
)[1];
|
)![1];
|
||||||
|
|
||||||
await act(async () => {
|
await act(async () => {
|
||||||
// Emit the update
|
// Emit the update
|
||||||
|
|
|
@ -37,7 +37,7 @@ function generateRoomId() {
|
||||||
|
|
||||||
describe("MemberList", () => {
|
describe("MemberList", () => {
|
||||||
function createRoom(opts = {}) {
|
function createRoom(opts = {}) {
|
||||||
const room = new Room(generateRoomId(), null, client.getUserId());
|
const room = new Room(generateRoomId(), client, client.getUserId()!);
|
||||||
if (opts) {
|
if (opts) {
|
||||||
Object.assign(room, opts);
|
Object.assign(room, opts);
|
||||||
}
|
}
|
||||||
|
|
|
@ -370,7 +370,7 @@ describe("MessageComposer", () => {
|
||||||
replyToEvent = mkEvent({
|
replyToEvent = mkEvent({
|
||||||
event: true,
|
event: true,
|
||||||
type: EventType.RoomMessage,
|
type: EventType.RoomMessage,
|
||||||
user: cli.getUserId(),
|
user: cli.getUserId()!,
|
||||||
content: {},
|
content: {},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -377,7 +377,7 @@ describe("RoomHeader (React Testing Library)", () => {
|
||||||
content,
|
content,
|
||||||
});
|
});
|
||||||
room.addLiveEvents([event]);
|
room.addLiveEvents([event]);
|
||||||
return { event_id: event.getId() };
|
return { event_id: event.getId()! };
|
||||||
});
|
});
|
||||||
|
|
||||||
alice = mkRoomMember(room.roomId, "@alice:example.org");
|
alice = mkRoomMember(room.roomId, "@alice:example.org");
|
||||||
|
|
|
@ -21,7 +21,7 @@ import { Key } from "../../../../src/Keyboard";
|
||||||
import { mockPlatformPeg, unmockPlatformPeg } from "../../../test-utils/platform";
|
import { mockPlatformPeg, unmockPlatformPeg } from "../../../test-utils/platform";
|
||||||
import { KeyboardKey, KeyboardShortcut } from "../../../../src/components/views/settings/KeyboardShortcut";
|
import { KeyboardKey, KeyboardShortcut } from "../../../../src/components/views/settings/KeyboardShortcut";
|
||||||
|
|
||||||
const renderKeyboardShortcut = (Component: React.FunctionComponentFactory<any>, props: Record<string, any>) => {
|
const renderKeyboardShortcut = (Component: React.FunctionComponent<any>, props: Record<string, any>) => {
|
||||||
return render(<Component {...props} />).container;
|
return render(<Component {...props} />).container;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -30,7 +30,6 @@ describe("<DeviceDetails />", () => {
|
||||||
};
|
};
|
||||||
const defaultProps: ComponentProps<typeof DeviceDetails> = {
|
const defaultProps: ComponentProps<typeof DeviceDetails> = {
|
||||||
device: baseDevice,
|
device: baseDevice,
|
||||||
pusher: null,
|
|
||||||
isSigningOut: false,
|
isSigningOut: false,
|
||||||
onSignOutDevice: jest.fn(),
|
onSignOutDevice: jest.fn(),
|
||||||
saveDeviceName: jest.fn(),
|
saveDeviceName: jest.fn(),
|
||||||
|
|
|
@ -53,7 +53,7 @@ describe("<SelectableDeviceTile />", () => {
|
||||||
const { container } = render(getComponent({ onSelect }));
|
const { container } = render(getComponent({ onSelect }));
|
||||||
|
|
||||||
act(() => {
|
act(() => {
|
||||||
fireEvent.click(container.querySelector(`#device-tile-checkbox-${device.device_id}`));
|
fireEvent.click(container.querySelector(`#device-tile-checkbox-${device.device_id}`)!);
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(onSelect).toHaveBeenCalled();
|
expect(onSelect).toHaveBeenCalled();
|
||||||
|
|
|
@ -92,7 +92,7 @@ describe("deleteDevices()", () => {
|
||||||
// opened modal
|
// opened modal
|
||||||
expect(modalSpy).toHaveBeenCalled();
|
expect(modalSpy).toHaveBeenCalled();
|
||||||
|
|
||||||
const [, { title, authData, aestheticsForStagePhases }] = modalSpy.mock.calls[0];
|
const { title, authData, aestheticsForStagePhases } = modalSpy.mock.calls[0][1]!;
|
||||||
|
|
||||||
// modal opened as expected
|
// modal opened as expected
|
||||||
expect(title).toEqual("Authentication");
|
expect(title).toEqual("Authentication");
|
||||||
|
|
|
@ -21,7 +21,7 @@ import { DeviceInfo } from "matrix-js-sdk/src/crypto/deviceinfo";
|
||||||
import { logger } from "matrix-js-sdk/src/logger";
|
import { logger } from "matrix-js-sdk/src/logger";
|
||||||
import { DeviceTrustLevel } from "matrix-js-sdk/src/crypto/CrossSigning";
|
import { DeviceTrustLevel } from "matrix-js-sdk/src/crypto/CrossSigning";
|
||||||
import { VerificationRequest } from "matrix-js-sdk/src/crypto/verification/request/VerificationRequest";
|
import { VerificationRequest } from "matrix-js-sdk/src/crypto/verification/request/VerificationRequest";
|
||||||
import { sleep } from "matrix-js-sdk/src/utils";
|
import { defer, sleep } from "matrix-js-sdk/src/utils";
|
||||||
import {
|
import {
|
||||||
ClientEvent,
|
ClientEvent,
|
||||||
IMyDevice,
|
IMyDevice,
|
||||||
|
@ -927,12 +927,9 @@ describe("<SessionManagerTab />", () => {
|
||||||
// get a handle for resolving the delete call
|
// get a handle for resolving the delete call
|
||||||
// because promise flushing after the confirm modal is resolving this too
|
// because promise flushing after the confirm modal is resolving this too
|
||||||
// and we want to test the loading state here
|
// and we want to test the loading state here
|
||||||
let resolveDeleteRequest: (v?: IAuthData) => void;
|
const resolveDeleteRequest = defer<IAuthData>();
|
||||||
mockClient.deleteMultipleDevices.mockImplementation(() => {
|
mockClient.deleteMultipleDevices.mockImplementation(() => {
|
||||||
const promise = new Promise<IAuthData>((resolve) => {
|
return resolveDeleteRequest.promise;
|
||||||
resolveDeleteRequest = resolve;
|
|
||||||
});
|
|
||||||
return promise;
|
|
||||||
});
|
});
|
||||||
|
|
||||||
const { getByTestId } = render(getComponent());
|
const { getByTestId } = render(getComponent());
|
||||||
|
@ -972,7 +969,7 @@ describe("<SessionManagerTab />", () => {
|
||||||
undefined,
|
undefined,
|
||||||
);
|
);
|
||||||
|
|
||||||
resolveDeleteRequest?.();
|
resolveDeleteRequest.resolve({});
|
||||||
});
|
});
|
||||||
|
|
||||||
it("signs out of all other devices from other sessions context menu", async () => {
|
it("signs out of all other devices from other sessions context menu", async () => {
|
||||||
|
|
|
@ -54,7 +54,7 @@ function textMessageReply(body: string, msgtype = "m.text") {
|
||||||
function mergeAdjacentParts(parts: Part[]) {
|
function mergeAdjacentParts(parts: Part[]) {
|
||||||
let prevPart: Part | undefined;
|
let prevPart: Part | undefined;
|
||||||
for (let i = 0; i < parts.length; ++i) {
|
for (let i = 0; i < parts.length; ++i) {
|
||||||
let part = parts[i];
|
let part: Part | undefined = parts[i];
|
||||||
const isEmpty = !part.text.length;
|
const isEmpty = !part.text.length;
|
||||||
const isMerged = !isEmpty && prevPart && prevPart.merge?.(part);
|
const isMerged = !isEmpty && prevPart && prevPart.merge?.(part);
|
||||||
if (isEmpty || isMerged) {
|
if (isEmpty || isMerged) {
|
||||||
|
|
|
@ -38,7 +38,7 @@ async function md2html(markdown: string): Promise<string> {
|
||||||
const pc = createPartCreator();
|
const pc = createPartCreator();
|
||||||
const oldModel = new EditorModel([], pc, () => {});
|
const oldModel = new EditorModel([], pc, () => {});
|
||||||
await oldModel.update(markdown, "insertText", new DocumentOffset(markdown.length, false));
|
await oldModel.update(markdown, "insertText", new DocumentOffset(markdown.length, false));
|
||||||
return htmlSerializeIfNeeded(oldModel, { forceHTML: true });
|
return htmlSerializeIfNeeded(oldModel, { forceHTML: true })!;
|
||||||
}
|
}
|
||||||
|
|
||||||
function html2md(html: string): string {
|
function html2md(html: string): string {
|
||||||
|
|
|
@ -143,7 +143,7 @@ describe("useProfileInfo", () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should be able to handle an empty result", async () => {
|
it("should be able to handle an empty result", async () => {
|
||||||
cli.getProfileInfo = () => null;
|
cli.getProfileInfo = () => null as unknown as Promise<{}>;
|
||||||
const query = "@user:home.server";
|
const query = "@user:home.server";
|
||||||
|
|
||||||
const wrapper = mount(
|
const wrapper = mount(
|
||||||
|
|
|
@ -107,7 +107,7 @@ const setUpClientRoomAndStores = (): {
|
||||||
content,
|
content,
|
||||||
});
|
});
|
||||||
room.addLiveEvents([event]);
|
room.addLiveEvents([event]);
|
||||||
return { event_id: event.getId() };
|
return { event_id: event.getId()! };
|
||||||
});
|
});
|
||||||
|
|
||||||
setupAsyncStoreWithClient(WidgetStore.instance, client);
|
setupAsyncStoreWithClient(WidgetStore.instance, client);
|
||||||
|
|
|
@ -20,7 +20,7 @@ import { AppModule } from "../../src/modules/AppModule";
|
||||||
describe("AppModule", () => {
|
describe("AppModule", () => {
|
||||||
describe("constructor", () => {
|
describe("constructor", () => {
|
||||||
it("should call the factory immediately", () => {
|
it("should call the factory immediately", () => {
|
||||||
let module: MockModule;
|
let module: MockModule | undefined;
|
||||||
const appModule = new AppModule((api) => {
|
const appModule = new AppModule((api) => {
|
||||||
if (module) {
|
if (module) {
|
||||||
throw new Error("State machine error: Factory called twice");
|
throw new Error("State machine error: Factory called twice");
|
||||||
|
|
|
@ -30,7 +30,7 @@ export class MockModule extends RuntimeModule {
|
||||||
}
|
}
|
||||||
|
|
||||||
export function registerMockModule(): MockModule {
|
export function registerMockModule(): MockModule {
|
||||||
let module: MockModule;
|
let module: MockModule | undefined;
|
||||||
ModuleRunner.instance.registerModule((api) => {
|
ModuleRunner.instance.registerModule((api) => {
|
||||||
if (module) {
|
if (module) {
|
||||||
throw new Error("State machine error: ModuleRunner created the module twice");
|
throw new Error("State machine error: ModuleRunner created the module twice");
|
||||||
|
|
|
@ -800,7 +800,7 @@ describe("SpaceStore", () => {
|
||||||
testUtils.mockStateEventImplementation([childEvent]),
|
testUtils.mockStateEventImplementation([childEvent]),
|
||||||
);
|
);
|
||||||
|
|
||||||
client.emit(RoomStateEvent.Events, childEvent, spaceRoom.currentState, undefined);
|
client.emit(RoomStateEvent.Events, childEvent, spaceRoom.currentState, null);
|
||||||
};
|
};
|
||||||
|
|
||||||
const addMember = (spaceId: string, user: RoomMember) => {
|
const addMember = (spaceId: string, user: RoomMember) => {
|
||||||
|
@ -964,7 +964,7 @@ describe("SpaceStore", () => {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
client.emit(RoomStateEvent.Members, event, null, null);
|
client.emit(RoomStateEvent.Members, event, space.currentState, dm1Partner);
|
||||||
return deferred.resolve(true) as unknown as Promise<boolean>;
|
return deferred.resolve(true) as unknown as Promise<boolean>;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -1279,7 +1279,7 @@ describe("SpaceStore", () => {
|
||||||
user: dm1Partner.userId,
|
user: dm1Partner.userId,
|
||||||
room: space1,
|
room: space1,
|
||||||
});
|
});
|
||||||
client.emit(RoomStateEvent.Members, memberEvent, undefined, undefined);
|
client.emit(RoomStateEvent.Members, memberEvent, rootSpace.currentState, dm1Partner);
|
||||||
jest.runOnlyPendingTimers();
|
jest.runOnlyPendingTimers();
|
||||||
expect(SpaceStore.instance.getSpaceFilteredUserIds(space1).has(dm1Partner.userId)).toBeTruthy();
|
expect(SpaceStore.instance.getSpaceFilteredUserIds(space1).has(dm1Partner.userId)).toBeTruthy();
|
||||||
const dm1Room = mkRoom(dm1);
|
const dm1Room = mkRoom(dm1);
|
||||||
|
|
|
@ -21,7 +21,7 @@ import { MatrixClientPeg } from "../../src/MatrixClientPeg";
|
||||||
import { flushPromises } from "../test-utils";
|
import { flushPromises } from "../test-utils";
|
||||||
import { VoiceMessageRecording } from "../../src/audio/VoiceMessageRecording";
|
import { VoiceMessageRecording } from "../../src/audio/VoiceMessageRecording";
|
||||||
|
|
||||||
const stubClient = {} as undefined as MatrixClient;
|
const stubClient = {} as unknown as MatrixClient;
|
||||||
jest.spyOn(MatrixClientPeg, "get").mockReturnValue(stubClient);
|
jest.spyOn(MatrixClientPeg, "get").mockReturnValue(stubClient);
|
||||||
|
|
||||||
describe("VoiceRecordingStore", () => {
|
describe("VoiceRecordingStore", () => {
|
||||||
|
|
|
@ -216,7 +216,7 @@ describe("RoomListStore", () => {
|
||||||
|
|
||||||
// But when we update the feature flag
|
// But when we update the feature flag
|
||||||
featureFlagValue = true;
|
featureFlagValue = true;
|
||||||
watchCallback(
|
watchCallback!(
|
||||||
"feature_dynamic_room_predecessors",
|
"feature_dynamic_room_predecessors",
|
||||||
"",
|
"",
|
||||||
SettingLevel.DEFAULT,
|
SettingLevel.DEFAULT,
|
||||||
|
|
|
@ -68,6 +68,7 @@ describe("RecentAlgorithm", () => {
|
||||||
|
|
||||||
it("returns a fake ts for rooms without a timeline", () => {
|
it("returns a fake ts for rooms without a timeline", () => {
|
||||||
const room = mkRoom(cli, "!new:example.org");
|
const room = mkRoom(cli, "!new:example.org");
|
||||||
|
// @ts-ignore
|
||||||
room.timeline = undefined;
|
room.timeline = undefined;
|
||||||
expect(algorithm.getLastTs(room, "@john:matrix.org")).toBe(Number.MAX_SAFE_INTEGER);
|
expect(algorithm.getLastTs(room, "@john:matrix.org")).toBe(Number.MAX_SAFE_INTEGER);
|
||||||
});
|
});
|
||||||
|
|
|
@ -196,7 +196,7 @@ describe("geolocation utilities", () => {
|
||||||
// suppress expected errors from test log
|
// suppress expected errors from test log
|
||||||
jest.spyOn(logger, "error").mockImplementation(() => {});
|
jest.spyOn(logger, "error").mockImplementation(() => {});
|
||||||
geolocation.watchPosition.mockImplementation((_callback, error) => {
|
geolocation.watchPosition.mockImplementation((_callback, error) => {
|
||||||
error(getMockGeolocationPositionError(1, "message"));
|
error!(getMockGeolocationPositionError(1, "message"));
|
||||||
return -1;
|
return -1;
|
||||||
});
|
});
|
||||||
const positionHandler = jest.fn();
|
const positionHandler = jest.fn();
|
||||||
|
@ -224,7 +224,7 @@ describe("geolocation utilities", () => {
|
||||||
jest.spyOn(logger, "error").mockImplementation(() => {});
|
jest.spyOn(logger, "error").mockImplementation(() => {});
|
||||||
|
|
||||||
const timeoutError = getMockGeolocationPositionError(3, "message");
|
const timeoutError = getMockGeolocationPositionError(3, "message");
|
||||||
geolocation.getCurrentPosition.mockImplementation((callback, error) => error(timeoutError));
|
geolocation.getCurrentPosition.mockImplementation((callback, error) => error!(timeoutError));
|
||||||
|
|
||||||
await expect(() => getCurrentPosition()).rejects.toThrow(GeolocationError.Timeout);
|
await expect(() => getCurrentPosition()).rejects.toThrow(GeolocationError.Timeout);
|
||||||
});
|
});
|
||||||
|
|
|
@ -135,7 +135,7 @@ describe("VoiceBroadcastRecording", () => {
|
||||||
event_id: infoEvent.getId(),
|
event_id: infoEvent.getId(),
|
||||||
},
|
},
|
||||||
} as VoiceBroadcastInfoEventContent,
|
} as VoiceBroadcastInfoEventContent,
|
||||||
client.getUserId(),
|
client.getUserId()!,
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
|
@ -49,14 +49,14 @@ describe("VoiceBroadcastRecordingsStore", () => {
|
||||||
infoEvent = mkVoiceBroadcastInfoStateEvent(
|
infoEvent = mkVoiceBroadcastInfoStateEvent(
|
||||||
roomId,
|
roomId,
|
||||||
VoiceBroadcastInfoState.Started,
|
VoiceBroadcastInfoState.Started,
|
||||||
client.getUserId(),
|
client.getUserId()!,
|
||||||
client.getDeviceId(),
|
client.getDeviceId()!,
|
||||||
);
|
);
|
||||||
otherInfoEvent = mkVoiceBroadcastInfoStateEvent(
|
otherInfoEvent = mkVoiceBroadcastInfoStateEvent(
|
||||||
roomId,
|
roomId,
|
||||||
VoiceBroadcastInfoState.Started,
|
VoiceBroadcastInfoState.Started,
|
||||||
client.getUserId(),
|
client.getUserId()!,
|
||||||
client.getDeviceId(),
|
client.getDeviceId()!,
|
||||||
);
|
);
|
||||||
recording = new VoiceBroadcastRecording(infoEvent, client);
|
recording = new VoiceBroadcastRecording(infoEvent, client);
|
||||||
otherRecording = new VoiceBroadcastRecording(otherInfoEvent, client);
|
otherRecording = new VoiceBroadcastRecording(otherInfoEvent, client);
|
||||||
|
|
|
@ -54,7 +54,7 @@ describe("VoiceBroadcastResumer", () => {
|
||||||
event_id: startedInfoEvent.getId(),
|
event_id: startedInfoEvent.getId(),
|
||||||
},
|
},
|
||||||
} as VoiceBroadcastInfoEventContent,
|
} as VoiceBroadcastInfoEventContent,
|
||||||
client.getUserId(),
|
client.getUserId()!,
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
|
@ -161,7 +161,7 @@ describe("startNewVoiceBroadcastRecording", () => {
|
||||||
device_id: client.getDeviceId(),
|
device_id: client.getDeviceId(),
|
||||||
state: VoiceBroadcastInfoState.Started,
|
state: VoiceBroadcastInfoState.Started,
|
||||||
},
|
},
|
||||||
client.getUserId(),
|
client.getUserId()!,
|
||||||
);
|
);
|
||||||
expect(recording!.infoEvent).toBe(infoEvent);
|
expect(recording!.infoEvent).toBe(infoEvent);
|
||||||
expect(recording!.start).toHaveBeenCalled();
|
expect(recording!.start).toHaveBeenCalled();
|
||||||
|
|
Loading…
Reference in a new issue