Add types to DevtoolsDialog
This commit is contained in:
parent
df09bdf823
commit
d9e490926b
1 changed files with 221 additions and 171 deletions
|
@ -1,5 +1,6 @@
|
||||||
/*
|
/*
|
||||||
Copyright 2017 Michael Telatynski <7t3chguy@gmail.com>
|
Copyright 2017 Michael Telatynski <7t3chguy@gmail.com>
|
||||||
|
Copyright 2018-2021 The Matrix.org Foundation C.I.C.
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
you may not use this file except in compliance with the License.
|
you may not use this file except in compliance with the License.
|
||||||
|
@ -14,8 +15,7 @@ See the License for the specific language governing permissions and
|
||||||
limitations under the License.
|
limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import React, {useState, useEffect} from 'react';
|
import React, {useState, useEffect, ChangeEvent, MouseEvent} from 'react';
|
||||||
import PropTypes from 'prop-types';
|
|
||||||
import * as sdk from '../../../index';
|
import * as sdk from '../../../index';
|
||||||
import SyntaxHighlight from '../elements/SyntaxHighlight';
|
import SyntaxHighlight from '../elements/SyntaxHighlight';
|
||||||
import { _t } from '../../../languageHandler';
|
import { _t } from '../../../languageHandler';
|
||||||
|
@ -30,8 +30,9 @@ import {
|
||||||
PHASE_DONE,
|
PHASE_DONE,
|
||||||
PHASE_STARTED,
|
PHASE_STARTED,
|
||||||
PHASE_CANCELLED,
|
PHASE_CANCELLED,
|
||||||
|
VerificationRequest,
|
||||||
} from "matrix-js-sdk/src/crypto/verification/request/VerificationRequest";
|
} from "matrix-js-sdk/src/crypto/verification/request/VerificationRequest";
|
||||||
import WidgetStore from "../../../stores/WidgetStore";
|
import WidgetStore, { IApp } from "../../../stores/WidgetStore";
|
||||||
import {UPDATE_EVENT} from "../../../stores/AsyncStore";
|
import {UPDATE_EVENT} from "../../../stores/AsyncStore";
|
||||||
import {SETTINGS} from "../../../settings/Settings";
|
import {SETTINGS} from "../../../settings/Settings";
|
||||||
import SettingsStore, {LEVEL_ORDER} from "../../../settings/SettingsStore";
|
import SettingsStore, {LEVEL_ORDER} from "../../../settings/SettingsStore";
|
||||||
|
@ -40,17 +41,22 @@ import ErrorDialog from "./ErrorDialog";
|
||||||
import {replaceableComponent} from "../../../utils/replaceableComponent";
|
import {replaceableComponent} from "../../../utils/replaceableComponent";
|
||||||
import {Room} from "matrix-js-sdk/src/models/room";
|
import {Room} from "matrix-js-sdk/src/models/room";
|
||||||
import {MatrixEvent} from "matrix-js-sdk/src/models/event";
|
import {MatrixEvent} from "matrix-js-sdk/src/models/event";
|
||||||
|
import { SettingLevel } from '../../../settings/SettingLevel';
|
||||||
|
|
||||||
class GenericEditor extends React.PureComponent {
|
interface IGenericEditorProps {
|
||||||
// static propTypes = {onBack: PropTypes.func.isRequired};
|
onBack: () => void;
|
||||||
|
|
||||||
constructor(props) {
|
|
||||||
super(props);
|
|
||||||
this._onChange = this._onChange.bind(this);
|
|
||||||
this.onBack = this.onBack.bind(this);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
onBack() {
|
interface IGenericEditorState {
|
||||||
|
message?: string;
|
||||||
|
[inputId: string]: boolean | string;
|
||||||
|
}
|
||||||
|
|
||||||
|
abstract class GenericEditor<
|
||||||
|
P extends IGenericEditorProps = IGenericEditorProps,
|
||||||
|
S extends IGenericEditorState = IGenericEditorState,
|
||||||
|
> extends React.PureComponent<P, S> {
|
||||||
|
protected onBack = () => {
|
||||||
if (this.state.message) {
|
if (this.state.message) {
|
||||||
this.setState({ message: null });
|
this.setState({ message: null });
|
||||||
} else {
|
} else {
|
||||||
|
@ -58,47 +64,60 @@ class GenericEditor extends React.PureComponent {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_onChange(e) {
|
protected onChange = (e: ChangeEvent<HTMLInputElement | HTMLTextAreaElement>) => {
|
||||||
|
// @ts-ignore: Unsure how to convince TS this is okay when the state
|
||||||
|
// type can be extended.
|
||||||
this.setState({[e.target.id]: e.target.type === 'checkbox' ? e.target.checked : e.target.value});
|
this.setState({[e.target.id]: e.target.type === 'checkbox' ? e.target.checked : e.target.value});
|
||||||
}
|
}
|
||||||
|
|
||||||
_buttons() {
|
protected abstract send();
|
||||||
return <div className="mx_Dialog_buttons">
|
|
||||||
|
protected buttons(): React.ReactNode {
|
||||||
|
return <div className="mx_Dialogbuttons">
|
||||||
<button onClick={this.onBack}>{ _t('Back') }</button>
|
<button onClick={this.onBack}>{ _t('Back') }</button>
|
||||||
{ !this.state.message && <button onClick={this._send}>{ _t('Send') }</button> }
|
{ !this.state.message && <button onClick={this.send}>{ _t('Send') }</button> }
|
||||||
</div>;
|
</div>;
|
||||||
}
|
}
|
||||||
|
|
||||||
textInput(id, label) {
|
protected textInput(id: string, label: string): React.ReactNode {
|
||||||
return <Field
|
return <Field
|
||||||
id={id}
|
id={id}
|
||||||
label={label}
|
label={label}
|
||||||
size="42"
|
size={42}
|
||||||
autoFocus={true}
|
autoFocus={true}
|
||||||
type="text"
|
type="text"
|
||||||
autoComplete="on"
|
autoComplete="on"
|
||||||
value={this.state[id]}
|
value={this.state[id] as string}
|
||||||
onChange={this._onChange}
|
onChange={this.onChange}
|
||||||
/>;
|
/>;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export class SendCustomEvent extends GenericEditor {
|
interface ISendCustomEventProps extends IGenericEditorProps {
|
||||||
static getLabel() { return _t('Send Custom Event'); }
|
room: Room;
|
||||||
|
forceStateEvent?: boolean;
|
||||||
static propTypes = {
|
forceGeneralEvent?: boolean;
|
||||||
onBack: PropTypes.func.isRequired,
|
inputs?: {
|
||||||
room: PropTypes.instanceOf(Room).isRequired,
|
eventType?: string;
|
||||||
forceStateEvent: PropTypes.bool,
|
stateKey?: string;
|
||||||
forceGeneralEvent: PropTypes.bool,
|
evContent?: string;
|
||||||
inputs: PropTypes.object,
|
|
||||||
};
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
interface ISendCustomEventState extends IGenericEditorState {
|
||||||
|
isStateEvent: boolean;
|
||||||
|
eventType: string;
|
||||||
|
stateKey: string;
|
||||||
|
evContent: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export class SendCustomEvent extends GenericEditor<ISendCustomEventProps, ISendCustomEventState> {
|
||||||
|
static getLabel() { return _t('Send Custom Event'); }
|
||||||
|
|
||||||
static contextType = MatrixClientContext;
|
static contextType = MatrixClientContext;
|
||||||
|
|
||||||
constructor(props) {
|
constructor(props) {
|
||||||
super(props);
|
super(props);
|
||||||
this._send = this._send.bind(this);
|
|
||||||
|
|
||||||
const {eventType, stateKey, evContent} = Object.assign({
|
const {eventType, stateKey, evContent} = Object.assign({
|
||||||
eventType: '',
|
eventType: '',
|
||||||
|
@ -115,7 +134,7 @@ export class SendCustomEvent extends GenericEditor {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
send(content) {
|
private doSend(content: object): Promise<void> {
|
||||||
const cli = this.context;
|
const cli = this.context;
|
||||||
if (this.state.isStateEvent) {
|
if (this.state.isStateEvent) {
|
||||||
return cli.sendStateEvent(this.props.room.roomId, this.state.eventType, content, this.state.stateKey);
|
return cli.sendStateEvent(this.props.room.roomId, this.state.eventType, content, this.state.stateKey);
|
||||||
|
@ -124,7 +143,7 @@ export class SendCustomEvent extends GenericEditor {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async _send() {
|
protected send = async () => {
|
||||||
if (this.state.eventType === '') {
|
if (this.state.eventType === '') {
|
||||||
this.setState({ message: _t('You must specify an event type!') });
|
this.setState({ message: _t('You must specify an event type!') });
|
||||||
return;
|
return;
|
||||||
|
@ -133,7 +152,7 @@ export class SendCustomEvent extends GenericEditor {
|
||||||
let message;
|
let message;
|
||||||
try {
|
try {
|
||||||
const content = JSON.parse(this.state.evContent);
|
const content = JSON.parse(this.state.evContent);
|
||||||
await this.send(content);
|
await this.doSend(content);
|
||||||
message = _t('Event sent!');
|
message = _t('Event sent!');
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
message = _t('Failed to send custom event.') + ' (' + e.toString() + ')';
|
message = _t('Failed to send custom event.') + ' (' + e.toString() + ')';
|
||||||
|
@ -147,7 +166,7 @@ export class SendCustomEvent extends GenericEditor {
|
||||||
<div className="mx_Dialog_content">
|
<div className="mx_Dialog_content">
|
||||||
{ this.state.message }
|
{ this.state.message }
|
||||||
</div>
|
</div>
|
||||||
{ this._buttons() }
|
{ this.buttons() }
|
||||||
</div>;
|
</div>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -163,16 +182,16 @@ export class SendCustomEvent extends GenericEditor {
|
||||||
<br />
|
<br />
|
||||||
|
|
||||||
<Field id="evContent" label={_t("Event Content")} type="text" className="mx_DevTools_textarea"
|
<Field id="evContent" label={_t("Event Content")} type="text" className="mx_DevTools_textarea"
|
||||||
autoComplete="off" value={this.state.evContent} onChange={this._onChange} element="textarea" />
|
autoComplete="off" value={this.state.evContent} onChange={this.onChange} element="textarea" />
|
||||||
</div>
|
</div>
|
||||||
<div className="mx_Dialog_buttons">
|
<div className="mx_Dialogbuttons">
|
||||||
<button onClick={this.onBack}>{ _t('Back') }</button>
|
<button onClick={this.onBack}>{ _t('Back') }</button>
|
||||||
{ !this.state.message && <button onClick={this._send}>{ _t('Send') }</button> }
|
{ !this.state.message && <button onClick={this.send}>{ _t('Send') }</button> }
|
||||||
{ showTglFlip && <div style={{float: "right"}}>
|
{ showTglFlip && <div style={{float: "right"}}>
|
||||||
<input id="isStateEvent" className="mx_DevTools_tgl mx_DevTools_tgl-flip"
|
<input id="isStateEvent" className="mx_DevTools_tgl mx_DevTools_tgl-flip"
|
||||||
type="checkbox"
|
type="checkbox"
|
||||||
checked={this.state.isStateEvent}
|
checked={this.state.isStateEvent}
|
||||||
onChange={this._onChange}
|
onChange={this.onChange}
|
||||||
/>
|
/>
|
||||||
<label className="mx_DevTools_tgl-btn"
|
<label className="mx_DevTools_tgl-btn"
|
||||||
data-tg-off="Event"
|
data-tg-off="Event"
|
||||||
|
@ -185,21 +204,29 @@ export class SendCustomEvent extends GenericEditor {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class SendAccountData extends GenericEditor {
|
interface ISendAccountDataProps extends IGenericEditorProps {
|
||||||
static getLabel() { return _t('Send Account Data'); }
|
room: Room;
|
||||||
|
isRoomAccountData: boolean;
|
||||||
static propTypes = {
|
forceMode: boolean;
|
||||||
room: PropTypes.instanceOf(Room).isRequired,
|
inputs?: {
|
||||||
isRoomAccountData: PropTypes.bool,
|
eventType?: string;
|
||||||
forceMode: PropTypes.bool,
|
evContent?: string;
|
||||||
inputs: PropTypes.object,
|
|
||||||
};
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
interface ISendAccountDataState extends IGenericEditorState {
|
||||||
|
isRoomAccountData: boolean;
|
||||||
|
eventType: string;
|
||||||
|
evContent: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
class SendAccountData extends GenericEditor<ISendAccountDataProps, ISendAccountDataState> {
|
||||||
|
static getLabel() { return _t('Send Account Data'); }
|
||||||
|
|
||||||
static contextType = MatrixClientContext;
|
static contextType = MatrixClientContext;
|
||||||
|
|
||||||
constructor(props) {
|
constructor(props) {
|
||||||
super(props);
|
super(props);
|
||||||
this._send = this._send.bind(this);
|
|
||||||
|
|
||||||
const {eventType, evContent} = Object.assign({
|
const {eventType, evContent} = Object.assign({
|
||||||
eventType: '',
|
eventType: '',
|
||||||
|
@ -214,7 +241,7 @@ class SendAccountData extends GenericEditor {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
send(content) {
|
private doSend(content: object): Promise<void> {
|
||||||
const cli = this.context;
|
const cli = this.context;
|
||||||
if (this.state.isRoomAccountData) {
|
if (this.state.isRoomAccountData) {
|
||||||
return cli.setRoomAccountData(this.props.room.roomId, this.state.eventType, content);
|
return cli.setRoomAccountData(this.props.room.roomId, this.state.eventType, content);
|
||||||
|
@ -222,7 +249,7 @@ class SendAccountData extends GenericEditor {
|
||||||
return cli.setAccountData(this.state.eventType, content);
|
return cli.setAccountData(this.state.eventType, content);
|
||||||
}
|
}
|
||||||
|
|
||||||
async _send() {
|
protected send = async () => {
|
||||||
if (this.state.eventType === '') {
|
if (this.state.eventType === '') {
|
||||||
this.setState({ message: _t('You must specify an event type!') });
|
this.setState({ message: _t('You must specify an event type!') });
|
||||||
return;
|
return;
|
||||||
|
@ -231,7 +258,7 @@ class SendAccountData extends GenericEditor {
|
||||||
let message;
|
let message;
|
||||||
try {
|
try {
|
||||||
const content = JSON.parse(this.state.evContent);
|
const content = JSON.parse(this.state.evContent);
|
||||||
await this.send(content);
|
await this.doSend(content);
|
||||||
message = _t('Event sent!');
|
message = _t('Event sent!');
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
message = _t('Failed to send custom event.') + ' (' + e.toString() + ')';
|
message = _t('Failed to send custom event.') + ' (' + e.toString() + ')';
|
||||||
|
@ -245,7 +272,7 @@ class SendAccountData extends GenericEditor {
|
||||||
<div className="mx_Dialog_content">
|
<div className="mx_Dialog_content">
|
||||||
{ this.state.message }
|
{ this.state.message }
|
||||||
</div>
|
</div>
|
||||||
{ this._buttons() }
|
{ this.buttons() }
|
||||||
</div>;
|
</div>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -255,17 +282,17 @@ class SendAccountData extends GenericEditor {
|
||||||
<br />
|
<br />
|
||||||
|
|
||||||
<Field id="evContent" label={_t("Event Content")} type="text" className="mx_DevTools_textarea"
|
<Field id="evContent" label={_t("Event Content")} type="text" className="mx_DevTools_textarea"
|
||||||
autoComplete="off" value={this.state.evContent} onChange={this._onChange} element="textarea" />
|
autoComplete="off" value={this.state.evContent} onChange={this.onChange} element="textarea" />
|
||||||
</div>
|
</div>
|
||||||
<div className="mx_Dialog_buttons">
|
<div className="mx_Dialogbuttons">
|
||||||
<button onClick={this.onBack}>{ _t('Back') }</button>
|
<button onClick={this.onBack}>{ _t('Back') }</button>
|
||||||
{ !this.state.message && <button onClick={this._send}>{ _t('Send') }</button> }
|
{ !this.state.message && <button onClick={this.send}>{ _t('Send') }</button> }
|
||||||
{ !this.state.message && <div style={{float: "right"}}>
|
{ !this.state.message && <div style={{float: "right"}}>
|
||||||
<input id="isRoomAccountData" className="mx_DevTools_tgl mx_DevTools_tgl-flip"
|
<input id="isRoomAccountData" className="mx_DevTools_tgl mx_DevTools_tgl-flip"
|
||||||
type="checkbox"
|
type="checkbox"
|
||||||
checked={this.state.isRoomAccountData}
|
checked={this.state.isRoomAccountData}
|
||||||
disabled={this.props.forceMode}
|
disabled={this.props.forceMode}
|
||||||
onChange={this._onChange}
|
onChange={this.onChange}
|
||||||
/>
|
/>
|
||||||
<label className="mx_DevTools_tgl-btn"
|
<label className="mx_DevTools_tgl-btn"
|
||||||
data-tg-off="Account Data"
|
data-tg-off="Account Data"
|
||||||
|
@ -281,17 +308,22 @@ class SendAccountData extends GenericEditor {
|
||||||
const INITIAL_LOAD_TILES = 20;
|
const INITIAL_LOAD_TILES = 20;
|
||||||
const LOAD_TILES_STEP_SIZE = 50;
|
const LOAD_TILES_STEP_SIZE = 50;
|
||||||
|
|
||||||
class FilteredList extends React.PureComponent {
|
interface IFilteredListProps {
|
||||||
static propTypes = {
|
children: React.ReactElement[];
|
||||||
children: PropTypes.any,
|
query: string;
|
||||||
query: PropTypes.string,
|
onChange: (value: string) => void;
|
||||||
onChange: PropTypes.func,
|
}
|
||||||
};
|
|
||||||
|
|
||||||
static filterChildren(children, query) {
|
interface IFilteredListState {
|
||||||
|
filteredChildren: React.ReactElement[];
|
||||||
|
truncateAt: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
class FilteredList extends React.PureComponent<IFilteredListProps, IFilteredListState> {
|
||||||
|
static filterChildren(children: React.ReactElement[], query: string): React.ReactElement[] {
|
||||||
if (!query) return children;
|
if (!query) return children;
|
||||||
const lcQuery = query.toLowerCase();
|
const lcQuery = query.toLowerCase();
|
||||||
return children.filter((child) => child.key.toLowerCase().includes(lcQuery));
|
return children.filter((child) => child.key.toString().toLowerCase().includes(lcQuery));
|
||||||
}
|
}
|
||||||
|
|
||||||
constructor(props) {
|
constructor(props) {
|
||||||
|
@ -312,27 +344,27 @@ class FilteredList extends React.PureComponent {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
showAll = () => {
|
private showAll = () => {
|
||||||
this.setState({
|
this.setState({
|
||||||
truncateAt: this.state.truncateAt + LOAD_TILES_STEP_SIZE,
|
truncateAt: this.state.truncateAt + LOAD_TILES_STEP_SIZE,
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
createOverflowElement = (overflowCount: number, totalCount: number) => {
|
private createOverflowElement = (overflowCount: number, totalCount: number) => {
|
||||||
return <button className="mx_DevTools_RoomStateExplorer_button" onClick={this.showAll}>
|
return <button className="mx_DevTools_RoomStateExplorer_button" onClick={this.showAll}>
|
||||||
{ _t("and %(count)s others...", { count: overflowCount }) }
|
{ _t("and %(count)s others...", { count: overflowCount }) }
|
||||||
</button>;
|
</button>;
|
||||||
};
|
};
|
||||||
|
|
||||||
onQuery = (ev) => {
|
private onQuery = (ev: ChangeEvent<HTMLInputElement>) => {
|
||||||
if (this.props.onChange) this.props.onChange(ev.target.value);
|
if (this.props.onChange) this.props.onChange(ev.target.value);
|
||||||
};
|
};
|
||||||
|
|
||||||
getChildren = (start: number, end: number) => {
|
private getChildren = (start: number, end: number): React.ReactElement[] => {
|
||||||
return this.state.filteredChildren.slice(start, end);
|
return this.state.filteredChildren.slice(start, end);
|
||||||
};
|
};
|
||||||
|
|
||||||
getChildCount = (): number => {
|
private getChildCount = (): number => {
|
||||||
return this.state.filteredChildren.length;
|
return this.state.filteredChildren.length;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -353,28 +385,31 @@ class FilteredList extends React.PureComponent {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class RoomStateExplorer extends React.PureComponent {
|
interface IExplorerProps {
|
||||||
static getLabel() { return _t('Explore Room State'); }
|
room: Room;
|
||||||
|
onBack: () => void;
|
||||||
|
}
|
||||||
|
|
||||||
static propTypes = {
|
interface IRoomStateExplorerState {
|
||||||
onBack: PropTypes.func.isRequired,
|
eventType?: string;
|
||||||
room: PropTypes.instanceOf(Room).isRequired,
|
event?: MatrixEvent;
|
||||||
};
|
editing: boolean;
|
||||||
|
queryEventType: string;
|
||||||
|
queryStateKey: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
class RoomStateExplorer extends React.PureComponent<IExplorerProps, IRoomStateExplorerState> {
|
||||||
|
static getLabel() { return _t('Explore Room State'); }
|
||||||
|
|
||||||
static contextType = MatrixClientContext;
|
static contextType = MatrixClientContext;
|
||||||
|
|
||||||
roomStateEvents: Map<string, Map<string, MatrixEvent>>;
|
private roomStateEvents: Map<string, Map<string, MatrixEvent>>;
|
||||||
|
|
||||||
constructor(props) {
|
constructor(props) {
|
||||||
super(props);
|
super(props);
|
||||||
|
|
||||||
this.roomStateEvents = this.props.room.currentState.events;
|
this.roomStateEvents = this.props.room.currentState.events;
|
||||||
|
|
||||||
this.onBack = this.onBack.bind(this);
|
|
||||||
this.editEv = this.editEv.bind(this);
|
|
||||||
this.onQueryEventType = this.onQueryEventType.bind(this);
|
|
||||||
this.onQueryStateKey = this.onQueryStateKey.bind(this);
|
|
||||||
|
|
||||||
this.state = {
|
this.state = {
|
||||||
eventType: null,
|
eventType: null,
|
||||||
event: null,
|
event: null,
|
||||||
|
@ -385,19 +420,19 @@ class RoomStateExplorer extends React.PureComponent {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
browseEventType(eventType) {
|
private browseEventType(eventType: string) {
|
||||||
return () => {
|
return () => {
|
||||||
this.setState({ eventType });
|
this.setState({ eventType });
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
onViewSourceClick(event) {
|
private onViewSourceClick(event: MatrixEvent) {
|
||||||
return () => {
|
return () => {
|
||||||
this.setState({ event });
|
this.setState({ event });
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
onBack() {
|
private onBack = () => {
|
||||||
if (this.state.editing) {
|
if (this.state.editing) {
|
||||||
this.setState({ editing: false });
|
this.setState({ editing: false });
|
||||||
} else if (this.state.event) {
|
} else if (this.state.event) {
|
||||||
|
@ -409,15 +444,15 @@ class RoomStateExplorer extends React.PureComponent {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
editEv() {
|
private editEv = () => {
|
||||||
this.setState({ editing: true });
|
this.setState({ editing: true });
|
||||||
}
|
}
|
||||||
|
|
||||||
onQueryEventType(filterEventType) {
|
private onQueryEventType = (filterEventType: string) => {
|
||||||
this.setState({ queryEventType: filterEventType });
|
this.setState({ queryEventType: filterEventType });
|
||||||
}
|
}
|
||||||
|
|
||||||
onQueryStateKey(filterStateKey) {
|
private onQueryStateKey = (filterStateKey: string) => {
|
||||||
this.setState({ queryStateKey: filterStateKey });
|
this.setState({ queryStateKey: filterStateKey });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -437,7 +472,7 @@ class RoomStateExplorer extends React.PureComponent {
|
||||||
{ JSON.stringify(this.state.event.event, null, 2) }
|
{ JSON.stringify(this.state.event.event, null, 2) }
|
||||||
</SyntaxHighlight>
|
</SyntaxHighlight>
|
||||||
</div>
|
</div>
|
||||||
<div className="mx_Dialog_buttons">
|
<div className="mx_Dialogbuttons">
|
||||||
<button onClick={this.onBack}>{ _t('Back') }</button>
|
<button onClick={this.onBack}>{ _t('Back') }</button>
|
||||||
<button onClick={this.editEv}>{ _t('Edit') }</button>
|
<button onClick={this.editEv}>{ _t('Edit') }</button>
|
||||||
</div>
|
</div>
|
||||||
|
@ -482,31 +517,29 @@ class RoomStateExplorer extends React.PureComponent {
|
||||||
<div className="mx_Dialog_content">
|
<div className="mx_Dialog_content">
|
||||||
{ list }
|
{ list }
|
||||||
</div>
|
</div>
|
||||||
<div className="mx_Dialog_buttons">
|
<div className="mx_Dialogbuttons">
|
||||||
<button onClick={this.onBack}>{ _t('Back') }</button>
|
<button onClick={this.onBack}>{ _t('Back') }</button>
|
||||||
</div>
|
</div>
|
||||||
</div>;
|
</div>;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class AccountDataExplorer extends React.PureComponent {
|
interface IAccountDataExplorerState {
|
||||||
static getLabel() { return _t('Explore Account Data'); }
|
isRoomAccountData: boolean;
|
||||||
|
event?: MatrixEvent;
|
||||||
|
editing: boolean;
|
||||||
|
queryEventType: string;
|
||||||
|
[inputId: string]: boolean | string;
|
||||||
|
}
|
||||||
|
|
||||||
static propTypes = {
|
class AccountDataExplorer extends React.PureComponent<IExplorerProps, IAccountDataExplorerState> {
|
||||||
onBack: PropTypes.func.isRequired,
|
static getLabel() { return _t('Explore Account Data'); }
|
||||||
room: PropTypes.instanceOf(Room).isRequired,
|
|
||||||
};
|
|
||||||
|
|
||||||
static contextType = MatrixClientContext;
|
static contextType = MatrixClientContext;
|
||||||
|
|
||||||
constructor(props) {
|
constructor(props) {
|
||||||
super(props);
|
super(props);
|
||||||
|
|
||||||
this.onBack = this.onBack.bind(this);
|
|
||||||
this.editEv = this.editEv.bind(this);
|
|
||||||
this._onChange = this._onChange.bind(this);
|
|
||||||
this.onQueryEventType = this.onQueryEventType.bind(this);
|
|
||||||
|
|
||||||
this.state = {
|
this.state = {
|
||||||
isRoomAccountData: false,
|
isRoomAccountData: false,
|
||||||
event: null,
|
event: null,
|
||||||
|
@ -516,20 +549,20 @@ class AccountDataExplorer extends React.PureComponent {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
getData() {
|
private getData(): Record<string, MatrixEvent> {
|
||||||
if (this.state.isRoomAccountData) {
|
if (this.state.isRoomAccountData) {
|
||||||
return this.props.room.accountData;
|
return this.props.room.accountData;
|
||||||
}
|
}
|
||||||
return this.context.store.accountData;
|
return this.context.store.accountData;
|
||||||
}
|
}
|
||||||
|
|
||||||
onViewSourceClick(event) {
|
private onViewSourceClick(event: MatrixEvent) {
|
||||||
return () => {
|
return () => {
|
||||||
this.setState({ event });
|
this.setState({ event });
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
onBack() {
|
private onBack = () => {
|
||||||
if (this.state.editing) {
|
if (this.state.editing) {
|
||||||
this.setState({ editing: false });
|
this.setState({ editing: false });
|
||||||
} else if (this.state.event) {
|
} else if (this.state.event) {
|
||||||
|
@ -539,15 +572,15 @@ class AccountDataExplorer extends React.PureComponent {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_onChange(e) {
|
private onChange = (e: ChangeEvent<HTMLInputElement>) => {
|
||||||
this.setState({[e.target.id]: e.target.type === 'checkbox' ? e.target.checked : e.target.value});
|
this.setState({[e.target.id]: e.target.type === 'checkbox' ? e.target.checked : e.target.value});
|
||||||
}
|
}
|
||||||
|
|
||||||
editEv() {
|
private editEv = () => {
|
||||||
this.setState({ editing: true });
|
this.setState({ editing: true });
|
||||||
}
|
}
|
||||||
|
|
||||||
onQueryEventType(queryEventType) {
|
private onQueryEventType = (queryEventType: string) => {
|
||||||
this.setState({ queryEventType });
|
this.setState({ queryEventType });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -570,7 +603,7 @@ class AccountDataExplorer extends React.PureComponent {
|
||||||
{ JSON.stringify(this.state.event.event, null, 2) }
|
{ JSON.stringify(this.state.event.event, null, 2) }
|
||||||
</SyntaxHighlight>
|
</SyntaxHighlight>
|
||||||
</div>
|
</div>
|
||||||
<div className="mx_Dialog_buttons">
|
<div className="mx_Dialogbuttons">
|
||||||
<button onClick={this.onBack}>{ _t('Back') }</button>
|
<button onClick={this.onBack}>{ _t('Back') }</button>
|
||||||
<button onClick={this.editEv}>{ _t('Edit') }</button>
|
<button onClick={this.editEv}>{ _t('Edit') }</button>
|
||||||
</div>
|
</div>
|
||||||
|
@ -595,40 +628,41 @@ class AccountDataExplorer extends React.PureComponent {
|
||||||
{ rows }
|
{ rows }
|
||||||
</FilteredList>
|
</FilteredList>
|
||||||
</div>
|
</div>
|
||||||
<div className="mx_Dialog_buttons">
|
<div className="mx_Dialogbuttons">
|
||||||
<button onClick={this.onBack}>{ _t('Back') }</button>
|
<button onClick={this.onBack}>{ _t('Back') }</button>
|
||||||
{ !this.state.message && <div style={{float: "right"}}>
|
<div style={{float: "right"}}>
|
||||||
<input id="isRoomAccountData" className="mx_DevTools_tgl mx_DevTools_tgl-flip"
|
<input id="isRoomAccountData" className="mx_DevTools_tgl mx_DevTools_tgl-flip"
|
||||||
type="checkbox"
|
type="checkbox"
|
||||||
checked={this.state.isRoomAccountData}
|
checked={this.state.isRoomAccountData}
|
||||||
onChange={this._onChange}
|
onChange={this.onChange}
|
||||||
/>
|
/>
|
||||||
<label className="mx_DevTools_tgl-btn"
|
<label className="mx_DevTools_tgl-btn"
|
||||||
data-tg-off="Account Data"
|
data-tg-off="Account Data"
|
||||||
data-tg-on="Room Data"
|
data-tg-on="Room Data"
|
||||||
htmlFor="isRoomAccountData"
|
htmlFor="isRoomAccountData"
|
||||||
/>
|
/>
|
||||||
</div> }
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>;
|
</div>;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class ServersInRoomList extends React.PureComponent {
|
interface IServersInRoomListState {
|
||||||
|
query: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
class ServersInRoomList extends React.PureComponent<IExplorerProps, IServersInRoomListState> {
|
||||||
static getLabel() { return _t('View Servers in Room'); }
|
static getLabel() { return _t('View Servers in Room'); }
|
||||||
|
|
||||||
static propTypes = {
|
|
||||||
onBack: PropTypes.func.isRequired,
|
|
||||||
room: PropTypes.instanceOf(Room).isRequired,
|
|
||||||
};
|
|
||||||
|
|
||||||
static contextType = MatrixClientContext;
|
static contextType = MatrixClientContext;
|
||||||
|
|
||||||
|
private servers: React.ReactElement[];
|
||||||
|
|
||||||
constructor(props) {
|
constructor(props) {
|
||||||
super(props);
|
super(props);
|
||||||
|
|
||||||
const room = this.props.room;
|
const room = this.props.room;
|
||||||
const servers = new Set();
|
const servers: Set<string> = new Set();
|
||||||
room.currentState.getStateEvents("m.room.member").forEach(ev => servers.add(ev.getSender().split(":")[1]));
|
room.currentState.getStateEvents("m.room.member").forEach(ev => servers.add(ev.getSender().split(":")[1]));
|
||||||
this.servers = Array.from(servers).map(s =>
|
this.servers = Array.from(servers).map(s =>
|
||||||
<button key={s} className="mx_DevTools_ServersInRoomList_button">
|
<button key={s} className="mx_DevTools_ServersInRoomList_button">
|
||||||
|
@ -640,7 +674,7 @@ class ServersInRoomList extends React.PureComponent {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
onQuery = (query) => {
|
private onQuery = (query: string) => {
|
||||||
this.setState({ query });
|
this.setState({ query });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -651,7 +685,7 @@ class ServersInRoomList extends React.PureComponent {
|
||||||
{ this.servers }
|
{ this.servers }
|
||||||
</FilteredList>
|
</FilteredList>
|
||||||
</div>
|
</div>
|
||||||
<div className="mx_Dialog_buttons">
|
<div className="mx_Dialogbuttons">
|
||||||
<button onClick={this.props.onBack}>{ _t('Back') }</button>
|
<button onClick={this.props.onBack}>{ _t('Back') }</button>
|
||||||
</div>
|
</div>
|
||||||
</div>;
|
</div>;
|
||||||
|
@ -667,7 +701,10 @@ const PHASE_MAP = {
|
||||||
[PHASE_CANCELLED]: "cancelled",
|
[PHASE_CANCELLED]: "cancelled",
|
||||||
};
|
};
|
||||||
|
|
||||||
function VerificationRequest({txnId, request}) {
|
const VerificationRequest: React.FC<{
|
||||||
|
txnId: string;
|
||||||
|
request: VerificationRequest;
|
||||||
|
}> = ({txnId, request}) => {
|
||||||
const [, updateState] = useState();
|
const [, updateState] = useState();
|
||||||
const [timeout, setRequestTimeout] = useState(request.timeout);
|
const [timeout, setRequestTimeout] = useState(request.timeout);
|
||||||
|
|
||||||
|
@ -704,7 +741,7 @@ function VerificationRequest({txnId, request}) {
|
||||||
</div>);
|
</div>);
|
||||||
}
|
}
|
||||||
|
|
||||||
class VerificationExplorer extends React.Component {
|
class VerificationExplorer extends React.PureComponent<IExplorerProps> {
|
||||||
static getLabel() {
|
static getLabel() {
|
||||||
return _t("Verification Requests");
|
return _t("Verification Requests");
|
||||||
}
|
}
|
||||||
|
@ -712,7 +749,7 @@ class VerificationExplorer extends React.Component {
|
||||||
/* Ensure this.context is the cli */
|
/* Ensure this.context is the cli */
|
||||||
static contextType = MatrixClientContext;
|
static contextType = MatrixClientContext;
|
||||||
|
|
||||||
onNewRequest = () => {
|
private onNewRequest = () => {
|
||||||
this.forceUpdate();
|
this.forceUpdate();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -738,14 +775,19 @@ class VerificationExplorer extends React.Component {
|
||||||
<VerificationRequest txnId={txnId} request={request} key={txnId} />,
|
<VerificationRequest txnId={txnId} request={request} key={txnId} />,
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
<div className="mx_Dialog_buttons">
|
<div className="mx_Dialogbuttons">
|
||||||
<button onClick={this.props.onBack}>{_t("Back")}</button>
|
<button onClick={this.props.onBack}>{_t("Back")}</button>
|
||||||
</div>
|
</div>
|
||||||
</div>);
|
</div>);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class WidgetExplorer extends React.Component {
|
interface IWidgetExplorerState {
|
||||||
|
query: string;
|
||||||
|
editWidget?: IApp;
|
||||||
|
}
|
||||||
|
|
||||||
|
class WidgetExplorer extends React.Component<IExplorerProps, IWidgetExplorerState> {
|
||||||
static getLabel() {
|
static getLabel() {
|
||||||
return _t("Active Widgets");
|
return _t("Active Widgets");
|
||||||
}
|
}
|
||||||
|
@ -759,19 +801,19 @@ class WidgetExplorer extends React.Component {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
onWidgetStoreUpdate = () => {
|
private onWidgetStoreUpdate = () => {
|
||||||
this.forceUpdate();
|
this.forceUpdate();
|
||||||
};
|
};
|
||||||
|
|
||||||
onQueryChange = (query) => {
|
private onQueryChange = (query: string) => {
|
||||||
this.setState({query});
|
this.setState({query});
|
||||||
};
|
};
|
||||||
|
|
||||||
onEditWidget = (widget) => {
|
private onEditWidget = (widget: IApp) => {
|
||||||
this.setState({editWidget: widget});
|
this.setState({editWidget: widget});
|
||||||
};
|
};
|
||||||
|
|
||||||
onBack = () => {
|
private onBack = () => {
|
||||||
const widgets = WidgetStore.instance.getApps(this.props.room.roomId);
|
const widgets = WidgetStore.instance.getApps(this.props.room.roomId);
|
||||||
if (this.state.editWidget && widgets.includes(this.state.editWidget)) {
|
if (this.state.editWidget && widgets.includes(this.state.editWidget)) {
|
||||||
this.setState({editWidget: null});
|
this.setState({editWidget: null});
|
||||||
|
@ -794,13 +836,16 @@ class WidgetExplorer extends React.Component {
|
||||||
const editWidget = this.state.editWidget;
|
const editWidget = this.state.editWidget;
|
||||||
const widgets = WidgetStore.instance.getApps(room.roomId);
|
const widgets = WidgetStore.instance.getApps(room.roomId);
|
||||||
if (editWidget && widgets.includes(editWidget)) {
|
if (editWidget && widgets.includes(editWidget)) {
|
||||||
const allState = Array.from(Array.from(room.currentState.events.values()).map(e => e.values()))
|
const allState = Array.from(
|
||||||
.reduce((p, c) => {p.push(...c); return p;}, []);
|
Array.from(room.currentState.events.values()).map((e: Map<string, MatrixEvent>) => {
|
||||||
|
return e.values();
|
||||||
|
}),
|
||||||
|
).reduce((p, c) => { p.push(...c); return p; }, []);
|
||||||
const stateEv = allState.find(ev => ev.getId() === editWidget.eventId);
|
const stateEv = allState.find(ev => ev.getId() === editWidget.eventId);
|
||||||
if (!stateEv) { // "should never happen"
|
if (!stateEv) { // "should never happen"
|
||||||
return <div>
|
return <div>
|
||||||
{_t("There was an error finding this widget.")}
|
{_t("There was an error finding this widget.")}
|
||||||
<div className="mx_Dialog_buttons">
|
<div className="mx_Dialogbuttons">
|
||||||
<button onClick={this.onBack}>{_t("Back")}</button>
|
<button onClick={this.onBack}>{_t("Back")}</button>
|
||||||
</div>
|
</div>
|
||||||
</div>;
|
</div>;
|
||||||
|
@ -829,14 +874,22 @@ class WidgetExplorer extends React.Component {
|
||||||
})}
|
})}
|
||||||
</FilteredList>
|
</FilteredList>
|
||||||
</div>
|
</div>
|
||||||
<div className="mx_Dialog_buttons">
|
<div className="mx_Dialogbuttons">
|
||||||
<button onClick={this.onBack}>{_t("Back")}</button>
|
<button onClick={this.onBack}>{_t("Back")}</button>
|
||||||
</div>
|
</div>
|
||||||
</div>);
|
</div>);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class SettingsExplorer extends React.Component {
|
interface ISettingsExplorerState {
|
||||||
|
query: string;
|
||||||
|
editSetting?: string;
|
||||||
|
viewSetting?: string;
|
||||||
|
explicitValues?: string;
|
||||||
|
explicitRoomValues?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
class SettingsExplorer extends React.PureComponent<IExplorerProps, ISettingsExplorerState> {
|
||||||
static getLabel() {
|
static getLabel() {
|
||||||
return _t("Settings Explorer");
|
return _t("Settings Explorer");
|
||||||
}
|
}
|
||||||
|
@ -854,19 +907,19 @@ class SettingsExplorer extends React.Component {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
onQueryChange = (ev) => {
|
private onQueryChange = (ev: ChangeEvent<HTMLInputElement>) => {
|
||||||
this.setState({query: ev.target.value});
|
this.setState({query: ev.target.value});
|
||||||
};
|
};
|
||||||
|
|
||||||
onExplValuesEdit = (ev) => {
|
private onExplValuesEdit = (ev: ChangeEvent<HTMLTextAreaElement>) => {
|
||||||
this.setState({explicitValues: ev.target.value});
|
this.setState({explicitValues: ev.target.value});
|
||||||
};
|
};
|
||||||
|
|
||||||
onExplRoomValuesEdit = (ev) => {
|
private onExplRoomValuesEdit = (ev: ChangeEvent<HTMLTextAreaElement>) => {
|
||||||
this.setState({explicitRoomValues: ev.target.value});
|
this.setState({explicitRoomValues: ev.target.value});
|
||||||
};
|
};
|
||||||
|
|
||||||
onBack = () => {
|
private onBack = () => {
|
||||||
if (this.state.editSetting) {
|
if (this.state.editSetting) {
|
||||||
this.setState({editSetting: null});
|
this.setState({editSetting: null});
|
||||||
} else if (this.state.viewSetting) {
|
} else if (this.state.viewSetting) {
|
||||||
|
@ -876,12 +929,12 @@ class SettingsExplorer extends React.Component {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
onViewClick = (ev, settingId) => {
|
private onViewClick = (ev: MouseEvent, settingId: string) => {
|
||||||
ev.preventDefault();
|
ev.preventDefault();
|
||||||
this.setState({viewSetting: settingId});
|
this.setState({viewSetting: settingId});
|
||||||
};
|
};
|
||||||
|
|
||||||
onEditClick = (ev, settingId) => {
|
private onEditClick = (ev: MouseEvent, settingId: string) => {
|
||||||
ev.preventDefault();
|
ev.preventDefault();
|
||||||
this.setState({
|
this.setState({
|
||||||
editSetting: settingId,
|
editSetting: settingId,
|
||||||
|
@ -890,7 +943,7 @@ class SettingsExplorer extends React.Component {
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
onSaveClick = async () => {
|
private onSaveClick = async () => {
|
||||||
try {
|
try {
|
||||||
const settingId = this.state.editSetting;
|
const settingId = this.state.editSetting;
|
||||||
const parsedExplicit = JSON.parse(this.state.explicitValues);
|
const parsedExplicit = JSON.parse(this.state.explicitValues);
|
||||||
|
@ -899,7 +952,7 @@ class SettingsExplorer extends React.Component {
|
||||||
console.log(`[Devtools] Setting value of ${settingId} at ${level} from user input`);
|
console.log(`[Devtools] Setting value of ${settingId} at ${level} from user input`);
|
||||||
try {
|
try {
|
||||||
const val = parsedExplicit[level];
|
const val = parsedExplicit[level];
|
||||||
await SettingsStore.setValue(settingId, null, level, val);
|
await SettingsStore.setValue(settingId, null, level as SettingLevel, val);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.warn(e);
|
console.warn(e);
|
||||||
}
|
}
|
||||||
|
@ -909,7 +962,7 @@ class SettingsExplorer extends React.Component {
|
||||||
console.log(`[Devtools] Setting value of ${settingId} at ${level} in ${roomId} from user input`);
|
console.log(`[Devtools] Setting value of ${settingId} at ${level} in ${roomId} from user input`);
|
||||||
try {
|
try {
|
||||||
const val = parsedExplicitRoom[level];
|
const val = parsedExplicitRoom[level];
|
||||||
await SettingsStore.setValue(settingId, roomId, level, val);
|
await SettingsStore.setValue(settingId, roomId, level as SettingLevel, val);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.warn(e);
|
console.warn(e);
|
||||||
}
|
}
|
||||||
|
@ -926,7 +979,7 @@ class SettingsExplorer extends React.Component {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
renderSettingValue(val) {
|
private renderSettingValue(val: any): string {
|
||||||
// Note: we don't .toString() a string because we want JSON.stringify to inject quotes for us
|
// Note: we don't .toString() a string because we want JSON.stringify to inject quotes for us
|
||||||
const toStringTypes = ['boolean', 'number'];
|
const toStringTypes = ['boolean', 'number'];
|
||||||
if (toStringTypes.includes(typeof(val))) {
|
if (toStringTypes.includes(typeof(val))) {
|
||||||
|
@ -936,7 +989,7 @@ class SettingsExplorer extends React.Component {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
renderExplicitSettingValues(setting, roomId) {
|
private renderExplicitSettingValues(setting: string, roomId: string): string {
|
||||||
const vals = {};
|
const vals = {};
|
||||||
for (const level of LEVEL_ORDER) {
|
for (const level of LEVEL_ORDER) {
|
||||||
try {
|
try {
|
||||||
|
@ -951,7 +1004,7 @@ class SettingsExplorer extends React.Component {
|
||||||
return JSON.stringify(vals, null, 4);
|
return JSON.stringify(vals, null, 4);
|
||||||
}
|
}
|
||||||
|
|
||||||
renderCanEditLevel(roomId, level) {
|
private renderCanEditLevel(roomId: string, level: SettingLevel): React.ReactNode {
|
||||||
const canEdit = SettingsStore.canSetValue(this.state.editSetting, roomId, level);
|
const canEdit = SettingsStore.canSetValue(this.state.editSetting, roomId, level);
|
||||||
const className = canEdit ? 'mx_DevTools_SettingsExplorer_mutable' : 'mx_DevTools_SettingsExplorer_immutable';
|
const className = canEdit ? 'mx_DevTools_SettingsExplorer_mutable' : 'mx_DevTools_SettingsExplorer_immutable';
|
||||||
return <td className={className}><code>{canEdit.toString()}</code></td>;
|
return <td className={className}><code>{canEdit.toString()}</code></td>;
|
||||||
|
@ -1006,7 +1059,7 @@ class SettingsExplorer extends React.Component {
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
<div className="mx_Dialog_buttons">
|
<div className="mx_Dialogbuttons">
|
||||||
<button onClick={this.onBack}>{_t("Back")}</button>
|
<button onClick={this.onBack}>{_t("Back")}</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -1068,7 +1121,7 @@ class SettingsExplorer extends React.Component {
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
<div className="mx_Dialog_buttons">
|
<div className="mx_Dialogbuttons">
|
||||||
<button onClick={this.onSaveClick}>{_t("Save setting values")}</button>
|
<button onClick={this.onSaveClick}>{_t("Save setting values")}</button>
|
||||||
<button onClick={this.onBack}>{_t("Back")}</button>
|
<button onClick={this.onBack}>{_t("Back")}</button>
|
||||||
</div>
|
</div>
|
||||||
|
@ -1114,7 +1167,7 @@ class SettingsExplorer extends React.Component {
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
<div className="mx_Dialog_buttons">
|
<div className="mx_Dialogbuttons">
|
||||||
<button onClick={(e) => this.onEditClick(e, this.state.viewSetting)}>{
|
<button onClick={(e) => this.onEditClick(e, this.state.viewSetting)}>{
|
||||||
_t("Edit Values")
|
_t("Edit Values")
|
||||||
}</button>
|
}</button>
|
||||||
|
@ -1126,7 +1179,11 @@ class SettingsExplorer extends React.Component {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const Entries = [
|
type DevtoolsDialogEntry = React.JSXElementConstructor<any> & {
|
||||||
|
getLabel: () => string;
|
||||||
|
};
|
||||||
|
|
||||||
|
const Entries: DevtoolsDialogEntry[] = [
|
||||||
SendCustomEvent,
|
SendCustomEvent,
|
||||||
RoomStateExplorer,
|
RoomStateExplorer,
|
||||||
SendAccountData,
|
SendAccountData,
|
||||||
|
@ -1137,43 +1194,36 @@ const Entries = [
|
||||||
SettingsExplorer,
|
SettingsExplorer,
|
||||||
];
|
];
|
||||||
|
|
||||||
@replaceableComponent("views.dialogs.DevtoolsDialog")
|
interface IProps {
|
||||||
export default class DevtoolsDialog extends React.PureComponent {
|
roomId: string;
|
||||||
static propTypes = {
|
onFinished: (finished: boolean) => void;
|
||||||
roomId: PropTypes.string.isRequired,
|
}
|
||||||
onFinished: PropTypes.func.isRequired,
|
|
||||||
};
|
|
||||||
|
|
||||||
|
interface IState {
|
||||||
|
mode?: DevtoolsDialogEntry;
|
||||||
|
}
|
||||||
|
|
||||||
|
@replaceableComponent("views.dialogs.DevtoolsDialog")
|
||||||
|
export default class DevtoolsDialog extends React.PureComponent<IProps, IState> {
|
||||||
constructor(props) {
|
constructor(props) {
|
||||||
super(props);
|
super(props);
|
||||||
this.onBack = this.onBack.bind(this);
|
|
||||||
this.onCancel = this.onCancel.bind(this);
|
|
||||||
|
|
||||||
this.state = {
|
this.state = {
|
||||||
mode: null,
|
mode: null,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
componentWillUnmount() {
|
private setMode(mode: DevtoolsDialogEntry) {
|
||||||
this._unmounted = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
_setMode(mode) {
|
|
||||||
return () => {
|
return () => {
|
||||||
this.setState({ mode });
|
this.setState({ mode });
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
onBack() {
|
private onBack = () => {
|
||||||
if (this.prevMode) {
|
|
||||||
this.setState({ mode: this.prevMode });
|
|
||||||
this.prevMode = null;
|
|
||||||
} else {
|
|
||||||
this.setState({ mode: null });
|
this.setState({ mode: null });
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
onCancel() {
|
private onCancel = () => {
|
||||||
this.props.onFinished(false);
|
this.props.onFinished(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1200,12 +1250,12 @@ export default class DevtoolsDialog extends React.PureComponent {
|
||||||
<div className="mx_Dialog_content">
|
<div className="mx_Dialog_content">
|
||||||
{ Entries.map((Entry) => {
|
{ Entries.map((Entry) => {
|
||||||
const label = Entry.getLabel();
|
const label = Entry.getLabel();
|
||||||
const onClick = this._setMode(Entry);
|
const onClick = this.setMode(Entry);
|
||||||
return <button className={classes} key={label} onClick={onClick}>{ label }</button>;
|
return <button className={classes} key={label} onClick={onClick}>{ label }</button>;
|
||||||
}) }
|
}) }
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="mx_Dialog_buttons">
|
<div className="mx_Dialogbuttons">
|
||||||
<button onClick={this.onCancel}>{ _t('Cancel') }</button>
|
<button onClick={this.onCancel}>{ _t('Cancel') }</button>
|
||||||
</div>
|
</div>
|
||||||
</React.Fragment>;
|
</React.Fragment>;
|
||||||
|
|
Loading…
Reference in a new issue