mirror of
https://github.com/element-hq/element-web
synced 2024-11-23 01:35:49 +03:00
Conform more code to strictNullChecks
(#10444
* Conform more code to `strictNullChecks` * Fix tests * Fix tests
This commit is contained in:
parent
ba2608ec74
commit
c225b8ec29
29 changed files with 85 additions and 75 deletions
|
@ -24,8 +24,6 @@ import { logger } from "matrix-js-sdk/src/logger";
|
|||
import { RoomStateEvent } from "matrix-js-sdk/src/models/room-state";
|
||||
import { M_BEACON_INFO } from "matrix-js-sdk/src/@types/beacon";
|
||||
import { isSupportedReceiptType } from "matrix-js-sdk/src/utils";
|
||||
import { ReadReceipt } from "matrix-js-sdk/src/models/read-receipt";
|
||||
import { ListenerMap } from "matrix-js-sdk/src/models/typed-event-emitter";
|
||||
|
||||
import shouldHideEvent from "../../shouldHideEvent";
|
||||
import { wantsDateSeparator } from "../../DateUtils";
|
||||
|
@ -543,7 +541,7 @@ export default class MessagePanel extends React.Component<IProps, IState> {
|
|||
return null;
|
||||
}
|
||||
|
||||
private collectGhostReadMarker = (node: HTMLElement): void => {
|
||||
private collectGhostReadMarker = (node: HTMLElement | null): void => {
|
||||
if (node) {
|
||||
// now the element has appeared, change the style which will trigger the CSS transition
|
||||
requestAnimationFrame(() => {
|
||||
|
@ -788,13 +786,13 @@ export default class MessagePanel extends React.Component<IProps, IState> {
|
|||
continuation={continuation}
|
||||
isRedacted={mxEv.isRedacted()}
|
||||
replacingEventId={mxEv.replacingEventId()}
|
||||
editState={isEditing && this.props.editState}
|
||||
editState={isEditing ? this.props.editState : undefined}
|
||||
onHeightChanged={this.onHeightChanged}
|
||||
readReceipts={readReceipts}
|
||||
readReceiptMap={this.readReceiptMap}
|
||||
showUrlPreview={this.props.showUrlPreview}
|
||||
checkUnmounting={this.isUnmounting}
|
||||
eventSendStatus={mxEv.getAssociatedStatus()}
|
||||
eventSendStatus={mxEv.getAssociatedStatus() ?? undefined}
|
||||
isTwelveHour={this.props.isTwelveHour}
|
||||
permalinkCreator={this.props.permalinkCreator}
|
||||
last={last}
|
||||
|
@ -836,9 +834,7 @@ export default class MessagePanel extends React.Component<IProps, IState> {
|
|||
return null;
|
||||
}
|
||||
|
||||
const receiptDestination: ReadReceipt<string, ListenerMap<string>> = this.context.threadId
|
||||
? room.getThread(this.context.threadId)
|
||||
: room;
|
||||
const receiptDestination = this.context.threadId ? room.getThread(this.context.threadId) : room;
|
||||
|
||||
const receipts: IReadReceiptProps[] = [];
|
||||
|
||||
|
@ -1215,7 +1211,7 @@ class CreationGrouper extends BaseGrouper {
|
|||
|
||||
let summaryText: string;
|
||||
const roomId = ev.getRoomId();
|
||||
const creator = ev.sender ? ev.sender.name : ev.getSender();
|
||||
const creator = ev.sender?.name ?? ev.getSender();
|
||||
if (DMRoomMap.shared().getUserIdForRoomId(roomId)) {
|
||||
summaryText = _t("%(creator)s created this DM.", { creator });
|
||||
} else {
|
||||
|
|
|
@ -377,7 +377,7 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {
|
|||
|
||||
private roomView = createRef<HTMLElement>();
|
||||
private searchResultsPanel = createRef<ScrollPanel>();
|
||||
private messagePanel?: TimelinePanel;
|
||||
private messagePanel: TimelinePanel | null = null;
|
||||
private roomViewBody = createRef<HTMLDivElement>();
|
||||
|
||||
public static contextType = SDKContext;
|
||||
|
@ -611,11 +611,11 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {
|
|||
|
||||
const newState: Partial<IRoomState> = {
|
||||
roomId: roomId ?? undefined,
|
||||
roomAlias: this.context.roomViewStore.getRoomAlias(),
|
||||
roomAlias: this.context.roomViewStore.getRoomAlias() ?? undefined,
|
||||
roomLoading: this.context.roomViewStore.isRoomLoading(),
|
||||
roomLoadError: this.context.roomViewStore.getRoomLoadError(),
|
||||
roomLoadError: this.context.roomViewStore.getRoomLoadError() ?? undefined,
|
||||
joining: this.context.roomViewStore.isJoining(),
|
||||
replyToEvent: this.context.roomViewStore.getQuotingEvent(),
|
||||
replyToEvent: this.context.roomViewStore.getQuotingEvent() ?? undefined,
|
||||
// we should only peek once we have a ready client
|
||||
shouldPeek: this.state.matrixClientIsReady && this.context.roomViewStore.shouldPeek(),
|
||||
showReadReceipts: SettingsStore.getValue("showReadReceipts", roomId),
|
||||
|
@ -654,7 +654,7 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {
|
|||
// and the root event.
|
||||
// The rest will be lost for now, until the aggregation API on the server
|
||||
// becomes available to fetch a whole thread
|
||||
if (!initialEvent) {
|
||||
if (!initialEvent && this.context.client) {
|
||||
initialEvent = (await fetchInitialEvent(this.context.client, roomId, initialEventId)) ?? undefined;
|
||||
}
|
||||
|
||||
|
@ -848,7 +848,7 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {
|
|||
isPeeking: true, // this will change to false if peeking fails
|
||||
});
|
||||
this.context.client
|
||||
.peekInRoom(roomId)
|
||||
?.peekInRoom(roomId)
|
||||
.then((room) => {
|
||||
if (this.unmounted) {
|
||||
return;
|
||||
|
@ -883,7 +883,7 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {
|
|||
});
|
||||
} else if (room) {
|
||||
// Stop peeking because we have joined this room previously
|
||||
this.context.client.stopPeeking();
|
||||
this.context.client?.stopPeeking();
|
||||
this.setState({ isPeeking: false });
|
||||
}
|
||||
}
|
||||
|
@ -909,9 +909,9 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {
|
|||
this.onRoomViewStoreUpdate(true);
|
||||
|
||||
const call = this.getCallForRoom();
|
||||
const callState = call ? call.state : null;
|
||||
const callState = call?.state;
|
||||
this.setState({
|
||||
callState: callState,
|
||||
callState,
|
||||
});
|
||||
|
||||
this.context.legacyCallHandler.on(LegacyCallHandlerEvent.CallState, this.onCallState);
|
||||
|
@ -959,7 +959,7 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {
|
|||
}
|
||||
|
||||
if (this.state.shouldPeek) {
|
||||
this.context.client.stopPeeking();
|
||||
this.context.client?.stopPeeking();
|
||||
}
|
||||
|
||||
// stop tracking room changes to format permalinks
|
||||
|
@ -1010,7 +1010,7 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {
|
|||
|
||||
if (this.viewsLocalRoom) {
|
||||
// clean up if this was a local room
|
||||
this.context.client.store.removeRoom(this.state.room.roomId);
|
||||
this.context.client?.store.removeRoom(this.state.room.roomId);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1469,7 +1469,7 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {
|
|||
|
||||
private updatePermissions(room: Room): void {
|
||||
if (room) {
|
||||
const me = this.context.client.getUserId();
|
||||
const me = this.context.client.getSafeUserId();
|
||||
const canReact =
|
||||
room.getMyMembership() === "join" && room.currentState.maySendEvent(EventType.Reaction, me);
|
||||
const canSendMessages = room.maySendMessage();
|
||||
|
@ -1866,7 +1866,7 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {
|
|||
|
||||
// this has to be a proper method rather than an unnamed function,
|
||||
// otherwise react calls it with null on each update.
|
||||
private gatherTimelinePanelRef = (r?: TimelinePanel): void => {
|
||||
private gatherTimelinePanelRef = (r: TimelinePanel | null): void => {
|
||||
this.messagePanel = r;
|
||||
};
|
||||
|
||||
|
|
|
@ -171,7 +171,7 @@ export default class ThreadView extends React.Component<IProps, IState> {
|
|||
if (payload.event && !payload.event.getThread()) return;
|
||||
this.setState(
|
||||
{
|
||||
editState: payload.event ? new EditorStateTransfer(payload.event) : null,
|
||||
editState: payload.event ? new EditorStateTransfer(payload.event) : undefined,
|
||||
},
|
||||
() => {
|
||||
if (payload.event) {
|
||||
|
@ -213,9 +213,11 @@ export default class ThreadView extends React.Component<IProps, IState> {
|
|||
};
|
||||
|
||||
private get threadLastReply(): MatrixEvent | undefined {
|
||||
return this.state.thread?.lastReply((ev: MatrixEvent) => {
|
||||
return ev.isRelation(THREAD_RELATION_TYPE.name) && !ev.status;
|
||||
});
|
||||
return (
|
||||
this.state.thread?.lastReply((ev: MatrixEvent) => {
|
||||
return ev.isRelation(THREAD_RELATION_TYPE.name) && !ev.status;
|
||||
}) ?? undefined
|
||||
);
|
||||
}
|
||||
|
||||
private updateThread = (thread?: Thread): void => {
|
||||
|
@ -245,7 +247,7 @@ export default class ThreadView extends React.Component<IProps, IState> {
|
|||
|
||||
private setupThreadListeners(thread?: Thread | undefined, oldThread?: Thread | undefined): void {
|
||||
if (oldThread) {
|
||||
this.state.thread.off(ThreadEvent.NewReply, this.updateThreadRelation);
|
||||
this.state.thread?.off(ThreadEvent.NewReply, this.updateThreadRelation);
|
||||
this.props.room.off(RoomEvent.LocalEchoUpdated, this.updateThreadRelation);
|
||||
}
|
||||
if (thread) {
|
||||
|
@ -344,7 +346,7 @@ export default class ThreadView extends React.Component<IProps, IState> {
|
|||
};
|
||||
|
||||
public render(): React.ReactNode {
|
||||
const highlightedEventId = this.props.isInitialEventHighlighted ? this.props.initialEvent?.getId() : null;
|
||||
const highlightedEventId = this.props.isInitialEventHighlighted ? this.props.initialEvent?.getId() : undefined;
|
||||
|
||||
const threadRelation = this.threadRelation;
|
||||
|
||||
|
|
|
@ -79,7 +79,7 @@ interface IProps {
|
|||
// representing. This may or may not have a room, depending on what it's
|
||||
// a timeline representing. If it has a room, we maintain RRs etc for
|
||||
// that room.
|
||||
timelineSet?: EventTimelineSet;
|
||||
timelineSet: EventTimelineSet;
|
||||
// overlay events from a second timelineset on the main timeline
|
||||
// added to support virtual rooms
|
||||
// events from the overlay timeline set will be added by localTimestamp
|
||||
|
|
|
@ -33,6 +33,7 @@ interface IProps {
|
|||
|
||||
const BetaFeedbackDialog: React.FC<IProps> = ({ featureId, onFinished }) => {
|
||||
const info = SettingsStore.getBetaInfo(featureId);
|
||||
if (!info) return null;
|
||||
|
||||
return (
|
||||
<GenericFeatureFeedbackDialog
|
||||
|
|
|
@ -42,7 +42,7 @@ const BulkRedactDialog: React.FC<Props> = (props) => {
|
|||
const { matrixClient: cli, room, member, onFinished } = props;
|
||||
const [keepStateEvents, setKeepStateEvents] = useState(true);
|
||||
|
||||
let timeline = room.getLiveTimeline();
|
||||
let timeline: EventTimeline | null = room.getLiveTimeline();
|
||||
let eventsToRedact: MatrixEvent[] = [];
|
||||
while (timeline) {
|
||||
eventsToRedact = [
|
||||
|
@ -93,7 +93,7 @@ const BulkRedactDialog: React.FC<Props> = (props) => {
|
|||
await Promise.all(
|
||||
eventsToRedact.reverse().map(async (event): Promise<void> => {
|
||||
try {
|
||||
await cli.redactEvent(room.roomId, event.getId());
|
||||
await cli.redactEvent(room.roomId, event.getId()!);
|
||||
} catch (err) {
|
||||
// log and swallow errors
|
||||
logger.error("Could not redact", event.getId());
|
||||
|
|
|
@ -71,7 +71,7 @@ interface IProps {
|
|||
type ToolInfo = [label: string, tool: Tool];
|
||||
|
||||
const DevtoolsDialog: React.FC<IProps> = ({ roomId, onFinished }) => {
|
||||
const [tool, setTool] = useState<ToolInfo>(null);
|
||||
const [tool, setTool] = useState<ToolInfo | null>(null);
|
||||
|
||||
let body: JSX.Element;
|
||||
let onBack: () => void;
|
||||
|
|
|
@ -51,6 +51,7 @@ import { ButtonEvent } from "../elements/AccessibleButton";
|
|||
import { isLocationEvent } from "../../../utils/EventUtils";
|
||||
import { isSelfLocation, locationEventGeoUri } from "../../../utils/location";
|
||||
import { RoomContextDetails } from "../rooms/RoomContextDetails";
|
||||
import { filterBoolean } from "../../../utils/arrays";
|
||||
|
||||
const AVATAR_SIZE = 30;
|
||||
|
||||
|
@ -194,7 +195,7 @@ const transformEvent = (event: MatrixEvent): { type: string; content: IContent }
|
|||
};
|
||||
|
||||
const ForwardDialog: React.FC<IProps> = ({ matrixClient: cli, event, permalinkCreator, onFinished }) => {
|
||||
const userId = cli.getUserId();
|
||||
const userId = cli.getSafeUserId();
|
||||
const [profileInfo, setProfileInfo] = useState<any>({});
|
||||
useEffect(() => {
|
||||
cli.getProfileInfo(userId).then((info) => setProfileInfo(info));
|
||||
|
@ -242,7 +243,7 @@ const ForwardDialog: React.FC<IProps> = ({ matrixClient: cli, event, permalinkCr
|
|||
if (lcQuery) {
|
||||
rooms = new QueryMatcher<Room>(rooms, {
|
||||
keys: ["name"],
|
||||
funcs: [(r) => [r.getCanonicalAlias(), ...r.getAltAliases()].filter(Boolean)],
|
||||
funcs: [(r) => filterBoolean([r.getCanonicalAlias(), ...r.getAltAliases()])],
|
||||
shouldMatchWordsOnly: false,
|
||||
}).match(lcQuery);
|
||||
}
|
||||
|
|
|
@ -34,6 +34,7 @@ const RegistrationEmailPromptDialog: React.FC<IProps> = ({ onFinished }) => {
|
|||
|
||||
const onSubmit = async (e: SyntheticEvent): Promise<void> => {
|
||||
e.preventDefault();
|
||||
if (!fieldRef.current) return;
|
||||
if (email) {
|
||||
const valid = await fieldRef.current.validate({});
|
||||
|
||||
|
|
|
@ -141,7 +141,7 @@ export default class ServerPickerDialog extends React.PureComponent<IProps, ISta
|
|||
return !error;
|
||||
},
|
||||
invalid: function ({ error }) {
|
||||
return error;
|
||||
return error ?? null;
|
||||
},
|
||||
},
|
||||
],
|
||||
|
|
|
@ -49,7 +49,7 @@ interface ITermsDialogProps {
|
|||
/**
|
||||
* urls that the user has already agreed to
|
||||
*/
|
||||
agreedUrls?: string[];
|
||||
agreedUrls: string[];
|
||||
|
||||
/**
|
||||
* Called with:
|
||||
|
@ -127,7 +127,7 @@ export default class TermsDialog extends React.PureComponent<ITermsDialogProps,
|
|||
};
|
||||
|
||||
public render(): React.ReactNode {
|
||||
const rows = [];
|
||||
const rows: JSX.Element[] = [];
|
||||
for (const policiesAndService of this.props.policiesAndServicePairs) {
|
||||
const parsedBaseUrl = url.parse(policiesAndService.service.baseUrl);
|
||||
|
||||
|
@ -135,8 +135,8 @@ export default class TermsDialog extends React.PureComponent<ITermsDialogProps,
|
|||
for (let i = 0; i < policyValues.length; ++i) {
|
||||
const termDoc = policyValues[i];
|
||||
const termsLang = pickBestLanguage(Object.keys(termDoc).filter((k) => k !== "version"));
|
||||
let serviceName;
|
||||
let summary;
|
||||
let serviceName: JSX.Element | undefined;
|
||||
let summary: JSX.Element | undefined;
|
||||
if (i === 0) {
|
||||
serviceName = this.nameForServiceType(policiesAndService.service.serviceType, parsedBaseUrl.host);
|
||||
summary = this.summaryForServiceType(policiesAndService.service.serviceType);
|
||||
|
|
|
@ -100,7 +100,7 @@ export default class TextInputDialog extends React.Component<IProps, IState> {
|
|||
};
|
||||
|
||||
private onValidate = async (fieldState: IFieldState): Promise<IValidationResult> => {
|
||||
const result = await this.props.validator(fieldState);
|
||||
const result = await this.props.validator!(fieldState);
|
||||
this.setState({
|
||||
valid: !!result.valid,
|
||||
});
|
||||
|
|
|
@ -38,7 +38,7 @@ export function RoomResultContextMenus({ room }: Props): JSX.Element {
|
|||
const [generalMenuPosition, setGeneralMenuPosition] = useState<DOMRect | null>(null);
|
||||
const [notificationMenuPosition, setNotificationMenuPosition] = useState<DOMRect | null>(null);
|
||||
|
||||
let generalMenu: JSX.Element;
|
||||
let generalMenu: JSX.Element | undefined;
|
||||
if (generalMenuPosition !== null) {
|
||||
if (room.isSpaceRoom()) {
|
||||
generalMenu = (
|
||||
|
@ -59,7 +59,7 @@ export function RoomResultContextMenus({ room }: Props): JSX.Element {
|
|||
}
|
||||
}
|
||||
|
||||
let notificationMenu: JSX.Element;
|
||||
let notificationMenu: JSX.Element | undefined;
|
||||
if (notificationMenuPosition !== null) {
|
||||
notificationMenu = (
|
||||
<RoomNotificationContextMenu
|
||||
|
|
|
@ -440,7 +440,7 @@ const SpotlightDialog: React.FC<IProps> = ({ initialText = "", initialFilter = n
|
|||
|
||||
// Sort results by most recent activity
|
||||
|
||||
const myUserId = cli.getUserId();
|
||||
const myUserId = cli.getSafeUserId();
|
||||
for (const resultArray of Object.values(results)) {
|
||||
resultArray.sort((a: Result, b: Result) => {
|
||||
if (isRoomResult(a) || isRoomResult(b)) {
|
||||
|
|
|
@ -27,17 +27,17 @@ enum Phases {
|
|||
|
||||
interface IProps {
|
||||
onValueChanged?: (value: string, shouldSubmit: boolean) => void;
|
||||
initialValue?: string;
|
||||
label?: string;
|
||||
placeholder?: string;
|
||||
className?: string;
|
||||
initialValue: string;
|
||||
label: string;
|
||||
placeholder: string;
|
||||
className: string;
|
||||
labelClassName?: string;
|
||||
placeholderClassName?: string;
|
||||
placeholderClassName: string;
|
||||
// Overrides blurToSubmit if true
|
||||
blurToCancel?: boolean;
|
||||
// Will cause onValueChanged(value, true) to fire on blur
|
||||
blurToSubmit?: boolean;
|
||||
editable?: boolean;
|
||||
blurToSubmit: boolean;
|
||||
editable: boolean;
|
||||
}
|
||||
|
||||
interface IState {
|
||||
|
@ -109,11 +109,11 @@ export default class EditableText extends React.Component<IProps, IState> {
|
|||
this.value = this.props.initialValue;
|
||||
this.showPlaceholder(!this.value);
|
||||
this.onValueChanged(false);
|
||||
this.editableDiv.current.blur();
|
||||
this.editableDiv.current?.blur();
|
||||
};
|
||||
|
||||
private onValueChanged = (shouldSubmit: boolean): void => {
|
||||
this.props.onValueChanged(this.value, shouldSubmit);
|
||||
this.props.onValueChanged?.(this.value, shouldSubmit);
|
||||
};
|
||||
|
||||
private onKeyDown = (ev: React.KeyboardEvent<HTMLDivElement>): void => {
|
||||
|
@ -171,7 +171,7 @@ export default class EditableText extends React.Component<IProps, IState> {
|
|||
|
||||
private onFinish = (
|
||||
ev: React.KeyboardEvent<HTMLDivElement> | React.FocusEvent<HTMLDivElement>,
|
||||
shouldSubmit?: boolean,
|
||||
shouldSubmit = false,
|
||||
): void => {
|
||||
// eslint-disable-next-line @typescript-eslint/no-this-alias
|
||||
const self = this;
|
||||
|
|
|
@ -187,8 +187,8 @@ export default class EventListSummary extends React.Component<IProps> {
|
|||
|
||||
let transition = t;
|
||||
|
||||
if (i < transitions.length - 1 && modMap[t] && modMap[t].after === t2) {
|
||||
transition = modMap[t].newTransition;
|
||||
if (i < transitions.length - 1 && modMap[t] && modMap[t]!.after === t2) {
|
||||
transition = modMap[t]!.newTransition;
|
||||
i++;
|
||||
}
|
||||
|
||||
|
@ -380,7 +380,7 @@ export default class EventListSummary extends React.Component<IProps> {
|
|||
return res ?? null;
|
||||
}
|
||||
|
||||
private static getTransitionSequence(events: IUserEvents[]): TransitionType[] {
|
||||
private static getTransitionSequence(events: IUserEvents[]): Array<TransitionType | null> {
|
||||
return events.map(EventListSummary.getTransition);
|
||||
}
|
||||
|
||||
|
|
|
@ -148,6 +148,7 @@ export default class ReplyChain extends React.Component<IProps, IState> {
|
|||
private async getNextEvent(ev: MatrixEvent): Promise<MatrixEvent | null> {
|
||||
try {
|
||||
const inReplyToEventId = getParentEventId(ev);
|
||||
if (!inReplyToEventId) return null;
|
||||
return await this.getEvent(inReplyToEventId);
|
||||
} catch (e) {
|
||||
return null;
|
||||
|
@ -196,7 +197,7 @@ export default class ReplyChain extends React.Component<IProps, IState> {
|
|||
};
|
||||
|
||||
private getReplyChainColorClass(ev: MatrixEvent): string {
|
||||
return getUserNameColorClass(ev.getSender()).replace("Username", "ReplyChain");
|
||||
return getUserNameColorClass(ev.getSender()!).replace("Username", "ReplyChain");
|
||||
}
|
||||
|
||||
public render(): React.ReactNode {
|
||||
|
@ -231,8 +232,8 @@ export default class ReplyChain extends React.Component<IProps, IState> {
|
|||
pill: (
|
||||
<Pill
|
||||
type={PillType.UserMention}
|
||||
room={room}
|
||||
url={makeUserPermalink(ev.getSender())}
|
||||
room={room ?? undefined}
|
||||
url={makeUserPermalink(ev.getSender()!)}
|
||||
shouldShowPillAvatar={SettingsStore.getValue("Pill.shouldShowPillAvatar")}
|
||||
/>
|
||||
),
|
||||
|
|
|
@ -63,7 +63,7 @@ export default class EditHistoryMessage extends React.PureComponent<IProps, ISta
|
|||
const event = this.props.mxEvent;
|
||||
const room = cli.getRoom(event.getRoomId());
|
||||
event.localRedactionEvent()?.on(MatrixEventEvent.Status, this.onAssociatedStatusChanged);
|
||||
const canRedact = room.currentState.maySendRedactionForEvent(event, userId);
|
||||
const canRedact = room?.currentState.maySendRedactionForEvent(event, userId) ?? false;
|
||||
this.state = { canRedact, sendStatus: event.getAssociatedStatus() };
|
||||
}
|
||||
|
||||
|
|
|
@ -71,7 +71,7 @@ export const usePinnedEvents = (room?: Room): string[] => {
|
|||
};
|
||||
|
||||
function getReadPinnedEventIds(room?: Room): Set<string> {
|
||||
return new Set(room.getAccountData(ReadPinsEventId)?.getContent()?.event_ids ?? []);
|
||||
return new Set(room?.getAccountData(ReadPinsEventId)?.getContent()?.event_ids ?? []);
|
||||
}
|
||||
|
||||
export const useReadPinnedEvents = (room?: Room): Set<string> => {
|
||||
|
|
|
@ -448,7 +448,7 @@ export const UserOptionsSection: React.FC<{
|
|||
const inviter = new MultiInviter(roomId || "");
|
||||
await inviter.invite([member.userId]).then(() => {
|
||||
if (inviter.getCompletionState(member.userId) !== "invited") {
|
||||
throw new Error(inviter.getErrorText(member.userId));
|
||||
throw new Error(inviter.getErrorText(member.userId) ?? undefined);
|
||||
}
|
||||
});
|
||||
} catch (err) {
|
||||
|
@ -766,8 +766,8 @@ export const BanToggleButton = ({
|
|||
const myMember = child.getMember(cli.credentials.userId || "");
|
||||
const theirMember = child.getMember(member.userId);
|
||||
return (
|
||||
myMember &&
|
||||
theirMember &&
|
||||
!!myMember &&
|
||||
!!theirMember &&
|
||||
theirMember.membership !== "ban" &&
|
||||
myMember.powerLevel > theirMember.powerLevel &&
|
||||
child.currentState.hasSufficientPowerLevelFor("ban", myMember.powerLevel)
|
||||
|
|
|
@ -25,7 +25,7 @@ import { OverflowMenuContext } from "./MessageComposerButtons";
|
|||
|
||||
interface IEmojiButtonProps {
|
||||
addEmoji: (unicode: string) => boolean;
|
||||
menuPosition: MenuProps;
|
||||
menuPosition?: MenuProps;
|
||||
className?: string;
|
||||
}
|
||||
|
||||
|
|
|
@ -73,8 +73,8 @@ const MessageComposerButtons: React.FC<IProps> = (props: IProps) => {
|
|||
return null;
|
||||
}
|
||||
|
||||
let mainButtons: ReactElement[];
|
||||
let moreButtons: ReactElement[];
|
||||
let mainButtons: ReactNode[];
|
||||
let moreButtons: ReactNode[];
|
||||
if (narrow) {
|
||||
mainButtons = [
|
||||
isWysiwygLabEnabled ? (
|
||||
|
|
|
@ -75,8 +75,8 @@ export const usePermalinkEvent = (
|
|||
const fetchRoomEvent = async (): Promise<void> => {
|
||||
try {
|
||||
const eventData = await MatrixClientPeg.get().fetchRoomEvent(
|
||||
parseResult.roomIdOrAlias,
|
||||
parseResult.eventId,
|
||||
parseResult.roomIdOrAlias!,
|
||||
parseResult.eventId!,
|
||||
);
|
||||
setEvent(new MatrixEvent(eventData));
|
||||
} catch {}
|
||||
|
|
|
@ -83,7 +83,7 @@ const findRoom = (roomIdOrAlias: string): Room | null => {
|
|||
export const usePermalinkTargetRoom = (
|
||||
type: PillType | null,
|
||||
parseResult: PermalinkParts | null,
|
||||
permalinkRoom: Room | null,
|
||||
permalinkRoom: Room | undefined,
|
||||
): Room | null => {
|
||||
// The listed permalink types require a room.
|
||||
// If it cannot be initially determined, it will be looked up later by a memo hook.
|
||||
|
|
|
@ -15,7 +15,6 @@ limitations under the License.
|
|||
*/
|
||||
|
||||
import React from "react";
|
||||
import { Optional } from "matrix-events-sdk";
|
||||
|
||||
import { _t } from "../languageHandler";
|
||||
import SdkConfig from "../SdkConfig";
|
||||
|
@ -75,7 +74,7 @@ const onLearnMorePreviouslyOptedIn = (): void => {
|
|||
|
||||
const TOAST_KEY = "analytics";
|
||||
|
||||
export function getPolicyUrl(): Optional<string> {
|
||||
export function getPolicyUrl(): string | undefined {
|
||||
return SdkConfig.get("privacy_policy_url");
|
||||
}
|
||||
|
||||
|
|
|
@ -22,7 +22,10 @@ import { Member } from "./direct-messages";
|
|||
import DMRoomMap from "./DMRoomMap";
|
||||
|
||||
export const compareMembers =
|
||||
(activityScores: Record<string, IActivityScore>, memberScores: Record<string, IMemberScore>) =>
|
||||
(
|
||||
activityScores: Record<string, IActivityScore | undefined>,
|
||||
memberScores: Record<string, IMemberScore | undefined>,
|
||||
) =>
|
||||
(a: Member | RoomMember, b: Member | RoomMember): number => {
|
||||
const aActivityScore = activityScores[a.userId]?.score ?? 0;
|
||||
const aMemberScore = memberScores[a.userId]?.score ?? 0;
|
||||
|
|
|
@ -716,7 +716,7 @@ describe("MessagePanel", function () {
|
|||
// Increase the length of the loop here to test performance issues with
|
||||
// rendering
|
||||
|
||||
const events = [];
|
||||
const events: MatrixEvent[] = [];
|
||||
for (let i = 0; i < 100; i++) {
|
||||
events.push(
|
||||
TestUtilsMatrix.mkMembership({
|
||||
|
|
|
@ -54,6 +54,7 @@ describe("ForwardDialog", () => {
|
|||
});
|
||||
const mockClient = getMockClientWithEventEmitter({
|
||||
getUserId: jest.fn().mockReturnValue(aliceId),
|
||||
getSafeUserId: jest.fn().mockReturnValue(aliceId),
|
||||
isGuest: jest.fn().mockReturnValue(false),
|
||||
getVisibleRooms: jest.fn().mockReturnValue([]),
|
||||
getRoom: jest.fn(),
|
||||
|
@ -92,6 +93,7 @@ describe("ForwardDialog", () => {
|
|||
DMRoomMap.makeShared();
|
||||
jest.clearAllMocks();
|
||||
mockClient.getUserId.mockReturnValue("@bob:example.org");
|
||||
mockClient.getSafeUserId.mockReturnValue("@bob:example.org");
|
||||
mockClient.sendEvent.mockReset();
|
||||
});
|
||||
|
||||
|
|
|
@ -112,6 +112,7 @@ const mockClient = mocked({
|
|||
setIgnoredUsers: jest.fn(),
|
||||
isCryptoEnabled: jest.fn(),
|
||||
getUserId: jest.fn(),
|
||||
getSafeUserId: jest.fn(),
|
||||
on: jest.fn(),
|
||||
off: jest.fn(),
|
||||
isSynapseAdministrator: jest.fn().mockResolvedValue(false),
|
||||
|
@ -348,6 +349,7 @@ describe("<DeviceItem />", () => {
|
|||
});
|
||||
|
||||
it("when userId is the same as userId from client, uses isCrossSigningVerified to determine if button is shown", () => {
|
||||
mockClient.getSafeUserId.mockReturnValueOnce(defaultUserId);
|
||||
mockClient.getUserId.mockReturnValueOnce(defaultUserId);
|
||||
renderComponent();
|
||||
|
||||
|
@ -431,6 +433,7 @@ describe("<UserOptionsSection />", () => {
|
|||
});
|
||||
|
||||
it("does not show ignore or direct message buttons when member userId matches client userId", () => {
|
||||
mockClient.getSafeUserId.mockReturnValueOnce(member.userId);
|
||||
mockClient.getUserId.mockReturnValueOnce(member.userId);
|
||||
renderComponent();
|
||||
|
||||
|
@ -676,6 +679,7 @@ describe("<PowerLevelEditor />", () => {
|
|||
content: { users: { [defaultUserId]: startPowerLevel }, users_default: 1 },
|
||||
});
|
||||
mockRoom.currentState.getStateEvents.mockReturnValue(powerLevelEvent);
|
||||
mockClient.getSafeUserId.mockReturnValueOnce(defaultUserId);
|
||||
mockClient.getUserId.mockReturnValueOnce(defaultUserId);
|
||||
mockClient.setPowerLevel.mockResolvedValueOnce({ event_id: "123" });
|
||||
renderComponent();
|
||||
|
@ -879,7 +883,7 @@ describe("<BanToggleButton />", () => {
|
|||
},
|
||||
};
|
||||
|
||||
expect(callback(mockRoom)).toBe(null);
|
||||
expect(callback(mockRoom)).toBe(false);
|
||||
expect(callback(mockRoom)).toBe(true);
|
||||
});
|
||||
|
||||
|
|
Loading…
Reference in a new issue