settings: the owner's own account is not "not an Officer account"

pastilhas rendered on the Jellyfin side with nothing opposite it, labelled as belonging to nobody —
reported by the owner, about their own name, which is the only line on that screen that could not
possibly be true.

The cause is a correct exclusion used for the wrong question. `listProvisionableUsers` leaves the
owner out on purpose: they hold the admin account this flow authenticates as, and provisioning them
would be a second admin nobody asked for. But this view is not the provisioning list, it is "who
exists on each side", and an account absent from the input read as an account that does not exist.

So the viewer is looked up directly and joined onto the account the connection signs in as — known
exactly from `jellyfinUserId` on the server row, never matched by name. It gets its own state rather
than being called "linked", because there is no row in jellyfin_accounts and there should not be: it
is the credential, not a provisioned account. It is also excluded from the "Jellyfin only" count,
which was counting the one account both sides agree on as belonging to neither.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
2026-08-20 22:11:34 +00:00
co-authored by Claude Opus 5
parent e8aa85a35b
commit 591c0dadc3
4 changed files with 60 additions and 8 deletions
+10 -4
View File
@@ -1,5 +1,5 @@
import type { AccountPair } from './useJellyfinData';
import { ArrowLeftRight, CircleSlash, Loader2, UserPlus, Users } from 'lucide-react';
import { ArrowLeftRight, CircleSlash, KeyRound, Loader2, UserPlus, Users } from 'lucide-react';
import { useJellyfinAccounts } from './useJellyfinData';
// Who exists on each side, shown side by side.
@@ -16,8 +16,13 @@ import { useJellyfinAccounts } from './useJellyfinData';
// Officer only no Jellyfin account, and no name that matches one — what connecting WOULD create
// Jellyfin only somebody with no Officer account. Never touched, and that is deliberate: an absence
// in Officer is indistinguishable from a list that has not been told about them yet.
// this connection the admin account Officer signs in as. It has to be its own state: the owner is
// excluded from the provisionable list on purpose, so without this their own account
// appears on the Jellyfin side with nothing opposite it and gets labelled as belonging
// to nobody — which is what the owner saw, next to their own name.
const TONE = {
connection: 'text-sky-600',
linked: 'text-emerald-600',
matchable: 'text-amber-600',
officer: 'text-muted-foreground',
@@ -25,6 +30,7 @@ const TONE = {
} as const;
const stateOf = (p: AccountPair) => {
if (p.isConnection) return { key: 'connection' as const, label: 'the account Officer connects with' };
if (p.linked && p.jellyfin) return { key: 'linked' as const, label: p.adopted ? 'linked (adopted)' : 'linked' };
if (p.linked) return { key: 'matchable' as const, label: 'linked, but the Jellyfin account is gone' };
if (p.matchable) return { key: 'matchable' as const, label: 'names match — not linked yet' };
@@ -96,9 +102,9 @@ export const AccountsSection = ({ serverId }: { serverId: number | null }) => {
muted
/>
<span className={`flex w-4 justify-center ${TONE[state.key]}`} title={state.label}>
{state.key === 'linked' ? (
<ArrowLeftRight className="h-3.5 w-3.5" />
) : state.key === 'matchable' ? (
{state.key === 'connection' ? (
<KeyRound className="h-3.5 w-3.5" />
) : state.key === 'linked' || state.key === 'matchable' ? (
<ArrowLeftRight className="h-3.5 w-3.5" />
) : (
<UserPlus className="h-3.5 w-3.5 opacity-30" />
+1
View File
@@ -284,6 +284,7 @@ export type AccountPair = {
linked: boolean;
adopted: boolean;
matchable: boolean;
isConnection: boolean;
};
export type AccountView =