mirror of
https://github.com/vector-im/element-web.git
synced 2024-11-16 05:04:57 +08:00
Merge branch 'develop' into bwindels/stylepreviewbar
This commit is contained in:
commit
22874f62ab
@ -9,6 +9,10 @@ steps:
|
||||
image: "node:10"
|
||||
|
||||
- label: ":chains: End-to-End Tests"
|
||||
agents:
|
||||
# We use a medium sized instance instead of the normal small ones because
|
||||
# e2e tests otherwise take +-8min
|
||||
queue: "medium"
|
||||
command:
|
||||
# TODO: Remove hacky chmod for BuildKite
|
||||
- "echo '--- Setup'"
|
||||
|
@ -36,6 +36,12 @@ body {
|
||||
color: $warning-color;
|
||||
}
|
||||
|
||||
b {
|
||||
// On Firefox, the default weight for `<b>` is `bolder` which results in no bold
|
||||
// effect since we only have specific weights of our fonts available.
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
h2 {
|
||||
color: $primary-fg-color;
|
||||
font-weight: 400;
|
||||
|
@ -6,6 +6,7 @@
|
||||
@import "./structures/_CreateRoom.scss";
|
||||
@import "./structures/_CustomRoomTagPanel.scss";
|
||||
@import "./structures/_FilePanel.scss";
|
||||
@import "./structures/_GenericErrorPage.scss";
|
||||
@import "./structures/_GroupView.scss";
|
||||
@import "./structures/_HeaderButtons.scss";
|
||||
@import "./structures/_HomePage.scss";
|
||||
|
19
res/css/structures/_GenericErrorPage.scss
Normal file
19
res/css/structures/_GenericErrorPage.scss
Normal file
@ -0,0 +1,19 @@
|
||||
.mx_GenericErrorPage {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background-color: #fff;
|
||||
}
|
||||
|
||||
.mx_GenericErrorPage_box {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
margin: auto;
|
||||
width: 500px;
|
||||
height: 200px;
|
||||
border: 1px solid #f22;
|
||||
padding: 10px;
|
||||
background-color: #fcc;
|
||||
}
|
@ -72,3 +72,7 @@ limitations under the License.
|
||||
// give them more visual distinction between the sections.
|
||||
margin-top: 30px;
|
||||
}
|
||||
|
||||
.mx_SettingsTab a {
|
||||
color: $accent-color-alt;
|
||||
}
|
@ -492,6 +492,9 @@ export default class ContentMessages {
|
||||
this.inprogress.push(upload);
|
||||
dis.dispatch({action: 'upload_started'});
|
||||
|
||||
// Focus the composer view
|
||||
dis.dispatch({action: 'focus_composer'});
|
||||
|
||||
let error;
|
||||
|
||||
function onProgress(ev) {
|
||||
|
@ -41,6 +41,12 @@ class SdkConfig {
|
||||
static unset() {
|
||||
global.mxReactSdkConfig = undefined;
|
||||
}
|
||||
|
||||
static add(cfg) {
|
||||
const liveConfig = SdkConfig.get();
|
||||
const newConfig = Object.assign({}, liveConfig, cfg);
|
||||
SdkConfig.put(newConfig);
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = SdkConfig;
|
||||
|
@ -155,7 +155,7 @@ export const CommandMap = {
|
||||
<p>
|
||||
{_t(
|
||||
"Please confirm that you'd like to go forward with upgrading this room " +
|
||||
"from <oldVersion /> to <newVersion />",
|
||||
"from <oldVersion /> to <newVersion />.",
|
||||
{},
|
||||
{
|
||||
oldVersion: () => <code>{room ? room.getVersion() : "1"}</code>,
|
||||
|
38
src/components/structures/GenericErrorPage.js
Normal file
38
src/components/structures/GenericErrorPage.js
Normal file
@ -0,0 +1,38 @@
|
||||
/*
|
||||
Copyright 2019 New Vector Ltd
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import {_t} from "../../languageHandler";
|
||||
|
||||
export default class GenericErrorPage extends React.PureComponent {
|
||||
static propTypes = {
|
||||
message: PropTypes.string.isRequired,
|
||||
};
|
||||
|
||||
render() {
|
||||
return <div className='mx_GenericErrorPage'>
|
||||
<div className='mx_GenericErrorPage_box'>
|
||||
<h1>{_t("Error loading Riot")}</h1>
|
||||
<p>{this.props.message}</p>
|
||||
<p>{_t(
|
||||
"If this is unexpected, please contact your system administrator " +
|
||||
"or technical support representative.",
|
||||
)}</p>
|
||||
</div>
|
||||
</div>;
|
||||
}
|
||||
}
|
@ -29,13 +29,6 @@ export default class IndicatorScrollbar extends React.Component {
|
||||
// scroll horizontally rather than vertically. This should only be used on components
|
||||
// with no vertical scroll opportunity.
|
||||
verticalScrollsHorizontally: PropTypes.bool,
|
||||
|
||||
// An object containing 2 numbers: xyThreshold and yReduction. xyThreshold is the amount
|
||||
// of horizontal movement required in order to ignore any vertical changes in scroll, and
|
||||
// only applies when verticalScrollsHorizontally is true. yReduction is the factor to
|
||||
// multiply the vertical delta by when verticalScrollsHorizontally is true. The default
|
||||
// behaviour is to have an xyThreshold of infinity and a yReduction of 0.8
|
||||
scrollTolerances: PropTypes.object,
|
||||
};
|
||||
|
||||
constructor(props) {
|
||||
@ -127,20 +120,19 @@ export default class IndicatorScrollbar extends React.Component {
|
||||
|
||||
onMouseWheel = (e) => {
|
||||
if (this.props.verticalScrollsHorizontally && this._scrollElement) {
|
||||
const xyThreshold = this.props.scrollTolerances
|
||||
? this.props.scrollTolerances.xyThreshold
|
||||
: Number.MAX_SAFE_INTEGER;
|
||||
// xyThreshold is the amount of horizontal motion required for the component to
|
||||
// ignore the vertical delta in a scroll. Used to stop trackpads from acting in
|
||||
// strange ways. Should be positive.
|
||||
const xyThreshold = 0;
|
||||
|
||||
const yReduction = this.props.scrollTolerances
|
||||
? this.props.scrollTolerances.yReduction
|
||||
: 0.8;
|
||||
// yRetention is the factor multiplied by the vertical delta to try and reduce
|
||||
// the harshness of the scroll behaviour. Should be a value between 0 and 1.
|
||||
const yRetention = 1.0;
|
||||
|
||||
// Don't apply vertical motion to horizontal scrolls. This is meant to eliminate
|
||||
// trackpads causing excessive scroll motion.
|
||||
if (e.deltaX >= xyThreshold) return;
|
||||
|
||||
// noinspection JSSuspiciousNameCombination
|
||||
this._scrollElement.scrollLeft += e.deltaY * yReduction;
|
||||
if (Math.abs(e.deltaX) < xyThreshold) {
|
||||
// noinspection JSSuspiciousNameCombination
|
||||
this._scrollElement.scrollLeft += e.deltaY * yRetention;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -565,23 +565,6 @@ export default React.createClass({
|
||||
},
|
||||
});
|
||||
break;
|
||||
case 'view_user':
|
||||
// FIXME: ugly hack to expand the RightPanel and then re-dispatch.
|
||||
if (this.state.collapsedRhs) {
|
||||
setTimeout(()=>{
|
||||
dis.dispatch({
|
||||
action: 'show_right_panel',
|
||||
});
|
||||
dis.dispatch({
|
||||
action: 'view_user',
|
||||
member: payload.member,
|
||||
});
|
||||
}, 0);
|
||||
}
|
||||
break;
|
||||
// different from view_user,
|
||||
// this show the user panel outside of the context
|
||||
// of a room, like a /user/<id> url
|
||||
case 'view_user_info':
|
||||
this._viewUser(payload.userId);
|
||||
break;
|
||||
@ -1820,7 +1803,7 @@ export default React.createClass({
|
||||
},
|
||||
|
||||
_setPageSubtitle: function(subtitle='') {
|
||||
document.title = `Riot ${subtitle}`;
|
||||
document.title = `${SdkConfig.get().brand || 'Riot'} ${subtitle}`;
|
||||
},
|
||||
|
||||
updateStatusIndicator: function(state, prevState) {
|
||||
|
@ -272,6 +272,28 @@ module.exports = React.createClass({
|
||||
return this.state.room ? this.state.room.roomId : this.state.roomId;
|
||||
},
|
||||
|
||||
_getPermalinkCreatorForRoom: function(room) {
|
||||
if (!this._permalinkCreators) this._permalinkCreators = {};
|
||||
if (this._permalinkCreators[room.roomId]) return this._permalinkCreators[room.roomId];
|
||||
|
||||
this._permalinkCreators[room.roomId] = new RoomPermalinkCreator(room);
|
||||
if (this.state.room && room.roomId === this.state.room.roomId) {
|
||||
// We want to watch for changes in the creator for the primary room in the view, but
|
||||
// don't need to do so for search results.
|
||||
this._permalinkCreators[room.roomId].start();
|
||||
} else {
|
||||
this._permalinkCreators[room.roomId].load();
|
||||
}
|
||||
return this._permalinkCreators[room.roomId];
|
||||
},
|
||||
|
||||
_stopAllPermalinkCreators: function() {
|
||||
if (!this._permalinkCreators) return;
|
||||
for (const roomId of Object.keys(this._permalinkCreators)) {
|
||||
this._permalinkCreators[roomId].stop();
|
||||
}
|
||||
},
|
||||
|
||||
_onWidgetEchoStoreUpdate: function() {
|
||||
this.setState({
|
||||
showApps: this._shouldShowApps(this.state.room),
|
||||
@ -436,9 +458,7 @@ module.exports = React.createClass({
|
||||
}
|
||||
|
||||
// stop tracking room changes to format permalinks
|
||||
if (this.state.permalinkCreator) {
|
||||
this.state.permalinkCreator.stop();
|
||||
}
|
||||
this._stopAllPermalinkCreators();
|
||||
|
||||
if (this.refs.roomView) {
|
||||
// disconnect the D&D event listeners from the room view. This
|
||||
@ -651,11 +671,6 @@ module.exports = React.createClass({
|
||||
this._loadMembersIfJoined(room);
|
||||
this._calculateRecommendedVersion(room);
|
||||
this._updateE2EStatus(room);
|
||||
if (!this.state.permalinkCreator) {
|
||||
const permalinkCreator = new RoomPermalinkCreator(room);
|
||||
permalinkCreator.start();
|
||||
this.setState({permalinkCreator});
|
||||
}
|
||||
},
|
||||
|
||||
_calculateRecommendedVersion: async function(room) {
|
||||
@ -1169,6 +1184,7 @@ module.exports = React.createClass({
|
||||
|
||||
const mxEv = result.context.getEvent();
|
||||
const roomId = mxEv.getRoomId();
|
||||
const room = cli.getRoom(roomId);
|
||||
|
||||
if (!EventTile.haveTileForEvent(mxEv)) {
|
||||
// XXX: can this ever happen? It will make the result count
|
||||
@ -1178,7 +1194,6 @@ module.exports = React.createClass({
|
||||
|
||||
if (this.state.searchScope === 'All') {
|
||||
if (roomId != lastRoomId) {
|
||||
const room = cli.getRoom(roomId);
|
||||
|
||||
// XXX: if we've left the room, we might not know about
|
||||
// it. We should tell the js sdk to go and find out about
|
||||
@ -1199,7 +1214,7 @@ module.exports = React.createClass({
|
||||
searchResult={result}
|
||||
searchHighlights={this.state.searchHighlights}
|
||||
resultLink={resultLink}
|
||||
permalinkCreator={this.state.permalinkCreator}
|
||||
permalinkCreator={this._getPermalinkCreatorForRoom(room)}
|
||||
onHeightChanged={onHeightChanged} />);
|
||||
}
|
||||
return ret;
|
||||
@ -1715,7 +1730,7 @@ module.exports = React.createClass({
|
||||
disabled={this.props.disabled}
|
||||
showApps={this.state.showApps}
|
||||
e2eStatus={this.state.e2eStatus}
|
||||
permalinkCreator={this.state.permalinkCreator}
|
||||
permalinkCreator={this._getPermalinkCreatorForRoom(this.state.room)}
|
||||
/>;
|
||||
}
|
||||
|
||||
@ -1812,7 +1827,7 @@ module.exports = React.createClass({
|
||||
showUrlPreview = {this.state.showUrlPreview}
|
||||
className="mx_RoomView_messagePanel"
|
||||
membersLoaded={this.state.membersLoaded}
|
||||
permalinkCreator={this.state.permalinkCreator}
|
||||
permalinkCreator={this._getPermalinkCreatorForRoom(this.state.room)}
|
||||
resizeNotifier={this.props.resizeNotifier}
|
||||
/>);
|
||||
|
||||
|
@ -42,7 +42,12 @@ const PHASES_ENABLED = true;
|
||||
// These are used in several places, and come from the js-sdk's autodiscovery
|
||||
// stuff. We define them here so that they'll be picked up by i18n.
|
||||
_td("Invalid homeserver discovery response");
|
||||
_td("Failed to get autodiscovery configuration from server");
|
||||
_td("Invalid base_url for m.homeserver");
|
||||
_td("Homeserver URL does not appear to be a valid Matrix homeserver");
|
||||
_td("Invalid identity server discovery response");
|
||||
_td("Invalid base_url for m.identity_server");
|
||||
_td("Identity server URL does not appear to be a valid identity server");
|
||||
_td("General failure");
|
||||
|
||||
/**
|
||||
|
@ -52,7 +52,7 @@ export default class RoomSettingsDialog extends React.Component {
|
||||
tabs.push(new Tab(
|
||||
_td("Advanced"),
|
||||
"mx_RoomSettingsDialog_warningIcon",
|
||||
<AdvancedRoomSettingsTab roomId={this.props.roomId} />,
|
||||
<AdvancedRoomSettingsTab roomId={this.props.roomId} closeSettingsFn={this.props.onFinished} />,
|
||||
));
|
||||
|
||||
return tabs;
|
||||
|
@ -19,23 +19,30 @@ limitations under the License.
|
||||
|
||||
import React from 'react';
|
||||
import { _t } from '../../../languageHandler';
|
||||
import dis from '../../../dispatcher';
|
||||
import HeaderButton from './HeaderButton';
|
||||
import HeaderButtons from './HeaderButtons';
|
||||
import RightPanel from '../../structures/RightPanel';
|
||||
|
||||
const GROUP_PHASES = [
|
||||
RightPanel.Phase.GroupMemberInfo,
|
||||
RightPanel.Phase.GroupMemberList,
|
||||
];
|
||||
const ROOM_PHASES = [
|
||||
RightPanel.Phase.GroupRoomList,
|
||||
RightPanel.Phase.GroupRoomInfo,
|
||||
];
|
||||
|
||||
export default class GroupHeaderButtons extends HeaderButtons {
|
||||
constructor(props) {
|
||||
super(props, RightPanel.Phase.GroupMemberList);
|
||||
this._onMembersClicked = this._onMembersClicked.bind(this);
|
||||
this._onRoomsClicked = this._onRoomsClicked.bind(this);
|
||||
}
|
||||
|
||||
onAction(payload) {
|
||||
super.onAction(payload);
|
||||
|
||||
if (payload.action === "view_user") {
|
||||
dis.dispatch({
|
||||
action: 'show_right_panel',
|
||||
});
|
||||
if (payload.member) {
|
||||
this.setPhase(RightPanel.Phase.RoomMemberInfo, {member: payload.member});
|
||||
} else {
|
||||
@ -54,27 +61,26 @@ export default class GroupHeaderButtons extends HeaderButtons {
|
||||
}
|
||||
}
|
||||
|
||||
renderButtons() {
|
||||
const groupPhases = [
|
||||
RightPanel.Phase.GroupMemberInfo,
|
||||
RightPanel.Phase.GroupMemberList,
|
||||
];
|
||||
const roomPhases = [
|
||||
RightPanel.Phase.GroupRoomList,
|
||||
RightPanel.Phase.GroupRoomInfo,
|
||||
];
|
||||
_onMembersClicked() {
|
||||
this.togglePhase(RightPanel.Phase.GroupMemberList, GROUP_PHASES);
|
||||
}
|
||||
|
||||
_onRoomsClicked() {
|
||||
this.togglePhase(RightPanel.Phase.GroupRoomList, ROOM_PHASES);
|
||||
}
|
||||
|
||||
renderButtons() {
|
||||
return [
|
||||
<HeaderButton key="groupMembersButton" name="groupMembersButton"
|
||||
title={_t('Members')}
|
||||
isHighlighted={this.isPhase(groupPhases)}
|
||||
clickPhase={RightPanel.Phase.GroupMemberList}
|
||||
isHighlighted={this.isPhase(GROUP_PHASES)}
|
||||
onClick={this._onMembersClicked}
|
||||
analytics={['Right Panel', 'Group Member List Button', 'click']}
|
||||
/>,
|
||||
<HeaderButton key="roomsButton" name="roomsButton"
|
||||
title={_t('Rooms')}
|
||||
isHighlighted={this.isPhase(roomPhases)}
|
||||
clickPhase={RightPanel.Phase.GroupRoomList}
|
||||
isHighlighted={this.isPhase(ROOM_PHASES)}
|
||||
onClick={this._onRoomsClicked}
|
||||
analytics={['Right Panel', 'Group Room List Button', 'click']}
|
||||
/>,
|
||||
];
|
||||
|
@ -20,7 +20,6 @@ limitations under the License.
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import classNames from 'classnames';
|
||||
import dis from '../../../dispatcher';
|
||||
import Analytics from '../../../Analytics';
|
||||
import AccessibleButton from '../elements/AccessibleButton';
|
||||
|
||||
@ -32,11 +31,7 @@ export default class HeaderButton extends React.Component {
|
||||
|
||||
onClick(ev) {
|
||||
Analytics.trackEvent(...this.props.analytics);
|
||||
dis.dispatch({
|
||||
action: 'view_right_panel_phase',
|
||||
phase: this.props.clickPhase,
|
||||
fromHeader: true,
|
||||
});
|
||||
this.props.onClick();
|
||||
}
|
||||
|
||||
render() {
|
||||
@ -59,9 +54,8 @@ export default class HeaderButton extends React.Component {
|
||||
HeaderButton.propTypes = {
|
||||
// Whether this button is highlighted
|
||||
isHighlighted: PropTypes.bool.isRequired,
|
||||
// The phase to swap to when the button is clicked
|
||||
clickPhase: PropTypes.string.isRequired,
|
||||
|
||||
// click handler
|
||||
onClick: PropTypes.func.isRequired,
|
||||
// The badge to display above the icon
|
||||
badge: PropTypes.node,
|
||||
// The parameters to track the click event
|
||||
|
@ -40,14 +40,36 @@ export default class HeaderButtons extends React.Component {
|
||||
dis.unregister(this.dispatcherRef);
|
||||
}
|
||||
|
||||
componentDidUpdate(prevProps) {
|
||||
if (!prevProps.collapsedRhs && this.props.collapsedRhs) {
|
||||
this.setState({
|
||||
phase: null,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
setPhase(phase, extras) {
|
||||
// TODO: delay?
|
||||
if (this.props.collapsedRhs) {
|
||||
dis.dispatch({
|
||||
action: 'show_right_panel',
|
||||
});
|
||||
}
|
||||
dis.dispatch(Object.assign({
|
||||
action: 'view_right_panel_phase',
|
||||
phase: phase,
|
||||
}, extras));
|
||||
}
|
||||
|
||||
togglePhase(phase, validPhases = [phase]) {
|
||||
if (validPhases.includes(this.state.phase)) {
|
||||
dis.dispatch({
|
||||
action: 'hide_right_panel',
|
||||
});
|
||||
} else {
|
||||
this.setPhase(phase);
|
||||
}
|
||||
}
|
||||
|
||||
isPhase(phases) {
|
||||
if (this.props.collapsedRhs) {
|
||||
return false;
|
||||
@ -61,28 +83,9 @@ export default class HeaderButtons extends React.Component {
|
||||
|
||||
onAction(payload) {
|
||||
if (payload.action === "view_right_panel_phase") {
|
||||
// only actions coming from header buttons should collapse the right panel
|
||||
if (this.state.phase === payload.phase && payload.fromHeader) {
|
||||
dis.dispatch({
|
||||
action: 'hide_right_panel',
|
||||
});
|
||||
this.setState({
|
||||
phase: null,
|
||||
});
|
||||
} else {
|
||||
if (this.props.collapsedRhs && payload.fromHeader) {
|
||||
dis.dispatch({
|
||||
action: 'show_right_panel',
|
||||
});
|
||||
// emit payload again as the RightPanel didn't exist up
|
||||
// till show_right_panel, just without the fromHeader flag
|
||||
// as that would hide the right panel again
|
||||
dis.dispatch(Object.assign({}, payload, {fromHeader: false}));
|
||||
}
|
||||
this.setState({
|
||||
phase: payload.phase,
|
||||
});
|
||||
}
|
||||
this.setState({
|
||||
phase: payload.phase,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -19,28 +19,33 @@ limitations under the License.
|
||||
|
||||
import React from 'react';
|
||||
import { _t } from '../../../languageHandler';
|
||||
import dis from '../../../dispatcher';
|
||||
import HeaderButton from './HeaderButton';
|
||||
import HeaderButtons from './HeaderButtons';
|
||||
import RightPanel from '../../structures/RightPanel';
|
||||
|
||||
const MEMBER_PHASES = [
|
||||
RightPanel.Phase.RoomMemberList,
|
||||
RightPanel.Phase.RoomMemberInfo,
|
||||
RightPanel.Phase.Room3pidMemberInfo,
|
||||
];
|
||||
|
||||
export default class RoomHeaderButtons extends HeaderButtons {
|
||||
constructor(props) {
|
||||
super(props, RightPanel.Phase.RoomMemberList);
|
||||
this._onMembersClicked = this._onMembersClicked.bind(this);
|
||||
this._onFilesClicked = this._onFilesClicked.bind(this);
|
||||
this._onNotificationsClicked = this._onNotificationsClicked.bind(this);
|
||||
}
|
||||
|
||||
onAction(payload) {
|
||||
super.onAction(payload);
|
||||
if (payload.action === "view_user") {
|
||||
dis.dispatch({
|
||||
action: 'show_right_panel',
|
||||
});
|
||||
if (payload.member) {
|
||||
this.setPhase(RightPanel.Phase.RoomMemberInfo, {member: payload.member});
|
||||
} else {
|
||||
this.setPhase(RightPanel.Phase.RoomMemberList);
|
||||
}
|
||||
} else if (payload.action === "view_room") {
|
||||
} else if (payload.action === "view_room" && !this.props.collapsedRhs) {
|
||||
this.setPhase(RightPanel.Phase.RoomMemberList);
|
||||
} else if (payload.action === "view_3pid_invite") {
|
||||
if (payload.event) {
|
||||
@ -51,30 +56,36 @@ export default class RoomHeaderButtons extends HeaderButtons {
|
||||
}
|
||||
}
|
||||
|
||||
renderButtons() {
|
||||
const membersPhases = [
|
||||
RightPanel.Phase.RoomMemberList,
|
||||
RightPanel.Phase.RoomMemberInfo,
|
||||
RightPanel.Phase.Room3pidMemberInfo,
|
||||
];
|
||||
_onMembersClicked() {
|
||||
this.togglePhase(RightPanel.Phase.RoomMemberList, MEMBER_PHASES);
|
||||
}
|
||||
|
||||
_onFilesClicked() {
|
||||
this.togglePhase(RightPanel.Phase.FilePanel);
|
||||
}
|
||||
|
||||
_onNotificationsClicked() {
|
||||
this.togglePhase(RightPanel.Phase.NotificationPanel);
|
||||
}
|
||||
|
||||
renderButtons() {
|
||||
return [
|
||||
<HeaderButton key="membersButton" name="membersButton"
|
||||
title={_t('Members')}
|
||||
isHighlighted={this.isPhase(membersPhases)}
|
||||
clickPhase={RightPanel.Phase.RoomMemberList}
|
||||
isHighlighted={this.isPhase(MEMBER_PHASES)}
|
||||
onClick={this._onMembersClicked}
|
||||
analytics={['Right Panel', 'Member List Button', 'click']}
|
||||
/>,
|
||||
<HeaderButton key="filesButton" name="filesButton"
|
||||
title={_t('Files')}
|
||||
isHighlighted={this.isPhase(RightPanel.Phase.FilePanel)}
|
||||
clickPhase={RightPanel.Phase.FilePanel}
|
||||
onClick={this._onFilesClicked}
|
||||
analytics={['Right Panel', 'File List Button', 'click']}
|
||||
/>,
|
||||
<HeaderButton key="notifsButton" name="notifsButton"
|
||||
title={_t('Notifications')}
|
||||
isHighlighted={this.isPhase(RightPanel.Phase.NotificationPanel)}
|
||||
clickPhase={RightPanel.Phase.NotificationPanel}
|
||||
onClick={this._onNotificationsClicked}
|
||||
analytics={['Right Panel', 'Notification List Button', 'click']}
|
||||
/>,
|
||||
];
|
||||
|
@ -33,12 +33,7 @@ const MAX_ROOMS = 20;
|
||||
export default class RoomBreadcrumbs extends React.Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
const tolerances = SettingsStore.getValue("breadcrumb_scroll_tolerances");
|
||||
this.state = {rooms: [], scrollTolerances: tolerances};
|
||||
|
||||
// Record this for debugging purposes
|
||||
console.log("Breadcrumbs scroll tolerances:", tolerances);
|
||||
this.state = {rooms: []};
|
||||
|
||||
this.onAction = this.onAction.bind(this);
|
||||
this._dispatcherRef = null;
|
||||
@ -343,8 +338,7 @@ export default class RoomBreadcrumbs extends React.Component {
|
||||
});
|
||||
return (
|
||||
<IndicatorScrollbar ref="scroller" className="mx_RoomBreadcrumbs"
|
||||
trackHorizontalOverflow={true} verticalScrollsHorizontally={true}
|
||||
scrollTolerances={this.state.scrollTolerances}>
|
||||
trackHorizontalOverflow={true} verticalScrollsHorizontally={true}>
|
||||
{ avatars }
|
||||
</IndicatorScrollbar>
|
||||
);
|
||||
|
@ -187,12 +187,17 @@ export default class KeyBackupPanel extends React.PureComponent {
|
||||
clientBackupStatus = <div>
|
||||
<p>{encryptedMessageAreEncrypted}</p>
|
||||
<p>{_t(
|
||||
"This device is <b>not backing up your keys</b>.", {},
|
||||
"This device is <b>not backing up your keys</b>, " +
|
||||
"but you do have an existing backup you can restore from " +
|
||||
"and add to going forward.", {},
|
||||
{b: sub => <b>{sub}</b>},
|
||||
)}</p>
|
||||
<p>{_t("Back up your keys before signing out to avoid losing them.")}</p>
|
||||
<p>{_t(
|
||||
"Connect this device to key backup before signing out to avoid " +
|
||||
"losing any keys that may only be on this device.",
|
||||
)}</p>
|
||||
</div>;
|
||||
restoreButtonCaption = _t("Use key backup");
|
||||
restoreButtonCaption = _t("Connect this device to Key Backup");
|
||||
}
|
||||
|
||||
let uploadStatus;
|
||||
@ -221,7 +226,10 @@ export default class KeyBackupPanel extends React.PureComponent {
|
||||
{sub}
|
||||
</span>;
|
||||
const device = sub => <span className="mx_KeyBackupPanel_deviceName">{deviceName}</span>;
|
||||
const fromThisDevice = sig.device.getFingerprint() === MatrixClientPeg.get().getDeviceEd25519Key();
|
||||
const fromThisDevice = (
|
||||
sig.device &&
|
||||
sig.device.getFingerprint() === MatrixClientPeg.get().getDeviceEd25519Key()
|
||||
);
|
||||
let sigStatus;
|
||||
if (!sig.device) {
|
||||
sigStatus = _t(
|
||||
|
@ -21,10 +21,12 @@ import MatrixClientPeg from "../../../../../MatrixClientPeg";
|
||||
import sdk from "../../../../..";
|
||||
import AccessibleButton from "../../../elements/AccessibleButton";
|
||||
import Modal from "../../../../../Modal";
|
||||
import dis from "../../../../../dispatcher";
|
||||
|
||||
export default class AdvancedRoomSettingsTab extends React.Component {
|
||||
static propTypes = {
|
||||
roomId: PropTypes.string.isRequired,
|
||||
closeSettingsFn: PropTypes.func.isRequired,
|
||||
};
|
||||
|
||||
constructor() {
|
||||
@ -41,9 +43,21 @@ export default class AdvancedRoomSettingsTab extends React.Component {
|
||||
const room = MatrixClientPeg.get().getRoom(this.props.roomId);
|
||||
room.getRecommendedVersion().then((v) => {
|
||||
const tombstone = room.currentState.getStateEvents("m.room.tombstone", "");
|
||||
|
||||
const additionalStateChanges = {};
|
||||
const createEvent = room.currentState.getStateEvents("m.room.create", "");
|
||||
const predecessor = createEvent ? createEvent.getContent().predecessor : null;
|
||||
if (predecessor && predecessor.room_id) {
|
||||
additionalStateChanges['oldRoomId'] = predecessor.room_id;
|
||||
additionalStateChanges['oldEventId'] = predecessor.event_id;
|
||||
additionalStateChanges['hasPreviousRoom'] = true;
|
||||
}
|
||||
|
||||
|
||||
this.setState({
|
||||
upgraded: tombstone && tombstone.getContent().replacement_room,
|
||||
upgradeRecommendation: v,
|
||||
...additionalStateChanges,
|
||||
});
|
||||
});
|
||||
}
|
||||
@ -59,6 +73,18 @@ export default class AdvancedRoomSettingsTab extends React.Component {
|
||||
Modal.createDialog(DevtoolsDialog, {roomId: this.props.roomId});
|
||||
};
|
||||
|
||||
_onOldRoomClicked = (e) => {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
|
||||
dis.dispatch({
|
||||
action: 'view_room',
|
||||
room_id: this.state.oldRoomId,
|
||||
event_id: this.state.oldEventId,
|
||||
});
|
||||
this.props.closeSettingsFn();
|
||||
};
|
||||
|
||||
render() {
|
||||
const client = MatrixClientPeg.get();
|
||||
const room = client.getRoom(this.props.roomId);
|
||||
@ -91,6 +117,18 @@ export default class AdvancedRoomSettingsTab extends React.Component {
|
||||
);
|
||||
}
|
||||
|
||||
let oldRoomLink;
|
||||
if (this.state.hasPreviousRoom) {
|
||||
let name = _t("this room");
|
||||
const room = MatrixClientPeg.get().getRoom(this.props.roomId);
|
||||
if (room && room.name) name = room.name;
|
||||
oldRoomLink = (
|
||||
<AccessibleButton element='a' onClick={this._onOldRoomClicked}>
|
||||
{_t("View older messages in %(roomName)s.", {roomName: name})}
|
||||
</AccessibleButton>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="mx_SettingsTab">
|
||||
<div className="mx_SettingsTab_heading">{_t("Advanced")}</div>
|
||||
@ -108,6 +146,7 @@ export default class AdvancedRoomSettingsTab extends React.Component {
|
||||
<span>{_t("Room version:")}</span>
|
||||
{room.getVersion()}
|
||||
</div>
|
||||
{oldRoomLink}
|
||||
{roomUpgradeButton}
|
||||
</div>
|
||||
<div className='mx_SettingsTab_section mx_SettingsTab_subsectionText'>
|
||||
|
@ -136,7 +136,7 @@ export default class HelpUserSettingsTab extends React.Component {
|
||||
<li>
|
||||
The <a href="themes/riot/img/backgrounds/valley.jpg" rel="noopener" target="_blank">
|
||||
default cover photo</a> is (C)
|
||||
<a href="https://www.flickr.com/golan" rel="noopener" target="_blank">Jesús Roncero</a>
|
||||
<a href="https://www.flickr.com/golan" rel="noopener" target="_blank">Jesús Roncero</a>{' '}
|
||||
used under the terms of
|
||||
<a href="https://creativecommons.org/licenses/by-sa/4.0/" rel="noopener" target="_blank">
|
||||
CC-BY-SA 4.0</a>. No warranties are given.
|
||||
|
@ -142,7 +142,7 @@
|
||||
"Room upgrades are usually recommended when a room version is considered <i>unstable</i>. Unstable room versions might have bugs, missing features, or security vulnerabilities.": "Room upgrades are usually recommended when a room version is considered <i>unstable</i>. Unstable room versions might have bugs, missing features, or security vulnerabilities.",
|
||||
"Room upgrades usually only affect <i>server-side</i> processing of the room. If you're having problems with your Riot client, please file an issue with <issueLink />.": "Room upgrades usually only affect <i>server-side</i> processing of the room. If you're having problems with your Riot client, please file an issue with <issueLink />.",
|
||||
"<b>Warning</b>: Upgrading a room will <i>not automatically migrate room members to the new version of the room.</i> We'll post a link to the new room in the old version of the room - room members will have to click this link to join the new room.": "<b>Warning</b>: Upgrading a room will <i>not automatically migrate room members to the new version of the room.</i> We'll post a link to the new room in the old version of the room - room members will have to click this link to join the new room.",
|
||||
"Please confirm that you'd like to go forward with upgrading this room from <oldVersion /> to <newVersion />": "Please confirm that you'd like to go forward with upgrading this room from <oldVersion /> to <newVersion />",
|
||||
"Please confirm that you'd like to go forward with upgrading this room from <oldVersion /> to <newVersion />.": "Please confirm that you'd like to go forward with upgrading this room from <oldVersion /> to <newVersion />.",
|
||||
"Upgrade": "Upgrade",
|
||||
"Changes your display nickname": "Changes your display nickname",
|
||||
"Changes your display nickname in the current room only": "Changes your display nickname in the current room only",
|
||||
@ -467,9 +467,9 @@
|
||||
"Unable to load key backup status": "Unable to load key backup status",
|
||||
"Restore from Backup": "Restore from Backup",
|
||||
"This device is backing up your keys. ": "This device is backing up your keys. ",
|
||||
"This device is <b>not backing up your keys</b>.": "This device is <b>not backing up your keys</b>.",
|
||||
"Back up your keys before signing out to avoid losing them.": "Back up your keys before signing out to avoid losing them.",
|
||||
"Use key backup": "Use key backup",
|
||||
"This device is <b>not backing up your keys</b>, but you do have an existing backup you can restore from and add to going forward.": "This device is <b>not backing up your keys</b>, but you do have an existing backup you can restore from and add to going forward.",
|
||||
"Connect this device to key backup before signing out to avoid losing any keys that may only be on this device.": "Connect this device to key backup before signing out to avoid losing any keys that may only be on this device.",
|
||||
"Connect this device to Key Backup": "Connect this device to Key Backup",
|
||||
"Backing up %(sessionsRemaining)s keys...": "Backing up %(sessionsRemaining)s keys...",
|
||||
"All keys backed up": "All keys backed up",
|
||||
"Backup has a signature from <verify>unknown</verify> device with ID %(deviceId)s.": "Backup has a signature from <verify>unknown</verify> device with ID %(deviceId)s.",
|
||||
@ -485,6 +485,7 @@
|
||||
"Backup version: ": "Backup version: ",
|
||||
"Algorithm: ": "Algorithm: ",
|
||||
"Your keys are <b>not being backed up from this device</b>.": "Your keys are <b>not being backed up from this device</b>.",
|
||||
"Back up your keys before signing out to avoid losing them.": "Back up your keys before signing out to avoid losing them.",
|
||||
"Start using Key Backup": "Start using Key Backup",
|
||||
"Error saving email notification preferences": "Error saving email notification preferences",
|
||||
"An error occurred whilst saving your email notification preferences.": "An error occurred whilst saving your email notification preferences.",
|
||||
@ -599,6 +600,8 @@
|
||||
"Voice & Video": "Voice & Video",
|
||||
"This room is not accessible by remote Matrix servers": "This room is not accessible by remote Matrix servers",
|
||||
"Upgrade this room to the recommended room version": "Upgrade this room to the recommended room version",
|
||||
"this room": "this room",
|
||||
"View older messages in %(roomName)s": "View older messages in %(roomName)s",
|
||||
"Room information": "Room information",
|
||||
"Internal room ID:": "Internal room ID:",
|
||||
"Room version": "Room version",
|
||||
@ -1347,6 +1350,8 @@
|
||||
"You must <a>register</a> to use this functionality": "You must <a>register</a> to use this functionality",
|
||||
"You must join the room to see its files": "You must join the room to see its files",
|
||||
"There are no visible files in this room": "There are no visible files in this room",
|
||||
"Error loading Riot": "Error loading Riot",
|
||||
"If this is unexpected, please contact your system administrator or technical support representative.": "If this is unexpected, please contact your system administrator or technical support representative.",
|
||||
"<h1>HTML for your community's page</h1>\n<p>\n Use the long description to introduce new members to the community, or distribute\n some important <a href=\"foo\">links</a>\n</p>\n<p>\n You can even use 'img' tags\n</p>\n": "<h1>HTML for your community's page</h1>\n<p>\n Use the long description to introduce new members to the community, or distribute\n some important <a href=\"foo\">links</a>\n</p>\n<p>\n You can even use 'img' tags\n</p>\n",
|
||||
"Add rooms to the community summary": "Add rooms to the community summary",
|
||||
"Which rooms would you like to add to this summary?": "Which rooms would you like to add to this summary?",
|
||||
@ -1487,7 +1492,12 @@
|
||||
"Return to login screen": "Return to login screen",
|
||||
"Set a new password": "Set a new password",
|
||||
"Invalid homeserver discovery response": "Invalid homeserver discovery response",
|
||||
"Failed to get autodiscovery configuration from server": "Failed to get autodiscovery configuration from server",
|
||||
"Invalid base_url for m.homeserver": "Invalid base_url for m.homeserver",
|
||||
"Homeserver URL does not appear to be a valid Matrix homeserver": "Homeserver URL does not appear to be a valid Matrix homeserver",
|
||||
"Invalid identity server discovery response": "Invalid identity server discovery response",
|
||||
"Invalid base_url for m.identity_server": "Invalid base_url for m.identity_server",
|
||||
"Identity server URL does not appear to be a valid identity server": "Identity server URL does not appear to be a valid identity server",
|
||||
"General failure": "General failure",
|
||||
"This homeserver does not support login using email address.": "This homeserver does not support login using email address.",
|
||||
"Please <a>contact your service administrator</a> to continue using this service.": "Please <a>contact your service administrator</a> to continue using this service.",
|
||||
|
@ -77,6 +77,7 @@ export class RoomPermalinkCreator {
|
||||
this._bannedHostsRegexps = null;
|
||||
this._allowedHostsRegexps = null;
|
||||
this._serverCandidates = null;
|
||||
this._started = false;
|
||||
|
||||
this.onMembership = this.onMembership.bind(this);
|
||||
this.onRoomState = this.onRoomState.bind(this);
|
||||
@ -101,11 +102,17 @@ export class RoomPermalinkCreator {
|
||||
this.load();
|
||||
this._room.on("RoomMember.membership", this.onMembership);
|
||||
this._room.on("RoomState.events", this.onRoomState);
|
||||
this._started = true;
|
||||
}
|
||||
|
||||
stop() {
|
||||
this._room.removeListener("RoomMember.membership", this.onMembership);
|
||||
this._room.removeListener("RoomState.events", this.onRoomState);
|
||||
this._started = false;
|
||||
}
|
||||
|
||||
isStarted() {
|
||||
return this._started;
|
||||
}
|
||||
|
||||
forEvent(eventId) {
|
||||
|
@ -262,13 +262,6 @@ export const SETTINGS = {
|
||||
supportedLevels: ['account'],
|
||||
default: [],
|
||||
},
|
||||
"breadcrumb_scroll_tolerances": {
|
||||
supportedLevels: LEVELS_DEVICE_ONLY_SETTINGS,
|
||||
default: {
|
||||
xyThreshold: 10,
|
||||
yReduction: 0.8,
|
||||
},
|
||||
},
|
||||
"analyticsOptIn": {
|
||||
supportedLevels: LEVELS_DEVICE_ONLY_SETTINGS_WITH_CONFIG,
|
||||
displayName: _td('Send analytics data'),
|
||||
|
Loading…
Reference in New Issue
Block a user