Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion web-ui/app/_components/store/AdminUiPanel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import {
useState,
} from 'react';
import { Globe } from 'lucide-react';
import { useTranslations } from 'next-intl';

import { cn } from '../../_lib/cn';

Expand Down Expand Up @@ -80,6 +81,7 @@ export function AdminUiArticleSwap({
pluginName: string;
children: React.ReactNode;
}): React.ReactElement {
const t = useTranslations('store.adminUi');
const { open, panelId } = useAdminUi();
const ref = useRef<HTMLElement | null>(null);

Expand Down Expand Up @@ -108,7 +110,7 @@ export function AdminUiArticleSwap({
</header>
<iframe
src={iframeSrc}
title={`${pluginName} Admin UI`}
title={t('iframeTitle', { plugin: pluginName })}
className="h-[1000px] w-full rounded border border-[color:var(--rule)] bg-[color:var(--bg)]"
loading="lazy"
/>
Expand Down
10 changes: 9 additions & 1 deletion web-ui/app/_lib/i18n-structural.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,15 @@ describe('#679 / I3 — swept components carry no user-facing literals', () => {
// So the ratchet now asks the scanner the same question the CLI asks:
// does this file still contain a user-facing literal? Files join `SWEPT`
// once they answer no, and can never silently regress afterwards.
const SWEPT_COMPONENTS = ['graph/_components/ListView.tsx'];
const SWEPT_COMPONENTS = [
'graph/_components/ListView.tsx',
'graph/_components/GraphCanvas.tsx',
'admin/duplicates/[id]/page.tsx',
'admin/duplicates/excerpt/[id]/page.tsx',
'admin/inconsistencies/[id]/page.tsx',
'admin/kg-priorities/page.tsx',
'system/_components/VaultStatusCard.tsx',
];

for (const file of SWEPT_COMPONENTS) {
it(`${file} has no untranslated user-facing literal`, () => {
Expand Down
8 changes: 4 additions & 4 deletions web-ui/app/admin/duplicates/[id]/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -124,20 +124,20 @@ export default function DuplicateDetailPage(): React.ReactElement {
})}
</p>
<dl className="mt-3 grid grid-cols-[max-content_1fr] gap-x-3 gap-y-1 text-[11px]">
<dt className="text-[color:var(--fg-muted)]">Status</dt>
<dt className="text-[color:var(--fg-muted)]">{t('status')}</dt>
<dd className="font-mono">{detail.props.status}</dd>
{detail.props.resolution && (
<>
<dt className="text-[color:var(--fg-muted)]">Resolution</dt>
<dt className="text-[color:var(--fg-muted)]">{t('resolution')}</dt>
<dd className="font-mono">{detail.props.resolution}</dd>
</>
)}
</dl>
</section>

<div className="grid gap-4 lg:grid-cols-2">
<MemoryCard label="Memory A" mk={detail.mkA} />
<MemoryCard label="Memory B" mk={detail.mkB} />
<MemoryCard label={t('memoryA')} mk={detail.mkA} />
<MemoryCard label={t('memoryB')} mk={detail.mkB} />
</div>

{detail.props.status === 'open' && (
Expand Down
8 changes: 4 additions & 4 deletions web-ui/app/admin/duplicates/excerpt/[id]/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -122,11 +122,11 @@ export default function ExcerptDuplicateDetailPage(): React.ReactElement {
})}
</p>
<dl className="mt-3 grid grid-cols-[max-content_1fr] gap-x-3 gap-y-1 text-[11px]">
<dt className="text-[color:var(--fg-muted)]">Status</dt>
<dt className="text-[color:var(--fg-muted)]">{t('status')}</dt>
<dd className="font-mono">{detail.props.status}</dd>
{detail.props.resolution && (
<>
<dt className="text-[color:var(--fg-muted)]">Resolution</dt>
<dt className="text-[color:var(--fg-muted)]">{t('resolution')}</dt>
<dd className="font-mono">{detail.props.resolution}</dd>
</>
)}
Expand All @@ -135,12 +135,12 @@ export default function ExcerptDuplicateDetailPage(): React.ReactElement {

<div className="grid gap-4 lg:grid-cols-2">
<ExcerptCard
label="Excerpt A"
label={t('excerptA')}
excerpt={detail.excerptA}
parentMk={detail.mkA}
/>
<ExcerptCard
label="Excerpt B"
label={t('excerptB')}
excerpt={detail.excerptB}
parentMk={detail.mkB}
/>
Expand Down
10 changes: 5 additions & 5 deletions web-ui/app/admin/inconsistencies/[id]/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -118,22 +118,22 @@ export default function InconsistencyDetailPage(): React.ReactElement {
</h2>
<p className="text-sm">{detail.props.summary}</p>
<dl className="mt-3 grid grid-cols-[max-content_1fr] gap-x-3 gap-y-1 text-[11px]">
<dt className="text-[color:var(--fg-muted)]">Severity</dt>
<dt className="text-[color:var(--fg-muted)]">{t('severity')}</dt>
<dd className="font-mono">{detail.props.severity}</dd>
<dt className="text-[color:var(--fg-muted)]">Status</dt>
<dt className="text-[color:var(--fg-muted)]">{t('status')}</dt>
<dd className="font-mono">{detail.props.status}</dd>
{detail.props.resolution && (
<>
<dt className="text-[color:var(--fg-muted)]">Resolution</dt>
<dt className="text-[color:var(--fg-muted)]">{t('resolution')}</dt>
<dd className="font-mono">{detail.props.resolution}</dd>
</>
)}
</dl>
</section>

<div className="grid gap-4 lg:grid-cols-2">
<MemoryCard label="Memory A" mk={detail.mkA} />
<MemoryCard label="Memory B" mk={detail.mkB} />
<MemoryCard label={t('memoryA')} mk={detail.mkA} />
<MemoryCard label={t('memoryB')} mk={detail.mkB} />
</div>

{detail.props.status === 'open' && (
Expand Down
18 changes: 9 additions & 9 deletions web-ui/app/admin/kg-priorities/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,7 @@ export default function KgPrioritiesPage(): React.ReactElement {
<main className="mx-auto max-w-[1200px] px-6 py-12 lg:px-8 lg:py-16">
<header className="mb-8">
<h1 className="font-display text-[clamp(2rem,4vw,3rem)] leading-[1.1] text-[color:var(--fg-strong)]">
Knowledge-Graph Priorities
{t('title')}
</h1>
<p className="mt-3 max-w-3xl text-[16px] leading-[1.55] text-[color:var(--fg-muted)]">
{t('intro')}
Expand Down Expand Up @@ -194,8 +194,8 @@ export default function KgPrioritiesPage(): React.ReactElement {
onChange={(e) => { setDraftAction(e.target.value as 'block' | 'boost'); }}
className="lg:col-span-2 rounded-md border border-[color:var(--border)] bg-[color:var(--bg)] px-3 py-2 text-sm text-[color:var(--fg-strong)]"
>
<option value="block">block</option>
<option value="boost">boost</option>
<option value="block">{t('actionBlock')}</option>
<option value="boost">{t('actionBoost')}</option>
</select>
<input
type="number"
Expand All @@ -215,7 +215,7 @@ export default function KgPrioritiesPage(): React.ReactElement {
type="text"
value={draftReason}
onChange={(e) => { setDraftReason(e.target.value); }}
placeholder="Reason (optional)"
placeholder={t('reasonPlaceholder')}
className="lg:col-span-3 rounded-md border border-[color:var(--border)] bg-[color:var(--bg)] px-3 py-2 text-sm text-[color:var(--fg-strong)]"
/>
<Button
Expand All @@ -241,11 +241,11 @@ export default function KgPrioritiesPage(): React.ReactElement {
<table className="w-full text-sm">
<thead className="border-b border-[color:var(--border)] text-left text-[color:var(--fg-muted)]">
<tr>
<th className="px-4 py-3 font-semibold">Entry External ID</th>
<th className="px-4 py-3 font-semibold">Action</th>
<th className="px-4 py-3 font-semibold">Weight</th>
<th className="px-4 py-3 font-semibold">Reason</th>
<th className="px-4 py-3 font-semibold">Updated</th>
<th className="px-4 py-3 font-semibold">{t('colEntryExternalId')}</th>
<th className="px-4 py-3 font-semibold">{t('colAction')}</th>
<th className="px-4 py-3 font-semibold">{t('colWeight')}</th>
<th className="px-4 py-3 font-semibold">{t('colReason')}</th>
<th className="px-4 py-3 font-semibold">{t('colUpdated')}</th>
<th className="px-4 py-3"></th>
</tr>
</thead>
Expand Down
13 changes: 9 additions & 4 deletions web-ui/app/chat/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -1230,25 +1230,30 @@ function TriageBadge({
model: string;
};
}): React.ReactElement {
const t = useTranslations('chat.routing');
const verdict: Record<typeof routing.bucket, { label: string; cls: string }> = {
simple: {
label: 'einfach',
label: t('bucketSimple'),
cls: 'bg-[color:var(--success)]/10 text-[color:var(--success)] ring-[color:var(--success)]',
},
complex: {
label: 'komplex',
label: t('bucketComplex'),
cls: 'bg-[color:var(--accent)]/10 text-[color:var(--accent)] ring-[color:var(--accent)]',
},
fallback: {
label: 'Fallback',
label: t('bucketFallback'),
cls: 'bg-[color:var(--warning)]/10 text-[color:var(--warning)] ring-[color:var(--warning)]',
},
};
const v = verdict[routing.bucket];
return (
<div
className="mb-2 inline-flex flex-wrap items-center gap-2 text-[11px] text-[color:var(--fg-muted)]"
title={`Triage-Klassifizierer: ${routing.classifierModel} → ${routing.bucket} → ${routing.model}`}
title={t('classifierTooltip', {
classifier: routing.classifierModel,
bucket: routing.bucket,
model: routing.model,
})}
>
<span className="font-medium uppercase tracking-[0.12em]">Triage</span>
<span className="text-[color:var(--fg-subtle)]">
Expand Down
8 changes: 4 additions & 4 deletions web-ui/app/graph/_components/GraphCanvas.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -915,10 +915,10 @@ export default function GraphCanvas({
<div className="pointer-events-none absolute inset-0 flex items-start justify-between p-3">
<Legend dark={dark} filter={filter} />
<div className="pointer-events-auto flex flex-col gap-2 rounded-lg border border-[color:var(--border)] bg-[color:var(--bg-elevated)]/90 p-2 shadow-sm backdrop-blur">
<IconBtn title="Zoom in" onClick={zoomIn}>+</IconBtn>
<IconBtn title="Zoom out" onClick={zoomOut}>−</IconBtn>
<IconBtn title="Fit" onClick={fit}>⤢</IconBtn>
<IconBtn title="Re-Layout" onClick={relayout}>↻</IconBtn>
<IconBtn title={t('zoomIn')} onClick={zoomIn}>+</IconBtn>
<IconBtn title={t('zoomOut')} onClick={zoomOut}>−</IconBtn>
<IconBtn title={t('fit')} onClick={fit}>⤢</IconBtn>
<IconBtn title={t('relayout')} onClick={relayout}>↻</IconBtn>
</div>
</div>
{elements.length === 0 && (
Expand Down
2 changes: 1 addition & 1 deletion web-ui/app/graph/_components/ListView.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -165,7 +165,7 @@ function RunTracePanel({
{user && (
<>
<span>·</span>
<span title={`User: ${user}`}>👤 {user.slice(0, 16)}</span>
<span title={t('userTooltip', { user })}>👤 {user.slice(0, 16)}</span>
</>
)}
</div>
Expand Down
8 changes: 4 additions & 4 deletions web-ui/app/system/_components/VaultStatusCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -28,10 +28,10 @@ export async function VaultStatusCard({
<header className="flex items-baseline justify-between gap-3">
<div>
<div className="text-[11px] uppercase tracking-[0.22em] text-[color:var(--fg-subtle)]">
Encrypted Secret Vault
{t('eyebrow')}
</div>
<h2 className="font-display mt-1 text-2xl text-[color:var(--fg-strong)]">
Vault
{t('heading')}
</h2>
</div>
<StatusDot tone={keyTone} label={dotLabel(keyTone, t)} />
Expand Down Expand Up @@ -79,8 +79,8 @@ export async function VaultStatusCard({

{backup.enabled ? (
<dl className="mt-4 grid grid-cols-1 gap-x-6 gap-y-3 text-sm sm:grid-cols-2">
<Row label="Bucket" value={backup.bucket} mono />
<Row label="Prefix" value={backup.prefix} mono />
<Row label={t('bucket')} value={backup.bucket} mono />
<Row label={t('prefix')} value={backup.prefix} mono />
<Row
label={t('interval')}
value={t('intervalValue', {
Expand Down
56 changes: 48 additions & 8 deletions web-ui/messages/de.json
Original file line number Diff line number Diff line change
Expand Up @@ -1373,7 +1373,13 @@
"factHintTags": "'<palaia-hint>'-Tags"
},
"errorUpstreamErrorPage": "Der Server hat statt einer Antwort eine Fehlerseite geliefert (HTTP 500). Es hat also etwas geantwortet, der Fehler liegt serverseitig — prüfe die Middleware-Logs oder melde das deinem Betreiber.",
"errorCorrelationRef": "Referenz für den Support: {id}"
"errorCorrelationRef": "Referenz für den Support: {id}",
"routing": {
"classifierTooltip": "Triage-Klassifizierer: {classifier} → {bucket} → {model}",
"bucketSimple": "einfach",
"bucketComplex": "komplex",
"bucketFallback": "Fallback"
}
},
"privacyReceipt": {
"summary": "🛡 Privacy Shield · {summary}",
Expand Down Expand Up @@ -3156,6 +3162,9 @@
"dontSet": "(nicht setzen)",
"noPasswordWarning": "Hier gehört kein Konto-Passwort hinein. Erwartet wird ein technischer Schlüssel aus der Anbieter-Konsole.",
"patternUnavailable": "Dieses Feld deklariert eine Formatprüfung, die nicht angewendet werden konnte — der Wert wird nicht validiert."
},
"adminUi": {
"iframeTitle": "{plugin} Admin-UI"
}
},
"adminAuth": {
Expand Down Expand Up @@ -4243,7 +4252,11 @@
}
},
"openMemory": "zur Memory →",
"memoryUnavailable": "Memory nicht zugänglich (gelöscht oder kein Owner)."
"memoryUnavailable": "Memory nicht zugänglich (gelöscht oder kein Owner).",
"memoryA": "Memory A",
"memoryB": "Memory B",
"status": "Status",
"resolution": "Behebung"
},
"excerptDetail": {
"title": "Excerpt-Duplikat auflösen",
Expand Down Expand Up @@ -4273,7 +4286,11 @@
"excerptUnavailable": "Excerpt nicht zugänglich (gelöscht oder kein Owner).",
"positionLine": "Position {position} · {source}",
"quotedText": "„{text}“",
"parentMemory": "Parent-Memory: {summary}"
"parentMemory": "Parent-Memory: {summary}",
"excerptA": "Auszug A",
"excerptB": "Auszug B",
"status": "Status",
"resolution": "Behebung"
}
},
"adminInconsistencies": {
Expand Down Expand Up @@ -4332,7 +4349,12 @@
}
},
"openMemory": "zur Memory →",
"memoryUnavailable": "Memory nicht zugänglich (gelöscht oder kein Owner)."
"memoryUnavailable": "Memory nicht zugänglich (gelöscht oder kein Owner).",
"memoryA": "Memory A",
"memoryB": "Memory B",
"severity": "Schweregrad",
"status": "Status",
"resolution": "Behebung"
}
},
"adminKgLifecycle": {
Expand Down Expand Up @@ -4394,7 +4416,16 @@
"newEntryTitle": "Neuer Eintrag",
"weightIgnoredTitle": "weight ignoriert für block",
"weightMultiplierTitle": "Score-Multiplikator",
"empty": "Keine Einträge für diesen Agent."
"empty": "Keine Einträge für diesen Agent.",
"title": "Knowledge-Graph-Prioritäten",
"colEntryExternalId": "Externe Eintrags-ID",
"actionBlock": "blockieren",
"actionBoost": "hervorheben",
"reasonPlaceholder": "Grund (optional)",
"colAction": "Aktion",
"colWeight": "Gewicht",
"colReason": "Grund",
"colUpdated": "Aktualisiert"
},
"adminMemoryBackend": {
"title": "Memory · Speicher-Backend",
Expand Down Expand Up @@ -4540,7 +4571,11 @@
"excerptDuplicate": "Excerpt-Duplikat",
"planStep": "Plan-Schritt",
"hasTopicTransitive": "HAS_TOPIC (Excerpt, transitiv)"
}
},
"zoomIn": "Vergrößern",
"zoomOut": "Verkleinern",
"fit": "Einpassen",
"relayout": "Neu anordnen"
},
"detailPanel": {
"manualTitle": "manuell erfasst — Score-Boost ×1.3 im Token-Budget-Assembler",
Expand Down Expand Up @@ -4577,7 +4612,8 @@
"toolsLabel": "Tools={count}",
"iterations": "{count} Iter.",
"orchestratorTools": "Orchestrator-Tools",
"toolCalls": "{count, plural, one {# Tool-Call} other {# Tool-Calls}}"
"toolCalls": "{count, plural, one {# Tool-Call} other {# Tool-Calls}}",
"userTooltip": "Benutzer: {user}"
}
},
"memory": {
Expand Down Expand Up @@ -4786,7 +4822,11 @@
"dotDanger": "Fehler",
"dotInactive": "Inaktiv",
"keySourceDevFile": "dev-file (nicht für Produktion)",
"keySourceDevFileCreated": "dev-file (neu generiert — DEV ONLY)"
"keySourceDevFileCreated": "dev-file (neu generiert — DEV ONLY)",
"eyebrow": "Verschlüsselter Secret Vault",
"heading": "Vault",
"bucket": "Bucket",
"prefix": "Präfix"
}
},
"help": {
Expand Down
Loading
Loading