فهرست منبع

chore(web) Add automatic server stats refetching (#1271)

Krisjanis Lejejs 2 سال پیش
والد
کامیت
5999af6c78

+ 0 - 1
web/src/lib/components/admin-page/jobs/jobs-panel.svelte

@@ -19,7 +19,6 @@
 			allJobsStatus = data;
 			allJobsStatus = data;
 		}, 1000);
 		}, 1000);
 	});
 	});
-	1;
 
 
 	onDestroy(() => {
 	onDestroy(() => {
 		clearInterval(setIntervalHandler);
 		clearInterval(setIntervalHandler);

+ 52 - 17
web/src/lib/components/admin-page/server-stats/server-stats-panel.svelte

@@ -1,13 +1,32 @@
 <script lang="ts">
 <script lang="ts">
-	import { ServerStatsResponseDto, UserResponseDto } from '@api';
+	import { api, ServerStatsResponseDto, UserResponseDto } from '@api';
 	import CameraIris from 'svelte-material-icons/CameraIris.svelte';
 	import CameraIris from 'svelte-material-icons/CameraIris.svelte';
 	import PlayCircle from 'svelte-material-icons/PlayCircle.svelte';
 	import PlayCircle from 'svelte-material-icons/PlayCircle.svelte';
 	import Memory from 'svelte-material-icons/Memory.svelte';
 	import Memory from 'svelte-material-icons/Memory.svelte';
 	import StatsCard from './stats-card.svelte';
 	import StatsCard from './stats-card.svelte';
 	import { getBytesWithUnit, asByteUnitString } from '../../../utils/byte-units';
 	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>;
 	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) => {
 	const getFullName = (userId: string) => {
 		let name = 'Admin'; // since we do not have admin user in allUsers
 		let name = 'Admin'; // since we do not have admin user in allUsers
 		allUsers.forEach((user) => {
 		allUsers.forEach((user) => {
@@ -16,7 +35,8 @@
 		return name;
 		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;
 	const locale = navigator.language;
 </script>
 </script>
@@ -26,9 +46,14 @@
 		<p class="text-sm dark:text-immich-dark-fg">TOTAL USAGE</p>
 		<p class="text-sm dark:text-immich-dark-fg">TOTAL USAGE</p>
 
 
 		<div class="flex mt-5 justify-between">
 		<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>
 	</div>
 	</div>
 
 
@@ -48,20 +73,30 @@
 			<tbody
 			<tbody
 				class="overflow-y-auto rounded-md w-full max-h-[320px] block border dark:border-immich-dark-gray dark:text-immich-dark-fg"
 				class="overflow-y-auto rounded-md w-full max-h-[320px] block border dark:border-immich-dark-gray dark:text-immich-dark-fg"
 			>
 			>
-				{#each stats.usageByUser as user, i}
+				{#if stats}
+					{#each stats.usageByUser as user, i}
+						<tr
+							class={`text-center flex place-items-center w-full h-[50px] ${
+								i % 2 == 0
+									? 'bg-immich-gray dark:bg-immich-dark-gray/75'
+									: 'bg-immich-bg dark:bg-immich-dark-gray/50'
+							}`}
+						>
+							<td class="text-sm px-2 w-1/4 text-ellipsis">{getFullName(user.userId)}</td>
+							<td class="text-sm px-2 w-1/4 text-ellipsis">{user.photos.toLocaleString(locale)}</td>
+							<td class="text-sm px-2 w-1/4 text-ellipsis">{user.videos.toLocaleString(locale)}</td>
+							<td class="text-sm px-2 w-1/4 text-ellipsis">{asByteUnitString(user.usageRaw)}</td>
+						</tr>
+					{/each}
+				{:else}
 					<tr
 					<tr
-						class={`text-center flex place-items-center w-full h-[50px] ${
-							i % 2 == 0
-								? 'bg-immich-gray dark:bg-immich-dark-gray/75'
-								: 'bg-immich-bg dark:bg-immich-dark-gray/50'
-						}`}
+						class="text-center flex place-items-center w-full h-[50px] bg-immich-gray dark:bg-immich-dark-gray/75"
 					>
 					>
-						<td class="text-sm px-2 w-1/4 text-ellipsis">{getFullName(user.userId)}</td>
-						<td class="text-sm px-2 w-1/4 text-ellipsis">{user.photos.toLocaleString(locale)}</td>
-						<td class="text-sm px-2 w-1/4 text-ellipsis">{user.videos.toLocaleString(locale)}</td>
-						<td class="text-sm px-2 w-1/4 text-ellipsis">{asByteUnitString(user.usageRaw)}</td>
+						<td class="w-full flex justify-center">
+							<LoadingSpinner />
+						</td>
 					</tr>
 					</tr>
-				{/each}
+				{/if}
 			</tbody>
 			</tbody>
 		</table>
 		</table>
 	</div>
 	</div>

+ 16 - 4
web/src/lib/components/admin-page/server-stats/stats-card.svelte

@@ -1,4 +1,6 @@
 <script lang="ts">
 <script lang="ts">
+	import LoadingSpinner from '$lib/components/shared-components/loading-spinner.svelte';
+
 	// eslint-disable-next-line @typescript-eslint/no-explicit-any
 	// eslint-disable-next-line @typescript-eslint/no-explicit-any
 	export let logo: any;
 	export let logo: any;
 	export let title: string;
 	export let title: string;
@@ -6,8 +8,12 @@
 	export let unit: string | undefined = undefined;
 	export let unit: string | undefined = undefined;
 
 
 	$: zeros = () => {
 	$: zeros = () => {
-		let result = '';
+		if (!value) {
+			return '';
+		}
+
 		const maxLength = 13;
 		const maxLength = 13;
+		let result = '';
 		const valueLength = parseInt(value).toString().length;
 		const valueLength = parseInt(value).toString().length;
 		const zeroLength = maxLength - valueLength;
 		const zeroLength = maxLength - valueLength;
 		for (let i = 0; i < zeroLength; i++) {
 		for (let i = 0; i < zeroLength; i++) {
@@ -26,9 +32,15 @@
 	</div>
 	</div>
 
 
 	<div class="relative text-center font-mono font-semibold text-2xl">
 	<div class="relative text-center font-mono font-semibold text-2xl">
-		<span class="text-[#DCDADA] dark:text-[#525252]">{zeros()}</span><span
-			class="text-immich-primary dark:text-immich-dark-primary">{parseInt(value)}</span
-		>
+		{#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}
 		{#if unit}
 			<span class="absolute -top-5 right-2 text-base font-light text-gray-400">{unit}</span>
 			<span class="absolute -top-5 right-2 text-base font-light text-gray-400">{unit}</span>
 		{/if}
 		{/if}

+ 1 - 1
web/src/routes/admin/server-status/+page.server.ts

@@ -13,5 +13,5 @@ export const load: PageServerLoad = async ({ parent }) => {
 
 
 	const { data: allUsers } = await serverApi.userApi.getAllUsers(false);
 	const { data: allUsers } = await serverApi.userApi.getAllUsers(false);
 
 
-	return { user, allUsers };
+	return { allUsers };
 };
 };

+ 2 - 19
web/src/routes/admin/server-status/+page.svelte

@@ -1,29 +1,12 @@
 <script lang="ts">
 <script lang="ts">
 	import ServerStatsPanel from '$lib/components/admin-page/server-stats/server-stats-panel.svelte';
 	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';
 	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>
 </script>
 
 
 <svelte:head>
 <svelte:head>
 	<title>Server Status - Immich</title>
 	<title>Server Status - Immich</title>
 </svelte:head>
 </svelte:head>
 
 
-{#if $page.data.allUsers && serverStat}
-	<ServerStatsPanel stats={serverStat} allUsers={$page.data.allUsers} />
+{#if $page.data.allUsers}
+	<ServerStatsPanel allUsers={$page.data.allUsers} />
 {/if}
 {/if}