mirror of https://github.com/vector-im/riot-web
commit
828e9d5eb4
|
@ -0,0 +1,276 @@
|
||||||
|
/*
|
||||||
|
Copyright 2017 Michael Telatynski <7t3chguy@gmail.com>
|
||||||
|
|
||||||
|
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 sdk from 'matrix-react-sdk';
|
||||||
|
import { _t } from 'matrix-react-sdk/lib/languageHandler';
|
||||||
|
import MatrixClientPeg from 'matrix-react-sdk/lib/MatrixClientPeg';
|
||||||
|
|
||||||
|
class SendCustomEvent extends React.Component {
|
||||||
|
static propTypes = {
|
||||||
|
roomId: React.PropTypes.string.isRequired,
|
||||||
|
onBack: React.PropTypes.func.isRequired,
|
||||||
|
};
|
||||||
|
|
||||||
|
constructor(props, context) {
|
||||||
|
super(props, context);
|
||||||
|
this._send = this._send.bind(this);
|
||||||
|
this.onBack = this.onBack.bind(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
state = {
|
||||||
|
message: null,
|
||||||
|
};
|
||||||
|
|
||||||
|
onBack() {
|
||||||
|
if (this.state.message) {
|
||||||
|
this.setState({ message: null });
|
||||||
|
} else {
|
||||||
|
this.props.onBack();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_buttons() {
|
||||||
|
return <div className="mx_Dialog_buttons">
|
||||||
|
<button onClick={this.onBack}>{ _t('Back') }</button>
|
||||||
|
{!this.state.message && <button onClick={this._send}>{ _t('Send') }</button>}
|
||||||
|
</div>;
|
||||||
|
}
|
||||||
|
|
||||||
|
send(content) {
|
||||||
|
return MatrixClientPeg.get().sendEvent(this.props.roomId, this.refs.eventType.value, content);
|
||||||
|
}
|
||||||
|
|
||||||
|
async _send() {
|
||||||
|
let message;
|
||||||
|
try {
|
||||||
|
const content = JSON.parse(this.refs.evContent.value);
|
||||||
|
await this.send(content);
|
||||||
|
message = _t('Event sent!');
|
||||||
|
} catch (e) {
|
||||||
|
message = _t('Failed to send custom event.') + ' (' + e.toString() + ')';
|
||||||
|
}
|
||||||
|
this.setState({ message });
|
||||||
|
}
|
||||||
|
|
||||||
|
_additionalFields() {
|
||||||
|
return <div></div>;
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
if (this.state.message) {
|
||||||
|
return <div>
|
||||||
|
<div className="mx_Dialog_content">
|
||||||
|
{this.state.message}
|
||||||
|
</div>
|
||||||
|
{this._buttons()}
|
||||||
|
</div>;
|
||||||
|
}
|
||||||
|
|
||||||
|
return <div>
|
||||||
|
<div className="mx_Dialog_content">
|
||||||
|
{this._additionalFields()}
|
||||||
|
<div className="mx_TextInputDialog_label">
|
||||||
|
<label htmlFor="eventType"> { _t('Event Type') } </label>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<input id="eventType" ref="eventType" className="mx_TextInputDialog_input" size="64" />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="mx_TextInputDialog_label">
|
||||||
|
<label htmlFor="evContent"> { _t('Event Content') } </label>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<textarea id="evContent" ref="evContent" className="mx_TextInputDialog_input" defaultValue={"{\n\n}"} cols="63" rows="5" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{this._buttons()}
|
||||||
|
</div>;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class SendCustomStateEvent extends SendCustomEvent {
|
||||||
|
send(content) {
|
||||||
|
return MatrixClientPeg.get().sendStateEvent(this.props.roomId, this.refs.eventType.value, content,
|
||||||
|
this.refs.stateKey.value);
|
||||||
|
}
|
||||||
|
|
||||||
|
_additionalFields() {
|
||||||
|
return <div>
|
||||||
|
<div className="mx_TextInputDialog_label">
|
||||||
|
<label htmlFor="stateKey"> { _t('State Key') } </label>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<input id="stateKey" ref="stateKey" className="mx_TextInputDialog_input" size="64" />
|
||||||
|
</div>
|
||||||
|
</div>;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class RoomStateExplorer extends React.Component {
|
||||||
|
static propTypes = {
|
||||||
|
roomId: React.PropTypes.string.isRequired,
|
||||||
|
onBack: React.PropTypes.func.isRequired,
|
||||||
|
};
|
||||||
|
|
||||||
|
constructor(props, context) {
|
||||||
|
super(props, context);
|
||||||
|
|
||||||
|
const room = MatrixClientPeg.get().getRoom(this.props.roomId);
|
||||||
|
this.roomStateEvents = room.currentState.events;
|
||||||
|
|
||||||
|
this.onBack = this.onBack.bind(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
state = {
|
||||||
|
eventType: null,
|
||||||
|
event: null,
|
||||||
|
};
|
||||||
|
|
||||||
|
browseEventType(eventType) {
|
||||||
|
return () => {
|
||||||
|
this.setState({ eventType });
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
onViewSourceClick(event) {
|
||||||
|
return () => {
|
||||||
|
this.setState({ event: event.event });
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
onBack() {
|
||||||
|
if (this.state.event) {
|
||||||
|
this.setState({ event: null });
|
||||||
|
} else if (this.state.eventType) {
|
||||||
|
this.setState({ eventType: null });
|
||||||
|
} else {
|
||||||
|
this.props.onBack();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
if (this.state.event) {
|
||||||
|
return <div className="mx_ViewSource">
|
||||||
|
<div className="mx_Dialog_content">
|
||||||
|
<pre>{JSON.stringify(this.state.event, null, 2)}</pre>
|
||||||
|
</div>
|
||||||
|
<div className="mx_Dialog_buttons">
|
||||||
|
<button onClick={this.onBack}>{ _t('Back') }</button>
|
||||||
|
</div>
|
||||||
|
</div>;
|
||||||
|
}
|
||||||
|
|
||||||
|
const rows = [];
|
||||||
|
|
||||||
|
if (this.state.eventType === null) {
|
||||||
|
Object.keys(this.roomStateEvents).forEach((evType) => {
|
||||||
|
const stateGroup = this.roomStateEvents[evType];
|
||||||
|
const stateKeys = Object.keys(stateGroup);
|
||||||
|
|
||||||
|
let onClickFn;
|
||||||
|
if (stateKeys.length > 1) {
|
||||||
|
onClickFn = this.browseEventType(evType);
|
||||||
|
} else if (stateKeys.length === 1) {
|
||||||
|
onClickFn = this.onViewSourceClick(stateGroup[stateKeys[0]]);
|
||||||
|
}
|
||||||
|
|
||||||
|
rows.push(<button className="mx_DevTools_RoomStateExplorer_button" key={evType} onClick={onClickFn}>
|
||||||
|
{ evType }
|
||||||
|
</button>);
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
const evType = this.state.eventType;
|
||||||
|
const stateGroup = this.roomStateEvents[evType];
|
||||||
|
Object.keys(stateGroup).forEach((stateKey) => {
|
||||||
|
const ev = stateGroup[stateKey];
|
||||||
|
rows.push(<button className="mx_DevTools_RoomStateExplorer_button" key={stateKey}
|
||||||
|
onClick={this.onViewSourceClick(ev)}>
|
||||||
|
{ stateKey }
|
||||||
|
</button>);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return <div>
|
||||||
|
<div className="mx_Dialog_content">
|
||||||
|
{rows}
|
||||||
|
</div>
|
||||||
|
<div className="mx_Dialog_buttons">
|
||||||
|
<button onClick={this.onBack}>{ _t('Back') }</button>
|
||||||
|
</div>
|
||||||
|
</div>;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default class DevtoolsDialog extends React.Component {
|
||||||
|
static propTypes = {
|
||||||
|
roomId: React.PropTypes.string.isRequired,
|
||||||
|
onFinished: React.PropTypes.func.isRequired,
|
||||||
|
};
|
||||||
|
|
||||||
|
state = {
|
||||||
|
mode: null,
|
||||||
|
};
|
||||||
|
|
||||||
|
constructor(props, context) {
|
||||||
|
super(props, context);
|
||||||
|
this.onBack = this.onBack.bind(this);
|
||||||
|
this.onCancel = this.onCancel.bind(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
componentWillUnmount() {
|
||||||
|
this._unmounted = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
_setMode(mode) {
|
||||||
|
return () => {
|
||||||
|
this.setState({ mode });
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
onBack() {
|
||||||
|
this.setState({ mode: null });
|
||||||
|
}
|
||||||
|
|
||||||
|
onCancel() {
|
||||||
|
this.props.onFinished(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
let body;
|
||||||
|
|
||||||
|
if (this.state.mode) {
|
||||||
|
body = <this.state.mode {...this.props} onBack={this.onBack} />;
|
||||||
|
} else {
|
||||||
|
body = <div>
|
||||||
|
<div className="mx_Dialog_content">
|
||||||
|
<button onClick={this._setMode(SendCustomEvent)}>{ _t('Send Custom Event') }</button>
|
||||||
|
<button onClick={this._setMode(SendCustomStateEvent)}>{ _t('Send Custom State Event') }</button>
|
||||||
|
<button onClick={this._setMode(RoomStateExplorer)}>{ _t('Explore Room State') }</button>
|
||||||
|
</div>
|
||||||
|
<div className="mx_Dialog_buttons">
|
||||||
|
<button onClick={this.onCancel}>{ _t('Cancel') }</button>
|
||||||
|
</div>
|
||||||
|
</div>;
|
||||||
|
}
|
||||||
|
|
||||||
|
const BaseDialog = sdk.getComponent('views.dialogs.BaseDialog');
|
||||||
|
return <BaseDialog className="mx_QuestionDialog" onFinished={this.props.onFinished} title={_t('Developer Tools')}>
|
||||||
|
<div>Room ID: {this.props.roomId}</div>
|
||||||
|
{ body }
|
||||||
|
</BaseDialog>;
|
||||||
|
}
|
||||||
|
}
|
|
@ -9,6 +9,7 @@
|
||||||
"All Rooms": "All Rooms",
|
"All Rooms": "All Rooms",
|
||||||
"All notifications are currently disabled for all targets.": "All notifications are currently disabled for all targets.",
|
"All notifications are currently disabled for all targets.": "All notifications are currently disabled for all targets.",
|
||||||
"An error occurred whilst saving your email notification preferences.": "An error occurred whilst saving your email notification preferences.",
|
"An error occurred whilst saving your email notification preferences.": "An error occurred whilst saving your email notification preferences.",
|
||||||
|
"Back": "Back",
|
||||||
"Bug report sent": "Bug report sent",
|
"Bug report sent": "Bug report sent",
|
||||||
"Call invitation": "Call invitation",
|
"Call invitation": "Call invitation",
|
||||||
"Cancel": "Cancel",
|
"Cancel": "Cancel",
|
||||||
|
@ -26,6 +27,7 @@
|
||||||
"delete the alias.": "delete the alias.",
|
"delete the alias.": "delete the alias.",
|
||||||
"Delete the room alias %(alias)s and remove %(name)s from the directory?": "Delete the room alias %(alias)s and remove %(name)s from the directory?",
|
"Delete the room alias %(alias)s and remove %(name)s from the directory?": "Delete the room alias %(alias)s and remove %(name)s from the directory?",
|
||||||
"Describe your problem here.": "Describe your problem here.",
|
"Describe your problem here.": "Describe your problem here.",
|
||||||
|
"Developer Tools": "Developer Tools",
|
||||||
"Direct Chat": "Direct Chat",
|
"Direct Chat": "Direct Chat",
|
||||||
"Directory": "Directory",
|
"Directory": "Directory",
|
||||||
"Dismiss": "Dismiss",
|
"Dismiss": "Dismiss",
|
||||||
|
@ -50,6 +52,7 @@
|
||||||
"Failed to get public room list": "Failed to get public room list",
|
"Failed to get public room list": "Failed to get public room list",
|
||||||
"Failed to join the room": "Failed to join the room",
|
"Failed to join the room": "Failed to join the room",
|
||||||
"Failed to remove tag %(tagName)s from room": "Failed to remove tag %(tagName)s from room",
|
"Failed to remove tag %(tagName)s from room": "Failed to remove tag %(tagName)s from room",
|
||||||
|
"Failed to send custom event.": "Failed to send custom event.",
|
||||||
"Failed to send report: ": "Failed to send report: ",
|
"Failed to send report: ": "Failed to send report: ",
|
||||||
"Failed to set direct chat tag": "Failed to set direct chat tag",
|
"Failed to set direct chat tag": "Failed to set direct chat tag",
|
||||||
"Failed to set Direct Message status of room": "Failed to set Direct Message status of room",
|
"Failed to set Direct Message status of room": "Failed to set Direct Message status of room",
|
||||||
|
@ -117,6 +120,9 @@
|
||||||
"Search for a room": "Search for a room",
|
"Search for a room": "Search for a room",
|
||||||
"Send": "Send",
|
"Send": "Send",
|
||||||
"Send logs": "Send logs",
|
"Send logs": "Send logs",
|
||||||
|
"Send Custom Event": "Send Custom Event",
|
||||||
|
"Send Custom State Event": "Send Custom State Event",
|
||||||
|
"Explore Room State": "Explore Room State",
|
||||||
"Settings": "Settings",
|
"Settings": "Settings",
|
||||||
"Source URL": "Source URL",
|
"Source URL": "Source URL",
|
||||||
"Sorry, your browser is <b>not</b> able to run Riot.": "Sorry, your browser is <b>not</b> able to run Riot.",
|
"Sorry, your browser is <b>not</b> able to run Riot.": "Sorry, your browser is <b>not</b> able to run Riot.",
|
||||||
|
@ -164,6 +170,10 @@
|
||||||
"Warning": "Warning",
|
"Warning": "Warning",
|
||||||
"Checking for an update...": "Checking for an update...",
|
"Checking for an update...": "Checking for an update...",
|
||||||
"Error encountered (%(errorDetail)s).": "Error encountered (%(errorDetail)s).",
|
"Error encountered (%(errorDetail)s).": "Error encountered (%(errorDetail)s).",
|
||||||
|
"Event sent!": "Event sent!",
|
||||||
|
"Event Type": "Event Type",
|
||||||
|
"Event Content": "Event Content",
|
||||||
|
"State Key": "State Key",
|
||||||
"No update available.": "No update available.",
|
"No update available.": "No update available.",
|
||||||
"Downloading update...": "Downloading update...",
|
"Downloading update...": "Downloading update...",
|
||||||
"You need to be using HTTPS to place a screen-sharing call.": "You need to be using HTTPS to place a screen-sharing call.",
|
"You need to be using HTTPS to place a screen-sharing call.": "You need to be using HTTPS to place a screen-sharing call.",
|
||||||
|
|
|
@ -74,6 +74,7 @@
|
||||||
@import "./vector-web/views/context_menus/_MessageContextMenu.scss";
|
@import "./vector-web/views/context_menus/_MessageContextMenu.scss";
|
||||||
@import "./vector-web/views/context_menus/_RoomTileContextMenu.scss";
|
@import "./vector-web/views/context_menus/_RoomTileContextMenu.scss";
|
||||||
@import "./vector-web/views/dialogs/_ChangelogDialog.scss";
|
@import "./vector-web/views/dialogs/_ChangelogDialog.scss";
|
||||||
|
@import "./vector-web/views/dialogs/_DevtoolsDialog.scss";
|
||||||
@import "./vector-web/views/dialogs/_SetEmailDialog.scss";
|
@import "./vector-web/views/dialogs/_SetEmailDialog.scss";
|
||||||
@import "./vector-web/views/dialogs/_SetPasswordDialog.scss";
|
@import "./vector-web/views/dialogs/_SetPasswordDialog.scss";
|
||||||
@import "./vector-web/views/directory/_NetworkDropdown.scss";
|
@import "./vector-web/views/directory/_NetworkDropdown.scss";
|
||||||
|
|
|
@ -0,0 +1,19 @@
|
||||||
|
/*
|
||||||
|
Copyright 2017 Michael Telatynski <7t3chguy@gmail.com>
|
||||||
|
|
||||||
|
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_DevTools_RoomStateExplorer_button {
|
||||||
|
margin-bottom: 10px;
|
||||||
|
}
|
Loading…
Reference in New Issue