Compare commits

...

107 Commits

Author SHA1 Message Date
David Baker
4ead2f338d v0.9.8-rc.3 2017-04-11 18:50:21 +01:00
David Baker
55ec7dcebc Prepare changelog for v0.9.8-rc.3 2017-04-11 18:50:20 +01:00
David Baker
8587df1dd9 React SDK rc.4 2017-04-11 18:49:27 +01:00
David Baker
d5b1db064f Merge remote-tracking branch 'origin/develop' into release-v0.9.8 2017-04-11 18:48:55 +01:00
Matthew Hodgson
b26c460f13 shrink the redacted tear 2017-04-10 23:22:25 +01:00
David Baker
3fa8460ed7 Merge pull request #3598 from vector-im/dbkr/clear_cache_button_electron
Make the clear cache button work on desktop
2017-04-10 17:56:49 +01:00
David Baker
7f6d9a625d Make the clear cache button work on desktop
Implement reload in Platforms to support
https://github.com/matrix-org/matrix-react-sdk/pull/798

Fixes https://github.com/vector-im/riot-web/issues/3597
2017-04-10 17:40:09 +01:00
David Baker
0b266d2e83 v0.9.8-rc.2 2017-04-10 16:56:41 +01:00
David Baker
7907d41ea8 Prepare changelog for v0.9.8-rc.2 2017-04-10 16:56:40 +01:00
David Baker
32c6482dcf Bump js-sdk & react-sdk versions 2017-04-10 16:55:27 +01:00
David Baker
ea0c41a9f8 Merge remote-tracking branch 'origin/develop' into release-v0.9.8 2017-04-10 16:55:02 +01:00
David Baker
a1cb566761 Bump electron version 2017-04-10 16:01:21 +01:00
Luke Barnard
01a96d92f4 Merge pull request #3596 from vector-im/luke/fix-redacted-bg
Redacted events bg: black lozenge -> torn paper
2017-04-10 15:59:41 +01:00
Luke Barnard
0b1745bceb Redacted events bg: black lozenge -> torn paper 2017-04-10 15:49:40 +01:00
David Baker
7d203f40cd Merge pull request #3594 from vector-im/rav/send_app_to_rageshake
Add 'app' parameter to rageshake report
2017-04-10 15:25:55 +01:00
Richard van der Hoff
b8b74402c1 Add 'app' parameter to rageshake report 2017-04-10 15:07:43 +01:00
David Baker
08ee93a57b v0.9.8-rc.1 2017-04-07 17:29:12 +01:00
David Baker
bced608c48 Roll back version number to try again 2017-04-07 17:28:32 +01:00
David Baker
c576e07c85 v0.9.8-rc.1 2017-04-07 17:19:08 +01:00
David Baker
cc87135b28 Prepare changelog for v0.9.8-rc.1 2017-04-07 17:19:08 +01:00
David Baker
a63eb2621b Prerelease js-sdk & react-sdk 2017-04-07 17:12:48 +01:00
David Baker
42e317dab8 Merge pull request #3578 from vector-im/dbkr/indexeddb_webworker
Add support for indexeddb sync in webworker
2017-04-07 16:17:39 +01:00
David Baker
ec870039bf Don't use endsWith as it'll break on old node
It's a lodash template though, so use lodash
2017-04-07 14:57:02 +01:00
David Baker
b65466bc4f Use dedicated indexeddb worker import 2017-04-07 14:41:41 +01:00
David Baker
515b57ba12 Update for rename of worker 2017-04-07 11:23:14 +01:00
Luke Barnard
4d4da0d7ca Merge pull request #3574 from vector-im/luke/feature-clickable-emotes
Add CSS to make Emote sender cursor : pointer
2017-04-06 15:56:45 +01:00
Luke Barnard
778e7dcab0 Add CSS to make Emote sender cursor : pointer 2017-04-06 14:11:37 +01:00
David Baker
fd5e94dfad Merge pull request #3565 from vector-im/rav/remove_rageshake
Remove rageshake server
2017-04-06 12:21:33 +01:00
David Baker
f187a359e6 Add support for indexeddb sync in webworker 2017-04-06 11:15:14 +01:00
Luke Barnard
579e70e967 Merge pull request #3566 from vector-im/luke/clarify-unread-msg-top-banner
Adjust CSS for matrix-org/matrix-react-sdk#789
2017-04-04 16:45:38 +01:00
Luke Barnard
3407f66e82 Adjust CSS for matrix-org/matrix-react-sdk#789 2017-04-04 16:36:05 +01:00
Richard van der Hoff
8707cca7bc Remove rageshake server
This is now at https://github.com/matrix-org/rageshake
2017-04-04 16:29:12 +01:00
Matthew Hodgson
e40c6905dd more instructions 2017-04-01 13:33:24 +01:00
Matthew Hodgson
84a0ef9695 spell out that if you're on develop you need to keep your deps up-to-date 2017-04-01 13:25:16 +01:00
Matthew Hodgson
546e2ab30b bump emojione 2017-04-01 01:28:44 +01:00
Luke Barnard
6380f1a24a Merge pull request #3537 from vector-im/luke/fix-flaky-tests-maybe
Fix tests to reflect recent changes
2017-03-29 17:32:31 +02:00
Luke Barnard
e40d3852ff Fix tests to reflect recent changes
This is an attempt to reduce flakiness (see https://github.com/matrix-org/matrix-react-sdk/pull/781 also)
2017-03-29 16:07:11 +01:00
David Baker
e248a7f029 Merge pull request #3536 from vector-im/luke/fix-people-unstable-ordering
Do not assume getTs will return comparable integer
2017-03-29 14:40:50 +01:00
Luke Barnard
91892ec18b Do not assume getTs will return comparable integer
Fixes https://github.com/vector-im/riot-web/issues/3529. In the worst case, tsOfNewestEvent will return MAX_SAFE_INTEGER, instead of undefined, as may be the case of some events that were redacted and persisted in indexDB before changes were made to how events are redacted locally. (The important change is that events are now not stripped of their `origin_server_ts`).
2017-03-29 14:30:08 +01:00
Richard van der Hoff
ff2a9f4b20 Merge pull request #3535 from vector-im/dbkr/rename_perf
Rename ReactPerf to Perf
2017-03-29 11:53:57 +02:00
David Baker
a3040e22d3 Rename ReactPerf to Perf
As this makes it work out of the box with react-perf chrome
extension (which doesn't do a whole lot other than save you having
to remember the commands, but is still quite nice).
2017-03-29 10:38:46 +01:00
David Baker
2480831e2f Merge pull request #3530 from vector-im/dbkr/email_notifs_only_to_email_addresses
Don't show phone number as target for email notifs
2017-03-28 16:40:13 +01:00
David Baker
c72a49d229 More equalses 2017-03-28 16:34:35 +01:00
David Baker
83b7f94609 Don't show phone number as target for email notifs
Fixes https://github.com/vector-im/riot-web/issues/3518
2017-03-28 16:24:54 +01:00
Luke Barnard
8b50ed8006 Merge pull request #3458 from vector-im/luke/fix-people-section2
Fix people section again
2017-03-27 15:52:15 +02:00
Matthew Hodgson
d696196d72 fix https://github.com/vector-im/riot-web/issues/3348 2017-03-27 12:39:58 +01:00
Luke Barnard
abc5b2d5f4 UI delay in UI 2017-03-27 09:44:33 +01:00
Matthew Hodgson
f4134167a0 Merge pull request #3479 from t3chguy/t3chguy/dark-theme-invert-inconsistency-fix
dark theme invert inconsistent across browsers
2017-03-25 14:06:01 +00:00
David Baker
bc67b1c87e Merge pull request #3451 from vector-im/dbkr/add_msisdn
CSS for adding phone number in UserSettings
2017-03-24 10:53:25 +00:00
David Baker
4326d7a182 Merge remote-tracking branch 'origin/develop' into dbkr/add_msisdn 2017-03-21 13:45:16 +00:00
David Baker
8e3a68dbdc Merge pull request #3426 from vector-im/dbkr/msisdn_signin_2
Support for phone number registration/signin, mk2
2017-03-21 13:43:49 +00:00
Michael Telatynski
05148b6e93 Add contributor to listing
Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>
2017-03-20 13:31:26 +00:00
Michael Telatynski
89447b7bfc Explicitly specify level of inversion to avoid inconsistent defaults with webkit-filter/filter
Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>
2017-03-20 13:31:00 +00:00
Matthew Hodgson
af122172f1 Merge pull request #3470 from kfatehi/277-confirmredact
Confirm redactions with a dialog
2017-03-19 02:36:01 +00:00
Keyvan Fatehi
a9ed2e20cb Confirm redactions with a dialog
Closes #277
Closes #1805

Signed-off-by: Keyvan Fatehi <keyvanfatehi@gmail.com>
2017-03-18 18:58:24 -07:00
Luke Barnard
be02ac3bc6 Fix people section again
- Alter CSS due to removed mx_RoomDropTarget_avatar. The avatar was removed because it didn't particularly add anything and we needed space for "Drop here to tag as direct chat", which is quite long.
 - Use guessAndSetDMRoom as a convenience method for guessing the DM member and setting the state.
 - Do evil hacks to make DNDRoomTile do dragging of RoomTiles to and from the People section. Dragging a DM to and from Rooms/Favourites/Low Priority now works as one would expect. This is still not ideal however because edge cases exist where you have more than one tag set and then you drag a DM from "Favourites" to "Rooms" and the tile ends up in "People". This would require setting multiple tags, and breaks the 1-1 mapping between tags and sections even further. Ultimately the UI needs a rework.
2017-03-17 12:14:44 +00:00
David Baker
e3e2e3a56c Merge pull request #3453 from vector-im/luke/display-redactions-better
Better CSS for redactions
2017-03-16 17:12:11 +00:00
Luke Barnard
49be954d31 Better CSS for redactions
See https://github.com/vector-im/riot-web/issues/3390

Also: The "Redact" option in the MessageContextMenu no longer appears for redacted events.
2017-03-16 17:03:16 +00:00
David Baker
ad306dd999 CSS for add phone number in UserSettings 2017-03-16 14:59:13 +00:00
David Baker
2efcf7023f Merge pull request #3448 from vector-im/luke/fix-room-list-people
Fix the people section
2017-03-16 13:19:45 +00:00
Luke Barnard
f8298b2482 Fix the people section
This does two things:
 - Fixes an incorrect import that was causing Direct Chat toggle to not be editable https://github.com/vector-im/riot-web/issues/3355
 - Use props.list in RoomSubList when calculating whether to show IncomingCallDialog. Fixes https://github.com/vector-im/riot-web/issues/2956
2017-03-16 11:36:57 +00:00
David Baker
c4d3d66f31 Support for phone number registration/signin, mk2
Changes from https://github.com/vector-im/riot-web/pull/3381
2017-03-14 14:45:54 +00:00
Luke Barnard
1ade7a711c Merge pull request #3395 from vector-im/luke/merge-RoomTile-context-menus
Merge the two RoomTile context menus into one
2017-03-14 14:19:41 +00:00
Luke Barnard
32b9ee7f6f Copyright 2017-03-14 14:07:10 +00:00
Luke Barnard
e4c155a881 Merge branch 'develop' into luke/merge-RoomTile-context-menus
Conflicts:
	src/components/views/context_menus/RoomTagContextMenu.js
2017-03-14 14:01:47 +00:00
David Baker
4e6541b404 Merge pull request #3385 from vector-im/luke/fix-screen-after-login
Refactor screen set after login
2017-03-14 13:47:55 +00:00
Matthew Hodgson
df22c90016 fix kick dialog CSS 2017-03-13 00:47:20 +00:00
Matthew Hodgson
ffba088192 fix CSS for ChatCreateOrReuseDialog 2017-03-13 00:03:53 +00:00
Matthew Hodgson
d639eb1049 beautify all error msgs 2017-03-12 23:26:26 +00:00
Matthew Hodgson
0a0293d8fb fix focus on cancel button 2017-03-12 20:13:53 +00:00
Matthew Hodgson
4ad825e4fe fix up cancelbutton CSS 2017-03-12 20:04:07 +00:00
Matthew Hodgson
611bb3a857 beautiful error on roomdirectory fail 2017-03-12 20:04:02 +00:00
Richard van der Hoff
e5b3ec83b3 Revert "Support for phone number registration / signin (#3381)"
This reverts commit 271fedd1e9.

This breaks against the current synapse release. We need to think more
carefully about backwards compatibility.
2017-03-09 20:41:11 +00:00
Luke Barnard
3dc45886f7 Merge the two RoomTile context menus into one 2017-03-09 17:05:51 +00:00
Tom Lant
927d305ed9 Fixing triage markdown as per #3382 2017-03-09 14:36:56 +00:00
David Baker
271fedd1e9 Support for phone number registration / signin (#3381)
* WIP msisdn signin (css)

* Changed how highlights are done

to support keyboard based navigation

* Support for new InteractiveAuth registration

* CSS for msisdn auth entry component

* CSS tweaks for msisdn login

* Fix tests
2017-03-09 10:58:58 +00:00
David Baker
23422fdb86 Merge pull request #3379 from vector-im/luke/css-visible-redactions
CSS for redacted EventTiles
2017-03-09 10:09:31 +00:00
Luke Barnard
7ff2871ad5 const 2017-03-09 10:04:15 +00:00
Luke Barnard
cbc31a6c41 Remove redundant thing 2017-03-09 10:03:23 +00:00
Luke Barnard
6a1118218b Merge pull request #3340 from vector-im/luke/css-rts-fix-welcome-pages-safari
Height:100% for welcome pages on Safari
2017-03-08 17:07:53 +00:00
Luke Barnard
eddf33a689 Refactor screen set after login 2017-03-08 14:57:13 +00:00
Luke Barnard
08852c6174 Merge pull request #3376 from vector-im/luke/refactor-room-tile
`view_room` dispatch from `onClick` RoomTile
2017-03-07 16:20:31 +00:00
Luke Barnard
2bf96d4887 Merge pull request #3350 from vector-im/luke/css-statusbar-v-balance
Hide statusAreaBox_line entirely when inCall
2017-03-07 13:29:56 +00:00
Luke Barnard
9d96baa613 Alter comments on height: auto
Having tested Riot with the middlePanel having a height of 100%, it seems to be OK.
2017-03-07 10:22:45 +00:00
Luke Barnard
a7db42d184 CSS for redacted EventTiles 2017-03-07 09:21:50 +00:00
Luke Barnard
3d67234372 view_room dispatch from onClick RoomTile
So that RoomTile does less, and if other things should happen onClick, they happen in the same place as the `view_room` for clarity.
2017-03-06 17:55:12 +00:00
Luke Barnard
b1f14ba979 Merge pull request #3351 from vector-im/luke/css-spinner-height
Set padding-bottom: 0px for .mx_Dialog spinner
2017-03-03 18:01:08 +00:00
Luke Barnard
a1462946cd padding: 0px 2017-03-03 13:54:26 +00:00
David Baker
ae27667f48 Merge pull request #3333 from vector-im/dbkr/register_ui_auth
Support InteractiveAuth based registration
2017-03-03 13:37:46 +00:00
David Baker
c6da4d93f1 Merge pull request #3334 from turt2live/travis/notifs
Expose notification option for username/MXID
2017-03-02 18:26:53 +00:00
Luke Barnard
024fea0687 Set padding-bottom: 0px for .mx_Dialog spinner
This was causing https://github.com/vector-im/riot-web/issues/3226
2017-03-02 17:39:02 +00:00
Luke Barnard
cfbcffac5a Hide statusAreaBox_line entirely when inCall
This is to keep things vertically balanced.

Fixes https://github.com/vector-im/riot-web/issues/3269
2017-03-02 16:57:52 +00:00
Luke Barnard
640c486bde Merge pull request #3190 from vector-im/luke/mels-toggle-scss
Float the toggle in the top right of MELS
2017-03-02 15:19:57 +00:00
Luke Barnard
66e93c8a8c Fix for vector-im/riot-web#3298 - height:100% for welcome pages on Safari 2017-03-01 10:04:48 +00:00
Matthew Hodgson
8a7ec27dc7 fix whitespace in urlpreview title 2017-02-28 00:16:43 +00:00
turt2live
9afbe8e3fc Change wording in notification description 2017-02-27 15:47:21 -07:00
turt2live
9b42fbe42f Expose notification option for username/MXID
For those unfortunate people that get pinged constantly.
2017-02-27 15:32:58 -07:00
Matthew Hodgson
ae145ff32e oops, fix #3270 properly 2017-02-27 22:25:22 +00:00
David Baker
a8e99109b1 Support InteractiveAuth based registration
Passes in a function to make a register URL rather than just
passing in the URL base
2017-02-24 11:45:28 +00:00
Richard van der Hoff
bb4d8ee3e8 Merge pull request #3311 from vector-im/rav/rageshake_culling
More aggressive rageshake log culling
2017-02-23 14:38:36 +00:00
Richard van der Hoff
038f5767f2 Add a comment 2017-02-23 14:37:46 +00:00
Richard van der Hoff
e2cec7b69c More aggressive rageshake log culling
Also bump the client-side timeout on the upload from 3 mins to 5 mins, to see
if it helps people on slower connections.
2017-02-23 14:22:03 +00:00
Matthew Hodgson
6690df1203 Merge pull request #3282 from Half-Shot/develop
Don't overflow directory network options
2017-02-22 01:13:14 +00:00
Aviral Dasgupta
c21cdf5b02 add .editorconfig
Signed-off-by: Aviral Dasgupta <me@aviraldg.com>
2017-02-21 23:38:03 +05:30
Will Hunt
37f320c4a4 Don't overflow directory network options 2017-02-21 12:25:29 +00:00
David Baker
feb8115d24 Desktop instructions: npm run build, not dist
Clarify that you only need to run build rather than dist to run
the electron app.

Hopefully satisfies: https://github.com/vector-im/riot-web/pull/3237
2017-02-20 10:32:14 +00:00
Luke Barnard
36b08fece7 Float the toggle in the top right of MELS
This is so that it stays put when the MELS is toggled.

Added style for a line that appears below "collapse" to indicate start of events.

Not possible to put "collapse" next to the expanded events because of read receipts.
2017-02-09 15:17:03 +00:00
54 changed files with 1269 additions and 909 deletions

23
.editorconfig Normal file
View File

@@ -0,0 +1,23 @@
# Copyright 2017 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.
root = true
[*]
charset=utf-8
end_of_line = lf
insert_final_newline = true
indent_style = space
indent_size = 4
trim_trailing_whitespace = true

View File

@@ -10,3 +10,6 @@ include:
* Florent VIOLLEAU (https://github.com/floviolleau) <floviolleau at gmail dot com>
Improve README.md for a better understanding of installation instructions
* Michael Telatynski (https://github.com/t3chguy)
Improved consistency of inverted elements in dark theme across browsers

View File

@@ -1,3 +1,116 @@
Changes in [0.9.8-rc.3](https://github.com/vector-im/riot-web/releases/tag/v0.9.8-rc.3) (2017-04-11)
====================================================================================================
[Full Changelog](https://github.com/vector-im/riot-web/compare/v0.9.8-rc.2...v0.9.8-rc.3)
* Make the clear cache button work on desktop
[\#3598](https://github.com/vector-im/riot-web/pull/3598)
Changes in [0.9.8-rc.2](https://github.com/vector-im/riot-web/releases/tag/v0.9.8-rc.2) (2017-04-10)
====================================================================================================
[Full Changelog](https://github.com/vector-im/riot-web/compare/v0.9.8-rc.1...v0.9.8-rc.2)
* Redacted events bg: black lozenge -> torn paper
[\#3596](https://github.com/vector-im/riot-web/pull/3596)
* Add 'app' parameter to rageshake report
[\#3594](https://github.com/vector-im/riot-web/pull/3594)
Changes in [0.9.8-rc.1](https://github.com/vector-im/riot-web/releases/tag/v0.9.8-rc.1) (2017-04-07)
====================================================================================================
[Full Changelog](https://github.com/vector-im/riot-web/compare/v0.9.7...v0.9.8-rc.1)
* Add support for indexeddb sync in webworker
[\#3578](https://github.com/vector-im/riot-web/pull/3578)
* Add CSS to make Emote sender cursor : pointer
[\#3574](https://github.com/vector-im/riot-web/pull/3574)
* Remove rageshake server
[\#3565](https://github.com/vector-im/riot-web/pull/3565)
* Adjust CSS for matrix-org/matrix-react-sdk#789
[\#3566](https://github.com/vector-im/riot-web/pull/3566)
* Fix tests to reflect recent changes
[\#3537](https://github.com/vector-im/riot-web/pull/3537)
* Do not assume getTs will return comparable integer
[\#3536](https://github.com/vector-im/riot-web/pull/3536)
* Rename ReactPerf to Perf
[\#3535](https://github.com/vector-im/riot-web/pull/3535)
* Don't show phone number as target for email notifs
[\#3530](https://github.com/vector-im/riot-web/pull/3530)
* Fix people section again
[\#3458](https://github.com/vector-im/riot-web/pull/3458)
* dark theme invert inconsistent across browsers
[\#3479](https://github.com/vector-im/riot-web/pull/3479)
* CSS for adding phone number in UserSettings
[\#3451](https://github.com/vector-im/riot-web/pull/3451)
* Support for phone number registration/signin, mk2
[\#3426](https://github.com/vector-im/riot-web/pull/3426)
* Confirm redactions with a dialog
[\#3470](https://github.com/vector-im/riot-web/pull/3470)
* Better CSS for redactions
[\#3453](https://github.com/vector-im/riot-web/pull/3453)
* Fix the people section
[\#3448](https://github.com/vector-im/riot-web/pull/3448)
* Merge the two RoomTile context menus into one
[\#3395](https://github.com/vector-im/riot-web/pull/3395)
* Refactor screen set after login
[\#3385](https://github.com/vector-im/riot-web/pull/3385)
* CSS for redacted EventTiles
[\#3379](https://github.com/vector-im/riot-web/pull/3379)
* Height:100% for welcome pages on Safari
[\#3340](https://github.com/vector-im/riot-web/pull/3340)
* `view_room` dispatch from `onClick` RoomTile
[\#3376](https://github.com/vector-im/riot-web/pull/3376)
* Hide statusAreaBox_line entirely when inCall
[\#3350](https://github.com/vector-im/riot-web/pull/3350)
* Set padding-bottom: 0px for .mx_Dialog spinner
[\#3351](https://github.com/vector-im/riot-web/pull/3351)
* Support InteractiveAuth based registration
[\#3333](https://github.com/vector-im/riot-web/pull/3333)
* Expose notification option for username/MXID
[\#3334](https://github.com/vector-im/riot-web/pull/3334)
* Float the toggle in the top right of MELS
[\#3190](https://github.com/vector-im/riot-web/pull/3190)
* More aggressive rageshake log culling
[\#3311](https://github.com/vector-im/riot-web/pull/3311)
* Don't overflow directory network options
[\#3282](https://github.com/vector-im/riot-web/pull/3282)
* CSS for ban / kick reason prompt
[\#3250](https://github.com/vector-im/riot-web/pull/3250)
* Allow forgetting rooms you're banned from
[\#3246](https://github.com/vector-im/riot-web/pull/3246)
* Fix icon paths in manifest
[\#3245](https://github.com/vector-im/riot-web/pull/3245)
* Fix broken tests caused by adding IndexedDB support
[\#3242](https://github.com/vector-im/riot-web/pull/3242)
* CSS for un-ban button in RoomSettings
[\#3227](https://github.com/vector-im/riot-web/pull/3227)
* Remove z-index property on avatar initials
[\#3239](https://github.com/vector-im/riot-web/pull/3239)
* Reposition certain icons in the status bar
[\#3233](https://github.com/vector-im/riot-web/pull/3233)
* CSS for kick/ban confirmation dialog
[\#3224](https://github.com/vector-im/riot-web/pull/3224)
* Style for split-out interactive auth
[\#3217](https://github.com/vector-im/riot-web/pull/3217)
* Use the teamToken threaded through from react sdk
[\#3196](https://github.com/vector-im/riot-web/pull/3196)
* rageshake: Add file server with basic auth
[\#3169](https://github.com/vector-im/riot-web/pull/3169)
* Fix bug with home icon not appearing when logged in as team member
[\#3162](https://github.com/vector-im/riot-web/pull/3162)
* Add ISSUE_TEMPLATE
[\#2836](https://github.com/vector-im/riot-web/pull/2836)
* Store bug reports in separate directories
[\#3150](https://github.com/vector-im/riot-web/pull/3150)
* Quick and dirty support for custom welcome pages.
[\#2575](https://github.com/vector-im/riot-web/pull/2575)
* RTS Welcome Pages
[\#3103](https://github.com/vector-im/riot-web/pull/3103)
* rageshake: Abide by Go standards
[\#3149](https://github.com/vector-im/riot-web/pull/3149)
* Bug report server script
[\#3072](https://github.com/vector-im/riot-web/pull/3072)
* Bump olm version
[\#3125](https://github.com/vector-im/riot-web/pull/3125)
Changes in [0.9.7](https://github.com/vector-im/riot-web/releases/tag/v0.9.7) (2017-02-04)
==========================================================================================
[Full Changelog](https://github.com/vector-im/riot-web/compare/v0.9.7-rc.3...v0.9.7)

View File

@@ -67,6 +67,18 @@ to build.
(cd node_modules/matrix-js-sdk && npm install)
(cd node_modules/matrix-react-sdk && npm install)
```
Whenever you git pull on riot-web you will also probably need to force an update
to these dependencies - the easiest way is probably:
```
rm -rf node_modules/matrjx-{js,react}-sdk && npm i
(cd node_modules/matrix-js-sdk && npm install)
(cd node_modules/matrix-react-sdk && npm install)
```
However, we recommend setting up a proper development environment (see "Setting
up a development environment" below) if you want to run your own copy of the
`develop` branch, as it makes it much easier to keep these dependencies
up-to-date. Or just use https://riot.im/develop - the continuous integration
release of the develop branch.
1. Configure the app by copying `config.sample.json` to `config.json` and
modifying it (see below for details)
1. `npm run dist` to build a tarball to deploy. Untaring this file will give
@@ -117,7 +129,8 @@ built it yourself.
To run as a desktop app:
1. Follow the instructions in 'Building From Source' above
1. Follow the instructions in 'Building From Source' above, but run
`npm run build` instead of `npm run dist` (since we don't need the tarball).
2. Install electron and run it:
```
@@ -266,21 +279,28 @@ Triaging issues
Issues will be triaged by the core team using the following primary set of tags:
priority:
P1: top priority; typically blocks releases.
P2: one below that
P3: non-urgent
P4/P5: bluesky some day, who knows.
* P1: top priority; typically blocks releases
* P2: still need to fix, but lower than P1
* P3: non-urgent
* P4: intereseting idea - bluesky some day
* P5: recorded for posterity/to avoid duplicates. No intention to resolves right now.
bug or feature:
bug severity:
* cosmetic - feature works functionally but UI/UX is broken.
* critical - whole app doesn't work
* major - entire feature doesn't work
* minor - partially broken feature (but still usable)
* release blocker
* bug
* feature
* ui/ux (think of this as cosmetic)
bug severity:
* cosmetic - feature works functionally but UI/UX is broken
* critical - whole app doesn't work
* major - entire feature doesn't work
* minor - partially broken feature (but still usable)
* network (specific to network conditions)
* platform (platform specific)
additional categories:
* release blocker
* ui/ux (think of this as cosmetic)
* network (specific to network conditions)
* platform (platform specific)

View File

@@ -2,7 +2,7 @@
"name": "riot-web",
"productName": "Riot",
"main": "electron/src/electron-main.js",
"version": "0.9.7",
"version": "0.9.8-rc.3",
"description": "A feature-rich client for Matrix.org",
"author": "Vector Creations Ltd.",
"repository": {
@@ -62,8 +62,8 @@
"gfm.css": "^1.1.1",
"highlight.js": "^9.0.0",
"linkifyjs": "^2.1.3",
"matrix-js-sdk": "matrix-org/matrix-js-sdk#develop",
"matrix-react-sdk": "matrix-org/matrix-react-sdk#develop",
"matrix-js-sdk": "0.7.6-rc.2",
"matrix-react-sdk": "0.8.7-rc.4",
"modernizr": "^3.1.0",
"q": "^1.4.1",
"react": "^15.4.0",
@@ -96,7 +96,7 @@
"css-raw-loader": "^0.1.1",
"electron-builder": "^11.2.4",
"electron-builder-squirrel-windows": "^11.2.1",
"emojione": "^2.2.3",
"emojione": "^2.2.7",
"eslint": "^3.14.0",
"eslint-config-google": "^0.7.1",
"eslint-plugin-flowtype": "^2.30.0",
@@ -138,7 +138,7 @@
"build": {
"appId": "im.riot.app",
"category": "Network",
"electronVersion": "1.4.14",
"electronVersion": "1.6.2",
"//asar=false": "https://github.com/electron-userland/electron-builder/issues/675",
"asar": false,
"dereference": true,

View File

@@ -1,146 +0,0 @@
// Run a web server capable of dumping bug reports sent by Riot.
// Requires Go 1.5+
// Usage: BUGS_USER=user BUGS_PASS=password go run rageshake.go PORT
// Example: BUGS_USER=alice BUGS_PASS=secret go run rageshake.go 8080
package main
import (
"bytes"
"compress/gzip"
"crypto/subtle"
"encoding/json"
"fmt"
"io/ioutil"
"log"
"net/http"
"os"
"path/filepath"
"strconv"
"time"
)
var maxPayloadSize = 1024 * 1024 * 55 // 55 MB
type LogEntry struct {
ID string `json:"id"`
Lines string `json:"lines"`
}
type Payload struct {
Text string `json:"text"`
Version string `json:"version"`
UserAgent string `json:"user_agent"`
Logs []LogEntry `json:"logs"`
}
func respond(code int, w http.ResponseWriter) {
w.WriteHeader(code)
w.Write([]byte("{}"))
}
func gzipAndSave(data []byte, dirname, fpath string) error {
_ = os.MkdirAll(filepath.Join("bugs", dirname), os.ModePerm)
fpath = filepath.Join("bugs", dirname, fpath)
if _, err := os.Stat(fpath); err == nil {
return fmt.Errorf("file already exists") // the user can just retry
}
var b bytes.Buffer
gz := gzip.NewWriter(&b)
if _, err := gz.Write(data); err != nil {
return err
}
if err := gz.Flush(); err != nil {
return err
}
if err := gz.Close(); err != nil {
return err
}
if err := ioutil.WriteFile(fpath, b.Bytes(), 0644); err != nil {
return err
}
return nil
}
func basicAuth(handler http.Handler, username, password, realm string) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
user, pass, ok := r.BasicAuth() // pull creds from the request
// check user and pass securely
if !ok || subtle.ConstantTimeCompare([]byte(user), []byte(username)) != 1 || subtle.ConstantTimeCompare([]byte(pass), []byte(password)) != 1 {
w.Header().Set("WWW-Authenticate", `Basic realm="`+realm+`"`)
w.WriteHeader(401)
w.Write([]byte("Unauthorised.\n"))
return
}
handler.ServeHTTP(w, r)
})
}
func main() {
http.HandleFunc("/api/submit", func(w http.ResponseWriter, req *http.Request) {
if req.Method != "POST" && req.Method != "OPTIONS" {
respond(405, w)
return
}
// Set CORS
w.Header().Set("Access-Control-Allow-Origin", "*")
w.Header().Set("Access-Control-Allow-Methods", "POST, OPTIONS")
w.Header().Set("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept")
if req.Method == "OPTIONS" {
respond(200, w)
return
}
if length, err := strconv.Atoi(req.Header.Get("Content-Length")); err != nil || length > maxPayloadSize {
respond(413, w)
return
}
var p Payload
if err := json.NewDecoder(req.Body).Decode(&p); err != nil {
respond(400, w)
return
}
// Dump bug report to disk as form:
// "bugreport-20170115-112233.log.gz" => user text, version, user agent, # logs
// "bugreport-20170115-112233-0.log.gz" => most recent log
// "bugreport-20170115-112233-1.log.gz" => ...
// "bugreport-20170115-112233-N.log.gz" => oldest log
t := time.Now().UTC()
prefix := t.Format("2006-01-02/150405")
summary := fmt.Sprintf(
"%s\n\nNumber of logs: %d\nVersion: %s\nUser-Agent: %s\n", p.Text, len(p.Logs), p.Version, p.UserAgent,
)
if err := gzipAndSave([]byte(summary), prefix, "details.log.gz"); err != nil {
respond(500, w)
return
}
for i, log := range p.Logs {
if err := gzipAndSave([]byte(log.Lines), prefix, fmt.Sprintf("logs-%d.log.gz", i)); err != nil {
respond(500, w)
return // TODO: Rollback?
}
}
respond(200, w)
})
// Make sure bugs directory exists
_ = os.Mkdir("bugs", os.ModePerm)
// serve files under "bugs"
fs := http.FileServer(http.Dir("bugs"))
fs = http.StripPrefix("/api/listing/", fs)
// set auth if env vars exist
usr := os.Getenv("BUGS_USER")
pass := os.Getenv("BUGS_PASS")
if usr == "" || pass == "" {
fmt.Println("BUGS_USER and BUGS_PASS env vars not found. No authentication is running for /api/listing")
} else {
fs = basicAuth(fs, usr, pass, "Riot bug reports")
}
http.Handle("/api/listing/", fs)
port := os.Args[1]
log.Fatal(http.ListenAndServe(":"+port, nil))
}

View File

@@ -30,12 +30,12 @@ import structures$BottomLeftMenu from './components/structures/BottomLeftMenu';
structures$BottomLeftMenu && (module.exports.components['structures.BottomLeftMenu'] = structures$BottomLeftMenu);
import structures$CompatibilityPage from './components/structures/CompatibilityPage';
structures$CompatibilityPage && (module.exports.components['structures.CompatibilityPage'] = structures$CompatibilityPage);
import structures$HomePage from './components/structures/HomePage';
structures$HomePage && (module.exports.components['structures.HomePage'] = structures$HomePage);
import structures$LeftPanel from './components/structures/LeftPanel';
structures$LeftPanel && (module.exports.components['structures.LeftPanel'] = structures$LeftPanel);
import structures$RightPanel from './components/structures/RightPanel';
structures$RightPanel && (module.exports.components['structures.RightPanel'] = structures$RightPanel);
import structures$HomePage from './components/structures/HomePage';
structures$HomePage && (module.exports.components['structures.HomePage'] = structures$HomePage);
import structures$RoomDirectory from './components/structures/RoomDirectory';
structures$RoomDirectory && (module.exports.components['structures.RoomDirectory'] = structures$RoomDirectory);
import structures$RoomSubList from './components/structures/RoomSubList';
@@ -46,10 +46,8 @@ import structures$ViewSource from './components/structures/ViewSource';
structures$ViewSource && (module.exports.components['structures.ViewSource'] = structures$ViewSource);
import views$context_menus$MessageContextMenu from './components/views/context_menus/MessageContextMenu';
views$context_menus$MessageContextMenu && (module.exports.components['views.context_menus.MessageContextMenu'] = views$context_menus$MessageContextMenu);
import views$context_menus$NotificationStateContextMenu from './components/views/context_menus/NotificationStateContextMenu';
views$context_menus$NotificationStateContextMenu && (module.exports.components['views.context_menus.NotificationStateContextMenu'] = views$context_menus$NotificationStateContextMenu);
import views$context_menus$RoomTagContextMenu from './components/views/context_menus/RoomTagContextMenu';
views$context_menus$RoomTagContextMenu && (module.exports.components['views.context_menus.RoomTagContextMenu'] = views$context_menus$RoomTagContextMenu);
import views$context_menus$RoomTileContextMenu from './components/views/context_menus/RoomTileContextMenu';
views$context_menus$RoomTileContextMenu && (module.exports.components['views.context_menus.RoomTileContextMenu'] = views$context_menus$RoomTileContextMenu);
import views$dialogs$BugReportDialog from './components/views/dialogs/BugReportDialog';
views$dialogs$BugReportDialog && (module.exports.components['views.dialogs.BugReportDialog'] = views$dialogs$BugReportDialog);
import views$dialogs$ChangelogDialog from './components/views/dialogs/ChangelogDialog';

View File

@@ -162,7 +162,7 @@ module.exports = React.createClass({
var ErrorDialog = sdk.getComponent("dialogs.ErrorDialog");
Modal.createDialog(ErrorDialog, {
title: "Failed to get public room list",
description: err.message
description: "The server may be unavailable or overloaded",
});
});
},
@@ -208,9 +208,10 @@ module.exports = React.createClass({
}, function(err) {
modal.close();
this.refreshRoomList();
console.error("Failed to " + step + ": " + err);
Modal.createDialog(ErrorDialog, {
title: "Failed to "+step,
description: err.toString()
title: "Error",
description: "Failed to " + step,
});
});
}

View File

@@ -146,12 +146,20 @@ var RoomSubList = React.createClass({
}
},
onRoomTileClick(roomId) {
dis.dispatch({
action: 'view_room',
room_id: roomId,
});
},
tsOfNewestEvent: function(room) {
for (var i = room.timeline.length - 1; i >= 0; --i) {
var ev = room.timeline[i];
if (Unread.eventTriggersUnreadCount(ev) ||
(ev.sender && ev.sender.userId === MatrixClientPeg.get().credentials.userId))
{
if (ev.getTs() &&
(Unread.eventTriggersUnreadCount(ev) ||
(ev.getSender() === MatrixClientPeg.get().credentials.userId))
) {
return ev.getTs();
}
}
@@ -159,7 +167,7 @@ var RoomSubList = React.createClass({
// we might only have events that don't trigger the unread indicator,
// in which case use the oldest event even if normally it wouldn't count.
// This is better than just assuming the last event was forever ago.
if (room.timeline.length) {
if (room.timeline.length && room.timeline[0].getTs()) {
return room.timeline[0].getTs();
} else {
return Number.MAX_SAFE_INTEGER;
@@ -364,7 +372,9 @@ var RoomSubList = React.createClass({
highlight={ room.getUnreadNotificationCount('highlight') > 0 || self.props.label === 'Invites' }
isInvite={ self.props.label === 'Invites' }
refreshSubList={ self._updateSubListCount }
incomingCall={ null } />
incomingCall={ null }
onClick={ self.onRoomTileClick }
/>
);
});
},
@@ -408,7 +418,7 @@ var RoomSubList = React.createClass({
if (this.props.incomingCall) {
var self = this;
// Check if the incoming call is for this section
var incomingCallRoom = this.state.sortedList.filter(function(room) {
var incomingCallRoom = this.props.list.filter(function(room) {
return self.props.incomingCall.roomId === room.roomId;
});
@@ -496,9 +506,10 @@ var RoomSubList = React.createClass({
// Do any final stuff here
}).fail(function(err) {
var ErrorDialog = sdk.getComponent("dialogs.ErrorDialog");
console.error("Failed to add tag " + self.props.tagName + " to room" + err);
Modal.createDialog(ErrorDialog, {
title: "Failed to add tag " + self.props.tagName + " to room",
description: err.toString()
title: "Error",
description: "Failed to add tag " + self.props.tagName + " to room",
});
});
break;

View File

@@ -45,6 +45,9 @@ module.exports = React.createClass({
},
onAction: function(payload) {
// Disabling this as I find it really really annoying, and was used to the
// previous behaviour - see https://github.com/vector-im/riot-web/issues/3348
/*
switch (payload.action) {
// Clear up the text field when a room is selected.
case 'view_room':
@@ -53,6 +56,7 @@ module.exports = React.createClass({
}
break;
}
*/
},
onChange: function() {

View File

@@ -62,19 +62,24 @@ module.exports = React.createClass({
},
onRedactClick: function() {
MatrixClientPeg.get().redactEvent(
this.props.mxEvent.getRoomId(), this.props.mxEvent.getId()
).done(function() {
// message should disappear by itself
}, function(e) {
var ErrorDialog = sdk.getComponent("dialogs.ErrorDialog");
// display error message stating you couldn't delete this.
var code = e.errcode || e.statusCode;
Modal.createDialog(ErrorDialog, {
title: "Error",
description: "You cannot delete this message. (" + code + ")"
});
});
const ConfirmRedactDialog = sdk.getComponent("dialogs.ConfirmRedactDialog");
Modal.createDialog(ConfirmRedactDialog, {
onFinished: (proceed) => {
if (!proceed) return;
MatrixClientPeg.get().redactEvent(
this.props.mxEvent.getRoomId(), this.props.mxEvent.getId()
).catch(function(e) {
var ErrorDialog = sdk.getComponent("dialogs.ErrorDialog");
// display error message stating you couldn't delete this.
var code = e.errcode || e.statusCode;
Modal.createDialog(ErrorDialog, {
title: "Error",
description: "You cannot delete this message. (" + code + ")"
});
}).done();
},
}, 'mx_Dialog_confirmredact');
if (this.props.onFinished) this.props.onFinished();
},
@@ -121,7 +126,7 @@ module.exports = React.createClass({
);
}
if (!eventStatus) { // sent
if (!eventStatus && !this.props.mxEvent.isRedacted()) { // sent and not redacted
redactButton = (
<div className="mx_MessageContextMenu_field" onClick={this.onRedactClick}>
Redact

View File

@@ -1,144 +0,0 @@
/*
Copyright 2015, 2016 OpenMarket Ltd
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
'use strict';
var q = require("q");
var React = require('react');
var classNames = require('classnames');
var RoomNotifs = require('matrix-react-sdk/lib/RoomNotifs');
var MatrixClientPeg = require('matrix-react-sdk/lib/MatrixClientPeg');
module.exports = React.createClass({
displayName: 'NotificationStateContextMenu',
propTypes: {
room: React.PropTypes.object.isRequired,
/* callback called when the menu is dismissed */
onFinished: React.PropTypes.func,
},
getInitialState() {
return {
roomNotifState: RoomNotifs.getRoomNotifsState(this.props.room.roomId),
}
},
componentWillMount: function() {
this._unmounted = false;
},
componentWillUnmount: function() {
this._unmounted = true;
},
_save: function(newState) {
const oldState = this.state.roomNotifState;
const roomId = this.props.room.roomId;
var cli = MatrixClientPeg.get();
if (cli.isGuest()) return;
this.setState({
roomNotifState: newState,
});
RoomNotifs.setRoomNotifsState(this.props.room.roomId, newState).done(() => {
// delay slightly so that the user can see their state change
// before closing the menu
return q.delay(500).then(() => {
if (this._unmounted) return;
// Close the context menu
if (this.props.onFinished) {
this.props.onFinished();
};
});
}, (error) => {
// TODO: some form of error notification to the user
// to inform them that their state change failed.
// For now we at least set the state back
if (this._unmounted) return;
this.setState({
roomNotifState: oldState,
});
});
},
_onClickAlertMe: function() {
this._save(RoomNotifs.ALL_MESSAGES_LOUD);
},
_onClickAllNotifs: function() {
this._save(RoomNotifs.ALL_MESSAGES);
},
_onClickMentions: function() {
this._save(RoomNotifs.MENTIONS_ONLY);
},
_onClickMute: function() {
this._save(RoomNotifs.MUTE);
},
render: function() {
var alertMeClasses = classNames({
'mx_NotificationStateContextMenu_field': true,
'mx_NotificationStateContextMenu_fieldSet': this.state.roomNotifState == RoomNotifs.ALL_MESSAGES_LOUD,
});
var allNotifsClasses = classNames({
'mx_NotificationStateContextMenu_field': true,
'mx_NotificationStateContextMenu_fieldSet': this.state.roomNotifState == RoomNotifs.ALL_MESSAGES,
});
var mentionsClasses = classNames({
'mx_NotificationStateContextMenu_field': true,
'mx_NotificationStateContextMenu_fieldSet': this.state.roomNotifState == RoomNotifs.MENTIONS_ONLY,
});
var muteNotifsClasses = classNames({
'mx_NotificationStateContextMenu_field': true,
'mx_NotificationStateContextMenu_fieldSet': this.state.roomNotifState == RoomNotifs.MUTE,
});
return (
<div>
<div className="mx_NotificationStateContextMenu_picker" >
<img src="img/notif-slider.svg" width="20" height="107" />
</div>
<div className={ alertMeClasses } onClick={this._onClickAlertMe} >
<img className="mx_NotificationStateContextMenu_activeIcon" src="img/notif-active.svg" width="12" height="12" />
<img className="mx_NotificationStateContextMenu_icon mx_filterFlipColor" src="img/icon-context-mute-off-copy.svg" width="16" height="12" />
All messages (loud)
</div>
<div className={ allNotifsClasses } onClick={this._onClickAllNotifs} >
<img className="mx_NotificationStateContextMenu_activeIcon" src="img/notif-active.svg" width="12" height="12" />
<img className="mx_NotificationStateContextMenu_icon mx_filterFlipColor" src="img/icon-context-mute-off.svg" width="16" height="12" />
All messages
</div>
<div className={ mentionsClasses } onClick={this._onClickMentions} >
<img className="mx_NotificationStateContextMenu_activeIcon" src="img/notif-active.svg" width="12" height="12" />
<img className="mx_NotificationStateContextMenu_icon mx_filterFlipColor" src="img/icon-context-mute-mentions.svg" width="16" height="12" />
Mentions only
</div>
<div className={ muteNotifsClasses } onClick={this._onClickMute} >
<img className="mx_NotificationStateContextMenu_activeIcon" src="img/notif-active.svg" width="12" height="12" />
<img className="mx_NotificationStateContextMenu_icon mx_filterFlipColor" src="img/icon-context-mute.svg" width="16" height="12" />
Mute
</div>
</div>
);
}
});

View File

@@ -1,255 +0,0 @@
/*
Copyright 2015, 2016 OpenMarket Ltd
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
'use strict';
import q from 'q';
import React from 'react';
import classNames from 'classnames';
import sdk from 'matrix-react-sdk';
import MatrixClientPeg from 'matrix-react-sdk/lib/MatrixClientPeg';
import dis from 'matrix-react-sdk/lib/dispatcher';
import DMRoomMap from 'matrix-react-sdk/lib/utils/DMRoomMap';
import Rooms from 'matrix-react-sdk/lib/Rooms';
import Modal from 'matrix-react-sdk/lib/Modal';
module.exports = React.createClass({
displayName: 'RoomTagContextMenu',
propTypes: {
room: React.PropTypes.object.isRequired,
/* callback called when the menu is dismissed */
onFinished: React.PropTypes.func,
},
getInitialState: function() {
const dmRoomMap = new DMRoomMap(MatrixClientPeg.get());
return {
isFavourite: this.props.room.tags.hasOwnProperty("m.favourite"),
isLowPriority: this.props.room.tags.hasOwnProperty("m.lowpriority"),
isDirectMessage: Boolean(dmRoomMap.getUserIdForRoomId(this.props.room.roomId)),
};
},
_toggleTag: function(tagNameOn, tagNameOff) {
var self = this;
const roomId = this.props.room.roomId;
var cli = MatrixClientPeg.get();
if (!cli.isGuest()) {
q.delay(500).then(function() {
if (tagNameOff !== null && tagNameOff !== undefined) {
cli.deleteRoomTag(roomId, tagNameOff).finally(function() {
// Close the context menu
if (self.props.onFinished) {
self.props.onFinished();
};
}).fail(function(err) {
var ErrorDialog = sdk.getComponent("dialogs.ErrorDialog");
Modal.createDialog(ErrorDialog, {
title: "Failed to remove tag " + tagNameOff + " from room",
description: err.toString()
});
});
}
if (tagNameOn !== null && tagNameOn !== undefined) {
// If the tag ordering meta data is required, it is added by
// the RoomSubList when it sorts its rooms
cli.setRoomTag(roomId, tagNameOn, {}).finally(function() {
// Close the context menu
if (self.props.onFinished) {
self.props.onFinished();
};
}).fail(function(err) {
var ErrorDialog = sdk.getComponent("dialogs.ErrorDialog");
Modal.createDialog(ErrorDialog, {
title: "Failed to add tag " + tagNameOn + " to room",
description: err.toString()
});
});
}
});
}
},
_onClickFavourite: function() {
// Tag room as 'Favourite'
if (!this.state.isFavourite && this.state.isLowPriority) {
this.setState({
isFavourite: true,
isLowPriority: false,
});
this._toggleTag("m.favourite", "m.lowpriority");
} else if (this.state.isFavourite) {
this.setState({isFavourite: false});
this._toggleTag(null, "m.favourite");
} else if (!this.state.isFavourite) {
this.setState({isFavourite: true});
this._toggleTag("m.favourite");
}
},
_onClickLowPriority: function() {
// Tag room as 'Low Priority'
if (!this.state.isLowPriority && this.state.isFavourite) {
this.setState({
isFavourite: false,
isLowPriority: true,
});
this._toggleTag("m.lowpriority", "m.favourite");
} else if (this.state.isLowPriority) {
this.setState({isLowPriority: false});
this._toggleTag(null, "m.lowpriority");
} else if (!this.state.isLowPriority) {
this.setState({isLowPriority: true});
this._toggleTag("m.lowpriority");
}
},
_onClickDM: function() {
const newIsDirectMessage = !this.state.isDirectMessage;
this.setState({
isDirectMessage: newIsDirectMessage,
});
if (MatrixClientPeg.get().isGuest()) return;
let newTarget;
if (newIsDirectMessage) {
const guessedTarget = Rooms.guessDMRoomTarget(
this.props.room,
this.props.room.getMember(MatrixClientPeg.get().credentials.userId),
);
newTarget = guessedTarget.userId;
} else {
newTarget = null;
}
// give some time for the user to see the icon change first, since
// this will hide the context menu once it completes
q.delay(500).done(() => {
return Rooms.setDMRoom(this.props.room.roomId, newTarget).finally(() => {
// Close the context menu
if (this.props.onFinished) {
this.props.onFinished();
};
}, (err) => {
var ErrorDialog = sdk.getComponent("dialogs.ErrorDialog");
Modal.createDialog(ErrorDialog, {
title: "Failed to set Direct Message status of room",
description: err.toString()
});
});
});
},
_onClickLeave: function() {
// Leave room
dis.dispatch({
action: 'leave_room',
room_id: this.props.room.roomId,
});
// Close the context menu
if (this.props.onFinished) {
this.props.onFinished();
};
},
_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() {
const myUserId = MatrixClientPeg.get().credentials.userId;
const myMember = this.props.room.getMember(myUserId);
const favouriteClasses = classNames({
'mx_RoomTagContextMenu_field': true,
'mx_RoomTagContextMenu_fieldSet': this.state.isFavourite,
'mx_RoomTagContextMenu_fieldDisabled': false,
});
const lowPriorityClasses = classNames({
'mx_RoomTagContextMenu_field': true,
'mx_RoomTagContextMenu_fieldSet': this.state.isLowPriority,
'mx_RoomTagContextMenu_fieldDisabled': false,
});
const leaveClasses = classNames({
'mx_RoomTagContextMenu_field': true,
'mx_RoomTagContextMenu_fieldSet': false,
'mx_RoomTagContextMenu_fieldDisabled': false,
});
const dmClasses = classNames({
'mx_RoomTagContextMenu_field': true,
'mx_RoomTagContextMenu_fieldSet': this.state.isDirectMessage,
'mx_RoomTagContextMenu_fieldDisabled': false,
});
if (myMember && (myMember.membership === "leave" || myMember.membership === "ban")) {
return (
<div>
<div className={ leaveClasses } onClick={ this._onClickForget } >
<img className="mx_RoomTagContextMenu_icon" src="img/icon_context_delete.svg" width="15" height="15" />
Forget
</div>
</div>
);
}
return (
<div>
<div className={ favouriteClasses } onClick={this._onClickFavourite} >
<img className="mx_RoomTagContextMenu_icon" src="img/icon_context_fave.svg" width="15" height="15" />
<img className="mx_RoomTagContextMenu_icon_set" src="img/icon_context_fave_on.svg" width="15" height="15" />
Favourite
</div>
<div className={ lowPriorityClasses } onClick={this._onClickLowPriority} >
<img className="mx_RoomTagContextMenu_icon" src="img/icon_context_low.svg" width="15" height="15" />
<img className="mx_RoomTagContextMenu_icon_set" src="img/icon_context_low_on.svg" width="15" height="15" />
Low Priority
</div>
<div className={ dmClasses } onClick={this._onClickDM} >
<img className="mx_RoomTagContextMenu_icon" src="img/icon_context_person.svg" width="15" height="15" />
<img className="mx_RoomTagContextMenu_icon_set" src="img/icon_context_person_on.svg" width="15" height="15" />
Direct Chat
</div>
<hr className="mx_RoomTagContextMenu_separator" />
<div className={ leaveClasses } onClick={(myMember && myMember.membership === "join") ? this._onClickLeave : null} >
<img className="mx_RoomTagContextMenu_icon" src="img/icon_context_delete.svg" width="15" height="15" />
Leave
</div>
</div>
);
}
});

View File

@@ -0,0 +1,392 @@
/*
Copyright 2015, 2016 OpenMarket Ltd
Copyright 2017 Vector Creations Ltd
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
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.
*/
'use strict';
import q from 'q';
import React from 'react';
import classNames from 'classnames';
import sdk from 'matrix-react-sdk';
import MatrixClientPeg from 'matrix-react-sdk/lib/MatrixClientPeg';
import dis from 'matrix-react-sdk/lib/dispatcher';
import DMRoomMap from 'matrix-react-sdk/lib/utils/DMRoomMap';
import * as Rooms from 'matrix-react-sdk/lib/Rooms';
import * as RoomNotifs from 'matrix-react-sdk/lib/RoomNotifs';
import Modal from 'matrix-react-sdk/lib/Modal';
module.exports = React.createClass({
displayName: 'RoomTileContextMenu',
propTypes: {
room: React.PropTypes.object.isRequired,
/* callback called when the menu is dismissed */
onFinished: React.PropTypes.func,
},
getInitialState() {
const dmRoomMap = new DMRoomMap(MatrixClientPeg.get());
return {
roomNotifState: RoomNotifs.getRoomNotifsState(this.props.room.roomId),
isFavourite: this.props.room.tags.hasOwnProperty("m.favourite"),
isLowPriority: this.props.room.tags.hasOwnProperty("m.lowpriority"),
isDirectMessage: Boolean(dmRoomMap.getUserIdForRoomId(this.props.room.roomId)),
}
},
componentWillMount: function() {
this._unmounted = false;
},
componentWillUnmount: function() {
this._unmounted = true;
},
_toggleTag: function(tagNameOn, tagNameOff) {
var self = this;
const roomId = this.props.room.roomId;
var cli = MatrixClientPeg.get();
if (!cli.isGuest()) {
q.delay(500).then(function() {
if (tagNameOff !== null && tagNameOff !== undefined) {
cli.deleteRoomTag(roomId, tagNameOff).finally(function() {
// Close the context menu
if (self.props.onFinished) {
self.props.onFinished();
};
}).fail(function(err) {
var ErrorDialog = sdk.getComponent("dialogs.ErrorDialog");
Modal.createDialog(ErrorDialog, {
title: "Failed to remove tag " + tagNameOff + " from room",
description: err.toString()
});
});
}
if (tagNameOn !== null && tagNameOn !== undefined) {
// If the tag ordering meta data is required, it is added by
// the RoomSubList when it sorts its rooms
cli.setRoomTag(roomId, tagNameOn, {}).finally(function() {
// Close the context menu
if (self.props.onFinished) {
self.props.onFinished();
};
}).fail(function(err) {
var ErrorDialog = sdk.getComponent("dialogs.ErrorDialog");
Modal.createDialog(ErrorDialog, {
title: "Failed to add tag " + tagNameOn + " to room",
description: err.toString()
});
});
}
});
}
},
_onClickFavourite: function() {
// Tag room as 'Favourite'
if (!this.state.isFavourite && this.state.isLowPriority) {
this.setState({
isFavourite: true,
isLowPriority: false,
});
this._toggleTag("m.favourite", "m.lowpriority");
} else if (this.state.isFavourite) {
this.setState({isFavourite: false});
this._toggleTag(null, "m.favourite");
} else if (!this.state.isFavourite) {
this.setState({isFavourite: true});
this._toggleTag("m.favourite");
}
},
_onClickLowPriority: function() {
// Tag room as 'Low Priority'
if (!this.state.isLowPriority && this.state.isFavourite) {
this.setState({
isFavourite: false,
isLowPriority: true,
});
this._toggleTag("m.lowpriority", "m.favourite");
} else if (this.state.isLowPriority) {
this.setState({isLowPriority: false});
this._toggleTag(null, "m.lowpriority");
} else if (!this.state.isLowPriority) {
this.setState({isLowPriority: true});
this._toggleTag("m.lowpriority");
}
},
_onClickDM: function() {
const newIsDirectMessage = !this.state.isDirectMessage;
this.setState({
isDirectMessage: newIsDirectMessage,
});
if (MatrixClientPeg.get().isGuest()) return;
Rooms.guessAndSetDMRoom(
this.props.room, newIsDirectMessage
).delay(500).finally(() => {
// Close the context menu
if (this.props.onFinished) {
this.props.onFinished();
};
}, (err) => {
var ErrorDialog = sdk.getComponent("dialogs.ErrorDialog");
Modal.createDialog(ErrorDialog, {
title: "Failed to set Direct Message status of room",
description: err.toString()
});
});
},
_onClickLeave: function() {
// Leave room
dis.dispatch({
action: 'leave_room',
room_id: this.props.room.roomId,
});
// Close the context menu
if (this.props.onFinished) {
this.props.onFinished();
};
},
_onClickReject: function() {
dis.dispatch({
action: 'reject_invite',
room_id: this.props.room.roomId,
});
// Close the context menu
if (this.props.onFinished) {
this.props.onFinished();
};
},
_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();
};
},
_saveNotifState: function(newState) {
const oldState = this.state.roomNotifState;
const roomId = this.props.room.roomId;
var cli = MatrixClientPeg.get();
if (cli.isGuest()) return;
this.setState({
roomNotifState: newState,
});
RoomNotifs.setRoomNotifsState(this.props.room.roomId, newState).done(() => {
// delay slightly so that the user can see their state change
// before closing the menu
return q.delay(500).then(() => {
if (this._unmounted) return;
// Close the context menu
if (this.props.onFinished) {
this.props.onFinished();
};
});
}, (error) => {
// TODO: some form of error notification to the user
// to inform them that their state change failed.
// For now we at least set the state back
if (this._unmounted) return;
this.setState({
roomNotifState: oldState,
});
});
},
_onClickAlertMe: function() {
this._saveNotifState(RoomNotifs.ALL_MESSAGES_LOUD);
},
_onClickAllNotifs: function() {
this._saveNotifState(RoomNotifs.ALL_MESSAGES);
},
_onClickMentions: function() {
this._saveNotifState(RoomNotifs.MENTIONS_ONLY);
},
_onClickMute: function() {
this._saveNotifState(RoomNotifs.MUTE);
},
_renderNotifMenu: function() {
var alertMeClasses = classNames({
'mx_RoomTileContextMenu_notif_field': true,
'mx_RoomTileContextMenu_notif_fieldSet': this.state.roomNotifState == RoomNotifs.ALL_MESSAGES_LOUD,
});
var allNotifsClasses = classNames({
'mx_RoomTileContextMenu_notif_field': true,
'mx_RoomTileContextMenu_notif_fieldSet': this.state.roomNotifState == RoomNotifs.ALL_MESSAGES,
});
var mentionsClasses = classNames({
'mx_RoomTileContextMenu_notif_field': true,
'mx_RoomTileContextMenu_notif_fieldSet': this.state.roomNotifState == RoomNotifs.MENTIONS_ONLY,
});
var muteNotifsClasses = classNames({
'mx_RoomTileContextMenu_notif_field': true,
'mx_RoomTileContextMenu_notif_fieldSet': this.state.roomNotifState == RoomNotifs.MUTE,
});
return (
<div>
<div className="mx_RoomTileContextMenu_notif_picker" >
<img src="img/notif-slider.svg" width="20" height="107" />
</div>
<div className={ alertMeClasses } onClick={this._onClickAlertMe} >
<img className="mx_RoomTileContextMenu_notif_activeIcon" src="img/notif-active.svg" width="12" height="12" />
<img className="mx_RoomTileContextMenu_notif_icon mx_filterFlipColor" src="img/icon-context-mute-off-copy.svg" width="16" height="12" />
All messages (loud)
</div>
<div className={ allNotifsClasses } onClick={this._onClickAllNotifs} >
<img className="mx_RoomTileContextMenu_notif_activeIcon" src="img/notif-active.svg" width="12" height="12" />
<img className="mx_RoomTileContextMenu_notif_icon mx_filterFlipColor" src="img/icon-context-mute-off.svg" width="16" height="12" />
All messages
</div>
<div className={ mentionsClasses } onClick={this._onClickMentions} >
<img className="mx_RoomTileContextMenu_notif_activeIcon" src="img/notif-active.svg" width="12" height="12" />
<img className="mx_RoomTileContextMenu_notif_icon mx_filterFlipColor" src="img/icon-context-mute-mentions.svg" width="16" height="12" />
Mentions only
</div>
<div className={ muteNotifsClasses } onClick={this._onClickMute} >
<img className="mx_RoomTileContextMenu_notif_activeIcon" src="img/notif-active.svg" width="12" height="12" />
<img className="mx_RoomTileContextMenu_notif_icon mx_filterFlipColor" src="img/icon-context-mute.svg" width="16" height="12" />
Mute
</div>
</div>
);
},
_renderLeaveMenu: function(membership) {
if (!membership) {
return null;
}
let leaveClickHandler = null;
let leaveText = null;
switch (membership) {
case "join":
leaveClickHandler = this._onClickLeave;
leaveText = "Leave";
break;
case "leave":
case "ban":
leaveClickHandler = this._onClickForget;
leaveText = "Forget";
break;
case "invite":
leaveClickHandler = this._onClickReject;
leaveText = "Reject";
break;
}
return (
<div>
<div className="mx_RoomTileContextMenu_leave" onClick={ leaveClickHandler } >
<img className="mx_RoomTileContextMenu_tag_icon" src="img/icon_context_delete.svg" width="15" height="15" />
{ leaveText }
</div>
</div>
);
},
_renderRoomTagMenu: function() {
const favouriteClasses = classNames({
'mx_RoomTileContextMenu_tag_field': true,
'mx_RoomTileContextMenu_tag_fieldSet': this.state.isFavourite,
'mx_RoomTileContextMenu_tag_fieldDisabled': false,
});
const lowPriorityClasses = classNames({
'mx_RoomTileContextMenu_tag_field': true,
'mx_RoomTileContextMenu_tag_fieldSet': this.state.isLowPriority,
'mx_RoomTileContextMenu_tag_fieldDisabled': false,
});
const dmClasses = classNames({
'mx_RoomTileContextMenu_tag_field': true,
'mx_RoomTileContextMenu_tag_fieldSet': this.state.isDirectMessage,
'mx_RoomTileContextMenu_tag_fieldDisabled': false,
});
return (
<div>
<div className={ favouriteClasses } onClick={this._onClickFavourite} >
<img className="mx_RoomTileContextMenu_tag_icon" src="img/icon_context_fave.svg" width="15" height="15" />
<img className="mx_RoomTileContextMenu_tag_icon_set" src="img/icon_context_fave_on.svg" width="15" height="15" />
Favourite
</div>
<div className={ lowPriorityClasses } onClick={this._onClickLowPriority} >
<img className="mx_RoomTileContextMenu_tag_icon" src="img/icon_context_low.svg" width="15" height="15" />
<img className="mx_RoomTileContextMenu_tag_icon_set" src="img/icon_context_low_on.svg" width="15" height="15" />
Low Priority
</div>
<div className={ dmClasses } onClick={this._onClickDM} >
<img className="mx_RoomTileContextMenu_tag_icon" src="img/icon_context_person.svg" width="15" height="15" />
<img className="mx_RoomTileContextMenu_tag_icon_set" src="img/icon_context_person_on.svg" width="15" height="15" />
Direct Chat
</div>
</div>
);
},
render: function() {
const myMember = this.props.room.getMember(
MatrixClientPeg.get().credentials.userId
);
// Can't set notif level or tags on non-join rooms
if (myMember.membership !== 'join') {
return this._renderLeaveMenu(myMember.membership);
}
return (
<div>
{ this._renderNotifMenu() }
<hr className="mx_RoomTileContextMenu_separator" />
{ this._renderLeaveMenu(myMember.membership) }
<hr className="mx_RoomTileContextMenu_separator" />
{ this._renderRoomTagMenu() }
</div>
);
}
});

View File

@@ -23,6 +23,8 @@ var MatrixClientPeg = require('matrix-react-sdk/lib/MatrixClientPeg');
var DateUtils = require('matrix-react-sdk/lib/DateUtils');
var filesize = require('filesize');
var AccessibleButton = require('matrix-react-sdk/lib/components/views/elements/AccessibleButton');
const Modal = require('matrix-react-sdk/lib/Modal');
const sdk = require('matrix-react-sdk');
module.exports = React.createClass({
displayName: 'ImageView',
@@ -62,19 +64,23 @@ module.exports = React.createClass({
},
onRedactClick: function() {
var self = this;
MatrixClientPeg.get().redactEvent(
this.props.mxEvent.getRoomId(), this.props.mxEvent.getId()
).done(function() {
if (self.props.onFinished) self.props.onFinished();
}, function(e) {
var ErrorDialog = sdk.getComponent("dialogs.ErrorDialog");
// display error message stating you couldn't delete this.
var code = e.errcode || e.statusCode;
Modal.createDialog(ErrorDialog, {
title: "Error",
description: "You cannot delete this image. (" + code + ")"
});
const ConfirmRedactDialog = sdk.getComponent("dialogs.ConfirmRedactDialog");
Modal.createDialog(ConfirmRedactDialog, {
onFinished: (proceed) => {
if (!proceed) return;
var self = this;
MatrixClientPeg.get().redactEvent(
this.props.mxEvent.getRoomId(), this.props.mxEvent.getId()
).catch(function(e) {
var ErrorDialog = sdk.getComponent("dialogs.ErrorDialog");
// display error message stating you couldn't delete this.
var code = e.errcode || e.statusCode;
Modal.createDialog(ErrorDialog, {
title: "Error",
description: "You cannot delete this image. (" + code + ")"
});
}).done();
}
});
},

View File

@@ -16,14 +16,16 @@ limitations under the License.
'use strict';
var React = require('react');
var DragSource = require('react-dnd').DragSource;
var DropTarget = require('react-dnd').DropTarget;
import React from 'react';
import {DragSource} from 'react-dnd';
import {DropTarget} from 'react-dnd';
var dis = require("matrix-react-sdk/lib/dispatcher");
var MatrixClientPeg = require('matrix-react-sdk/lib/MatrixClientPeg');
var sdk = require('matrix-react-sdk');
var RoomTile = require('matrix-react-sdk/lib/components/views/rooms/RoomTile');
import dis from 'matrix-react-sdk/lib/dispatcher';
import MatrixClientPeg from 'matrix-react-sdk/lib/MatrixClientPeg';
import sdk from 'matrix-react-sdk';
import RoomTile from 'matrix-react-sdk/lib/components/views/rooms/RoomTile';
import * as Rooms from 'matrix-react-sdk/lib/Rooms';
import Modal from 'matrix-react-sdk/lib/Modal';
/**
* Defines a new Component, DNDRoomTile that wraps RoomTile, making it draggable.
@@ -72,21 +74,49 @@ var roomTileSource = {
item.targetList.forceUpdate(); // as we're not using state
}
const prevTag = item.originalList.props.tagName;
const newTag = item.targetList.props.tagName;
if (monitor.didDrop() && item.targetList.props.editable) {
// Evil hack to get DMs behaving
if ((prevTag === undefined && newTag === 'im.vector.fake.direct') ||
(prevTag === 'im.vector.fake.direct' && newTag === undefined)
) {
Rooms.guessAndSetDMRoom(
item.room, newTag === 'im.vector.fake.direct',
).done(() => {
item.originalList.removeRoomTile(item.room);
}, (err) => {
const ErrorDialog = sdk.getComponent("dialogs.ErrorDialog");
console.error("Failed to set direct chat tag " + err);
Modal.createDialog(ErrorDialog, {
title: "Error",
description: "Failed to set direct chat tag",
});
});
return;
}
// More evilness: We will still be dealing with moving to favourites/low prio,
// but we avoid ever doing a request with 'im.vector.fake.direct`.
// if we moved lists, remove the old tag
if (item.targetList !== item.originalList && item.originalList.props.tagName) {
if (prevTag && prevTag !== 'im.vector.fake.direct' &&
item.targetList !== item.originalList
) {
// commented out attempts to set a spinner on our target component as component is actually
// the original source component being dragged, not our target. To fix we just need to
// move all of this to endDrop in the target instead. FIXME later.
//component.state.set({ spinner: component.state.spinner ? component.state.spinner++ : 1 });
MatrixClientPeg.get().deleteRoomTag(item.room.roomId, item.originalList.props.tagName).finally(function() {
MatrixClientPeg.get().deleteRoomTag(item.room.roomId, prevTag).finally(function() {
//component.state.set({ spinner: component.state.spinner-- });
}).fail(function(err) {
var ErrorDialog = sdk.getComponent("dialogs.ErrorDialog");
console.error("Failed to remove tag " + prevTag + " from room: " + err);
Modal.createDialog(ErrorDialog, {
title: "Failed to remove tag " + item.originalList.props.tagName + " from room",
description: err.toString()
title: "Error",
description: "Failed to remove tag " + prevTag + " from room",
});
});
}
@@ -97,15 +127,18 @@ var roomTileSource = {
}
// if we moved lists or the ordering changed, add the new tag
if (item.targetList.props.tagName && (item.targetList !== item.originalList || newOrder)) {
if (newTag && newTag !== 'im.vector.fake.direct' &&
(item.targetList !== item.originalList || newOrder)
) {
//component.state.set({ spinner: component.state.spinner ? component.state.spinner++ : 1 });
MatrixClientPeg.get().setRoomTag(item.room.roomId, item.targetList.props.tagName, newOrder).finally(function() {
MatrixClientPeg.get().setRoomTag(item.room.roomId, newTag, newOrder).finally(function() {
//component.state.set({ spinner: component.state.spinner-- });
}).fail(function(err) {
var ErrorDialog = sdk.getComponent("dialogs.ErrorDialog");
console.error("Failed to add tag " + newTag + " to room: " + err);
Modal.createDialog(ErrorDialog, {
title: "Failed to add tag " + item.targetList.props.tagName + " to room",
description: err.toString()
title: "Error",
description: "Failed to add tag " + newTag + " to room",
});
});
}

View File

@@ -31,7 +31,6 @@ module.exports = React.createClass({
else {
return (
<div className="mx_RoomDropTarget">
<div className="mx_RoomDropTarget_avatar"></div>
<div className="mx_RoomDropTarget_label">
{ this.props.label }
</div>

View File

@@ -238,9 +238,10 @@ module.exports = React.createClass({
self._refreshFromServer();
}, function(error) {
var ErrorDialog = sdk.getComponent("dialogs.ErrorDialog");
console.error("Failed to change settings: " + error);
Modal.createDialog(ErrorDialog, {
title: "Can't change settings",
description: error.toString(),
title: "Error",
description: "Failed to change settings",
onFinished: self._refreshFromServer
});
});
@@ -307,9 +308,10 @@ module.exports = React.createClass({
self._refreshFromServer();
}, function(error) {
var ErrorDialog = sdk.getComponent("dialogs.ErrorDialog");
console.error("Can't update user notification settings: " + error);
Modal.createDialog(ErrorDialog, {
title: "Can't update user notification settings",
description: error.toString(),
title: "Error",
description: "Can't update user notification settings",
onFinished: self._refreshFromServer
});
});
@@ -348,9 +350,10 @@ module.exports = React.createClass({
var onError = function(error) {
var ErrorDialog = sdk.getComponent("dialogs.ErrorDialog");
console.error("Failed to update keywords: " + error);
Modal.createDialog(ErrorDialog, {
title: "Can't update keywords",
description: error.toString(),
title: "Error",
description: "Failed to update keywords",
onFinished: self._refreshFromServer
});
}
@@ -458,8 +461,8 @@ module.exports = React.createClass({
'.m.rule.master': 'master',
// The default push rules displayed by Vector UI
// XXX: .m.rule.contains_user_name is not managed (not a fancy rule for Vector?)
'.m.rule.contains_display_name': 'vector',
'.m.rule.contains_user_name': 'vector',
'.m.rule.room_one_to_one': 'vector',
'.m.rule.message': 'vector',
'.m.rule.invite_for_me': 'vector',
@@ -512,6 +515,7 @@ module.exports = React.createClass({
var vectorRuleIds = [
'.m.rule.contains_display_name',
'.m.rule.contains_user_name',
'_keywords',
'.m.rule.room_one_to_one',
'.m.rule.message',
@@ -715,20 +719,17 @@ module.exports = React.createClass({
);
}
var emailNotificationsRow;
if (this.props.threepids.filter(function(tp) {
if (tp.medium == "email") {
return true;
}
}).length == 0) {
const emailThreepids = this.props.threepids.filter((tp) => tp.medium === "email");
let emailNotificationsRow;
if (emailThreepids.length === 0) {
emailNotificationsRow = <div>
Add an email address above to configure email notifications
</div>;
} else {
// This only supports the first email address in your profile for now
emailNotificationsRow = this.emailNotificationsRow(
this.props.threepids[0].address,
"Enable email notifications ("+this.props.threepids[0].address+")"
emailThreepids[0].address,
"Enable email notifications ("+emailThreepids[0].address+")"
);
}

View File

@@ -63,10 +63,20 @@ class VectorPushRuleDefinition {
*/
module.exports = {
// Messages containing user's display name
// (skip contains_user_name which is too geeky)
".m.rule.contains_display_name": new VectorPushRuleDefinition({
kind: "override",
description: "Messages containing my name",
description: "Messages containing my display name",
vectorStateToActions: { // The actions for each vector state, or null to disable the rule.
on: StandardActions.ACTION_NOTIFY,
loud: StandardActions.ACTION_HIGHLIGHT_DEFAULT_SOUND,
off: StandardActions.ACTION_DISABLED
}
}),
// Messages containing user's username (localpart/MXID)
".m.rule.contains_user_name": new VectorPushRuleDefinition({
kind: "override",
description: "Messages containing my user name",
vectorStateToActions: { // The actions for each vector state, or null to disable the rule.
on: StandardActions.ACTION_NOTIFY,
loud: StandardActions.ACTION_HIGHLIGHT_DEFAULT_SOUND,

View File

@@ -135,7 +135,7 @@ textarea {
.mx_Dialog_wrapper.mx_Dialog_spinner .mx_Dialog {
width: auto;
border-radius: 8px;
padding-left: 0px;
padding: 0px;
box-shadow: none;
}
@@ -187,12 +187,16 @@ textarea {
}
.mx_Dialog_cancelButton {
float: right;
margin-top: 5px;
margin-right: 5px;
position: absolute;
right: 11px;
top: 13px;
cursor: pointer;
}
.mx_Dialog_cancelButton object {
pointer-events: none;
}
.mx_Dialog_content {
margin: 24px 58px 68px 0;
font-size: 14px;

View File

@@ -13,6 +13,7 @@
@import "./matrix-react-sdk/structures/login/_Login.scss";
@import "./matrix-react-sdk/views/avatars/_BaseAvatar.scss";
@import "./matrix-react-sdk/views/dialogs/_BugReportDialog.scss";
@import "./matrix-react-sdk/views/dialogs/_ChatCreateOrReuseChatDialog.scss";
@import "./matrix-react-sdk/views/dialogs/_ChatInviteDialog.scss";
@import "./matrix-react-sdk/views/dialogs/_ConfirmUserActionDialog.scss";
@import "./matrix-react-sdk/views/dialogs/_EncryptedEventDialog.scss";
@@ -21,10 +22,13 @@
@import "./matrix-react-sdk/views/elements/_AddressSelector.scss";
@import "./matrix-react-sdk/views/elements/_AddressTile.scss";
@import "./matrix-react-sdk/views/elements/_DirectorySearchBox.scss";
@import "./matrix-react-sdk/views/elements/_Dropdown.scss";
@import "./matrix-react-sdk/views/elements/_MemberEventListSummary.scss";
@import "./matrix-react-sdk/views/elements/_ProgressBar.scss";
@import "./matrix-react-sdk/views/elements/_RichText.scss";
@import "./matrix-react-sdk/views/login/_InteractiveAuthEntryComponents.scss";
@import "./matrix-react-sdk/views/login/_ServerConfig.scss";
@import "./matrix-react-sdk/views/messages/_MEmoteBody.scss";
@import "./matrix-react-sdk/views/messages/_MImageBody.scss";
@import "./matrix-react-sdk/views/messages/_MNoticeBody.scss";
@import "./matrix-react-sdk/views/messages/_MTextBody.scss";
@@ -61,8 +65,7 @@
@import "./vector-web/structures/_RoomSubList.scss";
@import "./vector-web/structures/_ViewSource.scss";
@import "./vector-web/views/context_menus/_MessageContextMenu.scss";
@import "./vector-web/views/context_menus/_NotificationStateContextMenu.scss";
@import "./vector-web/views/context_menus/_RoomTagContextMenu.scss";
@import "./vector-web/views/context_menus/_RoomTileContextMenu.scss";
@import "./vector-web/views/dialogs/_ChangelogDialog.scss";
@import "./vector-web/views/directory/_NetworkDropdown.scss";
@import "./vector-web/views/elements/_ImageView.scss";

View File

@@ -90,16 +90,13 @@ limitations under the License.
*/
overflow-x: auto;
/* XXX: Hack: apparently if you try to nest a flex-box
* within a non-flex-box within a flex-box, the height
* of the innermost element gets miscalculated if the
* parents are both auto. Height has to be auto here
* for RoomView to correctly fit when the Toolbar is shown.
* Ideally we'd launch straight into the RoomView at this
* point, but instead we fudge it and make the middlePanel
* flex itself.
*/
display: flex;
/* To fix https://github.com/vector-im/riot-web/issues/3298 where Safari
needed height 100% all the way down to the HomePage. Height does not
have to be auto, empirically.
*/
height: 100%;
}
.mx_MatrixChat .mx_RightPanel {

View File

@@ -206,8 +206,9 @@ hr.mx_RoomView_myReadMarker {
}
.mx_RoomView_inCall .mx_RoomView_statusAreaBox_line {
border-top: 1px hidden;
padding-top: 1px;
margin-top: 2px;
border: none;
height: 0px;
}
.mx_RoomView_inCall .mx_MessageComposer_wrapper {

View File

@@ -1,5 +1,6 @@
/*
Copyright 2015, 2016 OpenMarket Ltd
Copyright 2017 Vector Creations Ltd
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -175,6 +176,12 @@ limitations under the License.
cursor: pointer;
}
input.mx_UserSettings_phoneNumberField {
margin-left: 3px;
width: 172px;
border: 1px solid transparent;
}
.mx_UserSettings_changePasswordButton {
float: right;
margin-right: 32px;

View File

@@ -66,6 +66,10 @@ limitations under the License.
margin-bottom: 14px;
}
.mx_Login_username {
margin-bottom: 0px;
}
.mx_Login_fieldLabel {
margin-top: -10px;
margin-left: 8px;
@@ -163,3 +167,16 @@ limitations under the License.
margin-bottom: 12px;
}
.mx_Login_phoneSection {
display: table;
}
.mx_Login_phoneCountry {
display: table-cell;
width: 70px;
}
.mx_Login_phoneNumberField {
width: 210px;
margin-left: 3px;
}

View File

@@ -0,0 +1,27 @@
/*
Copyright 2016 OpenMarket Ltd
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
.mx_ChatCreateOrReuseDialog .mx_ChatCreateOrReuseDialog_tiles {
margin-top: 24px;
}
.mx_ChatCreateOrReuseDialog .mx_Dialog_content {
margin-bottom: 24px;
}
.mx_ChatCreateOrReuseDialog .mx_RoomTile_badge {
display: none;
}

View File

@@ -14,22 +14,39 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
.mx_ConfirmUserActionDialog .mx_Dialog_content {
min-height: 48px;
margin-bottom: 24px;
}
.mx_ConfirmUserActionDialog_avatar {
float: left;
margin-right: 20px;
margin-top: -2px;
}
.mx_ConfirmUserActionDialog_name {
font-size: 150%;
font-size: 18px;
}
.mx_ConfirmUserActionDialog_userId {
font-style: italic;
font-size: 13px;
}
.mx_ConfirmUserActionDialog_reasonField {
margin-bottom: 40px;
font-family: 'Open Sans', Arial, Helvetica, Sans-Serif;
font-size: 14px;
color: $primary-fg-color;
border-radius: 3px;
border: solid 1px $input-border-color;
line-height: 36px;
padding-left: 16px;
padding-right: 16px;
padding-top: 1px;
padding-bottom: 1px;
margin-bottom: 24px;
width: 90%;
font-size: 120%;
height: 35px;
}

View File

@@ -0,0 +1,93 @@
/*
Copyright 2017 OpenMarket Ltd
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
.mx_Dropdown {
position: relative;
}
.mx_Dropdown_input {
position: relative;
border-radius: 3px;
border: 1px solid $strong-input-border-color;
font-weight: 300;
font-size: 13px;
user-select: none;
}
.mx_Dropdown_arrow {
border-color: $primary-fg-color transparent transparent;
border-style: solid;
border-width: 5px 5px 0;
display: block;
height: 0;
position: absolute;
right: 10px;
top: 14px;
width: 0
}
.mx_Dropdown_option {
height: 35px;
line-height: 35px;
padding-left: 8px;
padding-right: 8px;
}
.mx_Dropdown_option img {
margin: 5px;
width: 25px;
vertical-align: middle;
}
input.mx_Dropdown_option, input.mx_Dropdown_option:focus {
border: 0;
padding-top: 0;
padding-bottom: 0;
// XXX: hack to prevent text box being too big and pushing
// its parent out / overlapping the dropdown arrow. Only really
// works in the Country dropdown.
width: 60%;
}
.mx_Dropdown_menu {
position: absolute;
left: -1px;
right: -1px;
top: 100%;
z-index: 2;
margin: 0;
padding: 0px;
border-radius: 3px;
border: 1px solid $accent-color;
background-color: $primary-bg-color;
max-height: 200px;
overflow-y: scroll;
}
.mx_Dropdown_menu .mx_Dropdown_option_highlight {
background-color: $focus-bg-color;
}
.mx_Dropdown_menu {
font-weight: bold;
}
.mx_Dropdown_searchPrompt {
font-weight: normal;
margin-left: 5px;
margin-bottom: 5px;
}

View File

@@ -14,6 +14,10 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
.mx_MemberEventListSummary {
position: relative;
}
.mx_TextualEvent.mx_MemberEventListSummary_summary {
font-size: 14px;
}
@@ -31,6 +35,15 @@ limitations under the License.
}
.mx_MemberEventListSummary_toggle {
color:$accent-color;
cursor:pointer;
color: $accent-color;
cursor: pointer;
float: right;
margin-right: 10px;
margin-top: 8px;
}
.mx_MemberEventListSummary_line {
border-bottom: 1px solid $primary-hairline-color;
margin-left: 63px;
line-height: 30px;
}

View File

@@ -0,0 +1,42 @@
/*
Copyright 2017 Vector Creations Ltd
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
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_InteractiveAuthEntryComponents_msisdnWrapper {
text-align: center;
}
.mx_InteractiveAuthEntryComponents_msisdnEntry {
font-size: 200%;
font-weight: bold;
border: 1px solid $strong-input-border-color;
border-radius: 3px;
width: 6em;
}
.mx_InteractiveAuthEntryComponents_msisdnEntry:focus {
border: 1px solid $accent-color;
}
.mx_InteractiveAuthEntryComponents_msisdnSubmit {
margin-top: 4px;
margin-bottom: 5px;
}
// XXX: This should be a common button class
.mx_InteractiveAuthEntryComponents_msisdnSubmit:disabled {
background-color: $light-fg-color;
cursor: default;
}

View File

@@ -0,0 +1,19 @@
/*
Copyright 2017 Vector Creations Ltd.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
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_MEmoteBody_sender {
cursor: pointer;
}

View File

@@ -130,6 +130,23 @@ limitations under the License.
color: $event-notsent-color;
}
.mx_EventTile_redacted .mx_EventTile_line .mx_UnknownBody {
display: block;
width: 100%;
height: 36px;
background-image: $event-redacted-img;
background-repeat: no-repeat;
background-size: contain;
}
.mx_EventTile.mx_EventTile_redacted .mx_EventTile_line {
/*
Prevent changing colour of the background because
$event-redacted-img matches $primary-bg-color
*/
background-color: initial !important;
}
.mx_EventTile_highlight,
.mx_EventTile_highlight .markdown-body
{
@@ -251,9 +268,9 @@ limitations under the License.
padding-left: 60px;
}
.mx_EventTile_selected .mx_EventTile_info .mx_EventTile_line,
.mx_EventTile:hover.mx_EventTile_verified .mx_EventTile_info .mx_EventTile_line,
.mx_EventTile:hover.mx_EventTile_unverified .mx_EventTile_info .mx_EventTile_line {
.mx_EventTile_selected.mx_EventTile_info .mx_EventTile_line,
.mx_EventTile:hover.mx_EventTile_verified.mx_EventTile_info .mx_EventTile_line,
.mx_EventTile:hover.mx_EventTile_unverified.mx_EventTile_info .mx_EventTile_line {
padding-left: 78px;
}

View File

@@ -38,6 +38,7 @@ limitations under the License.
.mx_LinkPreviewWidget_title {
display: inline;
font-weight: bold;
white-space: normal;
}
.mx_LinkPreviewWidget_siteName {

View File

@@ -59,41 +59,6 @@ limitations under the License.
z-index: 2;
}
.mx_RoomTile:hover .mx_RoomTile_avatar_container:before,
.mx_RoomTile_avatar_container.mx_RoomTile_avatar_roomTagMenu:before {
display: block;
position: absolute;
content: "";
border-radius: 40px;
background-image: url("../../img/icons_ellipsis.svg");
background-size: 25px;
width: 24px;
height: 24px;
z-index: 4;
}
.mx_RoomTile:hover .mx_RoomTile_avatar_container:after,
.mx_RoomTile_avatar_container.mx_RoomTile_avatar_roomTagMenu:after {
display: block;
position: absolute;
content: "";
border-radius: 40px;
background: $primary-fg-color;
bottom: 0;
width: 24px;
height: 24px;
opacity: 0.6;
z-index: 1;
}
.collapsed .mx_RoomTile:hover .mx_RoomTile_avatar_container:before {
display: none;
}
.collapsed .mx_RoomTile:hover .mx_RoomTile_avatar_container:after {
display: none;
}
.mx_RoomTile_name {
display: inline-block;
position: relative;
@@ -164,13 +129,13 @@ limitations under the License.
}
.mx_RoomTile .mx_RoomTile_badge.mx_RoomTile_badgeButton,
.mx_RoomTile.mx_RoomTile_notificationStateMenu .mx_RoomTile_badge {
.mx_RoomTile.mx_RoomTile_menuDisplayed .mx_RoomTile_badge {
letter-spacing: 0.1em;
opacity: 1;
}
.mx_RoomTile.mx_RoomTile_noBadges .mx_RoomTile_badge.mx_RoomTile_badgeButton,
.mx_RoomTile.mx_RoomTile_notificationStateMenu.mx_RoomTile_noBadges .mx_RoomTile_badge {
.mx_RoomTile.mx_RoomTile_menuDisplayed.mx_RoomTile_noBadges .mx_RoomTile_badge {
background-color: $neutral-badge-color;
}

View File

@@ -20,11 +20,17 @@ limitations under the License.
padding-top: 5px;
padding-bottom: 5px;
border-bottom: 1px solid $primary-hairline-color;
/* in absence of img */
height: 24px;
}
.mx_TopUnreadMessagesBar_scrollUp {
display: inline;
cursor: pointer;
/* in absence of img */
padding-left: 65px;
}
.mx_TopUnreadMessagesBar_scrollUp img {

View File

@@ -93,6 +93,9 @@ $event-encrypting-color: #abddbc;
$event-sending-color: #ddd;
$event-notsent-color: #f44;
// event redaction
$event-redacted-img: url('../../img/redacted.jpg');
// event timestamp
$event-timestamp-color: #acacac;

View File

@@ -93,6 +93,9 @@ $event-encrypting-color: rgba(171, 221, 188, 0.4);
$event-sending-color: #888;
$event-notsent-color: #f44;
// event redaction
$event-redacted-img: url('../../img/redacted-dark.jpg');
// event timestamp
$event-timestamp-color: #acacac;
@@ -115,17 +118,17 @@ $progressbar-color: #000;
// better match the theme. Typically applied to dark grey 'off' buttons or
// light grey 'on' buttons.
.mx_filterFlipColor {
filter: invert();
filter: invert(1);
}
.gm-scrollbar .thumb {
filter: invert();
filter: invert(1);
}
// markdown overrides:
.mx_EventTile_content .markdown-body {
pre, code {
filter: invert();
filter: invert(1);
}
pre code {

View File

@@ -18,6 +18,8 @@ limitations under the License.
.mx_HomePage {
max-width: 960px;
width: 100%;
height: 100%;
overflow-y: hidden;
margin-left: auto;
margin-right: auto;
}

View File

@@ -1,56 +0,0 @@
/*
Copyright 2015, 2016 OpenMarket Ltd
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
.mx_NotificationStateContextMenu_picker {
position: absolute;
top: 16px;
left: 5px;
}
.mx_NotificationStateContextMenu_field {
padding-top: 4px;
padding-right: 6px;
padding-bottom: 10px;
padding-left: 8px; /* 20px */
cursor: pointer;
white-space: nowrap;
display: flex;
align-items: center;
}
.mx_NotificationStateContextMenu_field.mx_NotificationStateContextMenu_fieldSet {
font-weight: bold;
}
.mx_NotificationStateContextMenu_field.mx_NotificationStateContextMenu_fieldDisabled {
color: rgba(0, 0, 0, 0.2);
}
.mx_NotificationStateContextMenu_icon {
padding-right: 4px;
padding-left: 4px;
}
.mx_NotificationStateContextMenu_activeIcon {
display: inline-block;
opacity: 0;
position: relative;
left: -5px;
}
.mx_NotificationStateContextMenu_fieldSet .mx_NotificationStateContextMenu_activeIcon {
opacity: 1;
}

View File

@@ -1,78 +0,0 @@
/*
Copyright 2015, 2016 OpenMarket Ltd
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
.mx_RoomTagContextMenu_field {
padding-top: 8px;
padding-right: 20px;
padding-bottom: 8px;
cursor: pointer;
white-space: nowrap;
display: flex;
align-items: center;
line-height: 16px;
}
.mx_RoomTagContextMenu_field:first-child {
padding-top: 4px;
}
.mx_RoomTagContextMenu_field:last-child {
padding-bottom: 4px;
color: $warning-color;
}
.mx_RoomTagContextMenu_field.mx_RoomTagContextMenu_fieldSet {
font-weight: bold;
}
.mx_RoomTagContextMenu_field.mx_RoomTagContextMenu_fieldSet .mx_RoomTagContextMenu_icon {
display: none;
}
.mx_RoomTagContextMenu_field.mx_RoomTagContextMenu_fieldSet .mx_RoomTagContextMenu_icon_set {
display: inline-block;
}
.mx_RoomTagContextMenu_field.mx_RoomTagContextMenu_fieldDisabled {
color: rgba(0, 0, 0, 0.2);
}
.mx_RoomTagContextMenu_icon {
padding-right: 8px;
padding-left: 4px;
display: inline-block
}
.mx_RoomTagContextMenu_icon_set {
padding-right: 8px;
padding-left: 4px;
display: none;
}
.mx_RoomTagContextMenu_separator {
margin-top: 0;
margin-bottom: 0;
border-bottom-style: none;
border-left-style: none;
border-right-style: none;
border-top-style: solid;
border-top-width: 1px;
border-color: $menu-border-color;
}
.mx_RoomTagContextMenu_fieldSet .mx_RoomTagContextMenu_icon {
/* Something to indicate that the icon is the set tag */
}

View File

@@ -0,0 +1,114 @@
/*
Copyright 2015, 2016 OpenMarket Ltd
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
.mx_RoomTileContextMenu_tag_field, .mx_RoomTileContextMenu_leave {
padding-top: 8px;
padding-right: 20px;
padding-bottom: 8px;
cursor: pointer;
white-space: nowrap;
display: flex;
align-items: center;
line-height: 16px;
}
.mx_RoomTileContextMenu_tag_field.mx_RoomTileContextMenu_tag_fieldSet {
font-weight: bold;
}
.mx_RoomTileContextMenu_tag_field.mx_RoomTileContextMenu_tag_fieldSet .mx_RoomTileContextMenu_tag_icon {
display: none;
}
.mx_RoomTileContextMenu_tag_field.mx_RoomTileContextMenu_tag_fieldSet .mx_RoomTileContextMenu_tag_icon_set {
display: inline-block;
}
.mx_RoomTileContextMenu_tag_field.mx_RoomTileContextMenu_tag_fieldDisabled {
color: rgba(0, 0, 0, 0.2);
}
.mx_RoomTileContextMenu_tag_icon {
padding-right: 8px;
padding-left: 4px;
display: inline-block
}
.mx_RoomTileContextMenu_tag_icon_set {
padding-right: 8px;
padding-left: 4px;
display: none;
}
.mx_RoomTileContextMenu_separator {
margin-top: 0;
margin-bottom: 0;
border-bottom-style: none;
border-left-style: none;
border-right-style: none;
border-top-style: solid;
border-top-width: 1px;
border-color: $menu-border-color;
}
.mx_RoomTileContextMenu_leave {
color: $warning-color;
}
.mx_RoomTileContextMenu_tag_fieldSet .mx_RoomTileContextMenu_tag_icon {
/* Something to indicate that the icon is the set tag */
}
.mx_RoomTileContextMenu_notif_picker {
position: absolute;
top: 16px;
left: 5px;
}
.mx_RoomTileContextMenu_notif_field {
padding-top: 4px;
padding-right: 6px;
padding-bottom: 10px;
padding-left: 8px; /* 20px */
cursor: pointer;
white-space: nowrap;
display: flex;
align-items: center;
}
.mx_RoomTileContextMenu_notif_field.mx_RoomTileContextMenu_notif_fieldSet {
font-weight: bold;
}
.mx_RoomTileContextMenu_notif_field.mx_RoomTileContextMenu_notif_fieldDisabled {
color: rgba(0, 0, 0, 0.2);
}
.mx_RoomTileContextMenu_notif_icon {
padding-right: 4px;
padding-left: 4px;
}
.mx_RoomTileContextMenu_notif_activeIcon {
display: inline-block;
opacity: 0;
position: relative;
left: -5px;
}
.mx_RoomTileContextMenu_notif_fieldSet .mx_RoomTileContextMenu_notif_activeIcon {
opacity: 1;
}

View File

@@ -44,6 +44,9 @@ limitations under the License.
line-height: 35px;
padding-left: 8px;
padding-right: 8px;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
}
.mx_NetworkDropdown_networkoption img {

View File

@@ -38,21 +38,12 @@ limitations under the License.
padding-bottom: 1px;
}
.mx_RoomDropTarget_avatar {
background-color: $primary-bg-color;
border-radius: 24px;
width: 24px;
height: 24px;
float: left;
margin-left: 7px;
margin-right: 7px;
}
.mx_RoomDropTarget_label {
position: relative;
margin-top: 3px;
line-height: 21px;
z-index: 1;
text-align: center;
}
.collapsed .mx_RoomDropTarget_avatar {

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.2 KiB

View File

@@ -37,8 +37,19 @@
<body style="height: 100%;">
<section id="matrixchat" style="height: 100%;"></section>
<noscript>Sorry, Riot requires JavaScript to be enabled.</noscript>
<% for (var i=0; i < htmlWebpackPlugin.files.js.length; i++) {%>
<script src="<%= htmlWebpackPlugin.files.js[i] %>"></script>
<% for (var i=0; i < htmlWebpackPlugin.files.js.length; i++) {
// Not a particularly graceful way of not putting the indexeddb worker script
// into the main page
if (_.endsWith(htmlWebpackPlugin.files.js[i], 'indexeddb-worker.js')) {
%>
<script>
window.vector_indexeddb_worker_script = '<%= htmlWebpackPlugin.files.js[i] %>';
</script>
<%
continue;
}
%>
<script src="<%= htmlWebpackPlugin.files.js[i] %>"></script>
<% } %>
<img src="img/warning.svg" width="24" height="23" style="visibility: hidden; position: absolute; top: 0px; left: 0px;"/>
<audio id="messageAudio">

View File

@@ -1,5 +1,6 @@
/*
Copyright 2015, 2016 OpenMarket Ltd
Copyright 2017 Vector Creations Ltd
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -49,7 +50,7 @@ rageshake.init().then(() => {
// access via the console
global.React = require("react");
if (process.env.NODE_ENV !== 'production') {
global.ReactPerf = require("react-addons-perf");
global.Perf = require("react-addons-perf");
}
var RunModernizrTests = require("./modernizr"); // this side-effects a global
@@ -67,11 +68,15 @@ import url from 'url';
import {parseQs, parseQsFromFragment} from './url_utils';
import Platform from './platform';
import MatrixClientPeg from 'matrix-react-sdk/lib/MatrixClientPeg';
var lastLocationHashSet = null;
var CallHandler = require("matrix-react-sdk/lib/CallHandler");
CallHandler.setConferenceHandler(VectorConferenceHandler);
MatrixClientPeg.setIndexedDbWorkerScript(window.vector_indexeddb_worker_script);
function checkBrowserFeatures(featureList) {
if (!window.Modernizr) {
console.error("Cannot check features - Modernizr global is missing.");
@@ -101,15 +106,24 @@ var validBrowser = checkBrowserFeatures([
"objectfit"
]);
// Parse the given window.location and return parameters that can be used when calling
// MatrixChat.showScreen(screen, params)
function getScreenFromLocation(location) {
const fragparts = parseQsFromFragment(location);
return {
screen: fragparts.location.substring(1),
params: fragparts.params,
}
}
// Here, we do some crude URL analysis to allow
// deep-linking.
function routeUrl(location) {
if (!window.matrixChat) return;
console.log("Routing URL "+location);
var fragparts = parseQsFromFragment(location);
window.matrixChat.showScreen(fragparts.location.substring(1),
fragparts.params);
console.log("Routing URL ", location.href);
const s = getScreenFromLocation(location);
window.matrixChat.showScreen(s.screen, s.params);
}
function onHashChange(ev) {
@@ -120,22 +134,13 @@ function onHashChange(ev) {
routeUrl(window.location);
}
var loaded = false;
var lastLoadedScreen = null;
// This will be called whenever the SDK changes screens,
// so a web page can update the URL bar appropriately.
var onNewScreen = function(screen) {
console.log("newscreen "+screen);
// just remember the most recent screen while we are loading, so that the
// user doesn't see the URL bar doing a dance
if (!loaded) {
lastLoadedScreen = screen;
} else {
var hash = '#/' + screen;
lastLocationHashSet = hash;
window.location.hash = hash;
}
var hash = '#/' + screen;
lastLocationHashSet = hash;
window.location.hash = hash;
}
// We use this to work out what URL the SDK should
@@ -147,16 +152,30 @@ var onNewScreen = function(screen) {
// If we're in electron, we should never pass through a file:// URL otherwise
// the identity server will try to 302 the browser to it, which breaks horribly.
// so in that instance, hardcode to use riot.im/app for now instead.
var makeRegistrationUrl = function() {
var makeRegistrationUrl = function(params) {
let url;
if (window.location.protocol === "file:") {
return 'https://riot.im/app/#/register';
url = 'https://riot.im/app/#/register';
} else {
url = (
window.location.protocol + '//' +
window.location.host +
window.location.pathname +
'#/register'
);
}
else {
return window.location.protocol + '//' +
window.location.host +
window.location.pathname +
'#/register';
const keys = Object.keys(params);
for (let i = 0; i < keys.length; ++i) {
if (i == 0) {
url += '?';
} else {
url += '&';
}
const k = keys[i];
url += k + '=' + encodeURIComponent(params[k]);
}
return url;
}
window.addEventListener('hashchange', onHashChange);
@@ -253,31 +272,22 @@ async function loadApp() {
} else if (validBrowser) {
UpdateChecker.start();
var MatrixChat = sdk.getComponent('structures.MatrixChat');
const MatrixChat = sdk.getComponent('structures.MatrixChat');
window.matrixChat = ReactDOM.render(
<MatrixChat
onNewScreen={onNewScreen}
registrationUrl={makeRegistrationUrl()}
makeRegistrationUrl={makeRegistrationUrl}
ConferenceHandler={VectorConferenceHandler}
config={configJson}
realQueryParams={params}
startingFragmentQueryParams={fragparts.params}
enableGuest={true}
onLoadCompleted={onLoadCompleted}
initialScreenAfterLogin={getScreenFromLocation(window.location)}
defaultDeviceDisplayName={PlatformPeg.get().getDefaultDeviceDisplayName()}
/>,
document.getElementById('matrixchat')
);
routeUrl(window.location);
// we didn't propagate screen changes to the URL bar while we were loading; do it now.
loaded = true;
if (lastLoadedScreen) {
onNewScreen(lastLoadedScreen);
lastLoadedScreen = null;
}
}
else {
console.error("Browser is missing required features.");

View File

@@ -0,0 +1,21 @@
/*
Copyright 2017 Vector Creations Ltd
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
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 {IndexedDBStoreWorker} from 'matrix-js-sdk/lib/indexeddb-worker.js';
const remoteWorker = new IndexedDBStoreWorker(postMessage);
onmessage = remoteWorker.onMessage;

View File

@@ -139,4 +139,8 @@ export default class ElectronPlatform extends VectorBasePlatform {
requestNotificationPermission() : Promise {
return q('granted');
}
reload() {
electron.remote.getCurrentWebContents().reload();
}
}

View File

@@ -206,4 +206,10 @@ export default class WebPlatform extends VectorBasePlatform {
}
return null;
}
reload() {
// forceReload=false since we don't really need new HTML/JS files
// we just need to restart the JS runtime.
window.location.reload(false);
}
}

View File

@@ -314,17 +314,24 @@ class IndexedDBLogStore {
let size = 0;
for (let i = 0; i < allLogIds.length; i++) {
let lines = await fetchLogs(allLogIds[i]);
// always include at least one log file, but only include
// subsequent ones if they won't take us over the MAX_LOG_SIZE
if (i > 0 && size + lines.length > MAX_LOG_SIZE) {
// the remaining log IDs should be removed. If we go out of
// bounds this is just []
//
// XXX: there's nothing stopping the current session exceeding
// MAX_LOG_SIZE. We ought to think about culling it.
removeLogIds = allLogIds.slice(i + 1);
break;
}
logs.push({
lines: lines,
id: allLogIds[i],
});
size += lines.length;
if (size > MAX_LOG_SIZE) {
// the remaining log IDs should be removed. If we go out of
// bounds this is just []
removeLogIds = allLogIds.slice(i + 1);
break;
}
}
if (removeLogIds.length > 0) {
console.log("Removing logs: ", removeLogIds);
@@ -481,10 +488,12 @@ module.exports = {
text: (
userText || "User did not supply any additional text."
),
app: 'riot-web',
version: version,
user_agent: userAgent,
},
json: true,
timeout: 5 * 60 * 1000,
}, (err, res) => {
if (err) {
reject(err);

View File

@@ -23,6 +23,7 @@ var jssdk = require('matrix-js-sdk');
var sdk = require('matrix-react-sdk');
var peg = require('matrix-react-sdk/lib/MatrixClientPeg');
var dis = require('matrix-react-sdk/lib/dispatcher');
var PageTypes = require('matrix-react-sdk/lib/PageTypes');
var MatrixChat = sdk.getComponent('structures.MatrixChat');
var RoomDirectory = sdk.getComponent('structures.RoomDirectory');
var RoomPreviewBar = sdk.getComponent('rooms.RoomPreviewBar');
@@ -90,9 +91,7 @@ describe('joining a room', function () {
matrixChat = ReactDOM.render(mc, parentDiv);
// switch to the Directory
dis.dispatch({
action: 'view_room_directory',
});
matrixChat._setPage(PageTypes.RoomDirectory);
var roomView;
// wait for /sync to happen

View File

@@ -104,6 +104,23 @@ describe('loading:', function () {
}
}
// Parse the given window.location and return parameters that can be used when calling
// MatrixChat.showScreen(screen, params)
function getScreenFromLocation(location) {
const fragparts = parseQsFromFragment(location);
return {
screen: fragparts.location.substring(1),
params: fragparts.params,
}
}
function routeUrl(location, matrixChat) {
console.log(Date.now() + "Routing URL " + location);
const s = getScreenFromLocation(location);
console.log("Showing screen", s);
matrixChat.showScreen(s.screen, s.params);
}
const MatrixChat = sdk.getComponent('structures.MatrixChat');
const fragParts = parseQsFromFragment(windowLocation);
var params = parseQs(windowLocation);
@@ -118,16 +135,10 @@ describe('loading:', function () {
startingFragmentQueryParams={fragParts.params}
enableGuest={true}
onLoadCompleted={loadCompleteDefer.resolve}
initialScreenAfterLogin={getScreenFromLocation(windowLocation)}
/>, parentDiv
);
function routeUrl(location, matrixChat) {
console.log(Date.now() + " Routing URL "+location);
var fragparts = parseQsFromFragment(location);
matrixChat.showScreen(fragparts.location.substring(1),
fragparts.params);
}
// pause for a cycle, then simulate the window.onload handler
window.setTimeout(() => {
console.log(Date.now() + " simulating window.onload");
@@ -188,15 +199,17 @@ describe('loading:', function () {
let login = ReactTestUtils.findRenderedComponentWithType(
matrixChat, sdk.getComponent('structures.login.Login'));
httpBackend.when('POST', '/login').check(function(req) {
console.log(req);
expect(req.data.type).toEqual('m.login.password');
expect(req.data.user).toEqual('user');
expect(req.data.identifier.type).toEqual('m.id.user');
expect(req.data.identifier.user).toEqual('user');
expect(req.data.password).toEqual('pass');
}).respond(200, {
user_id: '@user:id',
device_id: 'DEVICE_ID',
access_token: 'access_token',
});
login.onPasswordLogin("user", "pass")
login.onPasswordLogin("user", undefined, undefined, "pass")
return httpBackend.flush();
}).then(() => {
// Wait for another trip around the event loop for the UI to update
@@ -474,7 +487,8 @@ function awaitRoomView(matrixChat, retryLimit, retryCount) {
retryCount = 0;
}
if (!matrixChat.state.ready) {
if (matrixChat.state.loading ||
!(matrixChat.state.loggedIn && matrixChat.state.ready)) {
console.log(Date.now() + " Awaiting room view: not ready yet.");
if (retryCount >= retryLimit) {
throw new Error("MatrixChat still not ready after " +

View File

@@ -6,6 +6,7 @@ var HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
entry: {
"bundle": "./src/vector/index.js",
"indexeddb-worker": "./src/vector/indexedbd-worker.js",
// We ship olm.js as a separate lump of javascript. This makes it get
// loaded via a separate <script/> tag in index.html (which loads it