Skip to content

Commit 898d32c

Browse files
committed
feat(config): auto-generate config.yaml on first run
Add automatic config file generation when launching the application in an empty workspace (no existing config.yaml/config.yml/config.json). Changes: - Add ensure_default_config() function to create config.yaml with defaults - Integrate config generation into app startup (before database setup) - Add config.yaml/config.yml/config.json to .gitignore (user-specific) - Default config includes helpful comments explaining each section Benefits: - New users get a ready-to-use config file they can customize - No need to manually copy or create config files - Easier onboarding with documented configuration options - Existing configs are never overwritten Technical details: - Checks for existing config before creating (yaml > yml > json) - Only creates if YAML library is available - Silently falls back to defaults if creation fails (read-only fs) - Contains all DEFAULT_CONFIG values with inline documentation
1 parent f5eac0a commit 898d32c

3 files changed

Lines changed: 118 additions & 0 deletions

File tree

.gitignore

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,11 @@ exports/
7979
logs/
8080
backups/
8181

82+
# User configuration (auto-generated on first run)
83+
config.yaml
84+
config.yml
85+
config.json
86+
8287
# Test files in root directory (ad-hoc tests)
8388
test_*.py
8489

src/ui_ctk/app.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -253,6 +253,15 @@ def main():
253253
setup_logging(level="INFO", enable_console=True, enable_file=True)
254254
logger.info(f"Starting {APP_NAME} v{APP_VERSION}")
255255

256+
# Step 0.5: Ensure default config file exists
257+
from utils.config import ensure_default_config
258+
config_path = ensure_default_config()
259+
if config_path:
260+
print(f"[OK] Default config created: {config_path}")
261+
print(f" You can customize this file to change application settings")
262+
else:
263+
print("[INFO] Using existing configuration or defaults")
264+
256265
# Step 1: Setup CustomTkinter
257266
setup_customtkinter()
258267

src/utils/config.py

Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -705,3 +705,107 @@ def ensure_database_directory() -> Path:
705705
db_dir = get_database_dir()
706706
db_dir.mkdir(parents=True, exist_ok=True)
707707
return db_dir
708+
709+
710+
def ensure_default_config() -> Path | None:
711+
"""
712+
Create default config.yaml if no config file exists.
713+
714+
This function checks for existing config files (config.yaml, config.yml, config.json).
715+
If none exist, it creates a config.yaml file with default values and helpful comments.
716+
717+
Returns:
718+
Path to created config.yaml, or None if config already exists or YAML not available
719+
720+
Example:
721+
>>> config_path = ensure_default_config()
722+
>>> if config_path:
723+
... print(f"Created: {config_path}")
724+
"""
725+
# Check if any config file already exists
726+
for filename in ["config.yaml", "config.yml", "config.json"]:
727+
if Path(filename).exists():
728+
return None # Config already exists, don't overwrite
729+
730+
# Check if YAML is available
731+
if not YAML_AVAILABLE:
732+
# Can't create YAML file, will use defaults
733+
return None
734+
735+
# Create default config.yaml with comments
736+
default_config_content = """# Wareflow EMS Configuration File
737+
# This file controls application behavior and settings.
738+
#
739+
# Format: YAML (recommended over JSON for readability)
740+
# - Comments start with # (like this line)
741+
# - Indentation matters (use spaces, not tabs)
742+
# - Strings don't need quotes (most of the time)
743+
744+
# ============================================================================
745+
# ALERT SETTINGS
746+
# ============================================================================
747+
# Configure when alerts are shown for expiring certifications and visits
748+
alerts:
749+
# Warning period: Show warnings when expiration is within this many days
750+
warning_days: 30
751+
752+
# Critical period: Show critical alerts when expiration is within this many days
753+
critical_days: 7
754+
755+
# ============================================================================
756+
# LOCK SETTINGS
757+
# ============================================================================
758+
# Prevent multiple users from modifying the database simultaneously
759+
lock:
760+
# Auto-lock timeout: Release lock after this many minutes of inactivity
761+
timeout_minutes: 2
762+
763+
# Heartbeat interval: Send heartbeat signal every N seconds to maintain lock
764+
heartbeat_interval_seconds: 30
765+
766+
# ============================================================================
767+
# ORGANIZATION SETTINGS
768+
# ============================================================================
769+
# Define your organization structure (roles and workspaces)
770+
# These values are used in employee dropdowns and validation
771+
organization:
772+
# Job positions/roles in your organization
773+
roles:
774+
- Cariste
775+
- Préparateur de commandes
776+
- Magasinier
777+
- Réceptionnaire
778+
- Gestionnaire
779+
- Chef d'équipe
780+
781+
# Physical work areas/locations in your warehouse
782+
workspaces:
783+
- Quai
784+
- Zone A
785+
- Zone B
786+
- Zone C
787+
- Bureau
788+
- Stockage
789+
790+
# ============================================================================
791+
# ADVANCED SETTINGS (OPTIONAL)
792+
# ============================================================================
793+
# These settings have sensible defaults and rarely need to be changed
794+
#
795+
# Database location (use environment variables DATABASE_DIR and DATABASE_NAME instead)
796+
# See README.md for more details on configuration
797+
"""
798+
799+
try:
800+
config_path = Path("config.yaml")
801+
802+
# Write the default config file
803+
with open(config_path, "w", encoding="utf-8") as f:
804+
f.write(default_config_content)
805+
806+
return config_path
807+
808+
except (IOError, OSError) as e:
809+
# Silent fail - application will use defaults
810+
# This avoids issues in read-only environments
811+
return None

0 commit comments

Comments
 (0)