master user anlegen #2
|
|
@ -21,6 +21,8 @@ export default function App() {
|
||||||
const [health, setHealth] = useState(null)
|
const [health, setHealth] = useState(null)
|
||||||
const [healthError, setHealthError] = useState(null)
|
const [healthError, setHealthError] = useState(null)
|
||||||
const [setup, setSetup] = useState(null)
|
const [setup, setSetup] = useState(null)
|
||||||
|
const [setupLoading, setSetupLoading] = useState(true)
|
||||||
|
const [setupError, setSetupError] = useState(null)
|
||||||
const [authMode, setAuthMode] = useState('login')
|
const [authMode, setAuthMode] = useState('login')
|
||||||
const [token, setToken] = useState(() => localStorage.getItem(TOKEN_KEY) || '')
|
const [token, setToken] = useState(() => localStorage.getItem(TOKEN_KEY) || '')
|
||||||
const [email, setEmail] = useState('')
|
const [email, setEmail] = useState('')
|
||||||
|
|
@ -42,13 +44,33 @@ export default function App() {
|
||||||
.then(setHealth)
|
.then(setHealth)
|
||||||
.catch((err) => setHealthError(err.message))
|
.catch((err) => setHealthError(err.message))
|
||||||
|
|
||||||
fetch('/api/auth/setup-status')
|
async function loadSetupStatus() {
|
||||||
.then((res) => res.json())
|
setSetupLoading(true)
|
||||||
.then((data) => {
|
setSetupError(null)
|
||||||
setSetup(data)
|
try {
|
||||||
if (data.registration_open) setAuthMode('register')
|
const res = await fetch('/api/auth/setup-status')
|
||||||
})
|
const body = await res.json().catch(() => ({}))
|
||||||
.catch(() => setSetup({ registration_open: false, has_users: true }))
|
if (!res.ok) {
|
||||||
|
throw new Error(
|
||||||
|
res.status === 404
|
||||||
|
? 'Endpoint /api/auth/setup-status nicht gefunden — Backend neu deployen?'
|
||||||
|
: parseError(body, `Setup-Status fehlgeschlagen (HTTP ${res.status})`),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
if (typeof body.registration_open !== 'boolean') {
|
||||||
|
throw new Error('Ungültige Antwort vom Setup-Status — Backend-Version prüfen')
|
||||||
|
}
|
||||||
|
setSetup(body)
|
||||||
|
if (body.registration_open) setAuthMode('register')
|
||||||
|
} catch (err) {
|
||||||
|
setSetup(null)
|
||||||
|
setSetupError(err.message)
|
||||||
|
} finally {
|
||||||
|
setSetupLoading(false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
loadSetupStatus()
|
||||||
}, [])
|
}, [])
|
||||||
|
|
||||||
const loadSession = useCallback(async (activeToken) => {
|
const loadSession = useCallback(async (activeToken) => {
|
||||||
|
|
@ -155,6 +177,7 @@ export default function App() {
|
||||||
}
|
}
|
||||||
|
|
||||||
const registrationOpen = setup?.registration_open === true
|
const registrationOpen = setup?.registration_open === true
|
||||||
|
const registrationClosedBecauseUsersExist = setup?.has_users === true && !registrationOpen
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<main className="shell">
|
<main className="shell">
|
||||||
|
|
@ -174,7 +197,24 @@ export default function App() {
|
||||||
</p>
|
</p>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{!token && (
|
{!token && setupLoading && (
|
||||||
|
<p className="muted">Prüfe Ersteinrichtung …</p>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{!token && setupError && (
|
||||||
|
<p className="error">{setupError}</p>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{!token && registrationClosedBecauseUsersExist && (
|
||||||
|
<p className="setup-hint setup-hint-muted">
|
||||||
|
Es existiert bereits mindestens ein Benutzer ({setup.user_count ?? '≥1'}).
|
||||||
|
Registrierung ist nur für die Ersteinrichtung vorgesehen — bitte anmelden.
|
||||||
|
Falls der Admin per <code>KAIRO_BOOTSTRAP_*</code> in der <code>.env</code> angelegt
|
||||||
|
wurde, nutzen Sie diese Zugangsdaten.
|
||||||
|
</p>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{!token && !setupLoading && !setupError && (
|
||||||
<>
|
<>
|
||||||
<div className="tabs" role="tablist">
|
<div className="tabs" role="tablist">
|
||||||
<button
|
<button
|
||||||
|
|
@ -313,6 +353,16 @@ export default function App() {
|
||||||
{authError && <p className="error">{authError}</p>}
|
{authError && <p className="error">{authError}</p>}
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
|
<section className="card">
|
||||||
|
<h2>Ersteinrichtung</h2>
|
||||||
|
{setupLoading && <p className="muted">Lade …</p>}
|
||||||
|
{setupError && <p className="error">{setupError}</p>}
|
||||||
|
{setup && <pre>{JSON.stringify(setup, null, 2)}</pre>}
|
||||||
|
{!setupLoading && !setup && !setupError && (
|
||||||
|
<p className="muted">Kein Setup-Status verfügbar.</p>
|
||||||
|
)}
|
||||||
|
</section>
|
||||||
|
|
||||||
<section className="card">
|
<section className="card">
|
||||||
<h2>API Health</h2>
|
<h2>API Health</h2>
|
||||||
{healthError && <p className="error">Fehler: {healthError}</p>}
|
{healthError && <p className="error">Fehler: {healthError}</p>}
|
||||||
|
|
|
||||||
|
|
@ -49,6 +49,11 @@ body {
|
||||||
margin: 0 0 1rem;
|
margin: 0 0 1rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.setup-hint-muted {
|
||||||
|
background: #f3f3f3;
|
||||||
|
border-color: #ddd;
|
||||||
|
}
|
||||||
|
|
||||||
.tabs {
|
.tabs {
|
||||||
display: flex;
|
display: flex;
|
||||||
gap: 0.35rem;
|
gap: 0.35rem;
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user