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
pull/21833/head
Kegsay 2017-07-11 12:15:27 +01:00 committed by GitHub
parent 5c89d3303b
commit cf158530f5
4 changed files with 82 additions and 100 deletions

View File

@ -143,41 +143,44 @@ Example:
get_widgets get_widgets
----------- -----------
Get a list of all widgets in the room. The response is the `content` field Get a list of all widgets in the room. The response is an array
of the state event. of state events.
Request: Request:
- `room_id` (String) is the room to get the widgets in. - `room_id` (String) is the room to get the widgets in.
Response: Response:
{ [
$widget_id: { {
type: "example", type: "im.vector.modular.widgets",
url: "http://widget.url", state_key: "wid1",
name: "Example Widget", content: {
data: { type: "grafana",
key: "val" url: "https://grafanaurl",
name: "dashboard",
data: {key: "val"}
} }
}, room_id: !foo:bar,
$widget_id: { ... } sender: "@alice:localhost"
} }
]
Example: Example:
{ {
action: "get_widgets", action: "get_widgets",
room_id: "!foo:bar", room_id: "!foo:bar",
widget_id: "abc123", response: [
url: "http://widget.url", {
type: "example", type: "im.vector.modular.widgets",
response: { state_key: "wid1",
$widget_id: { content: {
type: "example", type: "grafana",
url: "http://widget.url", url: "https://grafanaurl",
name: "Example Widget", name: "dashboard",
data: { data: {key: "val"}
key: "val"
} }
}, room_id: !foo:bar,
$widget_id: { ... } 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. let content = {
client.getStateEvent(roomId, "im.vector.modular.widgets", "").then((widgets) => { type: widgetType,
if (widgetUrl === null) { url: widgetUrl,
delete widgets[widgetId]; name: widgetName,
} data: widgetData,
else { };
widgets[widgetId] = { if (widgetUrl === null) { // widget is being deleted
type: widgetType, content = {};
url: widgetUrl, }
name: widgetName,
data: widgetData, client.sendStateEvent(roomId, "im.vector.modular.widgets", content, widgetId).done(() => {
};
}
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(() => {
sendResponse(event, { sendResponse(event, {
success: true, success: true,
}); });
@ -337,7 +324,26 @@ function setWidget(event, roomId) {
} }
function getWidgets(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) { function setPlumbingState(event, roomId, status) {

View File

@ -275,8 +275,14 @@ module.exports = React.createClass({
}, },
_shouldShowApps: function(room) { _shouldShowApps: function(room) {
const appsStateEvents = room.currentState.getStateEvents('im.vector.modular.widgets', ''); const appsStateEvents = room.currentState.getStateEvents('im.vector.modular.widgets');
return appsStateEvents && Object.keys(appsStateEvents.getContent()).length > 0; // 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() { componentDidMount: function() {

View File

@ -91,24 +91,16 @@ export default React.createClass({
_onDeleteClick: function() { _onDeleteClick: function() {
console.log("Delete widget %s", this.props.id); console.log("Delete widget %s", this.props.id);
const appsStateEvents = this.props.room.currentState.getStateEvents('im.vector.modular.widgets', ''); MatrixClientPeg.get().sendStateEvent(
if (!appsStateEvents) { this.props.room.roomId,
return; 'im.vector.modular.widgets',
} {}, // empty content
const appsStateEvent = appsStateEvents.getContent(); this.props.id,
if (appsStateEvent[this.props.id]) { ).then(() => {
delete appsStateEvent[this.props.id]; console.log('Deleted widget');
MatrixClientPeg.get().sendStateEvent( }, (e) => {
this.props.room.roomId, console.error('Failed to delete widget', e);
'im.vector.modular.widgets', });
appsStateEvent,
'',
).then(() => {
console.log('Deleted widget');
}, (e) => {
console.error('Failed to delete widget', e);
});
}
}, },
formatAppTileName: function() { formatAppTileName: function() {

View File

@ -111,26 +111,6 @@ module.exports = React.createClass({
app.name = app.name || app.type; app.name = app.name || app.type;
app.url = this.encodeUri(app.url, params); 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; return app;
}, },
@ -142,17 +122,15 @@ module.exports = React.createClass({
}, },
_getApps: function() { _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) { if (!appsStateEvents) {
return []; return [];
} }
const appsStateEvent = appsStateEvents.getContent();
if (Object.keys(appsStateEvent).length < 1) {
return [];
}
return Object.keys(appsStateEvent).map((appId) => { return appsStateEvents.filter((ev) => {
return this._initAppConfig(appId, appsStateEvent[appId]); return ev.getContent().type && ev.getContent().url;
}).map((ev) => {
return this._initAppConfig(ev.getStateKey(), ev.getContent());
}); });
}, },