Skip to content
This repository has been archived by the owner on Sep 11, 2024. It is now read-only.

Commit

Permalink
Make the Manage Integrations Button defer scalar auth to the manager
Browse files Browse the repository at this point in the history
This moves the responsibility of creating a URL to open from the button (and other components) to the integrations manager dialog itself.

By doing this, we also cut down on scalar API calls because we don't pick up on account information until the user opens the dialog.
  • Loading branch information
turt2live committed Jun 17, 2019
1 parent 6cc443c commit a5f2964
Show file tree
Hide file tree
Showing 5 changed files with 125 additions and 80 deletions.
13 changes: 13 additions & 0 deletions res/css/views/settings/_IntegrationsManager.scss
Original file line number Diff line number Diff line change
Expand Up @@ -29,3 +29,16 @@ limitations under the License.
width: 100%;
height: 100%;
}

.mx_IntegrationsManager_loading h3 {
text-align: center;
}

.mx_IntegrationsManager_error {
text-align: center;
padding-top: 20px;
}

.mx_IntegrationsManager_error h3 {
color: $warning-color;
}
11 changes: 10 additions & 1 deletion src/ScalarAuthClient.js
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,14 @@ class ScalarAuthClient {
this.scalarToken = null;
}

/**
* Determines if setting up a ScalarAuthClient is even possible
* @returns {boolean} true if possible, false otherwise.
*/
static isPossible() {
return SdkConfig.get()['integrations_rest_url'] && SdkConfig.get()['integrations_ui_url'];
}

connect() {
return this.getScalarToken().then((tok) => {
this.scalarToken = tok;
Expand All @@ -41,7 +49,8 @@ class ScalarAuthClient {

// Returns a scalar_token string
getScalarToken() {
const token = window.localStorage.getItem("mx_scalar_token");
let token = this.scalarToken;
if (!token) token = window.localStorage.getItem("mx_scalar_token");

if (!token) {
return this.registerForToken();
Expand Down
87 changes: 14 additions & 73 deletions src/components/views/elements/ManageIntegsButton.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
/*
Copyright 2017 New Vector Ltd
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.
Expand All @@ -17,96 +18,36 @@ limitations under the License.
import React from 'react';
import PropTypes from 'prop-types';
import sdk from '../../../index';
import classNames from 'classnames';
import SdkConfig from '../../../SdkConfig';
import ScalarAuthClient from '../../../ScalarAuthClient';
import ScalarMessaging from '../../../ScalarMessaging';
import Modal from "../../../Modal";
import { _t } from '../../../languageHandler';
import AccessibleButton from './AccessibleButton';

export default class ManageIntegsButton extends React.Component {
constructor(props) {
super(props);

this.state = {
scalarError: null,
};

this.onManageIntegrations = this.onManageIntegrations.bind(this);
}

componentWillMount() {
ScalarMessaging.startListening();
this.scalarClient = null;

if (SdkConfig.get().integrations_ui_url && SdkConfig.get().integrations_rest_url) {
this.scalarClient = new ScalarAuthClient();
this.scalarClient.connect().done(() => {
this.forceUpdate();
}, (err) => {
this.setState({scalarError: err});
console.error('Error whilst initialising scalarClient for ManageIntegsButton', err);
});
}
}

componentWillUnmount() {
ScalarMessaging.stopListening();
}

onManageIntegrations(ev) {
onManageIntegrations = (ev) => {
ev.preventDefault();
if (this.state.scalarError && !this.scalarClient.hasCredentials()) {
return;
}

const IntegrationsManager = sdk.getComponent("views.settings.IntegrationsManager");
this.scalarClient.connect().done(() => {
Modal.createDialog(IntegrationsManager, {
src: (this.scalarClient !== null && this.scalarClient.hasCredentials()) ?
this.scalarClient.getScalarInterfaceUrlForRoom(this.props.room) :
null,
}, "mx_IntegrationsManager");
}, (err) => {
this.setState({scalarError: err});
console.error('Error ensuring a valid scalar_token exists', err);
});
}
Modal.createDialog(IntegrationsManager, {
room: this.props.room,
}, "mx_IntegrationsManager");
};

render() {
let integrationsButton = <div />;
let integrationsWarningTriangle = <div />;
let integrationsErrorPopup = <div />;
if (this.scalarClient !== null) {
const integrationsButtonClasses = classNames({
mx_RoomHeader_button: true,
mx_RoomHeader_manageIntegsButton: true,
mx_ManageIntegsButton_error: !!this.state.scalarError,
});

if (this.state.scalarError && !this.scalarClient.hasCredentials()) {
integrationsWarningTriangle = <img
src={require("../../../../res/img/warning.svg")}
title={_t('Integrations Error')}
width="17"
/>;
// Popup shown when hovering over integrationsButton_error (via CSS)
integrationsErrorPopup = (
<span className="mx_ManageIntegsButton_errorPopup">
{ _t('Could not connect to the integration server') }
</span>
);
}

if (ScalarAuthClient.isPossible()) {
const AccessibleButton = sdk.getComponent("elements.AccessibleButton");
integrationsButton = (
<AccessibleButton className={integrationsButtonClasses}
<AccessibleButton
className='mx_RoomHeader_button mx_RoomHeader_manageIntegsButton'
title={_t("Manage Integrations")}
onClick={this.onManageIntegrations}
title={_t('Manage Integrations')}
>
{ integrationsWarningTriangle }
{ integrationsErrorPopup }
</AccessibleButton>
);
/>
)
}

return integrationsButton;
Expand Down
86 changes: 81 additions & 5 deletions src/components/views/settings/IntegrationsManager.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,20 +18,68 @@ limitations under the License.
import React from 'react';
import PropTypes from 'prop-types';
import sdk from '../../../index';
import MatrixClientPeg from '../../../MatrixClientPeg';
import { _t } from '../../../languageHandler';
import Modal from '../../../Modal';
import dis from '../../../dispatcher';
import ScalarAuthClient from '../../../ScalarAuthClient';

export default class IntegrationsManager extends React.Component {
static propTypes = {
// the source of the integration manager being embedded
src: PropTypes.string.isRequired,
// the room object where the integrations manager should be opened in
room: PropTypes.object.isRequired,

// the screen name to open
screen: PropTypes.string,

// the integration ID to open
integrationId: PropTypes.string,

// callback when the manager is dismissed
onFinished: PropTypes.func.isRequired,
};

constructor(props) {
super(props);

this.state = {
loading: true,
configured: ScalarAuthClient.isPossible(),
connected: false, // true if a `src` is set and able to be connected to
src: null, // string for where to connect to
};
}

componentWillMount() {
if (!this.state.configured) return;

const scalarClient = new ScalarAuthClient();
scalarClient.connect().then(() => {
const hasCredentials = scalarClient.hasCredentials();
if (!hasCredentials) {
this.setState({
connected: false,
loading: false,
});
} else {
const src = scalarClient.getScalarInterfaceUrlForRoom(
this.props.room,
this.props.screen,
this.props.integrationId,
);
this.setState({
loading: false,
connected: true,
src: src,
});
}
}).catch(err => {
console.error(err);
this.setState({
loading: false,
connected: false,
});
})
}

componentDidMount() {
this.dispatcherRef = dis.register(this.onAction);
document.addEventListener("keydown", this.onKeyDown);
Expand All @@ -57,6 +105,34 @@ export default class IntegrationsManager extends React.Component {
};

render() {
return <iframe src={ this.props.src }></iframe>;
if (!this.state.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.state.loading) {
const Spinner = sdk.getComponent("elements.Spinner");
return (
<div className='mx_IntegrationsManager_loading'>
<h3>{_t("Connecting to integrations server...")}</h3>
<Spinner />
</div>
);
}

if (!this.state.connected) {
return (
<div className='mx_IntegrationsManager_error'>
<h3>{_t("Cannot connect to integrations server")}</h3>
<p>{_t("The integrations server is offline or it cannot reach your homeserver.")}</p>
</div>
);
}

return <iframe src={this.state.src}></iframe>;
}
}
8 changes: 7 additions & 1 deletion src/i18n/strings/en_EN.json
Original file line number Diff line number Diff line change
Expand Up @@ -483,6 +483,11 @@
"Email Address": "Email Address",
"Disable Notifications": "Disable Notifications",
"Enable Notifications": "Enable Notifications",
"No integrations server configured": "No integrations server configured",
"This Riot instance does not have an integrations server configured.": "This Riot instance does not have an integrations server configured.",
"Connecting to integrations server...": "Connecting to integrations server...",
"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",
"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.",
Expand Down Expand Up @@ -864,6 +869,8 @@
"This Room": "This Room",
"All Rooms": "All Rooms",
"Search…": "Search…",
"Failed to connect to integrations server": "Failed to connect to integrations server",
"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",
"Add some now": "Add some now",
"Stickerpack": "Stickerpack",
Expand Down Expand Up @@ -1017,7 +1024,6 @@
"Rotate Right": "Rotate Right",
"Rotate clockwise": "Rotate clockwise",
"Download this file": "Download this file",
"Integrations Error": "Integrations Error",
"Manage Integrations": "Manage Integrations",
"%(nameList)s %(transitionList)s": "%(nameList)s %(transitionList)s",
"%(severalUsers)sjoined %(count)s times|other": "%(severalUsers)sjoined %(count)s times",
Expand Down

0 comments on commit a5f2964

Please sign in to comment.