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

This commit is contained in:
Michael Telatynski 2021-09-08 12:57:37 +01:00
commit 1da65d459c
35 changed files with 1110 additions and 376 deletions

View file

@ -158,7 +158,7 @@ export default class ShareDialog extends React.PureComponent<IProps, IState> {
if (this.state.linkSpecificEvent) {
matrixToUrl = this.props.permalinkCreator.forEvent(this.props.target.getId());
} else {
matrixToUrl = this.props.permalinkCreator.forRoom();
matrixToUrl = this.props.permalinkCreator.forShareableRoom();
}
}
return matrixToUrl;

View file

@ -1,5 +1,6 @@
/*
Copyright 2019 Travis Ralston
Copyright 2021 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.
@ -15,42 +16,46 @@ limitations under the License.
*/
import React from 'react';
import PropTypes from 'prop-types';
import { _t } from "../../../languageHandler";
import * as sdk from "../../../index";
import LabelledToggleSwitch from "../elements/LabelledToggleSwitch";
import { Widget } from "matrix-widget-api";
import { Widget, WidgetKind } from "matrix-widget-api";
import { OIDCState, WidgetPermissionStore } from "../../../stores/widgets/WidgetPermissionStore";
import { replaceableComponent } from "../../../utils/replaceableComponent";
import { IDialogProps } from "./IDialogProps";
import BaseDialog from "./BaseDialog";
import DialogButtons from "../elements/DialogButtons";
interface IProps extends IDialogProps {
widget: Widget;
widgetKind: WidgetKind;
inRoomId?: string;
}
interface IState {
rememberSelection: boolean;
}
@replaceableComponent("views.dialogs.WidgetOpenIDPermissionsDialog")
export default class WidgetOpenIDPermissionsDialog extends React.Component {
static propTypes = {
onFinished: PropTypes.func.isRequired,
widget: PropTypes.objectOf(Widget).isRequired,
widgetKind: PropTypes.string.isRequired, // WidgetKind from widget-api
inRoomId: PropTypes.string,
};
constructor() {
super();
export default class WidgetOpenIDPermissionsDialog extends React.PureComponent<IProps, IState> {
constructor(props: IProps) {
super(props);
this.state = {
rememberSelection: false,
};
}
_onAllow = () => {
this._onPermissionSelection(true);
private onAllow = () => {
this.onPermissionSelection(true);
};
_onDeny = () => {
this._onPermissionSelection(false);
private onDeny = () => {
this.onPermissionSelection(false);
};
_onPermissionSelection(allowed) {
private onPermissionSelection(allowed: boolean) {
if (this.state.rememberSelection) {
console.log(`Remembering ${this.props.widgetId} as allowed=${allowed} for OpenID`);
console.log(`Remembering ${this.props.widget.id} as allowed=${allowed} for OpenID`);
WidgetPermissionStore.instance.setOIDCState(
this.props.widget, this.props.widgetKind, this.props.inRoomId,
@ -61,14 +66,11 @@ export default class WidgetOpenIDPermissionsDialog extends React.Component {
this.props.onFinished(allowed);
}
_onRememberSelectionChange = (newVal) => {
private onRememberSelectionChange = (newVal: boolean) => {
this.setState({ rememberSelection: newVal });
};
render() {
const BaseDialog = sdk.getComponent('views.dialogs.BaseDialog');
const DialogButtons = sdk.getComponent('views.elements.DialogButtons');
public render() {
return (
<BaseDialog
className='mx_WidgetOpenIDPermissionsDialog'
@ -87,13 +89,13 @@ export default class WidgetOpenIDPermissionsDialog extends React.Component {
</div>
<DialogButtons
primaryButton={_t("Continue")}
onPrimaryButtonClick={this._onAllow}
onCancel={this._onDeny}
onPrimaryButtonClick={this.onAllow}
onCancel={this.onDeny}
additive={
<LabelledToggleSwitch
value={this.state.rememberSelection}
toggleInFront={true}
onChange={this._onRememberSelectionChange}
onChange={this.onRememberSelectionChange}
label={_t("Remember this")} />}
/>
</BaseDialog>

View file

@ -17,8 +17,7 @@ limitations under the License.
*/
import React, { useEffect } from 'react';
import PropTypes from 'prop-types';
import { EventStatus } from 'matrix-js-sdk/src/models/event';
import { MatrixEvent, EventStatus } from 'matrix-js-sdk/src/models/event';
import { _t } from '../../../languageHandler';
import * as sdk from '../../../index';
@ -37,48 +36,65 @@ import { MatrixClientPeg } from "../../../MatrixClientPeg";
import { MediaEventHelper } from "../../../utils/MediaEventHelper";
import DownloadActionButton from "./DownloadActionButton";
import SettingsStore from '../../../settings/SettingsStore';
import { RoomPermalinkCreator } from '../../../utils/permalinks/Permalinks';
import ReplyThread from '../elements/ReplyThread';
const OptionsButton = ({ mxEvent, getTile, getReplyThread, permalinkCreator, onFocusChange }) => {
const [menuDisplayed, button, openMenu, closeMenu] = useContextMenu();
const [onFocus, isActive, ref] = useRovingTabIndex(button);
useEffect(() => {
onFocusChange(menuDisplayed);
}, [onFocusChange, menuDisplayed]);
interface IOptionsButtonProps {
mxEvent: MatrixEvent;
getTile: () => any; // TODO: FIXME, haven't figured out what the return type is here
getReplyThread: () => ReplyThread;
permalinkCreator: RoomPermalinkCreator;
onFocusChange: (menuDisplayed: boolean) => void;
}
let contextMenu;
if (menuDisplayed) {
const MessageContextMenu = sdk.getComponent('context_menus.MessageContextMenu');
const OptionsButton: React.FC<IOptionsButtonProps> =
({ mxEvent, getTile, getReplyThread, permalinkCreator, onFocusChange }) => {
const [menuDisplayed, button, openMenu, closeMenu] = useContextMenu();
const [onFocus, isActive, ref] = useRovingTabIndex(button);
useEffect(() => {
onFocusChange(menuDisplayed);
}, [onFocusChange, menuDisplayed]);
const tile = getTile && getTile();
const replyThread = getReplyThread && getReplyThread();
let contextMenu;
if (menuDisplayed) {
const MessageContextMenu = sdk.getComponent('context_menus.MessageContextMenu');
const buttonRect = button.current.getBoundingClientRect();
contextMenu = <MessageContextMenu
{...aboveLeftOf(buttonRect)}
mxEvent={mxEvent}
permalinkCreator={permalinkCreator}
eventTileOps={tile && tile.getEventTileOps ? tile.getEventTileOps() : undefined}
collapseReplyThread={replyThread && replyThread.canCollapse() ? replyThread.collapse : undefined}
onFinished={closeMenu}
/>;
}
const tile = getTile && getTile();
const replyThread = getReplyThread && getReplyThread();
return <React.Fragment>
<ContextMenuTooltipButton
className="mx_MessageActionBar_maskButton mx_MessageActionBar_optionsButton"
title={_t("Options")}
onClick={openMenu}
isExpanded={menuDisplayed}
inputRef={ref}
onFocus={onFocus}
tabIndex={isActive ? 0 : -1}
/>
const buttonRect = button.current.getBoundingClientRect();
contextMenu = <MessageContextMenu
{...aboveLeftOf(buttonRect)}
mxEvent={mxEvent}
permalinkCreator={permalinkCreator}
eventTileOps={tile && tile.getEventTileOps ? tile.getEventTileOps() : undefined}
collapseReplyThread={replyThread && replyThread.canCollapse() ? replyThread.collapse : undefined}
onFinished={closeMenu}
/>;
}
{ contextMenu }
</React.Fragment>;
};
return <React.Fragment>
<ContextMenuTooltipButton
className="mx_MessageActionBar_maskButton mx_MessageActionBar_optionsButton"
title={_t("Options")}
onClick={openMenu}
isExpanded={menuDisplayed}
inputRef={ref}
onFocus={onFocus}
tabIndex={isActive ? 0 : -1}
/>
const ReactButton = ({ mxEvent, reactions, onFocusChange }) => {
{ contextMenu }
</React.Fragment>;
};
interface IReactButtonProps {
mxEvent: MatrixEvent;
reactions: any; // TODO: types
onFocusChange: (menuDisplayed: boolean) => void;
}
const ReactButton: React.FC<IReactButtonProps> = ({ mxEvent, reactions, onFocusChange }) => {
const [menuDisplayed, button, openMenu, closeMenu] = useContextMenu();
const [onFocus, isActive, ref] = useRovingTabIndex(button);
useEffect(() => {
@ -109,21 +125,21 @@ const ReactButton = ({ mxEvent, reactions, onFocusChange }) => {
</React.Fragment>;
};
interface IMessageActionBarProps {
mxEvent: MatrixEvent;
// The Relations model from the JS SDK for reactions to `mxEvent`
reactions?: any; // TODO: types
permalinkCreator?: RoomPermalinkCreator;
getTile: () => any; // TODO: FIXME, haven't figured out what the return type is here
getReplyThread?: () => ReplyThread;
onFocusChange?: (menuDisplayed: boolean) => void;
}
@replaceableComponent("views.messages.MessageActionBar")
export default class MessageActionBar extends React.PureComponent {
static propTypes = {
mxEvent: PropTypes.object.isRequired,
// The Relations model from the JS SDK for reactions to `mxEvent`
reactions: PropTypes.object,
permalinkCreator: PropTypes.object,
getTile: PropTypes.func,
getReplyThread: PropTypes.func,
onFocusChange: PropTypes.func,
};
export default class MessageActionBar extends React.PureComponent<IMessageActionBarProps> {
public static contextType = RoomContext;
static contextType = RoomContext;
componentDidMount() {
public componentDidMount(): void {
if (this.props.mxEvent.status && this.props.mxEvent.status !== EventStatus.SENT) {
this.props.mxEvent.on("Event.status", this.onSent);
}
@ -137,43 +153,43 @@ export default class MessageActionBar extends React.PureComponent {
this.props.mxEvent.on("Event.beforeRedaction", this.onBeforeRedaction);
}
componentWillUnmount() {
public componentWillUnmount(): void {
this.props.mxEvent.off("Event.status", this.onSent);
this.props.mxEvent.off("Event.decrypted", this.onDecrypted);
this.props.mxEvent.off("Event.beforeRedaction", this.onBeforeRedaction);
}
onDecrypted = () => {
private onDecrypted = (): void => {
// When an event decrypts, it is likely to change the set of available
// actions, so we force an update to check again.
this.forceUpdate();
};
onBeforeRedaction = () => {
private onBeforeRedaction = (): void => {
// When an event is redacted, we can't edit it so update the available actions.
this.forceUpdate();
};
onSent = () => {
private onSent = (): void => {
// When an event is sent and echoed the possible actions change.
this.forceUpdate();
};
onFocusChange = (focused) => {
private onFocusChange = (focused: boolean): void => {
if (!this.props.onFocusChange) {
return;
}
this.props.onFocusChange(focused);
};
onReplyClick = (ev) => {
private onReplyClick = (ev: React.MouseEvent): void => {
dis.dispatch({
action: 'reply_to_event',
event: this.props.mxEvent,
});
};
onThreadClick = () => {
private onThreadClick = (): void => {
dis.dispatch({
action: Action.SetRightPanelPhase,
phase: RightPanelPhases.ThreadView,
@ -182,9 +198,9 @@ export default class MessageActionBar extends React.PureComponent {
event: this.props.mxEvent,
},
});
}
};
onEditClick = (ev) => {
private onEditClick = (ev: React.MouseEvent): void => {
dis.dispatch({
action: 'edit_event',
event: this.props.mxEvent,
@ -200,7 +216,7 @@ export default class MessageActionBar extends React.PureComponent {
* @param {Function} fn The execution function.
* @param {Function} checkFn The test function.
*/
runActionOnFailedEv(fn, checkFn) {
private runActionOnFailedEv(fn: (ev: MatrixEvent) => void, checkFn?: (ev: MatrixEvent) => boolean): void {
if (!checkFn) checkFn = () => true;
const mxEvent = this.props.mxEvent;
@ -215,18 +231,18 @@ export default class MessageActionBar extends React.PureComponent {
}
}
onResendClick = (ev) => {
private onResendClick = (ev: React.MouseEvent): void => {
this.runActionOnFailedEv((tarEv) => Resend.resend(tarEv));
};
onCancelClick = (ev) => {
private onCancelClick = (ev: React.MouseEvent): void => {
this.runActionOnFailedEv(
(tarEv) => Resend.removeFromQueue(tarEv),
(testEv) => canCancel(testEv.status),
);
};
render() {
public render(): JSX.Element {
const toolbarOpts = [];
if (canEditContent(this.props.mxEvent)) {
toolbarOpts.push(<RovingAccessibleTooltipButton
@ -249,7 +265,7 @@ export default class MessageActionBar extends React.PureComponent {
const editStatus = mxEvent.replacingEvent() && mxEvent.replacingEvent().status;
const redactStatus = mxEvent.localRedactionEvent() && mxEvent.localRedactionEvent().status;
const allowCancel = canCancel(mxEvent.status) || canCancel(editStatus) || canCancel(redactStatus);
const isFailed = [mxEvent.status, editStatus, redactStatus].includes("not_sent");
const isFailed = [mxEvent.status, editStatus, redactStatus].includes(EventStatus.NOT_SENT);
if (allowCancel && isFailed) {
// The resend button needs to appear ahead of the edit button, so insert to the
// start of the opts

View file

@ -72,8 +72,10 @@ export default class HelpUserSettingsTab extends React.Component<IProps, IState>
private getVersionInfo(): { appVersion: string, olmVersion: string } {
const brand = SdkConfig.get().brand;
const appVersion = this.state.appVersion || 'unknown';
let olmVersion = MatrixClientPeg.get().olmVersion;
olmVersion = olmVersion ? `${olmVersion[0]}.${olmVersion[1]}.${olmVersion[2]}` : '<not-enabled>';
const olmVersionTuple = MatrixClientPeg.get().olmVersion;
const olmVersion = olmVersionTuple
? `${olmVersionTuple[0]}.${olmVersionTuple[1]}.${olmVersionTuple[2]}`
: '<not-enabled>';
return {
appVersion: `${_t("%(brand)s version:", { brand })} ${appVersion}`,

View file

@ -195,12 +195,10 @@ const InnerSpacePanel = React.memo<IInnerSpacePanelProps>(({ children, isPanelCo
{ (provided, snapshot) => (
<SpaceItem
{...provided.draggableProps}
{...provided.dragHandleProps}
dragHandleProps={provided.dragHandleProps}
key={s.roomId}
innerRef={provided.innerRef}
className={snapshot.isDragging
? "mx_SpaceItem_dragging"
: undefined}
className={snapshot.isDragging ? "mx_SpaceItem_dragging" : undefined}
space={s}
activeSpaces={activeSpaces}
isPanelCollapsed={isPanelCollapsed}
@ -223,6 +221,8 @@ const SpacePanel = () => {
}, []);
const onKeyDown = (ev: React.KeyboardEvent) => {
if (ev.defaultPrevented) return;
let handled = true;
switch (ev.key) {

View file

@ -39,7 +39,7 @@ const SpacePublicShare = ({ space, onFinished }: IProps) => {
onClick={async () => {
const permalinkCreator = new RoomPermalinkCreator(space);
permalinkCreator.load();
const success = await copyPlaintext(permalinkCreator.forRoom());
const success = await copyPlaintext(permalinkCreator.forShareableRoom());
const text = success ? _t("Copied!") : _t("Failed to copy");
setCopiedText(text);
await sleep(5000);

View file

@ -29,7 +29,6 @@ import RoomAvatar from "../avatars/RoomAvatar";
import SpaceStore from "../../../stores/SpaceStore";
import SpaceTreeLevelLayoutStore from "../../../stores/SpaceTreeLevelLayoutStore";
import NotificationBadge from "../rooms/NotificationBadge";
import { RovingAccessibleTooltipButton } from "../../../accessibility/roving/RovingAccessibleTooltipButton";
import { _t } from "../../../languageHandler";
import { ContextMenuTooltipButton } from "../../../accessibility/context_menu/ContextMenuTooltipButton";
import { toRightOf, useContextMenu } from "../../structures/ContextMenu";
@ -40,8 +39,11 @@ import { NotificationColor } from "../../../stores/notifications/NotificationCol
import { getKeyBindingsManager, RoomListAction } from "../../../KeyBindingsManager";
import { NotificationState } from "../../../stores/notifications/NotificationState";
import SpaceContextMenu from "../context_menus/SpaceContextMenu";
import AccessibleTooltipButton from "../elements/AccessibleTooltipButton";
import { DraggableProvidedDragHandleProps } from "react-beautiful-dnd";
import { useRovingTabIndex } from "../../../accessibility/RovingTabIndex";
interface IButtonProps extends Omit<ComponentProps<typeof RovingAccessibleTooltipButton>, "title"> {
interface IButtonProps extends Omit<ComponentProps<typeof AccessibleTooltipButton>, "title"> {
space?: Room;
className?: string;
selected?: boolean;
@ -68,7 +70,9 @@ export const SpaceButton: React.FC<IButtonProps> = ({
ContextMenuComponent,
...props
}) => {
const [menuDisplayed, handle, openMenu, closeMenu] = useContextMenu<HTMLElement>();
const [menuDisplayed, ref, openMenu, closeMenu] = useContextMenu<HTMLElement>();
const [onFocus, isActive, handle] = useRovingTabIndex(ref);
const tabIndex = isActive ? 0 : -1;
let avatar = <div className="mx_SpaceButton_avatarPlaceholder"><div className="mx_SpaceButton_icon" /></div>;
if (space) {
@ -88,6 +92,7 @@ export const SpaceButton: React.FC<IButtonProps> = ({
forceCount={false}
notification={notificationState}
aria-label={ariaLabel}
tabIndex={tabIndex}
/>
</div>;
}
@ -102,7 +107,7 @@ export const SpaceButton: React.FC<IButtonProps> = ({
}
return (
<RovingAccessibleTooltipButton
<AccessibleTooltipButton
{...props}
className={classNames("mx_SpaceButton", className, {
mx_SpaceButton_active: selected,
@ -114,6 +119,8 @@ export const SpaceButton: React.FC<IButtonProps> = ({
onContextMenu={openMenu}
forceHide={!isNarrow || menuDisplayed}
inputRef={handle}
tabIndex={tabIndex}
onFocus={onFocus}
>
{ children }
<div className="mx_SpaceButton_selectionWrapper">
@ -130,7 +137,7 @@ export const SpaceButton: React.FC<IButtonProps> = ({
{ contextMenu }
</div>
</RovingAccessibleTooltipButton>
</AccessibleTooltipButton>
);
};
@ -142,6 +149,7 @@ interface IItemProps extends InputHTMLAttributes<HTMLLIElement> {
onExpand?: Function;
parents?: Set<string>;
innerRef?: LegacyRef<HTMLLIElement>;
dragHandleProps?: DraggableProvidedDragHandleProps;
}
interface IItemState {
@ -270,8 +278,10 @@ export class SpaceItem extends React.PureComponent<IItemProps, IItemState> {
? StaticNotificationState.forSymbol("!", NotificationColor.Red)
: SpaceStore.instance.getNotificationState(space.roomId);
const hasChildren = this.state.childSpaces?.length;
let childItems;
if (this.state.childSpaces?.length && !collapsed) {
if (hasChildren && !collapsed) {
childItems = <SpaceTreeLevel
spaces={this.state.childSpaces}
activeSpaces={activeSpaces}
@ -280,7 +290,7 @@ export class SpaceItem extends React.PureComponent<IItemProps, IItemState> {
/>;
}
const toggleCollapseButton = this.state.childSpaces?.length ?
const toggleCollapseButton = hasChildren ?
<AccessibleButton
className="mx_SpaceButton_toggleCollapse"
onClick={this.toggleCollapse}
@ -288,9 +298,19 @@ export class SpaceItem extends React.PureComponent<IItemProps, IItemState> {
aria-label={collapsed ? _t("Expand") : _t("Collapse")}
/> : null;
// eslint-disable-next-line @typescript-eslint/no-unused-vars
const { tabIndex, ...dragHandleProps } = this.props.dragHandleProps || {};
return (
<li {...otherProps} className={itemClasses} ref={innerRef} aria-expanded={!collapsed} role="treeitem">
<li
{...otherProps}
className={itemClasses}
ref={innerRef}
aria-expanded={hasChildren ? !collapsed : undefined}
role="treeitem"
>
<SpaceButton
{...dragHandleProps}
space={space}
className={isInvite ? "mx_SpaceButton_invite" : undefined}
selected={activeSpaces.includes(space)}