diff --git a/.gitignore b/.gitignore index c5826b78..cba50a69 100644 --- a/.gitignore +++ b/.gitignore @@ -5,6 +5,7 @@ /key.pem /lib /node_modules +/electron/node_modules /packages/ /webapp /.npmrc diff --git a/CHANGELOG.md b/CHANGELOG.md index a2ed3149..ea63ee66 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -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) ========================================================================================== [Full Changelog](https://github.com/vector-im/riot-web/compare/v0.9.8-rc.3...v0.9.8) diff --git a/README.md b/README.md index 2d7ab81b..55463a37 100644 --- a/README.md +++ b/README.md @@ -135,7 +135,7 @@ To run as a desktop app: ``` npm install electron - node_modules/.bin/electron . + npm run electron ``` To build packages, use electron-builder. This is configured to output: diff --git a/config.sample.json b/config.sample.json index a65646ac..3c513f7a 100644 --- a/config.sample.json +++ b/config.sample.json @@ -4,7 +4,7 @@ "brand": "Riot", "integrations_ui_url": "https://scalar.vector.im/", "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, "roomDirectory": { "servers": [ diff --git a/electron/img/riot.ico b/electron/img/riot.ico deleted file mode 100644 index 8b681ffb..00000000 Binary files a/electron/img/riot.ico and /dev/null differ diff --git a/electron/img/riot.png b/electron/img/riot.png deleted file mode 100644 index fe13aa99..00000000 Binary files a/electron/img/riot.png and /dev/null differ diff --git a/electron/build/icon.icns b/electron_app/build/icon.icns similarity index 100% rename from electron/build/icon.icns rename to electron_app/build/icon.icns diff --git a/electron/build/icon.ico b/electron_app/build/icon.ico similarity index 100% rename from electron/build/icon.ico rename to electron_app/build/icon.ico diff --git a/electron/build/icons/128x128.png b/electron_app/build/icons/128x128.png similarity index 100% rename from electron/build/icons/128x128.png rename to electron_app/build/icons/128x128.png diff --git a/electron/build/icons/16x16.png b/electron_app/build/icons/16x16.png similarity index 100% rename from electron/build/icons/16x16.png rename to electron_app/build/icons/16x16.png diff --git a/electron/build/icons/24x24.png b/electron_app/build/icons/24x24.png similarity index 100% rename from electron/build/icons/24x24.png rename to electron_app/build/icons/24x24.png diff --git a/electron/build/icons/256x256.png b/electron_app/build/icons/256x256.png similarity index 100% rename from electron/build/icons/256x256.png rename to electron_app/build/icons/256x256.png diff --git a/electron/build/icons/48x48.png b/electron_app/build/icons/48x48.png similarity index 100% rename from electron/build/icons/48x48.png rename to electron_app/build/icons/48x48.png diff --git a/electron/build/icons/512x512.png b/electron_app/build/icons/512x512.png similarity index 100% rename from electron/build/icons/512x512.png rename to electron_app/build/icons/512x512.png diff --git a/electron/build/icons/64x64.png b/electron_app/build/icons/64x64.png similarity index 100% rename from electron/build/icons/64x64.png rename to electron_app/build/icons/64x64.png diff --git a/electron/build/icons/96x96.png b/electron_app/build/icons/96x96.png similarity index 100% rename from electron/build/icons/96x96.png rename to electron_app/build/icons/96x96.png diff --git a/electron/build/install-spinner.gif b/electron_app/build/install-spinner.gif similarity index 100% rename from electron/build/install-spinner.gif rename to electron_app/build/install-spinner.gif diff --git a/electron_app/img/riot.ico b/electron_app/img/riot.ico new file mode 100644 index 00000000..8f8ff94e Binary files /dev/null and b/electron_app/img/riot.ico differ diff --git a/electron_app/img/riot.png b/electron_app/img/riot.png new file mode 100644 index 00000000..85e9f8ca Binary files /dev/null and b/electron_app/img/riot.png differ diff --git a/electron_app/package.json b/electron_app/package.json new file mode 100644 index 00000000..99651cc1 --- /dev/null +++ b/electron_app/package.json @@ -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" + } +} diff --git a/electron/riot.im/README b/electron_app/riot.im/README similarity index 100% rename from electron/riot.im/README rename to electron_app/riot.im/README diff --git a/electron/riot.im/config.json b/electron_app/riot.im/config.json similarity index 100% rename from electron/riot.im/config.json rename to electron_app/riot.im/config.json diff --git a/electron/src/electron-main.js b/electron_app/src/electron-main.js similarity index 95% rename from electron/src/electron-main.js rename to electron_app/src/electron-main.js index a1fc9c1a..32e305d8 100644 --- a/electron/src/electron-main.js +++ b/electron_app/src/electron-main.js @@ -30,6 +30,8 @@ const tray = require('./tray'); const VectorMenu = require('./vectormenu'); +const windowStateKeeper = require('electron-window-state'); + let vectorConfig = {}; try { vectorConfig = require('../../webapp/config.json'); @@ -187,11 +189,21 @@ electron.app.on('ready', () => { 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({ icon: icon_path, - width: 1024, height: 768, show: false, autoHideMenuBar: true, + + x: mainWindowState.x, + y: mainWindowState.y, + width: mainWindowState.width, + height: mainWindowState.height, }); mainWindow.loadURL(`file://${__dirname}/../../webapp/index.html`); electron.Menu.setApplicationMenu(VectorMenu); @@ -230,6 +242,8 @@ electron.app.on('ready', () => { onLinkContextMenu(ev, params); } }); + + mainWindowState.manage(mainWindow); }); electron.app.on('window-all-closed', () => { diff --git a/electron/src/squirrelhooks.js b/electron_app/src/squirrelhooks.js similarity index 100% rename from electron/src/squirrelhooks.js rename to electron_app/src/squirrelhooks.js diff --git a/electron/src/tray.js b/electron_app/src/tray.js similarity index 100% rename from electron/src/tray.js rename to electron_app/src/tray.js diff --git a/electron/src/vectormenu.js b/electron_app/src/vectormenu.js similarity index 100% rename from electron/src/vectormenu.js rename to electron_app/src/vectormenu.js diff --git a/package.json b/package.json index a25e1795..884811af 100644 --- a/package.json +++ b/package.json @@ -1,8 +1,8 @@ { "name": "riot-web", "productName": "Riot", - "main": "electron/src/electron-main.js", - "version": "0.9.8", + "main": "electron_app/src/electron-main.js", + "version": "0.9.9", "description": "A feature-rich client for Matrix.org", "author": "Vector Creations Ltd.", "repository": { @@ -33,13 +33,15 @@ "build:bundle": "cross-env NODE_ENV=production webpack -p --progress", "build:bundle:dev": "webpack --optimize-occurence-order --progress", "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:dev": "node scripts/babelcheck.js && npm run build:res && npm run build:bundle:dev", + "build": "npm run build:res && npm run build:bundle", + "build:dev": "npm run build:res && npm run build:bundle:dev", "dist": "scripts/package.sh", + "install:electron": "install-app-deps", + "electron": "npm run install:electron && electron .", "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: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\"", "lint": "eslint src/", "lintall": "eslint src/ test/", @@ -145,10 +147,12 @@ "dereference": true, "//files": "We bundle everything, so we only need to include webapp/", "files": [ - "electron/src/**", - "electron/img/**", - "webapp/**", - "package.json" + "node_modules/**", + "src/**", + "img/**" + ], + "extraResources": [ + "webapp/**/*" ], "linux": { "target": "deb", @@ -159,10 +163,11 @@ }, "win": { "target": "squirrel" + }, + "directories": { + "buildResources": "electron_app/build", + "output": "electron_app/dist", + "app": "electron_app" } - }, - "directories": { - "buildResources": "electron/build", - "output": "electron/dist" } } diff --git a/release.sh b/release.sh index e8c68b90..c2454560 100755 --- a/release.sh +++ b/release.sh @@ -1,12 +1,25 @@ -#!/bin/sh +#!/bin/bash # # 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 set -e 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 "$@" diff --git a/scripts/babelcheck.js b/scripts/babelcheck.js deleted file mode 100644 index 89f5cac5..00000000 --- a/scripts/babelcheck.js +++ /dev/null @@ -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); - } -}); diff --git a/scripts/electron-package.sh b/scripts/electron-package.sh index 87e353f7..a5718df8 100755 --- a/scripts/electron-package.sh +++ b/scripts/electron-package.sh @@ -90,8 +90,8 @@ npm run build:electron popd -distdir="$builddir/electron/dist" -pubdir="$projdir/electron/pub" +distdir="$builddir/electron_app/dist" +pubdir="$projdir/electron_app/pub" rm -r "$pubdir" || true mkdir -p "$pubdir" @@ -120,11 +120,11 @@ cp $distdir/win/*.nupkg "$pubdir/update/win32/x64/" cp $distdir/win/RELEASES "$pubdir/update/win32/x64/" # Move the debs to the main project dir's dist folder -rm -r "$projdir/electron/dist" || true -mkdir -p "$projdir/electron/dist" -cp $distdir/*.deb "$projdir/electron/dist/" +rm -r "$projdir/electron_app/dist" || true +mkdir -p "$projdir/electron_app/dist" +cp $distdir/*.deb "$projdir/electron_app/dist/" rm -rf "$builddir" 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" diff --git a/scripts/issues-burndown.pl b/scripts/issues-burndown.pl old mode 100644 new mode 100755 index 7d0f3409..67c05673 --- a/scripts/issues-burndown.pl +++ b/scripts/issues-burndown.pl @@ -4,16 +4,24 @@ use warnings; use strict; use Net::GitHub; -use DateTime; -use DateTime::Format::ISO8601; +use Time::Moment; +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( - login => 'ara4n', pass => 'secret' + login => 'ara4n', pass => read_password("github password: "), ); $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) { push @issues, $gh->issue->next_page; } @@ -30,11 +38,11 @@ while ($gh->issue->has_next_page) { my $days = {}; my $schema = {}; -my $now = DateTime->now(); +my $now = Time::Moment->now; foreach my $issue (@issues) { next if ($issue->{pull_request}); - + # use Data::Dumper; # print STDERR Dumper($issue); @@ -56,10 +64,10 @@ foreach my $issue (@issues) { my $priority = &$extract_labels(qw(p1 p2 p3 p4 p5)) || "unprioritised"; 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 { - my $ymd = $start->ymd(); + my $ymd = $start->strftime('%F'); $days->{ $ymd }->{ 'created' }->{ $type }->{ $priority }->{ $severity }->{ total }++; $schema->{ 'created' }->{ $type }->{ $priority }->{ $severity }->{ total }++; @@ -68,13 +76,14 @@ foreach my $issue (@issues) { $schema->{ 'created' }->{ $type }->{ $priority }->{ $severity }->{ $_ }++; } - $start = $start->add(days => 1); - } while (DateTime->compare($start, $now) < 0); + $start = $start->plus_days(1); + # print STDERR "^"; + } while ($start->compare($now) < 0); if ($state eq 'closed') { - my $end = DateTime::Format::ISO8601->parse_datetime($issue->{closed_at}); + my $end = Time::Moment->from_string($issue->{closed_at}); do { - my $ymd = $end->ymd(); + my $ymd = $end->strftime('%F'); $days->{ $ymd }->{ 'resolved' }->{ $type }->{ $priority }->{ $severity }->{ total }++; $schema->{ 'resolved' }->{ $type }->{ $priority }->{ $severity }->{ total }++; @@ -83,9 +92,12 @@ foreach my $issue (@issues) { $schema->{ 'resolved' }->{ $type }->{ $priority }->{ $severity }->{ $_ }++; } - $end = $end->add(days => 1); - } while (DateTime->compare($end, $now) < 0); + $end = $end->plus_days(1); + } while ($end->compare($now) < 0); + # print STDERR "v"; } + + # print STDERR "\n"; } print "day,"; diff --git a/scripts/issues-no-state.pl b/scripts/issues-no-state.pl index da12fb22..9b07ed27 100755 --- a/scripts/issues-no-state.pl +++ b/scripts/issues-no-state.pl @@ -6,14 +6,22 @@ use strict; use Net::GitHub; use DateTime; 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( - login => 'ara4n', pass => 'secret' + login => 'ara4n', pass => read_password("github password: "), ); $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) { push @issues, $gh->issue->next_page; } diff --git a/scripts/make-icons.sh b/scripts/make-icons.sh index c77064ab..19e48895 100755 --- a/scripts/make-icons.sh +++ b/scripts/make-icons.sh @@ -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_512x512.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/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/310.png" "res/vector-icons/mstile-310x310.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" -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 for i in 24 96 16 48 64 128 256 512 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 rm -r "$tmpdir" diff --git a/scripts/package.sh b/scripts/package.sh index 5c1fdd5e..b3bc00bf 100755 --- a/scripts/package.sh +++ b/scripts/package.sh @@ -1,4 +1,4 @@ -#!/bin/sh +#!/bin/bash set -e @@ -22,7 +22,14 @@ cp config.sample.json webapp/ mkdir -p dist 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 rm -r vector-$version diff --git a/src/components/structures/BottomLeftMenu.js b/src/components/structures/BottomLeftMenu.js index f378cac6..63dfac60 100644 --- a/src/components/structures/BottomLeftMenu.js +++ b/src/components/structures/BottomLeftMenu.js @@ -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 ; - } - }, - 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 = ( - - - { this.getLabel("Welcome page", this.state.homeHover) } - - ); + homeButton = ; } return (
{ homeButton } - - - { this.getLabel("Start chat", this.state.peopleHover) } - - - - { this.getLabel("Room directory", this.state.directoryHover) } - - - - { this.getLabel("Create new room", this.state.roomsHover) } - - - - { this.getLabel("Settings", this.state.settingsHover) } - + + + + + +
); diff --git a/src/components/structures/RoomDirectory.js b/src/components/structures/RoomDirectory.js index cdf8d19e..91046959 100644 --- a/src/components/structures/RoomDirectory.js +++ b/src/components/structures/RoomDirectory.js @@ -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); diff --git a/src/components/structures/RoomSubList.js b/src/components/structures/RoomSubList.js index 577dac9c..ab6c4422 100644 --- a/src/components/structures/RoomSubList.js +++ b/src/components/structures/RoomSubList.js @@ -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 = ; + 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 = - { target } - { this.makeRoomTiles() } + { content } ; } else { @@ -520,6 +522,7 @@ var RoomSubList = React.createClass({ roomNotificationCount={ this.roomNotificationCount() } onClick={ this.onClick } onHeaderClick={ this.props.onHeaderClick } + headerItems={this.props.headerItems} /> { subList } @@ -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) ? : undefined } diff --git a/src/components/structures/RoomSubListHeader.js b/src/components/structures/RoomSubListHeader.js index ad9aff5f..74094ae0 100644 --- a/src/components/structures/RoomSubListHeader.js +++ b/src/components/structures/RoomSubListHeader.js @@ -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 =
{ FormattingUtils.formatCount(subListNotifCount) }
; - } - else if (subListNotifHighlight) { + badge =
{ formatCount(subListNotifCount) }
; + } else if (subListNotifHighlight) { badge =
!
; } // 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 = ; } @@ -109,6 +104,7 @@ module.exports = React.createClass({
{ this.props.collapsed ? '' : this.props.label } + {this.props.headerItems}
{ roomCount }
{ badge } diff --git a/src/skins/vector/css/_components.scss b/src/skins/vector/css/_components.scss index 54f6c795..a0864817 100644 --- a/src/skins/vector/css/_components.scss +++ b/src/skins/vector/css/_components.scss @@ -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"; diff --git a/src/skins/vector/css/matrix-react-sdk/structures/_RoomView.scss b/src/skins/vector/css/matrix-react-sdk/structures/_RoomView.scss index 12861939..e251ecd1 100644 --- a/src/skins/vector/css/matrix-react-sdk/structures/_RoomView.scss +++ b/src/skins/vector/css/matrix-react-sdk/structures/_RoomView.scss @@ -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 { diff --git a/src/skins/vector/css/matrix-react-sdk/views/elements/_MemberEventListSummary.scss b/src/skins/vector/css/matrix-react-sdk/views/elements/_MemberEventListSummary.scss index 18588659..1969bc2d 100644 --- a/src/skins/vector/css/matrix-react-sdk/views/elements/_MemberEventListSummary.scss +++ b/src/skins/vector/css/matrix-react-sdk/views/elements/_MemberEventListSummary.scss @@ -20,6 +20,7 @@ limitations under the License. .mx_TextualEvent.mx_MemberEventListSummary_summary { font-size: 14px; + display: inline-flex; } .mx_MemberEventListSummary_avatars { diff --git a/src/skins/vector/css/matrix-react-sdk/views/elements/_RoleButton.scss b/src/skins/vector/css/matrix-react-sdk/views/elements/_RoleButton.scss new file mode 100644 index 00000000..094e0b9b --- /dev/null +++ b/src/skins/vector/css/matrix-react-sdk/views/elements/_RoleButton.scss @@ -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; +} diff --git a/src/skins/vector/css/matrix-react-sdk/views/rooms/_RoomList.scss b/src/skins/vector/css/matrix-react-sdk/views/rooms/_RoomList.scss index 110dcd5b..35787ca0 100644 --- a/src/skins/vector/css/matrix-react-sdk/views/rooms/_RoomList.scss +++ b/src/skins/vector/css/matrix-react-sdk/views/rooms/_RoomList.scss @@ -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; +} diff --git a/src/skins/vector/css/vector-web/structures/_LeftPanel.scss b/src/skins/vector/css/vector-web/structures/_LeftPanel.scss index d3bbce1b..f171591c 100644 --- a/src/skins/vector/css/vector-web/structures/_LeftPanel.scss +++ b/src/skins/vector/css/vector-web/structures/_LeftPanel.scss @@ -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; -} diff --git a/src/vector/platform/ElectronPlatform.js b/src/vector/platform/ElectronPlatform.js index 9c857e35..82ef0b51 100644 --- a/src/vector/platform/ElectronPlatform.js +++ b/src/vector/platform/ElectronPlatform.js @@ -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 { 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 { return q('granted'); } diff --git a/src/vector/platform/VectorBasePlatform.js b/src/vector/platform/VectorBasePlatform.js index 5240f3f5..1466b76a 100644 --- a/src/vector/platform/VectorBasePlatform.js +++ b/src/vector/platform/VectorBasePlatform.js @@ -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"; } } diff --git a/src/vector/platform/WebPlatform.js b/src/vector/platform/WebPlatform.js index 5dc55052..72ca19f0 100644 --- a/src/vector/platform/WebPlatform.js +++ b/src/vector/platform/WebPlatform.js @@ -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 { // 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 { 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 { 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."; diff --git a/src/vector/submit-rageshake.js b/src/vector/submit-rageshake.js index ef6fbabe..45b427e8 100644 --- a/src/vector/submit-rageshake.js +++ b/src/vector/submit-rageshake.js @@ -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();