Conform more of the codebase to strictNullChecks (#10607)
* Conform more of the codebase to `strictNullChecks` * Conform more of the codebase to `strictNullChecks` * Fix types * Conform more of the codebase to `strictNullChecks` * Conform more of the codebase to `strictNullChecks`
This commit is contained in:
parent
9d8d610f31
commit
56e4ae41f8
19 changed files with 71 additions and 68 deletions
|
@ -327,7 +327,11 @@ export default class MessagePanel extends React.Component<IProps, IState> {
|
||||||
}
|
}
|
||||||
|
|
||||||
private shouldHideSender(): boolean {
|
private shouldHideSender(): boolean {
|
||||||
return this.props.room?.getInvitedAndJoinedMemberCount() <= 2 && this.props.layout === Layout.Bubble;
|
return (
|
||||||
|
!!this.props.room &&
|
||||||
|
this.props.room.getInvitedAndJoinedMemberCount() <= 2 &&
|
||||||
|
this.props.layout === Layout.Bubble
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
private calculateRoomMembersCount = (): void => {
|
private calculateRoomMembersCount = (): void => {
|
||||||
|
@ -465,7 +469,7 @@ export default class MessagePanel extends React.Component<IProps, IState> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (MatrixClientPeg.get().isUserIgnored(mxEv.getSender())) {
|
if (MatrixClientPeg.get().isUserIgnored(mxEv.getSender()!)) {
|
||||||
return false; // ignored = no show (only happens if the ignore happens after an event was received)
|
return false; // ignored = no show (only happens if the ignore happens after an event was received)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -647,7 +651,7 @@ export default class MessagePanel extends React.Component<IProps, IState> {
|
||||||
for (let i = 0; i < events.length; i++) {
|
for (let i = 0; i < events.length; i++) {
|
||||||
const eventAndShouldShow = events[i];
|
const eventAndShouldShow = events[i];
|
||||||
const { event, shouldShow } = eventAndShouldShow;
|
const { event, shouldShow } = eventAndShouldShow;
|
||||||
const eventId = event.getId();
|
const eventId = event.getId()!;
|
||||||
const last = event === lastShownEvent;
|
const last = event === lastShownEvent;
|
||||||
const { nextEventAndShouldShow, nextTile } = this.getNextEventInfo(events, i);
|
const { nextEventAndShouldShow, nextTile } = this.getNextEventInfo(events, i);
|
||||||
|
|
||||||
|
@ -745,7 +749,7 @@ export default class MessagePanel extends React.Component<IProps, IState> {
|
||||||
!wantsDateSeparator &&
|
!wantsDateSeparator &&
|
||||||
shouldFormContinuation(prevEvent, mxEv, this.showHiddenEvents, this.context.timelineRenderingType);
|
shouldFormContinuation(prevEvent, mxEv, this.showHiddenEvents, this.context.timelineRenderingType);
|
||||||
|
|
||||||
const eventId = mxEv.getId();
|
const eventId = mxEv.getId()!;
|
||||||
const highlight = eventId === this.props.highlightedEventId;
|
const highlight = eventId === this.props.highlightedEventId;
|
||||||
|
|
||||||
const readReceipts = this.readReceiptsByEvent.get(eventId);
|
const readReceipts = this.readReceiptsByEvent.get(eventId);
|
||||||
|
@ -1075,7 +1079,7 @@ abstract class BaseGrouper {
|
||||||
public readonly nextEventTile?: MatrixEvent | null,
|
public readonly nextEventTile?: MatrixEvent | null,
|
||||||
) {
|
) {
|
||||||
this.readMarker = panel.readMarkerForEvent(
|
this.readMarker = panel.readMarkerForEvent(
|
||||||
firstEventAndShouldShow.event.getId(),
|
firstEventAndShouldShow.event.getId()!,
|
||||||
firstEventAndShouldShow.event === lastShownEvent,
|
firstEventAndShouldShow.event === lastShownEvent,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -1143,7 +1147,7 @@ class CreationGrouper extends BaseGrouper {
|
||||||
|
|
||||||
public add({ event: ev, shouldShow }: EventAndShouldShow): void {
|
public add({ event: ev, shouldShow }: EventAndShouldShow): void {
|
||||||
const panel = this.panel;
|
const panel = this.panel;
|
||||||
this.readMarker = this.readMarker || panel.readMarkerForEvent(ev.getId(), ev === this.lastShownEvent);
|
this.readMarker = this.readMarker || panel.readMarkerForEvent(ev.getId()!, ev === this.lastShownEvent);
|
||||||
if (!shouldShow) {
|
if (!shouldShow) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -1295,7 +1299,7 @@ class MainGrouper extends BaseGrouper {
|
||||||
// We can ignore any events that don't actually have a message to display
|
// We can ignore any events that don't actually have a message to display
|
||||||
if (!hasText(ev, this.panel.showHiddenEvents)) return;
|
if (!hasText(ev, this.panel.showHiddenEvents)) return;
|
||||||
}
|
}
|
||||||
this.readMarker = this.readMarker || this.panel.readMarkerForEvent(ev.getId(), ev === this.lastShownEvent);
|
this.readMarker = this.readMarker || this.panel.readMarkerForEvent(ev.getId()!, ev === this.lastShownEvent);
|
||||||
if (!this.panel.showHiddenEvents && !shouldShow) {
|
if (!this.panel.showHiddenEvents && !shouldShow) {
|
||||||
// absorb hidden events to not split the summary
|
// absorb hidden events to not split the summary
|
||||||
return;
|
return;
|
||||||
|
@ -1331,7 +1335,10 @@ class MainGrouper extends BaseGrouper {
|
||||||
// This will prevent it from being re-created unnecessarily, and instead will allow new props to be provided.
|
// This will prevent it from being re-created unnecessarily, and instead will allow new props to be provided.
|
||||||
// In turn, the shouldComponentUpdate method on ELS can be used to prevent unnecessary renderings.
|
// In turn, the shouldComponentUpdate method on ELS can be used to prevent unnecessary renderings.
|
||||||
const keyEvent = this.events.find((e) => this.panel.grouperKeyMap.get(e));
|
const keyEvent = this.events.find((e) => this.panel.grouperKeyMap.get(e));
|
||||||
const key = keyEvent ? this.panel.grouperKeyMap.get(keyEvent) : this.generateKey();
|
const key =
|
||||||
|
keyEvent && this.panel.grouperKeyMap.has(keyEvent)
|
||||||
|
? this.panel.grouperKeyMap.get(keyEvent)!
|
||||||
|
: this.generateKey();
|
||||||
if (!keyEvent) {
|
if (!keyEvent) {
|
||||||
// Populate the weak map with the key.
|
// Populate the weak map with the key.
|
||||||
// Note that we only set the key on the specific event it refers to, since this group might get
|
// Note that we only set the key on the specific event it refers to, since this group might get
|
||||||
|
|
|
@ -182,7 +182,7 @@ const ExportDialog: React.FC<IProps> = ({ room, onFinished }) => {
|
||||||
{
|
{
|
||||||
key: "number",
|
key: "number",
|
||||||
test: ({ value }) => {
|
test: ({ value }) => {
|
||||||
const parsedSize = parseInt(value, 10);
|
const parsedSize = parseInt(value!, 10);
|
||||||
return validateNumberInRange(1, 2000)(parsedSize);
|
return validateNumberInRange(1, 2000)(parsedSize);
|
||||||
},
|
},
|
||||||
invalid: () => {
|
invalid: () => {
|
||||||
|
@ -218,7 +218,7 @@ const ExportDialog: React.FC<IProps> = ({ room, onFinished }) => {
|
||||||
{
|
{
|
||||||
key: "number",
|
key: "number",
|
||||||
test: ({ value }) => {
|
test: ({ value }) => {
|
||||||
const parsedSize = parseInt(value, 10);
|
const parsedSize = parseInt(value!, 10);
|
||||||
return validateNumberInRange(1, 10 ** 8)(parsedSize);
|
return validateNumberInRange(1, 10 ** 8)(parsedSize);
|
||||||
},
|
},
|
||||||
invalid: () => {
|
invalid: () => {
|
||||||
|
|
|
@ -38,7 +38,7 @@ interface IProps {
|
||||||
}
|
}
|
||||||
|
|
||||||
const FeedbackDialog: React.FC<IProps> = (props: IProps) => {
|
const FeedbackDialog: React.FC<IProps> = (props: IProps) => {
|
||||||
const feedbackRef = useRef<Field>();
|
const feedbackRef = useRef<Field>(null);
|
||||||
const [comment, setComment] = useState<string>("");
|
const [comment, setComment] = useState<string>("");
|
||||||
const [canContact, toggleCanContact] = useStateToggle(false);
|
const [canContact, toggleCanContact] = useStateToggle(false);
|
||||||
|
|
||||||
|
|
|
@ -22,7 +22,7 @@ import { SettingLevel } from "../../../settings/SettingLevel";
|
||||||
|
|
||||||
interface IProps {
|
interface IProps {
|
||||||
// Current room
|
// Current room
|
||||||
roomId: string;
|
roomId: string | null;
|
||||||
minWidth: number;
|
minWidth: number;
|
||||||
maxWidth: number;
|
maxWidth: number;
|
||||||
}
|
}
|
||||||
|
|
|
@ -97,7 +97,7 @@ export default class BridgeTile extends React.PureComponent<IProps> {
|
||||||
<Pill
|
<Pill
|
||||||
type={PillType.UserMention}
|
type={PillType.UserMention}
|
||||||
room={this.props.room}
|
room={this.props.room}
|
||||||
url={makeUserPermalink(content.creator)}
|
url={makeUserPermalink(content.creator!)}
|
||||||
shouldShowPillAvatar={SettingsStore.getValue("Pill.shouldShowPillAvatar")}
|
shouldShowPillAvatar={SettingsStore.getValue("Pill.shouldShowPillAvatar")}
|
||||||
/>
|
/>
|
||||||
),
|
),
|
||||||
|
|
|
@ -213,7 +213,7 @@ export default class ChangePassword extends React.Component<IProps, IState> {
|
||||||
const modal = Modal.createDialog(SetEmailDialog, {
|
const modal = Modal.createDialog(SetEmailDialog, {
|
||||||
title: _t("Do you want to set an email address?"),
|
title: _t("Do you want to set an email address?"),
|
||||||
});
|
});
|
||||||
return modal.finished.then(([confirmed]) => confirmed);
|
return modal.finished.then(([confirmed]) => !!confirmed);
|
||||||
}
|
}
|
||||||
|
|
||||||
private onExportE2eKeysClicked = (): void => {
|
private onExportE2eKeysClicked = (): void => {
|
||||||
|
|
|
@ -94,9 +94,9 @@ export default class CrossSigningPanel extends React.PureComponent<{}, IState> {
|
||||||
const secretStorage = cli.crypto!.secretStorage;
|
const secretStorage = cli.crypto!.secretStorage;
|
||||||
const crossSigningPublicKeysOnDevice = Boolean(crossSigning.getId());
|
const crossSigningPublicKeysOnDevice = Boolean(crossSigning.getId());
|
||||||
const crossSigningPrivateKeysInStorage = Boolean(await crossSigning.isStoredInSecretStorage(secretStorage));
|
const crossSigningPrivateKeysInStorage = Boolean(await crossSigning.isStoredInSecretStorage(secretStorage));
|
||||||
const masterPrivateKeyCached = !!(pkCache && (await pkCache.getCrossSigningKeyCache("master")));
|
const masterPrivateKeyCached = !!(await pkCache?.getCrossSigningKeyCache?.("master"));
|
||||||
const selfSigningPrivateKeyCached = !!(pkCache && (await pkCache.getCrossSigningKeyCache("self_signing")));
|
const selfSigningPrivateKeyCached = !!(await pkCache?.getCrossSigningKeyCache?.("self_signing"));
|
||||||
const userSigningPrivateKeyCached = !!(pkCache && (await pkCache.getCrossSigningKeyCache("user_signing")));
|
const userSigningPrivateKeyCached = !!(await pkCache?.getCrossSigningKeyCache?.("user_signing"));
|
||||||
const homeserverSupportsCrossSigning = await cli.doesServerSupportUnstableFeature(
|
const homeserverSupportsCrossSigning = await cli.doesServerSupportUnstableFeature(
|
||||||
"org.matrix.e2e_cross_signing",
|
"org.matrix.e2e_cross_signing",
|
||||||
);
|
);
|
||||||
|
|
|
@ -51,7 +51,7 @@ export default class DevicesPanelEntry extends React.Component<IProps, IState> {
|
||||||
super(props);
|
super(props);
|
||||||
this.state = {
|
this.state = {
|
||||||
renaming: false,
|
renaming: false,
|
||||||
displayName: props.device.display_name,
|
displayName: props.device.display_name ?? "",
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -103,11 +103,11 @@ export default class DevicesPanelEntry extends React.Component<IProps, IState> {
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
const cli = MatrixClientPeg.get();
|
const cli = MatrixClientPeg.get();
|
||||||
const userId = cli.getUserId()!;
|
const userId = cli.getSafeUserId();
|
||||||
const verificationRequestPromise = cli.requestVerification(userId, [this.props.device.device_id]);
|
const verificationRequestPromise = cli.requestVerification(userId, [this.props.device.device_id]);
|
||||||
Modal.createDialog(VerificationRequestDialog, {
|
Modal.createDialog(VerificationRequestDialog, {
|
||||||
verificationRequestPromise,
|
verificationRequestPromise,
|
||||||
member: cli.getUser(userId),
|
member: cli.getUser(userId) ?? undefined,
|
||||||
onFinished: async (): Promise<void> => {
|
onFinished: async (): Promise<void> => {
|
||||||
const request = await verificationRequestPromise;
|
const request = await verificationRequestPromise;
|
||||||
request.cancel();
|
request.cancel();
|
||||||
|
|
|
@ -26,7 +26,6 @@ import EventIndexPeg from "../../../indexing/EventIndexPeg";
|
||||||
import { SettingLevel } from "../../../settings/SettingLevel";
|
import { SettingLevel } from "../../../settings/SettingLevel";
|
||||||
import SeshatResetDialog from "../dialogs/SeshatResetDialog";
|
import SeshatResetDialog from "../dialogs/SeshatResetDialog";
|
||||||
import InlineSpinner from "../elements/InlineSpinner";
|
import InlineSpinner from "../elements/InlineSpinner";
|
||||||
import { IIndexStats } from "../../../indexing/BaseEventIndexManager";
|
|
||||||
|
|
||||||
interface IState {
|
interface IState {
|
||||||
enabling: boolean;
|
enabling: boolean;
|
||||||
|
@ -49,15 +48,9 @@ export default class EventIndexPanel extends React.Component<{}, IState> {
|
||||||
|
|
||||||
public updateCurrentRoom = async (): Promise<void> => {
|
public updateCurrentRoom = async (): Promise<void> => {
|
||||||
const eventIndex = EventIndexPeg.get();
|
const eventIndex = EventIndexPeg.get();
|
||||||
let stats: IIndexStats | undefined;
|
const stats = await eventIndex?.getStats().catch(() => {});
|
||||||
|
// This call may fail if sporadically, not a huge issue as we will try later again and probably succeed.
|
||||||
try {
|
if (!stats) return;
|
||||||
stats = await eventIndex?.getStats();
|
|
||||||
} catch {
|
|
||||||
// This call may fail if sporadically, not a huge issue as we will
|
|
||||||
// try later again and probably succeed.
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.setState({
|
this.setState({
|
||||||
eventIndexSize: stats.size,
|
eventIndexSize: stats.size,
|
||||||
|
@ -88,14 +81,13 @@ export default class EventIndexPanel extends React.Component<{}, IState> {
|
||||||
if (eventIndex !== null) {
|
if (eventIndex !== null) {
|
||||||
eventIndex.on("changedCheckpoint", this.updateCurrentRoom);
|
eventIndex.on("changedCheckpoint", this.updateCurrentRoom);
|
||||||
|
|
||||||
try {
|
const stats = await eventIndex.getStats().catch(() => {});
|
||||||
const stats = await eventIndex.getStats();
|
|
||||||
eventIndexSize = stats.size;
|
|
||||||
roomCount = stats.roomCount;
|
|
||||||
} catch {
|
|
||||||
// This call may fail if sporadically, not a huge issue as we
|
// This call may fail if sporadically, not a huge issue as we
|
||||||
// will try later again in the updateCurrentRoom call and
|
// will try later again in the updateCurrentRoom call and
|
||||||
// probably succeed.
|
// probably succeed.
|
||||||
|
if (stats) {
|
||||||
|
eventIndexSize = stats.size;
|
||||||
|
roomCount = stats.roomCount;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -83,7 +83,7 @@ export default class FontScalingPanel extends React.Component<IProps, IState> {
|
||||||
};
|
};
|
||||||
|
|
||||||
private onValidateFontSize = async ({ value }: Pick<IFieldState, "value">): Promise<IValidationResult> => {
|
private onValidateFontSize = async ({ value }: Pick<IFieldState, "value">): Promise<IValidationResult> => {
|
||||||
const parsedSize = parseFloat(value);
|
const parsedSize = parseFloat(value!);
|
||||||
const min = FontWatcher.MIN_SIZE + FontWatcher.SIZE_DIFF;
|
const min = FontWatcher.MIN_SIZE + FontWatcher.SIZE_DIFF;
|
||||||
const max = FontWatcher.MAX_SIZE + FontWatcher.SIZE_DIFF;
|
const max = FontWatcher.MAX_SIZE + FontWatcher.SIZE_DIFF;
|
||||||
|
|
||||||
|
@ -98,7 +98,7 @@ export default class FontScalingPanel extends React.Component<IProps, IState> {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
SettingsStore.setValue("baseFontSize", null, SettingLevel.DEVICE, parseInt(value, 10) - FontWatcher.SIZE_DIFF);
|
SettingsStore.setValue("baseFontSize", null, SettingLevel.DEVICE, parseInt(value!, 10) - FontWatcher.SIZE_DIFF);
|
||||||
|
|
||||||
return { valid: true, feedback: _t("Use between %(min)s pt and %(max)s pt", { min, max }) };
|
return { valid: true, feedback: _t("Use between %(min)s pt and %(max)s pt", { min, max }) };
|
||||||
};
|
};
|
||||||
|
|
|
@ -61,7 +61,7 @@ const JoinRuleSettings: React.FC<IProps> = ({
|
||||||
|
|
||||||
const disabled = !room.currentState.mayClientSendStateEvent(EventType.RoomJoinRules, cli);
|
const disabled = !room.currentState.mayClientSendStateEvent(EventType.RoomJoinRules, cli);
|
||||||
|
|
||||||
const [content, setContent] = useLocalEcho<IJoinRuleEventContent>(
|
const [content, setContent] = useLocalEcho<IJoinRuleEventContent | undefined>(
|
||||||
() => room.currentState.getStateEvents(EventType.RoomJoinRules, "")?.getContent(),
|
() => room.currentState.getStateEvents(EventType.RoomJoinRules, "")?.getContent(),
|
||||||
(content) => cli.sendStateEvent(room.roomId, EventType.RoomJoinRules, content, ""),
|
(content) => cli.sendStateEvent(room.roomId, EventType.RoomJoinRules, content, ""),
|
||||||
onError,
|
onError,
|
||||||
|
@ -70,10 +70,10 @@ const JoinRuleSettings: React.FC<IProps> = ({
|
||||||
const { join_rule: joinRule = JoinRule.Invite } = content || {};
|
const { join_rule: joinRule = JoinRule.Invite } = content || {};
|
||||||
const restrictedAllowRoomIds =
|
const restrictedAllowRoomIds =
|
||||||
joinRule === JoinRule.Restricted
|
joinRule === JoinRule.Restricted
|
||||||
? content.allow?.filter((o) => o.type === RestrictedAllowType.RoomMembership).map((o) => o.room_id)
|
? content?.allow?.filter((o) => o.type === RestrictedAllowType.RoomMembership).map((o) => o.room_id)
|
||||||
: undefined;
|
: undefined;
|
||||||
|
|
||||||
const editRestrictedRoomIds = async (): Promise<string[]> => {
|
const editRestrictedRoomIds = async (): Promise<string[] | undefined> => {
|
||||||
let selected = restrictedAllowRoomIds;
|
let selected = restrictedAllowRoomIds;
|
||||||
if (!selected?.length && SpaceStore.instance.activeSpaceRoom) {
|
if (!selected?.length && SpaceStore.instance.activeSpaceRoom) {
|
||||||
selected = [SpaceStore.instance.activeSpaceRoom.roomId];
|
selected = [SpaceStore.instance.activeSpaceRoom.roomId];
|
||||||
|
@ -207,7 +207,7 @@ const JoinRuleSettings: React.FC<IProps> = ({
|
||||||
"Anyone in <spaceName/> can find and join. You can select other spaces too.",
|
"Anyone in <spaceName/> can find and join. You can select other spaces too.",
|
||||||
{},
|
{},
|
||||||
{
|
{
|
||||||
spaceName: () => <b>{SpaceStore.instance.activeSpaceRoom.name}</b>,
|
spaceName: () => <b>{SpaceStore.instance.activeSpaceRoom!.name}</b>,
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
|
@ -229,7 +229,7 @@ const JoinRuleSettings: React.FC<IProps> = ({
|
||||||
}
|
}
|
||||||
|
|
||||||
const onChange = async (joinRule: JoinRule): Promise<void> => {
|
const onChange = async (joinRule: JoinRule): Promise<void> => {
|
||||||
const beforeJoinRule = content.join_rule;
|
const beforeJoinRule = content?.join_rule;
|
||||||
|
|
||||||
let restrictedAllowRoomIds: string[] | undefined;
|
let restrictedAllowRoomIds: string[] | undefined;
|
||||||
if (joinRule === JoinRule.Restricted) {
|
if (joinRule === JoinRule.Restricted) {
|
||||||
|
|
|
@ -31,7 +31,6 @@ import { chromeFileInputFix } from "../../../utils/BrowserWorkarounds";
|
||||||
import PosthogTrackers from "../../../PosthogTrackers";
|
import PosthogTrackers from "../../../PosthogTrackers";
|
||||||
|
|
||||||
interface IState {
|
interface IState {
|
||||||
userId?: string;
|
|
||||||
originalDisplayName: string;
|
originalDisplayName: string;
|
||||||
displayName: string;
|
displayName: string;
|
||||||
originalAvatarUrl: string | null;
|
originalAvatarUrl: string | null;
|
||||||
|
@ -41,16 +40,16 @@ interface IState {
|
||||||
}
|
}
|
||||||
|
|
||||||
export default class ProfileSettings extends React.Component<{}, IState> {
|
export default class ProfileSettings extends React.Component<{}, IState> {
|
||||||
|
private readonly userId: string;
|
||||||
private avatarUpload: React.RefObject<HTMLInputElement> = createRef();
|
private avatarUpload: React.RefObject<HTMLInputElement> = createRef();
|
||||||
|
|
||||||
public constructor(props: {}) {
|
public constructor(props: {}) {
|
||||||
super(props);
|
super(props);
|
||||||
|
|
||||||
const client = MatrixClientPeg.get();
|
this.userId = MatrixClientPeg.get().getSafeUserId();
|
||||||
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()!,
|
|
||||||
originalDisplayName: OwnProfileStore.instance.displayName ?? "",
|
originalDisplayName: OwnProfileStore.instance.displayName ?? "",
|
||||||
displayName: OwnProfileStore.instance.displayName ?? "",
|
displayName: OwnProfileStore.instance.displayName ?? "",
|
||||||
originalAvatarUrl: avatarUrl,
|
originalAvatarUrl: avatarUrl,
|
||||||
|
@ -150,7 +149,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 ?? undefined,
|
||||||
avatarFile: file,
|
avatarFile: file,
|
||||||
enableProfileSave: true,
|
enableProfileSave: true,
|
||||||
});
|
});
|
||||||
|
@ -159,7 +158,7 @@ export default class ProfileSettings extends React.Component<{}, IState> {
|
||||||
};
|
};
|
||||||
|
|
||||||
public render(): React.ReactNode {
|
public render(): React.ReactNode {
|
||||||
const userIdentifier = UserIdentifierCustomisations.getDisplayUserIdentifier(this.state.userId, {
|
const userIdentifier = UserIdentifierCustomisations.getDisplayUserIdentifier(this.userId, {
|
||||||
withDisplayName: true,
|
withDisplayName: true,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -198,7 +197,7 @@ export default class ProfileSettings extends React.Component<{}, IState> {
|
||||||
</div>
|
</div>
|
||||||
<AvatarSetting
|
<AvatarSetting
|
||||||
avatarUrl={avatarUrl}
|
avatarUrl={avatarUrl}
|
||||||
avatarName={this.state.displayName || this.state.userId}
|
avatarName={this.state.displayName || this.userId}
|
||||||
avatarAltText={_t("Profile picture")}
|
avatarAltText={_t("Profile picture")}
|
||||||
uploadAvatar={this.uploadAvatar}
|
uploadAvatar={this.uploadAvatar}
|
||||||
removeAvatar={this.removeAvatar}
|
removeAvatar={this.removeAvatar}
|
||||||
|
|
|
@ -379,12 +379,12 @@ export default class SecureBackupPanel extends React.PureComponent<{}, IState> {
|
||||||
|
|
||||||
return <div key={i}>{sigStatus}</div>;
|
return <div key={i}>{sigStatus}</div>;
|
||||||
});
|
});
|
||||||
if (backupSigStatus.sigs.length === 0) {
|
if (!backupSigStatus?.sigs?.length) {
|
||||||
backupSigStatuses = _t("Backup is not signed by any of your sessions");
|
backupSigStatuses = _t("Backup is not signed by any of your sessions");
|
||||||
}
|
}
|
||||||
|
|
||||||
let trustedLocally;
|
let trustedLocally: string | undefined;
|
||||||
if (backupSigStatus.trusted_locally) {
|
if (backupSigStatus?.trusted_locally) {
|
||||||
trustedLocally = _t("This backup is trusted because it has been restored on this session");
|
trustedLocally = _t("This backup is trusted because it has been restored on this session");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -105,13 +105,13 @@ const DeviceDetails: React.FC<Props> = ({
|
||||||
|
|
||||||
const showPushNotificationSection = !!pusher || !!localNotificationSettings;
|
const showPushNotificationSection = !!pusher || !!localNotificationSettings;
|
||||||
|
|
||||||
function isPushNotificationsEnabled(pusher: IPusher, notificationSettings: LocalNotificationSettings): boolean {
|
function isPushNotificationsEnabled(pusher?: IPusher, notificationSettings?: LocalNotificationSettings): boolean {
|
||||||
if (pusher) return pusher[PUSHER_ENABLED.name];
|
if (pusher) return !!pusher[PUSHER_ENABLED.name];
|
||||||
if (localNotificationSettings) return !localNotificationSettings.is_silenced;
|
if (localNotificationSettings) return !localNotificationSettings.is_silenced;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
function isCheckboxDisabled(pusher: IPusher, notificationSettings: LocalNotificationSettings): boolean {
|
function isCheckboxDisabled(pusher?: IPusher, notificationSettings?: LocalNotificationSettings): boolean {
|
||||||
if (localNotificationSettings) return false;
|
if (localNotificationSettings) return false;
|
||||||
if (pusher && !supportsMSC3881) return true;
|
if (pusher && !supportsMSC3881) return true;
|
||||||
return false;
|
return false;
|
||||||
|
|
|
@ -47,8 +47,8 @@ const deviceTypeLabel: Record<DeviceType, string> = {
|
||||||
};
|
};
|
||||||
|
|
||||||
export const DeviceTypeIcon: React.FC<Props> = ({ isVerified, isSelected, deviceType }) => {
|
export const DeviceTypeIcon: React.FC<Props> = ({ isVerified, isSelected, deviceType }) => {
|
||||||
const Icon = deviceTypeIcon[deviceType] || deviceTypeIcon[DeviceType.Unknown];
|
const Icon = deviceTypeIcon[deviceType!] || deviceTypeIcon[DeviceType.Unknown];
|
||||||
const label = deviceTypeLabel[deviceType] || deviceTypeLabel[DeviceType.Unknown];
|
const label = deviceTypeLabel[deviceType!] || deviceTypeLabel[DeviceType.Unknown];
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
className={classNames("mx_DeviceTypeIcon", {
|
className={classNames("mx_DeviceTypeIcon", {
|
||||||
|
|
|
@ -212,9 +212,9 @@ const SpaceCreateMenu: React.FC<{
|
||||||
const [busy, setBusy] = useState<boolean>(false);
|
const [busy, setBusy] = useState<boolean>(false);
|
||||||
|
|
||||||
const [name, setName] = useState("");
|
const [name, setName] = useState("");
|
||||||
const spaceNameField = useRef<Field>();
|
const spaceNameField = useRef<Field>(null);
|
||||||
const [alias, setAlias] = useState("");
|
const [alias, setAlias] = useState("");
|
||||||
const spaceAliasField = useRef<RoomAliasField>();
|
const spaceAliasField = useRef<RoomAliasField>(null);
|
||||||
const [avatar, setAvatar] = useState<File | undefined>(undefined);
|
const [avatar, setAvatar] = useState<File | undefined>(undefined);
|
||||||
const [topic, setTopic] = useState<string>("");
|
const [topic, setTopic] = useState<string>("");
|
||||||
|
|
||||||
|
|
|
@ -331,9 +331,9 @@ const InnerSpacePanel = React.memo<IInnerSpacePanelProps>(
|
||||||
|
|
||||||
const SpacePanel: React.FC = () => {
|
const SpacePanel: React.FC = () => {
|
||||||
const [isPanelCollapsed, setPanelCollapsed] = useState(true);
|
const [isPanelCollapsed, setPanelCollapsed] = useState(true);
|
||||||
const ref = useRef<HTMLDivElement>();
|
const ref = useRef<HTMLDivElement>(null);
|
||||||
useLayoutEffect(() => {
|
useLayoutEffect(() => {
|
||||||
UIStore.instance.trackElementDimensions("SpacePanel", ref.current);
|
if (ref.current) UIStore.instance.trackElementDimensions("SpacePanel", ref.current);
|
||||||
return () => UIStore.instance.stopTrackingElementDimensions("SpacePanel");
|
return () => UIStore.instance.stopTrackingElementDimensions("SpacePanel");
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
|
|
|
@ -553,6 +553,7 @@ export class SpaceStoreClass extends AsyncStoreWithClient<IState> {
|
||||||
};
|
};
|
||||||
|
|
||||||
private rebuildSpaceHierarchy = (): void => {
|
private rebuildSpaceHierarchy = (): void => {
|
||||||
|
if (!this.matrixClient) return;
|
||||||
const visibleSpaces = this.matrixClient
|
const visibleSpaces = this.matrixClient
|
||||||
.getVisibleRooms(this._msc3946ProcessDynamicPredecessor)
|
.getVisibleRooms(this._msc3946ProcessDynamicPredecessor)
|
||||||
.filter((r) => r.isSpaceRoom());
|
.filter((r) => r.isSpaceRoom());
|
||||||
|
@ -589,6 +590,7 @@ export class SpaceStoreClass extends AsyncStoreWithClient<IState> {
|
||||||
};
|
};
|
||||||
|
|
||||||
private rebuildParentMap = (): void => {
|
private rebuildParentMap = (): void => {
|
||||||
|
if (!this.matrixClient) return;
|
||||||
const joinedSpaces = this.matrixClient.getVisibleRooms(this._msc3946ProcessDynamicPredecessor).filter((r) => {
|
const joinedSpaces = this.matrixClient.getVisibleRooms(this._msc3946ProcessDynamicPredecessor).filter((r) => {
|
||||||
return r.isSpaceRoom() && r.getMyMembership() === "join";
|
return r.isSpaceRoom() && r.getMyMembership() === "join";
|
||||||
});
|
});
|
||||||
|
@ -624,6 +626,7 @@ export class SpaceStoreClass extends AsyncStoreWithClient<IState> {
|
||||||
};
|
};
|
||||||
|
|
||||||
private rebuildMetaSpaces = (): void => {
|
private rebuildMetaSpaces = (): void => {
|
||||||
|
if (!this.matrixClient) return;
|
||||||
const enabledMetaSpaces = new Set(this.enabledMetaSpaces);
|
const enabledMetaSpaces = new Set(this.enabledMetaSpaces);
|
||||||
const visibleRooms = this.matrixClient.getVisibleRooms(this._msc3946ProcessDynamicPredecessor);
|
const visibleRooms = this.matrixClient.getVisibleRooms(this._msc3946ProcessDynamicPredecessor);
|
||||||
|
|
||||||
|
@ -658,6 +661,7 @@ export class SpaceStoreClass extends AsyncStoreWithClient<IState> {
|
||||||
};
|
};
|
||||||
|
|
||||||
private updateNotificationStates = (spaces?: SpaceKey[]): void => {
|
private updateNotificationStates = (spaces?: SpaceKey[]): void => {
|
||||||
|
if (!this.matrixClient) return;
|
||||||
const enabledMetaSpaces = new Set(this.enabledMetaSpaces);
|
const enabledMetaSpaces = new Set(this.enabledMetaSpaces);
|
||||||
const visibleRooms = this.matrixClient.getVisibleRooms(this._msc3946ProcessDynamicPredecessor);
|
const visibleRooms = this.matrixClient.getVisibleRooms(this._msc3946ProcessDynamicPredecessor);
|
||||||
|
|
||||||
|
@ -745,6 +749,7 @@ export class SpaceStoreClass extends AsyncStoreWithClient<IState> {
|
||||||
};
|
};
|
||||||
|
|
||||||
private onRoomsUpdate = (): void => {
|
private onRoomsUpdate = (): void => {
|
||||||
|
if (!this.matrixClient) return;
|
||||||
const visibleRooms = this.matrixClient.getVisibleRooms(this._msc3946ProcessDynamicPredecessor);
|
const visibleRooms = this.matrixClient.getVisibleRooms(this._msc3946ProcessDynamicPredecessor);
|
||||||
|
|
||||||
const prevRoomsBySpace = this.roomIdsBySpace;
|
const prevRoomsBySpace = this.roomIdsBySpace;
|
||||||
|
|
|
@ -133,7 +133,7 @@ describe("ThreadPanel", () => {
|
||||||
jest.spyOn(mockClient, "getRoom").mockReturnValue(room);
|
jest.spyOn(mockClient, "getRoom").mockReturnValue(room);
|
||||||
await room.createThreadsTimelineSets();
|
await room.createThreadsTimelineSets();
|
||||||
const [allThreads, myThreads] = room.threadsTimelineSets;
|
const [allThreads, myThreads] = room.threadsTimelineSets;
|
||||||
jest.spyOn(room, "createThreadsTimelineSets").mockReturnValue(Promise.resolve([allThreads, myThreads]));
|
jest.spyOn(room, "createThreadsTimelineSets").mockReturnValue(Promise.resolve([allThreads!, myThreads!]));
|
||||||
});
|
});
|
||||||
|
|
||||||
function toggleThreadFilter(container: HTMLElement, newFilter: ThreadFilterType) {
|
function toggleThreadFilter(container: HTMLElement, newFilter: ThreadFilterType) {
|
||||||
|
@ -195,11 +195,11 @@ describe("ThreadPanel", () => {
|
||||||
return event ? Promise.resolve(event) : Promise.reject();
|
return event ? Promise.resolve(event) : Promise.reject();
|
||||||
});
|
});
|
||||||
const [allThreads, myThreads] = room.threadsTimelineSets;
|
const [allThreads, myThreads] = room.threadsTimelineSets;
|
||||||
allThreads.addLiveEvent(otherThread.rootEvent);
|
allThreads!.addLiveEvent(otherThread.rootEvent);
|
||||||
allThreads.addLiveEvent(mixedThread.rootEvent);
|
allThreads!.addLiveEvent(mixedThread.rootEvent);
|
||||||
allThreads.addLiveEvent(ownThread.rootEvent);
|
allThreads!.addLiveEvent(ownThread.rootEvent);
|
||||||
myThreads.addLiveEvent(mixedThread.rootEvent);
|
myThreads!.addLiveEvent(mixedThread.rootEvent);
|
||||||
myThreads.addLiveEvent(ownThread.rootEvent);
|
myThreads!.addLiveEvent(ownThread.rootEvent);
|
||||||
|
|
||||||
let events: EventData[] = [];
|
let events: EventData[] = [];
|
||||||
const renderResult = render(<TestThreadPanel />);
|
const renderResult = render(<TestThreadPanel />);
|
||||||
|
@ -245,7 +245,7 @@ describe("ThreadPanel", () => {
|
||||||
return event ? Promise.resolve(event) : Promise.reject();
|
return event ? Promise.resolve(event) : Promise.reject();
|
||||||
});
|
});
|
||||||
const [allThreads] = room.threadsTimelineSets;
|
const [allThreads] = room.threadsTimelineSets;
|
||||||
allThreads.addLiveEvent(otherThread.rootEvent);
|
allThreads!.addLiveEvent(otherThread.rootEvent);
|
||||||
|
|
||||||
let events: EventData[] = [];
|
let events: EventData[] = [];
|
||||||
const renderResult = render(<TestThreadPanel />);
|
const renderResult = render(<TestThreadPanel />);
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue