feat(client): add instances doughnuts charts for dashboard
This commit is contained in:
		
							parent
							
								
									d7c6e2e61c
								
							
						
					
					
						commit
						fe460c022c
					
				
					 2 changed files with 155 additions and 5 deletions
				
			
		
							
								
								
									
										102
									
								
								packages/client/src/pages/admin/overview.pie.vue
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										102
									
								
								packages/client/src/pages/admin/overview.pie.vue
									
										
									
									
									
										Normal 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> | ||||
|  | @ -43,7 +43,12 @@ | |||
| 				</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="title">Enviroment</div> | ||||
|  | @ -103,10 +108,18 @@ | |||
| 					</div> | ||||
| 				</div> | ||||
| 			</div> | ||||
| 			<div class="container files"> | ||||
| 				<div class="title">Recent files</div> | ||||
| 			<div v-if="fedStats" class="container federationPies"> | ||||
| 				<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> | ||||
|  | @ -140,6 +153,7 @@ import XMetrics from './metrics.vue'; | |||
| import XFederation from './overview.federation.vue'; | ||||
| import XQueueChart from './overview.queue-chart.vue'; | ||||
| import XUser from './overview.user.vue'; | ||||
| import XPie from './overview.pie.vue'; | ||||
| import MkInstanceStats from '@/components/instance-stats.vue'; | ||||
| import MkNumberDiff from '@/components/number-diff.vue'; | ||||
| import { version, url } from '@/config'; | ||||
|  | @ -175,6 +189,7 @@ const rootEl = $ref<HTMLElement>(); | |||
| const chartEl = $ref<HTMLCanvasElement>(null); | ||||
| let stats: any = $ref(null); | ||||
| let serverInfo: any = $ref(null); | ||||
| let fedStats: any = $ref(null); | ||||
| let usersComparedToThePrevDay: any = $ref(null); | ||||
| let notesComparedToThePrevDay: any = $ref(null); | ||||
| let federationPubActive = $ref<number | null>(null); | ||||
|  | @ -257,7 +272,7 @@ async function renderChart() { | |||
| 			layout: { | ||||
| 				padding: { | ||||
| 					left: 0, | ||||
| 					right: 8, | ||||
| 					right: 0, | ||||
| 					top: 0, | ||||
| 					bottom: 0, | ||||
| 				}, | ||||
|  | @ -380,6 +395,10 @@ onMounted(async () => { | |||
| 		federationSubActiveDiff = chart.subActive[0] - chart.subActive[1]; | ||||
| 	}); | ||||
| 
 | ||||
| 	os.apiGet('federation/stats').then(res => { | ||||
| 		fedStats = res; | ||||
| 	}); | ||||
| 
 | ||||
| 	os.api('admin/server-info').then(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%; | ||||
| 						} | ||||
| 					} | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue