import os from shutil import rmtree import dash_bootstrap_components as dbc import pandas # noqa: F401 # eager import: avoid plotly's lazy-import race across Dash callback threads import tomllib from dash import Dash, Input, Output, State, dcc, html, page_container, page_registry from dotenv import load_dotenv from flask import Response from src.utils import DEVELOPMENT from src.utils.cache import cache load_dotenv() # if os.getenv("PYTEST_CURRENT_TEST"): # os.environ["DATA_FILE_PARQUET_PATH"] META_TAGS = [ {"name": "viewport", "content": "width=device-width, initial-scale=1"}, { "name": "keywords", "content": "commande publique, decp, marchés publics, données essentielles", }, ] if DEVELOPMENT: META_TAGS.append({"name": "robots", "content": "noindex"}) app: Dash = Dash( title="decp.info", use_pages=True, compress=True, meta_tags=META_TAGS, ) cache_dir = os.getenv("CACHE_DIR", "/tmp/decp-cache") if os.path.exists(cache_dir): rmtree(cache_dir) cache.init_app( app.server, config={ "CACHE_TYPE": "FileSystemCache", "CACHE_DIR": cache_dir, "CACHE_DEFAULT_TIMEOUT": int( os.getenv("CACHE_DEFAULT_TIMEOUT", 3600 * 24) ), # 24h par défaut "CACHE_THRESHOLD": 300, }, ) # robots.txt @app.server.route("/robots.txt") def robots(): text = """User-agent: * Allow: / """ return Response(text, mimetype="text/plain") @app.server.route("/sitemap.xml") def sitemap(): base_url = "https://decp.info" pages = [ "/", "/observatoire", "/tableau", "/a-propos", ] xml = '\n' xml += '\n' for page in pages: xml += " \n" xml += f" {base_url}{page}\n" xml += " \n" xml += "" return Response(xml, mimetype="text/xml") with open("./pyproject.toml", "rb") as f: pyproject = tomllib.load(f) version = "v" + pyproject["project"]["version"] app.index_string = """ {%metas%} {%title%} {%favicon%} {%css%} {%app_entry%} """ navbar = dbc.Navbar( dbc.Container( fluid=True, children=[ dbc.NavItem( children=[ html.Div( [ dcc.Link(html.H1("decp.info"), href="/", className="logo"), html.P( [ html.A( version, href="https://github.com/ColinMaudry/decp.info/blob/main/CHANGELOG.md", ) ], className="version", ), ], className="logo-wrapper", ) ], style={"minWidth": "230px"}, ), dbc.Nav( children=[dcc.Markdown(os.getenv("ANNOUNCEMENTS"), id="announcements")], style={ "maxWidth": "1200px", "display": "inline-block", }, navbar=True, id="announcements-nav", ), dbc.NavbarToggler(id="navbar-toggler"), dbc.Collapse( dbc.Nav( [ dbc.NavItem( dbc.NavLink( page["name"].replace(" ", " "), href=page["relative_path"], active="exact", ) ) for page in page_registry.values() if page["name"] in ["Recherche", "À propos", "Tableau", "Observatoire"] ], className="ms-auto", navbar=True, ), id="navbar-collapse", navbar=True, ), ], ), color="light", dark=False, className="mb-4", expand="lg", ) app.layout = html.Div( [ navbar, dbc.Container( page_container, fluid=True, id="page-content-container", className="mb-4", ), ] ) @app.callback( Output("navbar-collapse", "is_open"), [Input("navbar-toggler", "n_clicks")], [State("navbar-collapse", "is_open")], ) def toggle_navbar_collapse(n, is_open): if n: return not is_open return is_open