From cf158530f5fb0c69a4198d6d4f4b49e901926e39 Mon Sep 17 00:00:00 2001 From: Kegsay Date: Tue, 11 Jul 2017 12:15:27 +0100 Subject: [PATCH] Implement new widget API (#1201) * Implement new widget API This allows clients to see who provisioned which widgets. * Update to make state_key the wid * Update to latest API * Only show widgets which have required fields * Don't constantly show apps dialog * Fix example to include data key --- src/ScalarMessaging.js | 112 ++++++++++++----------- src/components/structures/RoomView.js | 10 +- src/components/views/elements/AppTile.js | 28 ++---- src/components/views/rooms/AppsDrawer.js | 32 +------ 4 files changed, 82 insertions(+), 100 deletions(-) diff --git a/src/ScalarMessaging.js b/src/ScalarMessaging.js index e7767cb3cd..df89f7dba2 100644 --- a/src/ScalarMessaging.js +++ b/src/ScalarMessaging.js @@ -143,41 +143,44 @@ Example: get_widgets ----------- -Get a list of all widgets in the room. The response is the `content` field -of the state event. +Get a list of all widgets in the room. The response is an array +of state events. Request: - `room_id` (String) is the room to get the widgets in. Response: -{ - $widget_id: { - type: "example", - url: "http://widget.url", - name: "Example Widget", - data: { - key: "val" +[ + { + type: "im.vector.modular.widgets", + state_key: "wid1", + content: { + type: "grafana", + url: "https://grafanaurl", + name: "dashboard", + data: {key: "val"} } - }, - $widget_id: { ... } -} + room_id: “!foo:bar”, + sender: "@alice:localhost" + } +] Example: { action: "get_widgets", room_id: "!foo:bar", - widget_id: "abc123", - url: "http://widget.url", - type: "example", - response: { - $widget_id: { - type: "example", - url: "http://widget.url", - name: "Example Widget", - data: { - key: "val" + response: [ + { + type: "im.vector.modular.widgets", + state_key: "wid1", + content: { + type: "grafana", + url: "https://grafanaurl", + name: "dashboard", + data: {key: "val"} } - }, - $widget_id: { ... } - } + room_id: “!foo:bar”, + sender: "@alice:localhost" + } + ] } @@ -301,33 +304,17 @@ function setWidget(event, roomId) { } } - // TODO: same dance we do for power levels. It'd be nice if the JS SDK had helper methods to do this. - client.getStateEvent(roomId, "im.vector.modular.widgets", "").then((widgets) => { - if (widgetUrl === null) { - delete widgets[widgetId]; - } - else { - widgets[widgetId] = { - type: widgetType, - url: widgetUrl, - name: widgetName, - data: widgetData, - }; - } - return client.sendStateEvent(roomId, "im.vector.modular.widgets", widgets); - }, (err) => { - if (err.errcode === "M_NOT_FOUND") { - return client.sendStateEvent(roomId, "im.vector.modular.widgets", { - [widgetId]: { - type: widgetType, - url: widgetUrl, - name: widgetName, - data: widgetData, - } - }); - } - throw err; - }).done(() => { + let content = { + type: widgetType, + url: widgetUrl, + name: widgetName, + data: widgetData, + }; + if (widgetUrl === null) { // widget is being deleted + content = {}; + } + + client.sendStateEvent(roomId, "im.vector.modular.widgets", content, widgetId).done(() => { sendResponse(event, { success: true, }); @@ -337,7 +324,26 @@ function setWidget(event, roomId) { } function getWidgets(event, roomId) { - returnStateEvent(event, roomId, "im.vector.modular.widgets", ""); + const client = MatrixClientPeg.get(); + if (!client) { + sendError(event, _t('You need to be logged in.')); + return; + } + const room = client.getRoom(roomId); + if (!room) { + sendError(event, _t('This room is not recognised.')); + return; + } + const stateEvents = room.currentState.getStateEvents("im.vector.modular.widgets"); + // Only return widgets which have required fields + let widgetStateEvents = []; + stateEvents.forEach((ev) => { + if (ev.getContent().type && ev.getContent().url) { + widgetStateEvents.push(ev.event); // return the raw event + } + }) + + sendResponse(event, widgetStateEvents); } function setPlumbingState(event, roomId, status) { diff --git a/src/components/structures/RoomView.js b/src/components/structures/RoomView.js index ffb0c1243c..f09e1197cf 100644 --- a/src/components/structures/RoomView.js +++ b/src/components/structures/RoomView.js @@ -275,8 +275,14 @@ module.exports = React.createClass({ }, _shouldShowApps: function(room) { - const appsStateEvents = room.currentState.getStateEvents('im.vector.modular.widgets', ''); - return appsStateEvents && Object.keys(appsStateEvents.getContent()).length > 0; + const appsStateEvents = room.currentState.getStateEvents('im.vector.modular.widgets'); + // any valid widget = show apps + for (let i = 0; i < appsStateEvents.length; i++) { + if (appsStateEvents[i].getContent().type && appsStateEvents[i].getContent().url) { + return true; + } + } + return false; }, componentDidMount: function() { diff --git a/src/components/views/elements/AppTile.js b/src/components/views/elements/AppTile.js index 9fed0e7d5b..23b7d9f604 100644 --- a/src/components/views/elements/AppTile.js +++ b/src/components/views/elements/AppTile.js @@ -91,24 +91,16 @@ export default React.createClass({ _onDeleteClick: function() { console.log("Delete widget %s", this.props.id); - const appsStateEvents = this.props.room.currentState.getStateEvents('im.vector.modular.widgets', ''); - if (!appsStateEvents) { - return; - } - const appsStateEvent = appsStateEvents.getContent(); - if (appsStateEvent[this.props.id]) { - delete appsStateEvent[this.props.id]; - MatrixClientPeg.get().sendStateEvent( - this.props.room.roomId, - 'im.vector.modular.widgets', - appsStateEvent, - '', - ).then(() => { - console.log('Deleted widget'); - }, (e) => { - console.error('Failed to delete widget', e); - }); - } + MatrixClientPeg.get().sendStateEvent( + this.props.room.roomId, + 'im.vector.modular.widgets', + {}, // empty content + this.props.id, + ).then(() => { + console.log('Deleted widget'); + }, (e) => { + console.error('Failed to delete widget', e); + }); }, formatAppTileName: function() { diff --git a/src/components/views/rooms/AppsDrawer.js b/src/components/views/rooms/AppsDrawer.js index a12bd8ecac..c95a473db8 100644 --- a/src/components/views/rooms/AppsDrawer.js +++ b/src/components/views/rooms/AppsDrawer.js @@ -111,26 +111,6 @@ module.exports = React.createClass({ app.name = app.name || app.type; app.url = this.encodeUri(app.url, params); - // switch(app.type) { - // case 'etherpad': - // app.queryParams = '?userName=' + this.props.userId + - // '&padId=' + this.props.room.roomId; - // break; - // case 'jitsi': { - // - // app.queryParams = '?confId=' + app.data.confId + - // '&displayName=' + encodeURIComponent(user.displayName) + - // '&avatarUrl=' + encodeURIComponent(MatrixClientPeg.get().mxcUrlToHttp(user.avatarUrl)) + - // '&email=' + encodeURIComponent(this.props.userId) + - // '&isAudioConf=' + app.data.isAudioConf; - // - // break; - // } - // case 'vrdemo': - // app.queryParams = '?roomAlias=' + encodeURIComponent(app.data.roomAlias); - // break; - // } - return app; }, @@ -142,17 +122,15 @@ module.exports = React.createClass({ }, _getApps: function() { - const appsStateEvents = this.props.room.currentState.getStateEvents('im.vector.modular.widgets', ''); + const appsStateEvents = this.props.room.currentState.getStateEvents('im.vector.modular.widgets'); if (!appsStateEvents) { return []; } - const appsStateEvent = appsStateEvents.getContent(); - if (Object.keys(appsStateEvent).length < 1) { - return []; - } - return Object.keys(appsStateEvent).map((appId) => { - return this._initAppConfig(appId, appsStateEvent[appId]); + return appsStateEvents.filter((ev) => { + return ev.getContent().type && ev.getContent().url; + }).map((ev) => { + return this._initAppConfig(ev.getStateKey(), ev.getContent()); }); },