Make stats limit configurable
This commit is contained in:
parent
be1d3f6da4
commit
ef92e31195
@ -7,6 +7,7 @@ module.exports = {
|
||||
'plugin:vue/essential',
|
||||
'@vue/airbnb',
|
||||
'@vue/typescript/recommended',
|
||||
'prettier'
|
||||
],
|
||||
parserOptions: {
|
||||
ecmaVersion: 2020,
|
||||
|
@ -38,6 +38,7 @@
|
||||
"@vue/eslint-config-airbnb": "^5.0.2",
|
||||
"@vue/eslint-config-typescript": "^7.0.0",
|
||||
"eslint": "^6.7.2",
|
||||
"eslint-config-prettier": "^8.1.0",
|
||||
"eslint-plugin-import": "^2.20.2",
|
||||
"eslint-plugin-vue": "^6.2.2",
|
||||
"sass": "^1.26.5",
|
||||
@ -45,4 +46,4 @@
|
||||
"typescript": "~4.1.5",
|
||||
"vue-template-compiler": "^2.6.11"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,14 +1,55 @@
|
||||
<template>
|
||||
<div class="stats-container" :class="containerClass">
|
||||
<h2>{{ title() }}</h2>
|
||||
<h2>
|
||||
{{ title() }}
|
||||
<b-icon :id="chartSettingsID()" icon="gear-fill"></b-icon>
|
||||
</h2>
|
||||
<div class="chart-container">
|
||||
<canvas :id="chartID()" widht="400" height="400"></canvas>
|
||||
</div>
|
||||
<b-popover
|
||||
:target="chartSettingsID()"
|
||||
triggers="click"
|
||||
:show.sync="settingsShow"
|
||||
placement="auto"
|
||||
container="stats-container"
|
||||
ref="popover"
|
||||
@show="onShow"
|
||||
>
|
||||
<template #title>
|
||||
<b-button @click="onClose" class="close" aria-label="Close">
|
||||
<span class="d-inline-block" aria-hidden="true">×</span>
|
||||
</b-button>
|
||||
Settings
|
||||
</template>
|
||||
|
||||
<div>
|
||||
<b-form-group
|
||||
label="Limit"
|
||||
label-for="limitinput"
|
||||
label-cols="3"
|
||||
class="mb-1"
|
||||
description="Limit number of items"
|
||||
invalid-feedback="This field is required"
|
||||
>
|
||||
<b-form-input
|
||||
ref="limitinput"
|
||||
id="limitinput"
|
||||
v-model="limitState"
|
||||
type="number"
|
||||
size="sm"
|
||||
></b-form-input>
|
||||
</b-form-group>
|
||||
|
||||
<b-button @click="onClose" size="sm" variant="danger">Cancel</b-button>
|
||||
<b-button @click="onOk" size="sm" variant="primary">Ok</b-button>
|
||||
</div>
|
||||
</b-popover>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { Component, Prop, Vue } from 'vue-property-decorator';
|
||||
import { Component, Prop, Vue, Watch } from 'vue-property-decorator';
|
||||
import { StatResult } from '@/apiary/apiary';
|
||||
import axios from 'axios';
|
||||
import Chart from 'chart.js/auto';
|
||||
@ -20,23 +61,31 @@ export type StatType = 'username' | 'password' | 'ip' | 'country' | 'total';
|
||||
export default class StatsPie extends Vue {
|
||||
@Prop() private statType!: StatType;
|
||||
|
||||
limit: number;
|
||||
|
||||
limitState: number;
|
||||
|
||||
settingsShow = false;
|
||||
|
||||
stats: StatResult[];
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
this.stats = [];
|
||||
this.limit = 10;
|
||||
this.limitState = 10;
|
||||
}
|
||||
|
||||
title(): string {
|
||||
switch (this.statType) {
|
||||
case 'password':
|
||||
return 'Top 10 Passwords';
|
||||
return `Top ${this.limit} Passwords`;
|
||||
case 'username':
|
||||
return 'Top 10 Usernames';
|
||||
return `Top ${this.limit} Usernames`;
|
||||
case 'ip':
|
||||
return 'Top 10 IPs';
|
||||
return `Top ${this.limit} IPs`;
|
||||
case 'country':
|
||||
return 'Top 10 Countries';
|
||||
return `Top ${this.limit} Countries`;
|
||||
case 'total':
|
||||
return 'Totals';
|
||||
// Why doesn't eslint know that this switch is exhaustive?
|
||||
@ -53,14 +102,48 @@ export default class StatsPie extends Vue {
|
||||
return `chart-${this.statType}`;
|
||||
}
|
||||
|
||||
mounted(): void {
|
||||
const url = `/api/stats?type=${this.statType}&limit=10`;
|
||||
chartSettingsID(): string {
|
||||
return `chartsettings-${this.statType}`;
|
||||
}
|
||||
|
||||
settingsID(): string {
|
||||
return `settings-${this.statType}`;
|
||||
}
|
||||
|
||||
onClose(): void {
|
||||
this.settingsShow = false;
|
||||
}
|
||||
|
||||
onOk(): void {
|
||||
if (this.limitState) {
|
||||
this.limit = this.limitState;
|
||||
this.settingsShow = false;
|
||||
}
|
||||
}
|
||||
|
||||
onShow(): void {
|
||||
// This is called just before the popover is shown
|
||||
// Reset our popover form variables
|
||||
this.limitState = this.limit;
|
||||
}
|
||||
|
||||
@Watch('limit')
|
||||
limitChanged(value: number, oldValue: number): void {
|
||||
this.fetchData();
|
||||
}
|
||||
|
||||
fetchData(): void {
|
||||
const url = `/api/stats?type=${this.statType}&limit=${this.limit}`;
|
||||
axios.get<StatResult[]>(url).then((resp) => {
|
||||
this.stats = resp.data;
|
||||
this.renderPie();
|
||||
});
|
||||
}
|
||||
|
||||
mounted(): void {
|
||||
this.fetchData();
|
||||
}
|
||||
|
||||
renderPie(): void {
|
||||
const elem = document.getElementById(this.chartID()) as HTMLCanvasElement;
|
||||
const ctx = elem.getContext('2d') as CanvasRenderingContext2D;
|
||||
@ -87,6 +170,9 @@ export default class StatsPie extends Vue {
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.stats-container {
|
||||
align-content: center;
|
||||
}
|
||||
.chart-container {
|
||||
max-width: 500px;
|
||||
max-height: 500px;
|
||||
|
@ -4301,6 +4301,11 @@ eslint-config-airbnb-base@^14.0.0:
|
||||
object.assign "^4.1.2"
|
||||
object.entries "^1.1.2"
|
||||
|
||||
eslint-config-prettier@^8.1.0:
|
||||
version "8.1.0"
|
||||
resolved "https://registry.yarnpkg.com/eslint-config-prettier/-/eslint-config-prettier-8.1.0.tgz#4ef1eaf97afe5176e6a75ddfb57c335121abc5a6"
|
||||
integrity sha512-oKMhGv3ihGbCIimCAjqkdzx2Q+jthoqnXSP+d86M9tptwugycmTFdVR4IpLgq2c4SHifbwO90z2fQ8/Aio73yw==
|
||||
|
||||
eslint-import-resolver-node@^0.3.4:
|
||||
version "0.3.4"
|
||||
resolved "https://registry.yarnpkg.com/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.4.tgz#85ffa81942c25012d8231096ddf679c03042c717"
|
||||
|
Loading…
Reference in New Issue
Block a user