- Add theme_tab_bar_position setting (top/bottom/responsive) - Tab bar is now fixed at top, stays visible during scroll - Bottom position uses fixed positioning with safe-area-inset - Add edge swipe gesture to open sidebar on mobile - Remove backdrop-filter for better scroll performance - Simplify TabsScroller by removing inline style manipulation 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
675 lines
20 KiB
Python
675 lines
20 KiB
Python
"""
|
|
Settings Registry - Central definition of all application settings.
|
|
|
|
This file defines ALL configurable settings in the application with:
|
|
- Storage location (database in /config, localStorage, env)
|
|
- Scope (global or user-specific)
|
|
- Default values
|
|
- Data types
|
|
- Descriptions
|
|
|
|
IMPORTANT: Any new setting MUST be added here first.
|
|
"""
|
|
|
|
from enum import Enum
|
|
from dataclasses import dataclass, field
|
|
from typing import Any, Optional
|
|
|
|
|
|
class SettingScope(Enum):
|
|
"""Defines who the setting applies to."""
|
|
GLOBAL = "global" # Same for all users, admin-controlled
|
|
USER_SPECIFIC = "user" # Each user can have different value
|
|
SYSTEM = "system" # Infrastructure/env settings, not in DB
|
|
|
|
|
|
class SettingStorage(Enum):
|
|
"""Defines where the setting is stored."""
|
|
DATABASE = "database" # Stored in /config/config.db (settings table)
|
|
LOCAL_STORAGE = "localStorage" # Browser localStorage (frontend only)
|
|
ENV = "env" # Environment variable (.env file)
|
|
MEMORY = "memory" # Runtime only, not persisted
|
|
|
|
|
|
class SettingType(Enum):
|
|
"""Data type of the setting value."""
|
|
BOOLEAN = "boolean"
|
|
STRING = "string"
|
|
INTEGER = "integer"
|
|
JSON = "json"
|
|
LIST = "list"
|
|
|
|
|
|
@dataclass
|
|
class SettingDefinition:
|
|
"""Definition of a single setting."""
|
|
key: str
|
|
type: SettingType
|
|
scope: SettingScope
|
|
storage: SettingStorage
|
|
default: Any
|
|
description: str
|
|
category: str
|
|
admin_only: bool = True # Only admins can modify (for DB settings)
|
|
sync_to_frontend: bool = True # Should be synced to frontend
|
|
choices: Optional[list] = None # Valid values if restricted
|
|
|
|
|
|
# =============================================================================
|
|
# SETTINGS REGISTRY
|
|
# =============================================================================
|
|
|
|
SETTINGS_REGISTRY: dict[str, SettingDefinition] = {}
|
|
|
|
|
|
def register_setting(setting: SettingDefinition) -> SettingDefinition:
|
|
"""Register a setting in the registry."""
|
|
SETTINGS_REGISTRY[setting.key] = setting
|
|
return setting
|
|
|
|
|
|
# =============================================================================
|
|
# THEME SETTINGS (Global, Database)
|
|
# =============================================================================
|
|
|
|
register_setting(SettingDefinition(
|
|
key="theme_accent_color",
|
|
type=SettingType.STRING,
|
|
scope=SettingScope.GLOBAL,
|
|
storage=SettingStorage.DATABASE,
|
|
default="auto",
|
|
description="Accent color for UI elements",
|
|
category="theme",
|
|
choices=["auto", "blue", "purple", "green", "orange", "pink", "red", "teal", "amber", "indigo", "cyan", "rose"]
|
|
))
|
|
|
|
register_setting(SettingDefinition(
|
|
key="theme_border_radius",
|
|
type=SettingType.STRING,
|
|
scope=SettingScope.GLOBAL,
|
|
storage=SettingStorage.DATABASE,
|
|
default="large",
|
|
description="Border radius style for UI components",
|
|
category="theme",
|
|
choices=["small", "medium", "large"]
|
|
))
|
|
|
|
register_setting(SettingDefinition(
|
|
key="theme_sidebar_style",
|
|
type=SettingType.STRING,
|
|
scope=SettingScope.GLOBAL,
|
|
storage=SettingStorage.DATABASE,
|
|
default="default",
|
|
description="Visual style of the sidebar",
|
|
category="theme",
|
|
choices=["default", "dark", "light"]
|
|
))
|
|
|
|
register_setting(SettingDefinition(
|
|
key="theme_density",
|
|
type=SettingType.STRING,
|
|
scope=SettingScope.GLOBAL,
|
|
storage=SettingStorage.DATABASE,
|
|
default="compact",
|
|
description="UI density/spacing",
|
|
category="theme",
|
|
choices=["compact", "comfortable", "spacious"]
|
|
))
|
|
|
|
register_setting(SettingDefinition(
|
|
key="theme_font_family",
|
|
type=SettingType.STRING,
|
|
scope=SettingScope.GLOBAL,
|
|
storage=SettingStorage.DATABASE,
|
|
default="sans",
|
|
description="Font family for the application",
|
|
category="theme",
|
|
choices=["sans", "inter", "roboto"]
|
|
))
|
|
|
|
register_setting(SettingDefinition(
|
|
key="theme_color_palette",
|
|
type=SettingType.STRING,
|
|
scope=SettingScope.GLOBAL,
|
|
storage=SettingStorage.DATABASE,
|
|
default="monochrome",
|
|
description="Color palette preset",
|
|
category="theme",
|
|
choices=["default", "monochrome", "monochromeBlue", "sepia", "nord", "dracula", "solarized", "github", "ocean", "forest", "midnight", "sunset"]
|
|
))
|
|
|
|
register_setting(SettingDefinition(
|
|
key="theme_custom_colors",
|
|
type=SettingType.JSON,
|
|
scope=SettingScope.GLOBAL,
|
|
storage=SettingStorage.DATABASE,
|
|
default="{}",
|
|
description="Custom color overrides as JSON",
|
|
category="theme"
|
|
))
|
|
|
|
register_setting(SettingDefinition(
|
|
key="theme_dark_mode_location",
|
|
type=SettingType.STRING,
|
|
scope=SettingScope.GLOBAL,
|
|
storage=SettingStorage.DATABASE,
|
|
default="sidebar",
|
|
description="Where to show dark mode toggle",
|
|
category="theme",
|
|
choices=["sidebar", "user_menu"]
|
|
))
|
|
|
|
register_setting(SettingDefinition(
|
|
key="theme_language_location",
|
|
type=SettingType.STRING,
|
|
scope=SettingScope.GLOBAL,
|
|
storage=SettingStorage.DATABASE,
|
|
default="sidebar",
|
|
description="Where to show language toggle",
|
|
category="theme",
|
|
choices=["sidebar", "user_menu"]
|
|
))
|
|
|
|
register_setting(SettingDefinition(
|
|
key="theme_show_dark_mode_toggle",
|
|
type=SettingType.BOOLEAN,
|
|
scope=SettingScope.GLOBAL,
|
|
storage=SettingStorage.DATABASE,
|
|
default=True,
|
|
description="Show/hide dark mode toggle globally",
|
|
category="theme"
|
|
))
|
|
|
|
register_setting(SettingDefinition(
|
|
key="theme_show_language_toggle",
|
|
type=SettingType.BOOLEAN,
|
|
scope=SettingScope.GLOBAL,
|
|
storage=SettingStorage.DATABASE,
|
|
default=False,
|
|
description="Show/hide language toggle globally",
|
|
category="theme"
|
|
))
|
|
|
|
register_setting(SettingDefinition(
|
|
key="theme_show_dark_mode_login",
|
|
type=SettingType.BOOLEAN,
|
|
scope=SettingScope.GLOBAL,
|
|
storage=SettingStorage.DATABASE,
|
|
default=True,
|
|
description="Show dark mode toggle on login page",
|
|
category="theme"
|
|
))
|
|
|
|
register_setting(SettingDefinition(
|
|
key="theme_show_language_login",
|
|
type=SettingType.BOOLEAN,
|
|
scope=SettingScope.GLOBAL,
|
|
storage=SettingStorage.DATABASE,
|
|
default=False,
|
|
description="Show language toggle on login page",
|
|
category="theme"
|
|
))
|
|
|
|
register_setting(SettingDefinition(
|
|
key="theme_tab_bar_position",
|
|
type=SettingType.STRING,
|
|
scope=SettingScope.GLOBAL,
|
|
storage=SettingStorage.DATABASE,
|
|
default="top",
|
|
description="Position of the tab bar (top, bottom, or responsive)",
|
|
category="theme",
|
|
choices=["top", "bottom", "responsive"]
|
|
))
|
|
|
|
|
|
# =============================================================================
|
|
# MODULE/FEATURE SETTINGS (Global, Database)
|
|
# =============================================================================
|
|
|
|
register_setting(SettingDefinition(
|
|
key="module_feature1_admin_enabled",
|
|
type=SettingType.BOOLEAN,
|
|
scope=SettingScope.GLOBAL,
|
|
storage=SettingStorage.DATABASE,
|
|
default=True,
|
|
description="Enable Feature 1 module for admin users",
|
|
category="modules"
|
|
))
|
|
|
|
register_setting(SettingDefinition(
|
|
key="module_feature1_user_enabled",
|
|
type=SettingType.BOOLEAN,
|
|
scope=SettingScope.GLOBAL,
|
|
storage=SettingStorage.DATABASE,
|
|
default=True,
|
|
description="Enable Feature 1 module for regular users",
|
|
category="modules"
|
|
))
|
|
|
|
register_setting(SettingDefinition(
|
|
key="module_feature2_admin_enabled",
|
|
type=SettingType.BOOLEAN,
|
|
scope=SettingScope.GLOBAL,
|
|
storage=SettingStorage.DATABASE,
|
|
default=True,
|
|
description="Enable Feature 2 module for admin users",
|
|
category="modules"
|
|
))
|
|
|
|
register_setting(SettingDefinition(
|
|
key="module_feature2_user_enabled",
|
|
type=SettingType.BOOLEAN,
|
|
scope=SettingScope.GLOBAL,
|
|
storage=SettingStorage.DATABASE,
|
|
default=True,
|
|
description="Enable Feature 2 module for regular users",
|
|
category="modules"
|
|
))
|
|
|
|
register_setting(SettingDefinition(
|
|
key="module_feature3_admin_enabled",
|
|
type=SettingType.BOOLEAN,
|
|
scope=SettingScope.GLOBAL,
|
|
storage=SettingStorage.DATABASE,
|
|
default=True,
|
|
description="Enable Feature 3 module for admin users",
|
|
category="modules"
|
|
))
|
|
|
|
register_setting(SettingDefinition(
|
|
key="module_feature3_user_enabled",
|
|
type=SettingType.BOOLEAN,
|
|
scope=SettingScope.GLOBAL,
|
|
storage=SettingStorage.DATABASE,
|
|
default=True,
|
|
description="Enable Feature 3 module for regular users",
|
|
category="modules"
|
|
))
|
|
|
|
register_setting(SettingDefinition(
|
|
key="modules_order",
|
|
type=SettingType.LIST,
|
|
scope=SettingScope.GLOBAL,
|
|
storage=SettingStorage.DATABASE,
|
|
default=["feature1", "feature2", "feature3"],
|
|
description="Order of feature modules in sidebar",
|
|
category="modules"
|
|
))
|
|
|
|
|
|
# =============================================================================
|
|
# AUTHENTICATION & SECURITY SETTINGS (Global, Database)
|
|
# =============================================================================
|
|
|
|
register_setting(SettingDefinition(
|
|
key="registration_enabled",
|
|
type=SettingType.BOOLEAN,
|
|
scope=SettingScope.GLOBAL,
|
|
storage=SettingStorage.DATABASE,
|
|
default=True,
|
|
description="Allow new user registration",
|
|
category="auth"
|
|
))
|
|
|
|
register_setting(SettingDefinition(
|
|
key="user_mode_enabled",
|
|
type=SettingType.BOOLEAN,
|
|
scope=SettingScope.GLOBAL,
|
|
storage=SettingStorage.DATABASE,
|
|
default=False,
|
|
description="Enable admin/user view mode switching",
|
|
category="auth"
|
|
))
|
|
|
|
# Password policy settings
|
|
register_setting(SettingDefinition(
|
|
key="password_min_length",
|
|
type=SettingType.INTEGER,
|
|
scope=SettingScope.GLOBAL,
|
|
storage=SettingStorage.DATABASE,
|
|
default=8,
|
|
description="Minimum password length",
|
|
category="security"
|
|
))
|
|
|
|
register_setting(SettingDefinition(
|
|
key="password_require_uppercase",
|
|
type=SettingType.BOOLEAN,
|
|
scope=SettingScope.GLOBAL,
|
|
storage=SettingStorage.DATABASE,
|
|
default=True,
|
|
description="Require uppercase letters in passwords",
|
|
category="security"
|
|
))
|
|
|
|
register_setting(SettingDefinition(
|
|
key="password_require_lowercase",
|
|
type=SettingType.BOOLEAN,
|
|
scope=SettingScope.GLOBAL,
|
|
storage=SettingStorage.DATABASE,
|
|
default=True,
|
|
description="Require lowercase letters in passwords",
|
|
category="security"
|
|
))
|
|
|
|
register_setting(SettingDefinition(
|
|
key="password_require_digit",
|
|
type=SettingType.BOOLEAN,
|
|
scope=SettingScope.GLOBAL,
|
|
storage=SettingStorage.DATABASE,
|
|
default=True,
|
|
description="Require digits in passwords",
|
|
category="security"
|
|
))
|
|
|
|
register_setting(SettingDefinition(
|
|
key="password_require_special",
|
|
type=SettingType.BOOLEAN,
|
|
scope=SettingScope.GLOBAL,
|
|
storage=SettingStorage.DATABASE,
|
|
default=False,
|
|
description="Require special characters in passwords",
|
|
category="security"
|
|
))
|
|
|
|
|
|
# =============================================================================
|
|
# UI/LAYOUT SETTINGS (Global, Database)
|
|
# =============================================================================
|
|
|
|
register_setting(SettingDefinition(
|
|
key="sidebar_mode",
|
|
type=SettingType.STRING,
|
|
scope=SettingScope.GLOBAL,
|
|
storage=SettingStorage.DATABASE,
|
|
default="toggle",
|
|
description="Sidebar behavior mode",
|
|
category="ui",
|
|
choices=["collapsed", "expanded", "toggle", "dynamic"]
|
|
))
|
|
|
|
register_setting(SettingDefinition(
|
|
key="show_logo",
|
|
type=SettingType.BOOLEAN,
|
|
scope=SettingScope.GLOBAL,
|
|
storage=SettingStorage.DATABASE,
|
|
default=True,
|
|
description="Show logo in sidebar instead of text",
|
|
category="ui"
|
|
))
|
|
|
|
|
|
# =============================================================================
|
|
# USER-SPECIFIC SETTINGS (Frontend localStorage)
|
|
# These settings are managed by the frontend per-browser/user-session.
|
|
# If you need cross-device persistence, implement a per-user DB table + API.
|
|
# =============================================================================
|
|
|
|
register_setting(SettingDefinition(
|
|
key="user_theme_mode",
|
|
type=SettingType.STRING,
|
|
scope=SettingScope.USER_SPECIFIC,
|
|
storage=SettingStorage.LOCAL_STORAGE,
|
|
default="system",
|
|
description="User's preferred theme mode (light/dark/system)",
|
|
category="user_preferences",
|
|
admin_only=False,
|
|
choices=["light", "dark", "system"]
|
|
))
|
|
|
|
register_setting(SettingDefinition(
|
|
key="user_language",
|
|
type=SettingType.STRING,
|
|
scope=SettingScope.USER_SPECIFIC,
|
|
storage=SettingStorage.LOCAL_STORAGE,
|
|
default="en",
|
|
description="User's preferred language",
|
|
category="user_preferences",
|
|
admin_only=False,
|
|
choices=["en", "it"]
|
|
))
|
|
|
|
register_setting(SettingDefinition(
|
|
key="user_sidebar_collapsed",
|
|
type=SettingType.BOOLEAN,
|
|
scope=SettingScope.USER_SPECIFIC,
|
|
storage=SettingStorage.LOCAL_STORAGE,
|
|
default=False,
|
|
description="User's sidebar collapsed state preference",
|
|
category="user_preferences",
|
|
admin_only=False
|
|
))
|
|
|
|
register_setting(SettingDefinition(
|
|
key="user_view_mode",
|
|
type=SettingType.STRING,
|
|
scope=SettingScope.USER_SPECIFIC,
|
|
storage=SettingStorage.LOCAL_STORAGE,
|
|
default="admin",
|
|
description="User's current view mode (admin/user)",
|
|
category="user_preferences",
|
|
admin_only=False,
|
|
choices=["admin", "user"]
|
|
))
|
|
|
|
|
|
# =============================================================================
|
|
# SYSTEM/ENVIRONMENT SETTINGS (Infrastructure, .env file)
|
|
# These are NOT stored in the database
|
|
# =============================================================================
|
|
|
|
register_setting(SettingDefinition(
|
|
key="SECRET_KEY",
|
|
type=SettingType.STRING,
|
|
scope=SettingScope.SYSTEM,
|
|
storage=SettingStorage.ENV,
|
|
default=None, # Required, no default
|
|
description="Secret key for JWT token signing",
|
|
category="security",
|
|
sync_to_frontend=False
|
|
))
|
|
|
|
register_setting(SettingDefinition(
|
|
key="DATABASE_URL",
|
|
type=SettingType.STRING,
|
|
scope=SettingScope.SYSTEM,
|
|
storage=SettingStorage.ENV,
|
|
default="sqlite:////config/config.db",
|
|
description="Database connection URL",
|
|
category="infrastructure",
|
|
sync_to_frontend=False
|
|
))
|
|
|
|
register_setting(SettingDefinition(
|
|
key="ALGORITHM",
|
|
type=SettingType.STRING,
|
|
scope=SettingScope.SYSTEM,
|
|
storage=SettingStorage.ENV,
|
|
default="HS256",
|
|
description="JWT signing algorithm",
|
|
category="security",
|
|
sync_to_frontend=False
|
|
))
|
|
|
|
register_setting(SettingDefinition(
|
|
key="ACCESS_TOKEN_EXPIRE_MINUTES",
|
|
type=SettingType.INTEGER,
|
|
scope=SettingScope.SYSTEM,
|
|
storage=SettingStorage.ENV,
|
|
default=1440,
|
|
description="JWT token expiration time in minutes",
|
|
category="security",
|
|
sync_to_frontend=False
|
|
))
|
|
|
|
register_setting(SettingDefinition(
|
|
key="ALLOWED_HOSTS",
|
|
type=SettingType.LIST,
|
|
scope=SettingScope.SYSTEM,
|
|
storage=SettingStorage.ENV,
|
|
default=[],
|
|
description="Additional allowed CORS origins",
|
|
category="security",
|
|
sync_to_frontend=False
|
|
))
|
|
|
|
register_setting(SettingDefinition(
|
|
key="LOG_LEVEL",
|
|
type=SettingType.STRING,
|
|
scope=SettingScope.SYSTEM,
|
|
storage=SettingStorage.ENV,
|
|
default="info",
|
|
description="Application logging level",
|
|
category="infrastructure",
|
|
choices=["debug", "info", "warning", "error", "critical"],
|
|
sync_to_frontend=False
|
|
))
|
|
|
|
register_setting(SettingDefinition(
|
|
key="DEBUG",
|
|
type=SettingType.BOOLEAN,
|
|
scope=SettingScope.SYSTEM,
|
|
storage=SettingStorage.ENV,
|
|
default=False,
|
|
description="Enable debug mode",
|
|
category="infrastructure",
|
|
sync_to_frontend=False
|
|
))
|
|
|
|
|
|
# =============================================================================
|
|
# FRONTEND-ONLY SETTINGS (localStorage, not in database)
|
|
# These are managed entirely by the frontend
|
|
# =============================================================================
|
|
|
|
register_setting(SettingDefinition(
|
|
key="token",
|
|
type=SettingType.STRING,
|
|
scope=SettingScope.USER_SPECIFIC,
|
|
storage=SettingStorage.LOCAL_STORAGE,
|
|
default=None,
|
|
description="JWT authentication token",
|
|
category="auth",
|
|
sync_to_frontend=False # Managed by frontend only
|
|
))
|
|
|
|
|
|
# =============================================================================
|
|
# HELPER FUNCTIONS
|
|
# =============================================================================
|
|
|
|
def get_settings_by_category(category: str) -> list[SettingDefinition]:
|
|
"""Get all settings in a specific category."""
|
|
return [s for s in SETTINGS_REGISTRY.values() if s.category == category]
|
|
|
|
|
|
def get_settings_by_scope(scope: SettingScope) -> list[SettingDefinition]:
|
|
"""Get all settings with a specific scope."""
|
|
return [s for s in SETTINGS_REGISTRY.values() if s.scope == scope]
|
|
|
|
|
|
def get_settings_by_storage(storage: SettingStorage) -> list[SettingDefinition]:
|
|
"""Get all settings stored in a specific location."""
|
|
return [s for s in SETTINGS_REGISTRY.values() if s.storage == storage]
|
|
|
|
|
|
def get_database_settings() -> list[SettingDefinition]:
|
|
"""Get all settings that should be stored in the database."""
|
|
return get_settings_by_storage(SettingStorage.DATABASE)
|
|
|
|
|
|
def get_global_settings() -> list[SettingDefinition]:
|
|
"""Get all global (non user-specific) settings."""
|
|
return get_settings_by_scope(SettingScope.GLOBAL)
|
|
|
|
|
|
def get_user_specific_settings() -> list[SettingDefinition]:
|
|
"""Get all user-specific settings."""
|
|
return get_settings_by_scope(SettingScope.USER_SPECIFIC)
|
|
|
|
|
|
def get_default_value(key: str) -> Any:
|
|
"""Get the default value for a setting."""
|
|
if key in SETTINGS_REGISTRY:
|
|
return SETTINGS_REGISTRY[key].default
|
|
return None
|
|
|
|
|
|
def get_all_defaults() -> dict[str, Any]:
|
|
"""Get all default values as a dictionary."""
|
|
return {key: setting.default for key, setting in SETTINGS_REGISTRY.items()}
|
|
|
|
|
|
def get_database_defaults() -> dict[str, Any]:
|
|
"""Get default values for all database-stored settings."""
|
|
return {
|
|
setting.key: setting.default
|
|
for setting in get_database_settings()
|
|
}
|
|
|
|
|
|
def validate_setting_value(key: str, value: Any) -> bool:
|
|
"""Validate a setting value against its definition."""
|
|
if key not in SETTINGS_REGISTRY:
|
|
return False
|
|
|
|
setting = SETTINGS_REGISTRY[key]
|
|
|
|
# Check type
|
|
if setting.type == SettingType.BOOLEAN:
|
|
if not isinstance(value, bool) and value not in ['true', 'false', 'True', 'False']:
|
|
return False
|
|
elif setting.type == SettingType.INTEGER:
|
|
if not isinstance(value, int):
|
|
try:
|
|
int(value)
|
|
except (ValueError, TypeError):
|
|
return False
|
|
elif setting.type == SettingType.STRING:
|
|
if not isinstance(value, str):
|
|
return False
|
|
|
|
# Check choices if defined
|
|
if setting.choices and value not in setting.choices:
|
|
# For booleans converted to strings
|
|
if setting.type == SettingType.BOOLEAN:
|
|
return True
|
|
return False
|
|
|
|
return True
|
|
|
|
|
|
# =============================================================================
|
|
# CATEGORY KEYS (for API endpoints)
|
|
# =============================================================================
|
|
|
|
THEME_KEYS = [s.key for s in get_settings_by_category("theme")]
|
|
MODULE_KEYS = [s.key for s in get_settings_by_category("modules")]
|
|
AUTH_KEYS = [s.key for s in get_settings_by_category("auth")]
|
|
UI_KEYS = [s.key for s in get_settings_by_category("ui")]
|
|
USER_PREFERENCE_KEYS = [s.key for s in get_settings_by_category("user_preferences")]
|
|
|
|
|
|
# =============================================================================
|
|
# PRINT SUMMARY (for debugging)
|
|
# =============================================================================
|
|
|
|
if __name__ == "__main__":
|
|
print("\n=== SETTINGS REGISTRY SUMMARY ===\n")
|
|
|
|
print(f"Total settings: {len(SETTINGS_REGISTRY)}")
|
|
print(f" - Database settings: {len(get_database_settings())}")
|
|
print(f" - Global settings: {len(get_global_settings())}")
|
|
print(f" - User-specific settings: {len(get_user_specific_settings())}")
|
|
|
|
print("\n--- By Category ---")
|
|
categories = set(s.category for s in SETTINGS_REGISTRY.values())
|
|
for cat in sorted(categories):
|
|
settings = get_settings_by_category(cat)
|
|
print(f" {cat}: {len(settings)} settings")
|
|
|
|
print("\n--- Database Settings (stored in /config/config.db) ---")
|
|
for setting in get_database_settings():
|
|
scope_label = "GLOBAL" if setting.scope == SettingScope.GLOBAL else "USER"
|
|
print(f" [{scope_label}] {setting.key}: {setting.type.value} = {setting.default}")
|