Conform more of the codebase to strictNullChecks (#10505
* Conform more of the codebase to `strictNullChecks` * Iterate * Conform more of the codebase to `strictNullChecks` * Iterate * Iterate * Iterate * Iteratepull/28788/head^2
parent
7503bf6b96
commit
e5a314617a
|
@ -332,7 +332,7 @@ class MatrixClientPegClass implements IMatrixClientPeg {
|
||||||
|
|
||||||
homeserverUrl: this.matrixClient.baseUrl,
|
homeserverUrl: this.matrixClient.baseUrl,
|
||||||
identityServerUrl: this.matrixClient.idBaseUrl,
|
identityServerUrl: this.matrixClient.idBaseUrl,
|
||||||
userId: this.matrixClient.credentials.userId,
|
userId: this.matrixClient.getSafeUserId(),
|
||||||
deviceId: this.matrixClient.getDeviceId() ?? undefined,
|
deviceId: this.matrixClient.getDeviceId() ?? undefined,
|
||||||
accessToken: this.matrixClient.getAccessToken(),
|
accessToken: this.matrixClient.getAccessToken(),
|
||||||
guest: this.matrixClient.isGuest(),
|
guest: this.matrixClient.isGuest(),
|
||||||
|
@ -340,7 +340,7 @@ class MatrixClientPegClass implements IMatrixClientPeg {
|
||||||
}
|
}
|
||||||
|
|
||||||
public getHomeserverName(): string {
|
public getHomeserverName(): string {
|
||||||
const matches = /^@[^:]+:(.+)$/.exec(this.matrixClient.credentials.userId);
|
const matches = /^@[^:]+:(.+)$/.exec(this.matrixClient.getSafeUserId());
|
||||||
if (matches === null || matches.length < 1) {
|
if (matches === null || matches.length < 1) {
|
||||||
throw new Error("Failed to derive homeserver name from user ID!");
|
throw new Error("Failed to derive homeserver name from user ID!");
|
||||||
}
|
}
|
||||||
|
|
|
@ -102,7 +102,7 @@ const Tile: React.FC<ITileProps> = ({
|
||||||
}) => {
|
}) => {
|
||||||
const cli = useContext(MatrixClientContext);
|
const cli = useContext(MatrixClientContext);
|
||||||
const [joinedRoom, setJoinedRoom] = useState<Room | undefined>(() => {
|
const [joinedRoom, setJoinedRoom] = useState<Room | undefined>(() => {
|
||||||
const cliRoom = cli.getRoom(room.room_id);
|
const cliRoom = cli?.getRoom(room.room_id);
|
||||||
return cliRoom?.getMyMembership() === "join" ? cliRoom : undefined;
|
return cliRoom?.getMyMembership() === "join" ? cliRoom : undefined;
|
||||||
});
|
});
|
||||||
const joinedRoomName = useTypedEventEmitterState(joinedRoom, RoomEvent.Name, (room) => room?.name);
|
const joinedRoomName = useTypedEventEmitterState(joinedRoom, RoomEvent.Name, (room) => room?.name);
|
||||||
|
|
|
@ -30,7 +30,6 @@ import { ClientEvent } from "matrix-js-sdk/src/client";
|
||||||
import { Thread, ThreadEvent } from "matrix-js-sdk/src/models/thread";
|
import { Thread, ThreadEvent } from "matrix-js-sdk/src/models/thread";
|
||||||
import { ReceiptType } from "matrix-js-sdk/src/@types/read_receipts";
|
import { ReceiptType } from "matrix-js-sdk/src/@types/read_receipts";
|
||||||
import { MatrixError } from "matrix-js-sdk/src/http-api";
|
import { MatrixError } from "matrix-js-sdk/src/http-api";
|
||||||
import { ReadReceipt } from "matrix-js-sdk/src/models/read-receipt";
|
|
||||||
import { Relations } from "matrix-js-sdk/src/models/relations";
|
import { Relations } from "matrix-js-sdk/src/models/relations";
|
||||||
|
|
||||||
import SettingsStore from "../../settings/SettingsStore";
|
import SettingsStore from "../../settings/SettingsStore";
|
||||||
|
@ -515,23 +514,22 @@ class TimelinePanel extends React.Component<IProps, IState> {
|
||||||
|
|
||||||
if (count > 0) {
|
if (count > 0) {
|
||||||
debuglog("Unpaginating", count, "in direction", dir);
|
debuglog("Unpaginating", count, "in direction", dir);
|
||||||
this.timelineWindow.unpaginate(count, backwards);
|
this.timelineWindow?.unpaginate(count, backwards);
|
||||||
|
|
||||||
const { events, liveEvents, firstVisibleEventIndex } = this.getEvents();
|
const { events, liveEvents, firstVisibleEventIndex } = this.getEvents();
|
||||||
this.buildLegacyCallEventGroupers(events);
|
this.buildLegacyCallEventGroupers(events);
|
||||||
const newState: Partial<IState> = {
|
this.setState({
|
||||||
events,
|
events,
|
||||||
liveEvents,
|
liveEvents,
|
||||||
firstVisibleEventIndex,
|
firstVisibleEventIndex,
|
||||||
};
|
});
|
||||||
|
|
||||||
// We can now paginate in the unpaginated direction
|
// We can now paginate in the unpaginated direction
|
||||||
if (backwards) {
|
if (backwards) {
|
||||||
newState.canBackPaginate = true;
|
this.setState({ canBackPaginate: true });
|
||||||
} else {
|
} else {
|
||||||
newState.canForwardPaginate = true;
|
this.setState({ canForwardPaginate: true });
|
||||||
}
|
}
|
||||||
this.setState<null>(newState);
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -636,6 +634,7 @@ class TimelinePanel extends React.Component<IProps, IState> {
|
||||||
private doManageReadMarkers = debounce(
|
private doManageReadMarkers = debounce(
|
||||||
() => {
|
() => {
|
||||||
const rmPosition = this.getReadMarkerPosition();
|
const rmPosition = this.getReadMarkerPosition();
|
||||||
|
if (rmPosition === null) return;
|
||||||
// we hide the read marker when it first comes onto the screen, but if
|
// we hide the read marker when it first comes onto the screen, but if
|
||||||
// it goes back off the top of the screen (presumably because the user
|
// it goes back off the top of the screen (presumably because the user
|
||||||
// clicks on the 'jump to bottom' button), we need to re-enable it.
|
// clicks on the 'jump to bottom' button), we need to re-enable it.
|
||||||
|
@ -1125,7 +1124,7 @@ class TimelinePanel extends React.Component<IProps, IState> {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const lastDisplayedEvent = this.state.events[lastDisplayedIndex];
|
const lastDisplayedEvent = this.state.events[lastDisplayedIndex];
|
||||||
this.setReadMarker(lastDisplayedEvent.getId(), lastDisplayedEvent.getTs());
|
this.setReadMarker(lastDisplayedEvent.getId()!, lastDisplayedEvent.getTs());
|
||||||
|
|
||||||
// the read-marker should become invisible, so that if the user scrolls
|
// the read-marker should become invisible, so that if the user scrolls
|
||||||
// down, they don't see it.
|
// down, they don't see it.
|
||||||
|
@ -1141,7 +1140,7 @@ class TimelinePanel extends React.Component<IProps, IState> {
|
||||||
|
|
||||||
// advance the read marker past any events we sent ourselves.
|
// advance the read marker past any events we sent ourselves.
|
||||||
private advanceReadMarkerPastMyEvents(): void {
|
private advanceReadMarkerPastMyEvents(): void {
|
||||||
if (!this.props.manageReadMarkers) return;
|
if (!this.props.manageReadMarkers || !this.timelineWindow) return;
|
||||||
|
|
||||||
// we call `timelineWindow.getEvents()` rather than using
|
// we call `timelineWindow.getEvents()` rather than using
|
||||||
// `this.state.liveEvents`, because React batches the update to the
|
// `this.state.liveEvents`, because React batches the update to the
|
||||||
|
@ -1171,7 +1170,7 @@ class TimelinePanel extends React.Component<IProps, IState> {
|
||||||
i--;
|
i--;
|
||||||
|
|
||||||
const ev = events[i];
|
const ev = events[i];
|
||||||
this.setReadMarker(ev.getId(), ev.getTs());
|
this.setReadMarker(ev.getId()!, ev.getTs());
|
||||||
}
|
}
|
||||||
|
|
||||||
/* jump down to the bottom of this room, where new events are arriving
|
/* jump down to the bottom of this room, where new events are arriving
|
||||||
|
@ -1280,6 +1279,7 @@ class TimelinePanel extends React.Component<IProps, IState> {
|
||||||
public getReadMarkerPosition = (): number | null => {
|
public getReadMarkerPosition = (): number | null => {
|
||||||
if (!this.props.manageReadMarkers) return null;
|
if (!this.props.manageReadMarkers) return null;
|
||||||
if (!this.messagePanel.current) return null;
|
if (!this.messagePanel.current) return null;
|
||||||
|
if (!this.props.timelineSet.room) return null;
|
||||||
|
|
||||||
const ret = this.messagePanel.current.getReadMarkerPosition();
|
const ret = this.messagePanel.current.getReadMarkerPosition();
|
||||||
if (ret !== null) {
|
if (ret !== null) {
|
||||||
|
@ -1629,7 +1629,7 @@ class TimelinePanel extends React.Component<IProps, IState> {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
const userId = cli.credentials.userId;
|
const userId = cli.getSafeUserId();
|
||||||
|
|
||||||
// get the user's membership at the last event by getting the timeline
|
// get the user's membership at the last event by getting the timeline
|
||||||
// that the event belongs to, and traversing the timeline looking for
|
// that the event belongs to, and traversing the timeline looking for
|
||||||
|
@ -1648,7 +1648,7 @@ class TimelinePanel extends React.Component<IProps, IState> {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
userMembership = timeline.getState(EventTimeline.FORWARDS).getMember(userId)?.membership ?? "leave";
|
userMembership = timeline.getState(EventTimeline.FORWARDS)?.getMember(userId)?.membership ?? "leave";
|
||||||
const timelineEvents = timeline.getEvents();
|
const timelineEvents = timeline.getEvents();
|
||||||
for (let j = timelineEvents.length - 1; j >= 0; j--) {
|
for (let j = timelineEvents.length - 1; j >= 0; j--) {
|
||||||
const event = timelineEvents[j];
|
const event = timelineEvents[j];
|
||||||
|
@ -1769,7 +1769,7 @@ class TimelinePanel extends React.Component<IProps, IState> {
|
||||||
for (let i = this.state.liveEvents.length - 1; i >= 0; --i) {
|
for (let i = this.state.liveEvents.length - 1; i >= 0; --i) {
|
||||||
const ev = this.state.liveEvents[i];
|
const ev = this.state.liveEvents[i];
|
||||||
|
|
||||||
const node = messagePanel.getNodeForEventId(ev.getId());
|
const node = messagePanel.getNodeForEventId(ev.getId()!);
|
||||||
const isInView = isNodeInView(node);
|
const isInView = isNodeInView(node);
|
||||||
|
|
||||||
// when we've reached the first visible event, and the previous
|
// when we've reached the first visible event, and the previous
|
||||||
|
@ -1829,8 +1829,8 @@ class TimelinePanel extends React.Component<IProps, IState> {
|
||||||
}
|
}
|
||||||
|
|
||||||
const myUserId = client.getSafeUserId();
|
const myUserId = client.getSafeUserId();
|
||||||
const receiptStore: ReadReceipt<any, any> = this.props.timelineSet.thread ?? this.props.timelineSet.room;
|
const receiptStore = this.props.timelineSet.thread ?? this.props.timelineSet.room;
|
||||||
return receiptStore?.getEventReadUpTo(myUserId, ignoreSynthesized);
|
return receiptStore?.getEventReadUpTo(myUserId, ignoreSynthesized) ?? null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private setReadMarker(eventId: string | null, eventTs: number, inhibitSetState = false): void {
|
private setReadMarker(eventId: string | null, eventTs: number, inhibitSetState = false): void {
|
||||||
|
@ -1924,7 +1924,7 @@ class TimelinePanel extends React.Component<IProps, IState> {
|
||||||
// If the state is PREPARED or CATCHUP, we're still waiting for the js-sdk to sync with
|
// If the state is PREPARED or CATCHUP, we're still waiting for the js-sdk to sync with
|
||||||
// the HS and fetch the latest events, so we are effectively forward paginating.
|
// the HS and fetch the latest events, so we are effectively forward paginating.
|
||||||
const forwardPaginating =
|
const forwardPaginating =
|
||||||
this.state.forwardPaginating || ["PREPARED", "CATCHUP"].includes(this.state.clientSyncState);
|
this.state.forwardPaginating || ["PREPARED", "CATCHUP"].includes(this.state.clientSyncState!);
|
||||||
const events = this.state.firstVisibleEventIndex
|
const events = this.state.firstVisibleEventIndex
|
||||||
? this.state.events.slice(this.state.firstVisibleEventIndex)
|
? this.state.events.slice(this.state.firstVisibleEventIndex)
|
||||||
: this.state.events;
|
: this.state.events;
|
||||||
|
@ -1985,7 +1985,7 @@ function serializeEventIdsFromTimelineSets(timelineSets: EventTimelineSet[]): {
|
||||||
// Add a special label when it is the live timeline so we can tell
|
// Add a special label when it is the live timeline so we can tell
|
||||||
// it apart from the others
|
// it apart from the others
|
||||||
const isLiveTimeline = timeline === liveTimeline;
|
const isLiveTimeline = timeline === liveTimeline;
|
||||||
timelineMap[isLiveTimeline ? "liveTimeline" : `${index}`] = timeline.getEvents().map((ev) => ev.getId());
|
timelineMap[isLiveTimeline ? "liveTimeline" : `${index}`] = timeline.getEvents().map((ev) => ev.getId()!);
|
||||||
});
|
});
|
||||||
|
|
||||||
return timelineMap;
|
return timelineMap;
|
||||||
|
|
|
@ -89,6 +89,7 @@ export const RoomGeneralContextMenu: React.FC<RoomGeneralContextMenuProps> = ({
|
||||||
};
|
};
|
||||||
|
|
||||||
const onTagRoom = (ev: ButtonEvent, tagId: TagID): void => {
|
const onTagRoom = (ev: ButtonEvent, tagId: TagID): void => {
|
||||||
|
if (!cli) return;
|
||||||
if (tagId === DefaultTagID.Favourite || tagId === DefaultTagID.LowPriority) {
|
if (tagId === DefaultTagID.Favourite || tagId === DefaultTagID.LowPriority) {
|
||||||
const inverseTag = tagId === DefaultTagID.Favourite ? DefaultTagID.LowPriority : DefaultTagID.Favourite;
|
const inverseTag = tagId === DefaultTagID.Favourite ? DefaultTagID.LowPriority : DefaultTagID.Favourite;
|
||||||
const isApplied = RoomListStore.instance.getTagsForRoom(room).includes(tagId);
|
const isApplied = RoomListStore.instance.getTagsForRoom(room).includes(tagId);
|
||||||
|
|
|
@ -53,7 +53,7 @@ export default class ConfirmAndWaitRedactDialog extends React.PureComponent<IPro
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
public onParentFinished = async (proceed: boolean): Promise<void> => {
|
public onParentFinished = async (proceed?: boolean): Promise<void> => {
|
||||||
if (proceed) {
|
if (proceed) {
|
||||||
this.setState({ isRedacting: true });
|
this.setState({ isRedacting: true });
|
||||||
try {
|
try {
|
||||||
|
|
|
@ -26,7 +26,8 @@ import ErrorDialog from "./ErrorDialog";
|
||||||
import TextInputDialog from "./TextInputDialog";
|
import TextInputDialog from "./TextInputDialog";
|
||||||
|
|
||||||
interface IProps {
|
interface IProps {
|
||||||
onFinished: (success: boolean) => void;
|
onFinished(success?: false, reason?: void): void;
|
||||||
|
onFinished(success: true, reason?: string): void;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -67,7 +68,7 @@ export function createRedactEventDialog({
|
||||||
Modal.createDialog(
|
Modal.createDialog(
|
||||||
ConfirmRedactDialog,
|
ConfirmRedactDialog,
|
||||||
{
|
{
|
||||||
onFinished: async (proceed: boolean, reason?: string): Promise<void> => {
|
onFinished: async (proceed, reason): Promise<void> => {
|
||||||
if (!proceed) return;
|
if (!proceed) return;
|
||||||
|
|
||||||
const cli = MatrixClientPeg.get();
|
const cli = MatrixClientPeg.get();
|
||||||
|
|
|
@ -72,7 +72,7 @@ const KeySignatureUploadFailedDialog: React.FC<IProps> = ({ failures, source, co
|
||||||
}, [continuation, onFinished]);
|
}, [continuation, onFinished]);
|
||||||
|
|
||||||
let body;
|
let body;
|
||||||
if (!success && !cancelled && continuation && retry > 0) {
|
if (!success && !cancelled && retry > 0) {
|
||||||
const reason = causes.get(source) || defaultCause;
|
const reason = causes.get(source) || defaultCause;
|
||||||
const brand = SdkConfig.get().brand;
|
const brand = SdkConfig.get().brand;
|
||||||
|
|
||||||
|
|
|
@ -20,6 +20,7 @@ import { EventType, RelationType } from "matrix-js-sdk/src/@types/event";
|
||||||
import { defer } from "matrix-js-sdk/src/utils";
|
import { defer } from "matrix-js-sdk/src/utils";
|
||||||
import { logger } from "matrix-js-sdk/src/logger";
|
import { logger } from "matrix-js-sdk/src/logger";
|
||||||
import { MatrixClient } from "matrix-js-sdk/src/client";
|
import { MatrixClient } from "matrix-js-sdk/src/client";
|
||||||
|
import { MatrixError } from "matrix-js-sdk/src/http-api";
|
||||||
|
|
||||||
import { MatrixClientPeg } from "../../../MatrixClientPeg";
|
import { MatrixClientPeg } from "../../../MatrixClientPeg";
|
||||||
import { _t } from "../../../languageHandler";
|
import { _t } from "../../../languageHandler";
|
||||||
|
@ -37,12 +38,10 @@ interface IProps {
|
||||||
}
|
}
|
||||||
|
|
||||||
interface IState {
|
interface IState {
|
||||||
originalEvent: MatrixEvent;
|
originalEvent: MatrixEvent | null;
|
||||||
error: {
|
error: MatrixError | null;
|
||||||
errcode: string;
|
|
||||||
};
|
|
||||||
events: MatrixEvent[];
|
events: MatrixEvent[];
|
||||||
nextBatch: string;
|
nextBatch: string | null;
|
||||||
isLoading: boolean;
|
isLoading: boolean;
|
||||||
isTwelveHour: boolean;
|
isTwelveHour: boolean;
|
||||||
}
|
}
|
||||||
|
@ -65,9 +64,9 @@ export default class MessageEditHistoryDialog extends React.PureComponent<IProps
|
||||||
// bail out on backwards as we only paginate in one direction
|
// bail out on backwards as we only paginate in one direction
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
const opts = { from: this.state.nextBatch };
|
const opts = { from: this.state.nextBatch ?? undefined };
|
||||||
const roomId = this.props.mxEvent.getRoomId();
|
const roomId = this.props.mxEvent.getRoomId()!;
|
||||||
const eventId = this.props.mxEvent.getId();
|
const eventId = this.props.mxEvent.getId()!;
|
||||||
const client = MatrixClientPeg.get();
|
const client = MatrixClientPeg.get();
|
||||||
|
|
||||||
const { resolve, reject, promise } = defer<boolean>();
|
const { resolve, reject, promise } = defer<boolean>();
|
||||||
|
@ -80,7 +79,7 @@ export default class MessageEditHistoryDialog extends React.PureComponent<IProps
|
||||||
if (error.errcode) {
|
if (error.errcode) {
|
||||||
logger.error("fetching /relations failed with error", error);
|
logger.error("fetching /relations failed with error", error);
|
||||||
}
|
}
|
||||||
this.setState({ error }, () => reject(error));
|
this.setState({ error: error as MatrixError }, () => reject(error));
|
||||||
return promise;
|
return promise;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -88,9 +87,9 @@ export default class MessageEditHistoryDialog extends React.PureComponent<IProps
|
||||||
this.locallyRedactEventsIfNeeded(newEvents);
|
this.locallyRedactEventsIfNeeded(newEvents);
|
||||||
this.setState(
|
this.setState(
|
||||||
{
|
{
|
||||||
originalEvent: this.state.originalEvent || result.originalEvent,
|
originalEvent: this.state.originalEvent ?? result.originalEvent ?? null,
|
||||||
events: this.state.events.concat(newEvents),
|
events: this.state.events.concat(newEvents),
|
||||||
nextBatch: result.nextBatch,
|
nextBatch: result.nextBatch ?? null,
|
||||||
isLoading: false,
|
isLoading: false,
|
||||||
},
|
},
|
||||||
() => {
|
() => {
|
||||||
|
@ -105,6 +104,7 @@ export default class MessageEditHistoryDialog extends React.PureComponent<IProps
|
||||||
const roomId = this.props.mxEvent.getRoomId();
|
const roomId = this.props.mxEvent.getRoomId();
|
||||||
const client = MatrixClientPeg.get();
|
const client = MatrixClientPeg.get();
|
||||||
const room = client.getRoom(roomId);
|
const room = client.getRoom(roomId);
|
||||||
|
if (!room) return;
|
||||||
const pendingEvents = room.getPendingEvents();
|
const pendingEvents = room.getPendingEvents();
|
||||||
for (const e of newEvents) {
|
for (const e of newEvents) {
|
||||||
const pendingRedaction = pendingEvents.find((pe) => {
|
const pendingRedaction = pendingEvents.find((pe) => {
|
||||||
|
@ -133,7 +133,7 @@ export default class MessageEditHistoryDialog extends React.PureComponent<IProps
|
||||||
if (!lastEvent || wantsDateSeparator(lastEvent.getDate() || undefined, e.getDate() || undefined)) {
|
if (!lastEvent || wantsDateSeparator(lastEvent.getDate() || undefined, e.getDate() || undefined)) {
|
||||||
nodes.push(
|
nodes.push(
|
||||||
<li key={e.getTs() + "~"}>
|
<li key={e.getTs() + "~"}>
|
||||||
<DateSeparator roomId={e.getRoomId()} ts={e.getTs()} />
|
<DateSeparator roomId={e.getRoomId()!} ts={e.getTs()} />
|
||||||
</li>,
|
</li>,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -141,7 +141,7 @@ export default class MessageEditHistoryDialog extends React.PureComponent<IProps
|
||||||
nodes.push(
|
nodes.push(
|
||||||
<EditHistoryMessage
|
<EditHistoryMessage
|
||||||
key={e.getId()}
|
key={e.getId()}
|
||||||
previousEdit={!isBaseEvent ? allEvents[i + 1] : null}
|
previousEdit={!isBaseEvent ? allEvents[i + 1] : undefined}
|
||||||
isBaseEvent={isBaseEvent}
|
isBaseEvent={isBaseEvent}
|
||||||
mxEvent={e}
|
mxEvent={e}
|
||||||
isTwelveHour={this.state.isTwelveHour}
|
isTwelveHour={this.state.isTwelveHour}
|
||||||
|
|
|
@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
|
||||||
limitations under the License.
|
limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import * as React from "react";
|
import React, { ReactNode } from "react";
|
||||||
|
|
||||||
import BaseDialog from "./BaseDialog";
|
import BaseDialog from "./BaseDialog";
|
||||||
import { _t } from "../../../languageHandler";
|
import { _t } from "../../../languageHandler";
|
||||||
|
@ -46,7 +46,7 @@ export default class ServerOfflineDialog extends React.PureComponent<IProps> {
|
||||||
this.forceUpdate(); // no state to worry about
|
this.forceUpdate(); // no state to worry about
|
||||||
};
|
};
|
||||||
|
|
||||||
private renderTimeline(): React.ReactElement[] {
|
private renderTimeline(): ReactNode[] {
|
||||||
return EchoStore.instance.contexts.map((c, i) => {
|
return EchoStore.instance.contexts.map((c, i) => {
|
||||||
if (!c.firstFailedTime) return null; // not useful
|
if (!c.firstFailedTime) return null; // not useful
|
||||||
if (!(c instanceof RoomEchoContext))
|
if (!(c instanceof RoomEchoContext))
|
||||||
|
|
|
@ -124,7 +124,7 @@ export const SlidingSyncOptionsDialog: React.FC<{ onFinished(enabled: boolean):
|
||||||
value={currentProxy}
|
value={currentProxy}
|
||||||
button={_t("Enable")}
|
button={_t("Enable")}
|
||||||
validator={validProxy}
|
validator={validProxy}
|
||||||
onFinished={(enable: boolean, proxyUrl: string) => {
|
onFinished={(enable, proxyUrl) => {
|
||||||
if (enable) {
|
if (enable) {
|
||||||
SettingsStore.setValue("feature_sliding_sync_proxy_url", null, SettingLevel.DEVICE, proxyUrl);
|
SettingsStore.setValue("feature_sliding_sync_proxy_url", null, SettingLevel.DEVICE, proxyUrl);
|
||||||
onFinished(true);
|
onFinished(true);
|
||||||
|
|
|
@ -33,7 +33,8 @@ interface IProps {
|
||||||
hasCancel: boolean;
|
hasCancel: boolean;
|
||||||
validator?: (fieldState: IFieldState) => Promise<IValidationResult>; // result of withValidation
|
validator?: (fieldState: IFieldState) => Promise<IValidationResult>; // result of withValidation
|
||||||
fixedWidth?: boolean;
|
fixedWidth?: boolean;
|
||||||
onFinished(ok?: boolean, text?: string): void;
|
onFinished(ok?: false, text?: void): void;
|
||||||
|
onFinished(ok: true, text: string): void;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface IState {
|
interface IState {
|
||||||
|
|
|
@ -35,7 +35,6 @@ import React, {
|
||||||
import sanitizeHtml from "sanitize-html";
|
import sanitizeHtml from "sanitize-html";
|
||||||
|
|
||||||
import { KeyBindingAction } from "../../../../accessibility/KeyboardShortcuts";
|
import { KeyBindingAction } from "../../../../accessibility/KeyboardShortcuts";
|
||||||
import { Ref } from "../../../../accessibility/roving/types";
|
|
||||||
import {
|
import {
|
||||||
findSiblingElement,
|
findSiblingElement,
|
||||||
RovingTabIndexContext,
|
RovingTabIndexContext,
|
||||||
|
@ -104,8 +103,8 @@ interface IProps {
|
||||||
onFinished(): void;
|
onFinished(): void;
|
||||||
}
|
}
|
||||||
|
|
||||||
function refIsForRecentlyViewed(ref: RefObject<HTMLElement>): boolean {
|
function refIsForRecentlyViewed(ref?: RefObject<HTMLElement>): boolean {
|
||||||
return ref.current?.id?.startsWith("mx_SpotlightDialog_button_recentlyViewed_") === true;
|
return ref?.current?.id?.startsWith("mx_SpotlightDialog_button_recentlyViewed_") === true;
|
||||||
}
|
}
|
||||||
|
|
||||||
function getRoomTypes(showRooms: boolean, showSpaces: boolean): Set<RoomType | null> {
|
function getRoomTypes(showRooms: boolean, showSpaces: boolean): Set<RoomType | null> {
|
||||||
|
@ -366,7 +365,7 @@ const SpotlightDialog: React.FC<IProps> = ({ initialText = "", initialFilter = n
|
||||||
return [
|
return [
|
||||||
...SpaceStore.instance.enabledMetaSpaces.map((spaceKey) => ({
|
...SpaceStore.instance.enabledMetaSpaces.map((spaceKey) => ({
|
||||||
section: Section.Spaces,
|
section: Section.Spaces,
|
||||||
filter: [],
|
filter: [] as Filter[],
|
||||||
avatar: (
|
avatar: (
|
||||||
<div
|
<div
|
||||||
className={classNames(
|
className={classNames(
|
||||||
|
@ -456,6 +455,7 @@ const SpotlightDialog: React.FC<IProps> = ({ initialText = "", initialFilter = n
|
||||||
|
|
||||||
return memberComparator(a.member, b.member);
|
return memberComparator(a.member, b.member);
|
||||||
}
|
}
|
||||||
|
return 0;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -474,17 +474,16 @@ const SpotlightDialog: React.FC<IProps> = ({ initialText = "", initialFilter = n
|
||||||
};
|
};
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setImmediate(() => {
|
setImmediate(() => {
|
||||||
let ref: Ref | undefined;
|
const ref = rovingContext.state.refs[0];
|
||||||
if (rovingContext.state.refs) {
|
if (ref) {
|
||||||
ref = rovingContext.state.refs[0];
|
|
||||||
}
|
|
||||||
rovingContext.dispatch({
|
rovingContext.dispatch({
|
||||||
type: Type.SetFocus,
|
type: Type.SetFocus,
|
||||||
payload: { ref },
|
payload: { ref },
|
||||||
});
|
});
|
||||||
ref?.current?.scrollIntoView?.({
|
ref.current?.scrollIntoView?.({
|
||||||
block: "nearest",
|
block: "nearest",
|
||||||
});
|
});
|
||||||
|
}
|
||||||
});
|
});
|
||||||
// we intentionally ignore changes to the rovingContext for the purpose of this hook
|
// we intentionally ignore changes to the rovingContext for the purpose of this hook
|
||||||
// we only want to reset the focus whenever the results or filters change
|
// we only want to reset the focus whenever the results or filters change
|
||||||
|
@ -635,7 +634,7 @@ const SpotlightDialog: React.FC<IProps> = ({ initialText = "", initialFilter = n
|
||||||
roomId: publicRoom.room_id,
|
roomId: publicRoom.room_id,
|
||||||
autoJoin: !result.publicRoom.world_readable && !cli.isGuest(),
|
autoJoin: !result.publicRoom.world_readable && !cli.isGuest(),
|
||||||
shouldPeek: result.publicRoom.world_readable || cli.isGuest(),
|
shouldPeek: result.publicRoom.world_readable || cli.isGuest(),
|
||||||
viaServers: [config.roomServer],
|
viaServers: config ? [config.roomServer] : undefined,
|
||||||
},
|
},
|
||||||
true,
|
true,
|
||||||
ev.type !== "click",
|
ev.type !== "click",
|
||||||
|
|
|
@ -148,7 +148,7 @@ export const NetworkDropdown: React.FC<IProps> = ({ protocols, config, setConfig
|
||||||
const { allServers, homeServer, userDefinedServers, setUserDefinedServers } = useServers();
|
const { allServers, homeServer, userDefinedServers, setUserDefinedServers } = useServers();
|
||||||
|
|
||||||
const options: GenericDropdownMenuItem<IPublicRoomDirectoryConfig | null>[] = allServers.map((roomServer) => ({
|
const options: GenericDropdownMenuItem<IPublicRoomDirectoryConfig | null>[] = allServers.map((roomServer) => ({
|
||||||
key: { roomServer, instanceId: null },
|
key: { roomServer, instanceId: undefined },
|
||||||
label: roomServer,
|
label: roomServer,
|
||||||
description: roomServer === homeServer ? _t("Your server") : null,
|
description: roomServer === homeServer ? _t("Your server") : null,
|
||||||
options: [
|
options: [
|
||||||
|
|
|
@ -154,7 +154,7 @@ export default class MPollBody extends React.Component<IBodyProps, IState> {
|
||||||
}
|
}
|
||||||
|
|
||||||
public componentDidMount(): void {
|
public componentDidMount(): void {
|
||||||
const room = this.context.getRoom(this.props.mxEvent.getRoomId());
|
const room = this.context?.getRoom(this.props.mxEvent.getRoomId());
|
||||||
const poll = room?.polls.get(this.props.mxEvent.getId()!);
|
const poll = room?.polls.get(this.props.mxEvent.getId()!);
|
||||||
if (poll) {
|
if (poll) {
|
||||||
this.setPollInstance(poll);
|
this.setPollInstance(poll);
|
||||||
|
@ -291,8 +291,8 @@ export default class MPollBody extends React.Component<IBodyProps, IState> {
|
||||||
const votes = countVotes(userVotes, pollEvent);
|
const votes = countVotes(userVotes, pollEvent);
|
||||||
const totalVotes = this.totalVotes(votes);
|
const totalVotes = this.totalVotes(votes);
|
||||||
const winCount = Math.max(...votes.values());
|
const winCount = Math.max(...votes.values());
|
||||||
const userId = this.context.getUserId();
|
const userId = this.context.getSafeUserId();
|
||||||
const myVote = userVotes?.get(userId!)?.answers[0];
|
const myVote = userVotes?.get(userId)?.answers[0];
|
||||||
const disclosed = M_POLL_KIND_DISCLOSED.matches(pollEvent.kind.name);
|
const disclosed = M_POLL_KIND_DISCLOSED.matches(pollEvent.kind.name);
|
||||||
|
|
||||||
// Disclosed: votes are hidden until I vote or the poll ends
|
// Disclosed: votes are hidden until I vote or the poll ends
|
||||||
|
|
|
@ -259,7 +259,7 @@ interface IFavouriteButtonProp {
|
||||||
const FavouriteButton: React.FC<IFavouriteButtonProp> = ({ mxEvent }) => {
|
const FavouriteButton: React.FC<IFavouriteButtonProp> = ({ mxEvent }) => {
|
||||||
const { isFavourite, toggleFavourite } = useFavouriteMessages();
|
const { isFavourite, toggleFavourite } = useFavouriteMessages();
|
||||||
|
|
||||||
const eventId = mxEvent.getId();
|
const eventId = mxEvent.getId()!;
|
||||||
const classes = classNames("mx_MessageActionBar_iconButton mx_MessageActionBar_favouriteButton", {
|
const classes = classNames("mx_MessageActionBar_iconButton mx_MessageActionBar_favouriteButton", {
|
||||||
mx_MessageActionBar_favouriteButton_fillstar: isFavourite(eventId),
|
mx_MessageActionBar_favouriteButton_fillstar: isFavourite(eventId),
|
||||||
});
|
});
|
||||||
|
|
|
@ -995,19 +995,8 @@ export const RoomAdminToolsContainer: React.FC<IBaseRoomProps> = ({
|
||||||
return <div />;
|
return <div />;
|
||||||
};
|
};
|
||||||
|
|
||||||
const useIsSynapseAdmin = (cli: MatrixClient): boolean => {
|
const useIsSynapseAdmin = (cli?: MatrixClient): boolean => {
|
||||||
const [isAdmin, setIsAdmin] = useState(false);
|
return useAsyncMemo(async () => (cli ? cli.isSynapseAdministrator().catch(() => false) : false), [cli], false);
|
||||||
useEffect(() => {
|
|
||||||
cli.isSynapseAdministrator().then(
|
|
||||||
(isAdmin) => {
|
|
||||||
setIsAdmin(isAdmin);
|
|
||||||
},
|
|
||||||
() => {
|
|
||||||
setIsAdmin(false);
|
|
||||||
},
|
|
||||||
);
|
|
||||||
}, [cli]);
|
|
||||||
return isAdmin;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const useHomeserverSupportsCrossSigning = (cli: MatrixClient): boolean => {
|
const useHomeserverSupportsCrossSigning = (cli: MatrixClient): boolean => {
|
||||||
|
|
|
@ -250,7 +250,7 @@ export class MessageComposer extends React.Component<IProps, IState> {
|
||||||
// The members should already be loading, and loadMembersIfNeeded
|
// The members should already be loading, and loadMembersIfNeeded
|
||||||
// will return the promise for the existing operation
|
// will return the promise for the existing operation
|
||||||
this.props.room.loadMembersIfNeeded().then(() => {
|
this.props.room.loadMembersIfNeeded().then(() => {
|
||||||
const me = this.props.room.getMember(MatrixClientPeg.get().getUserId()!);
|
const me = this.props.room.getMember(MatrixClientPeg.get().getSafeUserId()) ?? undefined;
|
||||||
this.setState({ me });
|
this.setState({ me });
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -64,7 +64,7 @@ type OverflowMenuCloser = () => void;
|
||||||
export const OverflowMenuContext = createContext<OverflowMenuCloser | null>(null);
|
export const OverflowMenuContext = createContext<OverflowMenuCloser | null>(null);
|
||||||
|
|
||||||
const MessageComposerButtons: React.FC<IProps> = (props: IProps) => {
|
const MessageComposerButtons: React.FC<IProps> = (props: IProps) => {
|
||||||
const matrixClient: MatrixClient = useContext(MatrixClientContext);
|
const matrixClient = useContext(MatrixClientContext);
|
||||||
const { room, roomId, narrow } = useContext(RoomContext);
|
const { room, roomId, narrow } = useContext(RoomContext);
|
||||||
|
|
||||||
const isWysiwygLabEnabled = useSettingValue<boolean>("feature_wysiwyg_composer");
|
const isWysiwygLabEnabled = useSettingValue<boolean>("feature_wysiwyg_composer");
|
||||||
|
@ -183,7 +183,7 @@ const UploadButtonContextProvider: React.FC<IUploadButtonProps> = ({ roomId, rel
|
||||||
const uploadInput = useRef<HTMLInputElement>();
|
const uploadInput = useRef<HTMLInputElement>();
|
||||||
|
|
||||||
const onUploadClick = (): void => {
|
const onUploadClick = (): void => {
|
||||||
if (cli.isGuest()) {
|
if (cli?.isGuest()) {
|
||||||
dis.dispatch({ action: "require_registration" });
|
dis.dispatch({ action: "require_registration" });
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
|
@ -59,7 +59,7 @@ export default function EditWysiwygComposer({
|
||||||
const { editMessage, endEditing, onChange, isSaveDisabled } = useEditing(editorStateTransfer, initialContent);
|
const { editMessage, endEditing, onChange, isSaveDisabled } = useEditing(editorStateTransfer, initialContent);
|
||||||
|
|
||||||
if (!isReady) {
|
if (!isReady) {
|
||||||
return null;
|
return <></>;
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|
|
@ -439,10 +439,12 @@ export default class Notifications extends React.PureComponent<IProps, IState> {
|
||||||
append: true,
|
append: true,
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
const pusher = this.state.pushers.find((p) => p.kind === "email" && p.pushkey === email);
|
const pusher = this.state.pushers?.find((p) => p.kind === "email" && p.pushkey === email);
|
||||||
|
if (pusher) {
|
||||||
pusher.kind = null; // flag for delete
|
pusher.kind = null; // flag for delete
|
||||||
await MatrixClientPeg.get().setPusher(pusher);
|
await MatrixClientPeg.get().setPusher(pusher);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
await this.refreshFromServer();
|
await this.refreshFromServer();
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
|
|
|
@ -129,8 +129,8 @@ const SessionManagerTab: React.FC = () => {
|
||||||
const scrollIntoViewTimeoutRef = useRef<number>();
|
const scrollIntoViewTimeoutRef = useRef<number>();
|
||||||
|
|
||||||
const matrixClient = useContext(MatrixClientContext);
|
const matrixClient = useContext(MatrixClientContext);
|
||||||
const userId = matrixClient.getUserId();
|
const userId = matrixClient?.getUserId();
|
||||||
const currentUserMember = (userId && matrixClient.getUser(userId)) || undefined;
|
const currentUserMember = (userId && matrixClient?.getUser(userId)) || undefined;
|
||||||
const clientVersions = useAsyncMemo(() => matrixClient.getVersions(), [matrixClient]);
|
const clientVersions = useAsyncMemo(() => matrixClient.getVersions(), [matrixClient]);
|
||||||
|
|
||||||
const onDeviceExpandToggle = (deviceId: ExtendedDevice["device_id"]): void => {
|
const onDeviceExpandToggle = (deviceId: ExtendedDevice["device_id"]): void => {
|
||||||
|
|
Loading…
Reference in New Issue