Merge pull request #3301 from matrix-org/travis/integs/base
Refactor integration manager handling into a common place
This commit is contained in:
commit
831da696ad
13 changed files with 275 additions and 151 deletions
|
@ -63,7 +63,7 @@ import SdkConfig from './SdkConfig';
|
|||
import { showUnknownDeviceDialogForCalls } from './cryptodevices';
|
||||
import WidgetUtils from './utils/WidgetUtils';
|
||||
import WidgetEchoStore from './stores/WidgetEchoStore';
|
||||
import ScalarAuthClient from './ScalarAuthClient';
|
||||
import {IntegrationManagers} from "./integrations/IntegrationManagers";
|
||||
|
||||
global.mxCalls = {
|
||||
//room_id: MatrixCall
|
||||
|
@ -348,14 +348,20 @@ async function _startCallApp(roomId, type) {
|
|||
// 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
|
||||
// room sees it.
|
||||
const scalarClient = new ScalarAuthClient();
|
||||
let haveScalar = false;
|
||||
try {
|
||||
await scalarClient.connect();
|
||||
haveScalar = scalarClient.hasCredentials();
|
||||
} catch (e) {
|
||||
// fall through
|
||||
const managers = IntegrationManagers.sharedInstance();
|
||||
let haveScalar = true;
|
||||
if (managers.hasManager()) {
|
||||
try {
|
||||
const scalarClient = managers.getPrimaryManager().getScalarClient();
|
||||
await scalarClient.connect();
|
||||
haveScalar = scalarClient.hasCredentials();
|
||||
} catch (e) {
|
||||
// ignore
|
||||
}
|
||||
} else {
|
||||
haveScalar = false;
|
||||
}
|
||||
|
||||
if (!haveScalar) {
|
||||
const ErrorDialog = sdk.getComponent("dialogs.ErrorDialog");
|
||||
|
||||
|
@ -421,7 +427,8 @@ async function _startCallApp(roomId, type) {
|
|||
// URL, but this will at least allow the integration manager to not be hardcoded.
|
||||
widgetUrl = SdkConfig.get().integrations_jitsi_widget_url + '?' + queryString;
|
||||
} else {
|
||||
widgetUrl = SdkConfig.get().integrations_rest_url + '/widgets/jitsi.html?' + queryString;
|
||||
const apiUrl = IntegrationManagers.sharedInstance().getPrimaryManager().apiUrl;
|
||||
widgetUrl = apiUrl + '/widgets/jitsi.html?' + queryString;
|
||||
}
|
||||
|
||||
const widgetData = { widgetSessionId };
|
||||
|
|
|
@ -22,7 +22,7 @@ import WidgetMessagingEndpoint from './WidgetMessagingEndpoint';
|
|||
import ActiveWidgetStore from './stores/ActiveWidgetStore';
|
||||
import MatrixClientPeg from "./MatrixClientPeg";
|
||||
import RoomViewStore from "./stores/RoomViewStore";
|
||||
import { showIntegrationsManager } from './integrations/integrations';
|
||||
import {IntegrationManagers} from "./integrations/IntegrationManagers";
|
||||
|
||||
const WIDGET_API_VERSION = '0.0.2'; // Current API version
|
||||
const SUPPORTED_WIDGET_API_VERSIONS = [
|
||||
|
@ -193,11 +193,12 @@ export default class FromWidgetPostMessageApi {
|
|||
const integType = (data && data.integType) ? data.integType : null;
|
||||
const integId = (data && data.integId) ? data.integId : null;
|
||||
|
||||
showIntegrationsManager({
|
||||
room: MatrixClientPeg.get().getRoom(RoomViewStore.getRoomId()),
|
||||
screen: 'type_' + integType,
|
||||
integrationId: integId,
|
||||
});
|
||||
// TODO: Open the right integration manager for the widget
|
||||
IntegrationManagers.sharedInstance().getPrimaryManager().open(
|
||||
MatrixClientPeg.get().getRoom(RoomViewStore.getRoomId()),
|
||||
`type_${integType}`,
|
||||
integId,
|
||||
);
|
||||
} else if (action === 'set_always_on_screen') {
|
||||
// This is a new message: there is no reason to support the deprecated widgetData here
|
||||
const data = event.data.data;
|
||||
|
|
|
@ -29,20 +29,43 @@ import * as Matrix from 'matrix-js-sdk';
|
|||
// The version of the integration manager API we're intending to work with
|
||||
const imApiVersion = "1.1";
|
||||
|
||||
class ScalarAuthClient {
|
||||
constructor() {
|
||||
export default class ScalarAuthClient {
|
||||
constructor(apiUrl, uiUrl) {
|
||||
this.apiUrl = apiUrl;
|
||||
this.uiUrl = uiUrl;
|
||||
this.scalarToken = null;
|
||||
// `undefined` to allow `startTermsFlow` to fallback to a default
|
||||
// callback if this is unset.
|
||||
this.termsInteractionCallback = undefined;
|
||||
|
||||
// We try and store the token on a per-manager basis, but need a fallback
|
||||
// for the default manager.
|
||||
const configApiUrl = SdkConfig.get()['integrations_rest_url'];
|
||||
const configUiUrl = SdkConfig.get()['integrations_ui_url'];
|
||||
this.isDefaultManager = apiUrl === configApiUrl && configUiUrl === uiUrl;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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'];
|
||||
_writeTokenToStore() {
|
||||
window.localStorage.setItem("mx_scalar_token_at_" + this.apiUrl, this.scalarToken);
|
||||
if (this.isDefaultManager) {
|
||||
// We remove the old token from storage to migrate upwards. This is safe
|
||||
// to do because even if the user switches to /app when this is on /develop
|
||||
// they'll at worst register for a new token.
|
||||
window.localStorage.removeItem("mx_scalar_token"); // no-op when not present
|
||||
}
|
||||
}
|
||||
|
||||
_readTokenFromStore() {
|
||||
let token = window.localStorage.getItem("mx_scalar_token_at_" + this.apiUrl);
|
||||
if (!token && this.isDefaultManager) {
|
||||
token = window.localStorage.getItem("mx_scalar_token");
|
||||
}
|
||||
return token;
|
||||
}
|
||||
|
||||
_readToken() {
|
||||
if (this.scalarToken) return this.scalarToken;
|
||||
return this._readTokenFromStore();
|
||||
}
|
||||
|
||||
setTermsInteractionCallback(callback) {
|
||||
|
@ -61,8 +84,7 @@ class ScalarAuthClient {
|
|||
|
||||
// Returns a promise that resolves to a scalar_token string
|
||||
getScalarToken() {
|
||||
let token = this.scalarToken;
|
||||
if (!token) token = window.localStorage.getItem("mx_scalar_token");
|
||||
const token = this._readToken();
|
||||
|
||||
if (!token) {
|
||||
return this.registerForToken();
|
||||
|
@ -78,7 +100,7 @@ class ScalarAuthClient {
|
|||
}
|
||||
|
||||
_getAccountName(token) {
|
||||
const url = SdkConfig.get().integrations_rest_url + "/account";
|
||||
const url = this.apiUrl + "/account";
|
||||
|
||||
return new Promise(function(resolve, reject) {
|
||||
request({
|
||||
|
@ -111,7 +133,7 @@ class ScalarAuthClient {
|
|||
return token;
|
||||
}).catch((e) => {
|
||||
if (e instanceof TermsNotSignedError) {
|
||||
console.log("Integrations manager requires new terms to be agreed to");
|
||||
console.log("Integration manager requires new terms to be agreed to");
|
||||
// The terms endpoints are new and so live on standard _matrix prefixes,
|
||||
// but IM rest urls are currently configured with paths, so remove the
|
||||
// path from the base URL before passing it to the js-sdk
|
||||
|
@ -126,7 +148,7 @@ class ScalarAuthClient {
|
|||
// Once we've fully transitioned to _matrix URLs, we can give people
|
||||
// a grace period to update their configs, then use the rest url as
|
||||
// a regular base url.
|
||||
const parsedImRestUrl = url.parse(SdkConfig.get().integrations_rest_url);
|
||||
const parsedImRestUrl = url.parse(this.apiUrl);
|
||||
parsedImRestUrl.path = '';
|
||||
parsedImRestUrl.pathname = '';
|
||||
return startTermsFlow([new Service(
|
||||
|
@ -147,17 +169,18 @@ class ScalarAuthClient {
|
|||
return MatrixClientPeg.get().getOpenIdToken().then((tokenObject) => {
|
||||
// Now we can send that to scalar and exchange it for a scalar token
|
||||
return this.exchangeForScalarToken(tokenObject);
|
||||
}).then((tokenObject) => {
|
||||
}).then((token) => {
|
||||
// Validate it (this mostly checks to see if the IM needs us to agree to some terms)
|
||||
return this._checkToken(tokenObject);
|
||||
}).then((tokenObject) => {
|
||||
window.localStorage.setItem("mx_scalar_token", tokenObject);
|
||||
return tokenObject;
|
||||
return this._checkToken(token);
|
||||
}).then((token) => {
|
||||
this.scalarToken = token;
|
||||
this._writeTokenToStore();
|
||||
return token;
|
||||
});
|
||||
}
|
||||
|
||||
exchangeForScalarToken(openidTokenObject) {
|
||||
const scalarRestUrl = SdkConfig.get().integrations_rest_url;
|
||||
const scalarRestUrl = this.apiUrl;
|
||||
|
||||
return new Promise(function(resolve, reject) {
|
||||
request({
|
||||
|
@ -181,7 +204,7 @@ class ScalarAuthClient {
|
|||
}
|
||||
|
||||
getScalarPageTitle(url) {
|
||||
let scalarPageLookupUrl = SdkConfig.get().integrations_rest_url + '/widgets/title_lookup';
|
||||
let scalarPageLookupUrl = this.apiUrl + '/widgets/title_lookup';
|
||||
scalarPageLookupUrl = this.getStarterLink(scalarPageLookupUrl);
|
||||
scalarPageLookupUrl += '&curl=' + encodeURIComponent(url);
|
||||
|
||||
|
@ -217,7 +240,7 @@ class ScalarAuthClient {
|
|||
* @return {Promise} Resolves on completion
|
||||
*/
|
||||
disableWidgetAssets(widgetType, widgetId) {
|
||||
let url = SdkConfig.get().integrations_rest_url + '/widgets/set_assets_state';
|
||||
let url = this.apiUrl + '/widgets/set_assets_state';
|
||||
url = this.getStarterLink(url);
|
||||
return new Promise((resolve, reject) => {
|
||||
request({
|
||||
|
@ -246,7 +269,7 @@ class ScalarAuthClient {
|
|||
getScalarInterfaceUrlForRoom(room, screen, id) {
|
||||
const roomId = room.roomId;
|
||||
const roomName = room.name;
|
||||
let url = SdkConfig.get().integrations_ui_url;
|
||||
let url = this.uiUrl;
|
||||
url += "?scalar_token=" + encodeURIComponent(this.scalarToken);
|
||||
url += "&room_id=" + encodeURIComponent(roomId);
|
||||
url += "&room_name=" + encodeURIComponent(roomName);
|
||||
|
@ -264,5 +287,3 @@ class ScalarAuthClient {
|
|||
return starterLinkUrl + "?scalar_token=" + encodeURIComponent(this.scalarToken);
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = ScalarAuthClient;
|
||||
|
|
|
@ -232,13 +232,13 @@ Example:
|
|||
}
|
||||
*/
|
||||
|
||||
import SdkConfig from './SdkConfig';
|
||||
import MatrixClientPeg from './MatrixClientPeg';
|
||||
import { MatrixEvent } from 'matrix-js-sdk';
|
||||
import dis from './dispatcher';
|
||||
import WidgetUtils from './utils/WidgetUtils';
|
||||
import RoomViewStore from './stores/RoomViewStore';
|
||||
import { _t } from './languageHandler';
|
||||
import {IntegrationManagers} from "./integrations/IntegrationManagers";
|
||||
|
||||
function sendResponse(event, res) {
|
||||
const data = JSON.parse(JSON.stringify(event.data));
|
||||
|
@ -548,7 +548,8 @@ const onMessage = function(event) {
|
|||
// (See https://developer.mozilla.org/en-US/docs/Web/API/Window/postMessage)
|
||||
let configUrl;
|
||||
try {
|
||||
configUrl = new URL(SdkConfig.get().integrations_ui_url);
|
||||
// TODO: Support multiple integration managers
|
||||
configUrl = new URL(IntegrationManagers.sharedInstance().getPrimaryManager().uiUrl);
|
||||
} catch (e) {
|
||||
// No integrations UI URL, ignore silently.
|
||||
return;
|
||||
|
|
|
@ -22,7 +22,6 @@ import qs from 'querystring';
|
|||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import MatrixClientPeg from '../../../MatrixClientPeg';
|
||||
import ScalarAuthClient from '../../../ScalarAuthClient';
|
||||
import WidgetMessaging from '../../../WidgetMessaging';
|
||||
import AccessibleButton from './AccessibleButton';
|
||||
import Modal from '../../../Modal';
|
||||
|
@ -35,7 +34,7 @@ import WidgetUtils from '../../../utils/WidgetUtils';
|
|||
import dis from '../../../dispatcher';
|
||||
import ActiveWidgetStore from '../../../stores/ActiveWidgetStore';
|
||||
import classNames from 'classnames';
|
||||
import { showIntegrationsManager } from '../../../integrations/integrations';
|
||||
import {IntegrationManagers} from "../../../integrations/IntegrationManagers";
|
||||
|
||||
const ALLOWED_APP_URL_SCHEMES = ['https:', 'http:'];
|
||||
const ENABLE_REACT_PERF = false;
|
||||
|
@ -178,9 +177,22 @@ export default class AppTile extends React.Component {
|
|||
return;
|
||||
}
|
||||
|
||||
const managers = IntegrationManagers.sharedInstance();
|
||||
if (!managers.hasManager()) {
|
||||
console.warn("No integration manager - not setting scalar token", url);
|
||||
this.setState({
|
||||
error: null,
|
||||
widgetUrl: this._addWurlParams(this.props.url),
|
||||
initialising: false,
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO: Pick the right manager for the widget
|
||||
|
||||
// Fetch the token before loading the iframe as we need it to mangle the URL
|
||||
if (!this._scalarClient) {
|
||||
this._scalarClient = new ScalarAuthClient();
|
||||
this._scalarClient = managers.getPrimaryManager().getScalarClient();
|
||||
}
|
||||
this._scalarClient.getScalarToken().done((token) => {
|
||||
// Append scalar_token as a query param if not already present
|
||||
|
@ -189,7 +201,7 @@ export default class AppTile extends React.Component {
|
|||
const params = qs.parse(u.query);
|
||||
if (!params.scalar_token) {
|
||||
params.scalar_token = encodeURIComponent(token);
|
||||
// u.search must be set to undefined, so that u.format() uses query paramerters - https://nodejs.org/docs/latest/api/url.html#url_url_format_url_options
|
||||
// u.search must be set to undefined, so that u.format() uses query parameters - https://nodejs.org/docs/latest/api/url.html#url_url_format_url_options
|
||||
u.search = undefined;
|
||||
u.query = params;
|
||||
}
|
||||
|
@ -251,11 +263,12 @@ export default class AppTile extends React.Component {
|
|||
if (this.props.onEditClick) {
|
||||
this.props.onEditClick();
|
||||
} else {
|
||||
showIntegrationsManager({
|
||||
room: this.props.room,
|
||||
screen: 'type_' + this.props.type,
|
||||
integrationId: this.props.id,
|
||||
});
|
||||
// TODO: Open the right manager for the widget
|
||||
IntegrationManagers.sharedInstance().getPrimaryManager().open(
|
||||
this.props.room,
|
||||
this.props.type,
|
||||
this.props.id,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -18,9 +18,8 @@ limitations under the License.
|
|||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import sdk from '../../../index';
|
||||
import ScalarAuthClient from '../../../ScalarAuthClient';
|
||||
import { _t } from '../../../languageHandler';
|
||||
import { showIntegrationsManager } from '../../../integrations/integrations';
|
||||
import {IntegrationManagers} from "../../../integrations/IntegrationManagers";
|
||||
|
||||
export default class ManageIntegsButton extends React.Component {
|
||||
constructor(props) {
|
||||
|
@ -30,12 +29,17 @@ export default class ManageIntegsButton extends React.Component {
|
|||
onManageIntegrations = (ev) => {
|
||||
ev.preventDefault();
|
||||
|
||||
showIntegrationsManager({ room: this.props.room });
|
||||
const managers = IntegrationManagers.sharedInstance();
|
||||
if (!managers.hasManager()) {
|
||||
managers.openNoManagerDialog();
|
||||
} else {
|
||||
managers.getPrimaryManager().open(this.props.room);
|
||||
}
|
||||
};
|
||||
|
||||
render() {
|
||||
let integrationsButton = <div />;
|
||||
if (ScalarAuthClient.isPossible()) {
|
||||
if (IntegrationManagers.sharedInstance().hasManager()) {
|
||||
const AccessibleButton = sdk.getComponent("elements.AccessibleButton");
|
||||
integrationsButton = (
|
||||
<AccessibleButton
|
||||
|
|
|
@ -25,7 +25,6 @@ import highlight from 'highlight.js';
|
|||
import * as HtmlUtils from '../../../HtmlUtils';
|
||||
import {formatDate} from '../../../DateUtils';
|
||||
import sdk from '../../../index';
|
||||
import ScalarAuthClient from '../../../ScalarAuthClient';
|
||||
import Modal from '../../../Modal';
|
||||
import SdkConfig from '../../../SdkConfig';
|
||||
import dis from '../../../dispatcher';
|
||||
|
@ -35,6 +34,7 @@ import SettingsStore from "../../../settings/SettingsStore";
|
|||
import ReplyThread from "../elements/ReplyThread";
|
||||
import {host as matrixtoHost} from '../../../matrix-to';
|
||||
import {pillifyLinks} from '../../../utils/pillify';
|
||||
import {IntegrationManagers} from "../../../integrations/IntegrationManagers";
|
||||
|
||||
module.exports = React.createClass({
|
||||
displayName: 'TextualBody',
|
||||
|
@ -318,12 +318,19 @@ module.exports = React.createClass({
|
|||
// which requires the user to click through and THEN we can open the link in a new tab because
|
||||
// the window.open command occurs in the same stack frame as the onClick callback.
|
||||
|
||||
const managers = IntegrationManagers.sharedInstance();
|
||||
if (!managers.hasManager()) {
|
||||
managers.openNoManagerDialog();
|
||||
return;
|
||||
}
|
||||
|
||||
// Go fetch a scalar token
|
||||
const scalarClient = new ScalarAuthClient();
|
||||
const integrationManager = managers.getPrimaryManager();
|
||||
const scalarClient = integrationManager.getScalarClient();
|
||||
scalarClient.connect().then(() => {
|
||||
const completeUrl = scalarClient.getStarterLink(starterLink);
|
||||
const QuestionDialog = sdk.getComponent("dialogs.QuestionDialog");
|
||||
const integrationsUrl = SdkConfig.get().integrations_ui_url;
|
||||
const integrationsUrl = integrationManager.uiUrl;
|
||||
Modal.createTrackedDialog('Add an integration', '', QuestionDialog, {
|
||||
title: _t("Add an Integration"),
|
||||
description:
|
||||
|
|
|
@ -29,7 +29,7 @@ import { _t } from '../../../languageHandler';
|
|||
import WidgetUtils from '../../../utils/WidgetUtils';
|
||||
import WidgetEchoStore from "../../../stores/WidgetEchoStore";
|
||||
import AccessibleButton from '../elements/AccessibleButton';
|
||||
import { showIntegrationsManager } from '../../../integrations/integrations';
|
||||
import {IntegrationManagers} from "../../../integrations/IntegrationManagers";
|
||||
|
||||
// The maximum number of widgets that can be added in a room
|
||||
const MAX_WIDGETS = 2;
|
||||
|
@ -128,10 +128,7 @@ module.exports = React.createClass({
|
|||
},
|
||||
|
||||
_launchManageIntegrations: function() {
|
||||
showIntegrationsManager({
|
||||
room: this.props.room,
|
||||
screen: 'add_integ',
|
||||
});
|
||||
IntegrationManagers.sharedInstance().getPrimaryManager().open(this.props.room, 'add_integ');
|
||||
},
|
||||
|
||||
onClickAddWidget: function(e) {
|
||||
|
|
|
@ -18,13 +18,12 @@ import {_t, _td} from '../../../languageHandler';
|
|||
import AppTile from '../elements/AppTile';
|
||||
import MatrixClientPeg from '../../../MatrixClientPeg';
|
||||
import sdk from '../../../index';
|
||||
import ScalarAuthClient from '../../../ScalarAuthClient';
|
||||
import dis from '../../../dispatcher';
|
||||
import AccessibleButton from '../elements/AccessibleButton';
|
||||
import WidgetUtils from '../../../utils/WidgetUtils';
|
||||
import ActiveWidgetStore from '../../../stores/ActiveWidgetStore';
|
||||
import PersistedElement from "../elements/PersistedElement";
|
||||
import { showIntegrationsManager } from '../../../integrations/integrations';
|
||||
import {IntegrationManagers} from "../../../integrations/IntegrationManagers";
|
||||
|
||||
const widgetType = 'm.stickerpicker';
|
||||
|
||||
|
@ -67,8 +66,9 @@ export default class Stickerpicker extends React.Component {
|
|||
|
||||
_acquireScalarClient() {
|
||||
if (this.scalarClient) return Promise.resolve(this.scalarClient);
|
||||
if (ScalarAuthClient.isPossible()) {
|
||||
this.scalarClient = new ScalarAuthClient();
|
||||
// TODO: Pick the right manager for the widget
|
||||
if (IntegrationManagers.sharedInstance().hasManager()) {
|
||||
this.scalarClient = IntegrationManagers.sharedInstance().getPrimaryManager().getScalarClient();
|
||||
return this.scalarClient.connect().then(() => {
|
||||
this.forceUpdate();
|
||||
return this.scalarClient;
|
||||
|
@ -348,11 +348,12 @@ export default class Stickerpicker extends React.Component {
|
|||
* Launch the integrations manager on the stickers integration page
|
||||
*/
|
||||
_launchManageIntegrations() {
|
||||
showIntegrationsManager({
|
||||
room: this.props.room,
|
||||
screen: `type_${widgetType}`,
|
||||
integrationId: this.state.widgetId,
|
||||
});
|
||||
// TODO: Open the right integration manager for the widget
|
||||
IntegrationManagers.sharedInstance().getPrimaryManager().open(
|
||||
this.props.room,
|
||||
`type_${widgetType}`,
|
||||
this.state.widgetId,
|
||||
);
|
||||
}
|
||||
|
||||
render() {
|
||||
|
|
81
src/integrations/IntegrationManagerInstance.js
Normal file
81
src/integrations/IntegrationManagerInstance.js
Normal file
|
@ -0,0 +1,81 @@
|
|||
/*
|
||||
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 ScalarAuthClient from "../ScalarAuthClient";
|
||||
import sdk from "../index";
|
||||
import {dialogTermsInteractionCallback, TermsNotSignedError} from "../Terms";
|
||||
import type {Room} from "matrix-js-sdk";
|
||||
import Modal from '../Modal';
|
||||
|
||||
export class IntegrationManagerInstance {
|
||||
apiUrl: string;
|
||||
uiUrl: string;
|
||||
|
||||
constructor(apiUrl: string, uiUrl: string) {
|
||||
this.apiUrl = apiUrl;
|
||||
this.uiUrl = uiUrl;
|
||||
|
||||
// Per the spec: UI URL is optional.
|
||||
if (!this.uiUrl) this.uiUrl = this.apiUrl;
|
||||
}
|
||||
|
||||
getScalarClient(): ScalarAuthClient {
|
||||
return new ScalarAuthClient(this.apiUrl, this.uiUrl);
|
||||
}
|
||||
|
||||
async open(room: Room = null, screen: string = null, integrationId: string = null): void {
|
||||
const IntegrationsManager = sdk.getComponent("views.settings.IntegrationsManager");
|
||||
const dialog = Modal.createTrackedDialog(
|
||||
'Integration Manager', '', IntegrationsManager,
|
||||
{loading: true}, 'mx_IntegrationsManager',
|
||||
);
|
||||
|
||||
const client = this.getScalarClient();
|
||||
client.setTermsInteractionCallback((policyInfo, agreedUrls) => {
|
||||
// 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
|
||||
// it gets the same basic size as the IM's own modal.
|
||||
return dialogTermsInteractionCallback(
|
||||
policyInfo, agreedUrls, 'mx_TermsDialog_forIntegrationsManager',
|
||||
);
|
||||
});
|
||||
|
||||
const newProps = {};
|
||||
try {
|
||||
await client.connect();
|
||||
if (!client.hasCredentials()) {
|
||||
newProps["connected"] = false;
|
||||
} else {
|
||||
newProps["url"] = client.getScalarInterfaceUrlForRoom(room, screen, integrationId);
|
||||
}
|
||||
} catch (e) {
|
||||
if (e instanceof TermsNotSignedError) {
|
||||
dialog.close();
|
||||
return;
|
||||
}
|
||||
|
||||
console.error(e);
|
||||
newProps["connected"] = false;
|
||||
}
|
||||
|
||||
// Close the old dialog and open a new one
|
||||
dialog.close();
|
||||
Modal.createTrackedDialog(
|
||||
'Integration Manager', '', IntegrationsManager,
|
||||
newProps, 'mx_IntegrationsManager',
|
||||
);
|
||||
}
|
||||
}
|
68
src/integrations/IntegrationManagers.js
Normal file
68
src/integrations/IntegrationManagers.js
Normal file
|
@ -0,0 +1,68 @@
|
|||
/*
|
||||
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 SdkConfig from '../SdkConfig';
|
||||
import sdk from "../index";
|
||||
import Modal from '../Modal';
|
||||
import {IntegrationManagerInstance} from "./IntegrationManagerInstance";
|
||||
|
||||
export class IntegrationManagers {
|
||||
static _instance;
|
||||
|
||||
static sharedInstance(): IntegrationManagers {
|
||||
if (!IntegrationManagers._instance) {
|
||||
IntegrationManagers._instance = new IntegrationManagers();
|
||||
}
|
||||
return IntegrationManagers._instance;
|
||||
}
|
||||
|
||||
_managers: IntegrationManagerInstance[] = [];
|
||||
|
||||
constructor() {
|
||||
this._setupConfiguredManager();
|
||||
}
|
||||
|
||||
_setupConfiguredManager() {
|
||||
const apiUrl = SdkConfig.get()['integrations_rest_url'];
|
||||
const uiUrl = SdkConfig.get()['integrations_ui_url'];
|
||||
|
||||
if (apiUrl && uiUrl) {
|
||||
this._managers.push(new IntegrationManagerInstance(apiUrl, uiUrl));
|
||||
}
|
||||
}
|
||||
|
||||
hasManager(): boolean {
|
||||
return this._managers.length > 0;
|
||||
}
|
||||
|
||||
getPrimaryManager(): IntegrationManagerInstance {
|
||||
if (this.hasManager()) {
|
||||
// TODO: TravisR - Handle custom integration managers (widgets)
|
||||
return this._managers[0];
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
openNoManagerDialog(): void {
|
||||
// TODO: Is it Integrations (plural) or Integration (singular). Singular is easier spoken.
|
||||
const IntegrationsManager = sdk.getComponent("views.settings.IntegrationsManager");
|
||||
Modal.createTrackedDialog(
|
||||
"Integration Manager", "None", IntegrationsManager,
|
||||
{configured: false}, 'mx_IntegrationsManager',
|
||||
);
|
||||
}
|
||||
}
|
|
@ -1,79 +0,0 @@
|
|||
/*
|
||||
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 sdk from "../index";
|
||||
import ScalarAuthClient from '../ScalarAuthClient';
|
||||
import Modal from '../Modal';
|
||||
import { TermsNotSignedError, dialogTermsInteractionCallback } from '../Terms';
|
||||
|
||||
export async function showIntegrationsManager(opts) {
|
||||
const IntegrationsManager = sdk.getComponent("views.settings.IntegrationsManager");
|
||||
|
||||
let props = {};
|
||||
if (ScalarAuthClient.isPossible()) {
|
||||
props.loading = true;
|
||||
} else {
|
||||
props.configured = false;
|
||||
}
|
||||
|
||||
const close = Modal.createTrackedDialog(
|
||||
'Integrations Manager', '', IntegrationsManager, props, "mx_IntegrationsManager",
|
||||
).close;
|
||||
|
||||
if (!ScalarAuthClient.isPossible()) {
|
||||
return;
|
||||
}
|
||||
|
||||
const scalarClient = new ScalarAuthClient();
|
||||
scalarClient.setTermsInteractionCallback(integrationsTermsInteractionCallback);
|
||||
try {
|
||||
await scalarClient.connect();
|
||||
if (!scalarClient.hasCredentials()) {
|
||||
props = { connected: false };
|
||||
} else {
|
||||
props = {
|
||||
url: scalarClient.getScalarInterfaceUrlForRoom(
|
||||
opts.room,
|
||||
opts.screen,
|
||||
opts.integrationId,
|
||||
),
|
||||
};
|
||||
}
|
||||
} catch (err) {
|
||||
if (err instanceof TermsNotSignedError) {
|
||||
// user canceled terms dialog, so just cancel the action
|
||||
close();
|
||||
return;
|
||||
}
|
||||
console.error(err);
|
||||
props = { connected: false };
|
||||
}
|
||||
close();
|
||||
Modal.createTrackedDialog('Integrations Manager', '', IntegrationsManager, props, "mx_IntegrationsManager");
|
||||
}
|
||||
|
||||
/*
|
||||
* 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
|
||||
* it gets the same basic size as the IM's own modal.
|
||||
*/
|
||||
function integrationsTermsInteractionCallback(policiesAndServicePairs, agreedUrls) {
|
||||
return dialogTermsInteractionCallback(
|
||||
policiesAndServicePairs,
|
||||
agreedUrls,
|
||||
"mx_TermsDialog_forIntegrationsManager",
|
||||
);
|
||||
}
|
|
@ -27,6 +27,7 @@ import WidgetEchoStore from '../stores/WidgetEchoStore';
|
|||
const WIDGET_WAIT_TIME = 20000;
|
||||
import SettingsStore from "../settings/SettingsStore";
|
||||
import ActiveWidgetStore from "../stores/ActiveWidgetStore";
|
||||
import {IntegrationManagers} from "../integrations/IntegrationManagers";
|
||||
|
||||
/**
|
||||
* Encodes a URI according to a set of template variables. Variables will be
|
||||
|
@ -102,7 +103,8 @@ export default class WidgetUtils {
|
|||
|
||||
let scalarUrls = SdkConfig.get().integrations_widgets_urls;
|
||||
if (!scalarUrls || scalarUrls.length === 0) {
|
||||
scalarUrls = [SdkConfig.get().integrations_rest_url];
|
||||
const defaultManager = IntegrationManagers.sharedInstance().getPrimaryManager();
|
||||
if (defaultManager) scalarUrls = [defaultManager.apiUrl];
|
||||
}
|
||||
|
||||
for (let i = 0; i < scalarUrls.length; i++) {
|
||||
|
|
Loading…
Reference in a new issue