mirror of
https://codeberg.org/likwid/likwid.git
synced 2026-03-26 19:03:08 +00:00
feat(settings): instance theme
This commit is contained in:
parent
c8e90fccbf
commit
3e14fe7326
9 changed files with 194 additions and 43 deletions
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "SELECT id, setup_completed, instance_name, platform_mode,\n registration_enabled, registration_mode,\n default_community_visibility, allow_private_communities,\n default_plugin_policy, default_moderation_mode\n FROM instance_settings LIMIT 1",
|
||||
"query": "SELECT id, setup_completed, instance_name, platform_mode,\n theme_id, registration_enabled, registration_mode,\n default_community_visibility, allow_private_communities,\n default_plugin_policy, default_moderation_mode\n FROM instance_settings LIMIT 1",
|
||||
"describe": {
|
||||
"columns": [
|
||||
{
|
||||
|
|
@ -25,31 +25,36 @@
|
|||
},
|
||||
{
|
||||
"ordinal": 4,
|
||||
"name": "theme_id",
|
||||
"type_info": "Varchar"
|
||||
},
|
||||
{
|
||||
"ordinal": 5,
|
||||
"name": "registration_enabled",
|
||||
"type_info": "Bool"
|
||||
},
|
||||
{
|
||||
"ordinal": 5,
|
||||
"ordinal": 6,
|
||||
"name": "registration_mode",
|
||||
"type_info": "Varchar"
|
||||
},
|
||||
{
|
||||
"ordinal": 6,
|
||||
"ordinal": 7,
|
||||
"name": "default_community_visibility",
|
||||
"type_info": "Varchar"
|
||||
},
|
||||
{
|
||||
"ordinal": 7,
|
||||
"ordinal": 8,
|
||||
"name": "allow_private_communities",
|
||||
"type_info": "Bool"
|
||||
},
|
||||
{
|
||||
"ordinal": 8,
|
||||
"ordinal": 9,
|
||||
"name": "default_plugin_policy",
|
||||
"type_info": "Varchar"
|
||||
},
|
||||
{
|
||||
"ordinal": 9,
|
||||
"ordinal": 10,
|
||||
"name": "default_moderation_mode",
|
||||
"type_info": "Varchar"
|
||||
}
|
||||
|
|
@ -67,8 +72,9 @@
|
|||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false
|
||||
]
|
||||
},
|
||||
"hash": "18c0fb05da45a3eea514f660bc4ac4d6aca71442645666a9c08db8f2a564ff6c"
|
||||
"hash": "0620f314de8df0c7990ef63fda55f2ff646d5159c59d8288e4ffdfdb07dc159f"
|
||||
}
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "SELECT setup_completed, instance_name, platform_mode,\n registration_enabled, registration_mode,\n single_community_id\n FROM instance_settings\n LIMIT 1",
|
||||
"query": "SELECT setup_completed, instance_name, theme_id, platform_mode,\n registration_enabled, registration_mode,\n single_community_id\n FROM instance_settings\n LIMIT 1",
|
||||
"describe": {
|
||||
"columns": [
|
||||
{
|
||||
|
|
@ -15,21 +15,26 @@
|
|||
},
|
||||
{
|
||||
"ordinal": 2,
|
||||
"name": "platform_mode",
|
||||
"name": "theme_id",
|
||||
"type_info": "Varchar"
|
||||
},
|
||||
{
|
||||
"ordinal": 3,
|
||||
"name": "platform_mode",
|
||||
"type_info": "Varchar"
|
||||
},
|
||||
{
|
||||
"ordinal": 4,
|
||||
"name": "registration_enabled",
|
||||
"type_info": "Bool"
|
||||
},
|
||||
{
|
||||
"ordinal": 4,
|
||||
"ordinal": 5,
|
||||
"name": "registration_mode",
|
||||
"type_info": "Varchar"
|
||||
},
|
||||
{
|
||||
"ordinal": 5,
|
||||
"ordinal": 6,
|
||||
"name": "single_community_id",
|
||||
"type_info": "Uuid"
|
||||
}
|
||||
|
|
@ -43,8 +48,9 @@
|
|||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
true
|
||||
]
|
||||
},
|
||||
"hash": "200e864fa5778cf58d36d49f94a4006f7d104eb84e6f166b795df0f222ee93d8"
|
||||
"hash": "593dc329afc129680dd505221df649aa8cb544841fa78a5fe740adfbb4439502"
|
||||
}
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "UPDATE instance_settings SET\n setup_completed = true,\n setup_completed_at = NOW(),\n setup_completed_by = $1,\n instance_name = $2,\n platform_mode = $3,\n single_community_id = $4\n RETURNING id, setup_completed, instance_name, platform_mode,\n registration_enabled, registration_mode,\n default_community_visibility, allow_private_communities,\n default_plugin_policy, default_moderation_mode",
|
||||
"query": "UPDATE instance_settings SET\n setup_completed = true,\n setup_completed_at = NOW(),\n setup_completed_by = $1,\n instance_name = $2,\n platform_mode = $3,\n single_community_id = $4\n RETURNING id, setup_completed, instance_name, platform_mode,\n theme_id,\n registration_enabled, registration_mode,\n default_community_visibility, allow_private_communities,\n default_plugin_policy, default_moderation_mode",
|
||||
"describe": {
|
||||
"columns": [
|
||||
{
|
||||
|
|
@ -25,31 +25,36 @@
|
|||
},
|
||||
{
|
||||
"ordinal": 4,
|
||||
"name": "theme_id",
|
||||
"type_info": "Varchar"
|
||||
},
|
||||
{
|
||||
"ordinal": 5,
|
||||
"name": "registration_enabled",
|
||||
"type_info": "Bool"
|
||||
},
|
||||
{
|
||||
"ordinal": 5,
|
||||
"ordinal": 6,
|
||||
"name": "registration_mode",
|
||||
"type_info": "Varchar"
|
||||
},
|
||||
{
|
||||
"ordinal": 6,
|
||||
"ordinal": 7,
|
||||
"name": "default_community_visibility",
|
||||
"type_info": "Varchar"
|
||||
},
|
||||
{
|
||||
"ordinal": 7,
|
||||
"ordinal": 8,
|
||||
"name": "allow_private_communities",
|
||||
"type_info": "Bool"
|
||||
},
|
||||
{
|
||||
"ordinal": 8,
|
||||
"ordinal": 9,
|
||||
"name": "default_plugin_policy",
|
||||
"type_info": "Varchar"
|
||||
},
|
||||
{
|
||||
"ordinal": 9,
|
||||
"ordinal": 10,
|
||||
"name": "default_moderation_mode",
|
||||
"type_info": "Varchar"
|
||||
}
|
||||
|
|
@ -72,8 +77,9 @@
|
|||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false
|
||||
]
|
||||
},
|
||||
"hash": "b9586185e84644f0bd936d7bf5e9bec6ebeaba77ab354d0b7096d9334656497f"
|
||||
"hash": "8dd178663df95d64d72c776e3b8bda63851d2ad0e13a6d80b327610078ecbaeb"
|
||||
}
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "UPDATE instance_settings SET\n instance_name = COALESCE($1, instance_name),\n platform_mode = COALESCE($2, platform_mode),\n registration_enabled = COALESCE($3, registration_enabled),\n registration_mode = COALESCE($4, registration_mode)\n RETURNING id, setup_completed, instance_name, platform_mode,\n registration_enabled, registration_mode,\n default_community_visibility, allow_private_communities,\n default_plugin_policy, default_moderation_mode",
|
||||
"query": "UPDATE instance_settings SET\n instance_name = COALESCE($1, instance_name),\n theme_id = COALESCE($2, theme_id),\n platform_mode = COALESCE($3, platform_mode),\n registration_enabled = COALESCE($4, registration_enabled),\n registration_mode = COALESCE($5, registration_mode)\n RETURNING id, setup_completed, instance_name, platform_mode,\n theme_id, registration_enabled, registration_mode,\n default_community_visibility, allow_private_communities,\n default_plugin_policy, default_moderation_mode",
|
||||
"describe": {
|
||||
"columns": [
|
||||
{
|
||||
|
|
@ -25,37 +25,43 @@
|
|||
},
|
||||
{
|
||||
"ordinal": 4,
|
||||
"name": "theme_id",
|
||||
"type_info": "Varchar"
|
||||
},
|
||||
{
|
||||
"ordinal": 5,
|
||||
"name": "registration_enabled",
|
||||
"type_info": "Bool"
|
||||
},
|
||||
{
|
||||
"ordinal": 5,
|
||||
"ordinal": 6,
|
||||
"name": "registration_mode",
|
||||
"type_info": "Varchar"
|
||||
},
|
||||
{
|
||||
"ordinal": 6,
|
||||
"ordinal": 7,
|
||||
"name": "default_community_visibility",
|
||||
"type_info": "Varchar"
|
||||
},
|
||||
{
|
||||
"ordinal": 7,
|
||||
"ordinal": 8,
|
||||
"name": "allow_private_communities",
|
||||
"type_info": "Bool"
|
||||
},
|
||||
{
|
||||
"ordinal": 8,
|
||||
"ordinal": 9,
|
||||
"name": "default_plugin_policy",
|
||||
"type_info": "Varchar"
|
||||
},
|
||||
{
|
||||
"ordinal": 9,
|
||||
"ordinal": 10,
|
||||
"name": "default_moderation_mode",
|
||||
"type_info": "Varchar"
|
||||
}
|
||||
],
|
||||
"parameters": {
|
||||
"Left": [
|
||||
"Varchar",
|
||||
"Varchar",
|
||||
"Varchar",
|
||||
"Bool",
|
||||
|
|
@ -72,8 +78,9 @@
|
|||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false
|
||||
]
|
||||
},
|
||||
"hash": "c35608b0d7569f739dda24b3da59b7b500ff26f5e79433b3f7e3625d91177d26"
|
||||
"hash": "a903d88370faa52169ffd4ec6a54a789ee4a6173fe84aca0ef8dedaa46b1f93c"
|
||||
}
|
||||
2
backend/migrations/20260215190000_instance_theme.sql
Normal file
2
backend/migrations/20260215190000_instance_theme.sql
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
ALTER TABLE instance_settings
|
||||
ADD COLUMN IF NOT EXISTS theme_id VARCHAR(50) NOT NULL DEFAULT 'neutral';
|
||||
|
|
@ -30,6 +30,7 @@ pub struct SetupStatus {
|
|||
pub struct PublicInstanceSettings {
|
||||
pub setup_completed: bool,
|
||||
pub instance_name: String,
|
||||
pub theme_id: String,
|
||||
pub platform_mode: String,
|
||||
pub registration_enabled: bool,
|
||||
pub registration_mode: String,
|
||||
|
|
@ -42,6 +43,7 @@ pub struct InstanceSettings {
|
|||
pub id: Uuid,
|
||||
pub setup_completed: bool,
|
||||
pub instance_name: String,
|
||||
pub theme_id: String,
|
||||
pub platform_mode: String,
|
||||
pub registration_enabled: bool,
|
||||
pub registration_mode: String,
|
||||
|
|
@ -64,6 +66,8 @@ pub struct UpdateInstanceRequest {
|
|||
#[serde(default)]
|
||||
pub instance_name: Option<String>,
|
||||
#[serde(default)]
|
||||
pub theme_id: Option<String>,
|
||||
#[serde(default)]
|
||||
pub platform_mode: Option<String>,
|
||||
#[serde(default)]
|
||||
pub registration_enabled: Option<bool>,
|
||||
|
|
@ -71,6 +75,32 @@ pub struct UpdateInstanceRequest {
|
|||
pub registration_mode: Option<String>,
|
||||
}
|
||||
|
||||
const KNOWN_THEME_IDS: [&str; 4] = ["neutral", "breeze-light", "breeze-dark", "opensuse"];
|
||||
|
||||
fn validate_theme_id(theme_id: &str) -> Result<(), (StatusCode, String)> {
|
||||
if theme_id.trim().is_empty() {
|
||||
return Err((StatusCode::BAD_REQUEST, "Theme cannot be empty".to_string()));
|
||||
}
|
||||
if theme_id.len() > 50 {
|
||||
return Err((StatusCode::BAD_REQUEST, "Theme is too long".to_string()));
|
||||
}
|
||||
if !theme_id
|
||||
.chars()
|
||||
.all(|c| c.is_ascii_lowercase() || c.is_ascii_digit() || c == '-')
|
||||
{
|
||||
return Err((
|
||||
StatusCode::BAD_REQUEST,
|
||||
"Theme contains invalid characters".to_string(),
|
||||
));
|
||||
}
|
||||
|
||||
if !KNOWN_THEME_IDS.iter().any(|t| t == &theme_id) {
|
||||
return Err((StatusCode::BAD_REQUEST, "Unknown theme".to_string()));
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize)]
|
||||
pub struct CommunitySettings {
|
||||
pub community_id: Uuid,
|
||||
|
|
@ -121,7 +151,7 @@ async fn get_public_settings(
|
|||
State(pool): State<PgPool>,
|
||||
) -> Result<Json<PublicInstanceSettings>, String> {
|
||||
let row = sqlx::query!(
|
||||
r#"SELECT setup_completed, instance_name, platform_mode,
|
||||
r#"SELECT setup_completed, instance_name, theme_id, platform_mode,
|
||||
registration_enabled, registration_mode,
|
||||
single_community_id
|
||||
FROM instance_settings
|
||||
|
|
@ -135,6 +165,7 @@ async fn get_public_settings(
|
|||
return Ok(Json(PublicInstanceSettings {
|
||||
setup_completed: false,
|
||||
instance_name: "Likwid".to_string(),
|
||||
theme_id: "neutral".to_string(),
|
||||
platform_mode: "open".to_string(),
|
||||
registration_enabled: true,
|
||||
registration_mode: "open".to_string(),
|
||||
|
|
@ -161,6 +192,7 @@ async fn get_public_settings(
|
|||
Ok(Json(PublicInstanceSettings {
|
||||
setup_completed: r.setup_completed,
|
||||
instance_name: r.instance_name,
|
||||
theme_id: r.theme_id,
|
||||
platform_mode: r.platform_mode,
|
||||
registration_enabled: r.registration_enabled,
|
||||
registration_mode: r.registration_mode,
|
||||
|
|
@ -224,6 +256,7 @@ async fn complete_setup(
|
|||
platform_mode = $3,
|
||||
single_community_id = $4
|
||||
RETURNING id, setup_completed, instance_name, platform_mode,
|
||||
theme_id,
|
||||
registration_enabled, registration_mode,
|
||||
default_community_visibility, allow_private_communities,
|
||||
default_plugin_policy, default_moderation_mode"#,
|
||||
|
|
@ -240,6 +273,7 @@ async fn complete_setup(
|
|||
id: settings.id,
|
||||
setup_completed: settings.setup_completed,
|
||||
instance_name: settings.instance_name,
|
||||
theme_id: settings.theme_id,
|
||||
platform_mode: settings.platform_mode,
|
||||
registration_enabled: settings.registration_enabled,
|
||||
registration_mode: settings.registration_mode,
|
||||
|
|
@ -260,7 +294,7 @@ async fn get_instance_settings(
|
|||
|
||||
let s = sqlx::query!(
|
||||
r#"SELECT id, setup_completed, instance_name, platform_mode,
|
||||
registration_enabled, registration_mode,
|
||||
theme_id, registration_enabled, registration_mode,
|
||||
default_community_visibility, allow_private_communities,
|
||||
default_plugin_policy, default_moderation_mode
|
||||
FROM instance_settings LIMIT 1"#
|
||||
|
|
@ -273,6 +307,7 @@ async fn get_instance_settings(
|
|||
id: s.id,
|
||||
setup_completed: s.setup_completed,
|
||||
instance_name: s.instance_name,
|
||||
theme_id: s.theme_id,
|
||||
platform_mode: s.platform_mode,
|
||||
registration_enabled: s.registration_enabled,
|
||||
registration_mode: s.registration_mode,
|
||||
|
|
@ -293,24 +328,37 @@ async fn update_instance_settings(
|
|||
// Check platform settings permission
|
||||
require_permission(&pool, auth.user_id, perms::PLATFORM_SETTINGS, None).await?;
|
||||
|
||||
if let Some(theme_id) = req.theme_id.as_deref() {
|
||||
validate_theme_id(theme_id)?;
|
||||
}
|
||||
|
||||
if config.is_demo() {
|
||||
return Err((
|
||||
StatusCode::FORBIDDEN,
|
||||
"Instance settings cannot be modified in demo mode".to_string(),
|
||||
));
|
||||
let allowed = req.theme_id.is_some()
|
||||
&& req.instance_name.is_none()
|
||||
&& req.platform_mode.is_none()
|
||||
&& req.registration_enabled.is_none()
|
||||
&& req.registration_mode.is_none();
|
||||
if !allowed {
|
||||
return Err((
|
||||
StatusCode::FORBIDDEN,
|
||||
"Only theme updates are allowed in demo mode".to_string(),
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
let s = sqlx::query!(
|
||||
r#"UPDATE instance_settings SET
|
||||
instance_name = COALESCE($1, instance_name),
|
||||
platform_mode = COALESCE($2, platform_mode),
|
||||
registration_enabled = COALESCE($3, registration_enabled),
|
||||
registration_mode = COALESCE($4, registration_mode)
|
||||
theme_id = COALESCE($2, theme_id),
|
||||
platform_mode = COALESCE($3, platform_mode),
|
||||
registration_enabled = COALESCE($4, registration_enabled),
|
||||
registration_mode = COALESCE($5, registration_mode)
|
||||
RETURNING id, setup_completed, instance_name, platform_mode,
|
||||
registration_enabled, registration_mode,
|
||||
theme_id, registration_enabled, registration_mode,
|
||||
default_community_visibility, allow_private_communities,
|
||||
default_plugin_policy, default_moderation_mode"#,
|
||||
req.instance_name,
|
||||
req.theme_id,
|
||||
req.platform_mode,
|
||||
req.registration_enabled,
|
||||
req.registration_mode
|
||||
|
|
@ -323,6 +371,7 @@ async fn update_instance_settings(
|
|||
id: s.id,
|
||||
setup_completed: s.setup_completed,
|
||||
instance_name: s.instance_name,
|
||||
theme_id: s.theme_id,
|
||||
platform_mode: s.platform_mode,
|
||||
registration_enabled: s.registration_enabled,
|
||||
registration_mode: s.registration_mode,
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ interface Props {
|
|||
}
|
||||
|
||||
import { DEFAULT_THEME, themes as themeRegistry } from '../lib/themes';
|
||||
import { API_BASE as apiBase } from '../lib/api';
|
||||
import { API_BASE as apiBase, SERVER_API_BASE } from '../lib/api';
|
||||
import VotingIcons from '../components/icons/VotingIcons.astro';
|
||||
import DesignSystemStyles from '../components/ui/DesignSystemStyles.astro';
|
||||
|
||||
|
|
@ -22,11 +22,24 @@ const publicDemoSite = isEnabled((globalThis as any).process?.env?.PUBLIC_DEMO_S
|
|||
Object.entries(themeRegistry).map(([id, t]) => [id, { isDark: t.isDark, colors: t.colors }]),
|
||||
);
|
||||
|
||||
const defaultTheme = DEFAULT_THEME;
|
||||
const settingsApiBase = SERVER_API_BASE || 'http://127.0.0.1:3000';
|
||||
|
||||
let defaultTheme = DEFAULT_THEME;
|
||||
try {
|
||||
const res = await fetch(`${settingsApiBase}/api/settings/public`);
|
||||
if (res.ok) {
|
||||
const settings = await res.json();
|
||||
if (settings && typeof settings.theme_id === 'string' && themeRegistry[settings.theme_id]) {
|
||||
defaultTheme = settings.theme_id;
|
||||
}
|
||||
}
|
||||
} catch (_e) {}
|
||||
|
||||
const initialTheme = themeRegistry[defaultTheme] || themeRegistry[DEFAULT_THEME];
|
||||
---
|
||||
|
||||
<!doctype html>
|
||||
<html lang="en" data-theme="neutral" data-theme-mode="dark">
|
||||
<html lang="en" data-theme={defaultTheme} data-theme-mode={initialTheme.isDark ? 'dark' : 'light'}>
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ interface Props {
|
|||
}
|
||||
|
||||
import { DEFAULT_THEME, themes as themeRegistry } from '../lib/themes';
|
||||
import { SERVER_API_BASE } from '../lib/api';
|
||||
import DesignSystemStyles from '../components/ui/DesignSystemStyles.astro';
|
||||
|
||||
function isEnabled(v: string | undefined): boolean {
|
||||
|
|
@ -21,11 +22,24 @@ const themes = Object.fromEntries(
|
|||
Object.entries(themeRegistry).map(([id, t]) => [id, { isDark: t.isDark, colors: t.colors }]),
|
||||
);
|
||||
|
||||
const defaultTheme = DEFAULT_THEME;
|
||||
const settingsApiBase = SERVER_API_BASE || 'http://127.0.0.1:3000';
|
||||
|
||||
let defaultTheme = DEFAULT_THEME;
|
||||
try {
|
||||
const res = await fetch(`${settingsApiBase}/api/settings/public`);
|
||||
if (res.ok) {
|
||||
const settings = await res.json();
|
||||
if (settings && typeof settings.theme_id === 'string' && themeRegistry[settings.theme_id]) {
|
||||
defaultTheme = settings.theme_id;
|
||||
}
|
||||
}
|
||||
} catch (_e) {}
|
||||
|
||||
const initialTheme = themeRegistry[defaultTheme] || themeRegistry[DEFAULT_THEME];
|
||||
---
|
||||
|
||||
<!doctype html>
|
||||
<html lang="en" data-theme="neutral" data-theme-mode="dark">
|
||||
<html lang="en" data-theme={defaultTheme} data-theme-mode={initialTheme.isDark ? 'dark' : 'light'}>
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
|
|
|
|||
|
|
@ -29,6 +29,16 @@ import { API_BASE as apiBase } from '../../lib/api';
|
|||
<label for="instance_name">Platform Name</label>
|
||||
<input type="text" id="instance_name" name="instance_name" />
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="theme_id">Theme</label>
|
||||
<select id="theme_id" name="theme_id">
|
||||
<option value="neutral">Neutral Dark</option>
|
||||
<option value="breeze-light">Breeze Light</option>
|
||||
<option value="breeze-dark">Breeze Dark</option>
|
||||
<option value="opensuse">openSUSE</option>
|
||||
</select>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- Platform Mode -->
|
||||
|
|
@ -182,6 +192,8 @@ import { API_BASE as apiBase } from '../../lib/api';
|
|||
const saveBtn = document.getElementById('save-btn');
|
||||
const saveStatus = document.getElementById('save-status');
|
||||
|
||||
let initialSettings = null;
|
||||
|
||||
if (!form || !loadingEl || !errorEl || !saveStatus) return;
|
||||
|
||||
async function loadSettings() {
|
||||
|
|
@ -213,9 +225,11 @@ import { API_BASE as apiBase } from '../../lib/api';
|
|||
}
|
||||
|
||||
const settings = await res.json();
|
||||
initialSettings = settings;
|
||||
|
||||
// Populate form
|
||||
(document.getElementById('instance_name')).value = settings.instance_name;
|
||||
(document.getElementById('theme_id')).value = settings.theme_id || 'neutral';
|
||||
(document.getElementById('platform_mode')).value = settings.platform_mode;
|
||||
(document.getElementById('registration_enabled')).checked = settings.registration_enabled;
|
||||
(document.getElementById('registration_mode')).value = settings.registration_mode;
|
||||
|
|
@ -240,14 +254,39 @@ import { API_BASE as apiBase } from '../../lib/api';
|
|||
|
||||
if (saveBtn) saveBtn.disabled = true;
|
||||
saveStatus.textContent = 'Saving...';
|
||||
saveStatus.style.color = '';
|
||||
|
||||
const data = {
|
||||
const current = {
|
||||
instance_name: (document.getElementById('instance_name')).value,
|
||||
theme_id: (document.getElementById('theme_id')).value,
|
||||
platform_mode: (document.getElementById('platform_mode')).value,
|
||||
registration_enabled: (document.getElementById('registration_enabled')).checked,
|
||||
registration_mode: (document.getElementById('registration_mode')).value
|
||||
registration_mode: (document.getElementById('registration_mode')).value,
|
||||
};
|
||||
|
||||
const data = {};
|
||||
if (!initialSettings || current.instance_name !== initialSettings.instance_name) {
|
||||
data.instance_name = current.instance_name;
|
||||
}
|
||||
if (!initialSettings || current.theme_id !== initialSettings.theme_id) {
|
||||
data.theme_id = current.theme_id;
|
||||
}
|
||||
if (!initialSettings || current.platform_mode !== initialSettings.platform_mode) {
|
||||
data.platform_mode = current.platform_mode;
|
||||
}
|
||||
if (!initialSettings || current.registration_enabled !== initialSettings.registration_enabled) {
|
||||
data.registration_enabled = current.registration_enabled;
|
||||
}
|
||||
if (!initialSettings || current.registration_mode !== initialSettings.registration_mode) {
|
||||
data.registration_mode = current.registration_mode;
|
||||
}
|
||||
|
||||
if (Object.keys(data).length === 0) {
|
||||
saveStatus.textContent = 'No changes to save.';
|
||||
if (saveBtn) saveBtn.disabled = false;
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
const res = await fetch(`${API_BASE}/api/settings/instance`, {
|
||||
method: 'PATCH',
|
||||
|
|
@ -262,8 +301,17 @@ import { API_BASE as apiBase } from '../../lib/api';
|
|||
throw new Error(await res.text());
|
||||
}
|
||||
|
||||
const updated = await res.json();
|
||||
initialSettings = updated;
|
||||
|
||||
saveStatus.textContent = 'Saved!';
|
||||
setTimeout(() => { saveStatus.textContent = ''; }, 3000);
|
||||
|
||||
if (data.theme_id) {
|
||||
setTimeout(() => {
|
||||
window.location.reload();
|
||||
}, 150);
|
||||
}
|
||||
} catch (err) {
|
||||
saveStatus.textContent = 'Error: ' + err.message;
|
||||
saveStatus.style.color = '#c62828';
|
||||
|
|
|
|||
Loading…
Reference in a new issue