fix: Better error handling for goal types loading
Some checks failed
Build Test / lint-backend (push) Waiting to run
Build Test / build-frontend (push) Waiting to run
Deploy Development / deploy (push) Has been cancelled

- Check if goal_type_definitions table exists
- Detailed error messages
- Fallback if goalTypes is empty
- Prevent form opening without types

Helps debugging Migration 024 issues.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Lars 2026-03-27 07:28:14 +01:00
parent 043bed4323
commit bbee44ecdc
2 changed files with 63 additions and 29 deletions

View File

@ -14,6 +14,7 @@ from pydantic import BaseModel
from typing import Optional, List from typing import Optional, List
from datetime import date, datetime, timedelta from datetime import date, datetime, timedelta
from decimal import Decimal from decimal import Decimal
import traceback
from db import get_db, get_cursor, r2d from db import get_db, get_cursor, r2d
from auth import require_auth from auth import require_auth
@ -499,24 +500,51 @@ def list_goal_type_definitions(session: dict = Depends(require_auth)):
Public endpoint - returns all available goal types for dropdown. Public endpoint - returns all available goal types for dropdown.
""" """
with get_db() as conn: try:
cur = get_cursor(conn) with get_db() as conn:
cur.execute(""" cur = get_cursor(conn)
SELECT id, type_key, label_de, label_en, unit, icon, category,
source_table, source_column, aggregation_method,
calculation_formula, description, is_system,
created_at, updated_at
FROM goal_type_definitions
WHERE is_active = true
ORDER BY
CASE
WHEN is_system = true THEN 0
ELSE 1
END,
label_de
""")
return [r2d(row) for row in cur.fetchall()] # Check if table exists first
cur.execute("""
SELECT EXISTS (
SELECT FROM information_schema.tables
WHERE table_name = 'goal_type_definitions'
)
""")
table_exists = cur.fetchone()[0]
if not table_exists:
print("[ERROR] goal_type_definitions table does not exist!")
raise HTTPException(
status_code=500,
detail="Goal Types Tabelle existiert nicht. Migration 024 muss ausgeführt werden."
)
cur.execute("""
SELECT id, type_key, label_de, label_en, unit, icon, category,
source_table, source_column, aggregation_method,
calculation_formula, description, is_system,
created_at, updated_at
FROM goal_type_definitions
WHERE is_active = true
ORDER BY
CASE
WHEN is_system = true THEN 0
ELSE 1
END,
label_de
""")
return [r2d(row) for row in cur.fetchall()]
except HTTPException:
raise
except Exception as e:
print(f"[ERROR] list_goal_type_definitions failed: {e}")
print(traceback.format_exc())
raise HTTPException(
status_code=500,
detail=f"Fehler beim Laden der Goal Types: {str(e)}"
)
@router.post("/goal-types") @router.post("/goal-types")
def create_goal_type_definition( def create_goal_type_definition(

View File

@ -84,21 +84,23 @@ export default function GoalsPage() {
// Convert types array to map for quick lookup // Convert types array to map for quick lookup
const typesMap = {} const typesMap = {}
typesData.forEach(type => { if (typesData && Array.isArray(typesData)) {
typesMap[type.type_key] = { typesData.forEach(type => {
label: type.label_de, typesMap[type.type_key] = {
unit: type.unit, label: type.label_de,
icon: type.icon || '📊', unit: type.unit,
category: type.category, icon: type.icon || '📊',
is_system: type.is_system category: type.category,
} is_system: type.is_system
}) }
})
}
setGoalTypes(typesData) setGoalTypes(typesData || [])
setGoalTypesMap(typesMap) setGoalTypesMap(typesMap)
} catch (err) { } catch (err) {
console.error('Failed to load goals:', err) console.error('Failed to load goals:', err)
setError('Fehler beim Laden der Ziele') setError(`Fehler beim Laden: ${err.message || err.toString()}`)
} finally { } finally {
setLoading(false) setLoading(false)
} }
@ -121,8 +123,12 @@ export default function GoalsPage() {
} }
const handleCreateGoal = () => { const handleCreateGoal = () => {
if (goalTypes.length === 0) {
setError('Keine Goal Types verfügbar. Bitte Admin kontaktieren.')
return
}
setEditingGoal(null) setEditingGoal(null)
const firstType = goalTypes.length > 0 ? goalTypes[0].type_key : 'weight' const firstType = goalTypes[0].type_key
setFormData({ setFormData({
goal_type: firstType, goal_type: firstType,
is_primary: goals.length === 0, // First goal is primary by default is_primary: goals.length === 0, // First goal is primary by default