mirror of https://github.com/vector-im/riot-web
Implement RequiresClient capability for widgets (#7005)
parent
68b64564c0
commit
5736fea5f3
|
@ -84,6 +84,7 @@ interface IState {
|
||||||
error: Error;
|
error: Error;
|
||||||
menuDisplayed: boolean;
|
menuDisplayed: boolean;
|
||||||
widgetPageTitle: string;
|
widgetPageTitle: string;
|
||||||
|
requiresClient: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
import { logger } from "matrix-js-sdk/src/logger";
|
import { logger } from "matrix-js-sdk/src/logger";
|
||||||
|
@ -114,8 +115,10 @@ export default class AppTile extends React.Component<IProps, IState> {
|
||||||
this.persistKey = getPersistKey(this.props.app.id);
|
this.persistKey = getPersistKey(this.props.app.id);
|
||||||
try {
|
try {
|
||||||
this.sgWidget = new StopGapWidget(this.props);
|
this.sgWidget = new StopGapWidget(this.props);
|
||||||
this.sgWidget.on("preparing", this.onWidgetPrepared);
|
this.sgWidget.on("preparing", this.onWidgetPreparing);
|
||||||
this.sgWidget.on("ready", this.onWidgetReady);
|
this.sgWidget.on("ready", this.onWidgetReady);
|
||||||
|
// emits when the capabilites have been setup or changed
|
||||||
|
this.sgWidget.on("capabilitiesNotified", this.onWidgetCapabilitiesNotified);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
logger.log("Failed to construct widget", e);
|
logger.log("Failed to construct widget", e);
|
||||||
this.sgWidget = null;
|
this.sgWidget = null;
|
||||||
|
@ -155,6 +158,10 @@ export default class AppTile extends React.Component<IProps, IState> {
|
||||||
error: null,
|
error: null,
|
||||||
menuDisplayed: false,
|
menuDisplayed: false,
|
||||||
widgetPageTitle: this.props.widgetPageTitle,
|
widgetPageTitle: this.props.widgetPageTitle,
|
||||||
|
// requiresClient is initially set to true. This avoids the broken state of the popout
|
||||||
|
// button being visible (for an instance) and then disappearing when the widget is loaded.
|
||||||
|
// requiresClient <-> hide the popout button
|
||||||
|
requiresClient: true,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -216,7 +223,7 @@ export default class AppTile extends React.Component<IProps, IState> {
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
this.sgWidget = new StopGapWidget(newProps);
|
this.sgWidget = new StopGapWidget(newProps);
|
||||||
this.sgWidget.on("preparing", this.onWidgetPrepared);
|
this.sgWidget.on("preparing", this.onWidgetPreparing);
|
||||||
this.sgWidget.on("ready", this.onWidgetReady);
|
this.sgWidget.on("ready", this.onWidgetReady);
|
||||||
this.startWidget();
|
this.startWidget();
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
|
@ -287,7 +294,7 @@ export default class AppTile extends React.Component<IProps, IState> {
|
||||||
if (this.sgWidget) this.sgWidget.stop({ forceDestroy: true });
|
if (this.sgWidget) this.sgWidget.stop({ forceDestroy: true });
|
||||||
}
|
}
|
||||||
|
|
||||||
private onWidgetPrepared = (): void => {
|
private onWidgetPreparing = (): void => {
|
||||||
this.setState({ loading: false });
|
this.setState({ loading: false });
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -297,6 +304,12 @@ export default class AppTile extends React.Component<IProps, IState> {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
private onWidgetCapabilitiesNotified = (): void => {
|
||||||
|
this.setState({
|
||||||
|
requiresClient: this.sgWidget.widgetApi.hasCapability(MatrixCapabilities.RequiresClient),
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
private onAction = (payload): void => {
|
private onAction = (payload): void => {
|
||||||
if (payload.widgetId === this.props.app.id) {
|
if (payload.widgetId === this.props.app.id) {
|
||||||
switch (payload.action) {
|
switch (payload.action) {
|
||||||
|
@ -512,7 +525,7 @@ export default class AppTile extends React.Component<IProps, IState> {
|
||||||
{ this.props.showTitle && this.getTileTitle() }
|
{ this.props.showTitle && this.getTileTitle() }
|
||||||
</span>
|
</span>
|
||||||
<span className="mx_AppTileMenuBarWidgets">
|
<span className="mx_AppTileMenuBarWidgets">
|
||||||
{ this.props.showPopout && <AccessibleButton
|
{ (this.props.showPopout && !this.state.requiresClient) && <AccessibleButton
|
||||||
className="mx_AppTileMenuBar_iconButton mx_AppTileMenuBar_iconButton_popout"
|
className="mx_AppTileMenuBar_iconButton mx_AppTileMenuBar_iconButton_popout"
|
||||||
title={_t('Popout widget')}
|
title={_t('Popout widget')}
|
||||||
onClick={this.onPopoutWidgetClick}
|
onClick={this.onPopoutWidgetClick}
|
||||||
|
|
|
@ -135,7 +135,7 @@ export class ElementWidget extends Widget {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
public getCompleteUrl(params: ITemplateParams, asPopout=false): string {
|
public getCompleteUrl(params: ITemplateParams, asPopout = false): string {
|
||||||
return runTemplate(asPopout ? this.popoutTemplateUrl : this.templateUrl, {
|
return runTemplate(asPopout ? this.popoutTemplateUrl : this.templateUrl, {
|
||||||
...this.rawDefinition,
|
...this.rawDefinition,
|
||||||
data: this.rawData,
|
data: this.rawData,
|
||||||
|
@ -149,7 +149,7 @@ export class StopGapWidget extends EventEmitter {
|
||||||
private scalarToken: string;
|
private scalarToken: string;
|
||||||
private roomId?: string;
|
private roomId?: string;
|
||||||
private kind: WidgetKind;
|
private kind: WidgetKind;
|
||||||
private readUpToMap: {[roomId: string]: string} = {}; // room ID to event ID
|
private readUpToMap: { [roomId: string]: string } = {}; // room ID to event ID
|
||||||
|
|
||||||
constructor(private appTileProps: IAppTileProps) {
|
constructor(private appTileProps: IAppTileProps) {
|
||||||
super();
|
super();
|
||||||
|
@ -262,6 +262,7 @@ export class StopGapWidget extends EventEmitter {
|
||||||
this.messaging = new ClientWidgetApi(this.mockWidget, iframe, driver);
|
this.messaging = new ClientWidgetApi(this.mockWidget, iframe, driver);
|
||||||
this.messaging.on("preparing", () => this.emit("preparing"));
|
this.messaging.on("preparing", () => this.emit("preparing"));
|
||||||
this.messaging.on("ready", () => this.emit("ready"));
|
this.messaging.on("ready", () => this.emit("ready"));
|
||||||
|
this.messaging.on("capabilitiesNotified", () => this.emit("capabilitiesNotified"));
|
||||||
this.messaging.on(`action:${WidgetApiFromWidgetAction.OpenModalWidget}`, this.onOpenModal);
|
this.messaging.on(`action:${WidgetApiFromWidgetAction.OpenModalWidget}`, this.onOpenModal);
|
||||||
WidgetMessagingStore.instance.storeMessaging(this.mockWidget, this.messaging);
|
WidgetMessagingStore.instance.storeMessaging(this.mockWidget, this.messaging);
|
||||||
|
|
||||||
|
|
|
@ -73,7 +73,9 @@ export class StopGapWidgetDriver extends WidgetDriver {
|
||||||
// Always allow screenshots to be taken because it's a client-induced flow. The widget can't
|
// Always allow screenshots to be taken because it's a client-induced flow. The widget can't
|
||||||
// spew screenshots at us and can't request screenshots of us, so it's up to us to provide the
|
// spew screenshots at us and can't request screenshots of us, so it's up to us to provide the
|
||||||
// button if the widget says it supports screenshots.
|
// button if the widget says it supports screenshots.
|
||||||
this.allowedCapabilities = new Set([...allowedCapabilities, MatrixCapabilities.Screenshots]);
|
this.allowedCapabilities = new Set([...allowedCapabilities,
|
||||||
|
MatrixCapabilities.Screenshots,
|
||||||
|
MatrixCapabilities.RequiresClient]);
|
||||||
|
|
||||||
// Grant the permissions that are specific to given widget types
|
// Grant the permissions that are specific to given widget types
|
||||||
if (WidgetType.JITSI.matches(this.forWidget.type) && forWidgetKind === WidgetKind.Room) {
|
if (WidgetType.JITSI.matches(this.forWidget.type) && forWidgetKind === WidgetKind.Room) {
|
||||||
|
|
Loading…
Reference in New Issue