From 63f38781da4ed9ee51abe361af45874e39eebe92 Mon Sep 17 00:00:00 2001 From: "Amy J. Ko" Date: Sat, 7 Nov 2026 14:49:20 -0800 Subject: [PATCH] Hide role assignments from viewers who can't see the org's roles. Roles are only readable by members, or by anyone if the org is public. Everyone else got an empty role list, so each ARCI chart and the accountable line rendered as red "Unknown role" badges. Hide them under the same rule as the RLS policy. Co-Authored-By: Claude Opus 5.5 --- CHANGELOG | 6 + package-lock.json | 4 +- package.json | 2 +- src/lib/ARCI.svelte | 293 +++++++++--------- .../[orgid]/process/[processid]/+page.svelte | 88 +++--- 5 files changed, 206 insertions(+), 187 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index e70eebf..1a04e00 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -3,6 +3,12 @@ We'll document all notable changes in this file, including bug fixes, enhancements, and dependency updates. Dates should be in`YYYY-MM-DD` format and versions are in [semantic versioning](http://semver.org/) format. +## v0.10.6 2026-11-07 + +### Fixed + +- Process pages no longer show "Unknown role" to people who aren't logged in. + ## v0.10.5 2026-11-07 ### Fixed diff --git a/package-lock.json b/package-lock.json index d6f8e89..758162f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "adminima", - "version": "0.10.5", + "version": "0.10.6", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "adminima", - "version": "0.10.5", + "version": "0.10.6", "dependencies": { "@supabase/ssr": "^0", "@sveltejs/adapter-vercel": "^7", diff --git a/package.json b/package.json index 5c49a0c..cb28860 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "adminima", - "version": "0.10.5", + "version": "0.10.6", "private": true, "scripts": { "dev": "vite dev", diff --git a/src/lib/ARCI.svelte b/src/lib/ARCI.svelte index bc5f50e..49e02a1 100644 --- a/src/lib/ARCI.svelte +++ b/src/lib/ARCI.svelte @@ -7,6 +7,7 @@ import { getDB } from '#routes/+layout.svelte'; import Options from './Options.svelte'; import { mutate } from '#routes/errors.svelte.ts'; + import { getOrg } from '#routes/org/[orgid]/+layout.svelte'; interface Props { how: HowRow; @@ -17,6 +18,12 @@ let { roles, how, verbose, editable }: Props = $props(); + const orgContext = getOrg(); + + // Mirrors the roles RLS policy: only members, or anyone if the org is public, can see its roles. + // Without them, every assignment would render as "Unknown role", so show nothing instead. + let canSeeRoles = $derived(orgContext().member || orgContext().org.visibility === 'public'); + const dbContext = getDB(); const db = $derived(dbContext()); @@ -50,152 +57,154 @@ }; -
-
-
- {#if !verbose} - - {/if} - {#if editable} - = 1} - bind:selection={responsible} - change={async (value) => { - if (value) { - const { error } = await mutate( - db.addHowRCI(how, value, 'responsible'), - "Couldn't add role." - ); - if (error) return false; - responsible = undefined; - } - return true; - }} - /> - {/if} +{#if canSeeRoles} +
+
+
+ {#if !verbose} + + {/if} + {#if editable} + = 1} + bind:selection={responsible} + change={async (value) => { + if (value) { + const { error } = await mutate( + db.addHowRCI(how, value, 'responsible'), + "Couldn't add role." + ); + if (error) return false; + responsible = undefined; + } + return true; + }} + /> + {/if} +
+
+ {#each how.responsible as responsible} + r.id === responsible)} + >{#if editable} + + {/if} + {/each} + {#if verbose} + is for completing this process. + {/if} +
-
- {#each how.responsible as responsible} - r.id === responsible)} - >{#if editable} - - {/if} - {/each} - {#if verbose} - is for completing this process. - {/if} -
-
-
-
- {#if !verbose} - - {/if} - {#if editable} - = 1} - bind:selection={consulted} - searchable={roleSearch} - change={async (value) => { - if (value) { - const { error } = await mutate( - db.addHowRCI(how, value, 'consulted'), - "Couldn't add role." - ); - if (error) return false; - consulted = undefined; - } - return true; - }} - /> - {/if} -
-
- {#each how.consulted as consulted} - r.id === consulted)} - >{#if editable} - - {/if} - {/each} - {#if verbose} - is to complete this process. - {/if} -
-
-
-
- {#if !verbose} - - {/if} - {#if editable} - = 1} - change={async (value) => { - if (value) { - const { error } = await mutate( - db.addHowRCI(how, value, 'informed'), - "Couldn't add role." - ); - if (error) return false; - informed = undefined; - } - return true; - }} - /> - {/if} +
+
+ {#if !verbose} + + {/if} + {#if editable} + = 1} + bind:selection={consulted} + searchable={roleSearch} + change={async (value) => { + if (value) { + const { error } = await mutate( + db.addHowRCI(how, value, 'consulted'), + "Couldn't add role." + ); + if (error) return false; + consulted = undefined; + } + return true; + }} + /> + {/if} +
+
+ {#each how.consulted as consulted} + r.id === consulted)} + >{#if editable} + + {/if} + {/each} + {#if verbose} + is to complete this process. + {/if} +
-
- {#each how.informed as informed} - r.id === informed)} - >{#if editable} - - {/if} - {/each} - {#if verbose} - is about this process and its outcomes. - {/if} +
+
+ {#if !verbose} + + {/if} + {#if editable} + = 1} + change={async (value) => { + if (value) { + const { error } = await mutate( + db.addHowRCI(how, value, 'informed'), + "Couldn't add role." + ); + if (error) return false; + informed = undefined; + } + return true; + }} + /> + {/if} +
+
+ {#each how.informed as informed} + r.id === informed)} + >{#if editable} + + {/if} + {/each} + {#if verbose} + is about this process and its outcomes. + {/if} +
-
+{/if}