up
This commit is contained in:
parent
0df830f93d
commit
2ad98b5864
11 changed files with 808 additions and 224 deletions
91
public/js/table-sort.js
Normal file
91
public/js/table-sort.js
Normal file
|
@ -0,0 +1,91 @@
|
||||||
|
/**
|
||||||
|
* Simple table sorting script
|
||||||
|
* Enables sorting for all tables with the class 'sortable'
|
||||||
|
*/
|
||||||
|
document.addEventListener('DOMContentLoaded', function() {
|
||||||
|
// Get all tables with the class 'table'
|
||||||
|
const tables = document.querySelectorAll('table.table');
|
||||||
|
|
||||||
|
// Add sortable class to all tables
|
||||||
|
tables.forEach(table => {
|
||||||
|
table.classList.add('sortable');
|
||||||
|
});
|
||||||
|
|
||||||
|
// Get all sortable tables
|
||||||
|
const sortableTables = document.querySelectorAll('table.sortable');
|
||||||
|
|
||||||
|
sortableTables.forEach(table => {
|
||||||
|
const thead = table.querySelector('thead');
|
||||||
|
const tbody = table.querySelector('tbody');
|
||||||
|
const thList = thead ? thead.querySelectorAll('th') : [];
|
||||||
|
|
||||||
|
// Add click event to each header cell
|
||||||
|
thList.forEach((th, columnIndex) => {
|
||||||
|
// Skip if the header spans multiple rows or columns
|
||||||
|
if (th.hasAttribute('rowspan') || th.hasAttribute('colspan')) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add sort indicator and cursor style
|
||||||
|
th.style.cursor = 'pointer';
|
||||||
|
th.innerHTML = `${th.innerHTML} <span class="sort-indicator"></span>`;
|
||||||
|
|
||||||
|
// Add click event
|
||||||
|
th.addEventListener('click', () => {
|
||||||
|
const isAscending = th.classList.contains('sort-asc');
|
||||||
|
|
||||||
|
// Remove sort classes from all headers
|
||||||
|
thList.forEach(header => {
|
||||||
|
header.classList.remove('sort-asc', 'sort-desc');
|
||||||
|
const indicator = header.querySelector('.sort-indicator');
|
||||||
|
if (indicator) {
|
||||||
|
indicator.textContent = '';
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Set sort direction
|
||||||
|
if (isAscending) {
|
||||||
|
th.classList.add('sort-desc');
|
||||||
|
th.querySelector('.sort-indicator').textContent = ' ▼';
|
||||||
|
} else {
|
||||||
|
th.classList.add('sort-asc');
|
||||||
|
th.querySelector('.sort-indicator').textContent = ' ▲';
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get all rows from tbody
|
||||||
|
const rows = Array.from(tbody.querySelectorAll('tr'));
|
||||||
|
|
||||||
|
// Sort rows
|
||||||
|
rows.sort((rowA, rowB) => {
|
||||||
|
const cellA = rowA.querySelectorAll('td')[columnIndex];
|
||||||
|
const cellB = rowB.querySelectorAll('td')[columnIndex];
|
||||||
|
|
||||||
|
if (!cellA || !cellB) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
const valueA = cellA.textContent.trim();
|
||||||
|
const valueB = cellB.textContent.trim();
|
||||||
|
|
||||||
|
// Check if values are numbers
|
||||||
|
const numA = parseFloat(valueA);
|
||||||
|
const numB = parseFloat(valueB);
|
||||||
|
|
||||||
|
if (!isNaN(numA) && !isNaN(numB)) {
|
||||||
|
return isAscending ? numB - numA : numA - numB;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sort as strings
|
||||||
|
return isAscending
|
||||||
|
? valueB.localeCompare(valueA, undefined, {sensitivity: 'base'})
|
||||||
|
: valueA.localeCompare(valueB, undefined, {sensitivity: 'base'});
|
||||||
|
});
|
||||||
|
|
||||||
|
// Reorder rows in the table
|
||||||
|
rows.forEach(row => {
|
||||||
|
tbody.appendChild(row);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
|
@ -8,6 +8,44 @@ use Symfony\Component\Routing\Annotation\Route;
|
||||||
|
|
||||||
class WikiController extends AbstractController
|
class WikiController extends AbstractController
|
||||||
{
|
{
|
||||||
|
/**
|
||||||
|
* Displays the evolution of decrepitude scores from JSON history data
|
||||||
|
*/
|
||||||
|
#[Route('/wiki/decrepitude', name: 'app_admin_wiki_decrepitude')]
|
||||||
|
public function decrepitudeScores(): Response
|
||||||
|
{
|
||||||
|
$outdatedPagesFile = $this->getParameter('kernel.project_dir') . '/wiki_compare/outdated_pages.json';
|
||||||
|
$histogramFile = $this->getParameter('kernel.project_dir') . '/wiki_compare/staleness_histogram.png';
|
||||||
|
|
||||||
|
$regularPages = [];
|
||||||
|
$specificPages = [];
|
||||||
|
$lastUpdated = null;
|
||||||
|
$histogramExists = file_exists($histogramFile);
|
||||||
|
|
||||||
|
if (file_exists($outdatedPagesFile)) {
|
||||||
|
$outdatedPagesData = json_decode(file_get_contents($outdatedPagesFile), true);
|
||||||
|
|
||||||
|
if (isset($outdatedPagesData['regular_pages']) && is_array($outdatedPagesData['regular_pages'])) {
|
||||||
|
$regularPages = $outdatedPagesData['regular_pages'];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isset($outdatedPagesData['specific_pages']) && is_array($outdatedPagesData['specific_pages'])) {
|
||||||
|
$specificPages = $outdatedPagesData['specific_pages'];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isset($outdatedPagesData['last_updated'])) {
|
||||||
|
$lastUpdated = $outdatedPagesData['last_updated'];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->render('admin/wiki_decrepitude.html.twig', [
|
||||||
|
'regular_pages' => $regularPages,
|
||||||
|
'specific_pages' => $specificPages,
|
||||||
|
'last_updated' => $lastUpdated,
|
||||||
|
'histogram_exists' => $histogramExists,
|
||||||
|
'json_exists' => file_exists($outdatedPagesFile)
|
||||||
|
]);
|
||||||
|
}
|
||||||
/**
|
/**
|
||||||
* Detects incorrect heading hierarchies in a list of sections
|
* Detects incorrect heading hierarchies in a list of sections
|
||||||
* For example, h4 directly under h2 without h3 in between
|
* For example, h4 directly under h2 without h3 in between
|
||||||
|
@ -284,8 +322,24 @@ class WikiController extends AbstractController
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Remove duplicates based on page title
|
||||||
|
$uniquePages = [];
|
||||||
|
$seenTitles = [];
|
||||||
|
|
||||||
|
foreach ($untranslatedPages as $page) {
|
||||||
|
if (!isset($seenTitles[$page['title']])) {
|
||||||
|
$seenTitles[$page['title']] = true;
|
||||||
|
$uniquePages[] = $page;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sort pages by title
|
||||||
|
usort($uniquePages, function($a, $b) {
|
||||||
|
return strcasecmp($a['title'], $b['title']);
|
||||||
|
});
|
||||||
|
|
||||||
return $this->render('admin/wiki_missing_translations.html.twig', [
|
return $this->render('admin/wiki_missing_translations.html.twig', [
|
||||||
'untranslated_pages' => $untranslatedPages,
|
'untranslated_pages' => $uniquePages,
|
||||||
'last_updated' => $lastUpdated
|
'last_updated' => $lastUpdated
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
@ -717,7 +771,7 @@ class WikiController extends AbstractController
|
||||||
public function createFrench(string $key): Response
|
public function createFrench(string $key): Response
|
||||||
{
|
{
|
||||||
// Construct the URLs for the English page and the French page creation form
|
// Construct the URLs for the English page and the French page creation form
|
||||||
$englishUrl = "https://wiki.openstreetmap.org/wiki/Key:{$key}";
|
$englishUrl = "https://wiki.openstreetmap.org/wiki/{$key}";
|
||||||
$frenchEditUrl = "https://wiki.openstreetmap.org/w/index.php?title=FR:{$key}&action=edit";
|
$frenchEditUrl = "https://wiki.openstreetmap.org/w/index.php?title=FR:{$key}&action=edit";
|
||||||
|
|
||||||
// Fetch the HTML content of the English page using wiki_compare.py
|
// Fetch the HTML content of the English page using wiki_compare.py
|
||||||
|
@ -910,7 +964,7 @@ EOT;
|
||||||
$pageDifferences = [];
|
$pageDifferences = [];
|
||||||
$pagesUnavailableInEnglish = [];
|
$pagesUnavailableInEnglish = [];
|
||||||
|
|
||||||
// First pass: collect all staleness scores to find min and max
|
// Collect all staleness scores for statistics
|
||||||
$stalenessScores = [];
|
$stalenessScores = [];
|
||||||
foreach ($csvData as $row) {
|
foreach ($csvData as $row) {
|
||||||
$page = array_combine($headers, $row);
|
$page = array_combine($headers, $row);
|
||||||
|
@ -919,27 +973,40 @@ EOT;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Find min and max scores for normalization
|
// Calculate statistics
|
||||||
$minScore = !empty($stalenessScores) ? min($stalenessScores) : 0;
|
$stalenessStats = [
|
||||||
$maxScore = !empty($stalenessScores) ? max($stalenessScores) : 100;
|
'count' => count($stalenessScores),
|
||||||
|
'min' => !empty($stalenessScores) ? min($stalenessScores) : 0,
|
||||||
|
'max' => !empty($stalenessScores) ? max($stalenessScores) : 0,
|
||||||
|
'mean' => 0,
|
||||||
|
'std_dev' => 0
|
||||||
|
];
|
||||||
|
|
||||||
// Second pass: process pages and normalize scores
|
// Calculate mean
|
||||||
|
if (!empty($stalenessScores)) {
|
||||||
|
$stalenessStats['mean'] = array_sum($stalenessScores) / count($stalenessScores);
|
||||||
|
|
||||||
|
// Calculate standard deviation
|
||||||
|
$variance = 0;
|
||||||
|
foreach ($stalenessScores as $score) {
|
||||||
|
$variance += pow($score - $stalenessStats['mean'], 2);
|
||||||
|
}
|
||||||
|
$stalenessStats['std_dev'] = sqrt($variance / count($stalenessScores));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Round statistics to 2 decimal places
|
||||||
|
$stalenessStats['mean'] = round($stalenessStats['mean'], 2);
|
||||||
|
$stalenessStats['std_dev'] = round($stalenessStats['std_dev'], 2);
|
||||||
|
|
||||||
|
// Process pages - use absolute values without normalization
|
||||||
foreach ($csvData as $row) {
|
foreach ($csvData as $row) {
|
||||||
$page = array_combine($headers, $row);
|
$page = array_combine($headers, $row);
|
||||||
|
|
||||||
// Normalize staleness score to 0-100 range (0 = best, 100 = worst)
|
// Use absolute values of staleness score without normalization
|
||||||
if (isset($page['staleness_score']) && is_numeric($page['staleness_score'])) {
|
if (isset($page['staleness_score']) && is_numeric($page['staleness_score'])) {
|
||||||
$originalScore = (float)$page['staleness_score'];
|
$page['staleness_score'] = abs((float)$page['staleness_score']);
|
||||||
|
|
||||||
// Avoid division by zero
|
|
||||||
if ($maxScore > $minScore) {
|
|
||||||
$normalizedScore = ($originalScore - $minScore) / ($maxScore - $minScore) * 100;
|
|
||||||
} else {
|
|
||||||
$normalizedScore = 50; // Default to middle value if all scores are the same
|
|
||||||
}
|
|
||||||
|
|
||||||
// Round to 2 decimal places
|
// Round to 2 decimal places
|
||||||
$page['staleness_score'] = round($normalizedScore, 2);
|
$page['staleness_score'] = round($page['staleness_score'], 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
$wikiPages[$page['key']][$page['language']] = $page;
|
$wikiPages[$page['key']][$page['language']] = $page;
|
||||||
|
@ -953,6 +1020,18 @@ EOT;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Prepare arrays for statistics
|
||||||
|
$stats = [
|
||||||
|
'en_sections' => [],
|
||||||
|
'fr_sections' => [],
|
||||||
|
'en_words' => [],
|
||||||
|
'fr_words' => [],
|
||||||
|
'en_links' => [],
|
||||||
|
'fr_links' => [],
|
||||||
|
'en_media' => [],
|
||||||
|
'fr_media' => []
|
||||||
|
];
|
||||||
|
|
||||||
// Calculate differences between English and French versions
|
// Calculate differences between English and French versions
|
||||||
foreach ($wikiPages as $key => $languages) {
|
foreach ($wikiPages as $key => $languages) {
|
||||||
if (isset($languages['en']) && isset($languages['fr'])) {
|
if (isset($languages['en']) && isset($languages['fr'])) {
|
||||||
|
@ -977,6 +1056,39 @@ EOT;
|
||||||
'media_diff' => $mediaDiff,
|
'media_diff' => $mediaDiff,
|
||||||
'media_diff_formatted' => ($mediaDiff >= 0 ? '+' : '') . $mediaDiff,
|
'media_diff_formatted' => ($mediaDiff >= 0 ? '+' : '') . $mediaDiff,
|
||||||
];
|
];
|
||||||
|
|
||||||
|
// Collect data for statistics
|
||||||
|
$stats['en_sections'][] = (int)$en['sections'];
|
||||||
|
$stats['fr_sections'][] = (int)$fr['sections'];
|
||||||
|
$stats['en_words'][] = (int)$en['word_count'];
|
||||||
|
$stats['fr_words'][] = (int)$fr['word_count'];
|
||||||
|
$stats['en_links'][] = (int)$en['link_count'];
|
||||||
|
$stats['fr_links'][] = (int)$fr['link_count'];
|
||||||
|
$stats['en_media'][] = isset($en['media_count']) ? (int)$en['media_count'] : 0;
|
||||||
|
$stats['fr_media'][] = isset($fr['media_count']) ? (int)$fr['media_count'] : 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Calculate statistics
|
||||||
|
$wikiPagesStats = [];
|
||||||
|
foreach ($stats as $key => $values) {
|
||||||
|
if (!empty($values)) {
|
||||||
|
$mean = array_sum($values) / count($values);
|
||||||
|
|
||||||
|
// Calculate standard deviation
|
||||||
|
$variance = 0;
|
||||||
|
foreach ($values as $value) {
|
||||||
|
$variance += pow($value - $mean, 2);
|
||||||
|
}
|
||||||
|
$stdDev = sqrt($variance / count($values));
|
||||||
|
|
||||||
|
$wikiPagesStats[$key] = [
|
||||||
|
'count' => count($values),
|
||||||
|
'min' => min($values),
|
||||||
|
'max' => max($values),
|
||||||
|
'mean' => round($mean, 2),
|
||||||
|
'std_dev' => round($stdDev, 2)
|
||||||
|
];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1022,7 +1134,9 @@ EOT;
|
||||||
'page_differences' => $pageDifferences,
|
'page_differences' => $pageDifferences,
|
||||||
'pages_unavailable_in_english' => $pagesUnavailableInEnglish,
|
'pages_unavailable_in_english' => $pagesUnavailableInEnglish,
|
||||||
'specific_pages' => $specificPages,
|
'specific_pages' => $specificPages,
|
||||||
'newly_created_pages' => $newlyCreatedPages
|
'newly_created_pages' => $newlyCreatedPages,
|
||||||
|
'staleness_stats' => $stalenessStats,
|
||||||
|
'wiki_pages_stats' => $wikiPagesStats
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1380,7 +1494,7 @@ EOT;
|
||||||
// Create URL for new French page if it doesn't exist
|
// Create URL for new French page if it doesn't exist
|
||||||
$createFrUrl = null;
|
$createFrUrl = null;
|
||||||
if (!$frPage) {
|
if (!$frPage) {
|
||||||
$createFrUrl = 'https://wiki.openstreetmap.org/wiki/FR:Key:' . $key;
|
$createFrUrl = 'https://wiki.openstreetmap.org/wiki/FR:' . $key;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Format section titles for copy functionality
|
// Format section titles for copy functionality
|
||||||
|
|
|
@ -51,6 +51,11 @@
|
||||||
<i class="bi bi-clock-history"></i> Changements récents
|
<i class="bi bi-clock-history"></i> Changements récents
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
|
<li class="nav-item">
|
||||||
|
<a class="nav-link {% if app.request.get('_route') == 'app_admin_wiki_decrepitude' %}active{% endif %}" href="{{ path('app_admin_wiki_decrepitude') }}">
|
||||||
|
<i class="bi bi-graph-up"></i> Scores de décrépitude
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -20,6 +20,31 @@
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
|
{% if wiki_pages_stats is defined %}
|
||||||
|
<div class="alert alert-info mb-3">
|
||||||
|
<h4>Statistiques des pages wiki</h4>
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-md-6">
|
||||||
|
<h5>Pages en anglais</h5>
|
||||||
|
<ul>
|
||||||
|
<li><strong>Sections :</strong> Moyenne: {{ wiki_pages_stats.en_sections.mean }}, Écart type: {{ wiki_pages_stats.en_sections.std_dev }}</li>
|
||||||
|
<li><strong>Mots :</strong> Moyenne: {{ wiki_pages_stats.en_words.mean }}, Écart type: {{ wiki_pages_stats.en_words.std_dev }}</li>
|
||||||
|
<li><strong>Liens :</strong> Moyenne: {{ wiki_pages_stats.en_links.mean }}, Écart type: {{ wiki_pages_stats.en_links.std_dev }}</li>
|
||||||
|
<li><strong>Images :</strong> Moyenne: {{ wiki_pages_stats.en_media.mean }}, Écart type: {{ wiki_pages_stats.en_media.std_dev }}</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
<div class="col-md-6">
|
||||||
|
<h5>Pages en français</h5>
|
||||||
|
<ul>
|
||||||
|
<li><strong>Sections :</strong> Moyenne: {{ wiki_pages_stats.fr_sections.mean }}, Écart type: {{ wiki_pages_stats.fr_sections.std_dev }}</li>
|
||||||
|
<li><strong>Mots :</strong> Moyenne: {{ wiki_pages_stats.fr_words.mean }}, Écart type: {{ wiki_pages_stats.fr_words.std_dev }}</li>
|
||||||
|
<li><strong>Liens :</strong> Moyenne: {{ wiki_pages_stats.fr_links.mean }}, Écart type: {{ wiki_pages_stats.fr_links.std_dev }}</li>
|
||||||
|
<li><strong>Images :</strong> Moyenne: {{ wiki_pages_stats.fr_media.mean }}, Écart type: {{ wiki_pages_stats.fr_media.std_dev }}</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
<div class="table-responsive">
|
<div class="table-responsive">
|
||||||
<table class="table table-striped table-hover">
|
<table class="table table-striped table-hover">
|
||||||
<thead class="thead-dark">
|
<thead class="thead-dark">
|
||||||
|
@ -283,12 +308,13 @@
|
||||||
<thead class="thead-dark">
|
<thead class="thead-dark">
|
||||||
<tr>
|
<tr>
|
||||||
<th>Titre</th>
|
<th>Titre</th>
|
||||||
<th>Score de décrépitude</th>
|
{# <th>Score de décrépitude</th>#}
|
||||||
<th>Actions</th>
|
<th>Actions</th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
{% for page in pages_unavailable_in_english %}
|
{% for page in pages_unavailable_in_english %}
|
||||||
|
{% if "FR:Réunions" not in page.title %}
|
||||||
<tr>
|
<tr>
|
||||||
<td>
|
<td>
|
||||||
<div class="d-flex align-items-center">
|
<div class="d-flex align-items-center">
|
||||||
|
@ -303,22 +329,22 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</td>
|
</td>
|
||||||
<td>
|
{# <td>#}
|
||||||
{% if page.outdatedness_score is defined %}
|
{# {% if page.outdatedness_score is defined %}#}
|
||||||
<div class="progress" style="height: 20px;">
|
{# <div class="progress" style="height: 20px;">#}
|
||||||
{% set score_class = page.outdatedness_score > 70 ? 'bg-danger' : (page.outdatedness_score > 40 ? 'bg-warning' : 'bg-success') %}
|
{# {% set score_class = page.outdatedness_score > 70 ? 'bg-danger' : (page.outdatedness_score > 40 ? 'bg-warning' : 'bg-success') %}#}
|
||||||
<div class="progress-bar {{ score_class }}" role="progressbar"
|
{# <div class="progress-bar {{ score_class }}" role="progressbar"#}
|
||||||
style="width: {{ page.outdatedness_score }}%;"
|
{# style="width: {{ page.outdatedness_score }}%;"#}
|
||||||
aria-valuenow="{{ page.outdatedness_score }}"
|
{# aria-valuenow="{{ page.outdatedness_score }}"#}
|
||||||
aria-valuemin="0"
|
{# aria-valuemin="0"#}
|
||||||
aria-valuemax="100">
|
{# aria-valuemax="100">#}
|
||||||
{{ page.outdatedness_score }}
|
{# {{ page.outdatedness_score }}#}
|
||||||
</div>
|
{# </div>#}
|
||||||
</div>
|
{# </div>#}
|
||||||
{% else %}
|
{# {% else %}#}
|
||||||
<span class="text-muted">Non disponible</span>
|
{# <span class="text-muted">Non disponible</span>#}
|
||||||
{% endif %}
|
{# {% endif %}#}
|
||||||
</td>
|
{# </td>#}
|
||||||
<td class="text-center">
|
<td class="text-center">
|
||||||
<div class="btn-group" role="group">
|
<div class="btn-group" role="group">
|
||||||
<a href="{{ page.url }}" target="_blank"
|
<a href="{{ page.url }}" target="_blank"
|
||||||
|
@ -334,6 +360,7 @@
|
||||||
</div>
|
</div>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
{% endif %}
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
|
@ -413,6 +440,16 @@
|
||||||
<h2>Graphe de décrépitude</h2>
|
<h2>Graphe de décrépitude</h2>
|
||||||
</div>
|
</div>
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
|
{% if staleness_stats is defined %}
|
||||||
|
<div class="alert alert-info mb-3">
|
||||||
|
<strong>Statistiques :</strong>
|
||||||
|
Moyenne : {{ staleness_stats.mean }} |
|
||||||
|
Écart type : {{ staleness_stats.std_dev }} |
|
||||||
|
Min : {{ staleness_stats.min }} |
|
||||||
|
Max : {{ staleness_stats.max }} |
|
||||||
|
Nombre de pages : {{ staleness_stats.count }}
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
<canvas id="decrepitudeChart" height="300"></canvas>
|
<canvas id="decrepitudeChart" height="300"></canvas>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -436,13 +473,19 @@
|
||||||
{% set score = languages['en'].staleness_score|default(0) %}
|
{% set score = languages['en'].staleness_score|default(0) %}
|
||||||
scores.push({{ score }});
|
scores.push({{ score }});
|
||||||
|
|
||||||
// Set color based on score
|
// Set color based on score with more nuanced intermediate colors
|
||||||
{% if score > 50 %}
|
{% if score > 80 %}
|
||||||
colors.push('rgba(220, 53, 69, 0.7)'); // danger
|
colors.push('rgba(220, 53, 69, 0.7)'); // danger (red)
|
||||||
|
{% elseif score > 60 %}
|
||||||
|
colors.push('rgba(232, 113, 55, 0.7)'); // dark orange
|
||||||
|
{% elseif score > 40 %}
|
||||||
|
colors.push('rgba(255, 153, 0, 0.7)'); // orange
|
||||||
{% elseif score > 20 %}
|
{% elseif score > 20 %}
|
||||||
colors.push('rgba(255, 193, 7, 0.7)'); // warning
|
colors.push('rgba(255, 193, 7, 0.7)'); // warning (yellow)
|
||||||
|
{% elseif score > 10 %}
|
||||||
|
colors.push('rgba(140, 195, 38, 0.7)'); // light green
|
||||||
{% else %}
|
{% else %}
|
||||||
colors.push('rgba(25, 135, 84, 0.7)'); // success
|
colors.push('rgba(25, 135, 84, 0.7)'); // success (green)
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
|
|
|
@ -112,8 +112,8 @@
|
||||||
<a href="{{ fr_page.url|default('https://wiki.openstreetmap.org/wiki/FR:' ~ key) }}">fr</a>
|
<a href="{{ fr_page.url|default('https://wiki.openstreetmap.org/wiki/FR:' ~ key) }}">fr</a>
|
||||||
<a href="{{ en_page.url }}">en</a>
|
<a href="{{ en_page.url }}">en</a>
|
||||||
{% else %}
|
{% else %}
|
||||||
<a href="https://wiki.openstreetmap.org/wiki/FR:Key:{{ key }}">fr</a>
|
<a href="https://wiki.openstreetmap.org/wiki/FR:{{ key }}">fr</a>
|
||||||
<a href="https://wiki.openstreetmap.org/wiki/Key:{{ key }}">en</a>
|
<a href="https://wiki.openstreetmap.org/wiki/{{ key }}">en</a>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</h1>
|
</h1>
|
||||||
|
|
||||||
|
@ -738,164 +738,164 @@
|
||||||
{# {% endif %} #}
|
{# {% endif %} #}
|
||||||
|
|
||||||
|
|
||||||
{# <div class="card mb-4"> #}
|
<div class="card mb-4">
|
||||||
{# <div class="card-header"> #}
|
<div class="card-header">
|
||||||
{# <h2>Score de décrépitude</h2> #}
|
<h2>Score de décrépitude</h2>
|
||||||
{# </div> #}
|
</div>
|
||||||
{# <div class="card-body"> #}
|
<div class="card-body">
|
||||||
{# <p>Le score de décrépitude est calculé en prenant en compte plusieurs facteurs, avec une pondération #}
|
<p>Le score de décrépitude est calculé en prenant en compte plusieurs facteurs, avec une pondération
|
||||||
{# plus importante pour la différence de nombre de mots :</p> #}
|
plus importante pour la différence de nombre de mots :</p>
|
||||||
|
|
||||||
{# <div class="table-responsive"> #}
|
<div class="table-responsive">
|
||||||
{# <table class="table table-striped"> #}
|
<table class="table table-striped">
|
||||||
{# <thead> #}
|
<thead>
|
||||||
{# <tr> #}
|
<tr>
|
||||||
{# <th>Facteur</th> #}
|
<th>Facteur</th>
|
||||||
{# <th>Valeur</th> #}
|
<th>Valeur</th>
|
||||||
{# <th>Poids</th> #}
|
<th>Poids</th>
|
||||||
{# <th>Contribution</th> #}
|
<th>Contribution</th>
|
||||||
{# </tr> #}
|
</tr>
|
||||||
{# </thead> #}
|
</thead>
|
||||||
{# <tbody> #}
|
<tbody>
|
||||||
{# {% for key, component in score_components %} #}
|
{% for key, component in score_components %}
|
||||||
{# <tr> #}
|
<tr>
|
||||||
{# <td>{{ component.description }}</td> #}
|
<td>{{ component.description }}</td>
|
||||||
{# <td>{{ component.value }}</td> #}
|
<td>{{ component.value }}</td>
|
||||||
{# <td>{{ component.weight * 100 }}%</td> #}
|
<td>{{ component.weight * 100 }}%</td>
|
||||||
{# <td>{{ component.component|round(2) }}</td> #}
|
<td>{{ component.component|round(2) }}</td>
|
||||||
{# </tr> #}
|
</tr>
|
||||||
{# {% endfor %} #}
|
{% endfor %}
|
||||||
{# <tr class="table-dark"> #}
|
<tr class="table-dark">
|
||||||
{# <td colspan="3"><strong>Score total</strong></td> #}
|
<td colspan="3"><strong>Score total</strong></td>
|
||||||
{# <td> #}
|
<td>
|
||||||
{# {% set total_score = 0 %} #}
|
{% set total_score = 0 %}
|
||||||
{# {% for key, component in score_components %} #}
|
{% for key, component in score_components %}
|
||||||
{# {% set total_score = total_score + component.component %} #}
|
{% set total_score = total_score + component.component %}
|
||||||
{# {% endfor %} #}
|
{% endfor %}
|
||||||
{# <strong>{{ total_score|round(2) }}</strong> #}
|
<strong>{{ total_score|round(2) }}</strong>
|
||||||
{# </td> #}
|
</td>
|
||||||
{# </tr> #}
|
</tr>
|
||||||
{# </tbody> #}
|
</tbody>
|
||||||
{# </table> #}
|
</table>
|
||||||
{# </div> #}
|
</div>
|
||||||
|
|
||||||
{# <div class="alert alert-info"> #}
|
<div class="alert alert-info">
|
||||||
{# <p><strong>Comment interpréter ce score :</strong></p> #}
|
<p><strong>Comment interpréter ce score :</strong></p>
|
||||||
{# <ul> #}
|
<ul>
|
||||||
{# <li>Plus le score est élevé, plus la page française est considérée comme "décrépite" par rapport #}
|
<li>Plus le score est élevé, plus la page française est considérée comme "décrépite" par rapport
|
||||||
{# à la version anglaise. #}
|
à la version anglaise.
|
||||||
{# </li> #}
|
</li>
|
||||||
{# <li>La différence de nombre de mots compte pour 50% du score, car c'est l'indicateur le plus #}
|
<li>La différence de nombre de mots compte pour 50% du score, car c'est l'indicateur le plus
|
||||||
{# important de la complétude de la traduction. #}
|
important de la complétude de la traduction.
|
||||||
{# </li> #}
|
</li>
|
||||||
{# <li>Les différences de sections (15%), de liens (15%) et de date de modification (20%) #}
|
<li>Les différences de sections (15%), de liens (15%) et de date de modification (20%)
|
||||||
{# complètent le score. #}
|
complètent le score.
|
||||||
{# </li> #}
|
</li>
|
||||||
{# </ul> #}
|
</ul>
|
||||||
{# </div> #}
|
</div>
|
||||||
{# </div> #}
|
</div>
|
||||||
{# </div> #}
|
</div>
|
||||||
|
|
||||||
{# <div class="mt-3"> #}
|
<div class="mt-3">
|
||||||
{# <a href="{{ path('app_admin_wiki') }}" class="btn btn-secondary"> #}
|
<a href="{{ path('app_admin_wiki') }}" class="btn btn-secondary">
|
||||||
{# <i class="bi bi-arrow-left"></i> Retour à la liste des pages wiki #}
|
<i class="bi bi-arrow-left"></i> Retour à la liste des pages wiki
|
||||||
{# </a> #}
|
</a>
|
||||||
{# </div> #}
|
</div>
|
||||||
{# <div class="card mb-4"> #}
|
<div class="card mb-4">
|
||||||
{# <div class="card-header"> #}
|
<div class="card-header">
|
||||||
{# <h2>Comparaison des versions</h2> #}
|
<h2>Comparaison des versions</h2>
|
||||||
{# </div> #}
|
</div>
|
||||||
{# <div class="card-body"> #}
|
<div class="card-body">
|
||||||
{# <div class="row"> #}
|
<div class="row">
|
||||||
{# <div class="col-md-6"> #}
|
<div class="col-md-6">
|
||||||
{# <div class="card h-100"> #}
|
<div class="card h-100">
|
||||||
{# <div class="card-header bg-primary text-white"> #}
|
<div class="card-header bg-primary text-white">
|
||||||
{# <h3>Version anglaise</h3> #}
|
<h3>Version anglaise</h3>
|
||||||
{# <p class="mb-0"> #}
|
<p class="mb-0">
|
||||||
{# <small>Dernière modification: {{ en_page.last_modified }}</small> #}
|
<small>Dernière modification: {{ en_page.last_modified }}</small>
|
||||||
{# </p> #}
|
</p>
|
||||||
{# </div> #}
|
</div>
|
||||||
{# <div class="card-body"> #}
|
<div class="card-body">
|
||||||
{# <ul class="list-group mb-3"> #}
|
<ul class="list-group mb-3">
|
||||||
{# <li class="list-group-item d-flex justify-content-between align-items-center"> #}
|
<li class="list-group-item d-flex justify-content-between align-items-center">
|
||||||
{# Sections #}
|
Sections
|
||||||
{# <span class="badge bg-primary rounded-pill"> #}
|
<span class="badge bg-primary rounded-pill">
|
||||||
{# {% if detailed_comparison.adjusted_en_section_count is defined %} #}
|
{% if detailed_comparison.adjusted_en_section_count is defined %}
|
||||||
{# {{ detailed_comparison.adjusted_en_section_count }} #}
|
{{ detailed_comparison.adjusted_en_section_count }}
|
||||||
{# {% else %} #}
|
{% else %}
|
||||||
{# {{ en_page.sections }} #}
|
{{ en_page.sections }}
|
||||||
{# {% endif %} #}
|
{% endif %}
|
||||||
{# </span> #}
|
</span>
|
||||||
{# </li> #}
|
</li>
|
||||||
{# <li class="list-group-item d-flex justify-content-between align-items-center"> #}
|
<li class="list-group-item d-flex justify-content-between align-items-center">
|
||||||
{# Mots #}
|
Mots
|
||||||
{# <span class="badge bg-primary rounded-pill">{{ en_page.word_count }}</span> #}
|
<span class="badge bg-primary rounded-pill">{{ en_page.word_count }}</span>
|
||||||
{# </li> #}
|
</li>
|
||||||
{# <li class="list-group-item d-flex justify-content-between align-items-center"> #}
|
<li class="list-group-item d-flex justify-content-between align-items-center">
|
||||||
{# Liens #}
|
Liens
|
||||||
{# <span class="badge bg-primary rounded-pill">{{ en_page.link_count }}</span> #}
|
<span class="badge bg-primary rounded-pill">{{ en_page.link_count }}</span>
|
||||||
{# </li> #}
|
</li>
|
||||||
{# </ul> #}
|
</ul>
|
||||||
{# <div class="d-grid gap-2"> #}
|
<div class="d-grid gap-2">
|
||||||
{# <a href="{{ en_page.url }}" target="_blank" class="btn btn-outline-primary"> #}
|
<a href="{{ en_page.url }}" target="_blank" class="btn btn-outline-primary">
|
||||||
{# <i class="bi bi-box-arrow-up-right"></i> Voir la page #}
|
<i class="bi bi-box-arrow-up-right"></i> Voir la page
|
||||||
{# </a> #}
|
</a>
|
||||||
{# <button class="btn btn-outline-secondary copy-btn" data-content="sections-en"> #}
|
<button class="btn btn-outline-secondary copy-btn" data-content="sections-en">
|
||||||
{# <i class="bi bi-clipboard"></i> Copier la liste des sections #}
|
<i class="bi bi-clipboard"></i> Copier la liste des sections
|
||||||
{# </button> #}
|
</button>
|
||||||
{# <button class="btn btn-outline-secondary copy-btn" data-content="links-en"> #}
|
<button class="btn btn-outline-secondary copy-btn" data-content="links-en">
|
||||||
{# <i class="bi bi-clipboard"></i> Copier la liste des liens #}
|
<i class="bi bi-clipboard"></i> Copier la liste des liens
|
||||||
{# </button> #}
|
</button>
|
||||||
{# </div> #}
|
</div>
|
||||||
{# </div> #}
|
</div>
|
||||||
{# </div> #}
|
</div>
|
||||||
{# </div> #}
|
</div>
|
||||||
{# <div class="col-md-6"> #}
|
<div class="col-md-6">
|
||||||
{# <div class="card h-100"> #}
|
<div class="card h-100">
|
||||||
{# <div class="card-header bg-info text-white"> #}
|
<div class="card-header bg-info text-white">
|
||||||
{# <h3>Version française</h3> #}
|
<h3>Version française</h3>
|
||||||
{# <p class="mb-0"> #}
|
<p class="mb-0">
|
||||||
{# <small>Dernière modification: {{ fr_page.last_modified }}</small> #}
|
<small>Dernière modification: {{ fr_page.last_modified }}</small>
|
||||||
{# </p> #}
|
</p>
|
||||||
{# </div> #}
|
</div>
|
||||||
{# <div class="card-body"> #}
|
<div class="card-body">
|
||||||
{# <ul class="list-group mb-3"> #}
|
<ul class="list-group mb-3">
|
||||||
{# <li class="list-group-item d-flex justify-content-between align-items-center"> #}
|
<li class="list-group-item d-flex justify-content-between align-items-center">
|
||||||
{# Sections #}
|
Sections
|
||||||
{# <span class="badge bg-info rounded-pill"> #}
|
<span class="badge bg-info rounded-pill">
|
||||||
{# {% if detailed_comparison.adjusted_fr_section_count is defined %} #}
|
{% if detailed_comparison.adjusted_fr_section_count is defined %}
|
||||||
{# {{ detailed_comparison.adjusted_fr_section_count }} #}
|
{{ detailed_comparison.adjusted_fr_section_count }}
|
||||||
{# {% else %} #}
|
{% else %}
|
||||||
{# {{ fr_page.sections }} #}
|
{{ fr_page.sections }}
|
||||||
{# {% endif %} #}
|
{% endif %}
|
||||||
{# </span> #}
|
</span>
|
||||||
{# </li> #}
|
</li>
|
||||||
{# <li class="list-group-item d-flex justify-content-between align-items-center"> #}
|
<li class="list-group-item d-flex justify-content-between align-items-center">
|
||||||
{# Mots #}
|
Mots
|
||||||
{# <span class="badge bg-info rounded-pill">{{ fr_page.word_count }}</span> #}
|
<span class="badge bg-info rounded-pill">{{ fr_page.word_count }}</span>
|
||||||
{# </li> #}
|
</li>
|
||||||
{# <li class="list-group-item d-flex justify-content-between align-items-center"> #}
|
<li class="list-group-item d-flex justify-content-between align-items-center">
|
||||||
{# Liens #}
|
Liens
|
||||||
{# <span class="badge bg-info rounded-pill">{{ fr_page.link_count }}</span> #}
|
<span class="badge bg-info rounded-pill">{{ fr_page.link_count }}</span>
|
||||||
{# </li> #}
|
</li>
|
||||||
{# </ul> #}
|
</ul>
|
||||||
{# <div class="d-grid gap-2"> #}
|
<div class="d-grid gap-2">
|
||||||
{# <a href="{{ fr_page.url }}" target="_blank" class="btn btn-outline-info"> #}
|
<a href="{{ fr_page.url }}" target="_blank" class="btn btn-outline-info">
|
||||||
{# <i class="bi bi-box-arrow-up-right"></i> Voir la page #}
|
<i class="bi bi-box-arrow-up-right"></i> Voir la page
|
||||||
{# </a> #}
|
</a>
|
||||||
{# <button class="btn btn-outline-secondary copy-btn" data-content="sections-fr"> #}
|
<button class="btn btn-outline-secondary copy-btn" data-content="sections-fr">
|
||||||
{# <i class="bi bi-clipboard"></i> Copier la liste des sections #}
|
<i class="bi bi-clipboard"></i> Copier la liste des sections
|
||||||
{# </button> #}
|
</button>
|
||||||
{# <button class="btn btn-outline-secondary copy-btn" data-content="links-fr"> #}
|
<button class="btn btn-outline-secondary copy-btn" data-content="links-fr">
|
||||||
{# <i class="bi bi-clipboard"></i> Copier la liste des liens #}
|
<i class="bi bi-clipboard"></i> Copier la liste des liens
|
||||||
{# </button> #}
|
</button>
|
||||||
{# </div> #}
|
</div>
|
||||||
{# </div> #}
|
</div>
|
||||||
{# </div> #}
|
</div>
|
||||||
{# </div> #}
|
</div>
|
||||||
{# </div> #}
|
</div>
|
||||||
{# </div> #}
|
</div>
|
||||||
{# </div> #}
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Hidden content for copy functionality -->
|
<!-- Hidden content for copy functionality -->
|
||||||
|
|
325
templates/admin/wiki_decrepitude.html.twig
Normal file
325
templates/admin/wiki_decrepitude.html.twig
Normal file
|
@ -0,0 +1,325 @@
|
||||||
|
{% extends 'base.html.twig' %}
|
||||||
|
|
||||||
|
{% block title %}Évolution des scores de décrépitude - Wiki OSM{% endblock %}
|
||||||
|
|
||||||
|
{% block body %}
|
||||||
|
<div class="container mt-4">
|
||||||
|
{% include 'admin/_wiki_navigation.html.twig' %}
|
||||||
|
|
||||||
|
<h1>Évolution des scores de décrépitude</h1>
|
||||||
|
<p class="lead">
|
||||||
|
Cette page montre l'évolution des scores de décrépitude des pages wiki OpenStreetMap en français par rapport aux versions anglaises.
|
||||||
|
<a href="https://forum.openstreetmap.fr/t/fabriquer-un-outil-de-qualite-pour-le-wiki-osm/36814">
|
||||||
|
Venez discuter QualiWiki sur le forum
|
||||||
|
</a>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
{% if not json_exists %}
|
||||||
|
<div class="alert alert-warning">
|
||||||
|
<h4 class="alert-heading">Données manquantes</h4>
|
||||||
|
<p>Le fichier JSON contenant les données de décrépitude n'existe pas. Vous pouvez le générer en exécutant le script Python suivant :</p>
|
||||||
|
<pre class="bg-light p-3 rounded"><code>cd {{ app.request.server.get('DOCUMENT_ROOT')|replace({'/public': ''}) }}/wiki_compare
|
||||||
|
python3 wiki_compare.py</code></pre>
|
||||||
|
<p>Ce script va analyser les pages wiki et générer les fichiers nécessaires, y compris le fichier <code>outdated_pages.json</code> et l'histogramme.</p>
|
||||||
|
</div>
|
||||||
|
{% else %}
|
||||||
|
{% if last_updated %}
|
||||||
|
<div class="alert alert-info">
|
||||||
|
<p>Dernière mise à jour des données : {{ last_updated|date('d/m/Y H:i:s') }}</p>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{% if histogram_exists %}
|
||||||
|
<div class="card mb-4">
|
||||||
|
<div class="card-header">
|
||||||
|
<h2>Histogramme des scores de décrépitude</h2>
|
||||||
|
</div>
|
||||||
|
<div class="card-body text-center">
|
||||||
|
<img src="{{ asset('wiki_compare/staleness_histogram.png') }}" alt="Histogramme des scores de décrépitude" class="img-fluid">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
<div class="card mb-4">
|
||||||
|
<div class="card-header">
|
||||||
|
<h2>Évolution des scores de décrépitude</h2>
|
||||||
|
</div>
|
||||||
|
<div class="card-body">
|
||||||
|
<p>Le score de décrépitude est calculé en prenant en compte plusieurs facteurs :</p>
|
||||||
|
<ul>
|
||||||
|
<li>La différence de date entre les versions anglaise et française (20%)</li>
|
||||||
|
<li>La différence de nombre de mots entre les versions (50%)</li>
|
||||||
|
<li>La différence de nombre de sections entre les versions (15%)</li>
|
||||||
|
<li>La différence de nombre de liens entre les versions (15%)</li>
|
||||||
|
</ul>
|
||||||
|
<p>Plus le score est élevé, plus la page française est considérée comme "décrépite" par rapport à sa version anglaise.</p>
|
||||||
|
|
||||||
|
<canvas id="decrepitudeChart" height="300"></canvas>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="card mb-4">
|
||||||
|
<div class="card-header bg-warning text-dark">
|
||||||
|
<h2>Pages régulières avec les scores de décrépitude les plus élevés</h2>
|
||||||
|
</div>
|
||||||
|
<div class="card-body">
|
||||||
|
<div class="table-responsive">
|
||||||
|
<table class="table table-striped table-hover">
|
||||||
|
<thead class="thead-dark">
|
||||||
|
<tr>
|
||||||
|
<th>Clé</th>
|
||||||
|
<th>Raison</th>
|
||||||
|
<th>Différence de mots</th>
|
||||||
|
<th>Différence de sections</th>
|
||||||
|
<th>Différence de liens</th>
|
||||||
|
<th>Score de décrépitude</th>
|
||||||
|
<th>Actions</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
{% for page in regular_pages|slice(0, 20) %}
|
||||||
|
<tr>
|
||||||
|
<td><strong>{{ page.key }}</strong></td>
|
||||||
|
<td>{{ page.reason }}</td>
|
||||||
|
<td class="text-center">
|
||||||
|
{% if page.word_diff > 0 %}
|
||||||
|
<span class="badge bg-danger">{{ page.word_diff }}</span>
|
||||||
|
{% elseif page.word_diff < 0 %}
|
||||||
|
<span class="badge bg-success">{{ page.word_diff }}</span>
|
||||||
|
{% else %}
|
||||||
|
<span class="badge bg-secondary">0</span>
|
||||||
|
{% endif %}
|
||||||
|
</td>
|
||||||
|
<td class="text-center">
|
||||||
|
{% if page.section_diff > 0 %}
|
||||||
|
<span class="badge bg-danger">{{ page.section_diff }}</span>
|
||||||
|
{% elseif page.section_diff < 0 %}
|
||||||
|
<span class="badge bg-success">{{ page.section_diff }}</span>
|
||||||
|
{% else %}
|
||||||
|
<span class="badge bg-secondary">0</span>
|
||||||
|
{% endif %}
|
||||||
|
</td>
|
||||||
|
<td class="text-center">
|
||||||
|
{% if page.link_diff > 0 %}
|
||||||
|
<span class="badge bg-danger">{{ page.link_diff }}</span>
|
||||||
|
{% elseif page.link_diff < 0 %}
|
||||||
|
<span class="badge bg-success">{{ page.link_diff }}</span>
|
||||||
|
{% else %}
|
||||||
|
<span class="badge bg-secondary">0</span>
|
||||||
|
{% endif %}
|
||||||
|
</td>
|
||||||
|
<td class="text-center">
|
||||||
|
<div class="progress" style="height: 20px;">
|
||||||
|
{% set score_class = page.staleness_score > 70 ? 'bg-danger' : (page.staleness_score > 40 ? 'bg-warning' : 'bg-success') %}
|
||||||
|
<div class="progress-bar {{ score_class }}" role="progressbar"
|
||||||
|
style="width: {{ page.staleness_score }}%;"
|
||||||
|
aria-valuenow="{{ page.staleness_score }}"
|
||||||
|
aria-valuemin="0"
|
||||||
|
aria-valuemax="100">
|
||||||
|
{{ page.staleness_score }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
<td class="text-center">
|
||||||
|
<div class="btn-group" role="group">
|
||||||
|
<a href="{{ page.en_page.url }}" target="_blank"
|
||||||
|
class="btn btn-sm btn-outline-primary" title="Version anglaise">
|
||||||
|
<i class="bi bi-translate"></i> EN
|
||||||
|
</a>
|
||||||
|
{% if page.fr_page %}
|
||||||
|
<a href="{{ page.fr_page.url }}" target="_blank"
|
||||||
|
class="btn btn-sm btn-outline-info" title="Version française">
|
||||||
|
<i class="bi bi-translate"></i> FR
|
||||||
|
</a>
|
||||||
|
<a href="{{ path('app_admin_wiki_compare', {'key': page.key}) }}"
|
||||||
|
class="btn btn-sm btn-outline-secondary"
|
||||||
|
title="Comparer les versions">
|
||||||
|
<i class="bi bi-arrows-angle-expand"></i> Comparer
|
||||||
|
</a>
|
||||||
|
{% else %}
|
||||||
|
<a href="{{ path('app_admin_wiki_create_french', {'key': page.key}) }}"
|
||||||
|
class="btn btn-sm btn-success"
|
||||||
|
title="Créer une traduction française">
|
||||||
|
<i class="bi bi-plus-circle"></i> Traduire
|
||||||
|
</a>
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
{% endfor %}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{% if specific_pages|length > 0 %}
|
||||||
|
<div class="card mb-4">
|
||||||
|
<div class="card-header bg-primary text-white">
|
||||||
|
<h2>Pages spécifiques avec scores de décrépitude ({{ specific_pages|length }})</h2>
|
||||||
|
</div>
|
||||||
|
<div class="card-body">
|
||||||
|
<p>Ces pages wiki sont des pages spécifiques qui ont été sélectionnées pour une comparaison particulière.</p>
|
||||||
|
<div class="table-responsive">
|
||||||
|
<table class="table table-striped table-hover">
|
||||||
|
<thead class="thead-dark">
|
||||||
|
<tr>
|
||||||
|
<th>Titre</th>
|
||||||
|
<th>Raison</th>
|
||||||
|
<th>Score de décrépitude</th>
|
||||||
|
<th>Actions</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
{% for page in specific_pages %}
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
<div class="d-flex align-items-center">
|
||||||
|
{% if page.en_page.description_img_url is defined and page.en_page.description_img_url %}
|
||||||
|
<div class="me-3">
|
||||||
|
<img src="{{ page.en_page.description_img_url }}"
|
||||||
|
alt="{{ page.key }}"
|
||||||
|
style="max-width: 80px; max-height: 60px; object-fit: contain;">
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
<div>
|
||||||
|
<strong>{{ page.key }}</strong>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
{{ page.reason }}
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<div class="progress" style="height: 20px;">
|
||||||
|
{% set score_class = page.staleness_score > 70 ? 'bg-danger' : (page.staleness_score > 40 ? 'bg-warning' : 'bg-success') %}
|
||||||
|
<div class="progress-bar {{ score_class }}" role="progressbar"
|
||||||
|
style="width: {{ page.staleness_score }}%;"
|
||||||
|
aria-valuenow="{{ page.staleness_score }}"
|
||||||
|
aria-valuemin="0"
|
||||||
|
aria-valuemax="100">
|
||||||
|
{{ page.staleness_score }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
<td class="text-center">
|
||||||
|
<div class="btn-group" role="group">
|
||||||
|
<a href="{{ page.en_page.url }}" target="_blank"
|
||||||
|
class="btn btn-sm btn-outline-primary" title="Version anglaise">
|
||||||
|
<i class="bi bi-translate"></i> EN
|
||||||
|
</a>
|
||||||
|
{% if page.fr_page %}
|
||||||
|
<a href="{{ page.fr_page.url }}" target="_blank"
|
||||||
|
class="btn btn-sm btn-outline-info" title="Version française">
|
||||||
|
<i class="bi bi-translate"></i> FR
|
||||||
|
</a>
|
||||||
|
<a href="{{ path('app_admin_wiki_compare', {'key': page.key}) }}"
|
||||||
|
class="btn btn-sm btn-outline-secondary"
|
||||||
|
title="Comparer les versions">
|
||||||
|
<i class="bi bi-arrows-angle-expand"></i> Comparer
|
||||||
|
</a>
|
||||||
|
{% else %}
|
||||||
|
<a href="{{ path('app_admin_wiki_create_french', {'key': page.key}) }}"
|
||||||
|
class="btn btn-sm btn-success"
|
||||||
|
title="Créer une traduction française">
|
||||||
|
<i class="bi bi-plus-circle"></i> Traduire
|
||||||
|
</a>
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
{% endfor %}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
{% block javascripts %}
|
||||||
|
{{ parent() }}
|
||||||
|
{% if json_exists %}
|
||||||
|
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
|
||||||
|
<script>
|
||||||
|
document.addEventListener('DOMContentLoaded', function () {
|
||||||
|
// Collect data for the chart
|
||||||
|
const labels = [];
|
||||||
|
const scores = [];
|
||||||
|
const colors = [];
|
||||||
|
|
||||||
|
{% for page in regular_pages|slice(0, 20) %}
|
||||||
|
labels.push("{{ page.key }}");
|
||||||
|
scores.push({{ page.staleness_score }});
|
||||||
|
|
||||||
|
// Set color based on score
|
||||||
|
{% if page.staleness_score > 80 %}
|
||||||
|
colors.push('rgba(220, 53, 69, 0.7)'); // danger (red)
|
||||||
|
{% elseif page.staleness_score > 60 %}
|
||||||
|
colors.push('rgba(232, 113, 55, 0.7)'); // dark orange
|
||||||
|
{% elseif page.staleness_score > 40 %}
|
||||||
|
colors.push('rgba(255, 153, 0, 0.7)'); // orange
|
||||||
|
{% elseif page.staleness_score > 20 %}
|
||||||
|
colors.push('rgba(255, 193, 7, 0.7)'); // warning (yellow)
|
||||||
|
{% elseif page.staleness_score > 10 %}
|
||||||
|
colors.push('rgba(140, 195, 38, 0.7)'); // light green
|
||||||
|
{% else %}
|
||||||
|
colors.push('rgba(25, 135, 84, 0.7)'); // success (green)
|
||||||
|
{% endif %}
|
||||||
|
{% endfor %}
|
||||||
|
|
||||||
|
// Sort data by score (descending)
|
||||||
|
const indices = Array.from(Array(scores.length).keys())
|
||||||
|
.sort((a, b) => scores[b] - scores[a]);
|
||||||
|
|
||||||
|
const sortedLabels = indices.map(i => labels[i]);
|
||||||
|
const sortedScores = indices.map(i => scores[i]);
|
||||||
|
const sortedColors = indices.map(i => colors[i]);
|
||||||
|
|
||||||
|
// Create the chart
|
||||||
|
const ctx = document.getElementById('decrepitudeChart').getContext('2d');
|
||||||
|
new Chart(ctx, {
|
||||||
|
type: 'bar',
|
||||||
|
data: {
|
||||||
|
labels: sortedLabels,
|
||||||
|
datasets: [{
|
||||||
|
label: 'Score de décrépitude',
|
||||||
|
data: sortedScores,
|
||||||
|
backgroundColor: sortedColors,
|
||||||
|
borderColor: sortedColors.map(c => c.replace('0.7', '1')),
|
||||||
|
borderWidth: 1
|
||||||
|
}]
|
||||||
|
},
|
||||||
|
options: {
|
||||||
|
indexAxis: 'y',
|
||||||
|
responsive: true,
|
||||||
|
plugins: {
|
||||||
|
legend: {
|
||||||
|
display: false
|
||||||
|
},
|
||||||
|
tooltip: {
|
||||||
|
callbacks: {
|
||||||
|
label: function (context) {
|
||||||
|
return `Score: ${context.raw}`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
scales: {
|
||||||
|
x: {
|
||||||
|
beginAtZero: true,
|
||||||
|
max: 100,
|
||||||
|
title: {
|
||||||
|
display: true,
|
||||||
|
text: 'Score de décrépitude (0-100)'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
{% endif %}
|
||||||
|
{% endblock %}
|
|
@ -40,7 +40,7 @@
|
||||||
<a href="{{ page.url }}" target="_blank" class="btn btn-sm btn-outline-info" title="Version française">
|
<a href="{{ page.url }}" target="_blank" class="btn btn-sm btn-outline-info" title="Version française">
|
||||||
<i class="bi bi-translate"></i> FR
|
<i class="bi bi-translate"></i> FR
|
||||||
</a>
|
</a>
|
||||||
<a href="https://wiki.openstreetmap.org/wiki/{{ page.key }}" target="_blank" class="btn btn-sm btn-success" title="Créer la version anglaise">
|
<a href="https://wiki.openstreetmap.org/w/index.php?title={{ page.key }}&action=edit" target="_blank" class="btn btn-sm btn-success" title="Créer la version anglaise">
|
||||||
<i class="bi bi-plus-circle"></i> Créer EN
|
<i class="bi bi-plus-circle"></i> Créer EN
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -93,7 +93,7 @@
|
||||||
<p>Vous pouvez contribuer en créant cette page sur le wiki OpenStreetMap.</p>
|
<p>Vous pouvez contribuer en créant cette page sur le wiki OpenStreetMap.</p>
|
||||||
</div>
|
</div>
|
||||||
<div class="d-grid gap-2">
|
<div class="d-grid gap-2">
|
||||||
<a href="https://wiki.openstreetmap.org/w/index.php?title=FR:Key:{{ page.key }}&action=edit"
|
<a href="https://wiki.openstreetmap.org/w/index.php?title=FR:{{ page.key }}&action=edit"
|
||||||
target="_blank" class="btn btn-success">
|
target="_blank" class="btn btn-success">
|
||||||
<i class="bi bi-plus-circle"></i> Créer la page française
|
<i class="bi bi-plus-circle"></i> Créer la page française
|
||||||
</a>
|
</a>
|
||||||
|
|
|
@ -119,7 +119,7 @@
|
||||||
<script src='{{ asset('js/maplibre/maplibre-gl.js') }}'></script>
|
<script src='{{ asset('js/maplibre/maplibre-gl.js') }}'></script>
|
||||||
|
|
||||||
<!-- Script pour le tri automatique des tableaux -->
|
<!-- Script pour le tri automatique des tableaux -->
|
||||||
{# <script src="{{ asset('js/bootstrap/Sortable.min.js') }}"></script> #}
|
<script src="{{ asset('js/table-sort.js') }}"></script>
|
||||||
<script src="{{ asset('js/qrcode/qrcode.min.js') }}"></script>
|
<script src="{{ asset('js/qrcode/qrcode.min.js') }}"></script>
|
||||||
<script>
|
<script>
|
||||||
new QRCode(document.getElementById('qrcode'), {
|
new QRCode(document.getElementById('qrcode'), {
|
||||||
|
|
|
@ -6,11 +6,17 @@
|
||||||
<div class="collapse navbar-collapse" id="navbarNav">
|
<div class="collapse navbar-collapse" id="navbarNav">
|
||||||
<ul class="navbar-nav">
|
<ul class="navbar-nav">
|
||||||
<li class="nav-item">
|
<li class="nav-item">
|
||||||
<a class="nav-link active" href="{{ path('app_public_index') }}">
|
<a class="nav-link {% if app.request.get('_route') == 'app_public_index' %}active{% endif %}" href="{{ path('app_public_index') }}">
|
||||||
<i class="bi bi-house-fill"></i>
|
<i class="bi bi-house-fill"></i>
|
||||||
{{ 'accueil'|trans }}
|
{{ 'accueil'|trans }}
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
|
<li class="nav-item">
|
||||||
|
<a class="nav-link {% if app.request.get('_route') == 'app_admin_wiki_decrepitude' %}active{% endif %}" href="{{ path('app_admin_wiki_decrepitude') }}">
|
||||||
|
<i class="bi bi-graph-up"></i>
|
||||||
|
Scores de décrépitude
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -282,7 +282,7 @@
|
||||||
<thead class="thead-dark">
|
<thead class="thead-dark">
|
||||||
<tr>
|
<tr>
|
||||||
<th>Titre</th>
|
<th>Titre</th>
|
||||||
<th>Score de décrépitude</th>
|
{# <th>Score de décrépitude</th>#}
|
||||||
<th>Actions</th>
|
<th>Actions</th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
|
@ -302,22 +302,22 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</td>
|
</td>
|
||||||
<td>
|
{# <td>#}
|
||||||
{% if page.outdatedness_score is defined %}
|
{# {% if page.outdatedness_score is defined %}#}
|
||||||
<div class="progress" style="height: 20px;">
|
{# <div class="progress" style="height: 20px;">#}
|
||||||
{% set score_class = page.outdatedness_score > 70 ? 'bg-danger' : (page.outdatedness_score > 40 ? 'bg-warning' : 'bg-success') %}
|
{# {% set score_class = page.outdatedness_score > 70 ? 'bg-danger' : (page.outdatedness_score > 40 ? 'bg-warning' : 'bg-success') %}#}
|
||||||
<div class="progress-bar {{ score_class }}" role="progressbar"
|
{# <div class="progress-bar {{ score_class }}" role="progressbar"#}
|
||||||
style="width: {{ page.outdatedness_score }}%;"
|
{# style="width: {{ page.outdatedness_score }}%;"#}
|
||||||
aria-valuenow="{{ page.outdatedness_score }}"
|
{# aria-valuenow="{{ page.outdatedness_score }}"#}
|
||||||
aria-valuemin="0"
|
{# aria-valuemin="0"#}
|
||||||
aria-valuemax="100">
|
{# aria-valuemax="100">#}
|
||||||
{{ page.outdatedness_score }}
|
{# {{ page.outdatedness_score }}#}
|
||||||
</div>
|
{# </div>#}
|
||||||
</div>
|
{# </div>#}
|
||||||
{% else %}
|
{# {% else %}#}
|
||||||
<span class="text-muted">Non disponible</span>
|
{# <span class="text-muted">Non disponible</span>#}
|
||||||
{% endif %}
|
{# {% endif %}#}
|
||||||
</td>
|
{# </td>#}
|
||||||
<td class="text-center">
|
<td class="text-center">
|
||||||
<div class="btn-group" role="group">
|
<div class="btn-group" role="group">
|
||||||
<a href="{{ page.url }}" target="_blank"
|
<a href="{{ page.url }}" target="_blank"
|
||||||
|
@ -325,8 +325,8 @@
|
||||||
<i class="bi bi-flag-fill"></i> FR
|
<i class="bi bi-flag-fill"></i> FR
|
||||||
</a>
|
</a>
|
||||||
{% set en_url = page.url|replace({'FR:': ''}) %}
|
{% set en_url = page.url|replace({'FR:': ''}) %}
|
||||||
<a href="{{ en_url }}" target="_blank"
|
<a href="https://wiki.openstreetmap.org/w/index.php?title={{ page.key }}&action=edit" target="_blank" class="btn btn-sm btn-outline-primary" title="Créer la version anglaise">
|
||||||
class="btn btn-sm btn-outline-primary"
|
|
||||||
title="Créer une traduction anglaise">
|
title="Créer une traduction anglaise">
|
||||||
<i class="bi bi-translate"></i> créer EN
|
<i class="bi bi-translate"></i> créer EN
|
||||||
</a>
|
</a>
|
||||||
|
@ -492,10 +492,10 @@
|
||||||
scales: {
|
scales: {
|
||||||
x: {
|
x: {
|
||||||
beginAtZero: true,
|
beginAtZero: true,
|
||||||
max: 100,
|
// max: 100,
|
||||||
title: {
|
title: {
|
||||||
display: true,
|
display: true,
|
||||||
text: 'Score de décrépitude (0-100)'
|
text: 'Score de décrépitude'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue