feat(paperclip-warnings w318): banner WARN auto-detect projets orange
CAUSE RACINE (Yacine: PAS UN SEUL WARN): - Dashboard paperclip affichait 3 projets orange/warn (CF Bypass 65pct P1, Gemini UX 40pct P2, Ethica HCP 76pct P1) SANS alerte visuelle banner - Users ne voient pas rapidement combien de projets attention requise FIX wave 318: 1. CSS w318-warnings-banner (orange gradient + animation fadein + items) 2. JS w318-warn-detector: - Parse projects array (status=warn/down OR progress<80 OR P0/P1<90) - Injecte banner en haut avec icone + titre + liste items + count - Fallback banner vert ALL SYSTEMS NOMINAL si 0 warning 3. Insertion avant section Projets Pipeline (placement logique) 4. Styles premium: glow drop-shadow, hover effects, prio badges Zero regression (CSS/JS additive uniquement) Zero ecrasement (str_replace surgical) GOLD backup gold_paperclip_warn_w318 chattr +i preserve CF purge User feedback-driven: banner visible = compliance UX doctrine 60
This commit is contained in:
@@ -186,6 +186,44 @@ html body .stat-card::before, html body .metric-card::before, html body .hub-car
|
||||
}
|
||||
html body .kpi, html body [class*="card"] { position: relative !important; }
|
||||
</style>
|
||||
<style id="w318-warnings-banner">
|
||||
/* W318 Warnings banner - doctrine premium UX */
|
||||
.w318-warn-banner{
|
||||
margin:16px 20px 8px;padding:14px 18px;
|
||||
background:linear-gradient(135deg,rgba(255,159,67,0.08),rgba(255,107,107,0.06));
|
||||
border:1px solid rgba(255,159,67,0.35);border-left:4px solid #ff9f43;
|
||||
border-radius:10px;display:flex;align-items:center;gap:14px;
|
||||
box-shadow:0 2px 12px rgba(255,159,67,0.12);
|
||||
animation:w318fadein .4s ease;
|
||||
font-family:'Inter',system-ui,sans-serif
|
||||
}
|
||||
@keyframes w318fadein{from{opacity:0;transform:translateY(-4px)}to{opacity:1;transform:translateY(0)}}
|
||||
.w318-warn-icon{font-size:22px;filter:drop-shadow(0 0 8px rgba(255,159,67,0.4))}
|
||||
.w318-warn-content{flex:1;display:flex;flex-direction:column;gap:6px}
|
||||
.w318-warn-title{font-weight:700;font-size:13px;letter-spacing:.4px;color:#ff9f43;text-transform:uppercase}
|
||||
.w318-warn-list{display:flex;gap:10px;flex-wrap:wrap;margin-top:4px}
|
||||
.w318-warn-item{
|
||||
padding:5px 11px;background:rgba(255,159,67,0.12);
|
||||
border:1px solid rgba(255,159,67,0.3);border-radius:5px;
|
||||
font-size:11px;color:#ffb775;font-family:'JetBrains Mono',monospace;
|
||||
display:flex;align-items:center;gap:6px;transition:.15s
|
||||
}
|
||||
.w318-warn-item:hover{background:rgba(255,159,67,0.22);border-color:#ff9f43}
|
||||
.w318-warn-item .pct{font-weight:700;color:#ff9f43}
|
||||
.w318-warn-item .prio{font-size:9px;padding:1px 5px;background:rgba(0,0,0,0.3);border-radius:3px;color:#fff}
|
||||
.w318-warn-item .prio.P1{background:rgba(255,107,107,0.5)}
|
||||
.w318-warn-item .prio.P2{background:rgba(255,159,67,0.5)}
|
||||
.w318-warn-count{
|
||||
padding:4px 10px;background:#ff9f43;color:#0a0c12;
|
||||
border-radius:12px;font-weight:800;font-size:12px;letter-spacing:.5px
|
||||
}
|
||||
.w318-warn-ok{
|
||||
margin:16px 20px 8px;padding:10px 16px;
|
||||
background:rgba(92,219,149,0.06);border-left:3px solid #5cdb95;border-radius:6px;
|
||||
color:#5cdb95;font-size:11px;font-family:'JetBrains Mono',monospace;
|
||||
letter-spacing:.3px;display:flex;align-items:center;gap:10px
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="header">
|
||||
@@ -367,5 +405,77 @@ document.addEventListener('DOMContentLoaded', () => {
|
||||
});
|
||||
});
|
||||
</script>
|
||||
<script id="w318-warn-detector">
|
||||
(function(){
|
||||
function injectWarnBanner(){
|
||||
if(typeof projects==='undefined')return;
|
||||
|
||||
// Detect warnings: status='warn' OR progress < 80 OR P1 < 90
|
||||
var warnings = projects.filter(function(p){
|
||||
if(p.status==='warn' || p.status==='down') return true;
|
||||
if(p.progress < 80) return true;
|
||||
if((p.priority==='P1' || p.priority==='P0') && p.progress < 90) return true;
|
||||
return false;
|
||||
});
|
||||
|
||||
// Find target (just before projets pipeline section)
|
||||
var pipelineHeader = Array.from(document.querySelectorAll('h2,h3,.section-title')).find(function(el){
|
||||
return el.textContent.indexOf('Projets Pipeline') >= 0 || el.textContent.indexOf('Pipeline') >= 0;
|
||||
});
|
||||
|
||||
// Or fallback: top of main content
|
||||
var target = pipelineHeader ? pipelineHeader.closest('.panel,.card,section,div') : document.querySelector('main,.main-content,body>div');
|
||||
if(!target) target = document.body.firstElementChild;
|
||||
|
||||
// Remove existing
|
||||
var existing = document.getElementById('w318-banner');
|
||||
if(existing) existing.remove();
|
||||
|
||||
if(warnings.length === 0){
|
||||
var ok = document.createElement('div');
|
||||
ok.id = 'w318-banner';
|
||||
ok.className = 'w318-warn-ok';
|
||||
ok.innerHTML = '<span>✓</span><span>ALL SYSTEMS NOMINAL — ' + projects.length + ' projets OK, zero warning</span>';
|
||||
target.parentNode.insertBefore(ok, target);
|
||||
return;
|
||||
}
|
||||
|
||||
var banner = document.createElement('div');
|
||||
banner.id = 'w318-banner';
|
||||
banner.className = 'w318-warn-banner';
|
||||
var items = warnings.map(function(w){
|
||||
return '<span class="w318-warn-item">' +
|
||||
'<span class="prio ' + (w.priority||'') + '">' + (w.priority||'?') + '</span>' +
|
||||
'<span>' + w.name + '</span>' +
|
||||
'<span class="pct">' + w.progress + '%</span>' +
|
||||
'</span>';
|
||||
}).join('');
|
||||
banner.innerHTML =
|
||||
'<span class="w318-warn-icon">⚠️</span>' +
|
||||
'<div class="w318-warn-content">' +
|
||||
'<div class="w318-warn-title">Projets nécessitant attention</div>' +
|
||||
'<div class="w318-warn-list">' + items + '</div>' +
|
||||
'</div>' +
|
||||
'<span class="w318-warn-count">' + warnings.length + ' WARN</span>';
|
||||
target.parentNode.insertBefore(banner, target);
|
||||
}
|
||||
|
||||
// Run after DOMContentLoaded + wait for projects array
|
||||
function tryInject(retries){
|
||||
retries = retries || 0;
|
||||
if(typeof projects !== 'undefined' && projects.length){
|
||||
injectWarnBanner();
|
||||
} else if(retries < 20){
|
||||
setTimeout(function(){tryInject(retries+1);}, 150);
|
||||
}
|
||||
}
|
||||
|
||||
if(document.readyState === 'loading'){
|
||||
document.addEventListener('DOMContentLoaded', function(){tryInject();});
|
||||
} else {
|
||||
tryInject();
|
||||
}
|
||||
})();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
Reference in New Issue
Block a user