Conform more of the codebase to strictNullChecks
(#10731)
This commit is contained in:
parent
9f8113eabd
commit
1281c0746b
40 changed files with 147 additions and 119 deletions
|
@ -76,3 +76,5 @@ interface DeepReadonlyArray<T> extends ReadonlyArray<DeepReadonly<T>> {}
|
||||||
type DeepReadonlyObject<T> = {
|
type DeepReadonlyObject<T> = {
|
||||||
readonly [P in keyof T]: DeepReadonly<T[P]>;
|
readonly [P in keyof T]: DeepReadonly<T[P]>;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export type AtLeastOne<T, U = { [K in keyof T]: Pick<T, K> }> = Partial<T> & U[keyof U];
|
||||||
|
|
|
@ -272,7 +272,8 @@ export default class LegacyCallHandler extends EventEmitter {
|
||||||
return localNotificationsAreSilenced(cli);
|
return localNotificationsAreSilenced(cli);
|
||||||
}
|
}
|
||||||
|
|
||||||
public silenceCall(callId: string): void {
|
public silenceCall(callId?: string): void {
|
||||||
|
if (!callId) return;
|
||||||
this.silencedCalls.add(callId);
|
this.silencedCalls.add(callId);
|
||||||
this.emit(LegacyCallHandlerEvent.SilencedCallsChanged, this.silencedCalls);
|
this.emit(LegacyCallHandlerEvent.SilencedCallsChanged, this.silencedCalls);
|
||||||
|
|
||||||
|
@ -281,8 +282,8 @@ export default class LegacyCallHandler extends EventEmitter {
|
||||||
this.pause(AudioID.Ring);
|
this.pause(AudioID.Ring);
|
||||||
}
|
}
|
||||||
|
|
||||||
public unSilenceCall(callId: string): void {
|
public unSilenceCall(callId?: string): void {
|
||||||
if (this.isForcedSilent()) return;
|
if (!callId || this.isForcedSilent()) return;
|
||||||
this.silencedCalls.delete(callId);
|
this.silencedCalls.delete(callId);
|
||||||
this.emit(LegacyCallHandlerEvent.SilencedCallsChanged, this.silencedCalls);
|
this.emit(LegacyCallHandlerEvent.SilencedCallsChanged, this.silencedCalls);
|
||||||
this.play(AudioID.Ring);
|
this.play(AudioID.Ring);
|
||||||
|
@ -1182,8 +1183,9 @@ export default class LegacyCallHandler extends EventEmitter {
|
||||||
// Prevent double clicking the call button
|
// Prevent double clicking the call button
|
||||||
const widget = WidgetStore.instance.getApps(roomId).find((app) => WidgetType.JITSI.matches(app.type));
|
const widget = WidgetStore.instance.getApps(roomId).find((app) => WidgetType.JITSI.matches(app.type));
|
||||||
if (widget) {
|
if (widget) {
|
||||||
|
const room = client.getRoom(roomId);
|
||||||
// If there already is a Jitsi widget, pin it
|
// If there already is a Jitsi widget, pin it
|
||||||
WidgetLayoutStore.instance.moveToContainer(client.getRoom(roomId), widget, Container.Top);
|
if (room) WidgetLayoutStore.instance.moveToContainer(room, widget, Container.Top);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -30,7 +30,7 @@ const STATIC_DIALOG_CONTAINER_ID = "mx_Dialog_StaticContainer";
|
||||||
|
|
||||||
// Type which accepts a React Component which looks like a Modal (accepts an onFinished prop)
|
// Type which accepts a React Component which looks like a Modal (accepts an onFinished prop)
|
||||||
export type ComponentType = React.ComponentType<{
|
export type ComponentType = React.ComponentType<{
|
||||||
onFinished?(...args: any): void;
|
onFinished(...args: any): void;
|
||||||
}>;
|
}>;
|
||||||
|
|
||||||
// Generic type which returns the props of the Modal component with the onFinished being optional.
|
// Generic type which returns the props of the Modal component with the onFinished being optional.
|
||||||
|
@ -135,7 +135,7 @@ export class ModalManager extends TypedEventEmitter<ModalManagerEvent, HandlerMa
|
||||||
}
|
}
|
||||||
|
|
||||||
public appendDialog<C extends ComponentType>(
|
public appendDialog<C extends ComponentType>(
|
||||||
Element: React.ComponentType,
|
Element: C,
|
||||||
props?: ComponentProps<C>,
|
props?: ComponentProps<C>,
|
||||||
className?: string,
|
className?: string,
|
||||||
): IHandle<C> {
|
): IHandle<C> {
|
||||||
|
@ -157,7 +157,7 @@ export class ModalManager extends TypedEventEmitter<ModalManagerEvent, HandlerMa
|
||||||
}
|
}
|
||||||
|
|
||||||
private buildModal<C extends ComponentType>(
|
private buildModal<C extends ComponentType>(
|
||||||
prom: Promise<React.ComponentType>,
|
prom: Promise<C>,
|
||||||
props?: ComponentProps<C>,
|
props?: ComponentProps<C>,
|
||||||
className?: string,
|
className?: string,
|
||||||
options?: IOptions<C>,
|
options?: IOptions<C>,
|
||||||
|
@ -301,7 +301,7 @@ export class ModalManager extends TypedEventEmitter<ModalManagerEvent, HandlerMa
|
||||||
}
|
}
|
||||||
|
|
||||||
private appendDialogAsync<C extends ComponentType>(
|
private appendDialogAsync<C extends ComponentType>(
|
||||||
prom: Promise<React.ComponentType>,
|
prom: Promise<C>,
|
||||||
props?: ComponentProps<C>,
|
props?: ComponentProps<C>,
|
||||||
className?: string,
|
className?: string,
|
||||||
): IHandle<C> {
|
): IHandle<C> {
|
||||||
|
|
|
@ -15,11 +15,11 @@ See the License for the specific language governing permissions and
|
||||||
limitations under the License.
|
limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import React, { ComponentType } from "react";
|
import React from "react";
|
||||||
|
|
||||||
import dis from "../../../../dispatcher/dispatcher";
|
import dis from "../../../../dispatcher/dispatcher";
|
||||||
import { _t } from "../../../../languageHandler";
|
import { _t } from "../../../../languageHandler";
|
||||||
import Modal from "../../../../Modal";
|
import Modal, { ComponentType } from "../../../../Modal";
|
||||||
import { Action } from "../../../../dispatcher/actions";
|
import { Action } from "../../../../dispatcher/actions";
|
||||||
import BaseDialog from "../../../../components/views/dialogs/BaseDialog";
|
import BaseDialog from "../../../../components/views/dialogs/BaseDialog";
|
||||||
import DialogButtons from "../../../../components/views/elements/DialogButtons";
|
import DialogButtons from "../../../../components/views/elements/DialogButtons";
|
||||||
|
@ -37,7 +37,7 @@ export default class RecoveryMethodRemovedDialog extends React.PureComponent<IPr
|
||||||
private onSetupClick = (): void => {
|
private onSetupClick = (): void => {
|
||||||
this.props.onFinished();
|
this.props.onFinished();
|
||||||
Modal.createDialogAsync(
|
Modal.createDialogAsync(
|
||||||
import("./CreateKeyBackupDialog") as unknown as Promise<ComponentType<{}>>,
|
import("./CreateKeyBackupDialog") as unknown as Promise<ComponentType>,
|
||||||
undefined,
|
undefined,
|
||||||
undefined,
|
undefined,
|
||||||
/* priority = */ false,
|
/* priority = */ false,
|
||||||
|
|
|
@ -62,7 +62,7 @@ export interface InteractiveAuthProps<T> {
|
||||||
continueText?: string;
|
continueText?: string;
|
||||||
continueKind?: string;
|
continueKind?: string;
|
||||||
// callback
|
// callback
|
||||||
makeRequest(auth?: IAuthData): Promise<UIAResponse<T>>;
|
makeRequest(auth: IAuthDict | null): Promise<UIAResponse<T>>;
|
||||||
// callback called when the auth process has finished,
|
// callback called when the auth process has finished,
|
||||||
// successfully or unsuccessfully.
|
// successfully or unsuccessfully.
|
||||||
// @param {boolean} status True if the operation requiring
|
// @param {boolean} status True if the operation requiring
|
||||||
|
@ -200,7 +200,7 @@ export default class InteractiveAuthComponent<T> extends React.Component<Interac
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
private requestCallback = (auth: IAuthData | null, background: boolean): Promise<IAuthData> => {
|
private requestCallback = (auth: IAuthDict | null, background: boolean): Promise<UIAResponse<T>> => {
|
||||||
// This wrapper just exists because the js-sdk passes a second
|
// This wrapper just exists because the js-sdk passes a second
|
||||||
// 'busy' param for backwards compat. This throws the tests off
|
// 'busy' param for backwards compat. This throws the tests off
|
||||||
// so discard it here.
|
// so discard it here.
|
||||||
|
|
|
@ -152,15 +152,21 @@ export default class LegacyCallEventGrouper extends EventEmitter {
|
||||||
};
|
};
|
||||||
|
|
||||||
public answerCall = (): void => {
|
public answerCall = (): void => {
|
||||||
LegacyCallHandler.instance.answerCall(this.roomId);
|
const roomId = this.roomId;
|
||||||
|
if (!roomId) return;
|
||||||
|
LegacyCallHandler.instance.answerCall(roomId);
|
||||||
};
|
};
|
||||||
|
|
||||||
public rejectCall = (): void => {
|
public rejectCall = (): void => {
|
||||||
LegacyCallHandler.instance.hangupOrReject(this.roomId, true);
|
const roomId = this.roomId;
|
||||||
|
if (!roomId) return;
|
||||||
|
LegacyCallHandler.instance.hangupOrReject(roomId, true);
|
||||||
};
|
};
|
||||||
|
|
||||||
public callBack = (): void => {
|
public callBack = (): void => {
|
||||||
LegacyCallHandler.instance.placeCall(this.roomId, this.isVoice ? CallType.Voice : CallType.Video);
|
const roomId = this.roomId;
|
||||||
|
if (!roomId) return;
|
||||||
|
LegacyCallHandler.instance.placeCall(roomId, this.isVoice ? CallType.Voice : CallType.Video);
|
||||||
};
|
};
|
||||||
|
|
||||||
public toggleSilenced = (): void => {
|
public toggleSilenced = (): void => {
|
||||||
|
@ -191,9 +197,10 @@ export default class LegacyCallEventGrouper extends EventEmitter {
|
||||||
};
|
};
|
||||||
|
|
||||||
private setCall = (): void => {
|
private setCall = (): void => {
|
||||||
if (this.call) return;
|
const callId = this.callId;
|
||||||
|
if (!callId || this.call) return;
|
||||||
|
|
||||||
this.call = LegacyCallHandler.instance.getCallById(this.callId);
|
this.call = LegacyCallHandler.instance.getCallById(callId);
|
||||||
this.setCallListeners();
|
this.setCallListeners();
|
||||||
this.setState();
|
this.setState();
|
||||||
};
|
};
|
||||||
|
|
|
@ -99,7 +99,7 @@ interface IProps {
|
||||||
currentRoomId: string;
|
currentRoomId: string;
|
||||||
collapseLhs: boolean;
|
collapseLhs: boolean;
|
||||||
config: ConfigOptions;
|
config: ConfigOptions;
|
||||||
currentUserId?: string;
|
currentUserId: string;
|
||||||
justRegistered?: boolean;
|
justRegistered?: boolean;
|
||||||
roomJustCreatedOpts?: IOpts;
|
roomJustCreatedOpts?: IOpts;
|
||||||
forceTimeline?: boolean; // see props on MatrixChat
|
forceTimeline?: boolean; // see props on MatrixChat
|
||||||
|
@ -360,7 +360,7 @@ class LoggedInView extends React.Component<IProps, IState> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pinnedEventTs && this.state.usageLimitEventTs > pinnedEventTs) {
|
if (pinnedEventTs && this.state.usageLimitEventTs && this.state.usageLimitEventTs > pinnedEventTs) {
|
||||||
// We've processed a newer event than this one, so ignore it.
|
// We've processed a newer event than this one, so ignore it.
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
|
@ -422,8 +422,10 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
|
||||||
public componentDidUpdate(prevProps: IProps, prevState: IState): void {
|
public componentDidUpdate(prevProps: IProps, prevState: IState): void {
|
||||||
if (this.shouldTrackPageChange(prevState, this.state)) {
|
if (this.shouldTrackPageChange(prevState, this.state)) {
|
||||||
const durationMs = this.stopPageChangeTimer();
|
const durationMs = this.stopPageChangeTimer();
|
||||||
|
if (durationMs != null) {
|
||||||
PosthogTrackers.instance.trackPageChange(this.state.view, this.state.page_type, durationMs);
|
PosthogTrackers.instance.trackPageChange(this.state.view, this.state.page_type, durationMs);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
if (this.focusComposer) {
|
if (this.focusComposer) {
|
||||||
dis.fire(Action.FocusSendMessageComposer);
|
dis.fire(Action.FocusSendMessageComposer);
|
||||||
this.focusComposer = false;
|
this.focusComposer = false;
|
||||||
|
@ -935,7 +937,7 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
|
||||||
await this.firstSyncPromise.promise;
|
await this.firstSyncPromise.promise;
|
||||||
}
|
}
|
||||||
|
|
||||||
let presentedId = roomInfo.room_alias || roomInfo.room_id;
|
let presentedId = roomInfo.room_alias || roomInfo.room_id!;
|
||||||
const room = MatrixClientPeg.get().getRoom(roomInfo.room_id);
|
const room = MatrixClientPeg.get().getRoom(roomInfo.room_id);
|
||||||
if (room) {
|
if (room) {
|
||||||
// Not all timeline events are decrypted ahead of time anymore
|
// Not all timeline events are decrypted ahead of time anymore
|
||||||
|
|
|
@ -308,7 +308,11 @@ export default class MessagePanel extends React.Component<IProps, IState> {
|
||||||
this.calculateRoomMembersCount();
|
this.calculateRoomMembersCount();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (prevProps.readMarkerVisible && this.props.readMarkerEventId !== prevProps.readMarkerEventId) {
|
if (
|
||||||
|
prevProps.readMarkerVisible &&
|
||||||
|
prevProps.readMarkerEventId &&
|
||||||
|
this.props.readMarkerEventId !== prevProps.readMarkerEventId
|
||||||
|
) {
|
||||||
const ghostReadMarkers = this.state.ghostReadMarkers;
|
const ghostReadMarkers = this.state.ghostReadMarkers;
|
||||||
ghostReadMarkers.push(prevProps.readMarkerEventId);
|
ghostReadMarkers.push(prevProps.readMarkerEventId);
|
||||||
this.setState({
|
this.setState({
|
||||||
|
@ -906,7 +910,7 @@ export default class MessagePanel extends React.Component<IProps, IState> {
|
||||||
if (receiptsByUserId.get(userId)) {
|
if (receiptsByUserId.get(userId)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
const { lastShownEventId, receipt } = this.readReceiptsByUserId.get(userId);
|
const { lastShownEventId, receipt } = this.readReceiptsByUserId.get(userId)!;
|
||||||
const existingReceipts = receiptsByEvent.get(lastShownEventId) || [];
|
const existingReceipts = receiptsByEvent.get(lastShownEventId) || [];
|
||||||
receiptsByEvent.set(lastShownEventId, existingReceipts.concat(receipt));
|
receiptsByEvent.set(lastShownEventId, existingReceipts.concat(receipt));
|
||||||
receiptsByUserId.set(userId, { lastShownEventId, receipt });
|
receiptsByUserId.set(userId, { lastShownEventId, receipt });
|
||||||
|
|
|
@ -239,7 +239,7 @@ class PipContainerInner extends React.Component<IProps, IState> {
|
||||||
let notDocked = false;
|
let notDocked = false;
|
||||||
// Sanity check the room - the widget may have been destroyed between render cycles, and
|
// Sanity check the room - the widget may have been destroyed between render cycles, and
|
||||||
// thus no room is associated anymore.
|
// thus no room is associated anymore.
|
||||||
if (persistentWidgetId && MatrixClientPeg.get().getRoom(persistentRoomId)) {
|
if (persistentWidgetId && persistentRoomId && MatrixClientPeg.get().getRoom(persistentRoomId)) {
|
||||||
notDocked = !ActiveWidgetStore.instance.isDocked(persistentWidgetId, persistentRoomId);
|
notDocked = !ActiveWidgetStore.instance.isDocked(persistentWidgetId, persistentRoomId);
|
||||||
fromAnotherRoom = this.state.viewedRoomId !== persistentRoomId;
|
fromAnotherRoom = this.state.viewedRoomId !== persistentRoomId;
|
||||||
}
|
}
|
||||||
|
@ -314,10 +314,10 @@ class PipContainerInner extends React.Component<IProps, IState> {
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.state.showWidgetInPip) {
|
if (this.state.showWidgetInPip && this.state.persistentWidgetId) {
|
||||||
pipContent.push(({ onStartMoving }) => (
|
pipContent.push(({ onStartMoving }) => (
|
||||||
<WidgetPip
|
<WidgetPip
|
||||||
widgetId={this.state.persistentWidgetId}
|
widgetId={this.state.persistentWidgetId!}
|
||||||
room={MatrixClientPeg.get().getRoom(this.state.persistentRoomId ?? undefined)!}
|
room={MatrixClientPeg.get().getRoom(this.state.persistentRoomId ?? undefined)!}
|
||||||
viewingRoom={this.state.viewedRoomId === this.state.persistentRoomId}
|
viewingRoom={this.state.viewedRoomId === this.state.persistentRoomId}
|
||||||
onStartMoving={onStartMoving}
|
onStartMoving={onStartMoving}
|
||||||
|
|
|
@ -207,7 +207,7 @@ export default class RightPanel extends React.Component<IProps, IState> {
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case RightPanelPhases.PinnedMessages:
|
case RightPanelPhases.PinnedMessages:
|
||||||
if (SettingsStore.getValue("feature_pinning")) {
|
if (this.props.room && SettingsStore.getValue("feature_pinning")) {
|
||||||
card = (
|
card = (
|
||||||
<PinnedMessagesCard
|
<PinnedMessagesCard
|
||||||
room={this.props.room}
|
room={this.props.room}
|
||||||
|
|
|
@ -62,7 +62,7 @@ export default class SearchBox extends React.Component<IProps, IState> {
|
||||||
|
|
||||||
private onSearch = throttle(
|
private onSearch = throttle(
|
||||||
(): void => {
|
(): void => {
|
||||||
this.props.onSearch(this.search.current?.value);
|
this.props.onSearch(this.search.current?.value ?? "");
|
||||||
},
|
},
|
||||||
200,
|
200,
|
||||||
{ trailing: true, leading: true },
|
{ trailing: true, leading: true },
|
||||||
|
@ -94,11 +94,9 @@ export default class SearchBox extends React.Component<IProps, IState> {
|
||||||
};
|
};
|
||||||
|
|
||||||
private clearSearch(source?: string): void {
|
private clearSearch(source?: string): void {
|
||||||
this.search.current.value = "";
|
if (this.search.current) this.search.current.value = "";
|
||||||
this.onChange();
|
this.onChange();
|
||||||
if (this.props.onCleared) {
|
this.props.onCleared?.(source);
|
||||||
this.props.onCleared(source);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public render(): React.ReactNode {
|
public render(): React.ReactNode {
|
||||||
|
|
|
@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
|
||||||
limitations under the License.
|
limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { AuthType, createClient, IAuthData, IInputs, MatrixError } from "matrix-js-sdk/src/matrix";
|
import { AuthType, createClient, IAuthDict, IAuthData, IInputs, MatrixError } from "matrix-js-sdk/src/matrix";
|
||||||
import React, { Fragment, ReactNode } from "react";
|
import React, { Fragment, ReactNode } from "react";
|
||||||
import { IRegisterRequestParams, IRequestTokenResponse, MatrixClient } from "matrix-js-sdk/src/client";
|
import { IRegisterRequestParams, IRequestTokenResponse, MatrixClient } from "matrix-js-sdk/src/client";
|
||||||
import classNames from "classnames";
|
import classNames from "classnames";
|
||||||
|
@ -461,7 +461,7 @@ export default class Registration extends React.Component<IProps, IState> {
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
private makeRegisterRequest = (auth: IAuthData | null): Promise<IAuthData> => {
|
private makeRegisterRequest = (auth: IAuthDict | null): Promise<IAuthData> => {
|
||||||
if (!this.state.matrixClient) throw new Error("Matrix client has not yet been loaded");
|
if (!this.state.matrixClient) throw new Error("Matrix client has not yet been loaded");
|
||||||
|
|
||||||
const registerParams: IRegisterRequestParams = {
|
const registerParams: IRegisterRequestParams = {
|
||||||
|
|
|
@ -19,7 +19,7 @@ import React from "react";
|
||||||
import BaseDialog from "./BaseDialog";
|
import BaseDialog from "./BaseDialog";
|
||||||
import { _t } from "../../../languageHandler";
|
import { _t } from "../../../languageHandler";
|
||||||
import DialogButtons from "../elements/DialogButtons";
|
import DialogButtons from "../elements/DialogButtons";
|
||||||
import Modal from "../../../Modal";
|
import Modal, { ComponentProps } from "../../../Modal";
|
||||||
import SdkConfig from "../../../SdkConfig";
|
import SdkConfig from "../../../SdkConfig";
|
||||||
import { getPolicyUrl } from "../../../toasts/AnalyticsToast";
|
import { getPolicyUrl } from "../../../toasts/AnalyticsToast";
|
||||||
|
|
||||||
|
@ -29,7 +29,7 @@ export enum ButtonClicked {
|
||||||
}
|
}
|
||||||
|
|
||||||
interface IProps {
|
interface IProps {
|
||||||
onFinished?(buttonClicked?: ButtonClicked): void;
|
onFinished(buttonClicked?: ButtonClicked): void;
|
||||||
analyticsOwner: string;
|
analyticsOwner: string;
|
||||||
privacyPolicyUrl?: string;
|
privacyPolicyUrl?: string;
|
||||||
primaryButton?: string;
|
primaryButton?: string;
|
||||||
|
@ -45,8 +45,8 @@ export const AnalyticsLearnMoreDialog: React.FC<IProps> = ({
|
||||||
cancelButton,
|
cancelButton,
|
||||||
hasCancel,
|
hasCancel,
|
||||||
}) => {
|
}) => {
|
||||||
const onPrimaryButtonClick = (): void => onFinished?.(ButtonClicked.Primary);
|
const onPrimaryButtonClick = (): void => onFinished(ButtonClicked.Primary);
|
||||||
const onCancelButtonClick = (): void => onFinished?.(ButtonClicked.Cancel);
|
const onCancelButtonClick = (): void => onFinished(ButtonClicked.Cancel);
|
||||||
const privacyPolicyLink = privacyPolicyUrl ? (
|
const privacyPolicyLink = privacyPolicyUrl ? (
|
||||||
<span>
|
<span>
|
||||||
{_t(
|
{_t(
|
||||||
|
@ -114,7 +114,9 @@ export const AnalyticsLearnMoreDialog: React.FC<IProps> = ({
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export const showDialog = (props: Omit<IProps, "cookiePolicyUrl" | "analyticsOwner">): void => {
|
export const showDialog = (
|
||||||
|
props: Omit<ComponentProps<typeof AnalyticsLearnMoreDialog>, "cookiePolicyUrl" | "analyticsOwner">,
|
||||||
|
): void => {
|
||||||
const privacyPolicyUrl = getPolicyUrl();
|
const privacyPolicyUrl = getPolicyUrl();
|
||||||
const analyticsOwner = SdkConfig.get("analytics_owner") ?? SdkConfig.get("brand");
|
const analyticsOwner = SdkConfig.get("analytics_owner") ?? SdkConfig.get("brand");
|
||||||
Modal.createDialog(
|
Modal.createDialog(
|
||||||
|
|
|
@ -38,7 +38,7 @@ const BetaFeedbackDialog: React.FC<IProps> = ({ featureId, onFinished }) => {
|
||||||
return (
|
return (
|
||||||
<GenericFeatureFeedbackDialog
|
<GenericFeatureFeedbackDialog
|
||||||
title={_t("%(featureName)s Beta feedback", { featureName: info.title })}
|
title={_t("%(featureName)s Beta feedback", { featureName: info.title })}
|
||||||
subheading={_t(info.feedbackSubheading)}
|
subheading={info.feedbackSubheading ? _t(info.feedbackSubheading) : undefined}
|
||||||
onFinished={onFinished}
|
onFinished={onFinished}
|
||||||
rageshakeLabel={info.feedbackLabel}
|
rageshakeLabel={info.feedbackLabel}
|
||||||
rageshakeData={Object.fromEntries(
|
rageshakeData={Object.fromEntries(
|
||||||
|
|
|
@ -48,14 +48,11 @@ const FeedbackDialog: React.FC<IProps> = (props: IProps) => {
|
||||||
Modal.createDialog(BugReportDialog, {});
|
Modal.createDialog(BugReportDialog, {});
|
||||||
};
|
};
|
||||||
|
|
||||||
const rageshakeUrl = SdkConfig.get().bug_report_endpoint_url;
|
const hasFeedback = !!SdkConfig.get().bug_report_endpoint_url;
|
||||||
const hasFeedback = !!rageshakeUrl;
|
|
||||||
const onFinished = (sendFeedback: boolean): void => {
|
const onFinished = (sendFeedback: boolean): void => {
|
||||||
if (hasFeedback && sendFeedback) {
|
if (hasFeedback && sendFeedback) {
|
||||||
if (rageshakeUrl) {
|
|
||||||
const label = props.feature ? `${props.feature}-feedback` : "feedback";
|
const label = props.feature ? `${props.feature}-feedback` : "feedback";
|
||||||
submitFeedback(rageshakeUrl, label, comment, canContact);
|
submitFeedback(label, comment, canContact);
|
||||||
}
|
|
||||||
|
|
||||||
Modal.createDialog(InfoDialog, {
|
Modal.createDialog(InfoDialog, {
|
||||||
title: _t("Feedback sent"),
|
title: _t("Feedback sent"),
|
||||||
|
@ -65,8 +62,8 @@ const FeedbackDialog: React.FC<IProps> = (props: IProps) => {
|
||||||
props.onFinished();
|
props.onFinished();
|
||||||
};
|
};
|
||||||
|
|
||||||
let feedbackSection;
|
let feedbackSection: JSX.Element | undefined;
|
||||||
if (rageshakeUrl) {
|
if (hasFeedback) {
|
||||||
feedbackSection = (
|
feedbackSection = (
|
||||||
<div className="mx_FeedbackDialog_section mx_FeedbackDialog_rateApp">
|
<div className="mx_FeedbackDialog_section mx_FeedbackDialog_rateApp">
|
||||||
<h3>{_t("Comment")}</h3>
|
<h3>{_t("Comment")}</h3>
|
||||||
|
@ -93,8 +90,8 @@ const FeedbackDialog: React.FC<IProps> = (props: IProps) => {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
let bugReports: JSX.Element | null = null;
|
let bugReports: JSX.Element | undefined;
|
||||||
if (rageshakeUrl) {
|
if (hasFeedback) {
|
||||||
bugReports = (
|
bugReports = (
|
||||||
<p className="mx_FeedbackDialog_section_microcopy">
|
<p className="mx_FeedbackDialog_section_microcopy">
|
||||||
{_t(
|
{_t(
|
||||||
|
|
|
@ -19,7 +19,6 @@ import React, { ReactNode, useState } from "react";
|
||||||
import QuestionDialog from "./QuestionDialog";
|
import QuestionDialog from "./QuestionDialog";
|
||||||
import { _t } from "../../../languageHandler";
|
import { _t } from "../../../languageHandler";
|
||||||
import Field from "../elements/Field";
|
import Field from "../elements/Field";
|
||||||
import SdkConfig from "../../../SdkConfig";
|
|
||||||
import { submitFeedback } from "../../../rageshake/submit-rageshake";
|
import { submitFeedback } from "../../../rageshake/submit-rageshake";
|
||||||
import StyledCheckbox from "../elements/StyledCheckbox";
|
import StyledCheckbox from "../elements/StyledCheckbox";
|
||||||
import Modal from "../../../Modal";
|
import Modal from "../../../Modal";
|
||||||
|
@ -27,8 +26,8 @@ import InfoDialog from "./InfoDialog";
|
||||||
|
|
||||||
interface IProps {
|
interface IProps {
|
||||||
title: string;
|
title: string;
|
||||||
subheading: string;
|
subheading?: string;
|
||||||
rageshakeLabel: string;
|
rageshakeLabel?: string;
|
||||||
rageshakeData?: Record<string, any>;
|
rageshakeData?: Record<string, any>;
|
||||||
children?: ReactNode;
|
children?: ReactNode;
|
||||||
onFinished(sendFeedback?: boolean): void;
|
onFinished(sendFeedback?: boolean): void;
|
||||||
|
@ -48,7 +47,7 @@ const GenericFeatureFeedbackDialog: React.FC<IProps> = ({
|
||||||
const sendFeedback = async (ok: boolean): Promise<void> => {
|
const sendFeedback = async (ok: boolean): Promise<void> => {
|
||||||
if (!ok) return onFinished(false);
|
if (!ok) return onFinished(false);
|
||||||
|
|
||||||
submitFeedback(SdkConfig.get().bug_report_endpoint_url, rageshakeLabel, comment, canContact, rageshakeData);
|
submitFeedback(rageshakeLabel, comment, canContact, rageshakeData);
|
||||||
onFinished(true);
|
onFinished(true);
|
||||||
|
|
||||||
Modal.createDialog(InfoDialog, {
|
Modal.createDialog(InfoDialog, {
|
||||||
|
|
|
@ -29,7 +29,7 @@ import { useMatrixClientContext } from "../../../contexts/MatrixClientContext";
|
||||||
interface IManualDeviceKeyVerificationDialogProps {
|
interface IManualDeviceKeyVerificationDialogProps {
|
||||||
userId: string;
|
userId: string;
|
||||||
device: Device;
|
device: Device;
|
||||||
onFinished?(confirm?: boolean): void;
|
onFinished(confirm?: boolean): void;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function ManualDeviceKeyVerificationDialog({
|
export function ManualDeviceKeyVerificationDialog({
|
||||||
|
@ -44,7 +44,7 @@ export function ManualDeviceKeyVerificationDialog({
|
||||||
if (confirm && mxClient) {
|
if (confirm && mxClient) {
|
||||||
mxClient.setDeviceVerified(userId, device.deviceId, true);
|
mxClient.setDeviceVerified(userId, device.deviceId, true);
|
||||||
}
|
}
|
||||||
onFinished?.(confirm);
|
onFinished(confirm);
|
||||||
},
|
},
|
||||||
[mxClient, userId, device, onFinished],
|
[mxClient, userId, device, onFinished],
|
||||||
);
|
);
|
||||||
|
|
|
@ -47,7 +47,7 @@ export class ModuleUiDialog extends ScrollableBaseModal<IProps, IState> {
|
||||||
|
|
||||||
protected async submit(): Promise<void> {
|
protected async submit(): Promise<void> {
|
||||||
try {
|
try {
|
||||||
const model = await this.contentRef.current.trySubmit();
|
const model = await this.contentRef.current!.trySubmit();
|
||||||
this.props.onFinished(true, model);
|
this.props.onFinished(true, model);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
logger.error("Error during submission of module dialog:", e);
|
logger.error("Error during submission of module dialog:", e);
|
||||||
|
|
|
@ -120,7 +120,11 @@ export default class ServerPickerDialog extends React.PureComponent<IProps, ISta
|
||||||
|
|
||||||
// try to carry on anyway
|
// try to carry on anyway
|
||||||
try {
|
try {
|
||||||
this.validatedConf = await AutoDiscoveryUtils.validateServerConfigWithStaticUrls(hsUrl, null, true);
|
this.validatedConf = await AutoDiscoveryUtils.validateServerConfigWithStaticUrls(
|
||||||
|
hsUrl,
|
||||||
|
undefined,
|
||||||
|
true,
|
||||||
|
);
|
||||||
return {};
|
return {};
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
logger.error(e);
|
logger.error(e);
|
||||||
|
|
|
@ -30,6 +30,7 @@ import SettingsStore from "../../../settings/SettingsStore";
|
||||||
import { UIFeature } from "../../../settings/UIFeature";
|
import { UIFeature } from "../../../settings/UIFeature";
|
||||||
import BaseDialog from "./BaseDialog";
|
import BaseDialog from "./BaseDialog";
|
||||||
import CopyableText from "../elements/CopyableText";
|
import CopyableText from "../elements/CopyableText";
|
||||||
|
import { XOR } from "../../../@types/common";
|
||||||
|
|
||||||
const socials = [
|
const socials = [
|
||||||
{
|
{
|
||||||
|
@ -63,19 +64,27 @@ const socials = [
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
interface IProps {
|
interface BaseProps {
|
||||||
target: Room | User | RoomMember | MatrixEvent;
|
|
||||||
permalinkCreator?: RoomPermalinkCreator;
|
|
||||||
onFinished(): void;
|
onFinished(): void;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
interface Props extends BaseProps {
|
||||||
|
target: Room | User | RoomMember;
|
||||||
|
permalinkCreator?: RoomPermalinkCreator;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface EventProps extends BaseProps {
|
||||||
|
target: MatrixEvent;
|
||||||
|
permalinkCreator: RoomPermalinkCreator;
|
||||||
|
}
|
||||||
|
|
||||||
interface IState {
|
interface IState {
|
||||||
linkSpecificEvent: boolean;
|
linkSpecificEvent: boolean;
|
||||||
permalinkCreator: RoomPermalinkCreator | null;
|
permalinkCreator: RoomPermalinkCreator | null;
|
||||||
}
|
}
|
||||||
|
|
||||||
export default class ShareDialog extends React.PureComponent<IProps, IState> {
|
export default class ShareDialog extends React.PureComponent<XOR<Props, EventProps>, IState> {
|
||||||
public constructor(props: IProps) {
|
public constructor(props: XOR<Props, EventProps>) {
|
||||||
super(props);
|
super(props);
|
||||||
|
|
||||||
let permalinkCreator: RoomPermalinkCreator | null = null;
|
let permalinkCreator: RoomPermalinkCreator | null = null;
|
||||||
|
@ -103,30 +112,25 @@ export default class ShareDialog extends React.PureComponent<IProps, IState> {
|
||||||
};
|
};
|
||||||
|
|
||||||
private getUrl(): string {
|
private getUrl(): string {
|
||||||
let matrixToUrl;
|
|
||||||
|
|
||||||
if (this.props.target instanceof Room) {
|
if (this.props.target instanceof Room) {
|
||||||
if (this.state.linkSpecificEvent) {
|
if (this.state.linkSpecificEvent) {
|
||||||
const events = this.props.target.getLiveTimeline().getEvents();
|
const events = this.props.target.getLiveTimeline().getEvents();
|
||||||
matrixToUrl = this.state.permalinkCreator!.forEvent(events[events.length - 1].getId()!);
|
return this.state.permalinkCreator!.forEvent(events[events.length - 1].getId()!);
|
||||||
} else {
|
} else {
|
||||||
matrixToUrl = this.state.permalinkCreator!.forShareableRoom();
|
return this.state.permalinkCreator!.forShareableRoom();
|
||||||
}
|
}
|
||||||
} else if (this.props.target instanceof User || this.props.target instanceof RoomMember) {
|
} else if (this.props.target instanceof User || this.props.target instanceof RoomMember) {
|
||||||
matrixToUrl = makeUserPermalink(this.props.target.userId);
|
return makeUserPermalink(this.props.target.userId);
|
||||||
} else if (this.props.target instanceof MatrixEvent) {
|
} else if (this.state.linkSpecificEvent) {
|
||||||
if (this.state.linkSpecificEvent) {
|
return this.props.permalinkCreator!.forEvent(this.props.target.getId()!);
|
||||||
matrixToUrl = this.props.permalinkCreator.forEvent(this.props.target.getId()!);
|
|
||||||
} else {
|
} else {
|
||||||
matrixToUrl = this.props.permalinkCreator.forShareableRoom();
|
return this.props.permalinkCreator!.forShareableRoom();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return matrixToUrl;
|
|
||||||
}
|
|
||||||
|
|
||||||
public render(): React.ReactNode {
|
public render(): React.ReactNode {
|
||||||
let title;
|
let title: string | undefined;
|
||||||
let checkbox;
|
let checkbox: JSX.Element | undefined;
|
||||||
|
|
||||||
if (this.props.target instanceof Room) {
|
if (this.props.target instanceof Room) {
|
||||||
title = _t("Share Room");
|
title = _t("Share Room");
|
||||||
|
|
|
@ -87,7 +87,7 @@ export const SlidingSyncOptionsDialog: React.FC<{ onFinished(enabled: boolean):
|
||||||
const validProxy = withValidation<undefined, { error?: Error }>({
|
const validProxy = withValidation<undefined, { error?: Error }>({
|
||||||
async deriveData({ value }): Promise<{ error?: Error }> {
|
async deriveData({ value }): Promise<{ error?: Error }> {
|
||||||
try {
|
try {
|
||||||
await proxyHealthCheck(value, MatrixClientPeg.get().baseUrl);
|
await proxyHealthCheck(value!, MatrixClientPeg.get().baseUrl);
|
||||||
return {};
|
return {};
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
return { error };
|
return { error };
|
||||||
|
|
|
@ -42,7 +42,7 @@ const VALIDATION_THROTTLE_MS = 200;
|
||||||
export type KeyParams = { passphrase?: string; recoveryKey?: string };
|
export type KeyParams = { passphrase?: string; recoveryKey?: string };
|
||||||
|
|
||||||
interface IProps {
|
interface IProps {
|
||||||
keyInfo?: ISecretStorageKeyInfo;
|
keyInfo: ISecretStorageKeyInfo;
|
||||||
checkPrivateKey: (k: KeyParams) => Promise<boolean>;
|
checkPrivateKey: (k: KeyParams) => Promise<boolean>;
|
||||||
onFinished(result?: false | KeyParams): void;
|
onFinished(result?: false | KeyParams): void;
|
||||||
}
|
}
|
||||||
|
|
|
@ -136,6 +136,7 @@ export default class RestoreKeyBackupDialog extends React.PureComponent<IProps,
|
||||||
};
|
};
|
||||||
|
|
||||||
private onPassPhraseNext = async (): Promise<void> => {
|
private onPassPhraseNext = async (): Promise<void> => {
|
||||||
|
if (!this.state.backupInfo) return;
|
||||||
this.setState({
|
this.setState({
|
||||||
loading: true,
|
loading: true,
|
||||||
restoreError: null,
|
restoreError: null,
|
||||||
|
@ -177,7 +178,7 @@ export default class RestoreKeyBackupDialog extends React.PureComponent<IProps,
|
||||||
};
|
};
|
||||||
|
|
||||||
private onRecoveryKeyNext = async (): Promise<void> => {
|
private onRecoveryKeyNext = async (): Promise<void> => {
|
||||||
if (!this.state.recoveryKeyValid) return;
|
if (!this.state.recoveryKeyValid || !this.state.backupInfo) return;
|
||||||
|
|
||||||
this.setState({
|
this.setState({
|
||||||
loading: true,
|
loading: true,
|
||||||
|
@ -228,6 +229,7 @@ export default class RestoreKeyBackupDialog extends React.PureComponent<IProps,
|
||||||
try {
|
try {
|
||||||
// `accessSecretStorage` may prompt for storage access as needed.
|
// `accessSecretStorage` may prompt for storage access as needed.
|
||||||
await accessSecretStorage(async (): Promise<void> => {
|
await accessSecretStorage(async (): Promise<void> => {
|
||||||
|
if (!this.state.backupInfo) return;
|
||||||
await MatrixClientPeg.get().restoreKeyBackupWithSecretStorage(
|
await MatrixClientPeg.get().restoreKeyBackupWithSecretStorage(
|
||||||
this.state.backupInfo,
|
this.state.backupInfo,
|
||||||
undefined,
|
undefined,
|
||||||
|
|
|
@ -748,7 +748,7 @@ export class UnwrappedEventTile extends React.Component<EventTileProps, IState>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (MatrixClientPeg.get().isRoomEncrypted(ev.getRoomId())) {
|
if (MatrixClientPeg.get().isRoomEncrypted(ev.getRoomId()!)) {
|
||||||
// else if room is encrypted
|
// else if room is encrypted
|
||||||
// and event is being encrypted or is not_sent (Unknown Devices/Network Error)
|
// and event is being encrypted or is not_sent (Unknown Devices/Network Error)
|
||||||
if (ev.status === EventStatus.ENCRYPTING) {
|
if (ev.status === EventStatus.ENCRYPTING) {
|
||||||
|
@ -783,7 +783,7 @@ export class UnwrappedEventTile extends React.Component<EventTileProps, IState>
|
||||||
if (!this.props.showReactions || !this.props.getRelationsForEvent) {
|
if (!this.props.showReactions || !this.props.getRelationsForEvent) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
const eventId = this.props.mxEvent.getId();
|
const eventId = this.props.mxEvent.getId()!;
|
||||||
return this.props.getRelationsForEvent(eventId, "m.annotation", "m.reaction") ?? null;
|
return this.props.getRelationsForEvent(eventId, "m.annotation", "m.reaction") ?? null;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -801,7 +801,7 @@ export class UnwrappedEventTile extends React.Component<EventTileProps, IState>
|
||||||
};
|
};
|
||||||
|
|
||||||
private onTimestampContextMenu = (ev: React.MouseEvent): void => {
|
private onTimestampContextMenu = (ev: React.MouseEvent): void => {
|
||||||
this.showContextMenu(ev, this.props.permalinkCreator?.forEvent(this.props.mxEvent.getId()));
|
this.showContextMenu(ev, this.props.permalinkCreator?.forEvent(this.props.mxEvent.getId()!));
|
||||||
};
|
};
|
||||||
|
|
||||||
private showContextMenu(ev: React.MouseEvent, permalink?: string): void {
|
private showContextMenu(ev: React.MouseEvent, permalink?: string): void {
|
||||||
|
@ -974,7 +974,7 @@ export class UnwrappedEventTile extends React.Component<EventTileProps, IState>
|
||||||
|
|
||||||
let permalink = "#";
|
let permalink = "#";
|
||||||
if (this.props.permalinkCreator) {
|
if (this.props.permalinkCreator) {
|
||||||
permalink = this.props.permalinkCreator.forEvent(this.props.mxEvent.getId());
|
permalink = this.props.permalinkCreator.forEvent(this.props.mxEvent.getId()!);
|
||||||
}
|
}
|
||||||
|
|
||||||
// we can't use local echoes as scroll tokens, because their event IDs change.
|
// we can't use local echoes as scroll tokens, because their event IDs change.
|
||||||
|
|
|
@ -60,12 +60,12 @@ export default class ThirdPartyMemberInfo extends React.Component<IProps, IState
|
||||||
const sender = this.room?.getMember(this.props.event.getSender());
|
const sender = this.room?.getMember(this.props.event.getSender());
|
||||||
|
|
||||||
this.state = {
|
this.state = {
|
||||||
stateKey: this.props.event.getStateKey(),
|
stateKey: this.props.event.getStateKey()!,
|
||||||
roomId: this.props.event.getRoomId(),
|
roomId: this.props.event.getRoomId()!,
|
||||||
displayName: this.props.event.getContent().display_name,
|
displayName: this.props.event.getContent().display_name,
|
||||||
invited: true,
|
invited: true,
|
||||||
canKick: me ? me.powerLevel > kickLevel : false,
|
canKick: me ? me.powerLevel > kickLevel : false,
|
||||||
senderName: sender ? sender.name : this.props.event.getSender(),
|
senderName: sender?.name ?? this.props.event.getSender(),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -123,7 +123,7 @@ export default class SecureBackupPanel extends React.PureComponent<{}, IState> {
|
||||||
this.getUpdatedDiagnostics();
|
this.getUpdatedDiagnostics();
|
||||||
try {
|
try {
|
||||||
const backupInfo = await MatrixClientPeg.get().getKeyBackupVersion();
|
const backupInfo = await MatrixClientPeg.get().getKeyBackupVersion();
|
||||||
const backupSigStatus = await MatrixClientPeg.get().isKeyBackupTrusted(backupInfo);
|
const backupSigStatus = await MatrixClientPeg.get().isKeyBackupTrusted(backupInfo!);
|
||||||
if (this.unmounted) return;
|
if (this.unmounted) return;
|
||||||
this.setState({
|
this.setState({
|
||||||
loading: false,
|
loading: false,
|
||||||
|
@ -285,7 +285,7 @@ export default class SecureBackupPanel extends React.PureComponent<{}, IState> {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
let backupSigStatuses: React.ReactNode = backupSigStatus.sigs.map((sig, i) => {
|
let backupSigStatuses: React.ReactNode = backupSigStatus?.sigs.map((sig, i) => {
|
||||||
const deviceName = sig.device ? sig.device.getDisplayName() || sig.device.deviceId : null;
|
const deviceName = sig.device ? sig.device.getDisplayName() || sig.device.deviceId : null;
|
||||||
const validity = (sub: string): JSX.Element => (
|
const validity = (sub: string): JSX.Element => (
|
||||||
<span className={sig.valid ? "mx_SecureBackupPanel_sigValid" : "mx_SecureBackupPanel_sigInvalid"}>
|
<span className={sig.valid ? "mx_SecureBackupPanel_sigValid" : "mx_SecureBackupPanel_sigInvalid"}>
|
||||||
|
|
|
@ -15,7 +15,7 @@ limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { MatrixClient } from "matrix-js-sdk/src/matrix";
|
import { MatrixClient } from "matrix-js-sdk/src/matrix";
|
||||||
import { IAuthData } from "matrix-js-sdk/src/interactive-auth";
|
import { IAuthDict, IAuthData } from "matrix-js-sdk/src/interactive-auth";
|
||||||
|
|
||||||
import { _t } from "../../../../languageHandler";
|
import { _t } from "../../../../languageHandler";
|
||||||
import Modal from "../../../../Modal";
|
import Modal from "../../../../Modal";
|
||||||
|
@ -25,8 +25,8 @@ import InteractiveAuthDialog from "../../dialogs/InteractiveAuthDialog";
|
||||||
|
|
||||||
const makeDeleteRequest =
|
const makeDeleteRequest =
|
||||||
(matrixClient: MatrixClient, deviceIds: string[]) =>
|
(matrixClient: MatrixClient, deviceIds: string[]) =>
|
||||||
async (auth?: IAuthData): Promise<IAuthData> => {
|
async (auth: IAuthDict | null): Promise<IAuthData> => {
|
||||||
return matrixClient.deleteMultipleDevices(deviceIds, auth);
|
return matrixClient.deleteMultipleDevices(deviceIds, auth ?? undefined);
|
||||||
};
|
};
|
||||||
|
|
||||||
export const deleteDevicesWithInteractiveAuth = async (
|
export const deleteDevicesWithInteractiveAuth = async (
|
||||||
|
@ -38,7 +38,7 @@ export const deleteDevicesWithInteractiveAuth = async (
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
await makeDeleteRequest(matrixClient, deviceIds)();
|
await makeDeleteRequest(matrixClient, deviceIds)(null);
|
||||||
// no interactive auth needed
|
// no interactive auth needed
|
||||||
onFinished(true, undefined);
|
onFinished(true, undefined);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
|
|
@ -161,7 +161,7 @@ const SessionManagerTab: React.FC = () => {
|
||||||
const shouldShowOtherSessions = otherSessionsCount > 0;
|
const shouldShowOtherSessions = otherSessionsCount > 0;
|
||||||
|
|
||||||
const onVerifyCurrentDevice = (): void => {
|
const onVerifyCurrentDevice = (): void => {
|
||||||
Modal.createDialog(SetupEncryptionDialog as unknown as React.ComponentType, { onFinished: refreshDevices });
|
Modal.createDialog(SetupEncryptionDialog, { onFinished: refreshDevices });
|
||||||
};
|
};
|
||||||
|
|
||||||
const onTriggerDeviceVerification = useCallback(
|
const onTriggerDeviceVerification = useCallback(
|
||||||
|
|
|
@ -22,17 +22,12 @@ import { Action } from "../actions";
|
||||||
import { IOOBData, IThreepidInvite } from "../../stores/ThreepidInviteStore";
|
import { IOOBData, IThreepidInvite } from "../../stores/ThreepidInviteStore";
|
||||||
import { IOpts } from "../../createRoom";
|
import { IOpts } from "../../createRoom";
|
||||||
import { JoinRoomPayload } from "./JoinRoomPayload";
|
import { JoinRoomPayload } from "./JoinRoomPayload";
|
||||||
|
import { AtLeastOne } from "../../@types/common";
|
||||||
|
|
||||||
/* eslint-disable camelcase */
|
/* eslint-disable camelcase */
|
||||||
export interface ViewRoomPayload extends Pick<ActionPayload, "action"> {
|
interface BaseViewRoomPayload extends Pick<ActionPayload, "action"> {
|
||||||
action: Action.ViewRoom;
|
action: Action.ViewRoom;
|
||||||
|
|
||||||
// either or both of room_id or room_alias must be specified
|
|
||||||
// where possible, a room_id should be provided with a room_alias as it reduces
|
|
||||||
// the number of API calls required.
|
|
||||||
room_id?: string;
|
|
||||||
room_alias?: string;
|
|
||||||
|
|
||||||
event_id?: string; // the event to ensure is in view if any
|
event_id?: string; // the event to ensure is in view if any
|
||||||
highlighted?: boolean; // whether to highlight `event_id`
|
highlighted?: boolean; // whether to highlight `event_id`
|
||||||
scroll_into_view?: boolean; // whether to scroll `event_id` into view
|
scroll_into_view?: boolean; // whether to scroll `event_id` into view
|
||||||
|
@ -57,4 +52,13 @@ export interface ViewRoomPayload extends Pick<ActionPayload, "action"> {
|
||||||
metricsTrigger: ViewRoomEvent["trigger"];
|
metricsTrigger: ViewRoomEvent["trigger"];
|
||||||
metricsViaKeyboard?: ViewRoomEvent["viaKeyboard"];
|
metricsViaKeyboard?: ViewRoomEvent["viaKeyboard"];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export type ViewRoomPayload = BaseViewRoomPayload &
|
||||||
|
AtLeastOne<{
|
||||||
|
// either or both of room_id or room_alias must be specified
|
||||||
|
// where possible, a room_id should be provided with a room_alias as it reduces
|
||||||
|
// the number of API calls required.
|
||||||
|
room_id?: string;
|
||||||
|
room_alias?: string;
|
||||||
|
}>;
|
||||||
/* eslint-enable camelcase */
|
/* eslint-enable camelcase */
|
||||||
|
|
|
@ -146,7 +146,7 @@ export const options: Opts = {
|
||||||
return {
|
return {
|
||||||
// @ts-ignore see https://linkify.js.org/docs/options.html
|
// @ts-ignore see https://linkify.js.org/docs/options.html
|
||||||
click: function (e: MouseEvent) {
|
click: function (e: MouseEvent) {
|
||||||
onUserClick(e, permalink.userId);
|
onUserClick(e, permalink.userId!);
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -280,8 +280,7 @@ function uint8ToString(buf: Uint8Array): string {
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function submitFeedback(
|
export async function submitFeedback(
|
||||||
endpoint: string,
|
label: string | undefined,
|
||||||
label: string,
|
|
||||||
comment: string,
|
comment: string,
|
||||||
canContact = false,
|
canContact = false,
|
||||||
extraData: Record<string, any> = {},
|
extraData: Record<string, any> = {},
|
||||||
|
@ -292,7 +291,7 @@ export async function submitFeedback(
|
||||||
} catch (err) {} // PlatformPeg already logs this.
|
} catch (err) {} // PlatformPeg already logs this.
|
||||||
|
|
||||||
const body = new FormData();
|
const body = new FormData();
|
||||||
body.append("label", label);
|
if (label) body.append("label", label);
|
||||||
body.append("text", comment);
|
body.append("text", comment);
|
||||||
body.append("can_contact", canContact ? "yes" : "no");
|
body.append("can_contact", canContact ? "yes" : "no");
|
||||||
|
|
||||||
|
|
|
@ -215,7 +215,7 @@ export const SETTINGS: { [setting: string]: ISetting } = {
|
||||||
),
|
),
|
||||||
feedbackLabel: "video-room-feedback",
|
feedbackLabel: "video-room-feedback",
|
||||||
feedbackSubheading: _td(
|
feedbackSubheading: _td(
|
||||||
"Thank you for trying the beta, " + "please go into as much detail as you can so we can improve it.",
|
"Thank you for trying the beta, please go into as much detail as you can so we can improve it.",
|
||||||
),
|
),
|
||||||
image: require("../../res/img/betas/video_rooms.png"),
|
image: require("../../res/img/betas/video_rooms.png"),
|
||||||
requiresRefresh: true,
|
requiresRefresh: true,
|
||||||
|
|
|
@ -308,7 +308,7 @@ export default class RightPanelStore extends ReadyWatchingStore {
|
||||||
if (card.phase === RightPanelPhases.RoomMemberInfo && card.state) {
|
if (card.phase === RightPanelPhases.RoomMemberInfo && card.state) {
|
||||||
// RightPanelPhases.RoomMemberInfo -> needs to be changed to RightPanelPhases.EncryptionPanel if there is a pending verification request
|
// RightPanelPhases.RoomMemberInfo -> needs to be changed to RightPanelPhases.EncryptionPanel if there is a pending verification request
|
||||||
const { member } = card.state;
|
const { member } = card.state;
|
||||||
const pendingRequest = pendingVerificationRequestForUser(member);
|
const pendingRequest = member ? pendingVerificationRequestForUser(member) : undefined;
|
||||||
if (pendingRequest) {
|
if (pendingRequest) {
|
||||||
return {
|
return {
|
||||||
phase: RightPanelPhases.EncryptionPanel,
|
phase: RightPanelPhases.EncryptionPanel,
|
||||||
|
|
|
@ -71,8 +71,8 @@ interface IRightPanelForRoomStored {
|
||||||
history: Array<IRightPanelCardStored>;
|
history: Array<IRightPanelCardStored>;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function convertToStorePanel(cacheRoom: IRightPanelForRoom): IRightPanelForRoomStored {
|
export function convertToStorePanel(cacheRoom?: IRightPanelForRoom): IRightPanelForRoomStored | undefined {
|
||||||
if (!cacheRoom) return cacheRoom;
|
if (!cacheRoom) return undefined;
|
||||||
const storeHistory = [...cacheRoom.history].map((panelState) => convertCardToStore(panelState));
|
const storeHistory = [...cacheRoom.history].map((panelState) => convertCardToStore(panelState));
|
||||||
return { isOpen: cacheRoom.isOpen, history: storeHistory };
|
return { isOpen: cacheRoom.isOpen, history: storeHistory };
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,13 +14,13 @@ See the License for the specific language governing permissions and
|
||||||
limitations under the License.
|
limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { IAuthData } from "matrix-js-sdk/src/interactive-auth";
|
import { IAuthDict } from "matrix-js-sdk/src/interactive-auth";
|
||||||
import { UIAResponse } from "matrix-js-sdk/src/@types/uia";
|
import { UIAResponse } from "matrix-js-sdk/src/@types/uia";
|
||||||
|
|
||||||
import Modal from "../Modal";
|
import Modal from "../Modal";
|
||||||
import InteractiveAuthDialog, { InteractiveAuthDialogProps } from "../components/views/dialogs/InteractiveAuthDialog";
|
import InteractiveAuthDialog, { InteractiveAuthDialogProps } from "../components/views/dialogs/InteractiveAuthDialog";
|
||||||
|
|
||||||
type FunctionWithUIA<R, A> = (auth?: IAuthData, ...args: A[]) => Promise<UIAResponse<R>>;
|
type FunctionWithUIA<R, A> = (auth?: IAuthDict | null, ...args: A[]) => Promise<UIAResponse<R>>;
|
||||||
|
|
||||||
export function wrapRequestWithDialog<R, A = any>(
|
export function wrapRequestWithDialog<R, A = any>(
|
||||||
requestFunction: FunctionWithUIA<R, A>,
|
requestFunction: FunctionWithUIA<R, A>,
|
||||||
|
@ -29,7 +29,7 @@ export function wrapRequestWithDialog<R, A = any>(
|
||||||
return async function (...args): Promise<R> {
|
return async function (...args): Promise<R> {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
const boundFunction = requestFunction.bind(opts.matrixClient) as FunctionWithUIA<R, A>;
|
const boundFunction = requestFunction.bind(opts.matrixClient) as FunctionWithUIA<R, A>;
|
||||||
boundFunction(undefined, ...args)
|
boundFunction(null, ...args)
|
||||||
.then((res) => resolve(res as R))
|
.then((res) => resolve(res as R))
|
||||||
.catch((error) => {
|
.catch((error) => {
|
||||||
if (error.httpStatus !== 401 || !error.data?.flows) {
|
if (error.httpStatus !== 401 || !error.data?.flows) {
|
||||||
|
@ -40,7 +40,7 @@ export function wrapRequestWithDialog<R, A = any>(
|
||||||
Modal.createDialog(InteractiveAuthDialog, {
|
Modal.createDialog(InteractiveAuthDialog, {
|
||||||
...opts,
|
...opts,
|
||||||
authData: error.data,
|
authData: error.data,
|
||||||
makeRequest: (authData?: IAuthData) => boundFunction(authData, ...args),
|
makeRequest: (authData: IAuthDict | null) => boundFunction(authData, ...args),
|
||||||
onFinished: (success, result) => {
|
onFinished: (success, result) => {
|
||||||
if (success) {
|
if (success) {
|
||||||
resolve(result as R);
|
resolve(result as R);
|
||||||
|
|
|
@ -18,7 +18,7 @@ import { Room } from "matrix-js-sdk/src/matrix";
|
||||||
|
|
||||||
import { LocalRoom, LOCAL_ROOM_ID_PREFIX } from "../../models/LocalRoom";
|
import { LocalRoom, LOCAL_ROOM_ID_PREFIX } from "../../models/LocalRoom";
|
||||||
|
|
||||||
export function isLocalRoom(roomOrID?: Room | string): boolean {
|
export function isLocalRoom(roomOrID?: Room | string | null): boolean {
|
||||||
if (typeof roomOrID === "string") {
|
if (typeof roomOrID === "string") {
|
||||||
return roomOrID.startsWith(LOCAL_ROOM_ID_PREFIX);
|
return roomOrID.startsWith(LOCAL_ROOM_ID_PREFIX);
|
||||||
}
|
}
|
||||||
|
|
|
@ -54,6 +54,7 @@ describe("<LoggedInView />", () => {
|
||||||
element_call: {},
|
element_call: {},
|
||||||
},
|
},
|
||||||
currentRoomId: "",
|
currentRoomId: "",
|
||||||
|
currentUserId: "@bob:server",
|
||||||
};
|
};
|
||||||
|
|
||||||
const getComponent = (props = {}): RenderResult =>
|
const getComponent = (props = {}): RenderResult =>
|
||||||
|
|
|
@ -529,25 +529,25 @@ describe("<RoomSearchView/>", () => {
|
||||||
);
|
);
|
||||||
|
|
||||||
const event1 = await screen.findByText("Room 1");
|
const event1 = await screen.findByText("Room 1");
|
||||||
expect(event1.closest(".mx_EventTile_line").querySelector("a")).toHaveAttribute(
|
expect(event1.closest(".mx_EventTile_line")!.querySelector("a")).toHaveAttribute(
|
||||||
"href",
|
"href",
|
||||||
`https://matrix.to/#/${room.roomId}/$2`,
|
`https://matrix.to/#/${room.roomId}/$2`,
|
||||||
);
|
);
|
||||||
|
|
||||||
const event2 = await screen.findByText("Room 2");
|
const event2 = await screen.findByText("Room 2");
|
||||||
expect(event2.closest(".mx_EventTile_line").querySelector("a")).toHaveAttribute(
|
expect(event2.closest(".mx_EventTile_line")!.querySelector("a")).toHaveAttribute(
|
||||||
"href",
|
"href",
|
||||||
`https://matrix.to/#/${room2.roomId}/$22`,
|
`https://matrix.to/#/${room2.roomId}/$22`,
|
||||||
);
|
);
|
||||||
|
|
||||||
const event2Message2 = await screen.findByText("Room 2 message 2");
|
const event2Message2 = await screen.findByText("Room 2 message 2");
|
||||||
expect(event2Message2.closest(".mx_EventTile_line").querySelector("a")).toHaveAttribute(
|
expect(event2Message2.closest(".mx_EventTile_line")!.querySelector("a")).toHaveAttribute(
|
||||||
"href",
|
"href",
|
||||||
`https://matrix.to/#/${room2.roomId}/$23`,
|
`https://matrix.to/#/${room2.roomId}/$23`,
|
||||||
);
|
);
|
||||||
|
|
||||||
const event3 = await screen.findByText("Room 3");
|
const event3 = await screen.findByText("Room 3");
|
||||||
expect(event3.closest(".mx_EventTile_line").querySelector("a")).toHaveAttribute(
|
expect(event3.closest(".mx_EventTile_line")!.querySelector("a")).toHaveAttribute(
|
||||||
"href",
|
"href",
|
||||||
`https://matrix.to/#/${room3.roomId}/$32`,
|
`https://matrix.to/#/${room3.roomId}/$32`,
|
||||||
);
|
);
|
||||||
|
|
|
@ -30,6 +30,7 @@ describe("AccessSecretStorageDialog", () => {
|
||||||
let mockClient: Mocked<MatrixClient>;
|
let mockClient: Mocked<MatrixClient>;
|
||||||
|
|
||||||
const defaultProps: ComponentProps<typeof AccessSecretStorageDialog> = {
|
const defaultProps: ComponentProps<typeof AccessSecretStorageDialog> = {
|
||||||
|
keyInfo: {} as any,
|
||||||
onFinished: jest.fn(),
|
onFinished: jest.fn(),
|
||||||
checkPrivateKey: jest.fn(),
|
checkPrivateKey: jest.fn(),
|
||||||
};
|
};
|
||||||
|
|
Loading…
Reference in a new issue