aboutsummaryrefslogtreecommitdiff
path: root/frontend/src
diff options
context:
space:
mode:
authorEmiliano Ciavatta2020-10-09 15:07:24 +0000
committerEmiliano Ciavatta2020-10-09 15:07:24 +0000
commitc21541a31fe45ba3a0bafca46415247f3837713e (patch)
tree9581c6a2801556d602099a64840909a451e61ffd /frontend/src
parentd203f3c7e3bcaa20895c0f32f348cd1513ae9876 (diff)
Add MainPane
Diffstat (limited to 'frontend/src')
-rw-r--r--frontend/src/components/App.js5
-rw-r--r--frontend/src/components/Notifications.js99
-rw-r--r--frontend/src/components/Notifications.scss16
-rw-r--r--frontend/src/components/Timeline.js8
-rw-r--r--frontend/src/components/Timeline.scss4
-rw-r--r--frontend/src/components/dialogs/Filters.js7
-rw-r--r--frontend/src/components/fields/ButtonField.js4
-rw-r--r--frontend/src/components/fields/TextField.scss4
-rw-r--r--frontend/src/components/filters/FiltersDefinitions.js38
-rw-r--r--frontend/src/components/objects/Connection.js39
-rw-r--r--frontend/src/components/objects/Connection.scss4
-rw-r--r--frontend/src/components/objects/LinkPopover.scss5
-rw-r--r--frontend/src/components/pages/MainPage.js2
-rw-r--r--frontend/src/components/pages/MainPage.scss1
-rw-r--r--frontend/src/components/panels/ConnectionsPane.js12
-rw-r--r--frontend/src/components/panels/ConnectionsPane.scss5
-rw-r--r--frontend/src/components/panels/MainPane.js82
-rw-r--r--frontend/src/components/panels/MainPane.scss27
-rw-r--r--frontend/src/components/panels/StreamsPane.js5
-rw-r--r--frontend/src/components/panels/StreamsPane.scss9
-rw-r--r--frontend/src/components/panels/common.scss8
-rw-r--r--frontend/src/index.scss12
-rw-r--r--frontend/src/logo.svg8
23 files changed, 278 insertions, 126 deletions
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 {
<>
<Notifications/>
{this.state.connected ?
- (this.state.configured ? <MainPage/> :
+ (this.state.configured ? <MainPage version={this.state.version}/> :
<ConfigurationPage onConfigured={() => this.setState({configured: true})}/>) :
<ServiceUnavailablePage/>
}
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 (
<div className="notifications">
<div className="notifications-list">
{
- this.state.closedNotifications.concat(this.state.notifications).map(n =>
- <div className={classNames("notification", {"notification-closed": n.closed},
- {"notification-open": n.open})} onClick={n.onClick}>
- <h3 className="notification-title">{n.event}</h3>
- <span className="notification-description">{JSON.stringify(n.message)}</span>
- </div>
- )
+ 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 <div className={classNames(notificationClassnames)} onClick={n.onClick}>
+ <h3 className="notification-title">{n.title}</h3>
+ <pre className="notification-description">{n.description}</pre>
+ </div>;
+ })
}
</div>
</div>
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 (
<footer className="footer">
- <div className="time-line">
+ <div className={classNames("time-line", {"pulse-timeline": this.state.pulseTimeline})}>
<Resizable>
<ChartContainer timeRange={this.state.timeRange} enableDragZoom={false}
paddingTop={5} minDuration={60000}
diff --git a/frontend/src/components/Timeline.scss b/frontend/src/components/Timeline.scss
index eeb9d50..db8d9c8 100644
--- a/frontend/src/components/Timeline.scss
+++ b/frontend/src/components/Timeline.scss
@@ -13,6 +13,10 @@
top: 5px;
right: 10px;
}
+
+ &.pulse-timeline {
+ animation: pulse 2s infinite;
+ }
}
svg text {
diff --git a/frontend/src/components/dialogs/Filters.js b/frontend/src/components/dialogs/Filters.js
index 35c11df..dfd554b 100644
--- a/frontend/src/components/dialogs/Filters.js
+++ b/frontend/src/components/dialogs/Filters.js
@@ -81,7 +81,7 @@ class Filters extends Component {
</thead>
<tbody>
{this.generateRows(["service_port", "client_address", "min_duration",
- "min_bytes", "started_after", "closed_after", "marked"])}
+ "min_bytes"])}
</tbody>
</Table>
</Col>
@@ -95,14 +95,11 @@ class Filters extends Component {
</thead>
<tbody>
{this.generateRows(["matched_rules", "client_port", "max_duration",
- "max_bytes", "started_before", "closed_before", "hidden"])}
+ "max_bytes", "marked"])}
</tbody>
</Table>
</Col>
-
</Row>
-
-
</Container>
</Modal.Body>
<Modal.Footer className="dialog-footer">
diff --git a/frontend/src/components/fields/ButtonField.js b/frontend/src/components/fields/ButtonField.js
index ffcceae..193339c 100644
--- a/frontend/src/components/fields/ButtonField.js
+++ b/frontend/src/components/fields/ButtonField.js
@@ -55,8 +55,8 @@ class ButtonField extends Component {
}
return (
- <div className={classNames( "field", "button-field", {"field-small": this.props.small})}>
- <button type="button" className={classNames(classNames(buttonClassnames))}
+ <div className={classNames("field", "button-field", {"field-small": this.props.small})}>
+ <button type="button" className={classNames(buttonClassnames)}
onClick={handler} style={buttonStyle}>{this.props.name}</button>
</div>
);
diff --git a/frontend/src/components/fields/TextField.scss b/frontend/src/components/fields/TextField.scss
index c2d6ef5..5fde9e6 100644
--- a/frontend/src/components/fields/TextField.scss
+++ b/frontend/src/components/fields/TextField.scss
@@ -51,4 +51,8 @@
padding: 5px 10px;
color: $color-secondary-0;
}
+
+ &:hover::-webkit-scrollbar-thumb {
+ background: $color-secondary-2 !important;
+ }
}
diff --git a/frontend/src/components/filters/FiltersDefinitions.js b/frontend/src/components/filters/FiltersDefinitions.js
index cde3cfb..9fb3b18 100644
--- a/frontend/src/components/filters/FiltersDefinitions.js
+++ b/frontend/src/components/filters/FiltersDefinitions.js
@@ -22,8 +22,7 @@ import RulesConnectionsFilter from "./RulesConnectionsFilter";
import BooleanConnectionsFilter from "./BooleanConnectionsFilter";
export const filtersNames = ["service_port", "matched_rules", "client_address", "client_port",
- "min_duration", "max_duration", "min_bytes", "max_bytes", "started_after",
- "started_before", "closed_after", "closed_before", "marked", "hidden"];
+ "min_duration", "max_duration", "min_bytes", "max_bytes", "marked"];
export const filtersDefinitions = {
service_port: <StringConnectionsFilter filterName="service_port"
@@ -66,34 +65,9 @@ export const filtersDefinitions = {
replaceFunc={cleanNumber}
key="max_bytes_filter"
width={200}/>,
- // started_after: <StringConnectionsFilter filterName="started_after"
- // defaultFilterValue="00:00:00"
- // validateFunc={validate24HourTime}
- // encodeFunc={timeToTimestamp}
- // decodeFunc={timestampToTime}
- // key="started_after_filter"
- // width={230} />,
- // started_before: <StringConnectionsFilter filterName="started_before"
- // defaultFilterValue="00:00:00"
- // validateFunc={validate24HourTime}
- // encodeFunc={timeToTimestamp}
- // decodeFunc={timestampToTime}
- // key="started_before_filter"
- // width={230} />,
- // closed_after: <StringConnectionsFilter filterName="closed_after"
- // defaultFilterValue="00:00:00"
- // validateFunc={validate24HourTime}
- // encodeFunc={timeToTimestamp}
- // decodeFunc={timestampToTime}
- // key="closed_after_filter"
- // width={230} />,
- // closed_before: <StringConnectionsFilter filterName="closed_before"
- // defaultFilterValue="00:00:00"
- // validateFunc={validate24HourTime}
- // encodeFunc={timeToTimestamp}
- // decodeFunc={timestampToTime}
- // key="closed_before_filter"
- // width={230} />,
- marked: <BooleanConnectionsFilter filterName={"marked"}/>,
- // hidden: <BooleanConnectionsFilter filterName={"hidden"} />
+ contains_string: <StringConnectionsFilter filterName="contains_string"
+ defaultFilterValue=""
+ key="contains_string_filter"
+ width={320}/>,
+ marked: <BooleanConnectionsFilter filterName={"marked"}/>
};
diff --git a/frontend/src/components/objects/Connection.js b/frontend/src/components/objects/Connection.js
index 5e2beba..e0e942a 100644
--- a/frontend/src/components/objects/Connection.js
+++ b/frontend/src/components/objects/Connection.js
@@ -17,11 +17,12 @@
import React, {Component} from 'react';
import './Connection.scss';
-import {Form, OverlayTrigger, Popover} from "react-bootstrap";
+import {Form} from "react-bootstrap";
import backend from "../../backend";
import {dateTimeToTime, durationBetween, formatSize} from "../../utils";
import ButtonField from "../fields/ButtonField";
import LinkPopover from "./LinkPopover";
+import TextField from "../fields/TextField";
const classNames = require('classnames');
@@ -81,14 +82,6 @@ class Connection extends Component {
<span>Closed at {closedAt.toLocaleDateString() + " " + closedAt.toLocaleTimeString()}</span>
</div>;
- const popoverFor = function (name, content) {
- return <Popover id={`popover-${name}-${conn.id}`} className="connection-popover">
- <Popover.Content>
- {content}
- </Popover.Content>
- </Popover>;
- };
-
const commentPopoverContent = <div>
<span>Click to <strong>{conn.comment.length > 0 ? "edit" : "add"}</strong> comment</span>
{conn.comment && <Form.Control as="textarea" readOnly={true} rows={2} defaultValue={conn.comment}/>}
@@ -97,7 +90,7 @@ class Connection extends Component {
const copyPopoverContent = <div>
{this.state.copiedMessage ? <span><strong>Copied!</strong></span> :
<span>Click to <strong>copy</strong> the connection id</span>}
- <Form.Control as="textarea" readOnly={true} rows={1} defaultValue={conn.id} ref={this.copyTextarea}/>
+ <TextField readonly rows={1} value={conn.id} textRef={this.copyTextarea}/>
</div>;
return (
@@ -119,22 +112,16 @@ class Connection extends Component {
<td className="clickable" onClick={this.props.onSelected}>{durationBetween(startedAt, closedAt)}</td>
<td className="clickable" onClick={this.props.onSelected}>{formatSize(conn["client_bytes"])}</td>
<td className="clickable" onClick={this.props.onSelected}>{formatSize(conn["server_bytes"])}</td>
- <td>
- <OverlayTrigger trigger={["focus", "hover"]} placement="right"
- overlay={popoverFor("hide", <span>Mark this connection</span>)}>
- <span className={"connection-icon" + (conn.marked ? " icon-enabled" : "")}
- onClick={() => this.handleAction("mark")}>!!</span>
- </OverlayTrigger>
- <OverlayTrigger trigger={["focus", "hover"]} placement="right"
- overlay={popoverFor("comment", commentPopoverContent)}>
- <span className={"connection-icon" + (conn.comment ? " icon-enabled" : "")}
- onClick={() => this.handleAction("comment")}>@</span>
- </OverlayTrigger>
- <OverlayTrigger trigger={["focus", "hover"]} placement="right"
- overlay={popoverFor("copy", copyPopoverContent)}>
- <span className="connection-icon"
- onClick={() => this.handleAction("copy")}>#</span>
- </OverlayTrigger>
+ <td className="connection-actions">
+ <LinkPopover text={<span className={classNames("connection-icon", {"icon-enabled": conn.marked})}
+ onClick={() => this.handleAction("mark")}>!!</span>}
+ content={<span>Mark this connection</span>} placement="right"/>
+ <LinkPopover text={<span className={classNames("connection-icon", {"icon-enabled": conn.comment})}
+ onClick={() => this.handleAction("comment")}>@</span>}
+ content={commentPopoverContent} placement="right"/>
+ <LinkPopover text={<span className={classNames("connection-icon", {"icon-enabled": conn.hidden})}
+ onClick={() => this.handleAction("copy")}>#</span>}
+ content={copyPopoverContent} placement="right"/>
</td>
</tr>
);
diff --git a/frontend/src/components/objects/Connection.scss b/frontend/src/components/objects/Connection.scss
index 3b9f479..bf66272 100644
--- a/frontend/src/components/objects/Connection.scss
+++ b/frontend/src/components/objects/Connection.scss
@@ -46,6 +46,10 @@
.link-popover {
font-weight: 400;
}
+
+ .connection-actions .link-popover {
+ text-decoration: none;
+ }
}
.connection-popover {
diff --git a/frontend/src/components/objects/LinkPopover.scss b/frontend/src/components/objects/LinkPopover.scss
index 725224c..c81f8bb 100644
--- a/frontend/src/components/objects/LinkPopover.scss
+++ b/frontend/src/components/objects/LinkPopover.scss
@@ -5,3 +5,8 @@
cursor: pointer;
text-decoration: underline;
}
+
+.popover {
+ font-family: "Fira Code", monospace;
+ font-size: 0.75em;
+}
diff --git a/frontend/src/components/pages/MainPage.js b/frontend/src/components/pages/MainPage.js
index 7376091..4632bbd 100644
--- a/frontend/src/components/pages/MainPage.js
+++ b/frontend/src/components/pages/MainPage.js
@@ -57,7 +57,7 @@ class MainPage extends Component {
<Route path="/services" children={<ServicesPane/>}/>
<Route exact path="/connections/:id"
children={<StreamsPane connection={this.state.selectedConnection}/>}/>
- <Route children={<MainPane/>}/>
+ <Route children={<MainPane version={this.props.version}/>}/>
</Switch>
</div>
diff --git a/frontend/src/components/pages/MainPage.scss b/frontend/src/components/pages/MainPage.scss
index 3b1a689..4ca54c0 100644
--- a/frontend/src/components/pages/MainPage.scss
+++ b/frontend/src/components/pages/MainPage.scss
@@ -13,6 +13,7 @@
}
.details-pane {
+ position: relative;
flex: 1 1;
margin-left: 7.5px;
}
diff --git a/frontend/src/components/panels/ConnectionsPane.js b/frontend/src/components/panels/ConnectionsPane.js
index 038ef8f..1f79ab8 100644
--- a/frontend/src/components/panels/ConnectionsPane.js
+++ b/frontend/src/components/panels/ConnectionsPane.js
@@ -27,6 +27,8 @@ import log from "../../log";
import ButtonField from "../fields/ButtonField";
import dispatcher from "../../dispatcher";
+const classNames = require('classnames');
+
class ConnectionsPane extends Component {
state = {
@@ -81,6 +83,11 @@ class ConnectionsPane extends Component {
this.loadServices().then(() => log.debug("Services reloaded after notification update"));
}
});
+
+ dispatcher.register("pulse_connections_view", payload => {
+ this.setState({pulseConnectionsView: true});
+ setTimeout(() => this.setState({pulseConnectionsView: false}), payload.duration);
+ });
}
connectionSelected = (c, doRedirect = true) => {
@@ -246,7 +253,7 @@ class ConnectionsPane extends Component {
return (
<div className="connections-container">
{this.state.showMoreRecentButton && <div className="most-recent-button">
- <ButtonField name="most_recent" variant="green" onClick={() => {
+ <ButtonField name="most_recent" variant="green" bordered onClick={() => {
this.disableScrollHandler = true;
this.connectionsListRef.current.scrollTop = 0;
this.loadConnections({limit: this.queryLimit})
@@ -257,7 +264,8 @@ class ConnectionsPane extends Component {
}}/>
</div>}
- <div className="connections" onScroll={this.handleScroll} ref={this.connectionsListRef}>
+ <div className={classNames("connections", {"connections-pulse": this.state.pulseConnectionsView})}
+ onScroll={this.handleScroll} ref={this.connectionsListRef}>
<Table borderless size="sm">
<thead>
<tr>
diff --git a/frontend/src/components/panels/ConnectionsPane.scss b/frontend/src/components/panels/ConnectionsPane.scss
index 06f5827..59fe372 100644
--- a/frontend/src/components/panels/ConnectionsPane.scss
+++ b/frontend/src/components/panels/ConnectionsPane.scss
@@ -33,6 +33,9 @@
z-index: 20;
top: 45px;
left: calc(50% - 50px);
- background-color: red;
+ }
+
+ .connections-pulse {
+ animation: pulse 2s infinite;
}
}
diff --git a/frontend/src/components/panels/MainPane.js b/frontend/src/components/panels/MainPane.js
index 74c859c..8aa8ad8 100644
--- a/frontend/src/components/panels/MainPane.js
+++ b/frontend/src/components/panels/MainPane.js
@@ -17,17 +17,91 @@
import React, {Component} from 'react';
import './common.scss';
-import './ServicesPane.scss';
+import './MainPane.scss';
+import Typed from "typed.js";
+import dispatcher from "../../dispatcher";
+import RulesPane from "./RulesPane";
+import StreamsPane from "./StreamsPane";
+import PcapsPane from "./PcapsPane";
+import ServicesPane from "./ServicesPane";
class MainPane extends Component {
state = {};
+ componentDidMount() {
+ const nl = "^600\n^400";
+ const options = {
+ strings: [
+ `welcome to caronte!^1000 the current version is ${this.props.version}` + nl +
+ "caronte is a network analyzer,^300 it is able to read pcaps and extract connections", // 0
+ "the left panel lists all connections that have already been closed" + nl +
+ "scrolling up the list will load the most recent connections,^300 downward the oldest ones", // 1
+ "by selecting a connection you can view its content,^300 which will be shown in the right panel" + nl +
+ "you can choose the display format,^300 or decide to download the connection content", // 2
+ "below there is the timeline,^300 which shows the number of connections per minute per service" + nl +
+ "you can use the sliding window to move the time range of the connections to be displayed", // 3
+ "there are also additional metrics,^300 selectable from the drop-down menu", // 4
+ "at the top are the filters,^300 which can be used to select only certain types of connections" + nl +
+ "you can choose which filters to display in the top bar from the filters window", // 5
+ "in the pcaps panel it is possible to analyze new pcaps,^300 or to see the pcaps already analyzed" + nl +
+ "you can load pcaps from your browser,^300 or process pcaps already present on the filesystem", // 6
+ "in the rules panel you can see the rules already created,^300 or create new ones" + nl +
+ "the rules inserted will be used only to label new connections, not those already analyzed" + nl +
+ "a connection is tagged if it meets all the requirements specified by the rule", // 7
+ "in the services panel you can assign new services or edit existing ones" + nl +
+ "each service is associated with a port number,^300 and will be shown in the connection list", // 8
+ "from the configuration panel you can change the settings of the frontend application", // 9
+ "that's all! and have fun!" + nl + "created by @eciavatta" // 10
+ ],
+ typeSpeed: 40,
+ cursorChar: "_",
+ backSpeed: 5,
+ smartBackspace: false,
+ backDelay: 1500,
+ preStringTyped: (arrayPos) => {
+ switch (arrayPos) {
+ case 1:
+ return dispatcher.dispatch("pulse_connections_view", {duration: 12000});
+ case 2:
+ return this.setState({backgroundPane: <StreamsPane/>});
+ case 3:
+ this.setState({backgroundPane: null});
+ return dispatcher.dispatch("pulse_timeline", {duration: 12000});
+ case 6:
+ return this.setState({backgroundPane: <PcapsPane/>});
+ case 7:
+ return this.setState({backgroundPane: <RulesPane/>});
+ case 8:
+ return this.setState({backgroundPane: <ServicesPane/>});
+ case 10:
+ return this.setState({backgroundPane: null});
+ default:
+ return;
+ }
+ },
+ };
+ this.typed = new Typed(this.el, options);
+ }
+
+ componentWillUnmount() {
+ this.typed.destroy();
+ }
+
render() {
return (
- <div className="pane-container main-pane">
- <div className="pane-section">
- MainPane
+ <div className="pane-container">
+ <div className="main-pane">
+ <div className="pane-section">
+ <div className="tutorial">
+ <span style={{whiteSpace: 'pre'}} ref={(el) => {
+ this.el = el;
+ }}/>
+ </div>
+ </div>
+ </div>
+ <div className="background-pane">
+ {this.state.backgroundPane}
</div>
</div>
);
diff --git a/frontend/src/components/panels/MainPane.scss b/frontend/src/components/panels/MainPane.scss
index c8460f2..8f99b3c 100644
--- a/frontend/src/components/panels/MainPane.scss
+++ b/frontend/src/components/panels/MainPane.scss
@@ -1,5 +1,30 @@
@import "../../colors";
-.main-pane {
+.pane-container {
+ background-color: $color-primary-0;
+ .main-pane {
+ position: absolute;
+ z-index: 50;
+ top: 0;
+ left: 0;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ width: 100%;
+ height: 100%;
+ background-color: transparent;
+
+ .tutorial {
+ flex-basis: 100%;
+ padding: 5px 10px;
+ text-align: center;
+ background-color: $color-primary-2;
+ }
+ }
+
+ .background-pane {
+ height: 100%;
+ opacity: 0.4;
+ }
}
diff --git a/frontend/src/components/panels/StreamsPane.js b/frontend/src/components/panels/StreamsPane.js
index c8bd121..bd1964e 100644
--- a/frontend/src/components/panels/StreamsPane.js
+++ b/frontend/src/components/panels/StreamsPane.js
@@ -208,8 +208,8 @@ class StreamsPane extends Component {
);
return (
- <div className="connection-content">
- <div className="connection-content-header container-fluid">
+ <div className="pane-container stream-pane">
+ <div className="stream-pane-header container-fluid">
<Row>
<div className="header-info col">
<span><strong>flow</strong>: {conn["ip_src"]}:{conn["port_src"]} -> {conn["ip_dst"]}:{conn["port_dst"]}</span>
@@ -235,7 +235,6 @@ class StreamsPane extends Component {
</div>
);
}
-
}
diff --git a/frontend/src/components/panels/StreamsPane.scss b/frontend/src/components/panels/StreamsPane.scss
index d5510cf..1f641f3 100644
--- a/frontend/src/components/panels/StreamsPane.scss
+++ b/frontend/src/components/panels/StreamsPane.scss
@@ -1,7 +1,6 @@
@import "../../colors";
-.connection-content {
- height: 100%;
+.stream-pane {
background-color: $color-primary-0;
pre {
@@ -15,6 +14,10 @@
margin: 0;
padding: 0;
}
+
+ &:hover::-webkit-scrollbar-thumb {
+ background: $color-secondary-2;
+ }
}
.connection-message {
@@ -87,7 +90,7 @@
}
}
- .connection-content-header {
+ .stream-pane-header {
height: 33px;
padding: 0;
background-color: $color-primary-3;
diff --git a/frontend/src/components/panels/common.scss b/frontend/src/components/panels/common.scss
index 1468f35..335e65b 100644
--- a/frontend/src/components/panels/common.scss
+++ b/frontend/src/components/panels/common.scss
@@ -32,6 +32,10 @@
margin-left: 10px;
color: $color-secondary-0;
}
+
+ &:hover::-webkit-scrollbar-thumb {
+ background: $color-secondary-2;
+ }
}
table {
@@ -96,4 +100,8 @@
margin-left: 5px;
}
}
+
+ &:hover::-webkit-scrollbar-thumb {
+ background: $color-secondary-2;
+ }
}
diff --git a/frontend/src/index.scss b/frontend/src/index.scss
index 9d6afc4..ea360be 100644
--- a/frontend/src/index.scss
+++ b/frontend/src/index.scss
@@ -77,3 +77,15 @@ a {
.popover-header {
color: $color-primary-1;
}
+
+@keyframes pulse {
+ 0% {
+ opacity: 1;
+ }
+ 50% {
+ opacity: 0.3;
+ }
+ 100% {
+ opacity: 1;
+ }
+}
diff --git a/frontend/src/logo.svg b/frontend/src/logo.svg
index 6b60c10..cb825f3 100644
--- a/frontend/src/logo.svg
+++ b/frontend/src/logo.svg
@@ -1,7 +1 @@
-<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 841.9 595.3">
- <g fill="#61DAFB">
- <path d="M666.3 296.5c0-32.5-40.7-63.3-103.1-82.4 14.4-63.6 8-114.2-20.2-130.4-6.5-3.8-14.1-5.6-22.4-5.6v22.3c4.6 0 8.3.9 11.4 2.6 13.6 7.8 19.5 37.5 14.9 75.7-1.1 9.4-2.9 19.3-5.1 29.4-19.6-4.8-41-8.5-63.5-10.9-13.5-18.5-27.5-35.3-41.6-50 32.6-30.3 63.2-46.9 84-46.9V78c-27.5 0-63.5 19.6-99.9 53.6-36.4-33.8-72.4-53.2-99.9-53.2v22.3c20.7 0 51.4 16.5 84 46.6-14 14.7-28 31.4-41.3 49.9-22.6 2.4-44 6.1-63.6 11-2.3-10-4-19.7-5.2-29-4.7-38.2 1.1-67.9 14.6-75.8 3-1.8 6.9-2.6 11.5-2.6V78.5c-8.4 0-16 1.8-22.6 5.6-28.1 16.2-34.4 66.7-19.9 130.1-62.2 19.2-102.7 49.9-102.7 82.3 0 32.5 40.7 63.3 103.1 82.4-14.4 63.6-8 114.2 20.2 130.4 6.5 3.8 14.1 5.6 22.5 5.6 27.5 0 63.5-19.6 99.9-53.6 36.4 33.8 72.4 53.2 99.9 53.2 8.4 0 16-1.8 22.6-5.6 28.1-16.2 34.4-66.7 19.9-130.1 62-19.1 102.5-49.9 102.5-82.3zm-130.2-66.7c-3.7 12.9-8.3 26.2-13.5 39.5-4.1-8-8.4-16-13.1-24-4.6-8-9.5-15.8-14.4-23.4 14.2 2.1 27.9 4.7 41 7.9zm-45.8 106.5c-7.8 13.5-15.8 26.3-24.1 38.2-14.9 1.3-30 2-45.2 2-15.1 0-30.2-.7-45-1.9-8.3-11.9-16.4-24.6-24.2-38-7.6-13.1-14.5-26.4-20.8-39.8 6.2-13.4 13.2-26.8 20.7-39.9 7.8-13.5 15.8-26.3 24.1-38.2 14.9-1.3 30-2 45.2-2 15.1 0 30.2.7 45 1.9 8.3 11.9 16.4 24.6 24.2 38 7.6 13.1 14.5 26.4 20.8 39.8-6.3 13.4-13.2 26.8-20.7 39.9zm32.3-13c5.4 13.4 10 26.8 13.8 39.8-13.1 3.2-26.9 5.9-41.2 8 4.9-7.7 9.8-15.6 14.4-23.7 4.6-8 8.9-16.1 13-24.1zM421.2 430c-9.3-9.6-18.6-20.3-27.8-32 9 .4 18.2.7 27.5.7 9.4 0 18.7-.2 27.8-.7-9 11.7-18.3 22.4-27.5 32zm-74.4-58.9c-14.2-2.1-27.9-4.7-41-7.9 3.7-12.9 8.3-26.2 13.5-39.5 4.1 8 8.4 16 13.1 24 4.7 8 9.5 15.8 14.4 23.4zM420.7 163c9.3 9.6 18.6 20.3 27.8 32-9-.4-18.2-.7-27.5-.7-9.4 0-18.7.2-27.8.7 9-11.7 18.3-22.4 27.5-32zm-74 58.9c-4.9 7.7-9.8 15.6-14.4 23.7-4.6 8-8.9 16-13 24-5.4-13.4-10-26.8-13.8-39.8 13.1-3.1 26.9-5.8 41.2-7.9zm-90.5 125.2c-35.4-15.1-58.3-34.9-58.3-50.6 0-15.7 22.9-35.6 58.3-50.6 8.6-3.7 18-7 27.7-10.1 5.7 19.6 13.2 40 22.5 60.9-9.2 20.8-16.6 41.1-22.2 60.6-9.9-3.1-19.3-6.5-28-10.2zM310 490c-13.6-7.8-19.5-37.5-14.9-75.7 1.1-9.4 2.9-19.3 5.1-29.4 19.6 4.8 41 8.5 63.5 10.9 13.5 18.5 27.5 35.3 41.6 50-32.6 30.3-63.2 46.9-84 46.9-4.5-.1-8.3-1-11.3-2.7zm237.2-76.2c4.7 38.2-1.1 67.9-14.6 75.8-3 1.8-6.9 2.6-11.5 2.6-20.7 0-51.4-16.5-84-46.6 14-14.7 28-31.4 41.3-49.9 22.6-2.4 44-6.1 63.6-11 2.3 10.1 4.1 19.8 5.2 29.1zm38.5-66.7c-8.6 3.7-18 7-27.7 10.1-5.7-19.6-13.2-40-22.5-60.9 9.2-20.8 16.6-41.1 22.2-60.6 9.9 3.1 19.3 6.5 28.1 10.2 35.4 15.1 58.3 34.9 58.3 50.6-.1 15.7-23 35.6-58.4 50.6zM320.8 78.4z"/>
- <circle cx="420.9" cy="296.5" r="45.7"/>
- <path d="M520.5 78.1z"/>
- </g>
-</svg>
+<svg height="512pt" viewBox="0 0 512.0001 512" width="512pt" xmlns="http://www.w3.org/2000/svg"><path d="m99 163h140v209h-140zm0 0" fill="#5aa096"/><path d="m10 372v-40h90l40 40h292l70-30-46.113281 75.878906c-14.972657 21.382813-39.433594 34.121094-65.539063 34.121094h-300.347656c-44.183594 0-80-35.816406-80-80zm0 0" fill="#96786e"/><path d="m320.246094 466.644531-35.355469 35.355469-45.960937-45.960938c-9.765626-9.765624-9.765626-25.59375 0-35.355468 9.761718-9.761719 25.589843-9.761719 35.355468 0zm0 0" fill="#5aa096"/><path d="m232.734375 132.625c11.335937-21.507812 10.265625-41.625 10.265625-41.625 0-46.945312-28.339844-81-67-81s-70 38.054688-70 85v37.144531c-14.839844 1.582031-41.0625 10.261719-41.0625 51.855469v107s35-49.5 53.5-49.5 30.5 21.5 30.5 21.5-6-50.5 23.5-50.5c42.5625 0 14.5625 103.5 50.5 103.5 31.0625 0 25-73 25-73l23 13v-75s4.351562-42.707031-38.203125-48.375zm0 0" fill="#96786e"/><path d="m201 85c0-19.328125-11.191406-35-25-35s-25 15.671875-25 35 11.191406 35 25 35 25-15.671875 25-35zm0 0" fill="#f0e6d2"/><path d="m509.554688 335.445312c-2.851563-3.285156-7.496094-4.347656-11.492188-2.636718l-68.117188 29.191406h-180.945312v-53.214844c7.375-13.921875 9.21875-33.839844 9.4375-48.363281l7.578125 4.28125c3.097656 1.75 6.890625 1.726563 9.960937-.066406 3.070313-1.792969 4.960938-5.082031 4.960938-8.636719v-74.570312c.21875-2.851563.703125-13.9375-3.773438-25.976563-3.972656-10.691406-12.425781-23.59375-30.378906-29.789063 6.328125-17.105468 6.316406-31.453124 6.222656-34.597656-.003906-.101562-.003906-.191406-.007812-.269531-.042969-24.925781-7.605469-47.75-21.304688-64.28125-14.167968-17.097656-33.949218-26.515625-55.695312-26.515625-44.113281 0-80 42.617188-80 95v28.789062c-7.277344 1.835938-15.53125 5.320313-22.785156 11.847657-12.128906 10.910156-18.277344 27.183593-18.277344 48.363281v15.785156l-37.480469-41.941406c-3.679687-4.117188-10.003906-4.476562-14.117187-.792969-4.121094 3.679688-4.476563 10.003907-.792969 14.121094l52.390625 58.628906v61.199219c0 4.355469 2.820312 8.210938 6.972656 9.53125s8.679688-.203125 11.195313-3.757812c.074219-.105469 6.878906-9.703126 15.894531-20.199219v45.425781h-79c-5.523438 0-10 4.476562-10 10v40c0 49.625 40.375 90 90 90h140.804688c.34375.375 47.015624 47.070312 47.015624 47.070312 1.953126 1.953126 4.511719 2.929688 7.070313 2.929688s5.117187-.976562 7.070313-2.929688l35.355468-35.355468c3.171875-3.167969 3.765625-7.941406 1.789063-11.714844h61.242187c29.339844 0 56.90625-14.351562 73.730469-38.390625.121094-.175781.238281-.355469.351563-.539063l46.117187-75.878906c2.257813-3.714844 1.855469-8.460937-.992187-11.746094zm-365.410157 26.554688-35.144531-35.140625v-36.5625l64.074219 71.703125zm-35.144531-101.71875v-3.59375c6.601562-5.085938 9.394531-5.1875 9.4375-5.1875 10.222656 0 19.191406 11.84375 21.769531 16.375 2.324219 4.164062 7.265625 6.097656 11.804688 4.636719 4.535156-1.464844 7.410156-5.941407 6.859375-10.675781-1.167969-10.050782-.550782-28.765626 6.070312-36.195313 1.933594-2.171875 4.246094-3.140625 7.496094-3.140625 12.25 0 15.25 19.105469 18.148438 46.097656 1.410156 13.171875 2.746093 25.613282 6.238281 35.710938 6.195312 17.929687 17.621093 21.691406 26.113281 21.691406 2.082031 0 4.109375-.226562 6.0625-.660156v36.660156h-29.101562zm-31.703125-.695312c-.800781.894531-1.585937 1.785156-2.359375 2.671874v-78.257812c0-20.65625 7.078125-33.828125 21.0625-39.3125v18.3125c0 5.511719 4.492188 10 10 10 5.511719 0 10-4.488281 10-10v-68c0-41.355469 26.917969-75 60-75 33.027344 0 57 29.859375 57 71 0 .148438.007812.339844.011719.492188.003906.015624.007812.207031.011719.546874 0 .097657.003906.203126 0 .328126v.121093c0 .15625 0 .328125-.003907.523438v.0625c-.121093 6.808593-2.050781 34.238281-24.488281 54.847656-4.066406 3.734375-4.335938 10.0625-.597656 14.128906 1.96875 2.144531 4.664062 3.234375 7.367187 3.234375 2.414063 0 4.839844-.871094 6.761719-2.636718 6.515625-5.988282 11.652344-12.378907 15.722656-18.792969 25.035156 7.121093 23.488282 33.03125 23.203125 36.128906-.03125.335937-.050781 58.875-.050781 58.875l-8.078125-4.566406c-3.226563-1.820313-7.1875-1.710938-10.308594.285156-3.121093 1.996094-4.882812 5.554687-4.578125 9.242187 1.4375 17.550782.191406 49.21875-9.273437 59.492188-1.734375 1.882812-3.457031 2.6875-5.761719 2.6875-1.632812 0-4.367188 0-7.210938-8.226562-2.75-7.953126-3.96875-19.296876-5.257812-31.3125-1.503906-13.996094-3.058594-28.472657-7.386719-40.046876-4.296875-11.488281-10.609375-17.691406-17.082031-20.882812v-45.53125c0-5.523438-4.476562-10-10-10s-10 4.476562-10 10v43.125c-6.253906 1.257812-11.714844 4.390625-16.023438 9.242188-6.230468 7.015624-9.226562 16.765624-10.574218 25.941406-5.785156-3.898438-12.832032-6.808594-20.964844-6.808594-6.882812 0-18.636719 2.910156-41.140625 28.085938zm12.703125 182.414062c-38.597656 0-70-31.402344-70-70v-30h75.855469l20 20h-25.855469c-5.511719 0-10 4.488281-10 10s4.488281 10 10 10h100.949219l17.871093 20h-9.820312c-5.523438 0-10 4.476562-10 10s4.476562 10 10 10h26.664062c-3.273437 6.199219-4.554687 13.183594-3.847656 20zm194.890625 45.859375-38.890625-38.890625c-5.847656-5.851562-5.847656-15.367188-.003906-21.214844 5.558594-5.558594 15.46875-5.75 21.214844 0l38.890624 38.890625zm162.625-75.460937c-13.105469 18.539062-34.453125 29.601562-57.167969 29.601562h-80.605468l-20-20h29.257812c5.523438 0 10-4.476562 10-10s-4.476562-10-10-10h-83.355469l-17.875-20h214.230469c1.355469 0 2.695312-.273438 3.9375-.808594l41.296875-17.699218zm0 0"/><path d="m50 362c-5.511719 0-10 4.488281-10 10s4.488281 10 10 10 10-4.488281 10-10-4.488281-10-10-10zm0 0"/><path d="m387 402h-28c-5.523438 0-10 4.476562-10 10s4.476562 10 10 10h28c5.523438 0 10-4.476562 10-10s-4.476562-10-10-10zm0 0"/><path d="m159 402h-30c-5.523438 0-10 4.476562-10 10s4.476562 10 10 10h30c5.523438 0 10-4.476562 10-10s-4.476562-10-10-10zm0 0"/><path d="m176 130c19.625 0 35-19.765625 35-45s-15.375-45-35-45-35 19.765625-35 45 15.375 45 35 45zm0-70c7.09375 0 15 10.265625 15 25s-7.90625 25-15 25-15-10.265625-15-25 7.90625-25 15-25zm0 0"/><path d="m106 193c-5.511719 0-10 4.488281-10 10s4.488281 10 10 10 10-4.488281 10-10-4.488281-10-10-10zm0 0"/></svg> \ No newline at end of file