mirror of
https://github.com/element-hq/element-web.git
synced 2024-12-13 13:19:56 +03:00
Convert WidgetUtils to TS and improve typing
Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>
This commit is contained in:
parent
c8b99b54e0
commit
2e6bad8b07
2 changed files with 46 additions and 30 deletions
|
@ -31,11 +31,16 @@ interface IState {}
|
||||||
|
|
||||||
export interface IApp {
|
export interface IApp {
|
||||||
id: string;
|
id: string;
|
||||||
|
url: string;
|
||||||
type: string;
|
type: string;
|
||||||
|
name: string;
|
||||||
roomId: string;
|
roomId: string;
|
||||||
eventId: string;
|
eventId: string;
|
||||||
creatorUserId: string;
|
creatorUserId: string;
|
||||||
waitForIframeLoad?: boolean;
|
waitForIframeLoad?: boolean;
|
||||||
|
data?: {
|
||||||
|
title?: string;
|
||||||
|
};
|
||||||
// eslint-disable-next-line camelcase
|
// eslint-disable-next-line camelcase
|
||||||
avatar_url: string; // MSC2765 https://github.com/matrix-org/matrix-doc/pull/2765
|
avatar_url: string; // MSC2765 https://github.com/matrix-org/matrix-doc/pull/2765
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
Copyright 2017 Vector Creations Ltd
|
Copyright 2017 Vector Creations Ltd
|
||||||
Copyright 2018 New Vector Ltd
|
Copyright 2018 New Vector Ltd
|
||||||
Copyright 2019 Travis Ralston
|
Copyright 2019 Travis Ralston
|
||||||
|
Copyright 2020 The Matrix.org Foundation C.I.C.
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
you may not use this file except in compliance with the License.
|
you may not use this file except in compliance with the License.
|
||||||
|
@ -16,15 +17,12 @@ See the License for the specific language governing permissions and
|
||||||
limitations under the License.
|
limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
import * as url from "url";
|
||||||
|
|
||||||
import {MatrixClientPeg} from '../MatrixClientPeg';
|
import {MatrixClientPeg} from '../MatrixClientPeg';
|
||||||
import SdkConfig from "../SdkConfig";
|
import SdkConfig from "../SdkConfig";
|
||||||
import dis from '../dispatcher/dispatcher';
|
import dis from '../dispatcher/dispatcher';
|
||||||
import * as url from "url";
|
|
||||||
import WidgetEchoStore from '../stores/WidgetEchoStore';
|
import WidgetEchoStore from '../stores/WidgetEchoStore';
|
||||||
|
|
||||||
// How long we wait for the state event echo to come back from the server
|
|
||||||
// before waitFor[Room/User]Widget rejects its promise
|
|
||||||
const WIDGET_WAIT_TIME = 20000;
|
|
||||||
import SettingsStore from "../settings/SettingsStore";
|
import SettingsStore from "../settings/SettingsStore";
|
||||||
import ActiveWidgetStore from "../stores/ActiveWidgetStore";
|
import ActiveWidgetStore from "../stores/ActiveWidgetStore";
|
||||||
import {IntegrationManagers} from "../integrations/IntegrationManagers";
|
import {IntegrationManagers} from "../integrations/IntegrationManagers";
|
||||||
|
@ -33,6 +31,19 @@ import {Room} from "matrix-js-sdk/src/models/room";
|
||||||
import {WidgetType} from "../widgets/WidgetType";
|
import {WidgetType} from "../widgets/WidgetType";
|
||||||
import {objectClone} from "./objects";
|
import {objectClone} from "./objects";
|
||||||
import {_t} from "../languageHandler";
|
import {_t} from "../languageHandler";
|
||||||
|
import {IApp} from "../stores/WidgetStore";
|
||||||
|
|
||||||
|
// How long we wait for the state event echo to come back from the server
|
||||||
|
// before waitFor[Room/User]Widget rejects its promise
|
||||||
|
const WIDGET_WAIT_TIME = 20000;
|
||||||
|
|
||||||
|
export interface IWidget {
|
||||||
|
id: string;
|
||||||
|
type: string;
|
||||||
|
sender: string;
|
||||||
|
state_key: string;
|
||||||
|
content: IApp;
|
||||||
|
}
|
||||||
|
|
||||||
export default class WidgetUtils {
|
export default class WidgetUtils {
|
||||||
/* Returns true if user is able to send state events to modify widgets in this room
|
/* Returns true if user is able to send state events to modify widgets in this room
|
||||||
|
@ -41,7 +52,7 @@ export default class WidgetUtils {
|
||||||
* @return Boolean -- true if the user can modify widgets in this room
|
* @return Boolean -- true if the user can modify widgets in this room
|
||||||
* @throws Error -- specifies the error reason
|
* @throws Error -- specifies the error reason
|
||||||
*/
|
*/
|
||||||
static canUserModifyWidgets(roomId) {
|
static canUserModifyWidgets(roomId: string): boolean {
|
||||||
if (!roomId) {
|
if (!roomId) {
|
||||||
console.warn('No room ID specified');
|
console.warn('No room ID specified');
|
||||||
return false;
|
return false;
|
||||||
|
@ -80,7 +91,7 @@ export default class WidgetUtils {
|
||||||
* @param {[type]} testUrlString URL to check
|
* @param {[type]} testUrlString URL to check
|
||||||
* @return {Boolean} True if specified URL is a scalar URL
|
* @return {Boolean} True if specified URL is a scalar URL
|
||||||
*/
|
*/
|
||||||
static isScalarUrl(testUrlString) {
|
static isScalarUrl(testUrlString: string): boolean {
|
||||||
if (!testUrlString) {
|
if (!testUrlString) {
|
||||||
console.error('Scalar URL check failed. No URL specified');
|
console.error('Scalar URL check failed. No URL specified');
|
||||||
return false;
|
return false;
|
||||||
|
@ -123,7 +134,7 @@ export default class WidgetUtils {
|
||||||
* @returns {Promise} that resolves when the widget is in the
|
* @returns {Promise} that resolves when the widget is in the
|
||||||
* requested state according to the `add` param
|
* requested state according to the `add` param
|
||||||
*/
|
*/
|
||||||
static waitForUserWidget(widgetId, add) {
|
static waitForUserWidget(widgetId: string, add: boolean): Promise<void> {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
// Tests an account data event, returning true if it's in the state
|
// Tests an account data event, returning true if it's in the state
|
||||||
// we're waiting for it to be in
|
// we're waiting for it to be in
|
||||||
|
@ -170,7 +181,7 @@ export default class WidgetUtils {
|
||||||
* @returns {Promise} that resolves when the widget is in the
|
* @returns {Promise} that resolves when the widget is in the
|
||||||
* requested state according to the `add` param
|
* requested state according to the `add` param
|
||||||
*/
|
*/
|
||||||
static waitForRoomWidget(widgetId, roomId, add) {
|
static waitForRoomWidget(widgetId: string, roomId: string, add: boolean): Promise<void> {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
// Tests a list of state events, returning true if it's in the state
|
// Tests a list of state events, returning true if it's in the state
|
||||||
// we're waiting for it to be in
|
// we're waiting for it to be in
|
||||||
|
@ -213,7 +224,7 @@ export default class WidgetUtils {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
static setUserWidget(widgetId, widgetType: WidgetType, widgetUrl, widgetName, widgetData) {
|
static setUserWidget(widgetId: string, widgetType: WidgetType, widgetUrl: string, widgetName: string, widgetData: object) {
|
||||||
const content = {
|
const content = {
|
||||||
type: widgetType.preferred,
|
type: widgetType.preferred,
|
||||||
url: widgetUrl,
|
url: widgetUrl,
|
||||||
|
@ -257,7 +268,7 @@ export default class WidgetUtils {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
static setRoomWidget(roomId, widgetId, widgetType: WidgetType, widgetUrl, widgetName, widgetData) {
|
static setRoomWidget(roomId: string, widgetId: string, widgetType: WidgetType, widgetUrl: string, widgetName: string, widgetData: object) {
|
||||||
let content;
|
let content;
|
||||||
|
|
||||||
const addingWidget = Boolean(widgetUrl);
|
const addingWidget = Boolean(widgetUrl);
|
||||||
|
@ -307,7 +318,7 @@ export default class WidgetUtils {
|
||||||
* Get user specific widgets (not linked to a specific room)
|
* Get user specific widgets (not linked to a specific room)
|
||||||
* @return {object} Event content object containing current / active user widgets
|
* @return {object} Event content object containing current / active user widgets
|
||||||
*/
|
*/
|
||||||
static getUserWidgets() {
|
static getUserWidgets(): Record<string, IWidget> {
|
||||||
const client = MatrixClientPeg.get();
|
const client = MatrixClientPeg.get();
|
||||||
if (!client) {
|
if (!client) {
|
||||||
throw new Error('User not logged in');
|
throw new Error('User not logged in');
|
||||||
|
@ -323,7 +334,7 @@ export default class WidgetUtils {
|
||||||
* Get user specific widgets (not linked to a specific room) as an array
|
* Get user specific widgets (not linked to a specific room) as an array
|
||||||
* @return {[object]} Array containing current / active user widgets
|
* @return {[object]} Array containing current / active user widgets
|
||||||
*/
|
*/
|
||||||
static getUserWidgetsArray() {
|
static getUserWidgetsArray(): IWidget[] {
|
||||||
return Object.values(WidgetUtils.getUserWidgets());
|
return Object.values(WidgetUtils.getUserWidgets());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -331,7 +342,7 @@ export default class WidgetUtils {
|
||||||
* Get active stickerpicker widgets (stickerpickers are user widgets by nature)
|
* Get active stickerpicker widgets (stickerpickers are user widgets by nature)
|
||||||
* @return {[object]} Array containing current / active stickerpicker widgets
|
* @return {[object]} Array containing current / active stickerpicker widgets
|
||||||
*/
|
*/
|
||||||
static getStickerpickerWidgets() {
|
static getStickerpickerWidgets(): IWidget[] {
|
||||||
const widgets = WidgetUtils.getUserWidgetsArray();
|
const widgets = WidgetUtils.getUserWidgetsArray();
|
||||||
return widgets.filter((widget) => widget.content && widget.content.type === "m.stickerpicker");
|
return widgets.filter((widget) => widget.content && widget.content.type === "m.stickerpicker");
|
||||||
}
|
}
|
||||||
|
@ -340,12 +351,12 @@ export default class WidgetUtils {
|
||||||
* Get all integration manager widgets for this user.
|
* Get all integration manager widgets for this user.
|
||||||
* @returns {Object[]} An array of integration manager user widgets.
|
* @returns {Object[]} An array of integration manager user widgets.
|
||||||
*/
|
*/
|
||||||
static getIntegrationManagerWidgets() {
|
static getIntegrationManagerWidgets(): IWidget[] {
|
||||||
const widgets = WidgetUtils.getUserWidgetsArray();
|
const widgets = WidgetUtils.getUserWidgetsArray();
|
||||||
return widgets.filter(w => w.content && w.content.type === "m.integration_manager");
|
return widgets.filter(w => w.content && w.content.type === "m.integration_manager");
|
||||||
}
|
}
|
||||||
|
|
||||||
static getRoomWidgetsOfType(room: Room, type: WidgetType) {
|
static getRoomWidgetsOfType(room: Room, type: WidgetType): IWidget[] {
|
||||||
const widgets = WidgetUtils.getRoomWidgets(room);
|
const widgets = WidgetUtils.getRoomWidgets(room);
|
||||||
return (widgets || []).filter(w => {
|
return (widgets || []).filter(w => {
|
||||||
const content = w.getContent();
|
const content = w.getContent();
|
||||||
|
@ -353,14 +364,14 @@ export default class WidgetUtils {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
static removeIntegrationManagerWidgets() {
|
static removeIntegrationManagerWidgets(): Promise<void> {
|
||||||
const client = MatrixClientPeg.get();
|
const client = MatrixClientPeg.get();
|
||||||
if (!client) {
|
if (!client) {
|
||||||
throw new Error('User not logged in');
|
throw new Error('User not logged in');
|
||||||
}
|
}
|
||||||
const widgets = client.getAccountData('m.widgets');
|
const widgets = client.getAccountData('m.widgets');
|
||||||
if (!widgets) return;
|
if (!widgets) return;
|
||||||
const userWidgets = widgets.getContent() || {};
|
const userWidgets: IWidget[] = widgets.getContent() || {};
|
||||||
Object.entries(userWidgets).forEach(([key, widget]) => {
|
Object.entries(userWidgets).forEach(([key, widget]) => {
|
||||||
if (widget.content && widget.content.type === "m.integration_manager") {
|
if (widget.content && widget.content.type === "m.integration_manager") {
|
||||||
delete userWidgets[key];
|
delete userWidgets[key];
|
||||||
|
@ -369,7 +380,7 @@ export default class WidgetUtils {
|
||||||
return client.setAccountData('m.widgets', userWidgets);
|
return client.setAccountData('m.widgets', userWidgets);
|
||||||
}
|
}
|
||||||
|
|
||||||
static addIntegrationManagerWidget(name: string, uiUrl: string, apiUrl: string) {
|
static addIntegrationManagerWidget(name: string, uiUrl: string, apiUrl: string): Promise<void> {
|
||||||
return WidgetUtils.setUserWidget(
|
return WidgetUtils.setUserWidget(
|
||||||
"integration_manager_" + (new Date().getTime()),
|
"integration_manager_" + (new Date().getTime()),
|
||||||
WidgetType.INTEGRATION_MANAGER,
|
WidgetType.INTEGRATION_MANAGER,
|
||||||
|
@ -383,14 +394,14 @@ export default class WidgetUtils {
|
||||||
* Remove all stickerpicker widgets (stickerpickers are user widgets by nature)
|
* Remove all stickerpicker widgets (stickerpickers are user widgets by nature)
|
||||||
* @return {Promise} Resolves on account data updated
|
* @return {Promise} Resolves on account data updated
|
||||||
*/
|
*/
|
||||||
static removeStickerpickerWidgets() {
|
static removeStickerpickerWidgets(): Promise<void> {
|
||||||
const client = MatrixClientPeg.get();
|
const client = MatrixClientPeg.get();
|
||||||
if (!client) {
|
if (!client) {
|
||||||
throw new Error('User not logged in');
|
throw new Error('User not logged in');
|
||||||
}
|
}
|
||||||
const widgets = client.getAccountData('m.widgets');
|
const widgets = client.getAccountData('m.widgets');
|
||||||
if (!widgets) return;
|
if (!widgets) return;
|
||||||
const userWidgets = widgets.getContent() || {};
|
const userWidgets: Record<string, IWidget> = widgets.getContent() || {};
|
||||||
Object.entries(userWidgets).forEach(([key, widget]) => {
|
Object.entries(userWidgets).forEach(([key, widget]) => {
|
||||||
if (widget.content && widget.content.type === 'm.stickerpicker') {
|
if (widget.content && widget.content.type === 'm.stickerpicker') {
|
||||||
delete userWidgets[key];
|
delete userWidgets[key];
|
||||||
|
@ -399,7 +410,7 @@ export default class WidgetUtils {
|
||||||
return client.setAccountData('m.widgets', userWidgets);
|
return client.setAccountData('m.widgets', userWidgets);
|
||||||
}
|
}
|
||||||
|
|
||||||
static makeAppConfig(appId, app, senderUserId, roomId, eventId) {
|
static makeAppConfig(appId: string, app: IApp, senderUserId: string, roomId: string | null, eventId: string): IApp {
|
||||||
if (!senderUserId) {
|
if (!senderUserId) {
|
||||||
throw new Error("Widgets must be created by someone - provide a senderUserId");
|
throw new Error("Widgets must be created by someone - provide a senderUserId");
|
||||||
}
|
}
|
||||||
|
@ -413,7 +424,7 @@ export default class WidgetUtils {
|
||||||
return app;
|
return app;
|
||||||
}
|
}
|
||||||
|
|
||||||
static getCapWhitelistForAppTypeInRoomId(appType, roomId) {
|
static getCapWhitelistForAppTypeInRoomId(appType: string, roomId: string): Capability[] {
|
||||||
const enableScreenshots = SettingsStore.getValue("enableWidgetScreenshots", roomId);
|
const enableScreenshots = SettingsStore.getValue("enableWidgetScreenshots", roomId);
|
||||||
|
|
||||||
const capWhitelist = enableScreenshots ? [Capability.Screenshot] : [];
|
const capWhitelist = enableScreenshots ? [Capability.Screenshot] : [];
|
||||||
|
@ -429,7 +440,7 @@ export default class WidgetUtils {
|
||||||
return capWhitelist;
|
return capWhitelist;
|
||||||
}
|
}
|
||||||
|
|
||||||
static getWidgetSecurityKey(widgetId, widgetUrl, isUserWidget) {
|
static getWidgetSecurityKey(widgetId: string, widgetUrl: string, isUserWidget: boolean): string {
|
||||||
let widgetLocation = ActiveWidgetStore.getRoomId(widgetId);
|
let widgetLocation = ActiveWidgetStore.getRoomId(widgetId);
|
||||||
|
|
||||||
if (isUserWidget) {
|
if (isUserWidget) {
|
||||||
|
@ -450,7 +461,7 @@ export default class WidgetUtils {
|
||||||
return encodeURIComponent(`${widgetLocation}::${widgetUrl}`);
|
return encodeURIComponent(`${widgetLocation}::${widgetUrl}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
static getLocalJitsiWrapperUrl(opts: {forLocalRender?: boolean, auth?: string}={}) {
|
static getLocalJitsiWrapperUrl(opts: {forLocalRender?: boolean, auth?: string} = {}) {
|
||||||
// NB. we can't just encodeURIComponent all of these because the $ signs need to be there
|
// NB. we can't just encodeURIComponent all of these because the $ signs need to be there
|
||||||
const queryStringParts = [
|
const queryStringParts = [
|
||||||
'conferenceDomain=$domain',
|
'conferenceDomain=$domain',
|
||||||
|
@ -466,7 +477,7 @@ export default class WidgetUtils {
|
||||||
}
|
}
|
||||||
const queryString = queryStringParts.join('&');
|
const queryString = queryStringParts.join('&');
|
||||||
|
|
||||||
let baseUrl = window.location;
|
let baseUrl = window.location.href;
|
||||||
if (window.location.protocol !== "https:" && !opts.forLocalRender) {
|
if (window.location.protocol !== "https:" && !opts.forLocalRender) {
|
||||||
// Use an external wrapper if we're not locally rendering the widget. This is usually
|
// Use an external wrapper if we're not locally rendering the widget. This is usually
|
||||||
// the URL that will end up in the widget event, so we want to make sure it's relatively
|
// the URL that will end up in the widget event, so we want to make sure it's relatively
|
||||||
|
@ -479,15 +490,15 @@ export default class WidgetUtils {
|
||||||
return url.href;
|
return url.href;
|
||||||
}
|
}
|
||||||
|
|
||||||
static getWidgetName(app) {
|
static getWidgetName(app?: IApp): string {
|
||||||
return app?.name?.trim() || _t("Unknown App");
|
return app?.name?.trim() || _t("Unknown App");
|
||||||
}
|
}
|
||||||
|
|
||||||
static getWidgetDataTitle(app) {
|
static getWidgetDataTitle(app?: IApp): string {
|
||||||
return app?.data?.title?.trim() || "";
|
return app?.data?.title?.trim() || "";
|
||||||
}
|
}
|
||||||
|
|
||||||
static editWidget(room, app) {
|
static editWidget(room: Room, app: IApp): void {
|
||||||
// TODO: Open the right manager for the widget
|
// TODO: Open the right manager for the widget
|
||||||
if (SettingsStore.getValue("feature_many_integration_managers")) {
|
if (SettingsStore.getValue("feature_many_integration_managers")) {
|
||||||
IntegrationManagers.sharedInstance().openAll(room, 'type_' + app.type, app.id);
|
IntegrationManagers.sharedInstance().openAll(room, 'type_' + app.type, app.id);
|
||||||
|
@ -496,7 +507,7 @@ export default class WidgetUtils {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static snapshotWidget(app) {
|
static snapshotWidget(app: IApp): void {
|
||||||
console.log("Requesting widget snapshot");
|
console.log("Requesting widget snapshot");
|
||||||
ActiveWidgetStore.getWidgetMessaging(app.id).getScreenshot().catch((err) => {
|
ActiveWidgetStore.getWidgetMessaging(app.id).getScreenshot().catch((err) => {
|
||||||
console.error("Failed to get screenshot", err);
|
console.error("Failed to get screenshot", err);
|
Loading…
Reference in a new issue