Skip to content

Commit

Permalink
feat: monitoring UI (wip)
Browse files Browse the repository at this point in the history
  • Loading branch information
andre8244 committed Sep 19, 2024
1 parent a613897 commit 06f1ff5
Show file tree
Hide file tree
Showing 4 changed files with 197 additions and 62 deletions.
9 changes: 6 additions & 3 deletions public/i18n/en/translation.json
Original file line number Diff line number Diff line change
Expand Up @@ -361,7 +361,7 @@
"cannot_retrieve_object_suggestions": "Cannot retrieve object suggestions",
"cannot_retrieve_nat_helpers": "Cannot retrieve NAT helpers",
"cannot_save_nat_helper": "Cannot save NAT helper",
"cannot_retrieve_wan_report": "Cannot retrieve WAN report",
"cannot_retrieve_mwan_report": "Cannot retrieve MultiWAN report",
"cannot_retrieve_malware_report": "Cannot retrieve malware report",
"cannot_retrieve_attack_report": "Cannot retrieve attack report"
},
Expand Down Expand Up @@ -1807,7 +1807,7 @@
"host_traffic": "Host traffic",
"host": "Host",
"connections": "Connections",
"wan_events": "WAN events",
"wan_name_events": "{name} events",
"wan_name_traffic": "{name} traffic",
"blocked_threats": "Blocked threats",
"blocked_packets": "Blocked packets",
Expand All @@ -1816,7 +1816,10 @@
"most_blocked_ip_addresses": "Most blocked IP addresses",
"blocked_ip_addresses_per_hour": "Blocked IP addresses per hour",
"times_blocked": "Times blocked",
"blocked_ip_addresses": "Blocked IP addresses"
"blocked_ip_addresses": "Blocked IP addresses",
"timestamp": "Timestamp",
"event": "Event",
"no_events": "No events"
},
"ping_latency_monitor": {
"title": "Ping latency monitor",
Expand Down
40 changes: 34 additions & 6 deletions src/components/standalone/monitoring/ConnectivityMonitor.vue
Original file line number Diff line number Diff line change
Expand Up @@ -19,18 +19,23 @@ export type Wan = {
const { t } = useI18n()
const wans = ref<Wan[]>([])
const mwanEvents = ref<Record<string, any[]> | undefined>(undefined)
let loading = ref({
listWans: false
listWans: false,
getMwanReport: false
})
let error = ref({
listWans: '',
listWansDescription: ''
listWansDescription: '',
getMwanReport: '',
getMwanReportDescription: ''
})
onMounted(() => {
getWanList()
getMwanReport()
})
async function getWanList() {
Expand All @@ -49,25 +54,48 @@ async function getWanList() {
loading.value.listWans = false
}
}
async function getMwanReport() {
loading.value.getMwanReport = true
error.value.getMwanReport = ''
error.value.getMwanReportDescription = ''
try {
const res = await ubusCall('ns.report', 'mwan-report')
mwanEvents.value = res.data.events_by_wan
} catch (err: any) {
console.error(err)
error.value.getMwanReport = t('error.cannot_retrieve_mwan_report')
error.value.getMwanReportDescription = t(getAxiosErrorMessage(err))
} finally {
loading.value.getMwanReport = false
}
}
</script>

<template>
<div>
<div class="grid grid-cols-1 gap-x-6 gap-y-6 lg:grid-cols-2">
<!-- connections -->
<NeCard
<!-- <NeCard ////
:title="t('standalone.real_time_monitor.connections')"
:skeletonLines="3"
:loading="loading.listWans"
:errorTitle="error.listWans"
:errorDescription="error.listWansDescription"
>
{{ wans }} ////
</NeCard>
</NeCard> -->
<!-- wan events -->
<WanEventsCard />
{{ mwanEvents }} ////
<WanEventsCard
v-for="(events, wanName) in mwanEvents"
:key="wanName"
:wan="wanName"
:wanEvents="events"
/>
<!-- wans traffic -->
<SingleWanTrafficCard v-for="wan in wans" :key="wan.device" :wan="wan" :wans="wans" />
<SingleWanTrafficCard v-for="wan in wans" :key="wan.device" :wan="wan" />
</div>
</div>
</template>
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,13 @@ import { CYAN_500, CYAN_600, INDIGO_400, INDIGO_600 } from '@/lib/color'
import { ubusCall } from '@/lib/standalone/ubus'
import { useThemeStore } from '@/stores/theme'
import { NeCard, NeSkeleton, getAxiosErrorMessage } from '@nethesis/vue-components'
import { isEmpty } from 'lodash-es'
import { onMounted, onUnmounted, ref } from 'vue'
import { useI18n } from 'vue-i18n'
import type { Wan } from '../ConnectivityMonitor.vue'
const props = defineProps<{
wan: Wan
wans: Wan[]
// wans: Wan[] ////
}>()
const { t } = useI18n()
Expand All @@ -34,8 +33,8 @@ let loading = ref({
})
let error = ref({
title: '',
description: ''
getInterfaceTraffic: '',
getInterfaceTrafficDescription: ''
})
onMounted(() => {
Expand All @@ -56,8 +55,8 @@ async function getInterfaceTraffic() {
if (!intervalId.value) {
loading.value.getInterfaceTraffic = true
}
error.value.title = ''
error.value.description = ''
error.value.getInterfaceTraffic = ''
error.value.getInterfaceTrafficDescription = ''
try {
const res = await ubusCall('ns.dashboard', 'interface-traffic', {
Expand Down Expand Up @@ -88,8 +87,8 @@ async function getInterfaceTraffic() {
]
} catch (err: any) {
console.error(err)
error.value.title = t('error.cannot_retrieve_wan_traffic')
error.value.description = t(getAxiosErrorMessage(err))
error.value.getInterfaceTraffic = t('error.cannot_retrieve_wan_traffic')
error.value.getInterfaceTrafficDescription = t(getAxiosErrorMessage(err))
} finally {
loading.value.getInterfaceTraffic = false
}
Expand All @@ -98,16 +97,17 @@ async function getInterfaceTraffic() {

<template>
<NeCard
:title="t('standalone.real_time_monitor.wan_name_traffic', { name: props.wan.iface })"
:description="isEmpty(wans) ? t('standalone.dashboard.no_wan_interfaces') : ''"
:title="
t('standalone.real_time_monitor.wan_name_traffic', {
name: props.wan.iface
})
"
:skeletonLines="8"
:loading="loading.listWans"
:errorTitle="error.title"
:errorDescription="error.description"
:errorTitle="error.getInterfaceTraffic"
:errorDescription="error.getInterfaceTrafficDescription"
>
<template v-if="wans.length">
<NeSkeleton v-if="loading.getInterfaceTraffic" :lines="6"></NeSkeleton>
<WanTrafficChart v-else :labels="chartLabels" :datasets="chartDatasets" height="30vh" />
</template>
<NeSkeleton v-if="loading.getInterfaceTraffic" :lines="6"></NeSkeleton>
<WanTrafficChart v-else :labels="chartLabels" :datasets="chartDatasets" height="30vh" />
</NeCard>
</template>
178 changes: 141 additions & 37 deletions src/components/standalone/monitoring/connectivity/WanEventsCard.vue
Original file line number Diff line number Diff line change
Expand Up @@ -4,58 +4,162 @@
-->

<script setup lang="ts">
import { ubusCall } from '@/lib/standalone/ubus'
import { getAxiosErrorMessage, NeCard } from '@nethesis/vue-components'
import { onMounted, ref } from 'vue'
import {
NeCard,
NeTable,
NeTableHead,
NeTableHeadCell,
NeTableBody,
NeTableRow,
NeTableCell,
NePaginator,
useItemPagination,
NeButton,
NeTooltip,
NeEmptyState
} from '@nethesis/vue-components'
import { computed, ref } from 'vue'
import { useI18n } from 'vue-i18n'
//// copy table from NatHelpersTable -->
//// review
const { t } = useI18n()
//// copy table from NatHelpersTable -->
const events = ref<any[]>([]) //// replace "any" with the correct type
const props = defineProps<{
wan: string
wanEvents: any[]
}>()
let loading = ref({
mwanReport: false
})
const { t } = useI18n()
let error = ref({
mwanReport: '',
mwanReportDescription: ''
const pageSize = ref(5)
const { currentPage, paginatedItems } = useItemPagination(() => events, {
itemsPerPage: pageSize
})
onMounted(() => {
getWanList()
const events = computed(() => {
return props.wanEvents.map((event) => {
return {
time: event[0],
message: event[1]
}
})
})
async function getWanList() {
loading.value.mwanReport = true
error.value.mwanReport = ''
error.value.mwanReportDescription = ''
try {
const res = await ubusCall('ns.report', 'mwan-report')
events.value = res.data.events_by_wan
} catch (err: any) {
console.error(err)
error.value.mwanReport = t('error.cannot_retrieve_wan_report')
error.value.mwanReportDescription = t(getAxiosErrorMessage(err))
} finally {
loading.value.mwanReport = false
}
}
</script>

<template>
<div>
<NeCard
:title="t('standalone.real_time_monitor.wan_events')"
:skeletonLines="3"
:loading="loading.mwanReport"
:errorTitle="error.mwanReport"
:errorDescription="error.mwanReportDescription"
:title="
t('standalone.real_time_monitor.wan_name_events', {
name: props.wan
})
"
>
{{ events }} ////
<NeTable
:ariaLabel="
t('standalone.real_time_monitor.wan_name_events', {
name: props.wan
})
"
cardBreakpoint="sm"
>
<NeTableHead>
<NeTableHeadCell>{{ t('standalone.real_time_monitor.timestamp') }}</NeTableHeadCell>
<NeTableHeadCell>{{ t('standalone.real_time_monitor.event') }}</NeTableHeadCell>
</NeTableHead>
<NeTableBody>
<!-- empty state -->
<NeTableRow v-if="!events.length">
<NeTableCell colspan="2">
<NeEmptyState
:title="t('standalone.real_time_monitor.no_events')"
:icon="['fas', 'table']"
class="bg-white dark:bg-gray-950"
/>
</NeTableCell>
</NeTableRow>
<NeTableRow v-else v-for="item in paginatedItems" :key="item.ip">
<NeTableCell :data-label="t('standalone.real_time_monitor.timestamp')">
{{ item.time }}
</NeTableCell>
<NeTableCell :data-label="t('standalone.real_time_monitor.event')">
<div class="flex items-center gap-2">
<font-awesome-icon
:icon="['fas', item.message ? 'circle-check' : 'circle-xmark']"
class="h-4 w-4"
aria-hidden="true"
/>
{{ item.enabled ? t('common.enabled') : t('common.disabled') }}
</div>
</NeTableCell>
<NeTableCell :data-label="t('standalone.nat_helpers.loaded_on_kernel')">
<div class="flex items-center gap-2">
<span>
{{
item.loaded
? t('standalone.nat_helpers.loaded')
: t('standalone.nat_helpers.not_loaded')
}}
</span>
<!-- enabled/loaded inconsistency warning -->
<NeTooltip v-if="(item.enabled && !item.loaded) || (!item.enabled && item.loaded)">
<template #trigger>
<font-awesome-icon
:icon="['fas', 'triangle-exclamation']"
class="h-4 w-4 text-amber-500"
/>
</template>
<template #content>
<p>
{{
item.enabled && !item.loaded
? t('standalone.nat_helpers.enabled_but_not_loaded_tooltip')
: t('standalone.nat_helpers.disabled_but_loaded_tooltip')
}}
</p>
</template>
</NeTooltip>
</div>
</NeTableCell>
<NeTableCell :data-label="t('common.actions')">
<div class="-ml-2.5 flex xl:ml-0 xl:justify-end">
<NeButton kind="tertiary" @click="emit('editNatHelper', item)">
<template #prefix>
<font-awesome-icon
:icon="['fas', 'pen-to-square']"
class="h-4 w-4"
aria-hidden="true"
/>
</template>
{{ t('common.edit') }}
</NeButton>
</div>
</NeTableCell>
</NeTableRow>
</NeTableBody>
<template #paginator>
<NePaginator
:current-page="currentPage"
:total-rows="events.length"
:page-size="pageSize"
:page-sizes="[5, 10]"
:nav-pagination-label="t('ne_table.pagination')"
:next-label="t('ne_table.go_to_next_page')"
:previous-label="t('ne_table.go_to_previous_page')"
:range-of-total-label="t('ne_table.of')"
:page-size-label="t('ne_table.show')"
@select-page="
(page: number) => {
currentPage = page
}"
@selectPageSize="
(size: number) => {
pageSize = size
}"
/>
</template>
</NeTable>
</NeCard>
</div>
</template>

0 comments on commit 06f1ff5

Please sign in to comment.