feat: edit button on View Source dialog

reuse component SendCustomEvent
swap it in place in the View Source dialog
the Back button takes you to the View Source dialog, not the DevTools dialog
do not display the flip toggle box for changing between State Event and Normal Event
pull/21833/head
Panagiotis 2021-03-04 23:17:29 +02:00
parent 725162ee00
commit af5cfff51d
3 changed files with 152 additions and 49 deletions

View File

@ -16,12 +16,13 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
import React from 'react';
import PropTypes from 'prop-types';
import SyntaxHighlight from '../views/elements/SyntaxHighlight';
import {_t} from "../../languageHandler";
import React from "react";
import PropTypes from "prop-types";
import SyntaxHighlight from "../views/elements/SyntaxHighlight";
import { _t } from "../../languageHandler";
import * as sdk from "../../index";
import MatrixClientContext from "../../contexts/MatrixClientContext";
import { SendCustomEvent } from "../views/dialogs/DevtoolsDialog";
export default class ViewSource extends React.Component {
static propTypes = {
@ -31,48 +32,157 @@ export default class ViewSource extends React.Component {
eventId: PropTypes.string.isRequired,
isEncrypted: PropTypes.bool.isRequired,
decryptedContent: PropTypes.object,
event: PropTypes.object.isRequired, // the MatrixEvent associated with the context menu
};
constructor(props) {
super(props);
this.state = {
editComponent: null,
};
}
onBack() {
this.setState({ editComponent: null });
}
editEvent() {
const isStateEvent = this.props.event.isState();
console.log("isStateEvent", isStateEvent);
if (isStateEvent) {
this.setState({
editComponent: (
<MatrixClientContext.Consumer>
{(cli) => (
<SendCustomEvent
room={cli.getRoom(this.props.roomId)}
forceStateEvent={true}
onBack={() => this.onBack()}
inputs={{
eventType: this.props.event.getType(),
evContent: JSON.stringify(
this.props.event.getContent(),
null,
"\t"
),
stateKey: this.props.event.getStateKey(),
}}
/>
)}
</MatrixClientContext.Consumer>
),
});
} else {
// send an edit-message event
// prefill the "m.new_content" field
const originalContent = this.props.event.getContent();
const originalEventId = this.props.eventId;
const content = {
...originalContent,
"m.new_content": originalContent,
"m.relates_to": {
rel_type: "m.replace",
event_id: originalEventId,
},
};
this.setState({
editComponent: (
<MatrixClientContext.Consumer>
{(cli) => (
<SendCustomEvent
room={cli.getRoom(this.props.roomId)}
forceStateEvent={false}
forceGeneralEvent={true}
onBack={() => this.onBack()}
inputs={{
eventType: this.props.event.getType(),
evContent: JSON.stringify(
content,
null,
"\t"
),
}}
/>
)}
</MatrixClientContext.Consumer>
),
});
}
}
render() {
const BaseDialog = sdk.getComponent('views.dialogs.BaseDialog');
const BaseDialog = sdk.getComponent("views.dialogs.BaseDialog");
let content;
if (this.props.isEncrypted) {
content = <>
<details open className="mx_ViewSource_details">
<summary>
<span className="mx_ViewSource_heading">{_t("Decrypted event source")}</span>
</summary>
<SyntaxHighlight className="json">
{ JSON.stringify(this.props.decryptedContent, null, 2) }
</SyntaxHighlight>
</details>
<details className="mx_ViewSource_details">
<summary>
<span className="mx_ViewSource_heading">{_t("Original event source")}</span>
</summary>
<SyntaxHighlight className="json">
{ JSON.stringify(this.props.content, null, 2) }
</SyntaxHighlight>
</details>
</>;
content = (
<>
<details open className="mx_ViewSource_details">
<summary>
<span className="mx_ViewSource_heading">
{_t("Decrypted event source")}
</span>
</summary>
<SyntaxHighlight className="json">
{JSON.stringify(
this.props.decryptedContent,
null,
2
)}
</SyntaxHighlight>
</details>
<details className="mx_ViewSource_details">
<summary>
<span className="mx_ViewSource_heading">
{_t("Original event source")}
</span>
</summary>
<SyntaxHighlight className="json">
{JSON.stringify(this.props.content, null, 2)}
</SyntaxHighlight>
</details>
</>
);
} else {
content = <>
<div className="mx_ViewSource_heading">{_t("Original event source")}</div>
<SyntaxHighlight className="json">
{ JSON.stringify(this.props.content, null, 2) }
</SyntaxHighlight>
</>;
content = (
<>
<div className="mx_ViewSource_heading">
{_t("Original event source")}
</div>
<SyntaxHighlight className="json">
{JSON.stringify(this.props.content, null, 2)}
</SyntaxHighlight>
</>
);
}
const isEditing = this.state.editComponent !== null;
console.log(isEditing);
return (
<BaseDialog className="mx_ViewSource" onFinished={this.props.onFinished} title={_t('View Source')}>
<div className="mx_Dialog_content">
<div className="mx_ViewSource_label_left">Room ID: { this.props.roomId }</div>
<div className="mx_ViewSource_label_left">Event ID: { this.props.eventId }</div>
<BaseDialog
className="mx_ViewSource"
onFinished={this.props.onFinished}
title={_t("View Source")}
>
<div>
<div className="mx_ViewSource_label_left">
Room ID: {this.props.roomId}
</div>
<div className="mx_ViewSource_label_left">
Event ID: {this.props.eventId}
</div>
<div className="mx_ViewSource_separator" />
{ content }
{isEditing ? this.state.editComponent : content}
</div>
{!isEditing && (
<div className="mx_Dialog_buttons">
<button onClick={() => this.editEvent()}>
{_t("Edit")}
</button>
</div>
)}
</BaseDialog>
);
}

View File

@ -130,20 +130,10 @@ export default class MessageContextMenu extends React.Component {
roomId: ev.getRoomId(),
eventId: ev.getId(),
content: ev.event,
event: ev,
isEncrypted: this.props.mxEvent.getType() !== this.props.mxEvent.getWireType(),
decryptedContent: ev._clearEvent,
}, 'mx_Dialog_viewsource');
this.closeMenu();
};
onViewClearSourceClick = () => {
const ev = this.props.mxEvent.replacingEvent() || this.props.mxEvent;
const ViewSource = sdk.getComponent('structures.ViewSource');
Modal.createTrackedDialog('View Clear Event Source', '', ViewSource, {
roomId: ev.getRoomId(),
eventId: ev.getId(),
// FIXME: _clearEvent is private
content: ev._clearEvent,
decryptedContent: ev._clearEvent,
}, 'mx_Dialog_viewsource');
this.closeMenu();
};

View File

@ -73,13 +73,14 @@ class GenericEditor extends React.PureComponent {
}
}
class SendCustomEvent extends GenericEditor {
export class SendCustomEvent extends GenericEditor {
static getLabel() { return _t('Send Custom Event'); }
static propTypes = {
onBack: PropTypes.func.isRequired,
room: PropTypes.instanceOf(Room).isRequired,
forceStateEvent: PropTypes.bool,
forceGeneralEvent: PropTypes.bool,
inputs: PropTypes.object,
};
@ -140,6 +141,8 @@ class SendCustomEvent extends GenericEditor {
</div>;
}
const showTglFlip = !this.state.message && !this.props.forceStateEvent && !this.props.forceGeneralEvent;
return <div>
<div className="mx_DevTools_content">
<div className="mx_DevTools_eventTypeStateKeyGroup">
@ -155,7 +158,7 @@ class SendCustomEvent extends GenericEditor {
<div className="mx_Dialog_buttons">
<button onClick={this.onBack}>{ _t('Back') }</button>
{ !this.state.message && <button onClick={this._send}>{ _t('Send') }</button> }
{ !this.state.message && !this.props.forceStateEvent && <div style={{float: "right"}}>
{ showTglFlip && <div style={{float: "right"}}>
<input id="isStateEvent" className="mx_DevTools_tgl mx_DevTools_tgl-flip" type="checkbox" onChange={this._onChange} checked={this.state.isStateEvent} />
<label className="mx_DevTools_tgl-btn" data-tg-off="Event" data-tg-on="State Event" htmlFor="isStateEvent" />
</div> }