mirror of https://github.com/vector-im/riot-web
Fix `getRelationsForEvent` under TypeScript `strict` mode (#9558)
* Fix getRelationsForEvent tsc strictness * Use shared type for GetRelationsForEvent * Fix lint * Add alternative type * getRelationsForEvent is not required * Relations are optional * Reactions are optional * We expect relations in these tests * Add more protection if the eventID is not defined * Allow null too * Better test typing * User ID is not necessary unless something is selected * It's okay to [].includes(null) * Null is as good as undefined here * Null or undefined is good here * We have some expectations for the tests * The room and user can be undefined too * Protec * Reactions are optional * Try match signatures * Null or undefined * More null or undefined * Protec * Fix typo (wrong variable) * Remove optional params See https://github.com/matrix-org/matrix-react-sdk/pull/9558#discussion_r1017515913 * Fix up last maaaaybe relevant lint Co-authored-by: Michael Telatynski <7t3chguy@gmail.com>pull/28788/head^2
parent
2cd1fad10b
commit
2393510a7f
|
@ -20,7 +20,6 @@ import classNames from 'classnames';
|
|||
import { Room } from 'matrix-js-sdk/src/models/room';
|
||||
import { EventType } from 'matrix-js-sdk/src/@types/event';
|
||||
import { MatrixEvent } from 'matrix-js-sdk/src/models/event';
|
||||
import { Relations } from "matrix-js-sdk/src/models/relations";
|
||||
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';
|
||||
|
@ -35,7 +34,7 @@ import SettingsStore from '../../settings/SettingsStore';
|
|||
import RoomContext, { TimelineRenderingType } from "../../contexts/RoomContext";
|
||||
import { Layout } from "../../settings/enums/Layout";
|
||||
import { _t } from "../../languageHandler";
|
||||
import EventTile, { UnwrappedEventTile, IReadReceiptProps } from "../views/rooms/EventTile";
|
||||
import EventTile, { UnwrappedEventTile, GetRelationsForEvent, IReadReceiptProps } from "../views/rooms/EventTile";
|
||||
import { hasText } from "../../TextForEvent";
|
||||
import IRCTimelineProfileResizer from "../views/elements/IRCTimelineProfileResizer";
|
||||
import DMRoomMap from "../../utils/DMRoomMap";
|
||||
|
@ -186,7 +185,7 @@ interface IProps {
|
|||
// helper function to access relations for an event
|
||||
onUnfillRequest?(backwards: boolean, scrollToken: string): void;
|
||||
|
||||
getRelationsForEvent?(eventId: string, relationType: string, eventType: string): Relations;
|
||||
getRelationsForEvent?: GetRelationsForEvent;
|
||||
|
||||
hideThreadedMessages?: boolean;
|
||||
disableGrouping?: boolean;
|
||||
|
|
|
@ -1714,7 +1714,7 @@ class TimelinePanel extends React.Component<IProps, IState> {
|
|||
|
||||
private getRelationsForEvent = (
|
||||
eventId: string,
|
||||
relationType: RelationType,
|
||||
relationType: RelationType | string,
|
||||
eventType: EventType | string,
|
||||
) => this.props.timelineSet.relations?.getChildEventsForEvent(eventId, relationType, eventType);
|
||||
|
||||
|
|
|
@ -130,7 +130,7 @@ interface IProps extends IPosition {
|
|||
// True if the menu is being used as a right click menu
|
||||
rightClick?: boolean;
|
||||
// The Relations model from the JS SDK for reactions to `mxEvent`
|
||||
reactions?: Relations;
|
||||
reactions?: Relations | null | undefined;
|
||||
// A permalink to this event or an href of an anchor element the user has clicked
|
||||
link?: string;
|
||||
|
||||
|
|
|
@ -17,7 +17,6 @@ limitations under the License.
|
|||
import React from "react";
|
||||
import { MatrixEvent } from "matrix-js-sdk/src/models/event";
|
||||
import { MatrixClient } from "matrix-js-sdk/src/client";
|
||||
import { Relations } from "matrix-js-sdk/src/models/relations";
|
||||
import { PollEndEvent } from "matrix-events-sdk";
|
||||
|
||||
import { _t } from "../../../languageHandler";
|
||||
|
@ -26,16 +25,13 @@ import QuestionDialog from "./QuestionDialog";
|
|||
import { findTopAnswer } from "../messages/MPollBody";
|
||||
import Modal from "../../../Modal";
|
||||
import ErrorDialog from "./ErrorDialog";
|
||||
import { GetRelationsForEvent } from "../rooms/EventTile";
|
||||
|
||||
interface IProps extends IDialogProps {
|
||||
matrixClient: MatrixClient;
|
||||
event: MatrixEvent;
|
||||
onFinished: (success: boolean) => void;
|
||||
getRelationsForEvent?: (
|
||||
eventId: string,
|
||||
relationType: string,
|
||||
eventType: string
|
||||
) => Relations;
|
||||
getRelationsForEvent?: GetRelationsForEvent;
|
||||
}
|
||||
|
||||
export default class EndPollDialog extends React.Component<IProps> {
|
||||
|
|
|
@ -19,7 +19,6 @@ import React from 'react';
|
|||
import classNames from 'classnames';
|
||||
import { MatrixEvent } from 'matrix-js-sdk/src/models/event';
|
||||
import { Room } from 'matrix-js-sdk/src/models/room';
|
||||
import { Relations } from 'matrix-js-sdk/src/models/relations';
|
||||
import { MatrixClient } from 'matrix-js-sdk/src/client';
|
||||
|
||||
import { _t } from '../../../languageHandler';
|
||||
|
@ -36,6 +35,7 @@ import AccessibleButton, { ButtonEvent } from './AccessibleButton';
|
|||
import { getParentEventId, shouldDisplayReply } from '../../../utils/Reply';
|
||||
import RoomContext from "../../../contexts/RoomContext";
|
||||
import { MatrixClientPeg } from '../../../MatrixClientPeg';
|
||||
import { GetRelationsForEvent } from "../rooms/EventTile";
|
||||
|
||||
/**
|
||||
* This number is based on the previous behavior - if we have message of height
|
||||
|
@ -56,9 +56,7 @@ interface IProps {
|
|||
forExport?: boolean;
|
||||
isQuoteExpanded?: boolean;
|
||||
setQuoteExpanded: (isExpanded: boolean) => void;
|
||||
getRelationsForEvent?: (
|
||||
(eventId: string, relationType: string, eventType: string) => Relations
|
||||
);
|
||||
getRelationsForEvent?: GetRelationsForEvent;
|
||||
}
|
||||
|
||||
interface IState {
|
||||
|
|
|
@ -29,7 +29,7 @@ import { FocusComposerPayload } from '../../../dispatcher/payloads/FocusComposer
|
|||
|
||||
interface IProps {
|
||||
mxEvent: MatrixEvent;
|
||||
reactions?: Relations;
|
||||
reactions?: Relations | null | undefined;
|
||||
onFinished(): void;
|
||||
}
|
||||
|
||||
|
|
|
@ -16,11 +16,11 @@ limitations under the License.
|
|||
|
||||
import React, { LegacyRef } from "react";
|
||||
import { MatrixEvent } from "matrix-js-sdk/src/models/event";
|
||||
import { Relations } from "matrix-js-sdk/src/models/relations";
|
||||
|
||||
import { MediaEventHelper } from "../../../utils/MediaEventHelper";
|
||||
import EditorStateTransfer from "../../../utils/EditorStateTransfer";
|
||||
import { RoomPermalinkCreator } from "../../../utils/permalinks/Permalinks";
|
||||
import { GetRelationsForEvent } from "../rooms/EventTile";
|
||||
|
||||
export interface IBodyProps {
|
||||
mxEvent: MatrixEvent;
|
||||
|
@ -52,7 +52,7 @@ export interface IBodyProps {
|
|||
isSeeingThroughMessageHiddenForModeration?: boolean;
|
||||
|
||||
// helper function to access relations for this event
|
||||
getRelationsForEvent?: (eventId: string, relationType: string, eventType: string) => Relations;
|
||||
getRelationsForEvent?: GetRelationsForEvent;
|
||||
|
||||
ref?: React.RefObject<any> | LegacyRef<any>;
|
||||
}
|
||||
|
|
|
@ -101,8 +101,8 @@ const useUniqueId = (eventId: string): string => {
|
|||
// remove related beacon locations on beacon redaction
|
||||
const useHandleBeaconRedaction = (
|
||||
event: MatrixEvent,
|
||||
getRelationsForEvent: GetRelationsForEvent,
|
||||
cli: MatrixClient,
|
||||
matrixClient: MatrixClient,
|
||||
getRelationsForEvent?: GetRelationsForEvent,
|
||||
): void => {
|
||||
const onBeforeBeaconInfoRedaction = useCallback((_event: MatrixEvent, redactionEvent: MatrixEvent) => {
|
||||
const relations = getRelationsForEvent ?
|
||||
|
@ -110,14 +110,14 @@ const useHandleBeaconRedaction = (
|
|||
undefined;
|
||||
|
||||
relations?.getRelations()?.forEach(locationEvent => {
|
||||
cli.redactEvent(
|
||||
matrixClient.redactEvent(
|
||||
locationEvent.getRoomId(),
|
||||
locationEvent.getId(),
|
||||
undefined,
|
||||
redactionEvent.getContent(),
|
||||
);
|
||||
});
|
||||
}, [event, getRelationsForEvent, cli]);
|
||||
}, [event, matrixClient, getRelationsForEvent]);
|
||||
|
||||
useEffect(() => {
|
||||
event.addListener(MatrixEventEvent.BeforeRedaction, onBeforeBeaconInfoRedaction);
|
||||
|
@ -151,7 +151,7 @@ const MBeaconBody: React.FC<IBodyProps> = React.forwardRef(({ mxEvent, getRelati
|
|||
const markerRoomMember = isSelfLocation(mxEvent.getContent()) ? mxEvent.sender : undefined;
|
||||
const isOwnBeacon = beacon?.beaconInfoOwner === matrixClient.getUserId();
|
||||
|
||||
useHandleBeaconRedaction(mxEvent, getRelationsForEvent, matrixClient);
|
||||
useHandleBeaconRedaction(mxEvent, matrixClient, getRelationsForEvent);
|
||||
|
||||
const onClick = () => {
|
||||
if (displayStatus !== BeaconDisplayStatus.Active) {
|
||||
|
|
|
@ -16,6 +16,7 @@ limitations under the License.
|
|||
|
||||
import React from 'react';
|
||||
import classNames from 'classnames';
|
||||
import { logger } from "matrix-js-sdk/src/logger";
|
||||
import { MatrixEvent, MatrixEventEvent } from "matrix-js-sdk/src/models/event";
|
||||
import { Relations, RelationsEvent } from 'matrix-js-sdk/src/models/relations';
|
||||
import { MatrixClient } from 'matrix-js-sdk/src/matrix';
|
||||
|
@ -43,49 +44,59 @@ import PollCreateDialog from "../elements/PollCreateDialog";
|
|||
import { MatrixClientPeg } from "../../../MatrixClientPeg";
|
||||
|
||||
interface IState {
|
||||
selected?: string; // Which option was clicked by the local user
|
||||
selected?: string | null | undefined; // Which option was clicked by the local user
|
||||
voteRelations: RelatedRelations; // Voting (response) events
|
||||
endRelations: RelatedRelations; // Poll end events
|
||||
}
|
||||
|
||||
export function createVoteRelations(
|
||||
getRelationsForEvent: (
|
||||
eventId: string,
|
||||
relationType: string,
|
||||
eventType: string
|
||||
) => Relations,
|
||||
getRelationsForEvent: GetRelationsForEvent,
|
||||
eventId: string,
|
||||
) {
|
||||
return new RelatedRelations([
|
||||
getRelationsForEvent(
|
||||
eventId,
|
||||
"m.reference",
|
||||
M_POLL_RESPONSE.name,
|
||||
),
|
||||
getRelationsForEvent(
|
||||
eventId,
|
||||
"m.reference",
|
||||
M_POLL_RESPONSE.altName,
|
||||
),
|
||||
]);
|
||||
const relationsList: Relations[] = [];
|
||||
|
||||
const pollResponseRelations = getRelationsForEvent(
|
||||
eventId,
|
||||
"m.reference",
|
||||
M_POLL_RESPONSE.name,
|
||||
);
|
||||
if (pollResponseRelations) {
|
||||
relationsList.push(pollResponseRelations);
|
||||
}
|
||||
|
||||
const pollResposnseAltRelations = getRelationsForEvent(
|
||||
eventId,
|
||||
"m.reference",
|
||||
M_POLL_RESPONSE.altName,
|
||||
);
|
||||
if (pollResposnseAltRelations) {
|
||||
relationsList.push(pollResposnseAltRelations);
|
||||
}
|
||||
|
||||
return new RelatedRelations(relationsList);
|
||||
}
|
||||
|
||||
export function findTopAnswer(
|
||||
pollEvent: MatrixEvent,
|
||||
matrixClient: MatrixClient,
|
||||
getRelationsForEvent?: (
|
||||
eventId: string,
|
||||
relationType: string,
|
||||
eventType: string
|
||||
) => Relations,
|
||||
getRelationsForEvent?: GetRelationsForEvent,
|
||||
): string {
|
||||
if (!getRelationsForEvent) {
|
||||
return "";
|
||||
}
|
||||
|
||||
const pollEventId = pollEvent.getId();
|
||||
if (!pollEventId) {
|
||||
logger.warn(
|
||||
"findTopAnswer: Poll event needs an event ID to fetch relations in order to determine " +
|
||||
"the top answer - assuming no best answer",
|
||||
);
|
||||
return "";
|
||||
}
|
||||
|
||||
const poll = pollEvent.unstableExtensibleEvent as PollStartEvent;
|
||||
if (!poll?.isEquivalentTo(M_POLL_START)) {
|
||||
console.warn("Failed to parse poll to determine top answer - assuming no best answer");
|
||||
logger.warn("Failed to parse poll to determine top answer - assuming no best answer");
|
||||
return "";
|
||||
}
|
||||
|
||||
|
@ -93,25 +104,32 @@ export function findTopAnswer(
|
|||
return poll.answers.find(a => a.id === answerId)?.text ?? "";
|
||||
};
|
||||
|
||||
const voteRelations = createVoteRelations(getRelationsForEvent, pollEvent.getId());
|
||||
const voteRelations = createVoteRelations(getRelationsForEvent, pollEventId);
|
||||
|
||||
const endRelations = new RelatedRelations([
|
||||
getRelationsForEvent(
|
||||
pollEvent.getId(),
|
||||
"m.reference",
|
||||
M_POLL_END.name,
|
||||
),
|
||||
getRelationsForEvent(
|
||||
pollEvent.getId(),
|
||||
"m.reference",
|
||||
M_POLL_END.altName,
|
||||
),
|
||||
]);
|
||||
const relationsList: Relations[] = [];
|
||||
|
||||
const pollEndRelations = getRelationsForEvent(
|
||||
pollEventId,
|
||||
"m.reference",
|
||||
M_POLL_END.name,
|
||||
);
|
||||
if (pollEndRelations) {
|
||||
relationsList.push(pollEndRelations);
|
||||
}
|
||||
|
||||
const pollEndAltRelations = getRelationsForEvent(
|
||||
pollEventId,
|
||||
"m.reference",
|
||||
M_POLL_END.altName,
|
||||
);
|
||||
if (pollEndAltRelations) {
|
||||
relationsList.push(pollEndAltRelations);
|
||||
}
|
||||
|
||||
const endRelations = new RelatedRelations(relationsList);
|
||||
|
||||
const userVotes: Map<string, UserVote> = collectUserVotes(
|
||||
allVotes(pollEvent, matrixClient, voteRelations, endRelations),
|
||||
matrixClient.getUserId(),
|
||||
null,
|
||||
);
|
||||
|
||||
const votes: Map<string, number> = countVotes(userVotes, poll);
|
||||
|
@ -132,36 +150,60 @@ export function findTopAnswer(
|
|||
export function isPollEnded(
|
||||
pollEvent: MatrixEvent,
|
||||
matrixClient: MatrixClient,
|
||||
getRelationsForEvent?: (
|
||||
eventId: string,
|
||||
relationType: string,
|
||||
eventType: string
|
||||
) => Relations,
|
||||
getRelationsForEvent?: GetRelationsForEvent,
|
||||
): boolean {
|
||||
if (!getRelationsForEvent) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const roomCurrentState = matrixClient.getRoom(pollEvent.getRoomId()).currentState;
|
||||
const pollEventId = pollEvent.getId();
|
||||
if (!pollEventId) {
|
||||
logger.warn(
|
||||
"isPollEnded: Poll event must have event ID in order to determine whether it has ended " +
|
||||
"- assuming poll has not ended",
|
||||
);
|
||||
return false;
|
||||
}
|
||||
|
||||
const roomId = pollEvent.getRoomId();
|
||||
if (!roomId) {
|
||||
logger.warn(
|
||||
"isPollEnded: Poll event must have room ID in order to determine whether it has ended " +
|
||||
"- assuming poll has not ended",
|
||||
);
|
||||
return false;
|
||||
}
|
||||
|
||||
const roomCurrentState = matrixClient.getRoom(roomId)?.currentState;
|
||||
function userCanRedact(endEvent: MatrixEvent) {
|
||||
return roomCurrentState.maySendRedactionForEvent(
|
||||
const endEventSender = endEvent.getSender();
|
||||
return endEventSender && roomCurrentState && roomCurrentState.maySendRedactionForEvent(
|
||||
pollEvent,
|
||||
endEvent.getSender(),
|
||||
endEventSender,
|
||||
);
|
||||
}
|
||||
|
||||
const endRelations = new RelatedRelations([
|
||||
getRelationsForEvent(
|
||||
pollEvent.getId(),
|
||||
"m.reference",
|
||||
M_POLL_END.name,
|
||||
),
|
||||
getRelationsForEvent(
|
||||
pollEvent.getId(),
|
||||
"m.reference",
|
||||
M_POLL_END.altName,
|
||||
),
|
||||
]);
|
||||
const relationsList: Relations[] = [];
|
||||
|
||||
const pollEndRelations = getRelationsForEvent(
|
||||
pollEventId,
|
||||
"m.reference",
|
||||
M_POLL_END.name,
|
||||
);
|
||||
if (pollEndRelations) {
|
||||
relationsList.push(pollEndRelations);
|
||||
}
|
||||
|
||||
const pollEndAltRelations = getRelationsForEvent(
|
||||
pollEventId,
|
||||
"m.reference",
|
||||
M_POLL_END.altName,
|
||||
);
|
||||
if (pollEndAltRelations) {
|
||||
relationsList.push(pollEndAltRelations);
|
||||
}
|
||||
|
||||
const endRelations = new RelatedRelations(relationsList);
|
||||
|
||||
if (!endRelations) {
|
||||
return false;
|
||||
|
@ -175,7 +217,10 @@ export function isPollEnded(
|
|||
export function pollAlreadyHasVotes(mxEvent: MatrixEvent, getRelationsForEvent?: GetRelationsForEvent): boolean {
|
||||
if (!getRelationsForEvent) return false;
|
||||
|
||||
const voteRelations = createVoteRelations(getRelationsForEvent, mxEvent.getId());
|
||||
const eventId = mxEvent.getId();
|
||||
if (!eventId) return false;
|
||||
|
||||
const voteRelations = createVoteRelations(getRelationsForEvent, eventId);
|
||||
return voteRelations.getRelations().length > 0;
|
||||
}
|
||||
|
||||
|
@ -335,18 +380,35 @@ export default class MPollBody extends React.Component<IBodyProps, IState> {
|
|||
|
||||
private fetchRelations(eventType: NamespacedValue<string, string>): RelatedRelations | null {
|
||||
if (this.props.getRelationsForEvent) {
|
||||
return new RelatedRelations([
|
||||
this.props.getRelationsForEvent(
|
||||
this.props.mxEvent.getId(),
|
||||
"m.reference",
|
||||
eventType.name,
|
||||
),
|
||||
this.props.getRelationsForEvent(
|
||||
this.props.mxEvent.getId(),
|
||||
const relationsList: Relations[] = [];
|
||||
|
||||
const eventId = this.props.mxEvent.getId();
|
||||
if (!eventId) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const relations = this.props.getRelationsForEvent(
|
||||
eventId,
|
||||
"m.reference",
|
||||
eventType.name,
|
||||
);
|
||||
if (relations) {
|
||||
relationsList.push(relations);
|
||||
}
|
||||
|
||||
// If there is an alternatve experimental event type, also look for that
|
||||
if (eventType.altName) {
|
||||
const altRelations = this.props.getRelationsForEvent(
|
||||
eventId,
|
||||
"m.reference",
|
||||
eventType.altName,
|
||||
),
|
||||
]);
|
||||
);
|
||||
if (altRelations) {
|
||||
relationsList.push(altRelations);
|
||||
}
|
||||
}
|
||||
|
||||
return new RelatedRelations(relationsList);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
|
@ -380,7 +442,7 @@ export default class MPollBody extends React.Component<IBodyProps, IState> {
|
|||
const newEvents: MatrixEvent[] = this.state.voteRelations.getRelations()
|
||||
.filter(isPollResponse)
|
||||
.filter((mxEvent: MatrixEvent) =>
|
||||
!this.seenEventIds.includes(mxEvent.getId()));
|
||||
!this.seenEventIds.includes(mxEvent.getId()!));
|
||||
let newSelected = this.state.selected;
|
||||
|
||||
if (newEvents.length > 0) {
|
||||
|
@ -422,7 +484,7 @@ export default class MPollBody extends React.Component<IBodyProps, IState> {
|
|||
const totalVotes = this.totalVotes(votes);
|
||||
const winCount = Math.max(...votes.values());
|
||||
const userId = this.context.getUserId();
|
||||
const myVote = userVotes.get(userId)?.answers[0];
|
||||
const myVote = userVotes?.get(userId!)?.answers[0];
|
||||
const disclosed = M_POLL_KIND_DISCLOSED.matches(poll.kind.name);
|
||||
|
||||
// Disclosed: votes are hidden until I vote or the poll ends
|
||||
|
@ -655,12 +717,16 @@ function isPollResponse(responseEvent: MatrixEvent): boolean {
|
|||
|
||||
/**
|
||||
* Figure out the correct vote for each user.
|
||||
* @param userResponses current vote responses in the poll
|
||||
* @param {string?} userId The userId for which the `selected` option will apply to.
|
||||
* Should be set to the current user ID.
|
||||
* @param {string?} selected Local echo selected option for the userId
|
||||
* @returns a Map of user ID to their vote info
|
||||
*/
|
||||
function collectUserVotes(
|
||||
userResponses: Array<UserVote>,
|
||||
userId: string,
|
||||
selected?: string,
|
||||
userId?: string | null | undefined,
|
||||
selected?: string | null | undefined,
|
||||
): Map<string, UserVote> {
|
||||
const userVotes: Map<string, UserVote> = new Map();
|
||||
|
||||
|
@ -671,7 +737,7 @@ function collectUserVotes(
|
|||
}
|
||||
}
|
||||
|
||||
if (selected) {
|
||||
if (selected && userId) {
|
||||
userVotes.set(userId, new UserVote(0, userId, [selected]));
|
||||
}
|
||||
|
||||
|
|
|
@ -59,6 +59,7 @@ import { Action } from '../../../dispatcher/actions';
|
|||
import SdkConfig from "../../../SdkConfig";
|
||||
import { ShowThreadPayload } from "../../../dispatcher/payloads/ShowThreadPayload";
|
||||
import useFavouriteMessages from '../../../hooks/useFavouriteMessages';
|
||||
import { GetRelationsForEvent } from '../rooms/EventTile';
|
||||
|
||||
interface IOptionsButtonProps {
|
||||
mxEvent: MatrixEvent;
|
||||
|
@ -67,11 +68,7 @@ interface IOptionsButtonProps {
|
|||
getReplyChain: () => ReplyChain;
|
||||
permalinkCreator: RoomPermalinkCreator;
|
||||
onFocusChange: (menuDisplayed: boolean) => void;
|
||||
getRelationsForEvent?: (
|
||||
eventId: string,
|
||||
relationType: string,
|
||||
eventType: string
|
||||
) => Relations;
|
||||
getRelationsForEvent?: GetRelationsForEvent;
|
||||
}
|
||||
|
||||
const OptionsButton: React.FC<IOptionsButtonProps> = ({
|
||||
|
@ -135,7 +132,7 @@ const OptionsButton: React.FC<IOptionsButtonProps> = ({
|
|||
|
||||
interface IReactButtonProps {
|
||||
mxEvent: MatrixEvent;
|
||||
reactions: Relations;
|
||||
reactions?: Relations | null | undefined;
|
||||
onFocusChange: (menuDisplayed: boolean) => void;
|
||||
}
|
||||
|
||||
|
@ -299,7 +296,7 @@ const FavouriteButton = ({ mxEvent }: IFavouriteButtonProp) => {
|
|||
|
||||
interface IMessageActionBarProps {
|
||||
mxEvent: MatrixEvent;
|
||||
reactions?: Relations;
|
||||
reactions?: Relations | null | undefined;
|
||||
// TODO: Types
|
||||
getTile: () => any | null;
|
||||
getReplyChain: () => ReplyChain | undefined;
|
||||
|
@ -307,11 +304,7 @@ interface IMessageActionBarProps {
|
|||
onFocusChange?: (menuDisplayed: boolean) => void;
|
||||
toggleThreadExpanded: () => void;
|
||||
isQuoteExpanded?: boolean;
|
||||
getRelationsForEvent?: (
|
||||
eventId: string,
|
||||
relationType: RelationType | string,
|
||||
eventType: string
|
||||
) => Relations;
|
||||
getRelationsForEvent?: GetRelationsForEvent;
|
||||
}
|
||||
|
||||
export default class MessageActionBar extends React.PureComponent<IMessageActionBarProps> {
|
||||
|
|
|
@ -16,7 +16,6 @@ limitations under the License.
|
|||
|
||||
import React, { createRef } from 'react';
|
||||
import { EventType, MsgType } from "matrix-js-sdk/src/@types/event";
|
||||
import { Relations } from 'matrix-js-sdk/src/models/relations';
|
||||
import { M_BEACON_INFO } from 'matrix-js-sdk/src/@types/beacon';
|
||||
import { M_LOCATION } from 'matrix-js-sdk/src/@types/location';
|
||||
import { M_POLL_START } from "matrix-events-sdk";
|
||||
|
@ -41,7 +40,7 @@ import MPollBody from "./MPollBody";
|
|||
import MLocationBody from "./MLocationBody";
|
||||
import MjolnirBody from "./MjolnirBody";
|
||||
import MBeaconBody from "./MBeaconBody";
|
||||
import { IEventTileOps } from "../rooms/EventTile";
|
||||
import { GetRelationsForEvent, IEventTileOps } from "../rooms/EventTile";
|
||||
import { VoiceBroadcastBody, VoiceBroadcastInfoEventType, VoiceBroadcastInfoState } from '../../../voice-broadcast';
|
||||
|
||||
// onMessageAllowed is handled internally
|
||||
|
@ -51,7 +50,7 @@ interface IProps extends Omit<IBodyProps, "onMessageAllowed" | "mediaEventHelper
|
|||
overrideEventTypes?: Record<string, typeof React.Component>;
|
||||
|
||||
// helper function to access relations for this event
|
||||
getRelationsForEvent?: (eventId: string, relationType: string, eventType: string) => Relations;
|
||||
getRelationsForEvent?: GetRelationsForEvent;
|
||||
|
||||
isSeeingThroughMessageHiddenForModeration?: boolean;
|
||||
}
|
||||
|
|
|
@ -65,7 +65,7 @@ interface IProps {
|
|||
// The event we're displaying reactions for
|
||||
mxEvent: MatrixEvent;
|
||||
// The Relations model from the JS SDK for reactions to `mxEvent`
|
||||
reactions?: Relations;
|
||||
reactions?: Relations | null | undefined;
|
||||
}
|
||||
|
||||
interface IState {
|
||||
|
@ -114,7 +114,7 @@ export default class ReactionsRow extends React.PureComponent<IProps, IState> {
|
|||
}
|
||||
|
||||
componentDidUpdate(prevProps: IProps) {
|
||||
if (prevProps.reactions !== this.props.reactions) {
|
||||
if (this.props.reactions && prevProps.reactions !== this.props.reactions) {
|
||||
this.props.reactions.on(RelationsEvent.Add, this.onReactionsChange);
|
||||
this.props.reactions.on(RelationsEvent.Remove, this.onReactionsChange);
|
||||
this.props.reactions.on(RelationsEvent.Redaction, this.onReactionsChange);
|
||||
|
|
|
@ -17,7 +17,7 @@ limitations under the License.
|
|||
|
||||
import React, { createRef, forwardRef, MouseEvent, RefObject } from 'react';
|
||||
import classNames from "classnames";
|
||||
import { EventType, MsgType } from "matrix-js-sdk/src/@types/event";
|
||||
import { EventType, MsgType, RelationType } from "matrix-js-sdk/src/@types/event";
|
||||
import { EventStatus, MatrixEvent, MatrixEventEvent } from "matrix-js-sdk/src/models/event";
|
||||
import { Relations } from "matrix-js-sdk/src/models/relations";
|
||||
import { RoomMember } from "matrix-js-sdk/src/models/room-member";
|
||||
|
@ -87,7 +87,11 @@ import { isLocalRoom } from '../../../utils/localRoom/isLocalRoom';
|
|||
import { ElementCall } from "../../../models/Call";
|
||||
import { UnreadNotificationBadge } from './NotificationBadge/UnreadNotificationBadge';
|
||||
|
||||
export type GetRelationsForEvent = (eventId: string, relationType: string, eventType: string) => Relations;
|
||||
export type GetRelationsForEvent = (
|
||||
eventId: string,
|
||||
relationType: RelationType | string,
|
||||
eventType: EventType | string,
|
||||
) => Relations | null | undefined;
|
||||
|
||||
// Our component structure for EventTiles on the timeline is:
|
||||
//
|
||||
|
@ -233,7 +237,7 @@ interface IState {
|
|||
// Whether onRequestKeysClick has been called since mounting.
|
||||
previouslyRequestedKeys: boolean;
|
||||
// The Relations model from the JS SDK for reactions to `mxEvent`
|
||||
reactions: Relations;
|
||||
reactions?: Relations | null | undefined;
|
||||
|
||||
hover: boolean;
|
||||
|
||||
|
|
|
@ -19,7 +19,6 @@ import classNames from 'classnames';
|
|||
import { MatrixEvent, MatrixEventEvent } from "matrix-js-sdk/src/models/event";
|
||||
import { EventType, MsgType } from 'matrix-js-sdk/src/@types/event';
|
||||
import { logger } from "matrix-js-sdk/src/logger";
|
||||
import { Relations } from 'matrix-js-sdk/src/models/relations';
|
||||
|
||||
import { _t } from '../../../languageHandler';
|
||||
import dis from '../../../dispatcher/dispatcher';
|
||||
|
@ -33,6 +32,7 @@ import MFileBody from "../messages/MFileBody";
|
|||
import MVoiceMessageBody from "../messages/MVoiceMessageBody";
|
||||
import { ViewRoomPayload } from "../../../dispatcher/payloads/ViewRoomPayload";
|
||||
import { renderReplyTile } from "../../../events/EventTileFactory";
|
||||
import { GetRelationsForEvent } from "../rooms/EventTile";
|
||||
|
||||
interface IProps {
|
||||
mxEvent: MatrixEvent;
|
||||
|
@ -41,9 +41,7 @@ interface IProps {
|
|||
highlightLink?: string;
|
||||
onHeightChanged?(): void;
|
||||
toggleExpandedQuote?: () => void;
|
||||
getRelationsForEvent?: (
|
||||
(eventId: string, relationType: string, eventType: string) => Relations
|
||||
);
|
||||
getRelationsForEvent?: GetRelationsForEvent;
|
||||
}
|
||||
|
||||
export default class ReplyTile extends React.PureComponent<IProps> {
|
||||
|
|
|
@ -321,12 +321,13 @@ describe("MPollBody", () => {
|
|||
const votes = [responseEvent("@me:example.com", "pizza", 100)];
|
||||
const body = newMPollBody(votes);
|
||||
const props: IBodyProps = body.instance().props as IBodyProps;
|
||||
const voteRelations: Relations = props.getRelationsForEvent(
|
||||
const voteRelations = props!.getRelationsForEvent!(
|
||||
"$mypoll", "m.reference", M_POLL_RESPONSE.name);
|
||||
expect(voteRelations).toBeDefined();
|
||||
clickRadio(body, "pizza");
|
||||
|
||||
// When a new vote from me comes in
|
||||
voteRelations.addEvent(responseEvent("@me:example.com", "wings", 101));
|
||||
voteRelations!.addEvent(responseEvent("@me:example.com", "wings", 101));
|
||||
|
||||
// Then the new vote is counted, not the old one
|
||||
expect(votesCount(body, "pizza")).toBe("0 votes");
|
||||
|
@ -342,12 +343,13 @@ describe("MPollBody", () => {
|
|||
const votes = [responseEvent("@me:example.com", "pizza")];
|
||||
const body = newMPollBody(votes);
|
||||
const props: IBodyProps = body.instance().props as IBodyProps;
|
||||
const voteRelations: Relations = props.getRelationsForEvent(
|
||||
const voteRelations = props!.getRelationsForEvent!(
|
||||
"$mypoll", "m.reference", M_POLL_RESPONSE.name);
|
||||
expect(voteRelations).toBeDefined();
|
||||
clickRadio(body, "pizza");
|
||||
|
||||
// When a new vote from someone else comes in
|
||||
voteRelations.addEvent(responseEvent("@xx:example.com", "wings", 101));
|
||||
voteRelations!.addEvent(responseEvent("@xx:example.com", "wings", 101));
|
||||
|
||||
// Then my vote is still for pizza
|
||||
// NOTE: the new event does not affect the counts for other people -
|
||||
|
|
Loading…
Reference in New Issue