diff --git a/res/css/views/dialogs/_DevtoolsDialog.scss b/res/css/views/dialogs/_DevtoolsDialog.scss index 9d58c999c3..500c46b5fd 100644 --- a/res/css/views/dialogs/_DevtoolsDialog.scss +++ b/res/css/views/dialogs/_DevtoolsDialog.scss @@ -189,3 +189,37 @@ limitations under the License. } } } + +.mx_DevTools_VerificationRequest { + border: 1px solid #cccccc; + border-radius: 3px; + padding: 1px 5px; + margin-bottom: 6px; + font-family: $monospace-font-family; + + dl { + display: grid; + grid-template-columns: max-content auto; + margin: 0; + } + + dd { + grid-column-start: 2; + } + + dd:empty { + color: #666666; + &::after { + content: "(empty)"; + } + } + + dt { + font-weight: bold; + grid-column-start: 1; + } + + dt::after { + content: ":"; + } +} diff --git a/src/components/views/dialogs/DevtoolsDialog.js b/src/components/views/dialogs/DevtoolsDialog.js index 34b2f5a52b..348965582b 100644 --- a/src/components/views/dialogs/DevtoolsDialog.js +++ b/src/components/views/dialogs/DevtoolsDialog.js @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -import React from 'react'; +import React, {useState, useEffect} from 'react'; import PropTypes from 'prop-types'; import * as sdk from '../../../index'; import SyntaxHighlight from '../elements/SyntaxHighlight'; @@ -22,6 +22,16 @@ import { _t } from '../../../languageHandler'; import { Room } from "matrix-js-sdk"; import Field from "../elements/Field"; import MatrixClientContext from "../../../contexts/MatrixClientContext"; +import {useEventEmitter} from "../../../hooks/useEventEmitter"; + +import { + PHASE_UNSENT, + PHASE_REQUESTED, + PHASE_READY, + PHASE_DONE, + PHASE_STARTED, + PHASE_CANCELLED, +} from "matrix-js-sdk/src/crypto/verification/request/VerificationRequest"; class GenericEditor extends React.PureComponent { // static propTypes = {onBack: PropTypes.func.isRequired}; @@ -605,12 +615,97 @@ class ServersInRoomList extends React.PureComponent { } } +const PHASE_MAP = { + [PHASE_UNSENT]: "unsent", + [PHASE_REQUESTED]: "requested", + [PHASE_READY]: "ready", + [PHASE_DONE]: "done", + [PHASE_STARTED]: "started", + [PHASE_CANCELLED]: "cancelled", +}; + +function VerificationRequest({txnId, request}) { + const [, updateState] = useState(); + const [timeout, setRequestTimeout] = useState(request.timeout); + + /* Re-render if something changes state */ + useEventEmitter(request, "change", updateState); + + /* Keep re-rendering if there's a timeout */ + useEffect(() => { + if (request.timeout == 0) return; + + /* Note that request.timeout is a getter, so its value changes */ + const id = setInterval(() => { + setRequestTimeout(request.timeout); + }, 500); + + return () => { clearInterval(id); }; + }, [request]); + + return (
+
+
Transaction
+
{txnId}
+
Phase
+
{PHASE_MAP[request.phase] || request.phase}
+
Timeout
+
{Math.floor(timeout / 1000)}
+
Methods
+
{request.methods && request.methods.join(", ")}
+
requestingUserId
+
{request.requestingUserId}
+
observeOnly
+
{JSON.stringify(request.observeOnly)}
+
+
); +} + +class VerificationExplorer extends React.Component { + static getLabel() { + return _t("Verification Requests"); + } + + /* Ensure this.context is the cli */ + static contextType = MatrixClientContext; + + onNewRequest = () => { + this.forceUpdate(); + } + + componentDidMount() { + const cli = this.context; + cli.on("crypto.verification.request", this.onNewRequest); + } + + componentWillUnmount() { + const cli = this.context; + cli.off("crypto.verification.request", this.onNewRequest); + } + + render() { + const cli = this.context; + const room = this.props.room; + const inRoomChannel = cli._crypto._inRoomVerificationRequests; + const inRoomRequests = (inRoomChannel._requestsByRoomId || new Map()).get(room.roomId) || new Map(); + + return (
+
+ {Array.from(inRoomRequests.entries()).reverse().map(([txnId, request]) => + , + )} +
+
); + } +} + const Entries = [ SendCustomEvent, RoomStateExplorer, SendAccountData, AccountDataExplorer, ServersInRoomList, + VerificationExplorer, ]; export default class DevtoolsDialog extends React.PureComponent { diff --git a/src/i18n/strings/en_EN.json b/src/i18n/strings/en_EN.json index b55b28ce97..82eb660d9d 100644 --- a/src/i18n/strings/en_EN.json +++ b/src/i18n/strings/en_EN.json @@ -1524,6 +1524,7 @@ "Explore Room State": "Explore Room State", "Explore Account Data": "Explore Account Data", "View Servers in Room": "View Servers in Room", + "Verification Requests": "Verification Requests", "Toolbox": "Toolbox", "Developer Tools": "Developer Tools", "An error has occurred.": "An error has occurred.",