mirror of https://github.com/vector-im/riot-web
Merge pull request #3646 from matrix-org/travis/integration-manager-opt
Add an option to disable the use of integration managers for provisioningpull/21833/head
commit
6597e0bd42
|
@ -173,7 +173,7 @@
|
||||||
@import "./views/rooms/_WhoIsTypingTile.scss";
|
@import "./views/rooms/_WhoIsTypingTile.scss";
|
||||||
@import "./views/settings/_DevicesPanel.scss";
|
@import "./views/settings/_DevicesPanel.scss";
|
||||||
@import "./views/settings/_EmailAddresses.scss";
|
@import "./views/settings/_EmailAddresses.scss";
|
||||||
@import "./views/settings/_IntegrationsManager.scss";
|
@import "./views/settings/_IntegrationManager.scss";
|
||||||
@import "./views/settings/_KeyBackupPanel.scss";
|
@import "./views/settings/_KeyBackupPanel.scss";
|
||||||
@import "./views/settings/_Notifications.scss";
|
@import "./views/settings/_Notifications.scss";
|
||||||
@import "./views/settings/_PhoneNumbers.scss";
|
@import "./views/settings/_PhoneNumbers.scss";
|
||||||
|
|
|
@ -16,10 +16,10 @@ limitations under the License.
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* To avoid visual glitching of two modals stacking briefly, we customise the
|
* To avoid visual glitching of two modals stacking briefly, we customise the
|
||||||
* terms dialog sizing when it will appear for the integrations manager so that
|
* terms dialog sizing when it will appear for the integration manager so that
|
||||||
* it gets the same basic size as the IM's own modal.
|
* it gets the same basic size as the IM's own modal.
|
||||||
*/
|
*/
|
||||||
.mx_TermsDialog_forIntegrationsManager .mx_Dialog {
|
.mx_TermsDialog_forIntegrationManager .mx_Dialog {
|
||||||
width: 60%;
|
width: 60%;
|
||||||
height: 70%;
|
height: 70%;
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
|
|
|
@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
|
||||||
limitations under the License.
|
limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
.mx_IntegrationsManager .mx_Dialog {
|
.mx_IntegrationManager .mx_Dialog {
|
||||||
width: 60%;
|
width: 60%;
|
||||||
height: 70%;
|
height: 70%;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
|
@ -23,22 +23,22 @@ limitations under the License.
|
||||||
max-height: initial;
|
max-height: initial;
|
||||||
}
|
}
|
||||||
|
|
||||||
.mx_IntegrationsManager iframe {
|
.mx_IntegrationManager iframe {
|
||||||
background-color: #fff;
|
background-color: #fff;
|
||||||
border: 0px;
|
border: 0px;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
.mx_IntegrationsManager_loading h3 {
|
.mx_IntegrationManager_loading h3 {
|
||||||
text-align: center;
|
text-align: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
.mx_IntegrationsManager_error {
|
.mx_IntegrationManager_error {
|
||||||
text-align: center;
|
text-align: center;
|
||||||
padding-top: 20px;
|
padding-top: 20px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.mx_IntegrationsManager_error h3 {
|
.mx_IntegrationManager_error h3 {
|
||||||
color: $warning-color;
|
color: $warning-color;
|
||||||
}
|
}
|
|
@ -14,10 +14,6 @@ See the License for the specific language governing permissions and
|
||||||
limitations under the License.
|
limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
.mx_SetIntegrationManager .mx_Field_input {
|
|
||||||
@mixin mx_Settings_fullWidthField;
|
|
||||||
}
|
|
||||||
|
|
||||||
.mx_SetIntegrationManager {
|
.mx_SetIntegrationManager {
|
||||||
margin-top: 10px;
|
margin-top: 10px;
|
||||||
margin-bottom: 10px;
|
margin-bottom: 10px;
|
||||||
|
@ -32,6 +28,10 @@ limitations under the License.
|
||||||
padding-left: 5px;
|
padding-left: 5px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.mx_SetIntegrationManager_tooltip {
|
.mx_SetIntegrationManager .mx_ToggleSwitch {
|
||||||
@mixin mx_Settings_tooltip;
|
display: inline-block;
|
||||||
|
float: right;
|
||||||
|
top: 9px;
|
||||||
|
|
||||||
|
@mixin mx_Settings_fullWidthField;
|
||||||
}
|
}
|
||||||
|
|
|
@ -382,7 +382,7 @@ function _onAction(payload) {
|
||||||
}
|
}
|
||||||
|
|
||||||
async function _startCallApp(roomId, type) {
|
async function _startCallApp(roomId, type) {
|
||||||
// check for a working integrations manager. Technically we could put
|
// check for a working integration manager. Technically we could put
|
||||||
// the state event in anyway, but the resulting widget would then not
|
// the state event in anyway, but the resulting widget would then not
|
||||||
// work for us. Better that the user knows before everyone else in the
|
// work for us. Better that the user knows before everyone else in the
|
||||||
// room sees it.
|
// room sees it.
|
||||||
|
|
|
@ -0,0 +1,57 @@
|
||||||
|
/*
|
||||||
|
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 PropTypes from 'prop-types';
|
||||||
|
import {_t} from "../../../languageHandler";
|
||||||
|
import sdk from "../../../index";
|
||||||
|
import dis from '../../../dispatcher';
|
||||||
|
|
||||||
|
export default class IntegrationsDisabledDialog extends React.Component {
|
||||||
|
static propTypes = {
|
||||||
|
onFinished: PropTypes.func.isRequired,
|
||||||
|
};
|
||||||
|
|
||||||
|
_onAcknowledgeClick = () => {
|
||||||
|
this.props.onFinished();
|
||||||
|
};
|
||||||
|
|
||||||
|
_onOpenSettingsClick = () => {
|
||||||
|
this.props.onFinished();
|
||||||
|
dis.dispatch({action: "view_user_settings"});
|
||||||
|
};
|
||||||
|
|
||||||
|
render() {
|
||||||
|
const BaseDialog = sdk.getComponent('views.dialogs.BaseDialog');
|
||||||
|
const DialogButtons = sdk.getComponent('views.elements.DialogButtons');
|
||||||
|
|
||||||
|
return (
|
||||||
|
<BaseDialog className='mx_IntegrationsDisabledDialog' hasCancel={true}
|
||||||
|
onFinished={this.props.onFinished}
|
||||||
|
title={_t("Integrations are disabled")}>
|
||||||
|
<div className='mx_IntegrationsDisabledDialog_content'>
|
||||||
|
<p>{_t("Enable 'Manage Integrations' in Settings to do this.")}</p>
|
||||||
|
</div>
|
||||||
|
<DialogButtons
|
||||||
|
primaryButton={_t("Settings")}
|
||||||
|
onPrimaryButtonClick={this._onOpenSettingsClick}
|
||||||
|
cancelButton={_t("OK")}
|
||||||
|
onCancel={this._onAcknowledgeClick}
|
||||||
|
/>
|
||||||
|
</BaseDialog>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,55 @@
|
||||||
|
/*
|
||||||
|
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 PropTypes from 'prop-types';
|
||||||
|
import {_t} from "../../../languageHandler";
|
||||||
|
import sdk from "../../../index";
|
||||||
|
|
||||||
|
export default class IntegrationsImpossibleDialog extends React.Component {
|
||||||
|
static propTypes = {
|
||||||
|
onFinished: PropTypes.func.isRequired,
|
||||||
|
};
|
||||||
|
|
||||||
|
_onAcknowledgeClick = () => {
|
||||||
|
this.props.onFinished();
|
||||||
|
};
|
||||||
|
|
||||||
|
render() {
|
||||||
|
const BaseDialog = sdk.getComponent('views.dialogs.BaseDialog');
|
||||||
|
const DialogButtons = sdk.getComponent('views.elements.DialogButtons');
|
||||||
|
|
||||||
|
return (
|
||||||
|
<BaseDialog className='mx_IntegrationsImpossibleDialog' hasCancel={false}
|
||||||
|
onFinished={this.props.onFinished}
|
||||||
|
title={_t("Integrations not allowed")}>
|
||||||
|
<div className='mx_IntegrationsImpossibleDialog_content'>
|
||||||
|
<p>
|
||||||
|
{_t(
|
||||||
|
"Your Riot doesn't allow you to use an Integration Manager to do this. " +
|
||||||
|
"Please contact an admin.",
|
||||||
|
)}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<DialogButtons
|
||||||
|
primaryButton={_t("OK")}
|
||||||
|
onPrimaryButtonClick={this._onAcknowledgeClick}
|
||||||
|
hasCancel={false}
|
||||||
|
/>
|
||||||
|
</BaseDialog>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
|
@ -82,10 +82,10 @@ export default class TabbedIntegrationManagerDialog extends React.Component {
|
||||||
|
|
||||||
client.setTermsInteractionCallback((policyInfo, agreedUrls) => {
|
client.setTermsInteractionCallback((policyInfo, agreedUrls) => {
|
||||||
// To avoid visual glitching of two modals stacking briefly, we customise the
|
// To avoid visual glitching of two modals stacking briefly, we customise the
|
||||||
// terms dialog sizing when it will appear for the integrations manager so that
|
// terms dialog sizing when it will appear for the integration manager so that
|
||||||
// it gets the same basic size as the IM's own modal.
|
// it gets the same basic size as the IM's own modal.
|
||||||
return dialogTermsInteractionCallback(
|
return dialogTermsInteractionCallback(
|
||||||
policyInfo, agreedUrls, 'mx_TermsDialog_forIntegrationsManager',
|
policyInfo, agreedUrls, 'mx_TermsDialog_forIntegrationManager',
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -139,7 +139,7 @@ export default class TabbedIntegrationManagerDialog extends React.Component {
|
||||||
}
|
}
|
||||||
|
|
||||||
_renderTab() {
|
_renderTab() {
|
||||||
const IntegrationsManager = sdk.getComponent("views.settings.IntegrationsManager");
|
const IntegrationManager = sdk.getComponent("views.settings.IntegrationManager");
|
||||||
let uiUrl = null;
|
let uiUrl = null;
|
||||||
if (this.state.currentScalarClient) {
|
if (this.state.currentScalarClient) {
|
||||||
uiUrl = this.state.currentScalarClient.getScalarInterfaceUrlForRoom(
|
uiUrl = this.state.currentScalarClient.getScalarInterfaceUrlForRoom(
|
||||||
|
@ -148,7 +148,7 @@ export default class TabbedIntegrationManagerDialog extends React.Component {
|
||||||
this.props.integrationId,
|
this.props.integrationId,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
return <IntegrationsManager
|
return <IntegrationManager
|
||||||
configured={true}
|
configured={true}
|
||||||
loading={this.state.currentLoading}
|
loading={this.state.currentLoading}
|
||||||
connected={this.state.currentConnected}
|
connected={this.state.currentConnected}
|
||||||
|
|
|
@ -86,7 +86,7 @@ export default class TermsDialog extends React.PureComponent {
|
||||||
case Matrix.SERVICE_TYPES.IS:
|
case Matrix.SERVICE_TYPES.IS:
|
||||||
return <div>{_t("Identity Server")}<br />({host})</div>;
|
return <div>{_t("Identity Server")}<br />({host})</div>;
|
||||||
case Matrix.SERVICE_TYPES.IM:
|
case Matrix.SERVICE_TYPES.IM:
|
||||||
return <div>{_t("Integrations Manager")}<br />({host})</div>;
|
return <div>{_t("Integration Manager")}<br />({host})</div>;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -74,10 +74,10 @@ export default class Stickerpicker extends React.Component {
|
||||||
this.forceUpdate();
|
this.forceUpdate();
|
||||||
return this.scalarClient;
|
return this.scalarClient;
|
||||||
}).catch((e) => {
|
}).catch((e) => {
|
||||||
this._imError(_td("Failed to connect to integrations server"), e);
|
this._imError(_td("Failed to connect to integration manager"), e);
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
this._imError(_td("No integrations server is configured to manage stickers with"));
|
IntegrationManagers.sharedInstance().openNoManagerDialog();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -287,12 +287,17 @@ export default class Stickerpicker extends React.Component {
|
||||||
return stickersContent;
|
return stickersContent;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
// Dev note: this isn't jsdoc because it's angry.
|
||||||
|
/*
|
||||||
* Show the sticker picker overlay
|
* Show the sticker picker overlay
|
||||||
* If no stickerpacks have been added, show a link to the integration manager add sticker packs page.
|
* If no stickerpacks have been added, show a link to the integration manager add sticker packs page.
|
||||||
* @param {Event} e Event that triggered the function
|
|
||||||
*/
|
*/
|
||||||
_onShowStickersClick(e) {
|
_onShowStickersClick(e) {
|
||||||
|
if (!SettingsStore.getValue("integrationProvisioning")) {
|
||||||
|
// Intercept this case and spawn a warning.
|
||||||
|
return IntegrationManagers.sharedInstance().showDisabledDialog();
|
||||||
|
}
|
||||||
|
|
||||||
// XXX: Simplify by using a context menu that is positioned relative to the sticker picker button
|
// XXX: Simplify by using a context menu that is positioned relative to the sticker picker button
|
||||||
|
|
||||||
const buttonRect = e.target.getBoundingClientRect();
|
const buttonRect = e.target.getBoundingClientRect();
|
||||||
|
@ -346,7 +351,7 @@ export default class Stickerpicker extends React.Component {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Launch the integrations manager on the stickers integration page
|
* Launch the integration manager on the stickers integration page
|
||||||
*/
|
*/
|
||||||
_launchManageIntegrations() {
|
_launchManageIntegrations() {
|
||||||
// TODO: Open the right integration manager for the widget
|
// TODO: Open the right integration manager for the widget
|
||||||
|
|
|
@ -21,12 +21,9 @@ import sdk from '../../../index';
|
||||||
import { _t } from '../../../languageHandler';
|
import { _t } from '../../../languageHandler';
|
||||||
import dis from '../../../dispatcher';
|
import dis from '../../../dispatcher';
|
||||||
|
|
||||||
export default class IntegrationsManager extends React.Component {
|
export default class IntegrationManager extends React.Component {
|
||||||
static propTypes = {
|
static propTypes = {
|
||||||
// false to display an error saying that there is no integrations manager configured
|
// false to display an error saying that we couldn't connect to the integration manager
|
||||||
configured: PropTypes.bool.isRequired,
|
|
||||||
|
|
||||||
// false to display an error saying that we couldn't connect to the integrations manager
|
|
||||||
connected: PropTypes.bool.isRequired,
|
connected: PropTypes.bool.isRequired,
|
||||||
|
|
||||||
// true to display a loading spinner
|
// true to display a loading spinner
|
||||||
|
@ -40,7 +37,6 @@ export default class IntegrationsManager extends React.Component {
|
||||||
};
|
};
|
||||||
|
|
||||||
static defaultProps = {
|
static defaultProps = {
|
||||||
configured: true,
|
|
||||||
connected: true,
|
connected: true,
|
||||||
loading: false,
|
loading: false,
|
||||||
};
|
};
|
||||||
|
@ -70,20 +66,11 @@ export default class IntegrationsManager extends React.Component {
|
||||||
};
|
};
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
if (!this.props.configured) {
|
|
||||||
return (
|
|
||||||
<div className='mx_IntegrationsManager_error'>
|
|
||||||
<h3>{_t("No integrations server configured")}</h3>
|
|
||||||
<p>{_t("This Riot instance does not have an integrations server configured.")}</p>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.props.loading) {
|
if (this.props.loading) {
|
||||||
const Spinner = sdk.getComponent("elements.Spinner");
|
const Spinner = sdk.getComponent("elements.Spinner");
|
||||||
return (
|
return (
|
||||||
<div className='mx_IntegrationsManager_loading'>
|
<div className='mx_IntegrationManager_loading'>
|
||||||
<h3>{_t("Connecting to integrations server...")}</h3>
|
<h3>{_t("Connecting to integration manager...")}</h3>
|
||||||
<Spinner />
|
<Spinner />
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
@ -91,9 +78,9 @@ export default class IntegrationsManager extends React.Component {
|
||||||
|
|
||||||
if (!this.props.connected) {
|
if (!this.props.connected) {
|
||||||
return (
|
return (
|
||||||
<div className='mx_IntegrationsManager_error'>
|
<div className='mx_IntegrationManager_error'>
|
||||||
<h3>{_t("Cannot connect to integrations server")}</h3>
|
<h3>{_t("Cannot connect to integration manager")}</h3>
|
||||||
<p>{_t("The integrations server is offline or it cannot reach your homeserver.")}</p>
|
<p>{_t("The integration manager is offline or it cannot reach your homeserver.")}</p>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
|
@ -16,13 +16,9 @@ limitations under the License.
|
||||||
|
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import {_t} from "../../../languageHandler";
|
import {_t} from "../../../languageHandler";
|
||||||
import sdk from '../../../index';
|
|
||||||
import Field from "../elements/Field";
|
|
||||||
import {IntegrationManagers} from "../../../integrations/IntegrationManagers";
|
import {IntegrationManagers} from "../../../integrations/IntegrationManagers";
|
||||||
import MatrixClientPeg from "../../../MatrixClientPeg";
|
import sdk from '../../../index';
|
||||||
import {SERVICE_TYPES} from "matrix-js-sdk";
|
import SettingsStore, {SettingLevel} from "../../../settings/SettingsStore";
|
||||||
import {IntegrationManagerInstance} from "../../../integrations/IntegrationManagerInstance";
|
|
||||||
import Modal from "../../../Modal";
|
|
||||||
|
|
||||||
export default class SetIntegrationManager extends React.Component {
|
export default class SetIntegrationManager extends React.Component {
|
||||||
constructor() {
|
constructor() {
|
||||||
|
@ -32,135 +28,23 @@ export default class SetIntegrationManager extends React.Component {
|
||||||
|
|
||||||
this.state = {
|
this.state = {
|
||||||
currentManager,
|
currentManager,
|
||||||
url: "", // user-entered text
|
provisioningEnabled: SettingsStore.getValue("integrationProvisioning"),
|
||||||
error: null,
|
|
||||||
busy: false,
|
|
||||||
checking: false,
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
_onUrlChanged = (ev) => {
|
onProvisioningToggled = () => {
|
||||||
const u = ev.target.value;
|
const current = this.state.provisioningEnabled;
|
||||||
this.setState({url: u});
|
SettingsStore.setValue("integrationProvisioning", null, SettingLevel.ACCOUNT, !current).catch(err => {
|
||||||
};
|
console.error("Error changing integration manager provisioning");
|
||||||
|
console.error(err);
|
||||||
|
|
||||||
_getTooltip = () => {
|
this.setState({provisioningEnabled: current});
|
||||||
if (this.state.checking) {
|
});
|
||||||
const InlineSpinner = sdk.getComponent('views.elements.InlineSpinner');
|
this.setState({provisioningEnabled: !current});
|
||||||
return <div>
|
|
||||||
<InlineSpinner />
|
|
||||||
{ _t("Checking server") }
|
|
||||||
</div>;
|
|
||||||
} else if (this.state.error) {
|
|
||||||
return <span className="warning">{this.state.error}</span>;
|
|
||||||
} else {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
_canChange = () => {
|
|
||||||
return !!this.state.url && !this.state.busy;
|
|
||||||
};
|
|
||||||
|
|
||||||
_continueTerms = async (manager) => {
|
|
||||||
try {
|
|
||||||
await IntegrationManagers.sharedInstance().overwriteManagerOnAccount(manager);
|
|
||||||
this.setState({
|
|
||||||
busy: false,
|
|
||||||
error: null,
|
|
||||||
currentManager: IntegrationManagers.sharedInstance().getPrimaryManager(),
|
|
||||||
url: "", // clear input
|
|
||||||
});
|
|
||||||
} catch (e) {
|
|
||||||
console.error(e);
|
|
||||||
this.setState({
|
|
||||||
busy: false,
|
|
||||||
error: _t("Failed to update integration manager"),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
_setManager = async (ev) => {
|
|
||||||
// Don't reload the page when the user hits enter in the form.
|
|
||||||
ev.preventDefault();
|
|
||||||
ev.stopPropagation();
|
|
||||||
|
|
||||||
this.setState({busy: true, checking: true, error: null});
|
|
||||||
|
|
||||||
let offline = false;
|
|
||||||
let manager: IntegrationManagerInstance;
|
|
||||||
try {
|
|
||||||
manager = await IntegrationManagers.sharedInstance().tryDiscoverManager(this.state.url);
|
|
||||||
offline = !manager; // no manager implies offline
|
|
||||||
} catch (e) {
|
|
||||||
console.error(e);
|
|
||||||
offline = true; // probably a connection error
|
|
||||||
}
|
|
||||||
if (offline) {
|
|
||||||
this.setState({
|
|
||||||
busy: false,
|
|
||||||
checking: false,
|
|
||||||
error: _t("Integration manager offline or not accessible."),
|
|
||||||
});
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Test the manager (causes terms of service prompt if agreement is needed)
|
|
||||||
// We also cancel the tooltip at this point so it doesn't collide with the dialog.
|
|
||||||
this.setState({checking: false});
|
|
||||||
try {
|
|
||||||
const client = manager.getScalarClient();
|
|
||||||
await client.connect();
|
|
||||||
} catch (e) {
|
|
||||||
console.error(e);
|
|
||||||
this.setState({
|
|
||||||
busy: false,
|
|
||||||
error: _t("Terms of service not accepted or the integration manager is invalid."),
|
|
||||||
});
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Specifically request the terms of service to see if there are any.
|
|
||||||
// The above won't trigger a terms of service check if there are no terms to
|
|
||||||
// sign, so when there's no terms at all we need to ensure we tell the user.
|
|
||||||
let hasTerms = true;
|
|
||||||
try {
|
|
||||||
const terms = await MatrixClientPeg.get().getTerms(SERVICE_TYPES.IM, manager.trimmedApiUrl);
|
|
||||||
hasTerms = terms && terms['policies'] && Object.keys(terms['policies']).length > 0;
|
|
||||||
} catch (e) {
|
|
||||||
// Assume errors mean there are no terms. This could be a 404, 500, etc
|
|
||||||
console.error(e);
|
|
||||||
hasTerms = false;
|
|
||||||
}
|
|
||||||
if (!hasTerms) {
|
|
||||||
this.setState({busy: false});
|
|
||||||
const QuestionDialog = sdk.getComponent("views.dialogs.QuestionDialog");
|
|
||||||
Modal.createTrackedDialog('No Terms Warning', '', QuestionDialog, {
|
|
||||||
title: _t("Integration manager has no terms of service"),
|
|
||||||
description: (
|
|
||||||
<div>
|
|
||||||
<span className="warning">
|
|
||||||
{_t("The integration manager you have chosen does not have any terms of service.")}
|
|
||||||
</span>
|
|
||||||
<span>
|
|
||||||
{_t("Only continue if you trust the owner of the server.")}
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
),
|
|
||||||
button: _t("Continue"),
|
|
||||||
onFinished: async (confirmed) => {
|
|
||||||
if (!confirmed) return;
|
|
||||||
this._continueTerms(manager);
|
|
||||||
},
|
|
||||||
});
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
this._continueTerms(manager);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const AccessibleButton = sdk.getComponent('views.elements.AccessibleButton');
|
const ToggleSwitch = sdk.getComponent("views.elements.ToggleSwitch");
|
||||||
|
|
||||||
const currentManager = this.state.currentManager;
|
const currentManager = this.state.currentManager;
|
||||||
let managerName;
|
let managerName;
|
||||||
|
@ -168,45 +52,32 @@ export default class SetIntegrationManager extends React.Component {
|
||||||
if (currentManager) {
|
if (currentManager) {
|
||||||
managerName = `(${currentManager.name})`;
|
managerName = `(${currentManager.name})`;
|
||||||
bodyText = _t(
|
bodyText = _t(
|
||||||
"You are currently using <b>%(serverName)s</b> to manage your bots, widgets, " +
|
"Use an Integration Manager <b>(%(serverName)s)</b> to manage bots, widgets, " +
|
||||||
"and sticker packs.",
|
"and sticker packs.",
|
||||||
{serverName: currentManager.name},
|
{serverName: currentManager.name},
|
||||||
{ b: sub => <b>{sub}</b> },
|
{ b: sub => <b>{sub}</b> },
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
bodyText = _t(
|
bodyText = _t("Use an Integration Manager to manage bots, widgets, and sticker packs.");
|
||||||
"Add which integration manager you want to manage your bots, widgets, " +
|
|
||||||
"and sticker packs.",
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<form className="mx_SettingsTab_section mx_SetIntegrationManager" onSubmit={this._setManager}>
|
<div className='mx_SetIntegrationManager'>
|
||||||
<div className="mx_SettingsTab_heading">
|
<div className="mx_SettingsTab_heading">
|
||||||
<span>{_t("Integration Manager")}</span>
|
<span>{_t("Integrations")}</span>
|
||||||
<span className="mx_SettingsTab_subheading">{managerName}</span>
|
<span className="mx_SettingsTab_subheading">{managerName}</span>
|
||||||
|
<ToggleSwitch checked={this.state.provisioningEnabled} onChange={this.onProvisioningToggled} />
|
||||||
</div>
|
</div>
|
||||||
<span className="mx_SettingsTab_subsectionText">
|
<span className="mx_SettingsTab_subsectionText">
|
||||||
{bodyText}
|
{bodyText}
|
||||||
|
<br />
|
||||||
|
<br />
|
||||||
|
{_t(
|
||||||
|
"Integration Managers receive configuration data, and can modify widgets, " +
|
||||||
|
"send room invites, and set power levels on your behalf.",
|
||||||
|
)}
|
||||||
</span>
|
</span>
|
||||||
<Field
|
</div>
|
||||||
label={_t("Enter a new integration manager")}
|
|
||||||
id="mx_SetIntegrationManager_newUrl"
|
|
||||||
type="text" value={this.state.url}
|
|
||||||
autoComplete="off"
|
|
||||||
onChange={this._onUrlChanged}
|
|
||||||
tooltipContent={this._getTooltip()}
|
|
||||||
tooltipClassName="mx_SetIntegrationManager_tooltip"
|
|
||||||
disabled={this.state.busy}
|
|
||||||
flagInvalid={!!this.state.error}
|
|
||||||
/>
|
|
||||||
<AccessibleButton
|
|
||||||
kind="primary_sm"
|
|
||||||
type="submit"
|
|
||||||
disabled={!this._canChange()}
|
|
||||||
onClick={this._setManager}
|
|
||||||
>{_t("Change")}</AccessibleButton>
|
|
||||||
</form>
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -507,11 +507,9 @@
|
||||||
"Failed to set display name": "Failed to set display name",
|
"Failed to set display name": "Failed to set display name",
|
||||||
"Disable Notifications": "Disable Notifications",
|
"Disable Notifications": "Disable Notifications",
|
||||||
"Enable Notifications": "Enable Notifications",
|
"Enable Notifications": "Enable Notifications",
|
||||||
"No integrations server configured": "No integrations server configured",
|
"Connecting to integration manager...": "Connecting to integration manager...",
|
||||||
"This Riot instance does not have an integrations server configured.": "This Riot instance does not have an integrations server configured.",
|
"Cannot connect to integration manager": "Cannot connect to integration manager",
|
||||||
"Connecting to integrations server...": "Connecting to integrations server...",
|
"The integration manager is offline or it cannot reach your homeserver.": "The integration manager is offline or it cannot reach your homeserver.",
|
||||||
"Cannot connect to integrations server": "Cannot connect to integrations server",
|
|
||||||
"The integrations server is offline or it cannot reach your homeserver.": "The integrations server is offline or it cannot reach your homeserver.",
|
|
||||||
"Delete Backup": "Delete Backup",
|
"Delete Backup": "Delete Backup",
|
||||||
"Are you sure? You will lose your encrypted messages if your keys are not backed up properly.": "Are you sure? You will lose your encrypted messages if your keys are not backed up properly.",
|
"Are you sure? You will lose your encrypted messages if your keys are not backed up properly.": "Are you sure? You will lose your encrypted messages if your keys are not backed up properly.",
|
||||||
"Encrypted messages are secured with end-to-end encryption. Only you and the recipient(s) have the keys to read these messages.": "Encrypted messages are secured with end-to-end encryption. Only you and the recipient(s) have the keys to read these messages.",
|
"Encrypted messages are secured with end-to-end encryption. Only you and the recipient(s) have the keys to read these messages.": "Encrypted messages are secured with end-to-end encryption. Only you and the recipient(s) have the keys to read these messages.",
|
||||||
|
@ -598,15 +596,10 @@
|
||||||
"Do not use an identity server": "Do not use an identity server",
|
"Do not use an identity server": "Do not use an identity server",
|
||||||
"Enter a new identity server": "Enter a new identity server",
|
"Enter a new identity server": "Enter a new identity server",
|
||||||
"Change": "Change",
|
"Change": "Change",
|
||||||
"Failed to update integration manager": "Failed to update integration manager",
|
"Use an Integration Manager <b>(%(serverName)s)</b> to manage bots, widgets, and sticker packs.": "Use an Integration Manager <b>(%(serverName)s)</b> to manage bots, widgets, and sticker packs.",
|
||||||
"Integration manager offline or not accessible.": "Integration manager offline or not accessible.",
|
"Use an Integration Manager to manage bots, widgets, and sticker packs.": "Use an Integration Manager to manage bots, widgets, and sticker packs.",
|
||||||
"Terms of service not accepted or the integration manager is invalid.": "Terms of service not accepted or the integration manager is invalid.",
|
"Integrations": "Integrations",
|
||||||
"Integration manager has no terms of service": "Integration manager has no terms of service",
|
"Integration Managers receive configuration data, and can modify widgets, send room invites, and set power levels on your behalf.": "Integration Managers receive configuration data, and can modify widgets, send room invites, and set power levels on your behalf.",
|
||||||
"The integration manager you have chosen does not have any terms of service.": "The integration manager you have chosen does not have any terms of service.",
|
|
||||||
"You are currently using <b>%(serverName)s</b> to manage your bots, widgets, and sticker packs.": "You are currently using <b>%(serverName)s</b> to manage your bots, widgets, and sticker packs.",
|
|
||||||
"Add which integration manager you want to manage your bots, widgets, and sticker packs.": "Add which integration manager you want to manage your bots, widgets, and sticker packs.",
|
|
||||||
"Integration Manager": "Integration Manager",
|
|
||||||
"Enter a new integration manager": "Enter a new integration manager",
|
|
||||||
"Flair": "Flair",
|
"Flair": "Flair",
|
||||||
"Failed to change password. Is your password correct?": "Failed to change password. Is your password correct?",
|
"Failed to change password. Is your password correct?": "Failed to change password. Is your password correct?",
|
||||||
"Success": "Success",
|
"Success": "Success",
|
||||||
|
@ -1024,8 +1017,7 @@
|
||||||
"numbered-list": "numbered-list",
|
"numbered-list": "numbered-list",
|
||||||
"Show Text Formatting Toolbar": "Show Text Formatting Toolbar",
|
"Show Text Formatting Toolbar": "Show Text Formatting Toolbar",
|
||||||
"Hide Text Formatting Toolbar": "Hide Text Formatting Toolbar",
|
"Hide Text Formatting Toolbar": "Hide Text Formatting Toolbar",
|
||||||
"Failed to connect to integrations server": "Failed to connect to integrations server",
|
"Failed to connect to integration manager": "Failed to connect to integration manager",
|
||||||
"No integrations server is configured to manage stickers with": "No integrations server is configured to manage stickers with",
|
|
||||||
"You don't currently have any stickerpacks enabled": "You don't currently have any stickerpacks enabled",
|
"You don't currently have any stickerpacks enabled": "You don't currently have any stickerpacks enabled",
|
||||||
"Add some now": "Add some now",
|
"Add some now": "Add some now",
|
||||||
"Stickerpack": "Stickerpack",
|
"Stickerpack": "Stickerpack",
|
||||||
|
@ -1397,6 +1389,10 @@
|
||||||
"Verifying this user will mark their device as trusted, and also mark your device as trusted to them.": "Verifying this user will mark their device as trusted, and also mark your device as trusted to them.",
|
"Verifying this user will mark their device as trusted, and also mark your device as trusted to them.": "Verifying this user will mark their device as trusted, and also mark your device as trusted to them.",
|
||||||
"Waiting for partner to confirm...": "Waiting for partner to confirm...",
|
"Waiting for partner to confirm...": "Waiting for partner to confirm...",
|
||||||
"Incoming Verification Request": "Incoming Verification Request",
|
"Incoming Verification Request": "Incoming Verification Request",
|
||||||
|
"Integrations are disabled": "Integrations are disabled",
|
||||||
|
"Enable 'Manage Integrations' in Settings to do this.": "Enable 'Manage Integrations' in Settings to do this.",
|
||||||
|
"Integrations not allowed": "Integrations not allowed",
|
||||||
|
"Your Riot doesn't allow you to use an Integration Manager to do this. Please contact an admin.": "Your Riot doesn't allow you to use an Integration Manager to do this. Please contact an admin.",
|
||||||
"You added a new device '%(displayName)s', which is requesting encryption keys.": "You added a new device '%(displayName)s', which is requesting encryption keys.",
|
"You added a new device '%(displayName)s', which is requesting encryption keys.": "You added a new device '%(displayName)s', which is requesting encryption keys.",
|
||||||
"Your unverified device '%(displayName)s' is requesting encryption keys.": "Your unverified device '%(displayName)s' is requesting encryption keys.",
|
"Your unverified device '%(displayName)s' is requesting encryption keys.": "Your unverified device '%(displayName)s' is requesting encryption keys.",
|
||||||
"Start verification": "Start verification",
|
"Start verification": "Start verification",
|
||||||
|
@ -1474,7 +1470,7 @@
|
||||||
"Missing session data": "Missing session data",
|
"Missing session data": "Missing session data",
|
||||||
"Some session data, including encrypted message keys, is missing. Sign out and sign in to fix this, restoring keys from backup.": "Some session data, including encrypted message keys, is missing. Sign out and sign in to fix this, restoring keys from backup.",
|
"Some session data, including encrypted message keys, is missing. Sign out and sign in to fix this, restoring keys from backup.": "Some session data, including encrypted message keys, is missing. Sign out and sign in to fix this, restoring keys from backup.",
|
||||||
"Your browser likely removed this data when running low on disk space.": "Your browser likely removed this data when running low on disk space.",
|
"Your browser likely removed this data when running low on disk space.": "Your browser likely removed this data when running low on disk space.",
|
||||||
"Integrations Manager": "Integrations Manager",
|
"Integration Manager": "Integration Manager",
|
||||||
"Find others by phone or email": "Find others by phone or email",
|
"Find others by phone or email": "Find others by phone or email",
|
||||||
"Be found by phone or email": "Be found by phone or email",
|
"Be found by phone or email": "Be found by phone or email",
|
||||||
"Use bots, bridges, widgets and sticker packs": "Use bots, bridges, widgets and sticker packs",
|
"Use bots, bridges, widgets and sticker packs": "Use bots, bridges, widgets and sticker packs",
|
||||||
|
|
|
@ -20,6 +20,8 @@ import {dialogTermsInteractionCallback, TermsNotSignedError} from "../Terms";
|
||||||
import type {Room} from "matrix-js-sdk";
|
import type {Room} from "matrix-js-sdk";
|
||||||
import Modal from '../Modal';
|
import Modal from '../Modal';
|
||||||
import url from 'url';
|
import url from 'url';
|
||||||
|
import SettingsStore from "../settings/SettingsStore";
|
||||||
|
import {IntegrationManagers} from "./IntegrationManagers";
|
||||||
|
|
||||||
export const KIND_ACCOUNT = "account";
|
export const KIND_ACCOUNT = "account";
|
||||||
export const KIND_CONFIG = "config";
|
export const KIND_CONFIG = "config";
|
||||||
|
@ -57,19 +59,23 @@ export class IntegrationManagerInstance {
|
||||||
}
|
}
|
||||||
|
|
||||||
async open(room: Room = null, screen: string = null, integrationId: string = null): void {
|
async open(room: Room = null, screen: string = null, integrationId: string = null): void {
|
||||||
const IntegrationsManager = sdk.getComponent("views.settings.IntegrationsManager");
|
if (!SettingsStore.getValue("integrationProvisioning")) {
|
||||||
|
return IntegrationManagers.sharedInstance().showDisabledDialog();
|
||||||
|
}
|
||||||
|
|
||||||
|
const IntegrationManager = sdk.getComponent("views.settings.IntegrationManager");
|
||||||
const dialog = Modal.createTrackedDialog(
|
const dialog = Modal.createTrackedDialog(
|
||||||
'Integration Manager', '', IntegrationsManager,
|
'Integration Manager', '', IntegrationManager,
|
||||||
{loading: true}, 'mx_IntegrationsManager',
|
{loading: true}, 'mx_IntegrationManager',
|
||||||
);
|
);
|
||||||
|
|
||||||
const client = this.getScalarClient();
|
const client = this.getScalarClient();
|
||||||
client.setTermsInteractionCallback((policyInfo, agreedUrls) => {
|
client.setTermsInteractionCallback((policyInfo, agreedUrls) => {
|
||||||
// To avoid visual glitching of two modals stacking briefly, we customise the
|
// To avoid visual glitching of two modals stacking briefly, we customise the
|
||||||
// terms dialog sizing when it will appear for the integrations manager so that
|
// terms dialog sizing when it will appear for the integration manager so that
|
||||||
// it gets the same basic size as the IM's own modal.
|
// it gets the same basic size as the IM's own modal.
|
||||||
return dialogTermsInteractionCallback(
|
return dialogTermsInteractionCallback(
|
||||||
policyInfo, agreedUrls, 'mx_TermsDialog_forIntegrationsManager',
|
policyInfo, agreedUrls, 'mx_TermsDialog_forIntegrationManager',
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -94,8 +100,8 @@ export class IntegrationManagerInstance {
|
||||||
// Close the old dialog and open a new one
|
// Close the old dialog and open a new one
|
||||||
dialog.close();
|
dialog.close();
|
||||||
Modal.createTrackedDialog(
|
Modal.createTrackedDialog(
|
||||||
'Integration Manager', '', IntegrationsManager,
|
'Integration Manager', '', IntegrationManager,
|
||||||
newProps, 'mx_IntegrationsManager',
|
newProps, 'mx_IntegrationManager',
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,6 +22,7 @@ import type {MatrixClient, MatrixEvent, Room} from "matrix-js-sdk";
|
||||||
import WidgetUtils from "../utils/WidgetUtils";
|
import WidgetUtils from "../utils/WidgetUtils";
|
||||||
import MatrixClientPeg from "../MatrixClientPeg";
|
import MatrixClientPeg from "../MatrixClientPeg";
|
||||||
import {AutoDiscovery} from "matrix-js-sdk";
|
import {AutoDiscovery} from "matrix-js-sdk";
|
||||||
|
import SettingsStore from "../settings/SettingsStore";
|
||||||
|
|
||||||
const HS_MANAGERS_REFRESH_INTERVAL = 8 * 60 * 60 * 1000; // 8 hours
|
const HS_MANAGERS_REFRESH_INTERVAL = 8 * 60 * 60 * 1000; // 8 hours
|
||||||
const KIND_PREFERENCE = [
|
const KIND_PREFERENCE = [
|
||||||
|
@ -172,15 +173,19 @@ export class IntegrationManagers {
|
||||||
}
|
}
|
||||||
|
|
||||||
openNoManagerDialog(): void {
|
openNoManagerDialog(): void {
|
||||||
// TODO: Is it Integrations (plural) or Integration (singular). Singular is easier spoken.
|
const IntegrationsImpossibleDialog = sdk.getComponent("dialogs.IntegrationsImpossibleDialog");
|
||||||
const IntegrationsManager = sdk.getComponent("views.settings.IntegrationsManager");
|
Modal.createTrackedDialog('Integrations impossible', '', IntegrationsImpossibleDialog);
|
||||||
Modal.createTrackedDialog(
|
|
||||||
"Integration Manager", "None", IntegrationsManager,
|
|
||||||
{configured: false}, 'mx_IntegrationsManager',
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
openAll(room: Room = null, screen: string = null, integrationId: string = null): void {
|
openAll(room: Room = null, screen: string = null, integrationId: string = null): void {
|
||||||
|
if (!SettingsStore.getValue("integrationProvisioning")) {
|
||||||
|
return this.showDisabledDialog();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this._managers.length === 0) {
|
||||||
|
return this.openNoManagerDialog();
|
||||||
|
}
|
||||||
|
|
||||||
const TabbedIntegrationManagerDialog = sdk.getComponent("views.dialogs.TabbedIntegrationManagerDialog");
|
const TabbedIntegrationManagerDialog = sdk.getComponent("views.dialogs.TabbedIntegrationManagerDialog");
|
||||||
Modal.createTrackedDialog(
|
Modal.createTrackedDialog(
|
||||||
'Tabbed Integration Manager', '', TabbedIntegrationManagerDialog,
|
'Tabbed Integration Manager', '', TabbedIntegrationManagerDialog,
|
||||||
|
@ -188,6 +193,11 @@ export class IntegrationManagers {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
showDisabledDialog(): void {
|
||||||
|
const IntegrationsDisabledDialog = sdk.getComponent("dialogs.IntegrationsDisabledDialog");
|
||||||
|
Modal.createTrackedDialog('Integrations disabled', '', IntegrationsDisabledDialog);
|
||||||
|
}
|
||||||
|
|
||||||
async overwriteManagerOnAccount(manager: IntegrationManagerInstance) {
|
async overwriteManagerOnAccount(manager: IntegrationManagerInstance) {
|
||||||
// TODO: TravisR - We should be logging out of scalar clients.
|
// TODO: TravisR - We should be logging out of scalar clients.
|
||||||
await WidgetUtils.removeIntegrationManagerWidgets();
|
await WidgetUtils.removeIntegrationManagerWidgets();
|
||||||
|
|
Loading…
Reference in New Issue