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 0a7f6ff commit a613897
Show file tree
Hide file tree
Showing 7 changed files with 316 additions and 13 deletions.
10 changes: 7 additions & 3 deletions public/i18n/en/translation.json
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,8 @@
"actions": "Actions",
"go_to_page": "Go to {page}",
"download": "Download",
"upload": "Upload"
"upload": "Upload",
"no_data_available": "No data available"
},
"error": {
"generic_error": "Something went wrong",
Expand Down Expand Up @@ -1810,9 +1811,12 @@
"wan_name_traffic": "{name} traffic",
"blocked_threats": "Blocked threats",
"blocked_packets": "Blocked packets",
"blocked_ip_addresses": "Blocked IP addresses",
"malware_by_direction": "Malware by direction",
"malware_by_category": "Malware by category"
"malware_by_category": "Malware by category",
"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"
},
"ping_latency_monitor": {
"title": "Ping latency monitor",
Expand Down
78 changes: 78 additions & 0 deletions src/components/charts/BasicBarChart.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
<!--
Copyright (C) 2024 Nethesis S.r.l.
SPDX-License-Identifier: GPL-3.0-or-later
-->

<script setup lang="ts">
import {
Chart as ChartJS,
Title,
Tooltip,
Legend,
BarElement,
CategoryScale,
LinearScale
} from 'chart.js'
import { Bar } from 'vue-chartjs'
import { computed } from 'vue'
import { useThemeStore } from '@/stores/theme'
import { GRAY_200, GRAY_700, GRAY_800 } from '@/lib/color'
const themeStore = useThemeStore()
const props = withDefaults(
defineProps<{
labels: string[]
datasets: any[]
height?: string
isHorizontal?: boolean
isLegendShown?: boolean
}>(),
{ isHorizontal: false, isLegendShown: false }
)
const options: any = {
indexAxis: props.isHorizontal ? 'y' : 'x',
scales: {
x: {
ticks: {
color: themeStore.isLight ? GRAY_700 : GRAY_200
},
grid: {
color: themeStore.isLight ? GRAY_200 : GRAY_800
}
},
y: {
ticks: {
color: themeStore.isLight ? GRAY_700 : GRAY_200
},
grid: {
color: themeStore.isLight ? GRAY_200 : GRAY_800
}
}
},
plugins: {
legend: {
display: props.isLegendShown
}
}
}
const chartData: any = computed(() => {
return { labels: props.labels, datasets: props.datasets }
})
const chartStyle = computed(() => {
return {
height: props.height || '',
width: '100%',
position: 'relative'
}
})
ChartJS.register(CategoryScale, LinearScale, BarElement, Title, Tooltip, Legend)
</script>

<template>
<Bar :data="chartData" :options="options" :style="chartStyle" />
</template>
File renamed without changes.
File renamed without changes.
118 changes: 110 additions & 8 deletions src/components/standalone/monitoring/SecurityMonitor.vue
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,10 @@

<script setup lang="ts">
import { ubusCall } from '@/lib/standalone/ubus'
import { getAxiosErrorMessage, NeCard } from '@nethesis/vue-components'
import { getAxiosErrorMessage, NeCard, NeEmptyState } from '@nethesis/vue-components'
import { onMounted, ref } from 'vue'
import { useI18n } from 'vue-i18n'
import SimpleStat from './SimpleStat.vue'
import SimpleStat from '../../charts/SimpleStat.vue'
import BlockedPacketsChart from './security/BlockedPacketsChart.vue'
import { useThemeStore } from '@/stores/theme'
import {
Expand All @@ -33,7 +33,9 @@ import {
VIOLET_500,
VIOLET_600
} from '@/lib/color'
import BasicPieChart from '../../BasicPieChart.vue'
import BasicPieChart from '../../charts/BasicPieChart.vue'
import BasicBarChart from '../../charts/BasicBarChart.vue'
import BlockedIpsPerHourChart from './security/BlockedIpsPerHourChart.vue'
type MalwareReport = {
first_seen: number
Expand All @@ -53,6 +55,7 @@ type AttackReport = {
const { t } = useI18n()
const themeStore = useThemeStore()
const CHART_NUM_ITEMS = 10
const malwareReport = ref<MalwareReport | undefined>(undefined)
const attackReport = ref<AttackReport | undefined>(undefined)
const blockedPacketsChartLabels = ref<number[]>([])
Expand All @@ -61,6 +64,10 @@ const malwareByDirectionChartLabels = ref<string[]>([])
const malwareByDirectionChartDatasets = ref<any[]>([])
const malwareByCategoryChartLabels = ref<string[]>([])
const malwareByCategoryChartDatasets = ref<any[]>([])
const mostBlockedIpsChartLabels = ref<string[]>([])
const mostBlockedIpsChartDatasets = ref<any[]>([])
const blockedIpsPerHourChartLabels = ref<string[]>([])
const blockedIpsPerHourChartDatasets = ref<any[]>([])
let loading = ref({
getMalwareReport: false,
Expand Down Expand Up @@ -128,7 +135,11 @@ const mockTsipAttackReport = {
['47.236.162.71', 5],
['47.236.232.63', 4],
['8.219.246.145', 4],
['123.56.251.31', 4]
['123.56.251.31', 4],
['123.56.251.32', 3],
['123.56.251.33', 3],
['123.56.251.34', 3],
['123.56.251.35', 3]
],
attack_by_hour: [
[0, 0],
Expand Down Expand Up @@ -170,7 +181,7 @@ async function getMalwareReport() {
try {
const res = await ubusCall('ns.report', 'tsip-malware-report')
// malwareReport.value = res.data ////
// malwareReport.value = res.data //// uncomment
//// remove
malwareReport.value = mockTsipMalwareReport ////
Expand Down Expand Up @@ -280,7 +291,51 @@ async function getAttackReport() {
try {
const res = await ubusCall('ns.report', 'tsip-attack-report')
attackReport.value = res.data
// attackReport.value = res.data //// uncomment
//// remove
attackReport.value = mockTsipAttackReport ////
res.data = mockTsipAttackReport ////
// most blocked ip addresses chart
mostBlockedIpsChartLabels.value = res.data.attack_by_ip
.slice(0, CHART_NUM_ITEMS)
.map((data: any[]) => data[0])
const mostBlockedIpAddresses = res.data.attack_by_ip
.slice(0, CHART_NUM_ITEMS)
.map((data: any[]) => data[1])
mostBlockedIpsChartDatasets.value = [
{
label: t('standalone.real_time_monitor.times_blocked'),
backgroundColor: themeStore.isLight ? CYAN_600 : CYAN_500,
borderColor: themeStore.isLight ? CYAN_600 : CYAN_500,
borderRadius: 6,
maxBarThickness: 25,
borderWidth: 1,
radius: 0,
data: mostBlockedIpAddresses
}
]
// blocked ip addresses per hour chart
blockedIpsPerHourChartLabels.value = res.data.attack_by_hour.map((data: any[]) => data[0])
const blockedIpsPerHourChartData = res.data.attack_by_hour.map((data: any[]) => data[1])
blockedIpsPerHourChartDatasets.value = [
{
label: t('standalone.real_time_monitor.blocked_ip_addresses'),
backgroundColor: themeStore.isLight ? CYAN_600 : CYAN_500,
borderColor: themeStore.isLight ? CYAN_600 : CYAN_500,
borderRadius: 6,
maxBarThickness: 25,
borderWidth: 1,
radius: 0,
data: blockedIpsPerHourChartData
}
]
} catch (err: any) {
console.error(err)
error.value.getAttackReport = t('error.cannot_retrieve_attack_report')
Expand All @@ -293,8 +348,8 @@ async function getAttackReport() {

<template>
<div>
<div>//// malwareReport {{ malwareReport }}</div>
<div class="mb-6">//// attackReport {{ attackReport }}</div>
<!-- <div>//// malwareReport {{ malwareReport }}</div>
<div class="mb-6">//// attackReport {{ attackReport }}</div> -->
<div
class="grid grid-cols-1 gap-x-6 gap-y-6 sm:grid-cols-2 md:grid-cols-4 xl:grid-cols-8 3xl:grid-cols-12"
>
Expand Down Expand Up @@ -372,6 +427,53 @@ async function getAttackReport() {
/>
</div>
</NeCard>
<!-- most blocked ip addresses -->
<NeCard
:title="t('standalone.real_time_monitor.most_blocked_ip_addresses')"
:skeletonLines="5"
:loading="loading.getAttackReport"
:errorTitle="error.getAttackReport"
:errorDescription="error.getAttackReportDescription"
class="sm:col-span-2 md:col-span-4 3xl:col-span-6"
>
<!-- empty state -->
<NeEmptyState
v-if="!mostBlockedIpsChartDatasets[0]?.data.length"
:title="t('common.no_data_available')"
:icon="['fas', 'chart-line']"
/>
<div v-else>
<BasicBarChart
:labels="mostBlockedIpsChartLabels"
:datasets="mostBlockedIpsChartDatasets"
isHorizontal
height="30vh"
/>
</div>
</NeCard>
<!-- blocked ip addresses per hour -->
<NeCard
:title="t('standalone.real_time_monitor.blocked_ip_addresses_per_hour')"
:skeletonLines="5"
:loading="loading.getAttackReport"
:errorTitle="error.getAttackReport"
:errorDescription="error.getAttackReportDescription"
class="sm:col-span-2 md:col-span-4 3xl:col-span-6"
>
<!-- empty state -->
<!-- <NeEmptyState ////
v-if="!blockedIpsPerHourChartDatasets[0]?.data.length"
:title="t('common.no_data_available')"
:icon="['fas', 'chart-line']"
/> -->
<div>
<BlockedIpsPerHourChart
:labels="blockedIpsPerHourChartLabels"
:datasets="blockedIpsPerHourChartDatasets"
isHorizontal
/>
</div>
</NeCard>
</div>
</div>
</template>
3 changes: 1 addition & 2 deletions src/components/standalone/monitoring/TrafficMonitor.vue
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import RealTimeTrafficCard from '@/components/standalone/monitoring/traffic/Real
import TrafficSummaryChart from '@/components/standalone/monitoring/traffic/TrafficSummaryChart.vue'
import WanTrafficCard from '@/components/standalone/monitoring/traffic/WanTrafficCard.vue'
import RecentTrafficChart from './traffic/RecentTrafficChart.vue'
import SimpleStat from './SimpleStat.vue'
import SimpleStat from '../../charts/SimpleStat.vue'
const { t } = useI18n()
Expand Down Expand Up @@ -155,7 +155,6 @@ const {
{{ t('standalone.real_time_monitor.recent_traffic') }}
</NeHeading>
<NeCard class="sm:col-span-2 md:col-span-4 3xl:col-span-6">
hoursLabels {{ hoursLabels }} ////
<RecentTrafficChart :labels="hoursLabels" :datasets="hoursDatasets" />
</NeCard>
</div>
Expand Down
Loading

0 comments on commit a613897

Please sign in to comment.