From 0acde6d199e8f6847a40b94d4703eaf50d0549bb Mon Sep 17 00:00:00 2001 From: pyr0ball Date: Sun, 22 Mar 2026 15:55:38 -0700 Subject: [PATCH] feat(profile): add ui_preference field (streamlit|vue, default: streamlit) --- config/user.yaml.example | 1 + scripts/user_profile.py | 31 +++++++++++++++++++++++++++++++ tests/test_user_profile.py | 31 +++++++++++++++++++++++++++++++ 3 files changed, 63 insertions(+) diff --git a/config/user.yaml.example b/config/user.yaml.example index b17c083..a2dbe94 100644 --- a/config/user.yaml.example +++ b/config/user.yaml.example @@ -43,6 +43,7 @@ dev_tier_override: null # overrides tier locally (for testing only) wizard_complete: false wizard_step: 0 dismissed_banners: [] +ui_preference: streamlit # UI preference — "streamlit" (default) or "vue" (Beta: Paid tier) docs_dir: "~/Documents/JobSearch" ollama_models_dir: "~/models/ollama" diff --git a/scripts/user_profile.py b/scripts/user_profile.py index fa2678f..25109de 100644 --- a/scripts/user_profile.py +++ b/scripts/user_profile.py @@ -29,6 +29,7 @@ _DEFAULTS = { "wizard_complete": False, "wizard_step": 0, "dismissed_banners": [], + "ui_preference": "streamlit", "services": { "streamlit_port": 8501, "ollama_host": "localhost", @@ -76,7 +77,37 @@ class UserProfile: self.wizard_complete: bool = bool(data.get("wizard_complete", False)) self.wizard_step: int = int(data.get("wizard_step", 0)) self.dismissed_banners: list[str] = list(data.get("dismissed_banners", [])) + raw_pref = data.get("ui_preference", "streamlit") + self.ui_preference: str = raw_pref if raw_pref in ("streamlit", "vue") else "streamlit" self._svc = data["services"] + self._path = path + + def save(self) -> None: + """Save all profile fields back to user.yaml.""" + output = { + "name": self.name, + "email": self.email, + "phone": self.phone, + "linkedin": self.linkedin, + "career_summary": self.career_summary, + "candidate_voice": self.candidate_voice, + "nda_companies": self.nda_companies, + "docs_dir": str(self.docs_dir), + "ollama_models_dir": str(self.ollama_models_dir), + "vllm_models_dir": str(self.vllm_models_dir), + "inference_profile": self.inference_profile, + "mission_preferences": self.mission_preferences, + "candidate_accessibility_focus": self.candidate_accessibility_focus, + "candidate_lgbtq_focus": self.candidate_lgbtq_focus, + "tier": self.tier, + "dev_tier_override": self.dev_tier_override, + "wizard_complete": self.wizard_complete, + "wizard_step": self.wizard_step, + "dismissed_banners": self.dismissed_banners, + "ui_preference": self.ui_preference, + "services": self._svc, + } + self._path.write_text(yaml.dump(output, default_flow_style=False)) # ── Service URLs ────────────────────────────────────────────────────────── def _url(self, host: str, port: int, ssl: bool) -> str: diff --git a/tests/test_user_profile.py b/tests/test_user_profile.py index 88c4c88..84c1d72 100644 --- a/tests/test_user_profile.py +++ b/tests/test_user_profile.py @@ -106,3 +106,34 @@ def test_effective_tier_no_override(tmp_path): p.write_text("name: T\nemail: t@t.com\ncareer_summary: x\ntier: paid\n") u = UserProfile(p) assert u.effective_tier == "paid" + +def test_ui_preference_default(tmp_path): + """Fresh profile defaults to streamlit.""" + p = tmp_path / "user.yaml" + p.write_text("name: Test User\n") + profile = UserProfile(p) + assert profile.ui_preference == "streamlit" + +def test_ui_preference_vue(tmp_path): + """Saved vue preference loads correctly.""" + p = tmp_path / "user.yaml" + p.write_text("name: Test\nui_preference: vue\n") + profile = UserProfile(p) + assert profile.ui_preference == "vue" + +def test_ui_preference_roundtrip(tmp_path): + """Saving ui_preference: vue persists and reloads.""" + p = tmp_path / "user.yaml" + p.write_text("name: Test\n") + profile = UserProfile(p) + profile.ui_preference = "vue" + profile.save() + reloaded = UserProfile(p) + assert reloaded.ui_preference == "vue" + +def test_ui_preference_invalid_falls_back(tmp_path): + """Unknown value falls back to streamlit.""" + p = tmp_path / "user.yaml" + p.write_text("name: Test\nui_preference: newui\n") + profile = UserProfile(p) + assert profile.ui_preference == "streamlit"