mirror of
https://github.com/SchildiChat/element-web.git
synced 2024-10-01 01:26:12 -04:00
Merge remote-tracking branch 'origin/develop' into dbkr/add_finnish
This commit is contained in:
commit
133e17c1db
47
CHANGELOG.md
47
CHANGELOG.md
@ -1,3 +1,50 @@
|
|||||||
|
Changes in [0.12.6](https://github.com/vector-im/riot-web/releases/tag/v0.12.6) (2017-09-21)
|
||||||
|
============================================================================================
|
||||||
|
[Full Changelog](https://github.com/vector-im/riot-web/compare/v0.12.5...v0.12.6)
|
||||||
|
|
||||||
|
* Use matrix-js-sdk v0.8.4 to fix build
|
||||||
|
|
||||||
|
Changes in [0.12.5](https://github.com/vector-im/riot-web/releases/tag/v0.12.5) (2017-09-21)
|
||||||
|
============================================================================================
|
||||||
|
[Full Changelog](https://github.com/vector-im/riot-web/compare/v0.12.4...v0.12.5)
|
||||||
|
|
||||||
|
* Use react-sdk v0.10.5 to fix build
|
||||||
|
|
||||||
|
Changes in [0.12.4](https://github.com/vector-im/riot-web/releases/tag/v0.12.4) (2017-09-20)
|
||||||
|
============================================================================================
|
||||||
|
[Full Changelog](https://github.com/vector-im/riot-web/compare/v0.12.4-rc.1...v0.12.4)
|
||||||
|
|
||||||
|
* No changes
|
||||||
|
|
||||||
|
Changes in [0.12.4-rc.1](https://github.com/vector-im/riot-web/releases/tag/v0.12.4-rc.1) (2017-09-19)
|
||||||
|
======================================================================================================
|
||||||
|
[Full Changelog](https://github.com/vector-im/riot-web/compare/v0.12.3...v0.12.4-rc.1)
|
||||||
|
|
||||||
|
* Fix test for new behaviour of 'joining' flag
|
||||||
|
[\#5053](https://github.com/vector-im/riot-web/pull/5053)
|
||||||
|
* fix really dumb blunder/typo preventing system from going to sleep.
|
||||||
|
[\#5080](https://github.com/vector-im/riot-web/pull/5080)
|
||||||
|
* T3chguy/devtools
|
||||||
|
[\#4735](https://github.com/vector-im/riot-web/pull/4735)
|
||||||
|
* CSS for unignore button in UserSettings
|
||||||
|
[\#5042](https://github.com/vector-im/riot-web/pull/5042)
|
||||||
|
* Fix alias on home page for identity room
|
||||||
|
[\#5044](https://github.com/vector-im/riot-web/pull/5044)
|
||||||
|
* generic contextual menu for tooltip/responses
|
||||||
|
[\#4989](https://github.com/vector-im/riot-web/pull/4989)
|
||||||
|
* Update from Weblate.
|
||||||
|
[\#5018](https://github.com/vector-im/riot-web/pull/5018)
|
||||||
|
* Avoid re-rendering RoomList on room switch
|
||||||
|
[\#5015](https://github.com/vector-im/riot-web/pull/5015)
|
||||||
|
* Fix menu on change keyboard language issue #4345
|
||||||
|
[\#4623](https://github.com/vector-im/riot-web/pull/4623)
|
||||||
|
* Make isInvite default to false
|
||||||
|
[\#4999](https://github.com/vector-im/riot-web/pull/4999)
|
||||||
|
* Revert "Implement sticky date separators"
|
||||||
|
[\#4991](https://github.com/vector-im/riot-web/pull/4991)
|
||||||
|
* Implement sticky date separators
|
||||||
|
[\#4939](https://github.com/vector-im/riot-web/pull/4939)
|
||||||
|
|
||||||
Changes in [0.12.3](https://github.com/vector-im/riot-web/releases/tag/v0.12.3) (2017-09-06)
|
Changes in [0.12.3](https://github.com/vector-im/riot-web/releases/tag/v0.12.3) (2017-09-06)
|
||||||
============================================================================================
|
============================================================================================
|
||||||
[Full Changelog](https://github.com/vector-im/riot-web/compare/v0.12.3-rc.3...v0.12.3)
|
[Full Changelog](https://github.com/vector-im/riot-web/compare/v0.12.3-rc.3...v0.12.3)
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
"name": "riot-web",
|
"name": "riot-web",
|
||||||
"productName": "Riot",
|
"productName": "Riot",
|
||||||
"main": "src/electron-main.js",
|
"main": "src/electron-main.js",
|
||||||
"version": "0.12.3",
|
"version": "0.12.6",
|
||||||
"description": "A feature-rich client for Matrix.org",
|
"description": "A feature-rich client for Matrix.org",
|
||||||
"author": "Vector Creations Ltd.",
|
"author": "Vector Creations Ltd.",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
@ -84,7 +84,7 @@ let powerSaveBlockerId;
|
|||||||
electron.ipcMain.on('app_onAction', function(ev, payload) {
|
electron.ipcMain.on('app_onAction', function(ev, payload) {
|
||||||
switch (payload.action) {
|
switch (payload.action) {
|
||||||
case 'call_state':
|
case 'call_state':
|
||||||
if (powerSaveBlockerId && powerSaveBlockerId.isStarted(powerSaveBlockerId)) {
|
if (powerSaveBlockerId && electron.powerSaveBlocker.isStarted(powerSaveBlockerId)) {
|
||||||
if (payload.state === 'ended') {
|
if (payload.state === 'ended') {
|
||||||
electron.powerSaveBlocker.stop(powerSaveBlockerId);
|
electron.powerSaveBlocker.stop(powerSaveBlockerId);
|
||||||
}
|
}
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
"name": "riot-web",
|
"name": "riot-web",
|
||||||
"productName": "Riot",
|
"productName": "Riot",
|
||||||
"main": "electron_app/src/electron-main.js",
|
"main": "electron_app/src/electron-main.js",
|
||||||
"version": "0.12.3",
|
"version": "0.12.6",
|
||||||
"description": "A feature-rich client for Matrix.org",
|
"description": "A feature-rich client for Matrix.org",
|
||||||
"author": "Vector Creations Ltd.",
|
"author": "Vector Creations Ltd.",
|
||||||
"repository": {
|
"repository": {
|
||||||
@ -47,7 +47,7 @@
|
|||||||
"lint": "eslint src/",
|
"lint": "eslint src/",
|
||||||
"lintall": "eslint src/ test/",
|
"lintall": "eslint src/ test/",
|
||||||
"clean": "rimraf lib webapp electron_app/dist",
|
"clean": "rimraf lib webapp electron_app/dist",
|
||||||
"prepublish": "npm run build:compile",
|
"prepublish": "npm run clean && npm run build:compile",
|
||||||
"test": "karma start --single-run=true --autoWatch=false --browsers ChromeHeadless",
|
"test": "karma start --single-run=true --autoWatch=false --browsers ChromeHeadless",
|
||||||
"test-multi": "karma start"
|
"test-multi": "karma start"
|
||||||
},
|
},
|
||||||
@ -66,8 +66,8 @@
|
|||||||
"gfm.css": "^1.1.1",
|
"gfm.css": "^1.1.1",
|
||||||
"highlight.js": "^9.0.0",
|
"highlight.js": "^9.0.0",
|
||||||
"linkifyjs": "^2.1.3",
|
"linkifyjs": "^2.1.3",
|
||||||
"matrix-js-sdk": "0.8.2",
|
"matrix-js-sdk": "0.8.4",
|
||||||
"matrix-react-sdk": "0.10.3",
|
"matrix-react-sdk": "0.10.6",
|
||||||
"modernizr": "^3.1.0",
|
"modernizr": "^3.1.0",
|
||||||
"pako": "^1.0.5",
|
"pako": "^1.0.5",
|
||||||
"prop-types": "^15.5.10",
|
"prop-types": "^15.5.10",
|
||||||
|
@ -249,7 +249,7 @@
|
|||||||
<span class="mx_HomePage_desc">_t("Implementing VoIP services with Matrix")</span>
|
<span class="mx_HomePage_desc">_t("Implementing VoIP services with Matrix")</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="mx_HomePage_room">
|
<div class="mx_HomePage_room">
|
||||||
<a href="#/room/#identity:matrix.org">
|
<a href="#/room/#matrix-identity:matrix.org">
|
||||||
<img class="mx_HomePage_icon" src="home/rooms/identity.jpg">
|
<img class="mx_HomePage_icon" src="home/rooms/identity.jpg">
|
||||||
<span class="mx_HomePage_name">Matrix Identity</span>
|
<span class="mx_HomePage_name">Matrix Identity</span>
|
||||||
</a>
|
</a>
|
||||||
|
@ -14,6 +14,7 @@ import subprocess
|
|||||||
import sys
|
import sys
|
||||||
import tarfile
|
import tarfile
|
||||||
import shutil
|
import shutil
|
||||||
|
import glob
|
||||||
|
|
||||||
try:
|
try:
|
||||||
# python3
|
# python3
|
||||||
@ -66,7 +67,7 @@ class Deployer:
|
|||||||
self.bundles_path = None
|
self.bundles_path = None
|
||||||
self.should_clean = False
|
self.should_clean = False
|
||||||
# filename -> symlink path e.g 'config.localhost.json' => '../localhost/config.json'
|
# filename -> symlink path e.g 'config.localhost.json' => '../localhost/config.json'
|
||||||
self.config_locations = {}
|
self.symlink_paths = {}
|
||||||
self.verify_signature = True
|
self.verify_signature = True
|
||||||
|
|
||||||
def deploy(self, tarball, extract_path):
|
def deploy(self, tarball, extract_path):
|
||||||
@ -98,11 +99,11 @@ class Deployer:
|
|||||||
|
|
||||||
print ("Extracted into: %s" % extracted_dir)
|
print ("Extracted into: %s" % extracted_dir)
|
||||||
|
|
||||||
if self.config_locations:
|
if self.symlink_paths:
|
||||||
for config_filename, config_loc in self.config_locations.iteritems():
|
for link_path, file_path in self.symlink_paths.iteritems():
|
||||||
create_relative_symlink(
|
create_relative_symlink(
|
||||||
target=config_loc,
|
target=file_path,
|
||||||
linkname=os.path.join(extracted_dir, config_filename)
|
linkname=os.path.join(extracted_dir, link_path)
|
||||||
)
|
)
|
||||||
|
|
||||||
if self.bundles_path:
|
if self.bundles_path:
|
||||||
@ -165,9 +166,10 @@ if __name__ == "__main__":
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
"--config", nargs='?', default='./config.json', help=(
|
"--include", nargs='*', default='./config*.json', help=(
|
||||||
"Write a symlink at config.json in the extracted tarball to this \
|
"Symlink these files into the root of the deployed tarball. \
|
||||||
location. (Default: '%(default)s')"
|
Useful for config files and home pages. Supports glob syntax. \
|
||||||
|
(Default: '%(default)s')"
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
@ -182,8 +184,8 @@ if __name__ == "__main__":
|
|||||||
deployer.packages_path = args.packages_dir
|
deployer.packages_path = args.packages_dir
|
||||||
deployer.bundles_path = args.bundles_dir
|
deployer.bundles_path = args.bundles_dir
|
||||||
deployer.should_clean = args.clean
|
deployer.should_clean = args.clean
|
||||||
deployer.config_locations = {
|
|
||||||
"config.json": args.config,
|
for include in args.include:
|
||||||
}
|
deployer.symlink_paths.update({ os.path.basename(pth): pth for pth in glob.iglob(include) })
|
||||||
|
|
||||||
deployer.deploy(args.tarball, args.extract_path)
|
deployer.deploy(args.tarball, args.extract_path)
|
||||||
|
@ -15,6 +15,7 @@ import json, requests, tarfile, argparse, os, errno
|
|||||||
import time
|
import time
|
||||||
import traceback
|
import traceback
|
||||||
from urlparse import urljoin
|
from urlparse import urljoin
|
||||||
|
import glob
|
||||||
|
|
||||||
from flask import Flask, jsonify, request, abort
|
from flask import Flask, jsonify, request, abort
|
||||||
|
|
||||||
@ -188,15 +189,12 @@ if __name__ == "__main__":
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
def _raise(ex):
|
# --include ../../config.json ./localhost.json homepages/*
|
||||||
raise ex
|
|
||||||
|
|
||||||
# --config config.json=../../config.json --config config.localhost.json=./localhost.json
|
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
"--config", action="append", dest="configs",
|
"--include", nargs='*', default='./config*.json', help=(
|
||||||
type=lambda kv: kv.split("=", 1) if "=" in kv else _raise(Exception("Missing =")), help=(
|
"Symlink these files into the root of the deployed tarball. \
|
||||||
"A list of configs to symlink into the extracted tarball. \
|
Useful for config files and home pages. Supports glob syntax. \
|
||||||
For example, --config config.json=../config.json config2.json=../test/config.json"
|
(Default: '%(default)s')"
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
@ -220,7 +218,9 @@ if __name__ == "__main__":
|
|||||||
deployer = Deployer()
|
deployer = Deployer()
|
||||||
deployer.bundles_path = args.bundles_dir
|
deployer.bundles_path = args.bundles_dir
|
||||||
deployer.should_clean = args.clean
|
deployer.should_clean = args.clean
|
||||||
deployer.config_locations = dict(args.configs) if args.configs else {}
|
|
||||||
|
for include in args.include:
|
||||||
|
deployer.symlink_paths.update({ os.path.basename(pth): pth for pth in glob.iglob(include) })
|
||||||
|
|
||||||
|
|
||||||
# we don't pgp-sign jenkins artifacts; instead we rely on HTTPS access to
|
# we don't pgp-sign jenkins artifacts; instead we rely on HTTPS access to
|
||||||
@ -234,13 +234,13 @@ if __name__ == "__main__":
|
|||||||
deploy_tarball(args.tarball_uri, build_dir)
|
deploy_tarball(args.tarball_uri, build_dir)
|
||||||
else:
|
else:
|
||||||
print(
|
print(
|
||||||
"Listening on port %s. Extracting to %s%s. Symlinking to %s. Jenkins URL: %s. Config locations: %s" %
|
"Listening on port %s. Extracting to %s%s. Symlinking to %s. Jenkins URL: %s. Include files: %s" %
|
||||||
(args.port,
|
(args.port,
|
||||||
arg_extract_path,
|
arg_extract_path,
|
||||||
" (clean after)" if deployer.should_clean else "",
|
" (clean after)" if deployer.should_clean else "",
|
||||||
arg_symlink,
|
arg_symlink,
|
||||||
arg_jenkins_url,
|
arg_jenkins_url,
|
||||||
deployer.config_locations,
|
deployer.symlink_paths,
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
app.run(host="0.0.0.0", port=args.port, debug=True)
|
app.run(host="0.0.0.0", port=args.port, debug=True)
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
Copyright 2015, 2016 OpenMarket Ltd
|
Copyright 2015, 2016 OpenMarket Ltd
|
||||||
|
Copyright 2017 Vector Creations Ltd
|
||||||
|
Copyright 2017 New Vector Ltd
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
you may not use this file except in compliance with the License.
|
you may not use this file except in compliance with the License.
|
||||||
@ -14,8 +16,6 @@ See the License for the specific language governing permissions and
|
|||||||
limitations under the License.
|
limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
'use strict';
|
|
||||||
|
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { _t } from 'matrix-react-sdk/lib/languageHandler';
|
import { _t } from 'matrix-react-sdk/lib/languageHandler';
|
||||||
import sdk from 'matrix-react-sdk';
|
import sdk from 'matrix-react-sdk';
|
||||||
@ -26,26 +26,31 @@ import Analytics from 'matrix-react-sdk/lib/Analytics';
|
|||||||
import rate_limited_func from 'matrix-react-sdk/lib/ratelimitedfunc';
|
import rate_limited_func from 'matrix-react-sdk/lib/ratelimitedfunc';
|
||||||
import Modal from 'matrix-react-sdk/lib/Modal';
|
import Modal from 'matrix-react-sdk/lib/Modal';
|
||||||
import AccessibleButton from 'matrix-react-sdk/lib/components/views/elements/AccessibleButton';
|
import AccessibleButton from 'matrix-react-sdk/lib/components/views/elements/AccessibleButton';
|
||||||
|
import { showGroupInviteDialog } from 'matrix-react-sdk/lib/GroupInvite';
|
||||||
|
|
||||||
module.exports = React.createClass({
|
module.exports = React.createClass({
|
||||||
displayName: 'RightPanel',
|
displayName: 'RightPanel',
|
||||||
|
|
||||||
propTypes: {
|
propTypes: {
|
||||||
// TODO: This should not be a prop, it should be received from the RoomViewStore
|
// TODO: We're trying to move away from these being props, but we need to know
|
||||||
|
// whether we should be displaying a room or group member list
|
||||||
roomId: React.PropTypes.string, // if showing panels for a given room, this is set
|
roomId: React.PropTypes.string, // if showing panels for a given room, this is set
|
||||||
|
groupId: React.PropTypes.string, // if showing panels for a given group, this is set
|
||||||
collapsed: React.PropTypes.bool, // currently unused property to request for a minimized view of the panel
|
collapsed: React.PropTypes.bool, // currently unused property to request for a minimized view of the panel
|
||||||
},
|
},
|
||||||
|
|
||||||
Phase: {
|
Phase: {
|
||||||
MemberList: 'MemberList',
|
RoomMemberList: 'RoomMemberList',
|
||||||
|
GroupMemberList: 'GroupMemberList',
|
||||||
FilePanel: 'FilePanel',
|
FilePanel: 'FilePanel',
|
||||||
NotificationPanel: 'NotificationPanel',
|
NotificationPanel: 'NotificationPanel',
|
||||||
MemberInfo: 'MemberInfo',
|
RoomMemberInfo: 'RoomMemberInfo',
|
||||||
|
GroupMemberInfo: 'GroupMemberInfo',
|
||||||
},
|
},
|
||||||
|
|
||||||
componentWillMount: function() {
|
componentWillMount: function() {
|
||||||
this.dispatcherRef = dis.register(this.onAction);
|
this.dispatcherRef = dis.register(this.onAction);
|
||||||
var cli = MatrixClientPeg.get();
|
const cli = MatrixClientPeg.get();
|
||||||
cli.on("RoomState.members", this.onRoomStateMember);
|
cli.on("RoomState.members", this.onRoomStateMember);
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -57,14 +62,20 @@ module.exports = React.createClass({
|
|||||||
},
|
},
|
||||||
|
|
||||||
getInitialState: function() {
|
getInitialState: function() {
|
||||||
return {
|
if (this.props.groupId) {
|
||||||
phase: this.Phase.MemberList
|
return {
|
||||||
};
|
phase: this.Phase.GroupMemberList,
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
return {
|
||||||
|
phase: this.Phase.RoomMemberList,
|
||||||
|
};
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
onMemberListButtonClick: function() {
|
onMemberListButtonClick: function() {
|
||||||
Analytics.trackEvent('Right Panel', 'Member List Button', 'click');
|
Analytics.trackEvent('Right Panel', 'Member List Button', 'click');
|
||||||
this.setState({ phase: this.Phase.MemberList });
|
this.setState({ phase: this.Phase.RoomMemberList });
|
||||||
},
|
},
|
||||||
|
|
||||||
onFileListButtonClick: function() {
|
onFileListButtonClick: function() {
|
||||||
@ -89,19 +100,23 @@ module.exports = React.createClass({
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// call ChatInviteDialog
|
if (this.state.phase === this.Phase.GroupMemberList) {
|
||||||
dis.dispatch({
|
showGroupInviteDialog(this.props.groupId);
|
||||||
action: 'view_invite',
|
} else {
|
||||||
roomId: this.props.roomId,
|
// call AddressPickerDialog
|
||||||
});
|
dis.dispatch({
|
||||||
|
action: 'view_invite',
|
||||||
|
roomId: this.props.roomId,
|
||||||
|
});
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
onRoomStateMember: function(ev, state, member) {
|
onRoomStateMember: function(ev, state, member) {
|
||||||
// redraw the badge on the membership list
|
// redraw the badge on the membership list
|
||||||
if (this.state.phase == this.Phase.MemberList && member.roomId === this.props.roomId) {
|
if (this.state.phase == this.Phase.RoomMemberList && member.roomId === this.props.roomId) {
|
||||||
this._delayedUpdate();
|
this._delayedUpdate();
|
||||||
}
|
}
|
||||||
else if (this.state.phase === this.Phase.MemberInfo && member.roomId === this.props.roomId &&
|
else if (this.state.phase === this.Phase.RoomMemberInfo && member.roomId === this.props.roomId &&
|
||||||
member.userId === this.state.member.userId) {
|
member.userId === this.state.member.userId) {
|
||||||
// refresh the member info (e.g. new power level)
|
// refresh the member info (e.g. new power level)
|
||||||
this._delayedUpdate();
|
this._delayedUpdate();
|
||||||
@ -119,39 +134,55 @@ module.exports = React.createClass({
|
|||||||
});
|
});
|
||||||
if (payload.member) {
|
if (payload.member) {
|
||||||
this.setState({
|
this.setState({
|
||||||
phase: this.Phase.MemberInfo,
|
phase: this.Phase.RoomMemberInfo,
|
||||||
member: payload.member,
|
member: payload.member,
|
||||||
});
|
});
|
||||||
|
} else {
|
||||||
|
if (this.props.roomId) {
|
||||||
|
this.setState({
|
||||||
|
phase: this.Phase.RoomMemberList
|
||||||
|
});
|
||||||
|
} else if (this.props.groupId) {
|
||||||
|
this.setState({
|
||||||
|
phase: this.Phase.GroupMemberList,
|
||||||
|
groupId: payload.groupId,
|
||||||
|
member: payload.member,
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else {
|
} else if (payload.action === "view_group") {
|
||||||
this.setState({
|
this.setState({
|
||||||
phase: this.Phase.MemberList
|
phase: this.Phase.GroupMemberList,
|
||||||
});
|
groupId: payload.groupId,
|
||||||
}
|
member: null,
|
||||||
}
|
});
|
||||||
else if (payload.action === "view_room") {
|
} else if (payload.action === "view_group_user") {
|
||||||
if (this.state.phase === this.Phase.MemberInfo) {
|
this.setState({
|
||||||
this.setState({
|
phase: this.Phase.GroupMemberInfo,
|
||||||
phase: this.Phase.MemberList
|
groupId: payload.groupId,
|
||||||
});
|
member: payload.member,
|
||||||
}
|
});
|
||||||
|
} else if (payload.action === "view_room") {
|
||||||
|
this.setState({
|
||||||
|
phase: this.Phase.RoomMemberList
|
||||||
|
});
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
render: function() {
|
render: function() {
|
||||||
var MemberList = sdk.getComponent('rooms.MemberList');
|
const MemberList = sdk.getComponent('rooms.MemberList');
|
||||||
var NotificationPanel = sdk.getComponent('structures.NotificationPanel');
|
const GroupMemberList = sdk.getComponent('groups.GroupMemberList');
|
||||||
var FilePanel = sdk.getComponent('structures.FilePanel');
|
const NotificationPanel = sdk.getComponent('structures.NotificationPanel');
|
||||||
var TintableSvg = sdk.getComponent("elements.TintableSvg");
|
const FilePanel = sdk.getComponent('structures.FilePanel');
|
||||||
var buttonGroup;
|
const TintableSvg = sdk.getComponent("elements.TintableSvg");
|
||||||
var inviteGroup;
|
let inviteGroup;
|
||||||
var panel;
|
let panel;
|
||||||
|
|
||||||
var filesHighlight;
|
let filesHighlight;
|
||||||
var membersHighlight;
|
let membersHighlight;
|
||||||
var notificationsHighlight;
|
let notificationsHighlight;
|
||||||
if (!this.props.collapsed) {
|
if (!this.props.collapsed) {
|
||||||
if (this.state.phase == this.Phase.MemberList || this.state.phase === this.Phase.MemberInfo) {
|
if (this.state.phase == this.Phase.RoomMemberList || this.state.phase === this.Phase.RoomMemberInfo) {
|
||||||
membersHighlight = <div className="mx_RightPanel_headerButton_highlight"></div>;
|
membersHighlight = <div className="mx_RightPanel_headerButton_highlight"></div>;
|
||||||
}
|
}
|
||||||
else if (this.state.phase == this.Phase.FilePanel) {
|
else if (this.state.phase == this.Phase.FilePanel) {
|
||||||
@ -162,11 +193,11 @@ module.exports = React.createClass({
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var membersBadge;
|
let membersBadge;
|
||||||
if ((this.state.phase == this.Phase.MemberList || this.state.phase === this.Phase.MemberInfo) && this.props.roomId) {
|
if ((this.state.phase == this.Phase.RoomMemberList || this.state.phase === this.Phase.RoomMemberInfo) && this.props.roomId) {
|
||||||
var cli = MatrixClientPeg.get();
|
const cli = MatrixClientPeg.get();
|
||||||
var room = cli.getRoom(this.props.roomId);
|
const room = cli.getRoom(this.props.roomId);
|
||||||
var user_is_in_room;
|
let user_is_in_room;
|
||||||
if (room) {
|
if (room) {
|
||||||
membersBadge = room.getJoinedMembers().length;
|
membersBadge = room.getJoinedMembers().length;
|
||||||
user_is_in_room = room.hasMembershipState(
|
user_is_in_room = room.hasMembershipState(
|
||||||
@ -186,48 +217,72 @@ module.exports = React.createClass({
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let headerButtons = [];
|
||||||
if (this.props.roomId) {
|
if (this.props.roomId) {
|
||||||
buttonGroup =
|
headerButtons.push(
|
||||||
<div className="mx_RightPanel_headerButtonGroup">
|
<AccessibleButton className="mx_RightPanel_headerButton" key="_membersButton"
|
||||||
<AccessibleButton className="mx_RightPanel_headerButton"
|
title={ _t('Members') } onClick={ this.onMemberListButtonClick }>
|
||||||
title={ _t('Members') } onClick={ this.onMemberListButtonClick }>
|
<div className="mx_RightPanel_headerButton_badge">{ membersBadge ? membersBadge : <span> </span>}</div>
|
||||||
<div className="mx_RightPanel_headerButton_badge">{ membersBadge ? membersBadge : <span> </span>}</div>
|
<TintableSvg src="img/icons-people.svg" width="25" height="25"/>
|
||||||
<TintableSvg src="img/icons-people.svg" width="25" height="25"/>
|
{ membersHighlight }
|
||||||
{ membersHighlight }
|
</AccessibleButton>
|
||||||
</AccessibleButton>
|
);
|
||||||
<AccessibleButton
|
headerButtons.push(
|
||||||
className="mx_RightPanel_headerButton mx_RightPanel_filebutton"
|
<AccessibleButton
|
||||||
title={ _t('Files') } onClick={ this.onFileListButtonClick }>
|
className="mx_RightPanel_headerButton mx_RightPanel_filebutton" key="_filesButton"
|
||||||
<div className="mx_RightPanel_headerButton_badge"> </div>
|
title={ _t('Files') } onClick={ this.onFileListButtonClick }>
|
||||||
<TintableSvg src="img/icons-files.svg" width="25" height="25"/>
|
<div className="mx_RightPanel_headerButton_badge"> </div>
|
||||||
{ filesHighlight }
|
<TintableSvg src="img/icons-files.svg" width="25" height="25"/>
|
||||||
</AccessibleButton>
|
{ filesHighlight }
|
||||||
<AccessibleButton
|
</AccessibleButton>
|
||||||
className="mx_RightPanel_headerButton mx_RightPanel_notificationbutton"
|
);
|
||||||
title={ _t('Notifications') } onClick={ this.onNotificationListButtonClick }>
|
headerButtons.push(
|
||||||
<div className="mx_RightPanel_headerButton_badge"> </div>
|
<AccessibleButton
|
||||||
<TintableSvg src="img/icons-notifications.svg" width="25" height="25"/>
|
className="mx_RightPanel_headerButton mx_RightPanel_notificationbutton" key="_notifsButton"
|
||||||
{ notificationsHighlight }
|
title={ _t('Notifications') } onClick={ this.onNotificationListButtonClick }>
|
||||||
</AccessibleButton>
|
<div className="mx_RightPanel_headerButton_badge"> </div>
|
||||||
<div className="mx_RightPanel_headerButton mx_RightPanel_collapsebutton" title={ _t("Hide panel") } onClick={ this.onCollapseClick }>
|
<TintableSvg src="img/icons-notifications.svg" width="25" height="25"/>
|
||||||
<TintableSvg src="img/minimise.svg" width="10" height="16"/>
|
{ notificationsHighlight }
|
||||||
</div>
|
</AccessibleButton>
|
||||||
</div>;
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.props.roomId || this.props.groupId) {
|
||||||
|
// Hiding the right panel hides it completely and relies on an 'expand' button
|
||||||
|
// being put in the RoomHeader or GroupView header, so only show the minimise
|
||||||
|
// button on these 2 screens or you won't be able to re-expand the panel.
|
||||||
|
headerButtons.push(
|
||||||
|
<div className="mx_RightPanel_headerButton mx_RightPanel_collapsebutton" key="_minimizeButton"
|
||||||
|
title={ _t("Hide panel") } onClick={ this.onCollapseClick }
|
||||||
|
>
|
||||||
|
<TintableSvg src="img/minimise.svg" width="10" height="16"/>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!this.props.collapsed) {
|
if (!this.props.collapsed) {
|
||||||
if(this.props.roomId && this.state.phase == this.Phase.MemberList) {
|
if (this.props.roomId && this.state.phase == this.Phase.RoomMemberList) {
|
||||||
panel = <MemberList roomId={this.props.roomId} key={this.props.roomId} />
|
panel = <MemberList roomId={this.props.roomId} key={this.props.roomId} />
|
||||||
}
|
} else if (this.props.groupId && this.state.phase == this.Phase.GroupMemberList) {
|
||||||
else if(this.state.phase == this.Phase.MemberInfo) {
|
panel = <GroupMemberList groupId={this.props.groupId} key={this.props.groupId} />;
|
||||||
var MemberInfo = sdk.getComponent('rooms.MemberInfo');
|
inviteGroup = (
|
||||||
|
<AccessibleButton className="mx_RightPanel_invite" onClick={ this.onInviteButtonClick } >
|
||||||
|
<div className="mx_RightPanel_icon" >
|
||||||
|
<TintableSvg src="img/icon-invite-people.svg" width="35" height="35" />
|
||||||
|
</div>
|
||||||
|
<div className="mx_RightPanel_message">{ _t('Invite to this group') }</div>
|
||||||
|
</AccessibleButton>
|
||||||
|
);
|
||||||
|
} else if (this.state.phase == this.Phase.RoomMemberInfo) {
|
||||||
|
const MemberInfo = sdk.getComponent('rooms.MemberInfo');
|
||||||
panel = <MemberInfo member={this.state.member} key={this.props.roomId || this.state.member.userId} />
|
panel = <MemberInfo member={this.state.member} key={this.props.roomId || this.state.member.userId} />
|
||||||
}
|
} else if (this.state.phase == this.Phase.GroupMemberInfo) {
|
||||||
else if (this.state.phase == this.Phase.NotificationPanel) {
|
const GroupMemberInfo = sdk.getComponent('groups.GroupMemberInfo');
|
||||||
panel = <NotificationPanel />
|
panel = <GroupMemberInfo groupMember={this.state.member} groupId={this.props.groupId} key={this.state.member.user_id} />;
|
||||||
}
|
} else if (this.state.phase == this.Phase.NotificationPanel) {
|
||||||
else if (this.state.phase == this.Phase.FilePanel) {
|
panel = <NotificationPanel />;
|
||||||
panel = <FilePanel roomId={this.props.roomId} />
|
} else if (this.state.phase == this.Phase.FilePanel) {
|
||||||
|
panel = <FilePanel roomId={this.props.roomId} />;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -235,7 +290,7 @@ module.exports = React.createClass({
|
|||||||
panel = <div className="mx_RightPanel_blank"></div>;
|
panel = <div className="mx_RightPanel_blank"></div>;
|
||||||
}
|
}
|
||||||
|
|
||||||
var classes = "mx_RightPanel mx_fadable";
|
let classes = "mx_RightPanel mx_fadable";
|
||||||
if (this.props.collapsed) {
|
if (this.props.collapsed) {
|
||||||
classes += " collapsed";
|
classes += " collapsed";
|
||||||
}
|
}
|
||||||
@ -243,7 +298,9 @@ module.exports = React.createClass({
|
|||||||
return (
|
return (
|
||||||
<aside className={classes} style={{ opacity: this.props.opacity }}>
|
<aside className={classes} style={{ opacity: this.props.opacity }}>
|
||||||
<div className="mx_RightPanel_header">
|
<div className="mx_RightPanel_header">
|
||||||
{ buttonGroup }
|
<div className="mx_RightPanel_headerButtonGroup">
|
||||||
|
{headerButtons}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{ panel }
|
{ panel }
|
||||||
<div className="mx_RightPanel_footer">
|
<div className="mx_RightPanel_footer">
|
||||||
|
@ -88,6 +88,7 @@ var RoomSubList = React.createClass({
|
|||||||
searchFilter: React.PropTypes.string,
|
searchFilter: React.PropTypes.string,
|
||||||
emptyContent: React.PropTypes.node, // content shown if the list is empty
|
emptyContent: React.PropTypes.node, // content shown if the list is empty
|
||||||
headerItems: React.PropTypes.node, // content shown in the sublist header
|
headerItems: React.PropTypes.node, // content shown in the sublist header
|
||||||
|
extraTiles: React.PropTypes.arrayOf(React.PropTypes.node), // extra elements added beneath tiles
|
||||||
},
|
},
|
||||||
|
|
||||||
getInitialState: function() {
|
getInitialState: function() {
|
||||||
@ -102,6 +103,7 @@ var RoomSubList = React.createClass({
|
|||||||
return {
|
return {
|
||||||
onHeaderClick: function() {}, // NOP
|
onHeaderClick: function() {}, // NOP
|
||||||
onShowMoreRooms: function() {}, // NOP
|
onShowMoreRooms: function() {}, // NOP
|
||||||
|
extraTiles: [],
|
||||||
isInvite: false,
|
isInvite: false,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
@ -534,13 +536,14 @@ var RoomSubList = React.createClass({
|
|||||||
var label = this.props.collapsed ? null : this.props.label;
|
var label = this.props.collapsed ? null : this.props.label;
|
||||||
|
|
||||||
let content;
|
let content;
|
||||||
if (this.state.sortedList.length == 0 && !this.props.searchFilter) {
|
if (this.state.sortedList.length == 0 && !this.props.searchFilter && !this.props.extraTiles) {
|
||||||
content = this.props.emptyContent;
|
content = this.props.emptyContent;
|
||||||
} else {
|
} else {
|
||||||
content = this.makeRoomTiles();
|
content = this.makeRoomTiles();
|
||||||
|
content.push(...this.props.extraTiles);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.state.sortedList.length > 0 || this.props.editable) {
|
if (this.state.sortedList.length > 0 || this.props.extraTiles.length > 0 || this.props.editable) {
|
||||||
var subList;
|
var subList;
|
||||||
var classes = "mx_RoomSubList";
|
var classes = "mx_RoomSubList";
|
||||||
|
|
||||||
|
350
src/components/views/dialogs/DevtoolsDialog.js
Normal file
350
src/components/views/dialogs/DevtoolsDialog.js
Normal file
@ -0,0 +1,350 @@
|
|||||||
|
/*
|
||||||
|
Copyright 2017 Michael Telatynski <7t3chguy@gmail.com>
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import React from 'react';
|
||||||
|
import sdk from 'matrix-react-sdk';
|
||||||
|
import { _t } from 'matrix-react-sdk/lib/languageHandler';
|
||||||
|
import MatrixClientPeg from 'matrix-react-sdk/lib/MatrixClientPeg';
|
||||||
|
|
||||||
|
class SendCustomEvent extends React.Component {
|
||||||
|
static propTypes = {
|
||||||
|
roomId: React.PropTypes.string.isRequired,
|
||||||
|
onBack: React.PropTypes.func.isRequired,
|
||||||
|
|
||||||
|
eventType: React.PropTypes.string.isRequired,
|
||||||
|
evContent: React.PropTypes.string.isRequired,
|
||||||
|
};
|
||||||
|
|
||||||
|
static defaultProps = {
|
||||||
|
eventType: '',
|
||||||
|
evContent: '{\n\n}',
|
||||||
|
};
|
||||||
|
|
||||||
|
constructor(props, context) {
|
||||||
|
super(props, context);
|
||||||
|
this._send = this._send.bind(this);
|
||||||
|
this.onBack = this.onBack.bind(this);
|
||||||
|
this._onChange = this._onChange.bind(this);
|
||||||
|
|
||||||
|
this.state = {
|
||||||
|
message: null,
|
||||||
|
input_eventType: this.props.eventType,
|
||||||
|
input_evContent: this.props.evContent,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
onBack() {
|
||||||
|
if (this.state.message) {
|
||||||
|
this.setState({ message: null });
|
||||||
|
} else {
|
||||||
|
this.props.onBack();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_buttons() {
|
||||||
|
return <div className="mx_Dialog_buttons">
|
||||||
|
<button onClick={this.onBack}>{ _t('Back') }</button>
|
||||||
|
{!this.state.message && <button onClick={this._send}>{ _t('Send') }</button>}
|
||||||
|
</div>;
|
||||||
|
}
|
||||||
|
|
||||||
|
send(content) {
|
||||||
|
return MatrixClientPeg.get().sendEvent(this.props.roomId, this.state.input_eventType, content);
|
||||||
|
}
|
||||||
|
|
||||||
|
async _send() {
|
||||||
|
if (this.state.input_eventType === '') {
|
||||||
|
this.setState({ message: _t('You must specify an event type!') });
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let message;
|
||||||
|
try {
|
||||||
|
const content = JSON.parse(this.state.input_evContent);
|
||||||
|
await this.send(content);
|
||||||
|
message = _t('Event sent!');
|
||||||
|
} catch (e) {
|
||||||
|
message = _t('Failed to send custom event.') + ' (' + e.toString() + ')';
|
||||||
|
}
|
||||||
|
this.setState({ message });
|
||||||
|
}
|
||||||
|
|
||||||
|
_additionalFields() {
|
||||||
|
return <div/>;
|
||||||
|
}
|
||||||
|
|
||||||
|
_onChange(e) {
|
||||||
|
this.setState({[`input_${e.target.id}`]: e.target.value});
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
if (this.state.message) {
|
||||||
|
return <div>
|
||||||
|
<div className="mx_Dialog_content">
|
||||||
|
{this.state.message}
|
||||||
|
</div>
|
||||||
|
{this._buttons()}
|
||||||
|
</div>;
|
||||||
|
}
|
||||||
|
|
||||||
|
return <div>
|
||||||
|
<div className="mx_Dialog_content">
|
||||||
|
{this._additionalFields()}
|
||||||
|
<div className="mx_TextInputDialog_label">
|
||||||
|
<label htmlFor="eventType"> { _t('Event Type') } </label>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<input id="eventType" onChange={this._onChange} value={this.state.input_eventType} className="mx_TextInputDialog_input" size="64" />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="mx_TextInputDialog_label">
|
||||||
|
<label htmlFor="evContent"> { _t('Event Content') } </label>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<textarea id="evContent" onChange={this._onChange} value={this.state.input_evContent} className="mx_TextInputDialog_input" cols="63" rows="5" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{this._buttons()}
|
||||||
|
</div>;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class SendCustomStateEvent extends SendCustomEvent {
|
||||||
|
static propTypes = {
|
||||||
|
roomId: React.PropTypes.string.isRequired,
|
||||||
|
onBack: React.PropTypes.func.isRequired,
|
||||||
|
|
||||||
|
eventType: React.PropTypes.string.isRequired,
|
||||||
|
evContent: React.PropTypes.string.isRequired,
|
||||||
|
stateKey: React.PropTypes.string.isRequired,
|
||||||
|
};
|
||||||
|
|
||||||
|
static defaultProps = {
|
||||||
|
eventType: '',
|
||||||
|
evContent: '{\n\n}',
|
||||||
|
stateKey: '',
|
||||||
|
};
|
||||||
|
|
||||||
|
constructor(props, context) {
|
||||||
|
super(props, context);
|
||||||
|
this.state['input_stateKey'] = this.props.stateKey;
|
||||||
|
}
|
||||||
|
|
||||||
|
send(content) {
|
||||||
|
const cli = MatrixClientPeg.get();
|
||||||
|
return cli.sendStateEvent(this.props.roomId, this.state.input_eventType, content, this.state.input_stateKey);
|
||||||
|
}
|
||||||
|
|
||||||
|
_additionalFields() {
|
||||||
|
return <div>
|
||||||
|
<div className="mx_TextInputDialog_label">
|
||||||
|
<label htmlFor="stateKey"> { _t('State Key') } </label>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<input id="stateKey" onChange={this._onChange} value={this.state.input_stateKey} className="mx_TextInputDialog_input" size="64" />
|
||||||
|
</div>
|
||||||
|
</div>;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class RoomStateExplorer extends React.Component {
|
||||||
|
static propTypes = {
|
||||||
|
setMode: React.PropTypes.func.isRequired,
|
||||||
|
roomId: React.PropTypes.string.isRequired,
|
||||||
|
onBack: React.PropTypes.func.isRequired,
|
||||||
|
};
|
||||||
|
|
||||||
|
constructor(props, context) {
|
||||||
|
super(props, context);
|
||||||
|
|
||||||
|
const room = MatrixClientPeg.get().getRoom(this.props.roomId);
|
||||||
|
this.roomStateEvents = room.currentState.events;
|
||||||
|
|
||||||
|
this.onBack = this.onBack.bind(this);
|
||||||
|
this.editEv = this.editEv.bind(this);
|
||||||
|
this.onQuery = this.onQuery.bind(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
state = {
|
||||||
|
query: '',
|
||||||
|
eventType: null,
|
||||||
|
event: null,
|
||||||
|
};
|
||||||
|
|
||||||
|
browseEventType(eventType) {
|
||||||
|
return () => {
|
||||||
|
this.setState({ eventType });
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
onViewSourceClick(event) {
|
||||||
|
return () => {
|
||||||
|
this.setState({ event });
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
onBack() {
|
||||||
|
if (this.state.event) {
|
||||||
|
this.setState({ event: null });
|
||||||
|
} else if (this.state.eventType) {
|
||||||
|
this.setState({ eventType: null });
|
||||||
|
} else {
|
||||||
|
this.props.onBack();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
editEv() {
|
||||||
|
const ev = this.state.event;
|
||||||
|
this.props.setMode(SendCustomStateEvent, {
|
||||||
|
eventType: ev.getType(),
|
||||||
|
evContent: JSON.stringify(ev.getContent(), null, '\t'),
|
||||||
|
stateKey: ev.getStateKey(),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
onQuery(ev) {
|
||||||
|
this.setState({ query: ev.target.value });
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
if (this.state.event) {
|
||||||
|
return <div className="mx_ViewSource">
|
||||||
|
<div className="mx_Dialog_content">
|
||||||
|
<pre>{JSON.stringify(this.state.event.event, null, 2)}</pre>
|
||||||
|
</div>
|
||||||
|
<div className="mx_Dialog_buttons">
|
||||||
|
<button onClick={this.onBack}>{ _t('Back') }</button>
|
||||||
|
<button onClick={this.editEv}>{ _t('Edit') }</button>
|
||||||
|
</div>
|
||||||
|
</div>;
|
||||||
|
}
|
||||||
|
|
||||||
|
const rows = [];
|
||||||
|
|
||||||
|
if (this.state.eventType === null) {
|
||||||
|
Object.keys(this.roomStateEvents).forEach((evType) => {
|
||||||
|
// Skip this entry if does not contain search query
|
||||||
|
if (this.state.query && !evType.includes(this.state.query)) return;
|
||||||
|
|
||||||
|
const stateGroup = this.roomStateEvents[evType];
|
||||||
|
const stateKeys = Object.keys(stateGroup);
|
||||||
|
|
||||||
|
let onClickFn;
|
||||||
|
if (stateKeys.length > 1) {
|
||||||
|
onClickFn = this.browseEventType(evType);
|
||||||
|
} else if (stateKeys.length === 1) {
|
||||||
|
onClickFn = this.onViewSourceClick(stateGroup[stateKeys[0]]);
|
||||||
|
}
|
||||||
|
|
||||||
|
rows.push(<button className="mx_DevTools_RoomStateExplorer_button" key={evType} onClick={onClickFn}>
|
||||||
|
{ evType }
|
||||||
|
</button>);
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
const evType = this.state.eventType;
|
||||||
|
const stateGroup = this.roomStateEvents[evType];
|
||||||
|
Object.keys(stateGroup).forEach((stateKey) => {
|
||||||
|
// Skip this entry if does not contain search query
|
||||||
|
if (this.state.query && !stateKey.includes(this.state.query)) return;
|
||||||
|
|
||||||
|
const ev = stateGroup[stateKey];
|
||||||
|
rows.push(<button className="mx_DevTools_RoomStateExplorer_button" key={stateKey}
|
||||||
|
onClick={this.onViewSourceClick(ev)}>
|
||||||
|
{ stateKey }
|
||||||
|
</button>);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return <div>
|
||||||
|
<div className="mx_Dialog_content">
|
||||||
|
<input onChange={this.onQuery} placeholder={_t('Filter results')} size="64" className="mx_TextInputDialog_input mx_DevTools_RoomStateExplorer_query" value={this.state.query} />
|
||||||
|
{rows}
|
||||||
|
</div>
|
||||||
|
<div className="mx_Dialog_buttons">
|
||||||
|
<button onClick={this.onBack}>{ _t('Back') }</button>
|
||||||
|
</div>
|
||||||
|
</div>;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default class DevtoolsDialog extends React.Component {
|
||||||
|
static propTypes = {
|
||||||
|
roomId: React.PropTypes.string.isRequired,
|
||||||
|
onFinished: React.PropTypes.func.isRequired,
|
||||||
|
};
|
||||||
|
|
||||||
|
state = {
|
||||||
|
mode: null,
|
||||||
|
modeArgs: {},
|
||||||
|
};
|
||||||
|
|
||||||
|
constructor(props, context) {
|
||||||
|
super(props, context);
|
||||||
|
this.onBack = this.onBack.bind(this);
|
||||||
|
this.setMode = this.setMode.bind(this);
|
||||||
|
this.onCancel = this.onCancel.bind(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
componentWillUnmount() {
|
||||||
|
this._unmounted = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
_setMode(mode) {
|
||||||
|
return () => {
|
||||||
|
this.setMode(mode);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
setMode(mode, modeArgs={}) {
|
||||||
|
this.setState({ mode, modeArgs });
|
||||||
|
}
|
||||||
|
|
||||||
|
onBack() {
|
||||||
|
this.setState({ mode: null });
|
||||||
|
}
|
||||||
|
|
||||||
|
onCancel() {
|
||||||
|
this.props.onFinished(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
let body;
|
||||||
|
|
||||||
|
if (this.state.mode) {
|
||||||
|
body =
|
||||||
|
<this.state.mode {...this.props} {...this.state.modeArgs} onBack={this.onBack} setMode={this.setMode} />;
|
||||||
|
} else {
|
||||||
|
body = <div>
|
||||||
|
<div className="mx_Dialog_content">
|
||||||
|
<button onClick={this._setMode(SendCustomEvent)}>{ _t('Send Custom Event') }</button>
|
||||||
|
<button onClick={this._setMode(SendCustomStateEvent)}>{ _t('Send Custom State Event') }</button>
|
||||||
|
<button onClick={this._setMode(RoomStateExplorer)}>{ _t('Explore Room State') }</button>
|
||||||
|
</div>
|
||||||
|
<div className="mx_Dialog_buttons">
|
||||||
|
<button onClick={this.onCancel}>{ _t('Cancel') }</button>
|
||||||
|
</div>
|
||||||
|
</div>;
|
||||||
|
}
|
||||||
|
|
||||||
|
const BaseDialog = sdk.getComponent('views.dialogs.BaseDialog');
|
||||||
|
return (
|
||||||
|
<BaseDialog className="mx_QuestionDialog" onFinished={this.props.onFinished} title={_t('Developer Tools')}>
|
||||||
|
<div>Room ID: { this.props.roomId }</div>
|
||||||
|
{ body }
|
||||||
|
</BaseDialog>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
@ -9,6 +9,7 @@
|
|||||||
"All Rooms": "All Rooms",
|
"All Rooms": "All Rooms",
|
||||||
"All notifications are currently disabled for all targets.": "All notifications are currently disabled for all targets.",
|
"All notifications are currently disabled for all targets.": "All notifications are currently disabled for all targets.",
|
||||||
"An error occurred whilst saving your email notification preferences.": "An error occurred whilst saving your email notification preferences.",
|
"An error occurred whilst saving your email notification preferences.": "An error occurred whilst saving your email notification preferences.",
|
||||||
|
"Back": "Back",
|
||||||
"Bug report sent": "Bug report sent",
|
"Bug report sent": "Bug report sent",
|
||||||
"Call invitation": "Call invitation",
|
"Call invitation": "Call invitation",
|
||||||
"Cancel": "Cancel",
|
"Cancel": "Cancel",
|
||||||
@ -26,6 +27,7 @@
|
|||||||
"delete the alias.": "delete the alias.",
|
"delete the alias.": "delete the alias.",
|
||||||
"Delete the room alias %(alias)s and remove %(name)s from the directory?": "Delete the room alias %(alias)s and remove %(name)s from the directory?",
|
"Delete the room alias %(alias)s and remove %(name)s from the directory?": "Delete the room alias %(alias)s and remove %(name)s from the directory?",
|
||||||
"Describe your problem here.": "Describe your problem here.",
|
"Describe your problem here.": "Describe your problem here.",
|
||||||
|
"Developer Tools": "Developer Tools",
|
||||||
"Direct Chat": "Direct Chat",
|
"Direct Chat": "Direct Chat",
|
||||||
"Directory": "Directory",
|
"Directory": "Directory",
|
||||||
"Dismiss": "Dismiss",
|
"Dismiss": "Dismiss",
|
||||||
@ -50,12 +52,14 @@
|
|||||||
"Failed to get public room list": "Failed to get public room list",
|
"Failed to get public room list": "Failed to get public room list",
|
||||||
"Failed to join the room": "Failed to join the room",
|
"Failed to join the room": "Failed to join the room",
|
||||||
"Failed to remove tag %(tagName)s from room": "Failed to remove tag %(tagName)s from room",
|
"Failed to remove tag %(tagName)s from room": "Failed to remove tag %(tagName)s from room",
|
||||||
|
"Failed to send custom event.": "Failed to send custom event.",
|
||||||
"Failed to send report: ": "Failed to send report: ",
|
"Failed to send report: ": "Failed to send report: ",
|
||||||
"Failed to set direct chat tag": "Failed to set direct chat tag",
|
"Failed to set direct chat tag": "Failed to set direct chat tag",
|
||||||
"Failed to set Direct Message status of room": "Failed to set Direct Message status of room",
|
"Failed to set Direct Message status of room": "Failed to set Direct Message status of room",
|
||||||
"Favourite": "Favourite",
|
"Favourite": "Favourite",
|
||||||
"Fetching third party location failed": "Fetching third party location failed",
|
"Fetching third party location failed": "Fetching third party location failed",
|
||||||
"Files": "Files",
|
"Files": "Files",
|
||||||
|
"Filter results": "Filter results",
|
||||||
"Filter room names": "Filter room names",
|
"Filter room names": "Filter room names",
|
||||||
"Forget": "Forget",
|
"Forget": "Forget",
|
||||||
"Forward Message": "Forward Message",
|
"Forward Message": "Forward Message",
|
||||||
@ -117,6 +121,9 @@
|
|||||||
"Search for a room": "Search for a room",
|
"Search for a room": "Search for a room",
|
||||||
"Send": "Send",
|
"Send": "Send",
|
||||||
"Send logs": "Send logs",
|
"Send logs": "Send logs",
|
||||||
|
"Send Custom Event": "Send Custom Event",
|
||||||
|
"Send Custom State Event": "Send Custom State Event",
|
||||||
|
"Explore Room State": "Explore Room State",
|
||||||
"Settings": "Settings",
|
"Settings": "Settings",
|
||||||
"Source URL": "Source URL",
|
"Source URL": "Source URL",
|
||||||
"Sorry, your browser is <b>not</b> able to run Riot.": "Sorry, your browser is <b>not</b> able to run Riot.",
|
"Sorry, your browser is <b>not</b> able to run Riot.": "Sorry, your browser is <b>not</b> able to run Riot.",
|
||||||
@ -150,6 +157,7 @@
|
|||||||
"You are not receiving desktop notifications": "You are not receiving desktop notifications",
|
"You are not receiving desktop notifications": "You are not receiving desktop notifications",
|
||||||
"You are Rioting as a guest. <a>Register</a> or <a>sign in</a> to access more rooms and features!": "You are Rioting as a guest. <a>Register</a> or <a>sign in</a> to access more rooms and features!",
|
"You are Rioting as a guest. <a>Register</a> or <a>sign in</a> to access more rooms and features!": "You are Rioting as a guest. <a>Register</a> or <a>sign in</a> to access more rooms and features!",
|
||||||
"You might have configured them in a client other than Riot. You cannot tune them in Riot but they still apply": "You might have configured them in a client other than Riot. You cannot tune them in Riot but they still apply",
|
"You might have configured them in a client other than Riot. You cannot tune them in Riot but they still apply": "You might have configured them in a client other than Riot. You cannot tune them in Riot but they still apply",
|
||||||
|
"You must specify an event type!": "You must specify an event type!",
|
||||||
"Thank you!": "Thank you!",
|
"Thank you!": "Thank you!",
|
||||||
"Sunday": "Sunday",
|
"Sunday": "Sunday",
|
||||||
"Monday": "Monday",
|
"Monday": "Monday",
|
||||||
@ -164,6 +172,10 @@
|
|||||||
"Warning": "Warning",
|
"Warning": "Warning",
|
||||||
"Checking for an update...": "Checking for an update...",
|
"Checking for an update...": "Checking for an update...",
|
||||||
"Error encountered (%(errorDetail)s).": "Error encountered (%(errorDetail)s).",
|
"Error encountered (%(errorDetail)s).": "Error encountered (%(errorDetail)s).",
|
||||||
|
"Event sent!": "Event sent!",
|
||||||
|
"Event Type": "Event Type",
|
||||||
|
"Event Content": "Event Content",
|
||||||
|
"State Key": "State Key",
|
||||||
"No update available.": "No update available.",
|
"No update available.": "No update available.",
|
||||||
"Downloading update...": "Downloading update...",
|
"Downloading update...": "Downloading update...",
|
||||||
"You need to be using HTTPS to place a screen-sharing call.": "You need to be using HTTPS to place a screen-sharing call.",
|
"You need to be using HTTPS to place a screen-sharing call.": "You need to be using HTTPS to place a screen-sharing call.",
|
||||||
@ -207,5 +219,6 @@
|
|||||||
"Remember, you can always set an email address in user settings if you change your mind.": "Remember, you can always set an email address in user settings if you change your mind.",
|
"Remember, you can always set an email address in user settings if you change your mind.": "Remember, you can always set an email address in user settings if you change your mind.",
|
||||||
"To return to your account in future you need to <u>set a password</u>": "To return to your account in future you need to <u>set a password</u>",
|
"To return to your account in future you need to <u>set a password</u>": "To return to your account in future you need to <u>set a password</u>",
|
||||||
"Set Password": "Set Password",
|
"Set Password": "Set Password",
|
||||||
"Couldn't load home page": "Couldn't load home page"
|
"Couldn't load home page": "Couldn't load home page",
|
||||||
|
"Invite to this group": "Invite to this group"
|
||||||
}
|
}
|
||||||
|
@ -32,6 +32,7 @@
|
|||||||
@import "./matrix-react-sdk/views/elements/_ProgressBar.scss";
|
@import "./matrix-react-sdk/views/elements/_ProgressBar.scss";
|
||||||
@import "./matrix-react-sdk/views/elements/_RichText.scss";
|
@import "./matrix-react-sdk/views/elements/_RichText.scss";
|
||||||
@import "./matrix-react-sdk/views/elements/_RoleButton.scss";
|
@import "./matrix-react-sdk/views/elements/_RoleButton.scss";
|
||||||
|
@import "./matrix-react-sdk/views/groups/_GroupInviteTile.scss";
|
||||||
@import "./matrix-react-sdk/views/login/_InteractiveAuthEntryComponents.scss";
|
@import "./matrix-react-sdk/views/login/_InteractiveAuthEntryComponents.scss";
|
||||||
@import "./matrix-react-sdk/views/login/_ServerConfig.scss";
|
@import "./matrix-react-sdk/views/login/_ServerConfig.scss";
|
||||||
@import "./matrix-react-sdk/views/messages/_MEmoteBody.scss";
|
@import "./matrix-react-sdk/views/messages/_MEmoteBody.scss";
|
||||||
@ -74,6 +75,7 @@
|
|||||||
@import "./vector-web/views/context_menus/_MessageContextMenu.scss";
|
@import "./vector-web/views/context_menus/_MessageContextMenu.scss";
|
||||||
@import "./vector-web/views/context_menus/_RoomTileContextMenu.scss";
|
@import "./vector-web/views/context_menus/_RoomTileContextMenu.scss";
|
||||||
@import "./vector-web/views/dialogs/_ChangelogDialog.scss";
|
@import "./vector-web/views/dialogs/_ChangelogDialog.scss";
|
||||||
|
@import "./vector-web/views/dialogs/_DevtoolsDialog.scss";
|
||||||
@import "./vector-web/views/dialogs/_SetEmailDialog.scss";
|
@import "./vector-web/views/dialogs/_SetEmailDialog.scss";
|
||||||
@import "./vector-web/views/dialogs/_SetPasswordDialog.scss";
|
@import "./vector-web/views/dialogs/_SetPasswordDialog.scss";
|
||||||
@import "./vector-web/views/directory/_NetworkDropdown.scss";
|
@import "./vector-web/views/directory/_NetworkDropdown.scss";
|
||||||
|
@ -70,8 +70,12 @@ limitations under the License.
|
|||||||
flex: 1;
|
flex: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
.mx_GroupView_saveButton, .mx_GroupView_cancelButton {
|
.mx_GroupView_header_rightCol {
|
||||||
display: table-cell;
|
display: flex;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mx_GroupView_textButton {
|
||||||
|
display: inline-block;
|
||||||
}
|
}
|
||||||
|
|
||||||
.mx_GroupView_header_groupid {
|
.mx_GroupView_header_groupid {
|
||||||
@ -126,6 +130,26 @@ limitations under the License.
|
|||||||
top: 5px;
|
top: 5px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.mx_GroupView_membershipSection {
|
||||||
|
margin-left: auto;
|
||||||
|
margin-right: auto;
|
||||||
|
margin-bottom: 11px;
|
||||||
|
justify-content: space-between;
|
||||||
|
display: flex;
|
||||||
|
color: $greyed-fg-color;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mx_GroupView_membershipSection_description {
|
||||||
|
/* To match textButton */
|
||||||
|
line-height: 34px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mx_GroupView_membershipSection .mx_GroupView_textButton {
|
||||||
|
margin-right: 0px;
|
||||||
|
margin-top: 0px;
|
||||||
|
margin-left: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
.mx_GroupView_featuredThings {
|
.mx_GroupView_featuredThings {
|
||||||
margin-top: 20px;
|
margin-top: 20px;
|
||||||
}
|
}
|
||||||
@ -142,9 +166,30 @@ limitations under the License.
|
|||||||
margin-top: 10px;
|
margin-top: 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.mx_GroupView_featuredThings_container {
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mx_GroupView_featuredThings_addButton,
|
||||||
.mx_GroupView_featuredThing {
|
.mx_GroupView_featuredThing {
|
||||||
cursor: pointer;
|
|
||||||
display: table-cell;
|
display: table-cell;
|
||||||
|
text-align: center;
|
||||||
|
|
||||||
|
width: 100px;
|
||||||
|
margin: 0px 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mx_GroupView_featuredThing .mx_BaseAvatar {
|
||||||
|
/* To prevent misalignment with mx_TintableSvg (in addButton) */
|
||||||
|
vertical-align: initial;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mx_GroupView_featuredThings_addButton object {
|
||||||
|
pointer-events: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mx_GroupView_featuredThing_name {
|
||||||
|
word-wrap: break-word;
|
||||||
}
|
}
|
||||||
|
|
||||||
.mx_GroupView_uploadInput {
|
.mx_GroupView_uploadInput {
|
||||||
|
@ -80,6 +80,16 @@ limitations under the License.
|
|||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.mx_UserSettings_button.mx_UserSettings_buttonSmall {
|
||||||
|
height: 36px;
|
||||||
|
padding: 4px;
|
||||||
|
padding-left: 7px;
|
||||||
|
padding-right: 7px;
|
||||||
|
font-size: 12px;
|
||||||
|
margin-right: 5px;
|
||||||
|
line-height: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
.mx_UserSettings_button.danger {
|
.mx_UserSettings_button.danger {
|
||||||
background-color: $warning-color;
|
background-color: $warning-color;
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,74 @@
|
|||||||
|
/*
|
||||||
|
Copyright 2017 New Vector Ltd
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
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_GroupInviteTile {
|
||||||
|
position: relative;
|
||||||
|
cursor: pointer;
|
||||||
|
font-size: 13px;
|
||||||
|
display: block;
|
||||||
|
height: 34px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mx_GroupInviteTile_nameContainer {
|
||||||
|
display: inline-block;
|
||||||
|
width: 180px;
|
||||||
|
height: 24px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mx_GroupInviteTile_avatarContainer {
|
||||||
|
display: inline-block;
|
||||||
|
padding-top: 5px;
|
||||||
|
padding-bottom: 5px;
|
||||||
|
padding-left: 16px;
|
||||||
|
padding-right: 6px;
|
||||||
|
width: 24px;
|
||||||
|
height: 24px;
|
||||||
|
vertical-align: middle;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mx_GroupInviteTile_name {
|
||||||
|
display: inline-block;
|
||||||
|
position: relative;
|
||||||
|
width: 165px;
|
||||||
|
vertical-align: middle;
|
||||||
|
padding-left: 6px;
|
||||||
|
padding-right: 6px;
|
||||||
|
padding-top: 2px;
|
||||||
|
padding-bottom: 3px;
|
||||||
|
color: $roomtile-name-color;
|
||||||
|
white-space: nowrap;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mx_GroupInviteTile_badge {
|
||||||
|
display: inline-block;
|
||||||
|
min-width: 15px;
|
||||||
|
height: 15px;
|
||||||
|
position: absolute;
|
||||||
|
right: 8px; /*gutter */
|
||||||
|
top: 9px;
|
||||||
|
border-radius: 8px;
|
||||||
|
color: $accent-fg-color;
|
||||||
|
background-color: $group-alert-color;
|
||||||
|
font-weight: 600;
|
||||||
|
font-size: 10px;
|
||||||
|
text-align: center;
|
||||||
|
padding-top: 1px;
|
||||||
|
padding-left: 4px;
|
||||||
|
padding-right: 4px;
|
||||||
|
}
|
||||||
|
|
@ -45,7 +45,6 @@ limitations under the License.
|
|||||||
|
|
||||||
.mx_EventTile .mx_SenderProfile {
|
.mx_EventTile .mx_SenderProfile {
|
||||||
color: $primary-fg-color;
|
color: $primary-fg-color;
|
||||||
opacity: 0.5;
|
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
display: block; /* anti-zalgo, with overflow hidden */
|
display: block; /* anti-zalgo, with overflow hidden */
|
||||||
overflow-y: hidden;
|
overflow-y: hidden;
|
||||||
@ -57,6 +56,15 @@ limitations under the License.
|
|||||||
line-height: 22px;
|
line-height: 22px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.mx_EventTile .mx_SenderProfile .mx_SenderProfile_name,
|
||||||
|
.mx_EventTile .mx_SenderProfile .mx_SenderProfile_aux {
|
||||||
|
opacity: 0.5;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mx_EventTile .mx_SenderProfile .mx_Flair {
|
||||||
|
opacity: 0.7;
|
||||||
|
}
|
||||||
|
|
||||||
.mx_EventTile .mx_MessageTimestamp {
|
.mx_EventTile .mx_MessageTimestamp {
|
||||||
display: block;
|
display: block;
|
||||||
visibility: hidden;
|
visibility: hidden;
|
||||||
|
@ -21,9 +21,7 @@ limitations under the License.
|
|||||||
}
|
}
|
||||||
|
|
||||||
.mx_RoomSettings_leaveButton,
|
.mx_RoomSettings_leaveButton,
|
||||||
.mx_RoomSettings_unbanButton,
|
.mx_RoomSettings_unbanButton {
|
||||||
.mx_RoomSettings_integrationsButton,
|
|
||||||
.mx_RoomSettings_integrationsButton_error {
|
|
||||||
position: relative;
|
position: relative;
|
||||||
height: 36px;
|
height: 36px;
|
||||||
background-color: $accent-color;
|
background-color: $accent-color;
|
||||||
@ -36,25 +34,37 @@ limitations under the License.
|
|||||||
padding-left: 12px;
|
padding-left: 12px;
|
||||||
padding-right: 12px;
|
padding-right: 12px;
|
||||||
}
|
}
|
||||||
|
.mx_RoomSettings_integrationsButton_error {
|
||||||
|
position: relative;
|
||||||
|
cursor: not-allowed;
|
||||||
|
}
|
||||||
|
.mx_RoomSettings_integrationsButton_error img {
|
||||||
|
position: absolute;
|
||||||
|
right: -5px;
|
||||||
|
top: -5px;
|
||||||
|
}
|
||||||
.mx_RoomSettings_leaveButton,
|
.mx_RoomSettings_leaveButton,
|
||||||
.mx_RoomSettings_integrationsButton,
|
|
||||||
.mx_RoomSettings_integrationsButton_error {
|
.mx_RoomSettings_integrationsButton_error {
|
||||||
float: right;
|
float: right;
|
||||||
}
|
}
|
||||||
.mx_RoomSettings_integrationsButton_error {
|
.mx_RoomSettings_integrationsButton_error .mx_RoomSettings_integrationsButton_errorPopup {
|
||||||
pointer: not-allowed;
|
display: none;
|
||||||
|
}
|
||||||
|
.mx_RoomSettings_integrationsButton_error:hover .mx_RoomSettings_integrationsButton_errorPopup {
|
||||||
|
display: inline;
|
||||||
}
|
}
|
||||||
.mx_RoomSettings_integrationsButton_errorPopup {
|
.mx_RoomSettings_integrationsButton_errorPopup {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: 110%;
|
top: 110%;
|
||||||
left: -26%;
|
left: -125%;
|
||||||
width: 150%;
|
width: 348%;
|
||||||
padding: 2%;
|
padding: 2%;
|
||||||
font-size: 10pt;
|
font-size: 10pt;
|
||||||
line-height: 1.5em;
|
line-height: 1.5em;
|
||||||
border-radius: 5px;
|
border-radius: 5px;
|
||||||
background-color: $accent-color;
|
background-color: $accent-color;
|
||||||
color: $accent-fg-color;
|
color: $accent-fg-color;
|
||||||
|
text-align: center;
|
||||||
}
|
}
|
||||||
.mx_RoomSettings_unbanButton {
|
.mx_RoomSettings_unbanButton {
|
||||||
display: inline;
|
display: inline;
|
||||||
|
@ -22,6 +22,8 @@ $warning-color: #ff0064;
|
|||||||
$mention-user-pill-bg-color: #ff0064;
|
$mention-user-pill-bg-color: #ff0064;
|
||||||
$other-user-pill-bg-color: rgba(0, 0, 0, 0.1);
|
$other-user-pill-bg-color: rgba(0, 0, 0, 0.1);
|
||||||
|
|
||||||
|
$group-alert-color: #774f7e;
|
||||||
|
|
||||||
$preview-bar-bg-color: #f7f7f7;
|
$preview-bar-bg-color: #f7f7f7;
|
||||||
|
|
||||||
// left-panel style muted accent color
|
// left-panel style muted accent color
|
||||||
|
@ -0,0 +1,19 @@
|
|||||||
|
/*
|
||||||
|
Copyright 2017 Michael Telatynski <7t3chguy@gmail.com>
|
||||||
|
|
||||||
|
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_DevTools_RoomStateExplorer_button, .mx_DevTools_RoomStateExplorer_query {
|
||||||
|
margin-bottom: 10px;
|
||||||
|
}
|
@ -176,8 +176,9 @@ describe('joining a room', function () {
|
|||||||
|
|
||||||
return Promise.delay(1);
|
return Promise.delay(1);
|
||||||
}).then(() => {
|
}).then(() => {
|
||||||
// We've joined, expect this to false
|
// NB. we don't expect the 'joining' flag to reset at any point:
|
||||||
expect(roomView.state.joining).toBe(false);
|
// it will stay set and we observe whether we have Room object for
|
||||||
|
// the room and whether our member event shows we're joined.
|
||||||
|
|
||||||
// now send the room down the /sync pipe
|
// now send the room down the /sync pipe
|
||||||
httpBackend.when('GET', '/sync').
|
httpBackend.when('GET', '/sync').
|
||||||
|
Loading…
Reference in New Issue
Block a user