/*
* SysDeck - Photos Panel (v0.0.35)
* Author: Jeremy Anderson (https://dcos.net)
*
* v0.0.35 directive: "as well as a photo manager of equal quality.
* with its own module." Following the Jellyfin pattern: each
* supported backend ships as a systemd service with a built-in admin
* web UI; the bridge starts/stops/restarts the service via systemctl
* and the panel iframes the running admin UI. Equal quality means
* the same service-control + iframe-load shape as Jellyfin.
*
* Multi-backend design — same shape as the DB Control module
* (plugins/sysdeck-db/db.js): the operator chooses the backend
* installed on the host; the bridge auto-detects each backend via
* CLI availability and/or systemd unit presence.
*
* Supported backends (see bridge/photos.py BACKEND_REGISTRY):
* PhotoPrism — single Go binary · MIT · port 2342
* Piwigo — single PHP-FPM app · GPL-2.0 · port 80
* Lychee — single PHP-FPM app · MIT · port 80
* Nextcloud Memories — Nextcloud plugin · AGPL-3.0 · port 80
* LibrePhotos — Django + React · MIT · port 3000
*
* Excluded (intentionally): NFS-mounted photo libraries (no admin
* panel — use the Remote FS module for storage management), Amanda
* (backup system, not a photo manager), Google Photos / iCloud /
* etc. (cloud-only, no on-host admin panel reachable).
*
* Bridge surface (see shared/bridge.js → bridge.photos):
* summary() → {backends, totalBackends, installedCount, runningCount}
* status(id) → single-backend detail dict
* start(id) → {action, rc, success, output, stderr}
* stop(id) → same shape
* restart(id) → same shape
* webStatus(id) → {running, url, port, ...}
*/
export async function mount(panel, { bridge, EventBus }) {
panel.innerHTML = renderSkeleton();
let summary = {};
try {
summary = await bridge.photos.summary();
} catch (err) {
panel.innerHTML = renderError(err);
return;
}
const backends = summary.backends || [];
const installed = backends.filter((b) => b.status !== 'uninstalled');
const running = backends.filter((b) => b.status === 'running');
panel.innerHTML = `
Self-hosted photo & album management · multi-backend
· ${summary.totalBackends || backends.length} supported
· ${summary.installedCount || installed.length} installed
· ${summary.runningCount || running.length} running
Photo Manager
The bridge runs systemctl start/stop/restart for
the chosen backend via the cockpit superuser channel (polkit
org.sysdeck.photos.modify). The admin UI loads in
an iframe once the service is running. Each backend is a
separate process — no third-party code is bundled in the suite.
No photo backends registered.
Not installed. ${escapeHtml(b.name)} is ${escapeHtml(b.license)} licensed — ${escapeHtml(b.homepage)}
${escapeHtml(b.installHint)}
| Status | ${statusBadge(b.status)} |
|---|---|
| Service | ${escapeHtml(b.serviceUnit || '—')} |
| Port | ${b.port} |
| URL | ${running ? `${escapeHtml(b.url)}` : '— (service stopped)'} |
| License | ${escapeHtml(b.license)} · ${escapeHtml(b.homepage)} |
Click ▶ Start to launch ${escapeHtml(b.name)}. The admin UI will load in an iframe below.
`}${escapeHtml(String(err.message || err))}. Ensure the bridge helper is installed at /usr/lib/sysdeck/bridge/photos.py.