Skip to content
This repository has been archived by the owner on Sep 11, 2024. It is now read-only.

Commit

Permalink
Merge pull request #5385 from matrix-org/travis/msc-send-widget-events
Browse files Browse the repository at this point in the history
Add new widget API actions for changing rooms and sending/receiving events
  • Loading branch information
turt2live authored Nov 20, 2020
2 parents 8c2f1b4 + 2446fb1 commit 5f47077
Show file tree
Hide file tree
Showing 16 changed files with 835 additions and 15 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@
"linkifyjs": "^2.1.9",
"lodash": "^4.17.19",
"matrix-js-sdk": "github:matrix-org/matrix-js-sdk#develop",
"matrix-widget-api": "^0.1.0-beta.8",
"matrix-widget-api": "^0.1.0-beta.9",
"minimist": "^1.2.5",
"pako": "^1.0.11",
"parse5": "^5.1.1",
Expand Down
9 changes: 9 additions & 0 deletions res/css/_common.scss
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,10 @@ pre, code {
color: $accent-color;
}

.text-muted {
color: $muted-fg-color;
}

b {
// On Firefox, the default weight for `<b>` is `bolder` which results in no bold
// effect since we only have specific weights of our fonts available.
Expand Down Expand Up @@ -364,6 +368,11 @@ input[type=text]:focus, input[type=password]:focus, textarea:focus {
.mx_Dialog_buttons {
margin-top: 20px;
text-align: right;

.mx_Dialog_buttons_additive {
// The consumer is responsible for positioning their elements.
float: left;
}
}

/* XXX: Our button style are a mess: buttons that happen to appear in dialogs get special styles applied
Expand Down
1 change: 1 addition & 0 deletions res/css/_components.scss
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,7 @@
@import "./views/dialogs/_TermsDialog.scss";
@import "./views/dialogs/_UploadConfirmDialog.scss";
@import "./views/dialogs/_UserSettingsDialog.scss";
@import "./views/dialogs/_WidgetCapabilitiesPromptDialog.scss";
@import "./views/dialogs/_WidgetOpenIDPermissionsDialog.scss";
@import "./views/dialogs/security/_AccessSecretStorageDialog.scss";
@import "./views/dialogs/security/_CreateCrossSigningDialog.scss";
Expand Down
75 changes: 75 additions & 0 deletions res/css/views/dialogs/_WidgetCapabilitiesPromptDialog.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
/*
Copyright 2020 The Matrix.org Foundation C.I.C.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/


.mx_WidgetCapabilitiesPromptDialog {
.text-muted {
font-size: $font-12px;
}

.mx_Dialog_content {
margin-bottom: 16px;
}

.mx_WidgetCapabilitiesPromptDialog_cap {
margin-top: 20px;
font-size: $font-15px;
line-height: $font-15px;

.mx_WidgetCapabilitiesPromptDialog_byline {
color: $muted-fg-color;
margin-left: 26px;
font-size: $font-12px;
line-height: $font-12px;
}
}

.mx_Dialog_buttons {
margin-top: 40px; // double normal
}

.mx_SettingsFlag {
line-height: calc($font-14px + 7px + 7px); // 7px top & bottom padding
color: $muted-fg-color;
font-size: $font-12px;

.mx_ToggleSwitch {
display: inline-block;
vertical-align: middle;
margin-right: 8px;

// downsize the switch + ball
width: $font-32px;
height: $font-15px;


&.mx_ToggleSwitch_on > .mx_ToggleSwitch_ball {
left: calc(100% - $font-15px);
}

.mx_ToggleSwitch_ball {
width: $font-15px;
height: $font-15px;
border-radius: $font-15px;
}
}

.mx_SettingsFlag_label {
display: inline-block;
vertical-align: middle;
}
}
}
3 changes: 2 additions & 1 deletion src/components/views/dialogs/ModalWidgetDialog.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ import {
ModalButtonKind,
Widget,
WidgetApiFromWidgetAction,
WidgetKind,
} from "matrix-widget-api";
import {StopGapWidgetDriver} from "../../../stores/widgets/StopGapWidgetDriver";
import {MatrixClientPeg} from "../../../MatrixClientPeg";
Expand Down Expand Up @@ -72,7 +73,7 @@ export default class ModalWidgetDialog extends React.PureComponent<IProps, IStat
}

public componentDidMount() {
const driver = new StopGapWidgetDriver( []);
const driver = new StopGapWidgetDriver( [], this.widget, WidgetKind.Modal);
const messaging = new ClientWidgetApi(this.widget, this.appFrame.current, driver);
this.setState({messaging});
}
Expand Down
147 changes: 147 additions & 0 deletions src/components/views/dialogs/WidgetCapabilitiesPromptDialog.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,147 @@
/*
Copyright 2020 The Matrix.org Foundation C.I.C.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

import React from 'react';
import BaseDialog from "./BaseDialog";
import { _t } from "../../../languageHandler";
import { IDialogProps } from "./IDialogProps";
import {
Capability,
Widget,
WidgetEventCapability,
WidgetKind,
} from "matrix-widget-api";
import { objectShallowClone } from "../../../utils/objects";
import StyledCheckbox from "../elements/StyledCheckbox";
import DialogButtons from "../elements/DialogButtons";
import LabelledToggleSwitch from "../elements/LabelledToggleSwitch";
import { CapabilityText } from "../../../widgets/CapabilityText";

export function getRememberedCapabilitiesForWidget(widget: Widget): Capability[] {
return JSON.parse(localStorage.getItem(`widget_${widget.id}_approved_caps`) || "[]");
}

function setRememberedCapabilitiesForWidget(widget: Widget, caps: Capability[]) {
localStorage.setItem(`widget_${widget.id}_approved_caps`, JSON.stringify(caps));
}

interface IProps extends IDialogProps {
requestedCapabilities: Set<Capability>;
widget: Widget;
widgetKind: WidgetKind; // TODO: Refactor into the Widget class
}

interface IBooleanStates {
// @ts-ignore - TS wants a string key, but we know better
[capability: Capability]: boolean;
}

interface IState {
booleanStates: IBooleanStates;
rememberSelection: boolean;
}

export default class WidgetCapabilitiesPromptDialog extends React.PureComponent<IProps, IState> {
private eventPermissionsMap = new Map<Capability, WidgetEventCapability>();

constructor(props: IProps) {
super(props);

const parsedEvents = WidgetEventCapability.findEventCapabilities(this.props.requestedCapabilities);
parsedEvents.forEach(e => this.eventPermissionsMap.set(e.raw, e));

const states: IBooleanStates = {};
this.props.requestedCapabilities.forEach(c => states[c] = true);

this.state = {
booleanStates: states,
rememberSelection: true,
};
}

private onToggle = (capability: Capability) => {
const newStates = objectShallowClone(this.state.booleanStates);
newStates[capability] = !newStates[capability];
this.setState({booleanStates: newStates});
};

private onRememberSelectionChange = (newVal: boolean) => {
this.setState({rememberSelection: newVal});
};

private onSubmit = async (ev) => {
this.closeAndTryRemember(Object.entries(this.state.booleanStates)
.filter(([_, isSelected]) => isSelected)
.map(([cap]) => cap));
};

private onReject = async (ev) => {
this.closeAndTryRemember([]); // nothing was approved
};

private closeAndTryRemember(approved: Capability[]) {
if (this.state.rememberSelection) {
setRememberedCapabilitiesForWidget(this.props.widget, approved);
}
this.props.onFinished({approved});
}

public render() {
const checkboxRows = Object.entries(this.state.booleanStates).map(([cap, isChecked], i) => {
const text = CapabilityText.for(cap, this.props.widgetKind);
const byline = text.byline
? <span className="mx_WidgetCapabilitiesPromptDialog_byline">{text.byline}</span>
: null;

return (
<div className="mx_WidgetCapabilitiesPromptDialog_cap" key={cap + i}>
<StyledCheckbox
checked={isChecked}
onChange={() => this.onToggle(cap)}
>{text.primary}</StyledCheckbox>
{byline}
</div>
);
});

return (
<BaseDialog
className="mx_WidgetCapabilitiesPromptDialog"
onFinished={this.props.onFinished}
title={_t("Approve widget permissions")}
>
<form onSubmit={this.onSubmit}>
<div className="mx_Dialog_content">
<div className="text-muted">{_t("This widget would like to:")}</div>
{checkboxRows}
<DialogButtons
primaryButton={_t("Approve")}
cancelButton={_t("Decline All")}
onPrimaryButtonClick={this.onSubmit}
onCancel={this.onReject}
additive={
<LabelledToggleSwitch
value={this.state.rememberSelection}
toggleInFront={true}
onChange={this.onRememberSelectionChange}
label={_t("Remember my selection for this widget")} />}
/>
</div>
</form>
</BaseDialog>
);
}
}
9 changes: 9 additions & 0 deletions src/components/views/elements/DialogButtons.js
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,9 @@ export default class DialogButtons extends React.Component {

// disables only the primary button
primaryDisabled: PropTypes.bool,

// something to stick next to the buttons, optionally
additive: PropTypes.element,
};

static defaultProps = {
Expand Down Expand Up @@ -85,8 +88,14 @@ export default class DialogButtons extends React.Component {
</button>;
}

let additive = null;
if (this.props.additive) {
additive = <div className="mx_Dialog_buttons_additive">{this.props.additive}</div>;
}

return (
<div className="mx_Dialog_buttons">
{ additive }
{ cancelButton }
{ this.props.children }
<button type={this.props.primaryIsSubmit ? 'submit' : 'button'}
Expand Down
62 changes: 61 additions & 1 deletion src/i18n/strings/en_EN.json
Original file line number Diff line number Diff line change
Expand Up @@ -569,6 +569,62 @@
"%(names)s and %(count)s others are typing …|other": "%(names)s and %(count)s others are typing …",
"%(names)s and %(count)s others are typing …|one": "%(names)s and one other is typing …",
"%(names)s and %(lastPerson)s are typing …": "%(names)s and %(lastPerson)s are typing …",
"Remain on your screen when viewing another room, when running": "Remain on your screen when viewing another room, when running",
"Remain on your screen while running": "Remain on your screen while running",
"Send stickers into this room": "Send stickers into this room",
"Send stickers into your active room": "Send stickers into your active room",
"Change which room you're viewing": "Change which room you're viewing",
"Change the topic of this room": "Change the topic of this room",
"See when the topic changes in this room": "See when the topic changes in this room",
"Change the topic of your active room": "Change the topic of your active room",
"See when the topic changes in your active room": "See when the topic changes in your active room",
"Change the name of this room": "Change the name of this room",
"See when the name changes in this room": "See when the name changes in this room",
"Change the name of your active room": "Change the name of your active room",
"See when the name changes in your active room": "See when the name changes in your active room",
"Change the avatar of this room": "Change the avatar of this room",
"See when the avatar changes in this room": "See when the avatar changes in this room",
"Change the avatar of your active room": "Change the avatar of your active room",
"See when the avatar changes in your active room": "See when the avatar changes in your active room",
"Send stickers to this room as you": "Send stickers to this room as you",
"See when a sticker is posted in this room": "See when a sticker is posted in this room",
"Send stickers to your active room as you": "Send stickers to your active room as you",
"See when anyone posts a sticker to your active room": "See when anyone posts a sticker to your active room",
"with an empty state key": "with an empty state key",
"with state key %(stateKey)s": "with state key %(stateKey)s",
"Send <b>%(eventType)s</b> events as you in this room": "Send <b>%(eventType)s</b> events as you in this room",
"See <b>%(eventType)s</b> events posted to this room": "See <b>%(eventType)s</b> events posted to this room",
"Send <b>%(eventType)s</b> events as you in your active room": "Send <b>%(eventType)s</b> events as you in your active room",
"See <b>%(eventType)s</b> events posted to your active room": "See <b>%(eventType)s</b> events posted to your active room",
"The <b>%(capability)s</b> capability": "The <b>%(capability)s</b> capability",
"Send messages as you in this room": "Send messages as you in this room",
"Send messages as you in your active room": "Send messages as you in your active room",
"See messages posted to this room": "See messages posted to this room",
"See messages posted to your active room": "See messages posted to your active room",
"Send text messages as you in this room": "Send text messages as you in this room",
"Send text messages as you in your active room": "Send text messages as you in your active room",
"See text messages posted to this room": "See text messages posted to this room",
"See text messages posted to your active room": "See text messages posted to your active room",
"Send emotes as you in this room": "Send emotes as you in this room",
"Send emotes as you in your active room": "Send emotes as you in your active room",
"See emotes posted to this room": "See emotes posted to this room",
"See emotes posted to your active room": "See emotes posted to your active room",
"Send images as you in this room": "Send images as you in this room",
"Send images as you in your active room": "Send images as you in your active room",
"See images posted to this room": "See images posted to this room",
"See images posted to your active room": "See images posted to your active room",
"Send videos as you in this room": "Send videos as you in this room",
"Send videos as you in your active room": "Send videos as you in your active room",
"See videos posted to this room": "See videos posted to this room",
"See videos posted to your active room": "See videos posted to your active room",
"Send general files as you in this room": "Send general files as you in this room",
"Send general files as you in your active room": "Send general files as you in your active room",
"See general files posted to this room": "See general files posted to this room",
"See general files posted to your active room": "See general files posted to your active room",
"Send <b>%(msgtype)s</b> messages as you in this room": "Send <b>%(msgtype)s</b> messages as you in this room",
"Send <b>%(msgtype)s</b> messages as you in your active room": "Send <b>%(msgtype)s</b> messages as you in your active room",
"See <b>%(msgtype)s</b> messages posted to this room": "See <b>%(msgtype)s</b> messages posted to this room",
"See <b>%(msgtype)s</b> messages posted to your active room": "See <b>%(msgtype)s</b> messages posted to your active room",
"Cannot reach homeserver": "Cannot reach homeserver",
"Ensure you have a stable internet connection, or get in touch with the server admin": "Ensure you have a stable internet connection, or get in touch with the server admin",
"Your %(brand)s is misconfigured": "Your %(brand)s is misconfigured",
Expand Down Expand Up @@ -2125,9 +2181,13 @@
"Upload Error": "Upload Error",
"Verify other session": "Verify other session",
"Verification Request": "Verification Request",
"Approve widget permissions": "Approve widget permissions",
"This widget would like to:": "This widget would like to:",
"Approve": "Approve",
"Decline All": "Decline All",
"Remember my selection for this widget": "Remember my selection for this widget",
"A widget would like to verify your identity": "A widget would like to verify your identity",
"A widget located at %(widgetUrl)s would like to verify your identity. By allowing this, the widget will be able to verify your user ID, but not perform actions as you.": "A widget located at %(widgetUrl)s would like to verify your identity. By allowing this, the widget will be able to verify your user ID, but not perform actions as you.",
"Remember my selection for this widget": "Remember my selection for this widget",
"Allow": "Allow",
"Deny": "Deny",
"Wrong file type": "Wrong file type",
Expand Down
Loading

0 comments on commit 5f47077

Please sign in to comment.