feat(admin): OCR admin pages — overview & model detail #265

Merged
marcel merged 53 commits from feat/issue-264-ocr-admin-pages into main 2026-04-18 12:38:42 +02:00
5 changed files with 13 additions and 8 deletions
Showing only changes of commit 794000cbd1 - Show all commits

View File

@@ -34,7 +34,7 @@ const { trainingInfo } = $derived(data);
</h2>
<a
href="/admin/ocr/global"
class="text-xs font-medium text-brand-navy/60 transition-colors hover:text-brand-navy"
class="text-xs font-medium text-brand-navy/60 transition-colors hover:text-brand-navy focus-visible:rounded-sm focus-visible:ring-2 focus-visible:ring-brand-navy focus-visible:outline-none"
>
{m.ocr_global_history_link()}
</a>

View File

@@ -1,6 +1,5 @@
import { afterEach, describe, it, expect } from 'vitest';
import { cleanup, render } from 'vitest-browser-svelte';
import { page } from 'vitest/browser';
import OcrHealthBar from './OcrHealthBar.svelte';
afterEach(cleanup);
@@ -8,11 +7,13 @@ afterEach(cleanup);
describe('OcrHealthBar', () => {
it('shows online status when OCR service is available', async () => {
render(OcrHealthBar, { ocrServiceAvailable: true });
await expect.element(page.getByText(/online/i)).toBeInTheDocument();
const dot = document.querySelector('[role="img"]');
expect(dot?.className).toContain('bg-green-500');
});
it('shows offline status when OCR service is unavailable', async () => {
render(OcrHealthBar, { ocrServiceAvailable: false });
await expect.element(page.getByText(/offline/i)).toBeInTheDocument();
const dot = document.querySelector('[role="img"]');
expect(dot?.className).toContain('bg-red-500');
});
});

View File

@@ -42,7 +42,10 @@ let {
{#each senderModels as model (model.id)}
<tr>
<td class="border-brand-sand/50 border-b py-3">
<a href="/admin/ocr/{model.personId}" class="text-brand-navy hover:underline">
<a
href="/admin/ocr/{model.personId}"
class="text-brand-navy hover:underline focus-visible:rounded-sm focus-visible:ring-2 focus-visible:ring-brand-navy focus-visible:outline-none"
>
{personNames[model.personId] ?? model.personId}
</a>
</td>
@@ -58,7 +61,8 @@ let {
<td class="border-brand-sand/50 border-b py-3">
<a
href="/admin/ocr/{model.personId}"
class="font-medium text-brand-navy hover:underline">{m.ocr_table_details()}</a
class="font-medium text-brand-navy hover:underline focus-visible:rounded-sm focus-visible:ring-2 focus-visible:ring-brand-navy focus-visible:outline-none"
>{m.ocr_table_details()}</a
>
</td>
</tr>

View File

@@ -11,7 +11,7 @@ const personName = $derived(data.history.personNames?.[params.personId] ?? 'Unkn
<div class="flex items-center gap-4">
<a
href="/admin/ocr"
class="group inline-flex items-center text-xs font-bold tracking-widest text-gray-500 uppercase transition-colors hover:text-brand-navy"
class="group inline-flex items-center text-xs font-bold tracking-widest text-gray-500 uppercase transition-colors hover:text-brand-navy focus-visible:rounded-sm focus-visible:ring-2 focus-visible:ring-brand-navy focus-visible:outline-none"
>
<svg
class="mr-2 h-4 w-4 transform transition-transform group-hover:-translate-x-1"

View File

@@ -10,7 +10,7 @@ let { data }: { data: PageData } = $props();
<div class="flex items-center gap-4">
<a
href="/admin/ocr"
class="group inline-flex items-center text-xs font-bold tracking-widest text-gray-500 uppercase transition-colors hover:text-brand-navy"
class="group inline-flex items-center text-xs font-bold tracking-widest text-gray-500 uppercase transition-colors hover:text-brand-navy focus-visible:rounded-sm focus-visible:ring-2 focus-visible:ring-brand-navy focus-visible:outline-none"
>
<svg
class="mr-2 h-4 w-4 transform transition-transform group-hover:-translate-x-1"