Merge branch 'develop' into matthew/fix_logging
This commit is contained in:
commit
9f455fae4b
136 changed files with 1483 additions and 775 deletions
|
@ -30,6 +30,7 @@ export default class AppPermission extends React.Component {
|
|||
creatorUserId: PropTypes.string.isRequired,
|
||||
roomId: PropTypes.string.isRequired,
|
||||
onPermissionGranted: PropTypes.func.isRequired,
|
||||
isRoomEncrypted: PropTypes.bool,
|
||||
};
|
||||
|
||||
static defaultProps = {
|
||||
|
@ -114,6 +115,8 @@ export default class AppPermission extends React.Component {
|
|||
: _t("Using this widget may share data <helpIcon /> with %(widgetDomain)s.",
|
||||
{widgetDomain: this.state.widgetDomain}, {helpIcon: () => warningTooltip});
|
||||
|
||||
const encryptionWarning = this.props.isRoomEncrypted ? _t("Widgets do not use message encryption.") : null;
|
||||
|
||||
return (
|
||||
<div className='mx_AppPermissionWarning'>
|
||||
<div className='mx_AppPermissionWarning_row mx_AppPermissionWarning_bolder mx_AppPermissionWarning_smallText'>
|
||||
|
@ -128,7 +131,7 @@ export default class AppPermission extends React.Component {
|
|||
{warning}
|
||||
</div>
|
||||
<div className='mx_AppPermissionWarning_row mx_AppPermissionWarning_smallText'>
|
||||
{_t("This widget may use cookies.")}
|
||||
{_t("This widget may use cookies.")} {encryptionWarning}
|
||||
</div>
|
||||
<div className='mx_AppPermissionWarning_row'>
|
||||
<AccessibleButton kind='primary_sm' onClick={this.props.onPermissionGranted}>
|
||||
|
|
|
@ -35,6 +35,7 @@ import ActiveWidgetStore from '../../../stores/ActiveWidgetStore';
|
|||
import classNames from 'classnames';
|
||||
import {IntegrationManagers} from "../../../integrations/IntegrationManagers";
|
||||
import SettingsStore, {SettingLevel} from "../../../settings/SettingsStore";
|
||||
import {createMenu} from "../../structures/ContextualMenu";
|
||||
|
||||
const ALLOWED_APP_URL_SCHEMES = ['https:', 'http:'];
|
||||
const ENABLE_REACT_PERF = false;
|
||||
|
@ -52,7 +53,7 @@ export default class AppTile extends React.Component {
|
|||
this._onLoaded = this._onLoaded.bind(this);
|
||||
this._onEditClick = this._onEditClick.bind(this);
|
||||
this._onDeleteClick = this._onDeleteClick.bind(this);
|
||||
this._onCancelClick = this._onCancelClick.bind(this);
|
||||
this._onRevokeClicked = this._onRevokeClicked.bind(this);
|
||||
this._onSnapshotClick = this._onSnapshotClick.bind(this);
|
||||
this.onClickMenuBar = this.onClickMenuBar.bind(this);
|
||||
this._onMinimiseClick = this._onMinimiseClick.bind(this);
|
||||
|
@ -207,7 +208,7 @@ export default class AppTile extends React.Component {
|
|||
if (!this._scalarClient) {
|
||||
this._scalarClient = defaultManager.getScalarClient();
|
||||
}
|
||||
this._scalarClient.getScalarToken().done((token) => {
|
||||
this._scalarClient.getScalarToken().then((token) => {
|
||||
// Append scalar_token as a query param if not already present
|
||||
this._scalarClient.scalarToken = token;
|
||||
const u = url.parse(this._addWurlParams(this.props.url));
|
||||
|
@ -271,7 +272,7 @@ export default class AppTile extends React.Component {
|
|||
return WidgetUtils.canUserModifyWidgets(this.props.room.roomId);
|
||||
}
|
||||
|
||||
_onEditClick(e) {
|
||||
_onEditClick() {
|
||||
console.log("Edit widget ID ", this.props.id);
|
||||
if (this.props.onEditClick) {
|
||||
this.props.onEditClick();
|
||||
|
@ -293,7 +294,7 @@ export default class AppTile extends React.Component {
|
|||
}
|
||||
}
|
||||
|
||||
_onSnapshotClick(e) {
|
||||
_onSnapshotClick() {
|
||||
console.warn("Requesting widget snapshot");
|
||||
ActiveWidgetStore.getWidgetMessaging(this.props.id).getScreenshot()
|
||||
.catch((err) => {
|
||||
|
@ -360,13 +361,9 @@ export default class AppTile extends React.Component {
|
|||
}
|
||||
}
|
||||
|
||||
_onCancelClick() {
|
||||
if (this.props.onDeleteClick) {
|
||||
this.props.onDeleteClick();
|
||||
} else {
|
||||
console.info("Revoke widget permissions - %s", this.props.id);
|
||||
this._revokeWidgetPermission();
|
||||
}
|
||||
_onRevokeClicked() {
|
||||
console.info("Revoke widget permissions - %s", this.props.id);
|
||||
this._revokeWidgetPermission();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -544,18 +541,59 @@ export default class AppTile extends React.Component {
|
|||
}
|
||||
}
|
||||
|
||||
_onPopoutWidgetClick(e) {
|
||||
_onPopoutWidgetClick() {
|
||||
// Using Object.assign workaround as the following opens in a new window instead of a new tab.
|
||||
// window.open(this._getSafeUrl(), '_blank', 'noopener=yes');
|
||||
Object.assign(document.createElement('a'),
|
||||
{ target: '_blank', href: this._getSafeUrl(), rel: 'noopener'}).click();
|
||||
}
|
||||
|
||||
_onReloadWidgetClick(e) {
|
||||
_onReloadWidgetClick() {
|
||||
// Reload iframe in this way to avoid cross-origin restrictions
|
||||
this.refs.appFrame.src = this.refs.appFrame.src;
|
||||
}
|
||||
|
||||
_getMenuOptions(ev) {
|
||||
// TODO: This block of code gets copy/pasted a lot. We should make that happen less.
|
||||
const menuOptions = {};
|
||||
const buttonRect = ev.target.getBoundingClientRect();
|
||||
// The window X and Y offsets are to adjust position when zoomed in to page
|
||||
const buttonLeft = buttonRect.left + window.pageXOffset;
|
||||
const buttonTop = buttonRect.top + window.pageYOffset;
|
||||
// Align the right edge of the menu to the left edge of the button
|
||||
menuOptions.right = window.innerWidth - buttonLeft;
|
||||
// Align the menu vertically on whichever side of the button has more
|
||||
// space available.
|
||||
if (buttonTop < window.innerHeight / 2) {
|
||||
menuOptions.top = buttonTop;
|
||||
} else {
|
||||
menuOptions.bottom = window.innerHeight - buttonTop;
|
||||
}
|
||||
return menuOptions;
|
||||
}
|
||||
|
||||
_onContextMenuClick = (ev) => {
|
||||
const WidgetContextMenu = sdk.getComponent('views.context_menus.WidgetContextMenu');
|
||||
const menuOptions = {
|
||||
...this._getMenuOptions(ev),
|
||||
|
||||
// A revoke handler is always required
|
||||
onRevokeClicked: this._onRevokeClicked,
|
||||
};
|
||||
|
||||
const canUserModify = this._canUserModify();
|
||||
const showEditButton = Boolean(this._scalarClient && canUserModify);
|
||||
const showDeleteButton = (this.props.showDelete === undefined || this.props.showDelete) && canUserModify;
|
||||
const showPictureSnapshotButton = this._hasCapability('m.capability.screenshot') && this.props.show;
|
||||
|
||||
if (showEditButton) menuOptions.onEditClicked = this._onEditClick;
|
||||
if (showDeleteButton) menuOptions.onDeleteClicked = this._onDeleteClick;
|
||||
if (showPictureSnapshotButton) menuOptions.onSnapshotClicked = this._onSnapshotClick;
|
||||
if (this.props.showReload) menuOptions.onReloadClicked = this._onReloadWidgetClick;
|
||||
|
||||
createMenu(WidgetContextMenu, menuOptions);
|
||||
};
|
||||
|
||||
render() {
|
||||
let appTileBody;
|
||||
|
||||
|
@ -565,7 +603,7 @@ export default class AppTile extends React.Component {
|
|||
}
|
||||
|
||||
// Note that there is advice saying allow-scripts shouldn't be used with allow-same-origin
|
||||
// because that would allow the iframe to prgramatically remove the sandbox attribute, but
|
||||
// because that would allow the iframe to programmatically remove the sandbox attribute, but
|
||||
// this would only be for content hosted on the same origin as the riot client: anything
|
||||
// hosted on the same origin as the client will get the same access as if you clicked
|
||||
// a link to it.
|
||||
|
@ -585,12 +623,14 @@ export default class AppTile extends React.Component {
|
|||
</div>
|
||||
);
|
||||
if (!this.state.hasPermissionToLoad) {
|
||||
const isEncrypted = MatrixClientPeg.get().isRoomEncrypted(this.props.room.roomId);
|
||||
appTileBody = (
|
||||
<div className={appTileBodyClass}>
|
||||
<AppPermission
|
||||
roomId={this.props.room.roomId}
|
||||
creatorUserId={this.props.creatorUserId}
|
||||
url={this.state.widgetUrl}
|
||||
isRoomEncrypted={isEncrypted}
|
||||
onPermissionGranted={this._grantWidgetPermission}
|
||||
/>
|
||||
</div>
|
||||
|
@ -643,13 +683,6 @@ export default class AppTile extends React.Component {
|
|||
}
|
||||
}
|
||||
|
||||
// editing is done in scalar
|
||||
const canUserModify = this._canUserModify();
|
||||
const showEditButton = Boolean(this._scalarClient && canUserModify);
|
||||
const showDeleteButton = (this.props.showDelete === undefined || this.props.showDelete) && canUserModify;
|
||||
const showCancelButton = (this.props.showCancel === undefined || this.props.showCancel) && !showDeleteButton;
|
||||
// Picture snapshot - only show button when apps are maximised.
|
||||
const showPictureSnapshotButton = this._hasCapability('m.capability.screenshot') && this.props.show;
|
||||
const showMinimiseButton = this.props.showMinimise && this.props.show;
|
||||
const showMaximiseButton = this.props.showMinimise && !this.props.show;
|
||||
|
||||
|
@ -688,41 +721,17 @@ export default class AppTile extends React.Component {
|
|||
{ this.props.showTitle && this._getTileTitle() }
|
||||
</span>
|
||||
<span className="mx_AppTileMenuBarWidgets">
|
||||
{ /* Reload widget */ }
|
||||
{ this.props.showReload && <AccessibleButton
|
||||
className="mx_AppTileMenuBar_iconButton mx_AppTileMenuBar_iconButton_reload"
|
||||
title={_t('Reload widget')}
|
||||
onClick={this._onReloadWidgetClick}
|
||||
/> }
|
||||
{ /* Popout widget */ }
|
||||
{ this.props.showPopout && <AccessibleButton
|
||||
className="mx_AppTileMenuBar_iconButton mx_AppTileMenuBar_iconButton_popout"
|
||||
title={_t('Popout widget')}
|
||||
onClick={this._onPopoutWidgetClick}
|
||||
/> }
|
||||
{ /* Snapshot widget */ }
|
||||
{ showPictureSnapshotButton && <AccessibleButton
|
||||
className="mx_AppTileMenuBar_iconButton mx_AppTileMenuBar_iconButton_snapshot"
|
||||
title={_t('Picture')}
|
||||
onClick={this._onSnapshotClick}
|
||||
/> }
|
||||
{ /* Edit widget */ }
|
||||
{ showEditButton && <AccessibleButton
|
||||
className="mx_AppTileMenuBar_iconButton mx_AppTileMenuBar_iconButton_edit"
|
||||
title={_t('Edit')}
|
||||
onClick={this._onEditClick}
|
||||
/> }
|
||||
{ /* Delete widget */ }
|
||||
{ showDeleteButton && <AccessibleButton
|
||||
className="mx_AppTileMenuBar_iconButton mx_AppTileMenuBar_iconButton_delete"
|
||||
title={_t('Delete widget')}
|
||||
onClick={this._onDeleteClick}
|
||||
/> }
|
||||
{ /* Cancel widget */ }
|
||||
{ showCancelButton && <AccessibleButton
|
||||
className="mx_AppTileMenuBar_iconButton mx_AppTileMenuBar_iconButton_cancel"
|
||||
title={_t('Revoke widget access')}
|
||||
onClick={this._onCancelClick}
|
||||
{ /* Context menu */ }
|
||||
{ <AccessibleButton
|
||||
className="mx_AppTileMenuBar_iconButton mx_AppTileMenuBar_iconButton_menu"
|
||||
title={_t('More options')}
|
||||
onClick={this._onContextMenuClick}
|
||||
/> }
|
||||
</span>
|
||||
</div> }
|
||||
|
|
|
@ -17,7 +17,6 @@ limitations under the License.
|
|||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import sdk from '../../../index';
|
||||
import Promise from 'bluebird';
|
||||
|
||||
/**
|
||||
* A component which wraps an EditableText, with a spinner while updates take
|
||||
|
@ -51,7 +50,7 @@ export default class EditableTextContainer extends React.Component {
|
|||
|
||||
this.setState({busy: true});
|
||||
|
||||
this.props.getInitialValue().done(
|
||||
this.props.getInitialValue().then(
|
||||
(result) => {
|
||||
if (this._unmounted) { return; }
|
||||
this.setState({
|
||||
|
@ -83,7 +82,7 @@ export default class EditableTextContainer extends React.Component {
|
|||
errorString: null,
|
||||
});
|
||||
|
||||
this.props.onSubmit(value).done(
|
||||
this.props.onSubmit(value).then(
|
||||
() => {
|
||||
if (this._unmounted) { return; }
|
||||
this.setState({
|
||||
|
|
|
@ -54,7 +54,7 @@ export default class ErrorBoundary extends React.PureComponent {
|
|||
if (!PlatformPeg.get()) return;
|
||||
|
||||
MatrixClientPeg.get().stopClient();
|
||||
MatrixClientPeg.get().store.deleteAllData().done(() => {
|
||||
MatrixClientPeg.get().store.deleteAllData().then(() => {
|
||||
PlatformPeg.get().reload();
|
||||
});
|
||||
};
|
||||
|
|
28
src/components/views/elements/FormButton.js
Normal file
28
src/components/views/elements/FormButton.js
Normal file
|
@ -0,0 +1,28 @@
|
|||
/*
|
||||
Copyright 2019 The Matrix.org Foundation C.I.C.
|
||||
|
||||
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 AccessibleButton from "./AccessibleButton";
|
||||
|
||||
export default function FormButton(props) {
|
||||
const {className, label, kind, ...restProps} = props;
|
||||
const newClassName = (className || "") + " mx_FormButton";
|
||||
const allProps = Object.assign({}, restProps,
|
||||
{className: newClassName, kind: kind || "primary", children: [label]});
|
||||
return React.createElement(AccessibleButton, allProps);
|
||||
}
|
||||
|
||||
FormButton.propTypes = AccessibleButton.propTypes;
|
|
@ -84,7 +84,7 @@ export default class ImageView extends React.Component {
|
|||
title: _t('Error'),
|
||||
description: _t('You cannot delete this image. (%(code)s)', {code: code}),
|
||||
});
|
||||
}).done();
|
||||
});
|
||||
},
|
||||
});
|
||||
};
|
||||
|
|
|
@ -49,7 +49,7 @@ export default class LanguageDropdown extends React.Component {
|
|||
this.setState({langs});
|
||||
}).catch(() => {
|
||||
this.setState({langs: ['en']});
|
||||
}).done();
|
||||
});
|
||||
|
||||
if (!this.props.value) {
|
||||
// If no value is given, we start with the first
|
||||
|
|
|
@ -100,7 +100,9 @@ module.exports = createReactClass({
|
|||
const parent = ReactDOM.findDOMNode(this).parentNode;
|
||||
let style = {};
|
||||
style = this._updatePosition(style);
|
||||
style.display = "block";
|
||||
// Hide the entire container when not visible. This prevents flashing of the tooltip
|
||||
// if it is not meant to be visible on first mount.
|
||||
style.display = this.props.visible ? "block" : "none";
|
||||
|
||||
const tooltipClasses = classNames("mx_Tooltip", this.props.tooltipClassName, {
|
||||
"mx_Tooltip_visible": this.props.visible,
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue