feat: grisage automatique des tuiles + data-app-id + polling dashboard prod
- Ajout CSS .app-card.offline (grisage, grayscale, pointer-events none) - Ajout .card-status-badge 'Hors ligne' sur toutes les tuiles - Ajout data-app-id sur toutes les tuiles Itinova (manquant en prod) - Ajout JS fetchAndApplyStatuses() avec polling 30s sur dashboard.santinova-soft.org - Synchronisation structurelle avec le portail recette
This commit is contained in:
148
index.html
148
index.html
@@ -249,6 +249,36 @@
|
|||||||
border: 1px solid rgba(16,185,129,0.2);
|
border: 1px solid rgba(16,185,129,0.2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* ===== APP OFFLINE (grisage) ===== */
|
||||||
|
.app-card.offline {
|
||||||
|
opacity: 0.42;
|
||||||
|
pointer-events: none;
|
||||||
|
cursor: not-allowed;
|
||||||
|
filter: grayscale(80%);
|
||||||
|
}
|
||||||
|
|
||||||
|
.app-card.offline .card-image-wrapper {
|
||||||
|
box-shadow: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-status-badge {
|
||||||
|
display: none;
|
||||||
|
margin-top: 4px;
|
||||||
|
font-size: 0.68rem;
|
||||||
|
font-weight: 700;
|
||||||
|
color: #ef4444;
|
||||||
|
text-transform: uppercase;
|
||||||
|
letter-spacing: 0.8px;
|
||||||
|
background: rgba(239,68,68,0.12);
|
||||||
|
padding: 2px 9px;
|
||||||
|
border-radius: 10px;
|
||||||
|
border: 1px solid rgba(239,68,68,0.3);
|
||||||
|
}
|
||||||
|
|
||||||
|
.app-card.offline .card-status-badge {
|
||||||
|
display: inline-block;
|
||||||
|
}
|
||||||
|
|
||||||
/* ===== FOOTER ===== */
|
/* ===== FOOTER ===== */
|
||||||
footer {
|
footer {
|
||||||
background: #0a0c14;
|
background: #0a0c14;
|
||||||
@@ -331,7 +361,7 @@
|
|||||||
</button>
|
</button>
|
||||||
<button class="tab-btn" onclick="switchTab('santinova', this)">
|
<button class="tab-btn" onclick="switchTab('santinova', this)">
|
||||||
Applications Santinova
|
Applications Santinova
|
||||||
<span class="tab-count">2</span>
|
<span class="tab-count">3</span>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -346,48 +376,54 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="apps-grid">
|
<div class="apps-grid">
|
||||||
|
|
||||||
<!-- Itinova Contacts -->
|
|
||||||
<a class="app-card" href="https://contacts.santinova-soft.org" target="_blank" rel="noopener noreferrer">
|
|
||||||
<div class="card-image-wrapper">
|
|
||||||
<img src="images/itinova-contacts.png" alt="Itinova Contacts" />
|
|
||||||
</div>
|
|
||||||
<div class="card-name">Itinova Contacts</div>
|
|
||||||
<div class="card-env-badge">Production</div>
|
|
||||||
</a>
|
|
||||||
|
|
||||||
<!-- Itinova Podcasts -->
|
|
||||||
<a class="app-card" href="https://podcasts.santinova-soft.org" target="_blank" rel="noopener noreferrer">
|
|
||||||
<div class="card-image-wrapper">
|
|
||||||
<img src="images/itinova-podcasts.png" alt="Itinova Podcasts" />
|
|
||||||
</div>
|
|
||||||
<div class="card-name">Itinova Podcasts</div>
|
|
||||||
<div class="card-env-badge">Production</div>
|
|
||||||
</a>
|
|
||||||
|
|
||||||
<!-- Veille Stratégique -->
|
|
||||||
<a class="app-card" href="https://veille.santinova-soft.org" target="_blank" rel="noopener noreferrer">
|
|
||||||
<div class="card-image-wrapper">
|
|
||||||
<img src="images/veille-reglementaire.png" alt="Veille Stratégique" />
|
|
||||||
</div>
|
|
||||||
<div class="card-name">Veille Stratégique</div>
|
|
||||||
<div class="card-env-badge">Production</div>
|
|
||||||
</a>
|
|
||||||
<!-- Gestion des Formations -->
|
<!-- Gestion des Formations -->
|
||||||
<a class="app-card" href="https://formations.itinova.org" target="_blank" rel="noopener noreferrer">
|
<a class="app-card" data-app-id="formation-manager-itinova" href="https://formations.itinova.org" target="_blank" rel="noopener noreferrer">
|
||||||
<div class="card-image-wrapper">
|
<div class="card-image-wrapper">
|
||||||
<img src="images/formation-manager-itinova.png" alt="Gestion des Formations" />
|
<img src="images/formation-manager-itinova.png" alt="Gestion des Formations" />
|
||||||
</div>
|
</div>
|
||||||
<div class="card-name">Gestion des Formations</div>
|
<div class="card-name">Gestion des Formations</div>
|
||||||
<div class="card-env-badge">Production</div>
|
<div class="card-env-badge">Production</div>
|
||||||
|
<div class="card-status-badge">Hors ligne</div>
|
||||||
|
</a>
|
||||||
|
|
||||||
|
<!-- Itinova Contacts -->
|
||||||
|
<a class="app-card" data-app-id="itinova-contacts" href="https://contacts.santinova-soft.org" target="_blank" rel="noopener noreferrer">
|
||||||
|
<div class="card-image-wrapper">
|
||||||
|
<img src="images/itinova-contacts.png" alt="Itinova Contacts" />
|
||||||
|
</div>
|
||||||
|
<div class="card-name">Itinova Contacts</div>
|
||||||
|
<div class="card-env-badge">Production</div>
|
||||||
|
<div class="card-status-badge">Hors ligne</div>
|
||||||
|
</a>
|
||||||
|
|
||||||
|
<!-- Itinova Podcasts -->
|
||||||
|
<a class="app-card" data-app-id="itinova-podcasts" href="https://podcasts.santinova-soft.org" target="_blank" rel="noopener noreferrer">
|
||||||
|
<div class="card-image-wrapper">
|
||||||
|
<img src="images/itinova-podcasts.png" alt="Itinova Podcasts" />
|
||||||
|
</div>
|
||||||
|
<div class="card-name">Itinova Podcasts</div>
|
||||||
|
<div class="card-env-badge">Production</div>
|
||||||
|
<div class="card-status-badge">Hors ligne</div>
|
||||||
|
</a>
|
||||||
|
|
||||||
|
<!-- Veille Stratégique -->
|
||||||
|
<a class="app-card" data-app-id="veille-reglementaire" href="https://veille.santinova-soft.org" target="_blank" rel="noopener noreferrer">
|
||||||
|
<div class="card-image-wrapper">
|
||||||
|
<img src="images/veille-reglementaire.png" alt="Veille Stratégique" />
|
||||||
|
</div>
|
||||||
|
<div class="card-name">Veille Stratégique</div>
|
||||||
|
<div class="card-env-badge">Production</div>
|
||||||
|
<div class="card-status-badge">Hors ligne</div>
|
||||||
</a>
|
</a>
|
||||||
|
|
||||||
<!-- Itinova Gestion de Flotte -->
|
<!-- Itinova Gestion de Flotte -->
|
||||||
<a class="app-card" href="https://flotte.santinova-soft.org" target="_blank" rel="noopener noreferrer">
|
<a class="app-card" data-app-id="itinova-vehicle-exchange" href="https://flotte.santinova-soft.org" target="_blank" rel="noopener noreferrer">
|
||||||
<div class="card-image-wrapper">
|
<div class="card-image-wrapper">
|
||||||
<img src="images/itinova-flotte.png" alt="Itinova Gestion de Flotte" />
|
<img src="images/itinova-flotte.png" alt="Itinova Gestion de Flotte" />
|
||||||
</div>
|
</div>
|
||||||
<div class="card-name">Itinova Gestion de Flotte</div>
|
<div class="card-name">Itinova Gestion de Flotte</div>
|
||||||
<div class="card-env-badge">Production</div>
|
<div class="card-env-badge">Production</div>
|
||||||
|
<div class="card-status-badge">Hors ligne</div>
|
||||||
</a>
|
</a>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
@@ -400,6 +436,7 @@
|
|||||||
<p>Cliquez sur une application pour l'ouvrir dans un nouvel onglet</p>
|
<p>Cliquez sur une application pour l'ouvrir dans un nouvel onglet</p>
|
||||||
</div>
|
</div>
|
||||||
<div class="apps-grid">
|
<div class="apps-grid">
|
||||||
|
|
||||||
<!-- SONUM -->
|
<!-- SONUM -->
|
||||||
<a class="app-card" data-app-id="sonum" href="https://sonum.santinova-soft.org" target="_blank" rel="noopener noreferrer">
|
<a class="app-card" data-app-id="sonum" href="https://sonum.santinova-soft.org" target="_blank" rel="noopener noreferrer">
|
||||||
<div class="card-image-wrapper">
|
<div class="card-image-wrapper">
|
||||||
@@ -442,12 +479,11 @@
|
|||||||
</div>
|
</div>
|
||||||
</footer>
|
</footer>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
|
// URL de l'API de statut du dashboard de production
|
||||||
|
var DASHBOARD_STATUS_URL = 'https://dashboard.santinova-soft.org/api/public/status';
|
||||||
|
|
||||||
function updateTabCounts() {
|
function updateTabCounts() {
|
||||||
// Compter les app-card dans chaque panel et mettre à jour les badges
|
|
||||||
document.querySelectorAll('.tab-btn').forEach(function(btn) {
|
document.querySelectorAll('.tab-btn').forEach(function(btn) {
|
||||||
var onclick = btn.getAttribute('onclick') || '';
|
var onclick = btn.getAttribute('onclick') || '';
|
||||||
var match = onclick.match(/switchTab\('(\w+)'/);
|
var match = onclick.match(/switchTab\('(\w+)'/);
|
||||||
@@ -468,10 +504,50 @@
|
|||||||
document.getElementById('panel-' + tabName).classList.add('active');
|
document.getElementById('panel-' + tabName).classList.add('active');
|
||||||
}
|
}
|
||||||
|
|
||||||
// Mise à jour au chargement
|
/**
|
||||||
document.addEventListener('DOMContentLoaded', updateTabCounts);
|
* Met à jour l'état visuel des tuiles en fonction des statuts reçus du dashboard.
|
||||||
|
*/
|
||||||
|
function applyStatuses(statuses) {
|
||||||
|
var cards = document.querySelectorAll('.app-card[data-app-id]');
|
||||||
|
cards.forEach(function(card) {
|
||||||
|
var appId = card.getAttribute('data-app-id');
|
||||||
|
var appStatus = statuses.find(function(s) { return s.id === appId; });
|
||||||
|
if (appStatus) {
|
||||||
|
var isOffline = appStatus.status === 'offline' || !appStatus.containerRunning;
|
||||||
|
if (isOffline) {
|
||||||
|
card.classList.add('offline');
|
||||||
|
} else {
|
||||||
|
card.classList.remove('offline');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Interroge le dashboard pour obtenir les statuts et met à jour les tuiles.
|
||||||
|
*/
|
||||||
|
function fetchAndApplyStatuses() {
|
||||||
|
fetch(DASHBOARD_STATUS_URL, { cache: 'no-store' })
|
||||||
|
.then(function(response) {
|
||||||
|
if (!response.ok) throw new Error('HTTP ' + response.status);
|
||||||
|
return response.json();
|
||||||
|
})
|
||||||
|
.then(function(statuses) {
|
||||||
|
applyStatuses(statuses);
|
||||||
|
})
|
||||||
|
.catch(function(err) {
|
||||||
|
console.warn('[Portail] Impossible de récupérer les statuts:', err.message);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
document.addEventListener('DOMContentLoaded', function() {
|
||||||
|
updateTabCounts();
|
||||||
|
// Premier appel immédiat
|
||||||
|
fetchAndApplyStatuses();
|
||||||
|
// Polling toutes les 30 secondes
|
||||||
|
setInterval(fetchAndApplyStatuses, 30000);
|
||||||
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user