Merge branch 'develop' into gsouquet/dialogs-ts-migration

This commit is contained in:
Germain 2021-06-15 00:02:49 +01:00 committed by GitHub
commit d3101b5ce4
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
13 changed files with 222 additions and 96 deletions

View file

@ -15,22 +15,23 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
import React, {ChangeEvent, createRef, KeyboardEvent, SyntheticEvent} from "react";
import {Room} from "matrix-js-sdk/src/models/room";
import React, { ChangeEvent, createRef, KeyboardEvent, SyntheticEvent } from "react";
import { Room } from "matrix-js-sdk/src/models/room";
import SdkConfig from '../../../SdkConfig';
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 {CommunityPrototypeStore} from "../../../stores/CommunityPrototypeStore";
import {replaceableComponent} from "../../../utils/replaceableComponent";
import withValidation, { IFieldState } from '../elements/Validation';
import { _t } from '../../../languageHandler';
import { MatrixClientPeg } from '../../../MatrixClientPeg';
import { Key } from "../../../Keyboard";
import { IOpts, privateShouldBeEncrypted } from "../../../createRoom";
import { CommunityPrototypeStore } from "../../../stores/CommunityPrototypeStore";
import { replaceableComponent } from "../../../utils/replaceableComponent";
import Field from "../elements/Field";
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;

View file

@ -14,7 +14,9 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
import React, {createRef} from 'react';
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 youre 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>
);

View file

@ -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>
);

View file

@ -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_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: {