feat(setup): collect server base URL during first-run wizard
Add a Server URL field to the admin-account step of the setup wizard so
the public base URL (used for device sync, OPDS feed, and API endpoints)
is configured up front instead of requiring a later visit to admin
settings.
- setup.templ: base URL input on the admin step plus a summary entry
- setup.ts: default baseUrl to window.location.origin and persist it via
PUT /system/config ({ base_url }) right after the admin account is
created, with a non-fatal warning if the save fails
This commit is contained in:
@@ -49,6 +49,19 @@ templ Setup() {
|
||||
<p class="mb-6" style="color: var(--text-secondary)">This first account will have full admin privileges.</p>
|
||||
|
||||
<form @submit.prevent="submitAdmin()">
|
||||
<div class="mb-6 p-4 rounded-lg border" style="background-color: var(--bg-primary); border-color: var(--border)">
|
||||
<label class="block text-sm font-medium mb-1" style="color: var(--text-secondary)">Server URL (Base URL)</label>
|
||||
<input
|
||||
type="url"
|
||||
x-model="admin.baseUrl"
|
||||
placeholder="https://books.example.com"
|
||||
class="w-full px-3 py-2 border rounded mt-2"
|
||||
style="background-color: var(--bg-secondary); color: var(--text-primary); border-color: var(--border)"
|
||||
required
|
||||
/>
|
||||
<p class="text-sm mt-2" style="color: var(--text-secondary)">The public URL of your Bookhoard instance. Used for device sync, OPDS feed, and API endpoints.</p>
|
||||
</div>
|
||||
|
||||
<div class="mb-4">
|
||||
<label class="block text-sm font-medium mb-1" style="color: var(--text-secondary)">Email</label>
|
||||
<input
|
||||
@@ -289,6 +302,10 @@ templ Setup() {
|
||||
|
||||
<!-- Summary -->
|
||||
<div class="space-y-3 mb-6">
|
||||
<div class="p-4 rounded-lg border" style="background-color: var(--bg-primary); border-color: var(--border)">
|
||||
<p class="text-sm font-medium mb-1" style="color: var(--text-secondary)">Server URL</p>
|
||||
<p style="color: var(--text-primary)" x-text="admin.baseUrl"></p>
|
||||
</div>
|
||||
<div class="p-4 rounded-lg border" style="background-color: var(--bg-primary); border-color: var(--border)">
|
||||
<p class="text-sm font-medium mb-1" style="color: var(--text-secondary)">Administrator</p>
|
||||
<p style="color: var(--text-primary)" x-text="admin.username + ' (' + admin.email + ')'"></p>
|
||||
|
||||
File diff suppressed because one or more lines are too long
+16
-3
@@ -36,14 +36,13 @@ function initSetup(): void {
|
||||
if (savedTheme && savedTheme !== "tokyo-night") {
|
||||
applyTheme(savedTheme);
|
||||
}
|
||||
}
|
||||
|
||||
Alpine.data("setupWizard", () => ({
|
||||
}Alpine.data("setupWizard", () => ({
|
||||
currentStep: 1 as number,
|
||||
loading: false as boolean,
|
||||
errorMsg: "" as string,
|
||||
|
||||
admin: {
|
||||
baseUrl: "",
|
||||
email: "",
|
||||
username: "",
|
||||
password: "",
|
||||
@@ -71,6 +70,7 @@ Alpine.data("setupWizard", () => ({
|
||||
|
||||
init() {
|
||||
initSetup();
|
||||
this.admin.baseUrl = window.location.origin;
|
||||
setTimeout(() => {
|
||||
initPasswordValidation();
|
||||
}, 100);
|
||||
@@ -128,6 +128,8 @@ Alpine.data("setupWizard", () => ({
|
||||
setToken(data.token || data.access_token);
|
||||
setRefreshToken(data.refresh_token);
|
||||
|
||||
await this.saveBaseUrl();
|
||||
|
||||
showToast("Admin account created successfully!", "success");
|
||||
this.currentStep = 2;
|
||||
} catch (err) {
|
||||
@@ -137,6 +139,17 @@ Alpine.data("setupWizard", () => ({
|
||||
}
|
||||
},
|
||||
|
||||
async saveBaseUrl() {
|
||||
if (!this.admin.baseUrl) return;
|
||||
try {
|
||||
await handleVoidResponse(
|
||||
await apiPut("/system/config", { base_url: this.admin.baseUrl })
|
||||
);
|
||||
} catch {
|
||||
showToast("Warning: could not save server URL. You can set it later in Admin Settings.", "warning");
|
||||
}
|
||||
},
|
||||
|
||||
async addLibrary() {
|
||||
this.clearError();
|
||||
this.loading = true;
|
||||
|
||||
Reference in New Issue
Block a user