From 18fee179b81e781e460abec05059d8c91d17ac65 Mon Sep 17 00:00:00 2001 From: Timo k Date: Wed, 20 Oct 2021 18:03:35 +0200 Subject: [PATCH 01/10] implement RequiresClient capability Fix #15744 On request, Element disables the Popout button, this guarantees that the widgetApi is available. --- .../views/dialogs/WidgetCapabilitiesPromptDialog.tsx | 1 + src/components/views/elements/AppTile.tsx | 7 ++++++- src/stores/widgets/StopGapWidgetDriver.ts | 2 +- src/widgets/CapabilityText.tsx | 3 +++ 4 files changed, 11 insertions(+), 2 deletions(-) diff --git a/src/components/views/dialogs/WidgetCapabilitiesPromptDialog.tsx b/src/components/views/dialogs/WidgetCapabilitiesPromptDialog.tsx index 366adb887c1..ae11f41c138 100644 --- a/src/components/views/dialogs/WidgetCapabilitiesPromptDialog.tsx +++ b/src/components/views/dialogs/WidgetCapabilitiesPromptDialog.tsx @@ -106,6 +106,7 @@ export default class WidgetCapabilitiesPromptDialog extends React.PureComponent< return 0; }); + // const filteredCapabilites = //TODO this would be where the NoPopout capability text can be hidden and approved by default const checkboxRows = orderedCapabilities.map(([cap, isChecked], i) => { const text = CapabilityText.for(cap, this.props.widgetKind); const byline = text.byline diff --git a/src/components/views/elements/AppTile.tsx b/src/components/views/elements/AppTile.tsx index 5f7c0543c41..455533de00b 100644 --- a/src/components/views/elements/AppTile.tsx +++ b/src/components/views/elements/AppTile.tsx @@ -84,6 +84,7 @@ interface IState { error: Error; menuDisplayed: boolean; widgetPageTitle: string; + noPopout: boolean; } import { logger } from "matrix-js-sdk/src/logger"; @@ -155,6 +156,7 @@ export default class AppTile extends React.Component { error: null, menuDisplayed: false, widgetPageTitle: this.props.widgetPageTitle, + noPopout: true, }; } @@ -295,6 +297,9 @@ export default class AppTile extends React.Component { if (WidgetType.JITSI.matches(this.props.app.type)) { this.sgWidget.widgetApi.transport.send(ElementWidgetActions.ClientReady, {}); } + this.setState({ + noPopout: this.sgWidget.widgetApi.hasCapability(MatrixCapabilities.RequiresClient) + }); }; private onAction = (payload): void => { @@ -512,7 +517,7 @@ export default class AppTile extends React.Component { { this.props.showTitle && this.getTileTitle() } - { this.props.showPopout && Date: Mon, 25 Oct 2021 11:08:29 +0200 Subject: [PATCH 02/10] rename noPopout to: noPopoutButton (more explicit) --- .../views/dialogs/WidgetCapabilitiesPromptDialog.tsx | 1 - src/components/views/elements/AppTile.tsx | 8 ++++---- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/src/components/views/dialogs/WidgetCapabilitiesPromptDialog.tsx b/src/components/views/dialogs/WidgetCapabilitiesPromptDialog.tsx index ae11f41c138..366adb887c1 100644 --- a/src/components/views/dialogs/WidgetCapabilitiesPromptDialog.tsx +++ b/src/components/views/dialogs/WidgetCapabilitiesPromptDialog.tsx @@ -106,7 +106,6 @@ export default class WidgetCapabilitiesPromptDialog extends React.PureComponent< return 0; }); - // const filteredCapabilites = //TODO this would be where the NoPopout capability text can be hidden and approved by default const checkboxRows = orderedCapabilities.map(([cap, isChecked], i) => { const text = CapabilityText.for(cap, this.props.widgetKind); const byline = text.byline diff --git a/src/components/views/elements/AppTile.tsx b/src/components/views/elements/AppTile.tsx index 455533de00b..6ace1bac035 100644 --- a/src/components/views/elements/AppTile.tsx +++ b/src/components/views/elements/AppTile.tsx @@ -84,7 +84,7 @@ interface IState { error: Error; menuDisplayed: boolean; widgetPageTitle: string; - noPopout: boolean; + noPopoutButton: boolean; } import { logger } from "matrix-js-sdk/src/logger"; @@ -156,7 +156,7 @@ export default class AppTile extends React.Component { error: null, menuDisplayed: false, widgetPageTitle: this.props.widgetPageTitle, - noPopout: true, + noPopoutButton: true, }; } @@ -298,7 +298,7 @@ export default class AppTile extends React.Component { this.sgWidget.widgetApi.transport.send(ElementWidgetActions.ClientReady, {}); } this.setState({ - noPopout: this.sgWidget.widgetApi.hasCapability(MatrixCapabilities.RequiresClient) + noPopoutButton: this.sgWidget.widgetApi.hasCapability(MatrixCapabilities.RequiresClient) }); }; @@ -517,7 +517,7 @@ export default class AppTile extends React.Component { { this.props.showTitle && this.getTileTitle() } - {(this.props.showPopout && !this.state.noPopout) && Date: Mon, 25 Oct 2021 16:25:52 +0200 Subject: [PATCH 03/10] rename state to requireClient & remove approval text --- src/components/views/elements/AppTile.tsx | 8 ++++---- src/widgets/CapabilityText.tsx | 5 +---- 2 files changed, 5 insertions(+), 8 deletions(-) diff --git a/src/components/views/elements/AppTile.tsx b/src/components/views/elements/AppTile.tsx index 6ace1bac035..5537a338188 100644 --- a/src/components/views/elements/AppTile.tsx +++ b/src/components/views/elements/AppTile.tsx @@ -84,7 +84,7 @@ interface IState { error: Error; menuDisplayed: boolean; widgetPageTitle: string; - noPopoutButton: boolean; + requiresClient: boolean; } import { logger } from "matrix-js-sdk/src/logger"; @@ -156,7 +156,7 @@ export default class AppTile extends React.Component { error: null, menuDisplayed: false, widgetPageTitle: this.props.widgetPageTitle, - noPopoutButton: true, + requiresClient: true, }; } @@ -298,7 +298,7 @@ export default class AppTile extends React.Component { this.sgWidget.widgetApi.transport.send(ElementWidgetActions.ClientReady, {}); } this.setState({ - noPopoutButton: this.sgWidget.widgetApi.hasCapability(MatrixCapabilities.RequiresClient) + requiresClient: this.sgWidget.widgetApi.hasCapability(MatrixCapabilities.RequiresClient) }); }; @@ -517,7 +517,7 @@ export default class AppTile extends React.Component { { this.props.showTitle && this.getTileTitle() } - {(this.props.showPopout && !this.state.noPopoutButton) && Date: Mon, 25 Oct 2021 17:42:15 +0200 Subject: [PATCH 04/10] fix added missing comma --- src/widgets/CapabilityText.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/widgets/CapabilityText.tsx b/src/widgets/CapabilityText.tsx index 57c6f0d62ec..8c13a4b2fc5 100644 --- a/src/widgets/CapabilityText.tsx +++ b/src/widgets/CapabilityText.tsx @@ -73,7 +73,7 @@ export class CapabilityText { }, [MatrixCapabilities.MSC2931Navigate]: { [GENERIC_WIDGET_KIND]: _td("Change which room, message, or user you're viewing"), - } + }, }; private static stateSendRecvCaps: ISendRecvStaticCapText = { From 9e22eacbaf63aa0d7a5f3283e391e557236897a1 Mon Sep 17 00:00:00 2001 From: Timo K Date: Tue, 26 Oct 2021 15:50:39 +0200 Subject: [PATCH 05/10] handle updateRequestedCapabilities properly --- src/components/views/elements/AppTile.tsx | 8 ++++++-- src/stores/widgets/StopGapWidget.ts | 5 +++-- src/stores/widgets/StopGapWidgetDriver.ts | 4 +++- 3 files changed, 12 insertions(+), 5 deletions(-) diff --git a/src/components/views/elements/AppTile.tsx b/src/components/views/elements/AppTile.tsx index 5537a338188..074464f1ac1 100644 --- a/src/components/views/elements/AppTile.tsx +++ b/src/components/views/elements/AppTile.tsx @@ -117,6 +117,7 @@ export default class AppTile extends React.Component { this.sgWidget = new StopGapWidget(this.props); this.sgWidget.on("preparing", this.onWidgetPrepared); this.sgWidget.on("ready", this.onWidgetReady); + this.sgWidget.on("capabilities_renegotiated", this.onWidgetCapabilitesRenegotiating); } catch (e) { logger.log("Failed to construct widget", e); this.sgWidget = null; @@ -297,8 +298,11 @@ export default class AppTile extends React.Component { if (WidgetType.JITSI.matches(this.props.app.type)) { this.sgWidget.widgetApi.transport.send(ElementWidgetActions.ClientReady, {}); } + }; + + private onWidgetCapabilitesRenegotiating = (): void => { this.setState({ - requiresClient: this.sgWidget.widgetApi.hasCapability(MatrixCapabilities.RequiresClient) + requiresClient: this.sgWidget.widgetApi.hasCapability(MatrixCapabilities.RequiresClient), }); }; @@ -517,7 +521,7 @@ export default class AppTile extends React.Component { { this.props.showTitle && this.getTileTitle() } - {(this.props.showPopout && !this.state.requiresClient) && this.emit("preparing")); this.messaging.on("ready", () => this.emit("ready")); + this.messaging.on("capabilities_renegotiated", () => this.emit("capabilities_renegotiated")); this.messaging.on(`action:${WidgetApiFromWidgetAction.OpenModalWidget}`, this.onOpenModal); WidgetMessagingStore.instance.storeMessaging(this.mockWidget, this.messaging); diff --git a/src/stores/widgets/StopGapWidgetDriver.ts b/src/stores/widgets/StopGapWidgetDriver.ts index dd3b5776386..da844b19235 100644 --- a/src/stores/widgets/StopGapWidgetDriver.ts +++ b/src/stores/widgets/StopGapWidgetDriver.ts @@ -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 // 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. - this.allowedCapabilities = new Set([...allowedCapabilities, MatrixCapabilities.Screenshots, MatrixCapabilities.RequiresClient]); + this.allowedCapabilities = new Set([...allowedCapabilities, + MatrixCapabilities.Screenshots, + MatrixCapabilities.RequiresClient]); // Grant the permissions that are specific to given widget types if (WidgetType.JITSI.matches(this.forWidget.type) && forWidgetKind === WidgetKind.Room) { From 748bf346b0580898f0878f17f81e18d80595366d Mon Sep 17 00:00:00 2001 From: Timo K Date: Wed, 27 Oct 2021 12:14:33 +0200 Subject: [PATCH 06/10] add explanation for initial requiresClient state --- src/components/views/elements/AppTile.tsx | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/components/views/elements/AppTile.tsx b/src/components/views/elements/AppTile.tsx index 074464f1ac1..e346e6dd3b0 100644 --- a/src/components/views/elements/AppTile.tsx +++ b/src/components/views/elements/AppTile.tsx @@ -157,6 +157,9 @@ export default class AppTile extends React.Component { error: null, menuDisplayed: false, widgetPageTitle: this.props.widgetPageTitle, + // requiresClient is initially set to true. This avoids the broken state of the popout + // button beeing visible (for an instance) and than disappearing when the widget is loaded. + // requiresClient <-> hide the popout button requiresClient: true, }; } From 364a0e7e68b7d22b78d537e279a92c768b860c0e Mon Sep 17 00:00:00 2001 From: Timo K Date: Wed, 27 Oct 2021 14:32:03 +0200 Subject: [PATCH 07/10] fix typo and rename to preparing --- src/components/views/elements/AppTile.tsx | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/components/views/elements/AppTile.tsx b/src/components/views/elements/AppTile.tsx index e346e6dd3b0..e82383eae32 100644 --- a/src/components/views/elements/AppTile.tsx +++ b/src/components/views/elements/AppTile.tsx @@ -115,7 +115,7 @@ export default class AppTile extends React.Component { this.persistKey = getPersistKey(this.props.app.id); try { 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("capabilities_renegotiated", this.onWidgetCapabilitesRenegotiating); } catch (e) { @@ -158,7 +158,7 @@ export default class AppTile extends React.Component { menuDisplayed: false, widgetPageTitle: this.props.widgetPageTitle, // requiresClient is initially set to true. This avoids the broken state of the popout - // button beeing visible (for an instance) and than disappearing when the widget is loaded. + // button being visible (for an instance) and than disappearing when the widget is loaded. // requiresClient <-> hide the popout button requiresClient: true, }; @@ -222,7 +222,7 @@ export default class AppTile extends React.Component { } try { this.sgWidget = new StopGapWidget(newProps); - this.sgWidget.on("preparing", this.onWidgetPrepared); + this.sgWidget.on("preparing", this.onWidgetPreparing); this.sgWidget.on("ready", this.onWidgetReady); this.startWidget(); } catch (e) { @@ -293,7 +293,7 @@ export default class AppTile extends React.Component { if (this.sgWidget) this.sgWidget.stop({ forceDestroy: true }); } - private onWidgetPrepared = (): void => { + private onWidgetPreparing = (): void => { this.setState({ loading: false }); }; From 40b0272cd917717ea8b516e3aaddd464f75249f2 Mon Sep 17 00:00:00 2001 From: Timo K Date: Wed, 27 Oct 2021 15:02:02 +0200 Subject: [PATCH 08/10] rename event to capabilitiesNotified --- src/components/views/elements/AppTile.tsx | 5 +++-- src/stores/widgets/StopGapWidget.ts | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/components/views/elements/AppTile.tsx b/src/components/views/elements/AppTile.tsx index e82383eae32..38f84f70820 100644 --- a/src/components/views/elements/AppTile.tsx +++ b/src/components/views/elements/AppTile.tsx @@ -117,7 +117,8 @@ export default class AppTile extends React.Component { this.sgWidget = new StopGapWidget(this.props); this.sgWidget.on("preparing", this.onWidgetPreparing); this.sgWidget.on("ready", this.onWidgetReady); - this.sgWidget.on("capabilities_renegotiated", this.onWidgetCapabilitesRenegotiating); + // emits when the capabilites have been setup or changed + this.sgWidget.on("capabilitiesNotified", this.onWidgetCapabilitiesNotified); } catch (e) { logger.log("Failed to construct widget", e); this.sgWidget = null; @@ -303,7 +304,7 @@ export default class AppTile extends React.Component { } }; - private onWidgetCapabilitesRenegotiating = (): void => { + private onWidgetCapabilitiesNotified = (): void => { this.setState({ requiresClient: this.sgWidget.widgetApi.hasCapability(MatrixCapabilities.RequiresClient), }); diff --git a/src/stores/widgets/StopGapWidget.ts b/src/stores/widgets/StopGapWidget.ts index 5733e840377..b08b51a32fa 100644 --- a/src/stores/widgets/StopGapWidget.ts +++ b/src/stores/widgets/StopGapWidget.ts @@ -262,7 +262,7 @@ export class StopGapWidget extends EventEmitter { this.messaging = new ClientWidgetApi(this.mockWidget, iframe, driver); this.messaging.on("preparing", () => this.emit("preparing")); this.messaging.on("ready", () => this.emit("ready")); - this.messaging.on("capabilities_renegotiated", () => this.emit("capabilities_renegotiated")); + this.messaging.on("capabilitiesNotified", () => this.emit("capabilitiesNotified")); this.messaging.on(`action:${WidgetApiFromWidgetAction.OpenModalWidget}`, this.onOpenModal); WidgetMessagingStore.instance.storeMessaging(this.mockWidget, this.messaging); From 200d637625a2eddcdd1f2ffb7c37431de0f4996c Mon Sep 17 00:00:00 2001 From: Timo K Date: Thu, 28 Oct 2021 12:25:50 +0200 Subject: [PATCH 09/10] update matrix-widget-api version to beta17 --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index 1e0b7ef8d3d..116469c0cdb 100644 --- a/package.json +++ b/package.json @@ -84,7 +84,7 @@ "linkifyjs": "^2.1.9", "lodash": "^4.17.20", "matrix-js-sdk": "github:matrix-org/matrix-js-sdk#develop", - "matrix-widget-api": "^0.1.0-beta.16", + "matrix-widget-api": "^0.1.0-beta.17", "minimist": "^1.2.5", "opus-recorder": "^8.0.3", "pako": "^2.0.3", diff --git a/yarn.lock b/yarn.lock index 310ddf616fe..a4133ade2e3 100644 --- a/yarn.lock +++ b/yarn.lock @@ -5905,10 +5905,10 @@ matrix-react-test-utils@^0.2.3: "@babel/traverse" "^7.13.17" walk "^2.3.14" -matrix-widget-api@^0.1.0-beta.16: - version "0.1.0-beta.16" - resolved "https://registry.yarnpkg.com/matrix-widget-api/-/matrix-widget-api-0.1.0-beta.16.tgz#32655f05cab48239b97fe4111a1d0858f2aad61a" - integrity sha512-9zqaNLaM14YDHfFb7WGSUOivGOjYw+w5Su84ZfOl6A4IUy1xT9QPp0nsSA8wNfz0LpxOIPn3nuoF8Tn/40F5tg== +matrix-widget-api@^0.1.0-beta.17: + version "0.1.0-beta.17" + resolved "https://registry.yarnpkg.com/matrix-widget-api/-/matrix-widget-api-0.1.0-beta.17.tgz#392be2bf42990e8f7e16aeadf2546f18681af49b" + integrity sha512-hyaDLQNvGvV67Ss23vI69y/ZwVMVz2160LJ2nYyhO0C4mk9zTl0Rbe9jNQ9B453V8MadHLiUUdjzoe++WW+6jA== dependencies: "@types/events" "^3.0.0" events "^3.2.0" From 91d97d56608c76c279174548837a4591938fec1f Mon Sep 17 00:00:00 2001 From: Timo K Date: Thu, 28 Oct 2021 14:06:31 +0200 Subject: [PATCH 10/10] typo --- src/components/views/elements/AppTile.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/views/elements/AppTile.tsx b/src/components/views/elements/AppTile.tsx index 38f84f70820..d8a29e81fcb 100644 --- a/src/components/views/elements/AppTile.tsx +++ b/src/components/views/elements/AppTile.tsx @@ -159,7 +159,7 @@ export default class AppTile extends React.Component { menuDisplayed: false, 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 than disappearing when the widget is loaded. + // button being visible (for an instance) and then disappearing when the widget is loaded. // requiresClient <-> hide the popout button requiresClient: true, };