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

1
.gitignore vendored
View file

@ -5,6 +5,7 @@
/key.pem /key.pem
/lib /lib
/node_modules /node_modules
/electron/node_modules
/packages/ /packages/
/webapp /webapp
/.npmrc /.npmrc

View file

@ -1,3 +1,24 @@
Changes in [0.9.9](https://github.com/vector-im/riot-web/releases/tag/v0.9.9) (2017-04-25)
==========================================================================================
[Full Changelog](https://github.com/vector-im/riot-web/compare/v0.9.9-rc.2...v0.9.9)
* No changes
Changes in [0.9.9-rc.2](https://github.com/vector-im/riot-web/releases/tag/v0.9.9-rc.2) (2017-04-24)
====================================================================================================
[Full Changelog](https://github.com/vector-im/riot-web/compare/v0.9.9-rc.1...v0.9.9-rc.2)
* Fix bug where links to Riot would fail to open.
Changes in [0.9.9-rc.1](https://github.com/vector-im/riot-web/releases/tag/v0.9.9-rc.1) (2017-04-21)
====================================================================================================
[Full Changelog](https://github.com/vector-im/riot-web/compare/v0.9.8...v0.9.9-rc.1)
* Update js-sdk and matrix-react-sdk to fix registration without a captcha (https://github.com/vector-im/riot-web/issues/3621)
Changes in [0.9.8](https://github.com/vector-im/riot-web/releases/tag/v0.9.8) (2017-04-12) Changes in [0.9.8](https://github.com/vector-im/riot-web/releases/tag/v0.9.8) (2017-04-12)
========================================================================================== ==========================================================================================
[Full Changelog](https://github.com/vector-im/riot-web/compare/v0.9.8-rc.3...v0.9.8) [Full Changelog](https://github.com/vector-im/riot-web/compare/v0.9.8-rc.3...v0.9.8)

View file

@ -135,7 +135,7 @@ To run as a desktop app:
``` ```
npm install electron npm install electron
node_modules/.bin/electron . npm run electron
``` ```
To build packages, use electron-builder. This is configured to output: To build packages, use electron-builder. This is configured to output:

View file

@ -4,7 +4,7 @@
"brand": "Riot", "brand": "Riot",
"integrations_ui_url": "https://scalar.vector.im/", "integrations_ui_url": "https://scalar.vector.im/",
"integrations_rest_url": "https://scalar.vector.im/api", "integrations_rest_url": "https://scalar.vector.im/api",
"bug_report_endpoint_url": "https://vector.im/bugs", "bug_report_endpoint_url": "https://riot.im/bugreports/submit",
"enableLabs": true, "enableLabs": true,
"roomDirectory": { "roomDirectory": {
"servers": [ "servers": [

Binary file not shown.

Before

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

View file

Before

Width:  |  Height:  |  Size: 102 KiB

After

Width:  |  Height:  |  Size: 102 KiB

View file

Before

Width:  |  Height:  |  Size: 7.2 KiB

After

Width:  |  Height:  |  Size: 7.2 KiB

View file

Before

Width:  |  Height:  |  Size: 673 B

After

Width:  |  Height:  |  Size: 673 B

View file

Before

Width:  |  Height:  |  Size: 1.1 KiB

After

Width:  |  Height:  |  Size: 1.1 KiB

View file

Before

Width:  |  Height:  |  Size: 14 KiB

After

Width:  |  Height:  |  Size: 14 KiB

View file

Before

Width:  |  Height:  |  Size: 2.6 KiB

After

Width:  |  Height:  |  Size: 2.6 KiB

View file

Before

Width:  |  Height:  |  Size: 30 KiB

After

Width:  |  Height:  |  Size: 30 KiB

View file

Before

Width:  |  Height:  |  Size: 3.6 KiB

After

Width:  |  Height:  |  Size: 3.6 KiB

View file

Before

Width:  |  Height:  |  Size: 5.5 KiB

After

Width:  |  Height:  |  Size: 5.5 KiB

View file

Before

Width:  |  Height:  |  Size: 4.4 KiB

After

Width:  |  Height:  |  Size: 4.4 KiB

BIN
electron_app/img/riot.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 102 KiB

BIN
electron_app/img/riot.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

11
electron_app/package.json Normal file
View file

@ -0,0 +1,11 @@
{
"name": "riot-web",
"productName": "Riot",
"main": "src/electron-main.js",
"version": "0.9.9",
"description": "A feature-rich client for Matrix.org",
"author": "Vector Creations Ltd.",
"dependencies": {
"electron-window-state": "^4.1.0"
}
}

View file

@ -30,6 +30,8 @@ const tray = require('./tray');
const VectorMenu = require('./vectormenu'); const VectorMenu = require('./vectormenu');
const windowStateKeeper = require('electron-window-state');
let vectorConfig = {}; let vectorConfig = {};
try { try {
vectorConfig = require('../../webapp/config.json'); vectorConfig = require('../../webapp/config.json');
@ -187,11 +189,21 @@ electron.app.on('ready', () => {
process.platform == 'win32' ? 'ico' : 'png' process.platform == 'win32' ? 'ico' : 'png'
); );
// Load the previous window state with fallback to defaults
let mainWindowState = windowStateKeeper({
defaultWidth: 1024,
defaultHeight: 768,
});
mainWindow = new electron.BrowserWindow({ mainWindow = new electron.BrowserWindow({
icon: icon_path, icon: icon_path,
width: 1024, height: 768,
show: false, show: false,
autoHideMenuBar: true, autoHideMenuBar: true,
x: mainWindowState.x,
y: mainWindowState.y,
width: mainWindowState.width,
height: mainWindowState.height,
}); });
mainWindow.loadURL(`file://${__dirname}/../../webapp/index.html`); mainWindow.loadURL(`file://${__dirname}/../../webapp/index.html`);
electron.Menu.setApplicationMenu(VectorMenu); electron.Menu.setApplicationMenu(VectorMenu);
@ -230,6 +242,8 @@ electron.app.on('ready', () => {
onLinkContextMenu(ev, params); onLinkContextMenu(ev, params);
} }
}); });
mainWindowState.manage(mainWindow);
}); });
electron.app.on('window-all-closed', () => { electron.app.on('window-all-closed', () => {

View file

@ -1,8 +1,8 @@
{ {
"name": "riot-web", "name": "riot-web",
"productName": "Riot", "productName": "Riot",
"main": "electron/src/electron-main.js", "main": "electron_app/src/electron-main.js",
"version": "0.9.8", "version": "0.9.9",
"description": "A feature-rich client for Matrix.org", "description": "A feature-rich client for Matrix.org",
"author": "Vector Creations Ltd.", "author": "Vector Creations Ltd.",
"repository": { "repository": {
@ -33,13 +33,15 @@
"build:bundle": "cross-env NODE_ENV=production webpack -p --progress", "build:bundle": "cross-env NODE_ENV=production webpack -p --progress",
"build:bundle:dev": "webpack --optimize-occurence-order --progress", "build:bundle:dev": "webpack --optimize-occurence-order --progress",
"build:electron": "npm run clean && npm run build && build -wml --ia32 --x64", "build:electron": "npm run clean && npm run build && build -wml --ia32 --x64",
"build": "node scripts/babelcheck.js && npm run build:res && npm run build:bundle", "build": "npm run build:res && npm run build:bundle",
"build:dev": "node scripts/babelcheck.js && npm run build:res && npm run build:bundle:dev", "build:dev": "npm run build:res && npm run build:bundle:dev",
"dist": "scripts/package.sh", "dist": "scripts/package.sh",
"install:electron": "install-app-deps",
"electron": "npm run install:electron && electron .",
"start:res": "node scripts/copy-res.js -w", "start:res": "node scripts/copy-res.js -w",
"start:js": "webpack-dev-server --output-filename=bundles/_dev_/[name].js --output-chunk-file=bundles/_dev_/[name].js -w --progress", "start:js": "webpack-dev-server --output-filename=bundles/_dev_/[name].js --output-chunk-file=bundles/_dev_/[name].js -w --progress",
"start:js:prod": "cross-env NODE_ENV=production webpack-dev-server -w --progress", "start:js:prod": "cross-env NODE_ENV=production webpack-dev-server -w --progress",
"start": "node scripts/babelcheck.js && parallelshell \"npm run start:res\" \"npm run start:js\"", "start": "parallelshell \"npm run start:res\" \"npm run start:js\"",
"start:prod": "parallelshell \"npm run start:res\" \"npm run start:js:prod\"", "start:prod": "parallelshell \"npm run start:res\" \"npm run start:js:prod\"",
"lint": "eslint src/", "lint": "eslint src/",
"lintall": "eslint src/ test/", "lintall": "eslint src/ test/",
@ -145,10 +147,12 @@
"dereference": true, "dereference": true,
"//files": "We bundle everything, so we only need to include webapp/", "//files": "We bundle everything, so we only need to include webapp/",
"files": [ "files": [
"electron/src/**", "node_modules/**",
"electron/img/**", "src/**",
"webapp/**", "img/**"
"package.json" ],
"extraResources": [
"webapp/**/*"
], ],
"linux": { "linux": {
"target": "deb", "target": "deb",
@ -159,10 +163,11 @@
}, },
"win": { "win": {
"target": "squirrel" "target": "squirrel"
},
"directories": {
"buildResources": "electron_app/build",
"output": "electron_app/dist",
"app": "electron_app"
} }
},
"directories": {
"buildResources": "electron/build",
"output": "electron/dist"
} }
} }

View file

@ -1,12 +1,25 @@
#!/bin/sh #!/bin/bash
# #
# Script to perform a release of vector-web. # Script to perform a release of vector-web.
# #
# Requires github-changelog-generator; to install, do # Requires github-changelog-generator; to install, do
# pip install git+https://github.com/matrix-org/github-changelog-generator.git # pip install git+https://github.com/matrix-org/github-changelog-generator.git
set -e set -e
cd `dirname $0` cd `dirname $0`
# bump Electron's package.json first
release="${1#v}"
tag="v${release}"
echo "electron npm version"
cd electron_app
npm version --no-git-tag-version "$release"
git commit package.json -m "$tag"
cd ..
exec ./node_modules/matrix-js-sdk/release.sh -z "$@" exec ./node_modules/matrix-js-sdk/release.sh -z "$@"

View file

@ -1,26 +0,0 @@
#!/usr/bin/env node
var exec = require('child_process').exec;
// Makes sure the babel executable in the path is babel 6 (or greater), not
// babel 5, which it is if you upgrade from an older version of react-sdk and
// run 'npm install' since the package has changed to babel-cli, so 'babel'
// remains installed and the executable in node_modules/.bin remains as babel
// 5.
// This script is duplicated from matrix-react-sdk because it can't reliably
// be pulled in from react-sdk while npm install is failing, as it will do
// if the environment is in the erroneous state this script checks for.
exec("babel -V", function (error, stdout, stderr) {
if ((error && error.code) || parseInt(stdout.substr(0,1), 10) < 6) {
console.log("\033[31m\033[1m"+
'*****************************************\n'+
'* vector-web has moved to babel 6 *\n'+
'* Please "rm -rf node_modules && npm i" *\n'+
'* then restore links as appropriate *\n'+
'*****************************************\n'+
"\033[91m");
process.exit(1);
}
});

View file

@ -90,8 +90,8 @@ npm run build:electron
popd popd
distdir="$builddir/electron/dist" distdir="$builddir/electron_app/dist"
pubdir="$projdir/electron/pub" pubdir="$projdir/electron_app/pub"
rm -r "$pubdir" || true rm -r "$pubdir" || true
mkdir -p "$pubdir" mkdir -p "$pubdir"
@ -120,11 +120,11 @@ cp $distdir/win/*.nupkg "$pubdir/update/win32/x64/"
cp $distdir/win/RELEASES "$pubdir/update/win32/x64/" cp $distdir/win/RELEASES "$pubdir/update/win32/x64/"
# Move the debs to the main project dir's dist folder # Move the debs to the main project dir's dist folder
rm -r "$projdir/electron/dist" || true rm -r "$projdir/electron_app/dist" || true
mkdir -p "$projdir/electron/dist" mkdir -p "$projdir/electron_app/dist"
cp $distdir/*.deb "$projdir/electron/dist/" cp $distdir/*.deb "$projdir/electron_app/dist/"
rm -rf "$builddir" rm -rf "$builddir"
echo "Riot Desktop is ready to go in $pubdir: this directory can be hosted on your web server." echo "Riot Desktop is ready to go in $pubdir: this directory can be hosted on your web server."
echo "deb archives are in electron/dist/ - these should be added into your debian repository" echo "deb archives are in electron_app/dist/ - these should be added into your debian repository"

40
scripts/issues-burndown.pl Normal file → Executable file
View file

@ -4,16 +4,24 @@ use warnings;
use strict; use strict;
use Net::GitHub; use Net::GitHub;
use DateTime; use Time::Moment;
use DateTime::Format::ISO8601; use Term::ReadPassword;
# This version of the script emits the cumulative number of bugs, split into open & closed
# suitable for drawing the 'top' and 'bottom' of a burndown graph.
#
# N.B. this doesn't take into account issues changing priority over time, but only their most recent priority.
#
# If you want instead the number of open issues on a given day, then look at issues-no-state.pl
my $gh = Net::GitHub->new( my $gh = Net::GitHub->new(
login => 'ara4n', pass => 'secret' login => 'ara4n', pass => read_password("github password: "),
); );
$gh->set_default_user_repo('vector-im', 'vector-web'); $gh->set_default_user_repo('vector-im', 'vector-web');
my @issues = $gh->issue->repos_issues({ state => 'all', milestone => 3 }); #my @issues = $gh->issue->repos_issues({ state => 'all', milestone => 3 });
my @issues = $gh->issue->repos_issues({ state => 'all' });
while ($gh->issue->has_next_page) { while ($gh->issue->has_next_page) {
push @issues, $gh->issue->next_page; push @issues, $gh->issue->next_page;
} }
@ -30,11 +38,11 @@ while ($gh->issue->has_next_page) {
my $days = {}; my $days = {};
my $schema = {}; my $schema = {};
my $now = DateTime->now(); my $now = Time::Moment->now;
foreach my $issue (@issues) { foreach my $issue (@issues) {
next if ($issue->{pull_request}); next if ($issue->{pull_request});
# use Data::Dumper; # use Data::Dumper;
# print STDERR Dumper($issue); # print STDERR Dumper($issue);
@ -56,10 +64,10 @@ foreach my $issue (@issues) {
my $priority = &$extract_labels(qw(p1 p2 p3 p4 p5)) || "unprioritised"; my $priority = &$extract_labels(qw(p1 p2 p3 p4 p5)) || "unprioritised";
my $severity = &$extract_labels(qw(minor major critical cosmetic network)) || "no-severity"; my $severity = &$extract_labels(qw(minor major critical cosmetic network)) || "no-severity";
my $start = DateTime::Format::ISO8601->parse_datetime($issue->{created_at}); my $start = Time::Moment->from_string($issue->{created_at});
do { do {
my $ymd = $start->ymd(); my $ymd = $start->strftime('%F');
$days->{ $ymd }->{ 'created' }->{ $type }->{ $priority }->{ $severity }->{ total }++; $days->{ $ymd }->{ 'created' }->{ $type }->{ $priority }->{ $severity }->{ total }++;
$schema->{ 'created' }->{ $type }->{ $priority }->{ $severity }->{ total }++; $schema->{ 'created' }->{ $type }->{ $priority }->{ $severity }->{ total }++;
@ -68,13 +76,14 @@ foreach my $issue (@issues) {
$schema->{ 'created' }->{ $type }->{ $priority }->{ $severity }->{ $_ }++; $schema->{ 'created' }->{ $type }->{ $priority }->{ $severity }->{ $_ }++;
} }
$start = $start->add(days => 1); $start = $start->plus_days(1);
} while (DateTime->compare($start, $now) < 0); # print STDERR "^";
} while ($start->compare($now) < 0);
if ($state eq 'closed') { if ($state eq 'closed') {
my $end = DateTime::Format::ISO8601->parse_datetime($issue->{closed_at}); my $end = Time::Moment->from_string($issue->{closed_at});
do { do {
my $ymd = $end->ymd(); my $ymd = $end->strftime('%F');
$days->{ $ymd }->{ 'resolved' }->{ $type }->{ $priority }->{ $severity }->{ total }++; $days->{ $ymd }->{ 'resolved' }->{ $type }->{ $priority }->{ $severity }->{ total }++;
$schema->{ 'resolved' }->{ $type }->{ $priority }->{ $severity }->{ total }++; $schema->{ 'resolved' }->{ $type }->{ $priority }->{ $severity }->{ total }++;
@ -83,9 +92,12 @@ foreach my $issue (@issues) {
$schema->{ 'resolved' }->{ $type }->{ $priority }->{ $severity }->{ $_ }++; $schema->{ 'resolved' }->{ $type }->{ $priority }->{ $severity }->{ $_ }++;
} }
$end = $end->add(days => 1); $end = $end->plus_days(1);
} while (DateTime->compare($end, $now) < 0); } while ($end->compare($now) < 0);
# print STDERR "v";
} }
# print STDERR "\n";
} }
print "day,"; print "day,";

View file

@ -6,14 +6,22 @@ use strict;
use Net::GitHub; use Net::GitHub;
use DateTime; use DateTime;
use DateTime::Format::ISO8601; use DateTime::Format::ISO8601;
use Term::ReadPassword;
# This version of the script emits the total number of bugs open on a given day,
# split by various tags.
#
# If you want instead the cumulative number of open & closed issues on a given day,
# then look at issues-burndown.pl
my $gh = Net::GitHub->new( my $gh = Net::GitHub->new(
login => 'ara4n', pass => 'secret' login => 'ara4n', pass => read_password("github password: "),
); );
$gh->set_default_user_repo('vector-im', 'vector-web'); $gh->set_default_user_repo('vector-im', 'vector-web');
my @issues = $gh->issue->repos_issues({ state => 'all', milestone => 3 }); #my @issues = $gh->issue->repos_issues({ state => 'all', milestone => 3 });
my @issues = $gh->issue->repos_issues({ state => 'all' });
while ($gh->issue->has_next_page) { while ($gh->issue->has_next_page) {
push @issues, $gh->issue->next_page; push @issues, $gh->issue->next_page;
} }

View file

@ -52,7 +52,7 @@ cp "$tmpdir/256.png" "$tmpdir/Riot.iconset/icon_256x256.png"
cp "$tmpdir/512.png" "$tmpdir/Riot.iconset/icon_256x256@2x.png" cp "$tmpdir/512.png" "$tmpdir/Riot.iconset/icon_256x256@2x.png"
cp "$tmpdir/512.png" "$tmpdir/Riot.iconset/icon_512x512.png" cp "$tmpdir/512.png" "$tmpdir/Riot.iconset/icon_512x512.png"
cp "$tmpdir/1024.png" "$tmpdir/Riot.iconset/icon_512x512@2x.png" cp "$tmpdir/1024.png" "$tmpdir/Riot.iconset/icon_512x512@2x.png"
iconutil -c icns -o electron/build/icon.icns "$tmpdir/Riot.iconset" iconutil -c icns -o electron_app/build/icon.icns "$tmpdir/Riot.iconset"
cp "$tmpdir/36.png" "res/vector-icons/android-chrome-36x36.png" cp "$tmpdir/36.png" "res/vector-icons/android-chrome-36x36.png"
cp "$tmpdir/48.png" "res/vector-icons/android-chrome-48x48.png" cp "$tmpdir/48.png" "res/vector-icons/android-chrome-48x48.png"
@ -79,15 +79,17 @@ cp "$tmpdir/144.png" "res/vector-icons/mstile-144x144.png"
cp "$tmpdir/150.png" "res/vector-icons/mstile-150x150.png" cp "$tmpdir/150.png" "res/vector-icons/mstile-150x150.png"
cp "$tmpdir/310.png" "res/vector-icons/mstile-310x310.png" cp "$tmpdir/310.png" "res/vector-icons/mstile-310x310.png"
cp "$tmpdir/310x150.png" "res/vector-icons/mstile-310x150.png" cp "$tmpdir/310x150.png" "res/vector-icons/mstile-310x150.png"
cp "$tmpdir/180.png" "electron_app/img/riot.png"
convert "$tmpdir/16.png" "$tmpdir/32.png" "$tmpdir/64.png" "$tmpdir/128.png" "$tmpdir/256.png" "res/vector-icons/favicon.ico" convert "$tmpdir/16.png" "$tmpdir/32.png" "$tmpdir/64.png" "$tmpdir/128.png" "$tmpdir/256.png" "res/vector-icons/favicon.ico"
cp "res/vector-icons/favicon.ico" "electron/build/icon.ico" cp "res/vector-icons/favicon.ico" "electron_app/build/icon.ico"
cp "res/vector-icons/favicon.ico" "electron_app/img/riot.ico"
# https://github.com/electron-userland/electron-builder/blob/3f97b86993d4ea5172e562b182230a194de0f621/src/targets/LinuxTargetHelper.ts#L127 # https://github.com/electron-userland/electron-builder/blob/3f97b86993d4ea5172e562b182230a194de0f621/src/targets/LinuxTargetHelper.ts#L127
for i in 24 96 16 48 64 128 256 512 for i in 24 96 16 48 64 128 256 512
do do
cp "$tmpdir/$i.png" "electron/build/icons/${i}x${i}.png" cp "$tmpdir/$i.png" "electron_app/build/icons/${i}x${i}.png"
done done
rm -r "$tmpdir" rm -r "$tmpdir"

View file

@ -1,4 +1,4 @@
#!/bin/sh #!/bin/bash
set -e set -e
@ -22,7 +22,14 @@ cp config.sample.json webapp/
mkdir -p dist mkdir -p dist
cp -r webapp vector-$version cp -r webapp vector-$version
echo $version > vector-$version/version
# if $version looks like semver with leading v, strip it before writing to file
if [[ ${version} =~ ^v[[:digit:]]+\.[[:digit:]]+\.[[:digit:]]+(-.+)?$ ]]; then
echo ${version:1} > vector-$version/version
else
echo ${version} > vector-$version/version
fi
tar chvzf dist/vector-$version.tar.gz vector-$version tar chvzf dist/vector-$version.tar.gz vector-$version
rm -r vector-$version rm -r vector-$version

View file

@ -1,5 +1,6 @@
/* /*
Copyright 2015, 2016 OpenMarket Ltd Copyright 2015, 2016 OpenMarket Ltd
Copyright 2017 Vector Creations Ltd
Licensed under the Apache License, Version 2.0 (the "License"); Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with 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. limitations under the License.
*/ */
'use strict'; import React from 'react';
import sdk from 'matrix-react-sdk';
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');
module.exports = React.createClass({ module.exports = React.createClass({
displayName: 'BottomLeftMenu', displayName: 'BottomLeftMenu',
@ -30,121 +26,28 @@ module.exports = React.createClass({
teamToken: React.PropTypes.string, 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() { 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; var homeButton;
if (this.props.teamToken) { if (this.props.teamToken) {
homeButton = ( homeButton = <HomeButton tooltip={true} />;
<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>
);
} }
return ( return (
<div className="mx_BottomLeftMenu"> <div className="mx_BottomLeftMenu">
<div className="mx_BottomLeftMenu_options"> <div className="mx_BottomLeftMenu_options">
{ homeButton } { homeButton }
<AccessibleButton className="mx_BottomLeftMenu_people" onClick={ this.onPeopleClick } onMouseEnter={ this.onPeopleMouseEnter } onMouseLeave={ this.onPeopleMouseLeave } > <StartChatButton tooltip={true} />
<TintableSvg src="img/icons-people.svg" width="25" height="25" /> <RoomDirectoryButton tooltip={true} />
{ this.getLabel("Start chat", this.state.peopleHover) } <CreateRoomButton tooltip={true} />
</AccessibleButton> <span className="mx_BottomLeftMenu_settings">
<AccessibleButton className="mx_BottomLeftMenu_directory" onClick={ this.onDirectoryClick } onMouseEnter={ this.onDirectoryMouseEnter } onMouseLeave={ this.onDirectoryMouseLeave } > <SettingsButton tooltip={true} />
<TintableSvg src="img/icons-directory.svg" width="25" height="25"/> </span>
{ 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>
</div> </div>
</div> </div>
); );

View file

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

View file

@ -1,4 +1,5 @@
/* /*
Copyright 2017 Vector Creations Ltd
Copyright 2015, 2016 OpenMarket Ltd Copyright 2015, 2016 OpenMarket Ltd
Licensed under the Apache License, Version 2.0 (the "License"); 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 AccessibleButton = require('matrix-react-sdk/lib/components/views/elements/AccessibleButton');
var ConstantTimeDispatcher = require('matrix-react-sdk/lib/ConstantTimeDispatcher'); var ConstantTimeDispatcher = require('matrix-react-sdk/lib/ConstantTimeDispatcher');
var RoomSubListHeader = require('./RoomSubListHeader.js'); var RoomSubListHeader = require('./RoomSubListHeader.js');
import Modal from 'matrix-react-sdk/lib/Modal';
// turn this on for drag & drop console debugging galore // turn this on for drag & drop console debugging galore
var debug = false; var debug = false;
@ -82,6 +84,8 @@ var RoomSubList = React.createClass({
incomingCall: React.PropTypes.object, incomingCall: React.PropTypes.object,
onShowMoreRooms: React.PropTypes.func, onShowMoreRooms: React.PropTypes.func,
searchFilter: React.PropTypes.string, 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() { getInitialState: function() {
@ -468,16 +472,15 @@ var RoomSubList = React.createClass({
render: function() { render: function() {
var connectDropTarget = this.props.connectDropTarget; var connectDropTarget = this.props.connectDropTarget;
var RoomDropTarget = sdk.getComponent('rooms.RoomDropTarget');
var TruncatedList = sdk.getComponent('elements.TruncatedList'); var TruncatedList = sdk.getComponent('elements.TruncatedList');
var label = this.props.collapsed ? null : this.props.label; var label = this.props.collapsed ? null : this.props.label;
//console.log("render: " + JSON.stringify(this.state.sortedList)); let content;
if (this.state.sortedList.length == 0) {
var target; content = this.props.emptyContent;
if (this.state.sortedList.length == 0 && this.props.editable) { } else {
target = <RoomDropTarget label={ 'Drop here to ' + this.props.verb }/>; content = this.makeRoomTiles();
} }
var roomCount = this.props.list.length > 0 ? this.props.list.length : ''; var roomCount = this.props.list.length > 0 ? this.props.list.length : '';
@ -497,8 +500,7 @@ var RoomSubList = React.createClass({
if (!this.state.hidden) { if (!this.state.hidden) {
subList = <TruncatedList className={ classes } truncateAt={this.state.truncateAt} subList = <TruncatedList className={ classes } truncateAt={this.state.truncateAt}
createOverflowElement={this._createOverflowTile} > createOverflowElement={this._createOverflowTile} >
{ target } { content }
{ this.makeRoomTiles() }
</TruncatedList>; </TruncatedList>;
} }
else { else {
@ -520,6 +522,7 @@ var RoomSubList = React.createClass({
roomNotificationCount={ this.roomNotificationCount() } roomNotificationCount={ this.roomNotificationCount() }
onClick={ this.onClick } onClick={ this.onClick }
onHeaderClick={ this.props.onHeaderClick } onHeaderClick={ this.props.onHeaderClick }
headerItems={this.props.headerItems}
/> />
{ subList } { subList }
</div> </div>
@ -541,6 +544,7 @@ var RoomSubList = React.createClass({
roomNotificationCount={ this.roomNotificationCount() } roomNotificationCount={ this.roomNotificationCount() }
onClick={ this.onClick } onClick={ this.onClick }
onHeaderClick={ this.props.onHeaderClick } onHeaderClick={ this.props.onHeaderClick }
headerItems={this.props.headerItems}
/> />
: undefined } : undefined }
{ (this.props.showSpinner && !this.state.hidden) ? <Loader /> : 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. limitations under the License.
*/ */
'use strict'; import React from 'react';
import classNames from 'classnames';
var React = require('react'); import sdk from 'matrix-react-sdk';
var ReactDOM = require('react-dom'); import { formatCount } from 'matrix-react-sdk/lib/utils/FormattingUtils';
var classNames = require('classnames'); import AccessibleButton from 'matrix-react-sdk/lib/components/views/elements/AccessibleButton';
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');
module.exports = React.createClass({ module.exports = React.createClass({
displayName: 'RoomSubListHeader', displayName: 'RoomSubListHeader',
@ -42,6 +37,7 @@ module.exports = React.createClass({
hidden: React.PropTypes.bool, hidden: React.PropTypes.bool,
onClick: React.PropTypes.func, onClick: React.PropTypes.func,
onHeaderClick: React.PropTypes.func, onHeaderClick: React.PropTypes.func,
headerItems: React.PropTypes.node, // content shown in the sublist header
}, },
getDefaultProps: function() { getDefaultProps: function() {
@ -63,35 +59,34 @@ module.exports = React.createClass({
// }, // },
render: function() { render: function() {
var TintableSvg = sdk.getComponent("elements.TintableSvg"); const TintableSvg = sdk.getComponent("elements.TintableSvg");
var subListNotifications = this.props.roomNotificationCount; const subListNotifications = this.props.roomNotificationCount;
var subListNotifCount = subListNotifications[0]; const subListNotifCount = subListNotifications[0];
var subListNotifHighlight = subListNotifications[1]; const subListNotifHighlight = subListNotifications[1];
var chevronClasses = classNames({ const chevronClasses = classNames({
'mx_RoomSubList_chevron': true, 'mx_RoomSubList_chevron': true,
'mx_RoomSubList_chevronRight': this.props.hidden, 'mx_RoomSubList_chevronRight': this.props.hidden,
'mx_RoomSubList_chevronDown': !this.props.hidden, 'mx_RoomSubList_chevronDown': !this.props.hidden,
}); });
var badgeClasses = classNames({ const badgeClasses = classNames({
'mx_RoomSubList_badge': true, 'mx_RoomSubList_badge': true,
'mx_RoomSubList_badgeHighlight': subListNotifHighlight, 'mx_RoomSubList_badgeHighlight': subListNotifHighlight,
}); });
var badge; let badge;
if (subListNotifCount > 0) { if (subListNotifCount > 0) {
badge = <div className={badgeClasses}>{ FormattingUtils.formatCount(subListNotifCount) }</div>; badge = <div className={badgeClasses}>{ formatCount(subListNotifCount) }</div>;
} } else if (subListNotifHighlight) {
else if (subListNotifHighlight) {
badge = <div className={badgeClasses}>!</div>; badge = <div className={badgeClasses}>!</div>;
} }
// When collapsed, allow a long hover on the header to show user // When collapsed, allow a long hover on the header to show user
// the full tag name and room count // the full tag name and room count
var title; let title;
var roomCount = this.props.roomCount; const roomCount = this.props.roomCount;
if (this.props.collapsed) { if (this.props.collapsed) {
title = this.props.label; title = this.props.label;
if (roomCount !== '') { if (roomCount !== '') {
@ -99,9 +94,9 @@ module.exports = React.createClass({
} }
} }
var incomingCall; let incomingCall;
if (this.props.isIncomingCallRoom) { 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 }/>; 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"> <div className="mx_RoomSubList_labelContainer" title={ title } ref="header">
<AccessibleButton onClick={ this.props.onClick } className="mx_RoomSubList_label" tabIndex="0"> <AccessibleButton onClick={ this.props.onClick } className="mx_RoomSubList_label" tabIndex="0">
{ this.props.collapsed ? '' : this.props.label } { this.props.collapsed ? '' : this.props.label }
{this.props.headerItems}
<div className="mx_RoomSubList_roomCount">{ roomCount }</div> <div className="mx_RoomSubList_roomCount">{ roomCount }</div>
<div className={chevronClasses}></div> <div className={chevronClasses}></div>
{ badge } { badge }

View file

@ -27,6 +27,7 @@
@import "./matrix-react-sdk/views/elements/_MemberEventListSummary.scss"; @import "./matrix-react-sdk/views/elements/_MemberEventListSummary.scss";
@import "./matrix-react-sdk/views/elements/_ProgressBar.scss"; @import "./matrix-react-sdk/views/elements/_ProgressBar.scss";
@import "./matrix-react-sdk/views/elements/_RichText.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/_InteractiveAuthEntryComponents.scss";
@import "./matrix-react-sdk/views/login/_ServerConfig.scss"; @import "./matrix-react-sdk/views/login/_ServerConfig.scss";
@import "./matrix-react-sdk/views/messages/_MEmoteBody.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; border-bottom: solid 1px $accent-color;
margin-top: 0px; margin-top: 0px;
position: relative; position: relative;
top: 5px; top: -1px;
z-index: 1;
} }
.mx_RoomView_statusArea { .mx_RoomView_statusArea {

View file

@ -20,6 +20,7 @@ limitations under the License.
.mx_TextualEvent.mx_MemberEventListSummary_summary { .mx_TextualEvent.mx_MemberEventListSummary_summary {
font-size: 14px; font-size: 14px;
display: inline-flex;
} }
.mx_MemberEventListSummary_avatars { .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 2015, 2016 OpenMarket Ltd
Copyright 2107 Vector Creations Ltd
Licensed under the Apache License, Version 2.0 (the "License"); Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with 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 { .mx_RoomList_scrollbar .gm-scrollbar.-vertical {
z-index: 6; 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; pointer-events: none;
} }
.mx_LeftPanel .mx_BottomLeftMenu_homePage, .collapsed .mx_RoleButton {
.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 {
margin-right: 0px ! important; margin-right: 0px ! important;
padding-top: 3px ! important; padding-top: 3px ! important;
padding-bottom: 3px ! important; padding-bottom: 3px ! important;
} }
.mx_LeftPanel .mx_BottomLeftMenu_homePage, .mx_BottomLeftMenu_options .mx_RoleButton {
.mx_LeftPanel .mx_BottomLeftMenu_directory, margin-left: 0px;
.mx_LeftPanel .mx_BottomLeftMenu_createRoom,
.mx_LeftPanel .mx_BottomLeftMenu_people {
margin-right: 10px; margin-right: 10px;
} }
.mx_LeftPanel .mx_BottomLeftMenu_settings { .mx_BottomLeftMenu_options .mx_BottomLeftMenu_settings {
float: right; float: right;
} }
.mx_BottomLeftMenu_options .mx_BottomLeftMenu_settings .mx_RoleButton {
margin-right: 0px;
}
.mx_LeftPanel.collapsed .mx_BottomLeftMenu_settings { .mx_LeftPanel.collapsed .mx_BottomLeftMenu_settings {
float: none; 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 VectorBasePlatform from './VectorBasePlatform';
import dis from 'matrix-react-sdk/lib/dispatcher'; import dis from 'matrix-react-sdk/lib/dispatcher';
import q from 'q'; import q from 'q';
import electron, {remote} from 'electron';
const electron = require('electron');
const remote = electron.remote;
remote.autoUpdater.on('update-downloaded', onUpdateDownloaded); 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({ dis.dispatch({
action: 'new_version', action: 'new_version',
currentVersion: remote.app.getVersion(), currentVersion: remote.app.getVersion(),
@ -35,7 +33,7 @@ function onUpdateDownloaded(ev, releaseNotes, ver, date, updateURL) {
}); });
} }
function platformFriendlyName() { function platformFriendlyName(): string {
console.log(window.process); console.log(window.process);
switch (window.process.platform) { switch (window.process.platform) {
case 'darwin': case 'darwin':
@ -72,11 +70,11 @@ export default class ElectronPlatform extends VectorBasePlatform {
} }
} }
supportsNotifications() : boolean { supportsNotifications(): boolean {
return true; return true;
} }
maySendNotifications() : boolean { maySendNotifications(): boolean {
return true; return true;
} }
@ -100,7 +98,7 @@ export default class ElectronPlatform extends VectorBasePlatform {
icon: avatarUrl, icon: avatarUrl,
tag: 'vector', tag: 'vector',
silent: true, // we play our own sounds silent: true, // we play our own sounds
} },
); );
notification.onclick = function() { notification.onclick = function() {
@ -123,7 +121,7 @@ export default class ElectronPlatform extends VectorBasePlatform {
notif.close(); notif.close();
} }
getAppVersion() { getAppVersion(): Promise<string> {
return q(remote.app.getVersion()); return q(remote.app.getVersion());
} }
@ -140,15 +138,15 @@ export default class ElectronPlatform extends VectorBasePlatform {
electron.ipcRenderer.send('install_update'); electron.ipcRenderer.send('install_update');
} }
getDefaultDeviceDisplayName() { getDefaultDeviceDisplayName(): string {
return 'Riot Desktop on ' + platformFriendlyName(); return 'Riot Desktop on ' + platformFriendlyName();
} }
screenCaptureErrorString() { screenCaptureErrorString(): ?string {
return null; return null;
} }
requestNotificationPermission() : Promise { requestNotificationPermission(): Promise<string> {
return q('granted'); return q('granted');
} }

View file

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

View file

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