diff --git a/backend/src/main.py b/backend/src/main.py index aca6ac5..c09a35c 100644 --- a/backend/src/main.py +++ b/backend/src/main.py @@ -109,7 +109,8 @@ async def get_settings_status(): return { "garmin": { - "configured": bool(os.getenv("GARMIN_EMAIL") and os.getenv("GARMIN_PASSWORD")) + "configured": bool(os.getenv("GARMIN_EMAIL") and os.getenv("GARMIN_PASSWORD")), + "email": os.getenv("GARMIN_EMAIL") }, "withings": { "configured": bool(os.getenv("WITHINGS_CLIENT_ID") and os.getenv("WITHINGS_CLIENT_SECRET")) diff --git a/backend/tests/test_api.py b/backend/tests/test_api.py index c193fa6..d026ee3 100644 --- a/backend/tests/test_api.py +++ b/backend/tests/test_api.py @@ -184,9 +184,11 @@ def test_update_settings_gemini_missing(): assert response.status_code == 400 def test_auth_status_not_configured(monkeypatch): - monkeypatch.setenv("GARMIN_EMAIL", "") - response = client.get("/auth/status") - assert response.json()["authenticated"] is False + # Mock load_service_env to prevent reloading from file + with patch("main.env.load_service_env"): + monkeypatch.setenv("GARMIN_EMAIL", "") + response = client.get("/auth/status") + assert response.json()["authenticated"] is False def test_sync_full_success(mock_sync): with patch("main.GarminClient") as mock_client: @@ -269,9 +271,12 @@ def test_trigger_sync_endpoint_fail(): response = client.post("/sync") assert response.status_code == 401 -def test_login_credentials_missing(): - response = client.post("/auth/login", json={"email": ""}) - assert response.status_code == 400 +def test_login_credentials_missing(monkeypatch): + with patch("main.env.load_service_env"): + monkeypatch.setenv("GARMIN_EMAIL", "") + monkeypatch.setenv("GARMIN_PASSWORD", "") + response = client.post("/auth/login", json={"email": ""}) + assert response.status_code == 400 def test_login_failed_error(): with patch("main.GarminClient") as mock_client: diff --git a/backend/tests/test_garmin_client.py b/backend/tests/test_garmin_client.py index b7fdae2..72d3207 100644 --- a/backend/tests/test_garmin_client.py +++ b/backend/tests/test_garmin_client.py @@ -71,7 +71,9 @@ def test_login_mfa_complete_no_client_in_state(mock_sso, mock_garmin): assert client.login(mfa_code="123456") == "SUCCESS" mock_garth.client.configure.assert_called_once() -def test_login_mfa_required_no_creds(mock_garmin): +def test_login_mfa_required_no_creds(mock_garmin, monkeypatch): + monkeypatch.setenv("GARMIN_EMAIL", "") + monkeypatch.setenv("GARMIN_PASSWORD", "") client = GarminClient(email="", password="") GarminClient._temp_client_state = {"some": "state"} with patch("os.path.exists", return_value=False): @@ -135,7 +137,9 @@ def test_login_json_error_cleanup(mock_garmin): assert client.login() == "FAILURE" assert mock_remove.called -def test_login_missing_creds(mock_garmin): +def test_login_missing_creds(mock_garmin, monkeypatch): + monkeypatch.setenv("GARMIN_EMAIL", "") + monkeypatch.setenv("GARMIN_PASSWORD", "") client = GarminClient(email="", password="") with patch("os.path.exists", return_value=False): assert client.login() == "FAILURE" diff --git a/frontend/src/App.vue b/frontend/src/App.vue index 5df245f..666ed26 100644 --- a/frontend/src/App.vue +++ b/frontend/src/App.vue @@ -814,4 +814,55 @@ button:disabled { justify-content: space-between; align-items: center; } + +.modal-body { + display: flex; + flex: 1; + overflow: hidden; +} + +.modal-sidebar { + width: 200px; + background: rgba(0, 0, 0, 0.2); + border-right: 1px solid var(--border-color); + padding: 1rem; + display: flex; + flex-direction: column; + gap: 0.5rem; +} + +.sidebar-item { + padding: 0.75rem 1rem; + border-radius: 6px; + cursor: pointer; + color: var(--text-muted); + transition: all 0.2s; +} + +.sidebar-item:hover { + background: rgba(255, 255, 255, 0.05); + color: var(--text-color); +} + +.sidebar-item.active { + background: var(--accent-color); + color: white; +} + +.modal-main { + flex: 1; + padding: 2rem; + overflow-y: auto; +} + +/* Fix for Menu Visibility Issues */ +.main-nav button { + white-space: nowrap; /* Prevent text wrapping */ + opacity: 0.7; /* Better than muted color for text visibility */ +} + +.main-nav button:hover, +.main-nav button.active { + opacity: 1; +}