Conform more of the codebase to strictNullChecks
(#10350
* Conform more of the codebase to `strictNullChecks` * Iterate * Generics ftw * Iterate
This commit is contained in:
parent
d53e91802d
commit
127a3b667c
53 changed files with 279 additions and 263 deletions
|
@ -61,7 +61,7 @@ const RoomContextMenu: React.FC<IProps> = ({ room, onFinished, ...props }) => {
|
|||
RoomListStore.instance.getTagsForRoom(room),
|
||||
);
|
||||
|
||||
let leaveOption: JSX.Element;
|
||||
let leaveOption: JSX.Element | undefined;
|
||||
if (roomTags.includes(DefaultTagID.Archived)) {
|
||||
const onForgetRoomClick = (ev: ButtonEvent): void => {
|
||||
ev.preventDefault();
|
||||
|
@ -112,7 +112,7 @@ const RoomContextMenu: React.FC<IProps> = ({ room, onFinished, ...props }) => {
|
|||
const isVideoRoom =
|
||||
videoRoomsEnabled && (room.isElementVideoRoom() || (elementCallVideoRoomsEnabled && room.isCallRoom()));
|
||||
|
||||
let inviteOption: JSX.Element;
|
||||
let inviteOption: JSX.Element | undefined;
|
||||
if (room.canInvite(cli.getUserId()!) && !isDm) {
|
||||
const onInviteClick = (ev: ButtonEvent): void => {
|
||||
ev.preventDefault();
|
||||
|
@ -136,9 +136,9 @@ const RoomContextMenu: React.FC<IProps> = ({ room, onFinished, ...props }) => {
|
|||
);
|
||||
}
|
||||
|
||||
let favouriteOption: JSX.Element;
|
||||
let lowPriorityOption: JSX.Element;
|
||||
let notificationOption: JSX.Element;
|
||||
let favouriteOption: JSX.Element | undefined;
|
||||
let lowPriorityOption: JSX.Element | undefined;
|
||||
let notificationOption: JSX.Element | undefined;
|
||||
if (room.getMyMembership() === "join") {
|
||||
const isFavorite = roomTags.includes(DefaultTagID.Favourite);
|
||||
favouriteOption = (
|
||||
|
@ -208,8 +208,8 @@ const RoomContextMenu: React.FC<IProps> = ({ room, onFinished, ...props }) => {
|
|||
);
|
||||
}
|
||||
|
||||
let peopleOption: JSX.Element;
|
||||
let copyLinkOption: JSX.Element;
|
||||
let peopleOption: JSX.Element | undefined;
|
||||
let copyLinkOption: JSX.Element | undefined;
|
||||
if (!isDm) {
|
||||
peopleOption = (
|
||||
<IconizedContextMenuOption
|
||||
|
@ -247,7 +247,7 @@ const RoomContextMenu: React.FC<IProps> = ({ room, onFinished, ...props }) => {
|
|||
);
|
||||
}
|
||||
|
||||
let filesOption: JSX.Element;
|
||||
let filesOption: JSX.Element | undefined;
|
||||
if (!isVideoRoom) {
|
||||
filesOption = (
|
||||
<IconizedContextMenuOption
|
||||
|
@ -266,9 +266,9 @@ const RoomContextMenu: React.FC<IProps> = ({ room, onFinished, ...props }) => {
|
|||
}
|
||||
|
||||
const pinningEnabled = useFeatureEnabled("feature_pinning");
|
||||
const pinCount = usePinnedEvents(pinningEnabled && room)?.length;
|
||||
const pinCount = usePinnedEvents(pinningEnabled ? room : undefined)?.length;
|
||||
|
||||
let pinsOption: JSX.Element;
|
||||
let pinsOption: JSX.Element | undefined;
|
||||
if (pinningEnabled && !isVideoRoom) {
|
||||
pinsOption = (
|
||||
<IconizedContextMenuOption
|
||||
|
@ -288,7 +288,7 @@ const RoomContextMenu: React.FC<IProps> = ({ room, onFinished, ...props }) => {
|
|||
);
|
||||
}
|
||||
|
||||
let widgetsOption: JSX.Element;
|
||||
let widgetsOption: JSX.Element | undefined;
|
||||
if (!isVideoRoom) {
|
||||
widgetsOption = (
|
||||
<IconizedContextMenuOption
|
||||
|
@ -306,7 +306,7 @@ const RoomContextMenu: React.FC<IProps> = ({ room, onFinished, ...props }) => {
|
|||
);
|
||||
}
|
||||
|
||||
let exportChatOption: JSX.Element;
|
||||
let exportChatOption: JSX.Element | undefined;
|
||||
if (!isVideoRoom) {
|
||||
exportChatOption = (
|
||||
<IconizedContextMenuOption
|
||||
|
|
|
@ -40,6 +40,7 @@ import DecoratedRoomAvatar from "../avatars/DecoratedRoomAvatar";
|
|||
import QueryMatcher from "../../../autocomplete/QueryMatcher";
|
||||
import LazyRenderList from "../elements/LazyRenderList";
|
||||
import { useSettingValue } from "../../../hooks/useSettings";
|
||||
import { filterBoolean } from "../../../utils/arrays";
|
||||
|
||||
// These values match CSS
|
||||
const ROW_HEIGHT = 32 + 12;
|
||||
|
@ -56,7 +57,7 @@ interface IProps {
|
|||
export const Entry: React.FC<{
|
||||
room: Room;
|
||||
checked: boolean;
|
||||
onChange(value: boolean): void;
|
||||
onChange?(value: boolean): void;
|
||||
}> = ({ room, checked, onChange }) => {
|
||||
return (
|
||||
<label className="mx_AddExistingToSpace_entry">
|
||||
|
@ -67,7 +68,7 @@ export const Entry: React.FC<{
|
|||
)}
|
||||
<span className="mx_AddExistingToSpace_entry_name">{room.name}</span>
|
||||
<StyledCheckbox
|
||||
onChange={onChange ? (e) => onChange(e.currentTarget.checked) : null}
|
||||
onChange={onChange ? (e) => onChange(e.currentTarget.checked) : undefined}
|
||||
checked={checked}
|
||||
disabled={!onChange}
|
||||
/>
|
||||
|
@ -150,8 +151,8 @@ export const AddExistingToSpace: React.FC<IAddExistingToSpaceProps> = ({
|
|||
});
|
||||
|
||||
const [selectedToAdd, setSelectedToAdd] = useState(new Set<Room>());
|
||||
const [progress, setProgress] = useState<number>(null);
|
||||
const [error, setError] = useState<Error>(null);
|
||||
const [progress, setProgress] = useState<number | null>(null);
|
||||
const [error, setError] = useState<Error | null>(null);
|
||||
const [query, setQuery] = useState("");
|
||||
const lcQuery = query.toLowerCase().trim();
|
||||
|
||||
|
@ -164,7 +165,7 @@ export const AddExistingToSpace: React.FC<IAddExistingToSpaceProps> = ({
|
|||
if (lcQuery) {
|
||||
const matcher = new QueryMatcher<Room>(visibleRooms, {
|
||||
keys: ["name"],
|
||||
funcs: [(r) => [r.getCanonicalAlias(), ...r.getAltAliases()].filter(Boolean)],
|
||||
funcs: [(r) => filterBoolean([r.getCanonicalAlias(), ...r.getAltAliases()])],
|
||||
shouldMatchWordsOnly: false,
|
||||
});
|
||||
|
||||
|
@ -172,7 +173,7 @@ export const AddExistingToSpace: React.FC<IAddExistingToSpaceProps> = ({
|
|||
}
|
||||
|
||||
const joinRule = space.getJoinRule();
|
||||
return sortRooms(rooms).reduce(
|
||||
return sortRooms(rooms).reduce<[spaces: Room[], rooms: Room[], dms: Room[]]>(
|
||||
(arr, room) => {
|
||||
if (room.isSpaceRoom()) {
|
||||
if (room !== space && !existingSubspacesSet.has(room)) {
|
||||
|
@ -289,7 +290,7 @@ export const AddExistingToSpace: React.FC<IAddExistingToSpaceProps> = ({
|
|||
}
|
||||
setSelectedToAdd(new Set(selectedToAdd));
|
||||
}
|
||||
: null;
|
||||
: undefined;
|
||||
|
||||
// only count spaces when alone as they're shown on a separate modal all on their own
|
||||
const numSpaces = spacesRenderer && !dmsRenderer && !roomsRenderer ? spaces.length : 0;
|
||||
|
@ -373,7 +374,7 @@ const defaultRendererFactory =
|
|||
? (checked: boolean) => {
|
||||
onChange(checked, room);
|
||||
}
|
||||
: null
|
||||
: undefined
|
||||
}
|
||||
/>
|
||||
)}
|
||||
|
@ -397,7 +398,7 @@ export const SubspaceSelector: React.FC<ISubspaceSelectorProps> = ({ title, spac
|
|||
return [
|
||||
space,
|
||||
...SpaceStore.instance.getChildSpaces(space.roomId).filter((space) => {
|
||||
return space.currentState.maySendStateEvent(EventType.SpaceChild, space.client.credentials.userId);
|
||||
return space.currentState.maySendStateEvent(EventType.SpaceChild, space.client.getSafeUserId());
|
||||
}),
|
||||
];
|
||||
}, [space]);
|
||||
|
|
|
@ -153,12 +153,11 @@ export default class BaseDialog extends React.Component<IProps> {
|
|||
|
||||
return (
|
||||
<MatrixClientContext.Provider value={this.matrixClient}>
|
||||
<PosthogScreenTracker screenName={this.props.screenName} />
|
||||
{this.props.screenName && <PosthogScreenTracker screenName={this.props.screenName} />}
|
||||
<FocusLock
|
||||
returnFocus={true}
|
||||
lockProps={lockProps}
|
||||
className={classNames({
|
||||
[this.props.className]: true,
|
||||
className={classNames(this.props.className, {
|
||||
mx_Dialog_fixedWidth: this.props.fixedWidth,
|
||||
})}
|
||||
>
|
||||
|
|
|
@ -74,6 +74,7 @@ import { InviteKind } from "./InviteDialogTypes";
|
|||
import Modal from "../../../Modal";
|
||||
import dis from "../../../dispatcher/dispatcher";
|
||||
import { privateShouldBeEncrypted } from "../../../utils/rooms";
|
||||
import { NonEmptyArray } from "../../../@types/common";
|
||||
|
||||
// we have a number of types defined from the Matrix spec which can't reasonably be altered here.
|
||||
/* eslint-disable camelcase */
|
||||
|
@ -1421,10 +1422,9 @@ export default class InviteDialog extends React.PureComponent<Props, IInviteDial
|
|||
|
||||
let dialogContent;
|
||||
if (this.props.kind === InviteKind.CallTransfer) {
|
||||
const tabs: Tab[] = [];
|
||||
tabs.push(
|
||||
const tabs: NonEmptyArray<Tab> = [
|
||||
new Tab(TabId.UserDirectory, _td("User Directory"), "mx_InviteDialog_userDirectoryIcon", usersSection),
|
||||
);
|
||||
];
|
||||
|
||||
const backspaceButton = <DialPadBackspaceButton onBackspacePress={this.onDeletePress} />;
|
||||
|
||||
|
|
|
@ -34,6 +34,7 @@ import BaseDialog from "./BaseDialog";
|
|||
import { Action } from "../../../dispatcher/actions";
|
||||
import { VoipRoomSettingsTab } from "../settings/tabs/room/VoipRoomSettingsTab";
|
||||
import { ActionPayload } from "../../../dispatcher/payloads";
|
||||
import { NonEmptyArray } from "../../../@types/common";
|
||||
|
||||
export const ROOM_GENERAL_TAB = "ROOM_GENERAL_TAB";
|
||||
export const ROOM_VOIP_TAB = "ROOM_VOIP_TAB";
|
||||
|
@ -85,11 +86,11 @@ export default class RoomSettingsDialog extends React.Component<IProps, IState>
|
|||
|
||||
private onRoomName = (): void => {
|
||||
this.setState({
|
||||
roomName: MatrixClientPeg.get().getRoom(this.props.roomId).name,
|
||||
roomName: MatrixClientPeg.get().getRoom(this.props.roomId)?.name ?? "",
|
||||
});
|
||||
};
|
||||
|
||||
private getTabs(): Tab[] {
|
||||
private getTabs(): NonEmptyArray<Tab> {
|
||||
const tabs: Tab[] = [];
|
||||
|
||||
tabs.push(
|
||||
|
@ -178,7 +179,7 @@ export default class RoomSettingsDialog extends React.Component<IProps, IState>
|
|||
);
|
||||
}
|
||||
|
||||
return tabs;
|
||||
return tabs as NonEmptyArray<Tab>;
|
||||
}
|
||||
|
||||
public render(): React.ReactNode {
|
||||
|
|
|
@ -26,6 +26,7 @@ import SettingsStore from "../../../settings/SettingsStore";
|
|||
import { SettingLevel } from "../../../settings/SettingLevel";
|
||||
import RoomName from "../elements/RoomName";
|
||||
import { SpacePreferenceTab } from "../../../dispatcher/payloads/OpenSpacePreferencesPayload";
|
||||
import { NonEmptyArray } from "../../../@types/common";
|
||||
|
||||
interface IProps {
|
||||
space: Room;
|
||||
|
@ -69,7 +70,7 @@ const SpacePreferencesAppearanceTab: React.FC<Pick<IProps, "space">> = ({ space
|
|||
};
|
||||
|
||||
const SpacePreferencesDialog: React.FC<IProps> = ({ space, initialTabId, onFinished }) => {
|
||||
const tabs = [
|
||||
const tabs: NonEmptyArray<Tab> = [
|
||||
new Tab(
|
||||
SpacePreferenceTab.Appearance,
|
||||
_td("Appearance"),
|
||||
|
|
|
@ -30,6 +30,7 @@ import { UIFeature } from "../../../settings/UIFeature";
|
|||
import AdvancedRoomSettingsTab from "../settings/tabs/room/AdvancedRoomSettingsTab";
|
||||
import RolesRoomSettingsTab from "../settings/tabs/room/RolesRoomSettingsTab";
|
||||
import { Action } from "../../../dispatcher/actions";
|
||||
import { NonEmptyArray } from "../../../@types/common";
|
||||
|
||||
export enum SpaceSettingsTab {
|
||||
General = "SPACE_GENERAL_TAB",
|
||||
|
@ -79,7 +80,7 @@ const SpaceSettingsDialog: React.FC<IProps> = ({ matrixClient: cli, space, onFin
|
|||
<AdvancedRoomSettingsTab roomId={space.roomId} closeSettingsFn={onFinished} />,
|
||||
)
|
||||
: null,
|
||||
].filter(Boolean);
|
||||
].filter(Boolean) as NonEmptyArray<Tab>;
|
||||
}, [cli, space, onFinished]);
|
||||
|
||||
return (
|
||||
|
|
|
@ -36,6 +36,7 @@ import SidebarUserSettingsTab from "../settings/tabs/user/SidebarUserSettingsTab
|
|||
import KeyboardUserSettingsTab from "../settings/tabs/user/KeyboardUserSettingsTab";
|
||||
import SessionManagerTab from "../settings/tabs/user/SessionManagerTab";
|
||||
import { UserTab } from "./UserTab";
|
||||
import { NonEmptyArray } from "../../../@types/common";
|
||||
|
||||
interface IProps {
|
||||
initialTabId?: UserTab;
|
||||
|
@ -80,7 +81,7 @@ export default class UserSettingsDialog extends React.Component<IProps, IState>
|
|||
this.setState({ newSessionManagerEnabled: newValue });
|
||||
};
|
||||
|
||||
private getTabs(): Tab[] {
|
||||
private getTabs(): NonEmptyArray<Tab> {
|
||||
const tabs: Tab[] = [];
|
||||
|
||||
tabs.push(
|
||||
|
@ -207,7 +208,7 @@ export default class UserSettingsDialog extends React.Component<IProps, IState>
|
|||
),
|
||||
);
|
||||
|
||||
return tabs;
|
||||
return tabs as NonEmptyArray<Tab>;
|
||||
}
|
||||
|
||||
public render(): React.ReactNode {
|
||||
|
|
|
@ -23,6 +23,7 @@ import DialogButtons from "./DialogButtons";
|
|||
import AccessibleButton from "./AccessibleButton";
|
||||
import TabbedView, { Tab, TabLocation } from "../../structures/TabbedView";
|
||||
import PlatformPeg from "../../../PlatformPeg";
|
||||
import { NonEmptyArray } from "../../../@types/common";
|
||||
|
||||
export function getDesktopCapturerSources(): Promise<Array<DesktopCapturerSource>> {
|
||||
const options: GetSourcesOptions = {
|
||||
|
@ -80,7 +81,7 @@ export interface PickerIState {
|
|||
selectedSource: DesktopCapturerSource | null;
|
||||
}
|
||||
export interface PickerIProps {
|
||||
onFinished(sourceId: string): void;
|
||||
onFinished(sourceId?: string): void;
|
||||
}
|
||||
|
||||
export default class DesktopCapturerSourcePicker extends React.Component<PickerIProps, PickerIState> {
|
||||
|
@ -129,7 +130,7 @@ export default class DesktopCapturerSourcePicker extends React.Component<PickerI
|
|||
};
|
||||
|
||||
private onCloseClick = (): void => {
|
||||
this.props.onFinished(null);
|
||||
this.props.onFinished();
|
||||
};
|
||||
|
||||
private getTab(type: "screen" | "window", label: string): Tab {
|
||||
|
@ -150,7 +151,7 @@ export default class DesktopCapturerSourcePicker extends React.Component<PickerI
|
|||
}
|
||||
|
||||
public render(): React.ReactNode {
|
||||
const tabs = [
|
||||
const tabs: NonEmptyArray<Tab> = [
|
||||
this.getTab("screen", _t("Share entire screen")),
|
||||
this.getTab("window", _t("Application window")),
|
||||
];
|
||||
|
|
|
@ -25,7 +25,7 @@ import { objectHasDiff } from "../../../utils/objects";
|
|||
|
||||
const CUSTOM_VALUE = "SELECT_VALUE_CUSTOM";
|
||||
|
||||
interface IProps {
|
||||
interface Props<K extends undefined | string> {
|
||||
value: number;
|
||||
// The maximum value that can be set with the power selector
|
||||
maxValue: number;
|
||||
|
@ -35,13 +35,14 @@ interface IProps {
|
|||
|
||||
// should the user be able to change the value? false by default.
|
||||
disabled?: boolean;
|
||||
onChange?: (value: number, powerLevelKey: string) => void;
|
||||
|
||||
// Optional key to pass as the second argument to `onChange`
|
||||
powerLevelKey?: string;
|
||||
|
||||
// The name to annotate the selector with
|
||||
label?: string;
|
||||
|
||||
onChange(value: number, powerLevelKey: K extends undefined ? void : K): void;
|
||||
|
||||
// Optional key to pass as the second argument to `onChange`
|
||||
powerLevelKey: K extends undefined ? void : K;
|
||||
}
|
||||
|
||||
interface IState {
|
||||
|
@ -54,13 +55,13 @@ interface IState {
|
|||
custom?: boolean;
|
||||
}
|
||||
|
||||
export default class PowerSelector extends React.Component<IProps, IState> {
|
||||
public static defaultProps: Partial<IProps> = {
|
||||
export default class PowerSelector<K extends undefined | string> extends React.Component<Props<K>, IState> {
|
||||
public static defaultProps: Partial<Props<any>> = {
|
||||
maxValue: Infinity,
|
||||
usersDefault: 0,
|
||||
};
|
||||
|
||||
public constructor(props: IProps) {
|
||||
public constructor(props: Props<K>) {
|
||||
super(props);
|
||||
|
||||
this.state = {
|
||||
|
@ -77,7 +78,7 @@ export default class PowerSelector extends React.Component<IProps, IState> {
|
|||
this.initStateFromProps();
|
||||
}
|
||||
|
||||
public componentDidUpdate(prevProps: Readonly<IProps>): void {
|
||||
public componentDidUpdate(prevProps: Readonly<Props<K>>): void {
|
||||
if (objectHasDiff(this.props, prevProps)) {
|
||||
this.initStateFromProps();
|
||||
}
|
||||
|
|
|
@ -31,7 +31,7 @@ const defaultOptions: QRCodeToDataURLOptions = {
|
|||
};
|
||||
|
||||
const QRCode: React.FC<IProps> = ({ data, className, ...options }) => {
|
||||
const [dataUri, setUri] = React.useState<string>(null);
|
||||
const [dataUri, setUri] = React.useState<string | null>(null);
|
||||
React.useEffect(() => {
|
||||
let cancelled = false;
|
||||
toDataURL(data, { ...defaultOptions, ...options }).then((uri) => {
|
||||
|
|
|
@ -63,7 +63,7 @@ interface IState {
|
|||
// The loaded events to be rendered as linear-replies
|
||||
events: MatrixEvent[];
|
||||
// The latest loaded event which has not yet been shown
|
||||
loadedEv: MatrixEvent;
|
||||
loadedEv: MatrixEvent | null;
|
||||
// Whether the component is still loading more events
|
||||
loading: boolean;
|
||||
// Whether as error was encountered fetching a replied to event.
|
||||
|
@ -145,7 +145,7 @@ export default class ReplyChain extends React.Component<IProps, IState> {
|
|||
}
|
||||
}
|
||||
|
||||
private async getNextEvent(ev: MatrixEvent): Promise<MatrixEvent> {
|
||||
private async getNextEvent(ev: MatrixEvent): Promise<MatrixEvent | null> {
|
||||
try {
|
||||
const inReplyToEventId = getParentEventId(ev);
|
||||
return await this.getEvent(inReplyToEventId);
|
||||
|
@ -154,7 +154,7 @@ export default class ReplyChain extends React.Component<IProps, IState> {
|
|||
}
|
||||
}
|
||||
|
||||
private async getEvent(eventId: string): Promise<MatrixEvent> {
|
||||
private async getEvent(eventId: string): Promise<MatrixEvent | null> {
|
||||
if (!eventId) return null;
|
||||
const event = this.room.findEventById(eventId);
|
||||
if (event) return event;
|
||||
|
@ -168,7 +168,7 @@ export default class ReplyChain extends React.Component<IProps, IState> {
|
|||
// Return null as it is falsy and thus should be treated as an error (as the event cannot be resolved).
|
||||
return null;
|
||||
}
|
||||
return this.room.findEventById(eventId);
|
||||
return this.room.findEventById(eventId) ?? null;
|
||||
}
|
||||
|
||||
public canCollapse = (): boolean => {
|
||||
|
@ -182,7 +182,7 @@ export default class ReplyChain extends React.Component<IProps, IState> {
|
|||
private onQuoteClick = async (event: ButtonEvent): Promise<void> => {
|
||||
const events = [this.state.loadedEv, ...this.state.events];
|
||||
|
||||
let loadedEv = null;
|
||||
let loadedEv: MatrixEvent | null = null;
|
||||
if (events.length > 0) {
|
||||
loadedEv = await this.getNextEvent(events[0]);
|
||||
}
|
||||
|
@ -200,7 +200,7 @@ export default class ReplyChain extends React.Component<IProps, IState> {
|
|||
}
|
||||
|
||||
public render(): React.ReactNode {
|
||||
let header = null;
|
||||
let header: JSX.Element | undefined;
|
||||
if (this.state.err) {
|
||||
header = (
|
||||
<blockquote className="mx_ReplyChain mx_ReplyChain_error">
|
||||
|
|
|
@ -81,7 +81,7 @@ export default class Slider extends React.Component<IProps> {
|
|||
/>
|
||||
));
|
||||
|
||||
let selection = null;
|
||||
let selection: JSX.Element | undefined;
|
||||
|
||||
if (!this.props.disabled) {
|
||||
const offset = this.offset(this.props.values, this.props.value);
|
||||
|
|
|
@ -21,7 +21,7 @@ import { _t } from "../../../languageHandler";
|
|||
|
||||
interface IProps {
|
||||
// The number of elements to show before truncating. If negative, no truncation is done.
|
||||
truncateAt?: number;
|
||||
truncateAt: number;
|
||||
// The className to apply to the wrapping div
|
||||
className?: string;
|
||||
// A function that returns the children to be rendered into the element.
|
||||
|
@ -34,7 +34,7 @@ interface IProps {
|
|||
getChildCount?: () => number;
|
||||
// A function which will be invoked when an overflow element is required.
|
||||
// This will be inserted after the children.
|
||||
createOverflowElement?: (overflowCount: number, totalCount: number) => React.ReactNode;
|
||||
createOverflowElement: (overflowCount: number, totalCount: number) => React.ReactNode;
|
||||
children?: ReactNode;
|
||||
}
|
||||
|
||||
|
@ -71,8 +71,8 @@ export default class TruncatedList extends React.Component<IProps> {
|
|||
}
|
||||
}
|
||||
|
||||
public render(): React.ReactNode {
|
||||
let overflowNode = null;
|
||||
public render(): ReactNode {
|
||||
let overflowNode: ReactNode | undefined;
|
||||
|
||||
const totalChildren = this.getChildCount();
|
||||
let upperBound = totalChildren;
|
||||
|
|
|
@ -37,6 +37,7 @@ import RoomContext, { TimelineRenderingType } from "../../../contexts/RoomContex
|
|||
import { ReadPinsEventId } from "./types";
|
||||
import Heading from "../typography/Heading";
|
||||
import { RoomPermalinkCreator } from "../../../utils/permalinks/Permalinks";
|
||||
import { filterBoolean } from "../../../utils/arrays";
|
||||
|
||||
interface IProps {
|
||||
room: Room;
|
||||
|
@ -44,7 +45,7 @@ interface IProps {
|
|||
onClose(): void;
|
||||
}
|
||||
|
||||
export const usePinnedEvents = (room: Room): string[] => {
|
||||
export const usePinnedEvents = (room?: Room): string[] => {
|
||||
const [pinnedEvents, setPinnedEvents] = useState<string[]>([]);
|
||||
|
||||
const update = useCallback(
|
||||
|
@ -173,8 +174,7 @@ const PinnedMessagesCard: React.FC<IProps> = ({ room, onClose, permalinkCreator
|
|||
};
|
||||
|
||||
// show them in reverse, with latest pinned at the top
|
||||
content = pinnedEvents
|
||||
.filter(Boolean)
|
||||
content = filterBoolean(pinnedEvents)
|
||||
.reverse()
|
||||
.map((ev) => (
|
||||
<PinnedEventTile
|
||||
|
|
|
@ -325,7 +325,7 @@ const RoomSummaryCard: React.FC<IProps> = ({ room, permalinkCreator, onClose })
|
|||
|
||||
const memberCount = useRoomMemberCount(room);
|
||||
const pinningEnabled = useFeatureEnabled("feature_pinning");
|
||||
const pinCount = usePinnedEvents(pinningEnabled && room)?.length;
|
||||
const pinCount = usePinnedEvents(pinningEnabled ? room : undefined)?.length;
|
||||
|
||||
const isPollHistoryEnabled = useFeatureEnabled("feature_poll_history");
|
||||
|
||||
|
|
|
@ -44,7 +44,7 @@ const crossSigningRoomTitles: { [key in E2EState]?: string } = {
|
|||
|
||||
interface IProps {
|
||||
isUser?: boolean;
|
||||
status?: E2EState | E2EStatus;
|
||||
status: E2EState | E2EStatus;
|
||||
className?: string;
|
||||
size?: number;
|
||||
onClick?: () => void;
|
||||
|
@ -76,7 +76,7 @@ const E2EIcon: React.FC<IProps> = ({
|
|||
className,
|
||||
);
|
||||
|
||||
let e2eTitle;
|
||||
let e2eTitle: string | undefined;
|
||||
if (isUser) {
|
||||
e2eTitle = crossSigningUserTitles[status];
|
||||
} else {
|
||||
|
|
|
@ -43,7 +43,7 @@ const PRESENCE_CLASS: Record<PresenceState, string> = {
|
|||
unavailable: "mx_EntityTile_unavailable",
|
||||
};
|
||||
|
||||
function presenceClassForMember(presenceState: PresenceState, lastActiveAgo: number, showPresence: boolean): string {
|
||||
function presenceClassForMember(presenceState?: PresenceState, lastActiveAgo?: number, showPresence?: boolean): string {
|
||||
if (showPresence === false) {
|
||||
return "mx_EntityTile_online_beenactive";
|
||||
}
|
||||
|
@ -74,7 +74,7 @@ interface IProps {
|
|||
presenceLastTs?: number;
|
||||
presenceCurrentlyActive?: boolean;
|
||||
showInviteButton?: boolean;
|
||||
onClick?(): void;
|
||||
onClick(): void;
|
||||
suppressOnHover?: boolean;
|
||||
showPresence?: boolean;
|
||||
subtextLabel?: string;
|
||||
|
@ -108,7 +108,7 @@ export default class EntityTile extends React.PureComponent<IProps, IState> {
|
|||
public render(): React.ReactNode {
|
||||
const mainClassNames: Record<string, boolean> = {
|
||||
mx_EntityTile: true,
|
||||
mx_EntityTile_noHover: this.props.suppressOnHover,
|
||||
mx_EntityTile_noHover: !!this.props.suppressOnHover,
|
||||
};
|
||||
if (this.props.className) mainClassNames[this.props.className] = true;
|
||||
|
||||
|
@ -127,7 +127,7 @@ export default class EntityTile extends React.PureComponent<IProps, IState> {
|
|||
? Date.now() - (this.props.presenceLastTs - this.props.presenceLastActiveAgo)
|
||||
: -1;
|
||||
|
||||
let presenceLabel = null;
|
||||
let presenceLabel: JSX.Element | undefined;
|
||||
if (this.props.showPresence) {
|
||||
presenceLabel = (
|
||||
<PresenceLabel
|
||||
|
|
|
@ -39,7 +39,7 @@ export default class PresenceLabel extends React.Component<IProps> {
|
|||
|
||||
// Return duration as a string using appropriate time units
|
||||
// XXX: This would be better handled using a culture-aware library, but we don't use one yet.
|
||||
private getDuration(time: number): string {
|
||||
private getDuration(time: number): string | undefined {
|
||||
if (!time) return;
|
||||
const t = Math.round(time / 1000);
|
||||
const s = t % 60;
|
||||
|
@ -61,11 +61,11 @@ export default class PresenceLabel extends React.Component<IProps> {
|
|||
return _t("%(duration)sd", { duration: d });
|
||||
}
|
||||
|
||||
private getPrettyPresence(presence: string, activeAgo: number, currentlyActive: boolean): string {
|
||||
private getPrettyPresence(presence?: string, activeAgo?: number, currentlyActive?: boolean): string {
|
||||
// for busy presence, we ignore the 'currentlyActive' flag: they're busy whether
|
||||
// they're active or not. It can be set while the user is active in which case
|
||||
// the 'active ago' ends up being 0.
|
||||
if (BUSY_PRESENCE_NAME.matches(presence)) return _t("Busy");
|
||||
if (presence && BUSY_PRESENCE_NAME.matches(presence)) return _t("Busy");
|
||||
|
||||
if (!currentlyActive && activeAgo !== undefined && activeAgo > 0) {
|
||||
const duration = this.getDuration(activeAgo);
|
||||
|
|
|
@ -129,9 +129,9 @@ interface IProps {
|
|||
|
||||
interface IState {
|
||||
verifying: boolean;
|
||||
verifyError: string;
|
||||
verifyError: string | null;
|
||||
verifyMsisdn: string;
|
||||
addTask: AddThreepid;
|
||||
addTask: AddThreepid | null;
|
||||
continueDisabled: boolean;
|
||||
phoneCountry: string;
|
||||
newPhoneNumber: string;
|
||||
|
@ -205,7 +205,7 @@ export default class PhoneNumbers extends React.Component<IProps, IState> {
|
|||
const token = this.state.newPhoneNumberCode;
|
||||
const address = this.state.verifyMsisdn;
|
||||
this.state.addTask
|
||||
.haveMsisdnToken(token)
|
||||
?.haveMsisdnToken(token)
|
||||
.then(([finished]) => {
|
||||
let newPhoneNumber = this.state.newPhoneNumber;
|
||||
if (finished) {
|
||||
|
|
|
@ -21,6 +21,7 @@ import { RoomState, RoomStateEvent } from "matrix-js-sdk/src/models/room-state";
|
|||
import { logger } from "matrix-js-sdk/src/logger";
|
||||
import { throttle, get } from "lodash";
|
||||
import { compare } from "matrix-js-sdk/src/utils";
|
||||
import { IContent } from "matrix-js-sdk/src/models/event";
|
||||
|
||||
import { _t, _td } from "../../../../../languageHandler";
|
||||
import { MatrixClientPeg } from "../../../../../MatrixClientPeg";
|
||||
|
@ -171,8 +172,8 @@ export default class RolesRoomSettingsTab extends React.Component<IProps> {
|
|||
private onPowerLevelsChanged = (value: number, powerLevelKey: string): void => {
|
||||
const client = MatrixClientPeg.get();
|
||||
const room = client.getRoom(this.props.roomId);
|
||||
const plEvent = room.currentState.getStateEvents(EventType.RoomPowerLevels, "");
|
||||
let plContent = plEvent ? plEvent.getContent() || {} : {};
|
||||
const plEvent = room?.currentState.getStateEvents(EventType.RoomPowerLevels, "");
|
||||
let plContent = plEvent?.getContent() ?? {};
|
||||
|
||||
// Clone the power levels just in case
|
||||
plContent = Object.assign({}, plContent);
|
||||
|
@ -185,7 +186,7 @@ export default class RolesRoomSettingsTab extends React.Component<IProps> {
|
|||
plContent["events"][powerLevelKey.slice(eventsLevelPrefix.length)] = value;
|
||||
} else {
|
||||
const keyPath = powerLevelKey.split(".");
|
||||
let parentObj;
|
||||
let parentObj: IContent | undefined;
|
||||
let currentObj = plContent;
|
||||
for (const key of keyPath) {
|
||||
if (!currentObj[key]) {
|
||||
|
@ -213,8 +214,8 @@ export default class RolesRoomSettingsTab extends React.Component<IProps> {
|
|||
private onUserPowerLevelChanged = (value: number, powerLevelKey: string): void => {
|
||||
const client = MatrixClientPeg.get();
|
||||
const room = client.getRoom(this.props.roomId);
|
||||
const plEvent = room.currentState.getStateEvents(EventType.RoomPowerLevels, "");
|
||||
let plContent = plEvent ? plEvent.getContent() || {} : {};
|
||||
const plEvent = room?.currentState.getStateEvents(EventType.RoomPowerLevels, "");
|
||||
let plContent = plEvent?.getContent() ?? {};
|
||||
|
||||
// Clone the power levels just in case
|
||||
plContent = Object.assign({}, plContent);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue