# creation.py import re import base64 import streamlit as st from utils.translations import _ from .core import charger_fiches_et_labels, construire_corps_ticket_markdown, creer_ticket_gitea, get_labels_existants, nettoyer_labels from config import ENV import requests def parser_modele_ticket(contenu_modele): """Parse le modèle de ticket en sections.""" sections = {} lignes = contenu_modele.splitlines() titre_courant, contenu = None, [] for ligne in lignes: if ligne.startswith("## "): if titre_courant: sections[titre_courant] = "\n".join(contenu).strip() titre_courant, contenu = ligne[3:].strip(), [] elif titre_courant: contenu.append(ligne) if titre_courant: sections[titre_courant] = "\n".join(contenu).strip() return sections def generer_labels(fiche_selectionnee): """Génère les labels basés sur la fiche sélectionnée.""" labels, selected_ops = [], [] correspondances = charger_fiches_et_labels() cible = correspondances.get(fiche_selectionnee) if cible: if len(cible["operations"]) == 1: labels.append(cible["operations"][0]) elif len(cible["operations"]) > 1: selected_ops = st.multiselect(str(_("pages.fiches.tickets.contribution_type")), cible["operations"], default=cible["operations"]) return labels, selected_ops, cible def creer_champs_formulaire(sections, fiche_selectionnee): """Crée les champs du formulaire basés sur les sections.""" reponses = {} for section, aide in sections.items(): if "Type de contribution" in section: options = sorted(set(re.findall(r"- \[.\] (.+)", aide))) if str(_("pages.fiches.tickets.other")) not in options: options.append(str(_("pages.fiches.tickets.other"))) choix = st.radio(str(_("pages.fiches.tickets.contribution_type")), options) reponses[section] = st.text_input(str(_("pages.fiches.tickets.specify")), "") if choix == str(_("pages.fiches.tickets.other")) else choix elif "Fiche concernée" in section: url_fiche = f"https://fabnum-git.peccini.fr/FabNum/Fiches/src/branch/{ENV}/Documents/{fiche_selectionnee.replace(' ', '%20')}" reponses[section] = url_fiche st.text_input(str(_("pages.fiches.tickets.concerned_card")), value=url_fiche, disabled=True) elif "Sujet de la proposition" in section: reponses[section] = st.text_input(section, help=aide) else: reponses[section] = st.text_area(section, help=aide) return reponses def afficher_controles_formulaire(): """Affiche les boutons de contrôle du formulaire.""" col1, col2 = st.columns(2) if col1.button(str(_("pages.fiches.tickets.preview"))): st.session_state.previsualiser = True # S'assurer que l'expander reste ouvert en mode prévisualisation st.session_state.expander_state = True if col2.button(str(_("pages.fiches.tickets.cancel"))): st.session_state.previsualiser = False st.rerun() def gerer_previsualisation_et_soumission(reponses, labels, selected_ops, cible): """Gère la prévisualisation et la soumission du ticket.""" # Si nous avons tenté de créer un ticket (succès ou erreur) if st.session_state.get("ticket_cree", False) or st.session_state.get("ticket_erreur", False): if st.session_state.get("ticket_cree", False): st.success(str(_("pages.fiches.tickets.created_success"))) else: st.error(str(_("pages.fiches.tickets.creation_error"))) if st.button(str(_("pages.fiches.tickets.continue"))): # Réinitialiser le formulaire et cacher l'expander st.session_state.ticket_cree = False st.session_state.ticket_erreur = False st.session_state.previsualiser = False st.session_state.expander_state = False st.rerun() return # Si nous ne sommes pas en mode prévisualisation, ne rien afficher if not st.session_state.get("previsualiser", False): return st.subheader(str(_("pages.fiches.tickets.preview_title"))) for section, texte in reponses.items(): st.markdown(f"#### {section}") st.code(texte, language="markdown") titre_ticket = reponses.get("Sujet de la proposition", "").strip() or "Ticket FabNum" final_labels = nettoyer_labels(labels + selected_ops + ([cible["item"]] if cible else [])) st.markdown(f"**{str(_('pages.fiches.tickets.summary'))} :**\n- **{str(_('pages.fiches.tickets.title'))}** : `{titre_ticket}`\n- **{str(_('pages.fiches.tickets.labels'))}** : `{', '.join(final_labels)}`") if st.button(str(_("pages.fiches.tickets.confirm"))): labels_existants = get_labels_existants() labels_ids = [labels_existants[l] for l in final_labels if l in labels_existants] if "Backlog" in labels_existants: labels_ids.append(labels_existants["Backlog"]) corps = construire_corps_ticket_markdown(reponses) resultat = creer_ticket_gitea(titre_ticket, corps, labels_ids) # Marquer le résultat et ouvrir l'expander pour afficher le résultat st.session_state.ticket_cree = resultat st.session_state.ticket_erreur = not resultat st.session_state.previsualiser = False st.session_state.expander_state = True st.rerun() def formulaire_creation_ticket_dynamique(fiche_selectionnee): """Fonction principale pour le formulaire de création de ticket.""" # Initialiser l'état de l'expander si ce n'est pas déjà fait if "expander_state" not in st.session_state: st.session_state.expander_state = False with st.expander(str(_("pages.fiches.tickets.create_new")), expanded=st.session_state.expander_state): # Initialiser les états si ce n'est pas déjà fait if "ticket_cree" not in st.session_state: st.session_state.ticket_cree = False if "ticket_erreur" not in st.session_state: st.session_state.ticket_erreur = False if "previsualiser" not in st.session_state: st.session_state.previsualiser = False # Chargement et vérification du modèle contenu_modele = charger_modele_ticket() if not contenu_modele: st.error(str(_("pages.fiches.tickets.model_load_error"))) return # Traitement du modèle et génération du formulaire sections = parser_modele_ticket(contenu_modele) labels, selected_ops, cible = generer_labels(fiche_selectionnee) # Créer le formulaire et gérer ses états if st.session_state.ticket_cree or st.session_state.ticket_erreur: # Si le ticket a été créé ou a échoué, afficher le message approprié et le bouton continuer gerer_previsualisation_et_soumission({}, labels, selected_ops, cible) else: # Sinon afficher le formulaire normal reponses = creer_champs_formulaire(sections, fiche_selectionnee) # Afficher les contrôles uniquement si nous ne sommes pas en mode prévisualisation if not st.session_state.previsualiser: afficher_controles_formulaire() # Gérer la prévisualisation et soumission gerer_previsualisation_et_soumission(reponses, labels, selected_ops, cible) def charger_modele_ticket(): from config import GITEA_URL, GITEA_TOKEN, ORGANISATION, DEPOT_FICHES headers = {"Authorization": f"token {GITEA_TOKEN}"} url = f"{GITEA_URL}/repos/{ORGANISATION}/{DEPOT_FICHES}/contents/.gitea/ISSUE_TEMPLATE/Contenu.md" try: r = requests.get(url, headers=headers, timeout=10) r.raise_for_status() return base64.b64decode(r.json().get("content", "")).decode("utf-8") except Exception as e: st.error(f"{str(_('pages.fiches.tickets.model_error'))} {e}") return ""