feat(header): badge mediu RAR compact langa chip-ul RAR
Muta indicatorul de mediu (Testare/PRODUCTIE) din statusbar (randare periodica, rand intreg) intr-un badge compact din header, langa chipul RAR scurtat la "RAR". Click pe badge comuta mediul cand exista 2 disponibile; pe mobil (<=560px) eticheta scurta PROD/TEST ramane mereu vizibila (semnal de risc L.142). Toggle-ul din header si schimbarea mediului implicit din Setari actualizeaza badge-ul via OOB swap. Co-Authored-By: Claude Agent <noreply@anthropic.com>
This commit is contained in:
@@ -400,6 +400,9 @@ def _get_acasa_context(request: Request, conn, account_id: int) -> dict:
|
|||||||
"csrf_token": get_csrf_token(request),
|
"csrf_token": get_csrf_token(request),
|
||||||
# Banner ne-blocant: contul nu are identitate completa (companie+email+CUI)
|
# Banner ne-blocant: contul nu are identitate completa (companie+email+CUI)
|
||||||
"cont_incomplet": cont_incomplet,
|
"cont_incomplet": cont_incomplet,
|
||||||
|
# Mediul RAR pentru caseta de upload (_upload.html): fara el, template-ul
|
||||||
|
# ar vedea medii=[] si ar afisa fals "Niciun mediu RAR activ".
|
||||||
|
**_import_env_ctx(conn, acct),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -420,12 +423,15 @@ def _render_panel_acasa(request: Request, conn=None, account_id: int = 1, status
|
|||||||
return templates.get_template("_acasa.html").render(ctx)
|
return templates.get_template("_acasa.html").render(ctx)
|
||||||
|
|
||||||
|
|
||||||
def _render_panel_import(request: Request) -> str:
|
def _render_panel_import(request: Request, conn=None, account_id: int = 1) -> str:
|
||||||
"""Randeaza panoul Import ca string HTML (include _upload.html)."""
|
"""Randeaza panoul Import ca string HTML (include _upload.html)."""
|
||||||
return templates.get_template("_upload.html").render({
|
ctx = {
|
||||||
"request": request,
|
"request": request,
|
||||||
"csrf_token": get_csrf_token(request),
|
"csrf_token": get_csrf_token(request),
|
||||||
})
|
}
|
||||||
|
if conn is not None:
|
||||||
|
ctx.update(_import_env_ctx(conn, account_id))
|
||||||
|
return templates.get_template("_upload.html").render(ctx)
|
||||||
|
|
||||||
|
|
||||||
def _render_panel_coada(request: Request, conn=None, account_id: int = 1) -> str:
|
def _render_panel_coada(request: Request, conn=None, account_id: int = 1) -> str:
|
||||||
@@ -448,12 +454,18 @@ def _render_panel_mapari(request: Request, conn, account_id: int) -> str:
|
|||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
def _render_panel_cont(request: Request, conn, account_id: int) -> str:
|
def _render_panel_cont(request: Request, conn, account_id: int, activ_subtab: str = "cont") -> str:
|
||||||
"""Randeaza panoul Cont ca string HTML."""
|
"""Randeaza panoul Cont ca string HTML.
|
||||||
|
|
||||||
|
`activ_subtab` permite deep-link pe un sub-tab din Setari (?tab=cont&subtab=rar):
|
||||||
|
'cont' | 'rar' | 'api'; valoare invalida -> 'cont'.
|
||||||
|
"""
|
||||||
from ..mapping import account_or_default
|
from ..mapping import account_or_default
|
||||||
acct = account_or_default(account_id)
|
acct = account_or_default(account_id)
|
||||||
account_meta = _fetch_account_meta(conn, acct)
|
account_meta = _fetch_account_meta(conn, acct)
|
||||||
env_ctx = _fetch_cont_env_state(conn, acct)
|
env_ctx = _fetch_cont_env_state(conn, acct)
|
||||||
|
if activ_subtab not in ("cont", "rar", "api"):
|
||||||
|
activ_subtab = "cont"
|
||||||
cont_ctx = {
|
cont_ctx = {
|
||||||
"request": request,
|
"request": request,
|
||||||
"csrf_token": get_csrf_token(request),
|
"csrf_token": get_csrf_token(request),
|
||||||
@@ -464,7 +476,7 @@ def _render_panel_cont(request: Request, conn, account_id: int) -> str:
|
|||||||
"account_meta": account_meta,
|
"account_meta": account_meta,
|
||||||
"date_firma_mesaj": None,
|
"date_firma_mesaj": None,
|
||||||
"date_firma_eroare": None,
|
"date_firma_eroare": None,
|
||||||
"activ_subtab": "cont",
|
"activ_subtab": activ_subtab,
|
||||||
"parola_mesaj": None,
|
"parola_mesaj": None,
|
||||||
"parola_eroare": None,
|
"parola_eroare": None,
|
||||||
"creds_test_mesaj": None,
|
"creds_test_mesaj": None,
|
||||||
@@ -604,20 +616,20 @@ def _render_panel_jurnal(request: Request, conn, account_id: int) -> str:
|
|||||||
return templates.get_template("_jurnal.html").render(_jurnal_context(request, conn, account_id))
|
return templates.get_template("_jurnal.html").render(_jurnal_context(request, conn, account_id))
|
||||||
|
|
||||||
|
|
||||||
def _render_panel_for_tab(request: Request, conn, account_id: int, tab: str, status: str | None = None) -> str:
|
def _render_panel_for_tab(request: Request, conn, account_id: int, tab: str, status: str | None = None, subtab: str | None = None) -> str:
|
||||||
"""Randeaza panoul corespunzator unui tab ca string HTML."""
|
"""Randeaza panoul corespunzator unui tab ca string HTML."""
|
||||||
if tab == "acasa":
|
if tab == "acasa":
|
||||||
return _render_panel_acasa(request, conn, account_id, status=status)
|
return _render_panel_acasa(request, conn, account_id, status=status)
|
||||||
if tab == "jurnal":
|
if tab == "jurnal":
|
||||||
return _render_panel_jurnal(request, conn, account_id)
|
return _render_panel_jurnal(request, conn, account_id)
|
||||||
if tab == "import":
|
if tab == "import":
|
||||||
return _render_panel_import(request)
|
return _render_panel_import(request, conn, account_id)
|
||||||
if tab == "coada":
|
if tab == "coada":
|
||||||
return _render_panel_coada(request, conn, account_id)
|
return _render_panel_coada(request, conn, account_id)
|
||||||
if tab == "mapari":
|
if tab == "mapari":
|
||||||
return _render_panel_mapari(request, conn, account_id)
|
return _render_panel_mapari(request, conn, account_id)
|
||||||
if tab == "cont":
|
if tab == "cont":
|
||||||
return _render_panel_cont(request, conn, account_id)
|
return _render_panel_cont(request, conn, account_id, activ_subtab=subtab or "cont")
|
||||||
if tab == "nomenclator":
|
if tab == "nomenclator":
|
||||||
return _render_panel_nomenclator(request, conn)
|
return _render_panel_nomenclator(request, conn)
|
||||||
if tab == "integrare":
|
if tab == "integrare":
|
||||||
@@ -722,7 +734,7 @@ def _plan_ctx(conn, account_id: int, now: datetime | None = None) -> dict:
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
def _layout_header_ctx(conn, account_id: int) -> dict:
|
def _layout_header_ctx(request: Request, conn, account_id: int) -> dict:
|
||||||
"""Context suplimentar pentru antetul branduit.
|
"""Context suplimentar pentru antetul branduit.
|
||||||
|
|
||||||
Citeste account_name, tier si starea de sanatate RAR pentru a popula:
|
Citeste account_name, tier si starea de sanatate RAR pentru a popula:
|
||||||
@@ -730,6 +742,7 @@ def _layout_header_ctx(conn, account_id: int) -> dict:
|
|||||||
- tier_label: eticheta planului (Gratuit/Standard/Pro/Premium)
|
- tier_label: eticheta planului (Gratuit/Standard/Pro/Premium)
|
||||||
- sanatate_ok: True daca worker viu si RAR ok (dot verde in antet)
|
- sanatate_ok: True daca worker viu si RAR ok (dot verde in antet)
|
||||||
- last_login: data/ora ultimei autentificari RAR (format romanesc)
|
- last_login: data/ora ultimei autentificari RAR (format romanesc)
|
||||||
|
- medii_disponibile + env_default: badge-ul de mediu RAR din header
|
||||||
- plan_linie + plan_warn + ...: context plan pentru burger
|
- plan_linie + plan_warn + ...: context plan pentru burger
|
||||||
"""
|
"""
|
||||||
row = conn.execute(
|
row = conn.execute(
|
||||||
@@ -753,6 +766,10 @@ def _layout_header_ctx(conn, account_id: int) -> dict:
|
|||||||
# Starea comutatorului "Trimite automat la RAR" pentru toggle-ul din clusterul
|
# Starea comutatorului "Trimite automat la RAR" pentru toggle-ul din clusterul
|
||||||
# de header — randat in afara swap-ului periodic al barei de status.
|
# de header — randat in afara swap-ului periodic al barei de status.
|
||||||
"auto_send_enabled": get_auto_send(conn, account_id),
|
"auto_send_enabled": get_auto_send(conn, account_id),
|
||||||
|
# Badge mediu RAR compact din header (langa chip-ul RAR).
|
||||||
|
"medii_disponibile": medii_disponibile_cont(conn, account_id),
|
||||||
|
"env_default": rar_env_efectiv_cont(conn, account_id) or "prod",
|
||||||
|
"csrf_token": get_csrf_token(request),
|
||||||
}
|
}
|
||||||
# Context plan pentru linia detaliata din meniul burger.
|
# Context plan pentru linia detaliata din meniul burger.
|
||||||
ctx.update(_plan_ctx(conn, account_id))
|
ctx.update(_plan_ctx(conn, account_id))
|
||||||
@@ -760,7 +777,7 @@ def _layout_header_ctx(conn, account_id: int) -> dict:
|
|||||||
|
|
||||||
|
|
||||||
@router.get("/", response_class=HTMLResponse)
|
@router.get("/", response_class=HTMLResponse)
|
||||||
def dashboard(request: Request, tab: str = "acasa", status: str | None = None) -> HTMLResponse:
|
def dashboard(request: Request, tab: str = "acasa", status: str | None = None, subtab: str | None = None) -> HTMLResponse:
|
||||||
"""Dashboard principal cu tab-uri.
|
"""Dashboard principal cu tab-uri.
|
||||||
|
|
||||||
Parametrul ?tab= permite deep-link pe orice sectiune; panoul activ e randat
|
Parametrul ?tab= permite deep-link pe orice sectiune; panoul activ e randat
|
||||||
@@ -788,7 +805,7 @@ def dashboard(request: Request, tab: str = "acasa", status: str | None = None) -
|
|||||||
active_tab = tab if tab in _TABS_VALIDE else "acasa"
|
active_tab = tab if tab in _TABS_VALIDE else "acasa"
|
||||||
conn = get_connection()
|
conn = get_connection()
|
||||||
try:
|
try:
|
||||||
panel_html = _render_panel_for_tab(request, conn, account_id, active_tab, status=status)
|
panel_html = _render_panel_for_tab(request, conn, account_id, active_tab, status=status, subtab=subtab)
|
||||||
# Badge contoare pe tab-uri: needs_mapping -> Mapari. Blocatele se reflecta in
|
# Badge contoare pe tab-uri: needs_mapping -> Mapari. Blocatele se reflecta in
|
||||||
# heading-ul sectiunii Trimiteri.
|
# heading-ul sectiunii Trimiteri.
|
||||||
counts = _status_counts(conn, account_id)
|
counts = _status_counts(conn, account_id)
|
||||||
@@ -807,7 +824,7 @@ def dashboard(request: Request, tab: str = "acasa", status: str | None = None) -
|
|||||||
"csrf_token": get_csrf_token(request),
|
"csrf_token": get_csrf_token(request),
|
||||||
}
|
}
|
||||||
# Context antet (account_name, tier, sanatate RAR).
|
# Context antet (account_name, tier, sanatate RAR).
|
||||||
ctx.update(_layout_header_ctx(conn, account_id))
|
ctx.update(_layout_header_ctx(request, conn, account_id))
|
||||||
return templates.TemplateResponse("dashboard.html", ctx)
|
return templates.TemplateResponse("dashboard.html", ctx)
|
||||||
finally:
|
finally:
|
||||||
conn.close()
|
conn.close()
|
||||||
@@ -984,10 +1001,6 @@ def _build_status_ctx(request: Request, conn, account_id: int, *, oob: bool = Fa
|
|||||||
else:
|
else:
|
||||||
sanatate_text = "Declaratiile curg normal"
|
sanatate_text = "Declaratiile curg normal"
|
||||||
|
|
||||||
# Mediul RAR activ per cont pentru indicatorul din statusbar.
|
|
||||||
medii_disp = medii_disponibile_cont(conn, account_id)
|
|
||||||
env_default = rar_env_efectiv_cont(conn, account_id) or "prod"
|
|
||||||
|
|
||||||
# Contor "In asteptare (manual)" + banner coada tinuta imbatranita.
|
# Contor "In asteptare (manual)" + banner coada tinuta imbatranita.
|
||||||
held_manual_count, held_aged_count = _held_counts(conn, account_id)
|
held_manual_count, held_aged_count = _held_counts(conn, account_id)
|
||||||
|
|
||||||
@@ -1012,9 +1025,6 @@ def _build_status_ctx(request: Request, conn, account_id: int, *, oob: bool = Fa
|
|||||||
"tab_activ": tab_activ,
|
"tab_activ": tab_activ,
|
||||||
"mapari_badge": counts.get("needs_mapping", 0),
|
"mapari_badge": counts.get("needs_mapping", 0),
|
||||||
"oob": oob,
|
"oob": oob,
|
||||||
# Indicator mediu RAR + toggle conditionat
|
|
||||||
"env_default": env_default,
|
|
||||||
"medii_disponibile": medii_disp,
|
|
||||||
"auto_send_enabled": get_auto_send(conn, account_id),
|
"auto_send_enabled": get_auto_send(conn, account_id),
|
||||||
"held_manual_count": held_manual_count,
|
"held_manual_count": held_manual_count,
|
||||||
"held_aged_count": held_aged_count,
|
"held_aged_count": held_aged_count,
|
||||||
@@ -2828,15 +2838,18 @@ def post_preview_regula_text(
|
|||||||
pattern: str = Form(""),
|
pattern: str = Form(""),
|
||||||
csrf_token: str | None = Form(None),
|
csrf_token: str | None = Form(None),
|
||||||
) -> HTMLResponse:
|
) -> HTMLResponse:
|
||||||
"""Preview pre-salvare: cate operatii nemapate ar potrivi regula.
|
"""Preview pre-salvare: cate operatii nemapate ar potrivi regula + cod propus.
|
||||||
|
|
||||||
NU salveaza nimic (zero scriere DB). Normalizeaza pattern-ul cu
|
NU salveaza nimic (zero scriere DB). Normalizeaza pattern-ul cu
|
||||||
normalize_for_match, numara operatiile DISTINCTE nemapate ale contului
|
normalize_for_match, numara operatiile DISTINCTE nemapate ale contului
|
||||||
(needs_mapping, reuse pending_unmapped) al caror text (denumire sau
|
(needs_mapping, reuse pending_unmapped) al caror text (denumire sau
|
||||||
cod_op_service, normalizat) CONTINE pattern-ul + intoarce pana la 3 exemple.
|
cod_op_service, normalizat) CONTINE pattern-ul + intoarce pana la 3 exemple.
|
||||||
|
Adauga propunerea automata de cod (GOLD partajat > SILVER > embeddings, via
|
||||||
|
enrich_suggestions) cu buton care preselecteaza codul in dropdown — fara salvare.
|
||||||
Pattern gol -> fragment gol (nu numara „tot"). Scoped pe contul sesiunii.
|
Pattern gol -> fragment gol (nu numara „tot"). Scoped pe contul sesiunii.
|
||||||
"""
|
"""
|
||||||
from markupsafe import escape
|
from markupsafe import escape
|
||||||
|
from ..mapping import enrich_suggestions, load_nomenclator
|
||||||
|
|
||||||
account_id = require_login(request)
|
account_id = require_login(request)
|
||||||
verify_csrf(request, csrf_token)
|
verify_csrf(request, csrf_token)
|
||||||
@@ -2846,9 +2859,32 @@ def post_preview_regula_text(
|
|||||||
conn = get_connection()
|
conn = get_connection()
|
||||||
try:
|
try:
|
||||||
pending = pending_unmapped(conn, account_id)
|
pending = pending_unmapped(conn, account_id)
|
||||||
|
# Propunere de cod pentru textul regulii (suggestion-only; embeddings sar
|
||||||
|
# peste model daca warmup-ul nu a terminat — degradare gratioasa).
|
||||||
|
enriched = enrich_suggestions(conn, (pattern or "").strip())
|
||||||
|
nume_coduri = {n["cod_prestatie"]: n["nume_prestatie"] for n in load_nomenclator(conn)}
|
||||||
finally:
|
finally:
|
||||||
conn.close()
|
conn.close()
|
||||||
|
|
||||||
|
_SURSE_UMANE = {"gold_partajat": "mapari validate", "silver": "etichetare LLM", "embedding": "similaritate"}
|
||||||
|
sugestie_html = ""
|
||||||
|
sp = enriched.get("sugestie_principala")
|
||||||
|
if sp and sp.get("cod_prestatie"):
|
||||||
|
cod = str(sp["cod_prestatie"])
|
||||||
|
nume = nume_coduri.get(cod, "")
|
||||||
|
sursa = _SURSE_UMANE.get(sp.get("sursa") or "", "")
|
||||||
|
cod_js = str(escape(cod)).replace("'", "")
|
||||||
|
sugestie_html = (
|
||||||
|
f'<div style="font-size:12px; margin-bottom:4px;">'
|
||||||
|
f'Propunere: <strong>{escape(cod)}</strong>'
|
||||||
|
f'{" — " + str(escape(nume)) if nume else ""}'
|
||||||
|
f'{f" <span class=muted>({sursa})</span>" if sursa else ""}'
|
||||||
|
f' <button type="button" style="padding:1px 10px; font-size:11px; border-radius:99px;"'
|
||||||
|
f' onclick="var s=document.querySelector(\'select[name=cod_prestatie][form=rt-add]\');'
|
||||||
|
f'if(s){{s.value=\'{cod_js}\';s.dispatchEvent(new Event(\'change\',{{bubbles:true}}));}}">'
|
||||||
|
f'Foloseste</button></div>'
|
||||||
|
)
|
||||||
|
|
||||||
matches = []
|
matches = []
|
||||||
for entry in pending:
|
for entry in pending:
|
||||||
text = normalize_for_match(entry.get("denumire") or entry.get("cod_op_service"))
|
text = normalize_for_match(entry.get("denumire") or entry.get("cod_op_service"))
|
||||||
@@ -2857,7 +2893,8 @@ def post_preview_regula_text(
|
|||||||
|
|
||||||
if not matches:
|
if not matches:
|
||||||
return HTMLResponse(
|
return HTMLResponse(
|
||||||
content='<span class="muted" style="font-size:12px;">Nicio potrivire acum.</span>'
|
content=sugestie_html
|
||||||
|
+ '<span class="muted" style="font-size:12px;">Nicio potrivire acum.</span>'
|
||||||
)
|
)
|
||||||
|
|
||||||
exemple = ", ".join(
|
exemple = ", ".join(
|
||||||
@@ -2868,7 +2905,8 @@ def post_preview_regula_text(
|
|||||||
plural = "operatie nemapata" if n == 1 else "operatii nemapate"
|
plural = "operatie nemapata" if n == 1 else "operatii nemapate"
|
||||||
return HTMLResponse(
|
return HTMLResponse(
|
||||||
content=(
|
content=(
|
||||||
f'<span class="muted" style="font-size:12px;">'
|
sugestie_html
|
||||||
|
+ f'<span class="muted" style="font-size:12px;">'
|
||||||
f'Potriveste {n} {plural}: {exemple}.</span>'
|
f'Potriveste {n} {plural}: {exemple}.</span>'
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
@@ -3941,7 +3979,7 @@ async def web_confirma_toate_review(
|
|||||||
)
|
)
|
||||||
result = _web_compute_preview(conn, import_id, account_id)
|
result = _web_compute_preview(conn, import_id, account_id)
|
||||||
if isinstance(result, str):
|
if isinstance(result, str):
|
||||||
return templates.TemplateResponse("_upload.html", _ctx(request, error=result))
|
return templates.TemplateResponse("_upload.html", _ctx(request, error=result, **_import_env_ctx(conn, account_id)))
|
||||||
return templates.TemplateResponse("_preview_import.html", _ctx(
|
return templates.TemplateResponse("_preview_import.html", _ctx(
|
||||||
request, import_id=import_id, message=message, **result
|
request, import_id=import_id, message=message, **result
|
||||||
))
|
))
|
||||||
@@ -3972,7 +4010,7 @@ async def web_mapare_operatie(
|
|||||||
def _render(message: str | None = None, error: bool = False) -> HTMLResponse:
|
def _render(message: str | None = None, error: bool = False) -> HTMLResponse:
|
||||||
result = _web_compute_preview(conn, import_id, account_id)
|
result = _web_compute_preview(conn, import_id, account_id)
|
||||||
if isinstance(result, str):
|
if isinstance(result, str):
|
||||||
return templates.TemplateResponse("_upload.html", _ctx(request, error=result))
|
return templates.TemplateResponse("_upload.html", _ctx(request, error=result, **_import_env_ctx(conn, account_id)))
|
||||||
return templates.TemplateResponse("_preview_import.html", _ctx(
|
return templates.TemplateResponse("_preview_import.html", _ctx(
|
||||||
request, import_id=import_id, message=message, error=error, **result
|
request, import_id=import_id, message=message, error=error, **result
|
||||||
))
|
))
|
||||||
@@ -4060,7 +4098,7 @@ async def web_mapare_operatii(
|
|||||||
|
|
||||||
result = _web_compute_preview(conn, import_id, account_id)
|
result = _web_compute_preview(conn, import_id, account_id)
|
||||||
if isinstance(result, str):
|
if isinstance(result, str):
|
||||||
return templates.TemplateResponse("_upload.html", _ctx(request, error=result))
|
return templates.TemplateResponse("_upload.html", _ctx(request, error=result, **_import_env_ctx(conn, account_id)))
|
||||||
return templates.TemplateResponse("_preview_import.html", _ctx(
|
return templates.TemplateResponse("_preview_import.html", _ctx(
|
||||||
request, import_id=import_id, message=message, error=error, **result
|
request, import_id=import_id, message=message, error=error, **result
|
||||||
))
|
))
|
||||||
@@ -4154,7 +4192,7 @@ async def web_confirma_import(
|
|||||||
# Re-arata preview cu eroare
|
# Re-arata preview cu eroare
|
||||||
result = _web_compute_preview(conn, import_id, account_id)
|
result = _web_compute_preview(conn, import_id, account_id)
|
||||||
if isinstance(result, str):
|
if isinstance(result, str):
|
||||||
return templates.TemplateResponse("_upload.html", _ctx(request, error=result))
|
return templates.TemplateResponse("_upload.html", _ctx(request, error=result, **_import_env_ctx(conn, account_id)))
|
||||||
return templates.TemplateResponse("_preview_import.html", _ctx(
|
return templates.TemplateResponse("_preview_import.html", _ctx(
|
||||||
request,
|
request,
|
||||||
import_id=import_id,
|
import_id=import_id,
|
||||||
@@ -4215,7 +4253,7 @@ async def web_confirma_import(
|
|||||||
)
|
)
|
||||||
_prev_result = _web_compute_preview(conn, import_id, account_id)
|
_prev_result = _web_compute_preview(conn, import_id, account_id)
|
||||||
if isinstance(_prev_result, str):
|
if isinstance(_prev_result, str):
|
||||||
return templates.TemplateResponse("_upload.html", _ctx(request, error=_err_msg))
|
return templates.TemplateResponse("_upload.html", _ctx(request, error=_err_msg, **_import_env_ctx(conn, account_id)))
|
||||||
return templates.TemplateResponse("_preview_import.html", _ctx(
|
return templates.TemplateResponse("_preview_import.html", _ctx(
|
||||||
request, import_id=import_id, message=_err_msg, error=True, **_prev_result
|
request, import_id=import_id, message=_err_msg, error=True, **_prev_result
|
||||||
))
|
))
|
||||||
@@ -4228,7 +4266,7 @@ async def web_confirma_import(
|
|||||||
f"Verifica preview-ul si retasteaza numarul corect."
|
f"Verifica preview-ul si retasteaza numarul corect."
|
||||||
)
|
)
|
||||||
if isinstance(result, str):
|
if isinstance(result, str):
|
||||||
return templates.TemplateResponse("_upload.html", _ctx(request, error=msg))
|
return templates.TemplateResponse("_upload.html", _ctx(request, error=msg, **_import_env_ctx(conn, account_id)))
|
||||||
return templates.TemplateResponse("_preview_import.html", _ctx(
|
return templates.TemplateResponse("_preview_import.html", _ctx(
|
||||||
request, import_id=import_id, message=msg, error=True, **result
|
request, import_id=import_id, message=msg, error=True, **result
|
||||||
))
|
))
|
||||||
@@ -4236,7 +4274,7 @@ async def web_confirma_import(
|
|||||||
if n_total_ok == 0:
|
if n_total_ok == 0:
|
||||||
result = _web_compute_preview(conn, import_id, account_id)
|
result = _web_compute_preview(conn, import_id, account_id)
|
||||||
if isinstance(result, str):
|
if isinstance(result, str):
|
||||||
return templates.TemplateResponse("_upload.html", _ctx(request, error=result))
|
return templates.TemplateResponse("_upload.html", _ctx(request, error=result, **_import_env_ctx(conn, account_id)))
|
||||||
return templates.TemplateResponse("_preview_import.html", _ctx(
|
return templates.TemplateResponse("_preview_import.html", _ctx(
|
||||||
request,
|
request,
|
||||||
import_id=import_id,
|
import_id=import_id,
|
||||||
@@ -5126,7 +5164,7 @@ async def cont_rar_medii(request: Request) -> HTMLResponse:
|
|||||||
|
|
||||||
account_meta = _fetch_account_meta(conn, acct)
|
account_meta = _fetch_account_meta(conn, acct)
|
||||||
env_ctx = _fetch_cont_env_state(conn, acct)
|
env_ctx = _fetch_cont_env_state(conn, acct)
|
||||||
return _render_cont(
|
resp = _render_cont(
|
||||||
request,
|
request,
|
||||||
account_meta=account_meta,
|
account_meta=account_meta,
|
||||||
creds_test_mesaj=creds_test_mesaj,
|
creds_test_mesaj=creds_test_mesaj,
|
||||||
@@ -5138,6 +5176,12 @@ async def cont_rar_medii(request: Request) -> HTMLResponse:
|
|||||||
activ_subtab="rar",
|
activ_subtab="rar",
|
||||||
**env_ctx,
|
**env_ctx,
|
||||||
)
|
)
|
||||||
|
# Anexeaza badge-ul din header (OOB) — reflecta imediat activarea/dezactivarea
|
||||||
|
# unui mediu sau schimbarea mediului implicit, fara reload.
|
||||||
|
badge_html = templates.get_template("_header_env_badge.html").render(
|
||||||
|
_header_env_badge_ctx(request, conn, account_id, oob=True)
|
||||||
|
)
|
||||||
|
return HTMLResponse(content=bytes(resp.body).decode("utf-8") + "\n" + badge_html)
|
||||||
finally:
|
finally:
|
||||||
conn.close()
|
conn.close()
|
||||||
|
|
||||||
@@ -5200,12 +5244,24 @@ async def cont_schimba_parola(request: Request) -> HTMLResponse:
|
|||||||
return _rerender(mesaj="Parola a fost schimbata.")
|
return _rerender(mesaj="Parola a fost schimbata.")
|
||||||
|
|
||||||
|
|
||||||
|
def _header_env_badge_ctx(request: Request, conn, account_id: int, *, oob: bool = False) -> dict:
|
||||||
|
"""Context pentru fragmentul badge-ului de mediu RAR din header."""
|
||||||
|
return {
|
||||||
|
"request": request,
|
||||||
|
"medii_disponibile": medii_disponibile_cont(conn, account_id),
|
||||||
|
"env_default": rar_env_efectiv_cont(conn, account_id) or "prod",
|
||||||
|
"csrf_token": get_csrf_token(request),
|
||||||
|
"oob": oob,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@router.post("/_fragments/status/toggle-env", response_class=HTMLResponse)
|
@router.post("/_fragments/status/toggle-env", response_class=HTMLResponse)
|
||||||
async def fragment_status_toggle_env(request: Request) -> HTMLResponse:
|
async def fragment_status_toggle_env(request: Request) -> HTMLResponse:
|
||||||
"""Comuta rar_env_default intre mediile disponibile ale contului.
|
"""Comuta rar_env_default intre mediile disponibile ale contului.
|
||||||
|
|
||||||
Valideaza ca noul mediu e in lista mediilor disponibile inainte de UPDATE.
|
Valideaza ca noul mediu e in lista mediilor disponibile inainte de UPDATE.
|
||||||
Intoarce statusbar-ul actualizat (acelasi format ca /_fragments/status).
|
Intoarce badge-ul din header actualizat (tinta hx-target) + status bar-ul
|
||||||
|
ca OOB swap, ca ambele sa ramana consecvente dupa comutare.
|
||||||
Ignorat silentios daca contul are un singur mediu sau zero medii disponibile.
|
Ignorat silentios daca contul are un singur mediu sau zero medii disponibile.
|
||||||
"""
|
"""
|
||||||
account_id = require_login(request)
|
account_id = require_login(request)
|
||||||
@@ -5237,7 +5293,11 @@ async def fragment_status_toggle_env(request: Request) -> HTMLResponse:
|
|||||||
)
|
)
|
||||||
conn.commit()
|
conn.commit()
|
||||||
|
|
||||||
ctx = _build_status_ctx(request, conn, account_id, tab_activ="acasa")
|
badge_html = templates.get_template("_header_env_badge.html").render(
|
||||||
return templates.TemplateResponse("_status.html", ctx)
|
_header_env_badge_ctx(request, conn, account_id)
|
||||||
|
)
|
||||||
|
status_ctx = _build_status_ctx(request, conn, account_id, oob=True, tab_activ="acasa")
|
||||||
|
status_html = templates.get_template("_status.html").render(status_ctx)
|
||||||
|
return HTMLResponse(content=badge_html + "\n" + status_html)
|
||||||
finally:
|
finally:
|
||||||
conn.close()
|
conn.close()
|
||||||
|
|||||||
29
app/web/templates/_header_env_badge.html
Normal file
29
app/web/templates/_header_env_badge.html
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
{# Badge compact "Mediu RAR" din header, langa chip-ul RAR.
|
||||||
|
0 medii: wrapper gol (id-ul ramane in DOM pentru viitoare OOB swap).
|
||||||
|
1 mediu: eticheta statica. 2 medii: buton de comutare HTMX (ciclic).
|
||||||
|
Clasele .env-badge-prod/.env-badge-test sunt cele din listele de trimiteri (consecventa). #}
|
||||||
|
{% set _medii = medii_disponibile | default([]) %}
|
||||||
|
<div id="header-env-badge"{% if oob %} hx-swap-oob="outerHTML"{% endif %}>
|
||||||
|
{% if _medii | length >= 1 %}
|
||||||
|
{% set _env = env_default | default('prod') %}
|
||||||
|
{% set _eb = eticheta_env(_env) %}
|
||||||
|
{% set _scurt = 'PROD' if _env == 'prod' else 'TEST' %}
|
||||||
|
{% if _medii | length >= 2 %}
|
||||||
|
<button type="button" class="{{ _eb[1] }}"
|
||||||
|
style="cursor:pointer;"
|
||||||
|
hx-post="/_fragments/status/toggle-env"
|
||||||
|
hx-target="#header-env-badge"
|
||||||
|
hx-swap="outerHTML"
|
||||||
|
hx-vals='{"csrf_token": {{ csrf_token | tojson }}}'
|
||||||
|
title="Comuta la {{ 'Testare' if _env == 'prod' else 'PRODUCȚIE' }}">
|
||||||
|
<span class="env-tx-full">{{ _eb[0] }}</span>
|
||||||
|
<span class="env-tx-short">{{ _scurt }}</span>
|
||||||
|
</button>
|
||||||
|
{% else %}
|
||||||
|
<span class="{{ _eb[1] }}">
|
||||||
|
<span class="env-tx-full">{{ _eb[0] }}</span>
|
||||||
|
<span class="env-tx-short">{{ _scurt }}</span>
|
||||||
|
</span>
|
||||||
|
{% endif %}
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
@@ -156,43 +156,6 @@
|
|||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{# === Indicator mediu RAR activ per cont.
|
|
||||||
La 0 medii: nu afisa (cont fara configuratie RAR).
|
|
||||||
La 1 mediu: eticheta statica (fara toggle).
|
|
||||||
La 2 medii: buton de comutare HTMX (toggle conditionat).
|
|
||||||
Culori prin eticheta_env/clase .env-badge-* (consistenta cu badge-urile din liste).
|
|
||||||
#}
|
|
||||||
{% set _medii = medii_disponibile | default([]) %}
|
|
||||||
{% set _env = env_default | default('prod') %}
|
|
||||||
{% set _eb = eticheta_env(_env) %}
|
|
||||||
{% if _medii | length >= 1 %}
|
|
||||||
<div class="env-indicator"
|
|
||||||
style="display:flex; align-items:center; gap:8px; margin-bottom:10px;
|
|
||||||
padding:6px 10px; border-radius:6px; font-size:var(--fs-sm);
|
|
||||||
background:color-mix(in srgb, {% if _env == 'prod' %}var(--err){% else %}var(--line){% endif %} 10%, var(--card));
|
|
||||||
border:1px solid color-mix(in srgb, {% if _env == 'prod' %}var(--err){% else %}var(--line){% endif %} 30%, transparent);">
|
|
||||||
<span style="font-weight:600;">Mediu RAR:</span>
|
|
||||||
<span class="{{ _eb[1] }}">{{ _eb[0] }}</span>
|
|
||||||
{% if _medii | length >= 2 %}
|
|
||||||
{# Toggle: apare DOAR cand sunt cel putin 2 medii disponibile #}
|
|
||||||
<form method="post" action="/_fragments/status/toggle-env"
|
|
||||||
hx-post="/_fragments/status/toggle-env"
|
|
||||||
hx-target="#status-bar"
|
|
||||||
hx-swap="outerHTML"
|
|
||||||
style="margin:0; padding:0; display:inline;">
|
|
||||||
<input type="hidden" name="csrf_token" value="{{ csrf_token | default('') }}">
|
|
||||||
<button type="submit"
|
|
||||||
style="padding:2px 10px; font-size:var(--fs-xs); border-radius:99px;
|
|
||||||
border:1px solid currentColor; background:transparent; cursor:pointer;
|
|
||||||
color:var(--muted); line-height:1.4;"
|
|
||||||
title="Comuta la {{ 'PRODUCȚIE' if _env == 'test' else 'Testare' }}">
|
|
||||||
Comuta
|
|
||||||
</button>
|
|
||||||
</form>
|
|
||||||
{% endif %}
|
|
||||||
</div>
|
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
{# === Navigatie rapida: Trimiteri + Mapari cu badge needs_mapping ===
|
{# === Navigatie rapida: Trimiteri + Mapari cu badge needs_mapping ===
|
||||||
Pastrata exact ca inainte: tab_activ determina marcajul activ.
|
Pastrata exact ca inainte: tab_activ determina marcajul activ.
|
||||||
#}
|
#}
|
||||||
|
|||||||
@@ -150,6 +150,15 @@
|
|||||||
background:color-mix(in srgb, var(--err) 80%, var(--card)); color:#fff; border:1px solid transparent; }
|
background:color-mix(in srgb, var(--err) 80%, var(--card)); color:#fff; border:1px solid transparent; }
|
||||||
.env-badge-test { display:inline-block; padding:1px 7px; border-radius:99px; font-size:11px;
|
.env-badge-test { display:inline-block; padding:1px 7px; border-radius:99px; font-size:11px;
|
||||||
background:transparent; color:var(--muted); border:1px solid var(--line); }
|
background:transparent; color:var(--muted); border:1px solid var(--line); }
|
||||||
|
/* Badge mediu RAR din header: eticheta scurta PROD/TEST ramane mereu vizibila pe
|
||||||
|
mobil (semnal de risc L.142), eticheta lunga se ascunde sub 560px. Clasele
|
||||||
|
.env-badge-prod/.env-badge-test isi redefinesc deja border-ul complet, deci
|
||||||
|
suprascriu stilul global de buton fara reguli suplimentare. */
|
||||||
|
.env-tx-short { display:none; }
|
||||||
|
@media (max-width:560px) {
|
||||||
|
.env-tx-full { display:none; }
|
||||||
|
.env-tx-short { display:inline; }
|
||||||
|
}
|
||||||
.muted { color:var(--muted); }
|
.muted { color:var(--muted); }
|
||||||
/* Heading/eticheta accesibila doar pentru cititoare de ecran (vizual ascunsa). */
|
/* Heading/eticheta accesibila doar pentru cititoare de ecran (vizual ascunsa). */
|
||||||
.sr-only { position:absolute; width:1px; height:1px; padding:0; margin:-1px; overflow:hidden;
|
.sr-only { position:absolute; width:1px; height:1px; padding:0; margin:-1px; overflow:hidden;
|
||||||
@@ -956,7 +965,7 @@
|
|||||||
title="RAR online{% if last_login|default('') %} — Ultima autentificare: {{ last_login }}{% endif %}"
|
title="RAR online{% if last_login|default('') %} — Ultima autentificare: {{ last_login }}{% endif %}"
|
||||||
aria-label="RAR online">
|
aria-label="RAR online">
|
||||||
<span class="rar-dot live" aria-hidden="true"></span>
|
<span class="rar-dot live" aria-hidden="true"></span>
|
||||||
<span class="rar-tx">RAR online</span>
|
<span class="rar-tx">RAR</span>
|
||||||
</div>
|
</div>
|
||||||
{% else %}
|
{% else %}
|
||||||
<div class="rar-chip rar-err" role="status"
|
<div class="rar-chip rar-err" role="status"
|
||||||
@@ -966,6 +975,7 @@
|
|||||||
<span class="rar-tx">RAR blocat</span>
|
<span class="rar-tx">RAR blocat</span>
|
||||||
</div>
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
{% include '_header_env_badge.html' %}
|
||||||
{# Comutatorul "Trimite automat la RAR" langa semnalul RAR.
|
{# Comutatorul "Trimite automat la RAR" langa semnalul RAR.
|
||||||
In afara swap-ului periodic al #status-bar. #}
|
In afara swap-ului periodic al #status-bar. #}
|
||||||
{% include '_auto_send_toggle.html' %}
|
{% include '_auto_send_toggle.html' %}
|
||||||
|
|||||||
@@ -1,13 +1,15 @@
|
|||||||
"""Indicator mediu RAR in statusbar + toggle conditionat.
|
"""Badge mediu RAR compact in header + toggle conditionat.
|
||||||
|
|
||||||
Rute testate:
|
Rute testate:
|
||||||
GET /_fragments/status -- indicator mediu (eticheta statica sau toggle)
|
GET / -- badge mediu in header (eticheta statica sau toggle)
|
||||||
POST /_fragments/status/toggle-env -- comuta rar_env_default intre mediile disponibile
|
POST /_fragments/status/toggle-env -- comuta rar_env_default intre mediile disponibile
|
||||||
|
POST /cont/rar-medii -- schimbare mediu implicit din Setari
|
||||||
|
|
||||||
Teste:
|
Teste:
|
||||||
test_afiseaza_env_default -- un mediu disponibil -> eticheta statica, fara toggle
|
test_afiseaza_env_default -- un mediu disponibil -> eticheta statica, fara toggle
|
||||||
test_toggle_doar_la_doua_medii -- doua medii -> toggle prezent; un mediu -> toggle absent
|
test_toggle_doar_la_doua_medii -- doua medii -> toggle prezent; un mediu -> toggle absent
|
||||||
test_toggle_schimba_default -- POST toggle -> rar_env_default schimbat in DB, 200
|
test_toggle_schimba_default -- POST toggle -> rar_env_default schimbat in DB, badge+status OOB
|
||||||
|
test_rar_medii_actualizeaza_badge_oob -- schimbarea mediului implicit din Setari anexeaza badge OOB
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
@@ -116,14 +118,14 @@ def _seteaza_mediu_disponibil(acct_id: int, env: str) -> None:
|
|||||||
conn.close()
|
conn.close()
|
||||||
|
|
||||||
|
|
||||||
def _get_csrf_din_status(client) -> str:
|
def _get_csrf_din_pagina(client) -> str:
|
||||||
"""Obtine CSRF token din fragmentul /_fragments/status."""
|
"""Obtine CSRF token din pagina completa `/` (header, randat o singura data)."""
|
||||||
resp = client.get("/_fragments/status")
|
resp = client.get("/")
|
||||||
assert resp.status_code == 200, f"/_fragments/status a returnat {resp.status_code}"
|
assert resp.status_code == 200, f"/ a returnat {resp.status_code}"
|
||||||
m = re.search(r'name="csrf_token"\s+value="([^"]+)"', resp.text)
|
m = re.search(r'name="csrf_token"\s+value="([^"]+)"', resp.text)
|
||||||
if not m:
|
if not m:
|
||||||
m = re.search(r'value="([^"]+)"\s+name="csrf_token"', resp.text)
|
m = re.search(r'value="([^"]+)"\s+name="csrf_token"', resp.text)
|
||||||
assert m, f"csrf_token negasit in statusbar: {resp.text[:600]}"
|
assert m, f"csrf_token negasit pe pagina: {resp.text[:600]}"
|
||||||
return m.group(1)
|
return m.group(1)
|
||||||
|
|
||||||
|
|
||||||
@@ -133,7 +135,7 @@ def _get_csrf_din_status(client) -> str:
|
|||||||
|
|
||||||
|
|
||||||
def test_afiseaza_env_default(client):
|
def test_afiseaza_env_default(client):
|
||||||
"""Cont cu UN singur mediu disponibil (prod) -> statusbar contine eticheta pentru Productie,
|
"""Cont cu UN singur mediu disponibil (prod) -> header contine eticheta pentru Productie,
|
||||||
fara niciun control de toggle/comutare.
|
fara niciun control de toggle/comutare.
|
||||||
Eticheta foloseste 'PRODUCȚIE' (diacritice + majuscule).
|
Eticheta foloseste 'PRODUCȚIE' (diacritice + majuscule).
|
||||||
"""
|
"""
|
||||||
@@ -141,13 +143,14 @@ def test_afiseaza_env_default(client):
|
|||||||
_seteaza_mediu_disponibil(acct_id, "prod")
|
_seteaza_mediu_disponibil(acct_id, "prod")
|
||||||
_login(client, "env1@test.com", "parolasecreta10")
|
_login(client, "env1@test.com", "parolasecreta10")
|
||||||
|
|
||||||
resp = client.get("/_fragments/status")
|
resp = client.get("/")
|
||||||
assert resp.status_code == 200, f"Status HTTP neasteptat: {resp.status_code}"
|
assert resp.status_code == 200, f"Status HTTP neasteptat: {resp.status_code}"
|
||||||
html = resp.text
|
html = resp.text
|
||||||
|
|
||||||
|
assert 'id="header-env-badge"' in html, f"Badge mediu absent din header: {html[:800]}"
|
||||||
# Eticheta mediului trebuie prezenta — "PRODUC" acopera atat 'PRODUCȚIE' cat si
|
# Eticheta mediului trebuie prezenta — "PRODUC" acopera atat 'PRODUCȚIE' cat si
|
||||||
# formele anterioare 'Productie'/'PRODUCTIE' (anti-regresie).
|
# formele anterioare 'Productie'/'PRODUCTIE' (anti-regresie).
|
||||||
assert "PRODUC" in html.upper(), f"Eticheta Productie absenta in statusbar: {html[:800]}"
|
assert "PRODUC" in html.upper(), f"Eticheta Productie absenta din badge: {html[:800]}"
|
||||||
|
|
||||||
# Nu trebuie sa existe un control de comutare (toggle) la un singur mediu
|
# Nu trebuie sa existe un control de comutare (toggle) la un singur mediu
|
||||||
assert "toggle-env" not in html, \
|
assert "toggle-env" not in html, \
|
||||||
@@ -155,7 +158,7 @@ def test_afiseaza_env_default(client):
|
|||||||
|
|
||||||
|
|
||||||
def test_toggle_doar_la_doua_medii(client):
|
def test_toggle_doar_la_doua_medii(client):
|
||||||
"""Cont cu DOUA medii disponibile -> statusbar contine controlul de toggle.
|
"""Cont cu DOUA medii disponibile -> header contine controlul de toggle.
|
||||||
Cont cu UN singur mediu -> NU contine toggle.
|
Cont cu UN singur mediu -> NU contine toggle.
|
||||||
"""
|
"""
|
||||||
# Cont cu doua medii
|
# Cont cu doua medii
|
||||||
@@ -164,7 +167,7 @@ def test_toggle_doar_la_doua_medii(client):
|
|||||||
_seteaza_mediu_disponibil(acct2_id, "prod")
|
_seteaza_mediu_disponibil(acct2_id, "prod")
|
||||||
_login(client, "env2@test.com", "parolasecreta10")
|
_login(client, "env2@test.com", "parolasecreta10")
|
||||||
|
|
||||||
resp2 = client.get("/_fragments/status")
|
resp2 = client.get("/")
|
||||||
assert resp2.status_code == 200
|
assert resp2.status_code == 200
|
||||||
html2 = resp2.text
|
html2 = resp2.text
|
||||||
assert "toggle-env" in html2, \
|
assert "toggle-env" in html2, \
|
||||||
@@ -176,7 +179,7 @@ def test_toggle_doar_la_doua_medii(client):
|
|||||||
# Relogin pe alt cont (simulam logout/login rapid prin schimbare sesiune)
|
# Relogin pe alt cont (simulam logout/login rapid prin schimbare sesiune)
|
||||||
_login(client, "env1b@test.com", "parolasecreta10")
|
_login(client, "env1b@test.com", "parolasecreta10")
|
||||||
|
|
||||||
resp1 = client.get("/_fragments/status")
|
resp1 = client.get("/")
|
||||||
assert resp1.status_code == 200
|
assert resp1.status_code == 200
|
||||||
html1 = resp1.text
|
html1 = resp1.text
|
||||||
assert "toggle-env" not in html1, \
|
assert "toggle-env" not in html1, \
|
||||||
@@ -187,7 +190,7 @@ def test_toggle_doar_la_doua_medii(client):
|
|||||||
|
|
||||||
def test_toggle_schimba_default(client):
|
def test_toggle_schimba_default(client):
|
||||||
"""POST la /_fragments/status/toggle-env comuta rar_env_default in DB
|
"""POST la /_fragments/status/toggle-env comuta rar_env_default in DB
|
||||||
si intoarce statusbar-ul actualizat (200).
|
si intoarce badge-ul actualizat (tinta hx-target) + status bar-ul ca OOB swap (200).
|
||||||
"""
|
"""
|
||||||
acct_id, _ = _create_account_user("Firma Toggle", "toggle@test.com")
|
acct_id, _ = _create_account_user("Firma Toggle", "toggle@test.com")
|
||||||
_seteaza_mediu_disponibil(acct_id, "test")
|
_seteaza_mediu_disponibil(acct_id, "test")
|
||||||
@@ -208,15 +211,17 @@ def test_toggle_schimba_default(client):
|
|||||||
env_inainte = row_inainte["rar_env_default"] or "prod"
|
env_inainte = row_inainte["rar_env_default"] or "prod"
|
||||||
|
|
||||||
# Obtine CSRF si face toggle
|
# Obtine CSRF si face toggle
|
||||||
csrf = _get_csrf_din_status(client)
|
csrf = _get_csrf_din_pagina(client)
|
||||||
resp = client.post("/_fragments/status/toggle-env", data={"csrf_token": csrf})
|
resp = client.post("/_fragments/status/toggle-env", data={"csrf_token": csrf})
|
||||||
assert resp.status_code == 200, \
|
assert resp.status_code == 200, \
|
||||||
f"Toggle a returnat {resp.status_code}: {resp.text[:300]}"
|
f"Toggle a returnat {resp.status_code}: {resp.text[:300]}"
|
||||||
|
|
||||||
# Verifica ca statusbar-ul actualizat e in raspuns
|
# Raspunsul contine badge-ul (tinta hx-target) + status bar-ul ca OOB swap
|
||||||
html = resp.text
|
html = resp.text
|
||||||
assert "status-bar" in html, \
|
assert 'id="header-env-badge"' in html, \
|
||||||
f"Raspunsul toggle nu contine statusbar: {html[:400]}"
|
f"Raspunsul toggle nu contine badge-ul din header: {html[:400]}"
|
||||||
|
assert "status-bar" in html and "hx-swap-oob" in html, \
|
||||||
|
f"Raspunsul toggle nu contine status bar-ul ca OOB swap: {html[:400]}"
|
||||||
|
|
||||||
# Verifica schimbarea in DB
|
# Verifica schimbarea in DB
|
||||||
conn = get_connection()
|
conn = get_connection()
|
||||||
@@ -232,3 +237,30 @@ def test_toggle_schimba_default(client):
|
|||||||
f"rar_env_default NU s-a schimbat: inainte={env_inainte!r}, dupa={env_dupa!r}"
|
f"rar_env_default NU s-a schimbat: inainte={env_inainte!r}, dupa={env_dupa!r}"
|
||||||
assert env_dupa in ("test", "prod"), \
|
assert env_dupa in ("test", "prod"), \
|
||||||
f"rar_env_default are valoare invalida: {env_dupa!r}"
|
f"rar_env_default are valoare invalida: {env_dupa!r}"
|
||||||
|
|
||||||
|
|
||||||
|
def test_rar_medii_actualizeaza_badge_oob(client):
|
||||||
|
"""POST /cont/rar-medii cu un nou mediu implicit anexeaza badge-ul din header
|
||||||
|
ca OOB swap, ca header-ul sa reflecte imediat schimbarea (fara reload).
|
||||||
|
"""
|
||||||
|
acct_id, _ = _create_account_user("Firma Setari", "setari@test.com")
|
||||||
|
_seteaza_mediu_disponibil(acct_id, "test")
|
||||||
|
_seteaza_mediu_disponibil(acct_id, "prod")
|
||||||
|
_login(client, "setari@test.com", "parolasecreta10")
|
||||||
|
|
||||||
|
csrf = _get_csrf_din_pagina(client)
|
||||||
|
resp = client.post(
|
||||||
|
"/cont/rar-medii",
|
||||||
|
data={
|
||||||
|
"csrf_token": csrf,
|
||||||
|
"test_enabled": "1",
|
||||||
|
"prod_enabled": "1",
|
||||||
|
"rar_env_default": "test",
|
||||||
|
},
|
||||||
|
)
|
||||||
|
assert resp.status_code == 200, \
|
||||||
|
f"/cont/rar-medii a returnat {resp.status_code}: {resp.text[:400]}"
|
||||||
|
|
||||||
|
html = resp.text
|
||||||
|
assert 'id="header-env-badge"' in html and "hx-swap-oob" in html, \
|
||||||
|
f"Raspunsul /cont/rar-medii nu anexeaza badge-ul OOB din header: {html[:600]}"
|
||||||
|
|||||||
Reference in New Issue
Block a user