diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 000000000..1fbc4dccb --- /dev/null +++ b/.travis.yml @@ -0,0 +1,6 @@ +language: node_js +node_js: + - 6 # node v6, to match jenkins +install: + - npm install + - (cd node_modules/matrix-react-sdk && npm run build) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2103aad1e..83d60f7d8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,40 @@ +Changes in [0.7.5-r1](https://github.com/vector-im/vector-web/releases/tag/v0.7.5-r1) (2016-08-28) +================================================================================================== +[Full Changelog](https://github.com/vector-im/vector-web/compare/v0.7.5...v0.7.5-r1) + + * Correctly pin deps :( + +Changes in [0.7.5](https://github.com/vector-im/vector-web/releases/tag/v0.7.5) (2016-08-28) +============================================================================================ +[Full Changelog](https://github.com/vector-im/vector-web/compare/v0.7.4-r1...v0.7.5) + + * re-add leave button in RoomSettings + * add /user URLs + * recognise matrix.to links and other vector links + * fix linkify dependency + * fix avatar clicking in MemberInfo + * fix RoomTagContextMenu so it works on historical rooms + * warn people to put their Matrix HS on a separate domain to Vector + * fix zalgos again + * Add .travis.yml + [\#2007](https://github.com/vector-im/vector-web/pull/2007) + * add fancy changelog dialog + [\#1972](https://github.com/vector-im/vector-web/pull/1972) + * Update autocomplete design + [\#1978](https://github.com/vector-im/vector-web/pull/1978) + * Update encryption info in README + [\#2001](https://github.com/vector-im/vector-web/pull/2001) + * Added event/info message avatars back in + [\#2000](https://github.com/vector-im/vector-web/pull/2000) + * Wmwragg/chat message presentation + [\#1987](https://github.com/vector-im/vector-web/pull/1987) + * Make the notification slider work + [\#1982](https://github.com/vector-im/vector-web/pull/1982) + * Use cpx to copy olm.js, and add watcher + [\#1966](https://github.com/vector-im/vector-web/pull/1966) + * Make up a device display name + [\#1959](https://github.com/vector-im/vector-web/pull/1959) + Changes in [0.7.4-r1](https://github.com/vector-im/vector-web/releases/tag/v0.7.4-r1) (2016-08-12) ================================================================================================== [Full Changelog](https://github.com/vector-im/vector-web/compare/v0.7.4...v0.7.4-r1) diff --git a/README.md b/README.md index a940da64d..aff57eb9d 100644 --- a/README.md +++ b/README.md @@ -8,7 +8,7 @@ Getting Started The easiest way to test Vector is to just use the hosted copy at https://vector.im/beta. The develop branch is continuously deployed by Jenkins at https://vector.im/develop for -those who like living dangerously. +those who like living dangerously. To host your own copy of Vector, the quickest bet is to use a pre-built released version of Vector: @@ -20,6 +20,19 @@ of Vector: as desired. See below for details. 1. Enter the URL into your browser and log into vector! +Important Security Note +======================= + +We do not recommend running Vector from the same domain name as your Matrix +homeserver. The reason is the risk of XSS (cross-site-scripting) vulnerabilities +that could occur if someone caused Vector to load and render malicious user generated +content from a Matrix API which then had trusted access to Vector (or other apps) due +to sharing the same domain. + +We have put some coarse mitigations into place to try to protect against this situation, +but it's still not good practice to do it in the first place. +See https://github.com/vector-im/vector-web/issues/1977 for more details. + Building From Source ==================== @@ -55,7 +68,7 @@ You can configure the app by copying `vector/config.sample.json` to for verifying third party identifiers like email addresses). If this is blank, registering with an email address, adding an email address to your account, or inviting users via email address will not work. Matrix identity servers are - very simple web services which map third party identifiers (currently only email + very simple web services which map third party identifiers (currently only email addresses) to matrix IDs: see http://matrix.org/docs/spec/identity_service/unstable.html for more details. Currently the only public matrix identity servers are https://matrix.org and https://vector.im. In future identity servers will be decentralised. @@ -75,7 +88,9 @@ nativefier https://vector.im/beta/ ``` krisa has a dedicated electron project at https://github.com/krisak/vector-electron-desktop -(although you should swap out the 'vector' folder for the latest vector tarball you want to run) +(although you should swap out the 'vector' folder for the latest vector tarball you want to run. +Get a tarball from https://vector.im/packages or build your own - see Building From Source +above). There's also a (much) older electron distribution at https://github.com/stevenhammerton/vector-desktop @@ -216,20 +231,13 @@ day-to-day use; it is experimental and should be considered only as a proof-of-concept. See https://matrix.org/jira/browse/SPEC-162 for an overview of the current progress. -Vector is built with support for end-to-end encryption by default. - -To enable encryption for a room, type - -``` -/encrypt on -``` - -in the message bar in that room. Vector will then generate a set of keys, and -encrypt all outgoing messages in that room. (Note that other people in that -room will send messages in the clear unless they also `/encrypt on`.) +To enable the (very experimental) support, check the 'End-to-End Encryption' +box in the 'Labs' section of the user settings (note that the labs are disabled +on http://vector.im/beta: you will need to use http://vector.im/develop or your +own deployment of vector). The Room Settings dialog will then show an +'Encryption' setting; rooms for which you are an administrator will offer you +the option of enabling encryption. Any messages sent in that room will then be +encrypted. Note that historical encrypted messages cannot currently be decoded - history is therefore lost when the page is reloaded. - -There is currently no visual indication of whether encryption is enabled for a -room. diff --git a/jenkins.sh b/jenkins.sh index f60bec38b..3a4ee0c70 100755 --- a/jenkins.sh +++ b/jenkins.sh @@ -4,12 +4,15 @@ set -e export NVM_DIR="/home/jenkins/.nvm" [ -s "$NVM_DIR/nvm.sh" ] && . "$NVM_DIR/nvm.sh" -nvm use 4 +nvm use 6 set -x npm install +# apparently npm 3.10.3 on node 6.4.0 doesn't upgrade #develop target with npm install unless explicitly asked. +npm install matrix-react-sdk matrix-js-sdk + # we may be using a dev branch of react-sdk, in which case we need to build it (cd node_modules/matrix-react-sdk && npm run build) diff --git a/package.json b/package.json index be87139b2..7f1e8d921 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "vector-web", - "version": "0.7.4-r1", + "version": "0.7.5-r1", "description": "Vector webapp", "author": "matrix.org", "repository": { @@ -46,9 +46,9 @@ "gemini-scrollbar": "matrix-org/gemini-scrollbar#b302279", "gfm.css": "^1.1.1", "highlight.js": "^9.0.0", - "linkifyjs": "^2.0.0-beta.4", - "matrix-js-sdk": "matrix-org/matrix-js-sdk#develop", - "matrix-react-sdk": "matrix-org/matrix-react-sdk#develop", + "linkifyjs": "2.0.0-beta.4", + "matrix-js-sdk": "0.5.6", + "matrix-react-sdk": "0.6.5", "modernizr": "^3.1.0", "q": "^1.4.1", "react": "^15.2.1", diff --git a/src/component-index.js b/src/component-index.js index b4c73a4b0..dfe549930 100644 --- a/src/component-index.js +++ b/src/component-index.js @@ -37,6 +37,7 @@ module.exports.components['structures.ViewSource'] = require('./components/struc module.exports.components['views.context_menus.MessageContextMenu'] = require('./components/views/context_menus/MessageContextMenu'); module.exports.components['views.context_menus.NotificationStateContextMenu'] = require('./components/views/context_menus/NotificationStateContextMenu'); module.exports.components['views.context_menus.RoomTagContextMenu'] = require('./components/views/context_menus/RoomTagContextMenu'); +module.exports.components['views.dialogs.ChangelogDialog'] = require('./components/views/dialogs/ChangelogDialog'); module.exports.components['views.elements.ImageView'] = require('./components/views/elements/ImageView'); module.exports.components['views.elements.Spinner'] = require('./components/views/elements/Spinner'); module.exports.components['views.globals.GuestWarningBar'] = require('./components/views/globals/GuestWarningBar'); diff --git a/src/components/structures/RightPanel.js b/src/components/structures/RightPanel.js index ca9376e1b..4ca3dded9 100644 --- a/src/components/structures/RightPanel.js +++ b/src/components/structures/RightPanel.js @@ -17,7 +17,8 @@ limitations under the License. 'use strict'; var React = require('react'); -var sdk = require('matrix-react-sdk') +var sdk = require('matrix-react-sdk'); +var Matrix = require("matrix-js-sdk"); var dis = require('matrix-react-sdk/lib/dispatcher'); var MatrixClientPeg = require("matrix-react-sdk/lib/MatrixClientPeg"); var rate_limited_func = require('matrix-react-sdk/lib/ratelimitedfunc'); @@ -45,8 +46,17 @@ module.exports = React.createClass({ }, getInitialState: function() { - return { - phase : this.Phase.MemberList + if (this.props.userId) { + var member = new Matrix.RoomMember(null, this.props.userId); + return { + phase: this.Phase.MemberInfo, + member: member, + } + } + else { + return { + phase: this.Phase.MemberList + } } }, @@ -97,7 +107,7 @@ module.exports = React.createClass({ }); } } - if (payload.action === "view_room") { + else if (payload.action === "view_room") { if (this.state.phase === this.Phase.MemberInfo) { this.setState({ phase: this.Phase.MemberList @@ -145,15 +155,15 @@ module.exports = React.createClass({ { filesHighlight } ; + } - if (!this.props.collapsed) { - if(this.state.phase == this.Phase.MemberList) { - panel = - } - else if(this.state.phase == this.Phase.MemberInfo) { - var MemberInfo = sdk.getComponent('rooms.MemberInfo'); - panel = - } + if (!this.props.collapsed) { + if(this.props.roomId && this.state.phase == this.Phase.MemberList) { + panel = + } + else if(this.state.phase == this.Phase.MemberInfo) { + var MemberInfo = sdk.getComponent('rooms.MemberInfo'); + panel = } } diff --git a/src/components/structures/RoomSubList.js b/src/components/structures/RoomSubList.js index 4817218be..4fd2618d6 100644 --- a/src/components/structures/RoomSubList.js +++ b/src/components/structures/RoomSubList.js @@ -456,7 +456,7 @@ var RoomSubList = React.createClass({ // is run with historical room tag data, after that there should only be undefined // in the list at a time anyway. for (let i = 0; i < list.length; i++) { - if (list[i].tags[self.props.tagName].order === undefined) { + if (list[i].tags[self.props.tagName] && list[i].tags[self.props.tagName].order === undefined) { MatrixClientPeg.get().setRoomTag(list[i].roomId, self.props.tagName, {order: (order + 1.0) / 2.0}).finally(function() { // Do any final stuff here }).fail(function(err) { diff --git a/src/components/views/context_menus/MessageContextMenu.js b/src/components/views/context_menus/MessageContextMenu.js index 401c0c6cc..737b7faa4 100644 --- a/src/components/views/context_menus/MessageContextMenu.js +++ b/src/components/views/context_menus/MessageContextMenu.js @@ -133,12 +133,11 @@ module.exports = React.createClass({ } } - // XXX: this should be https://matrix.to. // XXX: if we use room ID, we should also include a server where the event can be found (other than in the domain of the event ID) permalinkButton = (
- Permalink + Permalink
); diff --git a/src/components/views/context_menus/RoomTagContextMenu.js b/src/components/views/context_menus/RoomTagContextMenu.js index 776f95227..3637a3a5e 100644 --- a/src/components/views/context_menus/RoomTagContextMenu.js +++ b/src/components/views/context_menus/RoomTagContextMenu.js @@ -126,6 +126,25 @@ module.exports = React.createClass({ }; }, + _onClickForget: function() { + // FIXME: duplicated with RoomSettings (and dead code in RoomView) + MatrixClientPeg.get().forget(this.props.room.roomId).done(function() { + dis.dispatch({ action: 'view_next_room' }); + }, function(err) { + var errCode = err.errcode || "unknown error code"; + var ErrorDialog = sdk.getComponent("dialogs.ErrorDialog"); + Modal.createDialog(ErrorDialog, { + title: "Error", + description: `Failed to forget room (${errCode})` + }); + }); + + // Close the context menu + if (this.props.onFinished) { + this.props.onFinished(); + }; + }, + render: function() { var myUserId = MatrixClientPeg.get().credentials.userId; var myMember = this.props.room.getMember(myUserId); @@ -148,6 +167,17 @@ module.exports = React.createClass({ 'mx_RoomTagContextMenu_fieldDisabled': false, }); + if (myMember && myMember.membership === "leave") { + return ( +
+
+ + Forget +
+
+ ); + } + return (
diff --git a/src/components/views/dialogs/ChangelogDialog.js b/src/components/views/dialogs/ChangelogDialog.js new file mode 100644 index 000000000..ea32a756a --- /dev/null +++ b/src/components/views/dialogs/ChangelogDialog.js @@ -0,0 +1,82 @@ +/* + Copyright 2016 Aviral Dasgupta + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +import React from 'react'; +import sdk from 'matrix-react-sdk'; +import request from 'browser-request'; + +const REPOS = ['vector-im/vector-web', 'matrix-org/matrix-react-sdk', 'matrix-org/matrix-js-sdk']; + +export default class ChangelogDialog extends React.Component { + constructor(props) { + super(props); + + this.state = {}; + } + + componentDidMount() { + const version = this.props.newVersion.split('-'); + const version2 = this.props.version.split('-'); + if(version == null || version2 == null) return; + for(let i=0; i { + if(body == null) return; + this.setState({[REPOS[i]]: JSON.parse(body).commits}); + }); + } + } + + render() { + const Spinner = sdk.getComponent('views.elements.Spinner'); + const QuestionDialog = sdk.getComponent('dialogs.QuestionDialog'); + + const logs = REPOS.map(repo => { + if (this.state[repo] == null) return ; + return ( +
+

{repo}

+ {this.state[repo].map(commit => + + )} +
+ ) + }); + + const content = ( +
+ {this.props.version == null || this.props.newVersion == null ?

Unavailable

: logs} +
+ ); + + + return ( + + ) + } +} + +ChangelogDialog.propTypes = { + version: React.PropTypes.string.isRequired, + newVersion: React.PropTypes.string.isRequired, + onFinished: React.PropTypes.func.isRequired, +}; diff --git a/src/components/views/globals/NewVersionBar.js b/src/components/views/globals/NewVersionBar.js index 83dccf5d0..8d819323a 100644 --- a/src/components/views/globals/NewVersionBar.js +++ b/src/components/views/globals/NewVersionBar.js @@ -17,20 +17,36 @@ limitations under the License. 'use strict'; var React = require('react'); -var sdk = require('matrix-react-sdk') +var sdk = require('matrix-react-sdk'); +import Modal from 'matrix-react-sdk/lib/Modal'; -module.exports = React.createClass({ - displayName: 'NewVersionBar', +export default function NewVersionBar(props) { + const onChangelogClicked = () => { + const ChangelogDialog = sdk.getComponent('dialogs.ChangelogDialog'); - render: function() { - return ( -
- /!\ -
- A new version of Vector is available. Refresh your browser. -
+ Modal.createDialog(ChangelogDialog, { + version: props.version, + newVersion: props.newVersion, + onFinished: (update) => { + if(update) { + window.location.reload(); + } + } + }); + }; + + return ( +
+ /!\ +
+ A new version of Vector is available. Refresh your browser.
- ); - } -}); + +
+ ); +} +NewVersionBar.propTypes = { + version: React.PropTypes.string.isRequired, + newVersion: React.PropTypes.string.isRequired, +}; \ No newline at end of file diff --git a/src/skins/vector/css/common.css b/src/skins/vector/css/common.css index afca0214b..64cf4d6d4 100644 --- a/src/skins/vector/css/common.css +++ b/src/skins/vector/css/common.css @@ -251,7 +251,7 @@ input[type=text]:focus, textarea:focus { background-color: #fff; } -.emojione { +.mx_emojione { height: 1em; vertical-align: middle; } @@ -267,7 +267,7 @@ input[type=text]:focus, textarea:focus { } /** green button with rounded corners */ -.textButton { +.mx_textButton { color: #fff; background-color: #76cfa6; border-radius: 17px; diff --git a/src/skins/vector/css/matrix-react-sdk/views/rooms/Autocomplete.css b/src/skins/vector/css/matrix-react-sdk/views/rooms/Autocomplete.css index 40a08ee2d..6d611b5ef 100644 --- a/src/skins/vector/css/matrix-react-sdk/views/rooms/Autocomplete.css +++ b/src/skins/vector/css/matrix-react-sdk/views/rooms/Autocomplete.css @@ -4,7 +4,7 @@ z-index: 1000; width: 100%; border: 1px solid #e5e5e5; - background: rgba(255, 255, 255, 0.9); + background: white; border-bottom: none; border-radius: 4px 4px 0 0; max-height: 50vh; @@ -12,56 +12,68 @@ } .mx_Autocomplete_ProviderSection { - padding: 12px; border-bottom: 1px solid #e5e5e5; } -.mx_Autocomplete_ProviderSection * { - padding: 2px; - border-radius: 4px; +.mx_Autocomplete_Completion_container_pill { + margin: 12px; + display: flex; } -.mx_Autocomplete_Completion { +/* a "block" completion takes up a whole line */ +.mx_Autocomplete_Completion_block { + height: 34px; + display: flex; + padding: 0 12px; user-select: none; cursor: pointer; - transition: 0.3s all ease; - display: flex; align-items: center; + color: #4a4a4a; } -.mx_Autocomplete_Completion.selected * { - transition: 0.3s all ease; +.mx_Autocomplete_Completion_block * { + margin: 0 3px; +} + +.mx_Autocomplete_Completion_pill { + border-radius: 17px; + height: 34px; + display: flex; + user-select: none; + cursor: pointer; + align-items: center; + color: #4a4a4a; +} + +.mx_Autocomplete_Completion_pill * { + margin: 0 3px; +} + +/* container for pill-style completions */ +.mx_Autocomplete_Completion_container_pill { + margin: 12px; + display: flex; + flex-flow: wrap; } .mx_Autocomplete_Completion.selected { - background: #76cfa6; - color: white; + background: #f6f6f6; outline: none; } -.mx_Autocomplete_Completion.selected * { - color: white !important; -} - .mx_Autocomplete_provider_name { - color: #76cfa6; - font-weight: 600; + margin: 12px; + color: #454545; + font-weight: 400; + opacity: 0.4; } -.autocomplete-enter { - opacity: 0.01; +/* styling for common completion elements */ +.mx_Autocomplete_Completion_subtitle { + font-style: italic; + flex: 1; } -.autocomplete-enter.autocomplete-enter-active { - opacity: 1; - transition: opacity 300ms ease-in; -} - -.autocomplete-leave { - opacity: 1; -} - -.autocomplete-leave.autocomplete-leave-active { - opacity: 0.01; - transition: opacity 300ms ease-in; +.mx_Autocomplete_Completion_description { + color: gray; } diff --git a/src/skins/vector/css/matrix-react-sdk/views/rooms/EventTile.css b/src/skins/vector/css/matrix-react-sdk/views/rooms/EventTile.css index 22a88458a..432bdc285 100644 --- a/src/skins/vector/css/matrix-react-sdk/views/rooms/EventTile.css +++ b/src/skins/vector/css/matrix-react-sdk/views/rooms/EventTile.css @@ -34,6 +34,11 @@ limitations under the License. z-index: 2; } +.mx_EventTile.mx_EventTile_info .mx_EventTile_avatar { + top: 8px; + left: 44px; +} + .mx_EventTile_continuation { padding-top: 0px ! important; } diff --git a/src/skins/vector/css/matrix-react-sdk/views/rooms/MessageComposer.css b/src/skins/vector/css/matrix-react-sdk/views/rooms/MessageComposer.css index b1fbd2946..9dd93b804 100644 --- a/src/skins/vector/css/matrix-react-sdk/views/rooms/MessageComposer.css +++ b/src/skins/vector/css/matrix-react-sdk/views/rooms/MessageComposer.css @@ -63,6 +63,7 @@ limitations under the License. align-items: center; overflow: auto; font-size: 14px; + margin-right: 6px; } .mx_MessageComposer_input_rte { border-top: 2px solid #76cfa6; /* placeholder RTE indicator */ diff --git a/src/skins/vector/css/matrix-react-sdk/views/rooms/RoomSettings.css b/src/skins/vector/css/matrix-react-sdk/views/rooms/RoomSettings.css index 449b98191..68f02f7c1 100644 --- a/src/skins/vector/css/matrix-react-sdk/views/rooms/RoomSettings.css +++ b/src/skins/vector/css/matrix-react-sdk/views/rooms/RoomSettings.css @@ -19,6 +19,21 @@ limitations under the License. margin-bottom: 20px; } +.mx_RoomSettings_leaveButton { + height: 36px; + background-color: #76cfa6; + border-radius: 36px; + margin-right: 8px; + color: #fff; + line-height: 34px; + text-align: center; + float: right; + cursor: pointer; + padding-left: 12px; + padding-right: 12px; + margin-right: 32px; +} + .mx_RoomSettings_powerLevels { display: table; } diff --git a/src/skins/vector/css/vector-web/views/dialogs/ChangelogDialog.css b/src/skins/vector/css/vector-web/views/dialogs/ChangelogDialog.css new file mode 100644 index 000000000..37b865d94 --- /dev/null +++ b/src/skins/vector/css/vector-web/views/dialogs/ChangelogDialog.css @@ -0,0 +1,20 @@ +/* +Copyright 2016 Aviral Dasgupta + +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_ChangelogDialog_content { + max-height: 300px; + overflow: auto; +} diff --git a/src/skins/vector/css/vector-web/views/globals/MatrixToolbar.css b/src/skins/vector/css/vector-web/views/globals/MatrixToolbar.css index a8297f46c..4e214e113 100644 --- a/src/skins/vector/css/vector-web/views/globals/MatrixToolbar.css +++ b/src/skins/vector/css/vector-web/views/globals/MatrixToolbar.css @@ -54,3 +54,7 @@ limitations under the License. float: right; margin-right: 10px; } + +.mx_MatrixToolbar_action { + margin-right: 16px; +}