Skip to content

UI Configuration Editor #80

@AliiiBenn

Description

@AliiiBenn

ISSUE-067: UI Configuration Editor

Description

Currently, users must manually edit the config.yaml file to customize application settings. This issue proposes implementing a user-friendly dialog interface that allows users to modify configuration settings directly from the application UI.

Current State

  • Configuration is stored in config.yaml (auto-generated on first run)
  • Users must edit YAML file manually with a text editor
  • No GUI way to modify settings
  • Risk of syntax errors when editing YAML manually
  • Settings available:
    • alerts: warning_days, critical_days
    • lock: timeout_minutes, heartbeat_interval_seconds
    • organization: roles list, workspaces list

Problem

User Experience Issues:

  • Non-technical users may be uncomfortable editing YAML files
  • Risk of breaking syntax (indentation, format errors)
  • No visual feedback on valid value ranges
  • No validation until application restart
  • Changes require manual file editing with external tools

Support Issues:

  • Users need to understand YAML syntax
  • Configuration errors cause application failures
  • Hard to troubleshoot user config mistakes
  • Documentation must explain YAML editing

Expected Behavior

Main Dialog Features

Access:

  • New "⚙️ Paramètres" button in main navigation bar
  • Opens modal dialog similar to "Alert Settings" dialog

Tabbed Interface (3 tabs):

Tab 1: ⚠️ Alertes (Alerts)

┌─────────────────────────────────────────────┐
│ ⚠️ Paramètres d'Alerte                      │
│                                             │
│   Jours Warning :  [30    ]                 │
│   Jours Critique:  [7     ]                 │
│                                             │
│   Validation: critical < warning            │
└─────────────────────────────────────────────┘

Tab 2: 🔒 Verrouillage (Lock)

┌─────────────────────────────────────────────┐
│ 🔒 Verrouillage Concurrent                  │
│                                             │
│   Timeout (minutes):     [2    ]            │
│   Heartbeat (secondes):  [30   ]            │
│                                             │
│   Prevents multiple users from editing      │
└─────────────────────────────────────────────┘

Tab 3: 🏢 Organisation

┌─────────────────────────────────────────────┐
│ 🏢 Structure Organisation                  │
│                                             │
│   Postes/Rôles :                            │
│   ┌──────────────────────────────────────┐ │
│   │ Cariste                      [X]    │ │
│   │ Préparateur de commandes     [X]    │ │
│   │ Magasinier                   [X]    │ │
│   │ [+ Ajouter]                         │ │
│   └──────────────────────────────────────┘ │
│                                             │
│   Zones de travail :                        │
│   ┌──────────────────────────────────────┐ │
│   │ Quai                         [X]    │ │
│   │ Zone A                       [X]    │ │
│   │ [+ Ajouter]                         │ │
│   └──────────────────────────────────────┘ │
└─────────────────────────────────────────────┘

Dialog Behavior

Similar to AlertSettingsDialog:

  • Modal window (blocks main app)
  • 3 buttons: Enregistrer, Réinitialiser, Annuler
  • Validation before save
  • Unsaved changes detection (via BaseFormDialog)
  • Confirmation prompt if closing with unsaved changes
  • Status messages (success/error)
  • Auto-close after successful save (1 second delay)

Validation:

  • Positive values for all numeric fields
  • critical_days < warning_days
  • At least 1 role in organization
  • At least 1 workspace in organization
  • No empty strings in lists

Implementation Details

Files to Create

  1. src/ui_ctk/dialogs/app_config_dialog.py (NEW)

    • AppConfigDialog class
    • Extends BaseFormDialog
    • 300-400 lines estimated
    • Pattern: Similar to AlertSettingsDialog
    • Uses CTkNotebook for tabs
  2. src/utils/config_validators.py (OPTIONAL)

    • Specific validators for UI config editing
    • May reuse existing validate_config()
    • Helper functions for real-time validation

Files to Modify

  1. src/ui_ctk/main_window.py

    • Add show_app_settings() method
    • Add "⚙️ Paramètres" button to navigation bar
    • Integrate with existing navigation pattern
  2. src/ui_ctk/constants.py (OPTIONAL)

    • May add NAV_SETTINGS = "Paramètres" constant

Key Methods to Implement

class AppConfigDialog(BaseFormDialog):
    def __init__(self, parent):
        # Load current config with load_config()
        # Store original for unsaved changes detection
        # Initialize Tkinter variables for each field

    def create_form(self):
        # Create CTkNotebook with 3 tabs
        # Call _create_alerts_tab(), _create_lock_tab(), _create_org_tab()

    def _create_alerts_tab(self, parent):
        # 2 numeric inputs: warning_days, critical_days
        # Validation labels

    def _create_lock_tab(self, parent):
        # 2 numeric inputs: timeout_minutes, heartbeat_interval_seconds
        # Help text explaining concurrent access

    def _create_organization_tab(self, parent):
        # 2 editable lists with add/remove buttons
        # Scrollable frames for each list
        # Pattern: Similar to employee detail list views

    def _add_item(self, container, vars_list):
        # Add new row with entry + delete button

    def _remove_item(self, row, var, vars_list):
        # Remove row from list

    def validate(self) -> Tuple[bool, Optional[str]]:
        # Validate all fields
        # Check critical_days < warning_days
        # Check list not empty
        # Check positive values

    def save(self):
        # Build config dict from Tkinter variables
        # Call validate_config() for final check
        # Call save_config() to write config.yaml
        # Set result = True

Integration with Existing Config System

Reuse existing functions:

from utils.config import load_config, save_config, validate_config

# Load current configuration
config = load_config()

# Save modified configuration
save_config(new_config, Path("config.yaml"))

# Validate before saving
is_valid, errors = validate_config(new_config)

Editable Lists Implementation Pattern

For roles and workspaces lists:

def _create_editable_list(self, parent, items: list[str], title: str):
    """
    Create an editable list with add/remove buttons.

    Returns:
        List of StringVar for data binding
    """
    vars_list = []
    container = ctk.CTkFrame(parent)
    container.pack(fill="both", expand=True)

    # Title label
    ctk.CTkLabel(container, text=title, font=("Arial", 12, "bold")).pack(anchor="w")

    # Scrollable list
    scroll = ctk.CTkScrollableFrame(container, height=150)
    scroll.pack(fill="both", expand=True)

    # Create row for each item
    for item in items:
        row = ctk.CTkFrame(scroll, fg_color="transparent")
        row.pack(fill="x", pady=2)

        var = ctk.StringVar(value=item)
        vars_list.append(var)

        ctk.CTkEntry(row, textvariable=var).pack(side="left", fill="x", expand=True)

        ctk.CTkButton(
            row, text="✕", width=30,
            command=lambda: self._remove_item(row, var, vars_list)
        ).pack(side="left")

    # Add button
    ctk.CTkButton(
        container, text="+ Ajouter",
        command=lambda: self._add_item(scroll, vars_list)
    ).pack(anchor="w")

    return vars_list

UI/UX Considerations

Dialog Size & Position

  • Size: 900x750 (larger than AlertSettingsDialog)
  • Centered on parent window
  • Modal (blocks main app)

Visual Feedback

  • Color-coded validation indicators (similar to AlertSettingsDialog)
  • Real-time validation where possible
  • Clear error messages
  • Success message with auto-close

Unsaved Changes

  • Leverage BaseFormDialog automatic tracking
  • Warning on close if unsaved
  • Options: Save, Discard, Cancel

Accessibility

  • Clear labels in French
  • Helpful tooltips/help text
  • Logical tab ordering
  • Keyboard navigation support

Technical Challenges

1. YAML Comment Preservation

Issue: PyYAML loses comments when saving

Solutions (in preference order):

  1. Accept comment loss - Regenerate template with new values
  2. Use ruamel.yaml - Preserves comments (new dependency)
  3. Hybrid approach - Save values only, users re-edit in text editor if needed

Recommendation: Accept comment loss (option 1)

  • Template comments are for first-time setup
  • Power users can still edit YAML manually
  • Simpler implementation, no new dependencies

2. Real-time Validation

Approach: Use trace_add on Tkinter variables

# Validate when value changes
self.warning_days_var.trace_add('write', self._on_warning_days_changed)

def _on_warning_days_changed(self, *args):
    warning = self.warning_days_var.get()
    critical = self.critical_days_var.get()

    if warning <= critical:
        # Show validation error
        self.warning_error_label.configure(
            text="Doit être supérieur à critique",
            text_color="red"
        )
        self.warning_entry.configure(border_color="red")
    else:
        # Clear error
        self.warning_error_label.configure(text="")
        self.warning_entry.configure(border_color="gray")

3. Config Reload After Save

Issue: Application needs to use new values

Solutions:

  1. Hot reload - Reload config and update all components
  2. Restart required - Prompt user to restart app
  3. Selective reload - Reload only affected modules

Recommendation: Restart required (simplest)

  • Show dialog: "Configuration sauvegardée. Veuillez redémarrer l'application."
  • Consistent behavior, no complex state management

Affected Files

New Files

  • src/ui_ctk/dialogs/app_config_dialog.py - Main dialog implementation

Modified Files

  • src/ui_ctk/main_window.py - Add settings button and callback
  • src/ui_ctk/constants.py - Optionally add NAV_SETTINGS constant

Optional Files

  • src/utils/config_validators.py - UI-specific validators (if needed)

Implementation Plan

  1. Phase 1: Basic Dialog Structure

    • Create AppConfigDialog class extending BaseFormDialog
    • Implement dialog layout with CTkNotebook (3 tabs)
    • Add buttons (Enregistrer, Réinitialiser, Annuler)
    • Wire up unsaved changes detection
  2. Phase 2: Alerts & Lock Tabs

    • Implement alerts tab with 2 numeric inputs
    • Implement lock tab with 2 numeric inputs
    • Add validation (positive values, critical < warning)
    • Test save/load functionality
  3. Phase 3: Organization Tab

    • Implement editable lists for roles
    • Implement editable lists for workspaces
    • Add add/remove functionality
    • Validate non-empty lists
  4. Phase 4: Integration

    • Add settings button to MainWindow
    • Implement show_app_settings() callback
    • Add restart prompt after save
    • End-to-end testing
  5. Phase 5: Polish

    • Add help text/tooltips
    • Improve visual feedback
    • Add keyboard shortcuts
    • Accessibility review
    • Documentation updates

Acceptance Criteria

  • "⚙️ Paramètres" button visible in main navigation
  • Dialog opens with current config values loaded
  • All 3 tabs display correctly with appropriate fields
  • Can modify alerts settings and save successfully
  • Can modify lock settings and save successfully
  • Can add/edit/remove roles in organization tab
  • Can add/edit/remove workspaces in organization tab
  • Validation prevents invalid saves
  • Unsaved changes prompt appears when closing
  • Reset button restores values from config file
  • Cancel button closes without saving
  • Save button writes valid config.yaml file
  • App prompts for restart after saving
  • New settings are loaded after restart
  • All existing tests pass
  • New tests for dialog functionality

Estimated Effort

Total: 6-8 hours

  • Phase 1 (Dialog structure): 1.5 hours
  • Phase 2 (Alerts & Lock tabs): 2 hours
  • Phase 3 (Organization tab with lists): 2.5 hours
  • Phase 4 (Integration): 1 hour
  • Phase 5 (Polish & testing): 1-1.5 hours

Related Issues

None

Dependencies

  • BLOCKED BY: None
  • BLOCKS: None
  • RELATED: None

Example Use Cases

Use Case 1: Adjust Alert Thresholds

  1. Warehouse manager wants earlier warnings for certifications
  2. Opens ⚙️ Paramètres dialog
  3. Goes to "⚠️ Alertes" tab
  4. Changes "Jours Warning" from 30 to 60
  5. Clicks "Enregistrer"
  6. Dialog closes, prompt to restart appears
  7. After restart, warnings now appear 60 days before expiration

Use Case 2: Add New Workspace

  1. Company opens new warehouse zone "Zone D"
  2. Opens ⚙️ Paramètres dialog
  3. Goes to "🏢 Organisation" tab
  4. In "Zones de travail" list, clicks "+ Ajouter"
  5. Types "Zone D" in new entry
  6. Clicks "Enregistrer"
  7. After restart, "Zone D" appears in workspace dropdowns

Use Case 3: Configure Concurrent Access

  1. IT wants to adjust lock timeout for slow network
  2. Opens ⚙️ Paramètres dialog
  3. Goes to "🔒 Verrouillage" tab
  4. Changes "Timeout (minutes)" from 2 to 5
  5. Clicks "Enregistrer"
  6. After restart, lock timeout is now 5 minutes

Notes

Design Patterns to Follow

  • AlertSettingsDialog: Good reference for tabbed config dialog
  • BaseFormDialog: Extend for unsaved changes tracking
  • employee_detail.py: Reference for editable list patterns

Configuration System

  • Config file location: config.yaml in working directory
  • File format: YAML (with JSON fallback)
  • Auto-generated on first run
  • Uses PyYAML library
  • Comments may be lost on save (acceptable)

Future Enhancements

  • GUI-based config editor for advanced settings (database path, log level)
  • Import/export of configuration files
  • Configuration presets (templates for different warehouse types)
  • Per-user configuration profiles
  • Real-time config reload (without restart)

Documentation Updates Required

  • User manual: "Configuration" section
  • Screenshot of config dialog
  • Explanation of each setting
  • Troubleshooting common config issues

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions