fix(setup): hide YouTube/Google affordances when Google sign-in isn't configured
- /api/me exposes instance-wide google_enabled. The onboarding nudge no longer auto-opens, and Settings hides the YouTube-access section + the 'Connect Google' option, when the instance has no Google OAuth configured (e.g. an email+password-only self-host). A linked account still shows its 'Connected' status.
This commit is contained in:
parent
659e175755
commit
bc4bc20472
4 changed files with 53 additions and 28 deletions
|
|
@ -2,7 +2,14 @@ from fastapi import APIRouter, BackgroundTasks, Depends, HTTPException, Request
|
||||||
from sqlalchemy import func, select
|
from sqlalchemy import func, select
|
||||||
from sqlalchemy.orm import Session
|
from sqlalchemy.orm import Session
|
||||||
|
|
||||||
from app.auth import current_user, has_read_scope, has_write_scope, is_allowed, purge_user
|
from app.auth import (
|
||||||
|
current_user,
|
||||||
|
google_enabled,
|
||||||
|
has_read_scope,
|
||||||
|
has_write_scope,
|
||||||
|
is_allowed,
|
||||||
|
purge_user,
|
||||||
|
)
|
||||||
from app.db import get_db
|
from app.db import get_db
|
||||||
from app.models import Invite, User
|
from app.models import Invite, User
|
||||||
|
|
||||||
|
|
@ -80,6 +87,9 @@ def get_me(
|
||||||
"is_demo": user.is_demo,
|
"is_demo": user.is_demo,
|
||||||
"has_google": user.google_sub is not None,
|
"has_google": user.google_sub is not None,
|
||||||
"has_password": user.password_hash is not None,
|
"has_password": user.password_hash is not None,
|
||||||
|
# Instance-wide: whether Google sign-in / YouTube connect is available at all (the UI hides
|
||||||
|
# YouTube-access affordances and the onboarding nudge when it isn't configured).
|
||||||
|
"google_enabled": google_enabled(db),
|
||||||
"can_read": has_read_scope(user),
|
"can_read": has_read_scope(user),
|
||||||
"can_write": has_write_scope(user),
|
"can_write": has_write_scope(user),
|
||||||
"pending_invites": pending_invites,
|
"pending_invites": pending_invites,
|
||||||
|
|
|
||||||
|
|
@ -389,8 +389,13 @@ function SignInMethods({ me }: { me: Me }) {
|
||||||
const inputCls =
|
const inputCls =
|
||||||
"w-full bg-card border border-border rounded-xl px-3 py-2 text-sm outline-none focus:border-accent";
|
"w-full bg-card border border-border rounded-xl px-3 py-2 text-sm outline-none focus:border-accent";
|
||||||
|
|
||||||
|
// Offer Google only when this instance has Google OAuth configured (or the account is already
|
||||||
|
// linked — then we still show its "Connected" status even if the instance creds were removed).
|
||||||
|
const showGoogle = me.google_enabled || me.has_google;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Section title={t("settings.account.signInMethods")}>
|
<Section title={t("settings.account.signInMethods")}>
|
||||||
|
{showGoogle && (
|
||||||
<div className="flex items-start justify-between gap-3 py-2">
|
<div className="flex items-start justify-between gap-3 py-2">
|
||||||
<div className="min-w-0">
|
<div className="min-w-0">
|
||||||
<div className="text-sm font-medium">{t("settings.account.googleLink.title")}</div>
|
<div className="text-sm font-medium">{t("settings.account.googleLink.title")}</div>
|
||||||
|
|
@ -415,8 +420,9 @@ function SignInMethods({ me }: { me: Me }) {
|
||||||
</button>
|
</button>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
<div className="border-t border-border mt-1 pt-1">
|
<div className={showGoogle ? "border-t border-border mt-1 pt-1" : ""}>
|
||||||
<div className="flex items-start justify-between gap-3 py-2">
|
<div className="flex items-start justify-between gap-3 py-2">
|
||||||
<div className="min-w-0">
|
<div className="min-w-0">
|
||||||
<div className="text-sm font-medium">{t("settings.account.password.title")}</div>
|
<div className="text-sm font-medium">{t("settings.account.password.title")}</div>
|
||||||
|
|
@ -517,7 +523,8 @@ function Account({ me, onOpenWizard }: { me: Me; onOpenWizard: () => void }) {
|
||||||
{t("settings.account.demoNotice")}
|
{t("settings.account.demoNotice")}
|
||||||
</p>
|
</p>
|
||||||
</Section>
|
</Section>
|
||||||
) : (
|
) : me.google_enabled ? (
|
||||||
|
// YouTube access requires Google OAuth; hidden when this instance has no Google configured.
|
||||||
<Section title={t("settings.account.youtubeAccess")}>
|
<Section title={t("settings.account.youtubeAccess")}>
|
||||||
<p className="text-xs text-muted leading-relaxed mb-1">
|
<p className="text-xs text-muted leading-relaxed mb-1">
|
||||||
{t("settings.account.youtubeAccessIntro")}
|
{t("settings.account.youtubeAccessIntro")}
|
||||||
|
|
@ -549,7 +556,7 @@ function Account({ me, onOpenWizard }: { me: Me; onOpenWizard: () => void }) {
|
||||||
{t("settings.account.walkMeThrough")}
|
{t("settings.account.walkMeThrough")}
|
||||||
</button>
|
</button>
|
||||||
</Section>
|
</Section>
|
||||||
)}
|
) : null}
|
||||||
|
|
||||||
{!me.is_demo && (
|
{!me.is_demo && (
|
||||||
<Section title={t("settings.account.dangerZone")}>
|
<Section title={t("settings.account.dangerZone")}>
|
||||||
|
|
|
||||||
|
|
@ -11,6 +11,7 @@ export interface Me {
|
||||||
is_demo: boolean;
|
is_demo: boolean;
|
||||||
has_google: boolean;
|
has_google: boolean;
|
||||||
has_password: boolean;
|
has_password: boolean;
|
||||||
|
google_enabled: boolean;
|
||||||
can_read: boolean;
|
can_read: boolean;
|
||||||
can_write: boolean;
|
can_write: boolean;
|
||||||
pending_invites: number;
|
pending_invites: number;
|
||||||
|
|
|
||||||
|
|
@ -15,9 +15,16 @@
|
||||||
export const ONBOARD_ACTIVE = "subfeed.onboarding.active";
|
export const ONBOARD_ACTIVE = "subfeed.onboarding.active";
|
||||||
export const ONBOARD_DISMISSED = "subfeed.onboarding.dismissed";
|
export const ONBOARD_DISMISSED = "subfeed.onboarding.dismissed";
|
||||||
|
|
||||||
export function shouldAutoOpenOnboarding(me: { can_read: boolean; is_demo?: boolean }): boolean {
|
export function shouldAutoOpenOnboarding(me: {
|
||||||
|
can_read: boolean;
|
||||||
|
is_demo?: boolean;
|
||||||
|
google_enabled?: boolean;
|
||||||
|
}): boolean {
|
||||||
// The shared demo account can never connect YouTube, so never nudge it to.
|
// The shared demo account can never connect YouTube, so never nudge it to.
|
||||||
if (me.is_demo) return false;
|
if (me.is_demo) return false;
|
||||||
|
// YouTube connect needs Google OAuth configured on this instance. A self-host instance may run
|
||||||
|
// email+password only — then there's nothing to connect, so don't nudge.
|
||||||
|
if (me.google_enabled === false) return false;
|
||||||
if (sessionStorage.getItem(ONBOARD_ACTIVE)) return true;
|
if (sessionStorage.getItem(ONBOARD_ACTIVE)) return true;
|
||||||
return !me.can_read && !localStorage.getItem(ONBOARD_DISMISSED);
|
return !me.can_read && !localStorage.getItem(ONBOARD_DISMISSED);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue