diff --git a/CHANGELOG.md b/CHANGELOG.md index f2541d19..d3077644 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,50 @@ +Changes in [0.12.6](https://github.com/vector-im/riot-web/releases/tag/v0.12.6) (2017-09-21) +============================================================================================ +[Full Changelog](https://github.com/vector-im/riot-web/compare/v0.12.5...v0.12.6) + + * Use matrix-js-sdk v0.8.4 to fix build + +Changes in [0.12.5](https://github.com/vector-im/riot-web/releases/tag/v0.12.5) (2017-09-21) +============================================================================================ +[Full Changelog](https://github.com/vector-im/riot-web/compare/v0.12.4...v0.12.5) + + * Use react-sdk v0.10.5 to fix build + +Changes in [0.12.4](https://github.com/vector-im/riot-web/releases/tag/v0.12.4) (2017-09-20) +============================================================================================ +[Full Changelog](https://github.com/vector-im/riot-web/compare/v0.12.4-rc.1...v0.12.4) + + * No changes + +Changes in [0.12.4-rc.1](https://github.com/vector-im/riot-web/releases/tag/v0.12.4-rc.1) (2017-09-19) +====================================================================================================== +[Full Changelog](https://github.com/vector-im/riot-web/compare/v0.12.3...v0.12.4-rc.1) + + * Fix test for new behaviour of 'joining' flag + [\#5053](https://github.com/vector-im/riot-web/pull/5053) + * fix really dumb blunder/typo preventing system from going to sleep. + [\#5080](https://github.com/vector-im/riot-web/pull/5080) + * T3chguy/devtools + [\#4735](https://github.com/vector-im/riot-web/pull/4735) + * CSS for unignore button in UserSettings + [\#5042](https://github.com/vector-im/riot-web/pull/5042) + * Fix alias on home page for identity room + [\#5044](https://github.com/vector-im/riot-web/pull/5044) + * generic contextual menu for tooltip/responses + [\#4989](https://github.com/vector-im/riot-web/pull/4989) + * Update from Weblate. + [\#5018](https://github.com/vector-im/riot-web/pull/5018) + * Avoid re-rendering RoomList on room switch + [\#5015](https://github.com/vector-im/riot-web/pull/5015) + * Fix menu on change keyboard language issue #4345 + [\#4623](https://github.com/vector-im/riot-web/pull/4623) + * Make isInvite default to false + [\#4999](https://github.com/vector-im/riot-web/pull/4999) + * Revert "Implement sticky date separators" + [\#4991](https://github.com/vector-im/riot-web/pull/4991) + * Implement sticky date separators + [\#4939](https://github.com/vector-im/riot-web/pull/4939) + Changes in [0.12.3](https://github.com/vector-im/riot-web/releases/tag/v0.12.3) (2017-09-06) ============================================================================================ [Full Changelog](https://github.com/vector-im/riot-web/compare/v0.12.3-rc.3...v0.12.3) diff --git a/electron_app/package.json b/electron_app/package.json index ea0932b6..4d177690 100644 --- a/electron_app/package.json +++ b/electron_app/package.json @@ -2,7 +2,7 @@ "name": "riot-web", "productName": "Riot", "main": "src/electron-main.js", - "version": "0.12.3", + "version": "0.12.6", "description": "A feature-rich client for Matrix.org", "author": "Vector Creations Ltd.", "dependencies": { diff --git a/electron_app/src/electron-main.js b/electron_app/src/electron-main.js index ce5ac384..4ffe2110 100644 --- a/electron_app/src/electron-main.js +++ b/electron_app/src/electron-main.js @@ -84,7 +84,7 @@ let powerSaveBlockerId; electron.ipcMain.on('app_onAction', function(ev, payload) { switch (payload.action) { case 'call_state': - if (powerSaveBlockerId && powerSaveBlockerId.isStarted(powerSaveBlockerId)) { + if (powerSaveBlockerId && electron.powerSaveBlocker.isStarted(powerSaveBlockerId)) { if (payload.state === 'ended') { electron.powerSaveBlocker.stop(powerSaveBlockerId); } diff --git a/package.json b/package.json index 61fb440c..455692d1 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "name": "riot-web", "productName": "Riot", "main": "electron_app/src/electron-main.js", - "version": "0.12.3", + "version": "0.12.6", "description": "A feature-rich client for Matrix.org", "author": "Vector Creations Ltd.", "repository": { @@ -47,7 +47,7 @@ "lint": "eslint src/", "lintall": "eslint src/ test/", "clean": "rimraf lib webapp electron_app/dist", - "prepublish": "npm run build:compile", + "prepublish": "npm run clean && npm run build:compile", "test": "karma start --single-run=true --autoWatch=false --browsers ChromeHeadless", "test-multi": "karma start" }, @@ -66,10 +66,11 @@ "gfm.css": "^1.1.1", "highlight.js": "^9.0.0", "linkifyjs": "^2.1.3", - "matrix-js-sdk": "0.8.2", - "matrix-react-sdk": "0.10.3", + "matrix-js-sdk": "0.8.4", + "matrix-react-sdk": "0.10.6", "modernizr": "^3.1.0", "pako": "^1.0.5", + "prop-types": "^15.5.10", "react": "^15.6.0", "react-dnd": "^2.1.4", "react-dnd-html5-backend": "^2.1.2", diff --git a/res/home.html b/res/home.html index 3ba2e964..4b8da3da 100644 --- a/res/home.html +++ b/res/home.html @@ -249,7 +249,7 @@ _t("Implementing VoIP services with Matrix")
- + Matrix Identity diff --git a/scripts/copy-res.js b/scripts/copy-res.js index ac3daf60..59f71692 100755 --- a/scripts/copy-res.js +++ b/scripts/copy-res.js @@ -17,6 +17,7 @@ const INCLUDE_LANGS = [ {'value': 'eo', 'label': 'Esperanto'}, {'value': 'es', 'label': 'Español'}, {'value': 'eu', 'label': 'Euskal'}, + {'value': 'fi', 'label': 'Suomi'}, {'value': 'fr', 'label': 'Français'}, {'value': 'hu', 'label': 'Magyar'}, {'value': 'ko', 'label': '한국어'}, diff --git a/scripts/deploy.py b/scripts/deploy.py index e7ad3f78..e8fd9aa4 100755 --- a/scripts/deploy.py +++ b/scripts/deploy.py @@ -14,6 +14,7 @@ import subprocess import sys import tarfile import shutil +import glob try: # python3 @@ -66,7 +67,7 @@ class Deployer: self.bundles_path = None self.should_clean = False # filename -> symlink path e.g 'config.localhost.json' => '../localhost/config.json' - self.config_locations = {} + self.symlink_paths = {} self.verify_signature = True def deploy(self, tarball, extract_path): @@ -98,11 +99,11 @@ class Deployer: print ("Extracted into: %s" % extracted_dir) - if self.config_locations: - for config_filename, config_loc in self.config_locations.iteritems(): + if self.symlink_paths: + for link_path, file_path in self.symlink_paths.iteritems(): create_relative_symlink( - target=config_loc, - linkname=os.path.join(extracted_dir, config_filename) + target=file_path, + linkname=os.path.join(extracted_dir, link_path) ) if self.bundles_path: @@ -165,9 +166,10 @@ if __name__ == "__main__": ) ) parser.add_argument( - "--config", nargs='?', default='./config.json', help=( - "Write a symlink at config.json in the extracted tarball to this \ - location. (Default: '%(default)s')" + "--include", nargs='*', default='./config*.json', help=( + "Symlink these files into the root of the deployed tarball. \ + Useful for config files and home pages. Supports glob syntax. \ + (Default: '%(default)s')" ) ) parser.add_argument( @@ -182,8 +184,8 @@ if __name__ == "__main__": deployer.packages_path = args.packages_dir deployer.bundles_path = args.bundles_dir deployer.should_clean = args.clean - deployer.config_locations = { - "config.json": args.config, - } + + for include in args.include: + deployer.symlink_paths.update({ os.path.basename(pth): pth for pth in glob.iglob(include) }) deployer.deploy(args.tarball, args.extract_path) diff --git a/scripts/redeploy.py b/scripts/redeploy.py index e10a48c0..2dac2931 100755 --- a/scripts/redeploy.py +++ b/scripts/redeploy.py @@ -15,6 +15,7 @@ import json, requests, tarfile, argparse, os, errno import time import traceback from urlparse import urljoin +import glob from flask import Flask, jsonify, request, abort @@ -188,15 +189,12 @@ if __name__ == "__main__": ) ) - def _raise(ex): - raise ex - - # --config config.json=../../config.json --config config.localhost.json=./localhost.json + # --include ../../config.json ./localhost.json homepages/* parser.add_argument( - "--config", action="append", dest="configs", - type=lambda kv: kv.split("=", 1) if "=" in kv else _raise(Exception("Missing =")), help=( - "A list of configs to symlink into the extracted tarball. \ - For example, --config config.json=../config.json config2.json=../test/config.json" + "--include", nargs='*', default='./config*.json', help=( + "Symlink these files into the root of the deployed tarball. \ + Useful for config files and home pages. Supports glob syntax. \ + (Default: '%(default)s')" ) ) parser.add_argument( @@ -220,7 +218,9 @@ if __name__ == "__main__": deployer = Deployer() deployer.bundles_path = args.bundles_dir deployer.should_clean = args.clean - deployer.config_locations = dict(args.configs) if args.configs else {} + + for include in args.include: + deployer.symlink_paths.update({ os.path.basename(pth): pth for pth in glob.iglob(include) }) # we don't pgp-sign jenkins artifacts; instead we rely on HTTPS access to @@ -234,13 +234,13 @@ if __name__ == "__main__": deploy_tarball(args.tarball_uri, build_dir) else: print( - "Listening on port %s. Extracting to %s%s. Symlinking to %s. Jenkins URL: %s. Config locations: %s" % + "Listening on port %s. Extracting to %s%s. Symlinking to %s. Jenkins URL: %s. Include files: %s" % (args.port, arg_extract_path, " (clean after)" if deployer.should_clean else "", arg_symlink, arg_jenkins_url, - deployer.config_locations, + deployer.symlink_paths, ) ) app.run(host="0.0.0.0", port=args.port, debug=True) diff --git a/src/components/structures/RightPanel.js b/src/components/structures/RightPanel.js index 9120de8c..f867cd32 100644 --- a/src/components/structures/RightPanel.js +++ b/src/components/structures/RightPanel.js @@ -1,5 +1,7 @@ /* Copyright 2015, 2016 OpenMarket Ltd +Copyright 2017 Vector Creations Ltd +Copyright 2017 New Vector Ltd Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -14,8 +16,6 @@ See the License for the specific language governing permissions and limitations under the License. */ -'use strict'; - import React from 'react'; import { _t } from 'matrix-react-sdk/lib/languageHandler'; import sdk from 'matrix-react-sdk'; @@ -26,26 +26,31 @@ import Analytics from 'matrix-react-sdk/lib/Analytics'; import rate_limited_func from 'matrix-react-sdk/lib/ratelimitedfunc'; import Modal from 'matrix-react-sdk/lib/Modal'; import AccessibleButton from 'matrix-react-sdk/lib/components/views/elements/AccessibleButton'; +import { showGroupInviteDialog } from 'matrix-react-sdk/lib/GroupInvite'; module.exports = React.createClass({ displayName: 'RightPanel', propTypes: { - // TODO: This should not be a prop, it should be received from the RoomViewStore + // TODO: We're trying to move away from these being props, but we need to know + // whether we should be displaying a room or group member list roomId: React.PropTypes.string, // if showing panels for a given room, this is set + groupId: React.PropTypes.string, // if showing panels for a given group, this is set collapsed: React.PropTypes.bool, // currently unused property to request for a minimized view of the panel }, Phase: { - MemberList: 'MemberList', + RoomMemberList: 'RoomMemberList', + GroupMemberList: 'GroupMemberList', FilePanel: 'FilePanel', NotificationPanel: 'NotificationPanel', - MemberInfo: 'MemberInfo', + RoomMemberInfo: 'RoomMemberInfo', + GroupMemberInfo: 'GroupMemberInfo', }, componentWillMount: function() { this.dispatcherRef = dis.register(this.onAction); - var cli = MatrixClientPeg.get(); + const cli = MatrixClientPeg.get(); cli.on("RoomState.members", this.onRoomStateMember); }, @@ -57,14 +62,20 @@ module.exports = React.createClass({ }, getInitialState: function() { - return { - phase: this.Phase.MemberList - }; + if (this.props.groupId) { + return { + phase: this.Phase.GroupMemberList, + }; + } else { + return { + phase: this.Phase.RoomMemberList, + }; + } }, onMemberListButtonClick: function() { Analytics.trackEvent('Right Panel', 'Member List Button', 'click'); - this.setState({ phase: this.Phase.MemberList }); + this.setState({ phase: this.Phase.RoomMemberList }); }, onFileListButtonClick: function() { @@ -89,19 +100,23 @@ module.exports = React.createClass({ return; } - // call ChatInviteDialog - dis.dispatch({ - action: 'view_invite', - roomId: this.props.roomId, - }); + if (this.state.phase === this.Phase.GroupMemberList) { + showGroupInviteDialog(this.props.groupId); + } else { + // call AddressPickerDialog + dis.dispatch({ + action: 'view_invite', + roomId: this.props.roomId, + }); + } }, onRoomStateMember: function(ev, state, member) { // redraw the badge on the membership list - if (this.state.phase == this.Phase.MemberList && member.roomId === this.props.roomId) { + if (this.state.phase == this.Phase.RoomMemberList && member.roomId === this.props.roomId) { this._delayedUpdate(); } - else if (this.state.phase === this.Phase.MemberInfo && member.roomId === this.props.roomId && + else if (this.state.phase === this.Phase.RoomMemberInfo && member.roomId === this.props.roomId && member.userId === this.state.member.userId) { // refresh the member info (e.g. new power level) this._delayedUpdate(); @@ -119,39 +134,55 @@ module.exports = React.createClass({ }); if (payload.member) { this.setState({ - phase: this.Phase.MemberInfo, + phase: this.Phase.RoomMemberInfo, member: payload.member, }); + } else { + if (this.props.roomId) { + this.setState({ + phase: this.Phase.RoomMemberList + }); + } else if (this.props.groupId) { + this.setState({ + phase: this.Phase.GroupMemberList, + groupId: payload.groupId, + member: payload.member, + }); + } } - else { - this.setState({ - phase: this.Phase.MemberList - }); - } - } - else if (payload.action === "view_room") { - if (this.state.phase === this.Phase.MemberInfo) { - this.setState({ - phase: this.Phase.MemberList - }); - } + } else if (payload.action === "view_group") { + this.setState({ + phase: this.Phase.GroupMemberList, + groupId: payload.groupId, + member: null, + }); + } else if (payload.action === "view_group_user") { + this.setState({ + phase: this.Phase.GroupMemberInfo, + groupId: payload.groupId, + member: payload.member, + }); + } else if (payload.action === "view_room") { + this.setState({ + phase: this.Phase.RoomMemberList + }); } }, render: function() { - var MemberList = sdk.getComponent('rooms.MemberList'); - var NotificationPanel = sdk.getComponent('structures.NotificationPanel'); - var FilePanel = sdk.getComponent('structures.FilePanel'); - var TintableSvg = sdk.getComponent("elements.TintableSvg"); - var buttonGroup; - var inviteGroup; - var panel; + const MemberList = sdk.getComponent('rooms.MemberList'); + const GroupMemberList = sdk.getComponent('groups.GroupMemberList'); + const NotificationPanel = sdk.getComponent('structures.NotificationPanel'); + const FilePanel = sdk.getComponent('structures.FilePanel'); + const TintableSvg = sdk.getComponent("elements.TintableSvg"); + let inviteGroup; + let panel; - var filesHighlight; - var membersHighlight; - var notificationsHighlight; + let filesHighlight; + let membersHighlight; + let notificationsHighlight; if (!this.props.collapsed) { - if (this.state.phase == this.Phase.MemberList || this.state.phase === this.Phase.MemberInfo) { + if (this.state.phase == this.Phase.RoomMemberList || this.state.phase === this.Phase.RoomMemberInfo) { membersHighlight =
; } else if (this.state.phase == this.Phase.FilePanel) { @@ -162,11 +193,11 @@ module.exports = React.createClass({ } } - var membersBadge; - if ((this.state.phase == this.Phase.MemberList || this.state.phase === this.Phase.MemberInfo) && this.props.roomId) { - var cli = MatrixClientPeg.get(); - var room = cli.getRoom(this.props.roomId); - var user_is_in_room; + let membersBadge; + if ((this.state.phase == this.Phase.RoomMemberList || this.state.phase === this.Phase.RoomMemberInfo) && this.props.roomId) { + const cli = MatrixClientPeg.get(); + const room = cli.getRoom(this.props.roomId); + let user_is_in_room; if (room) { membersBadge = room.getJoinedMembers().length; user_is_in_room = room.hasMembershipState( @@ -186,48 +217,72 @@ module.exports = React.createClass({ } + let headerButtons = []; if (this.props.roomId) { - buttonGroup = -
- -
{ membersBadge ? membersBadge :  }
- - { membersHighlight } -
- -
 
- - { filesHighlight } -
- -
 
- - { notificationsHighlight } -
-
- -
-
; + headerButtons.push( + +
{ membersBadge ? membersBadge :  }
+ + { membersHighlight } +
+ ); + headerButtons.push( + +
 
+ + { filesHighlight } +
+ ); + headerButtons.push( + +
 
+ + { notificationsHighlight } +
+ ); + } + + if (this.props.roomId || this.props.groupId) { + // Hiding the right panel hides it completely and relies on an 'expand' button + // being put in the RoomHeader or GroupView header, so only show the minimise + // button on these 2 screens or you won't be able to re-expand the panel. + headerButtons.push( +
+ +
+ ); } if (!this.props.collapsed) { - if(this.props.roomId && this.state.phase == this.Phase.MemberList) { + if (this.props.roomId && this.state.phase == this.Phase.RoomMemberList) { panel = - } - else if(this.state.phase == this.Phase.MemberInfo) { - var MemberInfo = sdk.getComponent('rooms.MemberInfo'); + } else if (this.props.groupId && this.state.phase == this.Phase.GroupMemberList) { + panel = ; + inviteGroup = ( + +
+ +
+
{ _t('Invite to this group') }
+
+ ); + } else if (this.state.phase == this.Phase.RoomMemberInfo) { + const MemberInfo = sdk.getComponent('rooms.MemberInfo'); panel = - } - else if (this.state.phase == this.Phase.NotificationPanel) { - panel = - } - else if (this.state.phase == this.Phase.FilePanel) { - panel = + } else if (this.state.phase == this.Phase.GroupMemberInfo) { + const GroupMemberInfo = sdk.getComponent('groups.GroupMemberInfo'); + panel = ; + } else if (this.state.phase == this.Phase.NotificationPanel) { + panel = ; + } else if (this.state.phase == this.Phase.FilePanel) { + panel = ; } } @@ -235,7 +290,7 @@ module.exports = React.createClass({ panel =
; } - var classes = "mx_RightPanel mx_fadable"; + let classes = "mx_RightPanel mx_fadable"; if (this.props.collapsed) { classes += " collapsed"; } @@ -243,7 +298,9 @@ module.exports = React.createClass({ return (