From d203f3c7e3bcaa20895c0f32f348cd1513ae9876 Mon Sep 17 00:00:00 2001 From: Emiliano Ciavatta Date: Thu, 8 Oct 2020 22:17:04 +0200 Subject: Frontend folder structure refactor --- frontend/src/components/pages/MainPage.scss | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) create mode 100644 frontend/src/components/pages/MainPage.scss (limited to 'frontend/src/components/pages/MainPage.scss') diff --git a/frontend/src/components/pages/MainPage.scss b/frontend/src/components/pages/MainPage.scss new file mode 100644 index 0000000..3b1a689 --- /dev/null +++ b/frontend/src/components/pages/MainPage.scss @@ -0,0 +1,24 @@ +@import "../../colors"; + +.main-page { + .page-content { + display: flex; + flex: 1; + padding: 0 15px; + background-color: $color-primary-2; + + .connections-pane { + flex: 1 0; + margin-right: 7.5px; + } + + .details-pane { + flex: 1 1; + margin-left: 7.5px; + } + } + + .page-footer { + flex: 0; + } +} -- cgit v1.2.3-70-g09d2 From c21541a31fe45ba3a0bafca46415247f3837713e Mon Sep 17 00:00:00 2001 From: Emiliano Ciavatta Date: Fri, 9 Oct 2020 17:07:24 +0200 Subject: Add MainPane --- Dockerfile | 5 +- VERSION | 1 - application_router.go | 16 ++-- caronte.go | 11 ++- frontend/public/favicon.ico | Bin 34239 -> 12163 bytes frontend/public/logo192.png | Bin 34239 -> 6498 bytes frontend/public/logo512.png | Bin 34239 -> 26806 bytes frontend/src/components/App.js | 5 +- frontend/src/components/Notifications.js | 99 ++++++++++++++------- frontend/src/components/Notifications.scss | 16 +++- frontend/src/components/Timeline.js | 8 +- frontend/src/components/Timeline.scss | 4 + frontend/src/components/dialogs/Filters.js | 7 +- frontend/src/components/fields/ButtonField.js | 4 +- frontend/src/components/fields/TextField.scss | 4 + .../src/components/filters/FiltersDefinitions.js | 38 ++------ frontend/src/components/objects/Connection.js | 39 +++----- frontend/src/components/objects/Connection.scss | 4 + frontend/src/components/objects/LinkPopover.scss | 5 ++ frontend/src/components/pages/MainPage.js | 2 +- frontend/src/components/pages/MainPage.scss | 1 + frontend/src/components/panels/ConnectionsPane.js | 12 ++- .../src/components/panels/ConnectionsPane.scss | 5 +- frontend/src/components/panels/MainPane.js | 82 ++++++++++++++++- frontend/src/components/panels/MainPane.scss | 27 +++++- frontend/src/components/panels/StreamsPane.js | 5 +- frontend/src/components/panels/StreamsPane.scss | 9 +- frontend/src/components/panels/common.scss | 8 ++ frontend/src/index.scss | 12 +++ frontend/src/logo.svg | 8 +- notification_controller.go | 8 +- resources_controller.go | 2 +- 32 files changed, 297 insertions(+), 150 deletions(-) delete mode 100644 VERSION (limited to 'frontend/src/components/pages/MainPage.scss') diff --git a/Dockerfile b/Dockerfile index cf7730b..a9c8134 100644 --- a/Dockerfile +++ b/Dockerfile @@ -3,15 +3,16 @@ FROM ubuntu:20.04 AS BUILDSTAGE # Install tools and libraries RUN apt-get update && \ - DEBIAN_FRONTEND=noninteractive apt-get install -qq golang-1.14 pkg-config libpcap-dev libhyperscan-dev yarnpkg + DEBIAN_FRONTEND=noninteractive apt-get install -qq git golang-1.14 pkg-config libpcap-dev libhyperscan-dev yarnpkg COPY . /caronte WORKDIR /caronte RUN ln -sf ../lib/go-1.14/bin/go /usr/bin/go && \ + export VERSION=$(git describe --tags) && \ go mod download && \ - go build && \ + go build -ldflags "-X main.Version=$VERSION" && \ cd frontend && \ yarnpkg install && \ yarnpkg build --production=true && \ diff --git a/VERSION b/VERSION deleted file mode 100644 index bc1f22f..0000000 --- a/VERSION +++ /dev/null @@ -1 +0,0 @@ -v0.20.10 \ No newline at end of file diff --git a/application_router.go b/application_router.go index 9fd7e3d..89b471b 100644 --- a/application_router.go +++ b/application_router.go @@ -65,7 +65,7 @@ func CreateApplicationRouter(applicationContext *ApplicationContext, applicationContext.SetAccounts(settings.Accounts) c.JSON(http.StatusAccepted, gin.H{}) - notificationController.Notify("setup", InsertNotification, gin.H{}) + notificationController.Notify("setup", gin.H{}) }) router.GET("/ws", func(c *gin.Context) { @@ -95,7 +95,7 @@ func CreateApplicationRouter(applicationContext *ApplicationContext, } else { response := UnorderedDocument{"id": id} success(c, response) - notificationController.Notify("rules.new", InsertNotification, response) + notificationController.Notify("rules.new", response) } }) @@ -134,7 +134,7 @@ func CreateApplicationRouter(applicationContext *ApplicationContext, notFound(c, UnorderedDocument{"id": id}) } else { success(c, rule) - notificationController.Notify("rules.edit", UpdateNotification, rule) + notificationController.Notify("rules.edit", rule) } }) @@ -156,7 +156,7 @@ func CreateApplicationRouter(applicationContext *ApplicationContext, } else { response := gin.H{"session": sessionID} c.JSON(http.StatusAccepted, response) - notificationController.Notify("pcap.upload", InsertNotification, response) + notificationController.Notify("pcap.upload", response) } }) @@ -190,7 +190,7 @@ func CreateApplicationRouter(applicationContext *ApplicationContext, } else { response := gin.H{"session": sessionID} c.JSON(http.StatusAccepted, response) - notificationController.Notify("pcap.file", InsertNotification, response) + notificationController.Notify("pcap.file", response) } }) @@ -227,7 +227,7 @@ func CreateApplicationRouter(applicationContext *ApplicationContext, session := gin.H{"session": sessionID} if cancelled := applicationContext.PcapImporter.CancelSession(sessionID); cancelled { c.JSON(http.StatusAccepted, session) - notificationController.Notify("sessions.delete", DeleteNotification, session) + notificationController.Notify("sessions.delete", session) } else { notFound(c, session) } @@ -288,7 +288,7 @@ func CreateApplicationRouter(applicationContext *ApplicationContext, if result { response := gin.H{"connection_id": c.Param("id"), "action": c.Param("action")} success(c, response) - notificationController.Notify("connections.action", UpdateNotification, response) + notificationController.Notify("connections.action", response) } else { notFound(c, gin.H{"connection": id}) } @@ -344,7 +344,7 @@ func CreateApplicationRouter(applicationContext *ApplicationContext, } if err := applicationContext.ServicesController.SetService(c, service); err == nil { success(c, service) - notificationController.Notify("services.edit", UpdateNotification, service) + notificationController.Notify("services.edit", service) } else { unprocessableEntity(c, err) } diff --git a/caronte.go b/caronte.go index d4265bc..2d24af6 100644 --- a/caronte.go +++ b/caronte.go @@ -21,9 +21,10 @@ import ( "flag" "fmt" log "github.com/sirupsen/logrus" - "io/ioutil" ) +var Version string + func main() { mongoHost := flag.String("mongo-host", "localhost", "address of MongoDB") mongoPort := flag.Int("mongo-port", 27017, "port of MongoDB") @@ -40,12 +41,10 @@ func main() { log.WithError(err).WithFields(logFields).Fatal("failed to connect to MongoDB") } - versionBytes, err := ioutil.ReadFile("VERSION") - if err != nil { - log.WithError(err).Fatal("failed to load version file") + if Version == "" { + Version = "undefined" } - - applicationContext, err := CreateApplicationContext(storage, string(versionBytes)) + applicationContext, err := CreateApplicationContext(storage, Version) if err != nil { log.WithError(err).WithFields(logFields).Fatal("failed to create application context") } diff --git a/frontend/public/favicon.ico b/frontend/public/favicon.ico index 1dc499d..be9cec8 100644 Binary files a/frontend/public/favicon.ico and b/frontend/public/favicon.ico differ diff --git a/frontend/public/logo192.png b/frontend/public/logo192.png index 1dc499d..1969e1d 100644 Binary files a/frontend/public/logo192.png and b/frontend/public/logo192.png differ diff --git a/frontend/public/logo512.png b/frontend/public/logo512.png index 1dc499d..3afb127 100644 Binary files a/frontend/public/logo512.png and b/frontend/public/logo512.png differ diff --git a/frontend/src/components/App.js b/frontend/src/components/App.js index bf959c5..0f700db 100644 --- a/frontend/src/components/App.js +++ b/frontend/src/components/App.js @@ -31,7 +31,8 @@ class App extends Component { if (payload.event === "connected") { this.setState({ connected: true, - configured: payload.message["is_configured"] + configured: payload.message["is_configured"], + version: payload.message["version"] }); } }); @@ -50,7 +51,7 @@ class App extends Component { <> {this.state.connected ? - (this.state.configured ? : + (this.state.configured ? : this.setState({configured: true})}/>) : } diff --git a/frontend/src/components/Notifications.js b/frontend/src/components/Notifications.js index 1017a42..ad681a2 100644 --- a/frontend/src/components/Notifications.js +++ b/frontend/src/components/Notifications.js @@ -30,49 +30,84 @@ class Notifications extends Component { }; componentDidMount() { - dispatcher.register("notifications", notification => { + dispatcher.register("notifications", n => this.notificationHandler(n)); + } + + notificationHandler = (n) => { + switch (n.event) { + case "connected": + n.title = "connected"; + n.description = `number of active clients: ${n.message["connected_clients"]}`; + return this.pushNotification(n); + case "services.edit": + n.title = "services updated"; + n.description = `updated "${n.message["name"]}" on port ${n.message["port"]}`; + n.variant = "blue"; + return this.pushNotification(n); + case "rules.new": + n.title = "rules updated"; + n.description = `new rule added: ${n.message["name"]}`; + n.variant = "green"; + return this.pushNotification(n); + case "rules.edit": + n.title = "rules updated"; + n.description = `existing rule updated: ${n.message["name"]}`; + n.variant = "blue"; + return this.pushNotification(n); + default: + return; + } + }; + + pushNotification = (notification) => { + const notifications = this.state.notifications; + notifications.push(notification); + this.setState({notifications}); + setTimeout(() => { const notifications = this.state.notifications; - notifications.push(notification); + notification.open = true; this.setState({notifications}); - setTimeout(() => { - const notifications = this.state.notifications; - notification.open = true; - this.setState({notifications}); - }, 100); + }, 100); - const hideHandle = setTimeout(() => { - const notifications = _.without(this.state.notifications, notification); - const closedNotifications = this.state.closedNotifications.concat([notification]); - notification.closed = true; - this.setState({notifications, closedNotifications}); - }, 5000); + const hideHandle = setTimeout(() => { + const notifications = _.without(this.state.notifications, notification); + const closedNotifications = this.state.closedNotifications.concat([notification]); + notification.closed = true; + this.setState({notifications, closedNotifications}); + }, 5000); - const removeHandle = setTimeout(() => { - const closedNotifications = _.without(this.state.closedNotifications, notification); - this.setState({closedNotifications}); - }, 6000); + const removeHandle = setTimeout(() => { + const closedNotifications = _.without(this.state.closedNotifications, notification); + this.setState({closedNotifications}); + }, 6000); - notification.onClick = () => { - clearTimeout(hideHandle); - clearTimeout(removeHandle); - const notifications = _.without(this.state.notifications, notification); - this.setState({notifications}); - }; - }); - } + notification.onClick = () => { + clearTimeout(hideHandle); + clearTimeout(removeHandle); + const notifications = _.without(this.state.notifications, notification); + this.setState({notifications}); + }; + }; render() { return (
{ - this.state.closedNotifications.concat(this.state.notifications).map(n => -
-

{n.event}

- {JSON.stringify(n.message)} -
- ) + this.state.closedNotifications.concat(this.state.notifications).map(n => { + const notificationClassnames = { + "notification": true, + "notification-closed": n.closed, + "notification-open": n.open + }; + if (n.variant) { + notificationClassnames[`notification-${n.variant}`] = true; + } + return
+

{n.title}

+
{n.description}
+
; + }) }
diff --git a/frontend/src/components/Notifications.scss b/frontend/src/components/Notifications.scss index 324d0bb..98d228e 100644 --- a/frontend/src/components/Notifications.scss +++ b/frontend/src/components/Notifications.scss @@ -7,18 +7,15 @@ left: 30px; .notification { - overflow: hidden; width: 250px; margin: 10px 0; padding: 10px; + cursor: pointer; transition: all 1s ease; transform: translateX(-300px); - white-space: nowrap; - text-overflow: ellipsis; color: $color-green-light; border-left: 5px solid $color-green-dark; background-color: $color-green; - cursor: pointer; .notification-title { font-size: 0.9em; @@ -27,6 +24,11 @@ .notification-description { font-size: 0.8em; + overflow: hidden; + margin: 10px 0; + white-space: nowrap; + text-overflow: ellipsis; + color: $color-primary-4; } &.notification-open { @@ -37,5 +39,11 @@ transform: translateY(-50px); opacity: 0; } + + &.notification-blue { + color: $color-blue-light; + border-left: 5px solid $color-blue-dark; + background-color: $color-blue; + } } } diff --git a/frontend/src/components/Timeline.js b/frontend/src/components/Timeline.js index 7be42e0..615203f 100644 --- a/frontend/src/components/Timeline.js +++ b/frontend/src/components/Timeline.js @@ -35,6 +35,7 @@ import log from "../log"; import dispatcher from "../dispatcher"; const minutes = 60 * 1000; +const classNames = require('classnames'); class Timeline extends Component { @@ -70,6 +71,11 @@ class Timeline extends Component { this.loadServices().then(() => log.debug("Services reloaded after notification update")); } }); + + dispatcher.register("pulse_timeline", payload => { + this.setState({pulseTimeline: true}); + setTimeout(() => this.setState({pulseTimeline: false}), payload.duration); + }); } componentDidUpdate(prevProps, prevState, snapshot) { @@ -183,7 +189,7 @@ class Timeline extends Component { return (