Implement web ui
This commit is contained in:
parent
682ca6bb20
commit
4b9733531e
13 changed files with 1141 additions and 0 deletions
143
web/src/routes/test/[test]/+page.svelte
Normal file
143
web/src/routes/test/[test]/+page.svelte
Normal file
|
|
@ -0,0 +1,143 @@
|
|||
<script lang="ts">
|
||||
import { onMount, onDestroy } from "svelte";
|
||||
import { page } from "$app/state";
|
||||
import { getTest, getReport } from "$lib/api";
|
||||
import type { Test, Report } from "$lib/api/types.gen";
|
||||
import { ScoreCard, CheckCard, SpamAssassinCard, PendingState } from "$lib/components";
|
||||
|
||||
let testId = $derived(page.params.test);
|
||||
let test = $state<Test | null>(null);
|
||||
let report = $state<Report | null>(null);
|
||||
let loading = $state(true);
|
||||
let error = $state<string | null>(null);
|
||||
let pollInterval: ReturnType<typeof setInterval> | null = null;
|
||||
|
||||
async function fetchTest() {
|
||||
try {
|
||||
const testResponse = await getTest({ path: { id: testId } });
|
||||
if (testResponse.data) {
|
||||
test = testResponse.data;
|
||||
|
||||
if (test.status === "analyzed") {
|
||||
const reportResponse = await getReport({ path: { id: testId } });
|
||||
if (reportResponse.data) {
|
||||
report = reportResponse.data;
|
||||
}
|
||||
stopPolling();
|
||||
}
|
||||
}
|
||||
loading = false;
|
||||
} catch (err) {
|
||||
error = err instanceof Error ? err.message : "Failed to fetch test";
|
||||
loading = false;
|
||||
stopPolling();
|
||||
}
|
||||
}
|
||||
|
||||
function startPolling() {
|
||||
pollInterval = setInterval(fetchTest, 3000);
|
||||
}
|
||||
|
||||
function stopPolling() {
|
||||
if (pollInterval) {
|
||||
clearInterval(pollInterval);
|
||||
pollInterval = null;
|
||||
}
|
||||
}
|
||||
|
||||
onMount(() => {
|
||||
fetchTest();
|
||||
startPolling();
|
||||
});
|
||||
|
||||
onDestroy(() => {
|
||||
stopPolling();
|
||||
});
|
||||
</script>
|
||||
|
||||
<svelte:head>
|
||||
<title>{test ? `Test ${test.id.slice(0, 8)} - happyDeliver` : "Loading..."}</title>
|
||||
</svelte:head>
|
||||
|
||||
<div class="container py-5">
|
||||
{#if loading}
|
||||
<div class="text-center py-5">
|
||||
<div
|
||||
class="spinner-border text-primary"
|
||||
role="status"
|
||||
style="width: 3rem; height: 3rem;"
|
||||
>
|
||||
<span class="visually-hidden">Loading...</span>
|
||||
</div>
|
||||
<p class="mt-3 text-muted">Loading test...</p>
|
||||
</div>
|
||||
{:else if error}
|
||||
<div class="row justify-content-center">
|
||||
<div class="col-lg-6">
|
||||
<div class="alert alert-danger" role="alert">
|
||||
<i class="bi bi-exclamation-triangle me-2"></i>
|
||||
{error}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{:else if test && test.status !== "analyzed"}
|
||||
<!-- Pending State -->
|
||||
<PendingState {test} />
|
||||
{:else if report}
|
||||
<!-- Results State -->
|
||||
<div class="fade-in">
|
||||
<!-- Score Header -->
|
||||
<div class="row mb-4">
|
||||
<div class="col-12">
|
||||
<ScoreCard score={report.score} summary={report.summary} />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Detailed Checks -->
|
||||
<div class="row mb-4">
|
||||
<div class="col-12">
|
||||
<h3 class="fw-bold mb-3">Detailed Checks</h3>
|
||||
{#each report.checks as check}
|
||||
<CheckCard {check} />
|
||||
{/each}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Additional Information -->
|
||||
{#if report.spamassassin}
|
||||
<div class="row mb-4">
|
||||
<div class="col-12">
|
||||
<SpamAssassinCard spamassassin={report.spamassassin} />
|
||||
</div>
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
<!-- Test Again Button -->
|
||||
<div class="row">
|
||||
<div class="col-12 text-center">
|
||||
<a href="/" class="btn btn-primary btn-lg">
|
||||
<i class="bi bi-arrow-repeat me-2"></i>
|
||||
Test Another Email
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.fade-in {
|
||||
animation: fadeIn 0.6s ease-out;
|
||||
}
|
||||
|
||||
@keyframes fadeIn {
|
||||
from {
|
||||
opacity: 0;
|
||||
transform: translateY(20px);
|
||||
}
|
||||
to {
|
||||
opacity: 1;
|
||||
transform: translateY(0);
|
||||
}
|
||||
}
|
||||
</style>
|
||||
Loading…
Add table
Add a link
Reference in a new issue