Merge branch 'develop' of github.com:matrix-org/matrix-react-sdk into t3chguy/ts/5

This commit is contained in:
Michael Telatynski 2021-06-22 17:28:19 +01:00
commit 59258585b3
24 changed files with 295 additions and 276 deletions

View file

@ -60,7 +60,7 @@ import ScrollPanel from "./ScrollPanel";
import TimelinePanel from "./TimelinePanel";
import ErrorBoundary from "../views/elements/ErrorBoundary";
import RoomPreviewBar from "../views/rooms/RoomPreviewBar";
import SearchBar from "../views/rooms/SearchBar";
import SearchBar, { SearchScope } from "../views/rooms/SearchBar";
import RoomUpgradeWarningBar from "../views/rooms/RoomUpgradeWarningBar";
import AuxPanel from "../views/rooms/AuxPanel";
import RoomHeader from "../views/rooms/RoomHeader";
@ -139,7 +139,7 @@ export interface IState {
draggingFile: boolean;
searching: boolean;
searchTerm?: string;
searchScope?: "All" | "Room";
searchScope?: SearchScope;
searchResults?: XOR<{}, {
count: number;
highlights: string[];
@ -1263,7 +1263,7 @@ export default class RoomView extends React.Component<IProps, IState> {
});
}
private onSearch = (term: string, scope) => {
private onSearch = (term: string, scope: SearchScope) => {
this.setState({
searchTerm: term,
searchScope: scope,
@ -1284,7 +1284,7 @@ export default class RoomView extends React.Component<IProps, IState> {
this.searchId = new Date().getTime();
let roomId;
if (scope === "Room") roomId = this.state.room.roomId;
if (scope === SearchScope.Room) roomId = this.state.room.roomId;
debuglog("sending search request");
const searchPromise = eventSearch(term, roomId);

View file

@ -14,10 +14,14 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
import React from "react";
import EventIndexPeg from "../../../indexing/EventIndexPeg";
import { _t } from "../../../languageHandler";
import SdkConfig from "../../../SdkConfig";
import React from "react";
import dis from "../../../dispatcher/dispatcher";
import { Action } from "../../../dispatcher/actions";
import { UserTab } from "../dialogs/UserSettingsDialog";
export enum WarningKind {
Files,
@ -33,6 +37,22 @@ export default function DesktopBuildsNotice({isRoomEncrypted, kind}: IProps) {
if (!isRoomEncrypted) return null;
if (EventIndexPeg.get()) return null;
if (EventIndexPeg.error) {
return <>
{_t("Message search initialisation failed, check <a>your settings</a> for more information", {}, {
a: sub => (<a onClick={(evt) => {
evt.preventDefault();
dis.dispatch({
action: Action.ViewUserSettings,
initialTabId: UserTab.Security,
});
}}>
{sub}
</a>),
})}
</>;
}
const {desktopBuilds, brand} = SdkConfig.get();
let text = null;

View file

@ -1,28 +0,0 @@
/*
Copyright 2019 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 AccessibleButton from "./AccessibleButton";
export default function FormButton(props) {
const {className, label, kind, ...restProps} = props;
const newClassName = (className || "") + " mx_FormButton";
const allProps = Object.assign({}, restProps,
{className: newClassName, kind: kind || "primary", children: [label]});
return React.createElement(AccessibleButton, allProps);
}
FormButton.propTypes = AccessibleButton.propTypes;

View file

@ -15,41 +15,40 @@ limitations under the License.
*/
import React from 'react';
import PropTypes from 'prop-types';
import {MatrixClientPeg} from '../../../MatrixClientPeg';
import { MatrixEvent } from 'matrix-js-sdk/src';
import { MatrixClientPeg } from '../../../MatrixClientPeg';
import * as sdk from '../../../index';
import { _t } from '../../../languageHandler';
import {getNameForEventRoom, userLabelForEventRoom}
import { getNameForEventRoom, userLabelForEventRoom }
from '../../../utils/KeyVerificationStateObserver';
import dis from "../../../dispatcher/dispatcher";
import {RightPanelPhases} from "../../../stores/RightPanelStorePhases";
import {Action} from "../../../dispatcher/actions";
import { RightPanelPhases } from "../../../stores/RightPanelStorePhases";
import { Action } from "../../../dispatcher/actions";
import EventTileBubble from "./EventTileBubble";
import {replaceableComponent} from "../../../utils/replaceableComponent";
import { replaceableComponent } from "../../../utils/replaceableComponent";
interface IProps {
mxEvent: MatrixEvent
}
@replaceableComponent("views.messages.MKeyVerificationRequest")
export default class MKeyVerificationRequest extends React.Component {
constructor(props) {
super(props);
this.state = {};
}
componentDidMount() {
export default class MKeyVerificationRequest extends React.Component<IProps> {
public componentDidMount() {
const request = this.props.mxEvent.verificationRequest;
if (request) {
request.on("change", this._onRequestChanged);
request.on("change", this.onRequestChanged);
}
}
componentWillUnmount() {
public componentWillUnmount() {
const request = this.props.mxEvent.verificationRequest;
if (request) {
request.off("change", this._onRequestChanged);
request.off("change", this.onRequestChanged);
}
}
_openRequest = () => {
const {verificationRequest} = this.props.mxEvent;
private openRequest = () => {
const { verificationRequest } = this.props.mxEvent;
const member = MatrixClientPeg.get().getUser(verificationRequest.otherUserId);
dis.dispatch({
action: Action.SetRightPanelPhase,
@ -58,15 +57,15 @@ export default class MKeyVerificationRequest extends React.Component {
});
};
_onRequestChanged = () => {
private onRequestChanged = () => {
this.forceUpdate();
};
_onAcceptClicked = async () => {
private onAcceptClicked = async () => {
const request = this.props.mxEvent.verificationRequest;
if (request) {
try {
this._openRequest();
this.openRequest();
await request.accept();
} catch (err) {
console.error(err.message);
@ -74,7 +73,7 @@ export default class MKeyVerificationRequest extends React.Component {
}
};
_onRejectClicked = async () => {
private onRejectClicked = async () => {
const request = this.props.mxEvent.verificationRequest;
if (request) {
try {
@ -85,7 +84,7 @@ export default class MKeyVerificationRequest extends React.Component {
}
};
_acceptedLabel(userId) {
private acceptedLabel(userId: string) {
const client = MatrixClientPeg.get();
const myUserId = client.getUserId();
if (userId === myUserId) {
@ -95,7 +94,7 @@ export default class MKeyVerificationRequest extends React.Component {
}
}
_cancelledLabel(userId) {
private cancelledLabel(userId: string) {
const client = MatrixClientPeg.get();
const myUserId = client.getUserId();
const {cancellationCode} = this.props.mxEvent.verificationRequest;
@ -115,9 +114,8 @@ export default class MKeyVerificationRequest extends React.Component {
}
}
render() {
public render() {
const AccessibleButton = sdk.getComponent("elements.AccessibleButton");
const FormButton = sdk.getComponent("elements.FormButton");
const {mxEvent} = this.props;
const request = mxEvent.verificationRequest;
@ -134,11 +132,11 @@ export default class MKeyVerificationRequest extends React.Component {
let stateLabel;
const accepted = request.ready || request.started || request.done;
if (accepted) {
stateLabel = (<AccessibleButton onClick={this._openRequest}>
{this._acceptedLabel(request.receivingUserId)}
stateLabel = (<AccessibleButton onClick={this.openRequest}>
{this.acceptedLabel(request.receivingUserId)}
</AccessibleButton>);
} else if (request.cancelled) {
stateLabel = this._cancelledLabel(request.cancellingUserId);
stateLabel = this.cancelledLabel(request.cancellingUserId);
} else if (request.accepting) {
stateLabel = _t("Accepting …");
} else if (request.declining) {
@ -153,8 +151,12 @@ export default class MKeyVerificationRequest extends React.Component {
subtitle = userLabelForEventRoom(request.requestingUserId, mxEvent.getRoomId());
if (request.canAccept) {
stateNode = (<div className="mx_cryptoEvent_buttons">
<FormButton kind="danger" onClick={this._onRejectClicked} label={_t("Decline")} />
<FormButton onClick={this._onAcceptClicked} label={_t("Accept")} />
<AccessibleButton kind="danger" onClick={this.onRejectClicked}>
{_t("Decline")}
</AccessibleButton>
<AccessibleButton onClick={this.onAcceptClicked}>
{_t("Accept")}
</AccessibleButton>
</div>);
}
} else { // request sent by us
@ -174,8 +176,3 @@ export default class MKeyVerificationRequest extends React.Component {
return null;
}
}
MKeyVerificationRequest.propTypes = {
/* the MatrixEvent to show */
mxEvent: PropTypes.object.isRequired,
};

View file

@ -195,14 +195,7 @@ export default class VerificationPanel extends React.PureComponent<IProps, IStat
private renderQRReciprocatePhase() {
const {member, request} = this.props;
let Button;
// a bit of a hack, but the FormButton should only be used in the right panel
// they should probably just be the same component with a css class applied to it?
if (this.props.inDialog) {
Button = sdk.getComponent("elements.AccessibleButton");
} else {
Button = sdk.getComponent("elements.FormButton");
}
const AccessibleButton = sdk.getComponent("elements.AccessibleButton");
const description = request.isSelfVerification ?
_t("Almost there! Is your other session showing the same shield?") :
_t("Almost there! Is %(displayName)s showing the same shield?", {
@ -211,21 +204,24 @@ export default class VerificationPanel extends React.PureComponent<IProps, IStat
let body: JSX.Element;
if (this.state.reciprocateQREvent) {
// Element Web doesn't support scanning yet, so assume here we're the client being scanned.
//
// we're passing both a label and a child string to Button as
// FormButton and AccessibleButton expect this differently
body = <React.Fragment>
<p>{description}</p>
<E2EIcon isUser={true} status="verified" size={128} hideTooltip={true} />
<div className="mx_VerificationPanel_reciprocateButtons">
<Button
label={_t("No")} kind="danger"
<AccessibleButton
kind="danger"
disabled={this.state.reciprocateButtonClicked}
onClick={this.onReciprocateNoClick}>{_t("No")}</Button>
<Button
label={_t("Yes")} kind="primary"
onClick={this.onReciprocateNoClick}
>
{ _t("No") }
</AccessibleButton>
<AccessibleButton
kind="primary"
disabled={this.state.reciprocateButtonClicked}
onClick={this.onReciprocateYesClick}>{_t("Yes")}</Button>
onClick={this.onReciprocateYesClick}
>
{ _t("Yes") }
</AccessibleButton>
</div>
</React.Fragment>;
} else {

View file

@ -1,99 +0,0 @@
/*
Copyright 2015, 2016 OpenMarket Ltd
Copyright 2020 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, {createRef} from 'react';
import AccessibleButton from "../elements/AccessibleButton";
import classNames from "classnames";
import { _t } from '../../../languageHandler';
import {Key} from "../../../Keyboard";
import DesktopBuildsNotice, {WarningKind} from "../elements/DesktopBuildsNotice";
import {replaceableComponent} from "../../../utils/replaceableComponent";
@replaceableComponent("views.rooms.SearchBar")
export default class SearchBar extends React.Component {
constructor(props) {
super(props);
this._search_term = createRef();
this.state = {
scope: 'Room',
};
}
onThisRoomClick = () => {
this.setState({ scope: 'Room' }, () => this._searchIfQuery());
};
onAllRoomsClick = () => {
this.setState({ scope: 'All' }, () => this._searchIfQuery());
};
onSearchChange = (e) => {
switch (e.key) {
case Key.ENTER:
this.onSearch();
break;
case Key.ESCAPE:
this.props.onCancelClick();
break;
}
};
_searchIfQuery() {
if (this._search_term.current.value) {
this.onSearch();
}
}
onSearch = () => {
this.props.onSearch(this._search_term.current.value, this.state.scope);
};
render() {
const searchButtonClasses = classNames("mx_SearchBar_searchButton", {
mx_SearchBar_searching: this.props.searchInProgress,
});
const thisRoomClasses = classNames("mx_SearchBar_button", {
mx_SearchBar_unselected: this.state.scope !== 'Room',
});
const allRoomsClasses = classNames("mx_SearchBar_button", {
mx_SearchBar_unselected: this.state.scope !== 'All',
});
return (
<>
<div className="mx_SearchBar">
<div className="mx_SearchBar_buttons" role="radiogroup">
<AccessibleButton className={ thisRoomClasses } onClick={this.onThisRoomClick} aria-checked={this.state.scope === 'Room'} role="radio">
{_t("This Room")}
</AccessibleButton>
<AccessibleButton className={ allRoomsClasses } onClick={this.onAllRoomsClick} aria-checked={this.state.scope === 'All'} role="radio">
{_t("All Rooms")}
</AccessibleButton>
</div>
<div className="mx_SearchBar_input mx_textinput">
<input ref={this._search_term} type="text" autoFocus={true} placeholder={_t("Search…")} onKeyDown={this.onSearchChange} />
<AccessibleButton className={ searchButtonClasses } onClick={this.onSearch} />
</div>
<AccessibleButton className="mx_SearchBar_cancel" onClick={this.props.onCancelClick} />
</div>
<DesktopBuildsNotice isRoomEncrypted={this.props.isRoomEncrypted} kind={WarningKind.Search} />
</>
);
}
}

View file

@ -0,0 +1,130 @@
/*
Copyright 2015, 2016 OpenMarket Ltd
Copyright 2020 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, { createRef, RefObject } from 'react';
import AccessibleButton from "../elements/AccessibleButton";
import classNames from "classnames";
import { _t } from '../../../languageHandler';
import { Key } from "../../../Keyboard";
import DesktopBuildsNotice, { WarningKind } from "../elements/DesktopBuildsNotice";
import { replaceableComponent } from "../../../utils/replaceableComponent";
interface IProps {
onCancelClick: () => void;
onSearch: (query: string, scope: string) => void;
searchInProgress?: boolean;
isRoomEncrypted?: boolean;
}
interface IState {
scope: SearchScope;
}
export enum SearchScope {
Room = "Room",
All = "All",
}
@replaceableComponent("views.rooms.SearchBar")
export default class SearchBar extends React.Component<IProps, IState> {
private searchTerm: RefObject<HTMLInputElement> = createRef();
constructor(props: IProps) {
super(props);
this.state = {
scope: SearchScope.Room,
};
}
private onThisRoomClick = () => {
this.setState({ scope: SearchScope.Room }, () => this.searchIfQuery());
};
private onAllRoomsClick = () => {
this.setState({ scope: SearchScope.All }, () => this.searchIfQuery());
};
private onSearchChange = (e: React.KeyboardEvent) => {
switch (e.key) {
case Key.ENTER:
this.onSearch();
break;
case Key.ESCAPE:
this.props.onCancelClick();
break;
}
};
private searchIfQuery(): void {
if (this.searchTerm.current.value) {
this.onSearch();
}
}
private onSearch = (): void => {
this.props.onSearch(this.searchTerm.current.value, this.state.scope);
};
public render() {
const searchButtonClasses = classNames("mx_SearchBar_searchButton", {
mx_SearchBar_searching: this.props.searchInProgress,
});
const thisRoomClasses = classNames("mx_SearchBar_button", {
mx_SearchBar_unselected: this.state.scope !== SearchScope.Room,
});
const allRoomsClasses = classNames("mx_SearchBar_button", {
mx_SearchBar_unselected: this.state.scope !== SearchScope.All,
});
return (
<>
<div className="mx_SearchBar">
<div className="mx_SearchBar_buttons" role="radiogroup">
<AccessibleButton
className={thisRoomClasses}
onClick={this.onThisRoomClick}
aria-checked={this.state.scope === SearchScope.Room}
role="radio"
>
{_t("This Room")}
</AccessibleButton>
<AccessibleButton
className={allRoomsClasses}
onClick={this.onAllRoomsClick}
aria-checked={this.state.scope === SearchScope.All}
role="radio"
>
{_t("All Rooms")}
</AccessibleButton>
</div>
<div className="mx_SearchBar_input mx_textinput">
<input
ref={this.searchTerm}
type="text"
autoFocus={true}
placeholder={_t("Search…")}
onKeyDown={this.onSearchChange}
/>
<AccessibleButton className={ searchButtonClasses } onClick={this.onSearch} />
</div>
<AccessibleButton className="mx_SearchBar_cancel" onClick={this.props.onCancelClick} />
</div>
<DesktopBuildsNotice isRoomEncrypted={this.props.isRoomEncrypted} kind={WarningKind.Search} />
</>
);
}
}

View file

@ -15,8 +15,8 @@ limitations under the License.
*/
import React, {ReactNode} from "react";
import AccessibleButton from "../elements/AccessibleButton";
import FormButton from "../elements/FormButton";
import {XOR} from "../../../@types/common";
export interface IProps {
@ -50,8 +50,12 @@ const GenericToast: React.FC<XOR<IPropsExtended, IProps>> = ({
{detailContent}
</div>
<div className="mx_Toast_buttons" aria-live="off">
{onReject && rejectLabel && <FormButton label={rejectLabel} kind="danger" onClick={onReject} /> }
<FormButton label={acceptLabel} onClick={onAccept} />
{onReject && rejectLabel && <AccessibleButton kind="danger" onClick={onReject}>
{ rejectLabel }
</AccessibleButton> }
<AccessibleButton onClick={onAccept} kind="primary">
{ acceptLabel }
</AccessibleButton>
</div>
</div>;
};

View file

@ -23,7 +23,7 @@ import { _t } from '../../../languageHandler';
import { ActionPayload } from '../../../dispatcher/payloads';
import CallHandler, { AudioID } from '../../../CallHandler';
import RoomAvatar from '../avatars/RoomAvatar';
import FormButton from '../elements/FormButton';
import AccessibleButton from '../elements/AccessibleButton';
import { CallState } from 'matrix-js-sdk/src/webrtc/call';
import {replaceableComponent} from "../../../utils/replaceableComponent";
import AccessibleTooltipButton from '../elements/AccessibleTooltipButton';
@ -143,21 +143,22 @@ export default class IncomingCallBox extends React.Component<IProps, IState> {
/>
</div>
<div className="mx_IncomingCallBox_buttons">
<FormButton
<AccessibleButton
className={"mx_IncomingCallBox_decline"}
onClick={this.onRejectClick}
kind="danger"
label={_t("Decline")}
/>
>
{ _t("Decline") }
</AccessibleButton>
<div className="mx_IncomingCallBox_spacer" />
<FormButton
<AccessibleButton
className={"mx_IncomingCallBox_accept"}
onClick={this.onAnswerClick}
kind="primary"
label={_t("Accept")}
/>
>
{ _t("Accept") }
</AccessibleButton>
</div>
</div>;
}
}