mirror of
https://github.com/element-hq/element-web.git
synced 2024-12-18 07:22:08 +03:00
Merge branch 'develop' of github.com:matrix-org/matrix-react-sdk into room-preview-spaces
This commit is contained in:
commit
cf9edb1884
97 changed files with 819 additions and 568 deletions
|
@ -15,7 +15,6 @@ module.exports = {
|
|||
"prefer-promise-reject-errors": "off",
|
||||
"no-async-promise-executor": "off",
|
||||
"quotes": "off",
|
||||
"indent": "off",
|
||||
},
|
||||
|
||||
overrides: [{
|
||||
|
|
|
@ -34,6 +34,10 @@ limitations under the License.
|
|||
border-color: $reaction-row-button-selected-border-color;
|
||||
}
|
||||
|
||||
&.mx_AccessibleButton_disabled {
|
||||
cursor: not-allowed;
|
||||
}
|
||||
|
||||
.mx_ReactionsRowButton_content {
|
||||
max-width: 100px;
|
||||
overflow: hidden;
|
||||
|
|
|
@ -148,13 +148,15 @@ function _onGroupAddRoomFinished(groupId, addrs, addRoomsPublicly) {
|
|||
const ErrorDialog = sdk.getComponent("dialogs.ErrorDialog");
|
||||
Modal.createTrackedDialog(
|
||||
'Failed to add the following room to the group',
|
||||
'', ErrorDialog,
|
||||
'',
|
||||
ErrorDialog,
|
||||
{
|
||||
title: _t(
|
||||
"Failed to add the following rooms to %(groupId)s:",
|
||||
{groupId},
|
||||
),
|
||||
description: errorList.join(", "),
|
||||
});
|
||||
},
|
||||
);
|
||||
});
|
||||
}
|
||||
|
|
|
@ -547,17 +547,23 @@ function textForMjolnirEvent(event) {
|
|||
|
||||
// else the entity !== prevEntity - count as a removal & add
|
||||
if (USER_RULE_TYPES.includes(event.getType())) {
|
||||
return _t("%(senderName)s changed a rule that was banning users matching %(oldGlob)s to matching " +
|
||||
return _t(
|
||||
"%(senderName)s changed a rule that was banning users matching %(oldGlob)s to matching " +
|
||||
"%(newGlob)s for %(reason)s",
|
||||
{senderName, oldGlob: prevEntity, newGlob: entity, reason});
|
||||
{senderName, oldGlob: prevEntity, newGlob: entity, reason},
|
||||
);
|
||||
} else if (ROOM_RULE_TYPES.includes(event.getType())) {
|
||||
return _t("%(senderName)s changed a rule that was banning rooms matching %(oldGlob)s to matching " +
|
||||
return _t(
|
||||
"%(senderName)s changed a rule that was banning rooms matching %(oldGlob)s to matching " +
|
||||
"%(newGlob)s for %(reason)s",
|
||||
{senderName, oldGlob: prevEntity, newGlob: entity, reason});
|
||||
{senderName, oldGlob: prevEntity, newGlob: entity, reason},
|
||||
);
|
||||
} else if (SERVER_RULE_TYPES.includes(event.getType())) {
|
||||
return _t("%(senderName)s changed a rule that was banning servers matching %(oldGlob)s to matching " +
|
||||
return _t(
|
||||
"%(senderName)s changed a rule that was banning servers matching %(oldGlob)s to matching " +
|
||||
"%(newGlob)s for %(reason)s",
|
||||
{senderName, oldGlob: prevEntity, newGlob: entity, reason});
|
||||
{senderName, oldGlob: prevEntity, newGlob: entity, reason},
|
||||
);
|
||||
}
|
||||
|
||||
// Unknown type. We'll say something but we shouldn't end up here.
|
||||
|
|
|
@ -170,7 +170,10 @@ export default class ExportE2eKeysDialog extends React.Component {
|
|||
</div>
|
||||
</div>
|
||||
<div className='mx_Dialog_buttons'>
|
||||
<input className='mx_Dialog_primary' type='submit' value={_t('Export')}
|
||||
<input
|
||||
className='mx_Dialog_primary'
|
||||
type='submit'
|
||||
value={_t('Export')}
|
||||
disabled={disableForm}
|
||||
/>
|
||||
<button onClick={this._onCancelClick} disabled={disableForm}>
|
||||
|
|
|
@ -110,14 +110,16 @@ class CategoryRoomList extends React.Component {
|
|||
const ErrorDialog = sdk.getComponent("dialogs.ErrorDialog");
|
||||
Modal.createTrackedDialog(
|
||||
'Failed to add the following room to the group summary',
|
||||
'', ErrorDialog,
|
||||
'',
|
||||
ErrorDialog,
|
||||
{
|
||||
title: _t(
|
||||
"Failed to add the following rooms to the summary of %(groupId)s:",
|
||||
{groupId: this.props.groupId},
|
||||
),
|
||||
description: errorList.join(", "),
|
||||
});
|
||||
},
|
||||
);
|
||||
});
|
||||
},
|
||||
}, /*className=*/null, /*isPriority=*/false, /*isStatic=*/true);
|
||||
|
@ -196,7 +198,8 @@ class FeaturedRoom extends React.Component {
|
|||
{groupId: this.props.groupId},
|
||||
),
|
||||
description: _t("The room '%(roomName)s' could not be removed from the summary.", {roomName}),
|
||||
});
|
||||
},
|
||||
);
|
||||
});
|
||||
};
|
||||
|
||||
|
@ -289,7 +292,8 @@ class RoleUserList extends React.Component {
|
|||
{groupId: this.props.groupId},
|
||||
),
|
||||
description: errorList.join(", "),
|
||||
});
|
||||
},
|
||||
);
|
||||
});
|
||||
},
|
||||
}, /*className=*/null, /*isPriority=*/false, /*isStatic=*/true);
|
||||
|
@ -352,14 +356,16 @@ class FeaturedUser extends React.Component {
|
|||
const ErrorDialog = sdk.getComponent("dialogs.ErrorDialog");
|
||||
Modal.createTrackedDialog(
|
||||
'Failed to remove user from community summary',
|
||||
'', ErrorDialog,
|
||||
'',
|
||||
ErrorDialog,
|
||||
{
|
||||
title: _t(
|
||||
"Failed to remove a user from the summary of %(groupId)s",
|
||||
{groupId: this.props.groupId},
|
||||
),
|
||||
description: _t("The user '%(displayName)s' could not be removed from the summary.", {displayName}),
|
||||
});
|
||||
},
|
||||
);
|
||||
});
|
||||
};
|
||||
|
||||
|
@ -1055,7 +1061,8 @@ export default class GroupView extends React.Component {
|
|||
return null;
|
||||
}
|
||||
|
||||
const membershipButtonClasses = classnames([
|
||||
const membershipButtonClasses = classnames(
|
||||
[
|
||||
'mx_RoomHeader_textButton',
|
||||
'mx_GroupView_textButton',
|
||||
],
|
||||
|
|
|
@ -347,7 +347,7 @@ export default class LeftPanel extends React.Component<IProps, IState> {
|
|||
if (element) {
|
||||
classes = element.classList;
|
||||
}
|
||||
} while (element && !cssClasses.some(c => classes.contains(c)));
|
||||
} while (element && (!cssClasses.some(c => classes.contains(c)) || element.offsetParent === null));
|
||||
|
||||
if (element) {
|
||||
element.focus();
|
||||
|
|
|
@ -427,8 +427,10 @@ export default class MessagePanel extends React.Component {
|
|||
// we get a new DOM node (restarting the animation) when the ghost
|
||||
// moves to a different event.
|
||||
return (
|
||||
<li key={"_readuptoghost_"+eventId}
|
||||
className="mx_RoomView_myReadMarker_container">
|
||||
<li
|
||||
key={"_readuptoghost_"+eventId}
|
||||
className="mx_RoomView_myReadMarker_container"
|
||||
>
|
||||
{ hr }
|
||||
</li>
|
||||
);
|
||||
|
|
|
@ -17,6 +17,8 @@ limitations under the License.
|
|||
import * as React from "react";
|
||||
import { createRef } from "react";
|
||||
import classNames from "classnames";
|
||||
import { Room } from "matrix-js-sdk/src/models/room";
|
||||
|
||||
import defaultDispatcher from "../../dispatcher/dispatcher";
|
||||
import { _t } from "../../languageHandler";
|
||||
import { ActionPayload } from "../../dispatcher/payloads";
|
||||
|
@ -26,7 +28,7 @@ import RoomListStore from "../../stores/room-list/RoomListStore";
|
|||
import { NameFilterCondition } from "../../stores/room-list/filters/NameFilterCondition";
|
||||
import { getKeyBindingsManager, RoomListAction } from "../../KeyBindingsManager";
|
||||
import {replaceableComponent} from "../../utils/replaceableComponent";
|
||||
import SpaceStore, {UPDATE_SELECTED_SPACE} from "../../stores/SpaceStore";
|
||||
import SpaceStore, {UPDATE_SELECTED_SPACE, UPDATE_TOP_LEVEL_SPACES} from "../../stores/SpaceStore";
|
||||
|
||||
interface IProps {
|
||||
isMinimized: boolean;
|
||||
|
@ -40,6 +42,7 @@ interface IProps {
|
|||
interface IState {
|
||||
query: string;
|
||||
focused: boolean;
|
||||
inSpaces: boolean;
|
||||
}
|
||||
|
||||
@replaceableComponent("structures.RoomSearch")
|
||||
|
@ -54,11 +57,13 @@ export default class RoomSearch extends React.PureComponent<IProps, IState> {
|
|||
this.state = {
|
||||
query: "",
|
||||
focused: false,
|
||||
inSpaces: false,
|
||||
};
|
||||
|
||||
this.dispatcherRef = defaultDispatcher.register(this.onAction);
|
||||
// clear filter when changing spaces, in future we may wish to maintain a filter per-space
|
||||
SpaceStore.instance.on(UPDATE_SELECTED_SPACE, this.clearInput);
|
||||
SpaceStore.instance.on(UPDATE_TOP_LEVEL_SPACES, this.onSpaces);
|
||||
}
|
||||
|
||||
public componentDidUpdate(prevProps: Readonly<IProps>, prevState: Readonly<IState>): void {
|
||||
|
@ -79,8 +84,15 @@ export default class RoomSearch extends React.PureComponent<IProps, IState> {
|
|||
public componentWillUnmount() {
|
||||
defaultDispatcher.unregister(this.dispatcherRef);
|
||||
SpaceStore.instance.off(UPDATE_SELECTED_SPACE, this.clearInput);
|
||||
SpaceStore.instance.off(UPDATE_TOP_LEVEL_SPACES, this.onSpaces);
|
||||
}
|
||||
|
||||
private onSpaces = (spaces: Room[]) => {
|
||||
this.setState({
|
||||
inSpaces: spaces.length > 0,
|
||||
});
|
||||
};
|
||||
|
||||
private onAction = (payload: ActionPayload) => {
|
||||
if (payload.action === 'view_room' && payload.clear_search) {
|
||||
this.clearInput();
|
||||
|
@ -152,6 +164,11 @@ export default class RoomSearch extends React.PureComponent<IProps, IState> {
|
|||
'mx_RoomSearch_inputExpanded': this.state.query || this.state.focused,
|
||||
});
|
||||
|
||||
let placeholder = _t("Filter");
|
||||
if (this.state.inSpaces) {
|
||||
placeholder = _t("Filter all spaces");
|
||||
}
|
||||
|
||||
let icon = (
|
||||
<div className='mx_RoomSearch_icon' />
|
||||
);
|
||||
|
@ -165,7 +182,7 @@ export default class RoomSearch extends React.PureComponent<IProps, IState> {
|
|||
onBlur={this.onBlur}
|
||||
onChange={this.onChange}
|
||||
onKeyDown={this.onKeyDown}
|
||||
placeholder={_t("Filter")}
|
||||
placeholder={placeholder}
|
||||
autoComplete="off"
|
||||
/>
|
||||
);
|
||||
|
|
|
@ -200,7 +200,8 @@ export default class RoomStatusBar extends React.Component {
|
|||
} else if (resourceLimitError) {
|
||||
title = messageForResourceLimitError(
|
||||
resourceLimitError.data.limit_type,
|
||||
resourceLimitError.data.admin_contact, {
|
||||
resourceLimitError.data.admin_contact,
|
||||
{
|
||||
'monthly_active_user': _td(
|
||||
"Your message wasn't sent because this homeserver has hit its Monthly Active User Limit. " +
|
||||
"Please <a>contact your service administrator</a> to continue using the service.",
|
||||
|
@ -213,7 +214,8 @@ export default class RoomStatusBar extends React.Component {
|
|||
"Your message wasn't sent because this homeserver has exceeded a resource limit. " +
|
||||
"Please <a>contact your service administrator</a> to continue using the service.",
|
||||
),
|
||||
});
|
||||
},
|
||||
);
|
||||
} else {
|
||||
title = _t('Some of your messages have not been sent');
|
||||
}
|
||||
|
|
|
@ -190,6 +190,9 @@ export interface IState {
|
|||
rejectError?: Error;
|
||||
hasPinnedWidgets?: boolean;
|
||||
dragCounter: number;
|
||||
// whether or not a spaces context switch brought us here,
|
||||
// if it did we don't want the room to be marked as read as soon as it is loaded.
|
||||
wasContextSwitch?: boolean;
|
||||
}
|
||||
|
||||
@replaceableComponent("structures.RoomView")
|
||||
|
@ -326,6 +329,7 @@ export default class RoomView extends React.Component<IProps, IState> {
|
|||
shouldPeek: this.state.matrixClientIsReady && RoomViewStore.shouldPeek(),
|
||||
showingPinned: SettingsStore.getValue("PinnedEvents.isOpen", roomId),
|
||||
showReadReceipts: SettingsStore.getValue("showReadReceipts", roomId),
|
||||
wasContextSwitch: RoomViewStore.getWasContextSwitch(),
|
||||
};
|
||||
|
||||
if (!initial && this.state.shouldPeek && !newState.shouldPeek) {
|
||||
|
@ -2014,6 +2018,7 @@ export default class RoomView extends React.Component<IProps, IState> {
|
|||
timelineSet={this.state.room.getUnfilteredTimelineSet()}
|
||||
showReadReceipts={this.state.showReadReceipts}
|
||||
manageReadReceipts={!this.state.isPeeking}
|
||||
sendReadReceiptOnLoad={!this.state.wasContextSwitch}
|
||||
manageReadMarkers={!this.state.isPeeking}
|
||||
hidden={hideMessagePanel}
|
||||
highlightedEventId={highlightedEventId}
|
||||
|
|
|
@ -884,9 +884,13 @@ export default class ScrollPanel extends React.Component {
|
|||
|
||||
// give the <ol> an explicit role=list because Safari+VoiceOver seems to think an ordered-list with
|
||||
// list-style-type: none; is no longer a list
|
||||
return (<AutoHideScrollbar wrappedRef={this._collectScroll}
|
||||
return (
|
||||
<AutoHideScrollbar
|
||||
wrappedRef={this._collectScroll}
|
||||
onScroll={this.onScroll}
|
||||
className={`mx_ScrollPanel ${this.props.className}`} style={this.props.style}>
|
||||
className={`mx_ScrollPanel ${this.props.className}`}
|
||||
style={this.props.style}
|
||||
>
|
||||
{ this.props.fixedChildren }
|
||||
<div className="mx_RoomView_messageListWrapper">
|
||||
<ol ref={this._itemlist} className="mx_RoomView_MessageList" aria-live="polite" role="list">
|
||||
|
|
|
@ -68,6 +68,7 @@ class TimelinePanel extends React.Component {
|
|||
showReadReceipts: PropTypes.bool,
|
||||
// Enable managing RRs and RMs. These require the timelineSet to have a room.
|
||||
manageReadReceipts: PropTypes.bool,
|
||||
sendReadReceiptOnLoad: PropTypes.bool,
|
||||
manageReadMarkers: PropTypes.bool,
|
||||
|
||||
// true to give the component a 'display: none' style.
|
||||
|
@ -126,6 +127,7 @@ class TimelinePanel extends React.Component {
|
|||
// event tile heights. (See _unpaginateEvents)
|
||||
timelineCap: Number.MAX_VALUE,
|
||||
className: 'mx_RoomView_messagePanel',
|
||||
sendReadReceiptOnLoad: true,
|
||||
};
|
||||
|
||||
constructor(props) {
|
||||
|
@ -785,8 +787,10 @@ class TimelinePanel extends React.Component {
|
|||
return;
|
||||
}
|
||||
const lastDisplayedEvent = this.state.events[lastDisplayedIndex];
|
||||
this._setReadMarker(lastDisplayedEvent.getId(),
|
||||
lastDisplayedEvent.getTs());
|
||||
this._setReadMarker(
|
||||
lastDisplayedEvent.getId(),
|
||||
lastDisplayedEvent.getTs(),
|
||||
);
|
||||
|
||||
// the read-marker should become invisible, so that if the user scrolls
|
||||
// down, they don't see it.
|
||||
|
@ -1049,7 +1053,9 @@ class TimelinePanel extends React.Component {
|
|||
this._messagePanel.current.scrollToBottom();
|
||||
}
|
||||
|
||||
if (this.props.sendReadReceiptOnLoad) {
|
||||
this.sendReadReceipt();
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
|
|
|
@ -39,9 +39,12 @@ export default class ConfirmWipeDeviceDialog extends React.Component {
|
|||
const DialogButtons = sdk.getComponent('views.elements.DialogButtons');
|
||||
|
||||
return (
|
||||
<BaseDialog className='mx_ConfirmWipeDeviceDialog' hasCancel={true}
|
||||
<BaseDialog
|
||||
className='mx_ConfirmWipeDeviceDialog'
|
||||
hasCancel={true}
|
||||
onFinished={this.props.onFinished}
|
||||
title={_t("Clear all data in this session?")}>
|
||||
title={_t("Clear all data in this session?")}
|
||||
>
|
||||
<div className='mx_ConfirmWipeDeviceDialog_content'>
|
||||
<p>
|
||||
{_t(
|
||||
|
|
|
@ -70,8 +70,16 @@ class GenericEditor extends React.PureComponent {
|
|||
}
|
||||
|
||||
textInput(id, label) {
|
||||
return <Field id={id} label={label} size="42" autoFocus={true} type="text" autoComplete="on"
|
||||
value={this.state[id]} onChange={this._onChange} />;
|
||||
return <Field
|
||||
id={id}
|
||||
label={label}
|
||||
size="42"
|
||||
autoFocus={true}
|
||||
type="text"
|
||||
autoComplete="on"
|
||||
value={this.state[id]}
|
||||
onChange={this._onChange}
|
||||
/>;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -42,9 +42,12 @@ export default class IntegrationsDisabledDialog extends React.Component {
|
|||
const DialogButtons = sdk.getComponent('views.elements.DialogButtons');
|
||||
|
||||
return (
|
||||
<BaseDialog className='mx_IntegrationsDisabledDialog' hasCancel={true}
|
||||
<BaseDialog
|
||||
className='mx_IntegrationsDisabledDialog'
|
||||
hasCancel={true}
|
||||
onFinished={this.props.onFinished}
|
||||
title={_t("Integrations are disabled")}>
|
||||
title={_t("Integrations are disabled")}
|
||||
>
|
||||
<div className='mx_IntegrationsDisabledDialog_content'>
|
||||
<p>{_t("Enable 'Manage Integrations' in Settings to do this.")}</p>
|
||||
</div>
|
||||
|
|
|
@ -37,9 +37,12 @@ export default class IntegrationsImpossibleDialog extends React.Component {
|
|||
const DialogButtons = sdk.getComponent('views.elements.DialogButtons');
|
||||
|
||||
return (
|
||||
<BaseDialog className='mx_IntegrationsImpossibleDialog' hasCancel={false}
|
||||
<BaseDialog
|
||||
className='mx_IntegrationsImpossibleDialog'
|
||||
hasCancel={false}
|
||||
onFinished={this.props.onFinished}
|
||||
title={_t("Integrations not allowed")}>
|
||||
title={_t("Integrations not allowed")}
|
||||
>
|
||||
<div className='mx_IntegrationsImpossibleDialog_content'>
|
||||
<p>
|
||||
{_t(
|
||||
|
|
|
@ -164,8 +164,12 @@ export default class MessageEditHistoryDialog extends React.PureComponent {
|
|||
}
|
||||
const BaseDialog = sdk.getComponent('views.dialogs.BaseDialog');
|
||||
return (
|
||||
<BaseDialog className='mx_MessageEditHistoryDialog' hasCancel={true}
|
||||
onFinished={this.props.onFinished} title={_t("Message edits")}>
|
||||
<BaseDialog
|
||||
className='mx_MessageEditHistoryDialog'
|
||||
hasCancel={true}
|
||||
onFinished={this.props.onFinished}
|
||||
title={_t("Message edits")}
|
||||
>
|
||||
{content}
|
||||
</BaseDialog>
|
||||
);
|
||||
|
|
|
@ -116,8 +116,12 @@ export default class RoomSettingsDialog extends React.Component {
|
|||
|
||||
const roomName = MatrixClientPeg.get().getRoom(this.props.roomId).name;
|
||||
return (
|
||||
<BaseDialog className='mx_RoomSettingsDialog' hasCancel={true}
|
||||
onFinished={this.props.onFinished} title={_t("Room Settings - %(roomName)s", {roomName})}>
|
||||
<BaseDialog
|
||||
className='mx_RoomSettingsDialog'
|
||||
hasCancel={true}
|
||||
onFinished={this.props.onFinished}
|
||||
title={_t("Room Settings - %(roomName)s", {roomName})}
|
||||
>
|
||||
<div className='mx_SettingsDialog_content'>
|
||||
<TabbedView tabs={this._getTabs()} />
|
||||
</div>
|
||||
|
|
|
@ -45,10 +45,12 @@ export default class StorageEvictedDialog extends React.Component {
|
|||
let logRequest;
|
||||
if (SdkConfig.get().bug_report_endpoint_url) {
|
||||
logRequest = _t(
|
||||
"To help us prevent this in future, please <a>send us logs</a>.", {},
|
||||
"To help us prevent this in future, please <a>send us logs</a>.",
|
||||
{},
|
||||
{
|
||||
a: text => <a href="#" onClick={this._sendBugReport}>{text}</a>,
|
||||
});
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
|
|
|
@ -155,8 +155,12 @@ export default class UserSettingsDialog extends React.Component {
|
|||
const BaseDialog = sdk.getComponent('views.dialogs.BaseDialog');
|
||||
|
||||
return (
|
||||
<BaseDialog className='mx_UserSettingsDialog' hasCancel={true}
|
||||
onFinished={this.props.onFinished} title={_t("Settings")}>
|
||||
<BaseDialog
|
||||
className='mx_UserSettingsDialog'
|
||||
hasCancel={true}
|
||||
onFinished={this.props.onFinished}
|
||||
title={_t("Settings")}
|
||||
>
|
||||
<div className='mx_SettingsDialog_content'>
|
||||
<TabbedView tabs={this._getTabs()} initialTabId={this.props.initialTabId} />
|
||||
</div>
|
||||
|
|
|
@ -52,7 +52,9 @@ export default class VerificationRequestDialog extends React.Component {
|
|||
const title = request && request.isSelfVerification ?
|
||||
_t("Verify other login") : _t("Verification Request");
|
||||
|
||||
return <BaseDialog className="mx_InfoDialog" onFinished={this.props.onFinished}
|
||||
return <BaseDialog
|
||||
className="mx_InfoDialog"
|
||||
onFinished={this.props.onFinished}
|
||||
contentId="mx_Dialog_content"
|
||||
title={title}
|
||||
hasCancel={true}
|
||||
|
|
|
@ -70,9 +70,12 @@ export default class WidgetOpenIDPermissionsDialog extends React.Component {
|
|||
const DialogButtons = sdk.getComponent('views.elements.DialogButtons');
|
||||
|
||||
return (
|
||||
<BaseDialog className='mx_WidgetOpenIDPermissionsDialog' hasCancel={true}
|
||||
<BaseDialog
|
||||
className='mx_WidgetOpenIDPermissionsDialog'
|
||||
hasCancel={true}
|
||||
onFinished={this.props.onFinished}
|
||||
title={_t("Allow this widget to verify your identity")}>
|
||||
title={_t("Allow this widget to verify your identity")}
|
||||
>
|
||||
<div className='mx_WidgetOpenIDPermissionsDialog_content'>
|
||||
<p>
|
||||
{_t("The widget will verify your user ID, but won't be able to perform actions for you:")}
|
||||
|
|
|
@ -43,7 +43,8 @@ export default class ConfirmDestroyCrossSigningDialog extends React.Component {
|
|||
className='mx_ConfirmDestroyCrossSigningDialog'
|
||||
hasCancel={true}
|
||||
onFinished={this.props.onFinished}
|
||||
title={_t("Destroy cross-signing keys?")}>
|
||||
title={_t("Destroy cross-signing keys?")}
|
||||
>
|
||||
<div className='mx_ConfirmDestroyCrossSigningDialog_content'>
|
||||
<p>
|
||||
{_t(
|
||||
|
|
|
@ -373,15 +373,18 @@ export default class RestoreKeyBackupDialog extends React.PureComponent {
|
|||
{_t(
|
||||
"If you've forgotten your Security Phrase you can "+
|
||||
"<button1>use your Security Key</button1> or " +
|
||||
"<button2>set up new recovery options</button2>"
|
||||
, {}, {
|
||||
button1: s => <AccessibleButton className="mx_linkButton"
|
||||
"<button2>set up new recovery options</button2>",
|
||||
{},
|
||||
{
|
||||
button1: s => <AccessibleButton
|
||||
className="mx_linkButton"
|
||||
element="span"
|
||||
onClick={this._onUseRecoveryKeyClick}
|
||||
>
|
||||
{s}
|
||||
</AccessibleButton>,
|
||||
button2: s => <AccessibleButton className="mx_linkButton"
|
||||
button2: s => <AccessibleButton
|
||||
className="mx_linkButton"
|
||||
element="span"
|
||||
onClick={this._onResetRecoveryClick}
|
||||
>
|
||||
|
@ -435,15 +438,17 @@ export default class RestoreKeyBackupDialog extends React.PureComponent {
|
|||
</div>
|
||||
{_t(
|
||||
"If you've forgotten your Security Key you can "+
|
||||
"<button>set up new recovery options</button>"
|
||||
, {}, {
|
||||
"<button>set up new recovery options</button>",
|
||||
{},
|
||||
{
|
||||
button: s => <AccessibleButton className="mx_linkButton"
|
||||
element="span"
|
||||
onClick={this._onResetRecoveryClick}
|
||||
>
|
||||
{s}
|
||||
</AccessibleButton>,
|
||||
})}
|
||||
},
|
||||
)}
|
||||
</div>;
|
||||
}
|
||||
|
||||
|
|
|
@ -65,12 +65,18 @@ export class EditableItem extends React.Component {
|
|||
<span className="mx_EditableItem_promptText">
|
||||
{_t("Are you sure?")}
|
||||
</span>
|
||||
<AccessibleButton onClick={this._onActuallyRemove} kind="primary_sm"
|
||||
className="mx_EditableItem_confirmBtn">
|
||||
<AccessibleButton
|
||||
onClick={this._onActuallyRemove}
|
||||
kind="primary_sm"
|
||||
className="mx_EditableItem_confirmBtn"
|
||||
>
|
||||
{_t("Yes")}
|
||||
</AccessibleButton>
|
||||
<AccessibleButton onClick={this._onDontRemove} kind="danger_sm"
|
||||
className="mx_EditableItem_confirmBtn">
|
||||
<AccessibleButton
|
||||
onClick={this._onDontRemove}
|
||||
kind="danger_sm"
|
||||
className="mx_EditableItem_confirmBtn"
|
||||
>
|
||||
{_t("No")}
|
||||
</AccessibleButton>
|
||||
</div>
|
||||
|
@ -121,8 +127,12 @@ export default class EditableItemList extends React.Component {
|
|||
|
||||
_renderNewItemField() {
|
||||
return (
|
||||
<form onSubmit={this._onItemAdded} autoComplete="off"
|
||||
noValidate={true} className="mx_EditableItemList_newItem">
|
||||
<form
|
||||
onSubmit={this._onItemAdded}
|
||||
autoComplete="off"
|
||||
noValidate={true}
|
||||
className="mx_EditableItemList_newItem"
|
||||
>
|
||||
<Field label={this.props.placeholder} type="text"
|
||||
autoComplete="off" value={this.props.newItem || ""} onChange={this._onNewItemChanged}
|
||||
list={this.props.suggestionsListId} />
|
||||
|
|
|
@ -221,13 +221,15 @@ export default class EditableText extends React.Component {
|
|||
</div>;
|
||||
} else {
|
||||
// show the content editable div, but manually manage its contents as react and contentEditable don't play nice together
|
||||
editableEl = <div ref={this._editable_div}
|
||||
editableEl = <div
|
||||
ref={this._editable_div}
|
||||
contentEditable={true}
|
||||
className={className}
|
||||
onKeyDown={this.onKeyDown}
|
||||
onKeyUp={this.onKeyUp}
|
||||
onFocus={this.onFocus}
|
||||
onBlur={this.onBlur} />;
|
||||
onBlur={this.onBlur}
|
||||
/>;
|
||||
}
|
||||
|
||||
return editableEl;
|
||||
|
|
|
@ -46,8 +46,12 @@ export default class LabelledToggleSwitch extends React.Component {
|
|||
// This is a minimal version of a SettingsFlag
|
||||
|
||||
let firstPart = <span className="mx_SettingsFlag_label">{this.props.label}</span>;
|
||||
let secondPart = <ToggleSwitch checked={this.props.value} disabled={this.props.disabled}
|
||||
onChange={this.props.onChange} aria-label={this.props.label} />;
|
||||
let secondPart = <ToggleSwitch
|
||||
checked={this.props.value}
|
||||
disabled={this.props.disabled}
|
||||
onChange={this.props.onChange}
|
||||
aria-label={this.props.label}
|
||||
/>;
|
||||
|
||||
if (this.props.toggleInFront) {
|
||||
const temp = firstPart;
|
||||
|
|
|
@ -136,8 +136,12 @@ export default class PowerSelector extends React.Component {
|
|||
picker = (
|
||||
<Field type="number"
|
||||
label={label} max={this.props.maxValue}
|
||||
onBlur={this.onCustomBlur} onKeyDown={this.onCustomKeyDown} onChange={this.onCustomChange}
|
||||
value={String(this.state.customValue)} disabled={this.props.disabled} />
|
||||
onBlur={this.onCustomBlur}
|
||||
onKeyDown={this.onCustomKeyDown}
|
||||
onChange={this.onCustomChange}
|
||||
value={String(this.state.customValue)}
|
||||
disabled={this.props.disabled}
|
||||
/>
|
||||
);
|
||||
} else {
|
||||
// Each level must have a definition in this.state.levelRoleMap
|
||||
|
@ -155,7 +159,8 @@ export default class PowerSelector extends React.Component {
|
|||
picker = (
|
||||
<Field element="select"
|
||||
label={label} onChange={this.onSelectChange}
|
||||
value={String(this.state.selectValue)} disabled={this.props.disabled}>
|
||||
value={String(this.state.selectValue)} disabled={this.props.disabled}
|
||||
>
|
||||
{options}
|
||||
</Field>
|
||||
);
|
||||
|
|
|
@ -56,7 +56,8 @@ export default class RoomAliasField extends React.PureComponent {
|
|||
placeholder={_t("e.g. my-room")}
|
||||
onChange={this._onChange}
|
||||
value={this.props.value.substring(1, this.props.value.length - this.props.domain.length - 1)}
|
||||
maxLength={maxlength} />
|
||||
maxLength={maxlength}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -178,9 +178,15 @@ export default class GroupMemberList extends React.Component {
|
|||
}
|
||||
|
||||
const inputBox = (
|
||||
<input className="mx_GroupMemberList_query mx_textinput" id="mx_GroupMemberList_query" type="text"
|
||||
onChange={this.onSearchQueryChanged} value={this.state.searchQuery}
|
||||
placeholder={_t('Filter community members')} autoComplete="off" />
|
||||
<input
|
||||
className="mx_GroupMemberList_query mx_textinput"
|
||||
id="mx_GroupMemberList_query"
|
||||
type="text"
|
||||
onChange={this.onSearchQueryChanged}
|
||||
value={this.state.searchQuery}
|
||||
placeholder={_t('Filter community members')}
|
||||
autoComplete="off"
|
||||
/>
|
||||
);
|
||||
|
||||
const joined = this.state.members ? <div className="mx_MemberList_joined">
|
||||
|
|
|
@ -141,9 +141,14 @@ export default class GroupRoomList extends React.Component {
|
|||
);
|
||||
}
|
||||
const inputBox = (
|
||||
<input className="mx_GroupRoomList_query mx_textinput" id="mx_GroupRoomList_query" type="text"
|
||||
onChange={this.onSearchQueryChanged} value={this.state.searchQuery}
|
||||
placeholder={_t('Filter community rooms')} autoComplete="off" />
|
||||
<input
|
||||
className="mx_GroupRoomList_query mx_textinput" id="mx_GroupRoomList_query"
|
||||
type="text"
|
||||
onChange={this.onSearchQueryChanged}
|
||||
value={this.state.searchQuery}
|
||||
placeholder={_t('Filter community rooms')}
|
||||
autoComplete="off"
|
||||
/>
|
||||
);
|
||||
|
||||
const TruncatedList = sdk.getComponent("elements.TruncatedList");
|
||||
|
|
|
@ -82,9 +82,7 @@ export default class MKeyVerificationConclusion extends React.Component {
|
|||
}
|
||||
|
||||
// User isn't actually verified
|
||||
if (!MatrixClientPeg.get()
|
||||
.checkUserTrust(request.otherUserId)
|
||||
.isCrossSigningVerified()) {
|
||||
if (!MatrixClientPeg.get().checkUserTrust(request.otherUserId).isCrossSigningVerified()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
@ -129,12 +129,13 @@ export default class ReactionsRowButton extends React.PureComponent {
|
|||
},
|
||||
);
|
||||
}
|
||||
|
||||
const isPeeking = room.getMyMembership() !== "join";
|
||||
const AccessibleButton = sdk.getComponent('elements.AccessibleButton');
|
||||
return <AccessibleButton
|
||||
className={classes}
|
||||
aria-label={label}
|
||||
onClick={this.onClick}
|
||||
disabled={isPeeking}
|
||||
onMouseOver={this.onMouseOver}
|
||||
onMouseLeave={this.onMouseLeave}
|
||||
>
|
||||
|
|
|
@ -525,7 +525,8 @@ export default class TextualBody extends React.Component {
|
|||
link={link}
|
||||
mxEvent={this.props.mxEvent}
|
||||
onCancelClick={this.onCancelClick}
|
||||
onHeightChanged={this.props.onHeightChanged} />;
|
||||
onHeightChanged={this.props.onHeightChanged}
|
||||
/>;
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -310,9 +310,14 @@ export default class AliasSettings extends React.Component {
|
|||
let found = false;
|
||||
const canonicalValue = this.state.canonicalAlias || "";
|
||||
const canonicalAliasSection = (
|
||||
<Field onChange={this.onCanonicalAliasChange} value={canonicalValue}
|
||||
<Field
|
||||
onChange={this.onCanonicalAliasChange}
|
||||
value={canonicalValue}
|
||||
disabled={this.state.updatingCanonicalAlias || !this.props.canSetCanonicalAlias}
|
||||
element='select' id='canonicalAlias' label={_t('Main address')}>
|
||||
element='select'
|
||||
id='canonicalAlias'
|
||||
label={_t('Main address')}
|
||||
>
|
||||
<option value="" key="unset">{ _t('not specified') }</option>
|
||||
{
|
||||
this._getAliases().map((alias, i) => {
|
||||
|
|
|
@ -205,16 +205,34 @@ export default class RoomProfileSettings extends React.Component {
|
|||
noValidate={true}
|
||||
className="mx_ProfileSettings_profileForm"
|
||||
>
|
||||
<input type="file" ref={this._avatarUpload} className="mx_ProfileSettings_avatarUpload"
|
||||
onChange={this._onAvatarChanged} accept="image/*" />
|
||||
<input
|
||||
type="file"
|
||||
ref={this._avatarUpload}
|
||||
className="mx_ProfileSettings_avatarUpload"
|
||||
onChange={this._onAvatarChanged}
|
||||
accept="image/*"
|
||||
/>
|
||||
<div className="mx_ProfileSettings_profile">
|
||||
<div className="mx_ProfileSettings_controls">
|
||||
<Field label={_t("Room Name")}
|
||||
type="text" value={this.state.displayName} autoComplete="off"
|
||||
onChange={this._onDisplayNameChanged} disabled={!this.state.canSetName} />
|
||||
<Field className="mx_ProfileSettings_controls_topic" id="profileTopic" label={_t("Room Topic")} disabled={!this.state.canSetTopic}
|
||||
type="text" value={this.state.topic} autoComplete="off"
|
||||
onChange={this._onTopicChanged} element="textarea" />
|
||||
<Field
|
||||
label={_t("Room Name")}
|
||||
type="text"
|
||||
value={this.state.displayName}
|
||||
autoComplete="off"
|
||||
onChange={this._onDisplayNameChanged}
|
||||
disabled={!this.state.canSetName}
|
||||
/>
|
||||
<Field
|
||||
className="mx_ProfileSettings_controls_topic"
|
||||
id="profileTopic"
|
||||
label={_t("Room Topic")}
|
||||
disabled={!this.state.canSetTopic}
|
||||
type="text"
|
||||
value={this.state.topic}
|
||||
autoComplete="off"
|
||||
onChange={this._onTopicChanged}
|
||||
element="textarea"
|
||||
/>
|
||||
</div>
|
||||
<AvatarSetting
|
||||
avatarUrl={this.state.avatarUrl}
|
||||
|
|
|
@ -68,10 +68,12 @@ export default class UrlPreviewSettings extends React.Component {
|
|||
if (SettingsStore.canSetValue("urlPreviewsEnabled", roomId, "room")) {
|
||||
previewsForRoom = (
|
||||
<label>
|
||||
<SettingsFlag name="urlPreviewsEnabled"
|
||||
<SettingsFlag
|
||||
name="urlPreviewsEnabled"
|
||||
level={SettingLevel.ROOM}
|
||||
roomId={roomId}
|
||||
isExplicit={true} />
|
||||
isExplicit={true}
|
||||
/>
|
||||
</label>
|
||||
);
|
||||
} else {
|
||||
|
|
|
@ -176,8 +176,11 @@ class EntityTile extends React.Component {
|
|||
// The wrapping div is required to make the magic mouse listener work, for some reason.
|
||||
return (
|
||||
<div ref={(c) => this.container = c} >
|
||||
<AccessibleButton className={classNames(mainClassNames)} title={this.props.title}
|
||||
onClick={this.props.onClick}>
|
||||
<AccessibleButton
|
||||
className={classNames(mainClassNames)}
|
||||
title={this.props.title}
|
||||
onClick={this.props.onClick}
|
||||
>
|
||||
<div className="mx_EntityTile_avatar">
|
||||
{ av }
|
||||
{ e2eIcon }
|
||||
|
|
|
@ -98,7 +98,10 @@ export default class PinnedEventTile extends React.Component {
|
|||
{ formatFullDate(new Date(this.props.mxEvent.getTs())) }
|
||||
</span>
|
||||
<div className="mx_PinnedEventTile_message">
|
||||
<MessageEvent mxEvent={this.props.mxEvent} className="mx_PinnedEventTile_body" maxImageHeight={150}
|
||||
<MessageEvent
|
||||
mxEvent={this.props.mxEvent}
|
||||
className="mx_PinnedEventTile_body"
|
||||
maxImageHeight={150}
|
||||
onHeightChanged={() => {}} // we need to give this, apparently
|
||||
/>
|
||||
</div>
|
||||
|
|
|
@ -113,10 +113,14 @@ export default class PinnedEventsPanel extends React.Component {
|
|||
}
|
||||
|
||||
return this.state.pinned.map((context) => {
|
||||
return (<PinnedEventTile key={context.event.getId()}
|
||||
return (
|
||||
<PinnedEventTile
|
||||
key={context.event.getId()}
|
||||
mxRoom={this.props.room}
|
||||
mxEvent={context.event}
|
||||
onUnpinned={this._updatePinnedMessages} />);
|
||||
onUnpinned={this._updatePinnedMessages}
|
||||
/>
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -187,8 +187,7 @@ export default class ReadReceiptMarker extends React.PureComponent {
|
|||
}
|
||||
|
||||
return (
|
||||
<NodeAnimator
|
||||
startStyles={this.state.startStyles} >
|
||||
<NodeAnimator startStyles={this.state.startStyles}>
|
||||
<MemberAvatar
|
||||
member={this.props.member}
|
||||
fallbackUserId={this.props.fallbackUserId}
|
||||
|
|
|
@ -79,8 +79,13 @@ export default class ReplyPreview extends React.Component {
|
|||
{ _t('Replying') }
|
||||
</div>
|
||||
<div className="mx_ReplyPreview_header mx_ReplyPreview_cancel">
|
||||
<img className="mx_filterFlipColor" src={require("../../../../res/img/cancel.svg")} width="18" height="18"
|
||||
onClick={cancelQuoting} />
|
||||
<img
|
||||
className="mx_filterFlipColor"
|
||||
src={require("../../../../res/img/cancel.svg")}
|
||||
width="18"
|
||||
height="18"
|
||||
onClick={cancelQuoting}
|
||||
/>
|
||||
</div>
|
||||
<div className="mx_ReplyPreview_clear" />
|
||||
<EventTile
|
||||
|
|
|
@ -19,6 +19,7 @@ import React, {useState} from "react";
|
|||
import { _t } from "../../../languageHandler";
|
||||
import RoomListStore, { LISTS_UPDATE_EVENT } from "../../../stores/room-list/RoomListStore";
|
||||
import {useEventEmitter} from "../../../hooks/useEventEmitter";
|
||||
import SpaceStore from "../../../stores/SpaceStore";
|
||||
|
||||
const RoomListNumResults: React.FC = () => {
|
||||
const [count, setCount] = useState<number>(null);
|
||||
|
@ -34,7 +35,10 @@ const RoomListNumResults: React.FC = () => {
|
|||
if (typeof count !== "number") return null;
|
||||
|
||||
return <div className="mx_LeftPanel_roomListFilterCount">
|
||||
{_t("%(count)s results", { count })}
|
||||
{ SpaceStore.instance.spacePanelSpaces.length
|
||||
? _t("%(count)s results in all spaces", { count })
|
||||
: _t("%(count)s results", { count })
|
||||
}
|
||||
</div>;
|
||||
};
|
||||
|
||||
|
|
|
@ -170,8 +170,12 @@ export default class ProfileSettings extends React.Component {
|
|||
noValidate={true}
|
||||
className="mx_ProfileSettings_profileForm"
|
||||
>
|
||||
<input type="file" ref={this._avatarUpload} className="mx_ProfileSettings_avatarUpload"
|
||||
onChange={this._onAvatarChanged} accept="image/*" />
|
||||
<input
|
||||
type="file"
|
||||
ref={this._avatarUpload} className="mx_ProfileSettings_avatarUpload"
|
||||
onChange={this._onAvatarChanged}
|
||||
accept="image/*"
|
||||
/>
|
||||
<div className="mx_ProfileSettings_profile">
|
||||
<div className="mx_ProfileSettings_controls">
|
||||
<span className="mx_SettingsTab_subheading">{_t("Profile")}</span>
|
||||
|
|
|
@ -90,12 +90,18 @@ export class ExistingEmailAddress extends React.Component {
|
|||
<span className="mx_ExistingEmailAddress_promptText">
|
||||
{_t("Remove %(email)s?", {email: this.props.email.address} )}
|
||||
</span>
|
||||
<AccessibleButton onClick={this._onActuallyRemove} kind="danger_sm"
|
||||
className="mx_ExistingEmailAddress_confirmBtn">
|
||||
<AccessibleButton
|
||||
onClick={this._onActuallyRemove}
|
||||
kind="danger_sm"
|
||||
className="mx_ExistingEmailAddress_confirmBtn"
|
||||
>
|
||||
{_t("Remove")}
|
||||
</AccessibleButton>
|
||||
<AccessibleButton onClick={this._onDontRemove} kind="link_sm"
|
||||
className="mx_ExistingEmailAddress_confirmBtn">
|
||||
<AccessibleButton
|
||||
onClick={this._onDontRemove}
|
||||
kind="link_sm"
|
||||
className="mx_ExistingEmailAddress_confirmBtn"
|
||||
>
|
||||
{_t("Cancel")}
|
||||
</AccessibleButton>
|
||||
</div>
|
||||
|
@ -230,8 +236,11 @@ export default class EmailAddresses extends React.Component {
|
|||
addButton = (
|
||||
<div>
|
||||
<div>{_t("We've sent you an email to verify your address. Please follow the instructions there and then click the button below.")}</div>
|
||||
<AccessibleButton onClick={this._onContinueClick} kind="primary"
|
||||
disabled={this.state.continueDisabled}>
|
||||
<AccessibleButton
|
||||
onClick={this._onContinueClick}
|
||||
kind="primary"
|
||||
disabled={this.state.continueDisabled}
|
||||
>
|
||||
{_t("Continue")}
|
||||
</AccessibleButton>
|
||||
</div>
|
||||
|
@ -241,8 +250,12 @@ export default class EmailAddresses extends React.Component {
|
|||
return (
|
||||
<div className="mx_EmailAddresses">
|
||||
{existingEmailElements}
|
||||
<form onSubmit={this._onAddClick} autoComplete="off"
|
||||
noValidate={true} className="mx_EmailAddresses_new">
|
||||
<form
|
||||
onSubmit={this._onAddClick}
|
||||
autoComplete="off"
|
||||
noValidate={true}
|
||||
className="mx_EmailAddresses_new"
|
||||
>
|
||||
<Field
|
||||
type="text"
|
||||
label={_t("Email Address")}
|
||||
|
|
|
@ -85,12 +85,18 @@ export class ExistingPhoneNumber extends React.Component {
|
|||
<span className="mx_ExistingPhoneNumber_promptText">
|
||||
{_t("Remove %(phone)s?", {phone: this.props.msisdn.address})}
|
||||
</span>
|
||||
<AccessibleButton onClick={this._onActuallyRemove} kind="danger_sm"
|
||||
className="mx_ExistingPhoneNumber_confirmBtn">
|
||||
<AccessibleButton
|
||||
onClick={this._onActuallyRemove}
|
||||
kind="danger_sm"
|
||||
className="mx_ExistingPhoneNumber_confirmBtn"
|
||||
>
|
||||
{_t("Remove")}
|
||||
</AccessibleButton>
|
||||
<AccessibleButton onClick={this._onDontRemove} kind="link_sm"
|
||||
className="mx_ExistingPhoneNumber_confirmBtn">
|
||||
<AccessibleButton
|
||||
onClick={this._onDontRemove}
|
||||
kind="link_sm"
|
||||
className="mx_ExistingPhoneNumber_confirmBtn"
|
||||
>
|
||||
{_t("Cancel")}
|
||||
</AccessibleButton>
|
||||
</div>
|
||||
|
@ -246,8 +252,11 @@ export default class PhoneNumbers extends React.Component {
|
|||
value={this.state.newPhoneNumberCode}
|
||||
onChange={this._onChangeNewPhoneNumberCode}
|
||||
/>
|
||||
<AccessibleButton onClick={this._onContinueClick} kind="primary"
|
||||
disabled={this.state.continueDisabled}>
|
||||
<AccessibleButton
|
||||
onClick={this._onContinueClick}
|
||||
kind="primary"
|
||||
disabled={this.state.continueDisabled}
|
||||
>
|
||||
{_t("Continue")}
|
||||
</AccessibleButton>
|
||||
</form>
|
||||
|
|
|
@ -80,9 +80,11 @@ export default class GeneralRoomSettingsTab extends React.Component {
|
|||
flairSection = <>
|
||||
<span className='mx_SettingsTab_subheading'>{_t("Flair")}</span>
|
||||
<div className='mx_SettingsTab_section mx_SettingsTab_subsectionText'>
|
||||
<RelatedGroupSettings roomId={room.roomId}
|
||||
<RelatedGroupSettings
|
||||
roomId={room.roomId}
|
||||
canSetRelatedGroups={canChangeGroups}
|
||||
relatedGroupsEvent={groupsEvent} />
|
||||
relatedGroupsEvent={groupsEvent}
|
||||
/>
|
||||
</div>
|
||||
</>;
|
||||
}
|
||||
|
|
|
@ -323,8 +323,11 @@ export default class GeneralUserSettingsTab extends React.Component {
|
|||
return (
|
||||
<div className="mx_SettingsTab_section">
|
||||
<span className="mx_SettingsTab_subheading">{_t("Language and region")}</span>
|
||||
<LanguageDropdown className="mx_GeneralUserSettingsTab_languageInput"
|
||||
onOptionChange={this._onLanguageChange} value={this.state.language} />
|
||||
<LanguageDropdown
|
||||
className="mx_GeneralUserSettingsTab_languageInput"
|
||||
onOptionChange={this._onLanguageChange}
|
||||
value={this.state.language}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
@ -333,8 +336,10 @@ export default class GeneralUserSettingsTab extends React.Component {
|
|||
return (
|
||||
<div className="mx_SettingsTab_section">
|
||||
<span className="mx_SettingsTab_subheading">{_t("Spell check dictionaries")}</span>
|
||||
<SpellCheckSettings languages={this.state.spellCheckLanguages}
|
||||
onLanguagesChange={this._onSpellCheckLanguagesChange} />
|
||||
<SpellCheckSettings
|
||||
languages={this.state.spellCheckLanguages}
|
||||
onLanguagesChange={this._onSpellCheckLanguagesChange}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -257,12 +257,16 @@ export default class SecurityUserSettingsTab extends React.Component {
|
|||
|
||||
const userIds = !ignoredUserIds?.length
|
||||
? _t('You have no ignored users.')
|
||||
: ignoredUserIds.map((u) => <IgnoredUser
|
||||
: ignoredUserIds.map((u) => {
|
||||
return (
|
||||
<IgnoredUser
|
||||
userId={u}
|
||||
onUnignored={this._onUserUnignored}
|
||||
key={u}
|
||||
inProgress={waitingUnignored.includes(u)}
|
||||
/>);
|
||||
/>
|
||||
);
|
||||
});
|
||||
|
||||
return (
|
||||
<div className='mx_SettingsTab_section'>
|
||||
|
|
|
@ -61,9 +61,9 @@ export function htmlSerializeIfNeeded(model: EditorModel, {forceHTML = false} =
|
|||
// const inlinePattern = "(?:^|\\s)(?<!\\\\)\\$(?!\\s)(([^$]|\\\\\\$)+?)(?<!\\\\|\\s)\\$";
|
||||
|
||||
// conditions for display math detection $$...$$:
|
||||
// - pattern starts at beginning of line or is not prefixed with backslash or dollar
|
||||
// - pattern starts and ends on a new line
|
||||
// - left delimiter ($$) is not escaped by backslash
|
||||
"display": "(^|[^\\\\$])\\$\\$(([^$]|\\\\\\$)+?)\\$\\$",
|
||||
"display": "(^)\\$\\$(([^$]|\\\\\\$)+?)\\$\\$$",
|
||||
|
||||
// conditions for inline math detection $...$:
|
||||
// - pattern starts at beginning of line, follows whitespace character or punctuation
|
||||
|
@ -78,9 +78,9 @@ export function htmlSerializeIfNeeded(model: EditorModel, {forceHTML = false} =
|
|||
// detect math with latex delimiters, inline: \(...\), display \[...\]
|
||||
|
||||
// conditions for display math detection \[...\]:
|
||||
// - pattern starts at beginning of line or is not prefixed with backslash
|
||||
// - pattern starts and ends on a new line
|
||||
// - pattern is not empty
|
||||
"display": "(^|[^\\\\])\\\\\\[(?!\\\\\\])(.*?)\\\\\\]",
|
||||
"display": "(^)\\\\\\[(?!\\\\\\])(.*?)\\\\\\]$",
|
||||
|
||||
// conditions for inline math detection \(...\):
|
||||
// - pattern starts at beginning of line or is not prefixed with backslash
|
||||
|
|
|
@ -1552,6 +1552,8 @@
|
|||
"Explore all public rooms": "Explore all public rooms",
|
||||
"Quick actions": "Quick actions",
|
||||
"Use the + to make a new room or explore existing ones below": "Use the + to make a new room or explore existing ones below",
|
||||
"%(count)s results in all spaces|other": "%(count)s results in all spaces",
|
||||
"%(count)s results in all spaces|one": "%(count)s result in all spaces",
|
||||
"%(count)s results|other": "%(count)s results",
|
||||
"%(count)s results|one": "%(count)s result",
|
||||
"This room": "This room",
|
||||
|
@ -2612,6 +2614,7 @@
|
|||
"If you can't find the room you're looking for, ask for an invite or <a>Create a new room</a>.": "If you can't find the room you're looking for, ask for an invite or <a>Create a new room</a>.",
|
||||
"Explore rooms in %(communityName)s": "Explore rooms in %(communityName)s",
|
||||
"Filter": "Filter",
|
||||
"Filter all spaces": "Filter all spaces",
|
||||
"Clear filter": "Clear filter",
|
||||
"Filter rooms and people": "Filter rooms and people",
|
||||
"You can't send any messages until you review and agree to <consentLink>our terms and conditions</consentLink>.": "You can't send any messages until you review and agree to <consentLink>our terms and conditions</consentLink>.",
|
||||
|
|
|
@ -127,8 +127,13 @@ export default class EventIndex extends EventEmitter {
|
|||
this.crawlerCheckpoints.push(forwardCheckpoint);
|
||||
}
|
||||
} catch (e) {
|
||||
console.log("EventIndex: Error adding initial checkpoints for room",
|
||||
room.roomId, backCheckpoint, forwardCheckpoint, e);
|
||||
console.log(
|
||||
"EventIndex: Error adding initial checkpoints for room",
|
||||
room.roomId,
|
||||
backCheckpoint,
|
||||
forwardCheckpoint,
|
||||
e,
|
||||
);
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
@ -379,8 +384,12 @@ export default class EventIndex extends EventEmitter {
|
|||
try {
|
||||
await indexManager.addCrawlerCheckpoint(checkpoint);
|
||||
} catch (e) {
|
||||
console.log("EventIndex: Error adding new checkpoint for room",
|
||||
room.roomId, checkpoint, e);
|
||||
console.log(
|
||||
"EventIndex: Error adding new checkpoint for room",
|
||||
room.roomId,
|
||||
checkpoint,
|
||||
e,
|
||||
);
|
||||
}
|
||||
|
||||
this.crawlerCheckpoints.push(checkpoint);
|
||||
|
@ -776,8 +785,14 @@ export default class EventIndex extends EventEmitter {
|
|||
* @returns {Promise<boolean>} Resolves to true if events were added to the
|
||||
* timeline, false otherwise.
|
||||
*/
|
||||
async populateFileTimeline(timelineSet, timeline, room, limit = 10,
|
||||
fromEvent = null, direction = EventTimeline.BACKWARDS) {
|
||||
async populateFileTimeline(
|
||||
timelineSet,
|
||||
timeline,
|
||||
room,
|
||||
limit = 10,
|
||||
fromEvent = null,
|
||||
direction = EventTimeline.BACKWARDS,
|
||||
) {
|
||||
const matrixEvents = await this.loadFileEvents(room, limit, fromEvent, direction);
|
||||
|
||||
// If this is a normal fill request, not a pagination request, we need
|
||||
|
|
|
@ -124,17 +124,17 @@ class CustomRoomTagStore extends EventEmitter {
|
|||
const tags = Object.assign({}, oldTags, tag);
|
||||
this._setState({tags});
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 'on_client_not_viable':
|
||||
case 'on_logged_out': {
|
||||
// we assume to always have a tags object in the state
|
||||
this._state = {tags: {}};
|
||||
RoomListStore.instance.off(LISTS_UPDATE_EVENT, this._onListsUpdated);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_getUpdatedTags() {
|
||||
if (!SettingsStore.getValue("feature_custom_tags")) {
|
||||
|
|
|
@ -62,6 +62,8 @@ const INITIAL_STATE = {
|
|||
shouldPeek: false,
|
||||
|
||||
viaServers: [],
|
||||
|
||||
wasContextSwitch: false,
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -116,6 +118,7 @@ class RoomViewStore extends Store<ActionPayload> {
|
|||
roomId: null,
|
||||
roomAlias: null,
|
||||
viaServers: [],
|
||||
wasContextSwitch: false,
|
||||
});
|
||||
break;
|
||||
case 'view_room_error':
|
||||
|
@ -195,6 +198,7 @@ class RoomViewStore extends Store<ActionPayload> {
|
|||
// pull the user out of Room Settings
|
||||
isEditingSettings: false,
|
||||
viaServers: payload.via_servers,
|
||||
wasContextSwitch: payload.context_switch,
|
||||
};
|
||||
|
||||
// Allow being given an event to be replied to when switching rooms but sanity check its for this room
|
||||
|
@ -231,6 +235,7 @@ class RoomViewStore extends Store<ActionPayload> {
|
|||
roomLoading: true,
|
||||
roomLoadError: null,
|
||||
viaServers: payload.via_servers,
|
||||
wasContextSwitch: payload.context_switch,
|
||||
});
|
||||
try {
|
||||
const result = await MatrixClientPeg.get().getRoomIdForAlias(payload.room_alias);
|
||||
|
@ -256,6 +261,8 @@ class RoomViewStore extends Store<ActionPayload> {
|
|||
room_alias: payload.room_alias,
|
||||
auto_join: payload.auto_join,
|
||||
oob_data: payload.oob_data,
|
||||
viaServers: payload.via_servers,
|
||||
wasContextSwitch: payload.context_switch,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -266,7 +273,6 @@ class RoomViewStore extends Store<ActionPayload> {
|
|||
roomAlias: payload.room_alias,
|
||||
roomLoading: false,
|
||||
roomLoadError: payload.err,
|
||||
viaServers: [],
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -426,6 +432,10 @@ class RoomViewStore extends Store<ActionPayload> {
|
|||
public shouldPeek() {
|
||||
return this.state.shouldPeek;
|
||||
}
|
||||
|
||||
public getWasContextSwitch() {
|
||||
return this.state.wasContextSwitch;
|
||||
}
|
||||
}
|
||||
|
||||
let singletonRoomViewStore = null;
|
||||
|
|
|
@ -601,7 +601,11 @@ export class RoomListStoreClass extends AsyncStoreWithClient<IState> {
|
|||
|
||||
let rooms = this.matrixClient.getVisibleRooms().filter(r => VisibilityProvider.instance.isRoomVisible(r));
|
||||
|
||||
if (this.prefilterConditions.length > 0) {
|
||||
// if spaces are enabled only consider the prefilter conditions when there are no runtime conditions
|
||||
// for the search all spaces feature
|
||||
if (this.prefilterConditions.length > 0
|
||||
&& (!SettingsStore.getValue("feature_spaces") || !this.filterConditions.length)
|
||||
) {
|
||||
rooms = rooms.filter(r => {
|
||||
for (const filter of this.prefilterConditions) {
|
||||
if (!filter.isVisible(r)) {
|
||||
|
@ -675,6 +679,10 @@ export class RoomListStoreClass extends AsyncStoreWithClient<IState> {
|
|||
if (this.algorithm) {
|
||||
this.algorithm.addFilterCondition(filter);
|
||||
}
|
||||
// Runtime filters with spaces disable prefiltering for the search all spaces effect
|
||||
if (SettingsStore.getValue("feature_spaces")) {
|
||||
promise = this.recalculatePrefiltering();
|
||||
}
|
||||
}
|
||||
promise.then(() => this.updateFn.trigger());
|
||||
}
|
||||
|
@ -698,6 +706,10 @@ export class RoomListStoreClass extends AsyncStoreWithClient<IState> {
|
|||
|
||||
if (this.algorithm) {
|
||||
this.algorithm.removeFilterCondition(filter);
|
||||
// Runtime filters with spaces disable prefiltering for the search all spaces effect
|
||||
if (SettingsStore.getValue("feature_spaces")) {
|
||||
promise = this.recalculatePrefiltering();
|
||||
}
|
||||
}
|
||||
}
|
||||
idx = this.prefilterConditions.indexOf(filter);
|
||||
|
|
|
@ -310,8 +310,7 @@ function unpackMegolmKeyFile(data) {
|
|||
// look for the end line
|
||||
while (1) {
|
||||
const lineEnd = fileStr.indexOf('\n', lineStart);
|
||||
const line = fileStr.slice(lineStart, lineEnd < 0 ? undefined : lineEnd)
|
||||
.trim();
|
||||
const line = fileStr.slice(lineStart, lineEnd < 0 ? undefined : lineEnd).trim();
|
||||
if (line === TRAILER_LINE) {
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -89,10 +89,12 @@ describe("AccessSecretStorageDialog", function() {
|
|||
<AccessSecretStorageDialog
|
||||
checkPrivateKey={() => false}
|
||||
onFinished={() => {}}
|
||||
keyInfo={ { passphrase: {
|
||||
keyInfo={{
|
||||
passphrase: {
|
||||
salt: 'nonempty',
|
||||
iterations: 2,
|
||||
} } }
|
||||
},
|
||||
}}
|
||||
/>,
|
||||
);
|
||||
const e = { target: { value: "a" } };
|
||||
|
|
|
@ -245,8 +245,7 @@ describe('MemberEventListSummary', function() {
|
|||
);
|
||||
});
|
||||
|
||||
it('truncates multiple sequences of repetitions with other events between',
|
||||
function() {
|
||||
it('truncates multiple sequences of repetitions with other events between', function() {
|
||||
const events = generateEvents([
|
||||
{
|
||||
userId: "@user_1:some.domain",
|
||||
|
@ -395,8 +394,7 @@ describe('MemberEventListSummary', function() {
|
|||
);
|
||||
});
|
||||
|
||||
it('correctly orders sequences of transitions by the order of their first event',
|
||||
function() {
|
||||
it('correctly orders sequences of transitions by the order of their first event', function() {
|
||||
const events = generateEvents([
|
||||
{
|
||||
userId: "@user_2:some.domain",
|
||||
|
@ -568,8 +566,7 @@ describe('MemberEventListSummary', function() {
|
|||
);
|
||||
});
|
||||
|
||||
it('handles invitation plurals correctly when there are multiple invites',
|
||||
function() {
|
||||
it('handles invitation plurals correctly when there are multiple invites', function() {
|
||||
const events = generateEvents([
|
||||
{
|
||||
userId: "@user_1:some.domain",
|
||||
|
|
|
@ -70,8 +70,9 @@ describe('RoomList', () => {
|
|||
root = ReactDOM.render(
|
||||
<DragDropContext>
|
||||
<WrappedRoomList searchFilter="" onResize={() => {}} />
|
||||
</DragDropContext>
|
||||
, parentDiv);
|
||||
</DragDropContext>,
|
||||
parentDiv,
|
||||
);
|
||||
ReactTestUtils.findRenderedComponentWithType(root, RoomList);
|
||||
|
||||
movingRoom = createRoom({name: 'Moving room'});
|
||||
|
|
Loading…
Reference in a new issue