Compare commits

...

56 Commits

Author SHA1 Message Date
Richard van der Hoff
4507117f89 0.4.1 2016-03-23 14:58:30 +00:00
Richard van der Hoff
cad48b62e4 Prepare changelog for v0.4.1 2016-03-23 14:58:30 +00:00
Richard van der Hoff
5138dc9fd8 Bump to react-sdk 0.3.1
Disables ScrollPanel debug.
2016-03-23 14:56:22 +00:00
Richard van der Hoff
c12a77bc15 0.4.0 2016-03-23 14:40:16 +00:00
Richard van der Hoff
695b5d950c Prepare changelog for 0.4.0 2016-03-23 14:39:30 +00:00
Richard van der Hoff
17b2d14ffc Release script for vector-web 2016-03-23 14:15:22 +00:00
Richard van der Hoff
752f8363a7 Bump to release versions of react-sdk and js-sdk 2016-03-23 14:14:07 +00:00
Matthew Hodgson
a3a4ff569e stop scrollbars overlaying on the count 2016-03-23 13:51:38 +00:00
Richard van der Hoff
948b862c31 Bump gemini-scrollbar to latest version
RoomDirectory uses react-gemini-scrollbar directly, so make sure we are using a
consistent version.
2016-03-23 12:24:25 +00:00
Matthew Hodgson
27ab79fd38 handle unaliased room naming more sanely 2016-03-23 11:50:38 +00:00
Matthew Hodgson
8cbc8db1cb oops 2016-03-23 11:38:17 +00:00
Matthew Hodgson
e32299a50c fix enable notifs text 2016-03-23 11:32:47 +00:00
Matthew Hodgson
c843ee3157 handle canonical aliases correctly; search on names; support rooms with no aliases 2016-03-23 11:26:18 +00:00
Matthew Hodgson
490cbbd05f fix horiz pre scrollbars https://github.com/vector-im/vector-web/issues/754 2016-03-22 15:13:36 +00:00
Matthew Hodgson
e4aa43944f crude lipstick for warnings 2016-03-22 12:11:19 +00:00
Matthew Hodgson
827f891ae7 warning prompt for roomsettings 2016-03-22 00:56:38 +00:00
Matthew Hodgson
54c34ab8d5 improve previewbar look & feel 2016-03-21 22:06:06 +00:00
Matthew Hodgson
3339fa2a39 Merge pull request #1232 from vector-im/matthew/permalink
permalink button
2016-03-21 15:39:03 +00:00
Matthew Hodgson
d4a36f5081 permalink button 2016-03-19 23:26:04 +00:00
Matthew Hodgson
19cb06d040 prop fix 2016-03-18 20:08:31 +00:00
Richard van der Hoff
a5e0aa763b Bump gemini-scrollbar version
To fix scrollbar fail thanks to npm's lack of dependency-version conflict
resolution.
2016-03-18 16:34:20 +00:00
Matthew Hodgson
a1e3cf76e1 top-align search results 2016-03-18 16:24:48 +00:00
Matthew Hodgson
866bd55bc3 give notif bar a pointer cursor 2016-03-18 16:16:13 +00:00
Matthew Hodgson
a6257a1148 show right panel if needed when viewing users 2016-03-18 16:09:00 +00:00
Matthew Hodgson
92e187da64 fix ugly spinner on MemberList 2016-03-17 18:44:53 +00:00
Matthew Hodgson
f950b675bd workaround to avoid accidental click-throughs on narrow vertical scrollbars 2016-03-17 18:26:00 +00:00
Matthew Hodgson
aca4457a89 apparently we don't need a default onClick 2016-03-17 17:00:58 +00:00
Matthew Hodgson
725b9a6619 Merge pull request #1191 from vector-im/matthew/insert-displayname
make senderprofiles clickable
2016-03-17 16:59:03 +00:00
Matthew Hodgson
d7a851a353 make senderprofiles clickable 2016-03-17 16:28:49 +00:00
Matthew Hodgson
c6f95dfb3b Merge pull request #1180 from vector-im/matthew/fix-notif-spam
fix notif spam when logging in from a guest session by correctly logging out first.
2016-03-17 14:37:21 +00:00
Matthew Hodgson
4164688c24 add pointer to EventTile 2016-03-17 13:09:28 +00:00
Matthew Hodgson
cddfa62e27 reorder the push settings as off, on, loud - fixes https://github.com/vector-im/vector-web/issues/1117 2016-03-17 02:24:48 +00:00
Matthew Hodgson
a6e3b39f16 fix notif spam on launch by correctly logging out again. reverts start_login_from_guest stuff 2016-03-17 02:08:05 +00:00
Matthew Hodgson
f8fb3a7fe1 fix aspect ratio of roomavatar preview 2016-03-16 20:00:50 +00:00
Matthew Hodgson
50d18ac771 Merge pull request #1165 from vector-im/matthew/cancellable-upgrade
use new start_login_from_guest dispatch for cancellable logins from guest accounts
2016-03-16 14:37:50 +00:00
Mark Haines
1e0c4d8797 Merge pull request #1171 from vector-im/markjh/cleanup_promise
Use then() chaining rather than manual callbacks
2016-03-16 11:16:06 +00:00
Mark Haines
05e479a76c Use then() chaining rather than manual callbacks 2016-03-16 10:59:40 +00:00
Mark Haines
fe9816abf5 Merge pull request #1163 from vector-im/markjh/cleanup
Remove trailing whitespace
2016-03-16 10:52:12 +00:00
Matthew Hodgson
29815b1d13 try a new message tone 2016-03-16 00:54:43 +00:00
Matthew Hodgson
cb45db36c2 use new start_login_from_guest dispatch for cancellable logins from guest accounts 2016-03-15 21:02:25 +00:00
Mark Haines
31915db6f6 Remove trailing whitespace 2016-03-15 18:38:24 +00:00
Mark Haines
eb01cb9cba Merge pull request #1037 from vector-im/markjh/change_push_actions
Update the actions of default rules instead of overriding.
2016-03-15 18:10:04 +00:00
Matthew Hodgson
2a8afd49fb mx_Login_fieldLabel CSS 2016-03-15 18:09:54 +00:00
Mark Haines
9b85d88036 s/somme/some/ 2016-03-15 15:23:18 +00:00
Matthew Hodgson
c2049e991b padding for radio buttons on login pages 2016-03-15 13:37:07 +00:00
Mark Haines
3224a4e49e Add helper functions for decoding and encoding lists of push actions 2016-03-15 11:26:32 +00:00
Matthew Hodgson
cfc4b89225 fix https://github.com/vector-im/vector-web/issues/1154 2016-03-15 10:56:54 +00:00
Mark Haines
8b1444c954 Port the legacy im.vector rules to the new format on startup 2016-03-15 10:49:10 +00:00
Richard van der Hoff
d4d2ef326e Bump to dev branch of js-sdk 2016-03-14 15:54:56 +00:00
Richard van der Hoff
2a62fdb652 Switch back to dev version of react-sdk 2016-03-14 14:08:47 +00:00
Richard van der Hoff
6215326f8e Merge pull request #1137 from vector-im/rav/update_README
Update README to include `npm install` in react-sdk
2016-03-14 12:48:58 +00:00
Richard van der Hoff
da7e9840f3 reinstate npm 3 warning 2016-03-11 15:12:28 +00:00
Richard van der Hoff
cc18458bec Update README to include npm install in react-sdk
Casual users of /develop shouldn't need to do the whole
clone-three-repositories thing.
2016-03-11 15:09:29 +00:00
Richard van der Hoff
928915873b Use npm to fetch react-sdk and js-sdk
After some discussion, we've agreed it's less evil to have package.json point
to git develop, even if you then have to do a manual build step. That avoids
any future problems where (for example) js-sdk develop gains experimental
changes which would break for users using a build process which involves a
manual git checkout.
2016-03-11 14:30:53 +00:00
Mark Haines
3b2d0a6c01 Fix up reading the push rules 2016-02-29 16:56:33 +00:00
Mark Haines
731d94eea4 Update the actions of default rules instead of overriding.
The Matrix CS API, and synapse now supports setting the actions for default
rules. Doing that makes managing the rules much simpler from a vector
persepctive since the ON/LOUD/OFF toggle buttons can be implemented by
setting the actions and enabling/disabling the default rules rather than
overidding them.

Overriding the default rules was difficult because it was not possible
to intermingle the evaluation of user-specified rules with the default
rules. So even though you could add a rule with the same conditions as a
default rule, it would evaluate before *all* the other default rules.

Also creating new rules under a im.vector namespace creates challenges
if we want vector to cooperate with other matrix clients that want to
provide a similar set of toggle switches for the push rules.
2016-02-26 20:51:16 +00:00
42 changed files with 535 additions and 503 deletions

78
CHANGELOG.md Normal file
View File

@@ -0,0 +1,78 @@
Changes in [0.4.1](https://github.com/vector-im/vector-web/releases/tag/v0.4.1) (2016-03-23)
============================================================================================
[Full Changelog](https://github.com/vector-im/vector-web/compare/v0.4.0...v0.4.1)
* Update to matrix-react-sdk 0.3.1; see
https://github.com/matrix-org/matrix-react-sdk/blob/v0.3.1/CHANGELOG.md
(Disables debug logging)
Changes in [0.4.0](https://github.com/vector-im/vector-web/releases/tag/v0.4.0) (2016-03-23)
============================================================================================
[Full Changelog](https://github.com/vector-im/vector-web/compare/v0.3.0...v0.4.0)
* Update to matrix-react-sdk 0.3.0; see
https://github.com/matrix-org/matrix-react-sdk/blob/master/CHANGELOG.md
Other changes
* permalink button
[\#1232](https://github.com/vector-im/vector-web/pull/1232)
* make senderprofiles clickable
[\#1191](https://github.com/vector-im/vector-web/pull/1191)
* fix notif spam when logging in from a guest session by correctly logging out
first.
[\#1180](https://github.com/vector-im/vector-web/pull/1180)
* use new start_login_from_guest dispatch for cancellable logins from guest
accounts
[\#1165](https://github.com/vector-im/vector-web/pull/1165)
* Use then() chaining rather than manual callbacks
[\#1171](https://github.com/vector-im/vector-web/pull/1171)
* Remove trailing whitespace
[\#1163](https://github.com/vector-im/vector-web/pull/1163)
* Update the actions of default rules instead of overriding.
[\#1037](https://github.com/vector-im/vector-web/pull/1037)
* Update README to include `npm install` in react-sdk
[\#1137](https://github.com/vector-im/vector-web/pull/1137)
Changes in vector v0.3.0 (2016-03-11)
======================================
* Lots of new bug fixes and updates
Changes in vector v0.2.0 (2016-02-24)
======================================
* Refactor of matrix-react-sdk and vector to remove separation between views and
controllers
* Temporarily break the layering abstraction between vector and matrix-react-sdk
for expedience in developing vector.
* Vast numbers of new features, including read receipts, read-up-to markers,
updated look and feel, search, new room and user settings, and email invites.
Changes in vector v0.1.2 (2015-10-28)
======================================
* Support Room Avatars
* Fullscreen video calls
* Mute mic in VoIP calls
* Fix bug with multiple desktop notifications
* Context menu on messages
* Better hover-over on member list
* Support CAS auth
* Many other bug fixes
Changes in vector v0.1.1 (2015-08-10)
======================================
* Support logging in with an email address
* Use the Vector identity server
* Fix a bug where the client was not stopped properly on logout
* Fix bugs where field values would be forgotten if login or registration failed
* Improve URL bar navigation
* Add explanatory help text on advanced server options
* Fix a bug which caused execptions on malformed VoIP invitations
* Remove superfluous scrollbars on Firefox
* Numerous CSS fixes
* Improved accessibility
* Support command-click / middle click to open image in a new tab
* Improved room directory
* Fix display of text with many combining unicode points
Changes in vector v0.1.0 (2015-08-10)
======================================
Initial release

View File

@@ -1,44 +0,0 @@
Changes in vector v0.3.0 (2016-03-11)
======================================
* Lots of new bug fixes and updates
Changes in vector v0.2.0 (2016-02-24)
======================================
* Refactor of matrix-react-sdk and vector to remove separation between views and
controllers
* Temporarily break the layering abstraction between vector and matrix-react-sdk
for expedience in developing vector.
* Vast numbers of new features, including read receipts, read-up-to markers,
updated look and feel, search, new room and user settings, and email invites.
Changes in vector v0.1.2 (2015-10-28)
======================================
* Support Room Avatars
* Fullscreen video calls
* Mute mic in VoIP calls
* Fix bug with multiple desktop notifications
* Context menu on messages
* Better hover-over on member list
* Support CAS auth
* Many other bug fixes
Changes in vector v0.1.1 (2015-08-10)
======================================
* Support logging in with an email address
* Use the Vector identity server
* Fix a bug where the client was not stopped properly on logout
* Fix bugs where field values would be forgotten if login or registration failed
* Improve URL bar navigation
* Add explanatory help text on advanced server options
* Fix a bug which caused execptions on malformed VoIP invitations
* Remove superfluous scrollbars on Firefox
* Numerous CSS fixes
* Improved accessibility
* Support command-click / middle click to open image in a new tab
* Improved room directory
* Fix display of text with many combining unicode points
Changes in vector v0.1.0 (2015-08-10)
======================================
Initial release

View File

@@ -10,6 +10,9 @@ Getting started
1. Clone the repo: `git clone https://github.com/vector-im/vector-web.git`
1. Switch to the vector directory: `cd vector-web`
1. Install the prerequisites: `npm install`
1. If you are using the `develop` branch of vector, you will probably need to
rebuild one of the dependencies, due to https://github.com/npm/npm/issues/3055:
`(cd node_modules/matrix-react-sdk && npm install)`
1. Start the development builder and a testing server: `npm start`
1. Wait a few seconds for the initial build to finish (the command won't
terminate: it's running a web server for you).
@@ -48,14 +51,13 @@ webserver to actually serve up the app, which is entirely static content.
Development
===========
For simple tweaks, you can work on any of the source files within Vector with the
setup above, and your changes will cause an instant rebuild.
For simple tweaks, you can work on any of the source files within Vector with
the setup above, and your changes will cause an instant rebuild.
However, all serious development on Vector happens on the `develop` branch. This typically
depends on the `develop` snapshot versions of `matrix-react-sdk` and `matrix-js-sdk`
too, which can't be installed automatically due to https://github.com/npm/npm/issues/3055.
To get the right dependencies, check out the `develop` branches of these libraries and
then use `ln -s` to tell Vector about them:
However, much of the functionality in Vector is actually in the
`matrix-react-sdk` and `matrix-js-sdk` modules. It is possible to set these up
in a way that makes it easy to track the `develop` branches in git and to make
local changes without having to manually rebuild each time.
[Be aware that there may be problems with this process under npm version 3.]

View File

@@ -8,20 +8,23 @@ nvm use 4
set -x
# install the versions of js-sdk and react-sdk provided to us by jenkins
npm install ./node_modules/matrix-js-sdk-*.tgz
npm install ./node_modules/matrix-react-sdk-*.tgz
# install the other dependencies
npm install
# 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)
# build our artifacts; dumps them in ./vector
npm run build
# gzip up ./vector
rm vector-*.tar.gz || true # rm previous artifacts without failing if it doesn't exist
REACT_SHA=$(head -c 12 node_modules/matrix-react-sdk/git-revision.txt)
JSSDK_SHA=$(head -c 12 node_modules/matrix-js-sdk/git-revision.txt)
# node_modules deps from 'npm install' don't have a .git dir so can't
# rev-parse; but they do set the commit in package.json under 'gitHead' which
# we're grabbing here.
REACT_SHA=$(grep 'gitHead' node_modules/matrix-react-sdk/package.json | cut -d \" -f 4 | head -c 12)
JSSDK_SHA=$(grep 'gitHead' node_modules/matrix-js-sdk/package.json | cut -d \" -f 4 | head -c 12)
VECTOR_SHA=$(git rev-parse --short=12 HEAD) # use the ACTUAL SHA rather than assume develop
tar -zcvhf vector-$VECTOR_SHA-react-$REACT_SHA-js-$JSSDK_SHA.tar.gz vector #g[z]ip, [c]reate archive, [v]erbose, [f]ilename, [h]ard-dereference (do not archive symlinks)

View File

@@ -1,6 +1,6 @@
{
"name": "vector-web",
"version": "0.3.0",
"version": "0.4.1",
"description": "Vector webapp",
"author": "matrix.org",
"repository": {
@@ -33,19 +33,19 @@
"extract-text-webpack-plugin": "^0.9.1",
"filesize": "^3.1.2",
"flux": "~2.0.3",
"gemini-scrollbar": "^1.3.0",
"gemini-scrollbar": "matrix-org/gemini-scrollbar#7dc736d",
"gfm.css": "^1.1.1",
"highlight.js": "^9.0.0",
"linkifyjs": "^2.0.0-beta.4",
"matrix-js-sdk": "^0.4.1",
"matrix-react-sdk": "^0.2.0",
"matrix-js-sdk": "^0.5.0",
"matrix-react-sdk": "^0.3.1",
"modernizr": "^3.1.0",
"q": "^1.4.1",
"react": "^0.14.2",
"react-dnd": "^2.0.2",
"react-dnd-html5-backend": "^2.0.0",
"react-dom": "^0.14.2",
"react-gemini-scrollbar": "^2.0.1",
"react-gemini-scrollbar": "matrix-org/react-gemini-scrollbar#869a86b",
"sanitize-html": "^1.11.1"
},
"devDependencies": {

12
release.sh Executable file
View File

@@ -0,0 +1,12 @@
#!/bin/sh
#
# Script to perform a release of vector-web.
#
# Requires github-changelog-generator; to install, do
# pip install git+https://github.com/matrix-org/github-changelog-generator.git
set -e
cd `dirname $0`
exec ./node_modules/matrix-js-sdk/release.sh -z "$@"

View File

@@ -40,7 +40,7 @@ var LeftPanel = React.createClass({
componentWillReceiveProps: function(newProps) {
this._recheckCallElement(newProps.selectedRoom);
},
},
componentWillUnmount: function() {
dis.unregister(this.dispatcherRef);
@@ -95,7 +95,7 @@ var LeftPanel = React.createClass({
}
else {
// Hide the collapse button until we work out how to display it in the new skin
// collapseButton = <img className="mx_LeftPanel_hideButton" onClick={ this.onHideClick } src="img/hide.png" width="12" height="20" alt="<"/>
// collapseButton = <img className="mx_LeftPanel_hideButton" onClick={ this.onHideClick } src="img/hide.png" width="12" height="20" alt="<"/>
}
var callPreview;

View File

@@ -38,7 +38,7 @@ module.exports = React.createClass({
},
componentWillUnmount: function() {
dis.unregister(this.dispatcherRef);
dis.unregister(this.dispatcherRef);
if (MatrixClientPeg.get()) {
MatrixClientPeg.get().removeListener("RoomState.members", this.onRoomStateMember);
}
@@ -82,6 +82,9 @@ module.exports = React.createClass({
onAction: function(payload) {
if (payload.action === "view_user") {
dis.dispatch({
action: 'show_right_panel',
});
if (payload.member) {
this.setState({
phase: this.Phase.MemberInfo,

View File

@@ -47,7 +47,7 @@ module.exports = React.createClass({
var self = this;
MatrixClientPeg.get().publicRooms(function (err, data) {
if (err) {
self.setState({ loading: false });
self.setState({ loading: false });
console.error("Failed to get publicRooms: %s", JSON.stringify(err));
var ErrorDialog = sdk.getComponent("dialogs.ErrorDialog");
Modal.createDialog(ErrorDialog, {
@@ -83,7 +83,7 @@ module.exports = React.createClass({
avatarUrl: room.avatar_url,
// XXX: This logic is duplicated from the JS SDK which
// would normally decide what the name is.
name: room.name || room.aliases[0],
name: room.name || room.canonical_alias || (room.aliases ? room.aliases[0] : "Unnamed room"),
};
}
@@ -102,7 +102,9 @@ module.exports = React.createClass({
var rooms = this.state.publicRooms.filter(function(a) {
// FIXME: if incrementally typing, keep narrowing down the search set
// incrementally rather than starting over each time.
return (a.aliases[0].toLowerCase().search(filter.toLowerCase()) >= 0 && a.num_joined_members > 0);
return (((a.name && a.name.toLowerCase().search(filter.toLowerCase()) >= 0) ||
(a.aliases && a.aliases[0].toLowerCase().search(filter.toLowerCase()) >= 0)) &&
a.num_joined_members > 0);
}).sort(function(a,b) {
return a.num_joined_members - b.num_joined_members;
});
@@ -110,7 +112,8 @@ module.exports = React.createClass({
var self = this;
var guestRead, guestJoin, perms;
for (var i = 0; i < rooms.length; i++) {
var name = rooms[i].name || rooms[i].aliases[0];
var alias = rooms[i].canonical_alias || (rooms[i].aliases ? rooms[i].aliases[0] : "");
var name = rooms[i].name || alias || "Unnamed room";
guestRead = null;
guestJoin = null;
@@ -124,7 +127,7 @@ module.exports = React.createClass({
<div className="mx_RoomDirectory_perm">Guests can join</div>
);
}
perms = null;
if (guestRead || guestJoin) {
perms = <div className="mx_RoomDirectory_perms">{guestRead} {guestJoin}</div>;
@@ -148,7 +151,7 @@ module.exports = React.createClass({
<div className="mx_RoomDirectory_topic"
onClick={ function(e) { e.stopPropagation() } }
dangerouslySetInnerHTML={{ __html: topic }}/>
<div className="mx_RoomDirectory_alias">{ rooms[i].aliases[0] }</div>
<div className="mx_RoomDirectory_alias">{ alias }</div>
</td>
<td className="mx_RoomDirectory_roomMemberCount">
{ rooms[i].num_joined_members }
@@ -169,7 +172,7 @@ module.exports = React.createClass({
render: function() {
if (this.state.loading) {
var Loader = sdk.getComponent("elements.Spinner");
var Loader = sdk.getComponent("elements.Spinner");
return (
<div className="mx_RoomDirectory">
<Loader />

View File

@@ -187,15 +187,15 @@ var RoomSubList = React.createClass({
var rooms = this.state.sortedList;
if (found.room) {
rooms.splice(found.index, 1);
}
}
else {
console.warn("Can't remove room " + room.roomId + " - can't find it");
}
this.setState({ sortedList: rooms });
},
findRoomTile: function(room) {
var index = this.state.sortedList.indexOf(room);
findRoomTile: function(room) {
var index = this.state.sortedList.indexOf(room);
if (index >= 0) {
// console.log("found: room: " + room.roomId + " with index " + index);
}
@@ -210,7 +210,7 @@ var RoomSubList = React.createClass({
},
calcManualOrderTagData: function(room) {
var index = this.state.sortedList.indexOf(room);
var index = this.state.sortedList.indexOf(room);
// we sort rooms by the lexicographic ordering of the 'order' metadata on their tags.
// for convenience, we calculate this for now a floating point number between 0.0 and 1.0.
@@ -274,7 +274,7 @@ var RoomSubList = React.createClass({
},
_getHeaderJsx: function() {
var TintableSvg = sdk.getComponent("elements.TintableSvg");
var TintableSvg = sdk.getComponent("elements.TintableSvg");
return (
<h2 onClick={ this.onClick } className="mx_RoomSubList_label">
{ this.props.collapsed ? '' : this.props.label }
@@ -332,7 +332,7 @@ var RoomSubList = React.createClass({
}
else {
subList = <TruncatedList className={ classes }>
</TruncatedList>;
</TruncatedList>;
}
return connectDropTarget(
@@ -356,7 +356,7 @@ var RoomSubList = React.createClass({
// Export the wrapped version, inlining the 'collect' functions
// to more closely resemble the ES7
module.exports =
module.exports =
DropTarget('RoomTile', roomListTarget, function(connect) {
return {
connectDropTarget: connect.dropTarget(),

View File

@@ -40,7 +40,7 @@ module.exports = React.createClass({
this.props.onFinished();
}
},
render: function() {
return (
<div className="mx_ViewSource">

View File

@@ -21,6 +21,12 @@ var React = require('react');
module.exports = React.createClass({
displayName: 'SenderProfile',
propTypes: {
mxEvent: React.PropTypes.object.isRequired, // event whose sender we're showing
aux: React.PropTypes.string, // stuff to go after the sender name, if anything
onClick: React.PropTypes.func,
},
render: function() {
var mxEvent = this.props.mxEvent;
var name = mxEvent.sender ? mxEvent.sender.name : mxEvent.getSender();
@@ -30,7 +36,7 @@ module.exports = React.createClass({
name = ''; // emote message must include the name so don't duplicate it
}
return (
<span className="mx_SenderProfile">
<span className="mx_SenderProfile" onClick={this.props.onClick}>
{name} { this.props.aux }
</span>
);

View File

@@ -62,12 +62,17 @@ module.exports = React.createClass({
if (this.props.onFinished) this.props.onFinished();
},
onPermalinkClick: function() {
if (this.props.onFinished) this.props.onFinished();
},
render: function() {
var eventStatus = this.props.mxEvent.status;
var resendButton;
var viewSourceButton;
var redactButton;
var cancelButton;
var permalinkButton;
if (eventStatus === 'not_sent') {
resendButton = (
@@ -99,12 +104,22 @@ module.exports = React.createClass({
</div>
);
// 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 = (
<div className="mx_ContextualMenu_field">
<a href={ "#/room/" + this.props.mxEvent.getRoomId() +"/"+ this.props.mxEvent.getId() }
onClick={ this.onPermalinkClick }>Permalink</a>
</div>
);
return (
<div>
{resendButton}
{redactButton}
{cancelButton}
{viewSourceButton}
{permalinkButton}
</div>
);
}

View File

@@ -38,7 +38,7 @@ var roomTileSource = {
// Return the data describing the dragged item
var item = {
room: props.room,
originalList: props.roomSubList,
originalList: props.roomSubList,
originalIndex: props.roomSubList.findRoomTile(props.room).index,
targetList: props.roomSubList, // at first target is same as original
// lastTargetRoom: null,
@@ -145,10 +145,10 @@ var roomTileTarget = {
// shuffle the list to add our tile to that position.
props.roomSubList.moveRoomTile(item.room, roomTile.index);
}
// stop us from flickering between our droptarget and the previous room.
// whenever the cursor changes direction we have to reset the flicker-damping.
/*
/*
var yDelta = off.y - item.lastYOffset;
if ((yDelta > 0 && item.lastYDelta < 0) ||
@@ -168,7 +168,7 @@ var roomTileTarget = {
if (yDelta) item.lastYDelta = yDelta;
item.lastYOffset = off.y;
*/
*/
}
else if (switchedTarget) {
if (!props.roomSubList.findRoomTile(item.room).room) {
@@ -183,7 +183,7 @@ var roomTileTarget = {
// Export the wrapped version, inlining the 'collect' functions
// to more closely resemble the ES7
module.exports =
module.exports =
DropTarget('RoomTile', roomTileTarget, function(connect, monitor) {
return {
// Call this function inside render()

View File

@@ -34,7 +34,7 @@ module.exports = React.createClass({
});
}
else {
tooltip.style.top = tooltip.parentElement.getBoundingClientRect().top + "px";
tooltip.style.top = tooltip.parentElement.getBoundingClientRect().top + "px";
tooltip.style.display = "block";
}
},

View File

@@ -50,7 +50,7 @@ module.exports = React.createClass({
onSearch: function() {
this.props.onSearch(this.refs.search_term.value, this.state.scope);
},
render: function() {
var searchButtonClasses = classNames({ mx_SearchBar_searchButton : true, mx_SearchBar_searching: this.props.searchInProgress });
var thisRoomClasses = classNames({ mx_SearchBar_button : true, mx_SearchBar_unselected : this.state.scope !== 'Room' });

View File

@@ -28,249 +28,195 @@ var Modal = require('matrix-react-sdk/lib/Modal');
* @enum {string}
*/
var PushRuleVectorState = {
/** The push rule is disabled */
OFF: "off",
/** The user will receive push notification for this rule */
ON: "on",
/** The user will receive push notification for this rule with sound and
highlight if this is legitimate */
LOUD: "loud",
/** The push rule is disabled */
OFF: "off"
};
// Encodes a dictionary of {
// "notify": true/false,
// "sound": string or undefined,
// "highlight: true/false,
// }
// to a list of push actions.
function encodeActions(action) {
var notify = action.notify;
var sound = action.sound;
var highlight = action.highlight;
if (notify) {
var actions = ["notify"];
if (sound) {
actions.push({"set_tweak": "sound", "value": sound});
}
if (highlight) {
actions.push({"set_tweak": "highlight"});
} else {
actions.push({"set_tweak": "highlight", "value": false});
}
return actions;
} else {
return ["dont_notify"];
}
}
// Decode a list of actions to a dictionary of {
// "notify": true/false,
// "sound": string or undefined,
// "highlight: true/false,
// }
// If the actions couldn't be decoded then returns null.
function decodeActions(actions) {
var notify = false;
var sound = null;
var highlight = false;
for (var i = 0; i < actions.length; ++i) {
var action = actions[i];
if (action === "notify") {
notify = true;
} else if (action === "dont_notify") {
notify = false;
} else if (typeof action === 'object') {
if (action.set_tweak === "sound") {
sound = action.value
} else if (action.set_tweak === "highlight") {
highlight = action.value;
} else {
// We don't understand this kind of tweak, so give up.
return null;
}
} else {
// We don't understand this kind of action, so give up.
return null;
}
}
if (highlight === undefined) {
// If a highlight tweak is missing a value then it defaults to true.
highlight = true;
}
var result = {notify: notify, highlight: highlight};
if (sound !== null) {
result.sound = sound;
}
return result;
}
var ACTION_NOTIFY = encodeActions({notify: true});
var ACTION_NOTIFY_DEFAULT_SOUND = encodeActions({notify: true, sound: "default"});
var ACTION_NOTIFY_RING_SOUND = encodeActions({notify: true, sound: "ring"});
var ACTION_HIGHLIGHT_DEFAULT_SOUND = encodeActions({notify: true, sound: "default", highlight: true});
var ACTION_DONT_NOTIFY = encodeActions({notify: false});
var ACTION_DISABLED = null;
/**
* The descriptions of rules managed by the Vector UI.
* Each rule is described so that if the server does not have it in its default
* rules or if the user wants to use actions ('PushRuleVectorState') that are
* different from the hs one, the code will create a new rule that will override
* the hs one.
*/
var VectorPushRulesDefinitions = {
// Messages containing user's display name
// Messages containing user's display name
// (skip contains_user_name which is too geeky)
"im.vector.rule.contains_display_name": {
".m.rule.contains_display_name": {
kind: "underride",
hsDefaultRuleId: ".m.rule.contains_display_name",
description: "Messages containing my name",
conditions: [{
"kind": "contains_display_name"
}],
vectorStateToActions: { // The actions for each vector state
on: [
"notify"
],
loud: [
"notify",
{
"set_tweak": "sound",
"value": "default"
},
{
"set_tweak":"highlight"
}
]
},
vectorStateToHsDefaultRuleEnabled: { // If it exists, the hs default push rule enabled expected value for each vector state
on: undefined, // ON (and its actions) does not corresponds to the default hs push rule, so NA
loud: true, // LOUD corresponds to the default rule when its enabled value is true
off: false // OFF corresponds to the default rule when its enabled value is false
},
vectorStateToActions: { // The actions for each vector state, or null to disable the rule.
on: ACTION_NOTIFY,
loud: ACTION_HIGHLIGHT_DEFAULT_SOUND,
off: ACTION_DISABLED
}
},
// Messages just sent to the user in a 1:1 room
"im.vector.rule.room_one_to_one": {
".m.rule.room_one_to_one": {
kind: "underride",
hsDefaultRuleId: ".m.rule.room_one_to_one",
description: "Messages in one-to-one chats",
conditions: [{
"is": "2",
"kind": "room_member_count"
}],
vectorStateToActions: {
on: [
"notify"
],
loud: [
"notify",
{
"set_tweak": "sound",
"value": "default"
}
],
off: [
"dont_notify"
]
},
vectorStateToHsDefaultRuleEnabled: {
on: undefined,
loud: true,
off: undefined
on: ACTION_NOTIFY,
loud: ACTION_NOTIFY_DEFAULT_SOUND,
off: ACTION_DONT_NOTIFY
}
},
// Messages just sent to a group chat room
// 1:1 room messages are catched by the .m.rule.room_one_to_one rule if any defined
// By opposition, all other room messages are from group chat rooms.
"im.vector.rule.room_message": {
".m.rule.message": {
kind: "underride",
description: "Messages in group chats",
conditions: [{
"pattern": "m.room.message",
"kind": "event_match",
"key": "type"
}],
hsDefaultRuleId: ".m.rule.message",
vectorStateToActions: {
on: [
"notify"
],
loud: [
"notify",
{
"set_tweak": "sound",
"value": "default"
}
],
off: [
"dont_notify"
]
},
vectorStateToHsDefaultRuleEnabled: {
on: true,
loud: undefined,
off: undefined
on: ACTION_NOTIFY,
loud: ACTION_NOTIFY_DEFAULT_SOUND,
off: ACTION_DONT_NOTIFY
}
},
// Invitation for the user
"im.vector.rule.invite_for_me": {
".m.rule.invite_for_me": {
kind: "underride",
hsDefaultRuleId: ".m.rule.invite_for_me",
description: "When I'm invited to a room",
conditions: [
{
"key": "type",
"kind": "event_match",
"pattern": "m.room.member"
},
{
"key": "content.membership",
"kind": "event_match",
"pattern": "invite"
},
{
"key": "state_key",
"kind": "event_match",
"pattern": "" // It is updated at runtime the user id
}
],
vectorStateToActions: {
on: [
"notify"
],
loud: [
"notify",
{
"set_tweak": "sound",
"value": "default"
}
]
},
vectorStateToHsDefaultRuleEnabled: {
on: undefined,
loud: true,
off: false
on: ACTION_NOTIFY,
loud: ACTION_NOTIFY_DEFAULT_SOUND,
off: ACTION_DISABLED
}
},
// When people join or leave a room
/*"im.vector.rule.member_event": {
hsDefaultRuleId: ".m.rule.member_event",
description: "When people join or leave a room",
conditions: [{
"pattern": "m.room.member",
"kind": "event_match",
"key": "type"
}],
vectorStateToActions: {
on: [
"notify"
],
loud: [
"notify",
{
"set_tweak": "sound",
"value": "default"
}
]
},
vectorStateToHsDefaultRuleEnabled: {
on: true,
loud: undefined,
off: false
}
},*/
// Incoming call
"im.vector.rule.call": {
".m.rule.call": {
kind: "underride",
hsDefaultRuleId: ".m.rule.call",
description: "Call invitation",
conditions: [{
"pattern": "m.room.member",
"kind": "event_match",
"key": "type"
}],
vectorStateToActions: {
on: [
"notify"
],
loud: [
"notify",
{
"set_tweak": "sound",
"value": "ring"
}
],
},
vectorStateToHsDefaultRuleEnabled: {
on: undefined,
loud: true,
off: false
on: ACTION_NOTIFY,
loud: ACTION_NOTIFY_RING_SOUND,
off: ACTION_DISABLED
}
},
// Notifications from bots
"im.vector.rule.notices": {
".m.rule.suppress_notices": {
kind: "override",
hsDefaultRuleId: ".m.rule.suppress_notices",
description: "Messages sent by bot",
conditions: [{
"kind": "event_match",
"key": "content.msgtype",
"pattern": "m.notice"
}],
vectorStateToActions: {
on: undefined, // ON for vector UI means that the .m.rule.suppress_notices rule is disabled.
loud: [
"notify",
{
"set_tweak": "sound",
"value": "ring"
}
],
off: [
"dont_notify"
]
},
vectorStateToHsDefaultRuleEnabled: {
on: false, // .m.rule.suppress_notices is a "negative" rule, we have to invert its enabled value for vector UI
loud: undefined,
off: true
// .m.rule.suppress_notices is a "negative" rule, we have to invert its enabled value for vector UI
on: ACTION_DISABLED,
loud: ACTION_NOTIFY_DEFAULT_SOUND,
off: ACTION_DONT_NOTIFY,
}
}
};
/**
* Rules that Vector used to set in order to override the actions of default rules.
* These are used to port peoples existing overrides to match the current API.
* These can be removed and forgotten once everyone has moved to the new client.
*/
var LEGACY_RULES = {
"im.vector.rule.contains_display_name": ".m.rule.contains_display_name",
"im.vector.rule.room_one_to_one": ".m.rule.room_one_to_one",
"im.vector.rule.room_message": ".m.rule.message",
"im.vector.rule.invite_for_me": ".m.rule.invite_for_me",
"im.vector.rule.call": ".m.rule.call",
"im.vector.rule.notices": ".m.rule.suppress_notices"
};
function portLegacyActions(actions) {
var decoded = decodeActions(actions);
if (decoded !== null) {
return encodeActions(decoded);
} else {
// We don't recognise one of the actions here, so we don't try to
// canonicalise them.
return actions;
}
}
module.exports = React.createClass({
displayName: 'Notififications',
@@ -279,7 +225,7 @@ module.exports = React.createClass({
DISPLAY: "DISPLAY", // The component is ready and display data
ERROR: "ERROR" // There was an error
},
getInitialState: function() {
return {
phase: this.phases.LOADING,
@@ -293,14 +239,11 @@ module.exports = React.createClass({
externalContentRules: [] // Keyword push rules that have been defined outside Vector UI
};
},
componentWillMount: function() {
// Finalise the vector definitions
VectorPushRulesDefinitions["im.vector.rule.invite_for_me"].conditions[2].pattern = MatrixClientPeg.get().credentials.userId;
this._refreshFromServer();
},
onEnableNotificationsChange: function(event) {
var self = this;
this.setState({
@@ -311,15 +254,15 @@ module.exports = React.createClass({
self._refreshFromServer();
});
},
onEnableDesktopNotificationsChange: function(event) {
UserSettingsStore.setEnableNotifications(event.target.checked);
},
onNotifStateButtonClicked: function(event) {
var vectorRuleId = event.target.className.split("-")[0];
var newPushRuleVectorState = event.target.className.split("-")[1];
if ("_keywords" === vectorRuleId) {
this._setKeywordsPushRuleVectorState(newPushRuleVectorState)
}
@@ -330,7 +273,7 @@ module.exports = React.createClass({
}
}
},
onKeywordsClicked: function(event) {
var self = this;
@@ -371,13 +314,13 @@ module.exports = React.createClass({
}
return array;
},[]);
self._setKeywords(newKeywords);
}
}
});
},
getRule: function(vectorRuleId) {
for (var i in this.state.vectorPushRules) {
var rule = this.state.vectorPushRules[i];
@@ -386,24 +329,21 @@ module.exports = React.createClass({
}
}
},
_actionsFor: function(pushRuleVectorState) {
if (pushRuleVectorState === PushRuleVectorState.ON) {
return ['notify'];
return ACTION_NOTIFY;
}
else if (pushRuleVectorState === PushRuleVectorState.LOUD) {
return ['notify',
{'set_tweak': 'sound', 'value': 'default'},
{'set_tweak': 'highlight', 'value': 'true'}
];;
return ACTION_HIGHLIGHT_DEFAULT_SOUND;
}
},
// Determine whether a content rule is in the PushRuleVectorState.ON category or in PushRuleVectorState.LOUD
// regardless of its enabled state. Returns undefined if it does not match these categories.
_contentRuleVectorStateKind: function(rule) {
var stateKind;
// Count tweaks to determine if it is a ON or LOUD rule
var tweaks = 0;
for (var j in rule.actions) {
@@ -423,9 +363,9 @@ module.exports = React.createClass({
}
return stateKind;
},
_setPushRuleVectorState: function(rule, newPushRuleVectorState) {
if (rule && rule.vectorState !== newPushRuleVectorState) {
_setPushRuleVectorState: function(rule, newPushRuleVectorState) {
if (rule && rule.vectorState !== newPushRuleVectorState) {
this.setState({
phase: this.phases.LOADING
@@ -437,36 +377,18 @@ module.exports = React.createClass({
var ruleDefinition = VectorPushRulesDefinitions[rule.vectorRuleId];
if (rule.rule) {
if (undefined !== ruleDefinition.vectorStateToHsDefaultRuleEnabled[newPushRuleVectorState] && rule.hsDefaultRule) {
// The new state corresponds to the default hs rule
// Enable or disable it according to the rule definition
deferreds.push(cli.setPushRuleEnabled('global', rule.hsDefaultRule.kind, ruleDefinition.hsDefaultRuleId,
ruleDefinition.vectorStateToHsDefaultRuleEnabled[newPushRuleVectorState]));
var actions = ruleDefinition.vectorStateToActions[newPushRuleVectorState];
// Remove the vector rule if any
if (!rule.isHSDefaultRule) {
deferreds.push(cli.deletePushRule('global', rule.rule.kind, rule.rule.rule_id))
}
if (actions === ACTION_DISABLED) {
// The new state corresponds to disabling the rule.
deferreds.push(cli.setPushRuleEnabled('global', rule.rule.kind, rule.rule.rule_id, false));
}
else {
// The new state (and its implied actions) does not correspond to a default hs rule
// or the HS does not expose this default rule.
if (rule.isHSDefaultRule) {
// Create a new rule that will override the default one
deferreds.push(this._addOverridingVectorPushRule(rule.vectorRuleId, newPushRuleVectorState));
}
else {
// Change the actions of the existing overriding Vector rule
deferreds.push(this._updatePushRuleActions(rule.rule, ruleDefinition.vectorStateToActions[newPushRuleVectorState]));
}
// The new state corresponds to enabling the rule and setting specific actions
deferreds.push(this._updatePushRuleActions(rule.rule, actions, true));
}
}
else {
// This is a Vector rule which does not exist yet server side
// Create it
deferreds.push(this._addOverridingVectorPushRule(rule.vectorRuleId, newPushRuleVectorState));
}
q.all(deferreds).done(function() {
self._refreshFromServer();
}, function(error) {
@@ -479,14 +401,14 @@ module.exports = React.createClass({
});
}
},
_setKeywordsPushRuleVectorState: function(newPushRuleVectorState) {
// Is there really a change?
if (this.state.vectorContentRules.vectorState === newPushRuleVectorState
if (this.state.vectorContentRules.vectorState === newPushRuleVectorState
|| this.state.vectorContentRules.rules.length === 0) {
return;
}
var self = this;
var cli = MatrixClientPeg.get();
@@ -547,7 +469,7 @@ module.exports = React.createClass({
});
});
},
_setKeywords: function(newKeywords) {
this.setState({
phase: this.phases.LOADING
@@ -595,9 +517,9 @@ module.exports = React.createClass({
var pushRuleVectorStateKind = self.state.vectorContentRules.vectorState;
if (pushRuleVectorStateKind === PushRuleVectorState.OFF) {
// When the current global keywords rule is OFF, we need to look at
// the flavor of rules in 'vectorContentRules' to apply the same actions
// the flavor of rules in 'vectorContentRules' to apply the same actions
// when creating the new rule.
// Thus, this new rule will join the 'vectorContentRules' set.
// Thus, this new rule will join the 'vectorContentRules' set.
if (self.state.vectorContentRules.rules.length) {
pushRuleVectorStateKind = self._contentRuleVectorStateKind(self.state.vectorContentRules.rules[0]);
}
@@ -636,38 +558,50 @@ module.exports = React.createClass({
// Create a push rule but disabled
_addDisabledPushRule: function(scope, kind, ruleId, body) {
var cli = MatrixClientPeg.get();
var deferred = q.defer();
cli.addPushRule(scope, kind, ruleId, body).done(function() {
cli.setPushRuleEnabled(scope, kind, ruleId, false).done(function() {
deferred.resolve();
}, function(err) {
deferred.reject(err);
});
}, function(err) {
deferred.reject(err);
return cli.addPushRule(scope, kind, ruleId, body).then(function() {
return cli.setPushRuleEnabled(scope, kind, ruleId, false);
});
return deferred.promise;
},
// Add a push rule server side according to the 'VectorPushRulesDefinitions' spec
_addOverridingVectorPushRule: function(vectorRuleId, vectorState) {
// Check if any legacy im.vector rules need to be ported to the new API
// for overriding the actions of default rules.
_portRulesToNewAPI: function(rulesets) {
var self = this;
var needsUpdate = [];
var cli = MatrixClientPeg.get();
// Create the rule as predefined
var ruleDefinition = VectorPushRulesDefinitions[vectorRuleId];
var body = {
conditions: ruleDefinition.conditions,
actions: ruleDefinition.vectorStateToActions[vectorState]
for (var kind in rulesets.global) {
var ruleset = rulesets.global[kind];
for (var i = 0; i < ruleset.length; ++i) {
var rule = ruleset[i];
if (rule.rule_id in LEGACY_RULES) {
console.log("Porting legacy rule", rule);
needsUpdate.push( function(kind, rule) {
return cli.setPushRuleActions(
'global', kind, LEGACY_RULES[rule.rule_id], portLegacyActions(rule.actions)
).then( function() {
return cli.deletePushRule('global', kind, rule.rule_id);
})
}(kind, rule));
}
}
}
if (needsUpdate.length > 0) {
// If some of the rules need to be ported then wait for the porting
// to happen and then fetch the rules again.
return q.allSettled(needsUpdate).then( function() {
return cli.getPushRules();
});
} else {
// Otherwise return the rules that we already have.
return rulesets;
}
return MatrixClientPeg.get().addPushRule('global', ruleDefinition.kind, vectorRuleId, body);
},
_refreshFromServer: function() {
var self = this;
MatrixClientPeg.get().getPushRules().done(function(rulesets) {
var self = this;
MatrixClientPeg.get().getPushRules().then(self._portRulesToNewAPI).done(function(rulesets) {
MatrixClientPeg.get().pushRules = rulesets;
// Get homeserver default rules and triage them by categories
@@ -690,8 +624,6 @@ module.exports = React.createClass({
// HS default rules
var defaultRules = {master: [], vector: {}, others: []};
// Push rules defined py Vector to override hs default rules
var vectorOverridingRules = {};
// Content/keyword rules
var contentRules = {on: [], on_but_disabled:[], loud: [], loud_but_disabled: [], other: []};
@@ -700,30 +632,18 @@ module.exports = React.createClass({
var r = rulesets.global[kind][i];
var cat = rule_categories[r.rule_id];
r.kind = kind;
if (r.rule_id[0] === '.') {
if (cat) {
if (cat === 'vector') {
// Remove disabled, useless actions
r.actions = r.actions.reduce(function(array, action){
if (action.value !== false) {
array.push(action);
}
return array;
},[]);
defaultRules.vector[r.rule_id] = r;
}
else {
defaultRules[cat].push(r);
}
if (r.rule_id[0] === '.') {
if (cat === 'vector') {
defaultRules.vector[r.rule_id] = r;
}
else if (cat === 'master') {
defaultRules.master.push(r);
}
else {
defaultRules['others'].push(r);
}
}
else if (r.rule_id.startsWith('im.vector')) {
vectorOverridingRules[r.rule_id] = r;
}
else if (kind === 'content') {
switch (self._contentRuleVectorStateKind(r)) {
case PushRuleVectorState.ON:
@@ -755,8 +675,8 @@ module.exports = React.createClass({
// whereas Matrix has a push rule per keyword.
// Vector can set the unique rule in ON, LOUD or OFF state.
// Matrix has enabled/disabled plus a combination of (highlight, sound) tweaks.
// The code below determines which set of user's content push rules can be
// The code below determines which set of user's content push rules can be
// displayed by the vector UI.
// Push rules that does not fit, ie defined by another Matrix client, ends
// in self.state.externalContentRules.
@@ -767,14 +687,14 @@ module.exports = React.createClass({
self.state.vectorContentRules = {
vectorState: PushRuleVectorState.LOUD,
rules: contentRules.loud
}
}
self.state.externalContentRules = [].concat(contentRules.loud_but_disabled, contentRules.on, contentRules.on_but_disabled, contentRules.other);
}
else if (contentRules.loud_but_disabled.length) {
self.state.vectorContentRules = {
vectorState: PushRuleVectorState.OFF,
rules: contentRules.loud_but_disabled
}
}
self.state.externalContentRules = [].concat(contentRules.on, contentRules.on_but_disabled, contentRules.other);
}
else if (contentRules.on.length) {
@@ -804,14 +724,14 @@ module.exports = React.createClass({
self.state.vectorPushRules = [];
var vectorRuleIds = [
'im.vector.rule.contains_display_name',
'.m.rule.contains_display_name',
'_keywords',
'im.vector.rule.room_one_to_one',
'im.vector.rule.room_message',
'im.vector.rule.invite_for_me',
'.m.rule.room_one_to_one',
'.m.rule.message',
'.m.rule.invite_for_me',
//'im.vector.rule.member_event',
'im.vector.rule.call',
'im.vector.rule.notices'
'.m.rule.call',
'.m.rule.suppress_notices'
];
for (var i in vectorRuleIds) {
var vectorRuleId = vectorRuleIds[i];
@@ -828,13 +748,7 @@ module.exports = React.createClass({
});
}
else {
var rule = vectorOverridingRules[vectorRuleId];
var isHSDefaultRule = false;
if (!rule) {
// If the rule is not defined, look at the hs default one
rule = defaultRules.vector[ruleDefinition.hsDefaultRuleId];
isHSDefaultRule = true;
}
var rule = defaultRules.vector[vectorRuleId];
// Translate the rule actions and its enabled value into vector state
var vectorState;
@@ -843,9 +757,9 @@ module.exports = React.createClass({
var state = PushRuleVectorState[stateKey];
var vectorStateToActions = ruleDefinition.vectorStateToActions[state];
if (!vectorStateToActions) {
if (vectorStateToActions === ACTION_DISABLED) {
// No defined actions means that this vector state expects a disabled default hs rule
if (isHSDefaultRule && rule.enabled === ruleDefinition.vectorStateToHsDefaultRuleEnabled[state]) {
if (rule.enabled === false) {
vectorState = state;
break;
}
@@ -853,14 +767,8 @@ module.exports = React.createClass({
else {
// The actions must match to the ones expected by vector state
if (JSON.stringify(rule.actions) === JSON.stringify(vectorStateToActions)) {
if (isHSDefaultRule) {
// In the case of a default hs push rule, the enabled value must also match
if (rule.enabled === ruleDefinition.vectorStateToHsDefaultRuleEnabled[state]) {
vectorState = state;
break;
}
}
else {
// And the rule must be enabled.
if (rule.enabled === true) {
vectorState = state;
break;
}
@@ -869,8 +777,8 @@ module.exports = React.createClass({
}
if (!vectorState) {
console.error("Cannot translate rule actions into Vector rule state. Rule: " + rule);
vectorState = PushRuleVectorState.OFF;
console.error("Cannot translate rule actions into Vector rule state. Rule: " + rule);
vectorState = PushRuleVectorState.OFF;
}
}
else {
@@ -882,12 +790,10 @@ module.exports = React.createClass({
"description" : ruleDefinition.description,
"rule": rule,
"vectorState": vectorState,
"isHSDefaultRule": isHSDefaultRule,
"hsDefaultRule": defaultRules.vector[ruleDefinition.hsDefaultRuleId]
});
});
}
}
// Build the rules not managed by Vector UI
var otherRulesDescriptions = {
'.m.rule.message': "Notify for all other messages/rooms",
@@ -898,7 +804,7 @@ module.exports = React.createClass({
for (var i in defaultRules.others) {
var rule = defaultRules.others[i];
var ruleDescription = otherRulesDescriptions[rule.rule_id];
// Show enabled default rules that was modified by the user
if (ruleDescription && rule.enabled && !rule.default) {
rule.description = ruleDescription;
@@ -911,41 +817,22 @@ module.exports = React.createClass({
});
});
},
_updatePushRuleActions: function(rule, actions, enabled) {
// Workaround for SYN-590 : Push rule update fails
// Remove the rule and recreate it with the new actions
var cli = MatrixClientPeg.get();
var deferred = q.defer();
cli.deletePushRule('global', rule.kind, rule.rule_id).done(function() {
cli.addPushRule('global', rule.kind, rule.rule_id, {
conditions: rule.conditions,
actions: actions,
pattern: rule.pattern
}).done(function() {
// Then, if requested, enabled or disabled the rule
if (undefined != enabled) {
cli.setPushRuleEnabled('global', rule.kind, rule.rule_id, enabled).done(function() {
deferred.resolve();
}, function(err) {
deferred.reject(err);
});
}
else {
deferred.resolve();
}
}, function(err) {
deferred.reject(err);
});
}, function(err) {
deferred.reject(err);
});
return deferred.promise;
_updatePushRuleActions: function(rule, actions, enabled) {
var cli = MatrixClientPeg.get();
return cli.setPushRuleActions(
'global', rule.kind, rule.rule_id, actions
).then( function() {
// Then, if requested, enabled or disabled the rule
if (undefined != enabled) {
return cli.setPushRuleEnabled(
'global', rule.kind, rule.rule_id, enabled
);
}
});
},
renderNotifRulesTableRow: function(title, className, pushRuleVectorState) {
return (
<tr key = {className}>
@@ -953,6 +840,13 @@ module.exports = React.createClass({
{title}
</th>
<th>
<input className= {className + "-" + PushRuleVectorState.OFF}
type="radio"
checked={ pushRuleVectorState === PushRuleVectorState.OFF }
onChange={ this.onNotifStateButtonClicked } />
</th>
<th>
<input className= {className + "-" + PushRuleVectorState.ON}
type="radio"
@@ -966,17 +860,10 @@ module.exports = React.createClass({
checked={ pushRuleVectorState === PushRuleVectorState.LOUD }
onChange={ this.onNotifStateButtonClicked } />
</th>
<th>
<input className= {className + "-" + PushRuleVectorState.OFF}
type="radio"
checked={ pushRuleVectorState === PushRuleVectorState.OFF }
onChange={ this.onNotifStateButtonClicked } />
</th>
</tr>
);
},
renderNotifRulesTableRows: function() {
var rows = [];
for (var i in this.state.vectorPushRules) {
@@ -986,7 +873,7 @@ module.exports = React.createClass({
return rows;
},
render: function() {
render: function() {
var self = this;
if (this.state.phase === this.phases.LOADING) {
@@ -1010,7 +897,7 @@ module.exports = React.createClass({
</div>
<div className="mx_UserNotifSettings_labelCell">
<label htmlFor="enableNotifications">
Enable notifications
Enable notifications for this account
</label>
</div>
</div>
@@ -1019,7 +906,7 @@ module.exports = React.createClass({
// When enabled, the master rule inhibits all existing rules
// So do not show all notification settings
if (this.state.masterPushRule.enabled) {
if (this.state.masterPushRule && this.state.masterPushRule.enabled) {
return (
<div>
{masterPushRuleDiv}
@@ -1060,7 +947,7 @@ module.exports = React.createClass({
{ externalRules }
</ul>
</div>
);
);
}
return (
@@ -1110,9 +997,9 @@ module.exports = React.createClass({
<thead>
<tr>
<th width="55%"></th>
<th width="15%">Off</th>
<th width="15%">On</th>
<th width="15%">Loud</th>
<th width="15%">Off</th>
</tr>
</thead>
<tbody>
@@ -1124,7 +1011,7 @@ module.exports = React.createClass({
</div>
{ advancedSettings }
</div>
</div>

View File

@@ -63,7 +63,12 @@ input[type=text]:focus, textarea:focus {
flexbox to adapt to the new size and cause the view to keep growing.
*/
.gm-scrollbar-container .gm-scroll-view {
position: absolute;
position: absolute;
}
/* hack to avoid accidental click-throughs if you miss the narrow scrollbar */
.gm-scrollbar.-vertical {
border-left: 6px solid transparent;
}
.mx_ContextualMenu_background {

View File

@@ -18,7 +18,7 @@ limitations under the License.
width: 960px;
margin-left: auto;
margin-right: auto;
color: #4a4a4a;
color: #4a4a4a;
}
.mx_CreateRoom input,

View File

@@ -31,7 +31,7 @@ limitations under the License.
display: -moz-box;
display: -ms-flexbox;
display: -webkit-flex;
display: flex;
display: flex;
flex-direction: column;
-webkit-flex-direction: column;

View File

@@ -14,12 +14,12 @@
text-align: center;
}
.mx_RoomStatusBar_placeholderIndicator {
.mx_RoomStatusBar_placeholderIndicator {
color: #4a4a4a;
opacity: 0.5;
}
.mx_RoomStatusBar_scrollDownIndicator {
.mx_RoomStatusBar_scrollDownIndicator {
cursor: pointer;
}

View File

@@ -121,7 +121,7 @@ limitations under the License.
.mx_RoomView_messageListWrapper {
max-width: 960px;
margin: auto;
min-height: 100%;
display: -webkit-box;
@@ -137,6 +137,11 @@ limitations under the License.
-webkit-justify-content: flex-end;
}
.mx_RoomView_searchResultsPanel .mx_RoomView_messageListWrapper {
justify-content: flex-start;
-webkit-justify-content: flex-start;
}
.mx_RoomView_MessageList {
width: 100%;
list-style-type: none;
@@ -260,4 +265,5 @@ hr.mx_RoomView_myReadMarker {
color: #fff;
font-weight: bold;
padding: 6px 0;
cursor: pointer;
}

View File

@@ -32,12 +32,12 @@
margin-right: 10px;
position: relative;
opacity: 0.6;
cursor: pointer;
cursor: pointer;
z-index: 1;
}
.mx_UploadBar_uploadBytes {
float: right;
float: right;
margin-top: 5px;
margin-right: 30px;
color: #76cfa6;

View File

@@ -26,7 +26,7 @@ limitations under the License.
display: -webkit-flex;
display: flex;
flex-direction: column;
-webkit-flex-direction: column;
-webkit-flex-direction: column;
}
.mx_UserSettings .mx_RoomHeader {
@@ -50,7 +50,7 @@ limitations under the License.
-webkit-flex: 1 1 0;
flex: 1 1 0;
overflow-y: auto;
overflow-y: auto;
}
.mx_UserSettings_spinner {

View File

@@ -60,6 +60,14 @@ limitations under the License.
margin-bottom: 14px;
}
.mx_Login_fieldLabel {
margin-top: -10px;
margin-left: 8px;
margin-bottom: 14px;
font-size: 13px;
opacity: 0.8;
}
.mx_Login_submit {
margin-top: 35px;
margin-bottom: 24px;
@@ -77,7 +85,8 @@ limitations under the License.
opacity: 0.8;
}
.mx_Login_checkbox {
.mx_Login_checkbox,
.mx_Login_radio {
margin-right: 10px;
}

View File

@@ -47,7 +47,7 @@ limitations under the License.
top: 0px;
right: 6px;
}
.mx_EntityTile_name {
display: table-cell;
vertical-align: middle;

View File

@@ -29,6 +29,7 @@ limitations under the License.
float: left;
position: relative;
top: 0px;
cursor: pointer;
}
.mx_EventTile_continuation {
@@ -42,6 +43,7 @@ limitations under the License.
margin-bottom: 4px;
display: block;
overflow-y: hidden;
cursor: pointer;
}
.mx_EventTile .mx_MessageTimestamp {
@@ -55,9 +57,16 @@ limitations under the License.
margin-right: 95px;
}
/* all the overflow-y: hidden; are to trap Zalgos -
but they introduce an implicit overflow-x: auto.
so make that explicitly hidden too to avoid random
horizontal scrollbars occasionally appearing, like in
https://github.com/vector-im/vector-web/issues/1154
*/
.mx_EventTile_content {
display: block;
overflow-y: hidden;
overflow-x: hidden;
}
/* Various markdown overrides */
@@ -70,6 +79,15 @@ limitations under the License.
font-size: 15px;
}
/* have to use overlay rather than auto otherwise Linux and Windows
Chrome gets very confused about vertical spacing:
https://github.com/vector-im/vector-web/issues/754
*/
.mx_EventTile_content .markdown-body pre {
overflow-x: overlay;
overflow-y: visible;
}
.mx_EventTile_content .markdown-body h1,
.mx_EventTile_content .markdown-body h2,
.mx_EventTile_content .markdown-body h3,
@@ -90,10 +108,10 @@ limitations under the License.
/* end of overrides */
/* this is used for the tile for the event which is selected via the URL.
* TODO: ultimately we probably want some transition on here.
/* this is used for the tile for the event which is selected via the URL.
* TODO: ultimately we probably want some transition on here.
*/
.mx_EventTile_selected {
.mx_EventTile_selected {
border-left: #76cfa6 5px solid;
margin-left: 53px;
padding-left: 7px;
@@ -110,7 +128,7 @@ limitations under the License.
.mx_EventTile_searchHighlight a {
background-color: #76cfa6;
color: #fff;
color: #fff;
}
.mx_EventTile_sending {
@@ -158,7 +176,7 @@ limitations under the License.
.mx_EventTile_editButton {
position: absolute;
display: inline-block;
visibility: hidden;
visibility: hidden;
}
.mx_EventTile:hover .mx_EventTile_editButton {

View File

@@ -46,7 +46,7 @@ limitations under the License.
}
.mx_MemberInfo_profileField {
font-color: #999999;
font-color: #999999;
font-size: 13px;
position: relative;
background-color: #fff;

View File

@@ -30,6 +30,11 @@ limitations under the License.
-webkit-flex-direction: column;
}
.mx_MemberList .mx_Spinner {
flex: 0;
-webkit-flex: 0;
}
.mx_MemberList_chevron {
position: absolute;
right: 35px;
@@ -91,12 +96,12 @@ limitations under the License.
padding-left: 3px;
padding-right: 12px;
margin-top: 8px;
margin-bottom: 4px;
margin-bottom: 4px;
}
/* we have to have display: table in order for the horizontal wrapping to work */
.mx_MemberList_wrapper {
display: table;
display: table;
table-layout: fixed;
width: 100%;
}

View File

@@ -28,7 +28,7 @@ limitations under the License.
-webkit-align-items: center;
align-items: center;
display: -webkit-box;
display: -moz-box;
display: -ms-flexbox;
@@ -71,7 +71,7 @@ limitations under the License.
cursor: pointer;
/*
/*
-webkit-flex: 0 0 90px;
flex: 0 0 90px;
*/
@@ -203,12 +203,12 @@ limitations under the License.
float: left;
max-height: 42px;
color: #454545;
font-weight: 300;
font-weight: 300;
margin-left: 19px;
margin-right: 16px;
overflow: hidden;
text-overflow: ellipsis;
border-bottom: 1px solid transparent;
border-bottom: 1px solid transparent;
}
.mx_RoomHeader_avatar {
@@ -218,6 +218,10 @@ limitations under the License.
vertical-align: middle;
}
.mx_RoomHeader_avatar .mx_BaseAvatar_image {
object-fit: cover;
}
.mx_RoomHeader_avatarPicker_edit {
position: absolute;
margin-left: 16px;

View File

@@ -23,7 +23,7 @@ limitations under the License.
flex-direction: column;
-webkit-flex-direction: column;
justify-content: center;
-webkit-justify-content: center;
@@ -54,3 +54,15 @@ limitations under the License.
text-decoration: underline;
cursor: pointer;
}
.mx_RoomPreviewBar_warning {
display: -webkit-flex;
display: flex;
-webkit-align-items: center;
align-items: center;
padding: 8px;
}
.mx_RoomPreviewBar_warningIcon {
padding: 12px;
}

View File

@@ -107,7 +107,7 @@ limitations under the License.
.mx_RoomSettings .mx_RoomSettings_alias {
max-width: 400px;
margin-bottom: 16px;
/*
/*
commented out so margin applies
display: table-cell; */
}
@@ -130,6 +130,13 @@ limitations under the License.
visibility: visible;
}
.mx_RoomSettings_warning {
color: #ff0064;
font-weight: bold;
margin-top: 8px;
margin-bottom: 8px;
}
.mx_RoomSettings_editable {
border: 0px;
border-bottom: 1px solid #c7c7c7;

View File

@@ -39,7 +39,7 @@ limitations under the License.
vertical-align: middle;
overflow: hidden;
text-overflow: ellipsis;
padding-right: 16px;
padding-right: 16px;
color: rgba(69, 69, 69, 0.8);
}
@@ -70,7 +70,7 @@ limitations under the License.
width: 26px;
}
.mx_RoomTile_badge {
.mx_RoomTile_badge {
background-color: #76cfa6;
color: #fff;
border-radius: 26px;
@@ -84,7 +84,7 @@ limitations under the License.
*/
/*
.mx_RoomTile_badge {
.mx_RoomTile_badge {
background-color: #ff0064;
border: 3px solid #fff;
border-radius: 16px;
@@ -103,7 +103,7 @@ limitations under the License.
left: 0px;
top: 5px;
bottom: 5px;
}
}
.mx_RoomTile_unreadNotify .mx_RoomTile_badge {
background-color: #454545;

View File

@@ -51,13 +51,13 @@ limitations under the License.
flex: 1;
-webkit-flex: 1;
overflow-y: auto;
overflow-y: auto;
}
.mx_SearchableEntityList_list {
display: table;
table-layout: fixed;
width: 100%;
width: 100%;
}
.mx_SearchableEntityList_list .mx_EntityTile_chevron {
@@ -67,7 +67,7 @@ limitations under the License.
.mx_SearchableEntityList_hrWrapper {
width: 100%;
flex: 0 0 auto;
-webkit-flex: 0 0 auto;
-webkit-flex: 0 0 auto;
}
.mx_SearchableEntityList hr {

View File

@@ -22,22 +22,22 @@ limitations under the License.
border-bottom: 1px solid #eee;
}
.mx_TopUnreadMessagesBar_scrollUp {
.mx_TopUnreadMessagesBar_scrollUp {
display: inline;
cursor: pointer;
}
.mx_TopUnreadMessagesBar_scrollUp img {
.mx_TopUnreadMessagesBar_scrollUp img {
padding-left: 10px;
padding-right: 31px;
vertical-align: middle;
}
.mx_TopUnreadMessagesBar_scrollUp span {
.mx_TopUnreadMessagesBar_scrollUp span {
opacity: 0.5;
}
.mx_TopUnreadMessagesBar_close {
.mx_TopUnreadMessagesBar_close {
float: right;
padding-right: 14px;
padding-top: 3px;

View File

@@ -35,7 +35,7 @@ limitations under the License.
}
.mx_LeftPanel_callView {
}
.mx_LeftPanel .mx_RoomList_scrollbar {
@@ -48,7 +48,7 @@ limitations under the License.
-webkit-flex: 1 1 0;
flex: 1 1 0;
overflow-y: auto;
overflow-y: auto;
}
.mx_LeftPanel .mx_BottomLeftMenu {

View File

@@ -49,7 +49,7 @@ limitations under the License.
.mx_RightPanel_headerButton {
cursor: pointer;
display: table-cell;
vertical-align: middle;
vertical-align: middle;
padding-left: 15px;
padding-right: 15px;
position: relative;
@@ -72,7 +72,7 @@ limitations under the License.
position: absolute;
top: 4px;
left: 28px;
font-size: 12px;
font-size: 12px;
background-color: #76cfa6;
color: #fff;
font-weight: bold;

View File

@@ -26,21 +26,21 @@ limitations under the License.
display: -moz-box;
display: -ms-flexbox;
display: -webkit-flex;
display: flex;
display: flex;
flex-direction: column;
-webkit-flex-direction: column;
}
.mx_RoomDirectory_list {
-webkit-flex: 1;
-webkit-flex: 1;
flex: 1;
display: -webkit-box;
display: -moz-box;
display: -ms-flexbox;
display: -webkit-flex;
display: flex;
display: flex;
flex-direction: column;
-webkit-flex-direction: column;
@@ -59,7 +59,7 @@ limitations under the License.
.mx_RoomDirectory_tableWrapper {
overflow-y: auto;
-webkit-flex: 1 1 0;
-webkit-flex: 1 1 0;
flex: 1 1 0;
}
@@ -116,6 +116,7 @@ limitations under the License.
.mx_RoomDirectory_roomMemberCount {
text-align: right;
width: 100px;
padding-right: 10px;
}
.mx_RoomDirectory_table tr {

View File

@@ -52,7 +52,7 @@ limitations under the License.
.mx_SearchBar_searching img {
animation: pulsate 0.5s ease-out;
animation-iteration-count: infinite;
animation-iteration-count: infinite;
}
.mx_SearchBar_button {
@@ -77,7 +77,7 @@ limitations under the License.
background-color: #fff;
color: #76CFA6;
border: #76CFA6 1px solid;
}
}
.mx_SearchBar_cancel {
padding-left: 14px;

View File

@@ -184,7 +184,7 @@ function loadApp() {
}} />,
document.getElementById('matrixchat')
);
}
}
}
loadApp();

Binary file not shown.

Binary file not shown.