Merge branch 'develop' into gsouquet/benchmark-tracking
This commit is contained in:
commit
7310d35d7f
24 changed files with 314 additions and 208 deletions
|
@ -55,7 +55,6 @@
|
|||
"dependencies": {
|
||||
"@babel/runtime": "^7.12.5",
|
||||
"await-lock": "^2.1.0",
|
||||
"blueimp-canvas-to-blob": "^3.28.0",
|
||||
"browser-encrypt-attachment": "^0.3.0",
|
||||
"browser-request": "^0.3.3",
|
||||
"cheerio": "^1.0.0-rc.9",
|
||||
|
@ -88,7 +87,6 @@
|
|||
"png-chunks-extract": "^1.0.0",
|
||||
"prop-types": "^15.7.2",
|
||||
"qrcode": "^1.4.4",
|
||||
"qs": "^6.9.6",
|
||||
"re-resizable": "^6.9.0",
|
||||
"react": "^17.0.2",
|
||||
"react-beautiful-dnd": "^4.0.1",
|
||||
|
@ -99,7 +97,6 @@
|
|||
"rfc4648": "^1.4.0",
|
||||
"sanitize-html": "^2.3.2",
|
||||
"tar-js": "^0.3.0",
|
||||
"text-encoding-utf-8": "^1.0.2",
|
||||
"url": "^0.11.0",
|
||||
"what-input": "^5.2.10",
|
||||
"zxcvbn": "^4.4.2"
|
||||
|
|
|
@ -328,7 +328,8 @@ $SpaceRoomViewInnerWidth: 428px;
|
|||
font-size: $font-15px;
|
||||
margin-top: 12px;
|
||||
margin-bottom: 16px;
|
||||
white-space: pre;
|
||||
white-space: pre-wrap;
|
||||
word-wrap: break-word;
|
||||
}
|
||||
|
||||
> hr {
|
||||
|
|
|
@ -17,6 +17,9 @@ limitations under the License.
|
|||
.mx_InviteDialog_addressBar {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
// Right margin for the design. We could apply this to the whole dialog, but then the scrollbar
|
||||
// for the user section gets weird.
|
||||
margin: 8px 45px 0 0;
|
||||
|
||||
.mx_InviteDialog_editor {
|
||||
flex: 1;
|
||||
|
@ -73,7 +76,7 @@ limitations under the License.
|
|||
}
|
||||
|
||||
.mx_InviteDialog_section {
|
||||
padding-bottom: 10px;
|
||||
padding-bottom: 4px;
|
||||
|
||||
h3 {
|
||||
font-size: $font-12px;
|
||||
|
@ -82,6 +85,14 @@ limitations under the License.
|
|||
text-transform: uppercase;
|
||||
}
|
||||
|
||||
> p {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
> span {
|
||||
color: $primary-fg-color;
|
||||
}
|
||||
|
||||
.mx_InviteDialog_subname {
|
||||
margin-bottom: 10px;
|
||||
margin-top: -10px; // HACK: Positioning with margins is bad
|
||||
|
@ -90,6 +101,63 @@ limitations under the License.
|
|||
}
|
||||
}
|
||||
|
||||
.mx_InviteDialog_section_hidden_suggestions_disclaimer {
|
||||
padding: 8px 0 16px 0;
|
||||
font-size: $font-14px;
|
||||
|
||||
> span {
|
||||
color: $primary-fg-color;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
> p {
|
||||
margin: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.mx_InviteDialog_footer {
|
||||
border-top: 1px solid $input-border-color;
|
||||
|
||||
> h3 {
|
||||
margin: 12px 0;
|
||||
font-size: $font-12px;
|
||||
color: $muted-fg-color;
|
||||
font-weight: bold;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
|
||||
.mx_InviteDialog_footer_link {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
border-radius: 4px;
|
||||
border: solid 1px $light-fg-color;
|
||||
padding: 8px;
|
||||
|
||||
> a {
|
||||
text-decoration: none;
|
||||
flex-shrink: 1;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
}
|
||||
|
||||
.mx_InviteDialog_footer_link_copy {
|
||||
flex-shrink: 0;
|
||||
cursor: pointer;
|
||||
margin-left: 20px;
|
||||
display: inherit;
|
||||
|
||||
> div {
|
||||
mask-image: url($copy-button-url);
|
||||
background-color: $message-action-bar-fg-color;
|
||||
margin-left: 5px;
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
background-repeat: no-repeat;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.mx_InviteDialog_roomTile {
|
||||
cursor: pointer;
|
||||
padding: 5px 10px;
|
||||
|
@ -142,6 +210,7 @@ limitations under the License.
|
|||
|
||||
.mx_InviteDialog_roomTile_nameStack {
|
||||
display: inline-block;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.mx_InviteDialog_roomTile_name {
|
||||
|
@ -157,6 +226,13 @@ limitations under the License.
|
|||
margin-left: 7px;
|
||||
}
|
||||
|
||||
.mx_InviteDialog_roomTile_name,
|
||||
.mx_InviteDialog_roomTile_userId {
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.mx_InviteDialog_roomTile_time {
|
||||
text-align: right;
|
||||
font-size: $font-12px;
|
||||
|
@ -212,22 +288,29 @@ limitations under the License.
|
|||
|
||||
.mx_InviteDialog {
|
||||
// Prevent the dialog from jumping around randomly when elements change.
|
||||
height: 590px;
|
||||
height: 600px;
|
||||
padding-left: 20px; // the design wants some padding on the left
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
.mx_InviteDialog_content {
|
||||
overflow: hidden;
|
||||
}
|
||||
}
|
||||
|
||||
.mx_InviteDialog_userSections {
|
||||
margin-top: 10px;
|
||||
margin-top: 4px;
|
||||
overflow-y: auto;
|
||||
padding-right: 45px;
|
||||
height: 455px; // mx_InviteDialog's height minus some for the upper elements
|
||||
padding: 0 45px 4px 0;
|
||||
height: calc(100% - 115px); // mx_InviteDialog's height minus some for the upper and lower elements
|
||||
}
|
||||
|
||||
// Right margin for the design. We could apply this to the whole dialog, but then the scrollbar
|
||||
// for the user section gets weird.
|
||||
.mx_InviteDialog_helpText,
|
||||
.mx_InviteDialog_addressBar {
|
||||
margin-right: 45px;
|
||||
.mx_InviteDialog_hasFooter .mx_InviteDialog_userSections {
|
||||
height: calc(100% - 175px);
|
||||
}
|
||||
|
||||
.mx_InviteDialog_helpText {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.mx_InviteDialog_helpText .mx_AccessibleButton_kind_link {
|
||||
|
|
|
@ -14,7 +14,13 @@ See the License for the specific language governing permissions and
|
|||
limitations under the License.
|
||||
*/
|
||||
|
||||
.mx_SenderProfile_name {
|
||||
.mx_SenderProfile_displayName {
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.mx_SenderProfile_mxid {
|
||||
font-weight: 600;
|
||||
font-size: 1.1rem;
|
||||
margin-left: 5px;
|
||||
opacity: 0.5; // Match mx_TextualEvent
|
||||
}
|
||||
|
|
|
@ -178,7 +178,7 @@ $irc-line-height: $font-18px;
|
|||
overflow: hidden;
|
||||
display: flex;
|
||||
|
||||
> .mx_SenderProfile_name {
|
||||
> .mx_SenderProfile_displayName {
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
min-width: var(--name-width);
|
||||
|
@ -207,7 +207,7 @@ $irc-line-height: $font-18px;
|
|||
background: transparent;
|
||||
|
||||
> span {
|
||||
> .mx_SenderProfile_name {
|
||||
> .mx_SenderProfile_displayName {
|
||||
min-width: inherit;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -28,8 +28,6 @@ import encrypt from "browser-encrypt-attachment";
|
|||
import extractPngChunks from "png-chunks-extract";
|
||||
import Spinner from "./components/views/elements/Spinner";
|
||||
|
||||
// Polyfill for Canvas.toBlob API using Canvas.toDataURL
|
||||
import "blueimp-canvas-to-blob";
|
||||
import { Action } from "./dispatcher/actions";
|
||||
import CountlyAnalytics from "./CountlyAnalytics";
|
||||
import {
|
||||
|
|
|
@ -24,13 +24,6 @@ import {sleep} from "./utils/promise";
|
|||
import RoomViewStore from "./stores/RoomViewStore";
|
||||
import { Action } from "./dispatcher/actions";
|
||||
|
||||
// polyfill textencoder if necessary
|
||||
import * as TextEncodingUtf8 from 'text-encoding-utf-8';
|
||||
let TextEncoder = window.TextEncoder;
|
||||
if (!TextEncoder) {
|
||||
TextEncoder = TextEncodingUtf8.TextEncoder;
|
||||
}
|
||||
|
||||
const INACTIVITY_TIME = 20; // seconds
|
||||
const HEARTBEAT_INTERVAL = 5_000; // ms
|
||||
const SESSION_UPDATE_INTERVAL = 60; // seconds
|
||||
|
|
|
@ -520,6 +520,7 @@ export const SpaceHierarchy: React.FC<IHierarchyProps> = ({
|
|||
setError("Failed to update some suggestions. Try again later");
|
||||
}
|
||||
setSaving(false);
|
||||
setSelected(new Map());
|
||||
}}
|
||||
kind="primary_outline"
|
||||
disabled={disabled}
|
||||
|
|
|
@ -28,7 +28,7 @@ import RoomTopic from "../views/elements/RoomTopic";
|
|||
import InlineSpinner from "../views/elements/InlineSpinner";
|
||||
import {inviteMultipleToRoom, showRoomInviteDialog} from "../../RoomInvite";
|
||||
import {useRoomMembers} from "../../hooks/useRoomMembers";
|
||||
import createRoom, {IOpts, Preset} from "../../createRoom";
|
||||
import createRoom, {IOpts} from "../../createRoom";
|
||||
import Field from "../views/elements/Field";
|
||||
import {useEventEmitter} from "../../hooks/useEventEmitter";
|
||||
import withValidation from "../views/elements/Validation";
|
||||
|
@ -65,6 +65,7 @@ import dis from "../../dispatcher/dispatcher";
|
|||
import Modal from "../../Modal";
|
||||
import BetaFeedbackDialog from "../views/dialogs/BetaFeedbackDialog";
|
||||
import SdkConfig from "../../SdkConfig";
|
||||
import { Preset } from "matrix-js-sdk/src/@types/partials";
|
||||
|
||||
interface IProps {
|
||||
space: Room;
|
||||
|
|
|
@ -23,7 +23,7 @@ import withValidation, {IFieldState} from '../elements/Validation';
|
|||
import { _t } from '../../../languageHandler';
|
||||
import { MatrixClientPeg } from '../../../MatrixClientPeg';
|
||||
import { Key } from "../../../Keyboard";
|
||||
import {IOpts, Preset, privateShouldBeEncrypted, Visibility} from "../../../createRoom";
|
||||
import { IOpts, privateShouldBeEncrypted } from "../../../createRoom";
|
||||
import { CommunityPrototypeStore } from "../../../stores/CommunityPrototypeStore";
|
||||
import { replaceableComponent } from "../../../utils/replaceableComponent";
|
||||
import Field from "../elements/Field";
|
||||
|
@ -31,6 +31,7 @@ import RoomAliasField from "../elements/RoomAliasField";
|
|||
import LabelledToggleSwitch from "../elements/LabelledToggleSwitch";
|
||||
import DialogButtons from "../elements/DialogButtons";
|
||||
import BaseDialog from "../dialogs/BaseDialog";
|
||||
import { Preset, Visibility } from "matrix-js-sdk/src/@types/partials";
|
||||
|
||||
interface IProps {
|
||||
defaultPublic?: boolean;
|
||||
|
@ -72,7 +73,7 @@ export default class CreateRoomDialog extends React.Component<IProps, IState> {
|
|||
canChangeEncryption: true,
|
||||
};
|
||||
|
||||
MatrixClientPeg.get().doesServerForceEncryptionForPreset("private")
|
||||
MatrixClientPeg.get().doesServerForceEncryptionForPreset(Preset.PrivateChat)
|
||||
.then(isForced => this.setState({ canChangeEncryption: !isForced }));
|
||||
}
|
||||
|
||||
|
|
|
@ -15,6 +15,8 @@ limitations under the License.
|
|||
*/
|
||||
|
||||
import React, { createRef } from 'react';
|
||||
import classNames from 'classnames';
|
||||
|
||||
import {_t, _td} from "../../../languageHandler";
|
||||
import * as sdk from "../../../index";
|
||||
import {MatrixClientPeg} from "../../../MatrixClientPeg";
|
||||
|
@ -31,7 +33,6 @@ import Modal from "../../../Modal";
|
|||
import {humanizeTime} from "../../../utils/humanize";
|
||||
import createRoom, {
|
||||
canEncryptToAllUsers, ensureDMExists, findDMForUser, privateShouldBeEncrypted,
|
||||
IInvite3PID,
|
||||
} from "../../../createRoom";
|
||||
import {inviteMultipleToRoom, showCommunityInviteDialog} from "../../../RoomInvite";
|
||||
import {Key} from "../../../Keyboard";
|
||||
|
@ -50,6 +51,12 @@ import {getAddressType} from "../../../UserAddress";
|
|||
import BaseAvatar from '../avatars/BaseAvatar';
|
||||
import AccessibleButton from '../elements/AccessibleButton';
|
||||
import { compare } from '../../../utils/strings';
|
||||
import { IInvite3PID } from "matrix-js-sdk/src/@types/requests";
|
||||
import AccessibleTooltipButton from "../elements/AccessibleTooltipButton";
|
||||
import { copyPlaintext, selectText } from "../../../utils/strings";
|
||||
import * as ContextMenu from "../../structures/ContextMenu";
|
||||
import { toRightOf } from "../../structures/ContextMenu";
|
||||
import GenericTextContextMenu from "../context_menus/GenericTextContextMenu";
|
||||
|
||||
// we have a number of types defined from the Matrix spec which can't reasonably be altered here.
|
||||
/* eslint-disable camelcase */
|
||||
|
@ -351,6 +358,7 @@ export default class InviteDialog extends React.PureComponent<IInviteDialogProps
|
|||
initialText: "",
|
||||
};
|
||||
|
||||
private closeCopiedTooltip: () => void;
|
||||
private debounceTimer: NodeJS.Timeout = null; // actually number because we're in the browser
|
||||
private editorRef = createRef<HTMLInputElement>();
|
||||
private unmounted = false;
|
||||
|
@ -403,6 +411,9 @@ export default class InviteDialog extends React.PureComponent<IInviteDialogProps
|
|||
|
||||
componentWillUnmount() {
|
||||
this.unmounted = true;
|
||||
// if the Copied tooltip is open then get rid of it, there are ways to close the modal which wouldn't close
|
||||
// the tooltip otherwise, such as pressing Escape or clicking X really quickly
|
||||
if (this.closeCopiedTooltip) this.closeCopiedTooltip();
|
||||
}
|
||||
|
||||
private onConsultFirstChange = (ev) => {
|
||||
|
@ -1238,6 +1249,25 @@ export default class InviteDialog extends React.PureComponent<IInviteDialogProps
|
|||
}
|
||||
}
|
||||
|
||||
private async onLinkClick(e) {
|
||||
e.preventDefault();
|
||||
selectText(e.target);
|
||||
}
|
||||
|
||||
private onCopyClick = async e => {
|
||||
e.preventDefault();
|
||||
const target = e.target; // copy target before we go async and React throws it away
|
||||
|
||||
const successful = await copyPlaintext(makeUserPermalink(MatrixClientPeg.get().getUserId()));
|
||||
const buttonRect = target.getBoundingClientRect();
|
||||
const { close } = ContextMenu.createMenu(GenericTextContextMenu, {
|
||||
...toRightOf(buttonRect, 2),
|
||||
message: successful ? _t("Copied!") : _t("Failed to copy"),
|
||||
});
|
||||
// Drop a reference to this close handler for componentWillUnmount
|
||||
this.closeCopiedTooltip = target.onmouseleave = close;
|
||||
};
|
||||
|
||||
render() {
|
||||
const BaseDialog = sdk.getComponent('views.dialogs.BaseDialog');
|
||||
const AccessibleButton = sdk.getComponent("elements.AccessibleButton");
|
||||
|
@ -1248,12 +1278,12 @@ export default class InviteDialog extends React.PureComponent<IInviteDialogProps
|
|||
spinner = <Spinner w={20} h={20} />;
|
||||
}
|
||||
|
||||
|
||||
let title;
|
||||
let helpText;
|
||||
let buttonText;
|
||||
let goButtonFn;
|
||||
let consultSection;
|
||||
let extraSection;
|
||||
let footer;
|
||||
let keySharingWarning = <span />;
|
||||
|
||||
const identityServersEnabled = SettingsStore.getValue(UIFeature.IdentityServer);
|
||||
|
@ -1316,6 +1346,26 @@ export default class InviteDialog extends React.PureComponent<IInviteDialogProps
|
|||
}
|
||||
buttonText = _t("Go");
|
||||
goButtonFn = this.startDm;
|
||||
extraSection = <div className="mx_InviteDialog_section_hidden_suggestions_disclaimer">
|
||||
<span>{ _t("Some suggestions may be hidden for privacy.") }</span>
|
||||
<p>{ _t("If you can't see who you’re looking for, send them your invite link below.") }</p>
|
||||
</div>;
|
||||
const link = makeUserPermalink(MatrixClientPeg.get().getUserId());
|
||||
footer = <div className="mx_InviteDialog_footer">
|
||||
<h3>{ _t("Or send invite link") }</h3>
|
||||
<div className="mx_InviteDialog_footer_link">
|
||||
<a href={link} onClick={this.onLinkClick}>
|
||||
{ link }
|
||||
</a>
|
||||
<AccessibleTooltipButton
|
||||
title={_t("Copy")}
|
||||
onClick={this.onCopyClick}
|
||||
className="mx_InviteDialog_footer_link_copy"
|
||||
>
|
||||
<div />
|
||||
</AccessibleTooltipButton>
|
||||
</div>
|
||||
</div>
|
||||
} else if (this.props.kind === KIND_INVITE) {
|
||||
const room = MatrixClientPeg.get()?.getRoom(this.props.roomId);
|
||||
const isSpace = SettingsStore.getValue("feature_spaces") && room?.isSpaceRoom();
|
||||
|
@ -1377,7 +1427,7 @@ export default class InviteDialog extends React.PureComponent<IInviteDialogProps
|
|||
title = _t("Transfer");
|
||||
buttonText = _t("Transfer");
|
||||
goButtonFn = this.transferCall;
|
||||
consultSection = <div>
|
||||
footer = <div>
|
||||
<label>
|
||||
<input type="checkbox" checked={this.state.consultFirst} onChange={this.onConsultFirstChange} />
|
||||
{_t("Consult first")}
|
||||
|
@ -1391,7 +1441,9 @@ export default class InviteDialog extends React.PureComponent<IInviteDialogProps
|
|||
|| (this.state.filterText && this.state.filterText.includes('@'));
|
||||
return (
|
||||
<BaseDialog
|
||||
className='mx_InviteDialog'
|
||||
className={classNames("mx_InviteDialog", {
|
||||
mx_InviteDialog_hasFooter: !!footer,
|
||||
})}
|
||||
hasCancel={true}
|
||||
onFinished={this.props.onFinished}
|
||||
title={title}
|
||||
|
@ -1418,8 +1470,9 @@ export default class InviteDialog extends React.PureComponent<IInviteDialogProps
|
|||
<div className='mx_InviteDialog_userSections'>
|
||||
{this.renderSection('recents')}
|
||||
{this.renderSection('suggestions')}
|
||||
{extraSection}
|
||||
</div>
|
||||
{consultSection}
|
||||
{footer}
|
||||
</div>
|
||||
</BaseDialog>
|
||||
);
|
||||
|
|
|
@ -128,6 +128,7 @@ export default class EventTilePreview extends React.Component<IProps, IState> {
|
|||
mxEvent={event}
|
||||
layout={this.props.layout}
|
||||
enableFlair={SettingsStore.getValue(UIFeature.Flair)}
|
||||
as="div"
|
||||
/>
|
||||
</div>;
|
||||
}
|
||||
|
|
|
@ -15,24 +15,31 @@
|
|||
*/
|
||||
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import Flair from '../elements/Flair.js';
|
||||
import FlairStore from '../../../stores/FlairStore';
|
||||
import {getUserNameColorClass} from '../../../utils/FormattingUtils';
|
||||
import MatrixClientContext from "../../../contexts/MatrixClientContext";
|
||||
import {replaceableComponent} from "../../../utils/replaceableComponent";
|
||||
import MatrixEvent from "matrix-js-sdk/src/models/event";
|
||||
|
||||
interface IProps {
|
||||
mxEvent: MatrixEvent;
|
||||
onClick(): void;
|
||||
enableFlair: boolean;
|
||||
}
|
||||
|
||||
interface IState {
|
||||
userGroups;
|
||||
relatedGroups;
|
||||
}
|
||||
|
||||
@replaceableComponent("views.messages.SenderProfile")
|
||||
export default class SenderProfile extends React.Component {
|
||||
static propTypes = {
|
||||
mxEvent: PropTypes.object.isRequired, // event whose sender we're showing
|
||||
onClick: PropTypes.func,
|
||||
};
|
||||
|
||||
export default class SenderProfile extends React.Component<IProps, IState> {
|
||||
static contextType = MatrixClientContext;
|
||||
private unmounted: boolean;
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
constructor(props: IProps) {
|
||||
super(props)
|
||||
const senderId = this.props.mxEvent.getSender();
|
||||
|
||||
this.state = {
|
||||
|
@ -40,6 +47,7 @@ export default class SenderProfile extends React.Component {
|
|||
relatedGroups: [],
|
||||
};
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
this.unmounted = false;
|
||||
this._updateRelatedGroups();
|
||||
|
@ -100,14 +108,26 @@ export default class SenderProfile extends React.Component {
|
|||
render() {
|
||||
const {mxEvent} = this.props;
|
||||
const colorClass = getUserNameColorClass(mxEvent.getSender());
|
||||
const name = mxEvent.sender ? mxEvent.sender.name : mxEvent.getSender();
|
||||
const {msgtype} = mxEvent.getContent();
|
||||
|
||||
const disambiguate = mxEvent.sender?.disambiguate;
|
||||
const displayName = mxEvent.sender?.rawDisplayName || mxEvent.getSender() || "";
|
||||
const mxid = mxEvent.sender?.userId || mxEvent.getSender() || "";
|
||||
|
||||
if (msgtype === 'm.emote') {
|
||||
return null; // emote message must include the name so don't duplicate it
|
||||
}
|
||||
|
||||
let flair = null;
|
||||
let mxidElement;
|
||||
if (disambiguate) {
|
||||
mxidElement = (
|
||||
<span className="mx_SenderProfile_mxid">
|
||||
{ mxid }
|
||||
</span>
|
||||
);
|
||||
}
|
||||
|
||||
let flair;
|
||||
if (this.props.enableFlair) {
|
||||
const displayedGroups = this._getDisplayedGroups(
|
||||
this.state.userGroups, this.state.relatedGroups,
|
||||
|
@ -119,13 +139,12 @@ export default class SenderProfile extends React.Component {
|
|||
/>;
|
||||
}
|
||||
|
||||
const nameElem = name || '';
|
||||
|
||||
return (
|
||||
<div className="mx_SenderProfile mx_SenderProfile_hover" dir="auto" onClick={this.props.onClick}>
|
||||
<span className={`mx_SenderProfile_name ${colorClass}`}>
|
||||
{ nameElem }
|
||||
<span className={`mx_SenderProfile_displayName ${colorClass}`}>
|
||||
{ displayName }
|
||||
</span>
|
||||
{ mxidElement }
|
||||
{ flair }
|
||||
</div>
|
||||
);
|
|
@ -1059,22 +1059,26 @@ export default class EventTile extends React.Component<IProps, IState> {
|
|||
switch (this.props.tileShape) {
|
||||
case 'notif': {
|
||||
const room = this.context.getRoom(this.props.mxEvent.getRoomId());
|
||||
return (
|
||||
<li className={classes} aria-live={ariaLive} aria-atomic="true" data-scroll-tokens={scrollToken}>
|
||||
<div className="mx_EventTile_roomName">
|
||||
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">
|
||||
</div>,
|
||||
<div className="mx_EventTile_senderDetails" key="mx_EventTile_senderDetails">
|
||||
{ avatar }
|
||||
<a href={permalink} onClick={this.onPermalinkClicked}>
|
||||
{ sender }
|
||||
{ timestamp }
|
||||
</a>
|
||||
</div>
|
||||
<div className="mx_EventTile_line">
|
||||
</div>,
|
||||
<div className="mx_EventTile_line" key="mx_EventTile_line">
|
||||
<EventTileType ref={this.tile}
|
||||
mxEvent={this.props.mxEvent}
|
||||
highlights={this.props.highlights}
|
||||
|
@ -1082,14 +1086,17 @@ export default class EventTile extends React.Component<IProps, IState> {
|
|||
showUrlPreview={this.props.showUrlPreview}
|
||||
onHeightChanged={this.props.onHeightChanged}
|
||||
/>
|
||||
</div>
|
||||
</li>
|
||||
);
|
||||
</div>,
|
||||
]);
|
||||
}
|
||||
case 'file_grid': {
|
||||
return (
|
||||
<li className={classes} aria-live={ariaLive} aria-atomic="true" data-scroll-tokens={scrollToken}>
|
||||
<div className="mx_EventTile_line">
|
||||
return React.createElement(this.props.as || "li", {
|
||||
"className": classes,
|
||||
"aria-live": ariaLive,
|
||||
"aria-atomic": true,
|
||||
"data-scroll-tokens": scrollToken,
|
||||
}, [
|
||||
<div className="mx_EventTile_line" key="mx_EventTile_line">
|
||||
<EventTileType ref={this.tile}
|
||||
mxEvent={this.props.mxEvent}
|
||||
highlights={this.props.highlights}
|
||||
|
@ -1098,9 +1105,10 @@ export default class EventTile extends React.Component<IProps, IState> {
|
|||
tileShape={this.props.tileShape}
|
||||
onHeightChanged={this.props.onHeightChanged}
|
||||
/>
|
||||
</div>
|
||||
</div>,
|
||||
<a
|
||||
className="mx_EventTile_senderDetailsLink"
|
||||
key="mx_EventTile_senderDetailsLink"
|
||||
href={permalink}
|
||||
onClick={this.onPermalinkClicked}
|
||||
>
|
||||
|
@ -1108,9 +1116,8 @@ export default class EventTile extends React.Component<IProps, IState> {
|
|||
{ sender }
|
||||
{ timestamp }
|
||||
</div>
|
||||
</a>
|
||||
</li>
|
||||
);
|
||||
</a>,
|
||||
]);
|
||||
}
|
||||
|
||||
case 'reply':
|
||||
|
@ -1126,13 +1133,17 @@ export default class EventTile extends React.Component<IProps, IState> {
|
|||
this.props.alwaysShowTimestamps || this.state.hover,
|
||||
);
|
||||
}
|
||||
return (
|
||||
<li className={classes} aria-live={ariaLive} aria-atomic="true" data-scroll-tokens={scrollToken}>
|
||||
{ ircTimestamp }
|
||||
{ avatar }
|
||||
{ sender }
|
||||
{ ircPadlock }
|
||||
<div className="mx_EventTile_reply">
|
||||
return React.createElement(this.props.as || "li", {
|
||||
"className": classes,
|
||||
"aria-live": ariaLive,
|
||||
"aria-atomic": true,
|
||||
"data-scroll-tokens": scrollToken,
|
||||
}, [
|
||||
ircTimestamp,
|
||||
avatar,
|
||||
sender,
|
||||
ircPadlock,
|
||||
<div className="mx_EventTile_reply" key="mx_EventTile_reply">
|
||||
{ groupTimestamp }
|
||||
{ groupPadlock }
|
||||
{ thread }
|
||||
|
@ -1144,9 +1155,8 @@ export default class EventTile extends React.Component<IProps, IState> {
|
|||
replacingEventId={this.props.replacingEventId}
|
||||
showUrlPreview={false}
|
||||
/>
|
||||
</div>
|
||||
</li>
|
||||
);
|
||||
</div>,
|
||||
]);
|
||||
}
|
||||
default: {
|
||||
const thread = ReplyThread.makeThread(
|
||||
|
|
|
@ -95,6 +95,7 @@ export default class ReplyPreview extends React.Component {
|
|||
permalinkCreator={this.props.permalinkCreator}
|
||||
isTwelveHour={SettingsStore.getValue("showTwelveHourTimestamps")}
|
||||
enableFlair={SettingsStore.getValue(UIFeature.Flair)}
|
||||
as="div"
|
||||
/>
|
||||
</div>
|
||||
</div>;
|
||||
|
|
|
@ -22,7 +22,7 @@ import FocusLock from "react-focus-lock";
|
|||
import {_t} from "../../../languageHandler";
|
||||
import AccessibleTooltipButton from "../elements/AccessibleTooltipButton";
|
||||
import {ChevronFace, ContextMenu} from "../../structures/ContextMenu";
|
||||
import createRoom, {IStateEvent, Preset} from "../../../createRoom";
|
||||
import createRoom from "../../../createRoom";
|
||||
import MatrixClientContext from "../../../contexts/MatrixClientContext";
|
||||
import {SpaceAvatar} from "./SpaceBasicSettings";
|
||||
import AccessibleButton from "../elements/AccessibleButton";
|
||||
|
@ -33,6 +33,8 @@ import {USER_LABS_TAB} from "../dialogs/UserSettingsDialog";
|
|||
import Field from "../elements/Field";
|
||||
import withValidation from "../elements/Validation";
|
||||
import {SpaceFeedbackPrompt} from "../../structures/SpaceRoomView";
|
||||
import { Preset } from "matrix-js-sdk/src/@types/partials";
|
||||
import { ICreateRoomStateEvent } from "matrix-js-sdk/src/@types/requests";
|
||||
|
||||
const SpaceCreateMenuType = ({ title, description, className, onClick }) => {
|
||||
return (
|
||||
|
@ -81,7 +83,7 @@ const SpaceCreateMenu = ({ onFinished }) => {
|
|||
return;
|
||||
}
|
||||
|
||||
const initialState: IStateEvent[] = [
|
||||
const initialState: ICreateRoomStateEvent[] = [
|
||||
{
|
||||
type: EventType.RoomHistoryVisibility,
|
||||
content: {
|
||||
|
|
|
@ -35,53 +35,15 @@ import { VIRTUAL_ROOM_EVENT_TYPE } from "./CallHandler";
|
|||
import SpaceStore from "./stores/SpaceStore";
|
||||
import { makeSpaceParentEvent } from "./utils/space";
|
||||
import { Action } from "./dispatcher/actions"
|
||||
import { ICreateRoomOpts } from "matrix-js-sdk/src/@types/requests";
|
||||
import { Preset, Visibility } from "matrix-js-sdk/src/@types/partials";
|
||||
|
||||
// we define a number of interfaces which take their names from the js-sdk
|
||||
/* eslint-disable camelcase */
|
||||
|
||||
// TODO move these interfaces over to js-sdk once it has been typescripted enough to accept them
|
||||
export enum Visibility {
|
||||
Public = "public",
|
||||
Private = "private",
|
||||
}
|
||||
|
||||
export enum Preset {
|
||||
PrivateChat = "private_chat",
|
||||
TrustedPrivateChat = "trusted_private_chat",
|
||||
PublicChat = "public_chat",
|
||||
}
|
||||
|
||||
interface Invite3PID {
|
||||
id_server: string;
|
||||
id_access_token?: string; // this gets injected by the js-sdk
|
||||
medium: string;
|
||||
address: string;
|
||||
}
|
||||
|
||||
export interface IStateEvent {
|
||||
type: string;
|
||||
state_key?: string; // defaults to an empty string
|
||||
content: object;
|
||||
}
|
||||
|
||||
interface ICreateOpts {
|
||||
visibility?: Visibility;
|
||||
room_alias_name?: string;
|
||||
name?: string;
|
||||
topic?: string;
|
||||
invite?: string[];
|
||||
invite_3pid?: Invite3PID[];
|
||||
room_version?: string;
|
||||
creation_content?: object;
|
||||
initial_state?: IStateEvent[];
|
||||
preset?: Preset;
|
||||
is_direct?: boolean;
|
||||
power_level_content_override?: object;
|
||||
}
|
||||
|
||||
export interface IOpts {
|
||||
dmUserId?: string;
|
||||
createOpts?: ICreateOpts;
|
||||
createOpts?: ICreateRoomOpts;
|
||||
spinner?: boolean;
|
||||
guestAccess?: boolean;
|
||||
encryption?: boolean;
|
||||
|
@ -91,12 +53,6 @@ export interface IOpts {
|
|||
parentSpace?: Room;
|
||||
}
|
||||
|
||||
export interface IInvite3PID {
|
||||
id_server: string,
|
||||
medium: 'email',
|
||||
address: string,
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new room, and switch to it.
|
||||
*
|
||||
|
@ -136,7 +92,7 @@ export default function createRoom(opts: IOpts): Promise<string | null> {
|
|||
const defaultPreset = opts.dmUserId ? Preset.TrustedPrivateChat : Preset.PrivateChat;
|
||||
|
||||
// set some defaults for the creation
|
||||
const createOpts = opts.createOpts || {};
|
||||
const createOpts: ICreateRoomOpts = opts.createOpts || {};
|
||||
createOpts.preset = createOpts.preset || defaultPreset;
|
||||
createOpts.visibility = createOpts.visibility || Visibility.Private;
|
||||
if (opts.dmUserId && createOpts.invite === undefined) {
|
||||
|
|
|
@ -2257,6 +2257,9 @@
|
|||
"Start a conversation with someone using their name or username (like <userId/>).": "Start a conversation with someone using their name or username (like <userId/>).",
|
||||
"This won't invite them to %(communityName)s. To invite someone to %(communityName)s, click <a>here</a>": "This won't invite them to %(communityName)s. To invite someone to %(communityName)s, click <a>here</a>",
|
||||
"Go": "Go",
|
||||
"Some suggestions may be hidden for privacy.": "Some suggestions may be hidden for privacy.",
|
||||
"If you can't see who you’re looking for, send them your invite link below.": "If you can't see who you’re looking for, send them your invite link below.",
|
||||
"Or send invite link": "Or send invite link",
|
||||
"Unnamed Space": "Unnamed Space",
|
||||
"Invite to %(roomName)s": "Invite to %(roomName)s",
|
||||
"Invite someone using their name, email address, username (like <userId/>) or <a>share this space</a>.": "Invite someone using their name, email address, username (like <userId/>) or <a>share this space</a>.",
|
||||
|
|
|
@ -20,6 +20,7 @@ import SettingsStore from "../settings/SettingsStore";
|
|||
import {_t} from "../languageHandler";
|
||||
import dis from "../dispatcher/dispatcher";
|
||||
import {SettingLevel} from "../settings/SettingLevel";
|
||||
import { Preset } from "matrix-js-sdk/src/@types/partials";
|
||||
|
||||
// TODO: Move this and related files to the js-sdk or something once finalized.
|
||||
|
||||
|
@ -86,7 +87,7 @@ export class Mjolnir {
|
|||
const resp = await MatrixClientPeg.get().createRoom({
|
||||
name: _t("My Ban List"),
|
||||
topic: _t("This is your list of users/servers you have blocked - don't leave the room!"),
|
||||
preset: "private_chat",
|
||||
preset: Preset.PrivateChat,
|
||||
});
|
||||
personalRoomId = resp['room_id'];
|
||||
await SettingsStore.setValue(
|
||||
|
|
|
@ -25,14 +25,8 @@ import Tar from "tar-js";
|
|||
|
||||
import * as rageshake from './rageshake';
|
||||
|
||||
// polyfill textencoder if necessary
|
||||
import * as TextEncodingUtf8 from 'text-encoding-utf-8';
|
||||
import SettingsStore from "../settings/SettingsStore";
|
||||
import SdkConfig from "../SdkConfig";
|
||||
let TextEncoder = window.TextEncoder;
|
||||
if (!TextEncoder) {
|
||||
TextEncoder = TextEncodingUtf8.TextEncoder;
|
||||
}
|
||||
|
||||
interface IOpts {
|
||||
label?: string;
|
||||
|
|
|
@ -15,17 +15,6 @@ See the License for the specific language governing permissions and
|
|||
limitations under the License.
|
||||
*/
|
||||
|
||||
// polyfill textencoder if necessary
|
||||
import * as TextEncodingUtf8 from 'text-encoding-utf-8';
|
||||
let TextEncoder = window.TextEncoder;
|
||||
if (!TextEncoder) {
|
||||
TextEncoder = TextEncodingUtf8.TextEncoder;
|
||||
}
|
||||
let TextDecoder = window.TextDecoder;
|
||||
if (!TextDecoder) {
|
||||
TextDecoder = TextEncodingUtf8.TextDecoder;
|
||||
}
|
||||
|
||||
import { _t } from '../languageHandler';
|
||||
import SdkConfig from '../SdkConfig';
|
||||
|
||||
|
|
|
@ -122,7 +122,7 @@ function getAllEventTiles(session) {
|
|||
}
|
||||
|
||||
async function getMessageFromEventTile(eventTile) {
|
||||
const senderElement = await eventTile.$(".mx_SenderProfile_name");
|
||||
const senderElement = await eventTile.$(".mx_SenderProfile_displayName");
|
||||
const className = await (await eventTile.getProperty("className")).jsonValue();
|
||||
const classNames = className.split(" ");
|
||||
const bodyElement = await eventTile.$(".mx_EventTile_body");
|
||||
|
|
|
@ -1,6 +1,12 @@
|
|||
import * as languageHandler from "../src/languageHandler";
|
||||
import { TextEncoder, TextDecoder } from 'util';
|
||||
|
||||
languageHandler.setLanguage('en');
|
||||
languageHandler.setMissingEntryGenerator(key => key.split("|", 2)[1]);
|
||||
|
||||
require('jest-fetch-mock').enableMocks();
|
||||
|
||||
// polyfilling TextEncoder as it is not available on JSDOM
|
||||
// view https://github.com/facebook/jest/issues/9983
|
||||
global.TextEncoder = TextEncoder;
|
||||
global.TextDecoder = TextDecoder;
|
||||
|
|
10
yarn.lock
10
yarn.lock
|
@ -2181,11 +2181,6 @@ bluebird@^3.5.0:
|
|||
resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.7.2.tgz#9f229c15be272454ffa973ace0dbee79a1b0c36f"
|
||||
integrity sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==
|
||||
|
||||
blueimp-canvas-to-blob@^3.28.0:
|
||||
version "3.28.0"
|
||||
resolved "https://registry.yarnpkg.com/blueimp-canvas-to-blob/-/blueimp-canvas-to-blob-3.28.0.tgz#c8ab4dc6bb08774a7f273798cdf94b0776adf6c8"
|
||||
integrity sha512-5q+YHzgGsuHQ01iouGgJaPJXod2AzTxJXmVv90PpGrRxU7G7IqgPqWXz+PBmt3520jKKi6irWbNV87DicEa7wg==
|
||||
|
||||
boolbase@^1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/boolbase/-/boolbase-1.0.0.tgz#68dff5fbe60c51eb37725ea9e3ed310dcc1e776e"
|
||||
|
@ -7945,11 +7940,6 @@ test-exclude@^6.0.0:
|
|||
glob "^7.1.4"
|
||||
minimatch "^3.0.4"
|
||||
|
||||
text-encoding-utf-8@^1.0.2:
|
||||
version "1.0.2"
|
||||
resolved "https://registry.yarnpkg.com/text-encoding-utf-8/-/text-encoding-utf-8-1.0.2.tgz#585b62197b0ae437e3c7b5d0af27ac1021e10d13"
|
||||
integrity sha512-8bw4MY9WjdsD2aMtO0OzOCY3pXGYNx2d2FfHRVUKkiCPDWjKuOlhLVASS+pD7VkLTVjW268LYJHwsnPFlBpbAg==
|
||||
|
||||
text-table@^0.2.0:
|
||||
version "0.2.0"
|
||||
resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4"
|
||||
|
|
Loading…
Reference in a new issue