Score as percentages
This commit is contained in:
parent
dfc0eeb323
commit
74aee54432
23 changed files with 1027 additions and 1488 deletions
|
|
@ -32,7 +32,7 @@
|
|||
<div class="flex-grow-1">
|
||||
<div class="d-flex justify-content-between align-items-start">
|
||||
<h5 class="fw-bold mb-1">{check.name}</h5>
|
||||
<span class="badge bg-light text-dark">{check.score.toFixed(1)} pts</span>
|
||||
<span class="badge bg-light text-dark">{check.score}%</span>
|
||||
</div>
|
||||
|
||||
<p class="mt-2 mb-2">{check.message}</p>
|
||||
|
|
@ -48,7 +48,7 @@
|
|||
{#if check.details}
|
||||
<details class="small text-muted">
|
||||
<summary class="cursor-pointer">Technical Details</summary>
|
||||
<pre class="mt-2 mb-0 small bg-light p-2 rounded">{check.details}</pre>
|
||||
<pre class="mt-2 mb-0 small bg-light p-2 rounded" style="white-space: pre-wrap;">{check.details}</pre>
|
||||
</details>
|
||||
{/if}
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -2,25 +2,26 @@
|
|||
import type { ScoreSummary } from "$lib/api/types.gen";
|
||||
|
||||
interface Props {
|
||||
grade: string;
|
||||
score: number;
|
||||
summary?: ScoreSummary;
|
||||
}
|
||||
|
||||
let { score, summary }: Props = $props();
|
||||
let { grade, score, summary }: Props = $props();
|
||||
|
||||
function getScoreClass(score: number): string {
|
||||
if (score >= 9) return "score-excellent";
|
||||
if (score >= 7) return "score-good";
|
||||
if (score >= 5) return "score-warning";
|
||||
if (score >= 3) return "score-poor";
|
||||
if (score >= 90) return "score-excellent";
|
||||
if (score >= 70) return "score-good";
|
||||
if (score >= 50) return "score-warning";
|
||||
if (score >= 30) return "score-poor";
|
||||
return "score-bad";
|
||||
}
|
||||
|
||||
function getScoreLabel(score: number): string {
|
||||
if (score >= 9) return "Excellent";
|
||||
if (score >= 7) return "Good";
|
||||
if (score >= 5) return "Fair";
|
||||
if (score >= 3) return "Poor";
|
||||
if (score >= 90) return "Excellent";
|
||||
if (score >= 70) return "Good";
|
||||
if (score >= 50) return "Fair";
|
||||
if (score >= 30) return "Poor";
|
||||
return "Critical";
|
||||
}
|
||||
</script>
|
||||
|
|
@ -28,7 +29,7 @@
|
|||
<div class="card shadow-lg bg-white">
|
||||
<div class="card-body p-5 text-center">
|
||||
<h1 class="display-1 fw-bold mb-3 {getScoreClass(score)}">
|
||||
{score.toFixed(1)}/10
|
||||
{grade}
|
||||
</h1>
|
||||
<h3 class="fw-bold mb-2">{getScoreLabel(score)}</h3>
|
||||
<p class="text-muted mb-4">Overall Deliverability Score</p>
|
||||
|
|
@ -39,12 +40,12 @@
|
|||
<div class="p-2 bg-light rounded text-center">
|
||||
<strong
|
||||
class="fs-2"
|
||||
class:text-success={summary.authentication_score >= 3}
|
||||
class:text-warning={summary.authentication_score < 3 &&
|
||||
summary.authentication_score >= 1.5}
|
||||
class:text-danger={summary.authentication_score < 1.5}
|
||||
class:text-success={summary.authentication_score >= 100}
|
||||
class:text-warning={summary.authentication_score < 100 &&
|
||||
summary.authentication_score >= 50}
|
||||
class:text-danger={summary.authentication_score < 50}
|
||||
>
|
||||
{summary.authentication_score.toFixed(1)}/3
|
||||
{summary.authentication_score}%
|
||||
</strong>
|
||||
<small class="text-muted d-block">Authentication</small>
|
||||
</div>
|
||||
|
|
@ -53,11 +54,11 @@
|
|||
<div class="p-2 bg-light rounded text-center">
|
||||
<strong
|
||||
class="fs-2"
|
||||
class:text-success={summary.spam_score >= 2}
|
||||
class:text-warning={summary.spam_score < 2 && summary.spam_score >= 1}
|
||||
class:text-danger={summary.spam_score < 1}
|
||||
class:text-success={summary.spam_score >= 100}
|
||||
class:text-warning={summary.spam_score < 100 && summary.spam_score >= 50}
|
||||
class:text-danger={summary.spam_score < 50}
|
||||
>
|
||||
{summary.spam_score.toFixed(1)}/2
|
||||
{summary.spam_score}%
|
||||
</strong>
|
||||
<small class="text-muted d-block">Spam Score</small>
|
||||
</div>
|
||||
|
|
@ -66,12 +67,12 @@
|
|||
<div class="p-2 bg-light rounded text-center">
|
||||
<strong
|
||||
class="fs-2"
|
||||
class:text-success={summary.blacklist_score >= 2}
|
||||
class:text-warning={summary.blacklist_score < 2 &&
|
||||
summary.blacklist_score >= 1}
|
||||
class:text-danger={summary.blacklist_score < 1}
|
||||
class:text-success={summary.blacklist_score >= 100}
|
||||
class:text-warning={summary.blacklist_score < 100 &&
|
||||
summary.blacklist_score >= 50}
|
||||
class:text-danger={summary.blacklist_score < 50}
|
||||
>
|
||||
{summary.blacklist_score.toFixed(1)}/2
|
||||
{summary.blacklist_score}%
|
||||
</strong>
|
||||
<small class="text-muted d-block">Blacklists</small>
|
||||
</div>
|
||||
|
|
@ -80,12 +81,12 @@
|
|||
<div class="p-2 bg-light rounded text-center">
|
||||
<strong
|
||||
class="fs-2"
|
||||
class:text-success={summary.content_score >= 2}
|
||||
class:text-warning={summary.content_score < 2 &&
|
||||
summary.content_score >= 1}
|
||||
class:text-danger={summary.content_score < 1}
|
||||
class:text-success={summary.content_score >= 100}
|
||||
class:text-warning={summary.content_score < 100 &&
|
||||
summary.content_score >= 50}
|
||||
class:text-danger={summary.content_score < 50}
|
||||
>
|
||||
{summary.content_score.toFixed(1)}/2
|
||||
{summary.content_score}%
|
||||
</strong>
|
||||
<small class="text-muted d-block">Content</small>
|
||||
</div>
|
||||
|
|
@ -94,12 +95,12 @@
|
|||
<div class="p-2 bg-light rounded text-center">
|
||||
<strong
|
||||
class="fs-2"
|
||||
class:text-success={summary.header_score >= 1}
|
||||
class:text-warning={summary.header_score < 1 &&
|
||||
summary.header_score >= 0.5}
|
||||
class:text-danger={summary.header_score < 0.5}
|
||||
class:text-success={summary.header_score >= 100}
|
||||
class:text-warning={summary.header_score < 100 &&
|
||||
summary.header_score >= 50}
|
||||
class:text-danger={summary.header_score < 50}
|
||||
>
|
||||
{summary.header_score.toFixed(1)}/1
|
||||
{summary.header_score}%
|
||||
</strong>
|
||||
<small class="text-muted d-block">Headers</small>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -17,9 +17,9 @@
|
|||
|
||||
// Group checks by category
|
||||
let groupedChecks = $derived(() => {
|
||||
if (!report) return {};
|
||||
if (!report) return { };
|
||||
|
||||
const groups: Record<string, typeof report.checks> = {};
|
||||
const groups: Record<string, typeof report.checks> = { };
|
||||
for (const check of report.checks) {
|
||||
if (!groups[check.category]) {
|
||||
groups[check.category] = [];
|
||||
|
|
@ -106,31 +106,10 @@
|
|||
}
|
||||
|
||||
function getCategoryScore(checks: typeof report.checks): number {
|
||||
return checks.reduce((sum, check) => sum + check.score, 0);
|
||||
return Math.round(checks.reduce((sum, check) => sum + check.score, 0) / checks.filter((c) => c.status != "info").length);
|
||||
}
|
||||
|
||||
function getCategoryMaxScore(category: string): number {
|
||||
switch (category) {
|
||||
case "authentication":
|
||||
return 3;
|
||||
case "spam":
|
||||
return 2;
|
||||
case "blacklist":
|
||||
return 2;
|
||||
case "content":
|
||||
return 2;
|
||||
case "headers":
|
||||
return 1;
|
||||
case "dns":
|
||||
return 0; // DNS checks contribute to other categories
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
function getScoreColorClass(score: number, maxScore: number): string {
|
||||
if (maxScore === 0) return "text-muted";
|
||||
const percentage = (score / maxScore) * 100;
|
||||
function getScoreColorClass(percentage: number): string {
|
||||
if (percentage >= 80) return "text-success";
|
||||
if (percentage >= 50) return "text-warning";
|
||||
return "text-danger";
|
||||
|
|
@ -189,7 +168,7 @@
|
|||
<!-- Score Header -->
|
||||
<div class="row mb-4">
|
||||
<div class="col-12">
|
||||
<ScoreCard score={report.score} summary={report.summary} />
|
||||
<ScoreCard grade={report.grade} score={report.score} summary={report.summary} />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
|
@ -199,15 +178,14 @@
|
|||
<h3 class="fw-bold mb-3">Detailed Checks</h3>
|
||||
{#each Object.entries(groupedChecks()) as [category, checks]}
|
||||
{@const categoryScore = getCategoryScore(checks)}
|
||||
{@const maxScore = getCategoryMaxScore(category)}
|
||||
<div class="category-section mb-4">
|
||||
<h4 class="category-title text-capitalize mb-3 d-flex justify-content-between align-items-center">
|
||||
<span>
|
||||
<i class="bi {getCategoryIcon(category)} me-2"></i>
|
||||
{category}
|
||||
</span>
|
||||
<span class="category-score {getScoreColorClass(categoryScore, maxScore)}">
|
||||
{categoryScore.toFixed(1)}{#if maxScore > 0} / {maxScore}{/if} pts
|
||||
<span class="category-score {getScoreColorClass(categoryScore)}">
|
||||
{categoryScore}%
|
||||
</span>
|
||||
</h4>
|
||||
{#each checks as check}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue