Adds a network interface widget

This commit is contained in:
Alicia Sykes 2022-01-18 19:11:03 +00:00
parent 6b8a5ee086
commit 6d9e34c90f
3 changed files with 183 additions and 1 deletions

View File

@ -52,6 +52,7 @@ Dashy has support for displaying dynamic content in the form of widgets. There a
- [Disk IO](#disk-io)
- [System Load](#system-load)
- [System Load History](#system-load-history)
- [Network Interfaces](#network-interfaces)
- [Resource Usage Alerts](#resource-usage-alerts)
- **[Dynamic Widgets](#dynamic-widgets)**
- [Iframe Widget](#iframe-widget)
@ -1355,11 +1356,27 @@ Shows recent historical system load, calculated from the number of processes wai
---
### Network Interfaces
Lists visible network interfaces, including real-time upload/ download stats
<p align="center"><img width="400" src="https://i.ibb.co/FnhgHfG/gl-network-interfaces.png" /></p>
##### Example
```yaml
- type: gl-network-interfaces
options:
hostname: http://192.168.130.2:61208
```
---
### Resource Usage Alerts
Lists recent high resource usage alerts (e.g. CPU, mem, IO, load, temp)
<p align="center"><img width="500" src="https://i.ibb.co/w01NX5R/gl-alerts.png" /></p>
<p align="center"><img width="400" src="https://i.ibb.co/w01NX5R/gl-alerts.png" /></p>
##### Example

View File

@ -0,0 +1,157 @@
<template>
<div class="glances-network-interfaces-wrapper" v-if="networks">
<div class="interface-row" v-for="network in networks" :key="network.name">
<div class="network-info">
<p class="network-name">{{ network.name }}</p>
<p class="network-speed">{{ network.speed | formatSpeed }}</p>
<p :class="`network-online ${network.online}`">
{{ network.online }}
</p>
</div>
<div class="current" v-if="network.online === 'up'">
<span class="upload">
<span class="val">{{ network.currentUpload | formatDataSize }}</span>
</span>
<span class="separator">|</span>
<span class="download">
<span class="val">{{ network.currentDownload | formatDataSize }}</span>
</span>
</div>
<div class="total">
<b class="lbl">Total</b> Up
<span class="val">{{ network.totalUpload | formatDataSize }}</span>
<span class="separator">|</span>
Down
<span class="val">{{ network.totalDownload | formatDataSize }}</span>
</div>
</div>
</div>
</template>
<script>
import WidgetMixin from '@/mixins/WidgetMixin';
import { convertBytes } from '@/utils/MiscHelpers';
export default {
mixins: [WidgetMixin],
data() {
return {
networks: null,
previous: null,
};
},
computed: {
hostname() {
if (!this.options.hostname) this.error('You must specify a \'hostname\' for Glaces');
return this.options.hostname;
},
endpoint() {
return `${this.hostname}/api/3/network`;
},
},
filters: {
formatDataSize(data) {
return convertBytes(data);
},
formatSpeed(byteValue) {
if (!byteValue) return '';
return `${convertBytes(byteValue)}/s`;
},
getArrow(direction) {
if (direction === 'up') return '↑';
if (direction === 'down') return '↓';
return '';
},
},
methods: {
fetchData() {
this.makeRequest(this.endpoint).then(this.processData);
},
processData(networkData) {
this.previous = this.disks;
const networks = [];
networkData.forEach((network, index) => {
networks.push({
name: network.interface_name,
speed: network.speed,
online: network.is_up ? 'up' : 'down',
currentDownload: network.rx,
currentUpload: network.tx,
totalDownload: network.cumulative_rx,
totalUpload: network.cumulative_tx,
changeDownload: this.previous && network.rx > this.previous[index].rx,
changeUpload: this.previous && network.tx > this.previous[index].tx,
});
});
this.networks = networks;
},
},
created() {
this.overrideUpdateInterval = 5;
},
};
</script>
<style scoped lang="scss">
.glances-network-interfaces-wrapper {
color: var(--widget-text-color);
.interface-row {
display: flex;
flex-direction: column;
padding: 0.5rem 0;
.network-info {
display: flex;
justify-content: space-between;
.network-name {
width: 50%;
margin: 0.5rem 0;
overflow: hidden;
font-weight: bold;
white-space: nowrap;
text-overflow: ellipsis;
}
.network-speed {
font-family: var(--font-monospace);
margin: 0.5rem 0;
}
.network-online {
min-width: 15%;
margin: 0.5rem 0;
font-weight: bold;
text-align: right;
text-transform: capitalize;
&.up { color: var(--success); }
&.down { color: var(--danger); }
}
}
.total, .current {
display: inline;
margin: 0.25rem 0;
b.lbl {
margin-right: 0.25rem;
}
span.val {
margin-left: 0.25rem;
font-family: var(--font-monospace);
}
span.separator {
font-weight: bold;
margin: 0 0.5rem;
}
&.total {
opacity: var(--dimming-factor);
font-size: 0.85rem;
}
&.current {
text-align: center;
background: var(--widget-accent-color);
border-radius: var(--curve-factor);
padding: 0.2rem 0.5rem;
}
}
&:not(:last-child) {
border-bottom: 1px dashed var(--widget-text-color);
}
}
}
</style>

View File

@ -172,6 +172,13 @@
@error="handleError"
:ref="widgetRef"
/>
<GlNetworkInterfaces
v-else-if="widgetType === 'gl-network-interfaces'"
:options="widgetOptions"
@loading="setLoaderState"
@error="handleError"
:ref="widgetRef"
/>
<GlSystemLoad
v-else-if="widgetType === 'gl-system-load'"
:options="widgetOptions"
@ -378,6 +385,7 @@ export default {
GlLoadHistory: () => import('@/components/Widgets/GlLoadHistory.vue'),
GlMemGauge: () => import('@/components/Widgets/GlMemGauge.vue'),
GlMemHistory: () => import('@/components/Widgets/GlMemHistory.vue'),
GlNetworkInterfaces: () => import('@/components/Widgets/GlNetworkInterfaces.vue'),
GlSystemLoad: () => import('@/components/Widgets/GlSystemLoad.vue'),
HealthChecks: () => import('@/components/Widgets/HealthChecks.vue'),
IframeWidget: () => import('@/components/Widgets/IframeWidget.vue'),