mirror of
https://github.com/vector-im/element-web.git
synced 2024-11-15 20:54:59 +08:00
Unify notifications panel event design (#9754)
This commit is contained in:
parent
6585fb1f55
commit
bef8e077f6
@ -62,7 +62,6 @@
|
||||
@import "./structures/_MainSplit.pcss";
|
||||
@import "./structures/_MatrixChat.pcss";
|
||||
@import "./structures/_NonUrgentToastContainer.pcss";
|
||||
@import "./structures/_NotificationPanel.pcss";
|
||||
@import "./structures/_QuickSettingsButton.pcss";
|
||||
@import "./structures/_RightPanel.pcss";
|
||||
@import "./structures/_RoomSearch.pcss";
|
||||
|
@ -1,113 +0,0 @@
|
||||
/*
|
||||
Copyright 2015, 2016 OpenMarket Ltd
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
.mx_NotificationPanel {
|
||||
order: 2;
|
||||
flex: 1 1 0;
|
||||
overflow-y: auto;
|
||||
display: flex;
|
||||
|
||||
.mx_RoomView_messageListWrapper {
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.mx_RoomView_MessageList {
|
||||
width: 100%;
|
||||
|
||||
h2 {
|
||||
margin-left: 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* FIXME: rather than having EventTile's default CSS be for MessagePanel,
|
||||
we should make EventTile a base CSS class and customise it specifically
|
||||
for usage in {Message,File,Notification}Panel. */
|
||||
|
||||
.mx_EventTile_avatar {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.mx_EventTile {
|
||||
word-break: break-word;
|
||||
position: relative;
|
||||
padding-block: 18px;
|
||||
|
||||
.mx_EventTile_senderDetails,
|
||||
.mx_EventTile_line {
|
||||
padding-left: 36px; /* align with the room name */
|
||||
}
|
||||
|
||||
.mx_EventTile_senderDetails {
|
||||
position: relative;
|
||||
|
||||
a {
|
||||
display: flex;
|
||||
column-gap: 5px; /* TODO: Use a spacing variable */
|
||||
}
|
||||
}
|
||||
|
||||
.mx_DisambiguatedProfile,
|
||||
.mx_MessageTimestamp {
|
||||
color: $primary-content;
|
||||
font-size: $font-12px;
|
||||
display: inline;
|
||||
}
|
||||
|
||||
&:hover .mx_EventTile_line {
|
||||
background-color: $background;
|
||||
}
|
||||
|
||||
&:not(.mx_EventTile_last):not(.mx_EventTile_lastInSection)::after {
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
background-color: $tertiary-content;
|
||||
height: 1px;
|
||||
opacity: 0.4;
|
||||
content: "";
|
||||
}
|
||||
}
|
||||
|
||||
.mx_EventTile_roomName {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
column-gap: $spacing-8;
|
||||
font-weight: bold;
|
||||
font-size: $font-14px;
|
||||
|
||||
a {
|
||||
color: $primary-content;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
}
|
||||
|
||||
.mx_EventTile_selected .mx_EventTile_line {
|
||||
padding-left: 0;
|
||||
}
|
||||
|
||||
.mx_EventTile_content {
|
||||
margin-right: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.mx_NotificationPanel_empty::before {
|
||||
mask-image: url("$(res)/img/element-icons/notifications.svg");
|
||||
}
|
@ -210,7 +210,6 @@ limitations under the License.
|
||||
|
||||
.mx_FilePanel,
|
||||
.mx_UserInfo,
|
||||
.mx_NotificationPanel,
|
||||
.mx_MemberList {
|
||||
&.mx_BaseCard {
|
||||
padding: $spacing-32 0 0;
|
||||
|
@ -836,7 +836,8 @@ $left-gutter: 64px;
|
||||
}
|
||||
}
|
||||
|
||||
.mx_EventTile[data-shape="ThreadsList"] {
|
||||
.mx_EventTile[data-shape="ThreadsList"],
|
||||
.mx_EventTile[data-shape="Notification"] {
|
||||
--topOffset: $spacing-12;
|
||||
--leftOffset: 48px;
|
||||
$borderRadius: 8px;
|
||||
@ -916,9 +917,7 @@ $left-gutter: 64px;
|
||||
}
|
||||
|
||||
.mx_DisambiguatedProfile {
|
||||
margin-inline: 0 $spacing-12;
|
||||
display: inline-flex;
|
||||
flex: 1;
|
||||
|
||||
.mx_DisambiguatedProfile_displayName,
|
||||
.mx_DisambiguatedProfile_mxid {
|
||||
@ -941,6 +940,7 @@ $left-gutter: 64px;
|
||||
width: 100%;
|
||||
box-sizing: border-box;
|
||||
padding-bottom: 0;
|
||||
padding-inline-start: var(--leftOffset);
|
||||
|
||||
.mx_ThreadPanel_replies {
|
||||
margin-top: $spacing-8;
|
||||
@ -966,11 +966,6 @@ $left-gutter: 64px;
|
||||
}
|
||||
}
|
||||
|
||||
.mx_DisambiguatedProfile,
|
||||
.mx_EventTile_line {
|
||||
padding-inline-start: var(--leftOffset);
|
||||
}
|
||||
|
||||
.mx_MessageTimestamp {
|
||||
font-size: $font-12px;
|
||||
max-width: var(--MessageTimestamp-max-width);
|
||||
@ -1300,6 +1295,21 @@ $left-gutter: 64px;
|
||||
}
|
||||
}
|
||||
|
||||
.mx_EventTile_details {
|
||||
display: flex;
|
||||
width: -webkit-fill-available;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
gap: $spacing-8;
|
||||
margin-left: var(--leftOffset);
|
||||
.mx_EventTile_truncated {
|
||||
flex: 1;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
}
|
||||
|
||||
/* Media query for mobile UI */
|
||||
@media only screen and (max-width: 480px) {
|
||||
.mx_EventTile_content {
|
||||
|
@ -25,6 +25,7 @@ import Spinner from "../views/elements/Spinner";
|
||||
import { Layout } from "../../settings/enums/Layout";
|
||||
import RoomContext, { TimelineRenderingType } from "../../contexts/RoomContext";
|
||||
import Measured from "../views/elements/Measured";
|
||||
import Heading from "../views/typography/Heading";
|
||||
|
||||
interface IProps {
|
||||
onClose(): void;
|
||||
@ -90,8 +91,21 @@ export default class NotificationPanel extends React.PureComponent<IProps, IStat
|
||||
narrow: this.state.narrow,
|
||||
}}
|
||||
>
|
||||
<BaseCard className="mx_NotificationPanel" onClose={this.props.onClose} withoutScrollContainer>
|
||||
<Measured sensor={this.card.current} onMeasurement={this.onMeasurement} />
|
||||
<BaseCard
|
||||
header={
|
||||
<Heading size="h4" className="mx_BaseCard_header_title_heading">
|
||||
{_t("Notifications")}
|
||||
</Heading>
|
||||
}
|
||||
/**
|
||||
* Need to rename this CSS class to something more generic
|
||||
* Will be done once all the panels are using a similar layout
|
||||
*/
|
||||
className="mx_ThreadPanel"
|
||||
onClose={this.props.onClose}
|
||||
withoutScrollContainer={true}
|
||||
>
|
||||
{this.card.current && <Measured sensor={this.card.current} onMeasurement={this.onMeasurement} />}
|
||||
{content}
|
||||
</BaseCard>
|
||||
</RoomContext.Provider>
|
||||
|
@ -29,8 +29,6 @@ import { CryptoEvent } from "matrix-js-sdk/src/crypto";
|
||||
import { UserTrustLevel } from "matrix-js-sdk/src/crypto/CrossSigning";
|
||||
import { Feature, ServerSupport } from "matrix-js-sdk/src/feature";
|
||||
|
||||
import { Icon as LinkIcon } from "../../../../res/img/element-icons/link.svg";
|
||||
import { Icon as ViewInRoomIcon } from "../../../../res/img/element-icons/view-in-room.svg";
|
||||
import ReplyChain from "../elements/ReplyChain";
|
||||
import { _t } from "../../../languageHandler";
|
||||
import dis from "../../../dispatcher/dispatcher";
|
||||
@ -63,8 +61,6 @@ import SettingsStore from "../../../settings/SettingsStore";
|
||||
import { MessagePreviewStore } from "../../../stores/room-list/MessagePreviewStore";
|
||||
import RoomContext, { TimelineRenderingType } from "../../../contexts/RoomContext";
|
||||
import { MediaEventHelper } from "../../../utils/MediaEventHelper";
|
||||
import Toolbar from "../../../accessibility/Toolbar";
|
||||
import { RovingAccessibleTooltipButton } from "../../../accessibility/roving/RovingAccessibleTooltipButton";
|
||||
import { ThreadNotificationState } from "../../../stores/notifications/ThreadNotificationState";
|
||||
import { RoomNotificationStateStore } from "../../../stores/notifications/RoomNotificationStateStore";
|
||||
import { NotificationStateEvents } from "../../../stores/notifications/NotificationState";
|
||||
@ -85,6 +81,7 @@ import { ShowThreadPayload } from "../../../dispatcher/payloads/ShowThreadPayloa
|
||||
import { isLocalRoom } from "../../../utils/localRoom/isLocalRoom";
|
||||
import { ElementCall } from "../../../models/Call";
|
||||
import { UnreadNotificationBadge } from "./NotificationBadge/UnreadNotificationBadge";
|
||||
import { EventTileThreadToolbar } from "./EventTile/EventTileThreadToolbar";
|
||||
|
||||
export type GetRelationsForEvent = (
|
||||
eventId: string,
|
||||
@ -972,6 +969,8 @@ export class UnwrappedEventTile extends React.Component<EventTileProps, IState>
|
||||
isContinuation = false;
|
||||
}
|
||||
|
||||
const isRenderingNotification = this.context.timelineRenderingType === TimelineRenderingType.Notification;
|
||||
|
||||
const isEditing = !!this.props.editState;
|
||||
const classes = classNames({
|
||||
mx_EventTile_bubbleContainer: isBubbleMessage,
|
||||
@ -996,7 +995,8 @@ export class UnwrappedEventTile extends React.Component<EventTileProps, IState>
|
||||
mx_EventTile_bad: isEncryptionFailure,
|
||||
mx_EventTile_emote: msgtype === MsgType.Emote,
|
||||
mx_EventTile_noSender: this.props.hideSender,
|
||||
mx_EventTile_clamp: this.context.timelineRenderingType === TimelineRenderingType.ThreadsList,
|
||||
mx_EventTile_clamp:
|
||||
this.context.timelineRenderingType === TimelineRenderingType.ThreadsList || isRenderingNotification,
|
||||
mx_EventTile_noBubble: noBubbleEvent,
|
||||
});
|
||||
|
||||
@ -1012,12 +1012,12 @@ export class UnwrappedEventTile extends React.Component<EventTileProps, IState>
|
||||
// Local echos have a send "status".
|
||||
const scrollToken = this.props.mxEvent.status ? undefined : this.props.mxEvent.getId();
|
||||
|
||||
let avatar: JSX.Element;
|
||||
let sender: JSX.Element;
|
||||
let avatar: JSX.Element | null = null;
|
||||
let sender: JSX.Element | null = null;
|
||||
let avatarSize: number;
|
||||
let needsSenderProfile: boolean;
|
||||
|
||||
if (this.context.timelineRenderingType === TimelineRenderingType.Notification) {
|
||||
if (isRenderingNotification) {
|
||||
avatarSize = 24;
|
||||
needsSenderProfile = true;
|
||||
} else if (isInfoMessage) {
|
||||
@ -1061,7 +1061,9 @@ export class UnwrappedEventTile extends React.Component<EventTileProps, IState>
|
||||
member = this.props.mxEvent.sender;
|
||||
}
|
||||
// In the ThreadsList view we use the entire EventTile as a click target to open the thread instead
|
||||
const viewUserOnClick = this.context.timelineRenderingType !== TimelineRenderingType.ThreadsList;
|
||||
const viewUserOnClick = ![TimelineRenderingType.ThreadsList, TimelineRenderingType.Notification].includes(
|
||||
this.context.timelineRenderingType,
|
||||
);
|
||||
avatar = (
|
||||
<div className="mx_EventTile_avatar">
|
||||
<MemberAvatar
|
||||
@ -1202,57 +1204,6 @@ export class UnwrappedEventTile extends React.Component<EventTileProps, IState>
|
||||
const isOwnEvent = this.props.mxEvent?.getSender() === MatrixClientPeg.get().getUserId();
|
||||
|
||||
switch (this.context.timelineRenderingType) {
|
||||
case TimelineRenderingType.Notification: {
|
||||
const room = MatrixClientPeg.get().getRoom(this.props.mxEvent.getRoomId());
|
||||
return React.createElement(
|
||||
this.props.as || "li",
|
||||
{
|
||||
"className": classes,
|
||||
"aria-live": ariaLive,
|
||||
"aria-atomic": true,
|
||||
"data-scroll-tokens": scrollToken,
|
||||
},
|
||||
[
|
||||
<div className="mx_EventTile_roomName" key="mx_EventTile_roomName">
|
||||
<RoomAvatar room={room} width={28} height={28} />
|
||||
<a href={permalink} onClick={this.onPermalinkClicked}>
|
||||
{room ? room.name : ""}
|
||||
</a>
|
||||
</div>,
|
||||
<div className="mx_EventTile_senderDetails" key="mx_EventTile_senderDetails">
|
||||
{avatar}
|
||||
<a
|
||||
href={permalink}
|
||||
onClick={this.onPermalinkClicked}
|
||||
onContextMenu={this.onTimestampContextMenu}
|
||||
>
|
||||
{sender}
|
||||
{timestamp}
|
||||
</a>
|
||||
</div>,
|
||||
<div className={lineClasses} key="mx_EventTile_line" onContextMenu={this.onContextMenu}>
|
||||
{this.renderContextMenu()}
|
||||
{renderTile(
|
||||
TimelineRenderingType.Notification,
|
||||
{
|
||||
...this.props,
|
||||
|
||||
// overrides
|
||||
ref: this.tile,
|
||||
isSeeingThroughMessageHiddenForModeration,
|
||||
|
||||
// appease TS
|
||||
highlights: this.props.highlights,
|
||||
highlightLink: this.props.highlightLink,
|
||||
onHeightChanged: this.props.onHeightChanged,
|
||||
permalinkCreator: this.props.permalinkCreator,
|
||||
},
|
||||
this.context.showHiddenEvents,
|
||||
)}
|
||||
</div>,
|
||||
],
|
||||
);
|
||||
}
|
||||
case TimelineRenderingType.Thread: {
|
||||
return React.createElement(
|
||||
this.props.as || "li",
|
||||
@ -1289,8 +1240,8 @@ export class UnwrappedEventTile extends React.Component<EventTileProps, IState>
|
||||
// appease TS
|
||||
highlights: this.props.highlights,
|
||||
highlightLink: this.props.highlightLink,
|
||||
onHeightChanged: this.props.onHeightChanged,
|
||||
permalinkCreator: this.props.permalinkCreator,
|
||||
onHeightChanged: () => this.props.onHeightChanged,
|
||||
permalinkCreator: this.props.permalinkCreator!,
|
||||
},
|
||||
this.context.showHiddenEvents,
|
||||
)}
|
||||
@ -1304,6 +1255,7 @@ export class UnwrappedEventTile extends React.Component<EventTileProps, IState>
|
||||
],
|
||||
);
|
||||
}
|
||||
case TimelineRenderingType.Notification:
|
||||
case TimelineRenderingType.ThreadsList: {
|
||||
const room = MatrixClientPeg.get().getRoom(this.props.mxEvent.getRoomId());
|
||||
// tab-index=-1 to allow it to be focusable but do not add tab stop for it, primarily for screen readers
|
||||
@ -1326,20 +1278,48 @@ export class UnwrappedEventTile extends React.Component<EventTileProps, IState>
|
||||
"onMouseEnter": () => this.setState({ hover: true }),
|
||||
"onMouseLeave": () => this.setState({ hover: false }),
|
||||
"onClick": (ev: MouseEvent) => {
|
||||
const target = ev.currentTarget as HTMLElement;
|
||||
let index = -1;
|
||||
if (target.parentElement) index = Array.from(target.parentElement.children).indexOf(target);
|
||||
switch (this.context.timelineRenderingType) {
|
||||
case TimelineRenderingType.Notification:
|
||||
this.viewInRoom(ev);
|
||||
break;
|
||||
case TimelineRenderingType.ThreadsList:
|
||||
dis.dispatch<ShowThreadPayload>({
|
||||
action: Action.ShowThread,
|
||||
rootEvent: this.props.mxEvent,
|
||||
push: true,
|
||||
});
|
||||
const target = ev.currentTarget as HTMLElement;
|
||||
const index = Array.from(target.parentElement.children).indexOf(target);
|
||||
PosthogTrackers.trackInteraction("WebThreadsPanelThreadItem", ev, index);
|
||||
PosthogTrackers.trackInteraction("WebThreadsPanelThreadItem", ev, index ?? -1);
|
||||
break;
|
||||
}
|
||||
},
|
||||
},
|
||||
<>
|
||||
<div className="mx_EventTile_details">
|
||||
{sender}
|
||||
{avatar}
|
||||
{isRenderingNotification && room ? (
|
||||
<span className="mx_EventTile_truncated">
|
||||
{" "}
|
||||
{_t(
|
||||
" in <strong>%(room)s</strong>",
|
||||
{ room: room.name },
|
||||
{ strong: (sub) => <strong>{sub}</strong> },
|
||||
)}
|
||||
</span>
|
||||
) : (
|
||||
""
|
||||
)}
|
||||
{timestamp}
|
||||
</div>
|
||||
{isRenderingNotification && room ? (
|
||||
<div className="mx_EventTile_avatar">
|
||||
<RoomAvatar room={room} width={28} height={28} />
|
||||
</div>
|
||||
) : (
|
||||
avatar
|
||||
)}
|
||||
<div className={lineClasses} key="mx_EventTile_line">
|
||||
<div className="mx_EventTile_body">
|
||||
{this.props.mxEvent.isRedacted() ? (
|
||||
@ -1350,24 +1330,13 @@ export class UnwrappedEventTile extends React.Component<EventTileProps, IState>
|
||||
</div>
|
||||
{this.renderThreadPanelSummary()}
|
||||
</div>
|
||||
<Toolbar className="mx_MessageActionBar" aria-label={_t("Message Actions")} aria-live="off">
|
||||
<RovingAccessibleTooltipButton
|
||||
className="mx_MessageActionBar_iconButton"
|
||||
onClick={this.viewInRoom}
|
||||
title={_t("View in room")}
|
||||
key="view_in_room"
|
||||
>
|
||||
<ViewInRoomIcon />
|
||||
</RovingAccessibleTooltipButton>
|
||||
<RovingAccessibleTooltipButton
|
||||
className="mx_MessageActionBar_iconButton"
|
||||
onClick={this.copyLinkToThread}
|
||||
title={_t("Copy link to thread")}
|
||||
key="copy_link_to_thread"
|
||||
>
|
||||
<LinkIcon />
|
||||
</RovingAccessibleTooltipButton>
|
||||
</Toolbar>
|
||||
{this.context.timelineRenderingType === TimelineRenderingType.ThreadsList && (
|
||||
<EventTileThreadToolbar
|
||||
viewInRoom={this.viewInRoom}
|
||||
copyLinkToThread={this.copyLinkToThread}
|
||||
/>
|
||||
)}
|
||||
|
||||
{msgOption}
|
||||
<UnreadNotificationBadge room={room} threadId={this.props.mxEvent.getId()} />
|
||||
</>,
|
||||
|
@ -0,0 +1,53 @@
|
||||
/*
|
||||
Copyright 2022 The Matrix.org Foundation C.I.C.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
import React from "react";
|
||||
|
||||
import { RovingAccessibleTooltipButton } from "../../../../accessibility/RovingTabIndex";
|
||||
import Toolbar from "../../../../accessibility/Toolbar";
|
||||
import { _t } from "../../../../languageHandler";
|
||||
import { Icon as LinkIcon } from "../../../../../res/img/element-icons/link.svg";
|
||||
import { Icon as ViewInRoomIcon } from "../../../../../res/img/element-icons/view-in-room.svg";
|
||||
import { ButtonEvent } from "../../elements/AccessibleButton";
|
||||
|
||||
export function EventTileThreadToolbar({
|
||||
viewInRoom,
|
||||
copyLinkToThread,
|
||||
}: {
|
||||
viewInRoom: (evt: ButtonEvent) => void;
|
||||
copyLinkToThread: (evt: ButtonEvent) => void;
|
||||
}) {
|
||||
return (
|
||||
<Toolbar className="mx_MessageActionBar" aria-label={_t("Message Actions")} aria-live="off">
|
||||
<RovingAccessibleTooltipButton
|
||||
className="mx_MessageActionBar_iconButton"
|
||||
onClick={viewInRoom}
|
||||
title={_t("View in room")}
|
||||
key="view_in_room"
|
||||
>
|
||||
<ViewInRoomIcon />
|
||||
</RovingAccessibleTooltipButton>
|
||||
<RovingAccessibleTooltipButton
|
||||
className="mx_MessageActionBar_iconButton"
|
||||
onClick={copyLinkToThread}
|
||||
title={_t("Copy link to thread")}
|
||||
key="copy_link_to_thread"
|
||||
>
|
||||
<LinkIcon />
|
||||
</RovingAccessibleTooltipButton>
|
||||
</Toolbar>
|
||||
);
|
||||
}
|
@ -1879,9 +1879,7 @@
|
||||
"Mod": "Mod",
|
||||
"From a thread": "From a thread",
|
||||
"This event could not be displayed": "This event could not be displayed",
|
||||
"Message Actions": "Message Actions",
|
||||
"View in room": "View in room",
|
||||
"Copy link to thread": "Copy link to thread",
|
||||
" in <strong>%(room)s</strong>": " in <strong>%(room)s</strong>",
|
||||
"Encrypted by an unverified session": "Encrypted by an unverified session",
|
||||
"Unencrypted": "Unencrypted",
|
||||
"Encrypted by a deleted session": "Encrypted by a deleted session",
|
||||
@ -2130,6 +2128,9 @@
|
||||
"Italic": "Italic",
|
||||
"Underline": "Underline",
|
||||
"Code": "Code",
|
||||
"Message Actions": "Message Actions",
|
||||
"View in room": "View in room",
|
||||
"Copy link to thread": "Copy link to thread",
|
||||
"Error updating main address": "Error updating main address",
|
||||
"There was an error updating the room's main address. It may not be allowed by the server or a temporary failure occurred.": "There was an error updating the room's main address. It may not be allowed by the server or a temporary failure occurred.",
|
||||
"There was an error updating the room's alternative addresses. It may not be allowed by the server or a temporary failure occurred.": "There was an error updating the room's alternative addresses. It may not be allowed by the server or a temporary failure occurred.",
|
||||
|
@ -15,7 +15,6 @@ limitations under the License.
|
||||
*/
|
||||
|
||||
import * as React from "react";
|
||||
import { act, render, screen, waitFor } from "@testing-library/react";
|
||||
import { EventType } from "matrix-js-sdk/src/@types/event";
|
||||
import { MatrixClient, PendingEventOrdering } from "matrix-js-sdk/src/client";
|
||||
import { MatrixEvent } from "matrix-js-sdk/src/models/event";
|
||||
@ -23,6 +22,7 @@ import { NotificationCountType, Room } from "matrix-js-sdk/src/models/room";
|
||||
import { DeviceTrustLevel, UserTrustLevel } from "matrix-js-sdk/src/crypto/CrossSigning";
|
||||
import { DeviceInfo } from "matrix-js-sdk/src/crypto/deviceinfo";
|
||||
import { IEncryptedEventInfo } from "matrix-js-sdk/src/crypto/api";
|
||||
import { render, waitFor, screen, act, fireEvent } from "@testing-library/react";
|
||||
|
||||
import EventTile, { EventTileProps } from "../../../../src/components/views/rooms/EventTile";
|
||||
import MatrixClientContext from "../../../../src/contexts/MatrixClientContext";
|
||||
@ -31,6 +31,9 @@ import { MatrixClientPeg } from "../../../../src/MatrixClientPeg";
|
||||
import SettingsStore from "../../../../src/settings/SettingsStore";
|
||||
import { getRoomContext, mkEncryptedEvent, mkEvent, mkMessage, stubClient } from "../../../test-utils";
|
||||
import { mkThread } from "../../../test-utils/threads";
|
||||
import DMRoomMap from "../../../../src/utils/DMRoomMap";
|
||||
import dis from "../../../../src/dispatcher/dispatcher";
|
||||
import { Action } from "../../../../src/dispatcher/actions";
|
||||
|
||||
describe("EventTile", () => {
|
||||
const ROOM_ID = "!roomId:example.org";
|
||||
@ -159,6 +162,43 @@ describe("EventTile", () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe("EventTile in the right panel", () => {
|
||||
beforeAll(() => {
|
||||
const dmRoomMap: DMRoomMap = {
|
||||
getUserIdForRoomId: jest.fn(),
|
||||
} as unknown as DMRoomMap;
|
||||
DMRoomMap.setShared(dmRoomMap);
|
||||
});
|
||||
|
||||
it("renders the room name for notifications", () => {
|
||||
const { container } = getComponent({}, TimelineRenderingType.Notification);
|
||||
expect(container.getElementsByClassName("mx_EventTile_details")[0]).toHaveTextContent(
|
||||
"@alice:example.org in !roomId:example.org",
|
||||
);
|
||||
});
|
||||
|
||||
it("renders the sender for the thread list", () => {
|
||||
const { container } = getComponent({}, TimelineRenderingType.ThreadsList);
|
||||
expect(container.getElementsByClassName("mx_EventTile_details")[0]).toHaveTextContent("@alice:example.org");
|
||||
});
|
||||
|
||||
it.each([
|
||||
[TimelineRenderingType.Notification, Action.ViewRoom],
|
||||
[TimelineRenderingType.ThreadsList, Action.ShowThread],
|
||||
])("type %s dispatches %s", (renderingType, action) => {
|
||||
jest.spyOn(dis, "dispatch");
|
||||
|
||||
const { container } = getComponent({}, renderingType);
|
||||
|
||||
fireEvent.click(container.querySelector("li")!);
|
||||
|
||||
expect(dis.dispatch).toHaveBeenCalledWith(
|
||||
expect.objectContaining({
|
||||
action,
|
||||
}),
|
||||
);
|
||||
});
|
||||
});
|
||||
describe("Event verification", () => {
|
||||
// data for our stubbed getEventEncryptionInfo: a map from event id to result
|
||||
const eventToEncryptionInfoMap = new Map<string, IEncryptedEventInfo>();
|
||||
|
Loading…
Reference in New Issue
Block a user