Files
html/owner-actions-tracker.html

246 lines
12 KiB
HTML
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!DOCTYPE html>
<html lang="fr">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<meta http-equiv="Cache-Control" content="no-cache, no-store, must-revalidate">
<title>👤 Owner Actions Tracker — Yacine's Physical Actions · WEVAL</title>
<style>
*,*::before,*::after{box-sizing:border-box}
body{margin:0;background:linear-gradient(135deg,#0a0e1a 0%,#1a1f3a 100%);color:#e2e8f0;font-family:-apple-system,'Segoe UI',sans-serif;min-height:100vh;padding:20px}
.wrap{max-width:1400px;margin:0 auto}
.header{display:flex;align-items:center;justify-content:space-between;padding:20px 24px;background:rgba(99,102,241,0.08);border:1px solid rgba(99,102,241,0.25);border-radius:12px;margin-bottom:20px}
.header h1{margin:0;font-size:22px;font-weight:600}
.header p{margin:4px 0 0;color:#94a3b8;font-size:13px}
.badges{display:flex;gap:10px}
.badge{padding:6px 14px;background:rgba(16,185,129,0.15);border:1px solid rgba(16,185,129,0.4);border-radius:20px;font-size:12px;font-weight:600;color:#10b981}
.badge.warn{background:rgba(245,158,11,0.15);border-color:rgba(245,158,11,0.4);color:#f59e0b}
.badge.crit{background:rgba(239,68,68,0.15);border-color:rgba(239,68,68,0.4);color:#ef4444}
.stats{display:grid;grid-template-columns:repeat(auto-fit,minmax(200px,1fr));gap:14px;margin-bottom:24px}
.stat{padding:18px 20px;background:rgba(30,41,59,0.5);border:1px solid rgba(99,102,241,0.15);border-radius:10px}
.stat-v{font-size:32px;font-weight:700;color:#22d3ee;line-height:1}
.stat-l{color:#94a3b8;font-size:11px;text-transform:uppercase;letter-spacing:0.5px;margin-top:6px}
.items{display:grid;gap:16px}
.item{background:rgba(30,41,59,0.6);border:1px solid rgba(99,102,241,0.2);border-radius:12px;padding:20px 24px;transition:all 0.2s}
.item:hover{border-color:rgba(99,102,241,0.5);transform:translateX(4px)}
.item.critical{border-left:4px solid #ef4444}
.item.high{border-left:4px solid #f59e0b}
.item.medium{border-left:4px solid #22d3ee}
.item.low{border-left:4px solid #64748b}
.item-head{display:flex;align-items:center;gap:12px;margin-bottom:10px}
.item-icon{font-size:28px}
.item-title{flex:1;font-size:16px;font-weight:600;color:#f1f5f9}
.item-prio{padding:3px 10px;border-radius:12px;font-size:10px;font-weight:700;text-transform:uppercase;letter-spacing:0.8px}
.item-prio.critical{background:rgba(239,68,68,0.2);color:#ef4444}
.item-prio.high{background:rgba(245,158,11,0.2);color:#f59e0b}
.item-prio.medium{background:rgba(34,211,238,0.2);color:#22d3ee}
.item-prio.low{background:rgba(100,116,139,0.2);color:#94a3b8}
.item-cat{display:inline-block;margin:0 0 10px;padding:2px 8px;background:rgba(99,102,241,0.15);border-radius:6px;font-size:11px;color:#a78bfa}
.item-why{color:#cbd5e1;font-size:14px;line-height:1.5;margin:10px 0 14px;padding:12px;background:rgba(15,23,42,0.6);border-radius:8px;border-left:3px solid #a78bfa}
.item-why b{color:#f1f5f9}
.actions-list{list-style:none;padding:0;margin:10px 0}
.actions-list li{padding:8px 0 8px 28px;position:relative;color:#e2e8f0;font-size:13.5px;line-height:1.5}
.actions-list li::before{content:'▸';position:absolute;left:8px;color:#22d3ee;font-weight:700}
.item-footer{display:flex;flex-wrap:wrap;gap:16px;margin-top:14px;padding-top:12px;border-top:1px solid rgba(99,102,241,0.15);font-size:12px;color:#94a3b8}
.item-footer strong{color:#f1f5f9}
.item-footer .eta{color:#f59e0b}
.item-footer .value{color:#10b981;font-weight:600}
.cta-row{display:flex;gap:10px;margin-top:14px}
.cta{padding:8px 16px;background:rgba(99,102,241,0.2);border:1px solid rgba(99,102,241,0.4);border-radius:8px;color:#a78bfa;text-decoration:none;font-size:12px;font-weight:600;transition:all 0.2s;cursor:pointer;display:inline-block}
.cta:hover{background:rgba(99,102,241,0.35);transform:translateY(-1px)}
.cta.done{background:rgba(16,185,129,0.2);border-color:rgba(16,185,129,0.4);color:#10b981}
.cta.done:hover{background:rgba(16,185,129,0.35)}
.note{padding:10px 14px;background:rgba(16,185,129,0.08);border:1px dashed rgba(16,185,129,0.3);border-radius:8px;font-size:12px;color:#86efac;margin-top:10px}
.loading{padding:40px;text-align:center;color:#94a3b8}
.back{display:inline-block;margin-top:20px;padding:10px 18px;background:rgba(99,102,241,0.15);border:1px solid rgba(99,102,241,0.3);border-radius:8px;color:#a78bfa;text-decoration:none;font-size:13px}
.back:hover{background:rgba(99,102,241,0.3)}
.summary-box{padding:16px 20px;background:rgba(16,185,129,0.08);border:1px solid rgba(16,185,129,0.3);border-radius:10px;margin-bottom:20px;color:#86efac;font-size:13.5px;line-height:1.6}
</style>
<!-- DOCTRINE-60-UX-ENRICH direct-inject-20260424-144054 -->
<style id="doctrine60-ux-direct">
/* DOCTRINE-60-UX-ENRICH injected-direct */
body::before {
content: '';
position: fixed;
top: 0; left: 0; width: 100vw; height: 100vh;
background: radial-gradient(circle at 50% 50%, rgba(100,180,255,0.08), transparent 60%);
pointer-events: none;
z-index: -1;
}
.card, .kpi, .panel, .btn {
transition: all 0.3s cubic-bezier(0.2,0,0.1,1);
}
.card:hover, .kpi:hover, .panel:hover {
box-shadow: 0 4px 20px rgba(100,180,255,0.2);
border-color: rgba(100,180,255,0.5);
}
@keyframes pulseD60 {
0%,100% { opacity: 1; transform: scale(1); }
50% { opacity: 0.7; transform: scale(1.05); }
}
.pulse, .live-indicator, .active, .online {
animation: pulseD60 3s ease-in-out infinite;
}
.modal, .chat, .speech, .overlay {
backdrop-filter: blur(12px);
-webkit-backdrop-filter: blur(12px);
}
.enter-stagger {
animation: enterStagD60 0.5s cubic-bezier(0.2,0,0.1,1) forwards;
}
@keyframes enterStagD60 {
from { opacity: 0; transform: translateY(20px); }
to { opacity: 1; transform: translateY(0); }
}
</style>
</head>
<body>
<div class="wrap">
<div class="header">
<div>
<h1>👤 Owner Actions Tracker</h1>
<p>Les seules actions qui nécessitent Yacine physiquement — tout le reste est automatisé à 100% (6σ)</p>
</div>
<div class="badges">
<span class="badge">19/19 automatable DONE</span>
<span id="blocked-count" class="badge warn">— blocked</span>
</div>
</div>
<div class="summary-box">
<strong>🎯 État actuel</strong> : l'écosystème WEVAL est à <b>100% sur tout ce qui est automatable</b> (Plan 19/19 done · Risk 100% · NonReg 153/153 · Heatmap 144/144 · Qdrant 0 empty · Bias 20/20 · Alignment 10/10). Les items ci-dessous sont <b>strictement user-action-required</b> — doctrine #4 honnête.
</div>
<div class="stats" id="stats"></div>
<div id="items-container" class="loading">Loading owner actions…</div>
<a href="/weval-technology-platform.html" class="back">← Retour WTP (point d'entrée unique)</a>
</div>
<script>
async function load() {
try {
const r = await fetch('/api/wevia-owner-actions-tracker.php?t=' + Date.now());
const d = await r.json();
renderStats(d);
renderItems(d.items);
document.getElementById('blocked-count').textContent = d.total + ' blocked (Yacine-only)';
} catch(e) {
document.getElementById('items-container').innerHTML = '<div class="loading">❌ Erreur: '+e.message+'</div>';
}
}
function renderStats(d) {
const s = d.summary || {};
const byP = d.by_priority || {};
document.getElementById('stats').innerHTML = `
<div class="stat">
<div class="stat-v">${d.total}</div>
<div class="stat-l">Owner actions pending</div>
</div>
<div class="stat">
<div class="stat-v" style="color:#10b981">${s.automatable_closed || '—'}</div>
<div class="stat-l">Automatable closed</div>
</div>
<div class="stat">
<div class="stat-v" style="color:#ef4444">${byP.critical || 0}</div>
<div class="stat-l">Critical priority</div>
</div>
<div class="stat">
<div class="stat-v" style="color:#f59e0b">${byP.high || 0}</div>
<div class="stat-l">High priority</div>
</div>
<div class="stat">
<div class="stat-v" style="color:#10b981">${(d.total_value_keur || 0)}k€</div>
<div class="stat-l">Total pipeline value</div>
</div>
`;
}
function renderItems(items) {
const c = document.getElementById('items-container');
c.className = 'items';
c.innerHTML = items.map(it => {
const actions = (it.action_required || []).map(a => `<li>${escapeHtml(a)}</li>`).join('');
const prio = it.priority || 'medium';
const ctaRow = buildCTA(it);
const noteBlock = it.note ? `<div class="note"> ${escapeHtml(it.note)}</div>` : '';
return `
<div class="item ${prio}">
<div class="item-head">
<span class="item-icon">${it.icon || '📌'}</span>
<div class="item-title">${escapeHtml(it.title || '?')}</div>
<span class="item-prio ${prio}">${prio}</span>
</div>
${it.category ? `<span class="item-cat">${escapeHtml(it.category)}</span>` : ''}
<div class="item-why"><b>Pourquoi bloqué :</b> ${escapeHtml(it.why_blocked || '')}</div>
${actions ? `<div><b style="font-size:12px;color:#94a3b8;text-transform:uppercase;letter-spacing:0.5px">Action requise :</b><ul class="actions-list">${actions}</ul></div>` : ''}
<div class="item-footer">
${it.contact ? `<span>👤 <strong>${escapeHtml(it.contact)}</strong></span>` : ''}
${it.eta_realistic ? `<span class="eta">⏱️ ETA: ${escapeHtml(it.eta_realistic)}</span>` : ''}
${it.value_keur ? `<span class="value">💰 ${it.value_keur}k€ value</span>` : ''}
</div>
${ctaRow}
${noteBlock}
</div>
`;
}).join('');
}
function buildCTA(it) {
const buttons = [];
if (it.compose_template) buttons.push(`<a href="${it.compose_template}" class="cta" target="_blank">📧 Open compose template</a>`);
if (it.id === 'act_69e53d5d5e09c') buttons.push(`<a href="https://portal.azure.com" class="cta" target="_blank">🔗 Open Azure Portal</a>`);
if (it.id === 'act_69e53d5d9aa8d') buttons.push(`<a href="https://www.ovh.com/manager" class="cta" target="_blank">🔗 Open OVH Manager</a>`);
if (it.id === 'blade_razer_wake') buttons.push(`<a href="/tasks-live-opus5.html" class="cta" target="_blank">📊 Verify Blade status</a>`);
buttons.push(`<button class="cta done" onclick="markDone('${it.id}')" title="Mark as done once action completed">✅ Mark done (once done)</button>`);
return `<div class="cta-row">${buttons.join('')}</div>`;
}
async function markDone(id) {
if (!confirm('Mark ' + id + ' as done ? (update plan)')) return;
try {
const r = await fetch('/api/wevia-v71-risk-halu-plan.php?action=plan_update&id=' + encodeURIComponent(id) + '&status=done');
const j = await r.json();
if (j.ok) {
alert('✅ Marked done');
load();
} else alert('❌ Error: ' + JSON.stringify(j));
} catch(e) { alert('❌ ' + e.message); }
}
function escapeHtml(s) {
return String(s).replace(/[&<>"']/g, c => ({'&':'&amp;','<':'&lt;','>':'&gt;','"':'&quot;',"'":'&#39;'}[c]));
}
load();
// Auto-refresh every 60s
setInterval(load, 60000);
</script>
<script src="/api/a11y-auto-enhancer.js" defer></script>
<!-- WTP_UDOCK_V1 (Opus 21-avr t34final) --><script src="/wtp-unified-dock.js" defer></script>
<script src="/opus-antioverlap-doctrine.js?v=1776776094" defer></script>
<!-- DOCTRINE-60-UX-JS --><script id="doctrine60-ux-js-direct">
// DOCTRINE-60-UX-JS staggered entrance
(function(){
if (!('IntersectionObserver' in window)) return;
const obs = new IntersectionObserver((entries) => {
entries.forEach((e, i) => {
if (e.isIntersecting) {
setTimeout(() => e.target.classList.add('enter-stagger'), i * 80);
obs.unobserve(e.target);
}
});
});
document.querySelectorAll('.card, .kpi, .panel').forEach(el => obs.observe(el));
})();
</script>
</body>
</html>