From 346d23d4d8fc9cc3270a63cf66cf46a9e7240297 Mon Sep 17 00:00:00 2001 From: Scott Reimers Date: Thu, 14 May 2026 22:32:30 -0600 Subject: [PATCH] ux: Friend-button default + profile-rename plumbing + export/import clarity MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Three of the v0.7.0 device-testing feedback items, deferred for later rebuild/redeploy (Scott opted to batch UI fixes). (#1) Friend button on bio modal: - Primary action when neither following nor vouched: [Friend] (= follow + vouch in one click) plus secondary [Follow only]. - When following without a vouch: [Add Vouch] primary, [Unfollow] secondary. - When both follow + vouch (= friends): [Unfriend] (= revoke vouch + unfollow, with the rotation-cost confirm wording). - The standalone [Vouch] / [Revoke Vouch] flows stay reachable from the existing Vouches list in Settings. (#2) Profile shows "unnamed" — bug fix: - set_profile updated the profiles table + emitted a profile post, but never updated posting_identities.display_name. list_posting_ identities returns from the latter, so the Personas list kept showing "(unnamed)" forever after the first-run auto-persona was named. - Now set_profile also upserts the posting_identities row with the new display_name (secret_seed + created_at preserved). (#5) Export/import + persona-vs-device clarity: - Settings reorder: new "Your data on this device" explainer card up top (Personas = who you are to peers; Identities = device's network address, rarely useful to touch). - "Move to another device" section renamed + given a plain-English description; primary [Export personas] / [Import from another device] buttons. - "Identities (advanced)" demoted below; warning text added. - Export wizard heading: "Export your personas"; radio labels use persona/keys language consistently. - Import wizard heading: "Import from another device"; explainer notes that the default action restores personas. Tracking memory created at memory/project_v071_followups.md for deferred items (#4 PQ vouch delivery, #6 rename, #7 redundancy, #8/#9/#10 awaiting clarification). Co-Authored-By: Claude Opus 4.7 (1M context) --- crates/core/src/node.rs | 14 ++++++++++ frontend/app.js | 61 +++++++++++++++++++++++++++-------------- frontend/index.html | 34 +++++++++++++++++------ 3 files changed, 79 insertions(+), 30 deletions(-) diff --git a/crates/core/src/node.rs b/crates/core/src/node.rs index 7c90407..8dd0d46 100644 --- a/crates/core/src/node.rs +++ b/crates/core/src/node.rs @@ -1793,6 +1793,20 @@ impl Node { } } } + // Keep posting_identities.display_name in sync with the + // profile post so the Personas list and any UI reading + // PostingIdentity sees the current name (not the original + // empty/auto-gen one). The upsert preserves the persona's + // secret_seed / created_at; only display_name changes. + if let Ok(Some(existing)) = storage.get_posting_identity(&posting_id) { + let updated = crate::types::PostingIdentity { + node_id: existing.node_id, + secret_seed: existing.secret_seed, + display_name: display_name.clone(), + created_at: existing.created_at, + }; + let _ = storage.upsert_posting_identity(&updated); + } } // Propagate via neighbor-manifest header diffs like any other post. diff --git a/frontend/app.js b/frontend/app.js index 1840b8e..5bf2922 100644 --- a/frontend/app.js +++ b/frontend/app.js @@ -1687,12 +1687,13 @@ async function openBioModal(nodeId, preloadedName) { ${bio ? `

${escapeHtml(bio)}

` : '

No bio.

'}
- ${following - ? `` - : ``} - ${isVouched - ? `` - : ``} + ${(following && isVouched) + ? `` + : (following + ? ` + ` + : ` + `)} ${isIgnored ? `` @@ -1749,16 +1750,34 @@ async function openBioModal(nodeId, preloadedName) { } catch (e) { toast('Error: ' + e); } finally { vouch.disabled = false; } }; - const revokeVouch = document.getElementById('bio-revoke-vouch'); - if (revokeVouch) revokeVouch.onclick = async () => { - if (!confirm(`Revoke vouch for ${name}? This rotates your vouch key — they keep access to existing posts but not future ones.`)) return; - revokeVouch.disabled = true; + // Friend = follow + vouch in one click. Default action per v0.7.x UX. + const friend = document.getElementById('bio-friend'); + if (friend) friend.onclick = async () => { + friend.disabled = true; + try { + await invoke('follow_node', { nodeIdHex: nodeId }); + await invoke('vouch_for_peer', { nodeIdHex: nodeId }); + toast(`Friended ${name}`); + close(); + loadFollows(); + loadFeed(true); + } catch (e) { toast('Error: ' + e); } + finally { friend.disabled = false; } + }; + // Unfriend = revoke vouch + unfollow. Rotation cost is real; confirm. + const unfriend = document.getElementById('bio-unfriend'); + if (unfriend) unfriend.onclick = async () => { + if (!confirm(`Unfriend ${name}? This revokes your vouch (rotates your vouch key — they keep access to existing posts but not future ones) AND unfollows them.`)) return; + unfriend.disabled = true; try { await invoke('revoke_vouch_for_peer', { nodeIdHex: nodeId }); - toast('Revoked and rotated'); + await invoke('unfollow_node', { nodeIdHex: nodeId }); + toast(`Unfriended ${name}`); close(); + loadFollows(); + loadFeed(true); } catch (e) { toast('Error: ' + e); } - finally { revokeVouch.disabled = false; } + finally { unfriend.disabled = false; } }; } catch (e) { bodyEl.innerHTML = `

Error: ${e}

`; @@ -4041,14 +4060,14 @@ $('#export-btn').addEventListener('click', () => { overlay.className = 'image-lightbox'; overlay.style.cursor = 'default'; overlay.innerHTML = ` -
-

Export Data

-

Choose what to include in the export ZIP.

+
+

Export your personas

+

Save your personas + (optionally) your posts to a ZIP file so you can import them on another device.

- - - - + + + +
@@ -4118,8 +4137,8 @@ $('#import-btn').addEventListener('click', () => { overlay.style.cursor = 'default'; overlay.innerHTML = `
-

Import Data

-

Select an ItsGoin export ZIP file.

+

Import from another device

+

Select an ItsGoin export ZIP. Default action restores the exported personas onto this device so you can post as them.

diff --git a/frontend/index.html b/frontend/index.html index e415fd8..ba80394 100644 --- a/frontend/index.html +++ b/frontend/index.html @@ -231,13 +231,13 @@
-
-

Identities

-
-
- - -
+
+

Your data on this device

+

+ Personas are who you are to peers — the keys you post and message with. Most people only need one. To move your account to a new device, you export your personas from this device and import them on the new one. +

+ Identities below are this device's own network address — usually not what you want to move. Leave them alone unless you know why you're touching them. +

@@ -248,9 +248,25 @@
+

Move to another device

+

+ Export creates a ZIP containing your personas (and optionally posts/follows). Import on the other device's Settings > Move to another device. +

- - + + +
+
+ +
+

Identities (advanced)

+

+ This device's network address. Changing this is rarely useful — it lets you move the device's QUIC endpoint, NOT your posting identity. +

+
+
+ +