217 lines
8.1 KiB
Markdown
217 lines
8.1 KiB
Markdown
# Desktop (Pear) UI
|
||
|
||
The client shell is a **Pear desktop application** built with `pear-electron` + `pear-bridge`. The HTML UI runs inside a frameless-style window with in-content chrome.
|
||
|
||
## Entrypoints
|
||
|
||
| File | Role |
|
||
|------|------|
|
||
| `index.js` | Pear process entry — starts `pear-electron` Runtime + `pear-bridge` |
|
||
| `index.html` | GUI main (`pear.gui.main`) — titlebar + panels |
|
||
| `app.js` | UI logic (connect, fleet, live charts, invites, Data Manager wiring) |
|
||
| `ui/dashboard.js` | Charts tab master metrics wall |
|
||
| `ui/data-manager.js` | Settings → Data (retention / prune / storage usage) |
|
||
| `ui/logs.js` | System Log tab (journal default for admins) |
|
||
| `ui/qvac/*` | QVAC local AI tab (onboarding + tools; needs `@qvac/sdk` in this project) |
|
||
| `shared/taxonomy.js` | Section grouping for the metrics wall |
|
||
| `shared/container-names.js` | Human Docker/cgroup labels for the wall |
|
||
| `shared/format.js` | Overview KPI unit scaling |
|
||
| `shared/retention.js` | Retention presets shared with the agent |
|
||
| `ui/styles.css` | Layout, theme, **titlebar drag regions** |
|
||
| `client/*` | HyperDHT connection stack used by the UI |
|
||
| `docs/DASHBOARD.md` | Master Charts / metrics wall plan |
|
||
| `user-guide/` | End-user workflows (Correlate, Related, Logs, Containers, Settings, …) |
|
||
|
||
```bash
|
||
npm start # pear run -d .
|
||
npm run dev # same
|
||
pear run -d . # equivalent
|
||
```
|
||
|
||
Requires the [Pear](https://docs.pears.com) CLI installed and bootstrapped (`pear` once to fetch the runtime).
|
||
|
||
## Window configuration (`package.json` → `pear.gui`)
|
||
|
||
| Field | Template default | Purpose |
|
||
|-------|------------------|---------|
|
||
| `main` | `index.html` | HTML entry |
|
||
| `width` / `height` | `1280` / `860` | Initial size |
|
||
| `minWidth` / `minHeight` | `900` / `560` | Resize floor |
|
||
| `resizable` | `true` | Edge/corner resize |
|
||
| `movable` | `true` | Allow OS move (with drag region) |
|
||
| `minimizable` / `maximizable` / `closable` | `true` | Window buttons |
|
||
| `hasShadow` | `true` | Native shadow |
|
||
| `backgroundColor` | `#0a0c10` | Avoid white flash on boot |
|
||
| `pre` | `pear-electron/pre` | Runtime bootstrap (required) |
|
||
|
||
Platform overrides are supported:
|
||
|
||
```json
|
||
{
|
||
"pear": {
|
||
"gui": {
|
||
"darwin": { "resizable": true },
|
||
"linux": { "autoHideMenuBar": true },
|
||
"win32": { "autoHideMenuBar": true }
|
||
}
|
||
}
|
||
}
|
||
```
|
||
|
||
See [pear-electron README](https://github.com/holepunchto/pear-electron) for the full option list (`center`, `alwaysOnTop`, `transparent`, `closeHides`, etc.).
|
||
|
||
## Titlebar + `<pear-ctrl>`
|
||
|
||
Pear provides a custom element **`<pear-ctrl>`** for platform window controls:
|
||
|
||
- **macOS (`darwin`)** — layout for system traffic lights (hidden title bar chrome)
|
||
- **Windows / Linux** — minimize, maximize, close controls rendered by the runtime
|
||
|
||
### Required HTML shape
|
||
|
||
```html
|
||
<div id="titlebar" role="banner">
|
||
<div class="titlebar-left">
|
||
<pear-ctrl></pear-ctrl>
|
||
<div class="app-brand">…</div>
|
||
</div>
|
||
<div class="titlebar-right">
|
||
<!-- status chips, non-drag interactive bits -->
|
||
</div>
|
||
</div>
|
||
```
|
||
|
||
Do **not** remove `<pear-ctrl>` unless you intentionally ship a different window frame model and understand OS differences.
|
||
|
||
### Drag to move
|
||
|
||
```css
|
||
#titlebar {
|
||
-webkit-app-region: drag;
|
||
height: var(--titlebar-h); /* 42px in this template */
|
||
}
|
||
|
||
/* Interactive controls must not start a drag */
|
||
#titlebar pear-ctrl,
|
||
#titlebar .chip,
|
||
#titlebar button,
|
||
#titlebar input,
|
||
#titlebar a {
|
||
-webkit-app-region: no-drag;
|
||
}
|
||
|
||
.no-drag {
|
||
-webkit-app-region: no-drag;
|
||
}
|
||
```
|
||
|
||
### Resize
|
||
|
||
- Enabled by `pear.gui.resizable: true` (default in this template).
|
||
- Users resize via the OS window edges/corners.
|
||
- Content layout should flex with the viewport (`#app` uses `height: calc(100vh - var(--titlebar-h))`).
|
||
|
||
### Platform spacing
|
||
|
||
Reserve space so brand/text never sits under traffic lights:
|
||
|
||
```css
|
||
#titlebar pear-ctrl[data-platform='darwin'] { min-width: 78px; }
|
||
#titlebar pear-ctrl[data-platform='win32'],
|
||
#titlebar pear-ctrl[data-platform='linux'] { min-width: 110px; }
|
||
```
|
||
|
||
## Client identity (desktop process)
|
||
|
||
When the UI dials servers it uses a **persistent Ed25519 identity**:
|
||
|
||
| Item | Value |
|
||
|------|--------|
|
||
| Path | `~/.config/peardata/identity.json` (or `$PEARDATA_HOME/.config/peardata/…` if you set `PEARDATA_HOME` as home root — see `client/identity.js`) |
|
||
| Mode | Directory `0700`, file `0600` |
|
||
| Contents | `{ version, seedHex, createdAt }` |
|
||
|
||
Same identity ⇒ same `peerId` across restarts (useful for peer-bound capabilities and revoke).
|
||
|
||
Override home with `PEARDATA_HOME` if you need isolation (CI, multi-profile).
|
||
|
||
## UI modules
|
||
|
||
| Module | Responsibility |
|
||
|--------|----------------|
|
||
| `client/paths.js` | Unified `~/.config/peardata` home |
|
||
| `client/jsonCache.js` | Atomic JSON writes + LS mirror |
|
||
| `client/settings.js` | UI prefs → `cache/settings.json` |
|
||
| `client/peerCache.js` | Multi-host roster + last-active |
|
||
| `client/bookmarks.js` | Compat shim over peerCache |
|
||
| `client/identity.js` | Load/create keypair on disk |
|
||
| `client/connection.js` | Single HyperDHT + protomux-rpc session |
|
||
| `client/manager.js` | Multi-peer map, active selection, reconnect |
|
||
| `client/errors.js` | Unwrap / normalize RPC errors for UI |
|
||
| `app.js` | Wire DOM to manager + protocol methods |
|
||
|
||
## Persistence (PearDock-style)
|
||
|
||
| Store | Path |
|
||
|-------|------|
|
||
| Settings | `~/.config/peardata/cache/settings.json` (+ `localStorage` `peardata.settings.v1` FOUC) |
|
||
| Peers / last-active | `~/.config/peardata/cache/peers.json` |
|
||
| Identity | `~/.config/peardata/identity.json` |
|
||
|
||
Override root with `PEARDATA_HOME`. Writes are atomic (`tmp` → rename, mode `0600`). Legacy `bookmarks.json` / `ui-settings.json` migrate on first load.
|
||
|
||
### Multi-agent
|
||
|
||
- Many peers can be dialed at once; **one active** owns Overview / Charts RPC.
|
||
- Boot restores saved peers in parallel (`skipActivate`), then prefers last-active.
|
||
- Reconnect never steals the active host unless that host was active.
|
||
- Agents view + fleet strip: set active / connect / forget.
|
||
- Settings → Connections: auto-restore toggle, reconnect budget, forget-all.
|
||
|
||
### Manager reconnect
|
||
|
||
- Default max tries: settings `reconnectMaxAttempts` or `PEARDATA_MAX_RECONNECT` / **20**
|
||
- `connect(input, { adminSeed, autoReconnect, skipActivate })`
|
||
- Input may be **64-hex public key** or **`pd1.` invite**
|
||
|
||
## LocalStorage mirrors
|
||
|
||
| Key | Purpose |
|
||
|-----|---------|
|
||
| `peardata.settings.v1` | Flat settings FOUC + offline mirror |
|
||
| `peardata-ui-boot` | Theme-only early paint |
|
||
| `peardata_active_peer_id` | Last active peer mirror |
|
||
| `peardata.cache.peers` | Peers envelope mirror |
|
||
|
||
## Development tips
|
||
|
||
1. Keep DevTools available via `pear run -d .`
|
||
2. After HTML/CSS/JS edits, reload the Pear window (or restart `npm start`)
|
||
3. Server changes require restarting `npm run start:server`
|
||
4. If the window cannot be moved: check `#titlebar` has `drag` and children that cover the bar incorrectly are not all `no-drag` without a parent drag region
|
||
5. If controls don’t work: ensure `<pear-ctrl>` is present and not covered by another element with a higher z-index and full-width hit target
|
||
|
||
## Packaging beyond Pear
|
||
|
||
This template ships the **Pear run** path only. For Electron-forge / multi-arch standalone binaries, adapt packaging from a fuller product (e.g. peardock’s forge + bare-standalone scripts) once the app stabilizes.
|
||
|
||
## Charts investigation (summary)
|
||
|
||
| Control | Doc |
|
||
|---------|-----|
|
||
| Metrics wall, time, board, gestures | [user-guide/charts.md](../user-guide/charts.md) · [DASHBOARD.md](./DASHBOARD.md) |
|
||
| **Correlate** (highlight → Find Correlations) | [user-guide/metric-correlations.md](../user-guide/metric-correlations.md) |
|
||
| **Related (⇢)** (taxonomy + Pearson) | [user-guide/related-metrics.md](../user-guide/related-metrics.md) |
|
||
| **Filters** menu (search / TOC / group / sort) | [user-guide/charts.md](../user-guide/charts.md) |
|
||
| **Logs** tab | [user-guide/logs.md](../user-guide/logs.md) |
|
||
|
||
Implementation: `ui/dashboard.js`, `ui/logs.js`, `server/services/weights.js`, `server/services/logs.js`, `shared/related-metrics.js`.
|
||
|
||
## Related
|
||
|
||
- [User guide](../user-guide/README.md)
|
||
- [GETTING-STARTED.md](./GETTING-STARTED.md)
|
||
- [ARCHITECTURE.md](./ARCHITECTURE.md)
|
||
- [CONFIGURATION.md](./CONFIGURATION.md)
|
||
- [EXTENDING.md](./EXTENDING.md)
|