Quentin Lhoest
add app
f0806e2
<!DOCTYPE html>
<html lang="fr">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Généalogie des Modèles - Vue Experte</title>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-QWTKZyjpPEjISv5WaRU9OFeRpok6YctnYmDr5pNlyT2bRjXh0JMhjY6hW+ALEwIH" crossorigin="anonymous">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.11.3/font/bootstrap-icons.css">
<link rel="stylesheet" href="https://cdn.datatables.net/1.13.4/css/jquery.dataTables.min.css" />
<link rel="stylesheet" href="{{ url_for('static', filename='css/style.css') }}">
<style>
body { font-size: 1.05rem; }
.legend-color { width: 1em; height: 1em; display: inline-block; border-radius: 2px; }
.legend-color.edge { border-radius: 0; height: 0.25em; transform: translateY(-0.35em); }
</style>
</head>
<body class="d-flex flex-column min-vh-100">
<header class="navbar navbar-expand-lg navbar-light bg-light border-bottom">
<div class="container">
<a class="navbar-brand" href="/">
<span class="fw-bold">Généalogie des Modèles</span>
<small class="d-block text-muted">Exploration des relations entre modèles et datasets</small>
</a>
</div>
</header>
<main class="container mt-4 flex-grow-1">
<div class="row">
<div class="col-12">
<h1 class="display-5">Recherche Experte</h1>
<p class="lead">Explorez et filtrez la généalogie des modèles</p>
</div>
</div>
<div class="row g-3 mb-4">
<div class="col-12">
<form method="POST" action="{{ url_for('findnode_expert') }}" autocomplete="off">
<input type="hidden" name="filter" value="{{ search.filter or '' }}">
<div class="row g-3 align-items-end">
<!-- Champ de recherche -->
<div class="col-12 col-md-5">
<label for="search-input" class="form-label fw-bold">Nom à rechercher</label>
<div class="position-relative">
<input type="text" name="name" id="search-input" class="form-control"
placeholder="Taper le nom du modèle suspecté."
value="{{ request.form.name or '' }}" required autocomplete="off" />
<ul id="suggestions-list" class="list-group position-absolute w-100" style="display: none; z-index: 1000;"></ul>
</div>
</div>
<!-- Filtres -->
<div class="col-12 col-md-3">
<label class="form-label fw-bold">Filtres</label>
<div class="d-flex gap-3">
<div class="form-check">
<input class="form-check-input" type="checkbox" name="filters" value="Model" id="filter-model"
{% if 'Model' in search.filters %}checked{% endif %}>
<label class="form-check-label" for="filter-model">Modèle</label>
</div>
<div class="form-check">
<input class="form-check-input" type="checkbox" name="filters" value="Dataset" id="filter-dataset"
{% if 'Dataset' in search.filters %}checked{% endif %}>
<label class="form-check-label" for="filter-dataset">Dataset</label>
</div>
<div class="form-check">
<input class="form-check-input" type="checkbox" name="filters" value="Author" id="filter-author" {% if 'Author' in search.filters %}checked{% endif %}>
<label class="form-check-label" for="filter-author">Auteur</label>
</div>
</div>
</div>
<!-- Profondeur de recherche -->
<div class="col-12 col-md-4">
<label class="form-label fw-bold">Profondeur de recherche</label>
<div class="d-flex align-items-center gap-3">
<div class="form-check form-switch">
<input class="form-check-input" type="checkbox" id="depth-unlimited" name="depth_unlimited" checked>
<label class="form-check-label" for="depth-unlimited">Illimitée</label>
</div>
<div class="input-group input-group-sm">
<span class="input-group-text">Limité à:</span>
<input class="form-control" type="number" name="depth" id="depth"
value="{{ request.form.depth }}" min="1" max="5" disabled>
</div>
</div>
</div>
</div>
<div class="row mt-4">
<div class="col-12">
<button type="submit" name="submit" value="findnode_expert" class="btn btn-primary w-100">
<i class="bi bi-search me-1"></i>Rechercher
</button>
</div>
</div>
</form>
</div>
</div>
{% if message %}
<div class="alert alert-info mt-3"><p class="mb-0">{{ message }}</p></div>
{% endif %}
<!-- CORRECTION : Cette section s'affiche seulement s'il y a des données -->
{% if graph_data and graph_data.nodes %}
<div id="genealogy-graph-section" class="mt-4">
<div class="row g-4">
<div class="card-header"><h5 class="card-title mb-0">Composante connexe du noeud recherché</h5></div>
<!-- Colonne de gauche pour le graphe et la carte d'info -->
<div class="col-12 col-lg-8">
<div class="card position-relative">
<!-- Graphe Sigma -->
<div id="sigma-container" data-graph='{{ graph_data | tojson | safe }}' style="width: 100%; height: 600px;">
<!-- Légende flottante -->
<div id="floating-legend"
class="card p-2 position-absolute top-0 start-0 shadow-sm"
style="width: 220px; background-color: rgba(255,255,255,0.95);">
<div class="d-flex justify-content-between align-items-center mb-2">
<strong>Légendes</strong>
<button class="btn btn-sm btn-light p-0"
type="button"
data-bs-toggle="collapse"
data-bs-target="#legend-content"
aria-expanded="true"
aria-controls="legend-content">
<i class="bi bi-chevron-up"></i>
</button>
</div>
<!-- Contenu de la légende -->
<div id="legend-content" class="collapse show">
<div class="card mb-2">
<div class="card-header py-1"><h6 class="card-title mb-0">Nœuds</h6></div>
<div class="card-body p-2">
<ul id="legend-nodes" class="list-group list-group-flush small">
<li class="list-group-item d-flex align-items-center py-1">
<span class="legend-color me-2" style="background-color: hsl(45, 65%, 52%);"></span>Dataset
</li>
<li class="list-group-item d-flex align-items-center py-1">
<span class="legend-color me-2" style="background-color: #007bff;"></span>Personne
</li>
<li class="list-group-item d-flex align-items-center py-1">
<span class="legend-color me-2" style="background-color: #092d53;"></span>Organisation
</li>
<li class="list-group-item d-flex align-items-center py-1">
<span class="legend-color me-2" style="background-color:#7D7D7D;"></span>Modèle
</li>
</ul>
</div>
</div>
<div class="card">
<div class="card-header py-1"><h6 class="card-title mb-0">Relations</h6></div>
<div class="card-body p-2">
<ul id="legend-edges" class="list-group list-group-flush small">
</ul>
</div>
</div>
</div>
</div>
</div>
</div>
<div id="node-info-card" class="card mt-3 card-interactive" style="display: none;">
<div class="card-body">
<h5 class="card-title">Informations du nœud sélectionné</h5>
<div id="node-details" class="mt-2"></div>
</div>
</div>
</div>
<div class="col-12 col-lg-4">
<!-- CORRECTION : Chaque section est dans sa propre carte -->
<div class="card mb-3">
<div class="card-header"><h5 class="card-title mb-0">Filtres du Graphe</h5></div>
<div class="card-body" id="graph-filters-container">
<h6>Types de Nœuds</h6>
<div class="form-check form-switch">
<input class="form-check-input" type="checkbox" id="filter-node-model" value="Modèle" checked>
<label class="form-check-label" for="filter-node-model">Modèle</label>
</div>
<div class="form-check form-switch">
<input class="form-check-input" type="checkbox" id="filter-node-person" value="personne" checked>
<label class="form-check-label" for="filter-node-person">Personne</label>
</div>
<div class="form-check form-switch">
<input class="form-check-input" type="checkbox" id="filter-node-org" value="organisation" checked>
<label class="form-check-label" for="filter-node-org">Organisation</label>
</div>
<hr>
<h6>Types de Relations</h6>
<div id="edge-filters-container"></div>
</div>
</div>
<button id="export-btn" class="btn-modern">Télécharger le graphe</button>
</div>
</div>
<hr class="my-5">
<!-- CORRECTION : Tableau des modèles présents dans le graphe -->
<div class="row mt-4">
<div class="col-12">
<h4 class="h4">Modèles présents dans le graphe</h4>
<div class="table-responsive">
<table id="graph-models-table" class="table table-bordered table-striped table-hover" style="width:100%">
<thead>
<tr>
<th scope="col">Modèle</th>
<th scope="col">Auteur</th>
<th scope="col">Téléchargements</th>
<th scope="col">Tâche</th>
<th scope="col">J'aime</th>
<th scope="col">Date de publication</th>
<th scope="col">Dataset utilisé</th>
<th scope="col">Licence</th>
<th scope="col">Distance au modèle recherché</th>
<th scope="col">Ascendants</th>
<th scope="col">Descendants</th>
<th scope="col">Citations</th>
</tr>
</thead>
<tbody>
<!-- Le contenu sera rempli par JavaScript -->
</tbody>
</table>
</div>
</div>
</div>
</div>
{% endif %}
</main>
<footer class="bg-dark text-white text-center p-4 mt-auto">
<div class="container">
<p class="mb-0">Application de recherche et visualisation... © 2025</p>
</div>
</footer>
<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
<script src="https://cdn.datatables.net/1.13.4/js/jquery.dataTables.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js" integrity="sha384-YvpcrYf0tY3lHB60NNkmXc5s9fDVZLESaAA55NDzOxhy9GkcIdslK1eN7N6jIeHz" crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/sigma.js/2.4.0/sigma.min.js"></script>
<script src="https://unpkg.com/graphology@0.25.1/dist/graphology.umd.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/graphology-library/dist/graphology-library.min.js"></script>
<script src="{{ url_for('static', filename='js/utils.js') }}"></script>
<script src="{{ url_for('static', filename='js/script_expert.js') }}"></script>
<script>
document.addEventListener('DOMContentLoaded', function () {
const tooltipTriggerList = document.querySelectorAll('[data-bs-toggle="tooltip"]');
const tooltipList = [...tooltipTriggerList].map(tooltipTriggerEl => new bootstrap.Tooltip(tooltipTriggerEl));
});
</script>
</body>
</html>