1
0
mirror of https://github.com/hotomoe/hotomoe synced 2024-12-02 00:38:14 +09:00

feat(client): add instances doughnuts charts for dashboard

This commit is contained in:
syuilo 2022-06-28 10:42:26 +09:00
parent d7c6e2e61c
commit fe460c022c
2 changed files with 155 additions and 5 deletions

View File

@ -0,0 +1,102 @@
<template>
<canvas ref="chartEl"></canvas>
</template>
<script lang="ts" setup>
import { onMounted, onUnmounted, ref } from 'vue';
import {
Chart,
ArcElement,
LineElement,
BarElement,
PointElement,
BarController,
LineController,
CategoryScale,
LinearScale,
TimeScale,
Legend,
Title,
Tooltip,
SubTitle,
Filler,
DoughnutController,
} from 'chart.js';
import number from '@/filters/number';
import { defaultStore } from '@/store';
import { useChartTooltip } from '@/scripts/use-chart-tooltip';
Chart.register(
ArcElement,
LineElement,
BarElement,
PointElement,
BarController,
LineController,
DoughnutController,
CategoryScale,
LinearScale,
TimeScale,
Legend,
Title,
Tooltip,
SubTitle,
Filler,
);
const props = defineProps<{
data: { name: string; value: number; color: string; }[];
}>();
const chartEl = ref<HTMLCanvasElement>(null);
//
Chart.defaults.color = getComputedStyle(document.documentElement).getPropertyValue('--fg');
const { handler: externalTooltipHandler } = useChartTooltip();
let chartInstance: Chart;
onMounted(() => {
chartInstance = new Chart(chartEl.value, {
type: 'doughnut',
data: {
labels: props.data.map(x => x.name),
datasets: [{
backgroundColor: props.data.map(x => x.color),
data: props.data.map(x => x.value),
}],
},
options: {
layout: {
padding: {
left: 8,
right: 8,
top: 8,
bottom: 8,
},
},
interaction: {
intersect: false,
},
plugins: {
legend: {
display: false,
},
tooltip: {
enabled: false,
mode: 'index',
animation: {
duration: 0,
},
external: externalTooltipHandler,
},
},
},
});
});
</script>
<style lang="scss" scoped>
</style>

View File

@ -43,7 +43,12 @@
</div> </div>
</div> </div>
<!--<XMetrics/>--> <div class="container files">
<div class="title">Recent files</div>
<div class="body">
<MkFileListForAdmin :pagination="filesPagination" view-mode="grid"/>
</div>
</div>
<div class="container env"> <div class="container env">
<div class="title">Enviroment</div> <div class="title">Enviroment</div>
@ -103,10 +108,18 @@
</div> </div>
</div> </div>
</div> </div>
<div class="container files"> <div v-if="fedStats" class="container federationPies">
<div class="title">Recent files</div>
<div class="body"> <div class="body">
<MkFileListForAdmin :pagination="filesPagination" view-mode="grid"/> <div class="chart deliver">
<div class="title">Sub</div>
<XPie :data="fedStats.topSubInstances.map(x => ({ name: x.host, value: x.followersCount }))"/>
<div class="subTitle">Top 10</div>
</div>
<div class="chart inbox">
<div class="title">Pub</div>
<XPie :data="fedStats.topPubInstances.map(x => ({ name: x.host, value: x.followingCount }))"/>
<div class="subTitle">Top 10</div>
</div>
</div> </div>
</div> </div>
</div> </div>
@ -140,6 +153,7 @@ import XMetrics from './metrics.vue';
import XFederation from './overview.federation.vue'; import XFederation from './overview.federation.vue';
import XQueueChart from './overview.queue-chart.vue'; import XQueueChart from './overview.queue-chart.vue';
import XUser from './overview.user.vue'; import XUser from './overview.user.vue';
import XPie from './overview.pie.vue';
import MkInstanceStats from '@/components/instance-stats.vue'; import MkInstanceStats from '@/components/instance-stats.vue';
import MkNumberDiff from '@/components/number-diff.vue'; import MkNumberDiff from '@/components/number-diff.vue';
import { version, url } from '@/config'; import { version, url } from '@/config';
@ -175,6 +189,7 @@ const rootEl = $ref<HTMLElement>();
const chartEl = $ref<HTMLCanvasElement>(null); const chartEl = $ref<HTMLCanvasElement>(null);
let stats: any = $ref(null); let stats: any = $ref(null);
let serverInfo: any = $ref(null); let serverInfo: any = $ref(null);
let fedStats: any = $ref(null);
let usersComparedToThePrevDay: any = $ref(null); let usersComparedToThePrevDay: any = $ref(null);
let notesComparedToThePrevDay: any = $ref(null); let notesComparedToThePrevDay: any = $ref(null);
let federationPubActive = $ref<number | null>(null); let federationPubActive = $ref<number | null>(null);
@ -257,7 +272,7 @@ async function renderChart() {
layout: { layout: {
padding: { padding: {
left: 0, left: 0,
right: 8, right: 0,
top: 0, top: 0,
bottom: 0, bottom: 0,
}, },
@ -380,6 +395,10 @@ onMounted(async () => {
federationSubActiveDiff = chart.subActive[0] - chart.subActive[1]; federationSubActiveDiff = chart.subActive[0] - chart.subActive[1];
}); });
os.apiGet('federation/stats').then(res => {
fedStats = res;
});
os.api('admin/server-info').then(serverInfoResponse => { os.api('admin/server-info').then(serverInfoResponse => {
serverInfo = serverInfoResponse; serverInfo = serverInfoResponse;
}); });
@ -529,6 +548,35 @@ definePageMetadata({
} }
} }
} }
&.federationPies {
> .body {
display: grid;
grid-gap: 16px;
grid-template-columns: repeat(auto-fill, minmax(180px, 1fr));
> .chart {
position: relative;
padding: 20px;
background: var(--panel);
border-radius: var(--radius);
> .title {
position: absolute;
top: 20px;
left: 20px;
font-size: 90%;
}
> .subTitle {
position: absolute;
bottom: 20px;
right: 20px;
font-size: 85%;
}
}
}
}
} }
} }