Merge branch 'develop' into revert-6752-revert-6682-gsouquet/compact-composer-18533
This commit is contained in:
commit
2d45bfb976
22 changed files with 954 additions and 331 deletions
|
@ -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>
|
|
@ -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
|
|
@ -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}`,
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue