From 80e42596b31b74aa0a512d1c3d27f96a25de7c95 Mon Sep 17 00:00:00 2001 From: Jeff Emmett Date: Tue, 3 Mar 2026 13:29:01 -0800 Subject: [PATCH] fix: normalize visibility enums + tab tracking across remaining files Update remaining references from legacy 4-value visibility model (public/public_read/authenticated/members_only) to simplified 3-value model (public/permissioned/private) in rInbox, rVote, identity component, admin panel, and create-space page. Add tab trackRecent calls in shell. Co-Authored-By: Claude Opus 4.6 --- ONTOLOGY.md | 4 ++-- modules/rinbox/mod.ts | 2 +- modules/rvote/components/folk-vote-dashboard.ts | 4 ++-- modules/rvote/mod.ts | 4 ++-- server/shell.ts | 3 +++ shared/components/rstack-identity.ts | 14 +++++++------- website/admin.html | 17 +++++++---------- website/create-space.html | 7 +++---- 8 files changed, 27 insertions(+), 28 deletions(-) diff --git a/ONTOLOGY.md b/ONTOLOGY.md index 4b30007..cb1612d 100644 --- a/ONTOLOGY.md +++ b/ONTOLOGY.md @@ -154,8 +154,8 @@ A **space** is a collaborative context — a team, community, project, or individual workspace. Each space has: - **Slug** + optional subdomain (`alice.rspace.online`) -- **Visibility**: `public` | `public_read` | `authenticated` | `members_only` -- **Members**: `viewer` → `participant` → `moderator` → `admin` +- **Visibility**: `public` (👁 green — anyone reads, sign in to write) | `permissioned` (🔑 yellow — sign in to read & write) | `private` (🔒 red — invite-only) +- **Members**: `viewer` → `member` → `moderator` → `admin` - **Enabled modules**: which rApps are available in this space - **Module scoping**: per-module `space` (data lives in space) vs `global` (data follows identity) diff --git a/modules/rinbox/mod.ts b/modules/rinbox/mod.ts index 71bf9d2..a2686c4 100644 --- a/modules/rinbox/mod.ts +++ b/modules/rinbox/mod.ts @@ -280,7 +280,7 @@ routes.post("/api/mailboxes", async (c) => { try { claims = await verifyEncryptIDToken(token); } catch { return c.json({ error: "Invalid token" }, 401); } const body = await c.req.json(); - const { slug, name, email, description, visibility = "members_only", imap_user, imap_password } = body; + const { slug, name, email, description, visibility = "private", imap_user, imap_password } = body; if (!slug || !name || !email) return c.json({ error: "slug, name, email required" }, 400); if (!/^[a-z0-9-]+$/.test(slug)) return c.json({ error: "Invalid slug" }, 400); diff --git a/modules/rvote/components/folk-vote-dashboard.ts b/modules/rvote/components/folk-vote-dashboard.ts index 645200c..60ce32d 100644 --- a/modules/rvote/components/folk-vote-dashboard.ts +++ b/modules/rvote/components/folk-vote-dashboard.ts @@ -58,7 +58,7 @@ class FolkVoteDashboard extends HTMLElement { slug: "community", name: "Community Governance", description: "Proposals for the rSpace ecosystem", - visibility: "public_read", + visibility: "public", promotion_threshold: 100, voting_period_days: 7, credits_per_day: 10, @@ -328,7 +328,7 @@ class FolkVoteDashboard extends HTMLElement {
${this.esc(s.name)}
- ${s.visibility === "public_read" ? "Public" : s.visibility} + ${s.visibility === "public" ? "👁 Public" : s.visibility === "permissioned" ? "🔑 Permissioned" : s.visibility === "private" ? "🔒 Private" : s.visibility}
${this.esc(s.description || "")}
diff --git a/modules/rvote/mod.ts b/modules/rvote/mod.ts index a37dd6c..a7ee473 100644 --- a/modules/rvote/mod.ts +++ b/modules/rvote/mod.ts @@ -65,7 +65,7 @@ function ensureSpaceConfigDoc(space: string): ProposalDoc { name: '', description: '', ownerDid: '', - visibility: 'public_read', + visibility: 'public', promotionThreshold: 100, votingPeriodDays: 7, creditsPerDay: 10, @@ -281,7 +281,7 @@ routes.post("/api/spaces", async (c) => { try { claims = await verifyEncryptIDToken(token); } catch { return c.json({ error: "Invalid token" }, 401); } const body = await c.req.json(); - const { name, slug, description, visibility = "public_read" } = body; + const { name, slug, description, visibility = "public" } = body; if (!name || !slug) return c.json({ error: "name and slug required" }, 400); if (!/^[a-z0-9-]+$/.test(slug)) return c.json({ error: "Invalid slug" }, 400); diff --git a/server/shell.ts b/server/shell.ts index e116ccd..6a5750e 100644 --- a/server/shell.ts +++ b/server/shell.ts @@ -291,6 +291,8 @@ export function renderShell(opts: ShellOptions): string { // Render all tabs with the current one active tabBar.setLayers(layers); tabBar.setAttribute('active', 'layer-' + currentModuleId); + // Track current module as recently used + if (tabBar.trackRecent) tabBar.trackRecent(currentModuleId); // Helper: save current tab list to localStorage function saveTabs() { @@ -576,6 +578,7 @@ export function renderExternalAppShell(opts: ExternalAppShellOptions): string { localStorage.setItem(TABS_KEY, JSON.stringify(layers)); tabBar.setLayers(layers); tabBar.setAttribute('active', 'layer-' + currentModuleId); + if (tabBar.trackRecent) tabBar.trackRecent(currentModuleId); function saveTabs() { localStorage.setItem(TABS_KEY, JSON.stringify(layers)); } tabBar.addEventListener('layer-switch', (e) => { saveTabs(); window.location.href = window.__rspaceNavUrl(spaceSlug, e.detail.moduleId); }); tabBar.addEventListener('layer-add', (e) => { const { moduleId } = e.detail; if (!layers.find(l => l.moduleId === moduleId)) layers.push(makeLayer(moduleId, layers.length)); saveTabs(); window.location.href = window.__rspaceNavUrl(spaceSlug, moduleId); }); diff --git a/shared/components/rstack-identity.ts b/shared/components/rstack-identity.ts index ead7482..631307c 100644 --- a/shared/components/rstack-identity.ts +++ b/shared/components/rstack-identity.ts @@ -1300,17 +1300,17 @@ export class RStackIdentity extends HTMLElement { }; const visInfo = (v: string) => - v === "members_only" ? { icon: "🔒", cls: "vis-private", label: "private" } - : v === "authenticated" ? { icon: "🔑", cls: "vis-permissioned", label: "permissioned" } + v === "private" ? { icon: "🔒", cls: "vis-private", label: "private" } + : v === "permissioned" ? { icon: "🔑", cls: "vis-permissioned", label: "permissioned" } : { icon: "👁", cls: "vis-public", label: "public" }; const displayName = (s: any) => { - const v = s.visibility || "public_read"; - if (v === "members_only") { + const v = s.visibility || "public"; + if (v === "private") { const username = getUsername(); - return username ? `${username}'s (you)rSpace` : "(you)rSpace"; + return username ? `${username}'s Space` : "My Space"; } - return `${(s.name || s.slug).replace(/ { @@ -1318,7 +1318,7 @@ export class RStackIdentity extends HTMLElement { const publicSpaces = spaces.filter((s) => !s.role && s.accessible); const cardHTML = (s: any) => { - const vis = visInfo(s.visibility || "public_read"); + const vis = visInfo(s.visibility || "public"); return ` - - - + + - - - - + + +

You can change this later in space settings.