Summary
Reported: some teams cannot see the Add team button on their Unleash page. This issue records what the code establishes and what is still needed to diagnose it — the cause is not yet determined.
Component: src/routes/team/[team]/unleash/+page.svelte:662-675
What the code says
The button has exactly one visibility gate:
{#if viewerIsMember}
<Button title="Add team" disabled={unleash.ready === false} …>Add team</Button>
{/if}
So a user who cannot see it is one for whom the API returned viewerIsMember: false. There is no per-team, per-instance or feature-flag condition on visibility.
What has been ruled out
Not readiness. disabled={unleash.ready === false} only greys the button out, it does not hide it — and all 66 production instances are currently ready, so nothing is even disabled.
Not an owner/member distinction. UserIsMember in nais-api matches role_name IN ('Team member', 'Team owner') (internal/team/queries/team_members.sql:105-116), so team owners are members. An owner-but-not-member gap does not exist.
Not the same cause as the revoke bug. The revoke row action next to each team uses {#if viewerIsMember && team.slug !== teamSlug} — same gate — so a user missing the Add button should also be missing the per-row revoke buttons. That is a useful thing to confirm with the reporter.
Remaining candidates
- The reporting users genuinely have no role row on the team — for example access granted through a group whose sync has not run.
lastSuccessfulSync is already loaded in the team layout and would show this.
- The team layout's fallback:
src/routes/team/[team]/+layout.ts:44-56 returns a default object with viewerIsMember: false whenever current.data is falsy without current.errors. A partial GraphQL response would silently hide the button for everyone on that team rather than surfacing an error. This is a fail-closed path with no logging, which fits a symptom reported per-team rather than per-user.
Candidate 2 is the one that would explain "some teams" rather than "some users", and it is worth hardening regardless of whether it is the cause here.
What is needed to settle it
Regardless of cause
Summary
Reported: some teams cannot see the Add team button on their Unleash page. This issue records what the code establishes and what is still needed to diagnose it — the cause is not yet determined.
Component:
src/routes/team/[team]/unleash/+page.svelte:662-675What the code says
The button has exactly one visibility gate:
{#if viewerIsMember} <Button title="Add team" disabled={unleash.ready === false} …>Add team</Button> {/if}So a user who cannot see it is one for whom the API returned
viewerIsMember: false. There is no per-team, per-instance or feature-flag condition on visibility.What has been ruled out
Not readiness.
disabled={unleash.ready === false}only greys the button out, it does not hide it — and all 66 production instances are currently ready, so nothing is even disabled.Not an owner/member distinction.
UserIsMemberin nais-api matchesrole_name IN ('Team member', 'Team owner')(internal/team/queries/team_members.sql:105-116), so team owners are members. An owner-but-not-member gap does not exist.Not the same cause as the revoke bug. The revoke row action next to each team uses
{#if viewerIsMember && team.slug !== teamSlug}— same gate — so a user missing the Add button should also be missing the per-row revoke buttons. That is a useful thing to confirm with the reporter.Remaining candidates
lastSuccessfulSyncis already loaded in the team layout and would show this.src/routes/team/[team]/+layout.ts:44-56returns a default object withviewerIsMember: falsewhenevercurrent.datais falsy withoutcurrent.errors. A partial GraphQL response would silently hide the button for everyone on that team rather than surfacing an error. This is a fail-closed path with no logging, which fits a symptom reported per-team rather than per-user.Candidate 2 is the one that would explain "some teams" rather than "some users", and it is worth hardening regardless of whether it is the cause here.
What is needed to settle it
viewerIsMemberreturns for that user/team pair from the API directly.Regardless of cause
+layout.tsfallback should not silently degrade permissions. Either surface the error or log it, rather than rendering a member as a non-member.