Merge remote-tracking branch 'origin/develop' into element

This commit is contained in:
J. Ryan Stinnett 2020-07-13 18:49:55 +01:00
commit 995a7879a1
29 changed files with 265 additions and 200 deletions

View file

@ -35,8 +35,8 @@ import RoomListStore, { LISTS_UPDATE_EVENT } from "../../stores/room-list/RoomLi
import {Key} from "../../Keyboard";
import IndicatorScrollbar from "../structures/IndicatorScrollbar";
// TODO: Remove banner on launch: https://github.com/vector-im/riot-web/issues/14231
// TODO: Rename on launch: https://github.com/vector-im/riot-web/issues/14231
// TODO: Remove banner on launch: https://github.com/vector-im/riot-web/issues/14367
// TODO: Rename on launch: https://github.com/vector-im/riot-web/issues/14367
/*******************************************************************
* CAUTION *
@ -274,6 +274,14 @@ export default class LeftPanel2 extends React.Component<IProps, IState> {
}
};
private onEnter = () => {
const firstRoom = this.listContainerRef.current.querySelector<HTMLDivElement>(".mx_RoomTile2");
if (firstRoom) {
firstRoom.click();
this.onSearch(""); // clear the search field
}
};
private onMoveFocus = (up: boolean) => {
let element = this.focusedElement;
@ -346,6 +354,7 @@ export default class LeftPanel2 extends React.Component<IProps, IState> {
onQueryUpdate={this.onSearch}
isMinimized={this.props.isMinimized}
onVerticalArrow={this.onKeyDown}
onEnter={this.onEnter}
/>
<AccessibleButton
className="mx_LeftPanel2_exploreButton"

View file

@ -668,8 +668,7 @@ class LoggedInView extends React.Component<IProps, IState> {
disabled={this.props.leftDisabled}
/>
);
if (SettingsStore.isFeatureEnabled("feature_new_room_list")) {
// TODO: Supply props like collapsed and disabled to LeftPanel2
if (SettingsStore.getValue("feature_new_room_list")) {
leftPanel = (
<LeftPanel2
isMinimized={this.props.collapseLhs || false}

View file

@ -50,7 +50,7 @@ import PageTypes from '../../PageTypes';
import { getHomePageUrl } from '../../utils/pages';
import createRoom from "../../createRoom";
import { _t, getCurrentLanguage } from '../../languageHandler';
import {_t, _td, getCurrentLanguage} from '../../languageHandler';
import SettingsStore, { SettingLevel } from "../../settings/SettingsStore";
import ThemeController from "../../settings/controllers/ThemeController";
import { startAnyRegistrationFlow } from "../../Registration.js";
@ -74,6 +74,7 @@ import {
} from "../../toasts/AnalyticsToast";
import {showToast as showNotificationsToast} from "../../toasts/DesktopNotificationsToast";
import { OpenToTabPayload } from "../../dispatcher/payloads/OpenToTabPayload";
import ErrorDialog from "../views/dialogs/ErrorDialog";
/** constants for MatrixChat.state.view */
export enum Views {
@ -460,7 +461,6 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
onAction = (payload) => {
// console.log(`MatrixClientPeg.onAction: ${payload.action}`);
const ErrorDialog = sdk.getComponent("dialogs.ErrorDialog");
const QuestionDialog = sdk.getComponent("dialogs.QuestionDialog");
// Start the onboarding process for certain actions
@ -554,6 +554,9 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
case 'leave_room':
this.leaveRoom(payload.room_id);
break;
case 'forget_room':
this.forgetRoom(payload.room_id);
break;
case 'reject_invite':
Modal.createTrackedDialog('Reject invitation', '', QuestionDialog, {
title: _t('Reject invitation'),
@ -1060,7 +1063,6 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
private leaveRoom(roomId: string) {
const QuestionDialog = sdk.getComponent("dialogs.QuestionDialog");
const ErrorDialog = sdk.getComponent("dialogs.ErrorDialog");
const roomToLeave = MatrixClientPeg.get().getRoom(roomId);
const warnings = this.leaveRoomWarnings(roomId);
@ -1124,6 +1126,21 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
});
}
private forgetRoom(roomId: string) {
MatrixClientPeg.get().forget(roomId).then(() => {
// Switch to another room view if we're currently viewing the historical room
if (this.state.currentRoomId === roomId) {
dis.dispatch({ action: "view_next_room" });
}
}).catch((err) => {
const errCode = err.errcode || _td("unknown error code");
Modal.createTrackedDialog("Failed to forget room", '', ErrorDialog, {
title: _t("Failed to forget room %(errCode)s", {errCode}),
description: ((err && err.message) ? err.message : _t("Operation failed")),
});
});
}
/**
* Starts a chat with the welcome user, if the user doesn't already have one
* @returns {string} The room ID of the new room, or null if no room was created
@ -1372,7 +1389,6 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
return;
}
const ErrorDialog = sdk.getComponent("dialogs.ErrorDialog");
Modal.createTrackedDialog('Signed out', '', ErrorDialog, {
title: _t('Signed Out'),
description: _t('For security, this session has been signed out. Please sign in again.'),
@ -1442,7 +1458,6 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
}
});
cli.on("crypto.warning", (type) => {
const ErrorDialog = sdk.getComponent("dialogs.ErrorDialog");
switch (type) {
case 'CRYPTO_WARNING_OLD_VERSION_DETECTED':
const brand = SdkConfig.get().brand;

View file

@ -25,7 +25,7 @@ import { Key } from "../../Keyboard";
import AccessibleButton from "../views/elements/AccessibleButton";
import { Action } from "../../dispatcher/actions";
// TODO: Remove banner on launch: https://github.com/vector-im/riot-web/issues/14231
// TODO: Remove banner on launch: https://github.com/vector-im/riot-web/issues/14367
/*******************************************************************
* CAUTION *
@ -39,6 +39,7 @@ interface IProps {
onQueryUpdate: (newQuery: string) => void;
isMinimized: boolean;
onVerticalArrow(ev: React.KeyboardEvent);
onEnter(ev: React.KeyboardEvent);
}
interface IState {
@ -115,6 +116,8 @@ export default class RoomSearch extends React.PureComponent<IProps, IState> {
defaultDispatcher.fire(Action.FocusComposer);
} else if (ev.key === Key.ARROW_UP || ev.key === Key.ARROW_DOWN) {
this.props.onVerticalArrow(ev);
} else if (ev.key === Key.ENTER) {
this.props.onEnter(ev);
}
};

View file

@ -1380,15 +1380,9 @@ export default createReactClass({
},
onForgetClick: function() {
this.context.forget(this.state.room.roomId).then(function() {
dis.dispatch({ action: 'view_next_room' });
}, function(err) {
const errCode = err.errcode || _t("unknown error code");
const ErrorDialog = sdk.getComponent("dialogs.ErrorDialog");
Modal.createTrackedDialog('Failed to forget room', '', ErrorDialog, {
title: _t("Error"),
description: _t("Failed to forget room %(errCode)s", { errCode: errCode }),
});
dis.dispatch({
action: 'forget_room',
room_id: this.state.room.roomId,
});
},

View file

@ -99,6 +99,7 @@ const BaseAvatar = (props: IProps) => {
defaultToInitialLetter = true,
onClick,
inputRef,
className,
...otherProps
} = props;
@ -138,7 +139,7 @@ const BaseAvatar = (props: IProps) => {
<AccessibleButton
{...otherProps}
element="span"
className="mx_BaseAvatar"
className={classNames("mx_BaseAvatar", className)}
onClick={onClick}
inputRef={inputRef}
>
@ -149,7 +150,7 @@ const BaseAvatar = (props: IProps) => {
} else {
return (
<span
className="mx_BaseAvatar"
className={classNames("mx_BaseAvatar", className)}
ref={inputRef}
{...otherProps}
role="presentation"
@ -164,7 +165,7 @@ const BaseAvatar = (props: IProps) => {
if (onClick !== null) {
return (
<AccessibleButton
className="mx_BaseAvatar mx_BaseAvatar_image"
className={classNames("mx_BaseAvatar mx_BaseAvatar_image", className)}
element='img'
src={imageUrl}
onClick={onClick}
@ -180,7 +181,7 @@ const BaseAvatar = (props: IProps) => {
} else {
return (
<img
className="mx_BaseAvatar mx_BaseAvatar_image"
className={classNames("mx_BaseAvatar mx_BaseAvatar_image", className)}
src={imageUrl}
onError={onError}
style={{

View file

@ -126,16 +126,16 @@ export default class RoomAvatar extends React.Component<IProps, IState> {
};
public render() {
/*eslint no-unused-vars: ["error", { "ignoreRestSiblings": true }]*/
const {room, oobData, viewAvatarOnClick, ...otherProps} = this.props;
const roomName = room ? room.name : oobData.name;
return (
<BaseAvatar {...otherProps} name={roomName}
<BaseAvatar {...otherProps}
name={roomName}
idName={room ? room.roomId : null}
urls={this.state.urls}
onClick={this.props.viewAvatarOnClick && !this.state.urls[0] ? this.onRoomAvatarClick : null}
onClick={viewAvatarOnClick && this.state.urls[0] ? this.onRoomAvatarClick : null}
/>
);
}

View file

@ -27,8 +27,8 @@ import RoomListStore from "../../../stores/room-list/RoomListStore2";
import { DefaultTagID } from "../../../stores/room-list/models";
import AccessibleTooltipButton from "../elements/AccessibleTooltipButton";
// TODO: Remove banner on launch: https://github.com/vector-im/riot-web/issues/14231
// TODO: Rename on launch: https://github.com/vector-im/riot-web/issues/14231
// TODO: Remove banner on launch: https://github.com/vector-im/riot-web/issues/14367
// TODO: Rename on launch: https://github.com/vector-im/riot-web/issues/14367
/*******************************************************************
* CAUTION *

View file

@ -41,8 +41,8 @@ import { Action } from "../../../dispatcher/actions";
import { ViewRoomDeltaPayload } from "../../../dispatcher/payloads/ViewRoomDeltaPayload";
import { RoomNotificationStateStore } from "../../../stores/notifications/RoomNotificationStateStore";
// TODO: Remove banner on launch: https://github.com/vector-im/riot-web/issues/14231
// TODO: Rename on launch: https://github.com/vector-im/riot-web/issues/14231
// TODO: Remove banner on launch: https://github.com/vector-im/riot-web/issues/14367
// TODO: Rename on launch: https://github.com/vector-im/riot-web/issues/14367
/*******************************************************************
* CAUTION *

View file

@ -17,7 +17,7 @@ limitations under the License.
*/
import * as React from "react";
import { createRef } from "react";
import {createRef, UIEventHandler} from "react";
import { Room } from "matrix-js-sdk/src/models/room";
import classNames from 'classnames';
import { RovingAccessibleButton, RovingTabIndexWrapper } from "../../../accessibility/RovingTabIndex";
@ -48,8 +48,8 @@ import { polyfillTouchEvent } from "../../../@types/polyfill";
import { RoomNotificationStateStore } from "../../../stores/notifications/RoomNotificationStateStore";
import RoomListLayoutStore from "../../../stores/room-list/RoomListLayoutStore";
// TODO: Remove banner on launch: https://github.com/vector-im/riot-web/issues/14231
// TODO: Rename on launch: https://github.com/vector-im/riot-web/issues/14231
// TODO: Remove banner on launch: https://github.com/vector-im/riot-web/issues/14367
// TODO: Rename on launch: https://github.com/vector-im/riot-web/issues/14367
/*******************************************************************
* CAUTION *
@ -321,25 +321,29 @@ export default class RoomSublist2 extends React.Component<IProps, IState> {
}
};
private onHeaderClick = (ev: React.MouseEvent<HTMLDivElement>) => {
let target = ev.target as HTMLDivElement;
if (!target.classList.contains('mx_RoomSublist2_headerText')) {
// If we don't have the headerText class, the user clicked the span in the headerText.
target = target.parentElement as HTMLDivElement;
}
const possibleSticky = target.parentElement;
private onHeaderClick = () => {
const possibleSticky = this.headerButton.current.parentElement;
const sublist = possibleSticky.parentElement.parentElement;
const list = sublist.parentElement.parentElement;
// the scrollTop is capped at the height of the header in LeftPanel2
// the scrollTop is capped at the height of the header in LeftPanel2, the top header is always sticky
const isAtTop = list.scrollTop <= HEADER_HEIGHT;
const isSticky = possibleSticky.classList.contains('mx_RoomSublist2_headerContainer_sticky');
if (isSticky && !isAtTop) {
const isAtBottom = list.scrollTop >= list.scrollHeight - list.offsetHeight;
const isStickyTop = possibleSticky.classList.contains('mx_RoomSublist2_headerContainer_stickyTop');
const isStickyBottom = possibleSticky.classList.contains('mx_RoomSublist2_headerContainer_stickyBottom');
if ((isStickyBottom && !isAtBottom) || (isStickyTop && !isAtTop)) {
// is sticky - jump to list
sublist.scrollIntoView({behavior: 'smooth'});
} else {
// on screen - toggle collapse
const isExpanded = this.state.isExpanded;
this.toggleCollapsed();
// if the bottom list is collapsed then scroll it in so it doesn't expand off screen
if (!isExpanded && isStickyBottom) {
setImmediate(() => {
sublist.scrollIntoView({behavior: 'smooth'});
});
}
}
};
@ -595,6 +599,12 @@ export default class RoomSublist2 extends React.Component<IProps, IState> {
);
}
private onScrollPrevent(e: React.UIEvent<HTMLDivElement>) {
// the RoomTile calls scrollIntoView and the browser may scroll a div we do not wish to be scrollable
// this fixes https://github.com/vector-im/riot-web/issues/14413
(e.target as HTMLDivElement).scrollTop = 0;
}
public render(): React.ReactElement {
// TODO: Error boundary: https://github.com/vector-im/riot-web/issues/14185
@ -704,7 +714,7 @@ export default class RoomSublist2 extends React.Component<IProps, IState> {
className="mx_RoomSublist2_resizeBox"
enable={handles}
>
<div className="mx_RoomSublist2_tiles">
<div className="mx_RoomSublist2_tiles" onScroll={this.onScrollPrevent}>
{visibleTiles}
</div>
{showNButton}

View file

@ -55,8 +55,8 @@ import {ActionPayload} from "../../../dispatcher/payloads";
import { RoomNotificationStateStore } from "../../../stores/notifications/RoomNotificationStateStore";
import { NotificationState } from "../../../stores/notifications/NotificationState";
// TODO: Remove banner on launch: https://github.com/vector-im/riot-web/issues/14231
// TODO: Rename on launch: https://github.com/vector-im/riot-web/issues/14231
// TODO: Remove banner on launch: https://github.com/vector-im/riot-web/issues/14367
// TODO: Rename on launch: https://github.com/vector-im/riot-web/issues/14367
/*******************************************************************
* CAUTION *
@ -276,6 +276,17 @@ export default class RoomTile2 extends React.Component<IProps, IState> {
this.setState({generalMenuPosition: null}); // hide the menu
};
private onForgetRoomClick = (ev: ButtonEvent) => {
ev.preventDefault();
ev.stopPropagation();
dis.dispatch({
action: 'forget_room',
room_id: this.props.room.roomId,
});
this.setState({generalMenuPosition: null}); // hide the menu
};
private onOpenRoomSettings = (ev: ButtonEvent) => {
ev.preventDefault();
ev.stopPropagation();
@ -315,7 +326,7 @@ export default class RoomTile2 extends React.Component<IProps, IState> {
private onClickMute = ev => this.saveNotifState(ev, MUTE);
private renderNotificationsMenu(isActive: boolean): React.ReactElement {
if (MatrixClientPeg.get().isGuest() || !this.showContextMenu) {
if (MatrixClientPeg.get().isGuest() || this.props.tag === DefaultTagID.Archived || !this.showContextMenu) {
// the menu makes no sense in these cases so do not show one
return null;
}
@ -397,7 +408,20 @@ export default class RoomTile2 extends React.Component<IProps, IState> {
const favouriteLabel = isFavorite ? _t("Favourited") : _t("Favourite");
let contextMenu = null;
if (this.state.generalMenuPosition) {
if (this.state.generalMenuPosition && this.props.tag === DefaultTagID.Archived) {
contextMenu = (
<ContextMenu {...contextMenuBelow(this.state.generalMenuPosition)} onFinished={this.onCloseGeneralMenu}>
<div className="mx_IconizedContextMenu mx_IconizedContextMenu_compact mx_RoomTile2_contextMenu">
<div className="mx_IconizedContextMenu_optionList mx_RoomTile2_contextMenu_redRow">
<MenuItem onClick={this.onForgetRoomClick} label={_t("Leave Room")}>
<span className="mx_IconizedContextMenu_icon mx_RoomTile2_iconSignOut" />
<span className="mx_IconizedContextMenu_label">{_t("Forget Room")}</span>
</MenuItem>
</div>
</div>
</ContextMenu>
);
} else if (this.state.generalMenuPosition) {
contextMenu = (
<ContextMenu {...contextMenuBelow(this.state.generalMenuPosition)} onFinished={this.onCloseGeneralMenu}>
<div className="mx_IconizedContextMenu mx_IconizedContextMenu_compact mx_RoomTile2_contextMenu">

View file

@ -32,12 +32,12 @@ export default class PreferencesUserSettingsTab extends React.Component {
'breadcrumbs',
];
// TODO: Remove temp structures: https://github.com/vector-im/riot-web/issues/14231
// TODO: Remove temp structures: https://github.com/vector-im/riot-web/issues/14367
static ROOM_LIST_2_SETTINGS = [
'breadcrumbs',
];
// TODO: Remove temp structures: https://github.com/vector-im/riot-web/issues/14231
// TODO: Remove temp structures: https://github.com/vector-im/riot-web/issues/14367
static eligibleRoomListSettings = () => {
if (RoomListStoreTempProxy.isUsingNewStore()) {
return PreferencesUserSettingsTab.ROOM_LIST_2_SETTINGS;