blob: 83fcbe825f5e193fea3d3dd056ce50cbcb348584 [file] [log] [blame]
import {css, html, LitElement} from 'lit';
import {customElement, property} from 'lit/decorators.js';
import {Device, Notifiable, SimulationInfo, simulationState,} from './device-observer.js';
import {Capture, State} from './model.js';
@customElement('ns-packet-info')
export class PacketInformation extends LitElement implements Notifiable {
/**
* List of captures currently on the netsim.
*/
@property() captureData: Capture[] = [];
/**
* List of devices currently on the netsim.
*/
@property() deviceData: Device[] = [];
static styles = css`
:host {
display: flex;
justify-content: center;
align-items: flex-start;
height: 100vh;
}
.panel {
cursor: pointer;
display: grid;
place-content: center;
color: black;
font-size: 25px;
font-family: 'Lato', sans-serif;
border: 5px solid black;
border-radius: 12px;
margin: 10px;
padding: 10px;
background-color: #ffffff;
max-width: max-content;
float: left;
}
.title {
font-weight: bold;
text-transform: uppercase;
text-align: center;
margin-bottom: 10px;
}
.label {
text-align: left;
}
.styled-table {
border-collapse: collapse;
margin: 25px 0;
font-size: 20px;
font-family: sans-serif;
width: 100%;
box-shadow: 0 0 20px rgba(0, 0, 0, 0.15);
}
.styled-table thead tr {
background-color: #009879;
color: #ffffff;
text-align: left;
}
.styled-table th,
.styled-table td {
padding: 12px 15px;
text-align: left;
}
.styled-table tbody tr {
border-bottom: 1px solid #dddddd;
}
.styled-table tbody tr:nth-of-type(even) {
background-color: #cac0c0;
}
input[type='button'] {
height: 2rem;
font-size: inherit;
}
input[type='checkbox'].switch_1 {
font-size: 30px;
-webkit-appearance: none;
-moz-appearance: none;
appearance: none;
width: 3.5em;
height: 1.5em;
background: #ddd;
border-radius: 3em;
position: relative;
cursor: pointer;
outline: none;
-webkit-transition: all 0.2s ease-in-out;
transition: all 0.2s ease-in-out;
}
input[type='checkbox'].switch_1:checked {
background: #0ebeff;
}
input[type='checkbox'].switch_1:after {
position: absolute;
content: '';
width: 1.5em;
height: 1.5em;
border-radius: 50%;
background: #fff;
-webkit-box-shadow: 0 0 0.25em rgba(0, 0, 0, 0.3);
box-shadow: 0 0 0.25em rgba(0, 0, 0, 0.3);
-webkit-transform: scale(0.7);
transform: scale(0.7);
left: 0;
-webkit-transition: all 0.2s ease-in-out;
transition: all 0.2s ease-in-out;
}
input[type='checkbox'].switch_1:checked:after {
left: calc(100% - 1.5em);
}
button {
display: inline-block;
padding: 12px 24px;
background-color: #4CAF50;
color: #FFFFFF;
font-size: 18px;
font-weight: bold;
text-align: center;
text-decoration: none;
border: none;
cursor: pointer;
transition: background-color 0.3s ease;
}
button:hover {
background-color: #45a049;
transition: 0.5s;
}
`;
connectedCallback() {
super.connectedCallback(); // eslint-disable-line
simulationState.registerObserver(this);
}
disconnectedCallback() {
simulationState.removeObserver(this);
super.disconnectedCallback(); // eslint-disable-line
}
onNotify(data: SimulationInfo) {
this.captureData = data.captures;
this.deviceData = data.devices;
this.requestUpdate();
}
toggleCapture(capture: Capture) {
let id = capture.id.toString();
let state = capture.state === State.OFF ? '1' : '2';
simulationState.patchCapture(id, state);
}
private handleGetChips(device: Device) {
let btTable = html``;
let uwbTable = html``;
let wifiTable = html``;
if ('chips' in device && device.chips) {
for (const chip of device.chips) {
if ('bt' in chip && chip.bt) {
let bleTable = html``;
let bclassicTable = html``;
if ('lowEnergy' in chip.bt && chip.bt.lowEnergy) {
bleTable = html`
<tr>
<td>BLE</td>
<td>${chip.bt.lowEnergy.rxCount ?? 0}</td>
<td>${chip.bt.lowEnergy.txCount ?? 0}</td>
</tr>
`;
}
if ('classic' in chip.bt && chip.bt.classic) {
bclassicTable = html`
<tr>
<td>Bluetooth Classic</td>
<td>${chip.bt.classic.rxCount ?? 0}</td>
<td>${chip.bt.classic.txCount ?? 0}</td>
</tr>
`;
}
btTable = html`${bleTable} ${bclassicTable}`;
}
if ('uwb' in chip && chip.uwb) {
uwbTable = html`
<tr>
<td>UWB</td>
<td>${chip.uwb.rxCount ?? 0}</td>
<td>${chip.uwb.txCount ?? 0}</td>
</tr>
`;
}
if ('wifi' in chip && chip.wifi) {
wifiTable = html`
<tr>
<td>WIFI</td>
<td>${chip.wifi.rxCount ?? 0}</td>
<td>${chip.wifi.txCount ?? 0}</td>
</tr>
`;
}
}
}
return html`
${btTable}
${uwbTable}
${wifiTable}
`;
}
private handleListCaptures(capture: Capture) {
return html`
<tr>
<td>${capture.deviceName}</td>
<td>${capture.chipKind}</td>
<td>${capture.size}</td>
<td>${capture.records}</td>
<td>
<input
type="checkbox"
class="switch_1"
.checked=${capture.state === State.ON}
@click=${() => {
this.toggleCapture(capture);
}}
/>
</td>
<td>
<a
href="./v1/captures/${capture.id}"
target="_blank"
type="application/vnd.tcpdump.pcap"
><button>Download</button></a
>
</td>
</tr>
`
}
render() {
return html`
<div class="panel">
<div class="title">Packet Info</div>
${this.deviceData.map(device => html`
<div class="label">${device.name}</div>
<table class="styled-table">
<tr>
<th>Radio</th>
<th>RX Count</th>
<th>TX Count</th>
</tr>
${this.handleGetChips(device)}
</table>
`)}
</div>
<div class="panel">
<div class="title">Packet Capture</div>
<table class="styled-table">
<tr>
<th>Device Name</th>
<th>Chip Kind</th>
<th>Bytes</th>
<th>Records</th>
<th>Capture State</th>
<th>Download Pcap</th>
</tr>
${this.captureData.map(capture => this.handleListCaptures(capture))}
</table>
</div>
`;
}
}