From 7ecf3ef52b5f36ec9e52bf100fa958f5cb0b37b5 Mon Sep 17 00:00:00 2001 From: Emiliano Ciavatta Date: Tue, 20 Oct 2020 22:04:09 +0200 Subject: Add comment dialog --- application_router.go | 2 +- frontend/src/components/dialogs/CommentDialog.js | 70 ++++++++++++++++++++++ frontend/src/components/dialogs/CopyDialog.js | 69 +++++++++++++++++++++ frontend/src/components/objects/Connection.js | 30 +++++----- frontend/src/components/objects/MessageAction.js | 69 --------------------- frontend/src/components/objects/MessageAction.scss | 8 --- frontend/src/components/panels/ConnectionsPane.js | 2 +- frontend/src/components/panels/StreamsPane.js | 15 ++--- 8 files changed, 165 insertions(+), 100 deletions(-) create mode 100644 frontend/src/components/dialogs/CommentDialog.js create mode 100644 frontend/src/components/dialogs/CopyDialog.js delete mode 100644 frontend/src/components/objects/MessageAction.js delete mode 100644 frontend/src/components/objects/MessageAction.scss diff --git a/application_router.go b/application_router.go index 4048dc5..21758c9 100644 --- a/application_router.go +++ b/application_router.go @@ -273,7 +273,7 @@ func CreateApplicationRouter(applicationContext *ApplicationContext, result = applicationContext.ConnectionsController.SetMarked(c, id, false) case "comment": var comment struct { - Comment string `json:"comment" binding:"required"` + Comment string `json:"comment"` } if err := c.ShouldBindJSON(&comment); err != nil { badRequest(c, err) diff --git a/frontend/src/components/dialogs/CommentDialog.js b/frontend/src/components/dialogs/CommentDialog.js new file mode 100644 index 0000000..970aa83 --- /dev/null +++ b/frontend/src/components/dialogs/CommentDialog.js @@ -0,0 +1,70 @@ +/* + * This file is part of caronte (https://github.com/eciavatta/caronte). + * Copyright (c) 2020 Emiliano Ciavatta. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, version 3. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +import React, {Component} from "react"; +import {Modal} from "react-bootstrap"; +import backend from "../../backend"; +import log from "../../log"; +import ButtonField from "../fields/ButtonField"; +import TextField from "../fields/TextField"; + +class CommentDialog extends Component { + + state = {}; + + componentDidMount() { + this.setState({comment: this.props.initialComment || ""}); + } + + setComment = () => { + if (this.state.comment === this.props.initialComment) { + return this.close(); + } + const comment = this.state.comment || null; + backend.post(`/api/connections/${this.props.connectionId}/comment`, {comment}) + .then((_) => { + this.close(); + }).catch((e) => { + log.error(e); + this.setState({error: "failed to save comment"}); + }); + }; + + close = () => this.props.onSave(this.state.comment || null); + + render() { + return ( + + + + ~/.comment + + + + this.setState({comment})} + rows={7} error={this.state.error}/> + + + + + + + ); + } +} + +export default CommentDialog; diff --git a/frontend/src/components/dialogs/CopyDialog.js b/frontend/src/components/dialogs/CopyDialog.js new file mode 100644 index 0000000..069fd2e --- /dev/null +++ b/frontend/src/components/dialogs/CopyDialog.js @@ -0,0 +1,69 @@ +/* + * This file is part of caronte (https://github.com/eciavatta/caronte). + * Copyright (c) 2020 Emiliano Ciavatta. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, version 3. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +import React, {Component} from "react"; +import {Modal} from "react-bootstrap"; +import ButtonField from "../fields/ButtonField"; +import TextField from "../fields/TextField"; + +class CopyDialog extends Component { + + state = { + copyButtonText: "copy" + }; + + constructor(props) { + super(props); + this.textbox = React.createRef(); + } + + copyActionValue = () => { + this.textbox.current.select(); + document.execCommand("copy"); + this.setState({copyButtonText: "copied!"}); + this.timeoutHandle = setTimeout(() => this.setState({copyButtonText: "copy"}), 3000); + }; + + componentWillUnmount() { + if (this.timeoutHandle) { + clearTimeout(this.timeoutHandle); + } + } + + render() { + return ( + + + + {this.props.name} + + + + + + + + + + + ); + } +} + +export default CopyDialog; diff --git a/frontend/src/components/objects/Connection.js b/frontend/src/components/objects/Connection.js index b70b7f7..29c747a 100644 --- a/frontend/src/components/objects/Connection.js +++ b/frontend/src/components/objects/Connection.js @@ -16,11 +16,12 @@ */ import React, {Component} from "react"; -import {Form} from "react-bootstrap"; import backend from "../../backend"; import dispatcher from "../../dispatcher"; import {dateTimeToTime, durationBetween, formatSize} from "../../utils"; +import CommentDialog from "../dialogs/CommentDialog"; import ButtonField from "../fields/ButtonField"; +import TextField from "../fields/TextField"; import "./Connection.scss"; import CopyLinkPopover from "./CopyLinkPopover"; import LinkPopover from "./LinkPopover"; @@ -33,15 +34,7 @@ class Connection extends Component { update: false }; - handleAction = (name) => { - if (name === "hide") { - const enabled = !this.props.data.hidden; - backend.post(`/api/connections/${this.props.data.id}/${enabled ? "hide" : "show"}`) - .then((_) => { - this.props.onEnabled(!enabled); - this.setState({update: true}); - }); - } + handleAction = (name, comment) => { if (name === "mark") { const marked = this.props.data.marked; backend.post(`/api/connections/${this.props.data.id}/${marked ? "unmark" : "mark"}`) @@ -49,6 +42,9 @@ class Connection extends Component { this.props.onMarked(!marked); this.setState({update: true}); }); + } else if (name === "comment") { + this.props.onCommented(comment); + this.setState({showCommentDialog: false}); } }; @@ -70,9 +66,9 @@ class Connection extends Component { Closed at {closedAt.toLocaleDateString() + " " + closedAt.toLocaleTimeString()} ; - const commentPopoverContent =
- Click to {conn.comment.length > 0 ? "edit" : "add"} comment - {conn.comment && } + const commentPopoverContent =
+ Click to {conn.comment ? "edit" : "add"} comment + {conn.comment && }
; return ( @@ -100,10 +96,16 @@ class Connection extends Component { onClick={() => this.handleAction("mark")}>!!} content={Mark this connection} placement="right"/> this.handleAction("comment")}>@} + onClick={() => this.setState({showCommentDialog: true})}>@} content={commentPopoverContent} placement="right"/> + { + this.state.showCommentDialog && + this.handleAction("comment", comment)} + initialComment={conn.comment} connectionId={conn.id}/> + } + ); diff --git a/frontend/src/components/objects/MessageAction.js b/frontend/src/components/objects/MessageAction.js deleted file mode 100644 index e0c96e8..0000000 --- a/frontend/src/components/objects/MessageAction.js +++ /dev/null @@ -1,69 +0,0 @@ -/* - * This file is part of caronte (https://github.com/eciavatta/caronte). - * Copyright (c) 2020 Emiliano Ciavatta. - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, version 3. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -import React, {Component} from "react"; -import {Modal} from "react-bootstrap"; -import ButtonField from "../fields/ButtonField"; -import TextField from "../fields/TextField"; -import "./MessageAction.scss"; - -class MessageAction extends Component { - - constructor(props) { - super(props); - this.state = { - copyButtonText: "copy" - }; - this.actionValue = React.createRef(); - this.copyActionValue = this.copyActionValue.bind(this); - } - - copyActionValue() { - this.actionValue.current.select(); - document.execCommand("copy"); - this.setState({copyButtonText: "copied!"}); - setTimeout(() => this.setState({copyButtonText: "copy"}), 3000); - } - - render() { - return ( - - - - {this.props.actionName} - - - - - - - - - - - ); - } -} - -export default MessageAction; diff --git a/frontend/src/components/objects/MessageAction.scss b/frontend/src/components/objects/MessageAction.scss deleted file mode 100644 index 996007b..0000000 --- a/frontend/src/components/objects/MessageAction.scss +++ /dev/null @@ -1,8 +0,0 @@ -@import "../../colors"; - -.message-action-value { - font-size: 13px; - padding: 15px; - color: $color-primary-4; - background-color: $color-primary-2; -} diff --git a/frontend/src/components/panels/ConnectionsPane.js b/frontend/src/components/panels/ConnectionsPane.js index 6418b3e..708fc86 100644 --- a/frontend/src/components/panels/ConnectionsPane.js +++ b/frontend/src/components/panels/ConnectionsPane.js @@ -287,7 +287,7 @@ class ConnectionsPane extends Component { return [ this.connectionSelected(c)} selected={this.state.selected === c.id} onMarked={(marked) => c.marked = marked} - onEnabled={(enabled) => c.hidden = !enabled} + onCommented={(comment) => c.comment = comment} services={this.state.services}/>, c.matched_rules.length > 0 && ; + if (typeof json === "object") { + body = ; + } } catch (e) { log.error(e); - body = m.body; } } @@ -157,11 +158,11 @@ class StreamsPane extends Component { if (!connectionMessage.metadata["reproducers"]) { return; } - return Object.entries(connectionMessage.metadata["reproducers"]).map(([actionName, actionValue]) => - { + return Object.entries(connectionMessage.metadata["reproducers"]).map(([name, value]) => + { this.setState({ - messageActionDialog: this.setState({messageActionDialog: null})}/> + messageActionDialog: this.setState({messageActionDialog: null})}/> }); }}/> ); -- cgit v1.2.3-70-g09d2