Merge branch 'develop' into new-guest-access

This commit is contained in:
Luke Barnard 2017-05-11 09:50:13 +01:00
commit 2eccdf56b9
48 changed files with 293 additions and 276 deletions

View file

@ -1,5 +1,6 @@
/*
Copyright 2015, 2016 OpenMarket Ltd
Copyright 2017 Vector Creations Ltd
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@ -14,13 +15,8 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
'use strict';
var React = require('react');
var ReactDOM = require('react-dom');
var sdk = require('matrix-react-sdk')
var dis = require('matrix-react-sdk/lib/dispatcher');
var AccessibleButton = require('matrix-react-sdk/lib/components/views/elements/AccessibleButton');
import React from 'react';
import sdk from 'matrix-react-sdk';
module.exports = React.createClass({
displayName: 'BottomLeftMenu',
@ -30,121 +26,28 @@ module.exports = React.createClass({
teamToken: React.PropTypes.string,
},
getInitialState: function() {
return({
directoryHover : false,
roomsHover : false,
homeHover: false,
peopleHover : false,
settingsHover : false,
});
},
// Room events
onDirectoryClick: function() {
dis.dispatch({ action: 'view_room_directory' });
},
onDirectoryMouseEnter: function() {
this.setState({ directoryHover: true });
},
onDirectoryMouseLeave: function() {
this.setState({ directoryHover: false });
},
onRoomsClick: function() {
dis.dispatch({ action: 'view_create_room' });
},
onRoomsMouseEnter: function() {
this.setState({ roomsHover: true });
},
onRoomsMouseLeave: function() {
this.setState({ roomsHover: false });
},
// Home button events
onHomeClick: function() {
dis.dispatch({ action: 'view_home_page' });
},
onHomeMouseEnter: function() {
this.setState({ homeHover: true });
},
onHomeMouseLeave: function() {
this.setState({ homeHover: false });
},
// People events
onPeopleClick: function() {
dis.dispatch({ action: 'view_create_chat' });
},
onPeopleMouseEnter: function() {
this.setState({ peopleHover: true });
},
onPeopleMouseLeave: function() {
this.setState({ peopleHover: false });
},
// Settings events
onSettingsClick: function() {
dis.dispatch({ action: 'view_user_settings' });
},
onSettingsMouseEnter: function() {
this.setState({ settingsHover: true });
},
onSettingsMouseLeave: function() {
this.setState({ settingsHover: false });
},
// Get the label/tooltip to show
getLabel: function(label, show) {
if (show) {
var RoomTooltip = sdk.getComponent("rooms.RoomTooltip");
return <RoomTooltip className="mx_BottomLeftMenu_tooltip" label={label} />;
}
},
render: function() {
var TintableSvg = sdk.getComponent('elements.TintableSvg');
const HomeButton = sdk.getComponent('elements.HomeButton');
const StartChatButton = sdk.getComponent('elements.StartChatButton');
const RoomDirectoryButton = sdk.getComponent('elements.RoomDirectoryButton');
const CreateRoomButton = sdk.getComponent('elements.CreateRoomButton');
const SettingsButton = sdk.getComponent('elements.SettingsButton');
var homeButton;
if (this.props.teamToken) {
homeButton = (
<AccessibleButton className="mx_BottomLeftMenu_homePage" onClick={ this.onHomeClick } onMouseEnter={ this.onHomeMouseEnter } onMouseLeave={ this.onHomeMouseLeave } >
<TintableSvg src="img/icons-home.svg" width="25" height="25" />
{ this.getLabel("Welcome page", this.state.homeHover) }
</AccessibleButton>
);
homeButton = <HomeButton tooltip={true} />;
}
return (
<div className="mx_BottomLeftMenu">
<div className="mx_BottomLeftMenu_options">
{ homeButton }
<AccessibleButton className="mx_BottomLeftMenu_people" onClick={ this.onPeopleClick } onMouseEnter={ this.onPeopleMouseEnter } onMouseLeave={ this.onPeopleMouseLeave } >
<TintableSvg src="img/icons-people.svg" width="25" height="25" />
{ this.getLabel("Start chat", this.state.peopleHover) }
</AccessibleButton>
<AccessibleButton className="mx_BottomLeftMenu_directory" onClick={ this.onDirectoryClick } onMouseEnter={ this.onDirectoryMouseEnter } onMouseLeave={ this.onDirectoryMouseLeave } >
<TintableSvg src="img/icons-directory.svg" width="25" height="25"/>
{ this.getLabel("Room directory", this.state.directoryHover) }
</AccessibleButton>
<AccessibleButton className="mx_BottomLeftMenu_createRoom" onClick={ this.onRoomsClick } onMouseEnter={ this.onRoomsMouseEnter } onMouseLeave={ this.onRoomsMouseLeave } >
<TintableSvg src="img/icons-create-room.svg" width="25" height="25" />
{ this.getLabel("Create new room", this.state.roomsHover) }
</AccessibleButton>
<AccessibleButton className="mx_BottomLeftMenu_settings" onClick={ this.onSettingsClick } onMouseEnter={ this.onSettingsMouseEnter } onMouseLeave={ this.onSettingsMouseLeave } >
<TintableSvg src="img/icons-settings.svg" width="25" height="25" />
{ this.getLabel("Settings", this.state.settingsHover) }
</AccessibleButton>
<StartChatButton tooltip={true} />
<RoomDirectoryButton tooltip={true} />
<CreateRoomButton tooltip={true} />
<span className="mx_BottomLeftMenu_settings">
<SettingsButton tooltip={true} />
</span>
</div>
</div>
);

View file

@ -204,7 +204,7 @@ module.exports = React.createClass({
}).done(() => {
modal.close();
this.refreshRoomList();
}, function(err) {
}, (err) => {
modal.close();
this.refreshRoomList();
console.error("Failed to " + step + ": " + err);

View file

@ -1,4 +1,5 @@
/*
Copyright 2017 Vector Creations Ltd
Copyright 2015, 2016 OpenMarket Ltd
Licensed under the Apache License, Version 2.0 (the "License");
@ -29,6 +30,7 @@ var FormattingUtils = require('matrix-react-sdk/lib/utils/FormattingUtils');
var AccessibleButton = require('matrix-react-sdk/lib/components/views/elements/AccessibleButton');
var ConstantTimeDispatcher = require('matrix-react-sdk/lib/ConstantTimeDispatcher');
var RoomSubListHeader = require('./RoomSubListHeader.js');
import Modal from 'matrix-react-sdk/lib/Modal';
// turn this on for drag & drop console debugging galore
var debug = false;
@ -82,6 +84,8 @@ var RoomSubList = React.createClass({
incomingCall: React.PropTypes.object,
onShowMoreRooms: React.PropTypes.func,
searchFilter: React.PropTypes.string,
emptyContent: React.PropTypes.node, // content shown if the list is empty
headerItems: React.PropTypes.node, // content shown in the sublist header
},
getInitialState: function() {
@ -468,16 +472,15 @@ var RoomSubList = React.createClass({
render: function() {
var connectDropTarget = this.props.connectDropTarget;
var RoomDropTarget = sdk.getComponent('rooms.RoomDropTarget');
var TruncatedList = sdk.getComponent('elements.TruncatedList');
var label = this.props.collapsed ? null : this.props.label;
//console.log("render: " + JSON.stringify(this.state.sortedList));
var target;
if (this.state.sortedList.length == 0 && this.props.editable) {
target = <RoomDropTarget label={ 'Drop here to ' + this.props.verb }/>;
let content;
if (this.state.sortedList.length == 0) {
content = this.props.emptyContent;
} else {
content = this.makeRoomTiles();
}
var roomCount = this.props.list.length > 0 ? this.props.list.length : '';
@ -497,8 +500,7 @@ var RoomSubList = React.createClass({
if (!this.state.hidden) {
subList = <TruncatedList className={ classes } truncateAt={this.state.truncateAt}
createOverflowElement={this._createOverflowTile} >
{ target }
{ this.makeRoomTiles() }
{ content }
</TruncatedList>;
}
else {
@ -520,6 +522,7 @@ var RoomSubList = React.createClass({
roomNotificationCount={ this.roomNotificationCount() }
onClick={ this.onClick }
onHeaderClick={ this.props.onHeaderClick }
headerItems={this.props.headerItems}
/>
{ subList }
</div>
@ -541,6 +544,7 @@ var RoomSubList = React.createClass({
roomNotificationCount={ this.roomNotificationCount() }
onClick={ this.onClick }
onHeaderClick={ this.props.onHeaderClick }
headerItems={this.props.headerItems}
/>
: undefined }
{ (this.props.showSpinner && !this.state.hidden) ? <Loader /> : undefined }

View file

@ -14,16 +14,11 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
'use strict';
var React = require('react');
var ReactDOM = require('react-dom');
var classNames = require('classnames');
var sdk = require('matrix-react-sdk')
var FormattingUtils = require('matrix-react-sdk/lib/utils/FormattingUtils');
var RoomNotifs = require('matrix-react-sdk/lib/RoomNotifs');
var AccessibleButton = require('matrix-react-sdk/lib/components/views/elements/AccessibleButton');
var ConstantTimeDispatcher = require('matrix-react-sdk/lib/ConstantTimeDispatcher');
import React from 'react';
import classNames from 'classnames';
import sdk from 'matrix-react-sdk';
import { formatCount } from 'matrix-react-sdk/lib/utils/FormattingUtils';
import AccessibleButton from 'matrix-react-sdk/lib/components/views/elements/AccessibleButton';
module.exports = React.createClass({
displayName: 'RoomSubListHeader',
@ -42,6 +37,7 @@ module.exports = React.createClass({
hidden: React.PropTypes.bool,
onClick: React.PropTypes.func,
onHeaderClick: React.PropTypes.func,
headerItems: React.PropTypes.node, // content shown in the sublist header
},
getDefaultProps: function() {
@ -63,35 +59,34 @@ module.exports = React.createClass({
// },
render: function() {
var TintableSvg = sdk.getComponent("elements.TintableSvg");
const TintableSvg = sdk.getComponent("elements.TintableSvg");
var subListNotifications = this.props.roomNotificationCount;
var subListNotifCount = subListNotifications[0];
var subListNotifHighlight = subListNotifications[1];
const subListNotifications = this.props.roomNotificationCount;
const subListNotifCount = subListNotifications[0];
const subListNotifHighlight = subListNotifications[1];
var chevronClasses = classNames({
const chevronClasses = classNames({
'mx_RoomSubList_chevron': true,
'mx_RoomSubList_chevronRight': this.props.hidden,
'mx_RoomSubList_chevronDown': !this.props.hidden,
});
var badgeClasses = classNames({
const badgeClasses = classNames({
'mx_RoomSubList_badge': true,
'mx_RoomSubList_badgeHighlight': subListNotifHighlight,
});
var badge;
let badge;
if (subListNotifCount > 0) {
badge = <div className={badgeClasses}>{ FormattingUtils.formatCount(subListNotifCount) }</div>;
}
else if (subListNotifHighlight) {
badge = <div className={badgeClasses}>{ formatCount(subListNotifCount) }</div>;
} else if (subListNotifHighlight) {
badge = <div className={badgeClasses}>!</div>;
}
// When collapsed, allow a long hover on the header to show user
// the full tag name and room count
var title;
var roomCount = this.props.roomCount;
let title;
const roomCount = this.props.roomCount;
if (this.props.collapsed) {
title = this.props.label;
if (roomCount !== '') {
@ -99,9 +94,9 @@ module.exports = React.createClass({
}
}
var incomingCall;
let incomingCall;
if (this.props.isIncomingCallRoom) {
var IncomingCallBox = sdk.getComponent("voip.IncomingCallBox");
const IncomingCallBox = sdk.getComponent("voip.IncomingCallBox");
incomingCall = <IncomingCallBox className="mx_RoomSubList_incomingCall" incomingCall={ this.props.incomingCall }/>;
}
@ -109,6 +104,7 @@ module.exports = React.createClass({
<div className="mx_RoomSubList_labelContainer" title={ title } ref="header">
<AccessibleButton onClick={ this.props.onClick } className="mx_RoomSubList_label" tabIndex="0">
{ this.props.collapsed ? '' : this.props.label }
{this.props.headerItems}
<div className="mx_RoomSubList_roomCount">{ roomCount }</div>
<div className={chevronClasses}></div>
{ badge }

View file

@ -27,6 +27,7 @@
@import "./matrix-react-sdk/views/elements/_MemberEventListSummary.scss";
@import "./matrix-react-sdk/views/elements/_ProgressBar.scss";
@import "./matrix-react-sdk/views/elements/_RichText.scss";
@import "./matrix-react-sdk/views/elements/_RoleButton.scss";
@import "./matrix-react-sdk/views/login/_InteractiveAuthEntryComponents.scss";
@import "./matrix-react-sdk/views/login/_ServerConfig.scss";
@import "./matrix-react-sdk/views/messages/_MEmoteBody.scss";

View file

@ -160,7 +160,8 @@ hr.mx_RoomView_myReadMarker {
border-bottom: solid 1px $accent-color;
margin-top: 0px;
position: relative;
top: 5px;
top: -1px;
z-index: 1;
}
.mx_RoomView_statusArea {

View file

@ -20,6 +20,7 @@ limitations under the License.
.mx_TextualEvent.mx_MemberEventListSummary_summary {
font-size: 14px;
display: inline-flex;
}
.mx_MemberEventListSummary_avatars {

View file

@ -0,0 +1,33 @@
/*
Copyright 2107 Vector Creations 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.
*/
.mx_RoleButton {
margin-left: 4px;
margin-right: 4px;
cursor: pointer;
display: inline-block;
}
.mx_RoleButton object {
pointer-events: none;
}
.mx_RoleButton_tooltip {
display: inline-block;
position: relative;
top: -25px;
left: 6px;
}

View file

@ -1,5 +1,6 @@
/*
Copyright 2015, 2016 OpenMarket Ltd
Copyright 2107 Vector Creations Ltd
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@ -37,3 +38,25 @@ limitations under the License.
.mx_RoomList_scrollbar .gm-scrollbar.-vertical {
z-index: 6;
}
.mx_RoomList_emptySubListTip {
font-size: 13px;
margin-left: 18px;
margin-right: 18px;
margin-top: 8px;
margin-bottom: 7px;
padding: 5px;
border: 1px dashed $accent-color;
color: $primary-fg-color;
background-color: $droptarget-bg-color;
border-radius: 4px;
}
.mx_RoomList_emptySubListTip .mx_RoleButton {
vertical-align: -3px;
}
.mx_RoomList_headerButtons {
position: absolute;
right: 60px;
}

View file

@ -64,43 +64,25 @@ limitations under the License.
pointer-events: none;
}
.mx_LeftPanel .mx_BottomLeftMenu_homePage,
.mx_LeftPanel .mx_BottomLeftMenu_directory,
.mx_LeftPanel .mx_BottomLeftMenu_createRoom,
.mx_LeftPanel .mx_BottomLeftMenu_people,
.mx_LeftPanel .mx_BottomLeftMenu_settings {
display: inline-block;
cursor: pointer;
}
.collapsed .mx_BottomLeftMenu_homePage,
.collapsed .mx_BottomLeftMenu_directory,
.collapsed .mx_BottomLeftMenu_createRoom,
.collapsed .mx_BottomLeftMenu_people,
.collapsed .mx_BottomLeftMenu_settings {
.collapsed .mx_RoleButton {
margin-right: 0px ! important;
padding-top: 3px ! important;
padding-bottom: 3px ! important;
}
.mx_LeftPanel .mx_BottomLeftMenu_homePage,
.mx_LeftPanel .mx_BottomLeftMenu_directory,
.mx_LeftPanel .mx_BottomLeftMenu_createRoom,
.mx_LeftPanel .mx_BottomLeftMenu_people {
.mx_BottomLeftMenu_options .mx_RoleButton {
margin-left: 0px;
margin-right: 10px;
}
.mx_LeftPanel .mx_BottomLeftMenu_settings {
.mx_BottomLeftMenu_options .mx_BottomLeftMenu_settings {
float: right;
}
.mx_BottomLeftMenu_options .mx_BottomLeftMenu_settings .mx_RoleButton {
margin-right: 0px;
}
.mx_LeftPanel.collapsed .mx_BottomLeftMenu_settings {
float: none;
}
.mx_LeftPanel .mx_BottomLeftMenu_tooltip {
display: inline-block;
position: relative;
top: -25px;
left: 6px;
}

View file

@ -20,13 +20,11 @@ limitations under the License.
import VectorBasePlatform from './VectorBasePlatform';
import dis from 'matrix-react-sdk/lib/dispatcher';
import q from 'q';
const electron = require('electron');
const remote = electron.remote;
import electron, {remote} from 'electron';
remote.autoUpdater.on('update-downloaded', onUpdateDownloaded);
function onUpdateDownloaded(ev, releaseNotes, ver, date, updateURL) {
function onUpdateDownloaded(ev: Event, releaseNotes: string, ver: string, date: Date, updateURL: string) {
dis.dispatch({
action: 'new_version',
currentVersion: remote.app.getVersion(),
@ -35,7 +33,7 @@ function onUpdateDownloaded(ev, releaseNotes, ver, date, updateURL) {
});
}
function platformFriendlyName() {
function platformFriendlyName(): string {
console.log(window.process);
switch (window.process.platform) {
case 'darwin':
@ -72,11 +70,11 @@ export default class ElectronPlatform extends VectorBasePlatform {
}
}
supportsNotifications() : boolean {
supportsNotifications(): boolean {
return true;
}
maySendNotifications() : boolean {
maySendNotifications(): boolean {
return true;
}
@ -100,7 +98,7 @@ export default class ElectronPlatform extends VectorBasePlatform {
icon: avatarUrl,
tag: 'vector',
silent: true, // we play our own sounds
}
},
);
notification.onclick = function() {
@ -123,7 +121,7 @@ export default class ElectronPlatform extends VectorBasePlatform {
notif.close();
}
getAppVersion() {
getAppVersion(): Promise<string> {
return q(remote.app.getVersion());
}
@ -140,15 +138,15 @@ export default class ElectronPlatform extends VectorBasePlatform {
electron.ipcRenderer.send('install_update');
}
getDefaultDeviceDisplayName() {
getDefaultDeviceDisplayName(): string {
return 'Riot Desktop on ' + platformFriendlyName();
}
screenCaptureErrorString() {
screenCaptureErrorString(): ?string {
return null;
}
requestNotificationPermission() : Promise {
requestNotificationPermission(): Promise<string> {
return q('granted');
}

View file

@ -44,7 +44,7 @@ export default class VectorBasePlatform extends BasePlatform {
* Get a sensible default display name for the
* device Vector is running on
*/
getDefaultDeviceDisplayName() {
getDefaultDeviceDisplayName(): string {
return "Unknown device";
}
}

View file

@ -52,7 +52,7 @@ export default class WebPlatform extends VectorBasePlatform {
}
this.favicon.badge(notif, {
bgColor: bgColor
bgColor: bgColor,
});
} catch (e) {
console.warn(`Failed to set badge count: ${e.message}`);
@ -75,7 +75,7 @@ export default class WebPlatform extends VectorBasePlatform {
* Returns true if the platform supports displaying
* notifications, otherwise false.
*/
supportsNotifications() : boolean {
supportsNotifications(): boolean {
return Boolean(global.Notification);
}
@ -83,8 +83,8 @@ export default class WebPlatform extends VectorBasePlatform {
* Returns true if the application currently has permission
* to display notifications. Otherwise false.
*/
maySendNotifications() : boolean {
return global.Notification.permission == 'granted';
maySendNotifications(): boolean {
return global.Notification.permission === 'granted';
}
/**
@ -94,7 +94,7 @@ export default class WebPlatform extends VectorBasePlatform {
* that is 'granted' if the user allowed the request or
* 'denied' otherwise.
*/
requestNotificationPermission() : Promise {
requestNotificationPermission(): Promise<string> {
// annoyingly, the latest spec says this returns a
// promise, but this is only supported in Chrome 46
// and Firefox 47, so adapt the callback API.
@ -113,13 +113,13 @@ export default class WebPlatform extends VectorBasePlatform {
icon: avatarUrl,
tag: "vector",
silent: true, // we play our own sounds
}
},
);
notification.onclick = function() {
dis.dispatch({
action: 'view_room',
room_id: room.roomId
room_id: room.roomId,
});
global.focus();
notification.close();
@ -132,7 +132,7 @@ export default class WebPlatform extends VectorBasePlatform {
}, 5 * 1000);
}
_getVersion() {
_getVersion(): Promise<string> {
const deferred = q.defer();
// We add a cachebuster to the request to make sure that we know about
@ -148,19 +148,19 @@ export default class WebPlatform extends VectorBasePlatform {
},
(err, response, body) => {
if (err || response.status < 200 || response.status >= 300) {
if (err == null) err = { status: response.status };
if (err === null) err = { status: response.status };
deferred.reject(err);
return;
}
const ver = body.trim();
deferred.resolve(ver);
}
},
);
return deferred.promise;
}
getAppVersion() {
getAppVersion(): Promise<string> {
if (this.runningVersion !== null) {
return q(this.runningVersion);
}
@ -169,9 +169,9 @@ export default class WebPlatform extends VectorBasePlatform {
pollForUpdate() {
this._getVersion().done((ver) => {
if (this.runningVersion == null) {
if (this.runningVersion === null) {
this.runningVersion = ver;
} else if (this.runningVersion != ver) {
} else if (this.runningVersion !== ver) {
dis.dispatch({
action: 'new_version',
currentVersion: this.runningVersion,
@ -187,19 +187,18 @@ export default class WebPlatform extends VectorBasePlatform {
window.location.reload();
}
getDefaultDeviceDisplayName() {
getDefaultDeviceDisplayName(): string {
// strip query-string and fragment from uri
let u = url.parse(window.location.href);
const u = url.parse(window.location.href);
u.search = "";
u.hash = "";
let app_name = u.format();
const appName = u.format();
let ua = new UAParser();
return app_name + " via " + ua.getBrowser().name +
" on " + ua.getOS().name;
const ua = new UAParser();
return `${appName} via ${ua.getBrowser().name} on ${ua.getOS().name}`;
}
screenCaptureErrorString() {
screenCaptureErrorString(): ?string {
// it won't work at all if you're not on HTTPS so whine whine whine
if (!global.window || global.window.location.protocol !== "https:") {
return "You need to be using HTTPS to place a screen-sharing call.";

View file

@ -17,6 +17,7 @@ limitations under the License.
import pako from 'pako';
import q from "q";
import MatrixClientPeg from 'matrix-react-sdk/lib/MatrixClientPeg';
import PlatformPeg from 'matrix-react-sdk/lib/PlatformPeg';
import rageshake from './rageshake'
@ -64,6 +65,8 @@ export default async function sendBugReport(bugReportEndpoint, opts) {
userAgent = window.navigator.userAgent;
}
const client = MatrixClientPeg.get();
console.log("Sending bug report.");
const body = new FormData();
@ -72,6 +75,11 @@ export default async function sendBugReport(bugReportEndpoint, opts) {
body.append('version', version);
body.append('user_agent', userAgent);
if (client) {
body.append('user_id', client.credentials.userId);
body.append('device_id', client.deviceId);
}
if (opts.sendLogs) {
progressCallback("Collecting logs");
const logs = await rageshake.getLogsForReport();