diff --git a/app/fiches/interface.py b/app/fiches/interface.py index aeaf6b2..7e9d8fb 100644 --- a/app/fiches/interface.py +++ b/app/fiches/interface.py @@ -2,6 +2,7 @@ import streamlit as st import requests import os +import pathlib from .utils.tickets.display import afficher_tickets_par_fiche from .utils.tickets.creation import formulaire_creation_ticket_dynamique @@ -64,7 +65,8 @@ def interface_fiches(): else: SEUILS = st.session_state["seuils"] - html_path = os.path.join("HTML", dossier_choisi, os.path.splitext(fiche_choisie)[0] + ".html") + nom_fiche = os.path.splitext(fiche_choisie)[0] + html_path = os.path.join("HTML", dossier_choisi, nom_fiche + ".html") path_relative = f"Documents/{dossier_choisi}/{fiche_choisie}" commits_url = f"{GITEA_URL}/repos/{ORGANISATION}/{DEPOT_FICHES}/commits?path={path_relative}&sha={ENV}" @@ -82,7 +84,24 @@ def interface_fiches(): with open(html_path, "r", encoding="utf-8") as f: st.markdown(f.read(), unsafe_allow_html=True) - st.markdown("
", unsafe_allow_html=True) + if st.session_state.get("logged_in", False): + pdf_name = nom_fiche + ".pdf" + pdf_path = os.path.join("static", "Fiches", dossier_choisi, pdf_name) + + # Bouton de téléchargement du PDF + if os.path.exists(pdf_path): + with open(pdf_path, "rb") as pdf_file: + st.download_button( + label="Télécharger cette fiche en PDF", + data=pdf_file, + file_name=pdf_name, + mime="application/pdf", + help="Télécharger la version PDF de cette fiche", + key="telecharger_fiche_pdf" + ) + else: + st.warning("Le fichier PDF de cette fiche n'est pas disponible.") + st.markdown("## Gestion des tickets pour cette fiche") afficher_tickets_par_fiche(rechercher_tickets_gitea(fiche_choisie)) formulaire_creation_ticket_dynamique(fiche_choisie) diff --git a/app/fiches/utils/dynamic/assemblage_fabrication/production.py b/app/fiches/utils/dynamic/assemblage_fabrication/production.py index 6568e9f..d99dbca 100644 --- a/app/fiches/utils/dynamic/assemblage_fabrication/production.py +++ b/app/fiches/utils/dynamic/assemblage_fabrication/production.py @@ -23,7 +23,10 @@ def build_production_sections(md: str) -> str: yaml_block = re.search(r"```yaml\n(.+?)\n```", md, re.DOTALL) if not yaml_block: return md - + + # Capture le bloc YAML complet pour le supprimer plus tard + yaml_block_full = yaml_block.group(0) + try: yaml_data = yaml.safe_load(yaml_block.group(1)) except Exception as e: @@ -130,5 +133,8 @@ def build_production_sections(md: str) -> str: st.warning(f"Aucune section IHH trouvée pour le schéma {schema} dans la fiche technique IHH.") except Exception as e: st.error(f"Erreur lors de la lecture/traitement de la fiche IHH: {e}") + + # Supprimer le bloc YAML du markdown final + md_modifie = md_modifie.replace(yaml_block_full, "") return md_modifie diff --git a/app/fiches/utils/tickets/core.py b/app/fiches/utils/tickets/core.py index 8d4a9d3..99a88e5 100644 --- a/app/fiches/utils/tickets/core.py +++ b/app/fiches/utils/tickets/core.py @@ -64,7 +64,7 @@ def rechercher_tickets_gitea(fiche_selectionnee): if not cible: return [] - labels_cibles = set(cible["operations"] + [cible["item"]]) + labels_cibles = set([cible["item"]]) tickets_associes = [] for issue in issues: diff --git a/app/personnalisation/interface.py b/app/personnalisation/interface.py index 2993cb9..53480fb 100644 --- a/app/personnalisation/interface.py +++ b/app/personnalisation/interface.py @@ -9,7 +9,7 @@ def interface_personnalisation(G): st.markdown("# Personnalisation des produits finaux") with st.expander("Comment utiliser cet onglet ?", expanded=False): st.markdown(""" - 1. Cliquez sur "Ajouter un produit final" pour créer un nouveau produit + 1. Cliquez sur « Ajouter un produit final » pour créer un nouveau produit 2. Donnez un nom à votre produit 3. Sélectionnez une opération d'assemblage appropriée (si pertinent) 4. Choisissez les composants qui constituent votre produit dans la liste proposée diff --git a/assets/fiches_labels.csv b/assets/fiches_labels.csv index 5917b8c..e74ea37 100644 --- a/assets/fiches_labels.csv +++ b/assets/fiches_labels.csv @@ -36,15 +36,15 @@ Fiche minerai aluminium.md,Extraction/Traitement/Réserves,Aluminium Fiche minerai antimoine.md,Extraction/Traitement/Réserves,Antimoine Fiche minerai argent.md,Extraction/Traitement/Réserves,Argent Fiche minerai arsenic.md,Extraction/Traitement/Réserves,Arsenic -Fiche minerai beryllium.md,Extraction/Traitement/Réserves,Beryllium -Fiche minerai ceramiques.md,Extraction/Traitement/Réserves,Ceramiques -Fiche minerai cerium.md,Extraction/Traitement/Réserves,Cerium +Fiche minerai béryllium.md,Extraction/Traitement/Réserves,Beryllium +Fiche minerai céramiques.md,Extraction/Traitement/Réserves,Ceramiques +Fiche minerai cérium.md,Extraction/Traitement/Réserves,Cerium Fiche minerai chrome.md,Extraction/Traitement/Réserves,Chrome Fiche minerai cobalt.md,Extraction/Traitement/Réserves,Cobalt Fiche minerai cuivre.md,Extraction/Traitement/Réserves,Cuivre Fiche minerai dysprosium.md,Extraction/Traitement/Réserves,Dysprosium Fiche minerai erbium.md,Extraction/Traitement/Réserves,Erbium -Fiche minerai etain.md,Extraction/Traitement/Réserves,Etain +Fiche minerai étain.md,Extraction/Traitement/Réserves,Etain Fiche minerai europium.md,Extraction/Traitement/Réserves,Europium Fiche minerai fluorite.md,Extraction/Traitement/Réserves,Fluorite Fiche minerai gadolinium.md,Extraction/Traitement/Réserves,Gadolinium @@ -56,9 +56,9 @@ Fiche minerai holmium.md,Extraction/Traitement/Réserves,Holmium Fiche minerai indiumetain.md,Extraction/Traitement/Réserves,IndiumEtain Fiche minerai lanthane.md,Extraction/Traitement/Réserves,Lanthane Fiche minerai lithium.md,Extraction/Traitement/Réserves,Lithium -Fiche minerai magnesium.md,Extraction/Traitement/Réserves,Magnesium -Fiche minerai manganese.md,Extraction/Traitement/Réserves,Manganese -Fiche minerai neodyme.md,Extraction/Traitement/Réserves,Neodyme +Fiche minerai magnésium.md,Extraction/Traitement/Réserves,Magnesium +Fiche minerai manganèse.md,Extraction/Traitement/Réserves,Manganese +Fiche minerai néodyme.md,Extraction/Traitement/Réserves,Neodyme Fiche minerai nickel.md,Extraction/Traitement/Réserves,Nickel Fiche minerai or.md,Extraction/Traitement/Réserves,Or Fiche minerai palladium.md,Extraction/Traitement/Réserves,Palladium @@ -67,8 +67,8 @@ Fiche minerai phosphore.md,Extraction/Traitement/Réserves,Phosphore Fiche minerai plastiques.md,Extraction/Traitement/Réserves,Plastiques Fiche minerai platine.md,Extraction/Traitement/Réserves,Platine Fiche minerai plomb.md,Extraction/Traitement/Réserves,Plomb -Fiche minerai polystyrene.md,Extraction/Traitement/Réserves,Polystyrene -Fiche minerai praseodyme.md,Extraction/Traitement/Réserves,Praseodyme +Fiche minerai polystyrène.md,Extraction/Traitement/Réserves,Polystyrene +Fiche minerai praséodyme.md,Extraction/Traitement/Réserves,Praseodyme Fiche minerai pvc.md,Extraction/Traitement/Réserves,PVC Fiche minerai quartz.md,Extraction/Traitement/Réserves,Quartz Fiche minerai samarium.md,Extraction/Traitement/Réserves,Samarium @@ -77,7 +77,7 @@ Fiche minerai silicium.md,Extraction/Traitement/Réserves,Silicium Fiche minerai tantale.md,Extraction/Traitement/Réserves,Tantale Fiche minerai terbium.md,Extraction/Traitement/Réserves,Terbium Fiche minerai titane.md,Extraction/Traitement/Réserves,Titane -Fiche minerai tungstene.md,Extraction/Traitement/Réserves,Tungstene +Fiche minerai tungstène.md,Extraction/Traitement/Réserves,Tungstene Fiche minerai verre.md,Extraction/Traitement/Réserves,Verre Fiche minerai yttrium.md,Extraction/Traitement/Réserves,Yttrium Fiche minerai zinc.md,Extraction/Traitement/Réserves,Zinc diff --git a/assets/styles/base.css b/assets/styles/base.css index 92b4b22..ac9aa78 100644 --- a/assets/styles/base.css +++ b/assets/styles/base.css @@ -1,185 +1,60 @@ /* --- Base.css --- */ +/* ========================================== + 1. Reset et base + ========================================== */ .stAppHeader { visibility: hidden; } -/* Conteneur principal */ -.block-container { - max-width: 1024px !important; - padding-left: 2rem; - padding-right: 2rem; - padding: 0rem 1rem 10rem; +body, html { + font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif; } -.stVerticalBlock { - gap: 0.5rem !important; +body, .stApp, .block-container { + background-color: var(--bg-color) !important; + color: var(--text-color) !important; } -/* Typographie & structure */ -body, -html { - font-family: - -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, - sans-serif; -} +/* ========================================== + 2. Layout et containers + ========================================== */ .block-container { max-width: 1024px !important; padding: 0 1rem 10rem; } + .stVerticalBlock { gap: 0.5rem !important; } -/* Boutons & sliders */ +/* ========================================== + 3. Composants d'interface + ========================================== */ + +/* --- 3.1 Boutons --- */ .stButton > button, .stDownloadButton > button, +.stFormSubmitButton > button, .stSlider > div > div { background-color: darkgreen !important; color: white !important; border: 1px solid grey; } -/* Sidebar (style fixe) */ -section[data-testid="stSidebar"] { - background-color: #ccc !important; - color: #111 !important; +.st-key-FormSubmitter-auth_form-Se-connecter { + margin-left: auto; + margin-right: auto; } -section[data-testid="stSidebar"] .stButton > button { - background-color: darkgreen !important; +section:not([data-testid="stSidebar"]) button[data-testid="stBaseButton-primary"], +section:not([data-testid="stSidebar"]) button[data-testid="stBaseButton-secondary"] { color: white !important; - font-weight: bold; - border: 1px solid #ccc !important; + background: darkgreen !important; } -/* Footer commun */ -.wide-footer { - width: 100vw; - margin-left: calc(-50vw + 50%); - margin-top: 3rem; - box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1); - border-top: 1px solid #ddd; - text-align: center; - padding-top: 1rem; -} -.info-footer { - font-size: 1rem !important; - font-weight: 800; -} - -/* En-tête large */ -.wide-header { - width: 100vw; - margin-left: calc(-50vw + 50%); - box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1); - border-bottom: 1px solid #ddd; - text-align: center; - padding-top: 1rem; - margin-top: -1.25em; -} - -.titre-header { - font-size: 2rem !important; - font-weight: bolder !important; -} - -/* Accessibilité RGAA pour les onglets */ -div[role="radiogroup"] > label { - padding: 0.5em 1em; - border-radius: 0.4em; - margin-right: 0.5em; - cursor: pointer; - border: 1px solid #fff; -} -div[role="radiogroup"] > label[data-selected="true"] { - font-weight: bold; - border: 2px solid #145a1a; -} - -/* Styles pour les éléments décoratifs */ -section[data-testid="stSidebar"] .decorative-heading { - font-size: 1.25rem; - font-weight: bold; - margin-bottom: 0.5rem; - text-align: center; - color: #145a1a; -} - -section[data-testid="stSidebar"] div[role="radiogroup"] { - justify-content: center !important; - display: flex !important; - gap: 1rem; /* Optionnel : espace entre les boutons */ -} - -/* Corrige la couleur du texte des boutons de la sidebar - identique en light ou en dark */ -section[data-testid="stSidebar"] .stButton > button { - background-color: darkgreen !important; - color: white !important; - font-weight: bold !important; - border: 1px solid #ccc !important; - width: 100%; -} - -/* Translate Drag and drop and Browse files */ -/* Hide original "Drag and drop file here" text */ -div[data-testid="stFileUploaderDropzoneInstructions"] - .st-emotion-cache-j7qwjs - > span:nth-of-type(1) { - visibility: hidden; -} -/* Insert French translation */ -div[data-testid="stFileUploaderDropzoneInstructions"] - .st-emotion-cache-j7qwjs - > span:nth-of-type(1)::after { - content: "Glissez-déposez votre fichier ici"; - visibility: visible; - display: block; - font-size: inherit; - color: inherit; -} - -/* Hide original "Browse files" button text */ -/* Target the button within the dropzone container for uploader */ -div[data-testid="stFileUploaderDropzone"] - button[data-testid="stBaseButton-secondary"] { - color: transparent !important; - position: relative; -} -/* Insert French translation for button */ -div[data-testid="stFileUploaderDropzone"] - button[data-testid="stBaseButton-secondary"]::after { - content: "Parcourir les fichiers"; - visibility: visible !important; - position: absolute; - top: 50%; - left: 50%; - transform: translate(-50%, -50%); - display: block; - font-size: inherit; - color: inherit !important; -} - -/* Override Streamlit file uploader limit text to 100 Ko */ -div[data-testid="stFileUploaderDropzoneInstructions"] small { - visibility: hidden; -} -div[data-testid="stFileUploaderDropzoneInstructions"] small::after { - content: "Limite 100 Ko par fichier • JSON"; - visibility: visible; - display: block; - font-size: inherit; - color: inherit; - margin-top: 0.25em; -} - -button[data-testid="stBaseButton-primary"], -button[data-testid="stBaseButton-secondary"] { - color: white !important; -} -button[data-testid="stBaseButton-primary"] p, -, -button[data-testid="stBaseButton-secondary"] p { +section:not([data-testid="stSidebar"]) button[data-testid="stBaseButton-primary"] p, +section:not([data-testid="stSidebar"]) button[data-testid="stBaseButton-secondary"] p { color: white !important; } @@ -206,59 +81,35 @@ button[data-testid="stBaseButton-secondary"] p { letter-spacing: 0.2em; } -/* Utilisation des variables CSS définies dans les fichiers de thème */ - -body, -.stApp, -.block-container { - background-color: var(--bg-color) !important; - color: var(--text-color) !important; +button[data-testid="stBaseButton-headerNoPadding"] svg { + fill: var(--text-color) !important; } -/* En-tête large */ -.wide-header { - background-color: var(--header-bg); +/* --- 3.2 Onglets et radiogroup --- */ +div[role="radiogroup"] > label { + padding: 0.5em 1em; + border-radius: 0.4em; + margin-right: 0.5em; + cursor: pointer; + border: 1px solid #fff; } -.titre-header { - color: var(--header-title); +div[role="radiogroup"] > label[data-selected="true"] { + font-weight: bold; + border: 2px solid #145a1a; } -/* Footer commun */ -.wide-footer { - background-color: var(--footer-bg); -} - -.info-footer { - color: var(--footer-text); -} - -/* Accessibilité RGAA pour les onglets */ section:not([data-testid="stSidebar"]) div[role="radiogroup"] > label p { background-color: var(--radio-bg) !important; color: var(--radio-text) !important; } -section:not([data-testid="stSidebar"]) - div[role="radiogroup"] - > label[data-selected="true"] { +section:not([data-testid="stSidebar"]) div[role="radiogroup"] > label[data-selected="true"] { background-color: var(--radio-selected-bg) !important; color: var(--radio-selected-text) !important; } -/* Graphiques */ -.stPlotlyChart text { - fill: var(--plot-text) !important; -} - -/* Paragraphes */ -section:not([data-testid="stSidebar"]) - div:not[data-testid="stElementContainer"] - p:not(#Authentification):not(#Theme) { - color: var(--paragraph-color) !important; -} - -/* Champs de formulaire */ +/* --- 3.3 Champs de formulaire --- */ div[data-baseweb="select"], section:not([data-testid="stSidebar"]) div[data-baseweb="base-input"], section[data-testid="stFileUploaderDropzone"] { @@ -267,12 +118,89 @@ section[data-testid="stFileUploaderDropzone"] { padding: 4px; } -/* Détails */ -details { - border-color: var(--details-border) !important; +section:not([data-testid="stSidebar"]) div[data-testid="stSelectbox"] p, +section:not([data-testid="stSidebar"]) div[data-testid="stMultiSelect"] p, +section:not([data-testid="stSidebar"]) div[data-testid="stRadio"] p, +section:not([data-testid="stSidebar"]) div[data-testid="stCheckbox"] p, +section:not([data-testid="stSidebar"]) div[data-testid="stTextInput"] p, +section:not([data-testid="stSidebar"]) div[data-testid="stTextArea"] p, +section:not([data-testid="stSidebar"]) div[data-testid="stAlertContentInfo"] p { + color: var(--text-color) !important; } -/* Tables */ +/* ========================================== + 4. Header et Footer + ========================================== */ + +/* --- 4.1 Header --- */ +.wide-header { + width: 100vw; + margin-left: calc(-50vw + 50%); + box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1); + border-bottom: 1px solid #ddd; + text-align: center; + padding-top: 1rem; + margin-top: -1.25em; + background-color: var(--header-bg); +} + +.titre-header { + font-size: 2rem !important; + font-weight: bolder !important; + color: var(--header-title); +} + +/* --- 4.2 Footer --- */ +.wide-footer { + width: 100vw; + margin-left: calc(-50vw + 50%); + margin-top: 3rem; + box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1); + border-top: 1px solid #ddd; + text-align: center; + padding-top: 1rem; + background-color: var(--footer-bg); +} + +.info-footer { + font-size: 1rem !important; + font-weight: 800; + color: var(--footer-text); +} + +/* ========================================== + 5. Sidebar + ========================================== */ +section[data-testid="stSidebar"] { + background-color: #ccc !important; + color: #111 !important; +} + +section[data-testid="stSidebar"] .stButton > button { + background-color: darkgreen !important; + color: white !important; + font-weight: bold !important; + border: 1px solid #ccc !important; + width: 100%; +} + +section[data-testid="stSidebar"] .decorative-heading { + font-size: 1.25rem; + font-weight: bold; + margin-bottom: 0.5rem; + text-align: center; + color: #145a1a; +} + +section[data-testid="stSidebar"] div[role="radiogroup"] { + justify-content: center !important; + display: flex !important; + gap: 1rem; +} + +/* ========================================== + 6. Tables + ========================================== */ table { border: 1px solid var(--table-border) !important; border-collapse: collapse; @@ -280,14 +208,12 @@ table { margin-bottom: 1.5em; } -th, -td { +th, td { border: 1px solid var(--table-border) !important; padding: 8px; text-align: left; } -/* Accessibilité RGAA */ caption { caption-side: top; font-weight: bold; @@ -301,20 +227,61 @@ table[role="table"] th[scope="col"] { background-color: var(--background-color); } -/* Fin de Tables */ +/* ========================================== + 7. Composants spécifiques + ========================================== */ -section:not([data-testid="stSidebar"]) div[data-testid="stSelectbox"] p, -section:not([data-testid="stSidebar"]) div[data-testid="stMultiSelect"] p, -section:not([data-testid="stSidebar"]) div[data-testid="stRadio"] p, -section:not([data-testid="stSidebar"]) div[data-testid="stCheckbox"] p, -section:not([data-testid="stSidebar"]) div[data-testid="stTextInput"] p, -section:not([data-testid="stSidebar"]) div[data-testid="stTextArea"] p, -section:not([data-testid="stSidebar"]) div[data-testid="stAlertContentInfo"] p { - color: var(--text-color) !important; +/* --- 7.1 File Uploader (traductions) --- */ +/* Hide original "Drag and drop file here" text */ +div[data-testid="stFileUploaderDropzoneInstructions"] span:nth-of-type(1) { + visibility: hidden; } -section:not([data-testid="stSidebar"]) hr { - background-color: var(--hr-color) !important; +/* Insert French translation */ +div[data-testid="stFileUploaderDropzoneInstructions"] span:nth-of-type(1)::after { + content: "Glissez-déposez votre fichier ici"; + visibility: visible; + display: block; + font-size: inherit; + color: inherit; +} + +/* Hide original "Browse files" button text */ +div[data-testid="stFileUploaderDropzone"] button[data-testid="stBaseButton-secondary"] { + color: transparent !important; + position: relative; +} + +/* Insert French translation for button */ +div[data-testid="stFileUploaderDropzone"] button[data-testid="stBaseButton-secondary"]::after { + content: "Parcourir les fichiers"; + visibility: visible !important; + position: absolute; + top: 50%; + left: 50%; + transform: translate(-50%, -50%); + display: block; + font-size: inherit; + color: inherit !important; +} + +/* Override Streamlit file uploader limit text */ +div[data-testid="stFileUploaderDropzoneInstructions"] small { + visibility: hidden; +} + +div[data-testid="stFileUploaderDropzoneInstructions"] small::after { + content: "Limite 100 Ko par fichier • JSON"; + visibility: visible; + display: block; + font-size: inherit; + color: inherit; + margin-top: 0.25em; +} + +/* --- 7.2 Graphiques --- */ +.stPlotlyChart text { + fill: var(--plot-text) !important; } .stPlotlyChart text { @@ -325,60 +292,54 @@ section:not([data-testid="stSidebar"]) hr { font-family: Verdana, sans-serif !important; } -.conteneur_commentaire { - background: var(--background-color); - padding: 0.5rem; - border-radius: 8px; - margin-bottom: 0.5rem; - border: 1px solid #ccc; - border-radius: 8px; - padding: 1em; - margin-bottom: 1em; +/* Cache complètement la section d'actions Vega */ +.vega-actions { + display: none !important; } -.commentaire_auteur { - color: var(--text-color) !important; - margin: 0; -} - -.commentaire_contenu { - color: var(--text-color) !important; - margin: 0.5rem 0 0; -} - -.conteneur_ticket { - background: var(--background-color); - padding: 0.5rem; - border-radius: 8px; - margin-bottom: 0.5rem; - border: 1px solid #ccc; - border-radius: 8px; - padding: 1em; - margin-bottom: 1em; -} - -.ticket_auteur { - color: var(--text-color) !important; - margin: 0; -} - -.ticket_contenu { - color: var(--text-color) !important; - margin: 0.5rem 0 0; -} - -button[data-testid="stBaseButton-headerNoPadding"] svg { - fill: var(--text-color) !important; +/* Et aussi le
parent, s'il faut tout masquer */ +details[title="Click to view actions"] { + display: none !important; } +/* --- 7.3 Détails et paragraphes --- */ details { border: 1px solid #ccc; border-radius: 6px; padding: 0.5em; margin-bottom: 0.5em; background-color: var(--background-color); + border-color: var(--details-border) !important; } +section:not([data-testid="stSidebar"]) div:not[data-testid="stElementContainer"] p:not(#Authentification):not(#Theme) { + color: var(--paragraph-color) !important; +} + +section:not([data-testid="stSidebar"]) hr { + background-color: var(--hr-color) !important; +} + +/* --- 7.4 Conteneurs de commentaires et tickets --- */ +.conteneur_commentaire, .conteneur_ticket { + background: var(--background-color); + padding: 1em; + border-radius: 8px; + margin-bottom: 1em; + border: 1px solid #ccc; +} + +.commentaire_auteur, .ticket_auteur { + color: var(--text-color) !important; + margin: 0; +} + +.commentaire_contenu, .ticket_contenu { + color: var(--text-color) !important; + margin: 0.5rem 0 0; +} + +/* --- 7.5 Blocs mathématiques --- */ .math-block { display: block; text-align: center; @@ -394,16 +355,15 @@ details { display: inline-block; } -/* Cache complètement la section d’actions Vega */ -.vega-actions { - display: none !important; -} - -/* Et aussi le
parent, s’il faut tout masquer */ -details[title="Click to view actions"] { - display: none !important; -} - +/* ========================================== + 8. Éléments spécifiques + ========================================== */ div.stElementContainer.element-container.st-key-nom_utilisateur { display: none !important; } + +.st-key-telecharger_fiche_pdf { + margin-left: auto; + margin-right: auto; + margin-top: 1rem; +} \ No newline at end of file diff --git a/components/connexion.py b/components/connexion.py index aefa031..660ecbd 100644 --- a/components/connexion.py +++ b/components/connexion.py @@ -38,20 +38,11 @@ def connexion(): if not st.session_state.logged_in: with st.form("auth_form"): - # 🧠 Ajout d'un champ identifiant fictif pour activer l'autocomplétion navigateur + # Ajout d'un champ identifiant fictif pour activer l'autocomplétion navigateur + # et permettre de stocker le token comme un mot de passe par le navigateur identifiant = st.text_input("Identifiant_token", value="fabnum-connexion", key="nom_utilisateur") token = st.text_input("Token d'accès personnel Gitea", type="password") submitted = st.form_submit_button("Se connecter") - st.markdown(""" - - """, unsafe_allow_html=True) if submitted and token: erreur = True diff --git a/utils/gitea.py b/utils/gitea.py index 4772fc2..840efe8 100644 --- a/utils/gitea.py +++ b/utils/gitea.py @@ -1,24 +1,44 @@ import base64 import requests import os +import streamlit as st from dateutil import parser from datetime import datetime, timezone import logging from config import GITEA_URL, GITEA_TOKEN, ORGANISATION, DEPOT_FICHES, DEPOT_CODE, ENV, ENV_CODE, DOT_FILE +def lire_fichier_local(nom_fichier): + with open(nom_fichier, "r", encoding="utf-8") as f: + contenu_md = f.read() + return contenu_md def charger_instructions_depuis_gitea(nom_fichier="Instructions.md"): headers = {"Authorization": f"token {GITEA_TOKEN}"} url = f"{GITEA_URL}/repos/{ORGANISATION}/{DEPOT_FICHES}/contents/{nom_fichier}?ref={ENV}" try: - response = requests.get(url, headers=headers) - response.raise_for_status() - data = response.json() - contenu_md = base64.b64decode(data["content"]).decode("utf-8") - return contenu_md + # Vérifier si une version plus récente existe sur le dépôt + remote_last_modified = recuperer_date_dernier_commit(f"{GITEA_URL}/repos/{ORGANISATION}/{DEPOT_FICHES}/commits?path={nom_fichier}&sha={ENV}") + local_last_modified = datetime.fromtimestamp(os.path.getmtime(nom_fichier), tz=timezone.utc) if os.path.exists(nom_fichier) else None + + # Si le fichier local n'existe pas ou si la version distante est plus récente + if not local_last_modified or (remote_last_modified and remote_last_modified > local_last_modified): + response = requests.get(url, headers=headers) + response.raise_for_status() + data = response.json() + contenu_md = base64.b64decode(data["content"]).decode("utf-8") + # Sauvegarder en local + with open(nom_fichier, "w", encoding="utf-8") as f: + f.write(contenu_md) + return contenu_md + else: + # Lire depuis le cache local + return lire_fichier_local(nom_fichier) except Exception as e: - logging.error(f"Erreur chargement instructions Gitea : {e}") + st.error(f"Erreur chargement instructions Gitea : {e}") + # Essayer de charger depuis le cache local en cas d'erreur + if os.path.exists(nom_fichier): + return lire_fichier_local(nom_fichier) return None