Merge branch 'develop' into widget_state_no_update_invitation_room

This commit is contained in:
maheichyk 2023-01-16 11:31:08 +03:00 committed by GitHub
commit 53a3f3861e
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
42 changed files with 1970 additions and 2732 deletions

View file

@ -108,7 +108,7 @@ describe("Editing", () => {
// send a load of padding events. We make them large, so that they fill the whole screen
// and the client doesn't end up paginating into the event we want.
let i = 0;
while (i < 20) {
while (i < 10) {
await bob.sendMessage(room.room_id, mkPadding(i++));
}
@ -127,7 +127,7 @@ describe("Editing", () => {
cy.log(`Bot user sent edit event ${editEventId}`);
// ... then a load more padding ...
while (i < 40) {
while (i < 20) {
await bob.sendMessage(room.room_id, mkPadding(i++));
}
});

View file

@ -16,8 +16,6 @@ limitations under the License.
/// <reference types="cypress" />
import { PollResponseEvent } from "matrix-events-sdk";
import { HomeserverInstance } from "../../plugins/utils/homeserver";
import { MatrixClient } from "../../global";
import Chainable = Cypress.Chainable;
@ -70,8 +68,16 @@ describe("Polls", () => {
cy.get('input[type="radio"]')
.invoke("attr", "value")
.then((optionId) => {
const pollVote = PollResponseEvent.from([optionId], pollId).serialize();
bot.sendEvent(roomId, pollVote.type, pollVote.content);
// We can't use the js-sdk types for this stuff directly, so manually construct the event.
bot.sendEvent(roomId, "org.matrix.msc3381.poll.response", {
"m.relates_to": {
rel_type: "m.reference",
event_id: pollId,
},
"org.matrix.msc3381.poll.response": {
answers: [optionId],
},
});
});
});
};

View file

@ -49,6 +49,10 @@ limitations under the License.
mask-image: url("$(res)/img/element-icons/security.svg");
}
.mx_UserSettingsDialog_sessionsIcon::before {
mask-image: url("$(res)/img/element-icons/settings/devices.svg");
}
.mx_UserSettingsDialog_helpIcon::before {
mask-image: url("$(res)/img/element-icons/settings/help.svg");
}

View file

@ -619,6 +619,17 @@ $left-gutter: 64px;
ul ol {
list-style-type: revert;
}
/* Make list type disc to match rich text editor */
> ul {
list-style-type: disc;
}
/* Remove top and bottom margin for better consecutive list display */
> :is(ol, ul) {
margin-top: 0;
margin-bottom: 0;
}
}
}

View file

@ -25,6 +25,7 @@ limitations under the License.
}
.mx_WysiwygComposer_Editor_content {
line-height: $font-22px;
white-space: pre-wrap;
word-wrap: break-word;
outline: none;
@ -35,6 +36,19 @@ limitations under the License.
.caretNode {
user-select: all;
}
ul,
ol {
margin-top: 0;
margin-bottom: 0;
padding-inline-start: $spacing-28;
}
// model output always includes a linebreak but we do not want the user
// to see it when writing input in lists
:is(ol, ul) + br:last-of-type {
display: none;
}
}
.mx_WysiwygComposer_Editor_content_placeholder::before {

View file

@ -0,0 +1,3 @@
<svg width="13" height="10" viewBox="0 0 13 10" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M1.66666 4C1.11332 4 0.666656 4.44667 0.666656 5C0.666656 5.55333 1.11332 6 1.66666 6C2.21999 6 2.66666 5.55333 2.66666 5C2.66666 4.44667 2.21999 4 1.66666 4ZM1.66666 0C1.11332 0 0.666656 0.446667 0.666656 1C0.666656 1.55333 1.11332 2 1.66666 2C2.21999 2 2.66666 1.55333 2.66666 1C2.66666 0.446667 2.21999 0 1.66666 0ZM1.66666 8C1.11332 8 0.666656 8.45333 0.666656 9C0.666656 9.54667 1.11999 10 1.66666 10C2.21332 10 2.66666 9.54667 2.66666 9C2.66666 8.45333 2.21999 8 1.66666 8ZM4.33332 9.66667H12.3333C12.7 9.66667 13 9.36667 13 9C13 8.63333 12.7 8.33333 12.3333 8.33333H4.33332C3.96666 8.33333 3.66666 8.63333 3.66666 9C3.66666 9.36667 3.96666 9.66667 4.33332 9.66667ZM4.33332 5.66667H12.3333C12.7 5.66667 13 5.36667 13 5C13 4.63333 12.7 4.33333 12.3333 4.33333H4.33332C3.96666 4.33333 3.66666 4.63333 3.66666 5C3.66666 5.36667 3.96666 5.66667 4.33332 5.66667ZM3.66666 1C3.66666 1.36667 3.96666 1.66667 4.33332 1.66667H12.3333C12.7 1.66667 13 1.36667 13 1C13 0.633333 12.7 0.333333 12.3333 0.333333H4.33332C3.96666 0.333333 3.66666 0.633333 3.66666 1Z" fill="currentColor"/>
</svg>

After

Width:  |  Height:  |  Size: 1.2 KiB

View file

@ -0,0 +1,3 @@
<svg width="13" height="12" viewBox="0 0 13 12" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M4.33334 2.66663H12.3333C12.7 2.66663 13 2.36663 13 1.99996C13 1.63329 12.7 1.33329 12.3333 1.33329H4.33334C3.96668 1.33329 3.66668 1.63329 3.66668 1.99996C3.66668 2.36663 3.96668 2.66663 4.33334 2.66663ZM12.3333 9.33329H4.33334C3.96668 9.33329 3.66668 9.63329 3.66668 9.99996C3.66668 10.3666 3.96668 10.6666 4.33334 10.6666H12.3333C12.7 10.6666 13 10.3666 13 9.99996C13 9.63329 12.7 9.33329 12.3333 9.33329ZM12.3333 5.33329H4.33334C3.96668 5.33329 3.66668 5.63329 3.66668 5.99996C3.66668 6.36663 3.96668 6.66663 4.33334 6.66663H12.3333C12.7 6.66663 13 6.36663 13 5.99996C13 5.63329 12.7 5.33329 12.3333 5.33329ZM2.00001 8.66663H0.666677C0.48001 8.66663 0.333344 8.81329 0.333344 8.99996C0.333344 9.18663 0.48001 9.33329 0.666677 9.33329H1.66668V9.66663H1.33334C1.14668 9.66663 1.00001 9.81329 1.00001 9.99996C1.00001 10.1866 1.14668 10.3333 1.33334 10.3333H1.66668V10.6666H0.666677C0.48001 10.6666 0.333344 10.8133 0.333344 11C0.333344 11.1866 0.48001 11.3333 0.666677 11.3333H2.00001C2.18668 11.3333 2.33334 11.1866 2.33334 11V8.99996C2.33334 8.81329 2.18668 8.66663 2.00001 8.66663ZM0.666677 1.33329H1.00001V2.99996C1.00001 3.18663 1.14668 3.33329 1.33334 3.33329C1.52001 3.33329 1.66668 3.18663 1.66668 2.99996V0.999959C1.66668 0.813293 1.52001 0.666626 1.33334 0.666626H0.666677C0.48001 0.666626 0.333344 0.813293 0.333344 0.999959C0.333344 1.18663 0.48001 1.33329 0.666677 1.33329ZM2.00001 4.66663H0.666677C0.48001 4.66663 0.333344 4.81329 0.333344 4.99996C0.333344 5.18663 0.48001 5.33329 0.666677 5.33329H1.53334L0.413343 6.63996C0.36001 6.69996 0.333344 6.77996 0.333344 6.85329V6.99996C0.333344 7.18663 0.48001 7.33329 0.666677 7.33329H2.00001C2.18668 7.33329 2.33334 7.18663 2.33334 6.99996C2.33334 6.81329 2.18668 6.66663 2.00001 6.66663H1.13334L2.25334 5.35996C2.30668 5.29996 2.33334 5.21996 2.33334 5.14663V4.99996C2.33334 4.81329 2.18668 4.66663 2.00001 4.66663Z" fill="currentColor"/>
</svg>

After

Width:  |  Height:  |  Size: 2 KiB

View file

@ -0,0 +1,5 @@
<svg width="21" height="19" viewBox="0 0 21 19" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M20 2V7.005L18 7.003V4H2V14H13V16H2C1.45 16 0.979333 15.8043 0.588 15.413C0.196 15.021 0 14.55 0 14V2C0 1.45 0.196 0.979333 0.588 0.588C0.979333 0.196 1.45 0 2 0H18C18.55 0 19.021 0.196 19.413 0.588C19.8043 0.979333 20 1.45 20 2Z" fill="currentColor"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M15 8L20 8.005C20.55 8.005 21 8.45 21 9V18C21 18.55 20.55 19 20
19H15C14.45 19 14 18.55 14 18V9C14 8.45 14.45 8 15 8ZM15 17H20V10H15V17Z" fill="currentColor"/>
</svg>

After

Width:  |  Height:  |  Size: 574 B

View file

@ -20,7 +20,8 @@ import { logger } from "matrix-js-sdk/src/logger";
import { removeDirectionOverrideChars } from "matrix-js-sdk/src/utils";
import { GuestAccess, HistoryVisibility, JoinRule } from "matrix-js-sdk/src/@types/partials";
import { EventType, MsgType } from "matrix-js-sdk/src/@types/event";
import { M_POLL_START, M_POLL_END, PollStartEvent } from "matrix-events-sdk";
import { M_POLL_START, M_POLL_END } from "matrix-js-sdk/src/@types/polls";
import { PollStartEvent } from "matrix-js-sdk/src/extensible_events_v1/PollStartEvent";
import { _t } from "./languageHandler";
import * as Roles from "./Roles";

View file

@ -1,7 +1,6 @@
/*
Copyright 2015, 2016 OpenMarket Ltd
Copyright 2019 Michael Telatynski <7t3chguy@gmail.com>
Copyright 2019 The Matrix.org Foundation C.I.C.
Copyright 2015, 2016, 2019, 2023 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.
@ -77,9 +76,13 @@ export default class ViewSource extends React.Component<IProps, IState> {
<summary>
<span className="mx_ViewSource_heading">{_t("Decrypted event source")}</span>
</summary>
<CopyableText getTextToCopy={copyDecryptedFunc}>
<SyntaxHighlight language="json">{stringify(decryptedEventSource)}</SyntaxHighlight>
</CopyableText>
{decryptedEventSource ? (
<CopyableText getTextToCopy={copyDecryptedFunc}>
<SyntaxHighlight language="json">{stringify(decryptedEventSource)}</SyntaxHighlight>
</CopyableText>
) : (
<div>{_t("Decrypted source unavailable")}</div>
)}
</details>
<details className="mx_ViewSource_details">
<summary>

View file

@ -21,7 +21,7 @@ import { EventStatus, MatrixEvent } from "matrix-js-sdk/src/models/event";
import { EventType, RelationType } from "matrix-js-sdk/src/@types/event";
import { Relations } from "matrix-js-sdk/src/models/relations";
import { RoomMemberEvent } from "matrix-js-sdk/src/models/room-member";
import { M_POLL_START } from "matrix-events-sdk";
import { M_POLL_START } from "matrix-js-sdk/src/@types/polls";
import { Thread } from "matrix-js-sdk/src/models/thread";
import { MatrixClientPeg } from "../../../MatrixClientPeg";

View file

@ -17,7 +17,7 @@ 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 { PollEndEvent } from "matrix-events-sdk";
import { PollEndEvent } from "matrix-js-sdk/src/extensible_events_v1/PollEndEvent";
import { _t } from "../../../languageHandler";
import { IDialogProps } from "./IDialogProps";

View file

@ -164,7 +164,7 @@ export default class UserSettingsDialog extends React.Component<IProps, IState>
new Tab(
UserTab.SessionManager,
_td("Sessions"),
"mx_UserSettingsDialog_securityIcon",
"mx_UserSettingsDialog_sessionsIcon",
<SessionManagerTab />,
// don't track with posthog while under construction
undefined,

View file

@ -17,14 +17,14 @@ limitations under the License.
import React, { ChangeEvent, createRef } from "react";
import { Room } from "matrix-js-sdk/src/models/room";
import {
IPartialEvent,
KNOWN_POLL_KIND,
KnownPollKind,
M_POLL_KIND_DISCLOSED,
M_POLL_KIND_UNDISCLOSED,
M_POLL_START,
PollStartEvent,
} from "matrix-events-sdk";
} from "matrix-js-sdk/src/@types/polls";
import { PollStartEvent } from "matrix-js-sdk/src/extensible_events_v1/PollStartEvent";
import { MatrixEvent } from "matrix-js-sdk/src/models/event";
import { IPartialEvent } from "matrix-js-sdk/src/@types/extensible_events";
import ScrollableBaseModal, { IScrollableBaseState } from "../dialogs/ScrollableBaseModal";
import { IDialogProps } from "../dialogs/IDialogProps";
@ -51,7 +51,7 @@ interface IState extends IScrollableBaseState {
question: string;
options: string[];
busy: boolean;
kind: KNOWN_POLL_KIND;
kind: KnownPollKind;
autoFocusTarget: FocusTarget;
}
@ -263,7 +263,7 @@ export default class PollCreateDialog extends ScrollableBaseModal<IProps, IState
};
}
function pollTypeNotes(kind: KNOWN_POLL_KIND): string {
function pollTypeNotes(kind: KnownPollKind): string {
if (M_POLL_KIND_DISCLOSED.matches(kind.name)) {
return _t("Voters see results as soon as they have voted");
} else {

View file

@ -1,5 +1,6 @@
/*
Copyright 2017 Michael Telatynski <7t3chguy@gmail.com>
Copyright 2023 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.
@ -25,7 +26,7 @@ interface IProps {
export default class SyntaxHighlight extends React.PureComponent<IProps> {
public render(): JSX.Element {
const { children: content, language } = this.props;
const highlighted = language ? hljs.highlight(language, content) : hljs.highlightAuto(content);
const highlighted = language ? hljs.highlight(content, { language }) : hljs.highlightAuto(content);
return (
<pre className={`mx_SyntaxHighlight hljs language-${highlighted.language}`}>

View file

@ -20,17 +20,11 @@ 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";
import {
M_POLL_END,
M_POLL_KIND_DISCLOSED,
M_POLL_RESPONSE,
M_POLL_START,
NamespacedValue,
PollAnswerSubevent,
PollResponseEvent,
PollStartEvent,
} from "matrix-events-sdk";
import { M_POLL_END, M_POLL_KIND_DISCLOSED, M_POLL_RESPONSE, M_POLL_START } from "matrix-js-sdk/src/@types/polls";
import { RelatedRelations } from "matrix-js-sdk/src/models/related-relations";
import { NamespacedValue } from "matrix-events-sdk";
import { PollStartEvent, PollAnswerSubevent } from "matrix-js-sdk/src/extensible_events_v1/PollStartEvent";
import { PollResponseEvent } from "matrix-js-sdk/src/extensible_events_v1/PollResponseEvent";
import { _t } from "../../../languageHandler";
import Modal from "../../../Modal";
@ -454,7 +448,7 @@ export default class MPollBody extends React.Component<IBodyProps, IState> {
return (
<div className="mx_MPollBody">
<h2>
<h2 data-testid="pollQuestion">
{poll.question.text}
{editedSpan}
</h2>
@ -477,7 +471,12 @@ export default class MPollBody extends React.Component<IBodyProps, IState> {
const answerPercent = totalVotes === 0 ? 0 : Math.round((100.0 * answerVotes) / totalVotes);
return (
<div key={answer.id} className={cls} onClick={() => this.selectOption(answer.id)}>
<div
data-testid={`pollOption-${answer.id}`}
key={answer.id}
className={cls}
onClick={() => this.selectOption(answer.id)}
>
{ended ? (
<EndedPollOption answer={answer} checked={checked} votesText={votesText} />
) : (
@ -499,7 +498,9 @@ export default class MPollBody extends React.Component<IBodyProps, IState> {
);
})}
</div>
<div className="mx_MPollBody_totalVotes">{totalText}</div>
<div data-testid="totalVotes" className="mx_MPollBody_totalVotes">
{totalText}
</div>
</div>
);
}

View file

@ -18,7 +18,7 @@ import React, { createRef } from "react";
import { EventType, MsgType } from "matrix-js-sdk/src/@types/event";
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";
import { M_POLL_START } from "matrix-js-sdk/src/@types/polls";
import { MatrixEventEvent } from "matrix-js-sdk/src/models/event";
import SettingsStore from "../../../settings/SettingsStore";

View file

@ -16,7 +16,7 @@ limitations under the License.
import classNames from "classnames";
import { IEventRelation } from "matrix-js-sdk/src/models/event";
import { M_POLL_START } from "matrix-events-sdk";
import { M_POLL_START } from "matrix-js-sdk/src/@types/polls";
import React, { createContext, MouseEventHandler, ReactElement, useContext, useRef } from "react";
import { Room } from "matrix-js-sdk/src/models/room";
import { MatrixClient } from "matrix-js-sdk/src/client";

View file

@ -20,7 +20,7 @@ import { MatrixEvent } from "matrix-js-sdk/src/models/event";
import { Relations } from "matrix-js-sdk/src/models/relations";
import { EventType, RelationType } from "matrix-js-sdk/src/@types/event";
import { logger } from "matrix-js-sdk/src/logger";
import { M_POLL_START, M_POLL_RESPONSE, M_POLL_END } from "matrix-events-sdk";
import { M_POLL_START, M_POLL_RESPONSE, M_POLL_END } from "matrix-js-sdk/src/@types/polls";
import dis from "../../../dispatcher/dispatcher";
import { Action } from "../../../dispatcher/actions";

View file

@ -20,7 +20,7 @@ import React, { CSSProperties, forwardRef, memo, MutableRefObject, ReactNode } f
import { useIsExpanded } from "../hooks/useIsExpanded";
import { useSelection } from "../hooks/useSelection";
const HEIGHT_BREAKING_POINT = 20;
const HEIGHT_BREAKING_POINT = 24;
interface EditorProps {
disabled: boolean;

View file

@ -24,6 +24,8 @@ import { Icon as UnderlineIcon } from "../../../../../../res/img/element-icons/r
import { Icon as StrikeThroughIcon } from "../../../../../../res/img/element-icons/room/composer/strikethrough.svg";
import { Icon as InlineCodeIcon } from "../../../../../../res/img/element-icons/room/composer/inline_code.svg";
import { Icon as LinkIcon } from "../../../../../../res/img/element-icons/room/composer/link.svg";
import { Icon as BulletedListIcon } from "../../../../../../res/img/element-icons/room/composer/bulleted_list.svg";
import { Icon as NumberedListIcon } from "../../../../../../res/img/element-icons/room/composer/numbered_list.svg";
import AccessibleTooltipButton from "../../../elements/AccessibleTooltipButton";
import { Alignment } from "../../../elements/Tooltip";
import { KeyboardShortcut } from "../../../settings/KeyboardShortcut";
@ -109,6 +111,18 @@ export function FormattingButtons({ composer, actionStates }: FormattingButtonsP
onClick={() => composer.strikeThrough()}
icon={<StrikeThroughIcon className="mx_FormattingButtons_Icon" />}
/>
<Button
isActive={actionStates.unorderedList === "reversed"}
label={_td("Bulleted list")}
onClick={() => composer.unorderedList()}
icon={<BulletedListIcon className="mx_FormattingButtons_Icon" />}
/>
<Button
isActive={actionStates.orderedList === "reversed"}
label={_td("Numbered list")}
onClick={() => composer.orderedList()}
icon={<NumberedListIcon className="mx_FormattingButtons_Icon" />}
/>
<Button
isActive={actionStates.inlineCode === "reversed"}
label={_td("Code")}

View file

@ -353,8 +353,6 @@ export default class SecurityUserSettingsTab extends React.Component<IProps, ISt
{PosthogAnalytics.instance.isEnabled() && (
<SettingsFlag name="pseudonymousAnalyticsOptIn" level={SettingLevel.ACCOUNT} />
)}
</div>
<div className="mx_SettingsTab_section">
<span className="mx_SettingsTab_subheading">{_t("Sessions")}</span>
<SettingsFlag name="deviceClientInformationOptIn" level={SettingLevel.ACCOUNT} />
</div>

View file

@ -17,7 +17,8 @@ limitations under the License.
import React from "react";
import { MatrixEvent } from "matrix-js-sdk/src/models/event";
import { EventType, MsgType, RelationType } from "matrix-js-sdk/src/@types/event";
import { M_POLL_START, Optional } from "matrix-events-sdk";
import { Optional } from "matrix-events-sdk";
import { M_POLL_START } from "matrix-js-sdk/src/@types/polls";
import { MatrixClient } from "matrix-js-sdk/src/client";
import { GroupCallIntent } from "matrix-js-sdk/src/webrtc/groupCall";

View file

@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
import { M_POLL_START } from "matrix-events-sdk";
import { M_POLL_START } from "matrix-js-sdk/src/@types/polls";
import { M_BEACON_INFO } from "matrix-js-sdk/src/@types/beacon";
import { MatrixEvent, MatrixClient } from "matrix-js-sdk/src/matrix";

View file

@ -2135,6 +2135,8 @@
"Stop recording": "Stop recording",
"Italic": "Italic",
"Underline": "Underline",
"Bulleted list": "Bulleted list",
"Numbered list": "Numbered list",
"Code": "Code",
"Link": "Link",
"Edit link": "Edit link",
@ -3450,6 +3452,7 @@
"User menu": "User menu",
"Could not load user profile": "Could not load user profile",
"Decrypted event source": "Decrypted event source",
"Decrypted source unavailable": "Decrypted source unavailable",
"Original event source": "Original event source",
"Event ID: %(eventId)s": "Event ID: %(eventId)s",
"Thread root ID: %(threadRootId)s": "Thread root ID: %(threadRootId)s",

View file

@ -17,7 +17,7 @@ limitations under the License.
import { Room } from "matrix-js-sdk/src/models/room";
import { isNullOrUndefined } from "matrix-js-sdk/src/utils";
import { MatrixEvent } from "matrix-js-sdk/src/models/event";
import { M_POLL_START } from "matrix-events-sdk";
import { M_POLL_START } from "matrix-js-sdk/src/@types/polls";
import { ActionPayload } from "../../dispatcher/payloads";
import { AsyncStoreWithClient } from "../AsyncStoreWithClient";

View file

@ -15,7 +15,9 @@ limitations under the License.
*/
import { MatrixEvent } from "matrix-js-sdk/src/models/event";
import { InvalidEventError, M_POLL_START_EVENT_CONTENT, PollStartEvent } from "matrix-events-sdk";
import { PollStartEventContent } from "matrix-js-sdk/src/@types/polls";
import { InvalidEventError } from "matrix-js-sdk/src/extensible_events_v1/InvalidEventError";
import { PollStartEvent } from "matrix-js-sdk/src/extensible_events_v1/PollStartEvent";
import { IPreview } from "./IPreview";
import { TagID } from "../models";
@ -43,7 +45,7 @@ export class PollStartEventPreview implements IPreview {
try {
const poll = new PollStartEvent({
type: event.getType(),
content: eventContent as M_POLL_START_EVENT_CONTENT,
content: eventContent as PollStartEventContent,
});
let question = poll.question.text.trim();

View file

@ -16,7 +16,7 @@ limitations under the License.
import { MatrixEvent } from "matrix-js-sdk/src/models/event";
import { EventType, MsgType } from "matrix-js-sdk/src/@types/event";
import { M_POLL_START } from "matrix-events-sdk";
import { M_POLL_START } from "matrix-js-sdk/src/@types/polls";
import { M_BEACON_INFO } from "matrix-js-sdk/src/@types/beacon";
import { IContent } from "matrix-js-sdk/src/matrix";

View file

@ -18,7 +18,7 @@ import { EventStatus, MatrixEvent } from "matrix-js-sdk/src/models/event";
import { EventType, EVENT_VISIBILITY_CHANGE_TYPE, MsgType, RelationType } from "matrix-js-sdk/src/@types/event";
import { MatrixClient } from "matrix-js-sdk/src/client";
import { logger } from "matrix-js-sdk/src/logger";
import { M_POLL_START } from "matrix-events-sdk";
import { M_POLL_START } from "matrix-js-sdk/src/@types/polls";
import { M_LOCATION } from "matrix-js-sdk/src/@types/location";
import { M_BEACON_INFO } from "matrix-js-sdk/src/@types/beacon";
import { THREAD_RELATION_TYPE } from "matrix-js-sdk/src/models/thread";

View file

@ -16,7 +16,7 @@ limitations under the License.
import { MatrixEvent } from "matrix-js-sdk/src/models/event";
import { EventType } from "matrix-js-sdk/src/@types/event";
import { M_POLL_START } from "matrix-events-sdk";
import { M_POLL_START } from "matrix-js-sdk/src/@types/polls";
export default class PinningUtils {
/**

View file

@ -0,0 +1,59 @@
/*
Copyright 2023 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 { render } from "@testing-library/react";
import { EventType, MatrixEvent } from "matrix-js-sdk/src/matrix";
import React from "react";
import ViewSource from "../../../src/components/structures/ViewSource";
import { mkEvent, stubClient } from "../../test-utils/test-utils";
describe("ThreadView", () => {
const ROOM_ID = "!roomId:example.org";
const SENDER = "@alice:example.org";
let messageEvent: MatrixEvent;
const redactionEvent = mkEvent({
user: SENDER,
event: true,
type: EventType.RoomRedaction,
content: {},
});
beforeEach(() => {
messageEvent = new MatrixEvent({
type: EventType.RoomMessageEncrypted,
room_id: ROOM_ID,
sender: SENDER,
content: {},
state_key: undefined,
});
messageEvent.makeRedacted(redactionEvent);
});
beforeEach(stubClient);
// See https://github.com/vector-im/element-web/issues/24165
it("doesn't error when viewing redacted encrypted messages", () => {
// Sanity checks
expect(messageEvent.isEncrypted()).toBeTruthy();
// @ts-ignore clearEvent is private, but it's being used directly <ViewSource />
expect(messageEvent.clearEvent).toBe(undefined);
expect(() => render(<ViewSource mxEvent={messageEvent} onFinished={() => {}} />)).not.toThrow();
});
});

View file

@ -26,7 +26,8 @@ import {
getBeaconInfoIdentifier,
EventType,
} from "matrix-js-sdk/src/matrix";
import { M_POLL_KIND_DISCLOSED, PollStartEvent } from "matrix-events-sdk";
import { M_POLL_KIND_DISCLOSED } from "matrix-js-sdk/src/@types/polls";
import { PollStartEvent } from "matrix-js-sdk/src/extensible_events_v1/PollStartEvent";
import { FeatureSupport, Thread } from "matrix-js-sdk/src/models/thread";
import { mocked } from "jest-mock";
import { act } from "@testing-library/react";

View file

@ -18,7 +18,7 @@ import React from "react";
import { act } from "react-dom/test-utils";
import { MatrixEvent, EventType } from "matrix-js-sdk/src/matrix";
import { LocationAssetType, M_ASSET, M_LOCATION, M_TIMESTAMP } from "matrix-js-sdk/src/@types/location";
import { TEXT_NODE_TYPE } from "matrix-js-sdk/src/@types/extensible_events";
import { M_TEXT } from "matrix-js-sdk/src/@types/extensible_events";
import { fireEvent, getByTestId, render, RenderResult, screen } from "@testing-library/react";
import userEvent from "@testing-library/user-event";
@ -248,7 +248,7 @@ describe("ForwardDialog", () => {
const expectedStrippedContent = {
...modernLocationEvent.getContent(),
body: text,
[TEXT_NODE_TYPE.name]: text,
[M_TEXT.name]: text,
[M_TIMESTAMP.name]: now,
[M_ASSET.name]: { type: LocationAssetType.Pin },
[M_LOCATION.name]: {
@ -276,7 +276,7 @@ describe("ForwardDialog", () => {
const expectedStrippedContent = {
...modernLocationEvent.getContent(),
body: text,
[TEXT_NODE_TYPE.name]: text,
[M_TEXT.name]: text,
[M_ASSET.name]: { type: LocationAssetType.Pin },
[M_LOCATION.name]: {
uri: geoUri,
@ -297,7 +297,7 @@ describe("ForwardDialog", () => {
const expectedContent = {
msgtype: "m.location",
body: text,
[TEXT_NODE_TYPE.name]: text,
[M_TEXT.name]: text,
[M_ASSET.name]: { type: LocationAssetType.Pin },
[M_LOCATION.name]: {
uri: geoUri,

View file

@ -18,14 +18,10 @@ import React from "react";
// eslint-disable-next-line deprecate/import
import { mount, ReactWrapper } from "enzyme";
import { Room } from "matrix-js-sdk/src/models/room";
import {
M_POLL_KIND_DISCLOSED,
M_POLL_KIND_UNDISCLOSED,
M_POLL_START,
M_TEXT,
PollStartEvent,
} from "matrix-events-sdk";
import { M_POLL_KIND_DISCLOSED, M_POLL_KIND_UNDISCLOSED, M_POLL_START } from "matrix-js-sdk/src/@types/polls";
import { PollStartEvent } from "matrix-js-sdk/src/extensible_events_v1/PollStartEvent";
import { MatrixEvent } from "matrix-js-sdk/src/models/event";
import { M_TEXT } from "matrix-js-sdk/src/@types/extensible_events";
import { findById, getMockClientWithEventEmitter } from "../../../test-utils";
import { MatrixClientPeg } from "../../../../src/MatrixClientPeg";

View file

@ -0,0 +1,38 @@
/* eslint @typescript-eslint/no-unused-vars: ["error", { "varsIgnorePattern": "^_" }] */
/*
Copyright 2023 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 { render } from "@testing-library/react";
import hljs, { type HighlightOptions } from "highlight.js";
import React from "react";
import SyntaxHighlight from "../../../../src/components/views/elements/SyntaxHighlight";
describe("<SyntaxHighlight />", () => {
it("renders", () => {
const { container } = render(<SyntaxHighlight>console.log("Hello, World!");</SyntaxHighlight>);
expect(container).toMatchSnapshot();
});
it.each(["json", "javascript", "css"])("uses the provided language", (lang) => {
const mock = jest.spyOn(hljs, "highlight");
render(<SyntaxHighlight language={lang}>// Hello, World</SyntaxHighlight>);
const [_lang, opts] = mock.mock.lastCall!;
expect((opts as HighlightOptions)["language"]).toBe(lang);
});
});

View file

@ -0,0 +1,30 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`<SyntaxHighlight /> renders 1`] = `
<div>
<pre
class="mx_SyntaxHighlight hljs language-arcade"
>
<code>
<span
class="hljs-built_in"
>
console
</span>
.
<span
class="hljs-built_in"
>
log
</span>
(
<span
class="hljs-string"
>
"Hello, World!"
</span>
);
</code>
</pre>
</div>
`;

File diff suppressed because it is too large Load diff

View file

@ -23,14 +23,10 @@ import { MatrixEvent } from "matrix-js-sdk/src/models/event";
import { EventType, RelationType, MsgType } from "matrix-js-sdk/src/@types/event";
import { RoomStateEvent } from "matrix-js-sdk/src/models/room-state";
import { IEvent, Room, EventTimelineSet, IMinimalEvent } from "matrix-js-sdk/src/matrix";
import {
M_POLL_RESPONSE,
M_POLL_END,
M_POLL_KIND_DISCLOSED,
PollStartEvent,
PollResponseEvent,
PollEndEvent,
} from "matrix-events-sdk";
import { M_POLL_RESPONSE, M_POLL_END, M_POLL_KIND_DISCLOSED } from "matrix-js-sdk/src/@types/polls";
import { PollStartEvent } from "matrix-js-sdk/src/extensible_events_v1/PollStartEvent";
import { PollResponseEvent } from "matrix-js-sdk/src/extensible_events_v1/PollResponseEvent";
import { PollEndEvent } from "matrix-js-sdk/src/extensible_events_v1/PollEndEvent";
import { stubClient, mkStubRoom, mkEvent, mkMessage } from "../../../test-utils";
import { MatrixClientPeg } from "../../../../src/MatrixClientPeg";

View file

@ -17,90 +17,118 @@ limitations under the License.
import React from "react";
import { render, screen } from "@testing-library/react";
import userEvent from "@testing-library/user-event";
import { AllActionStates, FormattingFunctions } from "@matrix-org/matrix-wysiwyg";
import { ActionState, ActionTypes, AllActionStates, FormattingFunctions } from "@matrix-org/matrix-wysiwyg";
import { FormattingButtons } from "../../../../../../src/components/views/rooms/wysiwyg_composer/components/FormattingButtons";
import * as LinkModal from "../../../../../../src/components/views/rooms/wysiwyg_composer/components/LinkModal";
const mockWysiwyg = {
bold: jest.fn(),
italic: jest.fn(),
underline: jest.fn(),
strikeThrough: jest.fn(),
inlineCode: jest.fn(),
link: jest.fn(),
orderedList: jest.fn(),
unorderedList: jest.fn(),
} as unknown as FormattingFunctions;
const openLinkModalSpy = jest.spyOn(LinkModal, "openLinkModal");
const testCases: Record<
Exclude<ActionTypes, "undo" | "redo" | "clear">,
{ label: string; mockFormatFn: jest.Func | jest.SpyInstance }
> = {
bold: { label: "Bold", mockFormatFn: mockWysiwyg.bold },
italic: { label: "Italic", mockFormatFn: mockWysiwyg.italic },
underline: { label: "Underline", mockFormatFn: mockWysiwyg.underline },
strikeThrough: { label: "Strikethrough", mockFormatFn: mockWysiwyg.strikeThrough },
inlineCode: { label: "Code", mockFormatFn: mockWysiwyg.inlineCode },
link: { label: "Link", mockFormatFn: openLinkModalSpy },
orderedList: { label: "Numbered list", mockFormatFn: mockWysiwyg.orderedList },
unorderedList: { label: "Bulleted list", mockFormatFn: mockWysiwyg.unorderedList },
};
const createActionStates = (state: ActionState): AllActionStates => {
return Object.fromEntries(Object.keys(testCases).map((testKey) => [testKey, state])) as AllActionStates;
};
const defaultActionStates = createActionStates("enabled");
const renderComponent = (props = {}) => {
return render(<FormattingButtons composer={mockWysiwyg} actionStates={defaultActionStates} {...props} />);
};
const classes = {
active: "mx_FormattingButtons_active",
hover: "mx_FormattingButtons_Button_hover",
};
describe("FormattingButtons", () => {
const wysiwyg = {
bold: jest.fn(),
italic: jest.fn(),
underline: jest.fn(),
strikeThrough: jest.fn(),
inlineCode: jest.fn(),
link: jest.fn(),
} as unknown as FormattingFunctions;
const actionStates = {
bold: "reversed",
italic: "reversed",
underline: "enabled",
strikeThrough: "enabled",
inlineCode: "enabled",
link: "enabled",
} as AllActionStates;
afterEach(() => {
jest.resetAllMocks();
});
it("Should have the correspond CSS classes", () => {
// When
render(<FormattingButtons composer={wysiwyg} actionStates={actionStates} />);
it("Each button should not have active class when enabled", () => {
renderComponent();
// Then
expect(screen.getByLabelText("Bold")).toHaveClass("mx_FormattingButtons_active");
expect(screen.getByLabelText("Italic")).toHaveClass("mx_FormattingButtons_active");
expect(screen.getByLabelText("Underline")).not.toHaveClass("mx_FormattingButtons_active");
expect(screen.getByLabelText("Strikethrough")).not.toHaveClass("mx_FormattingButtons_active");
expect(screen.getByLabelText("Code")).not.toHaveClass("mx_FormattingButtons_active");
expect(screen.getByLabelText("Link")).not.toHaveClass("mx_FormattingButtons_active");
Object.values(testCases).forEach(({ label }) => {
expect(screen.getByLabelText(label)).not.toHaveClass(classes.active);
});
});
it("Should call wysiwyg function on button click", () => {
// When
const spy = jest.spyOn(LinkModal, "openLinkModal");
render(<FormattingButtons composer={wysiwyg} actionStates={actionStates} />);
screen.getByLabelText("Bold").click();
screen.getByLabelText("Italic").click();
screen.getByLabelText("Underline").click();
screen.getByLabelText("Strikethrough").click();
screen.getByLabelText("Code").click();
screen.getByLabelText("Link").click();
it("Each button should have active class when reversed", () => {
const reversedActionStates = createActionStates("reversed");
renderComponent({ actionStates: reversedActionStates });
// Then
expect(wysiwyg.bold).toHaveBeenCalledTimes(1);
expect(wysiwyg.italic).toHaveBeenCalledTimes(1);
expect(wysiwyg.underline).toHaveBeenCalledTimes(1);
expect(wysiwyg.strikeThrough).toHaveBeenCalledTimes(1);
expect(wysiwyg.inlineCode).toHaveBeenCalledTimes(1);
expect(spy).toHaveBeenCalledTimes(1);
Object.values(testCases).forEach((testCase) => {
const { label } = testCase;
expect(screen.getByLabelText(label)).toHaveClass(classes.active);
});
});
it("Should display the tooltip on mouse over", async () => {
// When
const user = userEvent.setup();
render(<FormattingButtons composer={wysiwyg} actionStates={actionStates} />);
await user.hover(screen.getByLabelText("Bold"));
it("Should call wysiwyg function on button click", async () => {
renderComponent();
// Then
expect(await screen.findByText("Bold")).toBeTruthy();
for (const testCase of Object.values(testCases)) {
const { label, mockFormatFn } = testCase;
screen.getByLabelText(label).click();
expect(mockFormatFn).toHaveBeenCalledTimes(1);
}
});
it("Should not have hover style when active", async () => {
// When
const user = userEvent.setup();
render(<FormattingButtons composer={wysiwyg} actionStates={actionStates} />);
await user.hover(screen.getByLabelText("Bold"));
it("Each button should display the tooltip on mouse over", async () => {
renderComponent();
// Then
expect(screen.getByLabelText("Bold")).not.toHaveClass("mx_FormattingButtons_Button_hover");
for (const testCase of Object.values(testCases)) {
const { label } = testCase;
// When
await user.hover(screen.getByLabelText("Underline"));
await userEvent.hover(screen.getByLabelText(label));
expect(await screen.findByText(label)).toBeTruthy();
}
});
// Then
expect(screen.getByLabelText("Underline")).toHaveClass("mx_FormattingButtons_Button_hover");
it("Each button should have hover style when hovered and enabled", async () => {
renderComponent();
for (const testCase of Object.values(testCases)) {
const { label } = testCase;
await userEvent.hover(screen.getByLabelText(label));
expect(screen.getByLabelText(label)).toHaveClass("mx_FormattingButtons_Button_hover");
}
});
it("Each button should not have hover style when hovered and reversed", async () => {
const reversedActionStates = createActionStates("reversed");
renderComponent({ actionStates: reversedActionStates });
for (const testCase of Object.values(testCases)) {
const { label } = testCase;
await userEvent.hover(screen.getByLabelText(label));
expect(screen.getByLabelText(label)).not.toHaveClass("mx_FormattingButtons_Button_hover");
}
});
});

View file

@ -15,9 +15,10 @@ limitations under the License.
*/
import { MatrixEvent } from "matrix-js-sdk/src/matrix";
import { M_TEXT, M_POLL_START, POLL_ANSWER, M_POLL_KIND_DISCLOSED } from "matrix-events-sdk";
import { M_POLL_START, PollAnswer, M_POLL_KIND_DISCLOSED } from "matrix-js-sdk/src/@types/polls";
import { M_TEXT } from "matrix-js-sdk/src/@types/extensible_events";
export const makePollStartEvent = (question: string, sender: string, answers?: POLL_ANSWER[]): MatrixEvent => {
export const makePollStartEvent = (question: string, sender: string, answers?: PollAnswer[]): MatrixEvent => {
if (!answers) {
answers = [
{ id: "socks", [M_TEXT.name]: "Socks" },

View file

@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
import { TEXT_NODE_TYPE } from "matrix-js-sdk/src/@types/extensible_events";
import { M_TEXT } from "matrix-js-sdk/src/@types/extensible_events";
import {
ILocationContent,
LocationAssetType,
@ -38,7 +38,7 @@ describe("isSelfLocation", () => {
msgtype: "m.location",
geo_uri: "",
[M_LOCATION.name]: { uri: "" },
[TEXT_NODE_TYPE.name]: "",
[M_TEXT.name]: "",
[M_TIMESTAMP.name]: 0,
// Note: no m.asset!
};
@ -51,7 +51,7 @@ describe("isSelfLocation", () => {
msgtype: "m.location",
geo_uri: "",
[M_LOCATION.name]: { uri: "" },
[TEXT_NODE_TYPE.name]: "",
[M_TEXT.name]: "",
[M_TIMESTAMP.name]: 0,
[M_ASSET.name]: {
// Note: no type!