aboutsummaryrefslogtreecommitdiff
path: root/frontend/src/components
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/components
parentd203f3c7e3bcaa20895c0f32f348cd1513ae9876 (diff)
Add MainPane
Diffstat (limited to 'frontend/src/components')
-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
21 files changed, 265 insertions, 119 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;
+ }
}