<script>
import { formatBytes, formatCount } from './lib/format.js'
let status = $state(null)
let error = $state(null)
async function load() {
try {
const resp = await fetch('/ui/status')
if (!resp.ok) throw new Error(`HTTP ${resp.status}`)
status = await resp.json()
error = null
} catch (e) {
error = e.message
}
}
$effect(() => {
load()
const timer = setInterval(load, 30000)
return () => clearInterval(timer)
})
const stats = $derived(
status
? [
{ label: 'Items', value: formatCount(status.library.items) },
{ label: 'Attachments', value: formatCount(status.library.attachments) },
{ label: 'Notes', value: formatCount(status.library.notes) },
{ label: 'Collections', value: formatCount(status.library.collections) },
{ label: 'Tags', value: formatCount(status.library.tags) },
{ label: 'In trash', value: formatCount(status.library.trashed) },
{ label: 'Files', value: formatCount(status.library.files) },
{ label: 'Stored', value: formatBytes(status.library.fileBytes) },
]
: [],
)
</script>
{#if error}
<p class="rounded-md border border-destructive/50 p-4 text-destructive">
Could not load the server status: {error}
</p>
{:else if !status}
<p class="text-muted-foreground">Loading…</p>
{:else}
<section class="space-y-2">
<h1 class="text-2xl font-semibold tracking-tight">Library</h1>
<p class="text-sm text-muted-foreground">
Library version {formatCount(status.library.version)} · user {status.userId} ·
defter {status.version} · commonmeta {status.commonmetaVersion}
</p>
</section>
<section class="mt-6 grid grid-cols-2 gap-3 sm:grid-cols-4">
{#each stats as stat (stat.label)}
<div class="rounded-lg border bg-card p-4">
<div class="text-xs uppercase tracking-wide text-muted-foreground">{stat.label}</div>
<div class="mt-1 text-2xl font-semibold tabular-nums">{stat.value}</div>
</div>
{/each}
</section>
<section class="mt-8 rounded-lg border bg-card p-5 space-y-2">
<h2 class="font-semibold">Attachment storage</h2>
<p class="text-sm">
<code class="rounded bg-muted px-1.5 py-0.5">{status.storage.location}</code>
</p>
<p class="text-sm text-muted-foreground">
{status.storage.signedDownloads
? 'Clients download files directly from the bucket through pre-signed URLs.'
: 'Downloads are streamed through this server.'}
Files up to {formatBytes(status.storage.maxUpload)} are accepted.
</p>
</section>
<section class="mt-4 rounded-lg border bg-card p-5 space-y-3">
<h2 class="font-semibold">Connect Zotero</h2>
<p class="text-sm text-muted-foreground">
In Zotero, open Settings → Advanced → Config Editor and set:
</p>
<pre class="overflow-x-auto rounded-md bg-muted p-3 text-sm"><code
>extensions.zotero.api.url = {status.apiUrl}/
extensions.zotero.streaming.enabled = false</code
></pre>
<p class="text-sm text-muted-foreground">
Then log in under Settings → Sync and approve the request on this server.
</p>
</section>
<section class="mt-4 rounded-lg border bg-card p-5 space-y-3">
<h2 class="font-semibold">Enrich with commonmeta</h2>
<p class="text-sm text-muted-foreground">
commonmeta sync talks to the same API (see <code>docs/commonmeta-rs-changes.md</code> for
the commonmeta release that supports a remote server):
</p>
<pre class="overflow-x-auto rounded-md bg-muted p-3 text-sm"><code
>commonmeta sync --zotero-url {status.apiUrl}</code
></pre>
</section>
{/if}