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 55 additions and 0 deletions
Showing only changes of commit 5f4e60a14c - Show all commits

View File

@@ -299,6 +299,7 @@
"history_field_receivers": "Empfänger",
"history_field_tags": "Schlagworte",
"admin_tab_system": "System",
"admin_tab_ocr": "OCR",
"admin_system_backfill_heading": "Verlaufsdaten auffüllen",
"admin_system_backfill_description": "Erstellt einen initialen Verlaufseintrag für alle Dokumente, die noch keinen Verlauf haben (z.B. importierte Dokumente). Dadurch werden beim nächsten Bearbeiten nur die tatsächlich geänderten Felder hervorgehoben.",
"admin_system_backfill_btn": "Jetzt auffüllen",

View File

@@ -299,6 +299,7 @@
"history_field_receivers": "Receivers",
"history_field_tags": "Tags",
"admin_tab_system": "System",
"admin_tab_ocr": "OCR",
"admin_system_backfill_heading": "Backfill history data",
"admin_system_backfill_description": "Creates an initial history entry for all documents that do not have one yet (e.g. imported documents). This ensures that future edits only highlight actually changed fields.",
"admin_system_backfill_btn": "Backfill now",

View File

@@ -299,6 +299,7 @@
"history_field_receivers": "Destinatarios",
"history_field_tags": "Etiquetas",
"admin_tab_system": "Sistema",
"admin_tab_ocr": "OCR",
"admin_system_backfill_heading": "Completar datos de historial",
"admin_system_backfill_description": "Crea una entrada de historial inicial para todos los documentos que aún no tienen ninguna (p.ej. documentos importados). Así, en la próxima edición solo se resaltarán los campos realmente modificados.",
"admin_system_backfill_btn": "Completar ahora",

View File

@@ -122,6 +122,23 @@ function handleKeydown(event: KeyboardEvent) {
</svg>
{/snippet}
{#snippet ocrIcon()}
<svg
class="h-5 w-5 flex-shrink-0 {isActive('ocr') ? 'text-brand-mint' : 'text-white/40'}"
fill="none"
viewBox="0 0 24 24"
stroke="currentColor"
stroke-width="1.5"
aria-hidden="true"
>
<path
stroke-linecap="round"
stroke-linejoin="round"
d="M9 12h6m-6 4h6m2 5H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z"
/>
</svg>
{/snippet}
<svelte:document onkeydown={handleKeydown} />
<!--
@@ -188,6 +205,17 @@ function handleKeydown(event: KeyboardEvent) {
icon={systemIcon}
/>
{/if}
{#if canRunMaintenance}
<EntityNavSection
variant="sidebar"
href="/admin/ocr"
label={m.admin_tab_ocr()}
isActive={isActive('ocr')}
onTabletTrigger={openFlyout}
icon={ocrIcon}
/>
{/if}
</nav>
{#if flyoutOpen}
@@ -261,5 +289,16 @@ function handleKeydown(event: KeyboardEvent) {
icon={systemIcon}
/>
{/if}
{#if canRunMaintenance}
<EntityNavSection
variant="flyout"
href="/admin/ocr"
label={m.admin_tab_ocr()}
isActive={isActive('ocr')}
onFlyoutClick={closeFlyout}
icon={ocrIcon}
/>
{/if}
</div>
{/if}

View File

@@ -79,3 +79,16 @@ describe('EntityNav — flyout', () => {
await expect.element(page.getByRole('dialog')).not.toBeInTheDocument();
});
});
describe('EntityNav — OCR entry', () => {
it('renders OCR link when canRunMaintenance is true', async () => {
render(EntityNav, props);
await expect.element(page.getByRole('link', { name: /OCR/i })).toBeInTheDocument();
});
it('does not render OCR link when canRunMaintenance is false', async () => {
render(EntityNav, { ...props, canRunMaintenance: false });
const links = document.querySelectorAll('a[href="/admin/ocr"]');
expect(links.length).toBe(0);
});
});