From a6e596fb8fd79418c3430819e6dab5946658c038 Mon Sep 17 00:00:00 2001
From: "hajar.bouamout" <hajar.bouamout@inrae.fr>
Date: Fri, 20 Dec 2024 17:04:55 +0100
Subject: [PATCH 01/51] Ajout de la route pour la page d'accueil

---
 __init__.py | 7 +++++++
 1 file changed, 7 insertions(+)

diff --git a/__init__.py b/__init__.py
index 8ba529a..213b855 100644
--- a/__init__.py
+++ b/__init__.py
@@ -57,6 +57,13 @@ with app.app_context():
         if db is not None:
             app.config['postgreSQL_pool'].putconn(db)
 
+
+#Home page v1
+@app.route('/home_page')
+def home():
+    return render_template('home.html')
+
+
 # Home page
 @app.route('/index')
 def index():
-- 
GitLab


From 439f7dc425461c73ce7756f91d07a5c6509c429d Mon Sep 17 00:00:00 2001
From: "hajar.bouamout" <hajar.bouamout@inrae.fr>
Date: Fri, 20 Dec 2024 17:22:06 +0100
Subject: [PATCH 02/51] =?UTF-8?q?Cr=C3=A9ation=20d'un=20prototype=20HTML?=
 =?UTF-8?q?=20avec=20des=20graphiques=20bas=C3=A9s=20sur=20des=20donn?=
 =?UTF-8?q?=C3=A9es=20fictives,=20=C3=A0=20valider=20par=20les=20utilisate?=
 =?UTF-8?q?urs?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 templates/home.html | 1236 +++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 1236 insertions(+)
 create mode 100644 templates/home.html

diff --git a/templates/home.html b/templates/home.html
new file mode 100644
index 0000000..7a7fbfd
--- /dev/null
+++ b/templates/home.html
@@ -0,0 +1,1236 @@
+{% extends 'main2' %} 
+{% block content %}
+
+<script type="text/javascript">
+  $SCRIPT_ROOT = {{ request.script_root|tojson|safe }};
+</script>
+
+<!-- Descriptive Section -->
+<div style="margin: 80px 0"></div>
+
+<div class="row no-gutters bg-light position-relative align-items-center">
+  <div class="col-12 col-md-9 mb-md-0 p-md-4 align-middle">
+    <h4 class="title">
+      HoloOligo : A Comprehensive Database of Milk Oligosaccharides
+    </h4>
+    <p class="description">
+      The HoloOligo database is a specialized platform that compiles and
+      organizes comprehensive information on milk oligosaccharides across
+      mammalian species. These oligosaccharides, which are complex
+      carbohydrates, play a critical role in biological processes such as infant
+      nutrition, gut health, and immune system modulation. The data included in
+      HoloOligo is automatically extracted from scientific text sources (e.g.,
+      research articles, reviews, and experimental studies) through advanced
+      text-mining techniques. This ensures that the database remains up-to-date
+      and offers a reliable resource for researchers and scientists working in
+      fields such as glycomics, nutrition science, and bioinformatics. The
+      platform provides a search functionality that allows users to efficiently
+      navigate through the dataset, explore specific types of oligosaccharides,
+      identify their biological associations (e.g., species, lactation stages,
+      methodologies), and directly access the sources of information. Whether
+      you are looking to understand the distribution of milk oligosaccharides,
+      analyze their role in mammalian physiology, or explore their potential
+      applications in research and industry, the HoloOligo database serves as a
+      comprehensive and user-friendly resource.
+      <a class="text-info" href="about">Click Here For More information.</a>
+    </p>
+  </div>
+
+  <div class="col-12 col-md-3 position-relative p-4 pl-md-0">
+    <center>
+      <img
+        src="{{ url_for('static', filename='img/logo_Omnicrobe_3_resize.png') }}"
+        alt="Omnicrobe"
+        class="logo"
+      />
+    </center>
+  </div>
+</div>
+
+<!-- Section Data Overview -->
+<section class="data-overview">
+  <h1 class="text-center section-title">HoloOligo Data Overview</h1>
+
+  <!-- Grid for table and charts -->
+<div class="row">
+  <!-- Table of entities and number of occurrences -->
+  <div class="col-12 col-md-4 table-container">
+    <h2>Entities Table</h2>
+    <table id="entitiesTable" class="table table-striped">
+      <thead>
+        <tr>
+          <th>Entity</th>
+          <th>Number of Occurrences</th>
+        </tr>
+      </thead>
+      <tbody id="entitiesTableBody"></tbody>
+    </table>
+  </div>
+
+  <!-- Chart: Distribution of Oligosaccharide Types -->
+  <div class="col-12 col-md-4 chart-container">
+    <h2>Distribution of Oligosaccharide Types</h2>
+    <canvas id="taxonsChart"></canvas>
+  </div>
+
+  <!-- Chart of types by taxon -->
+  <div class="col-12 col-md-4 chart-container">
+    <h2>Explore the oligosaccharide types associated with different taxa</h2>
+    <select id="taxonSelect" class="form-control mb-3">
+      <option value="taxon1">Sus scrofa</option>
+      <option value="taxon2">Homo sapiens</option>
+      <option value="taxon3">Bos taurus</option>
+      <option value="taxon4">Daubentonia madagascariensis</option>
+    </select>
+    <canvas id="taxonOligoChart"></canvas>
+  </div>
+</div>
+
+<!-- Section for additional charts -->
+<section class="additional-graphs">
+  <h1 class="text-center section-title">Other Visualizations</h1>
+  <div class="row">
+    <!-- Chart: Distribution of oligosaccharide types by taxon -->
+    <div class="col-12 col-md-6 chart-container">
+      <h2>Percentage Distribution of Oligosaccharide Types by Taxon</h2>
+      <canvas id="stackedBarChart"></canvas>
+    </div>
+
+    <!-- Chart: Distribution by lactation stage -->
+    <div class="col-12 col-md-6 chart-container">
+      <h2>Distribution of Oligosaccharide Types by Lactation Stage</h2>
+      <canvas id="lactationChart"></canvas>
+    </div>
+  </div>
+</section>
+
+
+
+  <!-- Chart : Taxon - Sample and Sample - Lactation Relationships -->
+  <div class="row">
+    <div class="col-12 col-md-6 chart-container">
+      <h3>Taxon - Sample Relationship</h3>
+      <canvas id="taxonSampleChart"></canvas>
+    </div>
+    <div class="col-12 col-md-6 chart-container">
+      <h3>Sample - Lactation Stage / Oligo Type Relationship</h3>
+      <canvas id="sampleCharacteristicsChart"></canvas>
+    </div>
+  </div>
+
+  <!-- CHart : Sample characteristics charts -->
+  <div>
+    <h1 class="text-center">Sample Characteristics Visualization</h1>
+    <div class="row">
+      <div class="col-12 col-md-6 chart-item">
+        <h2 class="text-center">Milk</h2>
+        <canvas id="milkChart"></canvas>
+      </div>
+      <div class="col-12 col-md-6 chart-item">
+        <h2 class="text-center">Pooled Milk</h2>
+        <canvas id="pooledMilkChart"></canvas>
+      </div>
+    </div>
+  </div>
+
+   <!-- Section for Heatmap and Stacked Bar Chart -->
+<section class="relationship-graphs">
+  <div class="row">
+    <!-- Heatmap Chart: Relationship between lactation stage and taxon -->
+    <div class="col-12 col-md-6 chart-container">
+      <h2>Lactation Stage / Taxon Relationship</h2>
+      <canvas id="heatmapChart"></canvas>
+    </div>
+
+    <!-- Stacked Bar Chart: Relationship between milk and oligosaccharide types -->
+    <div class="col-12 col-md-6 chart-container">
+      <h2>Milk / Oligosaccharide Types Relationship</h2>
+      <canvas id="stackedBarChart2"></canvas>
+    </div>
+  </div>
+</section>
+
+    
+
+        <!-- JavaScript -->
+        <script>
+          document.addEventListener("DOMContentLoaded", function () {
+            const jsonFilePath =
+              '{{ url_for("static", filename="files/data.all.json") }}';
+            // Fetching JSON data
+            fetch(jsonFilePath)
+              .then((response) => response.json())
+              .then((data) => {
+                if (!data.docs) {
+                  throw new Error(
+                    "Le fichier JSON ne contient pas de propriété 'docs'."
+                  );
+                }
+                // Statistics on roles
+                const rolesStats = {};
+                const oligosStats = {
+                  Sialylated: 0,
+                  Neutral: 0,
+                  Fucosylated: 0,
+                  "Type I": 0,
+                  "Type II": 0,
+                };
+
+                // Process each document and their occurrences
+                data.docs.forEach((doc) => {
+                  doc.occurrences.forEach((occurrence) => {
+                    occurrence.relation_occurrences.forEach((relation) => {
+                      relation.args.forEach((arg) => {
+                        // Counting roles
+                        rolesStats[arg.role] = (rolesStats[arg.role] || 0) + 1;
+                      });
+                    });
+                  });
+                });
+
+                // Update entities table
+                const entitiesTableBody =
+                  document.getElementById("entitiesTableBody");
+                Object.keys(rolesStats).forEach((entity) => {
+                  const row = document.createElement("tr");
+                  const cell1 = document.createElement("td");
+                  const cell2 = document.createElement("td");
+                  cell1.textContent = entity;
+                  cell2.textContent = rolesStats[entity];
+                  row.appendChild(cell1);
+                  row.appendChild(cell2);
+                  entitiesTableBody.appendChild(row);
+                });
+              })
+              .catch((error) => {
+                console.error("Error fetching the JSON data:", error);
+              });
+
+            // chart of oligo types per taxon 
+            const chartData = {
+              taxon1: {
+                Sialylated: 1,
+                Neutral: 1,
+                Fucosylated: 1,
+                "Type I": 0,
+                "Type II": 0,
+              },
+              taxon2: {
+                Sialylated: 1,
+                Neutral: 0.5,
+                Fucosylated: 1,
+                "Type I": 1,
+                "Type II": 0,
+              },
+              taxon3: {
+                Sialylated: 1,
+                Neutral: 1,
+                Fucosylated: 1,
+                "Type I": 0,
+                "Type II": 0,
+              },
+              taxon4: {
+                Sialylated: 0.3,
+                Neutral: 0.5,
+                Fucosylated: 0.8,
+                "Type I": 1,
+                "Type II": 0.4,
+              },
+              taxon5: {
+                Sialylated: 1,
+                Neutral: 0,
+                Fucosylated: 1,
+                "Type I": 0,
+                "Type II": 1,
+              },
+            };
+
+            let currentChart = null;
+
+            // Function to create/update chart
+            function createChart(taxon) {
+              const ctx = document
+                .getElementById("taxonOligoChart")
+                .getContext("2d");
+              if (currentChart) currentChart.destroy();
+
+              const data = chartData[taxon];
+              const labels = Object.keys(data);
+              const values = Object.values(data);
+
+              currentChart = new Chart(ctx, {
+                type: "bar",
+                data: {
+                  labels: labels,
+                  datasets: [
+                    {
+                      label: "Presence of Oligosaccharide Types",
+                      data: values,
+                      backgroundColor: [
+                        "#FF6384",
+                        "#36A2EB",
+                        "#FFCE56",
+                        "#4BC0C0",
+                        "#FF9F40",
+                      ],
+                      borderColor: "#ccc",
+                      borderWidth: 1,
+                    },
+                  ],
+                },
+                options: {
+                  responsive: true,
+                  plugins: {
+                    legend: { display: false },
+                    title: {
+                      display: true,
+                      text: "Presence of Oligosaccharide Types",
+                    },
+                  },
+                  scales: {
+                    y: { beginAtZero: true },
+                  },
+                },
+              });
+            }
+
+            // Initialize chart for the selected taxon
+            const taxonSelect = document.getElementById("taxonSelect");
+            createChart(taxonSelect.value);
+
+            // Update chart when a new taxon is selected
+            taxonSelect.addEventListener("change", function () {
+              createChart(this.value);
+            });
+          });
+
+          //type oligo
+
+          document.addEventListener("DOMContentLoaded", function () {
+            // Example data: I should Replace this with actual percentages when available
+            const taxons = [
+              "Sus scrofa",
+              "Homo sapiens",
+              "Bos taurus",
+              "Taxon 4",
+              "Taxon 5",
+            ];
+            const oligoTypes = [
+              "Sialylated",
+              "Neutral",
+              "Fucosylated",
+              "Type I",
+              "Type II",
+            ];
+            const distributionData = [
+              [30, 20, 10, 25, 15], // Sus scrofa
+              [20, 15, 30, 25, 10], // Homo sapiens
+              [25, 20, 15, 10, 30], // Bos taurus
+              [15, 25, 20, 30, 10], // Taxon 4
+              [10, 30, 25, 15, 20], // Taxon 5
+            ];
+
+            const datasets = oligoTypes.map((type, index) => {
+              const colors = [
+                "#FF6384",
+                "#36A2EB",
+                "#FFCE56",
+                "#4BC0C0",
+                "#FF9F40",
+              ];
+              return {
+                label: type,
+                data: distributionData.map((row) => row[index]),
+                backgroundColor: colors[index],
+                borderWidth: 1,
+              };
+            });
+
+            const ctx = document
+              .getElementById("stackedBarChart")
+              .getContext("2d");
+            new Chart(ctx, {
+              type: "bar",
+              data: {
+                labels: taxons,
+                datasets: datasets,
+              },
+              options: {
+                responsive: true,
+                plugins: {
+                  tooltip: {
+                    callbacks: {
+                      label: function (context) {
+                        return `${context.dataset.label}: ${context.raw}%`;
+                      },
+                    },
+                  },
+                  legend: { position: "top" },
+                },
+                scales: {
+                  x: {
+                    stacked: true,
+                    title: {
+                      display: true,
+                      text: "Taxons",
+                    },
+                  },
+                  y: {
+                    stacked: true,
+                    beginAtZero: true,
+                    title: {
+                      display: true,
+                      text: "Percentage",
+                    },
+                  },
+                },
+              },
+            });
+          });
+
+          // Dynamic chart for lactation stages
+          document.addEventListener("DOMContentLoaded", function () {
+            const lactationChartCtx = document
+              .getElementById("lactationChart")
+              .getContext("2d");
+            // data for each lactation stage
+            const lactationData = {
+              labels: [
+                "Colostrum",
+                "Early Lactation",
+                "Farrowing",
+                "Mature Milk",
+                "Mid Lactation",
+                "Transitional Milk",
+                "Weaning",
+              ], // lactation stages (X)
+              datasets: [
+                {
+                  label: "Sialylated",
+                  data: [80, 60, 50, 70, 65, 75, 85],
+                  backgroundColor: "#3E5C76", 
+                  borderColor: "#3E5C76",
+                  borderWidth: 1,
+                },
+                {
+                  label: "Neutral",
+                  data: [50, 70, 60, 80, 70, 65, 60],
+                  backgroundColor: "#7F9BA6", 
+                  borderColor: "#7F9BA6",
+                  borderWidth: 1,
+                },
+                {
+                  label: "Fucosylated",
+                  data: [40, 50, 40, 60, 55, 60, 65],
+                  backgroundColor: "#9A9A9A", 
+                  borderColor: "#9A9A9A",
+                  borderWidth: 1,
+                },
+                {
+                  label: "Type I",
+                  data: [60, 40, 30, 50, 55, 65, 60],
+                  backgroundColor: "#6C8C94", 
+                  borderColor: "#6C8C94",
+                  borderWidth: 1,
+                },
+                {
+                  label: "Type II",
+                  data: [30, 50, 60, 70, 65, 70, 75],
+                  backgroundColor: "#C0A080", 
+                  borderColor: "#C0A080",
+                  borderWidth: 1,
+                },
+              ],
+            };
+            // Create the chart
+            const lactationChart = new Chart(lactationChartCtx, {
+              type: "bar", 
+              data: lactationData,
+              options: {
+                responsive: true,
+                plugins: {
+                  legend: {
+                    position: "top",
+                  },
+                  title: {
+                    display: true,
+                  },
+                },
+                scales: {
+                  x: {
+                    title: {
+                      display: true,
+                      text: "Lactation Stages",
+                    },
+                    grid: {
+                      display: false,
+                    },
+                  },
+                  y: {
+                    beginAtZero: true,
+                    title: {
+                      display: true,
+                      text: "Percentage%",
+                    },
+                    max: 100,
+                  },
+                },
+              },
+            });
+          });
+
+          document.addEventListener("DOMContentLoaded", function () {
+            const speciesChartCtx = document
+              .getElementById("speciesChart")
+              .getContext("2d");
+            const speciesData = {
+              labels: [
+                "Colostrum",
+                "Early Lactation",
+                "Farrowing",
+                "Mature Milk",
+                "Mid Lactation",
+                "Transitional Milk",
+                "Weaning",
+              ],
+              datasets: [
+                {
+                  label: "Species A",
+                  data: [70, 50, 60, 75, 65, 80, 90],
+                  backgroundColor: "#A6D1E6",
+                  borderColor: "#A6D1E6",
+                  borderWidth: 1,
+                },
+                {
+                  label: "Species B",
+                  data: [55, 65, 70, 80, 70, 60, 50],
+                  backgroundColor: "#B6D7A8",
+                  borderColor: "#B6D7A8",
+                  borderWidth: 1,
+                },
+                {
+                  label: "Species C",
+                  data: [40, 60, 50, 65, 60, 75, 85],
+                  backgroundColor: "#F9CB9C",
+                  borderColor: "#F9CB9C",
+                  borderWidth: 1,
+                },
+              ],
+            };
+            const speciesChart = new Chart(speciesChartCtx, {
+              type: "bar",
+              data: speciesData,
+              options: {
+                responsive: true,
+                plugins: {
+                  legend: {
+                    position: "top",
+                  },
+                  title: {
+                    display: true,
+                    text: "Oligosaccharides per Species at Different Lactation Stages",
+                  },
+                },
+                scales: {
+                  x: {
+                    title: {
+                      display: true,
+                      text: "Lactation Stages",
+                    },
+                    grid: {
+                      display: false,
+                    },
+                  },
+                  y: {
+                    beginAtZero: true,
+                    title: {
+                      display: true,
+                      text: "Percentage%",
+                    },
+                    max: 100,
+                  },
+                },
+              },
+            });
+          });
+
+          document.addEventListener("DOMContentLoaded", function () {
+            // lactation stages chart
+            const lactationChartCtx = document
+              .getElementById("lactationChart")
+              .getContext("2d");
+            const lactationData = {
+              labels: [
+                "Colostrum",
+                "Early Lactation",
+                "Farrowing",
+                "Mature Milk",
+                "Mid Lactation",
+                "Transitional Milk",
+                "Weaning",
+              ],
+              datasets: [
+                {
+                  label: "Sialylated",
+                  data: [80, 60, 50, 70, 65, 75, 85],
+                  backgroundColor: "#3E5C76",
+                  borderColor: "#3E5C76",
+                  borderWidth: 1,
+                },
+                {
+                  label: "Neutral",
+                  data: [50, 70, 60, 80, 70, 65, 60],
+                  backgroundColor: "#7F9BA6",
+                  borderColor: "#7F9BA6",
+                  borderWidth: 1,
+                },
+                {
+                  label: "Fucosylated",
+                  data: [40, 50, 40, 60, 55, 60, 65],
+                  backgroundColor: "#9A9A9A",
+                  borderColor: "#9A9A9A",
+                  borderWidth: 1,
+                },
+                {
+                  label: "Type I",
+                  data: [60, 40, 30, 50, 55, 65, 60],
+                  backgroundColor: "#6C8C94",
+                  borderColor: "#6C8C94",
+                  borderWidth: 1,
+                },
+                {
+                  label: "Type II",
+                  data: [30, 50, 60, 70, 65, 70, 75],
+                  backgroundColor: "#C0A080",
+                  borderColor: "#C0A080",
+                  borderWidth: 1,
+                },
+              ],
+            };
+            const lactationChart = new Chart(lactationChartCtx, {
+              type: "bar",
+              data: lactationData,
+              options: {
+                responsive: true,
+                plugins: {
+                  legend: { position: "top" },
+                  title: {
+                    display: true,
+                    text: "Oligosaccharides by Lactation Stage",
+                  },
+                },
+                scales: {
+                  x: {
+                    title: { display: true, text: "Lactation Stages" },
+                    grid: { display: false },
+                  },
+                  y: {
+                    beginAtZero: true,
+                    title: { display: true, text: "Percentage%" },
+                    max: 100,
+                  },
+                },
+              },
+            });
+            // taxon's chart
+            const speciesChartCtx2 = document
+              .getElementById("speciesChart2")
+              .getContext("2d");
+            const speciesData = {
+              labels: [
+                "Colostrum",
+                "Early Lactation",
+                "Farrowing",
+                "Mature Milk",
+                "Mid Lactation",
+                "Transitional Milk",
+                "Weaning",
+              ],
+              datasets: [
+                {
+                  label: "Species A",
+                  data: [70, 50, 60, 75, 65, 80, 90],
+                  backgroundColor: "#A6D1E6",
+                  borderColor: "#A6D1E6",
+                  borderWidth: 1,
+                },
+                {
+                  label: "Species B",
+                  data: [55, 65, 70, 80, 70, 60, 50],
+                  backgroundColor: "#B6D7A8",
+                  borderColor: "#B6D7A8",
+                  borderWidth: 1,
+                },
+                {
+                  label: "Species C",
+                  data: [40, 60, 50, 65, 60, 75, 85],
+                  backgroundColor: "#F9CB9C",
+                  borderColor: "#F9CB9C",
+                  borderWidth: 1,
+                },
+              ],
+            };
+            const speciesChart2 = new Chart(speciesChartCtx2, {
+              type: "bar",
+              data: speciesData,
+              options: {
+                responsive: true,
+                plugins: {
+                  legend: { position: "top" },
+                  title: { display: true, text: "Oligosaccharides by Species" },
+                },
+                scales: {
+                  x: {
+                    title: { display: true, text: "Lactation Stages" },
+                    grid: { display: false },
+                  },
+                  y: {
+                    beginAtZero: true,
+                    title: { display: true, text: "Percentage%" },
+                    max: 100,
+                  },
+                },
+              },
+            });
+          });
+
+          // Distribution of samples per taxons
+          const taxonSampleCtx = document
+            .getElementById("taxonSampleChart")
+            .getContext("2d");
+          const taxonSampleChart = new Chart(taxonSampleCtx, {
+            type: "bar",
+            data: {
+              labels: [
+                "Sus scrofa",
+                "Homo sapiens",
+                "Bos taurus",
+                "Capra hircus",
+                "Elephas maximus",
+              ],
+              datasets: [
+                {
+                  label: "Milk",
+                  data: [0.5, 0.9, 0.2, 1, 0.7], // just for example
+                  backgroundColor: "rgba(54, 162, 235, 0.7)",
+                  borderColor: "rgba(54, 162, 235, 1)",
+                  borderWidth: 1,
+                },
+                {
+                  label: "Pooled Milk",
+                  data: [1, 0.6, 0.2, 0.5, 0.4],
+                  backgroundColor: "rgba(255, 99, 132, 0.7)",
+                  borderColor: "rgba(255, 99, 132, 1)",
+                  borderWidth: 1,
+                },
+              ],
+            },
+            options: {
+              responsive: true,
+              plugins: {
+                legend: {
+                  position: "top",
+                  labels: {
+                    boxWidth: 20,
+                    padding: 15,
+                  },
+                },
+              },
+              scales: {
+                x: {
+                  title: {
+                    display: true,
+                    text: "Taxons",
+                    font: {
+                      weight: "bold",
+                      size: 14,
+                    },
+                  },
+                  grid: {
+                    display: false,
+                  },
+                },
+                y: {
+                  title: {
+                    display: true,
+                    text: "Sample Quantity",
+                    font: {
+                      weight: "bold",
+                      size: 14,
+                    },
+                  },
+                  beginAtZero: true,
+                  grid: {
+                    color: "#e0e0e0",
+                  },
+                },
+              },
+            },
+          });
+
+          const sampleCharacteristicsCtx = document
+            .getElementById("sampleCharacteristicsChart")
+            .getContext("2d");
+          const sampleCharacteristicsChart = new Chart(
+            sampleCharacteristicsCtx,
+            {
+              type: "bar",
+              data: {
+                labels: [
+                  "Colostrum",
+                  "Early Lactation",
+                  "Farrowing",
+                  "Mature Milk",
+                  "Mid Lactation",
+                  "Transitional Milk",
+                  "Weaning",
+                ],
+                datasets: [
+                  {
+                    label: "Milk - Fucosylated Oligo",
+                    data: [0.9, 0.7, 0.5, 0.6, 0.8, 0.9, 0.4],
+                    backgroundColor: "rgba(33, 150, 243, 0.7)", 
+                    borderColor: "rgba(33, 150, 243, 1)",
+                    borderWidth: 1,
+                  },
+                  {
+                    label: "Pooled Milk - Fucosylated Oligo",
+                    data: [0.8, 0.6, 0.4, 0.7, 0.7, 0.8, 0.5],
+                    backgroundColor: "rgba(33, 150, 243, 0.4)", 
+                    borderColor: "rgba(33, 150, 243, 1)",
+                    borderWidth: 1,
+                  },
+                  {
+                    label: "Milk - Sialylated Oligo",
+                    data: [0.8, 0.5, 0.7, 0.6, 0.9, 0.6, 0.5],
+                    backgroundColor: "rgba(76, 175, 80, 0.7)", 
+                    borderColor: "rgba(76, 175, 80, 1)",
+                    borderWidth: 1,
+                  },
+                  {
+                    label: "Pooled Milk - Sialylated Oligo",
+                    data: [0.7, 0.4, 0.6, 0.5, 0.8, 0.7, 0.4],
+                    backgroundColor: "rgba(76, 175, 80, 0.4)",
+                    borderColor: "rgba(76, 175, 80, 1)",
+                    borderWidth: 1,
+                  },
+                  {
+                    label: "Milk - Type I Oligo",
+                    data: [0.6, 0.8, 0.4, 0.7, 0.5, 0.6, 0.7],
+                    backgroundColor: "rgba(244, 67, 54, 0.7)", 
+                    borderColor: "rgba(244, 67, 54, 1)",
+                    borderWidth: 1,
+                  },
+                  {
+                    label: "Pooled Milk - Type I Oligo",
+                    data: [0.5, 0.7, 0.3, 0.6, 0.6, 0.5, 0.6],
+                    backgroundColor: "rgba(244, 67, 54, 0.4)",
+                    borderColor: "rgba(244, 67, 54, 1)",
+                    borderWidth: 1,
+                  },
+                  {
+                    label: "Milk - Type II Oligo",
+                    data: [0.4, 0.6, 0.3, 0.5, 0.7, 0.8, 0.6],
+                    backgroundColor: "rgba(255, 193, 7, 0.7)", 
+                    borderColor: "rgba(255, 193, 7, 1)",
+                    borderWidth: 1,
+                  },
+                  {
+                    label: "Pooled Milk - Type II Oligo",
+                    data: [0.3, 0.5, 0.2, 0.4, 0.6, 0.7, 0.5],
+                    backgroundColor: "rgba(255, 193, 7, 0.4)",
+                    borderColor: "rgba(255, 193, 7, 1)",
+                    borderWidth: 1,
+                  },
+                  {
+                    label: "Milk - Neutral Oligo",
+                    data: [0.7, 0.6, 0.5, 0.7, 0.8, 0.5, 0.7],
+                    backgroundColor: "rgba(121, 85, 72, 0.7)", 
+                    borderColor: "rgba(121, 85, 72, 1)",
+                    borderWidth: 1,
+                  },
+                  {
+                    label: "Pooled Milk - Neutral Oligo",
+                    data: [0.6, 0.5, 0.4, 0.6, 0.7, 0.6, 0.6],
+                    backgroundColor: "rgba(121, 85, 72, 0.4)",
+                    borderColor: "rgba(121, 85, 72, 1)",
+                    borderWidth: 1,
+                  },
+                ],
+              },
+              options: {
+                responsive: true,
+                plugins: {
+                  legend: {
+                    position: "top",
+                    labels: {
+                      boxWidth: 20,
+                      padding: 15,
+                      font: {
+                        size: 12,
+                      },
+                    },
+                  },
+                },
+                scales: {
+                  x: {
+                    title: {
+                      display: true,
+                      text: "Stages of Lactation",
+                      font: {
+                        weight: "bold",
+                        size: 14,
+                      },
+                    },
+                    grid: {
+                      display: false,
+                    },
+                  },
+                  y: {
+                    title: {
+                      display: true,
+                      text: "Presence / Integrity",
+                      font: {
+                        weight: "bold",
+                        size: 14,
+                      },
+                    },
+                    beginAtZero: true,
+                    grid: {
+                      color: "#e0e0e0",
+                    },
+                  },
+                },
+              },
+            }
+          );
+
+          // Distribution of taxons
+          const taxonsCtx = document
+            .getElementById("taxonsChart")
+            .getContext("2d");
+          const taxonsChart = new Chart(taxonsCtx, {
+            type: "pie",
+            data: {
+              labels: [
+                "Neutral",
+                "Fucosylated",
+                "Sialylated",
+                "Type I",
+                "Type II",
+              ], // we raplace here with real names of taxons 
+              datasets: [
+                {
+                  label: "Number of occurrences",
+                  data: [30, 25, 20, 15, 10], // we replace here with real data
+                  backgroundColor: [
+                    "#4E79A7",
+                    "#F28E2B",
+                    "#E15759",
+                    "#76B7B2",
+                    "#59A14F",
+                  ],
+                  borderColor: "#ffffff",
+                  borderWidth: 2,
+                },
+              ],
+            },
+            options: {
+              responsive: true,
+              plugins: {
+                legend: {
+                  position: "top",
+                  labels: {
+                    font: {
+                      size: 14,
+                    },
+                  },
+                },
+              },
+            },
+          });
+
+          
+
+          const labels = [
+            "Colostrum",
+            "Early Lactation",
+            "Farrowing",
+            "Mature Milk",
+            "Mid Lactation",
+            "Transitional Milk",
+            "Weaning",
+          ];
+
+          // Milk chart
+          const milkCtx = document.getElementById("milkChart").getContext("2d");
+          const milkChart = new Chart(milkCtx, {
+            type: "bar",
+            data: {
+              labels: labels,
+              datasets: [
+                {
+                  label: "Fucosylated Oligo",
+                  data: [0.9, 0.7, 0.5, 0.6, 0.8, 0.9, 0.4],
+                  backgroundColor: "rgba(0, 123, 255, 0.7)", 
+                  borderColor: "rgba(0, 123, 255, 1)", 
+                  borderWidth: 1,
+                },
+                {
+                  label: "Sialylated Oligo",
+                  data: [0.8, 0.5, 0.7, 0.6, 0.9, 0.6, 0.5],
+                  backgroundColor: "rgba(40, 167, 69, 0.7)", 
+                  borderColor: "rgba(40, 167, 69, 1)", 
+                  borderWidth: 1,
+                },
+                {
+                  label: "Type I Oligo",
+                  data: [0.6, 0.8, 0.4, 0.7, 0.5, 0.6, 0.7],
+                  backgroundColor: "rgba(255, 193, 7, 0.7)", 
+                  borderColor: "rgba(255, 193, 7, 1)",
+                  borderWidth: 1,
+                },
+                {
+                  label: "Type II Oligo",
+                  data: [0.4, 0.6, 0.3, 0.5, 0.7, 0.8, 0.6],
+                  backgroundColor: "rgba(23, 162, 184, 0.7)", 
+                  borderColor: "rgba(23, 162, 184, 1)",
+                  borderWidth: 1,
+                },
+                {
+                  label: "Neutral Oligo",
+                  data: [0.7, 0.6, 0.5, 0.7, 0.8, 0.5, 0.7],
+                  backgroundColor: "rgba(108, 117, 125, 0.7)", 
+                  borderColor: "rgba(108, 117, 125, 1)", 
+                  borderWidth: 1,
+                },
+              ],
+            },
+            options: {
+              responsive: true,
+              plugins: {
+                legend: { position: "top" },
+              },
+              scales: {
+                x: { title: { display: true, text: "Stages of Lactation" } },
+                y: {
+                  beginAtZero: true,
+                  title: { display: true, text: "Presence / Integrity" },
+                },
+              },
+            },
+          });
+
+          // Pooled Milk chart
+          const pooledMilkCtx = document
+            .getElementById("pooledMilkChart")
+            .getContext("2d");
+          const pooledMilkChart = new Chart(pooledMilkCtx, {
+            type: "bar",
+            data: {
+              labels: labels,
+              datasets: [
+                {
+                  label: "Fucosylated Oligo",
+                  data: [0.8, 0.6, 0.4, 0.7, 0.7, 0.8, 0.5],
+                  backgroundColor: "rgba(0, 123, 255, 0.4)", 
+                  borderColor: "rgba(0, 123, 255, 1)", 
+                  borderWidth: 1,
+                },
+                {
+                  label: "Sialylated Oligo",
+                  data: [0.7, 0.4, 0.6, 0.5, 0.8, 0.7, 0.4],
+                  backgroundColor: "rgba(40, 167, 69, 0.4)", 
+                  borderColor: "rgba(40, 167, 69, 1)", 
+                  borderWidth: 1,
+                },
+                {
+                  label: "Type I Oligo",
+                  data: [0.5, 0.7, 0.3, 0.6, 0.6, 0.5, 0.6],
+                  backgroundColor: "rgba(255, 193, 7, 0.4)", 
+                  borderColor: "rgba(255, 193, 7, 1)", 
+                  borderWidth: 1,
+                },
+                {
+                  label: "Type II Oligo",
+                  data: [0.3, 0.5, 0.2, 0.4, 0.6, 0.7, 0.5],
+                  backgroundColor: "rgba(23, 162, 184, 0.4)", 
+                  borderColor: "rgba(23, 162, 184, 1)", 
+                  borderWidth: 1,
+                },
+                {
+                  label: "Neutral Oligo",
+                  data: [0.6, 0.5, 0.4, 0.6, 0.7, 0.6, 0.6],
+                  backgroundColor: "rgba(108, 117, 125, 0.4)", 
+                  borderColor: "rgba(108, 117, 125, 1)", 
+                  borderWidth: 1,
+                },
+              ],
+            },
+            options: {
+              responsive: true,
+              plugins: {
+                legend: { position: "top" },
+              },
+              scales: {
+                x: { title: { display: true, text: "Stages of Lactation" } },
+                y: {
+                  beginAtZero: true,
+                  title: { display: true, text: "Presence / Integrity" },
+                },
+              },
+            },
+          });
+
+          // Heatmap 
+
+          const heatmapData = {
+            labels: [
+              "Colostrum",
+              "Early Lactation",
+              "Farrowing",
+              "Mature Milk",
+              "Mid Lactation",
+              "Transitional Milk",
+              "Weaning",
+            ],
+            datasets: [
+              {
+                label: "Sus scrofa",
+                data: [12, 19, 3, 5, 4, 8, 9],
+                backgroundColor: "rgba(248, 103, 59, 0.7)", 
+              },
+              {
+                label: "Bos taurus",
+                data: [2, 3, 20, 3, 12, 19, 3],
+                backgroundColor: "rgba(69, 139, 223, 0.7)", 
+              },
+              {
+                label: "Homo sapiens",
+                data: [3, 10, 13, 15, 20, 3, 12],
+                backgroundColor: "rgba(88, 214, 141, 0.7)", 
+              },
+              {
+                label: "Taxon 4",
+                data: [12, 19, 3, 5, 4, 8, 9],
+                backgroundColor: "rgba(255, 99, 132, 0.4)", 
+              },
+              {
+                label: "Taxon 5",
+                data: [2, 3, 20, 3, 9, 3, 5],
+                backgroundColor: "rgba(54, 162, 235, 0.4)", 
+              },
+              {
+                label: "Taxon 6",
+                data: [3, 10, 13, 15, 6, 3, 20],
+                backgroundColor: "rgba(75, 192, 192, 0.4)", 
+              },
+            ],
+          };
+
+          const heatmapOptions = {
+            responsive: true,
+            plugins: {
+              legend: {
+                position: "top",
+              },
+              tooltip: {
+                mode: "index",
+                intersect: false,
+                callbacks: {
+                  label: function (tooltipItem) {
+                    return tooltipItem.dataset.label + ": " + tooltipItem.raw; 
+                  },
+                },
+              },
+            },
+            scales: {
+              x: {
+                stacked: true,
+                ticks: {
+                  font: {
+                    size: 14, 
+                  },
+                },
+              },
+              y: {
+                stacked: true,
+                ticks: {
+                  font: {
+                    size: 14, 
+                  },
+                },
+              },
+            },
+          };
+
+          const heatmapCtx = document
+            .getElementById("heatmapChart")
+            .getContext("2d");
+
+          new Chart(heatmapCtx, {
+            type: "bar",
+            data: heatmapData,
+            options: heatmapOptions,
+          });
+
+          // Stacked Bar Chart
+
+          const stackedBarData = {
+            labels: ["Milk", "Polled Milk"],
+            datasets: [
+              {
+                label: "Sialylated",
+                data: [20, 10],
+                backgroundColor: "rgba(246,190,167)",
+              },
+              {
+                label: "Neutral",
+                data: [5, 3],
+                backgroundColor: "rgba(250,207,190)",
+              },
+              {
+                label: "Fucosylated",
+                data: [2, 2],
+                backgroundColor: "rgba(253,220,203)",
+              },
+              {
+                label: "Type I",
+                data: [12, 40],
+                backgroundColor: "rgba(217,211,199)",
+              },
+              {
+                label: "Type II",
+                data: [30, 8],
+                backgroundColor: "rgba(218,217,215)",
+              },
+            ],
+          };
+
+          const stackedBarOptions = {
+            responsive: true,
+            plugins: {
+              legend: { position: "top" },
+            },
+            scales: {
+              x: { stacked: true },
+              y: { stacked: true, beginAtZero: true },
+            },
+          };
+
+          const stackedBarCtx = document
+            .getElementById("stackedBarChart2")
+            .getContext("2d");
+
+          new Chart(stackedBarCtx, {
+            type: "bar",
+            data: stackedBarData,
+            options: stackedBarOptions,
+          });
+        </script>
+
+        {% endblock %}
+      </div>
+    </div>
+  </div>
+</section>
\ No newline at end of file
-- 
GitLab


From a5c78edb561382bfe8fc3657ba037e9ab46697a2 Mon Sep 17 00:00:00 2001
From: "hajar.bouamout" <hajar.bouamout@inrae.fr>
Date: Fri, 20 Dec 2024 17:24:52 +0100
Subject: [PATCH 03/51] =?UTF-8?q?Premi=C3=A8re=20version=20du=20CSS=20pour?=
 =?UTF-8?q?=20la=20pr=C3=A9sentation=20des=20graphiques=20sur=20la=20page?=
 =?UTF-8?q?=20accueil?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 static/css/page_accueil.css | 318 ++++++++++++++++++++++++++++++++++++
 1 file changed, 318 insertions(+)
 create mode 100644 static/css/page_accueil.css

diff --git a/static/css/page_accueil.css b/static/css/page_accueil.css
new file mode 100644
index 0000000..fb80d5a
--- /dev/null
+++ b/static/css/page_accueil.css
@@ -0,0 +1,318 @@
+/* Global Reset and Base Styles */
+* {
+    margin: 0;
+    padding: 0;
+    box-sizing: border-box;
+}
+
+body {
+    font-family: 'Helvetica Neue', Arial, sans-serif;
+    line-height: 1.6;
+    color: #333;
+    background-color: #f8f9fa;
+}
+
+/* Layout Container */
+.container {
+    max-width: 1100px;
+    margin: 0 auto;
+    padding: 0 1.5rem;
+}
+
+/* Header Section */
+.header-section {
+    padding: 2rem 0;
+    background-color: #fff;
+    box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
+}
+
+.title {
+    font-size: 2.5rem;
+    color: #2c3e50;
+    margin-bottom: 1rem;
+    font-weight: 600;
+}
+
+.description {
+    font-size: 1.125rem;
+    color: #576574;
+    margin-bottom: 1.5rem;
+    line-height: 1.8;
+}
+
+/* Logo */
+.logo {
+    max-width: 200px;
+    height: auto;
+    display: block;
+    margin: 0 auto;
+}
+
+/* Data Overview Section */
+.data-overview {
+    padding: 3rem 0;
+}
+
+.section-title {
+    font-size: 2.25rem;
+    color: #2c3e50;
+    margin-bottom: 2.5rem;
+    text-align: center;
+    font-weight: 600;
+}
+
+/* Chart Containers */
+.chart-container {
+    background: #fff;
+    border-radius: 8px;
+    padding: 1.5rem;
+    margin-bottom: 2rem;
+    box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
+}
+
+.chart-container h2 {
+    font-size: 1.5rem;
+    color: #2c3e50;
+    margin-bottom: 1.5rem;
+    font-weight: 500;
+}
+
+/* Table Styles */
+.table-container {
+    background: #fff;
+    border-radius: 8px;
+    padding: 1rem;
+    margin-bottom: 2rem;
+    box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
+    overflow-x: auto;
+}
+
+.table {
+    width: 100%;
+    border-collapse: collapse;
+}
+
+.table th,
+.table td {
+    padding: 0.75rem;
+    border-bottom: 1px solid #669bcf;
+    font-size: 0.875rem;
+}
+
+.table th {
+    background-color: #f8f9fa;
+    font-weight: 600;
+    text-align: left;
+}
+
+.table tr:hover {
+    background-color: #f8f9fa;
+}
+
+/* Form Controls */
+.form-control {
+    width: 100%;
+    padding: 0.75rem;
+    margin-bottom: 1.25rem;
+    border: 1px solid #ced4da;
+    border-radius: 4px;
+    font-size: 1rem;
+}
+
+/* Grid Layout */
+.inline-block {
+    display: grid;
+    grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
+    gap: 2rem;
+    margin-bottom: 2rem;
+}
+
+/* Charts Grid */
+.charts-container {
+    display: grid;
+    grid-template-columns: repeat(auto-fit, minmax(350px, 1fr));
+    gap: 2rem;
+    margin: 2rem 0;
+}
+
+/* Responsive Design */
+@media (max-width: 1200px) {
+    .container {
+        padding: 0 1rem;
+    }
+
+    .title {
+        font-size: 2rem;
+    }
+
+    .section-title {
+        font-size: 2rem;
+    }
+
+    .chart-container h2 {
+        font-size: 1.25rem;
+    }
+}
+
+@media (max-width: 992px) {
+    .container {
+        padding: 0 1rem;
+    }
+
+    .title {
+        font-size: 1.75rem;
+    }
+
+    .section-title {
+        font-size: 1.75rem;
+    }
+
+    .description {
+        font-size: 1rem;
+    }
+
+    .chart-container,
+    .table-container {
+        padding: 1rem;
+    }
+
+    .table th,
+    .table td {
+        padding: 1rem;
+    }
+    
+    .inline-block {
+        grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
+    }
+
+    .charts-container {
+        grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
+    }
+}
+
+@media (max-width: 768px) {
+    .title {
+        font-size: 1.5rem;
+    }
+
+    .section-title {
+        font-size: 1.5rem;
+    }
+
+    .description {
+        font-size: 0.95rem;
+    }
+
+    .chart-container h2 {
+        font-size: 1rem;
+    }
+
+    .inline-block {
+        grid-template-columns: 1fr;
+        gap: 1.5rem;
+    }
+
+    .charts-container {
+        grid-template-columns: 1fr;
+    }
+
+    .form-control {
+        padding: 0.75rem;
+        font-size: 0.9rem;
+    }
+
+    .table th,
+    .table td {
+        padding: 0.75rem;
+    }
+}
+
+/* Small screens (max-width: 480px) */
+@media (max-width: 480px) {
+    .title {
+        font-size: 1.25rem;
+    }
+
+    .description {
+        font-size: 0.875rem;
+    }
+
+    .table th,
+    .table td {
+        padding: 0.5rem;
+    }
+
+    .form-control {
+        padding: 0.75rem;
+        font-size: 0.85rem;
+    }
+
+    .chart-container,
+    .table-container {
+        padding: 0.75rem;
+    }
+
+    .inline-block {
+        grid-template-columns: 1fr;
+    }
+
+    .charts-container {
+        grid-template-columns: 1fr;
+    }
+}
+
+/* Better image scaling for small screens */
+img {
+    max-width: 100%;
+    height: auto;
+}
+
+/* Mobile Menu */
+.menu {
+    display: none;
+}
+
+@media (max-width: 768px) {
+    .menu {
+        display: block;
+        padding: 1rem;
+        background-color: #2c3e50;
+        color: white;
+        border-radius: 8px;
+        cursor: pointer;
+    }
+
+    .menu-items {
+        display: none;
+        flex-direction: column;
+        gap: 1rem;
+    }
+
+    .menu-items.active {
+        display: flex;
+    }
+}
+
+/* Section for the relationship graphs */
+.relationship-graphs {
+    margin-top: 2rem;
+}
+
+.relationship-graphs .row {
+    margin-bottom: 2rem;
+}
+
+.relationship-graphs .chart-container {
+    padding: 1rem;
+    margin-bottom: 1.5rem;
+}
+
+.relationship-graphs .col-12 {
+    margin-bottom: 1rem;
+}
+
+@media (max-width: 768px) {
+    .relationship-graphs .col-md-6 {
+        margin-bottom: 1.5rem;
+    }
+}
-- 
GitLab


From 9cbf79d05ccfd82aab95a4c4dd804201cb0b3e7e Mon Sep 17 00:00:00 2001
From: "hajar.bouamout" <hajar.bouamout@inrae.fr>
Date: Mon, 23 Dec 2024 10:00:23 +0100
Subject: [PATCH 04/51] ajout des dependences chartjs

---
 templates/main2 | 26 +++++++++++++++++++++++++-
 1 file changed, 25 insertions(+), 1 deletion(-)

diff --git a/templates/main2 b/templates/main2
index 55c99cb..abb34c8 100644
--- a/templates/main2
+++ b/templates/main2
@@ -24,6 +24,9 @@
   <link rel="stylesheet" href="{{ url_for('static', filename='css/main.css') }}">
   <link rel="stylesheet" href="https://cdn.datatables.net/buttons/1.6.5/css/buttons.dataTables.min.css" />
   <link rel="stylesheet" href="https://cdn.datatables.net/responsive/2.2.9/css/responsive.dataTables.min.css" />
+  <link rel="stylesheet" href="{{ url_for('static', filename='css/page_accueil.css') }}">
+ 
+
 
   <!-- JS -->
   <script src="https://code.jquery.com/jquery-3.5.1.slim.min.js" integrity="sha384-DfXdz2htPH0lsSSs5nCTpuj/zy4C+OGpamoFVy38MVBnE+IbbVYUew+OrCXaRkfj" crossorigin="anonymous"></script>
@@ -37,7 +40,28 @@
   <script src="https://cdnjs.cloudflare.com/ajax/libs/pdfmake/0.1.53/vfs_fonts.js"></script>
   <script src="https://cdn.datatables.net/buttons/2.0.0/js/buttons.html5.min.js"></script>
   <script src="https://cdn.datatables.net/buttons/2.0.0/js/buttons.colVis.min.js"></script>
-  <script src="https://cdn.datatables.net/responsive/2.2.9/js/dataTables.responsive.min.js"></script>s
+  <script src="https://cdn.datatables.net/responsive/2.2.9/js/dataTables.responsive.min.js"></script>
+  <script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
+  <script src="https://cdn.jsdelivr.net/npm/chartjs-chart-matrix@1.1.0"></script>
+  <script src="https://cdn.jsdelivr.net/npm/chartjs-chart-boxplot@1.0.0/dist/chartjs-chart-boxplot.min.js"></script>
+  <script src="https://cdnjs.cloudflare.com/ajax/libs/chartjs-plugin-datalabels/2.0.0/chartjs-plugin-datalabels.js"></script>
+  <script src="https://unpkg.com/@sgratzl/chartjs-chart-boxplot@3.6.0/build/index.umd.min.js"></script>
+  <script src="js/chartjs-chart-box-and-violin-plot.min.js"></script>
+  
+
+
+  
+ 
+
+
+  
+
+
+
+  
+
+
+
 
   <body>
     <div id="left-div">
-- 
GitLab


From d7cf10c825bdd4d4dc22a14ba3766465c1de9902 Mon Sep 17 00:00:00 2001
From: Sandra Derozier <sandra.derozier@inrae.fr>
Date: Mon, 23 Dec 2024 10:49:05 +0100
Subject: [PATCH 05/51] Ajout Chart.js

---
 templates/main2 | 11 ++++++++++-
 1 file changed, 10 insertions(+), 1 deletion(-)

diff --git a/templates/main2 b/templates/main2
index 55c99cb..21bdf5e 100644
--- a/templates/main2
+++ b/templates/main2
@@ -24,6 +24,7 @@
   <link rel="stylesheet" href="{{ url_for('static', filename='css/main.css') }}">
   <link rel="stylesheet" href="https://cdn.datatables.net/buttons/1.6.5/css/buttons.dataTables.min.css" />
   <link rel="stylesheet" href="https://cdn.datatables.net/responsive/2.2.9/css/responsive.dataTables.min.css" />
+  <link rel="stylesheet" href="{{ url_for('static', filename='css/page_accueil.css') }}">
 
   <!-- JS -->
   <script src="https://code.jquery.com/jquery-3.5.1.slim.min.js" integrity="sha384-DfXdz2htPH0lsSSs5nCTpuj/zy4C+OGpamoFVy38MVBnE+IbbVYUew+OrCXaRkfj" crossorigin="anonymous"></script>
@@ -37,7 +38,15 @@
   <script src="https://cdnjs.cloudflare.com/ajax/libs/pdfmake/0.1.53/vfs_fonts.js"></script>
   <script src="https://cdn.datatables.net/buttons/2.0.0/js/buttons.html5.min.js"></script>
   <script src="https://cdn.datatables.net/buttons/2.0.0/js/buttons.colVis.min.js"></script>
-  <script src="https://cdn.datatables.net/responsive/2.2.9/js/dataTables.responsive.min.js"></script>s
+  <script src="https://cdn.datatables.net/responsive/2.2.9/js/dataTables.responsive.min.js"></script>
+  <script src="https://cdn.datatables.net/responsive/2.2.9/js/dataTables.responsive.min.js"></script>
+  <script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
+  <script src="https://cdn.jsdelivr.net/npm/chartjs-chart-matrix@1.1.0"></script>
+  <script src="https://cdn.jsdelivr.net/npm/chartjs-chart-boxplot@1.0.0/dist/chartjs-chart-boxplot.min.js"></script>
+  <script src="https://cdnjs.cloudflare.com/ajax/libs/chartjs-plugin-datalabels/2.0.0/chartjs-plugin-datalabels.js"></script>
+  <script src="https://unpkg.com/@sgratzl/chartjs-chart-boxplot@3.6.0/build/index.umd.min.js"></script>
+  <script src="js/chartjs-chart-box-and-violin-plot.min.js"></script>
+
 
   <body>
     <div id="left-div">
-- 
GitLab


From a5be02778c4ac885e442cc7e25e885852e1c3099 Mon Sep 17 00:00:00 2001
From: Sandra Derozier <sandra.derozier@inrae.fr>
Date: Mon, 23 Dec 2024 10:49:41 +0100
Subject: [PATCH 06/51] =?UTF-8?q?Ajout=20Requ=C3=AAtes=20DB=20Stat?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 __init__.py |  9 +++++++++
 database.py | 41 +++++++++++++++++++++++++++++++++++++++++
 2 files changed, 50 insertions(+)

diff --git a/__init__.py b/__init__.py
index 213b855..aae643d 100644
--- a/__init__.py
+++ b/__init__.py
@@ -376,6 +376,15 @@ def get_taxid():
     qps = request.args.get('qps', None)
     return(jsonify(list_taxid(app, conn, path, qps)))
 
+# Database queries (V2)
+@app.route('/_get_stat_entity')
+def get_stat_entity():
+    return(jsonify(stat_entity(app, conn)))
+
+@app.route('_get/stat_occurrence')
+def get_stat_occurrence():
+    return(jsonify(stat_occurrence(app, conn)))
+
 # API
 source_choices = ["pubmed", "CIRM-BIA", "CIRM-CFBP", "CIRM-Levures", "dsmz", "genbank"]
 qps_choices = ["yes", "no", "true", "false"]
diff --git a/database.py b/database.py
index 9b7c191..9b9b50e 100644
--- a/database.py
+++ b/database.py
@@ -18,6 +18,7 @@ import psycopg2
 from psycopg2 import pool
 import re
 from omnicrobe_web.config import *
+import json
 
 # Get Database connection
 def get_db(app):
@@ -59,6 +60,46 @@ def get_version(app, conn):
         return dict(zip(columns, cursor.fetchall()[0]))
         cursor.close()
 
+# Get statistics: /get/stat
+def stat_occurrence(app, conn):
+    conn = get_db(app)
+    if conn != None:
+        cursor = conn.cursor()
+        try:
+            cursor.execute("SELECT co_type, count(relation_occurrence.ro_id) \
+                            FROM relation_occurrence, concept_occurrence \
+                            WHERE relation_occurrence.ro_fk_concept_occurrence_id = concept_occurrence.co_id \
+                            GROUP BY concept_occurrence.co_type")
+        except Exception as err:
+            print_psycopg2_exception(err)
+        results = dict()
+        for row in cursor.fetchall():
+            results[row[0]] = row[1]
+        cursor.close()
+        return results
+
+def stat_entity(app, conn):
+    conn = get_db(app)
+    if conn != None:
+        cursor = conn.cursor()
+        try:
+            cursor.execute("SELECT c, sum(n) \
+                            FROM ( \
+                                SELECT co_type c, count(distinct co_fk_concept_id) n \
+                                FROM concept_occurrence GROUP BY co_type \
+                                UNION \
+                                SELECT co_type, count(distinct co_form_concept) \
+                                FROM concept_occurrence WHERE co_fk_concept_id ISNULL \
+                                GROUP BY co_type) \
+                            GROUP BY c")
+        except Exception as err:
+            print_psycopg2_exception(err)
+        results = dict()
+        for row in cursor.fetchall():
+            results[row[0]] = row[1]
+        cursor.close()
+        return results
+
 # Get taxon: /get/taxon
 def get_taxon(app, conn, id):
     conn = get_db(app)
-- 
GitLab


From 18b6dc934673dcae459bd85b81c76a32fad41176 Mon Sep 17 00:00:00 2001
From: Sandra Derozier <sandra.derozier@inrae.fr>
Date: Mon, 23 Dec 2024 11:53:55 +0100
Subject: [PATCH 07/51] =?UTF-8?q?#5=20-=20Ajout=20Requ=C3=AAtes=20DB=20Nb?=
 =?UTF-8?q?=20Occurrence=20par=20Concept?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 __init__.py |  5 +++++
 database.py | 24 ++++++++++++++++++++++--
 2 files changed, 27 insertions(+), 2 deletions(-)

diff --git a/__init__.py b/__init__.py
index aae643d..1dcd4b5 100644
--- a/__init__.py
+++ b/__init__.py
@@ -385,6 +385,11 @@ def get_stat_entity():
 def get_stat_occurrence():
     return(jsonify(stat_occurrence(app, conn)))
 
+@app.route('_get/nb_occ_by_concept')
+def get_nb_occ_by_concept():
+    concept = request.args.get('concept', None) # concept = 'Species' or 'Oligosaccharide_type' 
+    return(jsonify(get_nb_occ_by_concept(app, conn, concept)))
+
 # API
 source_choices = ["pubmed", "CIRM-BIA", "CIRM-CFBP", "CIRM-Levures", "dsmz", "genbank"]
 qps_choices = ["yes", "no", "true", "false"]
diff --git a/database.py b/database.py
index 9b9b50e..874f50a 100644
--- a/database.py
+++ b/database.py
@@ -60,7 +60,7 @@ def get_version(app, conn):
         return dict(zip(columns, cursor.fetchall()[0]))
         cursor.close()
 
-# Get statistics: /get/stat
+# Get statistics: /get/stat*
 def stat_occurrence(app, conn):
     conn = get_db(app)
     if conn != None:
@@ -77,7 +77,7 @@ def stat_occurrence(app, conn):
             results[row[0]] = row[1]
         cursor.close()
         return results
-
+    
 def stat_entity(app, conn):
     conn = get_db(app)
     if conn != None:
@@ -99,6 +99,26 @@ def stat_entity(app, conn):
             results[row[0]] = row[1]
         cursor.close()
         return results
+    
+# Get occurrence number by concept: 
+def get_nb_occ_by_concept(app, conn, concept):
+    conn = get_db(app)
+    if conn != None:
+        cursor = conn.cursor()
+        try:
+            cursor.execute("SELECT cn_name, count(distinct co_id) \
+                            FROM concept_occurrence, concept, concept_name \
+                            WHERE co_type = '%s' \
+                            AND concept_occurrence.co_fk_concept_id = concept.c_id \
+                            AND concept.c_id = concept_name.cn_fk_concept_id \
+                            GROUP BY concept_name.cn_name", (concept,))
+        except Exception as err:
+            print_psycopg2_exception(err)
+        results = dict()
+        for row in cursor.fetchall():
+            results[row[0]] = row[1]
+        cursor.close()
+        return results
 
 # Get taxon: /get/taxon
 def get_taxon(app, conn, id):
-- 
GitLab


From 289007a64e1e77ff4ec0206c13640e7859b7d29a Mon Sep 17 00:00:00 2001
From: Sandra Derozier <sandra.derozier@inrae.fr>
Date: Mon, 23 Dec 2024 12:05:21 +0100
Subject: [PATCH 08/51] Correctif

---
 __init__.py | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/__init__.py b/__init__.py
index 1dcd4b5..fbbb529 100644
--- a/__init__.py
+++ b/__init__.py
@@ -381,11 +381,11 @@ def get_taxid():
 def get_stat_entity():
     return(jsonify(stat_entity(app, conn)))
 
-@app.route('_get/stat_occurrence')
+@app.route('/_get/stat_occurrence')
 def get_stat_occurrence():
     return(jsonify(stat_occurrence(app, conn)))
 
-@app.route('_get/nb_occ_by_concept')
+@app.route('/_get/nb_occ_by_concept')
 def get_nb_occ_by_concept():
     concept = request.args.get('concept', None) # concept = 'Species' or 'Oligosaccharide_type' 
     return(jsonify(get_nb_occ_by_concept(app, conn, concept)))
-- 
GitLab


From 8493c4ba4ff70faecac0033220fe5ec6de6dd591 Mon Sep 17 00:00:00 2001
From: "hajar.bouamout" <hajar.bouamout@inrae.fr>
Date: Mon, 23 Dec 2024 16:25:24 +0100
Subject: [PATCH 09/51] ajout slash route stat_occurence

---
 __init__.py | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/__init__.py b/__init__.py
index aae643d..dda2f29 100644
--- a/__init__.py
+++ b/__init__.py
@@ -381,7 +381,7 @@ def get_taxid():
 def get_stat_entity():
     return(jsonify(stat_entity(app, conn)))
 
-@app.route('_get/stat_occurrence')
+@app.route('/_get/stat_occurrence')
 def get_stat_occurrence():
     return(jsonify(stat_occurrence(app, conn)))
 
-- 
GitLab


From badbfdcc15ff50aa2f6e19e727d77eb7c1f1109b Mon Sep 17 00:00:00 2001
From: "hajar.bouamout" <hajar.bouamout@inrae.fr>
Date: Tue, 24 Dec 2024 15:23:02 +0100
Subject: [PATCH 10/51] =?UTF-8?q?S=C3=A9paration=20HTML/JS=20du=20home=20p?=
 =?UTF-8?q?age,=20remplacement=20des=20donn=C3=A9es=20fictives=20par=20l'A?=
 =?UTF-8?q?PI=20pour=20le=20tableau=20et=20le=20camembert,=20ajustements?=
 =?UTF-8?q?=20SQL=20et=20gestion=20des=20erreurs?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 __init__.py            |   21 +-
 database.py            |    5 +-
 static/js/home_page.js | 1140 ++++++++++++++++++++++++++++++++++++++++
 templates/home.html    | 1081 +------------------------------------
 templates/main2        |    3 +-
 5 files changed, 1168 insertions(+), 1082 deletions(-)
 create mode 100644 static/js/home_page.js

diff --git a/__init__.py b/__init__.py
index fbbb529..07b7240 100644
--- a/__init__.py
+++ b/__init__.py
@@ -385,10 +385,27 @@ def get_stat_entity():
 def get_stat_occurrence():
     return(jsonify(stat_occurrence(app, conn)))
 
+# @app.route('/_get/nb_occ_by_concept')
+# def get_nb_occ_by_concept():
+#     concept = request.args.get('concept', None) # concept = 'Species' or 'Oligosaccharide_type' 
+#     return(jsonify(fetch_nb_occ_by_concept(app, conn, concept)))
 @app.route('/_get/nb_occ_by_concept')
 def get_nb_occ_by_concept():
-    concept = request.args.get('concept', None) # concept = 'Species' or 'Oligosaccharide_type' 
-    return(jsonify(get_nb_occ_by_concept(app, conn, concept)))
+    concept = request.args.get('concept', None)  # Exemple : 'Species' ou 'Oligosaccharide_type'
+    if not concept:
+        return jsonify({"error": "Concept parameter is missing"}), 400
+
+    # Appeler la fonction pour récupérer les données
+    results = fetch_nb_occ_by_concept(app, conn, concept)
+    if "error" in results:
+        return jsonify({"error": "Failed to fetch data", "details": results}), 500
+
+    # Formatage des données pour Chart.js
+    labels = list(results.keys())
+    data = list(results.values())
+
+    return jsonify({"labels": labels, "data": data})
+
 
 # API
 source_choices = ["pubmed", "CIRM-BIA", "CIRM-CFBP", "CIRM-Levures", "dsmz", "genbank"]
diff --git a/database.py b/database.py
index 874f50a..dceb3a2 100644
--- a/database.py
+++ b/database.py
@@ -101,14 +101,14 @@ def stat_entity(app, conn):
         return results
     
 # Get occurrence number by concept: 
-def get_nb_occ_by_concept(app, conn, concept):
+def fetch_nb_occ_by_concept(app, conn, concept):
     conn = get_db(app)
     if conn != None:
         cursor = conn.cursor()
         try:
             cursor.execute("SELECT cn_name, count(distinct co_id) \
                             FROM concept_occurrence, concept, concept_name \
-                            WHERE co_type = '%s' \
+                            WHERE co_type = %s \
                             AND concept_occurrence.co_fk_concept_id = concept.c_id \
                             AND concept.c_id = concept_name.cn_fk_concept_id \
                             GROUP BY concept_name.cn_name", (concept,))
@@ -119,6 +119,7 @@ def get_nb_occ_by_concept(app, conn, concept):
             results[row[0]] = row[1]
         cursor.close()
         return results
+    
 
 # Get taxon: /get/taxon
 def get_taxon(app, conn, id):
diff --git a/static/js/home_page.js b/static/js/home_page.js
new file mode 100644
index 0000000..a20b252
--- /dev/null
+++ b/static/js/home_page.js
@@ -0,0 +1,1140 @@
+//table displaying statistics for each entity
+document.addEventListener("DOMContentLoaded", function () {
+    // The API URL from which we are fetching the JSON data
+    const apiUrl = '/_get/stat_occurrence';
+     
+    // Fetching the JSON data from the API
+    fetch(apiUrl)
+      .then((response) => response.json())  // Convert the API response to JSON
+      .then((data) => {
+
+        // Log the received data to the console for verification
+        console.log("Data received from the API:", data);
+
+        // Check if the data is empty or null
+        if (!data || Object.keys(data).length === 0) {
+          throw new Error("The data from the API is empty or invalid.");
+        }
+        
+        // Initialize an object to store role statistics
+        const rolesStats = {};
+
+        // Iterate over the data and populate the rolesStats object
+        Object.keys(data).forEach((key) => {
+          rolesStats[key] = data[key];  
+        });
+
+        // Get the table body element where we will display the data
+        const entitiesTableBody = document.getElementById("entitiesTableBody");
+
+        // Iterate over the rolesStats object and create table rows for each entity
+        Object.keys(rolesStats).forEach((entity) => {
+          const row = document.createElement("tr");
+          const cell1 = document.createElement("td");
+          const cell2 = document.createElement("td");
+
+           // Set the content of the cells
+          cell1.textContent = entity;
+          cell2.textContent = rolesStats[entity];
+
+          // Append the cells to the row
+          row.appendChild(cell1);
+          row.appendChild(cell2);
+
+          // Append the row to the table body
+          entitiesTableBody.appendChild(row);
+        });
+      })
+      .catch((error) => {
+        console.error("Error fetching the JSON data:", error);
+      });
+
+     
+    // chart of oligo types per taxon 
+
+
+    const chartData = {
+      taxon1: {
+        Sialylated: 1,
+        Neutral: 1,
+        Fucosylated: 1,
+        "Type I": 0,
+        "Type II": 0,
+      },
+      taxon2: {
+        Sialylated: 1,
+        Neutral: 0.5,
+        Fucosylated: 1,
+        "Type I": 1,
+        "Type II": 0,
+      },
+      taxon3: {
+        Sialylated: 1,
+        Neutral: 1,
+        Fucosylated: 1,
+        "Type I": 0,
+        "Type II": 0,
+      },
+      taxon4: {
+        Sialylated: 0.3,
+        Neutral: 0.5,
+        Fucosylated: 0.8,
+        "Type I": 1,
+        "Type II": 0.4,
+      },
+      taxon5: {
+        Sialylated: 1,
+        Neutral: 0,
+        Fucosylated: 1,
+        "Type I": 0,
+        "Type II": 1,
+      },
+    };
+
+    let currentChart = null;
+
+    // Function to create/update chart
+    function createChart(taxon) {
+      const ctx = document
+        .getElementById("taxonOligoChart")
+        .getContext("2d");
+      if (currentChart) currentChart.destroy();
+
+      const data = chartData[taxon];
+      const labels = Object.keys(data);
+      const values = Object.values(data);
+
+      currentChart = new Chart(ctx, {
+        type: "bar",
+        data: {
+          labels: labels,
+          datasets: [
+            {
+              label: "Presence of Oligosaccharide Types",
+              data: values,
+              backgroundColor: [
+                "#FF6384",
+                "#36A2EB",
+                "#FFCE56",
+                "#4BC0C0",
+                "#FF9F40",
+              ],
+              borderColor: "#ccc",
+              borderWidth: 1,
+            },
+          ],
+        },
+        options: {
+          responsive: true,
+          plugins: {
+            legend: { display: false },
+            title: {
+              display: true,
+              text: "Presence of Oligosaccharide Types",
+            },
+          },
+          scales: {
+            y: { beginAtZero: true },
+          },
+        },
+      });
+    }
+
+    // Initialize chart for the selected taxon
+    const taxonSelect = document.getElementById("taxonSelect");
+    createChart(taxonSelect.value);
+
+    // Update chart when a new taxon is selected
+    taxonSelect.addEventListener("change", function () {
+      createChart(this.value);
+    });
+  });
+
+  //type oligo
+
+  document.addEventListener("DOMContentLoaded", function () {
+    // Example data: I should Replace this with actual percentages when available
+    const taxons = [
+      "Sus scrofa",
+      "Homo sapiens",
+      "Bos taurus",
+      "Taxon 4",
+      "Taxon 5",
+    ];
+    const oligoTypes = [
+      "Sialylated",
+      "Neutral",
+      "Fucosylated",
+      "Type I",
+      "Type II",
+    ];
+    const distributionData = [
+      [30, 20, 10, 25, 15], // Sus scrofa
+      [20, 15, 30, 25, 10], // Homo sapiens
+      [25, 20, 15, 10, 30], // Bos taurus
+      [15, 25, 20, 30, 10], // Taxon 4
+      [10, 30, 25, 15, 20], // Taxon 5
+    ];
+
+    const datasets = oligoTypes.map((type, index) => {
+      const colors = [
+        "#FF6384",
+        "#36A2EB",
+        "#FFCE56",
+        "#4BC0C0",
+        "#FF9F40",
+      ];
+      return {
+        label: type,
+        data: distributionData.map((row) => row[index]),
+        backgroundColor: colors[index],
+        borderWidth: 1,
+      };
+    });
+
+    const ctx = document
+      .getElementById("stackedBarChart")
+      .getContext("2d");
+    new Chart(ctx, {
+      type: "bar",
+      data: {
+        labels: taxons,
+        datasets: datasets,
+      },
+      options: {
+        responsive: true,
+        plugins: {
+          tooltip: {
+            callbacks: {
+              label: function (context) {
+                return `${context.dataset.label}: ${context.raw}%`;
+              },
+            },
+          },
+          legend: { position: "top" },
+        },
+        scales: {
+          x: {
+            stacked: true,
+            title: {
+              display: true,
+              text: "Taxons",
+            },
+          },
+          y: {
+            stacked: true,
+            beginAtZero: true,
+            title: {
+              display: true,
+              text: "Percentage",
+            },
+          },
+        },
+      },
+    });
+  });
+
+  // Dynamic chart for lactation stages
+  document.addEventListener("DOMContentLoaded", function () {
+    const lactationChartCtx = document
+      .getElementById("lactationChart")
+      .getContext("2d");
+    // data for each lactation stage
+    const lactationData = {
+      labels: [
+        "Colostrum",
+        "Early Lactation",
+        "Farrowing",
+        "Mature Milk",
+        "Mid Lactation",
+        "Transitional Milk",
+        "Weaning",
+      ], // lactation stages (X)
+      datasets: [
+        {
+          label: "Sialylated",
+          data: [80, 60, 50, 70, 65, 75, 85],
+          backgroundColor: "#3E5C76", 
+          borderColor: "#3E5C76",
+          borderWidth: 1,
+        },
+        {
+          label: "Neutral",
+          data: [50, 70, 60, 80, 70, 65, 60],
+          backgroundColor: "#7F9BA6", 
+          borderColor: "#7F9BA6",
+          borderWidth: 1,
+        },
+        {
+          label: "Fucosylated",
+          data: [40, 50, 40, 60, 55, 60, 65],
+          backgroundColor: "#9A9A9A", 
+          borderColor: "#9A9A9A",
+          borderWidth: 1,
+        },
+        {
+          label: "Type I",
+          data: [60, 40, 30, 50, 55, 65, 60],
+          backgroundColor: "#6C8C94", 
+          borderColor: "#6C8C94",
+          borderWidth: 1,
+        },
+        {
+          label: "Type II",
+          data: [30, 50, 60, 70, 65, 70, 75],
+          backgroundColor: "#C0A080", 
+          borderColor: "#C0A080",
+          borderWidth: 1,
+        },
+      ],
+    };
+    // Create the chart
+    const lactationChart = new Chart(lactationChartCtx, {
+      type: "bar", 
+      data: lactationData,
+      options: {
+        responsive: true,
+        plugins: {
+          legend: {
+            position: "top",
+          },
+          title: {
+            display: true,
+          },
+        },
+        scales: {
+          x: {
+            title: {
+              display: true,
+              text: "Lactation Stages",
+            },
+            grid: {
+              display: false,
+            },
+          },
+          y: {
+            beginAtZero: true,
+            title: {
+              display: true,
+              text: "Percentage%",
+            },
+            max: 100,
+          },
+        },
+      },
+    });
+  });
+
+  document.addEventListener("DOMContentLoaded", function () {
+    const speciesChartCtx = document
+      .getElementById("speciesChart")
+      .getContext("2d");
+    const speciesData = {
+      labels: [
+        "Colostrum",
+        "Early Lactation",
+        "Farrowing",
+        "Mature Milk",
+        "Mid Lactation",
+        "Transitional Milk",
+        "Weaning",
+      ],
+      datasets: [
+        {
+          label: "Species A",
+          data: [70, 50, 60, 75, 65, 80, 90],
+          backgroundColor: "#A6D1E6",
+          borderColor: "#A6D1E6",
+          borderWidth: 1,
+        },
+        {
+          label: "Species B",
+          data: [55, 65, 70, 80, 70, 60, 50],
+          backgroundColor: "#B6D7A8",
+          borderColor: "#B6D7A8",
+          borderWidth: 1,
+        },
+        {
+          label: "Species C",
+          data: [40, 60, 50, 65, 60, 75, 85],
+          backgroundColor: "#F9CB9C",
+          borderColor: "#F9CB9C",
+          borderWidth: 1,
+        },
+      ],
+    };
+    const speciesChart = new Chart(speciesChartCtx, {
+      type: "bar",
+      data: speciesData,
+      options: {
+        responsive: true,
+        plugins: {
+          legend: {
+            position: "top",
+          },
+          title: {
+            display: true,
+            text: "Oligosaccharides per Species at Different Lactation Stages",
+          },
+        },
+        scales: {
+          x: {
+            title: {
+              display: true,
+              text: "Lactation Stages",
+            },
+            grid: {
+              display: false,
+            },
+          },
+          y: {
+            beginAtZero: true,
+            title: {
+              display: true,
+              text: "Percentage%",
+            },
+            max: 100,
+          },
+        },
+      },
+    });
+  });
+
+  document.addEventListener("DOMContentLoaded", function () {
+    // lactation stages chart
+    const lactationChartCtx = document
+      .getElementById("lactationChart")
+      .getContext("2d");
+    const lactationData = {
+      labels: [
+        "Colostrum",
+        "Early Lactation",
+        "Farrowing",
+        "Mature Milk",
+        "Mid Lactation",
+        "Transitional Milk",
+        "Weaning",
+      ],
+      datasets: [
+        {
+          label: "Sialylated",
+          data: [80, 60, 50, 70, 65, 75, 85],
+          backgroundColor: "#3E5C76",
+          borderColor: "#3E5C76",
+          borderWidth: 1,
+        },
+        {
+          label: "Neutral",
+          data: [50, 70, 60, 80, 70, 65, 60],
+          backgroundColor: "#7F9BA6",
+          borderColor: "#7F9BA6",
+          borderWidth: 1,
+        },
+        {
+          label: "Fucosylated",
+          data: [40, 50, 40, 60, 55, 60, 65],
+          backgroundColor: "#9A9A9A",
+          borderColor: "#9A9A9A",
+          borderWidth: 1,
+        },
+        {
+          label: "Type I",
+          data: [60, 40, 30, 50, 55, 65, 60],
+          backgroundColor: "#6C8C94",
+          borderColor: "#6C8C94",
+          borderWidth: 1,
+        },
+        {
+          label: "Type II",
+          data: [30, 50, 60, 70, 65, 70, 75],
+          backgroundColor: "#C0A080",
+          borderColor: "#C0A080",
+          borderWidth: 1,
+        },
+      ],
+    };
+    const lactationChart = new Chart(lactationChartCtx, {
+      type: "bar",
+      data: lactationData,
+      options: {
+        responsive: true,
+        plugins: {
+          legend: { position: "top" },
+          title: {
+            display: true,
+            text: "Oligosaccharides by Lactation Stage",
+          },
+        },
+        scales: {
+          x: {
+            title: { display: true, text: "Lactation Stages" },
+            grid: { display: false },
+          },
+          y: {
+            beginAtZero: true,
+            title: { display: true, text: "Percentage%" },
+            max: 100,
+          },
+        },
+      },
+    });
+    // taxon's chart
+    const speciesChartCtx2 = document
+      .getElementById("speciesChart2")
+      .getContext("2d");
+    const speciesData = {
+      labels: [
+        "Colostrum",
+        "Early Lactation",
+        "Farrowing",
+        "Mature Milk",
+        "Mid Lactation",
+        "Transitional Milk",
+        "Weaning",
+      ],
+      datasets: [
+        {
+          label: "Species A",
+          data: [70, 50, 60, 75, 65, 80, 90],
+          backgroundColor: "#A6D1E6",
+          borderColor: "#A6D1E6",
+          borderWidth: 1,
+        },
+        {
+          label: "Species B",
+          data: [55, 65, 70, 80, 70, 60, 50],
+          backgroundColor: "#B6D7A8",
+          borderColor: "#B6D7A8",
+          borderWidth: 1,
+        },
+        {
+          label: "Species C",
+          data: [40, 60, 50, 65, 60, 75, 85],
+          backgroundColor: "#F9CB9C",
+          borderColor: "#F9CB9C",
+          borderWidth: 1,
+        },
+      ],
+    };
+    const speciesChart2 = new Chart(speciesChartCtx2, {
+      type: "bar",
+      data: speciesData,
+      options: {
+        responsive: true,
+        plugins: {
+          legend: { position: "top" },
+          title: { display: true, text: "Oligosaccharides by Species" },
+        },
+        scales: {
+          x: {
+            title: { display: true, text: "Lactation Stages" },
+            grid: { display: false },
+          },
+          y: {
+            beginAtZero: true,
+            title: { display: true, text: "Percentage%" },
+            max: 100,
+          },
+        },
+      },
+    });
+  });
+
+  // Distribution of samples per taxons
+  const taxonSampleCtx = document
+    .getElementById("taxonSampleChart")
+    .getContext("2d");
+  const taxonSampleChart = new Chart(taxonSampleCtx, {
+    type: "bar",
+    data: {
+      labels: [
+        "Sus scrofa",
+        "Homo sapiens",
+        "Bos taurus",
+        "Capra hircus",
+        "Elephas maximus",
+      ],
+      datasets: [
+        {
+          label: "Milk",
+          data: [0.5, 0.9, 0.2, 1, 0.7], // just for example
+          backgroundColor: "rgba(54, 162, 235, 0.7)",
+          borderColor: "rgba(54, 162, 235, 1)",
+          borderWidth: 1,
+        },
+        {
+          label: "Pooled Milk",
+          data: [1, 0.6, 0.2, 0.5, 0.4],
+          backgroundColor: "rgba(255, 99, 132, 0.7)",
+          borderColor: "rgba(255, 99, 132, 1)",
+          borderWidth: 1,
+        },
+      ],
+    },
+    options: {
+      responsive: true,
+      plugins: {
+        legend: {
+          position: "top",
+          labels: {
+            boxWidth: 20,
+            padding: 15,
+          },
+        },
+      },
+      scales: {
+        x: {
+          title: {
+            display: true,
+            text: "Taxons",
+            font: {
+              weight: "bold",
+              size: 14,
+            },
+          },
+          grid: {
+            display: false,
+          },
+        },
+        y: {
+          title: {
+            display: true,
+            text: "Sample Quantity",
+            font: {
+              weight: "bold",
+              size: 14,
+            },
+          },
+          beginAtZero: true,
+          grid: {
+            color: "#e0e0e0",
+          },
+        },
+      },
+    },
+  });
+
+  const sampleCharacteristicsCtx = document
+    .getElementById("sampleCharacteristicsChart")
+    .getContext("2d");
+  const sampleCharacteristicsChart = new Chart(
+    sampleCharacteristicsCtx,
+    {
+      type: "bar",
+      data: {
+        labels: [
+          "Colostrum",
+          "Early Lactation",
+          "Farrowing",
+          "Mature Milk",
+          "Mid Lactation",
+          "Transitional Milk",
+          "Weaning",
+        ],
+        datasets: [
+          {
+            label: "Milk - Fucosylated Oligo",
+            data: [0.9, 0.7, 0.5, 0.6, 0.8, 0.9, 0.4],
+            backgroundColor: "rgba(33, 150, 243, 0.7)", 
+            borderColor: "rgba(33, 150, 243, 1)",
+            borderWidth: 1,
+          },
+          {
+            label: "Pooled Milk - Fucosylated Oligo",
+            data: [0.8, 0.6, 0.4, 0.7, 0.7, 0.8, 0.5],
+            backgroundColor: "rgba(33, 150, 243, 0.4)", 
+            borderColor: "rgba(33, 150, 243, 1)",
+            borderWidth: 1,
+          },
+          {
+            label: "Milk - Sialylated Oligo",
+            data: [0.8, 0.5, 0.7, 0.6, 0.9, 0.6, 0.5],
+            backgroundColor: "rgba(76, 175, 80, 0.7)", 
+            borderColor: "rgba(76, 175, 80, 1)",
+            borderWidth: 1,
+          },
+          {
+            label: "Pooled Milk - Sialylated Oligo",
+            data: [0.7, 0.4, 0.6, 0.5, 0.8, 0.7, 0.4],
+            backgroundColor: "rgba(76, 175, 80, 0.4)",
+            borderColor: "rgba(76, 175, 80, 1)",
+            borderWidth: 1,
+          },
+          {
+            label: "Milk - Type I Oligo",
+            data: [0.6, 0.8, 0.4, 0.7, 0.5, 0.6, 0.7],
+            backgroundColor: "rgba(244, 67, 54, 0.7)", 
+            borderColor: "rgba(244, 67, 54, 1)",
+            borderWidth: 1,
+          },
+          {
+            label: "Pooled Milk - Type I Oligo",
+            data: [0.5, 0.7, 0.3, 0.6, 0.6, 0.5, 0.6],
+            backgroundColor: "rgba(244, 67, 54, 0.4)",
+            borderColor: "rgba(244, 67, 54, 1)",
+            borderWidth: 1,
+          },
+          {
+            label: "Milk - Type II Oligo",
+            data: [0.4, 0.6, 0.3, 0.5, 0.7, 0.8, 0.6],
+            backgroundColor: "rgba(255, 193, 7, 0.7)", 
+            borderColor: "rgba(255, 193, 7, 1)",
+            borderWidth: 1,
+          },
+          {
+            label: "Pooled Milk - Type II Oligo",
+            data: [0.3, 0.5, 0.2, 0.4, 0.6, 0.7, 0.5],
+            backgroundColor: "rgba(255, 193, 7, 0.4)",
+            borderColor: "rgba(255, 193, 7, 1)",
+            borderWidth: 1,
+          },
+          {
+            label: "Milk - Neutral Oligo",
+            data: [0.7, 0.6, 0.5, 0.7, 0.8, 0.5, 0.7],
+            backgroundColor: "rgba(121, 85, 72, 0.7)", 
+            borderColor: "rgba(121, 85, 72, 1)",
+            borderWidth: 1,
+          },
+          {
+            label: "Pooled Milk - Neutral Oligo",
+            data: [0.6, 0.5, 0.4, 0.6, 0.7, 0.6, 0.6],
+            backgroundColor: "rgba(121, 85, 72, 0.4)",
+            borderColor: "rgba(121, 85, 72, 1)",
+            borderWidth: 1,
+          },
+        ],
+      },
+      options: {
+        responsive: true,
+        plugins: {
+          legend: {
+            position: "top",
+            labels: {
+              boxWidth: 20,
+              padding: 15,
+              font: {
+                size: 12,
+              },
+            },
+          },
+        },
+        scales: {
+          x: {
+            title: {
+              display: true,
+              text: "Stages of Lactation",
+              font: {
+                weight: "bold",
+                size: 14,
+              },
+            },
+            grid: {
+              display: false,
+            },
+          },
+          y: {
+            title: {
+              display: true,
+              text: "Presence / Integrity",
+              font: {
+                weight: "bold",
+                size: 14,
+              },
+            },
+            beginAtZero: true,
+            grid: {
+              color: "#e0e0e0",
+            },
+          },
+        },
+      },
+    }
+  );
+
+  // Distribution of taxons
+  // const taxonsCtx = document
+  //   .getElementById("taxonsChart")
+  //   .getContext("2d");
+  // const taxonsChart = new Chart(taxonsCtx, {
+  //   type: "pie",
+  //   data: {
+  //     labels: [
+  //       "Neutral",
+  //       "Fucosylated",
+  //       "Sialylated",
+  //       "Type I",
+  //       "Type II",
+  //     ], // we raplace here with real names of taxons 
+  //     datasets: [
+  //       {
+  //         label: "Number of occurrences",
+  //         data: [30, 25, 20, 15, 10], // we replace here with real data
+  //         backgroundColor: [
+  //           "#4E79A7",
+  //           "#F28E2B",
+  //           "#E15759",
+  //           "#76B7B2",
+  //           "#59A14F",
+  //         ],
+  //         borderColor: "#ffffff",
+  //         borderWidth: 2,
+  //       },
+  //     ],
+  //   },
+  //   options: {
+  //     responsive: true,
+  //     plugins: {
+  //       legend: {
+  //         position: "top",
+  //         labels: {
+  //           font: {
+  //             size: 14,
+  //           },
+  //         },
+  //       },
+  //     },
+  //   },
+  // });
+
+  document.addEventListener("DOMContentLoaded", function () {
+    const taxonsCtx = document.getElementById("taxonsChart").getContext("2d");
+  
+    function fetchTaxonData() {
+      const apiUrl = "/_get/nb_occ_by_concept?concept=Oligosaccharide_type"; 
+      fetch(apiUrl)
+        .then((response) => {
+          if (!response.ok) {
+            throw new Error(`HTTP error! status: ${response.status}`);
+          }
+          return response.json();
+        })
+        .then((data) => {
+          if (!data.labels || !data.data || data.labels.length !== data.data.length) {
+            throw new Error("The structure of fetched data is invalid.");
+          }
+  
+          const taxonsChart = new Chart(taxonsCtx, {
+            type: "pie",
+            data: {
+              labels: data.labels, 
+              datasets: [
+                {
+                  label: "Number of occurrences",
+                  data: data.data,
+                  backgroundColor: [
+                    "#4E79A7",
+                    "#F28E2B",
+                    "#E15759",
+                    "#76B7B2",
+                    "#59A14F",
+                  ],
+                  borderColor: "#ffffff",
+                  borderWidth: 2,
+                },
+              ],
+            },
+            options: {
+              responsive: true,
+              plugins: {
+                legend: {
+                  position: "top",
+                  labels: {
+                    font: {
+                      size: 14,
+                    },
+                  },
+                },
+              },
+            },
+          });
+        })
+        .catch((error) => {
+          console.error("Error while fetching the data :", error);
+          alert("An error occurred while loading the data. Please try again later.");
+        });
+    }
+  
+
+    fetchTaxonData();
+  });
+  
+  
+  
+    
+
+  const labels = [
+    "Colostrum",
+    "Early Lactation",
+    "Farrowing",
+    "Mature Milk",
+    "Mid Lactation",
+    "Transitional Milk",
+    "Weaning",
+  ];
+
+  // Milk chart
+  const milkCtx = document.getElementById("milkChart").getContext("2d");
+  const milkChart = new Chart(milkCtx, {
+    type: "bar",
+    data: {
+      labels: labels,
+      datasets: [
+        {
+          label: "Fucosylated Oligo",
+          data: [0.9, 0.7, 0.5, 0.6, 0.8, 0.9, 0.4],
+          backgroundColor: "rgba(0, 123, 255, 0.7)", 
+          borderColor: "rgba(0, 123, 255, 1)", 
+          borderWidth: 1,
+        },
+        {
+          label: "Sialylated Oligo",
+          data: [0.8, 0.5, 0.7, 0.6, 0.9, 0.6, 0.5],
+          backgroundColor: "rgba(40, 167, 69, 0.7)", 
+          borderColor: "rgba(40, 167, 69, 1)", 
+          borderWidth: 1,
+        },
+        {
+          label: "Type I Oligo",
+          data: [0.6, 0.8, 0.4, 0.7, 0.5, 0.6, 0.7],
+          backgroundColor: "rgba(255, 193, 7, 0.7)", 
+          borderColor: "rgba(255, 193, 7, 1)",
+          borderWidth: 1,
+        },
+        {
+          label: "Type II Oligo",
+          data: [0.4, 0.6, 0.3, 0.5, 0.7, 0.8, 0.6],
+          backgroundColor: "rgba(23, 162, 184, 0.7)", 
+          borderColor: "rgba(23, 162, 184, 1)",
+          borderWidth: 1,
+        },
+        {
+          label: "Neutral Oligo",
+          data: [0.7, 0.6, 0.5, 0.7, 0.8, 0.5, 0.7],
+          backgroundColor: "rgba(108, 117, 125, 0.7)", 
+          borderColor: "rgba(108, 117, 125, 1)", 
+          borderWidth: 1,
+        },
+      ],
+    },
+    options: {
+      responsive: true,
+      plugins: {
+        legend: { position: "top" },
+      },
+      scales: {
+        x: { title: { display: true, text: "Stages of Lactation" } },
+        y: {
+          beginAtZero: true,
+          title: { display: true, text: "Presence / Integrity" },
+        },
+      },
+    },
+  });
+
+  // Pooled Milk chart
+  const pooledMilkCtx = document
+    .getElementById("pooledMilkChart")
+    .getContext("2d");
+  const pooledMilkChart = new Chart(pooledMilkCtx, {
+    type: "bar",
+    data: {
+      labels: labels,
+      datasets: [
+        {
+          label: "Fucosylated Oligo",
+          data: [0.8, 0.6, 0.4, 0.7, 0.7, 0.8, 0.5],
+          backgroundColor: "rgba(0, 123, 255, 0.4)", 
+          borderColor: "rgba(0, 123, 255, 1)", 
+          borderWidth: 1,
+        },
+        {
+          label: "Sialylated Oligo",
+          data: [0.7, 0.4, 0.6, 0.5, 0.8, 0.7, 0.4],
+          backgroundColor: "rgba(40, 167, 69, 0.4)", 
+          borderColor: "rgba(40, 167, 69, 1)", 
+          borderWidth: 1,
+        },
+        {
+          label: "Type I Oligo",
+          data: [0.5, 0.7, 0.3, 0.6, 0.6, 0.5, 0.6],
+          backgroundColor: "rgba(255, 193, 7, 0.4)", 
+          borderColor: "rgba(255, 193, 7, 1)", 
+          borderWidth: 1,
+        },
+        {
+          label: "Type II Oligo",
+          data: [0.3, 0.5, 0.2, 0.4, 0.6, 0.7, 0.5],
+          backgroundColor: "rgba(23, 162, 184, 0.4)", 
+          borderColor: "rgba(23, 162, 184, 1)", 
+          borderWidth: 1,
+        },
+        {
+          label: "Neutral Oligo",
+          data: [0.6, 0.5, 0.4, 0.6, 0.7, 0.6, 0.6],
+          backgroundColor: "rgba(108, 117, 125, 0.4)", 
+          borderColor: "rgba(108, 117, 125, 1)", 
+          borderWidth: 1,
+        },
+      ],
+    },
+    options: {
+      responsive: true,
+      plugins: {
+        legend: { position: "top" },
+      },
+      scales: {
+        x: { title: { display: true, text: "Stages of Lactation" } },
+        y: {
+          beginAtZero: true,
+          title: { display: true, text: "Presence / Integrity" },
+        },
+      },
+    },
+  });
+
+  // Heatmap 
+
+  const heatmapData = {
+    labels: [
+      "Colostrum",
+      "Early Lactation",
+      "Farrowing",
+      "Mature Milk",
+      "Mid Lactation",
+      "Transitional Milk",
+      "Weaning",
+    ],
+    datasets: [
+      {
+        label: "Sus scrofa",
+        data: [12, 19, 3, 5, 4, 8, 9],
+        backgroundColor: "rgba(248, 103, 59, 0.7)", 
+      },
+      {
+        label: "Bos taurus",
+        data: [2, 3, 20, 3, 12, 19, 3],
+        backgroundColor: "rgba(69, 139, 223, 0.7)", 
+      },
+      {
+        label: "Homo sapiens",
+        data: [3, 10, 13, 15, 20, 3, 12],
+        backgroundColor: "rgba(88, 214, 141, 0.7)", 
+      },
+      {
+        label: "Taxon 4",
+        data: [12, 19, 3, 5, 4, 8, 9],
+        backgroundColor: "rgba(255, 99, 132, 0.4)", 
+      },
+      {
+        label: "Taxon 5",
+        data: [2, 3, 20, 3, 9, 3, 5],
+        backgroundColor: "rgba(54, 162, 235, 0.4)", 
+      },
+      {
+        label: "Taxon 6",
+        data: [3, 10, 13, 15, 6, 3, 20],
+        backgroundColor: "rgba(75, 192, 192, 0.4)", 
+      },
+    ],
+  };
+
+  const heatmapOptions = {
+    responsive: true,
+    plugins: {
+      legend: {
+        position: "top",
+      },
+      tooltip: {
+        mode: "index",
+        intersect: false,
+        callbacks: {
+          label: function (tooltipItem) {
+            return tooltipItem.dataset.label + ": " + tooltipItem.raw; 
+          },
+        },
+      },
+    },
+    scales: {
+      x: {
+        stacked: true,
+        ticks: {
+          font: {
+            size: 14, 
+          },
+        },
+      },
+      y: {
+        stacked: true,
+        ticks: {
+          font: {
+            size: 14, 
+          },
+        },
+      },
+    },
+  };
+
+  const heatmapCtx = document
+    .getElementById("heatmapChart")
+    .getContext("2d");
+
+  new Chart(heatmapCtx, {
+    type: "bar",
+    data: heatmapData,
+    options: heatmapOptions,
+  });
+
+  // Stacked Bar Chart
+
+  const stackedBarData = {
+    labels: ["Milk", "Polled Milk"],
+    datasets: [
+      {
+        label: "Sialylated",
+        data: [20, 10],
+        backgroundColor: "rgba(246,190,167)",
+      },
+      {
+        label: "Neutral",
+        data: [5, 3],
+        backgroundColor: "rgba(250,207,190)",
+      },
+      {
+        label: "Fucosylated",
+        data: [2, 2],
+        backgroundColor: "rgba(253,220,203)",
+      },
+      {
+        label: "Type I",
+        data: [12, 40],
+        backgroundColor: "rgba(217,211,199)",
+      },
+      {
+        label: "Type II",
+        data: [30, 8],
+        backgroundColor: "rgba(218,217,215)",
+      },
+    ],
+  };
+
+  const stackedBarOptions = {
+    responsive: true,
+    plugins: {
+      legend: { position: "top" },
+    },
+    scales: {
+      x: { stacked: true },
+      y: { stacked: true, beginAtZero: true },
+    },
+  };
+
+  const stackedBarCtx = document
+    .getElementById("stackedBarChart2")
+    .getContext("2d");
+
+  new Chart(stackedBarCtx, {
+    type: "bar",
+    data: stackedBarData,
+    options: stackedBarOptions,
+  });
+
diff --git a/templates/home.html b/templates/home.html
index 7a7fbfd..a7f283f 100644
--- a/templates/home.html
+++ b/templates/home.html
@@ -5,6 +5,10 @@
   $SCRIPT_ROOT = {{ request.script_root|tojson|safe }};
 </script>
 
+
+<script src="{{ url_for('static', filename='js/home_page.js') }}" type="text/javascript" defer></script>
+
+
 <!-- Descriptive Section -->
 <div style="margin: 80px 0"></div>
 
@@ -152,1083 +156,6 @@
 
     
 
-        <!-- JavaScript -->
-        <script>
-          document.addEventListener("DOMContentLoaded", function () {
-            const jsonFilePath =
-              '{{ url_for("static", filename="files/data.all.json") }}';
-            // Fetching JSON data
-            fetch(jsonFilePath)
-              .then((response) => response.json())
-              .then((data) => {
-                if (!data.docs) {
-                  throw new Error(
-                    "Le fichier JSON ne contient pas de propriété 'docs'."
-                  );
-                }
-                // Statistics on roles
-                const rolesStats = {};
-                const oligosStats = {
-                  Sialylated: 0,
-                  Neutral: 0,
-                  Fucosylated: 0,
-                  "Type I": 0,
-                  "Type II": 0,
-                };
-
-                // Process each document and their occurrences
-                data.docs.forEach((doc) => {
-                  doc.occurrences.forEach((occurrence) => {
-                    occurrence.relation_occurrences.forEach((relation) => {
-                      relation.args.forEach((arg) => {
-                        // Counting roles
-                        rolesStats[arg.role] = (rolesStats[arg.role] || 0) + 1;
-                      });
-                    });
-                  });
-                });
-
-                // Update entities table
-                const entitiesTableBody =
-                  document.getElementById("entitiesTableBody");
-                Object.keys(rolesStats).forEach((entity) => {
-                  const row = document.createElement("tr");
-                  const cell1 = document.createElement("td");
-                  const cell2 = document.createElement("td");
-                  cell1.textContent = entity;
-                  cell2.textContent = rolesStats[entity];
-                  row.appendChild(cell1);
-                  row.appendChild(cell2);
-                  entitiesTableBody.appendChild(row);
-                });
-              })
-              .catch((error) => {
-                console.error("Error fetching the JSON data:", error);
-              });
-
-            // chart of oligo types per taxon 
-            const chartData = {
-              taxon1: {
-                Sialylated: 1,
-                Neutral: 1,
-                Fucosylated: 1,
-                "Type I": 0,
-                "Type II": 0,
-              },
-              taxon2: {
-                Sialylated: 1,
-                Neutral: 0.5,
-                Fucosylated: 1,
-                "Type I": 1,
-                "Type II": 0,
-              },
-              taxon3: {
-                Sialylated: 1,
-                Neutral: 1,
-                Fucosylated: 1,
-                "Type I": 0,
-                "Type II": 0,
-              },
-              taxon4: {
-                Sialylated: 0.3,
-                Neutral: 0.5,
-                Fucosylated: 0.8,
-                "Type I": 1,
-                "Type II": 0.4,
-              },
-              taxon5: {
-                Sialylated: 1,
-                Neutral: 0,
-                Fucosylated: 1,
-                "Type I": 0,
-                "Type II": 1,
-              },
-            };
-
-            let currentChart = null;
-
-            // Function to create/update chart
-            function createChart(taxon) {
-              const ctx = document
-                .getElementById("taxonOligoChart")
-                .getContext("2d");
-              if (currentChart) currentChart.destroy();
-
-              const data = chartData[taxon];
-              const labels = Object.keys(data);
-              const values = Object.values(data);
-
-              currentChart = new Chart(ctx, {
-                type: "bar",
-                data: {
-                  labels: labels,
-                  datasets: [
-                    {
-                      label: "Presence of Oligosaccharide Types",
-                      data: values,
-                      backgroundColor: [
-                        "#FF6384",
-                        "#36A2EB",
-                        "#FFCE56",
-                        "#4BC0C0",
-                        "#FF9F40",
-                      ],
-                      borderColor: "#ccc",
-                      borderWidth: 1,
-                    },
-                  ],
-                },
-                options: {
-                  responsive: true,
-                  plugins: {
-                    legend: { display: false },
-                    title: {
-                      display: true,
-                      text: "Presence of Oligosaccharide Types",
-                    },
-                  },
-                  scales: {
-                    y: { beginAtZero: true },
-                  },
-                },
-              });
-            }
-
-            // Initialize chart for the selected taxon
-            const taxonSelect = document.getElementById("taxonSelect");
-            createChart(taxonSelect.value);
-
-            // Update chart when a new taxon is selected
-            taxonSelect.addEventListener("change", function () {
-              createChart(this.value);
-            });
-          });
-
-          //type oligo
-
-          document.addEventListener("DOMContentLoaded", function () {
-            // Example data: I should Replace this with actual percentages when available
-            const taxons = [
-              "Sus scrofa",
-              "Homo sapiens",
-              "Bos taurus",
-              "Taxon 4",
-              "Taxon 5",
-            ];
-            const oligoTypes = [
-              "Sialylated",
-              "Neutral",
-              "Fucosylated",
-              "Type I",
-              "Type II",
-            ];
-            const distributionData = [
-              [30, 20, 10, 25, 15], // Sus scrofa
-              [20, 15, 30, 25, 10], // Homo sapiens
-              [25, 20, 15, 10, 30], // Bos taurus
-              [15, 25, 20, 30, 10], // Taxon 4
-              [10, 30, 25, 15, 20], // Taxon 5
-            ];
-
-            const datasets = oligoTypes.map((type, index) => {
-              const colors = [
-                "#FF6384",
-                "#36A2EB",
-                "#FFCE56",
-                "#4BC0C0",
-                "#FF9F40",
-              ];
-              return {
-                label: type,
-                data: distributionData.map((row) => row[index]),
-                backgroundColor: colors[index],
-                borderWidth: 1,
-              };
-            });
-
-            const ctx = document
-              .getElementById("stackedBarChart")
-              .getContext("2d");
-            new Chart(ctx, {
-              type: "bar",
-              data: {
-                labels: taxons,
-                datasets: datasets,
-              },
-              options: {
-                responsive: true,
-                plugins: {
-                  tooltip: {
-                    callbacks: {
-                      label: function (context) {
-                        return `${context.dataset.label}: ${context.raw}%`;
-                      },
-                    },
-                  },
-                  legend: { position: "top" },
-                },
-                scales: {
-                  x: {
-                    stacked: true,
-                    title: {
-                      display: true,
-                      text: "Taxons",
-                    },
-                  },
-                  y: {
-                    stacked: true,
-                    beginAtZero: true,
-                    title: {
-                      display: true,
-                      text: "Percentage",
-                    },
-                  },
-                },
-              },
-            });
-          });
-
-          // Dynamic chart for lactation stages
-          document.addEventListener("DOMContentLoaded", function () {
-            const lactationChartCtx = document
-              .getElementById("lactationChart")
-              .getContext("2d");
-            // data for each lactation stage
-            const lactationData = {
-              labels: [
-                "Colostrum",
-                "Early Lactation",
-                "Farrowing",
-                "Mature Milk",
-                "Mid Lactation",
-                "Transitional Milk",
-                "Weaning",
-              ], // lactation stages (X)
-              datasets: [
-                {
-                  label: "Sialylated",
-                  data: [80, 60, 50, 70, 65, 75, 85],
-                  backgroundColor: "#3E5C76", 
-                  borderColor: "#3E5C76",
-                  borderWidth: 1,
-                },
-                {
-                  label: "Neutral",
-                  data: [50, 70, 60, 80, 70, 65, 60],
-                  backgroundColor: "#7F9BA6", 
-                  borderColor: "#7F9BA6",
-                  borderWidth: 1,
-                },
-                {
-                  label: "Fucosylated",
-                  data: [40, 50, 40, 60, 55, 60, 65],
-                  backgroundColor: "#9A9A9A", 
-                  borderColor: "#9A9A9A",
-                  borderWidth: 1,
-                },
-                {
-                  label: "Type I",
-                  data: [60, 40, 30, 50, 55, 65, 60],
-                  backgroundColor: "#6C8C94", 
-                  borderColor: "#6C8C94",
-                  borderWidth: 1,
-                },
-                {
-                  label: "Type II",
-                  data: [30, 50, 60, 70, 65, 70, 75],
-                  backgroundColor: "#C0A080", 
-                  borderColor: "#C0A080",
-                  borderWidth: 1,
-                },
-              ],
-            };
-            // Create the chart
-            const lactationChart = new Chart(lactationChartCtx, {
-              type: "bar", 
-              data: lactationData,
-              options: {
-                responsive: true,
-                plugins: {
-                  legend: {
-                    position: "top",
-                  },
-                  title: {
-                    display: true,
-                  },
-                },
-                scales: {
-                  x: {
-                    title: {
-                      display: true,
-                      text: "Lactation Stages",
-                    },
-                    grid: {
-                      display: false,
-                    },
-                  },
-                  y: {
-                    beginAtZero: true,
-                    title: {
-                      display: true,
-                      text: "Percentage%",
-                    },
-                    max: 100,
-                  },
-                },
-              },
-            });
-          });
-
-          document.addEventListener("DOMContentLoaded", function () {
-            const speciesChartCtx = document
-              .getElementById("speciesChart")
-              .getContext("2d");
-            const speciesData = {
-              labels: [
-                "Colostrum",
-                "Early Lactation",
-                "Farrowing",
-                "Mature Milk",
-                "Mid Lactation",
-                "Transitional Milk",
-                "Weaning",
-              ],
-              datasets: [
-                {
-                  label: "Species A",
-                  data: [70, 50, 60, 75, 65, 80, 90],
-                  backgroundColor: "#A6D1E6",
-                  borderColor: "#A6D1E6",
-                  borderWidth: 1,
-                },
-                {
-                  label: "Species B",
-                  data: [55, 65, 70, 80, 70, 60, 50],
-                  backgroundColor: "#B6D7A8",
-                  borderColor: "#B6D7A8",
-                  borderWidth: 1,
-                },
-                {
-                  label: "Species C",
-                  data: [40, 60, 50, 65, 60, 75, 85],
-                  backgroundColor: "#F9CB9C",
-                  borderColor: "#F9CB9C",
-                  borderWidth: 1,
-                },
-              ],
-            };
-            const speciesChart = new Chart(speciesChartCtx, {
-              type: "bar",
-              data: speciesData,
-              options: {
-                responsive: true,
-                plugins: {
-                  legend: {
-                    position: "top",
-                  },
-                  title: {
-                    display: true,
-                    text: "Oligosaccharides per Species at Different Lactation Stages",
-                  },
-                },
-                scales: {
-                  x: {
-                    title: {
-                      display: true,
-                      text: "Lactation Stages",
-                    },
-                    grid: {
-                      display: false,
-                    },
-                  },
-                  y: {
-                    beginAtZero: true,
-                    title: {
-                      display: true,
-                      text: "Percentage%",
-                    },
-                    max: 100,
-                  },
-                },
-              },
-            });
-          });
-
-          document.addEventListener("DOMContentLoaded", function () {
-            // lactation stages chart
-            const lactationChartCtx = document
-              .getElementById("lactationChart")
-              .getContext("2d");
-            const lactationData = {
-              labels: [
-                "Colostrum",
-                "Early Lactation",
-                "Farrowing",
-                "Mature Milk",
-                "Mid Lactation",
-                "Transitional Milk",
-                "Weaning",
-              ],
-              datasets: [
-                {
-                  label: "Sialylated",
-                  data: [80, 60, 50, 70, 65, 75, 85],
-                  backgroundColor: "#3E5C76",
-                  borderColor: "#3E5C76",
-                  borderWidth: 1,
-                },
-                {
-                  label: "Neutral",
-                  data: [50, 70, 60, 80, 70, 65, 60],
-                  backgroundColor: "#7F9BA6",
-                  borderColor: "#7F9BA6",
-                  borderWidth: 1,
-                },
-                {
-                  label: "Fucosylated",
-                  data: [40, 50, 40, 60, 55, 60, 65],
-                  backgroundColor: "#9A9A9A",
-                  borderColor: "#9A9A9A",
-                  borderWidth: 1,
-                },
-                {
-                  label: "Type I",
-                  data: [60, 40, 30, 50, 55, 65, 60],
-                  backgroundColor: "#6C8C94",
-                  borderColor: "#6C8C94",
-                  borderWidth: 1,
-                },
-                {
-                  label: "Type II",
-                  data: [30, 50, 60, 70, 65, 70, 75],
-                  backgroundColor: "#C0A080",
-                  borderColor: "#C0A080",
-                  borderWidth: 1,
-                },
-              ],
-            };
-            const lactationChart = new Chart(lactationChartCtx, {
-              type: "bar",
-              data: lactationData,
-              options: {
-                responsive: true,
-                plugins: {
-                  legend: { position: "top" },
-                  title: {
-                    display: true,
-                    text: "Oligosaccharides by Lactation Stage",
-                  },
-                },
-                scales: {
-                  x: {
-                    title: { display: true, text: "Lactation Stages" },
-                    grid: { display: false },
-                  },
-                  y: {
-                    beginAtZero: true,
-                    title: { display: true, text: "Percentage%" },
-                    max: 100,
-                  },
-                },
-              },
-            });
-            // taxon's chart
-            const speciesChartCtx2 = document
-              .getElementById("speciesChart2")
-              .getContext("2d");
-            const speciesData = {
-              labels: [
-                "Colostrum",
-                "Early Lactation",
-                "Farrowing",
-                "Mature Milk",
-                "Mid Lactation",
-                "Transitional Milk",
-                "Weaning",
-              ],
-              datasets: [
-                {
-                  label: "Species A",
-                  data: [70, 50, 60, 75, 65, 80, 90],
-                  backgroundColor: "#A6D1E6",
-                  borderColor: "#A6D1E6",
-                  borderWidth: 1,
-                },
-                {
-                  label: "Species B",
-                  data: [55, 65, 70, 80, 70, 60, 50],
-                  backgroundColor: "#B6D7A8",
-                  borderColor: "#B6D7A8",
-                  borderWidth: 1,
-                },
-                {
-                  label: "Species C",
-                  data: [40, 60, 50, 65, 60, 75, 85],
-                  backgroundColor: "#F9CB9C",
-                  borderColor: "#F9CB9C",
-                  borderWidth: 1,
-                },
-              ],
-            };
-            const speciesChart2 = new Chart(speciesChartCtx2, {
-              type: "bar",
-              data: speciesData,
-              options: {
-                responsive: true,
-                plugins: {
-                  legend: { position: "top" },
-                  title: { display: true, text: "Oligosaccharides by Species" },
-                },
-                scales: {
-                  x: {
-                    title: { display: true, text: "Lactation Stages" },
-                    grid: { display: false },
-                  },
-                  y: {
-                    beginAtZero: true,
-                    title: { display: true, text: "Percentage%" },
-                    max: 100,
-                  },
-                },
-              },
-            });
-          });
-
-          // Distribution of samples per taxons
-          const taxonSampleCtx = document
-            .getElementById("taxonSampleChart")
-            .getContext("2d");
-          const taxonSampleChart = new Chart(taxonSampleCtx, {
-            type: "bar",
-            data: {
-              labels: [
-                "Sus scrofa",
-                "Homo sapiens",
-                "Bos taurus",
-                "Capra hircus",
-                "Elephas maximus",
-              ],
-              datasets: [
-                {
-                  label: "Milk",
-                  data: [0.5, 0.9, 0.2, 1, 0.7], // just for example
-                  backgroundColor: "rgba(54, 162, 235, 0.7)",
-                  borderColor: "rgba(54, 162, 235, 1)",
-                  borderWidth: 1,
-                },
-                {
-                  label: "Pooled Milk",
-                  data: [1, 0.6, 0.2, 0.5, 0.4],
-                  backgroundColor: "rgba(255, 99, 132, 0.7)",
-                  borderColor: "rgba(255, 99, 132, 1)",
-                  borderWidth: 1,
-                },
-              ],
-            },
-            options: {
-              responsive: true,
-              plugins: {
-                legend: {
-                  position: "top",
-                  labels: {
-                    boxWidth: 20,
-                    padding: 15,
-                  },
-                },
-              },
-              scales: {
-                x: {
-                  title: {
-                    display: true,
-                    text: "Taxons",
-                    font: {
-                      weight: "bold",
-                      size: 14,
-                    },
-                  },
-                  grid: {
-                    display: false,
-                  },
-                },
-                y: {
-                  title: {
-                    display: true,
-                    text: "Sample Quantity",
-                    font: {
-                      weight: "bold",
-                      size: 14,
-                    },
-                  },
-                  beginAtZero: true,
-                  grid: {
-                    color: "#e0e0e0",
-                  },
-                },
-              },
-            },
-          });
-
-          const sampleCharacteristicsCtx = document
-            .getElementById("sampleCharacteristicsChart")
-            .getContext("2d");
-          const sampleCharacteristicsChart = new Chart(
-            sampleCharacteristicsCtx,
-            {
-              type: "bar",
-              data: {
-                labels: [
-                  "Colostrum",
-                  "Early Lactation",
-                  "Farrowing",
-                  "Mature Milk",
-                  "Mid Lactation",
-                  "Transitional Milk",
-                  "Weaning",
-                ],
-                datasets: [
-                  {
-                    label: "Milk - Fucosylated Oligo",
-                    data: [0.9, 0.7, 0.5, 0.6, 0.8, 0.9, 0.4],
-                    backgroundColor: "rgba(33, 150, 243, 0.7)", 
-                    borderColor: "rgba(33, 150, 243, 1)",
-                    borderWidth: 1,
-                  },
-                  {
-                    label: "Pooled Milk - Fucosylated Oligo",
-                    data: [0.8, 0.6, 0.4, 0.7, 0.7, 0.8, 0.5],
-                    backgroundColor: "rgba(33, 150, 243, 0.4)", 
-                    borderColor: "rgba(33, 150, 243, 1)",
-                    borderWidth: 1,
-                  },
-                  {
-                    label: "Milk - Sialylated Oligo",
-                    data: [0.8, 0.5, 0.7, 0.6, 0.9, 0.6, 0.5],
-                    backgroundColor: "rgba(76, 175, 80, 0.7)", 
-                    borderColor: "rgba(76, 175, 80, 1)",
-                    borderWidth: 1,
-                  },
-                  {
-                    label: "Pooled Milk - Sialylated Oligo",
-                    data: [0.7, 0.4, 0.6, 0.5, 0.8, 0.7, 0.4],
-                    backgroundColor: "rgba(76, 175, 80, 0.4)",
-                    borderColor: "rgba(76, 175, 80, 1)",
-                    borderWidth: 1,
-                  },
-                  {
-                    label: "Milk - Type I Oligo",
-                    data: [0.6, 0.8, 0.4, 0.7, 0.5, 0.6, 0.7],
-                    backgroundColor: "rgba(244, 67, 54, 0.7)", 
-                    borderColor: "rgba(244, 67, 54, 1)",
-                    borderWidth: 1,
-                  },
-                  {
-                    label: "Pooled Milk - Type I Oligo",
-                    data: [0.5, 0.7, 0.3, 0.6, 0.6, 0.5, 0.6],
-                    backgroundColor: "rgba(244, 67, 54, 0.4)",
-                    borderColor: "rgba(244, 67, 54, 1)",
-                    borderWidth: 1,
-                  },
-                  {
-                    label: "Milk - Type II Oligo",
-                    data: [0.4, 0.6, 0.3, 0.5, 0.7, 0.8, 0.6],
-                    backgroundColor: "rgba(255, 193, 7, 0.7)", 
-                    borderColor: "rgba(255, 193, 7, 1)",
-                    borderWidth: 1,
-                  },
-                  {
-                    label: "Pooled Milk - Type II Oligo",
-                    data: [0.3, 0.5, 0.2, 0.4, 0.6, 0.7, 0.5],
-                    backgroundColor: "rgba(255, 193, 7, 0.4)",
-                    borderColor: "rgba(255, 193, 7, 1)",
-                    borderWidth: 1,
-                  },
-                  {
-                    label: "Milk - Neutral Oligo",
-                    data: [0.7, 0.6, 0.5, 0.7, 0.8, 0.5, 0.7],
-                    backgroundColor: "rgba(121, 85, 72, 0.7)", 
-                    borderColor: "rgba(121, 85, 72, 1)",
-                    borderWidth: 1,
-                  },
-                  {
-                    label: "Pooled Milk - Neutral Oligo",
-                    data: [0.6, 0.5, 0.4, 0.6, 0.7, 0.6, 0.6],
-                    backgroundColor: "rgba(121, 85, 72, 0.4)",
-                    borderColor: "rgba(121, 85, 72, 1)",
-                    borderWidth: 1,
-                  },
-                ],
-              },
-              options: {
-                responsive: true,
-                plugins: {
-                  legend: {
-                    position: "top",
-                    labels: {
-                      boxWidth: 20,
-                      padding: 15,
-                      font: {
-                        size: 12,
-                      },
-                    },
-                  },
-                },
-                scales: {
-                  x: {
-                    title: {
-                      display: true,
-                      text: "Stages of Lactation",
-                      font: {
-                        weight: "bold",
-                        size: 14,
-                      },
-                    },
-                    grid: {
-                      display: false,
-                    },
-                  },
-                  y: {
-                    title: {
-                      display: true,
-                      text: "Presence / Integrity",
-                      font: {
-                        weight: "bold",
-                        size: 14,
-                      },
-                    },
-                    beginAtZero: true,
-                    grid: {
-                      color: "#e0e0e0",
-                    },
-                  },
-                },
-              },
-            }
-          );
-
-          // Distribution of taxons
-          const taxonsCtx = document
-            .getElementById("taxonsChart")
-            .getContext("2d");
-          const taxonsChart = new Chart(taxonsCtx, {
-            type: "pie",
-            data: {
-              labels: [
-                "Neutral",
-                "Fucosylated",
-                "Sialylated",
-                "Type I",
-                "Type II",
-              ], // we raplace here with real names of taxons 
-              datasets: [
-                {
-                  label: "Number of occurrences",
-                  data: [30, 25, 20, 15, 10], // we replace here with real data
-                  backgroundColor: [
-                    "#4E79A7",
-                    "#F28E2B",
-                    "#E15759",
-                    "#76B7B2",
-                    "#59A14F",
-                  ],
-                  borderColor: "#ffffff",
-                  borderWidth: 2,
-                },
-              ],
-            },
-            options: {
-              responsive: true,
-              plugins: {
-                legend: {
-                  position: "top",
-                  labels: {
-                    font: {
-                      size: 14,
-                    },
-                  },
-                },
-              },
-            },
-          });
-
-          
-
-          const labels = [
-            "Colostrum",
-            "Early Lactation",
-            "Farrowing",
-            "Mature Milk",
-            "Mid Lactation",
-            "Transitional Milk",
-            "Weaning",
-          ];
-
-          // Milk chart
-          const milkCtx = document.getElementById("milkChart").getContext("2d");
-          const milkChart = new Chart(milkCtx, {
-            type: "bar",
-            data: {
-              labels: labels,
-              datasets: [
-                {
-                  label: "Fucosylated Oligo",
-                  data: [0.9, 0.7, 0.5, 0.6, 0.8, 0.9, 0.4],
-                  backgroundColor: "rgba(0, 123, 255, 0.7)", 
-                  borderColor: "rgba(0, 123, 255, 1)", 
-                  borderWidth: 1,
-                },
-                {
-                  label: "Sialylated Oligo",
-                  data: [0.8, 0.5, 0.7, 0.6, 0.9, 0.6, 0.5],
-                  backgroundColor: "rgba(40, 167, 69, 0.7)", 
-                  borderColor: "rgba(40, 167, 69, 1)", 
-                  borderWidth: 1,
-                },
-                {
-                  label: "Type I Oligo",
-                  data: [0.6, 0.8, 0.4, 0.7, 0.5, 0.6, 0.7],
-                  backgroundColor: "rgba(255, 193, 7, 0.7)", 
-                  borderColor: "rgba(255, 193, 7, 1)",
-                  borderWidth: 1,
-                },
-                {
-                  label: "Type II Oligo",
-                  data: [0.4, 0.6, 0.3, 0.5, 0.7, 0.8, 0.6],
-                  backgroundColor: "rgba(23, 162, 184, 0.7)", 
-                  borderColor: "rgba(23, 162, 184, 1)",
-                  borderWidth: 1,
-                },
-                {
-                  label: "Neutral Oligo",
-                  data: [0.7, 0.6, 0.5, 0.7, 0.8, 0.5, 0.7],
-                  backgroundColor: "rgba(108, 117, 125, 0.7)", 
-                  borderColor: "rgba(108, 117, 125, 1)", 
-                  borderWidth: 1,
-                },
-              ],
-            },
-            options: {
-              responsive: true,
-              plugins: {
-                legend: { position: "top" },
-              },
-              scales: {
-                x: { title: { display: true, text: "Stages of Lactation" } },
-                y: {
-                  beginAtZero: true,
-                  title: { display: true, text: "Presence / Integrity" },
-                },
-              },
-            },
-          });
-
-          // Pooled Milk chart
-          const pooledMilkCtx = document
-            .getElementById("pooledMilkChart")
-            .getContext("2d");
-          const pooledMilkChart = new Chart(pooledMilkCtx, {
-            type: "bar",
-            data: {
-              labels: labels,
-              datasets: [
-                {
-                  label: "Fucosylated Oligo",
-                  data: [0.8, 0.6, 0.4, 0.7, 0.7, 0.8, 0.5],
-                  backgroundColor: "rgba(0, 123, 255, 0.4)", 
-                  borderColor: "rgba(0, 123, 255, 1)", 
-                  borderWidth: 1,
-                },
-                {
-                  label: "Sialylated Oligo",
-                  data: [0.7, 0.4, 0.6, 0.5, 0.8, 0.7, 0.4],
-                  backgroundColor: "rgba(40, 167, 69, 0.4)", 
-                  borderColor: "rgba(40, 167, 69, 1)", 
-                  borderWidth: 1,
-                },
-                {
-                  label: "Type I Oligo",
-                  data: [0.5, 0.7, 0.3, 0.6, 0.6, 0.5, 0.6],
-                  backgroundColor: "rgba(255, 193, 7, 0.4)", 
-                  borderColor: "rgba(255, 193, 7, 1)", 
-                  borderWidth: 1,
-                },
-                {
-                  label: "Type II Oligo",
-                  data: [0.3, 0.5, 0.2, 0.4, 0.6, 0.7, 0.5],
-                  backgroundColor: "rgba(23, 162, 184, 0.4)", 
-                  borderColor: "rgba(23, 162, 184, 1)", 
-                  borderWidth: 1,
-                },
-                {
-                  label: "Neutral Oligo",
-                  data: [0.6, 0.5, 0.4, 0.6, 0.7, 0.6, 0.6],
-                  backgroundColor: "rgba(108, 117, 125, 0.4)", 
-                  borderColor: "rgba(108, 117, 125, 1)", 
-                  borderWidth: 1,
-                },
-              ],
-            },
-            options: {
-              responsive: true,
-              plugins: {
-                legend: { position: "top" },
-              },
-              scales: {
-                x: { title: { display: true, text: "Stages of Lactation" } },
-                y: {
-                  beginAtZero: true,
-                  title: { display: true, text: "Presence / Integrity" },
-                },
-              },
-            },
-          });
-
-          // Heatmap 
-
-          const heatmapData = {
-            labels: [
-              "Colostrum",
-              "Early Lactation",
-              "Farrowing",
-              "Mature Milk",
-              "Mid Lactation",
-              "Transitional Milk",
-              "Weaning",
-            ],
-            datasets: [
-              {
-                label: "Sus scrofa",
-                data: [12, 19, 3, 5, 4, 8, 9],
-                backgroundColor: "rgba(248, 103, 59, 0.7)", 
-              },
-              {
-                label: "Bos taurus",
-                data: [2, 3, 20, 3, 12, 19, 3],
-                backgroundColor: "rgba(69, 139, 223, 0.7)", 
-              },
-              {
-                label: "Homo sapiens",
-                data: [3, 10, 13, 15, 20, 3, 12],
-                backgroundColor: "rgba(88, 214, 141, 0.7)", 
-              },
-              {
-                label: "Taxon 4",
-                data: [12, 19, 3, 5, 4, 8, 9],
-                backgroundColor: "rgba(255, 99, 132, 0.4)", 
-              },
-              {
-                label: "Taxon 5",
-                data: [2, 3, 20, 3, 9, 3, 5],
-                backgroundColor: "rgba(54, 162, 235, 0.4)", 
-              },
-              {
-                label: "Taxon 6",
-                data: [3, 10, 13, 15, 6, 3, 20],
-                backgroundColor: "rgba(75, 192, 192, 0.4)", 
-              },
-            ],
-          };
-
-          const heatmapOptions = {
-            responsive: true,
-            plugins: {
-              legend: {
-                position: "top",
-              },
-              tooltip: {
-                mode: "index",
-                intersect: false,
-                callbacks: {
-                  label: function (tooltipItem) {
-                    return tooltipItem.dataset.label + ": " + tooltipItem.raw; 
-                  },
-                },
-              },
-            },
-            scales: {
-              x: {
-                stacked: true,
-                ticks: {
-                  font: {
-                    size: 14, 
-                  },
-                },
-              },
-              y: {
-                stacked: true,
-                ticks: {
-                  font: {
-                    size: 14, 
-                  },
-                },
-              },
-            },
-          };
-
-          const heatmapCtx = document
-            .getElementById("heatmapChart")
-            .getContext("2d");
-
-          new Chart(heatmapCtx, {
-            type: "bar",
-            data: heatmapData,
-            options: heatmapOptions,
-          });
-
-          // Stacked Bar Chart
-
-          const stackedBarData = {
-            labels: ["Milk", "Polled Milk"],
-            datasets: [
-              {
-                label: "Sialylated",
-                data: [20, 10],
-                backgroundColor: "rgba(246,190,167)",
-              },
-              {
-                label: "Neutral",
-                data: [5, 3],
-                backgroundColor: "rgba(250,207,190)",
-              },
-              {
-                label: "Fucosylated",
-                data: [2, 2],
-                backgroundColor: "rgba(253,220,203)",
-              },
-              {
-                label: "Type I",
-                data: [12, 40],
-                backgroundColor: "rgba(217,211,199)",
-              },
-              {
-                label: "Type II",
-                data: [30, 8],
-                backgroundColor: "rgba(218,217,215)",
-              },
-            ],
-          };
-
-          const stackedBarOptions = {
-            responsive: true,
-            plugins: {
-              legend: { position: "top" },
-            },
-            scales: {
-              x: { stacked: true },
-              y: { stacked: true, beginAtZero: true },
-            },
-          };
-
-          const stackedBarCtx = document
-            .getElementById("stackedBarChart2")
-            .getContext("2d");
-
-          new Chart(stackedBarCtx, {
-            type: "bar",
-            data: stackedBarData,
-            options: stackedBarOptions,
-          });
-        </script>
-
         {% endblock %}
       </div>
     </div>
diff --git a/templates/main2 b/templates/main2
index 21bdf5e..f36c534 100644
--- a/templates/main2
+++ b/templates/main2
@@ -45,7 +45,8 @@
   <script src="https://cdn.jsdelivr.net/npm/chartjs-chart-boxplot@1.0.0/dist/chartjs-chart-boxplot.min.js"></script>
   <script src="https://cdnjs.cloudflare.com/ajax/libs/chartjs-plugin-datalabels/2.0.0/chartjs-plugin-datalabels.js"></script>
   <script src="https://unpkg.com/@sgratzl/chartjs-chart-boxplot@3.6.0/build/index.umd.min.js"></script>
-  <script src="js/chartjs-chart-box-and-violin-plot.min.js"></script>
+  <script src="js/chartjs-chart-box-and-violin-plot.min.js"></script> 
+  <script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/3.9.1/chart.min.js"></script>
 
 
   <body>
-- 
GitLab


From c9dc56050522e07780105bdbd8074e188b8392d3 Mon Sep 17 00:00:00 2001
From: "hajar.bouamout" <hajar.bouamout@inrae.fr>
Date: Thu, 2 Jan 2025 16:59:35 +0100
Subject: [PATCH 11/51] ajout des routes research et sheet

---
 __init__.py | 44 +++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 43 insertions(+), 1 deletion(-)

diff --git a/__init__.py b/__init__.py
index 07b7240..0c59476 100644
--- a/__init__.py
+++ b/__init__.py
@@ -58,11 +58,50 @@ with app.app_context():
             app.config['postgreSQL_pool'].putconn(db)
 
 
-#Home page v1
+# Main homepage route 
 @app.route('/home_page')
 def home():
     return render_template('home.html')
 
+# Research page route
+@app.route('/research')
+def research():
+    return render_template('research.html')
+
+# Data sheet page - displays detailed information for individual oligosaccharides
+@app.route('/sheet')
+def sheet():
+    return render_template('sheet.html')
+
+#to upload an oligo structure
+@app.route('/upload_structure', methods=['POST'])
+def upload_structure():
+    if 'file' not in request.files:
+        return jsonify({'error': 'No file part'}), 400
+    file = request.files['file']
+    if file.filename == '':
+        return jsonify({'error': 'No selected file'}), 400
+    if file and allowed_file(file.filename):
+        filename = secure_filename(file.filename)
+        file.save(os.path.join(app.config['UPLOAD_FOLDER'], filename))
+        return jsonify({'success': True, 'filename': filename})
+
+#to save the modifications in the sheet
+@app.route('/save_field', methods=['POST'])
+def save_field():
+    data = request.json
+    field_id = data.get('field_id')
+    value = data.get('value')
+    # Update your database here
+    return jsonify({'success': True})
+
+#to download the sheet
+@app.route('/download_fiche', methods=['POST'])
+def download_fiche():
+    filename = 'fiche_modified.pdf'  
+    return jsonify({'success': True, 'filename': filename})
+
+
 
 # Home page
 @app.route('/index')
@@ -100,6 +139,9 @@ def contact():
     return render_template('contact.html')
 
 
+
+
+
 ##### TEST #####
 # Search by Taxon page (oligo name)
 @app.route('/searchByTaxonForOligosaccharideName/')
-- 
GitLab


From 994dfecc798f473a885b5c6be1ee63788be7bfa8 Mon Sep 17 00:00:00 2001
From: "hajar.bouamout" <hajar.bouamout@inrae.fr>
Date: Thu, 2 Jan 2025 17:16:22 +0100
Subject: [PATCH 12/51] Ajout des fichiers pour la page Sheet : HTML, JS et CSS

---
 static/css/sheet.css | 203 ++++++++++++++++++++++++++
 static/js/sheet.js   | 332 +++++++++++++++++++++++++++++++++++++++++++
 templates/sheet.html |  88 ++++++++++++
 3 files changed, 623 insertions(+)
 create mode 100644 static/css/sheet.css
 create mode 100644 static/js/sheet.js
 create mode 100644 templates/sheet.html

diff --git a/static/css/sheet.css b/static/css/sheet.css
new file mode 100644
index 0000000..35a435b
--- /dev/null
+++ b/static/css/sheet.css
@@ -0,0 +1,203 @@
+/* General Reset */
+body {
+    margin: 0;
+    padding: 0;
+    font-family: 'Arial', sans-serif;
+    background-color: #f9f9f9;
+    color: #333;
+    scroll-behavior:inherit;
+}
+
+/* Main Layout */
+main {
+    max-width: 1200px;
+    margin: 20px auto;
+    padding: 20px;
+    background-color: #ffffff;
+    border-radius: 8px;
+    box-shadow: 0 4px 10px rgba(0, 0, 0, 0.1);
+}
+
+/* Navigation Tabs */
+.nav-tabs {
+    display: flex;
+    justify-content: center;
+    border-bottom: 2px solid #ddd;
+    margin-bottom: 20px;
+    padding: 10px 0;
+    margin-top: 40px;
+}
+
+.nav-tabs a {
+    text-decoration: none;
+    color: #555;
+    padding: 10px 20px;
+    font-size: 1.1rem;
+    border-radius: 6px;
+    transition: all 0.3s ease;
+}
+
+.nav-tabs a:hover,
+.nav-tabs a.active {
+    background-color: #007bff;
+    color: white;
+}
+
+/* Section Headers */
+.section-header {
+    font-size: 1.5rem;
+    color: #444;
+    margin-bottom: 15px;
+    text-align: center;
+    border-bottom: 2px solid #ddd;
+    padding-bottom: 5px;
+}
+
+/* Information Boxes */
+.info-box {
+    margin-bottom: 30px;
+    padding: 20px;
+    background-color: #f7f7f7;
+    border: 1px solid #ddd;
+    border-radius: 8px;
+}
+
+.info-row {
+    display: flex;
+    justify-content: space-between;
+    align-items: center;
+    padding: 10px 0;
+    border-bottom: 1px solid #eaeaea;
+}
+
+.info-row:last-child {
+    border-bottom: none;
+}
+
+.info-label {
+    font-weight: bold;
+    font-size: 1rem;
+    color: #555;
+    flex: 0 0 40%;
+}
+
+.info-value {
+    flex: 0 0 55%;
+    text-align: right;
+    font-size: 1rem;
+    color: #333;
+    word-wrap: break-word;
+}
+
+.info-value[contenteditable="true"] {
+    border: 1px dashed #ccc;
+    padding: 5px;
+    border-radius: 4px;
+    cursor: text;
+}
+
+/* Buttons */
+button {
+    background-color: #007bff;
+    color: white;
+    border: none;
+    padding: 8px 15px;
+    font-size: 0.9rem;
+    cursor: pointer;
+    border-radius: 6px;
+    transition: background-color 0.3s ease;
+}
+
+button:hover {
+    background-color: #0056b3;
+}
+
+.edit-icon {
+    margin-left: 10px;
+    background: none;
+    border: none;
+    color: #007bff;
+    font-size: 1rem;
+    cursor: pointer;
+    transition: color 0.3s ease;
+}
+
+.edit-icon:hover {
+    color: #0056b3;
+}
+
+/* 3D Structure */
+.structure-container {
+    display: flex;
+    flex-direction: column;
+    align-items: center;
+}
+
+.structure-image {
+    max-width: 100%;
+    height: auto;
+    border: 1px solid #ddd;
+    border-radius: 8px;
+    margin: 10px 0;
+}
+
+.image-controls {
+    margin-top: 10px;
+}
+
+.image-path {
+    font-size: 0.9rem;
+    color: #555;
+    margin-top: 5px;
+    text-align: center;
+}
+
+/* Action Buttons */
+.action-buttons {
+    display: flex;
+    justify-content: center;
+    gap: 20px;
+    margin-top: 20px;
+}
+
+.save-button {
+    background-color: #28a745;
+}
+
+.save-button:hover {
+    background-color: #218838;
+}
+
+.download-button {
+    background-color: #17a2b8;
+}
+
+.download-button:hover {
+    background-color: #138496;
+}
+
+/* Responsiveness */
+@media (max-width: 768px) {
+    .info-row {
+        flex-direction: column;
+        align-items: flex-start;
+    }
+
+    .info-label,
+    .info-value {
+        text-align: left;
+        width: 100%;
+        margin-bottom: 5px;
+    }
+
+    .nav-tabs {
+        flex-wrap: wrap;
+        justify-content: space-around;
+    }
+
+    .action-buttons {
+        flex-direction: column;
+        gap: 10px;
+    }
+}
+
diff --git a/static/js/sheet.js b/static/js/sheet.js
new file mode 100644
index 0000000..24f9eda
--- /dev/null
+++ b/static/js/sheet.js
@@ -0,0 +1,332 @@
+document.addEventListener("DOMContentLoaded", function () {
+  // Cache DOM elements
+  const editableFields = document.querySelectorAll(
+    '.info-value[contenteditable="true"]'
+  );
+  const editIcons = document.querySelectorAll(".edit-icon");
+  const saveButton = document.getElementById("saveButton");
+  const downloadButton = document.getElementById("downloadButton");
+  const structureUpload = document.getElementById("structureUpload");
+  const structureImage = document.getElementById("structureImage");
+
+  // Track changes
+  let hasUnsavedChanges = false;
+
+  // Handle edit icon clicks
+  editIcons.forEach((icon, index) => {
+    icon.addEventListener("click", function () {
+      const field = editableFields[index];
+      field.focus();
+
+      // Place cursor at the end of the content
+      const range = document.createRange();
+      const selection = window.getSelection();
+      range.selectNodeContents(field);
+      range.collapse(false);
+      selection.removeAllRanges();
+      selection.addRange(range);
+    });
+  });
+
+  // Handle editable field changes
+  editableFields.forEach((field) => {
+    // Save on blur
+    field.addEventListener("blur", function () {
+      if (this.textContent.trim() !== this.getAttribute("data-original")) {
+        handleChange(this);
+      }
+    });
+
+    // Save on Enter key
+    field.addEventListener("keydown", function (e) {
+      if (e.key === "Enter") {
+        e.preventDefault();
+        this.blur();
+      }
+    });
+
+    // Store original value
+    field.setAttribute("data-original", field.textContent.trim());
+  });
+
+  // Handle image upload
+  if (structureUpload) {
+    structureUpload.addEventListener("change", function (e) {
+      const file = e.target.files[0];
+      if (file) {
+        const reader = new FileReader();
+        reader.onload = function (e) {
+          structureImage.src = e.target.result;
+          hasUnsavedChanges = true;
+          updateSaveButtonVisibility();
+        };
+        reader.readAsDataURL(file);
+
+        // Update image path display
+        document.getElementById("imagePath").textContent = `Path: ${file.name}`;
+      }
+    });
+  }
+
+  // Handle changes
+  function handleChange(field) {
+    hasUnsavedChanges = true;
+    updateSaveButtonVisibility();
+  }
+
+  // Update save button visibility
+  function updateSaveButtonVisibility() {
+    if (saveButton) {
+      saveButton.style.display = hasUnsavedChanges ? "inline-block" : "none";
+    }
+  }
+
+  // Save changes
+  if (saveButton) {
+    saveButton.addEventListener("click", async function () {
+      try {
+        const data = collectFormData();
+        const response = await fetch("/save-changes", {
+          method: "POST",
+          headers: {
+            "Content-Type": "application/json",
+          },
+          body: JSON.stringify(data),
+        });
+
+        if (!response.ok) {
+          throw new Error("Failed to save changes");
+        }
+
+        hasUnsavedChanges = false;
+        updateSaveButtonVisibility();
+        showNotification("Changes saved successfully!", "success");
+      } catch (error) {
+        console.error("Save error:", error);
+        showNotification("Error saving changes. Please try again.", "error");
+      }
+    });
+  }
+
+  // Download functionality
+  if (downloadButton) {
+    downloadButton.addEventListener("click", async function () {
+      try {
+        await generatePDF();
+        showNotification("Fiche downloaded successfully!", "success");
+      } catch (error) {
+        console.error("Download error:", error);
+        showNotification("Error downloading fiche. Please try again.", "error");
+      }
+    });
+  }
+
+  // Collect form data
+  function collectFormData() {
+    const data = {};
+    editableFields.forEach((field) => {
+      const label = field
+        .closest(".info-row")
+        .querySelector(".info-label")
+        .textContent.trim();
+      data[label] = field.textContent.trim();
+    });
+    return data;
+  }
+
+  // Generate PDF
+  async function generatePDF() {
+    const { jsPDF } = window.jspdf;
+    const doc = new jsPDF();
+
+    // Set default font
+    doc.setFont("helvetica");
+
+    // Page margins
+    const margin = 20;
+    let yPosition = margin;
+    const pageWidth = doc.internal.pageSize.width;
+    const contentWidth = pageWidth - 2 * margin;
+
+    // Define colors correctly for jsPDF
+    function setColor(r, g, b) {
+      return doc.setTextColor(r, g, b);
+    }
+
+    // Function to add a new page if needed
+    function checkNewPage(height) {
+      const pageHeight = doc.internal.pageSize.height;
+      if (yPosition + height > pageHeight - margin) {
+        doc.addPage();
+        yPosition = margin;
+        return true;
+      }
+      return false;
+    }
+
+    // Add navigation section title
+    setColor(33, 150, 243); 
+    doc.setFontSize(14);
+    doc.text("Oligosaccharides", margin, yPosition);
+    yPosition += 15;
+
+    // Function to add a section
+    function addSection(title, content) {
+      // Add section header
+      checkNewPage(30);
+
+      // Set header color
+      setColor(51, 51, 51); 
+      doc.setFontSize(12);
+      doc.setFont("helvetica", "bold");
+      doc.text(title.toUpperCase(), margin, yPosition);
+
+      // Underline the section header
+      const titleWidth = doc.getTextWidth(title.toUpperCase());
+      doc.setDrawColor(33, 150, 243); 
+      doc.line(margin, yPosition + 1, margin + titleWidth, yPosition + 1);
+      yPosition += 10;
+
+      // Add content
+      doc.setFont("helvetica", "normal");
+      doc.setFontSize(10);
+
+      Object.entries(content).forEach(([label, value]) => {
+        checkNewPage(15);
+
+        // Label in bold
+        setColor(85, 85, 85); 
+        doc.setFont("helvetica", "bold");
+        doc.text(label, margin, yPosition);
+
+        // Value in normal weight
+        setColor(51, 51, 51); 
+        doc.setFont("helvetica", "normal");
+
+        // Handle long text wrapping
+        const maxWidth = contentWidth - 70;
+        const valueLines = doc.splitTextToSize(value.toString(), maxWidth);
+        doc.text(valueLines, margin + 70, yPosition);
+
+        yPosition += Math.max(10, valueLines.length * 7);
+      });
+
+      yPosition += 10; 
+        }
+
+    try {
+      // Collect data from the page
+      const oligoSection = {};
+      const matchedSection = {};
+
+      // Collect oligosaccharide information
+      document
+        .querySelectorAll(".info-box:nth-child(2) .info-row")
+        .forEach((row) => {
+          const label = row.querySelector(".info-label").textContent.trim();
+          const value = row.querySelector(".info-value").textContent.trim();
+          oligoSection[label] = value;
+        });
+
+      // Collect matched information
+      document
+        .querySelectorAll(".info-box:nth-child(3) .info-row")
+        .forEach((row) => {
+          const label = row.querySelector(".info-label").textContent.trim();
+          const value = row.querySelector(".info-value").textContent.trim();
+          matchedSection[label] = value;
+        });
+
+      // Add sections to PDF
+      addSection("OLIGOSACCHARIDE INFORMATION", oligoSection);
+      addSection("MATCHED INFORMATION", matchedSection);
+
+      // Add structure image if present
+      const structureImage = document.getElementById("structureImage");
+      if (structureImage && structureImage.src) {
+        checkNewPage(180);
+        try {
+          setColor(51, 51, 51);
+          doc.text("3D Structure:", margin, yPosition);
+          yPosition += 10;
+
+          // Calculate image dimensions to maintain aspect ratio
+          const imgWidth = 160;
+          const imgHeight =
+            (imgWidth * structureImage.height) / structureImage.width;
+
+          doc.addImage(
+            structureImage,
+            "PNG",
+            margin,
+            yPosition,
+            imgWidth,
+            imgHeight
+          );
+          yPosition += imgHeight + 10;
+        } catch (error) {
+          console.error("Error adding image to PDF:", error);
+          throw new Error("Failed to add structure image to PDF");
+        }
+      }
+
+      // Add footer with date
+      const pageCount = doc.internal.getNumberOfPages();
+      for (let i = 1; i <= pageCount; i++) {
+        doc.setPage(i);
+        const footer = `Page ${i} of ${pageCount} - Generated on ${new Date().toLocaleDateString()}`;
+        doc.setFontSize(8);
+        setColor(128, 128, 128); 
+        doc.text(footer, pageWidth / 2, doc.internal.pageSize.height - 10, {
+          align: "center",
+        });
+      }
+
+      // Save the PDF
+      doc.save("oligosaccharide_sheet.pdf");
+      return true;
+    } catch (error) {
+      console.error("PDF generation error:", error);
+      throw new Error("Failed to generate PDF: " + error.message);
+    }
+  }
+
+  // Add the event listener for the download button
+  document
+    .getElementById("downloadButton")
+    .addEventListener("click", async () => {
+      try {
+        await generatePDF();
+        showNotification("Fiche downloaded successfully!", "success");
+      } catch (error) {
+        console.error("Error generating PDF:", error);
+        showNotification("Error downloading fiche. Please try again.", "error");
+      }
+    });
+
+  // Notification system
+  function showNotification(message, type) {
+    const notification = document.createElement("div");
+    notification.className = `notification ${type}`;
+    notification.textContent = message;
+
+    // Remove existing notifications
+    const existingNotifications = document.querySelectorAll(".notification");
+    existingNotifications.forEach((notif) => notif.remove());
+
+    document.body.appendChild(notification);
+
+    setTimeout(() => {
+      notification.classList.add("fade-out");
+      setTimeout(() => notification.remove(), 300);
+    }, 3000);
+  }
+
+  // Warn about unsaved changes before leaving
+  window.addEventListener("beforeunload", function (e) {
+    if (hasUnsavedChanges) {
+      e.preventDefault();
+      e.returnValue = "";
+    }
+  });
+});
diff --git a/templates/sheet.html b/templates/sheet.html
new file mode 100644
index 0000000..b608208
--- /dev/null
+++ b/templates/sheet.html
@@ -0,0 +1,88 @@
+{% extends 'main3' %} {% block content %}
+<script type="text/javascript">
+  const SCRIPT_ROOT = {{ request.script_root|tojson|safe }};
+</script>
+
+<script src="{{ url_for('static', filename='js/sheet.js') }}" defer></script>
+<link
+  href="{{ url_for('static', filename='css/sheet.css') }}"
+  rel="stylesheet"
+/>
+
+<main>
+  <!-- Navigation Tabs -->
+  <nav class="nav-tabs">
+    <a href="#" class="active" aria-current="page">Oligosaccharides</a>
+    <a href="#">Species</a>
+    <a href="#">Samples</a>
+  </nav>
+
+  <!-- OLIGOSACCHARIDE INFORMATION Section -->
+  <section id="oligosaccharide-info" class="info-box">
+    <h2 class="section-header">OLIGOSACCHARIDE INFORMATION</h2>
+    {% for label, value in [ ('Milk Oligosaccharide ID', 'OLIGO0137'), ('Milk
+    Oligosaccharide Normalized Name', '2\'-Fucosyllactose'), ('Abbreviated
+    Normalized MO Name', '2\'-FL'), ('Formula', 'C18H32O15'), ('Synonyms',
+    '2\'FL | 2\'fucosyllactose | 2FL') ] %}
+    <div class="info-row">
+      <div class="info-label">{{ label }}</div>
+      <div class="info-value" contenteditable="true">{{ value }}</div>
+      <button class="edit-icon" aria-label="Edit text occurrence">
+        <i class="fas fa-pencil-alt"></i>
+      </button>
+    </div>
+    {% endfor %}
+  </section>
+
+  <!-- MATCHED INFORMATION Section -->
+  <section id="matched-info" class="info-box">
+    <h2 class="section-header">MATCHED INFORMATION</h2>
+    {% for label, value in [ ('Text Occurrence', 'fucosyllactose'), ('Reference
+    Class', '2\'-Fucosyllactose'), ('Species', 'Rabbit'), ('MO Type', 'XX'),
+    ('MO Samples', 'Unidentified'), ('Methods of Analysis', 'A high-performance
+    anion-exchange chromatography-pulsed amperometric detector (HPAEC-PAD)'),
+    ('Text Snippet', 'A high-performance anion-exchange chromatography-pulsed
+    amperometric detector (HPAEC-PAD) was used to quantify 2\'-fucosyllactose
+    (2\'-FL)'), ('Number of Occurrences', '2'), ('Number of Matched Documents',
+    '13') ] %}
+    <div class="info-row">
+      <div class="info-label">{{ label }}</div>
+      <div class="info-value" contenteditable="true">{{ value }}</div>
+      <button class="edit-icon" aria-label="Edit text occurrence">
+        <i class="fas fa-pencil-alt"></i>
+      </button>
+    </div>
+    {% endfor %}
+
+    <!-- 3D Structure Section -->
+    <div class="info-row">
+      <div class="info-label">3D Structure</div>
+      <div class="info-value">
+        <div class="structure-container">
+          <img
+            id="structureImage"
+            class="structure-image"
+            src="{{ url_for('static', filename='img/2\'-Fucosyllactose.png') }}"
+            alt="3D Structure of 2'-Fucosyllactose"
+          />
+          <div class="image-controls">
+            <input
+              type="file"
+              id="structureUpload"
+              accept="image/*"
+              class="hidden"
+            />
+            <div id="imagePath" class="image-path"></div>
+          </div>
+        </div>
+      </div>
+    </div>
+  </section>
+
+  <!-- Action Buttons -->
+  <div class="action-buttons">
+    <button id="saveButton" class="save-button">Save All Changes</button>
+    <button id="downloadButton" class="download-button">Download Fiche</button>
+  </div>
+</main>
+{% endblock %}
-- 
GitLab


From 02c918b04ca2775fc495af92927f40299f83eff8 Mon Sep 17 00:00:00 2001
From: "hajar.bouamout" <hajar.bouamout@inrae.fr>
Date: Thu, 2 Jan 2025 17:41:07 +0100
Subject: [PATCH 13/51] =?UTF-8?q?Refactorisation=20de=20la=20page=20d'accu?=
 =?UTF-8?q?eil=20pour=20afficher=20que=20les=20visualisations=20avec=20des?=
 =?UTF-8?q?=20donn=C3=A9es=20r=C3=A9elles=20r=C3=A9cup=C3=A9r=C3=A9es=20vi?=
 =?UTF-8?q?a=20des=20APIs?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 static/css/home.css | 113 ++++++++++++++++++++++++
 static/js/home.js   | 110 +++++++++++++++++++++++
 templates/home.html | 207 +++++++++++++-------------------------------
 3 files changed, 282 insertions(+), 148 deletions(-)
 create mode 100644 static/css/home.css
 create mode 100644 static/js/home.js

diff --git a/static/css/home.css b/static/css/home.css
new file mode 100644
index 0000000..ec9d447
--- /dev/null
+++ b/static/css/home.css
@@ -0,0 +1,113 @@
+body {
+    font-family: 'Roboto', sans-serif;
+    color: #333;
+    background-color: #f8f9fa;
+  }
+  
+  /* Hero Section */
+.hero-section {
+    background: linear-gradient(145deg, #274757, #0077cc);
+    padding: 4rem 0;
+    border-radius: 0 0 2rem 2rem;
+    color: white;
+  }
+  
+  .hero-section h1 {
+    color: black;
+    font-size: 2.8rem;
+    margin-bottom: 1.5rem;
+  }
+  
+  .hero-section .description {
+    max-width: 800px;
+    margin: 0 auto;
+    font-size: 1.2rem;
+    line-height: 1.6;
+    color :black;
+    opacity: 0.95;
+  }
+  
+  .btn-info {
+    background-color: #4a90e2;
+    border: none;
+    padding: 0.8rem 2rem;
+    border-radius: 2rem;
+    font-weight: 500;
+    transition: transform 0.2s;
+  }
+  
+  .btn-info:hover {
+    transform: translateY(-2px);
+    background-color: #357abd;
+  }
+  
+  /* Data Overview Section */
+  .section-title {
+    font-size: 2.2rem;
+    color: #274757;
+    font-weight: 600;
+  }
+  
+  .visualization-row {
+    margin: 0 -15px;
+  }
+  
+  .viz-card {
+    background: white;
+    border-radius: 1rem;
+    padding: 1.5rem;
+    height: 400px;
+    box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
+    transition: transform 0.2s;
+  }
+  
+  .viz-card:hover {
+    transform: translateY(-5px);
+  }
+  
+  .viz-card h3 {
+    color: #274757;
+    font-size: 1.3rem;
+    margin-bottom: 1.5rem;
+    text-align: center;
+  }
+  
+  .table-wrapper {
+    max-height: 300px;
+    overflow-y: auto;
+  }
+  
+  .table {
+    margin-bottom: 0;
+  }
+  
+  .table th {
+    background-color: #274757;
+    color: white;
+    position: sticky;
+    top: 0;
+  }
+  
+  .coming-soon {
+    height: 100%;
+    display: flex;
+    flex-direction: column;
+    align-items: center;
+    justify-content: center;
+    color: #888;
+  }
+  
+  .coming-soon i {
+    font-size: 3rem;
+    margin-bottom: 1rem;
+  }
+  
+  @media (max-width: 768px) {
+    .visualization-row {
+      flex-direction: column;
+    }
+    
+    .viz-card {
+      margin-bottom: 2rem;
+    }
+  }
\ No newline at end of file
diff --git a/static/js/home.js b/static/js/home.js
new file mode 100644
index 0000000..ea3cfe4
--- /dev/null
+++ b/static/js/home.js
@@ -0,0 +1,110 @@
+//table displaying statistics for each entity
+document.addEventListener("DOMContentLoaded", function () {
+  // The API URL from which we are fetching the JSON data
+  const apiUrl = '/_get/stat_occurrence';
+   
+  // Fetching the JSON data from the API
+  fetch(apiUrl)
+    .then((response) => response.json())  // Convert the API response to JSON
+    .then((data) => {
+
+      // Log the received data to the console for verification
+      console.log("Data received from the API:", data);
+
+      // Check if the data is empty or null
+      if (!data || Object.keys(data).length === 0) {
+        throw new Error("The data from the API is empty or invalid.");
+      }
+      
+      // Initialize an object to store role statistics
+      const rolesStats = {};
+
+      // Iterate over the data and populate the rolesStats object
+      Object.keys(data).forEach((key) => {
+        rolesStats[key] = data[key];  
+      });
+
+      // Get the table body element where we will display the data
+      const entitiesTableBody = document.getElementById("entitiesTableBody");
+
+      // Iterate over the rolesStats object and create table rows for each entity
+      Object.keys(rolesStats).forEach((entity) => {
+        const row = document.createElement("tr");
+        const cell1 = document.createElement("td");
+        const cell2 = document.createElement("td");
+
+         // Set the content of the cells
+        cell1.textContent = entity;
+        cell2.textContent = rolesStats[entity];
+
+        // Append the cells to the row
+        row.appendChild(cell1);
+        row.appendChild(cell2);
+
+        // Append the row to the table body
+        entitiesTableBody.appendChild(row);
+      });
+    })
+    .catch((error) => {
+      console.error("Error fetching the JSON data:", error);
+    });})
+
+
+    // Event listener that triggers when the DOM is fully loaded
+  document.addEventListener("DOMContentLoaded", function () {
+      // Get the context of the canvas where the chart will be drawn
+    const taxonsCtx = document.getElementById("taxonsChart").getContext("2d");
+      // Function to fetch taxon data from the API
+    function fetchTaxonData() {
+      const apiUrl = "/_get/nb_occ_by_concept?concept=Oligosaccharide_type"; 
+      fetch(apiUrl)
+        .then((response) => {
+          if (!response.ok) {
+            throw new Error(`HTTP error! status: ${response.status}`);
+          }
+          return response.json();
+        })
+        .then((data) => {
+          if (!data.labels || !data.data || data.labels.length !== data.data.length) {
+            throw new Error("The structure of fetched data is invalid.");
+          }
+      // Create the chart with the fetched data
+          const taxonsChart = new Chart(taxonsCtx, {
+            type: "pie",
+            data: {
+              labels: data.labels, 
+              datasets: [
+                {
+                  label: "Number of occurrences",
+                  data: data.data,
+                  backgroundColor: [
+                    "#4E79A7", "#F28E2B", "#E15759", "#76B7B2", "#59A14F"
+                  ],
+                  borderColor: "#ffffff",
+                  borderWidth: 2,
+                },
+              ],
+            },
+            options: {
+              responsive: true,
+              plugins: {
+                legend: {
+                  position: "top",
+                  labels: {
+                    font: {
+                      size: 14,
+                    },
+                  },
+                },
+              },
+            },
+          });
+        })
+        .catch((error) => {
+          console.error("Error while fetching the data :", error);
+          alert("An error occurred while loading the data. Please try again later.");
+        });
+    }
+
+    fetchTaxonData();
+  });
\ No newline at end of file
diff --git a/templates/home.html b/templates/home.html
index a7f283f..1ac5e9e 100644
--- a/templates/home.html
+++ b/templates/home.html
@@ -1,163 +1,74 @@
-{% extends 'main2' %} 
-{% block content %}
-
+{% extends 'main3' %} {% block content %}
 <script type="text/javascript">
   $SCRIPT_ROOT = {{ request.script_root|tojson|safe }};
 </script>
 
-
-<script src="{{ url_for('static', filename='js/home_page.js') }}" type="text/javascript" defer></script>
-
-
-<!-- Descriptive Section -->
-<div style="margin: 80px 0"></div>
-
-<div class="row no-gutters bg-light position-relative align-items-center">
-  <div class="col-12 col-md-9 mb-md-0 p-md-4 align-middle">
-    <h4 class="title">
-      HoloOligo : A Comprehensive Database of Milk Oligosaccharides
-    </h4>
-    <p class="description">
-      The HoloOligo database is a specialized platform that compiles and
-      organizes comprehensive information on milk oligosaccharides across
-      mammalian species. These oligosaccharides, which are complex
-      carbohydrates, play a critical role in biological processes such as infant
-      nutrition, gut health, and immune system modulation. The data included in
-      HoloOligo is automatically extracted from scientific text sources (e.g.,
-      research articles, reviews, and experimental studies) through advanced
-      text-mining techniques. This ensures that the database remains up-to-date
-      and offers a reliable resource for researchers and scientists working in
-      fields such as glycomics, nutrition science, and bioinformatics. The
-      platform provides a search functionality that allows users to efficiently
-      navigate through the dataset, explore specific types of oligosaccharides,
-      identify their biological associations (e.g., species, lactation stages,
-      methodologies), and directly access the sources of information. Whether
-      you are looking to understand the distribution of milk oligosaccharides,
-      analyze their role in mammalian physiology, or explore their potential
-      applications in research and industry, the HoloOligo database serves as a
-      comprehensive and user-friendly resource.
-      <a class="text-info" href="about">Click Here For More information.</a>
+<script src="{{ url_for('static', filename='js/home.js') }}" defer></script>
+<link
+  rel="stylesheet"
+  href="{{ url_for('static', filename='css/home.css') }}"
+/>
+
+<!-- Header Section -->
+<section class="hero-section py-5 text-white text-center">
+  <div class="container">
+    <img
+      src="{{ url_for('static', filename='img/logo_Omnicrobe_3_resize.png') }}"
+      alt="Omnicrobe"
+      class="logo mb-4"
+    />
+    <h1 class="display-4 font-weight-bold mb-3">
+      Welcome to HoloOligo Database
+    </h1>
+    <p class="description mx-auto">
+      Explore comprehensive information on milk oligosaccharides across
+      mammalian species. Discover their roles in nutrition, gut health, and
+      immune modulation through curated data from scientific sources.
     </p>
-  </div>
-
-  <div class="col-12 col-md-3 position-relative p-4 pl-md-0">
-    <center>
-      <img
-        src="{{ url_for('static', filename='img/logo_Omnicrobe_3_resize.png') }}"
-        alt="Omnicrobe"
-        class="logo"
-      />
-    </center>
-  </div>
-</div>
-
-<!-- Section Data Overview -->
-<section class="data-overview">
-  <h1 class="text-center section-title">HoloOligo Data Overview</h1>
-
-  <!-- Grid for table and charts -->
-<div class="row">
-  <!-- Table of entities and number of occurrences -->
-  <div class="col-12 col-md-4 table-container">
-    <h2>Entities Table</h2>
-    <table id="entitiesTable" class="table table-striped">
-      <thead>
-        <tr>
-          <th>Entity</th>
-          <th>Number of Occurrences</th>
-        </tr>
-      </thead>
-      <tbody id="entitiesTableBody"></tbody>
-    </table>
-  </div>
-
-  <!-- Chart: Distribution of Oligosaccharide Types -->
-  <div class="col-12 col-md-4 chart-container">
-    <h2>Distribution of Oligosaccharide Types</h2>
-    <canvas id="taxonsChart"></canvas>
-  </div>
-
-  <!-- Chart of types by taxon -->
-  <div class="col-12 col-md-4 chart-container">
-    <h2>Explore the oligosaccharide types associated with different taxa</h2>
-    <select id="taxonSelect" class="form-control mb-3">
-      <option value="taxon1">Sus scrofa</option>
-      <option value="taxon2">Homo sapiens</option>
-      <option value="taxon3">Bos taurus</option>
-      <option value="taxon4">Daubentonia madagascariensis</option>
-    </select>
-    <canvas id="taxonOligoChart"></canvas>
-  </div>
-</div>
-
-<!-- Section for additional charts -->
-<section class="additional-graphs">
-  <h1 class="text-center section-title">Other Visualizations</h1>
-  <div class="row">
-    <!-- Chart: Distribution of oligosaccharide types by taxon -->
-    <div class="col-12 col-md-6 chart-container">
-      <h2>Percentage Distribution of Oligosaccharide Types by Taxon</h2>
-      <canvas id="stackedBarChart"></canvas>
-    </div>
-
-    <!-- Chart: Distribution by lactation stage -->
-    <div class="col-12 col-md-6 chart-container">
-      <h2>Distribution of Oligosaccharide Types by Lactation Stage</h2>
-      <canvas id="lactationChart"></canvas>
-    </div>
+    <a href="about" class="btn btn-info btn-lg mt-3">Learn More</a>
   </div>
 </section>
 
-
-
-  <!-- Chart : Taxon - Sample and Sample - Lactation Relationships -->
-  <div class="row">
-    <div class="col-12 col-md-6 chart-container">
-      <h3>Taxon - Sample Relationship</h3>
-      <canvas id="taxonSampleChart"></canvas>
-    </div>
-    <div class="col-12 col-md-6 chart-container">
-      <h3>Sample - Lactation Stage / Oligo Type Relationship</h3>
-      <canvas id="sampleCharacteristicsChart"></canvas>
-    </div>
-  </div>
-
-  <!-- CHart : Sample characteristics charts -->
-  <div>
-    <h1 class="text-center">Sample Characteristics Visualization</h1>
-    <div class="row">
-      <div class="col-12 col-md-6 chart-item">
-        <h2 class="text-center">Milk</h2>
-        <canvas id="milkChart"></canvas>
+<!-- Data Visualization Section -->
+<section class="data-overview my-5">
+  <div class="container">
+    <h2 class="text-center section-title mb-5">HoloOligo Data Overview</h2>
+    <div class="row visualization-row">
+      <div class="col-md-4">
+        <div class="viz-card">
+          <h3>Entities Overview</h3>
+          <div class="table-wrapper">
+            <table id="entitiesTable" class="table table-striped">
+              <thead>
+                <tr>
+                  <th>Entity</th>
+                  <th>Count</th>
+                </tr>
+              </thead>
+              <tbody id="entitiesTableBody"></tbody>
+            </table>
+          </div>
+        </div>
       </div>
-      <div class="col-12 col-md-6 chart-item">
-        <h2 class="text-center">Pooled Milk</h2>
-        <canvas id="pooledMilkChart"></canvas>
-      </div>
-    </div>
-  </div>
 
-   <!-- Section for Heatmap and Stacked Bar Chart -->
-<section class="relationship-graphs">
-  <div class="row">
-    <!-- Heatmap Chart: Relationship between lactation stage and taxon -->
-    <div class="col-12 col-md-6 chart-container">
-      <h2>Lactation Stage / Taxon Relationship</h2>
-      <canvas id="heatmapChart"></canvas>
-    </div>
+      <div class="col-md-4">
+        <div class="viz-card">
+          <h3>Oligosaccharide Types</h3>
+          <canvas id="taxonsChart"></canvas>
+        </div>
+      </div>
 
-    <!-- Stacked Bar Chart: Relationship between milk and oligosaccharide types -->
-    <div class="col-12 col-md-6 chart-container">
-      <h2>Milk / Oligosaccharide Types Relationship</h2>
-      <canvas id="stackedBarChart2"></canvas>
+      <div class="col-md-4">
+        <div class="viz-card">
+          <h3>Species Distribution</h3>
+          <div class="coming-soon">
+            <i class="fas fa-chart-line"></i>
+            <p>Coming Soon</p>
+          </div>
+        </div>
+      </div>
     </div>
   </div>
 </section>
 
-    
-
-        {% endblock %}
-      </div>
-    </div>
-  </div>
-</section>
\ No newline at end of file
+{% endblock %}
-- 
GitLab


From 0785bedb4aa620ea6b6652fa6e05f954acf008b1 Mon Sep 17 00:00:00 2001
From: "hajar.bouamout" <hajar.bouamout@inrae.fr>
Date: Thu, 2 Jan 2025 17:49:06 +0100
Subject: [PATCH 14/51] =?UTF-8?q?Ajout=20de=20la=20premi=C3=A8re=20version?=
 =?UTF-8?q?=20de=20la=20fonctionnalit=C3=A9=20de=20recherche=20simple=20et?=
 =?UTF-8?q?=20avanc=C3=A9e=20avec=20des=20donn=C3=A9es=20fictives?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 static/css/research.css | 227 ++++++++++++++++++++++++++++++
 static/js/research.js   | 302 ++++++++++++++++++++++++++++++++++++++++
 templates/research.html |  93 +++++++++++++
 3 files changed, 622 insertions(+)
 create mode 100644 static/css/research.css
 create mode 100644 static/js/research.js
 create mode 100644 templates/research.html

diff --git a/static/css/research.css b/static/css/research.css
new file mode 100644
index 0000000..ae8ff87
--- /dev/null
+++ b/static/css/research.css
@@ -0,0 +1,227 @@
+/* General Styles */
+body {
+    font-family: 'Arial', sans-serif;
+    margin: 0;
+    padding: 0;
+    background-color: #f9f9f9;
+    line-height: 1.6;
+    color: #333;
+}
+
+/* Container */
+.container {
+    max-width: 1200px;
+    margin: 20px auto;
+    padding: 20px;
+    background-color: #ffffff;
+    border-radius: 8px;
+    box-shadow: 0 4px 10px rgba(0, 0, 0, 0.1);
+    margin-top: 100px;
+}
+
+/* Navbar */
+.navbar {
+    background-color: #333;
+    padding: 15px 20px;
+    border-radius: 8px;
+    margin-bottom: 20px;
+}
+
+.nav-list {
+    list-style: none;
+    display: flex;
+    justify-content: center;
+    gap: 20px;
+    margin: 0;
+    padding: 0;
+}
+
+.nav-list li {
+    position: relative;
+}
+
+.search-btn {
+    background-color: #007bff;
+    color: white;
+    padding: 10px 20px;
+    border: none;
+    border-radius: 6px;
+    font-size: 1rem;
+    cursor: pointer;
+    transition: background-color 0.3s ease, transform 0.2s ease;
+}
+
+.search-btn:hover {
+    background-color: #0056b3;
+    transform: scale(1.05);
+}
+
+.search-btn:focus {
+    outline: none;
+    box-shadow: 0 0 5px rgba(0, 123, 255, 0.7);
+}
+
+/* Main Content */
+.main-content {
+    margin-top: 20px;
+}
+
+/* Sections */
+.search-section,
+.advanced-search-section,
+.results-section {
+    margin-bottom: 40px;
+}
+
+.search-section h2,
+.advanced-search-section h2,
+.results-section h2 {
+    font-size: 2rem;
+    color: #0056b3;
+    margin-bottom: 20px;
+    text-align: center;
+    font-weight: bold;
+}
+
+.search-bar {
+    display: flex;
+    flex-wrap: wrap;
+    gap: 15px;
+    justify-content: center;
+    align-items: center;
+}
+
+.search-bar input,
+.search-bar select,
+textarea {
+    padding: 10px;
+    font-size: 1rem;
+    border: 1px solid #ddd;
+    border-radius: 6px;
+    width: 300px;
+}
+
+.search-bar input:focus,
+.search-bar select:focus,
+textarea:focus {
+    outline: none;
+    border-color: #007bff;
+    box-shadow: 0 0 5px rgba(0, 123, 255, 0.7);
+}
+
+.autocomplete-box {
+    background-color: #ffffff;
+    border: 1px solid #ddd;
+    border-radius: 6px;
+    max-width: 300px;
+    margin: 5px auto;
+    box-shadow: 0 2px 6px rgba(0, 0, 0, 0.1);
+    position: absolute;
+    z-index: 10;
+}
+
+.autocomplete-box div {
+    padding: 10px;
+    cursor: pointer;
+    border-bottom: 1px solid #f1f1f1;
+}
+
+.autocomplete-box div:hover {
+    background-color: #f1f1f1;
+}
+
+/* Results Table */
+.results-table {
+    width: 100%;
+    border-collapse: collapse;
+    margin: 0 auto;
+    font-size: 1rem;
+}
+
+.results-table th,
+.results-table td {
+    padding: 12px 15px;
+    border: 1px solid #ddd;
+    text-align: center;
+}
+
+.results-table th {
+    background-color: #007bff;
+    color: white;
+    font-weight: bold;
+}
+
+.results-table tr:nth-child(even) {
+    background-color: #f9f9f9;
+}
+
+.results-table tr:hover {
+    background-color: #f1f1f1;
+    cursor: pointer;
+}
+
+.details-btn {
+    background-color: #28a745;
+    color: white;
+    padding: 8px 12px;
+    border: none;
+    border-radius: 4px;
+    font-size: 0.9rem;
+    cursor: pointer;
+    transition: background-color 0.3s ease;
+}
+
+.details-btn:hover {
+    background-color: #218838;
+}
+
+/* Advanced Search */
+.advanced-search-section textarea {
+    width: 100%;
+    height: 120px;
+    resize: none;
+}
+
+.advanced-btn {
+    background-color:  #007bff;
+    color: white;
+    padding: 10px 20px;
+    border-radius: 6px;
+    font-size: 1rem;
+    border: none;
+    cursor: pointer;
+    transition: background-color 0.3s ease;
+}
+
+.advanced-btn:hover {
+    background-color: #5a6268;
+}
+
+/* Accessibility Enhancements */
+button:focus,
+input:focus {
+    outline: none;
+    box-shadow: 0 0 5px rgba(0, 123, 255, 0.7);
+}
+
+/* Mobile Responsiveness */
+@media (max-width: 768px) {
+    .search-bar {
+        flex-direction: column;
+        gap: 10px;
+    }
+
+    .navbar {
+        flex-wrap: wrap;
+        text-align: center;
+    }
+
+    .search-btn {
+        width: 100%;
+        margin: 5px 0;
+    }
+
+    .results-table {
+        font-size: 0.9rem;
+    }
+}
diff --git a/static/js/research.js b/static/js/research.js
new file mode 100644
index 0000000..73c43a9
--- /dev/null
+++ b/static/js/research.js
@@ -0,0 +1,302 @@
+// Mock Data
+const dummyData = [
+    {
+        oligosaccharide: "2'-Fucosyllactose (2'-FL)",
+        sample: "Milk Sample A-123",
+        species: "Human",
+        lactationStage: "Early",
+        totalUsers: 3245
+    },
+    {
+        oligosaccharide: "3'-Sialyllactose (3'-SL)",
+        sample: "Milk Sample B-456",
+        species: "Cow",
+        lactationStage: "Mid",
+        totalUsers: 2890
+    },
+    {
+        oligosaccharide: "6'-Sialyllactose (6'-SL)",
+        sample: "Milk Sample C-789",
+        species: "Goat",
+        lactationStage: "Late",
+        totalUsers: 1567
+    },
+    {
+        oligosaccharide: "Lacto-N-tetraose (LNT)",
+        sample: "Milk Sample D-101",
+        species: "Human",
+        lactationStage: "Early",
+        totalUsers: 4102
+    },
+    {
+        oligosaccharide: "Lacto-N-neotetraose (LNnT)",
+        sample: "Milk Sample E-112",
+        species: "Human",
+        lactationStage: "Mid",
+        totalUsers: 3678
+    },
+    {
+        oligosaccharide: "Lacto-N-fucopentaose I (LNFP-I)",
+        sample: "Milk Sample F-131",
+        species: "Human",
+        lactationStage: "Late",
+        totalUsers: 2456
+    },
+    {
+        oligosaccharide: "3'-Galactosyllactose (3'-GL)",
+        sample: "Milk Sample G-415",
+        species: "Rabbit",
+        lactationStage: "Early",
+        totalUsers: 890
+    },
+    {
+        oligosaccharide: "4'-Galactosyllactose (4'-GL)",
+        sample: "Milk Sample H-521",
+        species: "Rabbit",
+        lactationStage: "Mid",
+        totalUsers: 765
+    },
+    {
+        oligosaccharide: "Sialyl-lacto-N-tetraose a (LSTa)",
+        sample: "Milk Sample I-634",
+        species: "Sheep",
+        lactationStage: "Early",
+        totalUsers: 1234
+    },
+    {
+        oligosaccharide: "Sialyl-lacto-N-tetraose b (LSTb)",
+        sample: "Milk Sample J-747",
+        species: "Sheep",
+        lactationStage: "Mid",
+        totalUsers: 1567
+    },
+    {
+        oligosaccharide: "Sialyl-lacto-N-tetraose c (LSTc)",
+        sample: "Milk Sample K-858",
+        species: "Horse",
+        lactationStage: "Late",
+        totalUsers: 678
+    }
+];
+
+// Global variable to store current data
+let currentData = [...dummyData];
+
+// Toggle between Simple and Advanced Search
+function toggleSearch(type) {
+    const simpleSection = document.getElementById('simple-search-section');
+    const advancedSection = document.getElementById('advanced-search-section');
+    
+    if (type === 'simple') {
+        simpleSection.style.display = 'block';
+        advancedSection.style.display = 'none';
+        // Clear advanced search
+        document.getElementById('advanced-search-input').value = '';
+    } else if (type === 'advanced') {
+        simpleSection.style.display = 'none';
+        advancedSection.style.display = 'block';
+        // Clear simple search
+        document.getElementById('simple-search').value = '';
+        document.getElementById('autocomplete-suggestions').innerHTML = '';
+    }
+    
+    // Reset results
+    currentData = [...dummyData];
+    populateResults(currentData);
+}
+
+// Simple Search Implementation
+document.querySelector('#simple-search-section .search-btn').addEventListener('click', performSimpleSearch);
+document.getElementById('simple-search').addEventListener('keyup', function(event) {
+    if (event.key === 'Enter') {
+        performSimpleSearch();
+    }
+});
+
+function performSimpleSearch() {
+    const searchType = document.getElementById('simple-search-type').value;
+    const searchQuery = document.getElementById('simple-search').value.toLowerCase().trim();
+
+    if (!searchQuery) {
+        currentData = [...dummyData];
+        populateResults(currentData);
+        return;
+    }
+
+    const filteredData = dummyData.filter(item => {
+        switch(searchType) {
+            case 'oligosaccharides':
+                return item.oligosaccharide.toLowerCase().includes(searchQuery);
+            case 'species':
+                return item.species.toLowerCase().includes(searchQuery);
+            case 'samples':
+                return item.sample.toLowerCase().includes(searchQuery);
+            case 'lactation-stage':
+                return item.lactationStage.toLowerCase().includes(searchQuery);
+            default:
+                return true;
+        }
+    });
+
+    currentData = filteredData;
+    populateResults(filteredData);
+}
+
+// Autocomplete for Simple Search
+function autocompleteSearch(query) {
+    if (!query) {
+        document.getElementById('autocomplete-suggestions').innerHTML = '';
+        return;
+    }
+
+    const searchType = document.getElementById('simple-search-type').value;
+    const suggestions = new Set();
+    const queryLower = query.toLowerCase();
+
+    dummyData.forEach(item => {
+        let value = '';
+        switch(searchType) {
+            case 'oligosaccharides':
+                value = item.oligosaccharide;
+                break;
+            case 'species':
+                value = item.species;
+                break;
+            case 'samples':
+                value = item.sample;
+                break;
+            case 'lactation-stage':
+                value = item.lactationStage;
+                break;
+        }
+        if (value.toLowerCase().includes(queryLower)) {
+            suggestions.add(value);
+        }
+    });
+
+    const suggestionBox = document.getElementById('autocomplete-suggestions');
+    suggestionBox.innerHTML = '';
+
+    if (suggestions.size > 0) {
+        Array.from(suggestions)
+            .slice(0, 5)
+            .forEach(item => {
+                const div = document.createElement('div');
+                div.textContent = item;
+                div.onclick = () => {
+                    document.getElementById('simple-search').value = item;
+                    suggestionBox.innerHTML = '';
+                    performSimpleSearch();
+                };
+                suggestionBox.appendChild(div);
+            });
+    }
+}
+
+// Advanced Search Implementation
+document.querySelector('#advanced-search-section .advanced-btn').addEventListener('click', performAdvancedSearch);
+document.getElementById('advanced-search-input').addEventListener('keyup', function(event) {
+    if (event.key === 'Enter') {
+        performAdvancedSearch();
+    }
+});
+
+function performAdvancedSearch() {
+    const query = document.getElementById('advanced-search-input').value.trim();
+    
+    if (!query) {
+        currentData = [...dummyData];
+        populateResults(currentData);
+        return;
+    }
+
+    try {
+        const filteredData = dummyData.filter(item => {
+            const andConditions = query.split('AND').map(condition => condition.trim());
+            
+            return andConditions.every(condition => {
+                if (condition.includes('NOT')) {
+                    const [field, value] = parseSearchCondition(condition.replace('NOT', '').trim());
+                    return !matchesCondition(item, field, value);
+                } else {
+                    const [field, value] = parseSearchCondition(condition);
+                    return matchesCondition(item, field, value);
+                }
+            });
+        });
+
+        currentData = filteredData;
+        populateResults(filteredData);
+    } catch (error) {
+        alert('Invalid search query. Please use format: field: "value" \nExample: species: "human" AND stage: "early"');
+    }
+}
+
+// Helper function to parse search conditions
+function parseSearchCondition(condition) {
+    const matches = condition.match(/(\w+):\s*["'](.+?)["']/);
+    if (!matches) {
+        throw new Error('Invalid search syntax');
+    }
+    return [matches[1], matches[2]];
+}
+
+// Helper function to check if an item matches a condition
+function matchesCondition(item, field, value) {
+    const searchValue = value.toLowerCase();
+    switch(field.toLowerCase()) {
+        case 'species':
+            return item.species.toLowerCase().includes(searchValue);
+        case 'stage':
+            return item.lactationStage.toLowerCase().includes(searchValue);
+        case 'samples':
+            return item.sample.toLowerCase().includes(searchValue);
+        case 'oligosaccharide':
+            return item.oligosaccharide.toLowerCase().includes(searchValue);
+        default:
+            return false;
+    }
+}
+
+// Update the populateResults function
+function populateResults(data) {
+    const resultsBody = document.getElementById("results-body");
+    resultsBody.innerHTML = "";
+
+    if (data.length === 0) {
+        const row = document.createElement("tr");
+        row.innerHTML = `
+            <td colspan="5" style="text-align: center; padding: 20px;">
+                No results found. Please try a different search.
+            </td>
+        `;
+        resultsBody.appendChild(row);
+        return;
+    }
+
+    data.forEach((item) => {
+        const row = document.createElement("tr");
+        row.innerHTML = `
+            <td>${item.oligosaccharide}</td>
+            <td>${item.sample}</td>
+            <td>${item.species}</td>
+            <td>${item.lactationStage}</td>
+            <td><button class="details-btn" onclick="showDetails('${item.oligosaccharide}')">Details</button></td>
+        `;
+        resultsBody.appendChild(row);
+    });
+}
+
+// Details function
+function showDetails(oligosaccharide) {
+   window.location.href = `sheet?oligosaccharide=${encodeURIComponent(oligosaccharide)}`;
+}
+
+
+
+// Initialize on page load
+window.onload = function() {
+    toggleSearch('simple');
+    currentData = [...dummyData];
+    populateResults(currentData);
+};
\ No newline at end of file
diff --git a/templates/research.html b/templates/research.html
new file mode 100644
index 0000000..d0b99e9
--- /dev/null
+++ b/templates/research.html
@@ -0,0 +1,93 @@
+{% extends 'main3' %} {% block content %}
+
+<head>
+  <link
+    rel="stylesheet"
+    href="{{ url_for('static', filename='css/research.css') }}"
+  />
+  <script
+    src="{{ url_for('static', filename='js/research.js') }}"
+    defer
+  ></script>
+</head>
+
+<body>
+  <div class="container">
+    <!-- Left Navigation Bar -->
+    <nav class="navbar">
+      <ul class="nav-list">
+        <li>
+          <button class="search-btn" onclick="toggleSearch('simple')">
+            Simple Search
+          </button>
+        </li>
+        <li>
+          <button class="search-btn" onclick="toggleSearch('advanced')">
+            Advanced Search
+          </button>
+        </li>
+      </ul>
+    </nav>
+
+    <!-- Main Content -->
+    <div class="main-content">
+      <!-- Simple Search -->
+      <section id="simple-search-section" class="search-section">
+        <h2>Simple Search</h2>
+        <div class="search-bar">
+          <span>Search By:</span>
+          <select id="simple-search-type">
+            <option value="oligosaccharides">Oligosaccharides</option>
+            <option value="species">Species</option>
+            <option value="samples">Samples</option>
+            <option value="lactation-stage">Lactation Stage</option>
+          </select>
+          <input
+            type="text"
+            id="simple-search"
+            placeholder="Enter a keyword to begin..."
+            onkeyup="autocompleteSearch(this.value)"
+          />
+          <div id="autocomplete-suggestions" class="autocomplete-box"></div>
+          <button class="search-btn">Search</button>
+        </div>
+      </section>
+
+      <!-- Advanced Search -->
+      <section
+        id="advanced-search-section"
+        class="advanced-search-section"
+        style="display: none"
+      >
+        <h2>Advanced Search</h2>
+        <p>Use logical operators to create more complex queries.</p>
+        <textarea
+          id="advanced-search-input"
+          placeholder="Example: species: 'rabbit' AND stage: 'early' NOT samples: 'milk'"
+        ></textarea>
+        <button class="search-btn advanced-btn">Search</button>
+      </section>
+
+      <!-- Results Table -->
+      <section id="results-section" class="results-section">
+        <h2>Search Results</h2>
+        <table class="results-table">
+          <thead>
+            <tr>
+              <th>Oligosaccharide</th>
+              <th>Sample</th>
+              <th>Species</th>
+              <th>Lactation Stage</th>
+              <th>Details</th>
+            </tr>
+          </thead>
+          <tbody id="results-body">
+            <!-- Rows will be dynamically populated by JavaScript -->
+          </tbody>
+        </table>
+      </section>
+    </div>
+  </div>
+</body>
+
+{% endblock %}
-- 
GitLab


From 9bf4ed122d0d27e74f00a689041f54d8c2c9afd1 Mon Sep 17 00:00:00 2001
From: "hajar.bouamout" <hajar.bouamout@inrae.fr>
Date: Thu, 2 Jan 2025 17:52:39 +0100
Subject: [PATCH 15/51] ajout dune structure 3D pour exemple dans la fiche

---
 static/img/2'-Fucosyllactose.png | Bin 0 -> 5311 bytes
 1 file changed, 0 insertions(+), 0 deletions(-)
 create mode 100644 static/img/2'-Fucosyllactose.png

diff --git a/static/img/2'-Fucosyllactose.png b/static/img/2'-Fucosyllactose.png
new file mode 100644
index 0000000000000000000000000000000000000000..3852c228aa130ce91312576f70ce6ec6db51c325
GIT binary patch
literal 5311
zcmV;w6hP~VP)<h;3K|Lk000e1NJLTq009~R006TH0{{R3VF@D|0002GP)t-s|Ns90
ztHl5S005@K0I0(NpuPa2zW}Pm`2GF>p}qj5!1nz8>-hTe`}_c{#sHqZY{u7K!qmOw
z?AGt}hR@xz;OUjr;okE0+S%F8>+z!4<8W?op`f4$006}2?s>}EO1#i2Cn%`g<}I|#
z?Ck7YSy~hh5O{WXm6Vh<GBfn_^wZPRhJ}S278mgF@VdFV#l^)U9v^08Wl&8{nwgoW
zrlvtYKa7iuNk~XMIXbejvcJB*Xl7<FEG&0AmFoZi6TnGCK~#90?Oh97n>-W-!mTYJ
zcWku~iB_j`&fPz^{r|u9<s^YZ3kBD^_I>uONTGz6oNJPUB%N@=2|LBuPi^?L$KvnN
zK3j7@h=wY0w2W?z5#OVY_u8O?!T2nq|0illHx0fE1$%AL!2pNsBSq$knmWva2R)F+
zGT&^a#tw-=LeNXT$Im9#)?2tYSOc4HI1%kNJ|JzQ#zNR1`&gxPM1<`zwKq&nqM3Yy
zP-+liXrspS%8z$PO@}~fe1D+54{9u}Do}j0g_>k2Sfpx6P$Ru%YHDhDH8sW8k};Md
zBr^=(Ff|g+*oUun`ZXmrGNpzDV~X@G_Zq4>n9GMI{i%Uovwwja2~8lRy!_lCBHh76
z1IMo;P)KwhTbWw2e>I#tnua{My2pK1-`T=d%ry7e9oi}1;oHpz>YTE%zJCi9>yd3H
z*q{%~joF@b8`ShbG9ig1Wt<O^?VXyD&YvQQw@uATF*Van)(nqQGja&^hKXbDoti>=
za<Xk|<Vo8%R*unt#6mBdA(2T8MEaQTaP~t@%rDQhqZ^vGZI7azQZo)6s_OCsw9lc-
zKNG6<Tzvo-k`>3NlQ?1u)aMU5iTYltks22bobW)CS~Y4y$u!MX7Rqvv=Mo+0z+C$B
z-d(JTnn(+iS2cH+h<TtZ1$rM{L)g&~^*JQW?=)J~#cF8mHICc&^xY#Dw+3CMlbW%{
zKfP>I)cD%rCi@Z*6uWK@Y9^R}0w0^9Mk2WH`MU>~kuf~IPHHmI{l_#+#9j>W)}&^9
zmcF8~yM-k?aqMc)?#@6V;{mi305!w~;5Dg{dj5bp@v!Unz1F6XyB@a_IlpugE*?RH
z2rC@TsR1WwLjpx5x{vv{s27-r2=~3%t`N~CC1=6h(x>v~sF7T`$H|z9y=laKueJ%u
z`KoWtNeb%7aHS#bQiY!kF7(EzvGmpmVt$MWqqgLzHzU_q`dl6w<dWy6S`5hoOPE?G
z-yk(osCFiZQqi-@{QE8-XKmk@MD-=AqIEmNQg+5D$Yjcm?Lk8~N6iQ=DYr!w-q)xr
z2+#RN5+?aUhH<tWh1h<th;5>`WRyU|xcUfZ5^-dDA@O735E(j#bI7X$1-Gq1aeE^K
z3Tn(jM_eJ?i(n{$)9yx5c2-wU<Cq{c)XF%&9co*r31TACyYW29&caH|N5Poip~ZKO
zdWXzBl57+RqqXY_l+<+f8eu2`YC`P+Gq}N7$!0Ray5?lD9zk|U&HPpKSmI&R^Rj(c
z)ns)z8ta4JfpsSWJ!kocX!-8)_B%Fx*BF(qmUY%KE2lzDK_{PzU`4JWk{{elO=2=Y
zxK*^w1}Uf1LVrsLCZ=R<GL3>UZ6W{l#op|Ajc3rd4Cv9L(n9%NhF(yUK=w&=MTl-v
zSsP+;)$v)Oe(cCYT1!qOM)m&9(~vGCWMXaO4!l3eD;KGy&6}dkap(+aALECSu=>%C
zP{wRTT`sdG%-|<kTHa|rYJ*Ig>MrH*N2sczAPreQ&;<3iJpJLQg*YTJ)-)W?b?QQt
zX-8C~tIspg!o&)&+-18%906jZG@*;W(DGBDeUmn3Qd961hhiKOZCFV|64dR7y&Czj
zlAWOn&CulHX;!1mWI}X(p{Y`U5mMbQOIFo2)m~FUqwJ1YW9E;-7H%jNIh7iZssP0Z
zZNaxPWmK1IY6dl-3X3Q+%^Ev6oDKUrd(E7hs;-%%UE}j4H5cH_5Um?5KB5G*8uhgh
zE{mx}p9_diqDQbj9FTB@$6<DL<_a|vaV@W=pU|osqdJ9|AZs{D!AQIQ(xV^-+DgjS
zLQS`3!t;`42kV1&V=B-UR8*+3_|UOc(=9RTkjassAx%|Li&Hp3244LG{|Z+{&G$}?
zy3_ECmS7H7+o%dP)XB~*E2?!9d)Oy*4`MfJX3#=1+EUUeK}NF&(;FQ@ML~@U|3_4v
zJGI0@rmlB&Y#4n~DF67|!!`Y-_IS7()?j4@rV|s|X||RzN|C%~$|cwST@8BcUE5M+
zS>4_+E0NXC6vS$@1Qk6HoUNxPupzIj4^|<feR4hPw_@nZjEO_SR%O&b#ove=$%~HJ
zW+5Bvn!nbetC2(UG{SAvr|Yd4v8g!8TL_=#h-tT3FVoRFbR}jjwGEA}IT}dCY2B80
zV1#6&GfD(d@1li*Ho-vr_+mhI0nu4wZ!&$)aT{_-OQ%zD>euiU5Q%sX%$(&SO((Tm
z%v8BE46$-gMbsx%-L#=GNppg&oVcwv3Xa?`^8hk7h$>fgNWyfb!^FgCT?-;<b82h@
zkF6xus+J)EZMG^-N<)HFgU_ZmknAlx$<0GoFxi8_X);8UrMS|Lu!_WW=xrkv$L-1p
z12rwKe1BA^5z?Qd>i3?}uFjGPZLTU;VIb98@Y|b*u2`-d&_vB*gaO$p)sX9;OnH-L
zB|dS`1}t}l8rc`^s`ipGbejgZ)Q(&Sm5&h~s45yy*}-|0oyI70Wv>a<N>-UhYy~fd
ziX20pKMwf2S@rmM{lq7w1}1j_HHGI&YRZAYoi9i>8w4?of)<41Br~EAQ&v>b<Vsk+
zJajc4OV-(3*O&`Rs?yIAxDqEEA>!sqq$jqYk)bLsZ_sOztfG2sKab!>*7s=;(g8Hu
zC>0~A2>>X2wW1WM(lu(2jSqv2SeTqd8IjpDh89l*JGCg&_NlU`o!t=A8MKjP5q(${
z!$La=Ug%G$ju-P)!(wI_ZAGoqswCz^L$L-k<u~F6Yh#PT_A1oix^8fc(yuhrY_4>n
zyHtcd7L)R&QINaN5PB75hi8<_C^Lz%E;75J@M}DNr&!ampps9=2tw$YDpR;=*#q;z
zTzrBF<XPvc2Qm;TlOt=Luy#&OscY;raaB@REfcu91FlP@C2-pd10S{KjK(oMRuv6_
z9UokTQJNVrI3XA`9pWb`E+atdvOr2IVP4=k1ags#!>Fcc%|(km1_DK+z$A%b+VLia
z+be2V7wT6|L7S9K8iA}Ec;0_0EpmhM%k{-wmLF0Rrt2h>z3K>vxXsX^(pb}CX{KsU
zrecRmILY#0>HeBVDXHpl5U3vLhQ(NNv$ym*RHzY*GygP)9I&{NjH}j)(rtEhnxkw`
zKL`yQ2SOVFa^!fEaidFT>n#Zwi`q*)14mNyNoNB=LWP=$FMxw_ONr;~4d(q@sH$|+
z*3sJbDBBEP^AOu9%#7BrD5*(x-ROF0Fov^Apy29ZG$Bs;z^H}LsOgYgLwH#E>I}uU
zCx}{l*9~u!8jnAtn03I^#a`V!QPZIh!5%Lv-6m{%f@pW%Z@#2<CzC8`RA)^3#UpE`
zpE{8A$omcX0~`$xZOK5t38MdsKE!+6BaBeTal41R#hH!iSr1*FusPM^PNlSaSlSjQ
zCJ6LX@~MG{(PNtG?y+)O*;<JDj@tx&^F+J-!^*>W8|LAVR~+?2J|LMZ%NsWk%Xz<J
zL&DRi8&}6mapmzL6Sa?q8y+3&G0FYVQDg}5W(VR;M4Cn`jtWIGAlvXnF*akc9=k)C
zE+>OsDP}tkyi6C`5;ZKE8|Y-7MzRekOn@OG5OX6(s~5NI8{4A>08>AUS-37PKMHCN
zE^w+r7O}UtErSxktZGOXh$1MEcsmYi3iZ2*EL$6r39-w}jHw3YWaI5j_uLe6K29=j
z9^~I3f+Du2{nQs}$it>aa<BzMo?Ca&s?<adFVl74)Yw=@Lv{NLQtQ;PE%UH-4TYWT
zqJ_oS0hG!+4mG?xh^b4#;8=_|Al}LPZZR;7-D9H0!@IbONk}yIiEJN>Hw^H$I9<1j
zn8+jq@8&pSD8R0$IYOMMX~l_}R-CA5#fh3$oTzEViJDfNsA<KCnpT{sX~mnRCe28;
z-n_FnNe#^0(+z`^<r<o?Y8=suylt)q-4CF?iH`FGg?wIoWjL$~+m(@un}@Wa=7o-j
zJFnxoP1un;)Ep*AV&L8MT^TB&EcTEQr6mbMZRz%5S;iUsM7F0w^xHrZS4z-S7j^}e
zN+<<HaxJbeje}(w1K!O7?eON&{S!uhW<Y(Da-P}3azM~N8mTN+6BBYrdO5RvlxFgo
zTvo9m>#hbp2tW}sy}qWRVS4Mxch$0{d0A^u3{P5%%Q7Y%)kls3rgOHurlMtTE~scG
zTIJ$5nCTA77>4zquu)gdnWMmD+03k%N^ecDHkmISq151pT5ujZ`q_vrSUoq_9!Ykk
z*96PPJw*pTxcblNQP+J~Sx>eMN5va$(BYs*NfohXHEEoy8ms7Vi=VHB71cdUM0|;#
zSWi}mg|=J#V}CF^Yr+CN6#El4Xt)GyY`6Hw{typ)Eimvsf*Y4dL}+_uyY`Dw+nUe5
zkd5t??b<I^uKDb9zPeOk;f)|!b9q&Ox+~orDO%Tj_VnS1ap=<w{}nB@-dM$pu0_m%
zyrE)@xwUm;J4I7m2`lwgQ9vSFUGvkHjm27TW2_DhR#-pef)*TSj%#_%Ck?Bs6^&LD
zOaQp*VsRv2ixX>%ArP;YK|MY!#Fc3#&x^4XHGE{$R%3|QMyk7e;w2UE!rodL)MG<b
zeH%pT8iE%ns)HS8UYy0?#aWhX9z!{f+MYn?2SHi<qo$^;^#<8;DD`9*ln&zNfn@0s
z)KPP)C4J<DO4%_~Myh+r#kv8gYIMv3H5o8pZ4`MbD}0A4byA9Qiw%XK3J1?(y1H(T
zig!lXnk|LA=+y8C!wB~B3RVzMRiR77{#>Ed@_q~D!&H$Jh5~hq%SPwaSW@WOP<1Lj
zLV*fp$bLfwCXz)9F3e)~!CELfCwmcl|9kD_@8+Bus10(wx`xUF6kr0yvV_LGUoyc)
zMKLpRD&0NXcOg#oMMM@L^N6WQhhE%VfT=z2Clqs8VNn#rgxB-%p*l-U{f@~oTc}iP
z{VHGeiYHbZPjnv4hw8*TWB`0RzBP=Fo0`@bptHVR5EEA9auQWvWeu=pGKoU=c9Y{Z
z-tE+Mzd=l5#or91H@wOkUVh2UTP{ks9pB`VR%*Il5m924ztMq&R%*g+ye8+U&_+$4
zcU-=4v{4fsp<};ctguk;9Zl3&W8nlQ{JV|50`PdSOpQe}N7g*Ldn9~5{01fz{R5V$
zF%1{qd<~gD6IE)2zCSEcGvR3{TOXgOS)iui0mtv2nzIFJin6OT_A%86N?8OOu6=bZ
zNETJBA>97hlT2B5DC8X!&^QWIsd;AtHRb|ivpB$v!f+vIt_svUqbB6pfdt-s5U5U;
zk@`ex{C?GNEU1CNnvVq3%d$?2@)hsTcvq+?vfDLpSG;5eMxfp?HA1!)Ui(X>%<~Yj
z=Y>zUR!r`|5R(w#8fJOR{=x(gKNi#U#p{gH&biia12M?}j2a;*oiDS0ClCT<p%XQW
zsOXxaR%i4^r-{E76>5rCjAw6kt<Eb^p~eyp&9+{AeQc<@e3?vbPeM-e#1Ufl!2$&-
z93pk-of799wumPAhnXaAV}9=m?+@n>=hFSd!~MS7u^F8Iy!m?Z9k%W+F3Y{YFK!tw
zUiV{PlrPe`qFisZh5N#tGF9lm4|MaZ@~7N=smv6H*L8r4=|w9wA3r{<)zV$#voibo
z@^m{>UL@&eI`1Qw)5p7S6nC%txmDCCaE&9v)5jb5c$`uWZk3Pa{>$mC;pqEwanqlc
zHaIHOl*bkuv*}Cgk9^v|t!xJmQ-x}qpUPa<%&GaM+)C1mqR>0Ip#pYArQ-T4-S|K^
z&VRt3&)16b8D#KzPR%(S!n(;V{hU2XAC>3lDZK#uk-wkIbLqw}y7B8k)zgdeIHNk{
z;oEt+>vH=1mEzZvbOU|qNuf-An9V-S9;f%xU$#LB_&fV>`ybUuzoxgq;kS~SdwSPj
z{)0olDANy*bmJ$bW=0>tj~V}4y5i@4x}VLSzdp}C?D76v0gvx*@zAb+-cfu5YM2)O
zPBoCA=Ch(az<s~4jqAth<tNyXD52kJhxr7ZWiC*(J6undhiiq3(fuQ(_kK40elI;h
z2fM$T{w&XZQT|GB^7+a}?gbyIE&5jeb<PNxfg1h}IG<BP*`fzLozsmgy77hfl-c9s
z?F;3BO4Rw2@}sJ29&VqNXXW8DvvI${)0rtx&_UrxZl_<$b3e|0-2J?J1d%*2Tqw#-
zMb78FrqDGdHFwkh_@28dB|-W_S$Oylh-AWac?$%W)KCrcfs*s^8<Z3Wqvktv6K<zB
z(!&RS?kyEf!0(;ia!*j>-DsaLr&Hn4RC*1tMLWRv=_B3v3i?I5{(Ui{5B$6G;|lsp
zK@F1|N(S^AYJDC)UzfcGe&i2x6WF;AKc_eM*Vp%l=Rkj){e56q5cLW*vtQEv&EpKz
z#0%3k=b%46PnD<ZyRQ=XE5E5kJwHNMDyU(d1$5FUW%g6Lz5-SLJiEQVr@H474B|_1
z?&l}v`ChvJadB`as_4!Ymxkd|DX6(q;0Q{M#OyKCC}M+h^n7#0Nc=^$vIO67YOd)C
ze?iw!$pUX14B*XlMvXVva%!~1xifn1)l~VbD2HdEZlA9h9v8&w^6^nnbN^-bcyaj%
z+Vkht?CK-z{`Qw{(9ef2&(ml2yuVMGpLa34mCmQrYw3mB=9jA}HA0skX8e%rKUcHw
z{BQV?hZ}M3r`u<~=Z)egQ_UwV;puKx@uW|v;Ew{j^n?cdzI@tu6He%X{{ge-e`TJZ
R%o6|r002ovPDHLkV1fiIND2S|

literal 0
HcmV?d00001

-- 
GitLab


From 7fa1eb0eaef6c6572c6801b543518beb14e4a307 Mon Sep 17 00:00:00 2001
From: "hajar.bouamout" <hajar.bouamout@inrae.fr>
Date: Thu, 2 Jan 2025 17:54:08 +0100
Subject: [PATCH 16/51] ajout des main templates

---
 templates/main2 | 11 +++++--
 templates/main3 | 77 +++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 86 insertions(+), 2 deletions(-)
 create mode 100644 templates/main3

diff --git a/templates/main2 b/templates/main2
index f36c534..d6f6138 100644
--- a/templates/main2
+++ b/templates/main2
@@ -25,6 +25,14 @@
   <link rel="stylesheet" href="https://cdn.datatables.net/buttons/1.6.5/css/buttons.dataTables.min.css" />
   <link rel="stylesheet" href="https://cdn.datatables.net/responsive/2.2.9/css/responsive.dataTables.min.css" />
   <link rel="stylesheet" href="{{ url_for('static', filename='css/page_accueil.css') }}">
+  <link rel="stylesheet" href="{{ url_for('static', filename='css/home.css') }}">
+  <link rel="stylesheet" href="{{ url_for('static', filename='css/research.css') }}">
+  <link rel="stylesheet" href="{{ url_for('static', filename='css/results.css') }}">
+  <link rel="stylesheet" href="{{ url_for('static', filename='css/sheet.css') }}">
+  <link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0-beta3/css/all.min.css" rel="stylesheet">
+
+
+
 
   <!-- JS -->
   <script src="https://code.jquery.com/jquery-3.5.1.slim.min.js" integrity="sha384-DfXdz2htPH0lsSSs5nCTpuj/zy4C+OGpamoFVy38MVBnE+IbbVYUew+OrCXaRkfj" crossorigin="anonymous"></script>
@@ -45,8 +53,7 @@
   <script src="https://cdn.jsdelivr.net/npm/chartjs-chart-boxplot@1.0.0/dist/chartjs-chart-boxplot.min.js"></script>
   <script src="https://cdnjs.cloudflare.com/ajax/libs/chartjs-plugin-datalabels/2.0.0/chartjs-plugin-datalabels.js"></script>
   <script src="https://unpkg.com/@sgratzl/chartjs-chart-boxplot@3.6.0/build/index.umd.min.js"></script>
-  <script src="js/chartjs-chart-box-and-violin-plot.min.js"></script> 
-  <script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/3.9.1/chart.min.js"></script>
+  <script src="js/chartjs-chart-box-and-violin-plot.min.js"></script>
 
 
   <body>
diff --git a/templates/main3 b/templates/main3
new file mode 100644
index 0000000..2f37376
--- /dev/null
+++ b/templates/main3
@@ -0,0 +1,77 @@
+<!--
+    # Copyright 2022 Sandra Dérozier (INRAE)
+    #
+    # Licensed under the Apache License, Version 2.0 (the "License");
+    # you may not use this file except in compliance with the License.
+    # You may obtain a copy of the License at
+    #
+    #    http://www.apache.org/licenses/LICENSE-2.0
+    #
+    #    Unless required by applicable law or agreed to in writing, software
+    #    distributed under the License is distributed on an "AS IS" BASIS,
+    #    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    #    See the License for the specific language governing permissions and
+    #    limitations under the License.
+    -->
+    
+    <!DOCTYPE html>
+    <html lang="en">
+    
+      <!-- CSS -->
+      <link href="https://cdn.datatables.net/1.10.23/css/jquery.dataTables.min.css" rel="stylesheet" type="text/css" />
+      <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@4.5.3/dist/css/bootstrap.min.css" integrity="sha384-TX8t27EcRE3e/ihU7zmQxVncDAy5uIKz4rEkgIXeMed4M0jlfIDPvg6uqKI2xXr2" crossorigin="anonymous">
+      <link rel="stylesheet" href="//code.jquery.com/ui/1.12.1/themes/base/jquery-ui.css" />
+      <link rel="stylesheet" href="https://cdn.datatables.net/buttons/1.6.5/css/buttons.dataTables.min.css" />
+      <link rel="stylesheet" href="https://cdn.datatables.net/responsive/2.2.9/css/responsive.dataTables.min.css" />
+      <link rel="stylesheet" href="{{ url_for('static', filename='css/home.css') }}">
+      <link rel="stylesheet" href="{{ url_for('static', filename='css/research.css') }}">
+      <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.4/css/all.min.css"/>
+    
+     
+      <!-- JS -->
+      <script src="https://code.jquery.com/jquery-3.5.1.slim.min.js" integrity="sha384-DfXdz2htPH0lsSSs5nCTpuj/zy4C+OGpamoFVy38MVBnE+IbbVYUew+OrCXaRkfj" crossorigin="anonymous"></script>
+      <script src="https://cdn.jsdelivr.net/npm/bootstrap@4.5.3/dist/js/bootstrap.min.js" integrity="sha384-w1Q4orYjBQndcko6MimVbzY0tgp4pWB4lZ7lr30WKz0vr/aWKhXdBNmNb5D92v7s" crossorigin="anonymous"></script>
+      <script src="https://code.jquery.com/jquery-3.5.1.js"></script>
+      <script src="https://code.jquery.com/ui/1.12.1/jquery-ui.js"></script>
+      <script src="https://cdn.datatables.net/1.10.23/js/jquery.dataTables.min.js"></script>
+      <script src="https://cdn.datatables.net/buttons/2.0.0/js/dataTables.buttons.min.js"></script>
+      <script src="https://cdnjs.cloudflare.com/ajax/libs/jszip/3.1.3/jszip.min.js"></script>
+      <script src="https://cdnjs.cloudflare.com/ajax/libs/pdfmake/0.1.53/pdfmake.min.js"></script>
+      <script src="https://cdnjs.cloudflare.com/ajax/libs/pdfmake/0.1.53/vfs_fonts.js"></script>
+      <script src="https://cdn.datatables.net/buttons/2.0.0/js/buttons.html5.min.js"></script>
+      <script src="https://cdn.datatables.net/buttons/2.0.0/js/buttons.colVis.min.js"></script>
+      <script src="https://cdn.datatables.net/responsive/2.2.9/js/dataTables.responsive.min.js"></script>
+      <script src="https://cdn.datatables.net/responsive/2.2.9/js/dataTables.responsive.min.js"></script>
+      <script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
+      <script src="https://cdn.jsdelivr.net/npm/chartjs-chart-matrix@1.1.0"></script>
+      <script src="https://cdn.jsdelivr.net/npm/chartjs-chart-boxplot@1.0.0/dist/chartjs-chart-boxplot.min.js"></script>
+      <script src="https://cdnjs.cloudflare.com/ajax/libs/chartjs-plugin-datalabels/2.0.0/chartjs-plugin-datalabels.js"></script>
+      <script src="https://unpkg.com/@sgratzl/chartjs-chart-boxplot@3.6.0/build/index.umd.min.js"></script>
+      <script src="js/chartjs-chart-box-and-violin-plot.min.js"></script>
+      <script  src="https://cdnjs.cloudflare.com/ajax/libs/jspdf/2.4.0/jspdf.umd.min.js"/>
+    
+    
+
+      <script type="text/javascript">
+        $SCRIPT_ROOT = {{ request.script_root|tojson|safe }};
+      </script>
+  
+      
+      <body>
+        <div id="left-div">
+          {% include "header" %}
+          {% include "nav" %}
+    
+        </div>
+        <div id="right-div">
+          <div id="content">
+            {% block content %}
+            {% endblock %}
+          </div>
+    
+          {% include "footer" %}
+        </div>
+    
+      </body>
+    </html>
+    
\ No newline at end of file
-- 
GitLab


From 578a616d2ba4f131fd593d1c11b6f46b44648a32 Mon Sep 17 00:00:00 2001
From: "hajar.bouamout" <hajar.bouamout@inrae.fr>
Date: Tue, 14 Jan 2025 16:22:27 +0100
Subject: [PATCH 17/51] =?UTF-8?q?suppression=20du=20template=20main3=20pou?=
 =?UTF-8?q?r=20=C3=A9viter=20la=20redondance?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 templates/main3 | 77 -------------------------------------------------
 1 file changed, 77 deletions(-)
 delete mode 100644 templates/main3

diff --git a/templates/main3 b/templates/main3
deleted file mode 100644
index 2f37376..0000000
--- a/templates/main3
+++ /dev/null
@@ -1,77 +0,0 @@
-<!--
-    # Copyright 2022 Sandra Dérozier (INRAE)
-    #
-    # Licensed under the Apache License, Version 2.0 (the "License");
-    # you may not use this file except in compliance with the License.
-    # You may obtain a copy of the License at
-    #
-    #    http://www.apache.org/licenses/LICENSE-2.0
-    #
-    #    Unless required by applicable law or agreed to in writing, software
-    #    distributed under the License is distributed on an "AS IS" BASIS,
-    #    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-    #    See the License for the specific language governing permissions and
-    #    limitations under the License.
-    -->
-    
-    <!DOCTYPE html>
-    <html lang="en">
-    
-      <!-- CSS -->
-      <link href="https://cdn.datatables.net/1.10.23/css/jquery.dataTables.min.css" rel="stylesheet" type="text/css" />
-      <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@4.5.3/dist/css/bootstrap.min.css" integrity="sha384-TX8t27EcRE3e/ihU7zmQxVncDAy5uIKz4rEkgIXeMed4M0jlfIDPvg6uqKI2xXr2" crossorigin="anonymous">
-      <link rel="stylesheet" href="//code.jquery.com/ui/1.12.1/themes/base/jquery-ui.css" />
-      <link rel="stylesheet" href="https://cdn.datatables.net/buttons/1.6.5/css/buttons.dataTables.min.css" />
-      <link rel="stylesheet" href="https://cdn.datatables.net/responsive/2.2.9/css/responsive.dataTables.min.css" />
-      <link rel="stylesheet" href="{{ url_for('static', filename='css/home.css') }}">
-      <link rel="stylesheet" href="{{ url_for('static', filename='css/research.css') }}">
-      <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.4/css/all.min.css"/>
-    
-     
-      <!-- JS -->
-      <script src="https://code.jquery.com/jquery-3.5.1.slim.min.js" integrity="sha384-DfXdz2htPH0lsSSs5nCTpuj/zy4C+OGpamoFVy38MVBnE+IbbVYUew+OrCXaRkfj" crossorigin="anonymous"></script>
-      <script src="https://cdn.jsdelivr.net/npm/bootstrap@4.5.3/dist/js/bootstrap.min.js" integrity="sha384-w1Q4orYjBQndcko6MimVbzY0tgp4pWB4lZ7lr30WKz0vr/aWKhXdBNmNb5D92v7s" crossorigin="anonymous"></script>
-      <script src="https://code.jquery.com/jquery-3.5.1.js"></script>
-      <script src="https://code.jquery.com/ui/1.12.1/jquery-ui.js"></script>
-      <script src="https://cdn.datatables.net/1.10.23/js/jquery.dataTables.min.js"></script>
-      <script src="https://cdn.datatables.net/buttons/2.0.0/js/dataTables.buttons.min.js"></script>
-      <script src="https://cdnjs.cloudflare.com/ajax/libs/jszip/3.1.3/jszip.min.js"></script>
-      <script src="https://cdnjs.cloudflare.com/ajax/libs/pdfmake/0.1.53/pdfmake.min.js"></script>
-      <script src="https://cdnjs.cloudflare.com/ajax/libs/pdfmake/0.1.53/vfs_fonts.js"></script>
-      <script src="https://cdn.datatables.net/buttons/2.0.0/js/buttons.html5.min.js"></script>
-      <script src="https://cdn.datatables.net/buttons/2.0.0/js/buttons.colVis.min.js"></script>
-      <script src="https://cdn.datatables.net/responsive/2.2.9/js/dataTables.responsive.min.js"></script>
-      <script src="https://cdn.datatables.net/responsive/2.2.9/js/dataTables.responsive.min.js"></script>
-      <script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
-      <script src="https://cdn.jsdelivr.net/npm/chartjs-chart-matrix@1.1.0"></script>
-      <script src="https://cdn.jsdelivr.net/npm/chartjs-chart-boxplot@1.0.0/dist/chartjs-chart-boxplot.min.js"></script>
-      <script src="https://cdnjs.cloudflare.com/ajax/libs/chartjs-plugin-datalabels/2.0.0/chartjs-plugin-datalabels.js"></script>
-      <script src="https://unpkg.com/@sgratzl/chartjs-chart-boxplot@3.6.0/build/index.umd.min.js"></script>
-      <script src="js/chartjs-chart-box-and-violin-plot.min.js"></script>
-      <script  src="https://cdnjs.cloudflare.com/ajax/libs/jspdf/2.4.0/jspdf.umd.min.js"/>
-    
-    
-
-      <script type="text/javascript">
-        $SCRIPT_ROOT = {{ request.script_root|tojson|safe }};
-      </script>
-  
-      
-      <body>
-        <div id="left-div">
-          {% include "header" %}
-          {% include "nav" %}
-    
-        </div>
-        <div id="right-div">
-          <div id="content">
-            {% block content %}
-            {% endblock %}
-          </div>
-    
-          {% include "footer" %}
-        </div>
-    
-      </body>
-    </html>
-    
\ No newline at end of file
-- 
GitLab


From 50331cf0572a8e2df137b3c4e55457e6e5ac9110 Mon Sep 17 00:00:00 2001
From: "hajar.bouamout" <hajar.bouamout@inrae.fr>
Date: Tue, 14 Jan 2025 16:29:12 +0100
Subject: [PATCH 18/51] =?UTF-8?q?am=C3=A9lioration=20du=20css=20+=20modif?=
 =?UTF-8?q?=20des=20fonctionnalit=C3=A9s=20(Possibilit=C3=A9=20de=20t?=
 =?UTF-8?q?=C3=A9l=C3=A9charger=20la=20fiche=20en=20format=20CSV=20au=20li?=
 =?UTF-8?q?eu=20de=20PDF=20,=20Read=20Only=20au=20lieu=20de=20possibilit?=
 =?UTF-8?q?=C3=A9=20de=20modif=20des=20champs...)?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 static/css/sheet.css | 269 +++++++++++++--------------
 static/js/sheet.js   | 421 ++++++++++---------------------------------
 templates/sheet.html | 187 +++++++++++--------
 3 files changed, 335 insertions(+), 542 deletions(-)

diff --git a/static/css/sheet.css b/static/css/sheet.css
index 35a435b..eefd291 100644
--- a/static/css/sheet.css
+++ b/static/css/sheet.css
@@ -1,203 +1,186 @@
-/* General Reset */
-body {
+* {
     margin: 0;
     padding: 0;
+    box-sizing: border-box;
+}
+
+body {
     font-family: 'Arial', sans-serif;
-    background-color: #f9f9f9;
+    line-height: 1.6;
     color: #333;
-    scroll-behavior:inherit;
+    background-color: #f5f7fa;
 }
 
 /* Main Layout */
-main {
-    max-width: 1200px;
-    margin: 20px auto;
-    padding: 20px;
-    background-color: #ffffff;
-    border-radius: 8px;
-    box-shadow: 0 4px 10px rgba(0, 0, 0, 0.1);
-}
-
-/* Navigation Tabs */
-.nav-tabs {
+.main-container {
     display: flex;
-    justify-content: center;
-    border-bottom: 2px solid #ddd;
-    margin-bottom: 20px;
-    padding: 10px 0;
+    min-height: 100vh;
+    background-color: #f5f7fa;
     margin-top: 40px;
 }
 
-.nav-tabs a {
-    text-decoration: none;
-    color: #555;
-    padding: 10px 20px;
-    font-size: 1.1rem;
-    border-radius: 6px;
-    transition: all 0.3s ease;
+/* Sidebar Navigation */
+.sidebar {
+    width: 250px;
+    background-color: #2c3e50;
+    padding: 2rem 0;
+    flex-shrink: 0;
+    height: 100vh;
+    position: sticky;
+    top: 0;
 }
 
-.nav-tabs a:hover,
-.nav-tabs a.active {
-    background-color: #007bff;
-    color: white;
+.nav-menu {
+    list-style: none;
+    padding: 0;
+    margin: 0;
 }
 
-/* Section Headers */
-.section-header {
-    font-size: 1.5rem;
-    color: #444;
-    margin-bottom: 15px;
-    text-align: center;
-    border-bottom: 2px solid #ddd;
-    padding-bottom: 5px;
+.nav-btn {
+    width: 100%;
+    padding: 1rem 2rem;
+    text-align: left;
+    background: none;
+    border: none;
+    color: #ecf0f1;
+    font-size: 1rem;
+    cursor: pointer;
+    transition: background-color 0.3s;
 }
 
-/* Information Boxes */
-.info-box {
-    margin-bottom: 30px;
-    padding: 20px;
-    background-color: #f7f7f7;
-    border: 1px solid #ddd;
-    border-radius: 8px;
+.nav-btn:hover {
+    background-color: #34495e;
 }
 
-.info-row {
-    display: flex;
-    justify-content: space-between;
-    align-items: center;
-    padding: 10px 0;
-    border-bottom: 1px solid #eaeaea;
+/* Content Area */
+.content {
+    flex-grow: 1;
+    padding: 2rem;
+    max-width: calc(100vw - 250px);
 }
 
-.info-row:last-child {
-    border-bottom: none;
+.section {
+    max-width: 1200px;
+    margin: 0 auto;
 }
 
-.info-label {
-    font-weight: bold;
-    font-size: 1rem;
-    color: #555;
-    flex: 0 0 40%;
+.section.hidden {
+    display: none;
 }
 
-.info-value {
-    flex: 0 0 55%;
-    text-align: right;
-    font-size: 1rem;
-    color: #333;
-    word-wrap: break-word;
+/* Information Cards */
+.info-card {
+    background-color: #ffffff;
+    border-radius: 8px;
+    box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
+    margin-bottom: 2rem;
+    overflow: hidden;
 }
 
-.info-value[contenteditable="true"] {
-    border: 1px dashed #ccc;
-    padding: 5px;
-    border-radius: 4px;
-    cursor: text;
+.card-header {
+    padding: 1.5rem;
+    margin: 0;
+    background-color: #f8f9fa;
+    border-bottom: 1px solid #e1e8ed;
+    font-size: 1.25rem;
+    color: #2c3e50;
+    font-weight: 600;
 }
 
-/* Buttons */
-button {
-    background-color: #007bff;
-    color: white;
-    border: none;
-    padding: 8px 15px;
-    font-size: 0.9rem;
-    cursor: pointer;
-    border-radius: 6px;
-    transition: background-color 0.3s ease;
+.info-grid {
+    display: grid;
+    grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
+    gap: 1.5rem;
+    padding: 1.5rem;
 }
 
-button:hover {
-    background-color: #0056b3;
+.info-item {
+    display: flex;
+    flex-direction: column;
+    gap: 0.5rem;
 }
 
-.edit-icon {
-    margin-left: 10px;
-    background: none;
-    border: none;
-    color: #007bff;
-    font-size: 1rem;
-    cursor: pointer;
-    transition: color 0.3s ease;
+.info-label {
+    font-size: 0.875rem;
+    color: #7f8c8d;
+    font-weight: 500;
 }
 
-.edit-icon:hover {
-    color: #0056b3;
+.info-value {
+    font-size: 1rem;
+    color: #2c3e50;
+    padding: 0.5rem;
+    background-color: #f8f9fa;
+    border-radius: 4px;
+    min-height: 2.5rem;
+    display: flex;
+    align-items: center;
 }
 
-/* 3D Structure */
-.structure-container {
+/* Structure Viewer */
+.structure-viewer {
+    padding: 1.5rem;
     display: flex;
-    flex-direction: column;
+    justify-content: center;
     align-items: center;
+    background-color: #f8f9fa;
 }
 
 .structure-image {
     max-width: 100%;
     height: auto;
-    border: 1px solid #ddd;
-    border-radius: 8px;
-    margin: 10px 0;
-}
-
-.image-controls {
-    margin-top: 10px;
-}
-
-.image-path {
-    font-size: 0.9rem;
-    color: #555;
-    margin-top: 5px;
-    text-align: center;
+    border-radius: 4px;
+    max-height: 400px;
+    object-fit: contain;
 }
 
-/* Action Buttons */
-.action-buttons {
+/* Action Bar */
+.action-bar {
     display: flex;
-    justify-content: center;
-    gap: 20px;
-    margin-top: 20px;
+    justify-content: flex-end;
+    padding: 1rem;
+    background-color: #f8f9fa;
+    border-top: 1px solid #e1e8ed;
 }
 
-.save-button {
-    background-color: #28a745;
-}
-
-.save-button:hover {
-    background-color: #218838;
-}
-
-.download-button {
-    background-color: #17a2b8;
+.download-btn {
+    padding: 0.75rem 1.5rem;
+    background-color: #3498db;
+    color: white;
+    border: none;
+    border-radius: 4px;
+    cursor: pointer;
+    transition: background-color 0.3s;
+    font-weight: 500;
 }
 
-.download-button:hover {
-    background-color: #138496;
+.download-btn:hover {
+    background-color: #2980b9;
 }
 
-/* Responsiveness */
+/* Responsive Design */
 @media (max-width: 768px) {
-    .info-row {
+    .main-container {
         flex-direction: column;
-        align-items: flex-start;
     }
-
-    .info-label,
-    .info-value {
-        text-align: left;
+    
+    .sidebar {
         width: 100%;
-        margin-bottom: 5px;
+        height: auto;
+        position: static;
+        padding: 1rem 0;
     }
-
-    .nav-tabs {
-        flex-wrap: wrap;
-        justify-content: space-around;
+    
+    .content {
+        max-width: 100%;
+        padding: 1rem;
     }
-
-    .action-buttons {
-        flex-direction: column;
-        gap: 10px;
+    
+    .info-grid {
+        grid-template-columns: 1fr;
     }
-}
-
+    
+    .info-item {
+        padding: 0.5rem;
+    }
+}
\ No newline at end of file
diff --git a/static/js/sheet.js b/static/js/sheet.js
index 24f9eda..99b65f7 100644
--- a/static/js/sheet.js
+++ b/static/js/sheet.js
@@ -1,332 +1,107 @@
-document.addEventListener("DOMContentLoaded", function () {
-  // Cache DOM elements
-  const editableFields = document.querySelectorAll(
-    '.info-value[contenteditable="true"]'
-  );
-  const editIcons = document.querySelectorAll(".edit-icon");
-  const saveButton = document.getElementById("saveButton");
-  const downloadButton = document.getElementById("downloadButton");
-  const structureUpload = document.getElementById("structureUpload");
-  const structureImage = document.getElementById("structureImage");
+document.addEventListener('DOMContentLoaded', function() {
+  // Initial setup
+  initializeApp();
 
-  // Track changes
-  let hasUnsavedChanges = false;
-
-  // Handle edit icon clicks
-  editIcons.forEach((icon, index) => {
-    icon.addEventListener("click", function () {
-      const field = editableFields[index];
-      field.focus();
-
-      // Place cursor at the end of the content
-      const range = document.createRange();
-      const selection = window.getSelection();
-      range.selectNodeContents(field);
-      range.collapse(false);
-      selection.removeAllRanges();
-      selection.addRange(range);
-    });
-  });
-
-  // Handle editable field changes
-  editableFields.forEach((field) => {
-    // Save on blur
-    field.addEventListener("blur", function () {
-      if (this.textContent.trim() !== this.getAttribute("data-original")) {
-        handleChange(this);
-      }
-    });
-
-    // Save on Enter key
-    field.addEventListener("keydown", function (e) {
-      if (e.key === "Enter") {
-        e.preventDefault();
-        this.blur();
-      }
-    });
+  // Event listeners for global elements
+  setupEventListeners();
+});
 
-    // Store original value
-    field.setAttribute("data-original", field.textContent.trim());
+function initializeApp() {
+  // Show initial section
+  toggleSection('oligo');
+
+  // Load initial structure
+  loadStructure('2\'-Fucosyllactose');
+}
+
+function setupEventListeners() {
+  // Navigation buttons are handled by inline onclick in HTML
+  
+  // Setup download buttons
+  const downloadButtons = document.querySelectorAll('.download-btn');
+  downloadButtons.forEach(button => {
+      button.addEventListener('click', () => downloadCSV());
   });
-
-  // Handle image upload
-  if (structureUpload) {
-    structureUpload.addEventListener("change", function (e) {
-      const file = e.target.files[0];
-      if (file) {
-        const reader = new FileReader();
-        reader.onload = function (e) {
-          structureImage.src = e.target.result;
-          hasUnsavedChanges = true;
-          updateSaveButtonVisibility();
-        };
-        reader.readAsDataURL(file);
-
-        // Update image path display
-        document.getElementById("imagePath").textContent = `Path: ${file.name}`;
-      }
-    });
-  }
-
-  // Handle changes
-  function handleChange(field) {
-    hasUnsavedChanges = true;
-    updateSaveButtonVisibility();
-  }
-
-  // Update save button visibility
-  function updateSaveButtonVisibility() {
-    if (saveButton) {
-      saveButton.style.display = hasUnsavedChanges ? "inline-block" : "none";
-    }
+}
+
+// Section visibility toggle
+window.toggleSection = function(sectionType) {
+  const sections = document.querySelectorAll('.section');
+  sections.forEach(section => section.classList.add('hidden'));
+  
+  const activeSection = document.getElementById(`${sectionType}-section`);
+  if (activeSection) {
+      activeSection.classList.remove('hidden');
   }
-
-  // Save changes
-  if (saveButton) {
-    saveButton.addEventListener("click", async function () {
-      try {
-        const data = collectFormData();
-        const response = await fetch("/save-changes", {
-          method: "POST",
-          headers: {
-            "Content-Type": "application/json",
-          },
-          body: JSON.stringify(data),
-        });
-
-        if (!response.ok) {
-          throw new Error("Failed to save changes");
-        }
-
-        hasUnsavedChanges = false;
-        updateSaveButtonVisibility();
-        showNotification("Changes saved successfully!", "success");
-      } catch (error) {
-        console.error("Save error:", error);
-        showNotification("Error saving changes. Please try again.", "error");
-      }
-    });
+}
+
+// CSV Download functionality
+window.downloadCSV = function() {
+  const section = document.querySelector('.section:not(.hidden)');
+  if (!section) return;
+
+  try {
+      const data = collectSectionData(section);
+      const csvContent = convertToCSV(data);
+      triggerDownload(csvContent, `${section.id}_data.csv`);
+  } catch (error) {
+      console.error('Error generating CSV:', error);
+      alert('Error generating CSV file. Please try again.');
   }
+}
+
+function collectSectionData(section) {
+  const data = [];
+  const infoItems = section.querySelectorAll('.info-item');
+  
+  infoItems.forEach(item => {
+      const label = item.querySelector('.info-label').textContent.trim();
+      const value = item.querySelector('.info-value').textContent.trim();
+      data.push([label, value]);
+  });
 
-  // Download functionality
-  if (downloadButton) {
-    downloadButton.addEventListener("click", async function () {
-      try {
-        await generatePDF();
-        showNotification("Fiche downloaded successfully!", "success");
-      } catch (error) {
-        console.error("Download error:", error);
-        showNotification("Error downloading fiche. Please try again.", "error");
-      }
-    });
-  }
-
-  // Collect form data
-  function collectFormData() {
-    const data = {};
-    editableFields.forEach((field) => {
-      const label = field
-        .closest(".info-row")
-        .querySelector(".info-label")
-        .textContent.trim();
-      data[label] = field.textContent.trim();
-    });
-    return data;
-  }
-
-  // Generate PDF
-  async function generatePDF() {
-    const { jsPDF } = window.jspdf;
-    const doc = new jsPDF();
-
-    // Set default font
-    doc.setFont("helvetica");
-
-    // Page margins
-    const margin = 20;
-    let yPosition = margin;
-    const pageWidth = doc.internal.pageSize.width;
-    const contentWidth = pageWidth - 2 * margin;
-
-    // Define colors correctly for jsPDF
-    function setColor(r, g, b) {
-      return doc.setTextColor(r, g, b);
-    }
-
-    // Function to add a new page if needed
-    function checkNewPage(height) {
-      const pageHeight = doc.internal.pageSize.height;
-      if (yPosition + height > pageHeight - margin) {
-        doc.addPage();
-        yPosition = margin;
-        return true;
-      }
-      return false;
-    }
-
-    // Add navigation section title
-    setColor(33, 150, 243); 
-    doc.setFontSize(14);
-    doc.text("Oligosaccharides", margin, yPosition);
-    yPosition += 15;
-
-    // Function to add a section
-    function addSection(title, content) {
-      // Add section header
-      checkNewPage(30);
-
-      // Set header color
-      setColor(51, 51, 51); 
-      doc.setFontSize(12);
-      doc.setFont("helvetica", "bold");
-      doc.text(title.toUpperCase(), margin, yPosition);
-
-      // Underline the section header
-      const titleWidth = doc.getTextWidth(title.toUpperCase());
-      doc.setDrawColor(33, 150, 243); 
-      doc.line(margin, yPosition + 1, margin + titleWidth, yPosition + 1);
-      yPosition += 10;
-
-      // Add content
-      doc.setFont("helvetica", "normal");
-      doc.setFontSize(10);
-
-      Object.entries(content).forEach(([label, value]) => {
-        checkNewPage(15);
-
-        // Label in bold
-        setColor(85, 85, 85); 
-        doc.setFont("helvetica", "bold");
-        doc.text(label, margin, yPosition);
-
-        // Value in normal weight
-        setColor(51, 51, 51); 
-        doc.setFont("helvetica", "normal");
-
-        // Handle long text wrapping
-        const maxWidth = contentWidth - 70;
-        const valueLines = doc.splitTextToSize(value.toString(), maxWidth);
-        doc.text(valueLines, margin + 70, yPosition);
-
-        yPosition += Math.max(10, valueLines.length * 7);
-      });
-
-      yPosition += 10; 
-        }
-
-    try {
-      // Collect data from the page
-      const oligoSection = {};
-      const matchedSection = {};
-
-      // Collect oligosaccharide information
-      document
-        .querySelectorAll(".info-box:nth-child(2) .info-row")
-        .forEach((row) => {
-          const label = row.querySelector(".info-label").textContent.trim();
-          const value = row.querySelector(".info-value").textContent.trim();
-          oligoSection[label] = value;
-        });
-
-      // Collect matched information
-      document
-        .querySelectorAll(".info-box:nth-child(3) .info-row")
-        .forEach((row) => {
-          const label = row.querySelector(".info-label").textContent.trim();
-          const value = row.querySelector(".info-value").textContent.trim();
-          matchedSection[label] = value;
-        });
-
-      // Add sections to PDF
-      addSection("OLIGOSACCHARIDE INFORMATION", oligoSection);
-      addSection("MATCHED INFORMATION", matchedSection);
-
-      // Add structure image if present
-      const structureImage = document.getElementById("structureImage");
-      if (structureImage && structureImage.src) {
-        checkNewPage(180);
-        try {
-          setColor(51, 51, 51);
-          doc.text("3D Structure:", margin, yPosition);
-          yPosition += 10;
-
-          // Calculate image dimensions to maintain aspect ratio
-          const imgWidth = 160;
-          const imgHeight =
-            (imgWidth * structureImage.height) / structureImage.width;
-
-          doc.addImage(
-            structureImage,
-            "PNG",
-            margin,
-            yPosition,
-            imgWidth,
-            imgHeight
-          );
-          yPosition += imgHeight + 10;
-        } catch (error) {
-          console.error("Error adding image to PDF:", error);
-          throw new Error("Failed to add structure image to PDF");
-        }
+  return data;
+}
+
+function convertToCSV(data) {
+  // Add header
+  const rows = [['Label', 'Value'], ...data];
+  
+  // Convert to CSV format
+  return rows
+      .map(row => 
+          row.map(cell => 
+              `"${(cell || '').replace(/"/g, '""')}"`)
+          .join(','))
+      .join('\n');
+}
+
+function triggerDownload(content, filename) {
+  const blob = new Blob([content], { type: 'text/csv;charset=utf-8;' });
+  const link = document.createElement('a');
+  link.href = URL.createObjectURL(blob);
+  link.download = filename;
+  document.body.appendChild(link);
+  link.click();
+  document.body.removeChild(link);
+}
+
+// Structure loading functionality
+async function loadStructure(compoundName) {
+  try {
+      // Example using PubChem API
+      const searchUrl = `https://pubchem.ncbi.nlm.nih.gov/rest/pug/compound/name/${encodeURIComponent(compoundName)}/PNG`;
+      
+      const structureImage = document.getElementById('structure-image');
+      if (structureImage) {
+          structureImage.src = searchUrl;
+          structureImage.alt = `${compoundName} structure`;
       }
-
-      // Add footer with date
-      const pageCount = doc.internal.getNumberOfPages();
-      for (let i = 1; i <= pageCount; i++) {
-        doc.setPage(i);
-        const footer = `Page ${i} of ${pageCount} - Generated on ${new Date().toLocaleDateString()}`;
-        doc.setFontSize(8);
-        setColor(128, 128, 128); 
-        doc.text(footer, pageWidth / 2, doc.internal.pageSize.height - 10, {
-          align: "center",
-        });
+  } catch (error) {
+      console.error('Error loading structure:', error);
+      const structureImage = document.getElementById('structure-image');
+      if (structureImage) {
+          structureImage.alt = 'Error loading structure';
       }
-
-      // Save the PDF
-      doc.save("oligosaccharide_sheet.pdf");
-      return true;
-    } catch (error) {
-      console.error("PDF generation error:", error);
-      throw new Error("Failed to generate PDF: " + error.message);
-    }
   }
-
-  // Add the event listener for the download button
-  document
-    .getElementById("downloadButton")
-    .addEventListener("click", async () => {
-      try {
-        await generatePDF();
-        showNotification("Fiche downloaded successfully!", "success");
-      } catch (error) {
-        console.error("Error generating PDF:", error);
-        showNotification("Error downloading fiche. Please try again.", "error");
-      }
-    });
-
-  // Notification system
-  function showNotification(message, type) {
-    const notification = document.createElement("div");
-    notification.className = `notification ${type}`;
-    notification.textContent = message;
-
-    // Remove existing notifications
-    const existingNotifications = document.querySelectorAll(".notification");
-    existingNotifications.forEach((notif) => notif.remove());
-
-    document.body.appendChild(notification);
-
-    setTimeout(() => {
-      notification.classList.add("fade-out");
-      setTimeout(() => notification.remove(), 300);
-    }, 3000);
-  }
-
-  // Warn about unsaved changes before leaving
-  window.addEventListener("beforeunload", function (e) {
-    if (hasUnsavedChanges) {
-      e.preventDefault();
-      e.returnValue = "";
-    }
-  });
-});
+}
\ No newline at end of file
diff --git a/templates/sheet.html b/templates/sheet.html
index b608208..dbe9808 100644
--- a/templates/sheet.html
+++ b/templates/sheet.html
@@ -1,88 +1,123 @@
-{% extends 'main3' %} {% block content %}
-<script type="text/javascript">
-  const SCRIPT_ROOT = {{ request.script_root|tojson|safe }};
-</script>
-
+{% extends 'main2' %} 
+{% block content %}
 <script src="{{ url_for('static', filename='js/sheet.js') }}" defer></script>
-<link
-  href="{{ url_for('static', filename='css/sheet.css') }}"
-  rel="stylesheet"
-/>
+<link href="{{ url_for('static', filename='css/sheet.css') }}" rel="stylesheet"/>
 
-<main>
-  <!-- Navigation Tabs -->
-  <nav class="nav-tabs">
-    <a href="#" class="active" aria-current="page">Oligosaccharides</a>
-    <a href="#">Species</a>
-    <a href="#">Samples</a>
+<main class="main-container">
+  <!-- Navigation Sidebar -->
+  <nav class="sidebar">
+    <ul class="nav-menu">
+      <li><button class="nav-btn" onclick="toggleSection('oligo')">Oligosaccharides</button></li>
+      <li><button class="nav-btn" onclick="toggleSection('species')">Species</button></li>
+      <li><button class="nav-btn" onclick="toggleSection('samples')">Samples</button></li>
+    </ul>
   </nav>
 
-  <!-- OLIGOSACCHARIDE INFORMATION Section -->
-  <section id="oligosaccharide-info" class="info-box">
-    <h2 class="section-header">OLIGOSACCHARIDE INFORMATION</h2>
-    {% for label, value in [ ('Milk Oligosaccharide ID', 'OLIGO0137'), ('Milk
-    Oligosaccharide Normalized Name', '2\'-Fucosyllactose'), ('Abbreviated
-    Normalized MO Name', '2\'-FL'), ('Formula', 'C18H32O15'), ('Synonyms',
-    '2\'FL | 2\'fucosyllactose | 2FL') ] %}
-    <div class="info-row">
-      <div class="info-label">{{ label }}</div>
-      <div class="info-value" contenteditable="true">{{ value }}</div>
-      <button class="edit-icon" aria-label="Edit text occurrence">
-        <i class="fas fa-pencil-alt"></i>
-      </button>
-    </div>
-    {% endfor %}
-  </section>
+  <!-- Content Area -->
+  <div class="content">
+    <!-- Oligosaccharides Section -->
+    <section id="oligo-section" class="section">
+      <div class="info-card">
+        <h2 class="card-header">Oligosaccharide Information</h2>
+        <div class="info-grid">
+          {% for label, value in [
+            ('Milk Oligosaccharide ID', 'OLIGO0137'),
+            ('Milk Oligosaccharide Normalized Name', '2\'-Fucosyllactose'),
+            ('Abbreviated Normalized MO Name', '2\'-FL'),
+            ('Formula', 'C18H32O15'),
+            ('Synonyms', '2\'FL | 2\'fucosyllactose | 2FL')
+          ] %}
+          <div class="info-item">
+            <span class="info-label">{{ label }}</span>
+            <span class="info-value">{{ value }}</span>
+          </div>
+          {% endfor %}
+        </div>
+      </div>
 
-  <!-- MATCHED INFORMATION Section -->
-  <section id="matched-info" class="info-box">
-    <h2 class="section-header">MATCHED INFORMATION</h2>
-    {% for label, value in [ ('Text Occurrence', 'fucosyllactose'), ('Reference
-    Class', '2\'-Fucosyllactose'), ('Species', 'Rabbit'), ('MO Type', 'XX'),
-    ('MO Samples', 'Unidentified'), ('Methods of Analysis', 'A high-performance
-    anion-exchange chromatography-pulsed amperometric detector (HPAEC-PAD)'),
-    ('Text Snippet', 'A high-performance anion-exchange chromatography-pulsed
-    amperometric detector (HPAEC-PAD) was used to quantify 2\'-fucosyllactose
-    (2\'-FL)'), ('Number of Occurrences', '2'), ('Number of Matched Documents',
-    '13') ] %}
-    <div class="info-row">
-      <div class="info-label">{{ label }}</div>
-      <div class="info-value" contenteditable="true">{{ value }}</div>
-      <button class="edit-icon" aria-label="Edit text occurrence">
-        <i class="fas fa-pencil-alt"></i>
-      </button>
-    </div>
-    {% endfor %}
+      <div class="info-card">
+        <h2 class="card-header">Matched Information</h2>
+        <div class="info-grid">
+          {% for label, value in [
+            ('Text Occurrence', 'fucosyllactose'),
+            ('Reference Class', '2\'-Fucosyllactose'),
+            ('Species', 'Rabbit'),
+            ('MO Type', 'XX'),
+            ('MO Samples', 'Unidentified'),
+            ('Methods of Analysis', 'HPAEC-PAD'),
+            ('Text Snippet', 'HPAEC-PAD was used to quantify 2\'-fucosyllactose (2\'-FL)'),
+            ('Number of Occurrences', '2'),
+            ('Number of Matched Documents', '13')
+          ] %}
+          <div class="info-item">
+            <span class="info-label">{{ label }}</span>
+            <span class="info-value">{{ value }}</span>
+          </div>
+          {% endfor %}
+        </div>
+      </div>
 
-    <!-- 3D Structure Section -->
-    <div class="info-row">
-      <div class="info-label">3D Structure</div>
-      <div class="info-value">
-        <div class="structure-container">
-          <img
-            id="structureImage"
-            class="structure-image"
-            src="{{ url_for('static', filename='img/2\'-Fucosyllactose.png') }}"
-            alt="3D Structure of 2'-Fucosyllactose"
-          />
-          <div class="image-controls">
-            <input
-              type="file"
-              id="structureUpload"
-              accept="image/*"
-              class="hidden"
-            />
-            <div id="imagePath" class="image-path"></div>
+      <div class="info-card">
+        <h2 class="card-header">3D Structure</h2>
+        <div class="structure-viewer">
+          <img id="structure-image" class="structure-image" alt="3D Structure">
+        </div>
+      </div>
+
+      <div class="action-bar">
+        <button class="download-btn" onclick="downloadCSV()">Download CSV</button>
+      </div>
+    </section>
+
+    <!-- Species Section -->
+    <section id="species-section" class="section hidden">
+      <div class="info-card">
+        <h2 class="card-header">Species Information</h2>
+        <div class="info-grid">
+          {% for label, value in [
+            ('Species ID', ''),
+            ('Species Scientific Name', ''),
+            ('Number Of Occurrence', ''),
+            ('Physiological Stage', ''),
+            ('Breed', ''),
+            ('Geography', ''),
+            ('Postpartum age', '')
+          ] %}
+          <div class="info-item">
+            <span class="info-label">{{ label }}</span>
+            <span class="info-value">{{ value }}</span>
           </div>
+          {% endfor %}
         </div>
       </div>
-    </div>
-  </section>
+      <div class="action-bar">
+        <button class="download-btn" onclick="downloadCSV()">Download CSV</button>
+      </div>
+    </section>
 
-  <!-- Action Buttons -->
-  <div class="action-buttons">
-    <button id="saveButton" class="save-button">Save All Changes</button>
-    <button id="downloadButton" class="download-button">Download Fiche</button>
+    <!-- Samples Section -->
+    <section id="samples-section" class="section hidden">
+      <div class="info-card">
+        <h2 class="card-header">Samples Information</h2>
+        <div class="info-grid">
+          {% for label, value in [
+            ('Samples ID', ''),
+            ('Samples Scientific Name', ''),
+            ('Associated Species', ''),
+            ('MO Normalization Method', ''),
+            ('Lactation Stage', '')
+          ] %}
+          <div class="info-item">
+            <span class="info-label">{{ label }}</span>
+            <span class="info-value">{{ value }}</span>
+          </div>
+          {% endfor %}
+        </div>
+      </div>
+      <div class="action-bar">
+        <button class="download-btn" onclick="downloadCSV()">Download CSV</button>
+      </div>
+    </section>
   </div>
 </main>
-{% endblock %}
+{% endblock %}
\ No newline at end of file
-- 
GitLab


From 681dfef6e94cebd09f42b032095d8b8ee6f9f08e Mon Sep 17 00:00:00 2001
From: "hajar.bouamout" <hajar.bouamout@inrae.fr>
Date: Tue, 14 Jan 2025 16:31:14 +0100
Subject: [PATCH 19/51] =?UTF-8?q?mise=20=C3=A0=20jour=20du=20main2?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 templates/main2 | 67 +++++++++++++++++++++++--------------------------
 1 file changed, 32 insertions(+), 35 deletions(-)

diff --git a/templates/main2 b/templates/main2
index d6f6138..0ccd73e 100644
--- a/templates/main2
+++ b/templates/main2
@@ -17,45 +17,42 @@
 <!DOCTYPE html>
 <html lang="en">
 
-  <!-- CSS -->
-  <link href="https://cdn.datatables.net/1.10.23/css/jquery.dataTables.min.css" rel="stylesheet" type="text/css" />
-  <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@4.5.3/dist/css/bootstrap.min.css" integrity="sha384-TX8t27EcRE3e/ihU7zmQxVncDAy5uIKz4rEkgIXeMed4M0jlfIDPvg6uqKI2xXr2" crossorigin="anonymous">
-  <link rel="stylesheet" href="//code.jquery.com/ui/1.12.1/themes/base/jquery-ui.css" />
-  <link rel="stylesheet" href="{{ url_for('static', filename='css/main.css') }}">
-  <link rel="stylesheet" href="https://cdn.datatables.net/buttons/1.6.5/css/buttons.dataTables.min.css" />
-  <link rel="stylesheet" href="https://cdn.datatables.net/responsive/2.2.9/css/responsive.dataTables.min.css" />
-  <link rel="stylesheet" href="{{ url_for('static', filename='css/page_accueil.css') }}">
-  <link rel="stylesheet" href="{{ url_for('static', filename='css/home.css') }}">
-  <link rel="stylesheet" href="{{ url_for('static', filename='css/research.css') }}">
-  <link rel="stylesheet" href="{{ url_for('static', filename='css/results.css') }}">
-  <link rel="stylesheet" href="{{ url_for('static', filename='css/sheet.css') }}">
-  <link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0-beta3/css/all.min.css" rel="stylesheet">
+<!-- CSS -->
+<link href="https://cdn.datatables.net/1.10.23/css/jquery.dataTables.min.css" rel="stylesheet" type="text/css" />
+<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@4.5.3/dist/css/bootstrap.min.css" integrity="sha384-TX8t27EcRE3e/ihU7zmQxVncDAy5uIKz4rEkgIXeMed4M0jlfIDPvg6uqKI2xXr2" crossorigin="anonymous">
+<link rel="stylesheet" href="//code.jquery.com/ui/1.12.1/themes/base/jquery-ui.css" />
+<link rel="stylesheet" href="{{ url_for('static', filename='css/main.css') }}">
+<link rel="stylesheet" href="https://cdn.datatables.net/buttons/1.6.5/css/buttons.dataTables.min.css" />
+<link rel="stylesheet" href="https://cdn.datatables.net/responsive/2.2.9/css/responsive.dataTables.min.css" />
+<link rel="stylesheet" href="{{ url_for('static', filename='css/home.css') }}">
+<link rel="stylesheet" href="{{ url_for('static', filename='css/research.css') }}">
+<link rel="stylesheet" href="{{ url_for('static', filename='css/results.css') }}">
+<link rel="stylesheet" href="{{ url_for('static', filename='css/sheet.css') }}">
+<link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0-beta3/css/all.min.css" rel="stylesheet">
 
+<!-- JS -->
+<script src="https://code.jquery.com/jquery-3.5.1.slim.min.js" integrity="sha384-DfXdz2htPH0lsSSs5nCTpuj/zy4C+OGpamoFVy38MVBnE+IbbVYUew+OrCXaRkfj" crossorigin="anonymous"></script>
+<script src="https://cdn.jsdelivr.net/npm/bootstrap@4.5.3/dist/js/bootstrap.min.js" integrity="sha384-w1Q4orYjBQndcko6MimVbzY0tgp4pWB4lZ7lr30WKz0vr/aWKhXdBNmNb5D92v7s" crossorigin="anonymous"></script>
+<script src="https://code.jquery.com/jquery-3.5.1.js"></script>
+<script src="https://code.jquery.com/ui/1.12.1/jquery-ui.js"></script>
+<script src="https://cdn.datatables.net/1.10.23/js/jquery.dataTables.min.js"></script>
+<script src="https://cdn.datatables.net/buttons/2.0.0/js/dataTables.buttons.min.js"></script>
+<script src="https://cdnjs.cloudflare.com/ajax/libs/jszip/3.1.3/jszip.min.js"></script>
+<script src="https://cdnjs.cloudflare.com/ajax/libs/pdfmake/0.1.53/pdfmake.min.js"></script>
+<script src="https://cdnjs.cloudflare.com/ajax/libs/pdfmake/0.1.53/vfs_fonts.js"></script>
+<script src="https://cdn.datatables.net/buttons/2.0.0/js/buttons.html5.min.js"></script>
+<script src="https://cdn.datatables.net/buttons/2.0.0/js/buttons.colVis.min.js"></script>
+<script src="https://cdn.datatables.net/responsive/2.2.9/js/dataTables.responsive.min.js"></script>
+<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
+<script src="https://cdn.jsdelivr.net/npm/chartjs-chart-matrix@1.1.0"></script>
+<script src="https://cdn.jsdelivr.net/npm/chartjs-chart-boxplot@1.0.0/dist/chartjs-chart-boxplot.min.js"></script>
+<script src="https://cdnjs.cloudflare.com/ajax/libs/chartjs-plugin-datalabels/2.0.0/chartjs-plugin-datalabels.js"></script>
+<script src="https://unpkg.com/@sgratzl/chartjs-chart-boxplot@3.6.0/build/index.umd.min.js"></script>
+<script src="js/chartjs-chart-box-and-violin-plot.min.js"></script>
+<script src="https://cdnjs.cloudflare.com/ajax/libs/jspdf/2.4.0/jspdf.umd.min.js"></script>
 
 
 
-  <!-- JS -->
-  <script src="https://code.jquery.com/jquery-3.5.1.slim.min.js" integrity="sha384-DfXdz2htPH0lsSSs5nCTpuj/zy4C+OGpamoFVy38MVBnE+IbbVYUew+OrCXaRkfj" crossorigin="anonymous"></script>
-  <script src="https://cdn.jsdelivr.net/npm/bootstrap@4.5.3/dist/js/bootstrap.min.js" integrity="sha384-w1Q4orYjBQndcko6MimVbzY0tgp4pWB4lZ7lr30WKz0vr/aWKhXdBNmNb5D92v7s" crossorigin="anonymous"></script>
-  <script src="https://code.jquery.com/jquery-3.5.1.js"></script>
-  <script src="https://code.jquery.com/ui/1.12.1/jquery-ui.js"></script>
-  <script src="https://cdn.datatables.net/1.10.23/js/jquery.dataTables.min.js"></script>
-  <script src="https://cdn.datatables.net/buttons/2.0.0/js/dataTables.buttons.min.js"></script>
-  <script src="https://cdnjs.cloudflare.com/ajax/libs/jszip/3.1.3/jszip.min.js"></script>
-  <script src="https://cdnjs.cloudflare.com/ajax/libs/pdfmake/0.1.53/pdfmake.min.js"></script>
-  <script src="https://cdnjs.cloudflare.com/ajax/libs/pdfmake/0.1.53/vfs_fonts.js"></script>
-  <script src="https://cdn.datatables.net/buttons/2.0.0/js/buttons.html5.min.js"></script>
-  <script src="https://cdn.datatables.net/buttons/2.0.0/js/buttons.colVis.min.js"></script>
-  <script src="https://cdn.datatables.net/responsive/2.2.9/js/dataTables.responsive.min.js"></script>
-  <script src="https://cdn.datatables.net/responsive/2.2.9/js/dataTables.responsive.min.js"></script>
-  <script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
-  <script src="https://cdn.jsdelivr.net/npm/chartjs-chart-matrix@1.1.0"></script>
-  <script src="https://cdn.jsdelivr.net/npm/chartjs-chart-boxplot@1.0.0/dist/chartjs-chart-boxplot.min.js"></script>
-  <script src="https://cdnjs.cloudflare.com/ajax/libs/chartjs-plugin-datalabels/2.0.0/chartjs-plugin-datalabels.js"></script>
-  <script src="https://unpkg.com/@sgratzl/chartjs-chart-boxplot@3.6.0/build/index.umd.min.js"></script>
-  <script src="js/chartjs-chart-box-and-violin-plot.min.js"></script>
-
-
   <body>
     <div id="left-div">
       {% include "header" %}
-- 
GitLab


From 44734aea36d1bdaaca0a2ab8d208649854cfdcb2 Mon Sep 17 00:00:00 2001
From: "hajar.bouamout" <hajar.bouamout@inrae.fr>
Date: Tue, 14 Jan 2025 16:35:39 +0100
Subject: [PATCH 20/51] suppression fichiers js et cssde l'ancienne page
 d'accueil

---
 static/css/page_accueil.css |  318 ----------
 static/js/home_page.js      | 1140 -----------------------------------
 2 files changed, 1458 deletions(-)
 delete mode 100644 static/css/page_accueil.css
 delete mode 100644 static/js/home_page.js

diff --git a/static/css/page_accueil.css b/static/css/page_accueil.css
deleted file mode 100644
index fb80d5a..0000000
--- a/static/css/page_accueil.css
+++ /dev/null
@@ -1,318 +0,0 @@
-/* Global Reset and Base Styles */
-* {
-    margin: 0;
-    padding: 0;
-    box-sizing: border-box;
-}
-
-body {
-    font-family: 'Helvetica Neue', Arial, sans-serif;
-    line-height: 1.6;
-    color: #333;
-    background-color: #f8f9fa;
-}
-
-/* Layout Container */
-.container {
-    max-width: 1100px;
-    margin: 0 auto;
-    padding: 0 1.5rem;
-}
-
-/* Header Section */
-.header-section {
-    padding: 2rem 0;
-    background-color: #fff;
-    box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
-}
-
-.title {
-    font-size: 2.5rem;
-    color: #2c3e50;
-    margin-bottom: 1rem;
-    font-weight: 600;
-}
-
-.description {
-    font-size: 1.125rem;
-    color: #576574;
-    margin-bottom: 1.5rem;
-    line-height: 1.8;
-}
-
-/* Logo */
-.logo {
-    max-width: 200px;
-    height: auto;
-    display: block;
-    margin: 0 auto;
-}
-
-/* Data Overview Section */
-.data-overview {
-    padding: 3rem 0;
-}
-
-.section-title {
-    font-size: 2.25rem;
-    color: #2c3e50;
-    margin-bottom: 2.5rem;
-    text-align: center;
-    font-weight: 600;
-}
-
-/* Chart Containers */
-.chart-container {
-    background: #fff;
-    border-radius: 8px;
-    padding: 1.5rem;
-    margin-bottom: 2rem;
-    box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
-}
-
-.chart-container h2 {
-    font-size: 1.5rem;
-    color: #2c3e50;
-    margin-bottom: 1.5rem;
-    font-weight: 500;
-}
-
-/* Table Styles */
-.table-container {
-    background: #fff;
-    border-radius: 8px;
-    padding: 1rem;
-    margin-bottom: 2rem;
-    box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
-    overflow-x: auto;
-}
-
-.table {
-    width: 100%;
-    border-collapse: collapse;
-}
-
-.table th,
-.table td {
-    padding: 0.75rem;
-    border-bottom: 1px solid #669bcf;
-    font-size: 0.875rem;
-}
-
-.table th {
-    background-color: #f8f9fa;
-    font-weight: 600;
-    text-align: left;
-}
-
-.table tr:hover {
-    background-color: #f8f9fa;
-}
-
-/* Form Controls */
-.form-control {
-    width: 100%;
-    padding: 0.75rem;
-    margin-bottom: 1.25rem;
-    border: 1px solid #ced4da;
-    border-radius: 4px;
-    font-size: 1rem;
-}
-
-/* Grid Layout */
-.inline-block {
-    display: grid;
-    grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
-    gap: 2rem;
-    margin-bottom: 2rem;
-}
-
-/* Charts Grid */
-.charts-container {
-    display: grid;
-    grid-template-columns: repeat(auto-fit, minmax(350px, 1fr));
-    gap: 2rem;
-    margin: 2rem 0;
-}
-
-/* Responsive Design */
-@media (max-width: 1200px) {
-    .container {
-        padding: 0 1rem;
-    }
-
-    .title {
-        font-size: 2rem;
-    }
-
-    .section-title {
-        font-size: 2rem;
-    }
-
-    .chart-container h2 {
-        font-size: 1.25rem;
-    }
-}
-
-@media (max-width: 992px) {
-    .container {
-        padding: 0 1rem;
-    }
-
-    .title {
-        font-size: 1.75rem;
-    }
-
-    .section-title {
-        font-size: 1.75rem;
-    }
-
-    .description {
-        font-size: 1rem;
-    }
-
-    .chart-container,
-    .table-container {
-        padding: 1rem;
-    }
-
-    .table th,
-    .table td {
-        padding: 1rem;
-    }
-    
-    .inline-block {
-        grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
-    }
-
-    .charts-container {
-        grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
-    }
-}
-
-@media (max-width: 768px) {
-    .title {
-        font-size: 1.5rem;
-    }
-
-    .section-title {
-        font-size: 1.5rem;
-    }
-
-    .description {
-        font-size: 0.95rem;
-    }
-
-    .chart-container h2 {
-        font-size: 1rem;
-    }
-
-    .inline-block {
-        grid-template-columns: 1fr;
-        gap: 1.5rem;
-    }
-
-    .charts-container {
-        grid-template-columns: 1fr;
-    }
-
-    .form-control {
-        padding: 0.75rem;
-        font-size: 0.9rem;
-    }
-
-    .table th,
-    .table td {
-        padding: 0.75rem;
-    }
-}
-
-/* Small screens (max-width: 480px) */
-@media (max-width: 480px) {
-    .title {
-        font-size: 1.25rem;
-    }
-
-    .description {
-        font-size: 0.875rem;
-    }
-
-    .table th,
-    .table td {
-        padding: 0.5rem;
-    }
-
-    .form-control {
-        padding: 0.75rem;
-        font-size: 0.85rem;
-    }
-
-    .chart-container,
-    .table-container {
-        padding: 0.75rem;
-    }
-
-    .inline-block {
-        grid-template-columns: 1fr;
-    }
-
-    .charts-container {
-        grid-template-columns: 1fr;
-    }
-}
-
-/* Better image scaling for small screens */
-img {
-    max-width: 100%;
-    height: auto;
-}
-
-/* Mobile Menu */
-.menu {
-    display: none;
-}
-
-@media (max-width: 768px) {
-    .menu {
-        display: block;
-        padding: 1rem;
-        background-color: #2c3e50;
-        color: white;
-        border-radius: 8px;
-        cursor: pointer;
-    }
-
-    .menu-items {
-        display: none;
-        flex-direction: column;
-        gap: 1rem;
-    }
-
-    .menu-items.active {
-        display: flex;
-    }
-}
-
-/* Section for the relationship graphs */
-.relationship-graphs {
-    margin-top: 2rem;
-}
-
-.relationship-graphs .row {
-    margin-bottom: 2rem;
-}
-
-.relationship-graphs .chart-container {
-    padding: 1rem;
-    margin-bottom: 1.5rem;
-}
-
-.relationship-graphs .col-12 {
-    margin-bottom: 1rem;
-}
-
-@media (max-width: 768px) {
-    .relationship-graphs .col-md-6 {
-        margin-bottom: 1.5rem;
-    }
-}
diff --git a/static/js/home_page.js b/static/js/home_page.js
deleted file mode 100644
index a20b252..0000000
--- a/static/js/home_page.js
+++ /dev/null
@@ -1,1140 +0,0 @@
-//table displaying statistics for each entity
-document.addEventListener("DOMContentLoaded", function () {
-    // The API URL from which we are fetching the JSON data
-    const apiUrl = '/_get/stat_occurrence';
-     
-    // Fetching the JSON data from the API
-    fetch(apiUrl)
-      .then((response) => response.json())  // Convert the API response to JSON
-      .then((data) => {
-
-        // Log the received data to the console for verification
-        console.log("Data received from the API:", data);
-
-        // Check if the data is empty or null
-        if (!data || Object.keys(data).length === 0) {
-          throw new Error("The data from the API is empty or invalid.");
-        }
-        
-        // Initialize an object to store role statistics
-        const rolesStats = {};
-
-        // Iterate over the data and populate the rolesStats object
-        Object.keys(data).forEach((key) => {
-          rolesStats[key] = data[key];  
-        });
-
-        // Get the table body element where we will display the data
-        const entitiesTableBody = document.getElementById("entitiesTableBody");
-
-        // Iterate over the rolesStats object and create table rows for each entity
-        Object.keys(rolesStats).forEach((entity) => {
-          const row = document.createElement("tr");
-          const cell1 = document.createElement("td");
-          const cell2 = document.createElement("td");
-
-           // Set the content of the cells
-          cell1.textContent = entity;
-          cell2.textContent = rolesStats[entity];
-
-          // Append the cells to the row
-          row.appendChild(cell1);
-          row.appendChild(cell2);
-
-          // Append the row to the table body
-          entitiesTableBody.appendChild(row);
-        });
-      })
-      .catch((error) => {
-        console.error("Error fetching the JSON data:", error);
-      });
-
-     
-    // chart of oligo types per taxon 
-
-
-    const chartData = {
-      taxon1: {
-        Sialylated: 1,
-        Neutral: 1,
-        Fucosylated: 1,
-        "Type I": 0,
-        "Type II": 0,
-      },
-      taxon2: {
-        Sialylated: 1,
-        Neutral: 0.5,
-        Fucosylated: 1,
-        "Type I": 1,
-        "Type II": 0,
-      },
-      taxon3: {
-        Sialylated: 1,
-        Neutral: 1,
-        Fucosylated: 1,
-        "Type I": 0,
-        "Type II": 0,
-      },
-      taxon4: {
-        Sialylated: 0.3,
-        Neutral: 0.5,
-        Fucosylated: 0.8,
-        "Type I": 1,
-        "Type II": 0.4,
-      },
-      taxon5: {
-        Sialylated: 1,
-        Neutral: 0,
-        Fucosylated: 1,
-        "Type I": 0,
-        "Type II": 1,
-      },
-    };
-
-    let currentChart = null;
-
-    // Function to create/update chart
-    function createChart(taxon) {
-      const ctx = document
-        .getElementById("taxonOligoChart")
-        .getContext("2d");
-      if (currentChart) currentChart.destroy();
-
-      const data = chartData[taxon];
-      const labels = Object.keys(data);
-      const values = Object.values(data);
-
-      currentChart = new Chart(ctx, {
-        type: "bar",
-        data: {
-          labels: labels,
-          datasets: [
-            {
-              label: "Presence of Oligosaccharide Types",
-              data: values,
-              backgroundColor: [
-                "#FF6384",
-                "#36A2EB",
-                "#FFCE56",
-                "#4BC0C0",
-                "#FF9F40",
-              ],
-              borderColor: "#ccc",
-              borderWidth: 1,
-            },
-          ],
-        },
-        options: {
-          responsive: true,
-          plugins: {
-            legend: { display: false },
-            title: {
-              display: true,
-              text: "Presence of Oligosaccharide Types",
-            },
-          },
-          scales: {
-            y: { beginAtZero: true },
-          },
-        },
-      });
-    }
-
-    // Initialize chart for the selected taxon
-    const taxonSelect = document.getElementById("taxonSelect");
-    createChart(taxonSelect.value);
-
-    // Update chart when a new taxon is selected
-    taxonSelect.addEventListener("change", function () {
-      createChart(this.value);
-    });
-  });
-
-  //type oligo
-
-  document.addEventListener("DOMContentLoaded", function () {
-    // Example data: I should Replace this with actual percentages when available
-    const taxons = [
-      "Sus scrofa",
-      "Homo sapiens",
-      "Bos taurus",
-      "Taxon 4",
-      "Taxon 5",
-    ];
-    const oligoTypes = [
-      "Sialylated",
-      "Neutral",
-      "Fucosylated",
-      "Type I",
-      "Type II",
-    ];
-    const distributionData = [
-      [30, 20, 10, 25, 15], // Sus scrofa
-      [20, 15, 30, 25, 10], // Homo sapiens
-      [25, 20, 15, 10, 30], // Bos taurus
-      [15, 25, 20, 30, 10], // Taxon 4
-      [10, 30, 25, 15, 20], // Taxon 5
-    ];
-
-    const datasets = oligoTypes.map((type, index) => {
-      const colors = [
-        "#FF6384",
-        "#36A2EB",
-        "#FFCE56",
-        "#4BC0C0",
-        "#FF9F40",
-      ];
-      return {
-        label: type,
-        data: distributionData.map((row) => row[index]),
-        backgroundColor: colors[index],
-        borderWidth: 1,
-      };
-    });
-
-    const ctx = document
-      .getElementById("stackedBarChart")
-      .getContext("2d");
-    new Chart(ctx, {
-      type: "bar",
-      data: {
-        labels: taxons,
-        datasets: datasets,
-      },
-      options: {
-        responsive: true,
-        plugins: {
-          tooltip: {
-            callbacks: {
-              label: function (context) {
-                return `${context.dataset.label}: ${context.raw}%`;
-              },
-            },
-          },
-          legend: { position: "top" },
-        },
-        scales: {
-          x: {
-            stacked: true,
-            title: {
-              display: true,
-              text: "Taxons",
-            },
-          },
-          y: {
-            stacked: true,
-            beginAtZero: true,
-            title: {
-              display: true,
-              text: "Percentage",
-            },
-          },
-        },
-      },
-    });
-  });
-
-  // Dynamic chart for lactation stages
-  document.addEventListener("DOMContentLoaded", function () {
-    const lactationChartCtx = document
-      .getElementById("lactationChart")
-      .getContext("2d");
-    // data for each lactation stage
-    const lactationData = {
-      labels: [
-        "Colostrum",
-        "Early Lactation",
-        "Farrowing",
-        "Mature Milk",
-        "Mid Lactation",
-        "Transitional Milk",
-        "Weaning",
-      ], // lactation stages (X)
-      datasets: [
-        {
-          label: "Sialylated",
-          data: [80, 60, 50, 70, 65, 75, 85],
-          backgroundColor: "#3E5C76", 
-          borderColor: "#3E5C76",
-          borderWidth: 1,
-        },
-        {
-          label: "Neutral",
-          data: [50, 70, 60, 80, 70, 65, 60],
-          backgroundColor: "#7F9BA6", 
-          borderColor: "#7F9BA6",
-          borderWidth: 1,
-        },
-        {
-          label: "Fucosylated",
-          data: [40, 50, 40, 60, 55, 60, 65],
-          backgroundColor: "#9A9A9A", 
-          borderColor: "#9A9A9A",
-          borderWidth: 1,
-        },
-        {
-          label: "Type I",
-          data: [60, 40, 30, 50, 55, 65, 60],
-          backgroundColor: "#6C8C94", 
-          borderColor: "#6C8C94",
-          borderWidth: 1,
-        },
-        {
-          label: "Type II",
-          data: [30, 50, 60, 70, 65, 70, 75],
-          backgroundColor: "#C0A080", 
-          borderColor: "#C0A080",
-          borderWidth: 1,
-        },
-      ],
-    };
-    // Create the chart
-    const lactationChart = new Chart(lactationChartCtx, {
-      type: "bar", 
-      data: lactationData,
-      options: {
-        responsive: true,
-        plugins: {
-          legend: {
-            position: "top",
-          },
-          title: {
-            display: true,
-          },
-        },
-        scales: {
-          x: {
-            title: {
-              display: true,
-              text: "Lactation Stages",
-            },
-            grid: {
-              display: false,
-            },
-          },
-          y: {
-            beginAtZero: true,
-            title: {
-              display: true,
-              text: "Percentage%",
-            },
-            max: 100,
-          },
-        },
-      },
-    });
-  });
-
-  document.addEventListener("DOMContentLoaded", function () {
-    const speciesChartCtx = document
-      .getElementById("speciesChart")
-      .getContext("2d");
-    const speciesData = {
-      labels: [
-        "Colostrum",
-        "Early Lactation",
-        "Farrowing",
-        "Mature Milk",
-        "Mid Lactation",
-        "Transitional Milk",
-        "Weaning",
-      ],
-      datasets: [
-        {
-          label: "Species A",
-          data: [70, 50, 60, 75, 65, 80, 90],
-          backgroundColor: "#A6D1E6",
-          borderColor: "#A6D1E6",
-          borderWidth: 1,
-        },
-        {
-          label: "Species B",
-          data: [55, 65, 70, 80, 70, 60, 50],
-          backgroundColor: "#B6D7A8",
-          borderColor: "#B6D7A8",
-          borderWidth: 1,
-        },
-        {
-          label: "Species C",
-          data: [40, 60, 50, 65, 60, 75, 85],
-          backgroundColor: "#F9CB9C",
-          borderColor: "#F9CB9C",
-          borderWidth: 1,
-        },
-      ],
-    };
-    const speciesChart = new Chart(speciesChartCtx, {
-      type: "bar",
-      data: speciesData,
-      options: {
-        responsive: true,
-        plugins: {
-          legend: {
-            position: "top",
-          },
-          title: {
-            display: true,
-            text: "Oligosaccharides per Species at Different Lactation Stages",
-          },
-        },
-        scales: {
-          x: {
-            title: {
-              display: true,
-              text: "Lactation Stages",
-            },
-            grid: {
-              display: false,
-            },
-          },
-          y: {
-            beginAtZero: true,
-            title: {
-              display: true,
-              text: "Percentage%",
-            },
-            max: 100,
-          },
-        },
-      },
-    });
-  });
-
-  document.addEventListener("DOMContentLoaded", function () {
-    // lactation stages chart
-    const lactationChartCtx = document
-      .getElementById("lactationChart")
-      .getContext("2d");
-    const lactationData = {
-      labels: [
-        "Colostrum",
-        "Early Lactation",
-        "Farrowing",
-        "Mature Milk",
-        "Mid Lactation",
-        "Transitional Milk",
-        "Weaning",
-      ],
-      datasets: [
-        {
-          label: "Sialylated",
-          data: [80, 60, 50, 70, 65, 75, 85],
-          backgroundColor: "#3E5C76",
-          borderColor: "#3E5C76",
-          borderWidth: 1,
-        },
-        {
-          label: "Neutral",
-          data: [50, 70, 60, 80, 70, 65, 60],
-          backgroundColor: "#7F9BA6",
-          borderColor: "#7F9BA6",
-          borderWidth: 1,
-        },
-        {
-          label: "Fucosylated",
-          data: [40, 50, 40, 60, 55, 60, 65],
-          backgroundColor: "#9A9A9A",
-          borderColor: "#9A9A9A",
-          borderWidth: 1,
-        },
-        {
-          label: "Type I",
-          data: [60, 40, 30, 50, 55, 65, 60],
-          backgroundColor: "#6C8C94",
-          borderColor: "#6C8C94",
-          borderWidth: 1,
-        },
-        {
-          label: "Type II",
-          data: [30, 50, 60, 70, 65, 70, 75],
-          backgroundColor: "#C0A080",
-          borderColor: "#C0A080",
-          borderWidth: 1,
-        },
-      ],
-    };
-    const lactationChart = new Chart(lactationChartCtx, {
-      type: "bar",
-      data: lactationData,
-      options: {
-        responsive: true,
-        plugins: {
-          legend: { position: "top" },
-          title: {
-            display: true,
-            text: "Oligosaccharides by Lactation Stage",
-          },
-        },
-        scales: {
-          x: {
-            title: { display: true, text: "Lactation Stages" },
-            grid: { display: false },
-          },
-          y: {
-            beginAtZero: true,
-            title: { display: true, text: "Percentage%" },
-            max: 100,
-          },
-        },
-      },
-    });
-    // taxon's chart
-    const speciesChartCtx2 = document
-      .getElementById("speciesChart2")
-      .getContext("2d");
-    const speciesData = {
-      labels: [
-        "Colostrum",
-        "Early Lactation",
-        "Farrowing",
-        "Mature Milk",
-        "Mid Lactation",
-        "Transitional Milk",
-        "Weaning",
-      ],
-      datasets: [
-        {
-          label: "Species A",
-          data: [70, 50, 60, 75, 65, 80, 90],
-          backgroundColor: "#A6D1E6",
-          borderColor: "#A6D1E6",
-          borderWidth: 1,
-        },
-        {
-          label: "Species B",
-          data: [55, 65, 70, 80, 70, 60, 50],
-          backgroundColor: "#B6D7A8",
-          borderColor: "#B6D7A8",
-          borderWidth: 1,
-        },
-        {
-          label: "Species C",
-          data: [40, 60, 50, 65, 60, 75, 85],
-          backgroundColor: "#F9CB9C",
-          borderColor: "#F9CB9C",
-          borderWidth: 1,
-        },
-      ],
-    };
-    const speciesChart2 = new Chart(speciesChartCtx2, {
-      type: "bar",
-      data: speciesData,
-      options: {
-        responsive: true,
-        plugins: {
-          legend: { position: "top" },
-          title: { display: true, text: "Oligosaccharides by Species" },
-        },
-        scales: {
-          x: {
-            title: { display: true, text: "Lactation Stages" },
-            grid: { display: false },
-          },
-          y: {
-            beginAtZero: true,
-            title: { display: true, text: "Percentage%" },
-            max: 100,
-          },
-        },
-      },
-    });
-  });
-
-  // Distribution of samples per taxons
-  const taxonSampleCtx = document
-    .getElementById("taxonSampleChart")
-    .getContext("2d");
-  const taxonSampleChart = new Chart(taxonSampleCtx, {
-    type: "bar",
-    data: {
-      labels: [
-        "Sus scrofa",
-        "Homo sapiens",
-        "Bos taurus",
-        "Capra hircus",
-        "Elephas maximus",
-      ],
-      datasets: [
-        {
-          label: "Milk",
-          data: [0.5, 0.9, 0.2, 1, 0.7], // just for example
-          backgroundColor: "rgba(54, 162, 235, 0.7)",
-          borderColor: "rgba(54, 162, 235, 1)",
-          borderWidth: 1,
-        },
-        {
-          label: "Pooled Milk",
-          data: [1, 0.6, 0.2, 0.5, 0.4],
-          backgroundColor: "rgba(255, 99, 132, 0.7)",
-          borderColor: "rgba(255, 99, 132, 1)",
-          borderWidth: 1,
-        },
-      ],
-    },
-    options: {
-      responsive: true,
-      plugins: {
-        legend: {
-          position: "top",
-          labels: {
-            boxWidth: 20,
-            padding: 15,
-          },
-        },
-      },
-      scales: {
-        x: {
-          title: {
-            display: true,
-            text: "Taxons",
-            font: {
-              weight: "bold",
-              size: 14,
-            },
-          },
-          grid: {
-            display: false,
-          },
-        },
-        y: {
-          title: {
-            display: true,
-            text: "Sample Quantity",
-            font: {
-              weight: "bold",
-              size: 14,
-            },
-          },
-          beginAtZero: true,
-          grid: {
-            color: "#e0e0e0",
-          },
-        },
-      },
-    },
-  });
-
-  const sampleCharacteristicsCtx = document
-    .getElementById("sampleCharacteristicsChart")
-    .getContext("2d");
-  const sampleCharacteristicsChart = new Chart(
-    sampleCharacteristicsCtx,
-    {
-      type: "bar",
-      data: {
-        labels: [
-          "Colostrum",
-          "Early Lactation",
-          "Farrowing",
-          "Mature Milk",
-          "Mid Lactation",
-          "Transitional Milk",
-          "Weaning",
-        ],
-        datasets: [
-          {
-            label: "Milk - Fucosylated Oligo",
-            data: [0.9, 0.7, 0.5, 0.6, 0.8, 0.9, 0.4],
-            backgroundColor: "rgba(33, 150, 243, 0.7)", 
-            borderColor: "rgba(33, 150, 243, 1)",
-            borderWidth: 1,
-          },
-          {
-            label: "Pooled Milk - Fucosylated Oligo",
-            data: [0.8, 0.6, 0.4, 0.7, 0.7, 0.8, 0.5],
-            backgroundColor: "rgba(33, 150, 243, 0.4)", 
-            borderColor: "rgba(33, 150, 243, 1)",
-            borderWidth: 1,
-          },
-          {
-            label: "Milk - Sialylated Oligo",
-            data: [0.8, 0.5, 0.7, 0.6, 0.9, 0.6, 0.5],
-            backgroundColor: "rgba(76, 175, 80, 0.7)", 
-            borderColor: "rgba(76, 175, 80, 1)",
-            borderWidth: 1,
-          },
-          {
-            label: "Pooled Milk - Sialylated Oligo",
-            data: [0.7, 0.4, 0.6, 0.5, 0.8, 0.7, 0.4],
-            backgroundColor: "rgba(76, 175, 80, 0.4)",
-            borderColor: "rgba(76, 175, 80, 1)",
-            borderWidth: 1,
-          },
-          {
-            label: "Milk - Type I Oligo",
-            data: [0.6, 0.8, 0.4, 0.7, 0.5, 0.6, 0.7],
-            backgroundColor: "rgba(244, 67, 54, 0.7)", 
-            borderColor: "rgba(244, 67, 54, 1)",
-            borderWidth: 1,
-          },
-          {
-            label: "Pooled Milk - Type I Oligo",
-            data: [0.5, 0.7, 0.3, 0.6, 0.6, 0.5, 0.6],
-            backgroundColor: "rgba(244, 67, 54, 0.4)",
-            borderColor: "rgba(244, 67, 54, 1)",
-            borderWidth: 1,
-          },
-          {
-            label: "Milk - Type II Oligo",
-            data: [0.4, 0.6, 0.3, 0.5, 0.7, 0.8, 0.6],
-            backgroundColor: "rgba(255, 193, 7, 0.7)", 
-            borderColor: "rgba(255, 193, 7, 1)",
-            borderWidth: 1,
-          },
-          {
-            label: "Pooled Milk - Type II Oligo",
-            data: [0.3, 0.5, 0.2, 0.4, 0.6, 0.7, 0.5],
-            backgroundColor: "rgba(255, 193, 7, 0.4)",
-            borderColor: "rgba(255, 193, 7, 1)",
-            borderWidth: 1,
-          },
-          {
-            label: "Milk - Neutral Oligo",
-            data: [0.7, 0.6, 0.5, 0.7, 0.8, 0.5, 0.7],
-            backgroundColor: "rgba(121, 85, 72, 0.7)", 
-            borderColor: "rgba(121, 85, 72, 1)",
-            borderWidth: 1,
-          },
-          {
-            label: "Pooled Milk - Neutral Oligo",
-            data: [0.6, 0.5, 0.4, 0.6, 0.7, 0.6, 0.6],
-            backgroundColor: "rgba(121, 85, 72, 0.4)",
-            borderColor: "rgba(121, 85, 72, 1)",
-            borderWidth: 1,
-          },
-        ],
-      },
-      options: {
-        responsive: true,
-        plugins: {
-          legend: {
-            position: "top",
-            labels: {
-              boxWidth: 20,
-              padding: 15,
-              font: {
-                size: 12,
-              },
-            },
-          },
-        },
-        scales: {
-          x: {
-            title: {
-              display: true,
-              text: "Stages of Lactation",
-              font: {
-                weight: "bold",
-                size: 14,
-              },
-            },
-            grid: {
-              display: false,
-            },
-          },
-          y: {
-            title: {
-              display: true,
-              text: "Presence / Integrity",
-              font: {
-                weight: "bold",
-                size: 14,
-              },
-            },
-            beginAtZero: true,
-            grid: {
-              color: "#e0e0e0",
-            },
-          },
-        },
-      },
-    }
-  );
-
-  // Distribution of taxons
-  // const taxonsCtx = document
-  //   .getElementById("taxonsChart")
-  //   .getContext("2d");
-  // const taxonsChart = new Chart(taxonsCtx, {
-  //   type: "pie",
-  //   data: {
-  //     labels: [
-  //       "Neutral",
-  //       "Fucosylated",
-  //       "Sialylated",
-  //       "Type I",
-  //       "Type II",
-  //     ], // we raplace here with real names of taxons 
-  //     datasets: [
-  //       {
-  //         label: "Number of occurrences",
-  //         data: [30, 25, 20, 15, 10], // we replace here with real data
-  //         backgroundColor: [
-  //           "#4E79A7",
-  //           "#F28E2B",
-  //           "#E15759",
-  //           "#76B7B2",
-  //           "#59A14F",
-  //         ],
-  //         borderColor: "#ffffff",
-  //         borderWidth: 2,
-  //       },
-  //     ],
-  //   },
-  //   options: {
-  //     responsive: true,
-  //     plugins: {
-  //       legend: {
-  //         position: "top",
-  //         labels: {
-  //           font: {
-  //             size: 14,
-  //           },
-  //         },
-  //       },
-  //     },
-  //   },
-  // });
-
-  document.addEventListener("DOMContentLoaded", function () {
-    const taxonsCtx = document.getElementById("taxonsChart").getContext("2d");
-  
-    function fetchTaxonData() {
-      const apiUrl = "/_get/nb_occ_by_concept?concept=Oligosaccharide_type"; 
-      fetch(apiUrl)
-        .then((response) => {
-          if (!response.ok) {
-            throw new Error(`HTTP error! status: ${response.status}`);
-          }
-          return response.json();
-        })
-        .then((data) => {
-          if (!data.labels || !data.data || data.labels.length !== data.data.length) {
-            throw new Error("The structure of fetched data is invalid.");
-          }
-  
-          const taxonsChart = new Chart(taxonsCtx, {
-            type: "pie",
-            data: {
-              labels: data.labels, 
-              datasets: [
-                {
-                  label: "Number of occurrences",
-                  data: data.data,
-                  backgroundColor: [
-                    "#4E79A7",
-                    "#F28E2B",
-                    "#E15759",
-                    "#76B7B2",
-                    "#59A14F",
-                  ],
-                  borderColor: "#ffffff",
-                  borderWidth: 2,
-                },
-              ],
-            },
-            options: {
-              responsive: true,
-              plugins: {
-                legend: {
-                  position: "top",
-                  labels: {
-                    font: {
-                      size: 14,
-                    },
-                  },
-                },
-              },
-            },
-          });
-        })
-        .catch((error) => {
-          console.error("Error while fetching the data :", error);
-          alert("An error occurred while loading the data. Please try again later.");
-        });
-    }
-  
-
-    fetchTaxonData();
-  });
-  
-  
-  
-    
-
-  const labels = [
-    "Colostrum",
-    "Early Lactation",
-    "Farrowing",
-    "Mature Milk",
-    "Mid Lactation",
-    "Transitional Milk",
-    "Weaning",
-  ];
-
-  // Milk chart
-  const milkCtx = document.getElementById("milkChart").getContext("2d");
-  const milkChart = new Chart(milkCtx, {
-    type: "bar",
-    data: {
-      labels: labels,
-      datasets: [
-        {
-          label: "Fucosylated Oligo",
-          data: [0.9, 0.7, 0.5, 0.6, 0.8, 0.9, 0.4],
-          backgroundColor: "rgba(0, 123, 255, 0.7)", 
-          borderColor: "rgba(0, 123, 255, 1)", 
-          borderWidth: 1,
-        },
-        {
-          label: "Sialylated Oligo",
-          data: [0.8, 0.5, 0.7, 0.6, 0.9, 0.6, 0.5],
-          backgroundColor: "rgba(40, 167, 69, 0.7)", 
-          borderColor: "rgba(40, 167, 69, 1)", 
-          borderWidth: 1,
-        },
-        {
-          label: "Type I Oligo",
-          data: [0.6, 0.8, 0.4, 0.7, 0.5, 0.6, 0.7],
-          backgroundColor: "rgba(255, 193, 7, 0.7)", 
-          borderColor: "rgba(255, 193, 7, 1)",
-          borderWidth: 1,
-        },
-        {
-          label: "Type II Oligo",
-          data: [0.4, 0.6, 0.3, 0.5, 0.7, 0.8, 0.6],
-          backgroundColor: "rgba(23, 162, 184, 0.7)", 
-          borderColor: "rgba(23, 162, 184, 1)",
-          borderWidth: 1,
-        },
-        {
-          label: "Neutral Oligo",
-          data: [0.7, 0.6, 0.5, 0.7, 0.8, 0.5, 0.7],
-          backgroundColor: "rgba(108, 117, 125, 0.7)", 
-          borderColor: "rgba(108, 117, 125, 1)", 
-          borderWidth: 1,
-        },
-      ],
-    },
-    options: {
-      responsive: true,
-      plugins: {
-        legend: { position: "top" },
-      },
-      scales: {
-        x: { title: { display: true, text: "Stages of Lactation" } },
-        y: {
-          beginAtZero: true,
-          title: { display: true, text: "Presence / Integrity" },
-        },
-      },
-    },
-  });
-
-  // Pooled Milk chart
-  const pooledMilkCtx = document
-    .getElementById("pooledMilkChart")
-    .getContext("2d");
-  const pooledMilkChart = new Chart(pooledMilkCtx, {
-    type: "bar",
-    data: {
-      labels: labels,
-      datasets: [
-        {
-          label: "Fucosylated Oligo",
-          data: [0.8, 0.6, 0.4, 0.7, 0.7, 0.8, 0.5],
-          backgroundColor: "rgba(0, 123, 255, 0.4)", 
-          borderColor: "rgba(0, 123, 255, 1)", 
-          borderWidth: 1,
-        },
-        {
-          label: "Sialylated Oligo",
-          data: [0.7, 0.4, 0.6, 0.5, 0.8, 0.7, 0.4],
-          backgroundColor: "rgba(40, 167, 69, 0.4)", 
-          borderColor: "rgba(40, 167, 69, 1)", 
-          borderWidth: 1,
-        },
-        {
-          label: "Type I Oligo",
-          data: [0.5, 0.7, 0.3, 0.6, 0.6, 0.5, 0.6],
-          backgroundColor: "rgba(255, 193, 7, 0.4)", 
-          borderColor: "rgba(255, 193, 7, 1)", 
-          borderWidth: 1,
-        },
-        {
-          label: "Type II Oligo",
-          data: [0.3, 0.5, 0.2, 0.4, 0.6, 0.7, 0.5],
-          backgroundColor: "rgba(23, 162, 184, 0.4)", 
-          borderColor: "rgba(23, 162, 184, 1)", 
-          borderWidth: 1,
-        },
-        {
-          label: "Neutral Oligo",
-          data: [0.6, 0.5, 0.4, 0.6, 0.7, 0.6, 0.6],
-          backgroundColor: "rgba(108, 117, 125, 0.4)", 
-          borderColor: "rgba(108, 117, 125, 1)", 
-          borderWidth: 1,
-        },
-      ],
-    },
-    options: {
-      responsive: true,
-      plugins: {
-        legend: { position: "top" },
-      },
-      scales: {
-        x: { title: { display: true, text: "Stages of Lactation" } },
-        y: {
-          beginAtZero: true,
-          title: { display: true, text: "Presence / Integrity" },
-        },
-      },
-    },
-  });
-
-  // Heatmap 
-
-  const heatmapData = {
-    labels: [
-      "Colostrum",
-      "Early Lactation",
-      "Farrowing",
-      "Mature Milk",
-      "Mid Lactation",
-      "Transitional Milk",
-      "Weaning",
-    ],
-    datasets: [
-      {
-        label: "Sus scrofa",
-        data: [12, 19, 3, 5, 4, 8, 9],
-        backgroundColor: "rgba(248, 103, 59, 0.7)", 
-      },
-      {
-        label: "Bos taurus",
-        data: [2, 3, 20, 3, 12, 19, 3],
-        backgroundColor: "rgba(69, 139, 223, 0.7)", 
-      },
-      {
-        label: "Homo sapiens",
-        data: [3, 10, 13, 15, 20, 3, 12],
-        backgroundColor: "rgba(88, 214, 141, 0.7)", 
-      },
-      {
-        label: "Taxon 4",
-        data: [12, 19, 3, 5, 4, 8, 9],
-        backgroundColor: "rgba(255, 99, 132, 0.4)", 
-      },
-      {
-        label: "Taxon 5",
-        data: [2, 3, 20, 3, 9, 3, 5],
-        backgroundColor: "rgba(54, 162, 235, 0.4)", 
-      },
-      {
-        label: "Taxon 6",
-        data: [3, 10, 13, 15, 6, 3, 20],
-        backgroundColor: "rgba(75, 192, 192, 0.4)", 
-      },
-    ],
-  };
-
-  const heatmapOptions = {
-    responsive: true,
-    plugins: {
-      legend: {
-        position: "top",
-      },
-      tooltip: {
-        mode: "index",
-        intersect: false,
-        callbacks: {
-          label: function (tooltipItem) {
-            return tooltipItem.dataset.label + ": " + tooltipItem.raw; 
-          },
-        },
-      },
-    },
-    scales: {
-      x: {
-        stacked: true,
-        ticks: {
-          font: {
-            size: 14, 
-          },
-        },
-      },
-      y: {
-        stacked: true,
-        ticks: {
-          font: {
-            size: 14, 
-          },
-        },
-      },
-    },
-  };
-
-  const heatmapCtx = document
-    .getElementById("heatmapChart")
-    .getContext("2d");
-
-  new Chart(heatmapCtx, {
-    type: "bar",
-    data: heatmapData,
-    options: heatmapOptions,
-  });
-
-  // Stacked Bar Chart
-
-  const stackedBarData = {
-    labels: ["Milk", "Polled Milk"],
-    datasets: [
-      {
-        label: "Sialylated",
-        data: [20, 10],
-        backgroundColor: "rgba(246,190,167)",
-      },
-      {
-        label: "Neutral",
-        data: [5, 3],
-        backgroundColor: "rgba(250,207,190)",
-      },
-      {
-        label: "Fucosylated",
-        data: [2, 2],
-        backgroundColor: "rgba(253,220,203)",
-      },
-      {
-        label: "Type I",
-        data: [12, 40],
-        backgroundColor: "rgba(217,211,199)",
-      },
-      {
-        label: "Type II",
-        data: [30, 8],
-        backgroundColor: "rgba(218,217,215)",
-      },
-    ],
-  };
-
-  const stackedBarOptions = {
-    responsive: true,
-    plugins: {
-      legend: { position: "top" },
-    },
-    scales: {
-      x: { stacked: true },
-      y: { stacked: true, beginAtZero: true },
-    },
-  };
-
-  const stackedBarCtx = document
-    .getElementById("stackedBarChart2")
-    .getContext("2d");
-
-  new Chart(stackedBarCtx, {
-    type: "bar",
-    data: stackedBarData,
-    options: stackedBarOptions,
-  });
-
-- 
GitLab


From daa37a99589656284e17286986f0037fc9f7572e Mon Sep 17 00:00:00 2001
From: "hajar.bouamout" <hajar.bouamout@inrae.fr>
Date: Tue, 14 Jan 2025 16:41:00 +0100
Subject: [PATCH 21/51] page de recherche v2

---
 static/css/research.css | 376 ++++++++++++++++++++++------------------
 static/js/research.js   | 362 +++++++++++++++++++++++---------------
 templates/research.html | 182 +++++++++++--------
 3 files changed, 543 insertions(+), 377 deletions(-)

diff --git a/static/css/research.css b/static/css/research.css
index ae8ff87..4511e66 100644
--- a/static/css/research.css
+++ b/static/css/research.css
@@ -1,227 +1,273 @@
-/* General Styles */
-body {
-    font-family: 'Arial', sans-serif;
-    margin: 0;
-    padding: 0;
-    background-color: #f9f9f9;
-    line-height: 1.6;
-    color: #333;
-}
 
-/* Container */
-.container {
-    max-width: 1200px;
-    margin: 20px auto;
-    padding: 20px;
-    background-color: #ffffff;
-    border-radius: 8px;
-    box-shadow: 0 4px 10px rgba(0, 0, 0, 0.1);
-    margin-top: 100px;
+* {
+  margin: 0;
+  padding: 0;
+  box-sizing: border-box;
 }
 
-/* Navbar */
-.navbar {
-    background-color: #333;
-    padding: 15px 20px;
-    border-radius: 8px;
-    margin-bottom: 20px;
-}
-
-.nav-list {
-    list-style: none;
-    display: flex;
-    justify-content: center;
-    gap: 20px;
-    margin: 0;
-    padding: 0;
-}
-
-.nav-list li {
-    position: relative;
+body {
+  font-family: 'Arial', sans-serif;
+  line-height: 1.6;
+  background: linear-gradient(180deg, #ffffff, #f0f0f5);
+  color: #333;
+  margin: 0;
+  display: flex;
+  flex-direction: column;
+  min-height: 100vh;
 }
 
-.search-btn {
-    background-color: #007bff;
-    color: white;
-    padding: 10px 20px;
-    border: none;
-    border-radius: 6px;
-    font-size: 1rem;
-    cursor: pointer;
-    transition: background-color 0.3s ease, transform 0.2s ease;
+.container2 {
+  flex: 1;
+  display: flex;
+  flex-direction: column;
+  padding: 2rem;
+  gap: 2rem;
+  width: 100%;
+  max-width: 95%; 
+  margin-top: 30px;
+  overflow-x: auto;
 }
 
-.search-btn:hover {
-    background-color: #0056b3;
-    transform: scale(1.05);
+.main-content2 {
+  padding: 2rem;
+  background: #ffffff;
+  /* border-radius: 10px; */
+  /* box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1); */
+  /* overflow-y: auto; */
+  /* width: 100%;
+  height: 100%; */
+  margin-top: 100px;
 }
 
-.search-btn:focus {
-    outline: none;
-    box-shadow: 0 0 5px rgba(0, 123, 255, 0.7);
+/* Search Bar */
+.search-bar2 {
+  display: flex;
+  align-items: center;
+  gap: 1rem;
+  padding: 1.5rem;
+  background: #8eb1b5;
+  border-radius: 10px;
+  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.05);
+  position: relative;
 }
 
-/* Main Content */
-.main-content {
-    margin-top: 20px;
+.search-bar2 span {
+  color: #21517A;
+  font-weight: 500;
+  white-space: nowrap;
 }
 
-/* Sections */
-.search-section,
-.advanced-search-section,
-.results-section {
-    margin-bottom: 40px;
+.search-bar2 select {
+  padding: 0.75rem 1rem;
+  border: 1px solid #ddd;
+  border-radius: 6px;
+  background: #fff;
+  color: #333;
+  font-size: 1rem;
+  cursor: pointer;
+  min-width: 180px;
+  transition: all 0.3s ease;
 }
 
-.search-section h2,
-.advanced-search-section h2,
-.results-section h2 {
-    font-size: 2rem;
-    color: #0056b3;
-    margin-bottom: 20px;
-    text-align: center;
-    font-weight: bold;
+.search-bar2 select:hover,
+.search-bar2 select:focus {
+  border-color: #3498db;
+  box-shadow: 0 0 0 2px rgba(52, 152, 219, 0.1);
 }
 
-.search-bar {
-    display: flex;
-    flex-wrap: wrap;
-    gap: 15px;
-    justify-content: center;
-    align-items: center;
+.search-bar2 input {
+  flex: 1;
+  padding: 0.75rem 1rem;
+  border: 1px solid #ddd;
+  border-radius: 6px;
+  font-size: 1rem;
+  transition: all 0.3s ease;
 }
 
-.search-bar input,
-.search-bar select,
-textarea {
-    padding: 10px;
-    font-size: 1rem;
-    border: 1px solid #ddd;
-    border-radius: 6px;
-    width: 300px;
-}
-
-.search-bar input:focus,
-.search-bar select:focus,
-textarea:focus {
-    outline: none;
-    border-color: #007bff;
-    box-shadow: 0 0 5px rgba(0, 123, 255, 0.7);
+.search-bar2 input:focus {
+  outline: none;
+  border-color: #3498db;
+  box-shadow: 0 0 0 2px rgba(52, 152, 219, 0.1);
 }
 
+/* Autocomplete */
 .autocomplete-box {
-    background-color: #ffffff;
-    border: 1px solid #ddd;
-    border-radius: 6px;
-    max-width: 300px;
-    margin: 5px auto;
-    box-shadow: 0 2px 6px rgba(0, 0, 0, 0.1);
-    position: absolute;
-    z-index: 10;
+  position: absolute;
+  top: calc(100% - 10px);
+  left: 250px;
+  right: 100px;
+  background: white;
+  border: 1px solid #ddd;
+  border-radius: 0 0 8px 8px;
+  max-height: 200px;
+  overflow-y: auto;
+  z-index: 1000;
+  /* box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1); */
 }
 
 .autocomplete-box div {
-    padding: 10px;
-    cursor: pointer;
-    border-bottom: 1px solid #f1f1f1;
+  padding: 0.75rem 1rem;
+  cursor: pointer;
+  transition: all 0.2s ease;
 }
 
 .autocomplete-box div:hover {
-    background-color: #f1f1f1;
+  background-color: #f0f7ff;
+  color: #21517A;
+}
+
+
+/* Table Styles for Large Data */
+.results-section {
+  background: #ffffff;
+  padding: 20px;
+  border-radius: 10px;
+  box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
+  width: 100%;
+  overflow-x: auto;
+  display: none;
+  /* margin-top: 100px; */
 }
 
-/* Results Table */
 .results-table {
-    width: 100%;
-    border-collapse: collapse;
-    margin: 0 auto;
-    font-size: 1rem;
+  width: 100%;
+  border-collapse: collapse;
+  margin-top: 20px;
+  font-size: 1rem;
+  table-layout: fixed; 
 }
 
 .results-table th,
 .results-table td {
-    padding: 12px 15px;
-    border: 1px solid #ddd;
-    text-align: center;
+  text-align: left;
+  padding: 15px;
+  border: 1px solid #ddd;
+  word-wrap: break-word; 
 }
 
 .results-table th {
-    background-color: #007bff;
-    color: white;
-    font-weight: bold;
+  background: #274757;
+  color: white;
+  font-size: 1.1rem;
+  text-transform: uppercase;
 }
 
 .results-table tr:nth-child(even) {
-    background-color: #f9f9f9;
+  background-color: #f9f9f9;
 }
 
 .results-table tr:hover {
-    background-color: #f1f1f1;
-    cursor: pointer;
+  background-color: #f1f1f1;
+  transition: background-color 0.3s ease;
 }
 
-.details-btn {
-    background-color: #28a745;
-    color: white;
-    padding: 8px 12px;
-    border: none;
-    border-radius: 4px;
-    font-size: 0.9rem;
-    cursor: pointer;
-    transition: background-color 0.3s ease;
+/* Pagination Styles */
+#pagination {
+  margin-top: 20px;
+  text-align: center;
 }
 
-.details-btn:hover {
-    background-color: #218838;
+#pagination button {
+  background: linear-gradient(45deg, #3498db, #2980b9);
+  color: white;
+  border: none;
+  padding: 10px 15px;
+  margin: 0 5px;
+  border-radius: 8px;
+  cursor: pointer;
+  font-size: 1rem;
+  transition: transform 0.3s ease, box-shadow 0.3s ease;
 }
 
-/* Advanced Search */
-.advanced-search-section textarea {
-    width: 100%;
-    height: 120px;
-    resize: none;
+#pagination button.active {
+  background: #2980b9;
+  font-weight: bold;
 }
 
-.advanced-btn {
-    background-color:  #007bff;
-    color: white;
-    padding: 10px 20px;
-    border-radius: 6px;
-    font-size: 1rem;
-    border: none;
-    cursor: pointer;
-    transition: background-color 0.3s ease;
+#pagination button:hover {
+  transform: scale(1.1);
+  box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2);
 }
 
-.advanced-btn:hover {
-    background-color: #5a6268;
+/* Large Data Adjustments */
+.results-table td {
+  max-width: 300px; 
+  white-space: nowrap; 
+  overflow: hidden; 
+  text-overflow: ellipsis; 
 }
 
-/* Accessibility Enhancements */
-button:focus,
-input:focus {
-    outline: none;
-    box-shadow: 0 0 5px rgba(0, 123, 255, 0.7);
+.results-table th:first-child,
+.results-table td:first-child {
+  width: 25%; 
 }
 
-/* Mobile Responsiveness */
-@media (max-width: 768px) {
-    .search-bar {
-        flex-direction: column;
-        gap: 10px;
-    }
+.results-table td:hover {
+  overflow: visible; 
+  white-space: normal; 
+}
 
-    .navbar {
-        flex-wrap: wrap;
-        text-align: center;
-    }
 
-    .search-btn {
-        width: 100%;
-        margin: 5px 0;
-    }
+/* Responsive */
+@media (min-width: 1200px) {
+  .container {
+    max-width: 90%; 
+  }
+  
+  .main-content {
+    padding: 4rem;
+  }
+}
+
+.info-section {
+  background-color: #f0f7f6;
+  border-radius: 10px;
+  box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
+  padding: 20px;
+  text-align: center;
+  margin-bottom: 20px;
+}
+
+.info-section {
+  margin-bottom: 10px;
+}
+
+.info-section h2 {
+  font-size: 2rem;
+  color: #21517A;
+}
+
+.info-section p {
+  font-size: 1.1rem;
+  color: #333;
+}
+
+/* Section Getting Started */
+.getting-started {
+  background-color: #f0f7f6;
+  border-radius: 10px;
+  box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
+  padding: 20px;
+  margin-bottom: 20px;
+}
+
+.getting-started h3 {
+  color: #21517A;
+  font-size: 1.5rem;
+}
+
+.getting-started ul {
+  font-size: 1.1rem;
+  color: #333;
+  text-align: left;
+  margin-top: 10px;
+  padding-left: 20px;
+}
+
+.getting-started ul li {
+  margin-bottom: 10px;
+}
 
-    .results-table {
-        font-size: 0.9rem;
-    }
+.search-icon i {
+  font-size: 40px;
 }
diff --git a/static/js/research.js b/static/js/research.js
index 73c43a9..2e540c7 100644
--- a/static/js/research.js
+++ b/static/js/research.js
@@ -1,150 +1,195 @@
-// Mock Data
+// ========================= Mock Data =========================
+// Sample data used for demonstrating search and pagination functionality
 const dummyData = [
     {
-        oligosaccharide: "2'-Fucosyllactose (2'-FL)",
-        sample: "Milk Sample A-123",
+        oligosaccharide: {
+            name: "2'-Fucosyllactose",
+            url: "https://pubmed.ncbi.nlm.nih.gov/30149573/"            
+        },  
+        oligosaccharide_type: "Fucosylated" ,   
+        sample: "Milk Sample A-123 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
         species: "Human",
+        descendants: ["Homo sapiens sapiens", "Homo erectus"],
         lactationStage: "Early",
-        totalUsers: 3245
     },
     {
-        oligosaccharide: "3'-Sialyllactose (3'-SL)",
+        oligosaccharide: {
+            name: "3'-Sialyllactose (3'-SL)",
+            url : null            
+        },
+        oligosaccharide_type: "Sialylated",
         sample: "Milk Sample B-456",
         species: "Cow",
+        descendants: null,
         lactationStage: "Mid",
-        totalUsers: 2890
     },
+
+
+    {
+        oligosaccharide: {
+            name: "3'-Sialyllactose (3'-SL)",
+            url : null            
+        },
+        oligosaccharide_type: "Sialylated",
+        sample: "Milk Sample B-456",
+        species: "homo sapiens",
+        descendants: null,
+        lactationStage: "Mid",
+    },
+
+
     {
-        oligosaccharide: "6'-Sialyllactose (6'-SL)",
+        oligosaccharide: {
+            name: "6'-Sialyllactose (6'-SL)",
+            url : null,  
+        },
+        oligosaccharide_type: "Sialylated" ,
         sample: "Milk Sample C-789",
         species: "Goat",
+        descendants: null,
         lactationStage: "Late",
-        totalUsers: 1567
     },
     {
-        oligosaccharide: "Lacto-N-tetraose (LNT)",
+        oligosaccharide: {
+            name : "Lacto-N-tetraose (LNT)",
+            url : null            
+        },
+        oligosaccharide_type: "Lacto-N",
         sample: "Milk Sample D-101",
         species: "Human",
         lactationStage: "Early",
-        totalUsers: 4102
     },
     {
-        oligosaccharide: "Lacto-N-neotetraose (LNnT)",
+        oligosaccharide: {
+            name : "Lacto-N-neotetraose (LNnT)",
+            url : null
+        },
+        oligosaccharide_type: "Lacto-N",
         sample: "Milk Sample E-112",
         species: "Human",
         lactationStage: "Mid",
-        totalUsers: 3678
     },
     {
-        oligosaccharide: "Lacto-N-fucopentaose I (LNFP-I)",
+        oligosaccharide: {
+            name : "Lacto-N-fucopentaose I (LNFP-I)",
+            url : null
+        },
+        oligosaccharide_type: "Lacto-N",
         sample: "Milk Sample F-131",
         species: "Human",
         lactationStage: "Late",
-        totalUsers: 2456
     },
     {
-        oligosaccharide: "3'-Galactosyllactose (3'-GL)",
+        oligosaccharide: {
+            name : "3'-Galactosyllactose (3'-GL)",
+            url : null,
+        },
+        oligosaccharide_type: "Galactosylated",
         sample: "Milk Sample G-415",
         species: "Rabbit",
+        descendants: null,
         lactationStage: "Early",
-        totalUsers: 890
     },
     {
-        oligosaccharide: "4'-Galactosyllactose (4'-GL)",
+        oligosaccharide: {
+            name : "4'-Galactosyllactose (4'-GL)",
+            url : null
+        },
+        oligosaccharide_type: "Galactosylated",
         sample: "Milk Sample H-521",
         species: "Rabbit",
+        descendants: null,
         lactationStage: "Mid",
-        totalUsers: 765
     },
     {
-        oligosaccharide: "Sialyl-lacto-N-tetraose a (LSTa)",
+        oligosaccharide: {
+            name : "Sialyl-lacto-N-tetraose a (LSTa)",
+            url : null,
+        },
+        oligosaccharide_type: "Sialylated",
         sample: "Milk Sample I-634",
         species: "Sheep",
+        descendants: null,
         lactationStage: "Early",
-        totalUsers: 1234
     },
     {
-        oligosaccharide: "Sialyl-lacto-N-tetraose b (LSTb)",
+        oligosaccharide: {
+            name : "Sialyl-lacto-N-tetraose b (LSTb)",
+            url : null,
+           
+        },
+        oligosaccharide_type: "Sialylated",
         sample: "Milk Sample J-747",
         species: "Sheep",
         lactationStage: "Mid",
-        totalUsers: 1567
     },
     {
-        oligosaccharide: "Sialyl-lacto-N-tetraose c (LSTc)",
+        oligosaccharide: {
+            name : "Sialyl-lacto-N-tetraose c (LSTc)",
+            url : null,
+        },
+        oligosaccharide_type : "Sialylated",
         sample: "Milk Sample K-858",
         species: "Horse",
+        descendants: null,
         lactationStage: "Late",
-        totalUsers: 678
     }
 ];
 
-// Global variable to store current data
-let currentData = [...dummyData];
-
-// Toggle between Simple and Advanced Search
-function toggleSearch(type) {
-    const simpleSection = document.getElementById('simple-search-section');
-    const advancedSection = document.getElementById('advanced-search-section');
-    
-    if (type === 'simple') {
-        simpleSection.style.display = 'block';
-        advancedSection.style.display = 'none';
-        // Clear advanced search
-        document.getElementById('advanced-search-input').value = '';
-    } else if (type === 'advanced') {
-        simpleSection.style.display = 'none';
-        advancedSection.style.display = 'block';
-        // Clear simple search
-        document.getElementById('simple-search').value = '';
-        document.getElementById('autocomplete-suggestions').innerHTML = '';
-    }
-    
-    // Reset results
-    currentData = [...dummyData];
-    populateResults(currentData);
-}
+// ========================= Global Variables =========================
+// Global variables to store the current dataset and manage pagination
+let currentData = [...dummyData]; 
+let currentPage = 1; 
+const resultsPerPage = 5; 
 
-// Simple Search Implementation
-document.querySelector('#simple-search-section .search-btn').addEventListener('click', performSimpleSearch);
-document.getElementById('simple-search').addEventListener('keyup', function(event) {
-    if (event.key === 'Enter') {
-        performSimpleSearch();
-    }
-});
+// ========================= Simple Search =========================
+// Initialize DOM elements for simple search functionality
+const searchInput = document.getElementById('simple-search');
+const searchButton = document.querySelector('#simple-search-section .search-btn');
+const suggestionBox = document.getElementById('suggestion-box');
+let activeIndex = -1; // Active index for navigating through suggestions
 
+// Main function to perform a simple search
 function performSimpleSearch() {
-    const searchType = document.getElementById('simple-search-type').value;
-    const searchQuery = document.getElementById('simple-search').value.toLowerCase().trim();
-
+    const searchType = document.getElementById('simple-search-type').value; // Type of search (e.g., name, species)
+    const searchQuery = searchInput.value.toLowerCase().trim(); 
     if (!searchQuery) {
+        // If no keyword, reset results to the full dataset
         currentData = [...dummyData];
         populateResults(currentData);
         return;
     }
 
+    // Filter the data based on the search type and query
     const filteredData = dummyData.filter(item => {
-        switch(searchType) {
-            case 'oligosaccharides':
-                return item.oligosaccharide.toLowerCase().includes(searchQuery);
+        switch (searchType) {
+            case 'oligosaccharide_name':
+                return item.oligosaccharide.name.toLowerCase().includes(searchQuery);
             case 'species':
-                return item.species.toLowerCase().includes(searchQuery);
+                return (item.species.toLowerCase().includes(searchQuery) ||
+                (item.descendants && item.descendants.some(desc => desc.toLowerCase().includes(searchQuery)))
+                );
             case 'samples':
                 return item.sample.toLowerCase().includes(searchQuery);
             case 'lactation-stage':
                 return item.lactationStage.toLowerCase().includes(searchQuery);
+            case 'oligosaccharide_type':
+                return item.oligosaccharide_type.toLowerCase().includes(searchQuery);
             default:
                 return true;
         }
     });
 
+    // Update the current data and refresh the results table
     currentData = filteredData;
     populateResults(filteredData);
 }
 
-// Autocomplete for Simple Search
+// ========================= Autocomplete =========================
+// Function to provide suggestions for simple search input
 function autocompleteSearch(query) {
     if (!query) {
+        // Clear suggestions if query is empty
         document.getElementById('autocomplete-suggestions').innerHTML = '';
         return;
     }
@@ -153,15 +198,26 @@ function autocompleteSearch(query) {
     const suggestions = new Set();
     const queryLower = query.toLowerCase();
 
+    // Generate suggestions based on search type
     dummyData.forEach(item => {
         let value = '';
-        switch(searchType) {
-            case 'oligosaccharides':
-                value = item.oligosaccharide;
+        switch (searchType) {
+            case 'oligosaccharide_name':
+                value = item.oligosaccharide.name;
                 break;
-            case 'species':
-                value = item.species;
+            case 'oligosaccharide_type':
+                value = item.oligosaccharide_type;
                 break;
+                case 'species':
+                    // Include both species and descendants in suggestions
+                    value = item.species;
+                    if (value.toLowerCase().includes(queryLower)) suggestions.add(value);
+                    if (item.descendants) {
+                        item.descendants.forEach(desc => {
+                            if (desc.toLowerCase().includes(queryLower)) suggestions.add(desc);
+                        });
+                    }
+                    break;
             case 'samples':
                 value = item.sample;
                 break;
@@ -174,8 +230,10 @@ function autocompleteSearch(query) {
         }
     });
 
+    // Update the suggestions box with the filtered suggestions
     const suggestionBox = document.getElementById('autocomplete-suggestions');
     suggestionBox.innerHTML = '';
+    activeIndex = -1;
 
     if (suggestions.size > 0) {
         Array.from(suggestions)
@@ -184,83 +242,47 @@ function autocompleteSearch(query) {
                 const div = document.createElement('div');
                 div.textContent = item;
                 div.onclick = () => {
-                    document.getElementById('simple-search').value = item;
+                    searchInput.value = item;
                     suggestionBox.innerHTML = '';
                     performSimpleSearch();
                 };
                 suggestionBox.appendChild(div);
             });
     }
-}
-
-// Advanced Search Implementation
-document.querySelector('#advanced-search-section .advanced-btn').addEventListener('click', performAdvancedSearch);
-document.getElementById('advanced-search-input').addEventListener('keyup', function(event) {
-    if (event.key === 'Enter') {
-        performAdvancedSearch();
-    }
-});
-
-function performAdvancedSearch() {
-    const query = document.getElementById('advanced-search-input').value.trim();
-    
-    if (!query) {
-        currentData = [...dummyData];
-        populateResults(currentData);
-        return;
-    }
 
-    try {
-        const filteredData = dummyData.filter(item => {
-            const andConditions = query.split('AND').map(condition => condition.trim());
-            
-            return andConditions.every(condition => {
-                if (condition.includes('NOT')) {
-                    const [field, value] = parseSearchCondition(condition.replace('NOT', '').trim());
-                    return !matchesCondition(item, field, value);
-                } else {
-                    const [field, value] = parseSearchCondition(condition);
-                    return matchesCondition(item, field, value);
-                }
-            });
-        });
-
-        currentData = filteredData;
-        populateResults(filteredData);
-    } catch (error) {
-        alert('Invalid search query. Please use format: field: "value" \nExample: species: "human" AND stage: "early"');
-    }
 }
 
-// Helper function to parse search conditions
-function parseSearchCondition(condition) {
-    const matches = condition.match(/(\w+):\s*["'](.+?)["']/);
-    if (!matches) {
-        throw new Error('Invalid search syntax');
-    }
-    return [matches[1], matches[2]];
+// ========================= Pagination =========================
+// Function to paginate results based on the current page and results per page
+function paginateResults(data) {
+    const start = (currentPage - 1) * resultsPerPage;
+    const end = start + resultsPerPage;
+    return data.slice(start, end);
 }
 
-// Helper function to check if an item matches a condition
-function matchesCondition(item, field, value) {
-    const searchValue = value.toLowerCase();
-    switch(field.toLowerCase()) {
-        case 'species':
-            return item.species.toLowerCase().includes(searchValue);
-        case 'stage':
-            return item.lactationStage.toLowerCase().includes(searchValue);
-        case 'samples':
-            return item.sample.toLowerCase().includes(searchValue);
-        case 'oligosaccharide':
-            return item.oligosaccharide.toLowerCase().includes(searchValue);
-        default:
-            return false;
+// Function to render pagination buttons
+function renderPagination(totalItems) {
+    const paginationElement = document.getElementById('pagination');
+    paginationElement.innerHTML = '';
+
+    const totalPages = Math.ceil(totalItems / resultsPerPage);
+    for (let i = 1; i <= totalPages; i++) {
+        const button = document.createElement('button');
+        button.textContent = i;
+        button.className = i === currentPage ? 'active' : '';
+        button.onclick = () => {
+            currentPage = i;
+            populateResults(currentData);
+        };
+        paginationElement.appendChild(button);
     }
 }
 
-// Update the populateResults function
+// ========================= Results Table =========================
+// Function to populate the results table with the given data
 function populateResults(data) {
     const resultsBody = document.getElementById("results-body");
+    const paginatedData = paginateResults(data);
     resultsBody.innerHTML = "";
 
     if (data.length === 0) {
@@ -274,29 +296,91 @@ function populateResults(data) {
         return;
     }
 
-    data.forEach((item) => {
+    // Create table rows for each item in the paginated data
+    paginatedData.forEach((item) => {
+        const oligosaccharideContent = item.oligosaccharide.url
+            ? `<a href="${item.oligosaccharide.url}" target="_blank">${item.oligosaccharide.name}</a>`
+            : item.oligosaccharide.name;
+
         const row = document.createElement("tr");
         row.innerHTML = `
-            <td>${item.oligosaccharide}</td>
+            <td>${oligosaccharideContent}</td>
+            <td>${item.oligosaccharide_type}</td>
             <td>${item.sample}</td>
             <td>${item.species}</td>
             <td>${item.lactationStage}</td>
-            <td><button class="details-btn" onclick="showDetails('${item.oligosaccharide}')">Details</button></td>
+            <td><button class="details-btn" onclick="showDetails('${item.oligosaccharide.name}')">Details</button></td>
         `;
         resultsBody.appendChild(row);
     });
+
+    // Render pagination buttons
+    renderPagination(data.length);
 }
 
-// Details function
-function showDetails(oligosaccharide) {
-   window.location.href = `sheet?oligosaccharide=${encodeURIComponent(oligosaccharide)}`;
+// ========================= Additional Features =========================
+// Redirect to a details page with the selected oligosaccharide
+function showDetails(oligosaccharideName) {
+    window.location.href = `sheet?oligosaccharide=${encodeURIComponent(oligosaccharideName)}`;
 }
 
+// Toggle visibility of extra information
+function toggleExtraInfo(button) {
+    const extraInfo = button.nextElementSibling;
+    if (extraInfo.style.display === "none") {
+        extraInfo.style.display = "block";
+        button.textContent = "-";
+    } else {
+        extraInfo.style.display = "none";
+        button.textContent = "+";
+    }
+}
 
+// Sort table data by the selected column
+function sortTable(columnIndex) {
+    const sortedData = [...currentData].sort((a, b) => {
+        const valueA = Object.values(a)[columnIndex]?.toString().toLowerCase() || '';
+        const valueB = Object.values(b)[columnIndex]?.toString().toLowerCase() || '';
+        return valueA.localeCompare(valueB);
+    });
+    populateResults(sortedData);
+}
 
-// Initialize on page load
+// ========================= Initialization =========================
+// Initialize the page and set up event listeners on page load
 window.onload = function() {
-    toggleSearch('simple');
     currentData = [...dummyData];
     populateResults(currentData);
-};
\ No newline at end of file
+};
+
+function showSimpleSearchResults() {
+    const searchType = document.getElementById('simple-search-type').value;
+    const searchKeyword = document.getElementById('simple-search').value;
+
+    if (searchKeyword.trim() === '') {
+      alert('Please enter a keyword!');
+      return;
+    }
+
+    const resultsSection = document.getElementById('results-section');
+    resultsSection.style.display = 'block';
+
+    console.log(`Search by ${searchType} with keyword "${searchKeyword}"`);
+  }
+
+// This script toggles the visibility of table columns based on checkbox selections.
+  document.querySelectorAll('#column-toggles input[type="checkbox"]').forEach((checkbox) => {
+    checkbox.addEventListener('change', function () {
+      const column = this.dataset.column; 
+      const table = document.querySelector('.results-table');
+      const rows = table.querySelectorAll('tr');
+  
+      rows.forEach((row) => {
+        const cells = row.querySelectorAll('th, td');
+        if (cells[column]) {
+          cells[column].style.display = this.checked ? '' : 'none';
+        }
+      });
+    });
+  });
+  
\ No newline at end of file
diff --git a/templates/research.html b/templates/research.html
index d0b99e9..61fd4ed 100644
--- a/templates/research.html
+++ b/templates/research.html
@@ -1,4 +1,4 @@
-{% extends 'main3' %} {% block content %}
+{% extends 'main2' %} {% block content %}
 
 <head>
   <link
@@ -11,82 +11,118 @@
   ></script>
 </head>
 
-<body>
-  <div class="container">
-    <!-- Left Navigation Bar -->
-    <nav class="navbar">
-      <ul class="nav-list">
-        <li>
-          <button class="search-btn" onclick="toggleSearch('simple')">
-            Simple Search
-          </button>
-        </li>
-        <li>
-          <button class="search-btn" onclick="toggleSearch('advanced')">
-            Advanced Search
-          </button>
-        </li>
-      </ul>
-    </nav>
+<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
 
-    <!-- Main Content -->
-    <div class="main-content">
-      <!-- Simple Search -->
-      <section id="simple-search-section" class="search-section">
-        <h2>Simple Search</h2>
-        <div class="search-bar">
-          <span>Search By:</span>
-          <select id="simple-search-type">
-            <option value="oligosaccharides">Oligosaccharides</option>
-            <option value="species">Species</option>
-            <option value="samples">Samples</option>
-            <option value="lactation-stage">Lactation Stage</option>
-          </select>
-          <input
-            type="text"
-            id="simple-search"
-            placeholder="Enter a keyword to begin..."
-            onkeyup="autocompleteSearch(this.value)"
-          />
-          <div id="autocomplete-suggestions" class="autocomplete-box"></div>
-          <button class="search-btn">Search</button>
+<script
+  type="application/javascript"
+  src="https://cdn.jsdelivr.net/npm/chartjs-chart-boxplot@4.0.0/dist/chartjs-chart-boxplot.min.js"
+></script>
+
+<script
+  type="application/javascript"
+  src="/static/js/chartjs-chart-box-and-violin-plot.min.js"
+></script>
+
+<body>
+  <div class="main-content2">
+    <section class="info-section">
+      <div class="info-box">
+        <div class="search-icon">
+          <i class="fas fa-search"></i>
         </div>
-      </section>
+        <h2>Simple Search</h2>
+        <p>
+          Quickly find oligosaccharides by name, type, species, or lactation
+          stage. Perfect for direct queries when you know what you're looking
+          for.
+        </p>
+      </div>
+    </section>
+
+    <!-- Section "Getting Started" 
+    <section class="getting-started">
+      <div class="info-box">
+        <h3>Getting Started</h3>
+        <ul>
+          <li>Select your search type from the dropdown menu</li>
+          <li>Enter your search terms in the search bar</li>
+          <li>Use the autocomplete suggestions for accurate results</li>
+          <li>Click search to view your results</li>
+        </ul>
+      </div>
+    </section>-->
+
+    <!-- Simple Search Form -->
+    <section id="simple-search-section" class="search-section">
+      <h2>Simple Search</h2>
+      <div class="search-bar2">
+        <span>Search By:</span>
+        <select id="simple-search-type">
+          <option value="oligosaccharide_name">Oligosaccharide Name</option>
+          <option value="oligosaccharide_type">Oligosaccharide Type</option>
+          <option value="species">Species</option>
+          <option value="samples">Samples</option>
+          <option value="lactation-stage">Lactation Stage</option>
+        </select>
+        <input
+          type="text"
+          id="simple-search"
+          placeholder="Enter a keyword to begin..."
+          onkeyup="autocompleteSearch(this.value)"
+        />
+        <div id="autocomplete-suggestions" class="autocomplete-box"></div>
+        <button class="search-btn" onclick="showSimpleSearchResults()">
+          Search
+        </button>
+        <div id="suggestion-box" class="autocomplete-box"></div>
+      </div>
+    </section>
+
+    <!-- Results Section -->
+    <section id="results-section" class="results-section">
+      <h2>Search Results</h2>
+      <div id="column-toggles">
+        <label
+          ><input type="checkbox" data-column="0" checked /> Oligosaccharide
+          Name</label
+        >
+        <label
+          ><input type="checkbox" data-column="1" checked /> Oligosaccharide
+          Type</label
+        >
+        <label><input type="checkbox" data-column="2" checked /> Sample</label>
+        <label><input type="checkbox" data-column="3" checked /> Species</label>
+        <label
+          ><input type="checkbox" data-column="4" checked /> Lactation
+          Stage</label
+        >
+        <label><input type="checkbox" data-column="5" checked /> Details</label>
+      </div>
 
-      <!-- Advanced Search -->
-      <section
-        id="advanced-search-section"
-        class="advanced-search-section"
-        style="display: none"
-      >
-        <h2>Advanced Search</h2>
-        <p>Use logical operators to create more complex queries.</p>
-        <textarea
-          id="advanced-search-input"
-          placeholder="Example: species: 'rabbit' AND stage: 'early' NOT samples: 'milk'"
-        ></textarea>
-        <button class="search-btn advanced-btn">Search</button>
-      </section>
+      <table class="results-table">
+        <thead>
+          <tr>
+            <th onclick="sortTable(0)">
+              Oligosaccharide Name <i class="fas fa-sort"></i>
+            </th>
+            <th onclick="sortTable(1)">
+              Oligosaccharide Type <i class="fas fa-sort"></i>
+            </th>
+            <th onclick="sortTable(2)">Sample <i class="fas fa-sort"></i></th>
+            <th onclick="sortTable(3)">Species <i class="fas fa-sort"></i></th>
+            <th onclick="sortTable(4)">
+              Lactation Stage <i class="fas fa-sort"></i>
+            </th>
+            <th onclick="sortTable(5)">Details <i class="fas fa-sort"></i></th>
+          </tr>
+        </thead>
+        <tbody id="results-body">
+          <!-- Rows will be dynamically populated by JavaScript -->
+        </tbody>
+      </table>
 
-      <!-- Results Table -->
-      <section id="results-section" class="results-section">
-        <h2>Search Results</h2>
-        <table class="results-table">
-          <thead>
-            <tr>
-              <th>Oligosaccharide</th>
-              <th>Sample</th>
-              <th>Species</th>
-              <th>Lactation Stage</th>
-              <th>Details</th>
-            </tr>
-          </thead>
-          <tbody id="results-body">
-            <!-- Rows will be dynamically populated by JavaScript -->
-          </tbody>
-        </table>
-      </section>
-    </div>
+      <div id="pagination" style="margin-top: 20px; text-align: center"></div>
+    </section>
   </div>
 </body>
 
-- 
GitLab


From c3fcfd27efa0378e52b181b8ce458d3a7b50c719 Mon Sep 17 00:00:00 2001
From: "hajar.bouamout" <hajar.bouamout@inrae.fr>
Date: Tue, 14 Jan 2025 16:42:49 +0100
Subject: [PATCH 22/51] modification css et structure de la page d'accueil

---
 static/css/home.css | 242 +++++++++++++++++++++++++-------------------
 templates/home.html |   4 +-
 2 files changed, 138 insertions(+), 108 deletions(-)

diff --git a/static/css/home.css b/static/css/home.css
index ec9d447..fae9b5c 100644
--- a/static/css/home.css
+++ b/static/css/home.css
@@ -1,113 +1,143 @@
 body {
-    font-family: 'Roboto', sans-serif;
-    color: #333;
-    background-color: #f8f9fa;
-  }
-  
-  /* Hero Section */
+  font-family: 'Roboto', sans-serif;
+  color: #333;
+  background-color: #f8f9fa;
+}
+
+/* Hero Section */
 .hero-section {
-    background: linear-gradient(145deg, #274757, #0077cc);
-    padding: 4rem 0;
-    border-radius: 0 0 2rem 2rem;
-    color: white;
-  }
-  
-  .hero-section h1 {
-    color: black;
-    font-size: 2.8rem;
-    margin-bottom: 1.5rem;
-  }
-  
-  .hero-section .description {
-    max-width: 800px;
-    margin: 0 auto;
-    font-size: 1.2rem;
-    line-height: 1.6;
-    color :black;
-    opacity: 0.95;
-  }
-  
-  .btn-info {
-    background-color: #4a90e2;
-    border: none;
-    padding: 0.8rem 2rem;
-    border-radius: 2rem;
-    font-weight: 500;
-    transition: transform 0.2s;
-  }
-  
-  .btn-info:hover {
-    transform: translateY(-2px);
-    background-color: #357abd;
-  }
-  
-  /* Data Overview Section */
-  .section-title {
-    font-size: 2.2rem;
-    color: #274757;
-    font-weight: 600;
-  }
-  
+  background: linear-gradient(145deg, #274757, #0077cc);
+  padding: 4rem 0;
+  border-radius: 0 0 2rem 2rem;
+  color: white;
+  margin-top: 40px;
+}
+
+.hero-section h1 {
+  color: black;
+  font-size: 2.8rem;
+  margin-bottom: 1.5rem;
+}
+
+.hero-section .description {
+  max-width: 800px;
+  margin: 0 auto;
+  font-size: 1.2rem;
+  line-height: 1.6;
+  color :black;
+  opacity: 0.95;
+}
+
+.btn-info {
+  background-color: #274757;
+  border: none;
+  padding: 0.8rem 2rem;
+  border-radius: 2rem;
+  font-weight: 500;
+  transition: transform 0.2s;
+}
+
+.btn-info:hover {
+  transform: translateY(-2px);
+  background-color: #274757;
+}
+
+/* Data Overview Section */
+.section-title {
+  font-size: 2.2rem;
+  color: #274757;
+  font-weight: 600;
+}
+
+.visualization-row {
+  margin: 0 -15px;
+}
+
+.viz-card1 {
+  background: white;
+  border-radius: 1rem;
+  padding: 1.5rem;
+  height: 400px;
+  box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
+  transition: transform 0.2s;
+  align-items: center;
+}
+
+
+/* Data Visualization Section  */
+.viz-card {
+  background: white;
+  border-radius: 1rem;
+  padding: 1.5rem;
+  height: 400px;
+  box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
+  transition: transform 0.2s;
+  align-items: center;
+  display: flex;
+  flex-direction: column;
+  justify-content: center; 
+}
+
+.viz-card canvas {
+  max-width: 100%; 
+  margin: 0 auto; 
+}
+
+
+#taxonsChart {
+  width: auto;
+  height: auto;
+}
+
+
+.viz-card:hover {
+  transform: translateY(-5px);
+}
+
+.viz-card h3 {
+  color: #274757;
+  font-size: 1.3rem;
+  margin-bottom: 1.5rem;
+  text-align: center;
+}
+
+.table-wrapper {
+  max-height: 300px;
+  overflow-y: auto;
+}
+
+.table {
+  margin-bottom: 0;
+}
+
+.table th {
+  background-color: #274757;
+  color: white;
+  position: sticky;
+  top: 0;
+}
+
+.coming-soon {
+  height: 100%;
+  display: flex;
+  flex-direction: column;
+  align-items: center;
+  justify-content: center;
+  color: #888;
+}
+
+.coming-soon i {
+  font-size: 3rem;
+  margin-bottom: 1rem;
+}
+
+@media (max-width: 768px) {
   .visualization-row {
-    margin: 0 -15px;
-  }
-  
-  .viz-card {
-    background: white;
-    border-radius: 1rem;
-    padding: 1.5rem;
-    height: 400px;
-    box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
-    transition: transform 0.2s;
-  }
-  
-  .viz-card:hover {
-    transform: translateY(-5px);
-  }
-  
-  .viz-card h3 {
-    color: #274757;
-    font-size: 1.3rem;
-    margin-bottom: 1.5rem;
-    text-align: center;
-  }
-  
-  .table-wrapper {
-    max-height: 300px;
-    overflow-y: auto;
-  }
-  
-  .table {
-    margin-bottom: 0;
-  }
-  
-  .table th {
-    background-color: #274757;
-    color: white;
-    position: sticky;
-    top: 0;
-  }
-  
-  .coming-soon {
-    height: 100%;
-    display: flex;
     flex-direction: column;
-    align-items: center;
-    justify-content: center;
-    color: #888;
   }
   
-  .coming-soon i {
-    font-size: 3rem;
-    margin-bottom: 1rem;
+  .viz-card {
+    margin-bottom: 2rem;
   }
-  
-  @media (max-width: 768px) {
-    .visualization-row {
-      flex-direction: column;
-    }
-    
-    .viz-card {
-      margin-bottom: 2rem;
-    }
-  }
\ No newline at end of file
+} 
+
diff --git a/templates/home.html b/templates/home.html
index 1ac5e9e..ea9fa5a 100644
--- a/templates/home.html
+++ b/templates/home.html
@@ -1,4 +1,4 @@
-{% extends 'main3' %} {% block content %}
+{% extends 'main2' %} {% block content %}
 <script type="text/javascript">
   $SCRIPT_ROOT = {{ request.script_root|tojson|safe }};
 </script>
@@ -35,7 +35,7 @@
     <h2 class="text-center section-title mb-5">HoloOligo Data Overview</h2>
     <div class="row visualization-row">
       <div class="col-md-4">
-        <div class="viz-card">
+        <div class="viz-card1">
           <h3>Entities Overview</h3>
           <div class="table-wrapper">
             <table id="entitiesTable" class="table table-striped">
-- 
GitLab


From cbe22dad9bcfeccf1ea6003dd1a97e4830d1fe5f Mon Sep 17 00:00:00 2001
From: "hajar.bouamout" <hajar.bouamout@inrae.fr>
Date: Tue, 14 Jan 2025 16:43:46 +0100
Subject: [PATCH 23/51] modif du style de la nav bar

---
 templates/nav | 182 ++++++++++++++++++++++++++++++++++----------------
 1 file changed, 126 insertions(+), 56 deletions(-)

diff --git a/templates/nav b/templates/nav
index 228164b..1e16583 100644
--- a/templates/nav
+++ b/templates/nav
@@ -13,61 +13,131 @@
 #    See the License for the specific language governing permissions and
 #    limitations under the License.
 -->
+           <!--
+            <a class="dropdown-item" href="searchByTaxonForOligosaccharideName" id="searchByTaxonForOligosaccharideName">Taxon : Oligosaccharide Name</a>
+            <a class="dropdown-item" href="searchByOligosaccharideName" id="searchByOligosaccharideName">Oligosaccharide Name:Taxon</a>
+            <div class="dropdown-divider"></div>
+            <a class="dropdown-item" href="searchByTaxonForOligosaccharideType" id="searchByTaxonForOligosaccharideType">Taxon :Oligosaccharide Type</a>
+            <a class="dropdown-item" href="searchByOligosaccharideType" id="searchByOligosaccharideType">Oligosaccharide Type : Taxon</a>
+            <div class="dropdown-divider"></div>
+            <a class="dropdown-item" href="searchByTaxon" id="searchByTaxon">Taxon : Physiological Stage</a>
+            <a class="dropdown-item" href="searchByPhysiologicalStage" id="searchByPhysiologicalStage">Physiological Stage :Taxon</a>
+            <div class="dropdown-divider"></div>
+            <a class="dropdown-item" href="searchByTaxonForPostpartum" id="searchByTaxonForPostpartum">Taxon : Postpartum Age</a>
+            <a class="dropdown-item" href="searchByPostpartum" id="searchByPostpartum">Postpartum Age : Taxon</a>
+            <div class="dropdown-divider"></div>
+            <a class="dropdown-item" href="searchByTaxonForSampleType" id="searchByTaxonForSampleType">Taxon : Sample Type</a>
+            <a class="dropdown-item" href="searchBySampleType" id="searchBySampleType">Sample Type : Taxon</a>
+            <div class="dropdown-divider"></div>
+            <a class="dropdown-item" href="searchByTaxonForLactation" id="searchByTaxonForLactation">Taxon : Lactation stage</a>
+            <a class="dropdown-item" href="searchByLactation" id="searchByLactation">Lactation Stage : Taxon</a>
+          -->
+  
+          <!DOCTYPE html>
+          <html lang="en">
+          <head>
+            <meta charset="UTF-8">
+            <meta name="viewport" content="width=device-width, initial-scale=1.0">
+            <title>HoloOligo</title>
+          
+            <style>
+              /* Style de la Navbar */
+              .navbar {
+                background-color:rgb(25, 70, 101) !important; /* Couleur de fond de la navbar */
+              }
+          
+              .navbar-nav .nav-link {
+                font-size: 1.2rem; /* Taille du texte des liens */
+                color: white !important; /* Couleur des liens */
+              }
+          
+              .navbar-nav .nav-link:hover {
+                color: #ffdd57 !important; /* Couleur au survol des liens */
+              }
+          
+              /* Personnalisation des éléments du dropdown */
+              .dropdown-menu {
+                background-color:rgb(73, 122, 157); /* Fond du menu déroulant */
+              }
+          
+              .dropdown-item {
+                color: white; /* Couleur des éléments du menu déroulant */
+              }
+          
+              .dropdown-item:hover {
+                background-color:rgb(255, 255, 255); /* Couleur de fond au survol */
+              }
+          
+              /* Style du logo de la navbar */
+              .navbar-brand img {
+                height: 40px; /* Ajuster la taille du logo */
+              }
+          
+              /* Modifier la couleur de fond et du texte du bouton burger sur mobile */
+              .navbar-toggler-icon {
+                background-color: white; /* Couleur du menu hamburger */
+              }
+          
+              /* Navbar active */
+              .nav-item.active .nav-link {
+                color: #ffdd57 !important; /* Couleur des liens actifs */
+              }
+            </style>
+          </head>
+          <body>
+            <!-- Navbar Section -->
+            <nav class="navbar navbar-expand-lg navbar-dark bg-info fixed-top">
+              <a class="navbar-brand" href="home_page" id="main">
+                <img src="{{ url_for('static', filename='img/logo_Omnicrobe_blanc_small.png') }}" />&nbsp;&nbsp;HoloOligo
+              </a>
+              <button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarSupportedContent" aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation">
+                <span class="navbar-toggler-icon"></span>
+              </button>
+          
+              <div class="collapse navbar-collapse" id="navbarSupportedContent">
+                <ul class="navbar-nav mr-auto">
+                  <li class="nav-item dropdown">
+                    <a class="nav-link dropdown-toggle" href="#" id="navbarDropdown" role="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
+                      Search
+                    </a>
+                    <div class="dropdown-menu" aria-labelledby="navbarDropdown">
+                      <div class="dropdown-divider"></div>
+                      <a class="dropdown-item" href="research" id="research">Simple search</a>
+                      <div class="dropdown-divider"></div>
+                      <a class="dropdown-item" href="advancedSearch" id="advancedSearch">Advanced search</a>
+                    </div>
+                  </li>
+                  <li class="nav-item dropdown">
+                    <a class="nav-link dropdown-toggle" href="#" id="navbarDropdown" role="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
+                      About
+                    </a>
+                    <div class="dropdown-menu" aria-labelledby="navbarDropdown">
+                      <a class="dropdown-item" href="about">About</a>
+                      <a class="dropdown-item" href="release">Release Notes</a>
+                      <div class="dropdown-divider"></div>
+                      <a class="dropdown-item" href="help">Help</a>
+                      <div class="dropdown-divider"></div>
+                      <a class="dropdown-item" href="contact" id="contact">Contact</a>
+                    </div>
+                  </li>
+                </ul>
+              </div>
+            </nav>
+          
+            <!-- Your page content goes here -->
+          
+            <!-- Scripts for Bootstrap -->
+            <!-- Utilisez jQuery complet pour activer les fonctionnalités Bootstrap -->
+            <script src="https://code.jquery.com/jquery-3.5.1.min.js"></script>
+            <script src="https://cdn.jsdelivr.net/npm/bootstrap@4.5.2/dist/js/bootstrap.bundle.min.js"></script>
+          </body>
+          </html>
 
-<nav class="navbar navbar-expand-lg navbar-dark bg-info fixed-top">
+          
+  <!-- Your page content goes here -->
 
-  <a class="navbar-brand" href="index" id="main"><img src="{{ url_for('static', filename='img/logo_Omnicrobe_blanc_small.png') }}" />&nbsp;&nbsp;HoloOligo</a>
-  <button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarSupportedContent" aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation">
-    <span class="navbar-toggler-icon"></span>
-  </button>
-
-  <div class="collapse navbar-collapse" id="navbarSupportedContent">
-    <ul class="navbar-nav mr-auto">
-      <li class="nav-item dropdown">
-        <a class="nav-link dropdown-toggle" href="#" id="navbarDropdown" role="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
-          Search
-        </a>
-        <div class="dropdown-menu" aria-labelledby="navbarDropdown">
-          <a class="dropdown-item" href="searchByTaxonForOligosaccharideName" id="searchByTaxonForOligosaccharideName">Taxon --> Oligosaccharide Name</a>
-          <a class="dropdown-item" href="searchByOligosaccharideName" id="searchByOligosaccharideName">Oligosaccharide Name --> Taxon</a>
-          <div class="dropdown-divider"></div>
-          <a class="dropdown-item" href="searchByTaxonForOligosaccharideType" id="searchByTaxonForOligosaccharideType">Taxon --> Oligosaccharide Type</a>
-          <a class="dropdown-item" href="searchByOligosaccharideType" id="searchByOligosaccharideType">Oligosaccharide Type --> Taxon</a>
-          <div class="dropdown-divider"></div>
-          <a class="dropdown-item" href="searchByTaxon" id="searchByTaxon">Taxon --> Physiological Stage</a>
-          <a class="dropdown-item" href="searchByPhysiologicalStage" id="searchByPhysiologicalStage">Physiological Stage --> Taxon</a>
-          <div class="dropdown-divider"></div>
-          <a class="dropdown-item" href="searchByTaxonForPostpartum" id="searchByTaxonForPostpartum">Taxon --> Postpartum Age</a>
-          <a class="dropdown-item" href="searchByPostpartum" id="searchByPostpartum">Postpartum Age --> Taxon</a>
-          <div class="dropdown-divider"></div>
-          <a class="dropdown-item" href="searchByTaxonForSampleType" id="searchByTaxonForSampleType">Taxon --> Sample Type</a>
-          <a class="dropdown-item" href="searchBySampleType" id="searchBySampleType">Sample Type --> Taxon</a>
-          <div class="dropdown-divider"></div>
-          <a class="dropdown-item" href="searchByTaxonForLactation" id="searchByTaxonForLactation">Taxon --> Lactation stage</a>
-          <a class="dropdown-item" href="searchByLactation" id="searchByLactation">Lactation Stage --> Taxon</a>
-          <!--div class="dropdown-divider"></div>
-          <a class="dropdown-item" href="advancedSearch" id="advancedSearch">Advanced search</a-->
-        </div>
-      </li>
-      <!--li class="nav-item dropdown">
-        <a class="nav-link" href="api" id="navbarDropdown" role="button" aria-haspopup="true">
-          Web services
-        </a>
-      </li-->
-      <li class="nav-item dropdown">
-        <a class="nav-link dropdown-toggle" href="#" id="navbarDropdown" role="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
-          About
-        </a>
-        <div class="dropdown-menu" aria-labelledby="navbarDropdown">
-          <a class="dropdown-item" href="about">About</a>
-          <a class="dropdown-item" href="release">Release Notes</a>
-          <div class="dropdown-divider"></div>
-          <a class="dropdown-item" href="help">Help</a>
-          <!--a class="dropdown-item" href="demo">Website usage documentation</a-->
-          <div class="dropdown-divider"></div>
-          <a class="dropdown-item" href="contact" id="contact">Contact</a>
-        </div>
-      </li>
-    </ul>
-  </div>
-</nav>
+  <!-- Scripts for Bootstrap -->
+  <script src="https://code.jquery.com/jquery-3.5.1.slim.min.js"></script>
+  <script src="https://cdn.jsdelivr.net/npm/bootstrap@4.5.2/dist/js/bootstrap.bundle.min.js"></script>
+</body>
+</html>
-- 
GitLab


From 1853196e95c2df11390531a394e064be00a717a7 Mon Sep 17 00:00:00 2001
From: "hajar.bouamout" <hajar.bouamout@inrae.fr>
Date: Tue, 14 Jan 2025 16:47:04 +0100
Subject: [PATCH 24/51] ajout d'une info section

---
 templates/advancedSearch.html | 15 +++++++++++++++
 1 file changed, 15 insertions(+)

diff --git a/templates/advancedSearch.html b/templates/advancedSearch.html
index 1c5ba1b..378091e 100644
--- a/templates/advancedSearch.html
+++ b/templates/advancedSearch.html
@@ -30,6 +30,7 @@
   <link rel="stylesheet" href="{{ url_for('static', filename='css/selectize.css') }}" />
   <link rel="stylesheet" href="{{ url_for('static', filename='css/selectize.boostrap3.css') }}" />
   <link rel="stylesheet" href="{{ url_for('static', filename='css/additional.css') }}" />"
+  <link rel="stylesheet" href="{{ url_for('static', filename='css/research.css') }}" />"
   <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/font-awesome@4.7.0/css/font-awesome.css" />
   <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/jQuery-QueryBuilder@2.5.2/dist/css/query-builder.default.css" />
 
@@ -47,6 +48,20 @@
   .rule-value-container{ display: inline }
 </style>
 
+<body>
+
+  <div class="main-content2">
+    <section class="info-section">
+      <div class="info-box">
+        <div class="search-icon">
+          <i class="fas fa-search"></i>
+        </div>
+        <h2>Advanced Search</h2>
+        <p> Build complex queries with multiple criteria and filters. Ideal for research and detailed analysis of oligosaccharide data.</p>
+      </div>
+    </section>
+
+
   <div style="margin:80px 0;"></div>
 
   <div style="margin-left: 5%;margin-right: 5%;">
-- 
GitLab


From 8f9f19a3068a2d6cd5fd364f3a1882f66392a7c5 Mon Sep 17 00:00:00 2001
From: "hajar.bouamout" <hajar.bouamout@inrae.fr>
Date: Wed, 15 Jan 2025 10:38:26 +0100
Subject: [PATCH 25/51] suppression redondance des titres

---
 templates/advancedSearch.html | 2 +-
 templates/research.html       | 1 -
 2 files changed, 1 insertion(+), 2 deletions(-)

diff --git a/templates/advancedSearch.html b/templates/advancedSearch.html
index 378091e..f694f97 100644
--- a/templates/advancedSearch.html
+++ b/templates/advancedSearch.html
@@ -65,7 +65,7 @@
   <div style="margin:80px 0;"></div>
 
   <div style="margin-left: 5%;margin-right: 5%;">
-    <h3><span style="color: #21517A;">Advanced search</span></h3>
+   <!-- <h3><span style="color: #21517A;">Advanced search</span></h3>  -->
 
     <div style="margin-left: 2%;margin-right: 2%;">
       <div class="d-flex justify-content-center text-info">
diff --git a/templates/research.html b/templates/research.html
index 61fd4ed..42badcf 100644
--- a/templates/research.html
+++ b/templates/research.html
@@ -54,7 +54,6 @@
 
     <!-- Simple Search Form -->
     <section id="simple-search-section" class="search-section">
-      <h2>Simple Search</h2>
       <div class="search-bar2">
         <span>Search By:</span>
         <select id="simple-search-type">
-- 
GitLab


From ae6f4af5ef15f46ad3a9c73809f3130be8fc0964 Mon Sep 17 00:00:00 2001
From: "hajar.bouamout" <hajar.bouamout@inrae.fr>
Date: Mon, 20 Jan 2025 14:43:00 +0100
Subject: [PATCH 26/51] =?UTF-8?q?Ajout=20des=20op=C3=A9rateurs=20NOT=20et?=
 =?UTF-8?q?=20NOT=20EQUAL=20+=20mise=20=C3=A0=20jour=20des=20d=C3=A9pendan?=
 =?UTF-8?q?ces?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 static/js/advancedSearch.js   | 1051 +++++++++++++++++++++------------
 templates/advancedSearch.html |   23 +-
 2 files changed, 674 insertions(+), 400 deletions(-)

diff --git a/static/js/advancedSearch.js b/static/js/advancedSearch.js
index a158cc1..5af855f 100644
--- a/static/js/advancedSearch.js
+++ b/static/js/advancedSearch.js
@@ -14,216 +14,226 @@
 #    limitations under the License.
 **/
 
-import { format_docs } from './utils.js';
+import { format_docs } from "./utils.js";
 
 // Spinner
-$('#spinner_advanced').show();
-$('#spinner_advanced2').show();
+$("#spinner_advanced").show();
+$("#spinner_advanced2").show();
 
 // Fix size input for Selectize
-$('#builder').on('afterCreateRuleInput.queryBuilder', function(e, rule) {
-  if (rule.filter.plugin == 'selectize') {
-    rule.$el.find('.rule-value-container').css('min-width', '200px')
-      .find('.selectize-control').removeClass('form-control');
+$("#builder").on("afterCreateRuleInput.queryBuilder", function (e, rule) {
+  if (rule.filter.plugin == "selectize") {
+    rule.$el
+      .find(".rule-value-container")
+      .css("min-width", "200px")
+      .find(".selectize-control")
+      .removeClass("form-control");
   }
 });
 
 // Default display
 var rules_basic = {
-  condition: 'AND',
-  rules: [{
-    id: 'taxon'
-  }
-]
+  condition: "AND",
+  rules: [
+    {
+      id: "taxon",
+    },
+  ],
 };
 
 // Options for Selectize
 var options = {
   allow_empty: false,
   // plugins: ['bt-tooltip-errors'],
+  conditions: ["AND", "OR", "NOT"], // Added NOT operator
   filters: [
-  {
-    id: 'taxon',
-    label: 'Taxon',
-    type: 'string',
-    placeholder: 'Bacillus subtilis',
-    plugin: 'selectize',
-    operators: ['equal'],
-    plugin_config: {
-      valueField: 'path',
-      labelField: 'name',
-      searchField: 'name',
-      sortField: 'name',
-      create: false,
-      maxItems: 1,
-      onInitialize: function() {
-        var that = this;
-
-        $.getJSON($SCRIPT_ROOT + '/_get_list_taxon_name',
-          function(data) {
-            data.forEach(function(item) {
-              that.addOption(item);
-            });
-            $('#spinner_advanced').hide();
-            $('#spinner_advanced2').hide();
-          });
-      }
+    {
+      id: "taxon",
+      label: "Taxon",
+      type: "string",
+      placeholder: "Bacillus subtilis",
+      plugin: "selectize",
+      operators: ["equal", "not_equal"],
+      plugin_config: {
+        valueField: "path",
+        labelField: "name",
+        searchField: "name",
+        sortField: "name",
+        create: false,
+        maxItems: 1,
+        onInitialize: async function () {
+          try {
+            const response = await fetch(
+              `${$SCRIPT_ROOT}/_get_list_taxon_name`
+            );
+            const data = await response.json();
+            data.forEach((item) => this.addOption(item));
+            $("#spinner_advanced, #spinner_advanced2").hide();
+          } catch (error) {
+            console.error("Error loading taxon data:", error);
+          }
+        },
+      },
     },
-    valueSetter: function(rule, value) {
-      rule.$el.find('.rule-value-container input')[0].selectize.setValue(value);
-    }
-  },
-  {
-    id: 'habitat',
-    label: 'Habitat',
-    type: 'string',
-    placeholder: 'milk product',
-    plugin: 'selectize',
-    operators: ['equal'],
-    plugin_config: {
-      valueField: 'path',
-      labelField: 'name',
-      searchField: 'name',
-      sortField: 'name',
-      create: false,
-      maxItems: 1,
-      onInitialize: function() {
-        var that = this;
-
-        if (localStorage.ontoHabitat === undefined) {
-          $.getJSON($SCRIPT_ROOT + '/_get_list_obt_class',
-            { table: 'list_habitat' },
-            function(data) {
+    {
+      id: "habitat",
+      label: "Habitat",
+      type: "string",
+      placeholder: "milk product",
+      plugin: "selectize",
+      operators: ["equal", "not_equal"],
+      plugin_config: {
+        valueField: "path",
+        labelField: "name",
+        searchField: "name",
+        sortField: "name",
+        create: false,
+        maxItems: 1,
+        onInitialize: async function () {
+          try {
+            if (!localStorage.ontoHabitat) {
+              const response = await fetch(
+                `${$SCRIPT_ROOT}/_get_list_obt_class`,
+                {
+                  method: "POST",
+                  headers: { "Content-Type": "application/json" },
+                  body: JSON.stringify({ table: "list_habitat" }),
+                }
+              );
+              const data = await response.json();
               localStorage.ontoHabitat = JSON.stringify(data);
-              data.forEach(function(item) {
-                that.addOption(item);
-              });
+              data.forEach((item) => this.addOption(item));
+            } else {
+              JSON.parse(localStorage.ontoHabitat).forEach((item) =>
+                this.addOption(item)
+              );
             }
-          );
-        }
-        else {
-          JSON.parse(localStorage.ontoHabitat).forEach(function(item) {
-            that.addOption(item);
-          });
-        }
-      }
+          } catch (error) {
+            console.error("Error loading habitat data:", error);
+          }
+        },
+      },
     },
-    valueSetter: function(rule, value) {
-      rule.$el.find('.rule-value-container input')[0].selectize.setValue(value);
-    }
-  },
-  {
-    id: 'phenotype',
-    label: 'Phenotype',
-    placeholder: 'adherent',
-    type: 'string',
-    plugin: 'selectize',
-    operators: ['equal'],
-    plugin_config: {
-      valueField: 'path',
-      labelField: 'name',
-      searchField: 'name',
-      sortField: 'name',
-      create: false,
-      maxItems: 1,
-      onInitialize: function() {
-        var that = this;
-
-        if (localStorage.ontoPhenotype === undefined) {
-          $.getJSON($SCRIPT_ROOT + '/_get_list_obt_class',
-            { table: 'list_phenotype_taxon' },
-            function(data) {
+    {
+      id: "phenotype",
+      label: "Phenotype",
+      placeholder: "adherent",
+      type: "string",
+      plugin: "selectize",
+      operators: ["equal", "not_equal"],
+      plugin_config: {
+        valueField: "path",
+        labelField: "name",
+        searchField: "name",
+        sortField: "name",
+        create: false,
+        maxItems: 1,
+        onInitialize: async function () {
+          try {
+            if (!localStorage.ontoPhenotype) {
+              const response = await fetch(
+                `${$SCRIPT_ROOT}/_get_list_obt_class`,
+                {
+                  method: "POST",
+                  headers: { "Content-Type": "application/json" },
+                  body: JSON.stringify({ table: "list_phenotype_taxon" }),
+                }
+              );
+              const data = await response.json();
               localStorage.ontoPhenotype = JSON.stringify(data);
-              data.forEach(function(item) {
-                that.addOption(item);
-              });
+              data.forEach((item) => this.addOption(item));
+            } else {
+              JSON.parse(localStorage.ontoPhenotype).forEach((item) =>
+                this.addOption(item)
+              );
             }
-          );
-        }
-        else {
-          JSON.parse(localStorage.ontoPhenotype).forEach(function(item) {
-            that.addOption(item);
-          });
-        }
-      }
+          } catch (error) {
+            console.error("Error loading phenotype data:", error);
+          }
+        },
+      },
     },
-    valueSetter: function(rule, value) {
-      rule.$el.find('.rule-value-container input')[0].selectize.setValue(value);
-    }
-  },
-  {
-    id: 'use',
-    label: 'Use',
-    placeholder: 'acidification activity',
-    type: 'string',
-    plugin: 'selectize',
-    operators: ['equal'],
-    plugin_config: {
-      valueField: 'path',
-      labelField: 'name',
-      searchField: 'name',
-      sortField: 'name',
-      create: false,
-      maxItems: 1,
-      onInitialize: function() {
-        var that = this;
-
-        if (localStorage.ontoUse === undefined) {
-          $.getJSON($SCRIPT_ROOT + '/_get_list_obt_class',
-            { table: 'list_use_taxon' },
-            function(data) {
+    {
+      id: "use",
+      label: "Use",
+      placeholder: "acidification activity",
+      type: "string",
+      plugin: "selectize",
+      operators: ["equal", "not_equal"],
+      plugin_config: {
+        valueField: "path",
+        labelField: "name",
+        searchField: "name",
+        sortField: "name",
+        create: false,
+        maxItems: 1,
+        onInitialize: async function () {
+          try {
+            if (!localStorage.ontoUse) {
+              const response = await fetch(
+                `${$SCRIPT_ROOT}/_get_list_obt_class`,
+                {
+                  method: "POST",
+                  headers: { "Content-Type": "application/json" },
+                  body: JSON.stringify({ table: "list_use_taxon" }),
+                }
+              );
+              const data = await response.json();
               localStorage.ontoUse = JSON.stringify(data);
-              data.forEach(function(item) {
-                that.addOption(item);
-              });
+              data.forEach((item) => this.addOption(item));
+            } else {
+              JSON.parse(localStorage.ontoUse).forEach((item) =>
+                this.addOption(item)
+              );
             }
-          );
-        }
-        else {
-          JSON.parse(localStorage.ontoUse).forEach(function(item) {
-            that.addOption(item);
-          });
-        }
-      }
+          } catch (error) {
+            console.error("Error loading use data:", error);
+          }
+        },
+      },
     },
-    valueSetter: function(rule, value) {
-      rule.$el.find('.rule-value-container input')[0].selectize.setValue(value);
-    }
-  },
-  {
-    id: 'source',
-    label: 'Source',
-    type: 'string',
-    input: 'checkbox',
-    values: {
-      'PubMed': 'PubMed',
-      'GenBank': 'GenBank',
-      'DSMZ': 'DSMZ',
-      'CIRM-BIA': 'CIRM-BIA',
-      'CIRM-CFBP': 'CIRM-CFBP',
-      'CIRM-Levures': 'CIRM-Levures'
+    {
+      id: "source",
+      label: "Source",
+      type: "string",
+      input: "checkbox",
+      operators: ["in", "not_in"],
+      values: {
+        PubMed: "PubMed",
+        GenBank: "GenBank",
+        DSMZ: "DSMZ",
+        "CIRM-BIA": "CIRM-BIA",
+        "CIRM-CFBP": "CIRM-CFBP",
+        "CIRM-Levures": "CIRM-Levures",
+      },
+      default_value: [
+        "PubMed",
+        "GenBank",
+        "DSMZ",
+        "CIRM-BIA",
+        "CIRM-CFBP",
+        "CIRM-Levures",
+      ],
+      operators: ["in"],
     },
-    default_value: ['PubMed', 'GenBank', 'DSMZ', 'CIRM-BIA', 'CIRM-CFBP', 'CIRM-Levures'],
-    operators: ['in'],
-  },
-  {
-    id: 'qps',
-    label: 'QPS',
-    type: 'string',
-    input: 'radio',
-    vertical: true,
-    values: {
-      'yes': 'only QPS (<i>Qualified presumption of safety</i>)',
-      'no': 'all'
+    {
+      id: "qps",
+      label: "QPS",
+      type: "string",
+      input: "radio",
+      vertical: true,
+      values: {
+        yes: "only QPS (<i>Qualified presumption of safety</i>)",
+        no: "all",
+      },
+      operators: ["equal", "not_equal"],
     },
-    operators: ['equal']
-  }
   ],
-  rules: rules_basic
+  rules: rules_basic,
 };
 
 // Query Builder
-var $qb = $("#builder").queryBuilder(options);
+// var $qb = $("#builder").queryBuilder(options);
 
 // function format(d, alvisir) {
 //
@@ -249,153 +259,315 @@ var $qb = $("#builder").queryBuilder(options);
 //     '</table>';
 // }
 
-var thtable = $('#results_advanced').DataTable();
+// var thtable = $('#results_advanced').DataTable();
+
+// Initialize QueryBuilder
+const $qb = $("#builder").queryBuilder(options);
+
+// Initialize DataTable with modern configuration
+let thtable = $("#results_advanced").DataTable({
+  dom: "Bfrtip",
+  responsive: true,
+  buttons: [
+    {
+      extend: "collection",
+      text: "Export",
+      buttons: ["copy", "csv", "excel", "pdf"],
+    },
+    "colvis",
+  ],
+  language: {
+    searchBuilder: {
+      button: "Advanced Search",
+      title: "Advanced Search",
+      data: "Column",
+      condition: "Condition",
+      value: "Value",
+    },
+  },
+});
+
+// Parse query and execute search
+$(".parse-json").on("click", async function () {
+  $("#spinner_advanced, #spinner_advanced2").show();
+
+  try {
+    const queryData = $("#builder").queryBuilder("getSQL");
+    const sql = JSON.parse(JSON.stringify(queryData)).sql;
+
+    // Process NOT conditions
+    const processedSql = processNotConditions(sql);
+
+    const response = await fetch(
+      `${$SCRIPT_ROOT}/_get_list_advanced_relations`,
+      {
+        method: "POST",
+        headers: { "Content-Type": "application/json" },
+        body: JSON.stringify({ query: processedSql }),
+      }
+    );
+
+    const data = await response.json();
+    updateResultsTable(data);
+  } catch (error) {
+    console.error("Error executing search:", error);
+    alert("An error occurred while searching. Please try again.");
+  } finally {
+    $("#spinner_advanced, #spinner_advanced2").hide();
+  }
+});
+
+// Helper function to process NOT conditions
+function processNotConditions(sql) {
+  // Handle NOT operator in SQL query
+  return sql.replace(/NOT\s+([^=]+=[^AND|OR]+)/g, (match, p1) => {
+    return `NOT EXISTS (SELECT 1 WHERE ${p1})`;
+  });
+}
+
+// Update results table with new data
+function updateResultsTable(data) {
+  thtable.clear();
+  thtable.rows.add(data);
+  thtable.draw();
+}
 
 // Create results table
 function createTableTest(relations) {
-
-  $('#hide').css( 'display', 'block' );
-  $('#results_advanced').DataTable().destroy();
-  thtable = $('#results_advanced').DataTable(
+  $("#hide").css("display", "block");
+  $("#results_advanced").DataTable().destroy();
+  thtable = $("#results_advanced").DataTable({
+    dom: "lifrtBp",
+    data: relations,
+    buttons: [
+      {
+        extend: "copyHtml5",
+        exportOptions: {
+          columns: function (idx, data, node) {
+            var table_id = node.getAttribute("aria-controls");
+            if (idx == 0) {
+              return false;
+            } // Never Source Text
+            else if (idx == 6) {
+              return true;
+            } // Always Full Source Text
+            return $("#" + table_id)
+              .DataTable()
+              .column(idx)
+              .visible();
+          },
+        },
+        title: "Omnicrobe_V_" + version,
+      },
+      {
+        extend: "csvHtml5",
+        exportOptions: {
+          columns: function (idx, data, node) {
+            var table_id = node.getAttribute("aria-controls");
+            if (idx == 0) {
+              return false;
+            } // Never Source Text
+            else if (idx == 6) {
+              return true;
+            } // Always Full Source Text
+            return $("#" + table_id)
+              .DataTable()
+              .column(idx)
+              .visible();
+          },
+        },
+        title: "Omnicrobe_V_" + version,
+      },
       {
-        dom: 'lifrtBp',
-        data: relations,
-        buttons: [
-                   {
-                       extend: 'copyHtml5',
-                       exportOptions: { columns: function ( idx, data, node ) {
-                                         var table_id = node.getAttribute('aria-controls');
-                                         if ( idx == 0 ) { return false; } // Never Source Text
-                                         else if ( idx == 6 ) { return true; } // Always Full Source Text
-                                         return $('#' + table_id).DataTable().column( idx ).visible(); }
-                                      },
-                       title: 'Omnicrobe_V_'+version
-                   },
-                   {
-                       extend: 'csvHtml5',
-                       exportOptions: { columns: function ( idx, data, node ) {
-                                         var table_id = node.getAttribute('aria-controls');
-                                         if ( idx == 0 ) { return false; } // Never Source Text
-                                         else if ( idx == 6 ) { return true; } // Always Full Source Text
-                                         return $('#' + table_id).DataTable().column( idx ).visible(); }
-                                      },
-                       title: 'Omnicrobe_V_'+version
-                   },
-                   {
-                       extend: 'excelHtml5',
-                       exportOptions: { columns: function ( idx, data, node ) {
-                                          var table_id = node.getAttribute('aria-controls');
-                                          if ( idx == 0 ) { return false; } // Never Source Text
-                                          else if ( idx == 6 ) { return true; } // Always Full Source Text
-                                          else { return $('#' + table_id).DataTable().column( idx ).visible(); } }
-                                      },
-                       title: 'Omnicrobe_V_'+version
-                   },
-                   {
-                       extend: 'pdfHtml5',
-                       exportOptions: { columns: function ( idx, data, node ) {
-                                          var table_id = node.getAttribute('aria-controls');
-                                          if ( idx == 0 ) { return false; } // Never Source Text
-                                          else if ( idx == 6 ) { return true; } // Always Full Source Text
-                                          return $('#' + table_id).DataTable().column( idx ).visible(); }
-                                      },
-                       title: 'Omnicrobe_V_'+version
-                   },
-                   'colvis'
-               ],
-        columns: [
-          {"render": function(data, type, row, meta) {
-             let rtype = '';
-             if ( row[2] == 'Lives in' || row[2] == 'Contains' ) { rtype = 'habitat'; }
-             else if ( row[2] == 'Studied for' || row[2] == 'Involves' ) { rtype = 'use'; }
-             else if ( row[2] == 'Exhibits' || row[2] == 'Is exhibited by' ) { rtype = 'phenotype'; }
-             var docids = format_docs(row, alvisir, rtype);
-             let docs = "";
-             if ( data.includes(', ') ) { docs = data.split(', '); }
-             else                       { docs = data.split(','); }
-             let docs_f = "";
-             if ( docs.length > 2 ) { // 3
-               docs_f = docids.split(", ").slice(0,2).join(', ') + ", ..."; // 0,3
-             }
-             else {
-               docs_f = docids;
-             }
-             return docs_f;
-           }},
-          {"render": function ( data, type, row, meta ) {
-            let taxa = row[1].split(', ');
-            let taxon = taxa[0];
-            if ( row[9].includes("ncbi") ) {
-              taxon = "<a target='_blank' class='doc' href='https://www.ncbi.nlm.nih.gov/Taxonomy/Browser/wwwtax.cgi?id="+row[9].replace(/.+:/ig, '')+"'>"+taxa[0]+"</a>";
+        extend: "excelHtml5",
+        exportOptions: {
+          columns: function (idx, data, node) {
+            var table_id = node.getAttribute("aria-controls");
+            if (idx == 0) {
+              return false;
+            } // Never Source Text
+            else if (idx == 6) {
+              return true;
+            } // Always Full Source Text
+            else {
+              return $("#" + table_id)
+                .DataTable()
+                .column(idx)
+                .visible();
             }
-            else if ( row[9].includes("bd") ) {
-              taxon = "<a target='_blank' class='doc' href='https://bacdive.dsmz.de/strain/"+row[9].replace(/.+:/ig, '')+"'>"+taxa[0]+"</a>";
+          },
+        },
+        title: "Omnicrobe_V_" + version,
+      },
+      {
+        extend: "pdfHtml5",
+        exportOptions: {
+          columns: function (idx, data, node) {
+            var table_id = node.getAttribute("aria-controls");
+            if (idx == 0) {
+              return false;
+            } // Never Source Text
+            else if (idx == 6) {
+              return true;
+            } // Always Full Source Text
+            return $("#" + table_id)
+              .DataTable()
+              .column(idx)
+              .visible();
+          },
+        },
+        title: "Omnicrobe_V_" + version,
+      },
+      "colvis",
+    ],
+    columns: [
+      {
+        render: function (data, type, row, meta) {
+          let rtype = "";
+          if (row[2] == "Lives in" || row[2] == "Contains") {
+            rtype = "habitat";
+          } else if (row[2] == "Studied for" || row[2] == "Involves") {
+            rtype = "use";
+          } else if (row[2] == "Exhibits" || row[2] == "Is exhibited by") {
+            rtype = "phenotype";
+          }
+          var docids = format_docs(row, alvisir, rtype);
+          let docs = "";
+          if (data.includes(", ")) {
+            docs = data.split(", ");
+          } else {
+            docs = data.split(",");
+          }
+          let docs_f = "";
+          if (docs.length > 2) {
+            // 3
+            docs_f = docids.split(", ").slice(0, 2).join(", ") + ", ..."; // 0,3
+          } else {
+            docs_f = docids;
+          }
+          return docs_f;
+        },
+      },
+      {
+        render: function (data, type, row, meta) {
+          let taxa = row[1].split(", ");
+          let taxon = taxa[0];
+          if (row[9].includes("ncbi")) {
+            taxon =
+              "<a target='_blank' class='doc' href='https://www.ncbi.nlm.nih.gov/Taxonomy/Browser/wwwtax.cgi?id=" +
+              row[9].replace(/.+:/gi, "") +
+              "'>" +
+              taxa[0] +
+              "</a>";
+          } else if (row[9].includes("bd")) {
+            taxon =
+              "<a target='_blank' class='doc' href='https://bacdive.dsmz.de/strain/" +
+              row[9].replace(/.+:/gi, "") +
+              "'>" +
+              taxa[0] +
+              "</a>";
+          }
+          return taxon;
+        },
+      },
+      {
+        render: function (data, type, row, meta) {
+          return row[2];
+        },
+      },
+      {
+        render: function (data, type, row, meta) {
+          return row[3].split(",")[0];
+        },
+      },
+      {
+        orderable: false,
+        render: function (data, type, row, meta) {
+          return row[4];
+        },
+      },
+      {
+        render: function (data, type, row, meta) {
+          return row[5];
+        },
+      },
+      {
+        render: function (data, type, row, meta) {
+          let taxs = row[1].split(", ");
+          let forms = "";
+          for (let i = 1; i < taxs.length; i++) {
+            forms += taxs[i];
+            if (i != taxs.length - 1) {
+              forms += ", ";
             }
-            return taxon;
-          }},
-          {"render": function (data, type, row, meta) {
-              return row[2];
-          }},
-          {"render": function (data, type, row, meta) {
-              return row[3].split(',')[0];
-          }},
-          {"orderable": false, "render": function (data, type, row, meta) {
-              return row[4];
-          }},
-          {"render": function (data, type, row, meta) {
-              return row[5];
-          }},
-          {"render": function (data, type, row, meta) {
-             let taxs = row[1].split(', ');
-             let forms = "";
-             for ( let i = 1; i < taxs.length ; i++ ) {
-               forms += taxs[i]
-               if ( i != taxs.length - 1 ) { forms += ", " }
-             }
-             return forms;
-          }},
-          {"render": function (data, type, row, meta) {
-              let elts = row[3].split(', ');
-              let forms = "";
-              for ( let i = 1; i < elts.length ; i++ ) {
-                forms += elts[i]
-                if ( i != elts.length - 1 ) { forms += ", " }
-              }
-              return forms;
-          }},
-          {"render": function (data, type, row, meta) {
-             let rtype = '';
-             if ( row[2] == 'Lives in' || row[2] == 'Contains' ) { rtype = 'habitat'; }
-             else if ( row[2] == 'Studied for' || row[2] == 'Involves' ) { rtype = 'use'; }
-             else if ( row[2] == 'Exhibits' || row[2] == 'Is exhibited by' ) { rtype = 'phenotype'; }
-             var docids = format_docs(row, alvisir, rtype);
-             return docids;
-          }},
-          {"visible": false, "render": function (data, type, row, meta) {
-              return row[9];
-          }},
-          {"visible": false, "render": function (data, type, row, meta) {
-             return row[7];
-          }},
-          {"visible": false, "render": function (data, type, row, meta) {
-              return row[8];
-          }},
-          {"visible": false, "render": function (data, type, row, meta) {
-              return row[6];
-          }}
-       ]
-      });
+          }
+          return forms;
+        },
+      },
+      {
+        render: function (data, type, row, meta) {
+          let elts = row[3].split(", ");
+          let forms = "";
+          for (let i = 1; i < elts.length; i++) {
+            forms += elts[i];
+            if (i != elts.length - 1) {
+              forms += ", ";
+            }
+          }
+          return forms;
+        },
+      },
+      {
+        render: function (data, type, row, meta) {
+          let rtype = "";
+          if (row[2] == "Lives in" || row[2] == "Contains") {
+            rtype = "habitat";
+          } else if (row[2] == "Studied for" || row[2] == "Involves") {
+            rtype = "use";
+          } else if (row[2] == "Exhibits" || row[2] == "Is exhibited by") {
+            rtype = "phenotype";
+          }
+          var docids = format_docs(row, alvisir, rtype);
+          return docids;
+        },
+      },
+      {
+        visible: false,
+        render: function (data, type, row, meta) {
+          return row[9];
+        },
+      },
+      {
+        visible: false,
+        render: function (data, type, row, meta) {
+          return row[7];
+        },
+      },
+      {
+        visible: false,
+        render: function (data, type, row, meta) {
+          return row[8];
+        },
+      },
+      {
+        visible: false,
+        render: function (data, type, row, meta) {
+          return row[6];
+        },
+      },
+    ],
+  });
 
-  $('#spinner_advanced').hide();
-  $('#spinner_advanced2').hide();
+  $("#spinner_advanced").hide();
+  $("#spinner_advanced2").hide();
 }
 
-$('.parse-json').on('click', function() {
+$(".parse-json").on("click", function () {
   // console.log(JSON.stringify($('#builder').queryBuilder('getSQL'), undefined, 2));
-  $('#spinner_advanced').show();
-  $('#spinner_advanced2').show();
+  $("#spinner_advanced").show();
+  $("#spinner_advanced2").show();
 
-  var sql = JSON.stringify($('#builder').queryBuilder('getSQL'), undefined, 2);
+  var sql = JSON.stringify($("#builder").queryBuilder("getSQL"), undefined, 2);
   sql = JSON.parse(sql).sql;
   var sql_f = sql;
 
@@ -403,22 +575,24 @@ $('.parse-json').on('click', function() {
   var regex_s = /source\s(IN\(.+\))/g;
   var found_s = sql.match(regex_s);
   var list_sources = [];
-  if ( found_s != null ) {
+  if (found_s != null) {
     var l_source = "";
-    for ( let i = 0 ; i < found_s.length ; i++ ) {
-      var sources = found_s[i].replace(regex_s, '$1');
-      sources = sources.replace('IN(', '');
-      sources = sources.replace(')', '');
+    for (let i = 0; i < found_s.length; i++) {
+      var sources = found_s[i].replace(regex_s, "$1");
+      sources = sources.replace("IN(", "");
+      sources = sources.replace(")", "");
       l_source = sources.replaceAll("'", "");
     }
-    if ( l_source != "" ) { list_sources = l_source.split(', '); }
+    if (l_source != "") {
+      list_sources = l_source.split(", ");
+    }
   }
 
   // qps
   var regex_q = /qps\s=\s'([a-z]+)'/g;
   var found_q = sql.match(regex_q);
-  if ( found_q != null ) {
-    var qps = found_q[0].replace(regex_q, '$1');
+  if (found_q != null) {
+    var qps = found_q[0].replace(regex_q, "$1");
   }
 
   // taxon
@@ -427,60 +601,102 @@ $('.parse-json').on('click', function() {
   var list_taxid = [];
   var list_op_tax = [];
   var op_tax = "";
-  if ( found_t != null ) {
+  if (found_t != null) {
     var l_taxid = "";
-    for ( let i = 0 ; i < found_t.length ; i++ ) {
-      var op_tax = found_t[i].replace(regex_t, '$1');
-      var par_tax_s = found_t[i].replace(regex_t, '$2');
-      var path_t = found_t[i].replace(regex_t, '$3'); // $2
-      var par_tax_e = found_t[i].replace(regex_t, '$4');
-      var id_t = path_t.split('/'); id_t = id_t[id_t.length - 1];
-      if ( l_taxid == "" ) { l_taxid = id_t; }
-      else                 { l_taxid += ", " + id_t; }
+    for (let i = 0; i < found_t.length; i++) {
+      var op_tax = found_t[i].replace(regex_t, "$1");
+      var par_tax_s = found_t[i].replace(regex_t, "$2");
+      var path_t = found_t[i].replace(regex_t, "$3"); // $2
+      var par_tax_e = found_t[i].replace(regex_t, "$4");
+      var id_t = path_t.split("/");
+      id_t = id_t[id_t.length - 1];
+      if (l_taxid == "") {
+        l_taxid = id_t;
+      } else {
+        l_taxid += ", " + id_t;
+      }
       list_taxid.push(id_t);
-      if ( op_tax != "" ) { list_op_tax.push(op_tax); }
-      sql_f = sql_f.replace(found_t[i], "r.id_taxon in (SELECT id FROM taxon t WHERE t.path like '%/"+id_t+"/%' OR t.taxonid = '"+id_t+"')");
+      if (op_tax != "") {
+        list_op_tax.push(op_tax);
+      }
+      sql_f = sql_f.replace(
+        found_t[i],
+        "r.id_taxon in (SELECT id FROM taxon t WHERE t.path like '%/" +
+          id_t +
+          "/%' OR t.taxonid = '" +
+          id_t +
+          "')"
+      );
     }
   }
 
   // habitat | phenotype | use
-  var regex_h = /(AND|OR)?\s?(\(?)\s?\b(habitat|phenotype|use)\b\s=\s'([\/A-Z0-9:,]+)'\s?(\)?)/g;
+  var regex_h =
+    /(AND|OR)?\s?(\(?)\s?\b(habitat|phenotype|use)\b\s=\s'([\/A-Z0-9:,]+)'\s?(\)?)/g;
   var found_h = sql.match(regex_h);
   var list_obtid = [];
   var list_op_obt = [];
   var op_obt = "";
-  if ( found_h != null ) {
+  if (found_h != null) {
     var type_obt = "";
     var l_obtid = "";
     var test = "";
-    for ( let i = 0 ; i < found_h.length ; i++ ) {
-      var op_obt = found_h[i].replace(regex_h, '$1');
-      var par_obt_s = found_h[i].replace(regex_h, '$2');
-      var type_obt = found_h[i].replace(regex_h, '$3'); // $2
-      var path_h = found_h[i].replace(regex_h, '$4'); // $3
-      var par_obt_e = found_h[i].replace(regex_h, '$5');
-      var id_h = path_h.split('/'); id_h = id_h[id_h.length - 1];
-      if ( op_obt == "AND" && i > 0 )      { test += "INTERSECT "; }
-      else if ( op_obt == "OR" && i > 0 )  { test += "UNION "; }
-      if ( par_obt_s == "(" )              { test += "("; }
-      test += "select distinct(t.taxonid) from taxon t, relation r, element e where r.id_taxon = t.id and r.id_element = e.id ";
-      test += "and (e.identifier = '"+id_h+"' or e.path like '%/"+id_h+"/%') ";
-      if ( list_taxid[0] != undefined ) {
-        test += "and (t.taxonid = '"+list_taxid[0]+"' or t.path like '%/"+list_taxid[0]+"/%') "; }
-      if ( qps == "yes" )                  { test += "and t.qps = 'yes' "; }
-      if ( list_sources.length > 0 ) {
+    for (let i = 0; i < found_h.length; i++) {
+      var op_obt = found_h[i].replace(regex_h, "$1");
+      var par_obt_s = found_h[i].replace(regex_h, "$2");
+      var type_obt = found_h[i].replace(regex_h, "$3"); // $2
+      var path_h = found_h[i].replace(regex_h, "$4"); // $3
+      var par_obt_e = found_h[i].replace(regex_h, "$5");
+      var id_h = path_h.split("/");
+      id_h = id_h[id_h.length - 1];
+      if (op_obt == "AND" && i > 0) {
+        test += "INTERSECT ";
+      } else if (op_obt == "OR" && i > 0) {
+        test += "UNION ";
+      }
+      if (par_obt_s == "(") {
+        test += "(";
+      }
+      test +=
+        "select distinct(t.taxonid) from taxon t, relation r, element e where r.id_taxon = t.id and r.id_element = e.id ";
+      test +=
+        "and (e.identifier = '" +
+        id_h +
+        "' or e.path like '%/" +
+        id_h +
+        "/%') ";
+      if (list_taxid[0] != undefined) {
+        test +=
+          "and (t.taxonid = '" +
+          list_taxid[0] +
+          "' or t.path like '%/" +
+          list_taxid[0] +
+          "/%') ";
+      }
+      if (qps == "yes") {
+        test += "and t.qps = 'yes' ";
+      }
+      if (list_sources.length > 0) {
         test += "and r.source in (";
-        for ( var k = 0 ; k < list_sources.length ; k++ ) {
+        for (var k = 0; k < list_sources.length; k++) {
           test += "'" + list_sources[k] + "'";
         }
         test += ") ";
       }
-      if ( par_obt_e == ")" )              { test += ")"; }
-      var id_h = path_h.split('/'); id_h = id_h[id_h.length - 1];
-      if ( l_obtid == "" ) { l_obtid = id_h; }
-      else                 { l_obtid += ", " + id_h; }
+      if (par_obt_e == ")") {
+        test += ")";
+      }
+      var id_h = path_h.split("/");
+      id_h = id_h[id_h.length - 1];
+      if (l_obtid == "") {
+        l_obtid = id_h;
+      } else {
+        l_obtid += ", " + id_h;
+      }
       list_obtid.push(id_h);
-      if ( op_obt != "" ) { list_op_obt.push(op_obt); }
+      if (op_obt != "") {
+        list_op_obt.push(op_obt);
+      }
     }
   }
 
@@ -488,91 +704,142 @@ $('.parse-json').on('click', function() {
   // 1.b. Taxon = subtilis OR taxon = cereus
   // 1.c. Taxon = subtilis AND OBT = abdomen
   if (
-       (list_taxid.length > 1  && list_obtid.length == 0 && op_obt == '' && op_tax == 'OR') ||
-       (list_taxid.length == 0 && list_obtid.length > 1 && op_obt == 'OR' && op_tax == '' && (list_op_obt.includes("OR") || list_op_obt.includes("AND"))) ||
-       (list_taxid.length == 1 && list_obtid.length == 1 && op_obt != 'OR' && op_tax != 'OR') ||
-       (list_taxid.length == 1 && list_obtid.length == 0) ||
-       (list_taxid.length == 0 && list_obtid.length == 1)) {
-
-    $.getJSON($SCRIPT_ROOT + '/_get_list_advanced_relations',
+    (list_taxid.length > 1 &&
+      list_obtid.length == 0 &&
+      op_obt == "" &&
+      op_tax == "OR") ||
+    (list_taxid.length == 0 &&
+      list_obtid.length > 1 &&
+      op_obt == "OR" &&
+      op_tax == "" &&
+      (list_op_obt.includes("OR") || list_op_obt.includes("AND"))) ||
+    (list_taxid.length == 1 &&
+      list_obtid.length == 1 &&
+      op_obt != "OR" &&
+      op_tax != "OR") ||
+    (list_taxid.length == 1 && list_obtid.length == 0) ||
+    (list_taxid.length == 0 && list_obtid.length == 1)
+  ) {
+    $.getJSON(
+      $SCRIPT_ROOT + "/_get_list_advanced_relations",
       {
         source: l_source,
         taxonid: l_taxid,
         qps: qps,
         ontobiotopeid: l_obtid,
-        type: type_obt
+        type: type_obt,
       },
       function success(relations) {
         createTableTest(relations);
-      });
+      }
+    );
   }
 
   // 4. Taxon = subtilis OR taxon = cereus AND OBT = abdomen
   // 4. OBT = abdomen OR OBT = salt AND taxon = Bacillus_subtilis
-  else if ( (list_taxid.length > 1 && list_obtid.length == 1 && ((op_tax == 'OR' && op_obt == 'AND') || (list_op_tax.indexOf('OR') !== -1 && list_op_tax.indexOf('AND') !== -1 && list_op_obt.length == 0))) ) {
-    $.getJSON($SCRIPT_ROOT + '/_get_list_advanced_relations',
+  else if (
+    list_taxid.length > 1 &&
+    list_obtid.length == 1 &&
+    ((op_tax == "OR" && op_obt == "AND") ||
+      (list_op_tax.indexOf("OR") !== -1 &&
+        list_op_tax.indexOf("AND") !== -1 &&
+        list_op_obt.length == 0))
+  ) {
+    $.getJSON(
+      $SCRIPT_ROOT + "/_get_list_advanced_relations",
       {
         source: l_source,
         taxonid: l_taxid,
         qps: qps,
         ontobiotopeid: l_obtid,
-        type: type_obt
+        type: type_obt,
       },
       function success(relations) {
         createTableTest(relations);
-      });
+      }
+    );
   }
 
   // 2.a. Taxon = subtilis OR OBT = abdomen
   // 2.b. Taxon = subtilis OR taxon = cereus OR OBT = abdomen
-  else if ( (list_taxid.length > 1 && list_obtid.length == 1 && op_tax != 'AND' && op_obt != 'AND' && par_tax_e == "") ||
-            (list_taxid.length == 1 && list_obtid.length > 1 && op_tax != 'AND' && op_obt != 'AND' && par_obt_e == "") ||
-            (list_taxid.length >= 1 && list_obtid.length >= 1 && (op_tax == 'OR' || op_obt == 'OR') && list_op_obt.indexOf('AND') == -1 && list_op_tax.indexOf('AND') == -1)) {
-    $.getJSON($SCRIPT_ROOT + '/_get_list_advanced_relations_2',
+  else if (
+    (list_taxid.length > 1 &&
+      list_obtid.length == 1 &&
+      op_tax != "AND" &&
+      op_obt != "AND" &&
+      par_tax_e == "") ||
+    (list_taxid.length == 1 &&
+      list_obtid.length > 1 &&
+      op_tax != "AND" &&
+      op_obt != "AND" &&
+      par_obt_e == "") ||
+    (list_taxid.length >= 1 &&
+      list_obtid.length >= 1 &&
+      (op_tax == "OR" || op_obt == "OR") &&
+      list_op_obt.indexOf("AND") == -1 &&
+      list_op_tax.indexOf("AND") == -1)
+  ) {
+    $.getJSON(
+      $SCRIPT_ROOT + "/_get_list_advanced_relations_2",
       {
         source: l_source,
         taxonid: l_taxid,
         qps: qps,
         ontobiotopeid: l_obtid,
-        type: type_obt
+        type: type_obt,
       },
       function success(relations) {
         createTableTest(relations);
-      });
+      }
+    );
   }
 
   // 3.a. Taxon = subtilis AND taxon = cereus / OBT = abdomen AND OBT = salt
   // 3.b. Taxon = subtilis AND taxon = cereus AND OBT = abdomen / OBT = abdomen AND OBT = salt AND taxon = subtilis
-  else if ( (list_taxid.length > 1 && list_obtid.length == 0 && op_tax == 'AND' && op_obt == '') ||
-            (list_taxid.length == 0 && list_obtid.length > 1 && op_tax == '' && op_obt == 'AND') ||
-            (list_taxid.length > 1 && list_obtid.length == 1 && op_tax == 'AND' && op_obt != 'OR') ||
-            (list_taxid.length == 1 && list_obtid.length > 1 && op_tax != 'OR' && ["AND","OR"].includes(op_obt)) ) {
-
-    if ( test != null ) {
-      $.getJSON($SCRIPT_ROOT + '/_get_list_advanced_relations_4',
+  else if (
+    (list_taxid.length > 1 &&
+      list_obtid.length == 0 &&
+      op_tax == "AND" &&
+      op_obt == "") ||
+    (list_taxid.length == 0 &&
+      list_obtid.length > 1 &&
+      op_tax == "" &&
+      op_obt == "AND") ||
+    (list_taxid.length > 1 &&
+      list_obtid.length == 1 &&
+      op_tax == "AND" &&
+      op_obt != "OR") ||
+    (list_taxid.length == 1 &&
+      list_obtid.length > 1 &&
+      op_tax != "OR" &&
+      ["AND", "OR"].includes(op_obt))
+  ) {
+    if (test != null) {
+      $.getJSON(
+        $SCRIPT_ROOT + "/_get_list_advanced_relations_4",
         {
           test: test,
           source: l_source,
           taxonid: l_taxid,
-          ontobiotopeid: l_obtid
+          ontobiotopeid: l_obtid,
         },
         function success(relations) {
           createTableTest(relations);
-        });
-    }
-    else {
+        }
+      );
+    } else {
       alert("Not implemented ! In progress ...");
       createTableTest([]);
     }
-  }
-
-  else {
+  } else {
     alert("Not implemented ! In progress ...");
     createTableTest([]);
   }
 
-  $('#divQuery').show();
-  $('#queryDisabled').val(JSON.stringify($('#builder').queryBuilder('getSQL'), undefined, 2));
+  $("#divQuery").show();
+  $("#queryDisabled").val(
+    JSON.stringify($("#builder").queryBuilder("getSQL"), undefined, 2)
+  );
 });
 
 // $('#results_advanced tbody').on('click', 'td.details-control', function () {
diff --git a/templates/advancedSearch.html b/templates/advancedSearch.html
index f694f97..5a8dd6e 100644
--- a/templates/advancedSearch.html
+++ b/templates/advancedSearch.html
@@ -29,14 +29,21 @@
 
   <link rel="stylesheet" href="{{ url_for('static', filename='css/selectize.css') }}" />
   <link rel="stylesheet" href="{{ url_for('static', filename='css/selectize.boostrap3.css') }}" />
-  <link rel="stylesheet" href="{{ url_for('static', filename='css/additional.css') }}" />"
-  <link rel="stylesheet" href="{{ url_for('static', filename='css/research.css') }}" />"
-  <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/font-awesome@4.7.0/css/font-awesome.css" />
-  <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/jQuery-QueryBuilder@2.5.2/dist/css/query-builder.default.css" />
-
-  <script type="text/javascript" src="https://cdn.jsdelivr.net/npm/sql-parser-mistic@1.2.3/browser/sql-parser.js"></script>
-  <script type="text/javascript" src="https://cdn.jsdelivr.net/npm/interactjs@1.6.2/dist/interact.js"></script>
-  <script src="https://cdn.jsdelivr.net/npm/jQuery-QueryBuilder@2.5.2/dist/js/query-builder.standalone.js"></script>
+  <link rel="stylesheet" href="{{ url_for('static', filename='css/additional.css') }}" />
+  <link rel="stylesheet" href="{{ url_for('static', filename='css/research.css') }}" />
+  <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.1/css/all.min.css" />
+
+<!-- jQuery QueryBuilder -->
+  <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/jQuery-QueryBuilder/2.7.0/css/query-builder.default.min.css" />
+
+<!-- Interact.js -->
+  <script src="https://cdnjs.cloudflare.com/ajax/libs/interact.js/1.10.26/interact.min.js"></script>
+
+<!-- jQuery QueryBuilder -->
+  <script src="https://cdnjs.cloudflare.com/ajax/libs/jQuery-QueryBuilder/2.7.0/js/query-builder.standalone.min.js"></script>
+
+<!-- Selectize.js -->
+  <script src="https://cdnjs.cloudflare.com/ajax/libs/selectize.js/0.15.2/js/selectize.min.js"></script>
   <script src="https://cdnjs.cloudflare.com/ajax/libs/selectize.js/0.12.1/js/standalone/selectize.js"></script>
   <script type="module" src="{{ url_for('static', filename='js/advancedSearch.js') }}"></script>
 
-- 
GitLab


From 437d16189f89cd9777cdc5d0d452021806715c48 Mon Sep 17 00:00:00 2001
From: Sandra Derozier <sandra.derozier@inrae.fr>
Date: Thu, 30 Jan 2025 22:29:59 +0100
Subject: [PATCH 27/51] #10 - Get list entities by concept

---
 __init__.py           |  45 ++++++++++++++-----
 database.py           | 100 ++++++++++++++++++++++++++----------------
 static/js/research.js |  12 +++++
 3 files changed, 109 insertions(+), 48 deletions(-)

diff --git a/__init__.py b/__init__.py
index 0c59476..9a96b72 100644
--- a/__init__.py
+++ b/__init__.py
@@ -427,27 +427,24 @@ def get_stat_entity():
 def get_stat_occurrence():
     return(jsonify(stat_occurrence(app, conn)))
 
-# @app.route('/_get/nb_occ_by_concept')
-# def get_nb_occ_by_concept():
-#     concept = request.args.get('concept', None) # concept = 'Species' or 'Oligosaccharide_type' 
-#     return(jsonify(fetch_nb_occ_by_concept(app, conn, concept)))
 @app.route('/_get/nb_occ_by_concept')
 def get_nb_occ_by_concept():
-    concept = request.args.get('concept', None)  # Exemple : 'Species' ou 'Oligosaccharide_type'
+    concept = request.args.get('concept', None)  # concept = 'Species' or 'Oligosaccharide_type'
     if not concept:
         return jsonify({"error": "Concept parameter is missing"}), 400
-
-    # Appeler la fonction pour récupérer les données
-    results = fetch_nb_occ_by_concept(app, conn, concept)
+    # Get data
+    results = nb_occ_by_concept(app, conn, concept)
     if "error" in results:
         return jsonify({"error": "Failed to fetch data", "details": results}), 500
-
-    # Formatage des données pour Chart.js
+    # Data format for Chart.js
     labels = list(results.keys())
     data = list(results.values())
-
     return jsonify({"labels": labels, "data": data})
 
+@app.route('/_get/entities')
+def get_entities():
+    concept = request.args.get('concept', None)   # type = 'Oligosaccharide_name' or 'Species'
+    return jsonify(entities(app, conn, concept))
 
 # API
 source_choices = ["pubmed", "CIRM-BIA", "CIRM-CFBP", "CIRM-Levures", "dsmz", "genbank"]
@@ -524,6 +521,32 @@ join_relation_model = api.model('JoinRelations', {
     "rightType": fields.String(example="habitat")
 })
 
+# ***** /search ***** #
+# @api.route('/api/search/', doc=False)
+# @api.route('/api/search', doc={"description": "Search based on the name or type of an oligosaccharide, a species, a sample or a stage of lactation"})
+# @api.doc(params={'searchType': 'oligosaccharide_name or oligosaccharide_type or species or samples or lactation_stage (example: oligosaccharide_name)'})
+# @api.doc(params={'query': 'query value (example: Human)'})
+# class ApiSearch(Resource):
+#     # @api.doc(model=taxonid_model)
+#     @api.doc(responses={
+#         200: 'Success',
+#         400: 'Missing mandatory parameter'
+#     })
+#     def get(self):
+#         searchType = request.args.get('searchType', None)
+#         query = request.args.get('query', None)
+#         if searchType == None and query == None:
+#             return {'error': 'At least one parameter required'}, 400
+#         else:
+#             return jsonify(search(app, conn, searchType, query))
+
+# ***** /get/entities ***** #
+@api.route('/api/get/entities', doc={"description": "Returns entities list."})
+class ApiVersion(Resource):
+    # @api.doc(model=version_model)
+    def get(self):
+        return jsonify(get_entities(app, conn))
+
 # ***** /get/version ***** #
 @api.route('/api/get/version', doc={"description": "Returns version information about this instance."})
 class ApiVersion(Resource):
diff --git a/database.py b/database.py
index dceb3a2..dcb04a1 100644
--- a/database.py
+++ b/database.py
@@ -26,40 +26,6 @@ def get_db(app):
         g.db = app.config['postgreSQL_pool'].getconn()
     return g.db
 
-# Check source format
-def check_source(s):
-    sources = ['PubMed', 'GenBank', 'DSMZ', 'CIRM-BIA', 'CIRM-Levures', 'CIRM-CFBP']
-    final = ''
-    for source in sources:
-        pattern = re.compile(source, re.IGNORECASE)
-        final = pattern.sub(source, s)
-        if final != s or final in sources:
-            return final
-
-# Available sources
-sources = {
-            "CIRM-BIA".lower() : "https://collection-cirmbia.fr/page/Display_souches/",
-            "CIRM-Levures".lower() : "",
-            "CIRM-CFBP".lower() : "",
-            "DSMZ".lower() : "https://bacdive.dsmz.de/strain/",
-            "GenBank".lower() : "https://www.ncbi.nlm.nih.gov/nuccore/",
-            "PubMed".lower() : "https://pubmed.ncbi.nlm.nih.gov/"
-          }
-
-# Get version: /get/version
-def get_version(app, conn):
-    conn = get_db(app)
-    if conn != None:
-        cursor = conn.cursor()
-        try:
-            cursor.execute("SELECT omnicrobe, taxonomy, ontobiotope, pubmed, dsmz, genbank, cirmbia, cirmlevures, cirmcfbp \
-                            FROM v_source")
-        except Exception as err:
-            print_psycopg2_exception(err)
-        columns = ('omnicrobe', 'taxonomy', 'ontobiotope', 'pubmed', 'dsmz', 'genbank', 'cirmbia', 'cirmlevures', 'cirmcfbp')
-        return dict(zip(columns, cursor.fetchall()[0]))
-        cursor.close()
-
 # Get statistics: /get/stat*
 def stat_occurrence(app, conn):
     conn = get_db(app)
@@ -100,8 +66,8 @@ def stat_entity(app, conn):
         cursor.close()
         return results
     
-# Get occurrence number by concept: 
-def fetch_nb_occ_by_concept(app, conn, concept):
+# Get occurrence number by concept: /get/nb_occ_by_concept
+def nb_occ_by_concept(app, conn, concept):
     conn = get_db(app)
     if conn != None:
         cursor = conn.cursor()
@@ -119,7 +85,67 @@ def fetch_nb_occ_by_concept(app, conn, concept):
             results[row[0]] = row[1]
         cursor.close()
         return results
-    
+
+# Get entities: /get/entities
+def entities(app, conn, concept):
+    conn = get_db(app)
+    if conn != None:
+        cursor = conn.cursor()
+        try:
+            cursor.execute("SELECT DISTINCT c_identifier, cn_name, c_path \
+                            FROM concept_occurrence, concept, concept_name \
+                            WHERE co_fk_concept_id = c_id \
+                            AND c_id = cn_fk_concept_id \
+                            AND co_type = %s \
+                            ORDER BY c_identifier", (concept,))
+        except Exception as err:
+            print_psycopg2_exception(err)
+        dico = dict()
+        list_results = []
+        for row in cursor.fetchall():
+            dico_tmp = dict()
+            dico_tmp['path'] = row[2]
+            dico_tmp['name'] = row[1]
+            dico_tmp['identifier'] = row[0]
+            list_results.append(dico_tmp)
+        cursor.close()
+        dico['results'] = list_results
+        dico['totalResults'] = len(dico['results'])
+        return dico
+
+# Check source format
+def check_source(s):
+    sources = ['PubMed', 'GenBank', 'DSMZ', 'CIRM-BIA', 'CIRM-Levures', 'CIRM-CFBP']
+    final = ''
+    for source in sources:
+        pattern = re.compile(source, re.IGNORECASE)
+        final = pattern.sub(source, s)
+        if final != s or final in sources:
+            return final
+
+# Available sources
+sources = {
+            "CIRM-BIA".lower() : "https://collection-cirmbia.fr/page/Display_souches/",
+            "CIRM-Levures".lower() : "",
+            "CIRM-CFBP".lower() : "",
+            "DSMZ".lower() : "https://bacdive.dsmz.de/strain/",
+            "GenBank".lower() : "https://www.ncbi.nlm.nih.gov/nuccore/",
+            "PubMed".lower() : "https://pubmed.ncbi.nlm.nih.gov/"
+          }
+
+# Get version: /get/version
+def get_version(app, conn):
+    conn = get_db(app)
+    if conn != None:
+        cursor = conn.cursor()
+        try:
+            cursor.execute("SELECT omnicrobe, taxonomy, ontobiotope, pubmed, dsmz, genbank, cirmbia, cirmlevures, cirmcfbp \
+                            FROM v_source")
+        except Exception as err:
+            print_psycopg2_exception(err)
+        columns = ('omnicrobe', 'taxonomy', 'ontobiotope', 'pubmed', 'dsmz', 'genbank', 'cirmbia', 'cirmlevures', 'cirmcfbp')
+        return dict(zip(columns, cursor.fetchall()[0]))
+        cursor.close()
 
 # Get taxon: /get/taxon
 def get_taxon(app, conn, id):
diff --git a/static/js/research.js b/static/js/research.js
index 2e540c7..1f171fb 100644
--- a/static/js/research.js
+++ b/static/js/research.js
@@ -136,6 +136,18 @@ const dummyData = [
     }
 ];
 
+// Test Sandra //
+document.addEventListener("DOMContentLoaded", function () {
+    const apiUrl = '/_get/entities?concept=Sample_type'; // Species // Oligosaccharide_name // Oligosaccharide_type // Lactation_stage
+    fetch(apiUrl)
+      .then((response) => response.json())
+      .then((data) => {
+          console.log("Data received from the API:", data);
+      })
+      .catch((error) => {
+        console.error("Error fetching the JSON data:", error);
+      });})
+
 // ========================= Global Variables =========================
 // Global variables to store the current dataset and manage pagination
 let currentData = [...dummyData]; 
-- 
GitLab


From 389b7e1e6338427612e68bdb10ab26cab9a5e02d Mon Sep 17 00:00:00 2001
From: Sandra Derozier <sandra.derozier@inrae.fr>
Date: Tue, 4 Feb 2025 14:36:21 +0100
Subject: [PATCH 28/51] #6 - API Get relations

---
 __init__.py           |  7 ++++++-
 database.py           | 48 +++++++++++++++++++++++++++++++++++++++++++
 static/js/research.js | 11 ++++++++++
 3 files changed, 65 insertions(+), 1 deletion(-)

diff --git a/__init__.py b/__init__.py
index 9a96b72..ba6092b 100644
--- a/__init__.py
+++ b/__init__.py
@@ -443,9 +443,14 @@ def get_nb_occ_by_concept():
 
 @app.route('/_get/entities')
 def get_entities():
-    concept = request.args.get('concept', None)   # type = 'Oligosaccharide_name' or 'Species'
+    concept = request.args.get('concept', None)   # concept = 'Oligosaccharide_name' or 'Species'
     return jsonify(entities(app, conn, concept))
 
+@app.route('/_get/relations')
+def get_relations():
+    id_entity = request.args.get('id_entity', None)   # id_entity = 'oligo_149'
+    return jsonify(relations(app, conn, id_entity))
+
 # API
 source_choices = ["pubmed", "CIRM-BIA", "CIRM-CFBP", "CIRM-Levures", "dsmz", "genbank"]
 qps_choices = ["yes", "no", "true", "false"]
diff --git a/database.py b/database.py
index dcb04a1..ee00e2b 100644
--- a/database.py
+++ b/database.py
@@ -113,6 +113,54 @@ def entities(app, conn, concept):
         dico['totalResults'] = len(dico['results'])
         return dico
 
+# Get relations: /get/relations
+def relations(app, conn, id_entity):
+    conn = get_db(app)
+    if conn != None:
+        cursor = conn.cursor()
+        try:
+            cursor.execute("SELECT ro_group, co_type, c_identifier, cn_name, co_form_concept, d_source, d_source_id \
+                             FROM concept_occurrence, relation_occurrence, concept, concept_name, text, document \
+                             WHERE ro_fk_concept_occurrence_id = co_id AND co_fk_concept_id = c_id AND cn_fk_concept_id = c_id \
+                             AND co_fk_text_id = t_id AND t_fk_document_id = d_id AND ro_group IN ( \
+                             SELECT ro_group FROM relation_occurrence WHERE ro_fk_concept_occurrence_id IN ( \
+                             SELECT co_id FROM concept, concept_occurrence WHERE concept.c_id = concept_occurrence.co_fk_concept_id \
+                             AND (c_identifier = %s OR c_path like %s)))", (id_entity, '%/'+id_entity+'/%'))
+
+        except Exception as err:
+            print_psycopg2_exception(err)
+        dico = dict()
+        list_results = []
+        list_tmp = []
+        group_id = 0
+        for row in cursor.fetchall():
+            dico_tmp = dict()
+            dico_tmp['type'] = row[1]
+            dico_tmp['id'] = row[2]
+            dico_tmp['name'] = row[3]
+            dico_tmp['form'] = row[4]
+            dico_tmp['source'] = row[5]
+            dico_tmp['source_id'] = row[6]
+
+            if group_id != row[0]:
+                if group_id != 0:
+                    dico_list = dict()
+                    dico_list[group_id] = list_tmp
+                    list_results.append(dico_list)
+                group_id = row[0]
+                list_tmp = []
+
+            list_tmp.append(dico_tmp)
+        
+        dico_list = dict()
+        dico_list[group_id] = list_tmp
+        list_results.append(dico_list)
+
+        cursor.close()
+        dico['results'] = list_results
+        dico['totalResults'] = len(dico['results'])
+        return dico
+
 # Check source format
 def check_source(s):
     sources = ['PubMed', 'GenBank', 'DSMZ', 'CIRM-BIA', 'CIRM-Levures', 'CIRM-CFBP']
diff --git a/static/js/research.js b/static/js/research.js
index 1f171fb..2036515 100644
--- a/static/js/research.js
+++ b/static/js/research.js
@@ -148,6 +148,17 @@ document.addEventListener("DOMContentLoaded", function () {
         console.error("Error fetching the JSON data:", error);
       });})
 
+document.addEventListener("DOMContentLoaded", function () {
+    const apiUrl = '/_get/relations?id_entity=oligo_149';   // oligo_149 // OST01 // ncbi:9615 // LS05 // ST01
+    fetch(apiUrl)
+        .then((response) => response.json())
+        .then((data) => {
+            console.log("Data received from the API:", data);
+        })
+        .catch((error) => {
+        console.error("Error fetching the JSON data:", error);
+        });})
+
 // ========================= Global Variables =========================
 // Global variables to store the current dataset and manage pagination
 let currentData = [...dummyData]; 
-- 
GitLab


From 90f8f891292cf87c6f89e511605bd181332e9f49 Mon Sep 17 00:00:00 2001
From: "hajar.bouamout" <hajar.bouamout@inrae.fr>
Date: Thu, 6 Feb 2025 10:12:07 +0100
Subject: [PATCH 29/51] =?UTF-8?q?Am=C3=A9lioration=20de=20la=20page=20de?=
 =?UTF-8?q?=20recherche=20simple=20:=20-=20Int=C3=A9gration=20du=20backend?=
 =?UTF-8?q?=20et=20adaptation=20du=20code=20frontend=20-=20Utilisation=20d?=
 =?UTF-8?q?e=20la=20librairie=20DataTables=20pour=20l'affichage=20des=20r?=
 =?UTF-8?q?=C3=A9sultats=20-=20Impl=C3=A9mentation=20de=20la=20gestion=20d?=
 =?UTF-8?q?es=20colonnes=20(affichage/cacher)=20via=20DataTables=20-=20Ajo?=
 =?UTF-8?q?ut=20du=20t=C3=A9l=C3=A9chargement=20des=20r=C3=A9sultats=20au?=
 =?UTF-8?q?=20format=20CSV=20-=20Optimisation=20de=20la=20pagination=20et?=
 =?UTF-8?q?=20correction=20des=20doublons=20d'affichage=20-=20Impl=C3=A9me?=
 =?UTF-8?q?ntation=20d'une=20autocompl=C3=A9tion=20des=20suggestions?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 static/js/research.js   | 646 +++++++++++++++++-----------------------
 templates/research.html |  97 ++----
 2 files changed, 303 insertions(+), 440 deletions(-)

diff --git a/static/js/research.js b/static/js/research.js
index 2036515..5faa561 100644
--- a/static/js/research.js
+++ b/static/js/research.js
@@ -1,409 +1,309 @@
-// ========================= Mock Data =========================
-// Sample data used for demonstrating search and pagination functionality
-const dummyData = [
-    {
-        oligosaccharide: {
-            name: "2'-Fucosyllactose",
-            url: "https://pubmed.ncbi.nlm.nih.gov/30149573/"            
-        },  
-        oligosaccharide_type: "Fucosylated" ,   
-        sample: "Milk Sample A-123 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
-        species: "Human",
-        descendants: ["Homo sapiens sapiens", "Homo erectus"],
-        lactationStage: "Early",
-    },
-    {
-        oligosaccharide: {
-            name: "3'-Sialyllactose (3'-SL)",
-            url : null            
-        },
-        oligosaccharide_type: "Sialylated",
-        sample: "Milk Sample B-456",
-        species: "Cow",
-        descendants: null,
-        lactationStage: "Mid",
-    },
-
-
-    {
-        oligosaccharide: {
-            name: "3'-Sialyllactose (3'-SL)",
-            url : null            
-        },
-        oligosaccharide_type: "Sialylated",
-        sample: "Milk Sample B-456",
-        species: "homo sapiens",
-        descendants: null,
-        lactationStage: "Mid",
-    },
-
-
-    {
-        oligosaccharide: {
-            name: "6'-Sialyllactose (6'-SL)",
-            url : null,  
-        },
-        oligosaccharide_type: "Sialylated" ,
-        sample: "Milk Sample C-789",
-        species: "Goat",
-        descendants: null,
-        lactationStage: "Late",
-    },
-    {
-        oligosaccharide: {
-            name : "Lacto-N-tetraose (LNT)",
-            url : null            
-        },
-        oligosaccharide_type: "Lacto-N",
-        sample: "Milk Sample D-101",
-        species: "Human",
-        lactationStage: "Early",
-    },
-    {
-        oligosaccharide: {
-            name : "Lacto-N-neotetraose (LNnT)",
-            url : null
-        },
-        oligosaccharide_type: "Lacto-N",
-        sample: "Milk Sample E-112",
-        species: "Human",
-        lactationStage: "Mid",
-    },
-    {
-        oligosaccharide: {
-            name : "Lacto-N-fucopentaose I (LNFP-I)",
-            url : null
+//Test Sandra
+// document.addEventListener("DOMContentLoaded", function () {
+//     const apiUrl = '/_get/relations?id_entity=oligo_149';   // oligo_149 // OST01 // ncbi:9615 // LS05 // ST01
+//     fetch(apiUrl)
+//         .then((response) => response.json())
+//         .then((data) => {
+//             console.log("Data received from the API:", data);
+//         })
+//         .catch((error) => {
+//         console.error("Error fetching the JSON data:", error);
+//         });})
+
+document.addEventListener("DOMContentLoaded", function () {
+  // DOM Element Selection
+  const searchInput = document.getElementById("search-input");
+  const searchType = document.getElementById("simple-search-type");
+  const suggestionBox = document.getElementById("autocomplete-suggestions");
+  const resultsTable = document.getElementById("results-table");
+
+  // Error handling for missing DOM elements
+  if (!searchInput || !searchType || !suggestionBox || !resultsTable) {
+    console.error("One or more DOM elements are missing!");
+    return;
+  }
+
+  let activeIndex = -1;
+  let table; // DataTable instance declaration
+
+  // Dynamic Script Loading
+  // Loads jQuery and DataTables scripts dynamically to ensure proper initialization
+
+  function loadScripts() {
+    return new Promise((resolve) => {
+      const jqueryScript = document.createElement("script");
+      jqueryScript.src = "https://code.jquery.com/jquery-3.6.0.min.js";
+      jqueryScript.onload = () => {
+        const dataTableScript = document.createElement("script");
+        dataTableScript.src =
+          "https://cdn.datatables.net/1.13.6/js/jquery.dataTables.min.js";
+        dataTableScript.onload = () => {
+          const buttonsScript = document.createElement("script");
+          buttonsScript.src =
+            "https://cdn.datatables.net/buttons/2.3.6/js/dataTables.buttons.min.js";
+          buttonsScript.onload = () => {
+            const colVisScript = document.createElement("script");
+            colVisScript.src =
+              "https://cdn.datatables.net/buttons/2.3.6/js/buttons.colVis.min.js";
+            colVisScript.onload = () => {
+              const csvScript = document.createElement("script");
+              csvScript.src =
+                "https://cdn.datatables.net/buttons/2.3.6/js/buttons.html5.min.js";
+              csvScript.onload = resolve;
+              document.head.appendChild(csvScript);
+            };
+            document.head.appendChild(colVisScript);
+          };
+          document.head.appendChild(buttonsScript);
+        };
+        document.head.appendChild(dataTableScript);
+      };
+      document.head.appendChild(jqueryScript);
+    });
+  }
+
+  // DataTable Initialization
+  // Configures the results table with advanced features
+  function initializeDataTable() {
+    table = $("#results-table").DataTable({
+      paging: true,
+      searching: true,
+      ordering: true,
+      info: true,
+      dom: '<"top"B>rt<"bottom"lip>',
+      buttons: [
+        {
+          extend: "colvis",
+          text: "Gérer les colonnes",
         },
-        oligosaccharide_type: "Lacto-N",
-        sample: "Milk Sample F-131",
-        species: "Human",
-        lactationStage: "Late",
-    },
-    {
-        oligosaccharide: {
-            name : "3'-Galactosyllactose (3'-GL)",
-            url : null,
+        {
+          extend: "csvHtml5",
+          text: "Télécharger CSV",
+          filename: "search_results",
+          title: "Search Results",
+          exportOptions: {
+            columns: ":visible",
+          },
         },
-        oligosaccharide_type: "Galactosylated",
-        sample: "Milk Sample G-415",
-        species: "Rabbit",
-        descendants: null,
-        lactationStage: "Early",
-    },
-    {
-        oligosaccharide: {
-            name : "4'-Galactosyllactose (4'-GL)",
-            url : null
+      ],
+      columns: [
+        {
+          data: "oligosaccharide_name",
+          title: "Oligosaccharide Name",
+          defaultContent: "N/A",
         },
-        oligosaccharide_type: "Galactosylated",
-        sample: "Milk Sample H-521",
-        species: "Rabbit",
-        descendants: null,
-        lactationStage: "Mid",
-    },
-    {
-        oligosaccharide: {
-            name : "Sialyl-lacto-N-tetraose a (LSTa)",
-            url : null,
+        {
+          data: "oligosaccharide_type",
+          title: "Oligosaccharide Type",
+          defaultContent: "N/A",
         },
-        oligosaccharide_type: "Sialylated",
-        sample: "Milk Sample I-634",
-        species: "Sheep",
-        descendants: null,
-        lactationStage: "Early",
-    },
-    {
-        oligosaccharide: {
-            name : "Sialyl-lacto-N-tetraose b (LSTb)",
-            url : null,
-           
+        { data: "sample_type", title: "Sample Type", defaultContent: "N/A" },
+        { data: "species", title: "Species", defaultContent: "N/A" },
+        {
+          data: "lactation_stage",
+          title: "Lactation Stage",
+          defaultContent: "N/A",
         },
-        oligosaccharide_type: "Sialylated",
-        sample: "Milk Sample J-747",
-        species: "Sheep",
-        lactationStage: "Mid",
-    },
-    {
-        oligosaccharide: {
-            name : "Sialyl-lacto-N-tetraose c (LSTc)",
-            url : null,
+        { data: "source", title: "Source", defaultContent: "N/A" },
+        {
+          data: "id",
+          title: "Details",
+          render: (id) => `<a href="/details/${id}">View</a>`,
+          defaultContent: "N/A",
         },
-        oligosaccharide_type : "Sialylated",
-        sample: "Milk Sample K-858",
-        species: "Horse",
-        descendants: null,
-        lactationStage: "Late",
-    }
-];
-
-// Test Sandra //
-document.addEventListener("DOMContentLoaded", function () {
-    const apiUrl = '/_get/entities?concept=Sample_type'; // Species // Oligosaccharide_name // Oligosaccharide_type // Lactation_stage
-    fetch(apiUrl)
-      .then((response) => response.json())
-      .then((data) => {
-          console.log("Data received from the API:", data);
-      })
-      .catch((error) => {
-        console.error("Error fetching the JSON data:", error);
-      });})
-
-document.addEventListener("DOMContentLoaded", function () {
-    const apiUrl = '/_get/relations?id_entity=oligo_149';   // oligo_149 // OST01 // ncbi:9615 // LS05 // ST01
-    fetch(apiUrl)
-        .then((response) => response.json())
-        .then((data) => {
-            console.log("Data received from the API:", data);
-        })
-        .catch((error) => {
-        console.error("Error fetching the JSON data:", error);
-        });})
-
-// ========================= Global Variables =========================
-// Global variables to store the current dataset and manage pagination
-let currentData = [...dummyData]; 
-let currentPage = 1; 
-const resultsPerPage = 5; 
-
-// ========================= Simple Search =========================
-// Initialize DOM elements for simple search functionality
-const searchInput = document.getElementById('simple-search');
-const searchButton = document.querySelector('#simple-search-section .search-btn');
-const suggestionBox = document.getElementById('suggestion-box');
-let activeIndex = -1; // Active index for navigating through suggestions
-
-// Main function to perform a simple search
-function performSimpleSearch() {
-    const searchType = document.getElementById('simple-search-type').value; // Type of search (e.g., name, species)
-    const searchQuery = searchInput.value.toLowerCase().trim(); 
-    if (!searchQuery) {
-        // If no keyword, reset results to the full dataset
-        currentData = [...dummyData];
-        populateResults(currentData);
-        return;
-    }
+      ],
+      order: [[0, "asc"]],
+    });
+  }
 
-    // Filter the data based on the search type and query
-    const filteredData = dummyData.filter(item => {
-        switch (searchType) {
-            case 'oligosaccharide_name':
-                return item.oligosaccharide.name.toLowerCase().includes(searchQuery);
-            case 'species':
-                return (item.species.toLowerCase().includes(searchQuery) ||
-                (item.descendants && item.descendants.some(desc => desc.toLowerCase().includes(searchQuery)))
-                );
-            case 'samples':
-                return item.sample.toLowerCase().includes(searchQuery);
-            case 'lactation-stage':
-                return item.lactationStage.toLowerCase().includes(searchQuery);
-            case 'oligosaccharide_type':
-                return item.oligosaccharide_type.toLowerCase().includes(searchQuery);
-            default:
-                return true;
-        }
+  // Data Deduplication
+  // Removes duplicate rows from search results
+  function removeDuplicateRows(data) {
+    const uniqueResults = [];
+    const seen = new Set();
+
+    data.forEach((row) => {
+      const rowKey = `${row.oligosaccharide_name}|${row.oligosaccharide_type}|${row.sample_type}|${row.species}|${row.lactation_stage}|${row.source}`;
+      if (!seen.has(rowKey)) {
+        seen.add(rowKey);
+        uniqueResults.push(row);
+      }
     });
 
-    // Update the current data and refresh the results table
-    currentData = filteredData;
-    populateResults(filteredData);
-}
+    return uniqueResults;
+  }
 
-// ========================= Autocomplete =========================
-// Function to provide suggestions for simple search input
-function autocompleteSearch(query) {
-    if (!query) {
-        // Clear suggestions if query is empty
-        document.getElementById('autocomplete-suggestions').innerHTML = '';
-        return;
-    }
+  // Autocomplete and Suggestions
+  // Fetches and displays suggestions based on user input
+  async function fetchEntities(concept) {
+    if (!concept) return [];
 
-    const searchType = document.getElementById('simple-search-type').value;
-    const suggestions = new Set();
-    const queryLower = query.toLowerCase();
-
-    // Generate suggestions based on search type
-    dummyData.forEach(item => {
-        let value = '';
-        switch (searchType) {
-            case 'oligosaccharide_name':
-                value = item.oligosaccharide.name;
-                break;
-            case 'oligosaccharide_type':
-                value = item.oligosaccharide_type;
-                break;
-                case 'species':
-                    // Include both species and descendants in suggestions
-                    value = item.species;
-                    if (value.toLowerCase().includes(queryLower)) suggestions.add(value);
-                    if (item.descendants) {
-                        item.descendants.forEach(desc => {
-                            if (desc.toLowerCase().includes(queryLower)) suggestions.add(desc);
-                        });
-                    }
-                    break;
-            case 'samples':
-                value = item.sample;
-                break;
-            case 'lactation-stage':
-                value = item.lactationStage;
-                break;
-        }
-        if (value.toLowerCase().includes(queryLower)) {
-            suggestions.add(value);
-        }
-    });
+    const normalizedConcept =
+      concept.charAt(0).toUpperCase() + concept.slice(1);
 
-    // Update the suggestions box with the filtered suggestions
-    const suggestionBox = document.getElementById('autocomplete-suggestions');
-    suggestionBox.innerHTML = '';
-    activeIndex = -1;
-
-    if (suggestions.size > 0) {
-        Array.from(suggestions)
-            .slice(0, 5)
-            .forEach(item => {
-                const div = document.createElement('div');
-                div.textContent = item;
-                div.onclick = () => {
-                    searchInput.value = item;
-                    suggestionBox.innerHTML = '';
-                    performSimpleSearch();
-                };
-                suggestionBox.appendChild(div);
-            });
-    }
+    try {
+      const response = await fetch(
+        `/_get/entities?concept=${normalizedConcept}`
+      );
+      if (!response.ok) throw new Error("Error fetching entities");
 
-}
+      const data = await response.json();
 
-// ========================= Pagination =========================
-// Function to paginate results based on the current page and results per page
-function paginateResults(data) {
-    const start = (currentPage - 1) * resultsPerPage;
-    const end = start + resultsPerPage;
-    return data.slice(start, end);
-}
+      // Log to view the retrieved entities
+      console.log(
+        "Entities received from the API :",
+        JSON.stringify(data, null, 2)
+      );
 
-// Function to render pagination buttons
-function renderPagination(totalItems) {
-    const paginationElement = document.getElementById('pagination');
-    paginationElement.innerHTML = '';
-
-    const totalPages = Math.ceil(totalItems / resultsPerPage);
-    for (let i = 1; i <= totalPages; i++) {
-        const button = document.createElement('button');
-        button.textContent = i;
-        button.className = i === currentPage ? 'active' : '';
-        button.onclick = () => {
-            currentPage = i;
-            populateResults(currentData);
-        };
-        paginationElement.appendChild(button);
+      return data.results || [];
+    } catch (error) {
+      console.error("🚨 Error API :", error);
+      return [];
+    }
+  }
+  async function displaySuggestions(query) {
+    suggestionBox.innerHTML = "";
+
+    const concept = searchType.value;
+    if (query.length >= 1) {
+        const suggestions = await fetchEntities(concept, query);
+
+        const filteredResults = suggestions.filter(item => {
+            const name = (item.name || item.form || "").toLowerCase();
+            return name.startsWith(query.toLowerCase()) || name.includes(query.toLowerCase());
+        }).slice(0, 5);
+
+        if (filteredResults.length > 0) {
+            filteredResults.forEach((item) => {
+                const div = document.createElement("div");
+                div.textContent = item.name || item.form;
+                div.dataset.id = item.identifier;
+                div.onclick = () => selectSuggestion(item);
+                suggestionBox.appendChild(div);
+            });
+        } else {
+            suggestionBox.innerHTML = '<div class="no-result">No suggestions</div>';
+        }
     }
 }
+  searchInput.addEventListener("input", function () {
+    setTimeout(() => displaySuggestions(this.value), 100);
+  });
 
-// ========================= Results Table =========================
-// Function to populate the results table with the given data
-function populateResults(data) {
-    const resultsBody = document.getElementById("results-body");
-    const paginatedData = paginateResults(data);
-    resultsBody.innerHTML = "";
-
-    if (data.length === 0) {
-        const row = document.createElement("tr");
-        row.innerHTML = `
-            <td colspan="5" style="text-align: center; padding: 20px;">
-                No results found. Please try a different search.
-            </td>
-        `;
-        resultsBody.appendChild(row);
-        return;
+  // Entity Selection and Relation Fetching
+  // Handles selection of autocomplete suggestions and retrieves related data
+  async function selectSuggestion(item) {
+    if (!item.identifier) {
+      console.error("No identifier found for selected item!");
+      return;
     }
 
-    // Create table rows for each item in the paginated data
-    paginatedData.forEach((item) => {
-        const oligosaccharideContent = item.oligosaccharide.url
-            ? `<a href="${item.oligosaccharide.url}" target="_blank">${item.oligosaccharide.name}</a>`
-            : item.oligosaccharide.name;
-
-        const row = document.createElement("tr");
-        row.innerHTML = `
-            <td>${oligosaccharideContent}</td>
-            <td>${item.oligosaccharide_type}</td>
-            <td>${item.sample}</td>
-            <td>${item.species}</td>
-            <td>${item.lactationStage}</td>
-            <td><button class="details-btn" onclick="showDetails('${item.oligosaccharide.name}')">Details</button></td>
-        `;
-        resultsBody.appendChild(row);
-    });
+    searchInput.value = item.name;
+    suggestionBox.innerHTML = "";
 
-    // Render pagination buttons
-    renderPagination(data.length);
-}
+    await fetchRelations(item.identifier);
+  }
 
-// ========================= Additional Features =========================
-// Redirect to a details page with the selected oligosaccharide
-function showDetails(oligosaccharideName) {
-    window.location.href = `sheet?oligosaccharide=${encodeURIComponent(oligosaccharideName)}`;
-}
+  // Listen to input to display suggestions
+  searchInput.addEventListener("input", async function () {
+    const query = this.value;
+    const concept = searchType.value;
 
-// Toggle visibility of extra information
-function toggleExtraInfo(button) {
-    const extraInfo = button.nextElementSibling;
-    if (extraInfo.style.display === "none") {
-        extraInfo.style.display = "block";
-        button.textContent = "-";
+    if (query.length > 1) {
+      // Display suggestions from the first letter
+      const entities = await fetchEntities(concept);
+      displaySuggestions(entities, query);
     } else {
-        extraInfo.style.display = "none";
-        button.textContent = "+";
+      suggestionBox.innerHTML = "";
     }
-}
+  });
 
-// Sort table data by the selected column
-function sortTable(columnIndex) {
-    const sortedData = [...currentData].sort((a, b) => {
-        const valueA = Object.values(a)[columnIndex]?.toString().toLowerCase() || '';
-        const valueB = Object.values(b)[columnIndex]?.toString().toLowerCase() || '';
-        return valueA.localeCompare(valueB);
-    });
-    populateResults(sortedData);
-}
+  // Request to retrieve an entity's relations
+  async function fetchRelations(entityId) {
+    if (!entityId) {
+      console.error("No identifier provided to retrieve relations!");
+      return;
+    }
 
-// ========================= Initialization =========================
-// Initialize the page and set up event listeners on page load
-window.onload = function() {
-    currentData = [...dummyData];
-    populateResults(currentData);
-};
+    try {
+      const response = await fetch(`/_get/relations?id_entity=${entityId}`);
+      if (!response.ok) throw new Error("Error while retrieving relations");
 
-function showSimpleSearchResults() {
-    const searchType = document.getElementById('simple-search-type').value;
-    const searchKeyword = document.getElementById('simple-search').value;
+      const data = await response.json();
+      console.log("🔍 Received data API:", JSON.stringify(data, null, 2));
 
-    if (searchKeyword.trim() === '') {
-      alert('Please enter a keyword!');
-      return;
+      displayResults(data);
+    } catch (error) {
+      console.error("Error while retrieving relations:", error);
     }
+  }
 
-    const resultsSection = document.getElementById('results-section');
-    resultsSection.style.display = 'block';
+  // Results Display
+  // Processes and displays search results in the DataTable
+  function displayResults(data) {
+    if (!table) {
+      console.error("DataTable not initialized!");
+      return;
+    }
 
-    console.log(`Search by ${searchType} with keyword "${searchKeyword}"`);
-  }
+    if (!data?.results) {
+      console.error("Invalid API response:", data);
+      return;
+    }
 
-// This script toggles the visibility of table columns based on checkbox selections.
-  document.querySelectorAll('#column-toggles input[type="checkbox"]').forEach((checkbox) => {
-    checkbox.addEventListener('change', function () {
-      const column = this.dataset.column; 
-      const table = document.querySelector('.results-table');
-      const rows = table.querySelectorAll('tr');
-  
-      rows.forEach((row) => {
-        const cells = row.querySelectorAll('th, td');
-        if (cells[column]) {
-          cells[column].style.display = this.checked ? '' : 'none';
+    const flatResults = [];
+
+    data.results.forEach((group) => {
+      Object.entries(group).forEach(([groupId, groupData]) => {
+        if (Array.isArray(groupData) && groupData.length > 0) {
+          let formattedItem = {
+            oligosaccharide_name: "N/A",
+            oligosaccharide_type: "N/A",
+            sample_type: "N/A",
+            species: "N/A",
+            lactation_stage: "N/A",
+            source: "N/A",
+            id: groupId,
+          };
+
+          groupData.forEach((item) => {
+            if (item && item.type) {
+              if (item.type === "Oligosaccharide_name")
+                formattedItem.oligosaccharide_name = item.name || "Unknown";
+              if (item.type === "Oligosaccharide_type")
+                formattedItem.oligosaccharide_type = item.name || "Unknown";
+              if (item.type === "Sample_type")
+                formattedItem.sample_type = item.name || "Unknown";
+              if (item.type === "Species")
+                formattedItem.species = item.name || "Unknown";
+              if (item.type === "Lactation_stage")
+                formattedItem.lactation_stage = item.name || "Unknown";
+              formattedItem.source = item.source || "Unknown";
+            }
+          });
+
+          flatResults.push(formattedItem);
         }
       });
     });
-  });
-  
\ No newline at end of file
+
+    const uniqueResults = removeDuplicateRows(flatResults);
+
+    console.log("Final unique data to display in DataTables:", uniqueResults);
+
+    table.clear();
+    table.rows.add(uniqueResults);
+    table.draw();
+    document.getElementById("results-section").style.display = "block";
+  }
+
+  // Initialization
+  // Loads scripts and initializes the page functionality
+  async function initialize() {
+    await loadScripts();
+    initializeDataTable();
+  }
+
+  // Start the initialization process
+  initialize().catch(console.error);
+});
diff --git a/templates/research.html b/templates/research.html
index 42badcf..8a3f122 100644
--- a/templates/research.html
+++ b/templates/research.html
@@ -1,5 +1,6 @@
 {% extends 'main2' %} {% block content %}
 
+<!--Head Section -->
 <head>
   <link
     rel="stylesheet"
@@ -9,20 +10,18 @@
     src="{{ url_for('static', filename='js/research.js') }}"
     defer
   ></script>
+  <!-- DataTables CSS -->
+  <link
+    rel="stylesheet"
+    href="https://cdn.datatables.net/1.13.6/css/jquery.dataTables.min.css"
+  />
+  <link
+    rel="stylesheet"
+    href="https://cdn.datatables.net/buttons/2.3.6/css/buttons.dataTables.min.css"
+  />
 </head>
 
-<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
-
-<script
-  type="application/javascript"
-  src="https://cdn.jsdelivr.net/npm/chartjs-chart-boxplot@4.0.0/dist/chartjs-chart-boxplot.min.js"
-></script>
-
-<script
-  type="application/javascript"
-  src="/static/js/chartjs-chart-box-and-violin-plot.min.js"
-></script>
-
+<!--Main Content Structure-->
 <body>
   <div class="main-content2">
     <section class="info-section">
@@ -39,19 +38,6 @@
       </div>
     </section>
 
-    <!-- Section "Getting Started" 
-    <section class="getting-started">
-      <div class="info-box">
-        <h3>Getting Started</h3>
-        <ul>
-          <li>Select your search type from the dropdown menu</li>
-          <li>Enter your search terms in the search bar</li>
-          <li>Use the autocomplete suggestions for accurate results</li>
-          <li>Click search to view your results</li>
-        </ul>
-      </div>
-    </section>-->
-
     <!-- Simple Search Form -->
     <section id="simple-search-section" class="search-section">
       <div class="search-bar2">
@@ -60,69 +46,46 @@
           <option value="oligosaccharide_name">Oligosaccharide Name</option>
           <option value="oligosaccharide_type">Oligosaccharide Type</option>
           <option value="species">Species</option>
-          <option value="samples">Samples</option>
-          <option value="lactation-stage">Lactation Stage</option>
+          <option value="sample_type">Sample Type</option>
+          <option value="lactation_stage">Lactation Stage</option>
         </select>
         <input
           type="text"
-          id="simple-search"
+          id="search-input"
           placeholder="Enter a keyword to begin..."
-          onkeyup="autocompleteSearch(this.value)"
         />
         <div id="autocomplete-suggestions" class="autocomplete-box"></div>
-        <button class="search-btn" onclick="showSimpleSearchResults()">
-          Search
-        </button>
-        <div id="suggestion-box" class="autocomplete-box"></div>
+        <button class="search-btn">Search</button>
       </div>
     </section>
 
     <!-- Results Section -->
     <section id="results-section" class="results-section">
       <h2>Search Results</h2>
-      <div id="column-toggles">
-        <label
-          ><input type="checkbox" data-column="0" checked /> Oligosaccharide
-          Name</label
-        >
-        <label
-          ><input type="checkbox" data-column="1" checked /> Oligosaccharide
-          Type</label
-        >
-        <label><input type="checkbox" data-column="2" checked /> Sample</label>
-        <label><input type="checkbox" data-column="3" checked /> Species</label>
-        <label
-          ><input type="checkbox" data-column="4" checked /> Lactation
-          Stage</label
-        >
-        <label><input type="checkbox" data-column="5" checked /> Details</label>
-      </div>
-
-      <table class="results-table">
+      <table id="results-table" class="display">
         <thead>
           <tr>
-            <th onclick="sortTable(0)">
-              Oligosaccharide Name <i class="fas fa-sort"></i>
-            </th>
-            <th onclick="sortTable(1)">
-              Oligosaccharide Type <i class="fas fa-sort"></i>
-            </th>
-            <th onclick="sortTable(2)">Sample <i class="fas fa-sort"></i></th>
-            <th onclick="sortTable(3)">Species <i class="fas fa-sort"></i></th>
-            <th onclick="sortTable(4)">
-              Lactation Stage <i class="fas fa-sort"></i>
-            </th>
-            <th onclick="sortTable(5)">Details <i class="fas fa-sort"></i></th>
+            <th>Oligosaccharide Name</th>
+            <th>Oligosaccharide Type</th>
+            <th>Sample</th>
+            <th>Species</th>
+            <th>Lactation Stage</th>
+            <th>Source</th>
+            <th>Details</th>
           </tr>
         </thead>
         <tbody id="results-body">
-          <!-- Rows will be dynamically populated by JavaScript -->
+          <!-- The data will be injected dynamically here-->
         </tbody>
       </table>
-
-      <div id="pagination" style="margin-top: 20px; text-align: center"></div>
     </section>
   </div>
+
+  <!-- Scripts jQuery and DataTables -->
+  <script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
+  <script src="https://cdn.datatables.net/1.13.6/js/jquery.dataTables.min.js"></script>
+  <script src="https://cdn.datatables.net/buttons/2.3.6/js/dataTables.buttons.min.js"></script>
+  <script src="https://cdn.datatables.net/buttons/2.3.6/js/buttons.colVis.min.js"></script>
 </body>
 
 {% endblock %}
-- 
GitLab


From d4ae8443a4ca863a91831f69e6f8be68b7bff4de Mon Sep 17 00:00:00 2001
From: "hajar.bouamout" <hajar.bouamout@inrae.fr>
Date: Thu, 6 Feb 2025 10:45:33 +0100
Subject: [PATCH 30/51] =?UTF-8?q?Ajout=20de=20la=20fonctionnalit=C3=A9=20d?=
 =?UTF-8?q?e=20recherche=20sur=20les=20donn=C3=A9es=20de=20tableau=20de=20?=
 =?UTF-8?q?r=C3=A9sultats?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 static/js/research.js | 12 ++++++++++--
 1 file changed, 10 insertions(+), 2 deletions(-)

diff --git a/static/js/research.js b/static/js/research.js
index 5faa561..aed172d 100644
--- a/static/js/research.js
+++ b/static/js/research.js
@@ -16,6 +16,7 @@ document.addEventListener("DOMContentLoaded", function () {
   const searchType = document.getElementById("simple-search-type");
   const suggestionBox = document.getElementById("autocomplete-suggestions");
   const resultsTable = document.getElementById("results-table");
+  const tableSearchInput = document.getElementById("table-search-input");
 
   // Error handling for missing DOM elements
   if (!searchInput || !searchType || !suggestionBox || !resultsTable) {
@@ -70,7 +71,7 @@ document.addEventListener("DOMContentLoaded", function () {
       searching: true,
       ordering: true,
       info: true,
-      dom: '<"top"B>rt<"bottom"lip>',
+      dom: '<"top"f>rt<"bottom"ip>',
       buttons: [
         {
           extend: "colvis",
@@ -157,7 +158,7 @@ document.addEventListener("DOMContentLoaded", function () {
 
       return data.results || [];
     } catch (error) {
-      console.error("🚨 Error API :", error);
+      console.error("Error API :", error);
       return [];
     }
   }
@@ -190,6 +191,13 @@ document.addEventListener("DOMContentLoaded", function () {
     setTimeout(() => displaySuggestions(this.value), 100);
   });
 
+
+  if (tableSearchInput) {
+    tableSearchInput.addEventListener("input", function () {
+        table.search(this.value).draw();
+    });
+}
+
   // Entity Selection and Relation Fetching
   // Handles selection of autocomplete suggestions and retrieves related data
   async function selectSuggestion(item) {
-- 
GitLab


From 630fcb526955af5fb0f83a505e920fdf7a9019eb Mon Sep 17 00:00:00 2001
From: "hajar.bouamout" <hajar.bouamout@inrae.fr>
Date: Wed, 12 Feb 2025 10:29:59 +0100
Subject: [PATCH 31/51] =?UTF-8?q?Correction=20et=20am=C3=A9lioration=20g?=
 =?UTF-8?q?=C3=A9n=C3=A9rale=20du=20code?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

- Définition des fonctions de collecte des données pour les différentes entités (oligosaccharides, espèces, échantillons).
- Ajout de la gestion dynamique des entités pour rendre le code plus modulaire.
- Validation du type d'entité avant d'accéder aux données pour éviter les erreurs.
- Amélioration de la gestion des erreurs pour le téléchargement CSV et l'affichage des données.
- Réorganisation du code pour une meilleure lisibilité et maintenance.
---
 static/js/sheet.js   | 204 ++++++++++++++++++++++++++-----------------
 templates/sheet.html | 109 +++++++++++------------
 2 files changed, 177 insertions(+), 136 deletions(-)

diff --git a/static/js/sheet.js b/static/js/sheet.js
index 99b65f7..caa1e20 100644
--- a/static/js/sheet.js
+++ b/static/js/sheet.js
@@ -1,84 +1,85 @@
-document.addEventListener('DOMContentLoaded', function() {
+document.addEventListener("DOMContentLoaded", function () {
   // Initial setup
   initializeApp();
-
-  // Event listeners for global elements
-  setupEventListeners();
 });
 
 function initializeApp() {
-  // Show initial section
-  toggleSection('oligo');
-
-  // Load initial structure
-  loadStructure('2\'-Fucosyllactose');
+  const { entityId, entityType } = getURLParams();
+  if (entityId && entityType) {
+    loadEntityData(entityId, entityType);
+  }
 }
 
-function setupEventListeners() {
-  // Navigation buttons are handled by inline onclick in HTML
-  
-  // Setup download buttons
-  const downloadButtons = document.querySelectorAll('.download-btn');
-  downloadButtons.forEach(button => {
-      button.addEventListener('click', () => downloadCSV());
-  });
+function getURLParams() {
+  const urlParams = new URLSearchParams(window.location.search);
+  return {
+    entityId: urlParams.get("entity_id"),
+    entityType: urlParams.get("entity_type")
+  };
 }
 
-// Section visibility toggle
-window.toggleSection = function(sectionType) {
-  const sections = document.querySelectorAll('.section');
-  sections.forEach(section => section.classList.add('hidden'));
-  
-  const activeSection = document.getElementById(`${sectionType}-section`);
-  if (activeSection) {
-      activeSection.classList.remove('hidden');
-  }
+// Function to load data for a specific entity
+function loadEntityData(entityId, entityType) {
+  fetch(`/api/sheet/entity/${entityId}?entity_type=${entityType}`)
+    .then((response) => response.json())
+    .then((data) => {
+      displayEntityData(data, entityType);
+    })
+    .catch((error) => console.error("Error fetching data:", error));
 }
 
-// CSV Download functionality
-window.downloadCSV = function() {
-  const section = document.querySelector('.section:not(.hidden)');
-  if (!section) return;
+// Function to display entities
+function displayEntityData(data, entityType) {
+  const dataMapping = {
+    oligosaccharide: [
+      { id: "oligo-id", field: "id" },
+      { id: "oligo-name", field: "name" },
+      { id: "oligo-formula", field: "formula" },
+      { id: "oligo-synonyms", field: "synonyms" },
+      { id: "oligo-occurrence-text", field: "occurrence_text" },
+      { id: "oligo-reference-class", field: "reference_class" },
+      { id: "oligo-species", field: "species" },
+      { id: "oligo-mo-type", field: "mo_type" },
+    ],
+    species: [
+      { id: "species-id", field: "id" },
+      { id: "species-name", field: "scientific_name" },
+      { id: "species-occurrences", field: "number_of_occurrences" },
+    ],
+    sample: [
+      { id: "sample-id", field: "id" },
+      { id: "sample-name", field: "scientific_name" },
+      { id: "sample-species", field: "associated_species" },
+    ],
+  };
 
-  try {
-      const data = collectSectionData(section);
-      const csvContent = convertToCSV(data);
-      triggerDownload(csvContent, `${section.id}_data.csv`);
-  } catch (error) {
-      console.error('Error generating CSV:', error);
-      alert('Error generating CSV file. Please try again.');
-  }
-}
-
-function collectSectionData(section) {
-  const data = [];
-  const infoItems = section.querySelectorAll('.info-item');
-  
-  infoItems.forEach(item => {
-      const label = item.querySelector('.info-label').textContent.trim();
-      const value = item.querySelector('.info-value').textContent.trim();
-      data.push([label, value]);
+  dataMapping[entityType].forEach(item => {
+    document.getElementById(item.id).textContent = Array.isArray(data[item.field]) ? data[item.field].join(", ") : data[item.field];
   });
 
-  return data;
+   // 3D image for oligosaccharides structure
+   if (entityType === "oligosaccharide") {
+    const structureImage = document.getElementById("structure-image");
+    structureImage.src = data.Image_URL;
+    structureImage.alt = `${data.name} structure`;
+  }
 }
 
-function convertToCSV(data) {
-  // Add header
-  const rows = [['Label', 'Value'], ...data];
-  
-  // Convert to CSV format
-  return rows
-      .map(row => 
-          row.map(cell => 
-              `"${(cell || '').replace(/"/g, '""')}"`)
-          .join(','))
-      .join('\n');
-}
+// Section visibility toggle
+window.toggleSection = function (sectionType) {
+  const sections = document.querySelectorAll(".section");
+  sections.forEach((section) => section.classList.add("hidden"));
+
+  const activeSection = document.getElementById(`${sectionType}-section`);
+  if (activeSection) {
+    activeSection.classList.remove("hidden");
+  }
+};
 
+// Function to trigger the download of the CSV file
 function triggerDownload(content, filename) {
-  const blob = new Blob([content], { type: 'text/csv;charset=utf-8;' });
-  const link = document.createElement('a');
+  const blob = new Blob([content], { type: "text/csv;charset=utf-8;" });
+  const link = document.createElement("a");
   link.href = URL.createObjectURL(blob);
   link.download = filename;
   document.body.appendChild(link);
@@ -86,22 +87,67 @@ function triggerDownload(content, filename) {
   document.body.removeChild(link);
 }
 
-// Structure loading functionality
-async function loadStructure(compoundName) {
+ // Function to convert data to CSV file
+ function convertToCSV(data) {
+  const rows = [['Label', 'Value'], ...data];
+  return rows
+    .map(row => row.map(cell => `"${(cell || '').replace(/"/g, '""')}"`).join(','))
+    .join('\n');
+}
+
+// Function to download data as CSV
+function downloadCSV() {
+  const section = document.querySelector(".section:not(.hidden)");
+  if (!section) return;
+
   try {
-      // Example using PubChem API
-      const searchUrl = `https://pubchem.ncbi.nlm.nih.gov/rest/pug/compound/name/${encodeURIComponent(compoundName)}/PNG`;
-      
-      const structureImage = document.getElementById('structure-image');
-      if (structureImage) {
-          structureImage.src = searchUrl;
-          structureImage.alt = `${compoundName} structure`;
-      }
+    let data;
+    if (section.id === "oligo-section") {
+      data = collectOligosaccharideData();
+    } else if (section.id === "species-section") {
+      data = collectSpeciesData();
+    } else if (section.id === "samples-section") {
+      data = collectSampleData();
+    }
+
+    const csvContent = convertToCSV(data);
+    triggerDownload(csvContent, `${section.id}_data.csv`);
   } catch (error) {
-      console.error('Error loading structure:', error);
-      const structureImage = document.getElementById('structure-image');
-      if (structureImage) {
-          structureImage.alt = 'Error loading structure';
-      }
+    console.error("Error generating CSV:", error);
+    alert("Error generating CSV file. Please try again.");
+  }
+}
+
+
+// Function to collect oligosaccharide data
+function collectOligosaccharideData() {
+  return [
+    ['Milk Oligosaccharide ID', document.getElementById('oligo-id').textContent],
+    ['Milk Oligosaccharide Normalized Name', document.getElementById('oligo-name').textContent],
+    ['Formula', document.getElementById('oligo-formula').textContent],
+    ['Synonyms', document.getElementById('oligo-synonyms').textContent],
+    ['Text Occurrence', document.getElementById('oligo-occurrence-text').textContent],
+    ['Reference Class', document.getElementById('oligo-reference-class').textContent],
+    ['Species', document.getElementById('oligo-species').textContent],
+    ['MO Type', document.getElementById('oligo-mo-type').textContent],
+  ];
+}
+
+ 
+  // Function to collect species data
+  function collectSpeciesData() {
+    return [
+      ['Species ID', document.getElementById('species-id').textContent],
+      ['Species Scientific Name', document.getElementById('species-name').textContent],
+      ['Number of Occurrences', document.getElementById('species-occurrences').textContent],
+    ];
   }
-}
\ No newline at end of file
+  
+  // Function to collect sample data
+  function collectSampleData() {
+    return [
+      ['Sample ID', document.getElementById('sample-id').textContent],
+      ['Sample Scientific Name', document.getElementById('sample-name').textContent],
+      ['Associated Species', document.getElementById('sample-species').textContent],
+    ];
+  }
\ No newline at end of file
diff --git a/templates/sheet.html b/templates/sheet.html
index dbe9808..dc07fa2 100644
--- a/templates/sheet.html
+++ b/templates/sheet.html
@@ -14,46 +14,53 @@
   </nav>
 
   <!-- Content Area -->
-  <div class="content">
+    <div class="content">
+      <div class="action-bar">
+        <button class="download-btn" onclick="downloadCSV()">Download CSV</button>
+      </div>
     <!-- Oligosaccharides Section -->
     <section id="oligo-section" class="section">
       <div class="info-card">
         <h2 class="card-header">Oligosaccharide Information</h2>
         <div class="info-grid">
-          {% for label, value in [
-            ('Milk Oligosaccharide ID', 'OLIGO0137'),
-            ('Milk Oligosaccharide Normalized Name', '2\'-Fucosyllactose'),
-            ('Abbreviated Normalized MO Name', '2\'-FL'),
-            ('Formula', 'C18H32O15'),
-            ('Synonyms', '2\'FL | 2\'fucosyllactose | 2FL')
-          ] %}
           <div class="info-item">
-            <span class="info-label">{{ label }}</span>
-            <span class="info-value">{{ value }}</span>
+            <span class="info-label">Milk Oligosaccharide ID</span>
+            <span class="info-value" id="oligo-id"></span>
+          </div>
+          <div class="info-item">
+            <span class="info-label">Milk Oligosaccharide Normalized Name</span>
+            <span class="info-value" id="oligo-name"></span>
+          </div>
+          <div class="info-item">
+            <span class="info-label">Formula</span>
+            <span class="info-value" id="oligo-formula"></span>
+          </div>
+          <div class="info-item">
+            <span class="info-label">Synonyms</span>
+            <span class="info-value" id="oligo-synonyms"></span>
           </div>
-          {% endfor %}
         </div>
       </div>
 
       <div class="info-card">
         <h2 class="card-header">Matched Information</h2>
         <div class="info-grid">
-          {% for label, value in [
-            ('Text Occurrence', 'fucosyllactose'),
-            ('Reference Class', '2\'-Fucosyllactose'),
-            ('Species', 'Rabbit'),
-            ('MO Type', 'XX'),
-            ('MO Samples', 'Unidentified'),
-            ('Methods of Analysis', 'HPAEC-PAD'),
-            ('Text Snippet', 'HPAEC-PAD was used to quantify 2\'-fucosyllactose (2\'-FL)'),
-            ('Number of Occurrences', '2'),
-            ('Number of Matched Documents', '13')
-          ] %}
           <div class="info-item">
-            <span class="info-label">{{ label }}</span>
-            <span class="info-value">{{ value }}</span>
+            <span class="info-label">Text Occurrence</span>
+            <span class="info-value" id="oligo-occurrence-text"></span>
+          </div>
+          <div class="info-item">
+            <span class="info-label">Reference Class</span>
+            <span class="info-value" id="oligo-reference-class"></span>
+          </div>
+          <div class="info-item">
+            <span class="info-label">Species</span>
+            <span class="info-value" id="oligo-species"></span>
+          </div>
+          <div class="info-item">
+            <span class="info-label">MO Type</span>
+            <span class="info-value" id="oligo-mo-type"></span>
           </div>
-          {% endfor %}
         </div>
       </div>
 
@@ -63,10 +70,6 @@
           <img id="structure-image" class="structure-image" alt="3D Structure">
         </div>
       </div>
-
-      <div class="action-bar">
-        <button class="download-btn" onclick="downloadCSV()">Download CSV</button>
-      </div>
     </section>
 
     <!-- Species Section -->
@@ -74,25 +77,20 @@
       <div class="info-card">
         <h2 class="card-header">Species Information</h2>
         <div class="info-grid">
-          {% for label, value in [
-            ('Species ID', ''),
-            ('Species Scientific Name', ''),
-            ('Number Of Occurrence', ''),
-            ('Physiological Stage', ''),
-            ('Breed', ''),
-            ('Geography', ''),
-            ('Postpartum age', '')
-          ] %}
           <div class="info-item">
-            <span class="info-label">{{ label }}</span>
-            <span class="info-value">{{ value }}</span>
+            <span class="info-label">Species ID</span>
+            <span class="info-value" id="species-id"></span>
+          </div>
+          <div class="info-item">
+            <span class="info-label">Species Scientific Name</span>
+            <span class="info-value" id="species-name"></span>
+          </div>
+          <div class="info-item">
+            <span class="info-label">Number of Occurrences</span>
+            <span class="info-value" id="species-occurrences"></span>
           </div>
-          {% endfor %}
         </div>
       </div>
-      <div class="action-bar">
-        <button class="download-btn" onclick="downloadCSV()">Download CSV</button>
-      </div>
     </section>
 
     <!-- Samples Section -->
@@ -100,23 +98,20 @@
       <div class="info-card">
         <h2 class="card-header">Samples Information</h2>
         <div class="info-grid">
-          {% for label, value in [
-            ('Samples ID', ''),
-            ('Samples Scientific Name', ''),
-            ('Associated Species', ''),
-            ('MO Normalization Method', ''),
-            ('Lactation Stage', '')
-          ] %}
           <div class="info-item">
-            <span class="info-label">{{ label }}</span>
-            <span class="info-value">{{ value }}</span>
+            <span class="info-label">Samples ID</span>
+            <span class="info-value" id="sample-id"></span>
+          </div>
+          <div class="info-item">
+            <span class="info-label">Samples Scientific Name</span>
+            <span class="info-value" id="sample-name"></span>
+          </div>
+          <div class="info-item">
+            <span class="info-label">Associated Species</span>
+            <span class="info-value" id="sample-species"></span>
           </div>
-          {% endfor %}
         </div>
       </div>
-      <div class="action-bar">
-        <button class="download-btn" onclick="downloadCSV()">Download CSV</button>
-      </div>
     </section>
   </div>
 </main>
-- 
GitLab


From 24fa98758571457bd0715967b64a62054d030416 Mon Sep 17 00:00:00 2001
From: "hajar.bouamout" <hajar.bouamout@inrae.fr>
Date: Wed, 12 Feb 2025 10:36:35 +0100
Subject: [PATCH 32/51] =?UTF-8?q?am=C3=A9lioration=20de=20l'affichage=20et?=
 =?UTF-8?q?=20du=20style=20de=20la=20home=20page?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 static/css/home.css | 72 +++++++++++++++++++++++++++++----------------
 templates/home.html | 15 +++++-----
 2 files changed, 55 insertions(+), 32 deletions(-)

diff --git a/static/css/home.css b/static/css/home.css
index fae9b5c..5532c61 100644
--- a/static/css/home.css
+++ b/static/css/home.css
@@ -7,41 +7,54 @@ body {
 /* Hero Section */
 .hero-section {
   background: linear-gradient(145deg, #274757, #0077cc);
-  padding: 4rem 0;
-  border-radius: 0 0 2rem 2rem;
+  padding: 2rem 0;
+  border-radius: 20px;
   color: white;
-  margin-top: 40px;
+  margin: 40px auto;
+  max-width: 80%;
+  text-align: center;
+  box-shadow: 0px 5px 15px rgba(0, 0, 0, 0.15);
+}
+
+.hero-section .logo {
+  max-width: 80px; 
+  margin-bottom: 0.8rem;
 }
 
+
+/* Titre plus compact */
 .hero-section h1 {
-  color: black;
-  font-size: 2.8rem;
-  margin-bottom: 1.5rem;
+  font-size: 2rem; 
+  font-weight: bold;
+  margin-bottom: 1rem;
+  color: white;
 }
 
 .hero-section .description {
-  max-width: 800px;
+  max-width: 600px;
+  font-size: 1rem;
+  line-height: 1.5;
+  color: white;
+  opacity: 0.9;
   margin: 0 auto;
-  font-size: 1.2rem;
-  line-height: 1.6;
-  color :black;
-  opacity: 0.95;
 }
 
 .btn-info {
-  background-color: #274757;
-  border: none;
-  padding: 0.8rem 2rem;
-  border-radius: 2rem;
-  font-weight: 500;
-  transition: transform 0.2s;
+  background-color: #ff8c00;
+  padding: 0.6rem 1.5rem;
+  border-radius: 30px;
+  font-weight: bold;
+  font-size: 1rem;
+  transition: all 0.3s ease-in-out;
+  box-shadow: 2px 2px 10px rgba(0, 0, 0, 0.15);
 }
 
 .btn-info:hover {
-  transform: translateY(-2px);
-  background-color: #274757;
+  background-color: #e67e00;
+  transform: scale(1.05);
 }
 
+
 /* Data Overview Section */
 .section-title {
   font-size: 2.2rem;
@@ -132,12 +145,21 @@ body {
 }
 
 @media (max-width: 768px) {
-  .visualization-row {
-    flex-direction: column;
+  .hero-section {
+    max-width: 90%;
+    padding: 1.5rem 0;
+  }
+
+  .hero-section h1 {
+    font-size: 1.8rem;
   }
-  
-  .viz-card {
-    margin-bottom: 2rem;
+
+  .hero-section .description {
+    font-size: 0.9rem;
   }
-} 
 
+  .btn-info {
+    font-size: 0.9rem;
+    padding: 0.5rem 1.2rem;
+  }
+}
diff --git a/templates/home.html b/templates/home.html
index ea9fa5a..bff49ae 100644
--- a/templates/home.html
+++ b/templates/home.html
@@ -10,25 +10,26 @@
 />
 
 <!-- Header Section -->
-<section class="hero-section py-5 text-white text-center">
+<section class="hero-section py-3 text-white text-center" style="padding: 1.5rem 0;">
   <div class="container">
     <img
       src="{{ url_for('static', filename='img/logo_Omnicrobe_3_resize.png') }}"
       alt="Omnicrobe"
-      class="logo mb-4"
+      class="logo mb-3"
+      style="max-width: 100px;"
     />
-    <h1 class="display-4 font-weight-bold mb-3">
+    <h1 class="display-6 font-weight-bold mb-2" style="font-size: 1.8rem;">
       Welcome to HoloOligo Database
     </h1>
-    <p class="description mx-auto">
+    <p class="description mx-auto" style="font-size: 0.9rem; max-width: 500px;">
       Explore comprehensive information on milk oligosaccharides across
-      mammalian species. Discover their roles in nutrition, gut health, and
-      immune modulation through curated data from scientific sources.
+      mammalian species.
     </p>
-    <a href="about" class="btn btn-info btn-lg mt-3">Learn More</a>
+    <a href="about" class="btn btn-info btn-sm mt-2">Learn More</a>
   </div>
 </section>
 
+
 <!-- Data Visualization Section -->
 <section class="data-overview my-5">
   <div class="container">
-- 
GitLab


From 48535d98f577f887b85470d8584a8376c3987db6 Mon Sep 17 00:00:00 2001
From: "hajar.bouamout" <hajar.bouamout@inrae.fr>
Date: Wed, 12 Feb 2025 10:50:41 +0100
Subject: [PATCH 33/51] =?UTF-8?q?Am=C3=A9lioration=20de=20la=20page=20de?=
 =?UTF-8?q?=20recherche=20simple=20:=20mise=20=C3=A0=20jour=20du=20style?=
 =?UTF-8?q?=20de=20l'interface=20utilisateur,=20correction=20du=20bouton?=
 =?UTF-8?q?=20Search=20qui=20est=20maintenant=20fonctionnel,=20ajout=20de?=
 =?UTF-8?q?=20liens=20permettant=20de=20rediriger=20vers=20PubMed=20ou=20d?=
 =?UTF-8?q?'autres=20sources=20depuis=20les=20r=C3=A9sultats=20de=20la=20r?=
 =?UTF-8?q?echerche.?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 static/css/research.css |  46 +++++++++++-
 static/js/research.js   | 150 +++++++++++++++++++++++++++++-----------
 templates/research.html |  22 +++---
 3 files changed, 163 insertions(+), 55 deletions(-)

diff --git a/static/css/research.css b/static/css/research.css
index 4511e66..4e2627e 100644
--- a/static/css/research.css
+++ b/static/css/research.css
@@ -28,6 +28,36 @@ body {
   overflow-x: auto;
 }
 
+/* HEADER STYLES */
+.header {
+  text-align: center;
+  padding: 2rem;
+  background: linear-gradient(145deg, #274757, #0077cc);
+  color: white;
+  border-radius: 8px;
+  box-shadow: 0 3px 6px rgba(0, 0, 0, 0.15);
+  margin-bottom: 20px;
+}
+
+.header h1 {
+  font-size: 2rem;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  gap: 10px;
+}
+
+.header h1 i {
+  font-size: 1.5rem;
+  color: #f1c40f;
+}
+
+.header p {
+  font-size: 1.1rem;
+  opacity: 0.9;
+}
+
+
 .main-content2 {
   padding: 2rem;
   background: #ffffff;
@@ -45,14 +75,14 @@ body {
   align-items: center;
   gap: 1rem;
   padding: 1.5rem;
-  background: #8eb1b5;
+  background: linear-gradient(145deg, #274757, #0077cc);
   border-radius: 10px;
   box-shadow: 0 2px 8px rgba(0, 0, 0, 0.05);
   position: relative;
 }
 
 .search-bar2 span {
-  color: #21517A;
+  color: white;
   font-weight: 500;
   white-space: nowrap;
 }
@@ -90,6 +120,17 @@ body {
   box-shadow: 0 0 0 2px rgba(52, 152, 219, 0.1);
 }
 
+
+.search-btn {
+  background-color: #d0d4e4;
+  padding: 0.6rem 1.5rem;
+  border-radius: 30px;
+  font-weight: bold;
+  font-size: 1rem;
+  transition: all 0.3s ease-in-out;
+  box-shadow: 2px 2px 10px rgba(0, 0, 0, 0.15);
+}
+
 /* Autocomplete */
 .autocomplete-box {
   position: absolute;
@@ -271,3 +312,4 @@ body {
 .search-icon i {
   font-size: 40px;
 }
+
diff --git a/static/js/research.js b/static/js/research.js
index aed172d..b086381 100644
--- a/static/js/research.js
+++ b/static/js/research.js
@@ -17,14 +17,16 @@ document.addEventListener("DOMContentLoaded", function () {
   const suggestionBox = document.getElementById("autocomplete-suggestions");
   const resultsTable = document.getElementById("results-table");
   const tableSearchInput = document.getElementById("table-search-input");
+  const searchButton = document.querySelector(".search-btn");
+  
 
   // Error handling for missing DOM elements
-  if (!searchInput || !searchType || !suggestionBox || !resultsTable) {
+  if (!searchInput || !searchType || !suggestionBox || !resultsTable || !searchButton) {
     console.error("One or more DOM elements are missing!");
     return;
   }
 
-  let activeIndex = -1;
+  // let activeIndex = -1;
   let table; // DataTable instance declaration
 
   // Dynamic Script Loading
@@ -72,6 +74,9 @@ document.addEventListener("DOMContentLoaded", function () {
       ordering: true,
       info: true,
       dom: '<"top"f>rt<"bottom"ip>',
+      language: {
+        search: "Filter with : "
+      },
       buttons: [
         {
           extend: "colvis",
@@ -105,7 +110,11 @@ document.addEventListener("DOMContentLoaded", function () {
           title: "Lactation Stage",
           defaultContent: "N/A",
         },
-        { data: "source", title: "Source", defaultContent: "N/A" },
+        { data: "source", title: "Source",
+          render: (id) => `<a href="/source/${id}">${id}</a>`,
+          defaultContent: "N/A",
+
+        },
         {
           data: "id",
           title: "Details",
@@ -130,6 +139,14 @@ document.addEventListener("DOMContentLoaded", function () {
         uniqueResults.push(row);
       }
     });
+    //Generalization of the previous code, because the unique key was based on specific columns (doesnt work)
+    // data.forEach((row) => {
+    //   const rowKey = keys.map((key) => row[key]).join("|"); // Dynamic generation
+    //   if (!seen.has(rowKey)) {
+    //     seen.add(rowKey);
+    //     uniqueResults.push(row);
+    //   }
+    // });
 
     return uniqueResults;
   }
@@ -158,45 +175,109 @@ document.addEventListener("DOMContentLoaded", function () {
 
       return data.results || [];
     } catch (error) {
-      console.error("Error API :", error);
+      console.error("Error API:", error);
       return [];
     }
   }
+
+  //Display Suggestions
+
   async function displaySuggestions(query) {
+    if (!query) {
+      suggestionBox.innerHTML = "";
+      return;
+    }
+
+    const concept = searchType.value;
+    const suggestions = await fetchEntities(concept);
+
     suggestionBox.innerHTML = "";
 
+    if (query.length >= 1) {
+      const filteredResults = suggestions
+        .filter((item) => {
+          const name = (item.name || item.form || "").toLowerCase();
+          return (
+            name.startsWith(query.toLowerCase()) ||
+            name.includes(query.toLowerCase())
+          );
+        })
+        .slice(0, 5);
+
+      if (filteredResults.length > 0) {
+        filteredResults.forEach((item) => {
+          const div = document.createElement("div");
+          div.textContent = item.name || item.form;
+          div.dataset.id = item.identifier;
+          div.onclick = () => selectSuggestion(item);
+          suggestionBox.appendChild(div);
+        });
+      } else {
+        suggestionBox.innerHTML = '<div class="no-result">No suggestions</div>';
+      }
+    }
+  }
+
+  // Handle Search
+  async function handleSearch() {
+    const query = searchInput.value.trim();
+    if (!query) {
+      alert("Please enter a search term");
+      return;
+    }
+
     const concept = searchType.value;
+    const entities = await fetchEntities(concept);
+    const filteredEntities = entities.filter(item => {
+      const name = (item.name || item.form || "").toLowerCase();
+      return name.startsWith(query.toLowerCase()) || name.includes(query.toLowerCase());
+    });
+    
+    if (filteredEntities.length > 0) {
+      const firstMatch = filteredEntities[0];
+      await fetchRelations(firstMatch.identifier);
+      suggestionBox.innerHTML = ""; // Clear suggestions after search
+    } else {
+      if (table) {
+        table.clear().draw();
+      }
+      alert("No results found for your search");
+    }
+  }
+
+
+  // Event Listeners
+  searchInput.addEventListener("input", function() {
+    const query = this.value.trim();
     if (query.length >= 1) {
-        const suggestions = await fetchEntities(concept, query);
-
-        const filteredResults = suggestions.filter(item => {
-            const name = (item.name || item.form || "").toLowerCase();
-            return name.startsWith(query.toLowerCase()) || name.includes(query.toLowerCase());
-        }).slice(0, 5);
-
-        if (filteredResults.length > 0) {
-            filteredResults.forEach((item) => {
-                const div = document.createElement("div");
-                div.textContent = item.name || item.form;
-                div.dataset.id = item.identifier;
-                div.onclick = () => selectSuggestion(item);
-                suggestionBox.appendChild(div);
-            });
-        } else {
-            suggestionBox.innerHTML = '<div class="no-result">No suggestions</div>';
-        }
+      displaySuggestions(query);
+    } else {
+      suggestionBox.innerHTML = "";
     }
-}
-  searchInput.addEventListener("input", function () {
-    setTimeout(() => displaySuggestions(this.value), 100);
   });
 
+  // Hide suggestions when clicking outside
+  document.addEventListener("click", function(event) {
+    if (!suggestionBox.contains(event.target) && event.target !== searchInput) {
+      suggestionBox.innerHTML = "";
+    }
+  });
+
+  searchButton.addEventListener("click", handleSearch);
+
+  searchInput.addEventListener("keypress", function(event) {
+    if (event.key === "Enter") {
+      event.preventDefault();
+      handleSearch();
+    }
+  });
 
   if (tableSearchInput) {
     tableSearchInput.addEventListener("input", function () {
-        table.search(this.value).draw();
+      table.search(this.value).draw();
     });
-}
+  }
+
 
   // Entity Selection and Relation Fetching
   // Handles selection of autocomplete suggestions and retrieves related data
@@ -212,19 +293,6 @@ document.addEventListener("DOMContentLoaded", function () {
     await fetchRelations(item.identifier);
   }
 
-  // Listen to input to display suggestions
-  searchInput.addEventListener("input", async function () {
-    const query = this.value;
-    const concept = searchType.value;
-
-    if (query.length > 1) {
-      // Display suggestions from the first letter
-      const entities = await fetchEntities(concept);
-      displaySuggestions(entities, query);
-    } else {
-      suggestionBox.innerHTML = "";
-    }
-  });
 
   // Request to retrieve an entity's relations
   async function fetchRelations(entityId) {
@@ -315,3 +383,5 @@ document.addEventListener("DOMContentLoaded", function () {
   // Start the initialization process
   initialize().catch(console.error);
 });
+
+
diff --git a/templates/research.html b/templates/research.html
index 8a3f122..50f3f9a 100644
--- a/templates/research.html
+++ b/templates/research.html
@@ -24,19 +24,13 @@
 <!--Main Content Structure-->
 <body>
   <div class="main-content2">
-    <section class="info-section">
-      <div class="info-box">
-        <div class="search-icon">
-          <i class="fas fa-search"></i>
-        </div>
-        <h2>Simple Search</h2>
-        <p>
-          Quickly find oligosaccharides by name, type, species, or lactation
-          stage. Perfect for direct queries when you know what you're looking
-          for.
-        </p>
-      </div>
-    </section>
+
+    <header class="header">
+      <h1><i class="fas fa-search"></i> Simple Search</h1>
+      <p>Quickly find oligosaccharides by name, type, species, sample type or lactation
+        stage. Perfect for direct queries when you know what you're looking
+        for.</p>
+    </header>
 
     <!-- Simple Search Form -->
     <section id="simple-search-section" class="search-section">
@@ -54,6 +48,7 @@
           id="search-input"
           placeholder="Enter a keyword to begin..."
         />
+        
         <div id="autocomplete-suggestions" class="autocomplete-box"></div>
         <button class="search-btn">Search</button>
       </div>
@@ -79,6 +74,7 @@
         </tbody>
       </table>
     </section>
+    
   </div>
 
   <!-- Scripts jQuery and DataTables -->
-- 
GitLab


From 43ed1230c796902cc1b4fe794b2d402bbca1a47b Mon Sep 17 00:00:00 2001
From: Sandra Derozier <sandra.derozier@inrae.fr>
Date: Sun, 16 Feb 2025 22:21:52 +0100
Subject: [PATCH 34/51] #8 - API Get entity

---
 __init__.py           |  6 ++++
 database.py           | 72 +++++++++++++++++++++++++++++++++++++++++++
 static/js/research.js | 20 ++++++------
 3 files changed, 88 insertions(+), 10 deletions(-)

diff --git a/__init__.py b/__init__.py
index ba6092b..3897f25 100644
--- a/__init__.py
+++ b/__init__.py
@@ -451,6 +451,12 @@ def get_relations():
     id_entity = request.args.get('id_entity', None)   # id_entity = 'oligo_149'
     return jsonify(relations(app, conn, id_entity))
 
+@app.route('/_get/entity')
+def get_entity():
+    type_entity = request.args.get('type_entity', None)
+    id_entity = request.args.get('id_entity', None)
+    return jsonify(entity(app, conn, type_entity, id_entity))
+
 # API
 source_choices = ["pubmed", "CIRM-BIA", "CIRM-CFBP", "CIRM-Levures", "dsmz", "genbank"]
 qps_choices = ["yes", "no", "true", "false"]
diff --git a/database.py b/database.py
index ee00e2b..d0ba48e 100644
--- a/database.py
+++ b/database.py
@@ -161,6 +161,78 @@ def relations(app, conn, id_entity):
         dico['totalResults'] = len(dico['results'])
         return dico
 
+# Get entity information: /get/info_entity
+def entity(app, conn, type_entity, id_entity):
+    conn = get_db(app)
+    if conn != None:
+        cursor = conn.cursor()
+        try:
+            # print("SELECT co_fk_concept_id, array_agg(distinct(c_identifier)) as identifiers, \
+            #                 array_agg(distinct(cn_name)) as name, array_agg(distinct(co_form_concept)) as form, \
+            #                 array_agg(distinct(t_fk_document_id)) as docs \
+            #                 FROM concept, concept_name, concept_occurrence, text \
+            #                 WHERE c_identifier = '"+id_entity+"' \
+            #                 AND c_id = cn_fk_concept_id \
+            #                 AND c_id = co_fk_concept_id \
+            #                 AND co_fk_text_id = t_id \
+            #                 GROUP BY co_fk_concept_id")
+
+            cursor.execute("SELECT co_fk_concept_id, array_agg(distinct(c_identifier)) as identifiers, \
+                            array_agg(distinct(cn_name)) as name, array_agg(distinct(co_form_concept)) as form, \
+                            array_agg(distinct(t_fk_document_id)) as docs \
+                            FROM concept, concept_name, concept_occurrence, text \
+                            WHERE c_identifier = %s \
+                            AND c_id = cn_fk_concept_id \
+                            AND c_id = co_fk_concept_id \
+                            AND co_fk_text_id = t_id \
+                            GROUP BY co_fk_concept_id", (id_entity,))
+        except Exception as err:
+            print_psycopg2_exception(err)
+        dico = dict()
+        for row in cursor.fetchall():
+            dico['identifier'] = row[1][0]
+            dico['name'] = row[2][0]
+            dico['occurrence_text'] = row[3]
+            dico['documents'] = row[4]
+
+        try:
+            # print("SELECT distinct(co_type), array_agg(distinct(cn_name)) \
+            #                 FROM concept_name, concept, concept_occurrence, relation_occurrence \
+            #                 WHERE cn_fk_concept_id = c_id \
+            #                 AND c_id = co_fk_concept_id \
+            #                 AND co_id = ro_fk_concept_occurrence_id \
+            #                 AND ro_group IN \
+            #                 (SELECT ro_group \
+            #                  FROM concept, concept_occurrence, relation_occurrence \
+            #                  WHERE c_id = co_fk_concept_id \
+            #                  AND co_id = ro_fk_concept_occurrence_id \
+            #                  AND c_identifier = '"+id_entity+"') \
+            #                 AND co_type != '"+type_entity+"' \
+            #                 GROUP BY co_type")
+            
+            cursor.execute("SELECT distinct(co_type), array_agg(distinct(cn_name)) \
+                            FROM concept_name, concept, concept_occurrence, relation_occurrence \
+                            WHERE cn_fk_concept_id = c_id \
+                            AND c_id = co_fk_concept_id \
+                            AND co_id = ro_fk_concept_occurrence_id \
+                            AND ro_group IN \
+                            (SELECT ro_group \
+                             FROM concept, concept_occurrence, relation_occurrence \
+                             WHERE c_id = co_fk_concept_id \
+                             AND co_id = ro_fk_concept_occurrence_id \
+                             AND c_identifier = %s) \
+                            AND co_type != %s \
+                            GROUP BY co_type", (id_entity, type_entity))
+        except Exception as err:
+            print_psycopg2_exception(err)
+        
+        for row in cursor.fetchall():
+            dico[row[0]] = row[1]
+
+        cursor.close()
+        # print(dico)
+        return dico
+
 # Check source format
 def check_source(s):
     sources = ['PubMed', 'GenBank', 'DSMZ', 'CIRM-BIA', 'CIRM-Levures', 'CIRM-CFBP']
diff --git a/static/js/research.js b/static/js/research.js
index b086381..002b58b 100644
--- a/static/js/research.js
+++ b/static/js/research.js
@@ -1,14 +1,14 @@
 //Test Sandra
-// document.addEventListener("DOMContentLoaded", function () {
-//     const apiUrl = '/_get/relations?id_entity=oligo_149';   // oligo_149 // OST01 // ncbi:9615 // LS05 // ST01
-//     fetch(apiUrl)
-//         .then((response) => response.json())
-//         .then((data) => {
-//             console.log("Data received from the API:", data);
-//         })
-//         .catch((error) => {
-//         console.error("Error fetching the JSON data:", error);
-//         });})
+document.addEventListener("DOMContentLoaded", function () {
+    const apiUrl = '/_get/entity?type_entity=Oligosaccharide_name&id_entity=oligo_149';   // Oligosaccharide_name&oligo_149 // Species&ncbi:9913 // Sample_type&ST02
+    fetch(apiUrl)
+        .then((response) => response.json())
+        .then((data) => {
+            console.log("Data received from the API:", data);
+        })
+        .catch((error) => {
+        console.error("Error fetching the JSON data:", error);
+        });})
 
 document.addEventListener("DOMContentLoaded", function () {
   // DOM Element Selection
-- 
GitLab


From c3e100ecc25970fc044d340936a71c02338b6c9a Mon Sep 17 00:00:00 2001
From: "hajar.bouamout" <hajar.bouamout@inrae.fr>
Date: Mon, 24 Feb 2025 15:23:57 +0100
Subject: [PATCH 35/51] =?UTF-8?q?Am=C3=A9lioration=20de=20l'initialisation?=
 =?UTF-8?q?=20et=20de=20l'affichage=20des=20r=C3=A9sultats?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Remplacement du chargement en chaîne des scripts par une itération sur un tableau, ajout du script DataTables RowGroup.

 Mise à jour de la configuration de DataTable : utilisation de 'Bfrtip' et ajout du callback createdRow pour fusionner et masquer les lignes similaires.

Modification de la colonne Details pour utiliser row identifier et générer un lien vers sheet.

Refactorisation de displayResults pour extraire l'entrée Oligosaccharide_name et définir correctement l'identifiant.

 Maintien des fonctionnalités d'autocomplétion et de déduplication des lignes.
---
 static/js/research.js | 334 +++++++++++++++++++++++++-----------------
 1 file changed, 198 insertions(+), 136 deletions(-)

diff --git a/static/js/research.js b/static/js/research.js
index 002b58b..d8d511d 100644
--- a/static/js/research.js
+++ b/static/js/research.js
@@ -1,14 +1,14 @@
 //Test Sandra
-document.addEventListener("DOMContentLoaded", function () {
-    const apiUrl = '/_get/entity?type_entity=Oligosaccharide_name&id_entity=oligo_149';   // Oligosaccharide_name&oligo_149 // Species&ncbi:9913 // Sample_type&ST02
-    fetch(apiUrl)
-        .then((response) => response.json())
-        .then((data) => {
-            console.log("Data received from the API:", data);
-        })
-        .catch((error) => {
-        console.error("Error fetching the JSON data:", error);
-        });})
+// document.addEventListener("DOMContentLoaded", function () {
+//     const apiUrl = '/_get/relations?id_entity=oligo_149';   // oligo_149 // OST01 // ncbi:9615 // LS05 // ST01
+//     fetch(apiUrl)
+//         .then((response) => response.json())
+//         .then((data) => {
+//             console.log("Data received from the API:", data);
+//         })
+//         .catch((error) => {
+//         console.error("Error fetching the JSON data:", error);
+//         });})
 
 document.addEventListener("DOMContentLoaded", function () {
   // DOM Element Selection
@@ -34,34 +34,25 @@ document.addEventListener("DOMContentLoaded", function () {
 
   function loadScripts() {
     return new Promise((resolve) => {
-      const jqueryScript = document.createElement("script");
-      jqueryScript.src = "https://code.jquery.com/jquery-3.6.0.min.js";
-      jqueryScript.onload = () => {
-        const dataTableScript = document.createElement("script");
-        dataTableScript.src =
-          "https://cdn.datatables.net/1.13.6/js/jquery.dataTables.min.js";
-        dataTableScript.onload = () => {
-          const buttonsScript = document.createElement("script");
-          buttonsScript.src =
-            "https://cdn.datatables.net/buttons/2.3.6/js/dataTables.buttons.min.js";
-          buttonsScript.onload = () => {
-            const colVisScript = document.createElement("script");
-            colVisScript.src =
-              "https://cdn.datatables.net/buttons/2.3.6/js/buttons.colVis.min.js";
-            colVisScript.onload = () => {
-              const csvScript = document.createElement("script");
-              csvScript.src =
-                "https://cdn.datatables.net/buttons/2.3.6/js/buttons.html5.min.js";
-              csvScript.onload = resolve;
-              document.head.appendChild(csvScript);
-            };
-            document.head.appendChild(colVisScript);
-          };
-          document.head.appendChild(buttonsScript);
+      const scripts = [
+        "https://code.jquery.com/jquery-3.6.0.min.js",
+        "https://cdn.datatables.net/1.13.6/js/jquery.dataTables.min.js",
+        "https://cdn.datatables.net/buttons/2.3.6/js/dataTables.buttons.min.js",
+        "https://cdn.datatables.net/buttons/2.3.6/js/buttons.colVis.min.js",
+        "https://cdn.datatables.net/buttons/2.3.6/js/buttons.html5.min.js",
+        "https://cdn.datatables.net/rowgroup/1.4.1/js/dataTables.rowGroup.min.js"
+      ];
+
+      let loaded = 0;
+      scripts.forEach(src => {
+        const script = document.createElement("script");
+        script.src = src;
+        script.onload = () => {
+          loaded++;
+          if (loaded === scripts.length) resolve();
         };
-        document.head.appendChild(dataTableScript);
-      };
-      document.head.appendChild(jqueryScript);
+        document.head.appendChild(script);
+      });
     });
   }
 
@@ -69,63 +60,128 @@ document.addEventListener("DOMContentLoaded", function () {
   // Configures the results table with advanced features
   function initializeDataTable() {
     table = $("#results-table").DataTable({
-      paging: true,
-      searching: true,
-      ordering: true,
-      info: true,
-      dom: '<"top"f>rt<"bottom"ip>',
-      language: {
-        search: "Filter with : "
-      },
-      buttons: [
-        {
-          extend: "colvis",
-          text: "Gérer les colonnes",
-        },
-        {
-          extend: "csvHtml5",
-          text: "Télécharger CSV",
-          filename: "search_results",
-          title: "Search Results",
-          exportOptions: {
-            columns: ":visible",
-          },
-        },
-      ],
-      columns: [
-        {
-          data: "oligosaccharide_name",
-          title: "Oligosaccharide Name",
-          defaultContent: "N/A",
-        },
-        {
-          data: "oligosaccharide_type",
-          title: "Oligosaccharide Type",
-          defaultContent: "N/A",
+        paging: true,
+        searching: true,
+        ordering: true,
+        info: true,
+        dom: 'Bfrtip',
+        language: {
+            search: "Filter with : "
         },
-        { data: "sample_type", title: "Sample Type", defaultContent: "N/A" },
-        { data: "species", title: "Species", defaultContent: "N/A" },
-        {
-          data: "lactation_stage",
-          title: "Lactation Stage",
-          defaultContent: "N/A",
-        },
-        { data: "source", title: "Source",
-          render: (id) => `<a href="/source/${id}">${id}</a>`,
-          defaultContent: "N/A",
-
-        },
-        {
-          data: "id",
-          title: "Details",
-          render: (id) => `<a href="/details/${id}">View</a>`,
-          defaultContent: "N/A",
+        createdRow: function(row, data, dataIndex) {
+            let rowsToHide = new Set();
+            
+            let allData = table.data().toArray();
+            
+            allData.forEach((compareData, compareIndex) => {
+                if (compareIndex <= dataIndex) return; 
+                
+                let differences = 0;
+                let differentColumn = '';
+                
+                ['oligosaccharide_name', 'oligosaccharide_type', 'sample_type', 'species', 'lactation_stage', 'source'].forEach(column => {
+                    if (data[column] !== compareData[column] && 
+                        data[column] !== 'N/A' && compareData[column] !== 'N/A') {
+                        differences++;
+                        differentColumn = column;
+                    }
+                });
+                
+                if (differences === 1) {
+                    rowsToHide.add(compareIndex);
+                    
+                    let originalCell = $('td', row).eq(getColumnIndex(differentColumn));
+                    let currentValue = data[differentColumn];
+                    let compareValue = compareData[differentColumn];
+                    
+                    let combinedValue = [currentValue, compareValue]
+                        .filter((v, i, a) => v !== 'N/A' && a.indexOf(v) === i)
+                        .join(' / ');
+                    
+                    originalCell.html(combinedValue);
+                }
+            });
+            
+            if (rowsToHide.has(dataIndex)) {
+                $(row).hide();
+            }
         },
-      ],
-      order: [[0, "asc"]],
+        buttons: [
+            {
+                extend: "colvis",
+                text: "Gérer les colonnes",
+            },
+            {
+                extend: "csvHtml5",
+                text: "Télécharger CSV",
+                filename: "search_results",
+                title: "Search Results",
+                exportOptions: {
+                    columns: ":visible",
+                }
+            }
+        ],
+        columns: [
+            {
+                data: "oligosaccharide_name",
+                title: "Oligosaccharide Name",
+                defaultContent: "N/A"
+            },
+            {
+                data: "oligosaccharide_type",
+                title: "Oligosaccharide Type",
+                defaultContent: "N/A"
+            },
+            { 
+                data: "sample_type", 
+                title: "Sample Type", 
+                defaultContent: "N/A" 
+            },
+            { 
+                data: "species", 
+                title: "Species", 
+                defaultContent: "N/A" 
+            },
+            {
+                data: "lactation_stage",
+                title: "Lactation Stage",
+                defaultContent: "N/A"
+            },
+            { 
+                data: "source", 
+                title: "Source",
+                render: (id) => `<a href="/source/${id}">${id}</a>`,
+                defaultContent: "N/A"
+            },
+            {
+                data: null,
+                title: "Details",
+                render: function(data, type, row) {
+                    if (row.identifier) {
+                        return `<a href="/sheet?type_entity=Oligosaccharide_name&id_entity=${encodeURIComponent(row.identifier)}">View</a>`;
+                    }
+                    return "N/A";
+                },
+                defaultContent: "N/A"
+            }
+          
+        ],
+        order: [[0, "asc"]]
     });
-  }
-
+}
+
+
+function getColumnIndex(columnName) {
+    const columnMapping = {
+        'oligosaccharide_name': 0,
+        'oligosaccharide_type': 1,
+        'sample_type': 2,
+        'species': 3,
+        'lactation_stage': 4,
+        'source': 5
+    };
+    return columnMapping[columnName] || 0;
+}
   // Data Deduplication
   // Removes duplicate rows from search results
   function removeDuplicateRows(data) {
@@ -139,14 +195,7 @@ document.addEventListener("DOMContentLoaded", function () {
         uniqueResults.push(row);
       }
     });
-    //Generalization of the previous code, because the unique key was based on specific columns (doesnt work)
-    // data.forEach((row) => {
-    //   const rowKey = keys.map((key) => row[key]).join("|"); // Dynamic generation
-    //   if (!seen.has(rowKey)) {
-    //     seen.add(rowKey);
-    //     uniqueResults.push(row);
-    //   }
-    // });
+  
 
     return uniqueResults;
   }
@@ -318,60 +367,73 @@ document.addEventListener("DOMContentLoaded", function () {
   // Processes and displays search results in the DataTable
   function displayResults(data) {
     if (!table) {
-      console.error("DataTable not initialized!");
-      return;
+        console.error("DataTable not initialized!");
+        return;
     }
 
     if (!data?.results) {
-      console.error("Invalid API response:", data);
-      return;
+        console.error("Invalid API response:", data);
+        return;
     }
 
     const flatResults = [];
 
     data.results.forEach((group) => {
-      Object.entries(group).forEach(([groupId, groupData]) => {
-        if (Array.isArray(groupData) && groupData.length > 0) {
-          let formattedItem = {
-            oligosaccharide_name: "N/A",
-            oligosaccharide_type: "N/A",
-            sample_type: "N/A",
-            species: "N/A",
-            lactation_stage: "N/A",
-            source: "N/A",
-            id: groupId,
-          };
-
-          groupData.forEach((item) => {
-            if (item && item.type) {
-              if (item.type === "Oligosaccharide_name")
-                formattedItem.oligosaccharide_name = item.name || "Unknown";
-              if (item.type === "Oligosaccharide_type")
-                formattedItem.oligosaccharide_type = item.name || "Unknown";
-              if (item.type === "Sample_type")
-                formattedItem.sample_type = item.name || "Unknown";
-              if (item.type === "Species")
-                formattedItem.species = item.name || "Unknown";
-              if (item.type === "Lactation_stage")
-                formattedItem.lactation_stage = item.name || "Unknown";
-              formattedItem.source = item.source || "Unknown";
+        Object.entries(group).forEach(([groupId, groupData]) => {
+            if (Array.isArray(groupData) && groupData.length > 0) {
+                let formattedItem = {
+                    oligosaccharide_name: "N/A",
+                    oligosaccharide_type: "N/A",
+                    sample_type: "N/A",
+                    species: "N/A",
+                    lactation_stage: "N/A",
+                    source: "N/A",
+                    identifier: null
+                };
+
+                const oligoEntry = groupData.find(item => 
+                    item.type === "Oligosaccharide_name"
+                );
+                
+                if (oligoEntry) {
+                    formattedItem.oligosaccharide_name = oligoEntry.name || "N/A";
+                    formattedItem.identifier = oligoEntry.id; // Utiliser le champ 'id' au lieu de 'identifier'
+                }
+
+                groupData.forEach((item) => {
+                    if (item && item.type) {
+                        switch(item.type) {
+                            case "Oligosaccharide_type":
+                                formattedItem.oligosaccharide_type = item.name || "N/A";
+                                break;
+                            case "Sample_type":
+                                formattedItem.sample_type = item.name || "N/A";
+                                break;
+                            case "Species":
+                                formattedItem.species = item.name || "N/A";
+                                break;
+                            case "Lactation_stage":
+                                formattedItem.lactation_stage = item.name || "N/A";
+                                break;
+                        }
+                        if (item.source) {
+                            formattedItem.source = item.source;
+                        }
+                    }
+                });
+
+                flatResults.push(formattedItem);
             }
-          });
-
-          flatResults.push(formattedItem);
-        }
-      });
+        });
     });
 
     const uniqueResults = removeDuplicateRows(flatResults);
 
-    console.log("Final unique data to display in DataTables:", uniqueResults);
-
     table.clear();
     table.rows.add(uniqueResults);
     table.draw();
     document.getElementById("results-section").style.display = "block";
-  }
+}
 
   // Initialization
   // Loads scripts and initializes the page functionality
-- 
GitLab


From ad992da90866fedad09648190f762438334dc813 Mon Sep 17 00:00:00 2001
From: "hajar.bouamout" <hajar.bouamout@inrae.fr>
Date: Mon, 24 Feb 2025 15:41:16 +0100
Subject: [PATCH 36/51] =?UTF-8?q?Am=C3=A9lioration=20du=20chargement=20et?=
 =?UTF-8?q?=20de=20l'affichage=20des=20donn=C3=A9es=20d'entit=C3=A9?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Ajout de la fonction fetchIdentifier pour récupérer l'identifiant correct en fonction du nom de l'entité.

Mise à jour de initializeApp pour utiliser fetchIdentifier et afficher la section correspondante.

Ajout de commentaires JSDoc pour documenter les fonctions et améliorer la lisibilité du code.

Refactorisation de la gestion des paramètres d'URL et des appels API.
---
 static/js/sheet.js | 549 ++++++++++++++++++++++++++++++++++++++-------
 1 file changed, 468 insertions(+), 81 deletions(-)

diff --git a/static/js/sheet.js b/static/js/sheet.js
index caa1e20..1d3feb9 100644
--- a/static/js/sheet.js
+++ b/static/js/sheet.js
@@ -1,71 +1,357 @@
+// Event listener for DOMContentLoaded ensures that the app is initialized
+// only after the complete HTML document has been loaded and parsed.
 document.addEventListener("DOMContentLoaded", function () {
-  // Initial setup
   initializeApp();
 });
 
+/**
+ * Fetch the correct identifier for a given entity type and name.
+ * 
+ * This function sends a request to retrieve entities based on the provided type.
+ * It then searches through the results to find a case-insensitive match for the given entity name.
+ * 
+ * @param {string} typeEntity - The type or concept of the entity to be fetched.
+ * @param {string} entityName - The name of the entity to be matched.
+ * @returns {Promise<string|null>} - A promise resolving to the identifier if found, or null if not.
+ */
+function fetchIdentifier(typeEntity, entityName) {
+  return fetch(`/_get/entities?concept=${typeEntity}`)
+    .then((response) => response.json())
+    .then((data) => {
+      console.log("🔍 Received entities:", data);
+
+      // Check if the data contains a valid results array
+      if (data && data.results && Array.isArray(data.results)) {
+        // Find a matching entity by comparing names (case-insensitive)
+        const match = data.results.find(
+          (entity) => entity.name.toLowerCase() === entityName.toLowerCase()
+        );
+
+        if (match) {
+          console.log(`✅ Found Identifier for ${entityName}:`, match.identifier);
+          return match.identifier; // Return the correct identifier if a match is found
+        }
+      }
+
+      // Log a warning if no matching identifier is found
+      console.warn(`⚠️ No identifier found for: ${entityName}`);
+      return null;
+    })
+    .catch((error) => {
+      // Log any errors encountered during the fetch process
+      console.error("❌ Error fetching identifier:", error);
+      return null;
+    });
+}
+
+/**
+ * Initializes the application by extracting query parameters and loading entity data.
+ * 
+ * It retrieves 'type_entity' and 'id_entity' from the URL query parameters. If both are present,
+ * it attempts to fetch a corrected identifier for the given entity. Once the identifier is confirmed,
+ * it loads the entity data and displays the correct section.
+ */
 function initializeApp() {
-  const { entityId, entityType } = getURLParams();
-  if (entityId && entityType) {
-    loadEntityData(entityId, entityType);
+  const typeEntity = getQueryParam("type_entity");
+  let idEntity = getQueryParam("id_entity");
+
+  console.log("🔍 Type Entity:", typeEntity);
+  console.log("🔍 ID Entity (before fetching correct identifier):", idEntity);
+
+  if (typeEntity && idEntity) {
+    fetchIdentifier(typeEntity, idEntity)
+      .then((correctIdentifier) => {
+        if (correctIdentifier) {
+          idEntity = correctIdentifier; 
+        }
+
+        console.log("🔍 Final ID Entity used for API call:", idEntity);
+        loadEntityData(typeEntity, idEntity);
+        showCorrectSection(typeEntity);
+      })
+      .catch((error) => {
+        // If there is an error fetching the identifier, load the entity data using the original idEntity
+        console.error("❌ Error retrieving correct identifier:", error);
+        loadEntityData(typeEntity, idEntity);
+        showCorrectSection(typeEntity);
+      });
   }
 }
 
-function getURLParams() {
+/**
+ * Extracts a specific query parameter from the current window URL.
+ * 
+ * @param {string} param - The name of the query parameter to retrieve.
+ * @returns {string|null} - The value of the parameter or null if not present.
+ */
+function getQueryParam(param) {
   const urlParams = new URLSearchParams(window.location.search);
-  return {
-    entityId: urlParams.get("entity_id"),
-    entityType: urlParams.get("entity_type")
+  return urlParams.get(param);
+}
+
+/**
+ * Displays the correct content section based on the entity type.
+ * 
+ * The mapping between entity types and section identifiers is predefined.
+ * If a corresponding section exists, it toggles its visibility.
+ * 
+ * @param {string} entityType - The type of the entity (e.g., "Oligosaccharide_name", "Species", "Sample_type").
+ */
+function showCorrectSection(entityType) {
+  const sections = {
+    Oligosaccharide_name: "oligo",
+    Species: "species",
+    Sample_type: "samples",
   };
+
+  const sectionToShow = sections[entityType];
+  if (sectionToShow) {
+    toggleSection(sectionToShow);
+  }
 }
 
-// Function to load data for a specific entity
-function loadEntityData(entityId, entityType) {
-  fetch(`/api/sheet/entity/${entityId}?entity_type=${entityType}`)
+/**
+ * Loads entity data from the server based on the entity type and identifier.
+ * 
+ * It makes an API call to retrieve the entity's data and then passes the data to a function
+ * that populates the HTML elements with the returned information.
+ * 
+ * @param {string} typeEntity - The type of the entity.
+ * @param {string} idEntity - The identifier of the entity.
+ */
+function loadEntityData(typeEntity, idEntity) {
+  fetch(`/_get/entity?type_entity=${typeEntity}&id_entity=${idEntity}`)
     .then((response) => response.json())
     .then((data) => {
-      displayEntityData(data, entityType);
+      console.log("🔍 Received data from API:", data); 
+      if (data) {
+        populateEntityData(data, typeEntity);
+      }
     })
-    .catch((error) => console.error("Error fetching data:", error));
+    .catch((error) => {
+      console.error("❌ Error loading data:", error);
+    });
 }
 
-// Function to display entities
-function displayEntityData(data, entityType) {
-  const dataMapping = {
-    oligosaccharide: [
-      { id: "oligo-id", field: "id" },
-      { id: "oligo-name", field: "name" },
-      { id: "oligo-formula", field: "formula" },
-      { id: "oligo-synonyms", field: "synonyms" },
-      { id: "oligo-occurrence-text", field: "occurrence_text" },
-      { id: "oligo-reference-class", field: "reference_class" },
-      { id: "oligo-species", field: "species" },
-      { id: "oligo-mo-type", field: "mo_type" },
-    ],
-    species: [
-      { id: "species-id", field: "id" },
-      { id: "species-name", field: "scientific_name" },
-      { id: "species-occurrences", field: "number_of_occurrences" },
-    ],
-    sample: [
-      { id: "sample-id", field: "id" },
-      { id: "sample-name", field: "scientific_name" },
-      { id: "sample-species", field: "associated_species" },
-    ],
-  };
+/**
+ * Populates the entity data on the page based on the entity type.
+ * 
+ * This function routes the data to the appropriate data population function:
+ * - For "Oligosaccharide_name", it calls populateOligoData.
+ * - For "Species", it calls populateSpeciesData.
+ * - For "Sample_type", it calls populateSampleData.
+ * 
+ * @param {object} data - The data object returned from the API.
+ * @param {string} entityType - The type of the entity.
+ */
+function populateEntityData(data, entityType) {
+  switch (entityType) {
+    case "Oligosaccharide_name":
+      populateOligoData(data);
+      break;
+    case "Species":
+      populateSpeciesData(data);
+      break;
+    case "Sample_type":
+      populateSampleData(data);
+      break;
+  }
+}
+
+/**
+ * Populates the oligosaccharide data on the page.
+ * 
+ * This version of populateOligoData sets basic information, documents,
+ * occurrence text, and adds links for associated Species and Sample types.
+ * 
+ * @param {object} data - The oligosaccharide data from the API.
+ */
+function populateOligoData(data) {
+  // Basic information display
+  document.getElementById("oligo-id").textContent = data.identifier;
+  document.getElementById("oligo-name").textContent = data.name;
+  document.getElementById("oligo-formula").textContent = data.formula;
+  document.getElementById("oligo-synonyms").textContent = data.synonyms;
+
+  // Display documents if available
+  document.getElementById("documents").textContent = data.documents
+    ? data.documents.join(", ")
+    : "";
+
+  // Display text occurrences if available
+  document.getElementById("oligo-occurrence-text").textContent =
+    data.occurrence_text ? data.occurrence_text.join(", ") : "";
+
+  // Add links for associated Species if available
+  if (data.Species && data.Species.length > 0) {
+    const speciesLinks = data.Species.map(
+      (species) =>
+        `<a href="/sheet?type_entity=Species&id_entity=${encodeURIComponent(
+          species
+        )}">${species}</a>`
+    ).join(", ");
+    document.getElementById("oligo-species").innerHTML = speciesLinks;
+  }
+
+  // Add links for associated Sample Types if available
+  if (data.Sample_type && data.Sample_type.length > 0) {
+    const sampleLinks = data.Sample_type.map(
+      (sample) =>
+        `<a href="/sheet?type_entity=Sample_type&id_entity=${encodeURIComponent(
+          sample
+        )}">${sample}</a>`
+    ).join(", ");
+    document.getElementById("sample_type").innerHTML = sampleLinks;
+  }
+  
+  // Display lactation stage if available
+  document.getElementById("lactation_stage").textContent = data.Lactation_stage
+    ? data.Lactation_stage.join(", ")
+    : "";
+
+  // Display MO Type if available
+  document.getElementById("oligo-mo-type").textContent = data.mo_type || "";
+}
+
+/**
+ * Populates species data on the page.
+ * 
+ * This function updates the species section with the species identifier, name, occurrence text,
+ * associated oligosaccharides, sample types, and documents.
+ * 
+ * @param {object} data - The species data from the API.
+ */
+function populateSpeciesData(data) {
+  document.getElementById("species-id").textContent = data.identifier || "N/A";
+  document.getElementById("species-name").textContent = data.name || "N/A";
+  document.getElementById("species-occurrences").textContent =
+    data.occurrence_text ? data.occurrence_text.join(", ") : "N/A";
+
+  // Display associated oligosaccharides if available
+  if (data.Oligosaccharide_name && Array.isArray(data.Oligosaccharide_name)) {
+    document.getElementById("species-oligosaccharides").textContent =
+      data.Oligosaccharide_name.join(", ");
+  } else {
+    document.getElementById("species-oligosaccharides").textContent = "N/A";
+  }
+
+  // Display associated sample types if available
+  if (data.Sample_type && Array.isArray(data.Sample_type)) {
+    document.getElementById("species-sample-type").textContent =
+      data.Sample_type.join(", ");
+  } else {
+    document.getElementById("species-sample-type").textContent = "N/A";
+  }
+
+  // Display associated documents if available
+  document.getElementById("species-documents").textContent = data.documents
+    ? data.documents.join(", ")
+    : "N/A";
+}
+
+/**
+ * Populates sample data on the page.
+ * 
+ * This function updates the sample section with sample identifier, name, breed,
+ * associated species, oligosaccharides, oligosaccharide type, methodology, lactation stage,
+ * documents, and occurrence text.
+ * 
+ * @param {object} data - The sample data from the API.
+ */
+function populateSampleData(data) {
+  document.getElementById("sample-id").textContent = data.identifier || "N/A";
+  document.getElementById("sample-name").textContent = data.name || "N/A";
+
+  // Display Breed information if available
+  const Breed = document.getElementById("breed");
+  if (Breed) {
+    Breed.textContent =
+      data.Breed && Array.isArray(data.Breed) ? data.Breed.join(", ") : "N/A";
+  }
+
+  // Display associated species if available
+  const speciesElement = document.getElementById("sample-species");
+  if (speciesElement) {
+    speciesElement.textContent =
+      data.Species && Array.isArray(data.Species)
+        ? data.Species.join(", ")
+        : "N/A";
+  }
+
+  // Display associated oligosaccharides if available
+  const sampleOligoElement = document.getElementById("sample-oligosaccharides");
+  if (sampleOligoElement) {
+    sampleOligoElement.textContent =
+      data.Oligosaccharide_name && Array.isArray(data.Oligosaccharide_name)
+        ? data.Oligosaccharide_name.join(", ")
+        : "N/A";
+  }
 
-  dataMapping[entityType].forEach(item => {
-    document.getElementById(item.id).textContent = Array.isArray(data[item.field]) ? data[item.field].join(", ") : data[item.field];
-  });
+  // Display oligosaccharide type if available
+  const oligoTypeElement = document.getElementById("sample-oligosaccharide-type");
+  if (oligoTypeElement) {
+    oligoTypeElement.textContent =
+      data.Oligosaccharide_type && Array.isArray(data.Oligosaccharide_type)
+        ? data.Oligosaccharide_type.join(", ")
+        : "N/A";
+  }
+
+  // Display methodology of analysis if available
+  const methodologyElement = document.getElementById("sample-methodology");
+  if (methodologyElement) {
+    methodologyElement.textContent =
+      data.Methodology_of_analysis &&
+      Array.isArray(data.Methodology_of_analysis)
+        ? data.Methodology_of_analysis.join(", ")
+        : "N/A";
+  }
 
-   // 3D image for oligosaccharides structure
-   if (entityType === "oligosaccharide") {
-    const structureImage = document.getElementById("structure-image");
-    structureImage.src = data.Image_URL;
-    structureImage.alt = `${data.name} structure`;
+  // Display lactation stage if available
+  const lactationElement = document.getElementById("sample-lactation-stage");
+  if (lactationElement) {
+    lactationElement.textContent =
+      data.Lactation_stage && Array.isArray(data.Lactation_stage)
+        ? data.Lactation_stage.join(", ")
+        : "N/A";
+  }
+
+  // Display associated documents if available
+  const documentsElement = document.getElementById("sample-documents");
+  if (documentsElement) {
+    documentsElement.textContent = data.documents
+      ? data.documents.join(", ")
+      : "N/A";
+  }
+
+  // Display occurrence text if available
+  const occurrenceElement = document.getElementById("sample-occurrence-text");
+  if (occurrenceElement) {
+    occurrenceElement.textContent =
+      data.occurrence_text && Array.isArray(data.occurrence_text)
+        ? data.occurrence_text.join(", ")
+        : "N/A";
   }
 }
 
-// Section visibility toggle
+/**
+ * Toggles the visibility of content sections.
+ * 
+ * This function hides all sections (elements with the "section" class) and then displays
+ * the section corresponding to the given type.
+ * 
+ * @param {string} sectionType - The identifier of the section to display.
+ */
+window.toggleSection = function (sectionType) {
+  const sections = document.querySelectorAll(".section");
+  sections.forEach((section) => section.classList.add("hidden"));
+
+  const activeSection = document.getElementById(`${sectionType}-section`);
+  if (activeSection) {
+    activeSection.classList.remove("hidden");
+  }
+};
+
+// Duplicate toggleSection function (can be removed if redundant)
 window.toggleSection = function (sectionType) {
   const sections = document.querySelectorAll(".section");
   sections.forEach((section) => section.classList.add("hidden"));
@@ -76,7 +362,12 @@ window.toggleSection = function (sectionType) {
   }
 };
 
-// Function to trigger the download of the CSV file
+/**
+ * Triggers the download of a CSV file containing the provided content.
+ * 
+ * @param {string} content - The CSV string content to be downloaded.
+ * @param {string} filename - The desired filename for the downloaded CSV.
+ */
 function triggerDownload(content, filename) {
   const blob = new Blob([content], { type: "text/csv;charset=utf-8;" });
   const link = document.createElement("a");
@@ -87,21 +378,37 @@ function triggerDownload(content, filename) {
   document.body.removeChild(link);
 }
 
- // Function to convert data to CSV file
- function convertToCSV(data) {
-  const rows = [['Label', 'Value'], ...data];
+/**
+ * Converts an array of data rows into CSV format.
+ * 
+ * Each row is an array where the first element is a label and the second is the value.
+ * Values are escaped appropriately for CSV format.
+ * 
+ * @param {Array[]} data - The data to be converted into CSV.
+ * @returns {string} - The resulting CSV string.
+ */
+function convertToCSV(data) {
+  const rows = [["Label", "Value"], ...data];
   return rows
-    .map(row => row.map(cell => `"${(cell || '').replace(/"/g, '""')}"`).join(','))
-    .join('\n');
+    .map((row) =>
+      row.map((cell) => `"${(cell || "").replace(/"/g, '""')}"`).join(",")
+    )
+    .join("\n");
 }
 
-// Function to download data as CSV
+/**
+ * Initiates the process to download the current visible section's data as a CSV file.
+ * 
+ * It first determines which section is active (visible), collects the corresponding data,
+ * converts it to CSV format, and then triggers a download.
+ */
 function downloadCSV() {
   const section = document.querySelector(".section:not(.hidden)");
   if (!section) return;
 
   try {
     let data;
+    // Determine the data collection method based on the section ID
     if (section.id === "oligo-section") {
       data = collectOligosaccharideData();
     } else if (section.id === "species-section") {
@@ -118,36 +425,116 @@ function downloadCSV() {
   }
 }
 
-
-// Function to collect oligosaccharide data
+/**
+ * Collects data from the oligosaccharide section of the page.
+ * 
+ * It extracts various fields from the DOM and returns them as an array of label-value pairs.
+ * 
+ * @returns {Array[]} - The oligosaccharide data formatted for CSV conversion.
+ */
 function collectOligosaccharideData() {
   return [
-    ['Milk Oligosaccharide ID', document.getElementById('oligo-id').textContent],
-    ['Milk Oligosaccharide Normalized Name', document.getElementById('oligo-name').textContent],
-    ['Formula', document.getElementById('oligo-formula').textContent],
-    ['Synonyms', document.getElementById('oligo-synonyms').textContent],
-    ['Text Occurrence', document.getElementById('oligo-occurrence-text').textContent],
-    ['Reference Class', document.getElementById('oligo-reference-class').textContent],
-    ['Species', document.getElementById('oligo-species').textContent],
-    ['MO Type', document.getElementById('oligo-mo-type').textContent],
+    [
+      "Milk Oligosaccharide ID",
+      document.getElementById("oligo-id").textContent,
+    ],
+    [
+      "Milk Oligosaccharide Normalized Name",
+      document.getElementById("oligo-name").textContent,
+    ],
+    ["Formula", document.getElementById("oligo-formula").textContent],
+    ["Synonyms", document.getElementById("oligo-synonyms").textContent],
+    [
+      "Text Occurrence",
+      document.getElementById("oligo-occurrence-text").textContent,
+    ],
+    [
+      "Reference Class",
+      document.getElementById("oligo-reference-class").textContent,
+    ],
+    ["Species", document.getElementById("oligo-species").textContent],
+    ["MO Type", document.getElementById("oligo-mo-type").textContent],
+    [
+      "Documents",
+      document.getElementById("oligo-documents")
+        ? document.getElementById("oligo-documents").textContent
+        : "N/A",
+    ],
   ];
 }
 
- 
-  // Function to collect species data
-  function collectSpeciesData() {
-    return [
-      ['Species ID', document.getElementById('species-id').textContent],
-      ['Species Scientific Name', document.getElementById('species-name').textContent],
-      ['Number of Occurrences', document.getElementById('species-occurrences').textContent],
-    ];
-  }
-  
-  // Function to collect sample data
-  function collectSampleData() {
-    return [
-      ['Sample ID', document.getElementById('sample-id').textContent],
-      ['Sample Scientific Name', document.getElementById('sample-name').textContent],
-      ['Associated Species', document.getElementById('sample-species').textContent],
-    ];
-  }
\ No newline at end of file
+/**
+ * Collects data from the species section of the page.
+ * 
+ * It extracts various fields from the DOM and returns them as an array of label-value pairs.
+ * 
+ * @returns {Array[]} - The species data formatted for CSV conversion.
+ */
+function collectSpeciesData() {
+  return [
+    ["Species ID", document.getElementById("species-id").textContent],
+    [
+      "Species Scientific Name",
+      document.getElementById("species-name").textContent,
+    ],
+    [
+      "Number of Occurrences",
+      document.getElementById("species-occurrences").textContent,
+    ],
+    [
+      "Oligosaccharides",
+      document.getElementById("species-oligosaccharides").textContent,
+    ],
+    ["Sample Type", document.getElementById("species-sample-type").textContent],
+    ["Documents", document.getElementById("species-documents").textContent],
+  ];
+}
+
+/**
+ * Collects data from the sample section of the page.
+ * 
+ * It extracts various fields from the DOM and returns them as an array of label-value pairs.
+ * 
+ * @returns {Array[]} - The sample data formatted for CSV conversion.
+ */
+function collectSampleData() {
+  return [
+    ["Sample ID", document.getElementById("sample-id").textContent],
+    [
+      "Sample Scientific Name",
+      document.getElementById("sample-name").textContent,
+    ],
+    ["Breed", document.getElementById("breed").textContent],
+    [
+      "Associated Species",
+      document.getElementById("sample-species").textContent,
+    ],
+    [
+      "Oligosaccharides",
+      document.getElementById("sample-oligosaccharides").textContent,
+    ],
+    [
+      "Oligosaccharide Type",
+      document.getElementById("sample-oligosaccharide-type").textContent,
+    ],
+    [
+      "Sample Type",
+      document.getElementById("sample-type")
+        ? document.getElementById("sample-type").textContent
+        : "N/A",
+    ],
+    [
+      "Methodology of Analysis",
+      document.getElementById("sample-methodology").textContent,
+    ],
+    [
+      "Sample Lactation Stage",
+      document.getElementById("sample-lactation-stage").textContent,
+    ],
+    ["Documents", document.getElementById("sample-documents").textContent],
+    [
+      "Text Occurrence",
+      document.getElementById("sample-occurrence-text").textContent,
+    ],
+  ];
+}
-- 
GitLab


From 650ef67a8dba278ba0b98b1fe4bb6688c29c2634 Mon Sep 17 00:00:00 2001
From: "hajar.bouamout" <hajar.bouamout@inrae.fr>
Date: Mon, 24 Feb 2025 15:48:45 +0100
Subject: [PATCH 37/51] =?UTF-8?q?Mise=20=C3=A0=20jour=20de=20sheet.html?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Ajout de nouveaux champs dans la section Oligosaccharide : Lactation_stage, Sample_type et Documents.

Modification de la section Species pour inclure Oligosaccharides, Sample Type et Documents.

Enrichissement de la section Samples avec des informations supplémentaires (Breed, Associated Species, Oligosaccharides, Oligosaccharide Type, Documents, Methodology Of Analysis, Sample Lactation Stage, Text Occurrence).

Optimisation de la structure HTML et de la cohérence de l'affichage.
---
 templates/sheet.html | 85 +++++++++++++++++++++++++++++++++++---------
 1 file changed, 69 insertions(+), 16 deletions(-)

diff --git a/templates/sheet.html b/templates/sheet.html
index dc07fa2..10f4658 100644
--- a/templates/sheet.html
+++ b/templates/sheet.html
@@ -39,6 +39,18 @@
             <span class="info-label">Synonyms</span>
             <span class="info-value" id="oligo-synonyms"></span>
           </div>
+          <div class="info-item">
+            <span class="info-label">Lactation_stage</span>
+            <span class="info-value" id="lactation_stage"></span>
+          </div>
+          <div class="info-item">
+            <span class="info-label">Sample_type</span>
+            <span class="info-value" id="sample_type"></span>
+          </div>
+          <div class="info-item">
+            <span class="info-label">Documents</span>
+            <span class="info-value" id="documents"></span>
+          </div>
         </div>
       </div>
 
@@ -89,30 +101,71 @@
             <span class="info-label">Number of Occurrences</span>
             <span class="info-value" id="species-occurrences"></span>
           </div>
-        </div>
-      </div>
-    </section>
-
-    <!-- Samples Section -->
-    <section id="samples-section" class="section hidden">
-      <div class="info-card">
-        <h2 class="card-header">Samples Information</h2>
-        <div class="info-grid">
           <div class="info-item">
-            <span class="info-label">Samples ID</span>
-            <span class="info-value" id="sample-id"></span>
+            <span class="info-label">Oligosaccharides</span>
+            <span class="info-value" id="species-oligosaccharides"></span>
           </div>
           <div class="info-item">
-            <span class="info-label">Samples Scientific Name</span>
-            <span class="info-value" id="sample-name"></span>
+            <span class="info-label">Sample Type</span>
+            <span class="info-value" id="species-sample-type"></span>
           </div>
           <div class="info-item">
-            <span class="info-label">Associated Species</span>
-            <span class="info-value" id="sample-species"></span>
-          </div>
+            <span class="info-label">Documents</span>
+            <span class="info-value" id="species-documents"></span>
+          </div>          
         </div>
       </div>
     </section>
+
+    <!-- Samples Section -->
+  <section id="samples-section" class="section hidden">
+    <div class="info-card">
+      <h2 class="card-header">Samples Information</h2>
+      <div class="info-grid">
+        <div class="info-item">
+          <span class="info-label">Samples ID</span>
+          <span class="info-value" id="sample-id"></span>
+        </div>
+        <div class="info-item">
+          <span class="info-label">Samples Scientific Name</span>
+          <span class="info-value" id="sample-name"></span>
+        </div>
+        <div class="info-item">
+          <span class="info-label">Breed</span>
+          <span class="info-value" id="breed"></span>
+        </div>
+        <div class="info-item">
+          <span class="info-label">Associated Species</span>
+          <span class="info-value" id="sample-species"></span>
+        </div>
+        <div class="info-item">
+          <span class="info-label">Oligosaccharides</span>
+          <span class="info-value" id="sample-oligosaccharides"></span>
+        </div>
+        <div class="info-item">
+          <span class="info-label">Oligosaccharide Type</span>
+          <span class="info-value" id="sample-oligosaccharide-type"></span>
+        </div>
+        <div class="info-item">
+          <span class="info-label">Documents</span>
+          <span class="info-value" id="sample-documents"></span>
+        </div>
+        <div class="info-item">
+          <span class="info-label">Methodology Of Analysis</span>
+          <span class="info-value" id="sample-methodology"></span>
+        </div>
+        <div class="info-item">
+          <span class="info-label">Sample Lactation Stage</span>
+          <span class="info-value" id="sample-lactation-stage"></span>
+        </div>
+        <div class="info-item">
+          <span class="info-label">Text Occurrence</span>
+          <span class="info-value" id="sample-occurrence-text"></span>
+        </div>
+      </div>
+    </div>
+  </section>
+
   </div>
 </main>
 {% endblock %}
\ No newline at end of file
-- 
GitLab


From 4a13985d2130b1ae13a2493e704c6e1da8298159 Mon Sep 17 00:00:00 2001
From: "hajar.bouamout" <hajar.bouamout@inrae.fr>
Date: Mon, 24 Feb 2025 16:37:58 +0100
Subject: [PATCH 38/51] =?UTF-8?q?ajout=20des=20infos=20en=20scrollant=20da?=
 =?UTF-8?q?ns=20le=20tableau=20des=20entit=C3=A9s?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 static/css/home.css | 53 +++++++++++++++++++++++++++++++++++++++++++++
 static/js/home.js   | 30 +++++++++++++++++++++++--
 2 files changed, 81 insertions(+), 2 deletions(-)

diff --git a/static/css/home.css b/static/css/home.css
index 5532c61..2e42a2a 100644
--- a/static/css/home.css
+++ b/static/css/home.css
@@ -144,6 +144,53 @@ body {
   margin-bottom: 1rem;
 }
 
+/* Pure CSS Tooltip Styling */
+.tooltip-container {
+  position: relative;
+  display: inline-block;
+}
+
+.entity-name {
+  cursor: help;
+  border-bottom: 1px dotted #274757;
+}
+
+.tooltip-text {
+  visibility: hidden;
+  width: 250px;
+  background-color: #274757;
+  color: #fff;
+  text-align: center;
+  border-radius: 6px;
+  padding: 8px;
+  position: absolute;
+  z-index: 1;
+  left: 105%;       
+  top: 50%;
+  transform: translateY(-50%);
+  opacity: 0;
+  transition: opacity 0.3s;
+  font-size: 0.85rem;
+  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.2);
+}
+
+.tooltip-container:hover .tooltip-text {
+  visibility: visible;
+  opacity: 1;
+}
+
+.tooltip-text::after {
+  content: "";
+  position: absolute;
+  top: 50%;
+  right: 100%;
+  transform: translateY(-50%);
+  border-width: 5px;
+  border-style: solid;
+  border-color: transparent #274757 transparent transparent;
+}
+
+
 @media (max-width: 768px) {
   .hero-section {
     max-width: 90%;
@@ -162,4 +209,10 @@ body {
     font-size: 0.9rem;
     padding: 0.5rem 1.2rem;
   }
+
+  .tooltip-text {
+    width: 200px;
+    margin-left: -100px;
+    font-size: 0.8rem;
+  }
 }
diff --git a/static/js/home.js b/static/js/home.js
index ea3cfe4..c40c5ee 100644
--- a/static/js/home.js
+++ b/static/js/home.js
@@ -2,6 +2,24 @@
 document.addEventListener("DOMContentLoaded", function () {
   // The API URL from which we are fetching the JSON data
   const apiUrl = '/_get/stat_occurrence';
+
+  // Entity definitions for tooltips
+  const entityDefinitions = {
+    "Species": "the vertebrate animals in which the young are nourished with milk from special mammary glands of the mother",
+    "Breed": "subclass of species",
+    "Geography": "indicates where the samples are from",
+    "FemalePhysiologicalstage": "lactation parity that indicates the number of gestation mothers have already had",
+    "Individual_number": "gives information on the number of individuals that have been studied",
+    "Sample_type": "refers to the samples used during the experimentation",
+    "Lactation_stage": "the period of lactation",
+    "Post_partum_age": "indicates the period since when the mother's has given birth",
+    "Methodology_of_analysis": "refers to the method that have been used to measure oligosaccharide's quantity and quality",
+    "Oligosaccharide_type": "groups based on their monosaccharides composition",
+    "Oligosaccharide_name": "the molecules' names",
+    "Absolute_quantification": "refers to the total quantity of one oligosaccharide (name or type) in the milk",
+    "Relative_quantification": "gives information on the part an oligosaccharide or a group of oligosaccharides occupy in the milk of a species",
+    "Oligosaccharide_richness": "quantify all the oligosaccharides"
+  };
    
   // Fetching the JSON data from the API
   fetch(apiUrl)
@@ -33,8 +51,16 @@ document.addEventListener("DOMContentLoaded", function () {
         const cell1 = document.createElement("td");
         const cell2 = document.createElement("td");
 
-         // Set the content of the cells
-        cell1.textContent = entity;
+         // Add HTML for the entity with tooltip
+         if (entityDefinitions[entity]) {
+          cell1.innerHTML = `<div class="tooltip-container">
+                              <span class="entity-name">${entity}</span>
+                              <span class="tooltip-text">${entityDefinitions[entity]}</span>
+                            </div>`;
+        } else {
+          cell1.textContent = entity;
+        }
+        
         cell2.textContent = rolesStats[entity];
 
         // Append the cells to the row
-- 
GitLab


From 7daacc99df0e5133cc6872741ea14f3af4a4da7f Mon Sep 17 00:00:00 2001
From: Sandra Derozier <sandra.derozier@inrae.fr>
Date: Tue, 25 Feb 2025 10:54:49 +0100
Subject: [PATCH 39/51] #9 - Add ChEBI ID

---
 database.py | 18 +++++++++++++++++-
 1 file changed, 17 insertions(+), 1 deletion(-)

diff --git a/database.py b/database.py
index d0ba48e..e3db6b6 100644
--- a/database.py
+++ b/database.py
@@ -229,8 +229,24 @@ def entity(app, conn, type_entity, id_entity):
         for row in cursor.fetchall():
             dico[row[0]] = row[1]
 
+        try:
+            print("SELECT ci_type, ci_value \
+                   FROM concept, concept_information \
+                   WHERE c_id = ci_fk_concept_id \
+                   AND c_identifier = '"+id_entity+"'")
+            
+            cursor.execute("SELECT ci_type, ci_value \
+                   FROM concept, concept_information \
+                   WHERE c_id = ci_fk_concept_id \
+                   AND c_identifier = %s", (id_entity,))
+        except Exception as err:
+            print_psycopg2_exception(err)
+        
+        for row in cursor.fetchall():
+            dico[row[0]] = row[1]
+
         cursor.close()
-        # print(dico)
+        print(dico)
         return dico
 
 # Check source format
-- 
GitLab


From 20230bf0744ce7de5aa66afa13e2703957bcbaaa Mon Sep 17 00:00:00 2001
From: "hajar.bouamout" <hajar.bouamout@inrae.fr>
Date: Tue, 25 Feb 2025 10:58:50 +0100
Subject: [PATCH 40/51] =?UTF-8?q?Correction=20du=20d=C3=A9bordement=20dans?=
 =?UTF-8?q?=20la=20section=20species?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 static/css/sheet.css | 9 ++++-----
 1 file changed, 4 insertions(+), 5 deletions(-)

diff --git a/static/css/sheet.css b/static/css/sheet.css
index eefd291..22285f2 100644
--- a/static/css/sheet.css
+++ b/static/css/sheet.css
@@ -107,14 +107,13 @@ body {
 }
 
 .info-value {
-    font-size: 1rem;
     color: #2c3e50;
-    padding: 0.5rem;
     background-color: #f8f9fa;
     border-radius: 4px;
-    min-height: 2.5rem;
-    display: flex;
-    align-items: center;
+    word-wrap: break-word;
+    overflow-wrap: break-word;
+    white-space: normal;
+    
 }
 
 /* Structure Viewer */
-- 
GitLab


From daae96480036495f9b35e6831ed1355eb099c2c2 Mon Sep 17 00:00:00 2001
From: Sandra Derozier <sandra.derozier@inrae.fr>
Date: Tue, 25 Feb 2025 13:10:39 +0100
Subject: [PATCH 41/51] #8 - API Get entity

---
 database.py | 10 +++++-----
 1 file changed, 5 insertions(+), 5 deletions(-)

diff --git a/database.py b/database.py
index e3db6b6..d1c43df 100644
--- a/database.py
+++ b/database.py
@@ -230,10 +230,10 @@ def entity(app, conn, type_entity, id_entity):
             dico[row[0]] = row[1]
 
         try:
-            print("SELECT ci_type, ci_value \
-                   FROM concept, concept_information \
-                   WHERE c_id = ci_fk_concept_id \
-                   AND c_identifier = '"+id_entity+"'")
+            # print("SELECT ci_type, ci_value \
+            #        FROM concept, concept_information \
+            #        WHERE c_id = ci_fk_concept_id \
+            #        AND c_identifier = '"+id_entity+"'")
             
             cursor.execute("SELECT ci_type, ci_value \
                    FROM concept, concept_information \
@@ -246,7 +246,7 @@ def entity(app, conn, type_entity, id_entity):
             dico[row[0]] = row[1]
 
         cursor.close()
-        print(dico)
+        # print(dico)
         return dico
 
 # Check source format
-- 
GitLab


From c8af25d5aaef4cc1f1037fae9c4b5e61a4365aa7 Mon Sep 17 00:00:00 2001
From: "hajar.bouamout" <hajar.bouamout@inrae.fr>
Date: Wed, 26 Feb 2025 11:39:52 +0100
Subject: [PATCH 42/51] =?UTF-8?q?Ajout=20de=20l'option=20de=20s=C3=A9lecti?=
 =?UTF-8?q?on=20du=20nombre=20d'entr=C3=A9es=20dans=20DataTables=20(10,=20?=
 =?UTF-8?q?25,=2050,=20100)?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 static/js/research.js | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/static/js/research.js b/static/js/research.js
index d8d511d..e2dec07 100644
--- a/static/js/research.js
+++ b/static/js/research.js
@@ -64,7 +64,8 @@ document.addEventListener("DOMContentLoaded", function () {
         searching: true,
         ordering: true,
         info: true,
-        dom: 'Bfrtip',
+        lengthMenu: [[10, 25, 50, 100], [10, 25, 50, 100]],
+        dom: 'lBfrtip',
         language: {
             search: "Filter with : "
         },
-- 
GitLab


From 84cc340e9e960c434eb514e1b2f0881937466873 Mon Sep 17 00:00:00 2001
From: "hajar.bouamout" <hajar.bouamout@inrae.fr>
Date: Wed, 26 Feb 2025 11:59:12 +0100
Subject: [PATCH 43/51] =?UTF-8?q?Mise=20=C3=A0=20jour=20des=20libell=C3=A9?=
 =?UTF-8?q?s=20des=20boutons=20:=20'Upload=20CSV'=20et=20'Columns=20Visibi?=
 =?UTF-8?q?lity',=20et=20configuration=20du=20nom=20de=20fichier=20CSV=20a?=
 =?UTF-8?q?vec=20la=20date=20et=20l'entit=C3=A9=20recherch=C3=A9e?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 static/js/research.js | 30 +++++++++++++++---------------
 1 file changed, 15 insertions(+), 15 deletions(-)

diff --git a/static/js/research.js b/static/js/research.js
index e2dec07..6c0a4e9 100644
--- a/static/js/research.js
+++ b/static/js/research.js
@@ -59,6 +59,7 @@ document.addEventListener("DOMContentLoaded", function () {
   // DataTable Initialization
   // Configures the results table with advanced features
   function initializeDataTable() {
+    let today = new Date().toISOString().slice(0, 10).replace(/-/g, "");
     table = $("#results-table").DataTable({
         paging: true,
         searching: true,
@@ -66,6 +67,19 @@ document.addEventListener("DOMContentLoaded", function () {
         info: true,
         lengthMenu: [[10, 25, 50, 100], [10, 25, 50, 100]],
         dom: 'lBfrtip',
+        buttons: [
+          {
+              extend: 'csv',
+              text: 'Upload CSV',
+              filename: function () {
+                  let entity = $('#search-input').val() || 'data';
+                  return today + '_' + entity;
+              }
+          },
+          'colvis'
+      ],
+      initComplete: function() {
+          $(".dataTables_length").css("margin-right", "20px"); },
         language: {
             search: "Filter with : "
         },
@@ -107,21 +121,7 @@ document.addEventListener("DOMContentLoaded", function () {
                 $(row).hide();
             }
         },
-        buttons: [
-            {
-                extend: "colvis",
-                text: "Gérer les colonnes",
-            },
-            {
-                extend: "csvHtml5",
-                text: "Télécharger CSV",
-                filename: "search_results",
-                title: "Search Results",
-                exportOptions: {
-                    columns: ":visible",
-                }
-            }
-        ],
+       
         columns: [
             {
                 data: "oligosaccharide_name",
-- 
GitLab


From cfc51db0ec6b2b47f2b6dcbd15fc362e0edf8cc5 Mon Sep 17 00:00:00 2001
From: "hajar.bouamout" <hajar.bouamout@inrae.fr>
Date: Wed, 26 Feb 2025 12:11:34 +0100
Subject: [PATCH 44/51] Suppression de la colonne 'Details' et rendu des noms
 des oligosaccharides cliquables vers leurs fiches

---
 static/js/research.js   | 19 +++++++------------
 templates/research.html |  1 -
 2 files changed, 7 insertions(+), 13 deletions(-)

diff --git a/static/js/research.js b/static/js/research.js
index 6c0a4e9..691738f 100644
--- a/static/js/research.js
+++ b/static/js/research.js
@@ -126,6 +126,12 @@ document.addEventListener("DOMContentLoaded", function () {
             {
                 data: "oligosaccharide_name",
                 title: "Oligosaccharide Name",
+                render: function(data, type, row) {
+                  if (row.identifier) {
+                      return `<a href="/sheet?type_entity=Oligosaccharide_name&id_entity=${encodeURIComponent(row.identifier)}">${data}</a>`;
+                  }
+                  return "N/A";
+              },
                 defaultContent: "N/A"
             },
             {
@@ -154,18 +160,7 @@ document.addEventListener("DOMContentLoaded", function () {
                 render: (id) => `<a href="/source/${id}">${id}</a>`,
                 defaultContent: "N/A"
             },
-            {
-                data: null,
-                title: "Details",
-                render: function(data, type, row) {
-                    if (row.identifier) {
-                        return `<a href="/sheet?type_entity=Oligosaccharide_name&id_entity=${encodeURIComponent(row.identifier)}">View</a>`;
-                    }
-                    return "N/A";
-                },
-                defaultContent: "N/A"
-            }
-          
+    
         ],
         order: [[0, "asc"]]
     });
diff --git a/templates/research.html b/templates/research.html
index 50f3f9a..c52e77a 100644
--- a/templates/research.html
+++ b/templates/research.html
@@ -66,7 +66,6 @@
             <th>Species</th>
             <th>Lactation Stage</th>
             <th>Source</th>
-            <th>Details</th>
           </tr>
         </thead>
         <tbody id="results-body">
-- 
GitLab


From 0d302edc25418fa9bb93edfd6fcf9ff534ed56f7 Mon Sep 17 00:00:00 2001
From: "hajar.bouamout" <hajar.bouamout@inrae.fr>
Date: Wed, 26 Feb 2025 12:19:18 +0100
Subject: [PATCH 45/51] =?UTF-8?q?Suppression=20du=20bouton=20'Search',=20l?=
 =?UTF-8?q?a=20recherche=20=C3=A9tant=20d=C3=A9sormais=20d=C3=A9clench?=
 =?UTF-8?q?=C3=A9e=20automatiquement=20via=20la=20s=C3=A9lection=20dans=20?=
 =?UTF-8?q?l'autocompl=C3=A9tion?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 static/js/research.js | 6 +++++-
 1 file changed, 5 insertions(+), 1 deletion(-)

diff --git a/static/js/research.js b/static/js/research.js
index 691738f..d31e482 100644
--- a/static/js/research.js
+++ b/static/js/research.js
@@ -164,7 +164,11 @@ document.addEventListener("DOMContentLoaded", function () {
         ],
         order: [[0, "asc"]]
     });
-}
+
+     // Deletion of search button 
+     $(".search-btn").remove();
+    }
+
 
 
 function getColumnIndex(columnName) {
-- 
GitLab


From e2be4130e0bd83ed0c2f4df999177a8efa19547a Mon Sep 17 00:00:00 2001
From: "hajar.bouamout" <hajar.bouamout@inrae.fr>
Date: Wed, 26 Feb 2025 13:56:49 +0100
Subject: [PATCH 46/51] =?UTF-8?q?=20R=C3=A9initialisation=20du=20champ=20d?=
 =?UTF-8?q?e=20recherche=20lors=20du=20changement=20de=20type=20d'entit?=
 =?UTF-8?q?=C3=A9?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 static/js/research.js | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/static/js/research.js b/static/js/research.js
index d31e482..eb1763b 100644
--- a/static/js/research.js
+++ b/static/js/research.js
@@ -167,6 +167,11 @@ document.addEventListener("DOMContentLoaded", function () {
 
      // Deletion of search button 
      $(".search-btn").remove();
+
+    // Reset search input when changing entity type
+    $("#simple-search-type").on("change", function() {
+      $("#search-input").val("");
+  });
     }
 
 
-- 
GitLab


From 3c538750d07b837df2d30f473ffe152ca58327be Mon Sep 17 00:00:00 2001
From: "hajar.bouamout" <hajar.bouamout@inrae.fr>
Date: Wed, 26 Feb 2025 16:27:31 +0100
Subject: [PATCH 47/51] =?UTF-8?q?R=C3=A9cup=C3=A9ration=20des=20identifian?=
 =?UTF-8?q?ts=20ChEBI=20et=20g=C3=A9n=C3=A9ration=20dynamique=20des=20imag?=
 =?UTF-8?q?es=203D=20avec=20options=20de=20zoom=20et=20plein=20=C3=A9cran?=
 =?UTF-8?q?=20et=20ajout=20du=20style=20CSS=20associ=C3=A9?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 static/css/sheet.css | 56 +++++++++++++++++++++++++++++++++++-
 static/js/sheet.js   | 67 ++++++++++++++++++++++++++++++++++++++++++++
 templates/sheet.html |  8 ++++--
 3 files changed, 127 insertions(+), 4 deletions(-)

diff --git a/static/css/sheet.css b/static/css/sheet.css
index 22285f2..6e4b513 100644
--- a/static/css/sheet.css
+++ b/static/css/sheet.css
@@ -182,4 +182,58 @@ body {
     .info-item {
         padding: 0.5rem;
     }
-}
\ No newline at end of file
+}
+
+/* Style du conteneur de l'image ChEBI */
+#chebi-structure-container {
+    text-align: center;
+    padding: 15px;
+    background-color: #ffffff;
+    border-radius: 8px;
+    box-shadow: 0px 2px 10px rgba(0, 0, 0, 0.2);
+    margin-top: 20px;
+    max-width: 400px;
+    margin-left: auto;
+    margin-right: auto;
+}
+
+/* Style de l'image 3D */
+#chebi-structure-img {
+    width: 300px;
+    height: 300px;
+    border-radius: 10px;
+    box-shadow: 0px 6px 12px rgba(0, 0, 0, 0.3);
+    transition: transform 0.3s ease-in-out;
+}
+
+#chebi-structure-img:hover {
+    transform: scale(1.05);
+}
+
+/* Style des boutons de contrôle */
+.zoom-controls {
+    display: flex;
+    justify-content: center;
+    margin-top: 10px;
+    gap: 10px;
+}
+
+.zoom-btn {
+    background: #0077cc;
+    color: white;
+    border: none;
+    padding: 10px 15px;
+    border-radius: 5px;
+    cursor: pointer;
+    font-size: 1rem;
+    transition: background 0.3s ease;
+}
+
+.zoom-btn:hover {
+    background: #005fa3;
+}
+
+.zoom-btn:active {
+    transform: scale(0.95);
+}
+
diff --git a/static/js/sheet.js b/static/js/sheet.js
index 1d3feb9..ab62139 100644
--- a/static/js/sheet.js
+++ b/static/js/sheet.js
@@ -538,3 +538,70 @@ function collectSampleData() {
     ],
   ];
 }
+
+document.addEventListener("DOMContentLoaded", function () {
+  let params = new URLSearchParams(window.location.search);
+  let type_entity = params.get("type_entity");
+  let id_entity = params.get("id_entity");
+
+  if (type_entity && id_entity) {
+      fetch(`/_get/entity?type_entity=${type_entity}&id_entity=${id_entity}`)
+          .then(response => response.json())
+          .then(data => {
+              if (data.ChEBI) {
+                  // **Update ChEBI ID in the DOM**
+                  document.getElementById("oligo-chebi-id").innerText = data.ChEBI;
+                  
+                  // **Dynamically add the 3D structure image**
+                  let imgElement = document.createElement("img");
+                  imgElement.src = `https://www.ebi.ac.uk/chebi/displayImage.do?defaultImage=true&chebiId=${data.ChEBI.replace("CHEBI:", "")}`;
+                  imgElement.alt = `3D Structure of ${data.ChEBI}`;
+                  imgElement.id = "chebi-structure-img";
+                  imgElement.style.cursor = "pointer";
+
+                  // **Add zoom and fullscreen buttons**
+                  let zoomInBtn = document.createElement("button");
+                  zoomInBtn.innerText = "+";
+                  zoomInBtn.className = "zoom-btn";
+                  zoomInBtn.onclick = function () {
+                      imgElement.style.width = (imgElement.clientWidth * 1.2) + "px";
+                      imgElement.style.height = (imgElement.clientHeight * 1.2) + "px";
+                  };
+
+                  let zoomOutBtn = document.createElement("button");
+                  zoomOutBtn.innerText = "-";
+                  zoomOutBtn.className = "zoom-btn";
+                  zoomOutBtn.onclick = function () {
+                      imgElement.style.width = (imgElement.clientWidth * 0.8) + "px";
+                      imgElement.style.height = (imgElement.clientHeight * 0.8) + "px";
+                  };
+
+                  let fullscreenBtn = document.createElement("button");
+                  fullscreenBtn.innerText = "⛶";
+                  fullscreenBtn.className = "zoom-btn";
+                  fullscreenBtn.onclick = function () {
+                      if (imgElement.requestFullscreen) {
+                          imgElement.requestFullscreen();
+                      } else if (imgElement.mozRequestFullScreen) { // Firefox
+                          imgElement.mozRequestFullScreen();
+                      } else if (imgElement.webkitRequestFullscreen) { // Chrome, Safari & Opera
+                          imgElement.webkitRequestFullscreen();
+                      } else if (imgElement.msRequestFullscreen) { // IE/Edge
+                          imgElement.msRequestFullscreen();
+                      }
+                  };
+
+                  let buttonContainer = document.createElement("div");
+                  buttonContainer.className = "zoom-controls";
+                  buttonContainer.appendChild(zoomInBtn);
+                  buttonContainer.appendChild(zoomOutBtn);
+                  buttonContainer.appendChild(fullscreenBtn);
+                  
+                  let container = document.getElementById("chebi-structure-container");
+                  container.appendChild(imgElement);
+                  container.appendChild(buttonContainer);
+              }
+          })
+          .catch(error => console.error("Error fetching ChEBI ID:", error));
+  }
+});
diff --git a/templates/sheet.html b/templates/sheet.html
index 10f4658..fdc1146 100644
--- a/templates/sheet.html
+++ b/templates/sheet.html
@@ -78,9 +78,11 @@
 
       <div class="info-card">
         <h2 class="card-header">3D Structure</h2>
-        <div class="structure-viewer">
-          <img id="structure-image" class="structure-image" alt="3D Structure">
-        </div>
+        <div class="info-item">
+          <span class="info-label">ChEBI ID:</span>
+          <span class="info-value" id="oligo-chebi-id">Loading...</span>
+      </div>
+      <div id="chebi-structure-container"></div>      
       </div>
     </section>
 
-- 
GitLab


From 831322306fec6f30c5f0c325564b8435462cf7f2 Mon Sep 17 00:00:00 2001
From: "hajar.bouamout" <hajar.bouamout@inrae.fr>
Date: Wed, 26 Feb 2025 16:33:32 +0100
Subject: [PATCH 48/51] Suppression de la sidebar

---
 static/css/sheet.css | 33 ---------------------------------
 static/js/sheet.js   | 17 -----------------
 templates/sheet.html | 10 +---------
 3 files changed, 1 insertion(+), 59 deletions(-)

diff --git a/static/css/sheet.css b/static/css/sheet.css
index 6e4b513..32b1578 100644
--- a/static/css/sheet.css
+++ b/static/css/sheet.css
@@ -19,39 +19,6 @@ body {
     margin-top: 40px;
 }
 
-/* Sidebar Navigation */
-.sidebar {
-    width: 250px;
-    background-color: #2c3e50;
-    padding: 2rem 0;
-    flex-shrink: 0;
-    height: 100vh;
-    position: sticky;
-    top: 0;
-}
-
-.nav-menu {
-    list-style: none;
-    padding: 0;
-    margin: 0;
-}
-
-.nav-btn {
-    width: 100%;
-    padding: 1rem 2rem;
-    text-align: left;
-    background: none;
-    border: none;
-    color: #ecf0f1;
-    font-size: 1rem;
-    cursor: pointer;
-    transition: background-color 0.3s;
-}
-
-.nav-btn:hover {
-    background-color: #34495e;
-}
-
 /* Content Area */
 .content {
     flex-grow: 1;
diff --git a/static/js/sheet.js b/static/js/sheet.js
index ab62139..81270d6 100644
--- a/static/js/sheet.js
+++ b/static/js/sheet.js
@@ -333,23 +333,6 @@ function populateSampleData(data) {
   }
 }
 
-/**
- * Toggles the visibility of content sections.
- * 
- * This function hides all sections (elements with the "section" class) and then displays
- * the section corresponding to the given type.
- * 
- * @param {string} sectionType - The identifier of the section to display.
- */
-window.toggleSection = function (sectionType) {
-  const sections = document.querySelectorAll(".section");
-  sections.forEach((section) => section.classList.add("hidden"));
-
-  const activeSection = document.getElementById(`${sectionType}-section`);
-  if (activeSection) {
-    activeSection.classList.remove("hidden");
-  }
-};
 
 // Duplicate toggleSection function (can be removed if redundant)
 window.toggleSection = function (sectionType) {
diff --git a/templates/sheet.html b/templates/sheet.html
index fdc1146..1baded7 100644
--- a/templates/sheet.html
+++ b/templates/sheet.html
@@ -4,15 +4,7 @@
 <link href="{{ url_for('static', filename='css/sheet.css') }}" rel="stylesheet"/>
 
 <main class="main-container">
-  <!-- Navigation Sidebar -->
-  <nav class="sidebar">
-    <ul class="nav-menu">
-      <li><button class="nav-btn" onclick="toggleSection('oligo')">Oligosaccharides</button></li>
-      <li><button class="nav-btn" onclick="toggleSection('species')">Species</button></li>
-      <li><button class="nav-btn" onclick="toggleSection('samples')">Samples</button></li>
-    </ul>
-  </nav>
-
+ 
   <!-- Content Area -->
     <div class="content">
       <div class="action-bar">
-- 
GitLab


From 7620b1f6ac820b4118507193e00a635f2fc92393 Mon Sep 17 00:00:00 2001
From: "hajar.bouamout" <hajar.bouamout@inrae.fr>
Date: Thu, 27 Feb 2025 16:12:48 +0100
Subject: [PATCH 49/51] =?UTF-8?q?Mise=20en=20ordre=20des=20entit=C3=A9s=20?=
 =?UTF-8?q?selon=20leur=20pertinence=20d=C3=A9finie=20et=20ajout=20de=20l'?=
 =?UTF-8?q?option=20de=20tri=20par=20Count=20dans=20le=20tableau=20des=20e?=
 =?UTF-8?q?ntit=C3=A9s?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 static/js/home.js | 135 ++++++++++++++++++++++++++++++++--------------
 1 file changed, 96 insertions(+), 39 deletions(-)

diff --git a/static/js/home.js b/static/js/home.js
index c40c5ee..03bd38c 100644
--- a/static/js/home.js
+++ b/static/js/home.js
@@ -5,22 +5,42 @@ document.addEventListener("DOMContentLoaded", function () {
 
   // Entity definitions for tooltips
   const entityDefinitions = {
-    "Species": "the vertebrate animals in which the young are nourished with milk from special mammary glands of the mother",
-    "Breed": "subclass of species",
-    "Geography": "indicates where the samples are from",
-    "FemalePhysiologicalstage": "lactation parity that indicates the number of gestation mothers have already had",
-    "Individual_number": "gives information on the number of individuals that have been studied",
-    "Sample_type": "refers to the samples used during the experimentation",
-    "Lactation_stage": "the period of lactation",
-    "Post_partum_age": "indicates the period since when the mother's has given birth",
-    "Methodology_of_analysis": "refers to the method that have been used to measure oligosaccharide's quantity and quality",
-    "Oligosaccharide_type": "groups based on their monosaccharides composition",
-    "Oligosaccharide_name": "the molecules' names",
-    "Absolute_quantification": "refers to the total quantity of one oligosaccharide (name or type) in the milk",
-    "Relative_quantification": "gives information on the part an oligosaccharide or a group of oligosaccharides occupy in the milk of a species",
-    "Oligosaccharide_richness": "quantify all the oligosaccharides"
+    "Species": "The vertebrate animals in which the young are nourished with milk from special mammary glands of the mother.",
+    "Breed": "Subclass of species.",
+    "Geography": "Indicates where the samples are from.",
+    "FemalePhysiologicalstage": "Lactation parity that indicates the number of gestation mothers have already had.",
+    "Individual_number": "Gives information on the number of individuals that have been studied.",
+    "Sample_type": "Refers to the samples used during the experimentation.",
+    "Lactation_stage": "The period of lactation.",
+    "Post_partum_age": "Indicates the period since when the mother's has given birth.",
+    "Methodology_of_analysis": "Refers to the method that have been used to measure oligosaccharide's quantity and quality.",
+    "Oligosaccharide_type": "Groups based on their monosaccharides composition.",
+    "Oligosaccharide_name": "The molecules' names.",
+    "Absolute_quantification": "Refers to the total quantity of one oligosaccharide (name or type) in the milk.",
+    "Relative_quantification": "Gives information on the part an oligosaccharide or a group of oligosaccharides occupy in the milk of a species.",
+    "Oligosaccharide_richness": "Quantify all the oligosaccharides."
   };
    
+
+  // Define the priority order of entities based on relevance
+  const entityPriorityOrder = {
+    "Oligosaccharide_name": 1,
+    "Oligosaccharide_type": 2,
+    "Sample_type": 3,
+    "Species": 4,
+    "Methodology_of_analysis": 5,
+    "Lactation_stage": 6,
+    "FemalePhysiologicalstage": 7,
+    "Post_partum_age": 8,
+    "Breed": 9,
+    "Geography": 10
+  };
+
+
+   // Variable to keep track of current sort order (initially ascending)
+   let isAscending = true;
+  
+
   // Fetching the JSON data from the API
   fetch(apiUrl)
     .then((response) => response.json())  // Convert the API response to JSON
@@ -42,38 +62,75 @@ document.addEventListener("DOMContentLoaded", function () {
         rolesStats[key] = data[key];  
       });
 
-      // Get the table body element where we will display the data
-      const entitiesTableBody = document.getElementById("entitiesTableBody");
-
-      // Iterate over the rolesStats object and create table rows for each entity
-      Object.keys(rolesStats).forEach((entity) => {
-        const row = document.createElement("tr");
-        const cell1 = document.createElement("td");
-        const cell2 = document.createElement("td");
-
-         // Add HTML for the entity with tooltip
-         if (entityDefinitions[entity]) {
-          cell1.innerHTML = `<div class="tooltip-container">
-                              <span class="entity-name">${entity}</span>
-                              <span class="tooltip-text">${entityDefinitions[entity]}</span>
-                            </div>`;
-        } else {
-          cell1.textContent = entity;
-        }
+      // Function to render the table with current data and sorting
+      function renderTable(sortOrder) {
+        // Get the table body element where we will display the data
+        const entitiesTableBody = document.getElementById("entitiesTableBody");
+        // Clear existing content
+        entitiesTableBody.innerHTML = '';
+        
+        // Create array of entries for sorting
+        let entries = Object.entries(rolesStats);
         
-        cell2.textContent = rolesStats[entity];
+        // Sort entries by priority order or alphabetically if priority not defined
+        entries.sort((a, b) => {
+          const priorityA = entityPriorityOrder[a[0]] || 999;
+          const priorityB = entityPriorityOrder[b[0]] || 999;
+          return priorityA - priorityB;
+        });
+        
+        // Apply count-based sorting if requested
+        if (sortOrder === 'count') {
+          entries.sort((a, b) => {
+            return isAscending ? a[1] - b[1] : b[1] - a[1];
+          });
+        }
+
+        // Iterate over the sorted entries and create table rows for each entity
+        entries.forEach(([entity, count]) => {
+          const row = document.createElement("tr");
+          const cell1 = document.createElement("td");
+          const cell2 = document.createElement("td");
 
-        // Append the cells to the row
-        row.appendChild(cell1);
-        row.appendChild(cell2);
+          // Add HTML for the entity with tooltip
+          if (entityDefinitions[entity]) {
+            cell1.innerHTML = `<div class="tooltip-container">
+                                <span class="entity-name">${entity}</span>
+                                <span class="tooltip-text">${entityDefinitions[entity]}</span>
+                              </div>`;
+          } else {
+            cell1.textContent = entity;
+          }
+          
+          cell2.textContent = count;
 
-        // Append the row to the table body
-        entitiesTableBody.appendChild(row);
+          // Append the cells to the row
+          row.appendChild(cell1);
+          row.appendChild(cell2);
+
+          // Append the row to the table body
+          entitiesTableBody.appendChild(row);
+        });
+      }
+      
+      // Initial table render with priority-based ordering
+      renderTable('priority');
+      
+      // Add header click event to sort by count
+      const countHeader = document.querySelector("#entitiesTable th:nth-child(2)");
+      countHeader.style.cursor = "pointer";
+      countHeader.innerHTML += ' <span id="sortIcon">â–¼</span>';
+      
+      countHeader.addEventListener("click", function() {
+        isAscending = !isAscending;
+        document.getElementById("sortIcon").textContent = isAscending ? 'â–²' : 'â–¼';
+        renderTable('count');
       });
     })
     .catch((error) => {
       console.error("Error fetching the JSON data:", error);
-    });})
+    });
+});
 
 
     // Event listener that triggers when the DOM is fully loaded
-- 
GitLab


From 28e180def7ff3df8710bf039e19e9e18770265c3 Mon Sep 17 00:00:00 2001
From: "hajar.bouamout" <hajar.bouamout@inrae.fr>
Date: Thu, 27 Feb 2025 16:14:08 +0100
Subject: [PATCH 50/51] ajout du style pour sort icon

---
 static/css/home.css | 7 +++++++
 1 file changed, 7 insertions(+)

diff --git a/static/css/home.css b/static/css/home.css
index 2e42a2a..7ead5ed 100644
--- a/static/css/home.css
+++ b/static/css/home.css
@@ -216,3 +216,10 @@ body {
     font-size: 0.8rem;
   }
 }
+
+
+#sortIcon {
+  margin-left: 5px;
+  font-size: 0.8em;
+}
+
-- 
GitLab


From ccdb4aeb745b41960e7e93b3f0fda12578cfa6bd Mon Sep 17 00:00:00 2001
From: "hajar.bouamout" <hajar.bouamout@inrae.fr>
Date: Mon, 3 Mar 2025 14:11:15 +0100
Subject: [PATCH 51/51] =?UTF-8?q?am=C3=A9lioration=20du=20style=20de=20la?=
 =?UTF-8?q?=20page=20d'accueil=20et=20rajout=20des=20btn=20de=20recherche?=
 =?UTF-8?q?=20simple=20et=20avanc=C3=A9e?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 static/css/home.css | 184 ++++++++++++++++++++++++++++++++++----------
 templates/home.html |   6 +-
 2 files changed, 150 insertions(+), 40 deletions(-)

diff --git a/static/css/home.css b/static/css/home.css
index 7ead5ed..13a72da 100644
--- a/static/css/home.css
+++ b/static/css/home.css
@@ -1,24 +1,62 @@
+/* Base styles */
+:root {
+  --primary-color: #0077cc;
+  --secondary-color: #274757;
+  --accent-color: #17a2b8;
+  --light-gray: #f8f9fa;
+  --dark-gray: #495057;
+  --white: #ffffff;
+  --shadow-sm: 0 2px 4px rgba(0, 0, 0, 0.1);
+  --shadow-md: 0 4px 8px rgba(0, 0, 0, 0.15);
+  --shadow-lg: 0 8px 16px rgba(0, 0, 0, 0.2);
+  --transition-standard: all 0.3s ease-in-out;
+  --border-radius-sm: 0.5rem;
+  --border-radius-md: 1rem;
+  --border-radius-lg: 1.5rem;
+}
+
 body {
   font-family: 'Roboto', sans-serif;
-  color: #333;
-  background-color: #f8f9fa;
+  color: var(--dark-gray);
+  background-color: var(--light-gray);
+  line-height: 1.6;
 }
 
 /* Hero Section */
 .hero-section {
-  background: linear-gradient(145deg, #274757, #0077cc);
-  padding: 2rem 0;
-  border-radius: 20px;
-  color: white;
-  margin: 40px auto;
+  background: linear-gradient(135deg, var(--secondary-color) 0%, var(--primary-color) 100%);
+  padding: 3rem 0;
+  border-radius: var(--border-radius-lg);
+  color: var(--white);
+  margin: 2.5rem auto;
   max-width: 80%;
   text-align: center;
-  box-shadow: 0px 5px 15px rgba(0, 0, 0, 0.15);
+  box-shadow: var(--shadow-lg);
+  position: relative;
+  overflow: hidden;
+}
+
+ 
+.hero-section::before {
+  content: "";
+  position: absolute;
+  top: 0;
+  left: 0;
+  width: 100%;
+  height: 100%;
+  background: radial-gradient(circle at 70% 30%, rgba(255, 255, 255, 0.15) 0%, transparent 70%);
+  pointer-events: none;
 }
 
 .hero-section .logo {
-  max-width: 80px; 
-  margin-bottom: 0.8rem;
+  max-width: 110px; 
+  margin-top: 30px;
+  filter: drop-shadow(0 2px 4px rgba(0, 0, 0, 0.2));
+  transition: var(--transition-standard);
+}
+
+.hero-section .logo:hover {
+  transform: scale(1.05);
 }
 
 
@@ -28,6 +66,8 @@ body {
   font-weight: bold;
   margin-bottom: 1rem;
   color: white;
+  text-shadow: 0 2px 4px rgba(0, 0, 0, 0.2);
+  letter-spacing: -0.02em
 }
 
 .hero-section .description {
@@ -39,19 +79,42 @@ body {
   margin: 0 auto;
 }
 
-.btn-info {
-  background-color: #ff8c00;
-  padding: 0.6rem 1.5rem;
-  border-radius: 30px;
-  font-weight: bold;
+.hero-section .btn {
+  margin: 0.5rem;
+  padding: 0.7rem 1.8rem;
+  border-radius: 50px;
+  font-weight: 600;
   font-size: 1rem;
-  transition: all 0.3s ease-in-out;
-  box-shadow: 2px 2px 10px rgba(0, 0, 0, 0.15);
+  transition: var(--transition-standard);
+  box-shadow: var(--shadow-md);
+  border: none;
 }
 
-.btn-info:hover {
-  background-color: #e67e00;
-  transform: scale(1.05);
+.btn-info {
+  background-color: var(--accent-color);
+  color: var(--white);
+}
+
+  
+.btn-primary {
+  background-color: var(--primary-color);
+  color: var(--white);
+}
+
+.btn-secondary {
+  background-color: rgba(255, 255, 255, 0.25);
+  color: var(--white);
+  backdrop-filter: blur(10px);
+}
+
+.hero-section .btn:hover {
+  transform: translateY(-3px);
+  box-shadow: var(--shadow-lg);
+  opacity: 1;
+}
+
+.hero-section .btn:active {
+  transform: translateY(1px);
 }
 
 
@@ -66,29 +129,20 @@ body {
   margin: 0 -15px;
 }
 
-.viz-card1 {
-  background: white;
-  border-radius: 1rem;
-  padding: 1.5rem;
-  height: 400px;
-  box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
-  transition: transform 0.2s;
-  align-items: center;
-}
-
 
 /* Data Visualization Section  */
 .viz-card {
-  background: white;
-  border-radius: 1rem;
-  padding: 1.5rem;
+  background: var(--white);
+  border-radius: var(--border-radius-md);
+  padding: 2rem;
   height: 400px;
-  box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
-  transition: transform 0.2s;
-  align-items: center;
+  box-shadow: var(--shadow-sm);
+  transition: var(--transition-standard);
   display: flex;
   flex-direction: column;
-  justify-content: center; 
+  margin-bottom: 2rem;
+  position: relative;
+  overflow: hidden;
 }
 
 .viz-card canvas {
@@ -114,20 +168,52 @@ body {
   text-align: center;
 }
 
+
+
 .table-wrapper {
   max-height: 300px;
   overflow-y: auto;
+  border-radius: var(--border-radius-sm);
+  box-shadow: inset 0 0 5px rgba(0, 0, 0, 0.05);
 }
 
 .table {
   margin-bottom: 0;
+  border-collapse: separate;
+  border-spacing: 0;
+  width: 100%;
 }
 
 .table th {
-  background-color: #274757;
-  color: white;
+  background-color: var(--secondary-color);
+  color: var(--white);
   position: sticky;
   top: 0;
+  z-index: 10;
+  padding: 1rem;
+  font-weight: 600;
+}
+
+.table th:first-child {
+  border-top-left-radius: var(--border-radius-sm);
+}
+
+.table th:last-child {
+  border-top-right-radius: var(--border-radius-sm);
+}
+
+.table td {
+  padding: 0.8rem 1rem;
+  vertical-align: middle;
+  border-bottom: 1px solid rgba(0, 0, 0, 0.05);
+}
+
+.table tr:last-child td {
+  border-bottom: none;
+}
+
+.table tr:hover {
+  background-color: rgba(0, 119, 204, 0.05);
 }
 
 .coming-soon {
@@ -223,3 +309,23 @@ body {
   font-size: 0.8em;
 }
 
+
+.hero-section .btn {
+  margin: 5px;
+}
+
+.btn-primary {
+  background-color: var(--primary-color);
+    color: var(--white);
+  }
+
+.btn-secondary {
+  background-color: rgba(255, 255, 255, 0.25);
+  color: var(--white);
+  backdrop-filter: blur(10px);
+}
+
+.btn-primary:hover, .btn-secondary:hover {
+  opacity: 0.85;
+}
+
diff --git a/templates/home.html b/templates/home.html
index bff49ae..3840013 100644
--- a/templates/home.html
+++ b/templates/home.html
@@ -27,6 +27,10 @@
     </p>
     <a href="about" class="btn btn-info btn-sm mt-2">Learn More</a>
   </div>
+  <div class="mt-3">
+    <a href="research" class="btn btn-primary btn-sm">Simple Search</a>
+    <a href="advancedSearch" class="btn btn-secondary btn-sm">Advanced Search</a>
+  </div>  
 </section>
 
 
@@ -36,7 +40,7 @@
     <h2 class="text-center section-title mb-5">HoloOligo Data Overview</h2>
     <div class="row visualization-row">
       <div class="col-md-4">
-        <div class="viz-card1">
+        <div class="viz-card">
           <h3>Entities Overview</h3>
           <div class="table-wrapper">
             <table id="entitiesTable" class="table table-striped">
-- 
GitLab