auto-sync-1700

This commit is contained in:
opus
2026-04-19 17:00:03 +02:00
parent 38025e6954
commit 2b1ae031a0
9 changed files with 237 additions and 1939 deletions

File diff suppressed because it is too large Load Diff

Binary file not shown.

After

Width:  |  Height:  |  Size: 294 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 374 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 336 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 374 KiB

View File

@@ -0,0 +1,51 @@
{
"start": "2026-04-19T16:58:27",
"tests": [
{
"name": "wtp-load",
"status": "OK",
"title": "WEVAL Technology Platform — All-in-One ERP Portal"
},
{
"name": "v80-toggle-visible",
"status": "OK",
"visible": true
},
{
"name": "drawer-open",
"status": "OK",
"open": true
},
{
"name": "kpis-loaded",
"status": "OK",
"agents": "906",
"pages": "253",
"autonomy": "100%"
},
{
"name": "search-filter",
"status": "OK",
"visible_after_search": 1,
"hidden_after_search": 34
},
{
"name": "nav-items",
"status": "OK",
"pillars": 6,
"quicks": 24,
"links": 5,
"total_nav_items": 35
},
{
"name": "js-errors",
"status": "OK",
"errors_count": 0,
"errors": []
}
],
"video_path": "5a4195998ff8a4838aa4d9c5370e77ff.webm",
"end": "2026-04-19T16:58:40",
"out_dir": "/var/www/html/api/playwright-results/v80-wtp-nav-2026-04-19T16-58-27",
"summary": "7/7 PASS"
}

View File

@@ -1,7 +1,7 @@
{
"ok": true,
"version": "V83-business-kpi",
"ts": "2026-04-19T14:58:29+00:00",
"ts": "2026-04-19T14:59:49+00:00",
"summary": {
"total_categories": 7,
"total_kpis": 56,

View File

@@ -395,7 +395,8 @@ async function loadTree(){
function renderSidebar(){
const el = document.getElementById('wtp-nav-modules');
if (!TREE) return;
el.innerHTML = Object.entries(TREE.modules).map(([id, mod]) => {
// 16 ERP modules
let html = Object.entries(TREE.modules).map(([id, mod]) => {
const count = (mod.submodules||[]).length;
return `<div class="wtp-nav-item" data-mod="${id}" onclick="navigateTo('${id}')">
<span class="wtp-nav-icon" style="color:${mod.color}">${mod.icon}</span>
@@ -403,16 +404,199 @@ function renderSidebar(){
<span class="wtp-nav-count">${count}</span>
</div>`;
}).join('');
// SECTION SÉPARATRICE · POINT D'ENTRÉE ENRICHI (Opus Yacine 19avr)
html += `<div style="padding:10px 14px 6px;font-size:10px;color:var(--wtp-muted);text-transform:uppercase;letter-spacing:1.5px;margin-top:14px;border-top:1px solid var(--wtp-border);padding-top:14px">POINT D'ENTRÉE TOTAL</div>`;
const extras = [
{id:'infra', icon:'🖥', label:'Infrastructure', color:'#22d3ee', count: (TREE.infra?.machines?.length||0) + (TREE.infra?.docker?.length||0)},
{id:'all_pages', icon:'📂', label:'Toutes les pages', color:'#d4af37', count: TREE.all_pages?.total||0},
{id:'all_apis', icon:'🔌', label:'Toutes les APIs', color:'#a855f7', count: TREE.apis?.total||0},
{id:'multiagent', icon:'🤖', label:'Multi-Agent Modes', color:'#ef4444', count: TREE.multiagent_modes?.length||0},
{id:'truth', icon:'🔒', label:'Truth Registry', color:'#22c55e', count: TREE.truth_registry?.agents||0},
];
html += extras.map(e => `<div class="wtp-nav-item" data-mod="${e.id}" onclick="navigateTo('${e.id}')">
<span class="wtp-nav-icon" style="color:${e.color}">${e.icon}</span>
<span>${e.label}</span>
<span class="wtp-nav-count">${e.count}</span>
</div>`).join('');
el.innerHTML = html;
}
function navigateTo(modId){
CURRENT_MOD = modId;
document.querySelectorAll('.wtp-nav-item').forEach(i => i.classList.toggle('active', i.dataset.mod === modId));
if (modId === 'home') renderHome();
else if (modId === 'infra') renderInfra();
else if (modId === 'all_pages') renderAllPages();
else if (modId === 'all_apis') renderAllApis();
else if (modId === 'multiagent') renderMultiagent();
else if (modId === 'truth') renderTruth();
else renderModule(modId);
document.getElementById('wtp-main').scrollTop = 0;
}
// === POINT D'ENTRÉE TOTAL views (Opus Yacine 19avr) ===
function renderInfra(){
const main = document.getElementById('wtp-main');
const i = TREE.infra || {};
const machines = (i.machines||[]).map(m => `
<div style="background:var(--wtp-panel2);padding:18px;border-radius:8px;border:1px solid var(--wtp-border)">
<div style="font-size:18px;font-weight:800;margin-bottom:4px;color:var(--wtp-ac)">${m.id}</div>
<div style="font-size:11px;color:var(--wtp-muted);margin-bottom:10px">${m.type||''}</div>
<div style="font-size:13px;line-height:1.6">${m.role||''}</div>
${m.cpu ? `<div style="margin-top:8px;font-size:11px;color:var(--wtp-muted)">CPU: ${m.cpu} · RAM: ${m.ram||'?'} · Disk: ${m.disk||'?'}</div>` : ''}
</div>`).join('');
const docker = (i.docker||[]).slice(0, 25).map(d => `
<div style="display:flex;justify-content:space-between;padding:8px 12px;background:var(--wtp-panel);border-radius:6px;margin-bottom:4px;font-size:12px">
<span style="font-weight:600">${d.name||'?'}</span>
<span style="color:var(--wtp-muted);font-family:monospace;font-size:10px">${d.status||''}</span>
</div>`).join('');
const gpus = (i.gpus||[]).map(g => `
<div style="background:var(--wtp-panel);padding:14px;border-radius:8px;margin-bottom:6px">
<div style="font-weight:700">${g.name||'?'}</div>
<div style="font-size:11px;color:var(--wtp-muted);margin-top:4px">${g.note||''}</div>
${g.mem_total_mb ? `<div style="margin-top:6px;font-family:monospace;font-size:11px">Mem: ${g.mem_used_mb}/${g.mem_total_mb} MB · Temp: ${g.temp_c}°C · Util: ${g.util_pct}%</div>` : ''}
</div>`).join('');
const subdoms = Object.entries(i.subdomains||{}).map(([d, role]) => `
<a href="https://${d}/" target="_blank" style="display:flex;justify-content:space-between;padding:8px 12px;background:var(--wtp-panel);border-radius:6px;margin-bottom:4px;font-size:12px;text-decoration:none;color:var(--wtp-text)">
<span style="font-family:monospace">${d}</span>
<span style="color:var(--wtp-muted)">${role}</span>
</a>`).join('');
main.innerHTML = `
<div style="padding:24px">
<h1 style="font-size:28px;margin-bottom:6px">🖥 Infrastructure</h1>
<div style="color:var(--wtp-muted);margin-bottom:24px">Machines · Docker · GPUs · Blade · Subdomains · tout en un</div>
<h2 style="font-size:18px;margin-bottom:12px">💻 Machines · ${(i.machines||[]).length}</h2>
<div style="display:grid;grid-template-columns:repeat(auto-fit,minmax(260px,1fr));gap:12px;margin-bottom:28px">${machines}</div>
<h2 style="font-size:18px;margin-bottom:12px">🔧 Blade yacineutt (Sentinel · Chrome persist)</h2>
<div style="background:var(--wtp-panel2);padding:18px;border-radius:8px;border:1px solid var(--wtp-border);margin-bottom:28px">
<div style="font-size:14px;font-weight:700;margin-bottom:8px">${i.blade?.host||'Razer Blade'}</div>
<div style="color:var(--wtp-muted);font-size:12px;margin-bottom:10px">${i.blade?.role||''}</div>
<div style="font-size:12px;margin-bottom:6px">Profile: ${i.blade?.yacineutt_profile||'?'}</div>
<div style="display:flex;gap:6px;flex-wrap:wrap;margin-top:10px">
${(i.blade?.services||[]).map(s=>`<span style="background:var(--wtp-panel);padding:4px 10px;border-radius:99px;font-size:11px;font-family:monospace">${s}</span>`).join('')}
</div>
</div>
<h2 style="font-size:18px;margin-bottom:12px">🎮 GPUs · ${(i.gpus||[]).length}</h2>
${gpus}
<div style="height:24px"></div>
<h2 style="font-size:18px;margin-bottom:12px">🐳 Docker · ${(i.docker||[]).length} containers</h2>
<div style="display:grid;grid-template-columns:repeat(auto-fit,minmax(280px,1fr));gap:6px;margin-bottom:28px">${docker}</div>
<h2 style="font-size:18px;margin-bottom:12px">🌐 Subdomains · ${Object.keys(i.subdomains||{}).length}</h2>
<div style="display:grid;grid-template-columns:repeat(auto-fit,minmax(280px,1fr));gap:6px">${subdoms}</div>
</div>`;
}
function renderAllPages(){
const main = document.getElementById('wtp-main');
const ap = TREE.all_pages || {};
const cats = ap.pages_by_category || {};
const catHtml = Object.entries(cats).sort((a,b)=>b[1].length-a[1].length).map(([cat, pages]) => {
const items = pages.slice(0, 50).map(p => `
<a href="${p.url}" style="display:flex;justify-content:space-between;padding:7px 11px;background:var(--wtp-panel);border:1px solid var(--wtp-border);border-radius:5px;text-decoration:none;color:var(--wtp-text);font-size:12px;transition:.15s"
onmouseover="this.style.borderColor='var(--wtp-ac)'" onmouseout="this.style.borderColor='var(--wtp-border)'">
<span style="font-weight:500">${p.name.replace(/\.html$/,'').replace(/[-_]/g,' ')}</span>
<span style="color:var(--wtp-muted);font-family:monospace;font-size:10px">${p.size_kb}k${p.is_orphan?' ·⚠':''}</span>
</a>`).join('');
return `<div style="margin-bottom:24px">
<h3 style="font-size:15px;margin-bottom:10px;display:flex;justify-content:space-between">
<span>${cat}</span><span style="color:var(--wtp-muted);font-size:11px;font-weight:400">${pages.length} pages</span>
</h3>
<div style="display:grid;grid-template-columns:repeat(auto-fill,minmax(340px,1fr));gap:4px">${items}</div>
${pages.length>50?`<div style="color:var(--wtp-muted);font-size:11px;margin-top:6px">+${pages.length-50} autres</div>`:''}
</div>`;
}).join('');
main.innerHTML = `
<div style="padding:24px">
<h1 style="font-size:28px;margin-bottom:6px">📂 Toutes les pages · ${ap.total}</h1>
<div style="color:var(--wtp-muted);margin-bottom:20px">${ap.orphans} orphelines identifiées · toutes accessibles depuis WTP</div>
<div style="margin-bottom:18px">
<input type="text" id="pg-search" placeholder="Recherche page..." oninput="_pgSearch(this.value)" style="width:100%;padding:12px 16px;background:var(--wtp-panel);border:1px solid var(--wtp-border);color:var(--wtp-text);border-radius:6px;font-size:13px;outline:none">
</div>
<div id="pg-content">${catHtml}</div>
</div>`;
}
window._pgSearch = function(q){
q = (q||'').toLowerCase();
document.querySelectorAll('#pg-content a').forEach(a => {
a.style.display = (!q || a.textContent.toLowerCase().includes(q)) ? '' : 'none';
});
};
function renderAllApis(){
const main = document.getElementById('wtp-main');
const a = TREE.apis || {};
main.innerHTML = `
<div style="padding:24px">
<h1 style="font-size:28px;margin-bottom:6px">🔌 Toutes les APIs · ${a.total}</h1>
<div style="color:var(--wtp-muted);margin-bottom:24px">Endpoints PHP dans /api/</div>
<h2 style="font-size:16px;margin-bottom:10px">Top WEVIA APIs (${(a.top_wevia||[]).length})</h2>
<div style="display:grid;grid-template-columns:repeat(auto-fill,minmax(320px,1fr));gap:6px">
${(a.top_wevia||[]).map(api => `
<a href="/api/${api}" target="_blank" style="padding:8px 12px;background:var(--wtp-panel);border:1px solid var(--wtp-border);border-radius:5px;text-decoration:none;color:var(--wtp-text);font-size:12px;font-family:monospace">
${api}
</a>`).join('')}
</div>
</div>`;
}
function renderMultiagent(){
const main = document.getElementById('wtp-main');
const modes = TREE.multiagent_modes || [];
main.innerHTML = `
<div style="padding:24px">
<h1 style="font-size:28px;margin-bottom:6px">🤖 Multi-Agent Modes</h1>
<div style="color:var(--wtp-muted);margin-bottom:24px">3 modes coexistent via WEVIA Master chat · /wevia-master.html</div>
<div style="display:grid;grid-template-columns:repeat(auto-fit,minmax(320px,1fr));gap:14px">
${modes.map((m, i) => `
<div style="background:var(--wtp-panel2);padding:20px;border-radius:10px;border:1px solid var(--wtp-border);border-left:4px solid ${['#6366f1','#22c55e','#f59e0b'][i]||'#6366f1'}">
<div style="font-size:17px;font-weight:800;margin-bottom:6px">${m.mode}</div>
<div style="font-size:22px;font-weight:700;margin:8px 0">${m.agents || m.agents_target} agents</div>
<div style="font-size:12px;color:var(--wtp-muted);margin-bottom:8px">Latency: <span style="color:var(--wtp-ac);font-family:monospace">${m.latency_ms}ms</span></div>
<div style="font-size:12px;margin-bottom:10px">${m.use}</div>
<div style="font-size:10px;color:var(--wtp-muted);font-family:monospace;padding:6px 10px;background:var(--wtp-panel);border-radius:4px">${m.trigger}</div>
</div>`).join('')}
</div>
<div style="margin-top:24px;padding:18px;background:var(--wtp-panel2);border-radius:8px">
<strong>💬 Tester en live:</strong> ouvre <a href="/wevia-master.html" style="color:var(--wtp-ac)">/wevia-master.html</a> et tape "agis en multiagent"
</div>
</div>`;
}
function renderTruth(){
const main = document.getElementById('wtp-main');
const t = TREE.truth_registry || {};
main.innerHTML = `
<div style="padding:24px">
<h1 style="font-size:28px;margin-bottom:6px">🔒 Truth Registry · source unique</h1>
<div style="color:var(--wtp-muted);margin-bottom:24px">Built: <span style="font-family:monospace">${t.built_at||'?'}</span> · rebuild cron /30min</div>
<div style="display:grid;grid-template-columns:repeat(auto-fit,minmax(180px,1fr));gap:10px;margin-bottom:24px">
${[['Agents',t.agents,'#d4af37'],['Intents',t.intents,'#22c55e'],['Skills',t.skills,'#6366f1'],['Brains',t.brains,'#a855f7'],['Doctrines',t.doctrines,'#ef4444'],['Dashboards',t.dashboards,'#22d3ee'],['Providers',t.providers,'#f59e0b'],['Qdrant Cols',t.qdrant_cols,'#ec4899'],['Qdrant Points',t.qdrant_points,'#10b981'],['Autonomy',(t.autonomy_score||0)+'/100 '+(t.autonomy_level||''),'#d4af37']].map(([l,v,c])=>`
<div style="background:var(--wtp-panel2);padding:16px;border-radius:8px;border-top:2px solid ${c}">
<div style="font-size:10px;color:var(--wtp-muted);text-transform:uppercase;letter-spacing:1px;margin-bottom:6px">${l}</div>
<div style="font-size:24px;font-weight:800;color:${c}">${typeof v==='number' ? v.toLocaleString('fr-FR') : v}</div>
</div>`).join('')}
</div>
<div style="display:flex;gap:10px;flex-wrap:wrap">
<a href="/api/wevia-truth-registry.json" target="_blank" style="padding:10px 16px;background:var(--wtp-panel);border:1px solid var(--wtp-border);border-radius:6px;text-decoration:none;color:var(--wtp-text);font-size:13px">📄 Truth Registry JSON (560 KB)</a>
<a href="/api/source-of-truth.json" target="_blank" style="padding:10px 16px;background:var(--wtp-panel);border:1px solid var(--wtp-border);border-radius:6px;text-decoration:none;color:var(--wtp-text);font-size:13px">📋 Source of Truth (snapshot)</a>
<a href="/api/wevia.php?q=status&format=text" target="_blank" style="padding:10px 16px;background:var(--wtp-panel);border:1px solid var(--wtp-border);border-radius:6px;text-decoration:none;color:var(--wtp-text);font-size:13px">🔍 NL Query API</a>
</div>
</div>`;
}
function renderHome(){
if (!TREE) return;
const kpis = TREE.kpis || {};