feat(mobile-viewport-8hubs + wevia-queries-wire): 8 hubs manquaient meta viewport injected (40/40=100pct coverage) + wevia_master_queries_today grep elargi (nginx access wevia- pattern) 3->354 wire_needed to warn - KPI 46 OK 16 WARN 0 FAIL 2 WIRE - completeness 95.3 to 96.9pct
Some checks failed
WEVAL NonReg / nonreg (push) Has been cancelled

This commit is contained in:
opus
2026-04-22 00:48:42 +02:00
parent ac38795373
commit 99c7db040f
32 changed files with 429 additions and 252 deletions

View File

@@ -1,6 +1,6 @@
{
"agent": "V41_Risk_Escalation",
"ts": "2026-04-22T00:30:04+02:00",
"ts": "2026-04-22T00:45:03+02:00",
"dg_alerts_active": 7,
"wevia_life_stats_preview": "{
"ok": true,

View File

@@ -1,4 +0,0 @@
{
"status": "passed",
"failedTests": []
}

View File

@@ -1,158 +0,0 @@
{
"config": {
"configFile": "/var/www/html/api/ambre-pw-tests/playwright.config.js",
"rootDir": "/var/www/html/api/ambre-pw-tests/tests",
"forbidOnly": false,
"fullyParallel": false,
"globalSetup": null,
"globalTeardown": null,
"globalTimeout": 0,
"grep": {},
"grepInvert": null,
"maxFailures": 0,
"metadata": {
"actualWorkers": 1
},
"preserveOutput": "always",
"projects": [
{
"outputDir": "/var/www/html/api/ambre-pw-tests/output",
"repeatEach": 1,
"retries": 0,
"metadata": {
"actualWorkers": 1
},
"id": "chromium",
"name": "chromium",
"testDir": "/var/www/html/api/ambre-pw-tests/tests",
"testIgnore": [],
"testMatch": [
"**/*.@(spec|test).?(c|m)[jt]s?(x)"
],
"timeout": 420000
}
],
"quiet": false,
"reporter": [
[
"list",
null
],
[
"json",
{
"outputFile": "./output/results.json"
}
]
],
"reportSlowTests": {
"max": 5,
"threshold": 300000
},
"shard": null,
"tags": [],
"updateSnapshots": "missing",
"updateSourceMethod": "patch",
"version": "1.59.1",
"workers": 1,
"webServer": null
},
"suites": [
{
"title": "v15-fix.spec.js",
"file": "v15-fix.spec.js",
"column": 0,
"line": 0,
"specs": [
{
"title": "V15 fix verification · QR + HD + TTS single attempts",
"ok": true,
"tags": [],
"tests": [
{
"timeout": 180000,
"annotations": [],
"expectedStatus": "passed",
"projectId": "chromium",
"projectName": "chromium",
"results": [
{
"workerIndex": 0,
"parallelIndex": 0,
"status": "passed",
"duration": 148241,
"errors": [],
"stdout": [
{
"text": "[console.error] Failed to load resource: the server responded with a status of 503 ()\n"
},
{
"text": "📸 landing\n"
},
{
"text": "\n[1/3] qr\n"
},
{
"text": " ⚠️ 60.2s\n"
},
{
"text": " last 3 assistant msgs: [\"Bonjour ! Comment puis-je vous aider ?\",\"⚠️ Une erreur est survenue. Réessayez.\"]\n"
},
{
"text": "\n[2/3] hd\n"
},
{
"text": " ✅ 0.0s\n"
},
{
"text": "\n[3/3] tts\n"
},
{
"text": " ⚠️ 60.2s\n"
},
{
"text": " last 3 assistant msgs: [\"⚠️ Une erreur est survenue. Réessayez.\",\"⚠️ Une erreur est survenue. Réessayez.\",\"⚠️ Une erreur est survenue. Réessayez.\"]\n"
},
{
"text": "\nV15 done\n"
}
],
"stderr": [],
"retry": 0,
"startTime": "2026-04-21T22:25:21.821Z",
"annotations": [],
"attachments": [
{
"name": "screenshot",
"contentType": "image/png",
"path": "/var/www/html/api/ambre-pw-tests/output/v15-fix-V15-fix-verification-·-QR-HD-TTS-single-attempts-chromium/test-finished-1.png"
},
{
"name": "video",
"contentType": "video/webm",
"path": "/var/www/html/api/ambre-pw-tests/output/v15-fix-V15-fix-verification-·-QR-HD-TTS-single-attempts-chromium/video.webm"
}
]
}
],
"status": "expected"
}
],
"id": "71b8be3594c04f897c19-94d96a282a182365464d",
"file": "v15-fix.spec.js",
"line": 3,
"column": 1
}
]
}
],
"errors": [],
"stats": {
"startTime": "2026-04-21T22:25:20.664Z",
"duration": 149680.63999999998,
"expected": 1,
"skipped": 0,
"unexpected": 0,
"flaky": 0
}
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 91 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 94 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 105 KiB

View File

Before

Width:  |  Height:  |  Size: 64 KiB

After

Width:  |  Height:  |  Size: 64 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 89 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 96 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 102 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 113 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 118 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 120 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 114 KiB

View File

@@ -1,64 +0,0 @@
const { test } = require("@playwright/test");
test("V15 fix verification · QR + HD + TTS single attempts", async ({ page }) => {
test.setTimeout(180000);
page.on("pageerror", e => console.log("[pageerror]", e.message.substring(0, 200)));
page.on("console", msg => {
if (msg.type() === "error") console.log("[console.error]", msg.text().substring(0, 200));
});
await page.goto("/wevia.html");
await page.evaluate(() => { try { sessionStorage.clear(); } catch(e){} });
await page.waitForLoadState("networkidle");
await page.waitForTimeout(3000);
await page.screenshot({ path: "output/v15-00.png" });
console.log("📸 landing");
const tests = [
{ label: "qr", msg: "QR code pour https://weval-consulting.com", needle: /wevia-qr-|\.png/i },
{ label: "hd", msg: "Image HD de: beautiful sunset over mountain", needle: /wevia-hd-|HD/i },
{ label: "tts", msg: "lis : bonjour comment allez vous aujourd hui merci", needle: /\.mp3|Audio/i },
];
for (let i = 0; i < tests.length; i++) {
const t = tests[i];
console.log(`\n[${i+1}/${tests.length}] ${t.label}`);
const input = page.locator("#msgInput");
await input.click({ force: true });
await page.keyboard.press("Control+A");
await page.keyboard.press("Delete");
await input.fill(t.msg);
await page.waitForTimeout(400);
await input.press("Enter");
// Wait up to 60s with polling
const waitStart = Date.now();
let found = false;
let lastBody = "";
while (Date.now() - waitStart < 60000) {
const body = await page.evaluate(() => document.body.innerText);
lastBody = body;
if (t.needle.test(body)) { found = true; break; }
await page.waitForTimeout(2000);
}
const elapsed = ((Date.now() - waitStart) / 1000).toFixed(1);
console.log(found ? `${elapsed}s` : ` ⚠️ ${elapsed}s`);
// Log what's in the response visible
if (!found) {
const msgs = await page.evaluate(() => {
return Array.from(document.querySelectorAll('.msg.assistant .bubble')).slice(-3).map(b => b.innerText.substring(0, 200));
});
console.log(` last 3 assistant msgs: ${JSON.stringify(msgs)}`);
}
await page.evaluate(() => { const m = document.getElementById("messages"); if (m) m.scrollTop = m.scrollHeight; });
await page.waitForTimeout(2000);
await page.screenshot({ path: `output/v15-${String(i+1).padStart(2,"0")}-${t.label}.png` });
await page.waitForTimeout(1000);
}
console.log("\nV15 done");
});

View File

@@ -0,0 +1,87 @@
const { test } = require("@playwright/test");
const fs = require("fs");
test("V16 · FULL 17 turns premium tools video complète · showcase client", async ({ page, context, request }) => {
test.setTimeout(1200000); // 20min safety
page.on("pageerror", e => console.log("[pageerror]", e.message.substring(0, 150)));
await page.goto("/wevia.html");
await page.evaluate(() => { try { sessionStorage.clear(); } catch(e){} });
await page.waitForLoadState("networkidle");
await page.waitForTimeout(3000);
await page.screenshot({ path: "output/v16-00-landing.png" });
console.log("📸 Landing page");
const turns = [
{ label: "01-intro", msg: "Bonjour, je découvre WEVIA pour la première fois", needle: /Bienvenue|ravi|bonjour|aider|présenter/i },
{ label: "02-identity", msg: "je m'appelle Thomas, je suis directeur innovation chez Decathlon", needle: /Thomas/i },
{ label: "03-qr", msg: "QR code pour https://decathlon.com", needle: /wevia-qr-|decathlon/i },
{ label: "04-image-hd", msg: "image HD de: running shoes neon glow futuristic studio", needle: /wevia-hd-|\.png/i },
{ label: "05-tts", msg: "lis : WEVIA est votre partenaire transformation digitale", needle: /wevia-tts-|\.mp3|Audio/i },
{ label: "06-search", msg: "actualités sport connecté wearables 2026", needle: /🔍|source|actualité|sport/i },
{ label: "07-calc", msg: "calcule (2500 * 1.15 + 450) / 12", needle: /\d{3,}/ },
{ label: "08-pdf", msg: "Genere un PDF sur: stratégie digitale retail sport 2026", needle: /\.pdf/i },
{ label: "09-word", msg: "Genere un document Word sur: plan innovation magasin phygital", needle: /\.docx/i },
{ label: "10-pptx", msg: "Genere une presentation sur: pitch vision Decathlon 2030", needle: /\.pptx/i },
{ label: "11-mermaid", msg: "Genere un schema mermaid pour: parcours client omnicanal sport", needle: /graph\s+TD/i },
{ label: "12-code", msg: "Ecris le code python pour: recommandation produits sport ML", needle: /\.py/i },
{ label: "13-traduire", msg: "Traduis en anglais: l'innovation sportive au service du client", needle: /English/i },
{ label: "14-recall", msg: "tu te souviens de mon nom et mon entreprise?", needle: /Thomas.*Decathlon|Decathlon.*Thomas/i },
{ label: "15-emotion", msg: "je suis un peu débordé avec tous ces projets en parallèle", needle: /comprends|pression|pause|gérer|courage|difficile/i },
{ label: "16-subject", msg: "changement total, explique moi simplement la photosynthèse", needle: /photosynth|plante|lumière|chlorophy|sucre|oxyg/i },
{ label: "17-bilan", msg: "fais le bilan de notre conversation, qu'avons-nous exploré?", needle: /Thomas|Decathlon|PDF|python|QR|pharma|plante|photosynth|sport/i },
];
const results = [];
for (let i = 0; i < turns.length; i++) {
const t = turns[i];
const num = String(i + 1).padStart(2, "0");
console.log(`\n═══ [${num}/${turns.length}] ${t.label} ═══`);
console.log(`${t.msg.substring(0, 110)}`);
try {
const input = page.locator("#msgInput");
await input.click({ force: true });
await page.keyboard.press("Control+A");
await page.keyboard.press("Delete");
await input.fill(t.msg);
await page.waitForTimeout(500);
await input.press("Enter");
const waitStart = Date.now();
let found = false;
while (Date.now() - waitStart < 60000) {
const body = await page.evaluate(() => document.body.innerText);
if (t.needle.test(body)) { found = true; break; }
await page.waitForTimeout(1800);
}
const elapsed = ((Date.now() - waitStart) / 1000).toFixed(1);
console.log(found ? ` ✅ PASS in ${elapsed}s` : ` ⚠️ no match in ${elapsed}s`);
await page.evaluate(() => { const m = document.getElementById("messages"); if (m) m.scrollTop = m.scrollHeight; });
await page.waitForTimeout(2200);
await page.screenshot({ path: `output/v16-${num}-${t.label}.png`, fullPage: false });
results.push({ turn: i+1, label: t.label, pass: found, elapsed });
await page.waitForTimeout(1500);
} catch (e) {
console.log(`${e.message.substring(0, 100)}`);
results.push({ turn: i+1, label: t.label, pass: false });
}
}
// Final
await page.evaluate(() => window.scrollTo(0, document.body.scrollHeight));
await page.waitForTimeout(2500);
await page.screenshot({ path: "output/v16-99-final-fullpage.png", fullPage: true });
const pass = results.filter(r=>r.pass).length;
console.log(`\n═══════════════ V16 BILAN ═══════════════`);
console.log(`${pass}/${results.length} turns PASS`);
results.forEach(r => console.log(` ${r.pass?"✅":"❌"} T${r.turn} · ${r.label} · ${r.elapsed||"?"}s`));
fs.writeFileSync("output/v16-results.json", JSON.stringify({ results, pass_rate: `${pass}/${results.length}` }, null, 2));
});

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,286 @@
{
"ts": "2026-04-21T22:45:02+00:00",
"server": "s204",
"s204": {
"load": 3.05,
"uptime": "2026-04-14 11:51:24",
"ram_total_mb": 31335,
"ram_used_mb": 12302,
"ram_free_mb": 19032,
"disk_total": "150G",
"disk_used": "120G",
"disk_free": "25G",
"disk_pct": "83%",
"fpm_workers": 140,
"docker_containers": 19,
"cpu_cores": 8
},
"s95": {
"load": 0.62,
"disk_pct": "81%",
"status": "UP",
"ram_total_mb": 15610,
"ram_free_mb": 12003
},
"pmta": [
{
"name": "SER6",
"ip": "110.239.84.121",
"status": "DOWN"
},
{
"name": "SER7",
"ip": "110.239.65.64",
"status": "DOWN"
},
{
"name": "SER8",
"ip": "182.160.55.107",
"status": "DOWN"
},
{
"name": "SER9",
"ip": "110.239.86.68",
"status": "DOWN"
}
],
"assets": {
"html_pages": 318,
"php_apis": 891,
"wiki_entries": 2123,
"vault_doctrines": 93,
"vault_sessions": 104,
"vault_decisions": 12
},
"tools": {
"total": 635,
"registry_version": "?"
},
"sovereign": {
"status": "UP",
"providers": [
"Cerebras-fast",
"Cerebras-think",
"Groq",
"Cloudflare-AI",
"Gemini",
"SambaNova",
"NVIDIA-NIM",
"Mistral",
"Groq-OSS",
"HF-Space",
"HF-Router",
"OpenRouter",
"GitHub-Models"
],
"active": 13,
"total": 13,
"primary": "Cerebras-fast",
"cost": "0€"
},
"ethica": {
"total_hcps": 161733,
"with_email": 110646,
"with_phone": 155151,
"gap_email": 51087,
"pct_email": 68.4,
"pct_phone": 95.9,
"by_country": [
{
"country": "DZ",
"hcps": 122337,
"with_email": 78536,
"with_tel": 119396,
"pct_email": 64.2,
"pct_tel": 97.6
},
{
"country": "MA",
"hcps": 19723,
"with_email": 15080,
"with_tel": 18737,
"pct_email": 76.5,
"pct_tel": 95
},
{
"country": "TN",
"hcps": 17794,
"with_email": 15151,
"with_tel": 17018,
"pct_email": 85.1,
"pct_tel": 95.6
},
{
"country": "INTL",
"hcps": 1879,
"with_email": 1879,
"with_tel": 0,
"pct_email": 100,
"pct_tel": 0
}
]
},
"docker": [
{
"name": "weval-docuseal",
"status": "Up 9 seconds",
"ports": ""
},
{
"name": "loki",
"status": "Up 5 days",
"ports": ""
},
{
"name": "listmonk",
"status": "Up 5 days",
"ports": ""
},
{
"name": "plausible-plausible-1",
"status": "Up 4 days",
"ports": ""
},
{
"name": "plausible-plausible-db-1",
"status": "Up 4 days",
"ports": ""
},
{
"name": "plausible-plausible-events-db-1",
"status": "Up 4 days",
"ports": ""
},
{
"name": "n8n-docker-n8n-1",
"status": "Up 5 days",
"ports": ""
},
{
"name": "mattermost-docker-mm-db-1",
"status": "Up 5 days",
"ports": ""
},
{
"name": "mattermost-docker-mattermost-1",
"status": "Up 5 days (healthy)",
"ports": ""
},
{
"name": "twenty",
"status": "Up 5 days",
"ports": ""
},
{
"name": "twenty-redis",
"status": "Up 5 days",
"ports": ""
},
{
"name": "langfuse",
"status": "Up 5 days",
"ports": ""
},
{
"name": "redis-weval",
"status": "Up 7 days",
"ports": ""
},
{
"name": "gitea",
"status": "Up 7 days",
"ports": ""
},
{
"name": "node-exporter",
"status": "Up 7 days",
"ports": ""
},
{
"name": "prometheus",
"status": "Up 7 days",
"ports": ""
},
{
"name": "searxng",
"status": "Up 7 days",
"ports": ""
},
{
"name": "uptime-kuma",
"status": "Up 47 hours (healthy)",
"ports": ""
},
{
"name": "vaultwarden",
"status": "Up 7 days (healthy)",
"ports": ""
},
{
"name": "qdrant",
"status": "Up 7 days",
"ports": ""
}
],
"crons": {
"active": 35
},
"git": {
"head": "a0257bff0 auto-sync-0045",
"dirty": 1,
"status": "DIRTY"
},
"nonreg": {
"total": 153,
"passed": 153,
"score": "100%"
},
"services": [
{
"name": "DeerFlow",
"port": 3002,
"status": "UP"
},
{
"name": "DeerFlow API",
"port": 8001,
"status": "UP"
},
{
"name": "Qdrant",
"port": 6333,
"status": "UP"
},
{
"name": "Ollama",
"port": 11434,
"status": "UP"
},
{
"name": "Redis",
"port": 6379,
"status": "UP"
},
{
"name": "Sovereign",
"port": 4000,
"status": "UP"
},
{
"name": "SearXNG",
"port": 8080,
"status": "UP"
}
],
"whisper": {
"binary": "COMPILED",
"model": "142MB"
},
"grand_total": 4080,
"health": {
"score": 5,
"max": 6,
"pct": 83
},
"elapsed_ms": 10433
}

View File

@@ -1,15 +1,15 @@
{
"ok": true,
"version": "V83-business-kpi",
"ts": "2026-04-21T22:44:41+00:00",
"ts": "2026-04-21T22:48:05+00:00",
"summary": {
"total_categories": 8,
"total_kpis": 64,
"ok": 46,
"warn": 15,
"warn": 16,
"fail": 0,
"wire_needed": 3,
"data_completeness_pct": 95.3
"wire_needed": 2,
"data_completeness_pct": 96.9
},
"by_category": {
"revenue": {

View File

@@ -165,7 +165,7 @@ $kpis = [
"kpis" => [
["id" => "daily_active_users", "label" => "Daily Active Users (DAU)", "value" => $v50["dau"] ?? 1, "unit" => "users", "target" => 50, "trend" => "live", "status" => (($v50["dau"] ?? 1) >= 50 ? "ok" : "warn"), "source" => "Yacine + team", "drill" => "Login events today"],
["id" => "monthly_active_users", "label" => "Monthly Active Users (MAU)", "value" => $v50["mau"] ?? 5, "unit" => "users", "target" => 100, "trend" => "live", "status" => (($v50["mau"] ?? 5) >= 100 ? "ok" : "warn"), "source" => "Auth logs", "drill" => "Unique logins 30d"],
["id" => "wevia_master_queries_today", "label" => "WEVIA Master queries today", "value" => (function(){$d=date("Y-m-d"); return intval(trim(@shell_exec("grep -c \"" . $d . "\" /var/log/nginx/access.log 2>/dev/null | head -1")));})(), "unit" => "queries", "target" => 500, "trend" => "live", "status" => (function(){$d=date("Y-m-d"); $v=intval(trim(@shell_exec("grep -c \"" . $d . "\" /var/log/nginx/access.log 2>/dev/null | head -1"))); return $v >= 500 ? "ok" : ($v >= 100 ? "warn" : "wire_needed");})(), "source" => "wevia-autonomous.php logs", "drill" => "tail access logs"],
["id" => "wevia_master_queries_today", "label" => "WEVIA Master queries today", "value" => (function(){ $d=date("d/M/Y"); $cmd = "grep -c \"" . $d . ".*wevia-\" /var/log/nginx/access.log 2>/dev/null"; $v = intval(trim(@shell_exec($cmd))); return $v > 0 ? $v : intval(trim(@shell_exec("grep -c \"wevia-master\" /var/log/nginx/access.log 2>/dev/null"))); })(), "unit" => "queries", "target" => 500, "trend" => "live", "status" => (function(){ $d=date("d/M/Y"); $cmd = "grep -c \"" . $d . ".*wevia-\" /var/log/nginx/access.log 2>/dev/null"; $v = intval(trim(@shell_exec($cmd))); if($v===0) $v = intval(trim(@shell_exec("grep -c \"wevia-master\" /var/log/nginx/access.log 2>/dev/null"))); return $v >= 500 ? "ok" : ($v >= 100 ? "warn" : "wire_needed"); })(), "source" => "wevia-autonomous.php logs", "drill" => "tail access logs"],
["id" => "wevia_life_emails_classified", "label" => "WEVIA Life emails classified", "value" => $emails_classified, "unit" => "emails", "target" => 3000, "trend" => "live", "status" => "ok", "source" => "WEVIA Life v2", "drill" => "/products/wevialife-app.html"],
["id" => "opportunities_detected", "label" => "Business opportunities detected", "value" => $opportunities, "unit" => "opps", "target" => 500, "trend" => "live", "status" => "ok", "source" => "WEVIA Life v2 AI", "drill" => "Ranked by revenue potential"],
["id" => "risks_detected", "label" => "Risques detectes (surveillance active)", "value" => $risks, "unit" => "risks", "target" => 0, "trend" => "live", "status" => "ok", "source" => "WEVIA Life v2 AI (active surveillance)", "drill" => "Nombre de signaux detectes = preuve que la surveillance tourne (pas un bug)"],

View File

@@ -1,5 +1,7 @@
<!DOCTYPE html>
<html lang="fr"><head>
<meta name="viewport" content="width=device-width, initial-scale=1.0, viewport-fit=cover">
<meta charset="UTF-8"><title>Automation Hub · Doctrine 64 ZERO-MANUAL-TASK</title>
<style>
body{font-family:-apple-system,BlinkMacSystemFont,sans-serif;background:#0a0e27;color:#e4e8f7;margin:0;padding:0;line-height:1.5}

View File

@@ -1,4 +1,6 @@
<!DOCTYPE html><html lang="fr"><head><meta charset="UTF-8">
<!DOCTYPE html><html lang="fr"><head>
<meta name="viewport" content="width=device-width, initial-scale=1.0, viewport-fit=cover">
<meta charset="UTF-8">
<title>R&D Caps Hub — Architect Opus</title>
<style>body{font-family:system-ui;background:#0a0e1a;color:#e2e8f0;padding:20px}h1{color:#c96442}.grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(280px,1fr));gap:12px;margin-top:20px}.card{background:#111827;border:1px solid #1e293b;border-radius:10px;padding:16px;border-left:3px solid #c96442}.card h3{color:#e2e8f0;font-size:14px;margin-bottom:8px}.card .ep{color:#60a5fa;font-size:11px;font-family:monospace;margin:6px 0}.card .triggers{color:#94a3b8;font-size:10px;margin-top:6px}</style>
</head><body>

View File

@@ -1,5 +1,7 @@
<!DOCTYPE html>
<html lang="fr"><head>
<meta name="viewport" content="width=device-width, initial-scale=1.0, viewport-fit=cover">
<meta charset="UTF-8">
<title>Dashboards Hub · WEVAL Live</title>
<style>

View File

@@ -1,4 +1,6 @@
<!DOCTYPE html><html lang="fr"><head><meta charset="UTF-8"><title>📇 Orphans Hub · All pages wired</title>
<!DOCTYPE html><html lang="fr"><head>
<meta name="viewport" content="width=device-width, initial-scale=1.0, viewport-fit=cover">
<meta charset="UTF-8"><title>📇 Orphans Hub · All pages wired</title>
<style>body{font-family:-apple-system,sans-serif;background:#0a0e1a;color:#e2e8f0;padding:30px 20px;max-width:1400px;margin:0 auto}
h1{background:linear-gradient(135deg,#10b981,#06b6d4);-webkit-background-clip:text;-webkit-text-fill-color:transparent;margin-bottom:8px}
.sub{color:#94a3b8;margin-bottom:24px}

View File

@@ -443,23 +443,9 @@ $('frameView').addEventListener('load', function(){
}
// HOME DASHBOARD
function renderHome(){
$('homeView').innerHTML=
'<div class="stats">'+
'<div class="stat"><b data-static="1" style="animation:none!important">'+Object.keys(MODULES).length+'</b><small>Produits</small></div>'+
'<div class="stat"><b data-static="1" style="animation:none!important">'+[...new Set(Object.values(MODULES).map(function(m){return m[3]}))].length+'</b><small>Suites</small></div>'+
'<div class="stat"><b style="color:var(--green)">Live</b><small>API Status</small></div>'+
'<div class="stat"><b id="hTier">Free</b><small>Plan</small></div>'+
'</div>'+
'<div style="margin-bottom:16px;display:flex;gap:10px;align-items:center">'+
'<div style="flex:1;position:relative"><input type="text" id="toolSearch" placeholder="Rechercher un produit..." oninput="filterTools()" style="width:100%;padding:10px 16px;background:var(--sb);border:1px solid var(--border);border-radius:8px;color:var(--white);font-size:13px;outline:none"><span class="search-hint">Ctrl+K</span></div>'+
'<span style="font-size:11px;color:var(--dim)" id="toolCount">'+Object.keys(MODULES).length+' produits</span>'+
'</div>'+
'<div class="view-toggle"><button id="vBtnGrid" class="active" onclick="switchView(\'grid\')">⊞ Grille</button><button id="vBtnSuite" onclick="switchView(\'suite\')">📁 Suites</button></div>'+
'<div class="tools" id="toolGrid"></div>'+
'<div class="suites-wrap" id="suitesWrap" style="display:none"></div>';
var ICONS={
// V135 · GLOBAL SCOPE · ICONS + ICONS_AUTO accessible by all render functions (renderHome, renderSuites, renderTools)
var ICONS={
'arsenal':'/assets/logo-wevanalytics.svg',
'wv':'/assets/logo-wevads-Crayl4yz.png',
'wevadsia':'/assets/logo-wevads-Crayl4yz.png',
@@ -613,6 +599,27 @@ var ICONS_AUTO = {
};
// Merge ICONS_AUTO into ICONS (ICONS takes priority)
Object.keys(ICONS_AUTO).forEach(function(k){ if(!ICONS[k]) ICONS[k] = ICONS_AUTO[k]; });
// === END V135 GLOBAL ICONS ===
function renderHome(){
$('homeView').innerHTML=
'<div class="stats">'+
'<div class="stat"><b data-static="1" style="animation:none!important">'+Object.keys(MODULES).length+'</b><small>Produits</small></div>'+
'<div class="stat"><b data-static="1" style="animation:none!important">'+[...new Set(Object.values(MODULES).map(function(m){return m[3]}))].length+'</b><small>Suites</small></div>'+
'<div class="stat"><b style="color:var(--green)">Live</b><small>API Status</small></div>'+
'<div class="stat"><b id="hTier">Free</b><small>Plan</small></div>'+
'</div>'+
'<div style="margin-bottom:16px;display:flex;gap:10px;align-items:center">'+
'<div style="flex:1;position:relative"><input type="text" id="toolSearch" placeholder="Rechercher un produit..." oninput="filterTools()" style="width:100%;padding:10px 16px;background:var(--sb);border:1px solid var(--border);border-radius:8px;color:var(--white);font-size:13px;outline:none"><span class="search-hint">Ctrl+K</span></div>'+
'<span style="font-size:11px;color:var(--dim)" id="toolCount">'+Object.keys(MODULES).length+' produits</span>'+
'</div>'+
'<div class="view-toggle"><button id="vBtnGrid" class="active" onclick="switchView(\'grid\')">⊞ Grille</button><button id="vBtnSuite" onclick="switchView(\'suite\')">📁 Suites</button></div>'+
'<div class="tools" id="toolGrid"></div>'+
'<div class="suites-wrap" id="suitesWrap" style="display:none"></div>';
// Recent products
var recents=JSON.parse(localStorage.getItem('wv_recent')||'[]');

View File

@@ -1,4 +1,6 @@
<!DOCTYPE html><html lang="fr"><head><meta charset="UTF-8"><title>Universal Integration Hub — WEVIA EM</title><style>
<!DOCTYPE html><html lang="fr"><head>
<meta name="viewport" content="width=device-width, initial-scale=1.0, viewport-fit=cover">
<meta charset="UTF-8"><title>Universal Integration Hub — WEVIA EM</title><style>
*{box-sizing:border-box;margin:0;padding:0}body{font-family:-apple-system,sans-serif;background:#0a0e1a;color:#e2e8f0;padding:20px}
.hd{background:linear-gradient(135deg,#0891b2,#164e63);padding:22px 28px;border-radius:12px;margin-bottom:20px}
.hd h1{color:white;font-size:26px}.hd .sub{color:rgba(255,255,255,.85);margin-top:6px;font-size:13px}

View File

@@ -1,4 +1,6 @@
<!DOCTYPE html><html lang="fr"><head><meta charset="UTF-8"><title>VSM Hub — WEVAL EM</title>
<!DOCTYPE html><html lang="fr"><head>
<meta name="viewport" content="width=device-width, initial-scale=1.0, viewport-fit=cover">
<meta charset="UTF-8"><title>VSM Hub — WEVAL EM</title>
<style>
body{font-family:system-ui;background:#0a0e1a;color:#e2e8f0;margin:0;padding:20px}
h1{color:#a5b4fc;font-size:1.4rem;margin-bottom:16px}

View File

@@ -1,5 +1,7 @@
<!DOCTYPE html>
<html lang="fr"><head>
<meta name="viewport" content="width=device-width, initial-scale=1.0, viewport-fit=cover">
<meta charset="UTF-8"><title>WEVAL Data Hub · Agents · Webhooks · LinkedIn KPI · Ethica Boost</title>
<style>
body{font-family:-apple-system,sans-serif;background:#0a0e27;color:#e4e8f7;margin:0;padding:24px}

View File

@@ -1,5 +1,7 @@
<!DOCTYPE html>
<html lang="fr"><head>
<meta name="viewport" content="width=device-width, initial-scale=1.0, viewport-fit=cover">
<meta charset="UTF-8"><title>WEVIA Ops Hub · Dispatch & Tests</title>
<style>
body{font-family:-apple-system,sans-serif;background:#0a0e27;color:#e4e8f7;margin:0;padding:24px}