- Admin applications: CRUD module (list/add/edit/delete/assign/multi-app) avec push iTop bidirectionnel (applications.py + 3 templates) - Correspondance prod<->hors-prod: migration vers server_correspondance globale, suppression ancien code quickwin, ajout filtre environnement et solution applicative, colonne environnement dans builder - Servers page: colonne application_name + equivalent(s) via get_links_bulk, filtre application_id, push iTop sur changement application - Patching: bulk_update_application, bulk_update_excludes, validations - Fix paramiko sftp.put (remote_path -> positional arg) - Tools: wiki_to_pdf.py (DokuWiki -> PDF) + generate_ppt.py (PPTX 19 slides DSI patching) + contenu source (processus_patching.txt, script_presentation.txt) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
80 lines
3.5 KiB
HTML
80 lines
3.5 KiB
HTML
{% extends 'base.html' %}
|
|
{% block title %}Serveurs multi-applications{% endblock %}
|
|
{% block content %}
|
|
<div class="flex justify-between items-center mb-4">
|
|
<div>
|
|
<a href="/admin/applications" class="text-xs text-gray-500 hover:text-gray-300">← Applications</a>
|
|
<h2 class="text-xl font-bold text-cyber-accent">Serveurs liés à plusieurs applications</h2>
|
|
<p class="text-xs text-gray-500 mt-1">Source : iTop (<code>applicationsolution_list</code> avec 2+ entrées). Cliquer sur une app pour la garder comme unique.</p>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="card p-3 mb-4 text-xs text-gray-400" style="background:#111827">
|
|
<b class="text-cyber-accent">Règle :</b> si un serveur apparaît sous plusieurs apps, souvent c'est une duplication (même app avec noms différents) ou une erreur de saisie. Sélectionner l'app à conserver → les autres seront retirées du serveur (côté iTop également).
|
|
</div>
|
|
|
|
{% if not multi_servers %}
|
|
<div class="card p-6 text-center text-gray-500">
|
|
<p>Aucun serveur avec plusieurs applications dans iTop.</p>
|
|
</div>
|
|
{% else %}
|
|
<div class="card overflow-x-auto">
|
|
<table class="w-full table-cyber text-xs">
|
|
<thead><tr>
|
|
<th class="p-2 text-left">Hostname</th>
|
|
<th class="p-2 text-left">App actuelle (PatchCenter)</th>
|
|
<th class="p-2 text-left">Apps iTop</th>
|
|
<th class="p-2">Action</th>
|
|
</tr></thead>
|
|
<tbody>
|
|
{% for m in multi_servers %}
|
|
<tr class="border-t border-cyber-border/30" id="row-{{ loop.index }}">
|
|
<td class="p-2 font-mono text-cyber-accent">{{ m.hostname }}</td>
|
|
<td class="p-2 text-xs text-gray-300">{{ m.current_app_name or '—' }}</td>
|
|
<td class="p-2">
|
|
{% for a in m.apps %}
|
|
<button onclick="keepApp('{{ m.hostname }}', {{ a.itop_id }}, '{{ a.name|e }}', {{ loop.index0 }}, this)"
|
|
class="btn-sm bg-cyber-border text-cyber-accent" style="margin:2px;padding:4px 10px">
|
|
<span class="font-mono">{{ a.name }}</span>
|
|
</button>
|
|
{% endfor %}
|
|
</td>
|
|
<td class="p-2 text-center">
|
|
<span id="result-{{ loop.index }}" class="text-xs"></span>
|
|
</td>
|
|
</tr>
|
|
{% endfor %}
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
{% endif %}
|
|
|
|
<script>
|
|
function keepApp(hostname, keepItopId, appName, btnIdx, btn) {
|
|
if (!confirm('Garder UNIQUEMENT "' + appName + '" pour ' + hostname + ' ?\n(Les autres apps seront retirées, iTop mis à jour)')) return;
|
|
const row = btn.closest('tr');
|
|
const resultEl = row.querySelector('[id^=result-]');
|
|
resultEl.textContent = '…';
|
|
resultEl.className = 'text-xs text-gray-400';
|
|
fetch('/admin/applications/keep-single-app', {
|
|
method: 'POST', credentials: 'same-origin',
|
|
headers: {'Content-Type': 'application/json'},
|
|
body: JSON.stringify({hostname: hostname, keep_itop_id: keepItopId})
|
|
})
|
|
.then(r => r.json())
|
|
.then(d => {
|
|
if (d.ok) {
|
|
resultEl.textContent = '✓ ' + d.app_name;
|
|
resultEl.className = 'text-xs text-cyber-green';
|
|
// Griser la ligne
|
|
row.style.opacity = '0.5';
|
|
row.querySelectorAll('button').forEach(b => b.disabled = true);
|
|
} else {
|
|
resultEl.textContent = '✗ ' + (d.msg || 'Erreur');
|
|
resultEl.className = 'text-xs text-cyber-red';
|
|
}
|
|
});
|
|
}
|
|
</script>
|
|
{% endblock %}
|