mirror of
				https://github.com/immich-app/immich.git
				synced 2025-10-31 10:49:11 -04:00 
			
		
		
		
	chore(web) Add automatic server stats refetching (#1271)
This commit is contained in:
		
							parent
							
								
									af2eac52a8
								
							
						
					
					
						commit
						5999af6c78
					
				| @ -19,7 +19,6 @@ | ||||
| 			allJobsStatus = data; | ||||
| 		}, 1000); | ||||
| 	}); | ||||
| 	1; | ||||
| 
 | ||||
| 	onDestroy(() => { | ||||
| 		clearInterval(setIntervalHandler); | ||||
|  | ||||
| @ -1,13 +1,32 @@ | ||||
| <script lang="ts"> | ||||
| 	import { ServerStatsResponseDto, UserResponseDto } from '@api'; | ||||
| 	import { api, ServerStatsResponseDto, UserResponseDto } from '@api'; | ||||
| 	import CameraIris from 'svelte-material-icons/CameraIris.svelte'; | ||||
| 	import PlayCircle from 'svelte-material-icons/PlayCircle.svelte'; | ||||
| 	import Memory from 'svelte-material-icons/Memory.svelte'; | ||||
| 	import StatsCard from './stats-card.svelte'; | ||||
| 	import { getBytesWithUnit, asByteUnitString } from '../../../utils/byte-units'; | ||||
| 	export let stats: ServerStatsResponseDto; | ||||
| 	import { onMount, onDestroy } from 'svelte'; | ||||
| 	import LoadingSpinner from '$lib/components/shared-components/loading-spinner.svelte'; | ||||
| 
 | ||||
| 	export let allUsers: Array<UserResponseDto>; | ||||
| 
 | ||||
| 	let stats: ServerStatsResponseDto; | ||||
| 	let setIntervalHandler: NodeJS.Timer; | ||||
| 
 | ||||
| 	onMount(async () => { | ||||
| 		const { data } = await api.serverInfoApi.getStats(); | ||||
| 		stats = data; | ||||
| 
 | ||||
| 		setIntervalHandler = setInterval(async () => { | ||||
| 			const { data } = await api.serverInfoApi.getStats(); | ||||
| 			stats = data; | ||||
| 		}, 5000); | ||||
| 	}); | ||||
| 
 | ||||
| 	onDestroy(() => { | ||||
| 		clearInterval(setIntervalHandler); | ||||
| 	}); | ||||
| 
 | ||||
| 	const getFullName = (userId: string) => { | ||||
| 		let name = 'Admin'; // since we do not have admin user in allUsers | ||||
| 		allUsers.forEach((user) => { | ||||
| @ -16,7 +35,8 @@ | ||||
| 		return name; | ||||
| 	}; | ||||
| 
 | ||||
| 	$: [spaceUsage, spaceUnit] = getBytesWithUnit(stats.usageRaw); | ||||
| 	// Stats are unavailable if data is not loaded yet | ||||
| 	$: [spaceUsage, spaceUnit] = getBytesWithUnit(stats ? stats.usageRaw : 0); | ||||
| 
 | ||||
| 	const locale = navigator.language; | ||||
| </script> | ||||
| @ -26,9 +46,14 @@ | ||||
| 		<p class="text-sm dark:text-immich-dark-fg">TOTAL USAGE</p> | ||||
| 
 | ||||
| 		<div class="flex mt-5 justify-between"> | ||||
| 			<StatsCard logo={CameraIris} title={'PHOTOS'} value={stats.photos.toString()} /> | ||||
| 			<StatsCard logo={PlayCircle} title={'VIDEOS'} value={stats.videos.toString()} /> | ||||
| 			<StatsCard logo={Memory} title={'STORAGE'} value={spaceUsage.toString()} unit={spaceUnit} /> | ||||
| 			<StatsCard logo={CameraIris} title={'PHOTOS'} value={stats && stats.photos.toString()} /> | ||||
| 			<StatsCard logo={PlayCircle} title={'VIDEOS'} value={stats && stats.videos.toString()} /> | ||||
| 			<StatsCard | ||||
| 				logo={Memory} | ||||
| 				title={'STORAGE'} | ||||
| 				value={stats && spaceUsage.toString()} | ||||
| 				unit={spaceUnit} | ||||
| 			/> | ||||
| 		</div> | ||||
| 	</div> | ||||
| 
 | ||||
| @ -48,6 +73,7 @@ | ||||
| 			<tbody | ||||
| 				class="overflow-y-auto rounded-md w-full max-h-[320px] block border dark:border-immich-dark-gray dark:text-immich-dark-fg" | ||||
| 			> | ||||
| 				{#if stats} | ||||
| 					{#each stats.usageByUser as user, i} | ||||
| 						<tr | ||||
| 							class={`text-center flex place-items-center w-full h-[50px] ${ | ||||
| @ -62,6 +88,15 @@ | ||||
| 							<td class="text-sm px-2 w-1/4 text-ellipsis">{asByteUnitString(user.usageRaw)}</td> | ||||
| 						</tr> | ||||
| 					{/each} | ||||
| 				{:else} | ||||
| 					<tr | ||||
| 						class="text-center flex place-items-center w-full h-[50px] bg-immich-gray dark:bg-immich-dark-gray/75" | ||||
| 					> | ||||
| 						<td class="w-full flex justify-center"> | ||||
| 							<LoadingSpinner /> | ||||
| 						</td> | ||||
| 					</tr> | ||||
| 				{/if} | ||||
| 			</tbody> | ||||
| 		</table> | ||||
| 	</div> | ||||
|  | ||||
| @ -1,4 +1,6 @@ | ||||
| <script lang="ts"> | ||||
| 	import LoadingSpinner from '$lib/components/shared-components/loading-spinner.svelte'; | ||||
| 
 | ||||
| 	// eslint-disable-next-line @typescript-eslint/no-explicit-any | ||||
| 	export let logo: any; | ||||
| 	export let title: string; | ||||
| @ -6,8 +8,12 @@ | ||||
| 	export let unit: string | undefined = undefined; | ||||
| 
 | ||||
| 	$: zeros = () => { | ||||
| 		let result = ''; | ||||
| 		if (!value) { | ||||
| 			return ''; | ||||
| 		} | ||||
| 
 | ||||
| 		const maxLength = 13; | ||||
| 		let result = ''; | ||||
| 		const valueLength = parseInt(value).toString().length; | ||||
| 		const zeroLength = maxLength - valueLength; | ||||
| 		for (let i = 0; i < zeroLength; i++) { | ||||
| @ -26,9 +32,15 @@ | ||||
| 	</div> | ||||
| 
 | ||||
| 	<div class="relative text-center font-mono font-semibold text-2xl"> | ||||
| 		{#if value !== undefined} | ||||
| 			<span class="text-[#DCDADA] dark:text-[#525252]">{zeros()}</span><span | ||||
| 				class="text-immich-primary dark:text-immich-dark-primary">{parseInt(value)}</span | ||||
| 			> | ||||
| 		{:else} | ||||
| 			<div class="flex justify-end pr-2"> | ||||
| 				<LoadingSpinner /> | ||||
| 			</div> | ||||
| 		{/if} | ||||
| 		{#if unit} | ||||
| 			<span class="absolute -top-5 right-2 text-base font-light text-gray-400">{unit}</span> | ||||
| 		{/if} | ||||
|  | ||||
| @ -13,5 +13,5 @@ export const load: PageServerLoad = async ({ parent }) => { | ||||
| 
 | ||||
| 	const { data: allUsers } = await serverApi.userApi.getAllUsers(false); | ||||
| 
 | ||||
| 	return { user, allUsers }; | ||||
| 	return { allUsers }; | ||||
| }; | ||||
|  | ||||
| @ -1,29 +1,12 @@ | ||||
| <script lang="ts"> | ||||
| 	import ServerStatsPanel from '$lib/components/admin-page/server-stats/server-stats-panel.svelte'; | ||||
| 	import { api, ServerStatsResponseDto } from '@api'; | ||||
| 	import { onMount } from 'svelte'; | ||||
| 	import { page } from '$app/stores'; | ||||
| 
 | ||||
| 	let serverStat: ServerStatsResponseDto; | ||||
| 
 | ||||
| 	onMount(() => { | ||||
| 		getServerStats(); | ||||
| 	}); | ||||
| 
 | ||||
| 	const getServerStats = async () => { | ||||
| 		try { | ||||
| 			const res = await api.serverInfoApi.getStats(); | ||||
| 			serverStat = res.data; | ||||
| 		} catch (e) { | ||||
| 			console.log(e); | ||||
| 		} | ||||
| 	}; | ||||
| </script> | ||||
| 
 | ||||
| <svelte:head> | ||||
| 	<title>Server Status - Immich</title> | ||||
| </svelte:head> | ||||
| 
 | ||||
| {#if $page.data.allUsers && serverStat} | ||||
| 	<ServerStatsPanel stats={serverStat} allUsers={$page.data.allUsers} /> | ||||
| {#if $page.data.allUsers} | ||||
| 	<ServerStatsPanel allUsers={$page.data.allUsers} /> | ||||
| {/if} | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user