feat: License tab in Settings (activate/deactivate UI) + startup refresh
This commit is contained in:
parent
5739d1935b
commit
8ff134addd
2 changed files with 56 additions and 2 deletions
|
|
@ -61,6 +61,13 @@ def _startup() -> None:
|
||||||
|
|
||||||
_startup()
|
_startup()
|
||||||
|
|
||||||
|
# Silent license refresh on startup — no-op if unreachable
|
||||||
|
try:
|
||||||
|
from scripts.license import refresh_if_needed as _refresh_license
|
||||||
|
_refresh_license()
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
|
||||||
# ── First-run wizard gate ───────────────────────────────────────────────────────
|
# ── First-run wizard gate ───────────────────────────────────────────────────────
|
||||||
from scripts.user_profile import UserProfile as _UserProfile
|
from scripts.user_profile import UserProfile as _UserProfile
|
||||||
_USER_YAML = Path(__file__).parent.parent / "config" / "user.yaml"
|
_USER_YAML = Path(__file__).parent.parent / "config" / "user.yaml"
|
||||||
|
|
|
||||||
|
|
@ -89,12 +89,12 @@ _show_dev_tab = _dev_mode or bool(_u_for_dev.get("dev_tier_override"))
|
||||||
_tab_names = [
|
_tab_names = [
|
||||||
"👤 My Profile", "🔎 Search", "🤖 LLM Backends", "📚 Notion",
|
"👤 My Profile", "🔎 Search", "🤖 LLM Backends", "📚 Notion",
|
||||||
"🔌 Services", "📝 Resume Profile", "📧 Email", "🏷️ Skills",
|
"🔌 Services", "📝 Resume Profile", "📧 Email", "🏷️ Skills",
|
||||||
"🔗 Integrations", "🎯 Fine-Tune"
|
"🔗 Integrations", "🎯 Fine-Tune", "🔑 License"
|
||||||
]
|
]
|
||||||
if _show_dev_tab:
|
if _show_dev_tab:
|
||||||
_tab_names.append("🛠️ Developer")
|
_tab_names.append("🛠️ Developer")
|
||||||
_all_tabs = st.tabs(_tab_names)
|
_all_tabs = st.tabs(_tab_names)
|
||||||
tab_profile, tab_search, tab_llm, tab_notion, tab_services, tab_resume, tab_email, tab_skills, tab_integrations, tab_finetune = _all_tabs[:10]
|
tab_profile, tab_search, tab_llm, tab_notion, tab_services, tab_resume, tab_email, tab_skills, tab_integrations, tab_finetune, tab_license = _all_tabs[:11]
|
||||||
|
|
||||||
with tab_profile:
|
with tab_profile:
|
||||||
from scripts.user_profile import UserProfile as _UP, _DEFAULTS as _UP_DEFAULTS
|
from scripts.user_profile import UserProfile as _UP, _DEFAULTS as _UP_DEFAULTS
|
||||||
|
|
@ -1129,6 +1129,53 @@ with tab_finetune:
|
||||||
if col_refresh.button("🔄 Check model status", key="ft_refresh3"):
|
if col_refresh.button("🔄 Check model status", key="ft_refresh3"):
|
||||||
st.rerun()
|
st.rerun()
|
||||||
|
|
||||||
|
# ── License tab ───────────────────────────────────────────────────────────────
|
||||||
|
with tab_license:
|
||||||
|
st.subheader("🔑 License")
|
||||||
|
|
||||||
|
from scripts.license import (
|
||||||
|
verify_local as _verify_local,
|
||||||
|
activate as _activate,
|
||||||
|
deactivate as _deactivate,
|
||||||
|
_DEFAULT_LICENSE_PATH,
|
||||||
|
_DEFAULT_PUBLIC_KEY_PATH,
|
||||||
|
)
|
||||||
|
|
||||||
|
_lic = _verify_local()
|
||||||
|
|
||||||
|
if _lic:
|
||||||
|
_grace_note = " _(grace period active)_" if _lic.get("in_grace") else ""
|
||||||
|
st.success(f"**{_lic['tier'].title()} tier** active{_grace_note}")
|
||||||
|
try:
|
||||||
|
import json as _json
|
||||||
|
_key_display = _json.loads(_DEFAULT_LICENSE_PATH.read_text()).get("key_display", "—")
|
||||||
|
except Exception:
|
||||||
|
_key_display = "—"
|
||||||
|
st.caption(f"Key: `{_key_display}`")
|
||||||
|
if _lic.get("notice"):
|
||||||
|
st.info(_lic["notice"])
|
||||||
|
if st.button("Deactivate this machine", type="secondary", key="lic_deactivate"):
|
||||||
|
_deactivate()
|
||||||
|
st.success("Deactivated. Restart the app to apply.")
|
||||||
|
st.rerun()
|
||||||
|
else:
|
||||||
|
st.info("No active license — running on **free tier**.")
|
||||||
|
st.caption("Enter a license key to unlock paid features.")
|
||||||
|
_key_input = st.text_input(
|
||||||
|
"License key",
|
||||||
|
placeholder="CFG-PRNG-XXXX-XXXX-XXXX",
|
||||||
|
label_visibility="collapsed",
|
||||||
|
key="lic_key_input",
|
||||||
|
)
|
||||||
|
if st.button("Activate", disabled=not (_key_input or "").strip(), key="lic_activate"):
|
||||||
|
with st.spinner("Activating…"):
|
||||||
|
try:
|
||||||
|
result = _activate(_key_input.strip())
|
||||||
|
st.success(f"Activated! Tier: **{result['tier']}**")
|
||||||
|
st.rerun()
|
||||||
|
except Exception as _e:
|
||||||
|
st.error(f"Activation failed: {_e}")
|
||||||
|
|
||||||
# ── Developer tab ─────────────────────────────────────────────────────────────
|
# ── Developer tab ─────────────────────────────────────────────────────────────
|
||||||
if _show_dev_tab:
|
if _show_dev_tab:
|
||||||
with _all_tabs[-1]:
|
with _all_tabs[-1]:
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue