A fresh install landed on the anonymous dashboard instead of prompting to create the first admin, so an operator had no way to discover /setup. The router now asks /api/setup/needs-admin before rendering any unauthenticated route and redirects to /login?firstrun=1 while no user exists. The result is cached in a composable so it costs one request per session, and the lookup fails open (a backend that cannot answer must not lock the login screen). Racing it against a 4s timeout keeps a slow or hung backend from blocking the first paint. Login.vue clears the flag after creating the admin so the gate stops firing without a reload.
57 lines
1.8 KiB
JavaScript
57 lines
1.8 KiB
JavaScript
// Tracks whether first-run setup is complete, so the app can steer a fresh
|
|
// admin into the /setup wizard. Defaults to "complete" so the wizard never
|
|
// flashes before the real value loads.
|
|
import { ref } from 'vue'
|
|
import { settingsApi, setupApi } from '../api'
|
|
|
|
export const setupComplete = ref(true)
|
|
// Session-only: a fresh admin who clicks "Skip for now" is not nagged again
|
|
// until the next login/reload.
|
|
export const setupSkipped = ref(false)
|
|
const loaded = ref(false)
|
|
|
|
export function isSetupLoaded() {
|
|
return loaded.value
|
|
}
|
|
|
|
export async function refreshSetupState() {
|
|
try {
|
|
const response = await settingsApi.get('setup_complete')
|
|
const value = response.data?.data?.value
|
|
setupComplete.value = value === true || value === 'true'
|
|
} catch (err) {
|
|
// If we cannot read it, assume complete so we do not trap the user.
|
|
setupComplete.value = true
|
|
}
|
|
loaded.value = true
|
|
return setupComplete.value
|
|
}
|
|
|
|
// First run, before any user exists. Defaults to false so the app never flashes
|
|
// the create-admin screen at an established site while this loads.
|
|
export const needsAdmin = ref(false)
|
|
const adminLoaded = ref(false)
|
|
|
|
export function isNeedsAdminLoaded() {
|
|
return adminLoaded.value
|
|
}
|
|
|
|
export async function refreshNeedsAdmin() {
|
|
try {
|
|
const response = await setupApi.needsAdmin()
|
|
needsAdmin.value = response.data?.data?.needsadmin === true
|
|
} catch (err) {
|
|
// Fail open: if we cannot tell, assume an admin exists rather than trap
|
|
// everyone behind a create-admin screen they cannot complete.
|
|
needsAdmin.value = false
|
|
}
|
|
adminLoaded.value = true
|
|
return needsAdmin.value
|
|
}
|
|
|
|
// Called after the first admin is created so the gate stops firing.
|
|
export function clearNeedsAdmin() {
|
|
needsAdmin.value = false
|
|
adminLoaded.value = true
|
|
}
|