Improve stats view

This commit is contained in:
Torjus Håkestad 2021-04-10 15:09:26 +02:00
parent 28120637e1
commit af6b022932
2 changed files with 112 additions and 6 deletions
web/frontend/src/components

View File

@ -1,26 +1,53 @@
<template>
<div class="stats">
<h1>Stats!</h1>
<stats-username />
<b-card no-body>
<b-tabs card>
<b-tab title="Totals">
<b-card-body>
<stats-pie statType="total" />
</b-card-body>
</b-tab>
<b-tab title="Usernames">
<b-card-body>
<stats-pie statType="username" />
</b-card-body>
</b-tab>
<b-tab title="Passwords">
<b-card-body>
<stats-pie statType="password"></stats-pie>
</b-card-body>
</b-tab>
<b-tab title="Countries">
<b-card-body>
<stats-pie statType="country"></stats-pie>
</b-card-body>
</b-tab>
<b-tab title="IPs">
<b-card-body>
<stats-pie statType="ip"></stats-pie>
</b-card-body>
</b-tab>
</b-tabs>
</b-card>
</div>
</template>
<script lang="ts">
import { Component, Prop, Vue } from 'vue-property-decorator';
import StatsUsername from '@/components/StatsUsername.vue';
import StatsPie from '@/components/StatsPie.vue';
@Component({
components: {
StatsUsername,
StatsPie,
},
})
export default class Stats extends Vue {
@Prop() private msg!: string;
}
export default class Stats extends Vue {}
</script>
<style lang="scss" scoped>
.stats {
align-content: center;
width: 70%;
margin: 50px;
}
</style>

View File

@ -0,0 +1,79 @@
<template>
<div class="stats-container" :class="containerClass">
<h2>{{ title() }}</h2>
<div class="chart-container">
<canvas id="chart" widht="400" height="400"></canvas>
</div>
</div>
</template>
<script lang="ts">
import { Component, Prop, Vue } from 'vue-property-decorator';
import { StatResult } from '@/apiary/apiary';
import axios from 'axios';
import Chart from 'chart.js/auto';
import randomColor from 'randomcolor';
export type StatType = 'username' | 'password' | 'ip' | 'country' | 'total';
@Component
export default class StatsPie extends Vue {
@Prop() private statType!: StatType;
stats: StatResult[];
constructor() {
super();
this.stats = [];
}
title(): string {
if (this.statType === 'total') {
return 'Totals';
}
return `Top 10 ${this.statType}s`;
}
containerClass(): string {
return `stats-container-${this.statType}`;
}
mounted(): void {
const url = `/api/stats?type=${this.statType}&limit=10`;
axios.get<StatResult[]>(url).then((resp) => {
this.stats = resp.data;
this.renderPie();
});
}
renderPie(): void {
const elem = document.getElementById('chart') as HTMLCanvasElement;
const ctx = elem.getContext('2d') as CanvasRenderingContext2D;
const sortedStats = this.stats.sort();
const values = sortedStats.map((s) => s.count);
const headers = sortedStats.map((s) => s.name);
const colors = sortedStats.map(() => randomColor());
const chart = new Chart(ctx, {
type: 'doughnut',
data: {
labels: headers,
options: {},
datasets: [
{
data: values,
backgroundColor: colors,
},
],
},
});
}
}
</script>
<style lang="scss" scoped>
.chart-container {
max-width: 500px;
max-height: 500px;
}
</style>