Peering: end-user "Send to peer" UI #105

Closed
opened 2026-08-04 11:04:30 +00:00 by Cordy · 2 comments
Owner

The user-facing sliver, exactly as Manuel framed it: "Der Endbenutzer sieht bei dem Senden von einer Datei zu seinem Empfänger nur ein Dropdown mit den Instanzen, die der Admin in die Peeringliste eingetragen hat."

Scope:

  • Row-actions menu (⋯) gains "Send to peer…" — feature-detected: hidden entirely when no peers are registered (boot-probe pattern like feat.spaces).
  • Dialog: peer dropdown (from #101's registry), recipient username field, confirm. Submits to #103's async API, shows a toast, and the dialog links to a small Transfers view (list from GET /api/v1/peering/transfers: file, peer, recipient, status, failure reason).
  • Received side: Inbox just appears as a normal folder (#104) — no new nav item in v1; optional "new file" badge per #104's notification decision.
  • i18n en/de/fr/it.

Open questions:

  • Recipient input UX: free-text only (validated at submit — the enemy of typos) vs a "check recipient" button that calls the #102 verification pre-send. Depends on the enumeration decision in #102; the button is the better UX if probing by authenticated peers is accepted.
  • Where does the Transfers view live: avatar menu (like App passwords) or inside the send dialog only? Recommend avatar menu once transfers exist for the user, hidden otherwise.
  • Failed-transfer retry button in the list (calls send again with same params) — v1 or later?
  • Do we show inbound transfers to the RECIPIENT in the same view ("Received from Omega, 2 files") or is the Inbox folder itself enough in v1? Recommend: folder is enough.
The user-facing sliver, exactly as Manuel framed it: "Der Endbenutzer sieht bei dem Senden von einer Datei zu seinem Empfänger nur ein Dropdown mit den Instanzen, die der Admin in die Peeringliste eingetragen hat." **Scope:** - Row-actions menu (⋯) gains **"Send to peer…"** — feature-detected: hidden entirely when no peers are registered (boot-probe pattern like `feat.spaces`). - Dialog: peer dropdown (from #101's registry), recipient username field, confirm. Submits to #103's async API, shows a toast, and the dialog links to a small **Transfers** view (list from `GET /api/v1/peering/transfers`: file, peer, recipient, status, failure reason). - Received side: **Inbox** just appears as a normal folder (#104) — no new nav item in v1; optional "new file" badge per #104's notification decision. - i18n en/de/fr/it. **Open questions:** - Recipient input UX: free-text only (validated at submit — the enemy of typos) vs a "check recipient" button that calls the #102 verification pre-send. Depends on the enumeration decision in #102; the button is the better UX if probing by authenticated peers is accepted. - Where does the Transfers view live: avatar menu (like App passwords) or inside the send dialog only? Recommend avatar menu once transfers exist for the user, hidden otherwise. - Failed-transfer retry button in the list (calls send again with same params) — v1 or later? - Do we show inbound transfers to the RECIPIENT in the same view ("Received from Omega, 2 files") or is the Inbox folder itself enough in v1? Recommend: folder is enough.
Author
Owner

Carried here from closed issues — two things this UI must cover

1. Inbox notification (from #104)

#104 asked "how does the recipient learn a file arrived?" and it is the one question from that issue not resolved by the implementation. Today a recipient finds out by opening their Inbox and noticing. That is a real gap, not a deferral, and closing #104 should not have made it disappear.

#104's own recommendation, which I would keep: a UI badge fed by a newest-inbox-mtime probe. No mailer — Cairn has none, and adding one for this would be a dependency out of all proportion to the feature. The probe is cheap: Stat on /home/<user>/Inbox, compare against a last-seen timestamp held client-side.

Worth deciding as part of the interaction design rather than bolted on: does the badge count files or just say "something new"? Counting means walking the inbox on every poll, which is a bounded but real cost on a large one.

2. Admin warning: group-only receivers lists (from #123)

CanReceive takes groups as a parameter rather than resolving them, because the recipient is not authenticated — they are a name on the wire with no session to read live groups from. The wiring currently passes nil.

Consequence: user-based receivers lists work in every auth mode; group-based lists only work where the IdP admin client is configured. Without it, a group-only list matches nobody. That is correctly fail-closed, but silently useless — and the failure surfaces on the peer's side as STATUS_UNKNOWN_RECIPIENT, which is the worst possible place to debug it.

The admin peering UI should either refuse to save a group-only receivers list when the admin client is absent, or warn plainly at save time. Cheaper to prevent than to diagnose from another instance.

Already available for this UI

GET /api/v1/peering/peers returns only the peers the caller may actually send to, as a projection that deliberately excludes the peering key — so the dropdown offers exactly what will work and leaks no credential. GET /api/v1/peering/transfers returns the caller's own transfers with pending / streaming / done / failed + reason, scoped to the owner.

Still needs your interaction design

Where the send entry point lives (per-row action, detail pane, multi-select), whether folder-send is offered at all given v1 is files-only, and what the transfer list looks like — inline in the file browser, a sidebar view, or its own page.

## Carried here from closed issues — two things this UI must cover ### 1. Inbox notification (from #104) #104 asked "how does the recipient learn a file arrived?" and it is the one question from that issue **not** resolved by the implementation. Today a recipient finds out by opening their Inbox and noticing. That is a real gap, not a deferral, and closing #104 should not have made it disappear. #104's own recommendation, which I would keep: a **UI badge fed by a newest-inbox-mtime probe**. No mailer — Cairn has none, and adding one for this would be a dependency out of all proportion to the feature. The probe is cheap: `Stat` on `/home/<user>/Inbox`, compare against a last-seen timestamp held client-side. Worth deciding as part of the interaction design rather than bolted on: does the badge count *files* or just say "something new"? Counting means walking the inbox on every poll, which is a bounded but real cost on a large one. ### 2. Admin warning: group-only `receivers` lists (from #123) `CanReceive` takes groups as a parameter rather than resolving them, because the recipient is **not authenticated** — they are a name on the wire with no session to read live groups from. The wiring currently passes `nil`. Consequence: **user-based `receivers` lists work in every auth mode; group-based lists only work where the IdP admin client is configured.** Without it, a group-only list matches nobody. That is correctly fail-closed, but silently useless — and the failure surfaces on the *peer's* side as `STATUS_UNKNOWN_RECIPIENT`, which is the worst possible place to debug it. The admin peering UI should either refuse to save a group-only `receivers` list when the admin client is absent, or warn plainly at save time. Cheaper to prevent than to diagnose from another instance. ## Already available for this UI `GET /api/v1/peering/peers` returns only the peers the caller may actually send to, as a projection that deliberately excludes the peering key — so the dropdown offers exactly what will work and leaks no credential. `GET /api/v1/peering/transfers` returns the caller's own transfers with `pending` / `streaming` / `done` / `failed` + reason, scoped to the owner. ## Still needs your interaction design Where the send entry point lives (per-row action, detail pane, multi-select), whether folder-send is offered at all given v1 is files-only, and what the transfer list looks like — inline in the file browser, a sidebar view, or its own page.
Cordy referenced this issue from a commit 2026-08-06 23:35:39 +00:00
Cordy referenced this issue from a commit 2026-08-06 23:54:04 +00:00
Cordy referenced this issue from a commit 2026-08-06 23:55:51 +00:00
Cordy closed this issue 2026-08-07 00:05:33 +00:00
Author
Owner

Implemented — closing

PR #128, built to the approved wireframe, all inside web/static/index.html following its own patterns.

Shipped: per-row download + share quick actions (Nikola's addition — promoted from the ⋯ menu, folders excluded), "Send to peer" in the ⋯ menu gated on feat.peerSend (probed via GET /peering/peers at boot — 200 shows the surface, 404/401 hides everything, no new server code), the two-field send dialog with in-dialog errors, the Transfers sidebar view modelled on openTrashView with state chips and failure reasons, and the inbox dot — one list call per minute against a localStorage watermark, cleared by viewing the Inbox. All strings in EN/DE/FR/IT. Fixed in passing: um-peering's duplicate data-i18n attribute, which had it mislabelled "License".

Deliberately not here:

  • The admin warning for group-only receivers lists → split to #129 so it survives this issue closing.
  • Visual verification: post-conditions and node --check prove structure, not layout. First real render lands on the dogfood with the next tag; v0.6 beta is the declared design-review point, and Nikola will raise whatever it surfaces.

The known sharp edge, by design: the recipient field is free text (no cross-instance roster exists), so a typo becomes a failed transfer with UNKNOWN_RECIPIENT visible in the Transfers view.

## Implemented — closing PR #128, built to the approved wireframe, all inside `web/static/index.html` following its own patterns. **Shipped:** per-row download + share quick actions (Nikola's addition — promoted from the ⋯ menu, folders excluded), "Send to peer" in the ⋯ menu gated on `feat.peerSend` (probed via `GET /peering/peers` at boot — 200 shows the surface, 404/401 hides everything, no new server code), the two-field send dialog with in-dialog errors, the **Transfers** sidebar view modelled on `openTrashView` with state chips and failure reasons, and the **inbox dot** — one list call per minute against a `localStorage` watermark, cleared by viewing the Inbox. All strings in EN/DE/FR/IT. Fixed in passing: `um-peering`'s duplicate `data-i18n` attribute, which had it mislabelled "License". **Deliberately not here:** - The admin warning for group-only `receivers` lists → split to **#129** so it survives this issue closing. - Visual verification: post-conditions and `node --check` prove structure, not layout. First real render lands on the dogfood with the next tag; v0.6 beta is the declared design-review point, and Nikola will raise whatever it surfaces. The known sharp edge, by design: the recipient field is free text (no cross-instance roster exists), so a typo becomes a failed transfer with `UNKNOWN_RECIPIENT` visible in the Transfers view.
Sign in to join this conversation.
No labels
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference: Cordy/Cairn#105
No description provided.