瀏覽代碼

feat: add test result component

Thomas Zhang 3 月之前
父節點
當前提交
2f9f321ef9

+ 8 - 0
src/lib/api/types.ts

@@ -21,4 +21,12 @@ const handleResponse = async <T>(res: Response): Promise<T> => {
 	throw new ApiError(res.status, body.code ?? 'UNKNOWN', body.message ?? res.statusText);
 };
 
+type TestResponse<T> = {
+	latencyMs?: number;
+	error?: { type: string; message: string };
+	response?: T;
+	headers?: Record<string, string>;
+};
+
+export type { TestResponse };
 export { ApiError, extractMessage, handleResponse };

+ 3 - 0
src/lib/components/common/test-result/index.ts

@@ -0,0 +1,3 @@
+import TestResult from './result.svelte';
+
+export { TestResult };

+ 45 - 0
src/lib/components/common/test-result/result.svelte

@@ -0,0 +1,45 @@
+<script generics="T" lang="ts">
+	import type { Snippet } from 'svelte';
+	import type { ClassValue } from 'svelte/elements';
+
+	import type { TestResponse } from '$lib/api/types';
+	import { Spinner } from '$lib/components/controls/spinner';
+
+	let {
+		class: className = '',
+		loading = false,
+		response,
+		error,
+		result,
+	}: {
+		class?: ClassValue;
+		loading?: boolean;
+		response?: TestResponse<T>;
+		error?: { type: string; message: string };
+		result: Snippet<[T | undefined]>;
+	} = $props();
+</script>
+
+<div class={['relative', className]}>
+	{#if error || response?.error}
+		<div class="flex h-48 flex-col items-center justify-center p-4">
+			<div class="text-sm font-medium text-red-500/50">
+				{error?.type || response?.error?.type}
+			</div>
+			<div class="text-sm text-white/50">{error?.message || response?.error?.message}</div>
+		</div>
+	{:else if response}
+		<div class={loading ? 'blur-[2px]' : ''}>
+			{@render result(response.response)}
+		</div>
+	{:else}
+		<div class="flex h-48 flex-col items-center justify-center">
+			<p class="text-sm text-white/50">No results yet</p>
+		</div>
+	{/if}
+	{#if loading}
+		<div class="absolute inset-0 z-10 flex items-center justify-center bg-black/25">
+			<Spinner class="size-6" />
+		</div>
+	{/if}
+</div>